@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,201 +0,0 @@
1
- import { publicProcedure } from "../../../procedures";
2
- import {
3
- UpdateRewardsDestinationInputSchema,
4
- UpdateRewardsDestinationOutputSchema,
5
- } from "../schemas";
6
- import { ORPCError } from "@orpc/server";
7
- import { PublicKey, TransactionInstruction } from "@solana/web3.js";
8
- import {
9
- generateTransactionTag,
10
- TRANSACTION_TYPES,
11
- } from "@/lib/utils/transaction-tags";
12
- import {
13
- populateMissingDraftInfo,
14
- toVersionedTx,
15
- withPriorityFees,
16
- proofArgsAndAccounts,
17
- } from "@helium/spl-utils";
18
- import {
19
- init as initLazy,
20
- initializeCompressionRecipient,
21
- recipientKey,
22
- } from "@helium/lazy-distributor-sdk";
23
- import { createSolanaConnection } from "@/lib/solana";
24
- import { env } from "@/lib/env";
25
- import { getAssetIdFromPubkey } from "@/lib/utils/hotspot-helpers";
26
-
27
- async function exists(
28
- connection: { getAccountInfo: (account: PublicKey) => Promise<unknown> },
29
- account: PublicKey,
30
- ): Promise<boolean> {
31
- return Boolean(await connection.getAccountInfo(account));
32
- }
33
-
34
- /**
35
- * Update the rewards destination for a hotspot across one or more lazy distributors.
36
- */
37
- export const updateRewardsDestination = publicProcedure
38
- .route({
39
- method: "POST",
40
- path: "/hotspots/wallet/{walletAddress}/{hotspotPubkey}/update-rewards-destination",
41
- })
42
- .input(UpdateRewardsDestinationInputSchema)
43
- .output(UpdateRewardsDestinationOutputSchema)
44
- .errors({
45
- NOT_FOUND: { message: "Hotspot not found" },
46
- BAD_REQUEST: { message: "Invalid request" },
47
- })
48
- .handler(async ({ input, errors }) => {
49
- const { walletAddress, hotspotPubkey, lazyDistributors, destination } =
50
- input;
51
-
52
- // Resolve hotspot pubkey to asset ID
53
- const assetId = await getAssetIdFromPubkey(hotspotPubkey);
54
- if (!assetId) {
55
- throw errors.NOT_FOUND({ message: "Hotspot not found" });
56
- }
57
-
58
- // Validate public keys
59
- let assetPubkey: PublicKey;
60
- let destinationPubkey: PublicKey;
61
- const lazyDistributorPubkeys: PublicKey[] = [];
62
-
63
- try {
64
- assetPubkey = new PublicKey(assetId);
65
- destinationPubkey = new PublicKey(destination);
66
-
67
- for (const ld of lazyDistributors) {
68
- lazyDistributorPubkeys.push(new PublicKey(ld));
69
- }
70
- } catch {
71
- throw errors.BAD_REQUEST({ message: "Invalid public key format" });
72
- }
73
-
74
- // Create connection and provider
75
- const { connection, provider, wallet } =
76
- createSolanaConnection(walletAddress);
77
-
78
- // Check if destination exists
79
- const destinationExists = await exists(connection, destinationPubkey);
80
-
81
- const program = await initLazy(provider);
82
-
83
- // Get proof args and accounts for the asset
84
- const assetEndpoint =
85
- env.ASSET_ENDPOINT || program.provider.connection.rpcEndpoint;
86
-
87
- const {
88
- asset: {
89
- ownership: { owner },
90
- },
91
- args,
92
- accounts,
93
- remainingAccounts,
94
- } = await proofArgsAndAccounts({
95
- connection: program.provider.connection,
96
- assetId: assetPubkey,
97
- assetEndpoint,
98
- });
99
-
100
- // Build instructions for each lazy distributor
101
- const instructions: TransactionInstruction[] = (
102
- await Promise.all(
103
- lazyDistributorPubkeys.map(async (lazy) => {
104
- const [recipientPk] = recipientKey(lazy, assetPubkey);
105
- const recipientExists = await exists(connection, recipientPk);
106
-
107
- const ixs: TransactionInstruction[] = [];
108
-
109
- // Initialize recipient if it doesn't exist
110
- if (!recipientExists) {
111
- ixs.push(
112
- await (
113
- await initializeCompressionRecipient({
114
- program,
115
- assetId: assetPubkey,
116
- lazyDistributor: lazy,
117
- payer: wallet.publicKey,
118
- })
119
- ).instruction(),
120
- );
121
- }
122
-
123
- // Create update compression destination instruction
124
- ixs.push(
125
- await program.methods
126
- .updateCompressionDestinationV0({
127
- ...args,
128
- })
129
- .accountsPartial({
130
- ...accounts,
131
- owner,
132
- recipient: recipientKey(lazy, assetPubkey)[0],
133
- destination:
134
- destination === PublicKey.default.toBase58()
135
- ? PublicKey.default
136
- : destinationPubkey,
137
- })
138
- .remainingAccounts(remainingAccounts)
139
- .instruction(),
140
- );
141
-
142
- return ixs;
143
- }),
144
- )
145
- ).flat();
146
-
147
- // Add priority fees
148
- const instructionsWithFees = await withPriorityFees({
149
- connection,
150
- instructions,
151
- feePayer: wallet.publicKey,
152
- });
153
-
154
- // Populate missing transaction info
155
- const draft = await populateMissingDraftInfo(connection, {
156
- instructions: instructionsWithFees,
157
- feePayer: wallet.publicKey,
158
- });
159
-
160
- // Convert to versioned transaction
161
- const versionedTx = toVersionedTx(draft);
162
- const serializedTransaction = Buffer.from(versionedTx.serialize()).toString(
163
- "base64",
164
- );
165
-
166
- // Generate transaction tag for deduplication
167
- const tag = generateTransactionTag({
168
- type: TRANSACTION_TYPES.UPDATE_REWARDS_DESTINATION,
169
- walletAddress,
170
- assetId,
171
- destination,
172
- lazyDistributors: lazyDistributors.join(","),
173
- timestamp: Date.now(),
174
- });
175
-
176
- return {
177
- transactionData: {
178
- transactions: [
179
- {
180
- serializedTransaction,
181
- metadata: {
182
- type: TRANSACTION_TYPES.UPDATE_REWARDS_DESTINATION,
183
- description: destinationExists
184
- ? `Update rewards destination to ${destination.slice(
185
- 0,
186
- 4,
187
- )}...${destination.slice(-4)}`
188
- : `Update rewards destination to ${destination.slice(
189
- 0,
190
- 4,
191
- )}...${destination.slice(
192
- -4,
193
- )} (Warning: destination account does not exist)`,
194
- },
195
- },
196
- ],
197
- parallel: false,
198
- tag,
199
- },
200
- };
201
- });
@@ -1,30 +0,0 @@
1
- import { getHotspots } from "./procedures/getHotspots";
2
- import { claimRewards } from "./procedures/claimRewards";
3
- import { getPendingRewards } from "./procedures/getPendingRewards";
4
- import { transferHotspot } from "./procedures/transferHotspot";
5
- import { updateRewardsDestination } from "./procedures/updateRewardsDestination";
6
- import { getSplit } from "./procedures/getSplit";
7
- import { createSplit } from "./procedures/createSplit";
8
- import { deleteSplit } from "./procedures/deleteSplit";
9
-
10
- /**
11
- * Hotspots router - handles all hotspot-related operations.
12
- */
13
- export const hotspotsRouter = {
14
- /** Get hotspots by wallet address with filtering and pagination */
15
- getHotspots,
16
- /** Create transactions to claim rewards for hotspots */
17
- claimRewards,
18
- /** Get pending rewards for all hotspots in a wallet */
19
- getPendingRewards,
20
- /** Create a transaction to transfer a hotspot to a new owner */
21
- transferHotspot,
22
- /** Update the rewards destination for a hotspot */
23
- updateRewardsDestination,
24
- /** Get the split configuration for a hotspot */
25
- getSplit,
26
- /** Create a split configuration for a hotspot */
27
- createSplit,
28
- /** Remove the split configuration from a hotspot */
29
- deleteSplit,
30
- };
@@ -1,182 +0,0 @@
1
- import { z } from "zod";
2
-
3
- // ============================================================================
4
- // Input Schemas
5
- // ============================================================================
6
-
7
- export const HotspotTypeSchema = z.enum(["iot", "mobile", "all"]);
8
-
9
- export const GetHotspotsInputSchema = z.object({
10
- walletAddress: z.string().min(32),
11
- type: HotspotTypeSchema.optional(),
12
- page: z.coerce.number().int().min(1).default(1),
13
- limit: z.coerce.number().int().min(1).max(100).default(10),
14
- });
15
-
16
- export const ClaimRewardsInputSchema = z.object({
17
- walletAddress: z.string().min(32),
18
- });
19
-
20
- export const GetPendingRewardsInputSchema = z.object({
21
- walletAddress: z.string().min(32),
22
- });
23
-
24
- export const TransferHotspotInputSchema = z.object({
25
- walletAddress: z.string().min(32),
26
- hotspotPubkey: z.string().min(1),
27
- recipient: z.string().min(32),
28
- });
29
-
30
- export const UpdateRewardsDestinationInputSchema = z.object({
31
- walletAddress: z.string().min(32),
32
- hotspotPubkey: z.string().min(1),
33
- destination: z.string().min(32),
34
- lazyDistributors: z.array(z.string().min(32)).min(1),
35
- });
36
-
37
- export const GetSplitInputSchema = z.object({
38
- walletAddress: z.string().min(32),
39
- hotspotPubkey: z.string().min(1),
40
- });
41
-
42
- export const RewardSplitInputSchema = z.object({
43
- address: z.string().min(32),
44
- type: z.enum(["percentage", "fixed"]),
45
- amount: z.number(),
46
- });
47
-
48
- export const ScheduleInputSchema = z.object({
49
- frequency: z.enum(["daily", "weekly", "monthly"]),
50
- time: z.string(),
51
- timezone: z.string(),
52
- dayOfWeek: z.string().optional(),
53
- dayOfMonth: z.string().optional(),
54
- });
55
-
56
- export const CreateSplitInputSchema = z.object({
57
- walletAddress: z.string().min(32),
58
- hotspotPubkey: z.string().min(1),
59
- rewardsSplit: z.array(RewardSplitInputSchema),
60
- schedule: ScheduleInputSchema,
61
- lazyDistributor: z.string().min(32),
62
- });
63
-
64
- export const DeleteSplitInputSchema = z.object({
65
- walletAddress: z.string().min(32),
66
- hotspotPubkey: z.string().min(1),
67
- });
68
-
69
- // ============================================================================
70
- // Output Schemas
71
- // ============================================================================
72
-
73
- export const DeviceTypeSchema = z.enum([
74
- "iot-gateway",
75
- "wifiIndoor",
76
- "wifiOutdoor",
77
- "wifiDataOnly",
78
- "cbrs",
79
- ]);
80
-
81
- export const HotspotSharesSchema = z.object({
82
- fixed: z.string().optional(),
83
- percentage: z.number().optional(),
84
- });
85
-
86
- export const HotspotSchema = z.object({
87
- address: z.string(),
88
- entityKey: z.string(),
89
- name: z.string(),
90
- type: HotspotTypeSchema,
91
- deviceType: DeviceTypeSchema,
92
- city: z.string().optional(),
93
- state: z.string().optional(),
94
- country: z.string().optional(),
95
- asset: z.string(),
96
- isOnline: z.boolean().optional(),
97
- owner: z.string().optional(),
98
- shares: HotspotSharesSchema.optional(),
99
- ownershipType: z.string(),
100
- });
101
-
102
- export const HotspotsDataSchema = z.object({
103
- hotspots: z.array(HotspotSchema),
104
- total: z.number(),
105
- page: z.number(),
106
- totalPages: z.number(),
107
- });
108
-
109
- export const TransactionMetadataSchema = z
110
- .object({
111
- type: z.string(),
112
- description: z.string(),
113
- })
114
- .catchall(z.unknown());
115
-
116
- export const TransactionItemSchema = z.object({
117
- serializedTransaction: z.string(),
118
- metadata: TransactionMetadataSchema.optional(),
119
- });
120
-
121
- export const TransactionDataSchema = z.object({
122
- transactions: z.array(TransactionItemSchema),
123
- parallel: z.boolean(),
124
- tag: z.string().optional(),
125
- });
126
-
127
- export const ClaimRewardsOutputSchema = z.object({
128
- transactionData: TransactionDataSchema,
129
- });
130
-
131
- export const TransferHotspotOutputSchema = z.object({
132
- transactionData: TransactionDataSchema,
133
- });
134
-
135
- export const UpdateRewardsDestinationOutputSchema = z.object({
136
- transactionData: TransactionDataSchema,
137
- });
138
-
139
- export const SplitShareSchema = z.object({
140
- wallet: z.string(),
141
- delegate: z.string(),
142
- fixed: z.number(),
143
- shares: z.number(),
144
- });
145
-
146
- export const SplitResponseSchema = z.object({
147
- walletAddress: z.string(),
148
- hotspotPubkey: z.string(),
149
- splitAddress: z.string(),
150
- shares: z.array(SplitShareSchema),
151
- });
152
-
153
- export const CreateSplitOutputSchema = z.object({
154
- transactionData: TransactionDataSchema,
155
- });
156
-
157
- export const DeleteSplitOutputSchema = z.object({
158
- transactionData: TransactionDataSchema,
159
- });
160
-
161
- // Pending rewards - proxied from oracle, so we use any for flexibility
162
- export const PendingRewardsOutputSchema = z.any();
163
-
164
- // ============================================================================
165
- // Type Exports
166
- // ============================================================================
167
-
168
- export type GetHotspotsInput = z.infer<typeof GetHotspotsInputSchema>;
169
- export type ClaimRewardsInput = z.infer<typeof ClaimRewardsInputSchema>;
170
- export type GetPendingRewardsInput = z.infer<
171
- typeof GetPendingRewardsInputSchema
172
- >;
173
- export type TransferHotspotInput = z.infer<typeof TransferHotspotInputSchema>;
174
- export type UpdateRewardsDestinationInput = z.infer<
175
- typeof UpdateRewardsDestinationInputSchema
176
- >;
177
- export type GetSplitInput = z.infer<typeof GetSplitInputSchema>;
178
- export type CreateSplitInput = z.infer<typeof CreateSplitInputSchema>;
179
- export type DeleteSplitInput = z.infer<typeof DeleteSplitInputSchema>;
180
- export type HotspotsData = z.infer<typeof HotspotsDataSchema>;
181
- export type Hotspot = z.infer<typeof HotspotSchema>;
182
- export type SplitResponse = z.infer<typeof SplitResponseSchema>;
@@ -1,152 +0,0 @@
1
- import { publicProcedure } from "../../../procedures";
2
- import { GetInstructionsInputSchema, TransactionDataSchema } from "../schemas";
3
- import { ORPCError } from "@orpc/server";
4
- import { env } from "@/lib/env";
5
- import { Connection, PublicKey, TransactionInstruction } from "@solana/web3.js";
6
- import {
7
- populateMissingDraftInfo,
8
- toVersionedTx,
9
- withPriorityFees,
10
- } from "@helium/spl-utils";
11
- import {
12
- generateTransactionTag,
13
- TRANSACTION_TYPES,
14
- } from "@/lib/utils/transaction-tags";
15
-
16
- /**
17
- * Get swap transaction instructions from Jupiter and build a transaction.
18
- */
19
- export const getInstructions = publicProcedure
20
- .route({ method: "POST", path: "/swap/instructions" })
21
- .input(GetInstructionsInputSchema)
22
- .output(TransactionDataSchema)
23
- .errors({
24
- JUPITER_ERROR: { message: "Failed to get swap instructions from Jupiter" },
25
- })
26
- .handler(async ({ input, errors }) => {
27
- const {
28
- quoteResponse,
29
- userPublicKey,
30
- destinationTokenAccount,
31
- dynamicComputeUnitLimit,
32
- prioritizationFeeLamports,
33
- } = input;
34
-
35
- // Get swap instructions from Jupiter
36
- const instructionsResponse = await fetch(
37
- `${env.JUPITER_API_URL}/swap/v1/swap-instructions`,
38
- {
39
- method: "POST",
40
- headers: {
41
- "Content-Type": "application/json",
42
- "x-api-key": env.JUPITER_API_KEY,
43
- },
44
- body: JSON.stringify({
45
- quoteResponse,
46
- userPublicKey,
47
- destinationTokenAccount,
48
- dynamicComputeUnitLimit,
49
- prioritizationFeeLamports: prioritizationFeeLamports || {
50
- priorityLevelWithMaxLamports: {
51
- maxLamports: 1000000,
52
- priorityLevel: "medium",
53
- },
54
- },
55
- }),
56
- },
57
- );
58
-
59
- if (!instructionsResponse.ok) {
60
- const errorText = await instructionsResponse.text();
61
- console.error("Jupiter API error:", errorText);
62
- throw errors.JUPITER_ERROR({
63
- message: `Failed to get swap instructions from Jupiter: HTTP ${instructionsResponse.status}`,
64
- });
65
- }
66
-
67
- const instructions = await instructionsResponse.json();
68
-
69
- if (instructions.error) {
70
- throw errors.JUPITER_ERROR({
71
- message: `Jupiter API returned error: ${instructions.error}`,
72
- });
73
- }
74
-
75
- // Build the transaction using the same pattern
76
- const deserializeInstruction = (instruction: {
77
- programId: string;
78
- accounts: { pubkey: string; isSigner: boolean; isWritable: boolean }[];
79
- data: string;
80
- }) => {
81
- return new TransactionInstruction({
82
- programId: new PublicKey(instruction.programId),
83
- keys: instruction.accounts.map((key) => ({
84
- pubkey: new PublicKey(key.pubkey),
85
- isSigner: key.isSigner,
86
- isWritable: key.isWritable,
87
- })),
88
- data: Buffer.from(instruction.data, "base64"),
89
- });
90
- };
91
-
92
- const jupIxs = [
93
- ...(instructions.setupInstructions
94
- ? instructions.setupInstructions.map(
95
- (instruction: {
96
- programId: string;
97
- accounts: {
98
- pubkey: string;
99
- isSigner: boolean;
100
- isWritable: boolean;
101
- }[];
102
- data: string;
103
- }) => deserializeInstruction(instruction),
104
- )
105
- : []),
106
- // Swap instruction
107
- deserializeInstruction(instructions.swapInstruction),
108
- // Cleanup instruction if present
109
- ...(instructions.cleanupInstruction
110
- ? [deserializeInstruction(instructions.cleanupInstruction)]
111
- : []),
112
- ];
113
-
114
- const draft = {
115
- instructions: jupIxs,
116
- feePayer: new PublicKey(userPublicKey),
117
- addressLookupTableAddresses: instructions.addressLookupTableAddresses.map(
118
- (address: string) => new PublicKey(address),
119
- ),
120
- };
121
-
122
- const connection = new Connection(process.env.SOLANA_RPC_URL!);
123
- const tx = toVersionedTx(
124
- await populateMissingDraftInfo(connection, {
125
- ...draft,
126
- instructions: await withPriorityFees({ ...draft, connection }),
127
- }),
128
- );
129
-
130
- // Generate transaction tag
131
- const tag = generateTransactionTag({
132
- type: TRANSACTION_TYPES.SWAP,
133
- userAddress: userPublicKey,
134
- inputMint: quoteResponse.inputMint,
135
- outputMint: quoteResponse.outputMint,
136
- amount: quoteResponse.inAmount,
137
- });
138
-
139
- return {
140
- transactions: [
141
- {
142
- serializedTransaction: Buffer.from(tx.serialize()).toString("base64"),
143
- metadata: {
144
- type: "swap",
145
- description: `Swap ${quoteResponse.inAmount} ${quoteResponse.inputMint} for ${quoteResponse.outAmount} ${quoteResponse.outputMint}`,
146
- },
147
- },
148
- ],
149
- parallel: false,
150
- tag,
151
- };
152
- });
@@ -1,53 +0,0 @@
1
- import { publicProcedure } from "../../../procedures";
2
- import { GetQuoteInputSchema, QuoteResponseSchema } from "../schemas";
3
- import { ORPCError } from "@orpc/server";
4
- import { env } from "@/lib/env";
5
-
6
- /**
7
- * Get a quote for swapping tokens from Jupiter.
8
- */
9
- export const getQuote = publicProcedure
10
- .route({ method: "GET", path: "/swap/quote" })
11
- .input(GetQuoteInputSchema)
12
- .output(QuoteResponseSchema)
13
- .errors({
14
- JUPITER_ERROR: { message: "Failed to get quote from Jupiter" },
15
- })
16
- .handler(async ({ input, errors }) => {
17
- const { inputMint, outputMint, amount, swapMode, slippageBps } = input;
18
-
19
- // Get quote from Jupiter
20
- const quoteUrl = new URL(`${env.JUPITER_API_URL}/swap/v1/quote`);
21
- quoteUrl.searchParams.set("inputMint", inputMint);
22
- quoteUrl.searchParams.set("outputMint", outputMint);
23
- quoteUrl.searchParams.set("amount", amount);
24
- quoteUrl.searchParams.set("swapMode", swapMode);
25
- quoteUrl.searchParams.set("slippageBps", slippageBps.toString());
26
-
27
- const quoteResponse = await fetch(quoteUrl.toString(), {
28
- headers: {
29
- "x-api-key": env.JUPITER_API_KEY,
30
- },
31
- });
32
-
33
- if (!quoteResponse.ok) {
34
- const errorText = await quoteResponse.text();
35
- console.error("Jupiter API error:", errorText);
36
- throw errors.JUPITER_ERROR({
37
- message: `Failed to get quote from Jupiter: HTTP ${quoteResponse.status}`,
38
- });
39
- }
40
-
41
- const quote = await quoteResponse.json();
42
-
43
- // Validate the response from Jupiter
44
- const responseValidation = QuoteResponseSchema.safeParse(quote);
45
- if (!responseValidation.success) {
46
- console.error("Invalid Jupiter response:", responseValidation.error);
47
- throw errors.JUPITER_ERROR({
48
- message: "Invalid response from Jupiter API",
49
- });
50
- }
51
-
52
- return responseValidation.data;
53
- });
@@ -1,88 +0,0 @@
1
- import { publicProcedure } from "../../../procedures";
2
- import { GetTokensInputSchema, TokenListOutputSchema, Token } from "../schemas";
3
- import { ORPCError } from "@orpc/server";
4
- import { env } from "@/lib/env";
5
- import { TOKEN_MINTS } from "@/lib/constants/tokens";
6
-
7
- /**
8
- * Get list of verified tokens available for swapping from Jupiter.
9
- */
10
- export const getTokens = publicProcedure
11
- .route({ method: "GET", path: "/swap/tokens" })
12
- .input(GetTokensInputSchema)
13
- .output(TokenListOutputSchema)
14
- .errors({
15
- JUPITER_ERROR: { message: "Failed to fetch tokens from Jupiter" },
16
- })
17
- .handler(async ({ input, errors }) => {
18
- const { limit } = input;
19
-
20
- // Use Jupiter's Token API V2 endpoint for verified tokens
21
- const jupiterUrl = new URL(`${env.JUPITER_API_URL}/tokens/v2/tag`);
22
- jupiterUrl.searchParams.set("query", "verified");
23
-
24
- const jupiterResponse = await fetch(jupiterUrl.toString(), {
25
- headers: {
26
- "User-Agent": "my-helium-api/1.0",
27
- "x-api-key": env.JUPITER_API_KEY,
28
- },
29
- });
30
-
31
- if (!jupiterResponse.ok) {
32
- const errorText = await jupiterResponse.text();
33
- console.error("Jupiter Token API error:", errorText);
34
- throw errors.JUPITER_ERROR({
35
- message: `Failed to fetch tokens from Jupiter: HTTP ${jupiterResponse.status}`,
36
- });
37
- }
38
-
39
- const jupiterTokens: {
40
- id: string;
41
- symbol: string;
42
- name: string;
43
- decimals: number;
44
- icon?: string;
45
- tags?: string[];
46
- }[] = await jupiterResponse.json();
47
-
48
- // Transform the V2 response format to our expected format
49
- const validatedTokens: Token[] = jupiterTokens
50
- .slice(0, limit)
51
- .map((token) => ({
52
- address: token.id,
53
- symbol: token.symbol,
54
- name: token.name,
55
- decimals: token.decimals,
56
- logoURI: token.icon,
57
- tags: token.tags || [],
58
- }));
59
-
60
- // Add HNT token at the top if it's not already in the list
61
- const hntToken: Token = {
62
- address: TOKEN_MINTS.HNT,
63
- symbol: "HNT",
64
- name: "Helium",
65
- decimals: 8,
66
- logoURI: "https://cryptologos.cc/logos/helium-hnt-logo.png",
67
- tags: ["helium", "iot", "crypto"],
68
- };
69
-
70
- // Check if HNT is already in the list
71
- const hasHNT = validatedTokens.some((token) => token.symbol === "HNT");
72
-
73
- // Add HNT at the top if not present
74
- if (!hasHNT) {
75
- validatedTokens.unshift(hntToken);
76
- } else {
77
- // Move HNT to the top if it exists
78
- const hntIndex = validatedTokens.findIndex(
79
- (token) => token.symbol === "HNT",
80
- );
81
- if (hntIndex > 0) {
82
- const hnt = validatedTokens.splice(hntIndex, 1)[0];
83
- validatedTokens.unshift(hnt);
84
- }
85
- }
86
-
87
- return { tokens: validatedTokens };
88
- });