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