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