@settlemint/sdk-viem
Version:
Viem (TypeScript Interface for Ethereum) module for SettleMint SDK
630 lines (616 loc) • 23 kB
JavaScript
/* 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