@lucid-evolution/provider 0.1.97 → 0.2.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 CHANGED
@@ -37,11 +37,103 @@ __export(index_exports, {
37
37
  Kupmios: () => Kupmios,
38
38
  KupmiosError: () => KupmiosError,
39
39
  Maestro: () => Maestro,
40
+ OgmiosJsonRpcError: () => OgmiosJsonRpcError,
40
41
  generateEmulatorAccount: () => generateEmulatorAccount,
41
- generateEmulatorAccountFromPrivateKey: () => generateEmulatorAccountFromPrivateKey
42
+ generateEmulatorAccountFromPrivateKey: () => generateEmulatorAccountFromPrivateKey,
43
+ isEmulatorProvider: () => isEmulatorProvider
42
44
  });
43
45
  module.exports = __toCommonJS(index_exports);
44
46
 
47
+ // src/errors.ts
48
+ var asRecord = (value) => typeof value === "object" && value !== null ? value : void 0;
49
+ var responseStatus = (cause) => {
50
+ const response = asRecord(asRecord(cause)?.response);
51
+ return typeof response?.status === "number" ? response.status : void 0;
52
+ };
53
+ var retryAfterHeaderToMs = (value) => {
54
+ if (value === void 0) return void 0;
55
+ const seconds = Number(value);
56
+ if (Number.isFinite(seconds)) return Math.max(0, seconds * 1e3);
57
+ const timestamp = Date.parse(value);
58
+ return Number.isNaN(timestamp) ? void 0 : Math.max(0, timestamp - Date.now());
59
+ };
60
+ var retryAfter = (cause) => {
61
+ const response = asRecord(asRecord(cause)?.response);
62
+ const headers = asRecord(response?.headers);
63
+ const value = headers?.["retry-after"];
64
+ return retryAfterHeaderToMs(typeof value === "string" ? value : void 0);
65
+ };
66
+ var errorTag = (cause) => {
67
+ const record = asRecord(cause);
68
+ return [record?._tag, record?.name, record?.reason].filter((value) => typeof value === "string").join(" ").toLowerCase();
69
+ };
70
+ var inferKind = (cause, status) => {
71
+ const tag = errorTag(cause);
72
+ if (tag.includes("timeout")) return "timeout";
73
+ if (tag.includes("parse") || tag.includes("decode")) return "decode";
74
+ if (status !== void 0) return "http";
75
+ if (tag.includes("request") || tag.includes("transport")) return "transport";
76
+ return "unknown";
77
+ };
78
+ var inferRetryable = (kind, status) => kind === "timeout" || kind === "transport" || status === 408 || status === 425 || status === 429 || status !== void 0 && status >= 500;
79
+ var KupmiosError = class extends Error {
80
+ _tag = "KupmiosError";
81
+ provider = "Kupmios";
82
+ protocol;
83
+ operation;
84
+ kind;
85
+ status;
86
+ retryable;
87
+ retryAfterMs;
88
+ cause;
89
+ constructor(options) {
90
+ const status = options.status ?? responseStatus(options.cause);
91
+ const kind = options.kind ?? inferKind(options.cause, status);
92
+ const retryable = options.retryable ?? inferRetryable(kind, status);
93
+ const operation = options.operation ?? "unknown";
94
+ const statusSuffix = status === void 0 ? "" : ` (HTTP ${status})`;
95
+ super(
96
+ options.message ?? `${options.protocol ?? "provider"} ${operation} failed${statusSuffix}`,
97
+ {
98
+ cause: options.cause
99
+ }
100
+ );
101
+ this.name = "KupmiosError";
102
+ this.protocol = options.protocol;
103
+ this.operation = operation;
104
+ this.kind = kind;
105
+ this.status = status;
106
+ this.retryable = retryable;
107
+ this.retryAfterMs = options.retryAfterMs ?? retryAfter(options.cause);
108
+ this.cause = options.cause;
109
+ }
110
+ };
111
+ var OgmiosJsonRpcError = class extends KupmiosError {
112
+ _tag = "OgmiosJsonRpcError";
113
+ code;
114
+ data;
115
+ method;
116
+ id;
117
+ constructor(options) {
118
+ const dataSuffix = options.data === void 0 ? "" : `: ${JSON.stringify(options.data)}`;
119
+ super({
120
+ protocol: "ogmios",
121
+ operation: options.operation ?? options.method ?? "unknown",
122
+ kind: "json_rpc",
123
+ status: options.status,
124
+ retryAfterMs: options.retryAfterMs,
125
+ cause: options.cause,
126
+ message: `Ogmios JSON-RPC error ${options.code}: ${options.message}${dataSuffix}`
127
+ });
128
+ this.name = "OgmiosJsonRpcError";
129
+ this.code = options.code;
130
+ this.data = options.data;
131
+ this.method = options.method;
132
+ this.id = options.id;
133
+ }
134
+ };
135
+ var toKupmiosError = (cause, protocol, operation) => cause instanceof KupmiosError ? cause : new KupmiosError({ cause, protocol, operation });
136
+
45
137
  // src/core.ts
46
138
  var CML = __toESM(require("@anastasia-labs/cardano-multiplatform-lib-nodejs"), 1);
47
139
 
@@ -52,7 +144,7 @@ var import_utils2 = require("@lucid-evolution/utils");
52
144
  // package.json
53
145
  var package_default = {
54
146
  name: "@lucid-evolution/provider",
55
- version: "0.1.97",
147
+ version: "0.2.1",
56
148
  description: "",
57
149
  main: "./dist/index.js",
58
150
  types: "./dist/index.d.ts",
@@ -295,18 +387,29 @@ var Blockfrost = class {
295
387
  )
296
388
  );
297
389
  }
298
- async getDelegation(rewardAddress) {
299
- const result = await fetch(`${this.url}/accounts/${rewardAddress}`, {
390
+ async getRewardAccount(rewardAddress) {
391
+ const response = await fetch(`${this.url}/accounts/${rewardAddress}`, {
300
392
  headers: { project_id: this.projectId, lucid }
301
- }).then((res) => res.json());
302
- if (!result || result.error) {
303
- return { poolId: null, rewards: 0n };
393
+ });
394
+ if (response.status === 404) {
395
+ return { registered: false, poolId: null, rewards: 0n };
396
+ }
397
+ if (!response.ok) {
398
+ throw new Error(
399
+ `Could not fetch reward account from Blockfrost. Received status code: ${response.status}`
400
+ );
304
401
  }
402
+ const result = await response.json();
305
403
  return {
404
+ registered: result.active,
306
405
  poolId: result.pool_id || null,
307
406
  rewards: BigInt(result.withdrawable_amount)
308
407
  };
309
408
  }
409
+ async getDelegation(rewardAddress) {
410
+ const { poolId, rewards } = await this.getRewardAccount(rewardAddress);
411
+ return { poolId, rewards };
412
+ }
310
413
  async getDatum(datumHash) {
311
414
  const datum = await fetch(`${this.url}/scripts/datum/${datumHash}/cbor`, {
312
415
  headers: { project_id: this.projectId, lucid }
@@ -330,6 +433,29 @@ var Blockfrost = class {
330
433
  }, checkInterval);
331
434
  });
332
435
  }
436
+ async getTransactionStatus(txHash, options = {}) {
437
+ const response = await fetch(`${this.url}/txs/${txHash}`, {
438
+ headers: { project_id: this.projectId, lucid },
439
+ signal: options.signal
440
+ });
441
+ if (response.status === 404) return { status: "not_found", txHash };
442
+ if (!response.ok) {
443
+ throw new Error(
444
+ `Could not fetch transaction status from Blockfrost. Received status code: ${response.status}`
445
+ );
446
+ }
447
+ const result = await response.json();
448
+ return {
449
+ status: "confirmed",
450
+ txHash,
451
+ confirmation: {
452
+ txHash,
453
+ blockHash: result.block,
454
+ blockHeight: result.block_height,
455
+ slot: result.slot
456
+ }
457
+ };
458
+ }
333
459
  async submitTx(tx) {
334
460
  const result = await fetch(`${this.url}/tx/submit`, {
335
461
  method: "POST",
@@ -488,12 +614,28 @@ var JSONRPCErrorResponseSchema = import_effect2.Schema.Struct({
488
614
  var JSONRPCResponseSchema = (schema) => import_effect2.Schema.Union(JSONRPCSchema(schema), JSONRPCErrorResponseSchema).annotations({
489
615
  identifier: "JSONRPCResponseSchema"
490
616
  });
491
- var getJSONRPCResult = (response) => {
617
+ var getJSONRPCResult = (response, operation, transport) => {
492
618
  if ("error" in response) {
493
- const data = response.error.data === void 0 ? "" : `: ${JSON.stringify(response.error.data)}`;
494
- throw new Error(
495
- `Ogmios JSON-RPC error ${response.error.code}: ${response.error.message}${data}`
496
- );
619
+ throw new OgmiosJsonRpcError({
620
+ code: response.error.code,
621
+ message: response.error.message,
622
+ data: response.error.data,
623
+ method: response.method,
624
+ id: response.id,
625
+ operation,
626
+ status: transport?.status,
627
+ retryAfterMs: retryAfterHeaderToMs(transport?.headers["retry-after"]),
628
+ cause: transport
629
+ });
630
+ }
631
+ if (transport && (transport.status < 200 || transport.status >= 300)) {
632
+ throw new KupmiosError({
633
+ protocol: "ogmios",
634
+ operation: operation ?? response.method ?? "unknown",
635
+ status: transport.status,
636
+ retryAfterMs: retryAfterHeaderToMs(transport.headers["retry-after"]),
637
+ cause: transport
638
+ });
497
639
  }
498
640
  return response.result;
499
641
  };
@@ -636,7 +778,7 @@ var LegacyDelegationSummarySchema = import_effect2.Schema.Struct({
636
778
  deposit: RewardAccountAdaSchema
637
779
  });
638
780
  var RewardAccountSummarySchema = import_effect2.Schema.Struct({
639
- from: import_effect2.Schema.optional(import_effect2.Schema.Literal("key", "script")),
781
+ from: import_effect2.Schema.optional(import_effect2.Schema.Literal("key", "verificationKey", "script")),
640
782
  credential: import_effect2.Schema.optional(import_effect2.Schema.String),
641
783
  stakePool: import_effect2.Schema.optional(import_effect2.Schema.NullOr(import_effect2.Schema.Struct({ id: import_effect2.Schema.String }))),
642
784
  rewards: RewardAccountAdaSchema,
@@ -740,7 +882,17 @@ var ValueSchema = import_effect3.Schema.Struct({
740
882
  coins: QuantitySchema,
741
883
  assets: import_effect3.Schema.Record({ key: import_effect3.Schema.String, value: QuantitySchema })
742
884
  });
743
- var UTxOSchema = import_effect3.Schema.Struct({
885
+ var PointSchema = import_effect3.Schema.Struct({
886
+ slot_no: import_effect3.Schema.Number,
887
+ header_hash: import_effect3.Schema.String
888
+ });
889
+ var ScriptSchema = import_effect3.Schema.NullOr(
890
+ import_effect3.Schema.Struct({
891
+ language: import_effect3.Schema.Literal("native", "plutus:v1", "plutus:v2", "plutus:v3"),
892
+ script: import_effect3.Schema.String
893
+ })
894
+ );
895
+ var UTxOFields = {
744
896
  transaction_index: import_effect3.Schema.Number,
745
897
  transaction_id: import_effect3.Schema.String,
746
898
  output_index: import_effect3.Schema.Number,
@@ -749,23 +901,15 @@ var UTxOSchema = import_effect3.Schema.Struct({
749
901
  datum_hash: import_effect3.Schema.NullOr(import_effect3.Schema.String),
750
902
  datum_type: import_effect3.Schema.optional(import_effect3.Schema.Literal("hash", "inline")),
751
903
  script_hash: import_effect3.Schema.NullOr(import_effect3.Schema.String),
752
- created_at: import_effect3.Schema.Struct({
753
- slot_no: import_effect3.Schema.Number,
754
- header_hash: import_effect3.Schema.String
755
- }),
756
- spent_at: import_effect3.Schema.NullOr(
757
- import_effect3.Schema.Struct({
758
- slot_no: import_effect3.Schema.Number,
759
- header_hash: import_effect3.Schema.String
760
- })
761
- )
904
+ created_at: PointSchema,
905
+ spent_at: import_effect3.Schema.NullOr(PointSchema)
906
+ };
907
+ var UTxOSchema = import_effect3.Schema.Struct(UTxOFields);
908
+ var ResolvedUTxOSchema = import_effect3.Schema.Struct({
909
+ ...UTxOFields,
910
+ datum: import_effect3.Schema.NullOr(import_effect3.Schema.String),
911
+ script: ScriptSchema
762
912
  });
763
- var ScriptSchema = import_effect3.Schema.NullOr(
764
- import_effect3.Schema.Struct({
765
- language: import_effect3.Schema.Literal("native", "plutus:v1", "plutus:v2", "plutus:v3"),
766
- script: import_effect3.Schema.String
767
- })
768
- );
769
913
  var DatumSchema = import_effect3.Schema.NullOr(import_effect3.Schema.Struct({ datum: import_effect3.Schema.String }));
770
914
  var DelegationSchema = import_effect3.Schema.NullOr(
771
915
  import_effect3.Schema.Record({
@@ -827,6 +971,33 @@ var makePostAsJson = (url, data, schema, headers) => (0, import_effect4.pipe)(
827
971
  // Prevents resource leaks and ensures clean request termination
828
972
  import_effect4.Effect.scoped
829
973
  );
974
+ var makePostAsJsonResponse = (url, data, schema, headers) => (0, import_effect4.pipe)(
975
+ import_platform.HttpClientRequest.post(url),
976
+ headers ? import_platform.HttpClientRequest.setHeaders(headers) : import_effect4.identity,
977
+ import_platform.HttpClientRequest.bodyJson(data),
978
+ import_effect4.Effect.flatMap(import_platform.HttpClient.execute),
979
+ import_effect4.Effect.flatMap(
980
+ (response) => (0, import_effect4.pipe)(
981
+ import_platform.HttpClientResponse.schemaBodyJson(schema)(response),
982
+ import_effect4.Effect.map((body) => ({
983
+ body,
984
+ status: response.status,
985
+ headers: response.headers
986
+ })),
987
+ import_effect4.Effect.catchAll(
988
+ (cause) => response.status >= 200 && response.status < 300 ? import_effect4.Effect.fail(cause) : import_effect4.Effect.fail(
989
+ new import_platform.HttpClientError.ResponseError({
990
+ response,
991
+ request: response.request,
992
+ reason: "StatusCode",
993
+ description: "non 2xx status code with an invalid JSON response"
994
+ })
995
+ )
996
+ )
997
+ )
998
+ ),
999
+ import_effect4.Effect.scoped
1000
+ );
830
1001
  var makePostAsUint8Array = (url, data, schema, headers) => (0, import_effect4.pipe)(
831
1002
  // Initiate a POST request to the specified URL
832
1003
  import_platform.HttpClientRequest.post(url),
@@ -848,19 +1019,50 @@ var makePostAsUint8Array = (url, data, schema, headers) => (0, import_effect4.pi
848
1019
 
849
1020
  // src/kupmios.ts
850
1021
  var import_platform2 = require("@effect/platform");
851
- var KupmiosError = class extends import_effect6.Data.TaggedError("KupmiosError") {
852
- get message() {
853
- return `${this.cause}`;
1022
+ var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
1023
+ var DEFAULT_AWAIT_TX_TIMEOUT_MS = 16e4;
1024
+ var validateTimeout = (name, timeout) => {
1025
+ if (!Number.isFinite(timeout) || timeout <= 0) {
1026
+ throw new TypeError(`${name} must be a positive finite number.`);
854
1027
  }
1028
+ return timeout;
1029
+ };
1030
+ var catchProviderError = (protocol, operation) => (effect) => import_effect6.Effect.catchAll(
1031
+ effect,
1032
+ (cause) => import_effect6.Effect.fail(toKupmiosError(cause, protocol, operation))
1033
+ );
1034
+ var runProviderEffect = async (effect, protocol, operation, signal) => {
1035
+ const exit = await import_effect6.Effect.runPromiseExit(effect, { signal });
1036
+ if (import_effect6.Exit.isSuccess(exit)) return exit.value;
1037
+ if (signal?.aborted) {
1038
+ throw new KupmiosError({
1039
+ protocol,
1040
+ operation,
1041
+ kind: "aborted",
1042
+ retryable: false,
1043
+ cause: signal.reason ?? import_effect6.Cause.squash(exit.cause)
1044
+ });
1045
+ }
1046
+ throw toKupmiosError(import_effect6.Cause.squash(exit.cause), protocol, operation);
855
1047
  };
856
1048
  var Kupmios = class {
857
1049
  kupoUrl;
858
1050
  ogmiosUrl;
859
- headers;
860
- constructor(kupoUrl, ogmiosUrl, headers) {
1051
+ options;
1052
+ requestTimeoutMs;
1053
+ awaitTxTimeoutMs;
1054
+ constructor(kupoUrl, ogmiosUrl, options = {}) {
861
1055
  this.kupoUrl = kupoUrl;
862
1056
  this.ogmiosUrl = ogmiosUrl;
863
- this.headers = headers;
1057
+ this.options = options;
1058
+ this.requestTimeoutMs = validateTimeout(
1059
+ "requestTimeoutMs",
1060
+ options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS
1061
+ );
1062
+ this.awaitTxTimeoutMs = validateTimeout(
1063
+ "awaitTxTimeoutMs",
1064
+ options.awaitTxTimeoutMs ?? DEFAULT_AWAIT_TX_TIMEOUT_MS
1065
+ );
864
1066
  }
865
1067
  async getProtocolParameters() {
866
1068
  const data = {
@@ -872,19 +1074,26 @@ var Kupmios = class {
872
1074
  const schema = JSONRPCResponseSchema(
873
1075
  import_effect5.Schema.Record({ key: import_effect5.Schema.String, value: import_effect5.Schema.Unknown })
874
1076
  );
875
- const response = await (0, import_effect6.pipe)(
876
- makePostAsJson(
877
- this.ogmiosUrl,
878
- data,
879
- schema,
880
- this.headers?.ogmiosHeader
1077
+ const response = await runProviderEffect(
1078
+ (0, import_effect6.pipe)(
1079
+ makePostAsJsonResponse(
1080
+ this.ogmiosUrl,
1081
+ data,
1082
+ schema,
1083
+ this.options.ogmiosHeader
1084
+ ),
1085
+ import_effect6.Effect.timeout(this.requestTimeoutMs),
1086
+ catchProviderError("ogmios", "queryLedgerState/protocolParameters"),
1087
+ import_effect6.Effect.provide(import_platform2.FetchHttpClient.layer)
881
1088
  ),
882
- import_effect6.Effect.timeout(1e4),
883
- import_effect6.Effect.catchAll((cause) => new KupmiosError({ cause })),
884
- import_effect6.Effect.provide(import_platform2.FetchHttpClient.layer),
885
- import_effect6.Effect.runPromise
1089
+ "ogmios",
1090
+ "queryLedgerState/protocolParameters"
1091
+ );
1092
+ const result = getJSONRPCResult(
1093
+ response.body,
1094
+ data.method,
1095
+ response
886
1096
  );
887
- const result = getJSONRPCResult(response);
888
1097
  const protocolParameters = import_effect5.Schema.decodeUnknownSync(
889
1098
  ProtocolParametersSchema
890
1099
  )(normalizeProtocolParameters(result));
@@ -900,35 +1109,43 @@ var Kupmios = class {
900
1109
  const schema = JSONRPCResponseSchema(
901
1110
  TreasuryAndReservesSchema
902
1111
  );
903
- const response = await (0, import_effect6.pipe)(
904
- makePostAsJson(
905
- this.ogmiosUrl,
906
- data,
907
- schema,
908
- this.headers?.ogmiosHeader
1112
+ const response = await runProviderEffect(
1113
+ (0, import_effect6.pipe)(
1114
+ makePostAsJsonResponse(
1115
+ this.ogmiosUrl,
1116
+ data,
1117
+ schema,
1118
+ this.options.ogmiosHeader
1119
+ ),
1120
+ import_effect6.Effect.timeout(this.requestTimeoutMs),
1121
+ catchProviderError("ogmios", "queryLedgerState/treasuryAndReserves"),
1122
+ import_effect6.Effect.provide(import_platform2.FetchHttpClient.layer)
909
1123
  ),
910
- import_effect6.Effect.timeout(1e4),
911
- import_effect6.Effect.catchAll((cause) => new KupmiosError({ cause })),
912
- import_effect6.Effect.provide(import_platform2.FetchHttpClient.layer),
913
- import_effect6.Effect.runPromise
1124
+ "ogmios",
1125
+ "queryLedgerState/treasuryAndReserves"
1126
+ );
1127
+ const result = getJSONRPCResult(
1128
+ response.body,
1129
+ data.method,
1130
+ response
914
1131
  );
915
- const result = getJSONRPCResult(response);
916
1132
  return lovelaceAmountToBigInt(result.treasury.ada.lovelace);
917
1133
  }
918
1134
  async getUtxos(addressOrCredential) {
919
1135
  const isAddress = typeof addressOrCredential === "string";
920
1136
  const queryPredicate = isAddress ? addressOrCredential : addressOrCredential.hash;
921
- const pattern = `${this.kupoUrl}/matches/${queryPredicate}${isAddress ? "" : "/*"}?unspent`;
922
- const schema = import_effect5.Schema.Array(UTxOSchema);
923
- const utxos = await (0, import_effect6.pipe)(
924
- makeGet(pattern, schema, this.headers?.kupoHeader),
925
- import_effect6.Effect.flatMap(
926
- (u) => kupmiosUtxosToUtxos(this.kupoUrl, u, this.headers?.kupoHeader)
1137
+ const pattern = `${this.kupoUrl}/matches/${queryPredicate}${isAddress ? "" : "/*"}?unspent&resolve_hashes`;
1138
+ const schema = import_effect5.Schema.Array(ResolvedUTxOSchema);
1139
+ const utxos = await runProviderEffect(
1140
+ (0, import_effect6.pipe)(
1141
+ makeGet(pattern, schema, this.options.kupoHeader),
1142
+ import_effect6.Effect.map(kupmiosUtxosToUtxos),
1143
+ import_effect6.Effect.timeout(this.requestTimeoutMs),
1144
+ catchProviderError("kupo", "getUtxos"),
1145
+ import_effect6.Effect.provide(import_platform2.FetchHttpClient.layer)
927
1146
  ),
928
- import_effect6.Effect.timeout(1e4),
929
- import_effect6.Effect.catchAll((cause) => new KupmiosError({ cause })),
930
- import_effect6.Effect.provide(import_platform2.FetchHttpClient.layer),
931
- import_effect6.Effect.runPromise
1147
+ "kupo",
1148
+ "getUtxos"
932
1149
  );
933
1150
  return utxos;
934
1151
  }
@@ -936,33 +1153,58 @@ var Kupmios = class {
936
1153
  const isAddress = typeof addressOrCredential === "string";
937
1154
  const queryPredicate = isAddress ? addressOrCredential : addressOrCredential.hash;
938
1155
  const { policyId, assetName } = (0, import_utils4.fromUnit)(unit);
939
- const pattern = `${this.kupoUrl}/matches/${queryPredicate}${isAddress ? "" : "/*"}?unspent&policy_id=${policyId}${assetName ? `&asset_name=${assetName}` : ""}`;
940
- const schema = import_effect5.Schema.Array(UTxOSchema);
941
- const utxos = await (0, import_effect6.pipe)(
942
- makeGet(pattern, schema, this.headers?.kupoHeader),
943
- import_effect6.Effect.flatMap(
944
- (u) => kupmiosUtxosToUtxos(this.kupoUrl, u, this.headers?.kupoHeader)
1156
+ const pattern = `${this.kupoUrl}/matches/${queryPredicate}${isAddress ? "" : "/*"}?unspent&resolve_hashes&policy_id=${policyId}${assetName ? `&asset_name=${assetName}` : ""}`;
1157
+ const schema = import_effect5.Schema.Array(ResolvedUTxOSchema);
1158
+ const utxos = await runProviderEffect(
1159
+ (0, import_effect6.pipe)(
1160
+ makeGet(pattern, schema, this.options.kupoHeader),
1161
+ import_effect6.Effect.map(kupmiosUtxosToUtxos),
1162
+ import_effect6.Effect.timeout(this.requestTimeoutMs),
1163
+ catchProviderError("kupo", "getUtxosWithUnit"),
1164
+ import_effect6.Effect.provide(import_platform2.FetchHttpClient.layer)
945
1165
  ),
946
- import_effect6.Effect.timeout(1e4),
947
- import_effect6.Effect.catchAll((cause) => new KupmiosError({ cause })),
948
- import_effect6.Effect.provide(import_platform2.FetchHttpClient.layer),
949
- import_effect6.Effect.runPromise
1166
+ "kupo",
1167
+ "getUtxosWithUnit"
1168
+ );
1169
+ return utxos.filter((utxo) => (utxo.assets[unit] ?? 0n) > 0n);
1170
+ }
1171
+ async getUtxosWithPolicy(addressOrCredential, policyId) {
1172
+ if (!/^[0-9a-f]{56}$/i.test(policyId)) {
1173
+ throw new TypeError(
1174
+ "policyId must be a 56-character hexadecimal string."
1175
+ );
1176
+ }
1177
+ const normalizedPolicyId = policyId.toLowerCase();
1178
+ const isAddress = typeof addressOrCredential === "string";
1179
+ const queryPredicate = isAddress ? addressOrCredential : addressOrCredential.hash;
1180
+ const pattern = `${this.kupoUrl}/matches/${queryPredicate}${isAddress ? "" : "/*"}?unspent&resolve_hashes&policy_id=${normalizedPolicyId}`;
1181
+ const schema = import_effect5.Schema.Array(ResolvedUTxOSchema);
1182
+ return runProviderEffect(
1183
+ (0, import_effect6.pipe)(
1184
+ makeGet(pattern, schema, this.options.kupoHeader),
1185
+ import_effect6.Effect.map(kupmiosUtxosToUtxos),
1186
+ import_effect6.Effect.timeout(this.requestTimeoutMs),
1187
+ catchProviderError("kupo", "getUtxosWithPolicy"),
1188
+ import_effect6.Effect.provide(import_platform2.FetchHttpClient.layer)
1189
+ ),
1190
+ "kupo",
1191
+ "getUtxosWithPolicy"
950
1192
  );
951
- return utxos;
952
1193
  }
953
1194
  async getUtxoByUnit(unit) {
954
1195
  const { policyId, assetName } = (0, import_utils4.fromUnit)(unit);
955
- const pattern = `${this.kupoUrl}/matches/${policyId}.${assetName ? `${assetName}` : "*"}?unspent`;
956
- const schema = import_effect5.Schema.Array(UTxOSchema);
957
- const utxos = await (0, import_effect6.pipe)(
958
- makeGet(pattern, schema, this.headers?.kupoHeader),
959
- import_effect6.Effect.flatMap(
960
- (u) => kupmiosUtxosToUtxos(this.kupoUrl, u, this.headers?.kupoHeader)
1196
+ const pattern = `${this.kupoUrl}/matches/${policyId}.${assetName ?? ""}?unspent&resolve_hashes`;
1197
+ const schema = import_effect5.Schema.Array(ResolvedUTxOSchema);
1198
+ const utxos = await runProviderEffect(
1199
+ (0, import_effect6.pipe)(
1200
+ makeGet(pattern, schema, this.options.kupoHeader),
1201
+ import_effect6.Effect.map(kupmiosUtxosToUtxos),
1202
+ import_effect6.Effect.timeout(this.requestTimeoutMs),
1203
+ catchProviderError("kupo", "getUtxoByUnit"),
1204
+ import_effect6.Effect.provide(import_platform2.FetchHttpClient.layer)
961
1205
  ),
962
- import_effect6.Effect.timeout(1e4),
963
- import_effect6.Effect.catchAll((cause) => new KupmiosError({ cause })),
964
- import_effect6.Effect.provide(import_platform2.FetchHttpClient.layer),
965
- import_effect6.Effect.runPromise
1206
+ "kupo",
1207
+ "getUtxoByUnit"
966
1208
  );
967
1209
  if (utxos.length === 0) {
968
1210
  throw new Error("Unit not found.");
@@ -976,21 +1218,21 @@ var Kupmios = class {
976
1218
  const queryHashes = [
977
1219
  ...new Set(outRefs.map((outRef) => outRef.txHash))
978
1220
  ];
979
- const mkPattern = (txHash) => `${this.kupoUrl}/matches/*@${txHash}?unspent`;
980
- const schema = import_effect5.Schema.Array(UTxOSchema);
1221
+ const mkPattern = (txHash) => `${this.kupoUrl}/matches/*@${txHash}?unspent&resolve_hashes`;
1222
+ const schema = import_effect5.Schema.Array(ResolvedUTxOSchema);
981
1223
  const program = import_effect6.Effect.forEach(
982
1224
  queryHashes,
983
1225
  (txHash) => (0, import_effect6.pipe)(
984
- makeGet(mkPattern(txHash), schema, this.headers?.kupoHeader),
985
- import_effect6.Effect.flatMap(
986
- (u) => kupmiosUtxosToUtxos(this.kupoUrl, u, this.headers?.kupoHeader)
987
- ),
988
- import_effect6.Effect.timeout(1e4),
989
- import_effect6.Effect.catchAll((cause) => new KupmiosError({ cause }))
1226
+ makeGet(mkPattern(txHash), schema, this.options.kupoHeader),
1227
+ import_effect6.Effect.map(kupmiosUtxosToUtxos),
1228
+ import_effect6.Effect.timeout(this.requestTimeoutMs),
1229
+ catchProviderError("kupo", "getUtxosByOutRef")
990
1230
  )
991
1231
  );
992
- const utxos = await import_effect6.Effect.runPromise(
993
- (0, import_effect6.pipe)(program, import_effect6.Effect.provide(import_platform2.FetchHttpClient.layer))
1232
+ const utxos = await runProviderEffect(
1233
+ (0, import_effect6.pipe)(program, import_effect6.Effect.provide(import_platform2.FetchHttpClient.layer)),
1234
+ "kupo",
1235
+ "getUtxosByOutRef"
994
1236
  );
995
1237
  return import_effect6.Array.flatten(utxos).filter(
996
1238
  (utxo) => outRefs.some(
@@ -998,7 +1240,7 @@ var Kupmios = class {
998
1240
  )
999
1241
  );
1000
1242
  }
1001
- async getDelegation(rewardAddress) {
1243
+ async getRewardAccount(rewardAddress) {
1002
1244
  const data = {
1003
1245
  jsonrpc: "2.0",
1004
1246
  method: "queryLedgerState/rewardAccountSummaries",
@@ -1006,50 +1248,95 @@ var Kupmios = class {
1006
1248
  id: null
1007
1249
  };
1008
1250
  const schema = JSONRPCResponseSchema(Delegation);
1009
- const response = await (0, import_effect6.pipe)(
1010
- makePostAsJson(
1011
- this.ogmiosUrl,
1012
- data,
1013
- schema,
1014
- this.headers?.ogmiosHeader
1251
+ const response = await runProviderEffect(
1252
+ (0, import_effect6.pipe)(
1253
+ makePostAsJsonResponse(
1254
+ this.ogmiosUrl,
1255
+ data,
1256
+ schema,
1257
+ this.options.ogmiosHeader
1258
+ ),
1259
+ import_effect6.Effect.provide(import_platform2.FetchHttpClient.layer),
1260
+ import_effect6.Effect.timeout(this.requestTimeoutMs),
1261
+ catchProviderError("ogmios", "queryLedgerState/rewardAccountSummaries")
1015
1262
  ),
1016
- import_effect6.Effect.provide(import_platform2.FetchHttpClient.layer),
1017
- import_effect6.Effect.timeout(1e4),
1018
- import_effect6.Effect.catchAll((cause) => new KupmiosError({ cause })),
1019
- import_effect6.Effect.runPromise
1263
+ "ogmios",
1264
+ "queryLedgerState/rewardAccountSummaries"
1265
+ );
1266
+ const result = getJSONRPCResult(
1267
+ response.body,
1268
+ data.method,
1269
+ response
1020
1270
  );
1021
- const result = getJSONRPCResult(response);
1022
- return toDelegation(result);
1271
+ return toRewardAccountState(result);
1272
+ }
1273
+ async getDelegation(rewardAddress) {
1274
+ const { poolId, rewards } = await this.getRewardAccount(rewardAddress);
1275
+ return { poolId, rewards };
1023
1276
  }
1024
1277
  async getDatum(datumHash) {
1025
1278
  const pattern = `${this.kupoUrl}/datums/${datumHash}`;
1026
1279
  const schema = DatumSchema;
1027
- const result = await (0, import_effect6.pipe)(
1028
- makeGet(pattern, schema, this.headers?.kupoHeader),
1029
- import_effect6.Effect.provide(import_platform2.FetchHttpClient.layer),
1030
- import_effect6.Effect.timeout(1e4),
1031
- import_effect6.Effect.flatMap(import_effect6.Effect.fromNullable),
1032
- import_effect6.Effect.catchAll((cause) => new KupmiosError({ cause })),
1033
- import_effect6.Effect.runPromise
1280
+ const result = await runProviderEffect(
1281
+ (0, import_effect6.pipe)(
1282
+ makeGet(pattern, schema, this.options.kupoHeader),
1283
+ import_effect6.Effect.provide(import_platform2.FetchHttpClient.layer),
1284
+ import_effect6.Effect.timeout(this.requestTimeoutMs),
1285
+ import_effect6.Effect.flatMap(import_effect6.Effect.fromNullable),
1286
+ catchProviderError("kupo", "getDatum")
1287
+ ),
1288
+ "kupo",
1289
+ "getDatum"
1034
1290
  );
1035
1291
  return result.datum;
1036
1292
  }
1293
+ async getTransactionStatus(txHash, options = {}) {
1294
+ const pattern = `${this.kupoUrl}/matches/*@${txHash}`;
1295
+ const schema = import_effect5.Schema.Array(UTxOSchema).annotations({
1296
+ identifier: "Array<KupmiosSchema.KupoUTxO>"
1297
+ });
1298
+ const matches = await runProviderEffect(
1299
+ (0, import_effect6.pipe)(
1300
+ makeGet(pattern, schema, this.options.kupoHeader),
1301
+ import_effect6.Effect.timeout(this.requestTimeoutMs),
1302
+ catchProviderError("kupo", "getTransactionStatus"),
1303
+ import_effect6.Effect.provide(import_platform2.FetchHttpClient.layer)
1304
+ ),
1305
+ "kupo",
1306
+ "getTransactionStatus",
1307
+ options.signal
1308
+ );
1309
+ if (matches.length === 0) return { status: "not_found", txHash };
1310
+ const createdAt = matches[0].created_at;
1311
+ return {
1312
+ status: "confirmed",
1313
+ txHash,
1314
+ confirmation: {
1315
+ txHash,
1316
+ blockHash: createdAt.header_hash,
1317
+ slot: createdAt.slot_no
1318
+ }
1319
+ };
1320
+ }
1037
1321
  async awaitTx(txHash, checkInterval = 2e4) {
1038
- const pattern = `${this.kupoUrl}/matches/*@${txHash}?unspent`;
1322
+ const pattern = `${this.kupoUrl}/matches/*@${txHash}`;
1039
1323
  const schema = import_effect5.Schema.Array(UTxOSchema).annotations({
1040
1324
  identifier: "Array<KupmiosSchema.KupoUTxO>"
1041
1325
  });
1042
- const result = await (0, import_effect6.pipe)(
1043
- makeGet(pattern, schema, this.headers?.kupoHeader),
1044
- import_effect6.Effect.provide(import_platform2.FetchHttpClient.layer),
1045
- import_effect6.Effect.repeat({
1046
- schedule: import_effect6.Schedule.exponential(checkInterval),
1047
- until: (result2) => result2.length > 0
1048
- }),
1049
- import_effect6.Effect.timeout(16e4),
1050
- import_effect6.Effect.catchAll((cause) => new KupmiosError({ cause })),
1051
- import_effect6.Effect.as(true),
1052
- import_effect6.Effect.runPromise
1326
+ const result = await runProviderEffect(
1327
+ (0, import_effect6.pipe)(
1328
+ makeGet(pattern, schema, this.options.kupoHeader),
1329
+ import_effect6.Effect.provide(import_platform2.FetchHttpClient.layer),
1330
+ import_effect6.Effect.repeat({
1331
+ schedule: import_effect6.Schedule.exponential(checkInterval),
1332
+ until: (result2) => result2.length > 0
1333
+ }),
1334
+ import_effect6.Effect.timeout(this.awaitTxTimeoutMs),
1335
+ catchProviderError("kupo", "awaitTx"),
1336
+ import_effect6.Effect.as(true)
1337
+ ),
1338
+ "kupo",
1339
+ "awaitTx"
1053
1340
  );
1054
1341
  return result;
1055
1342
  }
@@ -1069,19 +1356,26 @@ var Kupmios = class {
1069
1356
  })
1070
1357
  })
1071
1358
  );
1072
- const response = await (0, import_effect6.pipe)(
1073
- makePostAsJson(
1074
- this.ogmiosUrl,
1075
- data,
1076
- schema,
1077
- this.headers?.ogmiosHeader
1359
+ const response = await runProviderEffect(
1360
+ (0, import_effect6.pipe)(
1361
+ makePostAsJsonResponse(
1362
+ this.ogmiosUrl,
1363
+ data,
1364
+ schema,
1365
+ this.options.ogmiosHeader
1366
+ ),
1367
+ import_effect6.Effect.provide(import_platform2.FetchHttpClient.layer),
1368
+ import_effect6.Effect.timeout(this.requestTimeoutMs),
1369
+ catchProviderError("ogmios", "submitTransaction")
1078
1370
  ),
1079
- import_effect6.Effect.provide(import_platform2.FetchHttpClient.layer),
1080
- import_effect6.Effect.timeout(1e4),
1081
- import_effect6.Effect.catchAll((cause) => new KupmiosError({ cause })),
1082
- import_effect6.Effect.runPromise
1371
+ "ogmios",
1372
+ "submitTransaction"
1373
+ );
1374
+ const result = getJSONRPCResult(
1375
+ response.body,
1376
+ data.method,
1377
+ response
1083
1378
  );
1084
- const result = getJSONRPCResult(response);
1085
1379
  return result.transaction.id;
1086
1380
  }
1087
1381
  async evaluateTx(tx, additionalUTxOs) {
@@ -1095,19 +1389,26 @@ var Kupmios = class {
1095
1389
  id: null
1096
1390
  };
1097
1391
  const schema = JSONRPCResponseSchema(import_effect5.Schema.Array(RedeemerSchema));
1098
- const response = await (0, import_effect6.pipe)(
1099
- makePostAsJson(
1100
- this.ogmiosUrl,
1101
- data,
1102
- schema,
1103
- this.headers?.ogmiosHeader
1392
+ const response = await runProviderEffect(
1393
+ (0, import_effect6.pipe)(
1394
+ makePostAsJsonResponse(
1395
+ this.ogmiosUrl,
1396
+ data,
1397
+ schema,
1398
+ this.options.ogmiosHeader
1399
+ ),
1400
+ import_effect6.Effect.provide(import_platform2.FetchHttpClient.layer),
1401
+ import_effect6.Effect.timeout(this.requestTimeoutMs),
1402
+ catchProviderError("ogmios", "evaluateTransaction")
1104
1403
  ),
1105
- import_effect6.Effect.provide(import_platform2.FetchHttpClient.layer),
1106
- import_effect6.Effect.timeout(1e4),
1107
- import_effect6.Effect.catchAll((cause) => new KupmiosError({ cause })),
1108
- import_effect6.Effect.runPromise
1404
+ "ogmios",
1405
+ "evaluateTransaction"
1406
+ );
1407
+ const result = getJSONRPCResult(
1408
+ response.body,
1409
+ data.method,
1410
+ response
1109
1411
  );
1110
- const result = getJSONRPCResult(response);
1111
1412
  const evalRedeemers = result.map((item) => ({
1112
1413
  ex_units: {
1113
1414
  mem: item.budget.memory,
@@ -1119,59 +1420,6 @@ var Kupmios = class {
1119
1420
  return evalRedeemers;
1120
1421
  }
1121
1422
  };
1122
- var getDatumEffect = (kupoUrl, datum_type, datum_hash, kupoHeader) => import_effect6.Effect.gen(function* () {
1123
- if (datum_type === "inline" && datum_hash) {
1124
- const pattern = `${kupoUrl}/datums/${datum_hash}`;
1125
- const schema = DatumSchema;
1126
- return yield* (0, import_effect6.pipe)(
1127
- makeGet(pattern, schema, kupoHeader),
1128
- import_effect6.Effect.flatMap(import_effect6.Effect.fromNullable),
1129
- import_effect6.Effect.map((result) => result.datum),
1130
- import_effect6.Effect.retry(
1131
- import_effect6.Schedule.compose(import_effect6.Schedule.exponential(50), import_effect6.Schedule.recurs(5))
1132
- ),
1133
- import_effect6.Effect.timeout(5e3)
1134
- );
1135
- } else return void 0;
1136
- });
1137
- var getScriptEffect = (kupoUrl, script_hash, kupoHeader) => import_effect6.Effect.gen(function* () {
1138
- if (script_hash) {
1139
- const pattern = `${kupoUrl}/scripts/${script_hash}`;
1140
- const schema = ScriptSchema;
1141
- return yield* (0, import_effect6.pipe)(
1142
- makeGet(pattern, schema, kupoHeader),
1143
- import_effect6.Effect.flatMap(import_effect6.Effect.fromNullable),
1144
- import_effect6.Effect.retry(
1145
- import_effect6.Schedule.compose(import_effect6.Schedule.exponential(50), import_effect6.Schedule.recurs(5))
1146
- ),
1147
- import_effect6.Effect.timeout(5e3),
1148
- import_effect6.Effect.map(({ language, script }) => {
1149
- switch (language) {
1150
- case "native":
1151
- return {
1152
- type: "Native",
1153
- script
1154
- };
1155
- case "plutus:v1":
1156
- return {
1157
- type: "PlutusV1",
1158
- script: (0, import_utils4.applyDoubleCborEncoding)(script)
1159
- };
1160
- case "plutus:v2":
1161
- return {
1162
- type: "PlutusV2",
1163
- script: (0, import_utils4.applyDoubleCborEncoding)(script)
1164
- };
1165
- case "plutus:v3":
1166
- return {
1167
- type: "PlutusV3",
1168
- script: (0, import_utils4.applyDoubleCborEncoding)(script)
1169
- };
1170
- }
1171
- })
1172
- );
1173
- } else return void 0;
1174
- });
1175
1423
  var toAssets = (value) => {
1176
1424
  const assets = { lovelace: BigInt(value.coins) };
1177
1425
  for (const unit of Object.keys(value.assets)) {
@@ -1209,48 +1457,60 @@ var toProtocolParameters = (result) => {
1209
1457
  }
1210
1458
  };
1211
1459
  };
1212
- var toDelegation = (result) => {
1213
- if (!result) {
1214
- return { poolId: null, rewards: 0n };
1215
- }
1216
- const delegation = Array.isArray(result) ? result[0] : Object.values(result)[0];
1460
+ var toRewardAccountState = (result) => {
1461
+ const delegation = result ? Array.isArray(result) ? result[0] : Object.values(result)[0] : void 0;
1217
1462
  if (!delegation) {
1218
- return { poolId: null, rewards: 0n };
1463
+ return { registered: false, poolId: null, rewards: 0n };
1219
1464
  }
1220
1465
  return {
1466
+ registered: true,
1221
1467
  poolId: "stakePool" in delegation ? delegation.stakePool?.id || null : delegation.delegate?.id || null,
1222
1468
  rewards: BigInt(delegation.rewards.ada.lovelace)
1223
1469
  };
1224
1470
  };
1225
- var kupmiosUtxosToUtxos = (kupoURL, utxos, kupoHeader) => import_effect6.Effect.forEach(
1226
- utxos,
1227
- (utxo) => {
1228
- return (0, import_effect6.pipe)(
1229
- import_effect6.Effect.all([
1230
- getDatumEffect(kupoURL, utxo.datum_type, utxo.datum_hash, kupoHeader),
1231
- getScriptEffect(kupoURL, utxo.script_hash, kupoHeader)
1232
- ]),
1233
- import_effect6.Effect.map(
1234
- ([datum, script]) => ({
1235
- txHash: utxo.transaction_id,
1236
- outputIndex: utxo.output_index,
1237
- address: utxo.address,
1238
- assets: toAssets(utxo.value),
1239
- datumHash: utxo.datum_type === "hash" ? utxo.datum_hash : void 0,
1240
- datum,
1241
- scriptRef: script
1242
- })
1243
- )
1244
- );
1245
- },
1246
- { concurrency: "unbounded" }
1247
- );
1471
+ var toScriptRef = (script) => {
1472
+ if (!script) return void 0;
1473
+ switch (script.language) {
1474
+ case "native":
1475
+ return { type: "Native", script: script.script };
1476
+ case "plutus:v1":
1477
+ return {
1478
+ type: "PlutusV1",
1479
+ script: (0, import_utils4.applyDoubleCborEncoding)(script.script)
1480
+ };
1481
+ case "plutus:v2":
1482
+ return {
1483
+ type: "PlutusV2",
1484
+ script: (0, import_utils4.applyDoubleCborEncoding)(script.script)
1485
+ };
1486
+ case "plutus:v3":
1487
+ return {
1488
+ type: "PlutusV3",
1489
+ script: (0, import_utils4.applyDoubleCborEncoding)(script.script)
1490
+ };
1491
+ }
1492
+ };
1493
+ var kupmiosUtxosToUtxos = (utxos) => utxos.map((utxo) => ({
1494
+ txHash: utxo.transaction_id,
1495
+ outputIndex: utxo.output_index,
1496
+ address: utxo.address,
1497
+ assets: toAssets(utxo.value),
1498
+ datumHash: utxo.datum_type === "hash" ? utxo.datum_hash : void 0,
1499
+ datum: utxo.datum_type === "inline" ? utxo.datum : void 0,
1500
+ scriptRef: toScriptRef(utxo.script)
1501
+ }));
1248
1502
 
1249
1503
  // src/emulator.ts
1250
1504
  var import_utils5 = require("@lucid-evolution/utils");
1251
1505
  var import_utils6 = require("@lucid-evolution/utils");
1252
1506
  var import_core_utils2 = require("@lucid-evolution/core-utils");
1253
1507
  var import_wallet = require("@lucid-evolution/wallet");
1508
+ var EMULATOR_PROVIDER_BRAND = Symbol.for(
1509
+ "@lucid-evolution/provider/Emulator"
1510
+ );
1511
+ var isEmulatorProvider = (provider) => Boolean(
1512
+ provider && provider[EMULATOR_PROVIDER_BRAND]
1513
+ );
1254
1514
  function generateEmulatorAccountFromPrivateKey(assets) {
1255
1515
  const privateKey = CML.PrivateKey.generate_ed25519().to_bech32();
1256
1516
  const priv = CML.PrivateKey.from_bech32(privateKey);
@@ -1280,6 +1540,7 @@ function generateEmulatorAccount(assets) {
1280
1540
  };
1281
1541
  }
1282
1542
  var Emulator = class {
1543
+ [EMULATOR_PROVIDER_BRAND] = true;
1283
1544
  ledger;
1284
1545
  mempool = {};
1285
1546
  /**
@@ -1293,6 +1554,7 @@ var Emulator = class {
1293
1554
  protocolParameters;
1294
1555
  datumTable = {};
1295
1556
  treasury;
1557
+ transactionHistory = {};
1296
1558
  constructor(accounts, protocolParameters = import_utils5.PROTOCOL_PARAMETERS_DEFAULT, treasury = 0n) {
1297
1559
  const GENESIS_HASH = "00".repeat(32);
1298
1560
  this.blockHeight = 0;
@@ -1328,12 +1590,27 @@ var Emulator = class {
1328
1590
  now() {
1329
1591
  return this.time;
1330
1592
  }
1593
+ confirmPendingTransactions(blockHeight, slot) {
1594
+ for (const [txHash, status] of Object.entries(this.transactionHistory)) {
1595
+ if (status.status === "pending") {
1596
+ this.transactionHistory[txHash] = {
1597
+ status: "confirmed",
1598
+ blockHeight,
1599
+ slot
1600
+ };
1601
+ }
1602
+ }
1603
+ }
1331
1604
  awaitSlot(length = 1) {
1332
1605
  this.slot += length;
1333
1606
  this.time += length * 1e3;
1334
1607
  const currentHeight = this.blockHeight;
1335
1608
  this.blockHeight = Math.floor(this.slot / 20);
1336
1609
  if (this.blockHeight > currentHeight) {
1610
+ this.confirmPendingTransactions(
1611
+ currentHeight + 1,
1612
+ (currentHeight + 1) * 20
1613
+ );
1337
1614
  for (const [outRef, { utxo, spent }] of Object.entries(this.mempool)) {
1338
1615
  this.ledger[outRef] = { utxo, spent };
1339
1616
  }
@@ -1344,9 +1621,14 @@ var Emulator = class {
1344
1621
  }
1345
1622
  }
1346
1623
  awaitBlock(height = 1) {
1624
+ const previousHeight = this.blockHeight;
1625
+ const previousSlot = this.slot;
1347
1626
  this.blockHeight += height;
1348
1627
  this.slot += height * 20;
1349
1628
  this.time += height * 20 * 1e3;
1629
+ if (height > 0) {
1630
+ this.confirmPendingTransactions(previousHeight + 1, previousSlot + 20);
1631
+ }
1350
1632
  for (const [outRef, { utxo, spent }] of Object.entries(this.mempool)) {
1351
1633
  this.ledger[outRef] = { utxo, spent };
1352
1634
  }
@@ -1356,14 +1638,17 @@ var Emulator = class {
1356
1638
  this.mempool = {};
1357
1639
  }
1358
1640
  getUtxos(addressOrCredential) {
1359
- const utxos = Object.values(this.ledger).flatMap(({ utxo }) => {
1360
- if (typeof addressOrCredential === "string") {
1361
- return addressOrCredential === utxo.address ? utxo : [];
1362
- } else {
1363
- const { paymentCredential } = (0, import_utils6.getAddressDetails)(utxo.address);
1364
- return paymentCredential?.hash === addressOrCredential.hash ? utxo : [];
1641
+ const utxos = Object.values(this.ledger).flatMap(
1642
+ ({ utxo, spent }) => {
1643
+ if (spent) return [];
1644
+ if (typeof addressOrCredential === "string") {
1645
+ return addressOrCredential === utxo.address ? utxo : [];
1646
+ } else {
1647
+ const { paymentCredential } = (0, import_utils6.getAddressDetails)(utxo.address);
1648
+ return paymentCredential?.hash === addressOrCredential.hash ? utxo : [];
1649
+ }
1365
1650
  }
1366
- });
1651
+ );
1367
1652
  return Promise.resolve(utxos);
1368
1653
  }
1369
1654
  getProtocolParameters() {
@@ -1376,32 +1661,44 @@ var Emulator = class {
1376
1661
  return Promise.resolve(this.datumTable[datumHash]);
1377
1662
  }
1378
1663
  getUtxosWithUnit(addressOrCredential, unit) {
1379
- const utxos = Object.values(this.ledger).flatMap(({ utxo }) => {
1380
- if (typeof addressOrCredential === "string") {
1381
- return addressOrCredential === utxo.address && utxo.assets[unit] > 0n ? utxo : [];
1382
- } else {
1383
- const { paymentCredential } = (0, import_utils6.getAddressDetails)(utxo.address);
1384
- return paymentCredential?.hash === addressOrCredential.hash && utxo.assets[unit] > 0n ? utxo : [];
1664
+ const utxos = Object.values(this.ledger).flatMap(
1665
+ ({ utxo, spent }) => {
1666
+ if (spent) return [];
1667
+ if (typeof addressOrCredential === "string") {
1668
+ return addressOrCredential === utxo.address && utxo.assets[unit] > 0n ? utxo : [];
1669
+ } else {
1670
+ const { paymentCredential } = (0, import_utils6.getAddressDetails)(utxo.address);
1671
+ return paymentCredential?.hash === addressOrCredential.hash && utxo.assets[unit] > 0n ? utxo : [];
1672
+ }
1385
1673
  }
1386
- });
1674
+ );
1387
1675
  return Promise.resolve(utxos);
1388
1676
  }
1389
1677
  getUtxosByOutRef(outRefs) {
1390
1678
  return Promise.resolve(
1391
- outRefs.flatMap(
1392
- (outRef) => this.ledger[outRef.txHash + outRef.outputIndex]?.utxo || []
1393
- )
1679
+ outRefs.flatMap((outRef) => {
1680
+ const entry = this.ledger[outRef.txHash + outRef.outputIndex];
1681
+ return entry && !entry.spent ? entry.utxo : [];
1682
+ })
1394
1683
  );
1395
1684
  }
1396
1685
  getUtxoByUnit(unit) {
1397
1686
  const utxos = Object.values(this.ledger).flatMap(
1398
- ({ utxo }) => utxo.assets[unit] > 0n ? utxo : []
1687
+ ({ utxo, spent }) => !spent && utxo.assets[unit] > 0n ? utxo : []
1399
1688
  );
1400
1689
  if (utxos.length > 1) {
1401
1690
  throw new Error("Unit needs to be an NFT or only held by one address.");
1402
1691
  }
1403
1692
  return Promise.resolve(utxos[0]);
1404
1693
  }
1694
+ getRewardAccount(rewardAddress) {
1695
+ const account = this.chain[rewardAddress];
1696
+ return Promise.resolve({
1697
+ registered: account?.registeredStake ?? false,
1698
+ poolId: account?.delegation.poolId ?? null,
1699
+ rewards: account?.delegation.rewards ?? 0n
1700
+ });
1701
+ }
1405
1702
  getDelegation(rewardAddress) {
1406
1703
  return Promise.resolve({
1407
1704
  poolId: this.chain[rewardAddress]?.delegation?.poolId || null,
@@ -1409,12 +1706,34 @@ var Emulator = class {
1409
1706
  });
1410
1707
  }
1411
1708
  awaitTx(txHash) {
1412
- if (this.mempool[txHash + 0]) {
1709
+ if (this.transactionHistory[txHash]?.status === "pending") {
1413
1710
  this.awaitBlock();
1414
1711
  return Promise.resolve(true);
1415
1712
  }
1416
1713
  return Promise.resolve(true);
1417
1714
  }
1715
+ getTransactionStatus(txHash, options = {}) {
1716
+ if (options.signal?.aborted) {
1717
+ return Promise.reject(
1718
+ options.signal.reason instanceof Error ? options.signal.reason : new DOMException("The operation was aborted.", "AbortError")
1719
+ );
1720
+ }
1721
+ const status = this.transactionHistory[txHash];
1722
+ if (!status) return Promise.resolve({ status: "not_found", txHash });
1723
+ if (status.status === "pending") {
1724
+ return Promise.resolve({ status: "pending", txHash });
1725
+ }
1726
+ return Promise.resolve({
1727
+ status: "confirmed",
1728
+ txHash,
1729
+ confirmation: {
1730
+ txHash,
1731
+ blockHeight: status.blockHeight,
1732
+ slot: status.slot,
1733
+ confirmations: this.blockHeight - status.blockHeight + 1
1734
+ }
1735
+ });
1736
+ }
1418
1737
  /**
1419
1738
  * Emulates the behaviour of the reward distribution at epoch boundaries.
1420
1739
  * Stake keys need to be registered and delegated like on a real chain in order to receive rewards.
@@ -2095,6 +2414,7 @@ It does not exist or was already spent.`
2095
2414
  for (const [datumHash, datum] of Object.entries(datumTable)) {
2096
2415
  this.datumTable[datumHash] = datum;
2097
2416
  }
2417
+ this.transactionHistory[txHash] = { status: "pending" };
2098
2418
  return Promise.resolve(txHash);
2099
2419
  }
2100
2420
  async evaluateTx(tx, additionalUTxOs) {
@@ -2346,21 +2666,30 @@ var Maestro = class {
2346
2666
  );
2347
2667
  return utxos.map(this.maestroUtxoToUtxo);
2348
2668
  }
2349
- async getDelegation(rewardAddress) {
2350
- const timestampedResultResponse = await fetch(
2351
- `${this.url}/accounts/${rewardAddress}`,
2352
- { headers: this.commonHeaders() }
2353
- );
2354
- if (!timestampedResultResponse.ok) {
2355
- return { poolId: null, rewards: 0n };
2669
+ async getRewardAccount(rewardAddress) {
2670
+ const response = await fetch(`${this.url}/accounts/${rewardAddress}`, {
2671
+ headers: this.requireAmountsAsStrings(this.commonHeaders())
2672
+ });
2673
+ if (response.status === 404) {
2674
+ return { registered: false, poolId: null, rewards: 0n };
2356
2675
  }
2357
- const timestampedResult = await timestampedResultResponse.json();
2676
+ if (!response.ok) {
2677
+ throw new Error(
2678
+ `Could not fetch reward account from Maestro. Received status code: ${response.status}`
2679
+ );
2680
+ }
2681
+ const timestampedResult = await response.json();
2358
2682
  const result = timestampedResult.data;
2359
2683
  return {
2684
+ registered: result.registered,
2360
2685
  poolId: result.delegated_pool || null,
2361
2686
  rewards: BigInt(result.rewards_available)
2362
2687
  };
2363
2688
  }
2689
+ async getDelegation(rewardAddress) {
2690
+ const { poolId, rewards } = await this.getRewardAccount(rewardAddress);
2691
+ return { poolId, rewards };
2692
+ }
2364
2693
  async getDatum(datumHash) {
2365
2694
  const timestampedResultResponse = await fetch(
2366
2695
  `${this.url}/datums/${datumHash}`,
@@ -2398,6 +2727,42 @@ var Maestro = class {
2398
2727
  }, checkInterval);
2399
2728
  });
2400
2729
  }
2730
+ async getTransactionStatus(txHash, options = {}) {
2731
+ const response = await fetch(`${this.url}/txmanager/${txHash}/state`, {
2732
+ headers: this.commonHeaders(),
2733
+ signal: options.signal
2734
+ });
2735
+ if (response.status === 404) return { status: "not_found", txHash };
2736
+ if (!response.ok) {
2737
+ throw new Error(
2738
+ `Could not fetch transaction status from Maestro. Received status code: ${response.status}`
2739
+ );
2740
+ }
2741
+ const result = await response.json();
2742
+ switch (result.status) {
2743
+ case "pending":
2744
+ return { status: "pending", txHash };
2745
+ case "confirmed":
2746
+ return {
2747
+ status: "confirmed",
2748
+ txHash,
2749
+ confirmation: {
2750
+ txHash,
2751
+ confirmations: result.confirmations
2752
+ }
2753
+ };
2754
+ case "failed":
2755
+ return {
2756
+ status: "failed",
2757
+ txHash,
2758
+ reason: result.reason ?? result.error
2759
+ };
2760
+ default:
2761
+ throw new Error(
2762
+ `Maestro returned an unknown transaction status: ${String(result.status)}`
2763
+ );
2764
+ }
2765
+ }
2401
2766
  async submitTx(tx) {
2402
2767
  let queryUrl = `${this.url}/txmanager`;
2403
2768
  queryUrl += this.turboSubmit ? "/turbosubmit" : "";
@@ -2441,7 +2806,7 @@ var Maestro = class {
2441
2806
  address: result.address,
2442
2807
  datumHash: result.datum ? result.datum.type == "inline" ? void 0 : result.datum.hash : void 0,
2443
2808
  datum: result.datum?.bytes,
2444
- scriptRef: toScriptRef(result.reference_script)
2809
+ scriptRef: toScriptRef2(result.reference_script)
2445
2810
  };
2446
2811
  }
2447
2812
  async getAllPagesData(getResponse, qry, paramsGiven, errorMsg) {
@@ -2492,7 +2857,7 @@ var Maestro = class {
2492
2857
  return result;
2493
2858
  }
2494
2859
  };
2495
- var toScriptRef = (reference_script) => {
2860
+ var toScriptRef2 = (reference_script) => {
2496
2861
  if (reference_script && reference_script.bytes) {
2497
2862
  switch (reference_script.type) {
2498
2863
  case "native":
@@ -2747,8 +3112,13 @@ var AssetAddressSchema = import_effect7.Schema.Struct({
2747
3112
  quantity: import_effect7.Schema.String
2748
3113
  });
2749
3114
  var AccountInfoSchema = import_effect7.Schema.Struct({
3115
+ status: import_effect7.Schema.Literal("registered", "not registered"),
2750
3116
  delegated_pool: import_effect7.Schema.NullOr(import_effect7.Schema.String),
2751
- rewards_available: import_effect7.Schema.NumberFromString
3117
+ rewards_available: import_effect7.Schema.String
3118
+ });
3119
+ var TxStatusSchema = import_effect7.Schema.Struct({
3120
+ tx_hash: import_effect7.Schema.String,
3121
+ num_confirmations: import_effect7.Schema.NullOr(import_effect7.Schema.Number)
2752
3122
  });
2753
3123
  var DatumInfo = import_effect7.Schema.Struct({
2754
3124
  bytes: import_effect7.Schema.String
@@ -2769,9 +3139,9 @@ var toUTxO = (koiosUTxO, address) => ({
2769
3139
  address,
2770
3140
  datumHash: koiosUTxO.inline_datum ? void 0 : koiosUTxO.datum_hash || void 0,
2771
3141
  datum: koiosUTxO.inline_datum ? koiosUTxO.inline_datum.bytes : void 0,
2772
- scriptRef: toScriptRef2(koiosUTxO.reference_script)
3142
+ scriptRef: toScriptRef3(koiosUTxO.reference_script)
2773
3143
  });
2774
- var toScriptRef2 = (reference_script) => {
3144
+ var toScriptRef3 = (reference_script) => {
2775
3145
  if (reference_script && reference_script.bytes && reference_script.type) {
2776
3146
  switch (reference_script.type) {
2777
3147
  case "plutusV1":
@@ -2985,7 +3355,7 @@ var Koios = class {
2985
3355
  return [];
2986
3356
  }
2987
3357
  }
2988
- async getDelegation(rewardAddress) {
3358
+ async getRewardAccount(rewardAddress) {
2989
3359
  const body = {
2990
3360
  _stake_addresses: [rewardAddress]
2991
3361
  };
@@ -3000,18 +3370,24 @@ var Koios = class {
3000
3370
  ),
3001
3371
  // Allows for dependency injection and easier testing
3002
3372
  import_effect8.Effect.provide(import_platform4.FetchHttpClient.layer),
3003
- import_effect8.Effect.flatMap(
3004
- (result2) => result2.length === 0 ? import_effect8.Effect.fail("No Delegation Found by Reward Address") : import_effect8.Effect.succeed(result2[0])
3005
- ),
3006
3373
  import_effect8.Effect.timeout(1e4),
3007
3374
  import_effect8.Effect.catchAllCause((cause) => new KoiosError({ cause })),
3008
3375
  import_effect8.Effect.runPromise
3009
3376
  );
3377
+ const account = result[0];
3378
+ if (!account) {
3379
+ return { registered: false, poolId: null, rewards: 0n };
3380
+ }
3010
3381
  return {
3011
- poolId: result.delegated_pool || null,
3012
- rewards: BigInt(result.rewards_available)
3382
+ registered: account.status === "registered",
3383
+ poolId: account.delegated_pool || null,
3384
+ rewards: BigInt(account.rewards_available)
3013
3385
  };
3014
3386
  }
3387
+ async getDelegation(rewardAddress) {
3388
+ const { poolId, rewards } = await this.getRewardAccount(rewardAddress);
3389
+ return { poolId, rewards };
3390
+ }
3015
3391
  async getDatum(datumHash) {
3016
3392
  const url = `${this.baseUrl}/datum_info`;
3017
3393
  const body = {
@@ -3058,6 +3434,38 @@ var Koios = class {
3058
3434
  );
3059
3435
  return result;
3060
3436
  }
3437
+ async getTransactionStatus(txHash, options = {}) {
3438
+ const url = `${this.baseUrl}/tx_status`;
3439
+ const body = { _tx_hashes: [txHash] };
3440
+ const bearerToken = this.token ? { Authorization: `Bearer ${this.token}` } : void 0;
3441
+ const response = await fetch(url, {
3442
+ method: "POST",
3443
+ headers: { "Content-Type": "application/json", ...bearerToken },
3444
+ body: JSON.stringify(body),
3445
+ signal: options.signal
3446
+ });
3447
+ if (response.status === 404) return { status: "not_found", txHash };
3448
+ if (!response.ok) {
3449
+ throw new Error(
3450
+ `Could not fetch transaction status from Koios. Received status code: ${response.status}`
3451
+ );
3452
+ }
3453
+ const result = import_effect8.Schema.decodeUnknownSync(import_effect8.Schema.Array(TxStatusSchema))(
3454
+ await response.json()
3455
+ );
3456
+ const status = result[0];
3457
+ if (!status || status.num_confirmations === null) {
3458
+ return { status: "not_found", txHash };
3459
+ }
3460
+ return {
3461
+ status: "confirmed",
3462
+ txHash,
3463
+ confirmation: {
3464
+ txHash,
3465
+ confirmations: status.num_confirmations
3466
+ }
3467
+ };
3468
+ }
3061
3469
  async submitTx(tx) {
3062
3470
  const url = `${this.baseUrl}/submittx`;
3063
3471
  const body = (0, import_core_utils4.fromHex)(tx);
@@ -3114,6 +3522,8 @@ var Koios = class {
3114
3522
  Kupmios,
3115
3523
  KupmiosError,
3116
3524
  Maestro,
3525
+ OgmiosJsonRpcError,
3117
3526
  generateEmulatorAccount,
3118
- generateEmulatorAccountFromPrivateKey
3527
+ generateEmulatorAccountFromPrivateKey,
3528
+ isEmulatorProvider
3119
3529
  });