首頁 > 網路3.0 > TON專案開發教學(一):原始碼角度看如何在TON Chain上建立一個NFT

TON專案開發教學(一):原始碼角度看如何在TON Chain上建立一個NFT

WBOY
發布: 2024-06-25 07:51:29
原創
1200 人瀏覽過

摘要:承接上一篇關於TON技術介紹的文章,這段時間深入研究了一下TON官方開發文檔,感覺學習起來還是有些門檻,當前的文檔內容似乎更像是一個內部開發文檔,對新入門的開發者來說不太友好,因此試著以自己的學習軌跡,梳理一系列關於TON Chain專案開發的文章,希望可以對大家快速入門TON DApp開發有一些幫助。行文有誤也歡迎大家指正,一起學習。

在EVM中開發NFT和在TON Chain上開發NFT有哪些不同

發行一個FT或NFT對於DApp開發者來說通常是最基本的需求。因此我也以此作為學習入口。首先讓我們來了解以下在EVM技術堆疊中開發一個NFT和在TON Chain中的差異。基於EVM的NFT通常會選擇繼承ERC-721的標準。所謂NFT,指的是不可分割的加密資產類型,且每個資產具有唯一性,即存在某些專屬的特性。而ERC-721就是這個類型的資產的一種通用的開發範式。讓我們來看看一個常見的ERC721合約需要實作哪些函數以及記錄哪些資訊。下圖是一個ERC721介面。可以看到與FT不同,在轉帳介面中需要輸入的是待轉帳的tokenId而非數量。這個tokenId也是NFT資產唯一性最基本的體現,當然為了承載更多的屬性,通常會為每個tokenId記錄一個metadata,這個metadata是一個外部鏈接,保存了該NFT的其他可擴展數據,例如一張PFP圖片的鏈接,某些屬性名稱等。

TON项目开发教程(一):源码角度看如何在TON Chain上创建一个NFT

對於熟悉Solidity或熟悉物件導向的開發者來說,實現這樣一個智能合約是件容易的事,只要定義好合約中需要的資料類型,例如一些關鍵的映射關係mapping,並根據所需功能開發對應的這些資料的修改邏輯,即可實現一個NFT。

然而在TON Chain中這一切變的不太相同,造成不同的核心原因有兩個:

  • 在TON中數據的存儲是基於Cell實現的,而同一個賬戶的Cell通過有向無環圖來實現。這樣就導致需要之久化儲存的資料不能無邊界的成長下去,因為一個有向無環圖來說,資料深度決定的查詢成本,當深度無限延伸之後,有可能造成查詢成本過高,從而導致合約陷入死鎖問題。
  • 為了追求高並發性能,TON捨棄了串行執行的架構,轉而採用了一個專為並行而生的開發範式,Actor模型,來重構執行環境。這就造成了一個影響,智能合約之間只能透過發送所謂內部訊息的方式非同步調用,注意無論是狀態修改類型或只讀類型的調用都需要遵循這個原則,除此之外,也需要仔細考慮非同步呼叫若失敗,如何處理資料回滾的問題。

當然關於技術上其他不同點在上一篇文章中有過詳細的論述,本篇文章希望可以聚焦在智能合約開發上,所以不展開討論。上述兩條設計原則讓TON中智能合約開發與EVM產生了很大差異。在開始的論述中,我們知道一個NFT合約中需要定義一些映射關係,也就是mapping,來保存NFT相關的資料。其中最重要的就是owners,這個mapping儲存了某個tokenID對應的NFT的擁有者地址的映射關係,決定了NFT的所有權,轉帳就是對該所有權的修改。由於理論上這是一個可以沒有邊界的資料結構,需要盡量避免。因此官方推薦以是否存在無邊界資料結構作為分片的標準。即當有類似的資料儲存需求時,透過主從合約的範式來替代,透過建立子合約的方式來管理每個key對應的資料。並透過主合約管理全域參數,或協助處理子合約之間的內部資訊互動。

這也意味著在TON中的NFT也需要採用類似的架構來設計,每個NFT都是一個獨立的子合約,保存了諸如所有者地址,metadata等專屬數據,並通過一個主合約來管理全域數據,例如NFT name,symbol,總供應量等。

在明確了架構後,接下來就需要解決核心功能的需求了,由於採用了這個主從合約的方式,因此就需要明確哪些功能由主合約承載,哪些功能由子合約承載,並且兩者之間透過什麼內部訊息溝通,同時當出現執行錯誤時,如何回滾先前的資料。通常情況下,在開發複雜的大型專案之前,透過一個類別圖並明確彼此之間的資訊流,並仔細思考內部呼叫失敗後的回滾邏輯是必要的,當然上述NFT開發雖然簡單,但也可以做類似驗證。

TON项目开发教程(一):源码角度看如何在TON Chain上创建一个NFT

從源碼學習開發TON智能合約

TON選擇了設計一種類C 語言的、靜態類型語言,名為Func來作為智能合約開發語言,那麼接下來就讓我們從源碼來學習如何開發TON智能合約,我選擇了TON官方文件中的NFT範例來進行介紹,有興趣的小夥伴可以自行去查閱。在這個case中實作了一個簡單的TON NFT例。讓我們來看看合約結構,共分為兩個功能合約以及三個必要的庫。

TON项目开发教程(一):源码角度看如何在TON Chain上创建一个NFT

這兩個主要的功能合約即按照上述的原則進行設計,首先讓我們來看下主合約nft-collection的代碼:

TON项目开发教程(一):源码角度看如何在TON Chain上创建一个NFT

這引入了第一個知識點,如何在TON智能合約中持久化存儲數據,我們知道在Solidity中數據的持久化存儲是由EVM根據參數的類型自動處理的,通常情況下,智能合約的狀態變量將在執行結束後根據最新值自動被持久化存儲,開發者並不需要考慮這個過程。但在Func中情況並非如此,開發者需要自己來實現對應的處理邏輯,這個情況有點類似C和C++需要考慮GC的流程,但其他新的開發語言通常會將這部分邏輯自動化處理。讓我們來看下程式碼,首先引入一些需要的函式庫,然後看到第一個函數load_data用於讀取被持久化儲存的數據,其邏輯為首先透過get_data傳回持久化合約儲存cell,注意這是由標準庫stdlib.fc實現的,通常情況下可以將其中的一些函數視為系統函數來使用。

此函數的傳回值類型為cell,這是 TVM中的cell類型。在先前的介紹中,我們已經知道TON 區塊鏈中的所有持久性資料都儲存在cell樹中。每個cell最多有 1023 位元任意資料和最多四個對其他cell的引用。 cell在基於堆疊的 TVM 中用作記憶體。 cell中保存的是緊編碼後的數據,要取得其中具體的明文數據,需要將cell轉換為被稱為slice的類型。 cell可以透過begin_parse函數轉換成為slice類型,然後可以透過從slice載入資料位元和對其他cell的參考來獲得cell中的資料。注意15行程式碼中的這種呼叫方法是一個func中的語法糖,可以直接呼叫第一個函數的回傳值的第二個函數。並在最後按照資料持久化順序依序載入對應的資料。注意這個過程和solidity不同,並不是根據hashmap調用,所以這個調用順序不能亂。

在save_data函數中,邏輯與之類似,只不過這是一個反向的過程,這就引入了下一個知識點,一個新的類型builder,這是cell構建器的類型。資料位元和對其他cell的引用可以儲存在建構器中,然後建構器可以最終化為新cell。首先透過標準函數begin_cell建立一個builder,並依序透過store相關函數儲存相關函數,注意上文中呼叫順序與此處儲存順序需要保持一致。最後透過end_cell完成新cell構建,這時該cell被管理在記憶體中,最後透過最外層的set_data,就可以完成對該cell的持久化儲存。

TON项目开发教程(一):源码角度看如何在TON Chain上创建一个NFT

接下來讓我們來看下業務相關函數,首先需要先介紹下一個知識點,如何透過合約創建一個新的合約,這將在剛剛介紹的主從架構中經常被使用。我們知道在TON中,智能合約之間的呼叫是透過發送內部訊息的方式來實現的。這是透過一個名為send_raw_message來實現的,注意第一個參數是message編碼後的cell,第二個參數是標識位,用於表明該交易的執行方式的區別,在TON中設置了不同的內部訊息發送的執行方式,目前有3種訊息Modes和3種訊息Flags。可以將單一Mode與多個(也許沒有)標誌組合以獲得所需的mode。組合只是意味著將它們值的和填入即可。下面給出了Modes和Flags的描述表格:

TON项目开发教程(一):源码角度看如何在TON Chain上创建一个NFT

那麼讓我們來看第一個主要函數,deploy_nft_item,顧名思義,這是一個用於創建或者說鑄造新NFT實例的函數,經過一番操作編碼一個msg後,通過send_raw_message發送該內部合約,並選擇了flag 1的發送標識位,僅將編碼中指定的fee作為本次執行的gas fee。經過上文的介紹我們很容易意識到,這個編碼規則應該是對應創建一個新的智能合約的方式。那讓我們來看看具體是怎麼實現的。

讓我們直接看51行,上面兩個函數是用於生成message所需資訊的輔助函數,因此我們後面再來看,這是一個用於創建智能合約的內部消息的編碼過程,中間的一些數字其實也是一些識別位,用來說明該內部訊息的需求,這裡要引入下一個知識點,TON選擇了一種名為TL-B 的二進位語言來描述訊息的執行方式,並且根據設定不同的標記位來實現某些特定功能的內部訊息,最容易想到的兩個使用場景,新合約創建和已部署合約函數呼叫。而51行的這種方式即對應了前者,創建一個新的nft item合約,而這主要是透過55,56,57三行指定的。首先55行這一大串數字是一系列識別位,注意store_uint的第一個入參是數值,第二個是位長,其中決定了該內部訊息是合約創建的是後三個標記位,以及相應二進位值位元為111(十進位即為4+2+1),其中前兩個表示該訊息將附帶StateInit數據,而這個數據即為新合約的源碼,以及初始化所需的數據。而後一個標記位表示內部訊息附載,即希望執行相關邏輯以及所需的參數。因此你會看到在第66行程式碼並沒有設定該三位數據,則表示的是一次對已部署合約的函數呼叫。具體的編碼規則在這裡查看。

那麼StateInit的編碼規則即對應了49行程式碼,透過calculate_nft_item_state_init計算,注意stateinit資料的編碼也遵循了一種既定的TL-B編碼規則,除了一些標記位之外,主要涉及到兩部分新合約code和以及初始化data。 data的編碼順序需要與新合約指定的持久化cell的儲存順序保持一致。在36行可以看到,初始化資料有item_index,也就是類似與ERC721中的tokenId,以及由標準函數my_address傳回的目前合約位址,即為collection_address,這個資料的順序與nft-item中的宣告一致。

接下來一個知識點就是在TON中,所有未生成的智能合約而可以預先計算其生成後的地址,這點與Solidity中的create2函數類似,在TON中新地址的生成由兩部分組成, workchain標識位與stateinit的雜湊值拼接而成,前者在先前的介紹中我們已經知道是為了對應TON無限分片架構而需要被指定的,目前為統一值。由標準函數workchain獲得。後者由標準函數cell_hash獲得。因此回到這個例子,calculate_nft_item_address即為預先計算新合約位址的函數。並將生成值在第53行編碼到message中,作為該內部訊息的接收位址。而nft_content則對應了對被建立合約的初始化調用,具體的實作在下一篇文章中介紹。

至於send_royalty_params,則需要是對某隻讀請求的內部消息的相應,在之前的介紹中,我們特意強調了在TON中內部消息不光包含可能會修改數據的操作,只讀操作也需要通過這種方式實現,因此該合約即為此類操作,首先值得注意的是67行表示響應該請求後對請求者回調函數的標記,記下來即為返回的數據,分別是請求的item index,以及相應的royalty數據。

接下來讓我們引入下一個知識點,TON中智能合約只有兩個統一的入口,名為recv_internal和recv_external,其中前者為所有內部消息的統一調用入口,後者為所有外部消息的統一調用入口,開發者需要在函數內部根據需求,採用類似switch的方式根據message指定的不同標記位元來回應不同的請求,這裡的標記位元即為上述67行的回呼函數標記。回到該例子,首先對message進行空位檢查,通過後分別解析message中的信息,首先在83行解析獲得sender_address,該參數將用於後續的權限檢查,注意這裡的~操作符,屬於另一個語法糖。這裡先不展開將。接下來解析op操作標記位,後來依不同的標記位,分別處理對應請求。其中即根據某些邏輯分別呼叫了上述的函數。例如回應對royalty參數的請求,或鑄造新的nft,並自增全局index。

接下來一個知識點對應了108行,想必大家透過命名也可以知道該函數的處理邏輯,與Solidity中的require函數類似,Func中透過標準函數throw_unless來拋出異常,第一個入參為錯誤碼,第二個是檢查位布林值,若位false則拋出異常,並附帶該錯誤碼。而在這行中透過equal_slices來判斷上面解析到的sender_address是否等於該合約持久化儲存的owner_address,做權限判斷。

TON项目开发教程(一):源码角度看如何在TON Chain上创建一个NFT

最後為了使程式碼結構更清晰,開始閒了一系列幫助獲取持久化資訊的輔助函數,在這裡就不展開介紹了,開發者可以參考這種結構來開發自己的智能合約。

TON项目开发教程(一):源码角度看如何在TON Chain上创建一个NFT

TON生態的DApp開發實在是件有趣的事情,與EVM的開發範式有很大差異,因此我會透過一系列文章來介紹如何在TON Chain中開發DApp。與大家共同學習,把握這波機會。也歡迎大家在twitter上與我互動,碰撞一些新的有趣的dapp idea,一起開發。

以上是TON專案開發教學(一):原始碼角度看如何在TON Chain上建立一個NFT的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:panewslab.com
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板