编写忠诚度智能合约
现在您已经设置了开发环境,让我们开始编写智能合约。
现在让我们开始编写代码:
编写忠诚度合约
导航到 sources/loyalty.move 。让我们逐行查看您将要编写的代码:
首先, metaschool 是包名称。它应该与我们使用命令 sui move new metaschool 初始化 Sui 工作区的文件夹名称相同。因此,如果您使用了任何其他名称,请务必在此处替换它。此外, loyalty 是模块名称。因此,如果您将其命名为 loyalty 之外的其他名称,请务必在此处进行更新。
#![allow(unused)] fn main() { module loyalty::loyalty }
- 此行定义了一个名为 
metaschool::loyalty的模块,它将包含忠诚度合同的实现。模块是一种组织代码并将相关功能分组在一起的方法。 
#![allow(unused)] fn main() { use sui::clock::Clock; use sui::object::{Self, UID}; use sui::coin::{Self, Coin}; use sui::tx_context::TxContext; use sui::balance::{Self, Balance}; use deepbook::clob_v2::Pool; use deepbook::custodian_v2::AccountCap; use dex::eth::ETH; use dex::usdc::USDC; use dex::dex::{Self, DEX, Storage}; }
- 在这里,我们导入包含要在代码中使用的预构建函数和类型的模块。
 
#![allow(unused)] fn main() { public struct LoyaltyAccount has key, store { id: UID, stake: Balance<DEX>, points: u64 } public struct NFT has key, store { id: UID } }
- 现在我们定义了一个对象,其中包含程序中质押的 DEX 币数量以及每次交换累积的积分数量的信息。
 
现在让我们创建一个函数 create_account ,它创建一个帐户对象来跟踪用户积分和赌注金额,如下所示:
#![allow(unused)] fn main() { public fun create_account(ctx: &mut TxContext): LoyaltyAccount { LoyaltyAccount { id: object::new(ctx), stake: balance::zero(), points: 0 } } }
- 我们将创建另一个函数 
loyalty_account_stake,它允许模块读取LoyaltyAccount中质押的 DEX 代币数量。我们还将创建一个函数loyalty_account_points来读取LoyaltyAccount中的点数。 
#![allow(unused)] fn main() { public fun loyalty_account_stake(account: &LoyaltyAccount): u64 { balance::value(&account.stake) } public fun loyalty_account_points(account: &LoyaltyAccount): u64 { account.points } }
- 接下来,我们将创建一个 get_reward 函数,该函数向用户铸造 NFT,以换取 5 个积分。我们还需要确保在 NFT 铸币之后,这 5 个积分会从用户的账户中扣除。
 
#![allow(unused)] fn main() { public fun get_reward(account: &mut LoyaltyAccount, ctx: &mut TxContext): NFT { assert!(account.points >= 5, ENeeds5Points); let points_ref = &mut account.points; *points_ref = *points_ref - 5; NFT { id: object::new(ctx) } } }
- 最后,我们正在创建一个用于质押 DEX 币并赚取奖励的功能,如下所示:
 
#![allow(unused)] fn main() { public fun stake( account: &mut LoyaltyAccount, stake: Coin<DEX> ) { balance::join(&mut account.stake, coin::into_balance(stake)); } public fun unstake( account: &mut LoyaltyAccount, ctx: &mut TxContext ): Coin<DEX> { let value = loyalty_account_stake(account); coin::take(&mut account.stake, value, ctx) } public fun place_market_order( account: &mut LoyaltyAccount, self: &mut Storage, pool: &mut Pool<ETH, USDC>, account_cap: &AccountCap, quantity: u64, is_bid: bool, base_coin: Coin<ETH>, quote_coin: Coin<USDC>, c: &Clock, ctx: &mut TxContext, ): (Coin<ETH>, Coin<USDC>, Coin<DEX>) { let (eth, usdc, coin_dex) = dex::place_market_order(self, pool, account_cap, quantity, is_bid, base_coin, quote_coin, c, ctx); if (loyalty_account_stake(account) != 0) { let points_ref = &mut account.points; *points_ref = *points_ref + 1; }; (eth, usdc, coin_dex) } }
我们已成功创建忠诚度合同。
完整代码
最终合同应如下所示:
module loyalty::loyalty {
  
  use sui::clock::Clock;
  use sui::object::{Self, UID};
  use sui::coin::{Self, Coin};
  use sui::tx_context::TxContext;
  use sui::balance::{Self, Balance};
  use deepbook::clob_v2::Pool;
  use deepbook::custodian_v2::AccountCap;
  
  use dex::eth::ETH;
  use dex::usdc::USDC;
  use dex::dex::{Self, DEX, Storage};
  const ENeeds5Points: u64 = 0;
  public struct LoyaltyAccount has key, store {
    id: UID,
    // Amount of DEX Coin staked in the program
    stake: Balance<DEX>,
    // Amount of points accumulated per swap
    points: u64
  }
  
  public struct NFT has key, store {
    id: UID
  }
  // @dev It creates an account object to keep track of a user points and stake amount
  public fun create_account(ctx: &mut TxContext): LoyaltyAccount {
    LoyaltyAccount {
      id: object::new(ctx),
      stake: balance::zero(),
      points: 0
    }
  }
  // @dev It allows a module to read the amount of DEX coins staked in an `LoyaltyAccount`
  public fun loyalty_account_stake(account: &LoyaltyAccount): u64 {
    balance::value(&account.stake)
  }
  // @dev It allows a module to read the number of points in a `LoyaltyAccount`
  public fun loyalty_account_points(account: &LoyaltyAccount): u64 {
    account.points
  }
  // @dev It mints an NFT to the user in exchange for 5 points
  public fun get_reward(account: &mut LoyaltyAccount, ctx: &mut TxContext): NFT {
    // Make sure he has at least 5 points
    assert!(account.points >= 5, ENeeds5Points);
    // Deduct 5 points
    let points_ref = &mut account.points;
    *points_ref = *points_ref - 5;
    // Mint the reward
    NFT {
      id: object::new(ctx)
    }
  }
  public fun stake(
    account: &mut LoyaltyAccount,
    stake: Coin<DEX>
  ) {
    // Deposit the coin in the contract
    balance::join(&mut account.stake, coin::into_balance(stake));
  }
  public fun unstake(
    account: &mut LoyaltyAccount,
    ctx: &mut TxContext
  ): Coin<DEX> {
    // Save the total balance amount in memory
    let value = loyalty_account_stake(account);
    // unstake the balance into a coin
    coin::take(&mut account.stake, value, ctx)
  }
  // @ User can swap via the program to earn points
  public fun place_market_order(
    account: &mut LoyaltyAccount,
    self: &mut Storage,
    pool: &mut Pool<ETH, USDC>,
    account_cap: &AccountCap,
    quantity: u64,
    is_bid: bool,
    base_coin: Coin<ETH>,
    quote_coin: Coin<USDC>,
    c: &Clock,
    ctx: &mut TxContext,    
  ): (Coin<ETH>, Coin<USDC>, Coin<DEX>) {
    let (eth, usdc, coin_dex) = dex::place_market_order(self, pool, account_cap, quantity, is_bid, base_coin, quote_coin, c, ctx);
          // If the user has 0 DEX tokens staked he earns no points
      if (loyalty_account_stake(account) != 0) {
        
          // Borrow mut
          let points_ref = &mut account.points;
          // Increment
          *points_ref = *points_ref + 1;
      };
    (eth, usdc, coin_dex)
  }
  // @dev It allows a test file to destroy the Loyalty Account object
  #[test_only]
  public fun destroy_account_for_testing(account: LoyaltyAccount) {
    // @dev Properties without the drop ability must be destroyed via their libraries
    let LoyaltyAccount { id, stake, points: _ } = account;
    balance::destroy_for_testing(stake);
    object::delete(id);
  }
  // @dev It allows a test file to destroy the NFT object
  #[test_only]
  public fun destroy_nft_for_testing(nft: NFT) {
    let NFT { id} = nft;
    object::delete(id);
  }
}
小结
恭喜您完成忠诚合约。从这里开始只会变得更有趣!接下来,我们将部署我们的合约。下一节见