Skip to main content

Gate Layer 账户抽象 Bundler API 集成指南

本文档介绍如何使用 ERC-4337 账户抽象标准,向 Gate Layer Bundler 提交 UserOperation。

核心流程:构造 UserOperation → 估算 Gas → 签名 → 提交 Bundler → 轮询回执。

关键参数:

  • Bundler:https://gatelayer-bundler.gatenode.cc
  • EntryPoint v0.8(运行时通过 eth_supportedEntryPoints 获取)
  • Gas Token:GT;所有数值字段统一使用 0x 前缀的十六进制

支持能力:自付 Gas(默认,账户需在 EntryPoint 预存 GT)/ Paymaster 代付 / 通过 EIP-7702 将 EOA 临时委托为智能账户 / 首次账户部署与首个 UserOperation 合并执行(通过 factory + factoryData)。

接入路径二选一:直接调用 JSON-RPC(见 §6),或使用 viem + @aa-sdk/core + @account-kit/smart-contracts 的 SDK 快速集成(见 §8)。


1. 网络参数​

Gate Layer 主网​

参数值
Chain ID10088
RPC(HTTP)https://gatelayer-mainnet.gatenode.cc
RPC(WSS)wss://gatelayer-ws-mainnet.gatenode.cc
Bundlerhttps://gatelayer-bundler.gatenode.cc
EntryPoint(0.8)0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108
区块浏览器https://www.gatescan.org/gatelayer
Gas 代币GT
AA 标准ERC-4337 v0.7

Gate Layer 测试网​

参数值
Chain ID10087
RPC(HTTP)https://gatelayer-testnet.gatenode.cc
RPC(WSS)wss://gatelayer-ws-testnet.gatenode.cc
Bundlerhttps://gatelayer-testnet-bundler.gatenode.cc
区块浏览器https://www.gatescan.org/gatelayer-testnet
水龙头https://www.gatechain.io/docs/GateLayer/GettingStarted/GetTestnetGT

2. ERC-4337 概念​

ERC-4337 允许智能合约账户在无需 EOA 的情况下发起交易。用户不再提交原始交易,而是向 Bundler 提交 UserOperation 对象。

标准执行流程:

  1. 用户或 dApp 构造并签名一个 UserOperation
  2. Bundler 从替代内存池(alt-mempool)收集 UserOperation
  3. Bundler 将它们打包成一笔交易
  4. 该交易被发送至 EntryPoint 合约
  5. EntryPoint 验证并执行每个操作

Paymaster 为可选项。 当 paymaster 为空时,智能账户从其自身的 EntryPoint 存款中支付 Gas(需提前通过 depositTo() 充值)。当 paymaster 有值时,Paymaster 合约代替用户赞助 Gas。


3. EntryPoint 合约​

查询 Bundler 以获取当前活跃的 EntryPoint 地址:

curl -s "https://gatelayer-bundler.gatenode.cc" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "eth_supportedEntryPoints",
"params": []
}'

返回示例:

{
"jsonrpc": "2.0",
"id": 1,
"result": ["0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"]
}

始终在运行时通过 eth_supportedEntryPoints 动态获取 EntryPoint 地址。硬编码不同版本的地址会导致静默验证失败。


4. Gas 费用机制​

Gate Layer 运行于 OP Stack。每笔交易需支付三项费用,均以 GT 计价:

totalFee = l2ExecutionFee + l1DataFee + operatorFee

L2 执行费 — 链上执行的标准 EIP-1559 费用:

l2ExecutionFee = gasUsed × (baseFee + priorityFee)

L1 数据费 — 通过 EIP-4844 blobs 将交易数据发布至 Gate Chain 的成本:

l1DataFee = estimatedCompressedSize × (baseFeeScalar × l1BaseFee × 16 + blobFeeScalar × l1BlobBaseFee) / 10¹²

当前 Gate Layer 参数:baseFeeScalar = 113016,blobFeeScalar = 801949。

Operator 费 — 当前为零(operatorFeeScalar = 0,operatorFeeConstant = 0)。目前不收取额外的运营商费用。

对于 UserOperation,三项费用均须包含在 UserOperation 的 Gas 预算中。签名前请使用 eth_estimateUserOperationGas 和 eth_maxPriorityFeePerGas 计算正确值。


5. UserOperation 结构(v0.7)​

ERC-4337 v0.7 将 initCode 和 paymasterAndData 拆分为独立字段。

字段类型说明
senderaddress智能账户地址
nonceuint256从 EntryPoint.getNonce(sender, key) 获取
factoryaddress账户工厂地址(仅首次部署时填写,已部署则省略)
factoryDatabytes工厂调用数据(仅首次部署时填写,已部署则设为 0x)
callDatabytes在智能账户上执行的调用编码数据
callGasLimituint256执行阶段的 Gas 上限
verificationGasLimituint256验证阶段的 Gas 上限
preVerificationGasuint256覆盖 Bundler 打包成本及 L1 数据费组件的开销 Gas
maxFeePerGasuint256最高 Gas 价格(baseFee + priorityFee)
maxPriorityFeePerGasuint256给序列器的最高小费
paymasteraddressPaymaster 合约地址;自付时留空
paymasterVerificationGasLimituint256Paymaster 验证阶段的 Gas(无 Paymaster 时设为 0x0)
paymasterPostOpGasLimituint256Paymaster 后处理阶段的 Gas(无 Paymaster 时设为 0x0)
paymasterDatabytesPaymaster 专属数据(无 Paymaster 时设为 0x)
signaturebytes账户所有者对 UserOperation 哈希的签名
eip7702Authobject(可选) EIP-7702 授权元组——详见第 9 节

6. 集成流程​

第 1 步 — 查询 EntryPoint​

curl -s "https://gatelayer-bundler.gatenode.cc" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"eth_supportedEntryPoints","params":[]}'

第 2 步 — 获取优先费​

curl -s "https://gatelayer-mainnet.gatenode.cc" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"eth_maxPriorityFeePerGas","params":[]}'

将返回值作为 maxPriorityFeePerGas,加上当前 L2 baseFee 即得 maxFeePerGas。

第 3 步 — 估算 Gas​

将所有 Gas 字段设为 0x0,并使用哑签名发送 UserOperation:

curl -s "https://gatelayer-bundler.gatenode.cc" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 3,
"method": "eth_estimateUserOperationGas",
"params": [
{
"sender": "<SENDER_ADDRESS>",
"nonce": "<NONCE_HEX>",
"callData": "<CALL_DATA_HEX>",
"callGasLimit": "0x0",
"verificationGasLimit": "0x0",
"preVerificationGas": "0x0",
"maxPriorityFeePerGas": "<MAX_PRIORITY_FEE_HEX>",
"maxFeePerGas": "<MAX_FEE_HEX>",
"signature": "0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000011b"
},
"<ENTRY_POINT_ADDRESS>"
]
}'

关于占位签名(dummy signature):Gas 估算需要一个格式有效的 65 字节 ECDSA 签名。传入空的 0x 会导致 ECDSA.recover() 回滚,从而破坏估算流程。请使用上述占位签名,或任何格式有效、但不匹配账户所有者密钥的 65 字节十六进制值。

返回示例:

{
"jsonrpc": "2.0",
"id": 3,
"result": {
"preVerificationGas": "<HEX>",
"verificationGasLimit": "<HEX>",
"callGasLimit": "<HEX>",
"paymasterVerificationGasLimit": "0x0"
}
}

第 4 步 — 签名​

计算 UserOperation 哈希,并用账户所有者私钥签名:

userOpHash = keccak256(abi.encode(
keccak256(packed(userOp fields)),
entryPointAddress,
chainId
))
signature = owner.signMessage(userOpHash) // 需要 ETH 签名消息前缀

第 5 步 — 提交​

curl -s "https://gatelayer-bundler.gatenode.cc" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 4,
"method": "eth_sendUserOperation",
"params": [
{
"sender": "<SENDER_ADDRESS>",
"nonce": "<NONCE_HEX>",
"callData": "<CALL_DATA_HEX>",
"callGasLimit": "<CALL_GAS_LIMIT_HEX>",
"verificationGasLimit": "<VERIFICATION_GAS_LIMIT_HEX>",
"preVerificationGas": "<PRE_VERIFICATION_GAS_HEX>",
"maxPriorityFeePerGas": "<MAX_PRIORITY_FEE_HEX>",
"maxFeePerGas": "<MAX_FEE_HEX>",
"factory": "",
"factoryData": "0x",
"paymaster": "",
"paymasterVerificationGasLimit": "0x0",
"paymasterPostOpGasLimit": "0x0",
"paymasterData": "0x",
"signature": "<SIGNED_USER_OPERATION_HEX>"
},
"<ENTRY_POINT_ADDRESS>"
]
}'

返回示例:

{
"jsonrpc": "2.0",
"id": 4,
"result": "<USER_OPERATION_HASH>"
}

第 6 步 — 轮询回执​

curl -s "https://gatelayer-bundler.gatenode.cc" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 5,
"method": "eth_getUserOperationReceipt",
"params": ["<USER_OPERATION_HASH>"]
}'

待确认时返回 null。建议每 3–5 秒轮询一次,并采用指数退避策略。确认后的结果包含 transactionHash 和 "success": true。


7. 自付模式 vs. Paymaster 模式​

默认情况下无需 Paymaster,智能账户从其 EntryPoint 存款中支付 Gas。

自付模式(无 Paymaster)

将所有 paymaster 字段留空或设为零:

"paymaster": "",
"paymasterVerificationGasLimit": "0x0",
"paymasterPostOpGasLimit": "0x0",
"paymasterData": "0x"

提交前,请确保智能账户在 EntryPoint 中有足够的 GT 存款:

entryPoint.depositTo{value: amount}(smartAccountAddress);

Paymaster 赞助模式

当 Paymaster 赞助 Gas 时,填写以下字段:

"paymaster": "<PAYMASTER_CONTRACT_ADDRESS>",
"paymasterVerificationGasLimit": "<HEX>",
"paymasterPostOpGasLimit": "<HEX>",
"paymasterData": "<PAYMASTER_SIGNED_DATA_HEX>"

paymasterData 由 Paymaster 服务在验证并联署 UserOperation 后提供。


8. SDK 快速入门(quick-start.js)​

在生产环境中,quick-start.js 对原始 JSON-RPC 流程进行了封装。

安装依赖​

npm install viem @aa-sdk/core @account-kit/smart-contracts

定义 Gate Layer 链​

import { LocalAccountSigner, getEntryPoint } from '@aa-sdk/core';
import { createLightAccount } from '@account-kit/smart-contracts';
import {
createPublicClient,
defineChain,
http,
parseEther,
toHex,
encodeFunctionData,
getContract,
} from 'viem';
import { privateKeyToAccount } from 'viem/accounts';

const {
PRIVATE_KEY,
RPC_URL = 'https://gatelayer-mainnet.gatenode.cc',
BUNDLER_URL = 'https://gatelayer-bundler.gatenode.cc',
ENTRY_POINT = '0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108',
LIGHT_ACCOUNT_FACTORY = '0x13E9ed32155810FDbd067D4522C492D6f68E5944',
RECIPIENT_ADDRESS = '0xRECIPIENT_ADDRESS',
CHAIN_ID = '10088',
TRANSFER_GT = '0.001',
} = process.env;

if (!PRIVATE_KEY) throw new Error('Missing PRIVATE_KEY');

const chain = defineChain({
id: Number(CHAIN_ID),
name: `GateChain-${CHAIN_ID}`,
nativeCurrency: { name: 'GT', symbol: 'GT', decimals: 18 },
rpcUrls: { default: { http: [RPC_URL] } },
});

const publicClient = createPublicClient({ chain, transport: http(RPC_URL) });

async function bundlerRpc(method, params) {
const res = await fetch(BUNDLER_URL, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ jsonrpc: '2.0', id: 1, method, params }),
});
const { result, error } = await res.json();
if (error) throw new Error(`${method}: ${JSON.stringify(error)}`);
return result;
}

async function main() {
// 1. 创建智能账户
const owner = LocalAccountSigner.privateKeyToAccountSigner(PRIVATE_KEY);
const ownerAddr = await owner.getAddress();
const entryPointDef = { ...getEntryPoint(chain, { version: '0.7.0' }), address: ENTRY_POINT };

// 向工厂查询正确的反事实地址
const factoryContract = getContract({
address: LIGHT_ACCOUNT_FACTORY,
abi: [
{
name: 'getAddress',
type: 'function',
stateMutability: 'view',
inputs: [
{ name: 'owner', type: 'address' },
{ name: 'salt', type: 'uint256' },
],
outputs: [{ name: '', type: 'address' }],
},
],
client: publicClient,
});
const accountAddress = await factoryContract.read.getAddress([ownerAddr, 0n]);

const account = await createLightAccount({
chain,
transport: http(RPC_URL),
signer: owner,
factoryAddress: LIGHT_ACCOUNT_FACTORY,
accountAddress,
version: 'v2.0.0',
entryPoint: entryPointDef,
});

const sender = account.address;
console.log('Smart account address:', sender);

// 2. 检查部署状态 & 获取 initCode
const code = await publicClient.getCode({ address: sender });
const isDeployed = code && code !== '0x';
const initCode = await account.getInitCode();
const needsDeploy = !isDeployed && initCode && initCode !== '0x';

// 3. 构建 callData
const callData = encodeFunctionData({
abi: [
{
name: 'execute',
type: 'function',
stateMutability: 'nonpayable',
inputs: [
{ name: 'dest', type: 'address' },
{ name: 'value', type: 'uint256' },
{ name: 'func', type: 'bytes' },
],
outputs: [],
},
],
functionName: 'execute',
args: [RECIPIENT_ADDRESS, parseEther(TRANSFER_GT), '0x'],
});

// 4. 获取 nonce
const nonce = await publicClient.readContract({
address: ENTRY_POINT,
abi: entryPointDef.abi,
functionName: 'getNonce',
args: [sender, 0n],
});

// 5. Gas 限制 & 费用(需为整数 gwei)
// 注意:请根据实际交易复杂度调整这些值。
// 生产环境中应使用 eth_estimateUserOperationGas 获取精确值。
const callGasLimit = 200_000n;
const verificationGasLimit = 500_000n;
const preVerificationGas = 100_000n;
const maxPriorityFeePerGas = 1_000_000_000n; // 1 gwei
const maxFeePerGas = 20_000_000_000n; // 20 gwei

// 6. 通过 EntryPoint.getUserOpHash() 签名
const normalizedPk = PRIVATE_KEY.startsWith('0x') ? PRIVATE_KEY : `0x${PRIVATE_KEY}`;
const eoa = privateKeyToAccount(normalizedPk);
const packedForHash = {
sender,
nonce,
initCode: needsDeploy ? initCode : '0x',
callData,
accountGasLimits:
'0x' +
verificationGasLimit.toString(16).padStart(32, '0') +
callGasLimit.toString(16).padStart(32, '0'),
preVerificationGas,
gasFees:
'0x' +
maxPriorityFeePerGas.toString(16).padStart(32, '0') +
maxFeePerGas.toString(16).padStart(32, '0'),
paymasterAndData: '0x',
signature: '0x',
};
const userOpHash = await publicClient.readContract({
address: ENTRY_POINT,
abi: entryPointDef.abi,
functionName: 'getUserOpHash',
args: [packedForHash],
});
const signature = await eoa.sign({ hash: userOpHash });

// 7. 发送
const hash = await bundlerRpc('eth_sendUserOperation', [
{
sender,
nonce: toHex(nonce),
callData,
callGasLimit: toHex(callGasLimit),
verificationGasLimit: toHex(verificationGasLimit),
preVerificationGas: toHex(preVerificationGas),
maxPriorityFeePerGas: toHex(maxPriorityFeePerGas),
maxFeePerGas: toHex(maxFeePerGas),
signature,
...(needsDeploy
? { factory: initCode.slice(0, 42), factoryData: '0x' + initCode.slice(42) }
: {}),
},
ENTRY_POINT,
]);
console.log('UserOp hash:', hash);

// 8. 等待回执
let receipt;
for (let i = 0; i < 30; i++) {
receipt = await bundlerRpc('eth_getUserOperationReceipt', [hash]);
if (receipt?.receipt?.transactionHash) break;
await new Promise((r) => setTimeout(r, 4000));
}
console.log('Tx hash:', receipt.receipt.transactionHash);
}

main().catch((err) => {
console.error('Failed:', err);
process.exit(1);
});

9. EIP-7702 授权字段​

EIP-7702 允许 EOA 在单笔交易中将其代码临时委托给智能合约。结合 ERC-4337 使用时,eip7702Auth 字段使 EOA 账户无需单独部署即可获得智能账户能力。

该字段为可选项,仅在 UserOperation 需要 EIP-7702 代码委托时填写。

字段结构:

"eip7702Auth": {
"chainId": "<CHAIN_ID_HEX>",
"address": "<DELEGATED_CONTRACT_ADDRESS>",
"nonce": "<EOA_NONCE_HEX>",
"yParity": "<0x0 或 0x1>",
"r": "<SIGNATURE_R_HEX>",
"s": "<SIGNATURE_S_HEX>"
}

当该字段存在时,Bundler 会将授权元组加入交易的 authorizationList,并以 EIP-7702 交易类型提交。UserOperation 的哈希计算也会纳入被委托的合约地址。


10. 智能账户部署​

首次使用时,智能账户尚未在链上存在。账户地址是反事实的——由工厂地址和所有者地址确定性推导而来。

要在首次操作的同一笔交易中部署新智能账户,请填写 factory 和 factoryData:

"factory": "<ACCOUNT_FACTORY_ADDRESS>",
"factoryData": "<ENCODED_CONSTRUCTOR_CALLDATA>"

账户部署完成后(nonce > 0),后续操作省略这两个字段或将其设为空。

如果 factory 非空,EntryPoint 会在验证阶段调用 factory.createAccount(factoryData)。部署后的地址必须与 sender 一致,否则操作将被拒绝。


11. RPC 方法参考​

核心方法​

方法说明
eth_supportedEntryPoints返回当前活跃的 EntryPoint 合约地址
eth_estimateUserOperationGas估算 UserOperation 的 Gas 限制
eth_sendUserOperation将已签名的 UserOperation 提交至内存池
eth_getUserOperationReceipt返回执行结果(待确认时返回 null)
eth_getUserOperationByHash根据哈希返回完整的 UserOperation 详情

数值格式​

请求和响应中的所有数值均使用带 0x 前缀的十六进制字符串。示例:gasLimit: 21000 → "0x5208"。


12. 错误代码参考​

代码名称原因解决方案
AA10Sender 已存在提供了 factory 但账户已部署省略 factory 和 factoryData
AA13Init code 失败账户创建期间工厂调用回滚检查工厂地址和 factoryData 编码
AA21未支付预付款智能账户在 EntryPoint 中存款不足提交前调用 entryPoint.depositTo()
AA23验证时回滚validateUserOp() 返回失败检查签名、nonce 和账户逻辑
AA25账户 nonce 无效nonce 不匹配重新查询 EntryPoint.getNonce() 并重建 UserOp
AA31Paymaster 存款不足Paymaster 在 EntryPoint 中余额不足补充 Paymaster 存款
AA33Paymaster 验证时回滚validatePaymasterUserOp() 失败检查 paymaster 数据和策略条件
AA40超出验证 Gas 上限verificationGasLimit 过低重新运行 eth_estimateUserOperationGas
AA51预付款低于实际 Gas 成本maxFeePerGas 低于当前网络水平重新查询 eth_maxPriorityFeePerGas 并重建 UserOp

13. 故障排查​

EntryPoint 地址不匹配 — 始终在运行时通过 eth_supportedEntryPoints 动态获取 EntryPoint 地址。硬编码在版本不同时会导致静默验证失败。

Gas 估算失败 — eth_estimateUserOperationGas 报错的常见原因:callData 编码无效、账户余额不足以通过预付款检查,或验证逻辑在模拟时回滚。

回执持续返回 null — 操作仍在内存池中。每 3–5 秒轮询一次。如果超过 2 分钟仍为 null,操作可能因费用过低被丢弃。请更新 Gas 值后重新提交。

Nonce 冲突 — 每个 sender 在内存池中每个 nonce 同时只能有一个待确认的 UserOperation。要替换卡住的操作,请以相同 nonce 重新提交,并将 maxPriorityFeePerGas 提高至少 10%。


14. 快速参考​

项目值
主网 Bundlerhttps://gatelayer-bundler.gatenode.cc
主网 Chain ID10088
测试网 Chain ID10087
AA 标准ERC-4337 v0.7
EntryPoint v0.8通过 eth_supportedEntryPoints 查询
Gas 代币GT
数值格式所有值均带 0x 前缀的十六进制
核心流程eth_supportedEntryPoints → 构建 → eth_estimateUserOperationGas → 签名 → eth_sendUserOperation → eth_getUserOperationReceipt

15. 参考资料​

  • Gate Layer 端点 & API:https://www.gatechain.io/docs/GateLayer/Development/EndpointsAPI/
  • Gate Layer Gas 与费用机制:https://www.gatechain.io/docs/GateLayer/Concepts/GasAndFees/
  • Gate Layer 区块浏览器:https://www.gatescan.org/gatelayer
  • ERC-4337 规范:https://eips.ethereum.org/EIPS/eip-4337
  • permissionless.js:https://docs.pimlico.io/permissionless

最后更新于2026/05/28