diff --git a/app/[locale]/resources/_components/UpgradeCountdown.tsx b/app/[locale]/resources/_components/UpgradeCountdown.tsx index e8e88d9f0f0..2a3a6f12d5c 100644 --- a/app/[locale]/resources/_components/UpgradeCountdown.tsx +++ b/app/[locale]/resources/_components/UpgradeCountdown.tsx @@ -106,7 +106,9 @@ const UpgradeCountdown = () => { ) : (
Live Since{" "} - {new Intl.DateTimeFormat(locale, { timeZone: "UTC" }).format(new Date(upgradeDate))} + {new Intl.DateTimeFormat(locale, { timeZone: "UTC" }).format( + new Date(upgradeDate) + )}
)} diff --git a/public/content/translations/zh-tw/contributing/design/index.md b/public/content/translations/zh-tw/contributing/design/index.md index 21930c8a716..8f426562917 100644 --- a/public/content/translations/zh-tw/contributing/design/index.md +++ b/public/content/translations/zh-tw/contributing/design/index.md @@ -1,10 +1,10 @@ --- -title: 設計貢獻 -description: 為 ethereum.org 作出設計貢獻 +title: "設計貢獻" +description: "為 ethereum.org 作出設計貢獻" lang: zh-tw --- -# 為 ethereum.org 作出設計貢獻 {#design-contributions} +# 為 ethereum.org 貢獻設計 {#design-contributions} 設計是任何專案的關鍵組成部分,把你的時間和設計技能投入到 ethereum.org,有助替我們的訪客改善使用者體驗。 替開源專案做出貢獻,會為你提供機會以獲取相關經驗,並在協作環境中發展技能。 你有機會與其他擁有獨特觀點和見解的設計師、開發者和社群成員合作。 @@ -12,15 +12,15 @@ lang: zh-tw ## 如何做出貢獻? -###  對早期設計原型提供意見回饋 {#design-critique} +###  針對早期設計原型提供回饋 {#design-critique} 有時候我們需要獲得幫助來測試我們的原始構想。 這是在沒有任何技術知識的情況下做出貢獻的好方法。 -1. 設計團隊會在 [Discord](https://discord.com/invite/ethereum-org) 和 [GitHub](https://github.com/ethereum/ethereum-org-website/labels/design%20required%20%F0%9F%8E%A8) 上分享模型設計。 +1. 設計團隊會在 [Discord](https://discord.com/invite/ethereum-org) 和 [GitHub](https://github.com/ethereum/ethereum-org-website/labels/design%20required%20%F0%9F%8E%A8) 上分享設計模型。 2. 你會在指導下熟悉這些設計,並透過評論功能提供意見回饋。 3. 結果將在 GitHub 議題中分享,然後由團隊關閉。 -###  參與調查研究 {#answer-surveys} +###  參與問卷調查研究 {#answer-surveys} 透過以下方式在我們網站上提供意見回饋: @@ -28,40 +28,40 @@ lang: zh-tw 2. 點擊右下角的意見回饋小工具,並回答與設計和內容相關的問題。 3. 重點關注開放式問題。 -###  尋找網站上與設計相關的問題並回報 {#report-design-issues} +###  找出網站上與設計相關的問題並回報 {#report-design-issues} Ethereum.org 是個擁有許多功能和內容,而且快速發展的網站。 某些使用者介面很容易過時或需要改進。 如果你遇到這類情況,請報告以讓我們注意。 1. 瀏覽網站並注意其設計。 2. 如果你發現任何視覺或使用者體驗方面問題,請取得螢幕擷取畫面並記錄下來。 -3. 使用[錯誤報告](https://github.com/ethereum/ethereum-org-website/issues/new/choose)來報告發現的問題。 +3. 使用 [錯誤報告](https://github.com/ethereum/ethereum-org-website/issues/new/choose) 回報找到的問題。 -###  提出設計變更 {#propose-design-changes} +###  提出設計變更建議 {#propose-design-changes} -如果你願意接受設計挑戰,可以造訪我們的 GitHub 議題板並篩選[設計相關議題](https://github.com/ethereum/ethereum-org-website/labels/design%20required%20%F0%9F%8E%A8)。 +如果你樂於接受設計挑戰,可以前往我們的 GitHub 議題看板並篩選出 [設計相關議題](https://github.com/ethereum/ethereum-org-website/labels/design%20required%20%F0%9F%8E%A8)。 -1. 瀏覽我們的網站並注意其設計,或訪問我們的 GitHub 儲存庫並查看標示 [「Design required」標籤](https://github.com/ethereum/ethereum-org-website/labels/design%20required%20%F0%9F%8E%A8)的議題。 -2. 構思解決方案並進行設計。 (最好使用我們的[設計系統](https://www.figma.com/community/file/1134414495420383395))。 -3. 在對應的 GitHub 議題中提出解決方案或[建立一個新的議題](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=feature+%3Asparkles%3A&template=feature_request.yaml&title=Feature+request)。 +1. 瀏覽我們的網站並留意其設計,或前往我們的 GitHub 存放庫,檢視標有 [「需要設計」標籤](https://github.com/ethereum/ethereum-org-website/labels/design%20required%20%F0%9F%8E%A8) 的議題。 +2. 構思解決方案並進行設計。 (最好使用我們的 [設計系統](https://www.figma.com/community/file/1134414495420383395))。 +3. 在相應的 GitHub 議題中提出解決方案,或 [建立新議題。](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=feature+%3Asparkles%3A&template=feature_request.yaml&title=Feature+request) 4. 等待設計團隊審核。 -###  一起構建設計系統 {#Contribute-to-design-system} +###  共同建立設計系統 {#Contribute-to-design-system} 利用我們的設計系統,讓設計 ethereum.org 變得輕鬆有趣。 如果你是位經驗豐富的設計師,便可以幫助我們為網站準備許多組件。 -1. 從 GitHub 上的[設計系統板](https://github.com/ethereum/ethereum-org-website/labels/design%20system)選擇要處理的議題,或建立一個新的議題。 +1. 從 GitHub 上的 [設計系統看板](https://github.com/ethereum/ethereum-org-website/labels/design%20system) 中選擇要處理的議題,或建立新議題。 2. 請求將選定的議題分配給你。 3. 開始在 Figma 中設計所要求的組件。 4. 需要審核或指導時,請在 GitHub 上將組件分享給設計團隊。 5. 設計團隊將進行審核。 6. 設計團隊會將變更合併到主檔案中,並將它發佈到社群。 -###  在網站上撰寫與設計相關的內容 {#write-design-articles} +###  在網站上撰寫設計相關內容 {#write-design-articles} -以太坊開發者社群很強大,但設計社群稍顯落後。 如果你是具備 Web3 知識的設計師,請考慮與廣大社群分享你的知識,讓我們可以共同成長和進步;我們有一個[關於以太坊設計的頁面](/developers/docs/design-and-ux/),你可以在此做出貢獻。 你也可以查看我們的[上架政策](/contributing/design/adding-design-resources)。 +以太坊開發者社群很強大,但設計社群稍顯落後。 如果你是具備 Web3 知識的設計師,請考慮與廣大社群分享你的所學,讓我們可以共同成長和進步;我們有[一個關於為以太坊設計的頁面](/developers/docs/design-and-ux/),你可以在此做出貢獻。 你也可以查看我們的 [上架政策](/contributing/design/adding-design-resources)。 1. 構思 ethereum.org 上應該涵蓋的設計主題,會對該領域的設計師有所裨益。 -2. 前往我們的 GitHub 儲存庫,[發起議題](https://github.com/ethereum/ethereum-org-website/issues/new)來建議主題(先不要寫內容)。 +2. 前往我們的 GitHub 存放庫,並 [發起議題](https://github.com/ethereum/ethereum-org-website/issues/new) 來提議主題(還不要撰寫內容)。 3. 等待設計團隊核准。 4. 一旦核准,開始撰寫內容。 5. 在相應的 GitHub 議題中提交。 @@ -71,7 +71,7 @@ Ethereum.org 是個擁有許多功能和內容,而且快速發展的網站。 可視化是用來解釋抽象主題的其中一種最強大工具。 透過新增圖表和資訊圖,可以發掘巨大潛力。 畢竟,一張圖片勝過千言萬語。 1. 訪問我們的網站,並查看可以新增一些新資訊圖的頁面。 -2. 確保插圖風格與我們的[網站](/assets/)相對應。 -3. 前往我們的 GitHub 儲存庫並[發起議題](https://github.com/ethereum/ethereum-org-website/issues/new)來建議插圖。 +2. 確保插圖風格與我們的 [資產](/assets/) 一致。 +3. 前往我們的 GitHub 存放庫,並 [發起議題](https://github.com/ethereum/ethereum-org-website/issues/new) 提議此插圖。 4. 設計團隊將會審核。 5. 我們建立一個新議題,並邀請開發者來實作該新圖像。 diff --git a/public/content/translations/zh-tw/contributing/index.md b/public/content/translations/zh-tw/contributing/index.md index 7788c50e1e1..84bcd9b502e 100644 --- a/public/content/translations/zh-tw/contributing/index.md +++ b/public/content/translations/zh-tw/contributing/index.md @@ -1,44 +1,49 @@ --- -title: 參與貢獻 -description: 瞭解為 ethereum.org 做出貢獻的不同方法 +title: "參與貢獻" +description: "瞭解為 ethereum.org 做出貢獻的不同方法" lang: zh-tw --- -# 為 ethereum.org 做出貢獻 🦄 {#contributing-to-ethereumorg} +# 為 ethereum.org 作出貢獻 🦄 {#contributing-to-ethereumorg} -Ethereum.org 是一個開源專案,擁有超過 **12000 名**貢獻者,幫助翻譯、編寫、設計和維護網站。 +Ethereum.org 是一個開源專案,擁有 **12,000+** 名貢獻者,他們協助翻譯、撰寫、設計及維護網站。 我們是個熱情的社群,將助你在以太坊生態系統中成長和學習,同時讓你做出有意義的貢獻,並獲得相關實踐經驗! -## 貢獻方法 {#ways-to-contribute} +## 貢獻方式 {#ways-to-contribute} **翻譯** -- [加入翻譯計劃](/contributing/translation-program/) – 幫助我們把 ethereum.org 內容翻譯成新語言 + +- [加入翻譯計畫](/contributing/translation-program/) – 協助我們將 ethereum.org 推廣到新的語言 **開發** -- [處理未解決的問題](https://github.com/ethereum/ethereum-org-website/issues) – 我們確定為需要完成的工作 + +- [處理待解決的議題](https://github.com/ethereum/ethereum-org-website/issues) – 我們已找出需要處理的工作 **設計** -- [幫助設計網站](/contributing/design/) — 任何水平的設計者都可以為改進網站做出貢獻 + +- [協助設計網站](/contributing/design/) – 歡迎所有程度的設計師為改進網站作出貢獻 **內容** -- [建立/編輯內容](/contributing/#how-to-update-content) – 提議建立新頁面或對已有內容稍微改進 -- [新增社群資源](/contributing/content-resources/) – 將有用的文章或資源加入相關頁面 -- [建議設計資源](/contributing/design/adding-design-resources/) – 新增、更新和刪除設計資源 -- [新增詞彙表術語](/contributing/adding-glossary-terms/) – 幫助我們繼續擴大以太坊的[詞彙表](/glossary/) -- [測驗](/contributing/quizzes/) – 新增、更新和刪除相關頁面的測驗題庫 + +- [建立/編輯內容](/contributing/#how-to-update-content) – 建議新頁面或對現有內容進行微調 +- [新增社群資源](/contributing/content-resources/) – 將實用的文章或資源新增至相關頁面 +- [建議設計資源](/contributing/design/adding-design-resources/) – 新增、更新與刪除實用的設計資源 +- [測驗](/contributing/quizzes/) – 為相關頁面新增、更新與刪除測驗題庫 **特色功能的想法** -- [請求一項特色功能](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=Type%3A+Feature&template=feature_request.yaml&title=) – 讓我們知道有關你對新特色功能或設計的任何想法 + +- [請求新功能](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=Type%3A+Feature&template=feature_request.yaml&title=) – 讓我們知道您對新功能或設計的任何想法 **產品列表** -- [新增交易所](/contributing/adding-exchanges/) – 新增交易所到我們的 [交易所搜尋工具](/get-eth/#country-picker) -- [新增產品](/contributing/adding-products/) – 新增去中心化應用程式或錢包到相關頁面 -- [新增開發者工具](/contributing/adding-developer-tools/) – 新增開發者工具到相關頁面 -- [新增二層網路](/contributing/adding-layer-2s/) – 新增二層網路到相關頁面 -- [新增質押產品或服務](/contributing/adding-staking-products/) – 新增專案以幫助加速單獨質押、聯合質押,或質押即服務 -- [新增錢包](/contributing/adding-wallets/) – 為[查找錢包頁面](/wallets/find-wallet/)新增錢包 -- [為我們的去中心化科學頁面建議一個專案](/contributing/adding-desci-projects/) – 新增一個基於以太坊構建專案,為去中心化科學做出貢獻 + +- [新增交易所](/contributing/adding-exchanges/) – 將交易所新增至我們的[交易所搜尋器](/get-eth/#country-picker) +- [新增產品](/contributing/adding-products/) – 將去中心化應用程式或錢包新增至相關頁面 +- [新增開發者工具](/contributing/adding-developer-tools/) – 將開發者工具新增至相關頁面 +- [新增 Layer 2](/contributing/adding-layer-2s/) – 將 Layer 2 新增至相關頁面 +- [新增質押產品或服務](/contributing/adding-staking-products/) – 新增能促進個人質押、集合質押或質押即服務的專案 +- [新增錢包](/contributing/adding-wallets/) – 為[尋找錢包頁面](/wallets/find-wallet/)新增錢包 +- [為我們的 DeSci 頁面建議專案](/contributing/adding-desci-projects/) – 新增一個基於 Ethereum 建立、對去中心化科學有所貢獻的專案 有問題嗎? 🤔 加入我們的 [Discord 伺服器](https://discord.gg/ethereum-org) @@ -50,65 +55,65 @@ Ethereum.org 是一個開源專案,擁有超過 **12000 名**貢獻者,幫 查看所有任務 -## 如何開展 ethereum.org 相關工作 {#how-to-update-content} +## 如何為 ethereum.org 貢獻 {#how-to-update-content} -如你希望為[翻譯計劃](/contributing/translation-program/)做出貢獻,我們需要你在 [Crowdin](https://crowdin.com/project/ethereum-org) 上建立帳戶。 對於其他事項,例如在網站上新增或編輯內容或視覺效果、修復錯誤、處理未完成的任務,你將需要一個 [GitHub](https://github.com/) 帳戶。 +如果您希望參與[翻譯計畫](/contributing/translation-program/),請在 [Crowdin](https://crowdin.com/project/ethereum-org) 上建立一個帳戶。 至於其他所有事項——例如新增或編輯網站內容或視覺元素、修復程式錯誤、處理待辦任務——您都需要一個 [GitHub](https://github.com/) 帳戶。 -所有更新會透過 GitHub 提取請求 (PR) 流程完成。 這意味著你建立網站的一個本機副本,做出變更並要求合併你的變更。 如你未曾執行過該操作,請遵照 [GitHub 儲存庫](https://github.com/ethereum/ethereum-org-website) 底部的說明。 +所有更新會透過 GitHub 提取請求 (PR) 流程完成。 這意味著你建立網站的一個本機副本,做出變更並要求合併你的變更。 如果您從未這麼做過,請依照我們 [GitHub 儲存庫](https://github.com/ethereum/ethereum-org-website) 底部的說明進行。 你不需要許可即可開始任何工作內容,但最好始終告知我們你打算做什麼。 你可以透過以下方式向我們告知你的計劃: -- 在 [GitHub](https://github.com/ethereum/ethereum-org-website) 內對一個議題或提取請求做出評論 -- 在我們的 [Discord 伺服器](https://discord.gg/ethereum-org)上作訊息交流 +- 在 [GitHub](https://github.com/ethereum/ethereum-org-website) 的議題或提取請求中留言 +- 在我們的 [Discord 伺服器](https://discord.gg/ethereum-org) 上傳送訊息 在做出貢獻前,請確定你熟悉下列內容: -- 不斷演化的 [ethereum.org 願景](/about/) +- 不斷演進的 [ethereum.org 願景](/about/) - 我們的[設計原則](/contributing/design-principles/) - 我們的[風格指南](/contributing/style-guide/) - 我們的[行為準則](/community/code-of-conduct) -## 如何做出有關網站的決定 {#how-decisions-about-the-site-are-made} +## 網站相關決策的制定方式 {#how-decisions-about-the-site-are-made} -有關個人提取請求、設計演進和主要更新的決定由來自整個以太坊生態系統的人員組成的團隊作出。 該團隊包括專案管理人、開發者、設計師、市場和溝通部門,以及內容專家。 社群意見為每個決定提供參考:因此,請在議題中提出問題、提交提取請求或聯絡團隊: +關於個別的提取請求、設計演變和重大升級的決策,是由一個來自整個 Ethereum 生態系的團隊所制定。 此團隊成員包括專案經理、開發人員、設計師、行銷與傳播人員,以及主題專家。 社群的意見是我們每項決策的參考:因此請您在議題中提出問題、提交提取請求或聯絡團隊: - [website@ethereum.org](mailto:website@ethereum.org) - [@ethdotorg](https://twitter.com/ethdotorg) -- [Discord服務器](https://discord.gg/ethereum-org) +- [Discord 伺服器](https://discord.gg/ethereum-org) -### 有關抄襲的說明 {#plagiarism} +### 關於抄襲的注意事項 {#plagiarism} -向 ethereum.org 貢獻任何內容或作品時,請只使用原創作品或你有權使用的內容。 以太坊生態系統內的很多專案使用開放原始碼授權,允許自由分享資訊。 但是,如你未能找到有關開放原始碼授權的資訊,不要嘗試將其新增到 ethereum.org。 任何看似抄襲的提取請求將會被拒絕。 +在為 ethereum.org 貢獻任何內容或產出時,請務必只使用您自己的原創作品,或是您有權使用的內容。 Ethereum 生態系中的許多專案都使用開源授權,允許資訊自由分享。 然而,如果您找不到此類資訊,請勿嘗試將其新增至 ethereum.org。 任何被視為抄襲的提取請求都將被拒絕。 -## 剛開始接觸開放原始碼項目? {#new-to-open-source} +## 剛開始接觸開源專案? {#new-to-open-source} -在我們的 GitHub 儲存庫,問題的准入門檻很低,有些問題特別適合新接觸開放原始碼項目的開發者查看。我們將這類問題標記為[適合入門問題](https://github.com/ethereum/ethereum-org-website/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)。 +我們的 GitHub 儲存庫中有一些低門檻的議題,這些議題專為剛接觸開源的開發人員所設計,並標有 [good first issue](https://github.com/ethereum/ethereum-org-website/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) 標籤。 -## 領取你的鏈上成就代幣 (OAT) {#oat} +## 領取您的鏈上成就代幣 (OAT) {#oat} -如果你的貢獻合併到 ethereum.org,你將有機會在 [Galxe](https://app.galxe.com/quest/ethereumorg) 上領取特殊徽章。 鏈上成就代幣 (OAT) 證明你曾經協助生態系統變得更加出色。 +如果您的貢獻被合併至 ethereum.org,您將有機會在 [Galxe](https://app.galxe.com/quest/ethereumorg) 上領取一枚特殊徽章。 鏈上成就代幣 (OAT) 是您曾協助讓生態系變得更美好的證明。 -[有關鏈上成就代幣的更多資訊](https://help.galxe.com/en/articles/9645630-create-quest-rewards#h_1c5d63ba03) +[關於 OAT 的更多資訊](https://help.galxe.com/en/articles/9645630-create-quest-rewards#h_1c5d63ba03) ### 如何領取 -1. 加入我們的 [Discord 伺服器](https://discord.gg/ethereum-org)。 -2. 將你貢獻內容的連結貼到 `#🥇 | proof-of-contribution` 頻道。 -3. 等待我們團隊的成員向你發送前往你的鏈上成就代幣的連結。 -4. 領取你的鏈上成就代幣! -你應該只用自行保管的錢包來領取鏈上成就代幣。 請勿使用交易所帳戶或你未持有私密金鑰的其他帳戶,因為這些帳戶將不容許你存取和管理你的鏈上成就代幣。 +1. 加入我們的 [Discord 伺服器](https://discord.gg/ethereum-org)。 +2. 將您貢獻內容的連結貼到 `#🥇 | proof-of-contribution` 頻道。 +3. 等待我們團隊的成員傳送您的 OAT 連結給您。 +4. 領取您的 OAT! -## 領取你的 GitPOAP {#claim-gitpoap} +您應該只使用自我託管錢包來領取 OAT。 請勿使用交易所帳戶或您未持有私密金鑰的其他帳戶,因為這些帳戶將不允許您存取及管理您的 OAT。 -GitPOAP 還會自動識別你的合併貢獻,並讓你在其平臺上,鑄造一個獨有的貢獻者 POAP! +## 領取您的 GitPOAP {#claim-gitpoap} +GitPOAP 也會自動辨識您合併的貢獻,讓您在其平台上鑄造一枚專屬的貢獻者 POAP! ### 如何領取 {#how-to-claim} 1. 造訪 [GitPOAP](https://www.gitpoap.io)。 -2. 透過你的錢包建立連接,甚至以電子郵件登入選項來連接。 -3. 搜尋你的 GitHub 使用者名稱、以太幣地址、以太坊域名服務名稱或任何 GitPOAP 以檢查你是否符合條件。 -4. 如果你的 GitHub 帳戶符合條件,那麼你就可以鑄造一個 GitPOAP! +2. 透過登入選項,使用您的錢包或電子郵件進行連接。 +3. 搜尋您的 GitHub 使用者名稱、ETH 地址、ENS 名稱或任何 GitPOAP,以檢查您是否符合資格。 +4. 如果您的 GitHub 帳戶符合資格,您就可以鑄造一枚 GitPOAP! ## 貢獻者 {#contributors} diff --git a/public/content/translations/zh-tw/contributing/quizzes/index.md b/public/content/translations/zh-tw/contributing/quizzes/index.md index fe6123944e4..79ed8b0e15b 100644 --- a/public/content/translations/zh-tw/contributing/quizzes/index.md +++ b/public/content/translations/zh-tw/contributing/quizzes/index.md @@ -1,6 +1,6 @@ --- -title: 新增測驗 -description: 向 ethereum.org 新增測驗時使用的政策 +title: "新增測驗" +description: "向 ethereum.org 新增測驗時使用的政策" lang: zh-tw --- @@ -12,14 +12,14 @@ lang: zh-tw 一些現有測驗的範例可以在下面找到: -- [二層網路](/layer-2) -- [非同質化代幣](/nft/) +- [Layer 2](/layer-2) +- [NFT](/nft/) - [什麼是以太坊?](/what-is-ethereum/) -- [什麼是以太幣?](/what-is-ether/) +- [什麼是 ETH?](/what-is-ether/) ## 新增學習測驗 -如果有頁面尚未建立學習測驗,請為其[建立一個議題](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=&template=suggest_quiz.yaml)。 +如果某個頁面還沒有學習測驗,請[為此建立議題](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=&template=suggest_quiz.yaml)。 請提供以下資訊: @@ -32,7 +32,7 @@ lang: zh-tw ## 新增測驗問題 -如果你想將一個問題新增到測驗的問題庫中,請[建立一個議題](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=&template=suggest_quiz.yaml)並提供以下資訊: +如果您想將問題新增至測驗的題庫中,請[建立議題](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=&template=suggest_quiz.yaml)並提供以下資訊: - 你想新增測驗問題的頁面 - 對於每個問題,請提供以下資訊: @@ -43,7 +43,7 @@ lang: zh-tw ## 更新測驗問題 -如果你想在測驗的問題庫中更新問題,請[建立一個議題](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=&template=suggest_quiz.yaml)並提供以下資訊: +如果您想更新測驗題庫中的某個問題,請[建立議題](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=&template=suggest_quiz.yaml)並提供以下資訊: - 你想更新測驗問題的頁面 - 對於每個更新的問題,請提供以下資訊: @@ -55,7 +55,7 @@ lang: zh-tw ## 刪除測驗問題 -如果頁面上和問題相關的內容不再存在並且需要刪除問題,請[建立一個議題](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=&template=suggest_quiz.yaml)以刪除測驗問題並提供以下資訊: +如果頁面上與某問題相關的內容已不存在而需要移除該問題,請[建立議題](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=&template=suggest_quiz.yaml)以移除該問題並提供以下資訊: - 你想刪除測驗問題的頁面 - 你想刪除的問題 diff --git a/public/content/translations/zh-tw/contributing/translation-program/faq/index.md b/public/content/translations/zh-tw/contributing/translation-program/faq/index.md index 69b6b235f44..91ae1a43363 100644 --- a/public/content/translations/zh-tw/contributing/translation-program/faq/index.md +++ b/public/content/translations/zh-tw/contributing/translation-program/faq/index.md @@ -1,7 +1,7 @@ --- -title: 翻譯計劃常見問題 (FAQ) +title: "翻譯計劃常見問題 (FAQ)" lang: zh-tw -description: ethereum.org 翻譯計劃常見問題 +description: "ethereum.org 翻譯計劃常見問題" --- # ethereum.org 翻譯指南 {#translating-ethereum-guide} diff --git a/public/content/translations/zh-tw/contributing/translation-program/how-to-translate/index.md b/public/content/translations/zh-tw/contributing/translation-program/how-to-translate/index.md index ec37a59882e..c885c34de9b 100644 --- a/public/content/translations/zh-tw/contributing/translation-program/how-to-translate/index.md +++ b/public/content/translations/zh-tw/contributing/translation-program/how-to-translate/index.md @@ -1,7 +1,7 @@ --- -title: 如何翻譯 +title: "如何翻譯" lang: zh-tw -description: 使用 Crowdin 翻譯 ethereum.org 的說明 +description: "使用 Crowdin 翻譯 ethereum.org 的說明" --- # 如何翻譯 {#how-to-translate} diff --git a/public/content/translations/zh-tw/contributing/translation-program/index.md b/public/content/translations/zh-tw/contributing/translation-program/index.md index 05eb4047278..df2a9bdd51d 100644 --- a/public/content/translations/zh-tw/contributing/translation-program/index.md +++ b/public/content/translations/zh-tw/contributing/translation-program/index.md @@ -1,7 +1,7 @@ --- -title: 翻譯計劃 +title: "翻譯計劃" lang: zh-tw -description: 有關 ethereum.org 翻譯計劃的資訊 +description: "有關 ethereum.org 翻譯計劃的資訊" --- # 翻譯計畫 {#translation-program} @@ -36,9 +36,9 @@ ethereum.org 翻譯計劃旨在透過將 ethereum.org 和其他以太坊內容 ### 我們迄今為止取得的進展 {#our-progress} -- [**超過 6,000 位**譯者](/contributing/translation-program/contributors/) +- [超過 6,000 位譯者](/contributing/translation-program/contributors/) - 網站支持 **62** 種語言 -- [2023 年翻譯了 **300 萬**字](/contributing/translation-program/acknowledgements/) +- [2023 年翻譯了 300 萬字](/contributing/translation-program/acknowledgements/) diff --git a/public/content/translations/zh-tw/contributing/translation-program/mission-and-vision/index.md b/public/content/translations/zh-tw/contributing/translation-program/mission-and-vision/index.md index 733dbc905af..3f8a873db69 100644 --- a/public/content/translations/zh-tw/contributing/translation-program/mission-and-vision/index.md +++ b/public/content/translations/zh-tw/contributing/translation-program/mission-and-vision/index.md @@ -1,10 +1,10 @@ --- -title: 使命和願景 +title: "使命和願景" lang: zh-tw -description: ethereum.org 翻譯計畫的使命和願景 +description: "ethereum.org 翻譯計畫的使命和願景" --- -# 使命和願景 {#mission-and-vision} +# 使命與願景 {#mission-and-vision} 以太坊社群旨在成為全球化和包容性的社群,但大部分內容僅面向英語使用者,忽略了全球 60 億非英語使用者。 為了讓 ethereum.org 成為全球社群接觸以太坊的入口網站,我們認為很有必要為非英語國家人士以其母語提供以太坊內容。 diff --git a/public/content/translations/zh-tw/contributing/translation-program/playbook/index.md b/public/content/translations/zh-tw/contributing/translation-program/playbook/index.md new file mode 100644 index 00000000000..ffd55f2fb00 --- /dev/null +++ b/public/content/translations/zh-tw/contributing/translation-program/playbook/index.md @@ -0,0 +1,317 @@ +--- +title: "翻譯程序操作手冊" +lang: zh-tw +description: "建立翻譯項目的實用技巧與重要注意事項合集" +--- + +# 翻譯程序操作手冊 {#translation-program-playbook} + +英語是世界上使用最廣泛的語言之一,也是迄今為止全球學習人數最多的語言。 由於英語是互聯網上最常用的語言——尤其在社交媒體領域——且多語言編程語言較為稀缺,區塊鏈領域的大部分內容都以英語為母語編寫。 + +然而,全球超過60億人(占總人口的75%以上)完全不會說英語,這為絕大多數人接觸以太坊設置了巨大的門檻。 + +正因如此,該領域越來越多的項目正尋求將內容翻譯成不同語言並進行本地化,以面向全球市場。 + +提供多語言內容是拓展全球社區、為非英語使用者提供教育、確保內容與信息觸達更廣泛受眾、並吸引更多人加入該領域的簡單而有效的方式。 + +本指南旨在解決內容本地化過程中常見的挑戰與誤解。 它提供了一個分步指南,涵蓋內容管理、翻譯與審校流程、質量保證、譯員招募以及本地化流程中的其他關鍵環節。 + +## 内容管理 {#content-management} + +翻譯內容管理是指通過自動化翻譯工作流程,消除重複性手動操作,提升效率與質量,實現更佳管控,並促進協作的過程。 + +在本地化過程中,內容管理存在多種不同的方法,具體取決於內容類型和您的需求。 + +管理內容的基本方法是創建雙語文件,其中包含源文本和目標文本。 這種譯法很少被採用,因為除了簡潔之外,它並無顯著優勢。 + +翻譯機構通常通過使用翻譯管理軟件或本地化工具來管理翻譯項目,這些工具不僅具備項目管理功能,還能對文件、內容及譯員實現更全面的管控。 + +閱讀更多關於內容管理: + +[Trados 談什麼是翻譯管理](https://www.trados.com/solutions/translation-management/) + +[關於多語言內容管理的用語](https://phrase.com/blog/posts/multilingual-content-management/) + +### 翻譯管理軟件 {#translation-management-software} + +市面上有許多翻譯管理系統和本地化工具,軟件的選擇主要取決於您的具體需求。 + +儘管某些項目選擇不使用翻譯管理系統,而傾向於手動翻譯——無論是直接在雙語文件中操作,還是藉助GitHub等託管服務——這種做法都會顯著降低項目控制力、生產效率、翻譯質量、可擴展性及協作能力。 這種方法可能最適合小型或一次性翻譯項目。 + +快速了解一些功能強大且廣泛使用的翻譯管理工具: + +**最適合群眾外包與協作** + +[Crowdin](https://crowdin.com/) + +- 開放原始碼專案免費使用(不限字符串數量與專案數量) +- 所有方案皆提供翻譯記憶及詞彙表 +- 支援超過 60 種檔案格式,超過 70 種 API 整合 + +[Lokalise](https://lokalise.com/) + +- 2 位團隊成員可免費使用,更多貢獻者可選擇付費方案 (多數方案的字串數量有限) +- 部分付費方案提供翻譯記憶與詞彙表 +- 支援超過 30 種檔案格式,超過 40 種 API 整合 + +[Transifex](https://www.transifex.com/) + +- 僅提供付費方案 (多數方案的字串數量有限) +- 所有付費方案皆提供翻譯記憶與詞彙表 +- 支援超過 30 種檔案格式,超過 20 種 API 整合 + +[Phrase](https://phrase.com/) + +- 僅提供付費方案 (所有方案的字串數量無上限,但專案及團隊成員數量有限) +- 部分付費方案提供翻譯記憶與詞彙表 +- 支援超過 40 種檔案格式,超過 20 種 API 整合 + +[Smartcat](https://www.smartcat.com/) + +- 提供基本免費方案及付費進階功能 (所有方案的字串與專案數量皆無上限) +- 所有方案皆提供翻譯記憶及詞彙表 +- 支援超過 60 種檔案格式,超過 20 種 API 整合 + +[POEditor](https://poeditor.com/) + +- 開放原始碼專案可免費使用 (所有專案皆有字串數量限制,但開放原始碼專案則無限制) +- 付費方案提供翻譯記憶與詞彙表 +- 支援超過 20 種檔案格式,超過 10 種 API 整合 + +以及其他許多... + +**專業翻譯工具** + +[SDL Trados Studio](https://www.trados.com/products/trados-studio/) + +- 為自由譯者與團隊提供的付費方案 +- 功能強大的電腦輔助翻譯 (CAT) 工具與譯者生產力軟體 + +[MemoQ](https://www.memoq.com/) + +- 提供功能有限的免費版本,以及數種提供進階功能的付費方案 +- 適用於公司、語言服務供應商及譯者的翻譯管理軟體 + +[Memsource](https://www.memsource.com/) + +- 個人譯者可免費使用,並提供數種團隊用付費方案 +- 雲端電腦輔助翻譯與翻譯管理系統 + +以及其他許多... + +進一步了解翻譯管理軟體: + +[維基百科對翻譯管理系統的定義](https://en.wikipedia.org/wiki/Translation_management_system) + +[Phrase 談每個翻譯管理軟體都應具備的 7 件事](https://phrase.com/blog/posts/7-things-every-translation-management-software-should-have/) + +[MemoQ 談什麼是翻譯管理系統](https://www.memoq.com/tools/what-is-a-translation-management-system) + +[Gengo 的 16 個最佳翻譯管理系統清單](https://gengo.com/translator-product-updates/16-best-translation-management-systems/) + +## 工作流程 {#workflow} + +在翻譯領域中,「翻譯工作流程」可指代幾種不同概念,這些概念彼此略有關聯,且都是您專案中需重點考量的要素。 + +我們將在下文探討這兩種情況。 + +**意涵 1** + +這可能是人們理解翻譯工作流程最常見的方式,也是聽到“工作流程”這個詞時通常會想到的內容。 + +本質上,這是從開始考慮翻譯到在產品中使用翻譯內容的整個工作流程。 + +在此情況下,一個示例工作流如下: + +1. **翻譯文件的準備工作**——聽起來很簡單,但你需要考慮幾個重要事項。 在此步驟中,您應該對整個流程的運作方式有清晰的規劃。 + +- _您將使用哪些檔案類型?_ 您希望以何種格式接收翻譯後的文件?_ + - 若您的內容以DOCX或MD格式提供,翻譯過程將比處理PDF版本的白皮書或其他文檔簡單得多。 +- _哪些本地化工具支持此文件类型? 能否在翻譯該文件時保留原始格式?_ + - 並非所有文件類型都支持直接本地化(例如PDF文件、圖像文件),也並非所有本地化工具都支持所有文件類型。 +- _將由誰來翻譯內容?_ 您將選擇專業翻譯服務還是依靠志願者?_ + - 這會影響到你需要做出的其他若干決定。 例如,專業翻譯人員比志願者更擅長使用高級本地化工具。 +- _你對語言學家有什麼期望? 如果您正在使用語言服務供應商,他們對您有什麼期望?_ + - 此步驟是為了確保您的目標、期望和時程規劃能夠保持一致。 +- 所有待譯內容的重要性是否相同? 是否應先翻譯某些內容?_ + - 存在若干方法可用於確定特定內容的優先級,這些內容應優先進行翻譯與實施。 例如,如果你有大量內容需要翻譯,可以使用版本控制來確保譯者清楚哪些內容需要優先處理。 + +2. **共享待譯文件**——這一步驟同樣需要長遠考量,並非像將源文件發送給語言服務供應商那樣簡單直接。 + +- _將由誰來翻譯內容?_ 多少人在這一步驟中被包含了?_ + - 若計劃使用本地化工具,此步驟將得到簡化,因為您可以直接將源文件上傳至該工具。 即使翻譯過程在託管服務上進行,情況也是如此,因為源文件無需導出到任何地方。 +- _源文件將進行人工處理,還是可以實現自動化處理?_ + - 大多數本地化工具都支持某種形式的文件管理流程集成或自動化。 另一方面,若您採用的是獨立譯員協作模式而非本地化工具,手動向數百甚至數千名譯員發送源文件的做法顯然難以實現規模化運作。 +- _本地化將使用哪些工具?_ + - 這個問題的答案將決定你處理其他所有事情的方式。 選擇合適的工具可助您實現內容管理自動化,包括管理翻譯記憶庫和術語庫、管理譯員、追蹤翻譯/審校進度等,因此請花些時間研究您想要使用的工具。 若您不打算使用本地化工具,則上述所有操作均需手動完成。 +- _翻譯過程需要多長時間? 要花多少錢?_ + - 此時,您應該準備好將源文件分享給語言服務提供商或翻譯團隊。 語言服務供應商可協助您分析字數統計並提供報價,其中包含翻譯流程的費率及時間安排。 +- _您是否計劃在此過程中對源內容進行修改/更新?_ + - 如果您的內容具有動態性且頻繁變更,任何修改或更新都可能打亂翻譯進度。 使用翻譯記憶庫可顯著緩解此問題,但仍需仔細規劃工作流程,避免阻礙譯者的翻譯進度。 + +3. **管理翻譯流程**——源內容移交給語言服務供應商或譯員後,您的工作並未結束。 為確保翻譯質量達到最佳水平,內容創作者應儘可能深度參與翻譯流程。 + +- _您計劃如何與譯員進行溝通?_ + - 若您計劃使用本地化工具,溝通可直接在工具內進行。 建議與譯員建立備用溝通渠道,因為他們可能更願意主動聯繫,而即時通訊工具能實現更自由的交流。 +- 如何處理譯者的提問? 誰應該回答這些問題?_ + - 譯者 (無論是專業或非專業) 時常會提出問題、請求釐清、要求更多脈絡資訊,以及提供回饋與改進建議。 回覆這些詢問通常能帶來更高的參與度,並提升翻譯內容的品質。 為他們盡可能提供資源 (例如:指南、提示、術語準則、常見問題等) 也相當有幫助。 +- _如何處理審閱流程?_ 您想將其外包,還是有能力在內部進行審閱?_ + - 雖然並非總是必要,但審閱是最佳翻譯流程中不可或缺的一環。 通常,將審閱流程外包給專業審閱者是最簡單的方法。 然而,若您有大型的國際團隊,審閱或品質保證 (QA) 也可以在內部進行。 + +4. **導入翻譯內容** – 這是工作流程的最後一個部分,但仍需提前考量。 + +- _所有翻譯都會同時完成嗎?_ + - 若否,您應思考哪些翻譯應優先處理、如何追蹤進行中的翻譯,以及翻譯完成後如何處理導入作業。 +- _翻譯好的內容將如何交付給您?_ 會是哪種格式?_ + - 無論您採用哪種方法,這都是一個重要的考量。 在地化工具能讓您掌控目標檔案格式與匯出流程,且通常支援自動化,例如:透過與託管服務整合。 +- _您將如何在專案中導入翻譯?_ + - 在某些情況下,可能只是簡單地將翻譯好的檔案上傳,或將其新增至您的文件中。 然而,對於更複雜的專案,例如網站或應用程式翻譯,您應確保程式碼支援國際化,並提前規劃好導入流程將如何處理。 +- _如果格式與原始檔案不同該怎麼辦?_ + - 與上述類似,如果您翻譯的是簡單的文字檔,格式可能就不是那麼重要。 然而,對於更複雜的檔案,例如網站或應用程式的內容,其格式和程式碼必須與原始檔案完全相同,才能導入您的專案。 否則,目標檔案將需要由譯者或您的開發人員進行編輯。 + +**意涵 2** + +另一種翻譯工作流程,其不考量內部決策與方法。 這裡的主要考量是內容本身的流程。 + +在此情況下,一個示例工作流如下: + +1. _翻譯 → 導入_ + +- 最簡單的工作流程,其中翻譯很可能是人工翻譯,因為在導入前沒有審閱或品質保證流程來評估品質和編輯翻譯。 +- 在這個工作流程中,譯者能維持一定的品質非常重要,這將需要專案經理和譯者之間有適當的資源和溝通。 + +2. _翻譯 → 審閱 → 導入_ + +- 一個更進階的工作流程,其中包含審閱和編輯過程,以確保翻譯品質可接受且一致。 +- 這個工作流程有多種方法,翻譯可由專業譯者或志願者進行,而審閱過程則可能由專業審閱者處理,他們熟悉目標語言中需要遵守的所有文法和拼寫規則。 + +3. _翻譯 → 審閱 → 品質保證 → 導入_ + +- 確保最高品質水準的最佳工作流程。 雖然品保 (QA) 並非總是必要,但它有助於讓您在翻譯和審閱後,更清楚地了解翻譯文本的品質。 +- 透過這個工作流程,翻譯可以完全由志願者甚至機器翻譯來執行。 審閱過程應由專業譯者執行,而品保 (QA) 可由語言服務供應商執行,或者如果公司內部有目標語言的母語員工,也可以在內部進行。 + +進一步了解翻譯工作流程: + +[Content Rules 談翻譯工作流程的五個階段](https://contentrules.com/creating-translation-workflow/) + +[Smartling 談什麼是翻譯工作流程管理](https://www.smartling.com/resources/101/what-is-translation-workflow-management/) + +[RixTrans 談翻譯工作流程](https://www.rixtrans.com/translation-workflow) + +## 術語管理 {#terminology-management} + +建立處理術語的明確計畫,是確保翻譯品質和一致性,並節省譯者時間的最重要步驟之一。 + +在翻譯領域,這被稱為術語管理,是語言服務供應商除了提供語言專家人才庫和內容管理之外,為其客戶提供的關鍵服務之一。 + +術語管理是指識別、收集和管理對您的專案至關重要,且應始終被正確且一致地翻譯的術語的過程。 + +開始思考術語管理時,可以遵循以下幾個步驟: + +- 識別應納入術語庫的關鍵術語。 +- 建立術語及其定義的詞彙表。 +- 翻譯術語並將其新增至詞彙表。 +- 檢查並核准翻譯。 +- 維護詞彙表,並在出現新的重要術語時進行更新。 + +進一步了解術語管理: + +[Trados 談什麼是術語管理](https://www.trados.com/solutions/terminology-management/translation-101-what-is-terminology-management.html) + +[Language Scientific 談術語管理的重要性](https://www.languagescientific.com/terminology-management-why-it-matters/#:~:text=Terminology%20management%20is%20the%20process,are%20related%20to%20each%20other.) + +[Clear Words Translation 談什麼是術語管理及其重要性](http://clearwordstranslations.com/language/en/what-is-terminology-management/) + +### 翻譯記憶與詞彙表 {#tm-and-glossary} + +翻譯記憶 (TM) 和詞彙表是翻譯產業的重要工具,也是大多數語言服務供應商所依賴的東西。 + +讓我們來看看這些術語的含義,以及它們之間的區別: + +**翻譯記憶 (TM)** – 一個自動儲存句段或字串的資料庫,包括較長的文本區塊、完整句子、段落和個別術語,以及它們在各種語言中的當前和先前翻譯。 + +大多數在地化工具、翻譯管理系統和電腦輔助翻譯工具都內建翻譯記憶,這些翻譯記憶通常也可以匯出並在其他類似工具中使用。 + +使用翻譯記憶的好處包括:更快的翻譯速度、更好的翻譯品質、在更新或變更原始內容時保留特定翻譯的能力,以及降低重複內容的翻譯成本。 + +翻譯記憶根據不同句段之間的百分比匹配度運作,當兩個句段包含超過 50% 的相同內容時,通常最為有用。 它們也用於自動翻譯重複的句段 (100% 匹配),從而無需多次翻譯重複的內容。 + +進一步了解翻譯記憶: + +[Memsource 談翻譯記憶](https://www.memsource.com/translation-memory/) + +[Smartling 談什麼是翻譯記憶](https://www.smartling.com/resources/101/what-is-translation-memory/) + +**詞彙表 –** 一份包含重要或敏感術語、其定義、功能和既定翻譯的清單。 詞彙表和翻譯記憶之間的主要區別在於,詞彙表不是自動建立的,且不包含完整句子的翻譯。 + +大多數在地化工具、翻譯管理系統和電腦輔助翻譯工具都有內建的詞彙表,您可以維護這些詞彙表,以確保它們包含對您專案重要的術語。 與翻譯記憶 (TM) 一樣,詞彙表通常也可以匯出並在其他在地化工具中使用。 + +在開始翻譯專案之前,強烈建議您花一些時間為您的譯者和審閱者建立一份詞彙表。 使用詞彙表可以確保重要術語被正確翻譯,為譯者提供必要的脈絡,並保證翻譯的一致性。 + +雖然詞彙表通常包含目標語言的既定翻譯,但即使沒有這些翻譯,它們也很有用。 即使沒有既定的翻譯,詞彙表也可以提供技術術語的定義,標示出不應翻譯的術語,並告知譯者某個特定術語是用作名詞、動詞、專有名詞還是任何其他詞性。 + +進一步了解詞彙表: + +[Lionbridge 談什麼是翻譯詞彙表](http://info.lionbridge.com/rs/lionbridge/images/Lionbridge%20FAQ_Glossary_2013.pdf) + +[Transifex 談詞彙表](https://docs.transifex.com/glossary/glossary) + +如果您不打算在專案中使用在地化工具,您可能無法使用翻譯記憶和詞彙表 (您可以在 Excel 檔案中建立詞彙表或術語庫,但是,自動化的詞彙表免去了譯者手動查找術語及其定義的需要)。 + +這意味著所有重複和相似的內容每次都必須手動翻譯。 此外,譯者將不得不詢問某些術語是否需要翻譯、它們在文本中如何使用,以及某個術語是否已有既定翻譯等問題。 + +_您想在您的專案中使用 ethereum.org 的翻譯記憶和詞彙表嗎?_ 請透過 translations@ethereum.org 與我們聯絡。_ + +## 譯者聯繫與招募 {#translator-outreach} + +**與語言服務供應商合作** + +如果您正在與語言服務供應商及其專業譯者合作,本節可能與您不太相關。 + +在這種情況下,選擇一個有能力以多種語言提供您所需全部服務 (例如,翻譯、審閱、品保) 的語言服務供應商非常重要。 + +雖然僅根據報價來選擇語言服務供應商可能很誘人,但值得注意的是,最大的語言服務供應商收費較高是有原因的。 + +- 他們的資料庫中有數以萬計的語言專家,這意味著他們能夠為您的專案指派具有足夠經驗和特定領域知識的譯者 (即技術譯者)。 +- 他們在處理不同專案和滿足客戶多樣化需求方面擁有豐富的經驗。 這意味著他們更有可能適應您的特定工作流程,為您的翻譯流程提供有價值的建議和潛在的改進,並滿足您的需求、要求和期限。 +- 大多數大型語言服務供應商也擁有自己的在地化工具、翻譯記憶和詞彙表供您使用。 即使沒有,他們的人才庫中至少有足夠的語言專家,以確保其譯者熟悉並能夠使用您想使用的任何在地化工具。 + +您可以在 [2021 Nimdzi 100 報告](https://www.nimdzi.com/nimdzi-100-top-lsp/)中找到對全球最大語言服務供應商的深入比較,以及關於每家供應商的一些詳細資訊,和按其提供的服務、地理數據等分類的分析。 + +**與非專業譯者合作** + +您可能正在與非專業譯者合作,並尋找志願者來幫助您翻譯。 + +有多種方法可以聯繫人們並邀請他們加入您的專案。 這在很大程度上取決於您的產品以及您已有的社群規模。 + +以下概述了一些招募志願者的方法: + +**聯繫與招募 –** 雖然這在以下幾點中有所涉及,但聯繫潛在的志願者並確保他們了解您的翻譯計畫本身就是一種有效的方法。 + +許多人想參與並為他們喜愛的專案做出貢獻,但如果不是開發人員或沒有特殊技術技能,他們往往看不到明確的方法。 如果您能提高專案的知名度,很多雙語人士可能會熱衷於參與。 + +**從您的社群內部尋找 –** 該領域的大多數專案都已經擁有龐大而活躍的社群。 您的許多社群成員可能會很樂意有機會以簡單的方式為專案做出貢獻。 + +雖然對開放原始碼專案的貢獻通常是基於內在動機,但這也是一個絕佳的學習體驗。 任何有興趣進一步了解您的專案的人,都很可能會樂意以志願者身份參與翻譯計畫,因為這能讓他們將「為自己在乎的事物做出貢獻」與「密集的實作學習體驗」結合起來。 + +**在您的產品中提及此計畫 –** 如果您的產品很受歡迎且有大量使用者,在使用者使用產品時,突顯您的翻譯計畫並呼籲他們採取行動,可能會非常有效。 + +對於應用程式和網站,這可以像在您的產品中添加帶有行動呼籲 (CTA) 的橫幅或彈出視窗一樣簡單。 這是有效的,因為您的目標受眾是您的社群——那些最有可能首先參與的人。 + +**社群媒體 –** 社群媒體是宣傳您的翻譯計畫、聯繫您的社群成員以及尚未成為您社群成員的其他人的有效方式。 + +如果您有 Discord 伺服器或 Telegram 頻道,可以輕易地利用它們進行聯繫、與譯者溝通以及表揚您的貢獻者。 + +像 X (前身為 Twitter) 這樣的平台也有助於招募新的社群成員和公開表揚您的貢獻者。 + +Linux 基金會撰寫了一份詳盡的 [2020 年 FOSS 貢獻者調查報告](https://www.linuxfoundation.org/wp-content/uploads/2020FOSSContributorSurveyReport_121020.pdf),分析了開放原始碼貢獻者及其動機。 + +## 結論 {#conclusion} + +本文件包含每個翻譯計畫都應了解的一些關鍵考量因素。 這絕不是一份詳盡的指南,但它可以幫助任何在翻譯行業沒有經驗的人為他們的專案組織一個翻譯計畫。 + +如果您正在尋找關於管理翻譯計畫的不同工具、流程和關鍵方面的更詳細說明和分析,一些最大的語言服務供應商會維護部落格並經常發表關於在地化流程不同方面的文章。 如果您想深入探討上述任何主題,並了解在地化流程在專業上是如何運作的,這些是最好的資源。 + +每個部分的末尾都包含一些相關連結;但是,您可以在網路上找到許多其他資源。 + +如果您有合作提案,或想了解更多資訊、經驗和我們透過維護 ethereum.org 翻譯計畫所學到的最佳實踐,請隨時透過 translations@ethereum.org 與我們聯絡。 diff --git a/public/content/translations/zh-tw/contributing/translation-program/resources/index.md b/public/content/translations/zh-tw/contributing/translation-program/resources/index.md index 8b9a74e2644..6ce14c56283 100644 --- a/public/content/translations/zh-tw/contributing/translation-program/resources/index.md +++ b/public/content/translations/zh-tw/contributing/translation-program/resources/index.md @@ -1,7 +1,7 @@ --- -title: 供譯者使用的資源 +title: "供譯者使用的資源" lang: zh-tw -description: 對 ethereum.org 譯者有用的資源 +description: "對 ethereum.org 譯者有用的資源" --- # 資源 {#resources} diff --git a/public/content/translations/zh-tw/contributing/translation-program/translatathon/details/index.md b/public/content/translations/zh-tw/contributing/translation-program/translatathon/details/index.md new file mode 100644 index 00000000000..fea71dcf770 --- /dev/null +++ b/public/content/translations/zh-tw/contributing/translation-program/translatathon/details/index.md @@ -0,0 +1,90 @@ +--- +title: "詳細資訊與規則" +lang: zh-tw +template: translatathon +--- + +![](./participate.png) + +翻譯松是公開的,任何人都可以透過填寫申請表並加入 Crowdin 上的專案來參與。 + +在翻譯期間,譯者可以透過在 Crowdin 編輯器中為其語言中未翻譯的字串提供翻譯來收集積分。 + +每位參賽者的最終分數取決於他們在翻譯期間所翻譯的字數在排行榜上的排名,以及他們所收集到的任何潛在的額外積分。 + +## 入門 {#getting-started} + +翻譯過程在 Crowdin 的 ethereum.org 專案中進行,譯者為未翻譯的字串提供翻譯,這些字串幾乎包含了 ethereum.org 網站的所有內容。 + +翻譯建議直接在線上編輯器中提供,因此無需下載或上傳任何檔案或交付項目。 每個翻譯的字都會被追蹤和計算。 + +**1) 加入專案** + +- 若要開始貢獻,請加入 [Crowdin 上的 ethereum.org 專案](https://crowdin.com/project/ethereum-org) +- 您需要登入或建立帳戶—只需一個電子郵件地址和密碼即可 + +**2) 選擇您的語言** + +- 在目標語言清單中找到您的語言,然後按一下其名稱或旗幟來開啟 +- 如果您想翻譯成尚未提供的語言,請在 Crowdin 上聯絡 [Ethereum.org 團隊](https://crowdin.com/profile/ethdotorg),或傳送電子郵件至 translations@ethereum.org,我們將根據請求新增其他目標語言 + +**3) 開啟未翻譯的檔案** + +- 找到第一個未翻譯的檔案開始翻譯。 包含來源檔案的資料夾是根據優先順序排列的,所以您應該從包含未翻譯檔案的第一個資料夾開始翻譯 +- 每個檔案都有一個進度指示器,顯示檔案中可翻譯內容已翻譯和核准的程度… 如果任何檔案的翻譯進度低於 100%,請進行翻譯 + +**4) 翻譯未翻譯的字串** + +- 當您開啟要翻譯的檔案時,請確保您只翻譯未翻譯的字串! +- 每個字串都有一個狀態指示器,顯示其狀態為「_已翻譯_」、「_未翻譯_」或「_已核准_」。 如果來源字串在您的語言中已經有建議的翻譯,則無需再翻譯 +- 您也可以在編輯器中篩選字串以顯示「_未翻譯優先_」或「_僅顯示未翻譯_」 + +有關導覽和使用 Crowdin 編輯器的詳細指南,我們建議所有翻譯松參賽者閱讀我們的[如何翻譯](/contributing/translation-program/how-to-translate/)指南。 + +您也可以查看我們的[翻譯風格指南](/contributing/translation-program/translators-guide/),找到一些訣竅和最佳實踐。 + +**積分如何運作** + +每位翻譯松參賽者都可以透過翻譯 ethereum.org Crowdin 專案和其他符合資格的專案 (下面提供了符合資格的專案的完整清單) 中的內容來賺取積分,計入其最終分數。 + +計分方式很簡單:**1 個翻譯的字 = 1 分** + +為了獲得最終的積分分配,您建議的翻譯需要通過評估過程,專業審稿人將檢查每位參賽者的翻譯,以確保它們符合最低品質門檻,並且在過程中沒有使用機器或人工智慧翻譯。 + +## 生態系內容 {#ecosystem-content} + +由於 ethereum.org 翻譯計畫一直在進行中,網站上某些目標語言的翻譯進度明顯高於其他語言。 + +為了確保所有翻譯松參賽者都有平等的機會盡可能多地翻譯內容並爭奪最高獎項,作為翻譯松一部分的來源內容不僅限於 ethereum.org 網站內容。 + +翻譯任何符合資格的專案的參賽者都將獲得等量的積分,任何專案中 1 個翻譯的字 = 1 分。 + +以下是 2025 年翻譯松中所有符合資格的專案的清單: + +- [Ethereum.org](https://crowdin.com/project/ethereum-org) + +- [Ethereum.org 開發者教學](https://crowdin.com/project/33388446abbe9d7aa21e42e49bba7f97) + +- [EthStaker 存款命令列介面](https://crowdin.com/project/ethstaker-deposit-cli) + +- [Eth Docker 文件](https://crowdin.com/project/eth-docker-docs) + +- [Remix IDE 文件](https://crowdin.com/project/remix-translation) + +- [Remix LearnEth](https://crowdin.com/project/remix-learneth) + +- [web3.py](https://crowdin.com/project/web3py) + +## 評估過程 {#evaluation-process} + +所有翻譯都將接受品質保證和意見回饋,專業語言學家將根據品質和準確性評估提交的內容。 + +我們還將使用一些自動偵測機器或人工智慧翻譯的工具來執行**反機器翻譯措施**。 + +雖然翻譯品質在計分中不會扮演關鍵角色,但任何**被發現使用機器或人工智慧翻譯**或提供低品質和不準確翻譯的參賽者將沒有資格獲獎! + +評估期將在整個 9 月進行,結果將在 9 月 25 日的 ethereum.org 社群電話會議上宣布。 + +所有翻譯在新增至網站前也會經過全面審核。 + + diff --git a/public/content/translations/zh-tw/contributing/translation-program/translatathon/index.md b/public/content/translations/zh-tw/contributing/translation-program/translatathon/index.md new file mode 100644 index 00000000000..b4fc8f50c03 --- /dev/null +++ b/public/content/translations/zh-tw/contributing/translation-program/translatathon/index.md @@ -0,0 +1,100 @@ +--- +title: "2025 ethereum.org 翻譯松" +lang: zh-tw +template: translatathon +--- + + + + + + + +## 介紹 {#introduction} + +我們相信,無論人們使用何種語言,都應該能輕鬆取得以太坊的內容和入門資源。 +為了更接近這個目標,ethereum.org 翻譯計畫是一項旨在將網站翻譯成盡可能多種語言的倡議。 + +作為翻譯計畫的一部分,我們正在舉辦第三屆翻譯松,這是一項翻譯競賽,旨在鼓勵較少活躍語言的翻譯貢獻、增加網站上可用語言的數量和內容、引導新貢獻者加入,並獎勵我們現有的貢獻者。 + +如果您是英語以外語言的母語人士,並希望在爭奪獎品的同時幫助以太坊內容更容易被取得,請繼續閱讀以了解更多! + +[了解更多關於 ethereum.org 翻譯計畫的資訊](/contributing/translation-program/) + +## 時程 {#timeline} + +以下是 2025 年翻譯松的重要日期: + + + + + +## 參與 {#participate} + +![社群和地球的圖片](./participate.png) + + + +

誰可以參加?

+ 任何年滿 18 歲、以至少一種非英語語言為母語,且精通英語的人。 +
+ +

我需要是專業譯者嗎?

+ 否。 您只需要具備雙語能力並提交人工翻譯(禁止使用機器翻譯!) 盡您所能即可,不要求專業經驗。 +
+
+ + + +

我需要投入多少時間?

+ 投入多少時間由您決定。 獲得獎品資格的最低門檻是翻譯 1,000 個字,這大約需要 2 個小時才能完成,而爭奪最高獎項則需要投入更多的時間。 +
+ +

我需要熟悉以太坊嗎?

+ 否。 雖然熟悉以太坊有助於提高您的效率和品質,但翻譯松也是一個學習的體驗,我們邀請每個人在參與的同時,加入並學習更多關於以太坊的知識。 +
+
+ +欲知更多詳情,[請參閱完整的條款與條件](/contributing/translation-program/translatathon/terms-and-conditions) + +### 逐步說明 {#step-by-step-instructions} + + + +## 獎品 {#prizes} + +| 名次 | 獎金金額 | +| ------------- | ----- | +| 第 1 名 | $4000 | +| 第 2 名 | $2500 | +| 第 3 名 | $1500 | +| 第 4 名 | $1100 | +| 第 5 名 | $1000 | +| 第 6 名 | $600 | +| 第 7 名 | $550 | +| 第 8 名 | $500 | +| 第 9 名 | $450 | +| 第 10 名 | $400 | +| 第 11 - 20 名 | $240 | +| 第 21 - 50 名 | $120 | +| 第 51 - 100 名 | $60 | +| 第 101 - 150 名 | $40 | +| 其餘 | $20 | + +所有獎品都將以 ETH 支付。 + + + + diff --git a/public/content/translations/zh-tw/contributing/translation-program/translators-guide/index.md b/public/content/translations/zh-tw/contributing/translation-program/translators-guide/index.md index 78a31cf57c9..6fd38c62cec 100644 --- a/public/content/translations/zh-tw/contributing/translation-program/translators-guide/index.md +++ b/public/content/translations/zh-tw/contributing/translation-program/translators-guide/index.md @@ -1,7 +1,7 @@ --- -title: 譯者指南 +title: "譯者指南" lang: zh-tw -description: 給 ethereum.org 譯者的說明和小提示 +description: "給 ethereum.org 譯者的說明和小提示" --- # Ethereum.org 翻譯風格指南 {#style-guide} @@ -10,15 +10,15 @@ Ethereum.org 翻譯風格指南包含一些給譯者的最重要的準則、說 這份文件是一份通用指南,並不特定於任何一種語言。 -如你有任何問題、建議或意見回饋,請隨時透過 translations@ethereum.org 聯絡我們,在 Crowdin 上向 @ethdotorg 傳送訊息,或者[加入我們的 Discord](https://discord.gg/ethereum-org),你可以在當中透過 #translations 頻道聯絡我們,或者聯絡任何團隊成員。 +如果您有任何問題、建議或意見回饋,歡迎隨時透過 translations@ethereum.org 聯絡我們、在 Crowdin 上傳送訊息給 @ethdotorg,或是[加入我們的 Discord](https://discord.gg/ethereum-org)。您可以在 #translations 頻道中傳送訊息給我們,或聯絡任何團隊成員。 ## 使用 Crowdin {#using-crowdin} -你可以在[翻譯計劃頁面](/contributing/translation-program/#how-to-translate)中找到有關如何在 Crowdin 中加入專案以及如何使用 Crowdin 線上編輯器的基本說明。 +您可以在[翻譯計畫頁面](/contributing/translation-program/#how-to-translate)上找到關於如何在 Crowdin 加入專案以及如何使用 Crowdin 線上編輯器的基本說明。 -若你想要學習更多有關 Crowdin 及如何使用其某些進階功能的資訊,[Crowdin 知識庫](https://support.crowdin.com/online-editor/)內有很多針對所有 Crowdin 功能的深度指南和總觀。 +如果您想深入了解 Crowdin 及其進階功能,[Crowdin 知識庫](https://support.crowdin.com/online-editor/)提供了大量關於 Crowdin 所有功能的深入指南和總覽。 -## 傳達訊息的重點 {#capturing-the-essence} +## 掌握訊息精髓 {#capturing-the-essence} 翻譯 ethereum.org 的內容時,請避免字面翻譯。 @@ -36,7 +36,7 @@ Ethereum.org 翻譯風格指南包含一些給譯者的最重要的準則、說 多數印歐語係和亞非語係語言都使用特定於性別的第二人稱人稱代詞,以區分男性和女性。 在稱呼使用者或或使用所有格代名詞時,我們可以避免對訪客的性別作出假設,因為正式的稱呼形式通常適用且一致,無論他們如何定位自己的性別。 -## 簡單清楚的詞彙和意思 {#simple-vocabulary} +## 簡單明瞭的詞彙與意義 {#simple-vocabulary} 我們的目標是讓盡可能多的人能夠理解網站上的內容。 @@ -50,17 +50,17 @@ Ethereum.org 透過拉丁語外的不同書寫系統(或書寫腳本)提供 翻譯內容時,應該確保翻譯內容一致,且不包含任何拉丁字符。 -一個常見的錯誤觀念:Ethereum 應該一直用拉丁文來書寫。 這在大多情況下都是不正確的,請根據你的語言而改變「以太坊」的拼字(如在中文中是「以太坊」,在阿拉伯文中是「إيثيريوم」)。 +一個常見的錯誤觀念:Ethereum 應該一直用拉丁文來書寫。 這在大多數情況下是錯誤的,請使用您語言中原生的「Ethereum」拼法 (例如:中文的「以太坊」、阿拉伯文的「إيثيريوم」等等)。 **以上規則不適用於通常不應翻譯專有名詞的語言。** -## 翻譯頁面中繼資料 {#translating-metadata} +## 翻譯頁面元資料 {#translating-metadata} 某些頁面含有頁面上的中繼資料,像「title」、「lang」、「description」、「sidebar」等等。 在將新頁面上傳到 Crowdin 時,我們隱藏了譯者不應該翻譯的內容,這意味著 Crowdin 中對譯者可見的所有中繼資料都應該翻譯。 -翻譯源文本為「en」的任何語句中,請格外留意。 這代表頁面提供的語言,並且應該翻譯為[你的語言的 ISO 語言代碼](https://www.andiamo.co.uk/resources/iso-language-codes/)。 這些字串應該始終翻譯為拉丁文字元,而不是對應目標語言的書寫腳本。 +翻譯源文本為「en」的任何語句中,請格外留意。 這代表頁面可用的語言,應翻譯為[您語言的 ISO 語言代碼](https://www.andiamo.co.uk/resources/iso-language-codes/)。 這些字串應該始終翻譯為拉丁文字元,而不是對應目標語言的書寫腳本。 如你不確定要使用哪個語言代碼,可以在 Crowdin 中查看翻譯記憶,或在 Crowdin 線上編輯器中的頁面 URL 內尋找目標語言的語言代碼。 @@ -72,21 +72,24 @@ Ethereum.org 透過拉丁語外的不同書寫系統(或書寫腳本)提供 - 印地語 - hi - 西班牙語 - es -## 外部文章的標題 {#external-articles} +## 外部文章標題 {#external-articles} 一些語句中包含外部文章的標題。 我們的大多數開發者文件頁面,都包含外部文章的連結以供進一步閱讀。 不論文章是何種語言,都需要翻譯包含文章標題的語句,以確保以母語檢視頁面的訪客取得一致的使用者體驗。 你可以在下方找到譯者會遇到的這類字串,以及如何辨認出這類字串(文章的連結大多位於頁面底部的「延伸閱讀」區段): -![sidebar.png 中的文章標題](./article-titles-in-sidebar.png) ![editor.png 中的文章標題](./article-titles-in-editor.png) +![側邊欄中的文章標題](./article-titles-in-sidebar.png) +![編輯器中的文章標題](./article-titles-in-editor.png) ## Crowdin 警告 {#crowdin-warnings} -Crowdin 有一個內建功能,在譯者即將出錯時發出警告。 在儲存翻譯之前,如果你忘記包含原文中的標籤、翻譯了不應翻譯的元素、添加了多個連續空格、忘記結尾標點符號等,Crowdin 會自動警告你。 若你看見這類警告,請返回並仔細檢查你所提議的翻譯。 +Crowdin 有一個內建功能,在譯者即將出錯時發出警告。 在儲存翻譯之前,如果你忘記包含原文中的標籤、翻譯了不應翻譯的元素、添加了多個連續空格、忘記結尾標點符號等,Crowdin 會自動警告你。 +若你看見這類警告,請返回並仔細檢查你所提議的翻譯。 -**永遠不要忽視這類警告,因為它們通常意味著翻譯存在問題,或者缺少源文本中的關鍵部分。** +**切勿忽略這些警告,因為它們通常代表出現錯誤,或是譯文缺少了原文的關鍵部分。** -當你忘記在翻譯中新增標籤時會出現的 Crowdin 警告範例: ![Crowdin 警告範例](./crowdin-warning-example.png) +當您忘記在譯文中新增標籤時,Crowdin 會發出警告,範例如下: +![Crowdin 警告範例](./crowdin-warning-example.png) ## 處理標籤和程式碼片段 {#dealing-with-tags} @@ -96,15 +99,18 @@ Crowdin 有一個內建功能,在譯者即將出錯時發出警告。 在儲 為了更輕鬆地管理標籤並直接從原文複製它們,我們建議在 Crowdin 編輯器中更改你的設定。 -1. 開啟設定 ![如何在編輯器中開啟設定](./editor-settings.png) +1. 開啟設定 + ![如何在編輯器中開啟設定](./editor-settings.png) 2. 向下捲動至「HTML tags displaying」區段 -3. 選擇「Hide」 ![請選擇「Hide」](./hide-tags.png) +3. 選取「隱藏」 + ![請選取「隱藏」](./hide-tags.png) 4. 按一下「Save」 -透過選擇此選項,完整的標籤文本將不再顯示,並會替換為數字。 翻譯時,點擊該標籤會自動將準確的標籤複製到翻譯欄位。 +透過選擇此選項,完整的標籤文本將不再顯示,並會替換為數字。 +翻譯時,點擊該標籤會自動將準確的標籤複製到翻譯欄位。 **連結** @@ -116,7 +122,7 @@ Crowdin 有一個內建功能,在譯者即將出錯時發出警告。 在儲 ![link.png 的例子](./example-of-link.png) -連結也會以標籤的形式出現在源文本中(即 `<0>` ``). 若你將滑鼠停留在標籤上,編輯器將顯示標籤的全部內容 - 有時候這些標籤將會代表連結。 +連結也會以標籤的形式 (即 `<0>` ``) 出現在原文中。 若你將滑鼠停留在標籤上,編輯器將顯示標籤的全部內容 - 有時候這些標籤將會代表連結。 從原文複製連結並且不要改變連結的順序是很重要的。 @@ -130,21 +136,21 @@ Crowdin 有一個內建功能,在譯者即將出錯時發出警告。 在儲 標籤始終包含一個開始和結束標籤。 在多數情況下,開始標籤和結束標籤中間的文字應該翻譯。 -例子:``Decentralized`` +範例:``去中心化`` -`` - _讓文字變粗體的開始標籤_ +`` - _讓文字變粗體的開頭標籤_ -Decentralized - _可翻譯的文字_ +去中心化 - _可翻譯的文字_ `` - _結束標籤_ -![「strong」tags.png 的例子](./example-of-strong-tags.png) +![「strong」標籤範例](./example-of-strong-tags.png) 程式碼片段的處理方式與其他標籤略有不同,因為其包含不應翻譯的程式碼。 -例子:``nonce`` +範例:``nonce`` -`` - _開始標籤,其中含有一個程式碼片段_ +`` - _開頭標籤,內含程式碼片段_ nonce - _不可翻譯的文字_ @@ -154,13 +160,13 @@ nonce - _不可翻譯的文字_ 原文還包含縮短的標籤,這類標籤只含有數字,這意味著標籤的功能不明顯。 你可以將滑鼠停留在這些標籤上,查看標籤的確切功能。 -在下面的例子中,可以看見滑鼠停留在標籤上時, `<0>` 會顯示標籤代表 ``,並且含有一個程式碼片段,因此標籤內的內容不應該翻譯。 +在下方的範例中,您可以看到將滑鼠懸停在 `<0>` 標籤上會顯示它代表 `` 並包含程式碼片段,因此不應翻譯這些標籤內的內容。 ![意義含糊的 tags.png 例子](./example-of-ambiguous-tags.png) -## 簡短與完整形式/縮寫 {#short-vs-full-forms} +## 縮寫與完整形式/簡稱 {#short-vs-full-forms} -網站上使用很多縮寫,例如 dapps、NFT、DAO、DeFi 等等。 這些縮寫通常用於英語,並且多數網站的訪客都熟悉這些縮寫。 +網站上使用了許多縮寫,例如:dapps、NFT、DAO、DeFi 等等。 這些縮寫通常用於英語,並且多數網站的訪客都熟悉這些縮寫。 由於這些縮寫通常在其他語言中沒有既定翻譯,處理這些或類似術語最佳方法是提供完整形式的描述性翻譯,並在括號中添加英文縮寫。 @@ -168,9 +174,9 @@ nonce - _不可翻譯的文字_ 如何翻譯 dapps 的例子: -- Decentralized applications (dapps) → _完整翻譯形式 (括號內為英文縮寫)_ +- 去中心化應用程式 (dapps) → _翻譯後的完整形式 (括號中為英文縮寫)_ -## 沒有既定翻譯的術語 {#terms-without-established-translations} +## 尚無通用譯名的術語 {#terms-without-established-translations} 某些術語在其他語言中可能沒有既定翻譯,並且以原始英語術語的形式廣為人知。 這類術語主要包括較新的概念,如工作量證明、權益證明、信標鏈、質押等。 @@ -178,19 +184,19 @@ nonce - _不可翻譯的文字_ 翻譯時,請自由發揮創意,使用描述性翻譯,或直接按字面翻譯。 -**大多數術語應該翻譯而不是將其中一些保留英文的原因是,隨著越來越多的人開始使用以太坊和相關技術,這種新術語將在未來變得更加普及。 如果我們想讓來自世界各地的更多人加入這個領域,我們需要以盡可能多的語言提供易於理解的術語,即使需要我們自行創建這些術語。** +**之所以大多數術語都應翻譯,而非保留部分英文原文,是因為隨著越來越多人開始使用以太坊和相關技術,這些新術語在未來將會變得更普及。 如果我們想讓世界各地更多人加入這個領域,我們就需要用盡可能多的語言提供易於理解的術語,即使需要我們自行創建也一樣。** -## 按鈕和行動呼籲 {#buttons-and-ctas} +## 按鈕和行動呼籲 (CTA) {#buttons-and-ctas} 網站包含很多按鈕,其翻譯方式與其他內容不同。 可以透過檢視上下文螢幕擷取畫面、與大多數字串連結或通過查看編輯器中的上下文(包括詞語「按鈕」)來辨認出按鈕文字。 -按鈕的翻譯應該越短越好,以防止格式不匹配。 此外,按鈕翻譯應採用命令式,如:呈現命令或請求。 +按鈕的翻譯應該越短越好,以防止格式不匹配。 此外,按鈕翻譯應採用命令式,即呈現命令或請求。 ![如何尋找 button.png](./how-to-find-a-button.png) -## 翻譯的包容性 {#translating-for-inclusivity} +## 具包容性的翻譯 {#translating-for-inclusivity} Ethereum.org 的訪客來自世界各地和不同的背景。 因此,網站上的語言應該是中性的,歡迎所有人且沒有排他性。 @@ -208,7 +214,7 @@ Ethereum.org 的訪客來自世界各地和不同的背景。 因此,網站上 需要特別留意事項的具體例子: -### 標點符號、格式 {#punctuation-and-formatting} +### 標點符號與格式 {#punctuation-and-formatting} **大寫** @@ -220,8 +226,8 @@ Ethereum.org 的訪客來自世界各地和不同的背景。 因此,網站上 - 正字法規則定義了每種語言中空格的使用。 由於空格的使用很廣泛,所以這些規則最獨特,而空格是最容易錯譯的元素。 - 英語和其他語言在空格用法上的一些常見差異: - - 測量和貨幣單位(如:USD、EUR、kB、MB)前的空格 - - 溫度符號(如:°C、℉)前的空格 + - 測量和貨幣單位 (例如:USD、EUR、kB、MB) 前的空格 + - 溫度符號 (例如:°C、℉) 前的空格 - 一些標點符號前的空格,尤其是省略號 (…) - 斜線 (/) 前後的空格 @@ -229,7 +235,7 @@ Ethereum.org 的訪客來自世界各地和不同的背景。 因此,網站上 - 每種語言都有一套多樣化和複雜的規則來編寫清單。 這些規則可能與英語大不相同。 - 在一些語言中,每個新行的第一個字詞需要大寫,而在其他語言中,新行應以小寫字母開頭。 許多語言對清單中的大小寫也有不同的規則,具體取決於每行的長度。 -- 這同樣適用於列項目的標點符號。 清單中的結束標點可以是句號(**。**)、逗號(**,**)、或分號(**;**),具體取決於語言。 +- 這同樣適用於列項目的標點符號。 清單中的結尾標點符號可以是句號 (**.**)、逗號 (**,**),或分號 (**;**),視語言而定。 **引號** @@ -253,10 +259,10 @@ Ethereum.org 的訪客來自世界各地和不同的背景。 因此,網站上 - 不同語言中,數字書寫的主要區別是小數和千位數的分離符號。 對於千位數,分隔符號可以是句號、逗號或空格。 同樣,一些語言使用句號小數點,而其他語言則使用逗號小數點。 - 一些大數的例子: - - 英語 - **1,000.50** - - 西班牙語 - **1.000,50** - - 法語 - **1 000,50** -- 在翻譯數字時,另外一個重要考慮因素是百分比符號。 它能以不同方法書寫:**100%**、**100 %**或**%100**。 + - 英文 – **1,000.50** + - 西班牙文 – **1.000,50** + - 法文 – **1 000,50** +- 在翻譯數字時,另外一個重要考慮因素是百分比符號。 其寫法有多種方式:**100%**、**100 %** 或 **%100**。 - 最後,依據語言類型,負數可以有不同的形式:-100、100-、(100) 或 [100]。 **日期** diff --git a/public/content/translations/zh-tw/dao/index.md b/public/content/translations/zh-tw/dao/index.md index 2299c3d4590..18a899afd37 100644 --- a/public/content/translations/zh-tw/dao/index.md +++ b/public/content/translations/zh-tw/dao/index.md @@ -1,16 +1,16 @@ --- -title: 什麽是去中心化自治組織 (DAO)? -metaTitle: 什麽是去中心化自治組織 (DAO)? | 去中心化自治組織 -description: 以太坊上的去中心化自治組織概要 +title: "什麽是去中心化自治組織 (DAO)?" +metaTitle: "什麽是去中心化自治組織 (DAO)? | 去中心化自治組織" +description: "以太坊上的去中心化自治組織概要" lang: zh-tw template: use-cases emoji: ":handshake:" sidebarDepth: 2 image: /images/use-cases/dao-2.png -alt: 在對提案投票的去中心化自治組織代表。 -summaryPoint1: 沒有中心化領導的成員共有社群。 -summaryPoint2: 一個與網路上陌生人合作的安全方式。 -summaryPoint3: 一個將資產投入特定事業的安全場所。 +alt: "在對提案投票的去中心化自治組織代表。" +summaryPoint1: "沒有中心化領導的成員共有社群。" +summaryPoint2: "一個與網路上陌生人合作的安全方式。" +summaryPoint3: "一個將資產投入特定事業的安全場所。" --- ## 什麼是去中心化自治組織 {#what-are-daos} @@ -19,7 +19,7 @@ summaryPoint3: 一個將資產投入特定事業的安全場所。 去中心化自治組織使我們不需信任一個良善的領導者來管理資金或經營,便能與世界各地志趣相投的人們共事。 沒有執行長能夠衝動使用資金,也沒有財務長可以作假帳。 取而代之的是,由基於區塊鏈上程式碼所制定的規則來定義組織如何運作以及如何使用資金。 -組織擁有自己的資金庫,未經團體核准,任何人都無權使用。 決策經由提案和投票來治理,以確保每位組織成員都能發聲,且任何事都在[鏈上](/glossary/#on-chain)進行,公開透明。 +組織擁有自己的資金庫,未經團體核准,任何人都無權使用。 決策由提案和投票治理,以確保組織中的每個人都有發言權,且所有事情都在[鏈上](/glossary/#onchain)透明地進行。 ## 為何我們需要去中心化自治組織? {#why-dao} @@ -37,23 +37,23 @@ summaryPoint3: 一個將資產投入特定事業的安全場所。 | 以去中心化方式自動提供服務(例如慈善基金的分配)。 | 需要人工處理,或集中管控自動處理,易受操縱。 | | 所有活動皆完全公開透明。 | 活動通常是隱密進行,公開程度有限。 | -### 去中心化自治組織範例 {#dao-examples} +### DAO 範例 {#dao-examples} 為了幫助你了解,以下略舉幾個去中心化自治組織的使用範例: -- **慈善機構** – 你可以接受來自全世界任何人的捐贈,並投票決定要資助的事業。 +- **慈善機構** – 你可以接受來自全世界任何人的捐款,並投票決定資助的事業。 - **共同擁有權** – 你可以購買實體或虛擬資產,且組織成員可以對如何使用資產進行投票。 -- **風險投資和資助** – 你可以成立風險基金,透過該基金匯集投資資本並投票決定要進行的風險投資。 後續收益可以分配給相應的去中心化自治組織成員。 +- **風險投資和補助** – 你可以創建一個風險基金來匯集投資資本,並投票決定要支持的投資項目。 後續收益可以分配給相應的去中心化自治組織成員。 ## 去中心化自治組織如何運作? {#how-daos-work} -去中心化自治組織的基礎為其[智慧型合約](/glossary/#smart-contract),該合約定義組織的規則,並對該團體的資金庫進行規範。 一旦在以太坊上部署合約,除非投票通過,否則不能修改規則。 任何不符合程式碼規則和邏輯的行為都會失效。 由於資金庫也是以智慧型合約定義,因此任何人都無法不經團體核准而挪用資金。 這意味著去中心化自治組織不需要中心化管理機構。 相反地,團體會共同做出決定,而付款會在投票通過之後自動獲得授權。 +DAO 的骨幹是它的[智慧型合約](/glossary/#smart-contract),它定義了組織的規則並持有該組織的資金庫。 一旦在以太坊上部署合約,除非投票通過,否則不能修改規則。 任何不符合程式碼規則和邏輯的行為都會失效。 由於資金庫也是以智慧型合約定義,因此任何人都無法不經團體核准而挪用資金。 這意味著去中心化自治組織不需要中心化管理機構。 相反地,團體會共同做出決定,而付款會在投票通過之後自動獲得授權。 之所以能夠做到這一點,是因為智慧型合約一旦部署於以太坊,就無法被篡改。 一切都是公開的,只要有人修改程式碼(去中心化自治組織的規則)就會被發現。 -## 以太坊與去中心化自治組織 {#ethereum-and-daos} +## 以太坊與 DAO {#ethereum-and-daos} 以太坊為去中心化自治組織提供了極佳的基礎,原因如下: @@ -62,105 +62,105 @@ summaryPoint3: 一個將資產投入特定事業的安全場所。 - 智慧型合約可以發送/接收資金。 如果少了這點,你就需要可信的中間人來管理團體的資金。 - 事實證明,比起競爭,以太坊社群更趨向合作,使得最佳做法和支援系統得以快速發展。 -## 去中心化自治組織的治理 {#dao-governance} +## DAO 管理體系 {#dao-governance} 治理去中心化自治組織時有許多考量,例如投票及提案該如何運作。 -### 授權 {#governance-delegation} +### 委派 {#governance-delegation} 委託類似去中心化自治組織版本的代議民主。 代幣持有者向自我提名、並承諾管理協定且掌握最新消息的使用者委託選票。 -#### 知名案例 {#governance-example} +#### 一個著名的例子 {#governance-example} -[以太坊名稱服務](https://claim.ens.domains/delegate-ranking) – 以太坊名稱服務持有者可將其選票委託給參與活動的社群成員,以代表他們。 - -### 自動交易治理 {#governance-example} +### 自動交易管理體系 {#governance-example} 在許多去中心化自治組織中,如達法定人數的成員投票同意,交易將自動執行。 -#### 知名案例 {#governance-example} +#### 一個著名的例子 {#governance-example} -[Nouns](https://nouns.wtf) – 在去中心化組織 Nouns 中,如票數達法定數量且大多數票投票同意,只要不被創辦人所否決,交易就會自動執行。 +[Nouns](https://nouns.wtf) – 在 Nouns DAO 中,如果達到法定票數且多數票投下贊成票,只要創辦人沒有否決,交易就會自動執行。 -### 多簽治理 {#governance-example} +### 多重簽名管理體系 {#governance-example} -雖然去中心化自治組織可有成千上萬的投票成員,資金可存放在一個由 5-20 名受信任且通常資訊公開(有社群所知的公開身份)的活躍社群成員共管的[錢包](/glossary/#wallet)中。 投票後,[多簽](/glossary/#multisig)簽署人會執行社群的意願。 +雖然 DAO 可能有數千名投票成員,但資金可以存放在一個由 5-20 名受信任且通常身份公開(其公開身份為社群所知)的活躍社群成員所共享的[錢包](/glossary/#wallet)中。 投票後,[多重簽名](/glossary/#multisig)簽署人會執行社群的意願。 -## 去中心化自治組織相關法律 {#dao-laws} +## DAO 法律 {#dao-laws} 1977 年,懷俄明州創造了有限責任公司制度,以保護企業家並限定其責任。 更近期,懷俄明州首創去中心化自治組織相關法律,給予去中心化自治組織法律地位。 目前,懷俄明州、佛蒙特州以及維京群島皆建立某種形式的去中心化自治組織相關法律。 -### 知名案例 {#law-example} +### 一個著名的例子 {#law-example} -[CityDAO](https://citizen.citydao.io/) – CityDAO 透過懷俄明州去中心化自治組織的相關法律購買了黃石國家公園附近 40 英畝的地。 +[CityDAO](https://citizen.citydao.io/) – CityDAO 透過懷俄明州的 DAO 相關法律,購買了黃石國家公園附近 40 英畝的土地。 -## 去中心化自治組織成員 {#dao-membership} +## DAO 成員資格 {#dao-membership} 去中心化自治組織的成員有多種模式。 成員可以決定投票方式和去中心化自治組織的其他重要事務。 -### 代幣型成員 {#token-based-membership} +### 代幣制成員資格 {#token-based-membership} -通常完全[無需許可](/glossary/#permissionless),視所用的代幣而定。 這類治理代幣大部分都能在[去中心化交易所](/glossary/#dex)自由交易,無需許可。 其他少部分則必須透過提供流動性或其他某些「工作量證明」來賺取。 無論是哪一種方式,只要持有代幣就能獲得投票權。 +通常完全[無需許可](/glossary/#permissionless),取決於所使用的代幣。 這些治理代幣大多可以在[去中心化交易所](/glossary/#dex)上無需許可地交易。 其他少部分則必須透過提供流動性或其他某些「工作量證明」來賺取。 無論是哪一種方式,只要持有代幣就能獲得投票權。 -_通常用於治理廣泛的去中心化協定及/或代幣本身。_ +_通常用於治理廣泛的去中心化協定及/或代幣本身。_ -#### 知名案例 {#token-example} +#### 一個著名的例子 {#token-example} [MakerDAO](https://makerdao.com) – MakerDAO 的代幣 MKR 在去中心化交易所廣泛提供,且任何人皆可買進投票權來決定 Maker 協定的未來。 -### 股份型成員 {#share-based-membership} +### 股份制成員資格 {#share-based-membership} 股份型去中心化自治組織擁的許可制程度更高,但仍然相當公開。 任何潛在的成員都可以申請加入去中心化自治組織,通常以代幣或工作的形式提供有價值的貢獻。 股份代表直接投票權及所有權。 成員可以隨時帶著自己所佔的資金庫股份退出。 -_通常用於關係較為緊密、以人為中心的組織,例如慈善機構、勞工團體、投資俱樂部等, 也可以治理協定及代幣。_ +_通常用於關係較為緊密、以人為本的組織,例如慈善機構、工人合作社與投資俱樂部。 也可以治理協定和代幣。_ -#### 知名案例 {#share-example} +#### 一個著名的例子 {#share-example} [MolochDAO](http://molochdao.com/) – MolochDAO 致力於資助以太坊專案。 想加入為成員必須提出申請,以便團體評估你是否具備必要的專業知識和資本來對潛在的受資助者作出明智判斷。 你無法直接在公開市場購買加入該去中心化自治組織的資格。 -### 信譽型成員 {#reputation-based-membership} +### 信譽制成員資格 {#reputation-based-membership} 信譽代表參與證明,並能授予去中心化自治組織的投票權。 不同於代幣型或股份型成員,信譽型去中心化自治組織不會將所有權轉讓給貢獻者。 信譽不能購買、移轉或委託;去中心化自治組織成員必須透過參與來獲得信譽。 鏈上投票無需許可,潛在成員可以自由提出加入去中心化自治組織的申請,並要求獲得信譽和代幣作為其貢獻的獎勵。 -_通常用於協定和[去中心化應用程式](/glossary/#dapp)的去中心化開發及治理,但也非常適合各種組織,如慈善機構、勞工團體、投資俱樂部等。_ +_通常用於協定和[去中心化應用程式](/glossary/#dapp)的去中心化開發及管理體系,但也非常適合各種組織,如慈善機構、工人合作社、投資俱樂部等。_ -#### 知名案例 {#reputation-example} +#### 一個著名的例子 {#reputation-example} -[DXdao](https://DXdao.eth.limo) – DXdao 是一個全球主權聯合組織,自 2019 年以來一直致力於建構與治理去中心化協定和應用程式。 它利用信譽型治理和[全息共識](/glossary/#holographic-consensus)來協調和管理資金,這意味著沒有人可以透過金錢來影響其未來或治理決策。 +[DXdao](https://DXdao.eth.limo) – DXdao 是一個全球主權集體,自 2019 年以來一直致力於建構與治理去中心化協定和應用程式。 它利用以信譽為基礎的管理體系和[全息共識](/glossary/#holographic-consensus)來協調和管理資金,這意味著沒有人可以透過金錢來影響其未來或管理體系。 -## 參與/建立去中心化自治組織 {#join-start-a-dao} +## 加入/創立 DAO {#join-start-a-dao} -### 加入去中心化自治組織 (DAO) {#join-a-dao} +### 加入 DAO {#join-a-dao} -- [以太坊社群去中心化自治組織](/community/get-involved/#decentralized-autonomous-organizations-daos) -- [DAOHaus 的去中心化自治組織清單](https://app.daohaus.club/explore) -- [Tally.xyz 的去中心化自治組織清單](https://www.tally.xyz) +- [以太坊社群 DAO](/community/get-involved/#decentralized-autonomous-organizations-daos) +- [DAOHaus 的 DAO 列表](https://app.daohaus.club/explore) +- [Tally.xyz 的 DAO 列表](https://www.tally.xyz/explore) +- [DeGov.AI 的 DAO 列表](https://apps.degov.ai/) -### 建立去中心化自治組織 {#start-a-dao} +### 創立 DAO {#start-a-dao} -- [使用 DAOHaus 建立去中心化自治組織](https://app.daohaus.club/summon) -- [使用 Tally 建立一個治理者型去中心化自治組織](https://www.tally.xyz/add-a-dao) -- [建立由 Aragon 支援的去中心化自治組織](https://aragon.org/product) -- [建立 colony](https://colony.io/) -- [使用 DAOstack 全息共識建立去中心化自治組織](https://alchemy.daostack.io/daos/create) +- [用 DAOHaus 召喚一個 DAO](https://app.daohaus.club/summon) +- [用 Tally 創立一個 Governor DAO](https://www.tally.xyz/get-started) +- [創建一個由 Aragon 驅動的 DAO](https://aragon.org/product) +- [啟動一個 Colony](https://colony.io/) +- [用 DAOstack 的全息共識創建 DAO](https://alchemy.daostack.io/daos/create) +- [用 DeGov 啟動器發佈一個 DAO](https://docs.degov.ai/integration/deploy) ## 延伸閱讀 {#further-reading} -### 去中心化自治組織相關文章 {#dao-articles} +### DAO 文章 {#dao-articles} -- [什麼是去中心化自治組織?](https://aragon.org/dao)– [Aragon](https://aragon.org/) -- [去中心化自治組織之家](https://wiki.metagame.wtf/docs/great-houses/house-of-daos) – [Metagame](https://wiki.metagame.wtf/) -- [何謂去中心化自治組織?它有何用途?](https://daohaus.substack.com/p/-what-is-a-dao-and-what-is-it-for)– [DAOhaus](https://daohaus.club/) -- [如何創立由去中心化自治組織支援的數位社群](https://daohaus.substack.com/p/four-and-a-half-steps-to-start-a) – [DAOhaus](https://daohaus.club/) -- [什麼是去中心化自治組織?](https://coinmarketcap.com/alexandria/article/what-is-a-dao)– [Coinmarketcap](https://coinmarketcap.com) -- [什麼是全息共識?](https://medium.com/daostack/holographic-consensus-part-1-116a73ba1e1c)- [DAOstack](https://daostack.io/) -- [Vitalik,《去中心化自治組織並非法人團體:去中心化在自治組織裡的重要之處》](https://vitalik.eth.limo/general/2022/09/20/daos.html) -- [去中心化自治組織、去中心化自治公司、去中心化應用程式等:不完整術語指引](https://blog.ethereum.org/2014/05/06/daos-dacs-das-and-more-an-incomplete-terminology-guide) - [以太坊部落格](https://blog.ethereum.org) +- [什麼是 DAO?](https://aragon.org/dao) – [Aragon](https://aragon.org/) +- [DAO 之家](https://wiki.metagame.wtf/docs/great-houses/house-of-daos) – [Metagame](https://wiki.metagame.wtf/) +- [什麼是 DAO?它有什麼用?](https://daohaus.substack.com/p/-what-is-a-dao-and-what-is-it-for) – [DAOhaus](https://daohaus.club/) +- [如何啟動一個由 DAO 驅動的數位社群](https://daohaus.substack.com/p/four-and-a-half-steps-to-start-a) – [DAOhaus](https://daohaus.club/) +- [什麼是 DAO?](https://coinmarketcap.com/alexandria/article/what-is-a-dao) – [Coinmarketcap](https://coinmarketcap.com) +- [什麼是全息共識?](https://medium.com/daostack/holographic-consensus-part-1-116a73ba1e1c) - [DAOstack](https://daostack.io/) +- [DAOs 並非公司:Vitalik 談去中心化在自治組織中的重要性](https://vitalik.eth.limo/general/2022/09/20/daos.html) +- [DAO、DAC、DA 等等:不完全術語指南](https://blog.ethereum.org/2014/05/06/daos-dacs-das-and-more-an-incomplete-terminology-guide) - [以太坊部落格](https://blog.ethereum.org) ### 影片 {#videos} -- [什麼是加密貨幣世界的去中心化自治組織?](https://youtu.be/KHm0uUPqmVE) -- [一個去中心化自治組織是否能建立一座城市?](https://www.ted.com/talks/scott_fitsimones_could_a_dao_build_the_next_great_city)– [TED](https://www.ted.com/) +- [加密貨幣中的 DAO 是什麼?](https://youtu.be/KHm0uUPqmVE) +- [DAO 能建造一座城市嗎?](https://www.ted.com/talks/scott_fitsimones_could_a_dao_build_the_next_great_city) – [TED](https://www.ted.com/) diff --git a/public/content/translations/zh-tw/decentralized-identity/index.md b/public/content/translations/zh-tw/decentralized-identity/index.md index c7f3555470d..e6977b9fb12 100644 --- a/public/content/translations/zh-tw/decentralized-identity/index.md +++ b/public/content/translations/zh-tw/decentralized-identity/index.md @@ -1,25 +1,25 @@ --- -title: 去中心化身分 -description: 什麼是去中心化身分,它為什麼很重要? +title: "去中心化身分" +description: "什麼是去中心化身分,它為什麼很重要?" lang: zh-tw template: use-cases emoji: ":id:" sidebarDepth: 2 image: /images/eth-gif-cat.png -summaryPoint1: 傳統身分系統對你的身分識別進行中心化發行、維護和控制。 -summaryPoint2: 去中心化身分消除了對中心化第三方的依賴。 -summaryPoint3: 多虧了加密技術,使用者現在擁有了再次發行、持有和控制自身身分識別和證明的工具。 +summaryPoint1: "傳統身分系統對你的身分識別進行中心化發行、維護和控制。" +summaryPoint2: "去中心化身分消除了對中心化第三方的依賴。" +summaryPoint3: "多虧了加密技術,使用者現在擁有了再次發行、持有和控制自身身分識別和證明的工具。" --- 現如今,身分幾乎支撐著我們生活的方方面面。 使用線上服務、開設銀行帳戶、選舉投票、購買房產、就業,所有這些事情都需要證明你的身分。 -然而,傳統的身分管理系統長期以來一直依賴於中心化中間機構來發行、持有和控制你的身分識別和[身分證明](/glossary/#attestation)。 這意味著你無法掌控自己身分的相關資訊,也無法決定誰能夠存取你的個人身分資訊 (PII),以及各方擁有多大的訪問權限。 +然而,傳統的身分管理系統長期以來一直仰賴中心化的中介機構來發行、持有和控制您的身分識別和[證明](/glossary/#attestation)。 這意味著你無法掌控自己身分的相關資訊,也無法決定誰能夠存取你的個人身分資訊 (PII),以及各方擁有多大的訪問權限。 -為了解決這些問題,我們在以太坊等公共區塊鏈上構建了去中心化身分系統。 去中心化身分允許每個人管理他們的身分相關資訊。 借助去中心化身分解決方案,_你_可以建立身分識別、聲明和持有你的身分證明,而無需依賴於中央機構,例如服務提供方或是政府。 +為了解決這些問題,我們在以太坊等公共區塊鏈上構建了去中心化身分系統。 去中心化身分允許每個人管理他們的身分相關資訊。 有了去中心化身分解決方案,_您_就可以建立身分識別、宣告並持有您的證明,而無需仰賴服務供應商或政府等中心化機構。 ## 什麼是身分認同? {#what-is-identity} -身分意味著個人的自我意識,由獨特的特徵定義。 身分是指作為一個_個體_,即一個獨特的人類實體。 身分也可以是指其他非人類的實體,例如組織或機構。 +身分意味著個人的自我意識,由獨特的特徵定義。 身分指的是作為一個_個體_,即一個獨特的人類實體。 身分也可以是指其他非人類的實體,例如組織或機構。 @@ -27,7 +27,7 @@ summaryPoint3: 多虧了加密技術,使用者現在擁有了再次發行、 身分識別是一些資訊,用來指向一個特定身分或多個身分。 常見的身分識別包含: -- 姓名 +- 名稱 - 社會安全號碼/稅務識別號碼 - 手機號碼 - 出生日期和出生地點 @@ -39,15 +39,15 @@ summaryPoint3: 多虧了加密技術,使用者現在擁有了再次發行、 1. 去中心化身分增加了個人對身分識別資訊的掌握。 可以在無需依賴中心化機構和第三方服務的情況下,驗證去中心化身分識別和身分證明。 -2. 去中心化身分解決方案為驗證和管理使用者身分,提供了一種去信任、無縫且保護隱私的方法。 +2. 去中心化身分解決方案為驗證和管理使用者身分,提供了一種無須信任、順暢且保護隱私的方法。 3. 去中心化身分利用區塊鏈技術,在不同方之間建立信任,並提供加密擔保來驗證身分證明的有效性。 -4. 去中心化身分使得身分資料具有可便攜性。 使用者將身分證明和身分識別儲存在行動裝置錢包中,並可以分享給他們選擇的任一夥伴。 去中心化身分識別和身分證明不會被鎖在發行組織的資料庫中。 +4. 去中心化身分使得身分資料具有可便攜性。 使用者將證明和身分識別儲存在行動錢包中,並可與其選擇的任何一方分享。 去中心化身分識別和身分證明不會被鎖在發行組織的資料庫中。 -5. 去中心化身分與新興的[零知識證明](/glossary/#zk-proof)技術應能完美搭配,這將使個人能夠證明他們擁有某物或做過某些事,而無需透露那是什麼。 這可以成為一種將信任與隱私結合在一起的強而有力方案,適用於投票等應用方面。 +5. 去中心化身分應能與新興的[零知識](/glossary/#zk-proof)技術良好地配合,使個人能夠證明他們擁有某物或做過某事,而無需揭露那是什麼。 這可以成為一種將信任與隱私結合在一起的強而有力方案,適用於投票等應用方面。 -6. 去中心化身分能夠[防範女巫攻擊](/glossary/#anti-sybil)機制,識別一人分飾多角玩弄某系統,或向該系統發送垃圾訊息的情況。 +6. 去中心化身分能啟用[反女巫](/glossary/#anti-sybil)機制,以識別單一個人假冒成多人來濫用或向某個系統傳送垃圾訊息的情況。 ## 去中心化身分使用案例 {#decentralized-identity-use-cases} @@ -55,15 +55,15 @@ summaryPoint3: 多虧了加密技術,使用者現在擁有了再次發行、 ### 1. 通用登入 {#universal-dapp-logins} -去中心化身分可以使用去中心化驗證,有助於替代基於密碼的登入方式。 服務提供商可以向使用者簽發身分證明,這些證明可以儲存在以太坊錢包中。 一個身分證明範例是[非同質化代幣](/glossary/#nft),可以授予持有者訪問線上社群的權利。 +去中心化身分可以使用去中心化驗證,有助於替代基於密碼的登入方式。 服務提供商可以向使用者簽發身分證明,這些證明可以儲存在以太坊錢包中。 證明的一個範例是 [NFT](/glossary/#nft),它能授予持有者存取線上社群的權限。 -[使用以太坊登入](https://siwe.xyz/)功能將允許伺服器能夠確認使用者的以太坊帳戶,並從他們的帳戶地址中獲取所需的身分證明。 這意味著使用者無需記住冗長的密碼,就能夠訪問平台和網站,進而改善使用者的線上體驗。 +接著,[使用以太坊登入](https://siwe.xyz/)功能可讓伺服器確認使用者的以太坊帳戶,並從其帳戶地址擷取所需的證明。 這意味著使用者無需記住冗長的密碼,就能夠訪問平台和網站,進而改善使用者的線上體驗。 -### 2. 「認識客戶」驗證 {#kyc-authentication} +### 2. KYC 驗證 {#kyc-authentication} 許多線上服務的使用,需要提供個人的身分證明和憑證,例如駕駛執照或國家護照。 但這種方式是有問題的,因為使用者的私人資訊有可能會被洩露,並且服務提供商無法驗證身分證明的真實性。 -去中心化身分使公司能夠跳過傳統的[了解你的客戶 (KYC)](https://en.wikipedia.org/wiki/Know_your_customer) 流程,並透過可驗證憑證來核實使用者身分。 這降低了身份管理的成本,並防止使用偽造文件。 +去中心化身分讓公司可以跳過傳統的[了解你的客戶 (KYC)](https://en.wikipedia.org/wiki/Know_your_customer) 流程,並透過可驗證憑證來驗證使用者身分。 這降低了身份管理的成本,並防止使用偽造文件。 ### 3 投票和線上社群 {#voting-and-online-communities} @@ -73,41 +73,67 @@ summaryPoint3: 多虧了加密技術,使用者現在擁有了再次發行、 ### 4 反女巫保護 {#sybil-protection} -使用[平方投票法](/glossary/#quadratic-voting)的捐款應用程式很容易受到[女巫攻擊](/glossary/#sybil-attack),因為當更多人投票支持時,捐款的價值就會增加,這會激勵使用者將他們的貢獻分配給多個身分。 去中心化身分透過增加每位參與者的負擔來證明他們是真正的人,這有助於防止這種情況發生,而且通常也不必透露具體的私人資訊。 +使用[二次方投票](/glossary/#quadratic-voting)的補助金發放應用程式容易受到[女巫攻擊](/glossary/#sybil-attack)的影響,因為當越多人投票給某個補助金時,其價值就會增加,從而誘使使用者將其貢獻分散到許多身分中。 去中心化身分透過增加每位參與者的負擔來證明他們是真正的人,這有助於防止這種情況發生,而且通常也不必透露具體的私人資訊。 + +### 5 國家和政府 ID {#national-and-government-id} + +政府可以利用去中心化身分的原則,將國民身分證、護照或駕照等基礎身分文件作為以太坊上的可驗證憑證發行,提供強大的密碼學真偽保證,以減少線上身分驗證中的詐欺和偽造。 公民可以將這些證明儲存在個人[錢包](/wallets/)中,並用來證明其身分、年齡或投票權。 + +此模型允許選擇性揭露,特別是在與[零知識證明 (ZKP)](/zero-knowledge-proofs/) 隱私技術結合時。 例如,公民可以透過密碼學證明自己已滿 18 歲,以存取有年齡限制的服務,而無需透露其確切的出生日期,這比傳統 ID 提供了更高的隱私性。 + +#### 💡案例研究:不丹在以太坊上的國家數位 ID (NDI) {#case-study-bhutan-ndi} + +- 為不丹近 80 萬公民提供可驗證的身分憑證存取權限 +- 於 2025 年 10 月從 Polygon 網路[遷移至以太坊主網](https://www.bhutanndi.com/article/bhutan-adopts-ethereum-for-national-identity-a-new-chapter-in-digital-sovereignty_2d0c7ec2-5605-4c42-b258-bd9361ae8878) +- 截至 2025 年 3 月,已發行超過 [234,000 個數位 ID](https://www.blockchain-council.org/blockchain/bhutan-uses-blockchain-in-digital-id-project/) + +不丹王國於 2025 年 10 月將其[國家數位身分 (NDI) 系統遷移](https://www.bhutanndi.com/article/bhutan-adopts-ethereum-for-national-identity-a-new-chapter-in-digital-sovereignty_2d0c7ec2-5605-4c42-b258-bd9361ae8878)至以太坊。 不丹的 NDI 系統建構於去中心化身分和自主身分的原則之上,使用去中心化身分識別和可驗證憑證,將數位簽署的憑證直接發行到公民的個人錢包中。 透過將這些憑證的密碼學證明錨定在以太坊上,該系統確保它們是真實、防竄改的,並且任何一方都可以在不查詢中心機構的情況下進行驗證。 + +該系統的架構透過使用[零知識證明 (ZKP)](/zero-knowledge-proofs/) 技術來強調隱私。 這種「選擇性揭露」的實作允許公民證明特定事實 (例如「我已滿 18 歲」或「我是公民」) 以存取服務,而無需透露其完整的身分證號碼或確切的出生日期等底層個人資料。 這展示了以太坊在安全、以使用者為中心和保護隱私的國家 ID 系統方面的強大實際應用。 + +#### 💡案例研究:布宜諾斯艾利斯市在以太坊 [Layer 2](/layer-2/) ZKSync Era 上的 QuarkID {#case-study-buenos-aires-quarkid} + +- 在推出時向超過 [360 萬名使用者](https://buenosaires.gob.ar/innovacionytransformaciondigital/miba-con-tecnologia-quarkid-la-ciudad-de-buenos-aires-incorporo)發行了去中心化身分憑證 +- QuarkID 是一個開源協定,被聯合國永續發展目標認定為[數位公共財](https://www.digitalpublicgoods.net/r/quarkid) +- 強調「[政府即使用者](https://buenosaires.gob.ar/innovacionytransformaciondigital/miba-con-tecnologia-quarkid-la-ciudad-de-buenos-aires-incorporo)」模型,市政府不擁有該協定,賦予公民完整的資料所有權和隱私 + +2024 年,布宜諾斯艾利斯市政府 (GCBA) 將 QuarkID 整合到 miBA 中,QuarkID 是由 GCBA 創新和數位轉型秘書處建構的開源「數位信任框架」,而 miBA 則是該市居民用來存取政府服務和官方文件的官方應用程式。 推出時,miBA 的所有 360 萬以上使用者都獲得了去中心化數位身分,讓他們可以在鏈上管理和分享可驗證的數位文件和證書,包括公民身分憑證、出生、結婚和死亡證明、稅務記錄、疫苗接種記錄等。 + +QuarkID 系統建構於以太坊 [Layer 2](/layer-2/) 網路 ZKSync Era 之上,使用 ZKP 技術讓公民可以透過行動裝置對等驗證個人憑證,而無需揭露不必要的個人資料。 該計畫強調了「政府即使用者」模型,其中 GCBA 作為開源、可互通的 QuarkID 協定的一名使用者,而非中心化的擁有者。 這種支援 ZKP 的架構提供了一個關鍵的隱私功能:任何第三方,甚至 GCBA,都無法追蹤公民如何、何時或為何使用其憑證。 這個成功的計畫為公民提供了完整的自主身分和對其敏感資料的控制權,所有這些都由以太坊的全球分散式網路提供保護。 ## 什麼是身分證明 {#what-are-attestations} 身分證明是由一個實體提出的關於另一個實體的聲明。 如果你居住在美國,你的駕駛執照是由機動車輛管理局(一個實體)發布,它證明你(另一個實體)在法律上允許駕駛汽車。 -身分證明與身分識別不同。 身分證明_包含_用於指向特定身分的身分識別,並聲明與此身分相關的屬性。 因此,你的駕駛執照具有身分識別(姓名、出生日期、地址),但也是關於你合法駕駛權利的證明。 +身分證明與身分識別不同。 證明_包含_用來指稱特定身分的身分識別,並對與此身分相關的屬性進行宣告。 因此,你的駕駛執照具有身分識別(姓名、出生日期、地址),但也是關於你合法駕駛權利的證明。 ### 什麼是去中心化身分識別? {#what-are-decentralized-identifiers} 你的法定姓名或電子郵件地址等傳統身分識別依賴於第三方——政府和電子郵件提供商。 去中心化身分識別 (DID) 則不同-它們不由任何中央實體發行、管理或控制。 -去中心化身分識別由個人發行、持有和控制。 [以太坊帳戶](/glossary/#account)是去中心化身分識別的一個範例。 你可以根據需要建立任意數量的帳戶,無需任何人的許可,也無需將它們儲存在中央註冊系統中。 +去中心化身分識別由個人發行、持有和控制。 一個[以太坊帳戶](/glossary/#account)就是去中心化身分識別的一個範例。 你可以根據需要建立任意數量的帳戶,無需任何人的許可,也無需將它們儲存在中央註冊系統中。 -去中心化身分識別儲存在分散式帳本([區塊鏈](/glossary/#blockchain))或[點對點網路](/glossary/#peer-to-peer-network)上。 這使得去中心化身分識別 (DID) 具有[全球唯一性、高可用的可解析性、和加密驗證性](https://w3c-ccg.github.io/did-primer/)。 去中心化身份識別可與不同的實體相關聯,包含個人、組織或政府機構。 +去中心化身分識別儲存在分散式帳本 ([區塊鏈](/glossary/#blockchain)) 或[對等式網路](/glossary/#peer-to-peer-network)上。 這使得 DID 具有[全球唯一性、高可用度的可解析性,並可透過密碼學驗證](https://w3c-ccg.github.io/did-primer/)。 去中心化身份識別可與不同的實體相關聯,包含個人、組織或政府機構。 -## 什麼讓去中心化身分識別成為可能? {#what-makes-decentralized-identifiers-possible} +## 什麼讓去中心化身分識別成為可能? 是什麼讓去中心化身分識別成為可能? {#what-makes-decentralized-identifiers-possible} -### 1. 公鑰密碼學 {#public-key-cryptography} +### 1. 公鑰密碼學 {#public-key-cryptography} -公鑰密碼學是一種能夠為某實體產生[公鑰](/glossary/#public-key)和[私鑰](/glossary/#private-key)的資安措施。 公鑰[密碼學](/glossary/#cryptography)在區塊鏈網路中用於驗證使用者身分並證明對數位資產的所有權。 +公鑰密碼學是一種資訊安全措施,它為一個實體產生[公鑰](/glossary/#public-key)和[私鑰](/glossary/#private-key)。 公鑰[密碼學](/glossary/#cryptography)用於區塊鏈網路中,以驗證使用者身分並證明數位資產的所有權。 -一些去中心化身分識別,如以太坊帳戶,都有著公鑰與私鑰。 公鑰用於識別帳戶的控制者,而私鑰則可以簽署和解密此帳戶的訊息。 公鑰密碼學使用[加密簽名](https://andersbrownworth.com/blockchain/public-private-keys/)來驗證所有主張,提供了驗證實體並防止冒名頂替及使用假身分所需的證據。 +一些去中心化身分識別,如以太坊帳戶,都有著公鑰與私鑰。 公鑰用於識別帳戶的控制者,而私鑰則可以簽署和解密此帳戶的訊息。 公鑰密碼學提供了驗證實體、防止冒名頂替和使用假身分所需的證明,它使用[密碼學簽章](https://andersbrownworth.com/blockchain/public-private-keys/)來驗證所有宣告。 -### 2. 去中心化資料儲存 {#decentralized-datastores} +### 2. 去中心化資料儲存庫 {#decentralized-datastores} 區塊鏈充當可驗證的資料註冊系統:一個開放、去信任和去中心化的資訊儲存庫。 公共區塊鏈的存在使得不再需要將身分識別儲存在中心化的註冊系統上。 如果任何人需要確認去中心化身分識別的有效性,他們可以在區塊鏈上查找相關的公鑰。 這與需要由第三方進行驗證的傳統身分識別不同。 -## 去中心化身分識別和身分證明要如何實現去中心化身分? {#how-decentralized-identifiers-and-attestations-enable-decentralized-identity} +## 去中心化身分識別和身分證明要如何實現去中心化身分? 去中心化身分識別和證明如何實現去中心化身分? {#how-decentralized-identifiers-and-attestations-enable-decentralized-identity} 去中心化身分的概念是,與身分有關的資訊應該由自己控制,且是私密和可移植的,以去中心化身分識別和身分證明為基本構建模塊。 -在去中心化身分的背景下,身分證明(也稱為[可驗證憑證](https://www.w3.org/TR/vc-data-model/))是由發行人所發布、可加密驗證的防篡改聲明。 實體(如,組織)發行的每個身分證明或可驗證憑證都與它們的去中心化身分識別有關。 +在去中心化身分的脈絡中,證明 (也稱為[可驗證憑證](https://www.w3.org/TR/vc-data-model/)) 是由發行者所做出的防竄改、可透過密碼學驗證的宣告。 實體(如,組織)發行的每個身分證明或可驗證憑證都與它們的去中心化身分識別有關。 由於去中心化身分識別儲存在區塊鏈上,任何人都可以在以太坊上交叉驗證發行人的去中心化身分識別,來驗證身分證明的有效性。 實際上,以太坊就像是一個全球目錄,能夠驗證與某些實體相關的去中心化身分識別。 @@ -115,31 +141,31 @@ summaryPoint3: 多虧了加密技術,使用者現在擁有了再次發行、 透過去中心化身分,來使去中心化身分識別能夠保護個人隱私資訊也至關重要。 例如,如果某人提交一個身分證明(駕駛執照),則驗證方不需要檢查身分證明中資訊的有效性。 反之,驗證者只需要獲得身分證明真實性的加密擔保以及發證機構的身分,就足以確定此證明是否有效。 -## 去中心化身分中的身分證明類型 {#types-of-attestations-in-decentralized-identity} +## 去中心化身分中的證明類型 {#types-of-attestations-in-decentralized-identity} 在基於以太坊的身分生態系統中,如何儲存和檢索身分證明資訊與傳統身分管理不同。 以下是在去中心化身分系統中發行、儲存和驗證身分證明的各種方法的概覽: -### 鏈外身分證明 {#off-chain-attestations} +### 鏈下證明 {#offchain-attestations} 將身份證明儲存在鏈上的一個問題是,其中可能包含個人想要保密的資訊。 以太坊區塊鏈具有公開性,因此不適合用於儲存此類身分證明。 -解決方案是發行身分證明,由使用者在數位錢包中鏈外持有,但使用儲存在鏈上的發行人的去中心化身分識別進行簽名。 這些身分證明被編碼為 [JSON Web 代幣](https://en.wikipedia.org/wiki/JSON_Web_Token),其中包含發行人的數位簽名,從而可以輕鬆驗證鏈外聲明。 +解決方案是發行身分證明,由使用者在數位錢包中鏈下持有,但使用儲存在鏈上的發行人的去中心化身分識別進行簽名。 這些證明會被編碼為 [JSON Web Token](https://en.wikipedia.org/wiki/JSON_Web_Token) 並包含發行者的數位簽章,以便輕鬆驗證鏈下宣告。 -以下是解釋鏈外身分證明的假設場景: +以下是解釋鏈下身分證明的假設場景: 1. 某大學(發行人)產生身分證明(數位學歷證書),用其金鑰簽署,然後將證書頒發給 Bob(身分持有者)。 2. Bob 申請了一份工作並想向雇主證明他的學歷,因此他分享了行動裝置錢包中的身分證明。 公司(驗證者)可以透過檢查發行人的去中心化身分識別(即,其在以太坊上的公鑰),來確認身分證明的有效性。 -### 可持續訪問的鏈外身分證明 {#offchain-attestations-with-persistent-access} +### 具備永久存取權限的鏈下證明 {#offchain-attestations-with-persistent-access} -在這種場景下,身分證明被轉換為 JSON 文件並儲存在鏈外(理想情況下儲存在[去中心化雲端儲存](/developers/docs/storage/)平台上,例如 IPFS 或 Swarm)。 然而,JSON 文件的[雜凑值](/glossary/#hash)儲存在鏈上,並透過鏈上註冊系統連結到去中心化身分識別。 所關聯的去中心化身分識別可以是發行人或接收者的身分證明。 +在這種安排下,證明會被轉換成 JSON 檔案並儲存在鏈下 (最好是儲存在 [去中心化雲端儲存](/developers/docs/storage/) 平台,例如 IPFS 或 Swarm)。 然而,JSON 檔案的[哈希](/glossary/#hash)會儲存在鏈上,並透過鏈上登錄檔連結到 DID。 所關聯的去中心化身分識別可以是發行人或接收者的身分證明。 這種方法使身份證明能夠獲得基於區塊鏈的持久性,同時確保聲明資訊的加密性和可驗證性。 它還允許選擇性揭露,因為私鑰的持有者可以解密資訊。 -### 鏈上身分證明 {#onchain-attestations} +### 鏈上證明 {#onchain-attestations} -鏈上身分證明保存在以太坊區塊鏈上的[智慧型合約](/glossary/#smart-contract)中。 智慧型合約(充當註冊系統)將身分證明對應到相關的鏈上去中心化身分識別(公開金鑰)。 +鏈上證明保存在以太坊區塊鏈上的[智能合約](/glossary/#smart-contract)中。 智能合約(充當註冊系統)將身分證明對應到相關的鏈上去中心化身分識別(公開金鑰)。 以下範例展示了鏈上身分證明在實踐中的使用方式: @@ -149,43 +175,44 @@ summaryPoint3: 多虧了加密技術,使用者現在擁有了再次發行、 3. 出售股份的智慧型合約可以檢查註冊合約以獲得經篩選之買家的身分,從而使智慧型合約可以確定哪些人被允許購買股份。 -### 靈魂綁定代幣和身分 {#soulbound} +### 靈魂綁定代幣與身分 {#soulbound} -[靈魂綁定代幣](https://vitalik.eth.limo/general/2022/01/26/soulbound.html)([不可轉移的非同質化代幣](/glossary/#nft))可用於收集特定錢包獨有的資訊。 這有效地創建了綁定到特定以太坊地址的唯一鏈上身分,這可能包括代表成就的代幣(例如完成某些特定的線上課程或在遊戲中超過分數門檻)或社區參與代幣。 +[靈魂綁定代幣](https://vitalik.eth.limo/general/2022/01/26/soulbound.html) ([不可轉移的 NFT](/glossary/#nft)) 可用於收集特定錢包的專屬資訊。 這有效地建立了一個與特定以太坊地址綁定的獨特鏈上身分,其中可包含代表成就 (例如,完成某個特定的線上課程或在遊戲中達到門檻分數) 或社群參與的代幣。 ## 使用去中心化身分 {#use-decentralized-identity} 有許多雄心勃勃的專案使用以太坊作為去中心化身分解決方案基礎: -- **[以太坊名稱服務 (ENS)](https://ens.domains/)** - _一個去中心化的鏈上命名系統,適合機器可讀的識別符號,例如以太坊錢包地址、內容雜湊值和中繼資料。_ -- **[SpruceID](https://www.spruceid.com/)** - _去中心化身分專案,它允許使用者使用以太坊帳戶和以太坊名稱服務個人資料來控制數位身分,而不是依賴第三方服務。_ -- **[以太坊證明服務 (EAS)](https://attest.sh/)** - _一種去中心化分類帳/協議,用於對任何事物進行鏈上或鏈下證明。_ -- **[人性證明](https://www.proofofhumanity.id)** - _人性證明 (PoH) 是建立在以太坊上的社交身分驗證系統。_ -- **[BrightID](https://www.brightid.org/)** - _一個去中心化的開源社交身分網路,旨在通過創建和分析社交圖譜來改革身分驗證。_ -- **[walt.id](https://walt.id)** — _一種使開發者和組織能夠利用自主權身份、非同質化代幣/魂縛代幣的開源去中心化身份及錢包基礎設施。_ -- **[Veramo](https://veramo.io/)** - _ 一種 JavaScript 框架,讓任何人都可以輕鬆地在他們的應用程式中使用可加密驗證的資料。_ +- **[Ethereum Name Service (ENS)](https://ens.domains/)** - _一種去中心化的鏈上命名系統,適用於機器可讀的身分識別,例如以太坊錢包地址、內容哈希和元資料。_ +- **[使用以太坊登入 (SIWE)](https://siwe.xyz/)** - _使用以太坊帳戶進行驗證的開放標準。_ +- **[SpruceID](https://www.spruceid.com/)** - _一個去中心化身分專案,讓使用者能用以太坊帳戶和 ENS 個人資料控制數位身分,而無需仰賴第三方服務。_ +- **[Ethereum Attestation Service (EAS)](https://attest.org/)** - _一個去中心化的帳本/協定,可用於對任何事物進行鏈上或鏈下證明。_ +- **[Proof of Humanity](https://www.proofofhumanity.id)** - _Proof of Humanity (或 PoH) 是建構在以太坊上的一套社會身分驗證系統。_ +- **[BrightID](https://www.brightid.org/)** - _一個去中心化的開源社交身分網路,旨在透過建立和分析社交圖譜來改革身分驗證。_ +- **[walt.id](https://walt.id)** — _開源的去中心化身分和錢包基礎設施,讓開發者和組織能夠利用自主身分和 NFT/SBT。_ +- **[Veramo](https://veramo.io/)** - _一個 JavaScript 框架,讓任何人都能輕鬆地在其應用程式中使用可透過密碼學驗證的資料。_ ## 延伸閱讀 {#further-reading} ### 文章 {#articles} - [區塊鏈使用案例:數位身分中的區塊鏈](https://consensys.net/blockchain-use-cases/digital-identity/) — _ConsenSys_ -- [什麼是以太坊 ERC725? 區塊鏈上的自我主權身分管理](https://cryptoslate.com/what-is-erc725-self-sovereign-identity-management-on-the-blockchain/) — _Sam Town_ +- [什麼是以太坊 ERC725? 區塊鏈上的自主身分管理](https://cryptoslate.com/what-is-erc725-self-sovereign-identity-management-on-the-blockchain/) — _Sam Town_ - [區塊鏈如何解決數位身分問題](https://time.com/6142810/proof-of-humanity/) — _Andrew R. Chow_ -- [什麼是去中心化身分以及你為什麼需要關心?](https://web3.hashnode.com/what-is-decentralized-identity) — _Emmanuel Awosika_ -- [去中心化身份簡介](https://walt.id/white-paper/digital-identity) — _Dominik Beron_ +- [什麼是去中心化身分?為什麼您該關心?](https://web3.hashnode.com/what-is-decentralized-identity) — _Emmanuel Awosika_ +- [去中心化身分簡介](https://walt.id/white-paper/digital-identity) — _Dominik Beron_ ### 影片 {#videos} -- [去中心化身分(直播獎勵環節)](https://www.youtube.com/watch?v=ySHNB1za_SE&t=539s) — _一個很好的去中心化身分解說影片,創作者 Andreas Antonopolous_ -- [使用以太坊和去中心化身分登錄 Ceramic、IDX、React 和 3ID Connect](https://www.youtube.com/watch?v=t9gWZYJxk7c) — _YouTube 使用教學,作者 Nader Dabit,介紹如何構建身分管理系統,透過以太坊錢包建立、讀取和更新使用者個人資料。_ -- [BrightID - 以太坊上的去中心化身分](https://www.youtube.com/watch?v=D3DbMFYGRoM) — _Bankless 播客節目討論 BrightID,一個以太坊上的去中心化身分解決方案_ -- [鏈外互聯網:去中心化身分 & 可驗證憑證](https://www.youtube.com/watch?v=EZ_Bb6j87mg) — Evin McMullen 在 EthDenver 2022 的演講 -- [Verifiable Credentials Explained(可驗憑證說明)](https://www.youtube.com/watch?v=ce1IdSr-Kig) - 由 Tamino Baumann 主持演示的 YouTube 講解視頻 +- [去中心化身分 (直播加碼場)](https://www.youtube.com/watch?v=ySHNB1za_SE&t=539s) — _Andreas Antonopolous 製作的絕佳去中心化身分說明影片_ +- [使用以太坊登入和去中心化身分,搭配 Ceramic、IDX、React 和 3ID Connect](https://www.youtube.com/watch?v=t9gWZYJxk7c) — _Nader Dabit 製作的 YouTube 教學,介紹如何使用使用者的以太坊錢包建置身分管理系統來建立、讀取和更新其個人資料_ +- [BrightID - 以太坊上的去中心化身分](https://www.youtube.com/watch?v=D3DbMFYGRoM) — _Bankless 播客節目,討論 BrightID,一個以太坊的去中心化身分解決方案_ +- [鏈下網際網路:去中心化身分與可驗證憑證](https://www.youtube.com/watch?v=EZ_Bb6j87mg) — Evin McMullen 在 2022 年 EthDenver 的演講 +- [可驗證憑證說明](https://www.youtube.com/watch?v=ce1IdSr-Kig) - Tamino Baumann 附帶示範的 YouTube 說明影片 ### 社群 {#communities} -- [GitHub 上的 ERC-725 聯盟](https://github.com/erc725alliance) — _在以太坊區塊鏈上管理身分的 ERC725 標準的支持者_ -- [EthID Discord 伺服器](https://discord.com/invite/ZUyG3mSXFD) — _研究使用以太坊登錄的愛好者和開發者社群_ -- [Veramo Labs](https://discord.gg/sYBUXpACh4) — _一個開發人員社區,致力於為應用程式構建可驗證資料的框架_ -- [walt.id](https://discord.com/invite/AW8AgqJthZ) — _由開發者和構建者組成的社區,致力於開發各個行業的去中心化身份應用案例_ +- [GitHub 上的 ERC-725 聯盟](https://github.com/erc725alliance) — _支援在以太坊區塊鏈上管理身分的 ERC725 標準_ +- [EthID Discord 伺服器](https://discord.com/invite/ZUyG3mSXFD) — _致力於「使用以太坊登入」和「以太坊追蹤協定」的愛好者與開發者社群_ +- [Veramo Labs](https://discord.gg/sYBUXpACh4) — _一個致力於為應用程式建置可驗證資料框架的開發者社群_ +- [walt.id](https://discord.com/invite/AW8AgqJthZ) — _一個由開發者和建構者組成的社群,致力於開發各行各業的去中心化身分使用案例_ diff --git a/public/content/translations/zh-tw/defi/index.md b/public/content/translations/zh-tw/defi/index.md index 18d7a3da28f..dcffcf178fe 100644 --- a/public/content/translations/zh-tw/defi/index.md +++ b/public/content/translations/zh-tw/defi/index.md @@ -1,19 +1,19 @@ --- -title: 去中心化金融 (DeFi) -metaTitle: 甚麼是去中心化金融? | 去中心化金融的優點和作用 -description: 以太坊生態系之去中心化金融概要 +title: "去中心化金融 (DeFi)" +metaTitle: "甚麼是去中心化金融? | 去中心化金融的優點和作用" +description: "以太坊生態系之去中心化金融概要" lang: zh-tw template: use-cases emoji: ":money_with_wings:" image: /images/use-cases/defi.png -alt: 以樂高積木製作的以太幣標誌。 +alt: "以樂高積木製作的以太幣標誌。" sidebarDepth: 2 -summaryPoint1: 現行金融系統的全球開放性替代方案。 -summaryPoint2: 讓你借款、儲蓄、投資、交易和進行更多應用的產品。 -summaryPoint3: 基於所有人都可以編寫的開放原始碼技術。 +summaryPoint1: "現行金融系統的全球開放性替代方案。" +summaryPoint2: "讓你借款、儲蓄、投資、交易和進行更多應用的產品。" +summaryPoint3: "基於所有人都可以編寫的開放原始碼技術。" --- -去中心化金融是專為網際網路時代建構的開放式全球金融系統,可取代不透明、遭到嚴密控制、以幾十年前的基礎設施和流程維繫的系統, 讓你有能力控制及監管自己的資金, 觸及全球市場,並獲得本地貨幣或銀行以外的替代選項。 去中心化金融產品向所有擁有網際網路連線的人開放金融服務,同時主要是由使用者控制和維護。 到目前為止,已有價值數百億的加密貨幣透過去中心化金融應用程式流通,而且這個數字每天都還在成長。 +去中心化金融是專為網際網路時代建構的開放式全球金融系統,可取代不透明、遭到嚴密控制、以幾十年前的基礎設施和流程維繫的系統, 讓你有能力控制及監管自己的資金, 觸及全球市場,並獲得本地貨幣或銀行以外的替代選項。 去中心化金融產品向所有擁有網際網路連線的人開放金融服務,同時主要是由使用者控制和維護。 到目前為止,已有價值數百億美元的加密貨幣流經 DeFi 應用程式,且數量與日俱增。 ## 何謂去中心化金融? {#what-is-defi} @@ -23,7 +23,7 @@ summaryPoint3: 基於所有人都可以編寫的開放原始碼技術。 -## 去中心化金融與傳統金融 {#defi-vs-tradfi} +## DeFi 與傳統金融 {#defi-vs-tradfi} 了解去中心化金融潛力的一種最佳方法是了解目前存在的問題。 @@ -32,7 +32,7 @@ summaryPoint3: 基於所有人都可以編寫的開放原始碼技術。 - 金融服務可以讓你無法收款。 - 傳統金融服務還有一項隱藏費用,就是你的個人資料。 - 政府及中心化機構可以任意關閉市場。 -- 交易時間通常受到特定時區的營業時間所限。 +- 交易時間通常受特定時區的營業時間限制。 - 資金移轉可能因為內部人工流程而花上好幾天的時間。 - 金融服務存在溢價,因為中間機構需要分一杯羹。 @@ -56,17 +56,17 @@ summaryPoint3: 基於所有人都可以編寫的開放原始碼技術。 從許多方面來說,比特幣是第一款去中心化金融應用程式。 比特幣能讓你真正擁有及掌控價值,並傳送到世界上任何一個角落。 它提供了一種方式,讓眾多互不信任的人同意使用一套帳戶帳本,而無需透過可信賴的中間機構。 比特幣對所有人開放,而且沒有人有權改變其規則。 比特幣的規則,例如其稀有度及開放性,是這項技術與生俱來的特色。 在傳統金融中,政府可以印鈔讓你的存款貶值,企業也可以關閉市場,而比特幣與傳統金融截然不同。 -以太坊便是以此概念為基礎。 和比特幣一樣,以太坊的規則不能任意更改,而且所有人都能使用。 但它進一步使用[智慧型合約](/glossary/#smart-contract)讓這種數位貨幣可程式化,使其功能不侷限於存放及傳送價值。 +以太坊便是以此概念為基礎。 和比特幣一樣,以太坊的規則不能任意更改,而且所有人都能使用。 但它也使用[智能合約](/glossary/#smart-contract)讓這種數位貨幣可程式化,使其功能不侷限於存放及傳送價值。 -## 可程式化的貨幣 {#programmable-money} +## 可程式化貨幣 {#programmable-money} -這聽起來很奇怪……「我幹嘛把我的錢程式化?」 不過,這只是以太坊代幣的預設功能之一。 所有人都可以在付款時加入程式邏輯。 因此,你可以結合比特幣的控制權和安全性,以及金融機構提供的各種金融服務, 用加密貨幣來做一些比特幣辦不到的事,例如借貸、安排付款、投資指數型基金等等。 +這聽起來有點奇怪… 「我為什麼會想把我的錢程式化」? 然而,這不僅僅是以太坊上代幣的一項預設功能。 所有人都可以在付款時加入程式邏輯。 因此,你可以結合比特幣的控制權和安全性,以及金融機構提供的各種金融服務, 用加密貨幣來做一些比特幣辦不到的事,例如借貸、安排付款、投資指數型基金等等。 - +
如果你是剛開始使用以太坊,請嘗試我們推薦的去中心化金融應用程式。
探索去中心化金融應用程式 @@ -78,23 +78,23 @@ summaryPoint3: 基於所有人都可以編寫的開放原始碼技術。 大多數金融服務都有去中心化的替代方案。 但以太坊也為打造嶄新的金融產品創造了許多機會。 這個清單還在不斷成長。 -- [匯款到世界各地](#send-money) +- [將款項傳送到世界各地](#send-money) - [讓資金在全球流通](#stream-money) -- [取得穩定幣](#stablecoins) +- [存取穩定幣](#stablecoins) - [抵押借款](#lending) - [無抵押借款](#flash-loans) - [開始儲蓄加密貨幣](#saving) - [交易代幣](#swaps) -- [擴大投資組合](#investing) -- [為構想募資](#crowdfunding) +- [擴大您的投資組合](#investing) +- [為您的創意募資](#crowdfunding) - [購買保險](#insurance) -- [管理投資組合](#aggregators) +- [管理您的投資組合](#aggregators) -### 快速匯款到世界各地 {#send-money} +### 快速將款項傳送到世界各地 {#send-money} -作為一種區塊鏈,以太坊的核心功能是安全地在全球傳送交易。 和比特幣一樣,以太坊可以讓跨境匯款像傳送電子郵件一樣簡單。 只需從錢包輸入收款人的[以太坊名稱服務名稱](/glossary/#ens)(例如 bob.eth)或其帳戶地址,你的款項就會在幾分鐘內直接到達對方的帳戶(通常情況下)。 要收發款項,你需要一個[錢包](/wallets/)。 +作為一種區塊鏈,以太坊的核心功能是安全地在全球傳送交易。 和比特幣一樣,以太坊可以讓跨境匯款像傳送電子郵件一樣簡單。 只要在您的錢包中輸入收款人的 [ENS 名稱](/glossary/#ens) (例如 bob.eth) 或他們的帳戶地址,您的款項通常會在幾分鐘內直接送達他們。 要傳送或接收款項,您需要一個[錢包](/wallets/)。 查看支付去中心化應用程式 @@ -104,18 +104,18 @@ summaryPoint3: 基於所有人都可以編寫的開放原始碼技術。 你可以運用以太坊流通資金。 以太坊可以讓你在幾秒之內支付某人的薪資,供對方隨時取用; 或快速租用物品,如置物櫃或電動滑板車。 -如果你因為價值波動而不想傳送或串流[以太幣](/glossary/#ether),以太坊上也有替代貨幣:[穩定幣](/glossary/#stablecoin)。 +而且,如果您因為 [ETH](/glossary/#ether) 的價值波動劇烈而不想傳送或串流它,以太坊上還有其他替代貨幣:[穩定幣](/glossary/#stablecoin)。 -### 取得穩定幣 {#stablecoins} +### 存取穩定貨幣 {#stablecoins} 對許多金融產品和一般支出而言,加密貨幣的價格波動是一大問題。 去中心化金融社群以穩定幣解決了這個問題。 穩定幣的價值與其他資產掛鈎,通常是美元這類熱門貨幣。 Dai、USDC 等穩定幣的價值和美元的差距通常維持在幾美分之內, 使穩定幣非常適合用於收入或零售。 在南美洲,因為政府發行的貨幣有極大的不確定性,許多人已經在使用穩定幣保護自己的儲蓄。 - 深入了解穩定幣 +深入了解穩定幣 @@ -133,21 +133,21 @@ Dai、USDC 等穩定幣的價值和美元的差距通常維持在幾美分之內 選擇去中心化貸款有許多優勢…… -#### 在保有隱私的情況下借貸 {#borrowing-privacy} +#### 具隱私性的借款 {#borrowing-privacy} 今天,資金的借與貸都是圍繞著相關個人進行。 銀行在放款前,需要知道你是不是真的有能力償還貸款。 -去中心化借貸則不需任何一方表明身分即可運作。 然而,借款者必須提供抵押品,如果無法償還,抵押品就會自動歸貸款者所有。 有些貸款人甚至接受以[非同質化代幣](/glossary/#nft)作為抵押品。 非同質化代幣為獨特資產(如繪畫)的契據。 [更多非同質化代幣相關資訊](/nft/) +去中心化借貸則不需任何一方表明身分即可運作。 然而,借款者必須提供抵押品,如果無法償還,抵押品就會自動歸貸款者所有。 有些出借方甚至接受 [NFTs](/glossary/#nft) 作為抵押品。 非同質化代幣為獨特資產(如繪畫)的契據。 [更多關於 NFT 的資訊](/nft/) 透過這種方式,不必接受徵信調查或提供私人資訊也能借款。 -#### 獲得全球資金 {#access-global-funds} +#### 取得全球資金 {#access-global-funds} -選擇去中心化借貸服務時,你可以借入來自全球各地的存款,而不僅止於你選擇的銀行或機構所持有的資金。 這讓貸款更容易取得,也能改善利率。 +選擇去中心化借貸服務時,你可以借入來自全球各地的存款,而不僅止於你選擇的銀行或機構所持有的資金。 這讓貸款更容易取得,也能優化利率。 -#### 納稅效益 {#tax-efficiencies} +#### 節稅效益 {#tax-efficiencies} -借款可以讓你獲得需要的資金,而無需出售以太幣(此行為會被課稅)。 但是,你可以使用以太幣作為抵押品以借貸穩定幣。 如此一來,你便可以在保有以太幣的情況下,獲得所需的現金流。 穩定幣是需要現金時的最佳選擇,因為穩定幣的價值不像以太幣一樣易於波動。 [深入了解穩定幣](#stablecoins) +借款可以讓你獲得需要的資金,而無需出售以太幣(此行為會被課稅)。 但是,你可以使用以太幣作為抵押品以借貸穩定幣。 如此一來,你便可以在保有以太幣的情況下,獲得所需的現金流。 穩定幣是需要現金時的最佳選擇,因為穩定幣的價值不像以太幣一樣易於波動。 [更多關於穩定幣的資訊](#stablecoins) #### 閃電貸 {#flash-loans} @@ -173,27 +173,27 @@ Dai、USDC 等穩定幣的價值和美元的差距通常維持在幾美分之內 要在傳統金融體系內完成以上操作,你需要鉅額資金。 這種財產創造策略只有已經擁有財富的人才能操作。 閃電貸的例子告訴我們,未來「有錢」不見得是「賺錢」的先決條件。 - 深入了解閃電貸 + 更多關於閃電貸的資訊 -### 開始儲蓄加密貨幣 {#saving} +### 開始用加密貨幣儲蓄 {#saving} -#### 放貸 {#lending} +#### 借貸 {#lending} 你可以透過放貸加密貨幣來賺取利息,並即時看到資金成長。 目前的利息比你當地的銀行高出許多(如果你運氣夠好,可以使用銀行服務的話)。 例如: -- 你借出 100 Dai(一種[穩定幣](/stablecoins/))給某個類似 Aave 的產品。 +- 您將您的 100 Dai,一種[穩定幣](/stablecoins/),出借給像 Aave 這樣的產品。 - 你會收到 100 Aave Dai (aDai),此代幣代表著你借出的 Dai。 -- 你的 aDai 會按利率增加,你可以看到錢包裡的餘額在增長。 視[年利率](/glossary/#apr)而定,你的錢包餘額可能會在幾天,甚至幾小時後變成 100.1234! +- 你的 aDai 會按利率增加,你可以看到錢包裡的餘額在增長。 取決於[年利率](/glossary/#apr),幾天甚至幾小時後,您的錢包餘額就會變成 100.1234! - 你可以隨時提取和你的 aDai 餘額等額的一般 Dai。 查看借貸去中心化應用程式 -#### 無損樂透 {#no-loss-lotteries} +#### 無損失樂透 {#no-loss-lotteries} 無損樂透(如 PoolTogether)是一種有趣而創新的儲蓄方法。 @@ -206,7 +206,7 @@ Dai、USDC 等穩定幣的價值和美元的差距通常維持在幾美分之內 和上述放貸案例一樣,獎金池的資金來自於放貸樂透存款產生的所有利息。 - 嘗試 PoolTogether + 試用 PoolTogether @@ -235,11 +235,11 @@ Dai、USDC 等穩定幣的價值和美元的差距通常維持在幾美分之內 -### 擴大投資組合 {#investing} +### 擴大您的投資組合 {#investing} 以太坊上有一些資金管理產品可以根據你選擇的策略來擴展你的投資組合。 這是自動化作業,對所有人開放,而且不需要管理人員來分一杯羹。 -[DeFi Pulse 指數基金 (DPI)](https://defipulse.com/blog/defi-pulse-index/) 就是個很好的例子。 此基金會自動再平衡,確保你的投資組合永遠包含市值最高的去中心化金融代幣。 你無需親力親為處理任何細節,而且可以隨時提取資金。 +一個很好的例子是 [DeFi Pulse 指數基金 (DPI)](https://defipulse.com/blog/defi-pulse-index/)。 此基金會自動再平衡,確保你的投資組合永遠包含市值最高的去中心化金融代幣。 你無需親力親為處理任何細節,而且可以隨時提取資金。 查看投資去中心化應用程式 @@ -247,7 +247,7 @@ Dai、USDC 等穩定幣的價值和美元的差距通常維持在幾美分之內 -### 為構想募資 {#crowdfunding} +### 為您的創意募資 {#crowdfunding} 以太坊是群眾募資的理想平台: @@ -261,9 +261,9 @@ Dai、USDC 等穩定幣的價值和美元的差距通常維持在幾美分之內 #### 平方募資法 {#quadratic-funding} -以太坊是一款開放原始碼軟體,迄今有許多工作是由社群資助。 這也催生了一種有趣的新型募資模式:平方募資法。 這種募資法有機會改善我們未來為各種公共產品募資的方式。 +以太坊是一款開放原始碼軟體,迄今有許多工作是由社群資助。 這也催生了一種有趣的新型募資模式:平方募資法。 這種模式可能有助於改善我們在未來為各種公共產品募資的方式。 -平方募資法可以確保獲得最多資金的是需求最高的計畫案, 換言之,就是能夠改善大多數人生活的計畫案。 其運作方式如下: +二次融資確保獲得最多資金的是具有最獨特需求的專案。 換句話說,就是那些能夠改善大多數人生活的專案。 其運作方式如下: 1. 募得的資金會注入一個配比池。 2. 啟動一輪公開募資。 @@ -282,7 +282,7 @@ Dai、USDC 等穩定幣的價值和美元的差距通常維持在幾美分之內 去中心化保險的目標是使保險更加便宜、理賠更快速,同時更為透明。 隨著自動化程度的提高,保險價格可以更加低廉,理賠也可以更加快速。 用以決定索賠的資料完全透明。 -和其他軟體一樣,以太坊產品也可能受到錯誤或入侵的威脅, 因此目前這個領域有許多保險產品將重點放在保護使用者不會損失資金上。 然而,若干專案開始涵蓋生活中可能遇到的各種大小意外保障。 Etherisc 的農作物保險就是個很好的例子,這項產品的目標在於[保護肯亞小農對抗乾旱及洪災](https://blog.etherisc.com/etherisc-teams-up-with-chainlink-to-deliver-crop-insurance-in-kenya-137e433c29dc)。 去中心化保險可以為買不起傳統保險的農民提供更實惠的保障。 +以太坊產品, 就像任何軟體, 能因程式漏洞或bug而產生種種問題. 因此目前這個領域有許多保險產品將重點放在保護使用者不會損失資金上。 然而,若干專案開始涵蓋生活中可能遇到的各種大小意外保障。 一個很好的例子是 Etherisc 的農作物保險,旨在[保護肯亞的小農免受乾旱和洪水侵害](https://blog.etherisc.com/etherisc-teams-up-with-chainlink-to-deliver-crop-insurance-in-kenya-137e433c29dc)。 去中心化保險可以為買不起傳統保險的農民提供更實惠的保障。 查看保險去中心化應用程式 @@ -302,7 +302,7 @@ Dai、USDC 等穩定幣的價值和美元的差距通常維持在幾美分之內 ## 去中心化金融如何運作? {#how-defi-works} -去中心化金融使用加密貨幣及智慧型合約來提供服務,不需透過中間機構。 在今日的金融體系下,金融機構是交易的保證人。 你的資金是透過金融機構流通,因此賦予了這些機構巨大的權利。 此外,世界上還有數十億人甚至無法使用銀行帳戶。 +去中心化金融使用加密貨幣及智慧型合約來提供服務,不需透過中間機構。 在今日的金融體系下,金融機構是交易的保證人。 你的資金是透過金融機構流通,因此賦予了這些機構巨大的權利。 此外,全球有數十億人甚至無法存取銀行帳戶。 在去中心化金融中,智慧型合約在交易中取代了的金融機構。 智慧型合約是一種以太坊帳戶,可以持有資金並根據特定條件發送/退還資金。 智慧型合約上線後就沒有人可以篡改,它會永遠依照設定的方式運作。 @@ -312,7 +312,7 @@ Dai、USDC 等穩定幣的價值和美元的差距通常維持在幾美分之內 確實,這也意味著目前需要仰賴以太坊社群中能閲讀程式碼的更為精通技術的成員。 以開放原始碼為基礎的社群會約束開發者,但這種需求會隨著時間而趨緩,因為智慧型合約會變得越來越容易閲讀,同時也有其他可以證明程式碼可信度的方法誕生。 -## 以太坊及去中心化金融 {#ethereum-and-defi} +## 以太坊與 DeFi {#ethereum-and-defi} 以太坊為去中心化金融提供了良好的基礎,原因包括: @@ -324,36 +324,37 @@ Dai、USDC 等穩定幣的價值和美元的差距通常維持在幾美分之內 你可以把去中心化金融想成好幾層: 1. 區塊鏈:以太坊包含了交易記錄和帳戶狀態。 -2. 資產:[以太幣](/what-is-ether/)及其他代幣(貨幣)。 -3. 協定:提供功能的[智慧型合約](/glossary/#smart-contract),例如實現去中心化資產借貸的服務。 -4. [應用程式](/apps/):我們用以管理及存取協定的產品。 +2. 資產 – [ETH](/what-is-ether/) 和其他代幣 (貨幣)。 +3. 協定 – 提供功能的[智能合約](/glossary/#smart-contract),例如允許去中心化資產借貸的服務。 +4. [應用程式](/apps/) – 我們用來管理和存取協定的產品。 -注意:很多去中心化金融使用 [ERC-20 標準](/glossary/#erc-20)。 去中心化金融 (DeFi) 中的應用程式使用一種包裝的以太幣,稱爲包裝以太幣 (WETH)。 [了解更多關於包裝以太幣的資訊](/wrapped-eth)。 +注意:許多 DeFi 都使用 [ERC-20 標準](/glossary/#erc-20)。 去中心化金融 (DeFi) 中的應用程式使用一種包裝的以太幣,稱爲包裝以太幣 (WETH)。 [深入了解包裝以太幣](/wrapped-eth)。 -## 建構去中心化金融 {#build-defi} +## 建構 DeFi {#build-defi} 去中心化金融是一場開放原始碼運動。 去中心化金融協議和應用程式都是開放的,你可以自由檢視、分叉並進行各種創新。 因為採用分層堆疊結構(共享相同的基礎區塊鏈及資產),你可以結合和配對不同協定,開啟獨特的機會組合。 - 關於建構去中心化應用程式 + 更多關於建構去中心化應用程式的資訊 -## 了解更多 {#further-reading} +## 延伸閱讀 {#further-reading} -### 去中心化金融資料 {#defi-data} +### DeFi 資料 {#defi-data} - [DeFi Prime](https://defiprime.com/) - [DeFi Llama](https://defillama.com/) -### 去中心化金融文章 {#defi-articles} +### DeFi 文章 {#defi-articles} -- [去中心化金融新手指南](https://blog.coinbase.com/a-beginners-guide-to-decentralized-finance-defi-574c68ff43c4) – _Sid Coelho-Prabhu,2020 年 1 月 6 日_ +- [DeFi 新手指南](https://blog.coinbase.com/a-beginners-guide-to-decentralized-finance-defi-574c68ff43c4) – _Sid Coelho-Prabhu, 2020 年 1 月 6 日_ +- [EEA DeFi 風險評估指南](https://entethalliance.org/specs/defi-risks/) – 一份由業界支持的概覽,說明如何在 DeFi 協定中識別和評估關鍵風險。 ### 影片 {#videos} -- [Finematics - 去中心化金融教育](https://finematics.com/) – _關於去中心化金融的影片_ -- [The Defiant](https://www.youtube.com/playlist?list=PLaDcID4s1KronHMKojfjwiHL0DdQEPDcq) - _去中心化金融基本知識:在這個偶爾讓人感到困惑的領域裡邁出第一步,你所需要知道的一切。_ -- [加密貨幣白板講解](https://youtu.be/17QRFlml4pA) _- 何謂去中心化金融?_ +- [Finematics - 去中心化金融教育](https://finematics.com/) – _關於 DeFi 的影片_ +- [The Defiant](https://www.youtube.com/playlist?list=PLaDcID4s1KronHMKojfjwiHL0DdQEPDcq) - _DeFi 基礎知識:開始踏入這個偶爾令人困惑的領域前,您需要知道的一切。_ +- [Whiteboard Crypto](https://youtu.be/17QRFlml4pA) _什麼是 DeFi?_ ### 社群 {#communities} diff --git a/public/content/translations/zh-tw/desci/index.md b/public/content/translations/zh-tw/desci/index.md index 5f07a652559..4ba426945cb 100644 --- a/public/content/translations/zh-tw/desci/index.md +++ b/public/content/translations/zh-tw/desci/index.md @@ -1,15 +1,15 @@ --- -title: 去中心化科研 (DeSci) -description: 以太坊的去中心化科研概觀 +title: "去中心化科研 (DeSci)" +description: "以太坊的去中心化科研概觀" lang: zh-tw template: use-cases emoji: ":microscope:" sidebarDepth: 2 image: /images/future_transparent.png alt: "" -summaryPoint1: 當前科學系統的全球開放性替代方案。 -summaryPoint2: 使科學家得以進行募資、試驗研究、資料分享、發表見解等活動的技術。 -summaryPoint3: 以開放科學運動為原則。 +summaryPoint1: "當前科學系統的全球開放性替代方案。" +summaryPoint2: "使科學家得以進行募資、試驗研究、資料分享、發表見解等活動的技術。" +summaryPoint3: "以開放科學運動為原則。" --- ## 什麼是去中心化科研 (DeSci)? {#what-is-desci} @@ -37,7 +37,7 @@ summaryPoint3: 以開放科學運動為原則。 | 可以開發**新的發表模式**,使用 Web3 基礎單元實現信任、透明度和存取普及化。 | 透過既有途徑發表研究通常被認為**低效、受偏見影響且會受到剝削**。 | | 可以**藉由同儕審查工作獲得代幣與聲望**。 | **同儕審查工作是無償的**,只有商業出版商能獲益。 | | 產生的**知識產權 (IP) 歸你所有**,且能根據透明條款加以分配。 | 產生的**知識產權歸屬於你所屬的機構**。 無法透明地獲得知識產權。 | -| 透過在鏈上公佈所有步驟,包括來自失敗工作的資料,**實現全面的研究共享**。 | **發表偏見**導致研究者傾向於只分享獲得成功結果的實驗。 | +| 透過在鏈上公佈所有步驟,包括來自失敗工作的資料,**實現全面的研究共享**。 | 發表偏見導致研究者傾向於只分享獲得成功結果的實驗。 | ## 以太坊與去中心化科研 {#ethereum-and-desci} diff --git a/public/content/translations/zh-tw/developers/docs/accounts/index.md b/public/content/translations/zh-tw/developers/docs/accounts/index.md index 5412c9bfca5..ea7080ccddf 100644 --- a/public/content/translations/zh-tw/developers/docs/accounts/index.md +++ b/public/content/translations/zh-tw/developers/docs/accounts/index.md @@ -1,21 +1,21 @@ --- -title: 以太坊帳戶 -description: 以太坊帳戶釋義 — 帳戶的資料結構以及和金鑰組密碼學的關係。 +title: "以太坊帳戶" +description: "以太坊帳戶釋義 — 帳戶的資料結構以及和金鑰組密碼學的關係。" lang: zh-tw --- -以太坊帳戶是一個擁有以太幣 (ETH) 餘額且可以在以太坊上發送交易的實體。 帳戶可以為使用者控制的帳戶,或為智慧型合約形式的帳戶。 +以太坊帳戶是一個擁有以太幣 (ETH) 餘額且可以在以太坊上發送訊息的實體。 帳戶可以為使用者控制的帳戶,或為智慧型合約形式的帳戶。 -## 基本資訊 {#prerequisites} +## 先決條件 {#prerequisites} -為了讓你更容易理解本頁,建議你先通讀我們的[以太坊介紹](/developers/docs/intro-to-ethereum/)。 +為了幫助您更佳地理解本頁面,我們建議您先閱讀我們的[以太坊簡介](/developers/docs/intro-to-ethereum/)。 ## 帳戶類型 {#types-of-account} 以太坊有兩種帳戶類型: - 外部帳戶 (EOA) – 由任何持有私密金鑰的人控制 -- 合約帳戶 – 部署在網路上的智慧型合約,由程式碼控制。 瞭解[智慧型合約](/developers/docs/smart-contracts/)。 +- 合約帳戶 – 部署在網路上的智慧型合約,由程式碼控制。 了解[智能合約](/developers/docs/smart-contracts/) 這兩種帳戶類型都能: @@ -34,7 +34,7 @@ lang: zh-tw **合約帳戶** - 建立帳戶會佔用網路儲存因此會產生費用 -- 只能在接受到交易時發送交易 +- 只能在接受到交易時發送訊息 - 從外部帳戶向合約帳戶發送的交易能觸發程式碼,並能執行多種不同操作:例如傳送代幣,甚至建立新合約。 - 合約帳戶沒有私密金鑰。 但它們由智慧型合約程式碼的邏輯控制 @@ -42,14 +42,15 @@ lang: zh-tw 以太坊帳戶有四個欄位: -- `nonce` – 一個計數器,指示外部帳戶發送的交易數量或合約帳戶建立的合約數量。 對於每個帳戶,一筆特定 Nonce 的交易只能執行一次,這是未了防範重放攻擊,即不斷地廣播並重覆執行已簽署的交易。 -- `balance` – 該地址擁有的 Wei 的數量。 Wei 是以太幣的面額,1 以太幣等於1e+18 個 Wei。 -- `codeHash` -- 此雜湊值指帳戶於以太坊虛擬機 (EVM) 上的_程式碼_。 包含了程式碼片段的合約帳戶可以執行不同操作。 對帳戶進行訊息調用時,執行此以太坊虛擬機程式碼。 不同於帳戶的其他欄位,此欄位無法更改。 所有此等程式碼片段都包含於狀態資料庫中其對應的雜湊值下,以便日後擷取。 此雜湊值稱為 codeHash。 對於外部帳戶,codeHash 欄位是空字串的雜湊值。 -- `storageRoot` – 有時稱為儲存雜湊值。 梅克爾帕特里夏樹之根節點的 256 位雜湊值,它對帳戶的儲存內容進行編碼(256 位整數值之間的映射),在樹形資料結構中編碼成 256 位整數鍵的雜湊值到 RPL 編碼的 256 位整數值之間的映射。 該樹形資料結構對此帳戶的儲存內容的雜湊值進行編碼,且默認為空白。 +- `nonce` – 一個計數器,用來表示由外部擁有的帳戶所發送的交易數量,或由合約帳戶所建立的合約數量。 對於每個帳戶,一筆特定 Nonce 的交易只能執行一次,這是未了防範重放攻擊,即不斷地廣播並重覆執行已簽署的交易。 +- `balance` – 此地址擁有的 wei 數量。 Wei 是以太幣的面額,1 以太幣等於1e+18 個 Wei。 +- `codeHash` – 此哈希指的是以太坊虛擬機 (EVM) 上一個帳戶的_程式碼_。 包含了程式碼片段的合約帳戶可以執行不同操作。 對帳戶進行訊息調用時,執行此以太坊虛擬機程式碼。 不同於帳戶的其他欄位,此欄位無法更改。 所有此等程式碼片段都包含於狀態資料庫中其對應的雜湊值下,以便日後擷取。 此雜湊值稱為 codeHash。 對於外部帳戶,codeHash 欄位是空字串的雜湊值。 +- `storageRoot` – 有時也稱為儲存哈希。 [Merkle Patricia Trie](/developers/docs/data-structures-and-encoding/patricia-merkle-trie/) 樹根節點的 256 位元哈希,它會對帳戶的儲存內容(256 位元整數值之間的一個映射)進行編碼,該映射會在樹中編碼為從 256 位元整數鍵的 Keccak 256 位元哈希到 RLP 編碼的 256 位元整數值的映射。 該樹形資料結構對此帳戶的儲存內容的雜湊值進行編碼,且默認為空白。 -![顯示帳戶組成結構的圖表](./accounts.png) _此圖表源於[以太坊的以太坊虛擬機圖解](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ +![顯示帳戶構成的圖表](./accounts.png) +_圖表改編自 [Ethereum EVM illustrated](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ -## 外部帳戶和金鑰組 {#externally-owned-accounts-and-key-pairs} +## 外部擁有的帳戶和金鑰對 {#externally-owned-accounts-and-key-pairs} 帳戶由一對加密金鑰所組成:公鑰和私鑰。 金鑰組有助於證明交易確實由發送者簽署,並可防止偽造。 私密金鑰用於簽署交易,為你授予與帳戶相關的資金的監管權。 你從未真正持有加密貨幣,你持有的是私密金鑰 – 資金始終處於以太坊帳本中。 @@ -57,7 +58,7 @@ lang: zh-tw 假設 Alice 想從自己的帳戶給 Bob 的帳戶發送以太幣,她須建立交易請求並發送到網路上進行驗證。 以太坊採用公開金鑰加密,這能確保 Alice 可以證明是她自己最初發起了該交易請求。 如果沒有加密機制,惡意對手 Eve 就能輕鬆廣播一個請求,例如「從 Alice 的帳戶給 Eve 的帳戶發送 5 以太幣」。沒有人能夠驗證這個請求不是 Alice 發送的。 -## 建立帳戶 {#account-creation} +## 帳戶建立 {#account-creation} 當你想建立一個帳戶時,大多數程式庫會為你產生一個隨機私密金鑰。 @@ -67,32 +68,32 @@ lang: zh-tw `fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036415f` -公開金鑰是使用[橢圓曲線數位簽名演算法](https://wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm)從私密金鑰產生的。 你的帳戶的公開地址由公開金鑰 Keccak-256 雜湊值的後 20 位在開頭加上 `0x` 組成。 +公鑰是使用[橢圓曲線數位簽章演算法](https://wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm)從私鑰生成的。 取公鑰的 Keccak-256 哈希的最後 20 個位元組,並在開頭加上 `0x`,即可獲得您帳戶的公開地址。 -這意味著一個外部帳戶 (EOA) 會有一個 42 字元的地址(20 位元組的片段,即 40 個十六進制的字元加上前綴 `0x`)。 +這表示一個外部擁有的帳戶 (EOA) 有一個 42 個字元的地址 (20 位元組的區段,也就是 40 個十六進位字元,再加上 `0x` 前綴)。 -案例: +範例: `0x5e97870f263700f46aa00d967821199b9bc5a120` -下面的範例展示如何使用一種簽名工具 [Clef](https://geth.ethereum.org/docs/tools/clef/introduction) 來產生一個新帳戶。 Clef 是一種與以太坊用戶端 [Geth](https://geth.ethereum.org) 綁定的帳戶管理與簽名工具。 `clef newaccount` 命令建立一個新的金鑰組並將其儲存於加密的密鑰庫。 +以下範例說明如何使用名為 [Clef](https://geth.ethereum.org/docs/tools/clef/introduction) 的簽署工具來產生新帳戶。 Clef 是一個帳戶管理和簽署工具,與以太坊用戶端 [Geth](https://geth.ethereum.org) 捆綁在一起。 `clef newaccount` 命令會建立新的金鑰對,並將其儲存在加密的金鑰庫中。 ``` > clef newaccount --keystore -Please enter a password for the new account to be created: +請為要建立的新帳戶輸入密碼: > ------------ -INFO [10-28|16:19:09.156] Your new key was generated address=0x5e97870f263700f46aa00d967821199b9bc5a120 -WARN [10-28|16:19:09.306] Please backup your key file path=/home/user/go-ethereum/data/keystore/UTC--2022-10-28T15-19-08.000825927Z--5e97870f263700f46aa00d967821199b9bc5a120 -WARN [10-28|16:19:09.306] Please remember your password! -Generated account 0x5e97870f263700f46aa00d967821199b9bc5a120 +INFO [10-28|16:19:09.156] 您的新金鑰已產生 address=0x5e97870f263700f46aa00d967821199b9bc5a120 +WARN [10-28|16:19:09.306] 請備份您的金鑰檔 path=/home/user/go-ethereum/data/keystore/UTC--2022-10-28T15-19-08.000825927Z--5e97870f263700f46aa00d967821199b9bc5a120 +WARN [10-28|16:19:09.306] 請記住您的密碼! +產生的帳戶 0x5e97870f263700f46aa00d967821199b9bc5a120 ``` [Geth 文件](https://geth.ethereum.org/docs) -可以透過私密金鑰衍生出公開金鑰,但無法使用公開金鑰衍生出私密金鑰。 顧名思義,**私密**意味著確保私密金鑰安全至關重要。 +您可以從私鑰衍生出新的公鑰,但無法從公鑰衍生出私鑰。 保護您的私鑰安全至關重要,而且,顧名思義,請務必保持其**私密性**。 你需要使用私密金鑰來簽署訊息和交易,並輸出一個簽章。 之後,其他人能夠使用該簽章衍生出你的公開金鑰,證明你是這條訊息的創作者。 在你的應用程式中,你可以使用 JavaScript 程式庫將交易發送至網路。 @@ -110,13 +111,13 @@ Generated account 0x5e97870f263700f46aa00d967821199b9bc5a120 以太坊還有另一種金鑰,是在以太坊的共識機制從工作量證明過渡到權益證明時引入的。 它們是「BLS」金鑰,且被用於識別驗證者。 這些金鑰能有效地聚合起來,從而降低網路達成共識所需的帶寬。 如果沒有此等金鑰聚合,成為驗證者所需的最低質押量會高出許多。 -[更多驗證者金鑰相關資訊](/developers/docs/consensus-mechanisms/pos/keys/)。 +[更多關於驗證者金鑰的資訊](/developers/docs/consensus-mechanisms/pos/keys/)。 -## 關於錢包的備註 {#a-note-on-wallets} +## 關於錢包的說明 {#a-note-on-wallets} 帳戶並非錢包。 錢包是一個介面或應用程式,可讓你與你的以太坊帳戶(外部帳戶或合約帳戶)互動。 -## 視覺範例 {#a-visual-demo} +## 視覺化示範 {#a-visual-demo} 觀看 Austin 為你全面講解雜湊函式和金鑰組。 @@ -128,9 +129,9 @@ Generated account 0x5e97870f263700f46aa00d967821199b9bc5a120 - [了解以太坊帳戶](https://info.etherscan.com/understanding-ethereum-accounts/) - etherscan -_知道一個曾經幫助你學習更多社區或社團資源? 歡迎在本頁自由編輯或添加內容!!_ +_知道一個曾經幫助你學習更多社區或社團資源? 歡迎在本頁自由編輯或添加內容!_ ## 相關主題 {#related-topics} -- [智慧型合約](/developers/docs/smart-contracts/) -- [異動](/developers/docs/transactions/) +- [智能合約](/developers/docs/smart-contracts/) +- [交易](/developers/docs/transactions/) diff --git a/public/content/translations/zh-tw/developers/docs/apis/backend/index.md b/public/content/translations/zh-tw/developers/docs/apis/backend/index.md index 30a2c2d5966..10f5e6c83e3 100644 --- a/public/content/translations/zh-tw/developers/docs/apis/backend/index.md +++ b/public/content/translations/zh-tw/developers/docs/apis/backend/index.md @@ -1,6 +1,6 @@ --- -title: 後端應用程式介面程式庫 -description: 讓你能夠從應用程式與區塊鏈互動的以太坊用戶端應用程式介面簡介。 +title: "後端應用程式介面程式庫" +description: "讓你能夠從應用程式與區塊鏈互動的以太坊用戶端應用程式介面簡介。" lang: zh-tw --- diff --git a/public/content/translations/zh-tw/developers/docs/apis/javascript/index.md b/public/content/translations/zh-tw/developers/docs/apis/javascript/index.md index 7d1d24c2da5..07d21c77b54 100644 --- a/public/content/translations/zh-tw/developers/docs/apis/javascript/index.md +++ b/public/content/translations/zh-tw/developers/docs/apis/javascript/index.md @@ -1,41 +1,43 @@ --- -title: JavasScript API 圖書館 -description: JavaScript 用戶端程式庫簡介,可讓你從應用程式與區塊鏈進行互動。 +title: "JavaScript 應用程式介面程式庫" +description: "JavaScript 用戶端程式庫簡介,可讓你從應用程式與區塊鏈進行互動。" lang: zh-tw --- -為了使網路應用程式能夠與以太坊區塊鏈互動(即讀取區塊鏈資料和/或將交易傳送到網路),它必須連結到以太坊節點。 +若要讓 Web 應用程式與以太坊區塊鏈互動 (即讀取區塊鏈資料和/或將交易傳送到網路),它必須連線到以太坊節點。 -為了這個目的,每個以太坊用戶端需實作 [JSON-RPC](/developers/docs/apis/json-rpc/) 規範,如此一來,應用程式就可以使用一組統一的[方法](/developers/docs/apis/json-rpc/#json-rpc-methods)。 +為此,每個以太坊用戶端都會實作 [JSON-RPC](/developers/docs/apis/json-rpc/) 規範,因此應用程式可以仰賴一組統一的 [方法](/developers/docs/apis/json-rpc/#json-rpc-methods)。 如果你想使用 JavaScript 與以太坊節點連結,可以使用普通 JavaScript,但生態系統中存在幾個便利的程式庫,讓連結變得更加容易。 借助這些程式庫,開發者可以編寫直覺的單行方法來初始化與以太坊互動的 JSON-RPC 請求(在後台)。 -請注意,在[合併](/roadmap/merge/)後,如要運行節點,需要兩個互相連結的以太坊軟體:執行用戶端和共識用戶端。 請確定你的節點包含執行用戶端和共識用戶端。 如果你的節點不在本地機器上(比如你的節點在 AWS 執行個體上),請相應地修改教學中的 IP 位址。 更多資訊請見我們的[運行節點](/developers/docs/nodes-and-clients/run-a-node/)頁面。 +請注意,自 [合併](/roadmap/merge/) 之後,執行節點需要兩個相連的以太坊軟體:一個執行用戶端和一個共識用戶端。 請確定你的節點包含執行用戶端和共識用戶端。 如果您的節點不在本機電腦上 (例如,您的節點在 AWS 執行個體上執行),請相應地更新教學中的 IP 位址。 如需詳細資訊,請參閱我們的[執行節點](/developers/docs/nodes-and-clients/run-a-node/)頁面。 -## 基本資訊 {#prerequisites} +## 先決條件 {#prerequisites} -除了瞭解 JavaScript 之外,瞭解[以太坊堆疊](/developers/docs/ethereum-stack/)和[以太坊用戶端](/developers/docs/nodes-and-clients/)可能也會有所幫助。 +除了瞭解 JavaScript 之外,瞭解[以太坊技術堆疊](/developers/docs/ethereum-stack/)和[以太坊用戶端](/developers/docs/nodes-and-clients/)可能也會有幫助。 -## 為何使用資料圖書庫 {#why-use-a-library} +## 為何使用程式庫? {#why-use-a-library} -函式庫簡化與以太坊節點的複雜步驟. 並提供其他效功能(例如: 轉化以太(ETH)到Gwei)使開發者花少時間處理以太坊客戶, 且花更多時間在提升應用程式獨特功能. +這些程式庫顯著降低了直接和以太坊節點互動的複雜度。 它們也提供公用程式函式(例如將 ETH 轉換為 Gwei),因此作為開發者,您可以花費較少時間處理以太坊用戶端的複雜細節,並將更多時間專注於應用程式的獨特功能。 ## 程式庫功能 {#library-features} -### 連結以太坊節點 {#connect-to-ethereum-nodes} +### 連線至以太坊節點 {#connect-to-ethereum-nodes} 使用提供者,這些程式庫讓你能夠連結到以太坊並讀取其資料,無論是透過 JSON-RPC、INFURA、Etherscan、Alchemy 還是 MetaMask。 +> **警告:** Web3.js 已於 2025 年 3 月 4 日封存。 [閱讀公告](https://blog.chainsafe.io/web3-js-sunset/) 針對新專案,請考慮使用 [ethers.js](https://ethers.org) 或 [viem](https://viem.sh) 等替代程式庫。 + **Ethers 範例** ```js -// BrowserProvider 包裝了一個標準的 Web3 提供者 -// 這就是 MetaMask 注入到每個頁面中的 window.ethereum +// BrowserProvider 會包裝一個標準的 Web3 提供者, +// 也就是 MetaMask 注入到每個頁面的 window.ethereum const provider = new ethers.BrowserProvider(window.ethereum) // MetaMask 外掛程式也允許簽署交易 -// 以傳送以太幣並支付以改變區塊鏈中的狀態。 -//為此, 我們須帳戶簽署者 +// 以傳送以太幣並支付費用來變更區塊鏈中的狀態。 +// 為此,我們需要帳戶簽署者… const signer = provider.getSigner() ``` @@ -68,7 +70,7 @@ var web3 = new Web3( - 燃料預估值 - 智慧型合約活動 - 網路 id -- 和更多相關內容... +- 以及更多... ### 錢包功能 {#wallet-functionality} @@ -77,26 +79,26 @@ var web3 = new Web3( 下面是以太幣範例 ```js -//由助記符(mnemonic) 創建錢包 +// 從助記詞建立錢包執行個體... mnemonic = "announce room limb pattern dry unit scale effort smooth jazz weasel alcohol" walletMnemonic = Wallet.fromPhrase(mnemonic) -// ...或者從私鑰建立 +// ...或從私密金鑰 walletPrivateKey = new Wallet(walletMnemonic.privateKey) walletMnemonic.address === walletPrivateKey.address // true -// 根據簽署者應用程式介面取得地址(以 Promise 形式) +// 根據 Signer API,以 Promise 形式呈現的地址 walletMnemonic.getAddress() // { Promise: '0x71CB05EE1b1F506fF321Da3dac38f25c0c9ce6E1' } -// 錢包地址也可以同步獲取 +// 錢包地址也可以同步取得 walletMnemonic.address // '0x71CB05EE1b1F506fF321Da3dac38f25c0c9ce6E1' -// 內部加密組件 +// 內部加密元件 walletMnemonic.privateKey // '0x1da6847600b0ee25e9ad9a52abbd786dd2502fa4005dd5af9310b7cc7a3b25db' walletMnemonic.publicKey @@ -110,8 +112,8 @@ walletMnemonic.mnemonic // phrase: 'announce room limb pattern dry unit scale effort smooth jazz weasel alcohol' // } -// 注意:用私鑰建立的錢包 -// 沒有助記詞(因為衍生過程不支援) +// 注意:使用私密金鑰建立的錢包並 +// 不會有助記詞 (衍生過程不支援) walletPrivateKey.mnemonic // null @@ -128,8 +130,8 @@ tx = { walletMnemonic.signTransaction(tx) // { Promise: '0xf865808080948ba1f109551bd432803012645ac136ddd64dba72880de0b6b3a7640000801ca0918e294306d177ab7bd664f5e141436563854ebe0a3e523b9690b4922bbb52b8a01181612cec9c431c4257a79b8c9f0c980a2c49bb5a0e6ac52949163eeb565dfc' } -// 連接方法返回一個新的連接到提供者的 -// 錢包執行個體, +// connect 方法會回傳一個 +// 連線至提供者的新錢包執行個體 wallet = walletMnemonic.connect(provider) // 查詢網路 @@ -138,20 +140,20 @@ wallet.getBalance() wallet.getTransactionCount() // { Promise: 0 } -// 發送以太幣 +// 傳送以太幣 wallet.sendTransaction(tx) ``` -[閱讀完整文檔](https://docs.ethers.io/v5/api/signer/#Wallet) +[閱讀完整文件](https://docs.ethers.io/v5/api/signer/#Wallet) 設定完成後,你將能夠: - 建立帳戶 - 傳送交易 - 簽署交易 -- 和更多... +- 以及更多... -### 與智慧型合約功能互動 {#interact-with-smart-contract-functions} +### 與智能合約函式互動 {#interact-with-smart-contract-functions} JavaScript 用戶端程式庫讓你的應用程式能透過讀取編譯合約的應用程式二進位介面 (ABI) 呼叫智慧型合約函式。 @@ -164,7 +166,7 @@ contract Test { uint a; address d = 0x12345678901234567890123456789012; - function Test(uint testInt) { a = testInt;} + constructor(uint testInt) { a = testInt;} event Event(uint indexed b, bytes32 c); @@ -211,13 +213,13 @@ contract Test { - 傳送交易至智慧型合約並執行其方法 - 呼叫以預估在以太坊虛擬機中執行時方法將花費的燃料 - 部署合約 -- 和更多... +- 和更多相關內容... -### 公用程式功能 {#utility-functions} +### 工具函式 {#utility-functions} 公用程式功能提供了方便的捷徑,讓以太坊中的構建變得更加容易。 -以太幣值預設以 Wei 為單位。 1 以太幣 = 1,000,000,000,000,000,000 WEI – 這意味著你正在處理大量數字! `web3.utils.toWei` 自動將以太幣轉換至 Wei。 +以太幣值預設以 Wei 為單位。 1 以太幣 = 1,000,000,000,000,000,000 WEI – 這意味著你正在處理大量數字! `web3.utils.toWei` 會為您將 ether 轉換為 Wei。 在以太幣中,如下所示: @@ -232,59 +234,56 @@ ethers.utils.formatEther(balance) // '2.337132817842795605' ``` -- [Web3js 公用程式功能](https://docs.web3js.org/api/web3-utils) -- [Ethers 公用程式功能](https://docs.ethers.io/v5/api/utils/) +- [Web3js 工具函式](https://docs.web3js.org/api/web3-utils) +- [Ethers 工具函式](https://docs.ethers.org/v6/api/utils/) -## 可用資料圖書庫 {#available-libraries} +## 可用函式庫 {#available-libraries} -**Web3.js -** **_以太坊 JavaScript 應用程式介面。 _** +**Web3.js -** **_以太坊 JavaScript API。_** -- [文件](https://docs.web3js.org/) -- [Github](https://github.com/ethereum/web3.js/) +- [文件](https://docs.web3js.org) +- [GitHub](https://github.com/ethereum/web3.js) -**Ethers.js -** **_使用 JavaScript 和 TypeScript 的完整以太坊錢包實作和公用程式。 _** +**Ethers.js -** **_在 JavaScript 和 TypeScript 中的完整以太坊錢包實作與工具。_** -- [文件](https://docs.ethers.io/) -- [Github](https://github.com/ethers-io/ethers.js/) +- [Ethers.js 首頁](https://ethers.org/) +- [文件](https://docs.ethers.io) +- [GitHub](https://github.com/ethers-io/ethers.js) -**The Graph -** **_用於為以太坊和星際檔案係統資料編製索引並使用 GraphQL 進行查詢的協議。_** +**The Graph -** **_一種用於索引以太坊和 IPFS 資料,並使用 GraphQL 查詢資料的協定。_** -- [The Graph](https://thegraph.com/) -- [Graph Explorer](https://thegraph.com/explorer/) -- [文件](https://thegraph.com/docs/) -- [Github](https://github.com/graphprotocol/) +- [The Graph](https://thegraph.com) +- [Graph 瀏覽器](https://thegraph.com/explorer) +- [文件](https://thegraph.com/docs) +- [GitHub](https://github.com/graphprotocol) - [Discord](https://thegraph.com/discord) -**light.js ****_針對輕量用戶端最佳化的高階回應式 JS 程式庫。_** - -- [Github](https://github.com/openethereum/js-libs/tree/master/packages/light.js) - -**Alchemyweb3 -** **_具有自動重試和增強型應用程式介面的 Web3.js 包裝函式。_** +**Alchemy SDK -** **_Ethers.js 的包裝器,具備增強的 API。_** -- [文件](https://docs.alchemy.com/reference/api-overview) -- [Github](https://github.com/alchemyplatform/alchemy-web3) - -**Alchemy 非同質化代幣應用程式介面 -** **_用於擷取非同質化代幣資料的應用程式介面,包括所有權、中繼資料屬性以及更多。_** - -- [文件](https://docs.alchemy.com/alchemy/enhanced-apis/nft-api) -- [GitHub](https://github.com/alchemyplatform/alchemy-web3) +- [文件](https://www.alchemy.com/docs) +- [GitHub](https://github.com/alchemyplatform/alchemy-sdk-js) **viem -** **_以太坊的 TypeScript 介面。_** - [文件](https://viem.sh) - [GitHub](https://github.com/wagmi-dev/viem) -## 衍生閱讀 {#further-reading} +**Drift -** **_具有內建快取、掛鉤和測試模擬的 TypeScript 元程式庫。_** + +- [文件](https://ryangoree.github.io/drift/) +- [GitHub](https://github.com/ryangoree/drift/) + +## 延伸閱讀 {#further-reading} -_知道對你有幫助的社群資源嗎? 請編輯此頁面並新增資源!_ +_知道一個曾經幫助你學習更多社區或社團資源? 歡迎在本頁自由編輯或添加內容!_ ## 相關主題 {#related-topics} - [節點和用戶端](/developers/docs/nodes-and-clients/) -- [開發架構](/developers/docs/frameworks/) +- [開發框架](/developers/docs/frameworks/) -## 相關教學影片 {#related-tutorials} +## 相關教學 {#related-tutorials} -- [設定 Web3js 以在 Javascript 中使用以太坊區塊鏈](/developers/tutorials/set-up-web3js-to-use-ethereum-in-javascript/) _– 在專案中設定 web3.js 的說明。_ -- [從 JavaScript 呼叫智慧型合約](/developers/tutorials/calling-a-smart-contract-from-javascript/) _– 使用 DAI 代幣,瞭解如何使用 JavaScript 呼叫合約函式。_ -- [使用 web3 和 Alchemy 傳送交易](/developers/tutorials/sending-transactions-using-web3-and-alchemy/) _– 從後端傳送交易的逐步演練。_ +- [設定 Web3js 以在 JavaScript 中使用以太坊區塊鏈](/developers/tutorials/set-up-web3js-to-use-ethereum-in-javascript/) _– 在專案中設定 web3.js 的說明。_ +- [從 JavaScript 呼叫智慧型合約](/developers/tutorials/calling-a-smart-contract-from-javascript/) _– 使用 DAI 代幣,了解如何透過 JavaScript 呼叫合約函式。_ +- [使用 web3 和 Alchemy 傳送交易](/developers/tutorials/sending-transactions-using-web3-and-alchemy/) _– 從後端傳送交易的逐步教學。_ diff --git a/public/content/translations/zh-tw/developers/docs/apis/json-rpc/index.md b/public/content/translations/zh-tw/developers/docs/apis/json-rpc/index.md index 35ce2484970..0e5b9a746d9 100644 --- a/public/content/translations/zh-tw/developers/docs/apis/json-rpc/index.md +++ b/public/content/translations/zh-tw/developers/docs/apis/json-rpc/index.md @@ -1,32 +1,32 @@ --- -title: JSON-RPC 應用程式介面 -description: 一種無狀態、輕量的以太坊用戶端遠端程序呼叫 (RPC) 協定。 +title: "JSON-RPC 應用程式介面" +description: "一種無狀態、輕量的以太坊用戶端遠端程序呼叫 (RPC) 協定。" lang: zh-tw --- 為了讓軟體應用程式能夠和以太坊區塊鏈互動(例如:讀取區塊鏈資料,發送交易到網路),必須先連結以太坊節點。 -為此,每個[以太坊用戶端](/developers/docs/nodes-and-clients/#execution-clients)都實作 [JSON-RPC 規範](https://github.com/ethereum/execution-apis),因此無論特定節點或用戶端實作如何,應用程式都可以依賴一組統一的方法。 +為此,每個 [以太坊用戶端](/developers/docs/nodes-and-clients/#execution-clients) 都實作了 [JSON-RPC 規範](https://github.com/ethereum/execution-apis),因此無論特定的節點或用戶端實作如何,應用程式都可以依賴一組統一的方法。 -[JSON-RPC](https://www.jsonrpc.org/specification) 是一種無狀態、輕量級的遠端程序呼叫 (RPC) 協定。 該協定定義了幾種資料結構及其處理規則。 它與傳輸無關,因為這些概念可以在同一進程中、透過通訊端、透過超文字傳輸協定或在許多不同的訊息傳遞環境中使用。 它使用 JSON (RFC 4627) 作為資料格式。 +[JSON-RPC](https://www.jsonrpc.org/specification) 是一種無狀態、輕量的遠端程序呼叫 (RPC) 協定。 該協定定義了幾種資料結構及其處理規則。 它與傳輸無關,因為這些概念可以在同一進程中、透過通訊端、透過超文字傳輸協定或在許多不同的訊息傳遞環境中使用。 它使用 JSON (RFC 4627) 作為資料格式。 ## 用戶端實作 {#client-implementations} -每個以太坊用戶端在實作 JSON-RPC 規範時可能會使用不同的程式設計語言。 有關特定程式設計語言的更多詳細資料,請參閱各個[用戶端文件](/developers/docs/nodes-and-clients/#execution-clients)。 我們建議檢查每個用戶端的文件以取得最新的應用程式介面支援資訊。 +每個以太坊用戶端在實作 JSON-RPC 規範時可能會使用不同的程式設計語言。 有關特定程式設計語言的進一步詳細資訊,請參閱各個 [用戶端文件](/developers/docs/nodes-and-clients/#execution-clients)。 我們建議檢查每個用戶端的文件以取得最新的應用程式介面支援資訊。 -## 便利程式庫 {#convenience-libraries} +## 便利函式庫 {#convenience-libraries} -雖然可以選擇透過 JSON-RPC 應用程式介面直接與以太坊用戶端互動,但對於去中心化應用程式開發者來說通常有更簡單的選擇。 許多 [JavaScript](/developers/docs/apis/javascript/#available-libraries) 和[後端應用程式介面](/developers/docs/apis/backend/#available-libraries) 程式庫都是為了在 JSON-RPC 應用程式介面之上提供包裝函式。 借助這些程式庫,開發者可以用自己選擇的程式語言編寫直覺的單行方法,以初始化與以太坊互動的 JSON-RPC 請求(在後台)。 +雖然可以選擇透過 JSON-RPC 應用程式介面直接與以太坊用戶端互動,但對於去中心化應用程式開發者來說通常有更簡單的選擇。 有許多 [JavaScript](/developers/docs/apis/javascript/#available-libraries) 和 [後端應用程式介面](/developers/docs/apis/backend/#available-libraries) 函式庫,可在 JSON-RPC API 之上提供包裝函式。 借助這些程式庫,開發者可以用自己選擇的程式語言編寫直覺的單行方法,以初始化與以太坊互動的 JSON-RPC 請求(在後台)。 -## 共識用戶端應用程式介面 {#consensus-clients} +## 共識用戶端 API {#consensus-clients} -本頁面主要討論以太坊執行用戶端使用的 JSON-RPC 應用程式介面。 然而,共識用戶端也有一個遠端程序呼叫應用程式介面,讓使用者能夠直接從節點查詢有關節點的資訊、請求信標區塊、信標狀態和其他共識相關資訊。 [信標應用程式介面網頁](https://ethereum.github.io/beacon-APIs/#/)上記錄了此應用程式介面。 +本頁面主要討論以太坊執行用戶端使用的 JSON-RPC 應用程式介面。 然而,共識用戶端也有一個遠端程序呼叫應用程式介面,讓使用者能夠直接從節點查詢有關節點的資訊、請求信標區塊、信標狀態和其他共識相關資訊。 此 API 記錄在 [Beacon API 網頁](https://ethereum.github.io/beacon-APIs/#/) 上。 -內部應用程式介面也用於節點內的用戶端間通訊 - 也就是說,它讓共識用戶端和執行用戶端能夠交換資料。 這被稱為「引擎應用程式介面」,其規範可在 [GitHub](https://github.com/ethereum/execution-apis/blob/main/src/engine/common.md) 上取得。 +內部應用程式介面也用於節點內的用戶端間通訊 - 也就是說,它讓共識用戶端和執行用戶端能夠交換資料。 這稱為「引擎 API」,規格可在 [GitHub](https://github.com/ethereum/execution-apis/blob/main/src/engine/common.md) 上取得。 -## 執行用戶端規範 {#spec} +## 執行用戶端規格 {#spec} -[在 GitHub 上閱讀完整的 JSON-RPC 應用程式介面規範](https://github.com/ethereum/execution-apis)。 此應用程式介面記錄在[執行應用程式介面網頁](https://ethereum.github.io/execution-apis/api-documentation/)上,並包含一個檢查器來嘗試所有可用的方法。 +[在 GitHub 上閱讀完整的 JSON-RPC API 規格](https://github.com/ethereum/execution-apis)。 此 API 記錄在 [執行 API 網頁](https://ethereum.github.io/execution-apis/),並包含一個檢查器來試用所有可用的方法。 ## 慣例 {#conventions} @@ -46,11 +46,11 @@ lang: zh-tw - 錯誤:0x0400(不允許有前導零) - 錯誤:ff(必須有前綴 0x) -### 無格式資料 {#unformatted-data-encoding} +### 未格式化資料 {#unformatted-data-encoding} 編碼無格式資料(位元組陣列、帳戶位址、雜湊值、位元組碼陣列)時:編碼為十六進位,前綴為「0x」,每個位元組兩個十六進位數字。 -這裡有些範例: +下面有些範例: - 0x41(大小為 1,「A」) - 0x004200(大小為 3,「0B0」) @@ -58,9 +58,9 @@ lang: zh-tw - 錯誤:0xf0f0f(位數必須為偶數) - 錯誤:004200(必須以 0x 為前綴) -### 預設區塊參數 {#default-block} +### 區塊參數 {#block-parameter} -下列方法有一個額外的預設區塊參數: +下列方法有一個額外的區塊參數: - [eth_getBalance](#eth_getbalance) - [eth_getCode](#eth_getcode) @@ -68,34 +68,34 @@ lang: zh-tw - [eth_getStorageAt](#eth_getstorageat) - [eth_call](#eth_call) -當發出對以太坊狀態進行動作的請求時,最後一個預設區塊參數決定了區塊的高度。 +當發出對以太坊狀態進行查詢的請求時,提供的區塊參數決定了區塊的高度。 -defaultBlock 參數可以使用以下選項: +區塊參數可以使用以下選項: -- `HEX String` - 表示整數區塊編號 -- `String "earliest"` 表示最早的/創世區塊 -- `String "latest"` - 表示最新提議的區塊 -- `String "safe"` - 表示最新安全的頭部區塊 -- `String "finalized"` - 表示最新最終確定的區塊 -- `String "pending"` - 表示未決的狀態/交易 +- `HEX 字串` - 整數區塊編號 +- `字串 "earliest"` 代表最早/創世區塊 +- `字串 "latest"` - 代表最新提議的區塊 +- `字串 "safe"` - 代表最新安全標頭區塊 +- `字串 "finalized"` - 代表最新最終確認區塊 +- `字串 "pending"` - 代表待處理狀態/交易 ## 範例 -在此頁面上,我們提供了有關如何透過命令列工具 [curl](https://curl.se) 使用各 JSON_RPC 應用程式介面端點的範例。 這些單獨的端點範例位於下面的 [Curl 範例](#curl-examples)部分。 在頁面下方,我們還提供了一個使用 Geth 節點、JSON_RPC 應用程式介面和 curl 來編譯和部署智慧型合約的[端到端範例](#usage-example)。 +本頁我們提供使用命令列工具 [curl](https://curl.se) 來操作各個 JSON_RPC API 端點的範例。 這些個別的端點範例可在下方的 [Curl 範例](#curl-examples) 一節中找到。 在頁面下方,我們也提供一個使用 Geth 節點、JSON_RPC API 和 curl 來編譯和部署智能合約的 [端對端範例](#usage-example)。 ## Curl 範例 {#curl-examples} -下面提供了使用 JSON_RPC 應用程式介面向以太坊節點發出 [curl](https://curl.se) 請求的範例。 每個範例包含對特定端點的描述、其參數、傳回類型,以及應該如何使用的可行範例。 +下方提供了透過向以太坊節點發出 [curl](https://curl.se) 請求來使用 JSON_RPC API 的範例。 每個範例包含對特定端點的描述、其參數、傳回類型,以及應該如何使用的可行範例。 -curl 請求可能會傳回與內容類型相關的錯誤訊息。 這是因為 `--data` 選項將內容類型設定為 `application/x-www-form-urlencoded`。 如果你的節點確實抱怨這一點,請手動在呼叫程式開始處放置 `-H "Content-Type: application/json"` 來設定標頭。 這些範例也不包括 URL/IP 和通訊埠組合,該組合必須是給 curl 的最後一個引數(例如 `127.0.0.1:8545`)。 完整的 curl 請求包含採用以下形式的附加資料: +curl 請求可能會傳回與內容類型相關的錯誤訊息。 這是因為 `--data` 選項會將內容類型設定為 `application/x-www-form-urlencoded`。 如果你的節點確實對此發出警告,請在呼叫的開頭放置 `-H "Content-Type: application/json"` 來手動設定標頭。 這些範例也不包含 URL/IP 和通訊埠的組合,此組合必須是提供給 curl 的最後一個引數 (例如 `127.0.0.1:8545`)。 完整的 curl 請求包含採用以下形式的附加資料: ```shell curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"web3_clientVersion","params":[],"id":67}' 127.0.0.1:8545 ``` -## Gossip、State、History {#gossip-state-history} +## Gossip、狀態、歷史 {#gossip-state-history} -少數重要的 JSON-RPC 方法需要來自以太坊網路的資料,這些資料分屬於三個種類:_Gossip、State 和 History_。 利用這些章節中的連結移動至每個方法,或利用目錄探索完整的方法清單。 +少數核心 JSON-RPC 方法需要來自以太坊網路的資料,並可整齊地分為三大類:_Gossip、狀態和歷史_。 利用這些章節中的連結移動至每個方法,或利用目錄探索完整的方法清單。 ### Gossip 方法 {#gossip-methods} @@ -104,7 +104,7 @@ curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","metho - [eth_blockNumber](#eth_blocknumber) - [eth_sendRawTransaction](#eth_sendrawtransaction) -### State 方法 {#state_methods} +### 狀態方法 {#state_methods} > 報告所有已存儲資料的目前狀態的方法。 「狀態」像是一大塊可分享的隨機存取記憶體,包含帳戶餘額、合約資料和燃料預估。 @@ -115,7 +115,7 @@ curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","metho - [eth_call](#eth_call) - [eth_estimateGas](#eth_estimategas) -### History 方法 {#history_methods} +### 歷史方法 {#history_methods} > 取得包括創世區塊在內的每一區塊的歷史記錄。 這像一個大型只能附加資料的檔案,包括所有區塊頭、區塊體、叔塊和交易收據。 @@ -134,9 +134,9 @@ curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","metho ## JSON-RPC 應用程式介面訓練場 -你可以使用[訓練場工具](https://ethereum-json-rpc.com)去發掘和試用應用程式介面方法。 訓練場也顯示不同的節點提供者支援的方法和網路。 +你可以使用 [遊樂場工具](https://ethereum-json-rpc.com) 來探索和試用 API 方法。 訓練場也顯示不同的節點提供者支援的方法和網路。 -## JSON-RPC 應用程式介面方法 {#json-rpc-methods} +## JSON-RPC API 方法 {#json-rpc-methods} ### web3_clientVersion {#web3_clientversion} @@ -148,14 +148,14 @@ curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","metho **傳回** -`String` - 目前用戶端版本 +`字串` - 目前的用戶端版本 **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"web3_clientVersion","params":[],"id":67}' -// Result +// 結果 { "id":67, "jsonrpc":"2.0", @@ -165,7 +165,7 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"web3_clientVersion","params":[], ### web3_sha3 {#web3_sha3} -傳回給定資料的 Keccak-256(_不是_ 標準化的 SHA3-256)。 +傳回給定資料的 Keccak-256 (「不是」標準化的 SHA3-256)。 **參數** @@ -175,16 +175,16 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"web3_clientVersion","params":[], params: ["0x68656c6c6f20776f726c64"] ``` -**返回** +**傳回** `DATA` - 給定字串的 SHA3 結果。 **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"web3_sha3","params":["0x68656c6c6f20776f726c64"],"id":64}' -// Result +// 結果 { "id":64, "jsonrpc": "2.0", @@ -200,7 +200,7 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"web3_sha3","params":["0x68656c6c 無 -**返回** +**傳回** `String` - 目前網路 ID。 @@ -208,14 +208,14 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"web3_sha3","params":["0x68656c6c - `1`:以太坊主網 - `11155111`:Sepolia 測試網 -- `17000`:Hoodi 測試網 +- `560048`:Hoodi 測試網 **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"net_version","params":[],"id":67}' -// Result +// 結果 { "id":67, "jsonrpc": "2.0", @@ -225,22 +225,22 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"net_version","params":[],"id":67 ### net_listening {#net_listening} -如果用戶端正在主動偵聽網路連結,則傳回 `true`。 +如果用戶端正在主動偵聽網路連線,則傳回 `true`。 **參數** 無 -**返回** +**傳回** -`Boolean` - 偵聽時為 `true`,否則為 `false`。 +`布林值` - 偵聽時為 `true`,否則為 `false`。 **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"net_listening","params":[],"id":67}' -// Result +// 結果 { "id":67, "jsonrpc":"2.0", @@ -256,16 +256,16 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"net_listening","params":[],"id": 無 -**返回** +**傳回** -`QUANTITY` - 表示連結的對等點數量的整數。 +`QUANTITY` - 連線的對等點數量的整數。 **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"net_peerCount","params":[],"id":74}' -// Result +// 結果 { "id":74, "jsonrpc": "2.0", @@ -275,22 +275,22 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"net_peerCount","params":[],"id": ### eth_protocolVersion {#eth_protocolversion} -傳回目前的以太坊協定版本。 請注意此方法[在 Geth 中不可用](https://github.com/ethereum/go-ethereum/pull/22064#issuecomment-788682924)。 +傳回目前的以太坊協定版本。 請注意,此方法在 [Geth 中不可用](https://github.com/ethereum/go-ethereum/pull/22064#issuecomment-788682924)。 **參數** 無 -**返回** +**傳回** -`String` - 目前的以太坊協定版本 +`字串` - 目前的以太坊協定版本 **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_protocolVersion","params":[],"id":67}' -// Result +// 結果 { "id":67, "jsonrpc": "2.0", @@ -300,21 +300,25 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_protocolVersion","params":[] ### eth_syncing {#eth_syncing} -傳回一個物件,其中包含有關同步狀態的資料或傳回 `false`。 +傳回一個包含同步狀態資料的物件,或傳回 `false`。 + + + 在遊樂場試用端點 + **參數** 無 -**返回** +**傳回** -準確的傳回資料因用戶端實作而異。 當節點未同步時,所有用戶端傳回 `False`,並且所有用戶端傳回下列欄位。 +準確的傳回資料因用戶端實作而異。 當節點未同步時,所有用戶端都會傳回 `False`,且所有用戶端都會傳回下列欄位。 -`Object|Boolean`,具有同步狀態資料的物件,或不同步時為 `FALSE`: +`物件|布林值`,一個具有同步狀態資料的物件,或在未同步時為 `FALSE`: -- `startingBlock`: `QUANTITY` - 匯入之開始區塊(僅在同步到達其頭部後才會重設) -- `currentBlock`: `QUANTITY` - 目前區塊,與 eth_blockNumber 相同 -- `highestBlock`: `QUANTITY` - 估計的最高區塊 +- `startingBlock`:`QUANTITY` - 開始匯入的區塊 (只有在同步達到其標頭後才會重設) +- `currentBlock`:`QUANTITY` - 目前區塊,與 eth_blockNumber 相同 +- `highestBlock`:`QUANTITY` - 預估的最高區塊 然而,個別用戶端也可以提供額外的資料。 例如 Geth 傳回如下資料: @@ -362,9 +366,9 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_protocolVersion","params":[] **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_syncing","params":[],"id":1}' -// Result +// 結果 { "id":1, "jsonrpc": "2.0", @@ -374,7 +378,7 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_syncing","params":[],"id":1} highestBlock: '0x454' } } -// Or when not syncing +// 或在未同步時 { "id":1, "jsonrpc": "2.0", @@ -386,7 +390,11 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_syncing","params":[],"id":1} 傳回用戶端的 coinbase 地址。 -> **注意:**此方法已於 **v1.14.0** 棄用並不再支援。 嘗試採用此方法將會出現「不支援此方法」的錯誤。 + + 在遊樂場試用端點 + + +> 注意:此方法自 **v1.14.0** 起已被棄用,不再支援。 嘗試採用此方法將會出現「不支援此方法」的錯誤。 **參數** @@ -394,14 +402,14 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_syncing","params":[],"id":1} **傳回** -`DATA`,20 位元組 - 目前 coinbase 地址。 +`DATA`,20 位元組 - 目前的 coinbase 位址。 **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_coinbase","params":[],"id":64}' -// Result +// 結果 { "id":64, "jsonrpc": "2.0", @@ -413,20 +421,24 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_coinbase","params":[],"id":6 傳回用來簽署重新執行攻擊保護交易的區塊鏈 ID。 + + 在遊樂場試用端點 + + **參數** 無 **傳回** -`chainId`,十六進位數值字串,表示目前區塊鏈 ID 的整數值。 +`chainId`,十六進位值,以字串形式表示目前鏈 ID 的整數。 **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":67}' -// Result +// 結果 { "id":67, "jsonrpc": "2.0", @@ -436,7 +448,11 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":67 ### eth_mining {#eth_mining} -如果用戶端正活躍地開採新區塊,則傳回 `true`。 這方法只對工作量證明網路傳回 `true` 且自[合併](/roadmap/merge/)後這方法不可用在某些用戶端。 +如果用戶端正在積極開採新區塊,則傳回 `true`。 這只能對工作量證明網路傳回 `true`,且自 [合併](/roadmap/merge/) 後,某些用戶端可能無法使用。 + + + 在遊樂場試用端點 + **參數** @@ -444,12 +460,12 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":67 **傳回** -`Boolean` - 如果用戶端正在挖礦,則傳回 `true`,否則傳回 `false`。 +`布林值` - 如果用戶端正在挖礦,則傳回 `true`,否則為 `false`。 **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_mining","params":[],"id":71}' // { @@ -461,7 +477,11 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_mining","params":[],"id":71} ### eth_hashrate {#eth_hashrate} -傳回正在挖礦的節點每秒的雜湊值數量。 這方法只對工作量證明網路傳回 `true` 且自[合併](/roadmap/merge/)後這方法不可用在某些用戶端。 +傳回正在挖礦的節點每秒的雜湊值數量。 這只能對工作量證明網路傳回 `true`,且自 [合併](/roadmap/merge/) 後,某些用戶端可能無法使用。 + + + 在遊樂場試用端點 + **參數** @@ -469,14 +489,14 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_mining","params":[],"id":71} **傳回** -`QUANTITY` - 每秒的雜湊數。 +`QUANTITY` - 每秒的哈希數。 **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_hashrate","params":[],"id":71}' -// Result +// 結果 { "id":71, "jsonrpc": "2.0", @@ -488,20 +508,24 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_hashrate","params":[],"id":7 傳回預估的目前燃料價格,以 wei 為單位。 例如:Besu 用戶端檢查最後面 100 個區塊並預設傳回燃料單價中位數。 + + 在遊樂場試用端點 + + **參數** 無 **傳回** -`QUANTITY` - 表示目前燃料價格的整數,以 wei 為單位。 +`QUANTITY` - 目前 gas 價格的整數,以 wei 為單位。 **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_gasPrice","params":[],"id":73}' -// Result +// 結果 { "id":73, "jsonrpc": "2.0", @@ -513,20 +537,24 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_gasPrice","params":[],"id":7 傳回用戶端擁有的地址清單。 + + 在遊樂場試用端點 + + **參數** 無 **傳回** -`Array of DATA`,20 位元組 - 用戶端擁有的地址。 +`DATA 陣列`,20 位元組 - 用戶端擁有的位址。 **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_accounts","params":[],"id":1}' -// Result +// 結果 { "id":1, "jsonrpc": "2.0", @@ -536,7 +564,11 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_accounts","params":[],"id":1 ### eth_blockNumber {#eth_blocknumber} -傳回最近的區塊編號。 +傳回最新區塊的編號。 + + + 在遊樂場試用端點 + **參數** @@ -544,14 +576,14 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_accounts","params":[],"id":1 **傳回** -`QUANTITY` - 表示用戶端目前所在區塊編號的整數。 +`QUANTITY` - 用戶端目前所在區塊編號的整數。 **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":83}' -// Result +// 結果 { "id":83, "jsonrpc": "2.0", @@ -561,12 +593,16 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id ### eth_getBalance {#eth_getbalance} -傳回給定地址的帳戶餘額。 +傳回指定位址帳戶的餘額。 + + + 在遊樂場試用端點 + **參數** -1. `DATA`,20 位元組 - 要檢查餘額的地址。 -2. `QUANTITY|TAG` - 整數區塊編號,或字串 `"latest"`、`"earliest"`、`"pending"`、`"safe"` 或 `"finalized"`,請參閱[預設區塊參數](/developers/docs/apis/json-rpc/#default-block) +1. `DATA`,20 位元組 - 要檢查餘額的位址。 +2. `QUANTITY|TAG` - 整數區塊編號,或字串 `"latest"`、`"earliest"`、`"pending"`、`"safe"` 或 `"finalized"`,請參閱[區塊參數](/developers/docs/apis/json-rpc/#block-parameter) ```js params: ["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "latest"] @@ -574,14 +610,14 @@ params: ["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "latest"] **傳回** -`QUANTITY` - 表示目前餘額的整數,以 wei 為單位。 +`QUANTITY` - 目前餘額的整數,以 wei 為單位。 **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBalance","params":["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "latest"],"id":1}' -// Result +// 結果 { "id":1, "jsonrpc": "2.0", @@ -593,30 +629,35 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBalance","params":["0x407 從給定地址的存儲位置傳回值。 + + 在遊樂場試用端點 + + **參數** -1. `DATA`,20 位元組 - 存儲地址。 -2. `QUANTITY` - 表示存儲中的位置的整數。 -3. `QUANTITY|TAG` - 整數區塊編號,或字串 `"latest"`、`"earliest"`、`"pending"`、`"safe"`、`"finalized"`,請參閱[預設區塊參數](/developers/docs/apis/json-rpc/#default-block) +1. `DATA`,20 位元組 - 儲存的位址。 +2. `QUANTITY` - 儲存中位置的整數。 +3. `QUANTITY|TAG` - 整數區塊編號,或字串 `"latest"`、`"earliest"`、`"pending"`、`"safe"`、`"finalized"`,請參閱[區塊參數](/developers/docs/apis/json-rpc/#block-parameter) **傳回** -`DATA` - 此存儲位置的值。 +`DATA` - 此儲存位置的值。 -**範例** 正確的位置計算取決於要擷取的存儲。 考慮透過地址 `0x391694e7e0b0cce554cb130d723a9d27458f9298` 部署在 `0x295a70b2de5e3953354a6a8344e616ed314d7251` 的以下合約。 +**範例** +計算正確位置取決於要擷取的儲存。 請考慮由位址 `0x391694e7e0b0cce554cb130d723a9d27458f9298` 部署在 `0x295a70b2de5e3953354a6a8344e616ed314d7251` 的下列合約。 ``` contract Storage { uint pos0; mapping(address => uint) pos1; - function Storage() { + constructor() { pos0 = 1234; pos1[msg.sender] = 5678; } } ``` -擷取 pos0 的值很簡單。 +擷取 pos0 的值很簡單: ```js curl -X POST --data '{"jsonrpc":"2.0", "method": "eth_getStorageAt", "params": ["0x295a70b2de5e3953354a6a8344e616ed314d7251", "0x0", "latest"], "id": 1}' localhost:8545 @@ -658,30 +699,34 @@ curl -X POST --data '{"jsonrpc":"2.0", "method": "eth_getStorageAt", "params": [ ### eth_getTransactionCount {#eth_gettransactioncount} -傳回從一個地址_發送_的交易數量。 +傳回從某一位址「傳送」的交易數量。 + + + 在遊樂場試用端點 + **參數** -1. `DATA`,20 位元組 - 地址。 -2. `QUANTITY|TAG` - 整數區塊編號,或字串 `"latest"`、`"earliest"`、`"pending"`、`"safe"` 或 `"finalized"`,請參閱[預設區塊參數](/developers/docs/apis/json-rpc/#default-block) +1. `DATA`,20 位元組 - 位址。 +2. `QUANTITY|TAG` - 整數區塊編號,或字串 `"latest"`、`"earliest"`、`"pending"`、`"safe"` 或 `"finalized"`,請參閱[區塊參數](/developers/docs/apis/json-rpc/#block-parameter) ```js params: [ "0x407d73d8a49eeb85d32cf465507dd71d507100c1", - "latest", // state at the latest block + "latest", // 最新區塊的狀態 ] ``` **傳回** -`QUANTITY` - 表示從該地址發送的交易數量的整數。 +`QUANTITY` - 從此位址傳送的交易數量之整數。 **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionCount","params":["0x407d73d8a49eeb85d32cf465507dd71d507100c1","latest"],"id":1}' -// Result +// 結果 { "id":1, "jsonrpc": "2.0", @@ -693,9 +738,13 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionCount","params 傳回區塊中從符合給定區塊雜湊值的交易數量。 + + 在遊樂場試用端點 + + **參數** -1. `DATA`,32 位元組 - 區塊的雜湊值 +1. `DATA`,32 位元組 - 區塊的哈希 ```js params: ["0xd03ededb7415d22ae8bac30f96b2d1de83119632693b963642318d87d1bece5b"] @@ -703,7 +752,7 @@ params: ["0xd03ededb7415d22ae8bac30f96b2d1de83119632693b963642318d87d1bece5b"] **傳回** -`QUANTITY` - 表示該區塊中交易數量的整數。 +`QUANTITY` - 此區塊中交易數量的整數。 **範例** @@ -722,9 +771,13 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBlockTransactionCountByHa 傳回與給定區塊編號相符的區塊中的交易數量。 + + 在遊樂場試用端點 + + **參數** -1. `QUANTITY|TAG` - 整數區塊編號,或字串 `"earliest"`、`"latest"`、`"pending"`、`"safe"` 或 `"finalized"`,如[預設區塊參數](/developers/docs/apis/json-rpc/#default-block)所示。 +1. `QUANTITY|TAG` - 區塊編號的整數,或字串 `"earliest"`、`"latest"`、`"pending"`、`"safe"` 或 `"finalized"`,如[區塊參數](/developers/docs/apis/json-rpc/#block-parameter)中所述。 ```js params: [ @@ -734,7 +787,7 @@ params: [ **傳回** -`QUANTITY` - 表示該區塊中交易數量的整數。 +`QUANTITY` - 此區塊中交易數量的整數。 **範例** @@ -753,9 +806,13 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBlockTransactionCountByNu 傳回區塊中符合給定區塊雜湊值的叔塊數量。 + + 在遊樂場試用端點 + + **參數** -1. `DATA`,32 位元組 - 區塊的雜湊值 +1. `DATA`,32 位元組 - 區塊的哈希 ```js params: ["0x1d59ff54b1eb26b013ce3cb5fc9dab3705b415a67127a003c3e61eb445bb8df2"] @@ -763,7 +820,7 @@ params: ["0x1d59ff54b1eb26b013ce3cb5fc9dab3705b415a67127a003c3e61eb445bb8df2"] **傳回** -`QUANTITY` - 表示該區塊中叔塊數量的整數。 +`QUANTITY` - 此區塊中叔塊數量的整數。 **範例** @@ -782,9 +839,13 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getUncleCountByBlockHash","p 傳回區塊中符合給定區塊編號的叔塊數量。 + + 在遊樂場試用端點 + + **參數** -1. `QUANTITY|TAG` - 整數區塊編號,或字串 `"latest"`、`"earliest"`、`"pending"`、`"safe"` 或 `"finalized"`,請參閱[預設區塊參數](/developers/docs/apis/json-rpc/#default-block) +1. `QUANTITY|TAG` - 區塊編號的整數,或字串 `"latest"`、`"earliest"`、`"pending"`、`"safe"` 或 `"finalized"`,請參閱[區塊參數](/developers/docs/apis/json-rpc/#block-parameter) ```js params: [ @@ -794,7 +855,7 @@ params: [ **傳回** -`QUANTITY` - 表示該區塊中叔塊數量的整數。 +`QUANTITY` - 此區塊中叔塊數量的整數。 **範例** @@ -813,10 +874,14 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getUncleCountByBlockNumber", 傳回給定地址的程式碼。 + + 在遊樂場試用端點 + + **參數** -1. `DATA`,20 位元組 - 地址 -2. `QUANTITY|TAG` - 整數區塊編號,或字串 `"latest"`、`"earliest"`、`"pending"`、`"safe"` 或 `"finalized"`,請參閱[預設區塊參數](/developers/docs/apis/json-rpc/#default-block) +1. `DATA`,20 位元組 - 位址 +2. `QUANTITY|TAG` - 整數區塊編號,或字串 `"latest"`、`"earliest"`、`"pending"`、`"safe"` 或 `"finalized"`,請參閱[區塊參數](/developers/docs/apis/json-rpc/#block-parameter) ```js params: [ @@ -827,7 +892,7 @@ params: [ **傳回** -`DATA` - 來自給定地址的程式碼。 +`DATA` - 來自給定位址的程式碼。 **範例** @@ -844,16 +909,16 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getCode","params":["0xC02aaA ### eth_sign {#eth_sign} -Sign 方法按以下方式計算以太坊特定簽章:`sign(keccak256("\x19Ethereum Signed Message:\n" + len(message) + message)))`。 +sign 方法會使用 `sign(keccak256("\x19Ethereum Signed Message:\n" + len(message) + message)))` 計算以太坊特定的簽章。 -透過在訊息中加入前綴,可以將計算出的簽章識別為以太坊特定簽章。 這可以防止濫用,即惡意去中心化應用程式簽署任意資料(例如交易)並使用簽章來冒充受害者。 +透過在訊息中加入前綴,可以將計算出的簽章識別為以太坊特定簽章。 這可以防止惡意去中心化應用程式簽署任意資料 (例如交易),並使用簽章冒充受害者的濫用情況。 注意:要簽章的地址必須解鎖。 **參數** -1. `DATA`,20 位元組 - 地址 -2. `DATA`,N 位元組 - 要簽署的訊息。 +1. `DATA`,20 位元組 - 位址 +2. `DATA`,N 位元組 - 要簽署的訊息 **傳回** @@ -862,9 +927,9 @@ Sign 方法按以下方式計算以太坊特定簽章:`sign(keccak256("\x19Eth **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_sign","params":["0x9b2055d370f73ec7d8a03e965129118dc8f5bf83", "0xdeadbeaf"],"id":1}' -// Result +// 結果 { "id":1, "jsonrpc": "2.0", @@ -874,31 +939,31 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_sign","params":["0x9b2055d37 ### eth_signTransaction {#eth_signtransaction} -簽署交易,稍後可使用 [eth_sendRawTransaction](#eth_sendrawtransaction) 將交易提交到網路。 +簽署一筆交易,稍後可使用 [eth_sendRawTransaction](#eth_sendrawtransaction) 提交到網路。 **參數** -1. `Object` - 交易物件 +1. `物件` - 交易物件 -- `type`: -- `from`: `DATA`,20 位元組 - 發送交易的地址。 -- `to`: `DATA` 20 位元組 -(建立新合約時可選)交易指向的地址。 -- `gas`: `QUANTITY` -(可選,預設:90000)表示為交易執行提供的燃料的整數。 將傳回未使用的燃料。 -- `gasPrice`: `QUANTITY` -(可選,預設:尚未決定)表示每次支付燃料時的燃料價格的整數(單位為 Wei)。 -- `value`: `QUANTITY` -(可選)表示與此交易一起傳送的值的整數(單位為 Wei)。 -- `data`: `DATA` - 合約的編譯程式碼,或叫用的方法簽章和編碼參數的雜湊。 -- `nonce`: `QUANTITY` -(可選)表示隨機數的整數。 這允許覆寫你自己的使用相同隨機數的待處理交易。 +- `type`: +- `from`:`DATA`,20 位元組 - 交易傳送方的位址。 +- `to`:`DATA`,20 位元組 - (建立新合約時為選用) 交易指向的位址。 +- `gas`:`QUANTITY` - (選用,預設值:90000) 為交易執行提供的 gas 整數值。 將傳回未使用的燃料。 +- `gasPrice`:`QUANTITY` - (選用,預設值:待定) 用於每次支付 gas 的 gasPrice 整數值,以 Wei 為單位。 +- `value`:`QUANTITY` - (選用) 隨此交易傳送的價值整數值,以 Wei 為單位。 +- `data`:`DATA` - 合約的已編譯程式碼,或是所叫用方法簽章和已編碼參數的哈希。 +- `nonce`:`QUANTITY` - (選用) nonce 的整數值。 這允許覆寫你自己的使用相同隨機數的待處理交易。 **傳回** -`DATA`,特定帳戶簽署的遞迴長度前綴編碼的交易物件。 +`DATA`,由指定帳戶簽署的 RLP 編碼交易物件。 **範例** ```js -// Request +// 請求 curl -X POST --data '{"id": 1,"jsonrpc": "2.0","method": "eth_signTransaction","params": [{"data":"0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675","from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155","gas": "0x76c0","gasPrice": "0x9184e72a000","to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567","value": "0x9184e72a"}]}' -// Result +// 結果 { "id": 1, "jsonrpc": "2.0", @@ -908,19 +973,19 @@ curl -X POST --data '{"id": 1,"jsonrpc": "2.0","method": "eth_signTransaction"," ### eth_sendTransaction {#eth_sendtransaction} -如果資料欄位包含程式碼,則建立新的訊息呼叫交易或建立合約,並使用 `from` 中指定的帳戶對其進行簽署。 +如果資料欄位包含程式碼,則建立新的訊息呼叫交易或合約建立,並使用 `from` 中指定的帳戶簽署。 **參數** -1. `Object` - 交易物件 +1. `物件` - 交易物件 -- `from`: `DATA`,20 位元組 - 發送交易的地址。 -- `to`: `DATA` 20 位元組 -(建立新合約時可選)交易指向的地址。 -- `gas`: `QUANTITY` -(可選,預設:90000)表示為交易執行提供的燃料的整數。 將傳回未使用的燃料。 -- `gasPrice`: `QUANTITY` -(可選,預設:尚未決定)表示每次支付燃料時的燃料價格的整數。 -- `value`: `QUANTITY` -(可選)表示與此交易一起傳送的值的整數。 -- `input`: `DATA` - 合約的編譯程式碼,或叫用的方法簽章和編碼參數的雜湊值。 -- `nonce`: `QUANTITY` -(可選)表示隨機數的整數。 這允許覆寫你自己的使用相同隨機數的待處理交易。 +- `from`:`DATA`,20 位元組 - 交易傳送方的位址。 +- `to`:`DATA`,20 位元組 - (建立新合約時為選用) 交易指向的位址。 +- `gas`:`QUANTITY` - (選用,預設值:90000) 為交易執行提供的 gas 整數值。 將傳回未使用的燃料。 +- `gasPrice`:`QUANTITY` - (選用,預設值:待定) 用於每次支付 gas 的 gasPrice 整數值。 +- `value`:`QUANTITY` - (選用) 隨此交易傳送的價值整數值。 +- `input`:`DATA` - 合約的已編譯程式碼,或是所叫用方法簽章和已編碼參數的哈希。 +- `nonce`:`QUANTITY` - (選用) nonce 的整數值。 這允許覆寫你自己的使用相同隨機數的待處理交易。 ```js params: [ @@ -938,16 +1003,16 @@ params: [ **傳回** -`DATA`,32 位元組 - 交易雜湊值,如果交易尚未可用則為零雜湊值。 +`DATA`,32 位元組 - 交易哈希,如果交易尚不可用,則為零哈希。 -建立合約時,在區塊中提議交易後,使用 [eth_getTransactionReceipt](#eth_gettransactionreceipt) 取得合約地址。 +當您建立合約時,在區塊中提議交易後,使用 [eth_getTransactionReceipt](#eth_gettransactionreceipt) 來取得合約位址。 **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_sendTransaction","params":[{see above}],"id":1}' -// Result +// 結果 { "id":1, "jsonrpc": "2.0", @@ -961,7 +1026,7 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_sendTransaction","params":[{ **參數** -1. `DATA`,簽署的交易資料。 +1. `DATA`,已簽署的交易資料。 ```js params: [ @@ -971,16 +1036,16 @@ params: [ **傳回** -`DATA`,32 位元組 - 交易雜湊值,如果交易尚未可用則為零雜湊值。 +`DATA`,32 位元組 - 交易哈希,如果交易尚不可用,則為零哈希。 -建立合約時,在區塊中提議交易後,使用 [eth_getTransactionReceipt](#eth_gettransactionreceipt) 取得合約地址。 +當您建立合約時,在區塊中提議交易後,使用 [eth_getTransactionReceipt](#eth_gettransactionreceipt) 來取得合約位址。 **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_sendRawTransaction","params":[{see above}],"id":1}' -// Result +// 結果 { "id":1, "jsonrpc": "2.0", @@ -990,20 +1055,24 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_sendRawTransaction","params" ### eth_call {#eth_call} -立即執行一個新的訊息呼叫,但不在區塊鏈上建立交易。 通常用於執行唯讀智慧型合約函式,例如 ERC-20 合約的 ` balanceOf`。 +立即執行一個新的訊息調用,但不在區塊鏈上建立交易。 常見用於執行唯讀的智能合約函式,例如 ERC-20 合約的 `balanceOf`。 + + + 在遊樂場試用端點 + **參數** -1. `Object` - 交易呼叫物件 +1. `物件` - 交易呼叫物件 -- `from`: `DATA`,20 位元組 -(可選)發送交易的地址。 -- `to`: `DATA`,20 位元組 - 交易指向的地址。 -- `gas`: `QUANTITY` -(可選)表示為交易執行提供的燃料的整數。 eth_call 消耗零燃料,但某些執行可能需要此參數。 -- `gasPrice`: `QUANTITY` -(可選)表示每次支付燃料時的燃料價格的整數 -- `value`: `QUANTITY` -(可選)表示與此交易一起傳送的值的整數 -- `input`: `DATA` -(可選)方法簽章和編碼參數的雜湊值。 詳細資料請參考 [Solidity 文檔中的以太坊合約應用程式二進位介面](https://docs.soliditylang.org/en/latest/abi-spec.html)。 +- `from`:`DATA`,20 位元組 - (選用) 交易傳送方的位址。 +- `to`:`DATA`,20 位元組 - 交易指向的位址。 +- `gas`:`QUANTITY` - (選用) 為交易執行提供的 gas 整數值。 eth_call 消耗零燃料,但某些執行可能需要此參數。 +- `gasPrice`:`QUANTITY` - (選用) 用於每次支付 gas 的 gasPrice 整數值 +- `value`:`QUANTITY` - (選用) 隨此交易傳送的價值整數值 +- `input`:`DATA` - (選用) 方法簽章和已編碼參數的哈希。 有關詳細資訊,請參閱 [Solidity 文件中的以太坊合約 ABI](https://docs.soliditylang.org/en/latest/abi-spec.html)。 -2. `QUANTITY|TAG` - 整數區塊編號,或字串 `"latest"`、`"earliest"`、`"pending"`、`"safe"` 或 `"finalized"`,請參閱[預設區塊參數](/developers/docs/apis/json-rpc/#default-block) +2. `QUANTITY|TAG` - 整數區塊編號,或字串 `"latest"`、`"earliest"`、`"pending"`、`"safe"` 或 `"finalized"`,請參閱[區塊參數](/developers/docs/apis/json-rpc/#block-parameter) **傳回** @@ -1012,9 +1081,9 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_sendRawTransaction","params" **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_call","params":[{see above}],"id":1}' -// Result +// 結果 { "id":1, "jsonrpc": "2.0", @@ -1026,20 +1095,24 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_call","params":[{see above}] 產生和傳回完成交易所必需的燃料量預估值。 交易將不會新增至區塊鏈。 請注意,由於以太坊虛擬機機制和節點效能等種種原因,預估值可能明顯地大於交易實際使用的燃料量。 + + 在遊樂場試用端點 + + **參數** -請參閱 [eth_call](#eth_call) 參數,但所有屬性都是可選的。 假如沒有明確說明燃料限制,Geth 將使用來自待處理區塊的區塊燃料限制作為上限。 因此,當燃料量高於待處理區塊燃料限制時,傳回的預估值可能不足以執行呼叫或交易。 +請參閱 [eth_call](#eth_call) 參數,但所有屬性都是選用的。 假如沒有明確說明燃料限制,Geth 將使用來自待處理區塊的區塊燃料限制作為上限。 因此,當 gas 量高於待處理區塊的 gas 限制時,傳回的估計值可能不足以執行呼叫/交易。 **傳回** -`QUANTITY` - 使用的燃料數量。 +`QUANTITY` - 使用的 gas 數量。 **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_estimateGas","params":[{see above}],"id":1}' -// Result +// 結果 { "id":1, "jsonrpc": "2.0", @@ -1051,10 +1124,14 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_estimateGas","params":[{see 根據雜湊值傳回區塊資訊。 + + 在遊樂場試用端點 + + **參數** -1. `DATA`,32 位元組 - 區塊的雜湊值。 -2. `Boolean` - 如果為 `true`,傳回完整交易物件,如果為 `false`,只傳回交易的雜湊值。 +1. `DATA`,32 位元組 - 區塊的哈希。 +2. `布林值` - 如果為 `true`,則傳回完整的交易物件;如果為 `false`,則只傳回交易的哈希。 ```js params: [ @@ -1065,39 +1142,38 @@ params: [ **傳回** -`Object` - 區塊物件,或如果未找到區塊,則為 `null`: - -- `number`: `QUANTITY` - 區塊編號。 當為待處理區塊時,為 `null`。 -- `hash`: `DATA`,32 位元組 - 區塊的雜湊值。 當為待處理區塊時,為 `null`。 -- `parentHash`: `DATA`,32 位元組 - 父區塊的雜湊值。 -- `nonce`: `DATA`,8 位元組 - 產生的工作量證明的雜湊值。 當為待處理區塊時,為 `null`。 -- `sha3Uncles`: `DATA`,32 位元組 - 區塊中叔塊資料的第三代安全雜湊演算法。 -- `logsBloom`: `DATA`,256 位元組 - 區塊日誌的布隆篩選器。 當為待處理區塊時,為 `null`。 -- `transactionsRoot`: `DATA`,32 位元組 - 區塊交易樹的根。 -- `stateRoot`: `DATA`,32 位元組 - 區塊最終狀態樹的根。 -- `receiptsRoot`: `DATA`,32 位元組 - 區塊收據樹的根。 -- `miner`: `DATA`,20 位元組 - 挖礦獎勵受款人的地址。 -- `difficulty`: `QUANTITY` - 表示區塊難度的整數。 -- `totalDifficulty`: `QUANTITY` - 表示此區塊前的區塊鏈的總難度的整數。 -- `extraData`: `DATA` - 該區塊的「額外資料」欄位。 -- `size`: `QUANTITY` - 表示此區塊大小的整數,以位元組為單位。 -- `gasLimit`: `QUANTITY` - 此區塊允許的最大燃料量。 -- `gasUsed`: `QUANTITY` - 此區塊所有交易所使用的總燃料量。 -- `timestamp`: `QUANTITY` - 整理區塊時的 unix 時間戳。 -- `transactions`: `Array` - 交易物件陣列,或是 32 位元組交易雜湊值,取決於最後一個給定的參數。 -- `uncles`: `Array` - 叔塊雜湊值陣列。 +`物件` - 區塊物件,如果找不到區塊,則為 `null`: + +- `number`:`QUANTITY` - 區塊編號。 當區塊為待處理區塊時為 `null`。 +- `hash`:`DATA`,32 位元組 - 區塊的哈希。 當區塊為待處理區塊時為 `null`。 +- `parentHash`:`DATA`,32 位元組 - 父區塊的哈希。 +- `nonce`:`DATA`,8 位元組 - 產生的工作量證明哈希。 當區塊為待處理區塊時為 `null`,權益證明區塊 (自合併後) 為 `0x0`。 +- `sha3Uncles`:`DATA`,32 位元組 - 區塊中叔塊資料的 SHA3。 +- `logsBloom`:`DATA`,256 位元組 - 用於區塊日誌的布隆篩選器。 當區塊為待處理區塊時為 `null`。 +- `transactionsRoot`:`DATA`,32 位元組 - 區塊交易樹的根。 +- `stateRoot`:`DATA`,32 位元組 - 區塊最終狀態樹的根。 +- `receiptsRoot`:`DATA`,32 位元組 - 區塊收據樹的根。 +- `miner`:`DATA`,20 位元組 - 獲得區塊獎勵的受益人位址。 +- `difficulty`:`QUANTITY` - 此區塊難度的整數。 +- `totalDifficulty`:`QUANTITY` - 到此區塊為止的鏈總難度的整數。 +- `extraData`:`DATA` - 此區塊的「額外資料」欄位。 +- `size`:`QUANTITY` - 此區塊大小的整數,以位元組為單位。 +- `gasLimit`:`QUANTITY` - 此區塊中允許的最大 gas。 +- `gasUsed`:`QUANTITY` - 此區塊中所有交易使用的總 gas。 +- `timestamp`:`QUANTITY` - 區塊整理時的 unix 時間戳。 +- `transactions`:`陣列` - 交易物件的陣列,或 32 位元組的交易哈希,取決於最後一個給定的參數。 +- `uncles`:`陣列` - 叔塊哈希的陣列。 **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBlockByHash","params":["0xdc0818cf78f21a8e70579cb46a43643f78291264dda342ae31049421c82d21ae", false],"id":1}' -// Result -{ +// 結果 { -"jsonrpc": "2.0", -"id": 1, -"result": { + "jsonrpc": "2.0", + "id": 1, + "result": { "difficulty": "0x4ea3f27bc", "extraData": "0x476574682f4c5649562f76312e302e302f6c696e75782f676f312e342e32", "gasLimit": "0x1388", @@ -1120,7 +1196,7 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBlockByHash","params":["0 "transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncles": [ ] -} + } } ``` @@ -1128,10 +1204,14 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBlockByHash","params":["0 根據區塊編號傳回關於區塊的資訊。 + + 在遊樂場試用端點 + + **參數** -1. `QUANTITY|TAG` - 整數區塊編號,或字串 `"earliest"`、`"latest"`、`"pending"`、`"safe"` 或 `"finalized"`,如[預設區塊參數](/developers/docs/apis/json-rpc/#default-block)所示。 -2. `Boolean` - 如果為 `true`,傳回完整交易物件,如果為 `false`,只傳回交易的雜湊值。 +1. `QUANTITY|TAG` - 區塊編號的整數,或字串 `"earliest"`、`"latest"`、`"pending"`、`"safe"` 或 `"finalized"`,如[區塊參數](/developers/docs/apis/json-rpc/#block-parameter)中所述。 +2. `布林值` - 如果為 `true`,則傳回完整的交易物件;如果為 `false`,則只傳回交易的哈希。 ```js params: [ @@ -1140,12 +1220,13 @@ params: [ ] ``` -**傳回** 請參與 [eth_getBlockByHash](#eth_getblockbyhash) +**傳回** +請參閱 [eth_getBlockByHash](#eth_getblockbyhash) **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x1b4", true],"id":1}' ``` @@ -1155,9 +1236,13 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":[ 傳回有關按交易雜湊值請求的交易的資訊。 + + 在遊樂場試用端點 + + **參數** -1. `DATA`,32 位元組 - 交易的雜湊值 +1. `DATA`,32 位元組 - 交易的哈希 ```js params: ["0x88df016429689c079f3b2f6ad39fa052532c56795b733da78a91ebe6a713944b"] @@ -1165,29 +1250,29 @@ params: ["0x88df016429689c079f3b2f6ad39fa052532c56795b733da78a91ebe6a713944b"] **傳回** -`Object` - 交易物件,或當找不到交易時為 `null`: - -- `blockHash`: `DATA`,32 位元組 - 此交易所在區塊的雜湊值。 當為待處理時,為 `null`。 -- `blockNumber`: `QUANTITY` - 此交易所在的區塊編號。 當為待處理時,為 `null`。 -- `from`: `DATA`,20 位元組 - 發送者的地址。 -- `gas`: `QUANTITY` - 發送者提供的燃料。 -- `gasPrice`: `QUANTITY` - 發送者提供的燃料價格,以 Wei 為單位。 -- `hash`: `DATA`,32 位元組 - 交易的雜湊值。 -- `input`: `DATA` - 隨交易一起傳送的資料。 -- `nonce`: `QUANTITY` - 發送者在這之前所進行的交易數量。 -- `to`: `DATA`,20 位元組 - 接收者的地址。 如果是合約建立交易,則為 `null`。 -- `transactionIndex`: `QUANTITY` - 表示區塊中交易索引位置的整數。 當為待處理時,為 `null`。 -- `value`: `QUANTITY` - 傳輸的值,以 Wei 為單位。 -- `v`: `QUANTITY` - 橢圓曲線數位簽章演算法復原 ID -- `r`: `QUANTITY` - 橢圓曲線數位簽章演算法簽章 r -- `s`: `QUANTITY` - 橢圓曲線數位簽章演算法簽章 s +`物件` - 交易物件,如果找不到交易,則為 `null`: + +- `blockHash`:`DATA`,32 位元組 - 此交易所在區塊的哈希。 當為待處理時為 `null`。 +- `blockNumber`:`QUANTITY` - 此交易所在的區塊編號。 當為待處理時為 `null`。 +- `from`:`DATA`,20 位元組 - 傳送方的位址。 +- `gas`:`QUANTITY` - 傳送方提供的 gas。 +- `gasPrice`:`QUANTITY` - 傳送方提供的 gas 價格,以 Wei 為單位。 +- `hash`:`DATA`,32 位元組 - 交易的哈希。 +- `input`:`DATA` - 隨交易一起傳送的資料。 +- `nonce`:`QUANTITY` - 傳送方在此交易之前所做的交易數量。 +- `to`:`DATA`,20 位元組 - 接收方的位址。 當為合約建立交易時為 `null`。 +- `transactionIndex`:`QUANTITY` - 區塊中交易索引位置的整數。 當為待處理時為 `null`。 +- `value`:`QUANTITY` - 轉帳的價值,以 Wei 為單位。 +- `v`:`QUANTITY` - ECDSA 復原 ID +- `r`:`QUANTITY` - ECDSA 簽章 r +- `s`:`QUANTITY` - ECDSA 簽章 s **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionByHash","params":["0x88df016429689c079f3b2f6ad39fa052532c56795b733da78a91ebe6a713944b"],"id":1}' -// Result +// 結果 { "jsonrpc":"2.0", "id":1, @@ -1214,10 +1299,14 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionByHash","param 按區塊雜湊值和交易索引位置傳回有關交易的資訊。 + + 在遊樂場試用端點 + + **參數** -1. `DATA`,32 位元組 - 區塊的雜湊值。 -2. `QUANTITY` - 表示交易索引位置的整數。 +1. `DATA`,32 位元組 - 區塊的哈希。 +2. `QUANTITY` - 交易索引位置的整數。 ```js params: [ @@ -1226,7 +1315,8 @@ params: [ ] ``` -**傳回** 請參閱 [eth_getTransactionByHash](#eth_gettransactionbyhash) +**傳回** +請參閱 [eth_getTransactionByHash](#eth_gettransactionbyhash) **範例** @@ -1241,9 +1331,13 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionByBlockHashAnd 按區塊編號和交易索引位置傳回有關交易的資訊。 + + 在遊樂場試用端點 + + **參數** -1. `QUANTITY|TAG` - 區塊編號,或字串 `"earliest"`、`"latest"`、`"pending"`、`"safe"` 或 `"finalized"`,如[預設區塊參數](/developers/docs/apis/json-rpc/#default-block)所示。 +1. `QUANTITY|TAG` - 區塊編號,或字串 `"earliest"`、`"latest"`、`"pending"`、`"safe"` 或 `"finalized"`,如[區塊參數](/developers/docs/apis/json-rpc/#block-parameter)中所述。 2. `QUANTITY` - 交易索引位置。 ```js @@ -1253,12 +1347,13 @@ params: [ ] ``` -**傳回** 請參閱 [eth_getTransactionByHash](#eth_gettransactionbyhash) +**傳回** +請參閱 [eth_getTransactionByHash](#eth_gettransactionbyhash) **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionByBlockNumberAndIndex","params":["0x9c47cf", "0x24"],"id":1}' ``` @@ -1268,43 +1363,44 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionByBlockNumberA 按交易雜湊值返回交易的收據。 -**注意**待處理交易沒有收據。 +**注意** 待處理交易沒有收據。 **參數** -1. `DATA`,32 位元組 - 交易的雜湊值 +1. `DATA`,32 位元組 - 交易的哈希 ```js params: ["0x85d995eba9763907fdf35cd2034144dd9d53ce32cbec21349d4b12823c6860c5"] ``` -**傳回** `Object` - 交易收據物件,或當找不到收據時為 `null`: - -- `transactionHash`: `DATA`,32 位元組 - 交易的雜湊值。 -- `transactionIndex`: `QUANTITY` - 表示區塊中交易索引位置的整數。 -- `blockHash`: `DATA`,32 位元組 - 此交易所在區塊的雜湊值。 -- `blockNumber`: `QUANTITY` - 此交易所在的區塊編號。 -- `from`: `DATA`,20 位元組 - 發送者的地址。 -- `to`: `DATA`,20 位元組 - 接收者的地址。 如果是合約建立交易,則為 null。 -- `cumulativeGasUsed`: `QUANTITY` - 當區塊執行此交易時所使用的總燃料量。 -- `effectiveGasPrice`: `QUANTITY` - 每單位燃料支付的基本費用和小費的總和。 -- `gasUsed`: `QUANTITY` - 僅此特定交易所使用的燃料量。 -- `contractAddress`: `DATA`,20 位元組 - 如果交易為建立合約,則為建立的合約地址,否則為 `null`。 -- `logs`: `Array` - 此交易產生的日誌物件陣列。 -- `logsBloom`: `DATA`,256 位元組 - 給輕量用戶端快速擷取相關日誌的布隆篩選器。 -- `type`: `QUANTITY` - 表示交易類型的整數,`0x0` 表示傳統交易,`0x1` 表示存取清單類型, `0x2` 表示動態費用。 - -它也傳回 _以下兩者之一_: - -- `root` : `DATA` 32 位元組的交易後狀態根(拜占庭升級之前) -- `status`: `QUANTITY` 要麼 `1`(成功)要麼 `0`(失敗) +**傳回** +`物件` - 交易收據物件,如果找不到收據,則為 `null`: + +- `transactionHash `:`DATA`,32 位元組 - 交易的哈希。 +- `transactionIndex`:`QUANTITY` - 區塊中交易索引位置的整數。 +- `blockHash`:`DATA`,32 位元組 - 此交易所在區塊的哈希。 +- `blockNumber`:`QUANTITY` - 此交易所在的區塊編號。 +- `from`:`DATA`,20 位元組 - 傳送方的位址。 +- `to`:`DATA`,20 位元組 - 接收方的位址。 如果是合約建立交易,則為 null。 +- `cumulativeGasUsed` : `QUANTITY ` - 當此交易在區塊中執行時使用的總 gas 量。 +- `effectiveGasPrice`:`QUANTITY` - 每單位 gas 支付的基本費用和小費的總和。 +- `gasUsed `:`QUANTITY ` - 僅此特定交易所使用的 gas 量。 +- `contractAddress `:`DATA`,20 位元組 - 如果交易是合約建立,則為建立的合約位址,否則為 `null`。 +- `logs`:`陣列` - 此交易所產生的日誌物件陣列。 +- `logsBloom`:`DATA`,256 位元組 - 供輕用戶端快速擷取相關日誌的布隆篩選器。 +- `type`:`QUANTITY` - 交易類型的整數,`0x0` 為舊式交易,`0x1` 為存取列表類型,`0x2` 為動態費用。 + +它也傳回以下其中一項: + +- `root`:`DATA` 32 位元組的交易後狀態根 (拜占庭前) +- `status`:`QUANTITY` 為 `1` (成功) 或 `0` (失敗) **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionReceipt","params":["0x85d995eba9763907fdf35cd2034144dd9d53ce32cbec21349d4b12823c6860c5"],"id":1}' -// Result +// 結果 { "jsonrpc": "2.0", "id": 1, @@ -1312,15 +1408,15 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionReceipt","para "blockHash": "0xa957d47df264a31badc3ae823e10ac1d444b098d9b73d204c40426e57f47e8c3", "blockNumber": "0xeff35f", - "contractAddress": null, // string of the address if it was created + "contractAddress": null, // 如果已建立,則為位址字串 "cumulativeGasUsed": "0xa12515", "effectiveGasPrice": "0x5a9c688d4", "from": "0x6221a9c005f6e47eb398fd867784cacfdcfff4e7", "gasUsed": "0xb4c8", "logs": [{ - // logs as returned by getFilterLogs, etc. + // getFilterLogs 等傳回的日誌 }], - "logsBloom": "0x00...0", // 256 byte bloom filter + "logsBloom": "0x00...0", // 256 位元組布隆篩選器 "status": "0x1", "to": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "transactionHash": @@ -1333,11 +1429,15 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionReceipt","para ### eth_getUncleByBlockHashAndIndex {#eth_getunclebyblockhashandindex} -按雜湊值和叔塊索引位置傳回關於區塊的叔塊資訊。 +透過哈希和叔塊索引位置傳回區塊叔塊的相關資訊。 + + + 在遊樂場試用端點 + **參數** -1. `DATA`,32 位元組 - 區塊的雜湊值。 +1. `DATA`,32 位元組 - 區塊的哈希。 2. `QUANTITY` - 叔塊的索引位置。 ```js @@ -1347,7 +1447,8 @@ params: [ ] ``` -**傳回** 請參與 [eth_getBlockByHash](#eth_getblockbyhash) +**傳回** +請參閱 [eth_getBlockByHash](#eth_getblockbyhash) **範例** @@ -1358,15 +1459,19 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getUncleByBlockHashAndIndex" 結果請參閱 [eth_getBlockByHash](#eth_getblockbyhash) -**注意**:叔塊不包含單獨交易。 +**注意**:叔塊不包含個別交易。 ### eth_getUncleByBlockNumberAndIndex {#eth_getunclebyblocknumberandindex} -按編號和叔塊索引位置傳回關於區塊的叔塊資訊。 +透過編號和叔塊索引位置傳回區塊叔塊的相關資訊。 + + + 在遊樂場試用端點 + **參數** -1. `QUANTITY|TAG` - 區塊編號,或字串 `"earliest"`、`"latest"`、`"pending"`、`"safe"` 或 `"finalized"`,如[預設區塊參數](/developers/docs/apis/json-rpc/#default-block)所示。 +1. `QUANTITY|TAG` - 區塊編號,或字串 `"earliest"`、`"latest"`、`"pending"`、`"safe"`、`"finalized"`,如[區塊參數](/developers/docs/apis/json-rpc/#block-parameter)中所述。 2. `QUANTITY` - 叔塊的索引位置。 ```js @@ -1376,14 +1481,15 @@ params: [ ] ``` -**傳回** 請參與 [eth_getBlockByHash](#eth_getblockbyhash) +**傳回** +請參閱 [eth_getBlockByHash](#eth_getblockbyhash) -**注意**:叔塊不包含單獨交易。 +**注意**:叔塊不包含個別交易。 **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getUncleByBlockNumberAndIndex","params":["0x29c", "0x0"],"id":1}' ``` @@ -1391,23 +1497,25 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getUncleByBlockNumberAndInde ### eth_newFilter {#eth_newfilter} -根據篩選條件選項建立一個篩選條件物件,以在狀態改變時發出通知(日誌)。 檢查狀態是否改變,呼叫 [eth_getFilterChanges](#eth_getfilterchanges)。 +根據篩選條件選項建立一個篩選條件物件,以在狀態改變時發出通知(日誌)。 +若要檢查狀態是否已變更,請呼叫 [eth_getFilterChanges](#eth_getfilterchanges)。 -**關於指定主題篩選條件的說明:** 主題跟順序相關。 以下主題篩選條件將匹配日誌中包含主題 [A, B] 的交易: +**關於指定主題篩選器的說明:** +主題是順序相依的。 以下主題篩選條件將匹配日誌中包含主題 [A, B] 的交易: -- `[]`「任意值」 -- `[A]`「第一個位置為 A(其後為任意值)」 -- `[null, B]`「第一位置為任意值,且第二位置為 B(其後為任意值)」 -- `[A, B]`「第一位置為 A,且第二位置為 B(其後為任意值)」 -- `[[A, B], [A, B]]`「第一位置為(A 或 B)且第二位置為(A 或 B)(其後為任意值)」 +- `[]` 「任何內容」 +- `[A]` 「A 在第一個位置 (後面可以是任何內容)」 +- `[null, B]` 「第一個位置是任何內容,且 B 在第二個位置 (後面可以是任何內容)」 +- `[A, B]` 「A 在第一個位置,且 B 在第二個位置 (後面可以是任何內容)」 +- `[[A, B], [A, B]]` 「(A 或 B) 在第一個位置,且 (A 或 B) 在第二個位置 (後面可以是任何內容)」 - **參數** -1. `Object` - 篩選條件選項: +1. `物件` - 篩選選項: -- `fromBlock`: `QUANTITY|TAG` -(可選,預設:`"latest"`)整數區塊編號,或 `"latest"` 表示最近提議的區塊,`"safe"` 表示最新的安全區塊,`"finalized"` 表示最新的最終確定區塊,或 `"pending"`,`"earliest"` 表示尚未在區塊中的交易。 -- `toBlock`: `QUANTITY|TAG` -(可選,預設:`"latest"`)整數區塊編號,或 `"latest"` 表示最近提議的區塊,`"safe"` 表示最新的安全區塊,`"finalized"` 表示最新的最終確定區塊,或 `"pending"`,`"earliest"` 表示尚未在區塊中的交易。 -- `address`: `DATA|Array`,20 位元組 - (可選)合約地址或日誌起源的地址清單。 -- `topics`: `Array of DATA`,(可選)32 位元組陣列 `DATA` 主題。 主題與順序相關。 每個主題也可以為帶有「或」選項的 DATA 陣列。 +- `fromBlock`:`QUANTITY|TAG` - (選用,預設:`"latest"`) 整數區塊編號,或 `"latest"` 代表最後提議的區塊、`"safe"` 代表最新的安全區塊、`"finalized"` 代表最新的最終確認區塊,或 `"pending"`、`"earliest"` 代表尚未進入區塊的交易。 +- `toBlock`:`QUANTITY|TAG` - (選用,預設:`"latest"`) 整數區塊編號,或 `"latest"` 代表最後提議的區塊、`"safe"` 代表最新的安全區塊、`"finalized"` 代表最新的最終確認區塊,或 `"pending"`、`"earliest"` 代表尚未進入區塊的交易。 +- `address`:`DATA|陣列`,20 位元組 - (選用) 合約位址或日誌應源自的位址清單。 +- `topics`:`DATA 陣列` - (選用) 32 位元組 `DATA` 主題的陣列。 主題與順序相關。 每個主題也可以為帶有「或」選項的 DATA 陣列。 ```js params: [ @@ -1427,14 +1535,15 @@ params: [ ] ``` -**傳回** `QUANTITY` - 篩選條件 ID。 +**傳回** +`QUANTITY` - 篩選器 ID。 **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_newFilter","params":[{"topics":["0x12341234"]}],"id":73}' -// Result +// 結果 { "id":1, "jsonrpc": "2.0", @@ -1444,18 +1553,21 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_newFilter","params":[{"topic ### eth_newBlockFilter {#eth_newblockfilter} -在節點中建立一個篩選條件,以在新區塊到達時發出通知。 檢查狀態是否改變,呼叫 [eth_getFilterChanges](#eth_getfilterchanges)。 +在節點中建立一個篩選條件,以在新區塊到達時發出通知。 +若要檢查狀態是否已變更,請呼叫 [eth_getFilterChanges](#eth_getfilterchanges)。 -**參數** 無 +**參數** +無 -**傳回** `QUANTITY` - 篩選條件 ID。 +**傳回** +`QUANTITY` - 篩選器 ID。 **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_newBlockFilter","params":[],"id":73}' -// Result +// 結果 { "id":1, "jsonrpc": "2.0", @@ -1465,18 +1577,21 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_newBlockFilter","params":[], ### eth_newPendingTransactionFilter {#eth_newpendingtransactionfilter} -在節點中建立一個篩選條件,以在新的待處理交易到達時發出通知。 檢查狀態是否改變,呼叫 [eth_getFilterChanges](#eth_getfilterchanges)。 +在節點中建立一個篩選條件,以在新的待處理交易到達時發出通知。 +若要檢查狀態是否已變更,請呼叫 [eth_getFilterChanges](#eth_getfilterchanges)。 -**參數** 無 +**參數** +無 -**傳回** `QUANTITY` - 篩選條件 ID。 +**傳回** +`QUANTITY` - 篩選器 ID。 **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_newPendingTransactionFilter","params":[],"id":73}' -// Result +// 結果 { "id":1, "jsonrpc": "2.0", @@ -1486,11 +1601,12 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_newPendingTransactionFilter" ### eth_uninstallFilter {#eth_uninstallfilter} -根據給定 ID 解除安裝篩選條件。 當不再需要監視時,應始終對其進行呼叫。 另外,當在一段時間內未使用 [eth_getFilterChanges](#eth_getfilterchanges) 請求篩選條件時,篩選條件會逾時。 +根據給定 ID 解除安裝篩選條件。 當不再需要監視時,應始終對其進行呼叫。 +此外,如果篩選器在一段時間內未使用 [eth_getFilterChanges](#eth_getfilterchanges) 請求,則會逾時。 **參數** -1. `QUANTITY` - 篩選條件 ID。 +1. `QUANTITY` - 篩選器 ID。 ```js params: [ @@ -1498,14 +1614,15 @@ params: [ ] ``` -**傳回** `Boolean` - 如果成功解除安裝篩選條件,則為 `true`,否則為 `false`。 +**傳回** +`布林值` - 如果篩選器成功解除安裝,則為 `true`,否則為 `false`。 **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_uninstallFilter","params":["0xb"],"id":73}' -// Result +// 結果 { "id":1, "jsonrpc": "2.0", @@ -1519,7 +1636,7 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_uninstallFilter","params":[" **參數** -1. `QUANTITY` - 篩選條件 ID。 +1. `QUANTITY` - 篩選器 ID。 ```js params: [ @@ -1527,26 +1644,30 @@ params: [ ] ``` -**傳回** `Array` - 日誌物件陣列,或如果自上次輪詢沒有任何變更,則為空陣列。 - -- 對於使用 `eth_newBlockFilter` 建立的篩選條件,傳回值是區塊雜湊值(`DATA`,32 位元組),例如 `["0x3454645634534..."]`。 -- 對於使用 `eth_newPendingTransactionFilter` 建立的篩選條件,傳回值是交易雜湊值(`DATA`,32 位元組),例如 `["0x6345343454645..."]`。 -- 對於使用 `eth_newFilter` 建立的篩選條件,日誌是包含下列參數的物件: - - `removed`: `TAG` - 當日誌由於鏈重組被移除時,為 `true`。 如果是有效日誌,則為 `false`。 - - `logIndex`: `QUANTITY` - 表示區塊內日誌索引位置的整數。 當為待處理日誌時,為 `null`。 - - `transactionIndex`: `QUANTITY` - 表示從中建立日誌的交易索引位置的整數。 當為待處理日誌時,為 `null`。 - - `transactionHash`: `DATA`,32 位元組 - 從中建立此日誌的交易的雜湊值。 當為待處理日誌時,為 `null`。 - - `blockHash`: `DATA`,32 位元組 - 此日誌所在區塊的雜湊值。 當為待處理時,為 `null`。 當為待處理日誌時,為 `null`。 - - `blockNumber`: `QUANTITY` - 此日誌所在的區塊編號。 當為待處理時,為 `null`。 當為待處理日誌時,為 `null`。 - - `address`: `DATA`,20 位元組 -此日誌的來源地址。 - - `data`: `DATA` - 包含零個或多個 32 位元組非索引日誌引數。 - - `topics`: `Array of DATA` - 索引日誌引數的 0 到 4 個 32 位元組 `DATA` 陣列。 (在 _solidity_:第一個主題是事件簽章的_雜湊值_(例如 `Deposit(address,bytes32,uint256)`),除非你使用說明符 `anonymous` 宣告了該事件)。 +**傳回** +`陣列` - 日誌物件的陣列,如果自上次輪詢以來沒有任何變更,則為空陣列。 + +- 對於使用 `eth_newBlockFilter` 建立的篩選器,傳回值為區塊哈希 (`DATA`,32 位元組),例如 `["0x3454645634534..."]`。 + +- 對於使用 `eth_newPendingTransactionFilter ` 建立的篩選器,傳回值為交易哈希 (`DATA`,32 位元組),例如 `["0x6345343454645..."]`。 + +- 對於使用 `eth_newFilter` 建立的篩選器,日誌是具有以下參數的物件: + - `removed`:`TAG` - `true` 表示由於鏈重組而移除了日誌。 如果是有效日誌,則為 `false`。 + - `logIndex`:`QUANTITY` - 區塊中日誌索引位置的整數。 當為待處理日誌時為 `null`。 + - `transactionIndex`:`QUANTITY` - 建立日誌的交易索引位置的整數。 當為待處理日誌時為 `null`。 + - `transactionHash`:`DATA`,32 位元組 - 建立此日誌的交易哈希。 當為待處理日誌時為 `null`。 + - `blockHash`:`DATA`,32 位元組 - 此日誌所在區塊的哈希。 當為待處理時為 `null`。 當為待處理日誌時為 `null`。 + - `blockNumber`:`QUANTITY` - 此日誌所在的區塊編號。 當為待處理時為 `null`。 當為待處理日誌時為 `null`。 + - `address`:`DATA`,20 位元組 - 此日誌源自的位址。 + - `data`:`DATA` - 可變長度的非索引日誌資料。 (在 _solidity_ 中:零個或多個 32 位元組的非索引日誌引數。) + - `topics`:`DATA 陣列` - 0 到 4 個 32 位元組 `DATA` 的索引日誌引數陣列。 (在 _solidity_ 中:第一個主題是事件簽章的_哈希_ (例如 `Deposit(address,bytes32,uint256)`),除非您使用 `anonymous` 指定符宣告了該事件。) + - **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getFilterChanges","params":["0x16"],"id":73}' -// Result +// 結果 { "id":1, "jsonrpc":"2.0", @@ -1571,7 +1692,7 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getFilterChanges","params":[ **參數** -1. `QUANTITY` - 篩選條件 ID。 +1. `QUANTITY` - 篩選器 ID。 ```js params: [ @@ -1579,12 +1700,13 @@ params: [ ] ``` -**傳回** 請參閱 [eth_getFilterChanges](#eth_getfilterchanges) +**傳回** +請參閱 [eth_getFilterChanges](#eth_getfilterchanges) **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getFilterLogs","params":["0x16"],"id":74}' ``` @@ -1596,13 +1718,13 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getFilterLogs","params":["0x **參數** -1. `Object` - 篩選條件選項: +1. `物件` - 篩選選項: -- `fromBlock`: `QUANTITY|TAG` -(可選,預設:`"latest"`)整數區塊編號,或 `"latest"` 表示最近提議的區塊,`"safe"` 表示最新的安全區塊,`"finalized"` 表示最新的最終確定區塊,或 `"pending"`,`"earliest"` 表示尚未在區塊中的交易。 -- `toBlock`: `QUANTITY|TAG` -(可選,預設:`"latest"`)整數區塊編號,或 `"latest"` 表示最近提議的區塊,`"safe"` 表示最新的安全區塊,`"finalized"` 表示最新的最終確定區塊,或 `"pending"`,`"earliest"` 表示尚未在區塊中的交易。 -- `address`: `DATA|Array`,20 位元組 - (可選)合約地址或日誌起源的地址清單。 -- `topics`: `Array of DATA`,(可選)32 位元組陣列 `DATA` 主題。 主題與順序相關。 每個主題也可以為帶有「或」選項的 DATA 陣列。 -- `blockhash`: `DATA`,32 位元組 - (可選,**future**),新增 EIP-234 後,`blockHash` 將是一個新的篩選條件選項,會將傳回的日誌限制為具有 32 位元組雜湊值 `blockHash` 的單一區塊。 使用 `blockHash` 等於 `fromBlock` = `toBlock` = 具有雜湊值 `blockHash` 的區塊編號。 如果 `blockHash` 出現在篩選條件中,則 `fromBlock` 和 `toBlock` 都不允許使用。 +- `fromBlock`:`QUANTITY|TAG` - (選用,預設:`"latest"`) 整數區塊編號,或 `"latest"` 代表最後提議的區塊、`"safe"` 代表最新的安全區塊、`"finalized"` 代表最新的最終確認區塊,或 `"pending"`、`"earliest"` 代表尚未進入區塊的交易。 +- `toBlock`:`QUANTITY|TAG` - (選用,預設:`"latest"`) 整數區塊編號,或 `"latest"` 代表最後提議的區塊、`"safe"` 代表最新的安全區塊、`"finalized"` 代表最新的最終確認區塊,或 `"pending"`、`"earliest"` 代表尚未進入區塊的交易。 +- `address`:`DATA|陣列`,20 位元組 - (選用) 合約位址或日誌應源自的位址清單。 +- `topics`:`DATA 陣列` - (選用) 32 位元組 `DATA` 主題的陣列。 主題與順序相關。 每個主題也可以為帶有「或」選項的 DATA 陣列。 +- `blockHash`:`DATA`,32 位元組 - (選用,**未來**) 隨著 EIP-234 的新增,`blockHash` 將成為一個新的篩選選項,它會將傳回的日誌限制在具有 32 位元組哈希 `blockHash` 的單一區塊中。 使用 `blockHash` 等同於 `fromBlock` = `toBlock` = 具有哈希 `blockHash` 的區塊編號。 如果 `blockHash` 存在於篩選條件中,則不允許使用 `fromBlock` 和 `toBlock`。 ```js params: [ @@ -1614,12 +1736,13 @@ params: [ ] ``` -**傳回** 請參閱 [eth_getFilterChanges](#eth_getfilterchanges) +**傳回** +請參閱 [eth_getFilterChanges](#eth_getfilterchanges) **範例** ```js -// Request +// 請求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getLogs","params":[{"topics":["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b"]}],"id":74}' ``` @@ -1629,9 +1752,9 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getLogs","params":[{"topics" ### 使用 JSON_RPC 部署合約 {#deploying-contract} -這部分示範如何只使用遠端程序呼叫介面部署合約。 有其他的部署合約方法可以消除這種複雜性,例如,使用建置在遠端程序呼叫介面之上的程式庫,例如 [web3.js](https://web3js.readthedocs.io/) 和 [web3.py](https://github.com/ethereum/web3.py)。 雖然在抽象化之後,一般來說比較容易理解和較不易出錯,但理解在後台發生了什麼是有益的。 +這部分示範如何只使用遠端程序呼叫介面部署合約。 還有其他部署合約的替代途徑,可以將這種複雜性抽象化,例如,使用建構在 RPC 介面之上的函式庫,如 [web3.js](https://web3js.readthedocs.io/) 和 [web3.py](https://github.com/ethereum/web3.py)。 雖然在抽象化之後,一般來說比較容易理解和較不易出錯,但理解在後台發生了什麼是有益的。 -下面是一個名為 `Multiply7` 的簡單智慧型合約,將使用 JSON-RPC 介面把其部署到以太坊節點。 本教學假設讀者已經執行一個 Geth 節點。 更多節點和用戶端的資訊可以在[這裡](/developers/docs/nodes-and-clients/run-a-node)獲得。 請參考個別的[用戶端](/developers/docs/nodes-and-clients/)文件瞭解如何為非 Geth 用戶端開啟 HTTP JSON-RPC。 大多數用戶端預設在 `localhost:8545` 上提供服務。 +以下是一個名為 `Multiply7` 的簡單智能合約,將使用 JSON-RPC 介面部署到以太坊節點。 本教學假設讀者已經執行一個 Geth 節點。 有關節點和用戶端的更多資訊,請參閱[此處](/developers/docs/nodes-and-clients/run-a-node)。 請參閱個別[用戶端](/developers/docs/nodes-and-clients/)文件,以了解如何為非 Geth 用戶端啟動 HTTP JSON-RPC。 大多數用戶端預設在 `localhost:8545` 上提供服務。 ```javascript contract Multiply7 { @@ -1643,18 +1766,18 @@ contract Multiply7 { } ``` -首先,確定啟用了 HTTP 遠端程序呼叫介面。 也就是說,在啟動時我們為 Geth 提供 `--http` 旗標。 在這個例子中,我們使用私有開發鏈的 Geth 節點。 使用這個方法,將不需要真實網路上的以太幣。 +首先,確定啟用了 HTTP 遠端程序呼叫介面。 這表示我們在啟動時為 Geth 提供 `--http` 旗標。 在這個例子中,我們使用私有開發鏈的 Geth 節點。 使用這個方法,將不需要真實網路上的以太幣。 ```bash geth --http --dev console 2>>geth.log ``` -這將在 `http://localhost:8545` 上啟動 HTTP 遠端程序呼叫介面。 +這將在 `http://localhost:8545` 上啟動 HTTP RPC 介面。 -我們可以透過使用 [ curl](https://curl.se) 取得 Coinbase 地址(獲取帳戶陣列中的第一個地址)和餘額,驗證介面是否正在執行。 請注意,這些範例中的資料與你的本地節點有所不同。 如果你想嘗試這些命令,請將第二個 curl 請求中的請求參數替換為第一個請求返回的結果。 +我們可以使用 [curl](https://curl.se) 擷取 coinbase 位址 (透過取得帳戶陣列中的第一個位址) 和餘額,來驗證介面是否正在執行。 請注意,這些範例中的資料與你的本地節點有所不同。 如果你想嘗試這些命令,請將第二個 curl 請求中的請求參數替換為第一個請求返回的結果。 ```bash -curl --data '{"jsonrpc":"2.0","method":"eth_accounts","params":[]", "id":1}' -H "Content-Type: application/json" localhost:8545 +curl --data '{"jsonrpc":"2.0","method":"eth_accounts","params":[], "id":1}' -H "Content-Type: application/json" localhost:8545 {"id":1,"jsonrpc":"2.0","result":["0x9b1d35635cc34752ca54713bb99d38614f63c955"]} curl --data '{"jsonrpc":"2.0","method":"eth_getBalance", "params": ["0x9b1d35635cc34752ca54713bb99d38614f63c955", "latest"], "id":2}' -H "Content-Type: application/json" localhost:8545 @@ -1668,9 +1791,9 @@ web3.fromWei("0x1639e49bba16280000", "ether") // "410" ``` -現在我們的私有開發鏈上有一些以太幣,我們可以部署合約了。 第一步是把 Multiply7 合約編譯成可以傳送到以太坊虛擬機的字元組程式碼。 要安裝 Solidity 編譯器 solc,請參考 [Solidity 文件](https://docs.soliditylang.org/en/latest/installing-solidity.html)。 (為符合[我們的範例中使用的編譯器版本](https://github.com/ethereum/solidity/releases/tag/v0.4.20),你可能想要使用較舊的 `solc` 版本。) +現在我們的私有開發鏈上有一些以太幣,我們可以部署合約了。 第一步是把 Multiply7 合約編譯成可以傳送到以太坊虛擬機的字元組程式碼。 若要安裝 Solidity 編譯器 solc,請遵循 [Solidity 文件](https://docs.soliditylang.org/en/latest/installing-solidity.html)。 (您可能需要使用較舊的 `solc` 版本,以符合[我們範例中使用的編譯器版本](https://github.com/ethereum/solidity/releases/tag/v0.4.20)。) -下一步是把 Multiply7 合約編譯成可以傳送到以太坊虛擬機的字元組程式碼。 +下一步是將 Multiply7 合約編譯成可傳送至 EVM 的位元組碼。 ```bash echo 'pragma solidity ^0.4.16; contract Multiply7 { event Print(uint); function multiply(uint input) public returns (uint) { Print(input * 7); return input * 7; } }' | solc --bin @@ -1680,7 +1803,7 @@ Binary: 6060604052341561000f57600080fd5b60eb8061001d6000396000f300606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa1146044575b600080fd5b3415604e57600080fd5b606260048080359060200190919050506078565b6040518082815260200191505060405180910390f35b60007f24abdb5865df5079dcc5ac590ff6f01d5c16edbc5fab4e195d9febd1114503da600783026040518082815260200191505060405180910390a16007820290509190505600a165627a7a7230582040383f19d9f65246752244189b02f56e8d0980ed44e7a56c0b200458caad20bb0029 ``` -現在我們有了編譯後的程式碼,我們需要確定部署程式碼需要花費多少燃料。 遠端程序呼叫介面有 `eth_estimateGas` 方法可以給我們預估值。 +現在我們有了編譯後的程式碼,我們需要確定部署程式碼需要花費多少燃料。 RPC 介面有一個 `eth_estimateGas` 方法,可以提供我們一個估計值。 ```bash curl --data '{"jsonrpc":"2.0","method": "eth_estimateGas", "params": [{"from": "0x9b1d35635cc34752ca54713bb99d38614f63c955", "data": "0x6060604052341561000f57600080fd5b60eb8061001d6000396000f300606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa1146044575b600080fd5b3415604e57600080fd5b606260048080359060200190919050506078565b6040518082815260200191505060405180910390f35b60007f24abdb5865df5079dcc5ac590ff6f01d5c16edbc5fab4e195d9febd1114503da600783026040518082815260200191505060405180910390a16007820290509190505600a165627a7a7230582040383f19d9f65246752244189b02f56e8d0980ed44e7a56c0b200458caad20bb0029"}], "id": 5}' -H "Content-Type: application/json" localhost:8545 @@ -1694,20 +1817,20 @@ curl --data '{"jsonrpc":"2.0","method": "eth_sendTransaction", "params": [{"from {"id":6,"jsonrpc":"2.0","result":"0xe1f3095770633ab2b18081658bad475439f6a08c902d0915903bafff06e6febf"} ``` -交易被節點接受且傳回交易雜湊值。 雜湊值可以用來追蹤交易。 下一步是確定將合約部署至的地址。 每一個被執行的交易將會產生一份收據。 此收據包含各種關於交易的資訊,例如:交易包含在哪一個區塊中,以及以太坊虛擬機使用多少燃料。 假如交易建立一個合約,交易也將包含合約地址。 我們可以用 `eth_getTransactionReceipt` 遠端程序呼叫方法擷取收據。 +交易被節點接受且傳回交易雜湊值。 雜湊值可以用來追蹤交易。 下一步是確定將合約部署至的地址。 每一個被執行的交易將會產生一份收據。 此收據包含各種關於交易的資訊,例如:交易包含在哪一個區塊中,以及以太坊虛擬機使用多少燃料。 假如交易建立一個合約,交易也將包含合約地址。 我們可以使用 `eth_getTransactionReceipt` RPC 方法擷取收據。 ```bash curl --data '{"jsonrpc":"2.0","method": "eth_getTransactionReceipt", "params": ["0xe1f3095770633ab2b18081658bad475439f6a08c902d0915903bafff06e6febf"], "id": 7}' -H "Content-Type: application/json" localhost:8545 {"jsonrpc":"2.0","id":7,"result":{"blockHash":"0x77b1a4f6872b9066312de3744f60020cbd8102af68b1f6512a05b7619d527a4f","blockNumber":"0x1","contractAddress":"0x4d03d617d700cf81935d7f797f4e2ae719648262","cumulativeGasUsed":"0x1c31e","from":"0x9b1d35635cc34752ca54713bb99d38614f63c955","gasUsed":"0x1c31e","logs":[],"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","status":"0x1","to":null,"transactionHash":"0xe1f3095770633ab2b18081658bad475439f6a08c902d0915903bafff06e6febf","transactionIndex":"0x0"}} ``` -我們的合約是建立在 `0x4d03d617d700cf81935d7f797f4e2ae719648262`。 結果為 null 而不是收據時,表示交易尚未列入區塊中。 稍等一下,並檢查你的共識用戶端是否正常執行,然後重試一次。 +我們的合約建立於 `0x4d03d617d700cf81935d7f797f4e2ae719648262`。 結果為 null 而不是收據時,表示交易尚未列入區塊中。 稍等一下,並檢查你的共識用戶端是否正常執行,然後重試一次。 #### 與智能合約互動 {#interacting-with-smart-contract} -在此範例中,我們將使用 `eth_sendTransaction` 向合約的 `multiply` 方法傳送交易。 +在此範例中,我們將使用 `eth_sendTransaction` 將交易傳送到合約的 `multiply` 方法。 -`eth_sendTransaction` 需要若干引數,特別是 `from`、`to` 和 `data`。 `From` 是我們帳戶的公共地址,`to` 是合約地址。 `data` 引數包含有效負載,定義了必須呼叫哪個方法以及使用哪些引數。 這是 [ABI(應用程式二進位介面)](https://docs.soliditylang.org/en/latest/abi-spec.html)發揮作用的地方。 應用程式二進位介面是定義如何為以太坊虛擬機定義和編碼資料的 JSON 檔案。 +`eth_sendTransaction` 需要幾個引數,特別是 `from`、`to` 和 `data`。 `From` 是我們帳戶的公開位址,`to` 是合約位址。 `data` 引數包含一個有效負載,定義了必須呼叫哪個方法以及使用哪些引數。 這就是 [ABI (應用程式二進位介面)](https://docs.soliditylang.org/en/latest/abi-spec.html) 發揮作用的地方。 應用程式二進位介面是定義如何為以太坊虛擬機定義和編碼資料的 JSON 檔案。 有效負載中的位元組定義要呼叫合約中的哪個方法。 這是函式名稱及其引數類型的 Keccak 雜湊值的前 4 個位元組(十六進位編碼)。 Multiply 函式接受 uint,它是 uint256 的別名。 我們得到以下結果: @@ -1718,11 +1841,11 @@ web3.sha3("multiply(uint256)").substring(0, 10) 下一步是對引數進行編碼。 只有一個 uint256,例如值 6。 應用程式二進制介面有一個部分指定如何對 uint256 類型進行編碼。 -`int: enc(X)` 是 X 的高位元組在前二進位補碼編碼,對於負 X 在高位(左側)填充 0xff,對於正 X 填充零 > 位元組,使得長度為 32 位元組的倍數。 +`int`: `enc(X)` 是 X 的大序二補數編碼,對於負數 X,在高位(左側)填充 0xff;對於正數 X,則填充零位元組,使長度成為 32 位元組的倍數。 -這編碼為 `000000000000000000000000000000000000000000000000000000000000006`。 +這會編碼為 `0000000000000000000000000000000000000000000000000000000000000006`。 -結合函式選擇器和已編碼的引數,我們的資料如下:`0xc6888fa10000000000000000000000000000000000000000000000000000000000000006`。 +結合函式選擇器和編碼引數,我們的資料將是 `0xc6888fa10000000000000000000000000000000000000000000000000000000000000006`。 現在可將其傳送到節點: @@ -1755,7 +1878,7 @@ curl --data '{"jsonrpc":"2.0","method": "eth_sendTransaction", "params": [{"from } ``` -收據包含了日誌。 此日誌由以太坊虛擬機在交易執行時產生並包含在收據中。 `multiply` 函式顯示 `Print` 事件在輸入乘以 7 時觸發。 由於 `Print` 事件的引數是 uint256,我們可以根據應用程式二進位介面規則對其進行解碼,得到預期的十進位數 42。 除了資料之外,值得注意的是,主題可用於確定哪個事件建立了日誌: +收據包含了日誌。 此日誌由以太坊虛擬機在交易執行時產生並包含在收據中。 `multiply` 函式顯示,當輸入乘以 7 時,會引發 `Print` 事件。 由於 `Print` 事件的引數是 uint256,我們可以根據 ABI 規則對其進行解碼,這將得到預期的十進位 42。 除了資料之外,值得注意的是,主題可用於確定哪個事件建立了日誌: ```javascript web3.sha3("Print(uint256)") @@ -1768,7 +1891,6 @@ web3.sha3("Print(uint256)") - [JSON-RPC 規範](http://www.jsonrpc.org/specification) - [節點和用戶端](/developers/docs/nodes-and-clients/) -- [Javascript 應用程式介面](/developers/docs/apis/javascript/) -- [後端應用程式介面](/developers/docs/apis/backend/) +- [JavaScript API](/developers/docs/apis/javascript/) +- [後端 API](/developers/docs/apis/backend/) - [執行用戶端](/developers/docs/nodes-and-clients/#execution-clients) - diff --git a/public/content/translations/zh-tw/developers/docs/blocks/index.md b/public/content/translations/zh-tw/developers/docs/blocks/index.md index af267033ab6..4955385377c 100644 --- a/public/content/translations/zh-tw/developers/docs/blocks/index.md +++ b/public/content/translations/zh-tw/developers/docs/blocks/index.md @@ -1,30 +1,31 @@ --- -title: 區塊 -description: 以太坊區塊鏈之區塊概要 -- 資料結構、必要性及生成方式。 +title: "區塊" +description: "以太坊區塊鏈之區塊概要 -- 資料結構、必要性及生成方式。" lang: zh-tw --- 區塊為區塊鏈上擁有前一個區塊之雜湊值的交易批次。 透過這種方式,區域連結起來形成區塊鏈,因為雜湊值是透過加密方式從區塊資料中衍生得來的。 這樣就防止了假造,因為對歷史記錄中的任何區塊進行一處變更將會使其後的所有區塊無效,後面的所有雜湊值都會改變,並且所有運行區塊鏈的人都會注意到。 -## 基本資訊 {#prerequisites} +## 先決條件 {#prerequisites} -區塊是一個非常簡單易懂的主題。 為了讓你更容易理解本頁,建議你先閱讀[帳戶](/developers/docs/accounts/)、[交易](/developers/docs/transactions/)及我們的[以太坊介紹](/developers/docs/intro-to-ethereum/)。 +區塊是一個非常簡單易懂的主題。 但為協助您更瞭解此頁面,我們建議您先閱讀[帳戶](/developers/docs/accounts/)、[交易](/developers/docs/transactions/),以及我們的[以太坊簡介](/developers/docs/intro-to-ethereum/)。 ## 為何需要區塊? {#why-blocks} 為確保所有以太坊網路參與者擁有同步狀態並一致同意明確的交易歷史記錄,我們將交易分批打包成區塊。 此代表數十個(或數百個)交易將同時被提交、同意及同步。 -![顯示區塊中的交易導致狀態產生變化的圖表](./tx-block.png) _此圖源於[以太坊EVM圖解](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ +![顯示區塊中的交易導致狀態變更的圖表](./tx-block.png) +_圖表改編自 [Ethereum EVM illustrated](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ 透過將交易提交間隔分開,所有網路參與者能有足夠時間來達成共識:即便每秒有大量交易請求提出,但在以太坊上,僅以大約 12 秒的時間建立並提交一次區塊。 -## 區塊如何運作? {#how-blocks-work} +## 區塊的運作方式 {#how-blocks-work} 為了保持交易歷史記錄,區塊嚴格按照順序排列(新建立區塊包含父區塊之參照),而區塊內的交易也是嚴格按照順序排列。 除極個別情形外,在任何給定時間點,所有網路參與者都一致同意區塊的準確數量及歷史記錄,並致力於將當前的即時交易請求批次打包到下一個區塊中。 當隨機挑選的驗證者在網路上生成一個區塊後,區塊將被廣播至全網路;所有節點將此新區塊添加於它們的區塊鏈尾端,接著,挑選一個新的驗證者來產生下一個區塊。 目前區塊生成、提交/共識流程是由以太坊之「權益證明」協議規定的。 -## 權益證明協議 {#proof-of-work-protocol} +## 權益證明協議 {#proof-of-stake-protocol} 權益證明指的是: @@ -33,60 +34,60 @@ lang: zh-tw - 其他驗證者接到此新區塊後,重新執行這些交易,以確保他們同意新提交的全域狀態變更。 如果該區塊是有效的,他們將其加入自己的資料庫。 - 如果驗證者在同一時隙接到兩個衝突的區塊,他們會透過分叉選擇演算法選擇有最多質押以太幣支援的區塊。 -[更多詳情關於質押證明(PoS)](/developers/docs/consensus-mechanisms/pos) +[更多關於權益證明的資訊](/developers/docs/consensus-mechanisms/pos) ## 區塊中有什麼? {#block-anatomy} 區塊內有很多資訊。 在最高層級,區塊包含以下欄位: | 欄位 | 描述 | -|:---------------- |:-------------- | -| `時隙` | 區塊所屬的時隙 | +| :--------------- | :------------- | +| `slot` | 區塊所屬的時隙 | | `proposer_index` | 提出區塊的驗證者的識別碼 | | `parent_root` | 前一個區塊的雜湊值 | | `state_root` | 狀態物件的根雜湊值 | -| `主旨` | 包含多個欄位的物件,定義如下 | +| `body` | 包含多個欄位的物件,定義如下 | -區塊的 `body` 包含以下幾個欄位: +區塊 `body` 本身包含數個欄位: | 欄位 | 描述 | -|:-------------------- |:-------------- | +| :------------------- | :------------- | | `randao_reveal` | 用於選擇下一個區塊提出者的值 | | `eth1_data` | 關於存款合約的資訊 | -| `塗鴉` | 用於標記區塊的任意資料 | +| `graffiti` | 用於標記區塊的任意資料 | | `proposer_slashings` | 將被罰沒的驗證者清單 | | `attester_slashings` | 將被罰沒的證明者清單 | -| `證明` | 支持當前區塊的證明清單 | -| `存款` | 存款合約的新增存款清單 | +| `attestations` | 針對先前時隙所做證明的清單 | +| `deposits` | 存款合約的新增存款清單 | | `voluntary_exits` | 離開網路的驗證者清單 | | `sync_aggregate` | 服務輕量用端的驗證者子集 | | `execution_payload` | 執行用户端傳送來的交易 | `attestations` 欄位包含區塊中所有證明的清單。 每個證明都有自己的資料類型並包含一些資料。 每個證明包含: -| 欄位 | 描述 | -|:------------------ |:------------ | -| `aggregation_bits` | 參與過此證明的驗證者清單 | -| `數據資料` | 包含多個子欄位的容器 | -| `signature` | 所有證明驗證者的聚合簽名 | +| 欄位 | 描述 | +| :----------------- | :--------------------- | +| `aggregation_bits` | 參與過此證明的驗證者清單 | +| `data` | 包含多個子欄位的容器 | +| `signature` | 一組驗證者針對 `data` 部分的匯總簽章 | -`attestation` 中的 `data` 欄位包含: +`attestation` 中的 `data` 欄位包含以下內容: -| 欄位 | 描述 | -|:------------------- |:--------------- | -| `時隙` | 與證明相關的時隙 | -| `索引` | 證明驗證者的索引 | -| `beacon_block_root` | 包含此物件的信標區塊的根雜湊值 | -| `來源` | 最後一個合法檢查點 | -| `target` | 最新時期的邊界區塊 | +| 欄位 | 描述 | +| :------------------ | :------------ | +| `slot` | 與證明相關的時隙 | +| `index` | 證明驗證者的索引 | +| `beacon_block_root` | 被視為鏈頭的信標區塊根哈希 | +| `source` | 最後一個合法檢查點 | +| `target` | 最新時期的邊界區塊 | -執行 `execution_payload` 中的交易會更新全域狀態。 所有用戶端都重新執行 `execution_payload` 中的交易,以確保新的狀態與新區塊中 `state_root` 欄位中的狀態相符。 這就是用戶端辨別新區塊是否有效並可以安全添加至其區塊鏈中的方式。 `execution payload` 自身是一個有許多欄位的物件。 還有一個 `execution_payload_header` 欄位,其中包含了關於執行資料的重要摘要資訊。 這些資料結構組織方式如下: +執行 `execution_payload` 中的交易會更新全域狀態。 所有用戶端都會重新執行 `execution_payload` 中的交易,以確保新的狀態與新區塊 `state_root` 欄位中的狀態相符。 這就是用戶端辨別新區塊是否有效並可以安全添加至其區塊鏈中的方式。 `execution payload` 本身是具有數個欄位的物件。 此外,還有一個 `execution_payload_header`,其中包含關於執行資料的重要摘要資訊。 這些資料結構組織方式如下: -`xecution_payload_header` 包含以下欄位: +`execution_payload_header` 包含以下欄位: | 欄位 | 描述 | -|:------------------- |:-------------------- | -| `家長_雜湊值` | 父區塊的雜湊值 | +| :------------------ | :------------------- | +| `parent_hash` | 父區塊的雜湊值 | | `fee_recipient` | 用於支付交易費的帳戶地址 | | `state_root` | 在應用此區塊中的變更後全域狀態的根雜湊值 | | `receipts_root` | 交易收據樹的雜湊值 | @@ -95,18 +96,18 @@ lang: zh-tw | `block_number` | 目前區塊號碼 | | `gas_limit` | 此區塊允許的最高燃料用量 | | `gas_used` | 此區塊實際消耗的燃料用量 | -| `時間戳` | 區塊時間 | +| `timestamp` | 區塊時間 | | `extra_data` | 原始字節位元組格式的任意額外資料 | | `base_fee_per_gas` | 基本費用的值 | | `block_hash` | 執行區塊的雜湊值 | | `transactions_root` | 有效負載中交易的根雜湊值 | | `withdrawal_root` | 有效負載中提款的根雜湊值 | -`execution_payload` 自身包含了以下欄位(請注意,這些欄位與標頭相同,只是它不包含交易的根雜湊值,而是包含實際的交易清單和提款資訊): +`execution_payload` 本身包含以下內容 (請注意,這與標頭相同,只不過它包含的是實際的交易清單和提款資訊,而非交易的根哈希): | 欄位 | 描述 | -|:------------------ |:-------------------- | -| `家長_雜湊值` | 父區塊的雜湊值 | +| :----------------- | :------------------- | +| `parent_hash` | 父區塊的雜湊值 | | `fee_recipient` | 用於支付交易費的帳戶地址 | | `state_root` | 在應用此區塊中的變更後全域狀態的根雜湊值 | | `receipts_root` | 交易收據樹的雜湊值 | @@ -115,38 +116,38 @@ lang: zh-tw | `block_number` | 目前區塊號碼 | | `gas_limit` | 此區塊允許的最高燃料用量 | | `gas_used` | 此區塊實際消耗的燃料用量 | -| `時間戳` | 區塊時間 | +| `timestamp` | 區塊時間 | | `extra_data` | 原始字節位元組格式的任意額外資料 | | `base_fee_per_gas` | 基本費用的值 | | `block_hash` | 執行區塊的雜湊值 | -| `交易(transactions)` | 要執行交易的清單 | -| `提款` | 提款物件清單 | +| `transactions` | 要執行交易的清單 | +| `withdrawals` | 提款物件清單 | -`withdrawals` 清單包含 `withdrawals` 物件,具下列結構: +`withdrawals` 清單包含依下列方式建構的 `withdrawal` 物件: | 欄位 | 描述 | -|:---------------- |:-------- | +| :--------------- | :------- | | `address` | 已提款的帳戶地址 | | `amount` | 提款金額 | -| `索引` | 提款索引值 | +| `index` | 提款索引值 | | `validatorIndex` | 驗證者索引值 | ## 區塊時間 {#block-time} 區塊時間指的是分隔區塊的時間。 在以太坊上,時間被分割成 12 秒的單位,稱為「時隙」。 在每個時隙中,都會選擇一個驗證者來提交區塊。 假設所有驗證者都在線且功能完整,那每個時隙中都會有一個區塊,表示區塊時間為 12 秒。 然而,偶爾,當被要求提交區塊時驗證者可能下線,這表示時隙有時候會是空白的。 -這種實作與基於工作量證明的系統不同,在工作量證明系統中,區塊時間是機率性的,並根據協議的目標挖礦難度調整。 以太坊的[平均區塊時間](https://etherscan.io/chart/blocktime)就是個完美的範例,可以透過一致性的 12 秒區塊時間清楚地推斷出,已經由工作量證明過渡到權益證明了。 +這種實作與基於工作量證明的系統不同,在工作量證明系統中,區塊時間是機率性的,並根據協議的目標挖礦難度調整。 以太坊的[平均區塊時間](https://etherscan.io/chart/blocktime)就是一個很好的例子,根據新的 12 秒區塊時間的一致性,可以清楚地推斷出從工作量證明到權益證明的轉換。 ## 區塊大小 {#block-size} -最後一個重要事項:區塊本身具大小限制。 每個區塊具 35M 單位燃料用量之目標大小,但區塊大小將跟隨網路需求增減,最大可達到 60M 燃料用量的區塊大小限制(目標區塊大小之兩倍)。 區塊的燃料限制可以比前一個區塊的燃料限制上調或下調 1/1024。 因此,驗證者可以透過共識來改變區塊的燃料限制。 區塊中所有交易消耗的總燃料用量須少於區塊燃料限制。 這一點非常重要,因其確保區塊不能成為任意大小。 若區塊可以任意大,由於空間及速度方面的要求,那些效能一般的全節點可能逐漸跟不上網路。 區塊愈大,在下一個時隙中及時處理它們所需的算力就愈多。 這是一種中心化力量,可以透過限制區塊大小來抵制。 +最後一個重要事項:區塊本身具大小限制。 每個區塊的目標大小為 3,000 萬 gas,但區塊大小會根據網路需求增減,直到 6,000 萬 gas 的區塊上限 (目標區塊大小的 2 倍)。 區塊的燃料限制可以比前一個區塊的燃料限制上調或下調 1/1024。 因此,驗證者可以透過共識來改變區塊的燃料限制。 區塊中所有交易消耗的總燃料用量須少於區塊燃料限制。 這一點非常重要,因其確保區塊不能成為任意大小。 若區塊可以任意大,由於空間及速度方面的要求,那些效能一般的全節點可能逐漸跟不上網路。 區塊愈大,在下一個時隙中及時處理它們所需的算力就愈多。 這是一種中心化力量,可以透過限制區塊大小來抵制。 -## 衍生閱讀 {#further-reading} +## 延伸閱讀 {#further-reading} -_知道對你有幫助的社群資源嗎? 請編輯此頁面並新增資源!_ +_知道一個曾經幫助你學習更多社區或社團資源? 歡迎在本頁自由編輯或添加內容!_ ## 相關主題 {#related-topics} - [交易](/developers/docs/transactions/) -- [燃料](/developers/docs/gas/) -- [權益證明(PoS)](/developers/docs/consensus-mechanisms/pos) +- [Gas](/developers/docs/gas/) +- [權益證明](/developers/docs/consensus-mechanisms/pos) diff --git a/public/content/translations/zh-tw/developers/docs/bridges/index.md b/public/content/translations/zh-tw/developers/docs/bridges/index.md new file mode 100644 index 00000000000..ac619425b26 --- /dev/null +++ b/public/content/translations/zh-tw/developers/docs/bridges/index.md @@ -0,0 +1,138 @@ +--- +title: "跨鏈橋" +description: "給開發者的跨鏈橋概觀" +lang: zh-tw +--- + +隨著 Layer 1 區塊鏈與 Layer 2 [擴容](/developers/docs/scaling/) 解決方案的激增,加上愈來愈多去中心化應用程式走向跨鏈,跨鏈通訊與資產移動的需求,已成為網路基礎設施中不可或缺的一環。 存在不同類型的跨鏈橋就是為了幫助解決這種需求。 + +## 跨鏈橋的需求 {#need-for-bridges} + +跨鏈橋是一條負責在不同區塊鏈之間傳遞「訊息」的橋。 它連結不同的區塊鏈,幫助不同區塊鏈上的數位資產與資料進行互動。 + +每一個區塊鏈的運行都是各自獨立的,有其自身的規則、共識機制、原生代幣以及部署其上的智慧型合約。這意味著在自身的設計上每一個區塊鏈無法將內部的數位資產或儲存資料跨鏈轉移到另一個區塊鏈上。 儘管一個區塊鏈可以不斷發展並豐富自身內部的生態系,它始終缺乏連結不同區塊鏈、跨鏈共同運作的能力。 + +跨鏈橋有助於打破這些藩籬,整合各自孤立的區塊鏈生態系為一體。 它們在區塊鏈之間建立傳輸路徑,代幣、訊息、任意資料,甚至[智能合約](/developers/docs/smart-contracts/)呼叫都可以從一條鏈轉移到另一條鏈。 + +## 跨鏈橋的優點 {#benefits-of-bridges} + +區塊鏈橋最重要的好處是允許不同的區塊鏈進行資料交換與跨鏈資產的轉移。 + +想像每一個區塊鏈都是一塊被海洋分隔開的大陸,不同的大陸有各自不同的資源,如果能將這些大陸的優勢結合起來,就可以創造一個繁榮的生態圈。同樣地,每一個區塊鏈都有各自的優勢與限制、在體系與應用程式的建構上都有其獨特的取捨(如重視速度、吞吐量、或安全成本等)。 跨鏈橋也同樣能將不同區塊鏈的優勢整合起來,幫助彼此有效運用各自的優勢,打造一個繁榮的生態圈。 + +對於開發者,鏈橋可以實現以下功能: + +- 跨鏈傳輸任何資料、資訊和資產。 +- 解鎖協議的新功能和應用場景,因為鏈橋擴展了協議可以提供的設計空間。 例如,最初部署在以太坊主網路上用於提供流動性礦池的協議,可以為所有相容於以太坊虛擬機的鏈提供流動資金池。 +- 可以利用不同區塊鏈的優勢的機會。 例如,開發者可以透過將去中心化應用程式部署在多個磁碟區上來享受不同二層網路解決方案帶來的較低費用,而側鍊和使用者可以在它們之間建立鏈橋。 +- 不同區塊鏈生態系統的開發者之間相互協作,建構新產品。 +- 吸引來自不同生態系統的使用者和社群使用他們的去中心化應用程式。 + +## 跨鏈橋如何運作? {#how-do-bridges-work} + +雖然[跨鏈橋的設計類型](https://li.fi/knowledge-hub/blockchain-bridges-and-classification/)有很多種,但其中有三種促進跨鏈資產轉移的方式特別突出: + +- **鎖定與鑄造 –** 在來源鏈鎖定資產,並在目標鏈鑄造資產。 +- **銷毀與鑄造 –** 在來源鏈銷毀資產,並在目標鏈鑄造資產。 +- **原子交換 –** 與另一方將來源鏈上的資產交換為目標鏈上的資產。 + +## 跨鏈橋類型 {#bridge-types} + +鏈橋通常可以分為以下幾類之一: + +- **原生跨鏈橋 –** 這類跨鏈橋通常是為了引導特定區塊鏈上的流動性而建立,讓使用者可以更輕易地將資金轉移至生態系統。 例如,[Arbitrum 跨鏈橋](https://bridge.arbitrum.io/)的建立,是為了讓使用者可以便利地從以太坊主網跨鏈至 Arbitrum。 其他類似的跨鏈橋包括 Polygon PoS 跨鏈橋、[Optimism Gateway](https://app.optimism.io/bridge) 等等。 +- **基於驗證者或預言機的跨鏈橋 –** 這類跨鏈橋依賴外部驗證者集合或預言機,來驗證跨鏈轉移。 例如:Multichain 與 Across。 +- **通用訊息傳遞跨鏈橋 –** 這類跨鏈橋可以跨鏈轉移資產、訊息與任意資料。 舉例:Axelar, LayerZero 和 Nomad. +- **流動性網路 –** 這類跨鏈橋主要專注於透過原子交換,將資產從一條鏈轉移到另一條鏈。 一般來講,它們不支援跨鏈訊息傳遞。 例如:Connext 與 Hop。 + +## 需考量的權衡取捨 {#trade-offs} + +沒有完美的鏈橋解決方案。 有的只是為了實現目的而進行的權衡利弊。 開發者和使用者可以根據以下因素評估鏈橋: + +- **安全性 –** 由誰來驗證系統? 通常,由外部驗證者保護的鏈橋不如由區塊鏈驗證者在本地保護的鏈橋安全。 +- **便利性 –** 完成一筆交易需要多長時間?使用者需要簽署多少筆交易? 對於開發者來說,整合一個鏈橋需要多長時間,這個過程有多複雜? +- **連接性 –** 跨鏈橋可以連接哪些不同的目標鏈(例如 rollup、側鏈、其他 Layer 1 區塊鏈等)?整合一條新的區塊鏈有多困難? +- **傳遞更複雜資料的能力 –** 跨鏈橋能否跨鏈傳輸訊息和更複雜的任意資料,或者它只支援跨鏈資產轉移? +- **成本效益 –** 透過跨鏈橋跨鏈轉移資產的成本是多少? 通常情況下,鏈橋收取固定或變動的費用,具體取決於燃料成本和特定路線的流動性。 根據確保鏈橋安全所需的資本來評估鏈橋的成本效益也是至關重要的。 + +在較高層面上,鏈橋可分為需要信任鏈橋和去信任鏈橋。 + +- **需信任 –** 需信任的跨鏈橋由外部驗證。 它們使用一組外部驗證者(具有多重簽章的聯盟、多方運算系統、預言機網路)跨鏈發送資料。 因此,它們可以提供出色的連通性,並完全支援跨鏈通用資訊傳遞。 在速度和成本效益方面它們通常也表現良好。 但這些是以安全性為代價的,因為使用者必須依賴鏈橋的安全性。 +- **免信任 –** 這類跨鏈橋依賴其所連接的區塊鏈及驗證者來轉移訊息和代幣。 它們是 “去信任” 的,因為它們沒有增加新的信任假設(區塊鏈除外)。 因此,我們認為去信任鏈橋比可信任鏈橋更安全。 + +為了根據其他因素評估去信任鏈橋,我們須將其分為通用資訊傳遞鏈橋和流動性網路。 + +- **通用訊息傳遞跨鏈橋 –** 這類跨鏈橋在安全性以及跨鏈傳輸更複雜資料的能力方面表現卓越。 通常,它們還具有良好的成本效益。 然而,這些優點通常以輕用戶端鏈橋(例如 IBC)的連通性以及使用欺詐證明的樂觀鏈橋(例如 Nomad)的速度劣勢作為代價。 +- **流動性網路 –** 這類跨鏈橋使用原子交換來轉移資產,並且是本地驗證系統(亦即,它們使用底層區塊鏈的驗證者來驗證交易)。 因此,它們在安全性和速度方面表現出色。 此外,流動性網路具有良好的成本效益和良好的連結性。 然而,最大的折衷之處是它們無法傳遞更複雜的資料 — 因為它們不支援跨鏈訊息傳遞。 + +## 跨鏈橋的風險 {#risk-with-bridges} + +跨鏈橋佔了 [DeFi 三大駭客攻擊](https://rekt.news/leaderboard/)中的前三名,而且仍處於早期發展階段。 使用任何鏈橋都有以下風險: + +- **智能合約風險 –** 雖然許多跨鏈橋已成功通過審核,但智能合約中的一個瑕疵就足以讓資產暴露在駭客攻擊之下(例如:[Solana 的 Wormhole 跨鏈橋](https://rekt.news/wormhole-rekt/))。 +- **系統性金融風險** – 許多跨鏈橋使用封裝資產,在新鏈上鑄造原始資產的標準版本。 這使生態系統面臨系統性風險,正如我們所看到的那樣,包裝代幣遭到利用。 +- **交易對手風險 –** 有些跨鏈橋採用需信任的設計,這要求使用者必須依賴「驗證者不會串通竊取使用者資金」的假設。 使用者需要信任這些第三方參與者,這使他們面臨一些風險,例如跑路、審查和其他惡意活動。 +- **待解決問題 –** 鑑於跨鏈橋仍處於早期發展階段,還有許多未解的問題,關於跨鏈橋在不同市場條件下的表現,例如在網路壅塞時,或在發生網路層級攻擊或狀態回滾等無法預料的事件時。 這種不確定性帶來了一定的風險,且風險程度目前仍未知。 + +## 去中心化應用程式如何使用鏈橋? {#how-can-dapps-use-bridges} + +以下介紹一些實際應用,在這些應用中,開發者可以考慮鏈橋並讓他們的去中心化應用程式跨鏈: + +### 整合跨鏈橋 {#integrating-bridges} + +對於開發者來說,有很多方法可以添加對鏈橋的支援: + +1. **建立自己的跨鏈橋 –** 建立一個安全可靠的跨鏈橋並不容易,尤其當你選擇信任最小化的路徑時。 此外,還需要與可擴展性和互通性研究相關的多年經驗和技術專長。 另外,還需要一支親力親為的團隊來維護鏈橋,並吸引足夠的流動性使其可行。 + +2. **向使用者展示多種跨鏈橋選項 –** 許多[去中心化應用程式](/developers/docs/dapps/)都要求使用者擁有其原生代幣才能與之互動。 為了使用戶能夠訪問他們的代幣,去中心化應用程式在其網站上提供了不同的鏈橋選項。 然而,這種方法是權宜之計,因為它使用戶離開去中心化應用程式介面但仍需要用戶與其他去中心化應用程式和鏈橋互動。 這是一種繁瑣的上手體驗,會增加出錯的範圍。 + +3. **整合一座跨鏈橋 –** 這個解決方案不需要去中心化應用程式將使用者送到外部跨鏈橋和 DEX 介面。 這讓去中心化應用程式能夠改善用戶的上手體驗。 然而,這種方法有其局限性: + + - 鏈橋的評估和維護既困難又耗時。 + - 選用一個鏈橋將造成單點故障和依賴性。 + - 去中心化應用程式受限於鏈橋的能力。 + - 光有鏈橋可能還不夠。 去中心化應用程式可能需要去中心化交易所提供更多功能,例如跨鏈交換。 + +4. **整合多座跨鏈橋 –** 這個解決方案解決了許多與整合單一跨鏈橋相關的問題。 然而,它也有局限性,因為整合多個鏈橋會消耗資源,並為開發者帶來技術和通訊開銷 — 這是加密貨幣領域最稀缺的資源。 + +5. **整合跨鏈橋聚合器 –** 去中心化應用程式的另一個選項是整合跨鏈橋聚合解決方案,讓它們可以存取多座跨鏈橋。 鏈橋聚合器繼承了所有鏈橋的優點,因此不受任何單一鏈橋能力的限制。 值得注意的是,鏈橋聚合器通常維護鏈橋集成,這使去中心化應用程式避免了管控鏈橋集成技術和操作方面的麻煩。 + +儘管如此,鏈橋聚合器也有其限制。 比如說,雖然它們可以提供較多的鏈橋選擇,但除了聚合器平台上提供的鏈橋外,市場上通常還有更多的鏈橋。 此外,像鏈橋一樣,鏈橋聚合器也面臨智慧合約和技術風險(更多的智慧合約 = 更多的風險)。 + +如果去中心化應用程式規劃整合鏈橋或聚合器,那麼根據整合的深度會有不同的選擇。 例如,如果只是進行前端整合以改善用戶上手體驗,去中心化應用程式將整合小組件。 然而,如果整合是為了探索更深層的跨鏈策略,如質押、流動性礦池等,去中心化應用程式就整合軟體開發工具包或應用程式介面。 + +### 在多個鏈上部署去中心化應用程式 {#deploying-a-dapp-on-multiple-chains} + +若要在多條鏈上部署去中心化應用程式,開發者可以使用 [Alchemy](https://www.alchemy.com/)、[Hardhat](https://hardhat.org/)、[Moralis](https://moralis.io/) 等開發平台。 這些平台通常提供可組合的插件,能夠支援去中心化應用程式跨鏈。 例如,開發者可以使用 [hardhat-deploy 外掛程式](https://github.com/wighawag/hardhat-deploy)提供的確定性部署代理。 + +#### 範例: + +- [如何建立跨鏈去中心化應用程式](https://moralis.io/how-to-build-cross-chain-dapps/) +- [建立跨鏈 NFT 市場](https://youtu.be/WZWCzsB1xUE) +- [Moralis:建立跨鏈 NFT 去中心化應用程式](https://www.youtube.com/watch?v=ehv70kE1QYo) + +### 監控跨鏈合約活動 {#monitoring-contract-activity-across-chains} + +要監控跨鏈合約活動,開發者可以使用子圖和 Tenderly 等開發者平台即時觀察智能合約。 這類平台也提供工具,為跨鏈活動提供更強大的資料監控功能,例如檢查[合約發出的事件](https://docs.soliditylang.org/en/v0.8.14/contracts.html?highlight=events#events)等。 + +#### 工具 + +- [The Graph](https://thegraph.com/en/) +- [Tenderly](https://tenderly.co/) + +## 延伸閱讀 {#further-reading} + +- [區塊鏈跨鏈橋](/bridges/) – ethereum.org +- [L2Beat 跨鏈橋風險框架](https://l2beat.com/bridges/summary) +- [區塊鏈跨鏈橋:建構加密網路的網路](https://medium.com/1kxnetwork/blockchain-bridges-5db6afac44f8) - 2021 年 9 月 8 日 – Dmitriy Berenzon +- [互操作性三難困境](https://blog.connext.network/the-interoperability-trilemma-657c2cf69f17) - 2021 年 10 月 1 日 – Arjun Bhuptani +- [叢集:需信任與信任最小化跨鏈橋如何塑造多鏈格局](https://blog.celestia.org/clusters/) - 2021 年 10 月 4 日 – Mustafa Al-Bassam +- [LI.FI:有了跨鏈橋,信任就成了光譜](https://blog.li.fi/li-fi-with-bridges-trust-is-a-spectrum-354cd5a1a6d8) - 2022 年 4 月 28 日 – Arjun Chand +- [Rollup 互操作性解決方案的現狀](https://web.archive.org/web/20250428015516/https://research.2077.xyz/the-state-of-rollup-interoperability) - 2024 年 6 月 20 日 – Alex Hook +- [利用共享安全實現安全的跨鏈互操作性:Lagrange 狀態委員會及其他](https://web.archive.org/web/20250125035123/https://research.2077.xyz/harnessing-shared-security-for-secure-blockchain-interoperability) - 2024 年 6 月 12 日 – Emmanuel Awosika + +此外,以下是 [James Prestwich](https://twitter.com/_prestwich) 的一些精闢演講,有助於加深對跨鏈橋的理解: + +- [建立跨鏈橋,而非圍牆花園](https://youtu.be/ZQJWMiX4hT0) +- [剖析跨鏈橋](https://youtu.be/b0mC-ZqN8Oo) +- [跨鏈橋為何在燃燒](https://youtu.be/c7cm2kd20j8) diff --git a/public/content/translations/zh-tw/developers/docs/consensus-mechanisms/index.md b/public/content/translations/zh-tw/developers/docs/consensus-mechanisms/index.md index 832a6b165cf..98195358fba 100644 --- a/public/content/translations/zh-tw/developers/docs/consensus-mechanisms/index.md +++ b/public/content/translations/zh-tw/developers/docs/consensus-mechanisms/index.md @@ -1,14 +1,14 @@ --- -title: 共識機制 -description: 解釋分佈式系統中的共識協定及其於以太坊中扮演的角色。 +title: "共識機制" +description: "解釋分佈式系統中的共識協定及其於以太坊中扮演的角色。" lang: zh-tw --- -「共識機制」一詞常泛指「權益證明」、「工作量證明」或「權威證明」協定。 然而,這些證明方式僅為共識機制當中用來抵禦[女巫攻擊](/glossary/#sybil-attack)的組成部分。 共識機制是由一整套想法、協定和激勵構成的體系,使得一系列分佈式節點能夠就區塊鏈狀態達成一致。 +「共識機制」一詞常泛指「權益證明」、「工作量證明」或「權威證明」協定。 然而,這些只是共識機制中,用來抵禦[女巫攻擊](/glossary/#sybil-attack)的元件。 共識機制是由一整套想法、協定和激勵構成的體系,使得一系列分佈式節點能夠就區塊鏈狀態達成一致。 -## 基本資訊 {#prerequisites} +## 先決條件 {#prerequisites} -為了加深對本頁內容的理解,我們推薦你先仔細閱讀我們的[以太坊介紹](/developers/docs/intro-to-ethereum/)。 +為能更了解本頁面,我們建議您先閱讀我們的[以太坊簡介](/developers/docs/intro-to-ethereum/)。 ## 何為共識? {#what-is-consensus} @@ -28,11 +28,11 @@ lang: zh-tw 這些部分共同組成了共識機制。 -## 共識機制種類 {#types-of-consensus-mechanisms} +## 共識機制的類型 {#types-of-consensus-mechanisms} ### 基於工作量證明 {#proof-of-work} -和比特幣類似,以太坊也曾經使用基於**工作量證明 (PoW)** 的共識協定。 +和比特幣一樣,以太坊曾經也使用基於**工作量證明 (PoW)** 的共識協定。 #### 區塊建立 {#pow-block-creation} @@ -46,9 +46,9 @@ lang: zh-tw ### 基於權益證明 {#proof-of-stake} -以太坊目前使用基於**權益證明 (PoS)** 的共識協定。 +以太坊現在使用基於**權益證明 (PoS)** 的共識協定。 -#### 區塊生成 {#pos-block-creation} +#### 區塊建立 {#pos-block-creation} 驗證者建立區塊。 每個時隙都會隨機選擇一個驗證者成為區塊提議者。 區塊提議者的共識用戶端請求配對的執行用戶端對交易打包,作為「執行有效負載」。 然後它們將其包裝成共識資料以形成區塊,再把這個區塊傳送給以太坊網路上的其他節點。 這樣的區塊產生會得到以太幣獎勵。 在極少數情況下,當一個時隙中存在多個可能的區塊,或節點在不同時間收到區塊,分叉選擇演算法就會選擇使形成的鏈具有最大證明權重的區塊(證明權重是指提供證明的驗證者數量,並按驗證者質押的以太幣餘額進行調整)。 @@ -58,35 +58,35 @@ lang: zh-tw 更多關於[權益證明](/developers/docs/consensus-mechanisms/pos/)的資訊 -### 視覺導覽 {#types-of-consensus-video} +### 視覺化指南 {#types-of-consensus-video} 觀看以太坊上所用不同類型之共識機制的更多資訊: -### 抵禦女巫攻擊與區塊鏈選擇 {#sybil-chain} +### 抗女巫攻擊與鏈選擇 {#sybil-chain} 僅僅工作量證明和權益證明還不能構成共識協定,但為了簡便起見,通常將它們稱為共識協定。 它們實際是抵禦女巫攻擊機制及區塊鏈創作者選擇程式;提供了一種方法來決定誰能成為最新區塊創作者。 另一個重要組成部分是鏈選擇(又稱分叉選擇)演算法,在同一位置有多個區塊的情況下,它讓節點可以在鏈頭部選擇一個正確的區塊。 -**抵禦女巫攻擊**衡量協定有效對抗女巫攻擊的能力。 抵禦此類攻擊對於去中心化區塊鏈至關緊要,可使所有礦工與驗證者能夠基於其投入的資源平等地獲得獎勵。 工作量證明及權益證明透過讓使用者耗費大量能源或投入大量抵押,來防範此類攻擊。 此類保護會對女巫攻擊形成經濟上的威懾。 +抗女巫攻擊能力衡量的是一個協定對抗女巫攻擊的表現。 抵禦此類攻擊對於去中心化區塊鏈至關緊要,可使所有礦工與驗證者能夠基於其投入的資源平等地獲得獎勵。 工作量證明及權益證明透過讓使用者耗費大量能源或投入大量抵押,來防範此類攻擊。 此類保護會對女巫攻擊形成經濟上的威懾。 -**區塊鏈選擇規則**被用來決定哪條鏈為「正確」的鏈。 比特幣使用「最長鏈」規則。這意味著,任何最長的區塊鏈,都會被其他節點接受並與之合作。 對於工作量證明區塊鏈,最長鏈取決於該鏈所累積之工作量證明總難度。 以太坊也曾經用過最長鏈規則;但現在以太坊在權益證明機制下運作,採用了經過更新的分叉選擇演算法來衡量鏈的「權重」。 權重是累積的驗證者投票數累積總和,並以驗證者質押的以太幣餘額進行加權。 +鏈選擇規則是用來決定哪一條鏈是「正確」的鏈。 比特幣使用「最長鏈」規則。這意味著,任何最長的區塊鏈,都會被其他節點接受並與之合作。 對於工作量證明區塊鏈,最長鏈取決於該鏈所累積之工作量證明總難度。 以太坊也曾經用過最長鏈規則;但現在以太坊在權益證明機制下運作,採用了經過更新的分叉選擇演算法來衡量鏈的「權重」。 權重是累積的驗證者投票數累積總和,並以驗證者質押的以太幣餘額進行加權。 -以太坊使用一種被稱為 [Gasper](/developers/docs/consensus-mechanisms/pos/gasper/) 的共識機制,它結合了 [Casper 友善最終確定性組件權益證明](https://arxiv.org/abs/1710.09437)和[最貪婪最重觀測子樹 (GHOST) 分叉選擇規則](https://arxiv.org/abs/2003.03052)。 +以太坊使用一種名為 [Gasper](/developers/docs/consensus-mechanisms/pos/gasper/) 的共識機制,它將 [Casper FFG 權益證明](https://arxiv.org/abs/1710.09437)與 [GHOST 分叉選擇規則](https://arxiv.org/abs/2003.03052)結合起來。 -## 衍生閱讀 {#further-reading} +## 延伸閱讀 {#further-reading} -- [何為區塊鏈共識演算法?](https://academy.binance.com/en/articles/what-is-a-blockchain-consensus-algorithm) -- [何為 Nakamoto 共識? 完整初學者指南](https://blockonomi.com/nakamoto-consensus/) -- [Casper 機制如何運作?](https://medium.com/unitychain/intro-to-casper-ffg-9ed944d98b2d) -- [關於權益證明區塊鏈的安全性及效能](https://eprint.iacr.org/2016/555.pdf) -- [拜占庭問題](https://en.wikipedia.org/wiki/Byzantine_fault) +- [什麼是區塊鏈共識演算法?](https://academy.binance.com/en/articles/what-is-a-blockchain-consensus-algorithm) +- [什麼是中本聰共識? 完整新手指南](https://blockonomi.com/nakamoto-consensus/) +- [Casper 如何運作?](https://medium.com/unitychain/intro-to-casper-ffg-9ed944d98b2d) +- [關於工作量證明區塊鏈的安全性與效能](https://eprint.iacr.org/2016/555.pdf) +- [拜占庭故障](https://en.wikipedia.org/wiki/Byzantine_fault) -_知道一個曾經幫助你學習更多社區或社團資源? 歡迎在本頁自由編輯或添加內容!!_ +_知道一個曾經幫助你學習更多社區或社團資源? 歡迎在本頁自由編輯或添加內容!_ ## 相關主題 {#related-topics} - [工作量證明](/developers/docs/consensus-mechanisms/pow/) - [挖礦](/developers/docs/consensus-mechanisms/pow/mining/) -- [持有量證明(又稱:權益證明)](/developers/docs/consensus-mechanisms/pos/) +- [權益證明](/developers/docs/consensus-mechanisms/pos/) - [權威證明](/developers/docs/consensus-mechanisms/poa/) diff --git a/public/content/translations/zh-tw/developers/docs/standards/tokens/erc-721/index.md b/public/content/translations/zh-tw/developers/docs/standards/tokens/erc-721/index.md new file mode 100644 index 00000000000..e50d8f199fb --- /dev/null +++ b/public/content/translations/zh-tw/developers/docs/standards/tokens/erc-721/index.md @@ -0,0 +1,255 @@ +--- +title: "ERC-721 非同質化代幣標準" +description: "了解 ERC-721,這是以太坊上代表獨特數位資產的非同質化代幣 (NFT) 標準。" +lang: zh-tw +--- + +## 介紹 {#introduction} + +**什麼是非同質化代幣?** + +非同質化代幣 (NFT) 用於以獨一無二的方式來識別某物或某人。 這類型的代幣非常適合在提供收藏品、密鑰、彩票、音樂會和體育比賽的編號座位等平台上使用。 這種特殊類型的代幣具有驚人潛力,因此它應得一個適當標準,而 ERC-721 正是來解決這個問題! + +**什麼是 ERC-721?** + +ERC-721 引入了非同質化代幣標準,換句話說,這類型的代幣是獨一無二,並且可以與來自同一智慧型合約的另一種代幣有不同的價值,這可能是由於其存在時間、稀有性甚至是視覺觀感等其他原因。 +等一下,視覺觀感? + +是的! 所有 NFT 都有一個名為 `tokenId` 的 `uint256` 變數,因此對於任何 ERC-721 合約, +`contract address, uint256 tokenId` 這組配對都必須是全域唯一的。 話雖如此,一個去中心化應用程式可以有一個 "轉換器", +它使用 `tokenId` 作為輸入,並輸出一些很酷的東西的圖片,像是殭屍、武器、技能或超讚的貓咪! + +## 先決條件 {#prerequisites} + +- [賬戶](/developers/docs/accounts/) +- [智能合約](/developers/docs/smart-contracts/) +- [代幣標準](/developers/docs/standards/tokens/) + +## 主旨 {#body} + +ERC-721(以太坊意見請求 721)由 William Entriken、Dieter Shirley、Jacob Evans、Nastassia Sachs 於 2018 年 1 月提出,是一種非同質化代幣標準,在智慧型合約中實作代幣應用程式介面。 + +它提供的功能包括將代幣從一個帳戶轉移到另一個帳戶、獲取帳戶當前的代幣餘額、獲取特定代幣的所有者以及網路上可用代幣的總供應量。 +此外它還有一些其他功能,例如批准帳戶中一定數量的代幣可以被第三方帳戶轉移。 + +如果智慧型合約實作以下方法和事件,則可以將其稱為 ERC-721 非同質化代幣合約。一旦部署,它將負責追蹤以太坊上創建的代幣。 + +來自 [EIP-721](https://eips.ethereum.org/EIPS/eip-721): + +### 方法 {#methods} + +```solidity + function balanceOf(address _owner) external view returns (uint256); + function ownerOf(uint256 _tokenId) external view returns (address); + function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable; + function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable; + function transferFrom(address _from, address _to, uint256 _tokenId) external payable; + function approve(address _approved, uint256 _tokenId) external payable; + function setApprovalForAll(address _operator, bool _approved) external; + function getApproved(uint256 _tokenId) external view returns (address); + function isApprovedForAll(address _owner, address _operator) external view returns (bool); +``` + +### Events {#events} + +```solidity + event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); + event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); + event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved); +``` + +### 範例 {#web3py-example} + +讓我們看看為何標準如此重要,去讓我們檢查以太坊上的任何 ERC-721 代幣合約變得簡單。 +我們只需要合約應用程式二進位介面 (ABI) 來創建任何 ERC-721 代幣的介面。 如下所示,我們將使用簡化的 ABI,使其成為一個低門檻的範例。 + +#### Web3.py 範例 {#web3py-example} + +首先,請確認您已安裝 [Web3.py](https://web3py.readthedocs.io/en/stable/quickstart.html#installation) Python 函式庫: + +``` +pip install web3 +``` + +```python +from web3 import Web3 +from web3._utils.events import get_event_data + + +w3 = Web3(Web3.HTTPProvider("https://cloudflare-eth.com")) + +ck_token_addr = "0x06012c8cf97BEaD5deAe237070F9587f8E7A266d" # CryptoKitties 合約 + +acc_address = "0xb1690C08E213a35Ed9bAb7B318DE14420FB57d8C" # CryptoKitties 銷售拍賣 + +# 這是 ERC-721 NFT 合約的簡化版合約應用程式二進位介面 (ABI)。 +# 它只會公開以下方法:balanceOf(address)、name()、ownerOf(tokenId)、symbol()、totalSupply() +simplified_abi = [ + { + 'inputs': [{'internalType': 'address', 'name': 'owner', 'type': 'address'}], + 'name': 'balanceOf', + 'outputs': [{'internalType': 'uint256', 'name': '', 'type': 'uint256'}], + 'payable': False, 'stateMutability': 'view', 'type': 'function', 'constant': True + }, + { + 'inputs': [], + 'name': 'name', + 'outputs': [{'internalType': 'string', 'name': '', 'type': 'string'}], + 'stateMutability': 'view', 'type': 'function', 'constant': True + }, + { + 'inputs': [{'internalType': 'uint256', 'name': 'tokenId', 'type': 'uint256'}], + 'name': 'ownerOf', + 'outputs': [{'internalType': 'address', 'name': '', 'type': 'address'}], + 'payable': False, 'stateMutability': 'view', 'type': 'function', 'constant': True + }, + { + 'inputs': [], + 'name': 'symbol', + 'outputs': [{'internalType': 'string', 'name': '', 'type': 'string'}], + 'stateMutability': 'view', 'type': 'function', 'constant': True + }, + { + 'inputs': [], + 'name': 'totalSupply', + 'outputs': [{'internalType': 'uint256', 'name': '', 'type': 'uint256'}], + 'stateMutability': 'view', 'type': 'function', 'constant': True + }, +] + +ck_extra_abi = [ + { + 'inputs': [], + 'name': 'pregnantKitties', + 'outputs': [{'name': '', 'type': 'uint256'}], + 'payable': False, 'stateMutability': 'view', 'type': 'function', 'constant': True + }, + { + 'inputs': [{'name': '_kittyId', 'type': 'uint256'}], + 'name': 'isPregnant', + 'outputs': [{'name': '', 'type': 'bool'}], + 'payable': False, 'stateMutability': 'view', 'type': 'function', 'constant': True + } +] + +ck_contract = w3.eth.contract(address=w3.to_checksum_address(ck_token_addr), abi=simplified_abi+ck_extra_abi) +name = ck_contract.functions.name().call() +symbol = ck_contract.functions.symbol().call() +kitties_auctions = ck_contract.functions.balanceOf(acc_address).call() +print(f"{name} [{symbol}] 拍賣中的 NFT:{kitties_auctions}") + +pregnant_kitties = ck_contract.functions.pregnantKitties().call() +print(f"{name} [{symbol}] 懷孕中的 NFT:{pregnant_kitties}") + +# 使用 Transfer 事件 ABI 來取得已轉移貓咪的資訊。 +tx_event_abi = { + 'anonymous': False, + 'inputs': [ + {'indexed': False, 'name': 'from', 'type': 'address'}, + {'indexed': False, 'name': 'to', 'type': 'address'}, + {'indexed': False, 'name': 'tokenId', 'type': 'uint256'}], + 'name': 'Transfer', + 'type': 'event' +} + +# 我們需要事件的簽章來篩選日誌 +event_signature = w3.keccak(text="Transfer(address,address,uint256)").hex() + +logs = w3.eth.get_logs({ + "fromBlock": w3.eth.block_number - 120, + "address": w3.to_checksum_address(ck_token_addr), + "topics": [event_signature] +}) + +# 注意: +# - 如果沒有回傳任何 Transfer 事件,請增加 120 這個區塊數量。 +# - 如果找不到任何 Transfer 事件,您也可以嘗試在此處取得 tokenId: +# https://etherscan.io/address/0x06012c8cf97BEaD5deAe237070F9587f8E7A266d#events +# 按一下以展開事件的日誌,並複製其「tokenId」引數 +recent_tx = [get_event_data(w3.codec, tx_event_abi, log)["args"] for log in logs] + +if recent_tx: + kitty_id = recent_tx[0]['tokenId'] # 從上面的連結將「tokenId」貼在此處 + is_pregnant = ck_contract.functions.isPregnant(kitty_id).call() + print(f"{name} [{symbol}] NFT {kitty_id} 是否懷孕:{is_pregnant}") +``` + +除了標準事件外,謎戀貓合約還有一些有趣的事件。 + +讓我們檢查其中兩個:`Pregnant` 和 `Birth`。 + +```python +# 使用 Pregnant 和 Birth 事件的 ABI 來取得新貓咪的資訊。 +ck_extra_events_abi = [ + { + 'anonymous': False, + 'inputs': [ + {'indexed': False, 'name': 'owner', 'type': 'address'}, + {'indexed': False, 'name': 'matronId', 'type': 'uint256'}, + {'indexed': False, 'name': 'sireId', 'type': 'uint256'}, + {'indexed': False, 'name': 'cooldownEndBlock', 'type': 'uint256'}], + 'name': 'Pregnant', + 'type': 'event' + }, + { + 'anonymous': False, + 'inputs': [ + {'indexed': False, 'name': 'owner', 'type': 'address'}, + {'indexed': False, 'name': 'kittyId', 'type': 'uint256'}, + {'indexed': False, 'name': 'matronId', 'type': 'uint256'}, + {'indexed': False, 'name': 'sireId', 'type': 'uint256'}, + {'indexed': False, 'name': 'genes', 'type': 'uint256'}], + 'name': 'Birth', + 'type': 'event' + }] + +# 我們需要事件的簽章來篩選日誌 +ck_event_signatures = [ + w3.keccak(text="Pregnant(address,uint256,uint256,uint256)").hex(), + w3.keccak(text="Birth(address,uint256,uint256,uint256,uint256)").hex(), +] + +# 這是一個 Pregnant 事件: +# - https://etherscan.io/tx/0xc97eb514a41004acc447ac9d0d6a27ea6da305ac8b877dff37e49db42e1f8cef#eventlog +pregnant_logs = w3.eth.get_logs({ + "fromBlock": w3.eth.block_number - 120, + "address": w3.to_checksum_address(ck_token_addr), + "topics": [ck_event_signatures[0]] +}) + +recent_pregnants = [get_event_data(w3.codec, ck_extra_events_abi[0], log)["args"] for log in pregnant_logs] + +# 這是一個 Birth 事件: +# - https://etherscan.io/tx/0x3978028e08a25bb4c44f7877eb3573b9644309c044bf087e335397f16356340a +birth_logs = w3.eth.get_logs({ + "fromBlock": w3.eth.block_number - 120, + "address": w3.to_checksum_address(ck_token_addr), + "topics": [ck_event_signatures[1]] +}) + +recent_births = [get_event_data(w3.codec, ck_extra_events_abi[1], log)["args"] for log in birth_logs] +``` + +## 熱門 NFT {#popular-nfts} + +- [Etherscan NFT Tracker](https://etherscan.io/nft-top-contracts) 根據轉帳量列出以太坊上的頂級 NFT。 +- [CryptoKitties](https://www.cryptokitties.co/) 是一款遊戲,主題圍繞著一種我們稱之為「謎戀貓」的 + 可繁殖、可收藏且非常可愛的生物。 +- [Sorare](https://sorare.com/) 是一款全球夢幻足球遊戲,你可以在其中收集限量版收藏品、 + 管理你的球隊並參與競爭以贏得獎品。 +- [以太坊域名服務 (ENS)](https://ens.domains/) 提供一種安全且去中心化的方式,可使用簡單易讀的名稱來定址 + 鏈上和鏈下的資源。 +- [POAP](https://poap.xyz) 會向參加活動或完成特定行動的人們免費發放 NFT。 建立和分發 POAP 是免費的。 +- [Unstoppable Domains](https://unstoppabledomains.com/) 是一家總部位於舊金山的公司,專門在 + 區塊鏈上建立網域。 區塊鏈網域以人類可讀的名稱取代加密貨幣地址,並可用於啟用 + 抗審查的網站。 +- [Gods Unchained Cards](https://godsunchained.com/) 是以太坊區塊鏈上的一款集換式卡牌遊戲 (TCG),它使用 NFT 為 + 遊戲內資產帶來真正的所有權。 +- [Bored Ape Yacht Club](https://boredapeyachtclub.com) 是一個包含 10,000 個獨特 NFT 的收藏品,它既是一件可證明為稀有的藝術品,也同時是俱樂部的會員代幣,能為會員提供福利,而這些福利會隨著社群的努力與時俱進。 + +## 延伸閱讀 {#further-reading} + +- [EIP-721:ERC-721 非同質化代幣標準](https://eips.ethereum.org/EIPS/eip-721) +- [OpenZeppelin - ERC-721 文件](https://docs.openzeppelin.com/contracts/3.x/erc721) +- [OpenZeppelin - ERC-721 實作](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol) +- [Alchemy NFT API](https://www.alchemy.com/docs/reference/nft-api-quickstart) diff --git a/public/content/translations/zh-tw/developers/docs/standards/tokens/erc-777/index.md b/public/content/translations/zh-tw/developers/docs/standards/tokens/erc-777/index.md new file mode 100644 index 00000000000..6486d71e7ef --- /dev/null +++ b/public/content/translations/zh-tw/developers/docs/standards/tokens/erc-777/index.md @@ -0,0 +1,45 @@ +--- +title: "ERC-777 代幣標準" +description: "了解 ERC-777,這是一種帶有掛鉤 (hooks) 的改良版同質化代幣標準,但基於安全考量,建議使用 ERC-20。" +lang: zh-tw +--- + +## 警告 {#warning} + +ERC-777 由於[容易受到不同種類的網絡攻擊](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/2620),因此難以正確實行。 為此建議使用 [ERC-20](/developers/docs/standards/tokens/erc-20/)。本頁保留作歷史檔案。 + +## 簡介? {#introduction} + +ERC-777是一種同質化代幣標準, 改良於現有 [ERC-20](/developers/docs/standards/tokens/erc-20/) 標準上。 + +## 先決條件 {#prerequisites} + +為能更好地理解本頁內容, 我們推薦你先閱讀有關 [ERC-20](/developers/docs/standards/tokens/erc-20/)。 + +## ERC-777 相對於 ERC-20 提出了哪些改進? {#-erc-777-vs-erc-20} + +ERC-777 相對於 ERC-20 進行了以下改進。 + +### 掛鉤 {#hooks} + +掛鉤是智能合約程式碼中所描述的一種函式。當代幣透過合約發送或接收時,掛鉤就會被呼叫。這使得智能合約能夠對傳入或傳出的代幣做出反應。 + +掛鉤是使用 [ERC-1820](https://eips.ethereum.org/EIPS/eip-1820) 標準註冊和發現的。 + +#### 為什麼掛鉤如此出色? {#why-are-hooks-great} + +1. 掛鉤允許在單筆交易中向合約傳送代幣並通知合約,而 [ERC-20](https://eips.ethereum.org/EIPS/eip-20) 則需要進行雙重調用 (`approve`/`transferFrom`) 來達成同樣的操作。 +2. 未註冊掛鉤的合約與 ERC-777 不相容。當接收合約未註冊掛鉤時,發送合約將中止交易。這可防止意外轉帳至非 ERC-777 智能合約。 +3. 掛鉤可以拒絕交易。 + +### 小數 {#decimals} + +此標準還解決了 ERC-20 中引起的 `decimals` 混亂。 這種明確度改善了開發者的體驗。 + +### 向後兼容 ERC-20 {#backwards-compatibility-with-erc-20} + +ERC-777 合約可以像 ERC-20 合約一樣進行互動。 + +## 延伸閱讀 {#further-reading} + +[EIP-777: 代幣標準](https://eips.ethereum.org/EIPS/eip-777) diff --git a/public/content/translations/zh-tw/developers/docs/standards/tokens/index.md b/public/content/translations/zh-tw/developers/docs/standards/tokens/index.md new file mode 100644 index 00000000000..05d5dc57064 --- /dev/null +++ b/public/content/translations/zh-tw/developers/docs/standards/tokens/index.md @@ -0,0 +1,41 @@ +--- +title: "代幣標準" +description: "探索以太坊代幣標準,包含用於同質化與非同質化代幣的 ERC-20、ERC-721 和 ERC-1155。" +lang: zh-tw +incomplete: true +--- + +## 介紹 {#introduction} + +許多以太坊開發標準都專注於代幣介面。 這些標準有助於確保智能合約保持可組合性,因此當新專案發行代幣時,它能與現有的去中心化交易所和應用程式保持相容。 + +代幣標準定義了代幣在整個以太坊生態系統中的行為和互動方式。 它們讓開發者更容易建構,無需重造輪子,並確保代幣可與錢包、交易所及 DeFi 平台無縫運作。 無論是在遊戲、管理體系還是其他使用案例中,這些標準都提供了一致性,並讓以太坊更加互聯互通。 + +## 先決條件 {#prerequisites} + +- [以太坊開發標準](/developers/docs/standards/) +- [智能合約](/developers/docs/smart-contracts/) + +## 代幣標準 {#token-standards} + +以下是以太坊上一些最受歡迎的代幣標準: + +- [ERC-20](/developers/docs/standards/tokens/erc-20/) - 一種適用於同質化(可互換)代幣的標準介面,例如投票代幣、質押代幣或虛擬貨幣。 + +### NFT 標準 {#nft-standards} + +- [ERC-721](/developers/docs/standards/tokens/erc-721/) - 一種非同質化代幣的標準介面,例如藝術品或歌曲的契約。 +- [ERC-1155](/developers/docs/standards/tokens/erc-1155/) - ERC-1155 允許更有效率的交易和交易捆綁 – 從而節省成本。 該代幣標準允許創建實用代幣(例如 $BNB 或 $BAT)和非同質化代幣如 CryptoPunks。 + +完整的 [ERC](https://eips.ethereum.org/erc) 提案清單。 + +## 延伸閱讀 {#further-reading} + +_知道一個曾經幫助你學習更多社區或社團資源? 歡迎在本頁自由編輯或添加內容!_ + +## 相關教學 {#related-tutorials} + +- [代幣整合檢查清單](/developers/tutorials/token-integration-checklist/) _– 一份在與代幣互動時的注意事項清單。_ +- [了解 ERC20 代幣智能合約](/developers/tutorials/understand-the-erc-20-token-smart-contract/) _– 在以太坊測試網上部署您第一個智能合約的簡介。_ +- [從 Solidity 智能合約轉帳及授權 ERC20 代幣](/developers/tutorials/transfers-and-approval-of-erc-20-tokens-from-a-solidity-smart-contract/) _– 如何使用 Solidity 語言,透過智能合約與代幣互動。_ +- [實作 ERC721 市場 [操作指南]](/developers/tutorials/how-to-implement-an-erc721-market/) _– 如何在去中心化的分類廣告板上出售代幣化物品。_ diff --git a/public/content/translations/zh-tw/developers/docs/storage/index.md b/public/content/translations/zh-tw/developers/docs/storage/index.md index 8fc5397730a..d30769ec77f 100644 --- a/public/content/translations/zh-tw/developers/docs/storage/index.md +++ b/public/content/translations/zh-tw/developers/docs/storage/index.md @@ -1,12 +1,12 @@ --- -title: 去中心化存儲 -description: 去中心化存儲及可以將該存儲整合到去中心化應用程式的可用工具概觀 +title: "去中心化存儲" +description: "去中心化存儲及可以將該存儲整合到去中心化應用程式的可用工具概觀" lang: zh-tw --- 與單一公司或組織運作的中心化伺服器不同,去中心化存儲系統由持有全部資料中部分資料的使用者和營運者的點對點網路組成,建立了一個彈性文件存儲共用系統。 這些存儲系統可以位於基於區塊鏈的應用程式或任何點對點網路中。 -以太坊本身可以用作去中心化存儲系統,所有智慧型合約中的程式碼存儲都是如此。 然而,當涉及大量資料時,就不符合以太坊的設計目的。 該鏈正在穩步增長,但在撰寫本文時,以太坊鏈約為 500GB - 1TB([取決於用戶端](https://etherscan.io/chartsync/chaindefault)),網路上的每個節點都需要能夠存儲所有資料。 如果鏈上資料量擴大(例如 5TB),所有節點都無法繼續運作。 此外,由於[燃料](/developers/docs/gas)費用,將這麼多資料部署到主網的成本將非常昂貴。 +以太坊本身可以用作去中心化存儲系統,所有智慧型合約中的程式碼存儲都是如此。 然而,當涉及大量資料時,就不符合以太坊的設計目的。 該鏈正在穩步增長,但在撰寫本文時,以太坊鏈的大小約為 500GB 至 1TB([取決于用戶端](https://etherscan.io/chartsync/chaindefault)),網路上的每個節點都需要能夠存儲所有資料。 如果鏈上資料量擴大(例如 5TB),所有節點都無法繼續運作。 此外,由於 [gas](/developers/docs/gas) 費用,將這麼多資料部署到主網的成本將會高得嚇人。 由於這些限制,我們需要不同的鏈或方法來以去中心化方式存儲大量資料。 @@ -17,15 +17,15 @@ lang: zh-tw - 去中心化 - 共識 -## 持續機制 / 誘因架構 {#persistence-mechanism} +## 持久性機制 / 激勵結構 {#persistence-mechanism} ### 基於區塊鏈 {#blockchain-based} 為了讓一段資料永久保存,我們需要使用持久性機制。 例如,在以太坊上,持久性機制意味著運行一個節點時需要考慮整條鏈。 新的資料被新增至鏈的末端,並且鏈會繼續增長,並要求每個節點複製所有內嵌的資料。 -這稱為**基於區塊鏈**的持久性。 +這就是所謂的 **基於區塊鏈** 的持久性。 -基於區塊鏈的持久性會出現區塊鏈過大,無法維護和存儲所有資料的問題(例如[許多機構](https://healthit.com.au/how-big-is-the-internet-and-how-do-we-measure-it/)預測整條區塊鏈網路需要 40ZB 的存儲容量)。 +基於區塊鏈的持久性的問題在於,鏈可能會變得過於龐大,以至於無法實際地維護和存儲所有資料(例如,[許多來源](https://healthit.com.au/how-big-is-the-internet-and-how-do-we-measure-it/)估計網際網路需要超過 40 ZB 的存儲容量)。 區塊鏈也必須具有某種類型的激勵結構。 為實現基於區塊鏈的持久性,需要向驗證者支付費用。 資料被新增到鏈上後,向驗證者支付以讓其繼續添加資料。 @@ -36,14 +36,14 @@ lang: zh-tw ### 基於合約 {#contract-based} -我們能直觀地感受到,**基於合約**的持久性使得資料不能被每個節點複製並永久存儲,而必須根據合約協定進行維護。 這些是與多個節點簽訂的協定,承諾在一段時間內保存一段資料。 一旦時間結束,就必須向節點續費,以保持資料的持久性。 +基於合約的持久性認為,資料無法由每個節點複製並永久存儲,而必須透過合約協議來維護。 這些是與多個節點簽訂的協定,承諾在一段時間內保存一段資料。 一旦時間結束,就必須向節點續費,以保持資料的持久性。 -在大多數情況下,不會將所有資料存儲在鏈上,而是存儲資料在鏈上位置的雜湊值。 這樣,就不需要擴充整個鏈來保留所有資料。 +在大多數情況下,不會將所有資料存儲在鏈上,而是存儲資料在鏈上位置的哈希。 這樣,就不需要擴充整個鏈來保留所有資料。 具有基於合約的持久性的平台: -- [Filecoin](https://docs.filecoin.io/about-filecoin/what-is-filecoin/) -- [Skynet](https://siasky.net/) +- [Filecoin](https://docs.filecoin.io/basics/what-is-filecoin) +- [Skynet](https://sia.tech/) - [Storj](https://storj.io/) - [Züs](https://zus.network/) - [Crust Network](https://crust.network) @@ -54,14 +54,14 @@ lang: zh-tw 星際檔案系統是一個儲存和存取檔案、網站、應用程式和資料的分散式系統。 雖然它沒有內建激勵計劃,但可以與上述任何基於合約的激勵解決方案一起使用,以獲得更長期的持久性。 另一個將資料持久儲存在星際檔案系統上的方法是與某項固定服務(表示將你的資料固定在某處)一起使用。 你甚至可以運行自己的星際檔案系統節點來為該網路做出貢獻,從而將你和/或他人的資料免費且持久地儲存在星際檔案系統上。 -- [星際檔案系統](https://docs.ipfs.io/concepts/what-is-ipfs/) -- [Pinata](https://www.pinata.cloud/)_(星際檔案系統固定服務)_ -- [web3.storage](https://web3.storage/)_(星際檔案系統/菲樂幣固定服務)_ -- [Infura](https://infura.io/product/ipfs)_(星際檔案系統固定服務)_ -- [IPFS Scan](https://ipfs-scan.io) _(星際檔案系統固定瀏覽器)_ -- -- [Filebase](https://filebase.com)_(星際檔案系統固定服務)_ -- [Spheron Network](https://spheron.network/) _(星際檔案系統/菲樂幣固定服務)_ +- [IPFS](https://docs.ipfs.io/concepts/what-is-ipfs/) +- [Pinata](https://www.pinata.cloud/) _(IPFS 釘選服務)_ +- [web3.storage](https://web3.storage/) _(IPFS/Filecoin 釘選服務)_ +- [Infura](https://infura.io/product/ipfs) _(IPFS 釘選服務)_ +- [IPFS Scan](https://ipfs-scan.io) _(IPFS 釘選瀏覽器)_ +- [4EVERLAND](https://www.4everland.org/)_(IPFS 釘選服務)_ +- [Filebase](https://filebase.com) _(IPFS 釘選服務)_ +- [Spheron Network](https://spheron.network/) _(IPFS/Filecoin 釘選服務)_ SWARM 是一種去中心化的資料儲存和分發技術,具有儲存激勵系統和儲存空間租金價格預測機。 @@ -69,7 +69,7 @@ SWARM 是一種去中心化的資料儲存和分發技術,具有儲存激勵 為了保留資料,系統必須有某種機制來確保已保留資料。 -### 質詢機制 {#challenge-mechanism} +### 挑戰機制 {#challenge-mechanism} 確保已保留資料的最常用方法之一是使用向節點發出的某種類型的加密質詢以確保節點仍然擁有資料。 一個簡單的例子就是查看Arweave的存取證明。 它們向節點發出質詢,看看節點是否擁有最新區塊和過去隨機區塊的資料。 如果節點無法給出答案,就會受到處罰。 @@ -82,7 +82,7 @@ SWARM 是一種去中心化的資料儲存和分發技術,具有儲存激勵 - Crust Network - 4EVERLAND -### 去中央化性 {#decentrality} +### 去中心化 {#decentrality} 沒有很好的工具來衡量平台的去中心化程度,但一般來說,你會希望使用不具有某種形式的「認識客戶」的工具來提供平台並非中心化的證據。 @@ -91,14 +91,14 @@ SWARM 是一種去中心化的資料儲存和分發技術,具有儲存激勵 - Skynet - Arweave - Filecoin -- IPFS -- Ethereum +- 星際檔案系統 +- 以太坊 - Crust Network - 4EVERLAND ### 共識 {#consensus} -這些工具中的大多數都有自己的[共識機制](/developers/docs/consensus-mechanisms/)版本,但通常它們基於[**工作量證明 (PoW)**](/developers/docs/consensus-mechanisms/pow/) 或[**權益證明 (PoS)**](/developers/docs/consensus-mechanisms/pos/)。 +這些工具大多有自己的[共識機制](/developers/docs/consensus-mechanisms/)版本,但通常是基於 [**工作量證明 (PoW)**](/developers/docs/consensus-mechanisms/pow/) 或 [**權益證明 (PoS)**](/developers/docs/consensus-mechanisms/pos/)。 基於工作量證明: @@ -114,103 +114,103 @@ SWARM 是一種去中心化的資料儲存和分發技術,具有儲存激勵 ## 相關工具 {#related-tools} -**IPFS - _星際檔案系統是以太坊的去中心化存儲和檔案引用系統。_** +**IPFS - _星際檔案系統 (InterPlanetary File System) 是一種給以太坊使用的去中心化存儲與檔案參考系統。_** - [Ipfs.io](https://ipfs.io/) - [文件](https://docs.ipfs.io/) -- [Github](https://github.com/ipfs/ipfs) +- [GitHub](https://github.com/ipfs/ipfs) -**Storj DCS - _為開發者提供安全、私有且相容 S3 的去中心化雲端物件存儲。_** +**Storj DCS - _為開發者設計的安全、私有且與 S3 相容的去中心化雲端物件存儲。_** - [Storj.io](https://storj.io/) - [文件](https://docs.storj.io/) - [GitHub](https://github.com/storj/storj) -**Skynet - _Skynet 是一個致力於去中心化網路的去中心化工作量證明鏈。_** +**Sia - _利用密碼學建立無需信任的雲端存儲市集,讓買賣雙方可以直接交易。_** -- [Skynet.net](https://siasky.net/) -- [文件](https://siasky.net/docs/) -- [Github](https://github.com/SkynetLabs/) +- [Skynet.net](https://sia.tech/) +- [文件](https://docs.sia.tech/) +- [GitHub](https://github.com/SiaFoundation/) -**Filecoin - _Filecoin 是由星際檔案系統背後的同一團隊建立的。 它是星際檔案系統概念之上的激勵層。_** +**Filecoin - _Filecoin 由 IPFS 背後的同一個團隊所創建。 此添增一誘因層面於IPFS想法之上._** - [Filecoin.io](https://filecoin.io/) - [文件](https://docs.filecoin.io/) -- [Github](https://github.com/filecoin-project/) +- [GitHub](https://github.com/filecoin-project/) -**Arweave - _Arweave 是一個用於存儲資料的去中心化存儲平台。_** +**Arweave - _Arweave 是一個用來存儲資料的去中心化存儲平台。_** - [Arweave.org](https://www.arweave.org/) - [文件](https://docs.arweave.org/info/) - [Arweave](https://github.com/ArweaveTeam/arweave/) -**Züs - _Züs 是具有分片和 Blobber 的權益證明去中心化存儲平台。_** +**Züs - _Züs 是一個具有分片和 blobber 的權益證明去中心化存儲平台。_** - [zus.network](https://zus.network/) -- [文件](https://0chaindocs.gitbook.io/zus-docs) -- [Github](https://github.com/0chain/) +- [文件](https://docs.zus.network/zus-docs/) +- [GitHub](https://github.com/0chain/) -**Crust Network - _Crust 是基於星際檔案系統的去中心化存儲平台。_** +**Crust Network - _Crust 是建構於 IPFS 之上的去中心化存儲平台。_** - [Crust.network](https://crust.network) - [文件](https://wiki.crust.network) - [GitHub](https://github.com/crustio) -**Swarm - _用於以太坊 web3 堆疊的分佈式存儲平台和內容分發服務。_** +**Swarm - _為以太坊 web3 堆疊設計的分散式存儲平台與內容分發服務。_** - [EthSwarm.org](https://www.ethswarm.org/) -- [文件](https://docs.ethswarm.org/docs/) -- [Github](https://github.com/ethersphere/) +- [文件](https://docs.ethswarm.org/) +- [GitHub](https://github.com/ethersphere/) -**OrbitDB - _基於星際檔案系統的去中心化點對點資料庫。_** +**OrbitDB - _建構於 IPFS 之上的去中心化點對點資料庫。_** - [OrbitDB.org](https://orbitdb.org/) - [文件](https://github.com/orbitdb/field-manual/) -- [Github](https://github.com/orbitdb/orbit-db/) +- [GitHub](https://github.com/orbitdb/orbit-db/) -**Aleph.im - _去中心化雲端專案(資料庫、檔案存儲、運算和去中心化身分)。 鏈下和鏈上點對點技術的獨特融合。 星際檔案系統和多鏈相容性。_** +**Aleph.im - _去中心化雲端專案(資料庫、檔案存儲、運算與 DID)。 鏈下和鏈上點對點技術的獨特融合。 IPFS及跨鏈組合性._** -- [Aleph.im](https://aleph.im/) -- [文件](https://aleph.im/#/developers/) -- [Github](https://github.com/aleph-im/) +- [Aleph.im](https://aleph.cloud/) +- [文件](https://docs.aleph.cloud/) +- [GitHub](https://github.com/aleph-im/) -**Ceramic - _使用者控制的星際檔案系統資料庫存儲,用於資料豐富且引人入勝的應用程式。_** +**Ceramic - _為資料豐富且具吸引力的應用程式設計,由使用者控制的 IPFS 資料庫存儲。_** - [Ceramic.network](https://ceramic.network/) -- [文件](https://developers.ceramic.network/learn/welcome/) -- [Github](https://github.com/ceramicnetwork/js-ceramic/) +- [文件](https://developers.ceramic.network/) +- [GitHub](https://github.com/ceramicnetwork/js-ceramic/) -**Filebase - _ S3 相容的去中心化存儲和異地備援星際檔案系統固定服務。 所有透過 Filebase 上傳到星際檔案系統的檔案,都會自動被固定到 Filebase 基礎設施,並在全球複製 3 份。_** +**Filebase - _與 S3 相容的去中心化存儲和異地備援 IPFS 釘選服務。 所有透過 Filebase 上傳到 IPFS 的檔案都會自動釘選到 Filebase 基礎設施,並在全球複製 3 份。_** - [Filebase.com](https://filebase.com/) -- [文檔](https://docs.filebase.com/) -- [Github](https://github.com/filebase) +- [文件](https://docs.filebase.com/) +- [GitHub](https://github.com/filebase) -**4EVERLAND - _Web 3.0 雲端運算平台,集存儲、運算和網路核心能力於一身,相容於 S3 並在星際檔案系統和 Arweave 等去中心化存儲網路上提供同步資料存儲。_** +**4EVERLAND - _一個 Web 3.0 雲端運算平台,整合了存儲、運算和網路核心能力,與 S3 相容,並在 IPFS 和 Arweave 等去中心化存儲網路上提供同步資料存儲。_** - [4everland.org](https://www.4everland.org/) - [文件](https://docs.4everland.org/) - [GitHub](https://github.com/4everland) -**Kaleido - _區塊鏈即服務平台,具有點擊按鈕的星際檔案系統節點_** +**Kaleido - _一個提供可一鍵部署 IPFS 節點的區塊鏈即服務平台_** - [Kaleido](https://kaleido.io/) - [文件](https://docs.kaleido.io/kaleido-services/ipfs/) - [GitHub](https://github.com/kaleido-io) -**Spheron Network - _Spheron 是一個平台即服務 (PaaS),專為希望在去中心化基礎設施上以最佳效能啟動其應用程式的去中心化應用程式而設計。 它提供開箱即用的運算、去中心化存儲、內容傳遞網路和網頁寄存。_** +**Spheron Network - _Spheron 是一個平台即服務 (PaaS),專為希望在去中心化基礎設施上以最佳效能啟動其應用程式的去中心化應用程式而設計。 它提供開箱即用的運算、去中心化存儲、CDN 與網頁代管服務。_** - [spheron.network](https://spheron.network/) - [文件](https://docs.spheron.network/) - [GitHub](https://github.com/spheronFdn) -## 衍生閱讀 {#further-reading} +## 延伸閱讀 {#further-reading} -- [什麼是去中心化存儲?](https://coinmarketcap.com/alexandria/article/what-is-decentralized-storage-a-deep-dive-by-filecoin) - _CoinMarketCap_ -- [打破關於去中心化存儲的五個常見誤解](https://www.storj.io/blog/busting-five-common-myths-about-decentralized-storage) - _Storj_ +- [什麼是去中心化存儲?](https://coinmarketcap.com/academy/article/what-is-decentralized-storage-a-deep-dive-by-filecoin) - _CoinMarketCap_ +- [破解關於去中心化存儲的五個常見迷思](https://www.storj.io/blog/busting-five-common-myths-about-decentralized-storage) - _Storj_ -_知道一個曾經幫助你學習更多社區或社團資源? 歡迎在本頁自由編輯或添加內容!!_ +_知道一個曾經幫助你學習更多社區或社團資源? 歡迎在本頁自由編輯或添加內容!_ ## 相關主題 {#related-topics} -- [開發架構](/developers/docs/frameworks/) +- [開發框架](/developers/docs/frameworks/) diff --git a/public/content/translations/zh-tw/developers/docs/transactions/index.md b/public/content/translations/zh-tw/developers/docs/transactions/index.md index b233bf5bf44..7d55a46a269 100644 --- a/public/content/translations/zh-tw/developers/docs/transactions/index.md +++ b/public/content/translations/zh-tw/developers/docs/transactions/index.md @@ -1,20 +1,21 @@ --- -title: 交易 -description: 以太坊交易概觀 – 運作原理、資料結構以及如何透過應用程式發送。 +title: "交易" +description: "以太坊交易概觀 – 運作原理、資料結構以及如何透過應用程式發送。" lang: zh-tw --- 交易是帳戶發出的帶密碼學簽章的指令。 帳戶將發起交易以更新以太坊網路的狀態。 最簡單的交易是將以太幣從一個帳戶轉帳到另一個帳戶。 -## 前置要求 {#prerequisites} +## 先決條件 {#prerequisites} -為了讓你更容易理解本頁,建議你先閱讀[帳戶](/developers/docs/accounts/)及我們的[以太坊介紹](/developers/docs/intro-to-ethereum/)。 +為協助您更了解本頁,建議您先閱讀 [帳戶](/developers/docs/accounts/) 和我們的 [以太坊簡介](/developers/docs/intro-to-ethereum/)。 ## 什麼是交易? {#whats-a-transaction} 以太坊交易是指由外部帳戶發起的操作,換句話說,此帳戶是由人而不是智慧型合約管理的帳戶。 例如,如果 Bob 發送給 Alice 1 以太幣,Bob 的帳戶必須扣除,Alice 的帳戶必須存入。 此更改狀態的操作發生在交易中。 -![顯示交易導致狀態變化的圖表](./tx.png) _此圖源於[以太坊EVM圖解](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ +![顯示交易導致狀態變更的圖表](./tx.png) +_圖表改編自 [Ethereum EVM 圖解](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ 交易會改變以太坊虛擬機的狀態,須廣播至整個網路。 任何節點都可以廣播要在以太坊虛擬機上執行的交易請求;之後驗證者將執行交易並將引起的狀態變化傳播到網路上的其他節點。 @@ -22,17 +23,17 @@ lang: zh-tw 提交的交易包括下列資訊: -- `from` – 發送者(簽署交易者)的地址。 這將是一個外部擁有的帳戶,因爲合約帳戶無法傳送交易 -- `to` – 接收地址(若為外部帳戶,交易將會轉移金額。 如果為合約帳戶,交易將執行合約程式碼) +- `from` – 發送者的地址,將會用來簽署交易。 這將是一個外部擁有的帳戶,因爲合約帳戶無法傳送交易 +- `to` – 接收地址 (若是外部擁有的帳戶,此交易將會轉移價值。 如果為合約帳戶,交易將執行合約程式碼) - `signature` – 發送者的識別碼。 當發送者以私密金鑰簽署交易並確認發送者已授權此交易时,就會產生此簽章。 -- `nonce` - 用來表示帳戶中交易編號的按順序遞增計數器 -- `value` – 發送者轉帳至接收者的以太幣數量(面額為 WEI,1 以太幣等於 10 的 18 次方 wei) -- `input data` –可選欄位,可填入任意資料 -- `gasLimit` – 交易可以使用的最大燃料單位數量。 [以太坊虛擬機](/developers/docs/evm/opcodes)指定了每個計算步驟的所需燃料單位 -- `maxPriorityFeePerGas` - 已使用燃料的最高價格,可作為給驗證者的小費 -- `maxFeePerGas` - 願意為交易支付的每單位燃料的最高費用(包含 `baseFeePerGas` 和 `maxPriorityFeePerGas`) +- `nonce` - 一個循序遞增的計數器,代表來自該帳戶的交易編號 +- `value` – 從發送者轉移到接收者的 ETH 數量 (以 WEI 為單位,其中 1 ETH 等於 1e+18 wei) +- `input data` – 選填欄位,可包含任意資料 +- `gasLimit` – 交易可消耗的 Gas 單位上限。 [EVM](/developers/docs/evm/opcodes) 指定了每個運算步驟所需的 Gas 單位 +- `maxPriorityFeePerGas` - 可作為給驗證程式小費的每單位 Gas 最高價格 +- `maxFeePerGas` - 願意為此交易支付的每單位 Gas 最高費用 (包含 `baseFeePerGas` 與 `maxPriorityFeePerGas`) -燃料指請驗證者處理交易所需的計算。 使用者必須為計算支付費用。 `gasLimit` 和 `maxPriorityFeePerGas` 決定支付給驗證者的最高交易費。 [更多燃料相關資訊](/developers/docs/gas/)。 +燃料指請驗證者處理交易所需的計算。 使用者必須為計算支付費用。 `gasLimit` 和 `maxPriorityFeePerGas` 決定支付給驗證程式的最高交易費用。 [更多關於 Gas 的資訊](/developers/docs/gas/)。 交易物件看起來有些像以下內容: @@ -41,10 +42,10 @@ lang: zh-tw from: "0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8", to: "0xac03bb73b6a9e108530aff4df5077c2b3d481e5a", gasLimit: "21000", - maxFeePerGas: "300" - maxPriorityFeePerGas: "10" + maxFeePerGas: "300", + maxPriorityFeePerGas: "10", nonce: "0", - value: "10000000000", + value: "10000000000" } ``` @@ -52,7 +53,7 @@ lang: zh-tw Geth 之類的以太坊用戶端將處理此簽署過程。 -[JSON-RPC](/developers/docs/apis/json-rpc) 呼叫範例: +範例 [JSON-RPC](/developers/docs/apis/json-rpc) 呼叫: ```json { @@ -99,22 +100,26 @@ Geth 之類的以太坊用戶端將處理此簽署過程。 } ``` -- `raw` 是[遞迴長度前綴 (RLP)](/developers/docs/data-structures-and-encoding/rlp) 編碼形式的已簽署交易 +- `raw` 是以 [遞迴長度前綴 (RLP)](/developers/docs/data-structures-and-encoding/rlp) 編碼形式呈現的已簽署交易 - `tx` 是 JSON 形式的已簽署交易 交易具備簽章雜湊值,因此可通過加密技術證明交易來自發送者並提交至網路。 ### 資料欄位 {#the-data-field} -大多數交易從外部帳戶存取合約。 大部分合約都用 Solidity 寫成,並根據[應用程式介面 (ABI)](/glossary/#abi) 解譯其資料欄位。 +大多數交易從外部帳戶存取合約。 +大多數合約以 Solidity 撰寫,並根據 [應用程式二進位介面 (ABI)](/glossary/#abi) 解譯其資料欄位。 -前四個字節位元組使用函式名稱及參數的雜湊值指定要呼叫的函式。 有時候可以從使用[此資料庫](https://www.4byte.directory/signatures/)識別選擇器中的函式。 +前四個字節位元組使用函式名稱及參數的雜湊值指定要呼叫的函式。 +有時您可以使用[此資料庫](https://www.4byte.directory/signatures/) 來從選擇器識別函式。 -calldata 的剩餘部分是參數,[依據 ABI 規範中的說明編碼](https://docs.soliditylang.org/en/latest/abi-spec.html#formal-specification-of-the-encoding)。 +calldata 的其餘部分是引數,[根據 ABI 規格中的指定方式進行編碼](https://docs.soliditylang.org/en/latest/abi-spec.html#formal-specification-of-the-encoding)。 -例如,我們來看下[這筆交易](https://etherscan.io/tx/0xd0dcbe007569fcfa1902dae0ab8b4e078efe42e231786312289b1eee5590f6a1)。 使用 **Click to see More** 檢視 calldata。 +例如,我們來看看[這筆交易](https://etherscan.io/tx/0xd0dcbe007569fcfa1902dae0ab8b4e078efe42e231786312289b1eee5590f6a1)。 +使用 **Click to see More** 檢視 calldata。 -函式選擇器為 `0xa9059cbb`。 一些[已知的函式具有此簽章](https://www.4byte.directory/signatures/?bytes4_signature=0xa9059cbb)。 在這個例子中,[合約的原始程式碼](https://etherscan.io/address/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48#code)已經上傳到 Etherscan,所以我們知道函式是 `transfer(address,uint256)`。 +函式選擇器是 `0xa9059cbb`。 有數個[已知函式具有此簽章](https://www.4byte.directory/signatures/?bytes4_signature=0xa9059cbb)。 +在本案例中,[合約原始碼](https://etherscan.io/address/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48#code)已上傳至 Etherscan,因此我們知道函式為 `transfer(address,uint256)`。 其餘資料如下所示: @@ -123,7 +128,9 @@ calldata 的剩餘部分是參數,[依據 ABI 規範中的說明編碼](https: 000000000000000000000000000000000000000000000000000000003b0559f4 ``` -根據 ABI 規範,應用程式介面中的整數值(例如地址,20 字節位元組的整數)顯示為 32 字節位元組的字,並且前面用 0 來填補。 所以我們知道 `to` 地址為 [`4f6742badb049791cd9a37ea913f2bac38d01279`](https://etherscan.io/address/0x4f6742badb049791cd9a37ea913f2bac38d01279)。 `value` 為 0x3b0559f4 = 990206452。 +根據 ABI 規範,應用程式介面中的整數值(例如地址,20 字節位元組的整數)顯示為 32 字節位元組的字,並且前面用 0 來填補。 +因此我們知道 `to` 地址是 [`4f6742badb049791cd9a37ea913f2bac38d01279`](https://etherscan.io/address/0x4f6742badb049791cd9a37ea913f2bac38d01279)。 +`value` 為 0x3b0559f4 = 990206452。 ## 交易類型 {#types-of-transactions} @@ -133,11 +140,11 @@ calldata 的剩餘部分是參數,[依據 ABI 規範中的說明編碼](https: - 合約部署交易:沒有「to」地址的交易,其資料欄供合約程式碼所用。 - 合約執行:與部署的智慧型合約互動的交易。 在本例中,「to」地址為智慧型合約的地址。 -### 關於燃料 {#on-gas} +### 關於 Gas {#on-gas} -如上所述,執行交易需要花費[燃料](/developers/docs/gas/)。 簡單的轉帳交易需要 21000 單位燃料。 +如前所述,執行交易需要花費 [Gas](/developers/docs/gas/)。 簡單的轉帳交易需要 21000 單位燃料。 -所以,若 Bob 要以 190 gwei 的 `baseFeePerGas` 還有 10 gwei 的 `maxPriorityFeePerGas` 給 Alice 發送 1 以太幣,Bob 將需要支付以下費用: +因此,如果 Bob 要在 `baseFeePerGas` 為 190 gwei 且 `maxPriorityFeePerGas` 為 10 gwei 的情況下,傳送 1 ETH 給 Alice,Bob 將需要支付下列費用: ``` (190 + 10) * 21000 = 4,200,000 gwei @@ -145,77 +152,82 @@ calldata 的剩餘部分是參數,[依據 ABI 規範中的說明編碼](https: 0.0042 以太幣 ``` -Bob 的帳戶會被扣除 **-1.0042 以太幣**(1 以太幣給 Alice + 0.0042 以太幣用來支付燃料費) +Bob 的帳戶將會被扣款 **-1.0042 ETH** (1 ETH 給 Alice + 0.0042 ETH 的 Gas 費用) -Alice 的帳戶將存入 **+1.0 以太幣** +Alice 的帳戶將會存入 **+1.0 ETH** -基本費用將銷毀 **-0.00399 以太幣** +基本費用將被銷毀 **-0.00399 ETH** -驗證者將保留 **+0.000210 以太幣**的小費 +驗證程式保留小費 **+0.000210 ETH** - -![顯示如何退還未使用燃料的圖表](./gas-tx.png) _此圖源於[以太坊EVM圖解](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ +![顯示未使用 Gas 如何退款的圖表](./gas-tx.png) +_圖表改編自 [Ethereum EVM 圖解](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ 任何交易中未使用的燃料都會退還給使用者帳戶。 -### 智慧型合約互動 {#smart-contract-interactions} +### 智慧合約互動 {#smart-contract-interactions} 任何涉及智慧型合約的交易都需要燃料。 -智慧型合約也可以包含稱為 [`view`](https://docs.soliditylang.org/en/latest/contracts.html#view-functions) 或 [`pure`](https://docs.soliditylang.org/en/latest/contracts.html#pure-functions) 的函數,而不會改變合約的狀態。 因此,從外部帳戶調用這些函數不需要任何燃料。 此場景的底層遠端程序呼叫為 [`eth_call`](/developers/docs/apis/json-rpc#eth_call)。 +智慧合約也可以包含 [`view`](https://docs.soliditylang.org/en/latest/contracts.html#view-functions) 或 [`pure`](https://docs.soliditylang.org/en/latest/contracts.html#pure-functions) 函式,這些函式不會改變合約的狀態。 因此,從外部帳戶調用這些函數不需要任何燃料。 此情境的底層 RPC 呼叫是 [`eth_call`](/developers/docs/apis/json-rpc#eth_call)。 -與使用 `eth_call` 存取不同,這些 `view` 或 `pure` 函數也通常被內部調用(即從合約本身調用或從另一個合約調用),這會消耗燃料。 +與使用 `eth_call` 存取不同,這些 `view` 或 `pure` 函式也常在內部被呼叫 (即從合約本身或從另一個合約呼叫),這確實會花費 Gas。 -## 交易的生命週期 {#transaction-lifecycle} +## 交易生命週期 {#transaction-lifecycle} 一旦交易被提交,就會發生以下情況: -1. 透過加密方式生成交易雜湊值: `0x97d99bc7729211111a21b12c933c949d4f31684f1d6954ff477d0477538ff017` +1. 交易哈希是以密碼學方式產生的: + `0x97d99bc7729211111a21b12c933c949d4f31684f1d6954ff477d0477538ff017` 2. 然後該交易會廣播到網路並添加到交易池中,交易池中包含了其他所有等待中的網路交易。 3. 為了要驗證交易並使交易「成功」,驗證者必須選擇你的交易並將它打包進區塊中。 -4. 隨著時間推移,含有你交易的區塊會被升級為「已證明」,然後是「最終化」。 這些升級進一步確定 你的交易已經成功且永遠不會被更改。 當區塊「最終化」後,就僅可能被網路層級的攻擊變更, 此類攻擊需要花費數十億美元。 +4. 隨著時間推移,含有你交易的區塊會被升級為「已證明」,然後是「最終化」。 這些升級能讓您更加 + 確定交易成功,且永遠不會被更改。 一旦區塊「最終確認」,就只能透過 + 耗資數十億美元的網路層級攻擊才能更改。 -## 視訊示範 {#a-visual-demo} +## 視覺化示範 {#a-visual-demo} 觀看 Austin 為你講解交易、燃料和挖礦。 -## Typed Transaction Envelope 交易 {#typed-transaction-envelope} +## 類型化交易封包 {#typed-transaction-envelope} -以太坊最初有一種形式的交易。 每筆交易都包含 nonce、gas price、gas limit、to address、value、data、v、r 與 s。 這些欄位均為 [RLP 編碼](/developers/docs/data-structures-and-encoding/rlp/),看上去像是以下內容: +以太坊最初有一種形式的交易。 每筆交易都包含 nonce、gas price、gas limit、to address、value、data、v、r 與 s。 這些欄位經過 [RLP 編碼](/developers/docs/data-structures-and-encoding/rlp/)後,看起來像這樣: `RLP([nonce, gasPrice, gasLimit, to, value, data, v, r, s])` -以太坊不斷演進以支援多種交易類型,以便在實作存取清單和 [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) 等新功能時不會影響原有交易形式。 +以太坊已演進到支援多種類型的交易,以便在實作存取清單和 [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) 等新功能時,不會影響舊有交易格式。 -[EIP-2718](https://eips.ethereum.org/EIPS/eip-2718) 是支援此類行為的協議。 交易的解釋如下: +[EIP-2718](https://eips.ethereum.org/EIPS/eip-2718) 實現了這種行為。 交易的解釋如下: `TransactionType || TransactionPayload` 其欄位定義如下: -- `TransactionType` - 介於 0 和 0x7f 之間的數字,代表總計 128 種可能的交易類型。 -- `TransactionPayload` - 由交易類型定義的任意字節位元組陣列。 +- `TransactionType` - 一個介於 0 和 0x7f 之間的數字,總共有 128 種可能的交易類型。 +- `TransactionPayload` - 由交易類型定義的任意位元組陣列。 -根據 `TransactionType` 值,交易可以分類為: +根據 `TransactionType` 的值,交易可分類為: -1. **類型 0(傳統)交易:**自以太坊推出以來使用的原始交易格式。 它們不包括 [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) 的功能,例如動態燃料費計算或智慧型合約的存取清單。 傳統交易缺少在序列化形式中指示交易類型的特定前綴,在使用[遞迴長度前綴 (RLP)](/developers/docs/data-structures-and-encoding/rlp) 編碼時,該前綴以位元組 `0xf8` 開始。 這些交易的 TransactionType 值為 `0x0`。 +1. **類型 0 (傳統) 交易:** 自以太坊推出以來使用的原始交易格式。 它們不包含 [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) 的功能,例如動態 Gas 費用計算或智慧合約的存取清單。 傳統交易在其序列化形式中缺少指示其類型的特定前綴,在使用[遞迴長度前綴 (RLP)](/developers/docs/data-structures-and-encoding/rlp) 編碼時以位元組 `0xf8` 開頭。 這些交易的 TransactionType 值為 `0x0`。 -2. **類型 1 交易:**在 [EIP-2930](https://eips.ethereum.org/EIPS/eip-2930) 中引入作為以太坊[柏林升級](/ethereum-forks/#berlin)的一部分,這些交易包含一個 `accessList` 參數。 此清單指定了交易期望存取的地址和儲存金鑰,有助於潛在降低涉及智慧型合約的複雜交易的[燃料](/developers/docs/gas/)成本。 EIP-1559 的費用市場變化不會包含在類型 1 交易中。 類型 1 交易也包含一個 `yParity` 參數,該參數可以是 `0x0` 或 `0x1`,表示 secp256k1 簽章的 y 值的奇偶性。 此類交易透過開頭的位元組 `0x01` 開頭辨識,其 TransactionType 值為 `0x1`。 +2. **類型 1 交易:** 在 [EIP-2930](https://eips.ethereum.org/EIPS/eip-2930) 中作為以太坊[柏林升級](/ethereum-forks/#berlin) 的一部分引入,這些交易包含一個 `accessList` 參數。 此清單指定了交易預期存取的地址和儲存金鑰,有助於潛在降低涉及智慧合約的複雜交易的 [Gas](/developers/docs/gas/) 成本。 EIP-1559 的費用市場變化不會包含在類型 1 交易中。 類型 1 交易也包含一個 `yParity` 參數,可以是 `0x0` 或 `0x1`,表示 secp256k1 簽章的 y 值的奇偶性。 它們以位元組 `0x01` 開頭來識別,其 TransactionType 值為 `0x1`。 -3. **類型 2 交易**,通常稱為 EIP-1559 交易,是以太坊[倫敦升級](/ethereum-forks/#london)裡 [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) 中引入的交易。 這類交易已成為以太坊網路上的標準交易類型。 這些交易引入了一種新的費用市場機制,透過將交易費用分為基本費用和優先費來提高可預測性。 這些交易的開頭為位元組 `0x02`,並包含 `maxPriorityFeePerGas` 和 `maxFeePerGas` 等欄位。 類型 2 交易因其靈活性和效率而成為預設交易,在網路高度擁塞期間尤其受到青睞,因為它們能夠幫助使用者更好地預測及管理交易費用。 這些交易的 TransactionType 值為 `0x2`。 +3. **類型 2 交易**,通常稱為 EIP-1559 交易,是在以太坊[倫敦升級](/ethereum-forks/#london) 的 [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) 中引入的交易。 這類交易已成為以太坊網路上的標準交易類型。 這些交易引入了一種新的費用市場機制,透過將交易費用分為基本費用和優先費來提高可預測性。 它們以位元組 `0x02` 開頭,並包含 `maxPriorityFeePerGas` 和 `maxFeePerGas` 等欄位。 類型 2 交易因其靈活性和效率而成為預設交易,在網路高度擁塞期間尤其受到青睞,因為它們能夠幫助使用者更好地預測及管理交易費用。 這些交易的 TransactionType 值為 `0x2`。 +4. 類型 3 (Blob) 交易在[EIP-4844](https://eips.ethereum.org/EIPS/eip-4844) 中作為以太坊 [Dencun 升級](/ethereum-forks/#dencun) 的一部分被引入。 這些交易旨在更高效地處理「blob」資料 (二進位大型物件),它們提供了一種以更低成本將資料發佈到以太坊網路的方法,尤其有利於二層網路卷軸。 Blob 交易包含額外欄位,例如 `blobVersionedHashes`、`maxFeePerBlobGas` 和 `blobGasPrice`。 它們以位元組 `0x03` 開頭,其 TransactionType 值為 `0x3`。 Blob 交易代表了以太坊在資料可用性和可擴張性方面的重大改進。 +5. 類型 4 交易是在[EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) 中作為以太坊 [Pectra 升級](/roadmap/pectra/) 的一部分引入的。 這些交易被設計為與帳戶抽象化向前相容。 它們允許 EOA 暫時表現得像智慧合約帳戶,而不會影響其原始功能。 它們包含一個 `authorization_list` 參數,用於指定 EOA 將其權限委派給哪個智慧合約。 交易後,EOA 的程式碼欄位將包含被委派的智慧合約地址。 -## 衍生閱讀 {#further-reading} +## 延伸閱讀 {#further-reading} -- [EIP-2718:Typed Transaction Envelope 交易](https://eips.ethereum.org/EIPS/eip-2718) +- [EIP-2718:類型化交易封包](https://eips.ethereum.org/EIPS/eip-2718) -_認識社區或社團資源能幫助大家學習更多? 歡迎自由編輯或添加於本頁!!_ +_知道一個曾經幫助你學習更多社區或社團資源? 歡迎在本頁自由編輯或添加內容!_ ## 相關主題 {#related-topics} -- [帳戶](/developers/docs/accounts/) -- [以太坊虛擬機](/developers/docs/evm/) +- [賬戶](/developers/docs/accounts/) +- [以太坊虛擬機 (EVM)](/developers/docs/evm/) - [Gas](/developers/docs/gas/) diff --git a/public/content/translations/zh-tw/developers/docs/web2-vs-web3/index.md b/public/content/translations/zh-tw/developers/docs/web2-vs-web3/index.md index d98309a961b..13f27fdc3ef 100644 --- a/public/content/translations/zh-tw/developers/docs/web2-vs-web3/index.md +++ b/public/content/translations/zh-tw/developers/docs/web2-vs-web3/index.md @@ -1,6 +1,6 @@ --- -title: Web2 vs Web3 -description: +title: "Web2 與 Web3" +description: "比較中心化 Web2 服務與建立在以太坊區塊鏈技術上的去中心化 Web3 應用程式。" lang: zh-tw --- @@ -8,7 +8,7 @@ Web2 指的是目前我們大多人熟知的網際網路。 網際網路由各 正在找尋找更適合初學者的資源? 請參閱我們的 [web3 簡介](/web3/)。 -## Web3 優點 {#web3-benefits} +## Web3 的優點 {#web3-benefits} 很多 Web3 開發者選擇建立去中心化應用程式,是因為以太坊固有的去中心化優點: @@ -17,7 +17,7 @@ Web2 指的是目前我們大多人熟知的網際網路。 網際網路由各 - 支付是透過原生代幣以太幣建立的。 - 以太坊是圖靈完備的,這表示你可以在上面寫許多程式。 -## 實務對比 {#practical-comparisons} +## 實際比較 {#practical-comparisons} | Web2 | Web3 | | ------------------------- | --------------------------------------- | @@ -52,11 +52,11 @@ Web3 目前的一些限制: 注意,這些概況可能並不適用於每個網路。 此外實際當中,網路的中心化與去中心化程度是一個範圍;沒有任何一個網路是完全中心化或完全去中心化的。 -## 衍生閱讀 {#further-reading} +## 延伸閱讀 {#further-reading} - [什麼是 Web3?](/web3/) - _ethereum.org_ - [Web 3.0 應用程式的架構](https://www.preethikasireddy.com/post/the-architecture-of-a-web-3-0-application) - _Preethi Kasireddy_ -- [去中心化的意義](https://medium.com/@VitalikButerin/the-meaning-of-decentralization-a0c92b76a274) _2017 年 2 月 6日 - Vitalik Buterin_ -- [去中心化的重要性](https://medium.com/s/story/why-decentralization-matters-5e3f79f7638e) _2018 年 2 月 18 日 - Chris Dixon_ -- [什麼是 Web 3.0?它為什麼重要?](https://medium.com/fabric-ventures/what-is-web-3-0-why-it-matters-934eb07f3d2b) _2019 年 12 月 31 日 - Max Mersch 和 Richard Muirhead_ -- [為何我們需要 Web 3.0](https://medium.com/@gavofyork/why-we-need-web-3-0-5da4f2bf95ab) _2018 年 9 月 12 日 - Gavin Wood_ +- [去中心化的意義](https://medium.com/@VitalikButerin/the-meaning-of-decentralization-a0c92b76a274) _2017 年 2 月 6 日 - Vitalik Buterin_ +- [為什麼去中心化很重要](https://onezero.medium.com/why-decentralization-matters-5e3f79f7638e) _2018 年 2 月 18 日 - Chris Dixon_ +- [什麼是 Web 3.0,以及它為何重要](https://medium.com/fabric-ventures/what-is-web-3-0-why-it-matters-934eb07f3d2b) _2019 年 12 月 31 日 - Max Mersch 和 Richard Muirhead_ +- [為什麼我們需要 Web 3.0](https://gavofyork.medium.com/why-we-need-web-3-0-5da4f2bf95ab) _2018 年 9 月 12 日 - Gavin Wood_ diff --git a/public/content/translations/zh-tw/developers/docs/wrapped-eth/index.md b/public/content/translations/zh-tw/developers/docs/wrapped-eth/index.md index defbdf83881..412c113c089 100644 --- a/public/content/translations/zh-tw/developers/docs/wrapped-eth/index.md +++ b/public/content/translations/zh-tw/developers/docs/wrapped-eth/index.md @@ -1,6 +1,6 @@ --- -title: 甚麼是包裝以太幣 (WETH) -description: 包裝以太幣 (WETH) 簡介 — 以太幣 (ETH) 的一種 ERC20 相容包裝函式。 +title: "甚麼是包裝以太幣 (WETH)" +description: "包裝以太幣 (WETH) 簡介 — 以太幣 (ETH) 的一種 ERC20 相容包裝函式。" lang: zh-tw --- @@ -35,19 +35,16 @@ lang: zh-tw 你需要支付燃料費來使用包裝以太幣智慧型合約來兌換或贖回以太幣。 - 包裝以太幣通常被認為是安全的,因為它基於一個簡單且經過實證的智慧型合約。 包裝以太幣合約也已經經過正式驗證,這是以太坊上智慧型合約的最高安全標準。 - 除了本頁描述的 [包裝以太幣的規範化實作](https://etherscan.io/token/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2)外,還有其他變體存在於市場中。 這些可能是由應用程式開發者建立的自訂代幣,或在其他區塊鏈上發行的版本,可能會有不同的行為或具有不同的安全屬性。 **始終仔細檢查代幣資訊,以確認你正在與哪一種包裝以太幣實作進行互動。** - @@ -55,7 +52,6 @@ lang: zh-tw - [以太坊主網](https://etherscan.io/token/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2) - [Arbitrum](https://arbiscan.io/token/0x82af49447d8a07e3bd95bd0d56f35241523fbab1) - [Optimism](https://optimistic.etherscan.io/token/0x4200000000000000000000000000000000000006) - ## 延伸閱讀 {#further-reading} diff --git a/public/content/translations/zh-tw/developers/tutorials/a-developers-guide-to-ethereum-part-one/index.md b/public/content/translations/zh-tw/developers/tutorials/a-developers-guide-to-ethereum-part-one/index.md new file mode 100644 index 00000000000..aaf899fbfa5 --- /dev/null +++ b/public/content/translations/zh-tw/developers/tutorials/a-developers-guide-to-ethereum-part-one/index.md @@ -0,0 +1,300 @@ +--- +title: "給 Python 開發者的以太坊介紹,第一部分" +description: "以太坊開發介紹,特別適合了解 Python 程式語言的開發人員。" +author: Marc Garreau +lang: zh-tw +tags: [ "Python", "web3.py" ] +skill: beginner +published: 2020-09-08 +source: Snake charmers +sourceUrl: https://snakecharmers.ethereum.org/a-developers-guide-to-ethereum-pt-1/ +--- + +所以,您已經聽說過以太坊,並準備好要深入探索了嗎? 本文將快速介紹一些區塊鏈基礎知識,然後讓您與一個模擬的以太坊節點互動——讀取區塊資料、檢查帳戶餘額以及傳送交易。 在此過程中,我們將強調傳統的應用程式建置方式與這種新的去中心化範式之間的差異。 + +## (非強制)先決條件 {#soft-prerequisites} + +本文旨在讓廣大開發人員都能輕鬆理解。 [Python 工具](/developers/docs/programming-languages/python/)將會被使用,但它們只是用來傳達概念的載體——如果您不是 Python 開發人員也沒問題。 不過,我會先假設您已經具備一些基礎知識,這樣我們就可以快速進入以太坊專屬的部分。 + +假設: + +- 您能夠操作終端機, +- 您寫過幾行 Python 程式碼, +- 您的電腦上已安裝 Python 3.6 或更高版本(強烈建議使用[虛擬環境](https://realpython.com/effective-python-environment/#virtual-environments)),以及 +- 您使用過 `pip`,Python 的套件安裝程式。 + 再次強調,即使您不符合上述任何條件,或者不打算重現本文中的程式碼,您仍然可以順利地跟上進度。 + +## 區塊鏈簡介 {#blockchains-briefly} + +描述以太坊的方式有很多種,但其核心是一個區塊鏈。 區塊鏈由一系列的區塊組成,所以讓我們從這裡開始。 簡單來說,以太坊區塊鏈上的每個區塊只包含一些元資料和一個交易列表。 在 JSON 格式中,它看起來像這樣: + +```json +{ + "number": 1234567, + "hash": "0xabc123...", + "parentHash": "0xdef456...", + ..., + "transactions": [...] +} +``` + +每個[區塊](/developers/docs/blocks/)都包含對前一個區塊的引用;`parentHash` 就是前一個區塊的哈希。 + +注意:以太坊經常使用哈希函數來產生固定大小的值(「哈希」)。 哈希在以太坊中扮演著重要角色,但目前您可以放心地將它們視為唯一的識別碼。 + +![一個描述區塊鏈的圖表,包含每個區塊內的資料](./blockchain-diagram.png) + +_區塊鏈本質上是一個鏈結串列;每個區塊都包含對前一個區塊的引用。_ + +這種資料結構本身並不是什麼新奇的東西,但管理網路的規則(即點對點協定)卻是全新的。 沒有中心化的權威機構;網路中的對等節點必須合作以維持網路運作,並透過競爭來決定下一個區塊要包含哪些交易。 所以,當您想寄錢給朋友時,您需要將該交易廣播到網路上,然後等待它被包含在即將產生的區塊中。 + +區塊鏈要驗證金錢確實從一位使用者傳送給另一位使用者,唯一的方法是使用該區塊鏈的原生貨幣(即由該區塊鏈創造和管理的貨幣)。 在以太坊中,這種貨幣稱為以太幣 (ether),而以太坊區塊鏈是唯一包含帳戶餘額官方記錄的地方。 + +## 新範式 {#a-new-paradigm} + +這個新的去中心化技術堆疊催生了新的開發者工具。 這類工具存在於許多程式語言中,但我們將從 Python 的角度來探討。 重申一次:即使 Python 不是您偏好的語言,跟上本文的內容應該也不會太困難。 + +想要與以太坊互動的 Python 開發人員很可能會使用 [Web3.py](https://web3py.readthedocs.io/)。 Web3.py 是一個函式庫,它能大幅簡化您連接到以太坊節點,以及從節點傳送和接收資料的方式。 + +注意:「以太坊節點」和「以太坊用戶端」這兩個詞可以互換使用。 無論是哪個詞,指的都是以太坊網路參與者執行的軟體。 這個軟體可以讀取區塊資料、在新區塊加入鏈上時接收更新、廣播新交易等等。 技術上來說,用戶端是軟體,節點是執行軟體的電腦。 + +[以太坊用戶端](/developers/docs/nodes-and-clients/)可以設定為透過 [IPC](https://wikipedia.org/wiki/Inter-process_communication)、HTTP 或 Websocket 進行連線,因此 Web3.py 需要對應此設定。 Web3.py 將這些連線選項稱為**提供者**。 您需要從這三種提供者中選擇一種,將 Web3.py 執行個體與您的節點連結。 + +![一個圖表,顯示 web3.py 如何使用 IPC 將您的應用程式連接到以太坊節點](./web3py-and-nodes.png) + +_設定以太坊節點和 Web3.py 使用相同的協定進行通訊,例如此圖中的 IPC。_ + +一旦 Web3.py 設定正確,您就可以開始與區塊鏈互動。 以下是一些 Web3.py 的使用範例,作為後續內容的預覽: + +```python +# 讀取區塊資料: +w3.eth.get_block('latest') + +# 傳送一筆交易: +w3.eth.send_transaction({'from': ..., 'to': ..., 'value': ...}) +``` + +## 安裝 {#installation} + +在這份逐步教學中,我們只會在 Python 直譯器中操作。 我們不會建立任何目錄、檔案、類別或函式。 + +注意:在下面的範例中,以 `$` 開頭的指令是用於在終端機中執行的。 (請勿輸入 `$`,它只是表示一行的開始。) + +首先,安裝 [IPython](https://ipython.org/),這是一個方便探索的使用者友好環境。 IPython 提供了 tab 鍵自動完成等功能,讓您更容易了解 Web3.py 的各種可能性。 + +```bash +pip install ipython +``` + +Web3.py 是以 `web3` 的名稱發布的。 安裝方式如下: + +```bash +pip install web3 +``` + +還有一件事——我們稍後將模擬一個區塊鏈,這需要額外安裝幾個相依套件。 您可以透過以下方式安裝: + +```bash +pip install 'web3[tester]' +``` + +您已準備就緒! + +注意:`web3[tester]` 套件支援到 Python 3.10.xx 版本。 + +## 啟動沙箱 {#spin-up-a-sandbox} + +在終端機中執行 `ipython` 來開啟一個新的 Python 環境。 這和執行 `python` 類似,但提供了更多附加功能。 + +```bash +ipython +``` + +這會印出您正在執行的 Python 和 IPython 版本資訊,然後您會看到一個等待輸入的提示符號: + +```python +In [1]: +``` + +您現在看到的是一個互動式 Python shell。 基本上,這是一個可以讓您盡情實驗的沙箱。 如果您已經進行到這一步,是時候匯入 Web3.py 了: + +```python +In [1]: from web3 import Web3 +``` + +## Web3 模組介紹 {#introducing-the-web3-module} + +除了作為通往以太坊的閘道,[Web3](https://web3py.readthedocs.io/en/stable/overview.html#base-api) 模組還提供了一些便捷函式。 讓我們來探索其中幾個。 + +在以太坊應用程式中,您通常需要轉換貨幣單位。 Web3 模組為此提供了幾個輔助方法:[from_wei](https://web3py.readthedocs.io/en/stable/web3.main.html#web3.Web3.from_wei) 和 [to_wei](https://web3py.readthedocs.io/en/stable/web3.main.html#web3.Web3.to_wei)。 + + +注意:眾所周知,電腦不擅長處理小數運算。 為了解決這個問題,開發人員通常以「分」為單位來儲存美元金額。 例如,價格為 5.99 美元的商品在資料庫中可能會被儲存為 599。 + +在處理以太幣交易時也使用類似的模式。 然而,以太幣不是兩位小數點,而是 18 位! 以太幣的最小單位稱為 wei,因此在傳送交易時指定的是這個數值。 + +1 以太幣 = 1000000000000000000 wei + +1 wei = 0.000000000000000001 以太幣 + + + +試著在 wei 與其他單位之間轉換一些數值。 請注意,在以太幣和 wei 之間[還有許多單位的名稱](https://web3py.readthedocs.io/en/stable/troubleshooting.html#how-do-i-convert-currency-denominations)。 其中比較有名的是 **gwei**,因為交易費用通常用它來表示。 + +```python +In [2]: Web3.to_wei(1, 'ether') +Out[2]: 1000000000000000000 + +In [3]: Web3.from_wei(500000000, 'gwei') +Out[3]: Decimal('0.5') +``` + +Web3 模組上的其他工具方法包括資料格式轉換器(例如 [`toHex`](https://web3py.readthedocs.io/en/stable/web3.main.html#web3.Web3.toHex))、位址輔助工具(例如 [`isAddress`](https://web3py.readthedocs.io/en/stable/web3.main.html#web3.Web3.isAddress))和哈希函數(例如 [`keccak`](https://web3py.readthedocs.io/en/stable/web3.main.html#web3.Web3.keccak))。 本系列文章的後續部分將會介紹其中許多內容。 若要查看所有可用的方法和屬性,可以輸入 `Web3` 來利用 IPython 的自動完成功能。 並在句點後按兩次 tab 鍵。 + +## 與鏈互動 {#talk-to-the-chain} + +便捷方法很棒,但讓我們繼續來談談區塊鏈。 下一步是設定 Web3.py 與以太坊節點進行通訊。 在這裡,我們可以選擇使用 IPC、HTTP 或 Websocket 提供者。 + +我們不會走這條路,但使用 HTTP 提供者的完整工作流程範例如下: + +- 下載一個以太坊節點,例如 [Geth](https://geth.ethereum.org/)。 +- 在一個終端機視窗中啟動 Geth,並等待它同步網路。 預設的 HTTP 連接埠是 `8545`,但可以自行設定。 +- 讓 Web3.py 透過 HTTP 連接到 `localhost:8545` 上的節點。 + `w3 = Web3(Web3.HTTPProvider('http://127.0.0.1:8545'))` +- 使用 `w3` 執行個體與節點互動。 + +雖然這是一種「真實」的作法,但同步過程需要數小時,而且如果您只想要一個開發環境,這並非必要。 為此,Web3.py 提供了第四種提供者:**EthereumTesterProvider**。 這個測試提供者會連結到一個模擬的以太坊節點,它有較寬鬆的權限和可供使用的假貨幣。 + +![一個圖表,顯示 EthereumTesterProvider 將您的 web3.py 應用程式連結到一個模擬的以太坊節點](./ethereumtesterprovider.png) + +_EthereumTesterProvider 會連接到一個模擬節點,對於快速建立開發環境來說非常方便。_ + +那個模擬節點稱為 [eth-tester](https://github.com/ethereum/eth-tester),我們在執行 `pip install web3[tester]` 指令時已經將它安裝。 設定 Web3.py 使用此測試提供者非常簡單: + +```python +In [4]: w3 = Web3(Web3.EthereumTesterProvider()) +``` + +現在您準備好在鏈上遨遊了! 這不是大家會說的話。 我剛才亂編的。 讓我們快速導覽一下。 + +## 快速導覽 {#the-quick-tour} + +首先,做個基本功能檢查: + +```python +In [5]: w3.is_connected() +Out[5]: True +``` + +因為我們使用的是測試提供者,這個測試不是很有價值,但如果它失敗了,很可能是您在實例化 `w3` 變數時打錯了字。 再次檢查您是否包含了內層的括號,即 `Web3.EthereumTesterProvider()`。 + +## 導覽第一站:[帳戶](/developers/docs/accounts/) {#tour-stop-1-accounts} + +為了方便,測試提供者建立了一些帳戶,並預先存入了測試以太幣。 + +首先,讓我們看看這些帳戶的列表: + +```python +In [6]: w3.eth.accounts +Out[6]: ['0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf', + '0x2B5AD5c4795c026514f8317c7a215E218DcCD6cF', + '0x6813Eb9362372EEF6200f3b1dbC3f819671cBA69', ...] +``` + +如果您執行這個指令,您應該會看到一個包含十個以 `0x` 開頭的字串列表。 每個都是一個**公開位址**,在某些方面,類似於支票帳戶的帳號。 您可以將此位址提供給想傳送以太幣給您的人。 + +如前所述,測試提供者已為每個帳戶預先存入一些測試以太幣。 讓我們來看看第一個帳戶裡有多少錢: + +```python +In [7]: w3.eth.get_balance(w3.eth.accounts[0]) +Out[7]: 1000000000000000000000000 +``` + +好多個零! 在您笑著把錢存入假銀行之前,回想一下前面關於貨幣單位的課程。 以太幣的數值是以最小單位 wei 來表示的。 將它轉換成以太幣: + +```python +In [8]: w3.from_wei(1000000000000000000000000, 'ether') +Out[8]: Decimal('1000000') +``` + +一百萬測試以太幣——還不賴。 + +## 導覽第二站:區塊資料 {#tour-stop-2-block-data} + +讓我們來看看這個模擬區塊鏈的狀態: + +```python +In [9]: w3.eth.get_block('latest') +Out[9]: AttributeDict({ + 'number': 0, + 'hash': HexBytes('0x9469878...'), + 'parentHash': HexBytes('0x0000000...'), + ... + 'transactions': [] +}) +``` + +一個區塊會傳回很多資訊,但這裡只指出幾點: + +- 區塊編號是零——無論您多久之前設定測試提供者都一樣。 與真實的以太坊網路每 12 秒新增一個新區塊不同,這個模擬會等到您給它一些工作才會有動作。 +- `transactions` 是一個空列表,原因相同:我們還沒有做任何事。 第一個區塊是**空區塊**,只是為了啟動這條鏈。 +- 請注意,`parentHash` 只是一堆空位元組。 這表示它是鏈中的第一個區塊,也稱為**創世區塊**。 + +## 導覽第三站:[交易](/developers/docs/transactions/) {#tour-stop-3-transactions} + +在有待處理的交易之前,我們會一直停在區塊 0,所以讓我們來建立一筆交易。 從一個帳戶傳送幾枚測試以太幣到另一個帳戶: + +```python +In [10]: tx_hash = w3.eth.send_transaction({ + 'from': w3.eth.accounts[0], + 'to': w3.eth.accounts[1], + 'value': w3.to_wei(3, 'ether'), + 'gas': 21000 +}) +``` + +通常這時候您需要等待幾秒鐘,讓您的交易被包含在新區塊中。 完整的過程大致如下: + +1. 提交一筆交易並保留交易哈希。 在包含該交易的區塊被建立和廣播之前,該交易是「待處理」狀態。 + `tx_hash = w3.eth.send_transaction({ … })` +2. 等待交易被包含在一個區塊中: + `w3.eth.wait_for_transaction_receipt(tx_hash)` +3. 繼續執行應用程式邏輯。 查看成功的交易: + `w3.eth.get_transaction(tx_hash)` + +我們的模擬環境會立即將交易新增到新區塊中,因此我們可以立即查看該交易: + +```python +In [11]: w3.eth.get_transaction(tx_hash) +Out[11]: AttributeDict({ + 'hash': HexBytes('0x15e9fb95dc39...'), + 'blockNumber': 1, + 'transactionIndex': 0, + 'from': '0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf', + 'to': '0x2B5AD5c4795c026514f8317c7a215E218DcCD6cF', + 'value': 3000000000000000000, + ... +}) +``` + +您會在這裡看到一些熟悉的詳細資訊:`from`、`to` 和 `value` 欄位應與我們 `send_transaction` 呼叫的輸入相符。 另一個讓人安心的地方是,這筆交易被包含在區塊編號 1 中,作為第一筆交易 (`'transactionIndex': 0`)。 + +我們也可以透過檢查兩個相關帳戶的餘額來輕鬆驗證這筆交易是否成功。 三枚以太幣應該已經從一個帳戶轉移到另一個帳戶。 + +```python +In [12]: w3.eth.get_balance(w3.eth.accounts[0]) +Out[12]: 999996999979000000000000 + +In [13]: w3.eth.get_balance(w3.eth.accounts[1]) +Out[13]: 1000003000000000000000000 +``` + +後者看起來沒錯! 餘額從 1,000,000 以太幣增加到 1,000,003 以太幣。 但第一個帳戶發生了什麼事? 它似乎損失了比三枚以太幣多一點的金額。 唉,天下沒有白吃的午餐,使用以太坊公有網路需要您補償其他對等節點所提供的支援。 提交交易的帳戶被扣除了一筆小額交易費用——這筆費用是消耗的 gas 量(一次 ETH 轉帳為 21000 單位 gas)乘以根據網路活動變動的基本費用,再加上給予將交易包含在區塊中的驗證者的小費。 + +更多關於 [gas](/developers/docs/gas/#post-london) 的資訊 + +注意:在公有網路上,交易費用會根據網路需求以及您希望交易處理的速度而變動。 如果您對費用計算的詳細說明感興趣,請參閱我之前關於交易如何被包含在區塊中的文章。 + +## 喘口氣 {#and-breathe} + +我們已經進行了一段時間,這裡似乎是個休息的好時機。 兔子洞還很深,我們將在本系列的第二部分繼續探索。 即將介紹的概念:連接到真實節點、智慧合約和代幣。 還有其他問題嗎? 讓我知道! 您的回饋將影響我們接下來的方向。 歡迎透過 [Twitter](https://twitter.com/wolovim) 提出請求。 diff --git a/public/content/translations/zh-tw/developers/tutorials/all-you-can-cache/index.md b/public/content/translations/zh-tw/developers/tutorials/all-you-can-cache/index.md new file mode 100644 index 00000000000..9dbaedf4296 --- /dev/null +++ b/public/content/translations/zh-tw/developers/tutorials/all-you-can-cache/index.md @@ -0,0 +1,864 @@ +--- +title: "任你快取" +description: "學習如何創建和使用快取合約,以降低卷軸交易的成本" +author: Ori Pomerantz +tags: [ "Layer 2", "快取", "儲存" ] +skill: intermediate +published: 2022-09-15 +lang: zh-tw +--- + +使用卷軸時,交易中一個位元組的成本遠高於一個儲存時隙的成本。 因此,盡可能在鏈上快取資訊是合理的。 + +在本文中,您將學習如何創建和使用快取合約,讓任何可能被多次使用的參數值都被快取,並在(首次使用後)能以更少的位元組來取用,以及如何撰寫使用此快取的鏈外程式碼。 + +如果您想跳過文章,直接查看原始程式碼,[請點擊這裡](https://github.com/qbzzt/20220915-all-you-can-cache)。 開發堆疊為 [Foundry](https://getfoundry.sh/introduction/installation/)。 + +## 總體設計 {#overall-design} + +為求簡單,我們假設所有交易參數都是 `uint256`,長度為 32 位元組。 當我們收到一筆交易時,我們會像這樣解析每個參數: + +1. 如果第一個位元組是 `0xFF`,則將接下來的 32 個位元組作為參數值並寫入快取。 + +2. 如果第一個位元組是 `0xFE`,則將接下來的 32 個位元組作為參數值,但_不_寫入快取。 + +3. 對於任何其他值,將前四個位元作為附加位元組的數量,後四個位元作為快取鍵的最高有效位。 下面有些範例: + + | calldata 中的位元組 | 快取鍵 | + | :-------------- | -------: | + | 0x0F | 0x0F | + | 0x10,0x10 | 0x10 | + | 0x12,0xAC | 0x02AC | + | 0x2D,0xEA, 0xD6 | 0x0DEAD6 | + +## 快取操作 {#cache-manipulation} + +快取在 [`Cache.sol`](https://github.com/qbzzt/20220915-all-you-can-cache/blob/main/src/Cache.sol) 中實現。 讓我們逐行檢視它。 + +```solidity +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + + +contract Cache { + + bytes1 public constant INTO_CACHE = 0xFF; + bytes1 public constant DONT_CACHE = 0xFE; +``` + +這些常數用於解釋特殊情況,即我們提供所有資訊,並選擇是否要將其寫入快取。 寫入快取需要對先前未使用的儲存時隙進行兩次 [`SSTORE`](https://www.evm.codes/#55) 操作,每次成本為 22100 Gas,因此我們將其設為可選。 + +```solidity + + mapping(uint => uint) public val2key; +``` + +值與其鍵之間的 [映射](https://www.geeksforgeeks.org/solidity/solidity-mappings/)。 在您送出交易之前,此資訊是編碼值所必需的。 + +```solidity + // 位置 n 儲存鍵 n+1 的值,因為我們需要保留 + // 零作為「不在快取中」的標記。 + uint[] public key2val; +``` + +我們可以使用陣列來進行從鍵到值的映射,因為我們是自己指派鍵,而且為求簡單,我們會循序指派。 + +```solidity + function cacheRead(uint _key) public view returns (uint) { + require(_key <= key2val.length, "Reading uninitialize cache entry"); + return key2val[_key-1]; + } // cacheRead +``` + +從快取中讀取一個值。 + +```solidity + // 如果快取中尚無此值,則將其寫入 + // 設為 public 僅為了讓測試能運作 + function cacheWrite(uint _value) public returns (uint) { + // 如果該值已在快取中,則回傳目前的鍵 + if (val2key[_value] != 0) { + return val2key[_value]; + } +``` + +將相同的值多次放入快取中是沒有意義的。 如果值已經存在,只需回傳現有的鍵即可。 + +```solidity + // 因為 0xFE 是特殊情況,所以快取能容納的最大鍵 + // 是 0x0D 後面跟著 15 個 0xFF。如果快取長度已達 + // 這麼大,就失敗。 + // 1 2 3 4 5 6 7 8 9 A B C D E F + require(key2val.length+1 < 0x0DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, + "cache overflow"); +``` + +我不認為我們會有這麼大的快取 (約 1.8\*1037 個項目,需要約 1027 TB 來儲存)。 然而,我的年紀足以記得 ["640kB 永遠夠用"](https://quoteinvestigator.com/2011/09/08/640k-enough/)這句話。 這個測試的成本非常低。 + +```solidity + // 使用下一個鍵寫入值 + val2key[_value] = key2val.length+1; +``` + +新增反向查找 (從值到鍵)。 + +```solidity + key2val.push(_value); +``` + +新增正向查找 (從鍵到值)。 因為我們是循序指派值,所以可以直接將其加在陣列最後一個值的後面。 + +```solidity + return key2val.length; + } // cacheWrite +``` + +回傳 `key2val` 的新長度,也就是新值儲存的儲存格。 + +```solidity + function _calldataVal(uint startByte, uint length) + private pure returns (uint) +``` + +此函數從 calldata 讀取任意長度 (最多 32 位元組,即一個字組的大小) 的值。 + +```solidity + { + uint _retVal; + + require(length < 0x21, + "_calldataVal length limit is 32 bytes"); + require(length + startByte <= msg.data.length, + "_calldataVal trying to read beyond calldatasize"); +``` + +這個函數是內部的,所以如果其餘的程式碼都撰寫正確,這些測試就不是必需的。 不過,它們的成本不高,所以不妨保留。 + +```solidity + assembly { + _retVal := calldataload(startByte) + } +``` + +此程式碼使用 [Yul](https://docs.soliditylang.org/en/v0.8.16/yul.html) 撰寫。 它從 calldata 讀取一個 32 位元組的值。 即使 calldata 在 `startByte+32` 之前就結束了,這段程式碼也能運作,因為 EVM 中未初始化的空間會被視為零。 + +```solidity + _retVal = _retVal >> (256-length*8); +``` + +我們不一定需要一個 32 位元組的值。 這會移除多餘的位元組。 + +```solidity + return _retVal; + } // _calldataVal + + + // 從 calldata 讀取單一參數,從 _fromByte 開始 + function _readParam(uint _fromByte) internal + returns (uint _nextByte, uint _parameterValue) + { +``` + +從 calldata 讀取單一參數。 請注意,我們不僅需要回傳讀取的值,還需要回傳下一個位元組的位置,因為參數的長度可能從 1 位元組到 33 位元組不等。 + +```solidity + // 第一個位元組告訴我們如何解釋其餘的部分 + uint8 _firstByte; + + _firstByte = uint8(_calldataVal(_fromByte, 1)); +``` + +Solidity 藉由禁止潛在危險的[隱含類型轉換](https://docs.soliditylang.org/en/v0.8.16/types.html#implicit-conversions),試圖減少錯誤的數量。 降級,例如從 256 位元降到 8 位元,需要明確指定。 + +```solidity + + // 讀取值,但不寫入快取 + if (_firstByte == uint8(DONT_CACHE)) + return(_fromByte+33, _calldataVal(_fromByte+1, 32)); + + // 讀取值,並將其寫入快取 + if (_firstByte == uint8(INTO_CACHE)) { + uint _param = _calldataVal(_fromByte+1, 32); + cacheWrite(_param); + return(_fromByte+33, _param); + } + + // 如果執行到這裡,表示我們需要從快取中讀取 + + // 要讀取的額外位元組數 + uint8 _extraBytes = _firstByte / 16; +``` + +取較低的[半位元組 (nibble)](https://en.wikipedia.org/wiki/Nibble) 並將其與其他位元組組合,以從快取中讀取值。 + +```solidity + uint _key = (uint256(_firstByte & 0x0F) << (8*_extraBytes)) + + _calldataVal(_fromByte+1, _extraBytes); + + return (_fromByte+_extraBytes+1, cacheRead(_key)); + + } // _readParam + + + // 讀取 n 個參數 (函數知道它們預期有多少個參數) + function _readParams(uint _paramNum) internal returns (uint[] memory) { +``` + +我們可以從 calldata 本身取得參數數量,但是呼叫我們的函數知道它們預期有多少個參數。 讓它們告訴我們比較容易。 + +```solidity + // 我們讀取的參數 + uint[] memory params = new uint[](_paramNum); + + // 參數從第 4 個位元組開始,之前是函數簽章 + uint _atByte = 4; + + for(uint i=0; i<_paramNum; i++) { + (_atByte, params[i]) = _readParam(_atByte); + } +``` + +讀取參數,直到您取得所需的數量。 如果我們超出 calldata 的結尾,`_readParams` 將會還原呼叫。 + +```solidity + + return(params); + } // readParams + + // 用於測試 _readParams,測試讀取四個參數 + function fourParam() public + returns (uint256,uint256,uint256,uint256) + { + uint[] memory params; + params = _readParams(4); + return (params[0], params[1], params[2], params[3]); + } // fourParam +``` + +Foundry 的一個大優點是它允許用 Solidity 撰寫測試 ([見下文的測試快取](#testing-the-cache))。 這讓單元測試變得容易得多。 這是一個讀取四個參數並回傳它們的函數,以便測試可以驗證它們是否正確。 + +```solidity + // 取得一個值,回傳將其編碼的位元組 (如果可能,使用快取) + function encodeVal(uint _val) public view returns(bytes memory) { +``` + +`encodeVal` 是一個由鏈外程式碼呼叫的函數,用來幫助創建使用快取的 calldata。 它接收單一值並回傳對其編碼的位元組。 此函數是 `view` 函數,所以不需要交易,且從外部呼叫時不消耗任何 Gas。 + +```solidity + uint _key = val2key[_val]; + + // 該值尚不在快取中,將其加入 + if (_key == 0) + return bytes.concat(INTO_CACHE, bytes32(_val)); +``` + +在 [EVM](/developers/docs/evm/) 中,所有未初始化的儲存空間都假設為零。 所以,如果我們查找一個不存在的值的鍵,我們會得到零。 在這種情況下,編碼它的位元組是 `INTO_CACHE` (這樣下次就會被快取),後面跟著實際的值。 + +```solidity + // 如果鍵 <0x10,則以單一位元組回傳 + if (_key < 0x10) + return bytes.concat(bytes1(uint8(_key))); +``` + +單一位元組是最簡單的。 我們只需使用 [`bytes.concat`](https://docs.soliditylang.org/en/v0.8.16/types.html#the-functions-bytes-concat-and-string-concat) 將 `bytes` 類型轉換為任意長度的位元組陣列。 儘管有這個名稱,但當只提供一個參數時,它也能正常運作。 + +```solidity + // 兩位元組值,編碼為 0x1vvv + if (_key < 0x1000) + return bytes.concat(bytes2(uint16(_key) | 0x1000)); +``` + +當我們的鍵小於 163 時,我們可以用兩個位元組來表示它。 我們首先將 256 位元值的 `_key` 轉換為 16 位元值,並使用邏輯「或」將額外位元組的數量加到第一個位元組上。 然後我們將其轉換為 `bytes2` 值,該值可以轉換為 `bytes`。 + +```solidity + // 可能有更聰明的方法以迴圈方式處理以下幾行, + // 但這是一個 view 函數,所以我為了節省程式員時間和簡化而進行優化。 + + if (_key < 16*256**2) + return bytes.concat(bytes3(uint24(_key) | (0x2 * 16 * 256**2))); + if (_key < 16*256**3) + return bytes.concat(bytes4(uint32(_key) | (0x3 * 16 * 256**3))); + . + . + . + if (_key < 16*256**14) + return bytes.concat(bytes15(uint120(_key) | (0xE * 16 * 256**14))); + if (_key < 16*256**15) + return bytes.concat(bytes16(uint128(_key) | (0xF * 16 * 256**15))); +``` + +其他值 (3 位元組、4 位元組等) 以相同的方式處理,只是欄位大小不同。 + +```solidity + // 如果執行到這裡,表示出了問題。 + revert("Error in encodeVal, should not happen"); +``` + +如果我們執行到這裡,表示我們得到了一個不小於 16\*25615 的鍵。 但是 `cacheWrite` 限制了鍵的範圍,所以我們甚至無法達到 14\*25616 (其第一個位元組會是 0xFE,看起來就像 `DONT_CACHE`)。 但是,為了防止未來的程式員引入錯誤,增加一個測試並不會花費太多成本。 + +```solidity + } // encodeVal + +} // Cache +``` + +### 測試快取 {#testing-the-cache} + +Foundry 的優點之一是 [它允許您用 Solidity 撰寫測試](https://getfoundry.sh/forge/tests/overview/),這讓撰寫單元測試變得更容易。 `Cache` 類別的測試在[這裡](https://github.com/qbzzt/20220915-all-you-can-cache/blob/main/test/Cache.t.sol)。 因為測試程式碼通常是重複的,所以本文只解釋有趣的部分。 + +```solidity +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import "forge-std/Test.sol"; + + +// 需要執行 `forge test -vv` 才能使用主控台。 +import "forge-std/console.sol"; +``` + +這只是使用測試套件和 `console.log` 所需的樣板程式碼。 + +```solidity +import "src/Cache.sol"; +``` + +我們需要知道我們正在測試的合約。 + +```solidity +contract CacheTest is Test { + Cache cache; + + function setUp() public { + cache = new Cache(); + } +``` + +`setUp` 函數在每次測試前被呼叫。 在這種情況下,我們只是創建一個新的快取,這樣我們的測試就不會互相影響。 + +```solidity + function testCaching() public { +``` + +測試是以 `test` 開頭的函數。 此函數檢查基本的快取功能,即寫入值並再次讀取它們。 + +```solidity + for(uint i=1; i<5000; i++) { + cache.cacheWrite(i*i); + } + + for(uint i=1; i<5000; i++) { + assertEq(cache.cacheRead(i), i*i); +``` + +這就是您如何使用 [`assert...` 函數](https://getfoundry.sh/reference/forge-std/std-assertions/) 進行實際測試的方式。 在這種情況下,我們檢查我們寫入的值是否與我們讀取的值相同。 我們可以捨棄 `cache.cacheWrite` 的結果,因為我們知道快取鍵是線性指派的。 + +```solidity + } + } // testCaching + + + // 將相同的值多次快取,確保鍵保持不變 + // the same + function testRepeatCaching() public { + for(uint i=1; i<100; i++) { + uint _key1 = cache.cacheWrite(i); + uint _key2 = cache.cacheWrite(i); + assertEq(_key1, _key2); + } +``` + +首先,我們將每個值寫入快取兩次,並確保鍵是相同的 (表示第二次寫入沒有真正發生)。 + +```solidity + for(uint i=1; i<100; i+=3) { + uint _key = cache.cacheWrite(i); + assertEq(_key, i); + } + } // testRepeatCaching +``` + +理論上,可能存在一個不影響連續快取寫入的錯誤。 所以這裡我們做一些非連續的寫入,看看值是否仍然沒有被重寫。 + +```solidity + // 從記憶體緩衝區讀取 uint (以確保我們取回我們送出的參數) + function toUint256(bytes memory _bytes, uint256 _start) internal pure + returns (uint256) +``` + +從 `bytes memory` 緩衝區讀取一個 256 位元字組。 這個實用功能快鍵讓我們可以驗證當我們執行使用快取的函數呼叫時,是否收到正確的結果。 + +```solidity + { + require(_bytes.length >= _start + 32, "toUint256_outOfBounds"); + uint256 tempUint; + + assembly { + tempUint := mload(add(add(_bytes, 0x20), _start)) + } +``` + +Yul 不支援 `uint256` 以外的數據結構,所以當您引用更複雜的數據結構時,例如記憶體緩衝區 `_bytes`,您會得到該結構的地址。 Solidity 將 `bytes memory` 值儲存為一個 32 位元組字組,其中包含長度,後面跟著實際的位元組,所以要取得位元組編號 `_start`,我們需要計算 `_bytes+32+_start`。 + +```solidity + + return tempUint; + } // toUint256 + + // fourParams() 的函數簽章,由 + // https://www.4byte.directory/signatures/?bytes4_signature=0x3edc1e6d 提供 + bytes4 constant FOUR_PARAMS = 0x3edc1e6d; + + // 只是一些常數值,用來查看我們是否取回正確的值 + uint256 constant VAL_A = 0xDEAD60A7; + uint256 constant VAL_B = 0xBEEF; + uint256 constant VAL_C = 0x600D; + uint256 constant VAL_D = 0x600D60A7; +``` + +一些我們測試所需的常數。 + +```solidity + function testReadParam() public { +``` + +呼叫 `fourParams()`,一個使用 `readParams` 的函數,來測試我們是否能正確讀取參數。 + +```solidity + address _cacheAddr = address(cache); + bool _success; + bytes memory _callInput; + bytes memory _callOutput; +``` + +我們不能使用正常的 ABI 機制來呼叫使用快取的函數,所以我們需要使用低階的 [`
.call()`](https://docs.soliditylang.org/en/v0.8.16/types.html#members-of-addresses) 機制。 該機制接受一個 `bytes memory` 作為輸入,並回傳它 (以及一個布林值) 作為輸出。 + +```solidity + // 第一次呼叫,快取是空的 + _callInput = bytes.concat( + FOUR_PARAMS, +``` + +讓同一個合約同時支援快取函數 (用於直接從交易呼叫) 和非快取函數 (用於從其他智能合約呼叫) 是很有用的。 為此,我們需要繼續依賴 Solidity 的機制來呼叫正確的函數,而不是將所有東西都放在[一個 `fallback` 函數](https://docs.soliditylang.org/en/v0.8.16/contracts.html#fallback-function)中。 這樣做使得可組合性變得容易得多。 在大多數情況下,單一位元組就足以識別函數,所以我們浪費了三個位元組 (16\*3=48 Gas)。 然而,在我寫這篇文章的時候,那 48 Gas 的成本是 0.07 美分,對於更簡單、更少錯誤的程式碼來說,這是一個合理的成本。 + +```solidity + // 第一個值,將它加入快取 + cache.INTO_CACHE(), + bytes32(VAL_A), +``` + +第一個值:一個旗標,表示這是一個需要寫入快取的完整值,後面跟著值的 32 個位元組。 其他三個值是相似的,除了 `VAL_B` 沒有寫入快取,而 `VAL_C` 既是第三個參數也是第四個參數。 + +```solidity + . + . + . + ); + (_success, _callOutput) = _cacheAddr.call(_callInput); +``` + +這就是我們實際呼叫 `Cache` 合約的地方。 + +```solidity + assertEq(_success, true); +``` + +我們預期呼叫會成功。 + +```solidity + assertEq(cache.cacheRead(1), VAL_A); + assertEq(cache.cacheRead(2), VAL_C); +``` + +我們從一個空的快取開始,然後加入 `VAL_A`,接著是 `VAL_C`。 我們預期第一個的鍵是 1,第二個是 2。 + +``` + assertEq(toUint256(_callOutput,0), VAL_A); + assertEq(toUint256(_callOutput,32), VAL_B); + assertEq(toUint256(_callOutput,64), VAL_C); + assertEq(toUint256(_callOutput,96), VAL_C); +``` + +輸出是四個參數。 這裡我們驗證它是正確的。 + +```solidity + // 第二次呼叫,我們可以使用快取 + _callInput = bytes.concat( + FOUR_PARAMS, + + // 快取中的第一個值 + bytes1(0x01), +``` + +小於 16 的快取鍵只有一個位元組。 + +```solidity + // 第二個值,不要將它加入快取 + cache.DONT_CACHE(), + bytes32(VAL_B), + + // 第三和第四個值,相同的值 + bytes1(0x02), + bytes1(0x02) + ); + . + . + . + } // testReadParam +``` + +呼叫後的測試與第一次呼叫後的測試相同。 + +```solidity + function testEncodeVal() public { +``` + +這個函數與 `testReadParam` 相似,只是我們不顯式地寫入參數,而是使用 `encodeVal()`。 + +```solidity + . + . + . + _callInput = bytes.concat( + FOUR_PARAMS, + cache.encodeVal(VAL_A), + cache.encodeVal(VAL_B), + cache.encodeVal(VAL_C), + cache.encodeVal(VAL_D) + ); + . + . + . + assertEq(_callInput.length, 4+1*4); + } // testEncodeVal +``` + +在 `testEncodeVal()` 中唯一的額外測試是驗證 `_callInput` 的長度是否正確。 對於第一次呼叫,它是 4+33\*4。 對於第二次,其中每個值都已在快取中,它是 4+1\*4。 + +```solidity + // 當鍵超過一個位元組時測試 encodeVal + // 最多三個位元組,因為填滿快取到四個位元組需要太長時間。 + function testEncodeValBig() public { + // 將一些值放入快取。 + // 為保持簡單,對值 n 使用鍵 n。 + for(uint i=1; i<0x1FFF; i++) { + cache.cacheWrite(i); + } +``` + +上面的 `testEncodeVal` 函數只向快取中寫入四個值,因此 [處理多位元組值的函數部分](https://github.com/qbzzt/20220915-all-you-can-cache/blob/main/src/Cache.sol#L144-L171) 沒有被檢查到。 但那段程式碼很複雜且容易出錯。 + +這個函數的第一部分是一個迴圈,它按順序將從 1 到 0x1FFF 的所有值寫入快取,這樣我們就能夠編碼這些值並知道它們的位置。 + +```solidity + . + . + . + + _callInput = bytes.concat( + FOUR_PARAMS, + cache.encodeVal(0x000F), // 一個位元組 0x0F + cache.encodeVal(0x0010), // 兩個位元組 0x1010 + cache.encodeVal(0x0100), // 兩個位元組 0x1100 + cache.encodeVal(0x1000) // 三個位元組 0x201000 + ); +``` + +測試一個位元組、兩個位元組和三個位元組的值。 我們沒有測試超過這個範圍,因為寫入足夠多的堆疊項目 (至少 0x10000000,大約二十五億) 會花費太長時間。 + +```solidity + . + . + . + . + } // testEncodeValBig + + + // 測試當緩衝區過小時,我們會得到一個 revert + function testShortCalldata() public { +``` + +測試在參數不足的異常情況下會發生什麼。 + +```solidity + . + . + . + (_success, _callOutput) = _cacheAddr.call(_callInput); + assertEq(_success, false); + } // testShortCalldata +``` + +由於它會還原,我們應該得到的結果是 `false`。 + +``` + // 使用不存在的快取鍵呼叫 + function testNoCacheKey() public { + . + . + . + _callInput = bytes.concat( + FOUR_PARAMS, + + // 第一個值,將它加入快取 + cache.INTO_CACHE(), + bytes32(VAL_A), + + // 第二個值 + bytes1(0x0F), + bytes2(0x1234), + bytes11(0xA10102030405060708090A) + ); +``` + +這個函數得到四個完全合法的參數,但快取是空的,所以沒有值可以讀取。 + +```solidity + . + . + . + // 測試當緩衝區過長時一切都能正常運作 + function testLongCalldata() public { + address _cacheAddr = address(cache); + bool _success; + bytes memory _callInput; + bytes memory _callOutput; + + // 第一次呼叫,快取是空的 + _callInput = bytes.concat( + FOUR_PARAMS, + + // 第一個值,將它加入快取 + cache.INTO_CACHE(), bytes32(VAL_A), + + // 第二個值,將它加入快取 + cache.INTO_CACHE(), bytes32(VAL_B), + + // 第三個值,將它加入快取 + cache.INTO_CACHE(), bytes32(VAL_C), + + // 第四個值,將它加入快取 + cache.INTO_CACHE(), bytes32(VAL_D), + + // 再加上一個值來「祝好運」 + bytes4(0x31112233) + ); +``` + +此函數傳送五個值。 我們知道第五個值被忽略了,因為它不是一個有效的快取項目,如果它被包含進去,就會導致還原。 + +```solidity + (_success, _callOutput) = _cacheAddr.call(_callInput); + assertEq(_success, true); + . + . + . + } // testLongCalldata + +} // CacheTest + +``` + +## 一個範例應用程式 {#a-sample-app} + +用 Solidity 寫測試固然很好,但終究去中心化應用程式需要能夠處理來自鏈外的請求才能派上用場。 本文示範如何在一個名為 `WORM` (意指「寫一次,讀多次」) 的去中心化應用程式中使用快取。 如果一個鍵尚未寫入,您可以將一個值寫入其中。 如果鍵已經寫入,您會得到一個還原。 + +### 合約 {#the-contract} + +[這是合約](https://github.com/qbzzt/20220915-all-you-can-cache/blob/main/src/WORM.sol)。 它大部分重複了我們已經用 `Cache` 和 `CacheTest` 做過的事情,所以我們只涵蓋有趣的部分。 + +```solidity +import "./Cache.sol"; + +contract WORM is Cache { +``` + +使用 `Cache` 最簡單的方法是在我們自己的合約中繼承它。 + +```solidity + function writeEntryCached() external { + uint[] memory params = _readParams(2); + writeEntry(params[0], params[1]); + } // writeEntryCached +``` + +這個函數與上面 `CacheTest` 中的 `fourParam` 相似。 因為我們不遵循 ABI 規範,最好不要在函數中聲明任何參數。 + +```solidity + // 讓我們更容易被呼叫 + // writeEntryCached() 的函數簽章,由 + // https://www.4byte.directory/signatures/?bytes4_signature=0xe4e4f2d3 提供 + bytes4 constant public WRITE_ENTRY_CACHED = 0xe4e4f2d3; +``` + +呼叫 `writeEntryCached` 的外部程式碼將需要手動建構 calldata,而不是使用 `worm.writeEntryCached`,因為我們不遵循 ABI 規範。 有這個常數值只是為了讓撰寫更容易。 + +請注意,即使我們將 `WRITE_ENTRY_CACHED` 定義為狀態變數,要從外部讀取它,也必須使用它的 getter 函數,即 `worm.WRITE_ENTRY_CACHED()`。 + +```solidity + function readEntry(uint key) public view + returns (uint _value, address _writtenBy, uint _writtenAtBlock) +``` + +讀取函數是 `view` 函數,所以它不需要交易,也不消耗 Gas。 因此,對參數使用快取沒有任何好處。 對於 view 函數,最好使用更簡單的標準機制。 + +### 測試程式碼 {#the-testing-code} + +[這是合約的測試程式碼](https://github.com/qbzzt/20220915-all-you-can-cache/blob/main/test/WORM.t.sol)。 同樣,我們只看有趣的部分。 + +```solidity + function testWReadWrite() public { + worm.writeEntry(0xDEAD, 0x60A7); + + vm.expectRevert(bytes("entry already written")); + worm.writeEntry(0xDEAD, 0xBEEF); +``` + +[這個 (`vm.expectRevert`)](https://book.getfoundry.sh/cheatcodes/expect-revert#expectrevert) 是我們在 Foundry 測試中指定下一個呼叫應該失敗,以及失敗報告原因的方式。 這適用於我們使用語法 `.()` 而不是建構 calldata 並使用低階介面 (`.call()` 等) 呼叫合約的情況。 + +```solidity + function testReadWriteCached() public { + uint cacheGoat = worm.cacheWrite(0x60A7); +``` + +這裡我們利用 `cacheWrite` 回傳快取鍵的特性。 這不是我們期望在生產環境中使用的,因為 `cacheWrite` 會改變狀態,因此只能在交易中呼叫。 交易沒有回傳值,如果它們有結果,這些結果應該以事件的形式發出。 所以 `cacheWrite` 的回傳值只能從鏈上程式碼存取,而鏈上程式碼不需要參數快取。 + +```solidity + (_success,) = address(worm).call(_callInput); +``` + +這就是我們告訴 Solidity,雖然 `.call()` 有兩個回傳值,但我們只關心第一個。 + +```solidity + (_success,) = address(worm).call(_callInput); + assertEq(_success, false); +``` + +因為我們使用低階的 `
.call()` 函數,所以不能使用 `vm.expectRevert()`,而必須查看從呼叫中得到的布林成功值。 + +```solidity + event EntryWritten(uint indexed key, uint indexed value); + + . + . + . + + _callInput = bytes.concat( + worm.WRITE_ENTRY_CACHED(), worm.encodeVal(a), worm.encodeVal(b)); + vm.expectEmit(true, true, false, false); + emit EntryWritten(a, b); + (_success,) = address(worm).call(_callInput); +``` + +這是在 Foundry 中驗證程式碼 [正確發出事件](https://getfoundry.sh/reference/cheatcodes/expect-emit/) 的方式。 + +### 用戶端 {#the-client} + +用 Solidity 測試得不到的一件事,就是可以複製貼上到您自己應用程式中的 JavaScript 程式碼。 為了撰寫這段程式碼,我將 WORM 部署到了 [Optimism Goerli](https://community.optimism.io/docs/useful-tools/networks/#optimism-goerli),這是 [Optimism](https://www.optimism.io/) 的新測試網。 它的地址是 [`0xd34335b1d818cee54e3323d3246bd31d94e6a78a`](https://goerli-optimism.etherscan.io/address/0xd34335b1d818cee54e3323d3246bd31d94e6a78a)。 + +[您可以在這裡看到用戶端的 JavaScript 程式碼](https://github.com/qbzzt/20220915-all-you-can-cache/blob/main/javascript/index.js)。 如何使用它: + +1. 複製 git 儲存庫: + + ```sh + git clone https://github.com/qbzzt/20220915-all-you-can-cache.git + ``` + +2. 安裝必要的套件: + + ```sh + cd javascript + yarn + ``` + +3. 複製設定檔: + + ```sh + cp .env.example .env + ``` + +4. 編輯 `.env` 以符合您的設定: + + | 參數 | 數值 | + | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | + | MNEMONIC | 一個擁有足夠 ETH 支付交易費用的帳戶的助記詞。 [您可以在這裡免費獲得 Optimism Goerli 網路的 ETH](https://optimismfaucet.xyz/)。 | + | OPTIMISM_GOERLI_URL | Optimism Goerli 的 URL。 公共端點 `https://goerli.optimism.io` 有速率限制,但足以滿足我們在這裡的需求 | + +5. 執行 `index.js`。 + + ```sh + node index.js + ``` + + 這個範例應用程式首先向 WORM 寫入一個項目,顯示 calldata 和 Etherscan 上交易的連結。 然後它會讀回該項目,並顯示它使用的鍵以及項目中的值 (值、區塊號和作者)。 + +用戶端大部分是正常的去中心化應用程式 JavaScript。 所以我們同樣只會看有趣的部分。 + +```javascript +. +. +. +const main = async () => { + const func = await worm.WRITE_ENTRY_CACHED() + + // 每次都需要一個新的鍵 + const key = await worm.encodeVal(Number(new Date())) +``` + +一個給定的時隙只能寫入一次,所以我們使用時間戳來確保我們不會重複使用時隙。 + +```javascript +const val = await worm.encodeVal("0x600D") + +// 寫入一個項目 +const calldata = func + key.slice(2) + val.slice(2) +``` + +Ethers 期望呼叫資料是一個十六進制字串,即 `0x` 後面跟著偶數個十六進制數字。 由於 `key` 和 `val` 都以 `0x` 開頭,我們需要移除這些標頭。 + +```javascript +const tx = await worm.populateTransaction.writeEntryCached() +tx.data = calldata + +sentTx = await wallet.sendTransaction(tx) +``` + +與 Solidity 測試程式碼一樣,我們不能正常呼叫快取函數。 相反,我們需要使用更低階的機制。 + +```javascript + . + . + . + // 讀取剛寫入的項目 + const realKey = '0x' + key.slice(4) // 移除 FF 旗標 + const entryRead = await worm.readEntry(realKey) + . + . + . +``` + +對於讀取項目,我們可以使用正常的機制。 對於 `view` 函數,不需要使用參數快取。 + +## 結論 {#conclusion} + +本文中的程式碼是一個概念驗證,目的是讓這個想法更容易理解。 對於一個生產就緒的系統,您可能需要實現一些額外的功能: + +- 處理非 `uint256` 的值。 例如,字串。 +- 與其使用全域快取,或許可以建立使用者與快取之間的映射。 不同的使用者使用不同的值。 +- 用於地址的值與用於其他目的的值是不同的。 單獨為地址建立一個快取可能是有意義的。 +- 目前,快取鍵採用「先到先得,鍵值最小」的演算法。 前十六個值可以作為單一位元組傳送。 接下來的 4080 個值可以作為兩個位元組傳送。 接下來大約一百萬個值是三個位元組,依此類推。 一個生產系統應該對快取項目保留使用計數器,並重新組織它們,以便十六個_最常用_的值是一個位元組,接下來的 4080 個最常用值是兩個位元組,依此類推。 + + 然而,這是一個潛在危險的操作。 想像以下事件序列: + + 1. 天真的諾姆 (Noam Naive) 呼叫 `encodeVal` 來編碼他想傳送代幣的地址。 該地址是應用程式上最早使用的地址之一,所以編碼後的值是 0x06。 這是一個 `view` 函數,不是一個交易,所以它只發生在諾姆和他使用的節點之間,沒有其他人知道。 + + 2. 擁有者歐文 (Owen Owner) 執行快取重新排序操作。 很少有人真正使用那個地址,所以它現在被編碼為 0x201122。 一個不同的值,1018,被指派為 0x06。 + + 3. 天真的諾姆將他的代幣傳送到 0x06。 它們被送到地址 `0x0000000000000000000000000de0b6b3a7640000`,而且由於沒有人知道該地址的私密金鑰,它們就卡在那裡了。 諾姆_非常不開心_。 + + 有辦法解決這個問題,以及在快取重新排序期間交易在記憶體池中的相關問題,但您必須意識到這一點。 + +我在這裡用 Optimism 來示範快取,因為我是 Optimism 的員工,這是我最了解的 rollup。 但它應該適用於任何對內部處理收取最低成本的 rollup,這樣相比之下,將交易資料寫入 L1 就成了主要開銷。 + +[在此查看我的更多作品](https://cryptodocguy.pro/)。 + diff --git a/public/content/translations/zh-tw/developers/tutorials/app-plasma/index.md b/public/content/translations/zh-tw/developers/tutorials/app-plasma/index.md new file mode 100644 index 00000000000..6463ea6fdda --- /dev/null +++ b/public/content/translations/zh-tw/developers/tutorials/app-plasma/index.md @@ -0,0 +1,1255 @@ +--- +title: "編寫一個保護隱私的特定應用程式 plasma" +description: "在本使用教學中,我們將為存款建立一個半祕密的銀行。 此銀行為中心化元件;它知道每位使用者的餘額。 然而,此資訊不會儲存在鏈上。 銀行會改為張貼狀態的雜湊值。 每當交易發生時,銀行就會張貼新的雜湊值,以及證明其擁有將雜湊狀態變更為新狀態的簽署交易之零知識證明。 閱讀本使用教學後,您不僅將瞭解如何使用零知識證明,還會瞭解為何要使用以及如何安全地使用。" +author: Ori Pomerantz +tags: [ "零知識", "伺服器", "鏈下", "隱私" ] +skill: advanced +lang: zh-tw +published: 2025-10-15 +--- + +## 介紹 {#introduction} + +與 [rollups](/developers/docs/scaling/zk-rollups/) 相反,[plasma](/developers/docs/scaling/plasma) 使用以太坊主網來確保完整性,而非可用性。 在本文中,我們將編寫一個行為類似 plasma 的應用程式,由以太坊保證完整性 (無未經授權的變更),但不保證可用性 (中心化元件可能故障並停用整個系統)。 + +我們在此處編寫的應用程式是保留隱私權的銀行。 不同的地址擁有含餘額的帳戶,且可將資金 (ETH) 傳送至其他帳戶。 銀行會張貼狀態 (帳戶及其餘額) 和交易的雜湊值,但會將實際餘額保留在鏈下,以維持其隱私。 + +## 設計 {#design} + +這不是可供生產的系統,而是教學工具。 因此,它是基於幾個簡化的假設編寫的。 + +- 固定的帳戶池。 帳戶有特定數量,且每個帳戶都屬於預先決定的地址。 這使得系統更加簡單,因為在零知識證明中處理可變大小的資料結構很困難。 對於可供生產的系統,我們可以使用 [Merkle 根](/developers/tutorials/merkle-proofs-for-offline-data-integrity/) 作為狀態雜湊值,並為必要的餘額提供 Merkle 證明。 + +- 記憶體儲存。 在生產系統上,我們需要將所有帳戶餘額寫入磁碟,以在重新啟動時保留它們。 在此,即使資訊遺失也無妨。 + +- 僅限傳送。 生產系統需要一種將資產存入銀行並提款的方式。 但這裡的目的只是為了說明概念,所以此銀行僅限於傳送。 + +### 零知識證明 {#zero-knowledge-proofs} + +在基礎層面上,零知識證明顯示證明者知道一些資料 _Dataprivate_,使得一些公開資料 _Datapublic_ 和 _Dataprivate_ 之間存在關係 _Relationship_。 驗證者知道 _Relationship_ 和 _Datapublic_。 + +為了保護隱私,我們需要將狀態和交易設為私密。 但為了確保完整性,我們需要將狀態的 [密碼學雜湊值](https://en.wikipedia.org/wiki/Cryptographic_hash_function) 設為公開。 為了向提交交易的人證明這些交易確實發生了,我們還需要張貼交易雜湊值。 + +在大多數情況下,_Dataprivate_ 是零知識證明程式的輸入,而 _Datapublic_ 是輸出。 + +_Dataprivate_ 中的這些欄位: + +- _Staten_,舊的狀態 +- _Staten+1_,新的狀態 +- _Transaction_,將舊狀態變更為新狀態的交易。 此交易需要包含以下欄位: + - _目的地地址_,接收傳送的地址 + - 正在傳送的 _金額_ + - _Nonce_,確保每個交易只能處理一次。 + 來源地址不需要在交易中,因為它可以從簽章中恢復。 +- _簽章_,一個經授權執行交易的簽章。 在我們的案例中,唯一被授權執行交易的地址是來源地址。 由於我們的零知識系統的運作方式,除了以太坊簽章外,我們還需要帳戶的公鑰。 + +_Datapublic_ 中的這些欄位: + +- _Hash(Staten)_,舊狀態的雜湊值 +- _Hash(Staten+1)_,新狀態的雜湊值 +- _Hash(Transaction)_,將狀態從 _Staten_ 變更為 _Staten+1_ 的交易雜湊值。 + +此關係會檢查幾個條件: + +- 公開的雜湊值確實是私密欄位的正確雜湊值。 +- 交易應用於舊狀態時,會產生新狀態。 +- 簽章來自交易的來源地址。 + +由於密碼學雜湊函數的特性,證明這些條件就足以確保完整性。 + +### 數據結構 {#data-structures} + +主要資料結構是伺服器持有的狀態。 對於每個帳戶,伺服器都會追蹤帳戶餘額和一個 [nonce](https://en.wikipedia.org/wiki/Cryptographic_nonce),用於防止 [重放攻擊](https://en.wikipedia.org/wiki/Replay_attack)。 + +### 元件 {#components} + +此系統需要兩個元件: + +- _伺服器_,接收交易、處理交易,並將雜湊值與零知識證明一起發布到鏈上。 +- 一個 _智能合約_,儲存雜湊值並驗證零知識證明,以確保狀態轉換是合法的。 + +### 資料和控制流 {#flows} + +這些是各種元件之間溝通,以將資金從一個帳戶傳送到另一個帳戶的方式。 + +1. 網頁瀏覽器提交一份簽署的交易,要求從簽署者的帳戶傳送到另一個不同的帳戶。 + +2. 伺服器驗證該交易是否有效: + + - 簽署者在銀行中有一個餘額充足的帳戶。 + - 收款人在銀行中有一個帳戶。 + +3. 伺服器透過從簽署者的餘額中減去傳送的金額,並將其加到收款人的餘額中,來計算新的狀態。 + +4. 伺服器計算一個零知識證明,證明狀態變更是有效的。 + +5. 伺服器向以太坊提交一筆包含以下內容的交易: + + - 新狀態的雜湊值 + - 交易雜湊值 (以便交易發送者可以知道交易已處理) + - 證明轉換到新狀態是有效的零知識證明 + +6. 智能合約驗證零知識證明。 + +7. 如果零知識證明檢查通過,智能合約將執行以下操作: + - 將當前狀態雜湊值更新為新狀態雜湊值 + - 發出一個包含新狀態雜湊值和交易雜湊值的日誌項目 + +### 工具 {#tools} + +對於用戶端程式碼,我們將使用 [Vite](https://vite.dev/)、[React](https://react.dev/)、[Viem](https://viem.sh/) 和 [Wagmi](https://wagmi.sh/)。 這些是業界標準的工具;如果您不熟悉,可以使用[此教學](/developers/tutorials/creating-a-wagmi-ui-for-your-contract/)。 + +伺服器的主要部分是使用 [Node](https://nodejs.org/en) 以 JavaScript 編寫的。 零知識部分是用 [Noir](https://noir-lang.org/) 編寫的。 我們需要 `1.0.0-beta.10` 版本,因此在您 [按照指示安裝 Noir](https://noir-lang.org/docs/getting_started/quick_start) 後,請執行: + +``` +noirup -v 1.0.0-beta.10 +``` + +我們使用的區塊鏈是 `anvil`,一個本地測試區塊鏈,是 [Foundry](https://getfoundry.sh/introduction/installation) 的一部分。 + +## 實作 {#implementation} + +由於這是一個複雜的系統,我們將分階段實作。 + +### 第 1 階段 - 手動零知識 {#stage-1} + +在第一階段,我們將在瀏覽器中簽署一筆交易,然後手動提供資訊給零知識證明。 零知識程式碼預期會在 `server/noir/Prover.toml` 中取得該資訊 (文件記錄於 [此處](https://noir-lang.org/docs/getting_started/project_breakdown#provertoml-1))。 + +實際操作如下: + +1. 請確保您已安裝 [Node](https://nodejs.org/en/download) 和 [Noir](https://noir-lang.org/install)。 最好在 UNIX 系統上安裝它們,例如 macOS、Linux 或 [WSL](https://learn.microsoft.com/en-us/windows/wsl/install)。 + +2. 下載第 1 階段的程式碼並啟動網頁伺服器以提供用戶端程式碼。 + + ```sh + git clone https://github.com/qbzzt/250911-zk-bank.git -b 01-manual-zk + cd 250911-zk-bank + cd client + npm install + npm run dev + ``` + + 您需要網頁伺服器的原因是,為了防止某些類型的詐騙,許多錢包 (例如 MetaMask) 不接受直接從磁碟提供的檔案。 + +3. 打開帶有錢包的瀏覽器。 + +4. 在錢包中,輸入新的密碼。 請注意,這將刪除您現有的密碼,所以_請確保您有備份_。 + + 密碼是 `test test test test test test test test test test test junk`,這是 anvil 的預設測試密碼。 + +5. 瀏覽至 [用戶端程式碼](http://localhost:5173/)。 + +6. 連接到錢包並選擇您的目標帳戶和金額。 + +7. 按一下 **Sign** 並簽署交易。 + +8. 在 **Prover.toml** 標題下,您會找到文字。 將 `server/noir/Prover.toml` 替換為該文字。 + +9. 執行零知識證明。 + + ```sh + cd ../server/noir + nargo execute + ``` + + 輸出應類似於 + + ``` + ori@CryptoDocGuy:~/noir/250911-zk-bank/server/noir$ nargo execute + + [zkBank] Circuit witness successfully solved + [zkBank] Witness saved to target/zkBank.gz + [zkBank] Circuit output: (0x199aa62af8c1d562a6ec96e66347bf3240ab2afb5d022c895e6bf6a5e617167b, 0x0cfc0a67cb7308e4e9b254026b54204e34f6c8b041be207e64c5db77d95dd82d, 0x450cf9da6e180d6159290554ae3d8787, 0x6d8bc5a15b9037e52fb59b6b98722a85) + ``` + +10. 將最後兩個值與您在網頁瀏覽器上看到的雜湊值進行比較,以查看訊息是否已正確雜湊。 + +#### `server/noir/Prover.toml` {#server-noir-prover-toml} + +[此檔案](https://github.com/qbzzt/250911-zk-bank/blob/01-manual-zk/server/noir/Prover.toml) 顯示 Noir 預期的資訊格式。 + +```toml +message="send 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 500 finney (milliEth) 0 " +``` + +此訊息採用文字格式,方便使用者理解 (這在簽署時是必要的),也方便 Noir 程式碼解析。 金額以 finney 報價,一方面可以進行部分傳送,另一方面也易於閱讀。 最後一個數字是 [nonce](https://en.wikipedia.org/wiki/Cryptographic_nonce)。 + +該字串長度為 100 個字元。 零知識證明不善於處理可變大小的資料,因此通常需要填充資料。 + +```toml +pubKeyX=["0x83",...,"0x75"] +pubKeyY=["0x35",...,"0xa5"] +signature=["0xb1",...,"0x0d"] +``` + +這三個參數是固定大小的位元組陣列。 + +```toml +[[accounts]] +address="0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" +balance=100_000 +nonce=0 + +[[accounts]] +address="0x70997970C51812dc3A010C7d01b50e0d17dc79C8" +balance=100_000 +nonce=0 +``` + +這是指定結構陣列的方式。 對於每個項目,我們指定地址、餘額 (以 milliETH,又稱為 [finney](https://cryptovalleyjournal.com/glossary/finney/)),以及下一個 nonce 值。 + +#### `client/src/Transfer.tsx` {#client-src-transfer-tsx} + +[此檔案](https://github.com/qbzzt/250911-zk-bank/blob/01-manual-zk/client/src/Transfer.tsx) 會實作用戶端的處理,並產生 `server/noir/Prover.toml` 檔案 (包含零知識參數的檔案)。 + +以下是較有趣部分的說明。 + +```tsx +export default attrs => { +``` + +此函式會建立 `Transfer` React 元件,其他檔案可以匯入此元件。 + +```tsx + const accounts = [ + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", + "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC", + "0x90F79bf6EB2c4f870365E785982E1f101E93b906", + "0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65", + ] +``` + +這些是帳戶地址,也就是 `test ...` 建立的地址。 test junk` 密碼。 如果您想使用自己的地址,只需修改此定義即可。 + +```tsx + const account = useAccount() + const wallet = createWalletClient({ + transport: custom(window.ethereum!) + }) +``` + +這些 [Wagmi hooks](https://wagmi.sh/react/api/hooks) 讓我們能夠存取 [viem](https://viem.sh/) 庫和錢包。 + +```tsx + const message = `send ${toAccount} ${ethAmount*1000} finney (milliEth) ${nonce}`.padEnd(100, " ") +``` + +這是以空格填補的訊息。 每當 [`useState`](https://react.dev/reference/react/useState) 變數變更時,元件就會重新繪製,而 `message` 也會更新。 + +```tsx + const sign = async () => { +``` + +此函式會在使用者按一下 **Sign** 按鈕時呼叫。 訊息會自動更新,但簽章需要使用者在錢包中核准,除非必要,否則我們不想要求核准。 + +```tsx + const signature = await wallet.signMessage({ + account: fromAccount, + message, + }) +``` + +要求錢包 [簽署訊息](https://viem.sh/docs/accounts/local/signMessage)。 + +```tsx + const hash = hashMessage(message) +``` + +取得訊息雜湊值。 提供給使用者以供偵錯 (Noir 程式碼) 會很有幫助。 + +```tsx + const pubKey = await recoverPublicKey({ + hash, + signature + }) +``` + +[取得公鑰](https://viem.sh/docs/utilities/recoverPublicKey)。 這是 [Noir `ecrecover`](https://github.com/colinnielsen/ecrecover-noir) 函式所需的。 + +```tsx + setSignature(signature) + setHash(hash) + setPubKey(pubKey) +``` + +設定狀態變數。 這樣做會在 `sign` 函式結束後重新繪製元件,並向使用者顯示更新後的值。 + +```tsx + let proverToml = `" +``` + +`Prover.toml` 的文字。 + +```tsx +message="${message}" + +pubKeyX=${hexToArray(pubKey.slice(4,4+2*32))} +pubKeyY=${hexToArray(pubKey.slice(4+2*32))} +``` + +Viem 提供我們一個 65 位元組的十六進位字串作為公鑰。 第一個位元組是 `0x04`,一個版本標記。 接下來是 32 位元組的公鑰 `x`,然後是 32 位元組的公鑰 `y`。 + +然而,Noir 預期會以兩個位元組陣列的形式取得此資訊,一個用於 `x`,一個用於 `y`。 在用戶端解析比在零知識證明中解析更容易。 + +請注意,這通常是零知識中的良好作法。 零知識證明中的程式碼成本很高,因此任何可以在零知識證明之外完成的處理都_應該_在零知識證明之外完成。 + +```tsx +signature=${hexToArray(signature.slice(2,-2))} +``` + +簽章也以 65 位元組的十六進位字串提供。 然而,最後一個位元組僅用於恢復公鑰。 由於公鑰已經提供給 Noir 程式碼,我們不需要它來驗證簽章,Noir 程式碼也不需要它。 + +```tsx +${accounts.map(accountInProverToml).reduce((a,b) => a+b, "")} +` +``` + +提供帳戶。 + +```tsx + setProverToml(proverToml) + } + + return ( + <> +

Transfer

+``` + +這是元件的 HTML (更準確地說,是 [JSX](https://react.dev/learn/writing-markup-with-jsx)) 格式。 + +#### `server/noir/src/main.nr` {#server-noir-src-main-nr} + +[此檔案](https://github.com/qbzzt/250911-zk-bank/blob/01-manual-zk/server/noir/src/main.nr) 是實際的零知識程式碼。 + +``` +use std::hash::pedersen_hash; +``` + +[Pedersen 雜湊](https://rya-sge.github.io/access-denied/2024/05/07/pedersen-hash-function/) 由 [Noir 標準庫](https://noir-lang.org/docs/noir/standard_library/cryptographic_primitives/hashes#pedersen_hash) 提供。 零知識證明通常使用此雜湊函數。 與標準雜湊函數相比,在 [算術電路](https://rareskills.io/post/arithmetic-circuit) 內計算要容易得多。 + +``` +use keccak256::keccak256; +use dep::ecrecover; +``` + +這兩個函式是外部庫,定義在 [`Nargo.toml`](https://github.com/qbzzt/250911-zk-bank/blob/01-manual-zk/server/noir/Nargo.toml) 中。 它們的名稱恰如其分,一個是計算 [keccak256 雜湊](https://emn178.github.io/online-tools/keccak_256.html) 的函式,另一個是驗證以太坊簽章並恢復簽署者的以太坊地址的函式。 + +``` +global ACCOUNT_NUMBER : u32 = 5; +``` + +Noir 的靈感來自 [Rust](https://www.rust-lang.org/)。 變數預設是常數。 這是我們定義全域組態常數的方式。 具體來說,`ACCOUNT_NUMBER` 是我們儲存的帳戶數量。 + +名為 `u` 的資料類型是該位元數的無符號整數。 唯一支援的類型是 `u8`、`u16`、`u32`、`u64` 和 `u128`。 + +``` +global FLAT_ACCOUNT_FIELDS : u32 = 2; +``` + +此變數用於帳戶的 Pedersen 雜湊,如下所述。 + +``` +global MESSAGE_LENGTH : u32 = 100; +``` + +如上所述,訊息長度是固定的。 在此處指定。 + +``` +global ASCII_MESSAGE_LENGTH : [u8; 3] = [0x31, 0x30, 0x30]; +global HASH_BUFFER_SIZE : u32 = 26+3+MESSAGE_LENGTH; +``` + +[EIP-191 簽章](https://eips.ethereum.org/EIPS/eip-191) 需要一個緩衝區,其中包含 26 位元組的前綴,後接 ASCII 格式的訊息長度,最後是訊息本身。 + +``` +struct Account { + balance: u128, + address: Field, + nonce: u32, +} +``` + +我們儲存的帳戶資訊。 [`Field`](https://noir-lang.org/docs/noir/concepts/data_types/fields) 是一個數字,通常最多 253 位元,可直接用於實作零知識證明的 [算術電路](https://rareskills.io/post/arithmetic-circuit)。 在此,我們使用 `Field` 來儲存 160 位元的以太坊地址。 + +``` +struct TransferTxn { + from: Field, + to: Field, + amount: u128, + nonce: u32 +} +``` + +我們儲存的傳送交易資訊。 + +``` +fn flatten_account(account: Account) -> [Field; FLAT_ACCOUNT_FIELDS] { +``` + +函式定義。 參數是 `Account` 資訊。 結果是一個 `Field` 變數陣列,長度為 `FLAT_ACCOUNT_FIELDS` + +``` + let flat = [ + account.address, + ((account.balance << 32) + account.nonce.into()).into(), + ]; +``` + +陣列中的第一個值是帳戶地址。 第二個值包括餘額和 nonce。 `.into()` 呼叫會將數字變更為其所需的資料類型。 `account.nonce` 是一個 `u32` 值,但若要將其新增至 `account.balance « 32` (一個 `u128` 值),它需要是 `u128`。 這是第一個 `.into()`。 第二個 `.into()` 將 `u128` 結果轉換為 `Field`,使其符合陣列。 + +``` + flat +} +``` + +在 Noir 中,函式只能在結尾傳回一個值 (沒有提早傳回)。 若要指定傳回值,您只需在函式的右括號前評估它即可。 + +``` +fn flatten_accounts(accounts: [Account; ACCOUNT_NUMBER]) -> [Field; FLAT_ACCOUNT_FIELDS*ACCOUNT_NUMBER] { +``` + +此函式將帳戶陣列轉換為 `Field` 陣列,可作為 Petersen 雜湊的輸入。 + +``` + let mut flat: [Field; FLAT_ACCOUNT_FIELDS*ACCOUNT_NUMBER] = [0; FLAT_ACCOUNT_FIELDS*ACCOUNT_NUMBER]; +``` + +這是指定可變變數的方式,也就是_不是_常數。 Noir 中的變數必須始終有值,因此我們將此變數初始化為全零。 + +``` + for i in 0..ACCOUNT_NUMBER { +``` + +這是 `for` 迴圈。 請注意,邊界是常數。 Noir 迴圈的邊界必須在編譯時已知。 原因是算術電路不支援流程控制。 在處理 `for` 迴圈時,編譯器會簡單地將其中的程式碼多次放置,每次迭代一次。 + +``` + let fields = flatten_account(accounts[i]); + for j in 0..FLAT_ACCOUNT_FIELDS { + flat[i*FLAT_ACCOUNT_FIELDS + j] = fields[j]; + } + } + + flat +} + +fn hash_accounts(accounts: [Account; ACCOUNT_NUMBER]) -> Field { + pedersen_hash(flatten_accounts(accounts)) +} +``` + +最後,我們來到雜湊帳戶陣列的函式。 + +``` +fn find_account(accounts: [Account; ACCOUNT_NUMBER], address: Field) -> u32 { + let mut account : u32 = ACCOUNT_NUMBER; + + for i in 0..ACCOUNT_NUMBER { + if accounts[i].address == address { + account = i; + } + } +``` + +此函式會尋找具有特定地址的帳戶。 此函式在標準程式碼中效率極低,因為它會迭代所有帳戶,即使在找到地址後也是如此。 + +然而,在零知識證明中,沒有流程控制。 如果我們需要檢查條件,我們必須每次都檢查它。 + +`if` 陳述式也會發生類似的情況。 上述迴圈中的 `if` 陳述式會轉換為這些數學陳述式。 + +_conditionresult = accounts[i].address == address_ // 如果相等則為 1,否則為 0 + +_accountnew = conditionresult\*i + (1-conditionresult)\*accountold_ + +```rust + assert (account < ACCOUNT_NUMBER, f"{address} does not have an account"); + + account +} +``` + +如果斷言為假,[`assert`](https://noir-lang.org/docs/dev/noir/concepts/assert) 函式會導致零知識證明崩潰。 在這種情況下,如果我們找不到具有相關地址的帳戶。 若要報告地址,我們使用 [格式字串](https://noir-lang.org/docs/noir/concepts/data_types/strings#format-strings)。 + +```rust +fn apply_transfer_txn(accounts: [Account; ACCOUNT_NUMBER], txn: TransferTxn) -> [Account; ACCOUNT_NUMBER] { +``` + +此函式會套用一筆傳送交易,並傳回新的帳戶陣列。 + +```rust + let from = find_account(accounts, txn.from); + let to = find_account(accounts, txn.to); + + let (txnFrom, txnAmount, txnNonce, accountNonce) = + (txn.from, txn.amount, txn.nonce, accounts[from].nonce); +``` + +我們無法在 Noir 的格式字串內存取結構元素,因此我們建立了一個可用的副本。 + +```rust + assert (accounts[from].balance >= txn.amount, + f"{txnFrom} 沒有 {txnAmount} finney"); + + assert (accounts[from].nonce == txn.nonce, + f"交易的 nonce 為 {txnNonce},但帳戶應使用 {accountNonce}"); +``` + +這是兩個可能使交易無效的條件。 + +```rust + let mut newAccounts = accounts; + + newAccounts[from].balance -= txn.amount; + newAccounts[from].nonce += 1; + newAccounts[to].balance += txn.amount; + + newAccounts +} +``` + +建立新的帳戶陣列,然後傳回它。 + +```rust +fn readAddress(messageBytes: [u8; MESSAGE_LENGTH]) -> Field +``` + +此函式從訊息中讀取地址。 + +```rust +{ + let mut result : Field = 0; + + for i in 7..47 { +``` + +地址總是 20 位元組 (又稱為 40 個十六進位數字) 長,並從字元 #7 開始。 + +```rust + result *= 0x10; + if messageBytes[i] >= 48 & messageBytes[i] <= 57 { // 0-9 + result += (messageBytes[i]-48).into(); + } + if messageBytes[i] >= 65 & messageBytes[i] <= 70 { // A-F + result += (messageBytes[i]-65+10).into() + } + if messageBytes[i] >= 97 & messageBytes[i] <= 102 { // a-f + result += (messageBytes[i]-97+10).into() + } + } + + result +} + +fn readAmountAndNonce(messageBytes: [u8; MESSAGE_LENGTH]) -> (u128, u32) +``` + +從訊息中讀取金額和 nonce。 + +```rust +{ + let mut amount : u128 = 0; + let mut nonce: u32 = 0; + let mut stillReadingAmount: bool = true; + let mut lookingForNonce: bool = false; + let mut stillReadingNonce: bool = false; +``` + +在訊息中,地址後的第一個數字是要傳送的 finney (又稱為 千分之一 ETH) 金額。 第二個數字是 nonce。 兩者之間的任何文字都會被忽略。 + +```rust + for i in 48..MESSAGE_LENGTH { + if messageBytes[i] >= 48 & messageBytes[i] <= 57 { // 0-9 + let digit = (messageBytes[i]-48); + + if stillReadingAmount { + amount = amount*10 + digit.into(); + } + + if lookingForNonce { // We just found it + stillReadingNonce = true; + lookingForNonce = false; + } + + if stillReadingNonce { + nonce = nonce*10 + digit.into(); + } + } else { + if stillReadingAmount { + stillReadingAmount = false; + lookingForNonce = true; + } + if stillReadingNonce { + stillReadingNonce = false; + } + } + } + + (amount, nonce) +} +``` + +傳回 [元組](https://noir-lang.org/docs/noir/concepts/data_types/tuples) 是 Noir 從函式傳回多個值的方式。 + +```rust +fn readTransferTxn(message: str) -> TransferTxn +{ + let mut txn: TransferTxn = TransferTxn { from: 0, to: 0, amount:0, nonce:0 }; + let messageBytes = message.as_bytes(); + + txn.to = readAddress(messageBytes); + let (amount, nonce) = readAmountAndNonce(messageBytes); + txn.amount = amount; + txn.nonce = nonce; + + txn +} +``` + +此函式將訊息轉換為位元組,然後將金額轉換為 `TransferTxn`。 + +```rust +// The equivalent to Viem's hashMessage +// https://viem.sh/docs/utilities/hashMessage#hashmessage +fn hashMessage(message: str) -> [u8;32] { +``` + +我們能夠對帳戶使用 Pedersen 雜湊,因為它們只在零知識證明內雜湊。 然而,在此程式碼中,我們需要檢查訊息的簽章,這是由瀏覽器產生的。 為此,我們需要遵循 [EIP 191](https://eips.ethereum.org/EIPS/eip-191) 中的以太坊簽署格式。 這表示我們需要建立一個組合緩衝區,其中包含標準前綴、ASCII 格式的訊息長度以及訊息本身,並使用以太坊標準 keccak256 進行雜湊。 + +```rust + // ASCII prefix + let prefix_bytes = [ + 0x19, // \x19 + 0x45, // 'E' + 0x74, // 't' + 0x68, // 'h' + 0x65, // 'e' + 0x72, // 'r' + 0x65, // 'e' + 0x75, // 'u' + 0x6D, // 'm' + 0x20, // ' ' + 0x53, // 'S' + 0x69, // 'i' + 0x67, // 'g' + 0x6E, // 'n' + 0x65, // 'e' + 0x64, // 'd' + 0x20, // ' ' + 0x4D, // 'M' + 0x65, // 'e' + 0x73, // 's' + 0x73, // 's' + 0x61, // 'a' + 0x67, // 'g' + 0x65, // 'e' + 0x3A, // ':' + 0x0A // '\n' + ]; +``` + +為避免應用程式要求使用者簽署可用作交易或其他用途的訊息,EIP 191 指定所有簽署的訊息都以字元 0x19 (非有效 ASCII 字元) 開頭,後接 `Ethereum Signed Message:` 和換行符。 + +```rust + let mut buffer: [u8; HASH_BUFFER_SIZE] = [0u8; HASH_BUFFER_SIZE]; + for i in 0..26 { + buffer[i] = prefix_bytes[i]; + } + + let messageBytes : [u8; MESSAGE_LENGTH] = message.as_bytes(); + + if MESSAGE_LENGTH <= 9 { + for i in 0..1 { + buffer[i+26] = ASCII_MESSAGE_LENGTH[i]; + } + + for i in 0..MESSAGE_LENGTH { + buffer[i+26+1] = messageBytes[i]; + } + } + + if MESSAGE_LENGTH >= 10 & MESSAGE_LENGTH <= 99 { + for i in 0..2 { + buffer[i+26] = ASCII_MESSAGE_LENGTH[i]; + } + + for i in 0..MESSAGE_LENGTH { + buffer[i+26+2] = messageBytes[i]; + } + } + + if MESSAGE_LENGTH >= 100 { + for i in 0..3 { + buffer[i+26] = ASCII_MESSAGE_LENGTH[i]; + } + + for i in 0..MESSAGE_LENGTH { + buffer[i+26+3] = messageBytes[i]; + } + } + + assert(MESSAGE_LENGTH < 1000, "不支援長度超過三位數的訊息"); +``` + +處理長度達 999 的訊息,如果超過則失敗。 我新增了這段程式碼,即使訊息長度是常數,因為這樣更容易變更。 在生產系統上,為了更好的效能,您可能會假設 `MESSAGE_LENGTH` 不會變更。 + +```rust + keccak256::keccak256(buffer, HASH_BUFFER_SIZE) +} +``` + +使用以太坊標準的 `keccak256` 函式。 + +```rust +fn signatureToAddressAndHash( + message: str, + pubKeyX: [u8; 32], + pubKeyY: [u8; 32], + signature: [u8; 64] + ) -> (Field, Field, Field) // address, first 16 bytes of hash, last 16 bytes of hash +{ +``` + +此函式會驗證簽章,這需要訊息雜湊值。 然後,它會提供我們簽署它的地址和訊息雜湊值。 訊息雜湊值以兩個 `Field` 值提供,因為它們比位元組陣列在程式的其餘部分更容易使用。 + +我們需要使用兩個 `Field` 值,因為欄位計算是使用 [模數](https://en.wikipedia.org/wiki/Modulo) 一個大數來完成的,但該數字通常小於 256 位元 (否則在 EVM 中執行這些計算會很困難)。 + +```rust + let hash = hashMessage(message); + + let mut (hash1, hash2) = (0,0); + + for i in 0..16 { + hash1 = hash1*256 + hash[31-i].into(); + hash2 = hash2*256 + hash[15-i].into(); + } +``` + +將 `hash1` 和 `hash2` 指定為可變變數,並逐位元組將雜湊寫入其中。 + +```rust + ( + ecrecover::ecrecover(pubKeyX, pubKeyY, signature, hash), +``` + +這類似於 [Solidity 的 `ecrecover`](https://docs.soliditylang.org/en/v0.8.30/cheatsheet.html#mathematical-and-cryptographic-functions),但有兩個重要的差異: + +- 如果簽章無效,呼叫會失敗一個 `assert`,程式會被中止。 +- 雖然公鑰可以從簽章和雜湊中恢復,但這項處理可以在外部完成,因此不值得在零知識證明內進行。 如果有人在此試圖欺騙我們,簽章驗證將會失敗。 + +```rust + hash1, + hash2 + ) +} + +fn main( + accounts: [Account; ACCOUNT_NUMBER], + message: str, + pubKeyX: [u8; 32], + pubKeyY: [u8; 32], + signature: [u8; 64], + ) -> pub ( + Field, // Hash of old accounts array + Field, // Hash of new accounts array + Field, // First 16 bytes of message hash + Field, // Last 16 bytes of message hash + ) +``` + +最後,我們來到 `main` 函式。 我們需要證明我們有一個交易,該交易有效地將帳戶的雜湊從舊值變更為新值。 我們還需要證明它具有此特定的交易雜湊,以便發送它的人知道他們的交易已處理。 + +```rust +{ + let mut txn = readTransferTxn(message); +``` + +我們需要 `txn` 是可變的,因為我們不是從訊息中讀取 `from` 地址,而是從簽章中讀取。 + +```rust + let (fromAddress, txnHash1, txnHash2) = signatureToAddressAndHash( + message, + pubKeyX, + pubKeyY, + signature); + + txn.from = fromAddress; + + let newAccounts = apply_transfer_txn(accounts, txn); + + ( + hash_accounts(accounts), + hash_accounts(newAccounts), + txnHash1, + txnHash2 + ) +} +``` + +### 第 2 階段 - 新增伺服器 {#stage-2} + +在第二階段,我們新增一個伺服器,接收並實作來自瀏覽器的傳送交易。 + +實際操作如下: + +1. 如果 Vite 正在執行,請停止它。 + +2. 下載包含伺服器的分支,並確保您擁有所有必要的模組。 + + ```sh + git checkout 02-add-server + cd client + npm install + cd ../server + npm install + ``` + + 無需編譯 Noir 程式碼,它與您用於第 1 階段的程式碼相同。 + +3. 啟動伺服器。 + + ```sh + npm run start + ``` + +4. 在個別的命令列視窗中,執行 Vite 以提供瀏覽器程式碼。 + + ```sh + cd client + npm run dev + ``` + +5. 瀏覽至 [http://localhost:5173](http://localhost:5173) 的用戶端程式碼 + +6. 在發出交易之前,您需要知道 nonce 以及可以傳送的金額。 若要取得此資訊,請按一下 **Update account data** 並簽署訊息。 + + 我們在此遇到一個兩難的局面。 一方面,我們不希望簽署可重複使用的訊息 ([重放攻擊](https://en.wikipedia.org/wiki/Replay_attack)),這就是我們一開始需要 nonce 的原因。 然而,我們還沒有 nonce。 解決方案是選擇一個只能使用一次且雙方都已有的 nonce,例如目前時間。 + + 此解決方案的問題是時間可能無法完全同步。 因此,我們改為簽署一個每分鐘變更一次的值。 這表示我們遭受重放攻擊的漏洞窗口最多為一分鐘。 考量到在生產環境中,已簽署的請求將受到 TLS 保護,而且通道的另一端—伺服器—已經可以揭露餘額和 nonce (它必須知道這些才能運作),這是一個可接受的風險。 + +7. 瀏覽器取回餘額和 nonce 後,會顯示傳送表單。 選擇目的地地址和金額,然後按一下 **Transfer**。 簽署此請求。 + +8. 若要查看傳送,請 **更新帳戶資料** 或查看您執行伺服器的視窗。 伺服器每次變更狀態時都會記錄狀態。 + + ``` + ori@CryptoDocGuy:~/x/250911-zk-bank/server$ npm run start + + > server@1.0.0 start + > node --experimental-json-modules index.mjs + + Listening on port 3000 + Txn send 0x90F79bf6EB2c4f870365E785982E1f101E93b906 36000 finney (milliEth) 0 processed + New state: + 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 has 64000 (1) + 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 has 100000 (0) + 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC has 100000 (0) + 0x90F79bf6EB2c4f870365E785982E1f101E93b906 has 136000 (0) + 0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65 has 100000 (0) + Txn send 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 7200 finney (milliEth) 1 processed + New state: + 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 has 56800 (2) + 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 has 107200 (0) + 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC has 100000 (0) + 0x90F79bf6EB2c4f870365E785982E1f101E93b906 has 136000 (0) + 0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65 has 100000 (0) + Txn send 0x90F79bf6EB2c4f870365E785982E1f101E93b906 3000 finney (milliEth) 2 processed + New state: + 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 has 53800 (3) + 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 has 107200 (0) + 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC has 100000 (0) + 0x90F79bf6EB2c4f870365E785982E1f101E93b906 has 139000 (0) + 0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65 has 100000 (0) + ``` + +#### `server/index.mjs` {#server-index-mjs-1} + +[此檔案](https://github.com/qbzzt/250911-zk-bank/blob/02-add-server/server/index.mjs) 包含伺服器程序,並與 [`main.nr`](https://github.com/qbzzt/250911-zk-bank/blob/02-add-server/server/noir/src/main.nr) 的 Noir 程式碼互動。 以下是有趣部分的說明。 + +```js +import { Noir } from '@noir-lang/noir_js' +``` + +[noir.js](https://www.npmjs.com/package/@noir-lang/noir_js) 庫在 JavaScript 程式碼和 Noir 程式碼之間提供介面。 + +```js +const circuit = JSON.parse(await fs.readFile("./noir/target/zkBank.json")) +const noir = new Noir(circuit) +``` + +載入算術電路—我們在上一階段建立的已編譯 Noir 程式—並準備執行它。 + +```js +// We only provide account information in return to a signed request +const accountInformation = async signature => { + const fromAddress = await recoverAddress({ + hash: hashMessage("Get account data " + Math.floor((new Date().getTime())/60000)), + signature + }) +``` + +若要提供帳戶資訊,我們只需要簽章。 原因是我們已經知道訊息會是什麼,因此也知道訊息雜湊值。 + +```js +const processMessage = async (message, signature) => { +``` + +處理訊息並執行其編碼的交易。 + +```js + // Get the public key + const pubKey = await recoverPublicKey({ + hash, + signature + }) +``` + +現在我們在伺服器上執行 JavaScript,我們可以在那裡而不是在用戶端上擷取公鑰。 + +```js + let noirResult + try { + noirResult = await noir.execute({ + message, + signature: signature.slice(2,-2).match(/.{2}/g).map(x => `0x${x}`), + pubKeyX, + pubKeyY, + accounts: Accounts + }) +``` + +`noir.execute` 會執行 Noir 程式。 參數相當於 [`Prover.toml`](https://github.com/qbzzt/250911-zk-bank/blob/01-manual-zk/server/noir/Prover.toml) 中提供的參數。 請注意,長值是作為十六進位字串陣列 (`["0x60", "0xA7"]`) 提供的,而不是像 Viem 那樣作為單一十六進位值 (`0x60A7`)。 + +```js + } catch (err) { + console.log(`Noir 錯誤:${err}`) + throw Error("交易無效,未處理") + } +``` + +如果有錯誤,請將其攔截,然後將簡化版本轉送給用戶端。 + +```js + Accounts[fromAccountNumber].nonce++ + Accounts[fromAccountNumber].balance -= amount + Accounts[toAccountNumber].balance += amount +``` + +套用交易。 我們已經在 Noir 程式碼中完成了,但在這裡再做一次比從那裡擷取結果更容易。 + +```js +let Accounts = [ + { + address: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + balance: 5000, + nonce: 0, + }, +``` + +初始 `Accounts` 結構。 + +### 第 3 階段 - 以太坊智能合約 {#stage-3} + +1. 停止伺服器和用戶端程序。 + +2. 下載包含智能合約的分支,並確保您擁有所有必要的模組。 + + ```sh + git checkout 03-smart-contracts + cd client + npm install + cd ../server + npm install + ``` + +3. 在個別的命令列視窗中執行 `anvil`。 + +4. 產生驗證金鑰和 solidity 驗證器,然後將驗證器程式碼複製到 Solidity 專案。 + + ```sh + cd noir + bb write_vk -b ./target/zkBank.json -o ./target --oracle_hash keccak + bb write_solidity_verifier -k ./target/vk -o ./target/Verifier.sol + cp target/Verifier.sol ../../smart-contracts/src + ``` + +5. 前往智能合約並設定環境變數以使用 `anvil` 區塊鏈。 + + ```sh + cd ../../smart-contracts + export ETH_RPC_URL=http://localhost:8545 + ETH_PRIVATE_KEY=ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 + ``` + +6. 部署 `Verifier.sol` 並將地址儲存在環境變數中。 + + ```sh + VERIFIER_ADDRESS=`forge create src/Verifier.sol:HonkVerifier --private-key $ETH_PRIVATE_KEY --optimize --broadcast | awk '/Deployed to:/ {print $3}'` + echo $VERIFIER_ADDRESS + ``` + +7. 部署 `ZkBank` 合約。 + + ```sh + ZKBANK_ADDRESS=`forge create ZkBank --private-key $ETH_PRIVATE_KEY --broadcast --constructor-args $VERIFIER_ADDRESS 0x199aa62af8c1d562a6ec96e66347bf3240ab2afb5d022c895e6bf6a5e617167b | awk '/Deployed to:/ {print $3}'` + echo $ZKBANK_ADDRESS + ``` + + `0x199..67b` 值是 `Accounts` 初始狀態的 Pederson 雜湊。 如果您在 `server/index.mjs` 中修改此初始狀態,您可以執行一個交易,以查看零知識證明報告的初始雜湊。 + +8. 執行伺服器。 + + ```sh + cd ../server + npm run start + ``` + +9. 在不同的命令列視窗中執行用戶端。 + + ```sh + cd client + npm run dev + ``` + +10. 執行一些交易。 + +11. 若要驗證狀態已在鏈上變更,請重新啟動伺服器程序。 查看 `ZkBank` 是否不再接受交易,因為交易中的原始雜湊值與鏈上儲存的雜湊值不同。 + + 這是預期的錯誤類型。 + + ``` + ori@CryptoDocGuy:~/x/250911-zk-bank/server$ npm run start + + > server@1.0.0 start + > node --experimental-json-modules index.mjs + + 正在接聽連接埠 3000 + 驗證錯誤:ContractFunctionExecutionError: 合約函數 "processTransaction" 因以下原因而還原: + 舊狀態雜湊值錯誤 + + 合約呼叫: + 地址: 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512 + 函數: processTransaction(bytes _proof, bytes32[] _publicInputs) + 參數: (0x0000000000000000000000000000000000000000000000042ab5d6d1986846cf00000000000000000000000000000000000000000000000b75c020998797da7800000000000000000000000000000000000000000000000 + ``` + +#### `server/index.mjs` {#server-index-mjs-2} + +此檔案中的變更主要與建立實際證明並在鏈上提交有關。 + +```js +import { exec } from 'child_process' +import util from 'util' + +const execPromise = util.promisify(exec) +``` + +我們需要使用 [Barretenberg 套件](https://github.com/AztecProtocol/aztec-packages/tree/next/barretenberg) 來建立要傳送到鏈上的實際證明。 我們可以使用此套件,方法是執行命令列介面 (`bb`) 或使用 [JavaScript 庫 `bb.js`](https://www.npmjs.com/package/@aztec/bb.js)。 JavaScript 庫比原生執行程式碼慢得多,因此我們在此使用 [`exec`](https://nodejs.org/api/child_process.html#child_processexeccommand-options-callback) 來使用命令列。 + +請注意,如果您決定使用 `bb.js`,您需要使用與您正在使用的 Noir 版本相容的版本。 在撰寫本文時,目前的 Noir 版本 (1.0.0-beta.11) 使用 `bb.js` 版本 0.87。 + +```js +const zkBankAddress = process.env.ZKBANK_ADDRESS || "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512" +``` + +此處的地址是您從乾淨的 `anvil` 開始並遵循上述說明時取得的地址。 + +```js +const walletClient = createWalletClient({ + chain: anvil, + transport: http(), + account: privateKeyToAccount("0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6") +}) +``` + +此私密金鑰是 `anvil` 中預先資助的預設帳戶之一。 + +```js +const generateProof = async (witness, fileID) => { +``` + +使用 `bb` 可執行檔產生證明。 + +```js + const fname = `witness-${fileID}.gz` + await fs.writeFile(fname, witness) +``` + +將見證寫入檔案。 + +```js + await execPromise(`bb prove -b ./noir/target/zkBank.json -w ${fname} -o ${fileID} --oracle_hash keccak --output_format fields`) +``` + +實際建立證明。 此步驟也會建立一個包含公開變數的檔案,但我們不需要該檔案。 我們已經從 `noir.execute` 取得這些變數。 + +```js + const proof = "0x" + JSON.parse(await fs.readFile(`./${fileID}/proof_fields.json`)).reduce((a,b) => a+b, "").replace(/0x/g, "") +``` + +證明是一個 JSON 陣列,其中包含 `Field` 值,每個值都以十六進位值表示。 然而,我們需要將它作為單一的 `bytes` 值在交易中傳送,Viem 會以一個大的十六進位字串表示。 在此,我們透過串接所有值、移除所有 `0x`,然後在結尾加上一個來變更格式。 + +```js + await execPromise(`rm -r ${fname} ${fileID}`) + + return proof +} +``` + +清理並傳回證明。 + +```js +const processMessage = async (message, signature) => { + . + . + . + + const publicFields = noirResult.returnValue.map(x=>'0x' + x.slice(2).padStart(64, "0")) +``` + +公開欄位需要是 32 位元組值的陣列。 然而,由於我們需要將交易雜湊值分割到兩個 `Field` 值之間,因此它顯示為 16 位元組值。 在此,我們加上零,讓 Viem 了解它實際上是 32 位元組。 + +```js + const proof = await generateProof(noirResult.witness, `${fromAddress}-${nonce}`) +``` + +每個地址只會使用每個 nonce 一次,因此我們可以使用 `fromAddress` 和 `nonce` 的組合作為見證檔案和輸出目錄的唯一識別碼。 + +```js + try { + await zkBank.write.processTransaction([ + proof, publicFields]) + } catch (err) { + console.log(`驗證錯誤:${err}`) + throw Error("無法在鏈上驗證交易") + } + . + . + . +} +``` + +將交易傳送到鏈上。 + +#### `smart-contracts/src/ZkBank.sol` {#smart-contracts-src-zkbank-sol} + +這是接收交易的鏈上程式碼。 + +```solidity +// SPDX-License-Identifier: MIT + +pragma solidity >=0.8.21; + +import {HonkVerifier} from "./Verifier.sol"; + +contract ZkBank { + HonkVerifier immutable myVerifier; + bytes32 currentStateHash; + + constructor(address _verifierAddress, bytes32 _initialStateHash) { + currentStateHash = _initialStateHash; + myVerifier = HonkVerifier(_verifierAddress); + } +``` + +鏈上程式碼需要追蹤兩個變數:驗證器 (由 `nargo` 建立的獨立合約) 和目前的狀態雜湊。 + +```solidity + event TransactionProcessed( + bytes32 indexed transactionHash, + bytes32 oldStateHash, + bytes32 newStateHash + ); +``` + +每當狀態變更時,我們就會發出 `TransactionProcessed` 事件。 + +```solidity + function processTransaction( + bytes calldata _proof, + bytes32[] calldata _publicFields + ) public { +``` + +此函式會處理交易。 它會以驗證器所需的格式取得證明 (作為 `bytes`) 和公開輸入 (作為 `bytes32` 陣列),以最小化鏈上處理並因此降低 gas 成本。 + +```solidity + require(_publicInputs[0] == currentStateHash, + "舊狀態雜湊值錯誤"); +``` + +零知識證明需要證明交易從我們目前的雜湊變更為新的雜湊。 + +```solidity + myVerifier.verify(_proof, _publicFields); +``` + +呼叫驗證器合約以驗證零知識證明。 如果零知識證明錯誤,此步驟會還原交易。 + +```solidity + currentStateHash = _publicFields[1]; + + emit TransactionProcessed( + _publicFields[2]<<128 | _publicFields[3], + _publicFields[0], + _publicFields[1] + ); + } +} +``` + +如果一切都檢查無誤,請將狀態雜湊更新為新值,並發出 `TransactionProcessed` 事件。 + +## 中心化元件的濫用 {#abuses} + +資訊安全包含三個屬性: + +- _機密性_,使用者無法讀取他們未經授權讀取的資訊。 +- _完整性_,資訊不能被授權使用者以外的人以未經授權的方式變更。 +- _可用性_,授權使用者可以使用系統。 + +在此系統上,完整性是透過零知識證明提供的。 可用性更難保證,而機密性則不可能,因為銀行必須知道每個帳戶的餘額和所有交易。 無法阻止擁有資訊的實體分享該資訊。 + +也許可以使用 [隱身地址](https://vitalik.eth.limo/general/2023/01/20/stealth.html) 建立一個真正機密的銀行,但這超出了本文的範圍。 + +### 不實資訊 {#false-info} + +伺服器違反完整性的一種方式是在 [要求資料](https://github.com/qbzzt/250911-zk-bank/blob/03-smart-contracts/server/index.mjs#L278-L291) 時提供不實資訊。 + +為了解決這個問題,我們可以編寫第二個 Noir 程式,該程式接收帳戶作為私密輸入,並接收要求資訊的地址作為公開輸入。 輸出是該地址的餘額和 nonce,以及帳戶的雜湊。 + +當然,此證明無法在鏈上驗證,因為我們不想在鏈上張貼 nonce 和餘額。 然而,它可以由在瀏覽器中執行的用戶端程式碼來驗證。 + +### 強制交易 {#forced-txns} + +確保 L2 可用性和防止審查的通常機制是 [強制交易](https://docs.optimism.io/stack/transactions/forced-transaction)。 但強制交易與零知識證明不相容。 伺服器是唯一可以驗證交易的實體。 + +我們可以修改 `smart-contracts/src/ZkBank.sol` 以接受強制交易,並防止伺服器在處理它們之前變更狀態。 然而,這會讓我們面臨簡單的阻斷服務攻擊。 如果強制交易無效且因此無法處理,該怎麼辦? + +解決方案是擁有一個零知識證明,證明強制交易是無效的。 這給伺服器三個選項: + +- 處理強制交易,提供一個零知識證明,證明它已處理,並提供新的狀態雜湊。 +- 拒絕強制交易,並向合約提供一個零知識證明,證明該交易無效 (未知地址、錯誤的 nonce 或餘額不足)。 +- 忽略強制交易。 無法強制伺服器實際處理交易,但這表示整個系統都不可用。 + +#### 可用性保證金 {#avail-bonds} + +在實際的實作中,可能會有某種獲利動機來維持伺服器運作。 我們可以透過讓伺服器發布可用性保證金來加強此誘因,如果強制交易未在特定時間內處理,任何人都可以銷毀該保證金。 + +### 不良的 Noir 程式碼 {#bad-noir-code} + +通常,為了讓大家信任智能合約,我們會將原始程式碼上傳到 [區塊瀏覽器](https://eth.blockscout.com/address/0x7D16d2c4e96BCFC8f815E15b771aC847EcbDB48b?tab=contract)。 然而,在零知識證明的情況下,這是不夠的。 + +`Verifier.sol` 包含驗證金鑰,這是 Noir 程式的一個函數。 然而,該金鑰並未告訴我們 Noir 程式是什麼。 為了真正擁有一個可信賴的解決方案,您需要上傳 Noir 程式 (以及建立它的版本)。 否則,零知識證明可能反映出不同的程式,一個有後門的程式。 + +在區塊瀏覽器允許我們上傳和驗證 Noir 程式之前,您應該自己動手 (最好上傳到 [IPFS](/developers/tutorials/ipfs-decentralized-ui/))。 然後,有經驗的使用者將能夠下載原始程式碼,自己編譯,建立 `Verifier.sol`,並驗證它是否與鏈上的版本相同。 + +## 結論 {#conclusion} + +Plasma 類型的應用程式需要一個中心化元件作為資訊儲存。 這會帶來潛在的漏洞,但作為回報,它讓我們能夠以區塊鏈本身無法提供的方式保護隱私。 透過零知識證明,我們可以確保完整性,並可能使執行中心化元件的人在維持可用性方面具有經濟優勢。 + +[在此查看我的更多作品](https://cryptodocguy.pro/)。 + +## 致謝 {#acknowledgements} + +- Josh Crites 閱讀了本文的草稿,並幫助我解決了一個棘手的 Noir 問題。 + +任何剩餘的錯誤都由我負責。 diff --git a/public/content/translations/zh-tw/developers/tutorials/calling-a-smart-contract-from-javascript/index.md b/public/content/translations/zh-tw/developers/tutorials/calling-a-smart-contract-from-javascript/index.md new file mode 100644 index 00000000000..171f803566a --- /dev/null +++ b/public/content/translations/zh-tw/developers/tutorials/calling-a-smart-contract-from-javascript/index.md @@ -0,0 +1,131 @@ +--- +title: "從 JavaScript 呼叫智能合約" +description: "如何使用 JavaScript 呼叫智能合約函式:以 Dai 代幣為例" +author: jdourlens +tags: [ "交易", "前端", "JavaScript", "web3.js" ] +skill: beginner +lang: zh-tw +published: 2020-04-19 +source: EthereumDev +sourceUrl: https://ethereumdev.io/calling-a-smart-contract-from-javascript/ +address: "0x19dE91Af973F404EDF5B4c093983a7c6E3EC8ccE" +--- + +在本教學中,我們將了解如何從 JavaScript 呼叫[智能合約](/developers/docs/smart-contracts/)函式。 首先,我們會讀取智能合約的狀態 (例如 ERC20 持有者的餘額),然後透過代幣傳送來修改區塊鏈的狀態。 您應該已經熟悉如何[設定 JS 環境來與區塊鏈互動](/developers/tutorials/set-up-web3js-to-use-ethereum-in-javascript/)。 + +在本範例中,我們將使用 DAI 代幣。為了測試,我們將使用 ganache-cli 來分叉區塊鏈,並解鎖一個已持有大量 DAI 的地址: + +```bash +ganache-cli -f https://mainnet.infura.io/v3/[您的 INFURA 金鑰] -d -i 66 1 --unlock 0x4d10ae710Bd8D1C31bd7465c8CBC3add6F279E81 +``` + +要與智能合約互動,我們需要它的地址和 ABI: + +```js +const ERC20TransferABI = [ + { + constant: false, + inputs: [ + { + name: "_to", + type: "address", + }, + { + name: "_value", + type: "uint256", + }, + ], + name: "transfer", + outputs: [ + { + name: "", + type: "bool", + }, + ], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: true, + inputs: [ + { + name: "_owner", + type: "address", + }, + ], + name: "balanceOf", + outputs: [ + { + name: "balance", + type: "uint256", + }, + ], + payable: false, + stateMutability: "view", + type: "function", + }, +] + +const DAI_ADDRESS = "0x6b175474e89094c44da98b954eedeac495271d0f" +``` + +在這個專案中,我們刪減了完整的 ERC20 ABI,只保留 `balanceOf` 和 `transfer` 函式,但您可以在[此處找到完整的 ERC20 ABI](https://ethereumdev.io/abi-for-erc20-contract-on-ethereum/)。 + +接著我們需要實例化我們的智能合約: + +```js +const web3 = new Web3("http://localhost:8545") + +const daiToken = new web3.eth.Contract(ERC20TransferABI, DAI_ADDRESS) +``` + +我們也將設定兩個地址: + +- 接收傳送的地址,以及 +- 我們已解鎖、將用來傳送的地址: + +```js +const senderAddress = "0x4d10ae710Bd8D1C31bd7465c8CBC3add6F279E81" +const receiverAddress = "0x19dE91Af973F404EDF5B4c093983a7c6E3EC8ccE" +``` + +在下個部分,我們將呼叫 `balanceOf` 函式,以擷取兩個地址目前持有的代幣數量。 + +## 呼叫:從智能合約讀取數值 {#call-reading-value-from-a-smart-contract} + +第一個範例將呼叫一個「常數」(constant) 方法,並在以太坊虛擬機 (EVM) 中執行其智能合約方法,而不會傳送任何交易。 為此,我們將讀取一個地址的 ERC20 餘額。 [閱讀我們關於 ERC20 代幣的文章](/developers/tutorials/understand-the-erc-20-token-smart-contract/)。 + +您可以存取已實例化的智能合約方法,只要您已提供其 ABI,方式如下:`yourContract.methods.methodname`。 使用 `call` 函式,您將會收到執行函式的結果。 + +```js +daiToken.methods.balanceOf(senderAddress).call(function (err, res) { + if (err) { + console.log("發生錯誤", err) + return + } + console.log("餘額為:", res) +}) +``` + +請記住,DAI ERC20 有 18 位小數,這意味著您需要去掉 18 個零才能得到正確的金額。 由於 JavaScript 無法處理大數值,`uint256` 會以字串的形式傳回。 如果您不確定[如何在 JS 中處理大數值,請查看我們關於 bignumber.js 的教學](https://ethereumdev.io/how-to-deal-with-big-numbers-in-javascript/)。 + +## 傳送:傳送交易至智能合約函式 {#send-sending-a-transaction-to-a-smart-contract-function} + +在第二個範例中,我們將呼叫 DAI 智能合約的 `transfer` 函式,傳送 10 個 DAI 到我們的第二個地址。 `transfer` 函式接受兩個參數:接收方地址以及要傳送的代幣數量: + +```js +daiToken.methods + .transfer(receiverAddress, "100000000000000000000") + .send({ from: senderAddress }, function (err, res) { + if (err) { + console.log("發生錯誤", err) + return + } + console.log("交易哈希:" + res) + }) +``` + +此函式呼叫會傳回交易的哈希,該交易將被挖出並納入區塊鏈。 在以太坊上,交易哈希是可預測的——這就是我們能在交易執行前就取得其哈希的原因 ([在此了解哈希如何計算](https://ethereum.stackexchange.com/questions/45648/how-to-calculate-the-assigned-txhash-of-a-transaction))。 + +由於該函式只是將交易提交到區塊鏈,我們要等到它被挖出並納入區塊鏈後,才能看到結果。 在下一個教學中,我們將學習[如何根據交易哈希,等待交易在區塊鏈上被執行](https://ethereumdev.io/waiting-for-a-transaction-to-be-mined-on-ethereum-with-js/)。 diff --git a/public/content/translations/zh-tw/developers/tutorials/creating-a-wagmi-ui-for-your-contract/index.md b/public/content/translations/zh-tw/developers/tutorials/creating-a-wagmi-ui-for-your-contract/index.md new file mode 100644 index 00000000000..82d384425bb --- /dev/null +++ b/public/content/translations/zh-tw/developers/tutorials/creating-a-wagmi-ui-for-your-contract/index.md @@ -0,0 +1,585 @@ +--- +title: "為你的合約建立一個使用者介面" +description: "我們將使用 TypeScript、React、Vite 和 Wagmi 等現代元件,探討一個現代但極簡的使用者介面,並學習如何將錢包連接到使用者介面、呼叫智能合約來讀取資訊、將交易傳送到智能合約,以及監視智能合約的事件來識別變更。" +author: Ori Pomerantz +tags: [ "TypeScript", "React", "vite", "wagmi", "前端" ] +skill: beginner +published: 2023-11-01 +lang: zh-tw +sidebarDepth: 3 +--- + +你找到了一個我們在以太坊生態系統中需要的功能。 你編寫了智能合約來實作它,甚至可能編寫了一些在鏈外執行的相關程式碼。 這太棒了! 不幸的是,如果沒有使用者介面,你就不會有任何使用者。而且在你上一次寫網站的時候,人們還在使用撥接數據機,JavaScript 還是個新玩意兒。 + +這篇文章就是為你而寫的。 我假設你懂程式設計,可能也懂一點 JavaScript 和 HTML,但你的使用者介面技能已經生疏過時了。 我們將一起探討一個簡單的現代應用程式,讓你看看現在是怎麼做的。 + +## 為什麼這很重要 {#why-important} + +理論上,你可以讓大家直接使用 [Etherscan](https://holesky.etherscan.io/address/0x432d810484add7454ddb3b5311f0ac2e95cecea8#writeContract) 或 [Blockscout](https://eth-holesky.blockscout.com/address/0x432d810484AdD7454ddb3b5311f0Ac2E95CeceA8?tab=write_contract) 來與你的合約互動。 對於經驗豐富的以太坊使用者來說,這很棒。 但我們正試圖為 [另外十億人](https://blog.ethereum.org/2021/05/07/ethereum-for-the-next-billion) 提供服務。 如果沒有出色的使用者體驗,這一切都不會發生,而友善的使用者介面是其中的重要一環。 + +## Greeter 應用程式 {#greeter-app} + +現代 UI 的運作背後有很多理論,也有 [很多好的網站](https://react.dev/learn/thinking-in-react) [對此進行了解釋](https://wagmi.sh/core/getting-started)。 與其重複那些網站已經完成的出色工作,我假設你更喜歡從做中學,從一個你可以實際操作的應用程式開始。 你仍然需要理論來完成工作,我們也會談到它——我們將逐一檢視原始檔,並在遇到問題時進行討論。 + +### 安裝 {#installation} + +1. 如有需要,請將 [Holesky 區塊鏈](https://chainlist.org/?search=holesky&testnets=true) 新增到你的錢包,並 [取得測試 ETH](https://www.holeskyfaucet.io/)。 + +2. 複製 GitHub 儲存庫。 + + ```sh + git clone https://github.com/qbzzt/20230801-modern-ui.git + ``` + +3. 安裝必要的套件。 + + ```sh + cd 20230801-modern-ui + pnpm install + ``` + +4. 啟動應用程式。 + + ```sh + pnpm dev + ``` + +5. 瀏覽應用程式顯示的 URL。 在大多數情況下,它是 [http://localhost:5173/](http://localhost:5173/)。 + +6. 你可以在 [區塊鏈瀏覽器](https://eth-holesky.blockscout.com/address/0x432d810484AdD7454ddb3b5311f0Ac2E95CeceA8?tab=contract) 上看到合約的原始碼,它是 Hardhat 的 Greeter 的一個稍作修改的版本。 + +### 檔案走查 {#file-walk-through} + +#### `index.html` {#index-html} + +這個檔案是標準的 HTML 樣板,除了這一行,它匯入了腳本檔案。 + +```html + +``` + +#### `src/main.tsx` {#main-tsx} + +副檔名告訴我們這個檔案是一個用 [TypeScript](https://www.typescriptlang.org/) 編寫的 [React 元件](https://www.w3schools.com/react/react_components.asp),TypeScript 是 JavaScript 的一個擴充,支援 [型別檢查](https://en.wikipedia.org/wiki/Type_system#Type_checking)。 TypeScript 會被編譯成 JavaScript,所以我們可以用它來進行用戶端執行。 + +```tsx +import '@rainbow-me/rainbowkit/styles.css' +import { RainbowKitProvider } from '@rainbow-me/rainbowkit' +import * as React from 'react' +import * as ReactDOM from 'react-dom/client' +import { WagmiConfig } from 'wagmi' +import { chains, config } from './wagmi' +``` + +匯入我們需要的庫程式碼。 + +```tsx +import { App } from './App' +``` + +匯入實作應用程式的 React 元件(見下文)。 + +```tsx +ReactDOM.createRoot(document.getElementById('root')!).render( +``` + +建立根 React 元件。 `render` 的參數是 [JSX](https://www.w3schools.com/react/react_jsx.asp),這是一種使用 HTML 和 JavaScript/TypeScript 的擴充語言。 這裡的驚嘆號告訴 TypeScript 元件:「你不知道 `document.getElementById('root')` 將會是 `ReactDOM.createRoot` 的一個有效參數,但別擔心——我是開發者,我告訴你它會是」。 + +```tsx + +``` + +應用程式將放在 [一個 `React.StrictMode` 元件](https://react.dev/reference/react/StrictMode) 內。 此元件會告訴 React 庫插入額外的偵錯檢查,這在開發過程中很有用。 + +```tsx + +``` + +應用程式也放在 [一個 `WagmiConfig` 元件](https://wagmi.sh/react/api/WagmiProvider) 內。 [wagmi (we are going to make it) 庫](https://wagmi.sh/) 將 React UI 定義與 [viem 庫](https://viem.sh/) 連接起來,用於編寫以太坊去中心化應用程式。 + +```tsx + +``` + +最後是 [一個 `RainbowKitProvider` 元件](https://www.rainbowkit.com/)。 此元件處理登入以及錢包和應用程式之間的通訊。 + +```tsx + +``` + +現在我們可以擁有應用程式的元件,它實際實作了 UI。 元件結尾的 `/>` 告訴 React,根據 XML 標準,此元件內部沒有任何定義。 + +```tsx + + + , +) +``` + +當然,我們必須關閉其他元件。 + +#### `src/App.tsx` {#app-tsx} + +```tsx +import { ConnectButton } from '@rainbow-me/rainbowkit' +import { useAccount } from 'wagmi' +import { Greeter } from './components/Greeter' + +export function App() { +``` + +這是建立 React 元件的標準方法——定義一個函式,每次需要渲染時都會呼叫它。 這個函式通常在頂部有一些 TypeScript 或 JavaScript 程式碼,後面跟著一個回傳 JSX 程式碼的 `return` 陳述式。 + +```tsx + const { isConnected } = useAccount() +``` + +這裡我們使用 [`useAccount`](https://wagmi.sh/react/api/hooks/useAccount) 來檢查我們是否透過錢包連接到區塊鏈。 + +按照慣例,在 React 中,名為 `use...` 的函式是回傳某種資料的 [hook](https://www.w3schools.com/react/react_hooks.asp)。 當你使用這樣的 hook 時,你的元件不僅會取得資料,而且當該資料變更時,元件會用更新後的資訊重新渲染。 + +```tsx + return ( + <> +``` + +React 元件的 JSX _必須_回傳一個元件。 當我們有多個元件,並且沒有任何東西可以「自然地」包裝它們時,我們使用一個空元件(`<> ... `)來將它們變成單一元件。 + +```tsx +

Greeter

+ +``` + +我們從 RainbowKit 取得 [`ConnectButton` 元件](https://www.rainbowkit.com/docs/connect-button)。 當我們未連接時,它會提供一個 `Connect Wallet` 按鈕,開啟一個說明錢包的強制回應視窗,讓你選擇使用哪一個錢包。 當我們連接時,它會顯示我們使用的區塊鏈、我們的帳戶地址和我們的 ETH 餘額。 我們可以使用這些顯示來切換網路或中斷連接。 + +```tsx + {isConnected && ( +``` + +當我們需要將實際的 JavaScript(或將被編譯為 JavaScript 的 TypeScript)插入 JSX 時,我們使用大括號(`{}`)。 + +`a && b` 語法是 [`a ? b : a` 的簡寫](https://www.w3schools.com/react/react_es6_ternary.asp)。 也就是說,如果 `a`為 true,它的評估結果為`b`,否則它的評估結果為 `a`(可以是 `false`、`0` 等)。 這是一種簡單的方法,可以告訴 React 只有在滿足特定條件時才顯示元件。 + +在這種情況下,我們只想在使用者連接到區塊鏈時向使用者顯示 `Greeter`。 + +```tsx + + )} + + ) +} +``` + +#### `src/components/Greeter.tsx` {#greeter-tsx} + +這個檔案包含了大部分的 UI 功能。 它包含了一些通常會放在多個檔案中的定義,但因為這是一個教學,所以程式的最佳化目標是為了初次閱讀時容易理解,而不是為了效能或易於維護。 + +```tsx +import { useState, ChangeEventHandler } from 'react' +import { useNetwork, + useReadContract, + usePrepareContractWrite, + useContractWrite, + useContractEvent + } from 'wagmi' +``` + +我們使用這些庫函式。 同樣,它們在下面使用到的地方會進行解釋。 + +```tsx +import { AddressType } from 'abitype' +``` + +[`abitype` 庫](https://abitype.dev/) 為我們提供了各種以太坊資料型別的 TypeScript 定義,例如 [`AddressType`](https://abitype.dev/config#addresstype)。 + +```tsx +let greeterABI = [ + . + . + . +] as const // greeterABI +``` + +`Greeter` 合約的 ABI。 +如果你同時開發合約和 UI,通常會將它們放在同一個儲存庫中,並將 Solidity 編譯器產生的 ABI 作為一個檔案用在你的應用程式中。 然而,在這裡這不是必要的,因為合約已經開發完成,不會再變更。 + +```tsx +type AddressPerBlockchainType = { + [key: number]: AddressType +} +``` + +TypeScript 是強型別的。 我們使用這個定義來指定 `Greeter` 合約在不同鏈上部署的地址。 鍵是一個數字(chainId),值是一個 `AddressType`(一個地址)。 + +```tsx +const contractAddrs: AddressPerBlockchainType = { + // Holesky + 17000: '0x432d810484AdD7454ddb3b5311f0Ac2E95CeceA8', + + // Sepolia + 11155111: '0x7143d5c190F048C8d19fe325b748b081903E3BF0' +} +``` + +合約在兩個支援的網路上的地址:[Holesky](https://eth-holesky.blockscout.com/address/0x432d810484AdD7454ddb3b5311f0Ac2E95CeceA8?tab=contact_code) 和 [Sepolia](https://eth-sepolia.blockscout.com/address/0x7143d5c190F048C8d19fe325b748b081903E3BF0?tab=contact_code)。 + +注意:實際上還有第三個定義,針對 Redstone Holesky,下面將會解釋。 + +```tsx +type ShowObjectAttrsType = { + name: string, + object: any +} +``` + +這個型別被用作 `ShowObject` 元件(稍後解釋)的參數。 它包含物件的名稱和其值,這些是用於偵錯目的而顯示的。 + +```tsx +type ShowGreetingAttrsType = { + greeting: string | undefined +} +``` + +在任何時候,我們可能知道問候語是什麼(因為我們從區塊鏈讀取了它),也可能不知道(因為我們還沒有收到它)。 所以有一個可以是字串或什麼都沒有的型別是很有用的。 + +##### `Greeter` 元件 {#greeter-component} + +```tsx +const Greeter = () => { +``` + +最後,我們來定義元件。 + +```tsx + const { chain } = useNetwork() +``` + +關於我們正在使用的鏈的資訊,由 [wagmi](https://wagmi.sh/react/hooks/useNetwork) 提供。 +因為這是一個 hook (`use...`),所以每次這個資訊變更時,元件都會被重新繪製。 + +```tsx + const greeterAddr = chain && contractAddrs[chain.id] +``` + +Greeter 合約的地址,它會因鏈而異(如果我們沒有鏈的資訊,或者我們在沒有該合約的鏈上,則為 `undefined`)。 + +```tsx + const readResults = useReadContract({ + address: greeterAddr, + abi: greeterABI, + functionName: "greet" , // 無引數 + watch: true + }) +``` + +[`useReadContract` hook](https://wagmi.sh/react/api/hooks/useReadContract) 從合約中讀取資訊。 你可以在 UI 中展開 `readResults` 來查看它回傳的確切資訊。 在這種情況下,我們希望它持續檢查,以便在問候語變更時得到通知。 + +**注意:** 我們可以監聽 [`setGreeting` 事件](https://eth-holesky.blockscout.com/address/0x432d810484AdD7454ddb3b5311f0Ac2E95CeceA8?tab=logs) 來得知問候語何時變更,並以此方式更新。 然而,雖然這樣可能更有效率,但它並不適用於所有情況。 當使用者切換到不同的鏈時,問候語也會變更,但此變更並無伴隨事件。 我們可以讓一部分程式碼監聽事件,另一部分來識別鏈的變更,但這會比僅僅設定 [`watch` 參數](https://wagmi.sh/react/api/hooks/useReadContract#watch-optional) 更複雜。 + +```tsx + const [ newGreeting, setNewGreeting ] = useState("") +``` + +React 的 [`useState` hook](https://www.w3schools.com/react/react_usestate.asp) 讓我們可以指定一個狀態變數,其值在元件的多次渲染之間保持不變。 初始值是參數,此處為空字串。 + +`useState` hook 回傳一個包含兩個值的清單: + +1. 狀態變數的目前值。 +2. 一個在需要時修改狀態變數的函式。 因為這是一個 hook,所以每次呼叫它時,元件都會重新渲染。 + +在這種情況下,我們使用一個狀態變數來儲存使用者想要設定的新問候語。 + +```tsx + const greetingChange : ChangeEventHandler = (evt) => + setNewGreeting(evt.target.value) +``` + +這是當新問候語輸入欄位變更時的事件處理常式。 型別 [`ChangeEventHandler`](https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/forms_and_events/) 指定這是一個 HTML 輸入元素值變更的處理常式。 使用 `` 部分是因為這是一個 [泛型型別](https://www.w3schools.com/typescript/typescript_basic_generics.php)。 + +```tsx + const preparedTx = usePrepareContractWrite({ + address: greeterAddr, + abi: greeterABI, + functionName: 'setGreeting', + args: [ newGreeting ] + }) + const workingTx = useContractWrite(preparedTx.config) +``` + +這是從用戶端角度提交區塊鏈交易的過程: + +1. 使用 [`eth_estimateGas`](https://docs.alchemy.com/reference/eth-estimategas) 將交易傳送到區塊鏈中的一個節點。 +2. 等待節點的回應。 +3. 收到回應後,要求使用者透過錢包簽署交易。 這一步驟_必須_在收到節點回應後進行,因為使用者在簽署交易前會看到交易的 gas 成本。 +4. 等待使用者核准。 +5. 再次傳送交易,這次使用 [`eth_sendRawTransaction`](https://docs.alchemy.com/reference/eth-sendrawtransaction)。 + +步驟 2 可能會花費一段可觀的時間,在此期間,使用者會想知道他們的指令是否真的被使用者介面接收到,以及為什麼還沒有被要求簽署交易。 這會造成不好的使用者體驗(UX)。 + +解決方案是使用 [prepare hook](https://wagmi.sh/react/prepare-hooks)。 每當參數變更時,立即向節點傳送 `eth_estimateGas` 請求。 然後,當使用者實際想要傳送交易時(在此例中是按下 **更新問候語**),gas 成本是已知的,使用者可以立即看到錢包頁面。 + +```tsx + return ( +``` + +現在我們終於可以建立要回傳的實際 HTML 了。 + +```tsx + <> +

Greeter

+ { + !readResults.isError && !readResults.isLoading && + + } +
+``` + +建立一個 `ShowGreeting` 元件(下面會解釋),但只有在成功從區塊鏈讀取問候語時才建立。 + +```tsx + +``` + +這是使用者可以設定新問候語的輸入文字欄位。 每當使用者按下一個鍵,我們就呼叫 `greetingChange`,它會再呼叫 `setNewGreeting`。 由於 `setNewGreeting` 來自 `useState` hook,它會導致 `Greeter` 元件再次被渲染。 這表示: + +- 我們需要指定 `value` 來保留新問候語的值,否則它會變回預設的空字串。 +- 每當 `newGreeting` 變更時,`usePrepareContractWrite` 就會被呼叫,這表示它在準備好的交易中永遠會擁有最新的 `newGreeting`。 + +```tsx + +``` + +如果沒有 `workingTx.write`,那麼我們仍在等待傳送問候語更新所需的資訊,所以按鈕是停用的。 如果有 `workingTx.write` 值,那麼這就是傳送交易時要呼叫的函式。 + +```tsx +
+ + + + + ) +} +``` + +最後,為了幫助你了解我們在做什麼,顯示我們使用的三個物件: + +- `readResults` +- `preparedTx` +- `workingTx` + +##### `ShowGreeting` 元件 {#showgreeting-component} + +此元件顯示 + +```tsx +const ShowGreeting = (attrs : ShowGreetingAttrsType) => { +``` + +一個元件函式接收一個包含該元件所有屬性的參數。 + +```tsx + return {attrs.greeting} +} +``` + +##### `ShowObject` 元件 {#showobject-component} + +為了提供資訊,我們使用 `ShowObject` 元件來顯示重要的物件(`readResults` 用於讀取問候語,`preparedTx` 和 `workingTx` 用於我們建立的交易)。 + +```tsx +const ShowObject = (attrs: ShowObjectAttrsType ) => { + const keys = Object.keys(attrs.object) + const funs = keys.filter(k => typeof attrs.object[k] == "function") + return <> +
+``` + +我們不希望用所有資訊來塞滿 UI,所以為了可以檢視或關閉它們,我們使用了 [`details`](https://www.w3schools.com/tags/tag_details.asp) 標籤。 + +```tsx + {attrs.name} +
+        {JSON.stringify(attrs.object, null, 2)}
+```
+
+大部分的欄位都是使用 [`JSON.stringify`](https://www.w3schools.com/js/js_json_stringify.asp) 來顯示的。
+
+```tsx
+      
+ { funs.length > 0 && + <> + 函式: +
    +``` + +例外是函式,它們不是 [JSON 標準](https://www.json.org/json-en.html) 的一部分,所以必須分開顯示。 + +```tsx + {funs.map((f, i) => +``` + +在 JSX 中,`{` 大括號 `}` 內的程式碼會被解讀為 JavaScript。 然後,`(` 普通括號 `)` 內的程式碼會再次被解讀為 JSX。 + +```tsx + (
  • {f}
  • ) + )} +``` + +React 要求 [DOM 樹](https://www.w3schools.com/js/js_htmldom.asp) 中的標籤必須有不同的識別碼。 這表示同一個標籤的子標籤(在此例中為 [無序清單](https://www.w3schools.com/tags/tag_ul.asp))需要有不同的 `key` 屬性。 + +```tsx +
+ + } +
+ +} +``` + +結束各種 HTML 標籤。 + +##### 最後的 `export` {#the-final-export} + +```tsx +export { Greeter } +``` + +我們需要為應用程式匯出的就是 `Greeter` 元件。 + +#### `src/wagmi.ts` {#wagmi-ts} + +最後,與 WAGMI 相關的各種定義都在 `src/wagmi.ts` 中。 我不會在這裡解釋所有內容,因為大部分都是樣板程式碼,你不太可能需要變更。 + +這裡的程式碼與 [github 上的](https://github.com/qbzzt/20230801-modern-ui/blob/main/src/wagmi.ts) 不完全相同,因為在文章後面我們會新增另一條鏈 ([Redstone Holesky](https://redstone.xyz/docs/network-info))。 + +```ts +import { getDefaultWallets } from '@rainbow-me/rainbowkit' +import { configureChains, createConfig } from 'wagmi' +import { holesky, sepolia } from 'wagmi/chains' +``` + +匯入應用程式支援的區塊鏈。 你可以在 [viem 的 github](https://github.com/wagmi-dev/viem/tree/main/src/chains/definitions) 中看到支援的鏈的清單。 + +```ts +import { publicProvider } from 'wagmi/providers/public' + +const walletConnectProjectId = 'c96e690bb92b6311e8e9b2a6a22df575' +``` + +要能使用 [WalletConnect](https://walletconnect.com/),你的應用程式需要一個專案 ID。 你可以在 [cloud.walletconnect.com](https://cloud.walletconnect.com/sign-in) 上取得它。 + +```ts +const { chains, publicClient, webSocketPublicClient } = configureChains( + [ holesky, sepolia ], + [ + publicProvider(), + ], +) + +const { connectors } = getDefaultWallets({ + appName: 'My wagmi + RainbowKit App', + chains, + projectId: walletConnectProjectId, +}) + +export const config = createConfig({ + autoConnect: true, + connectors, + publicClient, + webSocketPublicClient, +}) + +export { chains } +``` + +### 新增另一條區塊鏈 {#add-blockchain} + +現今有很多 [L2 擴展解決方案](/layer-2/),你可能想要支援一些 viem 尚未支援的方案。 要做到這點,你需要修改 `src/wagmi.ts`。 這些說明解釋了如何新增 [Redstone Holesky](https://redstone.xyz/docs/network-info)。 + +1. 從 viem 匯入 `defineChain` 型別。 + + ```ts + import { defineChain } from 'viem' + ``` + +2. 新增網路定義。 + + ```ts + const redstoneHolesky = defineChain({ + id: 17_001, + name: 'Redstone Holesky', + network: 'redstone-holesky', + nativeCurrency: { + decimals: 18, + name: 'Ether', + symbol: 'ETH', + }, + rpcUrls: { + default: { + http: ['https://rpc.holesky.redstone.xyz'], + webSocket: ['wss://rpc.holesky.redstone.xyz/ws'], + }, + public: { + http: ['https://rpc.holesky.redstone.xyz'], + webSocket: ['wss://rpc.holesky.redstone.xyz/ws'], + }, + }, + blockExplorers: { + default: { name: 'Explorer', url: 'https://explorer.holesky.redstone.xyz' }, + }, + }) + ``` + +3. 將新鏈新增到 `configureChains` 呼叫中。 + + ```ts + const { chains, publicClient, webSocketPublicClient } = configureChains( + [ holesky, sepolia, redstoneHolesky ], + [ publicProvider(), ], + ) + ``` + +4. 確保應用程式知道你的合約在新網路上的地址。 在這種情況下,我們修改 `src/components/Greeter.tsx`: + + ```ts + const contractAddrs : AddressPerBlockchainType = { + // Holesky + 17000: '0x432d810484AdD7454ddb3b5311f0Ac2E95CeceA8', + + // Redstone Holesky + 17001: '0x4919517f82a1B89a32392E1BF72ec827ba9986D3', + + // Sepolia + 11155111: '0x7143d5c190F048C8d19fe325b748b081903E3BF0' + } + ``` + +## 結論 {#conclusion} + +當然,你並不是真的在乎為 `Greeter` 提供使用者介面。 你想要為你自己的合約建立一個使用者介面。 要建立你自己的應用程式,請執行以下步驟: + +1. 指定建立一個 wagmi 應用程式。 + + ```sh copy + pnpm create wagmi + ``` + +2. 為應用程式命名。 + +3. 選擇 **React** 框架。 + +4. 選擇 **Vite** 變體。 + +5. 你可以 [新增 Rainbow kit](https://www.rainbowkit.com/docs/installation#manual-setup)。 + +現在去讓你的合約為廣大世界所用吧。 + +[在此查看我的更多作品](https://cryptodocguy.pro/)。 + diff --git a/public/content/translations/zh-tw/developers/tutorials/deploying-your-first-smart-contract/index.md b/public/content/translations/zh-tw/developers/tutorials/deploying-your-first-smart-contract/index.md new file mode 100644 index 00000000000..7582c4901d6 --- /dev/null +++ b/public/content/translations/zh-tw/developers/tutorials/deploying-your-first-smart-contract/index.md @@ -0,0 +1,95 @@ +--- +title: "部署你的第一個智能合約" +description: "在以太坊測試網上部署你的第一個智能合約的簡介" +author: "jdourlens" +tags: [ "智能合約", "Remix", "Solidity", "部署" ] +skill: beginner +lang: zh-tw +published: 2020-04-03 +source: EthereumDev +sourceUrl: https://ethereumdev.io/deploying-your-first-smart-contract/ +address: "0x19dE91Af973F404EDF5B4c093983a7c6E3EC8ccE" +--- + +我想你和我們一樣興奮,都想在以太坊區塊鏈上[部署](/developers/docs/smart-contracts/deploying/)並與你的第一個[智能合約](/developers/docs/smart-contracts/)互動。 + +別擔心,因為這是我們的第一個智能合約,我們會在[本地測試網](/developers/docs/networks/)上部署它,所以你部署和盡情操作它都不需要任何費用。 + +## 撰寫我們的合約 {#writing-our-contract} + +第一步是[訪問 Remix](https://remix.ethereum.org/) 並建立一個新檔案。 在 Remix 介面的左上角新增一個新檔案,並輸入你想要的檔案名稱。 + +![在 Remix 介面中新增檔案](./remix.png) + +在新檔案中,我們將貼上以下程式碼: + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity >=0.5.17; + +contract Counter { + + // 公開的無正負號整數,用來記錄次數 + uint256 public count = 0; + + // 遞增計數器的函式 + function increment() public { + count += 1; + } + + // 取得計數值的 getter,非必要 + function getCount() public view returns (uint256) { + return count; + } + +} +``` + +如果你習慣寫程式,你應該可以輕易猜出這個程式的功能。 以下是逐行說明: + +- 第 4 行:我們定義了一個名為 `Counter` 的合約。 +- 第 7 行:我們的合約儲存一個名為 `count` 的無正負號整數,初始值為 0。 +- 第 10 行:第一個函式會修改合約的狀態,並透過 `increment()` 遞增我們的 `count` 變數。 +- 第 15 行:第二個函式只是一個 getter,用來從智能合約外部讀取 `count` 變數的值。 請注意,因為我們將 `count` 變數定義為 public (公開),所以這不是必要的,只是作為範例展示。 + +這就是我們第一個簡單的智能合約。 你可能知道,它看起來像 Java 或 C++ 等物件導向程式設計 (OOP) 語言中的類別 (class)。 現在可以來操作我們的合約了。 + +## 部署我們的合約 {#deploying-our-contract} + +既然我們寫好了第一個智能合約,現在就要將它部署到區塊鏈上,以便進行操作。 + +[在區塊鏈上部署智能合約](/developers/docs/smart-contracts/deploying/),實際上只是傳送一筆交易,其中包含已編譯智能合約的程式碼,而無須指定任何接收者。 + +首先,我們要點擊左側的編譯圖示來[編譯合約](/developers/docs/smart-contracts/compiling/): + +![Remix 工具列中的編譯圖示](./remix-compile-button.png) + +然後點擊編譯按鈕: + +![Remix Solidity 編譯器中的編譯按鈕](./remix-compile.png) + +你可以選擇「自動編譯」(Auto compile) 選項,這樣每當你在文字編輯器中儲存內容時,合約就會自動編譯。 + +然後前往「部署及執行交易」(deploy and run transactions) 畫面: + +![Remix 工具列中的部署圖示](./remix-deploy.png) + +進入「部署及執行交易」畫面後,再次確認你的合約名稱是否出現,然後點擊「部署」(Deploy)。 如你在頁面頂端所見,目前環境是「JavaScript VM」(JavaScript 虛擬機),這代表我們將在一個本地測試鏈上部署我們的智能合約並與之互動,以便能更快地測試,且無須支付任何費用。 + +![Remix Solidity 編譯器中的部署按鈕](./remix-deploy-button.png) + +點擊「部署」(Deploy) 按鈕後,你會在底部看到你的合約。 點擊左邊的箭頭將它展開,我們便能看到合約的內容。 這就是我們的 `count` 變數、`increment()` 函式和 `getCounter()` getter。 + +如果你點擊 `count` 或 `getCount` 按鈕,它會實際擷取合約的 `count` 變數內容並顯示出來。 因為我們還沒呼叫 `increment` 函式,所以它應該會顯示 0。 + +![Remix Solidity 編譯器中的函式按鈕](./remix-function-button.png) + +現在讓我們點擊按鈕來呼叫 `increment` 函式。 你會在視窗底部看到所執行交易的紀錄。 你會發現,當你按下擷取資料的按鈕時,紀錄會與按下 `increment` 按鈕時不同。 這是因為在區塊鏈上讀取資料不需要任何交易 (寫入) 或費用。 因為只有修改區塊鏈的狀態才需要進行交易: + +![交易紀錄](./transaction-log.png) + +按下 increment 按鈕會產生一筆交易來呼叫我們的 `increment()` 函式,之後如果我們回頭點擊 count 或 getCount 按鈕,我們就會讀取到智能合約已更新的狀態,其中 count 變數的值會大於 0。 + +![智能合約已更新的狀態](./updated-state.png) + +在下一篇教學中,我們將介紹[如何在你的智能合約中新增事件](/developers/tutorials/logging-events-smart-contracts/)。 記錄事件是個便利的方法,可以對你的智能合約進行除錯,並了解呼叫函式時發生了什麼事。 diff --git a/public/content/translations/zh-tw/developers/tutorials/develop-and-test-dapps-with-a-multi-client-local-eth-testnet/index.md b/public/content/translations/zh-tw/developers/tutorials/develop-and-test-dapps-with-a-multi-client-local-eth-testnet/index.md new file mode 100644 index 00000000000..c248ccf6d0d --- /dev/null +++ b/public/content/translations/zh-tw/developers/tutorials/develop-and-test-dapps-with-a-multi-client-local-eth-testnet/index.md @@ -0,0 +1,363 @@ +--- +title: "如何在本地多用戶端測試網上開發和測試 dApp" +description: "本指南將首先引導您完成如何實例化和設定多用戶端的本地以太坊測試網,然後再使用該測試網來部署與測試 dApp。" +author: "Tedi Mitiku" +tags: [ "用戶端", "節點", "智能合約", "可組合性", "共識層", "執行層", "測試" ] +skill: intermediate +lang: zh-tw +published: 2023-04-11 +--- + +## 介紹 {#introduction} + +本指南將引導您完成實例化可設定的本地以太坊測試網、將智能合約部署到其中,並使用該測試網對您的 dApp 執行測試的過程。 本指南專為希望在部署到即時測試網或主網之前,針對不同的網路設定在本地開發和測試其 dApp 的 dApp 開發者而設計。 + +在本指南中,您將會: + +- 使用 [Kurtosis](https://www.kurtosis.com/) 和 [`eth-network-package`](https://github.com/kurtosis-tech/eth-network-package) 實例化一個本地以太坊測試網, +- 將您的 Hardhat dApp 開發環境連接到本地測試網以編譯、部署和測試 dApp,以及 +- 設定本地測試網,包括節點數量和特定的 EL/CL 用戶端配對等參數,以實現針對各種網路設定的開發和測試工作流程。 + +### 什麼是 Kurtosis? {#what-is-kurtosis} + +[Kurtosis](https://www.kurtosis.com/) 是一個可組合的建構系統,專為設定多容器測試環境而設計。 它特別允許開發者創建需要動態設定邏輯的可重現環境,例如區塊鏈測試網。 + +在本指南中,Kurtosis eth-network-package 會啟動一個本地以太坊測試網,支援 [`geth`](https://geth.ethereum.org/) 執行層 (EL) 用戶端,以及 [`teku`](https://consensys.io/teku)、[`lighthouse`](https://lighthouse.sigmaprime.io/) 和 [`lodestar`](https://lodestar.chainsafe.io/) 共識層 (CL) 用戶端。 此套件可作為 Hardhat Network、Ganache 和 Anvil 等框架中網路的可設定和可組合替代方案。 Kurtosis 為開發者提供了對其使用的測試網更大的控制權和靈活性,這也是[以太坊基金會使用 Kurtosis 測試合併](https://www.kurtosis.com/blog/testing-the-ethereum-merge)並繼續使用它來測試網路升級的主要原因。 + +## 設定 Kurtosis {#setting-up-kurtosis} + +在繼續之前,請確定您已經: + +- 在您的本地機器上[安裝並啟動 Docker 引擎](https://docs.kurtosis.com/install/#i-install--start-docker) +- [安裝 Kurtosis CLI](https://docs.kurtosis.com/install#ii-install-the-cli)(如果您已安裝 CLI,則將其升級到最新版本) +- 安裝 [Node.js](https://nodejs.org/en)、[yarn](https://classic.yarnpkg.com/lang/en/docs/install/#mac-stable) 和 [npx](https://www.npmjs.com/package/npx)(為您的 dApp 環境) + +## 實例化本地以太坊測試網 {#instantiate-testnet} + +要啟動本地以太坊測試網,請執行: + +```python +kurtosis --enclave local-eth-testnet run github.com/kurtosis-tech/eth-network-package +``` + +注意:此命令使用 `--enclave` 標誌將您的網路命名為「local-eth-testnet」。 + +Kurtosis 在解譯、驗證和執行指令時,會印出其在幕後執行的步驟。 最後,您應該會看到類似以下的輸出: + +```python +INFO[2023-04-04T18:09:44-04:00] ====================================================== +INFO[2023-04-04T18:09:44-04:00] || Created enclave: local-eth-testnet || +INFO[2023-04-04T18:09:44-04:00] ====================================================== +Name: local-eth-testnet +UUID: 39372d756ae8 +Status: RUNNING +Creation Time: Tue, 04 Apr 2023 18:09:03 EDT + +========================================= Files Artifacts ========================================= +UUID Name +d4085a064230 cl-genesis-data +1c62cb792e4c el-genesis-data +bd60489b73a7 genesis-generation-config-cl +b2e593fe5228 genesis-generation-config-el +d552a54acf78 geth-prefunded-keys +5f7e661eb838 prysm-password +054e7338bb59 validator-keystore-0 + +========================================== User Services ========================================== +UUID Name Ports Status +e20f129ee0c5 cl-client-0-beacon http: 4000/tcp -> RUNNING + metrics: 5054/tcp -> + tcp-discovery: 9000/tcp -> 127.0.0.1:54263 + udp-discovery: 9000/udp -> 127.0.0.1:60470 +a8b6c926cdb4 cl-client-0-validator http: 5042/tcp -> 127.0.0.1:54267 RUNNING + metrics: 5064/tcp -> +d7b802f623e8 el-client-0 engine-rpc: 8551/tcp -> 127.0.0.1:54253 RUNNING + rpc: 8545/tcp -> 127.0.0.1:54251 + tcp-discovery: 30303/tcp -> 127.0.0.1:54254 + udp-discovery: 30303/udp -> 127.0.0.1:53834 + ws: 8546/tcp -> 127.0.0.1:54252 +514a829c0a84 prelaunch-data-generator-1680646157905431468 STOPPED +62bd62d0aa7a prelaunch-data-generator-1680646157915424301 STOPPED +05e9619e0e90 prelaunch-data-generator-1680646157922872635 STOPPED + +``` + +恭喜! 您透過 Docker 使用 Kurtosis 實例化了一個本地以太坊測試網,其中包含一個 CL(`lighthouse`)和一個 EL 用戶端(`geth`)。 + +### 回顧 {#review-instantiate-testnet} + +在本節中,您執行了一個指令,指示 Kurtosis 使用[遠端託管在 GitHub 上的 `eth-network-package`](https://github.com/kurtosis-tech/eth-network-package) 在 Kurtosis [Enclave](https://docs.kurtosis.com/advanced-concepts/enclaves/) 中啟動一個本地以太坊測試網。 在您的 enclave 中,您會找到「檔案成品」和「使用者服務」。 + +您 enclave 中的[檔案成品](https://docs.kurtosis.com/advanced-concepts/files-artifacts/)包含所有用於啟動 EL 和 CL 用戶端的已生成和已使用的資料。 這些資料是使用從這個 [Docker 映像檔](https://github.com/ethpandaops/ethereum-genesis-generator)建構的 `prelaunch-data-generator` 服務建立的 + +使用者服務會顯示在您 enclave 中運作的所有容器化服務。 您會注意到已建立一個單一節點,該節點同時具有 EL 用戶端和 CL 用戶端。 + +## 將您的 dApp 開發環境連接到本地以太坊測試網 {#connect-your-dapp} + +### 設定 dApp 開發環境 {#set-up-dapp-env} + +既然您已擁有一個正在運行的本地測試網,您可以將您的 dApp 開發環境連接到本地測試網來使用。 本指南將使用 Hardhat 框架將一個二十一點 dApp 部署到您的本地測試網。 + +要設定您的 dApp 開發環境,請複製包含我們的範例 dApp 的儲存庫並安裝其相依性,執行: + +```python +git clone https://github.com/kurtosis-tech/awesome-kurtosis.git && cd awesome-kurtosis/smart-contract-example && yarn +``` + +這裡使用的 [smart-contract-example](https://github.com/kurtosis-tech/awesome-kurtosis/tree/main/smart-contract-example) 資料夾包含使用 [Hardhat](https://hardhat.org/) 框架的 dApp 開發者的典型設定: + +- [`contracts/`](https://github.com/kurtosis-tech/awesome-kurtosis/tree/main/smart-contract-example/contracts) 包含一些用於二十一點 dApp 的簡單智能合約 +- [`scripts/`](https://github.com/kurtosis-tech/awesome-kurtosis/tree/main/smart-contract-example/scripts) 包含一個用於將代幣合約部署到您的本地以太坊網路的腳本 +- [`test/`](https://github.com/kurtosis-tech/awesome-kurtosis/tree/main/smart-contract-example/test) 包含一個針對您的代幣合約的簡單 .js 測試,以確認我們的二十一點 dApp 中的每個玩家都已為他們鑄造了 1000 個代幣 +- [`hardhat.config.ts`](https://github.com/kurtosis-tech/awesome-kurtosis/blob/main/smart-contract-example/hardhat.config.ts) 設定您的 Hardhat + +### 設定 Hardhat 以使用本地測試網 {#configure-hardhat} + +設定好您的 dApp 開發環境後,您現在將連接 Hardhat 以使用 Kurtosis 產生的本地以太坊測試網。 為此,請將您的 `hardhat.config.ts` 設定檔中 `localnet` 結構中的 `<$YOUR_PORT>` 替換為任何 `el-client-` 服務輸出的 RPC URI 的連接埠。 在這個範例中,連接埠會是 `64248`。 您的連接埠會不同。 + +`hardhat.config.ts` 中的範例: + +```js +localnet: { +url: 'http://127.0.0.1:<$YOUR_PORT>',// TODO:將 $YOUR_PORT 替換為 ETH NETWORK KURTOSIS 套件產生的節點 URI 的連接埠 + +// 這些是與 eth-network-package 創建的預先注資測試帳戶相關的私鑰 +// +accounts: [ + "ef5177cd0b6b21c87db5a0bf35d4084a8a57a9d6a064f86d51ac85f2b873a4e2", + "48fcc39ae27a0e8bf0274021ae6ebd8fe4a0e12623d61464c498900b28feb567", + "7988b3a148716ff800414935b305436493e1f25237a2a03e5eebc343735e2f31", + "b3c409b6b0b3aa5e65ab2dc1930534608239a478106acf6f3d9178e9f9b00b35", + "df9bb6de5d3dc59595bcaa676397d837ff49441d211878c024eabda2cd067c9f", + "7da08f856b5956d40a72968f93396f6acff17193f013e8053f6fbb6c08c194d6", + ], +}, +``` + +儲存檔案後,您的 Hardhat dApp 開發環境現在已連接到您的本地以太坊測試網! 您可以透過執行以下命令來驗證您的測試網是否正常運作: + +```python +npx hardhat balances --network localnet +``` + +輸出應該類似這樣: + +```python +0x878705ba3f8Bc32FCf7F4CAa1A35E72AF65CF766 has balance 10000000000000000000000000 +0x4E9A3d9D1cd2A2b2371b8b3F489aE72259886f1A has balance 10000000000000000000000000 +0xdF8466f277964Bb7a0FFD819403302C34DCD530A has balance 10000000000000000000000000 +0x5c613e39Fc0Ad91AfDA24587e6f52192d75FBA50 has balance 10000000000000000000000000 +0x375ae6107f8cC4cF34842B71C6F746a362Ad8EAc has balance 10000000000000000000000000 +0x1F6298457C5d76270325B724Da5d1953923a6B88 has balance 10000000000000000000000000 +``` + +這證實了 Hardhat 正在使用您的本地測試網,並偵測到由 `eth-network-package` 創建的預先注資帳戶。 + +### 在本地部署和測試您的 dApp {#deploy-and-test-dapp} + +在 dApp 開發環境完全連接到本地以太坊測試網後,您現在可以使用本地測試網對您的 dApp 執行開發和測試工作流程。 + +要編譯和部署 `ChipToken.sol` 智能合約以進行本地原型設計和開發,請執行: + +```python +npx hardhat compile +npx hardhat run scripts/deploy.ts --network localnet +``` + +輸出應該看起來像: + +```python +ChipToken deployed to: 0xAb2A01BC351770D09611Ac80f1DE076D56E0487d +``` + +現在嘗試對您的本地 dApp 執行 `simple.js` 測試,以確認我們的二十一點 dApp 中的每個玩家都已為他們鑄造了 1000 個代幣: + +輸出應該類似這樣: + +```python +npx hardhat test --network localnet +``` + +輸出應該類似這樣: + +```python +ChipToken + mint + ✔ 應為玩家一號鑄造 1000 枚籌碼 + + 1 個通過 (654ms) +``` + +### 回顧 {#review-dapp-workflows} + +至此,您已經設定了一個 dApp 開發環境,將其連接到由 Kurtosis 創建的本地以太坊網路,並已對您的 dApp 進行了編譯、部署和簡單的測試。 + +現在讓我們來探索如何設定底層網路,以便在不同的網路設定下測試我們的 dApp。 + +## 設定本地以太坊測試網 {#configure-testnet} + +### 變更用戶端設定和節點數量 {#configure-client-config-and-num-nodes} + +您的本地以太坊測試網可以設定為使用不同的 EL 和 CL 用戶端配對,以及不同數量的節點,這取決於您要開發或測試的場景和特定的網路設定。 這意味著,一旦設定完成,您就可以啟動一個客製化的本地測試網,並用它來執行相同的工作流程(部署、測試等) 在各種網路設定下,確保一切如預期般運作。 要了解更多關於您可以修改的其他參數,請造訪此連結。 + +試試看! 您可以透過 JSON 檔案將各種設定選項傳遞給 `eth-network-package`。 這個網路參數 JSON 檔案提供了 Kurtosis 用於設定本地以太坊網路的特定設定。 + +取得預設設定檔案並進行編輯,以啟動兩個具有不同 EL/CL 配對的節點: + +- 節點 1 使用 `geth`/`lighthouse` +- 節點 2 使用 `geth`/`lodestar` +- 節點 3 使用 `geth`/`teku` + +此設定建立了一個異構的以太坊節點實作網路,用於測試您的 dApp。 您的設定檔現在應該如下所示: + +```yaml +{ + "participants": + [ + { + "el_client_type": "geth", + "el_client_image": "", + "el_client_log_level": "", + "cl_client_type": "lighthouse", + "cl_client_image": "", + "cl_client_log_level": "", + "beacon_extra_params": [], + "el_extra_params": [], + "validator_extra_params": [], + "builder_network_params": null, + }, + { + "el_client_type": "geth", + "el_client_image": "", + "el_client_log_level": "", + "cl_client_type": "lodestar", + "cl_client_image": "", + "cl_client_log_level": "", + "beacon_extra_params": [], + "el_extra_params": [], + "validator_extra_params": [], + "builder_network_params": null, + }, + { + "el_client_type": "geth", + "el_client_image": "", + "el_client_log_level": "", + "cl_client_type": "teku", + "cl_client_image": "", + "cl_client_log_level": "", + "beacon_extra_params": [], + "el_extra_params": [], + "validator_extra_params": [], + "builder_network_params": null, + }, + ], + "network_params": + { + "preregistered_validator_keys_mnemonic": "giant issue aisle success illegal bike spike question tent bar rely arctic volcano long crawl hungry vocal artwork sniff fantasy very lucky have athlete", + "num_validator_keys_per_node": 64, + "network_id": "3151908", + "deposit_contract_address": "0x4242424242424242424242424242424242424242", + "seconds_per_slot": 12, + "genesis_delay": 120, + "capella_fork_epoch": 5, + }, +} +``` + +每個 `participants` 結構對應網路中的一個節點,因此 3 個 `participants` 結構將告知 Kurtosis 在您的網路中啟動 3 個節點。 每個 `participants` 結構將允許您指定該特定節點使用的 EL 和 CL 配對。 + +`network_params` 結構設定了用於為每個節點建立創世檔的網路設定,以及其他設定,例如網路的每時隙秒數。 + +將您編輯的參數檔案儲存到您希望的任何目錄中(在下面的範例中,它被儲存到桌面),然後透過執行以下命令來執行您的 Kurtosis 套件: + +```python +kurtosis clean -a && kurtosis run --enclave local-eth-testnet github.com/kurtosis-tech/eth-network-package "$(cat ~/eth-network-params.json)" +``` + +注意:這裡使用 `kurtosis clean -a` 命令來指示 Kurtosis 在啟動新的測試網之前銷毀舊的測試網及其內容。 + +同樣,Kurtosis 會運作一會兒,並印出正在進行的各個步驟。 最終,輸出應該會像這樣: + +```python +Starlark code successfully run. No output was returned. +INFO[2023-04-07T11:43:16-04:00] ========================================================== +INFO[2023-04-07T11:43:16-04:00] || Created enclave: local-eth-testnet || +INFO[2023-04-07T11:43:16-04:00] ========================================================== +Name: local-eth-testnet +UUID: bef8c192008e +Status: RUNNING +Creation Time: Fri, 07 Apr 2023 11:41:58 EDT + +========================================= Files Artifacts ========================================= +UUID Name +cc495a8e364a cl-genesis-data +7033fcdb5471 el-genesis-data +a3aef43fc738 genesis-generation-config-cl +8e968005fc9d genesis-generation-config-el +3182cca9d3cd geth-prefunded-keys +8421166e234f prysm-password +d9e6e8d44d99 validator-keystore-0 +23f5ba517394 validator-keystore-1 +4d28dea40b5c validator-keystore-2 + +========================================== User Services ========================================== +UUID Name Ports Status +485e6fde55ae cl-client-0-beacon http: 4000/tcp -> http://127.0.0.1:65010 RUNNING + metrics: 5054/tcp -> http://127.0.0.1:65011 + tcp-discovery: 9000/tcp -> 127.0.0.1:65012 + udp-discovery: 9000/udp -> 127.0.0.1:54455 +73739bd158b2 cl-client-0-validator http: 5042/tcp -> 127.0.0.1:65016 RUNNING + metrics: 5064/tcp -> http://127.0.0.1:65017 +1b0a233cd011 cl-client-1-beacon http: 4000/tcp -> 127.0.0.1:65021 RUNNING + metrics: 8008/tcp -> 127.0.0.1:65023 + tcp-discovery: 9000/tcp -> 127.0.0.1:65024 + udp-discovery: 9000/udp -> 127.0.0.1:56031 + validator-metrics: 5064/tcp -> 127.0.0.1:65022 +949b8220cd53 cl-client-1-validator http: 4000/tcp -> 127.0.0.1:65028 RUNNING + metrics: 8008/tcp -> 127.0.0.1:65030 + tcp-discovery: 9000/tcp -> 127.0.0.1:65031 + udp-discovery: 9000/udp -> 127.0.0.1:60784 + validator-metrics: 5064/tcp -> 127.0.0.1:65029 +c34417bea5fa cl-client-2 http: 4000/tcp -> 127.0.0.1:65037 RUNNING + metrics: 8008/tcp -> 127.0.0.1:65035 + tcp-discovery: 9000/tcp -> 127.0.0.1:65036 + udp-discovery: 9000/udp -> 127.0.0.1:63581 +e19738e6329d el-client-0 engine-rpc: 8551/tcp -> 127.0.0.1:64986 RUNNING + rpc: 8545/tcp -> 127.0.0.1:64988 + tcp-discovery: 30303/tcp -> 127.0.0.1:64987 + udp-discovery: 30303/udp -> 127.0.0.1:55706 + ws: 8546/tcp -> 127.0.0.1:64989 +e904687449d9 el-client-1 engine-rpc: 8551/tcp -> 127.0.0.1:64993 RUNNING + rpc: 8545/tcp -> 127.0.0.1:64995 + tcp-discovery: 30303/tcp -> 127.0.0.1:64994 + udp-discovery: 30303/udp -> 127.0.0.1:58096 + ws: 8546/tcp -> 127.0.0.1:64996 +ad6f401126fa el-client-2 engine-rpc: 8551/tcp -> 127.0.0.1:65003 RUNNING + rpc: 8545/tcp -> 127.0.0.1:65001 + tcp-discovery: 30303/tcp -> 127.0.0.1:65000 + udp-discovery: 30303/udp -> 127.0.0.1:57269 + ws: 8546/tcp -> 127.0.0.1:65002 +12d04a9dbb69 prelaunch-data-generator-1680882122181135513 STOPPED +5b45f9c0504b prelaunch-data-generator-1680882122192182847 STOPPED +3d4aaa75e218 prelaunch-data-generator-1680882122201668972 STOPPED +``` + +恭喜! 您已成功將您的本地測試網設定為擁有 3 個節點,而不是 1 個。 要在您的 dApp 上執行與之前相同的工作流程(部署和測試),請執行與之前相同的操作,將您的 `hardhat.config.ts` 設定檔中 `localnet` 結構中的 `<$YOUR_PORT>` 替換為您的新的 3 節點本地測試網中任何 `el-client-` 服務輸出的 RPC URI 的連接埠。 + +## 結論 {#conclusion} + +就是這樣! 總結一下本簡短指南,您: + +- 使用 Kurtosis 透過 Docker 建立了一個本地以太坊測試網 +- 將您的本地 dApp 開發環境連接到本地以太坊網路 +- 在本地以太坊網路上部署了一個 dApp 並對其進行了簡單的測試 +- 將底層以太坊網路設定為擁有 3 個節點 + +我們很樂意聽取您對哪些方面進展順利、哪些方面可以改進的意見,或回答您的任何問題。 請隨時透過 [GitHub](https://github.com/kurtosis-tech/kurtosis/issues/new/choose) 或[發送電子郵件給我們](mailto:feedback@kurtosistech.com)與我們聯絡! + +### 其他範例和指南 {#other-examples-guides} + +我們鼓勵您查看我們的[快速入門](https://docs.kurtosis.com/quickstart)(您將在其中建構 Postgres 資料庫和 API)以及我們 [awesome-kurtosis 儲存庫](https://github.com/kurtosis-tech/awesome-kurtosis)中的其他範例,您將在那裡找到一些很棒的範例,包括以下套件: + +- [啟動相同的本地以太坊測試網](https://github.com/kurtosis-tech/eth2-package),但連接了額外的服務,例如交易發送器(以模擬交易)、分叉監視器,以及一個已連接的 Grafana 和 Prometheus 實例 +- 對相同的本地以太坊網路執行[子網路測試](https://github.com/kurtosis-tech/awesome-kurtosis/tree/main/ethereum-network-partition-test) diff --git a/public/content/translations/zh-tw/developers/tutorials/downsizing-contracts-to-fight-the-contract-size-limit/index.md b/public/content/translations/zh-tw/developers/tutorials/downsizing-contracts-to-fight-the-contract-size-limit/index.md new file mode 100644 index 00000000000..bd0e02e2dba --- /dev/null +++ b/public/content/translations/zh-tw/developers/tutorials/downsizing-contracts-to-fight-the-contract-size-limit/index.md @@ -0,0 +1,144 @@ +--- +title: "縮小合約大小來對抗合約大小限制" +description: "你可以怎麼做來防止智能合約規模過大?" +author: Markus Waas +lang: zh-tw +tags: [ "Solidity", "智能合約", "儲存" ] +skill: intermediate +published: 2020-06-26 +source: soliditydeveloper.com +sourceUrl: https://soliditydeveloper.com/max-contract-size +--- + +## 為什麼要有個限制? {#why-is-there-a-limit} + +在 [2016 年 11 月 22 日](https://blog.ethereum.org/2016/11/18/hard-fork-no-4-spurious-dragon/),Spurious Dragon 硬分叉引入了 [EIP-170](https://eips.ethereum.org/EIPS/eip-170),新增了 24.576 kb 的智能合約大小限制。 身為 Solidity 開發者,這代表當你在合約中加入越來越多功能時,在某個時間點你會達到上限,並在部署時看到以下錯誤: + +`Warning: Contract code size exceeds 24576 bytes (a limit introduced in Spurious Dragon). 此合約可能無法在主網上部署。 Consider enabling the optimizer (with a low "runs" value!), turning off revert strings, or using libraries.` + +這個限制是為了防止阻斷服務 (DOS) 攻擊。 對合約的任何呼叫,在 gas 方面都相對便宜。 然而,合約呼叫對以太坊節點的影響,會根據被呼叫的合約程式碼大小(從磁碟讀取程式碼、預處理程式碼、將資料加入默克爾證明)而不成比例地增加。 每當發生攻擊者能以少量資源,造成他人大量工作負擔的情形,便可能產生 DOS 攻擊。 + +起初這問題不大,因為一個天然的合約大小限制就是區塊 gas 上限。 顯然,合約必須部署在一個包含其所有位元組碼的交易中。 如果你只在一個區塊中包含那筆交易,你可以用完所有的 gas,但它不是無限的。 自 [倫敦升級](/ethereum-forks/#london) 以來,區塊 gas 上限可以根據網路需求在 1500 萬到 3000 萬單位之間變動。 + +接下來,我們將按照潛在影響力的大小,來看看一些方法。 可以把它想像成減重。 一個人要達到目標體重(在我們的情況下是 24kb)的最佳策略是先專注於影響力大的方法。 在大多數情況下,單靠調整飲食就能達標,但有時候你需要做的更多一點。 然後你可能會增加一些運動(中等影響),或甚至營養補充品(小影響)。 + +## 重大影響 {#big-impact} + +### 拆分你的合約 {#separate-your-contracts} + +這應該永遠是你的首選方法。 你如何將合約拆分成多個較小的合約? 這通常會迫使你為合約設計一個好的架構。 從程式碼可讀性的角度來看,小合約總是比較好。 要拆分合約,可以問自己: + +- 哪些函式屬於同一組? 每一組函式可能最適合放在各自的合約中。 +- 哪些函式不需要讀取合約狀態,或只需要讀取狀態的特定子集? +- 你能將儲存空間和功能性拆分開來嗎? + +### 函式庫 {#libraries} + +一個將功能性程式碼從儲存空間移開的簡單方法是使用[函式庫](https://solidity.readthedocs.io/en/v0.6.10/contracts.html#libraries)。 不要將函式庫的函式宣告為 internal,因為它們會在編譯期間直接被[加到合約中](https://ethereum.stackexchange.com/questions/12975/are-internal-functions-in-libraries-not-covered-by-linking)。 但如果你使用 public 函式,那麼它們實際上會存在一個獨立的函式庫合約中。 可以考慮 [using for](https://solidity.readthedocs.io/en/v0.6.10/contracts.html#using-for) 讓函式庫的使用更方便。 + +### 代理 {#proxies} + +一個更進階的策略是代理系統。 函式庫在後端使用 `DELEGATECALL`,它只是用呼叫合約的狀態來執行另一個合約的函式。 查看[這篇部落格文章](https://hackernoon.com/how-to-make-smart-contracts-upgradable-2612e771d5a2),以了解更多關於代理系統的資訊。 它們提供你更多功能,例如,它們能讓合約可以升級,但也增加了許多複雜性。 除非出於某些原因這是你唯一的選擇,否則我不會只為了縮小合約大小而加入這些。 + +## 中等影響 {#medium-impact} + +### 移除函式 {#remove-functions} + +這點應該很明顯。 函式會增加不少合約大小。 + +- **External**:我們時常為了方便而加入許多 view 函式。 在你碰到大小限制之前,這完全沒問題。 那時你可能就得認真考慮,只保留絕對必要的函式,並移除其他的。 +- **Internal**:你也可以移除 internal/private 函式,並只要該函式只被呼叫一次,就直接內聯 (inline) 其程式碼。 + +### 避免額外的變數 {#avoid-additional-variables} + +```solidity +function get(uint id) returns (address,address) { + MyStruct memory myStruct = myStructs[id]; + return (myStruct.addr1, myStruct.addr2); +} +``` + +```solidity +function get(uint id) returns (address,address) { + return (myStructs[id].addr1, myStructs[id].addr2); +} +``` + +像這樣一個簡單的改變,就差了 **0.28kb**。 你的合約中很可能有很多類似的情況,這些情況累積起來的量可能相當可觀。 + +### 縮短錯誤訊息 {#shorten-error-message} + +長的 revert 訊息,特別是許多不同的 revert 訊息,會讓合約膨脹。 改用簡短的錯誤碼,並在你的合約中解碼它們。 一則長訊息可以變得更短: + +```solidity +require(msg.sender == owner, "Only the owner of this contract can call this function"); +``` + +```solidity +require(msg.sender == owner, "OW1"); +``` + +### 使用自訂錯誤而非錯誤訊息 + +[Solidity 0.8.4](https://blog.soliditylang.org/2021/04/21/custom-errors/) 引入了自訂錯誤。 它們是減少合約大小的好方法,因為它們會被 ABI 編碼為選擇器(就像函式一樣)。 + +```solidity +error Unauthorized(); + +if (msg.sender != owner) { + revert Unauthorized(); +} +``` + +### 在優化器中考慮使用較低的 run 值 {#consider-a-low-run-value-in-the-optimizer} + +你也可以更改優化器的設定。 預設值 200 代表它會試著優化位元組碼,就像函式被呼叫 200 次一樣。 如果你將它改為 1,基本上就是告訴優化器,針對每個函式只執行一次的情況進行優化。 一個為執行一次而優化的函式,代表它是為部署本身而優化。 請注意,**這會增加執行函式的 [gas 成本](/developers/docs/gas/)**,所以你可能不想這麼做。 + +## 微小影響 {#small-impact} + +### 避免將 struct 傳遞給函式 {#avoid-passing-structs-to-functions} + +如果你正在使用 [ABIEncoderV2](https://solidity.readthedocs.io/en/v0.6.10/layout-of-source-files.html#abiencoderv2),不將 struct 傳遞給函式會有所幫助。 不要將參數作為 struct 傳遞,而是直接傳遞所需的參數。 在這個範例中,我們又節省了 **0.1kb**。 + +```solidity +function get(uint id) returns (address,address) { + return _get(myStruct); +} + +function _get(MyStruct memory myStruct) private view returns(address,address) { + return (myStruct.addr1, myStruct.addr2); +} +``` + +```solidity +function get(uint id) returns(address,address) { + return _get(myStructs[id].addr1, myStructs[id].addr2); +} + +function _get(address addr1, address addr2) private view returns(address,address) { + return (addr1, addr2); +} +``` + +### 為函式和變數宣告正確的可見性 {#declare-correct-visibility-for-functions-and-variables} + +- 只會從外部呼叫的函式或變數? 將它們宣告為 `external` 而不是 `public`。 +- 只在合約內部呼叫的函式或變數? 將它們宣告為 `private` 或 `internal` 而不是 `public`。 + +### 移除修飾符 {#remove-modifiers} + +修飾符,特別是當大量使用時,可能對合約大小產生重大影響。 考慮移除它們,改用函式。 + +```solidity +modifier checkStuff() {} + +function doSomething() checkStuff {} +``` + +```solidity +function checkStuff() private {} + +function doSomething() { checkStuff(); } +``` + +這些技巧應該能幫助你大幅縮小合約大小。 再次強調,如果可能的話,請務必專注於拆分合約,以達到最大的影響。 diff --git a/public/content/translations/zh-tw/developers/tutorials/eip-1271-smart-contract-signatures/index.md b/public/content/translations/zh-tw/developers/tutorials/eip-1271-smart-contract-signatures/index.md new file mode 100644 index 00000000000..a0b40fe862d --- /dev/null +++ b/public/content/translations/zh-tw/developers/tutorials/eip-1271-smart-contract-signatures/index.md @@ -0,0 +1,123 @@ +--- +title: "EIP-1271:簽署與驗證智能合約簽章" +description: "使用 EIP-1271 生成與驗證智能合約簽章的概覽。 我們也會逐步說明 Safe (前身為 Gnosis Safe) 中使用的 EIP-1271 實作,為智能合約開發者提供具體範例以供參考。" +author: Nathan H. Leung +lang: zh-tw +tags: [ "eip-1271", "智能合約", "驗證", "簽署" ] +skill: intermediate +published: 2023-01-12 +--- + +[EIP-1271](https://eips.ethereum.org/EIPS/eip-1271) 標準允許智能合約驗證簽章。 + +在本教學中,我們將概覽數位簽章、EIP-1271 的背景,以及 [Safe](https://safe.global/) (前身為 Gnosis Safe) 所使用的 EIP-1271 特定實作。 總而言之,本篇內容可作為您在自己的合約中實作 EIP-1271 的起點。 + +## 什麼是簽章? + +在此背景下,簽章 (更準確地說,是「數位簽章」) 是一則訊息,加上某种證明,用以證明該訊息來自特定人士/傳送者/地址。 + +例如,數位簽章可能長這樣: + +1. 訊息:「我想用我的以太坊錢包登入這個網站。」 +2. 簽署者:我的地址是 `0x000…` +3. 證明:這是一些證明,證明我 (`0x000…`) 確實建立了這整則訊息 (這通常是某种加密的東西)。 + +請務必注意,數位簽章同時包含「訊息」與「簽章」。 + +為什麼? 舉例來說,如果您給我一份合約簽署,然後我把簽章頁撕下來,只把我的簽章還給您,而沒有合約的其他部分,那麼這份合約將無效。 + +同樣地,如果沒有相關的訊息,數位簽章就沒有任何意義! + +## EIP-1271 為何存在? + +為了建立在以太坊區塊鏈上使用的數位簽章,您通常需要一個其他人不知道的秘密私密金鑰。 這就是為什麼您的簽章專屬於您 (沒有其他人能在不知道秘密金鑰的情況下建立相同的簽章)。 + +您的以太坊帳戶 (即您的外部擁有帳戶/EOA) 有一個與其關聯的私密金鑰,當網站或去中心化應用程式要求您簽章 (例如,「用以太坊登入」) 時,通常會使用此私密金鑰。 + +應用程式可以使用 ethers.js 等第三方庫來 [驗證您建立的簽章](https://www.alchemy.com/docs/how-to-verify-a-message-signature-on-ethereum),且 [無需知道您的私密金鑰](https://en.wikipedia.org/wiki/Public-key_cryptography),並確信該簽章是由_您_所建立的。 + +> 事實上,由於 EOA 數位簽章使用公開金鑰密碼學,因此可以在**鏈外**生成與驗證! 這就是無 Gas 的 DAO 投票的運作方式 — 不在鏈上提交投票,而是使用加密庫在鏈外建立和驗證數位簽章。 + +雖然 EOA 帳戶有私密金鑰,但智能合約帳戶沒有任何形式的私密或秘密金鑰 (因此「用以太坊登入」等功能無法原生支援智能合約帳戶)。 + +EIP-1271 旨在解決的問題是:如果智能合約沒有可以納入簽章的「秘密」,我們如何判斷智能合約簽章是否有效? + +## EIP-1271 如何運作? + +智能合約沒有可用於簽署訊息的私密金鑰。 那麼,我們如何判斷簽章是否真實? + +嗯,一個想法是我們可以直接_詢問_智能合約簽章是否真實! + +EIP-1271 的作用是將「詢問」智能合約特定簽章是否有效的這個想法標準化。 + +實作 EIP-1271 的合約必須有一個名為 `isValidSignature` 的函式,該函式接收一個訊息和一個簽章。 然後,合約可以執行一些驗證邏輯 (規範在此處並未強制要求任何具體內容),然後傳回一個值,指出簽章是否有效。 + +如果 `isValidSignature` 傳回有效結果,這基本上就等於合約在說:「是的,我批准這個簽章 + 訊息!」 + +### 接口 + +以下是 EIP-1271 規範中的確切介面 (我們稍後會討論 `_hash` 參數,但現在,您可以將其視為正在驗證的訊息): + +```jsx +pragma solidity ^0.5.0; + +contract ERC1271 { + + // bytes4(keccak256("isValidSignature(bytes32,bytes)") + bytes4 constant internal MAGICVALUE = 0x1626ba7e; + + /** + * @dev 應傳回所提供的簽章對於所提供的哈希是否有效 + * @param _hash 待簽署資料的哈希 + * @param _signature 與 _hash 相關的簽章位元組陣列 + * + * 函式通過時必須傳回 bytes4 魔術值 0x1626ba7e。 + * 不得修改狀態 (對於 solc < 0.5 使用 STATICCALL,對於 solc > 0.5 使用 view 修飾符) + * 必須允許外部呼叫 + */ + function isValidSignature( + bytes32 _hash, + bytes memory _signature) + public + view + returns (bytes4 magicValue); +} +``` + +## EIP-1271 實作範例:Safe + +合約可以透過多種方式實作 `isValidSignature` — 該規範對於確切的實作方式並未多加說明。 + +一個實作 EIP-1271 的知名合約是 Safe (前身為 Gnosis Safe)。 + +在 Safe 的程式碼中,`isValidSignature` 的 [實作方式](https://github.com/safe-global/safe-contracts/blob/main/contracts/handler/CompatibilityFallbackHandler.sol) 讓簽章可以透過 [兩種方式](https://ethereum.stackexchange.com/questions/122635/signing-messages-as-a-gnosis-safe-eip1271-support) 建立與驗證: + +1. 鏈上訊息 + 1. 建立:Safe 持有者建立一筆新的 Safe 交易來「簽署」一則訊息,並將該訊息作為資料傳入交易中。 一旦有足夠的持有者簽署交易,達到多重簽章門檻,交易就會被廣播並執行。 在交易中,有一個名為 (`signMessage(bytes calldata _data)`) 的 Safe 函式,它會將訊息新增到「已批准」的訊息清單中。 + 2. 驗證:在 Safe 合約上呼叫 `isValidSignature`,並將要驗證的訊息作為訊息參數傳入,同時為簽章參數傳入 [一個空值](https://github.com/safe-global/safe-contracts/blob/main/contracts/handler/CompatibilityFallbackHandler.sol#L32) (即 `0x`)。 Safe 將會看到簽章參數為空,於是便不會以加密方式驗證簽章,而是會直接檢查該訊息是否在「已批准」的訊息清單上。 +2. 鏈外訊息: + 1. 建立:Safe 持有者在鏈外建立一則訊息,然後讓其他 Safe 持有者各自簽署該訊息,直到簽章數量足以超過多重簽章批准門檻為止。 + 2. 驗證:呼叫 `isValidSignature`。 在訊息參數中,傳入要驗證的訊息。 在簽章參數中,將每個 Safe 持有者的個人簽章一個接一個地串接起來傳入。 Safe 將會檢查是否有足夠的簽章來滿足門檻,**並且**每個簽章都有效。 如果是,它將傳回一個值,表示簽章驗證成功。 + +## `_hash` 參數到底是什麼? 為什麼不傳遞整個訊息? + +您可能已經注意到,[EIP-1271 介面](https://eips.ethereum.org/EIPS/eip-1271) 中的 `isValidSignature` 函式並非直接接收訊息本身,而是接收一個 `_hash` 參數。 這表示我們不是將完整的任意長度訊息傳遞給 `isValidSignature`,而是傳遞該訊息的 32 位元組哈希 (通常是 keccak256)。 + +calldata 的每個位元組 — 也就是傳遞給智能合約函式的函式參數資料 — [會花費 16 gas (如果為零位元組則為 4 gas)](https://eips.ethereum.org/EIPS/eip-2028),因此如果訊息很長,這樣可以節省大量 gas。 + +### 先前的 EIP-1271 規範 + +現存的一些 EIP-1271 規範中,`isValidSignature` 函式的第一個參數類型為 `bytes` (任意長度,而非固定長度的 `bytes32`),且參數名稱為 `message`。 這是 EIP-1271 標準的 [舊版](https://github.com/safe-global/safe-contracts/issues/391#issuecomment-1075427206)。 + +## 應如何在自己的合約中實作 EIP-1271? + +規範在此處非常有彈性。 Safe 的實作有一些不錯的想法: + +- 您可以將來自合約「持有者」的 EOA 簽章視為有效。 +- 您可以儲存一份已批准的訊息清單,並只將這些訊息視為有效。 + +最終,這取決於您這位合約開發者! + +## 結論 + +[EIP-1271](https://eips.ethereum.org/EIPS/eip-1271) 是一個多功能的標準,允許智能合約驗證簽章。 它為智能合約開啟了大門,讓它們的行為更像 EOA — 例如,為「用以太坊登入」提供了一種與智能合約搭配運作的方式 — 並且可以透過多種方式實作 (Safe 有一個值得考慮的、非同小可且有趣的實作)。 diff --git a/public/content/translations/zh-tw/developers/tutorials/erc-721-vyper-annotated-code/index.md b/public/content/translations/zh-tw/developers/tutorials/erc-721-vyper-annotated-code/index.md new file mode 100644 index 00000000000..5835cb1c427 --- /dev/null +++ b/public/content/translations/zh-tw/developers/tutorials/erc-721-vyper-annotated-code/index.md @@ -0,0 +1,646 @@ +--- +title: "Vyper ERC-721 合約逐步解說" +description: "Ryuya Nakamura 的 ERC-721 合約及其運作方式" +author: Ori Pomerantz +lang: zh-tw +tags: [ "Vyper", "erc-721", "Python" ] +skill: beginner +published: 2021-04-01 +--- + +## 介紹 {#introduction} + +[ERC-721](/developers/docs/standards/tokens/erc-721/) 標準是用於持有非同質化代幣 (NFT) 所有權的標準。 +[ERC-20](/developers/docs/standards/tokens/erc-20/) 代幣的行為類似商品,因為個別代幣之間沒有任何區別。 +與之對比,ERC-721 代幣是為相似但不相同的資產所設計,例如不同的貓 +卡通或不同房地產的所有權狀。 + +在本文中,我們將分析 [Ryuya Nakamura 的 ERC-721 合約](https://github.com/vyperlang/vyper/blob/master/examples/tokens/ERC721.vy)。 +此合約以 [Vyper](https://vyper.readthedocs.io/en/latest/index.html) 編寫,這是一種近似 Python 的合約語言,其設計目的是讓編寫不安全的程式碼比在 Solidity 中更困難。 + +## 合約 {#contract} + +```python +# @dev ERC-721 非同質化代幣標準的實作。 +# @author Ryuya Nakamura (@nrryuya) +# 修改自:https://github.com/vyperlang/vyper/blob/de74722bf2d8718cca46902be165f9fe0e3641dd/examples/tokens/ERC721.vy +``` + +Vyper 中的註解與 Python 相同,以井字號 (`#`) 開頭,並一直延續到該行結尾。 包含 `@<關鍵字>` 的註解會由 [NatSpec](https://vyper.readthedocs.io/en/latest/natspec.html) 用來產生人類可讀的文件。 + +```python +from vyper.interfaces import ERC721 + +implements: ERC721 +``` + +ERC-721 介面內建於 Vyper 語言中。 +[你可以在這裡看到程式碼定義](https://github.com/vyperlang/vyper/blob/master/vyper/builtin_interfaces/ERC721.py)。 +介面定義是以 Python 而非 Vyper 編寫的,因為介面不僅在區塊鏈內部使用,也用於從可能以 Python 編寫的外部用戶端向區塊鏈傳送交易。 + +第一行匯入介面,第二行則指明我們在此處實作該介面。 + +### ERC721Receiver 介面 {#receiver-interface} + +```python +# safeTransferFrom() 呼叫的合約介面 +interface ERC721Receiver: + def onERC721Received( +``` + +ERC-721 支援兩種轉移類型: + +- `transferFrom`,它讓傳送方可以指定任何目標地址,並將轉移的責任歸於傳送方。 這意味著你可以轉移到無效地址,在這種情況下,NFT 將會永久遺失。 +- `safeTransferFrom`,它會檢查目標地址是否為合約。 若是,ERC-721 合約會詢問接收合約是否願意接收該 NFT。 + +為了回應 `safeTransferFrom` 的請求,接收合約必須實作 `ERC721Receiver`。 + +```python + _operator: address, + _from: address, +``` + +`_from` 地址是代幣的目前擁有者。 `_operator` 地址是請求轉移的地址 (由於有授權額度的關係,這兩個地址可能不相同)。 + +```python + _tokenId: uint256, +``` + +ERC-721 代幣 ID 是 256 位元。 一般而言,它們是透過對代幣所代表之物的描述進行哈希運算而建立的。 + +```python + _data: Bytes[1024] +``` + +此請求最多可包含 1024 位元組的使用者資料。 + +```python + ) -> bytes32: view +``` + +為防止合約意外接受轉移的情況,傳回值不是布林值,而是帶有特定值的 256 位元數值。 + +此函式為 `view` 函式,代表它可以讀取區塊鏈的狀態,但不能修改它。 + +### Events {#events} + +[事件](https://media.consensys.net/technical-introduction-to-events-and-logs-in-ethereum-a074d65dd61e) +會被發出以通知區塊鏈外部的使用者和伺服器發生的事件。 請注意,事件的內容對於區塊鏈上的合約是不可用的。 + +```python +# @dev 當任何 NFT 的所有權因任何機制發生變更時發出。當 NFT 被 +# 建立 (`from` == 0) 和銷毀 (`to` == 0) 時會發出此事件。例外:在合約建立期間,可以 +# 建立並指派任意數量的 NFT 而不發出 Transfer 事件。在任何 +# 轉移時,該 NFT 的核准地址 (若有) 會被重設為無。 +# @param _from NFT 的傳送方 (若地址為零地址,則表示代幣建立)。 +# @param _to NFT 的接收方 (若地址為零地址,則表示代幣銷毀)。 +# @param _tokenId 已轉移的 NFT。 +event Transfer: + sender: indexed(address) + receiver: indexed(address) + tokenId: indexed(uint256) +``` + +這與 ERC-20 的 Transfer 事件相似,差別在於我們回報的是 `tokenId` 而非數量。 +沒有人擁有零地址,因此按照慣例,我們用它來回報代幣的建立和銷毀。 + +```python +# @dev 當一個 NFT 的核准地址被變更或再次確認時發出。零 +# 地址表示沒有核准地址。當 Transfer 事件發出時,這也 +# 表示該 NFT 的核准地址 (若有) 被重設為無。 +# @param _owner NFT 的擁有者。 +# @param _approved 我們正在核准的地址。 +# @param _tokenId 我們正在核准的 NFT。 +event Approval: + owner: indexed(address) + approved: indexed(address) + tokenId: indexed(uint256) +``` + +ERC-721 的核准類似於 ERC-20 的授權額度。 一個特定的地址被允許轉移一個特定的代幣。 這提供了一種機制,讓合約在接受代幣時能夠做出回應。 合約無法監聽事件,所以如果你只是將代幣轉移給它們,它們不會「知道」這件事。 這樣一來,擁有者首先提交一項核准,然後向合約傳送請求:"我已核准你轉移代幣 +X,請執行..."。 + +這是一項設計上的選擇,目的是讓 ERC-721 標準與 ERC-20 標準相似。 由於 ERC-721 代幣並非同質化代幣,合約也可以透過查看代幣的所有權來識別它是否取得了特定的代幣。 + +```python +# @dev 當擁有者的操作員被啟用或停用時發出。操作員可以管理 +# 該擁有者的所有 NFT。 +# @param _owner NFT 的擁有者。 +# @param _operator 我們要為其設定操作員權限的地址。 +# @param _approved 操作員權限的狀態 (true 表示授予操作員權限,false 表示 +# 撤銷)。 +event ApprovalForAll: + owner: indexed(address) + operator: indexed(address) + approved: bool +``` + +有時候,有一個可以管理某帳戶所有特定類型代幣(由特定合約管理的代幣)的_操作員_是很有用的,這類似於授權書。 例如,我可能會想將此權力賦予一個合約,讓它檢查我是否六個月未與其聯繫,若是,則將我的資產分配給我的繼承人 (前提是其中一位繼承人提出請求,因為合約若無交易呼叫則無法執行任何動作)。 在 ERC-20 中,我們可以只給予繼承合約一個高額的授權額度,但這在 ERC-721 中行不通,因為其代幣並非同質化的。 這就是等效的做法。 + +`approved` 值告訴我們該事件是進行核准,還是撤銷核准。 + +### 狀態變數 {#state-vars} + +這些變數包含代幣的目前狀態:哪些是可用的以及誰擁有它們。 這些變數大部分是 `HashMap` 物件,是[存在於兩種類型之間的單向映射](https://vyper.readthedocs.io/en/latest/types.html#mappings)。 + +```python +# @dev 從 NFT ID 到其擁有者地址的映射。 +idToOwner: HashMap[uint256, address] + +# @dev 從 NFT ID 到核准地址的映射。 +idToApprovals: HashMap[uint256, address] +``` + +在以太坊中,使用者和合約的身分由 160 位元的地址表示。 這兩個變數從代幣 ID 映射到其擁有者以及被核准轉移它們的人 (每個代幣最多一個)。 在以太坊中,未初始化的資料始終為零,所以如果沒有擁有者或核准的轉移者,該代幣的值就是零。 + +```python +# @dev 從擁有者地址到其代幣數量的映射。 +ownerToNFTokenCount: HashMap[address, uint256] +``` + +此變數持有每個擁有者的代幣數量。 由於沒有從擁有者到代幣的映射,所以識別特定擁有者所擁有的代幣的唯一方法是回顧區塊鏈的事件歷史,並查看相應的 `Transfer` 事件。 我們可以使用這個變數來知道我們何時擁有了所有的 NFT,而不需要再回溯更早的時間。 + +請注意,此演算法僅適用於使用者介面和外部伺服器。 在區塊鏈上執行的程式碼本身無法讀取過去的事件。 + +```python +# @dev 從擁有者地址到操作員地址映射的映射。 +ownerToOperators: HashMap[address, HashMap[address, bool]] +``` + +一個帳戶可能有多個操作員。 一個簡單的 `HashMap` 並不足以追蹤它們,因為每個鍵只會對應到一個值。 取而代之,你可以使用 `HashMap[address, bool]` 作為值。 預設情況下,每個地址的值為 `False`,這意味著它不是操作員。 你可以視需要將值設定為 `True`。 + +```python +# @dev 鑄幣者的地址,可以鑄造代幣 +minter: address +``` + +新代幣必須以某種方式被建立出來。 在此合約中,只有一個實體被允許這麼做,即 `minter` (鑄幣者)。 例如,對於一個遊戲來說,這可能就足夠了。 對於其他目的,可能需要建立更複雜的商業邏輯。 + +```python +# @dev 從介面 ID 到布林值的映射,代表是否支援該介面 +supportedInterfaces: HashMap[bytes32, bool] + +# @dev ERC165 的 ERC165 介面 ID +ERC165_INTERFACE_ID: constant(bytes32) = 0x0000000000000000000000000000000000000000000000000000000001ffc9a7 + +# @dev ERC721 的 ERC165 介面 ID +ERC721_INTERFACE_ID: constant(bytes32) = 0x0000000000000000000000000000000000000000000000000000000080ac58cd +``` + +[ERC-165](https://eips.ethereum.org/EIPS/eip-165) 規定了一種機制,讓合約能夠揭露應用程式可以如何與其通訊,以及它遵循哪些 ERC 標準。 在此例中,合約遵循 ERC-165 和 ERC-721。 + +### 函數 {#functions} + +這些是實際實作 ERC-721 的函式。 + +#### 建構函式 {#constructor} + +```python +@external +def __init__(): +``` + +在 Vyper 中,與 Python 相同,建構函式稱為 `__init__`。 + +```python + """ + @dev 合約建構函式。 + """ +``` + +在 Python 和 Vyper 中,你也可以透過指定一個多行字串 (以 `"""` 開頭和結尾) 且不以任何方式使用它來建立註解。 這些註解也可以包含 [NatSpec](https://vyper.readthedocs.io/en/latest/natspec.html)。 + +```python + self.supportedInterfaces[ERC165_INTERFACE_ID] = True + self.supportedInterfaces[ERC721_INTERFACE_ID] = True + self.minter = msg.sender +``` + +若要存取狀態變數,請使用 `self.<變數名稱>` (同樣,這和 Python 一樣)。 + +#### 檢視函式 {#views} + +這些函式不會修改區塊鏈的狀態,因此如果從外部呼叫它們,可以免費執行。 如果檢視函式是由合約呼叫的,它們仍然必須在每個節點上執行,因此會產生 gas 費用。 + +```python +@view +@external +``` + +在函式定義之前,以 at 符號 (`@`) 開頭的這些關鍵字稱為_裝飾器_。 它們指定了可以呼叫函式的條件。 + +- `@view` 指定此函式為檢視函式。 +- `@external` 指定此特定函式可由交易和其他合約呼叫。 + +```python +def supportsInterface(_interfaceID: bytes32) -> bool: +``` + +與 Python 不同,Vyper 是一種[靜態型別語言](https://wikipedia.org/wiki/Type_system#Static_type_checking)。 +若不指定[資料類型](https://vyper.readthedocs.io/en/latest/types.html),則無法宣告變數或函式參數。 在此例中,輸入參數為 `bytes32`,一個 256 位元的值 (256 位元是 [以太坊虛擬機](/developers/docs/evm/) 的原生字組大小)。 輸出是一個布林值。 按照慣例,函式參數的名稱以下底線 (`_`) 開頭。 + +```python + """ + @dev 介面識別在 ERC-165 中指定。 + @param _interfaceID 介面的 ID + """ + return self.supportedInterfaces[_interfaceID] +``` + +從 `self.supportedInterfaces` HashMap 傳回值,該值在建構函式 (`__init__`) 中設定。 + +```python +### 檢視函式 ### + +``` + +這些是讓使用者和其他合約能取得代幣相關資訊的檢視函式。 + +```python +@view +@external +def balanceOf(_owner: address) -> uint256: + """ + @dev 傳回 `_owner` 擁有的 NFT 數量。 + 如果 `_owner` 是零地址,則會擲出錯誤。指派給零地址的 NFT 被視為無效。 + @param _owner 要查詢餘額的地址。 + """ + assert _owner != ZERO_ADDRESS +``` + +此行[斷言](https://vyper.readthedocs.io/en/latest/statements.html#assert)`_owner` 不為零。 如果為零,則會出現錯誤並且操作將被還原。 + +```python + return self.ownerToNFTokenCount[_owner] + +@view +@external +def ownerOf(_tokenId: uint256) -> address: + """ + @dev 傳回 NFT 擁有者的地址。 + 如果 `_tokenId` 不是有效的 NFT,則會擲出錯誤。 + @param _tokenId NFT 的識別碼。 + """ + owner: address = self.idToOwner[_tokenId] + # 如果 `_tokenId` 不是有效的 NFT,則會擲出錯誤 + assert owner != ZERO_ADDRESS + return owner +``` + +在以太坊虛擬機 (evm) 中,任何沒有儲存值的儲存空間都為零。 +如果 `_tokenId` 沒有代幣,則 `self.idToOwner[_tokenId]` 的值為零。 在這種情況下,函式會還原。 + +```python +@view +@external +def getApproved(_tokenId: uint256) -> address: + """ + @dev 取得單一 NFT 的核准地址。 + 如果 `_tokenId` 不是有效的 NFT,則會擲出錯誤。 + @param _tokenId 要查詢核准的 NFT ID。 + """ + # 如果 `_tokenId` 不是有效的 NFT,則會擲出錯誤 + assert self.idToOwner[_tokenId] != ZERO_ADDRESS + return self.idToApprovals[_tokenId] +``` + +注意,`getApproved` _可以_傳回零。 如果代幣有效,它會傳回 `self.idToApprovals[_tokenId]`。 +如果沒有核准者,該值為零。 + +```python +@view +@external +def isApprovedForAll(_owner: address, _operator: address) -> bool: + """ + @dev 檢查 `_operator` 是否為 `_owner` 的核准操作員。 + @param _owner 擁有 NFT 的地址。 + @param _operator 代表擁有者行事的地址。 + """ + return (self.ownerToOperators[_owner])[_operator] +``` + +此函式檢查 `_operator` 是否被允許管理此合約中 `_owner` 的所有代幣。 +因為可以有多個操作員,這是一個兩層的 HashMap。 + +#### 轉移輔助函式 {#transfer-helpers} + +這些函式實作了轉移或管理代幣的部分操作。 + +```python + +### 轉移函式輔助工具 ### + +@view +@internal +``` + +這個裝飾器 `@internal` 表示該函式只能在同一個合約內的其他函式中存取。 按照慣例,這些函式名稱也以下底線 (`_`) 開頭。 + +```python +def _isApprovedOrOwner(_spender: address, _tokenId: uint256) -> bool: + """ + @dev 傳回給定的花費者是否可以轉移給定的代幣 ID + @param spender 要查詢的花費者地址 + @param tokenId 要轉移的代幣的 uint256 ID + @return bool 表示 msg.sender 是否被核准用於給定的代幣 ID、 + 是否為擁有者的操作員,或是否為代幣的擁有者 + """ + owner: address = self.idToOwner[_tokenId] + spenderIsOwner: bool = owner == _spender + spenderIsApproved: bool = _spender == self.idToApprovals[_tokenId] + spenderIsApprovedForAll: bool = (self.ownerToOperators[owner])[_spender] + return (spenderIsOwner or spenderIsApproved) or spenderIsApprovedForAll +``` + +有三種方式可以讓一個地址被允許轉移代幣: + +1. 該地址是代幣的擁有者 +2. 該地址被核准花費該代幣 +3. 該地址是代幣擁有者的操作員 + +上面的函式可以是檢視函式,因為它不會改變狀態。 為了降低操作成本,任何_可以_成為檢視函式的函式都_應該_是檢視函式。 + +```python +@internal +def _addTokenTo(_to: address, _tokenId: uint256): + """ + @dev 將 NFT 新增到給定地址 + 如果 `_tokenId` 已被他人擁有,則會擲出錯誤。 + """ + # 如果 `_tokenId` 已被他人擁有,則會擲出錯誤 + assert self.idToOwner[_tokenId] == ZERO_ADDRESS + # 變更擁有者 + self.idToOwner[_tokenId] = _to + # 變更計數追蹤 + self.ownerToNFTokenCount[_to] += 1 + + +@internal +def _removeTokenFrom(_from: address, _tokenId: uint256): + """ + @dev 從給定地址移除 NFT + 如果 `_from` 不是目前的擁有者,則會擲出錯誤。 + """ + # 如果 `_from` 不是目前的擁有者,則會擲出錯誤 + assert self.idToOwner[_tokenId] == _from + # 變更擁有者 + self.idToOwner[_tokenId] = ZERO_ADDRESS + # 變更計數追蹤 + self.ownerToNFTokenCount[_from] -= 1 +``` + +當轉移出現問題時,我們會還原該呼叫。 + +```python +@internal +def _clearApproval(_owner: address, _tokenId: uint256): + """ + @dev 清除給定地址的核准 + 如果 `_owner` 不是目前的擁有者,則會擲出錯誤。 + """ + # 如果 `_owner` 不是目前的擁有者,則會擲出錯誤 + assert self.idToOwner[_tokenId] == _owner + if self.idToApprovals[_tokenId] != ZERO_ADDRESS: + # 重設核准 + self.idToApprovals[_tokenId] = ZERO_ADDRESS +``` + +只有在必要時才變更值。 狀態變數存在儲存空間中。 寫入儲存空間是 EVM (以太坊虛擬機) 執行成本最昂貴的操作之一 (以 [gas](/developers/docs/gas/) 費用計算)。 因此,最好盡量減少寫入,即使寫入現有值也具有高成本。 + +```python +@internal +def _transferFrom(_from: address, _to: address, _tokenId: uint256, _sender: address): + """ + @dev 執行 NFT 的轉移。 + 除非 `msg.sender` 是目前的擁有者、授權的操作員或此 NFT 的核准 + 地址,否則會擲出錯誤。(注意:私有函式中不允許 `msg.sender`,所以傳入 `_sender`。) + 如果 `_to` 是零地址,則會擲出錯誤。 + 如果 `_from` 不是目前的擁有者,則會擲出錯誤。 + 如果 `_tokenId` 不是有效的 NFT,則會擲出錯誤。 + """ +``` + +我們有這個內部函式,因為有兩種轉移代幣的方式 (常規和安全),但我們希望只在程式碼中的一個位置執行它,以便於審核。 + +```python + # 檢查需求 + assert self._isApprovedOrOwner(_sender, _tokenId) + # 如果 `_to` 是零地址,則會擲出錯誤 + assert _to != ZERO_ADDRESS + # 清除核准。如果 `_from` 不是目前的擁有者,則會擲出錯誤 + self._clearApproval(_from, _tokenId) + # 移除 NFT。如果 `_tokenId` 不是有效的 NFT,則會擲出錯誤 + self._removeTokenFrom(_from, _tokenId) + # 新增 NFT + self._addTokenTo(_to, _tokenId) + # 記錄轉移 + log Transfer(_from, _to, _tokenId) +``` + +若要在 Vyper 中發出事件,請使用 `log` 陳述式 ([在此處查看更多詳細資訊](https://vyper.readthedocs.io/en/latest/event-logging.html#event-logging))。 + +#### 轉移函式 {#transfer-funs} + +```python + +### 轉移函式 ### + +@external +def transferFrom(_from: address, _to: address, _tokenId: uint256): + """ + @dev 除非 `msg.sender` 是目前的擁有者、授權的操作員或此 NFT 的核准 + 地址,否則會擲出錯誤。 + 如果 `_from` 不是目前的擁有者,則會擲出錯誤。 + 如果 `_to` 是零地址,則會擲出錯誤。 + 如果 `_tokenId` 不是有效的 NFT,則會擲出錯誤。 + @notice 呼叫者有責任確認 `_to` 能夠接收 NFT,否則 + 它們可能會永久遺失。 + @param _from NFT 的目前擁有者。 + @param _to 新的擁有者。 + @param _tokenId 要轉移的 NFT。 + """ + self._transferFrom(_from, _to, _tokenId, msg.sender) +``` + +此函式可讓你轉移到任意地址。 除非該地址是使用者,或是知道如何轉移代幣的合約,否則你轉移的任何代幣都會卡在該地址中而無法使用。 + +```python +@external +def safeTransferFrom( + _from: address, + _to: address, + _tokenId: uint256, + _data: Bytes[1024]=b"" + ): + """ + @dev 將 NFT 的所有權從一個地址轉移到另一個地址。 + 除非 `msg.sender` 是目前的擁有者、授權的操作員或此 + NFT 的核准地址,否則會擲出錯誤。 + 如果 `_from` 不是目前的擁有者,則會擲出錯誤。 + 如果 `_to` 是零地址,則會擲出錯誤。 + 如果 `_tokenId` 不是有效的 NFT,則會擲出錯誤。 + 如果 `_to` 是智慧合約,它會在 `_to` 上呼叫 `onERC721Received`,如果 + 傳回值不是 `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`,則會擲出錯誤。 + 注意:bytes4 由帶有填充的 bytes32 表示 + @param _from NFT 的目前擁有者。 + @param _to 新的擁有者。 + @param _tokenId 要轉移的 NFT。 + @param _data 額外資料,無指定格式,在對 `_to` 的呼叫中傳送。 + """ + self._transferFrom(_from, _to, _tokenId, msg.sender) +``` + +先執行轉移是沒問題的,因為如果出現問題,我們無論如何都會還原,所以在呼叫中完成的所有事情都將被取消。 + +```python + if _to.is_contract: # 檢查 `_to` 是否為合約地址 +``` + +首先檢查該地址是否為合約 (如果它有程式碼)。 如果不是,則假設它是一個使用者地址,使用者將能夠使用或轉移該代幣。 但不要讓它讓你產生虛假的安全感。 即使使用 `safeTransferFrom`,如果你將代幣轉移到一個沒人知道私鑰的地址,你仍然可能會遺失代幣。 + +```python + returnValue: bytes32 = ERC721Receiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data) +``` + +呼叫目標合約,看它是否能接收 ERC-721 代幣。 + +```python + # 如果轉移目標是不實作 'onERC721Received' 的合約,則會擲出錯誤 + assert returnValue == method_id("onERC721Received(address,address,uint256,bytes)", output_type=bytes32) +``` + +如果目標是一個合約,但不接受 ERC-721 代幣 (或決定不接受此特定轉移),則還原。 + +```python +@external +def approve(_approved: address, _tokenId: uint256): + """ + @dev 設定或再次確認 NFT 的核准地址。零地址表示沒有核准地址。 + 除非 `msg.sender` 是目前的 NFT 擁有者,或目前擁有者的授權操作員,否則會擲出錯誤。 + 如果 `_tokenId` 不是有效的 NFT,則會擲出錯誤。(注意:這未在 EIP 中撰寫) + 如果 `_approved` 是目前的擁有者,則會擲出錯誤。(注意:這未在 EIP 中撰寫) + @param _approved 要為給定 NFT ID 核准的地址。 + @param _tokenId 要核准的代幣 ID。 + """ + owner: address = self.idToOwner[_tokenId] + # 如果 `_tokenId` 不是有效的 NFT,則會擲出錯誤 + assert owner != ZERO_ADDRESS + # 如果 `_approved` 是目前的擁有者,則會擲出錯誤 + assert _approved != owner +``` + +按照慣例,如果你不想有核准者,你應該指定零地址,而不是你自己。 + +```python + # 檢查需求 + senderIsOwner: bool = self.idToOwner[_tokenId] == msg.sender + senderIsApprovedForAll: bool = (self.ownerToOperators[owner])[msg.sender] + assert (senderIsOwner or senderIsApprovedForAll) +``` + +要設定核准,你可以是擁有者,也可以是擁有者授權的操作員。 + +```python + # 設定核准 + self.idToApprovals[_tokenId] = _approved + log Approval(owner, _approved, _tokenId) + + +@external +def setApprovalForAll(_operator: address, _approved: bool): + """ + @dev 啟用或停用第三方 (「操作員」) 管理 `msg.sender` + 所有資產的核准。它也會發出 ApprovalForAll 事件。 + 如果 `_operator` 是 `msg.sender`,則會擲出錯誤。(注意:這未在 EIP 中撰寫) + @notice 即使傳送方當時沒有任何代幣,此函式也有效。 + @param _operator 要新增到授權操作員集合的地址。 + @param _approved 如果操作員被核准則為 True,若要撤銷核准則為 false。 + """ + # 如果 `_operator` 是 `msg.sender`,則會擲出錯誤 + assert _operator != msg.sender + self.ownerToOperators[msg.sender][_operator] = _approved + log ApprovalForAll(msg.sender, _operator, _approved) +``` + +#### 鑄造新代幣和銷毀現有代幣 {#mint-burn} + +建立合約的帳戶是 `minter` (鑄幣者),即有權鑄造新 NFT 的超級使用者。 然而,即使是鑄幣者也不被允許銷毀現有的代幣。 只有擁有者或由擁有者授權的實體才能這麼做。 + +```python +### 鑄幣與銷毀函式 ### + +@external +def mint(_to: address, _tokenId: uint256) -> bool: +``` + +此函式始終傳回 `True`,因為如果操作失敗,它將會被還原。 + +```python + """ + @dev 鑄造代幣的函式 + 如果 `msg.sender` 不是鑄幣者,則會擲出錯誤。 + 如果 `_to` 是零地址,則會擲出錯誤。 + 如果 `_tokenId` 已被他人擁有,則會擲出錯誤。 + @param _to 將接收鑄造代幣的地址。 + @param _tokenId 要鑄造的代幣 id。 + @return 一個布林值,表示操作是否成功。 + """ + # 如果 `msg.sender` 不是鑄幣者,則會擲出錯誤 + assert msg.sender == self.minter +``` + +只有鑄幣者 (建立 ERC-721 合約的帳戶) 才能鑄造新代幣。 如果我們未來想變更鑄幣者的身分,這可能會成為一個問題。 在一個生產合約中,你可能需要一個函式,允許鑄幣者將鑄幣權限轉移給其他人。 + +```python + # 如果 `_to` 是零地址,則會擲出錯誤 + assert _to != ZERO_ADDRESS + # 新增 NFT。如果 `_tokenId` 已被他人擁有,則會擲出錯誤 + self._addTokenTo(_to, _tokenId) + log Transfer(ZERO_ADDRESS, _to, _tokenId) + return True +``` + +按照慣例,鑄造新代幣被視為從零地址轉出。 + +```python + +@external +def burn(_tokenId: uint256): + """ + @dev 銷毀特定的 ERC721 代幣。 + 除非 `msg.sender` 是目前的擁有者、授權的操作員或此 NFT 的核准 + 地址,否則會擲出錯誤。 + 如果 `_tokenId` 不是有效的 NFT,則會擲出錯誤。 + @param _tokenId 要銷毀的 ERC721 代幣的 uint256 id。 + """ + # 檢查需求 + assert self._isApprovedOrOwner(msg.sender, _tokenId) + owner: address = self.idToOwner[_tokenId] + # 如果 `_tokenId` 不是有效的 NFT,則會擲出錯誤 + assert owner != ZERO_ADDRESS + self._clearApproval(owner, _tokenId) + self._removeTokenFrom(owner, _tokenId) + log Transfer(owner, ZERO_ADDRESS, _tokenId) +``` + +任何被允許轉移代幣的人都可以銷毀它。 雖然銷毀看起來等同於轉移到零地址,但零地址實際上並不會收到代幣。 這讓我們可以釋放用於該代幣的所有儲存空間,這可以降低交易的 gas 成本。 + +## 使用此合約 {#using-contract} + +與 Solidity 不同,Vyper 沒有繼承機制。 這是一項刻意的設計選擇,旨在讓程式碼更清晰,從而更容易確保其安全性。 因此,若要建立自己的 Vyper ERC-721 合約,你可以拿取[此合約](https://github.com/vyperlang/vyper/blob/master/examples/tokens/ERC721.vy)並修改它,以實作你想要的商業邏輯。 + +## 結論 {#conclusion} + +為了複習,以下是此合約中一些最重要的概念: + +- 要透過安全轉移接收 ERC-721 代幣,合約必須實作 `ERC721Receiver` 介面。 +- 即使你使用安全轉移,如果你將代幣傳送到私鑰未知的地址,代幣仍然可能會卡住。 +- 當操作出現問題時,最好是 `revert` (還原) 該呼叫,而不是只傳回一個失敗值。 +- ERC-721 代幣在其有擁有者時存在。 +- 有三種方式可以獲得轉移 NFT 的授權。 你可以是擁有者、被核准用於特定代幣,或是擁有者所有代幣的操作員。 +- 過去的事件只有在區塊鏈外部才可見。 在區塊鏈內部執行的程式碼無法檢視它們。 + +現在去實作安全的 Vyper 合約吧。 + +[在此查看我的更多作品](https://cryptodocguy.pro/)。 + diff --git a/public/content/translations/zh-tw/developers/tutorials/erc20-annotated-code/index.md b/public/content/translations/zh-tw/developers/tutorials/erc20-annotated-code/index.md new file mode 100644 index 00000000000..fb047e33b82 --- /dev/null +++ b/public/content/translations/zh-tw/developers/tutorials/erc20-annotated-code/index.md @@ -0,0 +1,803 @@ +--- +title: "ERC-20 合約逐步解說" +description: "OpenZeppelin 的 ERC-20 合約內容是什麼?這些內容又為何存在?" +author: Ori Pomerantz +lang: zh-tw +tags: [ "Solidity", "erc-20" ] +skill: beginner +published: 2021-03-09 +--- + +## 介紹 {#introduction} + +以太坊最常見的用處之一就是為一個團隊建立一種可交易的代幣。某種意義上,這是屬於他們自己的貨幣。 這些代幣通常會遵循一項標準,即 [ERC-20](/developers/docs/standards/tokens/erc-20/)。 這項標準讓開發能與所有 ERC-20 代幣相容的工具(例如流動性池和錢包)成為可能。 在本文中,我們將分析 [OpenZeppelin Solidity ERC20 實作](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol) 以及 [介面定義](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol)。 + +這是附有註解的原始碼。 如果您想實作 ERC-20,請[閱讀本教學](https://docs.openzeppelin.com/contracts/2.x/erc20-supply)。 + +## 介面 {#the-interface} + +像 ERC-20 這樣的標準,其目的是為了讓許多代幣實作能夠在錢包和去中心化交易所等應用程式之間互通。 為了達成這個目標,我們建立一個[介面](https://www.geeksforgeeks.org/solidity/solidity-basics-of-interface/)。 任何需要使用代幣合約的程式碼,都可以使用介面中的相同定義,並與所有使用該介面的代幣合約相容,無論是像 MetaMask 這樣的錢包、etherscan.io 這樣的 dapp,或是像流動性池這樣的不同合約。 + +![ERC-20 介面圖解](erc20_interface.png) + +如果你是有經驗的程式設計師,你可能還記得在 [Java](https://www.w3schools.com/java/java_interface.asp) 或甚至 [C 標頭檔](https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html) 中看過類似的結構。 + +這是 OpenZeppelin 的 [ERC-20 介面](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol) 定義。 它是將[人類可讀標準](https://eips.ethereum.org/EIPS/eip-20)翻譯成 Solidity 程式碼的結果。 當然,介面本身並未定義要 _如何_ 做任何事。 這點會在下方的合約原始碼中解釋。 + +  + +```solidity +// SPDX-License-Identifier: MIT +``` + +Solidity 檔案應該要包含一個授權許可證識別碼。 [您可以在此處查看授權許可證清單](https://spdx.org/licenses/)。 如果您需要不同的授權許可證,只要在註解中說明即可。 + +  + +```solidity +pragma solidity >=0.6.0 <0.8.0; +``` + +Solidity 語言仍在快速發展,新版本可能與舊程式碼不相容([請參見此處](https://docs.soliditylang.org/en/v0.7.0/070-breaking-changes.html))。 因此,最好不僅指定語言的最低版本,還要指定最高版本,也就是您用來測試程式碼的最新版本。 + +  + +```solidity +/** + * @dev EIP 中定義的 ERC20 標準介面。 + */ +``` + +註解中的 `@dev` 是 [NatSpec 格式](https://docs.soliditylang.org/en/develop/natspec-format.html) 的一部分,用於從原始碼產生文件。 + +  + +```solidity +interface IERC20 { +``` + +按照慣例,介面名稱以 `I` 開頭。 + +  + +```solidity + /** + * @dev 傳回現存的代幣數量。 + */ + function totalSupply() external view returns (uint256); +``` + +此函式為 `external`,表示[它只能從合約外部呼叫](https://docs.soliditylang.org/en/v0.7.0/cheatsheet.html#index-2)。 +它會傳回合約中的代幣總供應量。 此值使用以太坊中最常見的類型傳回,即無正負號 256 位元(256 位元是 EVM 的原生字組大小)。 此函式也是 `view`,表示它不會改變狀態,因此可以在單一節點上執行,而不需由區塊鏈中的每個節點都執行它。 這類函式不會產生交易,也不會花費 [Gas](/developers/docs/gas/)。 + +**注意:** 理論上,合約創建者似乎可以透過傳回比實際價值還小的總供應量來作弊,讓每個代幣看起來比實際更有價值。 然而,這種恐懼忽略了區塊鏈的真正本質。 區塊鏈上發生的每件事都可以由每個節點驗證。 為了達成這點,每個合約的機器語言程式碼和儲存空間在每個節點上都是可用的。 雖然您不需要為您的合約發布 Solidity 程式碼,但除非您發布原始碼以及編譯時所用的 Solidity 版本,否則沒有人會認真看待您的合約,這樣才能將其與您提供的機器語言程式碼進行驗證比對。 +例如,請參見[此合約](https://eth.blockscout.com/address/0xa530F85085C6FE2f866E7FdB716849714a89f4CD?tab=contract)。 + +  + +```solidity + /** + * @dev 傳回 `account` 擁有的代幣數量。 + */ + function balanceOf(address account) external view returns (uint256); +``` + +如同其名,`balanceOf` 傳回帳戶的餘額。 以太坊帳戶在 Solidity 中使用 `address` 類型來識別,該類型持有 160 位元。 +它也是 `external` 和 `view`。 + +  + +```solidity + /** + * @dev 將 `amount` 數量的代幣從呼叫者的帳戶轉移到 `recipient`。 + * + * 傳回一個布林值,表示操作是否成功。 + * + * 發出一個 {Transfer} 事件。 + */ + function transfer(address recipient, uint256 amount) external returns (bool); +``` + +`transfer` 函式將代幣從呼叫者轉移到一個不同的地址。 這涉及到狀態的改變,所以它不是一個 `view`。 +當使用者呼叫此函式時,會建立一筆交易並花費 Gas。 它也會發出一個 `Transfer` 事件,通知區塊鏈上的每個人該事件的發生。 + +此函式針對兩種不同類型的呼叫者,有兩種輸出類型: + +- 從使用者介面直接呼叫函式的使用者。 通常使用者提交交易後,不會等待回應,因為回應可能需要不確定的時間。 使用者可以透過查看交易收據(由交易哈希識別)或尋找 `Transfer` 事件來了解發生了什麼事。 +- 其他合約,將函式呼叫作為整體交易的一部分。 這些合約會立即得到結果,因為它們在同一個交易中執行,所以它們可以使用函式的傳回值。 + +其他改變合約狀態的函式也會產生相同類型的輸出。 + +  + +授權額度允許一個帳戶花費屬於不同所有者的代幣。 +舉例來說,這對於作為賣方的合約很有用。 合約無法監控事件,所以如果買方直接將代幣轉移給賣方合約,該合約不會知道它已收到款項。 取而代之的是,買方授權賣方合約花費一定金額,然後由賣方轉移該金額。 +這是透過賣方合約呼叫的一個函式來完成的,因此賣方合約可以知道它是否成功。 + +```solidity + /** + * @dev 傳回 `spender` 將被允許透過 {transferFrom} 代表 `owner` 花費的 + * 剩餘代幣數量。預設為零。 + * + * 當 {approve} 或 {transferFrom} 被呼叫時,此值會改變。 + */ + function allowance(address owner, address spender) external view returns (uint256); +``` + +`allowance` 函式讓任何人都可以查詢一個地址 (`owner`) 允許另一個地址 (`spender`) 花費的授權額度。 + +  + +```solidity + /** + * @dev 將 `spender` 對呼叫者代幣的授權額度設為 `amount`。 + * + * 傳回一個布林值,表示操作是否成功。 + * + * 重要:請注意,使用此方法更改授權額度存在風險, + * 有人可能會因不幸的交易排序而同時使用舊的和新的授權額度。一種可能的解決方案是 + * 先將花費者的授權額度降至 0,然後再設定所需的值,以減輕這種競爭 + * 條件: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * 發出一個 {Approval} 事件。 + */ + function approve(address spender, uint256 amount) external returns (bool); +``` + +`approve` 函式會建立一個授權額度。 請務必閱讀有關它如何被濫用的訊息。 在以太坊中,您可以控制自己交易的順序,但無法控制其他人交易的執行順序,除非您在看到對方的交易發生後才提交自己的交易。 + +  + +```solidity + /** + * @dev 使用授權額度機制將 `amount` 的代幣從 `sender` 轉移到 `recipient`。 + * 然後,`amount` 會從呼叫者的授權額度中扣除。 + * + * 傳回一個布林值,表示操作是否成功。 + * + * 發出一個 {Transfer} 事件。 + */ + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); +``` + +最後,`transferFrom` 由花費者用來實際花費授權額度。 + +  + +```solidity + + /** + * @dev 當 `value` 數量的代幣從一個帳戶 (`from`) 移動到 + * 另一個帳戶 (`to`) 時發出。 + * + * 請注意 `value` 可能為零。 + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev 當 `owner` 的 `spender` 的授權額度透過 + * 呼叫 {approve} 設定時發出。`value` 是新的授權額度。 + */ + event Approval(address indexed owner, address indexed spender, uint256 value); +} +``` + +當 ERC-20 合約的狀態改變時,這些事件會被發出。 + +## 實際的合約 {#the-actual-contract} + +這是實作 ERC-20 標準的實際合約,[取自此處](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol)。 +它並非設計來直接使用,但您可以[繼承](https://www.tutorialspoint.com/solidity/solidity_inheritance.htm)它來擴展成可用的東西。 + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.0 <0.8.0; +``` + +  + +### 匯入陳述式 {#import-statements} + +除了上述的介面定義外,合約定義還匯入了另外兩個檔案: + +```solidity + +import "../../GSN/Context.sol"; +import "./IERC20.sol"; +import "../../math/SafeMath.sol"; +``` + +- `GSN/Context.sol` 是使用 [OpenGSN](https://www.opengsn.org/) 所需的定義,這是一個允許沒有以太幣的使用者使用區塊鏈的系統。 請注意這是舊版本,如果您想與 OpenGSN 整合,[請使用此教學](https://docs.opengsn.org/javascript-client/tutorial.html)。 +- [SafeMath 程式庫](https://ethereumdev.io/using-safe-math-library-to-prevent-from-overflows/),它能防止 Solidity 版本 **<0.8.0** 的算術溢位/下溢。 在 Solidity ≥0.8.0 中,算術運算會在溢位/下溢時自動還原,使得 SafeMath 不再必要。 此合約使用 SafeMath 以便向後相容於舊的編譯器版本。 + +  + +此註解說明了合約的用途。 + +```solidity +/** + * @dev {IERC20} 介面的實作。 + * + * 此實作與代幣的創建方式無關。這意味著 + * 必須在衍生合約中使用 {_mint} 新增供應機制。 + * 若要使用通用機制,請參閱 {ERC20PresetMinterPauser}。 + * + * 提示:詳細說明請參閱我們的指南 + * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[如何 + * 實作供應機制]。 + * + * 我們遵循了一般的 OpenZeppelin 指南:函式在失敗時會還原 + * 而非傳回 `false`。此行為是常規的 + * 且不與 ERC20 應用程式的預期衝突。 + * + * 此外,在呼叫 {transferFrom} 時會發出 {Approval} 事件。 + * 這允許應用程式僅透過監聽所述事件來重構所有帳戶的授權額度。 + * EIP 的其他實作可能不會發出這些事件, + * 因為規範並未要求。 + * + * 最後,新增了非標準的 {decreaseAllowance} 和 {increaseAllowance} + * 函式來緩解圍繞設定授權額度的眾所周知的問題。 + * 請參閱 {IERC20-approve}。 + */ + +``` + +### 合約定義 {#contract-definition} + +```solidity +contract ERC20 is Context, IERC20 { +``` + +此行指定了繼承關係,在此例中是繼承自上方的 `IERC20` 和用於 OpenGSN 的 `Context`。 + +  + +```solidity + + using SafeMath for uint256; + +``` + +此行將 `SafeMath` 程式庫附加到 `uint256` 類型上。 您可以在[此處](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeMath.sol)找到此程式庫。 + +### 變數定義 {#variable-definitions} + +這些定義指定了合約的狀態變數。 這些變數被宣告為 `private`,但這只意味著區塊鏈上的其他合約無法讀取它們。 _區塊鏈上沒有秘密_,每個節點上的軟體都擁有每個合約在每個區塊的狀態。 按照慣例,狀態變數的命名方式為 `_`。 + +前兩個變數是[映射](https://www.tutorialspoint.com/solidity/solidity_mappings.htm),這意味著它們的行為大致與[關聯陣列](https://wikipedia.org/wiki/Associative_array)相同,只是鍵是數值。 只有值與預設值(零)不同的條目才會被分配儲存空間。 + +```solidity + mapping (address => uint256) private _balances; +``` + +第一個映射 `_balances` 是地址及其對應的此代幣餘額。 要存取餘額,請使用此語法:`_balances[
]`。 + +  + +```solidity + mapping (address => mapping (address => uint256)) private _allowances; +``` + +這個變數 `_allowances` 儲存了先前解釋過的授權額度。 第一個索引是代幣的所有者,第二個是擁有授權額度的合約。 要存取地址 A 可以從地址 B 帳戶花費的金額,請使用 `_allowances[B][A]`。 + +  + +```solidity + uint256 private _totalSupply; +``` + +如同其名,這個變數追蹤代幣的總供應量。 + +  + +```solidity + string private _name; + string private _symbol; + uint8 private _decimals; +``` + +這三個變數是用來提高可讀性的。 前兩個不言自明,但 `_decimals` 則不是。 + +一方面,以太坊沒有浮點數或分數變數。 另一方面,人類喜歡能夠分割代幣。 人們選擇黃金作為貨幣的一個原因是,當有人想用牛換取等值的鴨子時,很難找零。 + +解決方法是追蹤整數,但計算的不是實際的代幣,而是一個幾乎沒有價值的分數代幣。 以以太幣為例,分數代幣稱為 wei,而 10^18 wei 等於一 ETH。 在撰寫本文時,10,000,000,000,000 wei 約等於一美分或歐分。 + +應用程式需要知道如何顯示代幣餘額。 如果一個使用者有 3,141,000,000,000,000,000 wei,那是 3.14 ETH 嗎? 31.41 ETH? 3,141 ETH? 以以太幣為例,定義是 10^18 wei 等於一 ETH,但對於您的代幣,您可以選擇不同的值。 如果分割代幣沒有意義,您可以使用 `_decimals` 值為零。 如果您想使用與 ETH 相同的標準,請使用值 **18**。 + +### 建構函式 {#the-constructor} + +```solidity + /** + * @dev 設定 {name} 和 {symbol} 的值,並將 {decimals} 初始化為 + * 預設值 18。 + * + * 要為 {decimals} 選擇不同的值,請使用 {_setupDecimals}。 + * + * 這三個值都是不可變的:它們只能在建構期間設定一次。 + */ + constructor (string memory name_, string memory symbol_) public { + // 在 Solidity ≥0.7.0 中,'public' 是隱含的,可以省略。 + + _name = name_; + _symbol = symbol_; + _decimals = 18; + } +``` + +建構函式在合約首次建立時被呼叫。 按照慣例,函式參數的命名方式為 `_`。 + +### 使用者介面函式 {#user-interface-functions} + +```solidity + /** + * @dev 傳回代幣的名稱。 + */ + function name() public view returns (string memory) { + return _name; + } + + /** + * @dev 傳回代幣的符號,通常是名稱的較短版本。 + */ + function symbol() public view returns (string memory) { + return _symbol; + } + + /** + * @dev 傳回用於獲取其使用者表示的小數位數。 + * 例如,如果 `decimals` 等於 `2`,`505` 代幣的餘額應 + * 對使用者顯示為 `5,05` (`505 / 10 ** 2`)。 + * + * 代幣通常選擇值 18,模仿以太幣和 wei 之間的關係。這是 {ERC20} 使用的值, + * 除非呼叫 {_setupDecimals}。 + * + * 注意:此資訊僅用於 _顯示_ 目的:它在 + * 任何方面都不會影響合約的任何算術,包括 + * {IERC20-balanceOf} 和 {IERC20-transfer}。 + */ + function decimals() public view returns (uint8) { + return _decimals; + } +``` + +這些函式 `name`、`symbol` 和 `decimals` 幫助使用者介面了解您的合約,以便它們能夠正確顯示。 + +傳回類型是 `string memory`,意思是傳回一個儲存在記憶體中的字串。 變數,例如字串,可以儲存在三個位置: + +| | 生命週期 | 合約存取 | Gas 成本 | +| -------- | ---- | ---- | ------------------- | +| 記憶體 | 函式呼叫 | 讀/寫 | 數十或數百(位置越高,成本越高) | +| Calldata | 函式呼叫 | 唯讀 | 不能作為傳回類型,只能作為函式參數類型 | +| 儲存 | 直到改變 | 讀/寫 | 高(讀取為 800,寫入為 2 萬) | + +在這種情況下,`memory` 是最佳選擇。 + +### 讀取代幣資訊 {#read-token-information} + +這些是提供代幣資訊的函式,可以是總供應量或帳戶餘額。 + +```solidity + /** + * @dev 請參閱 {IERC20-totalSupply}。 + */ + function totalSupply() public view override returns (uint256) { + return _totalSupply; + } +``` + +`totalSupply` 函式傳回代幣的總供應量。 + +  + +```solidity + /** + * @dev 請參閱 {IERC20-balanceOf}。 + */ + function balanceOf(address account) public view override returns (uint256) { + return _balances[account]; + } +``` + +讀取帳戶的餘額。 請注意,任何人都可以獲取任何其他人的帳戶餘額。 試圖隱藏這些資訊是沒有意義的,因為它在每個節點上都是可用的。 _區塊鏈上沒有秘密。_ + +### 轉移代幣 {#transfer-tokens} + +```solidity + /** + * @dev 請參閱 {IERC20-transfer}。 + * + * 要求: + * + * - `recipient` 不能是零地址。 + * - 呼叫者必須擁有至少 `amount` 的餘額。 + */ + function transfer(address recipient, uint256 amount) public virtual override returns (bool) { +``` + +`transfer` 函式被呼叫來將代幣從發送者的帳戶轉移到另一個帳戶。 請注意,即使它傳回一個布林值,該值也始終為 **true**。 如果轉帳失敗,合約會還原該呼叫。 + +  + +```solidity + _transfer(_msgSender(), recipient, amount); + return true; + } +``` + +`_transfer` 函式執行實際的工作。 它是一個私有函式,只能由其他合約函式呼叫。 按照慣例,私有函式的命名方式與狀態變數相同,都是 `_`。 + +通常在 Solidity 中,我們使用 `msg.sender` 來表示訊息發送者。 然而,這會破壞 [OpenGSN](http://opengsn.org/)。 如果我們想讓我們的代幣允許無以太幣的交易,我們需要使用 `_msgSender()`。 對於正常交易,它傳回 `msg.sender`,但對於無以太幣的交易,它傳回原始簽署者,而不是轉發訊息的合約。 + +### 授權額度函式 {#allowance-functions} + +這些是實作授權額度功能的函式:`allowance`、`approve`、`transferFrom` 和 `_approve`。 此外,OpenZeppelin 的實作超越了基本標準,包含了一些提高安全性的功能:`increaseAllowance` 和 `decreaseAllowance`。 + +#### allowance 函式 {#allowance} + +```solidity + /** + * @dev 請參閱 {IERC20-allowance}。 + */ + function allowance(address owner, address spender) public view virtual override returns (uint256) { + return _allowances[owner][spender]; + } +``` + +`allowance` 函式允許每個人檢查任何授權額度。 + +#### approve 函式 {#approve} + +```solidity + /** + * @dev 請參閱 {IERC20-approve}。 + * + * 要求: + * + * - `spender` 不能是零地址。 + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) { +``` + +此函式被呼叫來建立一個授權額度。 它與上面的 `transfer` 函式相似: + +- 此函式僅呼叫一個執行實際工作的內部函式(在本例中為 `_approve`)。 +- 此函式要麼傳回 `true`(如果成功),要麼還原(如果不成功)。 + +  + +```solidity + _approve(_msgSender(), spender, amount); + return true; + } +``` + +我們使用內部函式來最小化狀態變更發生的位置數量。 _任何_ 改變狀態的函式都是一個潛在的安全風險,需要進行安全審計。 這樣我們出錯的機會就更少了。 + +#### transferFrom 函式 {#transferFrom} + +這是花費者呼叫來花費授權額度的函式。 這需要兩個操作:轉移花費的金額,並將授權額度減少該金額。 + +```solidity + /** + * @dev 請參閱 {IERC20-transferFrom}。 + * + * 發出一個 {Approval} 事件,表示已更新的授權額度。這不是 EIP 所要求的。 + * 請參閱 {ERC20} 開頭的說明。 + * + * 要求: + * + * - `sender` 和 `recipient` 不能是零地址。 + * - `sender` 必須擁有至少 `amount` 的餘額。 + * - 呼叫者對 ``sender`` 的代幣的授權額度必須至少為 + * `amount`。 + */ + function transferFrom(address sender, address recipient, uint256 amount) public virtual + override returns (bool) { + _transfer(sender, recipient, amount); +``` + +  + +`a.sub(b, "message")` 函式呼叫做兩件事。 首先,它計算 `a-b`,即新的授權額度。 +其次,它檢查此結果是否為負。 如果為負,則呼叫會以提供的訊息還原。 請註意,撤銷調用後,之前在調用中完成的任何處理都會被忽略,所以我們不需要撤消 _transfer。 + +```solidity + _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, + "ERC20: transfer amount exceeds allowance")); + return true; + } +``` + +#### OpenZeppelin 安全性附加功能 {#openzeppelin-safety-additions} + +將一個非零授權額度設定為另一個非零值是危險的,因為您只能控制自己交易的順序,而不能控制任何其他人的交易。 想像一下,您有兩個使用者,天真的 Alice 和不誠實的 Bill。 Alice 想要 Bill 的一些服務,她認為這需要五個代幣 - 所以她給了 Bill 五個代幣的授權額度。 + +然後情況有變,Bill 的價格漲到了十個代幣。 仍然想要服務的 Alice 發送了一筆交易,將 Bill 的授權額度設定為十。 Bill 一在交易池中看到這筆新交易,就立即發送一筆交易,花掉 Alice 的五個代幣,並設定更高的 Gas 價格,以便更快地被挖出。 這樣,Bill 可以先花掉五個代幣,然後,一旦 Alice 的新授權額度被挖出,再花掉十個,總共十五個代幣,超過了 Alice 想要授權的數量。 這種技術被稱為[預先交易](https://consensysdiligence.github.io/smart-contract-best-practices/attacks/#front-running) + +| Alice 的交易 | Alice 的 Nonce | Bill 的交易 | Bill 的 Nonce | Bill 的授權額度 | Bill 從 Alice 獲得的總收入 | +| ------------------------------------ | ------------- | ------------------------------------------------ | ------------ | ---------- | ------------------- | +| approve(Bill, 5) | 10 | | | 5 | 0 | +| | | transferFrom(Alice, Bill, 5) | 10,123 | 0 | 5 | +| approve(Bill, 10) | 11 | | | 10 | 5 | +| | | transferFrom(Alice, Bill, 10) | 10,124 | 0 | 15 | + +為避免此問題,這兩個函式(`increaseAllowance` 和 `decreaseAllowance`)允許您以特定數量修改授權額度。 因此,如果 Bill 已經花費了五個代幣,他將只能再花費五個。 根據時間點的不同,這有兩種可能的方式,但最終 Bill 都只會得到十個代幣: + +A: + +| Alice 的交易 | Alice 的 Nonce | Bill 的交易 | Bill 的 Nonce | Bill 的授權額度 | Bill 從 Alice 獲得的總收入 | +| --------------------------------------------- | ------------: | ----------------------------------------------- | -----------: | ---------: | ------------------- | +| approve(Bill, 5) | 10 | | | 5 | 0 | +| | | transferFrom(Alice, Bill, 5) | 10,123 | 0 | 5 | +| increaseAllowance(Bill, 5) | 11 | | | 0+5 = 5 | 5 | +| | | transferFrom(Alice, Bill, 5) | 10,124 | 0 | 10 | + +B: + +| Alice 的交易 | Alice 的 Nonce | Bill 的交易 | Bill 的 Nonce | Bill 的授權額度 | Bill 從 Alice 獲得的總收入 | +| --------------------------------------------- | ------------: | ------------------------------------------------ | -----------: | ---------: | ------------------: | +| approve(Bill, 5) | 10 | | | 5 | 0 | +| increaseAllowance(Bill, 5) | 11 | | | 5+5 = 10 | 0 | +| | | transferFrom(Alice, Bill, 10) | 10,124 | 0 | 10 | + +```solidity + /** + * @dev 以原子方式增加呼叫者授予 `spender` 的授權額度。 + * + * 這是 {approve} 的替代方案,可用於緩解 {IERC20-approve} 中描述的問題。 + * + * 發出一個 {Approval} 事件,表示已更新的授權額度。 + * + * 要求: + * + * - `spender` 不能是零地址。 + */ + function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { + _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); + return true; + } +``` + +`a.add(b)` 函式是安全的加法。 在 `a`+`b`>=`2^256` 的罕見情況下,它不會像正常加法那樣循環。 + +```solidity + + /** + * @dev 以原子方式減少呼叫者授予 `spender` 的授權額度。 + * + * 這是 {approve} 的替代方案,可用於緩解 {IERC20-approve} 中描述的問題。 + * + * 發出一個 {Approval} 事件,表示已更新的授權額度。 + * + * 要求: + * + * - `spender` 不能是零地址。 + * - `spender` 對呼叫者的授權額度必須至少為 + * `subtractedValue`。 + */ + function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { + _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, + "ERC20: decreased allowance below zero")); + return true; + } +``` + +### 修改代幣資訊的函式 {#functions-that-modify-token-information} + +這四個函式執行實際的工作:`_transfer`、`_mint`、`_burn` 和 `_approve`。 + +#### `_transfer` 函式 {#_transfer} + +```solidity + /** + * @dev 將 `amount` 的代幣從 `sender` 轉移到 `recipient`。 + * + * 這個內部函式相當於 {transfer},可以用於 + * 例如,實作自動代幣費用、削減機制等。 + * + * 發出一個 {Transfer} 事件。 + * + * 要求: + * + * - `sender` 不能是零地址。 + * - `recipient` 不能是零地址。 + * - `sender` 必須擁有至少 `amount` 的餘額。 + */ + function _transfer(address sender, address recipient, uint256 amount) internal virtual { +``` + +這個函式 `_transfer` 將代幣從一個帳戶轉移到另一個帳戶。 它同時被 `transfer`(用於從發送者自己的帳戶轉帳)和 `transferFrom`(用於使用授權額度從別人的帳戶轉帳)呼叫。 + +  + +```solidity + require(sender != address(0), "ERC20: transfer from the zero address"); + require(recipient != address(0), "ERC20: transfer to the zero address"); +``` + +在以太坊中,沒有人實際擁有零地址(也就是說,沒有人知道其對應的公鑰轉換為零地址的私鑰)。 當人們使用該地址時,通常是軟體錯誤 - 所以如果零地址被用作發送者或接收者,我們會失敗。 + +  + +```solidity + _beforeTokenTransfer(sender, recipient, amount); + +``` + +有兩種方式可以使用此合約: + +1. 將其作為您自己程式碼的範本 +2. [繼承它](https://www.bitdegree.org/learn/solidity-inheritance),並只覆寫您需要修改的函式 + +第二種方法要好得多,因為 OpenZeppelin ERC-20 程式碼已經過審計並被證明是安全的。 當您使用繼承時,您修改的函式會很清楚,要信任您的合約,人們只需要審計那些特定的函式。 + +每次代幣易手時執行一個函式通常很有用。 然而,`_transfer` 是一個非常重要的函式,而且有可能寫得不安全(見下文),所以最好不要覆寫它。 解決方案是 `_beforeTokenTransfer`,一個[鉤子函式](https://wikipedia.org/wiki/Hooking)。 您可以覆寫此函式,它將在每次轉帳時被呼叫。 + +  + +```solidity + _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); + _balances[recipient] = _balances[recipient].add(amount); +``` + +這些是實際執行轉帳的程式碼行。 請注意,它們之間**沒有任何東西**,而且我們在將轉帳金額加到接收者之前,先從發送者那裡減去它。 這很重要,因為如果中間有呼叫到不同的合約,它可能會被用來欺騙此合約。 這樣,轉帳就是原子性的,中間不會發生任何事情。 + +  + +```solidity + emit Transfer(sender, recipient, amount); + } +``` + +最後,發出一個 `Transfer` 事件。 事件無法被智慧型合約存取,但在區塊鏈外執行的程式碼可以監聽事件並對其做出反應。 例如,錢包可以追蹤所有者何時獲得更多代幣。 + +#### `_mint` 和 `_burn` 函式 {#_mint-and-_burn} + +這兩個函式(`_mint` 和 `_burn`)會修改代幣的總供應量。 +它們是內部函式,且此合約中沒有函式會呼叫它們,所以只有在您繼承此合約並加入自己的邏輯,以決定在何種情況下鑄造新代幣或銷毀現有代幣時,它們才有用。 + +**注意:** 每個 ERC-20 代幣都有自己的商業邏輯來決定代幣管理。 +例如,一個固定供應量的合約可能只在建構函式中呼叫 `_mint`,而永不呼叫 `_burn`。 一個銷售代幣的合約在收到付款時會呼叫 `_mint`,並可能在某個時間點呼叫 `_burn` 以避免失控的通貨膨脹。 + +```solidity + /** @dev 建立 `amount` 數量的代幣並將其分配給 `account`,增加 + * 總供應量。 + * + * 發出一個 `from` 設為零地址的 {Transfer} 事件。 + * + * 要求: + * + * - `to` 不能是零地址。 + */ + function _mint(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: mint to the zero address"); + _beforeTokenTransfer(address(0), account, amount); + _totalSupply = _totalSupply.add(amount); + _balances[account] = _balances[account].add(amount); + emit Transfer(address(0), account, amount); + } +``` + +當代幣總數變更時,請務必更新 `_totalSupply`。 + +  + +```solidity + /** + * @dev 從 `account` 銷毀 `amount` 數量的代幣,減少 + * 總供應量。 + * + * 發出一個 `to` 設為零地址的 {Transfer} 事件。 + * + * 要求: + * + * - `account` 不能是零地址。 + * - `account` 必須至少擁有 `amount` 數量的代幣。 + */ + function _burn(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: burn from the zero address"); + + _beforeTokenTransfer(account, address(0), amount); + + _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); + _totalSupply = _totalSupply.sub(amount); + emit Transfer(account, address(0), amount); + } +``` + +`_burn` 函式與 `_mint` 幾乎相同,只是方向相反。 + +#### `_approve` 函式 {#_approve} + +這個函式實際上指定了授權額度。 注意,它允許所有者指定一個高於其目前餘額的授權額度。 這是可以的,因為餘額是在轉帳時檢查的,那時的餘額可能與建立授權額度時的餘額不同。 + +```solidity + /** + * @dev 將 `spender` 對 `owner` 代幣的授權額度設為 `amount`。 + * + * 這個內部函式等同於 `approve`,可以用於例如 + * 為某些子系統設定自動授權額度等。 + * + * 發出一個 {Approval} 事件。 + * + * 要求: + * + * - `owner` 不能是零地址。 + * - `spender` 不能是零地址。 + */ + function _approve(address owner, address spender, uint256 amount) internal virtual { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; +``` + +  + +發出一個 `Approval` 事件。 根據應用程式的寫法,花費者合約可以由所有者或監聽這些事件的伺服器來告知核准。 + +```solidity + emit Approval(owner, spender, amount); + } + +``` + +### 修改小數位數變數 {#modify-the-decimals-variable} + +```solidity + + + /** + * @dev 將 {decimals} 設為非預設值 18 的值。 + * + * 警告:此函式只應在建構函式中呼叫。大多數 + * 與代幣合約互動的應用程式不會預期 + * {decimals} 會改變,如果改變了可能會運作不正確。 + */ + function _setupDecimals(uint8 decimals_) internal { + _decimals = decimals_; + } +``` + +此函式修改 `_decimals` 變數,該變數用於告知使用者介面如何解讀金額。 +您應該從建構函式中呼叫它。 在之後的任何時間點呼叫它都是不誠實的,且應用程式並非設計來處理這種情況。 + +### 挂鈎 {#hooks} + +```solidity + + /** + * @dev 在任何代幣轉移之前呼叫的鉤子。這包括 + * 鑄造和銷毀。 + * + * 呼叫條件: + * + * - 當 `from` 和 `to` 都非零時,`amount` 數量的 ``from`` 的代幣 + * 將被轉移到 `to`。 + * - 當 `from` 為零時,將為 `to` 鑄造 `amount` 數量的代幣。 + * - 當 `to` 為零時,`amount` 數量的 ``from`` 的代幣將被銷毀。 + * - `from` 和 `to` 永遠不會同時為零。 + * + * 要了解更多關於鉤子的資訊,請前往 xref:ROOT:extending-contracts.adoc#using-hooks[使用鉤子]。 + */ + function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { } +} +``` + +這是在轉帳期間被呼叫的鉤子函式。 這裡它是空的,但如果您需要它做些什麼,您只需要覆寫它即可。 + +## 結論 {#conclusion} + +總結一下,以下是此合約中一些最重要的概念(在我看來,您的看法可能會有所不同): + +- _在區塊鏈上沒有秘密_。 智慧型合約可以存取的任何資訊對全世界都是可用的。 +- 您可以控制自己交易的順序,但無法控制其他人交易的發生時間。 這就是為什麼更改授權額度可能很危險,因為它讓花費者可以花費兩個授權額度的總和。 +- `uint256` 類型的值會循環。 換句話說,_0-1=2^256-1_。 如果這不是期望的行為,您必須對其進行檢查(或使用 SafeMath 程式庫為您代勞)。 請注意,這在 [Solidity 0.8.0](https://docs.soliditylang.org/en/breaking/080-breaking-changes.html) 中已有所改變。 +- 將所有特定類型的狀態變更集中在一個特定地方處理,因為這樣更容易審計。 + 這就是為什麼我們有 `_approve`,它被 `approve`、`transferFrom`、`increaseAllowance` 和 `decreaseAllowance` 呼叫。 +- 狀態變更應該是原子性的,中間不應有任何其他操作(如您在 `_transfer` 中所見)。 這是因為在狀態變更期間,您會處於一個不一致的狀態。 例如,在您從發送者餘額中扣除和添加到接收者餘額之間的時間裡,存在的代幣數量少於應有的數量。 如果它們之間有操作,這點可能被濫用,特別是呼叫到一個不同的合約。 + +既然您已經了解 OpenZeppelin ERC-20 合約是如何編寫的,特別是它是如何變得更安全的,現在就去編寫您自己的安全合約和應用程式吧。 + +[在此查看我的更多作品](https://cryptodocguy.pro/)。 diff --git a/public/content/translations/zh-tw/developers/tutorials/erc20-with-safety-rails/index.md b/public/content/translations/zh-tw/developers/tutorials/erc20-with-safety-rails/index.md new file mode 100644 index 00000000000..7478093c611 --- /dev/null +++ b/public/content/translations/zh-tw/developers/tutorials/erc20-with-safety-rails/index.md @@ -0,0 +1,217 @@ +--- +title: "帶有安全措施的 ERC-20" +description: "如何幫助人們避免愚蠢的錯誤" +author: Ori Pomerantz +lang: zh-tw +tags: [ "erc-20" ] +skill: beginner +published: 2022-08-15 +--- + +## 介紹 {#introduction} + +以太坊的一大優點是沒有中央機構可以修改或撤銷您的交易。 以太坊的一大問題是沒有中央機構有權力撤銷使用者錯誤或非法交易。 在本文中,您將了解使用者在使用 [ERC-20](/developers/docs/standards/tokens/erc-20/) 代幣時常犯的一些錯誤,以及如何創建 ERC-20 合約來幫助使用者避免這些錯誤,或賦予中央機構某些權力(例如凍結帳戶)。 + +請注意,雖然我們將使用 [OpenZeppelin ERC-20 代幣合約](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC20),但本文不會詳細解釋它。 您可以在[此處](/developers/tutorials/erc20-annotated-code)找到此資訊。 + +如果您想查看完整的原始碼: + +1. 開啟 [Remix IDE](https://remix.ethereum.org/)。 +2. 點擊複製 github 圖示 (![clone github icon](icon-clone.png))。 +3. 複製 github 儲存庫 `https://github.com/qbzzt/20220815-erc20-safety-rails`。 +4. 開啟 **contracts > erc20-safety-rails.sol**。 + +## 建立 ERC-20 合約 {#creating-an-erc-20-contract} + +在新增安全措施功能之前,我們需要一個 ERC-20 合約。 在本文中,我們將使用 [OpenZeppelin Contracts Wizard](https://docs.openzeppelin.com/contracts/5.x/wizard)。 在另一個瀏覽器中開啟它,並按照以下說明操作: + +1. 選擇 **ERC20**。 + +2. 輸入以下設定: + + | 參數 | 數值 | + | ------- | ---------------- | + | 名稱 | SafetyRailsToken | + | 符號 | SAFE | + | Premint | 1000 | + | 功能 | 無 | + | 存取控制 | Ownable | + | 可升級性 | 無 | + +3. 向上捲動並點擊 **在 Remix 中開啟** (適用於 Remix) 或 **下載** 以使用不同的環境。 我將假設您正在使用 Remix,如果您使用其他工具,請進行相應的變更。 + +4. 我們現在有了一個功能齊全的 ERC-20 合約。 您可以展開 `.deps` > `npm` 以查看匯入的程式碼。 + +5. 編譯、部署並操作合約,以確認它能作為 ERC-20 合約運作。 如果您需要學習如何使用 Remix,請[使用此教學](https://remix.ethereum.org/?#activate=udapp,solidity,LearnEth)。 + +## 常見錯誤 {#common-mistakes} + +### 錯誤 {#the-mistakes} + +使用者有時會將代幣傳送到錯誤的地址。 雖然我們無法讀懂他們的心思來了解他們想做什麼,但有兩種經常發生且易於偵測的錯誤類型: + +1. 將代幣傳送到合約自己的地址。 例如,[Optimism 的 OP 代幣](https://optimism.mirror.xyz/qvd0WfuLKnePm1Gxb9dpGchPf5uDz5NSMEFdgirDS4c) 在不到兩個月的時間裡累積了[超過 120,000](https://optimism.blockscout.com/address/0x4200000000000000000000000000000000000042) 個 OP 代幣。 這代表著一筆巨大的財富,推測是人們剛剛損失的。 + +2. 將代幣傳送到一個空地址,該地址不對應於[外部擁有帳戶](/developers/docs/accounts/#externally-owned-accounts-and-key-pairs)或[智能合約](/developers/docs/smart-contracts)。 雖然我沒有關於這種情況發生頻率的統計數據,但[一次事件可能造成 20,000,000 個代幣的損失](https://gov.optimism.io/t/message-to-optimism-community-from-wintermute/2595)。 + +### 防止轉帳 {#preventing-transfers} + +OpenZeppelin ERC-20 合約包含一個[掛鉤 `_beforeTokenTransfer`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol#L364-L368),它在代幣轉移之前被調用。 預設情況下,這個掛鉤不做任何事情,但我們可以在其上掛載自己的功能,例如在出現問題時回復的檢查。 + +要使用此掛鉤,請在建構函式後新增此函式: + +```solidity + function _beforeTokenTransfer(address from, address to, uint256 amount) + internal virtual + override(ERC20) + { + super._beforeTokenTransfer(from, to, amount); + } +``` + +如果您對 Solidity 不太熟悉,此函式的某些部分可能對您來說是新的: + +```solidity + internal virtual +``` + +`virtual` 關鍵字表示,正如我們從 `ERC20` 繼承功能並覆寫此函式一樣,其他合約也可以從我們這裡繼承並覆寫此函式。 + +```solidity + override(ERC20) +``` + +我們必須明確指定我們正在[覆寫](https://docs.soliditylang.org/en/v0.8.15/contracts.html#function-overriding) `_beforeTokenTransfer` 的 ERC20 代幣定義。 一般來說,從安全角度來看,明確的定義比隱含的定義好得多——如果事情就在您眼前,您就不會忘記您做了什麼。 這也是我們需要指定我們正在覆寫哪個父類的 `_beforeTokenTransfer` 的原因。 + +```solidity + super._beforeTokenTransfer(from, to, amount); +``` + +此行調用我們從其繼承的合約中擁有 `_beforeTokenTransfer` 函式的函式。 在這種情況下,只有 `ERC20` 有這個掛鉤,`Ownable` 沒有。 儘管目前 `ERC20._beforeTokenTransfer` 不做任何事情,我們還是調用它,以防將來新增功能(然後我們決定重新部署合約,因為合約在部署後不會改變)。 + +### 編寫要求 {#coding-the-requirements} + +我們希望向函式新增這些要求: + +- `to` 地址不能等於 `address(this)`,即 ERC-20 合約本身的地址。 +- `to` 地址不能為空,它必須是: + - 一個外部擁有帳戶 (EOA)。 我們無法直接檢查一個地址是否為 EOA,但我們可以檢查一個地址的 ETH 餘額。 EOA 幾乎總是有餘額,即使它們不再使用——很難將它們清零到最後一個 wei。 + - 一個智能合約。 測試一個地址是否為智能合約有點困難。 有一個檢查外部程式碼長度的 opcode,稱為 [`EXTCODESIZE`](https://www.evm.codes/#3b),但它在 Solidity 中不能直接使用。 我們必須為此使用 [Yul](https://docs.soliditylang.org/en/v0.8.15/yul.html),它是一種 EVM 組合語言。 我們可以使用 Solidity 中的其他值([`
.code` 和 `
.codehash`](https://docs.soliditylang.org/en/v0.8.15/units-and-global-variables.html#members-of-address-types)),但它們的成本更高。 + +讓我們逐行查看新的程式碼: + +```solidity + require(to != address(this), "Can't send tokens to the contract address"); +``` + +這是第一個要求,檢查 `to` 和 `this(address)` 是否不是同一個東西。 + +```solidity + bool isToContract; + assembly { + isToContract := gt(extcodesize(to), 0) + } +``` + +這是我們檢查一個地址是否為合約的方式。 我們無法直接從 Yul 接收輸出,因此我們定義一個變數來儲存結果(在本例中為 `isToContract`)。 Yul 的工作方式是每個 opcode 都被視為一個函式。 所以首先我們調用 [`EXTCODESIZE`](https://www.evm.codes/#3b) 來獲取合約大小,然後使用 [`GT`](https://www.evm.codes/#11) 來檢查它是否不為零(我們處理的是無符號整數,所以它當然不能是負數)。 然後我們將結果寫入 `isToContract`。 + +```solidity + require(to.balance != 0 || isToContract, "Can't send tokens to an empty address"); +``` + +最後,我們有了對空地址的實際檢查。 + +## 管理員存取權 {#admin-access} + +有時,有一個可以撤銷錯誤的管理員是很有用的。 為了減少濫用的可能性,這個管理員可以是一個[多重簽名](https://blog.logrocket.com/security-choices-multi-signature-wallets/),這樣就需要多個人同意一項操作。 在本文中,我們將介紹兩種管理功能: + +1. 凍結和解凍帳戶。 這很有用,例如,當一個帳戶可能被盜用時。 +2. 資產清理。 + + 有時,詐騙者會將欺詐性代幣傳送到真實代幣的合約中以獲得合法性。 例如,[請看這裡](https://optimism.blockscout.com/token/0x2348B1a1228DDCd2dB668c3d30207c3E1852fBbe?tab=holders)。 合法的 ERC-20 合約是 [0x4200....0042](https://optimism.blockscout.com/token/0x4200000000000000000000000000000000000042)。 冒充它的詐騙是 [0x234....bbe](https://optimism.blockscout.com/token/0x2348B1a1228DDCd2dB668c3d30207c3E1852fBbe)。 + + 人們也可能錯誤地將合法的 ERC-20 代幣傳送到我們的合約中,這也是我們希望有辦法將它們取出的另一個原因。 + +OpenZeppelin 提供了兩種啟用管理員存取權的機制: + +- [`Ownable`](https://docs.openzeppelin.com/contracts/5.x/access-control#ownership-and-ownable) 合約只有一個擁有者。 具有 `onlyOwner` [修飾符](https://www.tutorialspoint.com/solidity/solidity_function_modifiers.htm)的函式只能由該擁有者調用。 擁有者可以將所有權轉讓給其他人或完全放棄。 所有其他帳戶的權利通常是相同的。 +- [`AccessControl`](https://docs.openzeppelin.com/contracts/5.x/access-control#role-based-access-control) 合約具有[基於角色的存取控制 (RBAC)](https://en.wikipedia.org/wiki/Role-based_access_control)。 + +為簡單起見,本文我們使用 `Ownable`。 + +### 凍結和解凍合約 {#freezing-and-thawing-contracts} + +凍結和解凍合約需要進行幾項變更: + +- 一個從地址到[布林值](https://en.wikipedia.org/wiki/Boolean_data_type)的[對應](https://www.tutorialspoint.com/solidity/solidity_mappings.htm),用於追蹤哪些地址被凍結。 所有值最初都為零,對於布林值,這被解釋為 false。 這就是我們想要的,因為預設情況下帳戶是未凍結的。 + + ```solidity + mapping(address => bool) public frozenAccounts; + ``` + +- 當帳戶被凍結或解凍時,使用[事件](https://www.tutorialspoint.com/solidity/solidity_events.htm)通知任何感興趣的人。 從技術上講,這些操作不需要事件,但它有助於鏈外程式碼能夠監聽這些事件並了解正在發生的事情。 當發生可能與他人相關的事情時,智能合約發出事件被認為是一種良好的習慣。 + + 事件被索引,因此可以搜尋帳戶被凍結或解凍的所有次數。 + + ```solidity + // 當帳戶被凍結或解凍時 + event AccountFrozen(address indexed _addr); + event AccountThawed(address indexed _addr); + ``` + +- 用於凍結和解凍帳戶的函式。 這兩個函式幾乎相同,所以我們只會介紹凍結函式。 + + ```solidity + function freezeAccount(address addr) + public + onlyOwner + ``` + + 標記為 [`public`](https://www.tutorialspoint.com/solidity/solidity_contracts.htm) 的函式可以從其他智能合約或直接透過交易調用。 + + ```solidity + { + require(!frozenAccounts[addr], "Account already frozen"); + frozenAccounts[addr] = true; + emit AccountFrozen(addr); + } // freezeAccount + ``` + + 如果帳戶已凍結,則回復。 否則,凍結它並 `emit` 一個事件。 + +- 變更 `_beforeTokenTransfer` 以防止資金從凍結帳戶中移出。 請注意,資金仍然可以轉入凍結帳戶。 + + ```solidity + require(!frozenAccounts[from], "The account is frozen"); + ``` + +### 資產清理 {#asset-cleanup} + +要釋放此合約持有的 ERC-20 代幣,我們需要調用它們所屬代幣合約上的一個函式,可以是 [`transfer`](https://eips.ethereum.org/EIPS/eip-20#transfer) 或 [`approve`](https://eips.ethereum.org/EIPS/eip-20#approve)。 在這種情況下,在授權上浪費 Gas 是沒有意義的,我們不如直接轉帳。 + +```solidity + function cleanupERC20( + address erc20, + address dest + ) + public + onlyOwner + { + IERC20 token = IERC20(erc20); +``` + +這是我們在收到地址時為合約建立物件的語法。 我們可以這樣做,因為我們的原始碼中包含了 ERC20 代幣的定義(參見第 4 行),並且該檔案包含了 [IERC20 的定義](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol),這是 OpenZeppelin ERC-20 合約的介面。 + +```solidity + uint balance = token.balanceOf(address(this)); + token.transfer(dest, balance); + } +``` + +這是一個清理函式,所以我們大概不希望留下任何代幣。 與其手動從使用者那裡獲取餘額,我們不如自動化這個過程。 + +## 結論 {#conclusion} + +這不是一個完美的解決方案——對於「使用者犯錯」這個問題,沒有完美的解決方案。 然而,使用這類檢查至少可以防止一些錯誤。 凍結帳戶的能力雖然危險,但可以用來限制某些駭客攻擊的損害,方法是拒絕駭客竊取資金。 + +[在此查看我的更多作品](https://cryptodocguy.pro/)。 diff --git a/public/content/translations/zh-tw/developers/tutorials/ethereum-for-web2-auth/index.md b/public/content/translations/zh-tw/developers/tutorials/ethereum-for-web2-auth/index.md new file mode 100644 index 00000000000..1ceb9671416 --- /dev/null +++ b/public/content/translations/zh-tw/developers/tutorials/ethereum-for-web2-auth/index.md @@ -0,0 +1,886 @@ +--- +title: "使用以太坊進行 Web2 驗證" +description: "閱讀本教學後,開發者將能夠將以太坊登入 (Web3) 與 SAML 登入整合。SAML 登入是 Web2 中使用的一種標準,可提供單一登入及其他相關服務。 這允許透過以太坊簽章來驗證對 Web2 資源的存取,且使用者屬性來自證明。" +author: Ori Pomerantz +tags: [ "web2", "驗證", "eas" ] +skill: beginner +lang: zh-tw +published: 2025-04-30 +--- + +## 簡介 + +[SAML](https://www.onelogin.com/learn/saml) 是 Web2 上使用的一種標準,允許[身分提供者 (IdP)](https://en.wikipedia.org/wiki/Identity_provider#SAML_identity_provider) 為[服務提供者 (SP)](https://en.wikipedia.org/wiki/Service_provider_\(SAML\)) 提供使用者資訊。 + +在本教學中,您將學習如何將以太坊簽章與 SAML 整合,讓使用者能夠使用其以太坊錢包來對那些尚不原生支援以太坊的 Web2 服務進行身分驗證。 + +請注意,本教學是為兩種不同的受眾所撰寫: + +- 了解以太坊且需要學習 SAML 的以太坊使用者 +- 了解 SAML 和 Web2 驗證且需要學習以太坊的 Web2 使用者 + +因此,本教學會包含許多您已知的入門資料。 您可以隨意跳過。 + +### 為以太坊使用者介紹 SAML + +SAML 是一種中心化協定。 只有在服務提供者 (SP) 與身分提供者 (IdP) 或簽署該 IdP 憑證的[憑證授權單位](https://www.ssl.com/article/what-is-a-certificate-authority-ca/)有預先存在的信任關係時,服務提供者才會接受身分提供者所做的斷言 (例如「這是我的使用者 John,他應該有權限執行 A、B 和 C」)。 + +例如,SP 可以是為公司提供旅行服務的旅行社,而 IdP 可以是公司的內部網站。 當員工需要預訂商務旅行時,旅行社會在允許他們實際預訂旅行之前,先將他們傳送到公司進行驗證。 + +![SAML 流程逐步說明](./fig-01-saml.png) + +這就是瀏覽器、SP 和 IdP 這三個實體協商存取權限的方式。 SP 不需要事先知道任何關於使用瀏覽器的使用者的資訊,只需要信任 IdP 即可。 + +### 為 SAML 使用者介紹以太坊 + +以太坊是去中心化系統。 + +![以太坊登入](./fig-02-eth-logon.png) + +使用者擁有私密金鑰 (通常儲存在瀏覽器擴充功能中)。 您可以從私密金鑰衍生出公鑰,再從公鑰衍生出 20 位元組的地址。 當使用者需要登入系統時,系統會要求他們簽署一則附有 nonce (單次使用值) 的訊息。 伺服器可以驗證該簽章是由該地址所建立。 + +![從證明中取得額外資料](./fig-03-eas-data.png) + +該簽章只會驗證以太坊地址。 若要取得其他使用者屬性,您通常會使用[證明](https://attest.org/)。 證明通常具有以下欄位: + +- **證明人**,做出證明的地址 +- **接收者**,證明所適用的地址 +- **資料**,正在證明的資料,例如姓名、權限等。 +- **結構**,用於解譯資料的結構 ID。 + +由於以太坊的去中心化性質,任何使用者都可以做出證明。 證明人的身分對於識別我們認為哪些證明是可靠的至關重要。 + +## 設定 + +第一步是讓 SAML SP 和 SAML IdP 能夠互相通訊。 + +1. 下載軟體。 本文的範例軟體在 [github](https://github.com/qbzzt/250420-saml-ethereum) 上。 不同的階段儲存在不同的分支中,此階段您需要 `saml-only` + + ```sh + git clone https://github.com/qbzzt/250420-saml-ethereum -b saml-only + cd 250420-saml-ethereum + pnpm install + ``` + +2. 使用自我簽署憑證建立金鑰。 這表示該金鑰本身即是憑證授權單位,需要手動匯入至服務提供者。 如需詳細資訊,請參閱 [OpenSSL 文件](https://docs.openssl.org/master/man1/openssl-req/)。 + + ```sh + mkdir keys + cd keys + openssl req -new -x509 -days 365 -nodes -sha256 -out saml-sp.crt -keyout saml-sp.pem -subj /CN=sp/ + openssl req -new -x509 -days 365 -nodes -sha256 -out saml-idp.crt -keyout saml-idp.pem -subj /CN=idp/ + cd .. + ``` + +3. 啟動伺服器 (SP 和 IdP) + + ```sh + pnpm start + ``` + +4. 瀏覽至 SP URL [http://localhost:3000/](http://localhost:3000/),然後按一下按鈕,重新導向至 IdP (通訊埠 3001)。 + +5. 向 IdP 提供您的電子郵件地址,然後按一下「**登入服務提供者**」。 確認您已重新導向回服務提供者 (通訊埠 3000),且服務提供者可透過您的電子郵件地址識別您的身分。 + +### 詳細說明 + +以下是逐步發生的情況: + +![不含以太坊的一般 SAML 登入](./fig-04-saml-no-eth.png) + +#### src/config.mts + +此檔案包含身分提供者和服務提供者的組態。 通常這兩者是不同的實體,但為了簡便起見,我們在此共用程式碼。 + +```typescript +const fs = await import("fs") + +const protocol="http" +``` + +目前我們只是在測試,所以使用 HTTP 沒問題。 + +```typescript +export const spCert = fs.readFileSync("keys/saml-sp.crt").toString() +export const idpCert = fs.readFileSync("keys/saml-idp.crt").toString() +``` + +讀取公鑰,公鑰通常可供兩個元件使用 (直接信任,或由受信任的憑證授權單位簽署)。 + +```typescript +export const spPort = 3000 +export const spHostname = "localhost" +export const spDir = "sp" + +export const idpPort = 3001 +export const idpHostname = "localhost" +export const idpDir = "idp" + +export const spUrl = `${protocol}://${spHostname}:${spPort}/${spDir}` +export const idpUrl = `${protocol}://${idpHostname}:${idpPort}/${idpDir}` +``` + +這兩個元件的 URL。 + +```typescript +export const spPublicData = { +``` + +服務提供者的公開資料。 + +```typescript + entityID: `${spUrl}/metadata`, +``` + +在 SAML 中,依照慣例,`entityID` 是實體中繼資料所在的 URL。 此中繼資料對應於此處的公開資料,但其格式為 XML。 + +```typescript + wantAssertionsSigned: true, + authnRequestsSigned: false, + signingCert: spCert, + allowCreate: true, + assertionConsumerService: [{ + Binding: 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST', + Location: `${spUrl}/assertion`, + }] + } +``` + +就我們的目的而言,最重要的定義是 `assertionConsumerServer`。 這表示若要向服務提供者宣告某件事 (例如「傳送此資訊給您的使用者是 somebody@example.com」),我們需要使用 [HTTP POST](https://www.w3schools.com/tags/ref_httpmethods.asp) 到 URL `http://localhost:3000/sp/assertion`。 + +```typescript +export const idpPublicData = { + entityID: `${idpUrl}/metadata`, + signingCert: idpCert, + wantAuthnRequestsSigned: false, + singleSignOnService: [{ + Binding: "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST", + Location: `${idpUrl}/login` + }], + singleLogoutService: [{ + Binding: "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST", + Location: `${idpUrl}/logout` + }], + } +``` + +身分提供者的公開資料是相似的。 它指定若要登入使用者,您需 POST 至 `http://localhost:3001/idp/login`,若要登出使用者,則 POST 至 `http://localhost:3001/idp/logout`。 + +#### src/sp.mts + +這是實作服務提供者的程式碼。 + +```typescript +import * as config from "./config.mts" +const fs = await import("fs") +const saml = await import("samlify") +``` + +我們使用 [`samlify`](https://www.npmjs.com/package/samlify) 庫來實作 SAML。 + +```typescript +import * as validator from "@authenio/samlify-node-xmllint" +saml.setSchemaValidator(validator) +``` + +`samlify` 庫需要一個套件來驗證 XML 是否正確、是否使用預期的公鑰簽署等。 為此,我們使用 [`@authenio/samlify-node-xmllint`](https://www.npmjs.com/package/@authenio/samlify-node-xmllint)。 + +```typescript +const express = (await import("express")).default +const spRouter = express.Router() +const app = express() +``` + +[`express`](https://expressjs.com/) [`Router`](https://expressjs.com/en/5x/api.html#router) 是一個可以掛載在網站中的「迷你網站」。 在此情況下,我們使用它將所有服務提供者定義群組在一起。 + +```typescript +const spPrivateKey = fs.readFileSync("keys/saml-sp.pem").toString() + +const sp = saml.ServiceProvider({ + privateKey: spPrivateKey, + ...config.spPublicData +}) +``` + +服務提供者自身的表示是所有公開資料,以及它用來簽署資訊的私密金鑰。 + +```typescript +const idp = saml.IdentityProvider(config.idpPublicData); +``` + +公開資料包含服務提供者需要了解的身分提供者的所有資訊。 + +```typescript +spRouter.get(`/metadata`, + (req, res) => res.header("Content-Type", "text/xml").send(sp.getMetadata()) +) +``` + +為了與其他 SAML 元件互通,服務和身分提供者的公開資料 (稱為中繼資料) 應以 XML 格式在 `/metadata` 中提供。 + +```typescript +spRouter.post(`/assertion`, +``` + +這是瀏覽器存取以識別自身的頁面。 宣告包含使用者識別碼 (此處我們使用電子郵件地址),並且可以包含額外的屬性。 這是上方序列圖中步驟 7 的處理常式。 + +```typescript + async (req, res) => { + // console.log(`SAML response:\n${Buffer.from(req.body.SAMLResponse, 'base64').toString('utf-8')}`) +``` + +您可以使用已註解的指令來查看斷言中提供的 XML 資料。 它是 [base64 編碼的](https://en.wikipedia.org/wiki/Base64)。 + +```typescript + try { + const loginResponse = await sp.parseLoginResponse(idp, 'post', req); +``` + +解析來自身分伺服器的登入請求。 + +```typescript + res.send(` + + +

Hello ${loginResponse.extract.nameID}

+ + + `) + res.send(); +``` + +傳送 HTML 回應,僅是為了向使用者顯示我們已收到登入請求。 + +```typescript + } catch (err) { + console.error('Error processing SAML response:', err); + res.status(400).send('SAML authentication failed'); + } + } +) +``` + +如果失敗,請通知使用者。 + +```typescript +spRouter.get('/login', +``` + +當瀏覽器嘗試取得此頁面時,建立一個登入請求。 這是上方序列圖中步驟 1 的處理常式。 + +```typescript + async (req, res) => { + const loginRequest = await sp.createLoginRequest(idp, "post") +``` + +取得發布登入請求的資訊。 + +```typescript + res.send(` + + + +``` + +此頁面會自動提交表單 (見下文)。 如此一來,使用者就不需要執行任何操作即可被重新導向。 這是上方序列圖中的步驟 2。 + +```typescript +
+``` + +張貼到 `loginRequest.entityEndpoint` (身分提供者端點的 URL)。 + +```typescript + +``` + +輸入名稱為 `loginRequest.type` (`SAMLRequest`)。 該欄位的內容是 `loginRequest.context`,它同樣是經過 base64 編碼的 XML。 + +```typescript +
+ + + `) + } +) + +app.use(express.urlencoded({extended: true})) +``` + +[此中介軟體](https://expressjs.com/en/5x/api.html#express.urlencoded) 會讀取 [HTTP 請求](https://www.tutorialspoint.com/http/http_requests.htm)的主體。 預設情況下,express 會忽略它,因為大多數請求並不需要它。 我們需要它,因為 POST 會使用主體。 + +```typescript +app.use(`/${config.spDir}`, spRouter) +``` + +在服務提供者目錄 (`/sp`) 中掛載路由器。 + +```typescript +app.get("/", (req, res) => { + res.send(` + + + + + + `) +}) +``` + +如果瀏覽器嘗試取得根目錄,請為其提供登入頁面的連結。 + +```typescript +app.listen(config.spPort, () => { + console.log(`service provider is running on http://${config.spHostname}:${config.spPort}`) +}) +``` + +使用此 express 應用程式監聽 `spPort`。 + +#### src/idp.mts + +這是身分提供者。 它與服務提供者非常相似,以下說明是針對不同的部分。 + +```typescript +const xmlParser = new (await import("fast-xml-parser")).XMLParser( + { + ignoreAttributes: false, // Preserve attributes + attributeNamePrefix: "@_", // Prefix for attributes + } +) +``` + +我們需要讀取並理解從服務提供者收到的 XML 請求。 + +```typescript +const getLoginPage = requestId => ` +``` + +此函數會建立一個帶有自動提交表單的頁面,該頁面會在上方序列圖的步驟 4 中傳回。 + +```typescript + + + Login page + + +

Login page

+
+ + Email address: +
+ +``` + +我們傳送給服務提供者的欄位有兩個: + +1. 我們正在回應的 `requestId`。 +2. 使用者識別碼 (目前我們使用使用者提供的電子郵件地址)。 + +```typescript +
+ + + +const idpRouter = express.Router() + +idpRouter.post("/loginSubmitted", async (req, res) => { + const loginResponse = await idp.createLoginResponse( +``` + +這是上方序列圖中步驟 5 的處理常式。 [`idp.createLoginResponse`](https://github.com/tngan/samlify/blob/master/src/entity-idp.ts#L73-L125) 會建立登入回應。 + +```typescript + sp, + { + authnContextClassRef: 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport', + audience: sp.entityID, +``` + +對象為服務提供者。 + +```typescript + extract: { + request: { + id: req.body.requestId + } + }, +``` + +從請求中提取的資訊。 我們在請求中關心的一個參數是 requestId,它讓服務提供者能夠匹配請求及其回應。 + +```typescript + signingKey: { privateKey: idpPrivateKey, publicKey: config.idpCert } // Ensure signing +``` + +我們需要 `signingKey` 擁有簽署回應的資料。 服務提供者不信任未經簽署的請求。 + +```typescript + }, + "post", + { + email: req.body.email +``` + +這是我們傳送回服務提供者的使用者資訊欄位。 + +```typescript + } + ); + + res.send(` + + + + +
+ +
+ + + `) +}) +``` + +同樣,使用自動提交的表單。 這是上方序列圖中的步驟 6。 + +```typescript + +// IdP endpoint for login requests +idpRouter.post(`/login`, +``` + +這是從服務提供者接收登入請求的端點。 這是上方序列圖中步驟 3 的處理常式。 + +```typescript + async (req, res) => { + try { + // Workaround because I couldn't get parseLoginRequest to work. + // const loginRequest = await idp.parseLoginRequest(sp, 'post', req) + const samlRequest = xmlParser.parse(Buffer.from(req.body.SAMLRequest, 'base64').toString('utf-8')) + res.send(getLoginPage(samlRequest["samlp:AuthnRequest"]["@_ID"])) +``` + +我們應該能夠使用 [`idp.parseLoginRequest`](https://github.com/tngan/samlify/blob/master/src/entity-idp.ts#L127-L144) 來讀取驗證請求的 ID。 然而,我無法讓它正常運作,而且不值得花太多時間,所以我只使用[通用的 XML 解析器](https://www.npmjs.com/package/fast-xml-parser)。 我們需要的資訊是 `` 標籤內的 `ID` 屬性,它位於 XML 的最上層。 + +## 使用以太坊簽章 + +既然我們能夠將使用者身分傳送給服務提供者,下一步就是以受信任的方式取得使用者身分。 Viem 允許我們直接向錢包詢問使用者地址,但這表示要向瀏覽器索取資訊。 我們無法控制瀏覽器,所以不能自動信任從它那裡得到的回應。 + +因此,IdP 會傳送一個字串給瀏覽器進行簽署。 如果瀏覽器中的錢包簽署了這個字串,這就表示它確實是那個地址 (也就是說,它知道對應於該地址的私密金鑰)。 + +要查看此操作,請停止現有的 IdP 和 SP,並執行以下命令: + +```sh +git checkout eth-signatures +pnpm install +pnpm start +``` + +然後瀏覽至 [SP](http://localhost:3000) 並依照指示操作。 + +請注意,此時我們不知道如何從以太坊地址取得電子郵件地址,因此我們向 SP 回報 `@bad.email.address`。 + +### 詳細說明 + +變更發生在先前圖表中的步驟 4-5。 + +![帶有以太坊簽章的 SAML](./fig-05-saml-w-signature.png) + +我們唯一變更的檔案是 `idp.mts`。 以下是已變更的部分。 + +```typescript +import { v4 as uuidv4 } from 'uuid' +import { verifyMessage } from 'viem' +``` + +我們需要這兩個額外的庫。 我們使用 [`uuid`](https://www.npmjs.com/package/uuid) 來建立 [nonce](https://en.wikipedia.org/wiki/Cryptographic_nonce) 值。 值本身並不重要,重要的是它只使用一次。 + +[`viem`](https://viem.sh/) 庫讓我們能夠使用以太坊的定義。 此處我們需要它來驗證簽章確實有效。 + +```typescript +const loginPrompt = "To access the service provider, sign this nonce: " +``` + +錢包會要求使用者允許簽署該訊息。 僅包含 nonce 的訊息可能會讓使用者感到困惑,因此我們加入了這個提示。 + +```typescript +// Keep requestIDs here +let nonces = {} +``` + +我們需要請求資訊才能回應它。 我們可以隨請求傳送它 (步驟 4),然後再接收回來 (步驟 5)。 然而,我們不能信任從瀏覽器取得的資訊,因為瀏覽器在一個可能具有敵意的使用者的控制之下。 所以最好將它儲存在這裡,並以 nonce 作為金鑰。 + +請注意,為了簡單起見,我們在此將它作為一個變數。 然而,這有幾個缺點: + +- 我們容易受到拒絕服務攻擊。 惡意使用者可以多次嘗試登入,耗盡我們的記憶體。 +- 如果 IdP 程序需要重新啟動,我們會遺失現有的值。 +- 我們無法在多個程序之間進行負載平衡,因為每個程序都有自己的變數。 + +在生產系統上,我們會使用資料庫並實作某種過期機制。 + +```typescript +const getSignaturePage = requestId => { + const nonce = uuidv4() + nonces[nonce] = requestId +``` + +建立一個 nonce,並儲存 `requestId` 以供日後使用。 + +```typescript + return ` + + + + + +

Please sign

+ +
+ + + +` +} +``` + +其餘的只是標準的 HTML。 + +```typescript +idpRouter.get("/signature/:nonce/:account/:signature", async (req, res) => { +``` + +這是序列圖中步驟 5 的處理常式。 + +```typescript + const requestId = nonces[req.params.nonce] + if (requestId === undefined) { + res.send("Bad nonce") + return ; + } + + nonces[req.params.nonce] = undefined +``` + +取得請求 ID,並從 `nonces` 中刪除該 nonce,以確保無法重複使用。 + +```typescript + try { +``` + +由於簽章可能無效的方式有很多種,我們將此包裝在 `try ...` `catch` 區塊中,以捕捉任何擲出的錯誤。 + +```typescript + const validSignature = await verifyMessage({ + address: req.params.account, + message: `${loginPrompt}${req.params.nonce}`, + signature: req.params.signature + }) +``` + +使用 [`verifyMessage`](https://viem.sh/docs/actions/public/verifyMessage#verifymessage) 來實作序列圖中的步驟 5.5。 + +```typescript + if (!validSignature) + throw("Bad signature") + } catch (err) { + res.send("Error:" + err) + return ; + } +``` + +此處理程式的其餘部分與我們之前在 `/loginSubmitted` 處理程式中所做的相同,除了一個小小的變更。 + +```typescript + const loginResponse = await idp.createLoginResponse( + . + . + . + { + email: req.params.account + "@bad.email.address" + } + ); +``` + +我們沒有實際的電子郵件地址 (我們將在下一節中取得),所以現在我們先傳回以太坊地址,並清楚地標示它不是一個電子郵件地址。 + +```typescript +// IdP endpoint for login requests +idpRouter.post(`/login`, + async (req, res) => { + try { + // Workaround because I couldn't get parseLoginRequest to work. + // const loginRequest = await idp.parseLoginRequest(sp, 'post', req) + const samlRequest = xmlParser.parse(Buffer.from(req.body.SAMLRequest, 'base64').toString('utf-8')) + res.send(getSignaturePage(samlRequest["samlp:AuthnRequest"]["@_ID"])) + } catch (err) { + console.error('Error processing SAML response:', err); + res.status(400).send('SAML authentication failed'); + } + } +) +``` + +現在在步驟 3 的處理常式中使用 `getSignaturePage` 取代 `getLoginPage`。 + +## 取得電子郵件地址 + +下一步是取得電子郵件地址,也就是服務提供者請求的識別碼。 為此,我們使用[以太坊證明服務 (EAS)](https://attest.org/)。 + +取得證明最簡單的方法是使用 [GraphQL API](https://docs.attest.org/docs/developer-tools/api)。 我們使用此查詢: + +``` +query GetAttestationsByRecipient { + attestations( + where: { + recipient: { equals: "${getAddress(ethAddr)}" } + schemaId: { equals: "0xfa2eff59a916e3cc3246f9aec5e0ca00874ae9d09e4678e5016006f07622f977" } + } + take: 1 + ) { + data + id + attester + } +} +``` + +這個 [`schemaId`](https://optimism.easscan.org/schema/view/0xfa2eff59a916e3cc3246f9aec5e0ca00874ae9d09e4678e5016006f07622f977) 只包含一個電子郵件地址。 此查詢要求此結構的證明。 證明的主體稱為「`recipient`」(接收者)。 它永遠是以太坊地址。 + +警告:我們在此處取得證明的方式有兩個安全問題。 + +- 我們前往的 API 端點是 `https://optimism.easscan.org/graphql`,這是一個中心化元件。 我們可以取得 `id` 屬性,然後在鏈上進行查詢以驗證證明是否真實,但 API 端點仍然可以透過不告知我們來審查證明。 + + 這個問題並非無法解決,我們可以執行自己的 GraphQL 端點並從鏈記錄中取得證明,但這對我們的目的來說太過繁瑣。 + +- 我們不看證明人的身分。 任何人都可以提供我們錯誤的資訊。 在實際的實作中,我們會有一組受信任的證明人,並且只查看他們的證明。 + +要查看此操作,請停止現有的 IdP 和 SP,並執行以下命令: + +```sh +git checkout email-address +pnpm install +pnpm start +``` + +然後提供您的電子郵件地址。 您有兩種方式可以做到: + +- 使用私密金鑰匯入錢包,並使用測試私密金鑰 `0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80`。 + +- 為您自己的電子郵件地址新增一則證明: + + 1. 在證明瀏覽器中瀏覽至[該結構](https://optimism.easscan.org/schema/view/0xfa2eff59a916e3cc3246f9aec5e0ca00874ae9d09e4678e5016006f07622f977)。 + + 2. 按一下「**使用結構證明**」。 + + 3. 輸入您的以太坊地址作為接收者,您的電子郵件地址作為 email address,並選取**鏈上**。 然後按一下「**進行證明**」。 + + 4. 在您的錢包中核准交易。 您將需要在 [Optimism 區塊鏈](https://app.optimism.io/bridge/deposit) 上擁有一些 ETH 以支付 Gas。 + +無論哪種方式,完成後請瀏覽至 [http://localhost:3000](http://localhost:3000) 並依照指示操作。 如果您匯入了測試私密金鑰,您收到的電子郵件是 `test_addr_0@example.com`。 如果您使用自己的地址,它應該是您所證明的任何內容。 + +### 詳細說明 + +![從以太坊地址取得電子郵件](./fig-06-saml-sig-n-email.png) + +新的步驟是 GraphQL 通訊,即步驟 5.6 和 5.7。 + +同樣,以下是 `idp.mts` 的已變更部分。 + +```typescript +import { GraphQLClient } from 'graphql-request' +import { SchemaEncoder } from '@ethereum-attestation-service/eas-sdk' +``` + +匯入我們需要的庫。 + +```typescript +const graphqlEndpointUrl = "https://optimism.easscan.org/graphql" +``` + +[每個區塊鏈都有一個獨立的端點](https://docs.attest.org/docs/developer-tools/api)。 + +```typescript +const graphqlClient = new GraphQLClient(graphqlEndpointUrl, { fetch }) +``` + +建立一個新的 `GraphQLClient` 用戶端,可用於查詢端點。 + +```typescript +const graphqlSchema = 'string emailAddress' +const graphqlEncoder = new SchemaEncoder(graphqlSchema) +``` + +GraphQL 只提供我們一個不透明的位元組資料物件。 若要理解它,我們需要結構。 + +```typescript +const ethereumAddressToEmail = async ethAddr => { +``` + +一個從以太坊地址取得電子郵件地址的函數。 + +```typescript + const query = ` + query GetAttestationsByRecipient { +``` + +這是一個 GraphQL 查詢。 + +```typescript + attestations( +``` + +我們正在尋找證明。 + +```typescript + where: { + recipient: { equals: "${getAddress(ethAddr)}" } + schemaId: { equals: "0xfa2eff59a916e3cc3246f9aec5e0ca00874ae9d09e4678e5016006f07622f977" } + } +``` + +我們想要的證明是我們結構中的證明,其中接收者是 `getAddress(ethAddr)`。 [`getAddress`](https://viem.sh/docs/utilities/getAddress#getaddress) 函數可確保我們的地址具有正確的[校驗和](https://github.com/ethereum/ercs/blob/master/ERCS/erc-55.md)。 這對於 GraphQL 而言是必要的,因為 GraphQL 區分大小寫。 「0xBAD060A7」、「0xBad060A7」和「0xbad060a7」是不同的值。 + +```typescript + take: 1 +``` + +無論我們找到多少則證明,我們只需要第一則。 + +```typescript + ) { + data + id + attester + } + }` +``` + +我們想要接收的欄位。 + +- `attester`:提交證明的地址。 通常這用於決定是否信任該證明。 +- `id`:證明 ID。 您可以使用此值[在鏈上讀取證明](https://optimism.blockscout.com/address/0x4200000000000000000000000000000000000021?tab=read_proxy&source_address=0x4E0275Ea5a89e7a3c1B58411379D1a0eDdc5b088#0xa3112a64)以驗證 GraphQL 查詢的資訊是否正確。 +- `data`:結構資料 (在此情況下為電子郵件地址)。 + +```typescript + const queryResult = await graphqlClient.request(query) + + if (queryResult.attestations.length == 0) + return "no_address@available.is" +``` + +如果沒有證明,則傳回一個明顯不正確的值,但服務提供者會認為它有效。 + +```typescript + const attestationDataFields = graphqlEncoder.decodeData(queryResult.attestations[0].data) + return attestationDataFields[0].value.value +} +``` + +如果有值,請使用 `decodeData` 解碼資料。 我們不需要它提供的中繼資料,只需要值本身。 + +```typescript + const loginResponse = await idp.createLoginResponse( + sp, + { + . + . + . + }, + "post", + { + email: await ethereumAddressToEmail(req.params.account) + } + ); +``` + +使用新函數取得電子郵件地址。 + +## 關於去中心化呢? + +在此組態中,只要我們依賴可信的證明人進行以太坊到電子郵件地址的對應,使用者就無法冒充他人。 然而,我們的身分提供者仍然是一個中心化元件。 任何擁有身分提供者私密金鑰的人都可以向服務提供者傳送虛假資訊。 + +使用[多方運算 (MPC)](https://en.wikipedia.org/wiki/Secure_multi-party_computation) 可能是一個解決方案。 我希望在未來的教學中寫到它。 + +## 結論 + +採用登入標準 (例如以太坊簽章) 會面臨雞生蛋、蛋生雞的問題。 服務提供者希望吸引盡可能廣泛的市場。 使用者希望能夠存取服務,而不用擔心支援其登入標準。 +建立適配器 (例如以太坊 IdP) 可以幫助我們克服這個障礙。 + +[在此查看我的更多作品](https://cryptodocguy.pro/)。 diff --git a/public/content/translations/zh-tw/developers/tutorials/getting-started-with-ethereum-development-using-alchemy/index.md b/public/content/translations/zh-tw/developers/tutorials/getting-started-with-ethereum-development-using-alchemy/index.md new file mode 100644 index 00000000000..379cc058bb9 --- /dev/null +++ b/public/content/translations/zh-tw/developers/tutorials/getting-started-with-ethereum-development-using-alchemy/index.md @@ -0,0 +1,149 @@ +--- +title: "開始以太坊開發之旅" +description: "這是一份以太坊開發的入門指南。 我們將引導您完成建立 API 端點、發出命令列請求,到撰寫您的第一個 Web3 腳本! 無需區塊鏈開發經驗!" +author: "Elan Halpern" +tags: [ "JavaScript", "ethers.js", "節點", "諮詢", "Alchemy" ] +skill: beginner +lang: zh-tw +published: 2020-10-30 +source: Medium +sourceUrl: https://medium.com/alchemy-api/getting-started-with-ethereum-development-using-alchemy-c3d6a45c567f +--- + +![以太坊和 Alchemy 標誌](./ethereum-alchemy.png) + +這是一份以太坊開發的入門指南。 在本教學中,我們將使用 [Alchemy](https://alchemyapi.io/),這是一個領先的區塊鏈開發者平台,為 70% 的頂級區塊鏈應用程式 (包括 Maker、0x、MyEtherWallet、Dharma 和 Kyber) 的數百萬名使用者提供支援。 Alchemy 將讓我們能夠存取以太坊鏈上的 API 端點,以便我們讀取和寫入交易。 + +我們將引導您從註冊 Alchemy 到撰寫您的第一個 Web3 腳本! 無需區塊鏈開發經驗! + +## 1. 註冊免費的 Alchemy 帳戶 {#sign-up-for-a-free-alchemy-account} + +建立 Alchemy 帳戶很簡單,[在此免費註冊](https://auth.alchemy.com/)。 + +## 2. 建立 Alchemy 應用程式 {#create-an-alchemy-app} + +若要與以太坊鏈通訊並使用 Alchemy 的產品,您需要一個 API 金鑰來驗證您的請求。 + +您可以[從儀表板建立 API 金鑰](https://dashboard.alchemy.com/)。 若要建立新的金鑰,請如下所示導覽至「Create App」: + +特別感謝 [_ShapeShift_](https://shapeshift.com/) _讓我們展示他們的儀表板!_ + +![Alchemy 儀表板](./alchemy-dashboard.png) + +在「Create App」下填寫詳細資料,即可取得新的金鑰。 您也可以在此處看到您先前建立的應用程式,以及您團隊建立的應用程式。 按一下任何應用程式的「View Key」來擷取現有的金鑰。 + +![使用 Alchemy 建立應用程式的螢幕截圖](./create-app.png) + +您也可以將游標懸停在「Apps」上並選取一個應用程式,來擷取現有的 API 金鑰。 您可以在此處「View Key」(檢視金鑰) 以及「Edit App」(編輯應用程式),將特定網域加入白名單、查看多個開發者工具,以及檢視分析資料。 + +![顯示使用者如何擷取 API 金鑰的 Gif](./pull-api-keys.gif) + +## 3 從命令列發出請求 {#make-a-request-from-the-command-line} + +透過 Alchemy 使用 JSON-RPC 和 curl 與以太坊區塊鏈互動。 + +對於手動請求,我們建議透過 `POST` 請求與 `JSON-RPC` 互動。 只需傳入 `Content-Type: application/json` 標頭,並將您的查詢作為 `POST` 主體,並包含以下欄位: + +- `jsonrpc`:JSON-RPC 版本—目前僅支援 `2.0`。 +- `method`:ETH API 方法。 [請參閱 API 參考資料。](https://docs.alchemyapi.io/documentation/alchemy-api-reference/json-rpc) +- `params`:要傳遞給方法的參數清單。 +- `id`:您請求的 ID。 回應中將會傳回此 ID,以便您追蹤哪個回應屬於哪個請求。 + +以下是您可以從命令列執行的範例,用以擷取目前的 gas 價格: + +```bash +curl https://eth-mainnet.alchemyapi.io/v2/demo \ +-X POST \ +-H "Content-Type: application/json" \ +-d '{"jsonrpc":"2.0","method":"eth_gasPrice","params":[],"id":73}' +``` + +_\*\*注意:\*\*將 [https://eth-mainnet.alchemyapi.io/v2/demo](https://eth-mainnet.alchemyapi.io/jsonrpc/demo) 替換為您自己的 API 金鑰 `https://eth-mainnet.alchemyapi.io/v2/**your-api-key`。_ + +**結果:** + +```json +{ "id": 73,"jsonrpc": "2.0","result": "0x09184e72a000" // 10000000000000 } +``` + +## 4 設定您的 Web3 用戶端 {#set-up-your-web3-client} + +如果您有現有的用戶端,請將您目前的節點提供者 URL 變更為帶有您 API 金鑰的 Alchemy URL:`“https://eth-mainnet.alchemyapi.io/v2/your-api-key\"` + +**_注意:_** 下方的腳本需要在 **節點環境** 中執行,或 **儲存在檔案中** 執行,而非從命令列執行。 如果您尚未安裝 Node 或 npm,請查看這份快速的 [mac 版設定指南](https://app.gitbook.com/@alchemyapi/s/alchemy/guides/alchemy-for-macs)。 + +有許多 [Web3 程式庫](https://docs.alchemyapi.io/guides/getting-started#other-web3-libraries)可以與 Alchemy 整合,但我們建議使用 [Alchemy Web3](https://docs.alchemy.com/reference/api-overview),它是 web3.js 的直接替代品,其建構與設定可和 Alchemy 無縫協作。 這提供了多種優點,例如自動重試和強大的 WebSocket 支援。 + +若要安裝 AlchemyWeb3.js,請 **導覽至您的專案目錄** 並執行: + +**使用 Yarn:** + +``` +yarn add @alch/alchemy-web3 +``` + +**使用 NPM:** + +``` +npm install @alch/alchemy-web3 +``` + +若要與 Alchemy 的節點基礎架構互動,請在 NodeJS 中執行或將此新增至 JavaScript 檔案: + +```js +const { createAlchemyWeb3 } = require("@alch/alchemy-web3") +const web3 = createAlchemyWeb3( + "https://eth-mainnet.alchemyapi.io/v2/your-api-key" +) +``` + +## 5 撰寫您的第一個 Web3 腳本! {#write-your-first-web3-script} + +現在,讓我們來實際動手做一點 Web3 程式設計,我們將撰寫一個簡單的腳本,從以太坊主網印出最新的區塊編號。 + +**1. 如果您尚未這麼做,請在您的終端機中建立一個新的專案目錄,並用 cd 進入該目錄:** + +``` +mkdir web3-example +cd web3-example +``` + +**2. 如果您尚未這麼做,請將 Alchemy Web3 (或任何 Web3) 相依性安裝到您的專案中:** + +``` +npm install @alch/alchemy-web3 +``` + +**3. 建立一個名為 `index.js` 的檔案,並新增以下內容:** + +> 最終您應該將 `demo` 替換為您的 Alchemy HTTP API 金鑰。 + +```js +async function main() { + const { createAlchemyWeb3 } = require("@alch/alchemy-web3") + const web3 = createAlchemyWeb3("https://eth-mainnet.alchemyapi.io/v2/demo") + const blockNumber = await web3.eth.getBlockNumber() + console.log("The latest block number is " + blockNumber) +} +main() +``` + +不熟悉非同步 (async) 相關內容? 請參閱這篇 [Medium 文章](https://medium.com/better-programming/understanding-async-await-in-javascript-1d81bb079b2c)。 + +**4. 使用 node 在您的終端機中執行它** + +``` +node index.js +``` + +**5. 您現在應該會在主控台中看到最新的區塊編號輸出!** + +``` +The latest block number is 11043912 +``` + +**讚! 恭喜! 您剛使用 Alchemy 撰寫了您的第一個 Web3 腳本 🎉** + +不確定下一步要做什麼? 試著部署您的第一個智能合約,並在我們的 [Hello World 智能合約指南](https://www.alchemy.com/docs/hello-world-smart-contract) 中實際動手進行一些 Solidity 程式設計,或使用 [儀表板示範應用程式](https://docs.alchemyapi.io/tutorials/demo-app) 來測試您的儀表板知識! + +_[免費註冊 Alchemy](https://auth.alchemy.com/)、查看我們的[文件](https://www.alchemy.com/docs/),以及如需最新消息,請在 [Twitter](https://twitter.com/AlchemyPlatform) 上追蹤我們_。 diff --git a/public/content/translations/zh-tw/developers/tutorials/guide-to-smart-contract-security-tools/index.md b/public/content/translations/zh-tw/developers/tutorials/guide-to-smart-contract-security-tools/index.md new file mode 100644 index 00000000000..fce032bf7a1 --- /dev/null +++ b/public/content/translations/zh-tw/developers/tutorials/guide-to-smart-contract-security-tools/index.md @@ -0,0 +1,102 @@ +--- +title: "智能合約安全工具指南" +description: "三種不同測試與程式分析技術的概觀" +author: "Trailofbits" +lang: zh-tw +tags: [ "Solidity", "智能合約", "安全性" ] +skill: intermediate +published: 2020-09-07 +source: Building secure contracts +sourceUrl: https://github.com/crytic/building-secure-contracts/tree/master/program-analysis +--- + +我們將使用三種獨特的測試與程式分析技術: + +- 透過 [Slither](/developers/tutorials/how-to-use-slither-to-find-smart-contract-bugs/) 進行靜態分析。程式的所有路徑會透過不同的程式呈現方式(例如控制流程圖)同時進行近似與分析 +- 透過 [Echidna](/developers/tutorials/how-to-use-echidna-to-test-smart-contracts/) 進行模糊測試。程式碼會透過偽隨機產生的交易來執行。 模糊測試器會嘗試找到違反給定屬性的交易序列。 +- 透過 [Manticore](/developers/tutorials/how-to-use-manticore-to-find-smart-contract-bugs/) 進行符號執行。一種正規的驗證技術,將每個執行路徑轉換成數學公式,並在其上檢查約束條件。 + +每種技術都有其優點和缺點,在[特定情況](#determining-security-properties)下會很有用: + +| 技術 | 工具 | 用法 | 速度 | 遺漏的錯誤 | 誤報 | +| ---- | --------- | --------------- | -- | ----- | -- | +| 靜態分析 | Slither | 命令列介面與指令碼 | 秒 | 中等 | 低 | +| 模糊測試 | Echidna | Solidity 屬性 | 分 | 低 | 無 | +| 符號執行 | Manticore | Solidity 屬性與指令碼 | 小時 | 無\* | 無 | + +\* 如果所有路徑都在沒有逾時的情況下完成探索 + +**Slither** 可在幾秒鐘內分析合約,但靜態分析可能會導致誤報,且較不適合用於複雜的檢查(例如算術檢查)。 透過應用程式介面執行 Slither,以按鈕方式存取內建的偵測器,或透過應用程式介面進行使用者定義的檢查。 + +**Echidna** 需要運行數分鐘,且只會產生真陽性結果。 Echidna 會檢查使用者提供的、以 Solidity 編寫的安全屬性。 由於它基於隨機探索,可能會遺漏錯誤。 + +**Manticore** 會執行「最重量級」的分析。 與 Echidna 類似,Manticore 也會驗證使用者提供的屬性。 它需要更長的運行時間,但可以證明屬性的有效性,且不會報告誤報。 + +## 建議工作流程 {#suggested-workflow} + +從 Slither 的內建偵測器開始,確保目前沒有簡單的錯誤,未來也不會引入。 使用 Slither 檢查與繼承、變數相依性和結構性問題相關的屬性。 隨著程式碼庫的增長,使用 Echidna 測試狀態機更複雜的屬性。 再次使用 Slither 開發自訂檢查,以提供 Solidity 中沒有的保護措施,例如防止函式被覆寫。 最後,使用 Manticore 對關鍵安全屬性(例如算術運算)執行有針對性的驗證。 + +- 使用 Slither 的命令列介面來捕捉常見問題 +- 使用 Echidna 測試合約的高階安全屬性 +- 使用 Slither 編寫自訂的靜態檢查 +- 當您想要對關鍵安全屬性進行深度保證時,請使用 Manticore + +**關於單元測試的說明**。 單元測試是建立高品質軟體的必要條件。 然而,這些技術並非最適合用來發現安全漏洞。 它們通常用於測試程式碼的正面行為(即程式碼在正常情況下如預期般運作),而安全漏洞則傾向於存在於開發者未曾考慮到的邊際情況。 在我們對數十個智能合約安全審查的研究中,我們在客戶的程式碼中發現,[單元測試覆蓋率對安全漏洞的數量或嚴重性沒有影響](https://blog.trailofbits.com/2019/08/08/246-findings-from-our-smart-contract-audits-an-executive-summary/)。 + +## 確定安全屬性 {#determining-security-properties} + +為了有效地測試和驗證您的程式碼,您必須找出需要注意的區域。 由於您在安全性上投入的資源有限,確定您程式碼庫中較弱或高價值的部分,對於優化您的投入非常重要。 威脅模型可以提供幫助。 請考慮審查: + +- [快速風險評估](https://infosec.mozilla.org/guidelines/risk/rapid_risk_assessment.html)(時間緊迫時我們的首選方法) +- [以資料為中心的系統威脅模型指南](https://csrc.nist.gov/pubs/sp/800/154/ipd) (又名 NIST 800-154) +- [Shostack 威脅模型](https://www.amazon.com/Threat-Modeling-Designing-Adam-Shostack/dp/1118809998) +- [STRIDE](https://wikipedia.org/wiki/STRIDE_\(security\)) / [DREAD](https://wikipedia.org/wiki/DREAD_\(risk_assessment_model\)) +- [PASTA](https://wikipedia.org/wiki/Threat_model#P.A.S.T.A.) +- [斷言的使用](https://blog.regehr.org/archives/1091) + +### 元件 {#components} + +了解您想檢查的內容,也有助於您選擇正確的工具。 + +與智能合約經常相關的廣泛領域包括: + +- 狀態機。大多數合約都可以表示為狀態機。 考慮檢查 (1) 無法達到任何無效狀態,(2) 如果一個狀態是有效的,那麼它可以被達到,以及 (3) 沒有任何狀態會讓合約陷入陷阱。 + + - Echidna 和 Manticore 是測試狀態機規格的首選工具。 + +- 存取控制。如果您的系統有特權使用者(例如擁有者、控制者等) 您必須確保 (1) 每個使用者只能執行授權的動作,以及 (2) 沒有使用者可以阻止更具特權的使用者執行動作。 + + - Slither、Echidna 和 Manticore 可以檢查存取控制的正確性。 例如,Slither 可以檢查是否只有列入白名單的函式缺少 `onlyOwner` 修飾符。 Echidna 和 Manticore 對於更複雜的存取控制很有用,例如只有在合約達到給定狀態時才授予權限。 + +- 算術運算。檢查算術運算的健全性至關重要。 在各處使用 `SafeMath` 是防止溢出/下溢的好方法,但您仍需考慮其他算術缺陷,包括捨入問題和會讓合約陷入陷阱的缺陷。 + + - Manticore 是這裡的最佳選擇。 如果算術超出 SMT 求解器的範圍,可以使用 Echidna。 + +- \*\*繼承正確性。\*\*Solidity 合約高度依賴多重繼承。 很容易會出現錯誤,例如遮蔽函式缺少 `super` 呼叫,以及對 C3 線性化順序的誤解。 + + - Slither 是確保偵測到這些問題的工具。 + +- 外部互動。合約會彼此互動,而某些外部合約不應被信任。 例如,如果您的合約依賴外部預言機,當一半可用的預言機遭到入侵時,它還能保持安全嗎? + + - Manticore 和 Echidna 是測試您的合約與外部互動的最佳選擇。 Manticore 有內建機制來模擬外部合約。 + +- 標準符合性。以太坊標準(例如 ERC20)的設計歷史上曾出現過瑕疵。 請注意您所依據的標準的限制。 + - Slither、Echidna 和 Manticore 將幫助您偵測與給定標準的偏差。 + +### 工具選擇快捷手冊 {#tool-selection-cheatsheet} + +| 元件 | 工具 | 範例 | +| ----- | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 狀態機 | Echidna、Manticore | | +| 存取控制 | Slither、Echidna、Manticore | [Slither 練習 2](https://github.com/crytic/slither/blob/7f54c8b948c34fb35e1d61adaa1bd568ca733253/docs/src/tutorials/exercise2.md)、[Echidna 練習 2](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/echidna/exercises/Exercise-2.md) | +| 算術運算 | Manticore、Echidna | [Echidna 練習 1](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/echidna/exercises/Exercise-1.md)、[Manticore 練習 1 - 3](https://github.com/crytic/building-secure-contracts/tree/master/program-analysis/manticore/exercises) | +| 繼承正確性 | Slither | [Slither 練習 1](https://github.com/crytic/slither/blob/7f54c8b948c34fb35e1d61adaa1bd568ca733253/docs/src/tutorials/exercise1.md) | +| 外部互動 | Manticore、Echidna | | +| 標準符合性 | Slither、Echidna、Manticore | [`slither-erc`](https://github.com/crytic/slither/wiki/ERC-Conformance) | + +根據您的目標,可能還需要檢查其他領域,但這些粗略的重點領域對於任何智能合約系統來說都是一個好的開始。 + +我們的公開審計報告中包含了經過驗證或測試的屬性範例。 請考慮閱讀以下報告的「自動化測試與驗證」部分,以審查真實世界的安全屬性: + +- [0x](https://github.com/trailofbits/publications/blob/master/reviews/0x-protocol.pdf) +- [Balancer](https://github.com/trailofbits/publications/blob/master/reviews/BalancerCore.pdf) diff --git a/public/content/translations/zh-tw/developers/tutorials/hello-world-smart-contract-fullstack/index.md b/public/content/translations/zh-tw/developers/tutorials/hello-world-smart-contract-fullstack/index.md new file mode 100644 index 00000000000..ea2cc5ceaa9 --- /dev/null +++ b/public/content/translations/zh-tw/developers/tutorials/hello-world-smart-contract-fullstack/index.md @@ -0,0 +1,1540 @@ +--- +title: "給初學者的 Hello World 智慧型合約 - 全端" +description: "在以太坊上撰寫和部署簡單智能合約的入門教學。" +author: "nstrike2" +tags: + [ + "Solidity", + "Hardhat", + "Alchemy", + "智能合約", + "部署", + "區塊瀏覽器", + "前端", + "交易" + ] +skill: beginner +lang: zh-tw +published: 2021-10-25 +--- + +如果您是區塊鏈開發新手,不知道從何開始,或不知道如何部署智慧型合約並與之互動,本指南就是為您準備的。 我們將逐步說明如何使用 [MetaMask](https://metamask.io)、[Solidity](https://docs.soliditylang.org/en/v0.8.0/)、[Hardhat](https://hardhat.org) 和 [Alchemy](https://alchemy.com/eth),在 Goerli 測試網上建立並部署一個簡單的智慧型合約。 + +您需要一個 Alchemy 帳戶才能完成本教學。 [註冊免費帳戶](https://www.alchemy.com/) + +如果您在任何時候有任何疑問,歡迎隨時到 [Alchemy Discord](https://discord.gg/gWuC7zB) 提問! + +## 第一部分 - 使用 Hardhat 建立與部署您的智慧型合約 {#part-1} + +### 連線至以太坊網路 {#connect-to-the-ethereum-network} + +向以太坊鏈發出請求有很多種方式。 為求簡單,我們將使用 Alchemy 上的免費帳戶。Alchemy 是一個區塊鏈開發者平台及 API,讓我們無須自行執行節點就能與以太坊鏈通訊。 Alchemy 也有用於監控和分析的開發者工具;我們將在本教學中利用這些工具來了解我們智慧型合約部署的底層運作情況。 + +### 建立您的應用程式和 API 金鑰 {#create-your-app-and-api-key} + +建立 Alchemy 帳戶後,您可以透過建立應用程式來產生 API 金鑰。 這將允許您向 Goerli 測試網發出請求。 如果您不熟悉測試網,可以閱讀 [Alchemy 選擇網路的指南](https://www.alchemy.com/docs/choosing-a-web3-network)。 + +在 Alchemy 儀表板上,於導覽列中找到 **Apps** 下拉式選單,然後點擊 **Create App**。 + +![Hello world 創建應用程式](./hello-world-create-app.png) + +將您的應用程式命名為「_Hello World_」,並寫下簡短描述。 選擇 **Staging** 作為您的環境,**Goerli** 作為您的網路。 + +![創建應用程式檢視 hello world](./create-app-view-hello-world.png) + +_注意:請務必選擇 **Goerli**,否則本教學將無法運作。_ + +點擊 **Create app**。 您的應用程式將出現在下方的表格中。 + +### 建立一個以太坊帳戶 {#create-an-ethereum-account} + +您需要一個以太坊帳戶來傳送和接收交易。 我們將使用 MetaMask,這是一款瀏覽器內的虛擬錢包,可讓使用者管理其以太坊帳戶地址。 + +您可以在[這裡](https://metamask.io/download)免費下載並建立 MetaMask 帳戶。 在建立帳戶時,或如果您已有帳戶,請確保切換到右上角的「Goerli 測試網」(這樣我們就不會處理真實貨幣)。 + +### 第 4 步:從水龍頭取得以太幣 {#step-4-add-ether-from-a-faucet} + +要將您的智慧型合約部署到測試網,您會需要一些假的 ETH。 要在 Goerli 網路上取得 ETH,請前往 Goerli 水龍頭,並輸入您的 Goerli 帳戶地址。 請注意,Goerli 水龍頭最近可能有點不穩定 - 請參閱[測試網頁面](/developers/docs/networks/#goerli),查看可嘗試的選項清單: + +_注意:由於網路壅塞,這可能需要一些時間。_ +`` + +### 步驟 5:檢查您的餘額 {#step-5-check-your-balance} + +為了再次確認 ETH 已在您的錢包中,讓我們使用 [Alchemy 的編寫工具](https://composer.alchemyapi.io/?composer_state=%7B%22network%22%3A0%2C%22methodName%22%3A%22eth_getBalance%22%2C%22paramValues%22%3A%5B%22%22%2C%22latest%22%5D%7D) 發出 [eth_getBalance](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc#eth_getbalance) 請求。 這將會回傳你的錢包裡的餘額。 要了解更多資訊,請查看 [Alchemy 關於如何使用編寫工具的簡短教學](https://youtu.be/r6sjRxBZJuU)。 + +輸入您的 MetaMask 帳戶地址,然後點擊 **Send Request**。 您將會看到類似下方程式碼片段的回應。 + +```json +{ "jsonrpc": "2.0", "id": 0, "result": "0x2B5E3AF16B1880000" } +``` + +> _注意:此結果以 wei 為單位,而非 ETH。_ Wei 是以太幣的最小單位。_ + +哈! 我們的假錢都在這。 + +### 步驟 6:初始化我們的專案 {#step-6-initialize-our-project} + +首先,我們需要為我們的專案建立一個資料夾。 導覽至您的命令列並輸入以下內容。 + +``` +mkdir hello-world +cd hello-world +``` + +現在我們在專案資料夾中了,我們將使用 `npm init` 來初始化專案。 + +> 如果您尚未安裝 npm,請遵循[這些說明來安裝 Node.js 和 npm](https://docs.alchemyapi.io/alchemy/guides/alchemy-for-macs#1-install-nodejs-and-npm)。 + +就本教學而言,您如何回答初始化問題並不重要。 以下是我們的做法,僅供參考: + +``` +套件名稱:(hello-world) +版本:(1.0.0) +描述:hello world 智慧型合約 +進入點:(index.js) +測試指令: +git 儲存庫: +關鍵字: +作者: +授權:(ISC) + +即將寫入 /Users/.../.../.../hello-world/package.json: + +{ + "name": "hello-world", + "version": "1.0.0", + "description": "hello world 智慧型合約", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC" +} +``` + +核准 package.json,我們就可以開始了! + +### 步驟 7:下載 Hardhat {#step-7-download-hardhat} + +Hardhat 是一個開發環境,提供你去編譯、部屬、測試、以及除錯你的以太坊軟體。 它能協助開發人員在部署至即時鏈之前,於本機建立智慧合約和去中心化應用程式。 + +在我們的 `hello-world` 專案中執行: + +``` +npm install --save-dev hardhat +``` + +如需更多[安裝指示](https://hardhat.org/getting-started/#overview)的詳細資訊,請查看此頁面。 + +### 步驟 8:建立 Hardhat 專案 {#step-8-create-hardhat-project} + +在我們的 `hello-world` 專案資料夾中,執行: + +``` +npx hardhat +``` + +你接下來會看到歡迎訊息以及關於你想做什麼的選項。 選擇"create an empty hardhat.config.js": + +``` +888 888 888 888 888 +888 888 888 888 888 +888 888 888 888 888 +8888888888 8888b. 888d888 .d88888 88888b. 8888b. 888888 +888 888 "88b 888P" d88" 888 888 "88b "88b 888 +888 888 .d888888 888 888 888 888 888 .d888888 888 +888 888 888 888 888 Y88b 888 888 888 888 888 Y88b. +888 888 "Y888888 888 "Y88888 888 888 "Y888888 "Y888 + +👷 歡迎使用 Hardhat v2.0.11 👷‍ + +您想做什麼?… +建立範例專案 +❯ 建立一個空的 hardhat.config.js +退出 +``` + +這將在專案中產生一個 `hardhat.config.js` 檔案。 我們稍後將在本教學中使用此檔案來指定專案的設定。 + +### 步驟 9:新增專案資料夾 {#step-9-add-project-folders} + +為了讓專案保持井然有序,我們來建立兩個新資料夾。 在命令列中,導覽至 `hello-world` 專案的根目錄並輸入: + +``` +mkdir contracts +mkdir scripts +``` + +- `contracts/` 是我們存放 hello world 智能合約程式碼檔案的地方 +- `scripts/` 是我們存放部署和與合約互動的腳本的地方 + +### 步驟 10:編寫我們的合約 {#step-10-write-our-contract} + +您可能會問自己,我們什麼時候才要開始寫程式碼? 就是現在! + +在您喜歡的編輯器中開啟 hello-world 專案。 智慧型合約最常用 Solidity 編寫,我們將使用它來編寫我們的智慧型合約。‌ + +1. 導覽至 `contracts` 資料夾並建立一個名為 `HelloWorld.sol` 的新檔案 +2. 以下是我們將在本教學中使用的範例 Hello World 智慧型合約。 將以下內容複製到 `HelloWorld.sol` 檔案中。 + +_注意:請務必閱讀註解以了解此合約的功能。_ + +``` +// 指定 Solidity 的版本,使用語意化版本控制。 +// 了解更多:https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma +pragma solidity >=0.7.3; + +// 定義一個名為「HelloWorld」的合約。 +// 合約是函式和資料 (其狀態) 的集合。部署後,合約會存放在以太坊區塊鏈的特定地址上。了解更多:https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html +contract HelloWorld { + + // 呼叫更新函式時發出 + // 智慧型合約事件是您合約的一種方式,可將區塊鏈上發生的事情傳達給您的應用程式前端,前端可以「監聽」某些事件並在事件發生時採取行動。 + event UpdatedMessages(string oldStr, string newStr); + + // 宣告一個「string」類型的狀態變數「message」。 + // 狀態變數是其值永久儲存在合約儲存空間中的變數。關鍵字「public」可讓變數從合約外部存取,並建立一個其他合約或用戶端可呼叫以存取該值的函式。 + string public message; + + // 與許多以類別為基礎的物件導向語言相似,建構函式是一個特殊函式,只在合約建立時執行。 + // 建構函式用於初始化合約的資料。了解更多:https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors + constructor(string memory initMessage) { + + // 接受一個字串引數「initMessage」,並將該值設定到合約的「message」儲存變數中)。 + message = initMessage; + } + + // 一個公共函式,接受一個字串引數並更新「message」儲存變數。 + function update(string memory newMessage) public { + string memory oldMsg = message; + message = newMessage; + emit UpdatedMessages(oldMsg, newMessage); + } +} +``` + +這是一個基本的智慧型合約,在建立時儲存一則訊息。 可以透過呼叫 `update` 函式來更新。 + +### 步驟 11:將 MetaMask 和 Alchemy 連線至您的專案 {#step-11-connect-metamask-alchemy-to-your-project} + +我們已經建立了 MetaMask 錢包、Alchemy 帳戶,並編寫了我們的智能合約,現在是時候將這三者連接起來了。 + +從您的錢包傳送的每筆交易都需要使用您唯一的私密金鑰簽署。 為了向我們的程式提供此權限,我們可以安全地將我們的私密金鑰儲存在環境檔案中。 我們也將在此處儲存 Alchemy 的 API 金鑰。 + +> 若要深入了解如何傳送交易,請查看這篇關於使用 web3 傳送交易的[教學](https://www.alchemy.com/docs/hello-world-smart-contract#step-11-connect-metamask--alchemy-to-your-project)。 + +首先,安裝 dotenv 套件。 + +``` +npm install dotenv --save +``` + +然後,在專案的根目錄中建立一個 `.env` 檔案。 將您的 MetaMask 私密金鑰和 HTTP Alchemy API URL 新增至其中。 + +您的環境檔案必須命名為 `.env`,否則它將不會被辨識為環境檔案。 + +請勿將其命名為 `process.env`、`.env-custom` 或任何其他名稱。 + +- 請遵循[這些說明](https://metamask.zendesk.com/hc/en-us/articles/360015289632-How-to-Export-an-Account-Private-Key)來匯出您的私密金鑰 +- 請參閱下文以取得 HTTP Alchemy API URL + +![](./get-alchemy-api-key.gif) + +你的 `.env` 應該看起來像這樣: + +``` +API_URL = "https://eth-goerli.alchemyapi.io/v2/your-api-key" +PRIVATE_KEY = "your-metamask-private-key" +``` + +為了實際將這些連接到我們的程式碼,我們將在第 13 步的 `hardhat.config.js` 檔案中引用這些變數。 + +### 第 12 步:安裝 Ethers.js {#step-12-install-ethersjs} + +Ethers.js 是一個函式庫,它透過將[標準 JSON-RPC 方法](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc)包裝成更方便使用者使用的方法,讓與以太坊的互動和請求變得更容易。 + +Hardhat 可讓您整合[外掛程式](https://hardhat.org/plugins/)以取得額外的工具和擴充功能。 我們將利用 [Ethers 外掛程式](https://hardhat.org/docs/plugins/official-plugins#hardhat-ethers)來部署合約。 + +在你的專案目錄輸入: + +```bash +npm install --save-dev @nomiclabs/hardhat-ethers "ethers@^5.0.0" +``` + +### 步驟 13:更新 hardhat.config.js {#step-13-update-hardhat-configjs} + +我們目前已經新增了幾個相依套件和外掛程式,現在我們需要更新 `hardhat.config.js`,讓我們的專案知道它們全部。 + +將你的 `hardhat.config.js` 更新成如下所示: + +```javascript +/** + * @type import('hardhat/config').HardhatUserConfig + */ + +require("dotenv").config() +require("@nomiclabs/hardhat-ethers") + +const { API_URL, PRIVATE_KEY } = process.env + +module.exports = { + solidity: "0.7.3", + defaultNetwork: "goerli", + networks: { + hardhat: {}, + goerli: { + url: API_URL, + accounts: [`0x${PRIVATE_KEY}`], + }, + }, +} +``` + +### 步驟 14:編譯我們的合約 {#step-14-compile-our-contract} + +為了確認一切運作正常,我們來編譯合約。 `compile` 任務是內建的 hardhat 任務之一。 + +在命令列工具輸入: + +```bash +npx hardhat compile +``` + +您可能會收到關於「原始程式檔中未提供 SPDX 授權識別碼」的警告,但無須擔心,希望其他一切都沒問題! 如果沒有,您隨時可以在 [Alchemy discord](https://discord.gg/u72VCg3) 中傳送訊息。 + +### 步驟 15:編寫我們的部署指令碼 {#step-15-write-our-deploy-script} + +現在我們已經寫好了合約,並且也搞定配置檔案。現在我們該來撰寫部署合約的腳本。 + +導覽至 `scripts/` 資料夾並建立一個名為 `deploy.js` 的新檔案,將以下內容加入其中: + +```javascript +async function main() { + const HelloWorld = await ethers.getContractFactory("HelloWorld") + + // 開始部署,回傳一個解析為合約物件的 promise + const hello_world = await HelloWorld.deploy("Hello World!") + console.log("合約已部署至地址:", hello_world.address) +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error) + process.exit(1) + }) +``` + +Hardhat 在其[合約教學文章](https://hardhat.org/tutorial/testing-contracts.html#writing-tests)中詳細地解釋了每一行程式碼的作用,我們在此採用了他們的解釋。 + +```javascript +const HelloWorld = await ethers.getContractFactory("HelloWorld") +``` + +ethers.js 中的 `ContractFactory` 是用於部署新智慧型合約的抽象概念,因此這裡的 `HelloWorld` 是我們 hello world 合約執行個體的[工廠](https://en.wikipedia.org/wiki/Factory_\(object-oriented_programming\))。 使用 `hardhat-ethers` 外掛程式時,`ContractFactory` 和 `Contract` 執行個體預設會連線至第一個簽署者 (擁有者)。 + +```javascript +const hello_world = await HelloWorld.deploy() +``` + +在 `ContractFactory` 上呼叫 `deploy()` 將會開始部署,並回傳一個解析為 `Contract` 物件的 `Promise`。 這就是和我們的智慧型合約函數有一對一的方法的物件。 + +### 第 16 步:部署我們的合約 {#step-16-deploy-our-contract} + +我們終於準備好要部署合約了! 導覽至命令列並執行: + +```bash +npx hardhat run scripts/deploy.js --network goerli +``` + +你會看到像這樣的輸出: + +```bash +合約已部署至地址:0x6cd7d44516a20882cEa2DE9f205bF401c0d23570 +``` + +**請儲存此地址**。 我們稍後將在本教學中使用它。 + +如果我們前往 [Goerli etherscan](https://goerli.etherscan.io) 並搜尋我們的合約地址,我們應該能夠看到它已成功部署。 這個交易執行看起來會像這樣: + +![](./etherscan-contract.png) + +`From` 地址應與您的 MetaMask 帳戶地址相符,而 `To` 地址將顯示 **Contract Creation**。 如果我們點擊進入交易,我們將在 `To` 欄位中看到我們的合約地址。 + +![](./etherscan-transaction.png) + +恭喜! 您剛剛將智慧型合約部署到以太坊測試網。 + +若要了解底層的運作情況,讓我們導覽至 [Alchemy 儀表板](https://dashboard.alchemy.com/explorer)中的 Explorer 標籤。 如果您有多個 Alchemy 應用程式,請務必依應用程式篩選並選取 **Hello World**。 + +![](./hello-world-explorer.png) + +在這裡您會看到當我們呼叫 `.deploy()` 函式時,Hardhat/Ethers 在幕後為我們進行的一些 JSON-RPC 方法。 這裡有兩個重要的方法:[`eth_sendRawTransaction`](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc#eth_sendrawtransaction) (這是將我們的合約寫入 Goerli 鏈的請求),以及 [`eth_getTransactionByHash`](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc#eth_gettransactionbyhash) (這是在給定哈希值的情況下,讀取我們交易資訊的請求)。 若要深入了解如何傳送交易,請查看[我們關於使用 Web3 傳送交易的教學](/developers/tutorials/sending-transactions-using-web3-and-alchemy/)。 + +## 第二部分:與您的智慧型合約互動 {#part-2-interact-with-your-smart-contract} + +既然我們已成功將智慧型合約部署至 Goerli 網路,讓我們來學習如何與它互動。 + +### 建立一個 interact.js 檔案 {#create-a-interactjs-file} + +這就是我們將編寫互動腳本的檔案。 我們將使用您先前在第一部分中安裝的 Ethers.js 函式庫。 + +在 `scripts/` 資料夾中,建立一個名為 `interact.js` 的新檔案,並新增以下程式碼: + +```javascript +// interact.js + +const API_KEY = process.env.API_KEY +const PRIVATE_KEY = process.env.PRIVATE_KEY +const CONTRACT_ADDRESS = process.env.CONTRACT_ADDRESS +``` + +### 更新您的 .env 檔案 {#update-your-env-file} + +我們將使用新的環境變數,因此我們需要在[先前建立](#step-11-connect-metamask-&-alchemy-to-your-project) 的 `.env` 檔案中定義它們。 + +我們需要新增我們的 Alchemy `API_KEY` 和部署智慧型合約的 `CONTRACT_ADDRESS` 的定義。 + +您的 `.env` 檔案應如下所示: + +```bash +# .env + +API_URL = "https://eth-goerli.alchemyapi.io/v2/" +API_KEY = "" +PRIVATE_KEY = "" +CONTRACT_ADDRESS = "0x" +``` + +### 取得您的合約 ABI {#grab-your-contract-ABI} + +我們的合約 [ABI (應用程式二進位介面)](/glossary/#abi) 是與我們的智慧型合約互動的介面。 Hardhat 會自動產生 ABI 並將其儲存在 `HelloWorld.json` 中。 若要使用 ABI,我們需要透過將以下程式碼行新增至我們的 `interact.js` 檔案來解析內容: + +```javascript +// interact.js +const contract = require("../artifacts/contracts/HelloWorld.sol/HelloWorld.json") +``` + +如果您想查看 ABI,可以將其輸出到您的主控台: + +```javascript +console.log(JSON.stringify(contract.abi)) +``` + +若要查看您的 ABI 列印至主控台,請導覽至您的終端機並執行: + +```bash +npx hardhat run scripts/interact.js +``` + +### 建立您的合約執行個體 {#create-an-instance-of-your-contract} + +若要與我們的合約互動,我們需要在我們的程式碼中建立一個合約執行個體。 若要使用 Ethers.js 執行此操作,我們需要處理三個概念: + +1. 提供者 - 一個節點提供者,提供您對區塊鏈的讀寫存取權 +2. 簽署者 - 代表一個可以簽署交易的以太坊帳戶 +3. 合約 - 代表部署在鏈上特定合約的 Ethers.js 物件 + +我們將使用上一步的合約 ABI 來建立我們的合約執行個體: + +```javascript +// interact.js + +// Provider +const alchemyProvider = new ethers.providers.AlchemyProvider( + (network = "goerli"), + API_KEY +) + +// Signer +const signer = new ethers.Wallet(PRIVATE_KEY, alchemyProvider) + +// Contract +const helloWorldContract = new ethers.Contract( + CONTRACT_ADDRESS, + contract.abi, + signer +) +``` + +在 [ethers.js 文件](https://docs.ethers.io/v5/) 中深入了解提供者、簽署者和合約。 + +### 讀取初始訊息 {#read-the-init-message} + +還記得我們在部署合約時設定了 `initMessage = "Hello world!"` 嗎? 我們現在要讀取儲存在我們智慧型合約中的那則訊息,並將它列印到主控台。 + +在 JavaScript 中,與網路互動時會使用非同步函式。 要深入了解非同步函式,請[閱讀這篇 Medium 文章](https://blog.bitsrc.io/understanding-asynchronous-javascript-the-event-loop-74cd408419ff)。 + +使用以下程式碼呼叫我們智慧型合約中的 `message` 函式並讀取初始訊息: + +```javascript +// interact.js + +// ... + +async function main() { + const message = await helloWorldContract.message() + console.log("訊息是:" + message) +} +main() +``` + +在終端機中使用 `npx hardhat run scripts/interact.js` 執行檔案後,我們應該會看到以下回應: + +``` +訊息是:Hello world! +``` + +恭喜! 您剛剛成功地從以太坊區塊鏈讀取智慧型合約資料,太棒了! + +### 更新訊息 {#update-the-message} + +除了只讀取訊息,我們還可以使用 `update` 函式來更新儲存在我們智慧型合約中的訊息! 很酷,對吧? + +若要更新訊息,我們可以直接在我們實例化的合約物件上呼叫 `update` 函式: + +```javascript +// interact.js + +// ... + +async function main() { + const message = await helloWorldContract.message() + console.log("訊息是:" + message) + + console.log("正在更新訊息...") + const tx = await helloWorldContract.update("這是新訊息。") + await tx.wait() +} +main() +``` + +請注意,在第 11 行,我們在回傳的交易物件上呼叫了 `.wait()`。 這可確保我們的腳本在結束函式前,會等待交易在區塊鏈上被挖出。 如果未包含 `.wait()` 呼叫,腳本可能無法看到合約中更新的 `message` 值。 + +### 讀取新訊息 {#read-the-new-message} + +您應該能夠重複[上一步](#read-the-init-message)來讀取更新的 `message` 值。 花點時間看看您是否能做出必要的變更來列印出那個新值! + +如果您需要提示,以下是您此時的 `interact.js` 檔案應有的樣子: + +```javascript +// interact.js + +const API_KEY = process.env.API_KEY +const PRIVATE_KEY = process.env.PRIVATE_KEY +const CONTRACT_ADDRESS = process.env.CONTRACT_ADDRESS + +const contract = require("../artifacts/contracts/HelloWorld.sol/HelloWorld.json") + +// 提供者 - Alchemy +const alchemyProvider = new ethers.providers.AlchemyProvider( + (network = "goerli"), + API_KEY +) + +// 簽署者 - 您 +const signer = new ethers.Wallet(PRIVATE_KEY, alchemyProvider) + +// 合約執行個體 +const helloWorldContract = new ethers.Contract( + CONTRACT_ADDRESS, + contract.abi, + signer +) + +async function main() { + const message = await helloWorldContract.message() + console.log("訊息是:" + message) + + console.log("正在更新訊息...") + const tx = await helloWorldContract.update("這是新訊息") + await tx.wait() + + const newMessage = await helloWorldContract.message() + console.log("新訊息是:" + newMessage) +} + +main() +``` + +現在只要執行腳本,您就應該能看到舊訊息、更新狀態,以及新訊息列印到您的終端機上! + +`npx hardhat run scripts/interact.js --network goerli` + +``` +訊息是:Hello World! +正在更新訊息... +新訊息是:這是新訊息。 +``` + +執行該腳本時,您可能會注意到「正在更新訊息...」步驟在新訊息載入前需要一些時間。 這是由於挖礦過程所致;如果您好奇在挖礦時追蹤交易,請造訪 [Alchemy 記憶體池](https://dashboard.alchemyapi.io/mempool)來查看交易狀態。 如果交易被丟棄,檢查 [Goerli Etherscan](https://goerli.etherscan.io) 並搜尋您的交易哈希也很有幫助。 + +## 第三部分:將您的智慧型合約發布至 Etherscan {#part-3-publish-your-smart-contract-to-etherscan} + +您已費盡心力讓您的智慧型合約活起來;現在是時候與全世界分享它了! + +透過在 Etherscan 上驗證您的智慧型合約,任何人都可以檢視您的原始碼並與您的智慧型合約互動。 我們開始吧! + +### 步驟 1:在您的 Etherscan 帳戶上產生 API 金鑰 {#step-1-generate-an-api-key-on-your-etherscan-account} + +需要 Etherscan API 金鑰來驗證您擁有您嘗試發布的智慧型合約。 + +如果您還沒有 Etherscan 帳戶,請[註冊一個帳戶](https://etherscan.io/register)。 + +登入後,在導覽列中找到您的使用者名稱,將滑鼠懸停在其上並選取 **My profile** 按鈕。 + +在您的個人資料頁面上,您應該會看到一個側邊導覽列。 從側邊導覽列中,選取 **API Keys**。 接下來,按下「新增」按鈕以建立新的 API 金鑰,將您的應用程式命名為 **hello-world** 並按下 **Create New API Key** 按鈕。 + +您的新 API 金鑰應會出現在 API 金鑰表格中。 將 API 金鑰複製到您的剪貼簿。 + +接下來,我們需要將 Etherscan API 金鑰新增至我們的 `.env` 檔案。 + +新增後,您的 `.env` 檔案應如下所示: + +```javascript +API_URL = "https://eth-goerli.alchemyapi.io/v2/your-api-key" +PUBLIC_KEY = "your-public-account-address" +PRIVATE_KEY = "your-private-account-address" +CONTRACT_ADDRESS = "your-contract-address" +ETHERSCAN_API_KEY = "your-etherscan-key" +``` + +### Hardhat 部署的智慧型合約 {#hardhat-deployed-smart-contracts} + +#### 安裝 hardhat-etherscan {#install-hardhat-etherscan} + +使用 Hardhat 將您的合約發布至 Etherscan 非常簡單。 您首先需要安裝 `hardhat-etherscan` 外掛程式才能開始。 `hardhat-etherscan` 會自動在 Etherscan 上驗證智慧型合約的原始碼和 ABI。 若要新增此項,請在 `hello-world` 目錄中執行: + +```text +npm install --save-dev @nomiclabs/hardhat-etherscan +``` + +安裝後,在您的 `hardhat.config.js` 頂端包含以下陳述式,並新增 Etherscan 設定選項: + +```javascript +// hardhat.config.js + +require("dotenv").config() +require("@nomiclabs/hardhat-ethers") +require("@nomiclabs/hardhat-etherscan") + +const { API_URL, PRIVATE_KEY, ETHERSCAN_API_KEY } = process.env + +module.exports = { + solidity: "0.7.3", + defaultNetwork: "goerli", + networks: { + hardhat: {}, + goerli: { + url: API_URL, + accounts: [`0x${PRIVATE_KEY}`], + }, + }, + etherscan: { + // Your API key for Etherscan + // 在 https://etherscan.io/ 取得一個 + apiKey: ETHERSCAN_API_KEY, + }, +} +``` + +#### 在 Etherscan 上驗證您的智慧型合約 {#verify-your-smart-contract-on-etherscan} + +確保所有檔案都已儲存,且所有 `.env` 變數都已正確設定。 + +執行 `verify` 任務,傳遞合約地址以及部署到的網路: + +```text +npx hardhat verify --network goerli DEPLOYED_CONTRACT_ADDRESS 'Hello World!' +``` + +請確定 `DEPLOYED_CONTRACT_ADDRESS` 是您在 Goerli 測試網上部署的智慧型合約的地址。 此外,最後一個引數 (`'Hello World!'`) 必須與[第一部分中的部署步驟](#write-our-deploy-script)中所使用的字串值相同。 + +如果一切順利,您將在終端機中看到以下訊息: + +```text +Successfully submitted source code for contract +contracts/HelloWorld.sol:HelloWorld at 0xdeployed-contract-address +for verification on Etherscan. Waiting for verification result... + + +Successfully verified contract HelloWorld on Etherscan. +https://goerli.etherscan.io/address/#contracts +``` + +恭喜! 您的智慧型合約程式碼已在 Etherscan 上! + +### 在 Etherscan 上查看您的智慧型合約! {#check-out-your-smart-contract-on-etherscan} + +當您導覽至終端機中提供的連結時,您應該能夠看到您在 Etherscan 上發布的智慧型合約程式碼和 ABI! + +**哇嗚 - 你做到了,冠軍! 現在任何人都可以呼叫或寫入您的智慧型合約! 我們迫不及待想看看您接下來會打造出什麼!** + +## 第四部分 - 將您的智慧型合約與前端整合 {#part-4-integrating-your-smart-contract-with-the-frontend} + +完成本教學後,您將知道如何: + +- 將 MetaMask 錢包連線至您的去中心化應用程式 +- 使用 [Alchemy Web3](https://docs.alchemy.com/alchemy/documentation/alchemy-web3) API 從您的智慧型合約讀取資料 +- 使用 MetaMask 簽署以太坊交易 + +對於這個去中心化應用程式,我們將使用 [React](https://react.dev/) 作為我們的前端框架;然而,需要注意的是,我們不會花太多時間分解其基礎知識,因為我們將主要專注於為我們的專案帶來 Web3 功能。 + +作為先決條件,您應該對 React 有初學者級的了解。 如果沒有,我們建議完成官方的[React 入門教學](https://react.dev/learn)。 + +### 複製入門檔案 {#clone-the-starter-files} + +首先,前往 [hello-world-part-four GitHub 儲存庫](https://github.com/alchemyplatform/hello-world-part-four-tutorial) 以取得此專案的入門檔案,並將此儲存庫複製到您的本機電腦。 + +在本機開啟複製的儲存庫。 請注意,它包含兩個資料夾:`starter-files` 和 `completed`。 + +- `starter-files` - **我們將在此目錄中工作**,我們將把 UI 連線至您的以太坊錢包和我們在[第三部分](#part-3)中發布到 Etherscan 的智慧型合約。 +- `completed` 包含整個已完成的教學,如果您遇到困難,應僅用作參考。 + +接下來,在您最喜歡的程式碼編輯器中開啟您的 `starter-files` 副本,然後導覽至 `src` 資料夾。 + +我們將撰寫的所有程式碼都會放在 `src` 資料夾底下。 我們將編輯 `HelloWorld.js` 元件和 `util/interact.js` JavaScript 檔案,為我們的專案提供 Web3 功能。 + +### 查看入門檔案 {#check-out-the-starter-files} + +在我們開始編寫程式碼之前,讓我們來探索一下入門檔案中提供了什麼。 + +#### 讓你的 React 專案動起來 {#get-your-react-project-running} + +讓我們透過在我們的瀏覽器內運行這個 React 專案來開始是日的教程吧: React 的美在於一旦我們在瀏覽器內已經有在運行自己的專案,我們儲存下來的任何改變都將會被實時更新到我們的瀏覽器裡。 + +若要讓專案執行,請導覽至 `starter-files` 資料夾的根目錄,然後在您的終端機中執行 `npm install` 以安裝專案的相依性: + +```bash +cd starter-files +npm install +``` + +安裝完成後,在你的終端機中執行 `npm start`: + +```bash +npm start +``` + +這麼做應該會在您的瀏覽器中開啟 [http://localhost:3000/](http://localhost:3000/),您將在那裡看到我們專案的前端。 它應該包含一個欄位 (一個更新儲存在您智慧型合約中訊息的地方)、一個「連線錢包」按鈕,和一個「更新」按鈕。 + +如果您嘗試點擊任一按鈕,您會發現它們無法運作——那是因為我們還需要編寫它們的功能。 + +#### `HelloWorld.js` 元件 {#the-helloworld-js-component} + +讓我們回到編輯器中的 `src` 資料夾,並開啟 `HelloWorld.js` 檔案。 這個動作在我們理解該檔案內所有東西上有著超級關鍵的作用,因為它是我們將會首先處理的第一個 React 組件。 + +在此檔案的頂端,您會注意到我們有幾個執行專案所必需的匯入陳述式,包括 React 函式庫、useEffect 和 useState hook、來自 `./util/interact.js` 的一些項目 (我們稍後將更詳細地描述它們!),以及 Alchemy 標誌。 + +```javascript +// HelloWorld.js + +import React from "react" +import { useEffect, useState } from "react" +import { + helloWorldContract, + connectWallet, + updateMessage, + loadCurrentMessage, + getCurrentWalletConnected, +} from "./util/interact.js" + +import alchemylogo from "./alchemylogo.svg" +``` + +接下來,我們有我們的狀態變數,我們將在特定事件後更新它們。 + +```javascript +// HelloWorld.js + +//狀態變數 +const [walletAddress, setWallet] = useState("") +const [status, setStatus] = useState("") +const [message, setMessage] = useState("未連線至網路。") +const [newMessage, setNewMessage] = useState("") +``` + +以下是每個變數所代表的意義: + +- `walletAddress` - 一個儲存使用者錢包位址的字串 +- `status` - 一個儲存有用訊息的字串,引導使用者如何與去中心化應用程式互動 +- `message` - 一個儲存智慧型合約中目前訊息的字串 +- `newMessage` - 一個儲存將寫入智慧型合約的新訊息的字串 + +在狀態變數之後,您會看到五個未實作的函式:`useEffect`、`addSmartContractListener`、`addWalletListener`、`connectWalletPressed` 和 `onUpdatePressed`。 我們將在下方解釋它們的功能: + +```javascript +// HelloWorld.js + +//僅呼叫一次 +useEffect(async () => { + //TODO: 實作 +}, []) + +function addSmartContractListener() { + //TODO: 實作 +} + +function addWalletListener() { + //TODO: 實作 +} + +const connectWalletPressed = async () => { + //TODO: 實作 +} + +const onUpdatePressed = async () => { + //TODO: 實作 +} +``` + +- [`useEffect`](https://legacy.reactjs.org/docs/hooks-effect.html) - 這是一個 React hook,在您的元件渲染後呼叫。 因為它傳入了一個空陣列 `[]` prop (見第 4 行),所以它只會在元件的_第一次_渲染時被呼叫。 在這裡,我們將載入儲存在我們智慧型合約中的目前訊息,呼叫我們的智慧型合約和錢包監聽器,並更新我們的 UI 以反映錢包是否已連線。 +- `addSmartContractListener` - 此函式設定一個監聽器,它將監看我們的 HelloWorld 合約的 `UpdatedMessages` 事件,並在我們智慧型合約中的訊息變更時更新我們的 UI。 +- `addWalletListener` - 此函式設定一個監聽器,偵測使用者 MetaMask 錢包狀態的變更,例如使用者中斷錢包連線或切換地址時。 +- `connectWalletPressed` - 此函式將被呼叫以將使用者的 MetaMask 錢包連線至我們的去中心化應用程式。 +- `onUpdatePressed` - 當使用者想要更新儲存在智慧型合約中的訊息時,將會呼叫此函式。 + +接近這份檔案的尾聲,我們得到了我們組件的UI。 + +```javascript +// HelloWorld.js + +//我們元件的 UI +return ( +
+ + + +

目前訊息:

+

{message}

+ +

新訊息:

+ +
+ setNewMessage(e.target.value)} + value={newMessage} + /> +

{status}

+ + +
+ +
+) +``` + +如果您仔細掃描此程式碼,您會注意到我們在 UI 中使用了各種狀態變數: + +- 在第 6-12 行,如果使用者的錢包已連線 (即 `walletAddress.length > 0`),我們會在 ID 為「walletButton」的按鈕中顯示使用者 `walletAddress` 的截斷版本;否則它只會顯示「連線錢包」。 +- 在第 17 行,我們顯示儲存在智慧型合約中的目前訊息,該訊息擷取在 `message` 字串中。 +- 在第 23-26 行,我們使用[受控元件](https://legacy.reactjs.org/docs/forms.html#controlled-components)來更新我們的 `newMessage` 狀態變數,當文字欄位中的輸入變更時。 + +除了我們的狀態變數,您還會看到 `connectWalletPressed` 和 `onUpdatePressed` 函式分別在點擊 ID 為 `publishButton` 和 `walletButton` 的按鈕時被呼叫。 + +最後,讓我們來處理這個 `HelloWorld.js` 元件被新增到哪裡的問題。 + +如果您前往 `App.js` 檔案,這是 React 中的主要元件,作為所有其他元件的容器,您會看到我們的 `HelloWorld.js` 元件被注入在第 7 行。 + +最後但同樣重要的是,讓我們查看為您提供的另一個檔案,即 `interact.js` 檔案。 + +#### `interact.js` 檔案 {#the-interact-js-file} + +因為我們想要遵循 [M-V-C](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) 範式,我們將需要一個單獨的檔案,其中包含我們所有的函式來管理我們去中心化應用程式的邏輯、資料和規則,然後能夠將這些函式匯出到我們的前端 (我們的 `HelloWorld.js` 元件)。 + +👆🏽這正是我們的 `interact.js` 檔案的目的! + +導覽至您 `src` 目錄中的 `util` 資料夾,您會注意到我們包含了一個名為 `interact.js` 的檔案,它將包含我們所有的智慧型合約互動和錢包函式與變數。 + +```javascript +// interact.js + +//export const helloWorldContract; + +export const loadCurrentMessage = async () => {} + +export const connectWallet = async () => {} + +const getCurrentWalletConnected = async () => {} + +export const updateMessage = async (message) => {} +``` + +您會注意到檔案頂端,我們已註解掉 `helloWorldContract` 物件。 稍後在本教學中,我們將取消註解此物件,並在此變數中實例化我們的智慧型合約,然後我們將其匯出至我們的 `HelloWorld.js` 元件。 + +我們 `helloWorldContract` 物件之後的四個未實作函式執行以下操作: + +- `loadCurrentMessage` - 此函式處理載入儲存在智慧型合約中目前訊息的邏輯。 它將使用 [Alchemy Web3 API](https://github.com/alchemyplatform/alchemy-web3) 對 Hello World 智慧型合約進行_讀取_呼叫。 +- `connectWallet` - 此函式將把使用者的 MetaMask 連線至我們的去中心化應用程式。 +- `getCurrentWalletConnected` - 此函式將在頁面載入時檢查以太坊帳戶是否已連線至我們的去中心化應用程式,並相應地更新我們的 UI。 +- `updateMessage` - 此函式將更新儲存在智慧型合約中的訊息。 它將對 Hello World 智慧型合約進行_寫入_呼叫,因此使用者的 MetaMask 錢包必須簽署一筆以太坊交易才能更新訊息。 + +既然我們了解了我們正在處理的內容,讓我們來弄清楚如何從我們的智慧型合約中讀取! + +### 步驟 3:從您的智慧型合約讀取 {#step-3-read-from-your-smart-contract} + +若要從您的智慧型合約讀取,您需要成功設定: + +- 與以太坊鏈的 API 連線 +- 您智慧型合約的載入執行個體 +- 呼叫您智慧型合約函式的函式 +- 一個監聽器,用於在您從智慧型合約讀取的資料變更時監看更新 + +這聽起來可能有很多步驟,但別擔心! 我們將一步一步引導您完成它們! :\) + +#### 建立與以太坊鏈的 API 連線 {#establish-an-api-connection-to-the-ethereum-chain} + +還記得在本教學的第二部分中,我們如何使用我們的 [Alchemy Web3 金鑰從我們的智慧型合約讀取](https://docs.alchemy.com/alchemy/tutorials/hello-world-smart-contract/interacting-with-a-smart-contract#step-1-install-web3-library)嗎? 您還需要在您的去中心化應用程式中使用 Alchemy Web3 金鑰才能從鏈上讀取。 + +如果您還沒有,首先安裝 [Alchemy Web3](https://github.com/alchemyplatform/alchemy-web3),方法是導覽至您 `starter-files` 的根目錄,並在您的終端機中執行以下指令: + +```text +npm install @alch/alchemy-web3 +``` + +[Alchemy Web3](https://github.com/alchemyplatform/alchemy-web3) 是 [Web3.js](https://docs.web3js.org/) 的一個包裝器,提供了增強的 API 方法和其他關鍵優勢,讓你的 web3 開發者生活更輕鬆。 它是被設計成最低配置,因此你能夠在你的應用程式內馬上開始使用它! + +然後,在您的專案目錄中安裝 [dotenv](https://www.npmjs.com/package/dotenv) 套件,這樣我們在取得 API 金鑰後就有一個安全的地方來儲存它。 + +```text +npm install dotenv --save +``` + +對於我們的去中心化應用程式,**我們將使用我們的 Websockets API 金鑰** 而非我們的 HTTP API 金鑰,因為它將允許我們設定一個監聽器,偵測儲存在智慧型合約中的訊息何時變更。 + +取得您的 API 金鑰後,在您的根目錄中建立一個 `.env` 檔案,並將您的 Alchemy Websockets url 新增至其中。 之後,您的 `.env` 檔案應如下所示: + +```javascript +REACT_APP_ALCHEMY_KEY = wss://eth-goerli.ws.alchemyapi.io/v2/ +``` + +現在,我們已準備好在我們的去中心化應用程式中設定我們的 Alchemy Web3 端點! 讓我們回到我們的 `interact.js`,它巢狀在我們的 `util` 資料夾中,並在檔案頂端新增以下程式碼: + +```javascript +// interact.js + +require("dotenv").config() +const alchemyKey = process.env.REACT_APP_ALCHEMY_KEY +const { createAlchemyWeb3 } = require("@alch/alchemy-web3") +const web3 = createAlchemyWeb3(alchemyKey) + +//export const helloWorldContract; +``` + +在上方,我們首先從我們的 `.env` 檔案匯入 Alchemy 金鑰,然後將我們的 `alchemyKey` 傳遞給 `createAlchemyWeb3` 以建立我們的 Alchemy Web3 端點。 + +有了這個端點,是時候載入我們的智慧型合約了! + +#### 載入您的 Hello World 智慧型合約 {#loading-your-hello-world-smart-contract} + +要載入您的 Hello World 智慧型合約,您需要其合約地址和 ABI,如果您完成了[本教學的第三部分](/developers/tutorials/hello-world-smart-contract-fullstack/#part-3-publish-your-smart-contract-to-etherscan-part-3-publish-your-smart-contract-to-etherscan),兩者都可以在 Etherscan 上找到。 + +#### 如何從 Etherscan 取得您的合約 ABI {#how-to-get-your-contract-abi-from-etherscan} + +如果您跳過了本教學的第三部分,您可以使用地址為 [0x6f3f635A9762B47954229Ea479b4541eAF402A6A](https://goerli.etherscan.io/address/0x6f3f635a9762b47954229ea479b4541eaf402a6a#code) 的 HelloWorld 合約。 其 ABI 可以在[這裡](https://goerli.etherscan.io/address/0x6f3f635a9762b47954229ea479b4541eaf402a6a#code)找到。 + +合約 ABI 對於指定合約將調用哪個函式以及確保函式將以您期望的格式回傳資料是必要的。 複製我們的合約 ABI 後,讓我們將其另存為一個名為 `contract-abi.json` 的 JSON 檔案,儲存在您的 `src` 目錄中。 + +您的 contract-abi.json 應儲存在您的 src 資料夾中。 + +有了我們的合約地址、ABI 和 Alchemy Web3 端點,我們可以使用 [contract 方法](https://docs.web3js.org/api/web3-eth-contract/class/Contract)來載入我們智慧型合約的執行個體。 將您的合約 ABI 匯入 `interact.js` 檔案並新增您的合約地址。 + +```javascript +// interact.js + +const contractABI = require("../contract-abi.json") +const contractAddress = "0x6f3f635A9762B47954229Ea479b4541eAF402A6A" +``` + +我們現在終於可以取消註解我們的 `helloWorldContract` 變數,並使用我們的 AlchemyWeb3 端點載入智慧型合約: + +```javascript +// interact.js +export const helloWorldContract = new web3.eth.Contract( + contractABI, + contractAddress +) +``` + +總結一下,您 `interact.js` 的前 12 行現在應該如下所示: + +```javascript +// interact.js + +require("dotenv").config() +const alchemyKey = process.env.REACT_APP_ALCHEMY_KEY +const { createAlchemyWeb3 } = require("@alch/alchemy-web3") +const web3 = createAlchemyWeb3(alchemyKey) + +const contractABI = require("../contract-abi.json") +const contractAddress = "0x6f3f635A9762B47954229Ea479b4541eAF402A6A" + +export const helloWorldContract = new web3.eth.Contract( + contractABI, + contractAddress +) +``` + +既然我們已載入合約,我們就可以實作我們的 `loadCurrentMessage` 函式了! + +#### 在您的 `interact.js` 檔案中實作 `loadCurrentMessage` {#implementing-loadCurrentMessage-in-your-interact-js-file} + +這個函式非常簡單。 我們將進行一個簡單的非同步 web3 呼叫來從我們的合約中讀取。 我們的函式將回傳儲存在智慧型合約中的訊息: + +將您 `interact.js` 檔案中的 `loadCurrentMessage` 更新為以下內容: + +```javascript +// interact.js + +export const loadCurrentMessage = async () => { + const message = await helloWorldContract.methods.message().call() + return message +} +``` + +由於我們希望在我們的 UI 中顯示此智慧型合約,讓我們將 `HelloWorld.js` 元件中的 `useEffect` 函式更新為以下內容: + +```javascript +// HelloWorld.js + +//僅呼叫一次 +useEffect(async () => { + const message = await loadCurrentMessage() + setMessage(message) +}, []) +``` + +請注意,我們只希望在元件第一次渲染時呼叫一次 `loadCurrentMessage`。 我們很快就會實作 `addSmartContractListener`,以便在智慧型合約中的訊息變更後自動更新 UI。 + +在我們深入研究我們的監聽器之前,讓我們來看看我們目前為止的成果! 儲存您的 `HelloWorld.js` 和 `interact.js` 檔案,然後前往 [http://localhost:3000/](http://localhost:3000/) + +您會注意到目前訊息不再顯示「未連線至網路」。 而是反映儲存在智慧型合約中的訊息。 太棒了! + +#### 您的 UI 現在應該反映儲存在智慧型合約中的訊息 {#your-UI-should-now-reflect-the-message-stored-in-the-smart-contract} + +現在說到那個監聽器... + +#### 實作 `addSmartContractListener` {#implement-addsmartcontractlistener} + +如果您回想一下我們在本教學系列[第一部分](https://docs.alchemy.com/alchemy/tutorials/hello-world-smart-contract#step-10-write-our-contract)中編寫的 `HelloWorld.sol` 檔案,您會記得在我們的智慧型合約的 `update` 函式被調用後 (見第 9 和 27 行),會發出一個名為 `UpdatedMessages` 的智慧型合約事件: + +```javascript +// HelloWorld.sol + +// 指定 Solidity 的版本,使用語意化版本控制。 +// 了解更多:https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma +pragma solidity ^0.7.3; + +// 定義一個名為「HelloWorld」的合約。 +// 合約是函式和資料 (其狀態) 的集合。部署後,合約會存放在以太坊區塊鏈的特定地址上。了解更多:https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html +contract HelloWorld { + + // 呼叫更新函式時發出 + // 智慧型合約事件是您合約的一種方式,可將區塊鏈上發生的事情傳達給您的應用程式前端,前端可以「監聽」某些事件並在事件發生時採取行動。 + event UpdatedMessages(string oldStr, string newStr); + + // 宣告一個「string」類型的狀態變數「message」。 + // 狀態變數是其值永久儲存在合約儲存空間中的變數。關鍵字「public」可讓變數從合約外部存取,並建立一個其他合約或用戶端可呼叫以存取該值的函式。 + string public message; + + // 與許多以類別為基礎的物件導向語言相似,建構函式是一個特殊函式,只在合約建立時執行。 + // 建構函式用於初始化合約的資料。了解更多:https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors + constructor(string memory initMessage) { + + // 接受一個字串引數「initMessage」,並將該值設定到合約的「message」儲存變數中)。 + message = initMessage; + } + + // 一個公共函式,接受一個字串引數並更新「message」儲存變數。 + function update(string memory newMessage) public { + string memory oldMsg = message; + message = newMessage; + emit UpdatedMessages(oldMsg, newMessage); + } +} +``` + +智慧型合約事件是您合約的一種方式,可將區塊鏈上發生的事情 (即發生了_事件_) 傳達給您的前端應用程式,前端可以「監聽」特定事件並在事件發生時採取行動。 + +`addSmartContractListener` 函式將專門監聽我們的 Hello World 智慧型合約的 `UpdatedMessages` 事件,並更新我們的 UI 以顯示新訊息。 + +將 `addSmartContractListener` 修改為以下內容: + +```javascript +// HelloWorld.js + +function addSmartContractListener() { + helloWorldContract.events.UpdatedMessages({}, (error, data) => { + if (error) { + setStatus("😥 " + error.message) + } else { + setMessage(data.returnValues[1]) + setNewMessage("") + setStatus("🎉 您的訊息已更新!") + } + }) +} +``` + +讓我們來分解一下監聽器偵測到事件時會發生什麼事: + +- 如果事件發出時發生錯誤,它將透過我們的 `status` 狀態變數反映在 UI 中。 +- 否則,我們將使用回傳的 `data` 物件。 `data.returnValues` 是一個從零開始索引的陣列,其中陣列中的第一個元素儲存先前的訊息,第二個元素儲存更新後的訊息。 總而言之,在一個成功的事件上,我們將把我們的 `message` 字串設定為更新後的訊息,清除 `newMessage` 字串,並更新我們的 `status` 狀態變數以反映新訊息已發布在我們的智慧型合約上。 + +最後,讓我們在我們的 `useEffect` 函式中呼叫我們的監聽器,以便它在 `HelloWorld.js` 元件的第一次渲染時被初始化。 總而言之,您的 `useEffect` 函式應如下所示: + +```javascript +// HelloWorld.js + +useEffect(async () => { + const message = await loadCurrentMessage() + setMessage(message) + addSmartContractListener() +}, []) +``` + +既然我們能從我們的智慧型合約中讀取,如果能弄清楚如何寫入就太好了! 然而,若要寫入我們的去中心化應用程式,我們必須先有一個以太坊錢包連線到它。 + +所以,接下來我們將處理設定我們的以太坊錢包 (MetaMask),然後將它連線至我們的去中心化應用程式! + +### 步驟 4:設定您的以太坊錢包 {#step-4-set-up-your-ethereum-wallet} + +若要向以太坊鏈寫入任何內容,使用者必須使用其虛擬錢包的私密金鑰簽署交易。 在本教學中,我們將使用 [MetaMask](https://metamask.io/),這是一款瀏覽器中的虛擬錢包,用於管理您的以太坊帳戶地址,因為它讓最終使用者簽署交易變得非常容易。 + +如果您想深入了解以太坊上的交易如何運作,請參閱以太坊基金會的[此頁面](/developers/docs/transactions/)。 + +#### 下載 MetaMask {#download-metamask} + +您可以在[這裡](https://metamask.io/download)免費下載並建立 MetaMask 帳戶。 在建立帳戶時,或如果您已有帳戶,請確保切換到右上角的「Goerli 測試網」 (這樣我們就不會處理真實貨幣)。 + +#### 從水龍頭新增以太幣 {#add-ether-from-a-faucet} + +若要在以太坊區塊鏈上簽署交易,我們需要一些假的 Eth。 若要取得 Eth,您可以前往 [FaucETH](https://fauceth.komputing.org) 並輸入您的 Goerli 帳戶地址,點擊「請求資金」,然後在下拉式選單中選取「以太坊測試網 Goerli」,最後再次點擊「請求資金」按鈕。 你應該很快便能在你的MetaMask帳戶裡看見ETH! + +#### 檢查您的餘額 {#check-your-balance} + +為了再次確認我們的餘額,讓我們使用 [Alchemy 的 composer 工具](https://composer.alchemyapi.io/?composer_state=%7B%22network%22%3A0%2C%22methodName%22%3A%22eth_getBalance%22%2C%22paramValues%22%3A%5B%22%22%2C%22latest%22%5D%7D) 發出一個 [eth_getBalance](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc#eth_getbalance) 請求。 這將會把我們錢包內的以太結餘回傳。 在你輸入自己的MetaMask帳戶地址,並且點下「寄送請求」後,你理應會看見一個這樣子的回應: + +```text +{"jsonrpc": "2.0", "id": 0, "result": "0xde0b6b3a7640000"} +``` + +**注意:** 此結果的單位是 wei,不是 eth。 Wei是一個被用來計算以太最少分數的單位。 要把wei換算到ETH的算術是:1 ETH = 10¹⁸ wei。 所以,如果我們要換算 0xde0b6b3a7640000 到小數點,我們會得到 1\*10¹⁸的結果,它相當於一個ETH的數值。 + +哈! 我們的假錢都在這! 🤑 + +### 步驟 5:將 MetaMask 連線至您的 UI {#step-5-connect-metamask-to-your-UI} + +既然我們的 MetaMask 錢包已經設定好了,就讓我們把去中心化應用程式連接到它吧! + +#### `connectWallet` 函式 {#the-connectWallet-function} + +在我們的 `interact.js` 檔案中,讓我們來實作 `connectWallet` 函式,然後我們可以在我們的 `HelloWorld.js` 元件中呼叫它。 + +讓我們將 `connectWallet` 修改為以下內容: + +```javascript +// interact.js + +export const connectWallet = async () => { + if (window.ethereum) { + try { + const addressArray = await window.ethereum.request({ + method: "eth_requestAccounts", + }) + const obj = { + status: "👆🏽 在上方的文字欄位中寫一則訊息。", + address: addressArray[0], + } + return obj + } catch (err) { + return { + address: "", + status: "😥 " + err.message, + } + } + } else { + return { + address: "", + status: ( + +

+ {" "} + 🦊 + 您必須在瀏覽器中安裝 MetaMask,這是一款虛擬以太坊錢包。 + +

+
+ ), + } + } +} +``` + +那麼這段龐大的程式碼究竟做了什麼? + +首先,它會檢查您的瀏覽器中是否啟用了 `window.ethereum`。 + +`window.ethereum` 是由 MetaMask 和其他錢包提供者注入的全域 API,允許網站請求使用者的以太坊帳戶。 如果獲得批准,它可以從使用者連線的區塊鏈讀取資料,並建議使用者簽署訊息和交易。 查看 [MetaMask 文件](https://docs.metamask.io/guide/ethereum-provider.html#table-of-contents)以獲得更多資訊! + +如果 `window.ethereum` _不存在_,那表示 MetaMask 沒有安裝。 這會回傳一個 JSON 物件,其中回傳的 `address` 是一個空字串,而 `status` JSX 物件則傳達使用者必須安裝 MetaMask 的訊息。 + +現在如果 `window.ethereum` _存在_,事情就變得有趣了。 + +使用 try/catch 迴圈,我們將透過呼叫 [`window.ethereum.request({ method: "eth_requestAccounts" });`](https://docs.metamask.io/guide/rpc-api.html#eth-requestaccounts) 來嘗試連接 MetaMask。 呼叫這個函式會在瀏覽器中開啟 MetaMask,提示使用者將他們的錢包連接到你的去中心化應用程式。 + +- 如果使用者選擇連線,`method: "eth_requestAccounts"` 將回傳一個陣列,其中包含所有連線至去中心化應用程式的使用者帳戶地址。 總而言之,我們的 `connectWallet` 函式會回傳一個 JSON 物件,其中包含此陣列中的_第一個_ `address` (見第 9 行) 和一則 `status` 訊息,提示使用者向智能合約寫入一則訊息。 +- 如果使用者拒絕連接,那麼 JSON 物件將包含一個空字串作為回傳的 `address`,以及一則反映使用者拒絕連接的 `status` 訊息。 + +既然我們已編寫此 `connectWallet` 函式,下一步就是將它呼叫至我們的 `HelloWorld.js` 元件。 + +#### 將 `connectWallet` 函式新增至您的 `HelloWorld.js` UI 元件 {#add-the-connectWallet-function-to-your-HelloWorld-js-ui-component} + +導覽至 `HelloWorld.js` 中的 `connectWalletPressed` 函式,並將其更新為以下內容: + +```javascript +// HelloWorld.js + +const connectWalletPressed = async () => { + const walletResponse = await connectWallet() + setStatus(walletResponse.status) + setWallet(walletResponse.address) +} +``` + +注意到我們的大部分功能是如何從 `interact.js` 檔案中抽象出來,遠離我們的 `HelloWorld.js` 元件嗎? 這是我們跟M-V-C規範相容的做法! + +在 `connectWalletPressed` 中,我們只需對匯入的 `connectWallet` 函式進行一個 await 呼叫,並利用其回應,透過它們的 state hooks 更新我們的 `status` 和 `walletAddress` 變數。 + +現在,讓我們儲存這兩個檔案 (`HelloWorld.js` 和 `interact.js`),並測試一下我們目前的 UI。 + +在 [http://localhost:3000/](http://localhost:3000/) 頁面上開啟您的瀏覽器,並按下頁面右上角的「連線錢包」按鈕。 + +如果你已安裝 MetaMask,系統應該會提示你將錢包連接到你的去中心化應用程式。 請接受進行連結的邀請。 + +您應該會看到錢包按鈕現在反映您的地址已連線! 太棒了 🔥 + +接下來,試著重新整理頁面... 這很奇怪。 我們的錢包按鈕會鼓勵我們對MetaMask進行連結,就算它已經被連結好了。。。。。。 + +不過,別擔心! 我們可以輕鬆地處理這個問題 (懂嗎?) 透過實作 `getCurrentWalletConnected`,它將檢查是否有地址已連線至我們的去中心化應用程式,並相應地更新我們的 UI! + +#### `getCurrentWalletConnected` 函式 {#the-getcurrentwalletconnected-function} + +將您 `interact.js` 檔案中的 `getCurrentWalletConnected` 函式更新為以下內容: + +```javascript +// interact.js + +export const getCurrentWalletConnected = async () => { + if (window.ethereum) { + try { + const addressArray = await window.ethereum.request({ + method: "eth_accounts", + }) + if (addressArray.length > 0) { + return { + address: addressArray[0], + status: "👆🏽 在上方的文字欄位中寫一則訊息。", + } + } else { + return { + address: "", + status: "🦊 使用右上角按鈕連線至 MetaMask。", + } + } + } catch (err) { + return { + address: "", + status: "😥 " + err.message, + } + } + } else { + return { + address: "", + status: ( + +

+ {" "} + 🦊 + 您必須在瀏覽器中安裝 MetaMask,這是一款虛擬以太坊錢包。 + +

+
+ ), + } + } +} +``` + +這段程式碼與我們剛在上一步中編寫的 `connectWallet` 函式_非常_相似。 + +主要的區別在於,我們不是呼叫 `eth_requestAccounts` 方法 (這會開啟 MetaMask 讓使用者連接他們的錢包),而是在這裡呼叫 `eth_accounts` 方法,它只會回傳一個包含當前連接到我們去中心化應用程式的 MetaMask 位址的陣列。 + +若要查看此函式的實際運作情況,讓我們在我們的 `HelloWorld.js` 元件的 `useEffect` 函式中呼叫它: + +```javascript +// HelloWorld.js + +useEffect(async () => { + const message = await loadCurrentMessage() + setMessage(message) + addSmartContractListener() + + const { address, status } = await getCurrentWalletConnected() + setWallet(address) + setStatus(status) +}, []) +``` + +注意,我們使用對 `getCurrentWalletConnected` 呼叫的回應來更新我們的 `walletAddress` 和 `status` 狀態變數。 + +既然您已新增此程式碼,讓我們試著重新整理我們的瀏覽器視窗。 + +太棒了! 這個按鈕應該會跟你說:「你已經連結好了。」,然後會顯出一個你錢包被連結好的地址的預視 - 就算在你刷新之後也會這樣! + +#### 實作 `addWalletListener` {#implement-addwalletlistener} + +我們去中心化應用程式錢包設定的最後一個步驟是實作錢包監聽器,這樣當我們錢包的狀態改變時 (例如使用者中斷連線或切換帳戶),我們的 UI 就會更新。 + +在您的 `HelloWorld.js` 檔案中,將您的 `addWalletListener` 函式修改為以下內容: + +```javascript +// HelloWorld.js + +function addWalletListener() { + if (window.ethereum) { + window.ethereum.on("accountsChanged", (accounts) => { + if (accounts.length > 0) { + setWallet(accounts[0]) + setStatus("👆🏽 在上方的文字欄位中寫一則訊息。") + } else { + setWallet("") + setStatus("🦊 使用右上角按鈕連線至 MetaMask。") + } + }) + } else { + setStatus( +

+ {" "} + 🦊 + 您必須在瀏覽器中安裝 MetaMask,這是一款虛擬以太坊錢包。 + +

+ ) + } +} +``` + +我敢打賭,此時您甚至不需要我們的幫助就能了解這裡發生了什麼事,但為了周全起見,讓我們快速分解一下: + +- 首先,我們的函式會檢查 `window.ethereum` 是否已啟用 (即 MetaMask 已安裝)。 + - 如果沒有啟用,我們只需將 `status` 狀態變數設定為一個 JSX 字串,提示使用者安裝 MetaMask。 + - 如果已啟用,我們在第 3 行設定監聽器 `window.ethereum.on("accountsChanged")`,它會監聽 MetaMask 錢包的狀態變化,包括使用者將額外帳戶連接到去中心化應用程式、切換帳戶或中斷帳戶連線時。 如果至少有一個帳戶已連接,`walletAddress` 狀態變數會更新為監聽器回傳的 `accounts` 陣列中的第一個帳戶。 否則,`walletAddress` 會被設定為空字串。 + +最後但同樣重要的是,我們必須在我們的 `useEffect` 函式中呼叫它: + +```javascript +// HelloWorld.js + +useEffect(async () => { + const message = await loadCurrentMessage() + setMessage(message) + addSmartContractListener() + + const { address, status } = await getCurrentWalletConnected() + setWallet(address) + setStatus(status) + + addWalletListener() +}, []) +``` + +就是這樣! 我們已成功完成所有錢包功能的編寫! 現在進入我們最後的任務:更新儲存在我們智慧型合約中的訊息! + +### 步驟 6:實作 `updateMessage` 函式 {#step-6-implement-the-updateMessage-function} + +好了,各位,我們已進入最後階段! 在您 `interact.js` 檔案的 `updateMessage` 中,我們將執行以下操作: + +1. 確保我們希望在我們的智慧合約中發布的訊息是有效的 +2. 使用 MetaMask 簽署我們的交易 +3. 從我們的 `HelloWorld.js` 前端元件呼叫此函式 + +這不會花很長時間;讓我們完成這個去中心化應用程式! + +#### 輸入錯誤處理 {#input-error-handling} + +自然地,在函式開始時進行某種輸入錯誤處理是合理的。 + +如果沒有安裝 MetaMask 擴充功能、沒有連線錢包 (即傳入的 `address` 是空字串),或者 `message` 是空字串,我們希望我們的函式能提早回傳。 讓我們將以下錯誤處理新增至 `updateMessage`: + +```javascript +// interact.js + +export const updateMessage = async (address, message) => { + if (!window.ethereum || address === null) { + return { + status: + "💡 連線您的 MetaMask 錢包以更新區塊鏈上的訊息。", + } + } + + if (message.trim() === "") { + return { + status: "❌ 您的訊息不能是空字串。", + } + } +} +``` + +既然它有了適當的輸入錯誤處理,是時候透過 MetaMask 簽署交易了! + +#### 簽署我們的交易 {#signing-our-transaction} + +如果您已經熟悉傳統的 web3 以太坊交易,我們接下來編寫的程式碼將會非常熟悉。 在您的輸入錯誤處理程式碼下方,將以下內容新增至 `updateMessage`: + +```javascript +// interact.js + +//設定交易參數 +const transactionParameters = { + to: contractAddress, // 合約發布期間除外為必要 + from: address, // 必須與使用者目前的地址相符 + data: helloWorldContract.methods.update(message).encodeABI(), +} + +//簽署交易 +try { + const txHash = await window.ethereum.request({ + method: "eth_sendTransaction", + params: [transactionParameters], + }) + return { + status: ( + + ✅{" "} + + 在 Etherscan 上查看您交易的狀態! + +
+ ℹ️ 交易一旦經網路驗證,訊息將自動更新。 +
+ ), + } +} catch (error) { + return { + status: "😥 " + error.message, + } +} +``` + +讓我們來分解一下發生了什麼事。 首先,我們設定我們的交易參數,其中: + +- `to` 指定接收方位址 (我們的智能合約) +- `from` 指定交易的簽署者,即我們傳入函式的 `address` 變數 +- `data` 包含對我們 Hello World 智慧型合約的 `update` 方法的呼叫,並接收我們的 `message` 字串變數作為輸入 + +然後,我們進行一個 await 呼叫,`window.ethereum.request`,我們在此請求 MetaMask 簽署交易。 請注意,在第 11 和 12 行,我們正在指定我們的 eth 方法 `eth_sendTransaction`,並傳入我們的 `transactionParameters`。 + +在這時機,MetaMask將會在瀏覽器中被開啟,然後鼓勵用戶去簽署或拒絕該筆交易。 + +- 如果交易成功,函式將回傳一個 JSON 物件,其中 `status` JSX 字串會提示使用者查看 Etherscan 以取得有關其交易的更多資訊。 +- 如果交易失敗,函式將回傳一個 JSON 物件,其中 `status` 字串會轉達錯誤訊息。 + +總而言之,我們的 `updateMessage` 函式應如下所示: + +```javascript +// interact.js + +export const updateMessage = async (address, message) => { + //輸入錯誤處理 + if (!window.ethereum || address === null) { + return { + status: + "💡 連線您的 MetaMask 錢包以更新區塊鏈上的訊息。", + } + } + + if (message.trim() === "") { + return { + status: "❌ 您的訊息不能是空字串。", + } + } + + //設定交易參數 + const transactionParameters = { + to: contractAddress, // 合約發布期間除外為必要 + from: address, // 必須與使用者目前的地址相符 + data: helloWorldContract.methods.update(message).encodeABI(), + } + + //簽署交易 + try { + const txHash = await window.ethereum.request({ + method: "eth_sendTransaction", + params: [transactionParameters], + }) + return { + status: ( + + ✅{" "} + + 在 Etherscan 上查看您交易的狀態! + +
+ ℹ️ 交易一旦經網路驗證,訊息將自動更新。 +
+ ), + } + } catch (error) { + return { + status: "😥 " + error.message, + } + } +} +``` + +最後但同樣重要的是,我們需要將我們的 `updateMessage` 函式連線至我們的 `HelloWorld.js` 元件。 + +#### 將 `updateMessage` 連線至 `HelloWorld.js` 前端 {#connect-updatemessage-to-the-helloworld-js-frontend} + +我們的 `onUpdatePressed` 函式應對匯入的 `updateMessage` 函式進行 await 呼叫,並修改 `status` 狀態變數以反映我們的交易是成功還是失敗: + +```javascript +// HelloWorld.js + +const onUpdatePressed = async () => { + const { status } = await updateMessage(walletAddress, newMessage) + setStatus(status) +} +``` + +它非常乾淨簡單。 您猜怎麼著... 您的去中心化應用程式完成了!!! + +去測試一下**更新**按鈕吧! + +### 製作您自己的自訂去中心化應用程式 {#make-your-own-custom-dapp} + +哇,您完成了本教學! 總結一下,您學會了如何: + +- 將 MetaMask 錢包連線至您的去中心化應用程式專案 +- 使用 [Alchemy Web3](https://docs.alchemy.com/alchemy/documentation/alchemy-web3) API 從您的智慧型合約讀取資料 +- 使用 MetaMask 簽署以太坊交易 + +現在您已完全具備應用本教學的技能,可以打造您自己的自訂去中心化應用程式專案了! 一如既往,如果您有任何問題,請隨時到 [Alchemy Discord](https://discord.gg/gWuC7zB) 尋求協助。 🧙‍♂️ + +完成本教學後,請在 Twitter 上標記我們 [@alchemyplatform](https://twitter.com/AlchemyPlatform),讓我們知道您的體驗如何,或是否有任何回饋! diff --git a/public/content/translations/zh-tw/gaming/index.md b/public/content/translations/zh-tw/gaming/index.md index 0a7ead6895a..b7700264405 100644 --- a/public/content/translations/zh-tw/gaming/index.md +++ b/public/content/translations/zh-tw/gaming/index.md @@ -23,10 +23,10 @@ buttons: ## 以太坊遊戲生態系統概覽 {#ethereums-gaming-ecosystem-overview} -- **二層網路:**由於費用較低且交易時間短,二層網路成為了遊戲發行的常見平台。 擁有遊戲的頂級二層網路包括:Starknet、Immutable、Base 和 Abstract。 -- **基礎設施:**為簡化鏈上遊戲的開發,現有多種工具堆疊可供您在自己的專案中使用,包括:Cartridge、Dojo、Proof of Play 和 Thirdweb。 -- **遊戲公會:**希望成為遊戲社群一份子的玩家可以加入遊戲公會,與公會中的其他玩家一起制定策略和協作。 著名的公會包括:YGG、WASD、LegacyGG、Gaming Grid、OLAGG 等。 -- **遊戲:**以太坊遊戲的類型與規模各不相同,從 _Realms: Eternum_ 的即時策略遊戲、_Axie: Atia's Legacy_ 的大型多人線上遊戲、_Fableborn_ 的動作角色扮演遊戲,到 _Ponziland_ 等遊戲化的 DeFi 平台,應有盡有。 隨著新遊戲在不同鏈上定期推出,總有新鮮事物等您探索。 +- 二層網路:由於費用較低且交易時間短,二層網路成為了遊戲發行的常見平台。 擁有遊戲的頂級二層網路包括:Starknet、Immutable、Base 和 Abstract。 +- 基礎設施:為簡化鏈上遊戲的開發,現有多種工具堆疊可供您在自己的專案中使用,包括:Cartridge、Dojo、Proof of Play 和 Thirdweb。 +- 遊戲公會:希望成為遊戲社群一份子的玩家可以加入遊戲公會,與公會中的其他玩家一起制定策略和協作。 著名的公會包括:YGG、WASD、LegacyGG、Gaming Grid、OLAGG 等。 +- 遊戲:以太坊遊戲的類型與規模各不相同,從 _Realms: Eternum_ 的即時策略遊戲、_Axie: Atia's Legacy_ 的大型多人線上遊戲、_Fableborn_ 的動作角色扮演遊戲,到 _Ponziland_ 等遊戲化的 DeFi 平台,應有盡有。 隨著新遊戲在不同鏈上定期推出,總有新鮮事物等您探索。 ## 試玩遊戲 {#games} diff --git a/public/content/translations/zh-tw/glossary/index.md b/public/content/translations/zh-tw/glossary/index.md index 5f2b6f00f58..0ce0299b820 100644 --- a/public/content/translations/zh-tw/glossary/index.md +++ b/public/content/translations/zh-tw/glossary/index.md @@ -1,6 +1,6 @@ --- -title: 以太坊詞彙表 -description: 與以太坊相關的技術和非技術術語的不完整詞彙表 +title: "以太坊詞彙表" +description: "與以太坊相關的技術和非技術術語的不完整詞彙表" lang: zh-tw --- @@ -118,6 +118,8 @@ lang: zh-tw + + @@ -320,11 +322,11 @@ lang: zh-tw ## O {#section-o} - + - + @@ -440,6 +442,8 @@ lang: zh-tw + + @@ -474,6 +478,8 @@ lang: zh-tw + + ## Z {#section-z} @@ -488,12 +494,12 @@ lang: zh-tw ## 來源 {#sources} -_摘自 [Andreas M. Antonopoulos 與 Gavin Wood](https://ethereumbook.info) 所著 [《精通以太坊》](https://github.com/ethereumbook/ethereumbook)(依據 CC-BY-SA 協議)_ +_部分內容來自 [Andreas M. Antonopoulos, Gavin Wood](https://aantonop.com/books/mastering-ethereum) 所著的 [《精通以太坊》](https://github.com/ethereumbook/ethereumbook),遵循 CC-BY-SA 授權_ -## 完善本頁面 {#contribute-to-this-page} +## 為本頁面做出貢獻 {#contribute-to-this-page} 我們是否有所遺漏? 是否存在謬誤? 請在 GitHub 上為此詞彙表貢獻力量,幫助我們改進! -[瞭解更多關於如何貢獻的資訊](/contributing/adding-glossary-terms) +[深入瞭解如何貢獻](/contributing/adding-glossary-terms) diff --git a/public/content/translations/zh-tw/governance/index.md b/public/content/translations/zh-tw/governance/index.md index 23e20216aea..3b41bd8f58a 100644 --- a/public/content/translations/zh-tw/governance/index.md +++ b/public/content/translations/zh-tw/governance/index.md @@ -1,6 +1,6 @@ --- -title: 以太坊管理體系 -description: 以太坊決策方式的簡介。 +title: "以太坊管理體系" +description: "以太坊決策方式的簡介。" lang: zh-tw --- @@ -22,7 +22,7 @@ _如果沒人擁有以太坊,如何針對以太坊過去和未來的變動, 以太坊管理體系是一種變更協定的流程。 此流程本身和人或應用程式如何使用協定無關,這點很重要,以太坊是無需許可的。 世界上每個人都能參與以太坊鏈上的活動。 對於誰能建立應用程式或傳送交易,並無規則限制。 但若想提議變更核心協定,確實有既定的流程,去中心化應用程式就是在此協定上執行。 由於現今太多人倚賴以太坊的穩定性,因此包括社會和技術流程在內,核心變更的協作門檻非常高,確保無論對以太坊作出何種變更,都能安全無虞且獲得社群的廣泛支援。 -### 鏈上與鏈下管理體系的比較 {#on-chain-vs-off-chain} +### 鏈上與鏈下管理體系的比較 {#onchain-vs-offchain} 區塊鏈技術為管理體系帶來了新的可能性,俗稱鏈上管理體系。 鏈上管理體系是指提出的協定變更由利益相關方投票決定。通常是管理體系代幣的持有者投票,且投票是在區塊鏈上進行。 某些形式的鏈上管理體系,提出的協定變更已經寫入程式碼中,如果利益相關方簽署交易核准許變更內容,還會自動實作這些變更。 @@ -78,7 +78,7 @@ _注意:任何人都能參與多個組別,例如,協定開發者可以支 > - 將請求進行技術變更 > - 如果非當務之急,或相對於開發工作而言,改善程度不夠顯著,可能會被拒絕 -3. **朝最終提案進行迭代:**收到所有利益相關方的回饋意見後,你很可能需要對初始提案進行修改,以提高安全性或更加滿足多種使用者的需求。 當以太坊改進提案納入你認為必須納入的所有變更,你需要再次提供給協定開發者。 之後將進入此流程的下個步驟;或是出現新的問題,提案必須再迭代一輪。 +3. 朝最終提案進行迭代:收到所有利益相關方的回饋意見後,你很可能需要對初始提案進行修改,以提高安全性或更加滿足多種使用者的需求。 當以太坊改進提案納入你認為必須納入的所有變更,你需要再次提供給協定開發者。 之後將進入此流程的下個步驟;或是出現新的問題,提案必須再迭代一輪。 4. **網路升級中納入以太坊改進提案**:假設以太坊改進提案已核准、測試及實作,以太坊改進提案會被安排為網路升級的一部分。 由於網路升級的協調成本很高(每個人需同步升級),升級通常會將以太坊改進提案綁搭在一起。 diff --git a/public/content/translations/zh-tw/guides/how-to-create-an-ethereum-account/index.md b/public/content/translations/zh-tw/guides/how-to-create-an-ethereum-account/index.md index b4232f7052d..f7c844f11f5 100644 --- a/public/content/translations/zh-tw/guides/how-to-create-an-ethereum-account/index.md +++ b/public/content/translations/zh-tw/guides/how-to-create-an-ethereum-account/index.md @@ -1,27 +1,26 @@ --- -title: 如何「建立」以太坊帳戶 -description: 使用錢包建立以太坊帳戶的逐步指南。 +title: "如何「建立」以太坊帳戶" +description: "使用錢包建立以太坊帳戶的逐步指南。" lang: zh-tw --- # 如何建立一個以太坊帳戶 -**任何人都可以免費建立以太坊帳戶。**你只需要安裝一個加密錢包應用程式。 錢包建立並與管理你的以太坊帳戶。 它們可以發送交易、查看你的餘額,並讓你連線到其他構建在以太坊網路的應用程式。 +任何人都可以免費建立以太坊帳戶。你只需要安裝一個加密錢包應用程式。 錢包建立並與管理你的以太坊帳戶。 它們可以發送交易、查看你的餘額,並讓你連線到其他構建在以太坊網路的應用程式。 -藉由使用錢包,你也可以立即登入任何代幣交易所、遊戲和[非同質化代幣](/glossary/#nft)市場。 無需單獨註冊,一個帳戶即可共用於所有構建在以太坊網路上的應用程式。 +有了錢包,你還可以立即登入任何代幣交易所、遊戲和 [NFT](/glossary/#nft) 市場。 無需單獨註冊,一個帳戶即可共用於所有構建在以太坊網路上的應用程式。 ## 第一步:建立一個錢包 錢包是一個幫助你管理以太坊帳戶的應用程式。 有數十種不同的錢包可供選擇:包括行動端、桌面版,甚至是瀏覽器擴充功能。 - 錢包列表 如果你第一次使用,可以在「找到一個錢包」頁面選擇「加密貨幣新手」篩選條件,得知哪些錢包應含有適合新手使用的所有必要功能。 -![「選擇錢包」頁面的篩選選項](./wallet-box.png) +![「尋找錢包」頁面上的篩選器選項](./wallet-box.png) 另有其他設定檔篩選條件可滿足你的需求。 下面是常用錢包的一些例子,在信任任何軟體之前,你應該先做些功課。 @@ -37,21 +36,21 @@ lang: zh-tw 有些應用程式會要求你記下一組秘密的「恢復助記詞」(有時稱為「種子助記詞」或「助記符」)。 妥善保管好這組助記詞非常重要! 它用於產生你的以太坊帳戶並且可以用來提交交易。 -**任何知道這組助記詞的人都可以掌管所有資金。**切勿與任何人分享此資訊。 這組助記詞應包含 12 到 24 個隨機產生的單字(這些單字的順序很重要)。 +任何知道這組助記詞的人都可以掌管所有資金。切勿與任何人分享。 這組助記詞應包含 12 到 24 個隨機產生的單字(這些單字的順序很重要)。
-
錢包安裝了嗎?
瞭解如何使用它。
+
錢包安裝好了嗎?
了解如何使用。
如何使用錢包 -
+
-對其他指南有興趣嗎? 查看我們的[逐步指南](/guides/) +對其他指南有興趣嗎? 查看我們的:[逐步指南](/guides/) ## 常見問題 @@ -61,11 +60,11 @@ lang: zh-tw ### 我可以將比特幣傳送到以太坊地址,或將以太幣傳送到比特幣地址嗎? -沒有辦法。 比特幣和以太幣存在於兩個獨立的網路上(即不同的區塊鏈),每個網路都有自己獨特的記帳和地址格式。 曾有各種將這兩個不同的網路橋接在一起的嘗試,目前最活躍的是[包裝比特幣或 WBTC](https://www.bitcoin.com/get-started/what-is-wbtc/)。 這不是一種認可背書,因為 WBTC 是一個託管解決方案(即由一組人控制某些關鍵功能),此處提供的資訊僅供參考。 +沒有辦法。 比特幣和以太幣存在於兩個獨立的網路上 (即不同的區塊鏈),每個網路都有自己獨特的記帳和地址格式。 曾有許多橋接這兩個不同網路的嘗試,其中目前最活躍的是 [Wrapped Bitcoin 或 WBTC](https://www.bitcoin.com/get-started/what-is-wbtc/)。 這不是一種認可背書,因為 WBTC 是一個託管解決方案(即由一組人控制某些關鍵功能),此處提供的資訊僅供參考。 ### 如果我有一個以太幣地址,我在其他區塊鏈上也擁有同一個地址嗎? -區塊鏈只要使用與以太坊類似的底層軟體(稱為「與以太坊虛擬機相容」),你都可以在所有這些區塊鏈上使用同一個地址。 此[列表](https://chainlist.org/)將展示出同一地址所適用的區塊鏈。 比特幣等某些區塊鏈,實作了一整套獨立的網路規則,你將需要一個不同格式的不同地址。 如果你有智慧型合約錢包,你應該查看其產品網站以更多瞭解它支援哪些區塊鏈,因為這些錢包通常支援的範圍有限但更安全。 +只要區塊鏈使用與以太坊類似的底層軟體 (稱為「與以太坊虛擬機相容」),就能在這些區塊鏈上使用同一個[地址](/glossary/#address)。 此[清單](https://chainlist.org/)會顯示您可以用相同地址使用哪些區塊鏈。 比特幣等某些區塊鏈,實作了一整套獨立的網路規則,你將需要一個不同格式的不同地址。 如果你有智慧型合約錢包,你應該查看其產品網站以更多瞭解它支援哪些區塊鏈,因為這些錢包通常支援的範圍有限但更安全。 ### 擁有自己的錢包,比將資金存放在交易所上更安全嗎? diff --git a/public/content/translations/zh-tw/guides/how-to-id-scam-tokens/index.md b/public/content/translations/zh-tw/guides/how-to-id-scam-tokens/index.md index 6a457a633d3..df357e670c5 100644 --- a/public/content/translations/zh-tw/guides/how-to-id-scam-tokens/index.md +++ b/public/content/translations/zh-tw/guides/how-to-id-scam-tokens/index.md @@ -1,26 +1,25 @@ --- -title: 如何辨識詐騙代幣 -description: 了解詐騙代幣、它們如何使自己看似合法,以及如何避開這種詐騙方式。 +title: "如何辨識詐騙代幣" +description: "了解詐騙代幣、它們如何使自己看似合法,以及如何避開這種詐騙方式。" lang: zh-tw --- # 如何辨識詐騙代幣 {#identify-scam-tokens} -以太坊最常見的用處之一就是為一個團隊建立一種可交易的代幣。某種意義上,這是屬於他們自己的貨幣。 這些代幣通常依循一種標準,那就是 [ERC-20](/developers/docs/standards/tokens/erc-20/)。 然而,任何能產生價值的正當使用案例中,就會有犯罪者嘗試竊取該價值納為已用。 +以太坊最常見的用處之一就是為一個團隊建立一種可交易的代幣。某種意義上,這是屬於他們自己的貨幣。 這些代幣通常會遵循 [ERC-20](/developers/docs/standards/tokens/erc-20/) 標準。 然而,任何能產生價值的正當使用案例中,就會有犯罪者嘗試竊取該價值納為已用。 他們可能透過這兩種方式行騙: -- **向你兜售詐騙代幣**,代幣可能看似你想要購買的正規代幣,但其實是由詐騙者發行且不具任何價值的代幣。 -- **誘騙你簽署不利的交易**,手段通常是導引你到他們自己的使用者介面。 他們可能會試圖讓你授權,使他們的合約能花費你的 ERC-20 代幣,暴露敏感訊息而使他們能存取你的資產等。 這些使用者介面可能是正規網站幾近完美的複製品,但隱藏著圈套。 +- **向您兜售詐騙代幣**,這些代幣可能看似您想要購買的合法代幣,但其實是由詐騙者發行且不具任何價值的代幣。 +- **誘騙您簽署惡意交易**,通常是將您引導至他們自己的使用者介面。 他們可能會試圖讓你授權,使他們的合約能花費你的 ERC-20 代幣,暴露敏感訊息而使他們能存取你的資產等。 這些使用者介面可能是正規網站幾近完美的複製品,但隱藏著圈套。 -為了說明詐騙代幣為何,以及如何辨識詐騙代幣,我們來看一個詐騙代幣示例:[`wARB`](https://etherscan.io/token/0xb047c8032b99841713b8e3872f06cf32beb27b82)。 這個代幣看起來試圖模仿 [`ARB`](https://etherscan.io/address/0xb50721bcf8d664c30412cfbc6cf7a15145234ad1) 代幣。 +為了說明什麼是詐騙代幣,以及如何辨識它們,我們將看一個範例:[`wARB`](https://eth.blockscout.com/token/0xB047c8032b99841713b8E3872F06cF32beb27b82)。 這個代幣試圖偽裝成合法的 [`ARB`](https://eth.blockscout.com/address/0xb50721bcf8d664c30412cfbc6cf7a15145234ad1) 代幣。 -Arbitrum 是一個開發並管理[樂觀卷軸](/developers/docs/scaling/optimistic-rollups/)的機構。 成立之初,Aubitrum 是一間營利公司,而後採取了去中心化的措施。 在此過程中,他們發行了一種可交易的[管理代幣](/dao/#token-based-membership)。 - +Arbitrum 是一個開發和管理[樂觀卷軸](/developers/docs/scaling/optimistic-rollups/)的組織。 成立之初,Arbitrum 是一間營利公司,而後採取了去中心化的措施。 在這個過程中,他們發行了可交易的[治理代幣](/dao/#token-based-membership)。 以太坊有一個慣例,當一種資產不兼容 ERC-20 時,我們會創建一種「打包」版本,名稱以「w」起頭。 因此,舉例來說,比特幣有 wBTC,而以太幣有 wETH。 創建以太坊已有的 ERC-20 代幣的打包版本並不合理,但詐騙代幣看似正規,實際並非如此。 - ## 詐騙代幣如何運作? {#how-do-scam-tokens-work} @@ -41,25 +39,24 @@ contentPreview=''> title="什麼是智慧型合約?" contentPreview=''> -[智慧型合約](/developers/docs/smart-contracts/)是在以太坊區塊鏈上運行的程式。 例如,每個 ERC-20 代幣都以智慧型合約的形式實施。 - +[智能合約](/developers/docs/smart-contracts/)是運行在以太坊區塊鏈上的程式。 例如,每個 ERC-20 代幣都以智慧型合約的形式實施。 -更具體地說,Arbitrum 部署了一種使用符號 `ARB` 的合約。 但這並不能阻止其他人也部署使用完全相同或類似符號的合約。 寫合約的人可以設定合約如何執行。 +具體來說,Arbitrum 部署了一個使用 `ARB` 符號的合約。 但這並不能阻止其他人也部署使用完全相同或類似符號的合約。 寫合約的人可以設定合約如何執行。 -## 看似正規 {#appearing-legitimate} +## 看似合法 {#appearing-legitimate} 詐騙者通常會使用一些技巧使詐騙代幣看似正規。 -- **正規的名稱和符號**。 如上所述,ERC-20 合約可以與其他 ERC-20 合約擁有相同的符號和名稱。 你不能依靠這些欄位確保安全性。 +- **合法的名稱和符號**。 如上所述,ERC-20 合約可以與其他 ERC-20 合約擁有相同的符號和名稱。 你不能依靠這些欄位確保安全性。 -- **正規擁有者**。 詐騙代幣通常會空投大量餘額到預計是真代幣正規擁有者的地址。 +- **合法的擁有者**。 詐騙代幣通常會空投大量餘額到預計是真代幣正規擁有者的地址。 - 我們再次以 `wARB` 為例。 [大概 16% 的代幣](https://etherscan.io/token/0xb047c8032b99841713b8e3872f06cf32beb27b82?a=0x1c8db745abe3c8162119b9ef2c13864cd1fdd72f)由公開標籤為 [Arbitrum Foundation: Deployer](https://etherscan.io/address/0x1c8db745abe3c8162119b9ef2c13864cd1fdd72f) 的地址所擁有。 這_並不是_一個假的地址;它真的是[在以太坊主網上部署真 ARB 合約](https://etherscan.io/tx/0x242b50ab4fe9896cb0439cfe6e2321d23feede7eeceb31aa2dbb46fc06ed2670)的地址。 + 舉例來說,我們再來看一下 `wARB`。 [大約 16% 的代幣](https://eth.blockscout.com/token/0xb047c8032b99841713b8E3872F06cF32beb27b82?tab=holders)是由一個公開標記為 [Arbitrum Foundation: Deployer](https://eth.blockscout.com/address/0x1C8db745ABe3C8162119b9Ef2c13864Cd1FDD72F) 的地址所持有。 這_不是_一個假的地址,這確實是[在以太坊主網上部署了真正 ARB 合約](https://eth.blockscout.com/tx/0x242b50ab4fe9896cb0439cfe6e2321d23feede7eeceb31aa2dbb46fc06ed2670)的地址。 因爲一個地址的 ERC-20 餘額為 ERC-20 合約儲存的一部分,合約開發者可以透過合約將其指定為想要的形式。 合約也可能禁止轉帳,使正規使用者無法擺脫詐騙代幣。 -- **正規轉帳**。 _正規擁有者不會付錢將詐騙代幣轉帳給他人,因此轉帳一定是正規的,對吧?_ **這是錯的**。 `轉帳`透過 ERC-20 合約發生。 詐騙犯可以輕鬆將合約撰寫成得以產生那些操作。 +- **合法的轉帳**。 _合法的擁有者不會付錢將詐騙代幣轉帳給他人,所以如果有轉帳,那一定就是合法的,對吧?_ **錯**。 `Transfer` 事件是由 ERC-20 合約產生的。 詐騙犯可以輕鬆將合約撰寫成得以產生那些操作。 ## 詐騙網站 {#websites} @@ -69,23 +66,23 @@ contentPreview=''> ## 如何保護自己? {#protect-yourself} -1. **檢查合約地址**。 正規的代幣來自於正規的機構,而你可以在機構網站上找到合約地址。 以 [`ARB` 為例,你可以在這裡](https://docs.arbitrum.foundation/deployment-addresses#token)看到正規地址。 +1. **檢查合約地址**。 正規的代幣來自於正規的機構,而你可以在機構網站上找到合約地址。 例如,[您可以在這裡查看 `ARB` 的合法地址](https://docs.arbitrum.foundation/deployment-addresses#token)。 -2. **真正的代幣具有流動性**。 另一個方案是在最常見的代幣交換協議 [Uniswap](https://uniswap.org/) 上查看流動池的大小。 此協議以流動性池操作,讓投資者存放他們的代幣,以期透過交易費用賺取回報。 +2. **真正的代幣具有流動性**。 另一個方法是到最常見的代幣交換協議之一 [Uniswap](https://uniswap.org/) 上查看流動性池的大小。 此協議以流動性池操作,讓投資者存放他們的代幣,以期透過交易費用賺取回報。 -即便有,詐騙代幣通常具有非常小的流動池,因為詐騙犯不想冒失去真資產的風險。 舉例來說,`ARB`/`ETH` 的 Uniswap 池大概有一百萬美元([單擊此處參考最新數值](https://info.uniswap.org/#/pools/0x755e5a186f0469583bd2e80d1216e02ab88ec6ca)),而小量買賣並不會改變價格: +即便有,詐騙代幣通常具有非常小的流動池,因為詐騙犯不想冒失去真資產的風險。 例如,`ARB`/`ETH` Uniswap 池持有約一百萬美元 ([在此處查看最新價值](https://app.uniswap.org/explore#/pools/0x755e5a186f0469583bd2e80d1216e02ab88ec6ca)),小額買賣不會改變價格: -![購買正規代幣](./uniswap-real.png) +![購買合法代幣](./uniswap-real.png) -但當你嘗試購買詐騙代幣 `wARB` 時,即使是小量的購買也會使價格改變超過 90%: +但是當您嘗試購買詐騙代幣 `wARB` 時,即使是極小額的購買也會使價格變動超過 90%: ![購買詐騙代幣](./uniswap-scam.png) -這裡是另外一個告訴我們 `wARB` 不太可能是正規代幣的證明。 +這是另一項證據,顯示 `wARB` 不太可能是個合法的代幣。 -3. **在 Etherscan 區塊瀏覽器中查看**。 社群已經辨識出且舉報過許多詐騙代幣。 那些代幣[會在 Etherscan 區塊瀏覽器上被標註](https://info.etherscan.com/etherscan-token-reputation/)。 雖然 Etherscan 區塊瀏覽器不是官方事實來源(這是因為去中心化網路本質上並不會有正規的官方來源),但 Etherscan 區塊瀏覽器辨識為詐騙的代幣通常為詐騙代幣。 +3. **在 Etherscan 中查看**。 社群已經辨識出且舉報過許多詐騙代幣。 這類代幣在 [Etherscan 上會被標記](https://info.etherscan.com/etherscan-token-reputation/)。 雖然 Etherscan 區塊瀏覽器不是官方事實來源(這是因為去中心化網路本質上並不會有正規的官方來源),但 Etherscan 區塊瀏覽器辨識為詐騙的代幣通常為詐騙代幣。 - ![Etherscan 區塊瀏覽器中的詐騙代幣](./etherscan-scam.png) + ![Etherscan 上的詐騙代幣](./etherscan-scam.png) ## 結論 {#conclusion} @@ -94,4 +91,4 @@ contentPreview=''> - 詐騙代幣會模仿正規代幣,且可以使用同樣的名稱、符號等等。 - 詐騙代幣_無法_使用相同的合約地址。 - 正規代幣地址的最佳來源是該代幣的發行機構。 -- 若無,你可以使用常見且可信的應用程式,例如 [Uniswap](https://app.uniswap.org/#/swap) 和 [Etherscan 區塊瀏覽器](https://etherscan.io/)。 +- 如果做不到,您可以使用熱門、受信任的應用程式,例如 [Uniswap](https://app.uniswap.org/#/swap) 和 [Blockscout](https://eth.blockscout.com/)。 diff --git a/public/content/translations/zh-tw/guides/how-to-revoke-token-access/index.md b/public/content/translations/zh-tw/guides/how-to-revoke-token-access/index.md index e0fc3ff9ab1..e9e57bf3a6d 100644 --- a/public/content/translations/zh-tw/guides/how-to-revoke-token-access/index.md +++ b/public/content/translations/zh-tw/guides/how-to-revoke-token-access/index.md @@ -1,16 +1,16 @@ --- -title: 如何撤銷授權智慧型合約與你的加密資產互動 -description: 關於如何撤銷授權智慧型合約代幣存取權的指南 +title: "如何撤銷授權智慧型合約與你的加密資產互動" +description: "關於如何撤銷授權智慧型合約代幣存取權的指南" lang: zh-tw --- # 如何撤銷授權智慧型合約與你的加密資產互動 -本指南會教你如何檢視所有你已授權存取你的資金的[智慧型合約](/glossary/#smart-contract)清單,以及如何取消授權。 +本指南會教你如何檢視所有你已授權存取你資金的[智能合約](/glossary/#smart-contract)清單,以及如何取消授權。 -有時惡意開發者會在智慧型合約開後門,以存取與該智慧型合約互動的不知情使用者的資金。 這樣的平台通常會要求使用者授予其支出**無限數量代幣**的權限,以嘗試在未來節省少量的[燃料](/glossary/#gas),但這會帶來更高的風險。 +有時惡意開發者會在智慧型合約開後門,以存取與該智慧型合約互動的不知情使用者的資金。 這樣的平台通常會要求使用者授予其支出**無限數量代幣**的權限,以嘗試在未來節省少量的[gas](/glossary/#gas),但這會帶來更高的風險。 -一旦平台取得你[錢包](/glossary/#wallet)中代幣的無限存取權限後,即使你把代幣從該平台提取到你的錢包裏,他們依然可以支出所有這些代幣。 不法者們仍然可以存取你的資金並提取到他們的錢包中,而你將無法做任何恢復操作。 +一旦平台對你[錢包](/glossary/#wallet)中的代幣擁有無限存取權,即使你已將資金從該平台提領至你的錢包,他們仍可以花掉所有這些代幣。 不法者們仍然可以存取你的資金並提取到他們的錢包中,而你將無法做任何恢復操作。 唯一的保護措施是避免使用未經測試的新專案,只授權你所需的權限,或者定期撤銷存取權限。 所以,你會怎麼做呢? @@ -18,11 +18,11 @@ lang: zh-tw 有幾個網站可以讓你查看和撤銷連接到你地址的智慧型合約。 訪問以下網站並連接你的錢包: -- [Ethallowance](https://ethallowance.com/)(以太坊) -- [Etherscan](https://etherscan.io/tokenapprovalchecker)(以太坊) -- [Revoke](https://revoke.cash/)(多種網路) -- [Unrekt](https://app.unrekt.net/)(多種網路) -- [EverRevoke](https://everrise.com/everrevoke/)(多種網路) +- [Etherscan](https://etherscan.io/tokenapprovalchecker) (以太坊) +- [Blockscout](https://eth.blockscout.com/apps/revokescout) (以太坊) +- [Revoke](https://revoke.cash/) (多個網路) +- [Unrekt](https://app.unrekt.net/) (多個網路) +- [EverRevoke](https://everrise.com/everrevoke/) (多個網路) ## 步驟 2:連接你的錢包 @@ -44,7 +44,7 @@ lang: zh-tw 我們建議你永遠不要讓專案無限制地存取你的代幣,並定期撤銷所有代幣存取權限。 撤銷代幣存取權限永遠不會導致資金損失,尤其是使用上面列出的工具時。 -
+
@@ -60,7 +60,7 @@ lang: zh-tw ### 撤銷代幣存取權限是否也會終止質押、聯合質押、借貸等操作? -否,這不會影響你的任何[去中心化金融](/glossary/#defi)策略。 你的持倉和所獲得的酬勞等都會保持不變。 +不會,這不會影響你的任何[DeFi](/glossary/#defi)策略。 你的持倉和所獲得的酬勞等都會保持不變。 ### 從專案中斷開錢包連接和撤銷資金使用權限是否相同? diff --git a/public/content/translations/zh-tw/guides/how-to-swap-tokens/index.md b/public/content/translations/zh-tw/guides/how-to-swap-tokens/index.md index 3b2b2c166b7..b4f78800f36 100644 --- a/public/content/translations/zh-tw/guides/how-to-swap-tokens/index.md +++ b/public/content/translations/zh-tw/guides/how-to-swap-tokens/index.md @@ -1,18 +1,18 @@ --- -title: 如何兌換代幣 -description: 關於如何在以太坊兌換代幣的指南。 +title: "如何兌換代幣" +description: "關於如何在以太坊兌換代幣的指南。" lang: zh-tw --- # 如何兌換代幣 -你是否厭倦了尋找一個能列出你喜歡的所有代幣的交易所? 你可以使用[去中心化交易所](/glossary/#dex)兌換大部分代幣。 +你是否厭倦了尋找一個能列出你喜歡的所有代幣的交易所? 你可以使用[去中心化交易所](/glossary/#dex)兌換大部分的代幣。 -代幣兌換是指在以太坊網路上交換兩種不同的資產,例如將以太幣兌換成 DAI(一種 [ERC-20](/glossary/#erc-20) 代幣)。 這個過程高效且便宜。 你需要一個加密錢包來兌換代幣。 +代幣兌換是指在以太坊網路上交換兩種不同的資產,例如將 ETH 兌換成 DAI (一種 [ERC-20](/glossary/#erc-20) 代幣)。 這個過程高效且便宜。 你需要一個加密錢包來兌換代幣。 **先決條件:** -- 如果擁有一個[加密錢包](/glossary/#wallet),你可以關注以下使用教學:[如何:「註冊」以太坊帳戶](/guides/how-to-create-an-ethereum-account/) +- 擁有一個[加密貨幣錢包](/glossary/#wallet);若您沒有,可以參考這篇[如何建立以太坊帳戶](/guides/how-to-create-an-ethereum-account/)的指南 - 在你的錢包中添加資金 ## 1. 連接你的錢包到所選擇的去中心化交易所 (DEX) @@ -22,37 +22,37 @@ lang: zh-tw - [Uniswap](https://app.uniswap.org/#/swap) - [Sushiswap](https://www.sushi.com/swap) - [1Inch](https://app.1inch.io/#/1/unified/swap/ETH/DAI) -- [Curve](https://curve.fi/#/ethereum/swap) +- [Curve](https://www.curve.finance/dex/ethereum/swap/) -有興趣嗎? 學習更多關於[去中心化金融 (DeFi)](/defi/) 是什麼,以及這些新形態的交易所是如何運作的知識。 +有興趣嗎? 進一步了解[去中心化金融 (DeFi)](/defi/) 的內容,以及這些新型交易所的運作方式。 ## 2. 選擇一對你想要兌換的代幣 -例如以太幣和 DAI。 確保兩種代幣中任意一種有資金。 ![兌換的通用接口](./swap1.png) +例如以太幣和 DAI。 確保兩種代幣中任意一種有資金。 +![用於兌換的通用介面](./swap1.png) -## 3. 輸入要交易的代幣數量,點擊「兌換」 +## 3 輸入要交易的代幣數量,點擊「兌換」 交易所將自動計算你將獲得多少代幣。 -![兌換的通用接口](./swap2.png) +![用於兌換的通用介面](./swap2.png) ## 4 確認交易 查看交易的詳細資訊。 了解兌換率和其他費用,以避免出現不必要的「驚喜」。 -![審查交易的通用接口](./swap3.png) +![用於檢視交易的通用介面](./swap3.png) ## 5 等待交易處理 你可以在任何區塊鏈瀏覽器上查看交易進度。 此過程不會超過 10 分鐘。 -交易處理完成後,你的錢包中將自動收到所兌換的代幣。 -
+交易處理完成後,你的錢包中將自動收到所兌換的代幣。
-
想要學習更多功能嗎?
+
想瞭解更多嗎?
查看我們的其他指南 diff --git a/public/content/translations/zh-tw/guides/how-to-use-a-bridge/index.md b/public/content/translations/zh-tw/guides/how-to-use-a-bridge/index.md index d09525d0ab8..05409789cee 100644 --- a/public/content/translations/zh-tw/guides/how-to-use-a-bridge/index.md +++ b/public/content/translations/zh-tw/guides/how-to-use-a-bridge/index.md @@ -1,31 +1,31 @@ --- -title: 如何通過跨鏈橋將代幣轉移至第二層網路 -description: 關於如何使用跨鏈橋將代幣從以太坊轉移到二層網路的指南。 +title: "如何通過跨鏈橋將代幣轉移至二層網路" +description: "關於如何使用跨鏈橋將代幣從以太坊轉移到二層網路的指南。" lang: zh-tw --- -# 如何通過跨鏈橋將代幣轉移至第二層網路 +# 如何通過跨鏈橋將代幣轉移至二層網路 -如果以太坊上的交易量很大,它將可能變得非常昂貴。 其中一種解決方式是在以太坊網路以外增加新的「網路層」(即使用與以太坊本身相似的方法運行的不同網路)。 這些稱為二層網路的解決方案能處理大量低費用交易,且有時只將這些交易結果儲存到以太坊,從而幫助以太坊減少擁堵與成本。 如此一來,這些二層網路可以讓使用者以更快的速度與較低的費用進行交易。 由於上述諸多優點,許多加密貨幣的專案方會逐漸轉移至二層網路。 而其中最簡單的方法,便是以「跨鏈橋」將貨幣從以太坊轉向二層網路。 +如果以太坊上的交易量很大,它將可能變得非常昂貴。 其中一個解決方案是建立新的「層」:即以類似以太坊本身的方式運作的不同網路。 這些稱為二層網路的解決方案能處理大量低費用交易,且有時只將這些交易結果儲存到以太坊,從而幫助以太坊減少擁堵與成本。 如此一來,這些二層網路可以讓使用者以更快的速度與較低的費用進行交易。 由於上述諸多優點,許多加密貨幣的專案方會逐漸轉移至二層網路。 而其中最簡單的方法,便是以「跨鏈橋」將貨幣從以太坊轉向二層網路。 **先決條件:** -- 擁有一個加密貨幣錢包,你可以跟隨以下使用教學:[如何建立以太坊帳戶](/guides/how-to-create-an-ethereum-account/) +- 擁有加密貨幣錢包 — 如果您沒有,請依照本指南[建立以太坊帳戶](/guides/how-to-create-an-ethereum-account/) - 在你的錢包中添加資金 -## 1. 決定你要使用哪一個二層網路 +## 1. 決定你要使用哪一個二層網路 -在我們的[二層網路頁面](/layer-2/)上,你可以更深入地了解不同的專案與重要連結。 +您可以在我們的 [Layer 2 頁面](/layer-2/) 上,進一步了解不同的專案和重要連結。 ## 2. 前往你選擇的跨鏈橋 一些熱門的二層網路如下: -- [Arbitrum 跨鏈橋](https://bridge.arbitrum.io/?l2ChainId=42161) +- [Arbitrum 跨鏈橋](https://portal.arbitrum.io/bridge?l2ChainId=42161) - [Optimism 跨鏈橋](https://app.optimism.io/bridge/deposit) -- [Boba 網路跨鏈橋](https://gateway.boba.network/) +- [Boba Network 跨鏈橋](https://hub.boba.network/) -## 3. 將跨鏈橋連接到你的錢包 +## 3 將跨鏈橋連接到你的錢包 確保你的錢包已經連結到以太坊主網網路。 如果並未連結,網頁會自動提示你切換網路。 @@ -39,7 +39,7 @@ lang: zh-tw ## 5 在錢包中確認交易 -你將需要用以太幣支付一定金額的交易處理費用。 +您需要以 ETH 的形式支付一筆費用(稱為 [gas](/glossary/#gas))來處理此交易。 ![橋接代幣的通用介面](./bridge3.png) @@ -49,13 +49,12 @@ lang: zh-tw ## 7. 把選取的二層網路加到你的錢包(可選) -可以使用 [chainlist.org](http://chainlist.org) 找到該網路遠端程式呼叫協定的詳細資訊。 添加網路並完成交易後,你會看到代幣出現在你的錢包中。 -
+您可以使用 [chainlist.org](http://chainlist.org) 來尋找網路的 RPC 詳細資訊。 添加網路並完成交易後,你會看到代幣出現在你的錢包中。
-
想要學習更多功能嗎?
+
想瞭解更多嗎?
查看我們的其他指南 @@ -66,7 +65,7 @@ lang: zh-tw ### 如果我在交易所持有資產怎麼辦? -你或許可以從交易所直接提取資產到二層網路。 你可以至我們[二層網路頁面](/layer-2/)的「移至二層網路」獲取更多資訊。 +你或許可以從交易所直接提取資產到二層網路。 請查看我們 [Layer 2 頁面](/layer-2/) 的「移至 Layer 2」部分以獲取更多資訊。 ### 我能夠在我的代幣橋接到二層網路之後回到以太坊主網嗎? diff --git a/public/content/translations/zh-tw/guides/how-to-use-a-wallet/index.md b/public/content/translations/zh-tw/guides/how-to-use-a-wallet/index.md index c3886ef24c5..7f466f6ec54 100644 --- a/public/content/translations/zh-tw/guides/how-to-use-a-wallet/index.md +++ b/public/content/translations/zh-tw/guides/how-to-use-a-wallet/index.md @@ -1,13 +1,13 @@ --- -title: 如何使用錢包 -metaTitle: 如何使用以太坊錢包 | 逐步教學 -description: 關於如何發送、接收代幣和連接到 web3 專案的指南。 +title: "如何使用錢包" +metaTitle: "如何使用以太坊錢包 | 逐步教學" +description: "關於如何發送、接收代幣和連接到 web3 專案的指南。" lang: zh-tw --- # 如何使用錢包 -學習如何使用錢包的所有基本功能。 如果你還沒有錢包,請查看[如何建立以太坊帳戶](/guides/how-to-create-an-ethereum-account/)。 +學習如何使用錢包的所有基本功能。 如果您還沒有帳戶,請參閱我們的[如何建立以太坊帳戶](/guides/how-to-create-an-ethereum-account/)。 ## 打開你的錢包 @@ -39,8 +39,7 @@ lang: zh-tw 3. 輸入接收者的地址或使用你的相機掃描二維碼,這樣就不需手動輸入地址。 4. 點擊錢包中的「發送」按鈕(或顯示類似描述的按鈕)。 -![加密貨幣地址的發送欄位](./send.png) -
+![傳送欄位供加密貨幣地址使用](./send.png)
5. 許多資產,如 DAI 或 USDC,存在於多種網路上。 轉移加密代幣時,請確認接收者和你在相同網路上,因為不同網路上的代幣不可互換。 6. 確保你的錢包中有足夠的以太幣可支付交易費,交易費依網路狀態而異。 大部分錢包會將建議的交易費自動加到交易中,你可以直接確認。 @@ -54,19 +53,19 @@ lang: zh-tw 2. 如果專案的登陸頁面只是描述該專案的靜態網頁,你應可點擊選單中的「開啟應用程式」按鈕,這麼做會將你導引至實際的應用程式頁面。 3. 進入應用程式後,按一下「連接」。 -![讓使用者透過錢包連接到網站的按鈕](./connect1.png) +![允許使用者用錢包連線至網站的按鈕](./connect1.png) 4. 從提供的錢包列表中選擇你使用的錢包。 如果找不到你所用的錢包,它可能隱藏在「WalletConnect」選項下。 -![從錢包列表中選擇要連接的錢包](./connect2.png) +![從錢包清單中選取要連線的錢包](./connect2.png) -5. 在你的錢包中確認並簽名以建立連接。 **簽署此訊息應不會花費任何以太幣**。 -6. 大功告成! 開始使用應用程式。 你可在我們的[去中心化應用程式頁面](/apps/#explore)找到許多有趣的專案。
+5. 在你的錢包中確認並簽名以建立連接。 **簽署此訊息時,不應花費任何 ETH**。 +6. 大功告成! 開始使用應用程式。 您可以在我們的[去中心化應用程式頁面](/apps/#explore)上找到一些有趣的專案。
-
想要學習更多功能嗎?
+
想瞭解更多嗎?
查看我們的其他指南 @@ -77,7 +76,7 @@ lang: zh-tw ### 如果我有一個以太幣地址,我在其他區塊鏈上也擁有同一個地址嗎? -你可以在所有兼容以太坊虛擬機的區塊鏈上使用相同的地址(如果你的錢包帶有助記詞)。 此[列表](https://chainlist.org/)將展示出同一地址所適用的區塊鏈。 比特幣等某些區塊鏈,實作了一整套獨立的網路規則,你將需要一個不同格式的不同地址。 如果你有智慧型合約錢包,應查看其產品網站,以深入了解哪些區塊鏈受支援。 +你可以在所有兼容以太坊虛擬機的區塊鏈上使用相同的地址(如果你的錢包帶有助記詞)。 此[清單](https://chainlist.org/)會顯示您可以用相同地址使用哪些區塊鏈。 比特幣等某些區塊鏈,實作了一整套獨立的網路規則,你將需要一個不同格式的不同地址。 如果你有智慧型合約錢包,應查看其產品網站,以深入了解哪些區塊鏈受支援。 ### 我可以在多台設備上使用相同的地址嗎? @@ -85,7 +84,7 @@ lang: zh-tw ### 我還沒有收到加密貨幣,我可以在哪裡查看交易狀態? -你可以使用[區塊鏈瀏覽器](/developers/docs/data-and-analytics/block-explorers/)即時查看交易狀態。 你只需要搜尋你的錢包地址或交易 ID。 +您可以使用[區塊瀏覽器](/developers/docs/data-and-analytics/block-explorers/)來即時查看任何交易的狀態。 你只需要搜尋你的錢包地址或交易 ID。 ### 我能否取消交易或退款? diff --git a/public/content/translations/zh-tw/guides/index.md b/public/content/translations/zh-tw/guides/index.md index 61f5104a44e..fcaec100696 100644 --- a/public/content/translations/zh-tw/guides/index.md +++ b/public/content/translations/zh-tw/guides/index.md @@ -1,6 +1,6 @@ --- -title: 以太坊指南 -description: 一組實用指南,向初學者解釋有關使用以太坊的基礎知識。 +title: "以太坊指南" +description: "一組實用指南,向初學者解釋有關使用以太坊的基礎知識。" lang: zh-tw --- @@ -12,16 +12,16 @@ lang: zh-tw 1. [如何「創建」以太坊帳戶](/guides/how-to-create-an-ethereum-account/) - 任何人都可以免費創建一個錢包。 本指南會引導你從哪裡開始。 -2. [如何使用錢包](/guides/how-to-use-a-wallet/) - 學習如何在你的錢包中發送、接收代幣,以及將錢包連接到專案。 +2. [如何使用錢包](/guides/how-to-use-a-wallet/) - 學習如何在您的錢包中發送和接收代幣,以及如何將錢包連接至專案。 ## 安全基礎知識 -1. [如何撤銷對加密資金的智慧型合約的存取權限](/guides/how-to-revoke-token-access/) - 如果你突然發現錢包裡有一筆不是由你發起的交易,本指南將教你如何防止該情況再次發生。 +1. [如何撤銷智慧型合約對您加密貨幣資金的存取權限](/guides/how-to-revoke-token-access/) - 如果您突然在錢包中看到一筆非您發起的交易,本指南將教您如何防止這種情況再次發生。 -2. [如何識別詐騙代幣](/guides/how-to-id-scam-tokens/) - 什麼是詐騙代幣?詐騙代幣如何使自身看起來像合法代幣?如何識別詐騙代幣並保護自己不掉入詐騙代幣的騙局。 +2. [如何辨識詐騙代幣](/guides/how-to-id-scam-tokens/) - 什麼是詐騙代幣? 它們如何讓自己看起來合法,您又能如何辨識它們,以保護自己不受詐騙? ## 使用以太坊 -1. [如何橋接代幣到二層網路?](/guides/how-to-use-a-bridge/) - 以太坊交易是否太過昂貴? 可以考慮轉而使用以太坊擴容方案,即二層網路。 +1. [如何將代幣橋接到 Layer 2](/guides/how-to-use-a-bridge/) - 以太坊交易費用是否太高? 可以考慮轉而使用以太坊擴容方案,即二層網路。 -2. [如何兌換代幣](/guides/how-to-swap-tokens/) - 你想要兌換為其他代幣嗎? 本簡潔指南將為你演示如何操作。 +2. [如何兌換代幣](/guides/how-to-swap-tokens/) - 您想將您的代幣兌換成另一種嗎? 本簡潔指南將為你演示如何操作。 diff --git a/public/content/translations/zh-tw/nft/index.md b/public/content/translations/zh-tw/nft/index.md index bd5e2ff028a..ac7c9ee94e7 100644 --- a/public/content/translations/zh-tw/nft/index.md +++ b/public/content/translations/zh-tw/nft/index.md @@ -1,44 +1,44 @@ --- -title: 非同質化代幣 (NFT) -metaTitle: 什麼是非同質化代幣? | 優點和作用 -description: 以太坊生態系非同質化代幣概要 +title: "非同質化代幣 (NFT)" +metaTitle: "什麼是非同質化代幣? | 優點和作用" +description: "以太坊生態系非同質化代幣概要" lang: zh-tw template: use-cases emoji: ":frame_with_picture:" sidebarDepth: 2 image: /images/infrastructure_transparent.png -alt: 全息投影顯示的以太幣標誌。 -summaryPoint1: 一種用以太坊資產來呈現任何獨特事物的方式。 -summaryPoint2: 非同質化代幣賦予了內容創作者前所未有的強大力量。 -summaryPoint3: 由建置於以太坊區塊鏈上的智慧型合約提供支援。 +alt: "全息投影顯示的以太幣標誌。" +summaryPoint1: "一種用以太坊資產來呈現任何獨特事物的方式。" +summaryPoint2: "非同質化代幣賦予了內容創作者前所未有的強大力量。" +summaryPoint3: "由建置於以太坊區塊鏈上的智慧型合約提供支援。" --- ## 什麼是非同質化代幣? {#what-are-nfts} -非同質化代幣是一種**獨一無二**的代幣。每個非同質化代幣都有不同的屬性(非同質性),它們的稀缺性是可以驗證的。 非同質化代幣與[以太幣](/glossary/#ether)和其他基於以太坊的代幣(例如 USDC)不同,後者的每一個代幣都一樣的,具有相同的特性(「同質化」)。 你不會在乎你錢包內的其中一張鈔票(以太幣),因為它們都一樣且價值相同。 但你_確實會_在意你自己持有的特定非同質化代幣,因為它們不同於其他的資產,全都有各自的屬性(非同質化)。 +NFT 是指**各自獨一無二**的代幣。 每個非同質化代幣都有不同的屬性(非同質性),它們的稀缺性是可以驗證的。 這與 [ETH](/glossary/#ether) 或其他基於以太坊的代幣 (如 USDC) 不同,後者的每個代幣都完全相同,並具有相同的特性 (「同質化」)。 你不會在乎你錢包內的其中一張鈔票(以太幣),因為它們都一樣且價值相同。 不過,您_確實_會在意自己擁有哪個特定的 NFT,因為它們都有各自的屬性,可藉此與其他 NFT 區分 (即「非同質化」)。 -每個非同質化代幣的獨特性使藝術品、收藏品,甚至房地產等等事物能夠代幣化,即一個特定的唯一非同質化代幣對應到現實世界的一些特定且獨一無二的物品或數位物品。 資產的所有權在以太坊[區塊鏈](/glossary/#blockchain)上被公開驗證。 +每個非同質化代幣的獨特性使藝術品、收藏品,甚至房地產等等事物能夠代幣化,即一個特定的唯一非同質化代幣對應到現實世界的一些特定且獨一無二的物品或數位物品。 資產的所有權可以在以太坊[區塊鏈](/glossary/#blockchain)上公開驗證。 -## 資產網路 {#internet-of-assets} +## 資產網際網路 {#internet-of-assets} -非同質化代幣和以太坊解決了網際網路上現存的某些問題。 隨著一切變得越來越數位化,有需求以不受中心組織控制的方式來複製實體物品的屬性,例如稀缺性、唯一性和所有權證明。 舉例來說,透過非同質化代幣,你可以在所有基於以太坊的應用程式上擁有某個音樂 mp3 檔 的所有權,不必綁定於單一公司特定的音樂 App 上,如 Spotify 或 Apple Music。 你可以擁有可出售或交換的社交媒體帳號,且該帳號**無法被平臺提供者任意奪走**。 +非同質化代幣和以太坊解決了網際網路上現存的某些問題。 隨著一切變得越來越數位化,有需求以不受中心組織控制的方式來複製實體物品的屬性,例如稀缺性、唯一性和所有權證明。 舉例來說,透過非同質化代幣,你可以在所有基於以太坊的應用程式上擁有某個音樂 mp3 檔 的所有權,不必綁定於單一公司特定的音樂 App 上,如 Spotify 或 Apple Music。 您可以擁有一個可以出售或交換的社交媒體帳號,而且平台供應商**無法任意將它從您手中奪走**。 相較於我們大多數人今天使用的網際網路,非同質化代幣網際網路的特色如下... ### 比較 {#nft-comparison} -| 非同質化代幣網際網路 | 目前的網際網路 | -| --------------------------------------------------------------------------------- | -------------------------------------------------- | -| **你擁有自己的資產!**只有你才可以出售或交換這些資產。 | **你向某些組織借用資產時**,這些資產可能被奪走。 | -| 非同質化代幣具有**數位獨特性**,每個非同質化代幣皆獨一無二。 | **往往無法區分複製品和正品**。 | -| 非同質化代幣的所有權儲存在區塊鏈上,任何人都可**公開驗證**該所有權。 | 數位物品的所有權紀錄儲存在**由機構控制**的伺服器上,必須在機構同意後才能獲取所有權紀錄。 | -| 非同質化代幣是以太坊上的[智能合約](/glossary/#smart-contract)。 這表示它們**可以直接在以太坊上的其他智能合約**和應用程式上使用! | 擁有數位物品的公司通常**需要自己的「封閉平台 (walled garden)」基礎架構**。 | -| 內容**創作者可以在任何地點出售自己的作品**,還能打入全球市場。 | 創作者依賴其使用的平台所提供的基礎架構和發佈通路。 這些通常會受到使用條款和**地理限制**的約束。 | -| 非同質化代幣創作者**可保有對自己作品的所有權**,並將版稅直接寫入非同質化代幣的智能合約。 | **音樂串流服務等平台分到大部分的銷售利潤**。 | +| 非同質化代幣網際網路 | 目前的網際網路 | +| ---------------------------------------------------------------------------------- | ------------------------------------------------- | +| \*\*您擁有自己的資產!\*\*只有您可以出售或交換它們。 | **您向某個組織租借資產**,而資產隨時可能被收回。 | +| NFT 具有**數位獨特性**,沒有兩個 NFT 是相同的。 | 複製品通常無法與原作區別。 | +| NFT 的所有權儲存在區塊鏈上,任何人都可以**公開驗證**。 | 數位項目的所有權記錄存取權**由機構控制**——您只能選擇相信他們。 | +| NFT 是以太坊上的[智慧型合約](/glossary/#smart-contract)。 這表示它們**可以輕易地在以太坊上的其他智慧型合約**和應用程式中使用! | 擁有數位項目的公司通常**需要自己的「圍牆花園」基礎架構**。 | +| 內容**創作者可以在任何地方銷售他們的作品**,並且可以進入全球市場。 | 創作者依賴其使用的平台所提供的基礎架構和發佈通路。 這些通常受到使用條款和**地理限制**的約束。 | +| NFT 創作者**可以保留自己作品的所有權**,並將權利金直接編寫進 NFT 合約。 | 音樂**串流服務等平台,保留了大部分的銷售利潤**。 | -## 非同質化代幣有哪些用途? {#nft-use-cases} +## 非同質化代幣有哪些用途? NFT 應用案例 {#nft-use-cases} 非同質化代幣有許多用途,包括: @@ -51,63 +51,64 @@ summaryPoint3: 由建置於以太坊區塊鏈上的智慧型合約提供支援 - 限制內容存取 - 票務 - 去中心化的網際網路網域名稱 -- [去中心化金融](/glossary/#defi)的抵押品 +- 在[去中心化金融](/glossary/#defi)中的抵押品 -或許你是位藝術家,想透過非同質化代幣分享你的作品,同時不失去對藝術品的控制權,並且不會因中介而損失收益。 你可以建立一份新合約,並明訂非同質化代幣的數量、屬性,以及連到某些特定藝術品的連結。 作為藝術家,**你可以將您應得的版稅寫入智能合約**(如:每當非同質化代幣被轉移時,支付銷售價格的 5% 給合約擁有者)。 你可以隨時證明該非同質化代幣由您建立,因為您擁有部署該合約的[錢包](/glossary/#wallet)。 你的買家可輕易證明他們擁有賣家收藏品的**正版非同質化代幣**,因為他們的錢包[地址](/glossary/#address)與賣家智能合約中的代幣相關聯。 他們可以在以太坊生態系統中使用非同質化代幣,並可信任代幣的真實性。 +或許你是位藝術家,想透過非同質化代幣分享你的作品,同時不失去對藝術品的控制權,並且不會因中介而損失收益。 你可以建立一份新合約,並明訂非同質化代幣的數量、屬性,以及連到某些特定藝術品的連結。 作為藝術家,**您可以將您應得的權利金編寫進智慧型合約** (例如,每當 NFT 轉移時,將售價的 5% 轉給合約所有者)。 您也隨時可以證明是您建立了這些 NFT,因為您擁有部署該合約的[錢包](/glossary/#wallet)。 您的買家可以輕易地證明他們擁有您收藏中的**正版 NFT**,因為他們的錢包[地址](/glossary/#address)與您智慧型合約中的代幣相關聯。 他們可以在以太坊生態系統中使用非同質化代幣,並可信任代幣的真實性。
探索、購買或建立你個人的非同質化代幣藝術品/收藏品……
- 探索非同質化代幣藝術品 + 探索 NFT 藝術
-又或者以體育賽事的門票為例, 如同**賽事主辦者可以決定要販售幾張門票**,非同質化代幣的創作者也可以決定要發行幾份複製品。 有時可能是完全相同的複製品,例如 5000 張普通門票; 有時可能會製作好幾種極為類似,但各自略有不同的複製品,例如指定席的票券。 此類票券可以在不需要給票務員付款的情況下進行點對點買賣,買家可以隨時檢查合約地址,以確保票券的真實性。 +又或者以體育賽事的門票為例, 正如**活動主辦方可以選擇要賣出多少張票**一樣,NFT 的創作者也可以決定存在多少個複製品。 有時可能是完全相同的複製品,例如 5000 張普通門票; 有時可能會製作好幾種極為類似,但各自略有不同的複製品,例如指定席的票券。 此類票券可以在不需要給票務員付款的情況下進行點對點買賣,買家可以隨時檢查合約地址,以確保票券的真實性。 -在 ethereum.org 上,**非同質化代幣被用來證明大家對我們的 Github 儲存庫做出了有意義的貢獻**(對網站進行編程、撰寫或修改文章等等)、翻譯我們的文字内容,或參加了我們的社群電話會議,以及我們甚至擁有專屬的非同質化代幣域名。 如果你對 ethereum.org 有貢獻,你可以領取[出席證明協定 (POAP)](/glossary/#poap) 非同質化代幣。 某些加密貨幣聚會使用 POAP 作為入場門票。 [深入了解如何貢獻](/contributing/#poap)。 +在 ethereum.org,**NFT 被用來證明人們對我們的 GitHub 儲存庫做出了有意義的貢獻** (為網站編寫程式、撰寫或修改文章…)、翻譯我們的內容,或參加我們的社群通話,我們甚至還有自己的 NFT 域名。 如果您對 ethereum.org 做出貢獻,您可以領取一個 [POAP](/glossary/#poap) NFT。 某些加密貨幣聚會使用 POAP 作為入場門票。 [關於貢獻的更多資訊](/contributing/#poap)。 -![ethereum.org POAP](./poap.png) +![ethereum.org 出席證明協定](./poap.png) -此網站也有一個由非同質化代幣提供支援的替代網域名稱:**ethereum.eth**。 我們的 `.org` 位址是由網域名稱系統 (DNS) 供應商集中管理,而 ethereum`.eth` 則是透過以太坊名稱服務 (ENS) 於以太坊註冊, 為我們所有,且由我們管理。 [查看我們的以太坊名稱服務記錄](https://app.ens.domains/name/ethereum.eth) +本網站還有一個由 NFT 支援的替代域名:**ethereum.eth**。 我們的 `.org` 位址由網域名稱系統 (DNS) 供應商集中管理,而 `ethereum.eth` 則是透過以太坊名稱服務 (ENS) 在以太坊上註冊的。 為我們所有,且由我們管理。 [查看我們的 ENS 記錄](https://app.ens.domains/name/ethereum.eth) -[更多以太坊名稱服務相關資訊](https://app.ens.domains) +[更多關於 ENS 的資訊](https://app.ens.domains) ## 非同質化代幣如何運作? {#how-nfts-work} -非同質化代幣 (NFT) 就如同以太坊區塊鏈上的任何數位物品一樣,是透過一種基於以太坊、被稱為「智慧型合約」的特別電腦程式所建立的。 這些合約會遵循特定的規則,如 [ERC-721](/glossary/#erc-721) 或 [ERC-1155](/glossary/#erc-1155) 標準,這些規則決定了合約的用途。 +非同質化代幣 (NFT) 就如同以太坊區塊鏈上的任何數位物品一樣,是透過一種基於以太坊、被稱為「智慧型合約」的特別電腦程式所建立的。 這些合約遵循特定的規則,例如 [ERC-721](/glossary/#erc-721) 或 [ERC-1155](/glossary/#erc-1155) 標準,這些標準決定了合約能做什麼。 非同質化代幣智慧型合約的一些關鍵用途: -- **建立非同質化代幣:**能製造新的非同質化代幣。 -- **分配所有權:**透過將非同質化代幣連結到特定的以太坊地址來追蹤其擁有者。 -- **為每一個非同質化代幣分配一個 ID:**每一個非同質化代幣都擁有一個獨一無二的編號。 此外,通常還會附加一些額外信息(元數據),描述該非同質化代幣所代表的含義。 +- 建立 NFT:它可以製作新的 NFT。 +- 指派所有權:它透過將 NFT 連結到特定的以太坊地址來追蹤誰擁有哪個 NFT。 +- 為每個 NFT 提供 ID:每個 NFT 都有一個使其獨一無二的編號。 此外,通常還會附加一些額外信息(元數據),描述該非同質化代幣所代表的含義。 當人們「建立」或「鑄造」非同質化代幣時,他們主要是在告訴智慧型合約將特定非同質化代幣的所有權賦予他們。 該資訊被安全和公開地儲存在區塊鏈中。 此外,合約創作者可以添加額外的規則。 可以限制某種非同質化代幣的製造數量或者決定每當非同質化代幣易手時都應獲得一小筆版稅。 -### 非同質化代幣的安全性 {#nft-security} +### NFT 安全性 {#nft-security} -以太坊的安全性來自[權益證明](/glossary/#pos)。 以太坊從經濟性的角度抑制惡意行為,這讓以太坊得以防竄改。 這也讓非同質化代幣得以成真。 一旦包含你的非同質化代幣交易的[區塊](/glossary/#block)[最終化](/glossary/#finality),攻擊者要對其作出變更,就得花費數百萬以太幣。 任何運行以太坊軟體的人皆能立即偵測到對非同質化代幣進行的欺詐性篡改,且惡意行為者也會遭到經濟處罰及驅逐。 +以太坊的安全性來自[權益證明](/glossary/#pos)。 以太坊從經濟性的角度抑制惡意行為,這讓以太坊得以防竄改。 這也讓非同質化代幣得以成真。 一旦包含您的 NFT 交易的[區塊](/glossary/#block)被[最終確認](/glossary/#finality),攻擊者若要更改它將需花費數百萬個 ETH。 任何運行以太坊軟體的人皆能立即偵測到對非同質化代幣進行的欺詐性篡改,且惡意行為者也會遭到經濟處罰及驅逐。 與非同質化代幣有關的安全問題最常與釣魚詐騙、智慧型合約漏洞或使用者錯誤(如無意間洩漏私密金鑰)有關,所以良好的錢包安全性對非同質化代幣持有者十分重要。 - 更多安全相關資訊 + 更多關於安全性的資訊 -## 了解更多 {#further-reading} +## 延伸閱讀 {#further-reading} -- [非同質化代幣入門指南](https://linda.mirror.xyz/df649d61efb92c910464a4e74ae213c4cab150b9cbcc4b7fb6090fc77881a95d) – _Linda Xie,2020 年 1 月_ -- [Etherscan 的非同質化代幣追蹤器](https://etherscan.io/nft-top-contracts) +- [NFT 新手指南](https://linda.mirror.xyz/df649d61efb92c910464a4e74ae213c4cab150b9cbcc4b7fb6090fc77881a95d) – _Linda Xie,2020 年 1 月_ +- [Etherscan NFT 追蹤器](https://etherscan.io/nft-top-contracts) +- [Blockscout NFT 追蹤器](https://eth.blockscout.com/tokens?type=ERC-721,ERC-1155,ERC-404) - [ERC-721 代幣標準](/developers/docs/standards/tokens/erc-721/) - [ERC-1155 代幣標準](/developers/docs/standards/tokens/erc-1155/) -- [熱門非同質化代幣應用程式和工具](https://www.ethereum-ecosystem.com/blockchains/ethereum/nfts) +- [熱門的 NFT 應用程式和工具](https://www.ethereum-ecosystem.com/blockchains/ethereum/nfts) ## 其他資源 {#other-resources} diff --git a/public/content/translations/zh-tw/payments/index.md b/public/content/translations/zh-tw/payments/index.md new file mode 100644 index 00000000000..f0d0f1f8c7a --- /dev/null +++ b/public/content/translations/zh-tw/payments/index.md @@ -0,0 +1,207 @@ +--- +title: "以太坊支付" +metaTitle: "以太坊支付" +description: "以太坊支付概要" +lang: zh-tw +template: use-cases +emoji: ":frame_with_picture:" +sidebarDepth: 2 +image: /images/impact_transparent.png +alt: "以太坊標誌與給予的手一同展示。" +summaryPoint1: "一個金錢如資訊般自由流通的世界" +summaryPoint2: "開放且全球化,讓所有人實現無國界交易" +summaryPoint3: "一分鐘內收到款項" +--- + +數百萬人每天面臨同樣的挑戰:跨境轉賬緩慢、昂貴,且經常遇到阻礙。 在峇里島的自由業者需等待多天才能收到紐約客戶的款項。 這由其影響銀行基礎設施有線區域的人們,使他們難以參與國際經濟。 + +這不是一個遙遠的夢——現今已在以太坊上實現。 雖然傳統金融機構在過去幾十年來建造了可靠的支付系統,他們經常受限於國界、工作時間,和所遺留的基礎設施。 以太坊提供一個新的範例:一個全球化、一週七天、每天24小時運作的金融平台,為有網路服務的任何人提供幾乎即時、可程式化的交易。 + +
+ +![電腦螢幕上的以太坊標誌](./computer.png) +
+ +## 匯款:更便宜的國際轉帳 {#remittances} + +對於數百萬在國外工作的人們來說,匯款回家是一種經常性需求。 傳統匯款服務通常費用昂貴,且處理時間緩慢。 以太坊提供一個更優秀的替代方案。 + + + + + + + +## 獲取全球貨幣 {#access-to-global-currencies} + +在許多國家,通貨膨脹是一個緊迫的問題,通常伴隨人們難以獲取外幣的問題。 在這些情況下的人們因為被迫持有快速貶值的儲蓄,難以保存財富。 + +以太坊社群創建了**一個強健的替代性金融系統**,不受限於任何國家的貨幣政策或控制。 + +以太坊使用者可以使用**穩定幣—通常與美元等強勢貨幣掛鉤的代幣**。 通過賺取和儲蓄加密貨幣,人們可以在其國內保護他們免受通貨膨脹之苦,幫助他們維持、甚至提高購買力。 這也使本地和全球的商品和服務支付變得更加容易。 + + +深入了解穩定幣 + + +## 購買商品與服務付款 {#buying-goods-and-payment-for-services} + +許多的企業開始接受以太幣(ETH)和其他加密貨幣的付款。 例如: + +- Newegg:這家受歡迎的電子產品零售商在部分國家接受以太幣付款。 +- **Travala.com:** 這家旅行預訂平台允許使用者使用以太幣支付飯店和機票。 +- **Shopify:** 此受歡迎的電子商務平台作為託管企業的平台,也接受以以太坊支付商品和服務。 +- 蘇富比:此機構交易精美和裝飾藝術品、珠寶和收藏品,並允許使用以太坊和其他加密貨幣付款。 + +像是薩爾瓦多和中非共和國等國家已經採用加密貨幣作為法定貨幣,為日常交易中更廣泛地接受以太坊支付開拓道路。 + +在那些支付方式與全球其他地方脫節的國家,加密貨幣整合支付解決方案已經帶來巨大的紓解。 通過如Gnosis Pay 和 Paypal 等加密貨幣支付平台,可以輕鬆支付 Netflix、Spotify,和教育課程等平台的訂閱費用。 + + + + +
使用一個錢包應用程式創建您的以太坊帳號。
+ +開始吧 + +
+ +
+ +## 使用自我保管加密貨幣卡付款 {#pay-with-self-custodial-crypto-cards} + +自我保管加密貨幣卡的運作方式,就像是使用自己的背包,而不是將錢鎖在別人的保險庫裡。 使用傳統卡片時,銀行或託管機構會持有您的資金,並在您消費時撥款。 使用自我保管卡,您可以始終掌控自己的資產——沒有中間人——同時仍然能夠感應或刷卡支付咖啡、雜貨,甚至是機票費用。 + +這些卡片直接連結到非託管錢包或智能合約帳戶,讓使用者在日常場景中花費 ETH 和穩定幣,而無需放棄所有權。 託管卡要求使用者將資金存入第三方,但自我保管卡與之不同,它能在保留鏈上控制權的同時,實現如 Visa 和 Mastercard 等現實世界的支付。 + +### 範例 {#crypto-cards-examples} + +- MetaMask Card:這張 Mastercard 簽帳金融卡連結至 MetaMask 錢包,可讓使用者花費 ETH、穩定幣及其他支援的代幣。 它支援 Apple Pay 和 Google Pay,包含加密貨幣現金回饋獎勵,並提供收益賺取選項。 + +- Tuyo Card:一張基於智能合約的 Visa 卡,可自動將加密貨幣轉換為 USDC,在任何接受 Visa 的地方消費。 使用者可保有資產的保管權,並可使用收益、交易和消費功能。 + +- Gnosis Pay:第一張與 Gnosis Safe 智能帳戶綁定的自我保管 Visa 卡。 使用者可直接從錢包中花費加密貨幣,無需支付 Gas、外匯或出金費用。 也支援透過 Ethereum 名稱服務 (ENS) 進行卡片個人化。 + +- Ether.Fi 現金卡:此卡與 ether.fi 的質押協議整合,讓使用者在消費的同時,其 ETH 仍保持質押狀態。 付款透過智能合約處理,即使在消費時也能維持自我保管。 + +### 自我保管加密貨幣卡比較 {#crypto-card-custody-comparison} + +| **加密貨幣卡** | **自我保管** | **無監管** | **重點** | +| ---------------------------- | :------: | :-----: | ------------------------------- | +| MetaMask 卡 | ✅ | ✅ | 錢包保留在 MetaMask 中;付款時自動出金 | +| Tuyo 卡 | ✅ | ✅ | 智能錢包會轉換為 USDC;使用者保留控制權 | +| Gnosis Pay | ✅ | ✅ | 連結至使用者的 Gnosis Safe;使用期間保管權不會轉移 | +| Ether.Fi 現金卡 | ✅ | ✅ | ETH 保持質押狀態;智能合約控制消費權限。 | + +> **注意:**"自我保管" 是指使用者控制的錢包,使用者對其資金擁有完全的存取和控制權。 +> "非託管" 是指資金在沒有第三方託管的情況下進行管理的錢包,通常是透過智能合約來實現。 +> 雖然所有自我保管卡都是非託管卡,但並非所有非託管卡都是自我保管卡。 + +## 適用於網站和代理程式的小額支付 (x402) {#x402} + +[x402](https://www.x402.org/) 是一種開放式支付標準,為網路帶來了原生的按次使用付費功能。 透過在低成本的[以太坊 Layer 2 網路](/layer-2/)上使用[穩定幣](/stablecoins/),x402 標準讓人們和機器能經濟實惠地為單一操作直接付費,例如閱讀一篇新聞文章或呼叫一個應用程式介面(API),而無需管理 API 金鑰、訂閱,或透過觀看廣告來"付費"。 + +- 移除付費牆和登入:您不再需要為了閱讀一篇新聞文章而建立帳戶和分享個人資訊,您的錢包可以直接支付幾分錢來解鎖文章。 +- \*\*為 AI 代理程式付款:\*\*x402 使自主軟體("AI 代理程式")能夠在無人為干預的情況下,為其運作所需的資料和應用程式介面(API)呼叫付費。 + +### x402 支付標準的運作方式 {#x402-how} + +當用戶端請求資源時,伺服器會傳回 `402 Payment Required` 錯誤碼以及付款說明(價格、帳戶,以及支援的代幣和鏈)。 + +- 您的[錢包](/wallets/)會偵測到該請求並處理付款(通常只需點擊一次即可核准,或使用預先核准的額度自動付款) +- 擁有預先核准錢包餘額的 [AI 代理程式](/ai-agents/)可以自動偵測價格並立即付款,以存取資料或服務 +- 用戶端需要在錢包中擁有其中一種支援的穩定幣,但不需要任何 ETH 來支付 [Gas 費用](/gas/) + +這開啟了一個新的"機器對機器"經濟,AI 代理程式可以自行購買資源,應用程式介面(API)服務也可以更有效率地被存取。 + +簽署後的訊息接著會傳送到伺服器。 伺服器通常使用 [x402 促進器](https://x402.gitbook.io/x402/core-concepts/facilitator)來處理區塊鏈的複雜性(傳送交易、獲取付款、促進 Gas 費用等),這表示開發者可以輕鬆接受加密貨幣小額支付,而無需管理支付基礎設施。 + +## 薪資支付 {#salary-payments} + +許多有遠見的公司現在為員工提供以以太幣(ETH)等加密貨幣收取薪水或部分薪水的選項: + +- Gipsybee:是一個從事電子、機器人、遊戲創作等服務的組織。 他們為員工提供了以以太坊支付薪水的選項。 +- SC5:這家芬蘭公司是最早提供以比特幣支付薪水的公司,為以以太坊的支付安排開拓道路。 +- 區塊鏈新創公司:許多區塊鏈領域的公司自然地提供員工以加密貨幣支付薪水的選項。 +- 去中心化自治組織:由於去中心化自治組織貢獻者的特殊性和多樣性,大部分的貢獻和薪水以加密貨幣作為獎勵。 + +此趨勢尤其吸引遠端工作者和數位遊民,可以受益於無國界支付和潛在的有利匯率。 + +## 全球救援工作 {#global-relief-efforts} + +2023年2月,當毀滅性的地震摧毀土耳其和敘利亞,全球加密貨幣社群迅速採取行動。 人們發起了各種募款活動來籌集救災資金,並展現了以太坊在危機時期的力量。 雖然加密貨幣在土耳其是 [不被認可](https://www.reuters.com/technology/no-more-kebabs-bitcoins-turkeys-crypto-payment-ban-looms-2021-04-28/)的支付方式,當局還是對一些組織[賦予豁免權](https://x.com/haluklevent/status/1622913175409623041),以收集捐款。 案例有: + +- [Refik Anadol](https://x.com/refikanadol/status/1622623521104089090):是一個著名的數位藝術家,他發起了一項募款活動。 +- 去中心化自治組織的力量:[Anka Relief DAO](https://ankarelief.org/) 和 [Bankless DAO](https://x.com/banklessDAO) 聯手 [Giveth](https://x.com/Giveth/status/1623493672149843969)來籌集募款。 +- [Pak](https://cause.quest/),一位著名的非同質化代幣藝術家,也做出了貢獻。 +- 甚至,以太坊的共同創辦人[Vitalik Buterin](https://cointelegraph.com/news/vitalik-buterin-donates-227k-to-help-earthquake-victims-in-turkey-syria) 也對多個募資活動進行個人捐款。 + +結果如何呢? 根據 [Dune](https://dune.com/davy42/turkiye-earthquake-donations) 分析面板,短短幾天內便籌集了超越六百萬美金的資金。 + +同樣, 印度和烏克蘭發生災難時, 以太坊社區也做出了快速的響應。 此快速的響應顯示了以太坊支付的關鍵優勢——沒有貨幣轉換、漫長銀行轉帳,或高額費用的障礙下,迅速動員全球支持的能力。 + +
+ +![以太坊機器人圖像](./eth_robot.png) +
+ +## 以太坊 vs 法幣 {#ethereum-vs-fiat} + +要想真正理解以太坊支付的影響,就要將其與傳統法幣進行比較: + +| | **以太坊** | **傳統銀行** | +| ---------- | --------------------- | -------------- | +| **速度** | 幾秒鐘到幾分鐘 | 幾小時到幾天 | +| **全球覆蓋** | 無國界,一週七天、一天24小時,全年無假日 | 受國際銀行制約和工作時間限制 | +| **透明度** | 完全透明 | 因機構而異 | +| 可程式化 | 使用智能合約 | 僅限於基本交易 | +| **通貨膨脹控制** | 可預測發行量 | 受中央銀行政策影響 | +| **易得性** | 有網路的人皆可 | 受國內和國際限制 | + +本質上來說,以太坊是個去中心化的平台,支持安全、快速,和透明的交易。 然而,許多部分使其有別於傳統支付方式。 讓我們來深入了解以太坊支付帶來的變革和優勢: + +### 可程式化 {#programmability} + +其中一個以太坊的特殊之處是其能夠支援智能合約。 智能合約是將條款直接寫入程式碼的自動執行協議。 這為自動化、基於條件的支付開闢了無限可能,可以大幅地改善交易,例如: + +- 代管服務 +- 定期支付 +- 基於效能的獎勵 + +### 速度 {#speed} + +您還記得上次未完成國際銀行轉帳等待數日的經驗嗎? 排隊久候? 以及一堆需要填寫的表格? 因為以太坊,這些日子已經成為過去式了。 不管發送方和收款方身在何處,以太坊網路上的交易數分鐘內就可以完成。 因為以太坊是無需許可的,發送款項時沒有監管方的繁文縟節。 這速度在時間緊迫的狀況下尤為重要,像是緊急救援工作。 + +### 更低的費用 {#lower-fees} + +傳統國際匯款費用有時佔發送金額很大一部分,尤其在處理數百美元的交易時。 以太坊的交易雖不是免費,通常費用較為低廉。 這代表更多的您的款項能夠按預期流向目的地,而非進到中間機構的口袋裡。 + +### 透明度 {#transparency} + +在以太坊區塊鏈上的每筆交易都記錄在公開帳本上。 這代表所有人都可以驗證資金的流動,讓其成為以下案例的絕佳工具: + +- 慈善機構展示捐款是如何被利用的 +- 企業向供應商和員工提供支付證明 +- 個人追蹤自己的資金活動 + +在以太坊上,每個人都能看到資金的流向和成本的執行方式,這與傳統組織不同,在傳統組織中,這些資訊大多是不透明的。 + +
+ +![走路圖像](./walking.png) +
+ +雖然法幣在廣泛接受度和穩定性方面具有優勢,但以太坊的獨特優勢讓其對於某些交易類型是極具吸引力的選擇。 + +從促進快速災難救援,到賦能全球工人,以太坊支付在金錢的漫長歷史中寫下了新的篇章。 儘管挑戰仍然存在,這項技術提供的獨特優勢吸引愈來愈多廣泛的應用場景。 + + + + +
是時候擁有自己的以太坊帳戶了。
+ + 開始使用! + +
+ +
diff --git a/public/content/translations/zh-tw/prediction-markets/index.md b/public/content/translations/zh-tw/prediction-markets/index.md new file mode 100644 index 00000000000..a0451d0e35c --- /dev/null +++ b/public/content/translations/zh-tw/prediction-markets/index.md @@ -0,0 +1,86 @@ +--- +title: "預測市場" +lang: zh-tw +template: use-cases +image: /images/use-cases/prediction-markets.png +sidebarDepth: 2 +summaryPoint1: "藉由得到財務的激勵產生正確的預測" +summaryPoint2: "高品質預測未來事件" +buttons: + - content: 瞭解更多 + toId: how-prediction-markets-work + - content: 探索 apps + toId: find-a-prediction-market + isSecondary: false +--- + +預測市場利用群眾智慧和財務動機來預測事件。 他們提供多元的高品質資料並在 2024 年的美國大選中被接受。 大選。 + +## 預測市場如何運作 {#how-prediction-markets-work} + +不同於依靠專家意見、有限的市調樣本或歷史資料的傳統預測方法,預測市場借助即時財務誘因和群眾智慧提出關於特定事件 -- 大選、加密貨幣價格、運動競賽結果等任何事件的見解。 + +這允許任何人以財務承諾表達支持一特定的結果。 +通過對現實世界事件進行下注,當新資訊出現時調整價格,具深入見解的意見獲得更高價值權重,也讓精確度得到回報。 + +理論上來說,因為下注者可以通過正確預判獲得利益,預測市場對現實事件結果預測的精確度很高。 基於區塊鏈的預測市場更加令人興奮,因爲幾乎任何人都可以參與預測並獲得穩定幣或加密貨幣獎勵。 + +## 爲什麽這很重要? {#why-does-this-matter} + +與傳統預測不同,基於區塊鏈的預測市場有以下特點: + + + + + + + +即便作為市場的旁觀者,您也可以評估原本無法獲得的有價值數據。 可以這樣想: + +1. 預測與特定事件相關(例如:Beam Chain 是否會在2030 年之前部署?)。 +2. 市場參與者根據他們對結果的信心來買賣份額。 +3. 當更多參與者質押他們的信念,價格隨之調整,反應即時的洞察。 +4. 下注正確的人都可以根據投注金額按比例賺取收益。 +5. 市場觀察者可以使用公開數據,為其研究或討論提供依據。 + +## 尋找預期市場 {#find-a-prediction-market} + +目前市面上已有數個基於以太坊建構的預測市場。 以下為目前最為人所知的預測市場: + + + + + + + +

警惕風險

+

只下注您能夠承受的金額,並注意潛在的上癮行為。

+
+ +
+ +
+ +## 挑戰和風險 {#challenges-and-risks} + +區塊鏈上的預測市場面臨幾個影響其公平性、合法性,和正確性的挑戰。 + +⚠️ **市場操控** – 有錢的玩家可以透過虛假交易扭曲結果。 +💧 **流動性問題** – 低參與率 ([流動性差](https://www.investopedia.com/terms/t/thinmarket.asp)) 會降低市場可靠度。 +🏛 **監管不確定性** – 政府對一些平台施加了限制。 + +為了緩解這些問題,以太坊開發者正在嘗試如 futarchy(預測市場治理)以及去中心化身份驗證等的解決方案。 + +## 預測市場實驗 {#experimenting-with-prediction-markets} + +預測市場正在重塑數位時代的決策方式。 透過利用以太坊,他們提供了 **公平、公開,且有獎勵機制的預測未來的方式。** + +除了經濟效益之外,預測工具還有許多用途。 例如,在 [DevCon 改進提案](https://forum.devcon.org/t/futarchy-decision-markets-for-deciding-next-devcon/5305) (DIP),有人建議 DevCon 的籌辦者可以使用預測市場來預期未來活動的參與率。 + +這可以幫助籌辦者決定,相較於哪個地點最能帶來國際化的參與,哪個地點能達成規模最大的活動。 這樣的好處是,DevCon 的籌辦者可以加速篩選多個簽證政策、機場易達性、當地的生活成本所需的時間,同時也可以了解潛在會議參與者最感興趣的地點。 + +## 延伸閱讀 {#further-reading} + +[從預測市場到資訊金融](https://vitalik.eth.limo/general/2024/11/09/infofinance.html) - Vitalik Buterin +[以太坊的去中心化預測市場開發](https://blockchain.oodles.io/dev-blog/decentralized-prediction-market-development-ethereum/) +[Augur 專案白皮書](https://github.com/AugurProject/whitepaper) \ No newline at end of file diff --git a/public/content/translations/zh-tw/privacy/index.md b/public/content/translations/zh-tw/privacy/index.md new file mode 100644 index 00000000000..6ccf7ed62e4 --- /dev/null +++ b/public/content/translations/zh-tw/privacy/index.md @@ -0,0 +1,97 @@ +--- +title: "以太坊上的隱私" +description: "在以太坊上保護您隱私的工具與技術" +lang: zh-tw +--- + +# 以太坊上的隱私 {#introduction} + +隱私不僅對個人安全至關重要,也是自由的基石,更是[去中心化的關鍵保障](https://vitalik.eth.limo/general/2025/04/14/privacy.html)。 隱私讓人們能夠自由地表達自我、與他人交易,以及組織社群。 但如同所有區塊鏈一樣,以太坊的公開帳本讓保護隱私變得充滿挑戰。 + +以太坊的設計本身就是透明的。 所有鏈上活動對任何查看者都是可見的。 雖然以太坊透過將您的活動連結至[公鑰](/decentralized-identity/#public-key-cryptography)而非現實世界的身分來提供匿名性,但活動模式可能會被分析,從而洩露敏感資訊並識別使用者。 + +將保護隱私的工具建構到以太坊中,可以幫助個人、組織和機構安全地互動,同時限制不必要的資訊暴露。 這使得生態系對於更廣泛的使用案例而言更安全、更實用。 + +## 寫入隱私 {#privacy-of-writes} + +根據預設,在以太坊上寫入的每筆交易都是公開且永久的。 這不僅包括傳送 ETH,還包括註冊 ENS 名稱、收集 POAP,或交易 NFT。 付款、投票或身分驗證等日常行為,可能會將您的資訊洩露給非預期的對象。 有幾種工具和技術可以幫助提高這些行為的隱私性: + +### 混幣協議 (或 "混幣器") {#mixing-protocols} + +混幣器將許多使用者的交易放入一個共享的 "資金池",然後讓使用者稍後提款至一個新地址,藉此打破發送者和接收者之間的連結。 由於存款和提款混雜在一起,觀察者很難將它們連結起來。 + +_範例:[PrivacyPools](https://docs.privacypools.com/)、[Tornado Cash](https://tornado.cash/)_ + +### 隱蔽池 {#shielded-pools} + +隱蔽池與混幣器相似,但它們允許使用者在池內私下持有和轉移資金。 隱蔽池不僅僅是模糊存款和提款之間的連結,它還會維持一個持續的私密狀態,通常使用零知識證明來確保安全。 這使得建立私密轉帳、私密餘額等成為可能。 + +_範例:[Railgun](https://www.railgun.org/)、[Aztec](https://aztec.network/)、Nightfall_ + +### 隱形地址 {#stealth-addresses} + +一個[隱形地址](https://vitalik.eth.limo/general/2023/01/20/stealth.html) 就像給每個發送者一個獨一無二、一次性的私人信 箱,只有您能打開。 每次有人向您發送加密貨幣時,都會發送到一個新地址,所以沒有人能看到所有這些款項都屬於您。 這能讓您的支付歷史保持私密,且更難追蹤。 + +_範例:[UmbraCash](https://app.umbra.cash/faq)、[FluidKey](https://www.fluidkey.com/)_ + +### 其他使用案例 {#other-use-cases} + +其他探索私密寫入的專案包括 [PlasmaFold](https://pse.dev/projects/plasma-fold) (私密支付) 以及像 [MACI](https://pse.dev/projects/maci) 和 [Semaphore](https://pse.dev/projects/semaphore) (私密投票) 這類的系統。 + +這些工具擴展了在以太坊上進行私密寫入的選項,但每種工具都有其權衡之處。 有些方法仍處於實驗階段,有些會增加成本或複雜性,而像混幣器這類的工具,則可能根據其使用方式面臨法律或監管審查。 + +## 讀取隱私 {#privacy-of-reads} + +在以太坊上讀取或檢查任何資訊 (例如您的錢包餘額) 通常會透過錢包供應商、節點供應商或區塊瀏覽器等服務。 因為您依賴他們為您讀取區塊鏈,他們也能看到您的請求以及 IP 位址或位置等元數據。 如果您持續檢查同一個帳戶,這些資訊可能會被拼湊起來,將您的身分與您的活動連結。 + +執行您自己的以太坊節點可以避免這種情況,但對於大多數使用者來說,儲存和同步整個區塊鏈仍然成本高昂且不切實際,尤其是在行動裝置上。 + +一些探索私密讀取的專案包括 [Private Information Retrieval](https://hackmd.io/@brech1/ethereum-privacy-pir?utm_source=preview-mode&utm_medium=rec) (PIR,在不透露您查詢內容的情況下擷取資料)、[zkID](https://hackmd.io/@brech1/ethereum-privacy-pir?utm_source=preview-mode&utm_medium=rec) (使用零知識證明進行私密身分檢查)、[vOPRF](https://pse.dev/projects/voprf) (在 Web3 中匿名使用 Web2 帳戶)、[vFHE](https://pse.dev/blog/zero-to-start-applied-fully-homomorphic-encryption-fhe-part-1) (對加密資料進行運算) 和 [MachinaIO](https://pse.dev/projects/machina-io) (在保持功能的同時隱藏程式細節)。 + +## 證明的隱私 {#privacy-of-proving} + +保護隱私的證明是您可以在以太坊上使用的工具,用以證明某事為真,而無需透露不必要的細節。 例如,您可以: + +- 證明您已年滿 18 歲,而無需分享您的完整出生日期 +- 證明您擁有某個 NFT 或代幣,而無需透露您的整個錢包 +- 證明您有資格獲得會員資格、獎勵或投票權,而無需暴露其他個人資料 + +大多數用於這些目的的工具都依賴於像零知識證明這樣的密碼學技術,但挑戰在於如何讓它們在日常裝置上高效運行、可移植到任何平台,並確保安全。 + +一些探索證明隱私的專案包括 [Client Side Proving](https://pse.dev/projects/client-side-proving) (ZK 證明系統)、[TLSNotary](https://tlsnotary.org/) (網路上任何資料的真實性證明)、[Mopro](https://pse.dev/projects/mopro) (行動用戶端證明)、[Private Proof Delegation](https://pse.dev/projects/private-proof-delegation) (避免信任假設的委託框架) 和 [Noir](https://noir-lang.org/) (用於私密和可驗證運算的語言)。 + +## 隱私詞彙表 {#privacy-glossary} + +**匿名**:在互動時,您的資料中所有識別碼都被永久移除,使得資訊無法追溯回個人 + +**加密**:一個將資料打亂的過程,只有擁有正確金鑰的人才能讀取 + +**[完全同態加密](https://pse.dev/blog/zero-to-start-applied-fully-homomorphic-encryption-fhe-part-1) (FHE)**:一種直接對加密資料執行運算而無需解密的方法 + +**[無法區分混淆](https://pse.dev/projects/machina-io) (iO)**:一種讓程式或資料在保持可用性的同時變得難以理解的隱私技術 + +**[多方運算](https://pse.dev/blog/secure-multi-party-computation) (MPC)**:允許多方在不暴露各自私密輸入的情況下共同計算出結果的方法 + +**可程式化密碼學**:一種靈活、由規則驅動的密碼學,可在軟體中自訂,以控制資料分享、驗證或揭露的方式和時機 + +**假名**:使用獨特的代碼或數字 (如以太坊地址) 來代替個人識別碼 + +**選擇性揭露**:僅分享必要資訊的能力 (例如,證明您擁有一個 NFT,而不透露您完整的錢包歷史) + +**不可連結性**:確保在區塊鏈上的不同行為無法被追溯回同一個地址 + +**可驗證性**:確保他人可以確認某個聲明為真,例如在以太坊上驗證一筆交易或一個證明 + +**可驗證委派**:將一項任務—例如產生一個證明—指派給另一方 (例如,行動錢包使用伺服器進行繁重的密碼學運算),同時仍能驗證其是否正確完成 + +**[零知識證明](/zero-knowledge-proofs/#why-zero-knowledge-proofs-are-important) (ZKP)**:一種密碼學協議,讓人們可以在不揭露底層資料的情況下,證明資訊為真 + +**ZK Rollup**:一種擴容系統,它在鏈下批次處理交易,並在鏈上提交有效性證明—預設情況下並非私密,但它們透過降低成本來實現高效的隱私系統 (如隱蔽池) + +## 資源 {#resources} + +- [Privacy Stewards of Ethereum](https://pse.dev/) (PSE),一個由以太坊基金會支持的研究與開發實驗室,專注於生態系的隱私保護 +- [Web3PrivacyNow](https://web3privacy.info/),一個由個人、專案和志同道合的組織組成的網路,致力於保護和促進線上的人權 +- [WalletBeat](https://beta.walletbeat.eth.limo/wallet/summary/),一個以太坊錢包評分網站,旨在提供一份詳盡的錢包清單,包含其功能、實務做法以及對特定標準的支援。 +- [Zk-kit](https://zkkit.pse.dev/):一套函式庫 (演算法、實用工具函式和資料結構),可在不同的專案和零知識協議中重複使用。 +- [隱私應用程式](/apps/categories/privacy/) - 探索在以太坊上執行的精選隱私應用程式清單。 diff --git a/public/content/translations/zh-tw/real-world-assets/index.md b/public/content/translations/zh-tw/real-world-assets/index.md new file mode 100644 index 00000000000..5c95985b4fc --- /dev/null +++ b/public/content/translations/zh-tw/real-world-assets/index.md @@ -0,0 +1,93 @@ +--- +title: "真實世界資產(RWAs)" +metaTitle: "什麼是真實世界資產(Real-World Assets, RWAs)? 真實世界資產的益處與應用" +description: "以太坊上真實世界資產概覽" +lang: zh-tw +template: use-cases +emoji: ":house_buildings:" +image: /images/man-and-dog-playing.png +alt: "男人和狗正在一起玩耍。" +sidebarDepth: 2 +summaryPoint1: "將有價值的商品轉換為數位代幣的方法。" +summaryPoint2: "你現在可以擁有現實生活中物體或資產的一部分,而無需購買整個物業或物品。" +summaryPoint3: "將傳統金融與區塊鏈生態系統連接起來。" +--- + +真實世界資產(RWAs)是代表現有財富形式的代幣,例如房地產、黃金、股票、藝術品、機械或收藏品。 將這些資產代幣化會將其轉化為數位形式,允許多個擁有者分割所有權,並使其更容易交易。 + +## 什麼是真實世界資產(Real-World Assets, RWAs)? {#what-are-rwas} + +一些真實世界資產(RWAs)是有形的——你可以看見和觸摸的物品,例如金條或商業建築。 有一些則是無形的,例如國債、智慧財產、公司股權。 + +我們可以藉由把這些資產代幣化,讓他們變成更小的價值單位。 代幣化黃金是個用來說明 RWA 如何運作的好例子。 [Paxos](https://www.paxos.com/) 這間公司將 400 盎司的金條轉換成以太坊區塊鏈上的 400 個代幣,每個代幣由一盎司的黃金擔保。 代幣持有者可以隨時將代幣兌換回黃金。 另一家 RWA 公司 [Tether Gold](https://gold.tether.to/)發行的代幣運作方式亦同。 + +每個代幣可被分割為更小的部分。 比如 Tether Gold 的代幣就可以被切成更小的 0.000001 顆。 + +RWA 代幣並沒有任何內在價值。 反之,其反映了他們所代表物品的價值,因此代幣的價值會隨著物品價值而改變。 + +## RWA 有哪些優點? {#rwas-benefits} + + + + + + + + + + +## RWA 如何運作? {#how-rwas-work} + +來看看來自 RWA 生態系統的幾個例子:不動產、傳統金融產品以及藝術品。 + +### 投資房地產 {#investing-in-real-estate} + +假設您想投資房地產,但買下整棟房子實在遙不可及。 取而代之的是,您可以透過如 [RealT](https://realt.co/) 的專案購買 RWA。 其代幣代表了一家專為持有不動產所有權狀而設立的責任有限公司的股權。 代幣持有者會根據他們持有的比例,收到穩定幣形式的租金收入;據 RealT 所述,它們至今已向投資者發放 1500 萬美金的淨租金。 + +另一個相似的專案,[LABS Group](https://x.com/labsgroupio),讓人們能用小於 100 美金購買代幣化不動產。 + +### 投資金融產品 {#investing-in-financial-products} + +許多專案將證券、股票、債券和其他金融工具橋接到鏈上,架起了傳統金融與去中心化金融(DeFi)間的橋梁。 + +舉例來說,基於以太坊的公司 [Securitize](https://securitize.io/) 專門將傳統金融的產品代幣化。 2024 年時,其與貝萊德合作發行了一檔 RWA 基金。 貝萊德稱其最終預計將其 10 兆美元的資產代幣化:其執行長將代幣化稱為「市場的下個階段」。 + +### 投資藝術品 {#investing-in-fine-art} + +投資藝術品有幾種不同的機制。 [Masterworks](https://www.masterworks.com/) 購買藝術品並將其證券化,再以代幣的形式出售。 他們預計在之後賣出藝術品,並向代幣持有者發放收益。 + +代幣持有者無法控制藝術品的儲存或未來銷售。 反之,他們負責決定該持有代幣多久,代幣會隨著藝術品價值改變而漲跌。 + +另一方面,基於區塊鏈的數位藝術註冊平臺 [Artory](https://www.artory.com/) 會驗證藝術品的真實性及記錄過去的所有權。 + +### 投資收藏品 {#investing-in-collectibles} + +到目前為止,多數例子都說明了代幣化如何讓人們對不同類型的財富有擁有權。 代幣化的另一個好處是,它讓有價值物品(如收藏品)能夠在國際市場上交易。 + +其中一個例子是 [Courtyard](https://courtyard.io/),它將集換式卡牌遊戲——比如棒球球員卡、橄欖球球員卡,或寶可夢卡代幣化。 卡片擁有著將其卡片運送到美國的安全儲存設施。 為了能夠在 Courtyard 市場上交易,該卡片會被鑄造成數位代幣並新增到擁有者的錢包中。 Courtyard 只接受經分級的卡片:即第三方已鑑定過該卡的真偽,並根據其狀況(不論是破舊或保存完整)標上一個分數。 + +Courtyard 也提供一種版稅機制。 每當某卡片被售出時,將該卡代幣化者將收到收益的百分之一。 只有卡片的發行者能拿到該獎勵。 無論卡片擁有者在世界上何處,他們都可以隨時將虛擬卡換成實體卡。 + +## 真實世界資產的限制為何? {#rwas-limitations} + +從早期階段,真實世界資產的其中一個挑戰是確保真實世界的物體和其數位代表的連接。 + +一種可行方案是當真實世界資產專案向投資者提供儲備證明時,保證他們是擔保數位代幣的實體物品的合法所有者。 比如前面提及的 Paxos、Tether Gold,或 Courtyard 都將資產保存在安全的儲藏庫中,並允許持有者隨時將代幣兌換為實物的選項。 + +另一個限制是,代幣所有權使否被世界各地法律系統所認可。 換句話說,智能合約是否可以在法庭上被強制執行,或者真實世界資產代幣的持有者是否可以宣稱擁有現實世界中的實品? + +在建立專門用於認可代幣化的法律框架方面處於領先地位的國家包含新加坡、阿拉伯聯合大公國、香港,和瑞士,瑞士於2021年推出了綽號為《區塊鏈法案》的立法,以規範如代幣化的技術。 歐盟已經開始對真實世界資產進行監管,而在美國,證券交易委員會預測將對真實世界資產發佈指南。 + +## 了解更多 {#learn-more} + +深入了解 [智能合約](/smart-contracts/),或探索另一類代幣——[非同質化代幣(NFT)](/nft/)。 + +## 延伸閱讀 {#further-reading} + +- [什麼是資產代幣化?](https://www.britannica.com/money/real-world-asset-tokenization)——大英百科全書 +- [代幣化如何改變全球金融和投資](https://www.weforum.org/stories/2024/12/tokenization-blockchain-assets-finance/)——世界經濟論壇 +- [加密貨幣投資者對於真實世界資產代幣化需要了解的知識](https://www.forbes.com/sites/irinaheaver/2024/03/14/what-crypto-investors-need-to-know-about-tokenizing-real-world-assets/)——富比世雜誌 +- [智能合約如何與區塊鏈協同運作](https://www.britannica.com/money/how-smart-contracts-work)——大英百科全書 +- [代幣化真實世界資產如何改變去中心化金融](https://medium.com/coinmonks/how-tokenized-real-world-assets-are-transforming-defi-4e040f28732a)——Medium文章 +- [加密貨幣中的真實世界資產是什麼? 闡述其在區塊鏈的作用](https://www.bitdegree.org/crypto/tutorials/what-is-rwa-in-crypto)——BitDegree +- [按市值排名的當今熱門真實世界資產(RWAs)代幣](https://www.forbes.com/digital-assets/categories/real-world-assets-rwa/)——富比世雜誌 diff --git a/public/content/translations/zh-tw/refi/index.md b/public/content/translations/zh-tw/refi/index.md index 417e70f4291..4c2bd780482 100644 --- a/public/content/translations/zh-tw/refi/index.md +++ b/public/content/translations/zh-tw/refi/index.md @@ -1,30 +1,30 @@ --- -title: 再生金融 (ReFi) -description: 再生金融概觀及當前使用案例。 +title: "再生金融 (ReFi)" +description: "再生金融概觀及當前使用案例。" lang: zh-tw template: use-cases emoji: ":recycle:" sidebarDepth: 2 image: /images/future_transparent.png alt: "" -summaryPoint1: 建立在再生原則上的替代性經濟體系 -summaryPoint2: 嘗試使用以太坊解決全球協調危機,如氣候變遷 -summaryPoint3: 大幅擴展生態效益資產(如已驗證碳權)的工具 +summaryPoint1: "建立在再生原則上的替代性經濟體系" +summaryPoint2: "嘗試使用以太坊解決全球協調危機,如氣候變遷" +summaryPoint3: "可大幅擴展生態效益資產 (如已驗證碳權) 的工具" --- ## 什麼是再生金融 (ReFi)? {#what-is-refi} -**再生金融 (ReFi)** 是建立在[區塊鏈](/glossary/#blockchain)上的一整套想法及工具,目標是建立再生經濟,而非榨取式或剝削式經濟。 榨取式系統最終會耗盡可用資源並崩潰;若沒有再生機制,這套系統便缺乏韌性。 再生金融在此假設下運作:貨幣價值的創造必須脫離以非永續的手段,從我們星球及社群抽取資源。 +**再生金融 (ReFi)** 是建立在 [區塊鏈](/glossary/#blockchain) 上的一整套想法及工具,目標是建立再生經濟,而非榨取式或剝削式經濟。 榨取式系統最終會耗盡可用資源並崩潰;若沒有再生機制,這套系統便缺乏韌性。 再生金融在此假設下運作:貨幣價值的創造必須脫離以非永續的手段,從我們星球及社群抽取資源。 相對的,再生金融的目標是透過建立再生循環以解決環境、公共或社會問題。 這些系統為參與者創造了價值,同時也有益於生態系統及社群。 -再生金融的其中一個基礎是由 Capital Institute 的 John Fullerton 所提出的再生經濟概念。 他提出了支撐系統健康的[八項相互關聯的原則](https://capitalinstitute.org/8-principles-regenerative-economy/): +再生金融的其中一個基礎是由 Capital Institute 的 John Fullerton 所提出的再生經濟概念。 他提出了構成系統健康的 [八項相互關聯的原則](https://capitalinstitute.org/8-principles-regenerative-economy/): -![八個關聯原則](refi-regenerative-economy-diagram.png) +![八項相互關聯的原則](refi-regenerative-economy-diagram.png) -再生金融專案透過[智慧型合約](/glossary/#smart-contract)及[去中心化金融 (DeFi)](/glossary/#defi) 應用程式來實現這些原則,從而獎勵再生行為,例如復原衰退的生態系統及促進氣候變遷及生物多樣性減損等國際性議題的大規模合作。 +ReFi 專案使用 [智慧型合約](/glossary/#smart-contract) 和 [去中心化金融 (DeFi)](/glossary/#defi) 應用程式來實現這些原則,以激勵再生行為 (例如復原退化的生態系統),並促進在全球問題 (例如氣候變遷和生物多樣性喪失) 上的大規模合作。 -再生金融也和[去中心化科研 (DeSci)](/desci/) 運動重疊,此運動將以太坊當成融資、創建、審查、信貸、儲存及傳播科學知識的平臺。 去中心化科研工具有益於開發可驗證的再生活動實作及監控之標準及實踐,例如:植樹、消除海洋中的塑膠垃圾,或復原衰退的生態系統等再生活動。 +ReFi 也與 [去中心化科學 (DeSci)](/desci/) 運動重疊,後者使用以太坊作為一個平台,用於資助、創造、審查、歸功、儲存和傳播科學知識。 去中心化科研工具有益於開發可驗證的再生活動實作及監控之標準及實踐,例如:植樹、消除海洋中的塑膠垃圾,或復原衰退的生態系統等再生活動。 @@ -32,7 +32,7 @@ summaryPoint3: 大幅擴展生態效益資產(如已驗證碳權)的工具 **[自願性碳交易市場 (VCM)](https://climatefocus.com/so-what-voluntary-carbon-market-exactly/)** 是為專案融資的一種機制,此等專案會對碳排放產生經驗證的正向影響,能減少持續進行中的碳排放,或消除已排放到大氣中的溫室氣體。 此等專案在經過驗證後會收到稱為「碳權」的資產,碳權可出售給願意支援氣候行動的個人或組織。 -除了自願性碳交易市場外,也有若干政府批准的官方碳交易市場(「規範市場」),目標是透過特定司法管轄區(如國家或地區)的法律或法規來制定碳權價格,控制可分配的許可供應量。 規範市場能獎勵其司法管轄區內的汙染排放者減少碳排放,但無法消除已被排放的溫室氣體。 +除了 VCM 外,還有數個政府強制執行的碳市場 (「合規市場」),目標是透過特定司法管轄區 (例如國家或地區) 內的法律或法規來建立碳價,並控制要分配的許可證供應量。 規範市場能獎勵其司法管轄區內的汙染排放者減少碳排放,但無法消除已被排放的溫室氣體。 雖然自願性碳交易市場已發展了數十年,它仍面臨各種問題: @@ -42,7 +42,7 @@ summaryPoint3: 大幅擴展生態效益資產(如已驗證碳權)的工具 4. 交易速度太慢 5. 缺乏可擴容性 -將自願性碳交易市場過渡到以區塊鏈為基礎的新型**數位碳交易市場 (DCM)** 可能是一個升級現有碳權驗證、交易及消費技術的好機會。 區塊鏈允許公開可驗證的資料、更廣泛的使用者存取權,以及更高的流動性。 +將自願性碳交易市場過渡到以區塊鏈為基礎的新型 **數位碳交易市場 (DCM)** 可能是一個升級現有碳權驗證、交易及消費技術的好機會。 區塊鏈允許公開可驗證的資料、更廣泛的使用者存取權,以及更高的流動性。 再生金融專案採用區塊鏈科技來緩解傳統市場遇到的諸多問題: @@ -50,17 +50,17 @@ summaryPoint3: 大幅擴展生態效益資產(如已驗證碳權)的工具 - **所有交易都記錄在公開的區塊鏈上**。 數位碳交易市場中一出現碳權交易,每筆交易活動的路徑永遠都能被追蹤。 - **交易幾乎即時完成**。 透過傳統市場獲得大量碳權可能會花上數天或數週的時間,但在數位碳交易市場中只需幾秒即可實現。 - **交易活動不需要中間人**,中間人還會向你收取高額費用。 與傳統碳權相比,數位碳權顯著降低了成本。 -- **數位碳交易市場既可擴張**,亦可滿足個人及跨國公司的需求。 +- **DCM 既可擴張**,亦可滿足個人及跨國公司的需求。 -### 數位碳交易市場的核心元件 {#key-components-dcm} +### DCM 的關鍵組成部分 {#key-components-dcm} 當前的數位碳交易市場由四個主要部分所組成: -1. [Verra](https://verra.org/project/vcs-program/registry-system/) 和 [Gold Standard](https://www.goldstandard.org/) 等登記處可確保建立碳權的專案可信、可靠。 他們也運用資料庫來記錄數位碳權的來源,碳權可在其中轉移或用罄(註銷)。 +1. [Verra](https://verra.org/project/vcs-program/registry-system/) 和 [Gold Standard](https://www.goldstandard.org/) 等註冊機構會確保創造碳權的專案是可靠的。 他們也運用資料庫來記錄數位碳權的來源,碳權可在其中轉移或用罄(註銷)。 一波建立於區塊鏈的創新專案正試圖顛覆該領域的現有企業。 -2. 碳權跨鏈橋,又稱 代幣轉換器,提供了代表傳統登記處中的碳權並將其轉移到數位碳交易市場的技術。 著名例子包括 [Toucan Protocol](https://toucan.earth/)、[C3](https://c3.app/) 和 [Moss.Earth](https://moss.earth/)。 +2. 碳權跨鏈橋,又稱 代幣轉換器,提供了代表傳統登記處中的碳權並將其轉移到數位碳交易市場的技術。 著名的例子包括 [Toucan Protocol](https://toucan.earth/)、[C3](https://c3.app/) 和 [Moss.Earth](https://moss.earth/)。 3. 整合服務是一種向使用者端提供碳減排和/或移除碳權的服務,讓使用者可以宣稱碳權對環境的效益,並與全世界分享他們對氣候行動的支援。 例如,[Klima Infinity](https://www.klimadao.finance/infinity) 和 [Senken](https://senken.io/) 提供了由第三方開發並在既定標準(如 Verra)下發行的各種專案;其他如 [Nori](https://nori.com/) 就只提供了以其自家碳權標準開發的特定專案,這些專案由他們發行,並為之準備了自己的專門市場。 @@ -69,13 +69,13 @@ summaryPoint3: 大幅擴展生態效益資產(如已驗證碳權)的工具 ## 碳交易市場以外的再生金融 {#refi-beyond} -雖然整體來說,目前各界對碳交易市場極為重視,且此領域中,特別看重從自願性碳交易市場轉換到數位碳交易市場,但「再生金融」一詞並不囿限於碳。 碳權以外的其他環境資產均可被開發和代幣化,這表示其他負面外部影響也可以在未來經濟體系的基礎層中定價。 此外,再生式的經濟模型也可用於其他領域,如使用 [Gitcoin](https://gitcoin.co/) 等平方募資平台為公共產品融資。 以開放參與及公平分配資源為核心精神的組織,讓每個人都能資助開放原始碼軟體專案以及教育、環保和社群導向專案。 +雖然整體來說,目前各界對碳交易市場極為重視,且此領域中,特別看重從自願性碳交易市場轉換到數位碳交易市場,但「再生金融」一詞並不囿限於碳。 碳權以外的其他環境資產均可被開發和代幣化,這表示其他負面外部影響也可以在未來經濟體系的基礎層中定價。 此外,此經濟模型的再生特性也可用於其他領域,如使用 [Gitcoin](https://gitcoin.co/) 等二次方募資平台為公共財融資。 以開放參與及公平分配資源為核心精神的組織,讓每個人都能資助開放原始碼軟體專案以及教育、環保和社群導向專案。 透過將資本由榨取式的做法轉變成再生循環的資金流,對那些提供了社會、環境或公共利益,但可能難以透過傳統金融取得資金的專案及公司來說,他們因而能順利發展,並更快、更輕鬆地為社會產生正向外部影響。 轉變到此融資模式也開啟了更包容的經濟體系,各種背景的人都可以成為主動參與者,而非僅僅是被動的觀察者。 再生金融是以太坊的願景之一,可作為一種行動協調機制,解決人類及地球上所有生命正面臨的現存挑戰 — 並作為新經濟典範的基礎層,促進更包容且更永續的未來世紀。 ## 關於再生金融的延伸閱讀 -- [碳貨幣及其在經濟中的地位概觀](https://www.klimadao.finance/blog/the-vision-of-a-carbon-currency) -- [小說《未來部門》(Ministry for the Future),描繪了碳貨幣在對抗氣候變遷上起到的作用。](https://en.wikipedia.org/wiki/The_Ministry_for_the_Future) -- [Taskforce 針對擴張自願性碳交易市場所撰的詳細報告](https://www.iif.com/Portals/1/Files/TSVCM_Report.pdf) -- [由 Kevin Owocki 和 Evan Miyazono 針對再生金融所建的 CoinMarketCap 術語列表](https://coinmarketcap.com/alexandria/glossary/regenerative-finance-refi) +- [碳貨幣及其在經濟中地位的高階概覽](https://www.klimadao.finance/resources/the-vision-of-a-carbon-currency) +- [小說《未來部門》(The Ministry for the Future),描繪了碳本位貨幣在對抗氣候變遷中所扮演的角色](https://en.wikipedia.org/wiki/The_Ministry_for_the_Future) +- [擴展自願性碳市場工作小組的詳細報告](https://www.iif.com/Portals/1/Files/TSVCM_Report.pdf) +- [Kevin Owocki 和 Evan Miyazono 在 CoinMarketCap 詞彙表中關於 ReFi 的條目](https://coinmarketcap.com/academy/glossary/regenerative-finance-refi) diff --git a/public/content/translations/zh-tw/restaking/index.md b/public/content/translations/zh-tw/restaking/index.md new file mode 100644 index 00000000000..97de703edde --- /dev/null +++ b/public/content/translations/zh-tw/restaking/index.md @@ -0,0 +1,188 @@ +--- +title: "再質押" +metaTitle: "什麼是再質押? | 再質押的好處和用途" +description: "使用已質押的 ETH 保護其他去中心化服務,並賺取額外獎勵。" +lang: zh-tw +template: use-cases +emoji: ":recycle:" +image: /images/use-cases/restaking.png +alt: "以太坊上再質押的視覺化呈現。" +sidebarDepth: 2 +summaryPoint1: "使用已質押的 ETH 保護其他去中心化服務,並賺取額外獎勵。" +buttons: + - content: 什麼是再質押? + toId: what-is-restaking + - content: 它是如何運作的? + toId: how-does-restaking-work + isSecondary: false +--- + +以太坊網路全年無休地保護著數十億美元的價值。 怎麼做到的? + +世界各地的人們將[以太幣 (ETH)](/what-is-ether/) 鎖定(或「質押」)在智能合約中,以運行處理以太坊交易和保護以太坊網路的軟體。 作為回報,他們會獲得更多 ETH 作為獎勵。 + +再質押是一項為[質押者](/staking/)打造的技術,可將此安全性擴展到其他服務、應用程式或網路。 作為回報,他們可以賺取額外的再質押獎勵。 然而,這也使他們已質押的 ETH 承受更大的風險。 + +**18 分鐘解釋再質押** + + + +## 什麼是再質押? {#what-is-restaking} + +再質押是指質押者使用他們已經質押的 ETH 來保護其他去中心化服務。 作為回報,再質押者除了常規的 ETH 質押獎勵外,還可以從那些其他服務中獲得額外獎勵。 + +透過再質押保護的去中心化服務被稱為「主動驗證服務」(AVS)。 +正如許多 ETH 質押者運行以太坊驗證軟體一樣,許多再質押者也運行專門的 AVS 軟體。 + +
+ + + + +

建議須知

+

雖然「主動驗證服務」(Actively Validated Services,簡稱 AVS) 是最常見的稱呼,但不同的再質押平台可能會為他們協助保護的去中心化服務使用其他名稱,例如「自主驗證服務」(Autonomously Validated Services)、「分散式安全服務」(Distributed Secure Services) 或「網路」(Networks)。

+
+
+
+ +## 質押與再質押 {#staking-vs-restaking} + +| 質押 | 再質押 | +| ---------- | ------------------ | +| 賺取 ETH 獎勵 | 賺取 ETH 獎勵 + AVS 獎勵 | +| 保護以太坊網路 | 保護以太坊網路 + AVS | +| 無最低 ETH 限制 | 無最低 ETH 限制 | +| 低風險等級 | 低至高風險等級 | +| 提款時間取決於佇列 | 提款時間取決於佇列 + 解綁定期 | + +## 我們為什麼需要再質押? {#why-do-we-need-restaking} + +想像兩個世界;一個有再質押,一個沒有。 + + + +在有再質押的這個世界裡,AVS 和質押者都能從互相找到對方並用安全性換取額外獎勵中獲益。 + +
+ + + + + +

再質押的額外好處

+

AVS 可以將所有資源投入建構和行銷他們的服務,而不用為去中心化和安全性分心。

+
+
+
+ +## 再質押如何運作? {#how-does-restaking-work} + +再質押涉及數個實體——每個實體都扮演著重要的角色。 + +| **術語** | **描述** | +| ----------- | -------------------------------------------------------------------------------------------------------------------------------------- | +| **再質押平台** | 再質押平台是一種連接 AVS、ETH 質押者和營運者的服務。 他們為質押者建構去中心化應用程式以再質押他們的 ETH,並建立市場讓質押者、AVS 和營運者可以找到彼此。 | +| **原生再質押者** | 透過運行自己的以太坊驗證者來質押 ETH 的人,可以將他們已質押的 ETH 連接到再質押平台(包括 EigenLayer 和其他平台),在 ETH 驗證者獎勵之上賺取再質押獎勵。 | +| | | +| **流動性再質押者** | 透過 Lido 或 Rocket Pool 等第三方流動性質押提供商質押 ETH 的人,會獲得代表其已質押 ETH 的流動性質押代幣 (LST)。 他們可以再質押這些 LST 來賺取再質押獎勵,同時保持其原始 ETH 的質押狀態。 | +| | | +| **營運者** | 營運者運行 AVS 的再質押軟體,執行每個 AVS 所需的驗證任務。 營運者通常是保證正常運行時間和效能等事項的專業服務提供商。 與非營運者再質押者一樣,營運者使用已質押的 ETH 來保護 AVS,但營運者也會因其工作而獲得額外獎勵。 | +| | | +| **AVS** | 這些是去中心化服務——例如價格預言機、代幣跨鏈橋和數據系統——它們從再質押者那裡獲得安全性,並提供代幣獎勵作為回報。 | + +
+ + + + + +

建議須知

+

原生和流動性再質押者通常會將他們已質押的 ETH 委託給營運者,而不是自己運行軟體來保護 AVS。

+

這樣他們就不需要擔心 AVS 複雜的技術要求,儘管他們收到的獎勵率比營運者低。

+
+
+
+ +## 再質押有哪些例子? {#what-are-some-examples-of-restaking} + +雖然這是一個新穎的想法,但已經出現了一些專案來探索再質押的可能性。 + + + +
+ + + + + +

用詞不當警報

+

有些人會將「再質押」與在 DeFi 中借出和借入 LST 混淆。 兩者都是讓已質押的 ETH 發揮作用,但再質押意味著保護 AVS,而不僅僅是在 LST 上賺取收益。

+
+
+
+ +## 我能從再質押中賺多少錢? {#how-much-can-i-make-from-restaking} + +雖然 AVS 提供不同的利率,但像 eETH 這樣的流動性再質押代幣 (LRT) 能讓您了解可以賺多少錢。 就像質押您的 ETH 會得到 stETH 等 LST 一樣,再質押 stETH 可以得到 eETH 等 LRT。 這些代幣可以賺取 ETH 質押和再質押獎勵。 + +**承認再質押的風險很重要。 潛在獎勵可能很吸引人,但並非沒有風險。** + +## 再質押的風險是什麼? {#what-are-the-risks-of-restaking} + +| **風險** | **描述** | +| ------------- | ----------------------------------------------------------- | +| **罰款(或「罰沒」)** | 就像 ETH 質押一樣,如果再質押者/營運者離線、審查訊息或試圖破壞網路,他們的質押品可能會被部分或全部罰沒(銷毀)。 | +| **中心化** | 如果少數營運者主導了大部分的再質押,他們可能會對再質押者、AVS 甚至再質押平台產生巨大影響。 | +| **連鎖反應** | 如果一個再質押者在保護多個 AVS 時被罰沒,這可能會降低其他 AVS 的安全性,使其變得易受攻擊。 | +| **立即存取資金** | 提取再質押的 ETH 有一段等待時間(或「解綁定期」),所以您可能無法總是立即存取。 | + +
+ + + + + +

以太坊共同創辦人正在輸入...

+

+ 以太坊共同創辦人 Vitalik 在 2021 年一篇名為 《不要讓共識超載》的部落格文章中警告了再質押的潛在風險。 +

+
+
+
+ +## 如何開始再質押? {#how-to-get-started-with-restaking} + +| 🫡 初學者 | 🤓 進階使用者 | +| ------------------------------------------------------------------- | ----------------------------------------------------------- | +| 1. 在 Lido 或 Rocket Pool 等平台上質押 ETH 以獲得 LST。 | 1. 在以太坊上作為驗證者質押您的 ETH。 | +| 2. 使用這些 LST 在再質押服務上開始再質押。 | 2. 比較 EigenLayer、Symbiotic 和其他再質押服務。 | +| | 3 按照說明將您的驗證者連接到再質押智能合約。 | + +
+ + + + + +

以太坊質押:如何運作?

+ + 了解更多 + +
+
+
+ +## 進階 {#advanced} + + + +## 延伸閱讀 {#further-reading} + +1. [ethereum.org - ETH 質押指南](https://ethereum.org/en/staking/) +2. [Ledger Academy - 什麼是以太坊再質押?](https://www.ledger.com/academy/what-is-ethereum-restaking) +3. [Consensys - EigenLayer:去中心化以太坊再質押協議詳解](https://consensys.io/blog/eigenlayer-decentralized-ethereum-restaking-protocol-explained) +4. [Vitalik Buterin - 不要讓以太坊的共識超載](https://vitalik.eth.limo/general/2023/05/21/dont_overload.html) +5. [Cointelegraph - 什麼是 EigenLayer? 以太坊的再質押協議詳解](https://cointelegraph.com/explained/what-is-eigenlayer-ethereums-restaking-protocol-explained) +6. [a16z crypto research - EigenLayer:與 Sreeram Kannan 談為以太坊添加無需許可的功能](https://www.youtube.com/watch?v=-V-fG4J1N_M) +7. [Junion - EigenLayer 詳解:什麼是再質押?](https://www.youtube.com/watch?v=5r0SooSQFJg) +8. [The Block - 再質押數據儀表板](https://www.theblock.co/data/decentralized-finance/restaking) diff --git a/public/content/translations/zh-tw/roadmap/account-abstraction/index.md b/public/content/translations/zh-tw/roadmap/account-abstraction/index.md index fd6a009a74f..ffa5da71e26 100644 --- a/public/content/translations/zh-tw/roadmap/account-abstraction/index.md +++ b/public/content/translations/zh-tw/roadmap/account-abstraction/index.md @@ -1,6 +1,6 @@ --- -title: 帳戶摘要 -description: 以太坊讓使用者帳戶更簡潔、更安全的計劃概述 +title: "帳戶摘要" +description: "以太坊讓使用者帳戶更簡潔、更安全的計劃概述" lang: zh-tw summaryPoints: - 帳戶抽象使得建立智慧型合約錢包變得更加容易 @@ -8,11 +8,11 @@ summaryPoints: - 可以使用多個備份來恢復遺失和暴露的金鑰 --- -# 帳戶摘要 {#account-abstraction} +# 帳戶抽象化 {#account-abstraction} -使用者使用**[外部帳戶 (EOA)](/glossary/#eoa)** 與以太坊互動。 這是開啟交易或執行智慧型合約的唯一方法, 限制了使用者與以太坊互動的方式。 舉例而言,它使得批次處理交易變得困難,並且要求使用者始終保持一定的以太幣餘額來支付燃料費用。 +大多數現有使用者都使用**[外部擁有帳戶 (EOAs)](/glossary/#eoa)** 與以太坊互動。 這限制了使用者與以太坊互動的方式。 舉例而言,它使得批次處理交易變得困難,並且要求使用者始終保持一定的以太幣餘額來支付交易費。 -帳戶抽象能夠解決這些問題,藉助它,使用者可以透過編程,靈活地將更高的安全性和更好的使用體驗帶到其帳戶中。 這可以透過兩種方式實現:[升級外部帳戶](https://eips.ethereum.org/EIPS/eip-3074),這樣它們可以由智慧型合約控制;[升級智慧型合約](https://eips.ethereum.org/EIPS/eip-2938),這樣他們可以發起交易。 兩個方案皆須變更以太坊協定。 還有第三條路徑涉及新增[第二個獨立的交易系統](https://eips.ethereum.org/EIPS/eip-4337),以便與現有協定並行運行。 無論選取哪條路徑,結果都是經由智慧型合約錢包存取以太坊,不管是作為現有協定一部分的本地支援或是藉由附加交易網路。 +帳戶抽象能夠解決這些問題,藉助它,使用者可以透過編程,靈活地將更高的安全性和更好的使用體驗帶到其帳戶中。 這可以透過[升級 EOAs](https://eips.ethereum.org/EIPS/eip-7702) (EIP-7702) 來實現,讓它們能夠被智能合約控制。 還有另一條路徑,涉及新增[第二個獨立的交易系統](https://eips.ethereum.org/EIPS/eip-4337) (EIP-4337),以便與現有協定並行運行。 無論採用哪種途徑,最終結果都是透過智能合約錢包存取以太坊,無論是作為現有協定的一部分獲得原生支援,或是透過附加的交易網路實現。 智慧型合約錢包為使用者帶來諸多好處,包括: @@ -20,107 +20,52 @@ summaryPoints: - 遺失金鑰時恢復帳戶 - 安全地與受信任的裝置或個人共用帳戶 - 幫助別人支付燃料費用,或者讓別人幫忙支付自己的燃料費用 -- 同時批量處理交易(例如一次性核准並執行兌換) +- 同時批量處理交易(例如一次性批准並執行兌換) - 為去中心化應用程式和錢包開發者提供更多機會來創新使用者體驗 -目前,這些優勢並未得到本地的支援,因為只有外部帳戶 ([EOA](/glossary/#eoa)) 才能開啟交易。 外部帳戶純粹只是公開-私密金鑰對。 它們的作用原理為: +現今這些好處並未獲得原生支援,因為只有外部擁有帳戶 ([EOAs](/glossary/#eoa)) 可以發起交易。 外部帳戶純粹只是公開-私密金鑰對。 它們的作用原理為: -- 如果你有私密金鑰,就可以在以太坊虛擬機 (EVM) 內_做任何事情_ -- 如果沒有私密金鑰,就_什麼事也做不了_。 +- 如果你有私密金鑰,就可以在以太坊虛擬機 (EVM) 的規則範圍內做_任何事_ +- 如果你沒有私密金鑰,就_什麼事也做不了_。 遺失的金鑰無法找回,竊賊可以利用被盜的金鑰立即存取帳戶中的所有資金。 -智慧型合約錢包可以解決這些問題,但如今它們很難編程,因為最終它們實作的任何邏輯都必須轉換為一組外部帳戶交易,然後才能由以太坊處理。 帳戶抽象使得智慧型合約能夠自行發起交易,因此使用者希望實作的任何邏輯皆可編碼到智慧型合約錢包本身並在以太坊上執行。 +智能合約錢包可以解決這些問題,但如今它們很難編程,因為它們實作的任何邏輯最終都必須轉換為一組 EOA 交易,然後才能由以太坊處理。 帳戶抽象使得智慧型合約能夠自行發起交易,因此使用者希望實作的任何邏輯皆可編碼到智慧型合約錢包本身並在以太坊上執行。 -最後,帳戶抽象改進了對智慧型合約錢包的支援,使其更易於建置且使用更安全。 總的說來,透過帳戶抽象,使用者可以享受以太坊的所有好處,而無需瞭解或關心底層技術。 +最後,帳戶抽象改進了對智慧型合約錢包的支援,使其更易於建置且使用更安全。 透過帳戶抽象,使用者可以享受以太坊的所有好處,而無需理解底層技術。 ## 超越種子助記詞 {#beyond-seed-phrases} -現今的帳戶使用依據種子助記詞計算出的私密金鑰來保護。 任何有權存取種子助記詞的人皆可輕鬆發現保護帳戶的私密金鑰,並取得其保護之所有資產的存取權限。 遺失的私密金鑰和種子助記詞將永遠無法恢復,所控制的資產亦將永遠凍結。 即使對於專家使用者來說,保管這些種子助記詞也很困難,且種子助記詞網路釣魚是使用者被騙的最常見方式之一。 +現今的帳戶使用依據種子助記詞計算出的私密金鑰來保護。 任何有權存取種子助記詞的人皆可輕鬆發現保護帳戶的私密金鑰,並取得其保護之所有資產的存取權限。 如果私鑰和助記詞遺失,資產將永久無法存取。 即使對於專家使用者來說,保管這些種子助記詞也很困難,且種子助記詞網路釣魚是使用者被騙的最常見方式之一。 -帳戶抽象將使用智慧型合約來持有資產和授權交易,從而解決這個問題。 然後可以用客製化邏輯裝飾這些智慧型合約,以使其盡可能安全並為使用者量身訂製。 最終,你依舊使用私密金鑰來管控對帳戶的存取,但安全網可以讓你的管理工作變得更輕鬆、更安全。 +帳戶抽象使用智能合約來持有資產和授權交易,從而解決這個問題。 智能合約可以包含客製化邏輯,以達到最高的安全性和可用性。 使用者仍然使用私密金鑰去控制帳戶,但有了強化的安全措施。 -例如,可以將備份金鑰新增至錢包中,以便在主金鑰遺失或意外暴露時,能夠在獲得備份金鑰許可的情況下,用新的安全金鑰取代主金鑰。 你可以透過不同方式保護這些金鑰,或者將它們分配給受信任的監護人。 如此,竊賊便更難完全控制你的資金。 同樣,你可以向錢包新增規則,以減少主金鑰洩露時的影響,舉例來說,你可以允許透過單一簽名來驗證小額交易,而大額交易則需要多位經驗證簽署者的批准。 智慧型合約錢包還有其他方法可以幫助你阻止竊賊,例如,可以使用白名單來阻止每筆交易,除非交易是傳送到受信任的地址或是透過你預先批准的多個金鑰進行驗證。 +舉例來說,使用者可以在錢包加入備用的安全金鑰,在主要的安全金鑰遺失時可以使用備用的。 每個金鑰都可以採用不同的保護方式,或分散給信任的人保管,大幅提升安全性。 額外的錢包規則可降低金鑰外洩的損害,如高額交易需多重簽名,或限制僅可轉帳至受信任地址。 -### 可以內建到智慧型合約錢包中的安全邏輯範例: +## 更佳的使用者體驗 {#better-user-experience} -- **多重簽名授權**:可以在多個受信任的人員或裝置之間共用授權憑證。 然後可以對合約進行設定,要求交易超過某個預設值時,必須得到一定比例(例如 3/5)的可信方的授權。 舉例來說,高額交易可能需要行動裝置和硬體錢包的批准,或者需要分配予可信家庭成員的帳戶的簽名。 -- **帳戶凍結**:若裝置遺失或受到入侵,可以從另一台授權裝置鎖定帳戶,從而保護使用者的資產。 -- **帳戶恢復**:裝置遺失或忘記密碼? 在目前的範例中,這意味著你的資產可能永遠凍結。 有了智慧型合約錢包,你可以設定一份帳戶白名單來授權新裝置並重設存取權限。 -- **設定交易限制**:指定每日閾值,以控制每日/週/月可以從帳戶轉出多少金額。 這意味著,即使攻擊者確實取得存取你帳戶的存取權限,也不能立即提領所有內容,並且你將有機會凍結和重設存取權限。 -- **建立白名單**:只允許發送交易到你確認安全的特定地址。 這代表_即使_你的私密金鑰遭竊,攻擊者也只能將資金傳送到白名單上的目標帳戶。 這些白名單需要多個簽名才能更改,因此攻擊者無法將自己的地址新增至名單,除非他們有權存取你的多個備份金鑰。 +帳戶抽象透過在協定層級支援智能合約錢包,大幅提升使用者體驗和安全性。 開發者可以自由創新,改善交易打包機制以提升速度和效率。 簡單的兌換只需一鍵就能完成,大大提升了使用體驗。 -## 更好的使用者體驗 {#better-user-experience} - -帳戶抽象可以提供**更好的整體使用者體驗**和**改進的安全性**,因為它在協定層級新增了對智慧型合約錢包的支援。 最重要的原因是,它將為智慧型合約、錢包和應用程式的開發者提供更大的自由,以我們可能無法預見的方式創新使用者體驗。 帳戶抽象帶來的一些明顯改進包括捆綁交易以提高速度和效率。 舉例來說,簡單的兌換原本應該是一鍵操作,但現在卻需要簽署多個交易,以批准各個代幣的使用,接著才能執行兌換。 帳戶抽象透過允許交易捆綁消除了這種分歧。 此外,捆綁交易可以精確批准每筆交易所需的代幣的正確價值,然後在交易完成後撤銷批准,從而提供額外的安全性。 - -透過帳戶抽象,燃料管理也得到很大的改進。 應用程式不僅可以支付使用者的燃料費用,還可以用以太幣以外的代幣支付燃料費用,讓使用者不必為了支付交易手續費而保留以太幣餘額。 這可以透過在合約內將使用者的代幣換成以太幣,然後使用以太幣支付燃料費用來實現。 - - - -燃料管理是以太坊使用者遇到的主要難題之一,主要原因是以太幣是唯一可用於支付交易手續費的資產。 想像一下,如果你的錢包中都是 USDC,沒有以太幣。 你無法移動或兌換這些 USDC 代幣,因為不能支付燃料費用。 也不能將 USDC 換成以太幣,因為這本身就需要消耗燃料。 必須從交易所或其他地址將更多以太幣傳送至你的帳戶,才能解決這個問題。 有了智慧型合約錢包後,你可以輕鬆地用 USDC 支付燃料費用,解放帳戶。 你不必再在所有帳戶中保留以太幣餘額。 - -帳戶抽象也允許去中心化應用程式開發者在燃料管理方面發揮創意。 舉例來說,你每個月或許可以為最喜愛的去中心化交易所支付一筆固定費用,以實現無限制的交易。 去中心化應用程式也可能代你支付所有燃料費用,作為對你使用其平台的獎勵,或作為入網優惠。 當協定層面支援智慧型合約錢包時,開發者將更容易在燃料方面實現創新。 - - - -可信會話還可能變革使用者體驗,特別是像遊戲這樣的應用程式,大量小額交易可能需要在短時間內獲得批准。 逐一批准交易將破壞遊戲體驗,但永久批准又不安全。 智慧型合約錢包可以在固定時間內核准某些特定交易,比如特定金額或地址的交易。 - -考慮購買過程如何隨著帳戶抽象而改變也非常有意思。 目前,必須使用已預先存入足夠數量代幣的錢包,每筆交易才能獲得批准和執行。 透過帳戶抽象,體驗比較像大家熟悉的線上購物,使用者只要將物品放入「購物車」並按一下結帳按鈕,即可一次性購買所有商品,所需的所有邏輯皆由合約處理,而非使用者。 - -這些只是帳戶抽象提升使用者體驗的個別例子,還有更多我們沒有想像到的使用場景。 帳戶抽象將開發者從現今的外部帳戶限制中解放,讓他們將 web2 的優點帶進 web3,而不必犧牲自我託管的權利,亦無需絞盡腦汁發明新的使用者體驗。 +Gas 管理得到顯著改善。 應用程式可以代替使用者支付 Gas 費用,或允許使用 ETH 以外的代幣支付,讓用戶無需持有 ETH 餘額。 ## 帳戶抽象將如何實作? {#how-will-aa-be-implemented} -目前市面上已經有智慧型合約錢包了,但因為以太坊虛擬機還不支援,要實作它們非常有挑戰性。 相對的,它們依賴於在標準以太坊交易中包裝相對複雜的程式碼。 透過允許智慧型合約開啟交易,不在鏈下而是在以太坊智慧型合約中處理必要的邏輯,以太坊可以改變上述情況。 將邏輯放進智慧型合約也提高了以太坊的去中心化程度,因為有了它之後,便不需要錢包開發者運行的「中繼器」將使用者簽署的訊息轉換為常規以太坊交易。 - - - -EIP-2771 引入了元交易的概念,允許第三方在不更改以太坊協定的情況下支付使用者的燃料費用。 這個想法是讓使用者簽署的交易會送到「轉發者」合約中。 轉發者是可信任的實體,會在將交易傳送到燃料中繼器之前驗證交易是否有效。 這在鏈下完成,因此無需支付燃料費用。 燃料中繼器將交易送到「接收者」合約,支付必要的燃料費用,以使交易可在以太坊上執行。 如果「接收者」知道和信任「轉發者」,交易即會執行。 這種模式使得開發者可以輕鬆為使用者實現無燃料交易。 - - +目前,智能合約錢包的實作仍具挑戰性,因為它們仰賴複雜的程式碼來包裝標準交易。 以太坊可以透過允許智能合約直接發起交易來改變這個狀況,將邏輯嵌入以太坊智能合約中,而非仰賴外部中繼器。 - +### EIP-4337:在不變更協定的情況下實現帳戶抽象 -EIP-4337 是以去中心化方式實現本地智慧型合約錢包支援的第一步,無需變更以太坊協定。 不是修改共識層來支援智慧型合約錢包,而是在正常的交易廣播協定中單獨新增一個系統。 這個更高級別的系統圍繞一個名為 UserOperation 的新物件建構,此等物件將使用者的操作以及相關簽名打包在一起。 接下來,這些 UserOperation 物件會被廣播到專用記憶體池中,驗證者會將其打包成「捆綁交易」。 捆綁交易代表許多單獨的 UserOperations 序列,可以像普通交易一樣包含在以太坊區塊中,並且可以由驗證者使用類似的費用最大化選取模型來選擇。 +EIP-4337 在不修改以太坊核心協定的情況下,實現了對智能合約錢包的原生支援。 它引入了 `UserOperation` 物件,這些物件會由驗證者收集並組成交易包,從而簡化錢包開發。 EIP-4337 EntryPoint 合約於 2023 年 3 月 1 日部署至以太坊主網,至今已促成超過 2,600 萬個智能錢包的創建,以及 1.7 億次 UserOperation 操作。 -EIP-4337 也會改變錢包的運作方式。 這些功能將外包給稱為「入口點」的全域錢包合約,而不是每個錢包重新實作常見但複雜的安全邏輯。 此合約將處理支付費用、執行以太坊虛擬機程式碼等操作,以便錢包開發者可以專注於提供出色的使用者體驗。 - -注意 EIP-4337 入口點合約已於 2023 年 3 月 1 日部署至以太坊主網。 你可以在 Etherscan 上查看此合約。 - - - - - -EIP-2938 的目標是藉由引入一種新的交易類型 AA_TX_TYPE 來更新以太坊協定,包含三個欄位:noncetargetdata,其中 nonce 是交易計數器,target 是入口點合約地址,data 是以太坊虛擬機位元組碼。 若要執行這些交易,需要新增兩條新的指令(又稱作業碼)到以太坊虛擬機:NONCEPAYGASNONCE 操作碼會追蹤交易序列,PAYGAS 則會計算並從合約餘額中提取執行交易所需的燃料費用。 這些新功能使得以太坊能夠在本地支援智慧型合約錢包,因為以太坊協定已內建必要的基礎設施。 - -請注意,EIP-2938 目前尚未啟用。 社群目前偏好 EIP-4337,因其不要求變更協定。 - - - - - -EIP-3074 的目標是更新以太坊的外部帳戶,方法是允許它們將控制權委託給智慧型合約。 這意味著智慧型合約邏輯可以批准源自外部帳戶的交易。 這可以讓一些功能成為可能,如燃料贊助和批次交易。 要使其可行,必須新增兩個新的作業碼到以太坊虛擬機:AUTHAUTHCALL。 透過 EIP-3074,無需合約即可獲得智慧型合約錢包的優勢;相反,一種稱為「調用者」的特定類型的無狀態、無信任、不可升級的合約會處理交易。 - -請注意,EIP-3074 目前尚未啟用。 社群目前偏好 EIP-4337,因其不要求變更協定。 +## 目前進度 {#current-progress} - +作爲以太坊 Pectra 升級的一部分,EIP-7702 計劃于 2025 年 3 月 7 日實施。 EIP-4337 已被廣泛採用,[部署超過 2600 萬個智能帳戶,並處理超過 1.7 億次 UserOperations](https://www.bundlebear.com/erc4337-overview/all)。 -## 目前進度 {#current-progress} +## 延伸閱讀 {#further-reading} -智慧型合約錢包早已可用,但需要更多升級才能讓它們盡可能去中心化及無需許可。 EIP-4337 是成熟的提案,且不需要對以太坊協定做任何變更,所以可以快速實作。 然而,改變以太坊協定的升級目前尚未積極開發,因此這些更改可能需要更長的時間才能發佈。 也有可能帳戶抽象透過 EIP-4337 完美實現,也就不需要變更任何協定了。 - -## 了解更多 {#further-reading} - -- [erc4337.io](https://www.erc4337.io/) -- [來自 Devcon Bogota 的帳戶抽象小組討論](https://www.youtube.com/watch?app=desktop&v=WsZBymiyT-8) -- [來自 Devcon Bogota 的「為何帳戶抽象對去中心化應用程式來說是革命性的改變」](https://www.youtube.com/watch?v=OwppworJGzs) -- [來自 Devcon Bogota 的「帳戶抽象 ELI5」(譯註:ELI5 是「把我當五歲小孩和我解釋」的英文縮寫,指用簡單易懂的方式解釋)](https://www.youtube.com/watch?v=QuYZWJj65AY) -- [Vitalik 的「帳戶抽象之路」筆記](https://notes.ethereum.org/@vbuterin/account_abstraction_roadmap#Transaction-inclusion-lists) -- [Vitalik 關於社交恢復錢包的部落格文章](https://vitalik.eth.limo/general/2021/01/11/recovery.html) -- [EIP-2938 筆記](https://hackmd.io/@SamWilsn/ryhxoGp4D#What-is-EIP-2938) -- [EIP-2938 文檔](https://eips.ethereum.org/EIPS/eip-2938) -- [EIP-4337 筆記](https://medium.com/infinitism/erc-4337-account-abstraction-without-ethereum-protocol-changes-d75c9d94dc4a) -- [EIP-4337 文檔](https://eips.ethereum.org/EIPS/eip-4337) -- [EIP-2771 文檔](https://eips.ethereum.org/EIPS/eip-2771) -- [「帳戶抽象的基本概念」 -- 什麼是帳戶抽象,第一部分](https://www.alchemy.com/blog/account-abstraction) +- [erc4337.io](https://docs.erc4337.io/) +- [EIP-4337 文件](https://eips.ethereum.org/EIPS/eip-4337) +- [EIP-7702 文件](https://eips.ethereum.org/EIPS/eip-7702) +- [ERC-4337 採用儀表板](https://www.bundlebear.com/erc4337-overview/all) +- [Vitalik 的「帳戶抽象化之路」](https://notes.ethereum.org/@vbuterin/account_abstraction_roadmap#Transaction-inclusion-lists) +- [Vitalik 關於社交恢復錢包的部落格](https://vitalik.eth.limo/general/2021/01/11/recovery.html) +- [帳戶抽象化精選資源](https://github.com/4337Mafia/awesome-account-abstraction) diff --git a/public/content/translations/zh-tw/roadmap/beacon-chain/index.md b/public/content/translations/zh-tw/roadmap/beacon-chain/index.md index b818759e95f..2f3b857c776 100644 --- a/public/content/translations/zh-tw/roadmap/beacon-chain/index.md +++ b/public/content/translations/zh-tw/roadmap/beacon-chain/index.md @@ -1,13 +1,13 @@ --- -title: 信標鏈(Beacon Chain) -description: 瞭解信標鍊 - 將權益證明引入以太坊的升級。 +title: "信標鏈(Beacon Chain)" +description: "瞭解信標鍊 - 將權益證明引入以太坊的升級。" lang: zh-tw template: upgrade image: /images/upgrades/core.png alt: -summaryPoint1: 信標鏈將權益證明引入以太坊生態系統。 -summaryPoint2: 信標鏈於 2022 年 9 月與原先的以太坊工作量證明鏈合併。 -summaryPoint3: 信標鏈引入共識邏輯和區塊廣播協定,現在可保護以太坊安全。 +summaryPoint1: "信標鏈將權益證明引入以太坊生態系統。" +summaryPoint2: "信標鏈於 2022 年 9 月與原先的以太坊工作量證明鏈合併。" +summaryPoint3: "信標鏈引入共識邏輯和區塊廣播協定,現在可保護以太坊安全。" --- diff --git a/public/content/translations/zh-tw/roadmap/danksharding/index.md b/public/content/translations/zh-tw/roadmap/danksharding/index.md index 9fe25af8abe..8b01aaf8cac 100644 --- a/public/content/translations/zh-tw/roadmap/danksharding/index.md +++ b/public/content/translations/zh-tw/roadmap/danksharding/index.md @@ -1,6 +1,6 @@ --- title: Danksharding -description: 瞭解 Proto-Danksharding 和 Danksharding - 兩種依序完成以太坊擴容的升級方案。 +description: "瞭解 Proto-Danksharding 和 Danksharding - 兩種依序完成以太坊擴容的升級方案。" lang: zh-tw summaryPoints: - Danksharding 是一項多階段升級,旨在提升以太坊的可擴容性和容量。 @@ -11,50 +11,46 @@ summaryPoints: # Danksharding {#danksharding} -**Danksharding** 可讓以太坊成為真正可擴容的區塊鏈,但需要進行一些協定升級才能實現這一目標。 **Proto-Danksharding** 是該過程中的一個中間步驟。 兩者的目標都是讓二層網路上的交易對使用者來說盡可能便宜,並且應該將以太坊擴容到每秒處理 >100,000 筆交易。 +**Danksharding** 可讓以太坊成為真正可擴容的區塊鏈,但需要進行一些協定升級才能實現這一目標。 **Proto-Danksharding** 是此過程中的一個中間步驟。 兩者的目標都是讓二層網路上的交易對使用者來說盡可能便宜,並應將以太坊擴容至每秒可處理超過 100,000 筆交易。 ## 什麼是 Proto-Danksharding? {#what-is-protodanksharding} -Proto-Danksharding 又稱 [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844),是一種供[卷軸](/layer-2/#rollups)新增較低成本的資料到區塊的方法。 這個名稱來自提出這個想法的兩位研究人員:Protolambda 和 Dankrad Feist。 在歷史上,透過卷軸節省使用者交易的成本受到了限制,因為它們實際上會將其交易發佈到 `CALLDATA` 中。 +Proto-Danksharding,也稱為 [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844),是讓[卷軸](/layer-2/#rollups)以更便宜的方式將資料新增至區塊的方法。 這個名稱來自提出這個想法的兩位研究人員:Protolambda 和 Dankrad Feist。 過去,由於卷軸會將交易張貼在 `CALLDATA` 中,因此能為使用者降低的交易費用有限。 該成本非常高,因為資料由所有以太坊節點處理並永遠存在鏈上,即使卷軸只需要短暫使用這些資料。 Proto-Danksharding 引入了可傳送並附加到區塊的資料二進位大型物件。 這些二進位大型物件中的資料無法被以太坊虛擬機存取,並且會在一段固定時間(撰文時為 4096 個時期,或約 18 天)後自動刪除。 這表示卷軸可以更實惠地傳送資料,並以更實惠的交易形式將節省的費用轉給終端使用者。 - + 卷軸是指在鏈下批次處理交易,然後將結果發佈到以太坊以實現以太坊擴容。 卷軸有兩個必要元件:資料與執行檢查。 資料指卷軸處理的完整交易序列,用於產生發佈到以太坊的狀態變更。 執行檢查指讓某些誠實的參與者(「證明者」)重新執行這些交易,以確保提出的狀態變更正確無誤。 要完成執行檢查,交易資料可供使用的時間必須夠長,以讓任何人都能下載並檢查。 這意味著證明者可以識別並質疑卷軸排序者的任何不誠實行為。 然而,資料並不需要永久可用。 - - + 卷軸在鏈上發佈對其交易資料的承諾,並在資料二進位大型物件中提供實際資料。 這表示證明者可以確認承諾是否有效,或質疑其認為錯誤的資料。 在節點層面,資料的二進位大型物件儲存在共識用戶端中。 共識用戶端證明自己已經看過資料,且資料已在網路上傳播。 如果永久儲存資料,這些用戶端會膨脹並導致對運行節點的硬體要求過高。 反之,資料每 18 天會從節點中自動刪除。 共識用戶端的證明顯示證明者有足夠的機會驗證資料。 實際資料可由卷軸運營商、使用者或其他人儲存在鏈下。 - ### 如何驗證二進位大型物件資料? {#how-are-blobs-verified} -卷軸會將它們執行的交易發佈在資料二進位大型物件中。 它們還會發佈一則對資料的「承諾」。 它們透過將多項式函式與資料擬合來做到這一點。 之後可在任意點計算此函式。 舉例來說,若我們定義一個非常簡單的函式 `f(x) = 2x-1`,則可以計算出 `x = 1`、`x = 2`、`x = 3` 時對應的結果分別為 `1、3、5`。 證明者會將相同的函式套用到資料上,並在相同的點進行計算。 如果原始資料改變,函式將不相同,因此每個點的計算結果值也會不同。 事實上,承諾和證明會更複雜,因為它們被包裝到加密函式中。 +卷軸會將它們執行的交易發佈在資料二進位大型物件中。 它們還會發佈一則對資料的「承諾」。 它們透過將多項式函式與資料擬合來做到這一點。 之後可在任意點計算此函式。 舉例來說,若我們定義一個非常簡單的函式 `f(x) = 2x-1`,則可以計算出 `x = 1`、`x = 2`、`x = 3` 時對應的結果分別為 `1, 3, 5`。 證明者會將相同的函式套用到資料上,並在相同的點進行計算。 如果原始資料改變,函式將不相同,因此每個點的計算結果值也會不同。 事實上,承諾和證明會更複雜,因為它們被包裝到加密函式中。 ### 什麼是 KZG? {#what-is-kzg} -KZG 代表 Kate-Zaverucha-Goldberg,這是一種方案的三位[原作者](https://link.springer.com/chapter/10.1007/978-3-642-17373-8_11)名字縮寫,該方案將二進位大型物件資料縮小至不大的[加密「承諾」](https://dankradfeist.de/ethereum/2020/06/16/kate-polynomial-commitments.html)。 卷軸提交的資料二進位大型物件必須經過驗證,以確保卷軸不會出錯。 這涉及證明者重新執行二進位大型物件中的交易,以檢查承諾是否有效。 這與執行客戶端使用梅克爾證明來檢查一層網路上的以太坊交易是否有效,在概念上是相同的。 KZG 是將多項式方程與資料擬合的另一種證明。 承諾會在一些保密資料點計算多項式。 證明者將對資料擬合相同的多項式,並以相同數值進行計算,以確認結果是否相同。 這是一種驗證資料的方法,與某些卷軸所用的以及最終由以太坊協定的其他部分使用的零知識技術相容。 +KZG 是 Kate-Zaverucha-Goldberg 的縮寫,這是某個方案三位[原始作者](https://link.springer.com/chapter/10.1007/978-3-642-17373-8_11)的姓名,該方案可將資料 blob 縮減為一個小型的[密碼學「承諾」](https://dankradfeist.de/ethereum/2020/06/16/kate-polynomial-commitments.html)。 卷軸提交的資料二進位大型物件必須經過驗證,以確保卷軸不會出錯。 這涉及證明者重新執行二進位大型物件中的交易,以檢查承諾是否有效。 這與執行用戶端使用梅克爾證明來檢查一層網路上的以太坊交易是否有效,在概念上是相同的。 KZG 是將多項式方程與資料擬合的另一種證明。 承諾會在一些保密資料點計算多項式。 證明者將對資料擬合相同的多項式,並以相同數值進行計算,以確認結果是否相同。 這是一種驗證資料的方法,與某些卷軸所用的以及最終由以太坊協定的其他部分使用的零知識技術相容。 ### 什麼是 KZG 儀式? {#what-is-a-kzg-ceremony} -KZG 儀式提供了一種方法,讓以太坊社群中的許多人一起產生可用於驗證某些資料的秘密隨機數字字串。 此數字字串是未知的,且任何人都無法重新建立,這一點很重要。 為了確保這點,每位儀式參與者都會收到前一位參與者傳來的字串。 接著他們會建立一些新的隨機值(例如,透過允許瀏覽器測量滑鼠的移動),並將其與先前收到的值進行混合。 然後他們會把新值傳給下一位參與者,並從本地機器中銷毀這個值。 只要其中一個儀式參與者是誠實的,那麼攻擊者就無法知道最終的值。 +KZG 儀式提供了一種方法,讓以太坊社群中的許多人一起產生可用於驗證某些資料的秘密隨機數字字串。 此數字字串是未知的,且任何人都無法重新建立,這一點很重要。 為了確保這點,每位儀式參與者都會收到前一位參與者傳來的字串。 接著他們會建立一些新的隨機值 (例如,透過允許瀏覽器測量滑鼠的移動),並將其與先前收到的值進行混合。 然後他們會把新值傳給下一位參與者,並從本地機器中銷毀這個值。 只要其中一個儀式參與者是誠實的,那麼攻擊者就無法知道最終的值。 EIP-4844 KZG 儀式已向公眾開放,有數萬人參與並新增自己的隨機變量不確定性(隨機性)。 總共收到了超過 14 萬份貢獻,使其成為全球同類型儀式中規模最大的一次。 全部參與者都進行不誠實的行為,才可能破壞這個儀式。 站在參與者的視角,如果他們知道自己是誠實的,則不需要信任任何人,因為他們知道自己可確保儀式安全(他們自己已滿足 n 分之一誠實參與者的要求)。 - + 當卷軸在二進位大型物件中發佈資料時,會提供一則在鏈上發佈的「承諾」。 這項承諾是在某些點對資料進行多項式擬合計算的結果。 這些點由 KZG 儀式中產生的隨機數字定義。 然後,證明者可以在相同點計算多項式以驗證資料;如果得出的值相同,則資料是正確的。 - -如果有人知道用於承諾的隨機位置,他們就很容易產生能在這些特定點擬合的新多項式(即「碰撞」)。 這表示他們可以從二進位大型物件新增或移除資料,並且仍然提供有效的證明。 為了避免這種情況,實際上不是向證明者提供實際的秘密位置,證明者實際收到的是使用橢圓曲線包裝在加密「黑盒子」中的位置。 這些方法有效地擾亂了這些值,使原始值無法被逆向工程,但透過一些聰明的代數方法,證明者和驗證者仍然可以在其代表的點上計算多項式。 - +如果有人知道用於承諾的隨機位置,他們就很容易產生能在這些特定點擬合的新多項式 (即「碰撞」)。 這表示他們可以從二進位大型物件新增或移除資料,並且仍然提供有效的證明。 為了避免這種情況,實際上不是向證明者提供實際的秘密位置,證明者實際收到的是使用橢圓曲線包裝在加密「黑盒子」中的位置。 這些方法有效地擾亂了這些值,使原始值無法被逆向工程,但透過一些聰明的代數方法,證明者和驗證者仍然可以在其代表的點上計算多項式。 @@ -70,26 +66,24 @@ Danksharding 完全實現了從 Proto-Danksharding 開始的卷軸擴容。 Dank 提交者-建置者分離是為了防止單一驗證者必須為 32MB 的二進位大型物件資料產生昂貴的承諾和證明。 這為家庭質押者帶來很大的壓力,因為他們需要花費更多資金購買更強大的硬體,這會降低去中心化程度。 相反,專門的區塊建置者會負責這項昂貴的計算工作。 之後,區塊提交者即可廣播他們的區塊。 區塊提交者會直接選擇收益最大的區塊。 所有人都能經濟快速地驗證二進位大型物件,表示所有普通驗證者皆可檢查區塊建置者的行為是否誠實。 這允許在不犧牲去中心化的情況下處理大型二進位大型物件。 錯誤行事的區塊建置者可能被強制退出網路並罰沒,其他人會補上他的位置,因為區塊建置是高收益的活動。 - 驗證者需要進行資料可用性採樣才能快速有效地驗證二進位大型物件資料。 透過資料可用性採樣,驗證者可以非常確定二進位大型物件資料可用且正確提交。 每個驗證者都可以隨機採樣幾個資料點並建立證明,這意味著驗證者無需檢查整個二進位大型物件。 任何資料缺漏的情況都可被快速發現且二進位大型物件會遭拒。 - ### 目前進度 {#current-progress} -完整的 Danksharding 還需要幾年的時間才會實作。 在此期間,KZG 儀式已經結束,收到了超過 140,000 份貢獻,Proto-Danksharding 的[以太坊改善提案](https://eips.ethereum.org/EIPS/eip-4844)業已成熟。 此提案已在所有測試網上充分實作,並在 2024 年 3 月的 Cancun-Deneb(「坎昆」)網路升級中在主網上線。 +完整的 Danksharding 還需要幾年的時間才會實作。 在此同時,KZG 儀式已結束,收到超過 140,000 份貢獻,而針對 Proto-Danksharding 的 [EIP](https://eips.ethereum.org/EIPS/eip-4844) 也已成熟。 此提案已在所有測試網上充分實作,並在 2024 年 3 月的 Cancun-Deneb(「坎昆」)網路升級中在主網上線。 -### 了解更多 {#further-reading} +### 延伸閱讀 {#further-reading} -- [Proto-Danksharding 筆記](https://notes.ethereum.org/@vbuterin/proto_danksharding_faq) - _Vitalik Buterin_ -- [Dankrad 的 Danksharding 筆記](https://notes.ethereum.org/@dankrad/new_sharding) +- [Proto-Danksharding 常見問題](https://notes.ethereum.org/@vbuterin/proto_danksharding_faq) - _Vitalik Buterin_ +- [Dankrad 關於 Danksharding 的筆記](https://notes.ethereum.org/@dankrad/new_sharding) - [Dankrad、Proto 和 Vitalik 討論 Danksharding](https://www.youtube.com/watch?v=N5p0TB77flM) - [KZG 儀式](https://ceremony.ethereum.org/) -- [Carl Beekhuizen 在 Devcon 的可信任設定演講](https://archive.devcon.org/archive/watch/6/the-kzg-ceremony-or-how-i-learnt-to-stop-worrying-and-love-trusted-setups/?tab=YouTube) -- [關於二進位大型物件資料可用性採樣的更多資訊](https://hackmd.io/@vbuterin/sharding_proposal#ELI5-data-availability-sampling) -- [Dankrad Feist 的 KZG 承諾和證明演講](https://youtu.be/8L2C6RDMV9Q) +- [Carl Beekhuizen 在 Devcon 上關於可信設定的演講](https://archive.devcon.org/archive/watch/6/the-kzg-ceremony-or-how-i-learnt-to-stop-worrying-and-love-trusted-setups/?tab=YouTube) +- [更多關於 blob 的資料可用性取樣](https://hackmd.io/@vbuterin/sharding_proposal#ELI5-data-availability-sampling) +- [Dankrad Feist 談 KZG 承諾與證明](https://youtu.be/8L2C6RDMV9Q) - [KZG 多項式承諾](https://dankradfeist.de/ethereum/2020/06/16/kate-polynomial-commitments.html) diff --git a/public/content/translations/zh-tw/roadmap/dencun/index.md b/public/content/translations/zh-tw/roadmap/dencun/index.md index c7ce62c50d2..33379e5d210 100644 --- a/public/content/translations/zh-tw/roadmap/dencun/index.md +++ b/public/content/translations/zh-tw/roadmap/dencun/index.md @@ -1,6 +1,6 @@ --- -title: Cancun-Deneb(坎昆)升級常見問題解答 -description: 有關 Cancun-Deneb(坎昆)網路升級的常見問題 +title: "Cancun-Deneb(坎昆)升級常見問題解答" +description: "有關 Cancun-Deneb(坎昆)網路升級的常見問題" lang: zh-tw --- @@ -14,7 +14,7 @@ Cancun-Deneb(坎昆)是以太坊網路的一次升級,這項升級啟用 ## 我們預計什麼時候卷軸會反映出 Proto-Danksharding 帶來的較低費用? {#when} -- 本次升級時間為時期 269568,即\*\* 2024 年 03 月 13 日下午 13:55 (UTC)\*\* +- 本次升級時間為時期 269568,即** 2024 年 03 月 13 日下午 13:55 (UTC)** - 所有主要的卷軸提供者,例如 Arbitrum 或 Optimism,都已經表示在升級後將立即支援二進位大型物件。 - 單個卷軸支援的時間表可能有所不同,因爲每個提供者都必須升級其系統才能使用新的二進位大型物件空間。 @@ -49,12 +49,12 @@ Cancun-Deneb(坎昆)是以太坊網路的一次升級,這項升級啟用 - **第三方索引協定**,如 The Graph,透過由加密經濟機制激勵的節點營運者的去中心化網路來儲存這些資料。 - **BitTorrent**,這是一種去中心化協定,使志願者能夠保存該資料並將其分發給其他人。 -- \*\*[以太坊入口網路](/developers/docs/networking-layer/portal-network/)\*\*的目的是使用節點營運者去中心化網路,透過在參與者之分發資料(類似於 BitTorrent)來提供對所有以太坊資料的存取。 -- **個人使用者**始終可以自由地儲存其希望作爲歷史參考的任何資料的副本。 -- **卷軸提供者**在激勵的作用下儲存這些資料來提升其卷軸的使用者體驗。 -- **區塊瀏覽器**通常運行歸檔節點來索引和儲存全部這些資料,讓使用者能夠透過網路介面存取簡單的歷史參考。 +- [以太坊入口網路](/developers/docs/networking-layer/portal-network/)的目的是使用節點營運者去中心化網路,透過在參與者之分發資料(類似於 BitTorrent)來提供對所有以太坊資料的存取。 +- 個人使用者始終可以自由地儲存其希望作爲歷史參考的任何資料的副本。 +- 卷軸提供者在激勵的作用下儲存這些資料來提升其卷軸的使用者體驗。 +- 區塊瀏覽器通常運行歸檔節點來索引和儲存全部這些資料,讓使用者能夠透過網路介面存取簡單的歷史參考。 -需要注意的是,恢復歷史狀態是在 **1-of-N 信任模型**上運行的。 這意味著你只需要來自_單個可信任來源_的資料,就可以使用當前網路狀態驗證其正確性。 +需要注意的是,恢復歷史狀態是在 1-of-N 信任模型上運行的。 這意味著你只需要來自_單個可信任來源_的資料,就可以使用當前網路狀態驗證其正確性。 ## 這項升級對更廣泛的以太坊開發藍圖有哪些貢獻? {#roadmap-impact} @@ -68,9 +68,9 @@ Proto-Danksharding 爲 [Danksharding](/roadmap/danksharding/) 的完全實作奠 共識用戶端處理_驗證者_軟體,這類軟體已全部更新以支援這項升級。 -## Cancun-Deneb(坎昆)升級是否對 Goerli 或其他以太坊測試網有影響? {#testnet-impact} +## Cancun-Deneb(Dencun)升級是否對以太坊測試網有影響? {#testnet-impact} -- Devnets、Goerli、Sepolia 和 Holesky 測試網都已經完成了坎昆升級,同時 Proto-Danksharding 已經全面運行 +- Devnets、Sepolia 和 Holesky 測試網都已經完成了 Dencun 升級,同時 Proto-Danksharding 已經全面運行 - 卷軸開發者可使用這些網路進行 EIP-4844 測試。 - 大多數的使用者完全不會受到此測試網變更的影響。 diff --git a/public/content/translations/zh-tw/roadmap/fusaka/index.md b/public/content/translations/zh-tw/roadmap/fusaka/index.md new file mode 100644 index 00000000000..918cf4872fc --- /dev/null +++ b/public/content/translations/zh-tw/roadmap/fusaka/index.md @@ -0,0 +1,300 @@ +--- +title: Fulu-Osaka (Fusaka) +description: "瞭解Fusaka協議升級" +lang: zh-tw +--- + +# Fusaka {#fusaka} + +**備受期待的以太坊 Fusaka 升級已於 2025 年 12 月 3 日上線** + +Fusaka 網路升級緊接在 [Pectra](/roadmap/pectra/) 之後推出,為每位以太坊用戶與開發者帶來更多新功能並提升使用體驗。 該名稱由執行層升級版「大阪」與以福祿星命名的共識層版本組成。 以太坊的兩大組件皆獲得升級,將以太坊的擴展性、安全性與使用者體驗推向未來。 + + + + +Fusaka 升級僅是以太坊長期發展目標中的單一步驟。 深入了解[協議開發藍圖](/roadmap/)與[過往升級紀錄](/ethereum-forks/)。 + + + + +## Fusaka的改進 {#improvements-in-fusaka} + +### 擴展 blob {#scale-blobs} + +#### 點對點資料可用性取樣(Peer Data Availability Sampling, PeerDAS) {#peerdas} + +這是 Fusaka 分叉的_主打功能_,也是此次升級新增的主要特性。 第二層解決方案目前將其資料以 blob 形式發佈至以太坊,這種短暫性資料類型是專為第二層解決方案所創建。 在Fusaka之前,每個完整節點都必須儲存每個數據塊,以確保資料確實存在。 隨著資料塊吞吐量增加,必須下載所有這些資料的操作將變得資源消耗過於龐大而難以承受。 + +透過[資料可用性採樣](https://notes.ethereum.org/@fradamt/das-fork-choice),各節點無需儲存所有大物件資料,而是各自負責其中一部分。 數據塊在網絡節點間均勻隨機分布,每個完整節點僅存儲八分之一數據,因此理論上可擴展至八倍規模。 為確保資料可用性,任何資料片段均可透過現有資料的 50% 進行重建,所採用的方法能將資料錯誤或缺失的機率降至密碼學意義上可忽略的水平(約 1020 至 1024 分之一)。 + +此設計使節點的硬體與頻寬需求維持在可控範圍,同時實現大塊資料擴展,從而為第二層解決方案帶來更大規模的擴展能力,並降低相關費用。 + +[了解更多關於 PeerDAS](/roadmap/fusaka/peerdas/) + +**資源**: + +- [EIP-7594 技術規範](https://eips.ethereum.org/EIPS/eip-7594) +- [DappLion 談 PeerDAS:今日擴展以太坊 | ETHSofia 2024](https://youtu.be/bONWd1x2TjQ?t=328) +- [學術:以太坊 PeerDAS 的文件 (PDF)](https://eprint.iacr.org/2024/1362.pdf) + +#### 僅限 Blob 參數的分叉 {#blob-parameter-only-forks} + +Layer 2s負責擴展以太坊:隨著這些網絡的成長,它們會需要提交更多的數據給以太坊。 這代表隨著時間推進,以太坊需要逐步增加可供這些網路使用的blobs數量。 儘管PeerDAS能夠讓blob數據具備更高的擴展性,但這個過程必須循序漸進且安全地完成。 + +由於以太坊是在數千個獨立節點上運行的程式碼,這些節點需要在相同的規則上達成共識,因此我們無法像部署網站更新一樣,簡單地引入增加 blob 數量等變更。 任何規則變更都必須是協調升級,要求所有節點、用戶端及驗證者軟體在預定區塊之前完成升級。 + +這些協調升級通常包含大量變更,需要大量測試,而這需要時間。 為了快速因應Layer2不斷變化的blob需求,blob參數限定分叉引入了一種機制,可以在不需要等待正式升級時程的情況下,直接新增可用的blob數量。 + +Blob參數限定分叉可以由用戶端自行設定,與gas限制的配置方式類似。 在以太坊重大升級之間,用戶端可協商將`目標的`與`最大的`區塊大小分別提升至例如9與12,隨後節點運營者將更新軟體以參與該微小分叉。 這些blob參數限定分叉可以在任何時間進行設定。 + +在 Dencun 升級中首次將 blob 新增至網路時,目標是 3 個。 在 Pectra 升級中增加到 6 個,而在 Fusaka 升級後,現在可以獨立於這些主要網路升級,以可持續的速率增加。 + +![圖表顯示每個區塊的平均 blob 數量以及隨升級而增加的目標](./average-blob-count-per-block.webp) + +圖表來源:[Ethereum Blobs - @hildobby, Dune Analytics](https://dune.com/hildobby/blobs) + +**資源**:[EIP-7892 技術規範](https://eips.ethereum.org/EIPS/eip-7892) + +#### Blob 的基礎費用以執行成本為上限 {#blob-base-fee-bounded-by-execution-costs} + +第二層協議在發布資料時需支付兩項費用:資料塊費用以及驗證這些資料塊所需的執行燃料費用。 若執行 Gas 主導市場,區塊拍賣費可能螺旋式下跌至 1 wei,進而喪失價格信號功能。 + +EIP-7918 為每個blob設定了一個按比例計算的保留價格。 當儲備高於名目 blob 基本費用時,費用調整演算法會將該區塊視為超出目標,停止壓低費用,並允許其正常增加。 因此: + +- blob費用市場會隨著網路的擁塞情況作出反應 +- layer 2s 必須為自己帶給節點的運算壓力,支付相應比例的費用 +- 執行層的基礎費用即使出現劇烈上升,也不會再讓blob費用卡在1wei + +**資源**: + +- [EIP-7918 技術規範](https://eips.ethereum.org/EIPS/eip-7918) +- [Storybook 解說](https://notes.ethereum.org/@anderselowsson/AIG) + +### 擴展 Layer 1 {#scale-l1} + +#### 歷史紀錄到期與更簡易的收據 {#history-expiry} + +在 2025 年 7 月,以太坊執行用戶端[開始支援部分歷史紀錄到期](https://blog.ethereum.org/2025/07/08/partial-history-exp)。 隨著以太坊不斷成長,此舉會捨棄比[合併](https://ethereum.org/roadmap/merge/)更早的歷史紀錄,以減少節點營運商所需的磁碟空間。 + +此 EIP 位於「核心 EIP」之外的章節,因為此分叉實際上未實作任何變更——它是一項通知,要求用戶端團隊必須在 Fusaka 升級前支援歷史紀錄到期。 實際上,用戶端可以隨時實作此功能,但將其新增至升級中,具體地將其納入其待辦清單,並讓他們能結合此功能測試 Fusaka 的變更。 + +**資源**:[EIP-7642 技術規範](https://eips.ethereum.org/EIPS/eip-7642) + +#### 設定MODEXP上限值 {#set-upper-bounds-for-modexp} + +目前為止,MODEXP的預編譯合約可以接受幾乎任何大小的數字。 這讓它難以測試、容易被濫用並對用戶端的穩定性帶來風險。 EIP-7823界定了明確的上限:每個輸入數值的長度最多為8192位元(1024個字節位元組)。 超過上限的輸入會被拒絕,該筆交易的gas仍會被燃燒,但不會變更任何狀態。 此上限足以涵蓋實務需求,同時排除那些讓gas上限設定與安全性審查變得複雜的極端情況。 這項調整在不影響用戶及開發者體驗的前提下,強化了安全性與抗阻斷服務的能力(DoS;Denial of Service)。 + +**資源**:[EIP-7823 技術規範](https://eips.ethereum.org/EIPS/eip-7823) + +#### GAS交易上限 {#transaction-gas-limit-cap} + +EIP-[7825](https://eips.ethereum.org/EIPS/eip-7825) 為每筆交易新增了 16,777,216 (2^24) 的 gas 上限。 當我們提高區塊燃料限制時,這是透過限制單一交易的最壞情況成本來進行的主動式 DoS 強化。 它讓驗證和傳播更容易模型化,使我們能夠透過提高燃料限制來處理擴張問題。 + +為什麼剛好是 2^24 gas? 它比目前的燃料限制小很多,但足以應付實際的合約部署和大量的預編譯,而且 2 的次方使其易於在各種用戶端上實作。 這個新的最大交易大小與 Pectra 之前的平均區塊大小相似,使其成為以太坊上任何操作的合理限制。 + +**資源**:[EIP-7825 技術規範](https://eips.ethereum.org/EIPS/eip-7825) + +#### 增加 `MODEXP` 的 gas 成本 {#modexp-gas-cost-increase} + +MODEXP 是一個預編譯的內建函式,用於計算模組化指數,這是一種用於 RSA 簽章驗證和證明系統的大數運算。 它允許合約直接執行這些計算,而無需自行實作。 + +開發人員和用戶端團隊將 MODEXP 視為增加區塊燃料限制的主要障礙,因為目前的 gas 定價通常低估了某些輸入所需的計算能力。 這意味著一筆使用 MODEXP 的交易可能會佔用處理整個區塊所需的大部分時間,從而減慢網路速度。 + +此 EIP 透過以下方式變更定價以符合實際計算成本: + +- 將最低費用從 200 gas 提高到 500 gas,並移除 EIP-2565 中對一般成本計算的三分之一折扣 +- 當指數輸入非常長時,更大幅度地增加成本。 如果指數(您作為第二個參數傳遞的「次方」數字)長度超過 32 位元組/256 位元,則每增加一個位元組,gas 費用會更快地攀升 +- 對較大的底數或模數也收取額外費用。 其他兩個數字(底數和模數)假設至少為 32 位元組——如果其中任何一個更大,成本將與其大小成比例增加 + +透過讓成本更符合實際處理時間,MODEXP 不再會導致區塊驗證時間過長。 這項變更是為了未來安全地增加以太坊的區塊燃料限制而進行的幾項變更之一。 + +**資源**:[EIP-7883 技術規範](https://eips.ethereum.org/EIPS/eip-7883) + +#### RLP 執行區塊大小限制 {#rlp-execution-block-size-limit} + +這為區塊允許的大小設定了上限——這是對透過網路_傳送_的內容的限制,與限制區塊內_工作量_的燃料限制是分開的。 區塊大小上限為 10 MiB,並為共識資料保留了少量空間(2 MiB),以確保所有內容都能完全容納並順利傳播。 如果出現的區塊大於該限制,用戶端會拒絕它。 +這是必要的,因為非常大的區塊需要更長的時間在網路上傳播和驗證,並可能產生共識問題或被濫用為 DoS 攻擊媒介。 此外,共識層的 gossip 協議已經不會轉發超過約 10 MiB 的區塊,因此將執行層與該限制對齊,可以避免「某些節點看到,但其他節點丟棄」的奇怪情況。 + +具體細節:這是對 [RLP](/developers/docs/data-structures-and-encoding/rlp/) 編碼的執行區塊大小的上限。 總共 10 MiB,其中 2 MiB 的安全邊際保留給信標區塊框架。 實際上,用戶端定義 + +`MAX_BLOCK_SIZE = 10,485,760` 位元組,以及 + +`SAFETY_MARGIN = 2,097,152` 位元組, + +並拒絕任何 RLP 負載超過以下限制的執行區塊 + +`MAX_RLP_BLOCK_SIZE = MAX_BLOCK_SIZE − SAFETY_MARGIN` + +目標是限制最壞情況下的傳播/驗證時間,並與共識層的 gossip 行為保持一致,在不改變 gas 核算的情況下降低重組/DoS 風險。 + +**資源**:[EIP-7934 技術規範](https://eips.ethereum.org/EIPS/eip-7934) + +#### 將預設燃料限制設定為 6000 萬 {#set-default-gas-limit-to-60-million} + +在 2025 年 2 月將燃料限制從 3000 萬提高到 3600 萬(以及後續提高到 4500 萬)之前,這個值自合併(2022 年 9 月)以來就沒有改變過。 此 EIP 的目標是將一致性的擴容能力列為優先事項。 + +EIP-7935 協調執行層用戶端團隊,為 Fusaka 升級將預設燃料限制提高到目前的 4500 萬以上。 這是一份資訊性 EIP,但它明確要求用戶端在開發網路上測試更高的限制,就一個安全的值達成共識,並在他們的 Fusaka 版本中發布該數值。 + +開發網路規劃的目標是約 6000 萬的壓力(帶有合成負載的完整區塊)和迭代提升;研究表明,最壞情況下的區塊大小病態不應在約 1.5 億以下受到限制。 推出時應與交易燃料限制上限(EIP-7825)配對,這樣隨著限制的提高,就不會有單一交易佔主導地位。 + +**資源**:[EIP-7935 技術規範](https://eips.ethereum.org/EIPS/eip-7935) + +### 改善使用者體驗 {#improve-ux} + +#### 確定性 proposer lookahead {#deterministic-proposer-lookahead} + +透過 EIP-7917,信標鏈將能夠知道下一個 epoch 的區塊提議者。 對於哪些驗證者將提議未來的區塊有確定性的視圖,可以實現[預先確認](https://ethresear.ch/t/based-preconfirmations/17353)——這是一種與即將到來的提議者所做的承諾,保證使用者交易將被包含在他們的區塊中,而無需等待實際的區塊。 + +此功能有益於用戶端實作和網路安全,因為它能防止驗證者可能操縱提議者排程的極端情況。 這種預先查看也降低了實作的複雜度。 + +**資源**:[EIP-7917 技術規範](https://eips.ethereum.org/EIPS/eip-7917) + +#### 計算前導零 (CLZ) 操作碼 {#count-leading-zeros-opcode} + +此功能新增了一個小型的 EVM 指令,**計算前導零 (CLZ)**。 EVM 中的絕大多數東西都表示為 256 位元的值——這個新的操作碼會回傳開頭有多少個零位元。 這是許多指令集架構的常見特性,因為它能實現更高效的算術運算。 在實務上,這將目前手動編寫的位元掃描壓縮成一個步驟,因此尋找第一個設定位元、掃描位元組或解析位元欄位變得更簡單、更便宜。 該操作碼成本低且固定,經基準測試與基本的加法運算相當,這可以精簡位元組碼並為相同的工作節省 gas。 + +**資源**:[EIP-7939 技術規範](https://eips.ethereum.org/EIPS/eip-7939) + +#### 支援 secp256r1 曲線的預編譯 {#secp256r1-precompile} + +在固定位址 `0x100` 引入一個內建的、通行金鑰風格的 secp256r1 (P-256) 簽章檢查器,使用許多 Layer 2 已經採用的相同呼叫格式並修復極端情況,因此為這些環境編寫的合約無需修改即可在 Layer 1 上運作。 + +使用者體驗升級! 對使用者而言,這解鎖了裝置原生簽署和通行金鑰。 錢包可以直接利用 Apple Secure Enclave、Android Keystore、硬體安全模組 (HSM) 和 FIDO2/WebAuthn——無需助記詞、更流暢的入門流程,以及感覺像現代應用程式的多重要素流程。 這帶來了更好的使用者體驗、更容易的復原,以及與數十億台裝置已在執行的模式相符的帳戶抽象模式。 + +對開發人員而言,它接收一個 160 位元組的輸入並回傳一個 32 位元組的輸出,使得移植現有的函式庫和 Layer 2 合約變得容易。 在底層,它包含無窮遠點和模組化比較檢查,以消除棘手的極端情況,而不會破壞有效的呼叫者。 + +**資源**: + +- [EIP-7951 技術規範](https://eips.ethereum.org/EIPS/eip-7951) +- [關於 RIP-7212 的更多資訊](https://www.alchemy.com/blog/what-is-rip-7212) _(請注意,EIP-7951 已取代 RIP-7212)_ + +### 元資訊 {#meta} + +#### `eth_config` JSON-RPC 方法 {#eth-config} + +這是一個 JSON-RPC 呼叫,可讓您詢問您的節點正在執行什麼分叉設定。 它會回傳三個快照:`current`、`next` 和 `last`,以便驗證者和監控工具可以驗證用戶端是否已為即將到來的分叉做好準備。 + +實際上,這是為了解決在 2025 年初 Pectra 分叉於 Holesky 測試網上線時,因輕微的設定錯誤導致非最終化狀態而發現的缺點。 這有助於測試團隊和開發人員確保,在從開發網路移至測試網,以及從測試網移至主網時,主要分叉的行為將如預期般運作。 + +快照包括:`chainId`、`forkId`、計畫的分叉啟動時間、哪些預編譯是作用中的、預編譯位址、系統合約相依性,以及分叉的 blob 排程。 + +此 EIP 位於「核心 EIP」之外的章節,因為此分叉實際上未實作任何變更——它是一項通知,要求用戶端團隊必須在 Fusaka 升級前實作此 JSON-RPC 方法。 + +**資源**:[EIP-7910 技術規範](https://eips.ethereum.org/EIPS/eip-7910) + +## 常見問題 {#faq} + +### 這次的升級是否會影響到所有以太坊節點和驗證者? {#does-this-upgrade-affect-all-ethereum-nodes-and-validators} + +是的,Fusaka升級需要同時更新[執行節點與共識節點](/developers/docs/nodes-and-clients/)。 所有主要的以太坊用戶端都會發行支援標示為高優先級的強分叉版本。 您可透過以下管道掌握這些版本的發布時程:用戶端 GitHub 儲存庫、其 [Discord 頻道](https://ethstaker.org/support)、[EthStaker Discord](https://dsc.gg/ethstaker),或訂閱以太坊部落格以獲取協議更新資訊。 爲了在升級之後與以太坊網路保持同步,節點營運者需要確保其運行的是受支援的用戶端版本。 請注意,關於用戶端版本的資訊具有時效性,使用者應該參考最新資訊以取得最新詳細資料。 + +### 硬分叉之後以太幣該如何兌換? {#how-can-eth-be-converted-after-the-hardfork} + +- **您的 ETH 無需任何操作**:隨著以太坊Fusaka 升級完成,您無需轉換或升級您的 ETH。 你的帳戶餘額將維持不變,同時你目前持有的以太幣在硬分叉之後,仍將保持以現有的形式存取。 +- **謹防詐騙!**  **任何要求你「升級」你的以太幣的人都是在嘗試欺騙你。** 本次升級你無須進行任何操作。 你的資產將完全不受影響。 請記住,隨時瞭解情況是防範詐騙的最佳方法。 + +[關於辨識和避免詐騙的更多資訊](/security/) + +### 斑馬是怎麼回事? {#whats-with-the-zebras} + +斑馬是 Fusaka 開發人員選擇的「吉祥物」,因為其條紋反映了 PeerDAS 的基於欄位的資料可用性取樣,其中節點保管某些欄位子網路,並從每個同儕的時槽中取樣一些其他欄位,以檢查 blob 資料是否可用。 + +2022 年的合併[使用貓熊](https://x.com/hwwonx/status/1431970802040127498)作為吉祥物,以象徵執行層與共識層的結合。 從那時起,每個分叉都非正式地選擇了吉祥物,並在升級時以 ASCII 藝術的形式出現在用戶端日誌中。 這只是一種有趣的慶祝方式。 + +### 為 Layer 2 擴展納入了哪些改進? {#what-improvements-are-included-for-l2-scaling} + +[PeerDAS](/roadmap/fusaka/peerdas) 是此分叉的主要功能。 它實作了資料可用性取樣 (DAS),為 rollup 解鎖了更多可擴展性,理論上可將 blob 空間擴展至目前大小的 8 倍。 Blob 費用市場也將得到改善,以有效應對壅塞,並保證 Layer 2 為 blob 對節點施加的計算和空間支付有意義的費用。 + +### BPO 分叉有何不同? {#how-are-bpo-forks-different} + +僅限 Blob 參數的分叉提供了一種機制,在 PeerDAS 啟動後,可以持續增加 blob 數量(目標和最大值),而無需等待完整的協調升級。 每次增加都在支援 Fusaka 的用戶端版本中以硬編碼方式預先設定。 + +作為使用者或驗證者,您無需為每個 BPO 更新您的用戶端,只需確保跟隨像 Fusaka 這樣的主要硬分叉。 這與之前的做法相同,無需特殊操作。仍然建議在升級和 BPO 期間監控您的用戶端,並在主要版本之間保持更新,因為修復或最佳化可能會在硬分叉之後推出。 + +### BPO 的排程是什麼? {#what-is-the-bpo-schedule} + +BPO 更新的確切排程將隨著 Fusaka 版本而確定。 請關注[協議公告](https://blog.ethereum.org/category/protocol)和您用戶端的版本說明。 + +可能的範例如下: + +- Fusaka 之前:目標 6,最大 9 +- Fusaka 啟動時:目標 6,最大 9 +- BPO1,Fusaka 啟動後幾週:目標 10,最大 15,增加三分之二 +- BPO2,BPO1 後幾週:目標 14,最大 21 + +### 這會降低以太坊 (Layer 1) 的費用嗎 {#will-this-lower-gas} + +此次升級不會降低 Layer 1 的 gas 費用,至少不會直接降低。 主要重點是為 rollup 資料提供更多 blob 空間,從而降低 Layer 2 的費用。 這可能會對 Layer 1 費用市場產生一些副作用,但預計不會有重大變化。 + +### 作為質押者,我需要為這次升級做些什麼? {#as-a-staker-what-do-i-need-to-do-for-the-upgrade} + +與每次網路升級一樣,請確保將您的用戶端更新到標有 Fusaka 支援的最新版本。 關注郵件清單中的更新和 [EF 部落格上的協議公告](https://blog.ethereum.org/category/protocol),以獲取有關版本的資訊。 +在 Fusaka 於主網上啟動之前,您可以在測試網上執行一個驗證者來驗證您的設定。 Fusaka [在測試網上會更早啟動](https://blog.ethereum.org/2025/09/26/fusaka-testnet-announcement),讓您有更多時間確保一切正常並回報錯誤。 測試網分叉也會在郵件清單和部落格中宣布。 + +### 「確定性提案者預先查看」(EIP-7917) 會影響驗證者嗎? {#does-7917-affect-validators} + +此變更不會改變您驗證者用戶端的功能,但是,它將提供更多關於您驗證者職責未來的資訊。 請務必更新您的監控工具,以跟上新功能。 + +### Fusaka 如何影響節點和驗證者的頻寬要求? {#how-does-fusaka-affect-bandwidth-requirements-for-nodes-and-validators} + +PeerDAS 在節點傳輸 blob 資料的方式上做出了重大改變。 所有資料都被劃分為稱為「欄」的片段,分布在 128 個子網路中,節點只訂閱其中一部分。 節點必須保管的子網路欄位數量取決於其設定和連接的驗證者數量。 實際頻寬要求將取決於網路中允許的 blob 數量和節點類型。 在 Fusaka 啟動時,blob 目標保持不變,但透過 PeerDAS,節點營運商可能會看到其 blob 的磁碟使用量和網路流量有所減少。 隨著 BPO 在網路中設定更高的 blob 數量,所需頻寬將隨著每個 BPO 而增加。 + +即使在 Fusaka BPO 之後,節點要求仍在[建議的範圍內](https://eips.ethereum.org/EIPS/eip-7870)。 + +#### 完整節點 {#full-nodes} + +沒有任何驗證者的普通節點將只訂閱 4 個子網路,為原始資料的 1/8 提供保管。 這意味著在相同 blob 資料量的情況下,節點下載它們的頻寬將減少八 (8) 倍。 對於一個正常的完整節點,blob 的磁碟使用量和下載頻寬可能會減少約 80%,僅剩幾 MB。 + +#### 單獨質押者 {#solo-stakers} + +如果該節點用於驗證者用戶端,它必須保管更多欄位,因此需要處理更多資料。 新增驗證者後,節點至少訂閱 8 個欄位子網路,因此處理的資料量是普通節點的兩倍,但仍比 Fusaka 之前少。 如果驗證者餘額超過 287 ETH,將會訂閱越來越多的子網路。 + +對於單獨質押者來說,這意味著他們的磁碟使用量和下載頻寬將減少約 50%。 然而,要在本機建立區塊並將所有 blob 上傳到網路,需要更高的上傳頻寬。 在 Fusaka 時期,本機建立者將需要比以前高 2-3 倍的上傳頻寬,而在 BPO2 的 15/21 blob 目標下,最終必要的上傳頻寬將必須高出約 5 倍,達到 100Mbps。 + +#### 大型驗證者 {#large-validators} + +隨著更多餘額和驗證者新增到節點,訂閱的子網路數量也會增加。 例如,在約 800 ETH 餘額時,節點保管 25 個欄位,將需要比以前多約 30% 的下載頻寬。 必要的上傳量與普通節點相似,至少需要 100Mbps。 + +在 4096 ETH 時,即 2 個最大餘額的驗證者,節點變為「超級節點」,保管所有欄位,因此下載和儲存所有內容。 這些節點透過回饋遺失的資料來主動修復網路,但也需要更高的頻寬和儲存空間。 隨著最終 blob 目標比以前高 6 倍,超級節點將需要額外儲存約 600GB 的 blob 資料,並擁有更快的持續下載頻寬,約為 20Mbps。 + +[閱讀更多關於預期要求的詳細資訊。](https://ethpandaops.io/posts/fusaka-bandwidth-estimation/#theoretical-requirements) + +### 實作了哪些 EVM 變更? {#what-evm-changes-are-implemented} + +Fusaka 透過新的微小變更和功能鞏固了 EVM。 + +- 為了在擴展時保障安全,單一交易的最大大小將[限制為 1670 萬](https://eips.ethereum.org/EIPS/eip-7825) gas 單位。 +- [新的操作碼計算前導零 (CLZ)](https://eips.ethereum.org/EIPS/eip-7939) 已新增至 EVM,將使智慧合約語言能夠更有效率地執行某些操作。 +- [`ModExp` 預編譯的成本將會增加](https://eips.ethereum.org/EIPS/eip-7883)——使用它的合約將收取更多的執行 gas。 + +### 新的 1600 萬 gas 限制對合約開發者有何影響? {#how-does-new-16m-gas-limit-affects-contract-developers} + +Fusaka 引入了一個限制,[將單一交易的最大大小限制為 1670 萬](https://eips.ethereum.org/EIPS/eip-7825) (2^24) gas 單位。 這大約是先前平均區塊的大小,使其足以容納會消耗整個區塊的複雜交易。 這個限制為用戶端提供了保護,防止未來在區塊燃料限制提高時潛在的 DoS 攻擊。 擴展的目標是讓更多交易進入區塊鏈,而不會有單一交易消耗整個區塊。 + +一般使用者交易遠未達到此限制。 某些極端情況,如大型複雜的 DeFi 操作、大型智慧合約部署或針對多個合約的批次交易,可能會受此變更影響。 這些交易將必須被分割成較小的交易或以其他方式進行最佳化。 在提交可能達到限制的交易之前,請使用模擬功能。 + +RPC 方法 `eth_call` 沒有限制,將允許模擬比實際區塊鏈限制更大的交易。 RPC 方法的實際限制可由用戶端營運商設定,以防止濫用。 + +### CLZ 對開發者意味著什麼? {#what-clz-means-for-developers} + +像 Solidity 這樣的 EVM 編譯器將在底層實作和利用這個新的計算零的功能。 如果新合約依賴此類操作,可能會從中節省 gas。 請關注智慧合約語言的版本和功能公告,以了解有關潛在節省的文件。 + +### 我現有的智慧合約會有任何變更嗎? {#what-clz-means-for-developers} + +Fusaka 沒有會破壞任何現有合約或改變其行為的直接影響。 對執行層的變更是為了向後相容而設計的,然而,請務必留意極端情況和潛在影響。 + +[隨著 `ModExp` 預編譯成本的增加](https://eips.ethereum.org/EIPS/eip-7883),依賴它的合約將消耗更多的執行 gas。 如果您的合約嚴重依賴此功能並且對使用者來說變得更昂貴,請重新考慮其使用方式。 + +如果執行您的合約的交易可能達到類似的大小,請考慮[新的 1670 萬限制](https://eips.ethereum.org/EIPS/eip-7825)。 + +## 延伸閱讀 {#further-reading} + +- [以太坊開發藍圖](/roadmap/) +- [Forkcast: Fusaka](https://forkcast.org/upgrade/fusaka) +- [Fusaka Meta EIP](https://eips.ethereum.org/EIPS/eip-7607) +- [Fusaka 測試網部落格公告](https://blog.ethereum.org/2025/09/26/fusaka-testnet-announcement) +- [Bankless: What Fusaka & Pectra will bring Ethereum](https://www.bankless.com/read/what-fusaka-pectra-will-bring-ethereum) +- [Bankless: Ethereum's Next Upgrades: Fusaka, Glamsterdam & Beyond with Preston Van Loon](https://x.com/BanklessHQ/status/1956017743289020633?t=502) +- [The Fusaka Files](https://www.youtube.com/playlist?list=PL4cwHXAawZxpz-erUbKKUnnGoQNdF8s7Z) +- [PEEPanEIPs 解說](https://www.youtube.com/playlist?list=PL4cwHXAawZxoIenfk7OJry4rxcqX-eqBt) diff --git a/public/content/translations/zh-tw/roadmap/fusaka/peerdas/index.md b/public/content/translations/zh-tw/roadmap/fusaka/peerdas/index.md new file mode 100644 index 00000000000..c8b482b9823 --- /dev/null +++ b/public/content/translations/zh-tw/roadmap/fusaka/peerdas/index.md @@ -0,0 +1,88 @@ +--- +title: PeerDAS +description: "作為 Fusaka 以太坊協議升級的一部分,了解 PeerDAS" +lang: zh-tw +--- + +# 點對點資料可用性取樣(Peer Data Availability Sampling, PeerDAS) {#peer-das} + +自從 [透過 EIP-4844 引入 blob 交易](/roadmap/danksharding/) 以來,以太坊協議正在進行其最重要的擴張升級。 作為 [Fusaka 升級](/roadmap/fusaka/) 的一部分,PeerDAS 引入了一種處理 blob 資料的新方法,為 Layer 2 的 **[資料可用性 (DA)](/developers/docs/data-availability/)** 容量帶來了約一個數量級的增長。 + +[關於 blob 擴張開發藍圖的更多資訊](https://blog.ethereum.org/2025/08/22/protocol-update-002) + +## 可擴展性 {#scalability} + +以太坊的願景是成為一個中立、安全、去中心化的平台,供世界上每個人使用。 隨著網路用量增長,需要在網路的擴張性、安全性和去中心化這三難困境之間取得平衡。 如果以太坊僅在其當前設計中增加網路處理的資料量,則可能會壓垮 [以太坊賴以實現去中心化的節點](/developers/docs/nodes-and-clients/)。 可擴展性需要嚴謹的機制設計,以盡量減少權衡取捨。 + +實現此目標的策略之一是允許多樣化的 Layer 2 擴張解決方案生態系統,而不是在 [Layer 1 (L1)](/glossary/#layer-1) 主網上處理所有交易。 [Layer 2 (L2)](/glossary/#layer-2) 或 [Rollup](/glossary#rollups) 在其各自的獨立鏈上處理交易,並使用以太坊進行驗證和保障安全。 僅發布對安全至關重要的承諾並壓縮負載,讓 L2 更有效地使用以太坊的資料可用性容量。 反過來,L1 承載的資料更少,且不影響安全保證,而 L2 則能以更低的 Gas 成本吸引更多使用者。 最初,L2 將資料作為 `calldata` 發布在普通交易中,這會與 L1 交易爭奪 Gas,對於大量資料的可用性來說並不實用。 + +## Proto-Danksharding {#proto-danksharding} + +擴張 L2 的第一個重要步驟是 Dencun 升級,它引入了 [原型 Danksharding](/roadmap/danksharding/) (EIP-4844)。 這次升級為 Rollup 創造了一種新的專用資料類型,稱為 blob。 [Blob](/developers/docs/data-availability/blockchain-data-storage-strategies/#eip-4844-blobs) (二進位大型物件) 是任意資料的短暫片段,不需要 EVM 執行,節點只會儲存有限的時間。 這種更高效的處理方式讓 L2 能夠向以太坊發布更多資料,並進一步擴張。 + +儘管使用 blob 對於擴張已經有很大的好處,但這只是最終目標的一部分。 在目前的協議中,網路中的每個節點仍然需要下載每個 blob。 瓶頸在於單一節點所需的頻寬,隨著 blob 數量的增加,需要下載的資料量也直接增加。 + +以太坊在去中心化方面毫不妥協,而頻寬是最敏感的調節因素之一。 即使任何負擔得起的人都能廣泛使用強大的計算能力,但在已開發國家的都會區 (例如[德國](https://www.speedtest.net/global-index/germany)、[比利時](https://www.speedtest.net/global-index/belgium)、[澳洲](https://www.speedtest.net/global-index/australia)或[美國](https://www.speedtest.net/global-index/united-states)),[上傳頻寬的限制](https://www.speedtest.net/global-index)若未經仔細調整,可能會導致節點只能在資料中心運行。 + +隨著 blob 增加,節點營運商對頻寬和磁碟空間的要求也越來越高。 blob 的大小和數量受到這些限制。 每個 blob 最多可承載 128kb 的資料,平均每個區塊有 6 個 blob。 這只是邁向未來更有效利用 blob 設計的第一步。 + +## 資料可用性抽樣 {#das} + +資料可用性是確保所有獨立驗證鏈所需的資料對所有網路參與者都可存取。 它確保資料已完全發布,並可用於無信任地驗證鏈的新狀態或傳入的交易。 + +以太坊 blob 提供了強大的資料可用性保證,確保了 L2 的安全性。 為此,以太坊節點需要完整下載並儲存 blob。 但是,如果我們能更有效地在網路中分發 blob 並避免此限制呢? + +儲存資料並確保其可用性的另一種方法是 **資料可用性抽樣 (DAS)**。 DAS 引入了去中心化的分工,而不是讓每台運行以太坊的電腦都完整儲存每個 blob。 它透過將較小、可管理的任務分發到整個節點網路中,來分擔處理資料的負擔。 Blob 被分成多個片段,每個節點使用一個在所有節點間均勻隨機分佈的機制,只下載幾個片段。 + +這帶來了一個新問題——證明資料的可用性和完整性。 當個別節點只持有小片段時,網路如何保證資料可用且全部正確? 惡意節點可能會提供假資料,輕易地破壞強大的資料可用性保證! 這就是密碼學發揮作用的地方。 + +為確保資料的完整性,EIP-4844 已經實作了 KZG 承諾。 這些是在新 blob 新增至網路時建立的密碼學證明。 每個區塊中都包含一個小證明,節點可以驗證收到的 blob 是否與該區塊的 KZG 承諾相對應。 + +DAS 是建立在此基礎上的一個機制,確保資料既正確又可用。 抽樣是一個過程,節點只查詢資料的一小部分,並根據承諾進行驗證。 KZG 是一種多項式承諾方案,這意味著多項式曲線上任何單一點都可以被驗證。 透過僅檢查多項式上的幾個點,進行抽樣的用戶端就可以對資料的可用性有很高的機率保證。 + +## 點對點資料可用性取樣(Peer Data Availability Sampling, PeerDAS) {#peer-das} + +[PeerDAS (EIP-7594)](https://eips.ethereum.org/EIPS/eip-7594) 是在以太坊中實作 DAS 機制的具體提案,這可能是自合併以來最大的一次升級。 PeerDAS 的設計旨在擴展 blob 資料,將其分成列,並將子集分發給節點。 + +以太坊借用了一些巧妙的數學方法來實現這一點:它將 Reed-Solomon 式的糾刪碼應用於 blob 資料。 Blob 資料表示為一個多項式,其係數對資料進行編碼,然後在額外的點上評估該多項式以建立擴展的 blob,從而使評估數量加倍。 這種增加的冗餘性使得糾刪恢復成為可能:即使某些評估缺失,只要包括擴展片段在內的總資料至少有一半可用,原始的 blob 就可以被重構。 + +![擴展多項式](./polynomial.png) + +實際上,這個多項式有數千個係數。 KZG 承諾是幾個位元組的值,類似於哈希,所有節點都知道。 每個持有足夠資料點的節點都可以 [有效地重構完整的 blob 資料集](https://arxiv.org/abs/2207.11079)。 + +> 有趣的是:DVD 也使用了相同的編碼技術。 如果你刮傷了 DVD,播放器仍然能夠讀取它,這要歸功於 Reed-Solomon 編碼,它會補上多項式中缺失的部分。 + +從歷史上看,區塊鏈中的資料,無論是區塊還是 blob,都會廣播給所有節點。 有了 PeerDAS 的分割和抽樣方法,就不再需要向所有人廣播所有內容。 Fusaka 之後,共識層網路被組織成 gossip 主題/子網:blob 列被分配給特定的子網,每個節點訂閱預定的子集並只保管這些片段。 + +使用 PeerDAS,擴展的 blob 資料被分成 128 個稱為列的片段。 資料透過專用的 gossip 協議,在節點訂閱的特定子網上分發給這些節點。 網路上的每個常規節點至少參與 8 個隨機選擇的列子網。 僅從 128 個子網中的 8 個接收資料,意味著這個預設節點只接收到所有資料的 1/16,但由於資料經過擴展,這相當於原始資料的 1/8。 + +這使得理論上的擴張極限,可以達到當前「每個人都下載所有東西」模式的 8 倍。 由於節點訂閱了提供 blob 列的不同的隨機子網,它們均勻分佈的機率非常高,因此每份資料都存在於網路的某個地方。 運行驗證程式的節點,每運行一個驗證程式就需要訂閱更多的子網。 + +> 每個節點都有一個獨特的隨機生成 ID,通常作為其連線的公開身份。 在 PeerDAS 中,這個數字被用來決定它必須訂閱的隨機子網集,從而實現所有 blob 資料的均勻隨機分佈。 + +一旦一個節點成功重構原始資料,它就會將恢復的列重新分發回網路,主動修復任何資料缺口並增強整體系統的彈性。 連線到總餘額 ≥4096 ETH 的驗證程式的節點必須是超級節點,因此必須訂閱所有資料列子網並保管所有列。 這些超級節點將持續修復資料缺口。 該協議的機率性自我修復特性允許強大的可用性保證,同時不限制僅持有部分資料的家庭營運商。 + +![訂閱透過子網分發的列的節點](./subnets.png) + +由於上述的抽樣機制,任何只持有 blob 資料小子集的節點都可以確認資料的可用性。 這種可用性是強制執行的:驗證程式必須遵循新的分叉選擇規則,這意味著他們只有在驗證了資料的可用性之後才會接受並投票給區塊。 + +對使用者(尤其是 L2 使用者)的直接影響是費用降低。 隨著 Rollup 資料空間增加 8 倍,使用者在其鏈上的操作成本會隨著時間推移而變得更便宜。 但在 Fusaka 之後,降低費用需要時間,並取決於 BPO。 + +## 僅限 Blob 參數 (BPO) {#bpo} + +理論上,網路將能夠處理多 8 倍的 blob,但是增加 blob 是一個需要逐步進行適當測試和安全執行的變更。 測試網為在主網上部署這些功能提供了足夠的信心,但在啟用顯著更高數量的 blob 之前,我們需要確保 p2p 網路的穩定性。 + +為了在不壓垮網路的情況下逐步提高每個區塊的目標 blob 數量,Fusaka 引入了 **[僅限 Blob 參數 (BPO)](https://ethereum-magicians.org/t/blob-parameter-only-bpo-forks/22623)** 分叉。 與需要廣泛生態系統協調、協議和軟體更新的常規分叉不同,[BPO (EIP-7892)](https://eips.ethereum.org/EIPS/eip-7892) 是預先編程的升級,隨著時間推移無需干預即可增加 blob 的最大數量。 + +這意味著在 Fusaka 啟動和 PeerDAS 上線後,blob 的數量將保持不變。 blob 的數量將每隔幾週開始翻倍,直到達到最大值 48,同時開發者會監控以確保該機制按預期工作,並且不會對運行網路的節點產生不利影響。 + +## 未來方向 {#future-directions} + +PeerDAS 只是邁向 [FullDAS (或稱 Danksharding) 這個更大擴張願景](https://ethresear.ch/t/fulldas-towards-massive-scalability-with-32mb-blocks-and-beyond/19529) 的一步。 PeerDAS 對每個 blob 單獨使用一維糾刪碼,而完整的 Danksharding 將在整個 blob 資料矩陣上使用更完整的二維糾刪碼方案。 在二維上擴展資料可產生更強的冗餘屬性,以及更高效的重構和驗證。 實現 FullDAS 將需要大量的網路和協議優化,以及額外的研究。 + +## 延伸閱讀 {#further-reading} + +- [PeerDAS:由 Francesco D'Amato 講解的對等資料可用性抽樣](https://www.youtube.com/watch?v=WOdpO1tH_Us) +- [以太坊 PeerDAS 的文件](https://eprint.iacr.org/2024/1362.pdf) +- [不使用 AGM 證明 PeerDAS 的安全性](https://eprint.iacr.org/2025/1683) +- [Vitalik 談 PeerDAS、其影響以及 Fusaka 測試](https://x.com/VitalikButerin/status/1970983281090085200) \ No newline at end of file diff --git a/src/scripts/i18n/post_import_sanitize.ts b/src/scripts/i18n/post_import_sanitize.ts index bf733bf47cd..05a6c5b2195 100644 --- a/src/scripts/i18n/post_import_sanitize.ts +++ b/src/scripts/i18n/post_import_sanitize.ts @@ -2139,13 +2139,10 @@ function fixGuillemetsInHtmlTags(content: string): { ) // Pattern 2: , left < is correct) - lines[j] = lines[j].replace( - /<([^<>]*)\u00BB/g, - (_, inner) => { - fixCount++ - return "<" + inner + ">" - } - ) + lines[j] = lines[j].replace(/<([^<>]*)\u00BB/g, (_, inner) => { + fixCount++ + return "<" + inner + ">" + }) } parts[i] = lines.join("\n") } diff --git a/tests/unit/sanitizer/english-comparison.spec.ts b/tests/unit/sanitizer/english-comparison.spec.ts index 97864c4ca52..e90e94b23aa 100644 --- a/tests/unit/sanitizer/english-comparison.spec.ts +++ b/tests/unit/sanitizer/english-comparison.spec.ts @@ -949,18 +949,15 @@ test.describe("English Comparison Fixes", () => { }) test("leaves components that exist in English", () => { - const translated = - '\n\nText' - const english = - '\n\nText' + const translated = '\n\nText' + const english = '\n\nText' const { content, fixCount } = removeStaleComponents(translated, english) expect(content).toBe(translated) expect(fixCount).toBe(0) }) test("removes multiple stale components", () => { - const translated = - '\nText\n' + const translated = '\nText\n' const english = "Text" const { content, fixCount } = removeStaleComponents(translated, english) expect(content).not.toContain("StaleOne") @@ -969,8 +966,7 @@ test.describe("English Comparison Fixes", () => { }) test("does not remove components inside code blocks", () => { - const translated = - '```\n\n```' + const translated = "```\n\n```" const english = "```\nsome code\n```" const { content, fixCount } = removeStaleComponents(translated, english) expect(content).toContain("ContributorsQuizBanner") @@ -978,8 +974,7 @@ test.describe("English Comparison Fixes", () => { }) test("cleans up blank line left behind after removal", () => { - const translated = - 'Before\n\n\n\nAfter' + const translated = "Before\n\n\n\nAfter" const english = "Before\n\nAfter" const { content, fixCount } = removeStaleComponents(translated, english) expect(content).not.toContain("\n\n\n") diff --git a/tests/unit/sanitizer/standalone-fixes.spec.ts b/tests/unit/sanitizer/standalone-fixes.spec.ts index f384913aded..63af910d8f1 100644 --- a/tests/unit/sanitizer/standalone-fixes.spec.ts +++ b/tests/unit/sanitizer/standalone-fixes.spec.ts @@ -1823,30 +1823,28 @@ author: Ori Pomerantz test.describe("fixGuillemetsInHtmlTags", () => { test("fixes right guillemet replacing > after quoted attribute", () => { - const input = - '' + const input = '' const { content, fixCount } = fixGuillemetsInHtmlTags(input) expect(content).toBe('$100,000') expect(fixCount).toBe(1) }) test("fixes right guillemet replacing > at end of self-closing tag", () => { - const input = '
") expect(fixCount).toBe(1) }) test("fixes right guillemet replacing > in closing tag", () => { - const input = '") expect(fixCount).toBe(1) }) test("fixes left guillemet replacing < in opening tag", () => { - const input = - '\u00ABspan dir="ltr">$100,000
' + const input = '\u00ABspan dir="ltr">$100,000
' const { content, fixCount } = fixGuillemetsInHtmlTags(input) expect(content).toBe('$100,000') expect(fixCount).toBe(1) @@ -1877,7 +1875,7 @@ author: Ori Pomerantz }) test("fixes guillemet in i tag", () => { - const input = '' + const input = "" const { content, fixCount } = fixGuillemetsInHtmlTags(input) expect(content).toBe("text") expect(fixCount).toBe(1) @@ -1891,8 +1889,7 @@ author: Ori Pomerantz }) test("leaves legitimate guillemet pairs unchanged", () => { - const input = - "\u00ABThe knowledge complexity\u00BB" + const input = "\u00ABThe knowledge complexity\u00BB" const { content, fixCount } = fixGuillemetsInHtmlTags(input) expect(content).toBe(input) expect(fixCount).toBe(0) @@ -1998,16 +1995,14 @@ author: Ori Pomerantz }) test("skips fenced code blocks", () => { - const input = - '```\nunclosed\n```' + const input = '```\nunclosed\n```' const { content, fixCount } = fixMissingComponentClosingTags(input) expect(content).toBe(input) expect(fixCount).toBe(0) }) test("skips inline code", () => { - const input = - 'Use `unclosed` as example' + const input = 'Use `unclosed` as example' const { content, fixCount } = fixMissingComponentClosingTags(input) expect(content).toBe(input) expect(fixCount).toBe(0) @@ -2044,7 +2039,7 @@ author: Ori Pomerantz }) test("leaves regular markdown links unchanged", () => { - const input = '[some text](https://example.com)' + const input = "[some text](https://example.com)" const { content, fixCount } = fixMangledDocLinks(input) expect(content).toBe(input) expect(fixCount).toBe(0)