GTokenTool全网最好的代币发行工具平台
当前位置:首页 >> solana教程 >> 面向开发人员的 Solana 智能合约示例

面向开发人员的 Solana 智能合约示例

admin solana教程 205

什么是智能合约? 

在深入研究 Solana 智能合约示例之前,我们将回顾基础知识并探索智能合约的复杂性。如果您已经熟悉智能合约的基本原理,请直接跳至“ Solana 智能合约示例”部分。否则,请加入我们,我们将回答“什么是智能合约?”这个问题。 

Solana 智能合约。

智能合约(Web3 合约)是托管在区块链网络上的程序,根据预定义的条件执行预定义的操作。此外,Web3 开发人员使用智能合约来自动执行两方或多方之间的协议。因此,Web3 合约与传统合约具有相同的基本功能,只是代码而不是传统中介来调解这些数字程序。

智能合约扩展了比特币的基本概念,即无需中介即可发送和接收资产,从而实现任何交易的安全自动化。因此,智能合约可以实现更复杂的交易/交易的自动化,而且由于它们在区块链网络上运行,因此它们具有高可靠性、安全性和无边界可访问性。  

此外,Web3 合约是区块链行业的支柱。这些合约允许开发人员创建创新的 dapp、代币和其他 Web3 项目。此外,智能合约还用于从革命性金融工具到游戏逻辑等各个领域。每当合约在区块链网络上部署时,它们通常是不可逆或不可变的,这意味着合约无法更改。不变性与智能合约的确定性特征相结合,可确保参与者能够确定结果。 

有趣的是,智能合约有时被称为“数字自动售货机”,因为自动售货机是解释智能合约功能的一个很好的类比。与传统的自动售货机一样,智能合约保证通过正确的输入获得特定的输出。然而,交易通常比收到零食或苏打水更复杂。 

Solana 有智能合约吗? 

Solana 有智能合约吗?答案是肯定的!Solana 是一个可编程的去中心化区块链,可以创建可扩展、用户友好的 dapp,并且与所有可编程区块链网络一样,Solana 具有智能合约。但是,Solana 智能合约与 EVM Web3 合约等不同。 

Solana 的智能合约架构与更传统的基于 EVM 的区块链模型略有不同。例如,以太坊智能合约的代码/逻辑和状态仅在部署在以太坊网络上的单个合约中累积。而对于 Solana,智能合约(或程序)是无状态或“只读”的,仅包含程序逻辑。 

一旦合约部署,就可以通过外部账户与其进行交互。然后,账户负责存储与程序交互相关的数据。因此,这就在逻辑(程序)和状态(账户)之间建立了分离。 

上述区别概述了 Solana 与其他兼容 EVM 的区块链在智能合约方面的关键区别。由于 EVM 链和 Solana 之间的智能合约架构存在差异,因此它们的构建方式也存在差异。开发人员使用 Solidity 编程语言编写兼容 EVM 的智能合约。而对于 Solana 合约,开发人员使用 Rust、C 和 C++ 编写。

因此,如果您想进入 Solana 智能合约开发领域,那么精通上述编程语言可能是一个好主意。但是,Solana 网络上已经有许多已部署的程序/智能合约供您交互。因此,在 Solana 区块链上构建时,您只需偶尔创建新的智能合约! 

Solana 智能合约示例

在更好地理解智能合约及其在 Solana 环境中的含义后,下一节将深入介绍一些 Solana 示例智能合约。这将概述 Solana 智能合约可能是什么样子,使之前的解释更加直接。 

Solana 智能合约示例。

具体来说,本节涵盖三个 Solana 智能合约示例: 

  1. “ hello_world ” ——第一个示例智能合约是“ hello_world ”,它负责在有人调用程序时 简单地显示“ Hello World!! ”消息。

  2. “ tic_tac_toe ” – 第二个 Solana 示例智能合约称为“ tic_tac_toe ”,它稍微复杂一些,因为该合约负责处理井字游戏的游戏逻辑。

  3. “ micro_blog ” ——我们将进一步研究的最后一个例子称为“ micro_blog ”,它负责微博必要的逻辑。 

尽管如此,让我们直接进入我们的第一个 Solana 智能合约示例,仔细看看“ hello_world ”合约!

“ hello_world ”合约

我们的三个 Solana 示例智能合约中的第一个“ hello_world ”相对简单。您可以在下面找到此智能合约的完整代码:

使用solana_program :: {
   account_info :: AccountInfo,entrypoint,entrypoint :: ProgramResult,msg,pubkey :: Pubkey,
}
入口点hello_world
发布fn hello_world (
   _program_id: & Pubkey, // 程序加载到的账户的公钥
   accounts: & [ AccountInfo ] , // 处理指令所需的所有账户
   _instruction_data: & [ u8 ] , // 序列化指令特定数据
) - >程序结果{
   msg ! ( "你好 {:}!!" , accounts [ 0 ] .key ) ;
   好的))
}

每当有人调用此智能合约时,它都会触发用户需要签署的 Solana 交易。当他们签署消息时,它会自动返回合约的数据日志,在本例中是一条“ Hello World!! ”消息。

“井字游戏”合约

接下来,让我们仔细看看第二个示例智能合约“井字游戏”。此合约比前一个合约更复杂,因为它处理了多人井字游戏的逻辑。不过,这是 Solana 智能合约的全部代码:

使用borsh :: { BorshDeserialize,BorshSerialize } ;
使用solana_program :: {
   account_info :: AccountInfo,entrypoint,entrypoint :: ProgramResult,msg,pubkey :: Pubkey,
}
pub fn win_check 移动:[ u32;9 ])- > u32 {
   // 玩家 1 的移动将被标记为 1,玩家 2 的移动将被标记为 2
   [ m1, m2, m3, m4, m5, m6, m7, m8, m9 ] = 移动;
   如果m1 == 1 && m2 == 1 && m3 == 1
       || ( m1 == 1 && m4 == 1 && m7 == 1 )
       || m7 == 1 && m8 == 1 && m9 == 1
       || m3 == 1 && m6 == 1 && m9 == 1
       || m1 == 1 && m5 == 1 && m9 == 1
       || ( m3 == 1 && m5 == 1 && m7 == 1 )
       || ( m2 == 1 && m5 == 1 && m8 == 1 )
       || ( m4 == 1 && m5 == 1 && m6 == 1 )
   {
       // 玩家 1 获胜的条件
       返回1
   }否则,如果m1 == 2 && m2 == 2 && m3 == 2
       || ( m1 == 2 && m4 == 2 && m7 == 2 )
       || m7 == 2 && m8 == 2 && m9 == 2
       || m3 == 2 && m6 == 2 && m9 == 2
       || m1 == 2 && m5 == 2 && m9 == 2
       || ( m3 == 2 && m5 == 2 && m7 == 2 )
       || ( m2 == 2 && m5 == 2 && m8 == 2 )
       || ( m4 == 2 && m5 == 2 && m6 == 2 )
   {
       // 玩家 2 获胜的条件
       返回2
   }否则,如果m1 == 1 || m1 == 2
       && ( m2 == 1 || m2 == 2 )
       && ( m3 == 1 || m3 == 2 )
       && ( m4 == 1 || m4 == 2 )
       && ( m5 == 1 || m5 == 2 )
       && ( m6 == 1 || m6 == 2 )
       && ( m7 == 1 || m7 == 2 )
       && ( m8 == 1 || m8 == 2 )
       && ( m9 == 1 || m9 == 2 )
   {
       // 绘制条件
       返回3
   }别的{
       返回0
   }
}
#[衍生 (BorshSerialize、BorshDeserialize、调试)]
pub结构GameAccount {
   酒吧玩家1:字符串,
   酒吧玩家2:字符串,
   pub移动:[ u32; 9 ]
   酒吧游戏状态:u32,
   酒吧下一个移动:u32,
}
入口点井字游戏
pub fn tic_tac_toe
   _program_id: 公钥,
   账户:& [账户信息]
   指令数据:& [ u8 ]
) - >程序结果{
   游戏账户 = &账户[ 0 ] ;
   玩家1 =账户[ 1 ] .key.to_string ( )
   玩家2 =账户[ 2 ] .key.to_string ( )
   指令:u32 = 指令数据[ 0 ] .into ( )
   playing_by: u32 = instructions_data [ 1 ] . into ( ) ;
   move_positon: usize = instructions_data [ 2 ] . into ( ) ;
   匹配指令{
       // 创建新游戏或重置游戏数据
       0 = > {
           msg ! ( "指令 0 开始" ) ;
           game_data = GameAccount {
               玩家1,
               玩家2,
               移动[ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ]
               游戏状态: 0 ,
               下一步移动:1
           }
           msg ! ( "游戏创建成功!!" ) ;
           msg ! ( "玩家 1:{:?}" , game_data.player1 ) ;
           msg ! ( "玩家 2:{:?}" , game_data.player2 ) ;
           game_data.serialize & mut & mut game_account.data.borrow_mut [ .. ] ?;
           msg ! ( "指令0结束" ) ;
       }
       // 玩游戏!
       1 = > {
           msg ! ( "指令1开始" ) ;
           mut game_data = GameAccount :: try_from_slice ( & game_account.data.borrow ( ) ) ? ;
           如果game_data.game_status == 0 {
               msg ! ( "玩家 1:{:?}" , game_data.player1 ) ;
               msg ! ( "玩家 2:{:?}" , game_data.player2 ) ;
               // 验证并更新游戏账户中的动作
               如果game_data.moves [ move_positon ] == 0 && game_data.next_move == playing_by {
                   如果game_data.next_move == 1 {
                       游戏数据.移动[移动位置] = 1 ;
                       game_data.next_move = 2
                   }否则,如果game_data.next_move == 2 {
                       游戏数据.移动[移动位置] = 2 ;
                       游戏数据.下一个移动 = 1
                   }
               }别的{
                   msg ! ( “错误的举动” ) ;
               }
               game_status = win_check ( game_data.moves ) ;
               比赛游戏状态{
                   0 = > {
                       // 记录下一个移动的玩家
                       msg ! ( "下一步:玩家 {}" , game_data.next_move ) ;
                   }
                   1 = > {
                       游戏数据.游戏状态 = 1
                       msg ! ( “玩家 1 赢得了游戏。” )
                   }
                   2 = > {
                       游戏数据.游戏状态 = 2
                       msg ! ( “玩家 2 赢得了比赛。” )
                   }
                   3 = > {
                       游戏数据.游戏状态 = 3
                       msg ! ( “平局。” )
                   }
                   _ = > {
                       msg ! ( "游戏错误!!!" ) ;
                   }
               }
               // 将更新的数据写入帐户。
               game_data.serialize & mut & mut game_account.data.borrow_mut [ .. ] ?;
               msg ! ( "指令1结束" ) ;
           }别的{
               msg ! ( “错误的举动。” )
           }
       }
       // 无效指令
       _ = > {
           msg ! ( "无效指令" )
       }
   }
   好的))
}

上述代码负责井字游戏的所有游戏逻辑,处理游戏的多个方面。首先,合约会检查两位玩家是否已经在进行游戏。如果没有,智能合约会从头开始创建一个新游戏。此外,合约还会检查正确的玩家是否正在移动,并相应地更新游戏状态。 

每次移动后,合约都会调用“ win_check() ”函数来检查是否有任何一位玩家赢得了游戏。最后,游戏状态返回给用户,使他们能够实时查看游戏板的更新!

“ micro_blog ” 合约 

我们最初的三个 Solana 示例智能合约中的最后一个是“ micro_blog ”。与第一个例子一样,这是一个相对简单的合约。下面,您将找到完整的代码: 

使用 borsh:: { BorshDeserialize, BorshSerialize } ;
使用 std::str;
使用 solana_program:: {
   account_info::AccountInfo,入口点,入口点::ProgramResult,消息,
   程序错误::程序错误, pubkey::Pubkey,
}
// 创建一个结构来存储博客数量
#[衍生 (BorshSerialize、BorshDeserialize、调试)]
pub 结构 BlogCount {
   pub total_blogs: u32,
}
// 将缓冲区数组转换回字符串的函数
pub fn buffer_to_string (缓冲区:& [ u8 ]) - > &str {
   让 s = 匹配 str:: from_utf8 (缓冲区) {
       好的v = > v,
       Err ( e ) = > panic! ( "无效的 UTF-8 序列: {}" , e ) ,
   }
   返回s;
}
入口点!微博
发布微博(
   程序 ID:&Pubkey,
   账户:& [账户信息]
   指令数据:& [ u8 ]
) - >程序结果{
   让数据 =缓冲区到字符串( &指令数据)
   让帐户 = &accounts [ 0 ] ;
   // 检查该帐户是否属于该程序,否则抛出错误。
   如果帐户。所有者!=程序ID {
       信息!
           “帐户 {:?} 没有将程序 ID {} 作为所有者”
           帐户,
           程序编号
       
       返回Err ProgramError::IncorrectProgramId
   }
   // 增加并存储用户创建新博客的次数。
   mut blog_counter = BlogCount:: try_from_slice ( &account.data.borrow ( )) ? ;
   blog_counter。total_blogs + = 1
   blog_counter.serialize &mut&mut account.data.borrow_mut [ .. ] ?;
   // 将数据保存到事务日志
   msg! ( "作者:{}" , accounts [ 1 ] .key ) ;
   msg! ( "博客编号:{}" blog_counter.total_blogs )
   msg! ( "博客:{}" ,数据)
   好的(())
}

该合约的目的是存储博客数据并跟踪用户发布的帖子数量。因此,合约从前端应用程序读取数据,这些数据是用户以博客文章形式输入的数据。一旦用户发出消息,合约就会增加跟踪该用户发布的帖子数量的数字。 

这涵盖了前三个 Solana 示例智能合约。不过,接下来我们将探讨第四个示例,它有点特殊,因为它与 NFT 有关。 

Solana NFT 智能合约示例

我们可以在此概述大量示例。但是,由于我们手头的时间有限,我们将看一个精心挑选的示例。现在,在仔细研究我们在几个不同的 Solana NFT 智能合约示例中的选择之前,值得一提的是 Metaplex。Metaplex 是一个著名的 NFT 生态系统,适用于游戏、市场、艺术品、收藏品等。该协议结合了工具和智能合约,为创建和启动 NFT 提供了无缝的工作流程。因此,如果您想了解有关 Solana NFT 智能合约开发的更多信息,值得一看 Metaplex。 

Metaplex 标志。

此外,我们之所以提到 Metaplex,是因为我们下面展示的 Solana NFT 智能合约就是基于该协议的。更具体地说,我们将简要介绍 Metaplex 的Candy Machine的 Solana NFT 智能合约。整个代码如下所示: 

使用anchor_lang :: prelude :: *;
酒吧使用错误:: CandyError;
使用说明:: *;
酒吧使用状态:: *;
酒吧使用实用程序:: *;
pub mod常量;
pub mod错误;
mod指令;
模式状态;
修改实用程序;
声明_id “CndyV3LdqHUfDLmE5naZjVN8rBZz4tqhdefbAnjHG3JR”
#[程序]
pub mod candy_machine_core {
   使用super :: *;
  /// 将每个NFT的配置(name+uri)添加到账户数据中。
   发布fn add_config_lines (
       ctx: 上下文< AddConfigLines >
       索引:u32,
配置        :Vec <ConfigLine>
   ) - >结果<()> {
       说明:: add_config_lines ctx,index,config_lines
   }
  /// 使用指定的数据初始化糖果机账户。
   pub fn初始化ctx:Context <Initialize> 数据:CandyMachineData - >结果<()> {
       指令::初始化ctx,数据
   }
  /// 铸造一个NFT。只有糖果机铸造机构才允许铸造。
   pub fn mint < 'info >(ctx:Context < ' _ ,' _ ,' _ ,'info,Mint < 'info >>)- >结果<()> {
       说明:: mint ( ctx )
   }
  /// 设置糖果机的新权限。
   pub fn set_authority ctx:Context <SetAuthority> new_authority:Pubkey - >结果<()> {
       说明:: set_authority ctx, new_authority
   }
  /// 为糖果机设置收集薄荷糖。
   pub fn set_collection ctx:Context <SetCollection> - >结果< ()> {
       说明:: set_collection ( ctx )
   }
  /// 设置糖果机新的铸造权限。
   pub fn set_mint_authority ctx:Context <SetMintAuthority> - >结果< ()> {
       说明:: set_mint_authority ctx
   }
  /// 更新糖果机配置。
   发布fn更新ctx:Context <Update> 数据:CandyMachineData - >结果<()> {
       指令::更新ctx,数据
   }
  /// 提取租赁灯泡并发送至授权地址。
   pub fn withdraw ctx:Context <Withdraw> - >结果<()> {
       指令::撤回( ctx )
   }
}

上述代码启用了 NFT 糖果机的所有功能。因此,它负责资产管理、索引生成/选择和铸造 NFT 的所有逻辑。此外,该合约使得铸造单个 NFT 或批量创建 NFT 成为可能。 

这涵盖了本教程的 Solana NFT 智能合约示例。下一节将快速向您展示如何实现和部署任何 Solana 智能合约示例!

如何部署 Solana 智能合约示例

编写完合约(例如本文中提到的 Solana 智能合约示例之一)后,您需要一种方法来构建合约并将其部署到 Solana 网络。因此,本节概述了此过程中的步骤,向您展示如何部署“ hello_world ”合约,这是我们上一节中的 Solana 智能合约示例之一。

首先,如果您还没有设置 Rust、Solana CLI 和 Solana 钱包,请先设置。接下来,打开您选择的 IDE 并启动一个新终端。然后,通过在终端中运行以下命令 设置“ Hello World ”Cargo 项目:

货物初始化 hello_world --lib

这将在您的目录中创建一个 Cargo 库,其中包含用于构建 Solana 智能合约示例的文件。然后,您可以使用以下命令导航到“hello_world”文件:

你好世界

接下来,打开”Cargo.toml”文件,复制下面的代码片段,并将其添加到文件底部: 

[]
名称= “hello_world”
板条箱-类型= [ “cdylib” “lib” ]

然后,您可以返回终端并通过运行以下命令添加 Solana 程序包: 

货物添加 solana_program

最后,打开”src/lib.rs”文件并将其所有内容替换为“ Solana 智能合约示例”部分中的“ hello_world ”合约代码

使用solana_program :: {
   account_info :: AccountInfo,entrypoint,entrypoint :: ProgramResult,msg,pubkey :: Pubkey,
}
入口点hello_world
发布fn hello_world (
   _program_id: & Pubkey, // 程序加载到的账户的公钥
   accounts: & [ AccountInfo ] , // 处理指令所需的所有账户
   _instruction_data: & [ u8 ] , // 序列化指令特定数据
) - >程序结果{
   msg ! ( "你好 {:}!!" , accounts [ 0 ] .key ) ;
   好的))
}

有了合约代码后,您现在可以通过输入以下 Cargo 命令并在终端中运行它来构建 Solana 智能合约:

货物建造-bpf

从那里开始,剩下的就是使用以下命令部署合约: 

solana 程序部署./target/deploy/hello_world.so

现在就完成了!您现在已经成功创建并部署了“ hello_world ”合约。现在,您可以将相同的原理用于要部署的任何其他 Solana 智能合约示例! 

作者:GTokenTool一键发币平台

交流群:https://t.me/+Kz4u3xoDpFo3ZWY1

同类推荐