@helium/blockchain-api 0.1.2 → 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 -169
- 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,253 +0,0 @@
|
|
|
1
|
-
import { publicProcedure } from "../../../procedures";
|
|
2
|
-
import { CreateSplitInputSchema, CreateSplitOutputSchema } from "../schemas";
|
|
3
|
-
import { ORPCError } from "@orpc/server";
|
|
4
|
-
import { env } from "@/lib/env";
|
|
5
|
-
import { createSolanaConnection } from "@/lib/solana";
|
|
6
|
-
import { connectToDb } from "@/lib/utils/db";
|
|
7
|
-
import { scheduleToUtcCron } from "@/lib/utils/misc";
|
|
8
|
-
import { getAssetIdFromPubkey } from "@/lib/utils/hotspot-helpers";
|
|
9
|
-
import {
|
|
10
|
-
initializeCompressionRecipient,
|
|
11
|
-
init as initLd,
|
|
12
|
-
recipientKey,
|
|
13
|
-
updateCompressionDestination,
|
|
14
|
-
} from "@helium/lazy-distributor-sdk";
|
|
15
|
-
import { init as initMiniFanout } from "@helium/mini-fanout-sdk";
|
|
16
|
-
import {
|
|
17
|
-
batchInstructionsToTxsWithPriorityFee,
|
|
18
|
-
HELIUM_COMMON_LUT,
|
|
19
|
-
HELIUM_COMMON_LUT_DEVNET,
|
|
20
|
-
HNT_MINT,
|
|
21
|
-
toVersionedTx,
|
|
22
|
-
} from "@helium/spl-utils";
|
|
23
|
-
import {
|
|
24
|
-
init as initTuktuk,
|
|
25
|
-
nextAvailableTaskIds,
|
|
26
|
-
taskKey,
|
|
27
|
-
} from "@helium/tuktuk-sdk";
|
|
28
|
-
import {
|
|
29
|
-
PublicKey,
|
|
30
|
-
SystemProgram,
|
|
31
|
-
TransactionInstruction,
|
|
32
|
-
} from "@solana/web3.js";
|
|
33
|
-
import BN from "bn.js";
|
|
34
|
-
import {
|
|
35
|
-
generateTransactionTag,
|
|
36
|
-
TRANSACTION_TYPES,
|
|
37
|
-
} from "@/lib/utils/transaction-tags";
|
|
38
|
-
import {
|
|
39
|
-
getCluster,
|
|
40
|
-
getJitoTipTransaction,
|
|
41
|
-
shouldUseJitoBundle,
|
|
42
|
-
} from "@/lib/utils/transaction-submission";
|
|
43
|
-
|
|
44
|
-
const TASK_QUEUE_ID = new PublicKey(
|
|
45
|
-
"H39gEszvsi6AT4rYBiJTuZHJSF5hMHy6CKGTd7wzhsg7",
|
|
46
|
-
);
|
|
47
|
-
const FANOUT_FUNDING_AMOUNT = 10000000; // 0.01 SOL
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Create a split configuration for a hotspot with reward distribution.
|
|
51
|
-
*/
|
|
52
|
-
export const createSplit = publicProcedure
|
|
53
|
-
.route({
|
|
54
|
-
method: "POST",
|
|
55
|
-
path: "/hotspots/wallet/{walletAddress}/{hotspotPubkey}/split",
|
|
56
|
-
})
|
|
57
|
-
.input(CreateSplitInputSchema)
|
|
58
|
-
.output(CreateSplitOutputSchema)
|
|
59
|
-
.errors({
|
|
60
|
-
NOT_FOUND: { message: "Hotspot not found" },
|
|
61
|
-
BAD_REQUEST: { message: "Invalid request" },
|
|
62
|
-
INSUFFICIENT_FUNDS: {
|
|
63
|
-
message: "Insufficient SOL balance to fund split setup",
|
|
64
|
-
},
|
|
65
|
-
})
|
|
66
|
-
.handler(async ({ input, errors }) => {
|
|
67
|
-
const {
|
|
68
|
-
walletAddress,
|
|
69
|
-
hotspotPubkey,
|
|
70
|
-
rewardsSplit,
|
|
71
|
-
schedule,
|
|
72
|
-
lazyDistributor,
|
|
73
|
-
} = input;
|
|
74
|
-
|
|
75
|
-
await connectToDb();
|
|
76
|
-
|
|
77
|
-
// Resolve hotspot pubkey to asset ID
|
|
78
|
-
const assetId = await getAssetIdFromPubkey(hotspotPubkey);
|
|
79
|
-
if (!assetId) {
|
|
80
|
-
throw errors.NOT_FOUND({ message: "Hotspot not found" });
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (!rewardsSplit?.length) {
|
|
84
|
-
throw errors.BAD_REQUEST({
|
|
85
|
-
message: "At least one reward split is required",
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (!schedule?.frequency || !schedule?.time || !schedule?.timezone) {
|
|
90
|
-
throw errors.BAD_REQUEST({
|
|
91
|
-
message: "Schedule frequency, time, and timezone are required",
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Build connection and programs
|
|
96
|
-
const { provider, wallet } = createSolanaConnection(walletAddress);
|
|
97
|
-
const miniFanoutProgram = await initMiniFanout(provider);
|
|
98
|
-
const tuktukProgram = await initTuktuk(provider);
|
|
99
|
-
const ldProgram = await initLd(provider);
|
|
100
|
-
|
|
101
|
-
// Convert schedule to UTC cron string
|
|
102
|
-
const rewardsSchedule = scheduleToUtcCron(schedule);
|
|
103
|
-
|
|
104
|
-
// Ensure Lazy Distributor Recipient exists for the asset
|
|
105
|
-
const recipientK = recipientKey(
|
|
106
|
-
new PublicKey(lazyDistributor),
|
|
107
|
-
new PublicKey(assetId),
|
|
108
|
-
)[0];
|
|
109
|
-
const recipientAcc =
|
|
110
|
-
await ldProgram.account.recipientV0.fetchNullable(recipientK);
|
|
111
|
-
const instructions: TransactionInstruction[] = [];
|
|
112
|
-
|
|
113
|
-
if (!recipientAcc) {
|
|
114
|
-
instructions.push(
|
|
115
|
-
await (
|
|
116
|
-
await initializeCompressionRecipient({
|
|
117
|
-
program: ldProgram,
|
|
118
|
-
assetId: new PublicKey(assetId),
|
|
119
|
-
payer: wallet.publicKey,
|
|
120
|
-
assetEndpoint: env.SOLANA_RPC_URL,
|
|
121
|
-
lazyDistributor: new PublicKey(lazyDistributor),
|
|
122
|
-
})
|
|
123
|
-
).instruction(),
|
|
124
|
-
);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const oracleSigner = new PublicKey(process.env.ORACLE_SIGNER!);
|
|
128
|
-
const oracleUrl = process.env.ORACLE_URL!;
|
|
129
|
-
|
|
130
|
-
const { instruction: initIx, pubkeys } = await miniFanoutProgram.methods
|
|
131
|
-
.initializeMiniFanoutV0({
|
|
132
|
-
seed: new PublicKey(assetId).toBuffer(),
|
|
133
|
-
shares: rewardsSplit.map((split) => ({
|
|
134
|
-
wallet: new PublicKey(split.address),
|
|
135
|
-
share:
|
|
136
|
-
split.type === "fixed"
|
|
137
|
-
? { fixed: { amount: new BN(split.amount) } }
|
|
138
|
-
: { share: { amount: split.amount } },
|
|
139
|
-
})),
|
|
140
|
-
schedule: rewardsSchedule,
|
|
141
|
-
preTask: {
|
|
142
|
-
remoteV0: {
|
|
143
|
-
url: `${oracleUrl}/v1/tuktuk/asset/${assetId}`,
|
|
144
|
-
signer: oracleSigner,
|
|
145
|
-
},
|
|
146
|
-
},
|
|
147
|
-
})
|
|
148
|
-
.accounts({
|
|
149
|
-
payer: wallet.publicKey,
|
|
150
|
-
owner: wallet.publicKey,
|
|
151
|
-
taskQueue: TASK_QUEUE_ID,
|
|
152
|
-
rentRefund: wallet.publicKey,
|
|
153
|
-
mint: HNT_MINT,
|
|
154
|
-
})
|
|
155
|
-
.prepare();
|
|
156
|
-
instructions.push(initIx);
|
|
157
|
-
|
|
158
|
-
// Ensure the user's wallet has enough SOL to fund the mini fanout rent
|
|
159
|
-
const balance = await provider.connection.getBalance(
|
|
160
|
-
new PublicKey(walletAddress),
|
|
161
|
-
);
|
|
162
|
-
if (balance < FANOUT_FUNDING_AMOUNT) {
|
|
163
|
-
throw errors.INSUFFICIENT_FUNDS({
|
|
164
|
-
message: "Insufficient SOL balance to fund split setup",
|
|
165
|
-
data: {
|
|
166
|
-
balance,
|
|
167
|
-
required: FANOUT_FUNDING_AMOUNT,
|
|
168
|
-
},
|
|
169
|
-
});
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
instructions.push(
|
|
173
|
-
SystemProgram.transfer({
|
|
174
|
-
fromPubkey: wallet.publicKey,
|
|
175
|
-
toPubkey: pubkeys.miniFanout!,
|
|
176
|
-
lamports: FANOUT_FUNDING_AMOUNT,
|
|
177
|
-
}),
|
|
178
|
-
);
|
|
179
|
-
|
|
180
|
-
const taskQueueAcc =
|
|
181
|
-
await tuktukProgram.account.taskQueueV0.fetchNullable(TASK_QUEUE_ID);
|
|
182
|
-
const [taskId, preTaskId] = nextAvailableTaskIds(
|
|
183
|
-
taskQueueAcc!.taskBitmap,
|
|
184
|
-
2,
|
|
185
|
-
);
|
|
186
|
-
|
|
187
|
-
// Schedule a task for the mini fanout
|
|
188
|
-
const scheduleIx = await (
|
|
189
|
-
await miniFanoutProgram.methods
|
|
190
|
-
.scheduleTaskV0({
|
|
191
|
-
program: miniFanoutProgram,
|
|
192
|
-
miniFanout: pubkeys.miniFanout!,
|
|
193
|
-
taskId,
|
|
194
|
-
preTaskId,
|
|
195
|
-
})
|
|
196
|
-
.accounts({
|
|
197
|
-
taskQueue: TASK_QUEUE_ID,
|
|
198
|
-
payer: wallet.publicKey,
|
|
199
|
-
miniFanout: pubkeys.miniFanout!,
|
|
200
|
-
task: taskKey(TASK_QUEUE_ID, taskId)[0],
|
|
201
|
-
preTask: taskKey(TASK_QUEUE_ID, preTaskId)[0],
|
|
202
|
-
nextTask: pubkeys.miniFanout!,
|
|
203
|
-
nextPreTask: pubkeys.miniFanout!,
|
|
204
|
-
})
|
|
205
|
-
).instruction();
|
|
206
|
-
instructions.push(scheduleIx);
|
|
207
|
-
|
|
208
|
-
// Point hotspot rewards destination to the mini fanout
|
|
209
|
-
const setRecipientIx = await (
|
|
210
|
-
await updateCompressionDestination({
|
|
211
|
-
program: ldProgram,
|
|
212
|
-
assetId: new PublicKey(assetId),
|
|
213
|
-
lazyDistributor: new PublicKey(lazyDistributor),
|
|
214
|
-
destination: pubkeys.miniFanout!,
|
|
215
|
-
})
|
|
216
|
-
).instruction();
|
|
217
|
-
instructions.push(setRecipientIx);
|
|
218
|
-
|
|
219
|
-
const txs = (
|
|
220
|
-
await batchInstructionsToTxsWithPriorityFee(provider, instructions, {
|
|
221
|
-
addressLookupTableAddresses: [
|
|
222
|
-
process.env.NEXT_PUBLIC_SOLANA_CLUSTER === "devnet"
|
|
223
|
-
? HELIUM_COMMON_LUT_DEVNET
|
|
224
|
-
: HELIUM_COMMON_LUT,
|
|
225
|
-
],
|
|
226
|
-
})
|
|
227
|
-
).map((tx) => toVersionedTx(tx));
|
|
228
|
-
|
|
229
|
-
const tag = generateTransactionTag({
|
|
230
|
-
type: TRANSACTION_TYPES.ADD_SPLIT,
|
|
231
|
-
walletAddress,
|
|
232
|
-
assetId,
|
|
233
|
-
lazyDistributor,
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
if (shouldUseJitoBundle(txs.length, getCluster())) {
|
|
237
|
-
txs.push(await getJitoTipTransaction(new PublicKey(walletAddress)));
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
return {
|
|
241
|
-
transactionData: {
|
|
242
|
-
transactions: txs.map((tx) => ({
|
|
243
|
-
serializedTransaction: Buffer.from(tx.serialize()).toString("base64"),
|
|
244
|
-
metadata: {
|
|
245
|
-
type: "add_split",
|
|
246
|
-
description: "Create split",
|
|
247
|
-
},
|
|
248
|
-
})),
|
|
249
|
-
parallel: true,
|
|
250
|
-
tag,
|
|
251
|
-
},
|
|
252
|
-
};
|
|
253
|
-
});
|
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
import { publicProcedure } from "../../../procedures";
|
|
2
|
-
import { DeleteSplitInputSchema, DeleteSplitOutputSchema } from "../schemas";
|
|
3
|
-
import { ORPCError } from "@orpc/server";
|
|
4
|
-
import { connectToDb } from "@/lib/utils/db";
|
|
5
|
-
import { AssetOwner } from "@/lib/models/hotspot";
|
|
6
|
-
import { MiniFanout } from "@/lib/models/mini-fanout";
|
|
7
|
-
import { Recipient } from "@/lib/models/recipient";
|
|
8
|
-
import { createSolanaConnection } from "@/lib/solana";
|
|
9
|
-
import { getAssetIdFromPubkey } from "@/lib/utils/hotspot-helpers";
|
|
10
|
-
import {
|
|
11
|
-
init as initLd,
|
|
12
|
-
updateCompressionDestination,
|
|
13
|
-
} from "@helium/lazy-distributor-sdk";
|
|
14
|
-
import { init as initMiniFanout } from "@helium/mini-fanout-sdk";
|
|
15
|
-
import {
|
|
16
|
-
HELIUM_COMMON_LUT,
|
|
17
|
-
HELIUM_COMMON_LUT_DEVNET,
|
|
18
|
-
populateMissingDraftInfo,
|
|
19
|
-
toVersionedTx,
|
|
20
|
-
withPriorityFees,
|
|
21
|
-
} from "@helium/spl-utils";
|
|
22
|
-
import { init as initTuktuk } from "@helium/tuktuk-sdk";
|
|
23
|
-
import { PublicKey } from "@solana/web3.js";
|
|
24
|
-
import {
|
|
25
|
-
generateTransactionTag,
|
|
26
|
-
TRANSACTION_TYPES,
|
|
27
|
-
} from "@/lib/utils/transaction-tags";
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Remove the split configuration from a hotspot.
|
|
31
|
-
*/
|
|
32
|
-
export const deleteSplit = publicProcedure
|
|
33
|
-
.route({
|
|
34
|
-
method: "DELETE",
|
|
35
|
-
path: "/hotspots/wallet/{walletAddress}/{hotspotPubkey}/split",
|
|
36
|
-
})
|
|
37
|
-
.input(DeleteSplitInputSchema)
|
|
38
|
-
.output(DeleteSplitOutputSchema)
|
|
39
|
-
.errors({
|
|
40
|
-
NOT_FOUND: { message: "Hotspot not found" },
|
|
41
|
-
NO_SPLIT: { message: "Hotspot does not have a split" },
|
|
42
|
-
})
|
|
43
|
-
.handler(async ({ input, errors }) => {
|
|
44
|
-
const { walletAddress, hotspotPubkey } = input;
|
|
45
|
-
|
|
46
|
-
await connectToDb();
|
|
47
|
-
|
|
48
|
-
// Resolve hotspot pubkey to asset ID
|
|
49
|
-
const assetId = await getAssetIdFromPubkey(hotspotPubkey);
|
|
50
|
-
if (!assetId) {
|
|
51
|
-
throw errors.NOT_FOUND({ message: "Hotspot not found" });
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Find the hotspot
|
|
55
|
-
const assetOwner = await AssetOwner.findOne({
|
|
56
|
-
where: { asset: assetId },
|
|
57
|
-
include: [
|
|
58
|
-
{
|
|
59
|
-
model: Recipient,
|
|
60
|
-
as: "recipient",
|
|
61
|
-
required: true,
|
|
62
|
-
include: [
|
|
63
|
-
{
|
|
64
|
-
model: MiniFanout,
|
|
65
|
-
as: "split",
|
|
66
|
-
required: true,
|
|
67
|
-
},
|
|
68
|
-
],
|
|
69
|
-
},
|
|
70
|
-
],
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
if (!assetOwner) {
|
|
74
|
-
throw errors.NOT_FOUND({ message: "Hotspot not found" });
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (!assetOwner.recipient?.split) {
|
|
78
|
-
throw errors.NO_SPLIT({ message: "Hotspot does not have a split" });
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const { provider, connection } = createSolanaConnection(walletAddress);
|
|
82
|
-
const program = await initMiniFanout(provider);
|
|
83
|
-
const miniFanoutK = new PublicKey(assetOwner.recipient.split.address);
|
|
84
|
-
const miniFanout =
|
|
85
|
-
await program.account.miniFanoutV0.fetchNullable(miniFanoutK);
|
|
86
|
-
|
|
87
|
-
if (!miniFanout) {
|
|
88
|
-
throw errors.NOT_FOUND({ message: "Fanout not found" });
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const tuktukProgram = await initTuktuk(provider);
|
|
92
|
-
|
|
93
|
-
// Create the transaction to remove the mini fanout
|
|
94
|
-
const task = miniFanout.nextTask.equals(miniFanoutK)
|
|
95
|
-
? null
|
|
96
|
-
: await tuktukProgram.account.taskV0.fetchNullable(miniFanout.nextTask);
|
|
97
|
-
|
|
98
|
-
const closeIx = await program.methods
|
|
99
|
-
.closeMiniFanoutV0()
|
|
100
|
-
.accounts({
|
|
101
|
-
miniFanout: miniFanoutK,
|
|
102
|
-
taskRentRefund: task?.rentRefund || walletAddress,
|
|
103
|
-
})
|
|
104
|
-
.instruction();
|
|
105
|
-
|
|
106
|
-
const ldProgram = await initLd(provider);
|
|
107
|
-
const setRecipientIx = await (
|
|
108
|
-
await updateCompressionDestination({
|
|
109
|
-
program: ldProgram,
|
|
110
|
-
assetId: new PublicKey(assetId),
|
|
111
|
-
lazyDistributor: new PublicKey(assetOwner.recipient.lazyDistributor),
|
|
112
|
-
destination: null,
|
|
113
|
-
})
|
|
114
|
-
).instruction();
|
|
115
|
-
|
|
116
|
-
const draft = {
|
|
117
|
-
instructions: [closeIx, setRecipientIx],
|
|
118
|
-
feePayer: new PublicKey(walletAddress),
|
|
119
|
-
addressLookupTableAddresses: [
|
|
120
|
-
process.env.NEXT_PUBLIC_SOLANA_CLUSTER === "devnet"
|
|
121
|
-
? HELIUM_COMMON_LUT_DEVNET
|
|
122
|
-
: HELIUM_COMMON_LUT,
|
|
123
|
-
],
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
const tx = toVersionedTx(
|
|
127
|
-
await populateMissingDraftInfo(connection, {
|
|
128
|
-
...draft,
|
|
129
|
-
instructions: await withPriorityFees({ ...draft, connection }),
|
|
130
|
-
}),
|
|
131
|
-
);
|
|
132
|
-
|
|
133
|
-
const tag = generateTransactionTag({
|
|
134
|
-
type: TRANSACTION_TYPES.REMOVE_SPLIT,
|
|
135
|
-
walletAddress,
|
|
136
|
-
assetId,
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
return {
|
|
140
|
-
transactionData: {
|
|
141
|
-
transactions: [
|
|
142
|
-
{
|
|
143
|
-
serializedTransaction: Buffer.from(tx.serialize()).toString(
|
|
144
|
-
"base64",
|
|
145
|
-
),
|
|
146
|
-
metadata: {
|
|
147
|
-
type: "remove_split",
|
|
148
|
-
description: "Remove split",
|
|
149
|
-
},
|
|
150
|
-
},
|
|
151
|
-
],
|
|
152
|
-
parallel: true,
|
|
153
|
-
tag,
|
|
154
|
-
},
|
|
155
|
-
};
|
|
156
|
-
});
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { publicProcedure } from "../../../procedures";
|
|
2
|
-
import { GetHotspotsInputSchema, HotspotsDataSchema } from "../schemas";
|
|
3
|
-
import { getHotspotsByOwner } from "@/lib/queries/hotspots";
|
|
4
|
-
import { ORPCError } from "@orpc/server";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Get hotspots by wallet address with optional filtering and pagination.
|
|
8
|
-
*/
|
|
9
|
-
export const getHotspots = publicProcedure
|
|
10
|
-
.route({ method: "GET", path: "/hotspots/wallet/{walletAddress}" })
|
|
11
|
-
.input(GetHotspotsInputSchema)
|
|
12
|
-
.output(HotspotsDataSchema)
|
|
13
|
-
.errors({
|
|
14
|
-
BAD_REQUEST: { message: "Invalid wallet address" },
|
|
15
|
-
})
|
|
16
|
-
.handler(async ({ input }) => {
|
|
17
|
-
const { walletAddress, type, page, limit } = input;
|
|
18
|
-
|
|
19
|
-
if (!walletAddress || walletAddress.length < 32) {
|
|
20
|
-
throw new ORPCError("BAD_REQUEST", { message: "Invalid wallet address" });
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const hotspots = await getHotspotsByOwner({
|
|
24
|
-
owner: walletAddress,
|
|
25
|
-
type,
|
|
26
|
-
page,
|
|
27
|
-
limit,
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
return hotspots;
|
|
31
|
-
});
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { publicProcedure } from "../../../procedures";
|
|
2
|
-
import {
|
|
3
|
-
GetPendingRewardsInputSchema,
|
|
4
|
-
PendingRewardsOutputSchema,
|
|
5
|
-
} from "../schemas";
|
|
6
|
-
import { ORPCError } from "@orpc/server";
|
|
7
|
-
import { env } from "@/lib/env";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Get pending rewards for all hotspots in a wallet.
|
|
11
|
-
* Proxies to the oracle's rewards endpoint.
|
|
12
|
-
*/
|
|
13
|
-
export const getPendingRewards = publicProcedure
|
|
14
|
-
.route({
|
|
15
|
-
method: "GET",
|
|
16
|
-
path: "/hotspots/wallet/{walletAddress}/pending-rewards",
|
|
17
|
-
})
|
|
18
|
-
.input(GetPendingRewardsInputSchema)
|
|
19
|
-
.output(PendingRewardsOutputSchema)
|
|
20
|
-
.errors({
|
|
21
|
-
BAD_REQUEST: { message: "Invalid wallet address" },
|
|
22
|
-
ORACLE_ERROR: { message: "Oracle request failed" },
|
|
23
|
-
})
|
|
24
|
-
.handler(async ({ input, errors }) => {
|
|
25
|
-
const { walletAddress } = input;
|
|
26
|
-
|
|
27
|
-
if (!walletAddress || walletAddress.length < 32) {
|
|
28
|
-
throw new ORPCError("BAD_REQUEST", { message: "Invalid wallet address" });
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const oracleBase = env.ORACLE_URL;
|
|
32
|
-
const url = new URL(`${oracleBase}/rewards`);
|
|
33
|
-
url.searchParams.set("destination", walletAddress);
|
|
34
|
-
|
|
35
|
-
const oracleRes = await fetch(url.toString());
|
|
36
|
-
if (!oracleRes.ok) {
|
|
37
|
-
throw errors.ORACLE_ERROR({
|
|
38
|
-
message: `Oracle request failed (${oracleRes.status})`,
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const data = await oracleRes.json();
|
|
43
|
-
return data;
|
|
44
|
-
});
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { publicProcedure } from "../../../procedures";
|
|
2
|
-
import { GetSplitInputSchema, SplitResponseSchema } from "../schemas";
|
|
3
|
-
import { connectToDb } from "@/lib/utils/db";
|
|
4
|
-
import { AssetOwner } from "@/lib/models/hotspot";
|
|
5
|
-
import { MiniFanout } from "@/lib/models/mini-fanout";
|
|
6
|
-
import { Recipient } from "@/lib/models/recipient";
|
|
7
|
-
import { getAssetIdFromPubkey } from "@/lib/utils/hotspot-helpers";
|
|
8
|
-
|
|
9
|
-
interface MiniFanoutShare {
|
|
10
|
-
wallet: string;
|
|
11
|
-
delegate: string;
|
|
12
|
-
share?: {
|
|
13
|
-
fixed?: { amount?: string | number };
|
|
14
|
-
share?: { amount?: number };
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Get the split configuration for a hotspot.
|
|
20
|
-
*/
|
|
21
|
-
export const getSplit = publicProcedure
|
|
22
|
-
.route({
|
|
23
|
-
method: "GET",
|
|
24
|
-
path: "/hotspots/wallet/{walletAddress}/{hotspotPubkey}/split",
|
|
25
|
-
})
|
|
26
|
-
.input(GetSplitInputSchema)
|
|
27
|
-
.output(SplitResponseSchema)
|
|
28
|
-
.errors({
|
|
29
|
-
NOT_FOUND: { message: "Hotspot not found or does not have a split" },
|
|
30
|
-
})
|
|
31
|
-
.handler(async ({ input, errors }) => {
|
|
32
|
-
const { walletAddress, hotspotPubkey } = input;
|
|
33
|
-
|
|
34
|
-
await connectToDb();
|
|
35
|
-
|
|
36
|
-
// Resolve hotspot pubkey to asset ID
|
|
37
|
-
const assetId = await getAssetIdFromPubkey(hotspotPubkey);
|
|
38
|
-
if (!assetId) {
|
|
39
|
-
throw errors.NOT_FOUND({ message: "Hotspot not found" });
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Look up the asset and ensure it has a mini fanout configured
|
|
43
|
-
const assetOwner = await AssetOwner.findOne({
|
|
44
|
-
where: { asset: assetId },
|
|
45
|
-
include: [
|
|
46
|
-
{
|
|
47
|
-
model: Recipient,
|
|
48
|
-
as: "recipient",
|
|
49
|
-
required: true,
|
|
50
|
-
include: [
|
|
51
|
-
{
|
|
52
|
-
model: MiniFanout,
|
|
53
|
-
as: "split",
|
|
54
|
-
required: true,
|
|
55
|
-
},
|
|
56
|
-
],
|
|
57
|
-
},
|
|
58
|
-
],
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
if (!assetOwner?.recipient?.split) {
|
|
62
|
-
throw errors.NOT_FOUND({ message: "Hotspot does not have a split" });
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const shares = assetOwner.recipient.split.shares as MiniFanoutShare[];
|
|
66
|
-
|
|
67
|
-
const totalShares = shares.reduce(
|
|
68
|
-
(acc: number, share: MiniFanoutShare) =>
|
|
69
|
-
acc + (share.share?.share?.amount || 0),
|
|
70
|
-
0,
|
|
71
|
-
);
|
|
72
|
-
|
|
73
|
-
return {
|
|
74
|
-
walletAddress,
|
|
75
|
-
hotspotPubkey,
|
|
76
|
-
splitAddress: assetOwner.recipient.split.address,
|
|
77
|
-
shares: shares.map((share: MiniFanoutShare) => ({
|
|
78
|
-
wallet: share.wallet,
|
|
79
|
-
delegate: share.delegate,
|
|
80
|
-
fixed: share.share?.fixed?.amount
|
|
81
|
-
? Number(share.share.fixed.amount)
|
|
82
|
-
: 0,
|
|
83
|
-
shares: share.share?.share?.amount
|
|
84
|
-
? share.share.share.amount / totalShares
|
|
85
|
-
: 0,
|
|
86
|
-
})),
|
|
87
|
-
};
|
|
88
|
-
});
|