UNPKG

@web3auth/no-modal

Version:
171 lines (163 loc) 6.76 kB
import { getBase58Encoder, address } from '@solana/kit'; import { encodeBase64Url } from '@toruslabs/metadata-helpers'; import { EVM_METHOD_TYPES } from '@web3auth/ws-embed'; import { toClientEvmSigner, ExactEvmScheme } from '@x402/evm'; import { x402Client, wrapFetchWithPayment } from '@x402/fetch'; import { ExactSvmScheme, toClientSvmSigner } from '@x402/svm'; import { createWalletClient, custom } from 'viem'; import { PAYMENT_REQUIRED_HEADER } from './interfaces.js'; import { walletSignTransaction } from '../base/wallet/solana.js'; const EVM_CAIP2_WILDCARD = "eip155:*"; const SOLANA_CAIP2_WILDCARD = "solana:*"; /** * For 402 responses that carry v2 payment requirements in the JSON body instead * of the PAYMENT-REQUIRED header, reads the body, promotes the data into the * header, and reconstructs the response so downstream code can consume it normally. * * Returns the original response unchanged when the body is not JSON, is malformed, * or does not carry an x402Version \>= 2 payload. */ async function normalizePaymentRequiredResponse(response) { var _response$headers$get; const contentType = (_response$headers$get = response.headers.get("Content-Type")) !== null && _response$headers$get !== void 0 ? _response$headers$get : ""; let body; if (contentType.includes("application/json")) { body = await response.json(); } else { const data = await response.text(); body = JSON.parse(data); } try { if (body.x402Version && body.x402Version >= 2) { const newHeaders = new Headers(response.headers); const jsonData = JSON.stringify(body); newHeaders.set(PAYMENT_REQUIRED_HEADER, encodeBase64Url(jsonData)); return new Response(jsonData, { status: response.status, statusText: response.statusText, headers: newHeaders }); } } catch { // Malformed JSON - fall through and return response with the already-consumed body } return new Response(JSON.stringify(body), { status: response.status, statusText: response.statusText, headers: response.headers }); } async function getEvmAddress(provider) { var _ref; const accounts = await provider.request({ method: EVM_METHOD_TYPES.GET_ACCOUNTS }); return (_ref = accounts === null || accounts === void 0 ? void 0 : accounts[0]) !== null && _ref !== void 0 ? _ref : null; } function createProviderBackedEvmSigner(provider, address) { const walletClient = createWalletClient({ account: address, transport: custom(provider) }); return walletClient; } /** * Wraps a fetch function so that 402 responses whose v2 payment requirements * arrive in the response body (instead of the PAYMENT-REQUIRED header) are * normalised: the body JSON is base64-encoded and promoted into the * PAYMENT-REQUIRED header so that the \@x402/fetch client library can process it. * * The \@x402/fetch library's body fallback only accepts x402Version === 1; * this shim bridges the gap for servers that send v2 data in the body. * * @param baseFetch - The underlying fetch implementation to wrap * @returns A fetch-compatible function with the shim applied */ function withX402BodyShim(baseFetch) { return async (input, init) => { const response = await baseFetch(input, init); if (response.status === 402 && !response.headers.get(PAYMENT_REQUIRED_HEADER)) { return normalizePaymentRequiredResponse(response); } return response; }; } /** * Builds a `@x402/svm`-compatible `TransactionPartialSigner` from a web3auth * Solana provider. * * The web3auth `signTransaction` call returns the signer's Ed25519 signature * encoded in base58 (64 bytes). We decode it back to bytes and slot it into * the signature dictionary that `@solana/kit`'s partial-signing helpers expect. */ function createSvmSigner(wallet, walletAddress) { const base58Encoder = getBase58Encoder(); const signerAddress = address(walletAddress); const clientSvmSigner = toClientSvmSigner({ address: signerAddress, signTransactions: async transactions => { const signatureDictionaries = await Promise.all(transactions.map(async tx => { const signatureBase58 = await walletSignTransaction(wallet, tx); return { [signerAddress]: base58Encoder.encode(signatureBase58) }; })); return signatureDictionaries; } }); return clientSvmSigner; } /** * Creates a payment-aware fetch function for a connected Solana wallet. * Registers the exact SVM payment scheme and applies the body-shim so that * servers returning v2 payment requirements in the response body are handled * transparently. * * @param wallet - Connected Solana wallet (must have an account) * @param walletAddress - The wallet's public key as a base58 address string * @param rpcUrl - Optional custom Solana RPC URL (defaults to public cluster endpoints) * @returns A fetch-compatible function that handles x402 payment flows */ function createSolanaX402Fetch(wallet, walletAddress, rpcUrl) { if (!walletAddress) throw new Error("Wallet address is unavailable."); const svmSigner = createSvmSigner(wallet, walletAddress); const client = new x402Client().register(SOLANA_CAIP2_WILDCARD, new ExactSvmScheme(svmSigner, rpcUrl ? { rpcUrl } : undefined)); return wrapFetchWithPayment(withX402BodyShim(fetch), client); } /** * Creates a payment-aware fetch function for an EVM typed-data signer. * Registers the exact EVM payment scheme and applies the body-shim so that * servers returning v2 payment requirements in the response body are handled * transparently. * * @param signer - Minimal signer with an address and EIP-712 signTypedData implementation * @returns A fetch-compatible function that handles x402 payment flows */ function createEvmX402Fetch(walletClient) { var _walletClient$account; const address = (_walletClient$account = walletClient.account) === null || _walletClient$account === void 0 ? void 0 : _walletClient$account.address; if (!address) throw new Error("Wallet account is unavailable."); const evmSigner = toClientEvmSigner({ address, signTypedData: async params => { const { domain, types, primaryType, message } = params; return walletClient.signTypedData({ account: address, domain, types, primaryType, message }); } }); const client = new x402Client().register(EVM_CAIP2_WILDCARD, new ExactEvmScheme(evmSigner)); return wrapFetchWithPayment(withX402BodyShim(fetch), client); } export { EVM_CAIP2_WILDCARD, PAYMENT_REQUIRED_HEADER, SOLANA_CAIP2_WILDCARD, createEvmX402Fetch, createProviderBackedEvmSigner, createSolanaX402Fetch, getEvmAddress, withX402BodyShim };