@helium/blockchain-api 0.1.1 → 0.1.3

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.
Files changed (52) hide show
  1. package/README.md +24 -2
  2. package/package.json +31 -31
  3. package/types/README.md +24 -2
  4. package/types/generated/index.d.mts +2481 -0
  5. package/types/generated/index.d.ts +2481 -0
  6. package/types/generated/index.js +723 -0
  7. package/types/generated/index.mjs +614 -0
  8. package/types/index.ts +11 -8
  9. package/src/server/api/errors.ts +0 -152
  10. package/src/server/api/index.ts +0 -40
  11. package/src/server/api/procedures.ts +0 -144
  12. package/src/server/api/routers/fiat/router.ts +0 -709
  13. package/src/server/api/routers/fiat/schemas.ts +0 -157
  14. package/src/server/api/routers/health/router.ts +0 -41
  15. package/src/server/api/routers/hotspots/procedures/claimRewards.ts +0 -258
  16. package/src/server/api/routers/hotspots/procedures/createSplit.ts +0 -253
  17. package/src/server/api/routers/hotspots/procedures/deleteSplit.ts +0 -156
  18. package/src/server/api/routers/hotspots/procedures/getHotspots.ts +0 -31
  19. package/src/server/api/routers/hotspots/procedures/getPendingRewards.ts +0 -44
  20. package/src/server/api/routers/hotspots/procedures/getSplit.ts +0 -88
  21. package/src/server/api/routers/hotspots/procedures/transferHotspot.ts +0 -204
  22. package/src/server/api/routers/hotspots/procedures/updateRewardsDestination.ts +0 -201
  23. package/src/server/api/routers/hotspots/router.ts +0 -30
  24. package/src/server/api/routers/hotspots/schemas.ts +0 -182
  25. package/src/server/api/routers/swap/procedures/getInstructions.ts +0 -152
  26. package/src/server/api/routers/swap/procedures/getQuote.ts +0 -53
  27. package/src/server/api/routers/swap/procedures/getTokens.ts +0 -88
  28. package/src/server/api/routers/swap/router.ts +0 -15
  29. package/src/server/api/routers/swap/schemas.ts +0 -96
  30. package/src/server/api/routers/tokens/procedures/createHntAccount.ts +0 -87
  31. package/src/server/api/routers/tokens/procedures/getBalances.ts +0 -27
  32. package/src/server/api/routers/tokens/procedures/transfer.ts +0 -159
  33. package/src/server/api/routers/tokens/router.ts +0 -15
  34. package/src/server/api/routers/tokens/schemas.ts +0 -80
  35. package/src/server/api/routers/transactions/procedures/get.ts +0 -46
  36. package/src/server/api/routers/transactions/procedures/getByPayer.ts +0 -111
  37. package/src/server/api/routers/transactions/procedures/getByPayerAndTag.ts +0 -119
  38. package/src/server/api/routers/transactions/procedures/resubmit.ts +0 -68
  39. package/src/server/api/routers/transactions/procedures/submit.ts +0 -216
  40. package/src/server/api/routers/transactions/router.ts +0 -21
  41. package/src/server/api/routers/transactions/schemas.ts +0 -119
  42. package/src/server/api/routers/webhooks/router.ts +0 -75
  43. package/src/server/api/routers/welcomePacks/procedures/claim.ts +0 -157
  44. package/src/server/api/routers/welcomePacks/procedures/create.ts +0 -247
  45. package/src/server/api/routers/welcomePacks/procedures/deletePack.ts +0 -118
  46. package/src/server/api/routers/welcomePacks/procedures/get.ts +0 -36
  47. package/src/server/api/routers/welcomePacks/procedures/getByAddress.ts +0 -26
  48. package/src/server/api/routers/welcomePacks/procedures/invite.ts +0 -44
  49. package/src/server/api/routers/welcomePacks/procedures/list.ts +0 -27
  50. package/src/server/api/routers/welcomePacks/router.ts +0 -27
  51. package/src/server/api/routers/welcomePacks/schemas.ts +0 -135
  52. package/src/server/api/schemas.ts +0 -281
@@ -1,119 +0,0 @@
1
- import { publicProcedure } from "../../../procedures";
2
- import {
3
- GetByPayerAndTagInputSchema,
4
- PayerBatchesOutputSchema,
5
- } from "../schemas";
6
- import { ORPCError } from "@orpc/server";
7
- import PendingTransaction from "@/lib/models/pending-transaction";
8
- import TransactionBatch, { BatchStatus } from "@/lib/models/transaction-batch";
9
- import { connectToDb } from "@/lib/utils/db";
10
- import { Op } from "sequelize";
11
-
12
- /**
13
- * Get transaction batches by payer address and tag.
14
- */
15
- export const getByPayerAndTag = publicProcedure
16
- .route({ method: "GET", path: "/transactions/payer/{payer}/tag/{tag}" })
17
- .input(GetByPayerAndTagInputSchema)
18
- .output(PayerBatchesOutputSchema)
19
- .errors({
20
- BAD_REQUEST: { message: "Invalid request" },
21
- })
22
- .handler(async ({ input, errors }) => {
23
- const { payer, tag, page, limit, status } = input;
24
-
25
- await connectToDb();
26
-
27
- if (!payer) {
28
- throw errors.BAD_REQUEST({ message: "Payer is required" });
29
- }
30
-
31
- if (!tag) {
32
- throw errors.BAD_REQUEST({ message: "Tag is required" });
33
- }
34
-
35
- // Parse status filter
36
- let statusFilter: BatchStatus[] = ["pending"];
37
-
38
- if (status) {
39
- const requestedStatuses = status
40
- .split(",")
41
- .map((s) => s.trim()) as BatchStatus[];
42
- const validStatuses: BatchStatus[] = [
43
- "pending",
44
- "confirmed",
45
- "failed",
46
- "expired",
47
- "partial",
48
- ];
49
- statusFilter = requestedStatuses.filter((s) => validStatuses.includes(s));
50
-
51
- if (statusFilter.length === 0) {
52
- throw errors.BAD_REQUEST({
53
- message:
54
- "Invalid status filter. Valid values: pending, confirmed, failed, expired, partial",
55
- });
56
- }
57
- }
58
-
59
- const offset = (page - 1) * limit;
60
-
61
- // Build where clause
62
- const whereClause = {
63
- payer,
64
- tag,
65
- status: {
66
- [Op.in]: statusFilter,
67
- },
68
- };
69
-
70
- // Get total count for pagination
71
- const total = await TransactionBatch.count({
72
- where: whereClause,
73
- });
74
-
75
- // Find paginated transaction batches for the payer and tag
76
- const batches = await TransactionBatch.findAll({
77
- where: whereClause,
78
- include: [
79
- {
80
- model: PendingTransaction,
81
- as: "transactions",
82
- },
83
- ],
84
- order: [["createdAt", "DESC"]],
85
- limit,
86
- offset,
87
- });
88
-
89
- const batchSummaries = batches.map((batch) => ({
90
- batchId: batch.id,
91
- tag: batch.tag || undefined,
92
- status: batch.status,
93
- submissionType: batch.submissionType,
94
- parallel: batch.parallel,
95
- createdAt: batch.createdAt.toISOString(),
96
- updatedAt: batch.updatedAt.toISOString(),
97
- transactions:
98
- (
99
- batch as unknown as { transactions?: { metadata?: unknown }[] }
100
- ).transactions?.map((tx) => ({
101
- metadata: tx.metadata as
102
- | { type: string; description: string }
103
- | undefined,
104
- })) || [],
105
- }));
106
-
107
- const totalPages = Math.ceil(total / limit);
108
-
109
- return {
110
- payer,
111
- batches: batchSummaries,
112
- pagination: {
113
- page,
114
- limit,
115
- total,
116
- totalPages,
117
- },
118
- };
119
- });
@@ -1,68 +0,0 @@
1
- import { publicProcedure } from "../../../procedures";
2
- import { ResubmitInputSchema, ResubmitOutputSchema } from "../schemas";
3
- import { ORPCError } from "@orpc/server";
4
- import TransactionBatch from "@/lib/models/transaction-batch";
5
- import PendingTransaction from "@/lib/models/pending-transaction";
6
- import { resubmitTransactionBatch } from "@/lib/utils/transaction-resubmission";
7
-
8
- /**
9
- * Resubmit a batch of pending transactions that may have failed.
10
- */
11
- export const resubmit = publicProcedure
12
- .route({ method: "POST", path: "/transactions/{id}/resubmit" })
13
- .input(ResubmitInputSchema)
14
- .output(ResubmitOutputSchema)
15
- .errors({
16
- NOT_FOUND: { message: "Batch not found" },
17
- BAD_REQUEST: { message: "Invalid request" },
18
- })
19
- .handler(async ({ input, errors }) => {
20
- const { id } = input;
21
-
22
- // Find the batch
23
- const batch = await TransactionBatch.findByPk(id, {
24
- include: [
25
- {
26
- model: PendingTransaction,
27
- as: "transactions",
28
- where: {
29
- status: "pending",
30
- },
31
- },
32
- ],
33
- });
34
-
35
- if (!batch) {
36
- throw errors.NOT_FOUND({ message: "Batch not found" });
37
- }
38
-
39
- if (batch.status !== "pending") {
40
- throw errors.BAD_REQUEST({ message: "Batch is not in pending status" });
41
- }
42
-
43
- const pendingTransactions =
44
- (batch as unknown as { transactions?: PendingTransaction[] })
45
- .transactions || [];
46
- if (pendingTransactions.length === 0) {
47
- throw errors.BAD_REQUEST({
48
- message: "No pending transactions to resubmit",
49
- });
50
- }
51
-
52
- // Attempt resubmission
53
- const result = await resubmitTransactionBatch(batch, pendingTransactions);
54
-
55
- if (result.success) {
56
- return {
57
- success: true,
58
- message: "Transactions resubmitted successfully",
59
- ...(result.newSignatures && { newSignatures: result.newSignatures }),
60
- };
61
- } else {
62
- return {
63
- success: false,
64
- message: "Failed to resubmit transactions",
65
- error: result.error,
66
- };
67
- }
68
- });
@@ -1,216 +0,0 @@
1
- import { publicProcedure } from "../../../procedures";
2
- import { SubmitInputSchema, SubmitOutputSchema } from "../schemas";
3
- import { ORPCError } from "@orpc/server";
4
- import { sequelize } from "@/lib/db";
5
- import { env } from "@/lib/env";
6
- import PendingTransaction from "@/lib/models/pending-transaction";
7
- import TransactionBatch from "@/lib/models/transaction-batch";
8
- import {
9
- getCluster,
10
- submitTransactionBatch,
11
- } from "@/lib/utils/transaction-submission";
12
- import { Connection, VersionedTransaction } from "@solana/web3.js";
13
-
14
- function getExplorerUrl(transaction: VersionedTransaction) {
15
- const message = Buffer.from(transaction.message.serialize()).toString(
16
- "base64",
17
- );
18
- return `https://explorer.solana.com/tx/inspector?cluster=${
19
- process.env.NEXT_PUBLIC_SOLANA_CLUSTER
20
- }&message=${encodeURIComponent(message)}`;
21
- }
22
-
23
- /**
24
- * Submit a batch of transactions for processing.
25
- */
26
- export const submit = publicProcedure
27
- .route({ method: "POST", path: "/transactions" })
28
- .input(SubmitInputSchema)
29
- .output(SubmitOutputSchema)
30
- .errors({
31
- BAD_REQUEST: { message: "Invalid request" },
32
- SIMULATION_FAILED: { message: "Transaction simulation failed" },
33
- CONFLICT: { message: "Duplicate transaction" },
34
- })
35
- .handler(async ({ input, errors }) => {
36
- const { transactions, parallel, tag } = input;
37
-
38
- if (
39
- !transactions ||
40
- !Array.isArray(transactions) ||
41
- transactions.length === 0
42
- ) {
43
- throw errors.BAD_REQUEST({
44
- message: "Transactions array is required and cannot be empty",
45
- });
46
- }
47
-
48
- // Extract payer from the first transaction
49
- let payer: string;
50
- try {
51
- const firstTransaction = VersionedTransaction.deserialize(
52
- Buffer.from(transactions[0].serializedTransaction, "base64"),
53
- );
54
- payer = firstTransaction.message.staticAccountKeys[0].toBase58();
55
- } catch {
56
- throw errors.BAD_REQUEST({
57
- message: "Failed to decode transaction to extract payer",
58
- });
59
- }
60
-
61
- if (transactions.length > 5) {
62
- throw errors.BAD_REQUEST({
63
- message: "Maximum of 5 transactions allowed per batch",
64
- });
65
- }
66
-
67
- // Simulate transactions before submission (except for sequential batches)
68
- if (parallel || transactions.length === 1) {
69
- const connection = new Connection(env.SOLANA_RPC_URL);
70
-
71
- const simulationPromises = transactions.map(async (tx, index) => {
72
- try {
73
- const transaction = VersionedTransaction.deserialize(
74
- Buffer.from(tx.serializedTransaction, "base64"),
75
- );
76
- const simulation = await connection.simulateTransaction(transaction);
77
-
78
- if (simulation.value.err) {
79
- const errorMessage =
80
- typeof simulation.value.err === "string"
81
- ? simulation.value.err
82
- : JSON.stringify(simulation.value.err);
83
-
84
- return {
85
- index,
86
- error: `Transaction ${
87
- index + 1
88
- } simulation failed: ${errorMessage}`,
89
- logs: simulation.value.logs,
90
- link: getExplorerUrl(transaction),
91
- };
92
- }
93
- return { index, success: true };
94
- } catch (err) {
95
- return {
96
- index,
97
- error: `Transaction ${index + 1} deserialization failed: ${
98
- err instanceof Error ? err.message : "Unknown error"
99
- }`,
100
- };
101
- }
102
- });
103
-
104
- const simulationResults = await Promise.all(simulationPromises);
105
- const failures = simulationResults.filter((result) => "error" in result);
106
-
107
- if (failures.length > 0) {
108
- const firstFailure = failures[0];
109
- throw errors.SIMULATION_FAILED({
110
- message: firstFailure.error || "Transaction simulation failed",
111
- data: {
112
- logs: "logs" in firstFailure ? firstFailure.logs : undefined,
113
- link: "link" in firstFailure ? firstFailure.link : undefined,
114
- },
115
- });
116
- }
117
- }
118
-
119
- // Check for existing pending transaction with same tag+payer
120
- if (tag) {
121
- const existingBatch = await TransactionBatch.findOne({
122
- where: {
123
- tag,
124
- payer,
125
- status: "pending",
126
- },
127
- });
128
-
129
- if (existingBatch) {
130
- return {
131
- batchId: existingBatch.id,
132
- message: `Transaction with tag "${tag}" already exists and is pending`,
133
- };
134
- }
135
- }
136
-
137
- const serializedTransactions = transactions.map(
138
- (tx) => tx.serializedTransaction,
139
- );
140
- const result = await submitTransactionBatch({
141
- transactions: serializedTransactions,
142
- parallel,
143
- });
144
-
145
- if (result.error) {
146
- throw errors.BAD_REQUEST({ message: result.error });
147
- }
148
-
149
- const cluster = getCluster();
150
-
151
- // Use database transaction to ensure data consistency
152
- const dbTransaction = await sequelize.transaction();
153
-
154
- try {
155
- // Create the batch record
156
- await TransactionBatch.create(
157
- {
158
- id: result.batchId,
159
- parallel,
160
- status: "pending",
161
- submissionType: result.submissionType,
162
- jitoBundleId: result.jitoBundleId,
163
- cluster,
164
- tag,
165
- payer,
166
- },
167
- { transaction: dbTransaction },
168
- );
169
-
170
- // Create individual transaction records
171
- const pendingTransactionPromises = transactions.map(async (txData, i) => {
172
- const signature = result.signatures?.[i] || null;
173
-
174
- // Decode transaction to get blockhash
175
- const transaction = VersionedTransaction.deserialize(
176
- Buffer.from(txData.serializedTransaction, "base64"),
177
- );
178
-
179
- return PendingTransaction.create(
180
- {
181
- signature: signature || `${result.batchId}-${i}`,
182
- blockhash: transaction.message.recentBlockhash,
183
- status: "pending",
184
- type: txData.metadata?.type || "batch",
185
- batchId: result.batchId,
186
- payer,
187
- metadata: txData.metadata,
188
- serializedTransaction: txData.serializedTransaction,
189
- },
190
- { transaction: dbTransaction },
191
- );
192
- });
193
-
194
- await Promise.all(pendingTransactionPromises);
195
-
196
- // Commit the transaction
197
- await dbTransaction.commit();
198
- } catch (error: unknown) {
199
- // Rollback the transaction on any error
200
- await dbTransaction.rollback();
201
-
202
- // Handle unique constraint violation for tag+payer when status is pending
203
- if (
204
- (error as { name?: string })?.name ===
205
- "SequelizeUniqueConstraintError" &&
206
- tag
207
- ) {
208
- throw errors.CONFLICT({
209
- message: `A pending transaction with tag "${tag}" already exists for this payer`,
210
- });
211
- }
212
- throw error;
213
- }
214
-
215
- return { batchId: result.batchId };
216
- });
@@ -1,21 +0,0 @@
1
- import { submit } from "./procedures/submit";
2
- import { get } from "./procedures/get";
3
- import { resubmit } from "./procedures/resubmit";
4
- import { getByPayer } from "./procedures/getByPayer";
5
- import { getByPayerAndTag } from "./procedures/getByPayerAndTag";
6
-
7
- /**
8
- * Transactions router - handles transaction submission and status tracking.
9
- */
10
- export const transactionsRouter = {
11
- /** Submit a batch of transactions */
12
- submit,
13
- /** Get transaction batch status by ID */
14
- get,
15
- /** Resubmit a batch of pending transactions */
16
- resubmit,
17
- /** Get transaction batches by payer */
18
- getByPayer,
19
- /** Get transaction batches by payer and tag */
20
- getByPayerAndTag,
21
- };
@@ -1,119 +0,0 @@
1
- import { z } from "zod";
2
-
3
- // ============================================================================
4
- // Input Schemas
5
- // ============================================================================
6
-
7
- export const TransactionMetadataSchema = z
8
- .object({
9
- type: z.string(),
10
- description: z.string(),
11
- })
12
- .catchall(z.unknown());
13
-
14
- export const TransactionItemSchema = z.object({
15
- serializedTransaction: z.string(),
16
- metadata: TransactionMetadataSchema.optional(),
17
- });
18
-
19
- export const SubmitInputSchema = z.object({
20
- transactions: z.array(TransactionItemSchema),
21
- parallel: z.boolean(),
22
- tag: z.string().optional(),
23
- });
24
-
25
- export const GetInputSchema = z.object({
26
- id: z.string(),
27
- commitment: z.enum(["confirmed", "finalized"]),
28
- });
29
-
30
- export const ResubmitInputSchema = z.object({
31
- id: z.string(),
32
- });
33
-
34
- export const GetByPayerInputSchema = z.object({
35
- payer: z.string().min(32),
36
- page: z.coerce.number().int().min(1).default(1),
37
- limit: z.coerce.number().int().min(1).max(100).default(20),
38
- status: z.string().optional().default("pending"),
39
- });
40
-
41
- export const GetByPayerAndTagInputSchema = z.object({
42
- payer: z.string().min(32),
43
- tag: z.string(),
44
- page: z.coerce.number().int().min(1).default(1),
45
- limit: z.coerce.number().int().min(1).max(100).default(20),
46
- status: z.string().optional().default("pending"),
47
- });
48
-
49
- // ============================================================================
50
- // Output Schemas
51
- // ============================================================================
52
-
53
- export const SubmitOutputSchema = z.object({
54
- batchId: z.string(),
55
- message: z.string().optional(),
56
- });
57
-
58
- export const TransactionStatusSchema = z.object({
59
- signature: z.string(),
60
- status: z.string(),
61
- transaction: z.unknown().optional(),
62
- });
63
-
64
- export const BatchStatusOutputSchema = z.object({
65
- batchId: z.string(),
66
- status: z.string(),
67
- submissionType: z.string(),
68
- parallel: z.boolean(),
69
- transactions: z.array(TransactionStatusSchema),
70
- jitoBundleId: z.string().optional(),
71
- jitoBundleStatus: z.unknown().optional(),
72
- });
73
-
74
- export const ResubmitOutputSchema = z.object({
75
- success: z.boolean(),
76
- message: z.string(),
77
- error: z.string().optional(),
78
- newSignatures: z.array(z.string()).optional(),
79
- });
80
-
81
- export const PayerBatchSummarySchema = z.object({
82
- batchId: z.string(),
83
- tag: z.string().optional(),
84
- status: z.string(),
85
- submissionType: z.string(),
86
- parallel: z.boolean(),
87
- createdAt: z.string(),
88
- updatedAt: z.string(),
89
- transactions: z.array(
90
- z.object({
91
- metadata: TransactionMetadataSchema.optional(),
92
- }),
93
- ),
94
- });
95
-
96
- export const PayerBatchesOutputSchema = z.object({
97
- payer: z.string(),
98
- batches: z.array(PayerBatchSummarySchema),
99
- pagination: z.object({
100
- page: z.number(),
101
- limit: z.number(),
102
- total: z.number(),
103
- totalPages: z.number(),
104
- }),
105
- });
106
-
107
- // ============================================================================
108
- // Type Exports
109
- // ============================================================================
110
-
111
- export type SubmitInput = z.infer<typeof SubmitInputSchema>;
112
- export type GetInput = z.infer<typeof GetInputSchema>;
113
- export type ResubmitInput = z.infer<typeof ResubmitInputSchema>;
114
- export type GetByPayerInput = z.infer<typeof GetByPayerInputSchema>;
115
- export type GetByPayerAndTagInput = z.infer<typeof GetByPayerAndTagInputSchema>;
116
- export type SubmitOutput = z.infer<typeof SubmitOutputSchema>;
117
- export type BatchStatusOutput = z.infer<typeof BatchStatusOutputSchema>;
118
- export type ResubmitOutput = z.infer<typeof ResubmitOutputSchema>;
119
- export type PayerBatchesOutput = z.infer<typeof PayerBatchesOutputSchema>;
@@ -1,75 +0,0 @@
1
- import { z } from "zod";
2
- import { publicProcedure } from "../../procedures";
3
- import { BridgeUser } from "@/lib/models/bridge-user";
4
- import { ORPCError } from "@orpc/server";
5
-
6
- // ============================================================================
7
- // Schemas
8
- // ============================================================================
9
-
10
- const BridgeWebhookInputSchema = z.object({
11
- type: z.string(),
12
- kyc_link_id: z.string().optional(),
13
- kyc_status: z.string().optional(),
14
- tos_status: z.string().optional(),
15
- customer_id: z.string().optional(),
16
- });
17
-
18
- const BridgeWebhookOutputSchema = z.object({
19
- success: z.boolean(),
20
- error: z.string().optional(),
21
- });
22
-
23
- // ============================================================================
24
- // Procedures
25
- // ============================================================================
26
-
27
- /**
28
- * Bridge webhook handler for KYC/ToS status updates.
29
- */
30
- const bridge = publicProcedure
31
- .route({ method: "POST", path: "/webhooks/bridge" })
32
- .input(BridgeWebhookInputSchema)
33
- .output(BridgeWebhookOutputSchema)
34
- .errors({
35
- NOT_FOUND: { message: "Bridge user not found" },
36
- INVALID_PAYLOAD: { message: "Invalid webhook payload" },
37
- })
38
- .handler(async ({ input, errors }) => {
39
- const data = input;
40
-
41
- // Handle KYC link status updates
42
- if (data.type === "kyc_link.status_updated") {
43
- const bridgeUser = await BridgeUser.findOne({
44
- where: { kycLinkId: data.kyc_link_id },
45
- });
46
-
47
- if (!bridgeUser) {
48
- console.error(
49
- "Bridge user not found for KYC link ID:",
50
- data.kyc_link_id,
51
- );
52
- throw errors.NOT_FOUND({ message: "Bridge user not found" });
53
- }
54
-
55
- // Update statuses
56
- await bridgeUser.update({
57
- kycStatus: data.kyc_status,
58
- tosStatus: data.tos_status,
59
- bridgeCustomerId: data.customer_id,
60
- });
61
-
62
- return { success: true };
63
- }
64
-
65
- // Handle other webhook types here
66
- return { success: true };
67
- });
68
-
69
- // ============================================================================
70
- // Router Export
71
- // ============================================================================
72
-
73
- export const webhooksRouter = {
74
- bridge,
75
- };