EIP-7702
BotChain 主网和测试网支持 EIP-7702 type 4 交易。已有 EOA 可以签署授权,把自己的执行代码委托给一份已部署的账户实现,同时保留原 EOA 地址、余额和私钥控制权。
支持分为两条调用路径:
-
原生交易:通过链 RPC 发送包含
authorizationList的 type 4 交易。 -
UserOperation:暂不支持通过BOT Chain Bundler提交7702模式的UserOperation,可在自建Bundler实现
原生 type 4 交易
原生路径不经过 EntryPoint 和 Bundler。EOA 自己支付交易 Gas。
1. 安装依赖
npm i viem
2. 创建客户端
以下示例使用测试网:
import {
createPublicClient,
createWalletClient,
http,
} from "viem";
import { privateKeyToAccount } from "viem/accounts";
const botTestnet = {
id: 968,
name: "BotChain Testnet",
nativeCurrency: {
name: "BOT",
symbol: "BOT",
decimals: 18,
},
rpcUrls: {
default: {
http: ["https://rpc.bohr.life"],
},
},
} as const;
const eoa = privateKeyToAccount("0x...");
const publicClient = createPublicClient({
chain: botTestnet,
transport: http("https://rpc.bohr.life"),
});
const walletClient = createWalletClient({
account: eoa,
chain: botTestnet,
transport: http("https://rpc.bohr.life"),
});
生产环境不要在前端源码中保存私钥,应使用钱包连接器或受保护的签名服务。
3. 签署授权并设置委托
当 EOA 同时是授权签名者和 type 4 交易发送者时,必须设置 executor: "self",由 viem 正确处理交易 nonce 与授权 nonce 的关系。
const implementation = "0x..." as const;
const authorization = await walletClient.signAuthorization({
account: eoa,
contractAddress: implementation,
executor: "self",
});
const hash = await walletClient.sendTransaction({
account: eoa,
authorizationList: [authorization],
to: eoa.address,
data: "0x",
});
await publicClient.waitForTransactionReceipt({ hash });
sendTransaction 会构造并提交 EIP-7702 type 4 交易。
如果账户实现需要初始化,把初始化 calldata 放进同一笔交易:
import { encodeFunctionData } from "viem";
const initializeData = encodeFunctionData({
abi: accountAbi,
functionName: "initialize",
args: [/* 初始化参数 */],
});
const hash = await walletClient.sendTransaction({
account: eoa,
authorizationList: [authorization],
to: eoa.address,
data: initializeData,
});
4. 验证委托结果
const code = await publicClient.getCode({
address: eoa.address,
});
const expectedCode =
`0xef0100${implementation.slice(2).toLowerCase()}`;
if (code?.toLowerCase() !== expectedCode) {
throw new Error("EIP-7702 delegation was not applied");
}
5. 调用委托账户
委托生效后,调用地址仍然是 EOA,calldata 按账户实现的 ABI 编码。
import { encodeFunctionData } from "viem";
const callData = encodeFunctionData({
abi: accountAbi,
functionName: "execute",
args: [
target,
value,
targetCallData,
],
});
const hash = await walletClient.sendTransaction({
account: eoa,
to: eoa.address,
data: callData,
});
业务目标地址是 target,账户实现地址仍是之前授权的 implementation。