@lucid-evolution/provider 0.0.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/dist/index.cjs +838 -0
- package/dist/index.d.cts +83 -0
- package/dist/index.d.ts +83 -0
- package/dist/index.js +798 -0
- package/package.json +30 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,838 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var src_exports = {};
|
|
32
|
+
__export(src_exports, {
|
|
33
|
+
Blockfrost: () => Blockfrost,
|
|
34
|
+
Kupmios: () => Kupmios,
|
|
35
|
+
Maestro: () => Maestro,
|
|
36
|
+
datumJsonToCbor: () => datumJsonToCbor
|
|
37
|
+
});
|
|
38
|
+
module.exports = __toCommonJS(src_exports);
|
|
39
|
+
|
|
40
|
+
// src/blockfrost.ts
|
|
41
|
+
var CML = __toESM(require("@dcspark/cardano-multiplatform-lib-nodejs"), 1);
|
|
42
|
+
var import_core_utils = require("@lucid-evolution/core-utils");
|
|
43
|
+
var import_utils = require("@lucid-evolution/utils");
|
|
44
|
+
|
|
45
|
+
// package.json
|
|
46
|
+
var package_default = {
|
|
47
|
+
name: "@anastasia-labs/provider",
|
|
48
|
+
version: "0.0.1",
|
|
49
|
+
description: "",
|
|
50
|
+
main: "./dist/index.js",
|
|
51
|
+
types: "./dist/index.d.ts",
|
|
52
|
+
type: "module",
|
|
53
|
+
files: [
|
|
54
|
+
"dist"
|
|
55
|
+
],
|
|
56
|
+
publishConfig: {
|
|
57
|
+
access: "public"
|
|
58
|
+
},
|
|
59
|
+
scripts: {
|
|
60
|
+
build: "tsup-node src/index.ts --format esm,cjs --dts --clean",
|
|
61
|
+
clean: "rm -rf .turbo && rm -rf node_modules && rm -rf dist"
|
|
62
|
+
},
|
|
63
|
+
keywords: [],
|
|
64
|
+
author: "",
|
|
65
|
+
license: "MIT",
|
|
66
|
+
devDependencies: {
|
|
67
|
+
"@anastasia-labs/core-types": "workspace:*",
|
|
68
|
+
"@anastasia-labs/core-utils": "workspace:*",
|
|
69
|
+
"@anastasia-labs/utils": "workspace:*",
|
|
70
|
+
"@dcspark/cardano-multiplatform-lib-nodejs": "^5.1.0",
|
|
71
|
+
"@types/node": "^20.11.24",
|
|
72
|
+
tsup: "^8.0.2",
|
|
73
|
+
typescript: "^5.3.3"
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// src/blockfrost.ts
|
|
78
|
+
var Blockfrost = class {
|
|
79
|
+
url;
|
|
80
|
+
projectId;
|
|
81
|
+
constructor(url, projectId) {
|
|
82
|
+
this.url = url;
|
|
83
|
+
this.projectId = projectId || "";
|
|
84
|
+
}
|
|
85
|
+
async getProtocolParameters() {
|
|
86
|
+
const result = await fetch(`${this.url}/epochs/latest/parameters`, {
|
|
87
|
+
headers: { project_id: this.projectId, lucid }
|
|
88
|
+
}).then((res) => res.json());
|
|
89
|
+
return {
|
|
90
|
+
minFeeA: parseInt(result.min_fee_a),
|
|
91
|
+
minFeeB: parseInt(result.min_fee_b),
|
|
92
|
+
maxTxSize: parseInt(result.max_tx_size),
|
|
93
|
+
maxValSize: parseInt(result.max_val_size),
|
|
94
|
+
keyDeposit: BigInt(result.key_deposit),
|
|
95
|
+
poolDeposit: BigInt(result.pool_deposit),
|
|
96
|
+
priceMem: parseFloat(result.price_mem),
|
|
97
|
+
priceStep: parseFloat(result.price_step),
|
|
98
|
+
maxTxExMem: BigInt(result.max_tx_ex_mem),
|
|
99
|
+
maxTxExSteps: BigInt(result.max_tx_ex_steps),
|
|
100
|
+
coinsPerUtxoByte: BigInt(result.coins_per_utxo_size),
|
|
101
|
+
collateralPercentage: parseInt(result.collateral_percent),
|
|
102
|
+
maxCollateralInputs: parseInt(result.max_collateral_inputs),
|
|
103
|
+
costModels: result.cost_models
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
async getUtxos(addressOrCredential) {
|
|
107
|
+
const queryPredicate = (() => {
|
|
108
|
+
if (typeof addressOrCredential === "string")
|
|
109
|
+
return addressOrCredential;
|
|
110
|
+
const credentialBech32 = addressOrCredential.type === "Key" ? CML.Ed25519KeyHash.from_hex(addressOrCredential.hash).to_bech32(
|
|
111
|
+
"addr_vkh"
|
|
112
|
+
) : CML.ScriptHash.from_hex(addressOrCredential.hash).to_bech32(
|
|
113
|
+
"addr_vkh"
|
|
114
|
+
);
|
|
115
|
+
return credentialBech32;
|
|
116
|
+
})();
|
|
117
|
+
let result = [];
|
|
118
|
+
let page = 1;
|
|
119
|
+
while (true) {
|
|
120
|
+
const pageResult = await fetch(
|
|
121
|
+
`${this.url}/addresses/${queryPredicate}/utxos?page=${page}`,
|
|
122
|
+
{ headers: { project_id: this.projectId, lucid } }
|
|
123
|
+
).then((res) => res.json());
|
|
124
|
+
if (pageResult.error) {
|
|
125
|
+
if (pageResult.status_code === 404) {
|
|
126
|
+
return [];
|
|
127
|
+
} else {
|
|
128
|
+
throw new Error("Could not fetch UTxOs from Blockfrost. Try again.");
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
result = result.concat(pageResult);
|
|
132
|
+
if (pageResult.length <= 0)
|
|
133
|
+
break;
|
|
134
|
+
page++;
|
|
135
|
+
}
|
|
136
|
+
return this.blockfrostUtxosToUtxos(result);
|
|
137
|
+
}
|
|
138
|
+
async getUtxosWithUnit(addressOrCredential, unit) {
|
|
139
|
+
const queryPredicate = (() => {
|
|
140
|
+
if (typeof addressOrCredential === "string")
|
|
141
|
+
return addressOrCredential;
|
|
142
|
+
const credentialBech32 = addressOrCredential.type === "Key" ? CML.Ed25519KeyHash.from_hex(addressOrCredential.hash).to_bech32(
|
|
143
|
+
"addr_vkh"
|
|
144
|
+
) : CML.ScriptHash.from_hex(addressOrCredential.hash).to_bech32(
|
|
145
|
+
"addr_vkh"
|
|
146
|
+
);
|
|
147
|
+
return credentialBech32;
|
|
148
|
+
})();
|
|
149
|
+
let result = [];
|
|
150
|
+
let page = 1;
|
|
151
|
+
while (true) {
|
|
152
|
+
const pageResult = await fetch(
|
|
153
|
+
`${this.url}/addresses/${queryPredicate}/utxos/${unit}?page=${page}`,
|
|
154
|
+
{ headers: { project_id: this.projectId, lucid } }
|
|
155
|
+
).then((res) => res.json());
|
|
156
|
+
if (pageResult.error) {
|
|
157
|
+
if (pageResult.status_code === 404) {
|
|
158
|
+
return [];
|
|
159
|
+
} else {
|
|
160
|
+
throw new Error("Could not fetch UTxOs from Blockfrost. Try again.");
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
result = result.concat(pageResult);
|
|
164
|
+
if (pageResult.length <= 0)
|
|
165
|
+
break;
|
|
166
|
+
page++;
|
|
167
|
+
}
|
|
168
|
+
return this.blockfrostUtxosToUtxos(result);
|
|
169
|
+
}
|
|
170
|
+
async getUtxoByUnit(unit) {
|
|
171
|
+
const addresses = await fetch(
|
|
172
|
+
`${this.url}/assets/${unit}/addresses?count=2`,
|
|
173
|
+
{ headers: { project_id: this.projectId, lucid } }
|
|
174
|
+
).then((res) => res.json());
|
|
175
|
+
if (!addresses || addresses.error) {
|
|
176
|
+
throw new Error("Unit not found.");
|
|
177
|
+
}
|
|
178
|
+
if (addresses.length > 1) {
|
|
179
|
+
throw new Error("Unit needs to be an NFT or only held by one address.");
|
|
180
|
+
}
|
|
181
|
+
const address = addresses[0].address;
|
|
182
|
+
const utxos = await this.getUtxosWithUnit(address, unit);
|
|
183
|
+
if (utxos.length > 1) {
|
|
184
|
+
throw new Error("Unit needs to be an NFT or only held by one address.");
|
|
185
|
+
}
|
|
186
|
+
return utxos[0];
|
|
187
|
+
}
|
|
188
|
+
async getUtxosByOutRef(outRefs) {
|
|
189
|
+
const queryHashes = [...new Set(outRefs.map((outRef) => outRef.txHash))];
|
|
190
|
+
const utxos = await Promise.all(
|
|
191
|
+
queryHashes.map(async (txHash) => {
|
|
192
|
+
const result = await fetch(`${this.url}/txs/${txHash}/utxos`, {
|
|
193
|
+
headers: { project_id: this.projectId, lucid }
|
|
194
|
+
}).then((res) => res.json());
|
|
195
|
+
if (!result || result.error) {
|
|
196
|
+
return [];
|
|
197
|
+
}
|
|
198
|
+
const utxosResult = result.outputs.map(
|
|
199
|
+
(r) => ({
|
|
200
|
+
...r,
|
|
201
|
+
tx_hash: txHash
|
|
202
|
+
})
|
|
203
|
+
);
|
|
204
|
+
return this.blockfrostUtxosToUtxos(utxosResult);
|
|
205
|
+
})
|
|
206
|
+
);
|
|
207
|
+
return utxos.reduce((acc, utxos2) => acc.concat(utxos2), []).filter(
|
|
208
|
+
(utxo) => outRefs.some(
|
|
209
|
+
(outRef) => utxo.txHash === outRef.txHash && utxo.outputIndex === outRef.outputIndex
|
|
210
|
+
)
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
async getDelegation(rewardAddress) {
|
|
214
|
+
const result = await fetch(`${this.url}/accounts/${rewardAddress}`, {
|
|
215
|
+
headers: { project_id: this.projectId, lucid }
|
|
216
|
+
}).then((res) => res.json());
|
|
217
|
+
if (!result || result.error) {
|
|
218
|
+
return { poolId: null, rewards: 0n };
|
|
219
|
+
}
|
|
220
|
+
return {
|
|
221
|
+
poolId: result.pool_id || null,
|
|
222
|
+
rewards: BigInt(result.withdrawable_amount)
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
async getDatum(datumHash) {
|
|
226
|
+
const datum = await fetch(`${this.url}/scripts/datum/${datumHash}/cbor`, {
|
|
227
|
+
headers: { project_id: this.projectId, lucid }
|
|
228
|
+
}).then((res) => res.json()).then((res) => res.cbor);
|
|
229
|
+
if (!datum || datum.error) {
|
|
230
|
+
throw new Error(`No datum found for datum hash: ${datumHash}`);
|
|
231
|
+
}
|
|
232
|
+
return datum;
|
|
233
|
+
}
|
|
234
|
+
awaitTx(txHash, checkInterval = 3e3) {
|
|
235
|
+
return new Promise((res) => {
|
|
236
|
+
const confirmation = setInterval(async () => {
|
|
237
|
+
const isConfirmed = await fetch(`${this.url}/txs/${txHash}`, {
|
|
238
|
+
headers: { project_id: this.projectId, lucid }
|
|
239
|
+
}).then((res2) => res2.json());
|
|
240
|
+
if (isConfirmed && !isConfirmed.error) {
|
|
241
|
+
clearInterval(confirmation);
|
|
242
|
+
await new Promise((res2) => setTimeout(() => res2(1), 1e3));
|
|
243
|
+
return res(true);
|
|
244
|
+
}
|
|
245
|
+
}, checkInterval);
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
async submitTx(tx) {
|
|
249
|
+
const result = await fetch(`${this.url}/tx/submit`, {
|
|
250
|
+
method: "POST",
|
|
251
|
+
headers: {
|
|
252
|
+
"Content-Type": "application/cbor",
|
|
253
|
+
project_id: this.projectId,
|
|
254
|
+
lucid
|
|
255
|
+
},
|
|
256
|
+
body: (0, import_core_utils.fromHex)(tx)
|
|
257
|
+
}).then((res) => res.json());
|
|
258
|
+
if (!result || result.error) {
|
|
259
|
+
if (result?.status_code === 400)
|
|
260
|
+
throw new Error(result.message);
|
|
261
|
+
else
|
|
262
|
+
throw new Error("Could not submit transaction.");
|
|
263
|
+
}
|
|
264
|
+
return result;
|
|
265
|
+
}
|
|
266
|
+
async blockfrostUtxosToUtxos(result) {
|
|
267
|
+
return await Promise.all(
|
|
268
|
+
result.map(async (r) => ({
|
|
269
|
+
txHash: r.tx_hash,
|
|
270
|
+
outputIndex: r.output_index,
|
|
271
|
+
assets: Object.fromEntries(
|
|
272
|
+
r.amount.map(({ unit, quantity }) => [unit, BigInt(quantity)])
|
|
273
|
+
),
|
|
274
|
+
address: r.address,
|
|
275
|
+
datumHash: !r.inline_datum && r.data_hash || void 0,
|
|
276
|
+
datum: r.inline_datum || void 0,
|
|
277
|
+
scriptRef: r.reference_script_hash ? await (async () => {
|
|
278
|
+
const { type } = await fetch(
|
|
279
|
+
`${this.url}/scripts/${r.reference_script_hash}`,
|
|
280
|
+
{
|
|
281
|
+
headers: { project_id: this.projectId, lucid }
|
|
282
|
+
}
|
|
283
|
+
).then((res) => res.json());
|
|
284
|
+
if (type === "Native" || type === "native") {
|
|
285
|
+
throw new Error("Native script ref not implemented!");
|
|
286
|
+
}
|
|
287
|
+
const { cbor: script } = await fetch(
|
|
288
|
+
`${this.url}/scripts/${r.reference_script_hash}/cbor`,
|
|
289
|
+
{ headers: { project_id: this.projectId, lucid } }
|
|
290
|
+
).then((res) => res.json());
|
|
291
|
+
return {
|
|
292
|
+
type: type === "plutusV1" ? "PlutusV1" : "PlutusV2",
|
|
293
|
+
script: (0, import_utils.applyDoubleCborEncoding)(script)
|
|
294
|
+
};
|
|
295
|
+
})() : void 0
|
|
296
|
+
}))
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
function datumJsonToCbor(json) {
|
|
301
|
+
const convert = (json2) => {
|
|
302
|
+
if (!isNaN(json2.int)) {
|
|
303
|
+
return CML.PlutusData.new_integer(
|
|
304
|
+
CML.BigInteger.from_str(json2.int.toString())
|
|
305
|
+
);
|
|
306
|
+
} else if (json2.bytes || !isNaN(Number(json2.bytes))) {
|
|
307
|
+
return CML.PlutusData.new_bytes((0, import_core_utils.fromHex)(json2.bytes));
|
|
308
|
+
} else if (json2.map) {
|
|
309
|
+
const m = CML.PlutusMap.new();
|
|
310
|
+
json2.map.forEach(({ k, v }) => {
|
|
311
|
+
m.set(convert(k), convert(v));
|
|
312
|
+
});
|
|
313
|
+
return CML.PlutusData.new_map(m);
|
|
314
|
+
} else if (json2.list) {
|
|
315
|
+
const l = CML.PlutusDataList.new();
|
|
316
|
+
json2.list.forEach((v) => {
|
|
317
|
+
l.add(convert(v));
|
|
318
|
+
});
|
|
319
|
+
return CML.PlutusData.new_list(l);
|
|
320
|
+
} else if (!isNaN(json2.constructor)) {
|
|
321
|
+
const l = CML.PlutusDataList.new();
|
|
322
|
+
json2.fields.forEach((v) => {
|
|
323
|
+
l.add(convert(v));
|
|
324
|
+
});
|
|
325
|
+
return CML.PlutusData.new_constr_plutus_data(
|
|
326
|
+
CML.ConstrPlutusData.new(
|
|
327
|
+
CML.BigInteger.from_str(json2.constructor.toString()).as_u64(),
|
|
328
|
+
l
|
|
329
|
+
)
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
throw new Error("Unsupported type");
|
|
333
|
+
};
|
|
334
|
+
return convert(json).to_cbor_hex();
|
|
335
|
+
}
|
|
336
|
+
var lucid = package_default.version;
|
|
337
|
+
|
|
338
|
+
// src/kupmios.ts
|
|
339
|
+
var import_utils2 = require("@lucid-evolution/utils");
|
|
340
|
+
var CML2 = __toESM(require("@dcspark/cardano-multiplatform-lib-nodejs"), 1);
|
|
341
|
+
var Kupmios = class {
|
|
342
|
+
kupoUrl;
|
|
343
|
+
ogmiosUrl;
|
|
344
|
+
/**
|
|
345
|
+
* @param kupoUrl: http(s)://localhost:1442
|
|
346
|
+
* @param ogmiosUrl: ws(s)://localhost:1337
|
|
347
|
+
*/
|
|
348
|
+
constructor(kupoUrl, ogmiosUrl) {
|
|
349
|
+
this.kupoUrl = kupoUrl;
|
|
350
|
+
this.ogmiosUrl = ogmiosUrl;
|
|
351
|
+
}
|
|
352
|
+
async getProtocolParameters() {
|
|
353
|
+
const client = await this.ogmiosWsp("Query", {
|
|
354
|
+
query: "currentProtocolParameters"
|
|
355
|
+
});
|
|
356
|
+
return new Promise((res, rej) => {
|
|
357
|
+
client.addEventListener(
|
|
358
|
+
"message",
|
|
359
|
+
(msg) => {
|
|
360
|
+
try {
|
|
361
|
+
const { result } = JSON.parse(msg.data);
|
|
362
|
+
const costModels = {};
|
|
363
|
+
Object.keys(result.costModels).forEach((v) => {
|
|
364
|
+
const version = v.split(":")[1].toUpperCase();
|
|
365
|
+
const plutusVersion = "Plutus" + version;
|
|
366
|
+
costModels[plutusVersion] = result.costModels[v];
|
|
367
|
+
});
|
|
368
|
+
const [memNum, memDenom] = result.prices.memory.split("/");
|
|
369
|
+
const [stepsNum, stepsDenom] = result.prices.steps.split("/");
|
|
370
|
+
res({
|
|
371
|
+
minFeeA: parseInt(result.minFeeCoefficient),
|
|
372
|
+
minFeeB: parseInt(result.minFeeConstant),
|
|
373
|
+
maxTxSize: parseInt(result.maxTxSize),
|
|
374
|
+
maxValSize: parseInt(result.maxValueSize),
|
|
375
|
+
keyDeposit: BigInt(result.stakeKeyDeposit),
|
|
376
|
+
poolDeposit: BigInt(result.poolDeposit),
|
|
377
|
+
priceMem: parseInt(memNum) / parseInt(memDenom),
|
|
378
|
+
priceStep: parseInt(stepsNum) / parseInt(stepsDenom),
|
|
379
|
+
maxTxExMem: BigInt(result.maxExecutionUnitsPerTransaction.memory),
|
|
380
|
+
maxTxExSteps: BigInt(
|
|
381
|
+
result.maxExecutionUnitsPerTransaction.steps
|
|
382
|
+
),
|
|
383
|
+
coinsPerUtxoByte: BigInt(result.coinsPerUtxoByte),
|
|
384
|
+
collateralPercentage: parseInt(result.collateralPercentage),
|
|
385
|
+
maxCollateralInputs: parseInt(result.maxCollateralInputs),
|
|
386
|
+
costModels
|
|
387
|
+
});
|
|
388
|
+
client.close();
|
|
389
|
+
} catch (e) {
|
|
390
|
+
rej(e);
|
|
391
|
+
}
|
|
392
|
+
},
|
|
393
|
+
{ once: true }
|
|
394
|
+
);
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
async getUtxos(addressOrCredential) {
|
|
398
|
+
const isAddress = typeof addressOrCredential === "string";
|
|
399
|
+
const queryPredicate = isAddress ? addressOrCredential : addressOrCredential.hash;
|
|
400
|
+
const result = await fetch(
|
|
401
|
+
`${this.kupoUrl}/matches/${queryPredicate}${isAddress ? "" : "/*"}?unspent`
|
|
402
|
+
).then((res) => res.json());
|
|
403
|
+
return this.kupmiosUtxosToUtxos(result);
|
|
404
|
+
}
|
|
405
|
+
async getUtxosWithUnit(addressOrCredential, unit) {
|
|
406
|
+
const isAddress = typeof addressOrCredential === "string";
|
|
407
|
+
const queryPredicate = isAddress ? addressOrCredential : addressOrCredential.hash;
|
|
408
|
+
const { policyId, assetName } = (0, import_utils2.fromUnit)(unit);
|
|
409
|
+
const result = await fetch(
|
|
410
|
+
`${this.kupoUrl}/matches/${queryPredicate}${isAddress ? "" : "/*"}?unspent&policy_id=${policyId}${assetName ? `&asset_name=${assetName}` : ""}`
|
|
411
|
+
).then((res) => res.json());
|
|
412
|
+
return this.kupmiosUtxosToUtxos(result);
|
|
413
|
+
}
|
|
414
|
+
async getUtxoByUnit(unit) {
|
|
415
|
+
const { policyId, assetName } = (0, import_utils2.fromUnit)(unit);
|
|
416
|
+
const result = await fetch(
|
|
417
|
+
`${this.kupoUrl}/matches/${policyId}.${assetName ? `${assetName}` : "*"}?unspent`
|
|
418
|
+
).then((res) => res.json());
|
|
419
|
+
const utxos = await this.kupmiosUtxosToUtxos(result);
|
|
420
|
+
if (utxos.length > 1) {
|
|
421
|
+
throw new Error("Unit needs to be an NFT or only held by one address.");
|
|
422
|
+
}
|
|
423
|
+
return utxos[0];
|
|
424
|
+
}
|
|
425
|
+
async getUtxosByOutRef(outRefs) {
|
|
426
|
+
const queryHashes = [...new Set(outRefs.map((outRef) => outRef.txHash))];
|
|
427
|
+
const utxos = await Promise.all(
|
|
428
|
+
queryHashes.map(async (txHash) => {
|
|
429
|
+
const result = await fetch(
|
|
430
|
+
`${this.kupoUrl}/matches/*@${txHash}?unspent`
|
|
431
|
+
).then((res) => res.json());
|
|
432
|
+
return this.kupmiosUtxosToUtxos(result);
|
|
433
|
+
})
|
|
434
|
+
);
|
|
435
|
+
return utxos.reduce((acc, utxos2) => acc.concat(utxos2), []).filter(
|
|
436
|
+
(utxo) => outRefs.some(
|
|
437
|
+
(outRef) => utxo.txHash === outRef.txHash && utxo.outputIndex === outRef.outputIndex
|
|
438
|
+
)
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
async getDelegation(rewardAddress) {
|
|
442
|
+
const client = await this.ogmiosWsp("Query", {
|
|
443
|
+
query: { delegationsAndRewards: [rewardAddress] }
|
|
444
|
+
});
|
|
445
|
+
return new Promise((res, rej) => {
|
|
446
|
+
client.addEventListener(
|
|
447
|
+
"message",
|
|
448
|
+
(msg) => {
|
|
449
|
+
try {
|
|
450
|
+
const { result } = JSON.parse(msg.data);
|
|
451
|
+
const delegation = result ? Object.values(result)[0] : {};
|
|
452
|
+
res({
|
|
453
|
+
poolId: delegation?.delegate || null,
|
|
454
|
+
rewards: BigInt(delegation?.rewards || 0)
|
|
455
|
+
});
|
|
456
|
+
client.close();
|
|
457
|
+
} catch (e) {
|
|
458
|
+
rej(e);
|
|
459
|
+
}
|
|
460
|
+
},
|
|
461
|
+
{ once: true }
|
|
462
|
+
);
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
async getDatum(datumHash) {
|
|
466
|
+
const result = await fetch(`${this.kupoUrl}/datums/${datumHash}`).then(
|
|
467
|
+
(res) => res.json()
|
|
468
|
+
);
|
|
469
|
+
if (!result || !result.datum) {
|
|
470
|
+
throw new Error(`No datum found for datum hash: ${datumHash}`);
|
|
471
|
+
}
|
|
472
|
+
return result.datum;
|
|
473
|
+
}
|
|
474
|
+
awaitTx(txHash, checkInterval = 3e3) {
|
|
475
|
+
return new Promise((res) => {
|
|
476
|
+
const confirmation = setInterval(async () => {
|
|
477
|
+
const isConfirmed = await fetch(
|
|
478
|
+
`${this.kupoUrl}/matches/*@${txHash}?unspent`
|
|
479
|
+
).then((res2) => res2.json());
|
|
480
|
+
if (isConfirmed && isConfirmed.length > 0) {
|
|
481
|
+
clearInterval(confirmation);
|
|
482
|
+
await new Promise((res2) => setTimeout(() => res2(1), 1e3));
|
|
483
|
+
return res(true);
|
|
484
|
+
}
|
|
485
|
+
}, checkInterval);
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
async submitTx(tx) {
|
|
489
|
+
const client = await this.ogmiosWsp("SubmitTx", {
|
|
490
|
+
submit: tx
|
|
491
|
+
});
|
|
492
|
+
return new Promise((res, rej) => {
|
|
493
|
+
client.addEventListener(
|
|
494
|
+
"message",
|
|
495
|
+
(msg) => {
|
|
496
|
+
try {
|
|
497
|
+
const { result } = JSON.parse(msg.data);
|
|
498
|
+
if (result.SubmitSuccess)
|
|
499
|
+
res(result.SubmitSuccess.txId);
|
|
500
|
+
else
|
|
501
|
+
rej(result.SubmitFail);
|
|
502
|
+
client.close();
|
|
503
|
+
} catch (e) {
|
|
504
|
+
rej(e);
|
|
505
|
+
}
|
|
506
|
+
},
|
|
507
|
+
{ once: true }
|
|
508
|
+
);
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
kupmiosUtxosToUtxos(utxos) {
|
|
512
|
+
return Promise.all(
|
|
513
|
+
utxos.map(async (utxo) => {
|
|
514
|
+
return {
|
|
515
|
+
txHash: utxo.transaction_id,
|
|
516
|
+
outputIndex: parseInt(utxo.output_index),
|
|
517
|
+
address: utxo.address,
|
|
518
|
+
assets: (() => {
|
|
519
|
+
const a = { lovelace: BigInt(utxo.value.coins) };
|
|
520
|
+
Object.keys(utxo.value.assets).forEach((unit) => {
|
|
521
|
+
a[unit.replace(".", "")] = BigInt(utxo.value.assets[unit]);
|
|
522
|
+
});
|
|
523
|
+
return a;
|
|
524
|
+
})(),
|
|
525
|
+
datumHash: utxo?.datum_type === "hash" ? utxo.datum_hash : null,
|
|
526
|
+
datum: utxo?.datum_type === "inline" ? await this.getDatum(utxo.datum_hash) : null,
|
|
527
|
+
scriptRef: utxo.script_hash && await (async () => {
|
|
528
|
+
const { script, language } = await fetch(
|
|
529
|
+
`${this.kupoUrl}/scripts/${utxo.script_hash}`
|
|
530
|
+
).then((res) => res.json());
|
|
531
|
+
if (language === "native") {
|
|
532
|
+
return { type: "Native", script };
|
|
533
|
+
} else if (language === "plutus:v1") {
|
|
534
|
+
return {
|
|
535
|
+
type: "PlutusV1",
|
|
536
|
+
script: CML2.PlutusV1Script.from_cbor_hex(script).to_cbor_hex()
|
|
537
|
+
};
|
|
538
|
+
} else if (language === "plutus:v2") {
|
|
539
|
+
return {
|
|
540
|
+
type: "PlutusV2",
|
|
541
|
+
script: CML2.PlutusV2Script.from_cbor_hex(script).to_cbor_hex()
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
})()
|
|
545
|
+
};
|
|
546
|
+
})
|
|
547
|
+
);
|
|
548
|
+
}
|
|
549
|
+
async ogmiosWsp(methodname, args) {
|
|
550
|
+
const client = new WebSocket(this.ogmiosUrl);
|
|
551
|
+
await new Promise((res) => {
|
|
552
|
+
client.addEventListener("open", () => res(1), { once: true });
|
|
553
|
+
});
|
|
554
|
+
client.send(
|
|
555
|
+
JSON.stringify({
|
|
556
|
+
type: "jsonwsp/request",
|
|
557
|
+
version: "1.0",
|
|
558
|
+
servicename: "ogmios",
|
|
559
|
+
methodname,
|
|
560
|
+
args
|
|
561
|
+
})
|
|
562
|
+
);
|
|
563
|
+
return client;
|
|
564
|
+
}
|
|
565
|
+
};
|
|
566
|
+
|
|
567
|
+
// src/maestro.ts
|
|
568
|
+
var CML3 = __toESM(require("@dcspark/cardano-multiplatform-lib-nodejs"), 1);
|
|
569
|
+
var import_utils3 = require("@lucid-evolution/utils");
|
|
570
|
+
var import_core_utils2 = require("@lucid-evolution/core-utils");
|
|
571
|
+
var Maestro = class {
|
|
572
|
+
url;
|
|
573
|
+
apiKey;
|
|
574
|
+
turboSubmit;
|
|
575
|
+
constructor({ network, apiKey, turboSubmit = false }) {
|
|
576
|
+
this.url = `https://${network}.gomaestro-api.org/v1`;
|
|
577
|
+
this.apiKey = apiKey;
|
|
578
|
+
this.turboSubmit = turboSubmit;
|
|
579
|
+
}
|
|
580
|
+
async getProtocolParameters() {
|
|
581
|
+
const timestampedResult = await fetch(`${this.url}/protocol-params`, {
|
|
582
|
+
headers: this.commonHeaders()
|
|
583
|
+
}).then((res) => res.json());
|
|
584
|
+
const result = timestampedResult.data;
|
|
585
|
+
const decimalFromRationalString = (str) => {
|
|
586
|
+
const forwardSlashIndex = str.indexOf("/");
|
|
587
|
+
return parseInt(str.slice(0, forwardSlashIndex)) / parseInt(str.slice(forwardSlashIndex + 1));
|
|
588
|
+
};
|
|
589
|
+
const renameKeysAndSort = (obj, newKeys) => {
|
|
590
|
+
const entries = Object.keys(obj).sort().map((key) => {
|
|
591
|
+
const newKey = newKeys[key] || key;
|
|
592
|
+
return {
|
|
593
|
+
[newKey]: Object.fromEntries(
|
|
594
|
+
Object.entries(obj[key]).sort(
|
|
595
|
+
([k, _v], [k2, _v2]) => k.localeCompare(k2)
|
|
596
|
+
)
|
|
597
|
+
)
|
|
598
|
+
};
|
|
599
|
+
});
|
|
600
|
+
return Object.assign({}, ...entries);
|
|
601
|
+
};
|
|
602
|
+
return {
|
|
603
|
+
minFeeA: parseInt(result.min_fee_coefficient),
|
|
604
|
+
minFeeB: parseInt(result.min_fee_constant),
|
|
605
|
+
maxTxSize: parseInt(result.max_tx_size),
|
|
606
|
+
maxValSize: parseInt(result.max_value_size),
|
|
607
|
+
keyDeposit: BigInt(result.stake_key_deposit),
|
|
608
|
+
poolDeposit: BigInt(result.pool_deposit),
|
|
609
|
+
priceMem: decimalFromRationalString(result.prices.memory),
|
|
610
|
+
priceStep: decimalFromRationalString(result.prices.steps),
|
|
611
|
+
maxTxExMem: BigInt(result.max_execution_units_per_transaction.memory),
|
|
612
|
+
maxTxExSteps: BigInt(result.max_execution_units_per_transaction.steps),
|
|
613
|
+
coinsPerUtxoByte: BigInt(result.coins_per_utxo_byte),
|
|
614
|
+
collateralPercentage: parseInt(result.collateral_percentage),
|
|
615
|
+
maxCollateralInputs: parseInt(result.max_collateral_inputs),
|
|
616
|
+
costModels: renameKeysAndSort(result.cost_models, {
|
|
617
|
+
"plutus:v1": "PlutusV1",
|
|
618
|
+
"plutus:v2": "PlutusV2"
|
|
619
|
+
})
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
async getUtxosInternal(addressOrCredential, unit) {
|
|
623
|
+
const queryPredicate = (() => {
|
|
624
|
+
if (typeof addressOrCredential === "string") {
|
|
625
|
+
return "/addresses/" + addressOrCredential;
|
|
626
|
+
}
|
|
627
|
+
let credentialBech32Query = "/addresses/cred/";
|
|
628
|
+
credentialBech32Query += addressOrCredential.type === "Key" ? CML3.Ed25519KeyHash.from_hex(addressOrCredential.hash).to_bech32(
|
|
629
|
+
"addr_vkh"
|
|
630
|
+
) : CML3.ScriptHash.from_hex(addressOrCredential.hash).to_bech32(
|
|
631
|
+
"addr_shared_vkh"
|
|
632
|
+
);
|
|
633
|
+
return credentialBech32Query;
|
|
634
|
+
})();
|
|
635
|
+
const qparams = new URLSearchParams({
|
|
636
|
+
count: "100",
|
|
637
|
+
...unit && { asset: unit }
|
|
638
|
+
});
|
|
639
|
+
const result = await this.getAllPagesData(
|
|
640
|
+
async (qry) => await fetch(qry, {
|
|
641
|
+
headers: this.requireAmountsAsStrings(this.commonHeaders())
|
|
642
|
+
}),
|
|
643
|
+
`${this.url}${queryPredicate}/utxos`,
|
|
644
|
+
qparams,
|
|
645
|
+
"Location: getUtxosInternal. Error: Could not fetch UTxOs from Maestro"
|
|
646
|
+
);
|
|
647
|
+
return result.map(this.maestroUtxoToUtxo);
|
|
648
|
+
}
|
|
649
|
+
getUtxos(addressOrCredential) {
|
|
650
|
+
return this.getUtxosInternal(addressOrCredential);
|
|
651
|
+
}
|
|
652
|
+
getUtxosWithUnit(addressOrCredential, unit) {
|
|
653
|
+
return this.getUtxosInternal(addressOrCredential, unit);
|
|
654
|
+
}
|
|
655
|
+
async getUtxoByUnit(unit) {
|
|
656
|
+
const timestampedAddressesResponse = await fetch(
|
|
657
|
+
`${this.url}/assets/${unit}/addresses?count=2`,
|
|
658
|
+
{ headers: this.commonHeaders() }
|
|
659
|
+
);
|
|
660
|
+
const timestampedAddresses = await timestampedAddressesResponse.json();
|
|
661
|
+
if (!timestampedAddressesResponse.ok) {
|
|
662
|
+
if (timestampedAddresses.message) {
|
|
663
|
+
throw new Error(timestampedAddresses.message);
|
|
664
|
+
}
|
|
665
|
+
throw new Error(
|
|
666
|
+
"Location: getUtxoByUnit. Error: Couldn't perform query. Received status code: " + timestampedAddressesResponse.status
|
|
667
|
+
);
|
|
668
|
+
}
|
|
669
|
+
const addressesWithAmount = timestampedAddresses.data;
|
|
670
|
+
if (addressesWithAmount.length === 0) {
|
|
671
|
+
throw new Error("Location: getUtxoByUnit. Error: Unit not found.");
|
|
672
|
+
}
|
|
673
|
+
if (addressesWithAmount.length > 1) {
|
|
674
|
+
throw new Error(
|
|
675
|
+
"Location: getUtxoByUnit. Error: Unit needs to be an NFT or only held by one address."
|
|
676
|
+
);
|
|
677
|
+
}
|
|
678
|
+
const address = addressesWithAmount[0].address;
|
|
679
|
+
const utxos = await this.getUtxosWithUnit(address, unit);
|
|
680
|
+
if (utxos.length > 1) {
|
|
681
|
+
throw new Error(
|
|
682
|
+
"Location: getUtxoByUnit. Error: Unit needs to be an NFT or only held by one address."
|
|
683
|
+
);
|
|
684
|
+
}
|
|
685
|
+
return utxos[0];
|
|
686
|
+
}
|
|
687
|
+
async getUtxosByOutRef(outRefs) {
|
|
688
|
+
const qry = `${this.url}/transactions/outputs`;
|
|
689
|
+
const body = JSON.stringify(
|
|
690
|
+
outRefs.map(({ txHash, outputIndex }) => `${txHash}#${outputIndex}`)
|
|
691
|
+
);
|
|
692
|
+
const utxos = await this.getAllPagesData(
|
|
693
|
+
async (qry2) => await fetch(qry2, {
|
|
694
|
+
method: "POST",
|
|
695
|
+
headers: {
|
|
696
|
+
"Content-Type": "application/json",
|
|
697
|
+
...this.requireAmountsAsStrings(this.commonHeaders())
|
|
698
|
+
},
|
|
699
|
+
body
|
|
700
|
+
}),
|
|
701
|
+
qry,
|
|
702
|
+
new URLSearchParams({}),
|
|
703
|
+
"Location: getUtxosByOutRef. Error: Could not fetch UTxOs by references from Maestro"
|
|
704
|
+
);
|
|
705
|
+
return utxos.map(this.maestroUtxoToUtxo);
|
|
706
|
+
}
|
|
707
|
+
async getDelegation(rewardAddress) {
|
|
708
|
+
const timestampedResultResponse = await fetch(
|
|
709
|
+
`${this.url}/accounts/${rewardAddress}`,
|
|
710
|
+
{ headers: this.commonHeaders() }
|
|
711
|
+
);
|
|
712
|
+
if (!timestampedResultResponse.ok) {
|
|
713
|
+
return { poolId: null, rewards: 0n };
|
|
714
|
+
}
|
|
715
|
+
const timestampedResult = await timestampedResultResponse.json();
|
|
716
|
+
const result = timestampedResult.data;
|
|
717
|
+
return {
|
|
718
|
+
poolId: result.delegated_pool || null,
|
|
719
|
+
rewards: BigInt(result.rewards_available)
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
async getDatum(datumHash) {
|
|
723
|
+
const timestampedResultResponse = await fetch(
|
|
724
|
+
`${this.url}/datums/${datumHash}`,
|
|
725
|
+
{
|
|
726
|
+
headers: this.commonHeaders()
|
|
727
|
+
}
|
|
728
|
+
);
|
|
729
|
+
if (!timestampedResultResponse.ok) {
|
|
730
|
+
if (timestampedResultResponse.status === 404) {
|
|
731
|
+
throw new Error(`No datum found for datum hash: ${datumHash}`);
|
|
732
|
+
} else {
|
|
733
|
+
throw new Error(
|
|
734
|
+
"Location: getDatum. Error: Couldn't successfully perform query. Received status code: " + timestampedResultResponse.status
|
|
735
|
+
);
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
const timestampedResult = await timestampedResultResponse.json();
|
|
739
|
+
return timestampedResult.data.bytes;
|
|
740
|
+
}
|
|
741
|
+
awaitTx(txHash, checkInterval = 3e3) {
|
|
742
|
+
return new Promise((res) => {
|
|
743
|
+
const confirmation = setInterval(async () => {
|
|
744
|
+
const isConfirmedResponse = await fetch(
|
|
745
|
+
`${this.url}/transactions/${txHash}/cbor`,
|
|
746
|
+
{
|
|
747
|
+
headers: this.commonHeaders()
|
|
748
|
+
}
|
|
749
|
+
);
|
|
750
|
+
if (isConfirmedResponse.ok) {
|
|
751
|
+
await isConfirmedResponse.json();
|
|
752
|
+
clearInterval(confirmation);
|
|
753
|
+
await new Promise((res2) => setTimeout(() => res2(1), 1e3));
|
|
754
|
+
return res(true);
|
|
755
|
+
}
|
|
756
|
+
}, checkInterval);
|
|
757
|
+
});
|
|
758
|
+
}
|
|
759
|
+
async submitTx(tx) {
|
|
760
|
+
let queryUrl = `${this.url}/txmanager`;
|
|
761
|
+
queryUrl += this.turboSubmit ? "/turbosubmit" : "";
|
|
762
|
+
const response = await fetch(queryUrl, {
|
|
763
|
+
method: "POST",
|
|
764
|
+
headers: {
|
|
765
|
+
"Content-Type": "application/cbor",
|
|
766
|
+
Accept: "text/plain",
|
|
767
|
+
...this.commonHeaders()
|
|
768
|
+
},
|
|
769
|
+
body: (0, import_core_utils2.fromHex)(tx)
|
|
770
|
+
});
|
|
771
|
+
const result = await response.text();
|
|
772
|
+
if (!response.ok) {
|
|
773
|
+
if (response.status === 400)
|
|
774
|
+
throw new Error(result);
|
|
775
|
+
else {
|
|
776
|
+
throw new Error(
|
|
777
|
+
"Could not submit transaction. Received status code: " + response.status
|
|
778
|
+
);
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
return result;
|
|
782
|
+
}
|
|
783
|
+
commonHeaders() {
|
|
784
|
+
return { "api-key": this.apiKey, lucid: lucid2 };
|
|
785
|
+
}
|
|
786
|
+
requireAmountsAsStrings(obj) {
|
|
787
|
+
return { ...obj, "amounts-as-strings": "true" };
|
|
788
|
+
}
|
|
789
|
+
maestroUtxoToUtxo(result) {
|
|
790
|
+
return {
|
|
791
|
+
txHash: result.tx_hash,
|
|
792
|
+
outputIndex: result.index,
|
|
793
|
+
assets: (() => {
|
|
794
|
+
const a = {};
|
|
795
|
+
result.assets.forEach((am) => {
|
|
796
|
+
a[am.unit] = BigInt(am.amount);
|
|
797
|
+
});
|
|
798
|
+
return a;
|
|
799
|
+
})(),
|
|
800
|
+
address: result.address,
|
|
801
|
+
datumHash: result.datum ? result.datum.type == "inline" ? void 0 : result.datum.hash : void 0,
|
|
802
|
+
datum: result.datum?.bytes,
|
|
803
|
+
scriptRef: result.reference_script ? result.reference_script.type == "native" ? void 0 : {
|
|
804
|
+
type: result.reference_script.type == "plutusv1" ? "PlutusV1" : "PlutusV2",
|
|
805
|
+
script: (0, import_utils3.applyDoubleCborEncoding)(result.reference_script.bytes)
|
|
806
|
+
} : void 0
|
|
807
|
+
};
|
|
808
|
+
}
|
|
809
|
+
async getAllPagesData(getResponse, qry, paramsGiven, errorMsg) {
|
|
810
|
+
let nextCursor = null;
|
|
811
|
+
let result = [];
|
|
812
|
+
while (true) {
|
|
813
|
+
if (nextCursor !== null) {
|
|
814
|
+
paramsGiven.set("cursor", nextCursor);
|
|
815
|
+
}
|
|
816
|
+
const response = await getResponse(`${qry}?` + paramsGiven);
|
|
817
|
+
const pageResult = await response.json();
|
|
818
|
+
if (!response.ok) {
|
|
819
|
+
throw new Error(
|
|
820
|
+
`${errorMsg}. Received status code: ${response.status}`
|
|
821
|
+
);
|
|
822
|
+
}
|
|
823
|
+
nextCursor = pageResult.next_cursor;
|
|
824
|
+
result = result.concat(pageResult.data);
|
|
825
|
+
if (nextCursor == null)
|
|
826
|
+
break;
|
|
827
|
+
}
|
|
828
|
+
return result;
|
|
829
|
+
}
|
|
830
|
+
};
|
|
831
|
+
var lucid2 = package_default.version;
|
|
832
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
833
|
+
0 && (module.exports = {
|
|
834
|
+
Blockfrost,
|
|
835
|
+
Kupmios,
|
|
836
|
+
Maestro,
|
|
837
|
+
datumJsonToCbor
|
|
838
|
+
});
|