@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.
- package/README.md +24 -2
- package/package.json +31 -31
- package/types/README.md +24 -2
- package/types/generated/index.d.mts +2481 -0
- package/types/generated/index.d.ts +2481 -0
- package/types/generated/index.js +723 -0
- package/types/generated/index.mjs +614 -0
- package/types/index.ts +11 -8
- package/src/server/api/errors.ts +0 -152
- package/src/server/api/index.ts +0 -40
- package/src/server/api/procedures.ts +0 -144
- package/src/server/api/routers/fiat/router.ts +0 -709
- package/src/server/api/routers/fiat/schemas.ts +0 -157
- package/src/server/api/routers/health/router.ts +0 -41
- package/src/server/api/routers/hotspots/procedures/claimRewards.ts +0 -258
- package/src/server/api/routers/hotspots/procedures/createSplit.ts +0 -253
- package/src/server/api/routers/hotspots/procedures/deleteSplit.ts +0 -156
- package/src/server/api/routers/hotspots/procedures/getHotspots.ts +0 -31
- package/src/server/api/routers/hotspots/procedures/getPendingRewards.ts +0 -44
- package/src/server/api/routers/hotspots/procedures/getSplit.ts +0 -88
- package/src/server/api/routers/hotspots/procedures/transferHotspot.ts +0 -204
- package/src/server/api/routers/hotspots/procedures/updateRewardsDestination.ts +0 -201
- package/src/server/api/routers/hotspots/router.ts +0 -30
- package/src/server/api/routers/hotspots/schemas.ts +0 -182
- package/src/server/api/routers/swap/procedures/getInstructions.ts +0 -152
- package/src/server/api/routers/swap/procedures/getQuote.ts +0 -53
- package/src/server/api/routers/swap/procedures/getTokens.ts +0 -88
- package/src/server/api/routers/swap/router.ts +0 -15
- package/src/server/api/routers/swap/schemas.ts +0 -96
- package/src/server/api/routers/tokens/procedures/createHntAccount.ts +0 -87
- package/src/server/api/routers/tokens/procedures/getBalances.ts +0 -27
- package/src/server/api/routers/tokens/procedures/transfer.ts +0 -159
- package/src/server/api/routers/tokens/router.ts +0 -15
- package/src/server/api/routers/tokens/schemas.ts +0 -80
- package/src/server/api/routers/transactions/procedures/get.ts +0 -46
- package/src/server/api/routers/transactions/procedures/getByPayer.ts +0 -111
- package/src/server/api/routers/transactions/procedures/getByPayerAndTag.ts +0 -119
- package/src/server/api/routers/transactions/procedures/resubmit.ts +0 -68
- package/src/server/api/routers/transactions/procedures/submit.ts +0 -216
- package/src/server/api/routers/transactions/router.ts +0 -21
- package/src/server/api/routers/transactions/schemas.ts +0 -119
- package/src/server/api/routers/webhooks/router.ts +0 -75
- package/src/server/api/routers/welcomePacks/procedures/claim.ts +0 -157
- package/src/server/api/routers/welcomePacks/procedures/create.ts +0 -247
- package/src/server/api/routers/welcomePacks/procedures/deletePack.ts +0 -118
- package/src/server/api/routers/welcomePacks/procedures/get.ts +0 -36
- package/src/server/api/routers/welcomePacks/procedures/getByAddress.ts +0 -26
- package/src/server/api/routers/welcomePacks/procedures/invite.ts +0 -44
- package/src/server/api/routers/welcomePacks/procedures/list.ts +0 -27
- package/src/server/api/routers/welcomePacks/router.ts +0 -27
- package/src/server/api/routers/welcomePacks/schemas.ts +0 -135
- 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
|
-
});
|