From 46af901551139e858e18d92b26d8398a31b0b6e9 Mon Sep 17 00:00:00 2001 From: kyranjamie Date: Fri, 10 Jan 2025 17:58:14 +0100 Subject: [PATCH] feat(rpc): add sip-30 schemas/types feat(rpc): add deployContract feat(rpc): add profile, backwards compat stx_signTransaction --- packages/rpc/src/index.ts | 54 +++++++---- .../methods/{ => bitcoin}/send-transfer.ts | 2 +- .../src/methods/{ => bitcoin}/sign-message.ts | 4 +- .../src/methods/{ => bitcoin}/sign-psbt.ts | 2 +- .../rpc/src/methods/stacks/_stacks-helpers.ts | 97 +++++++++++++++++++ .../src/methods/stacks/stx-contract-call.ts | 32 ++++++ .../src/methods/stacks/stx-deploy-contract.ts | 32 ++++++ .../methods/{ => stacks}/stx-sign-message.ts | 2 +- .../methods/stacks/stx-sign-transaction.ts | 46 +++++++++ .../methods/stacks/stx-transfer-sip10-ft.ts | 32 ++++++ .../src/methods/stacks/stx-transfer-stx.ts | 32 ++++++ .../src/methods/stacks/stx-update-profile.ts | 31 ++++++ .../rpc/src/methods/stx-sign-transaction.ts | 30 ------ 13 files changed, 341 insertions(+), 55 deletions(-) rename packages/rpc/src/methods/{ => bitcoin}/send-transfer.ts (94%) rename packages/rpc/src/methods/{ => bitcoin}/sign-message.ts (87%) rename packages/rpc/src/methods/{ => bitcoin}/sign-psbt.ts (97%) create mode 100644 packages/rpc/src/methods/stacks/_stacks-helpers.ts create mode 100644 packages/rpc/src/methods/stacks/stx-contract-call.ts create mode 100644 packages/rpc/src/methods/stacks/stx-deploy-contract.ts rename packages/rpc/src/methods/{ => stacks}/stx-sign-message.ts (97%) create mode 100644 packages/rpc/src/methods/stacks/stx-sign-transaction.ts create mode 100644 packages/rpc/src/methods/stacks/stx-transfer-sip10-ft.ts create mode 100644 packages/rpc/src/methods/stacks/stx-transfer-stx.ts create mode 100644 packages/rpc/src/methods/stacks/stx-update-profile.ts delete mode 100644 packages/rpc/src/methods/stx-sign-transaction.ts diff --git a/packages/rpc/src/index.ts b/packages/rpc/src/index.ts index 88257e67c..20b864ae3 100644 --- a/packages/rpc/src/index.ts +++ b/packages/rpc/src/index.ts @@ -1,39 +1,53 @@ import { ValueOf } from '@leather.io/models'; +import { DefineSendTransferMethod } from './methods/bitcoin/send-transfer'; +import { DefineSignMessageMethod } from './methods/bitcoin/sign-message'; +import { DefineSignPsbtMethod } from './methods/bitcoin/sign-psbt'; import { DefineGetAddressesMethod } from './methods/get-addresses'; import { DefineGetInfoMethod } from './methods/get-info'; import { DefineOpenMethod } from './methods/open'; import { DefineOpenSwapMethod } from './methods/open-swap'; -import { DefineSendTransferMethod } from './methods/send-transfer'; -import { DefineSignMessageMethod } from './methods/sign-message'; -import { DefineSignPsbtMethod } from './methods/sign-psbt'; -import { DefineStxSignMessageMethod } from './methods/stx-sign-message'; -import { DefineStxSignTransactionMethod } from './methods/stx-sign-transaction'; +import { DefineStxCallContractMethod } from './methods/stacks/stx-contract-call'; +import { DefineStxDeployContractMethod } from './methods/stacks/stx-deploy-contract'; +import { DefineStxSignMessageMethod } from './methods/stacks/stx-sign-message'; +import { DefineStxSignTransactionMethod } from './methods/stacks/stx-sign-transaction'; +import { DefineStxTransferSip10FtMethod } from './methods/stacks/stx-transfer-sip10-ft'; +import { DefineStxTransferStxMethod } from './methods/stacks/stx-transfer-stx'; +import { DefineStxUpdateProfileMethod } from './methods/stacks/stx-update-profile'; import { DefineSupportedMethods } from './methods/supported-methods'; import { ExtractErrorResponse, ExtractSuccessResponse } from './rpc/schemas'; export * from './rpc/schemas'; export * from './methods/get-info'; -export * from './methods/sign-psbt'; +export * from './methods/bitcoin/sign-psbt'; export * from './methods/get-addresses'; -export * from './methods/send-transfer'; -export * from './methods/sign-message'; -export * from './methods/stx-sign-message'; -export * from './methods/stx-sign-transaction'; +export * from './methods/bitcoin/send-transfer'; +export * from './methods/bitcoin/sign-message'; +export * from './methods/stacks/stx-sign-message'; +export * from './methods/stacks/stx-sign-transaction'; export * from './methods/supported-methods'; export * from './methods/open'; export * from './methods/open-swap'; -export type LeatherRpcMethodMap = DefineGetInfoMethod & - DefineGetAddressesMethod & - DefineSignPsbtMethod & - DefineSignMessageMethod & - DefineSendTransferMethod & - DefineStxSignMessageMethod & - DefineStxSignTransactionMethod & - DefineOpenSwapMethod & - DefineOpenMethod & - DefineSupportedMethods; +export type LeatherRpcMethodMap = + // Chain agnostic + DefineGetInfoMethod & + DefineOpenMethod & + DefineSupportedMethods & + DefineGetAddressesMethod & + DefineOpenSwapMethod & + // Bitcoin + DefineSignPsbtMethod & + DefineSignMessageMethod & + DefineSendTransferMethod & + // Stacks + DefineStxSignMessageMethod & + DefineStxSignTransactionMethod & + DefineStxCallContractMethod & + DefineStxDeployContractMethod & + DefineStxTransferSip10FtMethod & + DefineStxTransferStxMethod & + DefineStxUpdateProfileMethod; export type RpcRequests = ValueOf['request']; diff --git a/packages/rpc/src/methods/send-transfer.ts b/packages/rpc/src/methods/bitcoin/send-transfer.ts similarity index 94% rename from packages/rpc/src/methods/send-transfer.ts rename to packages/rpc/src/methods/bitcoin/send-transfer.ts index 91ada91a5..756dfbd56 100644 --- a/packages/rpc/src/methods/send-transfer.ts +++ b/packages/rpc/src/methods/bitcoin/send-transfer.ts @@ -1,6 +1,6 @@ import { z } from 'zod'; -import { DefineRpcMethod, RpcRequest, RpcResponse } from '../rpc/schemas'; +import { DefineRpcMethod, RpcRequest, RpcResponse } from '../../rpc/schemas'; export const sendTransferRequestParamSchema = z.object({ account: z.number().optional(), diff --git a/packages/rpc/src/methods/sign-message.ts b/packages/rpc/src/methods/bitcoin/sign-message.ts similarity index 87% rename from packages/rpc/src/methods/sign-message.ts rename to packages/rpc/src/methods/bitcoin/sign-message.ts index 4268716dd..cb11facb6 100644 --- a/packages/rpc/src/methods/sign-message.ts +++ b/packages/rpc/src/methods/bitcoin/sign-message.ts @@ -1,7 +1,7 @@ import { AllowAdditionalProperties } from '@leather.io/models'; -import { DefineRpcMethod, RpcRequest, RpcResponse } from '../rpc/schemas'; -import { PaymentTypes } from './get-addresses'; +import { DefineRpcMethod, RpcRequest, RpcResponse } from '../../rpc/schemas'; +import { PaymentTypes } from '../get-addresses'; // Implements BIP-322 // https://github.com/bitcoin/bips/blob/master/bip-0322.mediawiki diff --git a/packages/rpc/src/methods/sign-psbt.ts b/packages/rpc/src/methods/bitcoin/sign-psbt.ts similarity index 97% rename from packages/rpc/src/methods/sign-psbt.ts rename to packages/rpc/src/methods/bitcoin/sign-psbt.ts index 01ff2465c..60107a6e7 100644 --- a/packages/rpc/src/methods/sign-psbt.ts +++ b/packages/rpc/src/methods/bitcoin/sign-psbt.ts @@ -1,6 +1,6 @@ import { DefaultNetworkConfigurations } from '@leather.io/models'; -import { DefineRpcMethod, RpcParameterByName, RpcRequest, RpcResponse } from '../rpc/schemas'; +import { DefineRpcMethod, RpcParameterByName, RpcRequest, RpcResponse } from '../../rpc/schemas'; /** * DEFAULT -- all inputs, all outputs diff --git a/packages/rpc/src/methods/stacks/_stacks-helpers.ts b/packages/rpc/src/methods/stacks/_stacks-helpers.ts new file mode 100644 index 000000000..9070f52ce --- /dev/null +++ b/packages/rpc/src/methods/stacks/_stacks-helpers.ts @@ -0,0 +1,97 @@ +import { z } from 'zod'; + +export const stacksTransactionDetailsSchema = z.object({ + txid: z.string(), + transaction: z.string(), +}); + +// Clarity values +export const cvIntSchema = z.object({ + type: z.literal('int'), + value: z.string(), // `bigint` compatible +}); + +export const cvUintSchema = z.object({ + type: z.literal('uint'), + value: z.string(), // `bigint` compatible +}); + +export const cvBufferSchema = z.object({ + type: z.literal('buffer'), + value: z.string(), // hex-encoded string +}); + +export const cvTrueSchema = z.object({ + type: z.literal('true'), +}); + +export const cvFalseSchema = z.object({ + type: z.literal('false'), +}); + +export const cvAddressSchema = z.object({ + type: z.literal('address'), + value: z.string(), // Stacks c32-encoded +}); + +export const cvContractSchema = z.object({ + type: z.literal('contract'), + value: z.string(), // Stacks c32-encoded, with contract name suffix +}); + +export const cvOkSchema = z.object({ + type: z.literal('ok'), + value: z.unknown(), // Clarity value +}); + +export const cvErrSchema = z.object({ + type: z.literal('err'), + value: z.unknown(), // Clarity value +}); + +export const cvNoneSchema = z.object({ + type: z.literal('none'), +}); + +export const cvSomeSchema = z.object({ + type: z.literal('some'), + value: z.unknown(), // Clarity value +}); + +export const cvListSchema = z.object({ + type: z.literal('list'), + value: z.array(z.unknown()), // Array of Clarity values +}); + +export const cvTupleSchema = z.object({ + type: z.literal('tuple'), + value: z.record(z.unknown()), // Record of Clarity values +}); + +export const cvAsciiSchema = z.object({ + type: z.literal('ascii'), + value: z.string(), // ASCII-compatible string +}); + +export const cvUtf8Schema = z.object({ + type: z.literal('utf8'), + value: z.string(), +}); + +export const clarityValueSchema = z.union([ + cvIntSchema, + cvUintSchema, + cvBufferSchema, + cvTrueSchema, + cvFalseSchema, + cvAddressSchema, + cvContractSchema, + cvOkSchema, + cvErrSchema, + cvNoneSchema, + cvSomeSchema, + cvListSchema, + cvTupleSchema, + cvAsciiSchema, + cvUtf8Schema, +]); diff --git a/packages/rpc/src/methods/stacks/stx-contract-call.ts b/packages/rpc/src/methods/stacks/stx-contract-call.ts new file mode 100644 index 000000000..0a37ec4c5 --- /dev/null +++ b/packages/rpc/src/methods/stacks/stx-contract-call.ts @@ -0,0 +1,32 @@ +import { z } from 'zod'; + +import { DefineRpcMethod, RpcRequest, RpcResponse } from '../../rpc/schemas'; +import { stacksTransactionDetailsSchema } from './_stacks-helpers'; + +export const stxCallContractMethodName = 'stx_callContract'; + +type StxCallContractRequestMethodName = typeof stxCallContractMethodName; + +// Request +export const stxCallContractRequestParamsSchema = z.object({ + contract: z.string(), + asset: z.string(), + amount: z.coerce.number(), +}); + +export type StxCallContractRequestParams = z.infer; + +export type StxCallContractRequest = RpcRequest< + StxCallContractRequestMethodName, + StxCallContractRequestParams +>; + +// Result +export const stxCallContractResponseBodySchema = stacksTransactionDetailsSchema; + +export type StxCallContractResponse = RpcResponse; + +export type DefineStxCallContractMethod = DefineRpcMethod< + StxCallContractRequest, + StxCallContractResponse +>; diff --git a/packages/rpc/src/methods/stacks/stx-deploy-contract.ts b/packages/rpc/src/methods/stacks/stx-deploy-contract.ts new file mode 100644 index 000000000..9eb1e5930 --- /dev/null +++ b/packages/rpc/src/methods/stacks/stx-deploy-contract.ts @@ -0,0 +1,32 @@ +import { z } from 'zod'; + +import { DefineRpcMethod, RpcRequest, RpcResponse } from '../../rpc/schemas'; +import { stacksTransactionDetailsSchema } from './_stacks-helpers'; + +export const stxDeployContractMethodName = 'stx_deployContract'; + +type StxDeployContractRequestMethodName = typeof stxDeployContractMethodName; + +// Request +export const stxDeployContractRequestParamsSchema = z.object({ + name: z.string(), + clarityCode: z.string(), + clarityVersion: z.coerce.number().optional(), +}); + +export type StxDeployContractRequestParams = z.infer; + +export type StxDeployContractRequest = RpcRequest< + StxDeployContractRequestMethodName, + StxDeployContractRequestParams +>; + +// Result +export const stxDeployContractResponseBodySchema = stacksTransactionDetailsSchema; + +export type StxDeployContractResponse = RpcResponse; + +export type DefineStxDeployContractMethod = DefineRpcMethod< + StxDeployContractRequest, + StxDeployContractResponse +>; diff --git a/packages/rpc/src/methods/stx-sign-message.ts b/packages/rpc/src/methods/stacks/stx-sign-message.ts similarity index 97% rename from packages/rpc/src/methods/stx-sign-message.ts rename to packages/rpc/src/methods/stacks/stx-sign-message.ts index 0df8392f2..a6d856169 100644 --- a/packages/rpc/src/methods/stx-sign-message.ts +++ b/packages/rpc/src/methods/stacks/stx-sign-message.ts @@ -1,4 +1,4 @@ -import { DefineRpcMethod, RpcParameterByName, RpcRequest, RpcResponse } from '../rpc/schemas'; +import { DefineRpcMethod, RpcParameterByName, RpcRequest, RpcResponse } from '../../rpc/schemas'; export const stxMessageSigningTypes = ['utf8', 'structured'] as const; diff --git a/packages/rpc/src/methods/stacks/stx-sign-transaction.ts b/packages/rpc/src/methods/stacks/stx-sign-transaction.ts new file mode 100644 index 000000000..c3441768f --- /dev/null +++ b/packages/rpc/src/methods/stacks/stx-sign-transaction.ts @@ -0,0 +1,46 @@ +import { z } from 'zod'; + +import { DefineRpcMethod, RpcRequest, RpcResponse } from '../../rpc/schemas'; + +export const stxSignTransactionMethodName = 'stx_signTransaction'; + +// Leather's RPC params prior to SIP-30 +// Developers should be warned away from this structure +export const stxSignTransactionRequestLeatherRpcParamsSchema = z.object({ + txHex: z.string(), + stxAddress: z.string().optional(), + attachment: z.string().optional(), + accountIndex: z.string().optional(), +}); + +// SIP-30 params +export const stxSignTransactionRequestSip30ParamsSchema = z.object({ transaction: z.string() }); + +export const stxSignTransactionRequestParamsSchema = z.union([ + stxSignTransactionRequestLeatherRpcParamsSchema, + stxSignTransactionRequestSip30ParamsSchema, +]); + +export type StxSignTransactionRequestParams = z.infer< + typeof stxSignTransactionRequestSip30ParamsSchema +>; + +// For backwards compatibility, we return the same data under both properties +export const stxSignTransactionResponseSchema = z.object({ + transaction: z.string(), + txHex: z.string(), +}); + +export type StxSignTransactionResponseBody = z.infer; + +export type StxSignTransactionRequest = RpcRequest< + typeof stxSignTransactionMethodName, + StxSignTransactionRequestParams +>; + +export type StxSignTransactionResponse = RpcResponse; + +export type DefineStxSignTransactionMethod = DefineRpcMethod< + StxSignTransactionRequest, + StxSignTransactionResponse +>; diff --git a/packages/rpc/src/methods/stacks/stx-transfer-sip10-ft.ts b/packages/rpc/src/methods/stacks/stx-transfer-sip10-ft.ts new file mode 100644 index 000000000..4f6a56f4e --- /dev/null +++ b/packages/rpc/src/methods/stacks/stx-transfer-sip10-ft.ts @@ -0,0 +1,32 @@ +import { z } from 'zod'; + +import { DefineRpcMethod, RpcRequest, RpcResponse } from '../../rpc/schemas'; +import { stacksTransactionDetailsSchema } from './_stacks-helpers'; + +export const stxTransferSip10FtMethodName = 'stx_transferSip10Ft'; + +type StxTransferSip10FtRequestMethodName = typeof stxTransferSip10FtMethodName; + +// Request +export const stxTransferSip10FtRequestParamsSchema = z.object({ + recipient: z.string(), + asset: z.string(), + amount: z.coerce.number(), +}); + +export type StxTransferSip10FtRequestParams = z.infer; + +export type StxTransferSip10FtRequest = RpcRequest< + StxTransferSip10FtRequestMethodName, + StxTransferSip10FtRequestParams +>; + +// Result +export const stxTransferSip10FtResponseBodySchema = stacksTransactionDetailsSchema; + +export type StxTransferSip10FtResponse = RpcResponse; + +export type DefineStxTransferSip10FtMethod = DefineRpcMethod< + StxTransferSip10FtRequest, + StxTransferSip10FtResponse +>; diff --git a/packages/rpc/src/methods/stacks/stx-transfer-stx.ts b/packages/rpc/src/methods/stacks/stx-transfer-stx.ts new file mode 100644 index 000000000..399519698 --- /dev/null +++ b/packages/rpc/src/methods/stacks/stx-transfer-stx.ts @@ -0,0 +1,32 @@ +import { z } from 'zod'; + +import { DefineRpcMethod, RpcRequest, RpcResponse } from '../../rpc/schemas'; +import { stacksTransactionDetailsSchema } from './_stacks-helpers'; + +export const stxTransferStxMethodName = 'stx_transferStx'; + +type StxTransferStxRequestMethodName = typeof stxTransferStxMethodName; + +// Request +export const stxTransferStxRequestParamsSchema = z.object({ + recipient: z.string(), + amount: z.number(), + memo: z.string().optional(), +}); + +export type StxTransferStxRequestParams = z.infer; + +export type StxTransferStxRequest = RpcRequest< + StxTransferStxRequestMethodName, + StxTransferStxRequestParams +>; + +// Result +export const stxTransferStxResponseBodySchema = stacksTransactionDetailsSchema; + +export type StxTransferStxResponse = RpcResponse; + +export type DefineStxTransferStxMethod = DefineRpcMethod< + StxTransferStxRequest, + StxTransferStxResponse +>; diff --git a/packages/rpc/src/methods/stacks/stx-update-profile.ts b/packages/rpc/src/methods/stacks/stx-update-profile.ts new file mode 100644 index 000000000..7814b4c37 --- /dev/null +++ b/packages/rpc/src/methods/stacks/stx-update-profile.ts @@ -0,0 +1,31 @@ +import { z } from 'zod'; + +import { DefineRpcMethod, RpcRequest, RpcResponse } from '../../rpc/schemas'; +import { stacksTransactionDetailsSchema } from './_stacks-helpers'; + +export const stxUpdateProfileMethodName = 'stx_updateProfile'; + +type StxUpdateProfileRequestMethodName = typeof stxUpdateProfileMethodName; + +// Request +export const stxUpdateProfileRequestParamsSchema = z.object({ + // schema.org/Person + person: z.object({}).passthrough(), +}); + +export type StxUpdateProfileRequestParams = z.infer; + +export type StxUpdateProfileRequest = RpcRequest< + StxUpdateProfileRequestMethodName, + StxUpdateProfileRequestParams +>; + +// Result +export const stxUpdateProfileResponseBodySchema = stacksTransactionDetailsSchema; + +export type StxUpdateProfileResponse = RpcResponse; + +export type DefineStxUpdateProfileMethod = DefineRpcMethod< + StxUpdateProfileRequest, + StxUpdateProfileResponse +>; diff --git a/packages/rpc/src/methods/stx-sign-transaction.ts b/packages/rpc/src/methods/stx-sign-transaction.ts deleted file mode 100644 index 85f4e5a5c..000000000 --- a/packages/rpc/src/methods/stx-sign-transaction.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { z } from 'zod'; - -import { DefineRpcMethod, RpcRequest, RpcResponse } from '../rpc/schemas'; - -export const stxSignTransactionMethodName = 'stx_signTransaction'; - -export const stxSignTransactionRequestParamsSchema = z.object({ - txHex: z.string(), - stxAddress: z.string().optional(), - attachment: z.string().optional(), - accountIndex: z.string().optional(), -}); - -export type StxSignTransactionRequestParams = z.infer; - -export const stxSignTransactionResponseSchema = z.object({ txHex: z.string() }); - -export type StxSignTransactionResponseBody = z.infer; - -export type StxSignTransactionRequest = RpcRequest< - typeof stxSignTransactionMethodName, - StxSignTransactionRequestParams ->; - -export type StxSignTransactionResponse = RpcResponse; - -export type DefineStxSignTransactionMethod = DefineRpcMethod< - StxSignTransactionRequest, - StxSignTransactionResponse ->;