编写忠诚度智能合约

现在您已经设置了开发环境,让我们开始编写智能合约。

现在让我们开始编写代码:

编写忠诚度合约

导航到 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);
  }
}

小结

恭喜您完成忠诚合约。从这里开始只会变得更有趣!接下来,我们将部署我们的合约。下一节见

quiz

get_reward函数的目的是什么?