Maison > Article > développement back-end > Solana clignote avec Go
Les
Les clignotants sont des liens riches en métadonnées qui représentent et activent les activités en chaîne dans tout l'écosystème Solana sans avoir besoin de naviguer vers une autre application ou une autre page Web.
Blinks prend en charge un large éventail d'activités activées par Solana Actions
et permettent principalement aux utilisateurs d'interagir avec la blockchain via les médias sociaux et d'autres plateformes hors chaîne.
Les cas d'utilisation incluent :
Dans cet article, nous explorerons une application Blink simple axée sur la création de NFT à l'aide de Go. Bien que l'article soit axé sur Go, les concepts de base s'appliquent à n'importe quelle application Blink. Vous pouvez trouver le code complet sur GitHub.
Nous commencerons par configurer un serveur Web de base à l'aide du framework Gin, ainsi que la configuration CORS nécessaire telle que définie par la spécification. Nous définirons également certains points finaux qui seront discutés en détail ci-dessous.
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 } }
Le cœur de toute application Blinks réside dans la réplication de la spécification de l'API Solana Actions. Vous trouverez ci-dessous une représentation visuelle du fonctionnement des Blinks.
Blinks on Solana utilise un schéma d'URL d'action pour fournir un lien riche en métadonnées, permettant diverses activités en chaîne. Cette section décrit les principaux gestionnaires responsables du traitement de l'action mint NFT sur le /api/actions/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) }
La fonction mintNFT exploite Solana-Go-SDK pour créer des NFT, avec quelques ajustements.
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) }
Après avoir déployé votre application, vous pouvez utiliser l'application Blinks Inspector pour tester.
J'espère que cet article fournit une introduction pratique à la création d'applications Blinks sur Solana à l'aide de Go. Le code complet peut être trouvé ici.
Pour une analyse plus approfondie du cadre Solana Actions et une documentation détaillée, consultez les ressources officielles de Solana
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!