企业版SDK参考
@stablechain/enterprise 的完整概览。这涵盖了客户端从 createStableEnterprise 到其三个特性(免燃气费中继、保证区块空间和保证中继交易)、低级构建辅助函数以及共享结果和错误类型。有关这些概念的解释,请参阅Stable企业版SDK、免燃气费和保证区块空间。
安装
npm install @stablechain/enterprise viemadded 2 packages, audited 3 packages in 2sviem >= 2.0.0 是一个对等依赖项。该包以 @stablechain/enterprise 的形式发布,并重新导出 viem/chains 中的 stable 和 stableTestnet,因此您无需单独导入它们。
createStableEnterprise(config)
构造一个 StableEnterpriseClient。每个模块仅在您配置它时才存在,因此在使用前请进行空值检查。
import { createStableEnterprise, stable } from "@stablechain/enterprise";
import { privateKeyToAccount } from "viem/accounts";
const enterprise = createStableEnterprise({
chain: stable,
gasWaiver: { account: privateKeyToAccount("0xYOUR_WAIVER_KEY") },
});StableEnterpriseClient { gasWaiver, guaranteedBlock: undefined, guaranteedWaiver: undefined }StableEnterpriseConfig
| 字段 | 类型 | 默认值 | 描述 |
|---|---|---|---|
chain | StableChain | 目标链。传递 stable 或 stableTestnet(由包重新导出)。必填。 | |
rpcEndpoints | string[]? | 链的内置RPC | 一个或多个Stable RPC端点,在失败时按顺序尝试。仅在指向私有端点时才覆盖。 |
enterpriseRpcEndpoints | string[]? | 一个或多个企业版RPC网关端点,在失败时按顺序尝试。guaranteedBlock 和 guaranteedWaiver 必填。 | |
batchSizeLimit | number? | 100 | 每个批处理RPC调用的最大交易数量。 |
signer | Signer? | 免燃气费模块(gasWaiver、guaranteedWaiver)的默认签名者,当模块没有自己的密钥时。设置一次以通过单个托管后端驱动两者。请参阅签名密钥和托管。 | |
gasWaiver | GasWaiverConfig? | 启用免燃气费中继。 | |
guaranteedBlock | GuaranteedBlockConfig? | 启用保证区块空间。 | |
guaranteedWaiver | GuaranteedWaiverConfig? | 启用保证中继交易。 |
签名密钥和托管
持有免燃气费密钥的模块(gasWaiver 和 guaranteedWaiver)按顺序解析它:模块自己的 signer,然后是其 account(一个进程内 viem 密钥),然后是客户端配置上的顶级 signer,然后是 STABLE_ENTERPRISE_PRIVATE_KEY 环境变量。设置顶级 signer 一次,以通过单个托管后端驱动两个免燃气费模块。guaranteedBlock 使用其自己的已拨款 account 进行签名。
Signer 签署一个 32 字节的摘要,因此密钥永远不会离开托管后端。使用 awsKmsSigner 用于 AWS KMS,toSigner(account) 用于适配 viem 账户,或者 privateKeySigner(key) / envSigner() 用于进程内密钥。传递给模块的 send / sendBatch 的每次调用发送者也可以是 viem 账户或 Signer,因此 KMS/HSM 密钥可以在不降级到 relay 的情况下签署内部交易。
npm install @aws-sdk/client-kmsimport { createStableEnterprise, stable } from "@stablechain/enterprise";
import { awsKmsSigner } from "@stablechain/enterprise/aws-kms";
// KMS 密钥必须是 ECC_SECG_P256K1 (secp256k1);SDK 从中派生地址
const signer = await awsKmsSigner({ keyId: process.env.AWS_KMS_KEY_ID });
const enterprise = createStableEnterprise({
chain: stable,
gasWaiver: { signer }, // 托管级别的免燃气费密钥,代替 `account`
});awsKmsSigner 在 @stablechain/enterprise/aws-kms 子路径中提供,因此 @aws-sdk/client-kms 仍然是一个可选的对等依赖项,不在核心安装中。
StableEnterpriseClient
interface StableEnterpriseClient {
gasWaiver?: GasWaiverClient;
guaranteedBlock?: GuaranteedBlockClient;
guaranteedWaiver?: GuaranteedWaiverClient;
}免燃气费中继
gasWaiver 模块中继免燃气费交易。列入白名单的免燃气费账户将用户的零燃气费交易 (InnerTx) 封装到 WaiverTx 中并广播。用户无需USDT0。每个方法都返回 H_inner,即 InnerTx 的哈希值,而不是封装哈希值。
在配置中启用 gasWaiver:
const enterprise = createStableEnterprise({
chain: stable,
gasWaiver: {
account: privateKeyToAccount("0xYOUR_WAIVER_KEY"),
// 可选的每个合作伙伴的策略限制
maxGasLimit: 500_000n,
allowedTargets: [{ address: "0xToken", selectors: ["0xa9059cbb"] }],
},
});
const gw = enterprise.gasWaiver;GasWaiverConfig
扩展 ValidationLimits 和 SignerSource。
| 字段 | 类型 | 描述 |
|---|---|---|
signer | Signer? | 列入白名单的、治理注册的免燃气费密钥作为托管签名者(AWS KMS、HSM)。请参阅签名密钥和托管。优先于 account。 |
account | LocalAccount? | 免燃气费密钥作为进程内viem账户。如果两者都未设置,则回退到 STABLE_ENTERPRISE_PRIVATE_KEY。 |
maxGasLimit | bigint? | 继承自 ValidationLimits。 |
maxDataLength | number? | 继承自 ValidationLimits。 |
allowedTargets | AllowedTarget[]? | 继承自 ValidationLimits。 |
send(account, tx)
在一个调用中从 account 构建、签名和中继一个 InnerTx。gasPrice: 0、旧版类型、chainId 和待处理 nonce 都为您处理。如果拒绝,则抛出 StableEnterpriseRelayError。
const { txHash } = await gw.send(user, { to: token, data, gas: 150_000n });{ txHash: "0x8f3a...2d41" }tx 参数是 WaiverInnerTx 加上一个可选的 nonce。返回 RelayResult。
sendBatch(account, txs)
从一个 account 构建、签名和中继多个 InnerTx。Nonce 从账户的待处理 nonce 自动排序。每个输入返回一个结果,按顺序。
const results = await gw.sendBatch(user, [
{ to: token, data: dataA, gas: 150_000n },
{ to: token, data: dataB, gas: 150_000n },
]);[ { index: 0, success: true, txHash: "0x..." }, { index: 1, success: true, txHash: "0x..." } ]txs 是一个只读的 WaiverInnerTx 数组。返回 BatchResultItem[]。
relay(signedInnerTxHex)
中继一个预签名的零燃气费 InnerTx。这用于非托管流程,用户在其自己的环境中签名并只向您提供签名的十六进制,因此免燃气费操作员永远不会看到用户的密钥。使用 buildWaiverInnerTx 构建一个。如果拒绝,则抛出错误。
import { buildWaiverInnerTx, toSigner } from "@stablechain/enterprise";
const signed = await buildWaiverInnerTx(toSigner(user), stable.id, { to, data, gas: 150_000n, nonce });
const { txHash } = await gw.relay(signed);{ txHash: "0x8f3a...2d41" }relayBatch(signedInnerTxHexes)
中继一批预签名的 InnerTx。按顺序返回每个输入的 BatchResultItem。
const results = await gw.relayBatch([signed0, signed1]);[ { index: 0, success: true, txHash: "0x..." }, { index: 1, success: false, error: { code: "TARGET_NOT_ALLOWED", message: "..." } } ]保证区块空间
guaranteedBlock 模块通过企业版 RPC 网关中继 GuaranteedTx(类型 0x3F CustomTx),以便它们落在预留的企业版通道区块空间中。与免燃气费不同,签名者支付自己的燃气费并且必须有资金。每笔交易都带有与企业版通道关联的二维 nonce,并且广播仅通过网关进行。
通过 guaranteedBlock 和 enterpriseRpcEndpoints 启用它:
const enterprise = createStableEnterprise({
chain: stable,
enterpriseRpcEndpoints: [process.env.ENTERPRISE_RPC_URL], // Stable 提供的网关 URL
guaranteedBlock: {
account: privateKeyToAccount("0xFUNDED_SIGNER_KEY"),
laneId: 0n,
},
});
const gb = enterprise.guaranteedBlock;GuaranteedBlockConfig
| 字段 | 类型 | 描述 |
|---|---|---|
account | LocalAccount | 签署每笔 GuaranteedTx 并支付其燃气费的已拨款账户。 |
laneId | bigint | 企业版通道ID。必须在 [0, ENTERPRISE_MASK - 1] 范围内。无效ID将提前被拒绝。 |
send(account, tx)
构建、签名和中继一笔 GuaranteedTx。需要 1559 费用字段,因为签名者支付燃气费。chainId、企业版 nonceKey 和二维 nonce(从网关发现)都为您处理。
const gasPrice = await publicClient.getGasPrice();
const { txHash } = await gb.send(signer, {
to: recipient,
gas: 21_000n,
gasFeeCap: gasPrice * 2n,
gasTipCap: gasPrice,
});{ txHash: "0xabcd...7890" }tx 参数是 GuaranteedTxRequest 加上一个可选的 nonce。返回 RelayResult。
sendBatch(account, txs)
构建、签名并中继多个 GuaranteedTx。Nonce 从发现的基础自动排序。一次失败会影响其后续交易。
const results = await gb.sendBatch(signer, [
{ to: a, gas: 21_000n, gasFeeCap: gasPrice * 2n, gasTipCap: gasPrice },
{ to: b, gas: 21_000n, gasFeeCap: gasPrice * 2n, gasTipCap: gasPrice },
]);[ { index: 0, success: true, txHash: "0x..." }, { index: 1, success: true, txHash: "0x..." } ]relay(signedTx) / relayBatch(signedTxs)
中继预签名的 GuaranteedTx,或批量中继。使用 nonceKeyForLane 作为企业版 nonce 密钥,在其他地方使用 buildGuaranteedTx 构建并签名交易,然后只将签名的十六进制交给操作员。
import { buildGuaranteedTx, nonceKeyForLane, toSigner } from "@stablechain/enterprise";
const signed = await buildGuaranteedTx(toSigner(signer), stable.id, {
to,
gas: 21_000n,
gasFeeCap,
gasTipCap,
nonce, // 账户当前的二维通道 nonce
nonceKey: nonceKeyForLane(0n),
});
const { txHash } = await gb.relay(signed);{ txHash: "0xabcd...7890" }保证中继交易
guaranteedWaiver 模块结合了上述两个功能:通过保证区块空间路由的免燃气费交易。内部和外部交易都是 0x3F CustomTx,共享一个企业版 nonceKey,因此它像 guaranteedBlock 一样通过网关广播。免燃气费发起者承担燃气费,因此用户不需要余额和费用字段,就像 gasWaiver 一样。每个方法都返回 H_inner。
通过 guaranteedWaiver 和 enterpriseRpcEndpoints 启用它:
const enterprise = createStableEnterprise({
chain: stable,
enterpriseRpcEndpoints: [process.env.ENTERPRISE_RPC_URL], // Stable 提供的网关 URL
guaranteedWaiver: {
account: privateKeyToAccount("0xYOUR_WAIVER_KEY"),
laneId: 0n,
},
});
const gw = enterprise.guaranteedWaiver;GuaranteedWaiverConfig
扩展 ValidationLimits 和 SignerSource。它与 GasWaiverConfig 完全一样地获取外部包装器的免燃气费密钥(signer,然后是 account,然后是环境变量),并接受相同的 maxGasLimit、maxDataLength 和 allowedTargets 策略控制。
| 字段 | 类型 | 描述 |
|---|---|---|
signer | Signer? | 列入白名单的免燃气费密钥(签署外部包装器)作为托管签名者。优先于 account。请参阅签名密钥和托管。 |
account | LocalAccount? | 免燃气费密钥作为进程内viem账户。如果两者都未设置,则回退到 STABLE_ENTERPRISE_PRIVATE_KEY。 |
laneId | bigint | 企业版通道ID。必须在 [0, ENTERPRISE_MASK - 1] 范围内。 |
send(user, tx) / sendBatch(user, txs)
从 user 构建并签名内部 0x3F CustomTx,用免燃气费密钥包装,然后中继。由于燃气费已免除,因此不需要费用字段。内部二维 nonce 从网关发现,并且批处理从该基础自动排序。
// 单个
const { txHash } = await gw.send(user, { to: recipient });
// 批处理
const results = await gw.sendBatch(user, [{ to: a }, { to: b }]);{ txHash: "0x8f3a...2d41" }tx 参数是 GuaranteedWaiverTxRequest 加上一个可选的 nonce。send 返回 RelayResult;sendBatch 返回 BatchResultItem[]。
relay(signedInnerTx) / relayBatch(signedInnerTxs)
对于非托管流程,用户使用 buildGuaranteedTx 签名内部 0x3F CustomTx(费用为 0n,使用 nonceKeyForLane(laneId)),并只将签名的十六进制交给操作员。操作员用免燃气费密钥包装并中继。
import { buildGuaranteedTx, nonceKeyForLane, toSigner } from "@stablechain/enterprise";
const signedInner = await buildGuaranteedTx(toSigner(user), stable.id, {
to,
gas: 100_000n,
gasFeeCap: 0n, // 已免除
gasTipCap: 0n,
nonce,
nonceKey: nonceKeyForLane(0n),
});
const { txHash } = await gw.relay(signedInner); // 免燃气费包装 + 广播 → H_inner{ txHash: "0x8f3a...2d41" }构建辅助函数
用于非托管 relay 路径的低级签名者。每个都以 Hex 形式返回一个已签名的交易,没有 nonce 获取或费用估算。第一个参数是 Signer:用 toSigner(account) 包装一个 viem 账户,或传递一个托管签名者,例如 awsKmsSigner。
buildWaiverInnerTx(signer, chainId, req)
使用预设的免燃气费不变量(gasPrice: 0、旧版类型和给定的 chainId)签署一个免燃气费就绪的 InnerTx。req 是一个 WaiverInnerTx 加上一个必需的 nonce。
const signed = await buildWaiverInnerTx(toSigner(user), stable.id, { to, data, gas: 150_000n, nonce });buildGuaranteedTx(signer, chainId, req)
构建并签署一个 GuaranteedTx (0x3F CustomTx)。req 是一个 GuaranteedTxRequest 加上一个必需的 nonce 和 nonceKey。
buildGuaranteedWaiverTx(...)
将预签名的内部交易包装到外部 0x3F 免燃气费 CustomTx 中。由 guaranteedWaiver.relay 内部使用;为高级流程导出。
nonceKeyForLane(laneId)
返回用于 buildGuaranteedTx 的通道 ID 的企业版 nonceKey。
import { nonceKeyForLane } from "@stablechain/enterprise";
const nonceKey = nonceKeyForLane(0n);类型
SignerSource
免燃气费模块 (gasWaiver, guaranteedWaiver) 接受的签名密钥字段。按顺序解析:signer,然后是 account,然后是客户端的顶级 signer,然后是 STABLE_ENTERPRISE_PRIVATE_KEY 环境变量。请参阅签名密钥和托管。
| 字段 | 类型 | 描述 |
|---|---|---|
signer | Signer? | 托管级别的签名者(AWS KMS、HSM 或 privateKeySigner)。优先于 account。 |
account | LocalAccount? | 一个进程内 viem 账户,通过 toSigner 适配为 Signer。 |
Signer
一个可插拔的签名者,SDK 通过它签署 32 字节的摘要,因此密钥永远不会离开托管后端。可以使用 awsKmsSigner、toSigner、privateKeySigner 或 envSigner 构造一个。
interface Signer {
readonly address: Address;
signDigest(hash: Hex): Promise<Hex>;
}| 辅助函数 | 导入 | 描述 |
|---|---|---|
awsKmsSigner({ keyId, client? }) | @stablechain/enterprise/aws-kms | 由 AWS KMS ECC_SECG_P256K1 密钥支持的签名者。返回 Promise<Signer>。 |
toSigner(account) | @stablechain/enterprise | 将 viem LocalAccount 适配为 Signer。 |
privateKeySigner(key) | @stablechain/enterprise | 包装进程中原始私钥的签名者。 |
envSigner(varName?) | @stablechain/enterprise | 从 STABLE_ENTERPRISE_PRIVATE_KEY(或 varName)读取密钥的签名者。 |
WaiverInnerTx
每个调用不同的 InnerTx 字段。
| 字段 | 类型 | 默认值 | 描述 |
|---|---|---|---|
to | Address | 目标地址:ERC-20 转账的代币合约,原生代币的接收者。 | |
gas | bigint? | DEFAULT_INNER_GAS (150_000n) | 燃气限额。因为 gasPrice 为 0,所以慷慨的限额是免费的。 |
data | Hex? | "0x" | 调用数据。 |
value | bigint? | 0n | 要发送的原生代币值。 |
GuaranteedTxRequest
| 字段 | 类型 | 默认值 | 描述 |
|---|---|---|---|
to | Address? | 目标地址。 | |
gas | bigint | 燃气限额。必填。 | |
gasFeeCap | bigint | maxFeePerGas。必填。 | |
gasTipCap | bigint | maxPriorityFeePerGas。必填。 | |
data | Hex? | "0x" | 调用数据。 |
value | bigint? | 0n | 要发送的原生代币值。 |
GuaranteedWaiverTxRequest
费用字段始终为 0,因此此处省略。
| 字段 | 类型 | 默认值 | 描述 |
|---|---|---|---|
to | Address | 目标地址。 | |
gas | bigint? | 共享的内部燃气默认值 | 燃气限额。 |
data | Hex? | "0x" | 调用数据。 |
value | bigint? | 0n | 要发送的原生值。免燃气费允许进行值转移。 |
ValidationLimits
应用于 gasWaiver 和 guaranteedWaiver 的每个 InnerTx 的合作伙伴策略。
| 字段 | 类型 | 默认值 | 描述 |
|---|---|---|---|
maxGasLimit | bigint? | 10_000_000n | InnerTx 的最大燃气限额。超出此限额将导致 GAS_LIMIT_EXCEEDED 错误。 |
maxDataLength | number? | 131_072 (128 KB) | 调用数据的最大字节大小。超出此限额将导致 DATA_TOO_LARGE 错误。 |
allowedTargets | AllowedTarget[]? | 免燃气费可能赞助的合约和方法的允许列表。如果设置,则不在列表中的目标将导致 TARGET_NOT_ALLOWED 错误。 |
AllowedTarget
| 字段 | 类型 | 描述 |
|---|---|---|
address | Address | "*" | InnerTx 可能调用的合约,或 "*" 以匹配任何合约。 |
selectors | Hex[]? | 允许的 4 字节方法选择器(例如,ERC-20 transfer 的 "0xa9059cbb")。省略或留空以允许 address 上的任何方法。 |
RelayResult
interface RelayResult {
txHash: Hash; // 对于免燃气费是 H_inner,对于独立的保证区块是 GuaranteedTx 哈希
}BatchResultItem
批处理中每个输入的条目,按输入顺序。批处理不会抛出错误,而是报告每个项目的结果。
| 字段 | 类型 | 描述 |
|---|---|---|
index | number | 与输入数组匹配的从零开始的位置。 |
success | boolean | 此项目是否已中继。 |
txHash | Hash? | 成功时存在:内部交易哈希。 |
error | { code: ErrorCode; message: string }? | 失败时存在。 |
错误
单交易方法 (send, relay) 在拒绝时抛出错误。批处理方法则在 BatchResultItem.error 中报告每项失败。所有错误类都继承自 StableEnterpriseError。
| 类 | 抛出条件 | 有用字段 |
|---|---|---|
StableEnterpriseError | 所有 SDK 错误的基类。 | message |
StableEnterpriseRelayError | 交易在 RPC 或中继层被拒绝。 | code |
WaiverValidationError | InnerTx 在广播前未通过策略检查(燃气费、数据大小或目标允许列表)。 | code |
import { StableEnterpriseRelayError } from "@stablechain/enterprise";
try {
await gw.send(user, { to: token, data });
} catch (err) {
if (err instanceof StableEnterpriseRelayError && err.code === "TARGET_NOT_ALLOWED") {
// InnerTx 目标不在配置的允许列表中
}
throw err;
}StableEnterpriseRelayError: relay failed [TARGET_NOT_ALLOWED]: target 0x... not allowedErrorCode
抛出的错误或 BatchResultItem.error 上的 code 是以下之一:
| 代码 | 含义 |
|---|---|
UNKNOWN_ERROR | 没有特定代码时的回退。 |
BROADCAST_FAILED | 广播在 RPC 层被拒绝,或者网关中继失败。 |
INVALID_TRANSACTION | InnerTx 解码或解析失败。 |
INVALID_SIGNATURE | 签名验证失败。 |
UNSUPPORTED_TX_TYPE | InnerTx 类型不是 legacy、eip2930 或 eip1559。 |
WRONG_CHAIN_ID | InnerTx chainId 缺失或与目标链不匹配。 |
NON_ZERO_GAS_PRICE | InnerTx 带有非零燃气价格(对于免燃气费必须为零)。 |
GAS_LIMIT_EXCEEDED | InnerTx 燃气限制超过 maxGasLimit。 |
DATA_TOO_LARGE | InnerTx 调用数据超过 maxDataLength。 |
TARGET_NOT_ALLOWED | InnerTx 目标不在 allowedTargets 中。 |
GATEWAY_UNAUTHORIZED | 企业版 RPC 网关拒绝了 API 密钥(缺失、无效或过期)。 |
QUOTA_EXCEEDED | 企业版 RPC 网关燃气配额已用尽。 |
常量
| 常量 | 类型 | 描述 |
|---|---|---|
DEFAULT_INNER_GAS | bigint | 当 gas 被省略时,InnerTx 的默认燃气限额 (150_000n)。 |
ENTERPRISE_FLAG | bigint | 在通道的 nonceKey 上设置的企业版位。 |
ENTERPRISE_MASK | bigint | 通道 ID 的上限:laneId 必须在 [0, ENTERPRISE_MASK - 1] 范围内。 |
下一步建议
- Stable企业版SDK: 了解其功能和使用场景。
- 免燃气费协议: 交易格式、标记路由和治理控制。
- 保证区块空间: Stable 如何为企业工作负载保留区块容量。

