TwinKey
transport /api/rpctoken TKT

Unmodified viem

Below is ordinary EVM client code — createPublicClient, createWalletClient, readContract, writeContract, waitForTransactionReceipt — pointed at a TwinKey JSON-RPC endpoint. The write becomes a native revive.call extrinsic; the receipt is resolved from the Substrate archive, because the EVM log index on this chain omits native-origin calls entirely.

Read this honestly: the key signing here is the deployment's demo account, not yours — that is what makes the demo runnable in a browser with no extension. To sign as yourself, connect your wallet in the app.

The code that runs

import { createPublicClient, createWalletClient, http, erc20Abi, formatUnits } from "viem";

// one line differs from any other EVM project: the transport URL
const transport = http("/api/rpc");
const publicClient = createPublicClient({ transport });
const walletClient = createWalletClient({ transport });

const [from] = await walletClient.getAddresses();
const before = await publicClient.readContract({
  address: TOKEN, abi: erc20Abi, functionName: "balanceOf", args: [from],
});

const hash = await walletClient.writeContract({
  address: TOKEN, abi: erc20Abi, functionName: "transfer",
  args: [TO, 10n ** 18n], account: from,
});
const receipt = await publicClient.waitForTransactionReceipt({ hash });
// receipt.logs[0] -> Transfer(from, to, value), decoded by viem, from the receipt

Run it live chain