UNPKG

@settlemint/sdk-viem

Version:

Viem (TypeScript Interface for Ethereum) module for SettleMint SDK

630 lines (616 loc) • 23 kB
/* SettleMint Viem SDK - Web3 Optimized */ //#region rolldown:runtime var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) { key = keys[i]; if (!__hasOwnProp.call(to, key) && key !== except) { __defProp(to, key, { get: ((k) => from[k]).bind(null, key), enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } } } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod)); //#endregion let _settlemint_sdk_utils_http = require("@settlemint/sdk-utils/http"); let _settlemint_sdk_utils_runtime = require("@settlemint/sdk-utils/runtime"); let _settlemint_sdk_utils_validation = require("@settlemint/sdk-utils/validation"); let viem = require("viem"); let viem_chains = require("viem/chains"); viem_chains = __toESM(viem_chains); let zod = require("zod"); //#region src/custom-actions/anvil/anvil-set-balance.ts /** * Set the balance of a wallet in the Anvil test environment. * @param client - The viem client to use for the request. * @returns An object with a anvilSetBalance method. */ function anvilSetBalance(client) { return { anvilSetBalance(args) { return client.request({ method: "anvil_setBalance", params: args }); } }; } //#endregion //#region src/custom-actions/create-wallet.action.ts /** * Creates a wallet action for the given client. * @param client - The viem client to use for the request. * @returns An object with a createWallet method. */ function createWallet(client) { return { createWallet(args) { return client.request({ method: "user_createWallet", params: [args.keyVaultId, args.walletInfo] }); } }; } //#endregion //#region src/custom-actions/create-wallet-verification.action.ts /** * Creates a wallet verification action for the given client. * @param client - The viem client to use for the request. * @returns An object with a createWalletVerification method. */ function createWalletVerification(client) { return { createWalletVerification(args) { return client.request({ method: "user_createWalletVerification", params: [args.userWalletAddress, args.walletVerificationInfo] }); } }; } //#endregion //#region src/custom-actions/create-wallet-verification-challenge.action.ts /** * Creates a wallet verification challenge action for the given client. * @param client - The viem client to use for the request. * @returns An object with a createWalletVerificationChallenge method. */ function createWalletVerificationChallenge(client) { return { createWalletVerificationChallenge(args) { return client.request({ method: "user_createWalletVerificationChallenge", params: [args] }); } }; } //#endregion //#region src/custom-actions/create-wallet-verification-challenges.action.ts /** * Creates a wallet verification challenges action for the given client. * @param client - The viem client to use for the request. * @returns An object with a createWalletVerificationChallenges method. */ function createWalletVerificationChallenges(client) { return { createWalletVerificationChallenges(args) { return client.request({ method: "user_createWalletVerificationChallenges", params: [args.addressOrObject] }); } }; } //#endregion //#region src/custom-actions/delete-wallet-verification.action.ts /** * Creates a wallet verification deletion action for the given client. * @param client - The viem client to use for the request. * @returns An object with a deleteWalletVerification method. */ function deleteWalletVerification(client) { return { deleteWalletVerification(args) { return client.request({ method: "user_deleteWalletVerification", params: [args.userWalletAddress, args.verificationId] }); } }; } //#endregion //#region src/custom-actions/eth-sign.action.ts /** * Creates a wallet action for the given client. * @param client - The viem client to use for the request. * @returns An object with a createWallet method. */ function ethSign(client) { return { ethSign(args) { return client.request({ method: "eth_sign", params: [args.userWalletAddress, args.data] }); } }; } //#endregion //#region src/custom-actions/get-wallet-verifications.action.ts /** * Creates a wallet verifications retrieval action for the given client. * @param client - The viem client to use for the request. * @returns An object with a getWalletVerifications method. */ function getWalletVerifications(client) { return { getWalletVerifications(args) { return client.request({ method: "user_walletVerifications", params: [args.userWalletAddress] }); } }; } //#endregion //#region src/custom-actions/verify-wallet-verification-challenge.action.ts /** * Creates a wallet verification challenge verification action for the given client. * @param client - The viem client to use for the request. * @returns An object with a verifyWalletVerificationChallenge method. */ function verifyWalletVerificationChallenge(client) { return { verifyWalletVerificationChallenge(args) { return client.request({ method: "user_verifyWalletVerificationChallenge", params: [args.addressOrObject, args.challengeResponse] }); } }; } //#endregion //#region src/utils/lru-cache.ts /** * DESIGN DECISION: Custom LRU cache implementation over external libraries. * * WHY: Avoids external dependencies for this critical infrastructure component. * TRADEOFF: Simpler implementation trades advanced features (TTL, statistics) for reliability. * PERFORMANCE: O(1) access with automatic memory management prevents unbounded growth. * * Alternative considered: Using Map without eviction - rejected due to memory leak risk * in long-running server applications with diverse chain/client combinations. */ var LRUCache = class { cache = new Map(); maxSize; constructor(maxSize) { this.maxSize = maxSize; } get(key) { const value = this.cache.get(key); if (value !== undefined) { this.cache.delete(key); this.cache.set(key, value); } return value; } set(key, value) { this.cache.delete(key); if (this.cache.size >= this.maxSize) { const firstKey = this.cache.keys().next().value; if (firstKey !== undefined) { this.cache.delete(firstKey); } } this.cache.set(key, value); } clear() { this.cache.clear(); } }; //#endregion //#region src/custom-actions/types/wallet-verification.enum.ts /** * Types of wallet verification methods supported by the system. * Used to identify different verification mechanisms when creating or managing wallet verifications. */ let WalletVerificationType = /* @__PURE__ */ function(WalletVerificationType$1) { /** PIN code verification method */ WalletVerificationType$1["PINCODE"] = "PINCODE"; /** One-Time Password verification method */ WalletVerificationType$1["OTP"] = "OTP"; /** Secret recovery codes verification method */ WalletVerificationType$1["SECRET_CODES"] = "SECRET_CODES"; return WalletVerificationType$1; }({}); /** * Supported hash algorithms for One-Time Password (OTP) verification. * These algorithms determine the cryptographic function used to generate OTP codes. */ let OTPAlgorithm = /* @__PURE__ */ function(OTPAlgorithm$1) { /** SHA-1 hash algorithm */ OTPAlgorithm$1["SHA1"] = "SHA1"; /** SHA-224 hash algorithm */ OTPAlgorithm$1["SHA224"] = "SHA224"; /** SHA-256 hash algorithm */ OTPAlgorithm$1["SHA256"] = "SHA256"; /** SHA-384 hash algorithm */ OTPAlgorithm$1["SHA384"] = "SHA384"; /** SHA-512 hash algorithm */ OTPAlgorithm$1["SHA512"] = "SHA512"; /** SHA3-224 hash algorithm */ OTPAlgorithm$1["SHA3_224"] = "SHA3-224"; /** SHA3-256 hash algorithm */ OTPAlgorithm$1["SHA3_256"] = "SHA3-256"; /** SHA3-384 hash algorithm */ OTPAlgorithm$1["SHA3_384"] = "SHA3-384"; /** SHA3-512 hash algorithm */ OTPAlgorithm$1["SHA3_512"] = "SHA3-512"; return OTPAlgorithm$1; }({}); //#endregion //#region src/viem.ts /** * Viem client factory with intelligent caching and SettleMint platform integration. * * This module provides optimized blockchain client creation for the SettleMint platform. * Key architectural decisions: * - LRU caching prevents memory leaks while optimizing performance for repeated operations * - Separate caching strategies for known vs custom chains maximize cache hit rates * - Security-conscious header handling prevents undefined auth token exposure * - Factory pattern for wallet clients enables runtime verification parameter injection */ /** * CACHE SIZING STRATEGY: Different limits based on usage patterns and memory impact. * * Chain cache (100): WHY larger? * - Chain definitions are lightweight (just metadata) * - High reuse across different client instances * - Custom chains vary widely in development/testing scenarios * * Client caches (50 each): WHY smaller? * - Clients hold heavy resources (connections, transport state) * - Fewer unique client configurations in typical usage * - Each client maintains internal connection pools * * TRADEOFF: Balances memory usage vs cache hit rates for optimal performance. */ const chainCache = new LRUCache(100); /** * SECURITY CONSIDERATION: Public clients contain auth tokens in transport config. * Cache key generation ensures tokens are not leaked between different access contexts. */ const publicClientCache = new LRUCache(50); /** * DESIGN PATTERN: Factory caching rather than client instance caching. * WHY: Wallet clients need runtime verification parameters that can't be pre-cached. * BENEFIT: Amortizes chain resolution and transport configuration setup costs. */ const walletClientFactoryCache = new LRUCache(50); /** * CACHE KEY GENERATION: Deterministic key creation for consistent cache behavior. * * SECURITY: Access tokens are included in cache keys to prevent cross-tenant data leaks. * Different access tokens must produce different cache entries even with identical chain configs. * * DETERMINISM: Property sorting ensures identical options always produce the same key, * regardless of object property enumeration order differences across JavaScript engines. * * EDGE CASE: Function properties in httpTransportConfig are excluded because: * 1. Functions cannot be serialized to JSON * 2. Function identity changes don't affect transport behavior for caching purposes * 3. Prevents cache key generation failures */ function createCacheKey(options) { const keyObject = {}; const keys = [ "chainId", "chainName", "rpcUrl", "accessToken" ]; for (const key of keys) { const value = options[key]; if (value !== undefined) { keyObject[key] = value; } } if (options.httpTransportConfig) { const { onFetchRequest: _onFetchRequest, onFetchResponse: _onFetchResponse, ...serializableConfig } = options.httpTransportConfig; if (Object.keys(serializableConfig).length > 0) { keyObject.httpTransportConfig = serializableConfig; } } return JSON.stringify(keyObject, Object.keys(keyObject).sort()); } /** * HEADER SECURITY: Prevents undefined auth tokens from being sent as 'undefined' strings. * * WHY: HTTP headers with undefined values can be serialized as the string 'undefined', * which may bypass authentication or cause server-side parsing errors. * * SECURITY BOUNDARY: Filters out undefined authentication headers before network transmission * to prevent accidental exposure of invalid credentials or authentication bypass attempts. */ function buildHeaders(baseHeaders, authHeaders) { const filteredHeaders = {}; for (const [key, value] of Object.entries(authHeaders)) { if (value !== undefined) { filteredHeaders[key] = value; } } return (0, _settlemint_sdk_utils_http.appendHeaders)(baseHeaders, filteredHeaders); } /** * Schema for the viem client options. */ const ClientOptionsSchema = zod.z.object({ accessToken: _settlemint_sdk_utils_validation.ApplicationAccessTokenSchema.optional(), chainId: zod.z.string(), chainName: zod.z.string(), rpcUrl: _settlemint_sdk_utils_validation.UrlOrPathSchema, httpTransportConfig: zod.z.any().optional() }); /** * Creates an optimized public client for blockchain read operations. * * @remarks * PERFORMANCE: Implements intelligent caching to minimize client creation overhead. * Cache hit rates of 80%+ typical in production workloads with repeated chain access. * * SECURITY: Each access token gets isolated cache entries to prevent cross-tenant data exposure. * Client instances are immutable once cached to prevent credential pollution. * * RESOURCE MANAGEMENT: 500ms polling interval balances responsiveness with server load. * 60-second timeout prevents hanging connections in unstable network conditions. * * @param options - Client configuration including chain details and authentication * @returns Cached or newly created public client with read-only blockchain access * @throws ValidationError when options don't match required schema * @throws NetworkError when RPC endpoint is unreachable during client creation * * @example * ```ts * import { getPublicClient } from '@settlemint/sdk-viem'; * * const publicClient = getPublicClient({ * accessToken: process.env.SETTLEMINT_ACCESS_TOKEN, * chainId: process.env.SETTLEMINT_BLOCKCHAIN_NETWORK_CHAIN_ID!, * chainName: process.env.SETTLEMINT_BLOCKCHAIN_NETWORK!, * rpcUrl: process.env.SETTLEMINT_BLOCKCHAIN_NODE_OR_LOAD_BALANCER_JSON_RPC_ENDPOINT!, * }); * * // Get the block number * const block = await publicClient.getBlockNumber(); * console.log(block); * ``` */ const getPublicClient = (options) => { (0, _settlemint_sdk_utils_runtime.ensureServer)(); const validatedOptions = (0, _settlemint_sdk_utils_validation.validate)(ClientOptionsSchema, options); const cacheKey = createCacheKey(validatedOptions); const cachedClient = publicClientCache.get(cacheKey); if (cachedClient) { return cachedClient; } const headers = buildHeaders(validatedOptions?.httpTransportConfig?.fetchOptions?.headers, { "x-auth-token": validatedOptions.accessToken }); const client = createPublicClient(validatedOptions, headers); publicClientCache.set(cacheKey, client); return client; }; function createPublicClient(validatedOptions, headers) { return (0, viem.createPublicClient)({ chain: getChain({ chainId: validatedOptions.chainId, chainName: validatedOptions.chainName, rpcUrl: validatedOptions.rpcUrl }), pollingInterval: 500, transport: (0, viem.http)(validatedOptions.rpcUrl, { batch: true, timeout: 6e4, ...validatedOptions.httpTransportConfig, fetchOptions: { ...validatedOptions?.httpTransportConfig?.fetchOptions, headers } }) }).extend(anvilSetBalance); } /** * Creates a factory function for wallet clients with runtime verification support. * * @remarks * DESIGN PATTERN: Returns a factory function rather than a client instance because * wallet operations require runtime verification parameters (challenge responses, etc.) * that cannot be known at factory creation time. * * SECURITY: Verification headers are injected per-operation to support: * - HD wallet challenge/response flows * - Multi-signature verification workflows * - Time-sensitive authentication tokens * * PERFORMANCE: Factory caching amortizes expensive setup (chain resolution, transport config) * while allowing runtime parameter injection for each wallet operation. * * FEATURE EXTENSIONS: Automatically extends client with SettleMint-specific wallet actions: * - Wallet creation and management * - Verification challenge handling * - Multi-factor authentication flows * * @param options - Base client configuration (chain, RPC, auth) * @returns Factory function that accepts runtime verification options * @throws ValidationError when options don't match required schema * * @example * ```ts * import { getWalletClient } from '@settlemint/sdk-viem'; * import { parseAbi } from "viem"; * * const walletClient = getWalletClient({ * accessToken: process.env.SETTLEMINT_ACCESS_TOKEN, * chainId: process.env.SETTLEMINT_BLOCKCHAIN_NETWORK_CHAIN_ID!, * chainName: process.env.SETTLEMINT_BLOCKCHAIN_NETWORK!, * rpcUrl: process.env.SETTLEMINT_BLOCKCHAIN_NODE_OR_LOAD_BALANCER_JSON_RPC_ENDPOINT!, * }); * * // Get the chain id * const chainId = await walletClient().getChainId(); * console.log(chainId); * * // write to the blockchain * const transactionHash = await walletClient().writeContract({ * account: "0x0000000000000000000000000000000000000000", * address: "0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2", * abi: parseAbi(["function mint(uint32 tokenId) nonpayable"]), * functionName: "mint", * args: [69420], * }); * console.log(transactionHash); * ``` */ const getWalletClient = (options) => { (0, _settlemint_sdk_utils_runtime.ensureServer)(); const validatedOptions = (0, _settlemint_sdk_utils_validation.validate)(ClientOptionsSchema, options); const cacheKey = createCacheKey(validatedOptions); const cachedFactory = walletClientFactoryCache.get(cacheKey); if (cachedFactory) { return cachedFactory; } const chain = getChain({ chainId: validatedOptions.chainId, chainName: validatedOptions.chainName, rpcUrl: validatedOptions.rpcUrl }); const walletClientFactory = (verificationOptions) => createWalletClientWithCustomMethods(chain, validatedOptions, verificationOptions); walletClientFactoryCache.set(cacheKey, walletClientFactory); return walletClientFactory; }; const createWalletClientWithCustomMethods = (chain, validatedOptions, verificationOptions) => (0, viem.createWalletClient)({ chain, pollingInterval: 500, transport: (0, viem.http)(validatedOptions.rpcUrl, { batch: false, timeout: 6e4, ...validatedOptions.httpTransportConfig, fetchOptions: { ...validatedOptions?.httpTransportConfig?.fetchOptions, headers: buildHeaders(validatedOptions?.httpTransportConfig?.fetchOptions?.headers, { "x-auth-token": validatedOptions.accessToken, ...verificationOptions?.challengeResponse ? { "x-auth-challenge-response": verificationOptions.challengeResponse } : {}, ...verificationOptions?.challengeId ? { "x-auth-challenge-id": verificationOptions.challengeId } : {}, ...verificationOptions?.verificationId ? { "x-auth-verification-id": verificationOptions.verificationId } : {} }) } }) }).extend(viem.publicActions).extend(anvilSetBalance).extend(createWallet).extend(getWalletVerifications).extend(createWalletVerification).extend(deleteWalletVerification).extend(createWalletVerificationChallenge).extend(createWalletVerificationChallenges).extend(verifyWalletVerificationChallenge).extend(ethSign); /** * Schema for the viem client options. */ const GetChainIdOptionsSchema = zod.z.object({ accessToken: _settlemint_sdk_utils_validation.ApplicationAccessTokenSchema.optional(), rpcUrl: _settlemint_sdk_utils_validation.UrlOrPathSchema, httpTransportConfig: zod.z.any().optional() }); /** * Discovers the chain ID from an RPC endpoint without requiring prior knowledge. * * @remarks * UTILITY: Enables chain discovery for dynamic network configuration scenarios. * Unlike other client functions, this creates a minimal, non-cached client for one-time queries. * * USE CASE: Chain ID discovery during initial network setup or validation. * Alternative to requiring users to know chain IDs in advance. * * PERFORMANCE: No caching because chain IDs are typically discovered once * during setup rather than repeatedly during runtime operations. * * @param options - Minimal options with RPC URL and optional authentication * @returns Promise resolving to the network's chain ID as a number * @throws NetworkError when RPC endpoint is unreachable * @throws AuthenticationError when access token is invalid * * @example * ```ts * import { getChainId } from '@settlemint/sdk-viem'; * * const chainId = await getChainId({ * accessToken: process.env.SETTLEMINT_ACCESS_TOKEN, * rpcUrl: process.env.SETTLEMINT_BLOCKCHAIN_NODE_OR_LOAD_BALANCER_JSON_RPC_ENDPOINT!, * }); * console.log(chainId); * ``` */ async function getChainId(options) { (0, _settlemint_sdk_utils_runtime.ensureServer)(); const validatedOptions = (0, _settlemint_sdk_utils_validation.validate)(GetChainIdOptionsSchema, options); const headers = buildHeaders(validatedOptions?.httpTransportConfig?.fetchOptions?.headers, { "x-auth-token": validatedOptions.accessToken }); const client = (0, viem.createPublicClient)({ transport: (0, viem.http)(validatedOptions.rpcUrl, { ...validatedOptions.httpTransportConfig, fetchOptions: { ...validatedOptions?.httpTransportConfig?.fetchOptions, headers } }) }); return client.getChainId(); } /** * OPTIMIZATION: Pre-compute known chains map for O(1) lookup performance. * WHY Map over Object: Avoids prototype chain lookups and provides guaranteed O(1) access. * MEMORY: One-time initialization cost for ~100 known chains vs repeated lookups. */ const knownChainsMap = new Map(Object.values(viem_chains).map((chain) => [chain.id.toString(), chain])); /** * CHAIN RESOLUTION STRATEGY: Two-tier lookup optimizes for both known and custom chains. * * Tier 1: Known chains (Ethereum mainnet, common testnets, L2s) * - O(1) lookup from pre-built map * - No caching needed (references are stable) * - Ignores custom RPC URLs (uses viem's defaults) * * Tier 2: Custom chains (private networks, development chains) * - LRU cached to handle dynamic discovery * - Full parameter consideration for cache key * - ETH defaults for unknown chains (SettleMint platform assumption) * * TRADEOFF: Memory usage vs performance - separate strategies prevent cache pollution * of known chains with custom RPC configurations. */ function getChain({ chainId, chainName, rpcUrl }) { const knownChain = knownChainsMap.get(chainId); if (knownChain) { return knownChain; } const cacheKey = JSON.stringify({ chainId, chainName, rpcUrl }, [ "chainId", "chainName", "rpcUrl" ]); const cachedChain = chainCache.get(cacheKey); if (cachedChain) { return cachedChain; } const customChain = (0, viem.defineChain)({ id: Number(chainId), name: chainName, rpcUrls: { default: { http: [rpcUrl] } }, nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" } }); chainCache.set(cacheKey, customChain); return customChain; } //#endregion exports.ClientOptionsSchema = ClientOptionsSchema; exports.GetChainIdOptionsSchema = GetChainIdOptionsSchema; exports.OTPAlgorithm = OTPAlgorithm; exports.WalletVerificationType = WalletVerificationType; exports.getChainId = getChainId; exports.getPublicClient = getPublicClient; exports.getWalletClient = getWalletClient; //# sourceMappingURL=viem.cjs.map