零 Gas 自主智能體:Base L2 上的帳戶抽象
The user wants a technical article draft in Indonesian (the instructions are in Indones...
方案構想在 Base L2 以 ERC-4337 帳戶抽象建構零 Gas 自主智能體,並由 Paymaster 贊助 Gas。內容列出 Base 主網 Chain ID 8453、EntryPoint v0.7,並建議以合約和函式白名單、支出上限及限時 session key 控制權限。若 Paymaster 驗證不嚴,可能成為開放水龍頭;簽署金鑰遭入侵則可能造成無上限資產耗損。
The user wants a technical article draft in Indonesian (the instructions are in Indonesian, but the title is in English). Let me think about this. The instructions are in Indonesian, but targeting AI engineers, Web3 developers, crypto builders on Dev.to or Paragraph.com. The title is in English. Hmm. Dev.to and Paragraph.com are English-heavy platforms. But the writing rules include Indonesian clichés to avoid ('dalam era digital', 'merupakan tonggak penting', 'tak dapat dipungkiri'), which suggests they want the article in Indonesian.
Wait — actually, the request is "Tuliskan draf artikel teknis mendalam" — write a draft in Indonesian? The anti-AI-slop rules list both English and Indonesian clichés. Given the target audience is AI engineers/Web3 devs and the platform is Dev.to/Paragraph, English would be more natural. But the instruction language is Indonesian.
Hmm, I think the safest interpretation: they're an Indonesian speaker writing for Dev.to/Paragraph, and they want the article itself... Probably in Indonesian given the prompt is Indonesian. But the title given is English: "Zero-Gas Autonomous Agents: Account Abstraction on Base L2".
Let me write in Indonesian, since the instructions are in Indonesian and list Indonesian clichés to avoid. Actually, hmm. Let me reconsider. If they wanted English they'd have asked in English. The cliché list includes Indonesian phrases, which only makes sense if the output is Indonesian. I'll write in Indonesian.
Actually — a hybrid is common on Dev.to by Indonesian devs: Indonesian prose with English technical terms. That's realistic and natural. I'll do that.
Now the technical content. Let me get the facts right.
ERC-4337 Account Abstraction on Base:
- EntryPoint contract: v0.6 at
0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789, v0.7 at0x0000000071727De22E5E9d8BAf0edAc6f37da032. - Base mainnet Chain ID 8453. Base Sepolia is 84532.
- Paymasters can sponsor gas — that's the "zero-gas" part.
- Base has very cheap gas (EIP-1559, OP Stack, after EIP-4844 blobs it's sub-cent). Base sequencer fee + L1 data fee.
- Base also has native support: Coinbase Smart Wallet, Coinbase Developer Platform (CDP) Paymaster, Base Paymaster.
- ERC-4337 v0.7 introduced PackedUserOperation, and EIP-7702 (Pectra) allows EOAs to delegate to smart contract code — Base supports EIP-7702 since... Base enabled EIP-7702 at some point post-Pectra (May 2025). Actually Base activated EIP-7702 in May 2025 (Base mainnet supported it). I should be careful; I'll mention it as a path.
Architecture for zero-gas autonomous agents:
- Agent has a smart account (ERC-4337) instead of EOA.
- Paymaster sponsors gas, with policy: only allowed target contracts, only allowed function selectors, rate limits, spend caps.
- Agent signs UserOperation with its own key (session key preferably).
- Bundler submits to EntryPoint.
- Validation: validateUserOp -> paymaster.validatePaymasterUserOp -> if valid, paymaster pays.
The "zero-gas" phrasing: the agent holds no ETH. Gas is paid in USDC or sponsored by a paymaster. Or the agent's treasury contract pays via a paymaster with a deposit.
Key risk: a gas-sponsoring paymaster is an open faucet if the validation is sloppy. Signing key compromise = infinite drain. Need: allowlist of targets, per-day spend cap, session key with expiry, and a kill switch.
Code: Let me write real Python using web3.py and eth-account. Signing a UserOperation v0.7 requires computing the userOpHash.
Actually for v0.7 the hash is:
keccak256(abi.encode(
keccak256(abi.encode(
sender,
nonce,
keccak256(paymasterAndData), // wait, v0.7 changed
...
)),
entryPoint,
chainId
))
Let me recall precisely. ERC-4337 v0.7 getUserOpHash:
function getUserOpHash(PackedUserOperation calldata userOp) public view returns (bytes32) {
return keccak256(abi.encode(userOp.hash(), address(this), block.chainid));
}
And in PackedUserOperationLib:
function hash(PackedUserOperation calldata userOp) internal pure returns (bytes32) {
return keccak256(abi.encode(
userOp.sender,
userOp.nonce,
keccak256(userOp.initCode),
keccak256(userOp.callData),
userOp.accountGasLimits,
userOp.preVerificationGas,
userOp.gasFees,
keccak256(userOp.paymasterAndData)
));
}
For v0.6:
keccak256(abi.encode(
sender, nonce, keccak256(initCode), keccak256(callData),
callGasLimit, verificationGasLimit, preVerificationGas,
maxFeePerGas, maxPriorityFeePerGas, keccak256(paymasterAndData)
))
I'll use v0.7 since that's current. But sign with EIP-712? No, personal_sign of the hash... Actually accounts use toEthSignedMessageHash(userOpHash) in SimpleAccount. So the signature is an EIP-191 personal signature over the userOpHash.
Let me write clean Python:
from eth_account import Account
from eth_abi import encode
from eth_utils import keccak, to_checksum_address
from web3 import Web3
ENTRYPOINT_V07 = "0x0000000071727De22E5E9d8BAf0edAc6f37da032"
BASE_CHAIN_ID = 8453
def pack_uop_v07(sender, nonce, init_code, call_data, account_gas_limits,
pre_verification_gas, gas_fees, paymaster_and_data):
inner = encode(
["address","uint256","bytes32","bytes32","bytes32","uint256","bytes32","bytes32"],
[sender, nonce, keccak(init_code), keccak(call_data),
account_gas_limits, pre_verification_gas, gas_fees,
keccak(paymaster_and_data)]
)
return keccak(inner)
Then:
python
def user_op_hash(uop, entrypoint=ENTRYPOINT_V07, chain_id=BASE_CHAIN_ID):
h = pack_uop_v07(**uop)
return keccak(encode(["bytes
來源:DEV Community · dev.to