@lucid-evolution/provider 0.1.34 → 0.1.35

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
@@ -14,7 +14,7 @@ import { applyDoubleCborEncoding } from "@lucid-evolution/utils";
14
14
  // package.json
15
15
  var package_default = {
16
16
  name: "@lucid-evolution/provider",
17
- version: "0.1.34",
17
+ version: "0.1.35",
18
18
  description: "",
19
19
  main: "./dist/index.js",
20
20
  types: "./dist/index.d.ts",
@@ -51,6 +51,7 @@ var package_default = {
51
51
  "@lucid-evolution/core-types": "workspace:*",
52
52
  "@lucid-evolution/core-utils": "workspace:*",
53
53
  "@lucid-evolution/utils": "workspace:*",
54
+ "@lucid-evolution/wallet": "workspace:*",
54
55
  effect: "^3.5.6"
55
56
  },
56
57
  devDependencies: {
@@ -713,9 +714,671 @@ var kupmiosUtxosToUtxos = (kupoURL, utxos) => Effect.forEach(
713
714
  { concurrency: "unbounded" }
714
715
  );
715
716
 
717
+ // src/emulator.ts
718
+ import {
719
+ generateSeedPhrase,
720
+ PROTOCOL_PARAMETERS_DEFAULT
721
+ } from "@lucid-evolution/utils";
722
+ import { coreToUtxo, getAddressDetails } from "@lucid-evolution/utils";
723
+ import { fromHex as fromHex2 } from "@lucid-evolution/core-utils";
724
+ import { walletFromSeed } from "@lucid-evolution/wallet";
725
+ function generateEmulatorAccount(assets) {
726
+ const seedPhrase = generateSeedPhrase();
727
+ return {
728
+ seedPhrase,
729
+ address: walletFromSeed(seedPhrase, {
730
+ addressType: "Base",
731
+ accountIndex: 0,
732
+ network: "Custom"
733
+ }).address,
734
+ assets
735
+ };
736
+ }
737
+ var Emulator = class {
738
+ ledger;
739
+ mempool = {};
740
+ /**
741
+ * Only stake key registrations/delegations and rewards are tracked.
742
+ * Other certificates are not tracked.
743
+ */
744
+ chain = {};
745
+ blockHeight;
746
+ slot;
747
+ time;
748
+ protocolParameters;
749
+ datumTable = {};
750
+ constructor(accounts, protocolParameters = PROTOCOL_PARAMETERS_DEFAULT) {
751
+ const GENESIS_HASH = "00".repeat(32);
752
+ this.blockHeight = 0;
753
+ this.slot = 0;
754
+ this.time = Date.now();
755
+ this.ledger = {};
756
+ accounts.forEach(({ address, assets, outputData }, index) => {
757
+ if ([outputData?.hash, outputData?.asHash, outputData?.inline].filter(
758
+ (b) => b
759
+ ).length > 1) {
760
+ throw new Error(
761
+ "Not allowed to set hash, asHash and inline at the same time."
762
+ );
763
+ }
764
+ this.ledger[GENESIS_HASH + index] = {
765
+ utxo: {
766
+ txHash: GENESIS_HASH,
767
+ outputIndex: index,
768
+ address,
769
+ assets,
770
+ datumHash: outputData?.asHash ? CML.hash_plutus_data(
771
+ CML.PlutusData.from_cbor_hex(outputData.asHash)
772
+ ).to_hex() : outputData?.hash,
773
+ datum: outputData?.inline,
774
+ scriptRef: outputData?.scriptRef
775
+ },
776
+ spent: false
777
+ };
778
+ });
779
+ this.protocolParameters = protocolParameters;
780
+ }
781
+ now() {
782
+ return this.time;
783
+ }
784
+ awaitSlot(length = 1) {
785
+ this.slot += length;
786
+ this.time += length * 1e3;
787
+ const currentHeight = this.blockHeight;
788
+ this.blockHeight = Math.floor(this.slot / 20);
789
+ if (this.blockHeight > currentHeight) {
790
+ for (const [outRef, { utxo, spent }] of Object.entries(this.mempool)) {
791
+ this.ledger[outRef] = { utxo, spent };
792
+ }
793
+ for (const [outRef, { spent }] of Object.entries(this.ledger)) {
794
+ if (spent) delete this.ledger[outRef];
795
+ }
796
+ this.mempool = {};
797
+ }
798
+ }
799
+ awaitBlock(height = 1) {
800
+ this.blockHeight += height;
801
+ this.slot += height * 20;
802
+ this.time += height * 20 * 1e3;
803
+ for (const [outRef, { utxo, spent }] of Object.entries(this.mempool)) {
804
+ this.ledger[outRef] = { utxo, spent };
805
+ }
806
+ for (const [outRef, { spent }] of Object.entries(this.ledger)) {
807
+ if (spent) delete this.ledger[outRef];
808
+ }
809
+ this.mempool = {};
810
+ }
811
+ getUtxos(addressOrCredential) {
812
+ const utxos = Object.values(this.ledger).flatMap(({ utxo }) => {
813
+ if (typeof addressOrCredential === "string") {
814
+ return addressOrCredential === utxo.address ? utxo : [];
815
+ } else {
816
+ const { paymentCredential } = getAddressDetails(utxo.address);
817
+ return paymentCredential?.hash === addressOrCredential.hash ? utxo : [];
818
+ }
819
+ });
820
+ return Promise.resolve(utxos);
821
+ }
822
+ getProtocolParameters() {
823
+ return Promise.resolve(this.protocolParameters);
824
+ }
825
+ getDatum(datumHash) {
826
+ return Promise.resolve(this.datumTable[datumHash]);
827
+ }
828
+ getUtxosWithUnit(addressOrCredential, unit) {
829
+ const utxos = Object.values(this.ledger).flatMap(({ utxo }) => {
830
+ if (typeof addressOrCredential === "string") {
831
+ return addressOrCredential === utxo.address && utxo.assets[unit] > 0n ? utxo : [];
832
+ } else {
833
+ const { paymentCredential } = getAddressDetails(utxo.address);
834
+ return paymentCredential?.hash === addressOrCredential.hash && utxo.assets[unit] > 0n ? utxo : [];
835
+ }
836
+ });
837
+ return Promise.resolve(utxos);
838
+ }
839
+ getUtxosByOutRef(outRefs) {
840
+ return Promise.resolve(
841
+ outRefs.flatMap(
842
+ (outRef) => this.ledger[outRef.txHash + outRef.outputIndex]?.utxo || []
843
+ )
844
+ );
845
+ }
846
+ getUtxoByUnit(unit) {
847
+ const utxos = Object.values(this.ledger).flatMap(
848
+ ({ utxo }) => utxo.assets[unit] > 0n ? utxo : []
849
+ );
850
+ if (utxos.length > 1) {
851
+ throw new Error("Unit needs to be an NFT or only held by one address.");
852
+ }
853
+ return Promise.resolve(utxos[0]);
854
+ }
855
+ getDelegation(rewardAddress) {
856
+ return Promise.resolve({
857
+ poolId: this.chain[rewardAddress]?.delegation?.poolId || null,
858
+ rewards: this.chain[rewardAddress]?.delegation?.rewards || 0n
859
+ });
860
+ }
861
+ awaitTx(txHash) {
862
+ if (this.mempool[txHash + 0]) {
863
+ this.awaitBlock();
864
+ return Promise.resolve(true);
865
+ }
866
+ return Promise.resolve(true);
867
+ }
868
+ /**
869
+ * Emulates the behaviour of the reward distribution at epoch boundaries.
870
+ * Stake keys need to be registered and delegated like on a real chain in order to receive rewards.
871
+ */
872
+ distributeRewards(rewards) {
873
+ for (const [
874
+ rewardAddress,
875
+ { registeredStake, delegation }
876
+ ] of Object.entries(this.chain)) {
877
+ if (registeredStake && delegation.poolId) {
878
+ this.chain[rewardAddress] = {
879
+ registeredStake,
880
+ delegation: {
881
+ poolId: delegation.poolId,
882
+ rewards: delegation.rewards += rewards
883
+ }
884
+ };
885
+ }
886
+ }
887
+ this.awaitBlock();
888
+ }
889
+ submitTx(tx) {
890
+ const desTx = CML.Transaction.from_cbor_hex(tx);
891
+ const body = desTx.body();
892
+ const witnesses = desTx.witness_set();
893
+ const datums = witnesses.plutus_datums();
894
+ const txHash = CML.hash_transaction(body).to_hex();
895
+ const lowerBound = body.validity_interval_start() ? parseInt(body.validity_interval_start().toString()) : null;
896
+ const upperBound = body.ttl() ? parseInt(body.ttl().toString()) : null;
897
+ if (Number.isInteger(lowerBound) && this.slot < lowerBound) {
898
+ throw new Error(
899
+ `Lower bound (${lowerBound}) not in slot range (${this.slot}).`
900
+ );
901
+ }
902
+ if (Number.isInteger(upperBound) && this.slot > upperBound) {
903
+ throw new Error(
904
+ `Upper bound (${upperBound}) not in slot range (${this.slot}).`
905
+ );
906
+ }
907
+ const datumTable = (() => {
908
+ const table = {};
909
+ for (let i = 0; i < (datums?.len() || 0); i++) {
910
+ const datum = datums.get(i);
911
+ const datumHash = CML.hash_plutus_data(datum).to_hex();
912
+ table[datumHash] = datum.to_cbor_hex();
913
+ }
914
+ return table;
915
+ })();
916
+ const consumedHashes = /* @__PURE__ */ new Set();
917
+ const keyHashes = (() => {
918
+ const keyHashes2 = [];
919
+ for (let i = 0; i < (witnesses.vkeywitnesses()?.len() || 0); i++) {
920
+ const witness = witnesses.vkeywitnesses().get(i);
921
+ const publicKey = witness.vkey();
922
+ const keyHash = publicKey.hash().to_hex();
923
+ if (!publicKey.verify(fromHex2(txHash), witness.ed25519_signature())) {
924
+ throw new Error(`Invalid vkey witness. Key hash: ${keyHash}`);
925
+ }
926
+ keyHashes2.push(keyHash);
927
+ }
928
+ return keyHashes2;
929
+ })();
930
+ const edKeyHashes = CML.Ed25519KeyHashList.new();
931
+ keyHashes.forEach(
932
+ (keyHash) => edKeyHashes.add(CML.Ed25519KeyHash.from_hex(keyHash))
933
+ );
934
+ const nativeHashes = (() => {
935
+ const scriptHashes = [];
936
+ for (let i = 0; i < (witnesses.native_scripts()?.len() || 0); i++) {
937
+ const witness = witnesses.native_scripts().get(i);
938
+ const scriptHash = witness.hash().to_hex();
939
+ if (!witness.verify(
940
+ Number.isInteger(lowerBound) ? CML.BigInteger.from_str(lowerBound.toString()).to_js_value() : void 0,
941
+ Number.isInteger(upperBound) ? CML.BigInteger.from_str(upperBound.toString()).to_js_value() : void 0,
942
+ edKeyHashes
943
+ )) {
944
+ throw new Error(
945
+ `Invalid native script witness. Script hash: ${scriptHash}`
946
+ );
947
+ }
948
+ for (let i2 = 0; i2 < witness.get_required_signers().len(); i2++) {
949
+ const keyHash = witness.get_required_signers().get(i2).to_hex();
950
+ consumedHashes.add(keyHash);
951
+ }
952
+ scriptHashes.push(scriptHash);
953
+ }
954
+ return scriptHashes;
955
+ })();
956
+ const nativeHashesOptional = {};
957
+ const plutusHashesOptional = [];
958
+ const plutusHashes = (() => {
959
+ const scriptHashes = [];
960
+ for (let i = 0; i < (witnesses.plutus_v1_scripts()?.len() || 0); i++) {
961
+ const script = witnesses.plutus_v1_scripts().get(i);
962
+ const scriptHash = script.hash().to_hex();
963
+ scriptHashes.push(scriptHash);
964
+ }
965
+ for (let i = 0; i < (witnesses.plutus_v2_scripts()?.len() || 0); i++) {
966
+ const script = witnesses.plutus_v2_scripts().get(i);
967
+ const scriptHash = script.hash().to_hex();
968
+ scriptHashes.push(scriptHash);
969
+ }
970
+ return scriptHashes;
971
+ })();
972
+ const inputs = body.inputs();
973
+ const resolvedInputs = [];
974
+ for (let i = 0; i < inputs.len(); i++) {
975
+ const input = inputs.get(i);
976
+ const outRef = input.transaction_id().to_hex() + input.index().toString();
977
+ const entryLedger = this.ledger[outRef];
978
+ const { entry, type } = !entryLedger ? { entry: this.mempool[outRef], type: "Mempool" } : { entry: entryLedger, type: "Ledger" };
979
+ if (!entry || entry.spent) {
980
+ throw new Error(
981
+ `Could not spend UTxO: ${JSON.stringify({
982
+ txHash: entry?.utxo.txHash,
983
+ outputIndex: entry?.utxo.outputIndex
984
+ })}
985
+ It does not exist or was already spent.`
986
+ );
987
+ }
988
+ const scriptRef = entry.utxo.scriptRef;
989
+ if (scriptRef) {
990
+ switch (scriptRef.type) {
991
+ case "Native": {
992
+ const script = CML.NativeScript.from_cbor_bytes(
993
+ fromHex2(scriptRef.script)
994
+ );
995
+ nativeHashesOptional[script.hash().to_hex()] = script;
996
+ break;
997
+ }
998
+ case "PlutusV1": {
999
+ const script = CML.PlutusScript.from_v1(
1000
+ CML.PlutusV1Script.from_cbor_bytes(fromHex2(scriptRef.script))
1001
+ );
1002
+ plutusHashesOptional.push(script.hash().to_hex());
1003
+ break;
1004
+ }
1005
+ case "PlutusV2": {
1006
+ const script = CML.PlutusScript.from_v2(
1007
+ CML.PlutusV2Script.from_cbor_bytes(fromHex2(scriptRef.script))
1008
+ );
1009
+ plutusHashesOptional.push(script.hash().to_hex());
1010
+ break;
1011
+ }
1012
+ }
1013
+ }
1014
+ if (entry.utxo.datumHash) consumedHashes.add(entry.utxo.datumHash);
1015
+ resolvedInputs.push({ entry, type });
1016
+ }
1017
+ for (let i = 0; i < (body.reference_inputs()?.len() || 0); i++) {
1018
+ const input = body.reference_inputs().get(i);
1019
+ const outRef = input.transaction_id().to_hex() + input.index().toString();
1020
+ const entry = this.ledger[outRef] || this.mempool[outRef];
1021
+ if (!entry || entry.spent) {
1022
+ throw new Error(
1023
+ `Could not read UTxO: ${JSON.stringify({
1024
+ txHash: entry?.utxo.txHash,
1025
+ outputIndex: entry?.utxo.outputIndex
1026
+ })}
1027
+ It does not exist or was already spent.`
1028
+ );
1029
+ }
1030
+ const scriptRef = entry.utxo.scriptRef;
1031
+ if (scriptRef) {
1032
+ switch (scriptRef.type) {
1033
+ case "Native": {
1034
+ const script = CML.NativeScript.from_cbor_bytes(
1035
+ fromHex2(scriptRef.script)
1036
+ );
1037
+ nativeHashesOptional[script.hash().to_hex()] = script;
1038
+ break;
1039
+ }
1040
+ case "PlutusV1": {
1041
+ const script = CML.PlutusScript.from_v1(
1042
+ CML.PlutusV1Script.from_cbor_bytes(fromHex2(scriptRef.script))
1043
+ );
1044
+ plutusHashesOptional.push(script.hash().to_hex());
1045
+ break;
1046
+ }
1047
+ case "PlutusV2": {
1048
+ const script = CML.PlutusScript.from_v2(
1049
+ CML.PlutusV2Script.from_cbor_bytes(fromHex2(scriptRef.script))
1050
+ );
1051
+ plutusHashesOptional.push(script.hash().to_hex());
1052
+ break;
1053
+ }
1054
+ }
1055
+ }
1056
+ if (entry.utxo.datumHash) consumedHashes.add(entry.utxo.datumHash);
1057
+ }
1058
+ const redeemers = (() => {
1059
+ const tagMap = {
1060
+ 0: "Spend",
1061
+ 1: "Mint",
1062
+ 2: "Cert",
1063
+ 3: "Reward"
1064
+ };
1065
+ const collected = [];
1066
+ for (let i = 0; i < (witnesses.redeemers()?.to_js_value().len() || 0); i++) {
1067
+ const redeemer = witnesses.redeemers().to_js_value().get(i);
1068
+ collected.push({
1069
+ tag: tagMap[redeemer.tag().kind()],
1070
+ index: parseInt(redeemer.index().to_str())
1071
+ });
1072
+ }
1073
+ return collected;
1074
+ })();
1075
+ function checkAndConsumeHash(credential, tag, index) {
1076
+ switch (credential.type) {
1077
+ case "Key": {
1078
+ if (!keyHashes.includes(credential.hash)) {
1079
+ throw new Error(
1080
+ `Missing vkey witness. Key hash: ${credential.hash}`
1081
+ );
1082
+ }
1083
+ consumedHashes.add(credential.hash);
1084
+ break;
1085
+ }
1086
+ case "Script": {
1087
+ if (nativeHashes.includes(credential.hash)) {
1088
+ consumedHashes.add(credential.hash);
1089
+ break;
1090
+ } else if (nativeHashesOptional[credential.hash]) {
1091
+ if (!nativeHashesOptional[credential.hash].verify(
1092
+ Number.isInteger(lowerBound) ? CML.BigInteger.from_str(
1093
+ lowerBound.toString()
1094
+ ).to_js_value() : void 0,
1095
+ Number.isInteger(upperBound) ? CML.BigInteger.from_str(
1096
+ upperBound.toString()
1097
+ ).to_js_value() : void 0,
1098
+ edKeyHashes
1099
+ )) {
1100
+ throw new Error(
1101
+ `Invalid native script witness. Script hash: ${credential.hash}`
1102
+ );
1103
+ }
1104
+ break;
1105
+ } else if (plutusHashes.includes(credential.hash) || plutusHashesOptional.includes(credential.hash)) {
1106
+ if (redeemers.find(
1107
+ (redeemer) => redeemer.tag === tag && redeemer.index === index
1108
+ )) {
1109
+ consumedHashes.add(credential.hash);
1110
+ break;
1111
+ }
1112
+ }
1113
+ throw new Error(
1114
+ `Missing script witness. Script hash: ${credential.hash}`
1115
+ );
1116
+ }
1117
+ }
1118
+ }
1119
+ for (let i = 0; i < (body.collateral_inputs()?.len() || 0); i++) {
1120
+ const input = body.collateral_inputs().get(i);
1121
+ const outRef = input.transaction_id().to_hex() + input.index().toString();
1122
+ const entry = this.ledger[outRef] || this.mempool[outRef];
1123
+ if (!entry || entry.spent) {
1124
+ throw new Error(
1125
+ `Could not read UTxO: ${JSON.stringify({
1126
+ txHash: entry?.utxo.txHash,
1127
+ outputIndex: entry?.utxo.outputIndex
1128
+ })}
1129
+ It does not exist or was already spent.`
1130
+ );
1131
+ }
1132
+ const { paymentCredential } = getAddressDetails(entry.utxo.address);
1133
+ if (paymentCredential?.type === "Script") {
1134
+ throw new Error("Collateral inputs can only contain vkeys.");
1135
+ }
1136
+ checkAndConsumeHash(paymentCredential, null, null);
1137
+ }
1138
+ for (let i = 0; i < (body.required_signers()?.len() || 0); i++) {
1139
+ const signer = body.required_signers().get(i);
1140
+ checkAndConsumeHash({ type: "Key", hash: signer.to_hex() }, null, null);
1141
+ }
1142
+ for (let index = 0; index < (body.mint()?.keys().len() || 0); index++) {
1143
+ const policyId = body.mint().keys().get(index).to_hex();
1144
+ checkAndConsumeHash({ type: "Script", hash: policyId }, "Mint", index);
1145
+ }
1146
+ const withdrawalRequests = [];
1147
+ for (let index = 0; index < (body.withdrawals()?.keys().len() || 0); index++) {
1148
+ const rawAddress = body.withdrawals().keys().get(index);
1149
+ const withdrawal = BigInt(
1150
+ body.withdrawals().get(rawAddress).toString()
1151
+ );
1152
+ const rewardAddress = rawAddress.to_address().to_bech32(void 0);
1153
+ const { stakeCredential } = getAddressDetails(rewardAddress);
1154
+ checkAndConsumeHash(stakeCredential, "Reward", index);
1155
+ if (this.chain[rewardAddress]?.delegation.rewards !== withdrawal) {
1156
+ throw new Error(
1157
+ "Withdrawal amount doesn't match actual reward balance."
1158
+ );
1159
+ }
1160
+ withdrawalRequests.push({ rewardAddress, withdrawal });
1161
+ }
1162
+ const certRequests = [];
1163
+ for (let index = 0; index < (body.certs()?.len() || 0); index++) {
1164
+ const cert = body.certs().get(index);
1165
+ switch (cert.kind()) {
1166
+ case 0: {
1167
+ const registration = cert.as_stake_registration();
1168
+ const rewardAddress = CML.RewardAddress.new(
1169
+ CML.NetworkInfo.testnet().network_id(),
1170
+ registration.stake_credential()
1171
+ ).to_address().to_bech32(void 0);
1172
+ if (this.chain[rewardAddress]?.registeredStake) {
1173
+ throw new Error(
1174
+ `Stake key is already registered. Reward address: ${rewardAddress}`
1175
+ );
1176
+ }
1177
+ certRequests.push({ type: "Registration", rewardAddress });
1178
+ break;
1179
+ }
1180
+ case 1: {
1181
+ const deregistration = cert.as_stake_deregistration();
1182
+ const rewardAddress = CML.RewardAddress.new(
1183
+ CML.NetworkInfo.testnet().network_id(),
1184
+ deregistration.stake_credential()
1185
+ ).to_address().to_bech32(void 0);
1186
+ const { stakeCredential } = getAddressDetails(rewardAddress);
1187
+ checkAndConsumeHash(stakeCredential, "Cert", index);
1188
+ if (!this.chain[rewardAddress]?.registeredStake) {
1189
+ throw new Error(
1190
+ `Stake key is already deregistered. Reward address: ${rewardAddress}`
1191
+ );
1192
+ }
1193
+ certRequests.push({ type: "Deregistration", rewardAddress });
1194
+ break;
1195
+ }
1196
+ case 2: {
1197
+ const delegation = cert.as_stake_delegation();
1198
+ const rewardAddress = CML.RewardAddress.new(
1199
+ CML.NetworkInfo.testnet().network_id(),
1200
+ delegation.stake_credential()
1201
+ ).to_address().to_bech32(void 0);
1202
+ const poolId = delegation.pool().to_bech32("pool");
1203
+ const { stakeCredential } = getAddressDetails(rewardAddress);
1204
+ checkAndConsumeHash(stakeCredential, "Cert", index);
1205
+ if (!this.chain[rewardAddress]?.registeredStake && !certRequests.find(
1206
+ (request) => request.type === "Registration" && request.rewardAddress === rewardAddress
1207
+ )) {
1208
+ throw new Error(
1209
+ `Stake key is not registered. Reward address: ${rewardAddress}`
1210
+ );
1211
+ }
1212
+ certRequests.push({ type: "Delegation", rewardAddress, poolId });
1213
+ break;
1214
+ }
1215
+ }
1216
+ }
1217
+ resolvedInputs.forEach(({ entry: { utxo } }, index) => {
1218
+ const { paymentCredential } = getAddressDetails(utxo.address);
1219
+ checkAndConsumeHash(paymentCredential, "Spend", index);
1220
+ });
1221
+ const outputs = (() => {
1222
+ const collected = [];
1223
+ for (let i = 0; i < body.outputs().len(); i++) {
1224
+ const output = body.outputs().get(i);
1225
+ const unspentOutput = CML.TransactionUnspentOutput.new(
1226
+ CML.TransactionInput.new(
1227
+ CML.TransactionHash.from_hex(txHash),
1228
+ CML.BigInteger.from_str(i.toString()).to_js_value()
1229
+ ),
1230
+ output
1231
+ );
1232
+ const utxo = coreToUtxo(unspentOutput);
1233
+ if (utxo.datumHash) consumedHashes.add(utxo.datumHash);
1234
+ collected.push({
1235
+ utxo,
1236
+ spent: false
1237
+ });
1238
+ }
1239
+ return collected;
1240
+ })();
1241
+ const [extraKeyHash] = keyHashes.filter(
1242
+ (keyHash) => !consumedHashes.has(keyHash)
1243
+ );
1244
+ if (extraKeyHash) {
1245
+ throw new Error(`Extraneous vkey witness. Key hash: ${extraKeyHash}`);
1246
+ }
1247
+ const [extraNativeHash] = nativeHashes.filter(
1248
+ (scriptHash) => !consumedHashes.has(scriptHash)
1249
+ );
1250
+ if (extraNativeHash) {
1251
+ throw new Error(
1252
+ `Extraneous native script. Script hash: ${extraNativeHash}`
1253
+ );
1254
+ }
1255
+ const [extraPlutusHash] = plutusHashes.filter(
1256
+ (scriptHash) => !consumedHashes.has(scriptHash)
1257
+ );
1258
+ if (extraPlutusHash) {
1259
+ throw new Error(
1260
+ `Extraneous plutus script. Script hash: ${extraPlutusHash}`
1261
+ );
1262
+ }
1263
+ const [extraDatumHash] = Object.keys(datumTable).filter(
1264
+ (datumHash) => !consumedHashes.has(datumHash)
1265
+ );
1266
+ if (extraDatumHash) {
1267
+ throw new Error(`Extraneous plutus data. Datum hash: ${extraDatumHash}`);
1268
+ }
1269
+ resolvedInputs.forEach(({ entry, type }) => {
1270
+ const outRef = entry.utxo.txHash + entry.utxo.outputIndex;
1271
+ entry.spent = true;
1272
+ if (type === "Ledger") this.ledger[outRef] = entry;
1273
+ else if (type === "Mempool") this.mempool[outRef] = entry;
1274
+ });
1275
+ withdrawalRequests.forEach(({ rewardAddress, withdrawal }) => {
1276
+ this.chain[rewardAddress].delegation.rewards -= withdrawal;
1277
+ });
1278
+ certRequests.forEach(({ type, rewardAddress, poolId }) => {
1279
+ switch (type) {
1280
+ case "Registration": {
1281
+ if (this.chain[rewardAddress]) {
1282
+ this.chain[rewardAddress].registeredStake = true;
1283
+ } else {
1284
+ this.chain[rewardAddress] = {
1285
+ registeredStake: true,
1286
+ delegation: { poolId: null, rewards: 0n }
1287
+ };
1288
+ }
1289
+ break;
1290
+ }
1291
+ case "Deregistration": {
1292
+ this.chain[rewardAddress].registeredStake = false;
1293
+ this.chain[rewardAddress].delegation.poolId = null;
1294
+ break;
1295
+ }
1296
+ case "Delegation": {
1297
+ this.chain[rewardAddress].delegation.poolId = poolId;
1298
+ }
1299
+ }
1300
+ });
1301
+ outputs.forEach(({ utxo, spent }) => {
1302
+ this.mempool[utxo.txHash + utxo.outputIndex] = {
1303
+ utxo,
1304
+ spent
1305
+ };
1306
+ });
1307
+ for (const [datumHash, datum] of Object.entries(datumTable)) {
1308
+ this.datumTable[datumHash] = datum;
1309
+ }
1310
+ return Promise.resolve(txHash);
1311
+ }
1312
+ log() {
1313
+ function getRandomColor(unit) {
1314
+ const seed = unit === "lovelace" ? "1" : unit;
1315
+ let num = 0;
1316
+ for (let i = 0; i < seed.length; i++) {
1317
+ num += seed.charCodeAt(i);
1318
+ }
1319
+ const r = num * 123 % 256;
1320
+ const g = num * 321 % 256;
1321
+ const b = num * 213 % 256;
1322
+ return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
1323
+ }
1324
+ const totalBalances = {};
1325
+ const balances = {};
1326
+ for (const { utxo } of Object.values(this.ledger)) {
1327
+ for (const [unit, quantity] of Object.entries(utxo.assets)) {
1328
+ if (!balances[utxo.address]) {
1329
+ balances[utxo.address] = { [unit]: quantity };
1330
+ } else if (!balances[utxo.address]?.[unit]) {
1331
+ balances[utxo.address][unit] = quantity;
1332
+ } else {
1333
+ balances[utxo.address][unit] += quantity;
1334
+ }
1335
+ if (!totalBalances[unit]) {
1336
+ totalBalances[unit] = quantity;
1337
+ } else {
1338
+ totalBalances[unit] += quantity;
1339
+ }
1340
+ }
1341
+ }
1342
+ console.log("\n%cBlockchain state", "color:purple");
1343
+ console.log(
1344
+ `
1345
+ Block height: %c${this.blockHeight}%c
1346
+ Slot: %c${this.slot}%c
1347
+ Unix time: %c${this.time}
1348
+ `,
1349
+ "color:yellow",
1350
+ "color:white",
1351
+ "color:yellow",
1352
+ "color:white",
1353
+ "color:yellow"
1354
+ );
1355
+ console.log("\n");
1356
+ for (const [address, assets] of Object.entries(balances)) {
1357
+ console.log(`Address: %c${address}`, "color:blue", "\n");
1358
+ for (const [unit, quantity] of Object.entries(assets)) {
1359
+ const barLength = Math.max(
1360
+ Math.floor(60 * (Number(quantity) / Number(totalBalances[unit]))),
1361
+ 1
1362
+ );
1363
+ console.log(
1364
+ `%c${"\u2586".repeat(barLength) + " ".repeat(60 - barLength)}`,
1365
+ `color: ${getRandomColor(unit)}`,
1366
+ "",
1367
+ `${unit}:`,
1368
+ quantity,
1369
+ ""
1370
+ );
1371
+ }
1372
+ console.log(`
1373
+ ${"\u2581".repeat(60)}
1374
+ `);
1375
+ }
1376
+ }
1377
+ };
1378
+
716
1379
  // src/maestro.ts
717
1380
  import { applyDoubleCborEncoding as applyDoubleCborEncoding2 } from "@lucid-evolution/utils";
718
- import { fromHex as fromHex2 } from "@lucid-evolution/core-utils";
1381
+ import { fromHex as fromHex3 } from "@lucid-evolution/core-utils";
719
1382
  var Maestro = class {
720
1383
  url;
721
1384
  apiKey;
@@ -914,7 +1577,7 @@ var Maestro = class {
914
1577
  Accept: "text/plain",
915
1578
  ...this.commonHeaders()
916
1579
  },
917
- body: fromHex2(tx)
1580
+ body: fromHex3(tx)
918
1581
  });
919
1582
  const result = await response.text();
920
1583
  if (!response.ok) {
@@ -978,7 +1641,7 @@ var lucid2 = package_default.version;
978
1641
 
979
1642
  // src/koios/koios.ts
980
1643
  import * as S4 from "@effect/schema/Schema";
981
- import { fromHex as fromHex3 } from "@lucid-evolution/core-utils";
1644
+ import { fromHex as fromHex4 } from "@lucid-evolution/core-utils";
982
1645
  import { applyDoubleCborEncoding as applyDoubleCborEncoding3, fromUnit as fromUnit2 } from "@lucid-evolution/utils";
983
1646
 
984
1647
  // src/koios/schema.ts
@@ -1429,7 +2092,7 @@ var Koios = class {
1429
2092
  "Content-Type": "application/cbor"
1430
2093
  },
1431
2094
  method: "POST",
1432
- body: fromHex3(tx)
2095
+ body: fromHex4(tx)
1433
2096
  }).then((res) => res.json());
1434
2097
  const TxHashSchema = S4.String;
1435
2098
  const isTxHash = S4.is(TxHashSchema);
@@ -1465,10 +2128,12 @@ var toUTxO = (koiosUTxO, address) => ({
1465
2128
  });
1466
2129
  export {
1467
2130
  Blockfrost,
2131
+ Emulator,
1468
2132
  fetch_exports as FetchProvider,
1469
2133
  Koios,
1470
2134
  Kupmios,
1471
2135
  KupmiosError,
1472
2136
  Maestro,
1473
- datumJsonToCbor
2137
+ datumJsonToCbor,
2138
+ generateEmulatorAccount
1474
2139
  };