@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.js CHANGED
@@ -1,3 +1,93 @@
1
+ // src/errors.ts
2
+ var asRecord = (value) => typeof value === "object" && value !== null ? value : void 0;
3
+ var responseStatus = (cause) => {
4
+ const response = asRecord(asRecord(cause)?.response);
5
+ return typeof response?.status === "number" ? response.status : void 0;
6
+ };
7
+ var retryAfterHeaderToMs = (value) => {
8
+ if (value === void 0) return void 0;
9
+ const seconds = Number(value);
10
+ if (Number.isFinite(seconds)) return Math.max(0, seconds * 1e3);
11
+ const timestamp = Date.parse(value);
12
+ return Number.isNaN(timestamp) ? void 0 : Math.max(0, timestamp - Date.now());
13
+ };
14
+ var retryAfter = (cause) => {
15
+ const response = asRecord(asRecord(cause)?.response);
16
+ const headers = asRecord(response?.headers);
17
+ const value = headers?.["retry-after"];
18
+ return retryAfterHeaderToMs(typeof value === "string" ? value : void 0);
19
+ };
20
+ var errorTag = (cause) => {
21
+ const record = asRecord(cause);
22
+ return [record?._tag, record?.name, record?.reason].filter((value) => typeof value === "string").join(" ").toLowerCase();
23
+ };
24
+ var inferKind = (cause, status) => {
25
+ const tag = errorTag(cause);
26
+ if (tag.includes("timeout")) return "timeout";
27
+ if (tag.includes("parse") || tag.includes("decode")) return "decode";
28
+ if (status !== void 0) return "http";
29
+ if (tag.includes("request") || tag.includes("transport")) return "transport";
30
+ return "unknown";
31
+ };
32
+ var inferRetryable = (kind, status) => kind === "timeout" || kind === "transport" || status === 408 || status === 425 || status === 429 || status !== void 0 && status >= 500;
33
+ var KupmiosError = class extends Error {
34
+ _tag = "KupmiosError";
35
+ provider = "Kupmios";
36
+ protocol;
37
+ operation;
38
+ kind;
39
+ status;
40
+ retryable;
41
+ retryAfterMs;
42
+ cause;
43
+ constructor(options) {
44
+ const status = options.status ?? responseStatus(options.cause);
45
+ const kind = options.kind ?? inferKind(options.cause, status);
46
+ const retryable = options.retryable ?? inferRetryable(kind, status);
47
+ const operation = options.operation ?? "unknown";
48
+ const statusSuffix = status === void 0 ? "" : ` (HTTP ${status})`;
49
+ super(
50
+ options.message ?? `${options.protocol ?? "provider"} ${operation} failed${statusSuffix}`,
51
+ {
52
+ cause: options.cause
53
+ }
54
+ );
55
+ this.name = "KupmiosError";
56
+ this.protocol = options.protocol;
57
+ this.operation = operation;
58
+ this.kind = kind;
59
+ this.status = status;
60
+ this.retryable = retryable;
61
+ this.retryAfterMs = options.retryAfterMs ?? retryAfter(options.cause);
62
+ this.cause = options.cause;
63
+ }
64
+ };
65
+ var OgmiosJsonRpcError = class extends KupmiosError {
66
+ _tag = "OgmiosJsonRpcError";
67
+ code;
68
+ data;
69
+ method;
70
+ id;
71
+ constructor(options) {
72
+ const dataSuffix = options.data === void 0 ? "" : `: ${JSON.stringify(options.data)}`;
73
+ super({
74
+ protocol: "ogmios",
75
+ operation: options.operation ?? options.method ?? "unknown",
76
+ kind: "json_rpc",
77
+ status: options.status,
78
+ retryAfterMs: options.retryAfterMs,
79
+ cause: options.cause,
80
+ message: `Ogmios JSON-RPC error ${options.code}: ${options.message}${dataSuffix}`
81
+ });
82
+ this.name = "OgmiosJsonRpcError";
83
+ this.code = options.code;
84
+ this.data = options.data;
85
+ this.method = options.method;
86
+ this.id = options.id;
87
+ }
88
+ };
89
+ var toKupmiosError = (cause, protocol, operation) => cause instanceof KupmiosError ? cause : new KupmiosError({ cause, protocol, operation });
90
+
1
91
  // src/core.ts
2
92
  import * as CML from "@anastasia-labs/cardano-multiplatform-lib-nodejs";
3
93
 
@@ -11,7 +101,7 @@ import {
11
101
  // package.json
12
102
  var package_default = {
13
103
  name: "@lucid-evolution/provider",
14
- version: "0.1.97",
104
+ version: "0.2.1",
15
105
  description: "",
16
106
  main: "./dist/index.js",
17
107
  types: "./dist/index.d.ts",
@@ -254,18 +344,29 @@ var Blockfrost = class {
254
344
  )
255
345
  );
256
346
  }
257
- async getDelegation(rewardAddress) {
258
- const result = await fetch(`${this.url}/accounts/${rewardAddress}`, {
347
+ async getRewardAccount(rewardAddress) {
348
+ const response = await fetch(`${this.url}/accounts/${rewardAddress}`, {
259
349
  headers: { project_id: this.projectId, lucid }
260
- }).then((res) => res.json());
261
- if (!result || result.error) {
262
- return { poolId: null, rewards: 0n };
350
+ });
351
+ if (response.status === 404) {
352
+ return { registered: false, poolId: null, rewards: 0n };
353
+ }
354
+ if (!response.ok) {
355
+ throw new Error(
356
+ `Could not fetch reward account from Blockfrost. Received status code: ${response.status}`
357
+ );
263
358
  }
359
+ const result = await response.json();
264
360
  return {
361
+ registered: result.active,
265
362
  poolId: result.pool_id || null,
266
363
  rewards: BigInt(result.withdrawable_amount)
267
364
  };
268
365
  }
366
+ async getDelegation(rewardAddress) {
367
+ const { poolId, rewards } = await this.getRewardAccount(rewardAddress);
368
+ return { poolId, rewards };
369
+ }
269
370
  async getDatum(datumHash) {
270
371
  const datum = await fetch(`${this.url}/scripts/datum/${datumHash}/cbor`, {
271
372
  headers: { project_id: this.projectId, lucid }
@@ -289,6 +390,29 @@ var Blockfrost = class {
289
390
  }, checkInterval);
290
391
  });
291
392
  }
393
+ async getTransactionStatus(txHash, options = {}) {
394
+ const response = await fetch(`${this.url}/txs/${txHash}`, {
395
+ headers: { project_id: this.projectId, lucid },
396
+ signal: options.signal
397
+ });
398
+ if (response.status === 404) return { status: "not_found", txHash };
399
+ if (!response.ok) {
400
+ throw new Error(
401
+ `Could not fetch transaction status from Blockfrost. Received status code: ${response.status}`
402
+ );
403
+ }
404
+ const result = await response.json();
405
+ return {
406
+ status: "confirmed",
407
+ txHash,
408
+ confirmation: {
409
+ txHash,
410
+ blockHash: result.block,
411
+ blockHeight: result.block_height,
412
+ slot: result.slot
413
+ }
414
+ };
415
+ }
292
416
  async submitTx(tx) {
293
417
  const result = await fetch(`${this.url}/tx/submit`, {
294
418
  method: "POST",
@@ -422,7 +546,7 @@ var lucid = package_default.version;
422
546
  // src/kupmios.ts
423
547
  import { applyDoubleCborEncoding as applyDoubleCborEncoding2, fromUnit as fromUnit2 } from "@lucid-evolution/utils";
424
548
  import { Schema as S3 } from "effect";
425
- import { Effect as Effect2, pipe as pipe3, Array as _Array, Schedule, Data } from "effect";
549
+ import { Cause, Effect as Effect2, Exit, pipe as pipe3, Array as _Array, Schedule } from "effect";
426
550
 
427
551
  // src/internal/ogmios.ts
428
552
  import { Schema as S } from "effect";
@@ -447,12 +571,28 @@ var JSONRPCErrorResponseSchema = S.Struct({
447
571
  var JSONRPCResponseSchema = (schema) => S.Union(JSONRPCSchema(schema), JSONRPCErrorResponseSchema).annotations({
448
572
  identifier: "JSONRPCResponseSchema"
449
573
  });
450
- var getJSONRPCResult = (response) => {
574
+ var getJSONRPCResult = (response, operation, transport) => {
451
575
  if ("error" in response) {
452
- const data = response.error.data === void 0 ? "" : `: ${JSON.stringify(response.error.data)}`;
453
- throw new Error(
454
- `Ogmios JSON-RPC error ${response.error.code}: ${response.error.message}${data}`
455
- );
576
+ throw new OgmiosJsonRpcError({
577
+ code: response.error.code,
578
+ message: response.error.message,
579
+ data: response.error.data,
580
+ method: response.method,
581
+ id: response.id,
582
+ operation,
583
+ status: transport?.status,
584
+ retryAfterMs: retryAfterHeaderToMs(transport?.headers["retry-after"]),
585
+ cause: transport
586
+ });
587
+ }
588
+ if (transport && (transport.status < 200 || transport.status >= 300)) {
589
+ throw new KupmiosError({
590
+ protocol: "ogmios",
591
+ operation: operation ?? response.method ?? "unknown",
592
+ status: transport.status,
593
+ retryAfterMs: retryAfterHeaderToMs(transport.headers["retry-after"]),
594
+ cause: transport
595
+ });
456
596
  }
457
597
  return response.result;
458
598
  };
@@ -595,7 +735,7 @@ var LegacyDelegationSummarySchema = S.Struct({
595
735
  deposit: RewardAccountAdaSchema
596
736
  });
597
737
  var RewardAccountSummarySchema = S.Struct({
598
- from: S.optional(S.Literal("key", "script")),
738
+ from: S.optional(S.Literal("key", "verificationKey", "script")),
599
739
  credential: S.optional(S.String),
600
740
  stakePool: S.optional(S.NullOr(S.Struct({ id: S.String }))),
601
741
  rewards: RewardAccountAdaSchema,
@@ -699,7 +839,17 @@ var ValueSchema = S2.Struct({
699
839
  coins: QuantitySchema,
700
840
  assets: S2.Record({ key: S2.String, value: QuantitySchema })
701
841
  });
702
- var UTxOSchema = S2.Struct({
842
+ var PointSchema = S2.Struct({
843
+ slot_no: S2.Number,
844
+ header_hash: S2.String
845
+ });
846
+ var ScriptSchema = S2.NullOr(
847
+ S2.Struct({
848
+ language: S2.Literal("native", "plutus:v1", "plutus:v2", "plutus:v3"),
849
+ script: S2.String
850
+ })
851
+ );
852
+ var UTxOFields = {
703
853
  transaction_index: S2.Number,
704
854
  transaction_id: S2.String,
705
855
  output_index: S2.Number,
@@ -708,23 +858,15 @@ var UTxOSchema = S2.Struct({
708
858
  datum_hash: S2.NullOr(S2.String),
709
859
  datum_type: S2.optional(S2.Literal("hash", "inline")),
710
860
  script_hash: S2.NullOr(S2.String),
711
- created_at: S2.Struct({
712
- slot_no: S2.Number,
713
- header_hash: S2.String
714
- }),
715
- spent_at: S2.NullOr(
716
- S2.Struct({
717
- slot_no: S2.Number,
718
- header_hash: S2.String
719
- })
720
- )
861
+ created_at: PointSchema,
862
+ spent_at: S2.NullOr(PointSchema)
863
+ };
864
+ var UTxOSchema = S2.Struct(UTxOFields);
865
+ var ResolvedUTxOSchema = S2.Struct({
866
+ ...UTxOFields,
867
+ datum: S2.NullOr(S2.String),
868
+ script: ScriptSchema
721
869
  });
722
- var ScriptSchema = S2.NullOr(
723
- S2.Struct({
724
- language: S2.Literal("native", "plutus:v1", "plutus:v2", "plutus:v3"),
725
- script: S2.String
726
- })
727
- );
728
870
  var DatumSchema = S2.NullOr(S2.Struct({ datum: S2.String }));
729
871
  var DelegationSchema = S2.NullOr(
730
872
  S2.Record({
@@ -791,6 +933,33 @@ var makePostAsJson = (url, data, schema, headers) => pipe2(
791
933
  // Prevents resource leaks and ensures clean request termination
792
934
  Effect.scoped
793
935
  );
936
+ var makePostAsJsonResponse = (url, data, schema, headers) => pipe2(
937
+ HttpClientRequest.post(url),
938
+ headers ? HttpClientRequest.setHeaders(headers) : identity,
939
+ HttpClientRequest.bodyJson(data),
940
+ Effect.flatMap(HttpClient.execute),
941
+ Effect.flatMap(
942
+ (response) => pipe2(
943
+ HttpClientResponse.schemaBodyJson(schema)(response),
944
+ Effect.map((body) => ({
945
+ body,
946
+ status: response.status,
947
+ headers: response.headers
948
+ })),
949
+ Effect.catchAll(
950
+ (cause) => response.status >= 200 && response.status < 300 ? Effect.fail(cause) : Effect.fail(
951
+ new HttpClientError.ResponseError({
952
+ response,
953
+ request: response.request,
954
+ reason: "StatusCode",
955
+ description: "non 2xx status code with an invalid JSON response"
956
+ })
957
+ )
958
+ )
959
+ )
960
+ ),
961
+ Effect.scoped
962
+ );
794
963
  var makePostAsUint8Array = (url, data, schema, headers) => pipe2(
795
964
  // Initiate a POST request to the specified URL
796
965
  HttpClientRequest.post(url),
@@ -812,19 +981,50 @@ var makePostAsUint8Array = (url, data, schema, headers) => pipe2(
812
981
 
813
982
  // src/kupmios.ts
814
983
  import { FetchHttpClient } from "@effect/platform";
815
- var KupmiosError = class extends Data.TaggedError("KupmiosError") {
816
- get message() {
817
- return `${this.cause}`;
984
+ var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
985
+ var DEFAULT_AWAIT_TX_TIMEOUT_MS = 16e4;
986
+ var validateTimeout = (name, timeout) => {
987
+ if (!Number.isFinite(timeout) || timeout <= 0) {
988
+ throw new TypeError(`${name} must be a positive finite number.`);
818
989
  }
990
+ return timeout;
991
+ };
992
+ var catchProviderError = (protocol, operation) => (effect) => Effect2.catchAll(
993
+ effect,
994
+ (cause) => Effect2.fail(toKupmiosError(cause, protocol, operation))
995
+ );
996
+ var runProviderEffect = async (effect, protocol, operation, signal) => {
997
+ const exit = await Effect2.runPromiseExit(effect, { signal });
998
+ if (Exit.isSuccess(exit)) return exit.value;
999
+ if (signal?.aborted) {
1000
+ throw new KupmiosError({
1001
+ protocol,
1002
+ operation,
1003
+ kind: "aborted",
1004
+ retryable: false,
1005
+ cause: signal.reason ?? Cause.squash(exit.cause)
1006
+ });
1007
+ }
1008
+ throw toKupmiosError(Cause.squash(exit.cause), protocol, operation);
819
1009
  };
820
1010
  var Kupmios = class {
821
1011
  kupoUrl;
822
1012
  ogmiosUrl;
823
- headers;
824
- constructor(kupoUrl, ogmiosUrl, headers) {
1013
+ options;
1014
+ requestTimeoutMs;
1015
+ awaitTxTimeoutMs;
1016
+ constructor(kupoUrl, ogmiosUrl, options = {}) {
825
1017
  this.kupoUrl = kupoUrl;
826
1018
  this.ogmiosUrl = ogmiosUrl;
827
- this.headers = headers;
1019
+ this.options = options;
1020
+ this.requestTimeoutMs = validateTimeout(
1021
+ "requestTimeoutMs",
1022
+ options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS
1023
+ );
1024
+ this.awaitTxTimeoutMs = validateTimeout(
1025
+ "awaitTxTimeoutMs",
1026
+ options.awaitTxTimeoutMs ?? DEFAULT_AWAIT_TX_TIMEOUT_MS
1027
+ );
828
1028
  }
829
1029
  async getProtocolParameters() {
830
1030
  const data = {
@@ -836,19 +1036,26 @@ var Kupmios = class {
836
1036
  const schema = JSONRPCResponseSchema(
837
1037
  S3.Record({ key: S3.String, value: S3.Unknown })
838
1038
  );
839
- const response = await pipe3(
840
- makePostAsJson(
841
- this.ogmiosUrl,
842
- data,
843
- schema,
844
- this.headers?.ogmiosHeader
1039
+ const response = await runProviderEffect(
1040
+ pipe3(
1041
+ makePostAsJsonResponse(
1042
+ this.ogmiosUrl,
1043
+ data,
1044
+ schema,
1045
+ this.options.ogmiosHeader
1046
+ ),
1047
+ Effect2.timeout(this.requestTimeoutMs),
1048
+ catchProviderError("ogmios", "queryLedgerState/protocolParameters"),
1049
+ Effect2.provide(FetchHttpClient.layer)
845
1050
  ),
846
- Effect2.timeout(1e4),
847
- Effect2.catchAll((cause) => new KupmiosError({ cause })),
848
- Effect2.provide(FetchHttpClient.layer),
849
- Effect2.runPromise
1051
+ "ogmios",
1052
+ "queryLedgerState/protocolParameters"
1053
+ );
1054
+ const result = getJSONRPCResult(
1055
+ response.body,
1056
+ data.method,
1057
+ response
850
1058
  );
851
- const result = getJSONRPCResult(response);
852
1059
  const protocolParameters = S3.decodeUnknownSync(
853
1060
  ProtocolParametersSchema
854
1061
  )(normalizeProtocolParameters(result));
@@ -864,35 +1071,43 @@ var Kupmios = class {
864
1071
  const schema = JSONRPCResponseSchema(
865
1072
  TreasuryAndReservesSchema
866
1073
  );
867
- const response = await pipe3(
868
- makePostAsJson(
869
- this.ogmiosUrl,
870
- data,
871
- schema,
872
- this.headers?.ogmiosHeader
1074
+ const response = await runProviderEffect(
1075
+ pipe3(
1076
+ makePostAsJsonResponse(
1077
+ this.ogmiosUrl,
1078
+ data,
1079
+ schema,
1080
+ this.options.ogmiosHeader
1081
+ ),
1082
+ Effect2.timeout(this.requestTimeoutMs),
1083
+ catchProviderError("ogmios", "queryLedgerState/treasuryAndReserves"),
1084
+ Effect2.provide(FetchHttpClient.layer)
873
1085
  ),
874
- Effect2.timeout(1e4),
875
- Effect2.catchAll((cause) => new KupmiosError({ cause })),
876
- Effect2.provide(FetchHttpClient.layer),
877
- Effect2.runPromise
1086
+ "ogmios",
1087
+ "queryLedgerState/treasuryAndReserves"
1088
+ );
1089
+ const result = getJSONRPCResult(
1090
+ response.body,
1091
+ data.method,
1092
+ response
878
1093
  );
879
- const result = getJSONRPCResult(response);
880
1094
  return lovelaceAmountToBigInt(result.treasury.ada.lovelace);
881
1095
  }
882
1096
  async getUtxos(addressOrCredential) {
883
1097
  const isAddress = typeof addressOrCredential === "string";
884
1098
  const queryPredicate = isAddress ? addressOrCredential : addressOrCredential.hash;
885
- const pattern = `${this.kupoUrl}/matches/${queryPredicate}${isAddress ? "" : "/*"}?unspent`;
886
- const schema = S3.Array(UTxOSchema);
887
- const utxos = await pipe3(
888
- makeGet(pattern, schema, this.headers?.kupoHeader),
889
- Effect2.flatMap(
890
- (u) => kupmiosUtxosToUtxos(this.kupoUrl, u, this.headers?.kupoHeader)
1099
+ const pattern = `${this.kupoUrl}/matches/${queryPredicate}${isAddress ? "" : "/*"}?unspent&resolve_hashes`;
1100
+ const schema = S3.Array(ResolvedUTxOSchema);
1101
+ const utxos = await runProviderEffect(
1102
+ pipe3(
1103
+ makeGet(pattern, schema, this.options.kupoHeader),
1104
+ Effect2.map(kupmiosUtxosToUtxos),
1105
+ Effect2.timeout(this.requestTimeoutMs),
1106
+ catchProviderError("kupo", "getUtxos"),
1107
+ Effect2.provide(FetchHttpClient.layer)
891
1108
  ),
892
- Effect2.timeout(1e4),
893
- Effect2.catchAll((cause) => new KupmiosError({ cause })),
894
- Effect2.provide(FetchHttpClient.layer),
895
- Effect2.runPromise
1109
+ "kupo",
1110
+ "getUtxos"
896
1111
  );
897
1112
  return utxos;
898
1113
  }
@@ -900,33 +1115,58 @@ var Kupmios = class {
900
1115
  const isAddress = typeof addressOrCredential === "string";
901
1116
  const queryPredicate = isAddress ? addressOrCredential : addressOrCredential.hash;
902
1117
  const { policyId, assetName } = fromUnit2(unit);
903
- const pattern = `${this.kupoUrl}/matches/${queryPredicate}${isAddress ? "" : "/*"}?unspent&policy_id=${policyId}${assetName ? `&asset_name=${assetName}` : ""}`;
904
- const schema = S3.Array(UTxOSchema);
905
- const utxos = await pipe3(
906
- makeGet(pattern, schema, this.headers?.kupoHeader),
907
- Effect2.flatMap(
908
- (u) => kupmiosUtxosToUtxos(this.kupoUrl, u, this.headers?.kupoHeader)
1118
+ const pattern = `${this.kupoUrl}/matches/${queryPredicate}${isAddress ? "" : "/*"}?unspent&resolve_hashes&policy_id=${policyId}${assetName ? `&asset_name=${assetName}` : ""}`;
1119
+ const schema = S3.Array(ResolvedUTxOSchema);
1120
+ const utxos = await runProviderEffect(
1121
+ pipe3(
1122
+ makeGet(pattern, schema, this.options.kupoHeader),
1123
+ Effect2.map(kupmiosUtxosToUtxos),
1124
+ Effect2.timeout(this.requestTimeoutMs),
1125
+ catchProviderError("kupo", "getUtxosWithUnit"),
1126
+ Effect2.provide(FetchHttpClient.layer)
909
1127
  ),
910
- Effect2.timeout(1e4),
911
- Effect2.catchAll((cause) => new KupmiosError({ cause })),
912
- Effect2.provide(FetchHttpClient.layer),
913
- Effect2.runPromise
1128
+ "kupo",
1129
+ "getUtxosWithUnit"
1130
+ );
1131
+ return utxos.filter((utxo) => (utxo.assets[unit] ?? 0n) > 0n);
1132
+ }
1133
+ async getUtxosWithPolicy(addressOrCredential, policyId) {
1134
+ if (!/^[0-9a-f]{56}$/i.test(policyId)) {
1135
+ throw new TypeError(
1136
+ "policyId must be a 56-character hexadecimal string."
1137
+ );
1138
+ }
1139
+ const normalizedPolicyId = policyId.toLowerCase();
1140
+ const isAddress = typeof addressOrCredential === "string";
1141
+ const queryPredicate = isAddress ? addressOrCredential : addressOrCredential.hash;
1142
+ const pattern = `${this.kupoUrl}/matches/${queryPredicate}${isAddress ? "" : "/*"}?unspent&resolve_hashes&policy_id=${normalizedPolicyId}`;
1143
+ const schema = S3.Array(ResolvedUTxOSchema);
1144
+ return runProviderEffect(
1145
+ pipe3(
1146
+ makeGet(pattern, schema, this.options.kupoHeader),
1147
+ Effect2.map(kupmiosUtxosToUtxos),
1148
+ Effect2.timeout(this.requestTimeoutMs),
1149
+ catchProviderError("kupo", "getUtxosWithPolicy"),
1150
+ Effect2.provide(FetchHttpClient.layer)
1151
+ ),
1152
+ "kupo",
1153
+ "getUtxosWithPolicy"
914
1154
  );
915
- return utxos;
916
1155
  }
917
1156
  async getUtxoByUnit(unit) {
918
1157
  const { policyId, assetName } = fromUnit2(unit);
919
- const pattern = `${this.kupoUrl}/matches/${policyId}.${assetName ? `${assetName}` : "*"}?unspent`;
920
- const schema = S3.Array(UTxOSchema);
921
- const utxos = await pipe3(
922
- makeGet(pattern, schema, this.headers?.kupoHeader),
923
- Effect2.flatMap(
924
- (u) => kupmiosUtxosToUtxos(this.kupoUrl, u, this.headers?.kupoHeader)
1158
+ const pattern = `${this.kupoUrl}/matches/${policyId}.${assetName ?? ""}?unspent&resolve_hashes`;
1159
+ const schema = S3.Array(ResolvedUTxOSchema);
1160
+ const utxos = await runProviderEffect(
1161
+ pipe3(
1162
+ makeGet(pattern, schema, this.options.kupoHeader),
1163
+ Effect2.map(kupmiosUtxosToUtxos),
1164
+ Effect2.timeout(this.requestTimeoutMs),
1165
+ catchProviderError("kupo", "getUtxoByUnit"),
1166
+ Effect2.provide(FetchHttpClient.layer)
925
1167
  ),
926
- Effect2.timeout(1e4),
927
- Effect2.catchAll((cause) => new KupmiosError({ cause })),
928
- Effect2.provide(FetchHttpClient.layer),
929
- Effect2.runPromise
1168
+ "kupo",
1169
+ "getUtxoByUnit"
930
1170
  );
931
1171
  if (utxos.length === 0) {
932
1172
  throw new Error("Unit not found.");
@@ -940,21 +1180,21 @@ var Kupmios = class {
940
1180
  const queryHashes = [
941
1181
  ...new Set(outRefs.map((outRef) => outRef.txHash))
942
1182
  ];
943
- const mkPattern = (txHash) => `${this.kupoUrl}/matches/*@${txHash}?unspent`;
944
- const schema = S3.Array(UTxOSchema);
1183
+ const mkPattern = (txHash) => `${this.kupoUrl}/matches/*@${txHash}?unspent&resolve_hashes`;
1184
+ const schema = S3.Array(ResolvedUTxOSchema);
945
1185
  const program = Effect2.forEach(
946
1186
  queryHashes,
947
1187
  (txHash) => pipe3(
948
- makeGet(mkPattern(txHash), schema, this.headers?.kupoHeader),
949
- Effect2.flatMap(
950
- (u) => kupmiosUtxosToUtxos(this.kupoUrl, u, this.headers?.kupoHeader)
951
- ),
952
- Effect2.timeout(1e4),
953
- Effect2.catchAll((cause) => new KupmiosError({ cause }))
1188
+ makeGet(mkPattern(txHash), schema, this.options.kupoHeader),
1189
+ Effect2.map(kupmiosUtxosToUtxos),
1190
+ Effect2.timeout(this.requestTimeoutMs),
1191
+ catchProviderError("kupo", "getUtxosByOutRef")
954
1192
  )
955
1193
  );
956
- const utxos = await Effect2.runPromise(
957
- pipe3(program, Effect2.provide(FetchHttpClient.layer))
1194
+ const utxos = await runProviderEffect(
1195
+ pipe3(program, Effect2.provide(FetchHttpClient.layer)),
1196
+ "kupo",
1197
+ "getUtxosByOutRef"
958
1198
  );
959
1199
  return _Array.flatten(utxos).filter(
960
1200
  (utxo) => outRefs.some(
@@ -962,7 +1202,7 @@ var Kupmios = class {
962
1202
  )
963
1203
  );
964
1204
  }
965
- async getDelegation(rewardAddress) {
1205
+ async getRewardAccount(rewardAddress) {
966
1206
  const data = {
967
1207
  jsonrpc: "2.0",
968
1208
  method: "queryLedgerState/rewardAccountSummaries",
@@ -970,50 +1210,95 @@ var Kupmios = class {
970
1210
  id: null
971
1211
  };
972
1212
  const schema = JSONRPCResponseSchema(Delegation);
973
- const response = await pipe3(
974
- makePostAsJson(
975
- this.ogmiosUrl,
976
- data,
977
- schema,
978
- this.headers?.ogmiosHeader
1213
+ const response = await runProviderEffect(
1214
+ pipe3(
1215
+ makePostAsJsonResponse(
1216
+ this.ogmiosUrl,
1217
+ data,
1218
+ schema,
1219
+ this.options.ogmiosHeader
1220
+ ),
1221
+ Effect2.provide(FetchHttpClient.layer),
1222
+ Effect2.timeout(this.requestTimeoutMs),
1223
+ catchProviderError("ogmios", "queryLedgerState/rewardAccountSummaries")
979
1224
  ),
980
- Effect2.provide(FetchHttpClient.layer),
981
- Effect2.timeout(1e4),
982
- Effect2.catchAll((cause) => new KupmiosError({ cause })),
983
- Effect2.runPromise
1225
+ "ogmios",
1226
+ "queryLedgerState/rewardAccountSummaries"
1227
+ );
1228
+ const result = getJSONRPCResult(
1229
+ response.body,
1230
+ data.method,
1231
+ response
984
1232
  );
985
- const result = getJSONRPCResult(response);
986
- return toDelegation(result);
1233
+ return toRewardAccountState(result);
1234
+ }
1235
+ async getDelegation(rewardAddress) {
1236
+ const { poolId, rewards } = await this.getRewardAccount(rewardAddress);
1237
+ return { poolId, rewards };
987
1238
  }
988
1239
  async getDatum(datumHash) {
989
1240
  const pattern = `${this.kupoUrl}/datums/${datumHash}`;
990
1241
  const schema = DatumSchema;
991
- const result = await pipe3(
992
- makeGet(pattern, schema, this.headers?.kupoHeader),
993
- Effect2.provide(FetchHttpClient.layer),
994
- Effect2.timeout(1e4),
995
- Effect2.flatMap(Effect2.fromNullable),
996
- Effect2.catchAll((cause) => new KupmiosError({ cause })),
997
- Effect2.runPromise
1242
+ const result = await runProviderEffect(
1243
+ pipe3(
1244
+ makeGet(pattern, schema, this.options.kupoHeader),
1245
+ Effect2.provide(FetchHttpClient.layer),
1246
+ Effect2.timeout(this.requestTimeoutMs),
1247
+ Effect2.flatMap(Effect2.fromNullable),
1248
+ catchProviderError("kupo", "getDatum")
1249
+ ),
1250
+ "kupo",
1251
+ "getDatum"
998
1252
  );
999
1253
  return result.datum;
1000
1254
  }
1255
+ async getTransactionStatus(txHash, options = {}) {
1256
+ const pattern = `${this.kupoUrl}/matches/*@${txHash}`;
1257
+ const schema = S3.Array(UTxOSchema).annotations({
1258
+ identifier: "Array<KupmiosSchema.KupoUTxO>"
1259
+ });
1260
+ const matches = await runProviderEffect(
1261
+ pipe3(
1262
+ makeGet(pattern, schema, this.options.kupoHeader),
1263
+ Effect2.timeout(this.requestTimeoutMs),
1264
+ catchProviderError("kupo", "getTransactionStatus"),
1265
+ Effect2.provide(FetchHttpClient.layer)
1266
+ ),
1267
+ "kupo",
1268
+ "getTransactionStatus",
1269
+ options.signal
1270
+ );
1271
+ if (matches.length === 0) return { status: "not_found", txHash };
1272
+ const createdAt = matches[0].created_at;
1273
+ return {
1274
+ status: "confirmed",
1275
+ txHash,
1276
+ confirmation: {
1277
+ txHash,
1278
+ blockHash: createdAt.header_hash,
1279
+ slot: createdAt.slot_no
1280
+ }
1281
+ };
1282
+ }
1001
1283
  async awaitTx(txHash, checkInterval = 2e4) {
1002
- const pattern = `${this.kupoUrl}/matches/*@${txHash}?unspent`;
1284
+ const pattern = `${this.kupoUrl}/matches/*@${txHash}`;
1003
1285
  const schema = S3.Array(UTxOSchema).annotations({
1004
1286
  identifier: "Array<KupmiosSchema.KupoUTxO>"
1005
1287
  });
1006
- const result = await pipe3(
1007
- makeGet(pattern, schema, this.headers?.kupoHeader),
1008
- Effect2.provide(FetchHttpClient.layer),
1009
- Effect2.repeat({
1010
- schedule: Schedule.exponential(checkInterval),
1011
- until: (result2) => result2.length > 0
1012
- }),
1013
- Effect2.timeout(16e4),
1014
- Effect2.catchAll((cause) => new KupmiosError({ cause })),
1015
- Effect2.as(true),
1016
- Effect2.runPromise
1288
+ const result = await runProviderEffect(
1289
+ pipe3(
1290
+ makeGet(pattern, schema, this.options.kupoHeader),
1291
+ Effect2.provide(FetchHttpClient.layer),
1292
+ Effect2.repeat({
1293
+ schedule: Schedule.exponential(checkInterval),
1294
+ until: (result2) => result2.length > 0
1295
+ }),
1296
+ Effect2.timeout(this.awaitTxTimeoutMs),
1297
+ catchProviderError("kupo", "awaitTx"),
1298
+ Effect2.as(true)
1299
+ ),
1300
+ "kupo",
1301
+ "awaitTx"
1017
1302
  );
1018
1303
  return result;
1019
1304
  }
@@ -1033,19 +1318,26 @@ var Kupmios = class {
1033
1318
  })
1034
1319
  })
1035
1320
  );
1036
- const response = await pipe3(
1037
- makePostAsJson(
1038
- this.ogmiosUrl,
1039
- data,
1040
- schema,
1041
- this.headers?.ogmiosHeader
1321
+ const response = await runProviderEffect(
1322
+ pipe3(
1323
+ makePostAsJsonResponse(
1324
+ this.ogmiosUrl,
1325
+ data,
1326
+ schema,
1327
+ this.options.ogmiosHeader
1328
+ ),
1329
+ Effect2.provide(FetchHttpClient.layer),
1330
+ Effect2.timeout(this.requestTimeoutMs),
1331
+ catchProviderError("ogmios", "submitTransaction")
1042
1332
  ),
1043
- Effect2.provide(FetchHttpClient.layer),
1044
- Effect2.timeout(1e4),
1045
- Effect2.catchAll((cause) => new KupmiosError({ cause })),
1046
- Effect2.runPromise
1333
+ "ogmios",
1334
+ "submitTransaction"
1335
+ );
1336
+ const result = getJSONRPCResult(
1337
+ response.body,
1338
+ data.method,
1339
+ response
1047
1340
  );
1048
- const result = getJSONRPCResult(response);
1049
1341
  return result.transaction.id;
1050
1342
  }
1051
1343
  async evaluateTx(tx, additionalUTxOs) {
@@ -1059,19 +1351,26 @@ var Kupmios = class {
1059
1351
  id: null
1060
1352
  };
1061
1353
  const schema = JSONRPCResponseSchema(S3.Array(RedeemerSchema));
1062
- const response = await pipe3(
1063
- makePostAsJson(
1064
- this.ogmiosUrl,
1065
- data,
1066
- schema,
1067
- this.headers?.ogmiosHeader
1354
+ const response = await runProviderEffect(
1355
+ pipe3(
1356
+ makePostAsJsonResponse(
1357
+ this.ogmiosUrl,
1358
+ data,
1359
+ schema,
1360
+ this.options.ogmiosHeader
1361
+ ),
1362
+ Effect2.provide(FetchHttpClient.layer),
1363
+ Effect2.timeout(this.requestTimeoutMs),
1364
+ catchProviderError("ogmios", "evaluateTransaction")
1068
1365
  ),
1069
- Effect2.provide(FetchHttpClient.layer),
1070
- Effect2.timeout(1e4),
1071
- Effect2.catchAll((cause) => new KupmiosError({ cause })),
1072
- Effect2.runPromise
1366
+ "ogmios",
1367
+ "evaluateTransaction"
1368
+ );
1369
+ const result = getJSONRPCResult(
1370
+ response.body,
1371
+ data.method,
1372
+ response
1073
1373
  );
1074
- const result = getJSONRPCResult(response);
1075
1374
  const evalRedeemers = result.map((item) => ({
1076
1375
  ex_units: {
1077
1376
  mem: item.budget.memory,
@@ -1083,59 +1382,6 @@ var Kupmios = class {
1083
1382
  return evalRedeemers;
1084
1383
  }
1085
1384
  };
1086
- var getDatumEffect = (kupoUrl, datum_type, datum_hash, kupoHeader) => Effect2.gen(function* () {
1087
- if (datum_type === "inline" && datum_hash) {
1088
- const pattern = `${kupoUrl}/datums/${datum_hash}`;
1089
- const schema = DatumSchema;
1090
- return yield* pipe3(
1091
- makeGet(pattern, schema, kupoHeader),
1092
- Effect2.flatMap(Effect2.fromNullable),
1093
- Effect2.map((result) => result.datum),
1094
- Effect2.retry(
1095
- Schedule.compose(Schedule.exponential(50), Schedule.recurs(5))
1096
- ),
1097
- Effect2.timeout(5e3)
1098
- );
1099
- } else return void 0;
1100
- });
1101
- var getScriptEffect = (kupoUrl, script_hash, kupoHeader) => Effect2.gen(function* () {
1102
- if (script_hash) {
1103
- const pattern = `${kupoUrl}/scripts/${script_hash}`;
1104
- const schema = ScriptSchema;
1105
- return yield* pipe3(
1106
- makeGet(pattern, schema, kupoHeader),
1107
- Effect2.flatMap(Effect2.fromNullable),
1108
- Effect2.retry(
1109
- Schedule.compose(Schedule.exponential(50), Schedule.recurs(5))
1110
- ),
1111
- Effect2.timeout(5e3),
1112
- Effect2.map(({ language, script }) => {
1113
- switch (language) {
1114
- case "native":
1115
- return {
1116
- type: "Native",
1117
- script
1118
- };
1119
- case "plutus:v1":
1120
- return {
1121
- type: "PlutusV1",
1122
- script: applyDoubleCborEncoding2(script)
1123
- };
1124
- case "plutus:v2":
1125
- return {
1126
- type: "PlutusV2",
1127
- script: applyDoubleCborEncoding2(script)
1128
- };
1129
- case "plutus:v3":
1130
- return {
1131
- type: "PlutusV3",
1132
- script: applyDoubleCborEncoding2(script)
1133
- };
1134
- }
1135
- })
1136
- );
1137
- } else return void 0;
1138
- });
1139
1385
  var toAssets = (value) => {
1140
1386
  const assets = { lovelace: BigInt(value.coins) };
1141
1387
  for (const unit of Object.keys(value.assets)) {
@@ -1173,42 +1419,48 @@ var toProtocolParameters = (result) => {
1173
1419
  }
1174
1420
  };
1175
1421
  };
1176
- var toDelegation = (result) => {
1177
- if (!result) {
1178
- return { poolId: null, rewards: 0n };
1179
- }
1180
- const delegation = Array.isArray(result) ? result[0] : Object.values(result)[0];
1422
+ var toRewardAccountState = (result) => {
1423
+ const delegation = result ? Array.isArray(result) ? result[0] : Object.values(result)[0] : void 0;
1181
1424
  if (!delegation) {
1182
- return { poolId: null, rewards: 0n };
1425
+ return { registered: false, poolId: null, rewards: 0n };
1183
1426
  }
1184
1427
  return {
1428
+ registered: true,
1185
1429
  poolId: "stakePool" in delegation ? delegation.stakePool?.id || null : delegation.delegate?.id || null,
1186
1430
  rewards: BigInt(delegation.rewards.ada.lovelace)
1187
1431
  };
1188
1432
  };
1189
- var kupmiosUtxosToUtxos = (kupoURL, utxos, kupoHeader) => Effect2.forEach(
1190
- utxos,
1191
- (utxo) => {
1192
- return pipe3(
1193
- Effect2.all([
1194
- getDatumEffect(kupoURL, utxo.datum_type, utxo.datum_hash, kupoHeader),
1195
- getScriptEffect(kupoURL, utxo.script_hash, kupoHeader)
1196
- ]),
1197
- Effect2.map(
1198
- ([datum, script]) => ({
1199
- txHash: utxo.transaction_id,
1200
- outputIndex: utxo.output_index,
1201
- address: utxo.address,
1202
- assets: toAssets(utxo.value),
1203
- datumHash: utxo.datum_type === "hash" ? utxo.datum_hash : void 0,
1204
- datum,
1205
- scriptRef: script
1206
- })
1207
- )
1208
- );
1209
- },
1210
- { concurrency: "unbounded" }
1211
- );
1433
+ var toScriptRef = (script) => {
1434
+ if (!script) return void 0;
1435
+ switch (script.language) {
1436
+ case "native":
1437
+ return { type: "Native", script: script.script };
1438
+ case "plutus:v1":
1439
+ return {
1440
+ type: "PlutusV1",
1441
+ script: applyDoubleCborEncoding2(script.script)
1442
+ };
1443
+ case "plutus:v2":
1444
+ return {
1445
+ type: "PlutusV2",
1446
+ script: applyDoubleCborEncoding2(script.script)
1447
+ };
1448
+ case "plutus:v3":
1449
+ return {
1450
+ type: "PlutusV3",
1451
+ script: applyDoubleCborEncoding2(script.script)
1452
+ };
1453
+ }
1454
+ };
1455
+ var kupmiosUtxosToUtxos = (utxos) => utxos.map((utxo) => ({
1456
+ txHash: utxo.transaction_id,
1457
+ outputIndex: utxo.output_index,
1458
+ address: utxo.address,
1459
+ assets: toAssets(utxo.value),
1460
+ datumHash: utxo.datum_type === "hash" ? utxo.datum_hash : void 0,
1461
+ datum: utxo.datum_type === "inline" ? utxo.datum : void 0,
1462
+ scriptRef: toScriptRef(utxo.script)
1463
+ }));
1212
1464
 
1213
1465
  // src/emulator.ts
1214
1466
  import {
@@ -1219,6 +1471,12 @@ import {
1219
1471
  import { coreToUtxo, getAddressDetails } from "@lucid-evolution/utils";
1220
1472
  import { fromHex as fromHex2 } from "@lucid-evolution/core-utils";
1221
1473
  import { walletFromSeed } from "@lucid-evolution/wallet";
1474
+ var EMULATOR_PROVIDER_BRAND = Symbol.for(
1475
+ "@lucid-evolution/provider/Emulator"
1476
+ );
1477
+ var isEmulatorProvider = (provider) => Boolean(
1478
+ provider && provider[EMULATOR_PROVIDER_BRAND]
1479
+ );
1222
1480
  function generateEmulatorAccountFromPrivateKey(assets) {
1223
1481
  const privateKey = CML.PrivateKey.generate_ed25519().to_bech32();
1224
1482
  const priv = CML.PrivateKey.from_bech32(privateKey);
@@ -1248,6 +1506,7 @@ function generateEmulatorAccount(assets) {
1248
1506
  };
1249
1507
  }
1250
1508
  var Emulator = class {
1509
+ [EMULATOR_PROVIDER_BRAND] = true;
1251
1510
  ledger;
1252
1511
  mempool = {};
1253
1512
  /**
@@ -1261,6 +1520,7 @@ var Emulator = class {
1261
1520
  protocolParameters;
1262
1521
  datumTable = {};
1263
1522
  treasury;
1523
+ transactionHistory = {};
1264
1524
  constructor(accounts, protocolParameters = PROTOCOL_PARAMETERS_DEFAULT, treasury = 0n) {
1265
1525
  const GENESIS_HASH = "00".repeat(32);
1266
1526
  this.blockHeight = 0;
@@ -1296,12 +1556,27 @@ var Emulator = class {
1296
1556
  now() {
1297
1557
  return this.time;
1298
1558
  }
1559
+ confirmPendingTransactions(blockHeight, slot) {
1560
+ for (const [txHash, status] of Object.entries(this.transactionHistory)) {
1561
+ if (status.status === "pending") {
1562
+ this.transactionHistory[txHash] = {
1563
+ status: "confirmed",
1564
+ blockHeight,
1565
+ slot
1566
+ };
1567
+ }
1568
+ }
1569
+ }
1299
1570
  awaitSlot(length = 1) {
1300
1571
  this.slot += length;
1301
1572
  this.time += length * 1e3;
1302
1573
  const currentHeight = this.blockHeight;
1303
1574
  this.blockHeight = Math.floor(this.slot / 20);
1304
1575
  if (this.blockHeight > currentHeight) {
1576
+ this.confirmPendingTransactions(
1577
+ currentHeight + 1,
1578
+ (currentHeight + 1) * 20
1579
+ );
1305
1580
  for (const [outRef, { utxo, spent }] of Object.entries(this.mempool)) {
1306
1581
  this.ledger[outRef] = { utxo, spent };
1307
1582
  }
@@ -1312,9 +1587,14 @@ var Emulator = class {
1312
1587
  }
1313
1588
  }
1314
1589
  awaitBlock(height = 1) {
1590
+ const previousHeight = this.blockHeight;
1591
+ const previousSlot = this.slot;
1315
1592
  this.blockHeight += height;
1316
1593
  this.slot += height * 20;
1317
1594
  this.time += height * 20 * 1e3;
1595
+ if (height > 0) {
1596
+ this.confirmPendingTransactions(previousHeight + 1, previousSlot + 20);
1597
+ }
1318
1598
  for (const [outRef, { utxo, spent }] of Object.entries(this.mempool)) {
1319
1599
  this.ledger[outRef] = { utxo, spent };
1320
1600
  }
@@ -1324,14 +1604,17 @@ var Emulator = class {
1324
1604
  this.mempool = {};
1325
1605
  }
1326
1606
  getUtxos(addressOrCredential) {
1327
- const utxos = Object.values(this.ledger).flatMap(({ utxo }) => {
1328
- if (typeof addressOrCredential === "string") {
1329
- return addressOrCredential === utxo.address ? utxo : [];
1330
- } else {
1331
- const { paymentCredential } = getAddressDetails(utxo.address);
1332
- return paymentCredential?.hash === addressOrCredential.hash ? utxo : [];
1607
+ const utxos = Object.values(this.ledger).flatMap(
1608
+ ({ utxo, spent }) => {
1609
+ if (spent) return [];
1610
+ if (typeof addressOrCredential === "string") {
1611
+ return addressOrCredential === utxo.address ? utxo : [];
1612
+ } else {
1613
+ const { paymentCredential } = getAddressDetails(utxo.address);
1614
+ return paymentCredential?.hash === addressOrCredential.hash ? utxo : [];
1615
+ }
1333
1616
  }
1334
- });
1617
+ );
1335
1618
  return Promise.resolve(utxos);
1336
1619
  }
1337
1620
  getProtocolParameters() {
@@ -1344,32 +1627,44 @@ var Emulator = class {
1344
1627
  return Promise.resolve(this.datumTable[datumHash]);
1345
1628
  }
1346
1629
  getUtxosWithUnit(addressOrCredential, unit) {
1347
- const utxos = Object.values(this.ledger).flatMap(({ utxo }) => {
1348
- if (typeof addressOrCredential === "string") {
1349
- return addressOrCredential === utxo.address && utxo.assets[unit] > 0n ? utxo : [];
1350
- } else {
1351
- const { paymentCredential } = getAddressDetails(utxo.address);
1352
- return paymentCredential?.hash === addressOrCredential.hash && utxo.assets[unit] > 0n ? utxo : [];
1630
+ const utxos = Object.values(this.ledger).flatMap(
1631
+ ({ utxo, spent }) => {
1632
+ if (spent) return [];
1633
+ if (typeof addressOrCredential === "string") {
1634
+ return addressOrCredential === utxo.address && utxo.assets[unit] > 0n ? utxo : [];
1635
+ } else {
1636
+ const { paymentCredential } = getAddressDetails(utxo.address);
1637
+ return paymentCredential?.hash === addressOrCredential.hash && utxo.assets[unit] > 0n ? utxo : [];
1638
+ }
1353
1639
  }
1354
- });
1640
+ );
1355
1641
  return Promise.resolve(utxos);
1356
1642
  }
1357
1643
  getUtxosByOutRef(outRefs) {
1358
1644
  return Promise.resolve(
1359
- outRefs.flatMap(
1360
- (outRef) => this.ledger[outRef.txHash + outRef.outputIndex]?.utxo || []
1361
- )
1645
+ outRefs.flatMap((outRef) => {
1646
+ const entry = this.ledger[outRef.txHash + outRef.outputIndex];
1647
+ return entry && !entry.spent ? entry.utxo : [];
1648
+ })
1362
1649
  );
1363
1650
  }
1364
1651
  getUtxoByUnit(unit) {
1365
1652
  const utxos = Object.values(this.ledger).flatMap(
1366
- ({ utxo }) => utxo.assets[unit] > 0n ? utxo : []
1653
+ ({ utxo, spent }) => !spent && utxo.assets[unit] > 0n ? utxo : []
1367
1654
  );
1368
1655
  if (utxos.length > 1) {
1369
1656
  throw new Error("Unit needs to be an NFT or only held by one address.");
1370
1657
  }
1371
1658
  return Promise.resolve(utxos[0]);
1372
1659
  }
1660
+ getRewardAccount(rewardAddress) {
1661
+ const account = this.chain[rewardAddress];
1662
+ return Promise.resolve({
1663
+ registered: account?.registeredStake ?? false,
1664
+ poolId: account?.delegation.poolId ?? null,
1665
+ rewards: account?.delegation.rewards ?? 0n
1666
+ });
1667
+ }
1373
1668
  getDelegation(rewardAddress) {
1374
1669
  return Promise.resolve({
1375
1670
  poolId: this.chain[rewardAddress]?.delegation?.poolId || null,
@@ -1377,12 +1672,34 @@ var Emulator = class {
1377
1672
  });
1378
1673
  }
1379
1674
  awaitTx(txHash) {
1380
- if (this.mempool[txHash + 0]) {
1675
+ if (this.transactionHistory[txHash]?.status === "pending") {
1381
1676
  this.awaitBlock();
1382
1677
  return Promise.resolve(true);
1383
1678
  }
1384
1679
  return Promise.resolve(true);
1385
1680
  }
1681
+ getTransactionStatus(txHash, options = {}) {
1682
+ if (options.signal?.aborted) {
1683
+ return Promise.reject(
1684
+ options.signal.reason instanceof Error ? options.signal.reason : new DOMException("The operation was aborted.", "AbortError")
1685
+ );
1686
+ }
1687
+ const status = this.transactionHistory[txHash];
1688
+ if (!status) return Promise.resolve({ status: "not_found", txHash });
1689
+ if (status.status === "pending") {
1690
+ return Promise.resolve({ status: "pending", txHash });
1691
+ }
1692
+ return Promise.resolve({
1693
+ status: "confirmed",
1694
+ txHash,
1695
+ confirmation: {
1696
+ txHash,
1697
+ blockHeight: status.blockHeight,
1698
+ slot: status.slot,
1699
+ confirmations: this.blockHeight - status.blockHeight + 1
1700
+ }
1701
+ });
1702
+ }
1386
1703
  /**
1387
1704
  * Emulates the behaviour of the reward distribution at epoch boundaries.
1388
1705
  * Stake keys need to be registered and delegated like on a real chain in order to receive rewards.
@@ -2063,6 +2380,7 @@ It does not exist or was already spent.`
2063
2380
  for (const [datumHash, datum] of Object.entries(datumTable)) {
2064
2381
  this.datumTable[datumHash] = datum;
2065
2382
  }
2383
+ this.transactionHistory[txHash] = { status: "pending" };
2066
2384
  return Promise.resolve(txHash);
2067
2385
  }
2068
2386
  async evaluateTx(tx, additionalUTxOs) {
@@ -2318,21 +2636,30 @@ var Maestro = class {
2318
2636
  );
2319
2637
  return utxos.map(this.maestroUtxoToUtxo);
2320
2638
  }
2321
- async getDelegation(rewardAddress) {
2322
- const timestampedResultResponse = await fetch(
2323
- `${this.url}/accounts/${rewardAddress}`,
2324
- { headers: this.commonHeaders() }
2325
- );
2326
- if (!timestampedResultResponse.ok) {
2327
- return { poolId: null, rewards: 0n };
2639
+ async getRewardAccount(rewardAddress) {
2640
+ const response = await fetch(`${this.url}/accounts/${rewardAddress}`, {
2641
+ headers: this.requireAmountsAsStrings(this.commonHeaders())
2642
+ });
2643
+ if (response.status === 404) {
2644
+ return { registered: false, poolId: null, rewards: 0n };
2328
2645
  }
2329
- const timestampedResult = await timestampedResultResponse.json();
2646
+ if (!response.ok) {
2647
+ throw new Error(
2648
+ `Could not fetch reward account from Maestro. Received status code: ${response.status}`
2649
+ );
2650
+ }
2651
+ const timestampedResult = await response.json();
2330
2652
  const result = timestampedResult.data;
2331
2653
  return {
2654
+ registered: result.registered,
2332
2655
  poolId: result.delegated_pool || null,
2333
2656
  rewards: BigInt(result.rewards_available)
2334
2657
  };
2335
2658
  }
2659
+ async getDelegation(rewardAddress) {
2660
+ const { poolId, rewards } = await this.getRewardAccount(rewardAddress);
2661
+ return { poolId, rewards };
2662
+ }
2336
2663
  async getDatum(datumHash) {
2337
2664
  const timestampedResultResponse = await fetch(
2338
2665
  `${this.url}/datums/${datumHash}`,
@@ -2370,6 +2697,42 @@ var Maestro = class {
2370
2697
  }, checkInterval);
2371
2698
  });
2372
2699
  }
2700
+ async getTransactionStatus(txHash, options = {}) {
2701
+ const response = await fetch(`${this.url}/txmanager/${txHash}/state`, {
2702
+ headers: this.commonHeaders(),
2703
+ signal: options.signal
2704
+ });
2705
+ if (response.status === 404) return { status: "not_found", txHash };
2706
+ if (!response.ok) {
2707
+ throw new Error(
2708
+ `Could not fetch transaction status from Maestro. Received status code: ${response.status}`
2709
+ );
2710
+ }
2711
+ const result = await response.json();
2712
+ switch (result.status) {
2713
+ case "pending":
2714
+ return { status: "pending", txHash };
2715
+ case "confirmed":
2716
+ return {
2717
+ status: "confirmed",
2718
+ txHash,
2719
+ confirmation: {
2720
+ txHash,
2721
+ confirmations: result.confirmations
2722
+ }
2723
+ };
2724
+ case "failed":
2725
+ return {
2726
+ status: "failed",
2727
+ txHash,
2728
+ reason: result.reason ?? result.error
2729
+ };
2730
+ default:
2731
+ throw new Error(
2732
+ `Maestro returned an unknown transaction status: ${String(result.status)}`
2733
+ );
2734
+ }
2735
+ }
2373
2736
  async submitTx(tx) {
2374
2737
  let queryUrl = `${this.url}/txmanager`;
2375
2738
  queryUrl += this.turboSubmit ? "/turbosubmit" : "";
@@ -2413,7 +2776,7 @@ var Maestro = class {
2413
2776
  address: result.address,
2414
2777
  datumHash: result.datum ? result.datum.type == "inline" ? void 0 : result.datum.hash : void 0,
2415
2778
  datum: result.datum?.bytes,
2416
- scriptRef: toScriptRef(result.reference_script)
2779
+ scriptRef: toScriptRef2(result.reference_script)
2417
2780
  };
2418
2781
  }
2419
2782
  async getAllPagesData(getResponse, qry, paramsGiven, errorMsg) {
@@ -2464,7 +2827,7 @@ var Maestro = class {
2464
2827
  return result;
2465
2828
  }
2466
2829
  };
2467
- var toScriptRef = (reference_script) => {
2830
+ var toScriptRef2 = (reference_script) => {
2468
2831
  if (reference_script && reference_script.bytes) {
2469
2832
  switch (reference_script.type) {
2470
2833
  case "native":
@@ -2719,8 +3082,13 @@ var AssetAddressSchema = S4.Struct({
2719
3082
  quantity: S4.String
2720
3083
  });
2721
3084
  var AccountInfoSchema = S4.Struct({
3085
+ status: S4.Literal("registered", "not registered"),
2722
3086
  delegated_pool: S4.NullOr(S4.String),
2723
- rewards_available: S4.NumberFromString
3087
+ rewards_available: S4.String
3088
+ });
3089
+ var TxStatusSchema = S4.Struct({
3090
+ tx_hash: S4.String,
3091
+ num_confirmations: S4.NullOr(S4.Number)
2724
3092
  });
2725
3093
  var DatumInfo = S4.Struct({
2726
3094
  bytes: S4.String
@@ -2741,9 +3109,9 @@ var toUTxO = (koiosUTxO, address) => ({
2741
3109
  address,
2742
3110
  datumHash: koiosUTxO.inline_datum ? void 0 : koiosUTxO.datum_hash || void 0,
2743
3111
  datum: koiosUTxO.inline_datum ? koiosUTxO.inline_datum.bytes : void 0,
2744
- scriptRef: toScriptRef2(koiosUTxO.reference_script)
3112
+ scriptRef: toScriptRef3(koiosUTxO.reference_script)
2745
3113
  });
2746
- var toScriptRef2 = (reference_script) => {
3114
+ var toScriptRef3 = (reference_script) => {
2747
3115
  if (reference_script && reference_script.bytes && reference_script.type) {
2748
3116
  switch (reference_script.type) {
2749
3117
  case "plutusV1":
@@ -2786,9 +3154,9 @@ var getUtxosEffect = (baseUrl, addressOrCredential, headers) => {
2786
3154
  };
2787
3155
 
2788
3156
  // src/koios.ts
2789
- import { Data as Data2, Effect as Effect4, pipe as pipe5, Schedule as Schedule2, Schema as S5 } from "effect";
3157
+ import { Data, Effect as Effect4, pipe as pipe5, Schedule as Schedule2, Schema as S5 } from "effect";
2790
3158
  import { FetchHttpClient as FetchHttpClient3 } from "@effect/platform";
2791
- var KoiosError = class extends Data2.TaggedError("KoiosError") {
3159
+ var KoiosError = class extends Data.TaggedError("KoiosError") {
2792
3160
  get message() {
2793
3161
  return `${this.cause}`;
2794
3162
  }
@@ -2957,7 +3325,7 @@ var Koios = class {
2957
3325
  return [];
2958
3326
  }
2959
3327
  }
2960
- async getDelegation(rewardAddress) {
3328
+ async getRewardAccount(rewardAddress) {
2961
3329
  const body = {
2962
3330
  _stake_addresses: [rewardAddress]
2963
3331
  };
@@ -2972,18 +3340,24 @@ var Koios = class {
2972
3340
  ),
2973
3341
  // Allows for dependency injection and easier testing
2974
3342
  Effect4.provide(FetchHttpClient3.layer),
2975
- Effect4.flatMap(
2976
- (result2) => result2.length === 0 ? Effect4.fail("No Delegation Found by Reward Address") : Effect4.succeed(result2[0])
2977
- ),
2978
3343
  Effect4.timeout(1e4),
2979
3344
  Effect4.catchAllCause((cause) => new KoiosError({ cause })),
2980
3345
  Effect4.runPromise
2981
3346
  );
3347
+ const account = result[0];
3348
+ if (!account) {
3349
+ return { registered: false, poolId: null, rewards: 0n };
3350
+ }
2982
3351
  return {
2983
- poolId: result.delegated_pool || null,
2984
- rewards: BigInt(result.rewards_available)
3352
+ registered: account.status === "registered",
3353
+ poolId: account.delegated_pool || null,
3354
+ rewards: BigInt(account.rewards_available)
2985
3355
  };
2986
3356
  }
3357
+ async getDelegation(rewardAddress) {
3358
+ const { poolId, rewards } = await this.getRewardAccount(rewardAddress);
3359
+ return { poolId, rewards };
3360
+ }
2987
3361
  async getDatum(datumHash) {
2988
3362
  const url = `${this.baseUrl}/datum_info`;
2989
3363
  const body = {
@@ -3030,6 +3404,38 @@ var Koios = class {
3030
3404
  );
3031
3405
  return result;
3032
3406
  }
3407
+ async getTransactionStatus(txHash, options = {}) {
3408
+ const url = `${this.baseUrl}/tx_status`;
3409
+ const body = { _tx_hashes: [txHash] };
3410
+ const bearerToken = this.token ? { Authorization: `Bearer ${this.token}` } : void 0;
3411
+ const response = await fetch(url, {
3412
+ method: "POST",
3413
+ headers: { "Content-Type": "application/json", ...bearerToken },
3414
+ body: JSON.stringify(body),
3415
+ signal: options.signal
3416
+ });
3417
+ if (response.status === 404) return { status: "not_found", txHash };
3418
+ if (!response.ok) {
3419
+ throw new Error(
3420
+ `Could not fetch transaction status from Koios. Received status code: ${response.status}`
3421
+ );
3422
+ }
3423
+ const result = S5.decodeUnknownSync(S5.Array(TxStatusSchema))(
3424
+ await response.json()
3425
+ );
3426
+ const status = result[0];
3427
+ if (!status || status.num_confirmations === null) {
3428
+ return { status: "not_found", txHash };
3429
+ }
3430
+ return {
3431
+ status: "confirmed",
3432
+ txHash,
3433
+ confirmation: {
3434
+ txHash,
3435
+ confirmations: status.num_confirmations
3436
+ }
3437
+ };
3438
+ }
3033
3439
  async submitTx(tx) {
3034
3440
  const url = `${this.baseUrl}/submittx`;
3035
3441
  const body = fromHex4(tx);
@@ -3085,6 +3491,8 @@ export {
3085
3491
  Kupmios,
3086
3492
  KupmiosError,
3087
3493
  Maestro,
3494
+ OgmiosJsonRpcError,
3088
3495
  generateEmulatorAccount,
3089
- generateEmulatorAccountFromPrivateKey
3496
+ generateEmulatorAccountFromPrivateKey,
3497
+ isEmulatorProvider
3090
3498
  };