Blinks 是元資料豐富的鏈接,代表並支援整個 Solana 生態系統的鏈上活動,而無需導航到不同的應用程式或網頁。
Blinks 支援 Solana Actions 啟用的廣泛活動
主要允許用戶透過社群媒體和其他鏈下平台與區塊鏈進行互動。
用例包括:
在本文中,我們將探索一個簡單的 Blink 應用程序,專注於使用 Go 鑄造 NFT。雖然本文重點關注 Go,但核心概念適用於任何 Blink 應用程式。您可以在 GitHub 上找到完整的程式碼。
我們將首先使用 Gin 框架設定一個基本的 Web 伺服器,以及規範定義的必要的 CORS 配置。我們還將定義一些端點,以下將詳細討論。
func main() { var ( corsConfig = cors.DefaultConfig() router = gin.Default() port = os.Getenv("PORT") ) corsConfig.AllowAllOrigins = true corsConfig.AddAllowHeaders([]string{"Content-Length", "Content-Type", "Access-Control-Allow-Origin"}...) corsConfig.AddAllowMethods([]string{"GET", "POST", "OPTIONS"}...) router.Use(cors.New(corsConfig)) router.GET("/actions.json", app.ActionsRulesHandler) router.GET("/api/actions/mint_nft", app.GetActionsHandler) router.OPTIONS("/api/actions/mint_nft", app.OptionsHandler) router.POST("/api/actions/mint_nft", app.PostHandler) log.Println("StickyLabs Blink Active ?") if port == "" { port = "8081" } log.Println("Server is running") err := router.Run(fmt.Sprintf(":%v", port)) if err != nil { log.Fatal(err) return } }
任何 Blinks 應用程式的核心都在於複製 Solana Actions API 規範。以下是 Blinks 工作原理的直覺展示。
Solana 上的 Blinks 使用 Action URL 方案來提供元資料豐富的鏈接,從而實現各種鏈上活動。本節概述了負責處理 /api/actions/mint_nft
上的 mint NFT 操作的主要處理程序type ActionGetResponse struct { Title string `json:"title"` Icon string `json:"icon"` Description string `json:"description"` Label string `json:"label"` Links struct { Actions []Actions `json:"actions"` } `json:"links"` } type Actions struct { Label string `json:"label"` Href string `json:"href"` Parameters []ActionParameters `json:"parameters,omitempty"` } type ActionParameters struct { Name string `json:"name"` Label string `json:"label"` Required bool `json:"required"` } func GetActionsHandler(c *gin.Context) { payload := ActionGetResponse{ Title: "Actions Example - Mint NFT", Icon: c.Request.URL.Scheme + "://" + c.Request.URL.Host + "/solana_devs.jpg", Description: "Transfer SOL to another Solana wallet", Label: "Transfer", } payload.Links.Actions = []Actions{ {"Mint NFT", "/api/actions/mint_nft", []ActionParameters{ {"name", "Enter the Name of the NFT", true}, {"symbol", "Enter the Symbol of the NFT", true}, {"uri", "Enter the Uri of the NFT", true}, }}, } c.JSON(http.StatusOK, payload) }
var ACTIONS_CORS_HEADERS = map[string]string{ "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "GET,POST,OPTIONS", "Access-Control-Allow-Headers": "Content-Type", } func OptionsHandler(c *gin.Context) { for key, value := range ACTIONS_CORS_HEADERS { c.Header(key, value) } c.Status(http.StatusOK) }
type MintNFTParams struct { Name string `form:"name" binding:"required"` Symbol string `form:"symbol" binding:"required"` URI string `form:"uri" binding:"required"` } // { "account": "<account>" } //JSON type ActionPostRequest struct { Account string `json:"account"` } type ActionPostResponse struct { Fields ActionPostResponseFields `json:"fields"` } type ActionPostResponseFields struct { Transaction string `json:"transaction"` Message string `json:"message"` } func PostHandler(c *gin.Context) { var ( qPayload MintNFTParams request ActionPostRequest response ActionPostResponse ) if err := c.ShouldBindQuery(&qPayload); err != nil { c.JSON(http.StatusBadRequest, ActionError{Message: "Invalid Query Params"}) return } if err := c.ShouldBindJSON(&request); err != nil { log.Println(err) c.JSON(http.StatusBadRequest, ActionError{Message: "Invalid request"}) return } account, err := types.AccountFromBase58(request.Account) if err != nil { log.Println(err) c.JSON(http.StatusBadRequest, ActionError{Message: "Invalid request; Error validating account"}) return } response.Fields.Transaction, response.Fields.Message = mintNFT(qPayload, account) c.JSON(http.StatusOK, response) }
mintNFT 函數利用 Solana-Go-SDK 來鑄造 NFT,只需進行少量調整。
func mintNFT(metadata MintNFTParams, feePayer types.Account) (transaction, message string) { message = fmt.Sprintf("Mint NFT %s", metadata.Name) c := client.NewClient(rpc.DevnetRPCEndpoint) log.Println(metadata) mint := types.NewAccount() fmt.Printf("NFT: %v\n", mint.PublicKey.ToBase58()) collection := types.NewAccount() fmt.Printf("collection: %v\n", collection.PublicKey.ToBase58()) ata, _, err := common.FindAssociatedTokenAddress(feePayer.PublicKey, mint.PublicKey) if err != nil { log.Fatalf("failed to find a valid ata, err: %v", err) } tokenMetadataPubkey, err := token_metadata.GetTokenMetaPubkey(mint.PublicKey) if err != nil { log.Fatalf("failed to find a valid token metadata, err: %v", err) } tokenMasterEditionPubkey, err := token_metadata.GetMasterEdition(mint.PublicKey) if err != nil { log.Fatalf("failed to find a valid master edition, err: %v", err) } mintAccountRent, err := c.GetMinimumBalanceForRentExemption(context.Background(), token.MintAccountSize) if err != nil { log.Fatalf("failed to get mint account rent, err: %v", err) } recentBlockhashResponse, err := c.GetLatestBlockhash(context.Background()) if err != nil { log.Fatalf("failed to get recent blockhash, err: %v", err) } tx, err := types.NewTransaction(types.NewTransactionParam{ Signers: []types.Account{mint, feePayer}, Message: types.NewMessage(types.NewMessageParam{ FeePayer: feePayer.PublicKey, RecentBlockhash: recentBlockhashResponse.Blockhash, Instructions: []types.Instruction{ system.CreateAccount(system.CreateAccountParam{ From: feePayer.PublicKey, New: mint.PublicKey, Owner: common.TokenProgramID, Lamports: mintAccountRent, Space: token.MintAccountSize, }), token.InitializeMint(token.InitializeMintParam{ Decimals: 0, Mint: mint.PublicKey, MintAuth: feePayer.PublicKey, FreezeAuth: &feePayer.PublicKey, }), token_metadata.CreateMetadataAccountV3(token_metadata.CreateMetadataAccountV3Param{ Metadata: tokenMetadataPubkey, Mint: mint.PublicKey, MintAuthority: feePayer.PublicKey, Payer: feePayer.PublicKey, UpdateAuthority: feePayer.PublicKey, UpdateAuthorityIsSigner: true, IsMutable: true, Data: token_metadata.DataV2{ Name: metadata.Name, Symbol: metadata.Symbol, Uri: metadata.URI, SellerFeeBasisPoints: 100, Creators: &[]token_metadata.Creator{ // tODO rede && Minter { Address: feePayer.PublicKey, Verified: true, Share: 100, }, }, Collection: &token_metadata.Collection{ Verified: false, Key: collection.PublicKey, }, Uses: nil, }, CollectionDetails: nil, }), associated_token_account.Create(associated_token_account.CreateParam{ Funder: feePayer.PublicKey, Owner: feePayer.PublicKey, Mint: mint.PublicKey, AssociatedTokenAccount: ata, }), token.MintTo(token.MintToParam{ Mint: mint.PublicKey, To: ata, Auth: feePayer.PublicKey, Amount: 1, }), token_metadata.CreateMasterEditionV3(token_metadata.CreateMasterEditionParam{ Edition: tokenMasterEditionPubkey, Mint: mint.PublicKey, UpdateAuthority: feePayer.PublicKey, MintAuthority: feePayer.PublicKey, Metadata: tokenMetadataPubkey, Payer: feePayer.PublicKey, MaxSupply: pointer.Get[uint64](0), }), }, }), }) if err != nil { log.Fatalf("failed to new a tx, err: %v", err) } serialized, err := tx.Serialize() if err != nil { log.Fatal(err) } transaction = base64.StdEncoding.EncodeToString(serialized) return }
// { "message" : "Insert Error Message" } //JSON type ActionError struct { Message string `json:"message"` }
func ActionsRulesHandler(c *gin.Context) { payload := gin.H{ "rules": []gin.H{ { "pathPattern": "/*", "apiPath": "/api/actions/*", }, { "pathPattern": "/api/actions/**", "apiPath": "/api/actions/**", }, }, } c.JSON(http.StatusOK, payload) }
部署應用程式後,您可以使用 Blinks Inspector 應用程式進行測試。
我希望本文提供有關使用 Go 在 Solana 上建立 Blinks 應用程式的實用介紹。完整程式碼可以在這裡找到。
要深入了解 Solana Actions 框架和詳細文檔,請查看 Solana 的官方資源
以上是Solana 與 Go 一起閃爍的詳細內容。更多資訊請關注PHP中文網其他相關文章!