mcpField
S
smart-contracts

smart-contracts

github.com/stellar开发55193 次安装1 周前更新
代码仓库

关于 smart-contracts

面向 Rust 开发者的 Stellar 智能合约指南,涵盖构建、测试与安全审查。除入门流程外,还按任务链接开发、测试和安全专题文档。

主要功能

  1. 01Rust 合约设置与流程
  2. 02开发模式专题参考
  3. 03多层级测试指南
  4. 04安全审查清单
  5. 05构建与部署指引

适用场景

  1. 01启动 Stellar Rust 合约项目
  2. 02选择合约测试层级与方法
  3. 03主网上线前审查合约安全
  4. 04排查授权或存储错误

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/stellar/stellar-dev-skill --skill smart-contracts

安装后在 Claude Code 中输入/smart-contracts确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

development.md
security.md
testing.md

详细介绍

Stellar 智能合约

使用 Rust 构建 Stellar 智能合约的指南。Stellar 上的智能合约曾以“Soroban”作为品牌名——该平台名称已弃用,但 Rust SDK(soroban-sdk)和若干工具名称仍保留此前缀。

本文件介绍设置和核心工作流。深入内容见配套文件——请阅读与任务相符的文件:

任务文件
存储/TTL、授权、构造函数、跨合约调用、代币、事件、错误、升级、工厂、治理/DeFi 模式、费用/资源、故障排查development.md
单元、集成、模糊、属性、分叉和变异测试testing.md
安全审查、漏洞类别、检查清单、审计准备、工具security.md

何时使用此技能

  • 使用 Rust 编写 Stellar 智能合约
  • 设置合约测试(任何层级)
  • 审查合约是否存在安全问题
  • 设计可升级合约、工厂、自定义账户或 DeFi 基础组件
  • 调试合约特有错误(授权、存储、归档、资源限制)

相关技能

  • 资产发行、信任线和 SAC 部署 → ../assets/SKILL.md
  • 调用合约的前端/钱包 → ../dapp/SKILL.md
  • 链上数据查询(RPC/Horizon)→ ../data/SKILL.md
  • ZK 验证(BLS12-381、Groth16、Circom/Noir/RISC Zero)→ ../zk-proofs/SKILL.md
  • SEP/CAP 标准和生态链接 → ../standards/SKILL.md

版本

此技能基于 protocol 27(soroban-sdk v27、rs-soroban-env v27、stellar-cli v27)编写。示例中的版本号仅供参考——请从以下来源确认当前版本,不要盲信任何文档:

  • soroban-sdk 的主版本与协议版本一致(SDK 27 ↔ protocol 27)。此规则不受任何特定版本发布的影响。
  • 最新 SDK 版本:crates.io/crates/soroban-sdk(或使用 cargo add soroban-sdk 解析版本)。预发布版本(-rc.x)仅在协议升级期间存在,必须使用精确版本字符串固定;GitHub releases 中列出了这些版本及其变更日志。
  • 网络通过验证者投票升级,顺序为 testnet 在前、mainnet 在后——请固定与部署目标网络相匹配的 SDK 主版本。当前协议版本:通过 RPC getVersionInfo 或 Stellar Lab 查询。
  • 此处引用的数值网络限制为编写本文时的 mainnet 设置;它们会因投票而变更——Stellar Lab 的 Network Limits 页面 和 stellar network settings --network mainnet 可显示当前值。

平台限制

合约使用 Rust 编译为 WebAssembly,并在沙箱化主机中运行:

  • 必须使用 #![no_std]——使用 soroban_sdk 类型(String、Vec、Map、Symbol),而非 Rust 标准库
  • 编译时使用 wasm32v1-none 目标(Rust ≥ 1.84)——这是 Stellar 运行时支持的唯一 Wasm 目标
  • 编译后的合约大小限制为 128KB(由网络配置)
  • Symbol 限制为 32 个字符(a-zA-Z0-9_);symbol_short!() 最多支持 9 个字符
  • 存储需要租用:每个条目都有 TTL,且可能被归档——参见 development.md
  • 不支持 delegatecall,主机会阻止跨合约重入——参见 security.md
  • 不支持 I/O 和网络访问,除账本时间戳外也没有时钟——合约能执行的一切操作都依赖 Env

项目设置

stellar contract init my-contract   # scaffolds a Cargo workspace with contracts/
cd my-contract
rustup target add wasm32v1-none     # once per toolchain

Cargo.toml 基础配置(由 stellar contract init 生成):

[lib]
crate-type = ["lib", "cdylib"]   # lib is needed for tests and fuzzing

[dependencies]
soroban-sdk = "27"  # protocol 27, which mainnet runs at the time of writing.
                    # Pre-releases (`-rc.x`) exist only during a rollout and need the
                    # exact version string. Check crates.io for the latest release, and
                    # the live protocol version of your target network, before deploying.

[dev-dependencies]
soroban-sdk = { version = "27", features = ["testutils"] }  # match above

[profile.release]
opt-level = "z"
overflow-checks = true
debug = 0
strip = "symbols"
debug-assertions = false
panic = "abort"
codegen-units = 1
lto = true

合约结构

一个精简示例,展示状态、构造函数、授权、TTL、类型化错误和事件:

#![no_std]
use soroban_sdk::{
    contract, contracterror, contractevent, contractimpl, contracttype, Address, Env,
};

#[contracttype]
#[derive(Clone)]
pub enum DataKey {
    Admin,
    Counter,
}

#[contracterror]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(u32)]
pub enum Error {
    NotInitialized = 1,
}

// Emitted as topics ("incremented", by) with data {count} — #[topic] fields
// become topics, the rest go in the data payload.
#[contractevent]
pub struct Incremented {
    #[topic]
    pub by: Address,
    pub count: u32,
}

#[contract]
pub struct CounterContract;

#[contractimpl]
impl CounterContract {
    // Runs once, atomically, at deploy time. Must be named `__constructor`.
    // Does not run again on upgrade.
    pub fn __constructor(env: Env, admin: Address) {
        env.storage().instance().set(&DataKey::Admin, &admin);
        env.storage().instance().set(&DataKey::Counter, &0u32);
    }

    pub fn increment(env: Env) -> Result<u32, Error> {
        let admin: Address = env
            .storage()
            .instance()
            .get(&DataKey::Admin)
            .ok_or(Error::NotInitialized)?;
        admin.require_auth();

        let count: u32 = env.storage().instance().get(&DataKey::Counter).unwrap_or(0);
        let count = count + 1;
        env.storage().instance().set(&DataKey::Counter, &count);

        // Extend TTL so contract state is not archived (threshold, extend-to)
        env.storage().instance().extend_ttl(120 * 17280, 180 * 17280);

        Incremented { by: admin, count }.publish(&env);
        Ok(count)
    }

    pub fn get_count(env: Env) -> u32 {
        env.storage().instance().get(&DataKey::Counter).unwrap_or(0)
    }
}

完整模式(三种存储类型、授权变体、跨合约调用、代币、自定义类型):development.md。

构建、部署、调用

# Build optimized WASM → target/wasm32v1-none/release/*.wasm
# (optimization is on by default; --optimize=false to disable)
stellar contract build

# Create and fund an identity (testnet)
stellar keys generate alice --network testnet --fund

# Deploy (constructor args go after the `--`)
stellar contract deploy \
  --wasm target/wasm32v1-none/release/my_contract.wasm \
  --source-account alice \
  --network testnet \
  -- \
  --admin alice

# Invoke
stellar contract invoke \
  --id CONTRACT_ID \
  --source-account alice \
  --network testnet \
  -- \
  increment

如需上传 WASM 但不实例化(例如用于工厂或升级),请使用 stellar contract upload(旧命令 stellar contract install 是已弃用的别名)。

验证你的构建

链上没有任何信息能将已部署的 WASM 与其源代码关联起来。SEP-0055(草案)弥补了这一缺口:在 GitHub Actions 中构建,将源代码仓库信息写入 WASM 的 contractmetav0 区段,并为二进制文件发布 GitHub 构建证明——这样,任何人都能从链上的 WASM 哈希追溯到生成它的提交和工作流运行记录。验证者会未经身份验证地从 api.github.com/repos/<owner>/<repo>/attestations/sha256:<wasm-hash> 读取证明,因此源代码仓库必须公开,才能让“任何人”都能查看。Free、Pro 和 Team 计划中的私有或内部仓库根本无法发布证明。Enterprise Cloud 可以发布,但只有拥有仓库访问权限的账户才能读取,因此合约的任何用户都无法读取。在任何主网部署前,都应将其作为标准步骤;它只需一个工作流文件,因此没有理由只对面向用户的合约启用。

两个元数据条目用于记录这些信息(使用 stellar contract build --meta key=value 添加,通过 stellar contract info meta --wasm <file> 读取):

  • source_repo=github:<owner>/<repo> — 源代码所在位置
  • home_domain=<domain> — 提供 SEP-1 stellar.toml 的域名,用于组织/代币查询(可选;填写纯域名,不带协议或路径)

soroban-build-workflow 可完成整个流程——添加元数据并构建、优化、生成证明、发布附带 WASM 的发行版,并将构建注册到 stellar.expert 的合约验证系统。

请自行确定其版本,不要照抄任何文档(包括本文档)中的固定版本。固定版本会过时,而且该仓库中的最新标签不一定是已发布的版本:

REPO=stellar-expert/soroban-build-workflow
TAG=$(gh release view --repo "$REPO" --json tagName --jq .tagName)  # latest release
SHA=$(gh api "repos/$REPO/commits/$TAG" --jq .sha)                  # its commit
gh api "repos/$REPO/contents/.github/workflows/release.yml?ref=$SHA" \
  -H "Accept: application/vnd.github.raw"                           # the file you will pin

请读取该 SHA 对应的 release.yml,绝不要读取标签对应的文件。标签可能在这两个步骤之间移动,导致你审查的是一个提交,固定的却是另一个提交。该工作流应检出标签所指向的提交、从源代码构建,并为上传的同一文件生成证明。如果不符合这些要求,请停止并告知用户,而不是仍然固定该版本。然后固定完整 SHA,因为此工作流会使用你的仓库令牌、OIDC 和证明权限运行。

请告知用户这个固定版本的保护范围。它只固定了 release.yml,而非该文件调用的操作。这些操作使用各自可变的标签(actions/checkout@v4、CLI、证明操作),会在运行时以相同权限解析调用,而且调用方无法固定它们。如果无法接受这种剩余风险,请自行派生该工作流。

# .github/workflows/release.yml — verified build on every version tag
name: Build and Release
on:
  push:
    tags: ["v*"]

permissions:            # inherited by the called workflow, which cannot elevate them
  contents: write       # create the release, attach the WASM
  id-token: write       # sign the attestation
  attestations: write   # publish it

jobs:
  release:
    # the SHA you resolved and reviewed; keep the version in the comment
    uses: stellar-expert/soroban-build-workflow/.github/workflows/release.yml@<commit-sha>  # vX.Y.Z
    with:
      release_name: ${{ github.ref_name }}
      home_domain: example.com   # optional
      package: my-contract       # optional — omit to build the working directory
    secrets:
      release_token: ${{ secrets.GITHUB_TOKEN }}   # created by GitHub, nothing to configure

随后部署该发行版附带的 WASM,而不是在本地重新构建的版本——编译环境各不相同,只要哈希相差一个字节,就无法匹配任何证明。

构建结果会显示在 Stellar Lab 的合约浏览器和 stellar.expert 上。请准确告知用户它能证明什么:某次特定的工作流运行从某个提交构建了这个二进制文件。它无法说明代码是否安全,也无法证明代码曾经过审查。

最简测试

// src/test.rs — included from lib.rs with `mod test;`
#![cfg(test)]
use super::*;
use soroban_sdk::{testutils::Address as _, Address, Env};

#[test]
fn test_increment() {
    let env = Env::default();
    env.mock_all_auths();
    let admin = Address::generate(&env);
    let contract_id = env.register(CounterContract, (admin.clone(),));
    let client = CounterContractClient::new(&env, &contract_id);

    assert_eq!(client.increment(), 1);
    assert_eq!(client.get_count(), 1);
}

有关授权模拟、事件断言、模糊测试、分叉测试和 CI 设置,请参阅:testing.md。

主网部署前

请按照 security.md 中的清单逐项检查——授权、重新初始化、算术、存储 TTL 和跨合约验证都是常见的故障原因。通过已验证的构建进行部署,确保链上的 WASM 哈希能够追溯到可供审查的提交。

Documentation

评论

支持 Markdown