手摸手带你用anchor框架写一个Bank链上程序

大家好,感谢你们点开这篇文章!如果有兴趣,欢迎关注我的 GitHub,里面有一些我的小项目和代码,水平有限,还请多多指教!

相关背景:

手把手带你写一个solana程序:计数器合约 这篇文章中,我们实现了一个简单的计数器合约,并从源码的层面对其中涉及到的一些概念做了梳理,想必大家已经掌握了基本的概念。深入理解账户的概念能帮助我们更好的掌握开发套路。

这篇文章,我们从工程化的角度来带领大家使用 anchor 框架来实现一个 Bank 链上程序。

环境准备:

一文说透,如何在solana上铸造spl-token 这篇文章中,我已经详细的介绍了开发环境的相关配置,这里不再赘述,有需要的朋友可以移步这里查看。

1、我们在本地查看环境配置:

arduino 复制代码
➜  ~ solana config get

Config File: /Users/louis/.config/solana/cli/config.yml
RPC URL: http://localhost:8899
WebSocket URL: ws://localhost:8900/ (computed)
Keypair Path: /Users/louis/.config/solana/id.json
Commitment: confirmed

从上面的输出可以看到,我目前连接的是本地环境,这篇文章,我们就使用这个环境来给大家做演示。

项目初始化:

1、找一个空的目录,使用 anchor init 命令进行项目初始化:

csharp 复制代码
➜ anchor init solana_bank_demo

执行上面命令之后,会使用 yarn 命令初始化项目,项目初始化之后,我们用编辑器打开,项目长这个样子。

2、查看一些常用的配置文件:

programs/solana_bank_demo/Cargo.toml:

ini 复制代码
[package]
name = "solana_bank_demo"
version = "0.1.0"
description = "Created with Anchor"
edition = "2021"

[lib]
crate-type = ["cdylib", "lib"]
name = "solana_bank_demo"

[features]
default = []
cpi = ["no-entrypoint"]
no-entrypoint = []
no-idl = []
no-log-ix-name = []
idl-build = ["anchor-lang/idl-build"]


[dependencies]
anchor-lang = "0.31.0"

我们来梳理下每个配置的作用,这里有一个坑点,我们稍后回来解决。

markdown 复制代码
### [package] 部分
- `name`: 定义包的名称为 "solana_bank_demo"
- `version`: 包的版本号,遵循语义化版本规范
- `description`: 包的描述信息
- `edition`: Rust 版本,使用 2021 版本

### [lib] 部分
- `crate-type`: 指定生成的库类型
  - `cdylib`: 生成动态链接库,用于与其他语言交互
  - `lib`: 生成 Rust 标准库
- `name`: 指定库的名称

### [features] 部分(Solana/Anchor 特定功能)
- `default`: 默认启用的特性列表
- `cpi`: Cross-Program Invocation 特性,用于程序间调用
- `no-entrypoint`: 禁用程序入口点,通常在作为依赖被其他程序调用时使用
- `no-idl`: 禁用 IDL(Interface Description Language)生成
- `no-log-ix-name`: 禁用指令名称日志记录
- `idl-build`: 启用 Anchor IDL 构建功能

### [dependencies] 部分
- `anchor-lang`: 依赖 Anchor 框架,版本 0.31.0,这是 Solana 智能合约开发的主要框架

/solana_bank_demo/Anchor.toml:

ini 复制代码
[toolchain]
package_manager = "yarn"

[features]
resolution = true
skip-lint = false

[programs.localnet]
solana_bank_demo = "G3ABM8zJtyFrJF5e2D5CwvRxh7jDqHxFd9Rw6MF7uMpX"

[registry]
url = "https://api.apr.dev"

[provider]
cluster = "localnet"
wallet = "~/.config/solana/id.json"

[scripts]
test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
markdown 复制代码
### [toolchain] 部分
- `package_manager`: 指定使用 yarn 作为包管理器

### [features] 部分
- `resolution`: 启用依赖解析功能
- `skip-lint`: 设置为 false,表示不跳过代码检查

### [programs.localnet] 部分
- `solana_bank_demo`: 定义程序 ID,这是程序在 Solana 网络上的唯一标识符
- `"G3ABM8zJtyFrJF5e2D5CwvRxh7jDqHxFd9Rw6MF7uMpX"` 是程序的公钥地址

### [registry] 部分
- `url`: 指定 Anchor 包注册表的 URL,用于发布和下载 Anchor 包

### [provider] 部分
- `cluster`: 设置为 "localnet",表示使用本地测试网络
- `wallet`: 指定钱包密钥对的路径,这里使用的是默认的 Solana CLI 钱包路径

### [scripts] 部分
- `test`: 定义测试命令
- 使用 ts-mocha 运行测试
- `-p ./tsconfig.json`: 指定 TypeScript 配置文件
- `-t 1000000`: 设置测试超时时间为 1000000 毫秒
- `tests/**/*.ts`: 运行 tests 目录下所有的 TypeScript 测试文件

我们需要重点关注的是 programs.localnet 这个部分,这里显示的是程序的公钥地址。

3、程序的公钥地址是如何生成的呢?

我们在初始化项目的时候,anchor 框架自动的帮我们生成了这个公钥地址,并且在 target/deploy 目录中,还生成了一个 json 文件,格式就是 program_name-keypair.json,所以我这个项目当前的 文件名称就是:solana_bank_demo-keypair.json

需要注意的是,程序 ID 是确定性的,由程序的密钥对唯一决定,在本地开发时,每次重新生成密钥对都会得到新的程序 ID,在生产环境中,应该妥善保管程序的密钥对文件,因为它关系到程序的所有权和更新权限。

执行构建操作:

我们迫不及待想执行 build 操作,来构建我们的程序。

复制代码
anchor build
vbnet 复制代码
➜  solana_bank_demo git:(master) ✗ anchor build                
error: rustc 1.79.0-dev is not supported by the following package:
                 Note that this is the rustc version that ships with Solana tools and not your system's rustc version. Use `solana-install update` or head over to https://docs.solanalabs.com/cli/install to install a newer version.
[email protected] requires rustc 1.84
Either upgrade rustc or select compatible dependency versions with
`cargo update <name>@<current-ver> --precise <compatible-ver>`
where `<compatible-ver>` is the latest version supporting rustc 1.79.0-dev

不出意外的话,肯定会出意外,直接报错,其实这个报错的原因就是 solana cli 中带有的 rustc 工具版本和我本地的安装的一个包不太兼容。[email protected] requires rustc 1.84,我本地安装的 rust 版本比较新:

vbnet 复制代码
➜  solana_bank_demo git:(master) ✗ rustup --version
rustup 1.28.1 (f9edccde0 2025-03-05)
info: This is the version for the rustup toolchain manager, not the rustc compiler.
info: The currently active `rustc` version is `rustc 1.85.0 (4d91de4e4 2025-02-17)`

如何解决呢?我尝试了一些方法,最终的解决方法是 对这个包进行降级:

sql 复制代码
➜  solana_bank_demo git:(master) ✗ cargo update [email protected] --precise 1.8.1
    Updating crates.io index
 Downgrading bytemuck_derive v1.9.2 -> v1.8.1

然后再次执行 anchor build,经过漫长的编译之后,就构建成功了。

执行测试操作:

在 tests 目录下,有一个测试文件,当我们指定 anchor test 的时候,就会执行这个测试文件。

bash 复制代码
➜  solana_bank_demo git:(master) ✗ anchor test                       
scss 复制代码
solana_bank_demo
Your transaction signature jmSFrCk1LvaeB9P9CtZbLsQaSnvFn9VXrTbpVDKyN3Ta9yUfoCfyvAaQevYvebQqoebosNdqSKsXLTcuWaoV1uc
    ✔ Is initialized! (265ms)

  1 passing (266ms)
✨  Done in 2.25s.

如果显示出上面的打印内容,说明测试的脚本成功执行了。

执行部署操作:

到这里,我们还没有看,脚手架给我们默认生成的程序结构呢:

rust 复制代码
use anchor_lang::prelude::*;

declare_id!("G3ABM8zJtyFrJF5e2D5CwvRxh7jDqHxFd9Rw6MF7uMpX");

#[program]
pub mod solana_bank_demo {
    use super::*;

    pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
        msg!("Greetings from: {:?}", ctx.program_id);
        Ok(())
    }
}

#[derive(Accounts)]
pub struct Initialize {}

其实很简单对吧,我们也并不需要关心它的内容,因为我们会把这部分内容全部删掉,然后写我们自己的逻辑。

在此之前,我们先测试一下部署到本地的测试环境:

yaml 复制代码
➜  solana_bank_demo git:(master) ✗ solana-test-validator

Ledger location: test-ledger
Log: test-ledger/validator.log
⠈ Initializing...                                                                                                                                                                                             Waiting for fees to stabilize 1...
Identity: FNR8SCwvQwdcjdGhzZdnoEK77RRrMDGsG4XJJpUPht19
Genesis Hash: 2c8WcTPfKsSNTsxdae3h2tkWU3uQWTRVi3dnVF6j1VcV
Version: 2.1.17
Shred Version: 47570
Gossip Address: 127.0.0.1:1024
TPU Address: 127.0.0.1:1027
JSON RPC URL: http://127.0.0.1:8899
WebSocket PubSub URL: ws://127.0.0.1:8900
⠐ 00:00:07 | Processed Slot: 16 | Confirmed Slot: 15 | Finalized Slot: 0 | Full Snapshot Slot: - | Incremental Snapshot Slot: - | Transactions: 15 | ◎499.999930000 

我使用了 solana-test-validator 命令启动了测试环境,怎么验证这个环境有没有启动成功呢?我们可以打开浏览器链接本地的端口查看,看到出块信息说明我们的本地环境已经搭建好了。

执行 anchor deploy 命令,部署我们的程序:

javascript 复制代码
➜  solana_bank_demo git:(master) ✗ anchor deploy
Deploying cluster: http://127.0.0.1:8899
Upgrade authority: /Users/louis/.config/solana/id.json
Deploying program "solana_bank_demo"...
Program path: /Users/louis/Documents/myProject/Solana_project/solana_bank_demo/target/deploy/solana_bank_demo.so...
Program Id: G3ABM8zJtyFrJF5e2D5CwvRxh7jDqHxFd9Rw6MF7uMpX

Signature: 4cygxMjzD18vuv5iZTDQYd6vMuvM3FmxPHLtPBKuipPiT6Lb2XyNS5AdEns7SMWyjAPFM3uXVMYpUw9YH4xPwFAT

Deploy success

浏览器能够看到相应的部署信息,说明我们的程序部署完成。

编写 Bank 合约:

bank 合约的功能比较简单:

  • 1、bank 合约目前只支持原生代币 sol 的存款和取款的功能;
  • 2、任何人都可以向程序中存入不小于0.01个sol代币;
  • 3、用户任何时候可以从中提取自己的资金;
  • 4、程序中需要维护每个人的在bank中的余额,可以供外部查看每个人资金的情况;
  • 5、需要维护bank智能合约中总的余额;
  • 6、合约的部署人员也没有权限动用别人的资金;

好了,上面就是我们合约的全部需求了。我这里贴上提前写好的程序:

rust 复制代码
use anchor_lang::prelude::*;
use anchor_lang::solana_program::system_instruction;

declare_id!("98Frhx1UD56goz5ns2vTR6WaqHLPsJE7Jux8iWgJr3Fv");

#[program]
pub mod solana_bank_demo {
    use super::*;

    pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
        msg!("Initializing bank contract");
        let bank = &mut ctx.accounts.bank;
        bank.owner = ctx.accounts.owner.key();
        bank.total_balance = 0;
        Ok(())
    }

    pub fn deposit(ctx: Context<Deposit>, amount: u64) -> Result<()> {
        const MIN_DEPOSIT: u64 = 10_000_000; // 0.01 SOL
        msg!(
            "Processing deposit of {} lamports from user: {}",
            amount,
            ctx.accounts.user.key()
        );
        require!(amount >= MIN_DEPOSIT, BankError::DepositTooSmall);

        let transfer_instruction = system_instruction::transfer(
            &ctx.accounts.user.key(),
            &ctx.accounts.bank.key(),
            amount,
        );

        anchor_lang::solana_program::program::invoke(
            &transfer_instruction,
            &[
                ctx.accounts.user.to_account_info(),
                ctx.accounts.bank.to_account_info(),
                ctx.accounts.system_program.to_account_info(),
            ],
        )?;

        let user_account = &mut ctx.accounts.user_account;
        let old_balance = user_account.balance;
        user_account.balance = user_account.balance.checked_add(amount).unwrap();

        let bank = &mut ctx.accounts.bank;
        bank.total_balance = bank.total_balance.checked_add(amount).unwrap();
        msg!(
            "Deposit successful. User balance: {} -> {}, Bank total: {}",
            old_balance,
            user_account.balance,
            bank.total_balance
        );

        Ok(())
    }

    pub fn withdraw(ctx: Context<Withdraw>, amount: u64) -> Result<()> {
        let user_account = &mut ctx.accounts.user_account;
        msg!(
            "Processing withdrawal of {} lamports for user: {}",
            amount,
            ctx.accounts.user.key()
        );
        require!(user_account.balance >= amount, BankError::InsufficientFunds);

        let old_balance = user_account.balance;
        let old_bank_balance = ctx.accounts.bank.total_balance;

        **ctx
            .accounts
            .bank
            .to_account_info()
            .try_borrow_mut_lamports()? -= amount;
        **ctx
            .accounts
            .user
            .to_account_info()
            .try_borrow_mut_lamports()? += amount;

        user_account.balance = user_account.balance.checked_sub(amount).unwrap();

        let bank = &mut ctx.accounts.bank;
        bank.total_balance = bank.total_balance.checked_sub(amount).unwrap();
        msg!(
            "Withdrawal successful. User balance: {} -> {}, Bank total: {} -> {}",
            old_balance,
            user_account.balance,
            old_bank_balance,
            bank.total_balance
        );

        Ok(())
    }

    pub fn get_balance(ctx: Context<GetBalance>) -> Result<u64> {
        let balance = ctx.accounts.user_account.balance;
        msg!(
            "Queried balance for user {}: {} lamports",
            ctx.accounts.user.key(),
            balance
        );
        Ok(balance)
    }
}

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(
        init,
        payer = owner,
        space = 8 + 32 + 8,
        seeds = [b"bank"],
        bump
    )]
    pub bank: Account<'info, Bank>,
    #[account(mut)]
    pub owner: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct Deposit<'info> {
    #[account(mut, seeds = [b"bank"], bump)]
    pub bank: Account<'info, Bank>,
    #[account(
        init_if_needed,
        payer = user,
        space = 8 + 8,
        seeds = [b"user", user.key().as_ref()],
        bump
    )]
    pub user_account: Account<'info, UserAccount>,
    #[account(mut)]
    pub user: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct Withdraw<'info> {
    #[account(mut, seeds = [b"bank"], bump)]
    pub bank: Account<'info, Bank>,
    #[account(mut, seeds = [b"user", user.key().as_ref()], bump)]
    pub user_account: Account<'info, UserAccount>,
    #[account(mut)]
    pub user: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct GetBalance<'info> {
    #[account(seeds = [b"user", user.key().as_ref()], bump)]
    pub user_account: Account<'info, UserAccount>,
    pub user: Signer<'info>,
}

#[account]
pub struct Bank {
    pub owner: Pubkey,
    pub total_balance: u64,
}

#[account]
pub struct UserAccount {
    pub balance: u64,
}

#[error_code]
pub enum BankError {
    #[msg("Deposit amount must be at least 0.01 SOL")]
    DepositTooSmall,
    #[msg("Insufficient funds for withdrawal")]
    InsufficientFunds,
}

当我把这个代码贴到 lib.rs 中的时候,程序就直接报错了,提示我们当前我们的配置中不支持 init_if_needed 这个特性,还记得上面我们说的一个坑点吗,就是这里,我们修改下 Cargo.toml 相关配置:

programs/solana_bank_demo/Cargo.toml

ini 复制代码
[dependencies]
anchor-lang = { version = "0.31.0", features = ["init-if-needed"] }

添加完毕之后,发现我们的程序不报错了。

编译 bank 合约:

我们先清除掉之前的 build 的程序,然后再重新构建

bash 复制代码
anchor clean

anchor build

......

Finished `test` profile [unoptimized + debuginfo] target(s) in 17.19s
 Running unittests src/lib.rs (/Users/louis/Documents/myProject/Solana_project/solana_bank_demo/target/debug/deps/solana_bank_demo-829da3616c2d2786)

经过漫长的编译之后,我们开始部署自己的程序,在这之前我们还需要做一下 id 的同步:

bash 复制代码
anchor keys sync

执行完毕这个操作之后,我们代码中的 id 和 Anchor.toml 中的 id 就一致了。

部署到本地环境:

还记得我们本地启动的测试环境吗?

yaml 复制代码
➜  solana_bank_demo git:(master) ✗ solana-test-validator
Ledger location: test-ledger
Log: test-ledger/validator.log
⠙ Initializing...                                                                                                           Waiting for fees to stabilize 1...
Identity: KpdErpE6AYG8szQxg2MwYj2GFKXS3HJzjR3FzG6w8gd
Genesis Hash: GpWY36cVJZmxqMvchiUPgZHSPxdJcToGC5qQozKkGWyK
Version: 2.1.17
Shred Version: 9555
Gossip Address: 127.0.0.1:1024
TPU Address: 127.0.0.1:1027
JSON RPC URL: http://127.0.0.1:8899
WebSocket PubSub URL: ws://127.0.0.1:8900
⠖ 00:00:22 | Processed Slot: 48 | Confirmed Slot: 48 | Finalized Slot: 17 | Full Snapshot Slot: - | Incremental Snapshot Slot:

我们的测试和部署都要依赖于这个环境来做。

javascript 复制代码
➜  solana_bank_demo git:(master) ✗ anchor deploy
Deploying cluster: http://127.0.0.1:8899
Upgrade authority: /Users/chupengfei/.config/solana/id.json
Deploying program "solana_bank_demo"...
Program path: /Users/chupengfei/Documents/myProject/Solana_project/solana_bank_demo/target/deploy/solana_bank_demo.so...
Program Id: 98Frhx1UD56goz5ns2vTR6WaqHLPsJE7Jux8iWgJr3Fv

Signature: 24FuV8YRdnnUuVbiA39MQPmKZb8gzmziHCeUpomfpkYEJR893nzpgEuCmZ3qBZQq68H5jv2E1K5iwBt3qdRkmTfo

Deploy success
➜  solana_bank_demo git:(master) ✗ 

从上面的部署信息输出可以看出,我们部署成功了。

本地环境跑测试用例:

程序部署成功之后,我们就要开始写测试用例,完善的测试用例能够保证程序的安全性。这里我已经准备好了测试用例:

ts 复制代码
import * as anchor from "@coral-xyz/anchor";
import { Program } from "@coral-xyz/anchor";
import { SolanaBankDemo } from "../target/types/solana_bank_demo";
import { PublicKey } from '@solana/web3.js';
import { expect } from 'chai';

describe("solana_bank", () => {
  // Configure the client to use the local cluster.
  anchor.setProvider(anchor.AnchorProvider.env());

  const program = anchor.workspace.SolanaBank as Program<SolanaBankDemo>;
  const provider = anchor.getProvider();

  // 生成银行PDA地址
  const [bankPDA] = PublicKey.findProgramAddressSync(
    [Buffer.from("bank")],
    program.programId
  );

  it("Initialize bank", async () => {
    const tx = await program.methods
      .initialize()
      .accounts({
        bank: bankPDA,
        owner: provider.publicKey,
        systemProgram: anchor.web3.SystemProgram.programId,
      })
      .rpc();
    
    console.log("Bank initialized with tx:", tx);

    // 验证初始化结果
    const bankAccount = await program.account.bank.fetch(bankPDA);
    expect(bankAccount.owner.toString()).to.equal(provider.publicKey.toString());
    expect(bankAccount.totalBalance.toString()).to.equal("0");
  });


  it("Deposit funds", async () => {
    // 生成用户账户PDA
    const [userAccountPDA] = PublicKey.findProgramAddressSync(
      [Buffer.from("user"), provider.publicKey.toBuffer()],
      program.programId
    );

    const depositAmount = new anchor.BN(1_000_000_000); // 1 SOL
    
    const tx = await program.methods
      .deposit(depositAmount)
      .accounts({
        bank: bankPDA,
        userAccount: userAccountPDA,
        user: provider.publicKey,
        systemProgram: anchor.web3.SystemProgram.programId,
      })
      .rpc();

    console.log("Deposit tx:", tx);

    // 验证存款结果
    const userAccount = await program.account.userAccount.fetch(userAccountPDA);
    expect(userAccount.balance.toString()).to.equal(depositAmount.toString());
  });

  it("Get balance", async () => {
    const [userAccountPDA] = PublicKey.findProgramAddressSync(
      [Buffer.from("user"), provider.publicKey.toBuffer()],
      program.programId
    );

    const balance = await program.methods
      .getBalance()
      .accounts({
        userAccount: userAccountPDA,
        user: provider.publicKey,
      })
      .view();

    console.log("User balance:", balance.toString());
    // 验证余额结果
    expect(balance.toString()).to.equal("1000000000");
  });

  it("Withdraw funds", async () => {
    const [userAccountPDA] = PublicKey.findProgramAddressSync(
      [Buffer.from("user"), provider.publicKey.toBuffer()],
      program.programId
    );

    const withdrawAmount = new anchor.BN(500_000_000); // 0.5 SOL

    const tx = await program.methods
      .withdraw(withdrawAmount)
      .accounts({
        bank: bankPDA,
        userAccount: userAccountPDA,
        user: provider.publicKey,
        systemProgram: anchor.web3.SystemProgram.programId,
      })
      .rpc();

    console.log("Withdraw tx:", tx);

    // 验证取款结果
    const userAccount = await program.account.userAccount.fetch(userAccountPDA);
    expect(userAccount.balance.toString()).to.equal("500000000");
  });

  it("Should fail with insufficient funds", async () => {
    const [userAccountPDA] = PublicKey.findProgramAddressSync(
      [Buffer.from("user"), provider.publicKey.toBuffer()],
      program.programId
    );

    const withdrawAmount = new anchor.BN(1_000_000_000); // 尝试取出1 SOL(超过余额)

    try {
      await program.methods
        .withdraw(withdrawAmount)
        .accounts({
          bank: bankPDA,
          userAccount: userAccountPDA,
          user: provider.publicKey,
          systemProgram: anchor.web3.SystemProgram.programId,
        })
        .rpc();
      expect.fail("应该失败但没有失败");
    } catch (error) {
      expect(error.toString()).to.include("Insufficient funds for withdrawal");
    }
  });
});

我们执行 anchor test 查看执行结果:

bash 复制代码
➜  solana_bank_demo git:(master) ✗ anchor test 
    Finished `release` profile [optimized] target(s) in 0.33s
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.32s
     Running unittests src/lib.rs (/Users/louis/Documents/myProject/Solana_project/solana_bank_demo/target/debug/deps/solana_bank_demo-829da3616c2d2786)

Found a 'test' script in the Anchor.toml. Running it as a test suite!

Running test suite: "/Users/louis/Documents/myProject/Solana_project/solana_bank_demo/Anchor.toml"

Error: Your configured rpc port: 8899 is already in use

发现报错了,这是因为,我们本地已经启动了测试环境,我们需要叫上一个配置来复用这个环境。

bash 复制代码
➜  solana_bank_demo git:(master) ✗ anchor test --skip-local-validator
    Finished `release` profile [optimized] target(s) in 0.30s
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.33s
     Running unittests src/lib.rs (/Users/chupengfei/Documents/myProject/Solana_project/solana_bank_demo/target/debug/deps/solana_bank_demo-829da3616c2d2786)
Deploying cluster: http://127.0.0.1:8899
Upgrade authority: /Users/chupengfei/.config/solana/id.json
Deploying program "solana_bank_demo"...
Program path: /Users/chupengfei/Documents/myProject/Solana_project/solana_bank_demo/target/deploy/solana_bank_demo.so...
Program Id: 98Frhx1UD56goz5ns2vTR6WaqHLPsJE7Jux8iWgJr3Fv

Signature: 3b5YsQEyKpzKMfauJpArDd1eCeh2Pia1sn8ehwGBuNfxETogFBcbUvUiMsUgjvTqYbqnaYJkJjQPtQ63FWVffa6v

Deploy success

Found a 'test' script in the Anchor.toml. Running it as a test suite!

Running test suite: "/Users/chupengfei/Documents/myProject/Solana_project/solana_bank_demo/Anchor.toml"

yarn run v1.22.22
$ /Users/chupengfei/Documents/myProject/Solana_project/solana_bank_demo/node_modules/.bin/ts-mocha -p ./tsconfig.json -t 1000000 'tests/**/*.ts'
(node:64554) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.
(Use `node --trace-deprecation ...` to show where the warning was created)


  solana_bank
Bank initialized with tx: 2jrHk6x8dvXDrWjPwCY6aA1hRniLxeTyUrkPx7T9DGyU8vGszhGstskCMxVGZUsMBomwpDwMAJovW4Lzh9t4GjpS
    ✔ Initialize bank (290ms)
Deposit tx: 5ocrYK7MVBNanSrjvRWeBy9WJbSPwAvfQ3xFvjQTHMemQZcqoqvNy17ppbLVLvbSujVAPERsQqiK8Bba6KF8wn5q
    ✔ Deposit funds (461ms)
User balance: 1000000000
    ✔ Get balance
Withdraw tx: 5ykX6uGur9oHsnWr5QauhhwDVcaxBpJpTtfs6DF2M5SwpQAZAqN5re1XUEDtEuKb9AW6UJzeunh24FTF46mNMceG
    ✔ Withdraw funds (452ms)
    ✔ Should fail with insufficient funds


  5 passing (1s)

✨  Done in 2.40s.

你看,我们的所有测试用例都执行完毕了,而且通过了。

代码仓库链接:

github.com/MagicalBrid...

相关推荐
Blockchina1 天前
第 4 章 | Solidity安全 权限控制漏洞全解析
安全·web3·区块链·智能合约·solidity
Blockchina2 天前
第十四章 | DeFi / DAO / GameFi 项目高级实战
web3·区块链·智能合约·solidity
龙兵兵科技2 天前
利用智能合约技术打破线下陪玩私单僵局的可行性分析
智能合约·软件开发·线下陪玩·同城陪玩
渗透测试老鸟-九青2 天前
记一次常规的网络安全渗透测试
运维·服务器·安全·web安全·区块链·智能合约
0x派大星4 天前
打造更安全的区块链资产管理:Solidity 多重签名机制详解
安全·web3·区块链·智能合约·solidity
Blockchina5 天前
第十五章 | Layer2、Rollup 与 ZK 技术实战解析
python·web3·区块链·智能合约·solidity
Blockchina5 天前
第 2 章 | 智能合约攻击图谱全景解析
web3·区块链·智能合约·solidity·区块链安全
Blockchina5 天前
第 1 章 | 开篇词:Dapp安全 区块链安全 Web3安全 区块链合约一旦部署,安全就是生死线
安全·web3·区块链·智能合约·solidity·合约审计
我是前端小学生6 天前
一文说透,如何在solana上铸造spl-token
智能合约