乐趣区

关于区块链:Near-Protocol-Near开发Demo浅析Gamble-Game-Near一智能合约

[Near Protocol] Near 开发 Demo 浅析 -Gamble Game Near

智能合约

大家好,Near Protocol 是近年来比拟引人注目的公链我的项目,其分片技术也使得其性能和稳定性呈现了很大的晋升和冲破。我最近对 Near 相干开发的根底概念进行了学习,以掷色子游戏的概念为根底,开发了 Near 合约 +Dapp 的 Demo,当初和大家分享探讨,心愿都能有所进益。

源代码在 Github 上能够找到,以下是智能合约链接:

https://github.com/Yang94J/Gamble_Game_Near

简介

合约名称:Gamble
合约性能:容许用户通过发送 Near 进行投注,通过随机数模仿掷色子流动,当掷到 6 时,能够取得 6 倍返还。
实现语言:Rust
部署网络:Near Testnet
Near-sdk 文档:https://www.near-sdk.io


环境搭建

  • Prerequisite : 零碎中该当曾经装置好 Rust
  • 装置 wasm32(编译):

          rustup target add wasm32-unknown-unknown
  • 初始化我的项目(编译):

          cargo new Gamble_Game_Near
  • 在生成的工程上进行目录的批改,最终构造如下:

    其中 lib.rs 是合约文件,而 Cargo.toml 形容依赖(你能够了解为相似于 Maven 我的项目中的 pom.xml),而 Cargo.lock 则蕴含依赖项的确切信息。

<h3> 代码解析 </h3>

Cargo.toml

以下是 Cargo.toml 重点局部

[lib]
crate-type = ["cdylib","rlib"]

[dependencies]
uint = {version = "0.9.0", default-features = false}
near-sdk = "4.0.0-pre.7"
near-contract-standards = "4.0.0-pre.7"

其中 crate-type 指定为 C 动态链接库及 Rust 链接库,依赖应用 4.0.0-pre.7 版本的 near-sdk

lib.rs

lib.rs 首先从 near-sdk 中导入相干函数及接口:

use near_sdk::{borsh::{self, BorshDeserialize, BorshSerialize},
    near_bindgen, Balance,PanicOnDefault,
    env, require, log,  Promise, 
};

同时通过 #[near_bindgen]#[derive(BorshDeserialize, BorshSerialize,PanicOnDefault)]来申明 Gamble 类为智能合约类。#[near_bindgen]宏用以生成 Near 合约所需的代码并对外裸露接口。#[derive(BorshDeserialize, BorshSerialize,PanicOnDefault)]则声明序列化、反序列化,且要求实现构造函数。Gamble 类中蕴含 gamble_min_pricegamble_max_price属性,为投注的最小值和最大值。

pub struct Gamble {

    // Minimum price that should be transfered to the contract, revert otherwise
    gamble_min_price : Balance,

    // Maximum price that should be transfered to the contract, revert otherwise
    gamble_max_price : Balance,

}

本文后续实现 Gamble 类的相干办法,(留神 &self 和 &mut self 的区别,相似于 solidity view 和 change 的区别)如下:

  • pub fn new() -> Self:用以初始化合约,设置 gamble_min_pricegamble_max_price属性。
    #[init]
    pub fn new() -> Self {let account_balance = env::account_balance();
        let gamble_max_price = account_balance / (5 * FACTOR);
        log!("we have {} uints in total, be sure not to exceed the max gamble price limit {} to get {}X \n", account_balance, gamble_max_price, FACTOR);

        Self{
            gamble_max_price : gamble_max_price,
            gamble_min_price : 0,
        }
    }
  • pub fn get_minimal_gamble_price(&self) -> u128:获取最小投注数量(yoctoNEAR)
    // Get the Minimum amount of near to be transfered(Used for dapp, but usually won't as it's 0 all the time)
    pub fn get_minimal_gamble_price(&self) -> u128 {self.gamble_min_price}
  • pub fn get_maximum_gamble_price(&self) -> u128:获取最大投注数量(yoctoNEAR)
    // Get the Minimum amount of near to be transfered(Used for dapp)
    pub fn get_maximum_gamble_price(&self) -> u128 {self.gamble_max_price}    
  • pub fn get_balance(&self) -> u128:获取合约余额(yoctoNEAR)
    // Get contract balance U128
    pub fn get_balance(&self) -> u128 {env::account_balance()
    }  
  • pub fn update_price(&mut self):更新投注最大值和最小值
    // Update price everytime the account balance changes
    // Only contract call
    fn update_price(&mut self){let account_balance = env::account_balance();
        self.gamble_max_price = account_balance / (5 * FACTOR);
        log!("we have {} uints in total, be sure not to exceed the max gamble price limit {} to get {}X \n", account_balance, self.gamble_max_price, FACTOR);
    }
  • pub fn sponsor(&mut self):资助函数,即用户向合约账号发送 near(yoctoNEAR),最初更新投注下限和上限
    // The user could sponsor the contract(maybe only the owner will...)
    #[payable]
    pub fn sponsor(&mut self){let sponsor_id = env::signer_account_id();
        let deposit = env::attached_deposit();
        log!("sponsor {} has add {} to the game to increase balance, thank you ~ \n", sponsor_id, deposit);
        self.update_price();}
  • pub fn gamble(&mut self) -> u8:投掷函数,返回投掷出的点数(1-6),最初更新投注下限和上限
    // The user could transfer near to get a chance to gamble
    // return the dice throwed by the user (Randomly generated)
    #[payable]
    pub fn gamble(&mut self) -> u8{let gambler_id = env::signer_account_id();
        let deposit = env::attached_deposit();

        require!(deposit>=self.gamble_min_price,"The gamble price must exceed gamble_min_price");
        require!(deposit<=self.gamble_max_price,"The gamble price must not exceed gamble_max_price");
        
        let num = self.rand_dice();

        if num == FACTOR as u8 {let amount = (deposit as f32) *(FACTOR as f32) * TAX;
            let amount_u128 = amount  as u128;
            log!("Congratuations to {}, he has won the gamble, the prize is {} \n",gambler_id,deposit);
            Promise::new(gambler_id).transfer(amount_u128);
        }
        self.update_price();
        return num;
    }
  • pub fn rand_dice(&self) -> u8:基于 random_seed(),生成随机数并通过取余映射到 1 -6
    // Generate random number from 1 to 6
    pub fn rand_dice(&self) -> u8 {*env::random_seed().get(0).unwrap()%6+1}

后续则是单元测试局部,通过 fn get_context(input: Vec<u8>) -> VMContext 设置了测试背景,由 fn rand_test() 测试了随机数生成,fn gamble_test()则测试了合约初始化后的变量状况。

合约部署

  • 在此之前请先装置 Near-cli
  • 编译生成
        cargo build --target wasm32-unknown-unknown --release
  • 部署(学生成子账号再部署)
        near create-account gamble_game1.XXX.testnet --masterAccount XXX.testnet --initialBalance 100
        near deploy --wasmFile target/wasm32-unknown-unknown/release/gamble_game_near.wasm --accountId gamble_game1.XXX.testnet
  • 测试
        near call gamble_game1.XXX.testnet new  --accountId gamble_game1.XXX.testnet
        near view gamble_game1.XXX.testnet get_balance
        near view gamble_game1.XXX.testnet get_maximum_gamble_price
        near call gamble_game1.XXX.testnet sponsor --deposit 1  --accountId XXX.testnet
        near call gamble_game1.XXX.testnet gamble --deposit 1  --accountId XXX.testnet

至此,智能合约局部实现,后续会带来
[Near Protocol] Near 开发 Demo 浅析 -Gamble Game Near(二):Dapp 局部的介绍。

退出移动版