@provex/extension-react 1.6.2 → 1.7.0-rc.20260522201545.020a3eb
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +6 -0
- package/dist/ZKTLSContext.cjs +4 -1
- package/dist/ZKTLSContext.cjs.map +1 -1
- package/dist/ZKTLSContext.js +2 -2
- package/dist/{chunk-MXHT5VC5.js → chunk-VDCCIS6C.js} +3 -3
- package/dist/{chunk-MXHT5VC5.js.map → chunk-VDCCIS6C.js.map} +1 -1
- package/dist/{chunk-DVOEKDW7.js → chunk-W2QUSBIS.js} +16 -3
- package/dist/chunk-W2QUSBIS.js.map +1 -0
- package/dist/index.cjs +14 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/useZKTLS.cjs +14 -1
- package/dist/useZKTLS.cjs.map +1 -1
- package/dist/useZKTLS.js +1 -1
- package/dist/useZKTLSContext.cjs.map +1 -1
- package/dist/useZKTLSContext.js +2 -2
- package/package.json +4 -2
- package/skills/extension-react-integration/SKILL.md +157 -0
- package/dist/chunk-DVOEKDW7.js.map +0 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Provex
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -256,3 +256,9 @@ This package requires users to have the ZKTLS browser extension installed. The e
|
|
|
256
256
|
- No private keys or sensitive data are exposed to the web application
|
|
257
257
|
- Zero-knowledge proofs ensure payment verification without revealing account details
|
|
258
258
|
- All proof generation happens locally in the user's browser
|
|
259
|
+
|
|
260
|
+
## License
|
|
261
|
+
|
|
262
|
+
MIT — see `LICENSE` in this package.
|
|
263
|
+
|
|
264
|
+
> Versions `1.6.3` and later are licensed under MIT. Versions published before `1.6.3` carry the license they were originally published under.
|
package/dist/ZKTLSContext.cjs
CHANGED
|
@@ -42,7 +42,10 @@ var useZKTLS = () => {
|
|
|
42
42
|
await time.sleep(1e3);
|
|
43
43
|
} while (!notaryRequest || !notaryRequest.status || notaryRequest.status === "pending");
|
|
44
44
|
if (notaryRequest.status === "failed" || notaryRequest.status === "expired" || notaryRequest.status === "cancelled" || notaryRequest.status === "error") {
|
|
45
|
-
|
|
45
|
+
console.error("[waitForProof] proof terminal state:", JSON.stringify(notaryRequest, null, 2));
|
|
46
|
+
const req = notaryRequest;
|
|
47
|
+
const detail = req.errorMessage ?? req.error ?? req.message ?? notaryRequest.status;
|
|
48
|
+
throw new Error(`Proof generation failed: ${detail}`);
|
|
46
49
|
}
|
|
47
50
|
return notaryRequest;
|
|
48
51
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useZKTLS.ts","../src/ZKTLSContext.tsx"],"names":["parseAbiParameter","useState","useEffect","useMemo","sleep","extensionPlatforms","providers","createContext","useContext"],"mappings":"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","file":"ZKTLSContext.cjs","sourcesContent":["/**\n * @fileoverview React hook and utilities for PeerAuth browser extension integration.\n *\n * The PeerAuth extension (formerly ZK-TLS) provides secure proof generation\n * for off-chain payment verification. This module provides:\n *\n * 1. Type definitions for extension API (window.peer)\n * 2. useZKTLS hook for React components\n * 3. Utility functions for transaction matching and proof encoding\n *\n * @remarks\n * The extension exposes `window.peer` (or deprecated `window.zktls`) for:\n * - Requesting connection (OAuth-like flow)\n * - Authenticating with payment providers\n * - Generating notarized proofs\n * - Fetching transaction metadata\n *\n * @see {@link ZKTLSContext} for the React context provider\n */\n\nimport { useEffect, useMemo, useState } from \"react\"\nimport { encodeAbiParameters, encodePacked, parseAbiParameter, parseUnits, type Hex } from \"viem\"\nimport { sleep } from \"@provex/utils/time\"\nimport type { IntentStruct } from \"@provex/utils/intent\"\nimport type { TokenInfo } from \"@provex/utils/tokens\"\nimport { extensionPlatforms, providers, subProviderConfigs, type ActionType, type PlatformKey, type ProviderKey, type SubProviderKey } from \"@provex/utils/payment\"\nimport { convertTokenInputToCurrency } from \"@provex/utils/conversionRates\"\n\ndeclare global {\n interface ZKTLS {\n requestConnection(): Promise<boolean>\n checkConnectionStatus(): Promise<Status>\n getVersion(): Promise<string>\n authenticate(inputs: AuthenticationInputs): Promise<void>\n generateProof(inputs: GenerateProofInputs): Promise<GenerateProofResponse>\n fetchProofById(proofId: string): Promise<ProofResponse>\n fetchProofs(): Promise<FetchProofsResponse>\n openSidebar(route: string): Promise<void>\n onMetadataMessage(fn: (data: MetadataMessageResponse) => void): () => void\n }\n interface Window {\n /** @deprecated Use window.peer instead */\n zktls: ZKTLS | undefined\n /** PeerAuth extension API (replaces window.zktls) */\n peer: ZKTLS | undefined\n }\n}\n\n/** the status of the PeerAuth extension */\nexport type Status = 'connected' | 'disconnected' | 'pending'\n\n/** the individual metadata message sent by the PeerAuth extension */\nexport interface MetadataMessage {\n amount: number\n /** Currency code (e.g., 'USD', 'EUR') */\n currency?: string\n /**\n * Date of the transaction.\n * Can be a string in YYYYMMDD format, a number (YYYYMMDD or timestamp), or Date object.\n * The actual type depends on the extension implementation.\n */\n date: string | number | Date\n hidden: boolean\n originalIndex: number\n paymentId: number\n recipient: string\n}\n\n/** the response from the PeerAuth extension when a metadata message is received */\nexport interface MetadataMessageResponse {\n expiresAt: number\n platform: ProviderKey\n requestId: string\n metadata: MetadataMessage[]\n}\n\n/** the response from the PeerAuth extension when fetching proofs */\nexport interface FetchProofsResponse {\n notaryRequests: NotaryRequest[]\n}\n\n/** the inputs for the generateProof function */\nexport type GenerateProofInputsAbstracted = {\n platform: PlatformKey\n provider: ProviderKey\n intentHash: Hex\n originalIndex: number\n}\n\n/** the inputs for the generateProof function */\nexport type GenerateProofInputs = {\n platform: ProviderKey\n originalIndex: number\n proofIndex?: number\n intentHash: string\n}\n\n/**\n * inputs for the generate proof function that requires the intent hash\n * as hex to ensure it can be converted to a bigint string accurately\n */\nexport type HexIntentGenerateProofInputs = Exclude<GenerateProofInputs, 'intentHash'> & { intentHash: Hex }\n\n/** the response from the PeerAuth extension when generating a proof */\nexport type GenerateProofResponse = {\n proofId: string\n platform: ProviderKey\n}\n\n/** the inputs for the authenticate function */\nexport type AuthenticationInputs = {\n actionType: ActionType\n platform: PlatformKey\n}\n\n/** the response from the PeerAuth extension when fetching a proof */\nexport interface Proof {\n claimInfo: ClaimInfo\n signedClaim: SignedClaim\n isAppclipProof: boolean\n status: string\n}\n\n/** the response from the PeerAuth extension when fetching a proof */\nexport interface NotarizedProof {\n claim: {\n context: string\n epoch: number\n identifier: Hex\n owner: Hex\n parameters: string\n provider: string\n timestampS: number\n },\n signatures: {\n attestorAddress: Hex\n claimSignature: Record<number, number>\n resultSignature: Record<number, number>\n },\n}\n\n/** the claim info for a proof */\nexport interface ClaimInfo {\n provider: string\n parameters: string\n context: string\n}\n\n/** the complete claim data for a proof */\nexport interface CompleteClaimData {\n identifier: Hex\n owner: Hex\n timestampS: number\n epoch: number\n}\n\n/** the signed claim for a proof */\nexport interface SignedClaim {\n claim: CompleteClaimData\n signatures: Hex[]\n}\n\n/** the reclaim proof for a proof */\nexport type ReclaimProof = {\n claimInfo: ClaimInfo\n signedClaim: SignedClaim\n isAppclipProof: boolean\n}\n\n/** the notary request for a proof */\nexport interface NotaryRequest {\n metadata: (string | number)[]\n actionType: ActionType\n id: string\n status: string\n timestamp: number\n proof: NotarizedProof\n}\n\n/** the response from the PeerAuth extension when fetching a proof */\nexport interface ProofResponse {\n notaryRequest: NotaryRequest\n}\n\nexport const extensionUrl = 'https://chromewebstore.google.com/detail/ijpgccednehjpeclfcllnjjcmiohdjih'\n\n/** convert a byte array to a hex string */\nexport const byteArrayToHexString = (byteArray: number[]): Hex => {\n return `0x${byteArray\n .map(byte => byte.toString(16).padStart(2, '0'))\n .join('')}`\n}\n\n/** parse a proof object from the PeerAuth extension */\nexport const parseExtensionProof = (proofObject: NotarizedProof) => {\n return {\n claimInfo: {\n provider: proofObject.claim.provider,\n parameters: proofObject.claim.parameters,\n context: proofObject.claim.context\n },\n signedClaim: {\n claim: {\n identifier: proofObject.claim.identifier as Hex,\n owner: proofObject.claim.owner as Hex,\n timestampS: proofObject.claim.timestampS,\n epoch: proofObject.claim.epoch\n },\n signatures: [byteArrayToHexString(Object.values(proofObject.signatures.claimSignature))]\n },\n isAppclipProof: false\n } as ReclaimProof\n}\n\n/** the abi encoding for a proof */\nexport const PROOF_ENCODING = parseAbiParameter(\"((string provider, string parameters, string context) claimInfo, ((bytes32 identifier, address owner, uint32 timestampS, uint32 epoch) claim, bytes[] signatures) signedClaim, bool isAppclipProof)\")\n\n/** encode a single proof as a bytes array */\nexport function encodeProofAsBytes(proof: ReclaimProof): Hex {\n return encodeAbiParameters([PROOF_ENCODING], [proof])\n}\n\n/** encode two proofs to be passed to the underlying sub-provider */\nexport const encodeTwoProofs = (proof1: ReclaimProof, proof2: ReclaimProof) => {\n return encodeAbiParameters([PROOF_ENCODING, PROOF_ENCODING], [proof1, proof2])\n}\n\n/** a high level function to encode a proof for a given provider and sub-provider */\nexport const encodeProof = ({ extensionProofs, subProvider, provider }: {\n extensionProofs: NotarizedProof[],\n subProvider: PlatformKey | null,\n provider: ProviderKey\n}) => {\n const reclaimProofs = extensionProofs.map((p) => parseExtensionProof(p))\n if (provider === 'zelle') {\n // move this to check the blockchain for the payment method\n const paymentMethod = subProviderConfigs![provider]![subProvider as SubProviderKey]!.paymentMethod\n const twoEncoded = reclaimProofs.length === 2\n ? encodeTwoProofs(reclaimProofs[0]!, reclaimProofs[1]!)\n : encodeProofAsBytes(reclaimProofs[0]!)\n // select between various possible sub-providers\n const withPaymentMethod = encodeProofWithPaymentMethod({\n paymentMethod,\n proof: twoEncoded,\n })\n return withPaymentMethod\n }\n const [reclaimProof] = reclaimProofs\n return encodeProofAsBytes(reclaimProof!)\n}\n\n/**\n * wrap a proof with a payment method and proof\n * this allows us to use a single verifier as an entry point for multiple underlying sub-providers\n */\nexport const encodeProofWithPaymentMethod = ({\n proof,\n paymentMethod\n}: {\n proof: Hex,\n paymentMethod: number\n}): Hex => {\n return encodePacked(['uint8', 'bytes'], [paymentMethod, proof])\n}\n\n/** the progress of a proof series */\nexport enum SeriesProgress {\n Generating,\n Polling,\n Complete,\n}\n\nexport type ProgressInfo = {\n progress: SeriesProgress\n total: number\n step: number | null\n id: string | null\n}\n\n/** the mutations for the generate proof series function */\nexport type GenerateProofSeriesMutations = {\n progress?: ({ progress, step, id }: ProgressInfo) => void\n setOwnerName?: (name: string) => void\n}\n\n/** React hook to interact with the PeerAuth extension */\nexport const useZKTLS = () => {\n const [isInitialized, setIsInitialized] = useState(false)\n useEffect(() => {\n const setup = () => {\n setIsInitialized(true)\n }\n const eventName = 'peer#initialized'\n if (typeof window.peer !== 'undefined') {\n // api is available\n setup()\n } else {\n window.addEventListener(eventName, setup)\n return () => {\n window.removeEventListener(eventName, setup)\n }\n }\n }, [])\n return useMemo(() => {\n /** fetch a proof by its id */\n const fetchProofById = async (proofId: string): Promise<NotaryRequest | null> => {\n const proof = await window.peer!.fetchProofById(proofId)\n if (proof && proof.notaryRequest) return proof.notaryRequest\n const proofs = await window.peer!.fetchProofs()\n const proofFromList = proofs.notaryRequests.find((p) => p.id === proofId)\n if (proofFromList) return proofFromList\n return null\n }\n /** wait for a proof to be generated */\n const waitForProof = async (proofId: string, onCurrent?: (notaryRequest: NotaryRequest | null) => void) => {\n let notaryRequest: NotaryRequest | null = null\n do {\n notaryRequest = await fetchProofById(proofId)\n onCurrent?.(notaryRequest)\n await sleep(1_000)\n } while (!notaryRequest || !notaryRequest.status || notaryRequest.status === 'pending')\n if (notaryRequest.status === 'failed' || notaryRequest.status === 'expired' || notaryRequest.status === 'cancelled' || notaryRequest.status === 'error') {\n throw new Error(`Proof generation failed: ${notaryRequest.status}`)\n }\n return notaryRequest\n }\n /** generate a proof */\n const generateProof = async (inputs: HexIntentGenerateProofInputs): Promise<GenerateProofResponse> => {\n return await window.peer!.generateProof({\n proofIndex: 0,\n ...inputs,\n intentHash: BigInt(inputs.intentHash).toString(),\n })\n }\n return {\n /** check if the PeerAuth extension is initialized */\n isInitialized,\n /** request a connection to the PeerAuth extension */\n requestConnection: async () => {\n if (!window.peer) return false\n return window.peer!.requestConnection()\n },\n /**\n * check the connection status of the PeerAuth extension\n * @returns the connection status\n */\n checkConnectionStatus: async () => {\n return await window.peer!.checkConnectionStatus()\n },\n /** get the version of the PeerAuth extension */\n getVersion: async () => {\n return await window.peer?.getVersion()\n },\n /** authenticate with the PeerAuth extension */\n authenticate: async (inputs: AuthenticationInputs) => {\n // Create promise first to avoid race condition where message arrives before resolver is assigned\n let resolve: (value: MetadataMessageResponse) => void\n const promise = new Promise<MetadataMessageResponse>((resolver) => {\n resolve = resolver\n })\n\n // Now set up the listener - resolve is guaranteed to be the real resolver\n const unsub = window.peer!.onMetadataMessage((data) => {\n if (`transfer_${data.platform}` === inputs.actionType) {\n resolve(data)\n }\n })\n\n await window.peer!.authenticate(inputs)\n\n return await promise.then((data) => {\n unsub()\n return data\n })\n },\n /** generate a proof */\n generateProof,\n /** wait for a proof to be generated */\n waitForProof,\n /** generate a proof series */\n generateProofSeries: async (\n inputs: GenerateProofInputsAbstracted,\n { progress: progressCallback }: GenerateProofSeriesMutations = {},\n ): Promise<NotaryRequest[]> => {\n const { platform, provider, intentHash, originalIndex } = inputs\n const args = {\n platform: provider,\n originalIndex,\n intentHash,\n } as const\n // Chase requires 2 proofs (account verification + transaction)\n // Platform is the bank name (e.g., 'chase') from extensionPlatform config\n const isChase = platform === extensionPlatforms.CHASE\n const isZelle = provider === providers.ZELLE\n const expectedTotal = isZelle && isChase ? 2 : 1\n progressCallback?.({ progress: SeriesProgress.Generating, step: 0, id: null, total: expectedTotal })\n const genProofA = await generateProof({ ...args, proofIndex: 0 })\n progressCallback?.({ progress: SeriesProgress.Polling, step: 0, id: genProofA.proofId, total: expectedTotal })\n const proofA = await waitForProof(genProofA.proofId)\n if (!isChase || !isZelle) {\n progressCallback?.({ progress: SeriesProgress.Complete, step: null, id: null, total: expectedTotal })\n return [proofA]\n }\n progressCallback?.({ progress: SeriesProgress.Generating, step: 1, id: null, total: expectedTotal })\n const genProofB = await generateProof({ ...args, proofIndex: 1 })\n progressCallback?.({ progress: SeriesProgress.Polling, step: 1, id: genProofB.proofId, total: expectedTotal })\n const proofB = await waitForProof(genProofB.proofId)\n progressCallback?.({ progress: SeriesProgress.Complete, step: null, id: null, total: expectedTotal })\n return [proofA, proofB]\n },\n /** subscribe to metadata messages */\n onMetadataMessage: (fn: (data: any) => void) => {\n return window.peer!.onMetadataMessage(fn)\n },\n /** fetch a proof by its id */\n fetchProofById,\n /** fetch generated proofs */\n fetchGeneratedProofs: async (genProofResponses: GenerateProofResponse[]) => {\n return await Promise.all(genProofResponses.map((r) => fetchProofById(r.proofId)))\n },\n /** fetch all proofs */\n fetchProofs: async () => {\n return await window.peer!.fetchProofs()\n },\n /** open the PeerAuth sidebar */\n openSidebar: async (route: string) => {\n return await window.peer!.openSidebar(route)\n },\n }\n }, [isInitialized])\n}\n\n/**\n * Find the metadata message that matches the intent by amount.\n * Returns the first (most recent) transaction in the metadata array that matches the expected amount.\n *\n * Simplified matching: just find transactions with the correct amount.\n * The user can manually select if multiple matches exist.\n */\nexport const findMetadataMessage = ({ metadata, intent, token, centIsInt = false }: {\n metadata: MetadataMessage[],\n intent: IntentStruct,\n token: TokenInfo,\n /** @deprecated No longer used - kept for API compatibility */\n recipient?: string,\n centIsInt?: boolean,\n}): MetadataMessage | null => {\n const currencyAmount = convertTokenInputToCurrency({\n token,\n amountOutInt: intent.amount,\n rate: intent.conversionRate,\n })\n /**\n * Normalize an amount from the extension into a bigint in token base units.\n *\n * The extension sends amounts in different formats per provider:\n * - Venmo: `\"- $1.00\"` (formatted dollar string)\n * - Others: `100` (integer cents) or `1.00` (decimal dollars)\n *\n * We detect the format by checking for currency symbols or decimal points\n * in the raw value. If present, the value is already in dollars and we\n * skip the centIsInt division.\n */\n const normalizeAmount = (amount: number | string): bigint => {\n const raw = String(amount)\n const isFormattedDollars = /[^0-9\\-]/.test(raw) && raw.includes('.')\n const cleaned = raw.replace(/[^0-9.]/g, '')\n let value = parseUnits(cleaned, token.decimals)\n if (centIsInt && !isFormattedDollars) {\n value = value / 100n\n }\n return value\n }\n\n // Skip auto-match when manual selection is forced (dev/testing)\n if (typeof window !== 'undefined' && (window as unknown as Record<string, unknown>).__FORCE_MANUAL_TX_SELECT__) {\n return null\n }\n\n // Find the first transaction that matches the amount (first in array = most recent)\n // Note: We ignore the hidden flag - matching is purely by amount\n const match = metadata.find((m) => {\n const converted = normalizeAmount(m.amount)\n return converted === currencyAmount || converted === (currencyAmount * -1n)\n })\n\n if (!match) {\n return null\n }\n\n return match\n}\n","/**\n * @fileoverview React context for PeerAuth extension state.\n *\n * Provides global access to the useZKTLS hook state throughout the\n * component tree, avoiding prop drilling for extension status.\n *\n * @see {@link useZKTLS} for the underlying hook\n */\n\nimport { createContext, useContext, type ReactNode } from 'react'\nimport { useZKTLS } from './useZKTLS'\n\n/**\n * Context type derived from useZKTLS hook return value.\n */\ntype ZKTLSContextType = ReturnType<typeof useZKTLS>\n\nexport const ZKTLSContext = createContext<ZKTLSContextType | undefined>(undefined)\n\ninterface ZKTLSProviderProps {\n children: ReactNode\n}\n\n/**\n * Hook to consume the ZKTLS context.\n * Must be used within a ZKTLSProvider.\n *\n * @throws Error if used outside of ZKTLSProvider\n */\nexport function useZKTLSContext() {\n const context = useContext(ZKTLSContext)\n if (context === undefined) {\n throw new Error('useZKTLSContext must be used within a ZKTLSProvider')\n }\n return context\n}\n\nexport function ZKTLSProvider({ children }: ZKTLSProviderProps) {\n const zktlsHook = useZKTLS()\n\n return (\n <ZKTLSContext.Provider value={zktlsHook}>\n {children}\n </ZKTLSContext.Provider>\n )\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/useZKTLS.ts","../src/ZKTLSContext.tsx"],"names":["parseAbiParameter","useState","useEffect","useMemo","sleep","extensionPlatforms","providers","createContext","useContext"],"mappings":"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","file":"ZKTLSContext.cjs","sourcesContent":["/**\n * @fileoverview React hook and utilities for PeerAuth browser extension integration.\n *\n * The PeerAuth extension (formerly ZK-TLS) provides secure proof generation\n * for off-chain payment verification. This module provides:\n *\n * 1. Type definitions for extension API (window.peer)\n * 2. useZKTLS hook for React components\n * 3. Utility functions for transaction matching and proof encoding\n *\n * @remarks\n * The extension exposes `window.peer` (or deprecated `window.zktls`) for:\n * - Requesting connection (OAuth-like flow)\n * - Authenticating with payment providers\n * - Generating notarized proofs\n * - Fetching transaction metadata\n *\n * @see {@link ZKTLSContext} for the React context provider\n */\n\nimport { useEffect, useMemo, useState } from \"react\"\nimport { encodeAbiParameters, encodePacked, parseAbiParameter, parseUnits, type Hex } from \"viem\"\nimport { sleep } from \"@provex/utils/time\"\nimport type { IntentStruct } from \"@provex/utils/intent\"\nimport type { TokenInfo } from \"@provex/utils/tokens\"\nimport { extensionPlatforms, providers, subProviderConfigs, type ActionType, type PlatformKey, type ProviderKey, type SubProviderKey } from \"@provex/utils/payment\"\nimport { convertTokenInputToCurrency } from \"@provex/utils/conversionRates\"\n\ndeclare global {\n interface ZKTLS {\n requestConnection(): Promise<boolean>\n checkConnectionStatus(): Promise<Status>\n getVersion(): Promise<string>\n authenticate(inputs: AuthenticationInputs): Promise<void>\n generateProof(inputs: GenerateProofInputs): Promise<GenerateProofResponse>\n fetchProofById(proofId: string): Promise<ProofResponse>\n fetchProofs(): Promise<FetchProofsResponse>\n openSidebar(route: string): Promise<void>\n onMetadataMessage(fn: (data: MetadataMessageResponse) => void): () => void\n }\n interface Window {\n /** @deprecated Use window.peer instead */\n zktls: ZKTLS | undefined\n /** PeerAuth extension API (replaces window.zktls) */\n peer: ZKTLS | undefined\n }\n}\n\n/** the status of the PeerAuth extension */\nexport type Status = 'connected' | 'disconnected' | 'pending'\n\n/** the individual metadata message sent by the PeerAuth extension */\nexport interface MetadataMessage {\n amount: number\n /** Currency code (e.g., 'USD', 'EUR') */\n currency?: string\n /**\n * Date of the transaction.\n * Can be a string in YYYYMMDD format, a number (YYYYMMDD or timestamp), or Date object.\n * The actual type depends on the extension implementation.\n */\n date: string | number | Date\n hidden: boolean\n originalIndex: number\n paymentId: number\n recipient: string\n}\n\n/** the response from the PeerAuth extension when a metadata message is received */\nexport interface MetadataMessageResponse {\n expiresAt: number\n platform: ProviderKey\n requestId: string\n metadata: MetadataMessage[]\n}\n\n/** the response from the PeerAuth extension when fetching proofs */\nexport interface FetchProofsResponse {\n notaryRequests: NotaryRequest[]\n}\n\n/** the inputs for the generateProof function */\nexport type GenerateProofInputsAbstracted = {\n platform: PlatformKey\n provider: ProviderKey\n intentHash: Hex\n originalIndex: number\n}\n\n/** the inputs for the generateProof function */\nexport type GenerateProofInputs = {\n platform: ProviderKey\n originalIndex: number\n proofIndex?: number\n intentHash: string\n}\n\n/**\n * inputs for the generate proof function that requires the intent hash\n * as hex to ensure it can be converted to a bigint string accurately\n */\nexport type HexIntentGenerateProofInputs = Exclude<GenerateProofInputs, 'intentHash'> & { intentHash: Hex }\n\n/** the response from the PeerAuth extension when generating a proof */\nexport type GenerateProofResponse = {\n proofId: string\n platform: ProviderKey\n}\n\n/** the inputs for the authenticate function */\nexport type AuthenticationInputs = {\n actionType: ActionType\n platform: PlatformKey\n}\n\n/** the response from the PeerAuth extension when fetching a proof */\nexport interface Proof {\n claimInfo: ClaimInfo\n signedClaim: SignedClaim\n isAppclipProof: boolean\n status: string\n}\n\n/** the response from the PeerAuth extension when fetching a proof */\nexport interface NotarizedProof {\n claim: {\n context: string\n epoch: number\n identifier: Hex\n owner: Hex\n parameters: string\n provider: string\n timestampS: number\n },\n signatures: {\n attestorAddress: Hex\n claimSignature: Record<number, number>\n resultSignature: Record<number, number>\n },\n}\n\n/** the claim info for a proof */\nexport interface ClaimInfo {\n provider: string\n parameters: string\n context: string\n}\n\n/** the complete claim data for a proof */\nexport interface CompleteClaimData {\n identifier: Hex\n owner: Hex\n timestampS: number\n epoch: number\n}\n\n/** the signed claim for a proof */\nexport interface SignedClaim {\n claim: CompleteClaimData\n signatures: Hex[]\n}\n\n/** the reclaim proof for a proof */\nexport type ReclaimProof = {\n claimInfo: ClaimInfo\n signedClaim: SignedClaim\n isAppclipProof: boolean\n}\n\n/** the notary request for a proof */\nexport interface NotaryRequest {\n metadata: (string | number)[]\n actionType: ActionType\n id: string\n status: string\n timestamp: number\n proof: NotarizedProof\n}\n\n/** the response from the PeerAuth extension when fetching a proof */\nexport interface ProofResponse {\n notaryRequest: NotaryRequest\n}\n\nexport const extensionUrl = 'https://chromewebstore.google.com/detail/ijpgccednehjpeclfcllnjjcmiohdjih'\n\n/** convert a byte array to a hex string */\nexport const byteArrayToHexString = (byteArray: number[]): Hex => {\n return `0x${byteArray\n .map(byte => byte.toString(16).padStart(2, '0'))\n .join('')}`\n}\n\n/** parse a proof object from the PeerAuth extension */\nexport const parseExtensionProof = (proofObject: NotarizedProof) => {\n return {\n claimInfo: {\n provider: proofObject.claim.provider,\n parameters: proofObject.claim.parameters,\n context: proofObject.claim.context\n },\n signedClaim: {\n claim: {\n identifier: proofObject.claim.identifier as Hex,\n owner: proofObject.claim.owner as Hex,\n timestampS: proofObject.claim.timestampS,\n epoch: proofObject.claim.epoch\n },\n signatures: [byteArrayToHexString(Object.values(proofObject.signatures.claimSignature))]\n },\n isAppclipProof: false\n } as ReclaimProof\n}\n\n/** the abi encoding for a proof */\nexport const PROOF_ENCODING = parseAbiParameter(\"((string provider, string parameters, string context) claimInfo, ((bytes32 identifier, address owner, uint32 timestampS, uint32 epoch) claim, bytes[] signatures) signedClaim, bool isAppclipProof)\")\n\n/** encode a single proof as a bytes array */\nexport function encodeProofAsBytes(proof: ReclaimProof): Hex {\n return encodeAbiParameters([PROOF_ENCODING], [proof])\n}\n\n/** encode two proofs to be passed to the underlying sub-provider */\nexport const encodeTwoProofs = (proof1: ReclaimProof, proof2: ReclaimProof) => {\n return encodeAbiParameters([PROOF_ENCODING, PROOF_ENCODING], [proof1, proof2])\n}\n\n/** a high level function to encode a proof for a given provider and sub-provider */\nexport const encodeProof = ({ extensionProofs, subProvider, provider }: {\n extensionProofs: NotarizedProof[],\n subProvider: PlatformKey | null,\n provider: ProviderKey\n}) => {\n const reclaimProofs = extensionProofs.map((p) => parseExtensionProof(p))\n if (provider === 'zelle') {\n // move this to check the blockchain for the payment method\n const paymentMethod = subProviderConfigs![provider]![subProvider as SubProviderKey]!.paymentMethod\n const twoEncoded = reclaimProofs.length === 2\n ? encodeTwoProofs(reclaimProofs[0]!, reclaimProofs[1]!)\n : encodeProofAsBytes(reclaimProofs[0]!)\n // select between various possible sub-providers\n const withPaymentMethod = encodeProofWithPaymentMethod({\n paymentMethod,\n proof: twoEncoded,\n })\n return withPaymentMethod\n }\n const [reclaimProof] = reclaimProofs\n return encodeProofAsBytes(reclaimProof!)\n}\n\n/**\n * wrap a proof with a payment method and proof\n * this allows us to use a single verifier as an entry point for multiple underlying sub-providers\n */\nexport const encodeProofWithPaymentMethod = ({\n proof,\n paymentMethod\n}: {\n proof: Hex,\n paymentMethod: number\n}): Hex => {\n return encodePacked(['uint8', 'bytes'], [paymentMethod, proof])\n}\n\n/** the progress of a proof series */\nexport enum SeriesProgress {\n Generating,\n Polling,\n Complete,\n}\n\nexport type ProgressInfo = {\n progress: SeriesProgress\n total: number\n step: number | null\n id: string | null\n}\n\n/** the mutations for the generate proof series function */\nexport type GenerateProofSeriesMutations = {\n progress?: ({ progress, step, id }: ProgressInfo) => void\n setOwnerName?: (name: string) => void\n}\n\n/** React hook to interact with the PeerAuth extension */\nexport const useZKTLS = () => {\n const [isInitialized, setIsInitialized] = useState(false)\n useEffect(() => {\n const setup = () => {\n setIsInitialized(true)\n }\n const eventName = 'peer#initialized'\n if (typeof window.peer !== 'undefined') {\n // api is available\n setup()\n } else {\n window.addEventListener(eventName, setup)\n return () => {\n window.removeEventListener(eventName, setup)\n }\n }\n }, [])\n return useMemo(() => {\n /** fetch a proof by its id */\n const fetchProofById = async (proofId: string): Promise<NotaryRequest | null> => {\n const proof = await window.peer!.fetchProofById(proofId)\n if (proof && proof.notaryRequest) return proof.notaryRequest\n const proofs = await window.peer!.fetchProofs()\n const proofFromList = proofs.notaryRequests.find((p) => p.id === proofId)\n if (proofFromList) return proofFromList\n return null\n }\n /** wait for a proof to be generated */\n const waitForProof = async (proofId: string, onCurrent?: (notaryRequest: NotaryRequest | null) => void) => {\n let notaryRequest: NotaryRequest | null = null\n do {\n notaryRequest = await fetchProofById(proofId)\n onCurrent?.(notaryRequest)\n await sleep(1_000)\n } while (!notaryRequest || !notaryRequest.status || notaryRequest.status === 'pending')\n if (notaryRequest.status === 'failed' || notaryRequest.status === 'expired' || notaryRequest.status === 'cancelled' || notaryRequest.status === 'error') {\n console.error('[waitForProof] proof terminal state:', JSON.stringify(notaryRequest, null, 2))\n const req = notaryRequest as unknown as Record<string, unknown>\n const detail = req.errorMessage ?? req.error ?? req.message ?? notaryRequest.status\n throw new Error(`Proof generation failed: ${detail}`)\n }\n return notaryRequest\n }\n /** generate a proof */\n const generateProof = async (inputs: HexIntentGenerateProofInputs): Promise<GenerateProofResponse> => {\n return await window.peer!.generateProof({\n proofIndex: 0,\n ...inputs,\n intentHash: BigInt(inputs.intentHash).toString(),\n })\n }\n return {\n /** check if the PeerAuth extension is initialized */\n isInitialized,\n /** request a connection to the PeerAuth extension */\n requestConnection: async () => {\n if (!window.peer) return false\n return window.peer!.requestConnection()\n },\n /**\n * check the connection status of the PeerAuth extension\n * @returns the connection status\n */\n checkConnectionStatus: async () => {\n return await window.peer!.checkConnectionStatus()\n },\n /** get the version of the PeerAuth extension */\n getVersion: async () => {\n return await window.peer?.getVersion()\n },\n /** authenticate with the PeerAuth extension */\n authenticate: async (inputs: AuthenticationInputs) => {\n // Create promise first to avoid race condition where message arrives before resolver is assigned\n let resolve: (value: MetadataMessageResponse) => void\n const promise = new Promise<MetadataMessageResponse>((resolver) => {\n resolve = resolver\n })\n\n // Now set up the listener - resolve is guaranteed to be the real resolver\n const unsub = window.peer!.onMetadataMessage((data) => {\n if (`transfer_${data.platform}` === inputs.actionType) {\n resolve(data)\n }\n })\n\n await window.peer!.authenticate(inputs)\n\n return await promise.then((data) => {\n unsub()\n return data\n })\n },\n /** generate a proof */\n generateProof,\n /** wait for a proof to be generated */\n waitForProof,\n /** generate a proof series */\n generateProofSeries: async (\n inputs: GenerateProofInputsAbstracted,\n { progress: progressCallback }: GenerateProofSeriesMutations = {},\n ): Promise<NotaryRequest[]> => {\n const { platform, provider, intentHash, originalIndex } = inputs\n const args = {\n platform: provider,\n originalIndex,\n intentHash,\n } as const\n // Chase requires 2 proofs (account verification + transaction)\n // Platform is the bank name (e.g., 'chase') from extensionPlatform config\n const isChase = platform === extensionPlatforms.CHASE\n const isZelle = provider === providers.ZELLE\n const expectedTotal = isZelle && isChase ? 2 : 1\n progressCallback?.({ progress: SeriesProgress.Generating, step: 0, id: null, total: expectedTotal })\n const genProofA = await generateProof({ ...args, proofIndex: 0 })\n progressCallback?.({ progress: SeriesProgress.Polling, step: 0, id: genProofA.proofId, total: expectedTotal })\n const proofA = await waitForProof(genProofA.proofId)\n if (!isChase || !isZelle) {\n progressCallback?.({ progress: SeriesProgress.Complete, step: null, id: null, total: expectedTotal })\n return [proofA]\n }\n progressCallback?.({ progress: SeriesProgress.Generating, step: 1, id: null, total: expectedTotal })\n const genProofB = await generateProof({ ...args, proofIndex: 1 })\n progressCallback?.({ progress: SeriesProgress.Polling, step: 1, id: genProofB.proofId, total: expectedTotal })\n const proofB = await waitForProof(genProofB.proofId)\n progressCallback?.({ progress: SeriesProgress.Complete, step: null, id: null, total: expectedTotal })\n return [proofA, proofB]\n },\n /** subscribe to metadata messages */\n onMetadataMessage: (fn: (data: any) => void) => {\n return window.peer!.onMetadataMessage(fn)\n },\n /** fetch a proof by its id */\n fetchProofById,\n /** fetch generated proofs */\n fetchGeneratedProofs: async (genProofResponses: GenerateProofResponse[]) => {\n return await Promise.all(genProofResponses.map((r) => fetchProofById(r.proofId)))\n },\n /** fetch all proofs */\n fetchProofs: async () => {\n return await window.peer!.fetchProofs()\n },\n /** open the PeerAuth sidebar */\n openSidebar: async (route: string) => {\n return await window.peer!.openSidebar(route)\n },\n }\n }, [isInitialized])\n}\n\n/**\n * Find the metadata message that matches the intent by amount.\n * Returns the first (most recent) transaction in the metadata array that matches the expected amount.\n *\n * Simplified matching: just find transactions with the correct amount.\n * The user can manually select if multiple matches exist.\n */\nexport const findMetadataMessage = ({ metadata, intent, token, centIsInt = false }: {\n metadata: MetadataMessage[],\n intent: IntentStruct,\n token: TokenInfo,\n /** @deprecated No longer used - kept for API compatibility */\n recipient?: string,\n centIsInt?: boolean,\n}): MetadataMessage | null => {\n const currencyAmount = convertTokenInputToCurrency({\n token,\n amountOutInt: intent.amount,\n rate: intent.conversionRate,\n })\n /**\n * Normalize an amount from the extension into a bigint in token base units.\n *\n * The extension sends amounts in different formats per provider:\n * - Venmo: `\"- $1.00\"` (formatted dollar string)\n * - Others: `100` (integer cents) or `1.00` (decimal dollars)\n *\n * We detect the format by checking for currency symbols or decimal points\n * in the raw value. If present, the value is already in dollars and we\n * skip the centIsInt division.\n */\n const normalizeAmount = (amount: number | string): bigint => {\n const raw = String(amount)\n const isFormattedDollars = /[^0-9\\-]/.test(raw) && raw.includes('.')\n const cleaned = raw.replace(/[^0-9.]/g, '')\n let value = parseUnits(cleaned, token.decimals)\n if (centIsInt && !isFormattedDollars) {\n value = value / 100n\n }\n return value\n }\n\n // Skip auto-match when manual selection is forced (dev/testing)\n if (typeof window !== 'undefined' && (window as unknown as Record<string, unknown>).__FORCE_MANUAL_TX_SELECT__) {\n return null\n }\n\n // Find the first transaction that matches the amount (first in array = most recent)\n // Note: We ignore the hidden flag - matching is purely by amount\n const match = metadata.find((m) => {\n const converted = normalizeAmount(m.amount)\n return converted === currencyAmount || converted === (currencyAmount * -1n)\n })\n\n if (!match) {\n // Detect 100x scale mismatch — the most common failure mode when centIsInt\n // is wrong for a provider. Fires loudly so it's obvious in dev/staging logs.\n const hundredxMatch = metadata.find((m) => {\n const converted = normalizeAmount(m.amount)\n const abs = converted < 0n ? -converted : converted\n return abs === currencyAmount * 100n || abs * 100n === currencyAmount\n })\n if (hundredxMatch) {\n console.warn(\n `[findMetadataMessage] tx[0] amount=${String(hundredxMatch.amount)} is 100x off from expected ${currencyAmount.toString()} — centIsInt is likely wrong for this provider (currently ${centIsInt})`\n )\n }\n return null\n }\n\n return match\n}\n","/**\n * @fileoverview React context for PeerAuth extension state.\n *\n * Provides global access to the useZKTLS hook state throughout the\n * component tree, avoiding prop drilling for extension status.\n *\n * @see {@link useZKTLS} for the underlying hook\n */\n\nimport { createContext, useContext, type ReactNode } from 'react'\nimport { useZKTLS } from './useZKTLS'\n\n/**\n * Context type derived from useZKTLS hook return value.\n */\ntype ZKTLSContextType = ReturnType<typeof useZKTLS>\n\nexport const ZKTLSContext = createContext<ZKTLSContextType | undefined>(undefined)\n\ninterface ZKTLSProviderProps {\n children: ReactNode\n}\n\n/**\n * Hook to consume the ZKTLS context.\n * Must be used within a ZKTLSProvider.\n *\n * @throws Error if used outside of ZKTLSProvider\n */\nexport function useZKTLSContext() {\n const context = useContext(ZKTLSContext)\n if (context === undefined) {\n throw new Error('useZKTLSContext must be used within a ZKTLSProvider')\n }\n return context\n}\n\nexport function ZKTLSProvider({ children }: ZKTLSProviderProps) {\n const zktlsHook = useZKTLS()\n\n return (\n <ZKTLSContext.Provider value={zktlsHook}>\n {children}\n </ZKTLSContext.Provider>\n )\n}\n"]}
|
package/dist/ZKTLSContext.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { ZKTLSContext, ZKTLSProvider, useZKTLSContext } from './chunk-
|
|
2
|
-
import './chunk-
|
|
1
|
+
export { ZKTLSContext, ZKTLSProvider, useZKTLSContext } from './chunk-VDCCIS6C.js';
|
|
2
|
+
import './chunk-W2QUSBIS.js';
|
|
3
3
|
//# sourceMappingURL=ZKTLSContext.js.map
|
|
4
4
|
//# sourceMappingURL=ZKTLSContext.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useZKTLS } from './chunk-
|
|
1
|
+
import { useZKTLS } from './chunk-W2QUSBIS.js';
|
|
2
2
|
import { createContext, useContext } from 'react';
|
|
3
3
|
import { jsx } from 'react/jsx-runtime';
|
|
4
4
|
|
|
@@ -16,5 +16,5 @@ function ZKTLSProvider({ children }) {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export { ZKTLSContext, ZKTLSProvider, useZKTLSContext };
|
|
19
|
-
//# sourceMappingURL=chunk-
|
|
20
|
-
//# sourceMappingURL=chunk-
|
|
19
|
+
//# sourceMappingURL=chunk-VDCCIS6C.js.map
|
|
20
|
+
//# sourceMappingURL=chunk-VDCCIS6C.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/ZKTLSContext.tsx"],"names":[],"mappings":";;;;AAiBO,IAAM,YAAA,GAAe,cAA4C,MAAS;AAY1E,SAAS,eAAA,GAAkB;AAChC,EAAA,MAAM,OAAA,GAAU,WAAW,YAAY,CAAA;AACvC,EAAA,IAAI,YAAY,MAAA,EAAW;AACzB,IAAA,MAAM,IAAI,MAAM,qDAAqD,CAAA;AAAA,EACvE;AACA,EAAA,OAAO,OAAA;AACT;AAEO,SAAS,aAAA,CAAc,EAAE,QAAA,EAAS,EAAuB;AAC9D,EAAA,MAAM,YAAY,QAAA,EAAS;AAE3B,EAAA,2BACG,YAAA,CAAa,QAAA,EAAb,EAAsB,KAAA,EAAO,WAC3B,QAAA,EACH,CAAA;AAEJ","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/ZKTLSContext.tsx"],"names":[],"mappings":";;;;AAiBO,IAAM,YAAA,GAAe,cAA4C,MAAS;AAY1E,SAAS,eAAA,GAAkB;AAChC,EAAA,MAAM,OAAA,GAAU,WAAW,YAAY,CAAA;AACvC,EAAA,IAAI,YAAY,MAAA,EAAW;AACzB,IAAA,MAAM,IAAI,MAAM,qDAAqD,CAAA;AAAA,EACvE;AACA,EAAA,OAAO,OAAA;AACT;AAEO,SAAS,aAAA,CAAc,EAAE,QAAA,EAAS,EAAuB;AAC9D,EAAA,MAAM,YAAY,QAAA,EAAS;AAE3B,EAAA,2BACG,YAAA,CAAa,QAAA,EAAb,EAAsB,KAAA,EAAO,WAC3B,QAAA,EACH,CAAA;AAEJ","file":"chunk-VDCCIS6C.js","sourcesContent":["/**\n * @fileoverview React context for PeerAuth extension state.\n *\n * Provides global access to the useZKTLS hook state throughout the\n * component tree, avoiding prop drilling for extension status.\n *\n * @see {@link useZKTLS} for the underlying hook\n */\n\nimport { createContext, useContext, type ReactNode } from 'react'\nimport { useZKTLS } from './useZKTLS'\n\n/**\n * Context type derived from useZKTLS hook return value.\n */\ntype ZKTLSContextType = ReturnType<typeof useZKTLS>\n\nexport const ZKTLSContext = createContext<ZKTLSContextType | undefined>(undefined)\n\ninterface ZKTLSProviderProps {\n children: ReactNode\n}\n\n/**\n * Hook to consume the ZKTLS context.\n * Must be used within a ZKTLSProvider.\n *\n * @throws Error if used outside of ZKTLSProvider\n */\nexport function useZKTLSContext() {\n const context = useContext(ZKTLSContext)\n if (context === undefined) {\n throw new Error('useZKTLSContext must be used within a ZKTLSProvider')\n }\n return context\n}\n\nexport function ZKTLSProvider({ children }: ZKTLSProviderProps) {\n const zktlsHook = useZKTLS()\n\n return (\n <ZKTLSContext.Provider value={zktlsHook}>\n {children}\n </ZKTLSContext.Provider>\n )\n}\n"]}
|
|
@@ -94,7 +94,10 @@ var useZKTLS = () => {
|
|
|
94
94
|
await sleep(1e3);
|
|
95
95
|
} while (!notaryRequest || !notaryRequest.status || notaryRequest.status === "pending");
|
|
96
96
|
if (notaryRequest.status === "failed" || notaryRequest.status === "expired" || notaryRequest.status === "cancelled" || notaryRequest.status === "error") {
|
|
97
|
-
|
|
97
|
+
console.error("[waitForProof] proof terminal state:", JSON.stringify(notaryRequest, null, 2));
|
|
98
|
+
const req = notaryRequest;
|
|
99
|
+
const detail = req.errorMessage ?? req.error ?? req.message ?? notaryRequest.status;
|
|
100
|
+
throw new Error(`Proof generation failed: ${detail}`);
|
|
98
101
|
}
|
|
99
102
|
return notaryRequest;
|
|
100
103
|
};
|
|
@@ -216,11 +219,21 @@ var findMetadataMessage = ({ metadata, intent, token, centIsInt = false }) => {
|
|
|
216
219
|
return converted === currencyAmount || converted === currencyAmount * -1n;
|
|
217
220
|
});
|
|
218
221
|
if (!match) {
|
|
222
|
+
const hundredxMatch = metadata.find((m) => {
|
|
223
|
+
const converted = normalizeAmount(m.amount);
|
|
224
|
+
const abs = converted < 0n ? -converted : converted;
|
|
225
|
+
return abs === currencyAmount * 100n || abs * 100n === currencyAmount;
|
|
226
|
+
});
|
|
227
|
+
if (hundredxMatch) {
|
|
228
|
+
console.warn(
|
|
229
|
+
`[findMetadataMessage] tx[0] amount=${String(hundredxMatch.amount)} is 100x off from expected ${currencyAmount.toString()} \u2014 centIsInt is likely wrong for this provider (currently ${centIsInt})`
|
|
230
|
+
);
|
|
231
|
+
}
|
|
219
232
|
return null;
|
|
220
233
|
}
|
|
221
234
|
return match;
|
|
222
235
|
};
|
|
223
236
|
|
|
224
237
|
export { PROOF_ENCODING, SeriesProgress, byteArrayToHexString, encodeProof, encodeProofAsBytes, encodeProofWithPaymentMethod, encodeTwoProofs, extensionUrl, findMetadataMessage, parseExtensionProof, useZKTLS };
|
|
225
|
-
//# sourceMappingURL=chunk-
|
|
226
|
-
//# sourceMappingURL=chunk-
|
|
238
|
+
//# sourceMappingURL=chunk-W2QUSBIS.js.map
|
|
239
|
+
//# sourceMappingURL=chunk-W2QUSBIS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/useZKTLS.ts"],"names":["SeriesProgress"],"mappings":";;;;;;;AAwLO,IAAM,YAAA,GAAe;AAGrB,IAAM,oBAAA,GAAuB,CAAC,SAAA,KAA6B;AAChE,EAAA,OAAO,CAAA,EAAA,EAAK,SAAA,CACT,GAAA,CAAI,CAAA,IAAA,KAAQ,KAAK,QAAA,CAAS,EAAE,CAAA,CAAE,QAAA,CAAS,GAAG,GAAG,CAAC,CAAA,CAC9C,IAAA,CAAK,EAAE,CAAC,CAAA,CAAA;AACb;AAGO,IAAM,mBAAA,GAAsB,CAAC,WAAA,KAAgC;AAClE,EAAA,OAAO;AAAA,IACL,SAAA,EAAW;AAAA,MACT,QAAA,EAAU,YAAY,KAAA,CAAM,QAAA;AAAA,MAC5B,UAAA,EAAY,YAAY,KAAA,CAAM,UAAA;AAAA,MAC9B,OAAA,EAAS,YAAY,KAAA,CAAM;AAAA,KAC7B;AAAA,IACA,WAAA,EAAa;AAAA,MACX,KAAA,EAAO;AAAA,QACL,UAAA,EAAY,YAAY,KAAA,CAAM,UAAA;AAAA,QAC9B,KAAA,EAAO,YAAY,KAAA,CAAM,KAAA;AAAA,QACzB,UAAA,EAAY,YAAY,KAAA,CAAM,UAAA;AAAA,QAC9B,KAAA,EAAO,YAAY,KAAA,CAAM;AAAA,OAC3B;AAAA,MACA,UAAA,EAAY,CAAC,oBAAA,CAAqB,MAAA,CAAO,OAAO,WAAA,CAAY,UAAA,CAAW,cAAc,CAAC,CAAC;AAAA,KACzF;AAAA,IACA,cAAA,EAAgB;AAAA,GAClB;AACF;AAGO,IAAM,cAAA,GAAiB,kBAAkB,qMAAqM;AAG9O,SAAS,mBAAmB,KAAA,EAA0B;AAC3D,EAAA,OAAO,oBAAoB,CAAC,cAAc,CAAA,EAAG,CAAC,KAAK,CAAC,CAAA;AACtD;AAGO,IAAM,eAAA,GAAkB,CAAC,MAAA,EAAsB,MAAA,KAAyB;AAC7E,EAAA,OAAO,mBAAA,CAAoB,CAAC,cAAA,EAAgB,cAAc,GAAG,CAAC,MAAA,EAAQ,MAAM,CAAC,CAAA;AAC/E;AAGO,IAAM,cAAc,CAAC,EAAE,eAAA,EAAiB,WAAA,EAAa,UAAS,KAI/D;AACJ,EAAA,MAAM,gBAAgB,eAAA,CAAgB,GAAA,CAAI,CAAC,CAAA,KAAM,mBAAA,CAAoB,CAAC,CAAC,CAAA;AACvE,EAAA,IAAI,aAAa,OAAA,EAAS;AAExB,IAAA,MAAM,aAAA,GAAgB,kBAAA,CAAoB,QAAQ,CAAA,CAAG,WAA6B,CAAA,CAAG,aAAA;AACrF,IAAA,MAAM,UAAA,GAAa,aAAA,CAAc,MAAA,KAAW,CAAA,GACxC,gBAAgB,aAAA,CAAc,CAAC,CAAA,EAAI,aAAA,CAAc,CAAC,CAAE,CAAA,GACpD,kBAAA,CAAmB,aAAA,CAAc,CAAC,CAAE,CAAA;AAExC,IAAA,MAAM,oBAAoB,4BAAA,CAA6B;AAAA,MACrD,aAAA;AAAA,MACA,KAAA,EAAO;AAAA,KACR,CAAA;AACD,IAAA,OAAO,iBAAA;AAAA,EACT;AACA,EAAA,MAAM,CAAC,YAAY,CAAA,GAAI,aAAA;AACvB,EAAA,OAAO,mBAAmB,YAAa,CAAA;AACzC;AAMO,IAAM,+BAA+B,CAAC;AAAA,EAC3C,KAAA;AAAA,EACA;AACF,CAAA,KAGW;AACT,EAAA,OAAO,YAAA,CAAa,CAAC,OAAA,EAAS,OAAO,GAAG,CAAC,aAAA,EAAe,KAAK,CAAC,CAAA;AAChE;AAGO,IAAK,cAAA,qBAAAA,eAAAA,KAAL;AACL,EAAAA,eAAAA,CAAAA,eAAAA,CAAA,YAAA,CAAA,GAAA,CAAA,CAAA,GAAA,YAAA;AACA,EAAAA,eAAAA,CAAAA,eAAAA,CAAA,SAAA,CAAA,GAAA,CAAA,CAAA,GAAA,SAAA;AACA,EAAAA,eAAAA,CAAAA,eAAAA,CAAA,UAAA,CAAA,GAAA,CAAA,CAAA,GAAA,UAAA;AAHU,EAAA,OAAAA,eAAAA;AAAA,CAAA,EAAA,cAAA,IAAA,EAAA;AAoBL,IAAM,WAAW,MAAM;AAC5B,EAAA,MAAM,CAAC,aAAA,EAAe,gBAAgB,CAAA,GAAI,SAAS,KAAK,CAAA;AACxD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,QAAQ,MAAM;AAClB,MAAA,gBAAA,CAAiB,IAAI,CAAA;AAAA,IACvB,CAAA;AACA,IAAA,MAAM,SAAA,GAAY,kBAAA;AAClB,IAAA,IAAI,OAAO,MAAA,CAAO,IAAA,KAAS,WAAA,EAAa;AAEtC,MAAA,KAAA,EAAM;AAAA,IACR,CAAA,MAAO;AACL,MAAA,MAAA,CAAO,gBAAA,CAAiB,WAAW,KAAK,CAAA;AACxC,MAAA,OAAO,MAAM;AACX,QAAA,MAAA,CAAO,mBAAA,CAAoB,WAAW,KAAK,CAAA;AAAA,MAC7C,CAAA;AAAA,IACF;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AACL,EAAA,OAAO,QAAQ,MAAM;AAEnB,IAAA,MAAM,cAAA,GAAiB,OAAO,OAAA,KAAmD;AAC/E,MAAA,MAAM,KAAA,GAAQ,MAAM,MAAA,CAAO,IAAA,CAAM,eAAe,OAAO,CAAA;AACvD,MAAA,IAAI,KAAA,IAAS,KAAA,CAAM,aAAA,EAAe,OAAO,KAAA,CAAM,aAAA;AAC/C,MAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,IAAA,CAAM,WAAA,EAAY;AAC9C,MAAA,MAAM,aAAA,GAAgB,OAAO,cAAA,CAAe,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,OAAO,CAAA;AACxE,MAAA,IAAI,eAAe,OAAO,aAAA;AAC1B,MAAA,OAAO,IAAA;AAAA,IACT,CAAA;AAEA,IAAA,MAAM,YAAA,GAAe,OAAO,OAAA,EAAiB,SAAA,KAA8D;AACzG,MAAA,IAAI,aAAA,GAAsC,IAAA;AAC1C,MAAA,GAAG;AACD,QAAA,aAAA,GAAgB,MAAM,eAAe,OAAO,CAAA;AAC5C,QAAA,SAAA,GAAY,aAAa,CAAA;AACzB,QAAA,MAAM,MAAM,GAAK,CAAA;AAAA,MACnB,SAAS,CAAC,aAAA,IAAiB,CAAC,aAAA,CAAc,MAAA,IAAU,cAAc,MAAA,KAAW,SAAA;AAC7E,MAAA,IAAI,aAAA,CAAc,MAAA,KAAW,QAAA,IAAY,aAAA,CAAc,MAAA,KAAW,SAAA,IAAa,aAAA,CAAc,MAAA,KAAW,WAAA,IAAe,aAAA,CAAc,MAAA,KAAW,OAAA,EAAS;AACvJ,QAAA,OAAA,CAAQ,MAAM,sCAAA,EAAwC,IAAA,CAAK,UAAU,aAAA,EAAe,IAAA,EAAM,CAAC,CAAC,CAAA;AAC5F,QAAA,MAAM,GAAA,GAAM,aAAA;AACZ,QAAA,MAAM,SAAS,GAAA,CAAI,YAAA,IAAgB,IAAI,KAAA,IAAS,GAAA,CAAI,WAAW,aAAA,CAAc,MAAA;AAC7E,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,yBAAA,EAA4B,MAAM,CAAA,CAAE,CAAA;AAAA,MACtD;AACA,MAAA,OAAO,aAAA;AAAA,IACT,CAAA;AAEA,IAAA,MAAM,aAAA,GAAgB,OAAO,MAAA,KAAyE;AACpG,MAAA,OAAO,MAAM,MAAA,CAAO,IAAA,CAAM,aAAA,CAAc;AAAA,QACtC,UAAA,EAAY,CAAA;AAAA,QACZ,GAAG,MAAA;AAAA,QACH,UAAA,EAAY,MAAA,CAAO,MAAA,CAAO,UAAU,EAAE,QAAA;AAAS,OAChD,CAAA;AAAA,IACH,CAAA;AACA,IAAA,OAAO;AAAA;AAAA,MAEL,aAAA;AAAA;AAAA,MAEA,mBAAmB,YAAY;AAC7B,QAAA,IAAI,CAAC,MAAA,CAAO,IAAA,EAAM,OAAO,KAAA;AACzB,QAAA,OAAO,MAAA,CAAO,KAAM,iBAAA,EAAkB;AAAA,MACxC,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAKA,uBAAuB,YAAY;AACjC,QAAA,OAAO,MAAM,MAAA,CAAO,IAAA,CAAM,qBAAA,EAAsB;AAAA,MAClD,CAAA;AAAA;AAAA,MAEA,YAAY,YAAY;AACtB,QAAA,OAAO,MAAM,MAAA,CAAO,IAAA,EAAM,UAAA,EAAW;AAAA,MACvC,CAAA;AAAA;AAAA,MAEA,YAAA,EAAc,OAAO,MAAA,KAAiC;AAEpD,QAAA,IAAI,OAAA;AACJ,QAAA,MAAM,OAAA,GAAU,IAAI,OAAA,CAAiC,CAAC,QAAA,KAAa;AACjE,UAAA,OAAA,GAAU,QAAA;AAAA,QACZ,CAAC,CAAA;AAGD,QAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,IAAA,CAAM,iBAAA,CAAkB,CAAC,IAAA,KAAS;AACrD,UAAA,IAAI,CAAA,SAAA,EAAY,IAAA,CAAK,QAAQ,CAAA,CAAA,KAAO,OAAO,UAAA,EAAY;AACrD,YAAA,OAAA,CAAQ,IAAI,CAAA;AAAA,UACd;AAAA,QACF,CAAC,CAAA;AAED,QAAA,MAAM,MAAA,CAAO,IAAA,CAAM,YAAA,CAAa,MAAM,CAAA;AAEtC,QAAA,OAAO,MAAM,OAAA,CAAQ,IAAA,CAAK,CAAC,IAAA,KAAS;AAClC,UAAA,KAAA,EAAM;AACN,UAAA,OAAO,IAAA;AAAA,QACT,CAAC,CAAA;AAAA,MACH,CAAA;AAAA;AAAA,MAEA,aAAA;AAAA;AAAA,MAEA,YAAA;AAAA;AAAA,MAEA,mBAAA,EAAqB,OACnB,MAAA,EACA,EAAE,UAAU,gBAAA,EAAiB,GAAkC,EAAC,KACnC;AAC7B,QAAA,MAAM,EAAE,QAAA,EAAU,QAAA,EAAU,UAAA,EAAY,eAAc,GAAI,MAAA;AAC1D,QAAA,MAAM,IAAA,GAAO;AAAA,UACX,QAAA,EAAU,QAAA;AAAA,UACV,aAAA;AAAA,UACA;AAAA,SACF;AAGA,QAAA,MAAM,OAAA,GAAU,aAAa,kBAAA,CAAmB,KAAA;AAChD,QAAA,MAAM,OAAA,GAAU,aAAa,SAAA,CAAU,KAAA;AACvC,QAAA,MAAM,aAAA,GAAgB,OAAA,IAAW,OAAA,GAAU,CAAA,GAAI,CAAA;AAC/C,QAAA,gBAAA,GAAmB,EAAE,UAAU,CAAA,mBAA2B,IAAA,EAAM,GAAG,EAAA,EAAI,IAAA,EAAM,KAAA,EAAO,aAAA,EAAe,CAAA;AACnG,QAAA,MAAM,SAAA,GAAY,MAAM,aAAA,CAAc,EAAE,GAAG,IAAA,EAAM,UAAA,EAAY,GAAG,CAAA;AAChE,QAAA,gBAAA,GAAmB,EAAE,QAAA,EAAU,CAAA,gBAAwB,IAAA,EAAM,CAAA,EAAG,IAAI,SAAA,CAAU,OAAA,EAAS,KAAA,EAAO,aAAA,EAAe,CAAA;AAC7G,QAAA,MAAM,MAAA,GAAS,MAAM,YAAA,CAAa,SAAA,CAAU,OAAO,CAAA;AACnD,QAAA,IAAI,CAAC,OAAA,IAAW,CAAC,OAAA,EAAS;AACxB,UAAA,gBAAA,GAAmB,EAAE,UAAU,CAAA,iBAAyB,IAAA,EAAM,MAAM,EAAA,EAAI,IAAA,EAAM,KAAA,EAAO,aAAA,EAAe,CAAA;AACpG,UAAA,OAAO,CAAC,MAAM,CAAA;AAAA,QAChB;AACA,QAAA,gBAAA,GAAmB,EAAE,UAAU,CAAA,mBAA2B,IAAA,EAAM,GAAG,EAAA,EAAI,IAAA,EAAM,KAAA,EAAO,aAAA,EAAe,CAAA;AACnG,QAAA,MAAM,SAAA,GAAY,MAAM,aAAA,CAAc,EAAE,GAAG,IAAA,EAAM,UAAA,EAAY,GAAG,CAAA;AAChE,QAAA,gBAAA,GAAmB,EAAE,QAAA,EAAU,CAAA,gBAAwB,IAAA,EAAM,CAAA,EAAG,IAAI,SAAA,CAAU,OAAA,EAAS,KAAA,EAAO,aAAA,EAAe,CAAA;AAC7G,QAAA,MAAM,MAAA,GAAS,MAAM,YAAA,CAAa,SAAA,CAAU,OAAO,CAAA;AACnD,QAAA,gBAAA,GAAmB,EAAE,UAAU,CAAA,iBAAyB,IAAA,EAAM,MAAM,EAAA,EAAI,IAAA,EAAM,KAAA,EAAO,aAAA,EAAe,CAAA;AACpG,QAAA,OAAO,CAAC,QAAQ,MAAM,CAAA;AAAA,MACxB,CAAA;AAAA;AAAA,MAEA,iBAAA,EAAmB,CAAC,EAAA,KAA4B;AAC9C,QAAA,OAAO,MAAA,CAAO,IAAA,CAAM,iBAAA,CAAkB,EAAE,CAAA;AAAA,MAC1C,CAAA;AAAA;AAAA,MAEA,cAAA;AAAA;AAAA,MAEA,oBAAA,EAAsB,OAAO,iBAAA,KAA+C;AAC1E,QAAA,OAAO,MAAM,OAAA,CAAQ,GAAA,CAAI,iBAAA,CAAkB,GAAA,CAAI,CAAC,CAAA,KAAM,cAAA,CAAe,CAAA,CAAE,OAAO,CAAC,CAAC,CAAA;AAAA,MAClF,CAAA;AAAA;AAAA,MAEA,aAAa,YAAY;AACvB,QAAA,OAAO,MAAM,MAAA,CAAO,IAAA,CAAM,WAAA,EAAY;AAAA,MACxC,CAAA;AAAA;AAAA,MAEA,WAAA,EAAa,OAAO,KAAA,KAAkB;AACpC,QAAA,OAAO,MAAM,MAAA,CAAO,IAAA,CAAM,WAAA,CAAY,KAAK,CAAA;AAAA,MAC7C;AAAA,KACF;AAAA,EACF,CAAA,EAAG,CAAC,aAAa,CAAC,CAAA;AACpB;AASO,IAAM,mBAAA,GAAsB,CAAC,EAAE,QAAA,EAAU,QAAQ,KAAA,EAAO,SAAA,GAAY,OAAM,KAOnD;AAC5B,EAAA,MAAM,iBAAiB,2BAAA,CAA4B;AAAA,IACjD,KAAA;AAAA,IACA,cAAc,MAAA,CAAO,MAAA;AAAA,IACrB,MAAM,MAAA,CAAO;AAAA,GACd,CAAA;AAYD,EAAA,MAAM,eAAA,GAAkB,CAAC,MAAA,KAAoC;AAC3D,IAAA,MAAM,GAAA,GAAM,OAAO,MAAM,CAAA;AACzB,IAAA,MAAM,qBAAqB,UAAA,CAAW,IAAA,CAAK,GAAG,CAAA,IAAK,GAAA,CAAI,SAAS,GAAG,CAAA;AACnE,IAAA,MAAM,OAAA,GAAU,GAAA,CAAI,OAAA,CAAQ,UAAA,EAAY,EAAE,CAAA;AAC1C,IAAA,IAAI,KAAA,GAAQ,UAAA,CAAW,OAAA,EAAS,KAAA,CAAM,QAAQ,CAAA;AAC9C,IAAA,IAAI,SAAA,IAAa,CAAC,kBAAA,EAAoB;AACpC,MAAA,KAAA,GAAQ,KAAA,GAAQ,IAAA;AAAA,IAClB;AACA,IAAA,OAAO,KAAA;AAAA,EACT,CAAA;AAGA,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,IAAgB,MAAA,CAA8C,0BAAA,EAA4B;AAC9G,IAAA,OAAO,IAAA;AAAA,EACT;AAIA,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,IAAA,CAAK,CAAC,CAAA,KAAM;AACjC,IAAA,MAAM,SAAA,GAAY,eAAA,CAAgB,CAAA,CAAE,MAAM,CAAA;AAC1C,IAAA,OAAO,SAAA,KAAc,cAAA,IAAkB,SAAA,KAAe,cAAA,GAAiB,CAAC,EAAA;AAAA,EAC1E,CAAC,CAAA;AAED,EAAA,IAAI,CAAC,KAAA,EAAO;AAGV,IAAA,MAAM,aAAA,GAAgB,QAAA,CAAS,IAAA,CAAK,CAAC,CAAA,KAAM;AACzC,MAAA,MAAM,SAAA,GAAY,eAAA,CAAgB,CAAA,CAAE,MAAM,CAAA;AAC1C,MAAA,MAAM,GAAA,GAAM,SAAA,GAAY,EAAA,GAAK,CAAC,SAAA,GAAY,SAAA;AAC1C,MAAA,OAAO,GAAA,KAAQ,cAAA,GAAiB,IAAA,IAAQ,GAAA,GAAM,IAAA,KAAS,cAAA;AAAA,IACzD,CAAC,CAAA;AACD,IAAA,IAAI,aAAA,EAAe;AACjB,MAAA,OAAA,CAAQ,IAAA;AAAA,QACN,CAAA,mCAAA,EAAsC,MAAA,CAAO,aAAA,CAAc,MAAM,CAAC,8BAA8B,cAAA,CAAe,QAAA,EAAU,CAAA,+DAAA,EAA6D,SAAS,CAAA,CAAA;AAAA,OACjM;AAAA,IACF;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,OAAO,KAAA;AACT","file":"chunk-W2QUSBIS.js","sourcesContent":["/**\n * @fileoverview React hook and utilities for PeerAuth browser extension integration.\n *\n * The PeerAuth extension (formerly ZK-TLS) provides secure proof generation\n * for off-chain payment verification. This module provides:\n *\n * 1. Type definitions for extension API (window.peer)\n * 2. useZKTLS hook for React components\n * 3. Utility functions for transaction matching and proof encoding\n *\n * @remarks\n * The extension exposes `window.peer` (or deprecated `window.zktls`) for:\n * - Requesting connection (OAuth-like flow)\n * - Authenticating with payment providers\n * - Generating notarized proofs\n * - Fetching transaction metadata\n *\n * @see {@link ZKTLSContext} for the React context provider\n */\n\nimport { useEffect, useMemo, useState } from \"react\"\nimport { encodeAbiParameters, encodePacked, parseAbiParameter, parseUnits, type Hex } from \"viem\"\nimport { sleep } from \"@provex/utils/time\"\nimport type { IntentStruct } from \"@provex/utils/intent\"\nimport type { TokenInfo } from \"@provex/utils/tokens\"\nimport { extensionPlatforms, providers, subProviderConfigs, type ActionType, type PlatformKey, type ProviderKey, type SubProviderKey } from \"@provex/utils/payment\"\nimport { convertTokenInputToCurrency } from \"@provex/utils/conversionRates\"\n\ndeclare global {\n interface ZKTLS {\n requestConnection(): Promise<boolean>\n checkConnectionStatus(): Promise<Status>\n getVersion(): Promise<string>\n authenticate(inputs: AuthenticationInputs): Promise<void>\n generateProof(inputs: GenerateProofInputs): Promise<GenerateProofResponse>\n fetchProofById(proofId: string): Promise<ProofResponse>\n fetchProofs(): Promise<FetchProofsResponse>\n openSidebar(route: string): Promise<void>\n onMetadataMessage(fn: (data: MetadataMessageResponse) => void): () => void\n }\n interface Window {\n /** @deprecated Use window.peer instead */\n zktls: ZKTLS | undefined\n /** PeerAuth extension API (replaces window.zktls) */\n peer: ZKTLS | undefined\n }\n}\n\n/** the status of the PeerAuth extension */\nexport type Status = 'connected' | 'disconnected' | 'pending'\n\n/** the individual metadata message sent by the PeerAuth extension */\nexport interface MetadataMessage {\n amount: number\n /** Currency code (e.g., 'USD', 'EUR') */\n currency?: string\n /**\n * Date of the transaction.\n * Can be a string in YYYYMMDD format, a number (YYYYMMDD or timestamp), or Date object.\n * The actual type depends on the extension implementation.\n */\n date: string | number | Date\n hidden: boolean\n originalIndex: number\n paymentId: number\n recipient: string\n}\n\n/** the response from the PeerAuth extension when a metadata message is received */\nexport interface MetadataMessageResponse {\n expiresAt: number\n platform: ProviderKey\n requestId: string\n metadata: MetadataMessage[]\n}\n\n/** the response from the PeerAuth extension when fetching proofs */\nexport interface FetchProofsResponse {\n notaryRequests: NotaryRequest[]\n}\n\n/** the inputs for the generateProof function */\nexport type GenerateProofInputsAbstracted = {\n platform: PlatformKey\n provider: ProviderKey\n intentHash: Hex\n originalIndex: number\n}\n\n/** the inputs for the generateProof function */\nexport type GenerateProofInputs = {\n platform: ProviderKey\n originalIndex: number\n proofIndex?: number\n intentHash: string\n}\n\n/**\n * inputs for the generate proof function that requires the intent hash\n * as hex to ensure it can be converted to a bigint string accurately\n */\nexport type HexIntentGenerateProofInputs = Exclude<GenerateProofInputs, 'intentHash'> & { intentHash: Hex }\n\n/** the response from the PeerAuth extension when generating a proof */\nexport type GenerateProofResponse = {\n proofId: string\n platform: ProviderKey\n}\n\n/** the inputs for the authenticate function */\nexport type AuthenticationInputs = {\n actionType: ActionType\n platform: PlatformKey\n}\n\n/** the response from the PeerAuth extension when fetching a proof */\nexport interface Proof {\n claimInfo: ClaimInfo\n signedClaim: SignedClaim\n isAppclipProof: boolean\n status: string\n}\n\n/** the response from the PeerAuth extension when fetching a proof */\nexport interface NotarizedProof {\n claim: {\n context: string\n epoch: number\n identifier: Hex\n owner: Hex\n parameters: string\n provider: string\n timestampS: number\n },\n signatures: {\n attestorAddress: Hex\n claimSignature: Record<number, number>\n resultSignature: Record<number, number>\n },\n}\n\n/** the claim info for a proof */\nexport interface ClaimInfo {\n provider: string\n parameters: string\n context: string\n}\n\n/** the complete claim data for a proof */\nexport interface CompleteClaimData {\n identifier: Hex\n owner: Hex\n timestampS: number\n epoch: number\n}\n\n/** the signed claim for a proof */\nexport interface SignedClaim {\n claim: CompleteClaimData\n signatures: Hex[]\n}\n\n/** the reclaim proof for a proof */\nexport type ReclaimProof = {\n claimInfo: ClaimInfo\n signedClaim: SignedClaim\n isAppclipProof: boolean\n}\n\n/** the notary request for a proof */\nexport interface NotaryRequest {\n metadata: (string | number)[]\n actionType: ActionType\n id: string\n status: string\n timestamp: number\n proof: NotarizedProof\n}\n\n/** the response from the PeerAuth extension when fetching a proof */\nexport interface ProofResponse {\n notaryRequest: NotaryRequest\n}\n\nexport const extensionUrl = 'https://chromewebstore.google.com/detail/ijpgccednehjpeclfcllnjjcmiohdjih'\n\n/** convert a byte array to a hex string */\nexport const byteArrayToHexString = (byteArray: number[]): Hex => {\n return `0x${byteArray\n .map(byte => byte.toString(16).padStart(2, '0'))\n .join('')}`\n}\n\n/** parse a proof object from the PeerAuth extension */\nexport const parseExtensionProof = (proofObject: NotarizedProof) => {\n return {\n claimInfo: {\n provider: proofObject.claim.provider,\n parameters: proofObject.claim.parameters,\n context: proofObject.claim.context\n },\n signedClaim: {\n claim: {\n identifier: proofObject.claim.identifier as Hex,\n owner: proofObject.claim.owner as Hex,\n timestampS: proofObject.claim.timestampS,\n epoch: proofObject.claim.epoch\n },\n signatures: [byteArrayToHexString(Object.values(proofObject.signatures.claimSignature))]\n },\n isAppclipProof: false\n } as ReclaimProof\n}\n\n/** the abi encoding for a proof */\nexport const PROOF_ENCODING = parseAbiParameter(\"((string provider, string parameters, string context) claimInfo, ((bytes32 identifier, address owner, uint32 timestampS, uint32 epoch) claim, bytes[] signatures) signedClaim, bool isAppclipProof)\")\n\n/** encode a single proof as a bytes array */\nexport function encodeProofAsBytes(proof: ReclaimProof): Hex {\n return encodeAbiParameters([PROOF_ENCODING], [proof])\n}\n\n/** encode two proofs to be passed to the underlying sub-provider */\nexport const encodeTwoProofs = (proof1: ReclaimProof, proof2: ReclaimProof) => {\n return encodeAbiParameters([PROOF_ENCODING, PROOF_ENCODING], [proof1, proof2])\n}\n\n/** a high level function to encode a proof for a given provider and sub-provider */\nexport const encodeProof = ({ extensionProofs, subProvider, provider }: {\n extensionProofs: NotarizedProof[],\n subProvider: PlatformKey | null,\n provider: ProviderKey\n}) => {\n const reclaimProofs = extensionProofs.map((p) => parseExtensionProof(p))\n if (provider === 'zelle') {\n // move this to check the blockchain for the payment method\n const paymentMethod = subProviderConfigs![provider]![subProvider as SubProviderKey]!.paymentMethod\n const twoEncoded = reclaimProofs.length === 2\n ? encodeTwoProofs(reclaimProofs[0]!, reclaimProofs[1]!)\n : encodeProofAsBytes(reclaimProofs[0]!)\n // select between various possible sub-providers\n const withPaymentMethod = encodeProofWithPaymentMethod({\n paymentMethod,\n proof: twoEncoded,\n })\n return withPaymentMethod\n }\n const [reclaimProof] = reclaimProofs\n return encodeProofAsBytes(reclaimProof!)\n}\n\n/**\n * wrap a proof with a payment method and proof\n * this allows us to use a single verifier as an entry point for multiple underlying sub-providers\n */\nexport const encodeProofWithPaymentMethod = ({\n proof,\n paymentMethod\n}: {\n proof: Hex,\n paymentMethod: number\n}): Hex => {\n return encodePacked(['uint8', 'bytes'], [paymentMethod, proof])\n}\n\n/** the progress of a proof series */\nexport enum SeriesProgress {\n Generating,\n Polling,\n Complete,\n}\n\nexport type ProgressInfo = {\n progress: SeriesProgress\n total: number\n step: number | null\n id: string | null\n}\n\n/** the mutations for the generate proof series function */\nexport type GenerateProofSeriesMutations = {\n progress?: ({ progress, step, id }: ProgressInfo) => void\n setOwnerName?: (name: string) => void\n}\n\n/** React hook to interact with the PeerAuth extension */\nexport const useZKTLS = () => {\n const [isInitialized, setIsInitialized] = useState(false)\n useEffect(() => {\n const setup = () => {\n setIsInitialized(true)\n }\n const eventName = 'peer#initialized'\n if (typeof window.peer !== 'undefined') {\n // api is available\n setup()\n } else {\n window.addEventListener(eventName, setup)\n return () => {\n window.removeEventListener(eventName, setup)\n }\n }\n }, [])\n return useMemo(() => {\n /** fetch a proof by its id */\n const fetchProofById = async (proofId: string): Promise<NotaryRequest | null> => {\n const proof = await window.peer!.fetchProofById(proofId)\n if (proof && proof.notaryRequest) return proof.notaryRequest\n const proofs = await window.peer!.fetchProofs()\n const proofFromList = proofs.notaryRequests.find((p) => p.id === proofId)\n if (proofFromList) return proofFromList\n return null\n }\n /** wait for a proof to be generated */\n const waitForProof = async (proofId: string, onCurrent?: (notaryRequest: NotaryRequest | null) => void) => {\n let notaryRequest: NotaryRequest | null = null\n do {\n notaryRequest = await fetchProofById(proofId)\n onCurrent?.(notaryRequest)\n await sleep(1_000)\n } while (!notaryRequest || !notaryRequest.status || notaryRequest.status === 'pending')\n if (notaryRequest.status === 'failed' || notaryRequest.status === 'expired' || notaryRequest.status === 'cancelled' || notaryRequest.status === 'error') {\n console.error('[waitForProof] proof terminal state:', JSON.stringify(notaryRequest, null, 2))\n const req = notaryRequest as unknown as Record<string, unknown>\n const detail = req.errorMessage ?? req.error ?? req.message ?? notaryRequest.status\n throw new Error(`Proof generation failed: ${detail}`)\n }\n return notaryRequest\n }\n /** generate a proof */\n const generateProof = async (inputs: HexIntentGenerateProofInputs): Promise<GenerateProofResponse> => {\n return await window.peer!.generateProof({\n proofIndex: 0,\n ...inputs,\n intentHash: BigInt(inputs.intentHash).toString(),\n })\n }\n return {\n /** check if the PeerAuth extension is initialized */\n isInitialized,\n /** request a connection to the PeerAuth extension */\n requestConnection: async () => {\n if (!window.peer) return false\n return window.peer!.requestConnection()\n },\n /**\n * check the connection status of the PeerAuth extension\n * @returns the connection status\n */\n checkConnectionStatus: async () => {\n return await window.peer!.checkConnectionStatus()\n },\n /** get the version of the PeerAuth extension */\n getVersion: async () => {\n return await window.peer?.getVersion()\n },\n /** authenticate with the PeerAuth extension */\n authenticate: async (inputs: AuthenticationInputs) => {\n // Create promise first to avoid race condition where message arrives before resolver is assigned\n let resolve: (value: MetadataMessageResponse) => void\n const promise = new Promise<MetadataMessageResponse>((resolver) => {\n resolve = resolver\n })\n\n // Now set up the listener - resolve is guaranteed to be the real resolver\n const unsub = window.peer!.onMetadataMessage((data) => {\n if (`transfer_${data.platform}` === inputs.actionType) {\n resolve(data)\n }\n })\n\n await window.peer!.authenticate(inputs)\n\n return await promise.then((data) => {\n unsub()\n return data\n })\n },\n /** generate a proof */\n generateProof,\n /** wait for a proof to be generated */\n waitForProof,\n /** generate a proof series */\n generateProofSeries: async (\n inputs: GenerateProofInputsAbstracted,\n { progress: progressCallback }: GenerateProofSeriesMutations = {},\n ): Promise<NotaryRequest[]> => {\n const { platform, provider, intentHash, originalIndex } = inputs\n const args = {\n platform: provider,\n originalIndex,\n intentHash,\n } as const\n // Chase requires 2 proofs (account verification + transaction)\n // Platform is the bank name (e.g., 'chase') from extensionPlatform config\n const isChase = platform === extensionPlatforms.CHASE\n const isZelle = provider === providers.ZELLE\n const expectedTotal = isZelle && isChase ? 2 : 1\n progressCallback?.({ progress: SeriesProgress.Generating, step: 0, id: null, total: expectedTotal })\n const genProofA = await generateProof({ ...args, proofIndex: 0 })\n progressCallback?.({ progress: SeriesProgress.Polling, step: 0, id: genProofA.proofId, total: expectedTotal })\n const proofA = await waitForProof(genProofA.proofId)\n if (!isChase || !isZelle) {\n progressCallback?.({ progress: SeriesProgress.Complete, step: null, id: null, total: expectedTotal })\n return [proofA]\n }\n progressCallback?.({ progress: SeriesProgress.Generating, step: 1, id: null, total: expectedTotal })\n const genProofB = await generateProof({ ...args, proofIndex: 1 })\n progressCallback?.({ progress: SeriesProgress.Polling, step: 1, id: genProofB.proofId, total: expectedTotal })\n const proofB = await waitForProof(genProofB.proofId)\n progressCallback?.({ progress: SeriesProgress.Complete, step: null, id: null, total: expectedTotal })\n return [proofA, proofB]\n },\n /** subscribe to metadata messages */\n onMetadataMessage: (fn: (data: any) => void) => {\n return window.peer!.onMetadataMessage(fn)\n },\n /** fetch a proof by its id */\n fetchProofById,\n /** fetch generated proofs */\n fetchGeneratedProofs: async (genProofResponses: GenerateProofResponse[]) => {\n return await Promise.all(genProofResponses.map((r) => fetchProofById(r.proofId)))\n },\n /** fetch all proofs */\n fetchProofs: async () => {\n return await window.peer!.fetchProofs()\n },\n /** open the PeerAuth sidebar */\n openSidebar: async (route: string) => {\n return await window.peer!.openSidebar(route)\n },\n }\n }, [isInitialized])\n}\n\n/**\n * Find the metadata message that matches the intent by amount.\n * Returns the first (most recent) transaction in the metadata array that matches the expected amount.\n *\n * Simplified matching: just find transactions with the correct amount.\n * The user can manually select if multiple matches exist.\n */\nexport const findMetadataMessage = ({ metadata, intent, token, centIsInt = false }: {\n metadata: MetadataMessage[],\n intent: IntentStruct,\n token: TokenInfo,\n /** @deprecated No longer used - kept for API compatibility */\n recipient?: string,\n centIsInt?: boolean,\n}): MetadataMessage | null => {\n const currencyAmount = convertTokenInputToCurrency({\n token,\n amountOutInt: intent.amount,\n rate: intent.conversionRate,\n })\n /**\n * Normalize an amount from the extension into a bigint in token base units.\n *\n * The extension sends amounts in different formats per provider:\n * - Venmo: `\"- $1.00\"` (formatted dollar string)\n * - Others: `100` (integer cents) or `1.00` (decimal dollars)\n *\n * We detect the format by checking for currency symbols or decimal points\n * in the raw value. If present, the value is already in dollars and we\n * skip the centIsInt division.\n */\n const normalizeAmount = (amount: number | string): bigint => {\n const raw = String(amount)\n const isFormattedDollars = /[^0-9\\-]/.test(raw) && raw.includes('.')\n const cleaned = raw.replace(/[^0-9.]/g, '')\n let value = parseUnits(cleaned, token.decimals)\n if (centIsInt && !isFormattedDollars) {\n value = value / 100n\n }\n return value\n }\n\n // Skip auto-match when manual selection is forced (dev/testing)\n if (typeof window !== 'undefined' && (window as unknown as Record<string, unknown>).__FORCE_MANUAL_TX_SELECT__) {\n return null\n }\n\n // Find the first transaction that matches the amount (first in array = most recent)\n // Note: We ignore the hidden flag - matching is purely by amount\n const match = metadata.find((m) => {\n const converted = normalizeAmount(m.amount)\n return converted === currencyAmount || converted === (currencyAmount * -1n)\n })\n\n if (!match) {\n // Detect 100x scale mismatch — the most common failure mode when centIsInt\n // is wrong for a provider. Fires loudly so it's obvious in dev/staging logs.\n const hundredxMatch = metadata.find((m) => {\n const converted = normalizeAmount(m.amount)\n const abs = converted < 0n ? -converted : converted\n return abs === currencyAmount * 100n || abs * 100n === currencyAmount\n })\n if (hundredxMatch) {\n console.warn(\n `[findMetadataMessage] tx[0] amount=${String(hundredxMatch.amount)} is 100x off from expected ${currencyAmount.toString()} — centIsInt is likely wrong for this provider (currently ${centIsInt})`\n )\n }\n return null\n }\n\n return match\n}\n"]}
|
package/dist/index.cjs
CHANGED
|
@@ -97,7 +97,10 @@ var useZKTLS = () => {
|
|
|
97
97
|
await time.sleep(1e3);
|
|
98
98
|
} while (!notaryRequest || !notaryRequest.status || notaryRequest.status === "pending");
|
|
99
99
|
if (notaryRequest.status === "failed" || notaryRequest.status === "expired" || notaryRequest.status === "cancelled" || notaryRequest.status === "error") {
|
|
100
|
-
|
|
100
|
+
console.error("[waitForProof] proof terminal state:", JSON.stringify(notaryRequest, null, 2));
|
|
101
|
+
const req = notaryRequest;
|
|
102
|
+
const detail = req.errorMessage ?? req.error ?? req.message ?? notaryRequest.status;
|
|
103
|
+
throw new Error(`Proof generation failed: ${detail}`);
|
|
101
104
|
}
|
|
102
105
|
return notaryRequest;
|
|
103
106
|
};
|
|
@@ -219,6 +222,16 @@ var findMetadataMessage = ({ metadata, intent, token, centIsInt = false }) => {
|
|
|
219
222
|
return converted === currencyAmount || converted === currencyAmount * -1n;
|
|
220
223
|
});
|
|
221
224
|
if (!match) {
|
|
225
|
+
const hundredxMatch = metadata.find((m) => {
|
|
226
|
+
const converted = normalizeAmount(m.amount);
|
|
227
|
+
const abs = converted < 0n ? -converted : converted;
|
|
228
|
+
return abs === currencyAmount * 100n || abs * 100n === currencyAmount;
|
|
229
|
+
});
|
|
230
|
+
if (hundredxMatch) {
|
|
231
|
+
console.warn(
|
|
232
|
+
`[findMetadataMessage] tx[0] amount=${String(hundredxMatch.amount)} is 100x off from expected ${currencyAmount.toString()} \u2014 centIsInt is likely wrong for this provider (currently ${centIsInt})`
|
|
233
|
+
);
|
|
234
|
+
}
|
|
222
235
|
return null;
|
|
223
236
|
}
|
|
224
237
|
return match;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useZKTLS.ts","../src/ZKTLSContext.tsx"],"names":["parseAbiParameter","encodeAbiParameters","subProviderConfigs","encodePacked","SeriesProgress","useState","useEffect","useMemo","sleep","extensionPlatforms","providers","convertTokenInputToCurrency","parseUnits","createContext","useContext"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * @fileoverview React hook and utilities for PeerAuth browser extension integration.\n *\n * The PeerAuth extension (formerly ZK-TLS) provides secure proof generation\n * for off-chain payment verification. This module provides:\n *\n * 1. Type definitions for extension API (window.peer)\n * 2. useZKTLS hook for React components\n * 3. Utility functions for transaction matching and proof encoding\n *\n * @remarks\n * The extension exposes `window.peer` (or deprecated `window.zktls`) for:\n * - Requesting connection (OAuth-like flow)\n * - Authenticating with payment providers\n * - Generating notarized proofs\n * - Fetching transaction metadata\n *\n * @see {@link ZKTLSContext} for the React context provider\n */\n\nimport { useEffect, useMemo, useState } from \"react\"\nimport { encodeAbiParameters, encodePacked, parseAbiParameter, parseUnits, type Hex } from \"viem\"\nimport { sleep } from \"@provex/utils/time\"\nimport type { IntentStruct } from \"@provex/utils/intent\"\nimport type { TokenInfo } from \"@provex/utils/tokens\"\nimport { extensionPlatforms, providers, subProviderConfigs, type ActionType, type PlatformKey, type ProviderKey, type SubProviderKey } from \"@provex/utils/payment\"\nimport { convertTokenInputToCurrency } from \"@provex/utils/conversionRates\"\n\ndeclare global {\n interface ZKTLS {\n requestConnection(): Promise<boolean>\n checkConnectionStatus(): Promise<Status>\n getVersion(): Promise<string>\n authenticate(inputs: AuthenticationInputs): Promise<void>\n generateProof(inputs: GenerateProofInputs): Promise<GenerateProofResponse>\n fetchProofById(proofId: string): Promise<ProofResponse>\n fetchProofs(): Promise<FetchProofsResponse>\n openSidebar(route: string): Promise<void>\n onMetadataMessage(fn: (data: MetadataMessageResponse) => void): () => void\n }\n interface Window {\n /** @deprecated Use window.peer instead */\n zktls: ZKTLS | undefined\n /** PeerAuth extension API (replaces window.zktls) */\n peer: ZKTLS | undefined\n }\n}\n\n/** the status of the PeerAuth extension */\nexport type Status = 'connected' | 'disconnected' | 'pending'\n\n/** the individual metadata message sent by the PeerAuth extension */\nexport interface MetadataMessage {\n amount: number\n /** Currency code (e.g., 'USD', 'EUR') */\n currency?: string\n /**\n * Date of the transaction.\n * Can be a string in YYYYMMDD format, a number (YYYYMMDD or timestamp), or Date object.\n * The actual type depends on the extension implementation.\n */\n date: string | number | Date\n hidden: boolean\n originalIndex: number\n paymentId: number\n recipient: string\n}\n\n/** the response from the PeerAuth extension when a metadata message is received */\nexport interface MetadataMessageResponse {\n expiresAt: number\n platform: ProviderKey\n requestId: string\n metadata: MetadataMessage[]\n}\n\n/** the response from the PeerAuth extension when fetching proofs */\nexport interface FetchProofsResponse {\n notaryRequests: NotaryRequest[]\n}\n\n/** the inputs for the generateProof function */\nexport type GenerateProofInputsAbstracted = {\n platform: PlatformKey\n provider: ProviderKey\n intentHash: Hex\n originalIndex: number\n}\n\n/** the inputs for the generateProof function */\nexport type GenerateProofInputs = {\n platform: ProviderKey\n originalIndex: number\n proofIndex?: number\n intentHash: string\n}\n\n/**\n * inputs for the generate proof function that requires the intent hash\n * as hex to ensure it can be converted to a bigint string accurately\n */\nexport type HexIntentGenerateProofInputs = Exclude<GenerateProofInputs, 'intentHash'> & { intentHash: Hex }\n\n/** the response from the PeerAuth extension when generating a proof */\nexport type GenerateProofResponse = {\n proofId: string\n platform: ProviderKey\n}\n\n/** the inputs for the authenticate function */\nexport type AuthenticationInputs = {\n actionType: ActionType\n platform: PlatformKey\n}\n\n/** the response from the PeerAuth extension when fetching a proof */\nexport interface Proof {\n claimInfo: ClaimInfo\n signedClaim: SignedClaim\n isAppclipProof: boolean\n status: string\n}\n\n/** the response from the PeerAuth extension when fetching a proof */\nexport interface NotarizedProof {\n claim: {\n context: string\n epoch: number\n identifier: Hex\n owner: Hex\n parameters: string\n provider: string\n timestampS: number\n },\n signatures: {\n attestorAddress: Hex\n claimSignature: Record<number, number>\n resultSignature: Record<number, number>\n },\n}\n\n/** the claim info for a proof */\nexport interface ClaimInfo {\n provider: string\n parameters: string\n context: string\n}\n\n/** the complete claim data for a proof */\nexport interface CompleteClaimData {\n identifier: Hex\n owner: Hex\n timestampS: number\n epoch: number\n}\n\n/** the signed claim for a proof */\nexport interface SignedClaim {\n claim: CompleteClaimData\n signatures: Hex[]\n}\n\n/** the reclaim proof for a proof */\nexport type ReclaimProof = {\n claimInfo: ClaimInfo\n signedClaim: SignedClaim\n isAppclipProof: boolean\n}\n\n/** the notary request for a proof */\nexport interface NotaryRequest {\n metadata: (string | number)[]\n actionType: ActionType\n id: string\n status: string\n timestamp: number\n proof: NotarizedProof\n}\n\n/** the response from the PeerAuth extension when fetching a proof */\nexport interface ProofResponse {\n notaryRequest: NotaryRequest\n}\n\nexport const extensionUrl = 'https://chromewebstore.google.com/detail/ijpgccednehjpeclfcllnjjcmiohdjih'\n\n/** convert a byte array to a hex string */\nexport const byteArrayToHexString = (byteArray: number[]): Hex => {\n return `0x${byteArray\n .map(byte => byte.toString(16).padStart(2, '0'))\n .join('')}`\n}\n\n/** parse a proof object from the PeerAuth extension */\nexport const parseExtensionProof = (proofObject: NotarizedProof) => {\n return {\n claimInfo: {\n provider: proofObject.claim.provider,\n parameters: proofObject.claim.parameters,\n context: proofObject.claim.context\n },\n signedClaim: {\n claim: {\n identifier: proofObject.claim.identifier as Hex,\n owner: proofObject.claim.owner as Hex,\n timestampS: proofObject.claim.timestampS,\n epoch: proofObject.claim.epoch\n },\n signatures: [byteArrayToHexString(Object.values(proofObject.signatures.claimSignature))]\n },\n isAppclipProof: false\n } as ReclaimProof\n}\n\n/** the abi encoding for a proof */\nexport const PROOF_ENCODING = parseAbiParameter(\"((string provider, string parameters, string context) claimInfo, ((bytes32 identifier, address owner, uint32 timestampS, uint32 epoch) claim, bytes[] signatures) signedClaim, bool isAppclipProof)\")\n\n/** encode a single proof as a bytes array */\nexport function encodeProofAsBytes(proof: ReclaimProof): Hex {\n return encodeAbiParameters([PROOF_ENCODING], [proof])\n}\n\n/** encode two proofs to be passed to the underlying sub-provider */\nexport const encodeTwoProofs = (proof1: ReclaimProof, proof2: ReclaimProof) => {\n return encodeAbiParameters([PROOF_ENCODING, PROOF_ENCODING], [proof1, proof2])\n}\n\n/** a high level function to encode a proof for a given provider and sub-provider */\nexport const encodeProof = ({ extensionProofs, subProvider, provider }: {\n extensionProofs: NotarizedProof[],\n subProvider: PlatformKey | null,\n provider: ProviderKey\n}) => {\n const reclaimProofs = extensionProofs.map((p) => parseExtensionProof(p))\n if (provider === 'zelle') {\n // move this to check the blockchain for the payment method\n const paymentMethod = subProviderConfigs![provider]![subProvider as SubProviderKey]!.paymentMethod\n const twoEncoded = reclaimProofs.length === 2\n ? encodeTwoProofs(reclaimProofs[0]!, reclaimProofs[1]!)\n : encodeProofAsBytes(reclaimProofs[0]!)\n // select between various possible sub-providers\n const withPaymentMethod = encodeProofWithPaymentMethod({\n paymentMethod,\n proof: twoEncoded,\n })\n return withPaymentMethod\n }\n const [reclaimProof] = reclaimProofs\n return encodeProofAsBytes(reclaimProof!)\n}\n\n/**\n * wrap a proof with a payment method and proof\n * this allows us to use a single verifier as an entry point for multiple underlying sub-providers\n */\nexport const encodeProofWithPaymentMethod = ({\n proof,\n paymentMethod\n}: {\n proof: Hex,\n paymentMethod: number\n}): Hex => {\n return encodePacked(['uint8', 'bytes'], [paymentMethod, proof])\n}\n\n/** the progress of a proof series */\nexport enum SeriesProgress {\n Generating,\n Polling,\n Complete,\n}\n\nexport type ProgressInfo = {\n progress: SeriesProgress\n total: number\n step: number | null\n id: string | null\n}\n\n/** the mutations for the generate proof series function */\nexport type GenerateProofSeriesMutations = {\n progress?: ({ progress, step, id }: ProgressInfo) => void\n setOwnerName?: (name: string) => void\n}\n\n/** React hook to interact with the PeerAuth extension */\nexport const useZKTLS = () => {\n const [isInitialized, setIsInitialized] = useState(false)\n useEffect(() => {\n const setup = () => {\n setIsInitialized(true)\n }\n const eventName = 'peer#initialized'\n if (typeof window.peer !== 'undefined') {\n // api is available\n setup()\n } else {\n window.addEventListener(eventName, setup)\n return () => {\n window.removeEventListener(eventName, setup)\n }\n }\n }, [])\n return useMemo(() => {\n /** fetch a proof by its id */\n const fetchProofById = async (proofId: string): Promise<NotaryRequest | null> => {\n const proof = await window.peer!.fetchProofById(proofId)\n if (proof && proof.notaryRequest) return proof.notaryRequest\n const proofs = await window.peer!.fetchProofs()\n const proofFromList = proofs.notaryRequests.find((p) => p.id === proofId)\n if (proofFromList) return proofFromList\n return null\n }\n /** wait for a proof to be generated */\n const waitForProof = async (proofId: string, onCurrent?: (notaryRequest: NotaryRequest | null) => void) => {\n let notaryRequest: NotaryRequest | null = null\n do {\n notaryRequest = await fetchProofById(proofId)\n onCurrent?.(notaryRequest)\n await sleep(1_000)\n } while (!notaryRequest || !notaryRequest.status || notaryRequest.status === 'pending')\n if (notaryRequest.status === 'failed' || notaryRequest.status === 'expired' || notaryRequest.status === 'cancelled' || notaryRequest.status === 'error') {\n throw new Error(`Proof generation failed: ${notaryRequest.status}`)\n }\n return notaryRequest\n }\n /** generate a proof */\n const generateProof = async (inputs: HexIntentGenerateProofInputs): Promise<GenerateProofResponse> => {\n return await window.peer!.generateProof({\n proofIndex: 0,\n ...inputs,\n intentHash: BigInt(inputs.intentHash).toString(),\n })\n }\n return {\n /** check if the PeerAuth extension is initialized */\n isInitialized,\n /** request a connection to the PeerAuth extension */\n requestConnection: async () => {\n if (!window.peer) return false\n return window.peer!.requestConnection()\n },\n /**\n * check the connection status of the PeerAuth extension\n * @returns the connection status\n */\n checkConnectionStatus: async () => {\n return await window.peer!.checkConnectionStatus()\n },\n /** get the version of the PeerAuth extension */\n getVersion: async () => {\n return await window.peer?.getVersion()\n },\n /** authenticate with the PeerAuth extension */\n authenticate: async (inputs: AuthenticationInputs) => {\n // Create promise first to avoid race condition where message arrives before resolver is assigned\n let resolve: (value: MetadataMessageResponse) => void\n const promise = new Promise<MetadataMessageResponse>((resolver) => {\n resolve = resolver\n })\n\n // Now set up the listener - resolve is guaranteed to be the real resolver\n const unsub = window.peer!.onMetadataMessage((data) => {\n if (`transfer_${data.platform}` === inputs.actionType) {\n resolve(data)\n }\n })\n\n await window.peer!.authenticate(inputs)\n\n return await promise.then((data) => {\n unsub()\n return data\n })\n },\n /** generate a proof */\n generateProof,\n /** wait for a proof to be generated */\n waitForProof,\n /** generate a proof series */\n generateProofSeries: async (\n inputs: GenerateProofInputsAbstracted,\n { progress: progressCallback }: GenerateProofSeriesMutations = {},\n ): Promise<NotaryRequest[]> => {\n const { platform, provider, intentHash, originalIndex } = inputs\n const args = {\n platform: provider,\n originalIndex,\n intentHash,\n } as const\n // Chase requires 2 proofs (account verification + transaction)\n // Platform is the bank name (e.g., 'chase') from extensionPlatform config\n const isChase = platform === extensionPlatforms.CHASE\n const isZelle = provider === providers.ZELLE\n const expectedTotal = isZelle && isChase ? 2 : 1\n progressCallback?.({ progress: SeriesProgress.Generating, step: 0, id: null, total: expectedTotal })\n const genProofA = await generateProof({ ...args, proofIndex: 0 })\n progressCallback?.({ progress: SeriesProgress.Polling, step: 0, id: genProofA.proofId, total: expectedTotal })\n const proofA = await waitForProof(genProofA.proofId)\n if (!isChase || !isZelle) {\n progressCallback?.({ progress: SeriesProgress.Complete, step: null, id: null, total: expectedTotal })\n return [proofA]\n }\n progressCallback?.({ progress: SeriesProgress.Generating, step: 1, id: null, total: expectedTotal })\n const genProofB = await generateProof({ ...args, proofIndex: 1 })\n progressCallback?.({ progress: SeriesProgress.Polling, step: 1, id: genProofB.proofId, total: expectedTotal })\n const proofB = await waitForProof(genProofB.proofId)\n progressCallback?.({ progress: SeriesProgress.Complete, step: null, id: null, total: expectedTotal })\n return [proofA, proofB]\n },\n /** subscribe to metadata messages */\n onMetadataMessage: (fn: (data: any) => void) => {\n return window.peer!.onMetadataMessage(fn)\n },\n /** fetch a proof by its id */\n fetchProofById,\n /** fetch generated proofs */\n fetchGeneratedProofs: async (genProofResponses: GenerateProofResponse[]) => {\n return await Promise.all(genProofResponses.map((r) => fetchProofById(r.proofId)))\n },\n /** fetch all proofs */\n fetchProofs: async () => {\n return await window.peer!.fetchProofs()\n },\n /** open the PeerAuth sidebar */\n openSidebar: async (route: string) => {\n return await window.peer!.openSidebar(route)\n },\n }\n }, [isInitialized])\n}\n\n/**\n * Find the metadata message that matches the intent by amount.\n * Returns the first (most recent) transaction in the metadata array that matches the expected amount.\n *\n * Simplified matching: just find transactions with the correct amount.\n * The user can manually select if multiple matches exist.\n */\nexport const findMetadataMessage = ({ metadata, intent, token, centIsInt = false }: {\n metadata: MetadataMessage[],\n intent: IntentStruct,\n token: TokenInfo,\n /** @deprecated No longer used - kept for API compatibility */\n recipient?: string,\n centIsInt?: boolean,\n}): MetadataMessage | null => {\n const currencyAmount = convertTokenInputToCurrency({\n token,\n amountOutInt: intent.amount,\n rate: intent.conversionRate,\n })\n /**\n * Normalize an amount from the extension into a bigint in token base units.\n *\n * The extension sends amounts in different formats per provider:\n * - Venmo: `\"- $1.00\"` (formatted dollar string)\n * - Others: `100` (integer cents) or `1.00` (decimal dollars)\n *\n * We detect the format by checking for currency symbols or decimal points\n * in the raw value. If present, the value is already in dollars and we\n * skip the centIsInt division.\n */\n const normalizeAmount = (amount: number | string): bigint => {\n const raw = String(amount)\n const isFormattedDollars = /[^0-9\\-]/.test(raw) && raw.includes('.')\n const cleaned = raw.replace(/[^0-9.]/g, '')\n let value = parseUnits(cleaned, token.decimals)\n if (centIsInt && !isFormattedDollars) {\n value = value / 100n\n }\n return value\n }\n\n // Skip auto-match when manual selection is forced (dev/testing)\n if (typeof window !== 'undefined' && (window as unknown as Record<string, unknown>).__FORCE_MANUAL_TX_SELECT__) {\n return null\n }\n\n // Find the first transaction that matches the amount (first in array = most recent)\n // Note: We ignore the hidden flag - matching is purely by amount\n const match = metadata.find((m) => {\n const converted = normalizeAmount(m.amount)\n return converted === currencyAmount || converted === (currencyAmount * -1n)\n })\n\n if (!match) {\n return null\n }\n\n return match\n}\n","/**\n * @fileoverview React context for PeerAuth extension state.\n *\n * Provides global access to the useZKTLS hook state throughout the\n * component tree, avoiding prop drilling for extension status.\n *\n * @see {@link useZKTLS} for the underlying hook\n */\n\nimport { createContext, useContext, type ReactNode } from 'react'\nimport { useZKTLS } from './useZKTLS'\n\n/**\n * Context type derived from useZKTLS hook return value.\n */\ntype ZKTLSContextType = ReturnType<typeof useZKTLS>\n\nexport const ZKTLSContext = createContext<ZKTLSContextType | undefined>(undefined)\n\ninterface ZKTLSProviderProps {\n children: ReactNode\n}\n\n/**\n * Hook to consume the ZKTLS context.\n * Must be used within a ZKTLSProvider.\n *\n * @throws Error if used outside of ZKTLSProvider\n */\nexport function useZKTLSContext() {\n const context = useContext(ZKTLSContext)\n if (context === undefined) {\n throw new Error('useZKTLSContext must be used within a ZKTLSProvider')\n }\n return context\n}\n\nexport function ZKTLSProvider({ children }: ZKTLSProviderProps) {\n const zktlsHook = useZKTLS()\n\n return (\n <ZKTLSContext.Provider value={zktlsHook}>\n {children}\n </ZKTLSContext.Provider>\n )\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/useZKTLS.ts","../src/ZKTLSContext.tsx"],"names":["parseAbiParameter","encodeAbiParameters","subProviderConfigs","encodePacked","SeriesProgress","useState","useEffect","useMemo","sleep","extensionPlatforms","providers","convertTokenInputToCurrency","parseUnits","createContext","useContext"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * @fileoverview React hook and utilities for PeerAuth browser extension integration.\n *\n * The PeerAuth extension (formerly ZK-TLS) provides secure proof generation\n * for off-chain payment verification. This module provides:\n *\n * 1. Type definitions for extension API (window.peer)\n * 2. useZKTLS hook for React components\n * 3. Utility functions for transaction matching and proof encoding\n *\n * @remarks\n * The extension exposes `window.peer` (or deprecated `window.zktls`) for:\n * - Requesting connection (OAuth-like flow)\n * - Authenticating with payment providers\n * - Generating notarized proofs\n * - Fetching transaction metadata\n *\n * @see {@link ZKTLSContext} for the React context provider\n */\n\nimport { useEffect, useMemo, useState } from \"react\"\nimport { encodeAbiParameters, encodePacked, parseAbiParameter, parseUnits, type Hex } from \"viem\"\nimport { sleep } from \"@provex/utils/time\"\nimport type { IntentStruct } from \"@provex/utils/intent\"\nimport type { TokenInfo } from \"@provex/utils/tokens\"\nimport { extensionPlatforms, providers, subProviderConfigs, type ActionType, type PlatformKey, type ProviderKey, type SubProviderKey } from \"@provex/utils/payment\"\nimport { convertTokenInputToCurrency } from \"@provex/utils/conversionRates\"\n\ndeclare global {\n interface ZKTLS {\n requestConnection(): Promise<boolean>\n checkConnectionStatus(): Promise<Status>\n getVersion(): Promise<string>\n authenticate(inputs: AuthenticationInputs): Promise<void>\n generateProof(inputs: GenerateProofInputs): Promise<GenerateProofResponse>\n fetchProofById(proofId: string): Promise<ProofResponse>\n fetchProofs(): Promise<FetchProofsResponse>\n openSidebar(route: string): Promise<void>\n onMetadataMessage(fn: (data: MetadataMessageResponse) => void): () => void\n }\n interface Window {\n /** @deprecated Use window.peer instead */\n zktls: ZKTLS | undefined\n /** PeerAuth extension API (replaces window.zktls) */\n peer: ZKTLS | undefined\n }\n}\n\n/** the status of the PeerAuth extension */\nexport type Status = 'connected' | 'disconnected' | 'pending'\n\n/** the individual metadata message sent by the PeerAuth extension */\nexport interface MetadataMessage {\n amount: number\n /** Currency code (e.g., 'USD', 'EUR') */\n currency?: string\n /**\n * Date of the transaction.\n * Can be a string in YYYYMMDD format, a number (YYYYMMDD or timestamp), or Date object.\n * The actual type depends on the extension implementation.\n */\n date: string | number | Date\n hidden: boolean\n originalIndex: number\n paymentId: number\n recipient: string\n}\n\n/** the response from the PeerAuth extension when a metadata message is received */\nexport interface MetadataMessageResponse {\n expiresAt: number\n platform: ProviderKey\n requestId: string\n metadata: MetadataMessage[]\n}\n\n/** the response from the PeerAuth extension when fetching proofs */\nexport interface FetchProofsResponse {\n notaryRequests: NotaryRequest[]\n}\n\n/** the inputs for the generateProof function */\nexport type GenerateProofInputsAbstracted = {\n platform: PlatformKey\n provider: ProviderKey\n intentHash: Hex\n originalIndex: number\n}\n\n/** the inputs for the generateProof function */\nexport type GenerateProofInputs = {\n platform: ProviderKey\n originalIndex: number\n proofIndex?: number\n intentHash: string\n}\n\n/**\n * inputs for the generate proof function that requires the intent hash\n * as hex to ensure it can be converted to a bigint string accurately\n */\nexport type HexIntentGenerateProofInputs = Exclude<GenerateProofInputs, 'intentHash'> & { intentHash: Hex }\n\n/** the response from the PeerAuth extension when generating a proof */\nexport type GenerateProofResponse = {\n proofId: string\n platform: ProviderKey\n}\n\n/** the inputs for the authenticate function */\nexport type AuthenticationInputs = {\n actionType: ActionType\n platform: PlatformKey\n}\n\n/** the response from the PeerAuth extension when fetching a proof */\nexport interface Proof {\n claimInfo: ClaimInfo\n signedClaim: SignedClaim\n isAppclipProof: boolean\n status: string\n}\n\n/** the response from the PeerAuth extension when fetching a proof */\nexport interface NotarizedProof {\n claim: {\n context: string\n epoch: number\n identifier: Hex\n owner: Hex\n parameters: string\n provider: string\n timestampS: number\n },\n signatures: {\n attestorAddress: Hex\n claimSignature: Record<number, number>\n resultSignature: Record<number, number>\n },\n}\n\n/** the claim info for a proof */\nexport interface ClaimInfo {\n provider: string\n parameters: string\n context: string\n}\n\n/** the complete claim data for a proof */\nexport interface CompleteClaimData {\n identifier: Hex\n owner: Hex\n timestampS: number\n epoch: number\n}\n\n/** the signed claim for a proof */\nexport interface SignedClaim {\n claim: CompleteClaimData\n signatures: Hex[]\n}\n\n/** the reclaim proof for a proof */\nexport type ReclaimProof = {\n claimInfo: ClaimInfo\n signedClaim: SignedClaim\n isAppclipProof: boolean\n}\n\n/** the notary request for a proof */\nexport interface NotaryRequest {\n metadata: (string | number)[]\n actionType: ActionType\n id: string\n status: string\n timestamp: number\n proof: NotarizedProof\n}\n\n/** the response from the PeerAuth extension when fetching a proof */\nexport interface ProofResponse {\n notaryRequest: NotaryRequest\n}\n\nexport const extensionUrl = 'https://chromewebstore.google.com/detail/ijpgccednehjpeclfcllnjjcmiohdjih'\n\n/** convert a byte array to a hex string */\nexport const byteArrayToHexString = (byteArray: number[]): Hex => {\n return `0x${byteArray\n .map(byte => byte.toString(16).padStart(2, '0'))\n .join('')}`\n}\n\n/** parse a proof object from the PeerAuth extension */\nexport const parseExtensionProof = (proofObject: NotarizedProof) => {\n return {\n claimInfo: {\n provider: proofObject.claim.provider,\n parameters: proofObject.claim.parameters,\n context: proofObject.claim.context\n },\n signedClaim: {\n claim: {\n identifier: proofObject.claim.identifier as Hex,\n owner: proofObject.claim.owner as Hex,\n timestampS: proofObject.claim.timestampS,\n epoch: proofObject.claim.epoch\n },\n signatures: [byteArrayToHexString(Object.values(proofObject.signatures.claimSignature))]\n },\n isAppclipProof: false\n } as ReclaimProof\n}\n\n/** the abi encoding for a proof */\nexport const PROOF_ENCODING = parseAbiParameter(\"((string provider, string parameters, string context) claimInfo, ((bytes32 identifier, address owner, uint32 timestampS, uint32 epoch) claim, bytes[] signatures) signedClaim, bool isAppclipProof)\")\n\n/** encode a single proof as a bytes array */\nexport function encodeProofAsBytes(proof: ReclaimProof): Hex {\n return encodeAbiParameters([PROOF_ENCODING], [proof])\n}\n\n/** encode two proofs to be passed to the underlying sub-provider */\nexport const encodeTwoProofs = (proof1: ReclaimProof, proof2: ReclaimProof) => {\n return encodeAbiParameters([PROOF_ENCODING, PROOF_ENCODING], [proof1, proof2])\n}\n\n/** a high level function to encode a proof for a given provider and sub-provider */\nexport const encodeProof = ({ extensionProofs, subProvider, provider }: {\n extensionProofs: NotarizedProof[],\n subProvider: PlatformKey | null,\n provider: ProviderKey\n}) => {\n const reclaimProofs = extensionProofs.map((p) => parseExtensionProof(p))\n if (provider === 'zelle') {\n // move this to check the blockchain for the payment method\n const paymentMethod = subProviderConfigs![provider]![subProvider as SubProviderKey]!.paymentMethod\n const twoEncoded = reclaimProofs.length === 2\n ? encodeTwoProofs(reclaimProofs[0]!, reclaimProofs[1]!)\n : encodeProofAsBytes(reclaimProofs[0]!)\n // select between various possible sub-providers\n const withPaymentMethod = encodeProofWithPaymentMethod({\n paymentMethod,\n proof: twoEncoded,\n })\n return withPaymentMethod\n }\n const [reclaimProof] = reclaimProofs\n return encodeProofAsBytes(reclaimProof!)\n}\n\n/**\n * wrap a proof with a payment method and proof\n * this allows us to use a single verifier as an entry point for multiple underlying sub-providers\n */\nexport const encodeProofWithPaymentMethod = ({\n proof,\n paymentMethod\n}: {\n proof: Hex,\n paymentMethod: number\n}): Hex => {\n return encodePacked(['uint8', 'bytes'], [paymentMethod, proof])\n}\n\n/** the progress of a proof series */\nexport enum SeriesProgress {\n Generating,\n Polling,\n Complete,\n}\n\nexport type ProgressInfo = {\n progress: SeriesProgress\n total: number\n step: number | null\n id: string | null\n}\n\n/** the mutations for the generate proof series function */\nexport type GenerateProofSeriesMutations = {\n progress?: ({ progress, step, id }: ProgressInfo) => void\n setOwnerName?: (name: string) => void\n}\n\n/** React hook to interact with the PeerAuth extension */\nexport const useZKTLS = () => {\n const [isInitialized, setIsInitialized] = useState(false)\n useEffect(() => {\n const setup = () => {\n setIsInitialized(true)\n }\n const eventName = 'peer#initialized'\n if (typeof window.peer !== 'undefined') {\n // api is available\n setup()\n } else {\n window.addEventListener(eventName, setup)\n return () => {\n window.removeEventListener(eventName, setup)\n }\n }\n }, [])\n return useMemo(() => {\n /** fetch a proof by its id */\n const fetchProofById = async (proofId: string): Promise<NotaryRequest | null> => {\n const proof = await window.peer!.fetchProofById(proofId)\n if (proof && proof.notaryRequest) return proof.notaryRequest\n const proofs = await window.peer!.fetchProofs()\n const proofFromList = proofs.notaryRequests.find((p) => p.id === proofId)\n if (proofFromList) return proofFromList\n return null\n }\n /** wait for a proof to be generated */\n const waitForProof = async (proofId: string, onCurrent?: (notaryRequest: NotaryRequest | null) => void) => {\n let notaryRequest: NotaryRequest | null = null\n do {\n notaryRequest = await fetchProofById(proofId)\n onCurrent?.(notaryRequest)\n await sleep(1_000)\n } while (!notaryRequest || !notaryRequest.status || notaryRequest.status === 'pending')\n if (notaryRequest.status === 'failed' || notaryRequest.status === 'expired' || notaryRequest.status === 'cancelled' || notaryRequest.status === 'error') {\n console.error('[waitForProof] proof terminal state:', JSON.stringify(notaryRequest, null, 2))\n const req = notaryRequest as unknown as Record<string, unknown>\n const detail = req.errorMessage ?? req.error ?? req.message ?? notaryRequest.status\n throw new Error(`Proof generation failed: ${detail}`)\n }\n return notaryRequest\n }\n /** generate a proof */\n const generateProof = async (inputs: HexIntentGenerateProofInputs): Promise<GenerateProofResponse> => {\n return await window.peer!.generateProof({\n proofIndex: 0,\n ...inputs,\n intentHash: BigInt(inputs.intentHash).toString(),\n })\n }\n return {\n /** check if the PeerAuth extension is initialized */\n isInitialized,\n /** request a connection to the PeerAuth extension */\n requestConnection: async () => {\n if (!window.peer) return false\n return window.peer!.requestConnection()\n },\n /**\n * check the connection status of the PeerAuth extension\n * @returns the connection status\n */\n checkConnectionStatus: async () => {\n return await window.peer!.checkConnectionStatus()\n },\n /** get the version of the PeerAuth extension */\n getVersion: async () => {\n return await window.peer?.getVersion()\n },\n /** authenticate with the PeerAuth extension */\n authenticate: async (inputs: AuthenticationInputs) => {\n // Create promise first to avoid race condition where message arrives before resolver is assigned\n let resolve: (value: MetadataMessageResponse) => void\n const promise = new Promise<MetadataMessageResponse>((resolver) => {\n resolve = resolver\n })\n\n // Now set up the listener - resolve is guaranteed to be the real resolver\n const unsub = window.peer!.onMetadataMessage((data) => {\n if (`transfer_${data.platform}` === inputs.actionType) {\n resolve(data)\n }\n })\n\n await window.peer!.authenticate(inputs)\n\n return await promise.then((data) => {\n unsub()\n return data\n })\n },\n /** generate a proof */\n generateProof,\n /** wait for a proof to be generated */\n waitForProof,\n /** generate a proof series */\n generateProofSeries: async (\n inputs: GenerateProofInputsAbstracted,\n { progress: progressCallback }: GenerateProofSeriesMutations = {},\n ): Promise<NotaryRequest[]> => {\n const { platform, provider, intentHash, originalIndex } = inputs\n const args = {\n platform: provider,\n originalIndex,\n intentHash,\n } as const\n // Chase requires 2 proofs (account verification + transaction)\n // Platform is the bank name (e.g., 'chase') from extensionPlatform config\n const isChase = platform === extensionPlatforms.CHASE\n const isZelle = provider === providers.ZELLE\n const expectedTotal = isZelle && isChase ? 2 : 1\n progressCallback?.({ progress: SeriesProgress.Generating, step: 0, id: null, total: expectedTotal })\n const genProofA = await generateProof({ ...args, proofIndex: 0 })\n progressCallback?.({ progress: SeriesProgress.Polling, step: 0, id: genProofA.proofId, total: expectedTotal })\n const proofA = await waitForProof(genProofA.proofId)\n if (!isChase || !isZelle) {\n progressCallback?.({ progress: SeriesProgress.Complete, step: null, id: null, total: expectedTotal })\n return [proofA]\n }\n progressCallback?.({ progress: SeriesProgress.Generating, step: 1, id: null, total: expectedTotal })\n const genProofB = await generateProof({ ...args, proofIndex: 1 })\n progressCallback?.({ progress: SeriesProgress.Polling, step: 1, id: genProofB.proofId, total: expectedTotal })\n const proofB = await waitForProof(genProofB.proofId)\n progressCallback?.({ progress: SeriesProgress.Complete, step: null, id: null, total: expectedTotal })\n return [proofA, proofB]\n },\n /** subscribe to metadata messages */\n onMetadataMessage: (fn: (data: any) => void) => {\n return window.peer!.onMetadataMessage(fn)\n },\n /** fetch a proof by its id */\n fetchProofById,\n /** fetch generated proofs */\n fetchGeneratedProofs: async (genProofResponses: GenerateProofResponse[]) => {\n return await Promise.all(genProofResponses.map((r) => fetchProofById(r.proofId)))\n },\n /** fetch all proofs */\n fetchProofs: async () => {\n return await window.peer!.fetchProofs()\n },\n /** open the PeerAuth sidebar */\n openSidebar: async (route: string) => {\n return await window.peer!.openSidebar(route)\n },\n }\n }, [isInitialized])\n}\n\n/**\n * Find the metadata message that matches the intent by amount.\n * Returns the first (most recent) transaction in the metadata array that matches the expected amount.\n *\n * Simplified matching: just find transactions with the correct amount.\n * The user can manually select if multiple matches exist.\n */\nexport const findMetadataMessage = ({ metadata, intent, token, centIsInt = false }: {\n metadata: MetadataMessage[],\n intent: IntentStruct,\n token: TokenInfo,\n /** @deprecated No longer used - kept for API compatibility */\n recipient?: string,\n centIsInt?: boolean,\n}): MetadataMessage | null => {\n const currencyAmount = convertTokenInputToCurrency({\n token,\n amountOutInt: intent.amount,\n rate: intent.conversionRate,\n })\n /**\n * Normalize an amount from the extension into a bigint in token base units.\n *\n * The extension sends amounts in different formats per provider:\n * - Venmo: `\"- $1.00\"` (formatted dollar string)\n * - Others: `100` (integer cents) or `1.00` (decimal dollars)\n *\n * We detect the format by checking for currency symbols or decimal points\n * in the raw value. If present, the value is already in dollars and we\n * skip the centIsInt division.\n */\n const normalizeAmount = (amount: number | string): bigint => {\n const raw = String(amount)\n const isFormattedDollars = /[^0-9\\-]/.test(raw) && raw.includes('.')\n const cleaned = raw.replace(/[^0-9.]/g, '')\n let value = parseUnits(cleaned, token.decimals)\n if (centIsInt && !isFormattedDollars) {\n value = value / 100n\n }\n return value\n }\n\n // Skip auto-match when manual selection is forced (dev/testing)\n if (typeof window !== 'undefined' && (window as unknown as Record<string, unknown>).__FORCE_MANUAL_TX_SELECT__) {\n return null\n }\n\n // Find the first transaction that matches the amount (first in array = most recent)\n // Note: We ignore the hidden flag - matching is purely by amount\n const match = metadata.find((m) => {\n const converted = normalizeAmount(m.amount)\n return converted === currencyAmount || converted === (currencyAmount * -1n)\n })\n\n if (!match) {\n // Detect 100x scale mismatch — the most common failure mode when centIsInt\n // is wrong for a provider. Fires loudly so it's obvious in dev/staging logs.\n const hundredxMatch = metadata.find((m) => {\n const converted = normalizeAmount(m.amount)\n const abs = converted < 0n ? -converted : converted\n return abs === currencyAmount * 100n || abs * 100n === currencyAmount\n })\n if (hundredxMatch) {\n console.warn(\n `[findMetadataMessage] tx[0] amount=${String(hundredxMatch.amount)} is 100x off from expected ${currencyAmount.toString()} — centIsInt is likely wrong for this provider (currently ${centIsInt})`\n )\n }\n return null\n }\n\n return match\n}\n","/**\n * @fileoverview React context for PeerAuth extension state.\n *\n * Provides global access to the useZKTLS hook state throughout the\n * component tree, avoiding prop drilling for extension status.\n *\n * @see {@link useZKTLS} for the underlying hook\n */\n\nimport { createContext, useContext, type ReactNode } from 'react'\nimport { useZKTLS } from './useZKTLS'\n\n/**\n * Context type derived from useZKTLS hook return value.\n */\ntype ZKTLSContextType = ReturnType<typeof useZKTLS>\n\nexport const ZKTLSContext = createContext<ZKTLSContextType | undefined>(undefined)\n\ninterface ZKTLSProviderProps {\n children: ReactNode\n}\n\n/**\n * Hook to consume the ZKTLS context.\n * Must be used within a ZKTLSProvider.\n *\n * @throws Error if used outside of ZKTLSProvider\n */\nexport function useZKTLSContext() {\n const context = useContext(ZKTLSContext)\n if (context === undefined) {\n throw new Error('useZKTLSContext must be used within a ZKTLSProvider')\n }\n return context\n}\n\nexport function ZKTLSProvider({ children }: ZKTLSProviderProps) {\n const zktlsHook = useZKTLS()\n\n return (\n <ZKTLSContext.Provider value={zktlsHook}>\n {children}\n </ZKTLSContext.Provider>\n )\n}\n"]}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { ZKTLSContext, ZKTLSProvider, useZKTLSContext } from './chunk-
|
|
2
|
-
export { PROOF_ENCODING, SeriesProgress, byteArrayToHexString, encodeProof, encodeProofAsBytes, encodeProofWithPaymentMethod, encodeTwoProofs, extensionUrl, findMetadataMessage, parseExtensionProof, useZKTLS } from './chunk-
|
|
1
|
+
export { ZKTLSContext, ZKTLSProvider, useZKTLSContext } from './chunk-VDCCIS6C.js';
|
|
2
|
+
export { PROOF_ENCODING, SeriesProgress, byteArrayToHexString, encodeProof, encodeProofAsBytes, encodeProofWithPaymentMethod, encodeTwoProofs, extensionUrl, findMetadataMessage, parseExtensionProof, useZKTLS } from './chunk-W2QUSBIS.js';
|
|
3
3
|
//# sourceMappingURL=index.js.map
|
|
4
4
|
//# sourceMappingURL=index.js.map
|
package/dist/useZKTLS.cjs
CHANGED
|
@@ -96,7 +96,10 @@ var useZKTLS = () => {
|
|
|
96
96
|
await time.sleep(1e3);
|
|
97
97
|
} while (!notaryRequest || !notaryRequest.status || notaryRequest.status === "pending");
|
|
98
98
|
if (notaryRequest.status === "failed" || notaryRequest.status === "expired" || notaryRequest.status === "cancelled" || notaryRequest.status === "error") {
|
|
99
|
-
|
|
99
|
+
console.error("[waitForProof] proof terminal state:", JSON.stringify(notaryRequest, null, 2));
|
|
100
|
+
const req = notaryRequest;
|
|
101
|
+
const detail = req.errorMessage ?? req.error ?? req.message ?? notaryRequest.status;
|
|
102
|
+
throw new Error(`Proof generation failed: ${detail}`);
|
|
100
103
|
}
|
|
101
104
|
return notaryRequest;
|
|
102
105
|
};
|
|
@@ -218,6 +221,16 @@ var findMetadataMessage = ({ metadata, intent, token, centIsInt = false }) => {
|
|
|
218
221
|
return converted === currencyAmount || converted === currencyAmount * -1n;
|
|
219
222
|
});
|
|
220
223
|
if (!match) {
|
|
224
|
+
const hundredxMatch = metadata.find((m) => {
|
|
225
|
+
const converted = normalizeAmount(m.amount);
|
|
226
|
+
const abs = converted < 0n ? -converted : converted;
|
|
227
|
+
return abs === currencyAmount * 100n || abs * 100n === currencyAmount;
|
|
228
|
+
});
|
|
229
|
+
if (hundredxMatch) {
|
|
230
|
+
console.warn(
|
|
231
|
+
`[findMetadataMessage] tx[0] amount=${String(hundredxMatch.amount)} is 100x off from expected ${currencyAmount.toString()} \u2014 centIsInt is likely wrong for this provider (currently ${centIsInt})`
|
|
232
|
+
);
|
|
233
|
+
}
|
|
221
234
|
return null;
|
|
222
235
|
}
|
|
223
236
|
return match;
|
package/dist/useZKTLS.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useZKTLS.ts"],"names":["parseAbiParameter","encodeAbiParameters","subProviderConfigs","encodePacked","SeriesProgress","useState","useEffect","useMemo","sleep","extensionPlatforms","providers","convertTokenInputToCurrency","parseUnits"],"mappings":";;;;;;;;;AAwLO,IAAM,YAAA,GAAe;AAGrB,IAAM,oBAAA,GAAuB,CAAC,SAAA,KAA6B;AAChE,EAAA,OAAO,CAAA,EAAA,EAAK,SAAA,CACT,GAAA,CAAI,CAAA,IAAA,KAAQ,KAAK,QAAA,CAAS,EAAE,CAAA,CAAE,QAAA,CAAS,GAAG,GAAG,CAAC,CAAA,CAC9C,IAAA,CAAK,EAAE,CAAC,CAAA,CAAA;AACb;AAGO,IAAM,mBAAA,GAAsB,CAAC,WAAA,KAAgC;AAClE,EAAA,OAAO;AAAA,IACL,SAAA,EAAW;AAAA,MACT,QAAA,EAAU,YAAY,KAAA,CAAM,QAAA;AAAA,MAC5B,UAAA,EAAY,YAAY,KAAA,CAAM,UAAA;AAAA,MAC9B,OAAA,EAAS,YAAY,KAAA,CAAM;AAAA,KAC7B;AAAA,IACA,WAAA,EAAa;AAAA,MACX,KAAA,EAAO;AAAA,QACL,UAAA,EAAY,YAAY,KAAA,CAAM,UAAA;AAAA,QAC9B,KAAA,EAAO,YAAY,KAAA,CAAM,KAAA;AAAA,QACzB,UAAA,EAAY,YAAY,KAAA,CAAM,UAAA;AAAA,QAC9B,KAAA,EAAO,YAAY,KAAA,CAAM;AAAA,OAC3B;AAAA,MACA,UAAA,EAAY,CAAC,oBAAA,CAAqB,MAAA,CAAO,OAAO,WAAA,CAAY,UAAA,CAAW,cAAc,CAAC,CAAC;AAAA,KACzF;AAAA,IACA,cAAA,EAAgB;AAAA,GAClB;AACF;AAGO,IAAM,cAAA,GAAiBA,uBAAkB,qMAAqM;AAG9O,SAAS,mBAAmB,KAAA,EAA0B;AAC3D,EAAA,OAAOC,yBAAoB,CAAC,cAAc,CAAA,EAAG,CAAC,KAAK,CAAC,CAAA;AACtD;AAGO,IAAM,eAAA,GAAkB,CAAC,MAAA,EAAsB,MAAA,KAAyB;AAC7E,EAAA,OAAOA,wBAAA,CAAoB,CAAC,cAAA,EAAgB,cAAc,GAAG,CAAC,MAAA,EAAQ,MAAM,CAAC,CAAA;AAC/E;AAGO,IAAM,cAAc,CAAC,EAAE,eAAA,EAAiB,WAAA,EAAa,UAAS,KAI/D;AACJ,EAAA,MAAM,gBAAgB,eAAA,CAAgB,GAAA,CAAI,CAAC,CAAA,KAAM,mBAAA,CAAoB,CAAC,CAAC,CAAA;AACvE,EAAA,IAAI,aAAa,OAAA,EAAS;AAExB,IAAA,MAAM,aAAA,GAAgBC,0BAAA,CAAoB,QAAQ,CAAA,CAAG,WAA6B,CAAA,CAAG,aAAA;AACrF,IAAA,MAAM,UAAA,GAAa,aAAA,CAAc,MAAA,KAAW,CAAA,GACxC,gBAAgB,aAAA,CAAc,CAAC,CAAA,EAAI,aAAA,CAAc,CAAC,CAAE,CAAA,GACpD,kBAAA,CAAmB,aAAA,CAAc,CAAC,CAAE,CAAA;AAExC,IAAA,MAAM,oBAAoB,4BAAA,CAA6B;AAAA,MACrD,aAAA;AAAA,MACA,KAAA,EAAO;AAAA,KACR,CAAA;AACD,IAAA,OAAO,iBAAA;AAAA,EACT;AACA,EAAA,MAAM,CAAC,YAAY,CAAA,GAAI,aAAA;AACvB,EAAA,OAAO,mBAAmB,YAAa,CAAA;AACzC;AAMO,IAAM,+BAA+B,CAAC;AAAA,EAC3C,KAAA;AAAA,EACA;AACF,CAAA,KAGW;AACT,EAAA,OAAOC,iBAAA,CAAa,CAAC,OAAA,EAAS,OAAO,GAAG,CAAC,aAAA,EAAe,KAAK,CAAC,CAAA;AAChE;AAGO,IAAK,cAAA,qBAAAC,eAAAA,KAAL;AACL,EAAAA,eAAAA,CAAAA,eAAAA,CAAA,YAAA,CAAA,GAAA,CAAA,CAAA,GAAA,YAAA;AACA,EAAAA,eAAAA,CAAAA,eAAAA,CAAA,SAAA,CAAA,GAAA,CAAA,CAAA,GAAA,SAAA;AACA,EAAAA,eAAAA,CAAAA,eAAAA,CAAA,UAAA,CAAA,GAAA,CAAA,CAAA,GAAA,UAAA;AAHU,EAAA,OAAAA,eAAAA;AAAA,CAAA,EAAA,cAAA,IAAA,EAAA;AAoBL,IAAM,WAAW,MAAM;AAC5B,EAAA,MAAM,CAAC,aAAA,EAAe,gBAAgB,CAAA,GAAIC,eAAS,KAAK,CAAA;AACxD,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,MAAM,QAAQ,MAAM;AAClB,MAAA,gBAAA,CAAiB,IAAI,CAAA;AAAA,IACvB,CAAA;AACA,IAAA,MAAM,SAAA,GAAY,kBAAA;AAClB,IAAA,IAAI,OAAO,MAAA,CAAO,IAAA,KAAS,WAAA,EAAa;AAEtC,MAAA,KAAA,EAAM;AAAA,IACR,CAAA,MAAO;AACL,MAAA,MAAA,CAAO,gBAAA,CAAiB,WAAW,KAAK,CAAA;AACxC,MAAA,OAAO,MAAM;AACX,QAAA,MAAA,CAAO,mBAAA,CAAoB,WAAW,KAAK,CAAA;AAAA,MAC7C,CAAA;AAAA,IACF;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AACL,EAAA,OAAOC,cAAQ,MAAM;AAEnB,IAAA,MAAM,cAAA,GAAiB,OAAO,OAAA,KAAmD;AAC/E,MAAA,MAAM,KAAA,GAAQ,MAAM,MAAA,CAAO,IAAA,CAAM,eAAe,OAAO,CAAA;AACvD,MAAA,IAAI,KAAA,IAAS,KAAA,CAAM,aAAA,EAAe,OAAO,KAAA,CAAM,aAAA;AAC/C,MAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,IAAA,CAAM,WAAA,EAAY;AAC9C,MAAA,MAAM,aAAA,GAAgB,OAAO,cAAA,CAAe,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,OAAO,CAAA;AACxE,MAAA,IAAI,eAAe,OAAO,aAAA;AAC1B,MAAA,OAAO,IAAA;AAAA,IACT,CAAA;AAEA,IAAA,MAAM,YAAA,GAAe,OAAO,OAAA,EAAiB,SAAA,KAA8D;AACzG,MAAA,IAAI,aAAA,GAAsC,IAAA;AAC1C,MAAA,GAAG;AACD,QAAA,aAAA,GAAgB,MAAM,eAAe,OAAO,CAAA;AAC5C,QAAA,SAAA,GAAY,aAAa,CAAA;AACzB,QAAA,MAAMC,WAAM,GAAK,CAAA;AAAA,MACnB,SAAS,CAAC,aAAA,IAAiB,CAAC,aAAA,CAAc,MAAA,IAAU,cAAc,MAAA,KAAW,SAAA;AAC7E,MAAA,IAAI,aAAA,CAAc,MAAA,KAAW,QAAA,IAAY,aAAA,CAAc,MAAA,KAAW,SAAA,IAAa,aAAA,CAAc,MAAA,KAAW,WAAA,IAAe,aAAA,CAAc,MAAA,KAAW,OAAA,EAAS;AACvJ,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,yBAAA,EAA4B,aAAA,CAAc,MAAM,CAAA,CAAE,CAAA;AAAA,MACpE;AACA,MAAA,OAAO,aAAA;AAAA,IACT,CAAA;AAEA,IAAA,MAAM,aAAA,GAAgB,OAAO,MAAA,KAAyE;AACpG,MAAA,OAAO,MAAM,MAAA,CAAO,IAAA,CAAM,aAAA,CAAc;AAAA,QACtC,UAAA,EAAY,CAAA;AAAA,QACZ,GAAG,MAAA;AAAA,QACH,UAAA,EAAY,MAAA,CAAO,MAAA,CAAO,UAAU,EAAE,QAAA;AAAS,OAChD,CAAA;AAAA,IACH,CAAA;AACA,IAAA,OAAO;AAAA;AAAA,MAEL,aAAA;AAAA;AAAA,MAEA,mBAAmB,YAAY;AAC7B,QAAA,IAAI,CAAC,MAAA,CAAO,IAAA,EAAM,OAAO,KAAA;AACzB,QAAA,OAAO,MAAA,CAAO,KAAM,iBAAA,EAAkB;AAAA,MACxC,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAKA,uBAAuB,YAAY;AACjC,QAAA,OAAO,MAAM,MAAA,CAAO,IAAA,CAAM,qBAAA,EAAsB;AAAA,MAClD,CAAA;AAAA;AAAA,MAEA,YAAY,YAAY;AACtB,QAAA,OAAO,MAAM,MAAA,CAAO,IAAA,EAAM,UAAA,EAAW;AAAA,MACvC,CAAA;AAAA;AAAA,MAEA,YAAA,EAAc,OAAO,MAAA,KAAiC;AAEpD,QAAA,IAAI,OAAA;AACJ,QAAA,MAAM,OAAA,GAAU,IAAI,OAAA,CAAiC,CAAC,QAAA,KAAa;AACjE,UAAA,OAAA,GAAU,QAAA;AAAA,QACZ,CAAC,CAAA;AAGD,QAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,IAAA,CAAM,iBAAA,CAAkB,CAAC,IAAA,KAAS;AACrD,UAAA,IAAI,CAAA,SAAA,EAAY,IAAA,CAAK,QAAQ,CAAA,CAAA,KAAO,OAAO,UAAA,EAAY;AACrD,YAAA,OAAA,CAAQ,IAAI,CAAA;AAAA,UACd;AAAA,QACF,CAAC,CAAA;AAED,QAAA,MAAM,MAAA,CAAO,IAAA,CAAM,YAAA,CAAa,MAAM,CAAA;AAEtC,QAAA,OAAO,MAAM,OAAA,CAAQ,IAAA,CAAK,CAAC,IAAA,KAAS;AAClC,UAAA,KAAA,EAAM;AACN,UAAA,OAAO,IAAA;AAAA,QACT,CAAC,CAAA;AAAA,MACH,CAAA;AAAA;AAAA,MAEA,aAAA;AAAA;AAAA,MAEA,YAAA;AAAA;AAAA,MAEA,mBAAA,EAAqB,OACnB,MAAA,EACA,EAAE,UAAU,gBAAA,EAAiB,GAAkC,EAAC,KACnC;AAC7B,QAAA,MAAM,EAAE,QAAA,EAAU,QAAA,EAAU,UAAA,EAAY,eAAc,GAAI,MAAA;AAC1D,QAAA,MAAM,IAAA,GAAO;AAAA,UACX,QAAA,EAAU,QAAA;AAAA,UACV,aAAA;AAAA,UACA;AAAA,SACF;AAGA,QAAA,MAAM,OAAA,GAAU,aAAaC,0BAAA,CAAmB,KAAA;AAChD,QAAA,MAAM,OAAA,GAAU,aAAaC,iBAAA,CAAU,KAAA;AACvC,QAAA,MAAM,aAAA,GAAgB,OAAA,IAAW,OAAA,GAAU,CAAA,GAAI,CAAA;AAC/C,QAAA,gBAAA,GAAmB,EAAE,UAAU,CAAA,mBAA2B,IAAA,EAAM,GAAG,EAAA,EAAI,IAAA,EAAM,KAAA,EAAO,aAAA,EAAe,CAAA;AACnG,QAAA,MAAM,SAAA,GAAY,MAAM,aAAA,CAAc,EAAE,GAAG,IAAA,EAAM,UAAA,EAAY,GAAG,CAAA;AAChE,QAAA,gBAAA,GAAmB,EAAE,QAAA,EAAU,CAAA,gBAAwB,IAAA,EAAM,CAAA,EAAG,IAAI,SAAA,CAAU,OAAA,EAAS,KAAA,EAAO,aAAA,EAAe,CAAA;AAC7G,QAAA,MAAM,MAAA,GAAS,MAAM,YAAA,CAAa,SAAA,CAAU,OAAO,CAAA;AACnD,QAAA,IAAI,CAAC,OAAA,IAAW,CAAC,OAAA,EAAS;AACxB,UAAA,gBAAA,GAAmB,EAAE,UAAU,CAAA,iBAAyB,IAAA,EAAM,MAAM,EAAA,EAAI,IAAA,EAAM,KAAA,EAAO,aAAA,EAAe,CAAA;AACpG,UAAA,OAAO,CAAC,MAAM,CAAA;AAAA,QAChB;AACA,QAAA,gBAAA,GAAmB,EAAE,UAAU,CAAA,mBAA2B,IAAA,EAAM,GAAG,EAAA,EAAI,IAAA,EAAM,KAAA,EAAO,aAAA,EAAe,CAAA;AACnG,QAAA,MAAM,SAAA,GAAY,MAAM,aAAA,CAAc,EAAE,GAAG,IAAA,EAAM,UAAA,EAAY,GAAG,CAAA;AAChE,QAAA,gBAAA,GAAmB,EAAE,QAAA,EAAU,CAAA,gBAAwB,IAAA,EAAM,CAAA,EAAG,IAAI,SAAA,CAAU,OAAA,EAAS,KAAA,EAAO,aAAA,EAAe,CAAA;AAC7G,QAAA,MAAM,MAAA,GAAS,MAAM,YAAA,CAAa,SAAA,CAAU,OAAO,CAAA;AACnD,QAAA,gBAAA,GAAmB,EAAE,UAAU,CAAA,iBAAyB,IAAA,EAAM,MAAM,EAAA,EAAI,IAAA,EAAM,KAAA,EAAO,aAAA,EAAe,CAAA;AACpG,QAAA,OAAO,CAAC,QAAQ,MAAM,CAAA;AAAA,MACxB,CAAA;AAAA;AAAA,MAEA,iBAAA,EAAmB,CAAC,EAAA,KAA4B;AAC9C,QAAA,OAAO,MAAA,CAAO,IAAA,CAAM,iBAAA,CAAkB,EAAE,CAAA;AAAA,MAC1C,CAAA;AAAA;AAAA,MAEA,cAAA;AAAA;AAAA,MAEA,oBAAA,EAAsB,OAAO,iBAAA,KAA+C;AAC1E,QAAA,OAAO,MAAM,OAAA,CAAQ,GAAA,CAAI,iBAAA,CAAkB,GAAA,CAAI,CAAC,CAAA,KAAM,cAAA,CAAe,CAAA,CAAE,OAAO,CAAC,CAAC,CAAA;AAAA,MAClF,CAAA;AAAA;AAAA,MAEA,aAAa,YAAY;AACvB,QAAA,OAAO,MAAM,MAAA,CAAO,IAAA,CAAM,WAAA,EAAY;AAAA,MACxC,CAAA;AAAA;AAAA,MAEA,WAAA,EAAa,OAAO,KAAA,KAAkB;AACpC,QAAA,OAAO,MAAM,MAAA,CAAO,IAAA,CAAM,WAAA,CAAY,KAAK,CAAA;AAAA,MAC7C;AAAA,KACF;AAAA,EACF,CAAA,EAAG,CAAC,aAAa,CAAC,CAAA;AACpB;AASO,IAAM,mBAAA,GAAsB,CAAC,EAAE,QAAA,EAAU,QAAQ,KAAA,EAAO,SAAA,GAAY,OAAM,KAOnD;AAC5B,EAAA,MAAM,iBAAiBC,2CAAA,CAA4B;AAAA,IACjD,KAAA;AAAA,IACA,cAAc,MAAA,CAAO,MAAA;AAAA,IACrB,MAAM,MAAA,CAAO;AAAA,GACd,CAAA;AAYD,EAAA,MAAM,eAAA,GAAkB,CAAC,MAAA,KAAoC;AAC3D,IAAA,MAAM,GAAA,GAAM,OAAO,MAAM,CAAA;AACzB,IAAA,MAAM,qBAAqB,UAAA,CAAW,IAAA,CAAK,GAAG,CAAA,IAAK,GAAA,CAAI,SAAS,GAAG,CAAA;AACnE,IAAA,MAAM,OAAA,GAAU,GAAA,CAAI,OAAA,CAAQ,UAAA,EAAY,EAAE,CAAA;AAC1C,IAAA,IAAI,KAAA,GAAQC,eAAA,CAAW,OAAA,EAAS,KAAA,CAAM,QAAQ,CAAA;AAC9C,IAAA,IAAI,SAAA,IAAa,CAAC,kBAAA,EAAoB;AACpC,MAAA,KAAA,GAAQ,KAAA,GAAQ,IAAA;AAAA,IAClB;AACA,IAAA,OAAO,KAAA;AAAA,EACT,CAAA;AAGA,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,IAAgB,MAAA,CAA8C,0BAAA,EAA4B;AAC9G,IAAA,OAAO,IAAA;AAAA,EACT;AAIA,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,IAAA,CAAK,CAAC,CAAA,KAAM;AACjC,IAAA,MAAM,SAAA,GAAY,eAAA,CAAgB,CAAA,CAAE,MAAM,CAAA;AAC1C,IAAA,OAAO,SAAA,KAAc,cAAA,IAAkB,SAAA,KAAe,cAAA,GAAiB,CAAC,EAAA;AAAA,EAC1E,CAAC,CAAA;AAED,EAAA,IAAI,CAAC,KAAA,EAAO;AACV,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,OAAO,KAAA;AACT","file":"useZKTLS.cjs","sourcesContent":["/**\n * @fileoverview React hook and utilities for PeerAuth browser extension integration.\n *\n * The PeerAuth extension (formerly ZK-TLS) provides secure proof generation\n * for off-chain payment verification. This module provides:\n *\n * 1. Type definitions for extension API (window.peer)\n * 2. useZKTLS hook for React components\n * 3. Utility functions for transaction matching and proof encoding\n *\n * @remarks\n * The extension exposes `window.peer` (or deprecated `window.zktls`) for:\n * - Requesting connection (OAuth-like flow)\n * - Authenticating with payment providers\n * - Generating notarized proofs\n * - Fetching transaction metadata\n *\n * @see {@link ZKTLSContext} for the React context provider\n */\n\nimport { useEffect, useMemo, useState } from \"react\"\nimport { encodeAbiParameters, encodePacked, parseAbiParameter, parseUnits, type Hex } from \"viem\"\nimport { sleep } from \"@provex/utils/time\"\nimport type { IntentStruct } from \"@provex/utils/intent\"\nimport type { TokenInfo } from \"@provex/utils/tokens\"\nimport { extensionPlatforms, providers, subProviderConfigs, type ActionType, type PlatformKey, type ProviderKey, type SubProviderKey } from \"@provex/utils/payment\"\nimport { convertTokenInputToCurrency } from \"@provex/utils/conversionRates\"\n\ndeclare global {\n interface ZKTLS {\n requestConnection(): Promise<boolean>\n checkConnectionStatus(): Promise<Status>\n getVersion(): Promise<string>\n authenticate(inputs: AuthenticationInputs): Promise<void>\n generateProof(inputs: GenerateProofInputs): Promise<GenerateProofResponse>\n fetchProofById(proofId: string): Promise<ProofResponse>\n fetchProofs(): Promise<FetchProofsResponse>\n openSidebar(route: string): Promise<void>\n onMetadataMessage(fn: (data: MetadataMessageResponse) => void): () => void\n }\n interface Window {\n /** @deprecated Use window.peer instead */\n zktls: ZKTLS | undefined\n /** PeerAuth extension API (replaces window.zktls) */\n peer: ZKTLS | undefined\n }\n}\n\n/** the status of the PeerAuth extension */\nexport type Status = 'connected' | 'disconnected' | 'pending'\n\n/** the individual metadata message sent by the PeerAuth extension */\nexport interface MetadataMessage {\n amount: number\n /** Currency code (e.g., 'USD', 'EUR') */\n currency?: string\n /**\n * Date of the transaction.\n * Can be a string in YYYYMMDD format, a number (YYYYMMDD or timestamp), or Date object.\n * The actual type depends on the extension implementation.\n */\n date: string | number | Date\n hidden: boolean\n originalIndex: number\n paymentId: number\n recipient: string\n}\n\n/** the response from the PeerAuth extension when a metadata message is received */\nexport interface MetadataMessageResponse {\n expiresAt: number\n platform: ProviderKey\n requestId: string\n metadata: MetadataMessage[]\n}\n\n/** the response from the PeerAuth extension when fetching proofs */\nexport interface FetchProofsResponse {\n notaryRequests: NotaryRequest[]\n}\n\n/** the inputs for the generateProof function */\nexport type GenerateProofInputsAbstracted = {\n platform: PlatformKey\n provider: ProviderKey\n intentHash: Hex\n originalIndex: number\n}\n\n/** the inputs for the generateProof function */\nexport type GenerateProofInputs = {\n platform: ProviderKey\n originalIndex: number\n proofIndex?: number\n intentHash: string\n}\n\n/**\n * inputs for the generate proof function that requires the intent hash\n * as hex to ensure it can be converted to a bigint string accurately\n */\nexport type HexIntentGenerateProofInputs = Exclude<GenerateProofInputs, 'intentHash'> & { intentHash: Hex }\n\n/** the response from the PeerAuth extension when generating a proof */\nexport type GenerateProofResponse = {\n proofId: string\n platform: ProviderKey\n}\n\n/** the inputs for the authenticate function */\nexport type AuthenticationInputs = {\n actionType: ActionType\n platform: PlatformKey\n}\n\n/** the response from the PeerAuth extension when fetching a proof */\nexport interface Proof {\n claimInfo: ClaimInfo\n signedClaim: SignedClaim\n isAppclipProof: boolean\n status: string\n}\n\n/** the response from the PeerAuth extension when fetching a proof */\nexport interface NotarizedProof {\n claim: {\n context: string\n epoch: number\n identifier: Hex\n owner: Hex\n parameters: string\n provider: string\n timestampS: number\n },\n signatures: {\n attestorAddress: Hex\n claimSignature: Record<number, number>\n resultSignature: Record<number, number>\n },\n}\n\n/** the claim info for a proof */\nexport interface ClaimInfo {\n provider: string\n parameters: string\n context: string\n}\n\n/** the complete claim data for a proof */\nexport interface CompleteClaimData {\n identifier: Hex\n owner: Hex\n timestampS: number\n epoch: number\n}\n\n/** the signed claim for a proof */\nexport interface SignedClaim {\n claim: CompleteClaimData\n signatures: Hex[]\n}\n\n/** the reclaim proof for a proof */\nexport type ReclaimProof = {\n claimInfo: ClaimInfo\n signedClaim: SignedClaim\n isAppclipProof: boolean\n}\n\n/** the notary request for a proof */\nexport interface NotaryRequest {\n metadata: (string | number)[]\n actionType: ActionType\n id: string\n status: string\n timestamp: number\n proof: NotarizedProof\n}\n\n/** the response from the PeerAuth extension when fetching a proof */\nexport interface ProofResponse {\n notaryRequest: NotaryRequest\n}\n\nexport const extensionUrl = 'https://chromewebstore.google.com/detail/ijpgccednehjpeclfcllnjjcmiohdjih'\n\n/** convert a byte array to a hex string */\nexport const byteArrayToHexString = (byteArray: number[]): Hex => {\n return `0x${byteArray\n .map(byte => byte.toString(16).padStart(2, '0'))\n .join('')}`\n}\n\n/** parse a proof object from the PeerAuth extension */\nexport const parseExtensionProof = (proofObject: NotarizedProof) => {\n return {\n claimInfo: {\n provider: proofObject.claim.provider,\n parameters: proofObject.claim.parameters,\n context: proofObject.claim.context\n },\n signedClaim: {\n claim: {\n identifier: proofObject.claim.identifier as Hex,\n owner: proofObject.claim.owner as Hex,\n timestampS: proofObject.claim.timestampS,\n epoch: proofObject.claim.epoch\n },\n signatures: [byteArrayToHexString(Object.values(proofObject.signatures.claimSignature))]\n },\n isAppclipProof: false\n } as ReclaimProof\n}\n\n/** the abi encoding for a proof */\nexport const PROOF_ENCODING = parseAbiParameter(\"((string provider, string parameters, string context) claimInfo, ((bytes32 identifier, address owner, uint32 timestampS, uint32 epoch) claim, bytes[] signatures) signedClaim, bool isAppclipProof)\")\n\n/** encode a single proof as a bytes array */\nexport function encodeProofAsBytes(proof: ReclaimProof): Hex {\n return encodeAbiParameters([PROOF_ENCODING], [proof])\n}\n\n/** encode two proofs to be passed to the underlying sub-provider */\nexport const encodeTwoProofs = (proof1: ReclaimProof, proof2: ReclaimProof) => {\n return encodeAbiParameters([PROOF_ENCODING, PROOF_ENCODING], [proof1, proof2])\n}\n\n/** a high level function to encode a proof for a given provider and sub-provider */\nexport const encodeProof = ({ extensionProofs, subProvider, provider }: {\n extensionProofs: NotarizedProof[],\n subProvider: PlatformKey | null,\n provider: ProviderKey\n}) => {\n const reclaimProofs = extensionProofs.map((p) => parseExtensionProof(p))\n if (provider === 'zelle') {\n // move this to check the blockchain for the payment method\n const paymentMethod = subProviderConfigs![provider]![subProvider as SubProviderKey]!.paymentMethod\n const twoEncoded = reclaimProofs.length === 2\n ? encodeTwoProofs(reclaimProofs[0]!, reclaimProofs[1]!)\n : encodeProofAsBytes(reclaimProofs[0]!)\n // select between various possible sub-providers\n const withPaymentMethod = encodeProofWithPaymentMethod({\n paymentMethod,\n proof: twoEncoded,\n })\n return withPaymentMethod\n }\n const [reclaimProof] = reclaimProofs\n return encodeProofAsBytes(reclaimProof!)\n}\n\n/**\n * wrap a proof with a payment method and proof\n * this allows us to use a single verifier as an entry point for multiple underlying sub-providers\n */\nexport const encodeProofWithPaymentMethod = ({\n proof,\n paymentMethod\n}: {\n proof: Hex,\n paymentMethod: number\n}): Hex => {\n return encodePacked(['uint8', 'bytes'], [paymentMethod, proof])\n}\n\n/** the progress of a proof series */\nexport enum SeriesProgress {\n Generating,\n Polling,\n Complete,\n}\n\nexport type ProgressInfo = {\n progress: SeriesProgress\n total: number\n step: number | null\n id: string | null\n}\n\n/** the mutations for the generate proof series function */\nexport type GenerateProofSeriesMutations = {\n progress?: ({ progress, step, id }: ProgressInfo) => void\n setOwnerName?: (name: string) => void\n}\n\n/** React hook to interact with the PeerAuth extension */\nexport const useZKTLS = () => {\n const [isInitialized, setIsInitialized] = useState(false)\n useEffect(() => {\n const setup = () => {\n setIsInitialized(true)\n }\n const eventName = 'peer#initialized'\n if (typeof window.peer !== 'undefined') {\n // api is available\n setup()\n } else {\n window.addEventListener(eventName, setup)\n return () => {\n window.removeEventListener(eventName, setup)\n }\n }\n }, [])\n return useMemo(() => {\n /** fetch a proof by its id */\n const fetchProofById = async (proofId: string): Promise<NotaryRequest | null> => {\n const proof = await window.peer!.fetchProofById(proofId)\n if (proof && proof.notaryRequest) return proof.notaryRequest\n const proofs = await window.peer!.fetchProofs()\n const proofFromList = proofs.notaryRequests.find((p) => p.id === proofId)\n if (proofFromList) return proofFromList\n return null\n }\n /** wait for a proof to be generated */\n const waitForProof = async (proofId: string, onCurrent?: (notaryRequest: NotaryRequest | null) => void) => {\n let notaryRequest: NotaryRequest | null = null\n do {\n notaryRequest = await fetchProofById(proofId)\n onCurrent?.(notaryRequest)\n await sleep(1_000)\n } while (!notaryRequest || !notaryRequest.status || notaryRequest.status === 'pending')\n if (notaryRequest.status === 'failed' || notaryRequest.status === 'expired' || notaryRequest.status === 'cancelled' || notaryRequest.status === 'error') {\n throw new Error(`Proof generation failed: ${notaryRequest.status}`)\n }\n return notaryRequest\n }\n /** generate a proof */\n const generateProof = async (inputs: HexIntentGenerateProofInputs): Promise<GenerateProofResponse> => {\n return await window.peer!.generateProof({\n proofIndex: 0,\n ...inputs,\n intentHash: BigInt(inputs.intentHash).toString(),\n })\n }\n return {\n /** check if the PeerAuth extension is initialized */\n isInitialized,\n /** request a connection to the PeerAuth extension */\n requestConnection: async () => {\n if (!window.peer) return false\n return window.peer!.requestConnection()\n },\n /**\n * check the connection status of the PeerAuth extension\n * @returns the connection status\n */\n checkConnectionStatus: async () => {\n return await window.peer!.checkConnectionStatus()\n },\n /** get the version of the PeerAuth extension */\n getVersion: async () => {\n return await window.peer?.getVersion()\n },\n /** authenticate with the PeerAuth extension */\n authenticate: async (inputs: AuthenticationInputs) => {\n // Create promise first to avoid race condition where message arrives before resolver is assigned\n let resolve: (value: MetadataMessageResponse) => void\n const promise = new Promise<MetadataMessageResponse>((resolver) => {\n resolve = resolver\n })\n\n // Now set up the listener - resolve is guaranteed to be the real resolver\n const unsub = window.peer!.onMetadataMessage((data) => {\n if (`transfer_${data.platform}` === inputs.actionType) {\n resolve(data)\n }\n })\n\n await window.peer!.authenticate(inputs)\n\n return await promise.then((data) => {\n unsub()\n return data\n })\n },\n /** generate a proof */\n generateProof,\n /** wait for a proof to be generated */\n waitForProof,\n /** generate a proof series */\n generateProofSeries: async (\n inputs: GenerateProofInputsAbstracted,\n { progress: progressCallback }: GenerateProofSeriesMutations = {},\n ): Promise<NotaryRequest[]> => {\n const { platform, provider, intentHash, originalIndex } = inputs\n const args = {\n platform: provider,\n originalIndex,\n intentHash,\n } as const\n // Chase requires 2 proofs (account verification + transaction)\n // Platform is the bank name (e.g., 'chase') from extensionPlatform config\n const isChase = platform === extensionPlatforms.CHASE\n const isZelle = provider === providers.ZELLE\n const expectedTotal = isZelle && isChase ? 2 : 1\n progressCallback?.({ progress: SeriesProgress.Generating, step: 0, id: null, total: expectedTotal })\n const genProofA = await generateProof({ ...args, proofIndex: 0 })\n progressCallback?.({ progress: SeriesProgress.Polling, step: 0, id: genProofA.proofId, total: expectedTotal })\n const proofA = await waitForProof(genProofA.proofId)\n if (!isChase || !isZelle) {\n progressCallback?.({ progress: SeriesProgress.Complete, step: null, id: null, total: expectedTotal })\n return [proofA]\n }\n progressCallback?.({ progress: SeriesProgress.Generating, step: 1, id: null, total: expectedTotal })\n const genProofB = await generateProof({ ...args, proofIndex: 1 })\n progressCallback?.({ progress: SeriesProgress.Polling, step: 1, id: genProofB.proofId, total: expectedTotal })\n const proofB = await waitForProof(genProofB.proofId)\n progressCallback?.({ progress: SeriesProgress.Complete, step: null, id: null, total: expectedTotal })\n return [proofA, proofB]\n },\n /** subscribe to metadata messages */\n onMetadataMessage: (fn: (data: any) => void) => {\n return window.peer!.onMetadataMessage(fn)\n },\n /** fetch a proof by its id */\n fetchProofById,\n /** fetch generated proofs */\n fetchGeneratedProofs: async (genProofResponses: GenerateProofResponse[]) => {\n return await Promise.all(genProofResponses.map((r) => fetchProofById(r.proofId)))\n },\n /** fetch all proofs */\n fetchProofs: async () => {\n return await window.peer!.fetchProofs()\n },\n /** open the PeerAuth sidebar */\n openSidebar: async (route: string) => {\n return await window.peer!.openSidebar(route)\n },\n }\n }, [isInitialized])\n}\n\n/**\n * Find the metadata message that matches the intent by amount.\n * Returns the first (most recent) transaction in the metadata array that matches the expected amount.\n *\n * Simplified matching: just find transactions with the correct amount.\n * The user can manually select if multiple matches exist.\n */\nexport const findMetadataMessage = ({ metadata, intent, token, centIsInt = false }: {\n metadata: MetadataMessage[],\n intent: IntentStruct,\n token: TokenInfo,\n /** @deprecated No longer used - kept for API compatibility */\n recipient?: string,\n centIsInt?: boolean,\n}): MetadataMessage | null => {\n const currencyAmount = convertTokenInputToCurrency({\n token,\n amountOutInt: intent.amount,\n rate: intent.conversionRate,\n })\n /**\n * Normalize an amount from the extension into a bigint in token base units.\n *\n * The extension sends amounts in different formats per provider:\n * - Venmo: `\"- $1.00\"` (formatted dollar string)\n * - Others: `100` (integer cents) or `1.00` (decimal dollars)\n *\n * We detect the format by checking for currency symbols or decimal points\n * in the raw value. If present, the value is already in dollars and we\n * skip the centIsInt division.\n */\n const normalizeAmount = (amount: number | string): bigint => {\n const raw = String(amount)\n const isFormattedDollars = /[^0-9\\-]/.test(raw) && raw.includes('.')\n const cleaned = raw.replace(/[^0-9.]/g, '')\n let value = parseUnits(cleaned, token.decimals)\n if (centIsInt && !isFormattedDollars) {\n value = value / 100n\n }\n return value\n }\n\n // Skip auto-match when manual selection is forced (dev/testing)\n if (typeof window !== 'undefined' && (window as unknown as Record<string, unknown>).__FORCE_MANUAL_TX_SELECT__) {\n return null\n }\n\n // Find the first transaction that matches the amount (first in array = most recent)\n // Note: We ignore the hidden flag - matching is purely by amount\n const match = metadata.find((m) => {\n const converted = normalizeAmount(m.amount)\n return converted === currencyAmount || converted === (currencyAmount * -1n)\n })\n\n if (!match) {\n return null\n }\n\n return match\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/useZKTLS.ts"],"names":["parseAbiParameter","encodeAbiParameters","subProviderConfigs","encodePacked","SeriesProgress","useState","useEffect","useMemo","sleep","extensionPlatforms","providers","convertTokenInputToCurrency","parseUnits"],"mappings":";;;;;;;;;AAwLO,IAAM,YAAA,GAAe;AAGrB,IAAM,oBAAA,GAAuB,CAAC,SAAA,KAA6B;AAChE,EAAA,OAAO,CAAA,EAAA,EAAK,SAAA,CACT,GAAA,CAAI,CAAA,IAAA,KAAQ,KAAK,QAAA,CAAS,EAAE,CAAA,CAAE,QAAA,CAAS,GAAG,GAAG,CAAC,CAAA,CAC9C,IAAA,CAAK,EAAE,CAAC,CAAA,CAAA;AACb;AAGO,IAAM,mBAAA,GAAsB,CAAC,WAAA,KAAgC;AAClE,EAAA,OAAO;AAAA,IACL,SAAA,EAAW;AAAA,MACT,QAAA,EAAU,YAAY,KAAA,CAAM,QAAA;AAAA,MAC5B,UAAA,EAAY,YAAY,KAAA,CAAM,UAAA;AAAA,MAC9B,OAAA,EAAS,YAAY,KAAA,CAAM;AAAA,KAC7B;AAAA,IACA,WAAA,EAAa;AAAA,MACX,KAAA,EAAO;AAAA,QACL,UAAA,EAAY,YAAY,KAAA,CAAM,UAAA;AAAA,QAC9B,KAAA,EAAO,YAAY,KAAA,CAAM,KAAA;AAAA,QACzB,UAAA,EAAY,YAAY,KAAA,CAAM,UAAA;AAAA,QAC9B,KAAA,EAAO,YAAY,KAAA,CAAM;AAAA,OAC3B;AAAA,MACA,UAAA,EAAY,CAAC,oBAAA,CAAqB,MAAA,CAAO,OAAO,WAAA,CAAY,UAAA,CAAW,cAAc,CAAC,CAAC;AAAA,KACzF;AAAA,IACA,cAAA,EAAgB;AAAA,GAClB;AACF;AAGO,IAAM,cAAA,GAAiBA,uBAAkB,qMAAqM;AAG9O,SAAS,mBAAmB,KAAA,EAA0B;AAC3D,EAAA,OAAOC,yBAAoB,CAAC,cAAc,CAAA,EAAG,CAAC,KAAK,CAAC,CAAA;AACtD;AAGO,IAAM,eAAA,GAAkB,CAAC,MAAA,EAAsB,MAAA,KAAyB;AAC7E,EAAA,OAAOA,wBAAA,CAAoB,CAAC,cAAA,EAAgB,cAAc,GAAG,CAAC,MAAA,EAAQ,MAAM,CAAC,CAAA;AAC/E;AAGO,IAAM,cAAc,CAAC,EAAE,eAAA,EAAiB,WAAA,EAAa,UAAS,KAI/D;AACJ,EAAA,MAAM,gBAAgB,eAAA,CAAgB,GAAA,CAAI,CAAC,CAAA,KAAM,mBAAA,CAAoB,CAAC,CAAC,CAAA;AACvE,EAAA,IAAI,aAAa,OAAA,EAAS;AAExB,IAAA,MAAM,aAAA,GAAgBC,0BAAA,CAAoB,QAAQ,CAAA,CAAG,WAA6B,CAAA,CAAG,aAAA;AACrF,IAAA,MAAM,UAAA,GAAa,aAAA,CAAc,MAAA,KAAW,CAAA,GACxC,gBAAgB,aAAA,CAAc,CAAC,CAAA,EAAI,aAAA,CAAc,CAAC,CAAE,CAAA,GACpD,kBAAA,CAAmB,aAAA,CAAc,CAAC,CAAE,CAAA;AAExC,IAAA,MAAM,oBAAoB,4BAAA,CAA6B;AAAA,MACrD,aAAA;AAAA,MACA,KAAA,EAAO;AAAA,KACR,CAAA;AACD,IAAA,OAAO,iBAAA;AAAA,EACT;AACA,EAAA,MAAM,CAAC,YAAY,CAAA,GAAI,aAAA;AACvB,EAAA,OAAO,mBAAmB,YAAa,CAAA;AACzC;AAMO,IAAM,+BAA+B,CAAC;AAAA,EAC3C,KAAA;AAAA,EACA;AACF,CAAA,KAGW;AACT,EAAA,OAAOC,iBAAA,CAAa,CAAC,OAAA,EAAS,OAAO,GAAG,CAAC,aAAA,EAAe,KAAK,CAAC,CAAA;AAChE;AAGO,IAAK,cAAA,qBAAAC,eAAAA,KAAL;AACL,EAAAA,eAAAA,CAAAA,eAAAA,CAAA,YAAA,CAAA,GAAA,CAAA,CAAA,GAAA,YAAA;AACA,EAAAA,eAAAA,CAAAA,eAAAA,CAAA,SAAA,CAAA,GAAA,CAAA,CAAA,GAAA,SAAA;AACA,EAAAA,eAAAA,CAAAA,eAAAA,CAAA,UAAA,CAAA,GAAA,CAAA,CAAA,GAAA,UAAA;AAHU,EAAA,OAAAA,eAAAA;AAAA,CAAA,EAAA,cAAA,IAAA,EAAA;AAoBL,IAAM,WAAW,MAAM;AAC5B,EAAA,MAAM,CAAC,aAAA,EAAe,gBAAgB,CAAA,GAAIC,eAAS,KAAK,CAAA;AACxD,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,MAAM,QAAQ,MAAM;AAClB,MAAA,gBAAA,CAAiB,IAAI,CAAA;AAAA,IACvB,CAAA;AACA,IAAA,MAAM,SAAA,GAAY,kBAAA;AAClB,IAAA,IAAI,OAAO,MAAA,CAAO,IAAA,KAAS,WAAA,EAAa;AAEtC,MAAA,KAAA,EAAM;AAAA,IACR,CAAA,MAAO;AACL,MAAA,MAAA,CAAO,gBAAA,CAAiB,WAAW,KAAK,CAAA;AACxC,MAAA,OAAO,MAAM;AACX,QAAA,MAAA,CAAO,mBAAA,CAAoB,WAAW,KAAK,CAAA;AAAA,MAC7C,CAAA;AAAA,IACF;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AACL,EAAA,OAAOC,cAAQ,MAAM;AAEnB,IAAA,MAAM,cAAA,GAAiB,OAAO,OAAA,KAAmD;AAC/E,MAAA,MAAM,KAAA,GAAQ,MAAM,MAAA,CAAO,IAAA,CAAM,eAAe,OAAO,CAAA;AACvD,MAAA,IAAI,KAAA,IAAS,KAAA,CAAM,aAAA,EAAe,OAAO,KAAA,CAAM,aAAA;AAC/C,MAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,IAAA,CAAM,WAAA,EAAY;AAC9C,MAAA,MAAM,aAAA,GAAgB,OAAO,cAAA,CAAe,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,OAAO,CAAA;AACxE,MAAA,IAAI,eAAe,OAAO,aAAA;AAC1B,MAAA,OAAO,IAAA;AAAA,IACT,CAAA;AAEA,IAAA,MAAM,YAAA,GAAe,OAAO,OAAA,EAAiB,SAAA,KAA8D;AACzG,MAAA,IAAI,aAAA,GAAsC,IAAA;AAC1C,MAAA,GAAG;AACD,QAAA,aAAA,GAAgB,MAAM,eAAe,OAAO,CAAA;AAC5C,QAAA,SAAA,GAAY,aAAa,CAAA;AACzB,QAAA,MAAMC,WAAM,GAAK,CAAA;AAAA,MACnB,SAAS,CAAC,aAAA,IAAiB,CAAC,aAAA,CAAc,MAAA,IAAU,cAAc,MAAA,KAAW,SAAA;AAC7E,MAAA,IAAI,aAAA,CAAc,MAAA,KAAW,QAAA,IAAY,aAAA,CAAc,MAAA,KAAW,SAAA,IAAa,aAAA,CAAc,MAAA,KAAW,WAAA,IAAe,aAAA,CAAc,MAAA,KAAW,OAAA,EAAS;AACvJ,QAAA,OAAA,CAAQ,MAAM,sCAAA,EAAwC,IAAA,CAAK,UAAU,aAAA,EAAe,IAAA,EAAM,CAAC,CAAC,CAAA;AAC5F,QAAA,MAAM,GAAA,GAAM,aAAA;AACZ,QAAA,MAAM,SAAS,GAAA,CAAI,YAAA,IAAgB,IAAI,KAAA,IAAS,GAAA,CAAI,WAAW,aAAA,CAAc,MAAA;AAC7E,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,yBAAA,EAA4B,MAAM,CAAA,CAAE,CAAA;AAAA,MACtD;AACA,MAAA,OAAO,aAAA;AAAA,IACT,CAAA;AAEA,IAAA,MAAM,aAAA,GAAgB,OAAO,MAAA,KAAyE;AACpG,MAAA,OAAO,MAAM,MAAA,CAAO,IAAA,CAAM,aAAA,CAAc;AAAA,QACtC,UAAA,EAAY,CAAA;AAAA,QACZ,GAAG,MAAA;AAAA,QACH,UAAA,EAAY,MAAA,CAAO,MAAA,CAAO,UAAU,EAAE,QAAA;AAAS,OAChD,CAAA;AAAA,IACH,CAAA;AACA,IAAA,OAAO;AAAA;AAAA,MAEL,aAAA;AAAA;AAAA,MAEA,mBAAmB,YAAY;AAC7B,QAAA,IAAI,CAAC,MAAA,CAAO,IAAA,EAAM,OAAO,KAAA;AACzB,QAAA,OAAO,MAAA,CAAO,KAAM,iBAAA,EAAkB;AAAA,MACxC,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAKA,uBAAuB,YAAY;AACjC,QAAA,OAAO,MAAM,MAAA,CAAO,IAAA,CAAM,qBAAA,EAAsB;AAAA,MAClD,CAAA;AAAA;AAAA,MAEA,YAAY,YAAY;AACtB,QAAA,OAAO,MAAM,MAAA,CAAO,IAAA,EAAM,UAAA,EAAW;AAAA,MACvC,CAAA;AAAA;AAAA,MAEA,YAAA,EAAc,OAAO,MAAA,KAAiC;AAEpD,QAAA,IAAI,OAAA;AACJ,QAAA,MAAM,OAAA,GAAU,IAAI,OAAA,CAAiC,CAAC,QAAA,KAAa;AACjE,UAAA,OAAA,GAAU,QAAA;AAAA,QACZ,CAAC,CAAA;AAGD,QAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,IAAA,CAAM,iBAAA,CAAkB,CAAC,IAAA,KAAS;AACrD,UAAA,IAAI,CAAA,SAAA,EAAY,IAAA,CAAK,QAAQ,CAAA,CAAA,KAAO,OAAO,UAAA,EAAY;AACrD,YAAA,OAAA,CAAQ,IAAI,CAAA;AAAA,UACd;AAAA,QACF,CAAC,CAAA;AAED,QAAA,MAAM,MAAA,CAAO,IAAA,CAAM,YAAA,CAAa,MAAM,CAAA;AAEtC,QAAA,OAAO,MAAM,OAAA,CAAQ,IAAA,CAAK,CAAC,IAAA,KAAS;AAClC,UAAA,KAAA,EAAM;AACN,UAAA,OAAO,IAAA;AAAA,QACT,CAAC,CAAA;AAAA,MACH,CAAA;AAAA;AAAA,MAEA,aAAA;AAAA;AAAA,MAEA,YAAA;AAAA;AAAA,MAEA,mBAAA,EAAqB,OACnB,MAAA,EACA,EAAE,UAAU,gBAAA,EAAiB,GAAkC,EAAC,KACnC;AAC7B,QAAA,MAAM,EAAE,QAAA,EAAU,QAAA,EAAU,UAAA,EAAY,eAAc,GAAI,MAAA;AAC1D,QAAA,MAAM,IAAA,GAAO;AAAA,UACX,QAAA,EAAU,QAAA;AAAA,UACV,aAAA;AAAA,UACA;AAAA,SACF;AAGA,QAAA,MAAM,OAAA,GAAU,aAAaC,0BAAA,CAAmB,KAAA;AAChD,QAAA,MAAM,OAAA,GAAU,aAAaC,iBAAA,CAAU,KAAA;AACvC,QAAA,MAAM,aAAA,GAAgB,OAAA,IAAW,OAAA,GAAU,CAAA,GAAI,CAAA;AAC/C,QAAA,gBAAA,GAAmB,EAAE,UAAU,CAAA,mBAA2B,IAAA,EAAM,GAAG,EAAA,EAAI,IAAA,EAAM,KAAA,EAAO,aAAA,EAAe,CAAA;AACnG,QAAA,MAAM,SAAA,GAAY,MAAM,aAAA,CAAc,EAAE,GAAG,IAAA,EAAM,UAAA,EAAY,GAAG,CAAA;AAChE,QAAA,gBAAA,GAAmB,EAAE,QAAA,EAAU,CAAA,gBAAwB,IAAA,EAAM,CAAA,EAAG,IAAI,SAAA,CAAU,OAAA,EAAS,KAAA,EAAO,aAAA,EAAe,CAAA;AAC7G,QAAA,MAAM,MAAA,GAAS,MAAM,YAAA,CAAa,SAAA,CAAU,OAAO,CAAA;AACnD,QAAA,IAAI,CAAC,OAAA,IAAW,CAAC,OAAA,EAAS;AACxB,UAAA,gBAAA,GAAmB,EAAE,UAAU,CAAA,iBAAyB,IAAA,EAAM,MAAM,EAAA,EAAI,IAAA,EAAM,KAAA,EAAO,aAAA,EAAe,CAAA;AACpG,UAAA,OAAO,CAAC,MAAM,CAAA;AAAA,QAChB;AACA,QAAA,gBAAA,GAAmB,EAAE,UAAU,CAAA,mBAA2B,IAAA,EAAM,GAAG,EAAA,EAAI,IAAA,EAAM,KAAA,EAAO,aAAA,EAAe,CAAA;AACnG,QAAA,MAAM,SAAA,GAAY,MAAM,aAAA,CAAc,EAAE,GAAG,IAAA,EAAM,UAAA,EAAY,GAAG,CAAA;AAChE,QAAA,gBAAA,GAAmB,EAAE,QAAA,EAAU,CAAA,gBAAwB,IAAA,EAAM,CAAA,EAAG,IAAI,SAAA,CAAU,OAAA,EAAS,KAAA,EAAO,aAAA,EAAe,CAAA;AAC7G,QAAA,MAAM,MAAA,GAAS,MAAM,YAAA,CAAa,SAAA,CAAU,OAAO,CAAA;AACnD,QAAA,gBAAA,GAAmB,EAAE,UAAU,CAAA,iBAAyB,IAAA,EAAM,MAAM,EAAA,EAAI,IAAA,EAAM,KAAA,EAAO,aAAA,EAAe,CAAA;AACpG,QAAA,OAAO,CAAC,QAAQ,MAAM,CAAA;AAAA,MACxB,CAAA;AAAA;AAAA,MAEA,iBAAA,EAAmB,CAAC,EAAA,KAA4B;AAC9C,QAAA,OAAO,MAAA,CAAO,IAAA,CAAM,iBAAA,CAAkB,EAAE,CAAA;AAAA,MAC1C,CAAA;AAAA;AAAA,MAEA,cAAA;AAAA;AAAA,MAEA,oBAAA,EAAsB,OAAO,iBAAA,KAA+C;AAC1E,QAAA,OAAO,MAAM,OAAA,CAAQ,GAAA,CAAI,iBAAA,CAAkB,GAAA,CAAI,CAAC,CAAA,KAAM,cAAA,CAAe,CAAA,CAAE,OAAO,CAAC,CAAC,CAAA;AAAA,MAClF,CAAA;AAAA;AAAA,MAEA,aAAa,YAAY;AACvB,QAAA,OAAO,MAAM,MAAA,CAAO,IAAA,CAAM,WAAA,EAAY;AAAA,MACxC,CAAA;AAAA;AAAA,MAEA,WAAA,EAAa,OAAO,KAAA,KAAkB;AACpC,QAAA,OAAO,MAAM,MAAA,CAAO,IAAA,CAAM,WAAA,CAAY,KAAK,CAAA;AAAA,MAC7C;AAAA,KACF;AAAA,EACF,CAAA,EAAG,CAAC,aAAa,CAAC,CAAA;AACpB;AASO,IAAM,mBAAA,GAAsB,CAAC,EAAE,QAAA,EAAU,QAAQ,KAAA,EAAO,SAAA,GAAY,OAAM,KAOnD;AAC5B,EAAA,MAAM,iBAAiBC,2CAAA,CAA4B;AAAA,IACjD,KAAA;AAAA,IACA,cAAc,MAAA,CAAO,MAAA;AAAA,IACrB,MAAM,MAAA,CAAO;AAAA,GACd,CAAA;AAYD,EAAA,MAAM,eAAA,GAAkB,CAAC,MAAA,KAAoC;AAC3D,IAAA,MAAM,GAAA,GAAM,OAAO,MAAM,CAAA;AACzB,IAAA,MAAM,qBAAqB,UAAA,CAAW,IAAA,CAAK,GAAG,CAAA,IAAK,GAAA,CAAI,SAAS,GAAG,CAAA;AACnE,IAAA,MAAM,OAAA,GAAU,GAAA,CAAI,OAAA,CAAQ,UAAA,EAAY,EAAE,CAAA;AAC1C,IAAA,IAAI,KAAA,GAAQC,eAAA,CAAW,OAAA,EAAS,KAAA,CAAM,QAAQ,CAAA;AAC9C,IAAA,IAAI,SAAA,IAAa,CAAC,kBAAA,EAAoB;AACpC,MAAA,KAAA,GAAQ,KAAA,GAAQ,IAAA;AAAA,IAClB;AACA,IAAA,OAAO,KAAA;AAAA,EACT,CAAA;AAGA,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,IAAgB,MAAA,CAA8C,0BAAA,EAA4B;AAC9G,IAAA,OAAO,IAAA;AAAA,EACT;AAIA,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,IAAA,CAAK,CAAC,CAAA,KAAM;AACjC,IAAA,MAAM,SAAA,GAAY,eAAA,CAAgB,CAAA,CAAE,MAAM,CAAA;AAC1C,IAAA,OAAO,SAAA,KAAc,cAAA,IAAkB,SAAA,KAAe,cAAA,GAAiB,CAAC,EAAA;AAAA,EAC1E,CAAC,CAAA;AAED,EAAA,IAAI,CAAC,KAAA,EAAO;AAGV,IAAA,MAAM,aAAA,GAAgB,QAAA,CAAS,IAAA,CAAK,CAAC,CAAA,KAAM;AACzC,MAAA,MAAM,SAAA,GAAY,eAAA,CAAgB,CAAA,CAAE,MAAM,CAAA;AAC1C,MAAA,MAAM,GAAA,GAAM,SAAA,GAAY,EAAA,GAAK,CAAC,SAAA,GAAY,SAAA;AAC1C,MAAA,OAAO,GAAA,KAAQ,cAAA,GAAiB,IAAA,IAAQ,GAAA,GAAM,IAAA,KAAS,cAAA;AAAA,IACzD,CAAC,CAAA;AACD,IAAA,IAAI,aAAA,EAAe;AACjB,MAAA,OAAA,CAAQ,IAAA;AAAA,QACN,CAAA,mCAAA,EAAsC,MAAA,CAAO,aAAA,CAAc,MAAM,CAAC,8BAA8B,cAAA,CAAe,QAAA,EAAU,CAAA,+DAAA,EAA6D,SAAS,CAAA,CAAA;AAAA,OACjM;AAAA,IACF;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,OAAO,KAAA;AACT","file":"useZKTLS.cjs","sourcesContent":["/**\n * @fileoverview React hook and utilities for PeerAuth browser extension integration.\n *\n * The PeerAuth extension (formerly ZK-TLS) provides secure proof generation\n * for off-chain payment verification. This module provides:\n *\n * 1. Type definitions for extension API (window.peer)\n * 2. useZKTLS hook for React components\n * 3. Utility functions for transaction matching and proof encoding\n *\n * @remarks\n * The extension exposes `window.peer` (or deprecated `window.zktls`) for:\n * - Requesting connection (OAuth-like flow)\n * - Authenticating with payment providers\n * - Generating notarized proofs\n * - Fetching transaction metadata\n *\n * @see {@link ZKTLSContext} for the React context provider\n */\n\nimport { useEffect, useMemo, useState } from \"react\"\nimport { encodeAbiParameters, encodePacked, parseAbiParameter, parseUnits, type Hex } from \"viem\"\nimport { sleep } from \"@provex/utils/time\"\nimport type { IntentStruct } from \"@provex/utils/intent\"\nimport type { TokenInfo } from \"@provex/utils/tokens\"\nimport { extensionPlatforms, providers, subProviderConfigs, type ActionType, type PlatformKey, type ProviderKey, type SubProviderKey } from \"@provex/utils/payment\"\nimport { convertTokenInputToCurrency } from \"@provex/utils/conversionRates\"\n\ndeclare global {\n interface ZKTLS {\n requestConnection(): Promise<boolean>\n checkConnectionStatus(): Promise<Status>\n getVersion(): Promise<string>\n authenticate(inputs: AuthenticationInputs): Promise<void>\n generateProof(inputs: GenerateProofInputs): Promise<GenerateProofResponse>\n fetchProofById(proofId: string): Promise<ProofResponse>\n fetchProofs(): Promise<FetchProofsResponse>\n openSidebar(route: string): Promise<void>\n onMetadataMessage(fn: (data: MetadataMessageResponse) => void): () => void\n }\n interface Window {\n /** @deprecated Use window.peer instead */\n zktls: ZKTLS | undefined\n /** PeerAuth extension API (replaces window.zktls) */\n peer: ZKTLS | undefined\n }\n}\n\n/** the status of the PeerAuth extension */\nexport type Status = 'connected' | 'disconnected' | 'pending'\n\n/** the individual metadata message sent by the PeerAuth extension */\nexport interface MetadataMessage {\n amount: number\n /** Currency code (e.g., 'USD', 'EUR') */\n currency?: string\n /**\n * Date of the transaction.\n * Can be a string in YYYYMMDD format, a number (YYYYMMDD or timestamp), or Date object.\n * The actual type depends on the extension implementation.\n */\n date: string | number | Date\n hidden: boolean\n originalIndex: number\n paymentId: number\n recipient: string\n}\n\n/** the response from the PeerAuth extension when a metadata message is received */\nexport interface MetadataMessageResponse {\n expiresAt: number\n platform: ProviderKey\n requestId: string\n metadata: MetadataMessage[]\n}\n\n/** the response from the PeerAuth extension when fetching proofs */\nexport interface FetchProofsResponse {\n notaryRequests: NotaryRequest[]\n}\n\n/** the inputs for the generateProof function */\nexport type GenerateProofInputsAbstracted = {\n platform: PlatformKey\n provider: ProviderKey\n intentHash: Hex\n originalIndex: number\n}\n\n/** the inputs for the generateProof function */\nexport type GenerateProofInputs = {\n platform: ProviderKey\n originalIndex: number\n proofIndex?: number\n intentHash: string\n}\n\n/**\n * inputs for the generate proof function that requires the intent hash\n * as hex to ensure it can be converted to a bigint string accurately\n */\nexport type HexIntentGenerateProofInputs = Exclude<GenerateProofInputs, 'intentHash'> & { intentHash: Hex }\n\n/** the response from the PeerAuth extension when generating a proof */\nexport type GenerateProofResponse = {\n proofId: string\n platform: ProviderKey\n}\n\n/** the inputs for the authenticate function */\nexport type AuthenticationInputs = {\n actionType: ActionType\n platform: PlatformKey\n}\n\n/** the response from the PeerAuth extension when fetching a proof */\nexport interface Proof {\n claimInfo: ClaimInfo\n signedClaim: SignedClaim\n isAppclipProof: boolean\n status: string\n}\n\n/** the response from the PeerAuth extension when fetching a proof */\nexport interface NotarizedProof {\n claim: {\n context: string\n epoch: number\n identifier: Hex\n owner: Hex\n parameters: string\n provider: string\n timestampS: number\n },\n signatures: {\n attestorAddress: Hex\n claimSignature: Record<number, number>\n resultSignature: Record<number, number>\n },\n}\n\n/** the claim info for a proof */\nexport interface ClaimInfo {\n provider: string\n parameters: string\n context: string\n}\n\n/** the complete claim data for a proof */\nexport interface CompleteClaimData {\n identifier: Hex\n owner: Hex\n timestampS: number\n epoch: number\n}\n\n/** the signed claim for a proof */\nexport interface SignedClaim {\n claim: CompleteClaimData\n signatures: Hex[]\n}\n\n/** the reclaim proof for a proof */\nexport type ReclaimProof = {\n claimInfo: ClaimInfo\n signedClaim: SignedClaim\n isAppclipProof: boolean\n}\n\n/** the notary request for a proof */\nexport interface NotaryRequest {\n metadata: (string | number)[]\n actionType: ActionType\n id: string\n status: string\n timestamp: number\n proof: NotarizedProof\n}\n\n/** the response from the PeerAuth extension when fetching a proof */\nexport interface ProofResponse {\n notaryRequest: NotaryRequest\n}\n\nexport const extensionUrl = 'https://chromewebstore.google.com/detail/ijpgccednehjpeclfcllnjjcmiohdjih'\n\n/** convert a byte array to a hex string */\nexport const byteArrayToHexString = (byteArray: number[]): Hex => {\n return `0x${byteArray\n .map(byte => byte.toString(16).padStart(2, '0'))\n .join('')}`\n}\n\n/** parse a proof object from the PeerAuth extension */\nexport const parseExtensionProof = (proofObject: NotarizedProof) => {\n return {\n claimInfo: {\n provider: proofObject.claim.provider,\n parameters: proofObject.claim.parameters,\n context: proofObject.claim.context\n },\n signedClaim: {\n claim: {\n identifier: proofObject.claim.identifier as Hex,\n owner: proofObject.claim.owner as Hex,\n timestampS: proofObject.claim.timestampS,\n epoch: proofObject.claim.epoch\n },\n signatures: [byteArrayToHexString(Object.values(proofObject.signatures.claimSignature))]\n },\n isAppclipProof: false\n } as ReclaimProof\n}\n\n/** the abi encoding for a proof */\nexport const PROOF_ENCODING = parseAbiParameter(\"((string provider, string parameters, string context) claimInfo, ((bytes32 identifier, address owner, uint32 timestampS, uint32 epoch) claim, bytes[] signatures) signedClaim, bool isAppclipProof)\")\n\n/** encode a single proof as a bytes array */\nexport function encodeProofAsBytes(proof: ReclaimProof): Hex {\n return encodeAbiParameters([PROOF_ENCODING], [proof])\n}\n\n/** encode two proofs to be passed to the underlying sub-provider */\nexport const encodeTwoProofs = (proof1: ReclaimProof, proof2: ReclaimProof) => {\n return encodeAbiParameters([PROOF_ENCODING, PROOF_ENCODING], [proof1, proof2])\n}\n\n/** a high level function to encode a proof for a given provider and sub-provider */\nexport const encodeProof = ({ extensionProofs, subProvider, provider }: {\n extensionProofs: NotarizedProof[],\n subProvider: PlatformKey | null,\n provider: ProviderKey\n}) => {\n const reclaimProofs = extensionProofs.map((p) => parseExtensionProof(p))\n if (provider === 'zelle') {\n // move this to check the blockchain for the payment method\n const paymentMethod = subProviderConfigs![provider]![subProvider as SubProviderKey]!.paymentMethod\n const twoEncoded = reclaimProofs.length === 2\n ? encodeTwoProofs(reclaimProofs[0]!, reclaimProofs[1]!)\n : encodeProofAsBytes(reclaimProofs[0]!)\n // select between various possible sub-providers\n const withPaymentMethod = encodeProofWithPaymentMethod({\n paymentMethod,\n proof: twoEncoded,\n })\n return withPaymentMethod\n }\n const [reclaimProof] = reclaimProofs\n return encodeProofAsBytes(reclaimProof!)\n}\n\n/**\n * wrap a proof with a payment method and proof\n * this allows us to use a single verifier as an entry point for multiple underlying sub-providers\n */\nexport const encodeProofWithPaymentMethod = ({\n proof,\n paymentMethod\n}: {\n proof: Hex,\n paymentMethod: number\n}): Hex => {\n return encodePacked(['uint8', 'bytes'], [paymentMethod, proof])\n}\n\n/** the progress of a proof series */\nexport enum SeriesProgress {\n Generating,\n Polling,\n Complete,\n}\n\nexport type ProgressInfo = {\n progress: SeriesProgress\n total: number\n step: number | null\n id: string | null\n}\n\n/** the mutations for the generate proof series function */\nexport type GenerateProofSeriesMutations = {\n progress?: ({ progress, step, id }: ProgressInfo) => void\n setOwnerName?: (name: string) => void\n}\n\n/** React hook to interact with the PeerAuth extension */\nexport const useZKTLS = () => {\n const [isInitialized, setIsInitialized] = useState(false)\n useEffect(() => {\n const setup = () => {\n setIsInitialized(true)\n }\n const eventName = 'peer#initialized'\n if (typeof window.peer !== 'undefined') {\n // api is available\n setup()\n } else {\n window.addEventListener(eventName, setup)\n return () => {\n window.removeEventListener(eventName, setup)\n }\n }\n }, [])\n return useMemo(() => {\n /** fetch a proof by its id */\n const fetchProofById = async (proofId: string): Promise<NotaryRequest | null> => {\n const proof = await window.peer!.fetchProofById(proofId)\n if (proof && proof.notaryRequest) return proof.notaryRequest\n const proofs = await window.peer!.fetchProofs()\n const proofFromList = proofs.notaryRequests.find((p) => p.id === proofId)\n if (proofFromList) return proofFromList\n return null\n }\n /** wait for a proof to be generated */\n const waitForProof = async (proofId: string, onCurrent?: (notaryRequest: NotaryRequest | null) => void) => {\n let notaryRequest: NotaryRequest | null = null\n do {\n notaryRequest = await fetchProofById(proofId)\n onCurrent?.(notaryRequest)\n await sleep(1_000)\n } while (!notaryRequest || !notaryRequest.status || notaryRequest.status === 'pending')\n if (notaryRequest.status === 'failed' || notaryRequest.status === 'expired' || notaryRequest.status === 'cancelled' || notaryRequest.status === 'error') {\n console.error('[waitForProof] proof terminal state:', JSON.stringify(notaryRequest, null, 2))\n const req = notaryRequest as unknown as Record<string, unknown>\n const detail = req.errorMessage ?? req.error ?? req.message ?? notaryRequest.status\n throw new Error(`Proof generation failed: ${detail}`)\n }\n return notaryRequest\n }\n /** generate a proof */\n const generateProof = async (inputs: HexIntentGenerateProofInputs): Promise<GenerateProofResponse> => {\n return await window.peer!.generateProof({\n proofIndex: 0,\n ...inputs,\n intentHash: BigInt(inputs.intentHash).toString(),\n })\n }\n return {\n /** check if the PeerAuth extension is initialized */\n isInitialized,\n /** request a connection to the PeerAuth extension */\n requestConnection: async () => {\n if (!window.peer) return false\n return window.peer!.requestConnection()\n },\n /**\n * check the connection status of the PeerAuth extension\n * @returns the connection status\n */\n checkConnectionStatus: async () => {\n return await window.peer!.checkConnectionStatus()\n },\n /** get the version of the PeerAuth extension */\n getVersion: async () => {\n return await window.peer?.getVersion()\n },\n /** authenticate with the PeerAuth extension */\n authenticate: async (inputs: AuthenticationInputs) => {\n // Create promise first to avoid race condition where message arrives before resolver is assigned\n let resolve: (value: MetadataMessageResponse) => void\n const promise = new Promise<MetadataMessageResponse>((resolver) => {\n resolve = resolver\n })\n\n // Now set up the listener - resolve is guaranteed to be the real resolver\n const unsub = window.peer!.onMetadataMessage((data) => {\n if (`transfer_${data.platform}` === inputs.actionType) {\n resolve(data)\n }\n })\n\n await window.peer!.authenticate(inputs)\n\n return await promise.then((data) => {\n unsub()\n return data\n })\n },\n /** generate a proof */\n generateProof,\n /** wait for a proof to be generated */\n waitForProof,\n /** generate a proof series */\n generateProofSeries: async (\n inputs: GenerateProofInputsAbstracted,\n { progress: progressCallback }: GenerateProofSeriesMutations = {},\n ): Promise<NotaryRequest[]> => {\n const { platform, provider, intentHash, originalIndex } = inputs\n const args = {\n platform: provider,\n originalIndex,\n intentHash,\n } as const\n // Chase requires 2 proofs (account verification + transaction)\n // Platform is the bank name (e.g., 'chase') from extensionPlatform config\n const isChase = platform === extensionPlatforms.CHASE\n const isZelle = provider === providers.ZELLE\n const expectedTotal = isZelle && isChase ? 2 : 1\n progressCallback?.({ progress: SeriesProgress.Generating, step: 0, id: null, total: expectedTotal })\n const genProofA = await generateProof({ ...args, proofIndex: 0 })\n progressCallback?.({ progress: SeriesProgress.Polling, step: 0, id: genProofA.proofId, total: expectedTotal })\n const proofA = await waitForProof(genProofA.proofId)\n if (!isChase || !isZelle) {\n progressCallback?.({ progress: SeriesProgress.Complete, step: null, id: null, total: expectedTotal })\n return [proofA]\n }\n progressCallback?.({ progress: SeriesProgress.Generating, step: 1, id: null, total: expectedTotal })\n const genProofB = await generateProof({ ...args, proofIndex: 1 })\n progressCallback?.({ progress: SeriesProgress.Polling, step: 1, id: genProofB.proofId, total: expectedTotal })\n const proofB = await waitForProof(genProofB.proofId)\n progressCallback?.({ progress: SeriesProgress.Complete, step: null, id: null, total: expectedTotal })\n return [proofA, proofB]\n },\n /** subscribe to metadata messages */\n onMetadataMessage: (fn: (data: any) => void) => {\n return window.peer!.onMetadataMessage(fn)\n },\n /** fetch a proof by its id */\n fetchProofById,\n /** fetch generated proofs */\n fetchGeneratedProofs: async (genProofResponses: GenerateProofResponse[]) => {\n return await Promise.all(genProofResponses.map((r) => fetchProofById(r.proofId)))\n },\n /** fetch all proofs */\n fetchProofs: async () => {\n return await window.peer!.fetchProofs()\n },\n /** open the PeerAuth sidebar */\n openSidebar: async (route: string) => {\n return await window.peer!.openSidebar(route)\n },\n }\n }, [isInitialized])\n}\n\n/**\n * Find the metadata message that matches the intent by amount.\n * Returns the first (most recent) transaction in the metadata array that matches the expected amount.\n *\n * Simplified matching: just find transactions with the correct amount.\n * The user can manually select if multiple matches exist.\n */\nexport const findMetadataMessage = ({ metadata, intent, token, centIsInt = false }: {\n metadata: MetadataMessage[],\n intent: IntentStruct,\n token: TokenInfo,\n /** @deprecated No longer used - kept for API compatibility */\n recipient?: string,\n centIsInt?: boolean,\n}): MetadataMessage | null => {\n const currencyAmount = convertTokenInputToCurrency({\n token,\n amountOutInt: intent.amount,\n rate: intent.conversionRate,\n })\n /**\n * Normalize an amount from the extension into a bigint in token base units.\n *\n * The extension sends amounts in different formats per provider:\n * - Venmo: `\"- $1.00\"` (formatted dollar string)\n * - Others: `100` (integer cents) or `1.00` (decimal dollars)\n *\n * We detect the format by checking for currency symbols or decimal points\n * in the raw value. If present, the value is already in dollars and we\n * skip the centIsInt division.\n */\n const normalizeAmount = (amount: number | string): bigint => {\n const raw = String(amount)\n const isFormattedDollars = /[^0-9\\-]/.test(raw) && raw.includes('.')\n const cleaned = raw.replace(/[^0-9.]/g, '')\n let value = parseUnits(cleaned, token.decimals)\n if (centIsInt && !isFormattedDollars) {\n value = value / 100n\n }\n return value\n }\n\n // Skip auto-match when manual selection is forced (dev/testing)\n if (typeof window !== 'undefined' && (window as unknown as Record<string, unknown>).__FORCE_MANUAL_TX_SELECT__) {\n return null\n }\n\n // Find the first transaction that matches the amount (first in array = most recent)\n // Note: We ignore the hidden flag - matching is purely by amount\n const match = metadata.find((m) => {\n const converted = normalizeAmount(m.amount)\n return converted === currencyAmount || converted === (currencyAmount * -1n)\n })\n\n if (!match) {\n // Detect 100x scale mismatch — the most common failure mode when centIsInt\n // is wrong for a provider. Fires loudly so it's obvious in dev/staging logs.\n const hundredxMatch = metadata.find((m) => {\n const converted = normalizeAmount(m.amount)\n const abs = converted < 0n ? -converted : converted\n return abs === currencyAmount * 100n || abs * 100n === currencyAmount\n })\n if (hundredxMatch) {\n console.warn(\n `[findMetadataMessage] tx[0] amount=${String(hundredxMatch.amount)} is 100x off from expected ${currencyAmount.toString()} — centIsInt is likely wrong for this provider (currently ${centIsInt})`\n )\n }\n return null\n }\n\n return match\n}\n"]}
|
package/dist/useZKTLS.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { PROOF_ENCODING, SeriesProgress, byteArrayToHexString, encodeProof, encodeProofAsBytes, encodeProofWithPaymentMethod, encodeTwoProofs, extensionUrl, findMetadataMessage, parseExtensionProof, useZKTLS } from './chunk-
|
|
1
|
+
export { PROOF_ENCODING, SeriesProgress, byteArrayToHexString, encodeProof, encodeProofAsBytes, encodeProofWithPaymentMethod, encodeTwoProofs, extensionUrl, findMetadataMessage, parseExtensionProof, useZKTLS } from './chunk-W2QUSBIS.js';
|
|
2
2
|
//# sourceMappingURL=useZKTLS.js.map
|
|
3
3
|
//# sourceMappingURL=useZKTLS.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useZKTLS.ts","../src/ZKTLSContext.tsx"],"names":["parseAbiParameter","createContext","useContext"],"mappings":";;;;;;;;;;AAuN8BA,uBAAkB,qMAAqM;ACtM9O,IAAM,YAAA,GAAeC,oBAA4C,MAAS,CAAA;AAY1E,SAAS,eAAA,GAAkB;AAChC,EAAA,MAAM,OAAA,GAAUC,iBAAW,YAAY,CAAA;AACvC,EAAA,IAAI,YAAY,MAAA,EAAW;AACzB,IAAA,MAAM,IAAI,MAAM,qDAAqD,CAAA;AAAA,EACvE;AACA,EAAA,OAAO,OAAA;AACT","file":"useZKTLSContext.cjs","sourcesContent":["/**\n * @fileoverview React hook and utilities for PeerAuth browser extension integration.\n *\n * The PeerAuth extension (formerly ZK-TLS) provides secure proof generation\n * for off-chain payment verification. This module provides:\n *\n * 1. Type definitions for extension API (window.peer)\n * 2. useZKTLS hook for React components\n * 3. Utility functions for transaction matching and proof encoding\n *\n * @remarks\n * The extension exposes `window.peer` (or deprecated `window.zktls`) for:\n * - Requesting connection (OAuth-like flow)\n * - Authenticating with payment providers\n * - Generating notarized proofs\n * - Fetching transaction metadata\n *\n * @see {@link ZKTLSContext} for the React context provider\n */\n\nimport { useEffect, useMemo, useState } from \"react\"\nimport { encodeAbiParameters, encodePacked, parseAbiParameter, parseUnits, type Hex } from \"viem\"\nimport { sleep } from \"@provex/utils/time\"\nimport type { IntentStruct } from \"@provex/utils/intent\"\nimport type { TokenInfo } from \"@provex/utils/tokens\"\nimport { extensionPlatforms, providers, subProviderConfigs, type ActionType, type PlatformKey, type ProviderKey, type SubProviderKey } from \"@provex/utils/payment\"\nimport { convertTokenInputToCurrency } from \"@provex/utils/conversionRates\"\n\ndeclare global {\n interface ZKTLS {\n requestConnection(): Promise<boolean>\n checkConnectionStatus(): Promise<Status>\n getVersion(): Promise<string>\n authenticate(inputs: AuthenticationInputs): Promise<void>\n generateProof(inputs: GenerateProofInputs): Promise<GenerateProofResponse>\n fetchProofById(proofId: string): Promise<ProofResponse>\n fetchProofs(): Promise<FetchProofsResponse>\n openSidebar(route: string): Promise<void>\n onMetadataMessage(fn: (data: MetadataMessageResponse) => void): () => void\n }\n interface Window {\n /** @deprecated Use window.peer instead */\n zktls: ZKTLS | undefined\n /** PeerAuth extension API (replaces window.zktls) */\n peer: ZKTLS | undefined\n }\n}\n\n/** the status of the PeerAuth extension */\nexport type Status = 'connected' | 'disconnected' | 'pending'\n\n/** the individual metadata message sent by the PeerAuth extension */\nexport interface MetadataMessage {\n amount: number\n /** Currency code (e.g., 'USD', 'EUR') */\n currency?: string\n /**\n * Date of the transaction.\n * Can be a string in YYYYMMDD format, a number (YYYYMMDD or timestamp), or Date object.\n * The actual type depends on the extension implementation.\n */\n date: string | number | Date\n hidden: boolean\n originalIndex: number\n paymentId: number\n recipient: string\n}\n\n/** the response from the PeerAuth extension when a metadata message is received */\nexport interface MetadataMessageResponse {\n expiresAt: number\n platform: ProviderKey\n requestId: string\n metadata: MetadataMessage[]\n}\n\n/** the response from the PeerAuth extension when fetching proofs */\nexport interface FetchProofsResponse {\n notaryRequests: NotaryRequest[]\n}\n\n/** the inputs for the generateProof function */\nexport type GenerateProofInputsAbstracted = {\n platform: PlatformKey\n provider: ProviderKey\n intentHash: Hex\n originalIndex: number\n}\n\n/** the inputs for the generateProof function */\nexport type GenerateProofInputs = {\n platform: ProviderKey\n originalIndex: number\n proofIndex?: number\n intentHash: string\n}\n\n/**\n * inputs for the generate proof function that requires the intent hash\n * as hex to ensure it can be converted to a bigint string accurately\n */\nexport type HexIntentGenerateProofInputs = Exclude<GenerateProofInputs, 'intentHash'> & { intentHash: Hex }\n\n/** the response from the PeerAuth extension when generating a proof */\nexport type GenerateProofResponse = {\n proofId: string\n platform: ProviderKey\n}\n\n/** the inputs for the authenticate function */\nexport type AuthenticationInputs = {\n actionType: ActionType\n platform: PlatformKey\n}\n\n/** the response from the PeerAuth extension when fetching a proof */\nexport interface Proof {\n claimInfo: ClaimInfo\n signedClaim: SignedClaim\n isAppclipProof: boolean\n status: string\n}\n\n/** the response from the PeerAuth extension when fetching a proof */\nexport interface NotarizedProof {\n claim: {\n context: string\n epoch: number\n identifier: Hex\n owner: Hex\n parameters: string\n provider: string\n timestampS: number\n },\n signatures: {\n attestorAddress: Hex\n claimSignature: Record<number, number>\n resultSignature: Record<number, number>\n },\n}\n\n/** the claim info for a proof */\nexport interface ClaimInfo {\n provider: string\n parameters: string\n context: string\n}\n\n/** the complete claim data for a proof */\nexport interface CompleteClaimData {\n identifier: Hex\n owner: Hex\n timestampS: number\n epoch: number\n}\n\n/** the signed claim for a proof */\nexport interface SignedClaim {\n claim: CompleteClaimData\n signatures: Hex[]\n}\n\n/** the reclaim proof for a proof */\nexport type ReclaimProof = {\n claimInfo: ClaimInfo\n signedClaim: SignedClaim\n isAppclipProof: boolean\n}\n\n/** the notary request for a proof */\nexport interface NotaryRequest {\n metadata: (string | number)[]\n actionType: ActionType\n id: string\n status: string\n timestamp: number\n proof: NotarizedProof\n}\n\n/** the response from the PeerAuth extension when fetching a proof */\nexport interface ProofResponse {\n notaryRequest: NotaryRequest\n}\n\nexport const extensionUrl = 'https://chromewebstore.google.com/detail/ijpgccednehjpeclfcllnjjcmiohdjih'\n\n/** convert a byte array to a hex string */\nexport const byteArrayToHexString = (byteArray: number[]): Hex => {\n return `0x${byteArray\n .map(byte => byte.toString(16).padStart(2, '0'))\n .join('')}`\n}\n\n/** parse a proof object from the PeerAuth extension */\nexport const parseExtensionProof = (proofObject: NotarizedProof) => {\n return {\n claimInfo: {\n provider: proofObject.claim.provider,\n parameters: proofObject.claim.parameters,\n context: proofObject.claim.context\n },\n signedClaim: {\n claim: {\n identifier: proofObject.claim.identifier as Hex,\n owner: proofObject.claim.owner as Hex,\n timestampS: proofObject.claim.timestampS,\n epoch: proofObject.claim.epoch\n },\n signatures: [byteArrayToHexString(Object.values(proofObject.signatures.claimSignature))]\n },\n isAppclipProof: false\n } as ReclaimProof\n}\n\n/** the abi encoding for a proof */\nexport const PROOF_ENCODING = parseAbiParameter(\"((string provider, string parameters, string context) claimInfo, ((bytes32 identifier, address owner, uint32 timestampS, uint32 epoch) claim, bytes[] signatures) signedClaim, bool isAppclipProof)\")\n\n/** encode a single proof as a bytes array */\nexport function encodeProofAsBytes(proof: ReclaimProof): Hex {\n return encodeAbiParameters([PROOF_ENCODING], [proof])\n}\n\n/** encode two proofs to be passed to the underlying sub-provider */\nexport const encodeTwoProofs = (proof1: ReclaimProof, proof2: ReclaimProof) => {\n return encodeAbiParameters([PROOF_ENCODING, PROOF_ENCODING], [proof1, proof2])\n}\n\n/** a high level function to encode a proof for a given provider and sub-provider */\nexport const encodeProof = ({ extensionProofs, subProvider, provider }: {\n extensionProofs: NotarizedProof[],\n subProvider: PlatformKey | null,\n provider: ProviderKey\n}) => {\n const reclaimProofs = extensionProofs.map((p) => parseExtensionProof(p))\n if (provider === 'zelle') {\n // move this to check the blockchain for the payment method\n const paymentMethod = subProviderConfigs![provider]![subProvider as SubProviderKey]!.paymentMethod\n const twoEncoded = reclaimProofs.length === 2\n ? encodeTwoProofs(reclaimProofs[0]!, reclaimProofs[1]!)\n : encodeProofAsBytes(reclaimProofs[0]!)\n // select between various possible sub-providers\n const withPaymentMethod = encodeProofWithPaymentMethod({\n paymentMethod,\n proof: twoEncoded,\n })\n return withPaymentMethod\n }\n const [reclaimProof] = reclaimProofs\n return encodeProofAsBytes(reclaimProof!)\n}\n\n/**\n * wrap a proof with a payment method and proof\n * this allows us to use a single verifier as an entry point for multiple underlying sub-providers\n */\nexport const encodeProofWithPaymentMethod = ({\n proof,\n paymentMethod\n}: {\n proof: Hex,\n paymentMethod: number\n}): Hex => {\n return encodePacked(['uint8', 'bytes'], [paymentMethod, proof])\n}\n\n/** the progress of a proof series */\nexport enum SeriesProgress {\n Generating,\n Polling,\n Complete,\n}\n\nexport type ProgressInfo = {\n progress: SeriesProgress\n total: number\n step: number | null\n id: string | null\n}\n\n/** the mutations for the generate proof series function */\nexport type GenerateProofSeriesMutations = {\n progress?: ({ progress, step, id }: ProgressInfo) => void\n setOwnerName?: (name: string) => void\n}\n\n/** React hook to interact with the PeerAuth extension */\nexport const useZKTLS = () => {\n const [isInitialized, setIsInitialized] = useState(false)\n useEffect(() => {\n const setup = () => {\n setIsInitialized(true)\n }\n const eventName = 'peer#initialized'\n if (typeof window.peer !== 'undefined') {\n // api is available\n setup()\n } else {\n window.addEventListener(eventName, setup)\n return () => {\n window.removeEventListener(eventName, setup)\n }\n }\n }, [])\n return useMemo(() => {\n /** fetch a proof by its id */\n const fetchProofById = async (proofId: string): Promise<NotaryRequest | null> => {\n const proof = await window.peer!.fetchProofById(proofId)\n if (proof && proof.notaryRequest) return proof.notaryRequest\n const proofs = await window.peer!.fetchProofs()\n const proofFromList = proofs.notaryRequests.find((p) => p.id === proofId)\n if (proofFromList) return proofFromList\n return null\n }\n /** wait for a proof to be generated */\n const waitForProof = async (proofId: string, onCurrent?: (notaryRequest: NotaryRequest | null) => void) => {\n let notaryRequest: NotaryRequest | null = null\n do {\n notaryRequest = await fetchProofById(proofId)\n onCurrent?.(notaryRequest)\n await sleep(1_000)\n } while (!notaryRequest || !notaryRequest.status || notaryRequest.status === 'pending')\n if (notaryRequest.status === 'failed' || notaryRequest.status === 'expired' || notaryRequest.status === 'cancelled' || notaryRequest.status === 'error') {\n throw new Error(`Proof generation failed: ${notaryRequest.status}`)\n }\n return notaryRequest\n }\n /** generate a proof */\n const generateProof = async (inputs: HexIntentGenerateProofInputs): Promise<GenerateProofResponse> => {\n return await window.peer!.generateProof({\n proofIndex: 0,\n ...inputs,\n intentHash: BigInt(inputs.intentHash).toString(),\n })\n }\n return {\n /** check if the PeerAuth extension is initialized */\n isInitialized,\n /** request a connection to the PeerAuth extension */\n requestConnection: async () => {\n if (!window.peer) return false\n return window.peer!.requestConnection()\n },\n /**\n * check the connection status of the PeerAuth extension\n * @returns the connection status\n */\n checkConnectionStatus: async () => {\n return await window.peer!.checkConnectionStatus()\n },\n /** get the version of the PeerAuth extension */\n getVersion: async () => {\n return await window.peer?.getVersion()\n },\n /** authenticate with the PeerAuth extension */\n authenticate: async (inputs: AuthenticationInputs) => {\n // Create promise first to avoid race condition where message arrives before resolver is assigned\n let resolve: (value: MetadataMessageResponse) => void\n const promise = new Promise<MetadataMessageResponse>((resolver) => {\n resolve = resolver\n })\n\n // Now set up the listener - resolve is guaranteed to be the real resolver\n const unsub = window.peer!.onMetadataMessage((data) => {\n if (`transfer_${data.platform}` === inputs.actionType) {\n resolve(data)\n }\n })\n\n await window.peer!.authenticate(inputs)\n\n return await promise.then((data) => {\n unsub()\n return data\n })\n },\n /** generate a proof */\n generateProof,\n /** wait for a proof to be generated */\n waitForProof,\n /** generate a proof series */\n generateProofSeries: async (\n inputs: GenerateProofInputsAbstracted,\n { progress: progressCallback }: GenerateProofSeriesMutations = {},\n ): Promise<NotaryRequest[]> => {\n const { platform, provider, intentHash, originalIndex } = inputs\n const args = {\n platform: provider,\n originalIndex,\n intentHash,\n } as const\n // Chase requires 2 proofs (account verification + transaction)\n // Platform is the bank name (e.g., 'chase') from extensionPlatform config\n const isChase = platform === extensionPlatforms.CHASE\n const isZelle = provider === providers.ZELLE\n const expectedTotal = isZelle && isChase ? 2 : 1\n progressCallback?.({ progress: SeriesProgress.Generating, step: 0, id: null, total: expectedTotal })\n const genProofA = await generateProof({ ...args, proofIndex: 0 })\n progressCallback?.({ progress: SeriesProgress.Polling, step: 0, id: genProofA.proofId, total: expectedTotal })\n const proofA = await waitForProof(genProofA.proofId)\n if (!isChase || !isZelle) {\n progressCallback?.({ progress: SeriesProgress.Complete, step: null, id: null, total: expectedTotal })\n return [proofA]\n }\n progressCallback?.({ progress: SeriesProgress.Generating, step: 1, id: null, total: expectedTotal })\n const genProofB = await generateProof({ ...args, proofIndex: 1 })\n progressCallback?.({ progress: SeriesProgress.Polling, step: 1, id: genProofB.proofId, total: expectedTotal })\n const proofB = await waitForProof(genProofB.proofId)\n progressCallback?.({ progress: SeriesProgress.Complete, step: null, id: null, total: expectedTotal })\n return [proofA, proofB]\n },\n /** subscribe to metadata messages */\n onMetadataMessage: (fn: (data: any) => void) => {\n return window.peer!.onMetadataMessage(fn)\n },\n /** fetch a proof by its id */\n fetchProofById,\n /** fetch generated proofs */\n fetchGeneratedProofs: async (genProofResponses: GenerateProofResponse[]) => {\n return await Promise.all(genProofResponses.map((r) => fetchProofById(r.proofId)))\n },\n /** fetch all proofs */\n fetchProofs: async () => {\n return await window.peer!.fetchProofs()\n },\n /** open the PeerAuth sidebar */\n openSidebar: async (route: string) => {\n return await window.peer!.openSidebar(route)\n },\n }\n }, [isInitialized])\n}\n\n/**\n * Find the metadata message that matches the intent by amount.\n * Returns the first (most recent) transaction in the metadata array that matches the expected amount.\n *\n * Simplified matching: just find transactions with the correct amount.\n * The user can manually select if multiple matches exist.\n */\nexport const findMetadataMessage = ({ metadata, intent, token, centIsInt = false }: {\n metadata: MetadataMessage[],\n intent: IntentStruct,\n token: TokenInfo,\n /** @deprecated No longer used - kept for API compatibility */\n recipient?: string,\n centIsInt?: boolean,\n}): MetadataMessage | null => {\n const currencyAmount = convertTokenInputToCurrency({\n token,\n amountOutInt: intent.amount,\n rate: intent.conversionRate,\n })\n /**\n * Normalize an amount from the extension into a bigint in token base units.\n *\n * The extension sends amounts in different formats per provider:\n * - Venmo: `\"- $1.00\"` (formatted dollar string)\n * - Others: `100` (integer cents) or `1.00` (decimal dollars)\n *\n * We detect the format by checking for currency symbols or decimal points\n * in the raw value. If present, the value is already in dollars and we\n * skip the centIsInt division.\n */\n const normalizeAmount = (amount: number | string): bigint => {\n const raw = String(amount)\n const isFormattedDollars = /[^0-9\\-]/.test(raw) && raw.includes('.')\n const cleaned = raw.replace(/[^0-9.]/g, '')\n let value = parseUnits(cleaned, token.decimals)\n if (centIsInt && !isFormattedDollars) {\n value = value / 100n\n }\n return value\n }\n\n // Skip auto-match when manual selection is forced (dev/testing)\n if (typeof window !== 'undefined' && (window as unknown as Record<string, unknown>).__FORCE_MANUAL_TX_SELECT__) {\n return null\n }\n\n // Find the first transaction that matches the amount (first in array = most recent)\n // Note: We ignore the hidden flag - matching is purely by amount\n const match = metadata.find((m) => {\n const converted = normalizeAmount(m.amount)\n return converted === currencyAmount || converted === (currencyAmount * -1n)\n })\n\n if (!match) {\n return null\n }\n\n return match\n}\n","/**\n * @fileoverview React context for PeerAuth extension state.\n *\n * Provides global access to the useZKTLS hook state throughout the\n * component tree, avoiding prop drilling for extension status.\n *\n * @see {@link useZKTLS} for the underlying hook\n */\n\nimport { createContext, useContext, type ReactNode } from 'react'\nimport { useZKTLS } from './useZKTLS'\n\n/**\n * Context type derived from useZKTLS hook return value.\n */\ntype ZKTLSContextType = ReturnType<typeof useZKTLS>\n\nexport const ZKTLSContext = createContext<ZKTLSContextType | undefined>(undefined)\n\ninterface ZKTLSProviderProps {\n children: ReactNode\n}\n\n/**\n * Hook to consume the ZKTLS context.\n * Must be used within a ZKTLSProvider.\n *\n * @throws Error if used outside of ZKTLSProvider\n */\nexport function useZKTLSContext() {\n const context = useContext(ZKTLSContext)\n if (context === undefined) {\n throw new Error('useZKTLSContext must be used within a ZKTLSProvider')\n }\n return context\n}\n\nexport function ZKTLSProvider({ children }: ZKTLSProviderProps) {\n const zktlsHook = useZKTLS()\n\n return (\n <ZKTLSContext.Provider value={zktlsHook}>\n {children}\n </ZKTLSContext.Provider>\n )\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/useZKTLS.ts","../src/ZKTLSContext.tsx"],"names":["parseAbiParameter","createContext","useContext"],"mappings":";;;;;;;;;;AAuN8BA,uBAAkB,qMAAqM;ACtM9O,IAAM,YAAA,GAAeC,oBAA4C,MAAS,CAAA;AAY1E,SAAS,eAAA,GAAkB;AAChC,EAAA,MAAM,OAAA,GAAUC,iBAAW,YAAY,CAAA;AACvC,EAAA,IAAI,YAAY,MAAA,EAAW;AACzB,IAAA,MAAM,IAAI,MAAM,qDAAqD,CAAA;AAAA,EACvE;AACA,EAAA,OAAO,OAAA;AACT","file":"useZKTLSContext.cjs","sourcesContent":["/**\n * @fileoverview React hook and utilities for PeerAuth browser extension integration.\n *\n * The PeerAuth extension (formerly ZK-TLS) provides secure proof generation\n * for off-chain payment verification. This module provides:\n *\n * 1. Type definitions for extension API (window.peer)\n * 2. useZKTLS hook for React components\n * 3. Utility functions for transaction matching and proof encoding\n *\n * @remarks\n * The extension exposes `window.peer` (or deprecated `window.zktls`) for:\n * - Requesting connection (OAuth-like flow)\n * - Authenticating with payment providers\n * - Generating notarized proofs\n * - Fetching transaction metadata\n *\n * @see {@link ZKTLSContext} for the React context provider\n */\n\nimport { useEffect, useMemo, useState } from \"react\"\nimport { encodeAbiParameters, encodePacked, parseAbiParameter, parseUnits, type Hex } from \"viem\"\nimport { sleep } from \"@provex/utils/time\"\nimport type { IntentStruct } from \"@provex/utils/intent\"\nimport type { TokenInfo } from \"@provex/utils/tokens\"\nimport { extensionPlatforms, providers, subProviderConfigs, type ActionType, type PlatformKey, type ProviderKey, type SubProviderKey } from \"@provex/utils/payment\"\nimport { convertTokenInputToCurrency } from \"@provex/utils/conversionRates\"\n\ndeclare global {\n interface ZKTLS {\n requestConnection(): Promise<boolean>\n checkConnectionStatus(): Promise<Status>\n getVersion(): Promise<string>\n authenticate(inputs: AuthenticationInputs): Promise<void>\n generateProof(inputs: GenerateProofInputs): Promise<GenerateProofResponse>\n fetchProofById(proofId: string): Promise<ProofResponse>\n fetchProofs(): Promise<FetchProofsResponse>\n openSidebar(route: string): Promise<void>\n onMetadataMessage(fn: (data: MetadataMessageResponse) => void): () => void\n }\n interface Window {\n /** @deprecated Use window.peer instead */\n zktls: ZKTLS | undefined\n /** PeerAuth extension API (replaces window.zktls) */\n peer: ZKTLS | undefined\n }\n}\n\n/** the status of the PeerAuth extension */\nexport type Status = 'connected' | 'disconnected' | 'pending'\n\n/** the individual metadata message sent by the PeerAuth extension */\nexport interface MetadataMessage {\n amount: number\n /** Currency code (e.g., 'USD', 'EUR') */\n currency?: string\n /**\n * Date of the transaction.\n * Can be a string in YYYYMMDD format, a number (YYYYMMDD or timestamp), or Date object.\n * The actual type depends on the extension implementation.\n */\n date: string | number | Date\n hidden: boolean\n originalIndex: number\n paymentId: number\n recipient: string\n}\n\n/** the response from the PeerAuth extension when a metadata message is received */\nexport interface MetadataMessageResponse {\n expiresAt: number\n platform: ProviderKey\n requestId: string\n metadata: MetadataMessage[]\n}\n\n/** the response from the PeerAuth extension when fetching proofs */\nexport interface FetchProofsResponse {\n notaryRequests: NotaryRequest[]\n}\n\n/** the inputs for the generateProof function */\nexport type GenerateProofInputsAbstracted = {\n platform: PlatformKey\n provider: ProviderKey\n intentHash: Hex\n originalIndex: number\n}\n\n/** the inputs for the generateProof function */\nexport type GenerateProofInputs = {\n platform: ProviderKey\n originalIndex: number\n proofIndex?: number\n intentHash: string\n}\n\n/**\n * inputs for the generate proof function that requires the intent hash\n * as hex to ensure it can be converted to a bigint string accurately\n */\nexport type HexIntentGenerateProofInputs = Exclude<GenerateProofInputs, 'intentHash'> & { intentHash: Hex }\n\n/** the response from the PeerAuth extension when generating a proof */\nexport type GenerateProofResponse = {\n proofId: string\n platform: ProviderKey\n}\n\n/** the inputs for the authenticate function */\nexport type AuthenticationInputs = {\n actionType: ActionType\n platform: PlatformKey\n}\n\n/** the response from the PeerAuth extension when fetching a proof */\nexport interface Proof {\n claimInfo: ClaimInfo\n signedClaim: SignedClaim\n isAppclipProof: boolean\n status: string\n}\n\n/** the response from the PeerAuth extension when fetching a proof */\nexport interface NotarizedProof {\n claim: {\n context: string\n epoch: number\n identifier: Hex\n owner: Hex\n parameters: string\n provider: string\n timestampS: number\n },\n signatures: {\n attestorAddress: Hex\n claimSignature: Record<number, number>\n resultSignature: Record<number, number>\n },\n}\n\n/** the claim info for a proof */\nexport interface ClaimInfo {\n provider: string\n parameters: string\n context: string\n}\n\n/** the complete claim data for a proof */\nexport interface CompleteClaimData {\n identifier: Hex\n owner: Hex\n timestampS: number\n epoch: number\n}\n\n/** the signed claim for a proof */\nexport interface SignedClaim {\n claim: CompleteClaimData\n signatures: Hex[]\n}\n\n/** the reclaim proof for a proof */\nexport type ReclaimProof = {\n claimInfo: ClaimInfo\n signedClaim: SignedClaim\n isAppclipProof: boolean\n}\n\n/** the notary request for a proof */\nexport interface NotaryRequest {\n metadata: (string | number)[]\n actionType: ActionType\n id: string\n status: string\n timestamp: number\n proof: NotarizedProof\n}\n\n/** the response from the PeerAuth extension when fetching a proof */\nexport interface ProofResponse {\n notaryRequest: NotaryRequest\n}\n\nexport const extensionUrl = 'https://chromewebstore.google.com/detail/ijpgccednehjpeclfcllnjjcmiohdjih'\n\n/** convert a byte array to a hex string */\nexport const byteArrayToHexString = (byteArray: number[]): Hex => {\n return `0x${byteArray\n .map(byte => byte.toString(16).padStart(2, '0'))\n .join('')}`\n}\n\n/** parse a proof object from the PeerAuth extension */\nexport const parseExtensionProof = (proofObject: NotarizedProof) => {\n return {\n claimInfo: {\n provider: proofObject.claim.provider,\n parameters: proofObject.claim.parameters,\n context: proofObject.claim.context\n },\n signedClaim: {\n claim: {\n identifier: proofObject.claim.identifier as Hex,\n owner: proofObject.claim.owner as Hex,\n timestampS: proofObject.claim.timestampS,\n epoch: proofObject.claim.epoch\n },\n signatures: [byteArrayToHexString(Object.values(proofObject.signatures.claimSignature))]\n },\n isAppclipProof: false\n } as ReclaimProof\n}\n\n/** the abi encoding for a proof */\nexport const PROOF_ENCODING = parseAbiParameter(\"((string provider, string parameters, string context) claimInfo, ((bytes32 identifier, address owner, uint32 timestampS, uint32 epoch) claim, bytes[] signatures) signedClaim, bool isAppclipProof)\")\n\n/** encode a single proof as a bytes array */\nexport function encodeProofAsBytes(proof: ReclaimProof): Hex {\n return encodeAbiParameters([PROOF_ENCODING], [proof])\n}\n\n/** encode two proofs to be passed to the underlying sub-provider */\nexport const encodeTwoProofs = (proof1: ReclaimProof, proof2: ReclaimProof) => {\n return encodeAbiParameters([PROOF_ENCODING, PROOF_ENCODING], [proof1, proof2])\n}\n\n/** a high level function to encode a proof for a given provider and sub-provider */\nexport const encodeProof = ({ extensionProofs, subProvider, provider }: {\n extensionProofs: NotarizedProof[],\n subProvider: PlatformKey | null,\n provider: ProviderKey\n}) => {\n const reclaimProofs = extensionProofs.map((p) => parseExtensionProof(p))\n if (provider === 'zelle') {\n // move this to check the blockchain for the payment method\n const paymentMethod = subProviderConfigs![provider]![subProvider as SubProviderKey]!.paymentMethod\n const twoEncoded = reclaimProofs.length === 2\n ? encodeTwoProofs(reclaimProofs[0]!, reclaimProofs[1]!)\n : encodeProofAsBytes(reclaimProofs[0]!)\n // select between various possible sub-providers\n const withPaymentMethod = encodeProofWithPaymentMethod({\n paymentMethod,\n proof: twoEncoded,\n })\n return withPaymentMethod\n }\n const [reclaimProof] = reclaimProofs\n return encodeProofAsBytes(reclaimProof!)\n}\n\n/**\n * wrap a proof with a payment method and proof\n * this allows us to use a single verifier as an entry point for multiple underlying sub-providers\n */\nexport const encodeProofWithPaymentMethod = ({\n proof,\n paymentMethod\n}: {\n proof: Hex,\n paymentMethod: number\n}): Hex => {\n return encodePacked(['uint8', 'bytes'], [paymentMethod, proof])\n}\n\n/** the progress of a proof series */\nexport enum SeriesProgress {\n Generating,\n Polling,\n Complete,\n}\n\nexport type ProgressInfo = {\n progress: SeriesProgress\n total: number\n step: number | null\n id: string | null\n}\n\n/** the mutations for the generate proof series function */\nexport type GenerateProofSeriesMutations = {\n progress?: ({ progress, step, id }: ProgressInfo) => void\n setOwnerName?: (name: string) => void\n}\n\n/** React hook to interact with the PeerAuth extension */\nexport const useZKTLS = () => {\n const [isInitialized, setIsInitialized] = useState(false)\n useEffect(() => {\n const setup = () => {\n setIsInitialized(true)\n }\n const eventName = 'peer#initialized'\n if (typeof window.peer !== 'undefined') {\n // api is available\n setup()\n } else {\n window.addEventListener(eventName, setup)\n return () => {\n window.removeEventListener(eventName, setup)\n }\n }\n }, [])\n return useMemo(() => {\n /** fetch a proof by its id */\n const fetchProofById = async (proofId: string): Promise<NotaryRequest | null> => {\n const proof = await window.peer!.fetchProofById(proofId)\n if (proof && proof.notaryRequest) return proof.notaryRequest\n const proofs = await window.peer!.fetchProofs()\n const proofFromList = proofs.notaryRequests.find((p) => p.id === proofId)\n if (proofFromList) return proofFromList\n return null\n }\n /** wait for a proof to be generated */\n const waitForProof = async (proofId: string, onCurrent?: (notaryRequest: NotaryRequest | null) => void) => {\n let notaryRequest: NotaryRequest | null = null\n do {\n notaryRequest = await fetchProofById(proofId)\n onCurrent?.(notaryRequest)\n await sleep(1_000)\n } while (!notaryRequest || !notaryRequest.status || notaryRequest.status === 'pending')\n if (notaryRequest.status === 'failed' || notaryRequest.status === 'expired' || notaryRequest.status === 'cancelled' || notaryRequest.status === 'error') {\n console.error('[waitForProof] proof terminal state:', JSON.stringify(notaryRequest, null, 2))\n const req = notaryRequest as unknown as Record<string, unknown>\n const detail = req.errorMessage ?? req.error ?? req.message ?? notaryRequest.status\n throw new Error(`Proof generation failed: ${detail}`)\n }\n return notaryRequest\n }\n /** generate a proof */\n const generateProof = async (inputs: HexIntentGenerateProofInputs): Promise<GenerateProofResponse> => {\n return await window.peer!.generateProof({\n proofIndex: 0,\n ...inputs,\n intentHash: BigInt(inputs.intentHash).toString(),\n })\n }\n return {\n /** check if the PeerAuth extension is initialized */\n isInitialized,\n /** request a connection to the PeerAuth extension */\n requestConnection: async () => {\n if (!window.peer) return false\n return window.peer!.requestConnection()\n },\n /**\n * check the connection status of the PeerAuth extension\n * @returns the connection status\n */\n checkConnectionStatus: async () => {\n return await window.peer!.checkConnectionStatus()\n },\n /** get the version of the PeerAuth extension */\n getVersion: async () => {\n return await window.peer?.getVersion()\n },\n /** authenticate with the PeerAuth extension */\n authenticate: async (inputs: AuthenticationInputs) => {\n // Create promise first to avoid race condition where message arrives before resolver is assigned\n let resolve: (value: MetadataMessageResponse) => void\n const promise = new Promise<MetadataMessageResponse>((resolver) => {\n resolve = resolver\n })\n\n // Now set up the listener - resolve is guaranteed to be the real resolver\n const unsub = window.peer!.onMetadataMessage((data) => {\n if (`transfer_${data.platform}` === inputs.actionType) {\n resolve(data)\n }\n })\n\n await window.peer!.authenticate(inputs)\n\n return await promise.then((data) => {\n unsub()\n return data\n })\n },\n /** generate a proof */\n generateProof,\n /** wait for a proof to be generated */\n waitForProof,\n /** generate a proof series */\n generateProofSeries: async (\n inputs: GenerateProofInputsAbstracted,\n { progress: progressCallback }: GenerateProofSeriesMutations = {},\n ): Promise<NotaryRequest[]> => {\n const { platform, provider, intentHash, originalIndex } = inputs\n const args = {\n platform: provider,\n originalIndex,\n intentHash,\n } as const\n // Chase requires 2 proofs (account verification + transaction)\n // Platform is the bank name (e.g., 'chase') from extensionPlatform config\n const isChase = platform === extensionPlatforms.CHASE\n const isZelle = provider === providers.ZELLE\n const expectedTotal = isZelle && isChase ? 2 : 1\n progressCallback?.({ progress: SeriesProgress.Generating, step: 0, id: null, total: expectedTotal })\n const genProofA = await generateProof({ ...args, proofIndex: 0 })\n progressCallback?.({ progress: SeriesProgress.Polling, step: 0, id: genProofA.proofId, total: expectedTotal })\n const proofA = await waitForProof(genProofA.proofId)\n if (!isChase || !isZelle) {\n progressCallback?.({ progress: SeriesProgress.Complete, step: null, id: null, total: expectedTotal })\n return [proofA]\n }\n progressCallback?.({ progress: SeriesProgress.Generating, step: 1, id: null, total: expectedTotal })\n const genProofB = await generateProof({ ...args, proofIndex: 1 })\n progressCallback?.({ progress: SeriesProgress.Polling, step: 1, id: genProofB.proofId, total: expectedTotal })\n const proofB = await waitForProof(genProofB.proofId)\n progressCallback?.({ progress: SeriesProgress.Complete, step: null, id: null, total: expectedTotal })\n return [proofA, proofB]\n },\n /** subscribe to metadata messages */\n onMetadataMessage: (fn: (data: any) => void) => {\n return window.peer!.onMetadataMessage(fn)\n },\n /** fetch a proof by its id */\n fetchProofById,\n /** fetch generated proofs */\n fetchGeneratedProofs: async (genProofResponses: GenerateProofResponse[]) => {\n return await Promise.all(genProofResponses.map((r) => fetchProofById(r.proofId)))\n },\n /** fetch all proofs */\n fetchProofs: async () => {\n return await window.peer!.fetchProofs()\n },\n /** open the PeerAuth sidebar */\n openSidebar: async (route: string) => {\n return await window.peer!.openSidebar(route)\n },\n }\n }, [isInitialized])\n}\n\n/**\n * Find the metadata message that matches the intent by amount.\n * Returns the first (most recent) transaction in the metadata array that matches the expected amount.\n *\n * Simplified matching: just find transactions with the correct amount.\n * The user can manually select if multiple matches exist.\n */\nexport const findMetadataMessage = ({ metadata, intent, token, centIsInt = false }: {\n metadata: MetadataMessage[],\n intent: IntentStruct,\n token: TokenInfo,\n /** @deprecated No longer used - kept for API compatibility */\n recipient?: string,\n centIsInt?: boolean,\n}): MetadataMessage | null => {\n const currencyAmount = convertTokenInputToCurrency({\n token,\n amountOutInt: intent.amount,\n rate: intent.conversionRate,\n })\n /**\n * Normalize an amount from the extension into a bigint in token base units.\n *\n * The extension sends amounts in different formats per provider:\n * - Venmo: `\"- $1.00\"` (formatted dollar string)\n * - Others: `100` (integer cents) or `1.00` (decimal dollars)\n *\n * We detect the format by checking for currency symbols or decimal points\n * in the raw value. If present, the value is already in dollars and we\n * skip the centIsInt division.\n */\n const normalizeAmount = (amount: number | string): bigint => {\n const raw = String(amount)\n const isFormattedDollars = /[^0-9\\-]/.test(raw) && raw.includes('.')\n const cleaned = raw.replace(/[^0-9.]/g, '')\n let value = parseUnits(cleaned, token.decimals)\n if (centIsInt && !isFormattedDollars) {\n value = value / 100n\n }\n return value\n }\n\n // Skip auto-match when manual selection is forced (dev/testing)\n if (typeof window !== 'undefined' && (window as unknown as Record<string, unknown>).__FORCE_MANUAL_TX_SELECT__) {\n return null\n }\n\n // Find the first transaction that matches the amount (first in array = most recent)\n // Note: We ignore the hidden flag - matching is purely by amount\n const match = metadata.find((m) => {\n const converted = normalizeAmount(m.amount)\n return converted === currencyAmount || converted === (currencyAmount * -1n)\n })\n\n if (!match) {\n // Detect 100x scale mismatch — the most common failure mode when centIsInt\n // is wrong for a provider. Fires loudly so it's obvious in dev/staging logs.\n const hundredxMatch = metadata.find((m) => {\n const converted = normalizeAmount(m.amount)\n const abs = converted < 0n ? -converted : converted\n return abs === currencyAmount * 100n || abs * 100n === currencyAmount\n })\n if (hundredxMatch) {\n console.warn(\n `[findMetadataMessage] tx[0] amount=${String(hundredxMatch.amount)} is 100x off from expected ${currencyAmount.toString()} — centIsInt is likely wrong for this provider (currently ${centIsInt})`\n )\n }\n return null\n }\n\n return match\n}\n","/**\n * @fileoverview React context for PeerAuth extension state.\n *\n * Provides global access to the useZKTLS hook state throughout the\n * component tree, avoiding prop drilling for extension status.\n *\n * @see {@link useZKTLS} for the underlying hook\n */\n\nimport { createContext, useContext, type ReactNode } from 'react'\nimport { useZKTLS } from './useZKTLS'\n\n/**\n * Context type derived from useZKTLS hook return value.\n */\ntype ZKTLSContextType = ReturnType<typeof useZKTLS>\n\nexport const ZKTLSContext = createContext<ZKTLSContextType | undefined>(undefined)\n\ninterface ZKTLSProviderProps {\n children: ReactNode\n}\n\n/**\n * Hook to consume the ZKTLS context.\n * Must be used within a ZKTLSProvider.\n *\n * @throws Error if used outside of ZKTLSProvider\n */\nexport function useZKTLSContext() {\n const context = useContext(ZKTLSContext)\n if (context === undefined) {\n throw new Error('useZKTLSContext must be used within a ZKTLSProvider')\n }\n return context\n}\n\nexport function ZKTLSProvider({ children }: ZKTLSProviderProps) {\n const zktlsHook = useZKTLS()\n\n return (\n <ZKTLSContext.Provider value={zktlsHook}>\n {children}\n </ZKTLSContext.Provider>\n )\n}\n"]}
|
package/dist/useZKTLSContext.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@provex/extension-react",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0-rc.20260522201545.020a3eb",
|
|
4
4
|
"description": "React hooks and context for the PeerAuth browser extension (zkTLS proof generation)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -36,8 +36,10 @@
|
|
|
36
36
|
"publishConfig": {
|
|
37
37
|
"access": "public"
|
|
38
38
|
},
|
|
39
|
+
"license": "MIT",
|
|
39
40
|
"files": [
|
|
40
41
|
"dist",
|
|
42
|
+
"skills",
|
|
41
43
|
"README.md"
|
|
42
44
|
],
|
|
43
45
|
"scripts": {
|
|
@@ -46,7 +48,7 @@
|
|
|
46
48
|
"test": "vitest run"
|
|
47
49
|
},
|
|
48
50
|
"dependencies": {
|
|
49
|
-
"@provex/utils": "1.
|
|
51
|
+
"@provex/utils": "1.7.0-rc.20260522201545.020a3eb"
|
|
50
52
|
},
|
|
51
53
|
"peerDependencies": {
|
|
52
54
|
"react": "^18.0.0",
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: extension-react-integration
|
|
3
|
+
description: Use when integrating `@provex/extension-react` — when wiring zkTLS proof generation via the PeerAuth browser extension, when authenticating a user against a payment provider (Venmo, Zelle, CashApp, Revolut, Wise, MercadoPago), when generating single or series proofs for blockchain submission, when handling extension-not-installed states, or when encoding proofs as bytes for on-chain calldata. Covers the ZKTLSProvider mount requirement, the single-vs-series proof distinction (Zelle requires series), the metadata-message subscription pattern, and the proof encoding pipeline.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# `@provex/extension-react` Integration
|
|
7
|
+
|
|
8
|
+
React hooks + context for the PeerAuth browser extension, which generates zkTLS proofs of payment for the Provex protocol. The extension does all cryptographic work locally; this package is just the wire protocol between the web app and the extension.
|
|
9
|
+
|
|
10
|
+
## Hard requirement: PeerAuth extension installed
|
|
11
|
+
|
|
12
|
+
Without the extension, every call from this package returns "not initialized." Detect this state and surface install instructions before exposing buy flow UI.
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
import { useZKTLSContext } from '@provex/extension-react'
|
|
16
|
+
|
|
17
|
+
function PaymentStep() {
|
|
18
|
+
const zktls = useZKTLSContext()
|
|
19
|
+
|
|
20
|
+
if (!zktls.isInitialized) {
|
|
21
|
+
return <ExtensionInstallPrompt />
|
|
22
|
+
}
|
|
23
|
+
// ...
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The extension communicates via window message passing. There's no fallback "do it on the server" path — the extension is the trust boundary that lets users prove a Venmo payment without handing your app their Venmo password.
|
|
28
|
+
|
|
29
|
+
## Mount order
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
import { ZKTLSProvider } from '@provex/extension-react'
|
|
33
|
+
import { ProvexProvider } from '@provex/react'
|
|
34
|
+
|
|
35
|
+
function App() {
|
|
36
|
+
return (
|
|
37
|
+
<ZKTLSProvider fallbackComponent={<ProofToolkitLoading />}>
|
|
38
|
+
<ProvexProvider config={...} indexer={...}>
|
|
39
|
+
<YourApp />
|
|
40
|
+
</ProvexProvider>
|
|
41
|
+
</ZKTLSProvider>
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`ZKTLSProvider` outside `ProvexProvider` is the correct nesting — the SDK pulls zkTLS via `useZKTLSContext()` from within its own components, so the provider needs to be above. The `fallbackComponent` renders while the extension reports its initial status (~150ms).
|
|
47
|
+
|
|
48
|
+
## Single proof vs. proof series
|
|
49
|
+
|
|
50
|
+
Some providers (Venmo, CashApp, Revolut, Wise, MercadoPago) emit **one** proof per payment. Zelle is special — its bank-by-bank routing means it emits **two** proofs (the inbound and outbound legs). Always use `generateProofSeries`, even for single-proof providers:
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
const proofs = await zktls.generateProofSeries({
|
|
54
|
+
platform: 'venmo', // for Zelle: 'chase' / 'bank_of_america' / 'citi'
|
|
55
|
+
provider: 'venmo', // for Zelle subprovs: 'zelle'
|
|
56
|
+
intentHash: '0x1234...', // intent that locked the funds
|
|
57
|
+
originalIndex: 0,
|
|
58
|
+
})
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Single-proof providers return a one-element array; Zelle returns two. Letting the array shape vary is intentional — your on-chain submission picks the right `encodeProof` variant for the provider.
|
|
62
|
+
|
|
63
|
+
## Encoding proofs for blockchain submission
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
import { encodeProof, encodeTwoProofs, encodeProofAsBytes } from '@provex/extension-react'
|
|
67
|
+
|
|
68
|
+
// High-level: picks the right encoding for the provider
|
|
69
|
+
const encoded = encodeProof({
|
|
70
|
+
extensionProofs: proofs,
|
|
71
|
+
provider: 'zelle',
|
|
72
|
+
subProvider: 'chase',
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
// Low-level (rarely needed)
|
|
76
|
+
const single = encodeProofAsBytes(proofs[0].reclaimProof)
|
|
77
|
+
const pair = encodeTwoProofs(proofs[0].reclaimProof, proofs[1].reclaimProof)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Hand the result directly to `UnifiedPaymentVerifier.fulfillIntent` calldata via `@provex/abis/v3`.
|
|
81
|
+
|
|
82
|
+
## Authentication flow
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
const handlePay = async () => {
|
|
86
|
+
await zktls.requestConnection()
|
|
87
|
+
|
|
88
|
+
const metadata = await zktls.authenticate({
|
|
89
|
+
actionType: 'transfer_venmo', // platform-specific
|
|
90
|
+
platform: 'venmo',
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
// User is now logged in to Venmo via the extension's tab.
|
|
94
|
+
// Subscribe to metadata messages emitted as they pay:
|
|
95
|
+
const unsubscribe = zktls.onMetadataMessage((msg) => {
|
|
96
|
+
const matched = findMetadataMessage({ metadata: msg.metadata, intent: userIntent, token })
|
|
97
|
+
if (matched) { /* extract amount, recipient, timestamp */ }
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
// After the user confirms payment:
|
|
101
|
+
const proofs = await zktls.generateProofSeries({ ... })
|
|
102
|
+
unsubscribe()
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
`actionType` values come from the upstream Reclaim provider templates — they're hashed into the on-chain `providerHash`. Get them from `@provex/utils/payment` or the platform-specific docs.
|
|
107
|
+
|
|
108
|
+
## Progress feedback
|
|
109
|
+
|
|
110
|
+
For long-running proof generation (Zelle takes 15-30s end-to-end):
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
await zktls.generateProofSeries(
|
|
114
|
+
{ platform: 'chase', provider: 'zelle', intentHash, originalIndex: 0 },
|
|
115
|
+
{
|
|
116
|
+
progress: ({ progress, step, total, id }) => {
|
|
117
|
+
// step 0..N-1, total = 2 for Zelle, 1 for everything else
|
|
118
|
+
// progress is a 0..1 float
|
|
119
|
+
updateUI({ step, total, percent: progress * 100 })
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Error handling
|
|
126
|
+
|
|
127
|
+
Wrap every zkTLS call in try/catch. Common failure modes:
|
|
128
|
+
|
|
129
|
+
| Error message includes | Cause | Recovery |
|
|
130
|
+
|---|---|---|
|
|
131
|
+
| `not initialized` | Extension not installed or not yet ready | Show install prompt; retry after extension status changes |
|
|
132
|
+
| `cancelled` | User closed the extension's auth tab or rejected | Reset to browse phase; don't toast as an error |
|
|
133
|
+
| `failed` | Reclaim attestation backend rejected | Retry once with a delay; otherwise surface "try again" |
|
|
134
|
+
| `timeout` | Extension didn't respond within its window | Reload the extension's worker or prompt reinstall |
|
|
135
|
+
|
|
136
|
+
User cancellation is a UX state, not an error — distinguish it from real failures so the buyer can retry without a doom-shaped toast.
|
|
137
|
+
|
|
138
|
+
## Type imports
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
import type {
|
|
142
|
+
Status,
|
|
143
|
+
MetadataMessage,
|
|
144
|
+
MetadataMessageResponse,
|
|
145
|
+
GenerateProofInputs,
|
|
146
|
+
GenerateProofResponse,
|
|
147
|
+
AuthenticationInputs,
|
|
148
|
+
NotaryRequest,
|
|
149
|
+
ReclaimProof,
|
|
150
|
+
} from '@provex/extension-react'
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## When NOT to import from this package
|
|
154
|
+
|
|
155
|
+
- **You're building outside React** → consume the extension's message protocol directly (see [Provex Identity docs](https://provex.com)) or run the proofs server-side via the Reclaim attestor.
|
|
156
|
+
- **You don't need zkTLS proofs** → if your integration is read-only (just observing deposits), skip this package entirely. Use `@provex/indexer-client`.
|
|
157
|
+
- **You want to generate proofs without the browser extension** → not currently supported. The extension is the trust boundary. Self-hosted attestor work is on the roadmap but not in this package.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useZKTLS.ts"],"names":["SeriesProgress"],"mappings":"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","file":"chunk-DVOEKDW7.js","sourcesContent":["/**\n * @fileoverview React hook and utilities for PeerAuth browser extension integration.\n *\n * The PeerAuth extension (formerly ZK-TLS) provides secure proof generation\n * for off-chain payment verification. This module provides:\n *\n * 1. Type definitions for extension API (window.peer)\n * 2. useZKTLS hook for React components\n * 3. Utility functions for transaction matching and proof encoding\n *\n * @remarks\n * The extension exposes `window.peer` (or deprecated `window.zktls`) for:\n * - Requesting connection (OAuth-like flow)\n * - Authenticating with payment providers\n * - Generating notarized proofs\n * - Fetching transaction metadata\n *\n * @see {@link ZKTLSContext} for the React context provider\n */\n\nimport { useEffect, useMemo, useState } from \"react\"\nimport { encodeAbiParameters, encodePacked, parseAbiParameter, parseUnits, type Hex } from \"viem\"\nimport { sleep } from \"@provex/utils/time\"\nimport type { IntentStruct } from \"@provex/utils/intent\"\nimport type { TokenInfo } from \"@provex/utils/tokens\"\nimport { extensionPlatforms, providers, subProviderConfigs, type ActionType, type PlatformKey, type ProviderKey, type SubProviderKey } from \"@provex/utils/payment\"\nimport { convertTokenInputToCurrency } from \"@provex/utils/conversionRates\"\n\ndeclare global {\n interface ZKTLS {\n requestConnection(): Promise<boolean>\n checkConnectionStatus(): Promise<Status>\n getVersion(): Promise<string>\n authenticate(inputs: AuthenticationInputs): Promise<void>\n generateProof(inputs: GenerateProofInputs): Promise<GenerateProofResponse>\n fetchProofById(proofId: string): Promise<ProofResponse>\n fetchProofs(): Promise<FetchProofsResponse>\n openSidebar(route: string): Promise<void>\n onMetadataMessage(fn: (data: MetadataMessageResponse) => void): () => void\n }\n interface Window {\n /** @deprecated Use window.peer instead */\n zktls: ZKTLS | undefined\n /** PeerAuth extension API (replaces window.zktls) */\n peer: ZKTLS | undefined\n }\n}\n\n/** the status of the PeerAuth extension */\nexport type Status = 'connected' | 'disconnected' | 'pending'\n\n/** the individual metadata message sent by the PeerAuth extension */\nexport interface MetadataMessage {\n amount: number\n /** Currency code (e.g., 'USD', 'EUR') */\n currency?: string\n /**\n * Date of the transaction.\n * Can be a string in YYYYMMDD format, a number (YYYYMMDD or timestamp), or Date object.\n * The actual type depends on the extension implementation.\n */\n date: string | number | Date\n hidden: boolean\n originalIndex: number\n paymentId: number\n recipient: string\n}\n\n/** the response from the PeerAuth extension when a metadata message is received */\nexport interface MetadataMessageResponse {\n expiresAt: number\n platform: ProviderKey\n requestId: string\n metadata: MetadataMessage[]\n}\n\n/** the response from the PeerAuth extension when fetching proofs */\nexport interface FetchProofsResponse {\n notaryRequests: NotaryRequest[]\n}\n\n/** the inputs for the generateProof function */\nexport type GenerateProofInputsAbstracted = {\n platform: PlatformKey\n provider: ProviderKey\n intentHash: Hex\n originalIndex: number\n}\n\n/** the inputs for the generateProof function */\nexport type GenerateProofInputs = {\n platform: ProviderKey\n originalIndex: number\n proofIndex?: number\n intentHash: string\n}\n\n/**\n * inputs for the generate proof function that requires the intent hash\n * as hex to ensure it can be converted to a bigint string accurately\n */\nexport type HexIntentGenerateProofInputs = Exclude<GenerateProofInputs, 'intentHash'> & { intentHash: Hex }\n\n/** the response from the PeerAuth extension when generating a proof */\nexport type GenerateProofResponse = {\n proofId: string\n platform: ProviderKey\n}\n\n/** the inputs for the authenticate function */\nexport type AuthenticationInputs = {\n actionType: ActionType\n platform: PlatformKey\n}\n\n/** the response from the PeerAuth extension when fetching a proof */\nexport interface Proof {\n claimInfo: ClaimInfo\n signedClaim: SignedClaim\n isAppclipProof: boolean\n status: string\n}\n\n/** the response from the PeerAuth extension when fetching a proof */\nexport interface NotarizedProof {\n claim: {\n context: string\n epoch: number\n identifier: Hex\n owner: Hex\n parameters: string\n provider: string\n timestampS: number\n },\n signatures: {\n attestorAddress: Hex\n claimSignature: Record<number, number>\n resultSignature: Record<number, number>\n },\n}\n\n/** the claim info for a proof */\nexport interface ClaimInfo {\n provider: string\n parameters: string\n context: string\n}\n\n/** the complete claim data for a proof */\nexport interface CompleteClaimData {\n identifier: Hex\n owner: Hex\n timestampS: number\n epoch: number\n}\n\n/** the signed claim for a proof */\nexport interface SignedClaim {\n claim: CompleteClaimData\n signatures: Hex[]\n}\n\n/** the reclaim proof for a proof */\nexport type ReclaimProof = {\n claimInfo: ClaimInfo\n signedClaim: SignedClaim\n isAppclipProof: boolean\n}\n\n/** the notary request for a proof */\nexport interface NotaryRequest {\n metadata: (string | number)[]\n actionType: ActionType\n id: string\n status: string\n timestamp: number\n proof: NotarizedProof\n}\n\n/** the response from the PeerAuth extension when fetching a proof */\nexport interface ProofResponse {\n notaryRequest: NotaryRequest\n}\n\nexport const extensionUrl = 'https://chromewebstore.google.com/detail/ijpgccednehjpeclfcllnjjcmiohdjih'\n\n/** convert a byte array to a hex string */\nexport const byteArrayToHexString = (byteArray: number[]): Hex => {\n return `0x${byteArray\n .map(byte => byte.toString(16).padStart(2, '0'))\n .join('')}`\n}\n\n/** parse a proof object from the PeerAuth extension */\nexport const parseExtensionProof = (proofObject: NotarizedProof) => {\n return {\n claimInfo: {\n provider: proofObject.claim.provider,\n parameters: proofObject.claim.parameters,\n context: proofObject.claim.context\n },\n signedClaim: {\n claim: {\n identifier: proofObject.claim.identifier as Hex,\n owner: proofObject.claim.owner as Hex,\n timestampS: proofObject.claim.timestampS,\n epoch: proofObject.claim.epoch\n },\n signatures: [byteArrayToHexString(Object.values(proofObject.signatures.claimSignature))]\n },\n isAppclipProof: false\n } as ReclaimProof\n}\n\n/** the abi encoding for a proof */\nexport const PROOF_ENCODING = parseAbiParameter(\"((string provider, string parameters, string context) claimInfo, ((bytes32 identifier, address owner, uint32 timestampS, uint32 epoch) claim, bytes[] signatures) signedClaim, bool isAppclipProof)\")\n\n/** encode a single proof as a bytes array */\nexport function encodeProofAsBytes(proof: ReclaimProof): Hex {\n return encodeAbiParameters([PROOF_ENCODING], [proof])\n}\n\n/** encode two proofs to be passed to the underlying sub-provider */\nexport const encodeTwoProofs = (proof1: ReclaimProof, proof2: ReclaimProof) => {\n return encodeAbiParameters([PROOF_ENCODING, PROOF_ENCODING], [proof1, proof2])\n}\n\n/** a high level function to encode a proof for a given provider and sub-provider */\nexport const encodeProof = ({ extensionProofs, subProvider, provider }: {\n extensionProofs: NotarizedProof[],\n subProvider: PlatformKey | null,\n provider: ProviderKey\n}) => {\n const reclaimProofs = extensionProofs.map((p) => parseExtensionProof(p))\n if (provider === 'zelle') {\n // move this to check the blockchain for the payment method\n const paymentMethod = subProviderConfigs![provider]![subProvider as SubProviderKey]!.paymentMethod\n const twoEncoded = reclaimProofs.length === 2\n ? encodeTwoProofs(reclaimProofs[0]!, reclaimProofs[1]!)\n : encodeProofAsBytes(reclaimProofs[0]!)\n // select between various possible sub-providers\n const withPaymentMethod = encodeProofWithPaymentMethod({\n paymentMethod,\n proof: twoEncoded,\n })\n return withPaymentMethod\n }\n const [reclaimProof] = reclaimProofs\n return encodeProofAsBytes(reclaimProof!)\n}\n\n/**\n * wrap a proof with a payment method and proof\n * this allows us to use a single verifier as an entry point for multiple underlying sub-providers\n */\nexport const encodeProofWithPaymentMethod = ({\n proof,\n paymentMethod\n}: {\n proof: Hex,\n paymentMethod: number\n}): Hex => {\n return encodePacked(['uint8', 'bytes'], [paymentMethod, proof])\n}\n\n/** the progress of a proof series */\nexport enum SeriesProgress {\n Generating,\n Polling,\n Complete,\n}\n\nexport type ProgressInfo = {\n progress: SeriesProgress\n total: number\n step: number | null\n id: string | null\n}\n\n/** the mutations for the generate proof series function */\nexport type GenerateProofSeriesMutations = {\n progress?: ({ progress, step, id }: ProgressInfo) => void\n setOwnerName?: (name: string) => void\n}\n\n/** React hook to interact with the PeerAuth extension */\nexport const useZKTLS = () => {\n const [isInitialized, setIsInitialized] = useState(false)\n useEffect(() => {\n const setup = () => {\n setIsInitialized(true)\n }\n const eventName = 'peer#initialized'\n if (typeof window.peer !== 'undefined') {\n // api is available\n setup()\n } else {\n window.addEventListener(eventName, setup)\n return () => {\n window.removeEventListener(eventName, setup)\n }\n }\n }, [])\n return useMemo(() => {\n /** fetch a proof by its id */\n const fetchProofById = async (proofId: string): Promise<NotaryRequest | null> => {\n const proof = await window.peer!.fetchProofById(proofId)\n if (proof && proof.notaryRequest) return proof.notaryRequest\n const proofs = await window.peer!.fetchProofs()\n const proofFromList = proofs.notaryRequests.find((p) => p.id === proofId)\n if (proofFromList) return proofFromList\n return null\n }\n /** wait for a proof to be generated */\n const waitForProof = async (proofId: string, onCurrent?: (notaryRequest: NotaryRequest | null) => void) => {\n let notaryRequest: NotaryRequest | null = null\n do {\n notaryRequest = await fetchProofById(proofId)\n onCurrent?.(notaryRequest)\n await sleep(1_000)\n } while (!notaryRequest || !notaryRequest.status || notaryRequest.status === 'pending')\n if (notaryRequest.status === 'failed' || notaryRequest.status === 'expired' || notaryRequest.status === 'cancelled' || notaryRequest.status === 'error') {\n throw new Error(`Proof generation failed: ${notaryRequest.status}`)\n }\n return notaryRequest\n }\n /** generate a proof */\n const generateProof = async (inputs: HexIntentGenerateProofInputs): Promise<GenerateProofResponse> => {\n return await window.peer!.generateProof({\n proofIndex: 0,\n ...inputs,\n intentHash: BigInt(inputs.intentHash).toString(),\n })\n }\n return {\n /** check if the PeerAuth extension is initialized */\n isInitialized,\n /** request a connection to the PeerAuth extension */\n requestConnection: async () => {\n if (!window.peer) return false\n return window.peer!.requestConnection()\n },\n /**\n * check the connection status of the PeerAuth extension\n * @returns the connection status\n */\n checkConnectionStatus: async () => {\n return await window.peer!.checkConnectionStatus()\n },\n /** get the version of the PeerAuth extension */\n getVersion: async () => {\n return await window.peer?.getVersion()\n },\n /** authenticate with the PeerAuth extension */\n authenticate: async (inputs: AuthenticationInputs) => {\n // Create promise first to avoid race condition where message arrives before resolver is assigned\n let resolve: (value: MetadataMessageResponse) => void\n const promise = new Promise<MetadataMessageResponse>((resolver) => {\n resolve = resolver\n })\n\n // Now set up the listener - resolve is guaranteed to be the real resolver\n const unsub = window.peer!.onMetadataMessage((data) => {\n if (`transfer_${data.platform}` === inputs.actionType) {\n resolve(data)\n }\n })\n\n await window.peer!.authenticate(inputs)\n\n return await promise.then((data) => {\n unsub()\n return data\n })\n },\n /** generate a proof */\n generateProof,\n /** wait for a proof to be generated */\n waitForProof,\n /** generate a proof series */\n generateProofSeries: async (\n inputs: GenerateProofInputsAbstracted,\n { progress: progressCallback }: GenerateProofSeriesMutations = {},\n ): Promise<NotaryRequest[]> => {\n const { platform, provider, intentHash, originalIndex } = inputs\n const args = {\n platform: provider,\n originalIndex,\n intentHash,\n } as const\n // Chase requires 2 proofs (account verification + transaction)\n // Platform is the bank name (e.g., 'chase') from extensionPlatform config\n const isChase = platform === extensionPlatforms.CHASE\n const isZelle = provider === providers.ZELLE\n const expectedTotal = isZelle && isChase ? 2 : 1\n progressCallback?.({ progress: SeriesProgress.Generating, step: 0, id: null, total: expectedTotal })\n const genProofA = await generateProof({ ...args, proofIndex: 0 })\n progressCallback?.({ progress: SeriesProgress.Polling, step: 0, id: genProofA.proofId, total: expectedTotal })\n const proofA = await waitForProof(genProofA.proofId)\n if (!isChase || !isZelle) {\n progressCallback?.({ progress: SeriesProgress.Complete, step: null, id: null, total: expectedTotal })\n return [proofA]\n }\n progressCallback?.({ progress: SeriesProgress.Generating, step: 1, id: null, total: expectedTotal })\n const genProofB = await generateProof({ ...args, proofIndex: 1 })\n progressCallback?.({ progress: SeriesProgress.Polling, step: 1, id: genProofB.proofId, total: expectedTotal })\n const proofB = await waitForProof(genProofB.proofId)\n progressCallback?.({ progress: SeriesProgress.Complete, step: null, id: null, total: expectedTotal })\n return [proofA, proofB]\n },\n /** subscribe to metadata messages */\n onMetadataMessage: (fn: (data: any) => void) => {\n return window.peer!.onMetadataMessage(fn)\n },\n /** fetch a proof by its id */\n fetchProofById,\n /** fetch generated proofs */\n fetchGeneratedProofs: async (genProofResponses: GenerateProofResponse[]) => {\n return await Promise.all(genProofResponses.map((r) => fetchProofById(r.proofId)))\n },\n /** fetch all proofs */\n fetchProofs: async () => {\n return await window.peer!.fetchProofs()\n },\n /** open the PeerAuth sidebar */\n openSidebar: async (route: string) => {\n return await window.peer!.openSidebar(route)\n },\n }\n }, [isInitialized])\n}\n\n/**\n * Find the metadata message that matches the intent by amount.\n * Returns the first (most recent) transaction in the metadata array that matches the expected amount.\n *\n * Simplified matching: just find transactions with the correct amount.\n * The user can manually select if multiple matches exist.\n */\nexport const findMetadataMessage = ({ metadata, intent, token, centIsInt = false }: {\n metadata: MetadataMessage[],\n intent: IntentStruct,\n token: TokenInfo,\n /** @deprecated No longer used - kept for API compatibility */\n recipient?: string,\n centIsInt?: boolean,\n}): MetadataMessage | null => {\n const currencyAmount = convertTokenInputToCurrency({\n token,\n amountOutInt: intent.amount,\n rate: intent.conversionRate,\n })\n /**\n * Normalize an amount from the extension into a bigint in token base units.\n *\n * The extension sends amounts in different formats per provider:\n * - Venmo: `\"- $1.00\"` (formatted dollar string)\n * - Others: `100` (integer cents) or `1.00` (decimal dollars)\n *\n * We detect the format by checking for currency symbols or decimal points\n * in the raw value. If present, the value is already in dollars and we\n * skip the centIsInt division.\n */\n const normalizeAmount = (amount: number | string): bigint => {\n const raw = String(amount)\n const isFormattedDollars = /[^0-9\\-]/.test(raw) && raw.includes('.')\n const cleaned = raw.replace(/[^0-9.]/g, '')\n let value = parseUnits(cleaned, token.decimals)\n if (centIsInt && !isFormattedDollars) {\n value = value / 100n\n }\n return value\n }\n\n // Skip auto-match when manual selection is forced (dev/testing)\n if (typeof window !== 'undefined' && (window as unknown as Record<string, unknown>).__FORCE_MANUAL_TX_SELECT__) {\n return null\n }\n\n // Find the first transaction that matches the amount (first in array = most recent)\n // Note: We ignore the hidden flag - matching is purely by amount\n const match = metadata.find((m) => {\n const converted = normalizeAmount(m.amount)\n return converted === currencyAmount || converted === (currencyAmount * -1n)\n })\n\n if (!match) {\n return null\n }\n\n return match\n}\n"]}
|