sui-enoki

Use when adding social login (Google/Twitch/Facebook OAuth) or gasless/sponsored transactions to a SUI app via Mysten's Enoki service. Triggers on Enoki, zkLogin-as-a-service, sponsored transaction, gasless transaction, "sign in with Google" on Sui, social login, OAuth wallet, sponsor gas, pay gas for users, sponsored tx API, EnokiClient, registerEnokiWallets, or onboarding users without seed phrases. For self-hosted zkLogin (proving service you run yourself), use sui-zklogin instead. For passkey/WebAuthn auth, use sui-passkey.

Best use case

sui-enoki is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Use when adding social login (Google/Twitch/Facebook OAuth) or gasless/sponsored transactions to a SUI app via Mysten's Enoki service. Triggers on Enoki, zkLogin-as-a-service, sponsored transaction, gasless transaction, "sign in with Google" on Sui, social login, OAuth wallet, sponsor gas, pay gas for users, sponsored tx API, EnokiClient, registerEnokiWallets, or onboarding users without seed phrases. For self-hosted zkLogin (proving service you run yourself), use sui-zklogin instead. For passkey/WebAuthn auth, use sui-passkey.

Teams using sui-enoki should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/sui-enoki/SKILL.md --create-dirs "https://raw.githubusercontent.com/first-mover-tw/sui-dev-agents/main/skills/sui-enoki/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/sui-enoki/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How sui-enoki Compares

Feature / Agentsui-enokiStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Use when adding social login (Google/Twitch/Facebook OAuth) or gasless/sponsored transactions to a SUI app via Mysten's Enoki service. Triggers on Enoki, zkLogin-as-a-service, sponsored transaction, gasless transaction, "sign in with Google" on Sui, social login, OAuth wallet, sponsor gas, pay gas for users, sponsored tx API, EnokiClient, registerEnokiWallets, or onboarding users without seed phrases. For self-hosted zkLogin (proving service you run yourself), use sui-zklogin instead. For passkey/WebAuthn auth, use sui-passkey.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# SUI Enoki — zkLogin-as-a-Service + Sponsored Transactions

**Hosted OAuth sign-in (no seed phrase) + gasless transactions, via Mysten's Enoki backend.**

## SDK Versions

Targets: `@mysten/enoki` 1.0.8 (^1.0), `@mysten/sui` 2.17.0 (^2.16). Tested: 2026-06-03.

**Compatibility notes:** `@mysten/sui` is a peer dependency of `@mysten/enoki` (`workspace:^` → use your app's v2.x `@mysten/sui`). The React entry (`@mysten/enoki/react`) needs `react >= 17` as a peer; the core `EnokiClient`/`EnokiFlow` work without React. Do not mix `@mysten/sui@1.x` and `@2.x` — run `npm ls @mysten/sui` before adding. Enoki is NOT a `$extend()` client plugin; instantiate `new EnokiClient({ apiKey })` or use `registerEnokiWallets(...)` directly. Requires an Enoki API key + app config from the [Enoki Portal](https://portal.enoki.mystenlabs.com).

## What Enoki Does

1. **zkLogin** — users authenticate with an OAuth provider (Google, Twitch, Facebook, …); Enoki runs the proving service and derives a deterministic Sui address. No seed phrase, no key management for the user.
2. **Sponsored transactions** — your app (or backend) pays gas; users transact without holding SUI.
3. **dApp Kit wallet integration** — Enoki wallets register as standard wallets, so existing dApp-Kit `ConnectButton` / `useSignAndExecuteTransaction` flows just work.
4. **Subname management** — create/delete SuiNS subnames under a domain you own.

## Two credentials, two surfaces

| Credential | Where | Used for |
|---|---|---|
| **Public API key** | Frontend (browser) | zkLogin auth + wallet registration (`registerEnokiWallets`) |
| **Private API key** | Backend only — never ship to the client | Sponsored-transaction creation/execution, server-driven flows |

**Gas sponsorship is a backend operation.** `createSponsoredTransaction` / `executeSponsoredTransaction` should run on your server with the **private** key; the browser only builds the transaction *kind* and forwards it (plus the user's signature) to your backend. Don't put the private key — or the sponsorship call — in the browser. (The JWT travels in the `zklogin-jwt` header, the API key in `Authorization: Bearer` — distinct credentials.)

## Path A — dApp Kit wallet registration (recommended for React apps)

`registerEnokiWallets` is the modern, dApp-Kit-native path. Call it once at app setup, alongside your `SuiClient`.

```ts
// @check:skip
import { registerEnokiWallets } from '@mysten/enoki';
import { SuiGrpcClient } from '@mysten/sui/grpc';

const client = new SuiGrpcClient({ network: 'mainnet', baseUrl: 'https://fullnode.mainnet.sui.io:443' });

const { unregister } = registerEnokiWallets({
  apiKey: 'enoki_public_...',        // public key — safe for the browser
  client,                            // required: builds & executes txns
  network: 'mainnet',                // 'mainnet' | 'testnet' | 'devnet', default 'mainnet'
  providers: {
    // providers is an OBJECT keyed by provider, each with its OAuth clientId.
    google:   { clientId: 'GOOGLE_OAUTH_CLIENT_ID', redirectUrl: 'https://app.example.com/auth' },
    twitch:   { clientId: 'TWITCH_OAUTH_CLIENT_ID' },
    facebook: { clientId: 'FACEBOOK_OAUTH_CLIENT_ID' },
  },
});
```

After registration the Enoki wallets appear in dApp Kit's wallet list — use the normal `ConnectButton` and transaction hooks from `@mysten/dapp-kit-react`. See [sui-frontend](../sui-frontend/SKILL.md) for the provider/hooks setup.

> ⚠️ The package README shows `providers: ['google']` (an array) and `useEnokiFlow().login('google')`. Both are **illustrative and out of date** — the real `providers` type is an object (`Record<AuthProvider, { clientId, ... }>`) and `useEnokiFlow()` returns the `EnokiFlow` instance (which has **no** `login` method). Use the object form above.

## Path B — `EnokiClient` primitives (backend / non-dApp-Kit)

For server-side flows or apps not on dApp Kit, drive the hosted endpoints directly with `EnokiClient`. This is the supported low-level surface (see the EnokiClient API table below): `createZkLoginNonce` → redirect to the provider → on callback `getZkLogin({ jwt })` / `createZkLoginZkp` for the proof, and `createSponsoredTransaction` / `executeSponsoredTransaction` for gas sponsorship. You manage the ephemeral keypair yourself with `@mysten/sui/keypairs/ed25519`.

> ⚠️ **`EnokiFlow` and the `@mysten/enoki/react` hooks (`EnokiFlowProvider`, `useEnokiFlow`, `useZkLogin`, `useZkLoginSession`, `useAuthCallback`) are all marked `@deprecated` in `@mysten/enoki@1.0.8`** — their JSDoc says *"use `registerEnokiWallets` instead"*. Do **not** use them for new React integrations; use **Path A** (`registerEnokiWallets` + dApp Kit wallet hooks). They remain only as a legacy migration target.

## EnokiClient API (TS SDK method names)

> Method/param names below are the **TS SDK** (`@mysten/enoki`) surface. If you call the Enoki HTTP API directly, some field names differ — notably the sponsored-tx body field is `transactionBlockKindBytes`, not the SDK's `transactionKindBytes`.

`new EnokiClient({ apiKey, apiUrl?, additionalEpochs? })` — `apiUrl` defaults to `https://api.enoki.mystenlabs.com` (v1). `additionalEpochs` (nonce validity window) is constrained to `0 <= n <= 30`.

| Method | Purpose |
|---|---|
| `getApp()` | App config (allowed origins, providers, domains) |
| `getZkLogin({ jwt })` | `{ address, publicKey, salt }` for a JWT |
| `getZkLoginAddresses({ jwt })` | All addresses for a JWT across clientIds |
| `createZkLoginNonce({ network?, ephemeralPublicKey })` | Nonce + randomness + maxEpoch for the OAuth request |
| `createZkLoginZkp({ ... })` | The zkLogin proof |
| `createSponsoredTransaction({ network, transactionKindBytes, sender?, allowedAddresses?, allowedMoveCallTargets? })` | Returns `{ bytes, digest }` to sign |
| `executeSponsoredTransaction({ digest, signature })` | Submit the signed sponsored tx |
| `getSubnames` / `createSubname` / `deleteSubname` | SuiNS subname management |

## Sponsored transaction — the two-step flow

Sponsorship is **create → sign → execute**. The frontend builds a transaction **kind** (not a full transaction) and sends it to your backend; the **backend** (private key) creates the sponsored tx, returns the bytes for the user to sign, then executes the signed result. Below is the backend half.

```ts
// @check:skip
// --- BACKEND (private Enoki API key) ---
import { EnokiClient } from '@mysten/enoki';
import { SuiGrpcClient } from '@mysten/sui/grpc';
import { Transaction } from '@mysten/sui/transactions';
import { toBase64, fromBase64 } from '@mysten/sui/utils';

const client = new SuiGrpcClient({ network: 'mainnet', baseUrl: 'https://fullnode.mainnet.sui.io:443' });
const enoki = new EnokiClient({ apiKey: process.env.ENOKI_PRIVATE_KEY! }); // backend-only secret

const tx = new Transaction();
// ... add moveCalls; do NOT set gas — Enoki sponsors it ...

// build ONLY the transaction kind (no gas data, no sender-funded gas)
const kindBytes = await tx.build({ client, onlyTransactionKind: true });

const sponsored = await enoki.createSponsoredTransaction({
  network: 'mainnet',
  transactionKindBytes: toBase64(kindBytes),
  sender: userAddress,
  allowedMoveCallTargets: ['0xPKG::module::function'], // optional allowlist
});

// return `sponsored.bytes` to the client; the user signs with their zkLogin/Enoki keypair:
const { signature } = await keypair.signTransaction(fromBase64(sponsored.bytes));

const { digest } = await enoki.executeSponsoredTransaction({
  digest: sponsored.digest,
  signature,
});
```

## Common Mistakes

| Mistake | Reality |
|---|---|
| `providers: ['google']` (array) | Object form: `providers: { google: { clientId } }`. The array form in the README is stale. |
| Expecting `useEnokiFlow().login(...)` | `useEnokiFlow()` returns the `EnokiFlow` instance — drive auth via `createAuthorizationURL` / `handleAuthCallback`. There is **no `createEnokiHandlers` export** either. |
| Passing a full transaction to `createSponsoredTransaction` | Pass a transaction **kind** (`tx.build({ onlyTransactionKind: true })`), not a sender-funded transaction. |
| Setting gas on a sponsored tx | Leave gas unset — Enoki provides the gas payment. |
| Shipping the private API key to the browser | Public key for frontend (restricted by allowlists); private key backend-only. |
| `additionalEpochs > 30` | Clamped range is `0..30`; larger values are rejected. |
| Omitting `client` from `registerEnokiWallets` | A `SuiClient` (or `clients` + `getCurrentNetwork`) is required to build/execute. |
| Using Enoki for a fully self-hosted prover | Enoki *is* the hosted proving service. If you run your own salt/prover, use [sui-zklogin](../sui-zklogin/SKILL.md). |

## When NOT to use Enoki

- You need a self-custodied, self-hosted zkLogin stack (own salt service + prover) → **sui-zklogin**.
- You want device-bound passkey/WebAuthn auth with no OAuth provider → **sui-passkey**.
- You only need gas sponsorship without social login → a plain sponsored-transaction flow with your own gas station also works; Enoki just bundles both.

## References

- Enoki docs: https://docs.enoki.mystenlabs.com
- Enoki Portal (API keys, app config): https://portal.enoki.mystenlabs.com
- Source: `@mysten/enoki` (MystenLabs/ts-sdks `packages/enoki`)
- Related: `@mysten/enoki-connect` (`registerEnokiConnectWallets`, `EnokiConnectWallet`), *experimental* — lets a dApp connect to Enoki-powered wallets via the wallet standard. Register it through dApp Kit; see [sui-wallet](../sui-wallet/SKILL.md).

Related Skills

sui-zklogin

7
from first-mover-tw/sui-dev-agents

Use when implementing zkLogin on SUI — OAuth login (Google, Facebook, Apple, Twitch) with zero-knowledge proofs for privacy-preserving authentication. Triggers on "zkLogin", "social login on SUI", "Google login", "OAuth", "ephemeral keypair", "JWT proof", or any authentication flow that derives a SUI address from an OAuth provider. Also use when the user mentions "login without wallet extension".

sui-walrus

7
from first-mover-tw/sui-dev-agents

Use when storing or retrieving files using Walrus — SUI's decentralized blob storage. Triggers on "Walrus", "blob storage", "upload file to chain", "decentralized storage", "store NFT image", "IPFS alternative on SUI", "where to store NFT metadata", "host a site on-chain", or any off-chain data storage needs on SUI. Also use for Walrus Sites (decentralized web hosting), storing game assets, media files, or when the user asks "where do I put large files on SUI".

sui-wallet

7
from first-mover-tw/sui-dev-agents

Use when performing on-chain transactions (transfer, Move call, publish) through the agent's CLI wallet via MCP tools. Triggers on "transfer SUI", "call Move function", "publish package", "wallet status", "sign transaction", or any agent-driven on-chain operation. This is for headless/backend wallet operations — for browser wallet UI (React/Vue), use sui-frontend instead.

sui-tester

7
from first-mover-tw/sui-dev-agents

Use when writing Move tests, setting up test suites, running gas benchmarks, or planning test strategy for SUI contracts. Triggers on "write tests", "test this module", "#[test]", "test coverage", "gas benchmark", "property-based test", or any Move testing task. Use even for simple "how do I test this function" questions.

sui-suins

7
from first-mover-tw/sui-dev-agents

Use when integrating SuiNS (SUI Name Service) — resolving .sui names to addresses, reverse lookups, or registering names. Triggers on "SuiNS", ".sui name", "name resolution", "reverse lookup", "human-readable address", or any name service integration. Also use when the user wants to display user-friendly names instead of hex addresses.

sui-security-guard

7
from first-mover-tw/sui-dev-agents

Use when setting up security scanning, detecting leaked secrets/API keys, implementing pre-commit hooks, or auditing a Sui Move contract for security/architecture/quality issues. Triggers on "security scan", "detect secrets", "pre-commit hook", "security audit setup", "API key leaked", and on contract-level review requests like "audit this contract", "review access control", "is this Move safe", "check for vulnerabilities", "Move security review" — these load the SEC/DES/PAT/TST/QA/CFG finding registry in references/move-security-findings.md. For offensive/adversarial testing (attack vector discovery, writing exploits/PoCs), use sui-red-team instead. For Move style/idiom quality (non-security), use move-code-quality.

sui-seal

7
from first-mover-tw/sui-dev-agents

Use when implementing data encryption, access control, or secrets management on SUI using the Seal protocol. Triggers on threshold encryption, data privacy, token-gated content, encrypted storage, decryption policies, paywall, gated access, encrypted NFT metadata, private data sharing, or any scenario requiring on-chain access control for off-chain data. Also use when the user mentions Seal, pay-to-decrypt, "only NFT holders can see", or subscriber-only content on SUI.

sui-red-team

7
from first-mover-tw/sui-dev-agents

Use when performing adversarial security testing on SUI Move contracts — generating attack tests for access control bypass, integer overflow, object manipulation, economic exploits, reentrancy, and DoS vectors. Triggers on "red team", "attack test", "find vulnerabilities", "exploit", "pentest", "security test", or when the user wants to stress-test their contract's security. For defensive security setup (scanning, hooks, checklists), use sui-security-guard instead.

sui-passkey

7
from first-mover-tw/sui-dev-agents

Use when implementing WebAuthn passkeys or biometric authentication (Face ID, fingerprint, hardware keys) on SUI. Triggers on "passkey", "WebAuthn", "biometric login", "Face ID", "fingerprint auth", "FIDO2", or passwordless auth that uses device authenticators instead of seed phrases. Different from zkLogin (which uses OAuth providers).

sui-nautilus

7
from first-mover-tw/sui-dev-agents

Use when building verifiable off-chain computation, integrating external APIs with on-chain proof, or running trusted execution environments on SUI. Triggers on Nautilus, off-chain oracle, "verify API data on-chain", "connect external API to Move", "prove off-chain result", trusted compute, AWS Nitro Enclave, attestation, price feed, weather data on-chain, or any scenario requiring cryptographically verified external data. Also use when the user asks "how do I get real-world data into my SUI contract" or needs an oracle-like pattern.

sui-kiosk

7
from first-mover-tw/sui-dev-agents

Use when building NFT marketplaces, enforcing royalties, or managing transfer policies using SUI's Kiosk standard. Triggers on "Kiosk", "NFT marketplace", "transfer policy", "royalty enforcement", "list NFT for sale", "purchase rules", or any NFT commerce on SUI. Also use when the user asks about listing, delisting, or trading NFTs with enforced rules.

sui-install

7
from first-mover-tw/sui-dev-agents

Use when installing or updating the Sui CLI, managing CLI versions with suiup, or resolving environment/setup problems — "install sui", "update sui", "command not found", "sui not found", "client/server api version mismatch", build errors about "old dependencies", switching CLI versions per network, or installing toolchain components (Walrus, MVR, Move Analyzer, site-builder). Also use for first-time client setup, getting faucet tokens, recovering keys from a phrase, or "Cannot find gas coin for signer address". For deploying/upgrading packages use sui-deployer; for on-chain data queries use sui-ts-sdk.