bsv-mcp 0.3.0 → 0.3.1
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/CHANGELOG.md +11 -0
- package/README.md +82 -0
- package/dist/index.js +672 -114
- package/index.ts +61 -7
- package/package.json +1 -1
- package/tools/index.ts +12 -3
- package/tools/wallet/brc100.ts +25 -1
- package/tools/wallet/droplit.ts +124 -0
- package/tools/wallet/integratedWallet.ts +1 -3
- package/tools/wallet/setupDroplit.ts +10 -16
- package/tools/wallet/tools.ts +6 -4
- package/test-mcp-server.ts +0 -179
package/dist/index.js
CHANGED
|
@@ -223156,7 +223156,7 @@ var require_timestamp2 = __commonJS((exports, module) => {
|
|
|
223156
223156
|
|
|
223157
223157
|
// node_modules/knex/lib/migrations/migrate/MigrationGenerator.js
|
|
223158
223158
|
var require_MigrationGenerator = __commonJS((exports, module) => {
|
|
223159
|
-
var __dirname = "/Users/satchmo/
|
|
223159
|
+
var __dirname = "/Users/satchmo/.codex/worktrees/agent-stack-mcp/node_modules/knex/lib/migrations/migrate";
|
|
223160
223160
|
var path6 = __require("path");
|
|
223161
223161
|
var { writeJsFileUsingTemplate } = require_template2();
|
|
223162
223162
|
var { getMergedConfig } = require_migrator_configuration_merger();
|
|
@@ -223863,7 +223863,7 @@ var require_seeder_configuration_merger = __commonJS((exports, module) => {
|
|
|
223863
223863
|
|
|
223864
223864
|
// node_modules/knex/lib/migrations/seed/Seeder.js
|
|
223865
223865
|
var require_Seeder = __commonJS((exports, module) => {
|
|
223866
|
-
var __dirname = "/Users/satchmo/
|
|
223866
|
+
var __dirname = "/Users/satchmo/.codex/worktrees/agent-stack-mcp/node_modules/knex/lib/migrations/seed";
|
|
223867
223867
|
var path6 = __require("path");
|
|
223868
223868
|
var { ensureDirectoryExists } = require_fs();
|
|
223869
223869
|
var { writeJsFileUsingTemplate } = require_template2();
|
|
@@ -256042,7 +256042,7 @@ var package_default = {
|
|
|
256042
256042
|
name: "bsv-mcp",
|
|
256043
256043
|
module: "dist/index.js",
|
|
256044
256044
|
type: "module",
|
|
256045
|
-
version: "0.3.
|
|
256045
|
+
version: "0.3.1",
|
|
256046
256046
|
license: "MIT",
|
|
256047
256047
|
author: "satchmo",
|
|
256048
256048
|
description: "A collection of Bitcoin SV (BSV) tools for the Model Context Protocol (MCP) framework",
|
|
@@ -284875,6 +284875,281 @@ function registerUtilsTools(server) {
|
|
|
284875
284875
|
});
|
|
284876
284876
|
}
|
|
284877
284877
|
|
|
284878
|
+
// utils/droplit.ts
|
|
284879
|
+
init_mod2();
|
|
284880
|
+
class DroplitError extends Error {
|
|
284881
|
+
code;
|
|
284882
|
+
status;
|
|
284883
|
+
details;
|
|
284884
|
+
constructor(code, message, status, details = {}) {
|
|
284885
|
+
super(message);
|
|
284886
|
+
this.code = code;
|
|
284887
|
+
this.status = status;
|
|
284888
|
+
this.details = details;
|
|
284889
|
+
}
|
|
284890
|
+
}
|
|
284891
|
+
function quotaDetails(body) {
|
|
284892
|
+
if (!body || typeof body !== "object")
|
|
284893
|
+
return {};
|
|
284894
|
+
const value2 = body;
|
|
284895
|
+
return {
|
|
284896
|
+
...typeof value2.remaining === "number" || value2.remaining === null ? { remaining: value2.remaining } : {},
|
|
284897
|
+
...typeof value2.resets_at === "string" ? { resets_at: value2.resets_at } : {}
|
|
284898
|
+
};
|
|
284899
|
+
}
|
|
284900
|
+
function httpFailure(status, details = {}) {
|
|
284901
|
+
const known = {
|
|
284902
|
+
401: [
|
|
284903
|
+
"authentication_required",
|
|
284904
|
+
"Authenticate with the configured wallet before retrying."
|
|
284905
|
+
],
|
|
284906
|
+
402: [
|
|
284907
|
+
"approval_required",
|
|
284908
|
+
"Payment is required. No automatic payment was made; review payment with the wallet owner."
|
|
284909
|
+
],
|
|
284910
|
+
403: [
|
|
284911
|
+
"approval_required",
|
|
284912
|
+
"The sponsor has not authorized this action. Ask its owner to approve your wallet."
|
|
284913
|
+
],
|
|
284914
|
+
429: [
|
|
284915
|
+
"quota_exceeded",
|
|
284916
|
+
"Sponsor quota exhausted. Wait until resets_at or ask the owner to adjust your quota."
|
|
284917
|
+
]
|
|
284918
|
+
};
|
|
284919
|
+
const [code, message] = known[status] ?? [
|
|
284920
|
+
"http_error",
|
|
284921
|
+
"Droplit rejected the request. Check sponsor access and transaction history before retrying."
|
|
284922
|
+
];
|
|
284923
|
+
return new DroplitError(code, message, status, details);
|
|
284924
|
+
}
|
|
284925
|
+
|
|
284926
|
+
class DroplitClient {
|
|
284927
|
+
config;
|
|
284928
|
+
authFetch;
|
|
284929
|
+
wallet;
|
|
284930
|
+
constructor(config2) {
|
|
284931
|
+
this.config = config2;
|
|
284932
|
+
if (config2.wallet && config2.authKey)
|
|
284933
|
+
throw new Error("Configure Droplit wallet or authKey, not both");
|
|
284934
|
+
const url3 = new URL(config2.apiUrl);
|
|
284935
|
+
const loopback = url3.hostname === "localhost" || url3.hostname === "127.0.0.1" || url3.hostname === "[::1]";
|
|
284936
|
+
if (url3.username || url3.password || url3.search || url3.hash || !(url3.protocol === "https:" || url3.protocol === "http:" && loopback)) {
|
|
284937
|
+
throw new Error("Droplit API requires HTTPS or HTTP loopback without credentials, query or fragment");
|
|
284938
|
+
}
|
|
284939
|
+
if (!config2.faucetName.trim())
|
|
284940
|
+
throw new Error("Droplit faucet name is required");
|
|
284941
|
+
this.wallet = config2.wallet ?? (config2.authKey ? new ProtoWallet_default(config2.authKey) : undefined);
|
|
284942
|
+
if (this.wallet) {
|
|
284943
|
+
const authenticationWallet = new Proxy(this.wallet, {
|
|
284944
|
+
get(target, property) {
|
|
284945
|
+
if (property === "createAction" || property === "signAction") {
|
|
284946
|
+
return async () => {
|
|
284947
|
+
throw httpFailure(402);
|
|
284948
|
+
};
|
|
284949
|
+
}
|
|
284950
|
+
const value2 = Reflect.get(target, property, target);
|
|
284951
|
+
return typeof value2 === "function" ? value2.bind(target) : value2;
|
|
284952
|
+
}
|
|
284953
|
+
});
|
|
284954
|
+
this.authFetch = new AuthFetch(authenticationWallet);
|
|
284955
|
+
}
|
|
284956
|
+
}
|
|
284957
|
+
getConfig() {
|
|
284958
|
+
return { apiUrl: this.config.apiUrl, faucetName: this.config.faucetName };
|
|
284959
|
+
}
|
|
284960
|
+
async getIdentityKey() {
|
|
284961
|
+
if (!this.wallet)
|
|
284962
|
+
throw new DroplitError("authentication_required", "Configure a Droplit wallet identity.");
|
|
284963
|
+
const { publicKey } = await this.wallet.getPublicKey({ identityKey: true });
|
|
284964
|
+
return publicKey;
|
|
284965
|
+
}
|
|
284966
|
+
get faucetPath() {
|
|
284967
|
+
return `/faucet/${encodeURIComponent(this.config.faucetName)}`;
|
|
284968
|
+
}
|
|
284969
|
+
get base() {
|
|
284970
|
+
return this.config.apiUrl.replace(/\/+$/, "");
|
|
284971
|
+
}
|
|
284972
|
+
async authed(path3, init) {
|
|
284973
|
+
if (!this.authFetch) {
|
|
284974
|
+
throw new Error(`${path3} requires authentication and no Droplit auth key is configured.`);
|
|
284975
|
+
}
|
|
284976
|
+
try {
|
|
284977
|
+
return await this.authFetch.fetch(`${this.base}${path3}`, {
|
|
284978
|
+
method: init.method,
|
|
284979
|
+
headers: { "Content-Type": "application/json" },
|
|
284980
|
+
...init.body === undefined ? {} : { body: JSON.stringify(init.body) },
|
|
284981
|
+
paymentRetryAttempts: 0,
|
|
284982
|
+
...init.method === "GET" || init.method === "HEAD" ? {} : { retryCounter: 1 }
|
|
284983
|
+
});
|
|
284984
|
+
} catch (error52) {
|
|
284985
|
+
if (error52 instanceof DroplitError)
|
|
284986
|
+
throw error52;
|
|
284987
|
+
const details = error52?.details;
|
|
284988
|
+
const status = details?.status;
|
|
284989
|
+
if (typeof status === "number" && [401, 402, 403, 429].includes(status)) {
|
|
284990
|
+
let body;
|
|
284991
|
+
if (status === 429 && typeof details?.bodyPreview === "string") {
|
|
284992
|
+
try {
|
|
284993
|
+
body = JSON.parse(details.bodyPreview);
|
|
284994
|
+
} catch {}
|
|
284995
|
+
}
|
|
284996
|
+
throw httpFailure(status, status === 429 ? quotaDetails(body) : {});
|
|
284997
|
+
}
|
|
284998
|
+
const write = init.method !== "GET" && init.method !== "HEAD";
|
|
284999
|
+
throw new DroplitError(write ? "unknown_outcome" : "request_failed", write ? "Request outcome is unknown. Reconcile transaction/history before retrying; no automatic retry was made." : "Authenticated request failed. Check the signer and sponsor connection.");
|
|
285000
|
+
}
|
|
285001
|
+
}
|
|
285002
|
+
async parse(response, _attempted) {
|
|
285003
|
+
if (response.ok) {
|
|
285004
|
+
try {
|
|
285005
|
+
return await response.json();
|
|
285006
|
+
} catch {
|
|
285007
|
+
throw new DroplitError("unknown_outcome", "Response could not be read. Reconcile transaction/history before retrying.", response.status);
|
|
285008
|
+
}
|
|
285009
|
+
}
|
|
285010
|
+
let body = {};
|
|
285011
|
+
try {
|
|
285012
|
+
body = await response.json();
|
|
285013
|
+
} catch {}
|
|
285014
|
+
throw httpFailure(response.status, response.status === 429 ? quotaDetails(body) : {});
|
|
285015
|
+
}
|
|
285016
|
+
async getAccess() {
|
|
285017
|
+
const response = await this.authed(`${this.faucetPath}/access`, {
|
|
285018
|
+
method: "GET"
|
|
285019
|
+
});
|
|
285020
|
+
const access = await this.parse(response, "Reading sponsor access");
|
|
285021
|
+
const identity6 = await this.getIdentityKey();
|
|
285022
|
+
if (!access || access.public_key !== identity6 || access.slug !== this.config.faucetName || typeof access.authorized !== "boolean" || typeof access.is_owner !== "boolean" || !Array.isArray(access.quotas) || !Array.isArray(access.unrestricted_kinds)) {
|
|
285023
|
+
throw new DroplitError("invalid_response", "Sponsor access response did not match the authenticated wallet.");
|
|
285024
|
+
}
|
|
285025
|
+
access.approval_path = `/droplit/${encodeURIComponent(this.config.faucetName)}?tab=api&request_key=${encodeURIComponent(identity6)}`;
|
|
285026
|
+
return access;
|
|
285027
|
+
}
|
|
285028
|
+
async fund(rawtx) {
|
|
285029
|
+
const response = await this.authed(`${this.faucetPath}/fund`, {
|
|
285030
|
+
method: "POST",
|
|
285031
|
+
body: { rawtx }
|
|
285032
|
+
});
|
|
285033
|
+
return this.parse(response, "Funding transaction");
|
|
285034
|
+
}
|
|
285035
|
+
async getFaucetStatus() {
|
|
285036
|
+
const response = await fetch(`${this.base}${this.faucetPath}/status`);
|
|
285037
|
+
return this.parse(response, "Reading the faucet status");
|
|
285038
|
+
}
|
|
285039
|
+
async tap(recipientAddress, satoshis) {
|
|
285040
|
+
if (satoshis !== undefined && (!Number.isSafeInteger(satoshis) || satoshis <= 0))
|
|
285041
|
+
throw new Error("satoshis must be a positive safe integer");
|
|
285042
|
+
const response = await this.authed(`${this.faucetPath}/tap`, {
|
|
285043
|
+
method: "POST",
|
|
285044
|
+
body: {
|
|
285045
|
+
recipient_address: recipientAddress,
|
|
285046
|
+
...satoshis === undefined ? {} : { satoshis }
|
|
285047
|
+
}
|
|
285048
|
+
});
|
|
285049
|
+
return this.parse(response, "Tapping the faucet");
|
|
285050
|
+
}
|
|
285051
|
+
async push(data, encoding = "hex") {
|
|
285052
|
+
const response = await this.authed(`${this.faucetPath}/push`, {
|
|
285053
|
+
method: "POST",
|
|
285054
|
+
body: { data, encoding }
|
|
285055
|
+
});
|
|
285056
|
+
return this.parse(response, "Pushing data");
|
|
285057
|
+
}
|
|
285058
|
+
async authenticatedFetch(path3, init) {
|
|
285059
|
+
return this.authed(path3, init);
|
|
285060
|
+
}
|
|
285061
|
+
}
|
|
285062
|
+
|
|
285063
|
+
// tools/wallet/droplit.ts
|
|
285064
|
+
function errorResult(error52) {
|
|
285065
|
+
const failure = error52 instanceof DroplitError ? error52 : new DroplitError("request_failed", "Droplit operation failed. Check configuration and broadcasting policy.");
|
|
285066
|
+
const data = {
|
|
285067
|
+
error: failure.code,
|
|
285068
|
+
message: failure.message,
|
|
285069
|
+
...failure.status === undefined ? {} : { status: failure.status },
|
|
285070
|
+
...failure.details
|
|
285071
|
+
};
|
|
285072
|
+
return {
|
|
285073
|
+
...createSuccessResponse(data),
|
|
285074
|
+
structuredContent: data,
|
|
285075
|
+
isError: true
|
|
285076
|
+
};
|
|
285077
|
+
}
|
|
285078
|
+
function registerDroplitTools(server, client, disableBroadcasting = false) {
|
|
285079
|
+
server.registerTool("droplit_getAccess", {
|
|
285080
|
+
description: "Read this connected wallet's sponsor authorization and quotas. If unauthorized, a human sponsor owner must approve the wallet manually. Does not create, fund, or approve anything.",
|
|
285081
|
+
inputSchema: {},
|
|
285082
|
+
annotations: {
|
|
285083
|
+
readOnlyHint: true,
|
|
285084
|
+
destructiveHint: false,
|
|
285085
|
+
idempotentHint: true,
|
|
285086
|
+
openWorldHint: true
|
|
285087
|
+
}
|
|
285088
|
+
}, async () => {
|
|
285089
|
+
try {
|
|
285090
|
+
const access = await client.getAccess();
|
|
285091
|
+
const data = {
|
|
285092
|
+
...access,
|
|
285093
|
+
...!access.authorized ? {
|
|
285094
|
+
error: "approval_required",
|
|
285095
|
+
message: "Ask the sponsor owner to approve this wallet. Copy the approval URL for manual review; do not auto-open or submit approval.",
|
|
285096
|
+
approval_url: `https://droplit.dev${access.approval_path}`
|
|
285097
|
+
} : {}
|
|
285098
|
+
};
|
|
285099
|
+
return {
|
|
285100
|
+
...createSuccessResponse(data),
|
|
285101
|
+
structuredContent: data,
|
|
285102
|
+
isError: !access.authorized
|
|
285103
|
+
};
|
|
285104
|
+
} catch (error52) {
|
|
285105
|
+
return errorResult(error52);
|
|
285106
|
+
}
|
|
285107
|
+
});
|
|
285108
|
+
server.registerTool("droplit_push", {
|
|
285109
|
+
description: "Submit one sponsored data transaction. Subject to sponsor approval and quotas. An unknown outcome requires checking transaction history before retrying.",
|
|
285110
|
+
inputSchema: {
|
|
285111
|
+
data: exports_external.array(exports_external.string()).min(1),
|
|
285112
|
+
encoding: exports_external.enum(["hex", "utf8"])
|
|
285113
|
+
},
|
|
285114
|
+
annotations: {
|
|
285115
|
+
readOnlyHint: false,
|
|
285116
|
+
destructiveHint: true,
|
|
285117
|
+
idempotentHint: false,
|
|
285118
|
+
openWorldHint: true
|
|
285119
|
+
}
|
|
285120
|
+
}, async ({ data, encoding }) => {
|
|
285121
|
+
try {
|
|
285122
|
+
if (disableBroadcasting)
|
|
285123
|
+
throw new Error("Broadcasting disabled");
|
|
285124
|
+
assertBroadcastAllowed("droplit_push");
|
|
285125
|
+
return createSuccessResponse(await client.push(data, encoding));
|
|
285126
|
+
} catch (error52) {
|
|
285127
|
+
return errorResult(error52);
|
|
285128
|
+
}
|
|
285129
|
+
});
|
|
285130
|
+
server.registerTool("droplit_fund", {
|
|
285131
|
+
description: "Submit one raw transaction for sponsor funding and broadcast. Subject to sponsor approval and quotas. Unknown outcomes must be reconciled before retrying.",
|
|
285132
|
+
inputSchema: {
|
|
285133
|
+
rawtx: exports_external.string().min(2).regex(/^(?:[0-9a-fA-F]{2})+$/, "Expected raw transaction hex")
|
|
285134
|
+
},
|
|
285135
|
+
annotations: {
|
|
285136
|
+
readOnlyHint: false,
|
|
285137
|
+
destructiveHint: true,
|
|
285138
|
+
idempotentHint: false,
|
|
285139
|
+
openWorldHint: true
|
|
285140
|
+
}
|
|
285141
|
+
}, async ({ rawtx }) => {
|
|
285142
|
+
try {
|
|
285143
|
+
if (disableBroadcasting)
|
|
285144
|
+
throw new Error("Broadcasting disabled");
|
|
285145
|
+
assertBroadcastAllowed("droplit_fund");
|
|
285146
|
+
return createSuccessResponse(await client.fund(rawtx));
|
|
285147
|
+
} catch (error52) {
|
|
285148
|
+
return errorResult(error52);
|
|
285149
|
+
}
|
|
285150
|
+
});
|
|
285151
|
+
}
|
|
285152
|
+
|
|
284878
285153
|
// tools/wallet/getBalanceDroplit.ts
|
|
284879
285154
|
function registerWalletGetBalanceDroplitTool(server, droplitClient) {
|
|
284880
285155
|
server.tool("wallet_getBalance", "Gets the current balance of the wallet (Droplit mode)", {}, async () => {
|
|
@@ -284911,16 +285186,13 @@ function registerWalletGetBalanceDroplitTool(server, droplitClient) {
|
|
|
284911
285186
|
}
|
|
284912
285187
|
|
|
284913
285188
|
// tools/wallet/setupDroplit.ts
|
|
284914
|
-
function requireDroplit(integratedWallet) {
|
|
285189
|
+
async function requireDroplit(integratedWallet) {
|
|
284915
285190
|
const client = integratedWallet.getDroplitClient();
|
|
284916
285191
|
if (!client) {
|
|
284917
285192
|
throw new Error("Droplit client is not configured. Set DROPLIT_API_URL and DROPLIT_FAUCET_NAME.");
|
|
284918
285193
|
}
|
|
284919
|
-
const { apiUrl
|
|
284920
|
-
|
|
284921
|
-
throw new Error("Droplit requests must be signed, but no auth key is configured.");
|
|
284922
|
-
}
|
|
284923
|
-
return { apiUrl, publicKeyHex: authKey.toPublicKey().toString(), client };
|
|
285194
|
+
const { apiUrl } = client.getConfig();
|
|
285195
|
+
return { apiUrl, publicKeyHex: await client.getIdentityKey(), client };
|
|
284924
285196
|
}
|
|
284925
285197
|
async function failIfNotOk(response, attempted) {
|
|
284926
285198
|
if (response.ok)
|
|
@@ -284928,9 +285200,9 @@ async function failIfNotOk(response, attempted) {
|
|
|
284928
285200
|
throw new Error(`${attempted} failed (${response.status}): ${await response.text()}`);
|
|
284929
285201
|
}
|
|
284930
285202
|
function registerSetupDroplitTools(server, integratedWallet) {
|
|
284931
|
-
server.tool("wallet_registerDroplitKey", "Registers
|
|
285203
|
+
server.tool("wallet_registerDroplitKey", "Registers public authentication material. Registration does not grant sponsor access; a sponsor owner must approve the wallet separately.", {}, async () => {
|
|
284932
285204
|
try {
|
|
284933
|
-
const { apiUrl, publicKeyHex } = requireDroplit(integratedWallet);
|
|
285205
|
+
const { apiUrl, publicKeyHex } = await requireDroplit(integratedWallet);
|
|
284934
285206
|
const response = await fetch(`${apiUrl}/auth/register`, {
|
|
284935
285207
|
method: "POST",
|
|
284936
285208
|
headers: { "Content-Type": "application/json" },
|
|
@@ -284945,13 +285217,13 @@ function registerSetupDroplitTools(server, integratedWallet) {
|
|
|
284945
285217
|
return createErrorResponse(error52);
|
|
284946
285218
|
}
|
|
284947
285219
|
});
|
|
284948
|
-
server.tool("wallet_createDroplitFaucet", "
|
|
285220
|
+
server.tool("wallet_createDroplitFaucet", "Creates a faucet owned by this wallet which must be funded before use. This does not provide free credit or approval for another sponsor.", {
|
|
284949
285221
|
faucetName: exports_external.string().min(1).describe("Identifier for the new faucet; must be unique"),
|
|
284950
285222
|
fixedDropSats: exports_external.number().int().positive().optional().describe("Satoshis paid out per tap. Server default applies if unset."),
|
|
284951
285223
|
maxConsolidationInputs: exports_external.number().int().positive().optional().describe("Cap on inputs the faucet consolidates in one transaction")
|
|
284952
285224
|
}, async ({ faucetName, fixedDropSats, maxConsolidationInputs }) => {
|
|
284953
285225
|
try {
|
|
284954
|
-
const { client } = requireDroplit(integratedWallet);
|
|
285226
|
+
const { client } = await requireDroplit(integratedWallet);
|
|
284955
285227
|
const body = {
|
|
284956
285228
|
name: faucetName,
|
|
284957
285229
|
...fixedDropSats !== undefined && {
|
|
@@ -284974,9 +285246,9 @@ function registerSetupDroplitTools(server, integratedWallet) {
|
|
|
284974
285246
|
return createErrorResponse(error52);
|
|
284975
285247
|
}
|
|
284976
285248
|
});
|
|
284977
|
-
server.tool("wallet_checkDroplitFaucetStatus", "Reads
|
|
285249
|
+
server.tool("wallet_checkDroplitFaucetStatus", "Reads public faucet balance and payout settings. This is not proof of caller authorization; use droplit_getAccess for that.", {}, async () => {
|
|
284978
285250
|
try {
|
|
284979
|
-
const { client } = requireDroplit(integratedWallet);
|
|
285251
|
+
const { client } = await requireDroplit(integratedWallet);
|
|
284980
285252
|
return createSuccessResponse({
|
|
284981
285253
|
faucetStatus: await client.getFaucetStatus()
|
|
284982
285254
|
});
|
|
@@ -294891,7 +295163,7 @@ var package_default2 = {
|
|
|
294891
295163
|
name: "bsv-mcp",
|
|
294892
295164
|
module: "dist/index.js",
|
|
294893
295165
|
type: "module",
|
|
294894
|
-
version: "0.3.
|
|
295166
|
+
version: "0.3.1",
|
|
294895
295167
|
license: "MIT",
|
|
294896
295168
|
author: "satchmo",
|
|
294897
295169
|
description: "A collection of Bitcoin SV (BSV) tools for the Model Context Protocol (MCP) framework",
|
|
@@ -295324,8 +295596,15 @@ function registerBrc100Tools(server, ctx) {
|
|
|
295324
295596
|
txJSON: exports_external.string().describe("JSON array of AtomicBEEF bytes"),
|
|
295325
295597
|
outputsJSON: exports_external.string().describe("JSON array of outputs to internalize"),
|
|
295326
295598
|
description: exports_external.string().describe("5-50 char description"),
|
|
295327
|
-
labelsJSON: exports_external.string().optional().describe("JSON array of label strings")
|
|
295328
|
-
|
|
295599
|
+
labelsJSON: exports_external.string().optional().describe("JSON array of label strings"),
|
|
295600
|
+
seekPermission: exports_external.boolean().optional()
|
|
295601
|
+
}, async ({
|
|
295602
|
+
txJSON,
|
|
295603
|
+
outputsJSON,
|
|
295604
|
+
description,
|
|
295605
|
+
labelsJSON,
|
|
295606
|
+
seekPermission
|
|
295607
|
+
}) => {
|
|
295329
295608
|
if (!ctx)
|
|
295330
295609
|
return noCtx;
|
|
295331
295610
|
try {
|
|
@@ -295333,6 +295612,7 @@ function registerBrc100Tools(server, ctx) {
|
|
|
295333
295612
|
tx: parseRequiredJSON("txJSON", txJSON),
|
|
295334
295613
|
outputs: parseRequiredJSON("outputsJSON", outputsJSON),
|
|
295335
295614
|
description,
|
|
295615
|
+
seekPermission,
|
|
295336
295616
|
labels: parseJSON("labelsJSON", labelsJSON)
|
|
295337
295617
|
}));
|
|
295338
295618
|
} catch (e2) {
|
|
@@ -295349,7 +295629,8 @@ function registerBrc100Tools(server, ctx) {
|
|
|
295349
295629
|
includeOutputs: exports_external.boolean().default(false),
|
|
295350
295630
|
includeOutputLockingScripts: exports_external.boolean().default(false),
|
|
295351
295631
|
limit: exports_external.number().default(25),
|
|
295352
|
-
offset: exports_external.number().default(0)
|
|
295632
|
+
offset: exports_external.number().default(0),
|
|
295633
|
+
seekPermission: exports_external.boolean().optional()
|
|
295353
295634
|
}, async ({ labelsJSON, ...rest }) => {
|
|
295354
295635
|
if (!ctx)
|
|
295355
295636
|
return noCtx;
|
|
@@ -295371,7 +295652,8 @@ function registerBrc100Tools(server, ctx) {
|
|
|
295371
295652
|
includeTags: exports_external.boolean().default(false),
|
|
295372
295653
|
includeLabels: exports_external.boolean().default(false),
|
|
295373
295654
|
limit: exports_external.number().default(25),
|
|
295374
|
-
offset: exports_external.number().default(0)
|
|
295655
|
+
offset: exports_external.number().default(0),
|
|
295656
|
+
seekPermission: exports_external.boolean().optional()
|
|
295375
295657
|
}, async ({ tagsJSON, ...rest }) => {
|
|
295376
295658
|
if (!ctx)
|
|
295377
295659
|
return noCtx;
|
|
@@ -295423,7 +295705,9 @@ function registerBrc100Tools(server, ctx) {
|
|
|
295423
295705
|
protocolIDJSON: exports_external.string().describe("JSON array [securityLevel, protocolString]"),
|
|
295424
295706
|
keyID: exports_external.string(),
|
|
295425
295707
|
counterparty: exports_external.string().optional(),
|
|
295426
|
-
privileged: exports_external.boolean().optional()
|
|
295708
|
+
privileged: exports_external.boolean().optional(),
|
|
295709
|
+
privilegedReason: exports_external.string().optional(),
|
|
295710
|
+
seekPermission: exports_external.boolean().optional()
|
|
295427
295711
|
}, async ({ protocolIDJSON, ...rest }) => {
|
|
295428
295712
|
if (!ctx)
|
|
295429
295713
|
return noCtx;
|
|
@@ -295441,7 +295725,9 @@ function registerBrc100Tools(server, ctx) {
|
|
|
295441
295725
|
protocolIDJSON: exports_external.string().describe("JSON array [securityLevel, protocolString]"),
|
|
295442
295726
|
keyID: exports_external.string(),
|
|
295443
295727
|
counterparty: exports_external.string().optional(),
|
|
295444
|
-
privileged: exports_external.boolean().optional()
|
|
295728
|
+
privileged: exports_external.boolean().optional(),
|
|
295729
|
+
privilegedReason: exports_external.string().optional(),
|
|
295730
|
+
seekPermission: exports_external.boolean().optional()
|
|
295445
295731
|
}, async ({ protocolIDJSON, ...rest }) => {
|
|
295446
295732
|
if (!ctx)
|
|
295447
295733
|
return noCtx;
|
|
@@ -295459,7 +295745,9 @@ function registerBrc100Tools(server, ctx) {
|
|
|
295459
295745
|
protocolIDJSON: exports_external.string().describe("JSON array [securityLevel, protocolString]"),
|
|
295460
295746
|
keyID: exports_external.string(),
|
|
295461
295747
|
counterparty: exports_external.string().optional(),
|
|
295462
|
-
privileged: exports_external.boolean().optional()
|
|
295748
|
+
privileged: exports_external.boolean().optional(),
|
|
295749
|
+
privilegedReason: exports_external.string().optional(),
|
|
295750
|
+
seekPermission: exports_external.boolean().optional()
|
|
295463
295751
|
}, async ({ protocolIDJSON, ...rest }) => {
|
|
295464
295752
|
if (!ctx)
|
|
295465
295753
|
return noCtx;
|
|
@@ -295478,7 +295766,9 @@ function registerBrc100Tools(server, ctx) {
|
|
|
295478
295766
|
protocolIDJSON: exports_external.string().describe("JSON array [securityLevel, protocolString]"),
|
|
295479
295767
|
keyID: exports_external.string(),
|
|
295480
295768
|
counterparty: exports_external.string().optional(),
|
|
295481
|
-
privileged: exports_external.boolean().optional()
|
|
295769
|
+
privileged: exports_external.boolean().optional(),
|
|
295770
|
+
privilegedReason: exports_external.string().optional(),
|
|
295771
|
+
seekPermission: exports_external.boolean().optional()
|
|
295482
295772
|
}, async ({ protocolIDJSON, ...rest }) => {
|
|
295483
295773
|
if (!ctx)
|
|
295484
295774
|
return noCtx;
|
|
@@ -295497,7 +295787,9 @@ function registerBrc100Tools(server, ctx) {
|
|
|
295497
295787
|
protocolIDJSON: exports_external.string().describe("JSON array [securityLevel, protocolString]"),
|
|
295498
295788
|
keyID: exports_external.string(),
|
|
295499
295789
|
counterparty: exports_external.string().optional(),
|
|
295500
|
-
privileged: exports_external.boolean().optional()
|
|
295790
|
+
privileged: exports_external.boolean().optional(),
|
|
295791
|
+
privilegedReason: exports_external.string().optional(),
|
|
295792
|
+
seekPermission: exports_external.boolean().optional()
|
|
295501
295793
|
}, async ({ protocolIDJSON, ...rest }) => {
|
|
295502
295794
|
if (!ctx)
|
|
295503
295795
|
return noCtx;
|
|
@@ -295518,7 +295810,9 @@ function registerBrc100Tools(server, ctx) {
|
|
|
295518
295810
|
keyID: exports_external.string(),
|
|
295519
295811
|
counterparty: exports_external.string().optional(),
|
|
295520
295812
|
forSelf: exports_external.boolean().optional(),
|
|
295521
|
-
privileged: exports_external.boolean().optional()
|
|
295813
|
+
privileged: exports_external.boolean().optional(),
|
|
295814
|
+
privilegedReason: exports_external.string().optional(),
|
|
295815
|
+
seekPermission: exports_external.boolean().optional()
|
|
295522
295816
|
}, async ({ protocolIDJSON, ...rest }) => {
|
|
295523
295817
|
if (!ctx)
|
|
295524
295818
|
return noCtx;
|
|
@@ -295645,7 +295939,8 @@ function registerBrc100Tools(server, ctx) {
|
|
|
295645
295939
|
server.tool("wallet_discoverByIdentityKey", "Discovers certificates issued to a given identity key.", {
|
|
295646
295940
|
identityKey: exports_external.string().describe("Identity public key hex"),
|
|
295647
295941
|
limit: exports_external.number().default(25),
|
|
295648
|
-
offset: exports_external.number().default(0)
|
|
295942
|
+
offset: exports_external.number().default(0),
|
|
295943
|
+
seekPermission: exports_external.boolean().optional()
|
|
295649
295944
|
}, async (args) => {
|
|
295650
295945
|
if (!ctx)
|
|
295651
295946
|
return noCtx;
|
|
@@ -295658,7 +295953,8 @@ function registerBrc100Tools(server, ctx) {
|
|
|
295658
295953
|
server.tool("wallet_discoverByAttributes", "Discovers certificates matching specific attributes.", {
|
|
295659
295954
|
attributesJSON: exports_external.string().describe("JSON object of attribute key/value pairs to match"),
|
|
295660
295955
|
limit: exports_external.number().default(25),
|
|
295661
|
-
offset: exports_external.number().default(0)
|
|
295956
|
+
offset: exports_external.number().default(0),
|
|
295957
|
+
seekPermission: exports_external.boolean().optional()
|
|
295662
295958
|
}, async ({ attributesJSON, ...rest }) => {
|
|
295663
295959
|
if (!ctx)
|
|
295664
295960
|
return noCtx;
|
|
@@ -297365,14 +297661,16 @@ function registerWalletTools(server, wallet5, config2) {
|
|
|
297365
297661
|
registerRefreshUtxosTool(server, config2.ctx);
|
|
297366
297662
|
registerWalletGetBalanceTool(server, config2.ctx);
|
|
297367
297663
|
registerBrc100Tools(server, config2.ctx);
|
|
297368
|
-
if (config2.enableA2bTools) {
|
|
297664
|
+
if (config2.enableA2bTools && wallet5 && config2.identityPk) {
|
|
297369
297665
|
registerA2bPublishMcpTool(server, wallet5, config2.identityPk, {
|
|
297370
297666
|
disableBroadcasting: config2.disableBroadcasting
|
|
297371
297667
|
});
|
|
297372
297668
|
}
|
|
297373
297669
|
registerCreateOrdinalsTool(server, config2.ctx);
|
|
297374
|
-
|
|
297375
|
-
|
|
297670
|
+
if (wallet5) {
|
|
297671
|
+
registerGatherCollectionInfoTool(server, wallet5);
|
|
297672
|
+
registerMintCollectionTool(server, wallet5);
|
|
297673
|
+
}
|
|
297376
297674
|
registerGetOrdinalsTool(server, config2.ctx);
|
|
297377
297675
|
registerListTokensTool(server, config2.ctx);
|
|
297378
297676
|
registerGetBsv21BalancesTool(server, config2.ctx);
|
|
@@ -297412,7 +297710,7 @@ function registerAllTools(server, config2 = {}) {
|
|
|
297412
297710
|
if (enableA2bTools) {
|
|
297413
297711
|
registerA2bDiscoverTool(server);
|
|
297414
297712
|
}
|
|
297415
|
-
if (enableBapTools) {
|
|
297713
|
+
if (enableBapTools && (!config2.ctx || config2.wallet)) {
|
|
297416
297714
|
const bapConfig = {
|
|
297417
297715
|
disableBroadcasting: config2.disableBroadcasting,
|
|
297418
297716
|
identityPk: config2.identityPk,
|
|
@@ -297425,6 +297723,8 @@ function registerAllTools(server, config2 = {}) {
|
|
|
297425
297723
|
registerBsocialTools(server, { wallet: config2.wallet });
|
|
297426
297724
|
}
|
|
297427
297725
|
if (enableWalletTools) {
|
|
297726
|
+
if (config2.droplitClient)
|
|
297727
|
+
registerDroplitTools(server, config2.droplitClient, config2.disableBroadcasting);
|
|
297428
297728
|
if (config2.integratedWallet?.isDroplitMode) {
|
|
297429
297729
|
const droplitClient = config2.integratedWallet.getDroplitClient();
|
|
297430
297730
|
if (droplitClient) {
|
|
@@ -297434,7 +297734,7 @@ function registerAllTools(server, config2 = {}) {
|
|
|
297434
297734
|
}
|
|
297435
297735
|
console.error("Registered Droplit mode wallet tools");
|
|
297436
297736
|
}
|
|
297437
|
-
} else if (config2.wallet) {
|
|
297737
|
+
} else if (config2.wallet || config2.ctx) {
|
|
297438
297738
|
const walletToolOptions = {
|
|
297439
297739
|
disableBroadcasting: config2.disableBroadcasting === true,
|
|
297440
297740
|
enableA2bTools,
|
|
@@ -297444,7 +297744,7 @@ function registerAllTools(server, config2 = {}) {
|
|
|
297444
297744
|
registerWalletTools(server, config2.wallet, walletToolOptions);
|
|
297445
297745
|
}
|
|
297446
297746
|
}
|
|
297447
|
-
if (enableMneeTools) {
|
|
297747
|
+
if (enableMneeTools && (!config2.ctx || config2.wallet)) {
|
|
297448
297748
|
registerMneeTools(server);
|
|
297449
297749
|
}
|
|
297450
297750
|
}
|
|
@@ -297452,62 +297752,6 @@ function registerAllTools(server, config2 = {}) {
|
|
|
297452
297752
|
// tools/wallet/integratedWallet.ts
|
|
297453
297753
|
init_mod2();
|
|
297454
297754
|
|
|
297455
|
-
// utils/droplit.ts
|
|
297456
|
-
init_mod2();
|
|
297457
|
-
|
|
297458
|
-
class DroplitClient {
|
|
297459
|
-
config;
|
|
297460
|
-
authFetch;
|
|
297461
|
-
constructor(config2) {
|
|
297462
|
-
this.config = config2;
|
|
297463
|
-
if (config2.authKey) {
|
|
297464
|
-
this.authFetch = new AuthFetch(new ProtoWallet_default(config2.authKey));
|
|
297465
|
-
}
|
|
297466
|
-
}
|
|
297467
|
-
getConfig() {
|
|
297468
|
-
return this.config;
|
|
297469
|
-
}
|
|
297470
|
-
get base() {
|
|
297471
|
-
return this.config.apiUrl.replace(/\/+$/, "");
|
|
297472
|
-
}
|
|
297473
|
-
async authed(path5, init) {
|
|
297474
|
-
if (!this.authFetch) {
|
|
297475
|
-
throw new Error(`${path5} requires authentication and no Droplit auth key is configured.`);
|
|
297476
|
-
}
|
|
297477
|
-
return this.authFetch.fetch(`${this.base}${path5}`, {
|
|
297478
|
-
method: init.method,
|
|
297479
|
-
headers: { "Content-Type": "application/json" },
|
|
297480
|
-
...init.body === undefined ? {} : { body: JSON.stringify(init.body) }
|
|
297481
|
-
});
|
|
297482
|
-
}
|
|
297483
|
-
async parse(response, attempted) {
|
|
297484
|
-
if (response.ok)
|
|
297485
|
-
return await response.json();
|
|
297486
|
-
const raw = await response.text();
|
|
297487
|
-
let detail = raw.slice(0, 200);
|
|
297488
|
-
try {
|
|
297489
|
-
const parsed = JSON.parse(raw);
|
|
297490
|
-
detail = parsed.message ?? parsed.error ?? detail;
|
|
297491
|
-
} catch {}
|
|
297492
|
-
throw new Error(`${attempted} failed (${response.status}): ${detail}`);
|
|
297493
|
-
}
|
|
297494
|
-
async getFaucetStatus() {
|
|
297495
|
-
const response = await fetch(`${this.base}/faucet/${this.config.faucetName}/status`);
|
|
297496
|
-
return this.parse(response, "Reading the faucet status");
|
|
297497
|
-
}
|
|
297498
|
-
async tap(recipientAddress) {
|
|
297499
|
-
const response = await this.authed(`/faucet/${this.config.faucetName}/tap`, { method: "POST", body: { recipient_address: recipientAddress } });
|
|
297500
|
-
return this.parse(response, "Tapping the faucet");
|
|
297501
|
-
}
|
|
297502
|
-
async push(data, encoding = "hex") {
|
|
297503
|
-
const response = await this.authed(`/faucet/${this.config.faucetName}/push`, { method: "POST", body: { data, encoding } });
|
|
297504
|
-
return this.parse(response, "Pushing data");
|
|
297505
|
-
}
|
|
297506
|
-
async authenticatedFetch(path5, init) {
|
|
297507
|
-
return this.authed(path5, init);
|
|
297508
|
-
}
|
|
297509
|
-
}
|
|
297510
|
-
|
|
297511
297755
|
// tools/wallet/wallet.ts
|
|
297512
297756
|
init_mod2();
|
|
297513
297757
|
class Wallet {
|
|
@@ -297706,7 +297950,7 @@ class IntegratedWallet {
|
|
|
297706
297950
|
}
|
|
297707
297951
|
async sendToAddress(address, satoshis) {
|
|
297708
297952
|
if (this.droplitClient) {
|
|
297709
|
-
const response = await this.droplitClient.tap(address);
|
|
297953
|
+
const response = await this.droplitClient.tap(address, satoshis);
|
|
297710
297954
|
return { txid: response.txid };
|
|
297711
297955
|
}
|
|
297712
297956
|
if (this.localWallet) {
|
|
@@ -297912,6 +298156,245 @@ class Wallet2 {
|
|
|
297912
298156
|
}
|
|
297913
298157
|
}
|
|
297914
298158
|
|
|
298159
|
+
// utils/droplit.ts
|
|
298160
|
+
init_mod2();
|
|
298161
|
+
function readDroplitSponsorConfig(env = process.env) {
|
|
298162
|
+
const apiUrl = env.DROPLIT_API_URL;
|
|
298163
|
+
const faucetName = env.DROPLIT_FAUCET_NAME;
|
|
298164
|
+
if (apiUrl === undefined && faucetName === undefined)
|
|
298165
|
+
return;
|
|
298166
|
+
if (!apiUrl?.trim() || !faucetName?.trim()) {
|
|
298167
|
+
throw new Error("DROPLIT_API_URL and DROPLIT_FAUCET_NAME must both be explicitly configured");
|
|
298168
|
+
}
|
|
298169
|
+
return { apiUrl, faucetName };
|
|
298170
|
+
}
|
|
298171
|
+
|
|
298172
|
+
class DroplitError2 extends Error {
|
|
298173
|
+
code;
|
|
298174
|
+
status;
|
|
298175
|
+
details;
|
|
298176
|
+
constructor(code, message, status, details = {}) {
|
|
298177
|
+
super(message);
|
|
298178
|
+
this.code = code;
|
|
298179
|
+
this.status = status;
|
|
298180
|
+
this.details = details;
|
|
298181
|
+
}
|
|
298182
|
+
}
|
|
298183
|
+
function quotaDetails2(body) {
|
|
298184
|
+
if (!body || typeof body !== "object")
|
|
298185
|
+
return {};
|
|
298186
|
+
const value2 = body;
|
|
298187
|
+
return {
|
|
298188
|
+
...typeof value2.remaining === "number" || value2.remaining === null ? { remaining: value2.remaining } : {},
|
|
298189
|
+
...typeof value2.resets_at === "string" ? { resets_at: value2.resets_at } : {}
|
|
298190
|
+
};
|
|
298191
|
+
}
|
|
298192
|
+
function httpFailure2(status, details = {}) {
|
|
298193
|
+
const known = {
|
|
298194
|
+
401: [
|
|
298195
|
+
"authentication_required",
|
|
298196
|
+
"Authenticate with the configured wallet before retrying."
|
|
298197
|
+
],
|
|
298198
|
+
402: [
|
|
298199
|
+
"approval_required",
|
|
298200
|
+
"Payment is required. No automatic payment was made; review payment with the wallet owner."
|
|
298201
|
+
],
|
|
298202
|
+
403: [
|
|
298203
|
+
"approval_required",
|
|
298204
|
+
"The sponsor has not authorized this action. Ask its owner to approve your wallet."
|
|
298205
|
+
],
|
|
298206
|
+
429: [
|
|
298207
|
+
"quota_exceeded",
|
|
298208
|
+
"Sponsor quota exhausted. Wait until resets_at or ask the owner to adjust your quota."
|
|
298209
|
+
]
|
|
298210
|
+
};
|
|
298211
|
+
const [code, message] = known[status] ?? [
|
|
298212
|
+
"http_error",
|
|
298213
|
+
"Droplit rejected the request. Check sponsor access and transaction history before retrying."
|
|
298214
|
+
];
|
|
298215
|
+
return new DroplitError2(code, message, status, details);
|
|
298216
|
+
}
|
|
298217
|
+
|
|
298218
|
+
class DroplitClient2 {
|
|
298219
|
+
config;
|
|
298220
|
+
authFetch;
|
|
298221
|
+
wallet;
|
|
298222
|
+
constructor(config2) {
|
|
298223
|
+
this.config = config2;
|
|
298224
|
+
if (config2.wallet && config2.authKey)
|
|
298225
|
+
throw new Error("Configure Droplit wallet or authKey, not both");
|
|
298226
|
+
const url3 = new URL(config2.apiUrl);
|
|
298227
|
+
const loopback = url3.hostname === "localhost" || url3.hostname === "127.0.0.1" || url3.hostname === "[::1]";
|
|
298228
|
+
if (url3.username || url3.password || url3.search || url3.hash || !(url3.protocol === "https:" || url3.protocol === "http:" && loopback)) {
|
|
298229
|
+
throw new Error("Droplit API requires HTTPS or HTTP loopback without credentials, query or fragment");
|
|
298230
|
+
}
|
|
298231
|
+
if (!config2.faucetName.trim())
|
|
298232
|
+
throw new Error("Droplit faucet name is required");
|
|
298233
|
+
this.wallet = config2.wallet ?? (config2.authKey ? new ProtoWallet_default(config2.authKey) : undefined);
|
|
298234
|
+
if (this.wallet) {
|
|
298235
|
+
const authenticationWallet = new Proxy(this.wallet, {
|
|
298236
|
+
get(target, property) {
|
|
298237
|
+
if (property === "createAction" || property === "signAction") {
|
|
298238
|
+
return async () => {
|
|
298239
|
+
throw httpFailure2(402);
|
|
298240
|
+
};
|
|
298241
|
+
}
|
|
298242
|
+
const value2 = Reflect.get(target, property, target);
|
|
298243
|
+
return typeof value2 === "function" ? value2.bind(target) : value2;
|
|
298244
|
+
}
|
|
298245
|
+
});
|
|
298246
|
+
this.authFetch = new AuthFetch(authenticationWallet);
|
|
298247
|
+
}
|
|
298248
|
+
}
|
|
298249
|
+
getConfig() {
|
|
298250
|
+
return { apiUrl: this.config.apiUrl, faucetName: this.config.faucetName };
|
|
298251
|
+
}
|
|
298252
|
+
async getIdentityKey() {
|
|
298253
|
+
if (!this.wallet)
|
|
298254
|
+
throw new DroplitError2("authentication_required", "Configure a Droplit wallet identity.");
|
|
298255
|
+
const { publicKey } = await this.wallet.getPublicKey({ identityKey: true });
|
|
298256
|
+
return publicKey;
|
|
298257
|
+
}
|
|
298258
|
+
get faucetPath() {
|
|
298259
|
+
return `/faucet/${encodeURIComponent(this.config.faucetName)}`;
|
|
298260
|
+
}
|
|
298261
|
+
get base() {
|
|
298262
|
+
return this.config.apiUrl.replace(/\/+$/, "");
|
|
298263
|
+
}
|
|
298264
|
+
async authed(path5, init) {
|
|
298265
|
+
if (!this.authFetch) {
|
|
298266
|
+
throw new Error(`${path5} requires authentication and no Droplit auth key is configured.`);
|
|
298267
|
+
}
|
|
298268
|
+
try {
|
|
298269
|
+
return await this.authFetch.fetch(`${this.base}${path5}`, {
|
|
298270
|
+
method: init.method,
|
|
298271
|
+
headers: { "Content-Type": "application/json" },
|
|
298272
|
+
...init.body === undefined ? {} : { body: JSON.stringify(init.body) },
|
|
298273
|
+
paymentRetryAttempts: 0,
|
|
298274
|
+
...init.method === "GET" || init.method === "HEAD" ? {} : { retryCounter: 1 }
|
|
298275
|
+
});
|
|
298276
|
+
} catch (error53) {
|
|
298277
|
+
if (error53 instanceof DroplitError2)
|
|
298278
|
+
throw error53;
|
|
298279
|
+
const details = error53?.details;
|
|
298280
|
+
const status = details?.status;
|
|
298281
|
+
if (typeof status === "number" && [401, 402, 403, 429].includes(status)) {
|
|
298282
|
+
let body;
|
|
298283
|
+
if (status === 429 && typeof details?.bodyPreview === "string") {
|
|
298284
|
+
try {
|
|
298285
|
+
body = JSON.parse(details.bodyPreview);
|
|
298286
|
+
} catch {}
|
|
298287
|
+
}
|
|
298288
|
+
throw httpFailure2(status, status === 429 ? quotaDetails2(body) : {});
|
|
298289
|
+
}
|
|
298290
|
+
const write = init.method !== "GET" && init.method !== "HEAD";
|
|
298291
|
+
throw new DroplitError2(write ? "unknown_outcome" : "request_failed", write ? "Request outcome is unknown. Reconcile transaction/history before retrying; no automatic retry was made." : "Authenticated request failed. Check the signer and sponsor connection.");
|
|
298292
|
+
}
|
|
298293
|
+
}
|
|
298294
|
+
async parse(response, _attempted) {
|
|
298295
|
+
if (response.ok) {
|
|
298296
|
+
try {
|
|
298297
|
+
return await response.json();
|
|
298298
|
+
} catch {
|
|
298299
|
+
throw new DroplitError2("unknown_outcome", "Response could not be read. Reconcile transaction/history before retrying.", response.status);
|
|
298300
|
+
}
|
|
298301
|
+
}
|
|
298302
|
+
let body = {};
|
|
298303
|
+
try {
|
|
298304
|
+
body = await response.json();
|
|
298305
|
+
} catch {}
|
|
298306
|
+
throw httpFailure2(response.status, response.status === 429 ? quotaDetails2(body) : {});
|
|
298307
|
+
}
|
|
298308
|
+
async getAccess() {
|
|
298309
|
+
const response = await this.authed(`${this.faucetPath}/access`, {
|
|
298310
|
+
method: "GET"
|
|
298311
|
+
});
|
|
298312
|
+
const access = await this.parse(response, "Reading sponsor access");
|
|
298313
|
+
const identity6 = await this.getIdentityKey();
|
|
298314
|
+
if (!access || access.public_key !== identity6 || access.slug !== this.config.faucetName || typeof access.authorized !== "boolean" || typeof access.is_owner !== "boolean" || !Array.isArray(access.quotas) || !Array.isArray(access.unrestricted_kinds)) {
|
|
298315
|
+
throw new DroplitError2("invalid_response", "Sponsor access response did not match the authenticated wallet.");
|
|
298316
|
+
}
|
|
298317
|
+
access.approval_path = `/droplit/${encodeURIComponent(this.config.faucetName)}?tab=api&request_key=${encodeURIComponent(identity6)}`;
|
|
298318
|
+
return access;
|
|
298319
|
+
}
|
|
298320
|
+
async fund(rawtx) {
|
|
298321
|
+
const response = await this.authed(`${this.faucetPath}/fund`, {
|
|
298322
|
+
method: "POST",
|
|
298323
|
+
body: { rawtx }
|
|
298324
|
+
});
|
|
298325
|
+
return this.parse(response, "Funding transaction");
|
|
298326
|
+
}
|
|
298327
|
+
async getFaucetStatus() {
|
|
298328
|
+
const response = await fetch(`${this.base}${this.faucetPath}/status`);
|
|
298329
|
+
return this.parse(response, "Reading the faucet status");
|
|
298330
|
+
}
|
|
298331
|
+
async tap(recipientAddress, satoshis) {
|
|
298332
|
+
if (satoshis !== undefined && (!Number.isSafeInteger(satoshis) || satoshis <= 0))
|
|
298333
|
+
throw new Error("satoshis must be a positive safe integer");
|
|
298334
|
+
const response = await this.authed(`${this.faucetPath}/tap`, {
|
|
298335
|
+
method: "POST",
|
|
298336
|
+
body: {
|
|
298337
|
+
recipient_address: recipientAddress,
|
|
298338
|
+
...satoshis === undefined ? {} : { satoshis }
|
|
298339
|
+
}
|
|
298340
|
+
});
|
|
298341
|
+
return this.parse(response, "Tapping the faucet");
|
|
298342
|
+
}
|
|
298343
|
+
async push(data, encoding = "hex") {
|
|
298344
|
+
const response = await this.authed(`${this.faucetPath}/push`, {
|
|
298345
|
+
method: "POST",
|
|
298346
|
+
body: { data, encoding }
|
|
298347
|
+
});
|
|
298348
|
+
return this.parse(response, "Pushing data");
|
|
298349
|
+
}
|
|
298350
|
+
async authenticatedFetch(path5, init) {
|
|
298351
|
+
return this.authed(path5, init);
|
|
298352
|
+
}
|
|
298353
|
+
}
|
|
298354
|
+
|
|
298355
|
+
// utils/externalWalletConfig.ts
|
|
298356
|
+
function readExternalWalletConfig(env = process.env) {
|
|
298357
|
+
const raw = env.BRC100_WALLET_URL;
|
|
298358
|
+
if (raw === undefined) {
|
|
298359
|
+
if (env.BRC100_WALLET_ORIGINATOR !== undefined) {
|
|
298360
|
+
throw new Error("BRC100_WALLET_ORIGINATOR requires BRC100_WALLET_URL");
|
|
298361
|
+
}
|
|
298362
|
+
return;
|
|
298363
|
+
}
|
|
298364
|
+
for (const name of ["PRIVATE_KEY_WIF", "IDENTITY_KEY_WIF"]) {
|
|
298365
|
+
if (env[name] !== undefined) {
|
|
298366
|
+
throw new Error(`BRC100_WALLET_URL conflicts with ${name}; select one wallet identity`);
|
|
298367
|
+
}
|
|
298368
|
+
}
|
|
298369
|
+
if (env.USE_DROPLIT_API === "true") {
|
|
298370
|
+
throw new Error("BRC100_WALLET_URL conflicts with USE_DROPLIT_API");
|
|
298371
|
+
}
|
|
298372
|
+
let url3;
|
|
298373
|
+
try {
|
|
298374
|
+
url3 = new URL(raw);
|
|
298375
|
+
} catch {
|
|
298376
|
+
throw new Error("BRC100_WALLET_URL must be a valid signer RPC URL");
|
|
298377
|
+
}
|
|
298378
|
+
const loopback = url3.hostname === "localhost" || url3.hostname === "[::1]" || /^127\.(?:\d{1,3}\.){2}\d{1,3}$/.test(url3.hostname);
|
|
298379
|
+
if (!raw || raw !== raw.trim() || /[\\\s@?]/.test(raw) || url3.username || url3.password || raw.includes("#") || url3.search || !(url3.protocol === "https:" || url3.protocol === "http:" && loopback)) {
|
|
298380
|
+
throw new Error("BRC100_WALLET_URL requires HTTPS or HTTP loopback, without credentials, queries or fragments");
|
|
298381
|
+
}
|
|
298382
|
+
const originator = env.BRC100_WALLET_ORIGINATOR ?? "bsv-mcp.local";
|
|
298383
|
+
let origin;
|
|
298384
|
+
try {
|
|
298385
|
+
origin = new URL(originator.includes("://") ? originator : `http://${originator}`);
|
|
298386
|
+
} catch {
|
|
298387
|
+
throw new Error("BRC100_WALLET_ORIGINATOR must be a domain or HTTP(S) origin");
|
|
298388
|
+
}
|
|
298389
|
+
if (!originator || /[\s\\]/.test(originator) || originator.length >= 250 || !["http:", "https:"].includes(origin.protocol) || origin.username || origin.password || origin.pathname !== "/" || origin.search || /[#?@]/.test(originator) || !/^(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)*|\[::1\])$/i.test(origin.hostname) || origin.hostname.toLowerCase() === "admin.bsv-mcp.internal") {
|
|
298390
|
+
throw new Error("BRC100_WALLET_ORIGINATOR must be a non-admin domain or HTTP(S) origin without credentials, path, query or fragment");
|
|
298391
|
+
}
|
|
298392
|
+
return { url: url3.toString().replace(/\/$/, ""), originator };
|
|
298393
|
+
}
|
|
298394
|
+
async function initializeKeysForWalletMode(external4, loadLocalKeys) {
|
|
298395
|
+
return external4 ? undefined : loadLocalKeys();
|
|
298396
|
+
}
|
|
298397
|
+
|
|
297915
298398
|
// node_modules/jose/dist/webapi/lib/buffer_utils.js
|
|
297916
298399
|
var encoder = new TextEncoder;
|
|
297917
298400
|
var decoder = new TextDecoder;
|
|
@@ -301997,9 +302480,19 @@ async function buildLocalStorage(config2, baseOptions) {
|
|
|
301997
302480
|
init_storage_pg();
|
|
301998
302481
|
var import_wallet_toolbox2 = __toESM(require_src6(), 1);
|
|
301999
302482
|
|
|
302483
|
+
// node_modules/@1sat/wallet-remote/dist/index.js
|
|
302484
|
+
init_dist4();
|
|
302485
|
+
|
|
302486
|
+
// node_modules/@1sat/wallet-remote/dist/createRemoteWallet.js
|
|
302487
|
+
init_dist4();
|
|
302488
|
+
var import_index_client2 = __toESM(require_index_client5(), 1);
|
|
302489
|
+
|
|
302490
|
+
// node_modules/@1sat/wallet-remote/dist/index.js
|
|
302491
|
+
var import_index_client3 = __toESM(require_index_client5(), 1);
|
|
302492
|
+
|
|
302000
302493
|
// utils/walletInit.ts
|
|
302001
302494
|
init_mod2();
|
|
302002
|
-
var
|
|
302495
|
+
var import_index_client4 = __toESM(require_index_client5(), 1);
|
|
302003
302496
|
|
|
302004
302497
|
// utils/spendingApproval.ts
|
|
302005
302498
|
var serverInstance2 = null;
|
|
@@ -302096,7 +302589,7 @@ async function initWallet(privateKeyWif, chain = "main") {
|
|
|
302096
302589
|
activeRemote: process.env.REMOTE_STORAGE_URL ?? DEFAULT_REMOTE_STORAGE_URL,
|
|
302097
302590
|
storageIdentityKey: "bsv-mcp"
|
|
302098
302591
|
});
|
|
302099
|
-
const wpm = new
|
|
302592
|
+
const wpm = new import_index_client4.WalletPermissionsManager(result2.wallet, ADMIN_ORIGINATOR, {
|
|
302100
302593
|
seekProtocolPermissionsForSigning: false,
|
|
302101
302594
|
seekProtocolPermissionsForEncrypting: false,
|
|
302102
302595
|
seekProtocolPermissionsForHMAC: false,
|
|
@@ -302138,7 +302631,7 @@ async function initWallet(privateKeyWif, chain = "main") {
|
|
|
302138
302631
|
}).catch((err) => {
|
|
302139
302632
|
console.error("[wallet] message box sync failed:", err);
|
|
302140
302633
|
});
|
|
302141
|
-
activeResult =
|
|
302634
|
+
activeResult = result2;
|
|
302142
302635
|
return {
|
|
302143
302636
|
wallet: wpm,
|
|
302144
302637
|
services: result2.services,
|
|
@@ -302147,6 +302640,36 @@ async function initWallet(privateKeyWif, chain = "main") {
|
|
|
302147
302640
|
destroy: result2.destroy
|
|
302148
302641
|
};
|
|
302149
302642
|
}
|
|
302643
|
+
async function initExternalWallet(config2, chain = "main") {
|
|
302644
|
+
const httpClient = (input, init) => fetch(input, {
|
|
302645
|
+
...init,
|
|
302646
|
+
redirect: "error",
|
|
302647
|
+
signal: init?.signal ? AbortSignal.any([init.signal, AbortSignal.timeout(1e4)]) : AbortSignal.timeout(1e4)
|
|
302648
|
+
});
|
|
302649
|
+
const wallet7 = new HTTPWalletJSON(config2.originator, config2.url, httpClient);
|
|
302650
|
+
let identityKey;
|
|
302651
|
+
try {
|
|
302652
|
+
const identity6 = await wallet7.getPublicKey({ identityKey: true });
|
|
302653
|
+
if (!/^(02|03)[0-9a-f]{64}$/i.test(identity6.publicKey)) {
|
|
302654
|
+
throw new Error("Signer returned an invalid compressed identity public key");
|
|
302655
|
+
}
|
|
302656
|
+
PublicKey.fromString(identity6.publicKey);
|
|
302657
|
+
identityKey = identity6.publicKey;
|
|
302658
|
+
} catch (error53) {
|
|
302659
|
+
throw new Error("External BRC-100 signer readiness failed. Check BRC100_WALLET_URL and approve identity access in the signer. This must be SDK signer RPC, not 1sat serve wallet storage RPC. No local wallet was created.", { cause: error53 });
|
|
302660
|
+
}
|
|
302661
|
+
const services2 = new OneSatServices(chain, process.env.ONESAT_API_URL);
|
|
302662
|
+
const dataDir = join2(homedir(), ".bsv-mcp");
|
|
302663
|
+
const ctx = createContext(wallet7, {
|
|
302664
|
+
services: services2,
|
|
302665
|
+
chain,
|
|
302666
|
+
dataDir,
|
|
302667
|
+
log: (entry) => writeAuditLog(dataDir, entry)
|
|
302668
|
+
});
|
|
302669
|
+
const destroy = async () => {};
|
|
302670
|
+
activeResult = { destroy };
|
|
302671
|
+
return { wallet: wallet7, ctx, services: services2, identityKey, destroy };
|
|
302672
|
+
}
|
|
302150
302673
|
async function destroyWallet() {
|
|
302151
302674
|
if (activeResult) {
|
|
302152
302675
|
await activeResult.destroy();
|
|
@@ -302283,7 +302806,7 @@ async function initializeKeys() {
|
|
|
302283
302806
|
}
|
|
302284
302807
|
var APP_RESOURCE_URI = "ui://bsv-mcp/app.html";
|
|
302285
302808
|
var __appDirname = dirname2(fileURLToPath(import.meta.url));
|
|
302286
|
-
function registerMcpAppTools(server2,
|
|
302809
|
+
function registerMcpAppTools(server2, wallet7, ctx) {
|
|
302287
302810
|
K3(server2, "bsv_dashboard", {
|
|
302288
302811
|
title: "BSV Dashboard",
|
|
302289
302812
|
description: "Interactive BSV dashboard with Explorer, Wallet, and Ordinals tabs. Use this for any BSV-related query that benefits from visual display.",
|
|
@@ -302433,7 +302956,7 @@ function registerMcpAppTools(server2, wallet6, ctx) {
|
|
|
302433
302956
|
ui: { resourceUri: APP_RESOURCE_URI, visibility: ["app"] }
|
|
302434
302957
|
}
|
|
302435
302958
|
}, async () => {
|
|
302436
|
-
if (!ctx && !
|
|
302959
|
+
if (!ctx && !wallet7) {
|
|
302437
302960
|
return {
|
|
302438
302961
|
content: [
|
|
302439
302962
|
{
|
|
@@ -302465,9 +302988,9 @@ function registerMcpAppTools(server2, wallet6, ctx) {
|
|
|
302465
302988
|
const [txid = "", voutStr = "0"] = (o6.outpoint ?? "").split(".");
|
|
302466
302989
|
return { txid, vout: Number(voutStr), satoshis: o6.satoshis };
|
|
302467
302990
|
});
|
|
302468
|
-
} else if (
|
|
302469
|
-
address =
|
|
302470
|
-
const { paymentUtxos } = await
|
|
302991
|
+
} else if (wallet7) {
|
|
302992
|
+
address = wallet7.getAddress();
|
|
302993
|
+
const { paymentUtxos } = await wallet7.getUtxos();
|
|
302471
302994
|
for (const utxo of paymentUtxos) {
|
|
302472
302995
|
totalSatoshis += utxo.satoshis || 0;
|
|
302473
302996
|
}
|
|
@@ -302892,6 +303415,8 @@ Options:
|
|
|
302892
303415
|
Environment Variables:
|
|
302893
303416
|
TRANSPORT Transport mode: 'stdio' or 'http' (default: http)
|
|
302894
303417
|
PORT HTTP server port (default: 3000)
|
|
303418
|
+
BRC100_WALLET_URL Existing SDK HTTPWalletJSON signer RPC URL
|
|
303419
|
+
BRC100_WALLET_ORIGINATOR Signer permission origin (default: bsv-mcp.local)
|
|
302895
303420
|
PRIVATE_KEY_WIF Payment private key in WIF format
|
|
302896
303421
|
DISABLE_TOOLS Disable all tools (default: false)
|
|
302897
303422
|
DISABLE_WALLET_TOOLS Disable wallet tools (default: false)
|
|
@@ -302915,7 +303440,7 @@ Tool Categories:
|
|
|
302915
303440
|
|
|
302916
303441
|
Authentication:
|
|
302917
303442
|
- Most tools work without authentication
|
|
302918
|
-
- Wallet operations
|
|
303443
|
+
- Wallet operations use BRC100_WALLET_URL, PRIVATE_KEY_WIF or generated keys
|
|
302919
303444
|
- BAP/A2B tools require identity keys (generated via bap_generate tool)
|
|
302920
303445
|
`);
|
|
302921
303446
|
process.exit(0);
|
|
@@ -302924,11 +303449,31 @@ Authentication:
|
|
|
302924
303449
|
console.log(`${package_default.name} v${package_default.version}`);
|
|
302925
303450
|
process.exit(0);
|
|
302926
303451
|
}
|
|
302927
|
-
const
|
|
303452
|
+
const externalWallet = readExternalWalletConfig();
|
|
303453
|
+
const sponsorConfig = CONFIG.useDroplitApi ? undefined : readDroplitSponsorConfig();
|
|
303454
|
+
const keys = await initializeKeysForWalletMode(externalWallet, initializeKeys);
|
|
303455
|
+
const {
|
|
303456
|
+
payPk,
|
|
303457
|
+
identityPk,
|
|
303458
|
+
xprv,
|
|
303459
|
+
source: keySource
|
|
303460
|
+
} = keys ?? {
|
|
303461
|
+
payPk: undefined,
|
|
303462
|
+
identityPk: undefined,
|
|
303463
|
+
xprv: undefined,
|
|
303464
|
+
source: "external"
|
|
303465
|
+
};
|
|
302928
303466
|
const hasPersistentPayKey = keySource === "env" || keySource === "file" || keySource === "encrypted";
|
|
302929
303467
|
const hasPersistentIdentityKey = !!identityPk && (keySource === "file" || keySource === "encrypted");
|
|
302930
303468
|
const hasXprv = !!xprv && (keySource === "file" || keySource === "env" || keySource === "encrypted");
|
|
302931
303469
|
const effectiveConfig = { ...CONFIG };
|
|
303470
|
+
if (externalWallet) {
|
|
303471
|
+
effectiveConfig.loadBapTools = false;
|
|
303472
|
+
effectiveConfig.loadBsocialTools = false;
|
|
303473
|
+
effectiveConfig.loadMneeTools = false;
|
|
303474
|
+
effectiveConfig.loadA2bTools = false;
|
|
303475
|
+
logFunc2("External BRC-100 signer selected; local key loading and generation bypassed.");
|
|
303476
|
+
}
|
|
302932
303477
|
logFunc2(`
|
|
302933
303478
|
--- BSV MCP Server Configuration ---`);
|
|
302934
303479
|
logFunc2(`Server Version: ${package_default.version}`);
|
|
@@ -302939,8 +303484,8 @@ Environment Variables:`);
|
|
|
302939
303484
|
if (CONFIG.transportMode === "http") {
|
|
302940
303485
|
logFunc2(` PORT: ${process.env.PORT || "Not Set (3000 default)"}`);
|
|
302941
303486
|
}
|
|
302942
|
-
logFunc2(` PRIVATE_KEY_WIF: ${process.env.PRIVATE_KEY_WIF ? "Set (using env key)" : "Not Set (using file/generating)"}`);
|
|
302943
|
-
logFunc2(` IDENTITY_KEY_WIF: ${process.env.IDENTITY_KEY_WIF ? "Set (using env key)" : "Not Set (using file/generating)"}`);
|
|
303487
|
+
logFunc2(` PRIVATE_KEY_WIF: ${externalWallet ? "Unused (external signer)" : process.env.PRIVATE_KEY_WIF ? "Set (using env key)" : "Not Set (using file/generating)"}`);
|
|
303488
|
+
logFunc2(` IDENTITY_KEY_WIF: ${externalWallet ? "Unused (external signer)" : process.env.IDENTITY_KEY_WIF ? "Set (using env key)" : "Not Set (using file/generating)"}`);
|
|
302944
303489
|
if (process.env.BSV_MCP_PASSPHRASE) {
|
|
302945
303490
|
logFunc2(" BSV_MCP_PASSPHRASE: \x1B[31mDEPRECATED - Remove this!\x1B[0m");
|
|
302946
303491
|
}
|
|
@@ -302996,11 +303541,11 @@ Effective Component Status:`);
|
|
|
302996
303541
|
const a2bStatus = effectiveConfig.loadA2bTools ? "\x1B[32mEnabled\x1B[0m" : "\x1B[31mDisabled\x1B[0m";
|
|
302997
303542
|
const bapStatus = effectiveConfig.loadBapTools ? "\x1B[32mEnabled\x1B[0m" : "\x1B[31mDisabled\x1B[0m";
|
|
302998
303543
|
let payKeyNote = "";
|
|
302999
|
-
if (!hasPersistentPayKey) {
|
|
303544
|
+
if (!externalWallet && !hasPersistentPayKey) {
|
|
303000
303545
|
payKeyNote = " \x1B[33m(Using generated payPk)\x1B[0m";
|
|
303001
303546
|
}
|
|
303002
303547
|
let identityKeyNote = "";
|
|
303003
|
-
if (!hasPersistentIdentityKey) {
|
|
303548
|
+
if (!externalWallet && !hasPersistentIdentityKey) {
|
|
303004
303549
|
identityKeyNote = " \x1B[33m(Using generated identityPk)\x1B[0m";
|
|
303005
303550
|
}
|
|
303006
303551
|
logFunc2(` Wallet: ${walletStatus}${payKeyNote}`);
|
|
@@ -303017,12 +303562,20 @@ Effective Component Status:`);
|
|
|
303017
303562
|
}
|
|
303018
303563
|
logFunc2(`------------------------------------
|
|
303019
303564
|
`);
|
|
303020
|
-
let
|
|
303565
|
+
let wallet7;
|
|
303021
303566
|
let integratedWallet;
|
|
303022
303567
|
let remoteCtx;
|
|
303023
303568
|
let remoteServices;
|
|
303024
303569
|
if (CONFIG.loadTools) {
|
|
303025
|
-
if (
|
|
303570
|
+
if (externalWallet) {
|
|
303571
|
+
const chain = process.env.BSV_CHAIN ?? "main";
|
|
303572
|
+
if (chain !== "main" && chain !== "test")
|
|
303573
|
+
throw new Error("BSV_CHAIN must be main or test");
|
|
303574
|
+
const result2 = await initExternalWallet(externalWallet, chain);
|
|
303575
|
+
remoteCtx = result2.ctx;
|
|
303576
|
+
remoteServices = result2.services;
|
|
303577
|
+
logFunc2(`External BRC-100 signer ready. Identity: ${result2.identityKey}`);
|
|
303578
|
+
} else if (CONFIG.useDroplitApi && CONFIG.droplitFaucetName) {
|
|
303026
303579
|
if (CONFIG.loadWalletTools) {
|
|
303027
303580
|
try {
|
|
303028
303581
|
integratedWallet = new IntegratedWallet({
|
|
@@ -303037,7 +303590,7 @@ Effective Component Status:`);
|
|
|
303037
303590
|
logFunc2(`\x1B[32mINFO: Droplit API mode initialized successfully (Faucet: ${CONFIG.droplitFaucetName}).\x1B[0m`);
|
|
303038
303591
|
logFunc2(`\x1B[33mNOTE: Using Droplit API at ${CONFIG.droplitApiUrl}\x1B[0m`);
|
|
303039
303592
|
logFunc2("\x1B[33mNOTE: Local keys are ignored in Droplit API mode\x1B[0m");
|
|
303040
|
-
|
|
303593
|
+
wallet7 = integratedWallet.getLocalWallet();
|
|
303041
303594
|
effectiveConfig.loadMneeTools = false;
|
|
303042
303595
|
effectiveConfig.loadBapTools = false;
|
|
303043
303596
|
effectiveConfig.loadA2bTools = false;
|
|
@@ -303053,7 +303606,7 @@ Effective Component Status:`);
|
|
|
303053
303606
|
} else if (payPk) {
|
|
303054
303607
|
if (CONFIG.loadWalletTools) {
|
|
303055
303608
|
try {
|
|
303056
|
-
|
|
303609
|
+
wallet7 = new Wallet2(payPk, identityPk);
|
|
303057
303610
|
integratedWallet = new IntegratedWallet({
|
|
303058
303611
|
paymentKey: payPk,
|
|
303059
303612
|
identityKey: identityPk
|
|
@@ -303067,7 +303620,7 @@ Effective Component Status:`);
|
|
|
303067
303620
|
}
|
|
303068
303621
|
} catch (e2) {
|
|
303069
303622
|
logFunc2(`\x1B[31mERROR: Failed to initialize custom wallet: ${e2 instanceof Error ? e2.message : String(e2)}. Wallet-dependent tools will be unavailable.\x1B[0m`);
|
|
303070
|
-
|
|
303623
|
+
wallet7 = undefined;
|
|
303071
303624
|
integratedWallet = undefined;
|
|
303072
303625
|
effectiveConfig.loadWalletTools = false;
|
|
303073
303626
|
effectiveConfig.loadMneeTools = false;
|
|
@@ -303083,12 +303636,16 @@ Effective Component Status:`);
|
|
|
303083
303636
|
logFunc2(`\x1B[33mWARN: Remote BRC-100 wallet initialization failed: ${e2 instanceof Error ? e2.message : String(e2)}. Falling back to local wallet only.\x1B[0m`);
|
|
303084
303637
|
}
|
|
303085
303638
|
}
|
|
303086
|
-
if (effectiveConfig.loadMneeTools && !
|
|
303639
|
+
if (effectiveConfig.loadMneeTools && !wallet7 && CONFIG.loadWalletTools) {
|
|
303087
303640
|
logFunc2("\x1B[33mWARN: MNEE tools require a wallet but wallet initialization failed. MNEE tools disabled.\x1B[0m");
|
|
303088
303641
|
effectiveConfig.loadMneeTools = false;
|
|
303089
303642
|
}
|
|
303090
303643
|
}
|
|
303091
303644
|
}
|
|
303645
|
+
const droplitClient = sponsorConfig && remoteCtx ? new DroplitClient2({ ...sponsorConfig, wallet: remoteCtx.wallet }) : undefined;
|
|
303646
|
+
if (sponsorConfig && CONFIG.loadTools && !remoteCtx) {
|
|
303647
|
+
throw new Error("Configured Droplit sponsor requires an initialized BRC-100 wallet context");
|
|
303648
|
+
}
|
|
303092
303649
|
const toolsConfig = CONFIG.loadTools ? {
|
|
303093
303650
|
enableBsvTools: effectiveConfig.loadBsvTools,
|
|
303094
303651
|
enableOrdinalsTools: effectiveConfig.loadOrdinalsTools,
|
|
@@ -303101,11 +303658,12 @@ Effective Component Status:`);
|
|
|
303101
303658
|
identityPk,
|
|
303102
303659
|
payPk,
|
|
303103
303660
|
xprv,
|
|
303104
|
-
wallet:
|
|
303661
|
+
wallet: wallet7,
|
|
303105
303662
|
integratedWallet,
|
|
303106
303663
|
disableBroadcasting: effectiveConfig.disableBroadcasting,
|
|
303107
303664
|
ctx: remoteCtx,
|
|
303108
|
-
services: remoteServices
|
|
303665
|
+
services: remoteServices,
|
|
303666
|
+
droplitClient
|
|
303109
303667
|
} : {
|
|
303110
303668
|
enableBsvTools: false,
|
|
303111
303669
|
enableOrdinalsTools: false,
|
|
@@ -303119,7 +303677,7 @@ Effective Component Status:`);
|
|
|
303119
303677
|
};
|
|
303120
303678
|
const serverFactoryOpts = {
|
|
303121
303679
|
toolsConfig,
|
|
303122
|
-
wallet:
|
|
303680
|
+
wallet: wallet7,
|
|
303123
303681
|
ctx: remoteCtx,
|
|
303124
303682
|
loadPrompts: effectiveConfig.loadPrompts,
|
|
303125
303683
|
loadResources: effectiveConfig.loadResources
|