@lucid-evolution/provider 0.2.6 → 0.3.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/dist/index.cjs +523 -618
- package/dist/index.d.cts +48 -48
- package/dist/index.d.ts +48 -48
- package/dist/index.js +537 -622
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -101,7 +101,7 @@ import {
|
|
|
101
101
|
// package.json
|
|
102
102
|
var package_default = {
|
|
103
103
|
name: "@lucid-evolution/provider",
|
|
104
|
-
version: "0.
|
|
104
|
+
version: "0.3.0",
|
|
105
105
|
description: "",
|
|
106
106
|
main: "./dist/index.js",
|
|
107
107
|
types: "./dist/index.d.ts",
|
|
@@ -562,7 +562,15 @@ var lucid = package_default.version;
|
|
|
562
562
|
// src/kupmios.ts
|
|
563
563
|
import { applyDoubleCborEncoding as applyDoubleCborEncoding2, fromUnit as fromUnit2 } from "@lucid-evolution/utils";
|
|
564
564
|
import { Schema as S3 } from "effect";
|
|
565
|
-
import {
|
|
565
|
+
import {
|
|
566
|
+
Cause,
|
|
567
|
+
Effect as Effect2,
|
|
568
|
+
Exit,
|
|
569
|
+
Layer,
|
|
570
|
+
pipe as pipe3,
|
|
571
|
+
Array as _Array,
|
|
572
|
+
Schedule
|
|
573
|
+
} from "effect";
|
|
566
574
|
|
|
567
575
|
// src/internal/ogmios.ts
|
|
568
576
|
import { Schema as S } from "effect";
|
|
@@ -1029,6 +1037,7 @@ var Kupmios = class {
|
|
|
1029
1037
|
options;
|
|
1030
1038
|
requestTimeoutMs;
|
|
1031
1039
|
awaitTxTimeoutMs;
|
|
1040
|
+
httpLayer;
|
|
1032
1041
|
constructor(kupoUrl, ogmiosUrl, options = {}) {
|
|
1033
1042
|
this.kupoUrl = kupoUrl;
|
|
1034
1043
|
this.ogmiosUrl = ogmiosUrl;
|
|
@@ -1041,6 +1050,10 @@ var Kupmios = class {
|
|
|
1041
1050
|
"awaitTxTimeoutMs",
|
|
1042
1051
|
options.awaitTxTimeoutMs ?? DEFAULT_AWAIT_TX_TIMEOUT_MS
|
|
1043
1052
|
);
|
|
1053
|
+
this.httpLayer = options.fetchImpl === void 0 ? FetchHttpClient.layer : Layer.provide(
|
|
1054
|
+
FetchHttpClient.layer,
|
|
1055
|
+
Layer.succeed(FetchHttpClient.Fetch, options.fetchImpl)
|
|
1056
|
+
);
|
|
1044
1057
|
}
|
|
1045
1058
|
async getProtocolParameters() {
|
|
1046
1059
|
const data = {
|
|
@@ -1062,7 +1075,7 @@ var Kupmios = class {
|
|
|
1062
1075
|
),
|
|
1063
1076
|
Effect2.timeout(this.requestTimeoutMs),
|
|
1064
1077
|
catchProviderError("ogmios", "queryLedgerState/protocolParameters"),
|
|
1065
|
-
Effect2.provide(
|
|
1078
|
+
Effect2.provide(this.httpLayer)
|
|
1066
1079
|
),
|
|
1067
1080
|
"ogmios",
|
|
1068
1081
|
"queryLedgerState/protocolParameters"
|
|
@@ -1097,7 +1110,7 @@ var Kupmios = class {
|
|
|
1097
1110
|
),
|
|
1098
1111
|
Effect2.timeout(this.requestTimeoutMs),
|
|
1099
1112
|
catchProviderError("ogmios", "queryLedgerState/treasuryAndReserves"),
|
|
1100
|
-
Effect2.provide(
|
|
1113
|
+
Effect2.provide(this.httpLayer)
|
|
1101
1114
|
),
|
|
1102
1115
|
"ogmios",
|
|
1103
1116
|
"queryLedgerState/treasuryAndReserves"
|
|
@@ -1120,7 +1133,7 @@ var Kupmios = class {
|
|
|
1120
1133
|
Effect2.map(kupmiosUtxosToUtxos),
|
|
1121
1134
|
Effect2.timeout(this.requestTimeoutMs),
|
|
1122
1135
|
catchProviderError("kupo", "getUtxos"),
|
|
1123
|
-
Effect2.provide(
|
|
1136
|
+
Effect2.provide(this.httpLayer)
|
|
1124
1137
|
),
|
|
1125
1138
|
"kupo",
|
|
1126
1139
|
"getUtxos"
|
|
@@ -1139,7 +1152,7 @@ var Kupmios = class {
|
|
|
1139
1152
|
Effect2.map(kupmiosUtxosToUtxos),
|
|
1140
1153
|
Effect2.timeout(this.requestTimeoutMs),
|
|
1141
1154
|
catchProviderError("kupo", "getUtxosWithUnit"),
|
|
1142
|
-
Effect2.provide(
|
|
1155
|
+
Effect2.provide(this.httpLayer)
|
|
1143
1156
|
),
|
|
1144
1157
|
"kupo",
|
|
1145
1158
|
"getUtxosWithUnit"
|
|
@@ -1163,7 +1176,7 @@ var Kupmios = class {
|
|
|
1163
1176
|
Effect2.map(kupmiosUtxosToUtxos),
|
|
1164
1177
|
Effect2.timeout(this.requestTimeoutMs),
|
|
1165
1178
|
catchProviderError("kupo", "getUtxosWithPolicy"),
|
|
1166
|
-
Effect2.provide(
|
|
1179
|
+
Effect2.provide(this.httpLayer)
|
|
1167
1180
|
),
|
|
1168
1181
|
"kupo",
|
|
1169
1182
|
"getUtxosWithPolicy"
|
|
@@ -1179,7 +1192,7 @@ var Kupmios = class {
|
|
|
1179
1192
|
Effect2.map(kupmiosUtxosToUtxos),
|
|
1180
1193
|
Effect2.timeout(this.requestTimeoutMs),
|
|
1181
1194
|
catchProviderError("kupo", "getUtxoByUnit"),
|
|
1182
|
-
Effect2.provide(
|
|
1195
|
+
Effect2.provide(this.httpLayer)
|
|
1183
1196
|
),
|
|
1184
1197
|
"kupo",
|
|
1185
1198
|
"getUtxoByUnit"
|
|
@@ -1208,7 +1221,7 @@ var Kupmios = class {
|
|
|
1208
1221
|
)
|
|
1209
1222
|
);
|
|
1210
1223
|
const utxos = await runProviderEffect(
|
|
1211
|
-
pipe3(program, Effect2.provide(
|
|
1224
|
+
pipe3(program, Effect2.provide(this.httpLayer)),
|
|
1212
1225
|
"kupo",
|
|
1213
1226
|
"getUtxosByOutRef"
|
|
1214
1227
|
);
|
|
@@ -1234,7 +1247,7 @@ var Kupmios = class {
|
|
|
1234
1247
|
schema,
|
|
1235
1248
|
this.options.ogmiosHeader
|
|
1236
1249
|
),
|
|
1237
|
-
Effect2.provide(
|
|
1250
|
+
Effect2.provide(this.httpLayer),
|
|
1238
1251
|
Effect2.timeout(this.requestTimeoutMs),
|
|
1239
1252
|
catchProviderError("ogmios", "queryLedgerState/rewardAccountSummaries")
|
|
1240
1253
|
),
|
|
@@ -1258,7 +1271,7 @@ var Kupmios = class {
|
|
|
1258
1271
|
const result = await runProviderEffect(
|
|
1259
1272
|
pipe3(
|
|
1260
1273
|
makeGet(pattern, schema, this.options.kupoHeader),
|
|
1261
|
-
Effect2.provide(
|
|
1274
|
+
Effect2.provide(this.httpLayer),
|
|
1262
1275
|
Effect2.timeout(this.requestTimeoutMs),
|
|
1263
1276
|
Effect2.flatMap(Effect2.fromNullable),
|
|
1264
1277
|
catchProviderError("kupo", "getDatum")
|
|
@@ -1278,7 +1291,7 @@ var Kupmios = class {
|
|
|
1278
1291
|
makeGet(pattern, schema, this.options.kupoHeader),
|
|
1279
1292
|
Effect2.timeout(this.requestTimeoutMs),
|
|
1280
1293
|
catchProviderError("kupo", "getTransactionStatus"),
|
|
1281
|
-
Effect2.provide(
|
|
1294
|
+
Effect2.provide(this.httpLayer)
|
|
1282
1295
|
),
|
|
1283
1296
|
"kupo",
|
|
1284
1297
|
"getTransactionStatus",
|
|
@@ -1304,7 +1317,7 @@ var Kupmios = class {
|
|
|
1304
1317
|
const result = await runProviderEffect(
|
|
1305
1318
|
pipe3(
|
|
1306
1319
|
makeGet(pattern, schema, this.options.kupoHeader),
|
|
1307
|
-
Effect2.provide(
|
|
1320
|
+
Effect2.provide(this.httpLayer),
|
|
1308
1321
|
Effect2.repeat({
|
|
1309
1322
|
schedule: Schedule.exponential(checkInterval),
|
|
1310
1323
|
until: (result2) => result2.length > 0
|
|
@@ -1342,7 +1355,7 @@ var Kupmios = class {
|
|
|
1342
1355
|
schema,
|
|
1343
1356
|
this.options.ogmiosHeader
|
|
1344
1357
|
),
|
|
1345
|
-
Effect2.provide(
|
|
1358
|
+
Effect2.provide(this.httpLayer),
|
|
1346
1359
|
Effect2.timeout(this.requestTimeoutMs),
|
|
1347
1360
|
catchProviderError("ogmios", "submitTransaction")
|
|
1348
1361
|
),
|
|
@@ -1375,7 +1388,7 @@ var Kupmios = class {
|
|
|
1375
1388
|
schema,
|
|
1376
1389
|
this.options.ogmiosHeader
|
|
1377
1390
|
),
|
|
1378
|
-
Effect2.provide(
|
|
1391
|
+
Effect2.provide(this.httpLayer),
|
|
1379
1392
|
Effect2.timeout(this.requestTimeoutMs),
|
|
1380
1393
|
catchProviderError("ogmios", "evaluateTransaction")
|
|
1381
1394
|
),
|
|
@@ -1486,9 +1499,210 @@ import {
|
|
|
1486
1499
|
generateSeedPhrase,
|
|
1487
1500
|
PROTOCOL_PARAMETERS_DEFAULT
|
|
1488
1501
|
} from "@lucid-evolution/utils";
|
|
1489
|
-
import {
|
|
1490
|
-
|
|
1502
|
+
import {
|
|
1503
|
+
coreToUtxo,
|
|
1504
|
+
getAddressDetails as getAddressDetails2,
|
|
1505
|
+
ScriptCache,
|
|
1506
|
+
valueToAssets
|
|
1507
|
+
} from "@lucid-evolution/utils";
|
|
1508
|
+
import { fromHex as fromHex2, withCMLScope } from "@lucid-evolution/core-utils";
|
|
1491
1509
|
import { walletFromSeed } from "@lucid-evolution/wallet";
|
|
1510
|
+
|
|
1511
|
+
// src/internal/emulator-ledger.ts
|
|
1512
|
+
import { getAddressDetails } from "@lucid-evolution/utils";
|
|
1513
|
+
var isUnorderedKey = (key) => {
|
|
1514
|
+
if (key === "__proto__") return true;
|
|
1515
|
+
if (key.length > 10) return false;
|
|
1516
|
+
const index = Number(key);
|
|
1517
|
+
return Number.isInteger(index) && index < 2 ** 32 - 1 && String(index) === key;
|
|
1518
|
+
};
|
|
1519
|
+
var EmulatorLedger = class {
|
|
1520
|
+
#record = {};
|
|
1521
|
+
#exposed = false;
|
|
1522
|
+
/** Record keys in record order; `undefined` marks a deleted slot. */
|
|
1523
|
+
#keys = [];
|
|
1524
|
+
/** Record entries, parallel to `#keys`. */
|
|
1525
|
+
#entries = [];
|
|
1526
|
+
#slots = /* @__PURE__ */ new Map();
|
|
1527
|
+
#holes = 0;
|
|
1528
|
+
/** Per slot, the address whose payment hash `#slotHashes` holds. */
|
|
1529
|
+
#slotHashAddresses = [];
|
|
1530
|
+
#slotHashes = [];
|
|
1531
|
+
#paymentHashes = /* @__PURE__ */ new Map();
|
|
1532
|
+
/** The record, for internal reads that do not let it escape. */
|
|
1533
|
+
get record() {
|
|
1534
|
+
return this.#record;
|
|
1535
|
+
}
|
|
1536
|
+
/** Returns the record to a caller, who may then change it at any time. */
|
|
1537
|
+
expose() {
|
|
1538
|
+
this.#dropMirror();
|
|
1539
|
+
return this.#record;
|
|
1540
|
+
}
|
|
1541
|
+
/** Adopts a record supplied by a caller. */
|
|
1542
|
+
replace(record) {
|
|
1543
|
+
this.#record = record;
|
|
1544
|
+
this.#dropMirror();
|
|
1545
|
+
}
|
|
1546
|
+
get(outRef) {
|
|
1547
|
+
return this.#record[outRef];
|
|
1548
|
+
}
|
|
1549
|
+
set(outRef, entry) {
|
|
1550
|
+
this.#record[outRef] = entry;
|
|
1551
|
+
if (this.#exposed) return;
|
|
1552
|
+
if (isUnorderedKey(outRef)) {
|
|
1553
|
+
this.#dropMirror();
|
|
1554
|
+
return;
|
|
1555
|
+
}
|
|
1556
|
+
const slot = this.#slots.get(outRef);
|
|
1557
|
+
if (slot === void 0) {
|
|
1558
|
+
this.#slots.set(outRef, this.#keys.length);
|
|
1559
|
+
this.#keys.push(outRef);
|
|
1560
|
+
this.#entries.push(entry);
|
|
1561
|
+
this.#slotHashAddresses.push(void 0);
|
|
1562
|
+
this.#slotHashes.push(void 0);
|
|
1563
|
+
} else {
|
|
1564
|
+
this.#entries[slot] = entry;
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
/**
|
|
1568
|
+
* Moves the mempool into the record, then deletes every entry marked
|
|
1569
|
+
* spent, as the emulator always has.
|
|
1570
|
+
*/
|
|
1571
|
+
applyMempool(mempool) {
|
|
1572
|
+
for (const [outRef, { utxo, spent }] of Object.entries(mempool)) {
|
|
1573
|
+
this.set(outRef, { utxo, spent });
|
|
1574
|
+
}
|
|
1575
|
+
const record = this.#record;
|
|
1576
|
+
if (this.#exposed) {
|
|
1577
|
+
for (const [outRef, { spent }] of Object.entries(record)) {
|
|
1578
|
+
if (spent) delete record[outRef];
|
|
1579
|
+
}
|
|
1580
|
+
return;
|
|
1581
|
+
}
|
|
1582
|
+
const keys = this.#keys;
|
|
1583
|
+
const entries = this.#entries;
|
|
1584
|
+
for (let slot = 0; slot < entries.length; slot++) {
|
|
1585
|
+
const entry = entries[slot];
|
|
1586
|
+
if (entry === void 0 || !entry.spent) continue;
|
|
1587
|
+
const outRef = keys[slot];
|
|
1588
|
+
delete record[outRef];
|
|
1589
|
+
this.#slots.delete(outRef);
|
|
1590
|
+
keys[slot] = void 0;
|
|
1591
|
+
entries[slot] = void 0;
|
|
1592
|
+
this.#holes++;
|
|
1593
|
+
}
|
|
1594
|
+
if (this.#holes > 64 && this.#holes * 2 > entries.length) this.#compact();
|
|
1595
|
+
}
|
|
1596
|
+
/**
|
|
1597
|
+
* Unspent UTxOs at an address or payment credential, optionally holding
|
|
1598
|
+
* `unit`, in record order.
|
|
1599
|
+
*/
|
|
1600
|
+
utxosAt(addressOrCredential, unit) {
|
|
1601
|
+
const utxos = [];
|
|
1602
|
+
const entries = this.#inOrder();
|
|
1603
|
+
if (typeof addressOrCredential === "string") {
|
|
1604
|
+
for (let i = 0; i < entries.length; i++) {
|
|
1605
|
+
const entry = entries[i];
|
|
1606
|
+
if (entry === void 0 && !this.#exposed) continue;
|
|
1607
|
+
const { utxo, spent } = entry;
|
|
1608
|
+
if (!spent && utxo.address === addressOrCredential && (unit === void 0 || utxo.assets[unit] > 0n)) {
|
|
1609
|
+
utxos.push(utxo);
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
return utxos;
|
|
1613
|
+
}
|
|
1614
|
+
const hash = addressOrCredential.hash;
|
|
1615
|
+
const hashAddresses = this.#slotHashAddresses;
|
|
1616
|
+
const hashes = this.#slotHashes;
|
|
1617
|
+
for (let i = 0; i < entries.length; i++) {
|
|
1618
|
+
const entry = entries[i];
|
|
1619
|
+
if (entry === void 0 && !this.#exposed) continue;
|
|
1620
|
+
const { utxo, spent } = entry;
|
|
1621
|
+
if (spent) continue;
|
|
1622
|
+
const address = utxo.address;
|
|
1623
|
+
let paymentHash;
|
|
1624
|
+
if (this.#exposed) {
|
|
1625
|
+
paymentHash = this.#paymentHashOf(address);
|
|
1626
|
+
} else if (hashAddresses[i] === address) {
|
|
1627
|
+
paymentHash = hashes[i];
|
|
1628
|
+
} else {
|
|
1629
|
+
paymentHash = this.#paymentHashOf(address);
|
|
1630
|
+
hashAddresses[i] = address;
|
|
1631
|
+
hashes[i] = paymentHash;
|
|
1632
|
+
}
|
|
1633
|
+
if (paymentHash === hash && (unit === void 0 || utxo.assets[unit] > 0n)) {
|
|
1634
|
+
utxos.push(utxo);
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
return utxos;
|
|
1638
|
+
}
|
|
1639
|
+
/** Unspent UTxOs holding `unit`, in record order. */
|
|
1640
|
+
utxosWithUnit(unit) {
|
|
1641
|
+
const utxos = [];
|
|
1642
|
+
const entries = this.#inOrder();
|
|
1643
|
+
for (let i = 0; i < entries.length; i++) {
|
|
1644
|
+
const entry = entries[i];
|
|
1645
|
+
if (entry === void 0 && !this.#exposed) continue;
|
|
1646
|
+
const { utxo, spent } = entry;
|
|
1647
|
+
if (!spent && utxo.assets[unit] > 0n) utxos.push(utxo);
|
|
1648
|
+
}
|
|
1649
|
+
return utxos;
|
|
1650
|
+
}
|
|
1651
|
+
/**
|
|
1652
|
+
* The record's entries in record order. From the mirror, deleted slots
|
|
1653
|
+
* are `undefined`; from an exposed record, every value is as stored, so a
|
|
1654
|
+
* malformed entry fails a query just as a scan of the record would.
|
|
1655
|
+
*/
|
|
1656
|
+
#inOrder() {
|
|
1657
|
+
if (!this.#exposed) return this.#entries;
|
|
1658
|
+
const record = this.#record;
|
|
1659
|
+
const keys = Object.keys(record);
|
|
1660
|
+
const entries = new Array(keys.length);
|
|
1661
|
+
for (let i = 0; i < keys.length; i++) entries[i] = record[keys[i]];
|
|
1662
|
+
return entries;
|
|
1663
|
+
}
|
|
1664
|
+
/** Payment credential hash of an address; parse errors propagate. */
|
|
1665
|
+
#paymentHashOf(address) {
|
|
1666
|
+
if (this.#paymentHashes.has(address))
|
|
1667
|
+
return this.#paymentHashes.get(address);
|
|
1668
|
+
const hash = getAddressDetails(address).paymentCredential?.hash;
|
|
1669
|
+
this.#paymentHashes.set(address, hash);
|
|
1670
|
+
return hash;
|
|
1671
|
+
}
|
|
1672
|
+
#compact() {
|
|
1673
|
+
const keys = [];
|
|
1674
|
+
const entries = [];
|
|
1675
|
+
const hashAddresses = [];
|
|
1676
|
+
const hashes = [];
|
|
1677
|
+
this.#slots.clear();
|
|
1678
|
+
for (let slot = 0; slot < this.#entries.length; slot++) {
|
|
1679
|
+
const entry = this.#entries[slot];
|
|
1680
|
+
if (entry === void 0) continue;
|
|
1681
|
+
const outRef = this.#keys[slot];
|
|
1682
|
+
this.#slots.set(outRef, keys.length);
|
|
1683
|
+
keys.push(outRef);
|
|
1684
|
+
entries.push(entry);
|
|
1685
|
+
hashAddresses.push(this.#slotHashAddresses[slot]);
|
|
1686
|
+
hashes.push(this.#slotHashes[slot]);
|
|
1687
|
+
}
|
|
1688
|
+
this.#keys = keys;
|
|
1689
|
+
this.#entries = entries;
|
|
1690
|
+
this.#slotHashAddresses = hashAddresses;
|
|
1691
|
+
this.#slotHashes = hashes;
|
|
1692
|
+
this.#holes = 0;
|
|
1693
|
+
}
|
|
1694
|
+
#dropMirror() {
|
|
1695
|
+
this.#exposed = true;
|
|
1696
|
+
this.#keys = [];
|
|
1697
|
+
this.#entries = [];
|
|
1698
|
+
this.#slots.clear();
|
|
1699
|
+
this.#slotHashAddresses = [];
|
|
1700
|
+
this.#slotHashes = [];
|
|
1701
|
+
this.#holes = 0;
|
|
1702
|
+
}
|
|
1703
|
+
};
|
|
1704
|
+
|
|
1705
|
+
// src/emulator.ts
|
|
1492
1706
|
var EMULATOR_PROVIDER_BRAND = Symbol.for(
|
|
1493
1707
|
"@lucid-evolution/provider/Emulator"
|
|
1494
1708
|
);
|
|
@@ -1526,7 +1740,13 @@ function generateEmulatorAccount(assets) {
|
|
|
1526
1740
|
var DEFAULT_PROTOCOL_MAJOR_VERSION = 11;
|
|
1527
1741
|
var Emulator = class {
|
|
1528
1742
|
[EMULATOR_PROVIDER_BRAND] = true;
|
|
1529
|
-
|
|
1743
|
+
#confirmed = new EmulatorLedger();
|
|
1744
|
+
#ledgerProperty = Object.defineProperty(this, "ledger", {
|
|
1745
|
+
configurable: true,
|
|
1746
|
+
enumerable: true,
|
|
1747
|
+
get: () => this.#confirmed.expose(),
|
|
1748
|
+
set: (entries) => this.#confirmed.replace(entries)
|
|
1749
|
+
});
|
|
1530
1750
|
mempool = {};
|
|
1531
1751
|
/**
|
|
1532
1752
|
* Only stake key registrations/delegations and rewards are tracked.
|
|
@@ -1539,13 +1759,37 @@ var Emulator = class {
|
|
|
1539
1759
|
protocolParameters;
|
|
1540
1760
|
datumTable = {};
|
|
1541
1761
|
treasury;
|
|
1542
|
-
|
|
1762
|
+
#history = {};
|
|
1763
|
+
/** Whether a caller holds `transactionHistory`, and may edit it. */
|
|
1764
|
+
#historyExposed = false;
|
|
1765
|
+
#historyProperty = Object.defineProperty(this, "transactionHistory", {
|
|
1766
|
+
configurable: true,
|
|
1767
|
+
enumerable: true,
|
|
1768
|
+
get: () => {
|
|
1769
|
+
this.#historyExposed = true;
|
|
1770
|
+
return this.#history;
|
|
1771
|
+
},
|
|
1772
|
+
set: (history) => {
|
|
1773
|
+
this.#historyExposed = true;
|
|
1774
|
+
this.#history = history;
|
|
1775
|
+
}
|
|
1776
|
+
});
|
|
1777
|
+
/**
|
|
1778
|
+
* Transactions submitted since the last block. While no caller holds
|
|
1779
|
+
* `transactionHistory`, these are its only pending entries.
|
|
1780
|
+
*/
|
|
1781
|
+
#pendingTxHashes = [];
|
|
1782
|
+
/**
|
|
1783
|
+
* Script hashes of reference scripts, keyed by type and CBOR. A plain Map
|
|
1784
|
+
* keyed by long script text puts every script of the same length in one
|
|
1785
|
+
* hash bucket; `ScriptCache` keys a fingerprint and is bounded.
|
|
1786
|
+
*/
|
|
1787
|
+
#scriptRefHashes = new ScriptCache(4096, 64 * 1024 * 1024);
|
|
1543
1788
|
constructor(accounts, protocolParameters = PROTOCOL_PARAMETERS_DEFAULT, treasury = 0n) {
|
|
1544
1789
|
const GENESIS_HASH = "00".repeat(32);
|
|
1545
1790
|
this.blockHeight = 0;
|
|
1546
1791
|
this.slot = 0;
|
|
1547
1792
|
this.time = Date.now();
|
|
1548
|
-
this.ledger = {};
|
|
1549
1793
|
accounts.forEach(({ address, assets, outputData }, index) => {
|
|
1550
1794
|
if ([outputData?.hash, outputData?.asHash, outputData?.inline].filter(
|
|
1551
1795
|
(b) => b
|
|
@@ -1554,7 +1798,7 @@ var Emulator = class {
|
|
|
1554
1798
|
"Not allowed to set hash, asHash and inline at the same time."
|
|
1555
1799
|
);
|
|
1556
1800
|
}
|
|
1557
|
-
this.
|
|
1801
|
+
this.#confirmed.set(GENESIS_HASH + index, {
|
|
1558
1802
|
utxo: {
|
|
1559
1803
|
txHash: GENESIS_HASH,
|
|
1560
1804
|
outputIndex: index,
|
|
@@ -1567,7 +1811,7 @@ var Emulator = class {
|
|
|
1567
1811
|
scriptRef: outputData?.scriptRef
|
|
1568
1812
|
},
|
|
1569
1813
|
spent: false
|
|
1570
|
-
};
|
|
1814
|
+
});
|
|
1571
1815
|
});
|
|
1572
1816
|
this.protocolParameters = protocolParameters;
|
|
1573
1817
|
this.treasury = treasury;
|
|
@@ -1575,16 +1819,28 @@ var Emulator = class {
|
|
|
1575
1819
|
now() {
|
|
1576
1820
|
return this.time;
|
|
1577
1821
|
}
|
|
1822
|
+
/** Confirms every pending transaction in `transactionHistory`. */
|
|
1578
1823
|
confirmPendingTransactions(blockHeight, slot) {
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
blockHeight,
|
|
1584
|
-
|
|
1585
|
-
|
|
1824
|
+
const history = this.#history;
|
|
1825
|
+
if (this.#historyExposed) {
|
|
1826
|
+
for (const [txHash, { status }] of Object.entries(history)) {
|
|
1827
|
+
if (status === "pending") {
|
|
1828
|
+
history[txHash] = { status: "confirmed", blockHeight, slot };
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1831
|
+
} else {
|
|
1832
|
+
for (const txHash of this.#pendingTxHashes) {
|
|
1833
|
+
if (history[txHash].status === "pending") {
|
|
1834
|
+
history[txHash] = { status: "confirmed", blockHeight, slot };
|
|
1835
|
+
}
|
|
1586
1836
|
}
|
|
1587
1837
|
}
|
|
1838
|
+
this.#pendingTxHashes = [];
|
|
1839
|
+
}
|
|
1840
|
+
/** Moves the mempool into the ledger and drops spent entries. */
|
|
1841
|
+
applyMempool() {
|
|
1842
|
+
this.#confirmed.applyMempool(this.mempool);
|
|
1843
|
+
this.mempool = {};
|
|
1588
1844
|
}
|
|
1589
1845
|
awaitSlot(length = 1) {
|
|
1590
1846
|
this.slot += length;
|
|
@@ -1596,13 +1852,7 @@ var Emulator = class {
|
|
|
1596
1852
|
currentHeight + 1,
|
|
1597
1853
|
(currentHeight + 1) * 20
|
|
1598
1854
|
);
|
|
1599
|
-
|
|
1600
|
-
this.ledger[outRef] = { utxo, spent };
|
|
1601
|
-
}
|
|
1602
|
-
for (const [outRef, { spent }] of Object.entries(this.ledger)) {
|
|
1603
|
-
if (spent) delete this.ledger[outRef];
|
|
1604
|
-
}
|
|
1605
|
-
this.mempool = {};
|
|
1855
|
+
this.applyMempool();
|
|
1606
1856
|
}
|
|
1607
1857
|
}
|
|
1608
1858
|
awaitBlock(height = 1) {
|
|
@@ -1614,27 +1864,10 @@ var Emulator = class {
|
|
|
1614
1864
|
if (height > 0) {
|
|
1615
1865
|
this.confirmPendingTransactions(previousHeight + 1, previousSlot + 20);
|
|
1616
1866
|
}
|
|
1617
|
-
|
|
1618
|
-
this.ledger[outRef] = { utxo, spent };
|
|
1619
|
-
}
|
|
1620
|
-
for (const [outRef, { spent }] of Object.entries(this.ledger)) {
|
|
1621
|
-
if (spent) delete this.ledger[outRef];
|
|
1622
|
-
}
|
|
1623
|
-
this.mempool = {};
|
|
1867
|
+
this.applyMempool();
|
|
1624
1868
|
}
|
|
1625
1869
|
getUtxos(addressOrCredential) {
|
|
1626
|
-
|
|
1627
|
-
({ utxo, spent }) => {
|
|
1628
|
-
if (spent) return [];
|
|
1629
|
-
if (typeof addressOrCredential === "string") {
|
|
1630
|
-
return addressOrCredential === utxo.address ? utxo : [];
|
|
1631
|
-
} else {
|
|
1632
|
-
const { paymentCredential } = getAddressDetails(utxo.address);
|
|
1633
|
-
return paymentCredential?.hash === addressOrCredential.hash ? utxo : [];
|
|
1634
|
-
}
|
|
1635
|
-
}
|
|
1636
|
-
);
|
|
1637
|
-
return Promise.resolve(utxos);
|
|
1870
|
+
return Promise.resolve(this.#confirmed.utxosAt(addressOrCredential));
|
|
1638
1871
|
}
|
|
1639
1872
|
getProtocolParameters() {
|
|
1640
1873
|
return Promise.resolve(this.protocolParameters);
|
|
@@ -1646,31 +1879,18 @@ var Emulator = class {
|
|
|
1646
1879
|
return Promise.resolve(this.datumTable[datumHash]);
|
|
1647
1880
|
}
|
|
1648
1881
|
getUtxosWithUnit(addressOrCredential, unit) {
|
|
1649
|
-
|
|
1650
|
-
({ utxo, spent }) => {
|
|
1651
|
-
if (spent) return [];
|
|
1652
|
-
if (typeof addressOrCredential === "string") {
|
|
1653
|
-
return addressOrCredential === utxo.address && utxo.assets[unit] > 0n ? utxo : [];
|
|
1654
|
-
} else {
|
|
1655
|
-
const { paymentCredential } = getAddressDetails(utxo.address);
|
|
1656
|
-
return paymentCredential?.hash === addressOrCredential.hash && utxo.assets[unit] > 0n ? utxo : [];
|
|
1657
|
-
}
|
|
1658
|
-
}
|
|
1659
|
-
);
|
|
1660
|
-
return Promise.resolve(utxos);
|
|
1882
|
+
return Promise.resolve(this.#confirmed.utxosAt(addressOrCredential, unit));
|
|
1661
1883
|
}
|
|
1662
1884
|
getUtxosByOutRef(outRefs) {
|
|
1663
1885
|
return Promise.resolve(
|
|
1664
1886
|
outRefs.flatMap((outRef) => {
|
|
1665
|
-
const entry = this.
|
|
1887
|
+
const entry = this.#confirmed.get(outRef.txHash + outRef.outputIndex);
|
|
1666
1888
|
return entry && !entry.spent ? entry.utxo : [];
|
|
1667
1889
|
})
|
|
1668
1890
|
);
|
|
1669
1891
|
}
|
|
1670
1892
|
getUtxoByUnit(unit) {
|
|
1671
|
-
const utxos =
|
|
1672
|
-
({ utxo, spent }) => !spent && utxo.assets[unit] > 0n ? utxo : []
|
|
1673
|
-
);
|
|
1893
|
+
const utxos = this.#confirmed.utxosWithUnit(unit);
|
|
1674
1894
|
if (utxos.length > 1) {
|
|
1675
1895
|
throw new Error("Unit needs to be an NFT or only held by one address.");
|
|
1676
1896
|
}
|
|
@@ -1691,7 +1911,7 @@ var Emulator = class {
|
|
|
1691
1911
|
});
|
|
1692
1912
|
}
|
|
1693
1913
|
awaitTx(txHash) {
|
|
1694
|
-
if (this
|
|
1914
|
+
if (this.#history[txHash]?.status === "pending") {
|
|
1695
1915
|
this.awaitBlock();
|
|
1696
1916
|
return Promise.resolve(true);
|
|
1697
1917
|
}
|
|
@@ -1703,7 +1923,7 @@ var Emulator = class {
|
|
|
1703
1923
|
options.signal.reason instanceof Error ? options.signal.reason : new DOMException("The operation was aborted.", "AbortError")
|
|
1704
1924
|
);
|
|
1705
1925
|
}
|
|
1706
|
-
const status = this
|
|
1926
|
+
const status = this.#history[txHash];
|
|
1707
1927
|
if (!status) return Promise.resolve({ status: "not_found", txHash });
|
|
1708
1928
|
if (status.status === "pending") {
|
|
1709
1929
|
return Promise.resolve({ status: "pending", txHash });
|
|
@@ -1741,10 +1961,14 @@ var Emulator = class {
|
|
|
1741
1961
|
this.awaitBlock();
|
|
1742
1962
|
}
|
|
1743
1963
|
submitTx(tx) {
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1964
|
+
return withCMLScope((own) => Promise.resolve(this.applyTx(tx, own)));
|
|
1965
|
+
}
|
|
1966
|
+
/** Validates `tx` and applies it to the mempool; returns its hash. */
|
|
1967
|
+
applyTx(tx, own) {
|
|
1968
|
+
const desTx = own(CML.Transaction.from_cbor_hex(tx));
|
|
1969
|
+
const body = own(desTx.body());
|
|
1970
|
+
const witnesses = own(desTx.witness_set());
|
|
1971
|
+
const datums = own(witnesses.plutus_datums());
|
|
1748
1972
|
const txHash = CML.hash_transaction(body).to_hex();
|
|
1749
1973
|
const lowerBound = body.validity_interval_start() ? parseInt(body.validity_interval_start().toString()) : null;
|
|
1750
1974
|
const upperBound = body.ttl() ? parseInt(body.ttl().toString()) : null;
|
|
@@ -1778,24 +2002,24 @@ var Emulator = class {
|
|
|
1778
2002
|
const datumTable = (() => {
|
|
1779
2003
|
const table = {};
|
|
1780
2004
|
for (let i = 0; i < (datums?.len() || 0); i++) {
|
|
1781
|
-
withCMLScope((
|
|
1782
|
-
const datum =
|
|
1783
|
-
const datumHash =
|
|
2005
|
+
withCMLScope((own2) => {
|
|
2006
|
+
const datum = own2(datums.get(i));
|
|
2007
|
+
const datumHash = own2(CML.hash_plutus_data(datum)).to_hex();
|
|
1784
2008
|
table[datumHash] = datum.to_cbor_hex();
|
|
1785
2009
|
});
|
|
1786
2010
|
}
|
|
1787
2011
|
return table;
|
|
1788
2012
|
})();
|
|
1789
2013
|
const consumedHashes = /* @__PURE__ */ new Set();
|
|
1790
|
-
const
|
|
2014
|
+
const keyHashList = withCMLScope((own2) => {
|
|
1791
2015
|
const keyHashes2 = [];
|
|
1792
|
-
const vkeyWitnesses =
|
|
2016
|
+
const vkeyWitnesses = own2(witnesses.vkeywitnesses());
|
|
1793
2017
|
for (let i = 0; i < (vkeyWitnesses?.len() || 0); i++) {
|
|
1794
|
-
withCMLScope((
|
|
1795
|
-
const witness =
|
|
1796
|
-
const publicKey =
|
|
1797
|
-
const keyHash =
|
|
1798
|
-
if (!publicKey.verify(fromHex2(txHash),
|
|
2018
|
+
withCMLScope((own3) => {
|
|
2019
|
+
const witness = own3(vkeyWitnesses.get(i));
|
|
2020
|
+
const publicKey = own3(witness.vkey());
|
|
2021
|
+
const keyHash = own3(publicKey.hash()).to_hex();
|
|
2022
|
+
if (!publicKey.verify(fromHex2(txHash), own3(witness.ed25519_signature()))) {
|
|
1799
2023
|
throw new Error(`Invalid vkey witness. Key hash: ${keyHash}`);
|
|
1800
2024
|
}
|
|
1801
2025
|
keyHashes2.push(keyHash);
|
|
@@ -1803,19 +2027,20 @@ var Emulator = class {
|
|
|
1803
2027
|
}
|
|
1804
2028
|
return keyHashes2;
|
|
1805
2029
|
});
|
|
1806
|
-
const
|
|
1807
|
-
|
|
2030
|
+
const keyHashes = new Set(keyHashList);
|
|
2031
|
+
const edKeyHashes = own(CML.Ed25519KeyHashList.new());
|
|
2032
|
+
keyHashList.forEach(
|
|
1808
2033
|
(keyHash) => withCMLScope(
|
|
1809
|
-
(
|
|
2034
|
+
(own2) => edKeyHashes.add(own2(CML.Ed25519KeyHash.from_hex(keyHash)))
|
|
1810
2035
|
)
|
|
1811
2036
|
);
|
|
1812
|
-
const
|
|
2037
|
+
const nativeHashList = withCMLScope((own2) => {
|
|
1813
2038
|
const scriptHashes = [];
|
|
1814
|
-
const nativeScripts =
|
|
2039
|
+
const nativeScripts = own2(witnesses.native_scripts());
|
|
1815
2040
|
for (let i = 0; i < (nativeScripts?.len() || 0); i++) {
|
|
1816
|
-
withCMLScope((
|
|
1817
|
-
const witness =
|
|
1818
|
-
const scriptHash =
|
|
2041
|
+
withCMLScope((own3) => {
|
|
2042
|
+
const witness = own3(nativeScripts.get(i));
|
|
2043
|
+
const scriptHash = own3(witness.hash()).to_hex();
|
|
1819
2044
|
if (!witness.verify(
|
|
1820
2045
|
Number.isInteger(lowerBound) ? BigInt(lowerBound) : void 0,
|
|
1821
2046
|
Number.isInteger(upperBound) ? BigInt(upperBound) : void 0,
|
|
@@ -1825,9 +2050,9 @@ var Emulator = class {
|
|
|
1825
2050
|
`Invalid native script witness. Script hash: ${scriptHash}`
|
|
1826
2051
|
);
|
|
1827
2052
|
}
|
|
1828
|
-
const
|
|
1829
|
-
for (let j = 0; j <
|
|
1830
|
-
const keyHash =
|
|
2053
|
+
const requiredSigners2 = own3(witness.get_required_signers());
|
|
2054
|
+
for (let j = 0; j < requiredSigners2.len(); j++) {
|
|
2055
|
+
const keyHash = own3(requiredSigners2.get(j)).to_hex();
|
|
1831
2056
|
consumedHashes.add(keyHash);
|
|
1832
2057
|
}
|
|
1833
2058
|
scriptHashes.push(scriptHash);
|
|
@@ -1835,18 +2060,18 @@ var Emulator = class {
|
|
|
1835
2060
|
}
|
|
1836
2061
|
return scriptHashes;
|
|
1837
2062
|
});
|
|
1838
|
-
|
|
2063
|
+
const nativeHashes = new Set(nativeHashList);
|
|
1839
2064
|
const nativeHashesOptional = {};
|
|
1840
|
-
const plutusHashesOptional =
|
|
2065
|
+
const plutusHashesOptional = /* @__PURE__ */ new Set();
|
|
1841
2066
|
const plutusV3Hashes = /* @__PURE__ */ new Set();
|
|
1842
|
-
const
|
|
2067
|
+
const plutusHashList = withCMLScope((own2) => {
|
|
1843
2068
|
const scriptHashes = [];
|
|
1844
2069
|
const collectHashes = (scripts, isPlutusV3 = false) => {
|
|
1845
|
-
|
|
2070
|
+
own2(scripts);
|
|
1846
2071
|
for (let i = 0; i < (scripts?.len() || 0); i++) {
|
|
1847
|
-
withCMLScope((
|
|
1848
|
-
const script =
|
|
1849
|
-
const scriptHash =
|
|
2072
|
+
withCMLScope((own3) => {
|
|
2073
|
+
const script = own3(scripts.get(i));
|
|
2074
|
+
const scriptHash = own3(script.hash()).to_hex();
|
|
1850
2075
|
scriptHashes.push(scriptHash);
|
|
1851
2076
|
if (isPlutusV3) plutusV3Hashes.add(scriptHash);
|
|
1852
2077
|
});
|
|
@@ -1857,16 +2082,26 @@ var Emulator = class {
|
|
|
1857
2082
|
collectHashes(witnesses.plutus_v3_scripts(), true);
|
|
1858
2083
|
return scriptHashes;
|
|
1859
2084
|
});
|
|
1860
|
-
const
|
|
2085
|
+
const plutusHashes = new Set(plutusHashList);
|
|
2086
|
+
const collectScriptRef = (scriptRef) => {
|
|
2087
|
+
const scriptHash = this.scriptRefHash(scriptRef);
|
|
2088
|
+
if (scriptRef.type === "Native") {
|
|
2089
|
+
nativeHashesOptional[scriptHash] = scriptRef.script;
|
|
2090
|
+
return;
|
|
2091
|
+
}
|
|
2092
|
+
plutusHashesOptional.add(scriptHash);
|
|
2093
|
+
if (scriptRef.type === "PlutusV3") plutusV3Hashes.add(scriptHash);
|
|
2094
|
+
};
|
|
2095
|
+
const inputs = own(body.inputs());
|
|
1861
2096
|
const resolvedInputs = [];
|
|
1862
2097
|
const inputOutRefs = /* @__PURE__ */ new Set();
|
|
1863
2098
|
for (let i = 0; i < inputs.len(); i++) {
|
|
1864
|
-
const outRef = withCMLScope((
|
|
1865
|
-
const input =
|
|
1866
|
-
return
|
|
2099
|
+
const outRef = withCMLScope((own2) => {
|
|
2100
|
+
const input = own2(inputs.get(i));
|
|
2101
|
+
return own2(input.transaction_id()).to_hex() + input.index().toString();
|
|
1867
2102
|
});
|
|
1868
2103
|
inputOutRefs.add(outRef);
|
|
1869
|
-
const entryLedger = this.
|
|
2104
|
+
const entryLedger = this.#confirmed.get(outRef);
|
|
1870
2105
|
const { entry, type } = !entryLedger ? { entry: this.mempool[outRef], type: "Mempool" } : { entry: entryLedger, type: "Ledger" };
|
|
1871
2106
|
if (!entry || entry.spent) {
|
|
1872
2107
|
throw new Error(
|
|
@@ -1878,52 +2113,18 @@ It does not exist or was already spent.`
|
|
|
1878
2113
|
);
|
|
1879
2114
|
}
|
|
1880
2115
|
const scriptRef = entry.utxo.scriptRef;
|
|
1881
|
-
if (scriptRef)
|
|
1882
|
-
switch (scriptRef.type) {
|
|
1883
|
-
case "Native": {
|
|
1884
|
-
const script = CML.NativeScript.from_cbor_bytes(
|
|
1885
|
-
fromHex2(scriptRef.script)
|
|
1886
|
-
);
|
|
1887
|
-
nativeHashesOptional[script.hash().to_hex()] = script;
|
|
1888
|
-
break;
|
|
1889
|
-
}
|
|
1890
|
-
case "PlutusV1": {
|
|
1891
|
-
const script = CML.PlutusScript.from_v1(
|
|
1892
|
-
CML.PlutusV1Script.from_cbor_bytes(fromHex2(scriptRef.script))
|
|
1893
|
-
);
|
|
1894
|
-
plutusHashesOptional.push(script.hash().to_hex());
|
|
1895
|
-
break;
|
|
1896
|
-
}
|
|
1897
|
-
case "PlutusV2": {
|
|
1898
|
-
const script = CML.PlutusScript.from_v2(
|
|
1899
|
-
CML.PlutusV2Script.from_cbor_bytes(fromHex2(scriptRef.script))
|
|
1900
|
-
);
|
|
1901
|
-
plutusHashesOptional.push(script.hash().to_hex());
|
|
1902
|
-
break;
|
|
1903
|
-
}
|
|
1904
|
-
case "PlutusV3": {
|
|
1905
|
-
const script = CML.PlutusScript.from_v3(
|
|
1906
|
-
CML.PlutusV3Script.from_cbor_bytes(fromHex2(scriptRef.script))
|
|
1907
|
-
);
|
|
1908
|
-
const scriptHash = script.hash().to_hex();
|
|
1909
|
-
plutusHashesOptional.push(scriptHash);
|
|
1910
|
-
plutusV3Hashes.add(scriptHash);
|
|
1911
|
-
break;
|
|
1912
|
-
}
|
|
1913
|
-
}
|
|
1914
|
-
}
|
|
2116
|
+
if (scriptRef) collectScriptRef(scriptRef);
|
|
1915
2117
|
if (entry.utxo.datumHash) consumedHashes.add(entry.utxo.datumHash);
|
|
1916
2118
|
resolvedInputs.push({ entry, type });
|
|
1917
2119
|
}
|
|
1918
|
-
|
|
1919
|
-
const referenceInputs = body.reference_inputs();
|
|
2120
|
+
const referenceInputs = own(body.reference_inputs());
|
|
1920
2121
|
const nonDisjointRefInputs = [];
|
|
1921
2122
|
for (let i = 0; i < (referenceInputs?.len() || 0); i++) {
|
|
1922
|
-
const outRef = withCMLScope((
|
|
1923
|
-
const input =
|
|
1924
|
-
return
|
|
2123
|
+
const outRef = withCMLScope((own2) => {
|
|
2124
|
+
const input = own2(referenceInputs.get(i));
|
|
2125
|
+
return own2(input.transaction_id()).to_hex() + input.index().toString();
|
|
1925
2126
|
});
|
|
1926
|
-
const entry = this.
|
|
2127
|
+
const entry = this.#confirmed.get(outRef) || this.mempool[outRef];
|
|
1927
2128
|
if (!entry || entry.spent) {
|
|
1928
2129
|
throw new Error(
|
|
1929
2130
|
`Could not read UTxO: ${JSON.stringify({
|
|
@@ -1939,44 +2140,11 @@ It does not exist or was already spent.`
|
|
|
1939
2140
|
);
|
|
1940
2141
|
}
|
|
1941
2142
|
const scriptRef = entry.utxo.scriptRef;
|
|
1942
|
-
if (scriptRef)
|
|
1943
|
-
switch (scriptRef.type) {
|
|
1944
|
-
case "Native": {
|
|
1945
|
-
const script = CML.NativeScript.from_cbor_bytes(
|
|
1946
|
-
fromHex2(scriptRef.script)
|
|
1947
|
-
);
|
|
1948
|
-
nativeHashesOptional[script.hash().to_hex()] = script;
|
|
1949
|
-
break;
|
|
1950
|
-
}
|
|
1951
|
-
case "PlutusV1": {
|
|
1952
|
-
const script = CML.PlutusScript.from_v1(
|
|
1953
|
-
CML.PlutusV1Script.from_cbor_bytes(fromHex2(scriptRef.script))
|
|
1954
|
-
);
|
|
1955
|
-
plutusHashesOptional.push(script.hash().to_hex());
|
|
1956
|
-
break;
|
|
1957
|
-
}
|
|
1958
|
-
case "PlutusV2": {
|
|
1959
|
-
const script = CML.PlutusScript.from_v2(
|
|
1960
|
-
CML.PlutusV2Script.from_cbor_bytes(fromHex2(scriptRef.script))
|
|
1961
|
-
);
|
|
1962
|
-
plutusHashesOptional.push(script.hash().to_hex());
|
|
1963
|
-
break;
|
|
1964
|
-
}
|
|
1965
|
-
case "PlutusV3": {
|
|
1966
|
-
const script = CML.PlutusScript.from_v3(
|
|
1967
|
-
CML.PlutusV3Script.from_cbor_bytes(fromHex2(scriptRef.script))
|
|
1968
|
-
);
|
|
1969
|
-
const scriptHash = script.hash().to_hex();
|
|
1970
|
-
plutusHashesOptional.push(scriptHash);
|
|
1971
|
-
plutusV3Hashes.add(scriptHash);
|
|
1972
|
-
break;
|
|
1973
|
-
}
|
|
1974
|
-
}
|
|
1975
|
-
}
|
|
2143
|
+
if (scriptRef) collectScriptRef(scriptRef);
|
|
1976
2144
|
if (entry.utxo.datumHash) consumedHashes.add(entry.utxo.datumHash);
|
|
1977
2145
|
}
|
|
1978
|
-
|
|
1979
|
-
const redeemers = (() => {
|
|
2146
|
+
const redeemerKey = (tag, index) => `${tag}:${index}`;
|
|
2147
|
+
const redeemers = withCMLScope((own2) => {
|
|
1980
2148
|
const tagMap = {
|
|
1981
2149
|
0: "Spend",
|
|
1982
2150
|
1: "Mint",
|
|
@@ -1985,35 +2153,33 @@ It does not exist or was already spent.`
|
|
|
1985
2153
|
4: "Proposing",
|
|
1986
2154
|
5: "Voting"
|
|
1987
2155
|
};
|
|
1988
|
-
const collected =
|
|
1989
|
-
const redeemers2 = witnesses.redeemers();
|
|
1990
|
-
const arrLegacyRedeemer = redeemers2?.as_arr_legacy_redeemer();
|
|
2156
|
+
const collected = /* @__PURE__ */ new Set();
|
|
2157
|
+
const redeemers2 = own2(witnesses.redeemers());
|
|
2158
|
+
const arrLegacyRedeemer = own2(redeemers2?.as_arr_legacy_redeemer());
|
|
1991
2159
|
if (arrLegacyRedeemer) {
|
|
1992
2160
|
for (let i = 0; i < (arrLegacyRedeemer.len() || 0); i++) {
|
|
1993
|
-
const redeemer = arrLegacyRedeemer.get(i);
|
|
1994
|
-
collected.
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
});
|
|
2161
|
+
const redeemer = own2(arrLegacyRedeemer.get(i));
|
|
2162
|
+
collected.add(
|
|
2163
|
+
redeemerKey(tagMap[redeemer.tag()], Number(redeemer.index()))
|
|
2164
|
+
);
|
|
1998
2165
|
}
|
|
1999
2166
|
}
|
|
2000
|
-
const mapRedeemerKeyToRedeemerVal =
|
|
2167
|
+
const mapRedeemerKeyToRedeemerVal = own2(
|
|
2168
|
+
redeemers2?.as_map_redeemer_key_to_redeemer_val()
|
|
2169
|
+
);
|
|
2001
2170
|
if (mapRedeemerKeyToRedeemerVal) {
|
|
2002
|
-
const keys = mapRedeemerKeyToRedeemerVal.keys();
|
|
2171
|
+
const keys = own2(mapRedeemerKeyToRedeemerVal.keys());
|
|
2003
2172
|
for (let i = 0; i < (keys.len() || 0); i++) {
|
|
2004
|
-
const key = keys.get(i);
|
|
2005
|
-
collected.
|
|
2006
|
-
tag: tagMap[key.tag()],
|
|
2007
|
-
index: Number(key.index())
|
|
2008
|
-
});
|
|
2173
|
+
const key = own2(keys.get(i));
|
|
2174
|
+
collected.add(redeemerKey(tagMap[key.tag()], Number(key.index())));
|
|
2009
2175
|
}
|
|
2010
2176
|
}
|
|
2011
2177
|
return collected;
|
|
2012
|
-
})
|
|
2178
|
+
});
|
|
2013
2179
|
function checkAndConsumeHash(credential, tag, index) {
|
|
2014
2180
|
switch (credential.type) {
|
|
2015
2181
|
case "Key": {
|
|
2016
|
-
if (!keyHashes.
|
|
2182
|
+
if (!keyHashes.has(credential.hash)) {
|
|
2017
2183
|
throw new Error(
|
|
2018
2184
|
`Missing vkey witness. Key hash: ${credential.hash}`
|
|
2019
2185
|
);
|
|
@@ -2022,28 +2188,29 @@ It does not exist or was already spent.`
|
|
|
2022
2188
|
break;
|
|
2023
2189
|
}
|
|
2024
2190
|
case "Script": {
|
|
2025
|
-
if (nativeHashes.
|
|
2191
|
+
if (nativeHashes.has(credential.hash)) {
|
|
2026
2192
|
consumedHashes.add(credential.hash);
|
|
2027
2193
|
break;
|
|
2028
2194
|
} else if (nativeHashesOptional[credential.hash]) {
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2195
|
+
const valid = withCMLScope(
|
|
2196
|
+
(own2) => own2(
|
|
2197
|
+
CML.NativeScript.from_cbor_hex(
|
|
2198
|
+
nativeHashesOptional[credential.hash]
|
|
2199
|
+
)
|
|
2200
|
+
).verify(
|
|
2201
|
+
Number.isInteger(lowerBound) ? BigInt(lowerBound) : void 0,
|
|
2202
|
+
Number.isInteger(upperBound) ? BigInt(upperBound) : void 0,
|
|
2203
|
+
edKeyHashes
|
|
2204
|
+
)
|
|
2205
|
+
);
|
|
2206
|
+
if (!valid) {
|
|
2038
2207
|
throw new Error(
|
|
2039
2208
|
`Invalid native script witness. Script hash: ${credential.hash}`
|
|
2040
2209
|
);
|
|
2041
2210
|
}
|
|
2042
2211
|
break;
|
|
2043
|
-
} else if (plutusHashes.
|
|
2044
|
-
if (redeemers.
|
|
2045
|
-
(redeemer) => redeemer.tag === tag && redeemer.index === index
|
|
2046
|
-
)) {
|
|
2212
|
+
} else if (plutusHashes.has(credential.hash) || plutusHashesOptional.has(credential.hash)) {
|
|
2213
|
+
if (redeemers.has(redeemerKey(tag, index))) {
|
|
2047
2214
|
consumedHashes.add(credential.hash);
|
|
2048
2215
|
break;
|
|
2049
2216
|
}
|
|
@@ -2054,13 +2221,14 @@ It does not exist or was already spent.`
|
|
|
2054
2221
|
}
|
|
2055
2222
|
}
|
|
2056
2223
|
}
|
|
2057
|
-
const collateralInputs = body.collateral_inputs();
|
|
2224
|
+
const collateralInputs = own(body.collateral_inputs());
|
|
2225
|
+
const collateralBalance = {};
|
|
2058
2226
|
for (let i = 0; i < (collateralInputs?.len() || 0); i++) {
|
|
2059
|
-
const outRef = withCMLScope((
|
|
2060
|
-
const input =
|
|
2061
|
-
return
|
|
2227
|
+
const outRef = withCMLScope((own2) => {
|
|
2228
|
+
const input = own2(collateralInputs.get(i));
|
|
2229
|
+
return own2(input.transaction_id()).to_hex() + input.index().toString();
|
|
2062
2230
|
});
|
|
2063
|
-
const entry = this.
|
|
2231
|
+
const entry = this.#confirmed.get(outRef) || this.mempool[outRef];
|
|
2064
2232
|
if (!entry || entry.spent) {
|
|
2065
2233
|
throw new Error(
|
|
2066
2234
|
`Could not read UTxO: ${JSON.stringify({
|
|
@@ -2070,19 +2238,27 @@ It does not exist or was already spent.`
|
|
|
2070
2238
|
It does not exist or was already spent.`
|
|
2071
2239
|
);
|
|
2072
2240
|
}
|
|
2073
|
-
const { paymentCredential } =
|
|
2241
|
+
const { paymentCredential } = getAddressDetails2(entry.utxo.address);
|
|
2074
2242
|
if (paymentCredential?.type === "Script") {
|
|
2075
2243
|
throw new Error("Collateral inputs can only contain vkeys.");
|
|
2076
2244
|
}
|
|
2077
2245
|
checkAndConsumeHash(paymentCredential, null, null);
|
|
2246
|
+
for (const [unit, amount] of Object.entries(entry.utxo.assets)) {
|
|
2247
|
+
collateralBalance[unit] = (collateralBalance[unit] ?? 0n) + amount;
|
|
2248
|
+
}
|
|
2078
2249
|
}
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2250
|
+
if (redeemers.size > 0) {
|
|
2251
|
+
this.checkCollateral(body, collateralBalance, own);
|
|
2252
|
+
}
|
|
2253
|
+
const requiredSigners = own(body.required_signers());
|
|
2254
|
+
for (let i = 0; i < (requiredSigners?.len() || 0); i++) {
|
|
2255
|
+
const signer = own(requiredSigners.get(i));
|
|
2082
2256
|
checkAndConsumeHash({ type: "Key", hash: signer.to_hex() }, null, null);
|
|
2083
2257
|
}
|
|
2084
|
-
|
|
2085
|
-
|
|
2258
|
+
const mint = own(body.mint());
|
|
2259
|
+
const policyIds = own(mint?.keys());
|
|
2260
|
+
for (let index = 0; index < (policyIds?.len() || 0); index++) {
|
|
2261
|
+
const policyId = own(policyIds.get(index)).to_hex();
|
|
2086
2262
|
checkAndConsumeHash({ type: "Script", hash: policyId }, "Mint", index);
|
|
2087
2263
|
}
|
|
2088
2264
|
const withdrawalRequests = [];
|
|
@@ -2092,7 +2268,7 @@ It does not exist or was already spent.`
|
|
|
2092
2268
|
body.withdrawals().get(rawAddress).toString()
|
|
2093
2269
|
);
|
|
2094
2270
|
const rewardAddress = rawAddress.to_address().to_bech32(void 0);
|
|
2095
|
-
const { stakeCredential } =
|
|
2271
|
+
const { stakeCredential } = getAddressDetails2(rewardAddress);
|
|
2096
2272
|
checkAndConsumeHash(stakeCredential, "Reward", index);
|
|
2097
2273
|
if (this.chain[rewardAddress]?.delegation.rewards !== withdrawal) {
|
|
2098
2274
|
throw new Error(
|
|
@@ -2131,7 +2307,7 @@ It does not exist or was already spent.`
|
|
|
2131
2307
|
CML.NetworkInfo.testnet().network_id(),
|
|
2132
2308
|
registration.stake_credential()
|
|
2133
2309
|
).to_address().to_bech32(void 0);
|
|
2134
|
-
const { stakeCredential } =
|
|
2310
|
+
const { stakeCredential } = getAddressDetails2(rewardAddress);
|
|
2135
2311
|
checkAndConsumeHash(stakeCredential, "Cert", index);
|
|
2136
2312
|
if (this.chain[rewardAddress]?.registeredStake) {
|
|
2137
2313
|
throw new Error(
|
|
@@ -2147,7 +2323,7 @@ It does not exist or was already spent.`
|
|
|
2147
2323
|
CML.NetworkInfo.testnet().network_id(),
|
|
2148
2324
|
deregistration.stake_credential()
|
|
2149
2325
|
).to_address().to_bech32(void 0);
|
|
2150
|
-
const { stakeCredential } =
|
|
2326
|
+
const { stakeCredential } = getAddressDetails2(rewardAddress);
|
|
2151
2327
|
checkAndConsumeHash(stakeCredential, "Cert", index);
|
|
2152
2328
|
if (!this.chain[rewardAddress]?.registeredStake) {
|
|
2153
2329
|
throw new Error(
|
|
@@ -2164,7 +2340,7 @@ It does not exist or was already spent.`
|
|
|
2164
2340
|
delegation.stake_credential()
|
|
2165
2341
|
).to_address().to_bech32(void 0);
|
|
2166
2342
|
const poolId = delegation.pool().to_bech32("pool");
|
|
2167
|
-
const { stakeCredential } =
|
|
2343
|
+
const { stakeCredential } = getAddressDetails2(rewardAddress);
|
|
2168
2344
|
checkAndConsumeHash(stakeCredential, "Cert", index);
|
|
2169
2345
|
if (!this.chain[rewardAddress]?.registeredStake && !certRequests.find(
|
|
2170
2346
|
(request) => request.type === "Registration" && request.rewardAddress === rewardAddress
|
|
@@ -2339,19 +2515,19 @@ It does not exist or was already spent.`
|
|
|
2339
2515
|
}
|
|
2340
2516
|
}
|
|
2341
2517
|
resolvedInputs.forEach(({ entry: { utxo } }, index) => {
|
|
2342
|
-
const { paymentCredential } =
|
|
2518
|
+
const { paymentCredential } = getAddressDetails2(utxo.address);
|
|
2343
2519
|
checkAndConsumeHash(paymentCredential, "Spend", index);
|
|
2344
2520
|
});
|
|
2345
|
-
const outputs = withCMLScope((
|
|
2521
|
+
const outputs = withCMLScope((own2) => {
|
|
2346
2522
|
const collected = [];
|
|
2347
|
-
const bodyOutputs =
|
|
2523
|
+
const bodyOutputs = own2(body.outputs());
|
|
2348
2524
|
for (let i = 0; i < bodyOutputs.len(); i++) {
|
|
2349
|
-
const output =
|
|
2350
|
-
const unspentOutput =
|
|
2525
|
+
const output = own2(bodyOutputs.get(i));
|
|
2526
|
+
const unspentOutput = own2(
|
|
2351
2527
|
CML.TransactionUnspentOutput.new(
|
|
2352
|
-
|
|
2528
|
+
own2(
|
|
2353
2529
|
CML.TransactionInput.new(
|
|
2354
|
-
|
|
2530
|
+
own2(CML.TransactionHash.from_hex(txHash)),
|
|
2355
2531
|
BigInt(i)
|
|
2356
2532
|
)
|
|
2357
2533
|
),
|
|
@@ -2367,13 +2543,13 @@ It does not exist or was already spent.`
|
|
|
2367
2543
|
}
|
|
2368
2544
|
return collected;
|
|
2369
2545
|
});
|
|
2370
|
-
const [extraKeyHash] =
|
|
2546
|
+
const [extraKeyHash] = keyHashList.filter(
|
|
2371
2547
|
(keyHash) => !consumedHashes.has(keyHash)
|
|
2372
2548
|
);
|
|
2373
2549
|
if (extraKeyHash) {
|
|
2374
2550
|
throw new Error(`Extraneous vkey witness. Key hash: ${extraKeyHash}`);
|
|
2375
2551
|
}
|
|
2376
|
-
const [extraNativeHash] =
|
|
2552
|
+
const [extraNativeHash] = nativeHashList.filter(
|
|
2377
2553
|
(scriptHash) => !consumedHashes.has(scriptHash)
|
|
2378
2554
|
);
|
|
2379
2555
|
if (extraNativeHash) {
|
|
@@ -2381,7 +2557,7 @@ It does not exist or was already spent.`
|
|
|
2381
2557
|
`Extraneous native script. Script hash: ${extraNativeHash}`
|
|
2382
2558
|
);
|
|
2383
2559
|
}
|
|
2384
|
-
const [extraPlutusHash] =
|
|
2560
|
+
const [extraPlutusHash] = plutusHashList.filter(
|
|
2385
2561
|
(scriptHash) => !consumedHashes.has(scriptHash)
|
|
2386
2562
|
);
|
|
2387
2563
|
if (extraPlutusHash) {
|
|
@@ -2412,11 +2588,8 @@ It does not exist or was already spent.`
|
|
|
2412
2588
|
);
|
|
2413
2589
|
}
|
|
2414
2590
|
}
|
|
2415
|
-
resolvedInputs.forEach(({ entry
|
|
2416
|
-
const outRef = entry.utxo.txHash + entry.utxo.outputIndex;
|
|
2591
|
+
resolvedInputs.forEach(({ entry }) => {
|
|
2417
2592
|
entry.spent = true;
|
|
2418
|
-
if (type === "Ledger") this.ledger[outRef] = entry;
|
|
2419
|
-
else if (type === "Mempool") this.mempool[outRef] = entry;
|
|
2420
2593
|
});
|
|
2421
2594
|
withdrawalRequests.forEach(({ rewardAddress, withdrawal }) => {
|
|
2422
2595
|
this.chain[rewardAddress].delegation.rewards -= withdrawal;
|
|
@@ -2456,9 +2629,115 @@ It does not exist or was already spent.`
|
|
|
2456
2629
|
for (const [datumHash, datum] of Object.entries(datumTable)) {
|
|
2457
2630
|
this.datumTable[datumHash] = datum;
|
|
2458
2631
|
}
|
|
2459
|
-
this
|
|
2460
|
-
|
|
2461
|
-
return
|
|
2632
|
+
this.#history[txHash] = { status: "pending" };
|
|
2633
|
+
this.#pendingTxHashes.push(txHash);
|
|
2634
|
+
return txHash;
|
|
2635
|
+
}
|
|
2636
|
+
/**
|
|
2637
|
+
* The ledger's collateral rules for a transaction with redeemers: at least
|
|
2638
|
+
* one and at most `maxCollateralInputs` collateral inputs, a balance (inputs
|
|
2639
|
+
* minus the collateral return) of ADA only that covers
|
|
2640
|
+
* `collateralPercentage` of the fee, a `total_collateral` field, when
|
|
2641
|
+
* present, equal to that balance, and a collateral return holding at least
|
|
2642
|
+
* its minimum ADA.
|
|
2643
|
+
*/
|
|
2644
|
+
checkCollateral(body, collateralBalance, own) {
|
|
2645
|
+
const inputCount = own(body.collateral_inputs())?.len() ?? 0;
|
|
2646
|
+
if (inputCount === 0) {
|
|
2647
|
+
throw new Error(
|
|
2648
|
+
"NoCollateralInputs: a transaction that runs scripts needs collateral inputs."
|
|
2649
|
+
);
|
|
2650
|
+
}
|
|
2651
|
+
const { maxCollateralInputs, collateralPercentage } = this.protocolParameters;
|
|
2652
|
+
if (inputCount > maxCollateralInputs) {
|
|
2653
|
+
throw new Error(
|
|
2654
|
+
`TooManyCollateralInputs: ${inputCount} collateral inputs, but at most ${maxCollateralInputs} are allowed.`
|
|
2655
|
+
);
|
|
2656
|
+
}
|
|
2657
|
+
const balance = { ...collateralBalance };
|
|
2658
|
+
const collateralReturn = own(body.collateral_return());
|
|
2659
|
+
if (collateralReturn) {
|
|
2660
|
+
const minLovelace = CML.min_ada_required(
|
|
2661
|
+
collateralReturn,
|
|
2662
|
+
this.protocolParameters.coinsPerUtxoByte
|
|
2663
|
+
);
|
|
2664
|
+
const returnedLovelace = own(collateralReturn.amount()).coin();
|
|
2665
|
+
if (returnedLovelace < minLovelace) {
|
|
2666
|
+
throw new Error(
|
|
2667
|
+
`BabbageOutputTooSmallUTxO: collateral return holds ${returnedLovelace} Lovelace, but needs at least ${minLovelace} Lovelace.`
|
|
2668
|
+
);
|
|
2669
|
+
}
|
|
2670
|
+
const returned = valueToAssets(own(collateralReturn.amount()));
|
|
2671
|
+
for (const [unit, amount] of Object.entries(returned)) {
|
|
2672
|
+
balance[unit] = (balance[unit] ?? 0n) - amount;
|
|
2673
|
+
}
|
|
2674
|
+
}
|
|
2675
|
+
const nonAda = Object.entries(balance).filter(
|
|
2676
|
+
([unit, amount]) => unit !== "lovelace" && amount !== 0n
|
|
2677
|
+
);
|
|
2678
|
+
if (nonAda.length > 0) {
|
|
2679
|
+
throw new Error(
|
|
2680
|
+
`CollateralContainsNonADA: collateral balance holds ${nonAda.map(([unit, amount]) => `${amount} ${unit}`).join(", ")}.`
|
|
2681
|
+
);
|
|
2682
|
+
}
|
|
2683
|
+
const collateral = balance.lovelace ?? 0n;
|
|
2684
|
+
const fee = body.fee();
|
|
2685
|
+
if (collateral * 100n < fee * BigInt(collateralPercentage)) {
|
|
2686
|
+
const required = (fee * BigInt(collateralPercentage) + 99n) / 100n;
|
|
2687
|
+
throw new Error(
|
|
2688
|
+
`InsufficientCollateral: collateral balance is ${collateral} Lovelace, but the fee of ${fee} requires ${required} Lovelace (${collateralPercentage}%).`
|
|
2689
|
+
);
|
|
2690
|
+
}
|
|
2691
|
+
const totalCollateral = body.total_collateral();
|
|
2692
|
+
if (totalCollateral !== void 0 && totalCollateral !== collateral) {
|
|
2693
|
+
throw new Error(
|
|
2694
|
+
`IncorrectTotalCollateralField: total collateral is ${totalCollateral} Lovelace, but the collateral balance is ${collateral} Lovelace.`
|
|
2695
|
+
);
|
|
2696
|
+
}
|
|
2697
|
+
}
|
|
2698
|
+
/** Hash of a reference script, computed once per distinct script. */
|
|
2699
|
+
scriptRefHash(scriptRef) {
|
|
2700
|
+
let scriptHash = this.#scriptRefHashes.get(
|
|
2701
|
+
scriptRef.type,
|
|
2702
|
+
scriptRef.script
|
|
2703
|
+
);
|
|
2704
|
+
if (scriptHash === void 0) {
|
|
2705
|
+
scriptHash = withCMLScope((own) => {
|
|
2706
|
+
const bytes = fromHex2(scriptRef.script);
|
|
2707
|
+
switch (scriptRef.type) {
|
|
2708
|
+
case "Native":
|
|
2709
|
+
return own(
|
|
2710
|
+
own(CML.NativeScript.from_cbor_bytes(bytes)).hash()
|
|
2711
|
+
).to_hex();
|
|
2712
|
+
case "PlutusV1":
|
|
2713
|
+
return own(
|
|
2714
|
+
own(
|
|
2715
|
+
CML.PlutusScript.from_v1(
|
|
2716
|
+
own(CML.PlutusV1Script.from_cbor_bytes(bytes))
|
|
2717
|
+
)
|
|
2718
|
+
).hash()
|
|
2719
|
+
).to_hex();
|
|
2720
|
+
case "PlutusV2":
|
|
2721
|
+
return own(
|
|
2722
|
+
own(
|
|
2723
|
+
CML.PlutusScript.from_v2(
|
|
2724
|
+
own(CML.PlutusV2Script.from_cbor_bytes(bytes))
|
|
2725
|
+
)
|
|
2726
|
+
).hash()
|
|
2727
|
+
).to_hex();
|
|
2728
|
+
case "PlutusV3":
|
|
2729
|
+
return own(
|
|
2730
|
+
own(
|
|
2731
|
+
CML.PlutusScript.from_v3(
|
|
2732
|
+
own(CML.PlutusV3Script.from_cbor_bytes(bytes))
|
|
2733
|
+
)
|
|
2734
|
+
).hash()
|
|
2735
|
+
).to_hex();
|
|
2736
|
+
}
|
|
2737
|
+
});
|
|
2738
|
+
this.#scriptRefHashes.set(scriptRef.type, scriptRef.script, scriptHash);
|
|
2739
|
+
}
|
|
2740
|
+
return scriptHash;
|
|
2462
2741
|
}
|
|
2463
2742
|
async evaluateTx(tx, additionalUTxOs) {
|
|
2464
2743
|
return withCMLScope((own) => {
|
|
@@ -2523,7 +2802,7 @@ It does not exist or was already spent.`
|
|
|
2523
2802
|
}
|
|
2524
2803
|
const totalBalances = {};
|
|
2525
2804
|
const balances = {};
|
|
2526
|
-
for (const { utxo } of Object.values(this.
|
|
2805
|
+
for (const { utxo } of Object.values(this.#confirmed.record)) {
|
|
2527
2806
|
for (const [unit, quantity] of Object.entries(utxo.assets)) {
|
|
2528
2807
|
if (!balances[utxo.address]) {
|
|
2529
2808
|
balances[utxo.address] = { [unit]: quantity };
|
|
@@ -2576,377 +2855,14 @@ ${"\u2581".repeat(60)}
|
|
|
2576
2855
|
}
|
|
2577
2856
|
};
|
|
2578
2857
|
|
|
2579
|
-
// src/maestro.ts
|
|
2580
|
-
import {
|
|
2581
|
-
applyDoubleCborEncoding as applyDoubleCborEncoding3,
|
|
2582
|
-
scriptFromNative as scriptFromNative2,
|
|
2583
|
-
utxoToCore
|
|
2584
|
-
} from "@lucid-evolution/utils";
|
|
2585
|
-
import { fromHex as fromHex3 } from "@lucid-evolution/core-utils";
|
|
2586
|
-
var Maestro = class {
|
|
2587
|
-
url;
|
|
2588
|
-
apiKey;
|
|
2589
|
-
turboSubmit;
|
|
2590
|
-
constructor({ network, apiKey, turboSubmit = false }) {
|
|
2591
|
-
this.url = `https://${network}.gomaestro-api.org/v1`;
|
|
2592
|
-
this.apiKey = apiKey;
|
|
2593
|
-
this.turboSubmit = turboSubmit;
|
|
2594
|
-
}
|
|
2595
|
-
async getProtocolParameters() {
|
|
2596
|
-
const timestampedResult = await fetch(`${this.url}/protocol-parameters`, {
|
|
2597
|
-
headers: this.commonHeaders()
|
|
2598
|
-
}).then((res) => res.json());
|
|
2599
|
-
const result = timestampedResult.data;
|
|
2600
|
-
const decimalFromRationalString = (str) => {
|
|
2601
|
-
const forwardSlashIndex = str.indexOf("/");
|
|
2602
|
-
return parseInt(str.slice(0, forwardSlashIndex)) / parseInt(str.slice(forwardSlashIndex + 1));
|
|
2603
|
-
};
|
|
2604
|
-
return {
|
|
2605
|
-
protocolMajorVersion: result.version?.major,
|
|
2606
|
-
protocolMinorVersion: result.version?.minor,
|
|
2607
|
-
minFeeA: parseInt(result.min_fee_coefficient),
|
|
2608
|
-
minFeeB: parseInt(result.min_fee_constant.ada.lovelace),
|
|
2609
|
-
maxTxSize: parseInt(result.max_transaction_size.bytes),
|
|
2610
|
-
maxValSize: parseInt(result.max_value_size.bytes),
|
|
2611
|
-
keyDeposit: BigInt(result.stake_credential_deposit.ada.lovelace),
|
|
2612
|
-
poolDeposit: BigInt(result.stake_pool_deposit.ada.lovelace),
|
|
2613
|
-
drepDeposit: BigInt(result.delegate_representative_deposit.ada.lovelace),
|
|
2614
|
-
govActionDeposit: BigInt(result.governance_action_deposit.ada.lovelace),
|
|
2615
|
-
priceMem: decimalFromRationalString(
|
|
2616
|
-
result.script_execution_prices.memory
|
|
2617
|
-
),
|
|
2618
|
-
priceStep: decimalFromRationalString(result.script_execution_prices.cpu),
|
|
2619
|
-
maxTxExMem: BigInt(result.max_execution_units_per_transaction.memory),
|
|
2620
|
-
maxTxExSteps: BigInt(result.max_execution_units_per_transaction.cpu),
|
|
2621
|
-
coinsPerUtxoByte: BigInt(result.min_utxo_deposit_coefficient),
|
|
2622
|
-
collateralPercentage: parseInt(result.collateral_percentage),
|
|
2623
|
-
maxCollateralInputs: parseInt(result.max_collateral_inputs),
|
|
2624
|
-
minFeeRefScriptCostPerByte: parseInt(
|
|
2625
|
-
result.min_fee_reference_scripts.base
|
|
2626
|
-
),
|
|
2627
|
-
costModels: {
|
|
2628
|
-
PlutusV1: result.plutus_cost_models.plutus_v1,
|
|
2629
|
-
PlutusV2: result.plutus_cost_models.plutus_v2,
|
|
2630
|
-
PlutusV3: result.plutus_cost_models.plutus_v3
|
|
2631
|
-
}
|
|
2632
|
-
};
|
|
2633
|
-
}
|
|
2634
|
-
async getTreasury() {
|
|
2635
|
-
throw new Error(
|
|
2636
|
-
"Maestro does not expose a current treasury query. Pass currentTreasuryValue explicitly to donateToTreasury."
|
|
2637
|
-
);
|
|
2638
|
-
}
|
|
2639
|
-
async getUtxosInternal(addressOrCredential, unit) {
|
|
2640
|
-
const queryPredicate = (() => {
|
|
2641
|
-
if (typeof addressOrCredential === "string") {
|
|
2642
|
-
return "/addresses/" + addressOrCredential;
|
|
2643
|
-
}
|
|
2644
|
-
let credentialBech32Query = "/addresses/cred/";
|
|
2645
|
-
credentialBech32Query += addressOrCredential.type === "Key" ? CML.Ed25519KeyHash.from_hex(addressOrCredential.hash).to_bech32(
|
|
2646
|
-
"addr_vkh"
|
|
2647
|
-
) : CML.ScriptHash.from_hex(addressOrCredential.hash).to_bech32(
|
|
2648
|
-
"addr_shared_vkh"
|
|
2649
|
-
);
|
|
2650
|
-
return credentialBech32Query;
|
|
2651
|
-
})();
|
|
2652
|
-
const qparams = new URLSearchParams({
|
|
2653
|
-
count: "100",
|
|
2654
|
-
...unit && { asset: unit }
|
|
2655
|
-
});
|
|
2656
|
-
const result = await this.getAllPagesData(
|
|
2657
|
-
async (qry) => await fetch(qry, {
|
|
2658
|
-
headers: this.requireAmountsAsStrings(this.commonHeaders())
|
|
2659
|
-
}),
|
|
2660
|
-
`${this.url}${queryPredicate}/utxos`,
|
|
2661
|
-
qparams,
|
|
2662
|
-
"Location: getUtxosInternal. Error: Could not fetch UTxOs from Maestro"
|
|
2663
|
-
);
|
|
2664
|
-
return result.map(this.maestroUtxoToUtxo);
|
|
2665
|
-
}
|
|
2666
|
-
getUtxos(addressOrCredential) {
|
|
2667
|
-
return this.getUtxosInternal(addressOrCredential);
|
|
2668
|
-
}
|
|
2669
|
-
getUtxosWithUnit(addressOrCredential, unit) {
|
|
2670
|
-
return this.getUtxosInternal(addressOrCredential, unit);
|
|
2671
|
-
}
|
|
2672
|
-
async getUtxoByUnit(unit) {
|
|
2673
|
-
const timestampedAddressesResponse = await fetch(
|
|
2674
|
-
`${this.url}/assets/${unit}/addresses?count=2`,
|
|
2675
|
-
{ headers: this.commonHeaders() }
|
|
2676
|
-
);
|
|
2677
|
-
const timestampedAddresses = await timestampedAddressesResponse.json();
|
|
2678
|
-
if (!timestampedAddressesResponse.ok) {
|
|
2679
|
-
if (timestampedAddresses.message) {
|
|
2680
|
-
throw new Error(timestampedAddresses.message);
|
|
2681
|
-
}
|
|
2682
|
-
throw new Error(
|
|
2683
|
-
"Location: getUtxoByUnit. Error: Couldn't perform query. Received status code: " + timestampedAddressesResponse.status
|
|
2684
|
-
);
|
|
2685
|
-
}
|
|
2686
|
-
const addressesWithAmount = timestampedAddresses.data;
|
|
2687
|
-
if (addressesWithAmount.length === 0) {
|
|
2688
|
-
throw new Error("Location: getUtxoByUnit. Error: Unit not found.");
|
|
2689
|
-
}
|
|
2690
|
-
if (addressesWithAmount.length > 1) {
|
|
2691
|
-
throw new Error(
|
|
2692
|
-
"Location: getUtxoByUnit. Error: Unit needs to be an NFT or only held by one address."
|
|
2693
|
-
);
|
|
2694
|
-
}
|
|
2695
|
-
const address = addressesWithAmount[0].address;
|
|
2696
|
-
const utxos = await this.getUtxosWithUnit(address, unit);
|
|
2697
|
-
if (utxos.length > 1) {
|
|
2698
|
-
throw new Error(
|
|
2699
|
-
"Location: getUtxoByUnit. Error: Unit needs to be an NFT or only held by one address."
|
|
2700
|
-
);
|
|
2701
|
-
}
|
|
2702
|
-
return utxos[0];
|
|
2703
|
-
}
|
|
2704
|
-
async getUtxosByOutRef(outRefs) {
|
|
2705
|
-
const qry = `${this.url}/transactions/outputs`;
|
|
2706
|
-
const body = JSON.stringify(
|
|
2707
|
-
outRefs.map(({ txHash, outputIndex }) => `${txHash}#${outputIndex}`)
|
|
2708
|
-
);
|
|
2709
|
-
const utxos = await this.getAllPagesData(
|
|
2710
|
-
async (qry2) => await fetch(qry2, {
|
|
2711
|
-
method: "POST",
|
|
2712
|
-
headers: {
|
|
2713
|
-
"Content-Type": "application/json",
|
|
2714
|
-
...this.requireAmountsAsStrings(this.commonHeaders())
|
|
2715
|
-
},
|
|
2716
|
-
body
|
|
2717
|
-
}),
|
|
2718
|
-
qry,
|
|
2719
|
-
new URLSearchParams({}),
|
|
2720
|
-
"Location: getUtxosByOutRef. Error: Could not fetch UTxOs by references from Maestro"
|
|
2721
|
-
);
|
|
2722
|
-
return utxos.map(this.maestroUtxoToUtxo);
|
|
2723
|
-
}
|
|
2724
|
-
async getRewardAccount(rewardAddress) {
|
|
2725
|
-
const response = await fetch(`${this.url}/accounts/${rewardAddress}`, {
|
|
2726
|
-
headers: this.requireAmountsAsStrings(this.commonHeaders())
|
|
2727
|
-
});
|
|
2728
|
-
if (response.status === 404) {
|
|
2729
|
-
return { registered: false, poolId: null, rewards: 0n };
|
|
2730
|
-
}
|
|
2731
|
-
if (!response.ok) {
|
|
2732
|
-
throw new Error(
|
|
2733
|
-
`Could not fetch reward account from Maestro. Received status code: ${response.status}`
|
|
2734
|
-
);
|
|
2735
|
-
}
|
|
2736
|
-
const timestampedResult = await response.json();
|
|
2737
|
-
const result = timestampedResult.data;
|
|
2738
|
-
return {
|
|
2739
|
-
registered: result.registered,
|
|
2740
|
-
poolId: result.delegated_pool || null,
|
|
2741
|
-
rewards: BigInt(result.rewards_available)
|
|
2742
|
-
};
|
|
2743
|
-
}
|
|
2744
|
-
async getDelegation(rewardAddress) {
|
|
2745
|
-
const { poolId, rewards } = await this.getRewardAccount(rewardAddress);
|
|
2746
|
-
return { poolId, rewards };
|
|
2747
|
-
}
|
|
2748
|
-
async getDatum(datumHash) {
|
|
2749
|
-
const timestampedResultResponse = await fetch(
|
|
2750
|
-
`${this.url}/datums/${datumHash}`,
|
|
2751
|
-
{
|
|
2752
|
-
headers: this.commonHeaders()
|
|
2753
|
-
}
|
|
2754
|
-
);
|
|
2755
|
-
if (!timestampedResultResponse.ok) {
|
|
2756
|
-
if (timestampedResultResponse.status === 404) {
|
|
2757
|
-
throw new Error(`No datum found for datum hash: ${datumHash}`);
|
|
2758
|
-
} else {
|
|
2759
|
-
throw new Error(
|
|
2760
|
-
"Location: getDatum. Error: Couldn't successfully perform query. Received status code: " + timestampedResultResponse.status
|
|
2761
|
-
);
|
|
2762
|
-
}
|
|
2763
|
-
}
|
|
2764
|
-
const timestampedResult = await timestampedResultResponse.json();
|
|
2765
|
-
return timestampedResult.data.bytes;
|
|
2766
|
-
}
|
|
2767
|
-
awaitTx(txHash, checkInterval = 3e3) {
|
|
2768
|
-
return new Promise((res) => {
|
|
2769
|
-
const confirmation = setInterval(async () => {
|
|
2770
|
-
const isConfirmedResponse = await fetch(
|
|
2771
|
-
`${this.url}/transactions/${txHash}/cbor`,
|
|
2772
|
-
{
|
|
2773
|
-
headers: this.commonHeaders()
|
|
2774
|
-
}
|
|
2775
|
-
);
|
|
2776
|
-
if (isConfirmedResponse.ok) {
|
|
2777
|
-
await isConfirmedResponse.json();
|
|
2778
|
-
clearInterval(confirmation);
|
|
2779
|
-
await new Promise((res2) => setTimeout(() => res2(1), 1e3));
|
|
2780
|
-
return res(true);
|
|
2781
|
-
}
|
|
2782
|
-
}, checkInterval);
|
|
2783
|
-
});
|
|
2784
|
-
}
|
|
2785
|
-
async getTransactionStatus(txHash, options = {}) {
|
|
2786
|
-
const response = await fetch(`${this.url}/txmanager/${txHash}/state`, {
|
|
2787
|
-
headers: this.commonHeaders(),
|
|
2788
|
-
signal: options.signal
|
|
2789
|
-
});
|
|
2790
|
-
if (response.status === 404) return { status: "not_found", txHash };
|
|
2791
|
-
if (!response.ok) {
|
|
2792
|
-
throw new Error(
|
|
2793
|
-
`Could not fetch transaction status from Maestro. Received status code: ${response.status}`
|
|
2794
|
-
);
|
|
2795
|
-
}
|
|
2796
|
-
const result = await response.json();
|
|
2797
|
-
switch (result.status) {
|
|
2798
|
-
case "pending":
|
|
2799
|
-
return { status: "pending", txHash };
|
|
2800
|
-
case "confirmed":
|
|
2801
|
-
return {
|
|
2802
|
-
status: "confirmed",
|
|
2803
|
-
txHash,
|
|
2804
|
-
confirmation: {
|
|
2805
|
-
txHash,
|
|
2806
|
-
confirmations: result.confirmations
|
|
2807
|
-
}
|
|
2808
|
-
};
|
|
2809
|
-
case "failed":
|
|
2810
|
-
return {
|
|
2811
|
-
status: "failed",
|
|
2812
|
-
txHash,
|
|
2813
|
-
reason: result.reason ?? result.error
|
|
2814
|
-
};
|
|
2815
|
-
default:
|
|
2816
|
-
throw new Error(
|
|
2817
|
-
`Maestro returned an unknown transaction status: ${String(result.status)}`
|
|
2818
|
-
);
|
|
2819
|
-
}
|
|
2820
|
-
}
|
|
2821
|
-
async submitTx(tx) {
|
|
2822
|
-
let queryUrl = `${this.url}/txmanager`;
|
|
2823
|
-
queryUrl += this.turboSubmit ? "/turbosubmit" : "";
|
|
2824
|
-
const response = await fetch(queryUrl, {
|
|
2825
|
-
method: "POST",
|
|
2826
|
-
headers: {
|
|
2827
|
-
"Content-Type": "application/cbor",
|
|
2828
|
-
Accept: "text/plain",
|
|
2829
|
-
...this.commonHeaders()
|
|
2830
|
-
},
|
|
2831
|
-
body: fromHex3(tx)
|
|
2832
|
-
});
|
|
2833
|
-
const result = await response.text();
|
|
2834
|
-
if (!response.ok) {
|
|
2835
|
-
if (response.status === 400) throw new Error(result);
|
|
2836
|
-
else {
|
|
2837
|
-
throw new Error(
|
|
2838
|
-
"Could not submit transaction. Received status code: " + response.status
|
|
2839
|
-
);
|
|
2840
|
-
}
|
|
2841
|
-
}
|
|
2842
|
-
return result;
|
|
2843
|
-
}
|
|
2844
|
-
commonHeaders() {
|
|
2845
|
-
return { "api-key": this.apiKey, lucid: lucid2 };
|
|
2846
|
-
}
|
|
2847
|
-
requireAmountsAsStrings(obj) {
|
|
2848
|
-
return { ...obj, "amounts-as-strings": "true" };
|
|
2849
|
-
}
|
|
2850
|
-
maestroUtxoToUtxo(result) {
|
|
2851
|
-
return {
|
|
2852
|
-
txHash: result.tx_hash,
|
|
2853
|
-
outputIndex: result.index,
|
|
2854
|
-
assets: (() => {
|
|
2855
|
-
const a = {};
|
|
2856
|
-
result.assets.forEach((am) => {
|
|
2857
|
-
a[am.unit] = BigInt(am.amount);
|
|
2858
|
-
});
|
|
2859
|
-
return a;
|
|
2860
|
-
})(),
|
|
2861
|
-
address: result.address,
|
|
2862
|
-
datumHash: result.datum ? result.datum.type == "inline" ? void 0 : result.datum.hash : void 0,
|
|
2863
|
-
datum: result.datum?.bytes,
|
|
2864
|
-
scriptRef: toScriptRef2(result.reference_script)
|
|
2865
|
-
};
|
|
2866
|
-
}
|
|
2867
|
-
async getAllPagesData(getResponse, qry, paramsGiven, errorMsg) {
|
|
2868
|
-
let nextCursor = null;
|
|
2869
|
-
let result = [];
|
|
2870
|
-
while (true) {
|
|
2871
|
-
if (nextCursor !== null) {
|
|
2872
|
-
paramsGiven.set("cursor", nextCursor);
|
|
2873
|
-
}
|
|
2874
|
-
const response = await getResponse(`${qry}?` + paramsGiven);
|
|
2875
|
-
const pageResult = await response.json();
|
|
2876
|
-
if (!response.ok) {
|
|
2877
|
-
throw new Error(
|
|
2878
|
-
`${errorMsg}. Received status code: ${response.status}`
|
|
2879
|
-
);
|
|
2880
|
-
}
|
|
2881
|
-
nextCursor = pageResult.next_cursor;
|
|
2882
|
-
result = result.concat(pageResult.data);
|
|
2883
|
-
if (nextCursor == null) break;
|
|
2884
|
-
}
|
|
2885
|
-
return result;
|
|
2886
|
-
}
|
|
2887
|
-
async evaluateTx(tx, additionalUTxOs) {
|
|
2888
|
-
const additionalMaestroUTxOs = (additionalUTxOs || []).map((utxo) => ({
|
|
2889
|
-
tx_hash: utxo.txHash,
|
|
2890
|
-
index: utxo.outputIndex,
|
|
2891
|
-
txout_cbor: utxoToCore(utxo).output().to_cbor_hex()
|
|
2892
|
-
}));
|
|
2893
|
-
const payload = {
|
|
2894
|
-
cbor: tx,
|
|
2895
|
-
additional_utxos: additionalMaestroUTxOs
|
|
2896
|
-
};
|
|
2897
|
-
const res = await fetch(`${this.url}/transactions/evaluate`, {
|
|
2898
|
-
method: "POST",
|
|
2899
|
-
headers: {
|
|
2900
|
-
"Content-Type": "application/json",
|
|
2901
|
-
Accept: "application/json",
|
|
2902
|
-
"api-key": this.apiKey
|
|
2903
|
-
},
|
|
2904
|
-
body: JSON.stringify(payload)
|
|
2905
|
-
});
|
|
2906
|
-
if (!res.ok) {
|
|
2907
|
-
const body = await res.text();
|
|
2908
|
-
console.error("Response error:", JSON.stringify(res));
|
|
2909
|
-
throw new Error(`Evaluate transaction failed: ${body}`);
|
|
2910
|
-
}
|
|
2911
|
-
const result = await res.json();
|
|
2912
|
-
return result;
|
|
2913
|
-
}
|
|
2914
|
-
};
|
|
2915
|
-
var toScriptRef2 = (reference_script) => {
|
|
2916
|
-
if (reference_script && reference_script.bytes) {
|
|
2917
|
-
switch (reference_script.type) {
|
|
2918
|
-
case "native":
|
|
2919
|
-
return scriptFromNative2(reference_script.json);
|
|
2920
|
-
case "plutusv1":
|
|
2921
|
-
return {
|
|
2922
|
-
type: "PlutusV1",
|
|
2923
|
-
script: applyDoubleCborEncoding3(reference_script.bytes)
|
|
2924
|
-
};
|
|
2925
|
-
case "plutusv2":
|
|
2926
|
-
return {
|
|
2927
|
-
type: "PlutusV2",
|
|
2928
|
-
script: applyDoubleCborEncoding3(reference_script.bytes)
|
|
2929
|
-
};
|
|
2930
|
-
case "plutusv3":
|
|
2931
|
-
return {
|
|
2932
|
-
type: "PlutusV3",
|
|
2933
|
-
script: applyDoubleCborEncoding3(reference_script.bytes)
|
|
2934
|
-
};
|
|
2935
|
-
default:
|
|
2936
|
-
return void 0;
|
|
2937
|
-
}
|
|
2938
|
-
}
|
|
2939
|
-
};
|
|
2940
|
-
var lucid2 = package_default.version;
|
|
2941
|
-
|
|
2942
2858
|
// src/koios.ts
|
|
2943
|
-
import { fromHex as
|
|
2859
|
+
import { fromHex as fromHex3 } from "@lucid-evolution/core-utils";
|
|
2944
2860
|
import { fromUnit as fromUnit3 } from "@lucid-evolution/utils";
|
|
2945
2861
|
|
|
2946
2862
|
// src/internal/koios.ts
|
|
2947
2863
|
import { FetchHttpClient as FetchHttpClient2 } from "@effect/platform";
|
|
2948
2864
|
import { Effect as Effect3, pipe as pipe4, Schema as S4 } from "effect";
|
|
2949
|
-
import { applyDoubleCborEncoding as
|
|
2865
|
+
import { applyDoubleCborEncoding as applyDoubleCborEncoding3 } from "@lucid-evolution/utils";
|
|
2950
2866
|
var ProtocolParametersSchema2 = S4.Struct({
|
|
2951
2867
|
pvt_motion_no_confidence: S4.Number,
|
|
2952
2868
|
pvt_committee_normal: S4.Number,
|
|
@@ -3194,25 +3110,25 @@ var toUTxO = (koiosUTxO, address) => ({
|
|
|
3194
3110
|
address,
|
|
3195
3111
|
datumHash: koiosUTxO.inline_datum ? void 0 : koiosUTxO.datum_hash || void 0,
|
|
3196
3112
|
datum: koiosUTxO.inline_datum ? koiosUTxO.inline_datum.bytes : void 0,
|
|
3197
|
-
scriptRef:
|
|
3113
|
+
scriptRef: toScriptRef2(koiosUTxO.reference_script)
|
|
3198
3114
|
});
|
|
3199
|
-
var
|
|
3115
|
+
var toScriptRef2 = (reference_script) => {
|
|
3200
3116
|
if (reference_script && reference_script.bytes && reference_script.type) {
|
|
3201
3117
|
switch (reference_script.type) {
|
|
3202
3118
|
case "plutusV1":
|
|
3203
3119
|
return {
|
|
3204
3120
|
type: "PlutusV1",
|
|
3205
|
-
script:
|
|
3121
|
+
script: applyDoubleCborEncoding3(reference_script.bytes)
|
|
3206
3122
|
};
|
|
3207
3123
|
case "plutusV2":
|
|
3208
3124
|
return {
|
|
3209
3125
|
type: "PlutusV2",
|
|
3210
|
-
script:
|
|
3126
|
+
script: applyDoubleCborEncoding3(reference_script.bytes)
|
|
3211
3127
|
};
|
|
3212
3128
|
case "plutusV3":
|
|
3213
3129
|
return {
|
|
3214
3130
|
type: "PlutusV3",
|
|
3215
|
-
script:
|
|
3131
|
+
script: applyDoubleCborEncoding3(reference_script.bytes)
|
|
3216
3132
|
};
|
|
3217
3133
|
default:
|
|
3218
3134
|
return void 0;
|
|
@@ -3525,7 +3441,7 @@ var Koios = class {
|
|
|
3525
3441
|
}
|
|
3526
3442
|
async submitTx(tx) {
|
|
3527
3443
|
const url = `${this.baseUrl}/submittx`;
|
|
3528
|
-
const body =
|
|
3444
|
+
const body = fromHex3(tx);
|
|
3529
3445
|
const schema = TxHashSchema;
|
|
3530
3446
|
const bearerToken = this.token ? { Authorization: `Bearer ${this.token}` } : void 0;
|
|
3531
3447
|
const result = await pipe5(
|
|
@@ -3577,7 +3493,6 @@ export {
|
|
|
3577
3493
|
KoiosError,
|
|
3578
3494
|
Kupmios,
|
|
3579
3495
|
KupmiosError,
|
|
3580
|
-
Maestro,
|
|
3581
3496
|
OgmiosJsonRpcError,
|
|
3582
3497
|
generateEmulatorAccount,
|
|
3583
3498
|
generateEmulatorAccountFromPrivateKey,
|