@idos-network/kwil-infra 3.0.1 → 5.0.0

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["KwilSigner","KwilSigner","KwilSigner","KwilSigner"],"sources":["../src/wait-for-kwil-tx.ts","../src/create-kwil-client.ts","../src/mm-token/create-mm-token-kwil-signer.ts","../src/create-kgw-authenticated-fetch.ts","../src/near/get-config.ts","../src/near/create-near-wallet-kwil-signer.ts","../src/xrp/signer.ts","../src/create-kwil-signer.ts"],"sourcesContent":["const KWIL_TX_POLL_DEADLINE_MS = 90_000;\nconst INITIAL_POLL_INTERVAL_MS = 300;\nconst POLL_BACKOFF_FACTOR = 1.5;\nconst MAX_POLL_INTERVAL_MS = 2_000;\nconst MAX_POLL_JITTER_MS = 100;\n\nexport type KwilTxInfo = {\n height: number;\n tx_result: {\n code: number;\n log: string;\n };\n};\n\nexport class KwilTxFailedError extends Error {\n readonly name = \"KwilTxFailedError\";\n\n constructor(\n readonly txHash: string,\n readonly code: number,\n readonly log: string,\n readonly height: number,\n ) {\n super(`Kwil transaction ${txHash} failed at height ${height} (code ${code}): ${log}`);\n }\n}\n\nexport class KwilTxPollTimeoutError extends Error {\n readonly name = \"KwilTxPollTimeoutError\";\n\n constructor(\n readonly txHash: string,\n readonly deadlineMs: number,\n options?: { cause?: unknown },\n ) {\n const lastError =\n options?.cause instanceof Error\n ? options.cause.message\n : options?.cause != null\n ? String(options.cause)\n : undefined;\n super(\n lastError\n ? `Timed out after ${deadlineMs}ms waiting for Kwil transaction ${txHash}: last error: ${lastError}`\n : `Timed out after ${deadlineMs}ms waiting for Kwil transaction ${txHash}`,\n options?.cause !== undefined ? { cause: options.cause } : undefined,\n );\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction nextPollIntervalMs(currentIntervalMs: number): number {\n return Math.min(currentIntervalMs * POLL_BACKOFF_FACTOR, MAX_POLL_INTERVAL_MS);\n}\n\nfunction pollIntervalWithJitter(intervalMs: number): number {\n return intervalMs + Math.floor(Math.random() * (MAX_POLL_JITTER_MS + 1));\n}\n\nfunction isTxFinalized(txInfo: KwilTxInfo): boolean {\n return txInfo.height > 0;\n}\n\nexport async function waitForKwilTx(\n txInfo: (txHash: string) => Promise<{ data?: KwilTxInfo }>,\n txHash: string,\n deadlineMs: number = KWIL_TX_POLL_DEADLINE_MS,\n): Promise<void> {\n const deadlineAt = Date.now() + deadlineMs;\n let intervalMs = INITIAL_POLL_INTERVAL_MS;\n let lastPollError: unknown;\n\n while (Date.now() < deadlineAt) {\n let data: KwilTxInfo | undefined;\n\n // Transient poll failures (e.g. \"not found\" before the node indexes the tx) are\n // recorded and retried. Terminal tx failures are decided below, outside this catch.\n try {\n data = (await txInfo(txHash)).data;\n } catch (error) {\n lastPollError = error;\n }\n\n // height > 0 means the tx was included. Then code 0 is success; anything else is final failure.\n if (data && isTxFinalized(data)) {\n if (data.tx_result.code !== 0) {\n throw new KwilTxFailedError(txHash, data.tx_result.code, data.tx_result.log, data.height);\n }\n return;\n }\n\n // Not finalized yet (or last poll errored) — back off and try again until the deadline.\n const waitMs = pollIntervalWithJitter(intervalMs);\n const remainingMs = deadlineAt - Date.now();\n if (remainingMs <= 0) {\n break;\n }\n\n await sleep(Math.min(waitMs, remainingMs));\n intervalMs = nextPollIntervalMs(intervalMs);\n }\n\n throw new KwilTxPollTimeoutError(\n txHash,\n deadlineMs,\n lastPollError !== undefined ? { cause: lastPollError } : undefined,\n );\n}\n","import type { ActionBody, CallBody, PositionalParams } from \"@idos-network/kwil-js/action\";\nimport type { Config } from \"@idos-network/kwil-js/config\";\nimport type { DataInfo } from \"@idos-network/kwil-js/database\";\n\nimport { type KwilSigner, NodeKwil, WebKwil } from \"@idos-network/kwil-js\";\nimport invariant from \"tiny-invariant\";\n\nimport type { ActionSchemaElement } from \"./actions\";\n\nimport { actionSchema } from \"./actions\";\nimport { waitForKwilTx } from \"./wait-for-kwil-tx\";\n\nexport { KwilTxFailedError, KwilTxPollTimeoutError } from \"./wait-for-kwil-tx\";\n\ntype CreateKwilClientParams = {\n chainId?: string;\n nodeUrl: string;\n};\n\ntype KwilActions = typeof actionSchema;\ntype ActionName = keyof KwilActions;\n\ntype AllKwilCallAction = {\n [Name in ActionName]: {\n name: Name;\n // oxlint-disable-next-line typescript/no-explicit-any -- This is fine\n inputs: Record<KwilActions[Name][number][\"name\"], any>;\n };\n};\n\ntype KwilCallActionRequestParams = AllKwilCallAction[ActionName];\n\ntype AllKwilExecuteAction = {\n [Name in ActionName]: AllKwilCallAction[Name] & { description: string };\n};\n\ntype KwilExecuteActionRequestParams = AllKwilExecuteAction[ActionName];\n\n/**\n * A client for interacting with kwil with type-safe abstractions for `call` and `execute`.\n * Has utility methods for creating actions and setting a signer.\n */\nexport class KwilActionClient {\n signer?: KwilSigner;\n readonly client: NodeKwil | WebKwil;\n\n constructor(client: NodeKwil | WebKwil) {\n this.client = client;\n }\n\n #createActionInputs(actionName: string, params: Record<string, unknown> = {}): PositionalParams {\n if (!params || !Object.keys(params).length) return [];\n\n const args = (actionSchema as Record<string, readonly ActionSchemaElement[]>)[actionName];\n\n return args.map(({ name }) => {\n const value = params[name];\n // Handle falsy values appropriately\n if (value === \"\" || value === 0) return value;\n return value ?? null;\n }) as PositionalParams;\n }\n\n #actionTypes(actionName: string): DataInfo[] {\n const args = actionSchema[actionName];\n return args.map((arg) => arg.type);\n }\n\n /**\n * Calls an action on the kwil nodes. This similar to `GET` like request.\n */\n async call<T = unknown>(\n params: KwilCallActionRequestParams,\n signer: KwilSigner | undefined = this.signer,\n ): Promise<T> {\n const action: CallBody = {\n name: params.name,\n namespace: \"main\",\n inputs: this.#createActionInputs(params.name, params.inputs),\n types: this.#actionTypes(params.name),\n };\n\n const response = await this.client.call(action as CallBody, signer);\n return response?.data?.result as T;\n }\n\n /**\n * Executes an action on the kwil nodes. This similar to `POST` like request.\n *\n * When `synchronous` is true (default), the tx is broadcast without blocking the node,\n * then confirmed by polling `txInfo` with exponential backoff.\n */\n async execute(\n params: KwilExecuteActionRequestParams,\n signer: KwilSigner | undefined = this.signer,\n synchronous = true,\n ): Promise<string> {\n invariant(signer, \"Signer is not set, you must set it before executing an action\");\n const action: ActionBody = {\n name: params.name,\n namespace: \"main\",\n description: params.description,\n inputs: [this.#createActionInputs(params.name, params.inputs)],\n types: this.#actionTypes(params.name),\n };\n const response = await this.client.execute(action, signer, false);\n const txHash = response.data?.tx_hash;\n\n if (!txHash) {\n throw new Error(`Kwil execute \"${params.name}\" did not return a transaction hash`);\n }\n\n if (synchronous) {\n await this.waitForTx(txHash);\n }\n\n return txHash;\n }\n\n /**\n * Polls the node until a broadcast transaction is mined, or throws\n * `KwilTxFailedError` / `KwilTxPollTimeoutError`.\n *\n * Called through `this` rather than directly so that it is a seam an\n * instrumentation can wrap — the wait dominates the latency of `execute`.\n */\n async waitForTx(txHash: string): Promise<void> {\n await waitForKwilTx((hash) => this.client.txInfo(hash), txHash);\n }\n\n setSigner(signer: KwilSigner | undefined): void {\n this.signer = signer;\n }\n\n /**\n * Creates action inputs from the given parameters that are used in the action body.\n */\n}\n\nconst DEFAULT_TIMEOUT = 30_000;\n\nconst createKwilClient =\n (Cls: new (opts: Config) => NodeKwil | WebKwil) =>\n async ({ nodeUrl: kwilProvider, chainId }: CreateKwilClientParams): Promise<KwilActionClient> => {\n const _kwil = new Cls({ kwilProvider, chainId: \"\" });\n // oxlint-disable-next-line no-param-reassign -- Default value fallback\n chainId ||= (await _kwil.chainInfo({ disableWarning: true })).data?.chain_id;\n invariant(chainId, \"Can't discover `chainId`. You must pass it explicitly.\");\n\n const client = new KwilActionClient(\n new Cls({ kwilProvider, chainId, timeout: DEFAULT_TIMEOUT }),\n );\n\n return client;\n };\n\n/**\n * Create a kwil client for node.js environment\n */\nexport const createNodeKwilClient: (params: CreateKwilClientParams) => Promise<KwilActionClient> =\n createKwilClient(NodeKwil);\n\n/**\n * Create a kwil client for browser environment\n */\nexport const createWebKwilClient: (params: CreateKwilClientParams) => Promise<KwilActionClient> =\n createKwilClient(WebKwil);\n","import { KwilSigner } from \"@idos-network/kwil-js\";\nimport { createUkycContentUri } from \"@idos-network/utils/blob-gateway\";\nimport {\n base64UrlDecode,\n base64UrlEncode,\n utf8Decode,\n utf8Encode,\n} from \"@idos-network/utils/codecs\";\n\nconst ED25519_PUBLIC_KEY_BYTES = 32;\nconst ED25519_SIGNATURE_BYTES = 64;\n\n/** Decoded UKYC capability envelope. KGW signature data is base64url(JSON of this). */\nexport interface MmTokenEnvelope {\n payload: MmTokenPayload | Record<string, unknown>;\n signature: string;\n}\n\nexport interface MmTokenPayload {\n signing_public_key: string;\n storage_id?: string;\n [key: string]: unknown;\n}\n\n/**\n * One MM/UKYC capability, valid both as a KGW `mm_token` signer and as the\n * `Authorization: AccessToken …` credential for UKYC blob requests.\n */\nexport type MmTokenAuth = KwilSigner & {\n readonly mmTokenPayload: MmTokenPayload | Record<string, unknown>;\n /** Exact encoded envelope KGW and UKYC storage verify. Non-enumerable, so it stays out of logs. */\n readonly accessToken: string;\n /**\n * A capability signs its own envelope, never an arbitrary message. Declared so callers\n * handling a `Wallet` union can keep asking wallets for a message signature.\n */\n readonly signMessage?: undefined;\n};\n\nexport function isMmTokenAuth(value: unknown): value is MmTokenAuth {\n return (\n value !== null &&\n typeof value === \"object\" &&\n \"signatureType\" in value &&\n value.signatureType === \"mm_token\" &&\n \"identifier\" in value &&\n \"signer\" in value &&\n typeof (value as Partial<MmTokenAuth>).accessToken === \"string\"\n );\n}\n\n/** `storage_id` from the capability token used to construct this signer. */\nexport function mmTokenStorageId(signer: KwilSigner): string {\n const storageId = (signer as Partial<MmTokenAuth>).mmTokenPayload?.storage_id;\n if (typeof storageId !== \"string\" || !storageId.trim()) {\n throw new Error(\"mm_token payload is missing storage_id\");\n }\n return storageId.trim();\n}\n\nexport function mmTokenCredentialContentUri(signer: KwilSigner, credentialId: string): string {\n return createUkycContentUri(mmTokenStorageId(signer), credentialId);\n}\n\nfunction isMmTokenEnvelope(value: unknown): value is MmTokenEnvelope {\n return (\n value !== null &&\n typeof value === \"object\" &&\n \"payload\" in value &&\n value.payload !== null &&\n typeof value.payload === \"object\" &&\n !Array.isArray(value.payload) &&\n \"signature\" in value &&\n typeof value.signature === \"string\"\n );\n}\n\nfunction parseJson<T>(bytes: Uint8Array, errorMessage: string): T {\n try {\n return JSON.parse(utf8Decode(bytes)) as T;\n } catch (error) {\n throw new Error(errorMessage, { cause: error });\n }\n}\n\nfunction decodeBase64Url(value: string, errorMessage: string): Uint8Array {\n try {\n return base64UrlDecode(value);\n } catch (error) {\n throw new Error(errorMessage, { cause: error });\n }\n}\n\n/**\n * Build the MM authentication object for one UKYC capability.\n *\n * Pass the MetaMask-issued capability token as a **base64url-encoded** envelope string\n * (what KGW verifies). A decoded `{ payload, signature }` object is also accepted and\n * will be re-encoded.\n *\n * `signMessage` always returns the UTF-8 bytes of that encoded string — KGW ignores the\n * request message and only verifies the envelope.\n */\nexport function createMmTokenAuth(encodedEnvelope: string | MmTokenEnvelope): MmTokenAuth {\n let encodedToken: string;\n let envelope: MmTokenEnvelope;\n\n if (typeof encodedEnvelope === \"string\") {\n const trimmed = encodedEnvelope.trim();\n if (!trimmed) {\n throw new Error(\"Invalid mm_token envelope: empty\");\n }\n encodedToken = trimmed;\n const envelopeBytes = decodeBase64Url(trimmed, \"Invalid mm_token envelope encoding\");\n const parsed = parseJson<unknown>(envelopeBytes, \"Invalid mm_token envelope JSON\");\n if (!isMmTokenEnvelope(parsed)) {\n throw new Error(\"Invalid mm_token envelope: expected payload object and signature string\");\n }\n envelope = parsed;\n } else {\n if (!isMmTokenEnvelope(encodedEnvelope)) {\n throw new Error(\"Invalid mm_token envelope: expected payload object and signature string\");\n }\n envelope = encodedEnvelope;\n encodedToken = base64UrlEncode(utf8Encode(JSON.stringify(envelope)));\n }\n\n // KGW Verify receives UTF-8 of the base64url string, not the decoded JSON bytes.\n const signatureData = utf8Encode(encodedToken);\n\n const tokenSignatureBytes = decodeBase64Url(\n envelope.signature,\n \"Invalid mm_token envelope signature encoding\",\n );\n if (tokenSignatureBytes.length !== ED25519_SIGNATURE_BYTES) {\n throw new Error(\n `Invalid mm_token signature length: expected ${ED25519_SIGNATURE_BYTES}, got ${tokenSignatureBytes.length}`,\n );\n }\n\n const signingPublicKey = envelope.payload.signing_public_key;\n if (typeof signingPublicKey !== \"string\") {\n throw new Error(\"Invalid mm_token payload: missing signing_public_key\");\n }\n\n const signingPublicKeyBytes = decodeBase64Url(\n signingPublicKey,\n \"Invalid mm_token signing_public_key encoding\",\n );\n\n if (signingPublicKeyBytes.length !== ED25519_PUBLIC_KEY_BYTES) {\n throw new Error(\n `Invalid mm_token signing_public_key length: expected ${ED25519_PUBLIC_KEY_BYTES}, got ${signingPublicKeyBytes.length}`,\n );\n }\n\n const auth = Object.assign(\n new KwilSigner(async () => signatureData.slice(), signingPublicKeyBytes, \"mm_token\"),\n { mmTokenPayload: envelope.payload },\n );\n\n return Object.defineProperty(auth, \"accessToken\", {\n value: encodedToken,\n enumerable: false,\n }) as MmTokenAuth;\n}\n","import { type KwilSigner, NodeKwil } from \"@idos-network/kwil-js\";\nimport { BlobGateway, type BlobGatewayParams } from \"@idos-network/utils/blob-gateway\";\n\nimport type { KwilActionClient } from \"./create-kwil-client\";\nimport type { MmTokenAuth } from \"./mm-token/create-mm-token-kwil-signer\";\n\nimport { isMmTokenAuth } from \"./mm-token/create-mm-token-kwil-signer\";\n\nconst KGW_AUTH_ERROR_CODE = -901;\n\n/** Return true when the response means KGW auth is missing/expired.\n * May read the body only for `application/json` responses (those are probed via a clone). */\nexport type KgwAuthFailurePredicate = (response: Response) => Promise<boolean> | boolean;\n\nexport type CreateKgwAuthenticatedFetchParams = {\n kwilClient: KwilActionClient;\n signer: KwilSigner;\n fetchFn?: typeof fetch;\n isAuthFailure?: KgwAuthFailurePredicate;\n};\n\nexport type CreateKgwAuthenticatedBlobGatewayParams = CreateKgwAuthenticatedFetchParams & {\n url: string;\n maxFetchBytes?: BlobGatewayParams[\"maxFetchBytes\"];\n /**\n * UKYC storage authority for blob requests. Defaults to `signer` when that signer\n * is itself an MM authentication object, so the capability is never passed twice.\n */\n mmAuth?: MmTokenAuth;\n};\n\ntype KgwSessionNodeKwil = NodeKwil & {\n authenticateKGWAndSetCookie(signer: KwilSigner): Promise<string>;\n getKgwCookie(): string | undefined;\n};\n\nexport function createKgwAuthenticatedBlobGateway({\n url,\n maxFetchBytes,\n mmAuth,\n ...fetchParams\n}: CreateKgwAuthenticatedBlobGatewayParams): BlobGateway {\n const storageAuth =\n mmAuth ?? (isMmTokenAuth(fetchParams.signer) ? fetchParams.signer : undefined);\n\n return new BlobGateway({\n url,\n maxFetchBytes,\n accessToken: storageAuth?.accessToken,\n fetchFn: createKgwAuthenticatedFetch(fetchParams),\n });\n}\n\nexport function createKgwAuthenticatedFetch({\n kwilClient,\n signer,\n fetchFn = fetch,\n isAuthFailure = defaultKgwAuthFailurePredicate,\n}: CreateKgwAuthenticatedFetchParams): typeof fetch {\n const nodeKwil = getNodeKwilClient(kwilClient);\n // Coalesce in-flight re-auths. Node isn't multi-threaded, but concurrent awaits still\n // interleave: two fetches can both see an auth failure and both call refreshCookie before\n // either finishes. Without this, that would kick off two authenticateKGWAndSetCookie calls.\n // See \"shares one refresh across parallel auth failures\".\n let refreshPromise: Promise<string> | undefined;\n\n const refreshCookie = async (): Promise<string> => {\n refreshPromise ??= nodeKwil.authenticateKGWAndSetCookie(signer).finally(() => {\n refreshPromise = undefined;\n });\n\n return refreshPromise;\n };\n\n const ensureCookie = async (): Promise<{ cookie: string; refreshed: boolean }> => {\n const existingCookie = nodeKwil.getKgwCookie();\n if (existingCookie) {\n return { cookie: existingCookie, refreshed: false };\n }\n\n return { cookie: await refreshCookie(), refreshed: true };\n };\n\n return async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {\n const { cookie } = await ensureCookie();\n const bufferedRequest = await bufferRequestBody(input, init);\n const response = await fetchFn(\n ...withCookie(input, withMaterializedBody(bufferedRequest), cookie),\n );\n\n const probe = authFailureProbe(response);\n if (!(await isAuthFailure(probe.response))) {\n return response;\n }\n\n // Discard the failed response so an unread body doesn't keep streaming.\n await discardUnreadBodies(probe.discardResponses);\n const refreshedCookie = await refreshCookie();\n return fetchFn(...withCookie(input, withMaterializedBody(bufferedRequest), refreshedCookie));\n };\n}\n\ntype AuthFailureProbe = {\n response: Response;\n discardResponses: Response[];\n};\n\n/**\n * Body is one-shot. Only clone when the default predicate might call `.json()`\n * (JSON content-type). Cloning a large blob response would tee the stream and\n * risk buffering the download on an abandoned branch — and in Node, canceling\n * that unread tee branch hangs.\n *\n * When a cloned response is thrown away after an auth failure, cancel both tee\n * branches together; canceling only one branch can wait forever for the other.\n */\nfunction authFailureProbe(response: Response): AuthFailureProbe {\n const contentType = response.headers.get(\"content-type\");\n if (contentType?.includes(\"application/json\")) {\n const probe = response.clone();\n return { response: probe, discardResponses: [response, probe] };\n }\n\n return { response, discardResponses: [response] };\n}\n\nasync function discardUnreadBodies(responses: Response[]): Promise<void> {\n await Promise.all(responses.map(discardUnreadBody));\n}\n\nasync function discardUnreadBody(response: Response): Promise<void> {\n if (response.bodyUsed || !response.body) {\n return;\n }\n\n try {\n await response.body.cancel();\n } catch {\n // Already locked/closed by a concurrent reader.\n }\n}\n\ntype BufferedFormDataEntry =\n | { key: string; value: string }\n | { key: string; value: ArrayBuffer; fileName: string; type: string };\n\ntype BufferedBody =\n | { kind: \"body\"; value: BodyInit }\n | { kind: \"form-data\"; entries: BufferedFormDataEntry[] };\n\ntype BufferedRequestBody = {\n requestInit: RequestInit | undefined;\n bufferedBody?: BufferedBody;\n};\n\nasync function bufferRequestBody(\n input: RequestInfo | URL,\n init?: RequestInit,\n): Promise<BufferedRequestBody> {\n if (init?.body != null) {\n return {\n requestInit: init,\n bufferedBody: await bufferBody(init.body),\n };\n }\n\n if (input instanceof Request && input.body != null) {\n const requestClone = input.clone();\n return {\n requestInit: {\n ...init,\n method: init?.method ?? input.method,\n },\n bufferedBody: await bufferBody(requestClone.body!),\n };\n }\n\n return { requestInit: init };\n}\n\nfunction withMaterializedBody({\n requestInit,\n bufferedBody,\n}: BufferedRequestBody): RequestInit | undefined {\n if (!bufferedBody) {\n return requestInit;\n }\n\n return {\n ...requestInit,\n body: materializeBody(bufferedBody),\n };\n}\n\nasync function bufferBody(body: BodyInit): Promise<BufferedBody> {\n if (\n typeof body === \"string\" ||\n body instanceof Blob ||\n body instanceof ArrayBuffer ||\n body instanceof URLSearchParams\n ) {\n return { kind: \"body\", value: body };\n }\n\n if (ArrayBuffer.isView(body)) {\n return {\n kind: \"body\",\n value: new Uint8Array(body.buffer, body.byteOffset, body.byteLength),\n };\n }\n\n if (body instanceof FormData) {\n const entries: Promise<BufferedFormDataEntry>[] = [];\n\n body.forEach((value, key) => {\n entries.push(bufferFormDataEntry(key, value));\n });\n\n return { kind: \"form-data\", entries: await Promise.all(entries) };\n }\n\n if (body instanceof ReadableStream) {\n return {\n kind: \"body\",\n value: await new Response(body).arrayBuffer(),\n };\n }\n\n return { kind: \"body\", value: body };\n}\n\nasync function bufferFormDataEntry(\n key: string,\n value: FormDataEntryValue,\n): Promise<BufferedFormDataEntry> {\n if (typeof value === \"string\") {\n return { key, value };\n }\n\n return {\n key,\n value: await new Response(value).arrayBuffer(),\n fileName: value instanceof File ? value.name : \"blob\",\n type: value.type || \"application/octet-stream\",\n };\n}\n\nfunction materializeBody(bufferedBody: BufferedBody): BodyInit {\n if (bufferedBody.kind === \"body\") {\n return bufferedBody.value;\n }\n\n const formData = new FormData();\n\n for (const entry of bufferedBody.entries) {\n if (\"fileName\" in entry) {\n formData.append(entry.key, new Blob([entry.value], { type: entry.type }), entry.fileName);\n } else {\n formData.append(entry.key, entry.value);\n }\n }\n\n return formData;\n}\n\nfunction getNodeKwilClient(kwilClient: KwilActionClient): KgwSessionNodeKwil {\n if (!(kwilClient.client instanceof NodeKwil)) {\n throw new Error(\"KGW authenticated fetch can only be created from a NodeKwil client\");\n }\n\n if (!hasKgwSessionHelpers(kwilClient.client)) {\n throw new Error(\"NodeKwil client does not expose KGW session cookie helpers\");\n }\n\n return kwilClient.client;\n}\n\nfunction hasKgwSessionHelpers(client: NodeKwil): client is KgwSessionNodeKwil {\n const maybeClient = client as Partial<KgwSessionNodeKwil>;\n\n return (\n typeof maybeClient.getKgwCookie === \"function\" &&\n typeof maybeClient.authenticateKGWAndSetCookie === \"function\"\n );\n}\n\nfunction withCookie(\n input: RequestInfo | URL,\n init: RequestInit | undefined,\n cookie: string,\n): Parameters<typeof fetch> {\n const headers = new Headers(input instanceof Request ? input.headers : undefined);\n\n if (init?.headers) {\n new Headers(init.headers).forEach((value, key) => {\n headers.set(key, value);\n });\n }\n\n headers.set(\"Cookie\", cookie);\n\n return [input, { ...init, headers }];\n}\n\nasync function defaultKgwAuthFailurePredicate(response: Response): Promise<boolean> {\n if (response.status === 401) {\n return true;\n }\n\n const contentType = response.headers.get(\"content-type\");\n if (!contentType?.includes(\"application/json\")) {\n return false;\n }\n\n try {\n const body = (await response.json()) as { error?: { code?: number } };\n return body.error?.code === KGW_AUTH_ERROR_CODE;\n } catch {\n return false;\n }\n}\n","// Network configuration mapping\nconst NEAR_NETWORKS = {\n mainnet: {\n networkId: \"mainnet\",\n nodeUrl: \"https://rpc.mainnet.near.org\",\n },\n testnet: {\n networkId: \"testnet\",\n nodeUrl: \"https://rpc.testnet.near.org\",\n },\n betanet: {\n networkId: \"betanet\",\n nodeUrl: \"https://rpc.betanet.near.org\",\n },\n shardnet: {\n networkId: \"shardnet\",\n nodeUrl: \"https://rpc.shardnet.near.org\",\n },\n} as const;\n\n// Function to detect NEAR network from account ID\nexport const detectNearNetwork = (accountId: string): keyof typeof NEAR_NETWORKS => {\n if (accountId.endsWith(\".near\")) return \"mainnet\";\n if (accountId.endsWith(\".testnet\")) return \"testnet\";\n if (accountId.endsWith(\".betanet\")) return \"betanet\";\n if (accountId.endsWith(\".shardnet\")) return \"shardnet\";\n\n // Default to testnet for development, mainnet for production\n return \"testnet\";\n};\n\n// Function to get connection config based on account ID\nexport const getNearConnectionConfig = (\n accountId: string,\n): { networkId: string; nodeUrl: string } => {\n const network = detectNearNetwork(accountId);\n const networkConfig = NEAR_NETWORKS[network];\n\n return {\n networkId: networkConfig.networkId,\n nodeUrl: networkConfig.nodeUrl,\n };\n};\n","import type { Store } from \"@idos-network/utils/store\";\nimport type {\n Wallet as NearWallet,\n SignedMessage,\n SignMessageParams,\n} from \"@near-wallet-selector/core\";\nimport type { connect as connectT } from \"near-api-js\";\nimport type { AccessKeyList } from \"near-api-js/lib/providers/provider\";\n\nimport { KwilSigner } from \"@idos-network/kwil-js\";\nimport {\n base64Decode,\n binaryWriteUint16BE,\n bs58Decode,\n bytesConcat,\n hexEncode,\n utf8Decode,\n} from \"@idos-network/utils/codecs\";\nimport nacl from \"tweetnacl\";\n\nimport type { KwilActionClient } from \"../create-kwil-client\";\n\nimport { getNearConnectionConfig } from \"./get-config\";\nimport { nep413SignHash, serializeKwilNep413 } from \"./nep413\";\n\nconst NEAR_WALLET_TYPES: string[] = [\n \"browser\",\n \"injected\",\n \"instant-link\",\n \"hardware\",\n \"bridge\",\n] satisfies NearWallet[\"type\"][];\n\nexport function looksLikeNearWallet(signer: unknown): signer is NearWallet {\n return (\n signer !== null &&\n typeof signer === \"object\" &&\n \"id\" in signer &&\n \"metadata\" in signer &&\n \"type\" in signer &&\n typeof signer.type === \"string\" &&\n NEAR_WALLET_TYPES.includes(signer.type)\n );\n}\n\nclass KwilNonce {\n bytes: Uint8Array;\n\n constructor(length = 32) {\n // We're in the browser, so there's a window.crypto for sure.\n /* global crypto */\n this.bytes = crypto.getRandomValues(new Uint8Array(length));\n }\n\n get clampUTF8() {\n return this.bytes.map((byte) => byte & 127);\n }\n}\n\n/**\n * Creates a signer function that can be used to sign messages with a NEAR wallet\n */\nfunction createNearWalletSigner(\n wallet: NearWallet,\n recipient: string,\n): (message: string | Uint8Array) => Promise<Uint8Array> {\n return async (message: string | Uint8Array): Promise<Uint8Array> => {\n const messageString = typeof message === \"string\" ? message : utf8Decode(message);\n\n if (!wallet.signMessage) {\n throw new Error(\"Only wallets with signMessage are supported.\");\n }\n\n const nonceSuggestion = Buffer.from(new KwilNonce(32).bytes);\n\n const {\n nonce = nonceSuggestion,\n signature,\n // @ts-expect-error Signatures don't seem to be updated for NEP413 yet.\n callbackUrl,\n // oxlint-disable-next-line typescript/no-non-null-assertion -- Only non-signing wallets return void.\n } = (await (\n wallet.signMessage as (\n _: SignMessageParams,\n ) => Promise<SignedMessage & { nonce?: Uint8Array }>\n )({\n message: messageString,\n recipient,\n nonce: nonceSuggestion,\n }))!;\n\n const nep413BorshPayload = serializeKwilNep413({\n message: messageString,\n nonce: Array.from(nonce),\n recipient,\n callbackUrl,\n });\n const result = bytesConcat(\n binaryWriteUint16BE(nep413BorshPayload.length),\n nep413BorshPayload,\n base64Decode(signature),\n );\n\n return result;\n };\n}\n\nexport function implicitAddressFromPublicKey(publicKey: string): string {\n const key_without_prefix = publicKey.replace(/^ed25519:/, \"\");\n return hexEncode(bs58Decode(key_without_prefix), true);\n}\n\nexport async function getNearFullAccessPublicKeys(\n namedAddress: string,\n): Promise<string[] | undefined> {\n let connect: typeof connectT;\n try {\n connect = (await import(\"near-api-js\")).connect;\n } catch (_e) {\n throw new Error(\"Can't load near-api-js\");\n }\n const connectionConfig = getNearConnectionConfig(namedAddress);\n const nearConnection = await connect(connectionConfig);\n\n try {\n const response: AccessKeyList = await nearConnection.connection.provider.query({\n request_type: \"view_access_key_list\",\n finality: \"final\",\n account_id: namedAddress,\n });\n return response.keys\n .filter((element) => element.access_key.permission === \"FullAccess\")\n ?.map((i) => i.public_key);\n } catch {\n // `Near` failed if namedAddress contains uppercase symbols\n return;\n }\n}\n\ntype NearRedirect = {\n accountId?: string;\n publicKey?: string;\n signature?: string;\n error?: string;\n};\n\nfunction parseNearRedirect(hash: string): NearRedirect {\n const params = new URLSearchParams(hash.startsWith(\"#\") ? hash.slice(1) : hash);\n const signature = params.get(\"signature\");\n return {\n accountId: params.get(\"accountId\") ?? undefined,\n publicKey: params.get(\"publicKey\") ?? undefined,\n // URLSearchParams decodes a literal \"+\" as a space. NEP-413 signatures are base64.\n signature: signature?.replaceAll(\" \", \"+\"),\n error: params.get(\"error\") ?? undefined,\n };\n}\n\nfunction takeNearRedirect(): NearRedirect {\n const redirect = parseNearRedirect(window.location.hash);\n if (!redirect.accountId && !redirect.publicKey && !redirect.signature && !redirect.error) {\n return redirect;\n }\n\n const params = new URLSearchParams(window.location.hash.slice(1));\n for (const key of [\"accountId\", \"publicKey\", \"signature\", \"error\", \"state\"]) params.delete(key);\n const rest = params.toString();\n window.history.replaceState(\n null,\n \"\",\n `${window.location.pathname}${window.location.search}${rest ? `#${rest}` : \"\"}`,\n );\n return redirect;\n}\n\nfunction verifyNep413Signature(\n message: string,\n nonce: Uint8Array,\n recipient: string,\n callbackUrl: string,\n signature: string,\n publicKey: string,\n): boolean {\n const pieces = publicKey.split(\":\");\n if (pieces.length !== 2 || pieces[0] !== \"ed25519\" || !pieces[1] || nonce.length !== 32) {\n return false;\n }\n\n try {\n const publicKeyBytes = bs58Decode(pieces[1]);\n const signatureBytes = base64Decode(signature);\n if (publicKeyBytes.length !== 32 || signatureBytes.length !== 64) return false;\n\n return nacl.sign.detached.verify(\n nep413SignHash({ message, nonce, recipient, callbackUrl }),\n signatureBytes,\n publicKeyBytes,\n );\n } catch {\n return false;\n }\n}\n\n// The hash is attacker-controlled. A signature is only the wallet's if it verifies\n// against the request we stored before the redirect, for a full-access key of this account.\nasync function trustedNearRedirect(\n redirect: NearRedirect,\n currentAddress: string,\n recipient: string,\n store: Store,\n): Promise<{ signature: string; publicKey: string } | undefined> {\n if (\n redirect.error ||\n !redirect.signature ||\n !redirect.publicKey ||\n redirect.accountId !== currentAddress\n ) {\n return;\n }\n\n const message = await store.get<string>(\"sign-last-message\");\n const savedNonce = await store.get<number[] | Uint8Array>(\"sign-last-nonce\");\n const callbackUrl = await store.get<string>(\"sign-last-url\");\n if (!message || !savedNonce || !callbackUrl) return;\n\n const nonce = Uint8Array.from(savedNonce);\n if (\n !verifyNep413Signature(\n message,\n nonce,\n recipient,\n callbackUrl,\n redirect.signature,\n redirect.publicKey,\n )\n ) {\n return;\n }\n\n const keys = await getNearFullAccessPublicKeys(currentAddress);\n if (!keys?.includes(redirect.publicKey)) return;\n\n return { signature: redirect.signature, publicKey: redirect.publicKey };\n}\n\nexport async function signNearMessage(\n wallet: NearWallet,\n message: string,\n recipient = \"idos.network\",\n): Promise<string> {\n const signer = createNearWalletSigner(wallet, recipient);\n const signedPayload = await signer(message);\n return hexEncode(signedPayload);\n}\n\nexport async function createNearWalletKwilSigner(\n wallet: NearWallet,\n currentAddress: string,\n store: Store,\n kwilClient: KwilActionClient,\n recipient = \"idos.network\",\n): Promise<{ kwilSigner: KwilSigner; publicKey: string }> {\n if (!wallet.signMessage) throw new Error(\"Only wallets with signMessage are supported.\");\n\n if (wallet.id === \"my-near-wallet\") {\n const redirect = takeNearRedirect();\n const trusted = await trustedNearRedirect(redirect, currentAddress, recipient, store);\n\n if (trusted) {\n await store.set(\"signer-address\", currentAddress);\n await store.set(\"signer-public-key\", trusted.publicKey);\n }\n\n const signMessageOriginal = wallet.signMessage.bind(wallet);\n\n wallet.signMessage = async ({\n message,\n recipient: signRecipient,\n }: SignMessageParams): Promise<SignedMessage & { nonce?: Uint8Array }> => {\n if (redirect.error) return Promise.reject();\n\n const lastMessage = await store.get<string>(\"sign-last-message\");\n const lastNonce = await store.get<Uint8Array>(\"sign-last-nonce\");\n\n if (trusted && message === lastMessage && lastNonce) {\n const nonce = Buffer.from(lastNonce);\n const callbackUrl = await store.get<string>(\"sign-last-url\");\n\n return Promise.resolve({\n accountId: currentAddress,\n publicKey: trusted.publicKey,\n signature: trusted.signature,\n nonce,\n message,\n callbackUrl,\n } as SignedMessage);\n }\n\n const callbackUrl = window.location.href;\n const nonce = Buffer.from(new KwilNonce(32).clampUTF8);\n\n await store.set(\"sign-last-message\", message);\n await store.set(\"sign-last-nonce\", Array.from(nonce));\n await store.set(\"sign-last-url\", callbackUrl);\n\n signMessageOriginal({ message, nonce, recipient: signRecipient, callbackUrl });\n\n return new Promise(() => ({}) as SignedMessage);\n };\n }\n\n const storedAddress = await store.get<string>(\"signer-address\");\n\n let publicKey = await store.get<string>(\"signer-public-key\");\n\n if (storedAddress !== currentAddress || !publicKey) {\n store.reset();\n // To avoid re-using the old signer's kgw cookie.\n // When kwil-js supports multi cookies, we can remove this.\n await kwilClient.client.auth.logoutKGW();\n\n const message = \"idOS authentication\";\n const nonce = Buffer.from(new KwilNonce(32).bytes);\n const signResult = await wallet.signMessage({ message, recipient, nonce });\n if (!signResult) throw new Error(\"signMessage returned no result\");\n ({ publicKey } = signResult);\n\n await store.set(\"signer-address\", currentAddress);\n await store.set(\"signer-public-key\", publicKey);\n }\n\n const signer = createNearWalletSigner(wallet, recipient);\n\n return {\n kwilSigner: new KwilSigner(signer, implicitAddressFromPublicKey(publicKey), \"nep413\"),\n publicKey,\n };\n}\n","import type * as GemWallet from \"@gemwallet/api\";\nimport type { Store } from \"@idos-network/utils/store\";\nimport type { Xumm } from \"xumm\";\n\nimport { KwilSigner } from \"@idos-network/kwil-js\";\n\nimport type { KwilActionClient } from \"../create-kwil-client\";\n\nimport { getXrpTxHash } from \"./utils\";\n\nexport async function createXrpKwilSigner(\n wallet: Xumm | typeof GemWallet,\n currentAddress: string,\n store: Store,\n kwilClient: KwilActionClient,\n walletPublicKey: string,\n): Promise<KwilSigner> {\n const storedAddress = await store.get<string>(\"signer-address\");\n const storePublicKey = await store.get<string>(\"signer-public-key\");\n\n if (storedAddress !== currentAddress || (storePublicKey && storePublicKey !== walletPublicKey)) {\n try {\n // HEADS UP: for some reason logoutKGW fails on xrp\n // storePublicKey && await kwilClient.client.auth.logoutKGW();\n console.log(\"logoutKGW\", kwilClient);\n } catch (error) {\n console.error(\"Failed to logout KGW:\", error);\n }\n }\n\n await store.set(\"signer-address\", currentAddress);\n await store.set(\"signer-public-key\", walletPublicKey);\n\n const signer = async (message: string | Uint8Array): Promise<Uint8Array> => {\n const signature = await getXrpTxHash(message, wallet);\n // Buffer.from(_, \"hex\") silently truncates at the first non-hex char, so reject it up front.\n if (!signature || !/^(?:[0-9a-f]{2})+$/i.test(signature)) {\n throw new Error(\"Failed to sign transaction with XRP\");\n }\n return Buffer.from(signature, \"hex\");\n };\n\n return new KwilSigner(signer, walletPublicKey, \"xrpl\");\n}\n","import type { Store } from \"@idos-network/utils/store\";\nimport type { Wallet as NearWallet } from \"@near-wallet-selector/core\";\nimport type { Keypair as StellarKeypair } from \"@stellar/stellar-sdk\";\nimport type { Wallet as EthersWallet, JsonRpcSigner } from \"ethers\";\nimport type { KeyPair as NearKeyPair } from \"near-api-js\";\nimport type { KeyPair as XrpKeyPair } from \"ripple-keypairs/src/types\";\n\nimport { KwilSigner } from \"@idos-network/kwil-js\";\nimport { base64UrlEncode, bs58Encode, hexDecode, hexEncode } from \"@idos-network/utils/codecs\";\nimport nacl from \"tweetnacl\";\n\nimport type { WalletType } from \"./actions\";\nimport type { KwilActionClient } from \"./create-kwil-client\";\nimport type { MmTokenAuth } from \"./mm-token/create-mm-token-kwil-signer\";\n\nimport { FaceSignSignerProvider } from \"./facesign/facesign-signer\";\nimport { isMmTokenAuth } from \"./mm-token/create-mm-token-kwil-signer\";\nimport {\n createNearWalletKwilSigner,\n implicitAddressFromPublicKey,\n looksLikeNearWallet,\n} from \"./near/create-near-wallet-kwil-signer\";\nimport { kwilNep413Signer } from \"./near/nep413\";\nimport { createXrpKwilSigner } from \"./xrp/signer\";\nimport { getXrpPublicKey, looksLikeXrpWallet } from \"./xrp/utils\";\n\nexport { KwilSigner } from \"@idos-network/kwil-js\";\nexport type Wallet =\n | EthersWallet\n | JsonRpcSigner\n | NearWallet\n | CustomKwilSigner\n | MmTokenAuth\n | FaceSignSignerProvider;\n\n/**\n * Helper function to check if the given object is a `nacl.SignKeyPair`.\n */\nfunction isNaclSignKeyPair(object: unknown): object is nacl.SignKeyPair {\n return (\n object !== null &&\n typeof object === \"object\" &&\n \"publicKey\" in object &&\n object.publicKey instanceof Uint8Array &&\n object.publicKey.length === nacl.sign.publicKeyLength &&\n \"secretKey\" in object &&\n object.secretKey instanceof Uint8Array &&\n object.secretKey.length === nacl.sign.secretKeyLength\n );\n}\n\n/**\n * Helper function to check if the given object is a NEAR KeyPair.\n */\nfunction isNearKeyPair(object: unknown): object is NearKeyPair {\n return (\n object !== null &&\n typeof object === \"object\" &&\n \"getPublicKey\" in object &&\n \"sign\" in object &&\n typeof object.getPublicKey === \"function\" &&\n typeof object.sign === \"function\"\n );\n}\n\n/**\n * Helper function to check if the given object is a Stellar Keypair.\n */\nfunction isStellarKeyPair(object: unknown): object is StellarKeypair {\n return (\n object !== null &&\n typeof object === \"object\" &&\n \"publicKey\" in object &&\n \"sign\" in object &&\n \"canSign\" in object &&\n typeof object.publicKey === \"function\" &&\n typeof object.sign === \"function\" &&\n typeof object.canSign === \"function\"\n );\n}\n\nexport interface CustomKwilSigner extends KwilSigner {\n publicAddress: string;\n signatureType: string;\n publicKey: string;\n walletType: string;\n signMessage: (message: Uint8Array | string) => Promise<Uint8Array>;\n}\n\nfunction isCustomKwilSigner(object: unknown): object is CustomKwilSigner {\n return (\n object !== null &&\n typeof object === \"object\" &&\n \"publicAddress\" in object &&\n \"signatureType\" in object &&\n \"publicKey\" in object &&\n \"signMessage\" in object\n );\n}\n\n/**\n * Helper function to check if the given object is a XRP KeyPair (Server key pairs only).\n */\nfunction isXrplKeyPair(object: unknown): object is XrpKeyPair {\n return !!object && typeof object === \"object\" && \"privateKey\" in object && \"publicKey\" in object;\n}\n\nexport type KwilSignerType =\n | NearKeyPair\n | EthersWallet\n | nacl.SignKeyPair\n | JsonRpcSigner\n | StellarKeypair\n | XrpKeyPair\n | MmTokenAuth;\n\nexport type SignerAddress = string;\nexport type SignerPublicKey = string | undefined;\n\n/**\n * Creates a `KwilSigner` and its associated `SignerAddress`.\n *\n * This function is explicitly marked as being for backend use only because it doesn't reset\n * the KGW cookie when logging out and re-logging in with a different wallet.\n */\nexport async function createServerKwilSigner(\n signer: KwilSignerType,\n): Promise<[KwilSigner, SignerAddress]> {\n if (isMmTokenAuth(signer)) {\n return [signer, base64UrlEncode(signer.identifier)];\n }\n\n if (isNaclSignKeyPair(signer)) {\n return [\n new KwilSigner(\n async (msg: Uint8Array) => nacl.sign.detached(msg, signer.secretKey),\n signer.publicKey,\n \"ed25519\",\n ),\n implicitAddressFromPublicKey(bs58Encode(signer.publicKey)),\n ];\n }\n\n if (isNearKeyPair(signer)) {\n const rawPublicKey = signer.getPublicKey().toString();\n const hexPublicKey = implicitAddressFromPublicKey(rawPublicKey);\n return [\n new KwilSigner(kwilNep413Signer(\"idos-issuer\")(signer), hexPublicKey, \"nep413\"),\n rawPublicKey,\n ];\n }\n\n if (isStellarKeyPair(signer)) {\n const publicKeyString = signer.publicKey();\n const rawPublicKey = signer.rawPublicKey();\n return [\n new KwilSigner(\n async (msg: Uint8Array) => signer.sign(Buffer.from(msg)),\n rawPublicKey,\n \"ed25519\",\n ),\n publicKeyString,\n ];\n }\n\n if (isXrplKeyPair(signer)) {\n let xrpKeypair: typeof import(\"ripple-keypairs\");\n\n try {\n xrpKeypair = await import(\"ripple-keypairs\");\n } catch (e) {\n throw new Error(\"Can't load ripple-keypairs\", { cause: e });\n }\n\n return [\n new KwilSigner(\n async (msg: Uint8Array) => hexDecode(xrpKeypair.sign(hexEncode(msg), signer.privateKey)),\n signer.publicKey,\n \"xrpl\",\n ),\n signer.publicKey,\n ];\n }\n\n if (\"address\" in signer) {\n return [new KwilSigner(signer, signer.address), signer.address];\n }\n\n // Force the check that `signer` is never.\n // If these lines start complaining, that means we're missing an `if` above.\n return ((_: never) => {\n throw new Error(\"Invalid `signer` type\");\n })(signer);\n}\n\nexport async function createClientKwilSigner(\n store: Store,\n kwilClient: KwilActionClient,\n wallet: Wallet,\n): Promise<[KwilSigner, SignerAddress, SignerPublicKey, WalletType]> {\n if (\"connect\" in wallet && \"address\" in wallet) {\n // oxlint-disable-next-line no-param-reassign -- Narrowing the type on purpose\n wallet = wallet as unknown as JsonRpcSigner;\n const currentAddress = await wallet.getAddress();\n\n const storedAddress = await store.get<string>(\"signer-address\");\n\n if (storedAddress !== currentAddress) {\n // To avoid re-using the old signer's kgw cookie.\n // When kwil-js supports multi cookies, we can remove this.\n store.set(\"signer-address\", currentAddress);\n try {\n await kwilClient.client.auth.logoutKGW();\n } catch (error) {\n console.log(\"error logoutKGW\", error);\n }\n }\n\n return [new KwilSigner(wallet, currentAddress), currentAddress, undefined, \"EVM\"];\n }\n\n if (looksLikeNearWallet(wallet)) {\n const accounts = await wallet.getAccounts();\n const { kwilSigner, publicKey } = await createNearWalletKwilSigner(\n wallet,\n accounts[0].accountId,\n store,\n kwilClient,\n );\n\n return [kwilSigner, accounts[0].accountId, publicKey, \"NEAR\"];\n }\n\n if (looksLikeXrpWallet(wallet)) {\n const { address: currentAddress, publicKey: walletPublicKey } = (await getXrpPublicKey(\n wallet,\n )) as { address: string; publicKey: string };\n if (!currentAddress) {\n throw new Error(\"Failed to get XRP address\");\n }\n\n return [\n await createXrpKwilSigner(wallet, currentAddress, store, kwilClient, walletPublicKey),\n currentAddress,\n walletPublicKey,\n \"XRPL\",\n ];\n }\n\n if (isMmTokenAuth(wallet)) {\n const currentAddress = base64UrlEncode(wallet.identifier);\n const storedAddress = await store.get<string>(\"signer-address\");\n\n if (storedAddress !== currentAddress) {\n // A different MM signing identity must not re-use the previous KGW cookie.\n store.set(\"signer-address\", currentAddress);\n try {\n await kwilClient.client.auth.logoutKGW();\n } catch (error) {\n console.log(\"error logoutKGW\", error);\n }\n }\n\n return [wallet, currentAddress, currentAddress, \"MM\"];\n }\n\n if (isCustomKwilSigner(wallet) || wallet instanceof FaceSignSignerProvider) {\n const storedAddress = await store.get<string>(\"signer-address\");\n\n if (storedAddress !== wallet.publicAddress) {\n store.set(\"signer-address\", wallet.publicAddress);\n try {\n await kwilClient.client.auth.logoutKGW();\n } catch (error) {\n console.log(\"error logoutKGW\", error);\n }\n }\n\n return [\n new KwilSigner(\n async (msg: Uint8Array) => wallet.signMessage(msg),\n wallet.publicAddress,\n \"ed25519\",\n ),\n wallet.publicAddress,\n wallet.publicKey,\n wallet.walletType as WalletType,\n ];\n }\n\n // Force the check that `signer` is `never`.\n // If these lines start complaining, that means we're missing an `if` above.\n return ((_: never) => {\n throw new Error(\"Invalid `signer` type\");\n })(wallet);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["KwilSigner","KwilSigner","KwilSigner"],"sources":["../src/wait-for-kwil-tx.ts","../src/create-kwil-client.ts","../src/create-kgw-authenticated-fetch.ts","../src/near/get-config.ts","../src/near/create-near-wallet-kwil-signer.ts","../src/xrp/signer.ts","../src/create-kwil-signer.ts"],"sourcesContent":["const KWIL_TX_POLL_DEADLINE_MS = 90_000;\nconst INITIAL_POLL_INTERVAL_MS = 300;\nconst POLL_BACKOFF_FACTOR = 1.5;\nconst MAX_POLL_INTERVAL_MS = 2_000;\nconst MAX_POLL_JITTER_MS = 100;\n\nexport type KwilTxInfo = {\n height: number;\n tx_result: {\n code: number;\n log: string;\n };\n};\n\nexport class KwilTxFailedError extends Error {\n readonly name = \"KwilTxFailedError\";\n\n constructor(\n readonly txHash: string,\n readonly code: number,\n readonly log: string,\n readonly height: number,\n ) {\n super(`Kwil transaction ${txHash} failed at height ${height} (code ${code}): ${log}`);\n }\n}\n\nexport class KwilTxPollTimeoutError extends Error {\n readonly name = \"KwilTxPollTimeoutError\";\n\n constructor(\n readonly txHash: string,\n readonly deadlineMs: number,\n options?: { cause?: unknown },\n ) {\n const lastError =\n options?.cause instanceof Error\n ? options.cause.message\n : options?.cause != null\n ? String(options.cause)\n : undefined;\n super(\n lastError\n ? `Timed out after ${deadlineMs}ms waiting for Kwil transaction ${txHash}: last error: ${lastError}`\n : `Timed out after ${deadlineMs}ms waiting for Kwil transaction ${txHash}`,\n options?.cause !== undefined ? { cause: options.cause } : undefined,\n );\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction nextPollIntervalMs(currentIntervalMs: number): number {\n return Math.min(currentIntervalMs * POLL_BACKOFF_FACTOR, MAX_POLL_INTERVAL_MS);\n}\n\nfunction pollIntervalWithJitter(intervalMs: number): number {\n return intervalMs + Math.floor(Math.random() * (MAX_POLL_JITTER_MS + 1));\n}\n\nfunction isTxFinalized(txInfo: KwilTxInfo): boolean {\n return txInfo.height > 0;\n}\n\nexport async function waitForKwilTx(\n txInfo: (txHash: string) => Promise<{ data?: KwilTxInfo }>,\n txHash: string,\n deadlineMs: number = KWIL_TX_POLL_DEADLINE_MS,\n): Promise<void> {\n const deadlineAt = Date.now() + deadlineMs;\n let intervalMs = INITIAL_POLL_INTERVAL_MS;\n let lastPollError: unknown;\n\n while (Date.now() < deadlineAt) {\n let data: KwilTxInfo | undefined;\n\n // Transient poll failures (e.g. \"not found\" before the node indexes the tx) are\n // recorded and retried. Terminal tx failures are decided below, outside this catch.\n try {\n data = (await txInfo(txHash)).data;\n } catch (error) {\n lastPollError = error;\n }\n\n // height > 0 means the tx was included. Then code 0 is success; anything else is final failure.\n if (data && isTxFinalized(data)) {\n if (data.tx_result.code !== 0) {\n throw new KwilTxFailedError(txHash, data.tx_result.code, data.tx_result.log, data.height);\n }\n return;\n }\n\n // Not finalized yet (or last poll errored) — back off and try again until the deadline.\n const waitMs = pollIntervalWithJitter(intervalMs);\n const remainingMs = deadlineAt - Date.now();\n if (remainingMs <= 0) {\n break;\n }\n\n await sleep(Math.min(waitMs, remainingMs));\n intervalMs = nextPollIntervalMs(intervalMs);\n }\n\n throw new KwilTxPollTimeoutError(\n txHash,\n deadlineMs,\n lastPollError !== undefined ? { cause: lastPollError } : undefined,\n );\n}\n","import type { ActionBody, CallBody, PositionalParams } from \"@idos-network/kwil-js/action\";\nimport type { Config } from \"@idos-network/kwil-js/config\";\nimport type { DataInfo } from \"@idos-network/kwil-js/database\";\n\nimport { type KwilSigner, NodeKwil, WebKwil } from \"@idos-network/kwil-js\";\nimport invariant from \"tiny-invariant\";\n\nimport type { ActionSchemaElement } from \"./actions\";\n\nimport { actionSchema } from \"./actions\";\nimport { waitForKwilTx } from \"./wait-for-kwil-tx\";\n\nexport { KwilTxFailedError, KwilTxPollTimeoutError } from \"./wait-for-kwil-tx\";\n\ntype CreateKwilClientParams = {\n chainId?: string;\n nodeUrl: string;\n};\n\ntype KwilActions = typeof actionSchema;\ntype ActionName = keyof KwilActions;\n\ntype AllKwilCallAction = {\n [Name in ActionName]: {\n name: Name;\n // oxlint-disable-next-line typescript/no-explicit-any -- This is fine\n inputs: Record<KwilActions[Name][number][\"name\"], any>;\n };\n};\n\ntype KwilCallActionRequestParams = AllKwilCallAction[ActionName];\n\ntype AllKwilExecuteAction = {\n [Name in ActionName]: AllKwilCallAction[Name] & { description: string };\n};\n\ntype KwilExecuteActionRequestParams = AllKwilExecuteAction[ActionName];\n\n/**\n * A view action ran but failed (its `error()` or a runtime error). kwild reports that in the\n * call response's `error` field, not as an HTTP/RPC error, so it is only thrown when\n * `KwilActionClient.throwOnCallError` is set.\n */\nexport class KwilCallError extends Error {\n readonly name = \"KwilCallError\";\n\n constructor(\n readonly actionName: string,\n message: string,\n ) {\n super(message);\n }\n}\n\n/**\n * A client for interacting with kwil with type-safe abstractions for `call` and `execute`.\n * Has utility methods for creating actions and setting a signer.\n */\nexport class KwilActionClient {\n signer?: KwilSigner;\n /**\n * When true, `call` throws `KwilCallError` if the view action reports an error. When false\n * (default) such a call resolves to its (empty) result, as it always has.\n */\n throwOnCallError = false;\n readonly client: NodeKwil | WebKwil;\n\n constructor(client: NodeKwil | WebKwil) {\n this.client = client;\n }\n\n #createActionInputs(actionName: string, params: Record<string, unknown> = {}): PositionalParams {\n if (!params || !Object.keys(params).length) return [];\n\n const args = (actionSchema as Record<string, readonly ActionSchemaElement[]>)[actionName];\n\n return args.map(({ name }) => {\n const value = params[name];\n // Handle falsy values appropriately\n if (value === \"\" || value === 0) return value;\n return value ?? null;\n }) as PositionalParams;\n }\n\n #actionTypes(actionName: string): DataInfo[] {\n const args = actionSchema[actionName];\n return args.map((arg) => arg.type);\n }\n\n /**\n * Calls an action on the kwil nodes. This similar to `GET` like request.\n */\n async call<T = unknown>(\n params: KwilCallActionRequestParams,\n signer: KwilSigner | undefined = this.signer,\n ): Promise<T> {\n const action: CallBody = {\n name: params.name,\n namespace: \"main\",\n inputs: this.#createActionInputs(params.name, params.inputs),\n types: this.#actionTypes(params.name),\n };\n\n const response = await this.client.call(action as CallBody, signer);\n const actionError = response?.data?.error;\n if (this.throwOnCallError && actionError) {\n throw new KwilCallError(params.name, actionError);\n }\n return response?.data?.result as T;\n }\n\n /**\n * Executes an action on the kwil nodes. This similar to `POST` like request.\n *\n * When `synchronous` is true (default), the tx is broadcast without blocking the node,\n * then confirmed by polling `txInfo` with exponential backoff.\n */\n async execute(\n params: KwilExecuteActionRequestParams,\n signer: KwilSigner | undefined = this.signer,\n synchronous = true,\n ): Promise<string> {\n invariant(signer, \"Signer is not set, you must set it before executing an action\");\n const action: ActionBody = {\n name: params.name,\n namespace: \"main\",\n description: params.description,\n inputs: [this.#createActionInputs(params.name, params.inputs)],\n types: this.#actionTypes(params.name),\n };\n const response = await this.client.execute(action, signer, false);\n const txHash = response.data?.tx_hash;\n\n if (!txHash) {\n throw new Error(`Kwil execute \"${params.name}\" did not return a transaction hash`);\n }\n\n if (synchronous) {\n await this.waitForTx(txHash);\n }\n\n return txHash;\n }\n\n /**\n * Polls the node until a broadcast transaction is mined, or throws\n * `KwilTxFailedError` / `KwilTxPollTimeoutError`.\n *\n * Called through `this` rather than directly so that it is a seam an\n * instrumentation can wrap — the wait dominates the latency of `execute`.\n */\n async waitForTx(txHash: string): Promise<void> {\n await waitForKwilTx((hash) => this.client.txInfo(hash), txHash);\n }\n\n setSigner(signer: KwilSigner | undefined): void {\n this.signer = signer;\n }\n\n /**\n * Creates action inputs from the given parameters that are used in the action body.\n */\n}\n\nconst DEFAULT_TIMEOUT = 30_000;\n\nconst createKwilClient =\n (Cls: new (opts: Config) => NodeKwil | WebKwil) =>\n async ({ nodeUrl: kwilProvider, chainId }: CreateKwilClientParams): Promise<KwilActionClient> => {\n const _kwil = new Cls({ kwilProvider, chainId: \"\" });\n // oxlint-disable-next-line no-param-reassign -- Default value fallback\n chainId ||= (await _kwil.chainInfo({ disableWarning: true })).data?.chain_id;\n invariant(chainId, \"Can't discover `chainId`. You must pass it explicitly.\");\n\n const client = new KwilActionClient(\n new Cls({ kwilProvider, chainId, timeout: DEFAULT_TIMEOUT }),\n );\n\n return client;\n };\n\n/**\n * Create a kwil client for node.js environment\n */\nexport const createNodeKwilClient: (params: CreateKwilClientParams) => Promise<KwilActionClient> =\n createKwilClient(NodeKwil);\n\n/**\n * Create a kwil client for browser environment\n */\nexport const createWebKwilClient: (params: CreateKwilClientParams) => Promise<KwilActionClient> =\n createKwilClient(WebKwil);\n","import { type KwilSigner, NodeKwil } from \"@idos-network/kwil-js\";\nimport { BlobGateway, type BlobGatewayParams } from \"@idos-network/utils/blob-gateway\";\n\nimport type { KwilActionClient } from \"./create-kwil-client\";\n\nconst KGW_AUTH_ERROR_CODE = -901;\n\n/** Return true when the response means KGW auth is missing/expired.\n * May read the body only for `application/json` responses (those are probed via a clone). */\nexport type KgwAuthFailurePredicate = (response: Response) => Promise<boolean> | boolean;\n\nexport type CreateKgwAuthenticatedFetchParams = {\n kwilClient: KwilActionClient;\n signer: KwilSigner;\n fetchFn?: typeof fetch;\n isAuthFailure?: KgwAuthFailurePredicate;\n};\n\nexport type CreateKgwAuthenticatedBlobGatewayParams = CreateKgwAuthenticatedFetchParams & {\n url: string;\n maxFetchBytes?: BlobGatewayParams[\"maxFetchBytes\"];\n /**\n * UKYC storage token, sent as `Authorization: AccessToken <token>` next to the KGW session\n * cookie. Only MM operators use it; `BlobGateway.withAccessToken()` swaps it per request.\n */\n accessToken?: string;\n};\n\ntype KgwSessionNodeKwil = NodeKwil & {\n authenticateKGWAndSetCookie(signer: KwilSigner): Promise<string>;\n getKgwCookie(): string | undefined;\n};\n\nexport function createKgwAuthenticatedBlobGateway({\n url,\n maxFetchBytes,\n accessToken,\n ...fetchParams\n}: CreateKgwAuthenticatedBlobGatewayParams): BlobGateway {\n return new BlobGateway({\n url,\n maxFetchBytes,\n accessToken,\n fetchFn: createKgwAuthenticatedFetch(fetchParams),\n });\n}\n\nexport function createKgwAuthenticatedFetch({\n kwilClient,\n signer,\n fetchFn = fetch,\n isAuthFailure = defaultKgwAuthFailurePredicate,\n}: CreateKgwAuthenticatedFetchParams): typeof fetch {\n const nodeKwil = getNodeKwilClient(kwilClient);\n // Coalesce in-flight re-auths. Node isn't multi-threaded, but concurrent awaits still\n // interleave: two fetches can both see an auth failure and both call refreshCookie before\n // either finishes. Without this, that would kick off two authenticateKGWAndSetCookie calls.\n // See \"shares one refresh across parallel auth failures\".\n let refreshPromise: Promise<string> | undefined;\n\n const refreshCookie = async (): Promise<string> => {\n refreshPromise ??= nodeKwil.authenticateKGWAndSetCookie(signer).finally(() => {\n refreshPromise = undefined;\n });\n\n return refreshPromise;\n };\n\n const ensureCookie = async (): Promise<{ cookie: string; refreshed: boolean }> => {\n const existingCookie = nodeKwil.getKgwCookie();\n if (existingCookie) {\n return { cookie: existingCookie, refreshed: false };\n }\n\n return { cookie: await refreshCookie(), refreshed: true };\n };\n\n return async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {\n const { cookie } = await ensureCookie();\n const bufferedRequest = await bufferRequestBody(input, init);\n const response = await fetchFn(\n ...withCookie(input, withMaterializedBody(bufferedRequest), cookie),\n );\n\n const probe = authFailureProbe(response);\n if (!(await isAuthFailure(probe.response))) {\n return response;\n }\n\n // Discard the failed response so an unread body doesn't keep streaming.\n await discardUnreadBodies(probe.discardResponses);\n const refreshedCookie = await refreshCookie();\n return fetchFn(...withCookie(input, withMaterializedBody(bufferedRequest), refreshedCookie));\n };\n}\n\ntype AuthFailureProbe = {\n response: Response;\n discardResponses: Response[];\n};\n\n/**\n * Body is one-shot. Only clone when the default predicate might call `.json()`\n * (JSON content-type). Cloning a large blob response would tee the stream and\n * risk buffering the download on an abandoned branch — and in Node, canceling\n * that unread tee branch hangs.\n *\n * When a cloned response is thrown away after an auth failure, cancel both tee\n * branches together; canceling only one branch can wait forever for the other.\n */\nfunction authFailureProbe(response: Response): AuthFailureProbe {\n const contentType = response.headers.get(\"content-type\");\n if (contentType?.includes(\"application/json\")) {\n const probe = response.clone();\n return { response: probe, discardResponses: [response, probe] };\n }\n\n return { response, discardResponses: [response] };\n}\n\nasync function discardUnreadBodies(responses: Response[]): Promise<void> {\n await Promise.all(responses.map(discardUnreadBody));\n}\n\nasync function discardUnreadBody(response: Response): Promise<void> {\n if (response.bodyUsed || !response.body) {\n return;\n }\n\n try {\n await response.body.cancel();\n } catch {\n // Already locked/closed by a concurrent reader.\n }\n}\n\ntype BufferedFormDataEntry =\n | { key: string; value: string }\n | { key: string; value: ArrayBuffer; fileName: string; type: string };\n\ntype BufferedBody =\n | { kind: \"body\"; value: BodyInit }\n | { kind: \"form-data\"; entries: BufferedFormDataEntry[] };\n\ntype BufferedRequestBody = {\n requestInit: RequestInit | undefined;\n bufferedBody?: BufferedBody;\n};\n\nasync function bufferRequestBody(\n input: RequestInfo | URL,\n init?: RequestInit,\n): Promise<BufferedRequestBody> {\n if (init?.body != null) {\n return {\n requestInit: init,\n bufferedBody: await bufferBody(init.body),\n };\n }\n\n if (input instanceof Request && input.body != null) {\n const requestClone = input.clone();\n return {\n requestInit: {\n ...init,\n method: init?.method ?? input.method,\n },\n bufferedBody: await bufferBody(requestClone.body!),\n };\n }\n\n return { requestInit: init };\n}\n\nfunction withMaterializedBody({\n requestInit,\n bufferedBody,\n}: BufferedRequestBody): RequestInit | undefined {\n if (!bufferedBody) {\n return requestInit;\n }\n\n return {\n ...requestInit,\n body: materializeBody(bufferedBody),\n };\n}\n\nasync function bufferBody(body: BodyInit): Promise<BufferedBody> {\n if (\n typeof body === \"string\" ||\n body instanceof Blob ||\n body instanceof ArrayBuffer ||\n body instanceof URLSearchParams\n ) {\n return { kind: \"body\", value: body };\n }\n\n if (ArrayBuffer.isView(body)) {\n return {\n kind: \"body\",\n value: new Uint8Array(body.buffer, body.byteOffset, body.byteLength),\n };\n }\n\n if (body instanceof FormData) {\n const entries: Promise<BufferedFormDataEntry>[] = [];\n\n body.forEach((value, key) => {\n entries.push(bufferFormDataEntry(key, value));\n });\n\n return { kind: \"form-data\", entries: await Promise.all(entries) };\n }\n\n if (body instanceof ReadableStream) {\n return {\n kind: \"body\",\n value: await new Response(body).arrayBuffer(),\n };\n }\n\n return { kind: \"body\", value: body };\n}\n\nasync function bufferFormDataEntry(\n key: string,\n value: FormDataEntryValue,\n): Promise<BufferedFormDataEntry> {\n if (typeof value === \"string\") {\n return { key, value };\n }\n\n return {\n key,\n value: await new Response(value).arrayBuffer(),\n fileName: value instanceof File ? value.name : \"blob\",\n type: value.type || \"application/octet-stream\",\n };\n}\n\nfunction materializeBody(bufferedBody: BufferedBody): BodyInit {\n if (bufferedBody.kind === \"body\") {\n return bufferedBody.value;\n }\n\n const formData = new FormData();\n\n for (const entry of bufferedBody.entries) {\n if (\"fileName\" in entry) {\n formData.append(entry.key, new Blob([entry.value], { type: entry.type }), entry.fileName);\n } else {\n formData.append(entry.key, entry.value);\n }\n }\n\n return formData;\n}\n\nfunction getNodeKwilClient(kwilClient: KwilActionClient): KgwSessionNodeKwil {\n if (!(kwilClient.client instanceof NodeKwil)) {\n throw new Error(\"KGW authenticated fetch can only be created from a NodeKwil client\");\n }\n\n if (!hasKgwSessionHelpers(kwilClient.client)) {\n throw new Error(\"NodeKwil client does not expose KGW session cookie helpers\");\n }\n\n return kwilClient.client;\n}\n\nfunction hasKgwSessionHelpers(client: NodeKwil): client is KgwSessionNodeKwil {\n const maybeClient = client as Partial<KgwSessionNodeKwil>;\n\n return (\n typeof maybeClient.getKgwCookie === \"function\" &&\n typeof maybeClient.authenticateKGWAndSetCookie === \"function\"\n );\n}\n\nfunction withCookie(\n input: RequestInfo | URL,\n init: RequestInit | undefined,\n cookie: string,\n): Parameters<typeof fetch> {\n const headers = new Headers(input instanceof Request ? input.headers : undefined);\n\n if (init?.headers) {\n new Headers(init.headers).forEach((value, key) => {\n headers.set(key, value);\n });\n }\n\n headers.set(\"Cookie\", cookie);\n\n return [input, { ...init, headers }];\n}\n\n// blob-gateway also answers 401 for a bad UKYC storage token. A new KGW session doesn't fix that.\nconst STORAGE_TOKEN_AUTH_ERROR_CODES = new Set([\"MM_TOKEN_INVALID\", \"MM_TOKEN_EXPIRED\"]);\n\nasync function defaultKgwAuthFailurePredicate(response: Response): Promise<boolean> {\n const contentType = response.headers.get(\"content-type\");\n if (!contentType?.includes(\"application/json\")) {\n return response.status === 401;\n }\n\n try {\n const body = (await response.json()) as { code?: unknown; error?: { code?: number } };\n if (response.status === 401) {\n return !(typeof body.code === \"string\" && STORAGE_TOKEN_AUTH_ERROR_CODES.has(body.code));\n }\n return body.error?.code === KGW_AUTH_ERROR_CODE;\n } catch {\n return response.status === 401;\n }\n}\n","// Network configuration mapping\nconst NEAR_NETWORKS = {\n mainnet: {\n networkId: \"mainnet\",\n nodeUrl: \"https://rpc.mainnet.near.org\",\n },\n testnet: {\n networkId: \"testnet\",\n nodeUrl: \"https://rpc.testnet.near.org\",\n },\n betanet: {\n networkId: \"betanet\",\n nodeUrl: \"https://rpc.betanet.near.org\",\n },\n shardnet: {\n networkId: \"shardnet\",\n nodeUrl: \"https://rpc.shardnet.near.org\",\n },\n} as const;\n\n// Function to detect NEAR network from account ID\nexport const detectNearNetwork = (accountId: string): keyof typeof NEAR_NETWORKS => {\n if (accountId.endsWith(\".near\")) return \"mainnet\";\n if (accountId.endsWith(\".testnet\")) return \"testnet\";\n if (accountId.endsWith(\".betanet\")) return \"betanet\";\n if (accountId.endsWith(\".shardnet\")) return \"shardnet\";\n\n // Default to testnet for development, mainnet for production\n return \"testnet\";\n};\n\n// Function to get connection config based on account ID\nexport const getNearConnectionConfig = (\n accountId: string,\n): { networkId: string; nodeUrl: string } => {\n const network = detectNearNetwork(accountId);\n const networkConfig = NEAR_NETWORKS[network];\n\n return {\n networkId: networkConfig.networkId,\n nodeUrl: networkConfig.nodeUrl,\n };\n};\n","import type { Store } from \"@idos-network/utils/store\";\nimport type {\n Wallet as NearWallet,\n SignedMessage,\n SignMessageParams,\n} from \"@near-wallet-selector/core\";\nimport type { connect as connectT } from \"near-api-js\";\nimport type { AccessKeyList } from \"near-api-js/lib/providers/provider\";\n\nimport { KwilSigner } from \"@idos-network/kwil-js\";\nimport {\n base64Decode,\n binaryWriteUint16BE,\n bs58Decode,\n bytesConcat,\n hexEncode,\n utf8Decode,\n} from \"@idos-network/utils/codecs\";\nimport nacl from \"tweetnacl\";\n\nimport type { KwilActionClient } from \"../create-kwil-client\";\n\nimport { getNearConnectionConfig } from \"./get-config\";\nimport { nep413SignHash, serializeKwilNep413 } from \"./nep413\";\n\nconst NEAR_WALLET_TYPES: string[] = [\n \"browser\",\n \"injected\",\n \"instant-link\",\n \"hardware\",\n \"bridge\",\n] satisfies NearWallet[\"type\"][];\n\nexport function looksLikeNearWallet(signer: unknown): signer is NearWallet {\n return (\n signer !== null &&\n typeof signer === \"object\" &&\n \"id\" in signer &&\n \"metadata\" in signer &&\n \"type\" in signer &&\n typeof signer.type === \"string\" &&\n NEAR_WALLET_TYPES.includes(signer.type)\n );\n}\n\nclass KwilNonce {\n bytes: Uint8Array;\n\n constructor(length = 32) {\n // We're in the browser, so there's a window.crypto for sure.\n /* global crypto */\n this.bytes = crypto.getRandomValues(new Uint8Array(length));\n }\n\n get clampUTF8() {\n return this.bytes.map((byte) => byte & 127);\n }\n}\n\n/**\n * Creates a signer function that can be used to sign messages with a NEAR wallet\n */\nfunction createNearWalletSigner(\n wallet: NearWallet,\n recipient: string,\n): (message: string | Uint8Array) => Promise<Uint8Array> {\n return async (message: string | Uint8Array): Promise<Uint8Array> => {\n const messageString = typeof message === \"string\" ? message : utf8Decode(message);\n\n if (!wallet.signMessage) {\n throw new Error(\"Only wallets with signMessage are supported.\");\n }\n\n const nonceSuggestion = Buffer.from(new KwilNonce(32).bytes);\n\n const {\n nonce = nonceSuggestion,\n signature,\n // @ts-expect-error Signatures don't seem to be updated for NEP413 yet.\n callbackUrl,\n // oxlint-disable-next-line typescript/no-non-null-assertion -- Only non-signing wallets return void.\n } = (await (\n wallet.signMessage as (\n _: SignMessageParams,\n ) => Promise<SignedMessage & { nonce?: Uint8Array }>\n )({\n message: messageString,\n recipient,\n nonce: nonceSuggestion,\n }))!;\n\n const nep413BorshPayload = serializeKwilNep413({\n message: messageString,\n nonce: Array.from(nonce),\n recipient,\n callbackUrl,\n });\n const result = bytesConcat(\n binaryWriteUint16BE(nep413BorshPayload.length),\n nep413BorshPayload,\n base64Decode(signature),\n );\n\n return result;\n };\n}\n\nexport function implicitAddressFromPublicKey(publicKey: string): string {\n const key_without_prefix = publicKey.replace(/^ed25519:/, \"\");\n return hexEncode(bs58Decode(key_without_prefix), true);\n}\n\nexport async function getNearFullAccessPublicKeys(\n namedAddress: string,\n): Promise<string[] | undefined> {\n let connect: typeof connectT;\n try {\n connect = (await import(\"near-api-js\")).connect;\n } catch (_e) {\n throw new Error(\"Can't load near-api-js\");\n }\n const connectionConfig = getNearConnectionConfig(namedAddress);\n const nearConnection = await connect(connectionConfig);\n\n try {\n const response: AccessKeyList = await nearConnection.connection.provider.query({\n request_type: \"view_access_key_list\",\n finality: \"final\",\n account_id: namedAddress,\n });\n return response.keys\n .filter((element) => element.access_key.permission === \"FullAccess\")\n ?.map((i) => i.public_key);\n } catch {\n // `Near` failed if namedAddress contains uppercase symbols\n return;\n }\n}\n\ntype NearRedirect = {\n accountId?: string;\n publicKey?: string;\n signature?: string;\n error?: string;\n};\n\nfunction parseNearRedirect(hash: string): NearRedirect {\n const params = new URLSearchParams(hash.startsWith(\"#\") ? hash.slice(1) : hash);\n const signature = params.get(\"signature\");\n return {\n accountId: params.get(\"accountId\") ?? undefined,\n publicKey: params.get(\"publicKey\") ?? undefined,\n // URLSearchParams decodes a literal \"+\" as a space. NEP-413 signatures are base64.\n signature: signature?.replaceAll(\" \", \"+\"),\n error: params.get(\"error\") ?? undefined,\n };\n}\n\nfunction takeNearRedirect(): NearRedirect {\n const redirect = parseNearRedirect(window.location.hash);\n if (!redirect.accountId && !redirect.publicKey && !redirect.signature && !redirect.error) {\n return redirect;\n }\n\n const params = new URLSearchParams(window.location.hash.slice(1));\n for (const key of [\"accountId\", \"publicKey\", \"signature\", \"error\", \"state\"]) params.delete(key);\n const rest = params.toString();\n window.history.replaceState(\n null,\n \"\",\n `${window.location.pathname}${window.location.search}${rest ? `#${rest}` : \"\"}`,\n );\n return redirect;\n}\n\nfunction verifyNep413Signature(\n message: string,\n nonce: Uint8Array,\n recipient: string,\n callbackUrl: string,\n signature: string,\n publicKey: string,\n): boolean {\n const pieces = publicKey.split(\":\");\n if (pieces.length !== 2 || pieces[0] !== \"ed25519\" || !pieces[1] || nonce.length !== 32) {\n return false;\n }\n\n try {\n const publicKeyBytes = bs58Decode(pieces[1]);\n const signatureBytes = base64Decode(signature);\n if (publicKeyBytes.length !== 32 || signatureBytes.length !== 64) return false;\n\n return nacl.sign.detached.verify(\n nep413SignHash({ message, nonce, recipient, callbackUrl }),\n signatureBytes,\n publicKeyBytes,\n );\n } catch {\n return false;\n }\n}\n\n// The hash is attacker-controlled. A signature is only the wallet's if it verifies\n// against the request we stored before the redirect, for a full-access key of this account.\nasync function trustedNearRedirect(\n redirect: NearRedirect,\n currentAddress: string,\n recipient: string,\n store: Store,\n): Promise<{ signature: string; publicKey: string } | undefined> {\n if (\n redirect.error ||\n !redirect.signature ||\n !redirect.publicKey ||\n redirect.accountId !== currentAddress\n ) {\n return;\n }\n\n const message = await store.get<string>(\"sign-last-message\");\n const savedNonce = await store.get<number[] | Uint8Array>(\"sign-last-nonce\");\n const callbackUrl = await store.get<string>(\"sign-last-url\");\n if (!message || !savedNonce || !callbackUrl) return;\n\n const nonce = Uint8Array.from(savedNonce);\n if (\n !verifyNep413Signature(\n message,\n nonce,\n recipient,\n callbackUrl,\n redirect.signature,\n redirect.publicKey,\n )\n ) {\n return;\n }\n\n const keys = await getNearFullAccessPublicKeys(currentAddress);\n if (!keys?.includes(redirect.publicKey)) return;\n\n return { signature: redirect.signature, publicKey: redirect.publicKey };\n}\n\nexport async function signNearMessage(\n wallet: NearWallet,\n message: string,\n recipient = \"idos.network\",\n): Promise<string> {\n const signer = createNearWalletSigner(wallet, recipient);\n const signedPayload = await signer(message);\n return hexEncode(signedPayload);\n}\n\nexport async function createNearWalletKwilSigner(\n wallet: NearWallet,\n currentAddress: string,\n store: Store,\n kwilClient: KwilActionClient,\n recipient = \"idos.network\",\n): Promise<{ kwilSigner: KwilSigner; publicKey: string }> {\n if (!wallet.signMessage) throw new Error(\"Only wallets with signMessage are supported.\");\n\n if (wallet.id === \"my-near-wallet\") {\n const redirect = takeNearRedirect();\n const trusted = await trustedNearRedirect(redirect, currentAddress, recipient, store);\n\n if (trusted) {\n await store.set(\"signer-address\", currentAddress);\n await store.set(\"signer-public-key\", trusted.publicKey);\n }\n\n const signMessageOriginal = wallet.signMessage.bind(wallet);\n\n wallet.signMessage = async ({\n message,\n recipient: signRecipient,\n }: SignMessageParams): Promise<SignedMessage & { nonce?: Uint8Array }> => {\n if (redirect.error) return Promise.reject();\n\n const lastMessage = await store.get<string>(\"sign-last-message\");\n const lastNonce = await store.get<Uint8Array>(\"sign-last-nonce\");\n\n if (trusted && message === lastMessage && lastNonce) {\n const nonce = Buffer.from(lastNonce);\n const callbackUrl = await store.get<string>(\"sign-last-url\");\n\n return Promise.resolve({\n accountId: currentAddress,\n publicKey: trusted.publicKey,\n signature: trusted.signature,\n nonce,\n message,\n callbackUrl,\n } as SignedMessage);\n }\n\n const callbackUrl = window.location.href;\n const nonce = Buffer.from(new KwilNonce(32).clampUTF8);\n\n await store.set(\"sign-last-message\", message);\n await store.set(\"sign-last-nonce\", Array.from(nonce));\n await store.set(\"sign-last-url\", callbackUrl);\n\n signMessageOriginal({ message, nonce, recipient: signRecipient, callbackUrl });\n\n return new Promise(() => ({}) as SignedMessage);\n };\n }\n\n const storedAddress = await store.get<string>(\"signer-address\");\n\n let publicKey = await store.get<string>(\"signer-public-key\");\n\n if (storedAddress !== currentAddress || !publicKey) {\n store.reset();\n // To avoid re-using the old signer's kgw cookie.\n // When kwil-js supports multi cookies, we can remove this.\n await kwilClient.client.auth.logoutKGW();\n\n const message = \"idOS authentication\";\n const nonce = Buffer.from(new KwilNonce(32).bytes);\n const signResult = await wallet.signMessage({ message, recipient, nonce });\n if (!signResult) throw new Error(\"signMessage returned no result\");\n ({ publicKey } = signResult);\n\n await store.set(\"signer-address\", currentAddress);\n await store.set(\"signer-public-key\", publicKey);\n }\n\n const signer = createNearWalletSigner(wallet, recipient);\n\n return {\n kwilSigner: new KwilSigner(signer, implicitAddressFromPublicKey(publicKey), \"nep413\"),\n publicKey,\n };\n}\n","import type * as GemWallet from \"@gemwallet/api\";\nimport type { Store } from \"@idos-network/utils/store\";\nimport type { Xumm } from \"xumm\";\n\nimport { KwilSigner } from \"@idos-network/kwil-js\";\n\nimport type { KwilActionClient } from \"../create-kwil-client\";\n\nimport { getXrpTxHash } from \"./utils\";\n\nexport async function createXrpKwilSigner(\n wallet: Xumm | typeof GemWallet,\n currentAddress: string,\n store: Store,\n kwilClient: KwilActionClient,\n walletPublicKey: string,\n): Promise<KwilSigner> {\n const storedAddress = await store.get<string>(\"signer-address\");\n const storePublicKey = await store.get<string>(\"signer-public-key\");\n\n if (storedAddress !== currentAddress || (storePublicKey && storePublicKey !== walletPublicKey)) {\n try {\n // HEADS UP: for some reason logoutKGW fails on xrp\n // storePublicKey && await kwilClient.client.auth.logoutKGW();\n console.log(\"logoutKGW\", kwilClient);\n } catch (error) {\n console.error(\"Failed to logout KGW:\", error);\n }\n }\n\n await store.set(\"signer-address\", currentAddress);\n await store.set(\"signer-public-key\", walletPublicKey);\n\n const signer = async (message: string | Uint8Array): Promise<Uint8Array> => {\n const signature = await getXrpTxHash(message, wallet);\n // Buffer.from(_, \"hex\") silently truncates at the first non-hex char, so reject it up front.\n if (!signature || !/^(?:[0-9a-f]{2})+$/i.test(signature)) {\n throw new Error(\"Failed to sign transaction with XRP\");\n }\n return Buffer.from(signature, \"hex\");\n };\n\n return new KwilSigner(signer, walletPublicKey, \"xrpl\");\n}\n","import type { Store } from \"@idos-network/utils/store\";\nimport type { Wallet as NearWallet } from \"@near-wallet-selector/core\";\nimport type { Keypair as StellarKeypair } from \"@stellar/stellar-sdk\";\nimport type { Wallet as EthersWallet, JsonRpcSigner } from \"ethers\";\nimport type { KeyPair as NearKeyPair } from \"near-api-js\";\nimport type { KeyPair as XrpKeyPair } from \"ripple-keypairs/src/types\";\n\nimport { KwilSigner } from \"@idos-network/kwil-js\";\nimport { bs58Encode, hexDecode, hexEncode } from \"@idos-network/utils/codecs\";\nimport nacl from \"tweetnacl\";\n\nimport type { WalletType } from \"./actions\";\nimport type { KwilActionClient } from \"./create-kwil-client\";\n\nimport { FaceSignSignerProvider } from \"./facesign/facesign-signer\";\nimport {\n createNearWalletKwilSigner,\n implicitAddressFromPublicKey,\n looksLikeNearWallet,\n} from \"./near/create-near-wallet-kwil-signer\";\nimport { kwilNep413Signer } from \"./near/nep413\";\nimport { createXrpKwilSigner } from \"./xrp/signer\";\nimport { getXrpPublicKey, looksLikeXrpWallet } from \"./xrp/utils\";\n\nexport { KwilSigner } from \"@idos-network/kwil-js\";\nexport type Wallet =\n | EthersWallet\n | JsonRpcSigner\n | NearWallet\n | CustomKwilSigner\n | FaceSignSignerProvider;\n\n/**\n * Helper function to check if the given object is a `nacl.SignKeyPair`.\n */\nfunction isNaclSignKeyPair(object: unknown): object is nacl.SignKeyPair {\n return (\n object !== null &&\n typeof object === \"object\" &&\n \"publicKey\" in object &&\n object.publicKey instanceof Uint8Array &&\n object.publicKey.length === nacl.sign.publicKeyLength &&\n \"secretKey\" in object &&\n object.secretKey instanceof Uint8Array &&\n object.secretKey.length === nacl.sign.secretKeyLength\n );\n}\n\n/**\n * Helper function to check if the given object is a NEAR KeyPair.\n */\nfunction isNearKeyPair(object: unknown): object is NearKeyPair {\n return (\n object !== null &&\n typeof object === \"object\" &&\n \"getPublicKey\" in object &&\n \"sign\" in object &&\n typeof object.getPublicKey === \"function\" &&\n typeof object.sign === \"function\"\n );\n}\n\n/**\n * Helper function to check if the given object is a Stellar Keypair.\n */\nfunction isStellarKeyPair(object: unknown): object is StellarKeypair {\n return (\n object !== null &&\n typeof object === \"object\" &&\n \"publicKey\" in object &&\n \"sign\" in object &&\n \"canSign\" in object &&\n typeof object.publicKey === \"function\" &&\n typeof object.sign === \"function\" &&\n typeof object.canSign === \"function\"\n );\n}\n\nexport interface CustomKwilSigner extends KwilSigner {\n publicAddress: string;\n signatureType: string;\n publicKey: string;\n walletType: string;\n signMessage: (message: Uint8Array | string) => Promise<Uint8Array>;\n}\n\nfunction isCustomKwilSigner(object: unknown): object is CustomKwilSigner {\n return (\n object !== null &&\n typeof object === \"object\" &&\n \"publicAddress\" in object &&\n \"signatureType\" in object &&\n \"publicKey\" in object &&\n \"signMessage\" in object\n );\n}\n\n/**\n * Helper function to check if the given object is a XRP KeyPair (Server key pairs only).\n */\nfunction isXrplKeyPair(object: unknown): object is XrpKeyPair {\n return !!object && typeof object === \"object\" && \"privateKey\" in object && \"publicKey\" in object;\n}\n\nexport type KwilSignerType =\n | NearKeyPair\n | EthersWallet\n | nacl.SignKeyPair\n | JsonRpcSigner\n | StellarKeypair\n | XrpKeyPair;\n\nexport type SignerAddress = string;\nexport type SignerPublicKey = string | undefined;\n\n/**\n * Creates a `KwilSigner` and its associated `SignerAddress`.\n *\n * This function is explicitly marked as being for backend use only because it doesn't reset\n * the KGW cookie when logging out and re-logging in with a different wallet.\n */\nexport async function createServerKwilSigner(\n signer: KwilSignerType,\n): Promise<[KwilSigner, SignerAddress]> {\n if (isNaclSignKeyPair(signer)) {\n return [\n new KwilSigner(\n async (msg: Uint8Array) => nacl.sign.detached(msg, signer.secretKey),\n signer.publicKey,\n \"ed25519\",\n ),\n implicitAddressFromPublicKey(bs58Encode(signer.publicKey)),\n ];\n }\n\n if (isNearKeyPair(signer)) {\n const rawPublicKey = signer.getPublicKey().toString();\n const hexPublicKey = implicitAddressFromPublicKey(rawPublicKey);\n return [\n new KwilSigner(kwilNep413Signer(\"idos-issuer\")(signer), hexPublicKey, \"nep413\"),\n rawPublicKey,\n ];\n }\n\n if (isStellarKeyPair(signer)) {\n const publicKeyString = signer.publicKey();\n const rawPublicKey = signer.rawPublicKey();\n return [\n new KwilSigner(\n async (msg: Uint8Array) => signer.sign(Buffer.from(msg)),\n rawPublicKey,\n \"ed25519\",\n ),\n publicKeyString,\n ];\n }\n\n if (isXrplKeyPair(signer)) {\n let xrpKeypair: typeof import(\"ripple-keypairs\");\n\n try {\n xrpKeypair = await import(\"ripple-keypairs\");\n } catch (e) {\n throw new Error(\"Can't load ripple-keypairs\", { cause: e });\n }\n\n return [\n new KwilSigner(\n async (msg: Uint8Array) => hexDecode(xrpKeypair.sign(hexEncode(msg), signer.privateKey)),\n signer.publicKey,\n \"xrpl\",\n ),\n signer.publicKey,\n ];\n }\n\n if (\"address\" in signer) {\n return [new KwilSigner(signer, signer.address), signer.address];\n }\n\n // Force the check that `signer` is never.\n // If these lines start complaining, that means we're missing an `if` above.\n return ((_: never) => {\n throw new Error(\"Invalid `signer` type\");\n })(signer);\n}\n\nexport async function createClientKwilSigner(\n store: Store,\n kwilClient: KwilActionClient,\n wallet: Wallet,\n): Promise<[KwilSigner, SignerAddress, SignerPublicKey, WalletType]> {\n if (\"connect\" in wallet && \"address\" in wallet) {\n // oxlint-disable-next-line no-param-reassign -- Narrowing the type on purpose\n wallet = wallet as unknown as JsonRpcSigner;\n const currentAddress = await wallet.getAddress();\n\n const storedAddress = await store.get<string>(\"signer-address\");\n\n if (storedAddress !== currentAddress) {\n // To avoid re-using the old signer's kgw cookie.\n // When kwil-js supports multi cookies, we can remove this.\n store.set(\"signer-address\", currentAddress);\n try {\n await kwilClient.client.auth.logoutKGW();\n } catch (error) {\n console.log(\"error logoutKGW\", error);\n }\n }\n\n return [new KwilSigner(wallet, currentAddress), currentAddress, undefined, \"EVM\"];\n }\n\n if (looksLikeNearWallet(wallet)) {\n const accounts = await wallet.getAccounts();\n const { kwilSigner, publicKey } = await createNearWalletKwilSigner(\n wallet,\n accounts[0].accountId,\n store,\n kwilClient,\n );\n\n return [kwilSigner, accounts[0].accountId, publicKey, \"NEAR\"];\n }\n\n if (looksLikeXrpWallet(wallet)) {\n const { address: currentAddress, publicKey: walletPublicKey } = (await getXrpPublicKey(\n wallet,\n )) as { address: string; publicKey: string };\n if (!currentAddress) {\n throw new Error(\"Failed to get XRP address\");\n }\n\n return [\n await createXrpKwilSigner(wallet, currentAddress, store, kwilClient, walletPublicKey),\n currentAddress,\n walletPublicKey,\n \"XRPL\",\n ];\n }\n\n if (isCustomKwilSigner(wallet) || wallet instanceof FaceSignSignerProvider) {\n const storedAddress = await store.get<string>(\"signer-address\");\n\n if (storedAddress !== wallet.publicAddress) {\n store.set(\"signer-address\", wallet.publicAddress);\n try {\n await kwilClient.client.auth.logoutKGW();\n } catch (error) {\n console.log(\"error logoutKGW\", error);\n }\n }\n\n return [\n new KwilSigner(\n async (msg: Uint8Array) => wallet.signMessage(msg),\n wallet.publicAddress,\n \"ed25519\",\n ),\n wallet.publicAddress,\n wallet.publicKey,\n wallet.walletType as WalletType,\n ];\n }\n\n // Force the check that `signer` is `never`.\n // If these lines start complaining, that means we're missing an `if` above.\n return ((_: never) => {\n throw new Error(\"Invalid `signer` type\");\n })(wallet);\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { Ln as WalletType } from "../index-Bk8YCFlx.mjs";
1
+ import { rr as WalletType } from "../index-Dc_rffi1.mjs";
2
2
  //#region src/signature-verification/index.d.ts
3
3
  export interface WalletSignature {
4
4
  address: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@idos-network/kwil-infra",
3
- "version": "3.0.1",
3
+ "version": "5.0.0",
4
4
  "description": "Infrastructure and wallets for idOS",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -44,7 +44,7 @@
44
44
  },
45
45
  "dependencies": {
46
46
  "@idos-network/kwil-js": "0.2.2",
47
- "@idos-network/utils": "3.0.1",
47
+ "@idos-network/utils": "3.2.0",
48
48
  "tiny-invariant": "^1.3.3",
49
49
  "tweetnacl": "^1.0.3",
50
50
  "zod": "4.6.7"
@@ -3,6 +3,7 @@ import { describe, expect, it } from "vitest";
3
3
  import {
4
4
  addWalletMessage,
5
5
  CreatePreliminaryCredentialsByDwgInputSchema,
6
+ credentialBroaderMessage,
6
7
  getUser,
7
8
  SharePreliminaryCredentialInputSchema,
8
9
  UpsertWalletAsInserterInputSchema,
@@ -132,11 +133,11 @@ describe("SharePreliminaryCredentialInputSchema", () => {
132
133
  });
133
134
 
134
135
  describe("MM wallet type schemas", () => {
135
- it("accepts MM as a wallet type", () => {
136
+ it("accepts MM as a stored wallet type", () => {
136
137
  expect(walletTypeSchema.parse("MM")).toBe("MM");
137
138
  });
138
139
 
139
- it("accepts MM wallets created by trusted inserters", () => {
140
+ it("rejects MM wallets from inserters (MM operators create them)", () => {
140
141
  expect(() =>
141
142
  UpsertWalletAsInserterInputSchema.parse({
142
143
  id: "00000000-0000-4000-8000-000000000008",
@@ -144,15 +145,17 @@ describe("MM wallet type schemas", () => {
144
145
  address: "mm-signing-public-key",
145
146
  public_key: "mm-signing-public-key",
146
147
  wallet_type: "MM",
148
+ not_before: "2025-02-13T11:22:06Z",
149
+ not_after: "2025-02-13T11:37:06Z",
147
150
  signature: "",
148
151
  }),
149
- ).not.toThrow();
152
+ ).toThrow();
150
153
  });
151
154
  });
152
155
 
153
156
  const addWalletMessageInput = {
154
- address: "mm-signing-public-key",
155
- wallet_type: "MM" as const,
157
+ address: "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed",
158
+ wallet_type: "EVM" as const,
156
159
  user_id: "00000000-0000-4000-8000-000000000001",
157
160
  not_before: "2025-02-13T11:22:06Z",
158
161
  not_after: "2025-02-13T11:37:06Z",
@@ -178,6 +181,21 @@ describe("addWalletMessage", () => {
178
181
  });
179
182
  });
180
183
 
184
+ describe("credentialBroaderMessage", () => {
185
+ it("returns the message from the node", async () => {
186
+ await expect(
187
+ credentialBroaderMessage(
188
+ { call: async () => [{ message: "operation: credential" }] } as never,
189
+ {
190
+ public_notes_signature: "sig",
191
+ content_uri: "ipfs://cid",
192
+ recipient_wallet: "0xabc",
193
+ },
194
+ ),
195
+ ).resolves.toEqual({ message: "operation: credential" });
196
+ });
197
+ });
198
+
181
199
  describe("getUser", () => {
182
200
  it("throws an explicit not-found error when the view is empty", async () => {
183
201
  await expect(