<!--
Sitemap:
- [Welcome to Kakushi 隠し](/index): Kakushi is a private execution layer for institutions building on stablecoin rails.
- [What is Kakushi](/introduction/what-is-kakushi): Money is private.
- [Using Kakushi with AI](/introduction/using-kakushi-with-ai): Every page in these docs is available as plain markdown for use with language models.
- [Quickstart](/quickstart): This is the ten minute path.
- [Zones and the trust model](/concepts/zones-and-trust): A zone is a private blockchain only you can see inside, with a public chain's proofs underneath.
- [The portal](/concepts/the-portal): Money walks in as public USDC and becomes private the moment it crosses.
- [Accounts and custody](/concepts/accounts-and-custody): Your existing wallet address is already a Kakushi account. Nothing to deploy, nothing to enroll.
- [Bring your own address](/concepts/bring-your-own-address): A zone account is just an address, the one an auth key recovers to, with nothing deployed.
- [Virtual addresses](/concepts/virtual-addresses): Hand every customer their own address, the way a bank hands out virtual account numbers.
- [Private transfers](/concepts/private-transfers): Pay fifty thousand people and publish zero salaries.
- [Settlement and composability](/concepts/settlement-and-composability): Two institutions settle in real time without sharing a ledger or seeing each other's books.
- [Private deposits and withdrawals](/concepts/private-deposits-and-withdrawals): Soon, even the edges go dark.
- [Proofs and the verifier](/concepts/proofs-and-the-verifier): You cannot fake a balance, and you can prove you are solvent without showing a single customer.
- [Fees and gas](/concepts/fees-and-gas): Your users never hold ETH and never see gas. They pay in the dollars they are already sending.
- [Privacy and disclosure](/concepts/privacy-and-disclosure): The public sees nothing, you see everything, the regulator sees what the law entitles them to.
- [Zone policies](/concepts/zone-policies): Compliance is built into the zone. You configure your program; the substrate enforces it on every transfer.
- [Onboard a customer](/guides/onboard-a-customer): Two calls and a webhook, and your customer has a private on-chain account.
- [Accept deposits](/guides/accept-deposits): Anyone with funds on the host chain can pay into your zone, and it lands as a private balance for your user.
- [Make private transfers](/guides/private-transfers): One call moves money privately. One call pays a whole payroll.
- [Process withdrawals](/guides/withdrawals): Burn inside, release canonical USDC outside, in one call.
- [Settle between zones](/guides/settle-between-zones): Send money to another institution's zone like it is a withdrawal. It is interbank settlement.
- [Handle webhooks](/guides/webhooks): React to money moving. Do not poll for it.
- [Reconcile](/guides/reconcile): Two numbers that must always match. Assert it on a schedule.
- [Non-custodial integration](/guides/non-custodial-integration): The user signs on their device. You never hold the key, and you still cannot move their money.
- [Compliance and disclosure](/guides/compliance): You hold the whole record. Disclosure is an export, not a negotiation with the protocol.
- [SDK reference](/sdk-reference): The look-it-up layer.
- [Connect and EVM reference](/connect-and-evm-reference): The chain-level integration detail.
- [Run a zone](/run-a-zone): Most operators never run any infrastructure.
- [Protocol spec](/protocol-spec): The deep technical layer, for auditors and engineers integrating below the SDK.
- [Resources](/resources): See Key concepts for the working vocabulary, expanded throughout Core concepts.
-->

# Connect and EVM reference

The chain-level integration detail. The Kakushi SDK handles connection and authentication for you, so most integrations never touch this layer. It is here for when you want to talk to a zone directly with viem, ethers, or raw JSON-RPC.

**Networks and environments.**

| Environment | Host chain | Zone chainId | Host prefix |
| --- | --- | --- | --- |
| Sandbox | Base Sepolia | 8453000001 | 8453000000 |
| Production | Base | assigned per zone | 8453000000 |

The zone chainId is derived from the host chain (the host prefix) plus the zone's index. It is what binds a signed transaction to your specific zone and prevents a signature from being replayed on another zone or on the host chain.

**Connection details.** Use these when you need the RPC endpoint and chain metadata for a zone. The RPC URL and the host-side portal address are specific to your zone and are shown in your dashboard; the in-zone system addresses are fixed predeploys, the same in every zone.

| Property | Value |
| --- | --- |
| Network name | Kakushi Zone (sandbox) |
| Zone chainId | `8453000001` |
| Host chain | Base Sepolia |
| HTTP RPC | `https://rpc.sandbox.kakushi.xyz/zone/<zoneId>` |
| Portal address (host) | specific to your zone, shown in the dashboard |
| Inbox address (zone) | `0x1c00...0001` |
| Outbox address (zone) | `0x1c00...0002` |

**Connect with viem.** A zone is a standard EVM chain, so you connect to it the way you would any chain: define the chain, then create a client. Define the zone once with `defineChain`.

```ts
import { defineChain } from "viem";

export const kakushiSandbox = defineChain({
  id: 8453000001,
  name: "Kakushi Zone (sandbox)",
  nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
  rpcUrls: {
    default: { http: ["https://rpc.sandbox.kakushi.xyz/zone/<zoneId>"] },
  },
});
```

Unauthenticated reads of public chain metadata, like the current block, work with a plain public client.

```ts
import { createPublicClient, http } from "viem";

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

const blockNumber = await publicClient.getBlockNumber();
```

Anything account-scoped, like reading a balance, is access-controlled and requires the authentication token in an `X-Authorization-Token` header. viem's `http` transport takes `fetchOptions`, so you attach the header there.

```ts
const rpcUrl = "https://rpc.sandbox.kakushi.xyz/zone/<zoneId>";

const authedClient = createPublicClient({
  chain: kakushiSandbox,
  transport: http(rpcUrl, {
    fetchOptions: {
      headers: { "X-Authorization-Token": token },
    },
  }),
});

// access-controlled: only resolves for an account the token authorizes
import { erc20Abi } from "viem";

const balance = await authedClient.readContract({
  address: usdcRepresentation, // the in-zone representation of USDC
  abi: erc20Abi,
  functionName: "balanceOf",
  args: [accountAddress],
});
```

Without a token that authorizes the account, that read does not return another account's balance. That is the privacy boundary enforced at the transport, not just hidden in an explorer.

Writes are signed transactions submitted with `eth_sendRawTransaction`. You can send one directly, though in practice the SDK's `transfers.submit` and `withdrawals.submit` wrap this for you.

```ts
const hash = await authedClient.request({
  method: "eth_sendRawTransaction",
  params: [signedTx],
});
```

ethers and any other EVM library work the same way: point the provider at the zone RPC URL and attach the `X-Authorization-Token` header for account-scoped calls.

**Authenticated private RPC.** The zone RPC is not public. Account-scoped methods require an `X-Authorization-Token` header carrying a kzt token, a signature by the account you are acting as that the node recovers to identify you. The SDK builds and attaches it automatically, so you only deal with it when integrating directly. The same identity gates writes: `eth_sendRawTransaction` requires that the transaction's recovered `from` equals the token's address, so no token can move another account's funds. For the exact token format and the full list of scoped methods, see the Zone RPC specification. Reads are access-controlled at this layer, which is what keeps balances and history private rather than merely unlisted.

**EVM differences.** A zone is an EVM with privacy-preserving modifications. The differences that matter when you build:

* `balanceOf` and `allowance` are access-controlled. You cannot read an arbitrary account's balance, only your own or those you are authorized for.
* Transfers run at a fixed gas cost (100k), so transaction cost does not leak information about the work done.
* `CREATE` and `CREATE2` are disabled for users. Contract creation by zone users is not permitted. Token provisioning happens through a system registry path, not user deployment.

**Predeploys and precompiles.** Fixed addresses provide the zone's system functions, identical in every zone.

| Address | Name | Purpose |
| --- | --- | --- |
| `0x1c00...0000` | HostState | host-chain state mirror inside the zone |
| `0x1c00...0001` | ZoneInbox | sole minting authority |
| `0x1c00...0002` | ZoneOutbox | sole burning authority |
| `0x1c00...0003` | ZoneConfig | zone configuration |
| `0x1c00...0004` | HostStateReader | reads host-chain state slots |
| `0x1c00...0005` | ZoneTxContext | transaction context |
| `0x1c00...0100` | Chaum-Pedersen Verify | precompile for encrypted deposits |
| `0x1c00...0101` | AES-GCM Decrypt | precompile for encrypted deposits |

**RPC method reference.** Zone-specific methods extend the standard JSON-RPC surface. `zone_getDepositAddress` allocates a deposit (virtual) address for an account and `zone_getDepositAddresses` lists all of them; `zone_getVirtualAddressInfo` resolves a virtual address back to its account. The standard `eth_sendRawTransaction` is how signed transactions are submitted, and standard read methods like `eth_getBlockByNumber` work without authentication. Account-scoped methods require the token described above.

**Testnet faucet.** Sandbox runs on Base Sepolia. Fund a virtual address with testnet USDC from the Base Sepolia faucet to exercise the full deposit lifecycle.

<Callout variant="info">
  **No public explorer.** A zone does not expose a public block explorer for private activity, because that would defeat the point. Use authenticated RPC reads, or the operator dashboard, to inspect zone state.
</Callout>
