---
title: "Transfer assets from a Kernel smart account"
description: "A verified Base recovery method using local signing, Viem and a public RPC, with collateral checks."
category: "Account & security"
source: "https://help.tuyo.com/guides/recover-kernel-assets.html"
last_updated: "2026-10-09"
publisher: "Tuyo (https://tuyo.com)"
---

# Transfer assets from a Kernel smart account

This technical guide explains how an authorized signer can transfer tokens from a deployed Tuyo Kernel 3.2 smart account on Base using local signing and a public network connection. It is intended for readers comfortable running code and inspecting blockchain transactions.

For the signer and smart-account distinction, read [Your recovery phrase and smart-account address](https://help.tuyo.com/guides/understand-your-smart-account.html).

> **Tip: Get help from a coding agent**
>
> We strongly recommend using a coding agent to help inspect your account, prepare the code and simulate the transfer. Give it this guide and your public account details. Keep your recovery phrase out of the conversation and enter it privately on your device. Review the recipient, amount and fees yourself before signing; agents can make mistakes.

> **Danger: You are responsible for independent recovery**
>
> Self-custody gives you control of your funds, including the ability to lose them permanently. An incorrect address, contract call or exposed recovery phrase can cause irreversible loss. You use external tools at your own risk. Tuyo is not responsible for losses caused by your independent recovery actions and cannot undo blockchain transactions.

## Quick text guide

1. Locate the assets: check the smart account, collateral contracts and any Earn positions on the correct network.
2. Derive the signer privately from the mnemonic and verify its current authority on the smart account.
3. Check the deployed Kernel implementation and validator before choosing the direct-call route.
4. Fund the signer with native ETH on Base for gas; the tokens to transfer remain at the smart account.
5. Encode the token transfer inside the smart account's `execute` call, then simulate and estimate gas against real chain state.
6. Review the recipient, token, amount, network and fees; approve and submit the transaction once.
7. Confirm the receipt, token Transfer event and recipient balance increase.

## 1. Locate the funds first

An empty smart-account balance is not a complete account balance check. Funds may be held in separate collateral contracts or Earn positions. A direct token transfer from the main smart account cannot release assets held by another contract. Trace token transfers and check the receiving contract to locate the funds.

For collateral, verify the contract's depositor and release rules. For Earn, identify the vault shares and redemption requirements. [Read the collateral distinction](https://help.tuyo.com/guides/understand-your-smart-account.html#an-empty-wallet-address-may-not-mean-an-empty-account).

## 2. Tools and prerequisites

The tested tools are **Node.js**, **Viem 2.54.0** and the public Base JSON-RPC endpoint `https://mainnet.base.org`. This direct transaction route does not require a bundler or paymaster.

The owner mnemonic must remain private local input. Never paste it into an agent conversation or an online playground. Use a separate recipient wallet with private recovery material.

## 3. Verify authority and configuration

Derive the signer with `mnemonicToAccount(mnemonic)` from `viem/accounts`, using Ethereum path `m/44'/60'/0'/0/0` and no additional passphrase for the Tuyo implementation tested here.

Check the smart account's implementation slot and the ECDSA validator's owner record. The tested addresses were:

| Contract | Base address |
| --- | --- |
| Kernel 3.2 implementation | `0xD830D15D3dc0C269F3dBAa0F3e8626d33CFdaBe1` |
| ECDSA validator | `0x845ADb2C711129d4f3966735eD98a9F09fC4cE57` |

Kernel's direct execution modifier consults the root validator. This ECDSA validator implements a hook accepting the recorded owner as caller. That is why a normal signer transaction worked. Different roots, hooks or account versions can behave differently. A valid message signature alone is not enough: simulate the actual execution call.

### If the account is not deployed on the network

Check `getCode` at the smart-account address. If it returns no code, deploy the account before using the direct `execute` route below. Reconstruct its original Kernel version, factory, validator, owner and index, and verify that the predicted address exactly matches the address holding the funds.

With an ERC-4337 flow, the first user operation includes the deployment data. EntryPoint v0.7 represents this as `factory` and `factoryData`; some SDKs expose their concatenation as `initCode`. Use an SDK compatible with the account’s exact configuration to construct it. Alternatively, deploy through the matching factory first, then verify the deployed code and signing authority. A normal call to an address with no code does not execute the intended token transfer.

If the required Kernel implementation, factory or validator is missing from the network, contact ZeroDev about deployment support. Deploying those contracts yourself is an advanced alternative: the deployment addresses and bytecode must preserve the original account-address calculation. Deploying an arbitrary new Kernel account will not give it control of funds at the original address. This guide does not provide a tested deployment procedure for those networks.

## 4. Build the call

Set `token` to the asset’s verified contract address on Base, `destination` to your receiving wallet, and `amount` to the amount as a decimal string. Read `decimals` from that token contract; do not assume every token uses six decimals. The essential Viem encoding is:

```js
const transfer = encodeFunctionData({
  abi: erc20Abi,
  functionName: 'transfer',
  args: [destination, parseUnits(amount, decimals)],
})
const data = encodeFunctionData({
  abi: parseAbi(['function execute(bytes32,bytes) payable']),
  functionName: 'execute',
  args: [
    toHex(0, { size: 32 }), // single call, default execution
    encodePacked(['address', 'uint256', 'bytes'], [token, 0n, transfer]),
  ],
})
```

The outer transaction's recipient is the **smart account**. The inner call targets the **token contract**, whose transfer recipient is your destination wallet. This distinction matters: signing a token transfer directly from the signer would attempt to spend the signer's own token balance.

## 5. Simulate, fund and submit

Use `publicClient.call` from the signer to the smart account with the encoded data. Use real current state; a simulation with synthetic balances is not proof that a live transfer will work. Then use `estimateGas` and `estimateFeesPerGas`, allowing for Base's L1 data fee as well as execution gas.

Keep enough ETH at the signer for this direct route. Review the exact asset contract, units, destination and fee budget before `walletClient.sendTransaction`. A simulation can become stale if permissions, balances or other chain state change.

Repeat the balance and permission checks before sending. If broadcast or confirmation is uncertain, check the transaction hash and signer nonce before retrying; do not submit a duplicate automatically.

## 6. Confirm the result

Use `waitForTransactionReceipt`, check success, and inspect the token's Transfer event for the expected source, recipient and raw amount. Compare recipient balances as an additional check. Keep the transaction hash and block number as the evidence of completion.

## Sources

- [Kernel 3.2 source](https://github.com/zerodevapp/kernel/blob/v3.2/src/Kernel.sol): direct execution authorization.
- [ECDSA validator source](https://github.com/zerodevapp/kernel/blob/v3.2/src/validator/ECDSAValidator.sol): owner checks.
- [Viem mnemonic derivation](https://viem.sh/docs/accounts/local/mnemonicToAccount).
