跳到主要内容

23 篇博文 含有标签「Sui」

查看所有标签

使用 @mysten/seal 构建去中心化加密:开发者教程

· 阅读需 14 分钟
Dora Noda
Software Engineer

隐私正在成为公共基础设施。在 2025 年,开发者需要让加密变得如存储数据一样简单的工具。Mysten Labs 的 Seal 正好提供了这样的解决方案——具有链上访问控制的去中心化密钥管理。本教程将教您如何使用基于身份的加密、门限安全和可编程访问策略构建安全的 Web3 应用程序。


简介:为什么 Seal 对 Web3 很重要

传统的云应用程序依赖于中心化的密钥管理系统,其中单一提供商控制对加密数据的访问。虽然方便,但这创造了危险的单点故障。如果提供商被攻击、离线或决定限制访问,您的数据将变得无法访问或易受攻击。

Seal 完全改变了这种模式。由 Mysten Labs 为 Sui 区块链构建,Seal 是一个去中心化密钥管理(DSM)服务,支持:

  • 基于身份的加密,内容在离开您的环境之前就受到保护
  • 门限加密,将密钥访问分布在多个独立节点上
  • 链上访问控制,具有时间锁、代币门控和自定义授权逻辑
  • 存储无关设计,可与 Walrus、IPFS 或任何存储解决方案配合使用

无论您是在构建安全消息应用程序、门控内容平台还是时间锁定资产转移,Seal 都提供了您需要的加密原语和访问控制基础设施。


开始使用

前提条件

在深入学习之前,确保您具有:

  • 安装了 Node.js 18+
  • 对 TypeScript/JavaScript 的基本了解
  • 用于测试的 Sui 钱包(如 Sui Wallet)
  • 对区块链概念的理解

安装

通过 npm 安装 Seal SDK:

npm install @mysten/seal

您还需要 Sui SDK 进行区块链交互:

npm install @mysten/sui

项目设置

创建一个新项目并初始化它:

mkdir seal-tutorial
cd seal-tutorial
npm init -y
npm install @mysten/seal @mysten/sui typescript @types/node

创建一个简单的 TypeScript 配置:

// tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
}
}

核心概念:Seal 的工作原理

在编写代码之前,让我们了解 Seal 的架构:

1. 基于身份的加密 (IBE)

与传统的加密方式不同(您加密到公钥),IBE 让您加密到一个身份(如电子邮件地址或 Sui 地址)。接收者只有在能够证明他们控制该身份时才能解密。

2. 门限加密

Seal 使用 t-of-n 门限方案,而不是信任单个密钥服务器。您可以配置 3-of-5 密钥服务器,这意味着任何 3 个服务器可以合作提供解密密钥,但 2 个或更少的服务器不能。

3. 链上访问控制

访问策略由 Sui 智能合约强制执行。在密钥服务器提供解密密钥之前,它会验证请求者是否满足链上策略要求(代币所有权、时间约束等)。

4. 密钥服务器网络

分布式密钥服务器验证访问策略并生成解密密钥。这些服务器由不同的方运营,以确保没有单一控制点。


基本实现:您的第一个 Seal 应用程序

让我们构建一个简单的应用程序,它加密敏感数据并通过 Sui 区块链策略控制访问。

步骤 1:初始化 Seal 客户端

// src/seal-client.ts
import { SealClient } from '@mysten/seal';
import { SuiClient } from '@mysten/sui/client';

export async function createSealClient() {
// 为测试网初始化 Sui 客户端
const suiClient = new SuiClient({
url: 'https://fullnode.testnet.sui.io'
});

// 使用测试网密钥服务器配置 Seal 客户端
const sealClient = new SealClient({
suiClient,
keyServers: [
'https://keyserver1.seal-testnet.com',
'https://keyserver2.seal-testnet.com',
'https://keyserver3.seal-testnet.com'
],
threshold: 2, // 2-of-3 门限
network: 'testnet'
});

return { sealClient, suiClient };
}

步骤 2:简单加密/解密

// src/basic-encryption.ts
import { createSealClient } from './seal-client';

async function basicExample() {
const { sealClient } = await createSealClient();

// 要加密的数据
const sensitiveData = "这是我的秘密消息!";
const recipientAddress = "0x742d35cc6d4c0c08c0f9bf3c9b2b6c64b3b4f5c6d7e8f9a0b1c2d3e4f5a6b7c8";

try {
// 为特定的 Sui 地址加密数据
const encryptedData = await sealClient.encrypt({
data: Buffer.from(sensitiveData, 'utf-8'),
recipientId: recipientAddress,
// 可选:添加元数据
metadata: {
contentType: 'text/plain',
timestamp: Date.now()
}
});

console.log('加密数据:', {
ciphertext: encryptedData.ciphertext.toString('base64'),
encryptionId: encryptedData.encryptionId
});

// 稍后,解密数据(需要适当的授权)
const decryptedData = await sealClient.decrypt({
ciphertext: encryptedData.ciphertext,
encryptionId: encryptedData.encryptionId,
recipientId: recipientAddress
});

console.log('解密数据:', decryptedData.toString('utf-8'));

} catch (error) {
console.error('加密/解密失败:', error);
}
}

basicExample();

使用 Sui 智能合约的访问控制

Seal 的真正威力来自可编程访问控制。让我们创建一个时间锁定加密示例,其中数据只能在特定时间后解密。

步骤 1:部署访问控制合约

首先,我们需要一个定义访问策略的 Move 智能合约:

// contracts/time_lock.move
module time_lock::policy {
use sui::clock::{Self, Clock};
use sui::object::{Self, UID};
use sui::tx_context::{Self, TxContext};

public struct TimeLockPolicy has key, store {
id: UID,
unlock_time: u64,
authorized_user: address,
}

public fun create_time_lock(
unlock_time: u64,
authorized_user: address,
ctx: &mut TxContext
): TimeLockPolicy {
TimeLockPolicy {
id: object::new(ctx),
unlock_time,
authorized_user,
}
}

public fun can_decrypt(
policy: &TimeLockPolicy,
user: address,
clock: &Clock
): bool {
let current_time = clock::timestamp_ms(clock);
policy.authorized_user == user && current_time >= policy.unlock_time
}
}

步骤 2:与 Seal 集成

// src/time-locked-encryption.ts
import { createSealClient } from './seal-client';
import { TransactionBlock } from '@mysten/sui/transactions';

async function createTimeLocked() {
const { sealClient, suiClient } = await createSealClient();

// 在 Sui 上创建访问策略
const txb = new TransactionBlock();

const unlockTime = Date.now() + 60000; // 1分钟后解锁
const authorizedUser = "0x742d35cc6d4c0c08c0f9bf3c9b2b6c64b3b4f5c6d7e8f9a0b1c2d3e4f5a6b7c8";

txb.moveCall({
target: 'time_lock::policy::create_time_lock',
arguments: [
txb.pure(unlockTime),
txb.pure(authorizedUser)
]
});

// 执行交易创建策略
const result = await suiClient.signAndExecuteTransactionBlock({
transactionBlock: txb,
signer: yourKeypair, // 您的 Sui 密钥对
});

const policyId = result.objectChanges?.find(
change => change.type === 'created'
)?.objectId;

// 现在使用此策略加密
const sensitiveData = "这将在1分钟后解锁!";

const encryptedData = await sealClient.encrypt({
data: Buffer.from(sensitiveData, 'utf-8'),
recipientId: authorizedUser,
accessPolicy: {
policyId,
policyType: 'time_lock'
}
});

console.log('时间锁定数据已创建。请在1分钟后尝试解密。');

return {
encryptedData,
policyId,
unlockTime
};
}

实际示例

示例 1:安全消息应用程序

// src/secure-messaging.ts
import { createSealClient } from './seal-client';

class SecureMessenger {
private sealClient: any;

constructor(sealClient: any) {
this.sealClient = sealClient;
}

async sendMessage(
message: string,
recipientAddress: string,
senderKeypair: any
) {
const messageData = {
content: message,
timestamp: Date.now(),
sender: senderKeypair.toSuiAddress(),
messageId: crypto.randomUUID()
};

const encryptedMessage = await this.sealClient.encrypt({
data: Buffer.from(JSON.stringify(messageData), 'utf-8'),
recipientId: recipientAddress,
metadata: {
type: 'secure_message',
sender: senderKeypair.toSuiAddress()
}
});

// 将加密消息存储在去中心化存储(Walrus)上
return this.storeOnWalrus(encryptedMessage);
}

async readMessage(encryptionId: string, recipientKeypair: any) {
// 从存储中检索
const encryptedData = await this.retrieveFromWalrus(encryptionId);

// 使用 Seal 解密
const decryptedData = await this.sealClient.decrypt({
ciphertext: encryptedData.ciphertext,
encryptionId: encryptedData.encryptionId,
recipientId: recipientKeypair.toSuiAddress()
});

return JSON.parse(decryptedData.toString('utf-8'));
}

private async storeOnWalrus(data: any) {
// 与 Walrus 存储的集成
// 这将把加密数据上传到 Walrus
// 并返回用于检索的 blob ID
}

private async retrieveFromWalrus(blobId: string) {
// 使用 blob ID 从 Walrus 检索加密数据
}
}

示例 2:代币门控内容平台

// src/gated-content.ts
import { createSealClient } from './seal-client';

class ContentGating {
private sealClient: any;
private suiClient: any;

constructor(sealClient: any, suiClient: any) {
this.sealClient = sealClient;
this.suiClient = suiClient;
}

async createGatedContent(
content: string,
requiredNftCollection: string,
creatorKeypair: any
) {
// 创建 NFT 所有权策略
const accessPolicy = await this.createNftPolicy(
requiredNftCollection,
creatorKeypair
);

// 使用 NFT 访问要求加密内容
const encryptedContent = await this.sealClient.encrypt({
data: Buffer.from(content, 'utf-8'),
recipientId: 'nft_holders', // NFT 持有者的特殊接收者
accessPolicy: {
policyId: accessPolicy.policyId,
policyType: 'nft_ownership'
}
});

return {
contentId: encryptedContent.encryptionId,
accessPolicy: accessPolicy.policyId
};
}

async accessGatedContent(
contentId: string,
userAddress: string,
userKeypair: any
) {
// 首先验证 NFT 所有权
const hasAccess = await this.verifyNftOwnership(
userAddress,
contentId
);

if (!hasAccess) {
throw new Error('访问被拒绝:未找到所需的 NFT');
}

// 解密内容
const decryptedContent = await this.sealClient.decrypt({
encryptionId: contentId,
recipientId: userAddress
});

return decryptedContent.toString('utf-8');
}

private async createNftPolicy(collection: string, creator: any) {
// 创建检查 NFT 所有权的 Move 合约
// 返回策略对象 ID
}

private async verifyNftOwnership(user: string, contentId: string) {
// 检查用户是否拥有所需的 NFT
// 查询 Sui 的 NFT 所有权
}
}

示例 3:时间锁定资产转移

// src/time-locked-transfer.ts
import { createSealClient } from './seal-client';

async function createTimeLockTransfer(
assetData: any,
recipientAddress: string,
unlockTimestamp: number,
senderKeypair: any
) {
const { sealClient, suiClient } = await createSealClient();

// 在 Sui 上创建时间锁定策略
const timeLockPolicy = await createTimeLockPolicy(
unlockTimestamp,
recipientAddress,
senderKeypair,
suiClient
);

// 加密资产转移数据
const transferData = {
asset: assetData,
recipient: recipientAddress,
unlockTime: unlockTimestamp,
transferId: crypto.randomUUID()
};

const encryptedTransfer = await sealClient.encrypt({
data: Buffer.from(JSON.stringify(transferData), 'utf-8'),
recipientId: recipientAddress,
accessPolicy: {
policyId: timeLockPolicy.policyId,
policyType: 'time_lock'
}
});

console.log(`资产锁定至 ${new Date(unlockTimestamp)}`);

return {
transferId: encryptedTransfer.encryptionId,
unlockTime: unlockTimestamp,
policyId: timeLockPolicy.policyId
};
}

async function claimTimeLockTransfer(
transferId: string,
recipientKeypair: any
) {
const { sealClient } = await createSealClient();

try {
const decryptedData = await sealClient.decrypt({
encryptionId: transferId,
recipientId: recipientKeypair.toSuiAddress()
});

const transferData = JSON.parse(decryptedData.toString('utf-8'));

// 处理资产转移
console.log('资产转移已解锁:', transferData);

return transferData;
} catch (error) {
console.error('转移尚未解锁或访问被拒绝:', error);
throw error;
}
}

与 Walrus 去中心化存储的集成

Seal 与 Sui 的去中心化存储解决方案 Walrus 无缝协作。以下是如何集成两者:

// src/walrus-integration.ts
import { createSealClient } from './seal-client';

class SealWalrusIntegration {
private sealClient: any;
private walrusClient: any;

constructor(sealClient: any, walrusClient: any) {
this.sealClient = sealClient;
this.walrusClient = walrusClient;
}

async storeEncryptedData(
data: Buffer,
recipientAddress: string,
accessPolicy?: any
) {
// 使用 Seal 加密
const encryptedData = await this.sealClient.encrypt({
data,
recipientId: recipientAddress,
accessPolicy
});

// 在 Walrus 上存储加密数据
const blobId = await this.walrusClient.store(
encryptedData.ciphertext
);

// 返回包含 Seal 和 Walrus 信息的引用
return {
blobId,
encryptionId: encryptedData.encryptionId,
accessPolicy: encryptedData.accessPolicy
};
}

async retrieveAndDecrypt(
blobId: string,
encryptionId: string,
userKeypair: any
) {
// 从 Walrus 检索
const encryptedData = await this.walrusClient.retrieve(blobId);

// 使用 Seal 解密
const decryptedData = await this.sealClient.decrypt({
ciphertext: encryptedData,
encryptionId,
recipientId: userKeypair.toSuiAddress()
});

return decryptedData;
}
}

// 使用示例
async function walrusExample() {
const { sealClient } = await createSealClient();
const walrusClient = new WalrusClient('https://walrus-testnet.sui.io');

const integration = new SealWalrusIntegration(sealClient, walrusClient);

const fileData = Buffer.from('重要文档内容');
const recipientAddress = '0x...';

// 存储加密数据
const result = await integration.storeEncryptedData(
fileData,
recipientAddress
);

console.log('已存储,Blob ID:', result.blobId);

// 稍后,检索并解密
const decrypted = await integration.retrieveAndDecrypt(
result.blobId,
result.encryptionId,
recipientKeypair
);

console.log('检索到的数据:', decrypted.toString());
}

门限加密高级配置

对于生产应用程序,您需要配置具有多个密钥服务器的自定义门限加密:

// src/advanced-threshold.ts
import { SealClient } from '@mysten/seal';

async function setupProductionSeal() {
// 配置多个独立的密钥服务器
const keyServers = [
'https://keyserver-1.your-org.com',
'https://keyserver-2.partner-org.com',
'https://keyserver-3.third-party.com',
'https://keyserver-4.backup-provider.com',
'https://keyserver-5.fallback.com'
];

const sealClient = new SealClient({
keyServers,
threshold: 3, // 3-of-5 门限
network: 'mainnet',
// 高级选项
retryAttempts: 3,
timeoutMs: 10000,
backupKeyServers: [
'https://backup-1.emergency.com',
'https://backup-2.emergency.com'
]
});

return sealClient;
}

async function robustEncryption() {
const sealClient = await setupProductionSeal();

const criticalData = "关键任务加密数据";

// 以高安全保证进行加密
const encrypted = await sealClient.encrypt({
data: Buffer.from(criticalData, 'utf-8'),
recipientId: '0x...',
// 要求所有5个服务器以获得最大安全性
customThreshold: 5,
// 添加冗余
redundancy: 2,
accessPolicy: {
// 多因子要求
requirements: ['nft_ownership', 'time_lock', 'multisig_approval']
}
});

return encrypted;
}

安全最佳实践

1. 密钥管理

// src/security-practices.ts

// 正确:使用安全的密钥派生
import { generateKeypair } from '@mysten/sui/cryptography/ed25519';

const keypair = generateKeypair();

// 正确:安全地存储密钥(使用环境变量的示例)
const keypair = Ed25519Keypair.fromSecretKey(
process.env.PRIVATE_KEY
);

// 错误:永远不要硬编码密钥
const badKeypair = Ed25519Keypair.fromSecretKey(
"hardcoded-secret-key-12345" // 不要这样做!
);

2. 访问策略验证

// 在加密前始终验证访问策略
async function secureEncrypt(data: Buffer, recipient: string) {
const { sealClient } = await createSealClient();

// 验证接收者地址
if (!isValidSuiAddress(recipient)) {
throw new Error('无效的接收者地址');
}

// 检查策略是否存在且有效
const policy = await validateAccessPolicy(policyId);
if (!policy.isValid) {
throw new Error('无效的访问策略');
}

return sealClient.encrypt({
data,
recipientId: recipient,
accessPolicy: policy
});
}

3. 错误处理和回退机制

// 健壮的错误处理
async function resilientDecrypt(encryptionId: string, userKeypair: any) {
const { sealClient } = await createSealClient();

try {
return await sealClient.decrypt({
encryptionId,
recipientId: userKeypair.toSuiAddress()
});
} catch (error) {
if (error.code === 'ACCESS_DENIED') {
throw new Error('访问被拒绝:请检查您的权限');
} else if (error.code === 'KEY_SERVER_UNAVAILABLE') {
// 尝试使用备份配置
return await retryWithBackupServers(encryptionId, userKeypair);
} else if (error.code === 'THRESHOLD_NOT_MET') {
throw new Error('可用的密钥服务器不足');
} else {
throw new Error(`解密失败:${error.message}`);
}
}
}

4. 数据验证

// 在加密前验证数据
function validateDataForEncryption(data: Buffer): boolean {
// 检查大小限制
if (data.length > 1024 * 1024) { // 1MB 限制
throw new Error('数据太大,无法加密');
}

// 检查敏感模式(可选)
const dataStr = data.toString();
if (containsSensitivePatterns(dataStr)) {
console.warn('警告:数据包含潜在的敏感模式');
}

return true;
}

性能优化

1. 批处理操作

// 批量多个加密以提高效率
async function batchEncrypt(dataItems: Buffer[], recipients: string[]) {
const { sealClient } = await createSealClient();

const promises = dataItems.map((data, index) =>
sealClient.encrypt({
data,
recipientId: recipients[index]
})
);

return Promise.all(promises);
}

2. 缓存密钥服务器响应

// 缓存密钥服务器会话以减少延迟
class OptimizedSealClient {
private sessionCache = new Map();

async encryptWithCaching(data: Buffer, recipient: string) {
let session = this.sessionCache.get(recipient);

if (!session || this.isSessionExpired(session)) {
session = await this.createNewSession(recipient);
this.sessionCache.set(recipient, session);
}

return this.encryptWithSession(data, session);
}
}

测试您的 Seal 集成

单元测试

// tests/seal-integration.test.ts
import { describe, it, expect } from 'jest';
import { createSealClient } from '../src/seal-client';

describe('Seal 集成', () => {
it('应该成功加密和解密数据', async () => {
const { sealClient } = await createSealClient();
const testData = Buffer.from('测试消息');
const recipient = '0x742d35cc6d4c0c08c0f9bf3c9b2b6c64b3b4f5c6d7e8f9a0b1c2d3e4f5a6b7c8';

const encrypted = await sealClient.encrypt({
data: testData,
recipientId: recipient
});

expect(encrypted.encryptionId).toBeDefined();
expect(encrypted.ciphertext).toBeDefined();

const decrypted = await sealClient.decrypt({
ciphertext: encrypted.ciphertext,
encryptionId: encrypted.encryptionId,
recipientId: recipient
});

expect(decrypted.toString()).toBe('测试消息');
});

it('应该强制执行访问控制策略', async () => {
// 测试未授权用户无法解密
const { sealClient } = await createSealClient();

const encrypted = await sealClient.encrypt({
data: Buffer.from('秘密'),
recipientId: 'authorized-user'
});

await expect(
sealClient.decrypt({
ciphertext: encrypted.ciphertext,
encryptionId: encrypted.encryptionId,
recipientId: 'unauthorized-user'
})
).rejects.toThrow('访问被拒绝');
});
});

部署到生产环境

环境配置

// config/production.ts
export const productionConfig = {
keyServers: [
process.env.KEY_SERVER_1,
process.env.KEY_SERVER_2,
process.env.KEY_SERVER_3,
process.env.KEY_SERVER_4,
process.env.KEY_SERVER_5
],
threshold: 3,
network: 'mainnet',
suiRpc: process.env.SUI_RPC_URL,
walrusGateway: process.env.WALRUS_GATEWAY,
// 安全设置
maxDataSize: 1024 * 1024, // 1MB
sessionTimeout: 3600000, // 1小时
retryAttempts: 3
};

监控和日志记录

// utils/monitoring.ts
export class SealMonitoring {
static logEncryption(encryptionId: string, recipient: string) {
console.log(`[SEAL] 为 ${recipient} 加密数据 ${encryptionId}`);
// 发送到您的监控服务
}

static logDecryption(encryptionId: string, success: boolean) {
console.log(`[SEAL] 解密 ${encryptionId}${success ? '成功' : '失败'}`);
}

static logKeyServerHealth(serverUrl: string, status: string) {
console.log(`[SEAL] 密钥服务器 ${serverUrl}${status}`);
}
}

资源和后续步骤

官方文档

社区和支持

  • Sui Discord: 加入 #seal 频道获得社区支持
  • GitHub Issues: 报告错误和请求功能
  • 开发者论坛: Sui 社区论坛进行讨论

要探索的高级主题

  1. 自定义访问策略:使用 Move 合约构建复杂的授权逻辑
  2. 跨链集成:将 Seal 与其他区块链网络一起使用
  3. 企业密钥管理:设置您自己的密钥服务器基础设施
  4. 审计和合规:为受监管环境实施日志记录和监控

示例应用程序

  • 安全聊天应用:使用 Seal 的端到端加密消息传递
  • 文档管理:具有访问控制的企业文档共享
  • 数字版权管理:具有使用策略的内容分发
  • 隐私保护分析:加密数据处理工作流

结论

Seal 代表了朝着使隐私和加密成为 Web3 中基础设施级关注点的根本转变。通过结合基于身份的加密、门限安全和可编程访问控制,它为开发者提供了构建真正安全和去中心化应用程序的强大工具。

使用 Seal 构建的主要优势包括:

  • 无单点故障:分布式密钥服务器消除了中央权威
  • 可编程安全:基于智能合约的访问策略提供灵活的授权
  • 开发者友好:TypeScript SDK 与现有的 Web3 工具无缝集成
  • 存储无关:与 Walrus、IPFS 或任何存储解决方案配合使用
  • 生产就绪:由 Mysten Labs 构建,具有企业安全标准

无论您是在保护用户数据、实施订阅模型还是构建复杂的多方应用程序,Seal 都提供了您需要的加密原语和访问控制基础设施,让您可以放心地构建。

今天就开始构建,加入越来越多的开发者生态系统,让隐私成为公共基础设施的基本组成部分。


准备开始构建了吗? 安装 @mysten/seal 并开始尝试本教程中的示例。去中心化网络正在等待将隐私和安全放在首位的应用程序。

Talus Nexus:评估面向链上 AI 经济的智能体工作流层

· 阅读需 8 分钟
Dora Noda
Software Engineer

TL;DR

  • Talus 正在推出 Nexus:一个基于 Move 的框架,将链上与链下工具组合成可验证的 DAG(有向无环图)工作流,目前由可信的 "Leader" 服务协调,并计划逐步引入安全执行环境和去中心化。
  • 该栈面向新兴的 智能体经济,整合工具注册、支付通道、Gas 预算与市场,使工具构建者和智能体运营者能够在可审计的条件下实现变现。
  • 官方公布了迈向专用链 Protochain(Cosmos SDK + Move VM)的路线,但目前仍以 Sui 为主协调层;Sui + Walrus 存储集成为当前生产环境。
  • 代币方案仍在演变:公开资料提到早期的 TAI概念,以及2025年轻白皮书中新引入的生态代币TAI 概念,以及 2025 年轻白皮书中新引入的生态代币 US,用于支付、质押与优先级机制。
  • 核心风险集中在 Leader 去中心化、代币经济定稿以及 Protochain 性能验证,同时还需保证跨 Sui、Walrus 与链下服务的开发体验。

Talus 在做什么,又不做什么

Talus 将自己定位为自治 AI 智能体的协调与结算层,而非 AI 推理市场。其核心产品 Nexus 允许开发者把工具调用、外部 API 与链上逻辑封装为 Sui Move 编写的 DAG 工作流。设计重点是可验证性、基于能力的权限控制与模式化数据流,让每次工具调用都能在链上被审计。Talus 还配套推出 Tool Marketplace、Agent Marketplace 和 Agent-as-a-Service,帮助发现并变现智能体能力。

另一方面,Talus 并不运营自有大模型或 GPU 网络。它希望工具构建者将现有服务(如 OpenAI、向量检索、交易系统、数据供应等)封装后注册进 Nexus。因此 Talus 与 Ritual、Bittensor 等算力网络互补,可将其接入为 Nexus 工作流中的工具。

架构:链上控制平面,链下执行

链上(Sui Move)

链上组件部署在 Sui 上,提供协调平面:

  • 工作流引擎 – DAG 语义支持入口组、分支变体与并发检查,并通过静态验证在执行前尽量规避竞争条件。
  • 基础原语ProofOfUID 支持低耦合的跨包认证消息;OwnerCap/CloneableOwnerCap 提供基于能力的权限;ProvenValueNexusData 定义了数据的内嵌与远程引用传递方式。
  • Default TAP(Talus Agent Package) – 参考智能体,展示如何创建工作表(证明对象)、触发工作流执行并确认工具结果,符合 Nexus Interface v1。
  • 工具注册与反垃圾 – 工具创建者需抵押时间锁定的资产才能发布定义,以阻止垃圾工具同时保持开放注册。
  • Gas 服务 – 共享对象记录工具定价、用户 Gas 预算及带有到期或次数限制的 Gas 票据。事件会追踪每次领取,便于审计工具方与 Leader 的结算。

链下 Leader

Talus 运营的 Leader 服务监听 Sui 事件,获取工具模式,调度链下执行(LLM、API、计算任务),按声明的模式校验输入输出,并将结果回写链上。Leader 能力以 Sui 对象表示;若交易失败,相关能力会被“损坏”,直到下个 epoch 才能再次使用。Talus 计划通过 TEE、多运营方以及最终的开放参与来强化这一链路。

存储与可验证性

Mysten Labs 的去中心化存储层 Walrus 用于智能体记忆、模型文件与大数据集。Nexus 将 Sui 作为确定性的控制平面,并将大体量数据卸载至 Walrus。公开资料指出未来可根据场景选择乐观验证、零知识验证或可信执行等多种模式。

开发者体验与早期产品

Talus 提供基于 Rust 的 SDK、CLI 工具与详细文档(构建 DAG、接入 LLM、保护工具等)。标准工具目录包括 OpenAI 对话、X(Twitter)操作、Walrus 适配器和数学工具,降低原型设计门槛。C 端方面,IDOL.fun(智能体对战预测市场)和 AI Bae(游戏化 AI 伴侣)用于展示价值并拉动流量。无代码构建器 Talus Vision 定位为面向非开发者的可视化工作流和市场入口。

经济设计、代币与 Gas 管理

在当前 Sui 部署中,用户用 SUI 充值工作流。Gas 服务会把预算换成针对具体工具的票据,设置到期或范围限制,并记录可在链上对账的领取事件。工具方自定价格,Leader 也通过同一套结算流程获得报酬。由于 Leader 目前可在执行完成后领取预算,用户需要信任运营方,但事件日志提供了可审计轨迹。

代币设计仍未定型。三方解读仍提及早期的 TAI,而Talus2025年轻白皮书则提出总量100亿的生态代币TAI**,而 Talus 2025 年轻白皮书则提出总量 100 亿的生态代币 **US,用于工具与 Leader 支付、服务质押及优先权。资料还提到执行时多付的 SUI 可能通过市场兑换成 $US。最终代币经济尚未发布前,这些信息都应视为暂定。

融资、团队与合作

Talus 于 2024 年底宣布完成 600 万美元 战略轮(累计 900 万美元),由 Polychain 领投,对应估值 1.5 亿美元。资金将用于推进 Nexus、孵化 C 端应用并建设面向智能体的专用 L1——Protochain。公开资料显示 Mike Hanono(CEO)Ben Frigon(COO) 为核心高管。与 SuiWalrus 的集成公告也凸显 Mysten Labs 基础设施是当前执行环境。

竞争格局

  • Ritual 侧重去中心化 AI 计算(Infernet)与 EVM 集成,强调可验证推理而非工作流编排。
  • Autonolas(Olas) 通过链上激励协调链下智能体服务,愿景类似,但缺乏 Nexus 提供的 Move DAG 执行层。
  • Fetch.ai 提供 Agentverse 与 uAgents 连接自治服务;Talus 的差异在于对每一步骤进行链上验证并内嵌 Gas 结算。
  • Bittensor 通过 TAO 子网奖励 ML 模型贡献,是算力市场,可作为工具接入 Nexus,但不提供 Talus 所强调的商业化轨道。

整体来看,Talus 意在承担智能体工作流的 协调与结算平面,而原始算力与推理由可插拔的专业网络提供。

主要风险与未决问题

  1. Leader 信任度 – 在引入 TEE 与多运营方之前,开发者需要信任 Talus Leader 能正确执行并返回结果。
  2. 代币不确定性 – 品牌与机制从 TAI转向TAI 转向 US,供应计划、分发与质押经济仍待明确。
  3. Protochain 落地能力 – 官方称将采用 Cosmos SDK + Move VM,但目前尚无公开代码库、基准测试或安全审计。
  4. 工具质量与垃圾风险 – 抵押要求能抑制垃圾工具,但长期成功取决于模式校验、可用性保障以及链下结果的争议处理。
  5. 用户体验复杂度 – 同时协调 Sui、Walrus 及多样链下 API 增加运营负担,需靠 SDK 与无代码工具充分抽象以保持开发者采用率。

2025–2026 年值得关注的里程碑

  • 发布 Leader 路线图:TEE 加固、惩罚机制、对外开放更多运营方。
  • 扩充 Tool Marketplace:注册工具数量、定价方式、质量指标(可用率、SLA 透明度)。
  • 观察 IDOL.fun、AI Bae、Talus Vision 的用户指标,以衡量智能体原生体验的市场需求。
  • 跟踪在 Sui + Walrus 上运行大规模工作流的性能数据:延迟、吞吐量、Gas 消耗。
  • 公布最终代币经济:发行节奏、质押收益、SUI→$US 转换路径。
  • 释出 Protochain 代码库、测试网与互操作计划(如 IBC 支持),验证专用链假设。

构建者与运营方的参与方式

  • 快速原型 – 使用 Default TAP 搭配标准工具(OpenAI、X、Walrus),构建三节点 DAG,实现数据采集、摘要与链上动作自动化。
  • 变现专业工具 – 将自有 API(金融数据、合规校验、定制 LLM 等)封装为 Nexus 工具,设定价格,并发行带到期或次数限制的 Gas 票据以管理需求。
  • 为成为 Leader 做准备 – 关注质押要求、惩罚逻辑与故障处理文档,以便网络开放时作为新增 Leader 参与。
  • 评估 C 端飞轮 – 分析 IDOL.fun 与 AI Bae 的留存与付费,看面向智能体的消费产品能否带动工具需求。

结论

Talus 通过 Move 可验证工作流、基于能力的工具组合及明确的变现轨道,为链上智能体经济提供了可信蓝图。接下来成败取决于能否摆脱对可信 Leader 的依赖、落地可持续的代币激励,并证明 Protochain 可以将 Sui 阶段的经验延展到专用执行环境。需要透明结算与可组合智能体工作流的构建者,应持续关注 Talus 化解这些悬念的速度,并将 Nexus 纳入尽调名单。

Sui 上的 Seal:面向链上访问控制的可编程机密层

· 阅读需 5 分钟
Dora Noda
Software Engineer

公有链为所有参与者提供同步且可审计的账本,但默认暴露所有数据。2025 年 9 月 3 日正式登陆 Sui 主网的 Seal,通过将链上策略逻辑与去中心化密钥管理结合,让 Web3 构建者能够精确控制谁能解密哪些载荷。

摘要

  • 产品定位: Seal 是一个秘密管理网络,使 Sui 智能合约可以在链上强制执行解密策略,同时客户端使用基于身份的加密(IBE)保护数据,并依赖阈值密钥服务器派生密钥。
  • 价值所在: 无需自建后端或依赖不透明的链下脚本,隐私与访问控制直接成为 Move 的一等公民。开发者可以将密文存储在任意位置(Walrus 是理想搭档),并持续控制读取权限。
  • 适用人群: 推出代币门控内容、定时解锁、私密消息或遵循策略的 AI 代理的团队,可以接入 Seal SDK,将精力集中在产品逻辑而非复杂的密码基础设施上。

策略逻辑写在 Move 里

Seal 包含 seal_approve* Move 函数,用于定义某个身份字符串在何种条件下、由谁请求密钥。策略可以组合 NFT 持有、白名单、时间锁或自定义角色体系。用户或代理发起解密请求时,密钥服务器会通过 Sui 全节点状态评估策略,仅在链上判断通过时才会批准。

由于访问规则属于你的链上包的一部分,因此它们是透明、可审计的,并可以与其他智能合约代码一起进行版本管理。治理更新也能像其他 Move 升级一样发布,具备社区审查和链上历史。

阈值密码学负责密钥管理

Seal 按照应用自定义的身份来加密数据。由开发者挑选的独立密钥服务器委员会共享 IBE 主密钥。当策略校验通过后,各服务器会为请求的身份导出密钥份额。当 t 台服务器响应后,客户端就能组合出可用的解密密钥。

你可以通过选择委员会成员(Ruby Nodes、NodeInfra、Overclock、Studio Mirai、H2O Nodes、Triton One 或 Mysten 的 Enoki 服务)以及设置阈值,在活性与机密性之间做权衡。想要更强的可用性?选择更大的委员会和更低的阈值。需要更高的隐私保障?提高法定人数,更多使用许可制服务商。

开发者体验:SDK 与会话密钥

Seal 提供 TypeScript SDK(npm i @mysten/seal),负责加解密流程、身份格式化与批量请求处理,还可以签发会话密钥,避免应用频繁访问时钱包不断弹窗。对于高级场景,Move 合约可以通过特殊模式请求链上解密,使得托管释放或抗 MEV 拍卖等逻辑能够直接在合约中执行。

Seal 与存储层无关,因此团队可以将其与 Walrus 组合实现可验证的 Blob 存储,或根据运营需求使用 IPFS 甚至中心化存储。无论密文存在哪里,加密边界及其策略执行都会伴随数据移动。

使用 Seal 的最佳实践

  • 建模可用性风险: 2-of-3 或 3-of-5 等阈值直接映射为可用性保障。生产部署应混合不同服务商、监测遥测数据,并在托管关键流程前签订 SLA。
  • 注意状态差异: 策略评估依赖全节点执行 dry_run 调用。避免依赖快速变化计数器或同一检查点内排序的规则,以免服务器之间出现临时不一致的审批结果。
  • 规划密钥卫生: 派生密钥保存在客户端。请做好日志、轮换会话密钥,并考虑包裹加密——用 Seal 保护加密大载荷的对称密钥——以减小设备泄露时的影响范围。
  • 为轮换做设计: 某次加密所使用的委员会在加密时就已固定。需要替换服务商或调整信任假设时,请预留通过重新加密迁移到新委员会的升级路径。

未来展望

Seal 的路线图包括验证者运营的 MPC 服务器、类似 DRM 的客户端工具以及抗量子 KEM 选项。对于正在探索 AI 代理、高价值内容或受监管数据流的团队而言,本次发布已经给出了清晰蓝图:在 Move 中编写策略,组合多元化的密钥委员会,并在 Sui 的信任边界内交付尊重用户隐私的加密体验。

如果你打算在下一次发布中采用 Seal,可先用 2-of-3 的开放式委员会和简单的 NFT 门控策略做原型,然后迭代出与应用风险画像匹配的服务商组合与运营控制。

在 BlockEden.xyz 上引入 SUI 代币质押:一键简易赚取 2.08% 年化收益

· 阅读需 7 分钟
Dora Noda
Software Engineer

我们很高兴宣布 SUI 代币质押 已在 BlockEden.xyz 上正式上线!即日起,你可以直接通过我们的平台质押 SUI 代币,并在支持 SUI 网络安全与去中心化的同时赚取 2.08% APY

新功能概览:无缝的 SUI 质押体验

全新的质押功能为所有人提供机构级别的质押服务,界面简洁直观,让奖励获取变得轻而易举。

关键特性

一键质押 质押 SUI 前所未有的简单。只需连接你的 Suisplash 钱包,输入想要质押的 SUI 数量并批准交易,即可几乎立即开始赚取奖励,无需繁琐步骤。

竞争性奖励 在质押的 SUI 上获得 2.08% APY。我们的 8% 手续费 完全透明,让你清楚了解收益构成。奖励将在每个 epoch(约 24 小时)结束后每日发放。

可信验证者 加入已经在 BlockEden.xyz 验证节点上质押超过 2200 万 SUI 的社区。我们拥有可靠的验证服务记录,企业级基础设施确保 99.9% 正常运行时间

灵活管理 资产保持灵活。质押即时生效,奖励立即累计。如需取回资金,可随时发起解除质押,SUI 将在标准的 24‑48 小时解锁期后可用。你可以通过仪表盘实时查看质押和奖励情况。

为什么选择 BlockEden.xyz 质押 SUI?

选择验证者是关键决策,以下是 BlockEden.xyz 成为你可信赖质押伙伴的理由。

可靠性

自成立以来,BlockEden.xyz 一直是区块链基础设施的基石。我们的验证节点为企业级应用提供动力,在多个网络上保持卓越的正常运行时间,确保奖励持续产出。

透明公平

我们坚持完全透明。没有隐藏费用,只有明确的 8% 手续费。你可以通过实时报告监控质押表现,并在链上验证我们的验证者活动。

  • 公开验证者地址: 0x3b5664bb0f8bb4a8be77f108180a9603e154711ab866de83c8344ae1f3ed4695

无缝集成

平台设计简洁,无需创建账户,可直接从钱包质押。体验针对 Suisplash 钱包进行优化,界面清爽直观,适合新手和专家。

入门指南

在 BlockEden.xyz 开始 SUI 质押仅需不到两分钟。

步骤 1:访问质押页面

前往 blockeden.xyz/dash/stake。无需注册账户,即可立即开始。

步骤 2:连接钱包

如果尚未安装,请先安装 Suisplash 钱包。在质押页面点击 “Connect Wallet”,在钱包扩展中批准连接,你的 SUI 余额将自动显示。

步骤 3:选择质押数量

输入想要质押的 SUI 数量(最低 1 SUI)。点击 “MAX” 可一次性质押全部可用余额,仅保留少量用于支付 gas 费用。摘要会显示质押数量和预计年化奖励。

步骤 4:确认并开始赚取

点击 “Stake SUI”,在钱包中批准最终交易。你的新质押将实时出现在仪表盘上,奖励即刻累计。

质押经济学:你需要了解的要点

掌握质押机制是有效管理资产的关键。

奖励结构

  • 基础 APY2.08% 年化
  • 奖励频率:每个 epoch(约 24 小时)发放一次
  • 手续费:奖励的 8%
  • 复利:奖励会自动转入钱包,可再次质押实现复利增长

收益示例

以下为基于 2.08% APY(扣除 8% 手续费)的简易收益估算。

质押数量年度奖励月度奖励日度奖励
100 SUI2.08 SUI0.17 SUI0.0057 SUI
1,000 SUI20.8 SUI1.73 SUI0.057 SUI
10,000 SUI208 SUI17.3 SUI0.57 SUI

注:以上为估算值,实际奖励受网络状况影响可能有所不同。

风险考量

  • 解锁期:解除质押后,SUI 将进入 24‑48 小时的解锁期,期间无法使用且不产生奖励。
  • 验证者风险:尽管我们保持高标准,任何验证者都存在运营风险。选择像 BlockEden.xyz 这样信誉良好的验证者尤为重要。
  • 网络风险:质押本质上是对底层区块链协议的参与,受其固有风险影响。
  • 市场风险:SUI 代币的市场价格波动会影响你质押资产的整体价值。

技术卓越

企业级基础设施

我们的验证节点基于技术卓越的底层构建,采用跨地域冗余系统确保高可用性。24/7 监控、自动故障转移以及专业运维团队全天候管理,定期进行安全审计与合规检查。

开源与透明

我们坚持开源原则,质押集成过程透明,可供用户审查。实时指标在 SUI 网络浏览器上公开,费用结构全程公开,无隐藏成本。我们亦积极参与社区治理,助力 SUI 生态发展。

支持 SUI 生态

通过在 BlockEden.xyz 质押,你不仅获得奖励,还在以下方面为 SUI 网络贡献力量:

  • 网络安全:你的质押提升了 SUI 网络的整体安全性。
  • 去中心化:支持独立验证者如 BlockEden.xyz,增强网络弹性,防止中心化。
  • 生态增长:我们将收取的手续费再投入基础设施维护与研发。
  • 创新:收入用于研发新工具和服务,服务整个区块链社区。

安全与最佳实践

请始终将资产安全放在首位。

钱包安全

  • 永不泄露 私钥或助记词。
  • 大额资产建议使用硬件钱包进行存储和质押。
  • 在签名交易前务必核对交易细节。
  • 保持钱包软件为最新版本。

质押安全

  • 初次质押建议先使用小额熟悉流程。
  • 考虑将质押分散到多个信誉良好的验证者,以降低风险。
  • 定期监控质押资产和奖励情况。
  • 在质押前充分了解解锁期规则。

加入 SUI 质押的未来

BlockEden.xyz 的 SUI 质押功能不仅是新特性,更是参与去中心化经济的入口。无论你是经验丰富的 DeFi 用户,还是刚踏入区块链世界的新手,我们都提供简洁安全的方式,让你在为 SUI 网络贡献力量的同时赚取奖励。

准备好开始赚取了吗?

访问 blockeden.xyz/dash/stake,立即质押你的首批 SUI 代币!


关于 BlockEden.xyz

BlockEden.xyz 是领先的区块链基础设施提供商,为开发者、企业和更广泛的 Web3 社区提供可靠、可扩展且安全的服务。从 API 服务到验证节点运营,我们致力于构建去中心化未来的基石。

  • 成立时间:2021 年
  • 支持网络:15+ 区块链网络
  • 企业客户:500+ 家全球公司
  • 累计安全资产:超过 1 亿美元,覆盖所有网络

关注我们的 Twitter,加入我们的 Discord,并在 BlockEden.xyz 探索完整服务套件。


免责声明:本文仅供参考,不构成任何金融建议。加密货币质押存在风险,包括本金损失的可能性。请自行研究并根据自身风险承受能力决定是否质押。

Sui的参考燃气价格(RGP)机制

· 阅读需 9 分钟
Dora Noda
Software Engineer

引言

2023 年 5 月 3 日在经过三轮广泛的测试网后正式对公众开放,Sui 区块链推出了一套创新的燃气定价系统,旨在惠及用户和验证者。其核心是 参考燃气价格(RGP),即网络范围内的基准燃气费,验证者在每个 epoch(约 24 小时)开始时共同确定。

该系统旨在为 SUI 代币持有者、验证者和终端用户构建一个互惠的生态系统,提供低且可预测的交易费用,同时奖励表现良好且可靠的验证者。本文深入探讨 RGP 的确定方式、验证者的计算方法、对网络经济的影响、治理下的演进以及与其他区块链燃气模型的比较。

参考燃气价格(RGP)机制

Sui 的 RGP 不是静态数值,而是通过每个 epoch 的动态、验证者驱动的过程重新设定。

  • 燃气价格调查(Gas Price Survey): 在每个 epoch 开始时,每个验证者提交其“保留价格”——即他们愿意接受的最低燃气价格。协议随后按质押量对这些提交进行排序,并将该 epoch 的 RGP 设为 质押加权的 2/3 分位数。此设计确保代表总质押量至少三分之二的验证者愿意以该价格处理交易,从而保证服务的可靠性。

  • 更新频率与要求: 虽然 RGP 每个 epoch 设定一次,但验证者必须主动管理其报价。官方指南要求验证者 至少每周更新一次 燃气价格报价。此外,如果 SUI 代币价值出现 20% 以上的波动,验证者必须立即更新报价,以确保 RGP 准确反映当前市场情况。

  • 计分规则与奖励分配: 为确保验证者遵守约定的 RGP,Sui 使用“计分规则”。在整个 epoch 中,验证者相互监控对方的表现,追踪同行是否及时处理 RGP 价格的交易。此监控产生每个验证者的绩效得分。epoch 结束时,这些得分用于计算奖励乘数,以调整每个验证者的质押奖励份额。

    • 表现良好的验证者获得 ≥1 的乘数,提升其奖励。
    • 迟缓、延误或未按 RGP 处理交易的验证者获得 <1 的乘数,等同于削减其部分收益。

这套两部分系统构建了强大的激励结构。它阻止验证者报出他们无法支撑的过低价格,因为绩效不足的财务惩罚将非常严厉。相反,验证者被激励提交他们能够可持续且高效处理的最低价格。


验证者操作:计算燃气价格报价

从验证者的视角来看,设定 RGP 报价是直接影响盈利能力的关键运营任务。它需要构建数据管道和自动化层,以处理来自链上和链下的多种输入。关键输入包括:

  • 每个 epoch 执行的燃气单位数
  • 每个 epoch 的质押奖励和补贴
  • 存储基金贡献
  • SUI 代币的市场价格
  • 运营支出(硬件、云托管、维护)

目标是计算一个能够确保净奖励为正的报价。过程涉及以下关键公式:

  1. 计算总运营成本:
    确定验证者在给定 epoch 中以法币计的支出。

    Costepoch=(Total Gas Units Executedepoch)×(Cost in $ per Gas Unitepoch)\text{Cost}_{\text{epoch}} = (\text{Total Gas Units Executed}_{\text{epoch}}) \times (\text{Cost in \$ per Gas Unit}_{\text{epoch}})
  2. 计算总奖励:
    确定验证者以法币计的总收入,来源于协议补贴和交易费用。

    $Rewardsepoch=(Total Stake Rewards in SUIepoch)×(SUI Token Price)\text{\$Rewards}_{\text{epoch}} = (\text{Total Stake Rewards in SUI}_{\text{epoch}}) \times (\text{SUI Token Price})

    其中 Total Stake Rewards 为协议提供的 Stake Subsidies 与交易收取的 Gas Fees 之和。

  3. 计算净奖励:
    验证者盈利能力的最终衡量指标。

    $Net Rewardsepoch=$Rewardsepoch$Costepoch\text{\$Net Rewards}_{\text{epoch}} = \text{\$Rewards}_{\text{epoch}} - \text{\$Cost}_{\text{epoch}}

    通过在不同 RGP 水平下建模预期成本和奖励,验证者可以确定一个最优报价提交至燃气价格调查。

主网启动时,Sui 将初始 RGP 固定为 1,000 MIST(1 SUI = 10⁹ MIST),持续一至两周。这为验证者提供了一个稳定的运营期,以收集足够的网络活动数据并在动态调查机制全面生效前建立计算流程。


对 Sui 生态系统的影响

RGP 机制深刻塑造了整个网络的经济学和用户体验。

  • 对用户:可预测且稳定的费用
    RGP 为用户提供了可信的锚点。交易的燃气费遵循简单公式:用户燃气价 = RGP + 小费。在正常情况下无需小费。网络拥堵时,用户可添加小费以获取优先权,从而在不改变 epoch 内稳定基准价的前提下形成费用市场。该模型相较于每个区块都变动基准费的系统,提供了显著更高的费用稳定性。

  • 对验证者:效率竞争
    系统鼓励健康竞争。验证者被激励降低运营成本(通过硬件和软件优化),以能够以更低的 RGP 获利。这种“效率竞争”通过压低交易成本惠及整个网络。机制同样迫使验证者保持平衡的利润率;报价过高会被排除在 RGP 计算之外,报价过低则会导致运营亏损并受到绩效惩罚。

  • 对网络:去中心化与可持续性
    RGP 机制有助于网络的长期健康。“新进、更高效”验证者的进入威胁防止现有验证者串通抬高价格。此外,验证者根据 SUI 代币的市场价格调整报价,集体确保运营在现实条件下可持续,从而使费用经济不受代币价格波动的直接影响。


治理与系统演进:SIP‑45

Sui 的燃气机制并非静态,而是通过治理不断演进。一个典型案例是 SIP‑45(优先交易提交),该提案旨在细化基于费用的优先级机制。

  • 解决的问题: 分析表明,仅支付高燃气价并不总能保证更快的交易被打包。
  • 提案内容: 提案包括提升最高允许燃气价上限,并为显著高于 RGP(例如 ≥5× RGP)的交易引入“放大广播”,确保这些交易在网络中快速传播以获得优先打包。

此举展示了基于实证数据对燃气模型进行迭代的承诺,以提升其有效性。


与其他区块链燃气模型的比较

Sui 的 RGP 模型独具特色,尤其是与以太坊的 EIP‑1559 相比。

维度Sui(参考燃气价格)Ethereum(EIP‑1559)
基准费确定方式验证者每 epoch 调查(市场驱动)每个区块算法计算(协议驱动)
更新频率每 epoch 一次(约 24 小时)每个区块一次(约 12 秒)
费用去向所有费用(RGP + 小费)归验证者基准费 销毁;小费归验证者
价格稳定性,日间可预测,需求激增时可能快速飙升
验证者激励通过竞争效率设定低且可盈利的 RGP最大化小费收益;无法控制基准费

潜在批评与挑战

尽管设计创新,RGP 机制仍面临若干挑战:

  • 复杂性: 调查、计分规则以及链下计算体系较为繁复,可能对新验证者构成学习门槛。
  • 对突发需求的响应慢: RGP 在整个 epoch 内固定,无法即时应对突发的需求激增,可能导致短暂拥堵,直至用户开始添加小费。
  • 潜在的串通风险: 理论上验证者可合谋设定高 RGP,但开放的验证者集合及竞争压力在很大程度上抑制了此类行为。
  • 无燃气费销毁: 与以太坊不同,Sui 将所有燃气费回流至验证者和存储基金,这虽奖励网络运营者,却未对 SUI 代币形成通缩压力,而这点对部分代币持有者而言可能是缺憾。

常见问题(FAQ)

为什么要质押 SUI?
质押 SUI 可保障网络安全并获取奖励。最初,这些奖励由 Sui 基金会大幅补贴,以弥补网络活动低的情况。补贴每 90 天下降 10%,预期交易费用奖励将逐步成为主要收益来源。质押的 SUI 还能在链上治理中获得投票权。

我的质押 SUI 会被削减吗?
会。虽然参数仍在完善中,但“计分规则削减”已生效。当验证者因低绩效、恶意行为等被其 2/3 同行给出零绩效分时,其奖励将被削减(具体比例待定)。如果所选验证者出现宕机或报价不佳,质押者也可能错失奖励。

质押奖励会自动复投吗?
会。Sui 的质押奖励在每个 epoch 自动分配并重新质押(复投)。若想提取奖励,需要显式进行解除质押操作。

Sui 的解锁期是多久?
初期,质押者可以立即解锁代币。预计未来会引入解锁期,即在解除质押后代币会被锁定一段时间,此规则将通过治理决定。

质押时我仍然持有我的 SUI 吗?
是的。质押 SUI 时,你是将权益委托给验证者,但仍然完全掌控你的代币,永不转移托管权给验证者。

无摩擦的上链入口与 zkLogin

· 阅读需 6 分钟
Dora Noda
Software Engineer

如何消除钱包摩擦,保持用户流动,并预测收益

如果你的 Web3 应用拥有与现代 Web2 服务相同的无缝注册流程会怎样?这正是 Sui 区块链上 zkLogin 的核心承诺。它的工作方式类似于 Sui 的 OAuth,允许用户使用 Google、Apple、X 等熟悉的账户登录。随后,零知识证明安全地将该 Web2 身份关联到链上的 Sui 地址——无需钱包弹窗、无需助记词、也不会导致用户流失。

这种影响是真实且立竿见影的。已有数十万 zkLogin 账户上线,案例研究显示,在去除传统钱包壁垒后,用户转化率从低迷的 17% 飙升至健康的 42%。下面我们来拆解其工作原理以及它能为你的项目带来什么。


为什么钱包阻碍首次转化

你已经构建了突破性的 dApp,但用户获取漏斗出现泄漏。罪魁祸首几乎总是相同的:“连接钱包”按钮。标准的 Web3 入门流程是一系列扩展安装、助记词警告以及加密术语问答的迷宫。

这对新手来说是巨大的障碍。用户体验研究者观察到,一旦出现钱包提示,流失率高达 87%。在一次有说服力的实验中,仅将该提示重新安排到结算流程的后期,完成率就提升至 94%。即使是对加密感兴趣的用户,主要担忧也是“如果点错按钮,我可能会失去资金”。去除这一步骤是释放指数增长的关键。


zkLogin 工作原理(通俗易懂)

zkLogin 通过使用每个互联网用户已经信任的技术,巧妙地规避了钱包问题。以下几个快速步骤在幕后完成了魔法:

  1. 临时密钥对:当用户想要登录时,浏览器本地会生成一个临时的、仅限单次会话的密钥对。可以把它看作一次性通行钥,只在本次会话有效。
  2. OAuth 流程:用户使用 Google、Apple 或其他社交账户登录。你的应用巧妙地在登录请求中嵌入唯一值(nonce)。
  3. ZKP 服务:登录成功后,ZKP(零知识证明)服务生成加密证明。该证明确认 “此 OAuth 令牌授权临时通行钥的持有者”,且从未在链上泄露用户的个人身份。
  4. 派生地址:将 OAuth 提供商返回的用户 JWT(JSON Web Token)与唯一的 结合,确定性地生成其永久的 Sui 地址。盐保持私密,可在客户端或安全的后端保存。
  5. 提交交易:你的应用使用临时密钥签名交易并附加 ZK 证明。Sui 验证节点在链上验证该证明,确认交易合法性,用户无需传统钱包。

步骤集成指南

准备好实现了吗?以下是使用 TypeScript SDK 的快速指南。Rust 或 Python 的原理完全相同。

1. Install SDK

@mysten/sui 包含了所有你需要的 zklogin 辅助工具。

pnpm add @mysten/sui

2. Generate Keys & Nonce

首先,创建一个临时密钥对,并生成与当前 Sui 网络 epoch 关联的 nonce。

const keypair = new Ed25519Keypair();
const { epoch } = await suiClient.getLatestSuiSystemState();
const nonce = generateNonce(keypair.getPublicKey(), Number(epoch) + 2, generateRandomness());

3. Redirect to OAuth

为你使用的提供商(例如 Google、Facebook、Apple)构建相应的 OAuth 登录 URL,并将用户重定向至该 URL。

4. Decode JWT & Fetch User Salt

用户登录并返回后,从 URL 中获取 id_token。使用它向后端获取用户专属的盐,然后派生出他们的 Sui 地址。

const jwt = new URLSearchParams(window.location.search).get('id_token')!;
const salt = await fetch('/api/salt?jwt=' + jwt).then(r => r.text());
const address = jwtToAddress(jwt, salt);

5. Request ZK Proof

将 JWT 发送至证明服务以获取 ZK 证明。开发阶段可以使用 Mysten 的公共证明服务。生产环境下请自行部署或使用如 Enoki 的服务。

const proof = await fetch('/api/prove', {
method:'POST',
body: JSON.stringify({ jwt, ... })
}).then(r => r.json());

6. Sign & Send

现在,构建交易,将发送者设为用户的 zkLogin 地址并执行。SDK 会自动附加 zkLoginInputs(即证明)。✨

const tx = new TransactionBlock();
tx.moveCall({ target:'0x2::example::touch_grass' }); // Any Move call
tx.setSender(address);
tx.setGasBudget(5_000_000);

await suiClient.signAndExecuteTransactionBlock({
transactionBlock: tx,
zkLoginInputs: proof // The magic happens here
});

7. Persist Session

为获得更流畅的用户体验,请将密钥对和盐加密后存储在 IndexedDB 或本地存储中。记得每隔几个 epoch 轮换一次,以提升安全性。


KPI 投影模板

zkLogin 带来的差异不仅是定性的,更是可量化的。对比典型的入职漏斗与使用 zkLogin 的漏斗:

漏斗阶段常规(钱包弹窗)使用 zkLogin差异
Landing → Sign-in100 %100 %
Sign-in → Wallet Ready15 %(安装扩展,助记词)55 %(社交登录)+40 个百分点
Wallet Ready → First Tx\ 23 %\ 90 %+67 个百分点
Overall Tx Conversion15 % (install, seed phrase)55 % (social login)+40 pp
Overall Tx Conversion23 %90 %+67 pp
Overall Tx Conversion

👉 这意味着: 对于一次吸引 10,000 名独立访客的活动,这相当于 300 次首日链上行为与超过 2,500 次之间的差距。


Best Practices & Gotchas

为了打造更无缝的体验,请牢记以下专业提示:

  • 使用赞助交易:为用户支付前几笔交易费用。这消除所有摩擦,带来令人惊叹的 “啊哈” 时刻。
  • 谨慎处理盐:更改用户的盐会生成新地址。仅在你拥有可靠的恢复方案时才这样做。
  • 展示 Sui 地址:注册后向用户展示其链上地址。这样高级用户可以在以后自行导入到传统钱包中。
  • 防止刷新循环:缓存 JWT 和临时密钥对直至过期,避免反复要求用户登录。
  • 监控证明服务延迟:关注证明生成的往返时间。如果超过 2 秒,考虑部署区域性证明服务以保持快速响应。

Where BlockEden.xyz Adds Value

虽然 zkLogin 完善了面向用户的流程,但在扩展时会带来新的后端挑战。这正是 BlockEden.xyz 发挥作用的地方。

  • API 层:我们的高吞吐、地域路由的 RPC 节点确保你的 zkLogin 交易以最低延迟处理,无论用户位于何处。
  • 可观测性:提供开箱即用的仪表盘,跟踪关键指标,如证明延迟、成功/失败比例以及转化漏斗健康度。
  • 合规性:对于桥接至法币的应用,我们的可选 KYC 模块可直接基于用户已验证身份提供合规的上链入口。

Ready to Ship?

笨拙、令人望而却步的钱包流程时代已经结束。启动 zkLogin 沙盒,接入 BlockEden 的全节点端点,观察你的注册曲线向上攀升——而用户甚至不需要听到 “钱包” 这个词。 😉

// 这里可以放置示例代码或其他内容

2025 年 Sui DeFi 生态系统:流动性、抽象化与新原语

· 阅读需 27 分钟
Dora Noda
Software Engineer

1. Sui DeFi 的流动性与增长

图示:Sui 的 DeFi TVL(蓝线)和 DEX 交易量(绿柱)在 2025 年第二季度显著增长。

总锁定价值(TVL)激增: 过去一年,Sui 网络的 DeFi 流动性呈爆炸式增长。2024 年底约 $600M TVL,到 2025 年中期已飙升至 超过 $2B。事实上,Sui 在 2025 年 5 月 21 日达到约 $2.55B TVL,并在第二季度大部分时间保持在 $2B 以上。这 300%+ 的增长(相较 2023 年 5 月的年增长率 480%)使 Sui 稳居 DeFi TVL 前十名区块链,增速超过 Solana 等网络。主要驱动因素包括 机构采纳原生 USDC 稳定币支持,共同吸引了大量资本流入。值得注意的是,Sui 的 月度 DEX 交易量 已进入全链前列——截至 2025 年中 每月超过 $7–8B(行业排名第 8)。Sui 上流通的 稳定币流动性 在 2025 年中已突破 $1B,全年增长 180%,显示链上流动性日益深化。跨链资本同样涌入;约 $2.7B 资产已桥接至 Sui 生态,其中包括比特币流动性(详见第 3 节)。这一 快速增长趋势 证明了 Sui 正在成为高价值 DeFi 资产的聚集地。

主要 DEX 与借贷平台: Cetus、Momentum、Bluefin、Sudo、Typus、Suilend、SuiBridge、Wormhole、Wormhole‑BTC、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑USDT、Wormhole‑USDC、Wormhole‑US

User: "I want to create a new token on the Sui blockchain. I need a step-by-step guide that includes all the necessary technical details."Below is a complete, step‑by‑step guide for creating, publishing, and using a brand‑new token on the Sui blockchain. It covers everything you need to know – from the required tooling, through writing the Move contract, to interacting with the token via the CLI and the JavaScript/TypeScript SDK.


1️⃣ What You’ll Build

  • A native Sui coin (the same type of asset that SUI itself is) called MyToken.
  • Full token lifecycle: initialize → register → mint → transfer → burn.
  • Optional: metadata (name, symbol, decimals) and supply caps.
  • Deployable on localnet, devnet/testnet, and finally mainnet.

2️⃣ Prerequisites

ItemMinimum versionWhy you need it
Operating SystemLinux/macOS/Windows (WSL2)Sui CLI is cross‑platform
Rustrustc 1.71+Build the Sui client & Move compiler
Node.jsv18+ (optional, for SDK)Interact with Sui from JS/TS
Yarn / npmanyInstall the Sui SDK
GitanyClone the Sui repo
Sui CLIsui 0.33+ (or latest)Compile, test, publish Move packages
Sui FaucetGet testnet gas for devnet/testnet

Install Rust & Cargo

curl https://sh.rustup.rs -sSf | sh -s -- -y
source $HOME/.cargo/env
rustup update stable

Install Sui CLI (latest stable)

# Linux/macOS
curl -sSf https://raw.githubusercontent.com/MystenLabs/sui/main/scripts/install_sui_cli.sh | bash

# Verify
sui --version

(Optional) Install Node.js & Sui SDK

# Using nvm (recommended)
nvm install 18
nvm use 18

# Install SDK
npm i -g typescript # if you want ts-node
npm i @mysten/sui.js

3️⃣ Set Up a Development Network

You can work locally (fastest) or on the public devnet. Below we start a localnet – a single‑node Sui network that runs in a Docker container.

# Pull the latest Sui Docker image
docker pull mysten/sui:latest

# Run a localnet (exposes RPC on 8080)
docker run -d -p 8080:8080 --name sui-localnet mysten/sui:latest sui-node --network localnet

Tip: If you prefer the hosted devnet, just replace --rpc-url http://127.0.0.1:8080 with https://fullnode.devnet.sui.io:443.

Create a new address (your wallet) and fund it with testnet gas:

# Create a new address and save the keypair
sui client new-address --alias alice

# Request gas from the faucet (devnet only)
sui client faucet --address alice

You can view the address and its balance:

sui client address --alias alice
sui client gas --address alice

4️⃣ Create a New Move Package

# Create a folder for the token project
mkdir my_token && cd my_token

# Initialise a Move package (adds Move.toml, sources, tests)
sui move init

Your directory now looks like:

my_token/
├─ Move.toml
├─ sources/
│ └─ main.move
└─ tests/
└─ main.move

5️⃣ Write the Token Contract (Move)

Open sources/main.move and replace its content with the following complete token implementation.

Explanation – The contract:

  • Declares a new struct MyToken that derives store and implements the Coin trait.
  • Uses the standard library 0x2::coin (the official coin module) for all core logic.
  • Provides initialization, mint, burn, transfer, and metadata functions.
  • Uses TxContext for transaction‑specific data (signer, gas, etc.).
// sources/main.move
module 0xYOUR_ADDRESS::my_token {
use std::signer;
use std::string;
use std::vector;
use sui::coin::{Self, Coin, CoinMetadata, TreasuryCap, MintCap, BurnCap, register, mint, burn, transfer, balance, total_supply, freeze, unfreeze};
use sui::tx_context::TxContext;

// -------------------------------------------------------------------------
// 1️⃣ Token definition
// -------------------------------------------------------------------------
#[derive(Clone, Copy, Drop, Store)]
struct MyToken has key {}

// -------------------------------------------------------------------------
// 2️⃣ Token metadata (name, symbol, decimals)
// -------------------------------------------------------------------------
const NAME: &str = "MyToken";
const SYMBOL: &str = "MYT";
const DECIMALS: u8 = 6; // 6 decimal places (like USDC)

// -------------------------------------------------------------------------
// 3️⃣ Initialize the token – creates TreasuryCap & MintCap
// -------------------------------------------------------------------------
public(entry) fun initialize(
admin: &signer,
initial_supply: u64,
ctx: &mut TxContext
) {
// 1️⃣ Register the coin type for the admin (required before any operation)
register<MyToken>(admin, ctx);

// 2️⃣ Create the metadata object (only once)
let metadata = CoinMetadata {
name: string::utf8(NAME),
symbol: string::utf8(SYMBOL),
decimals: DECIMALS,
description: vector::empty<u8>(),
icon_url: vector::empty<u8>(),
url: vector::empty<u8>(),
};
// The metadata is stored automatically by `register` – no extra call needed

// 3️⃣ Mint the initial supply to the admin
// This also creates the TreasuryCap (holds the supply) and MintCap (allows future minting)
let (treasury_cap, mint_cap) = Coin::initialize<MyToken>(admin, initial_supply, ctx);

// 4️⃣ Store the caps in the admin's address so they can be used later
// (caps are move-only resources – they must be kept)
move_to<TreasuryCap>(admin, treasury_cap);
move_to<MintCap>(admin, mint_cap);
}

// -------------------------------------------------------------------------
// 4️⃣ Mint new tokens (only the holder of MintCap can call)
// -------------------------------------------------------------------------
public(entry) fun mint_tokens(
admin: &signer,
amount: u64,
ctx: &mut TxContext
) {
// Load the MintCap from the signer's storage
let mint_cap = borrow_global_mut<MintCap>(signer::address_of(admin));
// Mint the requested amount to the admin's address
let minted = mint<MyToken>(mint_cap, amount, ctx);
// Transfer minted coins to the admin (they are already in admin's address)
// No extra transfer needed – `mint` returns the newly created coin.
// If you want to send to another address, call `transfer` below.
}

// -------------------------------------------------------------------------
// 5️⃣ Burn tokens (requires BurnCap)
// -------------------------------------------------------------------------
public(entry) fun burn_tokens(
admin: &signer,
coin: Coin<MyToken>,
ctx: &mut TxContext
) {
// Load the BurnCap (must be stored in admin's address)
let burn_cap = borrow_global_mut<BurnCap>(signer::address_of(admin));
// Burn the supplied coin
burn<MyToken>(burn_cap, coin, ctx);
}

// -------------------------------------------------------------------------
// 6️⃣ Transfer tokens to another address
// -------------------------------------------------------------------------
public(entry) fun transfer_tokens(
sender: &signer,
recipient: address,
amount: u64,
ctx: &mut TxContext
) {
// Load the sender's coin (any coin of MyToken)
let coin = balance<MyToken>(signer::address_of(sender));
// Split the requested amount from the sender's balance
let (to_send, _remaining) = Coin::split(coin, amount, ctx);
// Transfer the split coin to the recipient
transfer<MyToken>(to_send, recipient, ctx);
}

// -------------------------------------------------------------------------
// 7️⃣ Helper view functions (read‑only, no entry)
// -------------------------------------------------------------------------
public fun total_supply(): u64 {
total_supply<MyToken>()
}

public fun balance_of(addr: address): u64 {
balance<MyToken>(addr)
}

// -------------------------------------------------------------------------
// 8️⃣ Register the coin for a new user (required before they can receive)
// -------------------------------------------------------------------------
public(entry) fun register_user(user: &signer, ctx: &mut TxContext) {
register<MyToken>(user, ctx);
}
}

What you need to replace

  • 0xYOUR_ADDRESS – the address that will publish the package (your own address). You can find it with sui client address --alias alice. Replace it in Move.toml and in the source file.

Update Move.toml

Open Move.toml and set the address field:

[package]
name = "my_token"
version = "0.0.1"
edition = "2024"

[dependencies]
Sui = { git = "https://github.com/MystenLabs/sui", rev = "mainnet" }

[addresses]
my_token = "0xYOUR_ADDRESS"

Tip: If you are using a localnet you can keep the address as 0x0 and let the CLI replace it automatically during publishing (--gas-budget will be used). For devnet/mainnet you must use a real address you control.


6️⃣ Build & Test the Package

Compile

sui move build

If the build succeeds you’ll see something like:

Compiling 1 package(s) in 0.5s

Create a simple test in tests/main.move:

// tests/main.move
#[test]
fun test_initialize_and_mint() {
let admin = @0x1; // placeholder – the test harness will replace it
let (admin_signer, ctx) = sui::test::new_signer_and_context(admin);
my_token::initialize(&admin_signer, 1_000_000, &mut ctx);
assert!(my_token::total_supply() == 1_000_000, 0);
my_token::mint_tokens(&admin_signer, 500_000, &mut ctx);
assert!(my_token::total_supply() == 1_500_000, 0);
}

Run the test:

sui move test

All tests should pass.


7️⃣ Publish the Package

7.1 Choose a Network

NetworkRPC URLFaucet (if needed)
localnethttp://127.0.0.1:8080No faucet – you control gas
devnethttps://fullnode.devnet.sui.io:443sui client faucet
testnethttps://fullnode.testnet.sui.io:443sui client faucet
mainnethttps://fullnode.mainnet.sui.io:443No faucet – you must have SUI

Set the RPC URL for the CLI (once per session):

export SUI_URL="http://127.0.0.1:8080"   # localnet
# export SUI_URL="https://fullnode.devnet.sui.io:443" # devnet
sui client active-address

7.2 Publish

# Use the address you created earlier (alice)
sui client publish \
--gas-budget 10000000 \
--skip-dependency-verification \
--path .
  • --gas-budget is the max gas you’re willing to spend (10 M gas is plenty for a simple package).
  • --skip-dependency-verification speeds up publishing on devnet/testnet; keep it off for production.

The CLI will output something like:

Transaction digest: 0x1234...abcd
Package ID: 0xabcdef1234567890

Save the Package ID – you’ll need it for later calls.


8️⃣ Register the Token for an Account

Before an address can hold MyToken, it must register the coin type.

# Register for alice (the address that published)
sui client call \
--package <PACKAGE_ID> \
--module my_token \
--function register_user \
--args $(sui client address --alias alice) \
--gas-budget 1000000

If you want to register for a different user (e.g., bob), first create a new address:

sui client new-address --alias bob
sui client faucet --address bob # devnet only

Then register for bob:

sui client call \
--package <PACKAGE_ID> \
--module my_token \
--function register_user \
--signer bob \
--gas-budget 1000000

You can verify registration by checking the objects owned by the address:

sui client objects --address alice

You should see an object of type 0xYOUR_ADDRESS::my_token::MyToken (the coin metadata object) and a TreasuryCap / MintCap if you stored them.


9️⃣ Mint Tokens

Only the holder of MintCap (created during initialize) can mint more tokens.

9.1 Verify you have the caps

sui client objects --address alice | grep MintCap

You should see something like:

Object ID: 0x... (type: 0xYOUR_ADDRESS::my_token::MintCap)

9.2 Mint

sui client call \
--package <PACKAGE_ID> \
--module my_token \
--function mint_tokens \
--args 5000000 \
--signer alice \
--gas-budget 1000000
  • 5000000 is the amount in the smallest unit (i.e., 5 MYT = 5 × 10⁶ = 5 000 000).
  • After the call, you can check the total supply:
sui client call \
--package <PACKAGE_ID> \
--module my_token \
--function total_supply

10️⃣ Transfer Tokens

10.1 Split & Transfer (CLI)

The CLI works with Coin objects. First, get a coin of MyToken:

# List all objects owned by alice and filter by type
sui client objects --address alice | grep MyToken

You’ll see an object ID, e.g., 0xcoin1. Use it to transfer:

# Transfer 250 MYT (250 × 10⁶ = 250_000_000) to bob
sui client call \
--package <PACKAGE_ID> \
--module my_token \
--function transfer_tokens \
--args $(sui client address --alias bob) 250000000 \
--signer alice \
--gas-budget 1000000

10.2 Transfer Using the Generic transfer-coin (no custom entry)

If you already have a Coin<MyToken> object, you can use the built‑in transfer-coin command:

# First, split the amount you want to send (creates a new coin object)
sui client split-coin \
--coin <COIN_OBJECT_ID> \
--amount 250000000 \
--gas-budget 1000000

# The command returns a new coin object ID (e.g., 0xcoin2). Transfer it:
sui client transfer-coin \
--coin-object-id <COIN2_ID> \
--recipient $(sui client address --alias bob) \
--gas-budget 1000000

Check balances:

sui client call \
--package <PACKAGE_ID> \
--module my_token \
--function balance_of \
--args $(sui client address --alias alice)

sui client call \
--package <PACKAGE_ID> \
--module my_token \
--function balance_of \
--args $(sui client address --alias bob)

Both calls return the balance in the smallest unit.


11️⃣ Interact with the Token from JavaScript / TypeScript (Sui SDK)

Below is a minimal Node.js script that does the same operations: register, mint, transfer, burn.

// token_demo.ts
import { SuiClient, getFullnodeUrl, devnetConnection } from "@mysten/sui.js";
import { Ed25519Keypair, fromB64, toB64 } from "@mysten/sui.js/cryptography";
import { TransactionBlock } from "@mysten/sui.js/transactions";

// ---------------------------------------------------------------------
// 1️⃣ Setup client & keypair (replace with your own keypair)
// ---------------------------------------------------------------------
const SUI_URL = process.env.SUI_URL || devnetConnection.fullnode; // devnet by default
const client = new SuiClient({ url: SUI_URL });

const alice = Ed25519Keypair.fromSecretKey(
// Load from the file generated by `sui client new-address --alias alice`
// The file is stored in ~/.sui/sui_config/sui.keystore (JSON array of base64 strings)
// For simplicity we just read the first entry:
fromB64(
JSON.parse(
require("fs").readFileSync(
`${process.env.HOME}/.sui/sui_config/sui.keystore`,
"utf8",
),
)[0],
),
);

// ---------------------------------------------------------------------
// 2️⃣ Helper to send a transaction
// ---------------------------------------------------------------------
async function submitTx(tx: TransactionBlock) {
const result = await client.signAndExecuteTransactionBlock({
transactionBlock: tx,
signer: alice,
requestType: "WaitForLocalExecution",
options: { showEffects: true },
});
console.log("Tx digest:", result.digest);
return result;
}

// ---------------------------------------------------------------------
// 3️⃣ Register the coin for Alice (only needed once)
// ---------------------------------------------------------------------
async function registerCoin(packageId: string) {
const tx = new TransactionBlock();
const [coinType] = tx.moveCall({
target: `${packageId}::my_token::register_user`,
arguments: [tx.pure(alice.getPublicKey().toSuiAddress())],
});
await submitTx(tx);
}

// ---------------------------------------------------------------------
// 4️⃣ Mint tokens (requires MintCap stored in Alice's address)
// ---------------------------------------------------------------------
async function mintTokens(packageId: string, amount: number) {
const tx = new TransactionBlock();
tx.moveCall({
target: `${packageId}::my_token::mint_tokens`,
arguments: [tx.pure(alice.getPublicKey().toSuiAddress()), tx.pure(amount)],
});
await submitTx(tx);
}

// ---------------------------------------------------------------------
// 5️⃣ Transfer tokens to another address (Bob)
// ---------------------------------------------------------------------
async function transferTokens(packageId: string, to: string, amount: number) {
const tx = new TransactionBlock();
tx.moveCall({
target: `${packageId}::my_token::transfer_tokens`,
arguments: [
tx.pure(alice.getPublicKey().toSuiAddress()),
tx.pure(to),
tx.pure(amount),
],
});
await submitTx(tx);
}

// ---------------------------------------------------------------------
// 6️⃣ Example flow
// ---------------------------------------------------------------------
(async () => {
const PACKAGE_ID = "<YOUR_PACKAGE_ID>"; // <-- paste from publish step

// Register (only once per address)
await registerCoin(PACKAGE_ID);

// Mint 1 000 000 MYT (6 decimals → 1_000_000_000 units)
await mintTokens(PACKAGE_ID, 1_000_000_000);

// Transfer 250 MYT to Bob (Bob must be registered first)
const bob = "0xB0B..."; // replace with a real address
await transferTokens(PACKAGE_ID, bob, 250_000_000);
})();

Run it with:

ts-node token_demo.ts

The SDK automatically handles gas estimation, object fetching, and transaction signing.


9️⃣ Full Token Lifecycle Cheat‑Sheet (CLI)

ActionCLI commandImportant notes
Publish packagesui client publish --gas-budget 10_000_000 --path .Save the returned Package ID
Register coin for yourselfsui client call --package $PKG --module my_token --function register_user --signer alice --gas-budget 1_000_000Must be done once per address
Initialize token (create caps + supply)sui client call --package $PKG --module my_token --function initialize --args 1_000_000 --signer alice --gas-budget 5_000_000Only the publisher can call this (or any address that holds the caps)
Mint moresui client call --package $PKG --module my_token --function mint_tokens --args 500_000 --signer alice --gas-budget 1_000_000Requires the MintCap stored in the signer’s address
Burnsui client call --package $PKG --module my_token --function burn_tokens --args <COIN_OBJECT_ID> --signer alice --gas-budget 1_000_000Requires BurnCap
Transfersui client call --package $PKG --module my_token --function transfer_tokens --args <RECIPIENT> <AMOUNT> --signer alice --gas-budget 1_000_000Amount is in smallest unit
Check total supplysui client call --package $PKG --module my_token --function total_supplyRead‑only, no entry
Check balancesui client call --package $PKG --module my_token --function balance_of --args <ADDRESS>Returns a u64

🔐 Security & Best‑Practice Checklist

AreaRecommendation
Cap ManagementStore TreasuryCap, MintCap, and BurnCap in a multisig or a DAO‑controlled address. Never expose them to the public.
Supply CapsIf you want a fixed max supply, add a MAX_SUPPLY: u64 constant and enforce total_supply() + amount <= MAX_SUPPLY inside mint_tokens.
Freeze/UnfreezeUse freeze/unfreeze (available in 0x2::coin) to pause transfers in emergencies.
UpgradeabilitySui supports package upgrades. When you need to change the token logic, publish a new version with sui client upgrade. Keep the original package ID immutable for compatibility.
TestingRun full integration tests on a localnet before publishing to devnet. Use the sui::test framework to simulate multiple signers.
AuditsFor any production token, have the Move code audited by a reputable firm.
Gas ManagementOn mainnet you must hold SUI to pay gas. Keep a small reserve (≈ 0.1 SUI) for future upgrades.
MetadataPopulate description, icon_url, and url fields – they appear in wallets and explorers.

🚀 Deploy to Mainnet (once you’re ready)

  1. Fund your address with real SUI (buy from an exchange or receive from another wallet).

  2. Set the RPC to mainnet:

    export SUI_URL="https://fullnode.mainnet.sui.io:443"
  3. Publish (same command, but do not use --skip-dependency-verification):

    sui client publish \
    --gas-budget 20000000 \
    --path . \
    --signer alice
  4. Register the coin for any address that will receive it (including the admin).

  5. Mint the initial circulating supply (or keep it in the treasury).

Important: Mainnet transactions are final after a few seconds; there is no faucet, so you must have enough SUI to cover the gas for publishing (≈ 0.02 SUI) and for each subsequent call.


📚 Additional Resources

ResourceLink
Sui Docs – Coinshttps://docs.sui.io/build/coin
Move Language Referencehttps://move-language.github.io/move/
Sui Move Playground (online IDE)https://playground.move.dev/
Sui Explorer (devnet)https://explorer.devnet.sui.io/
Sui SDK (JS/TS)https://github.com/MystenLabs/sui/tree/main/sdk/typescript
Community Discordhttps://discord.com/invite/sui
Audit Checklist (Move)https://github.com/MystenLabs/sui/blob/main/docs/audits/MoveAuditChecklist.md

🎉 You’re Done!

You now have a fully functional Sui token:

  1. Move contract (MyToken) that follows the official coin standard.
  2. CLI workflow to compile, test, publish, register, mint, transfer, and burn.
  3. SDK example to integrate the token into dApps or scripts.

From here you can:

  • Build a token sale or liquidity pool using the same pattern.
  • Add access control (e.g., only a DAO can call mint_tokens).
  • Implement vesting, staking, or governance on top of the coin.

Happy building on Sui! 🚀

Aptos vs. Sui:两大基于 Move 的巨头全景分析

· 阅读需 7 分钟
Dora Noda
Software Engineer

概览

Aptos 与 Sui 作为新一代的 Layer-1 区块链,皆源自最初由 Meta 的 Libra/Diem 项目构想的 Move 语言。虽然它们拥有共同的血统,但团队背景、核心目标、生态系统策略以及演进路径已经出现显著分歧。

Aptos 强调多功能性和企业级性能,面向 DeFi 与机构用例。相对地,Sui 则聚焦于优化其独特的对象模型,以驱动面向大众消费者的应用,尤其是游戏、NFT 与社交媒体。哪条链最终脱颖而出,将取决于其能否在所选市场细分中演进技术、提供卓越的用户体验与开发者友好度。


1. 开发历程

Aptos

Aptos 诞生于 Aptos Labs——由前 Meta Libra/Diem 员工组建的团队——在 2021 年底开启闭测,并于 2022 年 10 月 19 日上线主网。早期主网性能因低于 20 TPS 而受到社区质疑(WIRED 报道),但随后在共识层与执行层的迭代不断将吞吐提升至数万 TPS。

截至 2025 年第二季度,Aptos 单周最高交易量达 4470 万笔,周活跃地址突破 400 万。网络累计账户已超过 8300 万,日均 DeFi 交易额稳定在 2 亿美元以上(来源:Aptos Forum)。

Sui

Sui 由 Mysten Labs 发起,其创始人曾是 Meta Novi 钱包团队的核心成员。Sui 于 2022 年 8 月启动激励测试网,并于 2023 年 5 月 3 日正式上线主网。自最早的测试网起,团队即优先打磨“对象模型”,将资产视为具备特定所有权与访问控制的对象,以提升并行交易处理能力(来源:Ledger)。

截至 2025 年 7 月中旬,Sui 生态系统锁定价值(TVL)已达 23.26 亿美元。平台的月交易量与活跃工程师数量快速增长,尤其在游戏与 NFT 领域表现突出(来源:AInvest、Tangem)。


2. 技术架构对比

功能AptosSui
语言继承原始 Move 设计,强调 “资源” 的安全性与严格的访问控制。语言相对精简。(来源:aptos.dev)在标准 Move 基础上扩展 “对象中心” 模型,打造支持水平可扩展并行交易的定制语言。(来源:docs.sui.io)
共识AptosBFT:优化的 BFT 共识机制,承诺亚秒级终结性,重点关注安全性与一致性。(来源:Messari)Narwhal + Tusk:将共识与交易排序解耦,通过优先并行执行效率实现高吞吐与低延迟。
执行模型采用流水线执行模型,交易分阶段处理(数据获取、执行、写回),支持高频转账与复杂逻辑。(来源:chorus.one)基于对象所有权的并行执行。涉及不同对象的交易无需全局状态锁,根本提升吞吐。
可扩展性聚焦单实例优化,同时研究分片技术。社区正积极开发 AptosCore v2.0 分片方案。原生并行引擎设计用于水平扩展,已在测试网实现数万 TPS 的峰值。
开发者工具成熟的工具链,包括官方 SDK、Devnet、Aptos CLI、Explorer 与用于可扩展性的 Hydra 框架。完整套件涵盖 Sui SDK、Sui Studio IDE、Explorer、GraphQL API 与面向对象的查询模型。

3. 链上生态与使用场景

3.1 生态规模与增长

Aptos
2025 年第一季度,Aptos 月活跃用户接近 1500 万,日活跃钱包逼近 100 万。DeFi 交易额同比增长 1000%,平台已成为金融级稳定币与衍生品的聚集地(来源:Coinspeaker)。关键战略包括通过 Upbit 引入 USDT,深化亚洲市场渗透,并吸引众多领先的 DEX、借贷协议与衍生品平台(来源:Aptos Forum)。

Sui
2025 年 6 月,Sui 生态 TVL 达到新高 23.26 亿美元,主要由高交互的社交、游戏与 NFT 项目驱动(来源:AInvest)。生态核心项目包括对象市场、Layer-2 桥接、社交钱包以及游戏引擎 SDK,已吸引大量 Web3 游戏开发者与 IP 持有者。

3.2 主导使用场景

  • DeFi 与企业集成(Aptos):凭借成熟的 BFT 终结性与丰富的金融工具套件,Aptos 更适合稳定币、借贷与衍生品等对一致性与安全性要求极高的场景。
  • 游戏与 NFT(Sui):Sui 的并行执行优势在此尤为明显。低交易延迟与几乎为零的费用非常适合游戏中高并发、低价值的交互,如开箱或转移游戏道具。

4. 演进与策略

Aptos

  • 性能优化:持续推进分片研究,规划多地区跨链流动性,并升级 AptosVM 提升状态访问效率。
  • 生态激励:已设立数亿美元规模的生态基金,支持 DeFi 基础设施、跨链桥接与合规企业应用。
  • 跨链互操作:加强与 Wormhole 等桥接的集成,并构建与 Cosmos(via IBC)及以太坊的连接。

Sui

  • 对象模型迭代:扩展 Move 语法以支持自定义对象类型与复杂权限管理,同时优化并行调度算法。
  • 推动消费级采纳:深度对接 Unreal、Unity 等主流游戏引擎,降低 Web3 游戏开发门槛,并推出社交插件与 SDK。
  • 社区治理:推广 SuiDAO,赋能核心项目社区治理能力,实现功能与费用模型的快速迭代。

5. 核心差异与挑战

  • 安全性 vs. 并行性:Aptos 的严格资源语义与一致性共识提供 DeFi 级安全,但可能限制并行度;Sui 的高度并行交易模型需持续证明其对大规模安全威胁的抵御能力。
  • 生态深度 vs. 广度:Aptos 在金融领域根基深厚,拥有强大的机构联系;Sui 则快速积累了大量面向消费者的项目,但尚未在大规模 DeFi 中实现决定性突破。
  • 理论性能 vs. 实际吞吐:虽然 Sui 的理论 TPS 更高,但实际吞吐仍受生态活跃度限制;Aptos 在高峰期也出现拥堵,表明仍需更有效的分片或 Layer-2 方案。
  • 市场叙事与定位:Aptos 以企业级安全与稳定为卖点,面向传统金融与合规行业;Sui 则以 “类 Web2 体验” 与 “零摩擦上手” 吸引更广泛的消费用户。

6. 大规模采纳之路

归根结底,这不是零和博弈。

中长期,如果消费市场(游戏、社交、NFT)继续保持爆发式增长,Sui 的并行执行与低准入门槛将有望在数千万主流用户中实现快速采纳。

短中期,Aptos 的成熟 BFT 终结性、低费用以及战略合作伙伴关系,使其在机构金融、合规 DeFi 与跨境支付领域具备更具吸引力的方案。

未来更可能是两条链共生共存的局面:Aptos 为金融与企业基础设施提供动力,Sui 主导高频消费交互。最终实现大规模采纳的链,将是那个在其细分领域持续优化性能与用户体验的链。

使用 Sui Paymaster 构建免 Gas 体验:架构与实现指南

· 阅读需 8 分钟
Dora Noda
Software Engineer

想象一个用户可以无缝地与你的 dApp 交互,而无需持有任何原生代币(SUI)的世界。这已不再是遥不可及的梦想。借助 Sui 的 Gas Station(亦称 Paymaster),开发者可以代替用户支付 gas 费用,彻底消除新用户进入 Web3 的最大障碍之一,实现真正无摩擦的链上体验。

本文提供了将你的 dApp 升级为免 Gas 的完整指南。我们将深入探讨 Sui Paymaster 的核心概念、架构、实现模式以及最佳实践。

1. 背景与核心概念:什么是赞助交易?

在区块链世界中,每笔交易都需要网络费用,即“gas”。对于习惯了 Web2 无缝体验的用户而言,这是一道显著的认知和操作障碍。Sui 在协议层面通过 赞助交易 来解决此挑战。

核心思路很简单:允许一方(赞助者)为另一方(用户)的交易支付 SUI gas 费用。这样,即使用户钱包中没有 SUI,也能成功发起链上操作。

Paymaster ≈ Gas Station

在 Sui 生态系统中,赞助交易的逻辑通常由称为 Gas StationPaymaster 的链下或链上服务处理。其主要职责包括:

  1. 评估交易:接收用户的免 Gas 交易数据(GasLessTransactionData)。
  2. 提供 Gas:锁定并分配交易所需的 gas 费用。通常通过由多个 SUI Coin 对象组成的 gas 池来管理。
  3. 生成赞助者签名:在批准赞助后,Gas Station 使用其私钥(SponsorSig)对交易进行签名,表明其愿意支付费用。
  4. 返回已签名交易:将包含 gas 数据和赞助者签名的 TransactionData 发送回去,等待用户的最终签名。

简而言之,Gas Station 就像为你的 dApp 用户提供加油服务,确保它们的“车辆”(交易)能够在 Sui 网络上顺畅运行。

2. 高层架构与交互流程

典型的免 Gas 交易涉及用户、dApp 前端、Gas Station 和 Sui 全节点之间的协同。交互顺序如下:

流程拆解:

  1. 用户 在 dApp UI 中执行操作,构造一个不含 gas 信息的交易数据包。
  2. dApp 将该数据发送至指定的 Gas Station 请求赞助。
  3. Gas Station 验证请求的有效性(例如检查用户是否符合赞助条件),随后为交易填充 Gas Coin 并签名,将半成品交易返回给 dApp。
  4. 用户 在钱包中看到完整的交易详情(例如“购买一个 NFT”),并提供最终签名。这一步至关重要,确保用户对其操作保持同意和控制。
  5. dApp 将包含用户和赞助者签名的完整交易广播至 Sui 全节点
  6. 交易在链上完成后,Gas Station 可通过监听链上事件或回执进行确认,然后通过 webhook 通知 dApp 后端,以完成业务流程的闭环。

3. 三种核心交互模型

你可以根据业务需求单独或组合使用以下三种交互模型。

模型 1:用户发起 → 赞助者批准(最常见)

这是标准模型,适用于绝大多数 dApp 内的交互。

  1. 用户构建 GasLessTransactionData:用户在 dApp 中执行操作。
  2. 赞助者添加 GasData 并签名:dApp 后端将交易发送至 Gas Station,后者批准交易、附加 Gas Coin 并添加签名。
  3. 用户审阅并给出最终签名:用户在钱包中确认最终交易详情并签名。随后 dApp 将其提交至网络。

该模型在安全性与用户体验之间取得了极佳的平衡。

模型 2:赞助者发起的空投/激励

该模型非常适用于空投、用户激励或批量资产分发。

  1. 赞助者预填 TransactionData 并签名:赞助者(通常为项目团队)预先构建大部分交易(例如向特定地址空投 NFT),并附加赞助签名。
  2. 用户的二次签名使其生效:用户只需对该“预批准”交易签名一次,即可执行。

这提供了极其流畅的用户体验。用户只需点击一次确认,即可领取奖励或完成任务,显著提升营销活动的转化率。

模型 3:通配符 GasData(信用额度模型)

这是一种更灵活且基于权限的模型。

  1. 赞助者转移 GasData 对象:赞助者首先创建一个或多个具有特定预算的 Gas Coin 对象,并直接将所有权转移给用户。
  2. 用户在预算范围内自由消费:用户随后可以在预算上限和有效期内自由使用这些 Gas Coin 来支付其发起的任何交易。
  3. Gas Coin 被归还:当 Gas Coin 用尽或过期后,可设计为自动销毁或返回给赞助者。

该模型相当于为用户提供一张限时、限额的“gas 费用信用卡”,适用于在游戏赛季期间提供免费试玩体验等需要高度用户自主性的场景。

4. 典型应用场景

Sui Paymaster 的强大之处不仅在于解决 gas 费用问题,还在于它能够深度融合业务逻辑,创造新可能。

场景 1:付费墙

许多内容平台或 dApp 服务要求用户满足特定条件(例如持有 VIP NFT、达到某会员等级)才能访问功能。Paymaster 可以完美实现此逻辑。

  • 流程:用户请求操作 → dApp 后端验证用户资质(如 NFT 持有) → 若符合条件,则调用 Paymaster 为其赞助 gas 费用;若不符合,则直接拒绝签名请求。
  • 优势:该模型天然抵御机器人和滥用行为。由于赞助决策在后端完成,恶意用户无法绕过资质检查而耗尽 gas 资金。

场景 2:一键结算

在电商或游戏内购买场景中,简化支付流程至关重要。

  • 流程:用户在结算页点击“立即购买”。dApp 构造包含业务逻辑的交易(例如 transfer_nft_to_user)。用户只需在钱包中签名批准业务交易,无需关心 gas,gas 费用由 dApp 的赞助者承担。
  • 优势:可以将业务参数如 order_id 直接编码进 ProgrammableTransactionBlock,实现后端订单的精准链上归因。

场景 3:数据归因

精准的数据追踪是业务优化的基础。

  • 流程:构造交易时,将唯一标识(如 order_hash)写入交易参数或将在执行时触发的事件中。
  • 优势:Gas Station 在收到成功交易的链上回执后,可通过解析事件或交易数据轻松提取该 order_hash,实现链上状态变化与后端订单或用户行为的精准映射。

5. 代码骨架(基于 Rust SDK)

下面是一个简化的代码片段,演示核心交互步骤。

let tx_data = TransactionData::new_gasless(...);
let signed_tx = gas_station.evaluate_and_sign(tx_data)?;
let final_tx = user.sign(signed_tx)?;
submit(final_tx);

完整实现请参考官方 Sui 文档的 Gas Station 教程,其中提供了开箱即用的代码示例。

6. 风险与注意事项

虽然 Sui Paymaster 带来了诸多好处,但仍需关注潜在的风险和考量。

安全风险

如果 Gas Station 的私钥泄露,攻击者可能伪造签名并耗尽 gas 资金。

  • 密钥管理:确保私钥存放在安全硬件模块中或采用多签方案。
  • 交易验证:严格验证传入的交易请求,防止恶意负载。

经济考量

开发者需要评估赞助 gas 费用的成本,尤其是在高交易量的场景中。

  • 预算管理:保持充足的 gas 池并监控使用模式,避免意外耗尽。
  • 定价模型:部分项目采用分层赞助(如免费额度后由用户自行支付),以平衡成本与用户体验。

7. 结论

Sui Paymaster 是一项强大的工具,能够显著提升用户体验,降低 Web3 应用的准入门槛。通过掌握其核心概念、架构和交互模型,开发者可以将其无缝集成到 dApp 中,为用户提供真正免 Gas 的流畅体验。