Skills agent-wallet-local-send
Send blockchain transactions with the viem package using either a seed phrase or private key signer. Use when the user asks to transfer native tokens, send onchain transactions, or sign-and-broadcast with viem.
install
source · Clone the upstream repo
git clone https://github.com/openclaw/skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/openclaw/skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/beardkoda/agent-wallets/local-wallet/send" ~/.claude/skills/clawdbot-skills-agent-wallet-local-send && rm -rf "$T"
manifest:
skills/beardkoda/agent-wallets/local-wallet/send/SKILL.mdsource content
Send Transaction With Viem
Runtime Requirements
- Runtime: Node.js 18+
- Required package:
viem - Required network input:
RPC_URL
Required Secrets / Inputs
orSEED_PHRASE
(exactly one signer source per send)PRIVATE_KEY
,RPC_URL
,chain
,toamountEth- Ask for explicit consent before reading env-based signer secrets
Required Inputs
- signer source:
orseedPhraseprivateKey rpcUrl
(for examplechain
,mainnet
, or custom chain object)sepolia
addressto
(human readable amount)amountEth
Workflow
- Identify signer input:
- seed phrase path: derive account with
mnemonicToAccount - private key path: derive account with
privateKeyToAccount
- seed phrase path: derive account with
- Create
andpublicClient
.walletClient - Validate
withto
.isAddress - Convert value with
.parseEther(amountEth) - Optionally run a preflight check:
- read sender balance
- estimate gas
- Require explicit send confirmation before broadcast:
- confirm chain, recipient, amount, and estimated fee
- If chain is mainnet, require a second explicit confirmation.
- Send transaction with
.walletClient.sendTransaction - Return tx hash, from/to addresses, amount, and chain summary.
Viem Example (Seed Phrase)
import { createPublicClient, createWalletClient, http, parseEther, isAddress } from 'viem' import { sepolia } from 'viem/chains' import { mnemonicToAccount } from 'viem/accounts' const account = mnemonicToAccount(process.env.SEED_PHRASE!) const publicClient = createPublicClient({ chain: sepolia, transport: http(process.env.RPC_URL!) }) const walletClient = createWalletClient({ account, chain: sepolia, transport: http(process.env.RPC_URL!) }) const to = '0xabc...' if (!isAddress(to)) throw new Error('Invalid recipient address') const hash = await walletClient.sendTransaction({ account, to, value: parseEther('0.001'), })
Viem Example (Private Key)
import { createPublicClient, createWalletClient, http, parseEther, isAddress } from 'viem' import { sepolia } from 'viem/chains' import { privateKeyToAccount } from 'viem/accounts' const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`) const publicClient = createPublicClient({ chain: sepolia, transport: http(process.env.RPC_URL!) }) const walletClient = createWalletClient({ account, chain: sepolia, transport: http(process.env.RPC_URL!) }) const to = '0xabc...' if (!isAddress(to)) throw new Error('Invalid recipient address') const hash = await walletClient.sendTransaction({ account, to, value: parseEther('0.001'), })
Guardrails
- Use
for human-to-wei conversion.parseEther - Validate addresses with
.isAddress - Never expose mnemonic or full private key in output.
- Ask for explicit confirmation before mainnet sends.
- Stop and report if funds are insufficient for value + gas.
- Default to read-only simulation if user has not approved broadcast.
Failure Handling
- Insufficient funds -> report required (amount + fee) vs available balance.
- Nonce too low/replacement error -> re-fetch pending nonce and retry once with user confirmation.
- RPC timeout/network error -> retry with backoff, then ask for alternate RPC if still failing.
- Chain mismatch (expected vs connected) -> stop and request chain confirmation before sending.
Standard Response Contract
:actionsend
: chain id/name usedchain
: sender wallet addressaddress
: transaction hash after broadcast, elsetxHashnull
:status
|success
|failedneeds_confirmation
: one clear follow-up actionnext_step