@helium/blockchain-api 0.1.2 → 0.2.0

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 (51) hide show
  1. package/README.md +106 -49
  2. package/dist/index.d.ts +2382 -0
  3. package/dist/index.js +852 -0
  4. package/package.json +36 -126
  5. package/src/server/api/errors.ts +0 -152
  6. package/src/server/api/index.ts +0 -40
  7. package/src/server/api/procedures.ts +0 -144
  8. package/src/server/api/routers/fiat/router.ts +0 -709
  9. package/src/server/api/routers/fiat/schemas.ts +0 -169
  10. package/src/server/api/routers/health/router.ts +0 -41
  11. package/src/server/api/routers/hotspots/procedures/claimRewards.ts +0 -258
  12. package/src/server/api/routers/hotspots/procedures/createSplit.ts +0 -253
  13. package/src/server/api/routers/hotspots/procedures/deleteSplit.ts +0 -156
  14. package/src/server/api/routers/hotspots/procedures/getHotspots.ts +0 -31
  15. package/src/server/api/routers/hotspots/procedures/getPendingRewards.ts +0 -44
  16. package/src/server/api/routers/hotspots/procedures/getSplit.ts +0 -88
  17. package/src/server/api/routers/hotspots/procedures/transferHotspot.ts +0 -204
  18. package/src/server/api/routers/hotspots/procedures/updateRewardsDestination.ts +0 -201
  19. package/src/server/api/routers/hotspots/router.ts +0 -30
  20. package/src/server/api/routers/hotspots/schemas.ts +0 -182
  21. package/src/server/api/routers/swap/procedures/getInstructions.ts +0 -152
  22. package/src/server/api/routers/swap/procedures/getQuote.ts +0 -53
  23. package/src/server/api/routers/swap/procedures/getTokens.ts +0 -88
  24. package/src/server/api/routers/swap/router.ts +0 -15
  25. package/src/server/api/routers/swap/schemas.ts +0 -96
  26. package/src/server/api/routers/tokens/procedures/createHntAccount.ts +0 -87
  27. package/src/server/api/routers/tokens/procedures/getBalances.ts +0 -27
  28. package/src/server/api/routers/tokens/procedures/transfer.ts +0 -159
  29. package/src/server/api/routers/tokens/router.ts +0 -15
  30. package/src/server/api/routers/tokens/schemas.ts +0 -80
  31. package/src/server/api/routers/transactions/procedures/get.ts +0 -46
  32. package/src/server/api/routers/transactions/procedures/getByPayer.ts +0 -111
  33. package/src/server/api/routers/transactions/procedures/getByPayerAndTag.ts +0 -119
  34. package/src/server/api/routers/transactions/procedures/resubmit.ts +0 -68
  35. package/src/server/api/routers/transactions/procedures/submit.ts +0 -216
  36. package/src/server/api/routers/transactions/router.ts +0 -21
  37. package/src/server/api/routers/transactions/schemas.ts +0 -119
  38. package/src/server/api/routers/webhooks/router.ts +0 -75
  39. package/src/server/api/routers/welcomePacks/procedures/claim.ts +0 -157
  40. package/src/server/api/routers/welcomePacks/procedures/create.ts +0 -247
  41. package/src/server/api/routers/welcomePacks/procedures/deletePack.ts +0 -118
  42. package/src/server/api/routers/welcomePacks/procedures/get.ts +0 -36
  43. package/src/server/api/routers/welcomePacks/procedures/getByAddress.ts +0 -26
  44. package/src/server/api/routers/welcomePacks/procedures/invite.ts +0 -44
  45. package/src/server/api/routers/welcomePacks/procedures/list.ts +0 -27
  46. package/src/server/api/routers/welcomePacks/router.ts +0 -27
  47. package/src/server/api/routers/welcomePacks/schemas.ts +0 -135
  48. package/src/server/api/schemas.ts +0 -281
  49. package/tsconfig.json +0 -45
  50. package/types/README.md +0 -86
  51. package/types/index.ts +0 -27
@@ -1,169 +0,0 @@
1
- import { z } from "zod";
2
- import { QuoteResponseSchema } from "../swap/schemas";
3
-
4
- // ============================================================================
5
- // Input Schemas
6
- // ============================================================================
7
-
8
- export const InitKycInputSchema = z.object({
9
- type: z.enum(["individual", "business"]).optional(),
10
- });
11
-
12
- export const CreateBankAccountInputSchema = z.object({
13
- currency: z.string(),
14
- account_type: z.string(),
15
- bank_name: z.string(),
16
- account_name: z.string(),
17
- first_name: z.string().optional(),
18
- last_name: z.string().optional(),
19
- account_owner_name: z.string().optional(),
20
- business_name: z.string().optional(),
21
- account: z.object({
22
- account_number: z.string(),
23
- routing_number: z.string(),
24
- checking_or_savings: z.string(),
25
- }),
26
- address: z.object({
27
- street_line_1: z.string(),
28
- line2: z.string().optional(),
29
- city: z.string(),
30
- state: z.string(),
31
- postal_code: z.string(),
32
- country: z.string(),
33
- }),
34
- });
35
-
36
- export const GetBankAccountInputSchema = z.object({
37
- id: z.string(),
38
- });
39
-
40
- export const DeleteBankAccountInputSchema = z.object({
41
- id: z.number(),
42
- });
43
-
44
- export const GetSendQuoteInputSchema = z.object({
45
- id: z.string(),
46
- usdAmount: z.string(),
47
- });
48
-
49
- export const SendFundsInputSchema = z.object({
50
- id: z.string(),
51
- userAddress: z.string(),
52
- quoteResponse: z
53
- .object({
54
- inputMint: z.string(),
55
- inAmount: z.string(),
56
- outputMint: z.string(),
57
- outAmount: z.string(),
58
- otherAmountThreshold: z.string(),
59
- swapMode: z.string(),
60
- slippageBps: z.number(),
61
- platformFee: z.unknown().optional(),
62
- priceImpactPct: z.string(),
63
- routePlan: z.array(z.unknown()),
64
- contextSlot: z.number().optional(),
65
- timeTaken: z.number().optional(),
66
- })
67
- .passthrough(), // Allow additional fields from Jupiter
68
- });
69
-
70
- export const GetTransferInputSchema = z.object({
71
- id: z.string(),
72
- });
73
-
74
- export const UpdateTransferInputSchema = z.object({
75
- id: z.string(),
76
- solanaSignature: z.string(),
77
- });
78
-
79
- // ============================================================================
80
- // Output Schemas
81
- // ============================================================================
82
-
83
- export const KycStatusOutputSchema = z.object({
84
- kycStatus: z.string(),
85
- tosStatus: z.string(),
86
- tosLink: z.string().nullable(),
87
- kycLink: z.string().nullable(),
88
- kycLinkId: z.string().nullable(),
89
- accountType: z.string().optional(),
90
- rejectionReasons: z.array(z.string()).optional(),
91
- });
92
-
93
- export const FeesOutputSchema = z.object({
94
- developer_fee: z.string(),
95
- developer_fee_percent: z.number(),
96
- });
97
-
98
- export const BankAccountSchema = z
99
- .object({
100
- id: z.number().optional(),
101
- bridgeUserId: z.number().optional(),
102
- bridgeExternalAccountId: z.string().optional(),
103
- accountName: z.string().optional(),
104
- bankName: z.string().optional(),
105
- lastFourDigits: z.string().optional(),
106
- routingNumber: z.string().optional(),
107
- accountType: z.string().optional(),
108
- createdAt: z.union([z.string(), z.date()]).optional(),
109
- updatedAt: z.union([z.string(), z.date()]).optional(),
110
- })
111
- .passthrough();
112
-
113
- export const BankAccountListOutputSchema = z.array(BankAccountSchema);
114
-
115
- export const DeleteBankAccountOutputSchema = z.object({
116
- success: z.boolean(),
117
- });
118
-
119
- export const TransactionMetadataSchema = z
120
- .object({
121
- type: z.string(),
122
- description: z.string(),
123
- })
124
- .catchall(z.unknown());
125
-
126
- export const TransactionItemSchema = z.object({
127
- serializedTransaction: z.string(),
128
- metadata: TransactionMetadataSchema.optional(),
129
- });
130
-
131
- export const TransactionDataSchema = z.object({
132
- transactions: z.array(TransactionItemSchema),
133
- parallel: z.boolean(),
134
- tag: z.string().optional(),
135
- });
136
-
137
- export const BridgeTransferSchema = z
138
- .object({
139
- id: z.string(),
140
- state: z.string(),
141
- source_deposit_instructions: z.object({
142
- to_address: z.string(),
143
- }),
144
- })
145
- .passthrough();
146
-
147
- export const SendFundsOutputSchema = z.object({
148
- bridgeTransfer: BridgeTransferSchema,
149
- transactionData: TransactionDataSchema,
150
- });
151
-
152
- export const UpdateTransferOutputSchema = z.object({
153
- success: z.boolean(),
154
- });
155
-
156
- // Quote response is pass-through from Jupiter
157
- export const QuoteOutputSchema = QuoteResponseSchema;
158
-
159
- // ============================================================================
160
- // Type Exports
161
- // ============================================================================
162
-
163
- export type InitKycInput = z.infer<typeof InitKycInputSchema>;
164
- export type CreateBankAccountInput = z.infer<
165
- typeof CreateBankAccountInputSchema
166
- >;
167
- export type KycStatusOutput = z.infer<typeof KycStatusOutputSchema>;
168
- export type FeesOutput = z.infer<typeof FeesOutputSchema>;
169
- export type BridgeTransfer = z.infer<typeof BridgeTransferSchema>;
@@ -1,41 +0,0 @@
1
- import { z } from "zod";
2
- import { publicProcedure } from "../../procedures";
3
- import { connectToDb } from "@/lib/utils/db";
4
-
5
- // ============================================================================
6
- // Schemas
7
- // ============================================================================
8
-
9
- const HealthResponseSchema = z.object({
10
- ok: z.boolean(),
11
- error: z.string().optional(),
12
- });
13
-
14
- // ============================================================================
15
- // Procedures
16
- // ============================================================================
17
-
18
- /**
19
- * Health check procedure.
20
- * Verifies API and database connectivity.
21
- */
22
- const check = publicProcedure
23
- .route({ method: "GET", path: "/health" })
24
- .output(HealthResponseSchema)
25
- .handler(async () => {
26
- try {
27
- await connectToDb();
28
- return { ok: true };
29
- } catch (error) {
30
- console.error("Health check failed:", error);
31
- return { ok: false, error: "Database connection failed" };
32
- }
33
- });
34
-
35
- // ============================================================================
36
- // Router Export
37
- // ============================================================================
38
-
39
- export const healthRouter = {
40
- check,
41
- };
@@ -1,258 +0,0 @@
1
- import { publicProcedure } from "../../../procedures";
2
- import { ClaimRewardsInputSchema, ClaimRewardsOutputSchema } from "../schemas";
3
- import { getSingleton } from "@helium/account-fetch-cache";
4
- import {
5
- getHotspotsByOwner,
6
- getNumRecipientsNeeded,
7
- } from "@/lib/queries/hotspots";
8
- import { env } from "@/lib/env";
9
- import { createSolanaConnection } from "@/lib/solana";
10
- import { init as initLd } from "@helium/lazy-distributor-sdk";
11
- import {
12
- formBulkTransactions,
13
- getBulkRewards,
14
- } from "@/utils/distributorOracle";
15
- import {
16
- LAMPORTS_PER_SOL,
17
- PublicKey,
18
- SystemProgram,
19
- TransactionInstruction,
20
- VersionedTransaction,
21
- } from "@solana/web3.js";
22
- import * as anchor from "@coral-xyz/anchor";
23
- import {
24
- customSignerKey,
25
- init as initTuktuk,
26
- nextAvailableTaskIds,
27
- taskKey,
28
- taskQueueAuthorityKey,
29
- } from "@helium/tuktuk-sdk";
30
- import {
31
- HELIUM_COMMON_LUT,
32
- HELIUM_COMMON_LUT_DEVNET,
33
- HNT_MINT,
34
- batchInstructionsToTxsWithPriorityFee,
35
- toVersionedTx,
36
- } from "@helium/spl-utils";
37
- import { HNT_LAZY_DISTRIBUTOR_ADDRESS } from "@/lib/constants/lazy-distributor";
38
- import { getAssociatedTokenAddressSync } from "@solana/spl-token";
39
-
40
- const MIN_RENT = 0.00089088;
41
- const RECIPIENT_RENT = 0.00242208;
42
- const ATA_RENT = 0.002039 * LAMPORTS_PER_SOL;
43
- const MIN_RENT_LAMPORTS = Math.ceil(MIN_RENT * LAMPORTS_PER_SOL);
44
- const RECIPIENT_RENT_LAMPORTS = Math.ceil(RECIPIENT_RENT * LAMPORTS_PER_SOL);
45
- const ATA_RENT_LAMPORTS = Math.ceil(ATA_RENT);
46
-
47
- const HPL_CRONS_PROGRAM_ID = new PublicKey(
48
- "hcrLPFgFUY6sCUKzqLWxXx5bntDiDCrAZVcrXfx9AHu",
49
- );
50
- const TASK_QUEUE_ID = new PublicKey(
51
- process.env.HPL_CRONS_TASK_QUEUE ||
52
- "H39gEszvsi6AT4rYBiJTuZHJSF5hMHy6CKGTd7wzhsg7",
53
- );
54
-
55
- /**
56
- * Create transactions to claim rewards for all hotspots in a wallet.
57
- * For wallets with 3 or fewer hotspots, returns direct claim transactions.
58
- * For larger wallets, creates a Tuktuk task to process claims.
59
- */
60
- export const claimRewards = publicProcedure
61
- .route({ method: "POST", path: "/hotspots/wallet/{walletAddress}/claim" })
62
- .input(ClaimRewardsInputSchema)
63
- .output(ClaimRewardsOutputSchema)
64
- .errors({
65
- BAD_REQUEST: { message: "Invalid request" },
66
- INSUFFICIENT_FUNDS: {
67
- message: "Insufficient SOL balance to fund claim task",
68
- },
69
- })
70
- .handler(async ({ input, errors }) => {
71
- const { walletAddress } = input;
72
-
73
- // Single query: fetch up to 3 hotspots and total count
74
- const hotspotsData = await getHotspotsByOwner({
75
- owner: walletAddress,
76
- page: 1,
77
- limit: 3,
78
- });
79
- const { total } = hotspotsData;
80
-
81
- // For small wallets, request direct claim transactions
82
- if (total <= 3) {
83
- const assets = hotspotsData.hotspots.map((h) => new PublicKey(h.asset));
84
- const entityKeys = hotspotsData.hotspots.map((h) => h.entityKey);
85
-
86
- // Initialize programs
87
- const { provider } = createSolanaConnection(walletAddress);
88
- const ldProgram = await initLd(provider);
89
-
90
- // Fetch oracle rewards for these entity keys
91
- const rewards = await getBulkRewards(
92
- ldProgram,
93
- new PublicKey(HNT_LAZY_DISTRIBUTOR_ADDRESS),
94
- entityKeys,
95
- );
96
-
97
- // Build and sign transactions via oracle
98
- const vtxs: VersionedTransaction[] = await formBulkTransactions({
99
- program: ldProgram,
100
- rewards,
101
- assets,
102
- lazyDistributor: new PublicKey(HNT_LAZY_DISTRIBUTOR_ADDRESS),
103
- assetEndpoint: env.ASSET_ENDPOINT,
104
- skipOracleSign: false,
105
- });
106
-
107
- const singleton = await getSingleton(provider.connection);
108
- singleton.close();
109
-
110
- const txs = vtxs.map((tx) =>
111
- Buffer.from(tx.serialize()).toString("base64"),
112
- );
113
-
114
- return {
115
- transactionData: {
116
- transactions: txs.map((serialized) => ({
117
- serializedTransaction: serialized,
118
- metadata: {
119
- type: "claim_rewards",
120
- description: "Claim hotspot rewards",
121
- },
122
- })),
123
- parallel: true,
124
- tag: `claim_rewards:${walletAddress}`,
125
- },
126
- };
127
- }
128
-
129
- // For larger wallets, queue a Tuktuk claim task via HPL Crons
130
- const { provider } = createSolanaConnection(walletAddress);
131
- anchor.setProvider(provider);
132
-
133
- const tuktukProgram = await initTuktuk(provider);
134
- const taskQueueAcc =
135
- await tuktukProgram.account.taskQueueV0.fetch(TASK_QUEUE_ID);
136
- const [taskId] = nextAvailableTaskIds(taskQueueAcc.taskBitmap, 1);
137
-
138
- const queueAuthority = PublicKey.findProgramAddressSync(
139
- [Buffer.from("queue_authority")],
140
- HPL_CRONS_PROGRAM_ID,
141
- )[0];
142
-
143
- const idl = await anchor.Program.fetchIdl(HPL_CRONS_PROGRAM_ID, provider);
144
- const hplCronsProgram = new anchor.Program(
145
- idl as anchor.Idl,
146
- provider,
147
- ) as anchor.Program<anchor.Idl>;
148
-
149
- const instructions: TransactionInstruction[] = [];
150
-
151
- const pdaWallet = customSignerKey(TASK_QUEUE_ID, [
152
- Buffer.from("claim_payer"),
153
- new PublicKey(walletAddress).toBuffer(),
154
- ])[0];
155
- const pdaWalletBalanceLamports =
156
- await provider.connection.getBalance(pdaWallet);
157
- const ata = getAssociatedTokenAddressSync(
158
- HNT_MINT,
159
- new PublicKey(walletAddress),
160
- true,
161
- );
162
- const minCrankReward = taskQueueAcc?.minCrankReward?.toNumber() || 10000;
163
- const account = await provider.connection.getAccountInfo(ata);
164
- const pdaWalletFundingNeededLamports =
165
- MIN_RENT_LAMPORTS +
166
- (account ? 0 : ATA_RENT_LAMPORTS) +
167
- // Actual claim txs
168
- 20000 * (total || 1) +
169
- // Requeue transactions (5 queues per tx)
170
- minCrankReward * Math.ceil((total || 1) / 5);
171
- const pdaWalletLamportsShortfall = Math.max(
172
- 0,
173
- pdaWalletFundingNeededLamports - pdaWalletBalanceLamports,
174
- );
175
-
176
- const hotspotsNeedingRecipient =
177
- await getNumRecipientsNeeded(walletAddress);
178
- console.log(
179
- `[PDA WALLET ${pdaWallet.toBase58()}] Hotspots needing recipient: ${hotspotsNeedingRecipient}, shortfall: ${pdaWalletLamportsShortfall}`,
180
- );
181
-
182
- if (pdaWalletLamportsShortfall > 0 || hotspotsNeedingRecipient > 0) {
183
- const requiredLamports =
184
- pdaWalletLamportsShortfall +
185
- hotspotsNeedingRecipient * RECIPIENT_RENT_LAMPORTS;
186
- // Ensure the user's wallet has enough SOL to fund PDA and recipients before returning tx
187
- const senderBalance = await provider.connection.getBalance(
188
- new PublicKey(walletAddress),
189
- );
190
- if (senderBalance < requiredLamports) {
191
- throw errors.INSUFFICIENT_FUNDS({
192
- message: "Insufficient SOL balance to fund claim task",
193
- data: {
194
- balance: senderBalance,
195
- required: requiredLamports,
196
- },
197
- });
198
- }
199
- instructions.push(
200
- SystemProgram.transfer({
201
- fromPubkey: new PublicKey(walletAddress),
202
- toPubkey: pdaWallet,
203
- lamports: requiredLamports,
204
- }),
205
- );
206
- }
207
-
208
- const ix = await hplCronsProgram.methods
209
- .queueWalletClaimV0({ freeTaskId: taskId })
210
- .accountsStrict({
211
- task: taskKey(TASK_QUEUE_ID, taskId)[0],
212
- wallet: new PublicKey(walletAddress),
213
- taskQueue: TASK_QUEUE_ID,
214
- payer: provider.wallet.publicKey,
215
- systemProgram: SystemProgram.programId,
216
- queueAuthority,
217
- tuktukProgram: tuktukProgram.programId,
218
- pdaWallet: customSignerKey(TASK_QUEUE_ID, [
219
- Buffer.from("claim_payer"),
220
- new PublicKey(walletAddress).toBuffer(),
221
- ])[0],
222
- taskQueueAuthority: taskQueueAuthorityKey(
223
- TASK_QUEUE_ID,
224
- queueAuthority,
225
- )[0],
226
- })
227
- .instruction();
228
-
229
- instructions.push(ix);
230
- const vtxs = (
231
- await batchInstructionsToTxsWithPriorityFee(provider, instructions, {
232
- addressLookupTableAddresses: [
233
- process.env.NEXT_PUBLIC_SOLANA_CLUSTER?.trim() === "devnet"
234
- ? HELIUM_COMMON_LUT_DEVNET
235
- : HELIUM_COMMON_LUT,
236
- ],
237
- })
238
- ).map((tx) => toVersionedTx(tx));
239
-
240
- const txs: Array<string> = vtxs.map((tx) =>
241
- Buffer.from(tx.serialize()).toString("base64"),
242
- );
243
-
244
- return {
245
- transactionData: {
246
- transactions: txs.map((serialized) => ({
247
- serializedTransaction: serialized,
248
- metadata: {
249
- type: "queue_wallet_claim",
250
- description: "Queue wallet claim task via Tuktuk",
251
- taskIds: [taskId],
252
- },
253
- })),
254
- parallel: true,
255
- tag: `claim_rewards_tuktuk:${walletAddress}`,
256
- },
257
- };
258
- });