UNPKG

@worldcoin/minikit-js

Version:

minikit-js is our SDK for building mini-apps.

363 lines (355 loc) 11.9 kB
"use strict"; 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 __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/wagmi-fallback-register.ts var wagmi_fallback_register_exports = {}; __export(wagmi_fallback_register_exports, { registerWagmiFallback: () => registerWagmiFallback }); module.exports = __toCommonJS(wagmi_fallback_register_exports); // src/global-keys.ts var WAGMI_CONFIG_KEY = "__minikit_wagmi_config__"; var WAGMI_INSTALL_HOOK_KEY = "__minikit_install_wagmi_fallback__"; // src/helpers/hex.ts var HEX_ADDRESS_REGEX = /^0x[0-9a-fA-F]{40}$/; var HEX_STRING_REGEX = /^0x[0-9a-fA-F]*$/; function isHexAddress(value) { return typeof value === "string" && HEX_ADDRESS_REGEX.test(value); } function isHexString(value) { return typeof value === "string" && HEX_STRING_REGEX.test(value); } // src/commands/fallback.ts var PartialExecutionError = class extends Error { constructor(message, submitted, cause) { super(message); this.name = "PartialExecutionError"; this.submitted = submitted; this.cause = cause; } }; // src/commands/fallback-adapter-registry.ts var FALLBACK_ADAPTER_KEY = "__minikit_fallback_adapter__"; function setFallbackAdapter(adapter) { globalThis[FALLBACK_ADAPTER_KEY] = adapter; } // src/commands/wagmi-fallback.ts var SIWE_NONCE_REGEX = /^[a-zA-Z0-9]{8,}$/; function setWagmiConfig(config) { globalThis[WAGMI_CONFIG_KEY] = config; registerWagmiFallbacks(); } globalThis[WAGMI_INSTALL_HOOK_KEY] = setWagmiConfig; function getWagmiConfig() { return globalThis[WAGMI_CONFIG_KEY]; } function registerWagmiFallbacks() { setFallbackAdapter({ walletAuth: wagmiWalletAuth, signMessage: wagmiSignMessage, signTypedData: wagmiSignTypedData, sendTransaction: wagmiSendTransaction }); } async function loadWagmiActions() { try { return await import("wagmi/actions"); } catch (error) { const wrappedError = new Error( 'Wagmi fallback requires the "wagmi" package. Install wagmi or provide a custom fallback.' ); wrappedError.cause = error; throw wrappedError; } } async function loadSiwe() { try { return await import("siwe"); } catch (error) { const wrappedError = new Error( 'Wagmi walletAuth fallback requires the "siwe" package. Install siwe or provide a custom fallback.' ); wrappedError.cause = error; throw wrappedError; } } async function checksumAddress(addr) { try { const { getAddress } = await import("viem"); return getAddress(addr); } catch { return addr; } } async function ensureConnected(config) { const { connect, getConnections } = await loadWagmiActions(); const isWorldApp = typeof window !== "undefined" && Boolean(window.WorldApp); const existingConnection = getConnections(config).find( (connection) => connection.accounts && connection.accounts.length > 0 && (isWorldApp || connection.connector?.id !== "worldApp") ); if (existingConnection && existingConnection.accounts) { return { address: await checksumAddress(existingConnection.accounts[0]), connector: existingConnection.connector }; } const connectors = config.connectors; if (!connectors || connectors.length === 0) { throw new Error("No Wagmi connectors configured"); } const candidateConnectors = isWorldApp ? connectors : connectors.filter( (connector) => connector.id !== "worldApp" ); if (!isWorldApp && candidateConnectors.length === 0) { throw new Error( "No web Wagmi connectors configured. Add a web connector (e.g. injected or walletConnect) after worldApp()." ); } const selectedConnector = candidateConnectors[0]; try { const result = await connect(config, { connector: selectedConnector }); if (result.accounts.length > 0) { const account = result.accounts[0]; const address = typeof account === "string" ? account : account.address; if (address) { return { address: await checksumAddress(address), connector: selectedConnector }; } } } catch (error) { const connectorId = selectedConnector.id ?? "unknown"; const wrappedError = new Error( `Failed to connect with connector "${connectorId}". Reorder connectors to change the default connector.` ); wrappedError.cause = error; throw wrappedError; } throw new Error("Failed to connect wallet"); } async function wagmiWalletAuth(params) { const config = getWagmiConfig(); if (!config) { throw new Error( "Wagmi config not available. Pass wagmiConfig to MiniKitProvider." ); } const { signMessage } = await loadWagmiActions(); const { SiweMessage } = await loadSiwe(); const { address, connector } = await ensureConnected(config); if (!SIWE_NONCE_REGEX.test(params.nonce)) { throw new Error( "Invalid nonce: must be alphanumeric and at least 8 characters (EIP-4361)" ); } const siweMessage = new SiweMessage({ domain: typeof window !== "undefined" ? window.location.host : "localhost", address, statement: params.statement, uri: typeof window !== "undefined" ? window.location.origin : "http://localhost", version: "1", chainId: 480, // World Chain nonce: params.nonce, expirationTime: params.expirationTime?.toISOString() }); const message = siweMessage.prepareMessage(); const signature = await signMessage(config, { connector, account: address, message }); return { address, message, signature }; } async function wagmiSignMessage(params) { const config = getWagmiConfig(); if (!config) { throw new Error( "Wagmi config not available. Pass wagmiConfig to MiniKitProvider." ); } const { signMessage } = await loadWagmiActions(); const { address, connector } = await ensureConnected(config); const signature = await signMessage(config, { connector, account: address, message: params.message }); return { status: "success", version: 1, signature, address }; } async function wagmiSignTypedData(params) { const config = getWagmiConfig(); if (!config) { throw new Error( "Wagmi config not available. Pass wagmiConfig to MiniKitProvider." ); } const { getChainId, signTypedData, switchChain } = await loadWagmiActions(); const { address, connector } = await ensureConnected(config); if (params.chainId !== void 0) { const currentChainId = await getChainId(config); if (currentChainId !== params.chainId) { await switchChain(config, { chainId: params.chainId, connector }); } } const signature = await signTypedData(config, { connector, account: address, types: params.types, primaryType: params.primaryType, domain: params.domain, message: params.message }); return { status: "success", version: 1, signature, address }; } function isChainMismatchError(error) { const message = error instanceof Error ? error.message : String(error); return message.includes("does not match the target chain"); } function validateBatch(transactions) { return transactions.map((tx, i) => { if (!isHexAddress(tx.address)) { throw new Error( `Transaction ${i + 1}: invalid address "${tx.address}". Must be a 0x-prefixed 20-byte hex string.` ); } if (tx.data !== void 0 && !isHexString(tx.data)) { throw new Error( `Transaction ${i + 1}: invalid data "${tx.data}". Must be a 0x-prefixed hex string.` ); } let value; if (tx.value !== void 0 && tx.value !== "") { try { value = BigInt(tx.value); } catch { throw new Error( `Transaction ${i + 1}: invalid value "${tx.value}". Must be a decimal or hex string parseable as BigInt.` ); } if (value < 0n) { throw new Error( `Transaction ${i + 1}: value cannot be negative (got "${tx.value}").` ); } } return { to: tx.address, ...tx.data !== void 0 ? { data: tx.data } : {}, ...value !== void 0 ? { value } : {} }; }); } async function wagmiSendTransaction(params) { if (params.transactions.length === 0) { throw new Error("At least one transaction is required"); } const normalizedTxs = validateBatch(params.transactions); const config = getWagmiConfig(); if (!config) { throw new Error( "Wagmi config not available. Pass wagmiConfig to MiniKitProvider." ); } const { getChainId, getWalletClient, sendTransaction, switchChain } = await loadWagmiActions(); const { address, connector } = await ensureConnected(config); const targetChainId = params.chainId ?? config.chains?.[0]?.id; const ensureTargetChain = async () => { if (targetChainId === void 0) return; const currentChainId = await getChainId(config); if (currentChainId !== targetChainId) { await switchChain(config, { chainId: targetChainId, connector }); } const walletClient = await getWalletClient(config); const providerChainId = walletClient ? await walletClient.getChainId() : await getChainId(config); if (providerChainId !== targetChainId) { throw new Error( `Wallet network mismatch: expected chain ${targetChainId}, got ${providerChainId}. Please switch networks in your wallet and retry.` ); } }; await ensureTargetChain(); const sendWithChainRetry = async (tx) => { const send = () => sendTransaction(config, { connector, account: address, chainId: targetChainId, to: tx.to, data: tx.data, value: tx.value }); try { return await send(); } catch (error) { if (targetChainId !== void 0 && isChainMismatchError(error)) { await ensureTargetChain(); return await send(); } throw error; } }; const submitted = []; for (let i = 0; i < normalizedTxs.length; i++) { try { submitted.push(await sendWithChainRetry(normalizedTxs[i])); } catch (error) { if (submitted.length > 0) { throw new PartialExecutionError( `Transaction ${i + 1}/${normalizedTxs.length} failed after ${submitted.length} tx(s) were already submitted. Resolve manually.`, submitted, error ); } throw error; } } return { transactionHash: submitted[submitted.length - 1] }; } // src/wagmi-fallback-register.ts function registerWagmiFallback(config) { setWagmiConfig(config); } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { registerWagmiFallback });