Skip to content

Commit

Permalink
feat: added sendtransaction method and types
Browse files Browse the repository at this point in the history
  • Loading branch information
andreabadesso committed Feb 12, 2025
1 parent 5fcf239 commit a05531d
Show file tree
Hide file tree
Showing 5 changed files with 212 additions and 5 deletions.
1 change: 1 addition & 0 deletions packages/hathor-rpc-handler/src/rpcMethods/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export * from './signWithAddress';
export * from './getConnectedNetwork';
export * from './signOracleData';
export * from './createToken';
export * from './sendTransaction';
137 changes: 137 additions & 0 deletions packages/hathor-rpc-handler/src/rpcMethods/sendTransaction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/**
* Copyright (c) Hathor Labs and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import { z } from 'zod';
import type { HathorWallet } from '@hathor/wallet-lib';
import {
TriggerTypes,
PinConfirmationPrompt,
PinRequestResponse,
TriggerHandler,
RequestMetadata,
SendTransactionRpcRequest,
SendTransactionConfirmationPrompt,
SendTransactionConfirmationResponse,
SendTransactionLoadingTrigger,
SendTransactionLoadingFinishedTrigger,
RpcResponseTypes,
RpcResponse,
RpcMethods,
} from '../types';
import { PromptRejectedError, InvalidParamsError } from '../errors';
import { validateNetwork } from '../helpers';

const sendTransactionSchema = z.object({
method: z.literal(RpcMethods.SendTransaction),
params: z.object({
network: z.string().min(1),
outputs: z.array(z.object({
address: z.string().optional(),
value: z.number().positive(),
token: z.string().optional(),
type: z.string().optional(),
data: z.array(z.string()).optional(),
})).min(1),
inputs: z.array(z.object({
txId: z.string(),
index: z.number().nonnegative(),
})).optional(),
changeAddress: z.string().optional(),
}),
});

/**
* Handles the 'htr_sendTransaction' RPC request by prompting the user for confirmation
* and sending the transaction if confirmed.
*
* @param rpcRequest - The RPC request object containing the transaction details.
* @param wallet - The Hathor wallet instance used to send the transaction.
* @param requestMetadata - Metadata related to the dApp that sent the RPC
* @param promptHandler - The function to handle prompting the user for confirmation.
*
* @returns The transaction details if successful.
*
* @throws {PromptRejectedError} If the user rejects any of the prompts.
* @throws {InvalidParamsError} If the request parameters are invalid.
*/
export async function sendTransaction(
rpcRequest: SendTransactionRpcRequest,
wallet: HathorWallet,
requestMetadata: RequestMetadata,
promptHandler: TriggerHandler,
) {
try {
const validatedRequest = sendTransactionSchema.parse(rpcRequest);
const { params } = validatedRequest;

validateNetwork(wallet, params.network);

const prompt: SendTransactionConfirmationPrompt = {
type: TriggerTypes.SendTransactionConfirmationPrompt,
method: rpcRequest.method,
data: {
outputs: params.outputs,
inputs: params.inputs,
changeAddress: params.changeAddress,
}
};

const sendResponse = await promptHandler(prompt, requestMetadata) as SendTransactionConfirmationResponse;

if (!sendResponse.data.accepted) {
throw new PromptRejectedError('User rejected send transaction prompt');
}

const pinPrompt: PinConfirmationPrompt = {
type: TriggerTypes.PinConfirmationPrompt,
method: rpcRequest.method,
};

const pinResponse = await promptHandler(pinPrompt, requestMetadata) as PinRequestResponse;

if (!pinResponse.data.accepted) {
throw new PromptRejectedError('User rejected PIN prompt');
}

const loadingTrigger: SendTransactionLoadingTrigger = {
type: TriggerTypes.SendTransactionLoadingTrigger,
};
promptHandler(loadingTrigger, requestMetadata);

try {
const response = await wallet.sendManyOutputsTransaction(
params.outputs,
{
inputs: params.inputs,
changeAddress: params.changeAddress,
pinCode: pinResponse.data.pinCode,
}
);

const loadingFinishedTrigger: SendTransactionLoadingFinishedTrigger = {
type: TriggerTypes.SendTransactionLoadingFinishedTrigger,
};
promptHandler(loadingFinishedTrigger, requestMetadata);

return {
type: RpcResponseTypes.SendTransactionResponse,
response,
} as RpcResponse;
} catch (err) {
if (err instanceof Error) {
throw new Error(err.message);
} else {
throw new Error('An unknown error occurred while sending the transaction');
}
}
} catch (err) {
if (err instanceof z.ZodError) {
throw new InvalidParamsError(err.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', '));
}
throw err;
}
}
45 changes: 43 additions & 2 deletions packages/hathor-rpc-handler/src/types/prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ export enum TriggerTypes {
CreateTokenConfirmationPrompt,
CreateTokenLoadingTrigger,
SignOracleDataConfirmationPrompt,
SendTransactionConfirmationPrompt,
SendTransactionLoadingTrigger,
SendTransactionLoadingFinishedTrigger,
}

export enum TriggerResponseTypes {
Expand All @@ -37,6 +40,7 @@ export enum TriggerResponseTypes {
SendNanoContractTxConfirmationResponse,
CreateTokenConfirmationResponse,
SignOracleDataConfirmationResponse,
SendTransactionConfirmationResponse,
}

export type Trigger =
Expand All @@ -57,7 +61,10 @@ export type Trigger =
| CreateTokenConfirmationPrompt
| CreateTokenLoadingTrigger
| CreateTokenLoadingFinishedTrigger
| SignOracleDataConfirmationPrompt;
| SignOracleDataConfirmationPrompt
| SendTransactionConfirmationPrompt
| SendTransactionLoadingTrigger
| SendTransactionLoadingFinishedTrigger;

export interface BaseLoadingTrigger {
type: TriggerTypes;
Expand Down Expand Up @@ -236,14 +243,40 @@ export interface SignOracleDataConfirmationResponse {
data: boolean;
}

export interface SendTransactionConfirmationPrompt extends BaseConfirmationPrompt {
type: TriggerTypes.SendTransactionConfirmationPrompt;
data: {
outputs: Array<{
address?: string;
value: number;
token?: string;
type?: string;
data?: string[];
}>;
inputs?: Array<{
txId: string;
index: number;
}>;
changeAddress?: string;
}
}

export interface SendTransactionConfirmationResponse {
type: TriggerResponseTypes.SendTransactionConfirmationResponse;
data: {
accepted: boolean;
}
}

export type TriggerResponse =
AddressRequestClientResponse
| GetUtxosConfirmationResponse
| PinRequestResponse
| SignMessageWithAddressConfirmationResponse
| SendNanoContractTxConfirmationResponse
| CreateTokenConfirmationResponse
| SignOracleDataConfirmationResponse;
| SignOracleDataConfirmationResponse
| SendTransactionConfirmationResponse;

export type TriggerHandler = (prompt: Trigger, requestMetadata: RequestMetadata) => Promise<TriggerResponse | void>;

Expand All @@ -264,3 +297,11 @@ export interface UtxoDetails {
total_utxos_locked: number;
utxos: UtxoInfo[];
}

export interface SendTransactionLoadingTrigger extends BaseLoadingTrigger {
type: TriggerTypes.SendTransactionLoadingTrigger;
}

export interface SendTransactionLoadingFinishedTrigger extends BaseLoadingTrigger {
type: TriggerTypes.SendTransactionLoadingFinishedTrigger;
}
23 changes: 22 additions & 1 deletion packages/hathor-rpc-handler/src/types/rpcRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export enum RpcMethods {
GetOperationStatus = 'htr_getOperationStatus',
SendNanoContractTx = 'htr_sendNanoContractTx',
SignOracleData = 'htr_signOracleData',
SendTransaction = 'htr_sendTransaction',
}

export interface CreateTokenRpcRequest {
Expand Down Expand Up @@ -104,6 +105,25 @@ export interface SendNanoContractRpcRequest {
}
}

export interface SendTransactionRpcRequest {
method: RpcMethods.SendTransaction,
params: {
network: string;
outputs: Array<{
address?: string;
value: number;
token?: string;
type?: string;
data?: string[];
}>;
inputs?: Array<{
txId: string;
index: number;
}>;
changeAddress?: string;
}
}

export type RequestMetadata = {
[key: string]: string,
};
Expand All @@ -124,5 +144,6 @@ export type RpcRequest = GetAddressRpcRequest
| SendNanoContractRpcRequest
| GetConnectedNetworkRpcRequest
| GenericRpcRequest
| SignOracleDataRpcRequest;
| SignOracleDataRpcRequest
| SendTransactionRpcRequest;

11 changes: 9 additions & 2 deletions packages/hathor-rpc-handler/src/types/rpcResponse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ export enum RpcResponseTypes {
GetConnectedNetworkResponse,
GetUtxosResponse,
CreateTokenResponse,
SignOracleDataResponse
SignOracleDataResponse,
SendTransactionResponse,
}

export interface BaseRpcResponse {
Expand Down Expand Up @@ -76,11 +77,17 @@ export interface GetUtxosResponse extends BaseRpcResponse {
response: UtxoDetails[];
}

export interface SendTransactionResponse extends BaseRpcResponse {
type: RpcResponseTypes.SendTransactionResponse;
response: SendTransaction;
}

export type RpcResponse = GetAddressResponse
| SendNanoContractTxResponse
| SignWithAddressResponse
| GetBalanceResponse
| GetConnectedNetworkResponse
| CreateTokenResponse
| SignOracleDataResponse
| GetUtxosResponse;
| GetUtxosResponse
| SendTransactionResponse;

0 comments on commit a05531d

Please sign in to comment.