Solana Anchor 程序接口定义语言(IDL)

本文将带你探索 Anchor 框架中的 IDL(接口定义语言),这是一个自动生成的 JSON 文件,用于描述 Solana 程序的接口。我们将通过示例展示 IDL 的作用,解释 TypeScript 测试如何调用程序函数。


什么是 IDL?

IDL(Interface Definition Language)是 Anchor 生成的程序接口定义,存储在 target/idl/<program_name>.json 中,类似于 Solidity 的 ABI。它列出了程序的公共函数(instructions)、参数(args)和账户要求(accounts),为客户端(如 TypeScript)提供与链上程序交互的蓝图。


示例 1:函数调用与 IDL 映射

初始化项目

创建一个新项目:

复制代码
anchor init anchor-function-tutorial
cd anchor-function-tutorial

启动本地验证器:

复制代码
solana-test-validator

修改函数名

将默认的 initialize 函数改为 boaty_mc_boatface。编辑 programs/anchor-function-tutorial/src/lib.rs:

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

declare_id!("3ytdGXdSqfQ5Z9NB9c5bGbkNqkzVPkpijs4hj4BeoAa7");

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

    pub fn boaty_mc_boatface(ctx: Context<Initialize>) -> Result<()> {
        msg!("Boaty says hi!");
        Ok(())
    }
}

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

更新测试

编辑 tests/anchor-function-tutorial.ts:

复制代码
it("Call boaty mcboatface", async () => {
    const tx = await program.methods.boatyMcBoatface().rpc();
    console.log("Your transaction signature", tx);
});

运行测试:

复制代码
anchor test --skip-local-validator

测试如何定位函数?

Anchor 在构建时生成 IDL(target/idl/anchor_function_tutorial.json):

复制代码
{
  "version": "0.1.0",
  "name": "anchor_function_tutorial",
  "instructions": [
    {
      "name": "boatyMcBoatface",
      "accounts": [],
      "args": []
    }
  ],
  "metadata": {
    "address": "3ytdGXdSqfQ5Z9NB9c5bGbkNqkzVPkpijs4hj4BeoAa7"
  }
}
  • 解析
    • "instructions":列出公共函数,类似 Solidity 的外部函数。
    • TypeScript 的 program.methods 根据 IDL 映射函数名,生成调用逻辑。

Anchor 0.30.x 后的命名规则

如果在 Anchor 0.30.0 及以上版本(如 0.30.1):

  • 函数名 :保留 Rust 的蛇形命名(如 boaty_mc_boatface),不再转换为驼峰式(如 boatyMcBoatface)。
    • 原因:提升 Rust 代码与 IDL 的一致性,响应社区反馈。
  • 参数和账户名:仍使用驼峰式(如 firstArg、anotherSigner),适配 JavaScript/TypeScript 惯例。

测试调用注意

复制代码
await program.methods.boatyMcBoatface();   // 正确,客户端仍需驼峰式
await program.methods.boaty_mc_boatface(); // 可行但不推荐
  • 经验建议:尽管 IDL 使用蛇形命名,建议在前端保持驼峰式调用,以符合生态习惯。

示例 2:带参数的算术函数

添加加减法函数

更新 lib.rs,实现加法和减法(Solana 不支持直接返回值,需用 msg! 输出):

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

declare_id!("3ytdGXdSqfQ5Z9NB9c5bGbkNqkzVPkpijs4hj4BeoAa7");

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

    pub fn add(ctx: Context<Empty>, a: u64, b: u64) -> Result<()> {
        let sum = a + b;
        msg!("Sum is {}", sum);
        Ok(())
    }

    pub fn sub(ctx: Context<Empty>, a: u64, b: u64) -> Result<()> {
        let difference = a - b;
        msg!("Difference is {}", difference);
        Ok(())
    }
}

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

更新测试

编辑 tests/anchor-function-tutorial.ts:

复制代码
it("Should add", async () => {
    const tx = await program.methods.add(new anchor.BN(1), new anchor.BN(2)).rpc();
    console.log("Your transaction signature", tx);
});

it("Should subtract", async () => {
    const tx = await program.methods.sub(new anchor.BN(10), new anchor.BN(3)).rpc();
    console.log("Your transaction signature", tx);
});

运行测试:

复制代码
anchor test --skip-local-validator

生成的 IDL

复制代码
  "instructions": [
    {
      "name": "add",
      "accounts": [],
      "args": [
        {
          "name": "a",
          "type": "u64"
        },
        {
          "name": "b",
          "type": "u64"
        }
      ]
    },
    {
      "name": "sub",
      "accounts": [],
      "args": [
        {
          "name": "a",
          "type": "u64"
        },
        {
          "name": "b",
          "type": "u64"
        }
      ]
    }
  ],

账户结构体详解

Context 与结构体命名

函数中的 ctx: Context 指定账户上下文,T 是自定义结构体,名称(如 Initialize 或 Empty)任意,只要与函数签名一致。

#[derive(Accounts)] 的作用

这是 Anchor 的 Rust 属性宏,解析结构体字段并映射到 IDL 的 accounts。空结构体(如 Empty)生成空的 accounts 数组。

非空账户示例

更新 lib.rs

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

declare_id!("3ytdGXdSqfQ5Z9NB9c5bGbkNqkzVPkpijs4hj4BeoAa7");

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

    pub fn non_empty_account_example(ctx: Context<NonEmptyAccountExample>) -> Result<()> {
        msg!("Signers present");
        Ok(())
    }
}

#[derive(Accounts)]
pub struct NonEmptyAccountExample<'info> {
    signer: Signer<'info>,
    another_signer: Signer<'info>,
}

构建:

复制代码
anchor build

生成的 IDL 中的 instructions 部分为:

复制代码
  "instructions": [
    {
      "name": "nonEmptyAccountExample",
      "accounts": [
        {
          "name": "signer",
          "isMut": false,
          "isSigner": true
        },
        {
          "name": "anotherSigner",
          "isMut": false,
          "isSigner": true
        }
      ],
      "args": []
    }
  ]
  • 变化
    • 函数名:nonEmptyAccountExample(驼峰式)。
    • 账户名:signer 和 anotherSigner(another_signer 转为驼峰式)。
  • Signer:表示交易签名者,类似 Ethereum 的 tx.origin。

示例 3:综合应用

完整代码

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

declare_id!("3ytdGXdSqfQ5Z9NB9c5bGbkNqkzVPkpijs4hj4BeoAa7");

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

    pub fn function_a(ctx: Context<NonEmptyAccountExample>) -> Result<()> {
        msg!("Function A called");
        Ok(())
    }

    pub fn function_b(ctx: Context<Empty>, first_arg: u64) -> Result<()> {
        msg!("Function B with arg {}", first_arg);
        Ok(())
    }
}

#[derive(Accounts)]
pub struct NonEmptyAccountExample<'info> {
    signer: Signer<'info>,
    another_signer: Signer<'info>,
}

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

生成的 IDL

复制代码
{
  "version": "0.1.0",
  "name": "anchor_function_tutorial",
  "instructions": [
    {
      "name": "functionA",
      "accounts": [
        {
          "name": "signer",
          "isMut": false,
          "isSigner": true
        },
        {
          "name": "anotherSigner",
          "isMut": false,
          "isSigner": true
        }
      ],
      "args": []
    },
    {
      "name": "functionB",
      "accounts": [],
      "args": [
        {
          "name": "firstArg",
          "type": "u64"
        }
      ]
    }
  ]
}
  • 映射
    • functionA:无参数,账户来自 NonEmptyAccountExample。
    • functionB:参数 first_arg 转为 firstArg,账户为空。

教程到此结束,更多,请,,https://t.me/+_QibemQqIIg1OTY1

相关推荐
焗猪扒饭5 分钟前
加密货币安全基石: MTA协议在Ecdsa门限签名的应用(计算签名中的s)
web3·区块链·数字货币
北辰说生活3 小时前
B2-DPO:开启去中心化物联网(DePIN)的智能革命
物联网·去中心化·区块链
加密社3 小时前
【加密社】币圈合约交易量监控,含TG推送
区块链
加密新世界5 小时前
Four.meme是什么,一篇文章读懂
区块链
Blockchina1 天前
第八章 | 函数修饰符与访问控制模式
java·python·区块链·智能合约·solidity
Long_poem1 天前
【自学笔记】智能合约基础知识点总览-持续更新
笔记·区块链·智能合约
Blockchina1 天前
第十二章 | Solidity 智能合约前后端集成实战
java·python·区块链·智能合约·solidity
Blockchina2 天前
第十一章 | 智能合约主网部署与验证详解
区块链·智能合约·编程语言·solidity·区块链开发
Blockchina2 天前
第三章 | 初识 Solidity:开发环境搭建 & 第一个智能合约{介绍篇}
区块链·智能合约·solidity
Evanismal2 天前
区块链交易所平台开发全解析
大数据·区块链·visual studio·区块链开发