深入了解日誌智能合約

robertu
·
·
IPFS
·

在嘗試數字所有權時, Matters Lab正在通過三個 Web3 項目模糊私有和公共所有權之間的界限: Traveloggers ,關於私有所有權的個人資料圖片 (pfp) NFT; The Space是一個可賺取收入的像素畫布,具有普遍基本收入 (UBI) 和共同所有權的 Harberger 稅;還有, Logbook ,一個關於集體所有權的共同創作 dApp。

日誌起源於 Traveloggers 的一項功能,允許 NFT 所有者寫下關於以太坊區塊鏈的想法。隨著汽油費的痛苦和協作內容的新想法的出現,我們重新設計了 Logbook 智能合約,具有許多新功能:降低汽油費、分叉和捐贈、版稅分割、去中心化前端和鏈上 NFT。

你並不完全擁有你的 NFT。每個日誌都是 NFT,您有權轉讓並從您的寫作中受益。但它是開放的,就像開源軟件一樣,一旦公開,就永遠不會停止。任何人都可以使用或分叉您的代碼,在其他項目中生存和重生,您的代碼提交仍然存在。日誌是一樣的,你的內容仍然是你的,但它可以在任何日誌中。

概述

我們有三個關於 Logbook 的 GitHub 存儲庫:

編寫一個安全、省油且易於閱讀的智能合約很難,尤其是在這個快速增長且高度不確定的行業中。我們很樂意分享更多關於我們如何設計和實施 Logbook 智能合約的細節。

Hardhat是最流行的 Solidity 開發環境,通過插件為 JavaScript 開發人員提供流暢的體驗和出色的可擴展性,但上下文切換會損害生產力。我們用 Solidity 編寫合約,但用 JavaScript 進行測試。更糟糕的是,我們必須處理大包依賴關係。感謝Foundry ,我們可以在 Solidity 中更快地構建、更好地測試。

進入src/Logbook/Logbook.sol ,我們可以看到 Logbook 合約的依賴關係:

日誌
↖ ERC721
↖ 可擁有
↖ 版稅

ERC721是 OpenZeppelin 的ERC-721 標準的實現, Ownable允許地址調用索取日誌功能並更改公開銷售狀態(旅行者可以免費索取日誌,之後可以從公開銷售中鑄造)。

Logbook的核心繼承自Royalty ,包含有關如何鑄造日誌、所有者如何與日誌交互以及如何從分叉和捐贈中分離版稅的業務邏輯。

對於區塊鏈平台,我們選擇了Polygon,主要是因為低gas費和成熟的生態系統。作為開發人員,我們可以使用 Alchemy 和 The Graph 等服務。作為創作者,我們可以在 OpenSea 上買賣 Logbook NFT,在 Uniswap 上將收入兌換成穩定幣等。

最後但同樣重要的是,為了更方便地查詢合約數據,我們使用了The Graph ,這是一種為客戶提供GraphQL API的去中心化索引服務。

版稅分割和去中心化前端


讓我們仔細看看外部函數:

 // src/Logbook/ILobook.sol
ILogbook
  - 設置標題
  - 設置描述
  - 發布
  - 獲取日誌
  - 獲取日誌
  - setForkPrice
  - 叉子
  - forkWithCommission
  - 捐贈
  - donateWithCommission
  - ...

// src/Logbook/IRoyalty.sol
版稅
  - 提取
  - 獲得平衡

setTitlesetDescriptionpublish供所有者更新日誌。 getLogbookgetLogs只是獲取日誌詳細信息的簡單 getter。有了這些接口,我們已經可以製作一個不錯的 dApp,創建者可以在鏈上發佈內容。但不止於此。創作者可以從他們的作品中賺錢。

任何人都可以將 $MATIC 捐贈給日誌,或者所有者可以設置分叉價格 ( setForkPrice ) 允許其他人分叉日誌並繼續寫入。這些收入的 80% 歸所有者所有,其餘的高達 20% 則平分給內容的作者。如果某些內容是從分叉中繼承的,則原作者獲得此份額。

為什麼高達 20%?這取決於用戶如何調用函數。

大多數時候,用戶通過網站查看內容或與合同交互。儘管 Matters Lab 設計並構建了 logbook.matters.news ,但它是集中的,我們的品味,我們的局限。通過利用這些合約接口,開發人員可以自己製作定制的前端,也可以為他人製作,並從forkWithCommissiondonateWithCommission中獲得佣金。假設開發人員創建了一個具有出色 UI/UX 的 Logbook Web 應用程序,讀者和創建者都喜歡使用它。由於維護和託管它需要時間和金錢,開發人員決定從每次分叉和捐贈中抽取 5%。雙贏!

函數參數commission_ (接收佣金的地址)和commissionBPS_ (佣金百分比,以基點為單位)可以傳遞給forkWithCommissiondonateWithCommissioncommissionBPS_ BPS_ 的上限為 2,000(20%),這意味著開發者可以在日誌所有者收取 80% 的費用後決定一個地址收取多少費用。

加入破解日誌!

氣體優化

區塊鏈,顧名思義,就是一個由數據塊組成的鏈。一個塊包含有限數量的交易。交易費用通過提供計算和存儲資源來確認服務請求的區塊鍊網絡礦工。儘管摩爾定律使這些資源變得豐富,但去中心化的服務卻是稀缺的。我們正在為去中心化的承諾付出代價,以汽油價格競標。

那麼,我們做了哪些努力來對抗這種豐富的稀缺性呢?

空間。

在交易中執行的不同 EVM 操作碼花費不同單位的 gas。最昂貴的操作碼之一是SSTORE ,用於將數據放入合約存儲中,每個存儲槽(32 字節)最多約 20,000 個 gas。我們應該在存儲上存儲最少的數據。

有幾種高效的數據存儲方式:無狀態合約、鏈下存儲以及將數據作為事件發送。對於無狀態合約,數據被傳遞給什麼都不做的函數。對於鏈下存儲,數據存儲在 IPFS 或 Arweave 等存儲服務上,然後在鏈上提交標識符(URL、CID 等)。這兩種解決方案都不容易讓客戶端訪問數據。我們採用了最後一個,數據使用LOG*操作碼作為事件發出,與SSTORE相比節省了約 90% 的 gas,此外,客戶端可以直接使用主題過濾器或使用 Graph API 檢索鏈上數據。

另一個優化是在數據結構上。日誌支持協作內容創建,任何人都可以在未經所有者許可的情況下分叉日誌,並繼承內容。

我們可以使用最少的元數據集鏈接到父節點,而不是從父節點複製數據。

 // https://github.com/thematters/contracts/blob/81246e4/src/Logbook/ILogbook.sol#L26-L41

結構書{
    // 一系列日誌的結束位置
    uint32 endAt;
    //父書
    uint256 父級;
    // 書中所有的日誌哈希
    bytes32[] 內容哈希;
    ...
}

最後,內容髮布的gas下降到90%。使用 Polygon,美元成本下降了 99.99%!

Gas 價格 = 30 Gwei,1 MATIC ≈ 1.5 USD,1 ETH ≈ 3000 USD

時間。

Block 在 Polygon 上有30M的 gas 限制,因此交易可能會用完 gas。版稅拆分會迭代內容並更新作者的餘額。如果 slot 是零值, SSTORE花費 ~20,000 gas,但如果它是非零值,則只需 ~5,000,這是一個巨大的差異!

 // https://github.com/thematters/contracts/blob/81246e4/src/Logbook/Logbook.sol#L387-L397

for (uint32 i = 0; i < logCount; i++) {
日誌內存 log = logs[contentHashes[i]];
_balances[log.author] += fee.perLogAuthor;
...
}

我們做了一個小技巧來最大化可以運行的迭代次數。一旦擁有代幣,地址的餘額將始終為非零值。從長遠來看,通過分配到不同區塊中的特定交易來緩解氣體限制的瓶頸。

 // https://github.com/thematters/contracts/blob/81246e4/src/Logbook/Logbook.sol#L401-L414

函數_afterTokenTransfer(
地址來自_,
寫給_,
uint256 tokenId_
) 內部虛擬覆蓋 {
...
如果 (_balances[to_] == 0) {
_balances[to_] = 1 wei;
}
}

// https://github.com/thematters/contracts/blob/81246e4/src/Logbook/Royalty.sol#L12-L24

功能撤回()公共{
...
_balances[msg.sender] = 1 wei;
...
}

鏈上 NFT

Logbook 不僅是一個鏈上寫作 dApp,也是一個生成的 NFT 集合。每次發布或轉讓都會改變圖像的顏色。在24KB的合約代碼大小限制下,SVG 輕巧靈活,是鏈上生成圖像的理想格式。

另一個限制是連接大字符串時。很容易看到“堆棧太深”錯誤。為了解決這個問題,我們可以用struct打包參數並將generateSVG拆分為四個函數:

 // https://github.com/thematters/contracts/blob/81246e487008740f3515b7a6c91c7c43b58262dd/src/Logbook/NFTSVG.sol

結構 SVGParams {
uint32 日誌計數;
uint32 轉移計數;
uint160 創建時間;
uint256 令牌ID;
}

函數 generateSVG(SVGParams memory params) 內部純返回 (string memory svg) {
svg = 字符串(
abi.encodePacked(
'<svg width="800" height="800" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd">',
生成SVG背景(參數),
生成SVGPathsA(參數),
生成SVGPathsB(參數),
生成SVGTexts(參數),
"</g></svg>"
)
);
}

函數 generateSVGBackground() {}
函數 generateSVGPathsA() {}
函數 generateSVGPathsB() {}
函數 generateSVGTexts() {}


藝術永遠不會結束,只會被拋棄。

日誌,雖然它的合約代碼在區塊鏈上是靜態的,但當我們編寫、轉移、分叉、捐贈時……每一次互動都讓它變得生動起來。我們可以在這個不為人知的數字空間中共同創造我們的故事。

CC BY-NC-ND 2.0 授權

喜歡我的作品嗎?別忘了給予支持與讚賞,讓我知道在創作的路上有你陪伴,一起延續這份熱忱!