@stellar-snaps/sdk 0.1.0
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 +295 -0
- package/dist/index.d.mts +521 -0
- package/dist/index.d.ts +521 -0
- package/dist/index.js +505 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +461 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +58 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,505 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var StellarSdk = require('@stellar/stellar-sdk');
|
|
4
|
+
var freighterApi = require('@stellar/freighter-api');
|
|
5
|
+
|
|
6
|
+
function _interopNamespace(e) {
|
|
7
|
+
if (e && e.__esModule) return e;
|
|
8
|
+
var n = Object.create(null);
|
|
9
|
+
if (e) {
|
|
10
|
+
Object.keys(e).forEach(function (k) {
|
|
11
|
+
if (k !== 'default') {
|
|
12
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
13
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
14
|
+
enumerable: true,
|
|
15
|
+
get: function () { return e[k]; }
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
n.default = e;
|
|
21
|
+
return Object.freeze(n);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
var StellarSdk__namespace = /*#__PURE__*/_interopNamespace(StellarSdk);
|
|
25
|
+
|
|
26
|
+
// src/create-payment-snap.ts
|
|
27
|
+
var NETWORK_PASSPHRASES = {
|
|
28
|
+
public: "Public Global Stellar Network ; September 2015",
|
|
29
|
+
testnet: "Test SDF Network ; September 2015"
|
|
30
|
+
};
|
|
31
|
+
function createPaymentSnap(options) {
|
|
32
|
+
const {
|
|
33
|
+
destination,
|
|
34
|
+
amount,
|
|
35
|
+
assetCode,
|
|
36
|
+
assetIssuer,
|
|
37
|
+
memo,
|
|
38
|
+
memoType = "MEMO_TEXT",
|
|
39
|
+
message,
|
|
40
|
+
network,
|
|
41
|
+
callback
|
|
42
|
+
} = options;
|
|
43
|
+
if (!destination || destination.length !== 56 || !destination.startsWith("G")) {
|
|
44
|
+
throw new Error("Invalid destination address");
|
|
45
|
+
}
|
|
46
|
+
const params = { destination };
|
|
47
|
+
if (amount) {
|
|
48
|
+
if (isNaN(Number(amount)) || Number(amount) <= 0) {
|
|
49
|
+
throw new Error("Invalid amount");
|
|
50
|
+
}
|
|
51
|
+
params.amount = amount;
|
|
52
|
+
}
|
|
53
|
+
if (assetCode && assetCode !== "XLM") {
|
|
54
|
+
params.asset_code = assetCode;
|
|
55
|
+
if (!assetIssuer) {
|
|
56
|
+
throw new Error("asset_issuer required for non-XLM assets");
|
|
57
|
+
}
|
|
58
|
+
params.asset_issuer = assetIssuer;
|
|
59
|
+
}
|
|
60
|
+
if (memo) {
|
|
61
|
+
params.memo = memo;
|
|
62
|
+
params.memo_type = memoType;
|
|
63
|
+
}
|
|
64
|
+
if (message) {
|
|
65
|
+
if (message.length > 300) {
|
|
66
|
+
throw new Error("Message cannot exceed 300 characters");
|
|
67
|
+
}
|
|
68
|
+
params.msg = message;
|
|
69
|
+
}
|
|
70
|
+
if (network && network !== "public") {
|
|
71
|
+
params.network_passphrase = NETWORK_PASSPHRASES[network];
|
|
72
|
+
}
|
|
73
|
+
if (callback) {
|
|
74
|
+
params.callback = `url:${callback}`;
|
|
75
|
+
}
|
|
76
|
+
const queryString = Object.entries(params).map(([key, value]) => `${key}=${encodeURIComponent(value)}`).join("&");
|
|
77
|
+
return { uri: `web+stellar:pay?${queryString}`, params };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// src/constants.ts
|
|
81
|
+
var NETWORK_PASSPHRASES2 = {
|
|
82
|
+
public: "Public Global Stellar Network ; September 2015",
|
|
83
|
+
testnet: "Test SDF Network ; September 2015"
|
|
84
|
+
};
|
|
85
|
+
var HORIZON_URLS = {
|
|
86
|
+
public: "https://horizon.stellar.org",
|
|
87
|
+
testnet: "https://horizon-testnet.stellar.org"
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
// src/errors.ts
|
|
91
|
+
var StellarSnapError = class extends Error {
|
|
92
|
+
constructor(message, code) {
|
|
93
|
+
super(message);
|
|
94
|
+
this.code = code;
|
|
95
|
+
this.name = "StellarSnapError";
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
var InvalidAddressError = class extends StellarSnapError {
|
|
99
|
+
constructor(address) {
|
|
100
|
+
super(`Invalid Stellar address: ${address}`, "INVALID_ADDRESS");
|
|
101
|
+
this.name = "InvalidAddressError";
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
var InvalidAmountError = class extends StellarSnapError {
|
|
105
|
+
constructor(amount) {
|
|
106
|
+
super(`Invalid amount: ${amount}. Must be a positive number.`, "INVALID_AMOUNT");
|
|
107
|
+
this.name = "InvalidAmountError";
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
var InvalidAssetError = class extends StellarSnapError {
|
|
111
|
+
constructor(message) {
|
|
112
|
+
super(message, "INVALID_ASSET");
|
|
113
|
+
this.name = "InvalidAssetError";
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
var InvalidUriError = class extends StellarSnapError {
|
|
117
|
+
constructor(message) {
|
|
118
|
+
super(message, "INVALID_URI");
|
|
119
|
+
this.name = "InvalidUriError";
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// src/create-transaction-snap.ts
|
|
124
|
+
function createTransactionSnap(options) {
|
|
125
|
+
const { xdr, network = "public", message, callback, pubkey } = options;
|
|
126
|
+
if (!xdr || typeof xdr !== "string") {
|
|
127
|
+
throw new InvalidUriError("XDR is required for transaction snaps");
|
|
128
|
+
}
|
|
129
|
+
const params = {
|
|
130
|
+
xdr
|
|
131
|
+
};
|
|
132
|
+
if (network !== "public") {
|
|
133
|
+
params.network_passphrase = NETWORK_PASSPHRASES2[network];
|
|
134
|
+
}
|
|
135
|
+
if (message) {
|
|
136
|
+
if (message.length > 300) {
|
|
137
|
+
throw new InvalidUriError("Message cannot exceed 300 characters");
|
|
138
|
+
}
|
|
139
|
+
params.msg = message;
|
|
140
|
+
}
|
|
141
|
+
if (callback) {
|
|
142
|
+
params.callback = `url:${callback}`;
|
|
143
|
+
}
|
|
144
|
+
if (pubkey) {
|
|
145
|
+
params.pubkey = pubkey;
|
|
146
|
+
}
|
|
147
|
+
const queryString = Object.entries(params).map(([key, value]) => `${key}=${encodeURIComponent(value)}`).join("&");
|
|
148
|
+
return {
|
|
149
|
+
uri: `web+stellar:tx?${queryString}`,
|
|
150
|
+
params
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// src/parse-snap-uri.ts
|
|
155
|
+
function parseSnapUri(uri) {
|
|
156
|
+
if (!uri.startsWith("web+stellar:")) {
|
|
157
|
+
throw new Error("Invalid SEP-0007 URI: must start with web+stellar:");
|
|
158
|
+
}
|
|
159
|
+
const withoutScheme = uri.replace("web+stellar:", "");
|
|
160
|
+
const [operation, queryString] = withoutScheme.split("?");
|
|
161
|
+
if (operation !== "pay" && operation !== "tx") {
|
|
162
|
+
throw new Error(`Invalid operation: ${operation}. Must be 'pay' or 'tx'`);
|
|
163
|
+
}
|
|
164
|
+
const params = new URLSearchParams(queryString);
|
|
165
|
+
const parsed = { type: operation };
|
|
166
|
+
if (operation === "pay") {
|
|
167
|
+
const destination = params.get("destination");
|
|
168
|
+
if (!destination) {
|
|
169
|
+
throw new Error("Missing required parameter: destination");
|
|
170
|
+
}
|
|
171
|
+
parsed.destination = destination;
|
|
172
|
+
if (params.has("amount")) parsed.amount = params.get("amount");
|
|
173
|
+
if (params.has("asset_code")) parsed.assetCode = params.get("asset_code");
|
|
174
|
+
if (params.has("asset_issuer")) parsed.assetIssuer = params.get("asset_issuer");
|
|
175
|
+
if (params.has("memo")) parsed.memo = params.get("memo");
|
|
176
|
+
if (params.has("memo_type")) parsed.memoType = params.get("memo_type");
|
|
177
|
+
if (params.has("msg")) parsed.message = params.get("msg");
|
|
178
|
+
if (params.has("network_passphrase")) parsed.networkPassphrase = params.get("network_passphrase");
|
|
179
|
+
if (params.has("callback")) {
|
|
180
|
+
const cb = params.get("callback");
|
|
181
|
+
parsed.callback = cb.startsWith("url:") ? cb.slice(4) : cb;
|
|
182
|
+
}
|
|
183
|
+
} else {
|
|
184
|
+
const xdr = params.get("xdr");
|
|
185
|
+
if (!xdr) {
|
|
186
|
+
throw new Error("Missing required parameter: xdr");
|
|
187
|
+
}
|
|
188
|
+
parsed.xdr = xdr;
|
|
189
|
+
if (params.has("msg")) parsed.message = params.get("msg");
|
|
190
|
+
if (params.has("network_passphrase")) parsed.networkPassphrase = params.get("network_passphrase");
|
|
191
|
+
if (params.has("callback")) {
|
|
192
|
+
const cb = params.get("callback");
|
|
193
|
+
parsed.callback = cb.startsWith("url:") ? cb.slice(4) : cb;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return parsed;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// src/validation.ts
|
|
200
|
+
function isValidStellarAddress(address) {
|
|
201
|
+
if (!address || typeof address !== "string") {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
return address.length === 56 && address.startsWith("G");
|
|
205
|
+
}
|
|
206
|
+
function isValidAssetCode(code) {
|
|
207
|
+
if (!code || typeof code !== "string") {
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
return /^[a-zA-Z0-9]{1,12}$/.test(code);
|
|
211
|
+
}
|
|
212
|
+
function isValidAmount(amount) {
|
|
213
|
+
if (!amount || typeof amount !== "string") {
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
const num = Number(amount);
|
|
217
|
+
return !isNaN(num) && num > 0 && isFinite(num);
|
|
218
|
+
}
|
|
219
|
+
function createAsset(code, issuer) {
|
|
220
|
+
if (!code || code.toUpperCase() === "XLM") {
|
|
221
|
+
return StellarSdk__namespace.Asset.native();
|
|
222
|
+
}
|
|
223
|
+
if (!issuer) {
|
|
224
|
+
throw new InvalidAssetError(`Asset issuer is required for non-XLM asset: ${code}`);
|
|
225
|
+
}
|
|
226
|
+
if (!isValidStellarAddress(issuer)) {
|
|
227
|
+
throw new InvalidAssetError(`Invalid asset issuer address: ${issuer}`);
|
|
228
|
+
}
|
|
229
|
+
return new StellarSdk__namespace.Asset(code, issuer);
|
|
230
|
+
}
|
|
231
|
+
function buildPaymentTransaction(options) {
|
|
232
|
+
const {
|
|
233
|
+
source,
|
|
234
|
+
sequence,
|
|
235
|
+
destination,
|
|
236
|
+
amount,
|
|
237
|
+
asset,
|
|
238
|
+
memo,
|
|
239
|
+
network,
|
|
240
|
+
timeout = 180
|
|
241
|
+
} = options;
|
|
242
|
+
if (!isValidStellarAddress(source)) {
|
|
243
|
+
throw new InvalidAddressError(source);
|
|
244
|
+
}
|
|
245
|
+
if (!isValidStellarAddress(destination)) {
|
|
246
|
+
throw new InvalidAddressError(destination);
|
|
247
|
+
}
|
|
248
|
+
if (!isValidAmount(amount)) {
|
|
249
|
+
throw new InvalidAmountError(amount);
|
|
250
|
+
}
|
|
251
|
+
const networkPassphrase = NETWORK_PASSPHRASES2[network];
|
|
252
|
+
const sourceAccount = new StellarSdk__namespace.Account(source, sequence);
|
|
253
|
+
const builder = new StellarSdk__namespace.TransactionBuilder(sourceAccount, {
|
|
254
|
+
fee: StellarSdk__namespace.BASE_FEE,
|
|
255
|
+
networkPassphrase
|
|
256
|
+
});
|
|
257
|
+
const stellarAsset = asset ? createAsset(asset.code, asset.issuer) : StellarSdk__namespace.Asset.native();
|
|
258
|
+
builder.addOperation(
|
|
259
|
+
StellarSdk__namespace.Operation.payment({
|
|
260
|
+
destination,
|
|
261
|
+
asset: stellarAsset,
|
|
262
|
+
amount: String(amount)
|
|
263
|
+
})
|
|
264
|
+
);
|
|
265
|
+
if (memo) {
|
|
266
|
+
switch (memo.type) {
|
|
267
|
+
case "MEMO_ID":
|
|
268
|
+
builder.addMemo(StellarSdk__namespace.Memo.id(memo.value));
|
|
269
|
+
break;
|
|
270
|
+
case "MEMO_HASH":
|
|
271
|
+
builder.addMemo(StellarSdk__namespace.Memo.hash(memo.value));
|
|
272
|
+
break;
|
|
273
|
+
case "MEMO_RETURN":
|
|
274
|
+
builder.addMemo(StellarSdk__namespace.Memo.return(memo.value));
|
|
275
|
+
break;
|
|
276
|
+
case "MEMO_TEXT":
|
|
277
|
+
default:
|
|
278
|
+
builder.addMemo(StellarSdk__namespace.Memo.text(memo.value));
|
|
279
|
+
break;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
builder.setTimeout(timeout);
|
|
283
|
+
const transaction = builder.build();
|
|
284
|
+
return transaction.toXDR();
|
|
285
|
+
}
|
|
286
|
+
async function isFreighterConnected() {
|
|
287
|
+
try {
|
|
288
|
+
const connected = await freighterApi.isConnected();
|
|
289
|
+
if (!connected) return false;
|
|
290
|
+
const allowedResult = await freighterApi.isAllowed();
|
|
291
|
+
return allowedResult.isAllowed;
|
|
292
|
+
} catch {
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
async function getFreighterNetwork() {
|
|
297
|
+
try {
|
|
298
|
+
const networkDetails = await freighterApi.getNetwork();
|
|
299
|
+
const passphrase = networkDetails.networkPassphrase;
|
|
300
|
+
if (passphrase === NETWORK_PASSPHRASES2.public) {
|
|
301
|
+
return "public";
|
|
302
|
+
} else if (passphrase === NETWORK_PASSPHRASES2.testnet) {
|
|
303
|
+
return "testnet";
|
|
304
|
+
}
|
|
305
|
+
return "testnet";
|
|
306
|
+
} catch (error) {
|
|
307
|
+
throw new StellarSnapError(
|
|
308
|
+
`Failed to get network from Freighter: ${error}`,
|
|
309
|
+
"FREIGHTER_NETWORK_ERROR"
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
async function connectFreighter() {
|
|
314
|
+
try {
|
|
315
|
+
const connected = await freighterApi.isConnected();
|
|
316
|
+
if (!connected) {
|
|
317
|
+
throw new StellarSnapError(
|
|
318
|
+
"Freighter wallet is not installed. Please install it from https://freighter.app",
|
|
319
|
+
"FREIGHTER_NOT_INSTALLED"
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
const allowedResult = await freighterApi.isAllowed();
|
|
323
|
+
if (!allowedResult.isAllowed) {
|
|
324
|
+
await freighterApi.setAllowed();
|
|
325
|
+
}
|
|
326
|
+
const addressResult = await freighterApi.getAddress();
|
|
327
|
+
if (!addressResult.address) {
|
|
328
|
+
throw new StellarSnapError(
|
|
329
|
+
"Failed to get address from Freighter",
|
|
330
|
+
"FREIGHTER_ADDRESS_ERROR"
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
const network = await getFreighterNetwork();
|
|
334
|
+
return {
|
|
335
|
+
publicKey: addressResult.address,
|
|
336
|
+
network
|
|
337
|
+
};
|
|
338
|
+
} catch (error) {
|
|
339
|
+
if (error instanceof StellarSnapError) {
|
|
340
|
+
throw error;
|
|
341
|
+
}
|
|
342
|
+
throw new StellarSnapError(
|
|
343
|
+
`Failed to connect to Freighter: ${error}`,
|
|
344
|
+
"FREIGHTER_CONNECTION_ERROR"
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
async function signWithFreighter(xdr, network) {
|
|
349
|
+
try {
|
|
350
|
+
const networkPassphrase = NETWORK_PASSPHRASES2[network];
|
|
351
|
+
const result = await freighterApi.signTransaction(xdr, {
|
|
352
|
+
networkPassphrase
|
|
353
|
+
});
|
|
354
|
+
if (!result.signedTxXdr) {
|
|
355
|
+
throw new StellarSnapError(
|
|
356
|
+
"Transaction signing was cancelled or failed",
|
|
357
|
+
"FREIGHTER_SIGN_CANCELLED"
|
|
358
|
+
);
|
|
359
|
+
}
|
|
360
|
+
return result.signedTxXdr;
|
|
361
|
+
} catch (error) {
|
|
362
|
+
if (error instanceof StellarSnapError) {
|
|
363
|
+
throw error;
|
|
364
|
+
}
|
|
365
|
+
throw new StellarSnapError(
|
|
366
|
+
`Failed to sign transaction: ${error}`,
|
|
367
|
+
"FREIGHTER_SIGN_ERROR"
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
async function submitTransaction(signedXdr, network) {
|
|
372
|
+
try {
|
|
373
|
+
const horizonUrl = HORIZON_URLS[network];
|
|
374
|
+
const server = new StellarSdk__namespace.Horizon.Server(horizonUrl);
|
|
375
|
+
const networkPassphrase = NETWORK_PASSPHRASES2[network];
|
|
376
|
+
const transaction = StellarSdk__namespace.TransactionBuilder.fromXDR(
|
|
377
|
+
signedXdr,
|
|
378
|
+
networkPassphrase
|
|
379
|
+
);
|
|
380
|
+
const response = await server.submitTransaction(transaction);
|
|
381
|
+
return {
|
|
382
|
+
hash: response.hash,
|
|
383
|
+
successful: response.successful,
|
|
384
|
+
ledger: response.ledger
|
|
385
|
+
};
|
|
386
|
+
} catch (error) {
|
|
387
|
+
const horizonError = error;
|
|
388
|
+
if (horizonError.response?.data?.extras?.result_codes) {
|
|
389
|
+
const resultCodes = horizonError.response.data.extras.result_codes;
|
|
390
|
+
throw new StellarSnapError(
|
|
391
|
+
`Transaction failed: ${JSON.stringify(resultCodes)}`,
|
|
392
|
+
"TRANSACTION_FAILED"
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
throw new StellarSnapError(
|
|
396
|
+
`Failed to submit transaction: ${horizonError.message || error}`,
|
|
397
|
+
"SUBMIT_ERROR"
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// src/discovery.ts
|
|
403
|
+
function createDiscoveryFile(options) {
|
|
404
|
+
const { name, description, icon, rules } = options;
|
|
405
|
+
if (!name || typeof name !== "string") {
|
|
406
|
+
throw new Error("Discovery file requires a name");
|
|
407
|
+
}
|
|
408
|
+
if (!rules || !Array.isArray(rules) || rules.length === 0) {
|
|
409
|
+
throw new Error("Discovery file requires at least one rule");
|
|
410
|
+
}
|
|
411
|
+
for (const rule of rules) {
|
|
412
|
+
if (!rule.pathPattern || typeof rule.pathPattern !== "string") {
|
|
413
|
+
throw new Error("Each rule requires a pathPattern");
|
|
414
|
+
}
|
|
415
|
+
if (!rule.apiPath || typeof rule.apiPath !== "string") {
|
|
416
|
+
throw new Error("Each rule requires an apiPath");
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
const discoveryFile = {
|
|
420
|
+
name,
|
|
421
|
+
rules
|
|
422
|
+
};
|
|
423
|
+
if (description) {
|
|
424
|
+
discoveryFile.description = description;
|
|
425
|
+
}
|
|
426
|
+
if (icon) {
|
|
427
|
+
discoveryFile.icon = icon;
|
|
428
|
+
}
|
|
429
|
+
return discoveryFile;
|
|
430
|
+
}
|
|
431
|
+
function validateDiscoveryFile(file) {
|
|
432
|
+
if (!file || typeof file !== "object") {
|
|
433
|
+
return false;
|
|
434
|
+
}
|
|
435
|
+
const obj = file;
|
|
436
|
+
if (typeof obj.name !== "string" || !obj.name) {
|
|
437
|
+
return false;
|
|
438
|
+
}
|
|
439
|
+
if (!Array.isArray(obj.rules) || obj.rules.length === 0) {
|
|
440
|
+
return false;
|
|
441
|
+
}
|
|
442
|
+
for (const rule of obj.rules) {
|
|
443
|
+
if (!rule || typeof rule !== "object") {
|
|
444
|
+
return false;
|
|
445
|
+
}
|
|
446
|
+
const ruleObj = rule;
|
|
447
|
+
if (typeof ruleObj.pathPattern !== "string" || !ruleObj.pathPattern) {
|
|
448
|
+
return false;
|
|
449
|
+
}
|
|
450
|
+
if (typeof ruleObj.apiPath !== "string" || !ruleObj.apiPath) {
|
|
451
|
+
return false;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
if (obj.description !== void 0 && typeof obj.description !== "string") {
|
|
455
|
+
return false;
|
|
456
|
+
}
|
|
457
|
+
if (obj.icon !== void 0 && typeof obj.icon !== "string") {
|
|
458
|
+
return false;
|
|
459
|
+
}
|
|
460
|
+
return true;
|
|
461
|
+
}
|
|
462
|
+
function matchUrlToRule(pathname, rules) {
|
|
463
|
+
for (const rule of rules) {
|
|
464
|
+
const pattern = rule.pathPattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace(/\\\*/g, "(.+)");
|
|
465
|
+
const regex = new RegExp(`^${pattern}$`);
|
|
466
|
+
const match = pathname.match(regex);
|
|
467
|
+
if (match) {
|
|
468
|
+
let apiPath = rule.apiPath;
|
|
469
|
+
for (let i = 1; i < match.length; i++) {
|
|
470
|
+
const captured = match[i];
|
|
471
|
+
if (captured !== void 0) {
|
|
472
|
+
apiPath = apiPath.replace(`$${i}`, captured);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
return apiPath;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
return null;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
exports.HORIZON_URLS = HORIZON_URLS;
|
|
482
|
+
exports.InvalidAddressError = InvalidAddressError;
|
|
483
|
+
exports.InvalidAmountError = InvalidAmountError;
|
|
484
|
+
exports.InvalidAssetError = InvalidAssetError;
|
|
485
|
+
exports.InvalidUriError = InvalidUriError;
|
|
486
|
+
exports.NETWORK_PASSPHRASES = NETWORK_PASSPHRASES2;
|
|
487
|
+
exports.StellarSnapError = StellarSnapError;
|
|
488
|
+
exports.buildPaymentTransaction = buildPaymentTransaction;
|
|
489
|
+
exports.connectFreighter = connectFreighter;
|
|
490
|
+
exports.createAsset = createAsset;
|
|
491
|
+
exports.createDiscoveryFile = createDiscoveryFile;
|
|
492
|
+
exports.createPaymentSnap = createPaymentSnap;
|
|
493
|
+
exports.createTransactionSnap = createTransactionSnap;
|
|
494
|
+
exports.getFreighterNetwork = getFreighterNetwork;
|
|
495
|
+
exports.isFreighterConnected = isFreighterConnected;
|
|
496
|
+
exports.isValidAmount = isValidAmount;
|
|
497
|
+
exports.isValidAssetCode = isValidAssetCode;
|
|
498
|
+
exports.isValidStellarAddress = isValidStellarAddress;
|
|
499
|
+
exports.matchUrlToRule = matchUrlToRule;
|
|
500
|
+
exports.parseSnapUri = parseSnapUri;
|
|
501
|
+
exports.signWithFreighter = signWithFreighter;
|
|
502
|
+
exports.submitTransaction = submitTransaction;
|
|
503
|
+
exports.validateDiscoveryFile = validateDiscoveryFile;
|
|
504
|
+
//# sourceMappingURL=index.js.map
|
|
505
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/create-payment-snap.ts","../src/constants.ts","../src/errors.ts","../src/create-transaction-snap.ts","../src/parse-snap-uri.ts","../src/validation.ts","../src/transaction.ts","../src/freighter.ts","../src/discovery.ts"],"names":["NETWORK_PASSPHRASES","StellarSdk","isConnected","isAllowed","getNetwork","setAllowed","getAddress","signTransaction","StellarSdk2"],"mappings":"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","file":"index.js","sourcesContent":["export interface PaymentSnapOptions {\n destination: string;\n amount?: string;\n assetCode?: string;\n assetIssuer?: string;\n memo?: string;\n memoType?: 'MEMO_TEXT' | 'MEMO_ID' | 'MEMO_HASH' | 'MEMO_RETURN';\n message?: string;\n network?: 'public' | 'testnet';\n callback?: string;\n}\n\nexport interface PaymentSnapResult {\n uri: string;\n params: Record<string, string>;\n}\n\nconst NETWORK_PASSPHRASES = {\n public: 'Public Global Stellar Network ; September 2015',\n testnet: 'Test SDF Network ; September 2015',\n} as const;\n\nexport function createPaymentSnap(options: PaymentSnapOptions): PaymentSnapResult {\n const {\n destination,\n amount,\n assetCode,\n assetIssuer,\n memo,\n memoType = 'MEMO_TEXT',\n message,\n network,\n callback,\n } = options;\n\n if (!destination || destination.length !== 56 || !destination.startsWith('G')) {\n throw new Error('Invalid destination address');\n }\n\n const params: Record<string, string> = { destination };\n\n if (amount) {\n if (isNaN(Number(amount)) || Number(amount) <= 0) {\n throw new Error('Invalid amount');\n }\n params.amount = amount;\n }\n\n if (assetCode && assetCode !== 'XLM') {\n params.asset_code = assetCode;\n if (!assetIssuer) {\n throw new Error('asset_issuer required for non-XLM assets');\n }\n params.asset_issuer = assetIssuer;\n }\n\n if (memo) {\n params.memo = memo;\n params.memo_type = memoType;\n }\n\n if (message) {\n if (message.length > 300) {\n throw new Error('Message cannot exceed 300 characters');\n }\n params.msg = message;\n }\n\n if (network && network !== 'public') {\n params.network_passphrase = NETWORK_PASSPHRASES[network];\n }\n\n if (callback) {\n params.callback = `url:${callback}`;\n }\n\n const queryString = Object.entries(params)\n .map(([key, value]) => `${key}=${encodeURIComponent(value)}`)\n .join('&');\n\n return { uri: `web+stellar:pay?${queryString}`, params };\n}\n","/**\n * Stellar network passphrases used for transaction signing.\n * Each network has a unique passphrase that identifies it.\n */\nexport const NETWORK_PASSPHRASES = {\n public: 'Public Global Stellar Network ; September 2015',\n testnet: 'Test SDF Network ; September 2015',\n} as const;\n\n/**\n * Horizon API URLs for each Stellar network.\n * Horizon is the REST API for interacting with the Stellar network.\n */\nexport const HORIZON_URLS = {\n public: 'https://horizon.stellar.org',\n testnet: 'https://horizon-testnet.stellar.org',\n} as const;\n\n/**\n * Supported Stellar networks.\n * - `public`: The main Stellar network (real money)\n * - `testnet`: Test network for development (free test tokens)\n */\nexport type Network = 'public' | 'testnet';\n\n/**\n * Stellar memo types for attaching metadata to transactions.\n * - `MEMO_TEXT`: Plain text (max 28 bytes)\n * - `MEMO_ID`: 64-bit unsigned integer\n * - `MEMO_HASH`: 32-byte hash\n * - `MEMO_RETURN`: 32-byte hash (for returning payments)\n */\nexport type MemoType = 'MEMO_TEXT' | 'MEMO_ID' | 'MEMO_HASH' | 'MEMO_RETURN';\n","/**\n * Base error class for all Stellar Snaps SDK errors.\n * Includes an error code for programmatic error handling.\n */\nexport class StellarSnapError extends Error {\n constructor(\n message: string,\n public code: string\n ) {\n super(message);\n this.name = 'StellarSnapError';\n }\n}\n\n/**\n * Thrown when a Stellar address is invalid.\n * Valid addresses are 56 characters long and start with 'G'.\n */\nexport class InvalidAddressError extends StellarSnapError {\n constructor(address: string) {\n super(`Invalid Stellar address: ${address}`, 'INVALID_ADDRESS');\n this.name = 'InvalidAddressError';\n }\n}\n\n/**\n * Thrown when an amount is invalid.\n * Amounts must be positive numbers represented as strings.\n */\nexport class InvalidAmountError extends StellarSnapError {\n constructor(amount: string) {\n super(`Invalid amount: ${amount}. Must be a positive number.`, 'INVALID_AMOUNT');\n this.name = 'InvalidAmountError';\n }\n}\n\n/**\n * Thrown when an asset configuration is invalid.\n * Non-XLM assets require both a code and an issuer address.\n */\nexport class InvalidAssetError extends StellarSnapError {\n constructor(message: string) {\n super(message, 'INVALID_ASSET');\n this.name = 'InvalidAssetError';\n }\n}\n\n/**\n * Thrown when a SEP-0007 URI is invalid or malformed.\n */\nexport class InvalidUriError extends StellarSnapError {\n constructor(message: string) {\n super(message, 'INVALID_URI');\n this.name = 'InvalidUriError';\n }\n}\n","import { NETWORK_PASSPHRASES, type Network } from './constants';\nimport { InvalidUriError } from './errors';\n\n/**\n * Options for creating a transaction snap URI.\n * Used for advanced use cases where you need to sign arbitrary transactions,\n * not just simple payments.\n */\nexport interface TransactionSnapOptions {\n /** The transaction in XDR format (Stellar's binary encoding) */\n xdr: string;\n /** The network this transaction is for (default: 'public') */\n network?: Network;\n /** Human-readable message to show the user when signing */\n message?: string;\n /** URL to call after the transaction is signed */\n callback?: string;\n /** Public key of the required signer */\n pubkey?: string;\n}\n\n/**\n * Result of creating a transaction snap.\n */\nexport interface TransactionSnapResult {\n /** The complete SEP-0007 URI */\n uri: string;\n /** The parsed parameters */\n params: Record<string, string>;\n}\n\n/**\n * Creates a SEP-0007 transaction URI for signing arbitrary Stellar transactions.\n *\n * Unlike payment snaps which are for simple payments, transaction snaps can\n * encode any Stellar transaction (multi-operation, account creation, etc.).\n *\n * @param options - Transaction snap configuration\n * @returns The generated URI and parsed parameters\n * @throws {InvalidUriError} If the XDR is missing or invalid\n *\n * @example\n * ```typescript\n * const { uri } = createTransactionSnap({\n * xdr: 'AAAA...', // Your transaction XDR\n * network: 'testnet',\n * message: 'Please sign this transaction',\n * });\n * // => web+stellar:tx?xdr=AAAA...&network_passphrase=Test%20SDF%20Network...\n * ```\n */\nexport function createTransactionSnap(options: TransactionSnapOptions): TransactionSnapResult {\n const { xdr, network = 'public', message, callback, pubkey } = options;\n\n if (!xdr || typeof xdr !== 'string') {\n throw new InvalidUriError('XDR is required for transaction snaps');\n }\n\n const params: Record<string, string> = {\n xdr: xdr,\n };\n\n // Add network passphrase if not public (public is the default)\n if (network !== 'public') {\n params.network_passphrase = NETWORK_PASSPHRASES[network];\n }\n\n if (message) {\n if (message.length > 300) {\n throw new InvalidUriError('Message cannot exceed 300 characters');\n }\n params.msg = message;\n }\n\n if (callback) {\n params.callback = `url:${callback}`;\n }\n\n if (pubkey) {\n params.pubkey = pubkey;\n }\n\n const queryString = Object.entries(params)\n .map(([key, value]) => `${key}=${encodeURIComponent(value)}`)\n .join('&');\n\n return {\n uri: `web+stellar:tx?${queryString}`,\n params,\n };\n}\n","export interface ParsedSnap {\n type: 'pay' | 'tx';\n destination?: string;\n amount?: string;\n assetCode?: string;\n assetIssuer?: string;\n memo?: string;\n memoType?: string;\n message?: string;\n networkPassphrase?: string;\n callback?: string;\n xdr?: string;\n}\n\nexport function parseSnapUri(uri: string): ParsedSnap {\n if (!uri.startsWith('web+stellar:')) {\n throw new Error('Invalid SEP-0007 URI: must start with web+stellar:');\n }\n\n const withoutScheme = uri.replace('web+stellar:', '');\n const [operation, queryString] = withoutScheme.split('?');\n\n if (operation !== 'pay' && operation !== 'tx') {\n throw new Error(`Invalid operation: ${operation}. Must be 'pay' or 'tx'`);\n }\n\n const params = new URLSearchParams(queryString);\n const parsed: ParsedSnap = { type: operation };\n\n if (operation === 'pay') {\n const destination = params.get('destination');\n if (!destination) {\n throw new Error('Missing required parameter: destination');\n }\n parsed.destination = destination;\n\n if (params.has('amount')) parsed.amount = params.get('amount')!;\n if (params.has('asset_code')) parsed.assetCode = params.get('asset_code')!;\n if (params.has('asset_issuer')) parsed.assetIssuer = params.get('asset_issuer')!;\n if (params.has('memo')) parsed.memo = params.get('memo')!;\n if (params.has('memo_type')) parsed.memoType = params.get('memo_type')!;\n if (params.has('msg')) parsed.message = params.get('msg')!;\n if (params.has('network_passphrase')) parsed.networkPassphrase = params.get('network_passphrase')!;\n if (params.has('callback')) {\n const cb = params.get('callback')!;\n parsed.callback = cb.startsWith('url:') ? cb.slice(4) : cb;\n }\n } else {\n const xdr = params.get('xdr');\n if (!xdr) {\n throw new Error('Missing required parameter: xdr');\n }\n parsed.xdr = xdr;\n if (params.has('msg')) parsed.message = params.get('msg')!;\n if (params.has('network_passphrase')) parsed.networkPassphrase = params.get('network_passphrase')!;\n if (params.has('callback')) {\n const cb = params.get('callback')!;\n parsed.callback = cb.startsWith('url:') ? cb.slice(4) : cb;\n }\n }\n\n return parsed;\n}\n","/**\n * Validates a Stellar public address.\n * Valid addresses are 56 characters long and start with 'G'.\n *\n * @param address - The address to validate\n * @returns true if the address is valid\n *\n * @example\n * ```typescript\n * isValidStellarAddress('GDQP2KPQGKIHYJGXNUIYOMHARUARCA7DJT5FO2FFOOUJ3DTJE4QRK764');\n * // => true\n *\n * isValidStellarAddress('invalid');\n * // => false\n * ```\n */\nexport function isValidStellarAddress(address: string): boolean {\n if (!address || typeof address !== 'string') {\n return false;\n }\n return address.length === 56 && address.startsWith('G');\n}\n\n/**\n * Validates a Stellar asset code.\n * Asset codes are 1-12 alphanumeric characters.\n * \"XLM\" is the native asset and is always valid.\n *\n * @param code - The asset code to validate\n * @returns true if the asset code is valid\n *\n * @example\n * ```typescript\n * isValidAssetCode('USDC');\n * // => true\n *\n * isValidAssetCode('XLM');\n * // => true\n *\n * isValidAssetCode('ThisIsTooLongForAnAssetCode');\n * // => false\n * ```\n */\nexport function isValidAssetCode(code: string): boolean {\n if (!code || typeof code !== 'string') {\n return false;\n }\n // Asset codes are 1-12 alphanumeric characters\n return /^[a-zA-Z0-9]{1,12}$/.test(code);\n}\n\n/**\n * Validates a payment amount.\n * Amounts must be positive numbers represented as strings.\n * Stellar supports up to 7 decimal places.\n *\n * @param amount - The amount to validate\n * @returns true if the amount is valid\n *\n * @example\n * ```typescript\n * isValidAmount('10');\n * // => true\n *\n * isValidAmount('0.0000001');\n * // => true\n *\n * isValidAmount('-5');\n * // => false\n *\n * isValidAmount('0');\n * // => false\n * ```\n */\nexport function isValidAmount(amount: string): boolean {\n if (!amount || typeof amount !== 'string') {\n return false;\n }\n const num = Number(amount);\n return !isNaN(num) && num > 0 && isFinite(num);\n}\n","import * as StellarSdk from '@stellar/stellar-sdk';\nimport { NETWORK_PASSPHRASES, type Network, type MemoType } from './constants';\nimport { InvalidAddressError, InvalidAmountError, InvalidAssetError } from './errors';\nimport { isValidStellarAddress, isValidAmount } from './validation';\n\n/**\n * Options for building a payment transaction.\n */\nexport interface BuildPaymentOptions {\n /** The payer's Stellar public address */\n source: string;\n /** The account sequence number (prevents replay attacks) */\n sequence: string;\n /** The recipient's Stellar public address */\n destination: string;\n /** The amount to send (as a string for precision) */\n amount: string;\n /** The asset to send (defaults to XLM if not specified) */\n asset?: {\n /** Asset code, e.g., \"USDC\", \"XLM\" */\n code: string;\n /** Asset issuer address (required for non-XLM assets) */\n issuer?: string;\n };\n /** Optional memo to attach to the transaction */\n memo?: {\n /** The memo type */\n type: MemoType;\n /** The memo value */\n value: string;\n };\n /** The network to build for */\n network: Network;\n /** Transaction validity timeout in seconds (default: 180) */\n timeout?: number;\n}\n\n/**\n * Creates a Stellar Asset object.\n *\n * @param code - The asset code (e.g., \"XLM\", \"USDC\")\n * @param issuer - The asset issuer address (required for non-XLM assets)\n * @returns A Stellar Asset object\n * @throws {InvalidAssetError} If a non-XLM asset is missing an issuer\n *\n * @example\n * ```typescript\n * // Native XLM\n * const xlm = createAsset('XLM');\n *\n * // Custom asset\n * const usdc = createAsset('USDC', 'GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN');\n * ```\n */\nexport function createAsset(code: string, issuer?: string): StellarSdk.Asset {\n if (!code || code.toUpperCase() === 'XLM') {\n return StellarSdk.Asset.native();\n }\n\n if (!issuer) {\n throw new InvalidAssetError(`Asset issuer is required for non-XLM asset: ${code}`);\n }\n\n if (!isValidStellarAddress(issuer)) {\n throw new InvalidAssetError(`Invalid asset issuer address: ${issuer}`);\n }\n\n return new StellarSdk.Asset(code, issuer);\n}\n\n/**\n * Builds a Stellar payment transaction and returns the XDR.\n *\n * This function creates a complete unsigned transaction that can be\n * signed by a wallet like Freighter.\n *\n * @param options - The payment options\n * @returns The transaction XDR string\n * @throws {InvalidAddressError} If source or destination address is invalid\n * @throws {InvalidAmountError} If amount is invalid\n * @throws {InvalidAssetError} If asset configuration is invalid\n *\n * @example\n * ```typescript\n * const xdr = buildPaymentTransaction({\n * source: 'GDQP2K...',\n * sequence: '123456789',\n * destination: 'GBZX...',\n * amount: '10.5',\n * asset: { code: 'USDC', issuer: 'GA5ZS...' },\n * memo: { type: 'MEMO_TEXT', value: 'Payment for coffee' },\n * network: 'public',\n * });\n * ```\n */\nexport function buildPaymentTransaction(options: BuildPaymentOptions): string {\n const {\n source,\n sequence,\n destination,\n amount,\n asset,\n memo,\n network,\n timeout = 180,\n } = options;\n\n // Validate inputs\n if (!isValidStellarAddress(source)) {\n throw new InvalidAddressError(source);\n }\n\n if (!isValidStellarAddress(destination)) {\n throw new InvalidAddressError(destination);\n }\n\n if (!isValidAmount(amount)) {\n throw new InvalidAmountError(amount);\n }\n\n const networkPassphrase = NETWORK_PASSPHRASES[network];\n\n // Create a minimal account object for TransactionBuilder\n const sourceAccount = new StellarSdk.Account(source, sequence);\n\n // Build transaction\n const builder = new StellarSdk.TransactionBuilder(sourceAccount, {\n fee: StellarSdk.BASE_FEE,\n networkPassphrase,\n });\n\n // Determine asset\n const stellarAsset = asset\n ? createAsset(asset.code, asset.issuer)\n : StellarSdk.Asset.native();\n\n // Add payment operation\n builder.addOperation(\n StellarSdk.Operation.payment({\n destination,\n asset: stellarAsset,\n amount: String(amount),\n })\n );\n\n // Add memo if present\n if (memo) {\n switch (memo.type) {\n case 'MEMO_ID':\n builder.addMemo(StellarSdk.Memo.id(memo.value));\n break;\n case 'MEMO_HASH':\n builder.addMemo(StellarSdk.Memo.hash(memo.value));\n break;\n case 'MEMO_RETURN':\n builder.addMemo(StellarSdk.Memo.return(memo.value));\n break;\n case 'MEMO_TEXT':\n default:\n builder.addMemo(StellarSdk.Memo.text(memo.value));\n break;\n }\n }\n\n // Set timeout and build\n builder.setTimeout(timeout);\n const transaction = builder.build();\n\n return transaction.toXDR();\n}\n","import {\n isConnected,\n isAllowed,\n setAllowed,\n getAddress,\n getNetwork,\n signTransaction,\n} from '@stellar/freighter-api';\nimport * as StellarSdk from '@stellar/stellar-sdk';\nimport { NETWORK_PASSPHRASES, HORIZON_URLS, type Network } from './constants';\nimport { StellarSnapError } from './errors';\n\n/**\n * Result of connecting to Freighter wallet.\n */\nexport interface FreighterConnectionResult {\n /** The user's Stellar public address */\n publicKey: string;\n /** The network the wallet is connected to */\n network: Network;\n}\n\n/**\n * Result of submitting a transaction.\n */\nexport interface TransactionSubmitResult {\n /** The transaction hash (can be used in block explorers) */\n hash: string;\n /** Whether the transaction was successful */\n successful: boolean;\n /** The ledger number the transaction was included in */\n ledger?: number;\n}\n\n/**\n * Checks if Freighter wallet extension is installed and connected.\n *\n * @returns true if Freighter is installed and the user has granted access\n *\n * @example\n * ```typescript\n * if (await isFreighterConnected()) {\n * console.log('Ready to sign transactions!');\n * } else {\n * console.log('Please connect your Freighter wallet');\n * }\n * ```\n */\nexport async function isFreighterConnected(): Promise<boolean> {\n try {\n const connected = await isConnected();\n if (!connected) return false;\n\n const allowedResult = await isAllowed();\n return allowedResult.isAllowed;\n } catch {\n return false;\n }\n}\n\n/**\n * Gets the current network from Freighter wallet.\n *\n * @returns The network the user's wallet is connected to\n * @throws {StellarSnapError} If unable to get network\n *\n * @example\n * ```typescript\n * const network = await getFreighterNetwork();\n * console.log(`Connected to ${network}`); // 'public' or 'testnet'\n * ```\n */\nexport async function getFreighterNetwork(): Promise<Network> {\n try {\n const networkDetails = await getNetwork();\n const passphrase = networkDetails.networkPassphrase;\n\n if (passphrase === NETWORK_PASSPHRASES.public) {\n return 'public';\n } else if (passphrase === NETWORK_PASSPHRASES.testnet) {\n return 'testnet';\n }\n\n // Default to testnet for unknown networks\n return 'testnet';\n } catch (error) {\n throw new StellarSnapError(\n `Failed to get network from Freighter: ${error}`,\n 'FREIGHTER_NETWORK_ERROR'\n );\n }\n}\n\n/**\n * Connects to the Freighter wallet and returns the user's public key and network.\n *\n * This will prompt the user to grant access if they haven't already.\n *\n * @returns The user's public key and current network\n * @throws {StellarSnapError} If Freighter is not installed or connection fails\n *\n * @example\n * ```typescript\n * try {\n * const { publicKey, network } = await connectFreighter();\n * console.log(`Connected: ${publicKey} on ${network}`);\n * } catch (error) {\n * console.error('Failed to connect:', error.message);\n * }\n * ```\n */\nexport async function connectFreighter(): Promise<FreighterConnectionResult> {\n try {\n // Check if Freighter is installed\n const connected = await isConnected();\n if (!connected) {\n throw new StellarSnapError(\n 'Freighter wallet is not installed. Please install it from https://freighter.app',\n 'FREIGHTER_NOT_INSTALLED'\n );\n }\n\n // Request access if not already allowed\n const allowedResult = await isAllowed();\n if (!allowedResult.isAllowed) {\n await setAllowed();\n }\n\n // Get the user's address\n const addressResult = await getAddress();\n if (!addressResult.address) {\n throw new StellarSnapError(\n 'Failed to get address from Freighter',\n 'FREIGHTER_ADDRESS_ERROR'\n );\n }\n\n // Get the network\n const network = await getFreighterNetwork();\n\n return {\n publicKey: addressResult.address,\n network,\n };\n } catch (error) {\n if (error instanceof StellarSnapError) {\n throw error;\n }\n throw new StellarSnapError(\n `Failed to connect to Freighter: ${error}`,\n 'FREIGHTER_CONNECTION_ERROR'\n );\n }\n}\n\n/**\n * Signs a transaction using Freighter wallet.\n *\n * This will open the Freighter popup for the user to review and approve the transaction.\n *\n * @param xdr - The unsigned transaction XDR\n * @param network - The network the transaction is for\n * @returns The signed transaction XDR\n * @throws {StellarSnapError} If signing fails or user rejects\n *\n * @example\n * ```typescript\n * const unsignedXdr = buildPaymentTransaction({ ... });\n * const signedXdr = await signWithFreighter(unsignedXdr, 'public');\n * ```\n */\nexport async function signWithFreighter(\n xdr: string,\n network: Network\n): Promise<string> {\n try {\n const networkPassphrase = NETWORK_PASSPHRASES[network];\n const result = await signTransaction(xdr, {\n networkPassphrase,\n });\n\n if (!result.signedTxXdr) {\n throw new StellarSnapError(\n 'Transaction signing was cancelled or failed',\n 'FREIGHTER_SIGN_CANCELLED'\n );\n }\n\n return result.signedTxXdr;\n } catch (error) {\n if (error instanceof StellarSnapError) {\n throw error;\n }\n throw new StellarSnapError(\n `Failed to sign transaction: ${error}`,\n 'FREIGHTER_SIGN_ERROR'\n );\n }\n}\n\n/**\n * Submits a signed transaction to the Stellar network.\n *\n * @param signedXdr - The signed transaction XDR\n * @param network - The network to submit to\n * @returns The transaction result including hash and success status\n * @throws {StellarSnapError} If submission fails\n *\n * @example\n * ```typescript\n * const signedXdr = await signWithFreighter(unsignedXdr, 'public');\n * const result = await submitTransaction(signedXdr, 'public');\n *\n * if (result.successful) {\n * console.log(`Transaction successful! Hash: ${result.hash}`);\n * console.log(`View on explorer: https://stellar.expert/explorer/public/tx/${result.hash}`);\n * }\n * ```\n */\nexport async function submitTransaction(\n signedXdr: string,\n network: Network\n): Promise<TransactionSubmitResult> {\n try {\n const horizonUrl = HORIZON_URLS[network];\n const server = new StellarSdk.Horizon.Server(horizonUrl);\n const networkPassphrase = NETWORK_PASSPHRASES[network];\n\n // Parse the signed transaction\n const transaction = StellarSdk.TransactionBuilder.fromXDR(\n signedXdr,\n networkPassphrase\n );\n\n // Submit to the network\n const response = await server.submitTransaction(transaction);\n\n return {\n hash: response.hash,\n successful: response.successful,\n ledger: response.ledger,\n };\n } catch (error: unknown) {\n // Handle Horizon error responses\n const horizonError = error as { response?: { data?: { extras?: { result_codes?: unknown } } }; message?: string };\n if (horizonError.response?.data?.extras?.result_codes) {\n const resultCodes = horizonError.response.data.extras.result_codes;\n throw new StellarSnapError(\n `Transaction failed: ${JSON.stringify(resultCodes)}`,\n 'TRANSACTION_FAILED'\n );\n }\n\n throw new StellarSnapError(\n `Failed to submit transaction: ${horizonError.message || error}`,\n 'SUBMIT_ERROR'\n );\n }\n}\n","/**\n * A rule for matching URL paths to API endpoints.\n */\nexport interface DiscoveryRule {\n /**\n * URL path pattern with wildcards.\n * Use `*` as a wildcard that matches any characters.\n *\n * @example \"/s/*\" matches \"/s/abc123\"\n * @example \"/pay/*\" matches \"/pay/user123\"\n */\n pathPattern: string;\n\n /**\n * API endpoint path template.\n * Use `$1`, `$2`, etc. to insert captured wildcards.\n *\n * @example \"/api/snap/$1\" with pathPattern \"/s/*\" and URL \"/s/abc\"\n * resolves to \"/api/snap/abc\"\n */\n apiPath: string;\n}\n\n/**\n * Discovery file structure for Stellar Snaps.\n *\n * This file should be hosted at `/.well-known/stellar-snap.json` on your domain\n * to enable the browser extension to discover and render your snaps.\n */\nexport interface DiscoveryFile {\n /** The name of your application */\n name: string;\n\n /** A short description of your application */\n description?: string;\n\n /** URL to your application's icon (recommended: 128x128 PNG) */\n icon?: string;\n\n /** Rules for matching URLs to snap metadata endpoints */\n rules: DiscoveryRule[];\n}\n\n/**\n * Options for creating a discovery file.\n */\nexport interface CreateDiscoveryFileOptions {\n /** The name of your application */\n name: string;\n /** A short description of your application */\n description?: string;\n /** URL to your application's icon */\n icon?: string;\n /** Rules for matching URLs to snap metadata endpoints */\n rules: DiscoveryRule[];\n}\n\n/**\n * Creates a valid discovery file object.\n *\n * Use this to generate the JSON that should be hosted at\n * `/.well-known/stellar-snap.json` on your domain.\n *\n * @param options - The discovery file configuration\n * @returns A valid DiscoveryFile object\n *\n * @example\n * ```typescript\n * const discovery = createDiscoveryFile({\n * name: 'My Payment App',\n * description: 'Accept Stellar payments easily',\n * rules: [\n * { pathPattern: '/pay/*', apiPath: '/api/snap/$1' },\n * { pathPattern: '/donate/*', apiPath: '/api/donation/$1' },\n * ],\n * });\n *\n * // Save as /.well-known/stellar-snap.json\n * fs.writeFileSync(\n * 'public/.well-known/stellar-snap.json',\n * JSON.stringify(discovery, null, 2)\n * );\n * ```\n */\nexport function createDiscoveryFile(options: CreateDiscoveryFileOptions): DiscoveryFile {\n const { name, description, icon, rules } = options;\n\n if (!name || typeof name !== 'string') {\n throw new Error('Discovery file requires a name');\n }\n\n if (!rules || !Array.isArray(rules) || rules.length === 0) {\n throw new Error('Discovery file requires at least one rule');\n }\n\n // Validate rules\n for (const rule of rules) {\n if (!rule.pathPattern || typeof rule.pathPattern !== 'string') {\n throw new Error('Each rule requires a pathPattern');\n }\n if (!rule.apiPath || typeof rule.apiPath !== 'string') {\n throw new Error('Each rule requires an apiPath');\n }\n }\n\n const discoveryFile: DiscoveryFile = {\n name,\n rules,\n };\n\n if (description) {\n discoveryFile.description = description;\n }\n\n if (icon) {\n discoveryFile.icon = icon;\n }\n\n return discoveryFile;\n}\n\n/**\n * Validates that an unknown object is a valid discovery file.\n *\n * Use this to validate discovery files fetched from other domains.\n *\n * @param file - The object to validate\n * @returns true if the object is a valid DiscoveryFile\n *\n * @example\n * ```typescript\n * const response = await fetch('https://example.com/.well-known/stellar-snap.json');\n * const data = await response.json();\n *\n * if (validateDiscoveryFile(data)) {\n * console.log('Valid discovery file:', data.name);\n * } else {\n * console.error('Invalid discovery file');\n * }\n * ```\n */\nexport function validateDiscoveryFile(file: unknown): file is DiscoveryFile {\n if (!file || typeof file !== 'object') {\n return false;\n }\n\n const obj = file as Record<string, unknown>;\n\n // Check required fields\n if (typeof obj.name !== 'string' || !obj.name) {\n return false;\n }\n\n if (!Array.isArray(obj.rules) || obj.rules.length === 0) {\n return false;\n }\n\n // Validate each rule\n for (const rule of obj.rules) {\n if (!rule || typeof rule !== 'object') {\n return false;\n }\n const ruleObj = rule as Record<string, unknown>;\n if (typeof ruleObj.pathPattern !== 'string' || !ruleObj.pathPattern) {\n return false;\n }\n if (typeof ruleObj.apiPath !== 'string' || !ruleObj.apiPath) {\n return false;\n }\n }\n\n // Optional fields should be correct types if present\n if (obj.description !== undefined && typeof obj.description !== 'string') {\n return false;\n }\n\n if (obj.icon !== undefined && typeof obj.icon !== 'string') {\n return false;\n }\n\n return true;\n}\n\n/**\n * Matches a URL pathname against discovery rules and returns the API path.\n *\n * This is used to find which API endpoint to call for a given URL.\n *\n * @param pathname - The URL pathname to match (e.g., \"/s/abc123\")\n * @param rules - The discovery rules to match against\n * @returns The resolved API path, or null if no match\n *\n * @example\n * ```typescript\n * const rules = [\n * { pathPattern: '/s/*', apiPath: '/api/snap/$1' },\n * { pathPattern: '/pay/*', apiPath: '/api/payment/$1' },\n * ];\n *\n * matchUrlToRule('/s/abc123', rules);\n * // => '/api/snap/abc123'\n *\n * matchUrlToRule('/pay/user456', rules);\n * // => '/api/payment/user456'\n *\n * matchUrlToRule('/unknown/path', rules);\n * // => null\n * ```\n */\nexport function matchUrlToRule(\n pathname: string,\n rules: DiscoveryRule[]\n): string | null {\n for (const rule of rules) {\n // Convert pathPattern to regex\n // \"/s/*\" becomes /^\\/s\\/(.+)$/\n const pattern = rule.pathPattern\n .replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&') // Escape special regex chars\n .replace(/\\\\\\*/g, '(.+)'); // Convert \\* back to capture group\n\n const regex = new RegExp(`^${pattern}$`);\n const match = pathname.match(regex);\n\n if (match) {\n // Replace $1, $2, etc. with captured groups\n let apiPath = rule.apiPath;\n for (let i = 1; i < match.length; i++) {\n const captured = match[i];\n if (captured !== undefined) {\n apiPath = apiPath.replace(`$${i}`, captured);\n }\n }\n return apiPath;\n }\n }\n\n return null;\n}\n"]}
|