stelagent 0.0.4 → 0.0.5
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/dist/index.mjs +244 -41
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -324,7 +324,7 @@ z.enum(["asc", "desc"]).default("desc");
|
|
|
324
324
|
z.coerce.number().int().min(6e4);
|
|
325
325
|
//#endregion
|
|
326
326
|
//#region src/commands/wallet-login.ts
|
|
327
|
-
function formatZodError$
|
|
327
|
+
function formatZodError$12(e) {
|
|
328
328
|
return e.issues.map((issue) => issue.message).join(", ");
|
|
329
329
|
}
|
|
330
330
|
const walletLogin = defineCommand({
|
|
@@ -355,7 +355,7 @@ const walletLogin = defineCommand({
|
|
|
355
355
|
catch: (e) => e
|
|
356
356
|
});
|
|
357
357
|
if (Result.isError(validation)) {
|
|
358
|
-
const msg = validation.error instanceof z.ZodError ? formatZodError$
|
|
358
|
+
const msg = validation.error instanceof z.ZodError ? formatZodError$12(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
|
|
359
359
|
printResult(Result.err(msg), format);
|
|
360
360
|
return;
|
|
361
361
|
}
|
|
@@ -534,7 +534,7 @@ const walletAddress = defineCommand({
|
|
|
534
534
|
});
|
|
535
535
|
//#endregion
|
|
536
536
|
//#region src/services/stellar.ts
|
|
537
|
-
const HORIZON_URLS$
|
|
537
|
+
const HORIZON_URLS$2 = {
|
|
538
538
|
testnet: process.env.STELAGENT_HORIZON_TESTNET_URL ?? "https://horizon-testnet.stellar.org",
|
|
539
539
|
pubnet: process.env.STELAGENT_HORIZON_PUBNET_URL ?? "https://horizon-mainnet.stellar.org"
|
|
540
540
|
};
|
|
@@ -574,7 +574,7 @@ async function getBalances(publicKey, network) {
|
|
|
574
574
|
return Result.tryPromise({
|
|
575
575
|
try: async () => {
|
|
576
576
|
const { Horizon } = await import("@stellar/stellar-sdk");
|
|
577
|
-
return (await new Horizon.Server(HORIZON_URLS$
|
|
577
|
+
return (await new Horizon.Server(HORIZON_URLS$2[network]).loadAccount(publicKey)).balances.map((b) => ({
|
|
578
578
|
assetType: b.asset_type,
|
|
579
579
|
assetCode: b.asset_type === "native" ? "XLM" : "asset_code" in b && typeof b.asset_code === "string" ? b.asset_code : "",
|
|
580
580
|
balance: b.balance
|
|
@@ -587,7 +587,7 @@ async function transferXlm(sourceSecret, destination, amount, network) {
|
|
|
587
587
|
return Result.tryPromise({
|
|
588
588
|
try: async () => {
|
|
589
589
|
const { Keypair, Asset, Operation, TransactionBuilder, Horizon } = await import("@stellar/stellar-sdk");
|
|
590
|
-
const server = new Horizon.Server(HORIZON_URLS$
|
|
590
|
+
const server = new Horizon.Server(HORIZON_URLS$2[network]);
|
|
591
591
|
const sourceKp = Keypair.fromSecret(sourceSecret);
|
|
592
592
|
let sourceAccount;
|
|
593
593
|
try {
|
|
@@ -624,7 +624,7 @@ async function sendPayment(sourceSecret, destination, amount, assetStr, network,
|
|
|
624
624
|
return Result.tryPromise({
|
|
625
625
|
try: async () => {
|
|
626
626
|
const { Keypair, Operation, TransactionBuilder, Horizon, Memo } = await import("@stellar/stellar-sdk");
|
|
627
|
-
const server = new Horizon.Server(HORIZON_URLS$
|
|
627
|
+
const server = new Horizon.Server(HORIZON_URLS$2[network]);
|
|
628
628
|
const sourceKp = Keypair.fromSecret(sourceSecret);
|
|
629
629
|
let sourceAccount;
|
|
630
630
|
try {
|
|
@@ -686,7 +686,7 @@ const walletBalance = defineCommand({
|
|
|
686
686
|
});
|
|
687
687
|
//#endregion
|
|
688
688
|
//#region src/commands/wallet-transfer.ts
|
|
689
|
-
function formatZodError$
|
|
689
|
+
function formatZodError$11(e) {
|
|
690
690
|
return e.issues.map((issue) => issue.message).join(", ");
|
|
691
691
|
}
|
|
692
692
|
//#endregion
|
|
@@ -733,7 +733,7 @@ const walletCommand = defineCommand({
|
|
|
733
733
|
catch: (e) => e
|
|
734
734
|
});
|
|
735
735
|
if (Result.isError(validation)) {
|
|
736
|
-
const msg = validation.error instanceof z.ZodError ? formatZodError$
|
|
736
|
+
const msg = validation.error instanceof z.ZodError ? formatZodError$11(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
|
|
737
737
|
printResult(Result.err(msg), format);
|
|
738
738
|
return;
|
|
739
739
|
}
|
|
@@ -843,7 +843,7 @@ async function pay(url) {
|
|
|
843
843
|
}
|
|
844
844
|
//#endregion
|
|
845
845
|
//#region src/commands/pay.ts
|
|
846
|
-
function formatZodError$
|
|
846
|
+
function formatZodError$10(e) {
|
|
847
847
|
return e.issues.map((issue) => issue.message).join(", ");
|
|
848
848
|
}
|
|
849
849
|
const payCommand = defineCommand({
|
|
@@ -867,7 +867,7 @@ const payCommand = defineCommand({
|
|
|
867
867
|
catch: (e) => e
|
|
868
868
|
});
|
|
869
869
|
if (Result.isError(validation)) {
|
|
870
|
-
const msg = validation.error instanceof z.ZodError ? formatZodError$
|
|
870
|
+
const msg = validation.error instanceof z.ZodError ? formatZodError$10(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
|
|
871
871
|
printResult(Result.err(msg), format);
|
|
872
872
|
return;
|
|
873
873
|
}
|
|
@@ -880,12 +880,12 @@ const payCommand = defineCommand({
|
|
|
880
880
|
});
|
|
881
881
|
//#endregion
|
|
882
882
|
//#region src/services/horizon.ts
|
|
883
|
-
const HORIZON_URLS = {
|
|
883
|
+
const HORIZON_URLS$1 = {
|
|
884
884
|
testnet: process.env.STELAGENT_HORIZON_TESTNET_URL ?? "https://horizon-testnet.stellar.org",
|
|
885
885
|
pubnet: process.env.STELAGENT_HORIZON_PUBNET_URL ?? "https://horizon-mainnet.stellar.org"
|
|
886
886
|
};
|
|
887
887
|
function horizonServer(network) {
|
|
888
|
-
return new Horizon.Server(HORIZON_URLS[network]);
|
|
888
|
+
return new Horizon.Server(HORIZON_URLS$1[network]);
|
|
889
889
|
}
|
|
890
890
|
function classifyHorizonError(e, address) {
|
|
891
891
|
const message = e instanceof Error ? e.message : String(e);
|
|
@@ -1114,7 +1114,7 @@ function streamEffects(publicKey, network, opts, onMessage, onError) {
|
|
|
1114
1114
|
}
|
|
1115
1115
|
//#endregion
|
|
1116
1116
|
//#region src/commands/account-details.ts
|
|
1117
|
-
function formatZodError$
|
|
1117
|
+
function formatZodError$9(e) {
|
|
1118
1118
|
return e.issues.map((issue) => issue.message).join(", ");
|
|
1119
1119
|
}
|
|
1120
1120
|
const accountDetails = defineCommand({
|
|
@@ -1145,7 +1145,7 @@ const accountDetails = defineCommand({
|
|
|
1145
1145
|
catch: (e) => e
|
|
1146
1146
|
});
|
|
1147
1147
|
if (Result.isError(validation)) {
|
|
1148
|
-
const msg = validation.error instanceof z.ZodError ? formatZodError$
|
|
1148
|
+
const msg = validation.error instanceof z.ZodError ? formatZodError$9(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
|
|
1149
1149
|
printResult(Result.err(msg), format);
|
|
1150
1150
|
return;
|
|
1151
1151
|
}
|
|
@@ -1158,7 +1158,7 @@ const accountDetails = defineCommand({
|
|
|
1158
1158
|
});
|
|
1159
1159
|
//#endregion
|
|
1160
1160
|
//#region src/commands/account-transactions.ts
|
|
1161
|
-
function formatZodError$
|
|
1161
|
+
function formatZodError$8(e) {
|
|
1162
1162
|
return e.issues.map((issue) => issue.message).join(", ");
|
|
1163
1163
|
}
|
|
1164
1164
|
const accountTransactions = defineCommand({
|
|
@@ -1206,7 +1206,7 @@ const accountTransactions = defineCommand({
|
|
|
1206
1206
|
catch: (e) => e
|
|
1207
1207
|
});
|
|
1208
1208
|
if (Result.isError(validation)) {
|
|
1209
|
-
const msg = validation.error instanceof z.ZodError ? formatZodError$
|
|
1209
|
+
const msg = validation.error instanceof z.ZodError ? formatZodError$8(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
|
|
1210
1210
|
printResult(Result.err(msg), format);
|
|
1211
1211
|
return;
|
|
1212
1212
|
}
|
|
@@ -1227,7 +1227,7 @@ const accountTransactions = defineCommand({
|
|
|
1227
1227
|
});
|
|
1228
1228
|
//#endregion
|
|
1229
1229
|
//#region src/commands/account-payments.ts
|
|
1230
|
-
function formatZodError$
|
|
1230
|
+
function formatZodError$7(e) {
|
|
1231
1231
|
return e.issues.map((issue) => issue.message).join(", ");
|
|
1232
1232
|
}
|
|
1233
1233
|
const accountPayments = defineCommand({
|
|
@@ -1275,7 +1275,7 @@ const accountPayments = defineCommand({
|
|
|
1275
1275
|
catch: (e) => e
|
|
1276
1276
|
});
|
|
1277
1277
|
if (Result.isError(validation)) {
|
|
1278
|
-
const msg = validation.error instanceof z.ZodError ? formatZodError$
|
|
1278
|
+
const msg = validation.error instanceof z.ZodError ? formatZodError$7(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
|
|
1279
1279
|
printResult(Result.err(msg), format);
|
|
1280
1280
|
return;
|
|
1281
1281
|
}
|
|
@@ -1296,7 +1296,7 @@ const accountPayments = defineCommand({
|
|
|
1296
1296
|
});
|
|
1297
1297
|
//#endregion
|
|
1298
1298
|
//#region src/commands/account-effects.ts
|
|
1299
|
-
function formatZodError$
|
|
1299
|
+
function formatZodError$6(e) {
|
|
1300
1300
|
return e.issues.map((issue) => issue.message).join(", ");
|
|
1301
1301
|
}
|
|
1302
1302
|
//#endregion
|
|
@@ -1349,7 +1349,7 @@ const accountCommand = defineCommand({
|
|
|
1349
1349
|
catch: (e) => e
|
|
1350
1350
|
});
|
|
1351
1351
|
if (Result.isError(validation)) {
|
|
1352
|
-
const msg = validation.error instanceof z.ZodError ? formatZodError$
|
|
1352
|
+
const msg = validation.error instanceof z.ZodError ? formatZodError$6(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
|
|
1353
1353
|
printResult(Result.err(msg), format);
|
|
1354
1354
|
return;
|
|
1355
1355
|
}
|
|
@@ -1371,7 +1371,7 @@ const accountCommand = defineCommand({
|
|
|
1371
1371
|
});
|
|
1372
1372
|
//#endregion
|
|
1373
1373
|
//#region src/commands/assets-search.ts
|
|
1374
|
-
function formatZodError$
|
|
1374
|
+
function formatZodError$5(e) {
|
|
1375
1375
|
return e.issues.map((issue) => issue.message).join(", ");
|
|
1376
1376
|
}
|
|
1377
1377
|
//#endregion
|
|
@@ -1420,7 +1420,7 @@ const assetsCommand = defineCommand({
|
|
|
1420
1420
|
catch: (e) => e
|
|
1421
1421
|
});
|
|
1422
1422
|
if (Result.isError(validation)) {
|
|
1423
|
-
const msg = validation.error instanceof z.ZodError ? formatZodError$
|
|
1423
|
+
const msg = validation.error instanceof z.ZodError ? formatZodError$5(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
|
|
1424
1424
|
printResult(Result.err(msg), format);
|
|
1425
1425
|
return;
|
|
1426
1426
|
}
|
|
@@ -1507,7 +1507,7 @@ const assetsCommand = defineCommand({
|
|
|
1507
1507
|
});
|
|
1508
1508
|
//#endregion
|
|
1509
1509
|
//#region src/commands/send.ts
|
|
1510
|
-
function formatZodError$
|
|
1510
|
+
function formatZodError$4(e) {
|
|
1511
1511
|
return e.issues.map((issue) => issue.message).join(", ");
|
|
1512
1512
|
}
|
|
1513
1513
|
const sendCommand = defineCommand({
|
|
@@ -1562,7 +1562,7 @@ const sendCommand = defineCommand({
|
|
|
1562
1562
|
catch: (e) => e
|
|
1563
1563
|
});
|
|
1564
1564
|
if (Result.isError(validation)) {
|
|
1565
|
-
const msg = validation.error instanceof z.ZodError ? formatZodError$
|
|
1565
|
+
const msg = validation.error instanceof z.ZodError ? formatZodError$4(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
|
|
1566
1566
|
printResult(Result.err(msg), format);
|
|
1567
1567
|
return;
|
|
1568
1568
|
}
|
|
@@ -1610,7 +1610,7 @@ const feeCommand = defineCommand({
|
|
|
1610
1610
|
});
|
|
1611
1611
|
//#endregion
|
|
1612
1612
|
//#region src/commands/monitor-transactions.ts
|
|
1613
|
-
function formatZodError$
|
|
1613
|
+
function formatZodError$3(e) {
|
|
1614
1614
|
return e.issues.map((issue) => issue.message).join(", ");
|
|
1615
1615
|
}
|
|
1616
1616
|
const monitorTransactions = defineCommand({
|
|
@@ -1647,7 +1647,7 @@ const monitorTransactions = defineCommand({
|
|
|
1647
1647
|
catch: (e) => e
|
|
1648
1648
|
});
|
|
1649
1649
|
if (Result.isError(validation)) {
|
|
1650
|
-
const msg = validation.error instanceof z.ZodError ? formatZodError$
|
|
1650
|
+
const msg = validation.error instanceof z.ZodError ? formatZodError$3(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
|
|
1651
1651
|
printResult(Result.err(msg), format);
|
|
1652
1652
|
return;
|
|
1653
1653
|
}
|
|
@@ -1687,7 +1687,7 @@ const monitorTransactions = defineCommand({
|
|
|
1687
1687
|
});
|
|
1688
1688
|
//#endregion
|
|
1689
1689
|
//#region src/commands/monitor-payments.ts
|
|
1690
|
-
function formatZodError$
|
|
1690
|
+
function formatZodError$2(e) {
|
|
1691
1691
|
return e.issues.map((issue) => issue.message).join(", ");
|
|
1692
1692
|
}
|
|
1693
1693
|
const monitorPayments = defineCommand({
|
|
@@ -1724,7 +1724,7 @@ const monitorPayments = defineCommand({
|
|
|
1724
1724
|
catch: (e) => e
|
|
1725
1725
|
});
|
|
1726
1726
|
if (Result.isError(validation)) {
|
|
1727
|
-
const msg = validation.error instanceof z.ZodError ? formatZodError$
|
|
1727
|
+
const msg = validation.error instanceof z.ZodError ? formatZodError$2(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
|
|
1728
1728
|
printResult(Result.err(msg), format);
|
|
1729
1729
|
return;
|
|
1730
1730
|
}
|
|
@@ -1764,7 +1764,7 @@ const monitorPayments = defineCommand({
|
|
|
1764
1764
|
});
|
|
1765
1765
|
//#endregion
|
|
1766
1766
|
//#region src/commands/monitor-effects.ts
|
|
1767
|
-
function formatZodError(e) {
|
|
1767
|
+
function formatZodError$1(e) {
|
|
1768
1768
|
return e.issues.map((issue) => issue.message).join(", ");
|
|
1769
1769
|
}
|
|
1770
1770
|
//#endregion
|
|
@@ -1811,7 +1811,7 @@ const monitorCommand = defineCommand({
|
|
|
1811
1811
|
catch: (e) => e
|
|
1812
1812
|
});
|
|
1813
1813
|
if (Result.isError(validation)) {
|
|
1814
|
-
const msg = validation.error instanceof z.ZodError ? formatZodError(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
|
|
1814
|
+
const msg = validation.error instanceof z.ZodError ? formatZodError$1(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
|
|
1815
1815
|
printResult(Result.err(msg), format);
|
|
1816
1816
|
return;
|
|
1817
1817
|
}
|
|
@@ -2174,6 +2174,126 @@ function registerAssetTools(server) {
|
|
|
2174
2174
|
});
|
|
2175
2175
|
}
|
|
2176
2176
|
//#endregion
|
|
2177
|
+
//#region src/services/preflight.ts
|
|
2178
|
+
const HORIZON_URLS = {
|
|
2179
|
+
testnet: process.env.STELAGENT_HORIZON_TESTNET_URL ?? "https://horizon-testnet.stellar.org",
|
|
2180
|
+
pubnet: process.env.STELAGENT_HORIZON_PUBNET_URL ?? "https://horizon-mainnet.stellar.org"
|
|
2181
|
+
};
|
|
2182
|
+
const BASE_RESERVE = "1";
|
|
2183
|
+
const LINE_RESERVE = "0.5";
|
|
2184
|
+
async function preflightSend(destination, amount, assetStr, network) {
|
|
2185
|
+
const walletResult = await fetchWallet();
|
|
2186
|
+
if (Result.isError(walletResult)) return Result.err(walletResult.error);
|
|
2187
|
+
const wallet = walletResult.value;
|
|
2188
|
+
const sender = wallet.publicKey;
|
|
2189
|
+
const server = new Horizon.Server(HORIZON_URLS[network]);
|
|
2190
|
+
let senderAccount;
|
|
2191
|
+
let senderFunded = true;
|
|
2192
|
+
let destinationFunded = true;
|
|
2193
|
+
let destinationFundingRequired = false;
|
|
2194
|
+
const warnings = [];
|
|
2195
|
+
try {
|
|
2196
|
+
senderAccount = await server.loadAccount(sender);
|
|
2197
|
+
} catch {
|
|
2198
|
+
senderFunded = false;
|
|
2199
|
+
const msg = wallet.network === "testnet" ? `Sender account ${sender.slice(0, 8)}... is not funded. Use wallet login to auto-fund on testnet.` : `Sender account ${sender.slice(0, 8)}... is not funded. Send at least 1 XLM to activate it.`;
|
|
2200
|
+
return Result.ok({
|
|
2201
|
+
canProceed: false,
|
|
2202
|
+
sender,
|
|
2203
|
+
destination,
|
|
2204
|
+
amount,
|
|
2205
|
+
asset: assetStr === "native" ? "XLM" : assetStr,
|
|
2206
|
+
network,
|
|
2207
|
+
senderFunded,
|
|
2208
|
+
destinationFunded: true,
|
|
2209
|
+
destinationFundingRequired: false,
|
|
2210
|
+
balances: [],
|
|
2211
|
+
estimatedFee: "0",
|
|
2212
|
+
baseReserve: BASE_RESERVE,
|
|
2213
|
+
warnings: [msg]
|
|
2214
|
+
});
|
|
2215
|
+
}
|
|
2216
|
+
let feeStatsResult;
|
|
2217
|
+
try {
|
|
2218
|
+
const stats = await server.feeStats();
|
|
2219
|
+
feeStatsResult = {
|
|
2220
|
+
feeCharged: { mode: stats.fee_charged.mode },
|
|
2221
|
+
maxFee: { mode: stats.max_fee.mode }
|
|
2222
|
+
};
|
|
2223
|
+
} catch {
|
|
2224
|
+
feeStatsResult = {
|
|
2225
|
+
feeCharged: { mode: "100" },
|
|
2226
|
+
maxFee: { mode: "100" }
|
|
2227
|
+
};
|
|
2228
|
+
}
|
|
2229
|
+
const estimatedFee = feeStatsResult.feeCharged.mode;
|
|
2230
|
+
const balances = [];
|
|
2231
|
+
let sufficientOverall = true;
|
|
2232
|
+
for (const b of senderAccount.balances) {
|
|
2233
|
+
const code = b.asset_type === "native" ? "XLM" : "asset_code" in b ? String(b.asset_code) : "";
|
|
2234
|
+
const available = Number(b.balance);
|
|
2235
|
+
if (b.asset_type === "native") {
|
|
2236
|
+
const subentryCount = senderAccount.subentry_count;
|
|
2237
|
+
const effectiveAvailable = available - (Number(BASE_RESERVE) + Number(LINE_RESERVE) * subentryCount);
|
|
2238
|
+
const needed = Number(amount) + Number(estimatedFee) / 1e7;
|
|
2239
|
+
const sufficient = effectiveAvailable >= needed;
|
|
2240
|
+
if (!sufficient) sufficientOverall = false;
|
|
2241
|
+
balances.push({
|
|
2242
|
+
asset: "XLM",
|
|
2243
|
+
available: effectiveAvailable.toFixed(7),
|
|
2244
|
+
needed: needed.toFixed(7),
|
|
2245
|
+
sufficient
|
|
2246
|
+
});
|
|
2247
|
+
} else if (assetStr !== "native" && code === assetStr.split(":")[0] || assetStr === code) {
|
|
2248
|
+
const needed = Number(amount);
|
|
2249
|
+
const sufficient = available >= needed;
|
|
2250
|
+
if (!sufficient) sufficientOverall = false;
|
|
2251
|
+
balances.push({
|
|
2252
|
+
asset: code,
|
|
2253
|
+
available: available.toFixed(7),
|
|
2254
|
+
needed: needed.toFixed(7),
|
|
2255
|
+
sufficient
|
|
2256
|
+
});
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
try {
|
|
2260
|
+
await server.loadAccount(destination);
|
|
2261
|
+
} catch {
|
|
2262
|
+
destinationFunded = false;
|
|
2263
|
+
destinationFundingRequired = true;
|
|
2264
|
+
if (assetStr === "native") warnings.push(`Destination ${destination.slice(0, 8)}... is not funded. The transaction will create the account if amount >= 1 XLM.`);
|
|
2265
|
+
else {
|
|
2266
|
+
warnings.push(`Destination ${destination.slice(0, 8)}... is not funded. Cannot send custom assets to an unfunded account. The destination must first receive XLM.`);
|
|
2267
|
+
sufficientOverall = false;
|
|
2268
|
+
}
|
|
2269
|
+
}
|
|
2270
|
+
if (assetStr === "native") {
|
|
2271
|
+
const totalNeeded = Number(amount) + Number(estimatedFee) / 1e7;
|
|
2272
|
+
const xlmBalance = senderAccount.balances.find((b) => b.asset_type === "native");
|
|
2273
|
+
if (xlmBalance) {
|
|
2274
|
+
const subentryCount = senderAccount.subentry_count;
|
|
2275
|
+
const minReserve = Number(BASE_RESERVE) + Number(LINE_RESERVE) * subentryCount;
|
|
2276
|
+
if (Number(xlmBalance.balance) - totalNeeded - minReserve < 0) warnings.push(`After sending ${amount} XLM + fees, remaining balance would fall below minimum reserve (${minReserve} XLM).`);
|
|
2277
|
+
}
|
|
2278
|
+
}
|
|
2279
|
+
const canProceed = senderFunded && sufficientOverall;
|
|
2280
|
+
return Result.ok({
|
|
2281
|
+
canProceed,
|
|
2282
|
+
sender,
|
|
2283
|
+
destination,
|
|
2284
|
+
amount,
|
|
2285
|
+
asset: assetStr === "native" ? "XLM" : assetStr,
|
|
2286
|
+
network,
|
|
2287
|
+
senderFunded,
|
|
2288
|
+
destinationFunded,
|
|
2289
|
+
destinationFundingRequired,
|
|
2290
|
+
balances,
|
|
2291
|
+
estimatedFee,
|
|
2292
|
+
baseReserve: BASE_RESERVE,
|
|
2293
|
+
warnings
|
|
2294
|
+
});
|
|
2295
|
+
}
|
|
2296
|
+
//#endregion
|
|
2177
2297
|
//#region src/mcp/payment-tools.ts
|
|
2178
2298
|
function ok(data) {
|
|
2179
2299
|
return { content: [{
|
|
@@ -2231,6 +2351,25 @@ function registerPaymentTools(server) {
|
|
|
2231
2351
|
if (Result.isError(result)) return err(formatPaymentError(result.error));
|
|
2232
2352
|
return ok(result.value);
|
|
2233
2353
|
});
|
|
2354
|
+
server.registerTool("preflight_check", {
|
|
2355
|
+
description: "Validate a payment before sending. Checks if the sender has sufficient balance, estimates fees, and verifies the destination account. Returns whether the transaction can proceed, along with detailed balance info and warnings.",
|
|
2356
|
+
inputSchema: {
|
|
2357
|
+
destination: z.string().describe("Destination public key (G...)"),
|
|
2358
|
+
amount: z.string().describe("Amount to validate (up to 7 decimal places)"),
|
|
2359
|
+
asset: z.string().default("native").describe("Asset: 'native' for XLM, or 'CODE:ISSUER' for custom assets"),
|
|
2360
|
+
network: z.enum(["testnet", "pubnet"]).default("testnet").describe("Stellar network")
|
|
2361
|
+
}
|
|
2362
|
+
}, async ({ destination, amount, asset, network }) => {
|
|
2363
|
+
const destValidation = stellarPublicKey.safeParse(destination);
|
|
2364
|
+
if (!destValidation.success) return err(`Invalid destination: ${destValidation.error.issues.map((i) => i.message).join(", ")}`);
|
|
2365
|
+
const amountValidation = amountSchema.safeParse(amount);
|
|
2366
|
+
if (!amountValidation.success) return err(`Invalid amount: ${amountValidation.error.issues.map((i) => i.message).join(", ")}`);
|
|
2367
|
+
const assetValidation = assetSchema.safeParse(asset);
|
|
2368
|
+
if (!assetValidation.success) return err(`Invalid asset: ${assetValidation.error.issues.map((i) => i.message).join(", ")}`);
|
|
2369
|
+
const result = await preflightSend(destination, amount, asset, network === "pubnet" ? "pubnet" : "testnet");
|
|
2370
|
+
if (Result.isError(result)) return err(formatWalletError(result.error));
|
|
2371
|
+
return ok(result.value);
|
|
2372
|
+
});
|
|
2234
2373
|
}
|
|
2235
2374
|
//#endregion
|
|
2236
2375
|
//#region src/mcp/mod.ts
|
|
@@ -2253,6 +2392,29 @@ async function startMcpServer() {
|
|
|
2253
2392
|
await server.connect(transport);
|
|
2254
2393
|
}
|
|
2255
2394
|
//#endregion
|
|
2395
|
+
//#region src/commands/mcp.ts
|
|
2396
|
+
const mcpCommand = defineCommand({
|
|
2397
|
+
meta: {
|
|
2398
|
+
name: "mcp",
|
|
2399
|
+
description: "Start the MCP server on stdio"
|
|
2400
|
+
},
|
|
2401
|
+
args: {},
|
|
2402
|
+
async run() {
|
|
2403
|
+
try {
|
|
2404
|
+
await startMcpServer();
|
|
2405
|
+
} catch (e) {
|
|
2406
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
2407
|
+
console.error(`Failed to start MCP server: ${message}`);
|
|
2408
|
+
process.exit(1);
|
|
2409
|
+
}
|
|
2410
|
+
}
|
|
2411
|
+
});
|
|
2412
|
+
//#endregion
|
|
2413
|
+
//#region src/commands/preflight.ts
|
|
2414
|
+
function formatZodError(e) {
|
|
2415
|
+
return e.issues.map((issue) => issue.message).join(", ");
|
|
2416
|
+
}
|
|
2417
|
+
//#endregion
|
|
2256
2418
|
//#region src/index.ts
|
|
2257
2419
|
runMain(defineCommand({
|
|
2258
2420
|
meta: {
|
|
@@ -2268,20 +2430,61 @@ runMain(defineCommand({
|
|
|
2268
2430
|
send: sendCommand,
|
|
2269
2431
|
fee: feeCommand,
|
|
2270
2432
|
monitor: monitorCommand,
|
|
2271
|
-
mcp:
|
|
2433
|
+
mcp: mcpCommand,
|
|
2434
|
+
preflight: defineCommand({
|
|
2272
2435
|
meta: {
|
|
2273
|
-
name: "
|
|
2274
|
-
description: "
|
|
2436
|
+
name: "preflight",
|
|
2437
|
+
description: "Validate a payment before sending: check balances, fees, and destination"
|
|
2275
2438
|
},
|
|
2276
|
-
args: {
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2439
|
+
args: {
|
|
2440
|
+
destination: {
|
|
2441
|
+
type: "positional",
|
|
2442
|
+
description: "Destination public key (G...)",
|
|
2443
|
+
required: true
|
|
2444
|
+
},
|
|
2445
|
+
amount: {
|
|
2446
|
+
type: "string",
|
|
2447
|
+
alias: ["a"],
|
|
2448
|
+
description: "Amount to validate",
|
|
2449
|
+
required: true
|
|
2450
|
+
},
|
|
2451
|
+
asset: {
|
|
2452
|
+
type: "string",
|
|
2453
|
+
alias: ["s"],
|
|
2454
|
+
description: "Asset: 'native' (default) or 'CODE:ISSUER'",
|
|
2455
|
+
default: "native"
|
|
2456
|
+
},
|
|
2457
|
+
network: networkArg,
|
|
2458
|
+
format: formatArg
|
|
2459
|
+
},
|
|
2460
|
+
async run({ args }) {
|
|
2461
|
+
const networkResult = parseNetwork$4(String(args.network ?? "testnet"));
|
|
2462
|
+
const format = parseFormat(String(args.format ?? "json"));
|
|
2463
|
+
if (Result.isError(networkResult)) {
|
|
2464
|
+
printResult(Result.err(networkResult.error._tag), "json");
|
|
2465
|
+
return;
|
|
2466
|
+
}
|
|
2467
|
+
const destination = String(args.destination ?? "");
|
|
2468
|
+
const amount = String(args.amount ?? "");
|
|
2469
|
+
const asset = String(args.asset ?? "native");
|
|
2470
|
+
const validation = Result.try({
|
|
2471
|
+
try: () => {
|
|
2472
|
+
stellarPublicKey.parse(destination);
|
|
2473
|
+
amountSchema.parse(amount);
|
|
2474
|
+
assetSchema.parse(asset);
|
|
2475
|
+
},
|
|
2476
|
+
catch: (e) => e
|
|
2477
|
+
});
|
|
2478
|
+
if (Result.isError(validation)) {
|
|
2479
|
+
const msg = validation.error instanceof z.ZodError ? formatZodError(validation.error) : validation.error instanceof Error ? validation.error.message : String(validation.error);
|
|
2480
|
+
printResult(Result.err(msg), format);
|
|
2481
|
+
return;
|
|
2284
2482
|
}
|
|
2483
|
+
await runCommand(async () => {
|
|
2484
|
+
const result = await preflightSend(destination, amount, asset, networkResult.value);
|
|
2485
|
+
if (Result.isError(result)) return Result.err(formatWalletError(result.error));
|
|
2486
|
+
return Result.ok(result.value);
|
|
2487
|
+
}, format);
|
|
2285
2488
|
}
|
|
2286
2489
|
})
|
|
2287
2490
|
}
|