rocketh 0.9.2 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -115,9 +115,9 @@ function stringToJSON(str) {
115
115
  // src/environment/deployments.ts
116
116
  var import_node_path2 = __toESM(require("path"), 1);
117
117
  var import_node_fs2 = __toESM(require("fs"), 1);
118
- function loadDeployments(deploymentsPath, subPath, onlyABIAndAddress, expectedChain) {
118
+ function loadDeployments(deploymentsPath, networkName, onlyABIAndAddress, expectedChain) {
119
119
  const deploymentsFound = {};
120
- const deployPath = import_node_path2.default.join(deploymentsPath, subPath);
120
+ const deployPath = import_node_path2.default.join(deploymentsPath, networkName);
121
121
  let filesStats;
122
122
  try {
123
123
  filesStats = traverse(deployPath, void 0, void 0, (name) => !name.startsWith(".") && name !== "solcInputs");
@@ -139,7 +139,7 @@ function loadDeployments(deploymentsPath, subPath, onlyABIAndAddress, expectedCh
139
139
  genesisHash = chainData.genesisHash;
140
140
  } else {
141
141
  throw new Error(
142
- `A '.chain' or '.chainId' file is expected to be present in the deployment folder for network ${subPath}`
142
+ `A '.chain' or '.chainId' file is expected to be present in the deployment folder for network ${networkName}`
143
143
  );
144
144
  }
145
145
  }
@@ -430,7 +430,7 @@ function displayTransaction(transaction) {
430
430
  }
431
431
  }
432
432
  async function createEnvironment(config, providedContext) {
433
- const provider = "provider" in config ? config.provider : new import_eip_1193_jsonrpc_provider.JSONRPCHTTPProvider(config.nodeUrl);
433
+ const provider = "provider" in config.network ? config.network.provider : new import_eip_1193_jsonrpc_provider.JSONRPCHTTPProvider(config.network.nodeUrl);
434
434
  const transport = (0, import_viem.custom)(provider);
435
435
  const viemClient = (0, import_viem.createPublicClient)({ transport });
436
436
  const chainId = (await viemClient.getChainId()).toString();
@@ -442,23 +442,29 @@ async function createEnvironment(config, providedContext) {
442
442
  }
443
443
  let networkName;
444
444
  let saveDeployments;
445
- let tags = {};
445
+ let networkTags = {};
446
+ for (const networkTag of config.network.tags) {
447
+ networkTags[networkTag] = true;
448
+ }
446
449
  if ("nodeUrl" in config) {
447
- networkName = config.networkName;
450
+ networkName = config.network.name;
448
451
  saveDeployments = true;
449
452
  } else {
450
- if (config.networkName) {
451
- networkName = config.networkName;
453
+ if (config.network.name) {
454
+ networkName = config.network.name;
452
455
  } else {
453
456
  networkName = "memory";
454
457
  }
455
458
  if (networkName === "memory" || networkName === "hardhat") {
456
- tags["memory"] = true;
459
+ networkTags["memory"] = true;
457
460
  saveDeployments = false;
458
461
  } else {
459
462
  saveDeployments = true;
460
463
  }
461
464
  }
465
+ if (config.saveDeployments !== void 0) {
466
+ saveDeployments = config.saveDeployments;
467
+ }
462
468
  const resolvedAccounts = {};
463
469
  const accountCache = {};
464
470
  async function getAccount(name, accounts, accountDef) {
@@ -538,15 +544,21 @@ async function createEnvironment(config, providedContext) {
538
544
  artifacts: providedContext.artifacts,
539
545
  network: {
540
546
  name: networkName,
547
+ fork: config.network.fork,
541
548
  saveDeployments,
542
- tags
549
+ tags: networkTags
543
550
  }
544
551
  };
545
- const { deployments } = loadDeployments(config.deployments, context.network.name, false, {
546
- chainId,
547
- genesisHash,
548
- deleteDeploymentsIfDifferentGenesisHash: true
549
- });
552
+ const { deployments } = loadDeployments(
553
+ config.deployments,
554
+ context.network.name,
555
+ false,
556
+ context.network.fork ? void 0 : {
557
+ chainId,
558
+ genesisHash,
559
+ deleteDeploymentsIfDifferentGenesisHash: true
560
+ }
561
+ );
550
562
  const namedAccounts = {};
551
563
  const namedSigners = {};
552
564
  const addressSigners = {};
@@ -898,7 +910,72 @@ async function createEnvironment(config, providedContext) {
898
910
  };
899
911
  }
900
912
 
913
+ // src/utils/eth.ts
914
+ function avg(arr) {
915
+ const sum = arr.reduce((a, v) => a + v);
916
+ return sum / BigInt(arr.length);
917
+ }
918
+ async function getGasPriceEstimate(provider, options) {
919
+ const defaultOptions = {
920
+ blockCount: 20,
921
+ newestBlock: "pending",
922
+ rewardPercentiles: [10, 50, 80]
923
+ };
924
+ const optionsResolved = options ? { ...defaultOptions, ...options } : defaultOptions;
925
+ const historicalBlocks = optionsResolved.blockCount;
926
+ const rawFeeHistory = await provider.request({
927
+ method: "eth_feeHistory",
928
+ params: [`0x${historicalBlocks.toString(16)}`, optionsResolved.newestBlock, optionsResolved.rewardPercentiles]
929
+ });
930
+ let blockNum = Number(rawFeeHistory.oldestBlock);
931
+ const lastBlock = blockNum + rawFeeHistory.reward.length;
932
+ let index = 0;
933
+ const blocksHistory = [];
934
+ while (blockNum < lastBlock) {
935
+ blocksHistory.push({
936
+ number: blockNum,
937
+ baseFeePerGas: BigInt(rawFeeHistory.baseFeePerGas[index]),
938
+ gasUsedRatio: Number(rawFeeHistory.gasUsedRatio[index]),
939
+ priorityFeePerGas: rawFeeHistory.reward[index].map((x) => BigInt(x))
940
+ });
941
+ blockNum += 1;
942
+ index += 1;
943
+ }
944
+ const percentilePriorityFeeAverages = [];
945
+ for (let i = 0; i < optionsResolved.rewardPercentiles.length; i++) {
946
+ percentilePriorityFeeAverages.push(avg(blocksHistory.map((b) => b.priorityFeePerGas[i])));
947
+ }
948
+ const baseFeePerGas = BigInt(rawFeeHistory.baseFeePerGas[rawFeeHistory.baseFeePerGas.length - 1]);
949
+ const result = [];
950
+ for (let i = 0; i < optionsResolved.rewardPercentiles.length; i++) {
951
+ result.push({
952
+ maxFeePerGas: percentilePriorityFeeAverages[i] + baseFeePerGas,
953
+ maxPriorityFeePerGas: percentilePriorityFeeAverages[i]
954
+ });
955
+ }
956
+ return result;
957
+ }
958
+ async function getRoughGasPriceEstimate(provider, options) {
959
+ const defaultOptions = {
960
+ blockCount: 20,
961
+ newestBlock: "pending",
962
+ rewardPercentiles: [10, 50, 80]
963
+ };
964
+ const optionsResolved = options ? { ...defaultOptions, ...options } : defaultOptions;
965
+ if (optionsResolved.rewardPercentiles.length !== 3) {
966
+ throw new Error(`rough gas estimate require 3 percentile, it defaults to [10,50,80]`);
967
+ }
968
+ const result = await getGasPriceEstimate(provider, optionsResolved);
969
+ return {
970
+ slow: result[0],
971
+ average: result[1],
972
+ fast: result[2]
973
+ };
974
+ }
975
+
901
976
  // src/executor/index.ts
977
+ var import_prompts = __toESM(require("prompts"), 1);
978
+ var import_viem2 = require("viem");
902
979
  if (!process.env["ROCKETH_SKIP_ESBUILD"]) {
903
980
  require("esbuild-register/dist/node").register();
904
981
  }
@@ -909,24 +986,55 @@ function execute(context, callback, options) {
909
986
  scriptModule.dependencies = options.dependencies;
910
987
  return scriptModule;
911
988
  }
912
- function readConfig(options, extra) {
989
+ function readConfig(options) {
913
990
  let configFile;
914
991
  try {
915
992
  const configString = import_node_fs4.default.readFileSync("./rocketh.json", "utf-8");
916
993
  configFile = JSON.parse(configString);
917
994
  } catch {
918
995
  }
919
- let nodeUrl;
996
+ if (configFile) {
997
+ if (!options.deployments && configFile.deployments) {
998
+ options.deployments = configFile.deployments;
999
+ }
1000
+ if (!options.scripts && configFile.scripts) {
1001
+ options.scripts = configFile.scripts;
1002
+ }
1003
+ }
920
1004
  const fromEnv = process.env["ETH_NODE_URI_" + options.network];
921
- if (typeof fromEnv === "string") {
922
- nodeUrl = fromEnv;
923
- } else {
924
- if (configFile) {
925
- const network = configFile.networks && configFile.networks[options.network];
926
- if (network) {
927
- nodeUrl = network.rpcUrl;
1005
+ const fork = typeof options.network !== "string";
1006
+ let networkName = "memory";
1007
+ if (options.network) {
1008
+ if (typeof options.network === "string") {
1009
+ networkName = options.network;
1010
+ } else if ("fork" in options.network) {
1011
+ networkName = options.network.fork;
1012
+ }
1013
+ }
1014
+ let networkTags = configFile?.networks && configFile?.networks[networkName]?.tags || [];
1015
+ if (!options.provider) {
1016
+ let nodeUrl;
1017
+ if (typeof fromEnv === "string") {
1018
+ nodeUrl = fromEnv;
1019
+ } else {
1020
+ if (configFile) {
1021
+ const network = configFile.networks && configFile.networks[networkName];
1022
+ if (network && network.rpcUrl) {
1023
+ nodeUrl = network.rpcUrl;
1024
+ } else {
1025
+ if (options?.ignoreMissingRPC) {
1026
+ nodeUrl = "";
1027
+ } else {
1028
+ if (options.network === "localhost") {
1029
+ nodeUrl = "http://127.0.0.1:8545";
1030
+ } else {
1031
+ logger.error(`network "${options.network}" is not configured. Please add it to the rocketh.json file`);
1032
+ process.exit(1);
1033
+ }
1034
+ }
1035
+ }
928
1036
  } else {
929
- if (extra?.ignoreMissingRPC) {
1037
+ if (options?.ignoreMissingRPC) {
930
1038
  nodeUrl = "";
931
1039
  } else {
932
1040
  if (options.network === "localhost") {
@@ -937,47 +1045,61 @@ function readConfig(options, extra) {
937
1045
  }
938
1046
  }
939
1047
  }
940
- } else {
941
- if (extra?.ignoreMissingRPC) {
942
- nodeUrl = "";
943
- } else {
944
- if (options.network === "localhost") {
945
- nodeUrl = "http://127.0.0.1:8545";
946
- } else {
947
- logger.error(`network "${options.network}" is not configured. Please add it to the rocketh.json file`);
948
- process.exit(1);
949
- }
950
- }
951
1048
  }
1049
+ return {
1050
+ network: {
1051
+ nodeUrl,
1052
+ name: networkName,
1053
+ tags: networkTags,
1054
+ fork
1055
+ },
1056
+ deployments: options.deployments,
1057
+ saveDeployments: options.saveDeployments,
1058
+ scripts: options.scripts,
1059
+ tags: typeof options.tags === "undefined" ? void 0 : options.tags.split(","),
1060
+ logLevel: options.logLevel,
1061
+ askBeforeProceeding: options.askBeforeProceeding
1062
+ };
1063
+ } else {
1064
+ return {
1065
+ network: {
1066
+ provider: options.provider,
1067
+ name: networkName,
1068
+ tags: networkTags,
1069
+ fork
1070
+ },
1071
+ deployments: options.deployments,
1072
+ saveDeployments: options.saveDeployments,
1073
+ scripts: options.scripts,
1074
+ tags: typeof options.tags === "undefined" ? void 0 : options.tags.split(","),
1075
+ logLevel: options.logLevel,
1076
+ askBeforeProceeding: options.askBeforeProceeding
1077
+ };
952
1078
  }
953
- return {
954
- nodeUrl,
955
- networkName: options.network,
956
- deployments: options.deployments,
957
- scripts: options.scripts,
958
- tags: typeof options.tags === "undefined" ? void 0 : options.tags.split(",")
959
- };
960
1079
  }
961
- function readAndResolveConfig(options, extra) {
962
- return resolveConfig(readConfig(options, extra));
1080
+ function readAndResolveConfig(options) {
1081
+ return resolveConfig(readConfig(options));
963
1082
  }
964
1083
  function resolveConfig(config) {
965
1084
  const resolvedConfig = {
966
1085
  ...config,
967
- networkName: config.networkName || "memory",
1086
+ network: config.network,
1087
+ // TODO default to || {name: 'memory'....}
968
1088
  deployments: config.deployments || "deployments",
969
1089
  scripts: config.scripts || "deploy",
970
- tags: config.tags || []
1090
+ tags: config.tags || [],
1091
+ networkTags: config.networkTags || [],
1092
+ saveDeployments: config.saveDeployments
971
1093
  };
972
1094
  return resolvedConfig;
973
1095
  }
974
- async function loadEnvironment(config, context) {
975
- const resolvedConfig = resolveConfig(config);
1096
+ async function loadEnvironment(options, context) {
1097
+ const resolvedConfig = readAndResolveConfig(options);
976
1098
  const { external, internal } = await createEnvironment(resolvedConfig, context);
977
1099
  return external;
978
1100
  }
979
- async function loadAndExecuteDeployments(config, args) {
980
- const resolvedConfig = resolveConfig(config);
1101
+ async function loadAndExecuteDeployments(options, args) {
1102
+ const resolvedConfig = readAndResolveConfig(options);
981
1103
  return executeDeployScripts(resolvedConfig, args);
982
1104
  }
983
1105
  async function executeDeployScripts(config, args) {
@@ -1096,6 +1218,28 @@ async function executeDeployScripts(config, args) {
1096
1218
  for (const scriptFilePath of scriptFilePaths) {
1097
1219
  recurseDependencies(scriptFilePath);
1098
1220
  }
1221
+ if (config.askBeforeProceeding) {
1222
+ const gasPriceEstimate = await getRoughGasPriceEstimate(external.network.provider);
1223
+ const prompt = await (0, import_prompts.default)({
1224
+ type: "confirm",
1225
+ name: "proceed",
1226
+ message: `gas price is currently in this range:
1227
+ slow: ${(0, import_viem2.formatEther)(gasPriceEstimate.slow.maxFeePerGas)} (priority: ${(0, import_viem2.formatEther)(
1228
+ gasPriceEstimate.slow.maxPriorityFeePerGas
1229
+ )})
1230
+ average: ${(0, import_viem2.formatEther)(gasPriceEstimate.average.maxFeePerGas)} (priority: ${(0, import_viem2.formatEther)(
1231
+ gasPriceEstimate.average.maxPriorityFeePerGas
1232
+ )})
1233
+ fast: ${(0, import_viem2.formatEther)(gasPriceEstimate.fast.maxFeePerGas)} (priority: ${(0, import_viem2.formatEther)(
1234
+ gasPriceEstimate.fast.maxPriorityFeePerGas
1235
+ )})
1236
+
1237
+ Do you want to proceed (note that gas price can change for each tx)`
1238
+ });
1239
+ if (!prompt.proceed) {
1240
+ process.exit();
1241
+ }
1242
+ }
1099
1243
  for (const deployScript of scriptsToRun.concat(scriptsToRunAtTheEnd)) {
1100
1244
  const filename = import_node_path4.default.basename(deployScript.filePath);
1101
1245
  const relativeFilepath = import_node_path4.default.relative(".", deployScript.filePath);