### Initialize Sui Client and Get System State (TypeScript)
Source: https://context7.com/jovicheng/sui-zklogin-demo/llms.txt
Sets up the Sui blockchain client using '@mysten/sui.js/client' and retrieves the current network's system state, specifically the epoch. It uses a predefined fullnode URL for the Devnet environment. The function logs detailed system state information and returns the current epoch number, which can then be used for further calculations like determining `maxEpoch`.
```typescript
import { SuiClient } from "@mysten/sui.js/client";
const FULLNODE_URL = "https://fullnode.devnet.sui.io";
// Initialize Sui client
const suiClient = new SuiClient({ url: FULLNODE_URL });
// Get current blockchain state
async function getCurrentEpoch() {
const systemState = await suiClient.getLatestSuiSystemState();
console.log("System State:", {
epoch: systemState.epoch,
protocolVersion: systemState.protocolVersion,
systemStateVersion: systemState.systemStateVersion,
storageFundTotalObjectStorageRebates: systemState.storageFundTotalObjectStorageRebates,
storageFundNonRefundableBalance: systemState.storageFundNonRefundableBalance,
});
// Output:
// System State: {
// epoch: "245",
// protocolVersion: "48",
// systemStateVersion: "1",
// ...
// }
return systemState.epoch;
}
// Use epoch to calculate maxEpoch
const currentEpoch = await getCurrentEpoch();
const maxEpoch = Number(currentEpoch) + 10;
console.log(`Current Epoch: ${currentEpoch}, Max Epoch: ${maxEpoch}`);
// Output: "Current Epoch: 245, Max Epoch: 255"
```
--------------------------------
### Request Test Tokens from Sui Devnet Faucet using Axios
Source: https://context7.com/jovicheng/sui-zklogin-demo/llms.txt
Requests SUI test tokens from the Devnet faucet to fund a generated zkLogin address, enabling transaction execution. It uses `axios` to send a POST request to the faucet API. Includes error handling for rate limits and checks the balance using `@mysten/dapp-kit`.
```typescript
import axios from "axios";
const SUI_DEVNET_FAUCET = "https://faucet.devnet.sui.io/gas";
async function requestFaucet(zkLoginUserAddress: string) {
try {
const response = await axios.post(SUI_DEVNET_FAUCET, {
FixedAmountRequest: {
recipient: zkLoginUserAddress,
},
});
console.log("Faucet request successful:", response.data);
// Output: { task: "abc123", transferred_gas_objects: [...] }
// Wait a few seconds for transaction confirmation
// Balance will update automatically via useSuiClientQuery
} catch (error) {
console.error("Faucet request failed:", error);
// Common error: Rate limit exceeded
// Alternative: Request via Discord #devnet-faucet channel
}
}
// Check balance after faucet request
import { useSuiClientQuery } from "@mysten/dapp-kit";
import { MIST_PER_SUI } from "@mysten/sui.js/utils";
const { data: addressBalance } = useSuiClientQuery(
"getBalance",
{ owner: zkLoginUserAddress },
{ enabled: Boolean(zkLoginUserAddress), refetchInterval: 1500 }
);
if (addressBalance) {
const balanceInSui = BigNumber(addressBalance.totalBalance)
.div(MIST_PER_SUI.toString())
.toFixed(6);
console.log(`Balance: ${balanceInSui} SUI`);
// Output: "Balance: 1.000000 SUI"
}
```
--------------------------------
### Query Sui Address Balance with Real-time Updates (TypeScript)
Source: https://context7.com/jovicheng/sui-zklogin-demo/llms.txt
Monitors the balance of a zkLogin address in real-time using Sui's query hooks from '@mysten/dapp-kit'. It fetches balance data, converts it from MIST to SUI, and displays it. The query automatically refreshes every 1.5 seconds. It handles loading and error states gracefully.
```typescript
import { useSuiClientQuery } from "@mysten/dapp-kit";
import { MIST_PER_SUI } from "@mysten/sui.js/utils";
import { BigNumber } from "bignumber.js";
function BalanceDisplay({ zkLoginUserAddress }: { zkLoginUserAddress: string }) {
// Query balance with auto-refresh every 1.5 seconds
const { data: addressBalance, isLoading, error } = useSuiClientQuery(
"getBalance",
{
owner: zkLoginUserAddress,
},
{
enabled: Boolean(zkLoginUserAddress), // Only query when address exists
refetchInterval: 1500, // Refresh every 1500ms
}
);
if (isLoading) return
Loading balance...
;
if (error) return Error loading balance: {error.message}
;
if (addressBalance) {
// Convert from MIST (smallest unit) to SUI
const balanceInSui = BigNumber(addressBalance.totalBalance)
.div(MIST_PER_SUI.toString())
.toFixed(6);
return (
Address: {zkLoginUserAddress}
Balance: {balanceInSui} SUI
Total Balance (MIST): {addressBalance.totalBalance}
);
}
return No balance data
;
}
```
--------------------------------
### Assemble zkLogin Signature and Execute Transaction with TypeScript
Source: https://context7.com/jovicheng/sui-zklogin-demo/llms.txt
Combines all necessary components to construct a valid zkLogin signature and subsequently executes a transaction on the Sui blockchain. This involves generating an address seed, signing the transaction with an ephemeral key, and finally executing the transaction block. Error handling is included for common issues like insufficient balance or invalid signatures.
```typescript
import { TransactionBlock } from "@mysten/sui.js/transactions";
import { MIST_PER_SUI } from "@mysten/sui.js/utils";
import { genAddressSeed, getZkLoginSignature } from "@mysten/zklogin";
import { SerializedSignature } from "@mysten/sui.js/cryptography";
async function executeZkLoginTransaction() {
// Create a transaction to transfer 1 SUI
const txb = new TransactionBlock();
// Split 1 SUI from gas coin
const [coin] = txb.splitCoins(txb.gas, [MIST_PER_SUI * 1n]);
// Transfer to recipient address
txb.transferObjects(
[coin],
"0xfa0f8542f256e669694624aa3ee7bfbde5af54641646a3a05924cf9e329a8a36"
);
// Set sender as zkLogin address
txb.setSender(zkLoginUserAddress);
// Sign transaction with ephemeral key pair
const { bytes, signature: userSignature } = await txb.sign({
client: suiClient,
signer: ephemeralKeyPair, // Must be same key pair used in ZK proof request
});
// Generate address seed from JWT claims and salt
const addressSeed: string = genAddressSeed(
BigInt(userSalt),
"sub", // Key claim name
decodedJwt.sub, // User's subject ID
decodedJwt.aud as string // Application's client ID
).toString();
console.log("Address Seed:", addressSeed);
// Assemble final zkLogin signature
const zkLoginSignature: SerializedSignature = getZkLoginSignature({
inputs: {
...partialZkLoginSignature, // ZK proof from prover service
addressSeed, // Derived address seed
},
maxEpoch,
userSignature, // Ephemeral key signature
});
console.log("zkLogin Signature:", zkLoginSignature);
// Execute transaction on Sui blockchain
const executeRes = await suiClient.executeTransactionBlock({
transactionBlock: bytes,
signature: zkLoginSignature,
});
console.log("Transaction executed successfully!");
console.log("Digest:", executeRes.digest);
console.log("Explorer:", `https://suiexplorer.com/txblock/${executeRes.digest}?network=devnet`);
// Output:
// Transaction executed successfully!
// Digest: "8x7Y6z5W4v3U2t1S0r9Q8p7O6n5M4l3K2j1H0g9F8e7D6c5B4a3"
// Explorer: "https://suiexplorer.com/txblock/8x7Y6z.../network=devnet"
return executeRes;
}
// Execute with error handling
try {
const result = await executeZkLoginTransaction();
console.log("Success:", result);
} catch (error) {
console.error("Transaction failed:", error);
// Common errors:
// - Insufficient balance
// - Expired ephemeral key (maxEpoch exceeded)
// - Invalid signature
// - Network issues
}
```
--------------------------------
### Fetch Zero-Knowledge Proof with TypeScript
Source: https://context7.com/jovicheng/sui-zklogin-demo/llms.txt
Requests a zero-knowledge proof from Mysten Labs' proving service. This is crucial for verifying JWT ownership without revealing sensitive credentials. It requires the JWT, ephemeral public key, maximum epoch, randomness, user salt, and the key claim name as input. The output is a partial zkLogin signature.
```typescript
import axios from "axios";
import { getExtendedEphemeralPublicKey } from "@mysten/zklogin";
const SUI_PROVER_DEV_ENDPOINT = "https://prover-dev.mystenlabs.com/v1";
// First, get the extended ephemeral public key
const extendedEphemeralPublicKey = getExtendedEphemeralPublicKey(
ephemeralKeyPair.getPublicKey()
);
console.log("Extended Public Key:", extendedEphemeralPublicKey);
// Output: "AQNJ8K3L2M1P4R7T0W9Y5X6C8V1B2N4M7G3F9..."
// Request ZK proof from Mysten Labs prover service
const zkProofResult = await axios.post(
SUI_PROVER_DEV_ENDPOINT,
{
jwt: idToken, // Full JWT from Google
extendedEphemeralPublicKey: extendedEphemeralPublicKey,
maxEpoch: maxEpoch, // Key validity period
jwtRandomness: randomness, // Randomness used in nonce
salt: userSalt, // User's salt value
keyClaimName: "sub", // JWT claim to use (typically "sub")
},
{
headers: {
"Content-Type": "application/json",
},
}
);
const partialZkLoginSignature = zkProofResult.data;
console.log("ZK Proof received:", JSON.stringify(partialZkLoginSignature, null, 2));
// Output:
// {
// "proofPoints": {
// "a": ["...", "..."],
// "b": [["...", "..."], ["...", "..."]],
// "c": ["...", "..."]
// },
// "issBase64Details": { ... },
// "headerBase64": "..."
// }
```
--------------------------------
### Redirect to Google OAuth Login - TypeScript
Source: https://context7.com/jovicheng/sui-zklogin-demo/llms.txt
Constructs the OAuth2 URL with the generated nonce and redirects the user to Google's authentication page for login. It specifies the client ID, redirect URI, response type (id_token), and scope (openid) to facilitate the OAuth flow.
```typescript
const CLIENT_ID = "573120070871-0k7ga6ns79ie0jpg1ei6ip5vje2ostt6.apps.googleusercontent.com";
const REDIRECT_URI = "https://sui-zklogin.vercel.app/";
// Build OAuth URL with required parameters
const params = new URLSearchParams({
client_id: CLIENT_ID,
redirect_uri: REDIRECT_URI,
response_type: "id_token", // Request JWT as id_token
scope: "openid", // OpenID Connect scope
nonce: nonce, // Previously generated nonce
});
const loginURL = `https://accounts.google.com/o/oauth2/v2/auth?${params}`;
window.location.replace(loginURL);
// After successful authentication, Google redirects back with JWT:
// https://sui-zklogin.vercel.app/#id_token=eyJhbGciOiJSUzI1NiIsImtpZCI6...
```
--------------------------------
### Generate User Salt with @mysten/zklogin
Source: https://context7.com/jovicheng/sui-zklogin-demo/llms.txt
Creates a unique and persistent salt value for each user, ensuring deterministic address derivation across sessions. This salt is stored in `localStorage` for client-side persistence. The `generateRandomness` function from `@mysten/zklogin` is used.
```typescript
import { generateRandomness } from "@mysten/zklogin";
// Generate user salt (stores in localStorage for persistence)
const userSalt = generateRandomness();
window.localStorage.setItem("demo_user_salt_key_pair", userSalt);
console.log("User Salt:", userSalt);
// Output: "128318743981273498123749812374981273498"
// Retrieve salt in future sessions
const retrievedSalt = window.localStorage.getItem("demo_user_salt_key_pair");
// IMPORTANT: The same JWT (Google account) + same salt = same Sui address
// Different salt = different address, even with same Google account
// Losing the salt means losing access to the previously generated address
// Salt storage options:
// 1. User responsibility: Send to user's email
// 2. Client-side: Store in browser localStorage (as shown)
// 3. Backend database: Map UID to salt for enterprise applications
```
--------------------------------
### Generate User Sui Address with @mysten/zklogin
Source: https://context7.com/jovicheng/sui-zklogin-demo/llms.txt
Derives a deterministic Sui blockchain address using the decoded JWT claims and the user's unique salt. This function, `jwtToAddress` from `@mysten/zklogin`, ensures that the same inputs always produce the same address, enabling account recovery without private key management.
```typescript
import { jwtToAddress } from "@mysten/zklogin";
// Generate zkLogin Sui address from JWT and salt
const zkLoginUserAddress = jwtToAddress(idToken, userSalt);
console.log("zkLogin Sui Address:", zkLoginUserAddress);
// Output: "0x1a2b3c4d5e6f7890abcdef1234567890abcdef1234567890abcdef1234567890"
// Address is deterministically derived from:
// - JWT.sub (subject): User's unique ID from OAuth provider
// - JWT.iss (issuer): OAuth provider URL
// - JWT.aud (audience): Your application's client ID
// - userSalt: Your application's salt value
// The same inputs ALWAYS produce the same address
// This enables account recovery without private key storage
```
--------------------------------
### Generate Nonce for OAuth Authentication - TypeScript
Source: https://context7.com/jovicheng/sui-zklogin-demo/llms.txt
Generates a cryptographic nonce that links the OAuth JWT with the ephemeral key pair. This nonce is essential for verifying zero-knowledge proofs. It calculates the maximum epoch for key validity and generates randomness before creating the nonce.
```typescript
import { generateRandomness, generateNonce } from "@mysten/zklogin";
import { SuiClient } from "@mysten/sui.js/client";
const suiClient = new SuiClient({ url: "https://fullnode.devnet.sui.io" });
// Get current epoch and calculate maxEpoch (key validity period)
const { epoch } = await suiClient.getLatestSuiSystemState();
const currentEpoch = Number(epoch);
const maxEpoch = currentEpoch + 10; // Valid for 10 epochs (~10 days)
// Generate randomness for nonce
const randomness = generateRandomness();
window.sessionStorage.setItem("demo_randomness_key_pair", randomness);
// Generate nonce using ephemeralKeyPair, maxEpoch, and randomness
const nonce = generateNonce(
ephemeralKeyPair.getPublicKey(),
maxEpoch,
randomness
);
console.log("Generated nonce:", nonce);
```
--------------------------------
### Decode JWT Token with jwt-decode
Source: https://context7.com/jovicheng/sui-zklogin-demo/llms.txt
Parses and validates a JWT token received from an OAuth provider (e.g., Google). It extracts user claims such as issuer, audience, and subject, which are essential for generating a deterministic Sui address. Dependencies include `jwt-decode` and `query-string`.
```typescript
import { JwtPayload, jwtDecode } from "jwt-decode";
import queryString from "query-string";
// Parse OAuth callback URL
const parsed = queryString.parse(window.location.hash);
const idToken = parsed.id_token as string;
// Decode JWT to get payload
const decodedJwt = jwtDecode(idToken) as JwtPayload;
console.log("JWT Payload:", JSON.stringify(decodedJwt, null, 2));
// Example output:
// {
// "iss": "https://accounts.google.com",
// "aud": "573120070871-0k7ga6ns79ie0jpg1ei6ip5vje2ostt6.apps.googleusercontent.com",
// "sub": "106294929772244112345", // Unique user identifier
// "email": "user@example.com",
// "nonce": "hNj9q8KZe3L2m1P4r7T0w9Y5x6C8v1B2n4M7g3F9k2J5h8L1",
// "nbf": 1698765432,
// "iat": 1698765432,
// "exp": 1698769032,
// "jti": "abc123def456"
// }
// Key fields for zkLogin:
// - iss: OAuth provider (issuer)
// - aud: Your application's client ID (audience)
// - sub: User's unique identifier (subject)
// - nonce: Must match the generated nonce
```
--------------------------------
### Reset Local Authentication State (TypeScript)
Source: https://context7.com/jovicheng/sui-zklogin-demo/llms.txt
Clears all stored authentication data from both sessionStorage and localStorage, and resets various application state variables. This function effectively returns the application to its initial state. It includes a warning about the irretrievability of addresses after clearing localStorage due to the removal of the user salt.
```typescript
function resetLocalState() {
try {
// Clear all sessionStorage (ephemeral data)
window.sessionStorage.clear();
// Removes: ephemeralKeyPair, randomness
// Clear all localStorage (persistent data)
window.localStorage.clear();
// Removes: userSalt, maxEpoch
// WARNING: Clearing localStorage removes the user salt
// This makes previously generated addresses irretrievable!
// Reset application state
setCurrentEpoch("");
setNonce("");
setOauthParams(undefined);
setZkLoginUserAddress("");
setDecodedJwt(undefined);
setJwtString("");
setEphemeralKeyPair(undefined);
setUserSalt(undefined);
setZkProof(undefined);
setExtendedEphemeralPublicKey("");
setMaxEpoch(0);
setRandomness("");
setActiveStep(0);
setExecuteDigest("");
// Navigate to home page
navigate("/");
console.log("Local state reset successful");
} catch (error) {
console.error("Failed to reset local state:", error);
}
}
```
--------------------------------
### Generate Ephemeral Key Pair - TypeScript
Source: https://context7.com/jovicheng/sui-zklogin-demo/llms.txt
Generates a temporary Ed25519 key pair required for signing transaction blocks within the zkLogin flow. The generated key pair is stored in sessionStorage for subsequent retrieval and use. This function is crucial for establishing a temporary identity for the user during the authentication process.
```typescript
import { Ed25519Keypair } from "@mysten/sui.js/keypairs/ed25519";
// Generate a new ephemeral key pair
const ephemeralKeyPair = Ed25519Keypair.generate();
// Store in sessionStorage (cleared when browser closes)
window.sessionStorage.setItem(
"demo_ephemeral_key_pair",
ephemeralKeyPair.export().privateKey
);
// Retrieve the key pair later
const privateKey = window.sessionStorage.getItem("demo_ephemeral_key_pair");
if (privateKey) {
const restoredKeyPair = Ed25519Keypair.fromSecretKey(fromB64(privateKey));
console.log("Public Key:", restoredKeyPair.getPublicKey().toBase64());
}
```
=== COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.