// Operations for hardware security module (HSM) management
import { z } from "zod";
import { getHsmApi } from "../common/client";
import {
CurvegridResourceNotFoundError,
CurvegridError,
} from "../common/errors";
// Schema for listing HSM wallets
export const ListHsmWalletsSchema = z.object({
limit: z
.number()
.optional()
.describe("Maximum number of HSM wallets to return"),
offset: z.number().optional().describe("Offset for pagination"),
});
// Schema for getting HSM wallet details
export const GetHsmWalletSchema = z.object({
address: z.string().describe("HSM wallet address"),
});
// Schema for creating an HSM key
export const CreateHsmWalletSchema = z.object({
keyName: z.string().describe("Name of the key"),
vaultName: z.string().describe("Name of the key vault"),
clientId: z.string().describe("Client ID"),
useHardwareModule: z
.boolean()
.default(false)
.describe("Whether to use a hardware module"),
});
// Schema for signing data with HSM
export const SignMessageSchema = z.object({
address: z.string().describe("HSM wallet address"),
data: z.string().describe("Data to sign (hex format)"),
});
// Schema for signing and submitting a transaction
/*
gas: number;
from: string;
value: string;
data: string;
type: number;
nonce?: number;
gasPrice?: string;
gasFeeCap?: string;
gasTipCap?: string;
to?: string | null;
hash?: string;
**/
export const SignAndSubmitTransactionSchema = z.object({
tx: z.object({
gas: z.number().describe("Gas limit for the transaction"),
from: z.string().describe("Address of the signer to use"),
value: z.string().describe("Transaction value in wei"),
data: z.string().describe("Transaction data (hex format)"),
type: z.number().describe("Transaction type"),
nonce: z.number().optional().describe("Transaction nonce"),
gasPrice: z.string().optional().describe("Gas price in wei"),
gasLimit: z.string().optional().describe("Gas limit"),
to: z.string().optional().describe("Recipient address"),
}),
});
// Schema for setting local nonce
export const SetLocalNonceSchema = z.object({
address: z.string().describe("HSM wallet address"),
nonce: z.number().describe("New nonce value"),
});
// Schema for adding HSM key
export const AddHsmKeySchema = z.object({
clientId: z.string().describe("Client ID"),
keyName: z.string().describe("Name of the key"),
keyVersion: z.string().describe("The version of the key."),
vaultName: z.string().describe("Name of the key vault"),
});
// Schema for removing HSM key
export const RemoveHsmKeySchema = z.object({
keyName: z.string().describe("Name of the key"),
});
// Schema for adding HSM config
export const AddHsmConfigSchema = z.object({
label: z.string().describe("Name of Cloud Wallet"),
clientId: z.string().describe("Client ID"),
clientSecret: z.string().describe("Client secret"),
tenantId: z.string().describe("Tenant ID"),
subscriptionId: z.string().describe("Subscription ID"),
baseGroupName: z.string().describe("Base group name"),
});
// List HSM wallets
export async function listHsmWallets(
options: z.infer<typeof ListHsmWalletsSchema> = {},
) {
try {
const hsmApi = getHsmApi();
const response = await hsmApi.listHsmWallets(
undefined, // keyName
undefined, // keyVersion
undefined, // vaultName
undefined, // baseGroupName
undefined, // clientId
undefined, // publicAddress
options.limit,
options.offset,
);
return response.data.result;
} catch (error: any) {
if (error.response?.status === 404) {
throw new CurvegridResourceNotFoundError("HSM wallets not found");
}
throw new CurvegridError(`Failed to list HSM wallets: ${error.message}`);
}
}
// Get HSM wallet details
export async function getHsmWallet(
options: z.infer<typeof GetHsmWalletSchema>,
) {
try {
const hsmApi = getHsmApi();
const response = await hsmApi.listHsmWallets(
undefined,
undefined,
undefined,
undefined,
undefined,
options.address,
);
return response.data.result;
} catch (error: any) {
if (error.response?.status === 404) {
throw new CurvegridResourceNotFoundError(
`HSM wallet with address ${options.address} not found`,
);
}
throw new CurvegridError(`Failed to get HSM wallet: ${error.message}`);
}
}
// Create HSM wallet
export async function createHsmWallet(
options: z.infer<typeof CreateHsmWalletSchema>,
) {
try {
const hsmApi = getHsmApi();
const response = await hsmApi.createHsmKey({
keyName: options.keyName,
vaultName: options.vaultName,
clientID: options.clientId, // Note: SDK uses clientID not clientId
useHardwareModule: options.useHardwareModule,
});
return response.data.result;
} catch (error: any) {
throw new CurvegridError(`Failed to create HSM wallet: ${error.message}`);
}
}
// Sign message with HSM
export async function signMessage(options: z.infer<typeof SignMessageSchema>) {
try {
const hsmApi = getHsmApi();
const response = await hsmApi.signData({
method: "personal_sign", // Use personal_sign method
address: options.address,
data: options.data,
});
return response.data.result;
} catch (error: any) {
if (error.response?.status === 404) {
throw new CurvegridResourceNotFoundError(
`HSM wallet with address ${options.address} not found`,
);
}
throw new CurvegridError(`Failed to sign message: ${error.message}`);
}
}
// Sign and submit transaction with HSM
export async function signAndSubmitTransaction(
options: z.infer<typeof SignAndSubmitTransactionSchema>,
) {
try {
const hsmApi = getHsmApi();
const response = await hsmApi.signAndSubmitTransaction(options);
return response.data.result;
} catch (error: any) {
if (error.response?.status === 404) {
throw new CurvegridResourceNotFoundError(
`HSM wallet with address ${options.tx.from} not found`,
);
}
throw new CurvegridError(
`Failed to sign and submit transaction: ${error.message}`,
);
}
}
// Set local nonce for HSM wallet
export async function setLocalNonce(
options: z.infer<typeof SetLocalNonceSchema>,
) {
try {
const hsmApi = getHsmApi();
const response = await hsmApi.setLocalNonce(options.address, {
nonce: options.nonce,
});
return;
} catch (error: any) {
if (error.response?.status === 404) {
throw new CurvegridResourceNotFoundError(
`HSM wallet with address ${options.address} not found`,
);
}
throw new CurvegridError(`Failed to set local nonce: ${error.message}`);
}
}
// Add HSM key
export async function importHsmKey(options: z.infer<typeof AddHsmKeySchema>) {
try {
const hsmApi = getHsmApi();
await hsmApi.addHsmKey({
keyName: options.keyName,
vaultName: options.vaultName,
keyVersion: options.keyVersion,
clientID: options.clientId,
});
return;
} catch (error: any) {
throw new CurvegridError(`Failed to add HSM key: ${error.message}`);
}
}
// Remove HSM key
export async function removeHsmKey(
options: z.infer<typeof RemoveHsmKeySchema>,
) {
try {
const hsmApi = getHsmApi();
await hsmApi.removeHsmKey(options.keyName);
return;
} catch (error: any) {
throw new CurvegridError(`Failed to remove HSM key: ${error.message}`);
}
}
// Add HSM config
export async function addHsmConfig(
options: z.infer<typeof AddHsmConfigSchema>,
) {
try {
const hsmApi = getHsmApi();
await hsmApi.addHsmConfig({
label: options.label,
clientID: options.clientId, // Note: SDK uses clientID not clientId
clientSecret: options.clientSecret,
tenantID: options.tenantId, // Note: SDK uses tenantID not tenantId
subscriptionID: options.subscriptionId, // Note: SDK uses subscriptionID not subscriptionId
baseGroupName: options.baseGroupName,
});
return;
} catch (error: any) {
throw new CurvegridError(`Failed to add HSM config: ${error.message}`);
}
}
// List HSM
export async function listHsm() {
try {
const hsmApi = getHsmApi();
const response = await hsmApi.listHsm();
return response.data.result;
} catch (error: any) {
throw new CurvegridError(`Failed to list HSM: ${error.message}`);
}
}