From ccdca42e8b7d43f5d2388ede805c0aaf401d85a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduard=20Bardaj=C3=AD=20Puig?= Date: Sat, 22 Jun 2024 11:09:47 +0100 Subject: [PATCH 01/18] Add "build:watch" script --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 80bf0d6..35f3bb9 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "test": "jest", "build-debug": "webpack --mode development", "build": "npm run clean && tsup src/index.ts --format esm --dts", + "build:watch": "npm run clean && tsup src/index.ts --format esm --dts --watch", "clean": "rimraf dist", "lint": "prettier --write .", "prepare": "husky install" From a46560e74917926f71e73e305a941bef096707d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduard=20Bardaj=C3=AD=20Puig?= Date: Sat, 22 Jun 2024 11:10:09 +0100 Subject: [PATCH 02/18] Add getBalance method schema --- src/request/types/btcMethods.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/request/types/btcMethods.ts b/src/request/types/btcMethods.ts index 58c0811..9ce82d7 100644 --- a/src/request/types/btcMethods.ts +++ b/src/request/types/btcMethods.ts @@ -183,3 +183,24 @@ export type GetAccounts = MethodParamsAndResult< v.InferOutput, v.InferOutput >; + +// Get the balance of the current Bitcoin account. +export const getBalanceMethodName = 'getBalance'; +export const getBalanceParamsSchema = v.undefined(); +export const getBalanceResultSchema = v.object({ + /** + * The balance of the wallet in sats. + */ + balance: v.string(), +}); +export const getBalanceSchema = v.object({ + ...rpcRequestMessageSchema.entries, + ...v.object({ + method: v.literal(getBalanceMethodName), + id: v.string(), + }).entries, +}); +export type GetBalance = MethodParamsAndResult< + v.InferOutput, + v.InferOutput +>; From 5868953d68d9f194389356995d04f7f69c8fcaa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduard=20Bardaj=C3=AD=20Puig?= Date: Sat, 22 Jun 2024 19:42:20 +0100 Subject: [PATCH 03/18] Add access denied error code --- src/types.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/types.ts b/src/types.ts index 44ac597..5d2e051 100644 --- a/src/types.ts +++ b/src/types.ts @@ -96,6 +96,10 @@ export enum RpcErrorCode { * method is not supported for the address provided */ METHOD_NOT_SUPPORTED = -32001, + /** + * The client does not have permission to access the requested resource. + */ + ACCESS_DENIED = -32002, } export interface RpcError { From 8f4820e74b56b2cef45ea739a24fbaf904bdf66e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduard=20Bardaj=C3=AD=20Puig?= Date: Mon, 24 Jun 2024 10:43:28 +0100 Subject: [PATCH 04/18] Switch to bigint --- src/request/types/btcMethods.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/request/types/btcMethods.ts b/src/request/types/btcMethods.ts index 9ce82d7..2423119 100644 --- a/src/request/types/btcMethods.ts +++ b/src/request/types/btcMethods.ts @@ -191,7 +191,8 @@ export const getBalanceResultSchema = v.object({ /** * The balance of the wallet in sats. */ - balance: v.string(), + confirmedBalance: v.bigint(), + unconfirmedUtxosBalance: v.bigint(), }); export const getBalanceSchema = v.object({ ...rpcRequestMessageSchema.entries, From e61f2f55dd4345b6d06c1f8cfa72d2c44ded103d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduard=20Bardaj=C3=AD=20Puig?= Date: Mon, 24 Jun 2024 10:43:48 +0100 Subject: [PATCH 05/18] Add getBalance to BtcRequests --- src/request/types/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/request/types/index.ts b/src/request/types/index.ts index ce1314d..a90a3a0 100644 --- a/src/request/types/index.ts +++ b/src/request/types/index.ts @@ -1,6 +1,7 @@ import { GetAccounts, GetAddresses, + GetBalance, GetInfo, SendTransfer, SignMessage, @@ -45,6 +46,7 @@ export interface BtcRequests { getInfo: GetInfo; getAddresses: GetAddresses; getAccounts: GetAccounts; + getBalance: GetBalance; signMessage: SignMessage; sendTransfer: SendTransfer; signPsbt: SignPsbt; From ed04aa9945fee458fa39a41457647cff8ee07c28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduard=20Bardaj=C3=AD=20Puig?= Date: Tue, 25 Jun 2024 16:34:49 +0100 Subject: [PATCH 06/18] Add RPC response schemas --- src/request/index.ts | 42 +++++++++++++++++++++++++++++------------- src/types.ts | 23 +++++++++++++++++++---- 2 files changed, 48 insertions(+), 17 deletions(-) diff --git a/src/request/index.ts b/src/request/index.ts index c901dd6..5478e6f 100644 --- a/src/request/index.ts +++ b/src/request/index.ts @@ -1,6 +1,15 @@ import { getProviderById } from '../provider'; -import { RpcBase, RpcResult, RpcSuccessResponse } from '../types'; -import { Params, Requests } from './types'; +import { + RpcBase, + RpcError, + RpcErrorCode, + RpcResult, + RpcSuccessResponse, + rpcResponseMessageSchema, + rpcSuccessResponseMessageSchema, +} from '../types'; +import * as v from 'valibot'; +import { Params, Requests, Return } from './types'; export const request = async ( method: Method, @@ -20,23 +29,30 @@ export const request = async ( const response = await provider.request(method, params); - if (isRpcSuccessResponse(response)) { + const parseResult = v.safeParse(rpcResponseMessageSchema, response); + + if (!parseResult.success) { return { - status: 'success', - result: response.result, + status: 'error', + error: { + code: RpcErrorCode.INTERNAL_ERROR, + message: 'Received unknown response from provider.', + data: response, + }, }; } + const parsedResponse = parseResult.output; + if ('error' in parsedResponse) { + return { + status: 'error', + error: parsedResponse.error as RpcError, + }; + } return { - status: 'error', - error: response.error, + status: 'success', + result: parsedResponse.result as Return, }; }; -const isRpcSuccessResponse = ( - response: RpcBase -): response is RpcSuccessResponse => { - return Object.hasOwn(response, 'result') && !!(response as RpcSuccessResponse).result; -}; - export * from './types'; diff --git a/src/types.ts b/src/types.ts index 5d2e051..1d3215e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -26,6 +26,8 @@ export interface RequestOptions { // RPC Request and Response types +export const RpcIdSchema = v.optional(v.union([v.string(), v.number(), v.null()])); +export type RpcId = v.InferOutput; export const rpcRequestMessageSchema = v.object({ jsonrpc: v.literal('2.0'), method: v.string(), @@ -40,13 +42,10 @@ export const rpcRequestMessageSchema = v.object({ v.null(), ]) ), - id: v.optional(v.union([v.string(), v.number(), v.null()])), + id: RpcIdSchema, }); - export type RpcRequestMessage = v.InferOutput; -export type RpcId = string | null; - export interface RpcBase { jsonrpc: '2.0'; id: RpcId; @@ -102,6 +101,22 @@ export enum RpcErrorCode { ACCESS_DENIED = -32002, } +export const rpcSuccessResponseMessageSchema = v.object({ + jsonrpc: v.literal('2.0'), + result: v.unknown(), + id: RpcIdSchema, +}); + +export const rpcErrorResponseMessageSchema = v.object({ + jsonrpc: v.literal('2.0'), + error: v.unknown(), + id: RpcIdSchema, +}); +export const rpcResponseMessageSchema = v.union([ + rpcSuccessResponseMessageSchema, + rpcErrorResponseMessageSchema, +]); + export interface RpcError { code: number | RpcErrorCode; message: string; From b7729fde8d6a90f0d89573b80892df354fb50d3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduard=20Bardaj=C3=AD=20Puig?= Date: Tue, 25 Jun 2024 16:44:52 +0100 Subject: [PATCH 07/18] Update getBalance result schema --- src/request/types/btcMethods.ts | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/request/types/btcMethods.ts b/src/request/types/btcMethods.ts index 2423119..494ad72 100644 --- a/src/request/types/btcMethods.ts +++ b/src/request/types/btcMethods.ts @@ -189,10 +189,20 @@ export const getBalanceMethodName = 'getBalance'; export const getBalanceParamsSchema = v.undefined(); export const getBalanceResultSchema = v.object({ /** - * The balance of the wallet in sats. + * The confirmed balance of the wallet in sats. */ - confirmedBalance: v.bigint(), - unconfirmedUtxosBalance: v.bigint(), + confirmed: v.bigint(), + + /** + * The unconfirmed balance of the wallet in sats. + */ + unconfirmed: v.bigint(), + + /** + * The total balance (both confirmed and unconfrimed UTXOs) of the wallet in + * sats. + */ + total: v.bigint(), }); export const getBalanceSchema = v.object({ ...rpcRequestMessageSchema.entries, From fd0a4c75c6d85f85c1363919021adfe446d43bdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduard=20Bardaj=C3=AD=20Puig?= Date: Wed, 26 Jun 2024 15:15:10 +0100 Subject: [PATCH 08/18] Set result and error to non-optional --- src/request/index.ts | 31 +++++++++++++----------------- src/request/types/walletMethods.ts | 4 ++-- src/types.ts | 7 +++++-- 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/request/index.ts b/src/request/index.ts index 5478e6f..708f704 100644 --- a/src/request/index.ts +++ b/src/request/index.ts @@ -1,11 +1,8 @@ import { getProviderById } from '../provider'; import { - RpcBase, - RpcError, RpcErrorCode, RpcResult, - RpcSuccessResponse, - rpcResponseMessageSchema, + rpcErrorResponseMessageSchema, rpcSuccessResponseMessageSchema, } from '../types'; import * as v from 'valibot'; @@ -29,29 +26,27 @@ export const request = async ( const response = await provider.request(method, params); - const parseResult = v.safeParse(rpcResponseMessageSchema, response); - - if (!parseResult.success) { + if (v.is(rpcErrorResponseMessageSchema, response)) { return { status: 'error', - error: { - code: RpcErrorCode.INTERNAL_ERROR, - message: 'Received unknown response from provider.', - data: response, - }, + error: response.error, }; } - const parsedResponse = parseResult.output; - if ('error' in parsedResponse) { + if (v.is(rpcSuccessResponseMessageSchema, response)) { return { - status: 'error', - error: parsedResponse.error as RpcError, + status: 'success', + result: response.result as Return, }; } + return { - status: 'success', - result: parsedResponse.result as Return, + status: 'error', + error: { + code: RpcErrorCode.INTERNAL_ERROR, + message: 'Received unknown response from provider.', + data: response, + }, }; }; diff --git a/src/request/types/walletMethods.ts b/src/request/types/walletMethods.ts index b29f457..4d4f291 100644 --- a/src/request/types/walletMethods.ts +++ b/src/request/types/walletMethods.ts @@ -3,7 +3,7 @@ import * as v from 'valibot'; export const connectMethodName = 'wallet_connect'; export const connectParamsSchema = v.undefined(); -export const connectResultSchema = v.undefined(); +export const connectResultSchema = v.literal(true); export const connectSchema = v.object({ ...rpcRequestMessageSchema.entries, ...v.object({ @@ -19,7 +19,7 @@ export type Connect = MethodParamsAndResult< export const disconnectMethodName = 'wallet_disconnect'; export const disconnectParamsSchema = v.undefined(); -export const disconnectResultSchema = v.undefined(); +export const disconnectResultSchema = v.literal(true); export const disconnectSchema = v.object({ ...rpcRequestMessageSchema.entries, ...v.object({ diff --git a/src/types.ts b/src/types.ts index 1d3215e..176487f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -103,19 +103,22 @@ export enum RpcErrorCode { export const rpcSuccessResponseMessageSchema = v.object({ jsonrpc: v.literal('2.0'), - result: v.unknown(), + result: v.nonOptional(v.unknown()), id: RpcIdSchema, }); +export type RpcSuccessResponseMessage = v.InferOutput; export const rpcErrorResponseMessageSchema = v.object({ jsonrpc: v.literal('2.0'), - error: v.unknown(), + error: v.nonOptional(v.unknown()), id: RpcIdSchema, }); +export type RpcErrorResponseMessage = v.InferOutput; export const rpcResponseMessageSchema = v.union([ rpcSuccessResponseMessageSchema, rpcErrorResponseMessageSchema, ]); +export type RpcResponseMessage = v.InferOutput; export interface RpcError { code: number | RpcErrorCode; From f18a3a3b67b445bb9720274f4f4d60af3ca6d46e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduard=20Bardaj=C3=AD=20Puig?= Date: Wed, 26 Jun 2024 15:31:48 +0100 Subject: [PATCH 09/18] Update types --- src/request/types/btcMethods.ts | 2 +- src/request/types/index.ts | 1 + src/request/types/runesMethods.ts | 40 +++++++++++++++++++++---------- 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/request/types/btcMethods.ts b/src/request/types/btcMethods.ts index 494ad72..d971965 100644 --- a/src/request/types/btcMethods.ts +++ b/src/request/types/btcMethods.ts @@ -204,7 +204,7 @@ export const getBalanceResultSchema = v.object({ */ total: v.bigint(), }); -export const getBalanceSchema = v.object({ +export const getBalanceRequestMessageSchema = v.object({ ...rpcRequestMessageSchema.entries, ...v.object({ method: v.literal(getBalanceMethodName), diff --git a/src/request/types/index.ts b/src/request/types/index.ts index a90a3a0..ed4e7dd 100644 --- a/src/request/types/index.ts +++ b/src/request/types/index.ts @@ -80,3 +80,4 @@ export type Params = Method extends keyof Requests ? Requests[Method]['p export * from './stxMethods'; export * from './btcMethods'; export * from './walletMethods'; +export * from './runesMethods'; diff --git a/src/request/types/runesMethods.ts b/src/request/types/runesMethods.ts index 6103d21..affd295 100644 --- a/src/request/types/runesMethods.ts +++ b/src/request/types/runesMethods.ts @@ -9,7 +9,8 @@ import { RBFOrderRequest, RBFOrderResponse, } from '../../runes/types'; -import { BitcoinNetworkType, MethodParamsAndResult } from '../../types'; +import { BitcoinNetworkType, MethodParamsAndResult, rpcRequestMessageSchema } from '../../types'; +import * as v from 'valibot'; export interface EstimateRunesMintParams extends EstimateMintOrderRequest { network?: BitcoinNetworkType; @@ -81,15 +82,28 @@ interface RbfOrderResult { export type RbfOrder = MethodParamsAndResult; -type GetRunesBalanceParams = null; -interface GetRunesBalanceResult { - balances: { - runeName: string; - amount: string; - divisibility: number; - symbol: string; - inscriptionId: string | null; - }[]; -} - -export type GetRunesBalance = MethodParamsAndResult; +export const getRunesBalanceMethodName = 'getRunesBalance'; +export const getRunesBalanceParamsSchema = v.null(); +export const getRunesBalanceResultSchema = v.object({ + balances: v.array( + v.object({ + runeName: v.string(), + amount: v.string(), + divisibility: v.number(), + symbol: v.string(), + inscriptionId: v.nullish(v.string()), + }) + ), +}); +export const getRunesBalanceRequestMessageSchema = v.object({ + ...rpcRequestMessageSchema.entries, + ...v.object({ + method: v.literal(getRunesBalanceMethodName), + params: getRunesBalanceParamsSchema, + id: v.string(), + }).entries, +}); +export type GetRunesBalance = MethodParamsAndResult< + v.InferOutput, + v.InferOutput +>; From 596a6e1016b04fb1141bf8879950395ca91bd474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduard=20Bardaj=C3=AD=20Puig?= Date: Wed, 26 Jun 2024 17:15:17 +0100 Subject: [PATCH 10/18] Use string instead of bigint --- src/request/types/btcMethods.ts | 17 +++++++++++------ src/request/types/walletMethods.ts | 4 ++-- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/request/types/btcMethods.ts b/src/request/types/btcMethods.ts index d971965..580772a 100644 --- a/src/request/types/btcMethods.ts +++ b/src/request/types/btcMethods.ts @@ -189,20 +189,25 @@ export const getBalanceMethodName = 'getBalance'; export const getBalanceParamsSchema = v.undefined(); export const getBalanceResultSchema = v.object({ /** - * The confirmed balance of the wallet in sats. + * The confirmed balance of the wallet in sats. Using a string due to chrome + * messages not supporting bigint + * (https://issues.chromium.org/issues/40116184). */ - confirmed: v.bigint(), + confirmed: v.string(), /** - * The unconfirmed balance of the wallet in sats. + * The unconfirmed balance of the wallet in sats. Using a string due to chrome + * messages not supporting bigint + * (https://issues.chromium.org/issues/40116184). */ - unconfirmed: v.bigint(), + unconfirmed: v.string(), /** * The total balance (both confirmed and unconfrimed UTXOs) of the wallet in - * sats. + * sats. Using a string due to chrome messages not supporting bigint + * (https://issues.chromium.org/issues/40116184). */ - total: v.bigint(), + total: v.string(), }); export const getBalanceRequestMessageSchema = v.object({ ...rpcRequestMessageSchema.entries, diff --git a/src/request/types/walletMethods.ts b/src/request/types/walletMethods.ts index 4d4f291..c6b6684 100644 --- a/src/request/types/walletMethods.ts +++ b/src/request/types/walletMethods.ts @@ -4,7 +4,7 @@ import * as v from 'valibot'; export const connectMethodName = 'wallet_connect'; export const connectParamsSchema = v.undefined(); export const connectResultSchema = v.literal(true); -export const connectSchema = v.object({ +export const connectRequestMessageSchema = v.object({ ...rpcRequestMessageSchema.entries, ...v.object({ method: v.literal(connectMethodName), @@ -20,7 +20,7 @@ export type Connect = MethodParamsAndResult< export const disconnectMethodName = 'wallet_disconnect'; export const disconnectParamsSchema = v.undefined(); export const disconnectResultSchema = v.literal(true); -export const disconnectSchema = v.object({ +export const disconnectRequestMessageSchema = v.object({ ...rpcRequestMessageSchema.entries, ...v.object({ method: v.literal(disconnectMethodName), From c6e299d0bf932524c26867a57f08d5e9450f6e47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduard=20Bardaj=C3=AD=20Puig?= Date: Thu, 27 Jun 2024 09:09:48 +0100 Subject: [PATCH 11/18] Rename method names --- src/request/types/index.ts | 6 ++--- src/request/types/walletMethods.ts | 36 +++++++++++++++--------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/request/types/index.ts b/src/request/types/index.ts index ed4e7dd..83ffc6f 100644 --- a/src/request/types/index.ts +++ b/src/request/types/index.ts @@ -27,7 +27,7 @@ import { StxSignTransaction, StxTransferStx, } from './stxMethods'; -import { Connect, Disconnect } from './walletMethods'; +import { RequestPermissions, RenouncePermissions } from './walletMethods'; export interface StxRequests { stx_callContract: StxCallContract; @@ -68,8 +68,8 @@ export interface RunesRequests { export type RunesRequestMethod = keyof RunesRequests; export interface WalletMethods { - wallet_connect: Connect; - wallet_disconnect: Disconnect; + wallet_requestPermissions: RequestPermissions; + wallet_renouncePermissions: RenouncePermissions; } export type Requests = BtcRequests & StxRequests & RunesRequests & WalletMethods; diff --git a/src/request/types/walletMethods.ts b/src/request/types/walletMethods.ts index c6b6684..5fffc50 100644 --- a/src/request/types/walletMethods.ts +++ b/src/request/types/walletMethods.ts @@ -1,34 +1,34 @@ import { MethodParamsAndResult, rpcRequestMessageSchema } from '../../types'; import * as v from 'valibot'; -export const connectMethodName = 'wallet_connect'; -export const connectParamsSchema = v.undefined(); -export const connectResultSchema = v.literal(true); -export const connectRequestMessageSchema = v.object({ +export const requestPermissionsMethodName = 'wallet_requestPermissions'; +export const requestPermissionsParamsSchema = v.undefined(); +export const requestPermissionsResultSchema = v.literal(true); +export const requestPermissionsRequestMessageSchema = v.object({ ...rpcRequestMessageSchema.entries, ...v.object({ - method: v.literal(connectMethodName), - params: connectParamsSchema, + method: v.literal(requestPermissionsMethodName), + params: requestPermissionsParamsSchema, id: v.string(), }).entries, }); -export type Connect = MethodParamsAndResult< - v.InferOutput, - v.InferOutput +export type RequestPermissions = MethodParamsAndResult< + v.InferOutput, + v.InferOutput >; -export const disconnectMethodName = 'wallet_disconnect'; -export const disconnectParamsSchema = v.undefined(); -export const disconnectResultSchema = v.literal(true); -export const disconnectRequestMessageSchema = v.object({ +export const renouncePermissionsMethodName = 'wallet_renouncePermissions'; +export const renouncePermissionsParamsSchema = v.undefined(); +export const renouncePermissionsResultSchema = v.literal(true); +export const renouncePermissionsRequestMessageSchema = v.object({ ...rpcRequestMessageSchema.entries, ...v.object({ - method: v.literal(disconnectMethodName), - params: disconnectParamsSchema, + method: v.literal(renouncePermissionsMethodName), + params: renouncePermissionsParamsSchema, id: v.string(), }).entries, }); -export type Disconnect = MethodParamsAndResult< - v.InferOutput, - v.InferOutput +export type RenouncePermissions = MethodParamsAndResult< + v.InferOutput, + v.InferOutput >; From 50e2375f915fa604656b963b098838fec4d080ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduard=20Bardaj=C3=AD=20Puig?= Date: Thu, 27 Jun 2024 11:45:49 +0100 Subject: [PATCH 12/18] Fix method name --- src/request/types/runesMethods.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/request/types/runesMethods.ts b/src/request/types/runesMethods.ts index affd295..c7dec5a 100644 --- a/src/request/types/runesMethods.ts +++ b/src/request/types/runesMethods.ts @@ -82,7 +82,7 @@ interface RbfOrderResult { export type RbfOrder = MethodParamsAndResult; -export const getRunesBalanceMethodName = 'getRunesBalance'; +export const getRunesBalanceMethodName = 'runes_getBalance'; export const getRunesBalanceParamsSchema = v.null(); export const getRunesBalanceResultSchema = v.object({ balances: v.array( From b63ecc84be33d7660e7c1ec70787f3a61fa5c166 Mon Sep 17 00:00:00 2001 From: Mahmoud Aboelenein Date: Fri, 28 Jun 2024 08:29:44 +0300 Subject: [PATCH 13/18] added getInscriptions request --- src/provider/types.ts | 3 +- src/request/types/index.ts | 10 +++- src/request/types/ordinalsMethods.ts | 75 ++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 src/request/types/ordinalsMethods.ts diff --git a/src/provider/types.ts b/src/provider/types.ts index 2e24076..376d191 100644 --- a/src/provider/types.ts +++ b/src/provider/types.ts @@ -1,5 +1,6 @@ import { BtcRequestMethod, + OrdinalsRequestMethod, Params, Requests, RunesRequestMethod, @@ -46,7 +47,7 @@ export interface Provider { mozillaAddOnsUrl?: string; googlePlayStoreUrl?: string; iOSAppStoreUrl?: string; - methods?: (StxRequestMethod | BtcRequestMethod | RunesRequestMethod)[]; + methods?: (StxRequestMethod | BtcRequestMethod | RunesRequestMethod | OrdinalsRequestMethod)[]; } export interface SupportedWallet extends Provider { diff --git a/src/request/types/index.ts b/src/request/types/index.ts index ed4e7dd..166b18e 100644 --- a/src/request/types/index.ts +++ b/src/request/types/index.ts @@ -7,6 +7,7 @@ import { SignMessage, SignPsbt, } from './btcMethods'; +import { GetInscriptions } from './ordinalsMethods'; import { EstimateRbfOrder, EstimateRunesEtch, @@ -67,12 +68,18 @@ export interface RunesRequests { export type RunesRequestMethod = keyof RunesRequests; +export interface OrdinalsRequests { + ord_getInscriptions: GetInscriptions; +} + +export type OrdinalsRequestMethod = keyof OrdinalsRequests; + export interface WalletMethods { wallet_connect: Connect; wallet_disconnect: Disconnect; } -export type Requests = BtcRequests & StxRequests & RunesRequests & WalletMethods; +export type Requests = BtcRequests & StxRequests & RunesRequests & WalletMethods & OrdinalsRequests; export type Return = Method extends keyof Requests ? Requests[Method]['result'] : never; export type Params = Method extends keyof Requests ? Requests[Method]['params'] : never; @@ -81,3 +88,4 @@ export * from './stxMethods'; export * from './btcMethods'; export * from './walletMethods'; export * from './runesMethods'; +export * from './ordinalsMethods'; diff --git a/src/request/types/ordinalsMethods.ts b/src/request/types/ordinalsMethods.ts new file mode 100644 index 0000000..733396b --- /dev/null +++ b/src/request/types/ordinalsMethods.ts @@ -0,0 +1,75 @@ +import { MethodParamsAndResult, rpcRequestMessageSchema } from '../../types'; +import * as v from 'valibot'; + +export const getInscriptionsMethodName = 'ord_getInscriptions'; +export const getInscriptionsParamsSchema = v.object({ + offset: v.number(), + limit: v.number(), +}); +export const getInscriptionsResultSchema = v.object({ + inscriptions: v.array( + v.object({ + inscriptionId: v.string(), + inscriptionNumber: v.string(), + address: v.string(), + collectionName: v.optional(v.string()), + postage: v.string(), + contentLength: v.string(), + contentType: v.string(), + timestamp: v.number(), + offset: v.number(), + genesisTransaction: v.string(), + output: v.string(), + }) + ), +}); +export const getInscriptionsSchema = v.object({ + ...rpcRequestMessageSchema.entries, + ...v.object({ + method: v.literal(getInscriptionsMethodName), + params: getInscriptionsParamsSchema, + id: v.string(), + }).entries, +}); + +export type GetInscriptions = MethodParamsAndResult< + v.InferOutput, + v.InferOutput +>; + +// export type Inscription = { +// // the id of inscription. +// inscriptionId: string; +// // the number of inscription. +// inscriptionNumber: string; +// // the address of inscription. +// address: string; +// collectionName: string; +// // the size of the inscription’s parent UTXO +// postage: string; +// // the content url of inscription. +// content: string; +// // the content length of inscription. +// contentLength: string; +// // the content type of inscription. +// contentType: number; +// // the blocktime of inscription. +// timestamp: number; +// // the offset of inscription. +// offset: number; +// // the txid of genesis transaction +// genesisTransaction: string; +// // the txid and vout of current location +// output: string; +// }; + +// type GetInscriptionsParams = { +// offset: number; +// limit: number; +// }; + +// interface GetInscriptionsResult { +// inscriptions: Inscription[]; +// } + +// export type GetInscriptions = MethodParamsAndResult; From aa11706d2cc3fb0f335cec3b88b29bd6c956af39 Mon Sep 17 00:00:00 2001 From: Mahmoud Aboelenein Date: Fri, 28 Jun 2024 08:31:03 +0300 Subject: [PATCH 14/18] remove comments --- src/request/types/ordinalsMethods.ts | 37 ---------------------------- 1 file changed, 37 deletions(-) diff --git a/src/request/types/ordinalsMethods.ts b/src/request/types/ordinalsMethods.ts index 733396b..f75461f 100644 --- a/src/request/types/ordinalsMethods.ts +++ b/src/request/types/ordinalsMethods.ts @@ -36,40 +36,3 @@ export type GetInscriptions = MethodParamsAndResult< v.InferOutput, v.InferOutput >; - -// export type Inscription = { -// // the id of inscription. -// inscriptionId: string; -// // the number of inscription. -// inscriptionNumber: string; -// // the address of inscription. -// address: string; -// collectionName: string; -// // the size of the inscription’s parent UTXO -// postage: string; -// // the content url of inscription. -// content: string; -// // the content length of inscription. -// contentLength: string; -// // the content type of inscription. -// contentType: number; -// // the blocktime of inscription. -// timestamp: number; -// // the offset of inscription. -// offset: number; -// // the txid of genesis transaction -// genesisTransaction: string; -// // the txid and vout of current location -// output: string; -// }; - -// type GetInscriptionsParams = { -// offset: number; -// limit: number; -// }; - -// interface GetInscriptionsResult { -// inscriptions: Inscription[]; -// } - -// export type GetInscriptions = MethodParamsAndResult; From 0c1380c13f2e738b2e6fceb2ce7394c75a616fd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduard=20Bardaj=C3=AD=20Puig?= Date: Mon, 1 Jul 2024 11:16:35 +0100 Subject: [PATCH 15/18] Use same address definition for Stacks --- src/request/types/index.ts | 78 +++++++++++---------------------- src/request/types/stxMethods.ts | 35 ++++++++++++--- 2 files changed, 54 insertions(+), 59 deletions(-) diff --git a/src/request/types/index.ts b/src/request/types/index.ts index 07b8122..419e970 100644 --- a/src/request/types/index.ts +++ b/src/request/types/index.ts @@ -1,69 +1,43 @@ -import { - GetAccounts, - GetAddresses, - GetBalance, - GetInfo, - SendTransfer, - SignMessage, - SignPsbt, -} from './btcMethods'; +import type * as BtcMethods from './btcMethods'; import { GetInscriptions } from './ordinalsMethods'; -import { - EstimateRbfOrder, - EstimateRunesEtch, - EstimateRunesMint, - EtchRunes, - GetOrder, - GetRunesBalance, - MintRunes, - RbfOrder, -} from './runesMethods'; -import { - StxCallContract, - StxDeployContract, - StxGetAccounts, - StxGetAddresses, - StxSignStructuredMessage, - StxSignStxMessage, - StxSignTransaction, - StxTransferStx, -} from './stxMethods'; +import type * as RunesMethods from './runesMethods'; +import type * as StxMethods from './stxMethods'; import { RequestPermissions, RenouncePermissions } from './walletMethods'; export interface StxRequests { - stx_callContract: StxCallContract; - stx_deployContract: StxDeployContract; - stx_getAccounts: StxGetAccounts; - stx_getAddresses: StxGetAddresses; - stx_signMessage: StxSignStxMessage; - stx_signStructuredMessage: StxSignStructuredMessage; - stx_signTransaction: StxSignTransaction; - stx_transferStx: StxTransferStx; + stx_callContract: StxMethods.StxCallContract; + stx_deployContract: StxMethods.StxDeployContract; + stx_getAccounts: StxMethods.StxGetAccounts; + stx_getAddresses: StxMethods.StxGetAddresses; + stx_signMessage: StxMethods.StxSignStxMessage; + stx_signStructuredMessage: StxMethods.StxSignStructuredMessage; + stx_signTransaction: StxMethods.StxSignTransaction; + stx_transferStx: StxMethods.StxTransferStx; } export type StxRequestMethod = keyof StxRequests; export interface BtcRequests { - getInfo: GetInfo; - getAddresses: GetAddresses; - getAccounts: GetAccounts; - getBalance: GetBalance; - signMessage: SignMessage; - sendTransfer: SendTransfer; - signPsbt: SignPsbt; + getInfo: BtcMethods.GetInfo; + getAddresses: BtcMethods.GetAddresses; + getAccounts: BtcMethods.GetAccounts; + getBalance: BtcMethods.GetBalance; + signMessage: BtcMethods.SignMessage; + sendTransfer: BtcMethods.SendTransfer; + signPsbt: BtcMethods.SignPsbt; } export type BtcRequestMethod = keyof BtcRequests; export interface RunesRequests { - runes_estimateMint: EstimateRunesMint; - runes_mint: MintRunes; - runes_estimateEtch: EstimateRunesEtch; - runes_etch: EtchRunes; - runes_getOrder: GetOrder; - runes_estimateRbfOrder: EstimateRbfOrder; - runes_rbfOrder: RbfOrder; - runes_getBalance: GetRunesBalance; + runes_estimateMint: RunesMethods.EstimateRunesMint; + runes_mint: RunesMethods.MintRunes; + runes_estimateEtch: RunesMethods.EstimateRunesEtch; + runes_etch: RunesMethods.EtchRunes; + runes_getOrder: RunesMethods.GetOrder; + runes_estimateRbfOrder: RunesMethods.EstimateRbfOrder; + runes_rbfOrder: RunesMethods.RbfOrder; + runes_getBalance: RunesMethods.GetRunesBalance; } export type RunesRequestMethod = keyof RunesRequests; diff --git a/src/request/types/stxMethods.ts b/src/request/types/stxMethods.ts index 2f31186..a3ac066 100644 --- a/src/request/types/stxMethods.ts +++ b/src/request/types/stxMethods.ts @@ -1,4 +1,6 @@ -import { MethodParamsAndResult } from '../../types'; +import { addressSchema } from 'src/addresses'; +import { MethodParamsAndResult, rpcRequestMessageSchema } from '../../types'; +import * as v from 'valibot'; interface Pubkey { /** @@ -252,12 +254,31 @@ export type GetAccountsResult = { }; export type StxGetAccounts = MethodParamsAndResult<{}, GetAccountsResult>; -// Types for `stx_getAddresses` request -export type GetAddressesParams = undefined | null; -export type GetAddressesResult = { - addresses: Array
; -}; -export type StxGetAddresses = MethodParamsAndResult; +export const stxGetAddressesMethodName = 'stx_getAddresses'; +export const stxGetAddressesParamsSchema = v.object({ + /** + * A message to be displayed to the user in the request prompt. + */ + message: v.optional(v.string()), +}); +export const stxGetAddressesResultSchema = v.object({ + /** + * The addresses generated for the given purposes. + */ + addresses: v.array(addressSchema), +}); +export const stxGetAddressesRequestMessageSchema = v.object({ + ...rpcRequestMessageSchema.entries, + ...v.object({ + method: v.literal(stxGetAddressesMethodName), + params: stxGetAddressesParamsSchema, + id: v.string(), + }).entries, +}); +export type StxGetAddresses = MethodParamsAndResult< + v.InferOutput, + v.InferOutput +>; // Types for `stx_signTransaction` request export type SignTransactionParams = Transaction & Partial; From de448c5206ba8fa7da900046e9f49b3d3ad3a125 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduard=20Bardaj=C3=AD=20Puig?= Date: Mon, 1 Jul 2024 13:00:07 +0100 Subject: [PATCH 16/18] Support nullish param --- src/request/types/stxMethods.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/request/types/stxMethods.ts b/src/request/types/stxMethods.ts index a3ac066..591398b 100644 --- a/src/request/types/stxMethods.ts +++ b/src/request/types/stxMethods.ts @@ -255,12 +255,14 @@ export type GetAccountsResult = { export type StxGetAccounts = MethodParamsAndResult<{}, GetAccountsResult>; export const stxGetAddressesMethodName = 'stx_getAddresses'; -export const stxGetAddressesParamsSchema = v.object({ - /** - * A message to be displayed to the user in the request prompt. - */ - message: v.optional(v.string()), -}); +export const stxGetAddressesParamsSchema = v.nullish( + v.object({ + /** + * A message to be displayed to the user in the request prompt. + */ + message: v.optional(v.string()), + }) +); export const stxGetAddressesResultSchema = v.object({ /** * The addresses generated for the given purposes. From daca9f618960a75580fda49a471bbfbded18d850 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduard=20Bardaj=C3=AD=20Puig?= Date: Mon, 1 Jul 2024 14:47:48 +0100 Subject: [PATCH 17/18] Add more types --- src/request/types/btcMethods.ts | 18 +++++++++++++++--- src/request/types/runesMethods.ts | 7 ++++++- src/request/types/stxMethods.ts | 9 +++++++-- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/request/types/btcMethods.ts b/src/request/types/btcMethods.ts index 580772a..53ec675 100644 --- a/src/request/types/btcMethods.ts +++ b/src/request/types/btcMethods.ts @@ -7,7 +7,8 @@ import { MethodParamsAndResult, rpcRequestMessageSchema } from '../../types'; import * as v from 'valibot'; export const getInfoMethodName = 'getInfo'; -export const getInfoParamsSchema = v.null(); +export const getInfoParamsSchema = v.nullish(v.null()); +export type GetInfoParams = v.InferOutput; export const getInfoResultSchema = v.object({ /** * Version of the wallet. @@ -24,7 +25,8 @@ export const getInfoResultSchema = v.object({ */ supports: v.array(v.string()), }); -export const getInfoSchema = v.object({ +export type GetInfoResult = v.InferOutput; +export const getInfoRequestMessageSchema = v.object({ ...rpcRequestMessageSchema.entries, ...v.object({ method: v.literal(getInfoMethodName), @@ -32,6 +34,7 @@ export const getInfoSchema = v.object({ id: v.string(), }).entries, }); +export type GetInfoRequestMessage = v.InferOutput; export type GetInfo = MethodParamsAndResult< v.InferOutput, v.InferOutput @@ -49,12 +52,14 @@ export const getAddressesParamsSchema = v.object({ */ message: v.optional(v.string()), }); +export type GetAddressesParams = v.InferOutput; export const getAddressesResultSchema = v.object({ /** * The addresses generated for the given purposes. */ addresses: v.array(addressSchema), }); +export type GetAddressesResult = v.InferOutput; export const getAddressesRequestMessageSchema = v.object({ ...rpcRequestMessageSchema.entries, ...v.object({ @@ -63,6 +68,7 @@ export const getAddressesRequestMessageSchema = v.object({ id: v.string(), }).entries, }); +export type GetAddressesRequestMessage = v.InferOutput; export type GetAddresses = MethodParamsAndResult< v.InferOutput, v.InferOutput @@ -79,6 +85,7 @@ export const signMessageParamsSchema = v.object({ **/ message: v.string(), }); +export type SignMessageParams = v.InferOutput; export const signMessageResultSchema = v.object({ /** * The signature of the message. @@ -93,6 +100,7 @@ export const signMessageResultSchema = v.object({ */ address: v.string(), }); +export type SignMessageResult = v.InferOutput; export const signMessageRequestMessageSchema = v.object({ ...rpcRequestMessageSchema.entries, ...v.object({ @@ -101,6 +109,7 @@ export const signMessageRequestMessageSchema = v.object({ id: v.string(), }).entries, }); +export type SignMessageRequestMessage = v.InferOutput; export type SignMessage = MethodParamsAndResult< v.InferOutput, v.InferOutput @@ -170,7 +179,9 @@ export type SignPsbt = MethodParamsAndResult; export const getAccountsMethodName = 'getAccounts'; export const getAccountsParamsSchema = getAddressesParamsSchema; +export type GetAccountsParams = v.InferOutput; export const getAccountsResultSchema = v.array(addressSchema); +export type GetAccountsResult = v.InferOutput; export const getAccountsRequestMessageSchema = v.object({ ...rpcRequestMessageSchema.entries, ...v.object({ @@ -179,6 +190,7 @@ export const getAccountsRequestMessageSchema = v.object({ id: v.string(), }).entries, }); +export type GetAccountsRequestMessage = v.InferOutput; export type GetAccounts = MethodParamsAndResult< v.InferOutput, v.InferOutput @@ -186,7 +198,7 @@ export type GetAccounts = MethodParamsAndResult< // Get the balance of the current Bitcoin account. export const getBalanceMethodName = 'getBalance'; -export const getBalanceParamsSchema = v.undefined(); +export const getBalanceParamsSchema = v.nullish(v.null()); export const getBalanceResultSchema = v.object({ /** * The confirmed balance of the wallet in sats. Using a string due to chrome diff --git a/src/request/types/runesMethods.ts b/src/request/types/runesMethods.ts index c7dec5a..91061e6 100644 --- a/src/request/types/runesMethods.ts +++ b/src/request/types/runesMethods.ts @@ -83,7 +83,8 @@ interface RbfOrderResult { export type RbfOrder = MethodParamsAndResult; export const getRunesBalanceMethodName = 'runes_getBalance'; -export const getRunesBalanceParamsSchema = v.null(); +export const getRunesBalanceParamsSchema = v.nullish(v.null()); +export type GetRunesBalanceParams = v.InferOutput; export const getRunesBalanceResultSchema = v.object({ balances: v.array( v.object({ @@ -95,6 +96,7 @@ export const getRunesBalanceResultSchema = v.object({ }) ), }); +export type GetRunesBalanceResult = v.InferOutput; export const getRunesBalanceRequestMessageSchema = v.object({ ...rpcRequestMessageSchema.entries, ...v.object({ @@ -103,6 +105,9 @@ export const getRunesBalanceRequestMessageSchema = v.object({ id: v.string(), }).entries, }); +export type GetRunesBalanceRequestMessage = v.InferOutput< + typeof getRunesBalanceRequestMessageSchema +>; export type GetRunesBalance = MethodParamsAndResult< v.InferOutput, v.InferOutput diff --git a/src/request/types/stxMethods.ts b/src/request/types/stxMethods.ts index 591398b..2309d99 100644 --- a/src/request/types/stxMethods.ts +++ b/src/request/types/stxMethods.ts @@ -249,10 +249,10 @@ export type DeployContractResult = TxId & Transaction; export type StxDeployContract = MethodParamsAndResult; // Types for `stx_getAccounts` request -export type GetAccountsResult = { +export type StxGetAccountsResult = { addresses: Array
; }; -export type StxGetAccounts = MethodParamsAndResult<{}, GetAccountsResult>; +export type StxGetAccounts = MethodParamsAndResult<{}, StxGetAccountsResult>; export const stxGetAddressesMethodName = 'stx_getAddresses'; export const stxGetAddressesParamsSchema = v.nullish( @@ -263,12 +263,14 @@ export const stxGetAddressesParamsSchema = v.nullish( message: v.optional(v.string()), }) ); +export type StxGetAddressesParams = v.InferOutput; export const stxGetAddressesResultSchema = v.object({ /** * The addresses generated for the given purposes. */ addresses: v.array(addressSchema), }); +export type StxGetAddressesResult = v.InferOutput; export const stxGetAddressesRequestMessageSchema = v.object({ ...rpcRequestMessageSchema.entries, ...v.object({ @@ -277,6 +279,9 @@ export const stxGetAddressesRequestMessageSchema = v.object({ id: v.string(), }).entries, }); +export type StxGetAddressesRequestMessage = v.InferOutput< + typeof stxGetAddressesRequestMessageSchema +>; export type StxGetAddresses = MethodParamsAndResult< v.InferOutput, v.InferOutput From be8ef483643cb0917a381689c6ecd8b43eebb1e1 Mon Sep 17 00:00:00 2001 From: Den <36603049+dhriaznov@users.noreply.github.com> Date: Mon, 1 Jul 2024 15:58:31 +0200 Subject: [PATCH 18/18] Revert "Revert "Add message schema validators"" --- package-lock.json | 31 ++++-- package.json | 5 +- src/addresses/types.ts | 14 +-- src/request/types/btcMethods.ts | 151 ++++++++++++++++++----------- src/request/types/index.ts | 9 +- src/request/types/walletMethods.ts | 34 +++++++ src/types.ts | 20 ++++ 7 files changed, 193 insertions(+), 71 deletions(-) create mode 100644 src/request/types/walletMethods.ts diff --git a/package-lock.json b/package-lock.json index 4ef1a68..a7b88ba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,11 +27,14 @@ "ts-jest": "^29.0.5", "ts-loader": "^9.4.1", "tsup": "^8.0.2", - "typescript": "^4.9.4", + "typescript": "5.4.5", "util": "^0.12.4", "vm-browserify": "^1.1.2", "webpack": "^5.74.0", "webpack-cli": "^4.10.0" + }, + "peerDependencies": { + "valibot": "0.33.2" } }, "node_modules/@ampproject/remapping": { @@ -6794,16 +6797,16 @@ } }, "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } }, "node_modules/update-browserslist-db": { @@ -6882,6 +6885,12 @@ "dev": true, "peer": true }, + "node_modules/valibot": { + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/valibot/-/valibot-0.33.2.tgz", + "integrity": "sha512-ZpFWuI+bs5+PP66q4zVFn4e4t/s5jmMw5iPBZmGUoi8iQqXyU9YY/BLCAyk62Z/bNS8qdUNBEyx52952qdqW3w==", + "peer": true + }, "node_modules/vm-browserify": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", @@ -12040,9 +12049,9 @@ "peer": true }, "typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "dev": true }, "update-browserslist-db": { @@ -12104,6 +12113,12 @@ } } }, + "valibot": { + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/valibot/-/valibot-0.33.2.tgz", + "integrity": "sha512-ZpFWuI+bs5+PP66q4zVFn4e4t/s5jmMw5iPBZmGUoi8iQqXyU9YY/BLCAyk62Z/bNS8qdUNBEyx52952qdqW3w==", + "peer": true + }, "vm-browserify": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", diff --git a/package.json b/package.json index 57e1342..80bf0d6 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,9 @@ "jsontokens": "4.0.1", "lodash.omit": "4.5.0" }, + "peerDependencies": { + "valibot": "0.33.2" + }, "devDependencies": { "@types/jest": "^29.2.6", "@types/lodash.omit": "4.5.9", @@ -42,7 +45,7 @@ "ts-jest": "^29.0.5", "ts-loader": "^9.4.1", "tsup": "^8.0.2", - "typescript": "^4.9.4", + "typescript": "5.4.5", "util": "^0.12.4", "vm-browserify": "^1.1.2", "webpack": "^5.74.0", diff --git a/src/addresses/types.ts b/src/addresses/types.ts index 5b18e18..7501e01 100644 --- a/src/addresses/types.ts +++ b/src/addresses/types.ts @@ -1,3 +1,4 @@ +import * as v from 'valibot'; import type { RequestOptions, RequestPayload } from '../types'; export enum AddressPurpose { @@ -20,12 +21,13 @@ export enum AddressType { stacks = 'stacks', } -export interface Address { - address: string; - publicKey: string; - purpose?: AddressPurpose; - addressType?: AddressType; -} +export const addressSchema = v.object({ + address: v.string(), + publicKey: v.string(), + purpose: v.enum(AddressPurpose), + addressType: v.enum(AddressType), +}); +export type Address = v.InferOutput; export interface GetAddressResponse { addresses: Address[]; diff --git a/src/request/types/btcMethods.ts b/src/request/types/btcMethods.ts index 7499985..58c0811 100644 --- a/src/request/types/btcMethods.ts +++ b/src/request/types/btcMethods.ts @@ -2,65 +2,109 @@ * Represents the types and interfaces related to BTC methods. */ -import { Address, AddressPurpose } from '../../addresses'; -import { MethodParamsAndResult } from '../../types'; +import { AddressPurpose, addressSchema } from '../../addresses'; +import { MethodParamsAndResult, rpcRequestMessageSchema } from '../../types'; +import * as v from 'valibot'; -type GetInfoResult = { - version: number | string; - methods?: Array; - supports?: Array; -}; +export const getInfoMethodName = 'getInfo'; +export const getInfoParamsSchema = v.null(); +export const getInfoResultSchema = v.object({ + /** + * Version of the wallet. + */ + version: v.string(), -export type GetInfo = MethodParamsAndResult; + /** + * [WBIP](https://wbips.netlify.app/wbips/WBIP002) methods supported by the wallet. + */ + methods: v.optional(v.array(v.string())), -type GetAddressesParams = { /** - * The purposes for which to generate addresses. - * possible values are "payment", "ordinals", ... + * List of WBIP standards supported by the wallet. Not currently used. + */ + supports: v.array(v.string()), +}); +export const getInfoSchema = v.object({ + ...rpcRequestMessageSchema.entries, + ...v.object({ + method: v.literal(getInfoMethodName), + params: getInfoParamsSchema, + id: v.string(), + }).entries, +}); +export type GetInfo = MethodParamsAndResult< + v.InferOutput, + v.InferOutput +>; + +export const getAddressesMethodName = 'getAddresses'; +export const getAddressesParamsSchema = v.object({ + /** + * The purposes for which to generate addresses. See + * {@linkcode AddressPurpose} for available purposes. */ - purposes: Array; + purposes: v.array(v.enum(AddressPurpose)), /** - * a message to be displayed to the user in the request prompt. + * A message to be displayed to the user in the request prompt. */ - message?: string; -}; - -/** - * The addresses generated for the given purposes. - */ -type GetAddressesResult = { - addresses: Array
; -}; - -export type GetAddresses = MethodParamsAndResult; - -export type SignMessageParams = { + message: v.optional(v.string()), +}); +export const getAddressesResultSchema = v.object({ + /** + * The addresses generated for the given purposes. + */ + addresses: v.array(addressSchema), +}); +export const getAddressesRequestMessageSchema = v.object({ + ...rpcRequestMessageSchema.entries, + ...v.object({ + method: v.literal(getAddressesMethodName), + params: getAddressesParamsSchema, + id: v.string(), + }).entries, +}); +export type GetAddresses = MethodParamsAndResult< + v.InferOutput, + v.InferOutput +>; + +export const signMessageMethodName = 'signMessage'; +export const signMessageParamsSchema = v.object({ /** * The address used for signing. **/ - address: string; + address: v.string(), /** * The message to sign. **/ - message: string; -}; - -type SignMessageResult = { + message: v.string(), +}); +export const signMessageResultSchema = v.object({ /** * The signature of the message. */ - signature: string; + signature: v.string(), /** * hash of the message. */ - messageHash: string; + messageHash: v.string(), /** * The address used for signing. */ - address: string; -}; - -export type SignMessage = MethodParamsAndResult; + address: v.string(), +}); +export const signMessageRequestMessageSchema = v.object({ + ...rpcRequestMessageSchema.entries, + ...v.object({ + method: v.literal(signMessageMethodName), + params: signMessageParamsSchema, + id: v.string(), + }).entries, +}); +export type SignMessage = MethodParamsAndResult< + v.InferOutput, + v.InferOutput +>; type Recipient = { /** @@ -124,21 +168,18 @@ export type SignPsbtResult = { export type SignPsbt = MethodParamsAndResult; -export type GetAccountsParams = { - /** - * The purposes for which to generate addresses. - * possible values are "payment", "ordinals", ... - */ - purposes: Array; - /** - * a message to be displayed to the user in the request prompt. - */ - /** - * a message to be displayed to the user in the request prompt. - */ - message?: string; -}; - -export type GetAccountResult = Address[]; - -export type GetAccounts = MethodParamsAndResult; +export const getAccountsMethodName = 'getAccounts'; +export const getAccountsParamsSchema = getAddressesParamsSchema; +export const getAccountsResultSchema = v.array(addressSchema); +export const getAccountsRequestMessageSchema = v.object({ + ...rpcRequestMessageSchema.entries, + ...v.object({ + method: v.literal(getAccountsMethodName), + params: getAccountsParamsSchema, + id: v.string(), + }).entries, +}); +export type GetAccounts = MethodParamsAndResult< + v.InferOutput, + v.InferOutput +>; diff --git a/src/request/types/index.ts b/src/request/types/index.ts index 202feef..ce1314d 100644 --- a/src/request/types/index.ts +++ b/src/request/types/index.ts @@ -26,6 +26,7 @@ import { StxSignTransaction, StxTransferStx, } from './stxMethods'; +import { Connect, Disconnect } from './walletMethods'; export interface StxRequests { stx_callContract: StxCallContract; @@ -64,10 +65,16 @@ export interface RunesRequests { export type RunesRequestMethod = keyof RunesRequests; -export type Requests = BtcRequests & StxRequests & RunesRequests; +export interface WalletMethods { + wallet_connect: Connect; + wallet_disconnect: Disconnect; +} + +export type Requests = BtcRequests & StxRequests & RunesRequests & WalletMethods; export type Return = Method extends keyof Requests ? Requests[Method]['result'] : never; export type Params = Method extends keyof Requests ? Requests[Method]['params'] : never; export * from './stxMethods'; export * from './btcMethods'; +export * from './walletMethods'; diff --git a/src/request/types/walletMethods.ts b/src/request/types/walletMethods.ts new file mode 100644 index 0000000..b29f457 --- /dev/null +++ b/src/request/types/walletMethods.ts @@ -0,0 +1,34 @@ +import { MethodParamsAndResult, rpcRequestMessageSchema } from '../../types'; +import * as v from 'valibot'; + +export const connectMethodName = 'wallet_connect'; +export const connectParamsSchema = v.undefined(); +export const connectResultSchema = v.undefined(); +export const connectSchema = v.object({ + ...rpcRequestMessageSchema.entries, + ...v.object({ + method: v.literal(connectMethodName), + params: connectParamsSchema, + id: v.string(), + }).entries, +}); +export type Connect = MethodParamsAndResult< + v.InferOutput, + v.InferOutput +>; + +export const disconnectMethodName = 'wallet_disconnect'; +export const disconnectParamsSchema = v.undefined(); +export const disconnectResultSchema = v.undefined(); +export const disconnectSchema = v.object({ + ...rpcRequestMessageSchema.entries, + ...v.object({ + method: v.literal(disconnectMethodName), + params: disconnectParamsSchema, + id: v.string(), + }).entries, +}); +export type Disconnect = MethodParamsAndResult< + v.InferOutput, + v.InferOutput +>; diff --git a/src/types.ts b/src/types.ts index 2b97a2e..44ac597 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,3 +1,4 @@ +import * as v from 'valibot'; import type { BitcoinProvider } from './provider'; import { Requests, Return } from './request'; @@ -25,6 +26,25 @@ export interface RequestOptions { // RPC Request and Response types +export const rpcRequestMessageSchema = v.object({ + jsonrpc: v.literal('2.0'), + method: v.string(), + params: v.optional( + v.union([ + v.array(v.unknown()), + v.looseObject({}), + // Note: This is to support current incorrect usage of RPC 2.0. Params need + // to be either an array or an object when provided. Changing this now would + // be a breaking change, so accepting null values for now. Tracking in + // https://linear.app/xverseapp/issue/ENG-4538. + v.null(), + ]) + ), + id: v.optional(v.union([v.string(), v.number(), v.null()])), +}); + +export type RpcRequestMessage = v.InferOutput; + export type RpcId = string | null; export interface RpcBase {