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/cli.cjs CHANGED
@@ -95,9 +95,9 @@ function stringToJSON(str) {
95
95
  // src/environment/deployments.ts
96
96
  var import_node_path2 = __toESM(require("path"), 1);
97
97
  var import_node_fs2 = __toESM(require("fs"), 1);
98
- function loadDeployments(deploymentsPath, subPath, onlyABIAndAddress, expectedChain) {
98
+ function loadDeployments(deploymentsPath, networkName, onlyABIAndAddress, expectedChain) {
99
99
  const deploymentsFound = {};
100
- const deployPath = import_node_path2.default.join(deploymentsPath, subPath);
100
+ const deployPath = import_node_path2.default.join(deploymentsPath, networkName);
101
101
  let filesStats;
102
102
  try {
103
103
  filesStats = traverse(deployPath, void 0, void 0, (name) => !name.startsWith(".") && name !== "solcInputs");
@@ -119,7 +119,7 @@ function loadDeployments(deploymentsPath, subPath, onlyABIAndAddress, expectedCh
119
119
  genesisHash = chainData.genesisHash;
120
120
  } else {
121
121
  throw new Error(
122
- `A '.chain' or '.chainId' file is expected to be present in the deployment folder for network ${subPath}`
122
+ `A '.chain' or '.chainId' file is expected to be present in the deployment folder for network ${networkName}`
123
123
  );
124
124
  }
125
125
  }
@@ -401,8 +401,8 @@ function displayTransaction(transaction) {
401
401
  return `(gasPrice: ${BigInt(transaction.gasPrice).toString()})`;
402
402
  }
403
403
  }
404
- async function createEnvironment(config2, providedContext) {
405
- const provider = "provider" in config2 ? config2.provider : new import_eip_1193_jsonrpc_provider.JSONRPCHTTPProvider(config2.nodeUrl);
404
+ async function createEnvironment(config, providedContext) {
405
+ const provider = "provider" in config.network ? config.network.provider : new import_eip_1193_jsonrpc_provider.JSONRPCHTTPProvider(config.network.nodeUrl);
406
406
  const transport = (0, import_viem.custom)(provider);
407
407
  const viemClient = (0, import_viem.createPublicClient)({ transport });
408
408
  const chainId = (await viemClient.getChainId()).toString();
@@ -414,23 +414,29 @@ async function createEnvironment(config2, providedContext) {
414
414
  }
415
415
  let networkName;
416
416
  let saveDeployments;
417
- let tags = {};
418
- if ("nodeUrl" in config2) {
419
- networkName = config2.networkName;
417
+ let networkTags = {};
418
+ for (const networkTag of config.network.tags) {
419
+ networkTags[networkTag] = true;
420
+ }
421
+ if ("nodeUrl" in config) {
422
+ networkName = config.network.name;
420
423
  saveDeployments = true;
421
424
  } else {
422
- if (config2.networkName) {
423
- networkName = config2.networkName;
425
+ if (config.network.name) {
426
+ networkName = config.network.name;
424
427
  } else {
425
428
  networkName = "memory";
426
429
  }
427
430
  if (networkName === "memory" || networkName === "hardhat") {
428
- tags["memory"] = true;
431
+ networkTags["memory"] = true;
429
432
  saveDeployments = false;
430
433
  } else {
431
434
  saveDeployments = true;
432
435
  }
433
436
  }
437
+ if (config.saveDeployments !== void 0) {
438
+ saveDeployments = config.saveDeployments;
439
+ }
434
440
  const resolvedAccounts = {};
435
441
  const accountCache = {};
436
442
  async function getAccount(name, accounts, accountDef) {
@@ -510,15 +516,21 @@ async function createEnvironment(config2, providedContext) {
510
516
  artifacts: providedContext.artifacts,
511
517
  network: {
512
518
  name: networkName,
519
+ fork: config.network.fork,
513
520
  saveDeployments,
514
- tags
521
+ tags: networkTags
515
522
  }
516
523
  };
517
- const { deployments } = loadDeployments(config2.deployments, context.network.name, false, {
518
- chainId,
519
- genesisHash,
520
- deleteDeploymentsIfDifferentGenesisHash: true
521
- });
524
+ const { deployments } = loadDeployments(
525
+ config.deployments,
526
+ context.network.name,
527
+ false,
528
+ context.network.fork ? void 0 : {
529
+ chainId,
530
+ genesisHash,
531
+ deleteDeploymentsIfDifferentGenesisHash: true
532
+ }
533
+ );
522
534
  const namedAccounts = {};
523
535
  const namedSigners = {};
524
536
  const addressSigners = {};
@@ -530,7 +542,7 @@ async function createEnvironment(config2, providedContext) {
530
542
  namedSigners[name] = namedSigner;
531
543
  }
532
544
  const perliminaryEnvironment = {
533
- config: config2,
545
+ config,
534
546
  deployments,
535
547
  accounts: namedAccounts,
536
548
  signers: namedSigners,
@@ -544,7 +556,7 @@ async function createEnvironment(config2, providedContext) {
544
556
  }
545
557
  };
546
558
  function ensureDeploymentFolder() {
547
- const folderPath = import_node_path3.default.join(config2.deployments, context.network.name);
559
+ const folderPath = import_node_path3.default.join(config.deployments, context.network.name);
548
560
  import_node_fs3.default.mkdirSync(folderPath, { recursive: true });
549
561
  const chainFilepath = import_node_path3.default.join(folderPath, ".chain");
550
562
  if (!import_node_fs3.default.existsSync(chainFilepath)) {
@@ -870,28 +882,124 @@ async function createEnvironment(config2, providedContext) {
870
882
  };
871
883
  }
872
884
 
885
+ // src/utils/eth.ts
886
+ function avg(arr) {
887
+ const sum = arr.reduce((a, v) => a + v);
888
+ return sum / BigInt(arr.length);
889
+ }
890
+ async function getGasPriceEstimate(provider, options2) {
891
+ const defaultOptions = {
892
+ blockCount: 20,
893
+ newestBlock: "pending",
894
+ rewardPercentiles: [10, 50, 80]
895
+ };
896
+ const optionsResolved = options2 ? { ...defaultOptions, ...options2 } : defaultOptions;
897
+ const historicalBlocks = optionsResolved.blockCount;
898
+ const rawFeeHistory = await provider.request({
899
+ method: "eth_feeHistory",
900
+ params: [`0x${historicalBlocks.toString(16)}`, optionsResolved.newestBlock, optionsResolved.rewardPercentiles]
901
+ });
902
+ let blockNum = Number(rawFeeHistory.oldestBlock);
903
+ const lastBlock = blockNum + rawFeeHistory.reward.length;
904
+ let index = 0;
905
+ const blocksHistory = [];
906
+ while (blockNum < lastBlock) {
907
+ blocksHistory.push({
908
+ number: blockNum,
909
+ baseFeePerGas: BigInt(rawFeeHistory.baseFeePerGas[index]),
910
+ gasUsedRatio: Number(rawFeeHistory.gasUsedRatio[index]),
911
+ priorityFeePerGas: rawFeeHistory.reward[index].map((x) => BigInt(x))
912
+ });
913
+ blockNum += 1;
914
+ index += 1;
915
+ }
916
+ const percentilePriorityFeeAverages = [];
917
+ for (let i = 0; i < optionsResolved.rewardPercentiles.length; i++) {
918
+ percentilePriorityFeeAverages.push(avg(blocksHistory.map((b) => b.priorityFeePerGas[i])));
919
+ }
920
+ const baseFeePerGas = BigInt(rawFeeHistory.baseFeePerGas[rawFeeHistory.baseFeePerGas.length - 1]);
921
+ const result = [];
922
+ for (let i = 0; i < optionsResolved.rewardPercentiles.length; i++) {
923
+ result.push({
924
+ maxFeePerGas: percentilePriorityFeeAverages[i] + baseFeePerGas,
925
+ maxPriorityFeePerGas: percentilePriorityFeeAverages[i]
926
+ });
927
+ }
928
+ return result;
929
+ }
930
+ async function getRoughGasPriceEstimate(provider, options2) {
931
+ const defaultOptions = {
932
+ blockCount: 20,
933
+ newestBlock: "pending",
934
+ rewardPercentiles: [10, 50, 80]
935
+ };
936
+ const optionsResolved = options2 ? { ...defaultOptions, ...options2 } : defaultOptions;
937
+ if (optionsResolved.rewardPercentiles.length !== 3) {
938
+ throw new Error(`rough gas estimate require 3 percentile, it defaults to [10,50,80]`);
939
+ }
940
+ const result = await getGasPriceEstimate(provider, optionsResolved);
941
+ return {
942
+ slow: result[0],
943
+ average: result[1],
944
+ fast: result[2]
945
+ };
946
+ }
947
+
873
948
  // src/executor/index.ts
949
+ var import_prompts = __toESM(require("prompts"), 1);
950
+ var import_viem2 = require("viem");
874
951
  if (!process.env["ROCKETH_SKIP_ESBUILD"]) {
875
952
  require("esbuild-register/dist/node").register();
876
953
  }
877
- function readConfig(options2, extra) {
954
+ function readConfig(options2) {
878
955
  let configFile;
879
956
  try {
880
957
  const configString = import_node_fs4.default.readFileSync("./rocketh.json", "utf-8");
881
958
  configFile = JSON.parse(configString);
882
959
  } catch {
883
960
  }
884
- let nodeUrl;
961
+ if (configFile) {
962
+ if (!options2.deployments && configFile.deployments) {
963
+ options2.deployments = configFile.deployments;
964
+ }
965
+ if (!options2.scripts && configFile.scripts) {
966
+ options2.scripts = configFile.scripts;
967
+ }
968
+ }
885
969
  const fromEnv = process.env["ETH_NODE_URI_" + options2.network];
886
- if (typeof fromEnv === "string") {
887
- nodeUrl = fromEnv;
888
- } else {
889
- if (configFile) {
890
- const network = configFile.networks && configFile.networks[options2.network];
891
- if (network) {
892
- nodeUrl = network.rpcUrl;
970
+ const fork = typeof options2.network !== "string";
971
+ let networkName = "memory";
972
+ if (options2.network) {
973
+ if (typeof options2.network === "string") {
974
+ networkName = options2.network;
975
+ } else if ("fork" in options2.network) {
976
+ networkName = options2.network.fork;
977
+ }
978
+ }
979
+ let networkTags = configFile?.networks && configFile?.networks[networkName]?.tags || [];
980
+ if (!options2.provider) {
981
+ let nodeUrl;
982
+ if (typeof fromEnv === "string") {
983
+ nodeUrl = fromEnv;
984
+ } else {
985
+ if (configFile) {
986
+ const network = configFile.networks && configFile.networks[networkName];
987
+ if (network && network.rpcUrl) {
988
+ nodeUrl = network.rpcUrl;
989
+ } else {
990
+ if (options2?.ignoreMissingRPC) {
991
+ nodeUrl = "";
992
+ } else {
993
+ if (options2.network === "localhost") {
994
+ nodeUrl = "http://127.0.0.1:8545";
995
+ } else {
996
+ logger.error(`network "${options2.network}" is not configured. Please add it to the rocketh.json file`);
997
+ process.exit(1);
998
+ }
999
+ }
1000
+ }
893
1001
  } else {
894
- if (extra?.ignoreMissingRPC) {
1002
+ if (options2?.ignoreMissingRPC) {
895
1003
  nodeUrl = "";
896
1004
  } else {
897
1005
  if (options2.network === "localhost") {
@@ -902,45 +1010,62 @@ function readConfig(options2, extra) {
902
1010
  }
903
1011
  }
904
1012
  }
905
- } else {
906
- if (extra?.ignoreMissingRPC) {
907
- nodeUrl = "";
908
- } else {
909
- if (options2.network === "localhost") {
910
- nodeUrl = "http://127.0.0.1:8545";
911
- } else {
912
- logger.error(`network "${options2.network}" is not configured. Please add it to the rocketh.json file`);
913
- process.exit(1);
914
- }
915
- }
916
1013
  }
1014
+ return {
1015
+ network: {
1016
+ nodeUrl,
1017
+ name: networkName,
1018
+ tags: networkTags,
1019
+ fork
1020
+ },
1021
+ deployments: options2.deployments,
1022
+ saveDeployments: options2.saveDeployments,
1023
+ scripts: options2.scripts,
1024
+ tags: typeof options2.tags === "undefined" ? void 0 : options2.tags.split(","),
1025
+ logLevel: options2.logLevel,
1026
+ askBeforeProceeding: options2.askBeforeProceeding
1027
+ };
1028
+ } else {
1029
+ return {
1030
+ network: {
1031
+ provider: options2.provider,
1032
+ name: networkName,
1033
+ tags: networkTags,
1034
+ fork
1035
+ },
1036
+ deployments: options2.deployments,
1037
+ saveDeployments: options2.saveDeployments,
1038
+ scripts: options2.scripts,
1039
+ tags: typeof options2.tags === "undefined" ? void 0 : options2.tags.split(","),
1040
+ logLevel: options2.logLevel,
1041
+ askBeforeProceeding: options2.askBeforeProceeding
1042
+ };
917
1043
  }
918
- return {
919
- nodeUrl,
920
- networkName: options2.network,
921
- deployments: options2.deployments,
922
- scripts: options2.scripts,
923
- tags: typeof options2.tags === "undefined" ? void 0 : options2.tags.split(",")
924
- };
925
1044
  }
926
- function resolveConfig(config2) {
1045
+ function readAndResolveConfig(options2) {
1046
+ return resolveConfig(readConfig(options2));
1047
+ }
1048
+ function resolveConfig(config) {
927
1049
  const resolvedConfig = {
928
- ...config2,
929
- networkName: config2.networkName || "memory",
930
- deployments: config2.deployments || "deployments",
931
- scripts: config2.scripts || "deploy",
932
- tags: config2.tags || []
1050
+ ...config,
1051
+ network: config.network,
1052
+ // TODO default to || {name: 'memory'....}
1053
+ deployments: config.deployments || "deployments",
1054
+ scripts: config.scripts || "deploy",
1055
+ tags: config.tags || [],
1056
+ networkTags: config.networkTags || [],
1057
+ saveDeployments: config.saveDeployments
933
1058
  };
934
1059
  return resolvedConfig;
935
1060
  }
936
- async function loadAndExecuteDeployments(config2, args) {
937
- const resolvedConfig = resolveConfig(config2);
1061
+ async function loadAndExecuteDeployments(options2, args) {
1062
+ const resolvedConfig = readAndResolveConfig(options2);
938
1063
  return executeDeployScripts(resolvedConfig, args);
939
1064
  }
940
- async function executeDeployScripts(config2, args) {
941
- setLogLevel(typeof config2.logLevel === "undefined" ? 0 : config2.logLevel);
1065
+ async function executeDeployScripts(config, args) {
1066
+ setLogLevel(typeof config.logLevel === "undefined" ? 0 : config.logLevel);
942
1067
  let filepaths;
943
- filepaths = traverseMultipleDirectory([config2.scripts]);
1068
+ filepaths = traverseMultipleDirectory([config.scripts]);
944
1069
  filepaths = filepaths.filter((v) => !import_node_path4.default.basename(v).startsWith("_")).sort((a, b) => {
945
1070
  if (a < b) {
946
1071
  return -1;
@@ -992,10 +1117,10 @@ async function executeDeployScripts(config2, args) {
992
1117
  bag.push(scriptFilePath);
993
1118
  }
994
1119
  }
995
- if (config2.tags !== void 0 && config2.tags.length > 0) {
1120
+ if (config.tags !== void 0 && config.tags.length > 0) {
996
1121
  let found = false;
997
1122
  if (scriptTags !== void 0) {
998
- for (const tagToFind of config2.tags) {
1123
+ for (const tagToFind of config.tags) {
999
1124
  for (const tag of scriptTags) {
1000
1125
  if (tag === tagToFind) {
1001
1126
  scriptFilePaths.push(scriptFilePath);
@@ -1015,7 +1140,7 @@ async function executeDeployScripts(config2, args) {
1015
1140
  if (!providedContext) {
1016
1141
  throw new Error(`no context loaded`);
1017
1142
  }
1018
- const { internal, external } = await createEnvironment(config2, providedContext);
1143
+ const { internal, external } = await createEnvironment(config, providedContext);
1019
1144
  await internal.recoverTransactionsIfAny();
1020
1145
  const scriptsRegisteredToRun = {};
1021
1146
  const scriptsToRun = [];
@@ -1053,6 +1178,28 @@ async function executeDeployScripts(config2, args) {
1053
1178
  for (const scriptFilePath of scriptFilePaths) {
1054
1179
  recurseDependencies(scriptFilePath);
1055
1180
  }
1181
+ if (config.askBeforeProceeding) {
1182
+ const gasPriceEstimate = await getRoughGasPriceEstimate(external.network.provider);
1183
+ const prompt = await (0, import_prompts.default)({
1184
+ type: "confirm",
1185
+ name: "proceed",
1186
+ message: `gas price is currently in this range:
1187
+ slow: ${(0, import_viem2.formatEther)(gasPriceEstimate.slow.maxFeePerGas)} (priority: ${(0, import_viem2.formatEther)(
1188
+ gasPriceEstimate.slow.maxPriorityFeePerGas
1189
+ )})
1190
+ average: ${(0, import_viem2.formatEther)(gasPriceEstimate.average.maxFeePerGas)} (priority: ${(0, import_viem2.formatEther)(
1191
+ gasPriceEstimate.average.maxPriorityFeePerGas
1192
+ )})
1193
+ fast: ${(0, import_viem2.formatEther)(gasPriceEstimate.fast.maxFeePerGas)} (priority: ${(0, import_viem2.formatEther)(
1194
+ gasPriceEstimate.fast.maxPriorityFeePerGas
1195
+ )})
1196
+
1197
+ Do you want to proceed (note that gas price can change for each tx)`
1198
+ });
1199
+ if (!prompt.proceed) {
1200
+ process.exit();
1201
+ }
1202
+ }
1056
1203
  for (const deployScript of scriptsToRun.concat(scriptsToRunAtTheEnd)) {
1057
1204
  const filename = import_node_path4.default.basename(deployScript.filePath);
1058
1205
  const relativeFilepath = import_node_path4.default.relative(".", deployScript.filePath);
@@ -1079,7 +1226,7 @@ async function executeDeployScripts(config2, args) {
1079
1226
  throw e;
1080
1227
  }
1081
1228
  if (result && typeof result === "boolean") {
1082
- const deploymentFolderPath = config2.deployments;
1229
+ const deploymentFolderPath = config.deployments;
1083
1230
  }
1084
1231
  }
1085
1232
  }
@@ -1092,7 +1239,7 @@ var import_commander = require("commander");
1092
1239
  // package.json
1093
1240
  var package_default = {
1094
1241
  name: "rocketh",
1095
- version: "0.9.1",
1242
+ version: "0.10.1",
1096
1243
  description: "deploy smart contract on ethereum-compatible networks",
1097
1244
  publishConfig: {
1098
1245
  access: "public"
@@ -1107,8 +1254,9 @@ var package_default = {
1107
1254
  devDependencies: {
1108
1255
  "@types/figlet": "^1.5.8",
1109
1256
  "@types/node": "^20.11.19",
1257
+ "@types/prompts": "^2.4.9",
1110
1258
  abitype: "^1.0.0",
1111
- "eip-1193": "^0.4.7",
1259
+ "eip-1193": "^0.5.0",
1112
1260
  "ipfs-gateway-emulator": "4.2.1-ipfs.2",
1113
1261
  rimraf: "^5.0.5",
1114
1262
  tsup: "^8.0.2",
@@ -1125,6 +1273,7 @@ var package_default = {
1125
1273
  ldenv: "^0.3.9",
1126
1274
  "named-logs": "^0.2.2",
1127
1275
  "named-logs-console": "^0.3.0",
1276
+ prompts: "^2.4.2",
1128
1277
  viem: "^2.7.11"
1129
1278
  },
1130
1279
  scripts: {
@@ -1142,6 +1291,5 @@ var commandName = package_default.name;
1142
1291
  var program = new import_commander.Command();
1143
1292
  program.name(commandName).version(package_default.version).usage(`${commandName}`).description("execute deploy scripts and store the deployments").option("-s, --scripts <value>", "path the folder containing the deploy scripts to execute").option("-t, --tags <value>", "comma separated list of tags to execute").option("-d, --deployments <value>", "folder where deployments are saved").requiredOption("-n, --network <value>", "network context to use").parse(process.argv);
1144
1293
  var options = program.opts();
1145
- var config = readConfig(options);
1146
- loadAndExecuteDeployments({ ...config, logLevel: 1 });
1294
+ loadAndExecuteDeployments({ ...options, logLevel: 1, askBeforeProceeding: true });
1147
1295
  //# sourceMappingURL=cli.cjs.map