@gatedpath/preflight 0.2.1 → 0.2.2

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/README.md CHANGED
@@ -93,7 +93,8 @@ and `reports/gas-151-2026-09-14.md`. On both, 21,000 gas came to 1.000 US cents
93
93
  ## redbelly ship
94
94
 
95
95
  The mainnet gate that produces the document you wanted anyway (PLAN.md 18.3). `redbelly ship --chain
96
- <151|153> --account <keystore-name> [--admin <safe>] [--gas <n>]` (also `npm run ship` in a scaffold
96
+ <151|153> --account <keystore-name> [--admin <safe>] [--gas <n>]` (or `--address <0x…>` in place of
97
+ `--account`, or `DEPLOYER` in `.env`; also `npm run ship` in a scaffold
97
98
  and the MCP server's `ship_report` tool) runs the gas report first (its deployment row is the gas the
98
99
  balance check prices), then pre-flight's seven checks with the keystore's address, checks the verifier
99
100
  (`--verifier` or `VERIFIER` in `.env`; required on 151, where a missing one fails and on 153 warns that
@@ -104,7 +105,16 @@ the deployer and admin readings, the contracts from `deployments/<chain>-*.json`
104
105
  constructor arguments and the exact `forge verify-contract` command, the gas table, the tests, the
105
106
  Slither line, the compiler pins, and the list of what the report does not prove. It refuses to write
106
107
  when any check fails and exits 1 with the failing lines. Run it again after the deploy to fill in the
107
- contract section; the file is dated in UTC.
108
+ contract section; the file is dated in UTC. On 153 the report also says how many faucet claims the
109
+ deployment needs at today's base fee (the deployment rows plus the 25% margin, 500 test RBNT a claim,
110
+ one a day); `redbelly gas` prints the same line.
111
+
112
+ Two things learnt on the first real deploy (17 October 2026). `cast wallet address --account` asks for
113
+ the keystore password on a terminal, so run `redbelly ship` in one, not from an editor's run button;
114
+ without a terminal pass `--password-file`, or `--address` and no cast call is made. And the deploy
115
+ command itself needs `--sender <your address>` beside `--account`: without it forge rehearses as its
116
+ default sender, which fails `isAllowed`, and the scaffold's deploy script now says so and refuses to
117
+ broadcast.
108
118
 
109
119
  The scaffold's `RedbellyDeployScript.sol` refuses to broadcast on 151 without `deployments/ship-151-<today>.md`
110
120
  (a dry run says so and continues; 153 warns), and the Hardhat deploy script does the same. Tested on
@@ -6,6 +6,15 @@ export function checkCompilerPins(config) {
6
6
  const where = `${config.file}${config.profile ? ` (${config.kind === 'foundry' ? 'profile' : 'network'} ${config.profile})` : ''}`;
7
7
  const data = { solc: config.solc, evmVersion: config.evmVersion, file: config.file, profile: config.profile };
8
8
  const problems = [];
9
+ // A project that vendors a suite with its own compiler (ERC-3643's reference contracts pin 0.8.17, which
10
+ // knows neither prague nor cancun) can only build with solc detected per file. The pin then lives in each
11
+ // file's pragma, which this check does not read, so it warns instead of failing (card 15, 17 October 2026).
12
+ if (config.kind === 'foundry' && config.solc === null && config.autoDetectSolc) {
13
+ const evmOk = config.evmVersion !== null && config.evmVersion.toLowerCase() === EVM_PIN;
14
+ return { id: 'compiler-pins', status: evmOk ? 'warn' : 'fail', reason: evmOk
15
+ ? `${where} detects solc per file (auto_detect_solc = true) and sets EVM ${EVM_PIN}. The pin is not in the config: your own files must say pragma solidity ${SOLC_PIN}; a vendored dependency may compile with its own solc for the newest EVM it knows.`
16
+ : `${where} detects solc per file but ${config.evmVersion === null ? 'sets no evm_version' : `sets evm version ${config.evmVersion}, not ${EVM_PIN}`}; Redbelly is Prague.`, data };
17
+ }
9
18
  if (config.solc === null)
10
19
  problems.push(`no ${config.kind === 'foundry' ? 'solc_version' : 'solidity version'} is pinned`);
11
20
  else if (config.solc !== SOLC_PIN)
@@ -16,12 +16,12 @@ export async function resolveDeployer(src) {
16
16
  const args = ['wallet', 'address', '--account', src.account];
17
17
  if (src.passwordFile)
18
18
  args.push('--password-file', src.passwordFile);
19
- const r = await run('cast', args, { cwd: src.cwd, env: src.env, timeoutMs: 60_000, stdin: '' });
19
+ const r = await run('cast', args, { cwd: src.cwd, env: src.env, timeoutMs: 180_000, stdin: '' });
20
20
  if (r.spawnError)
21
21
  return { address: null, how: '--account', error: `cast is not installed or not on PATH (${r.spawnError}); install Foundry or pass --address for a read-only run.` };
22
22
  const m = /0x[0-9a-fA-F]{40}/.exec(r.stdout);
23
23
  if (r.code !== 0 || !m)
24
- return { address: null, how: '--account', error: `cast wallet address --account ${src.account} failed: ${(r.stderr || r.stdout).trim().split('\n').pop() ?? 'no output'}.` };
24
+ return { address: null, how: '--account', error: `cast wallet address --account ${src.account} failed: ${(r.stderr || r.stdout).trim().split('\n').pop() ?? 'no output'}. cast asks for the keystore password on a terminal; without one pass --password-file or --address.` };
25
25
  return { address: m[0], how: `cast wallet address --account ${src.account}` };
26
26
  }
27
27
  return { address: null, how: 'none' };
package/dist/config.d.ts CHANGED
@@ -3,6 +3,8 @@ export interface ProjectConfig {
3
3
  file: string | null;
4
4
  profile: string | null;
5
5
  solc: string | null;
6
+ /** foundry `auto_detect_solc = true`: solc chosen per file from its pragma; the pin cannot be read from the config alone. */
7
+ autoDetectSolc: boolean;
6
8
  evmVersion: string | null;
7
9
  optimizerRuns: number | null;
8
10
  /** foundry: `src`; hardhat: `contracts`. */
package/dist/config.js CHANGED
@@ -16,7 +16,7 @@ export function readProjectConfig(project, profile, env = process.env) {
16
16
  if (existsSync(file))
17
17
  return readHardhatConfig(file, profile ?? null);
18
18
  }
19
- return { kind: 'none', file: null, profile: null, solc: null, evmVersion: null, optimizerRuns: null, sourceDir: 'src', chainId: null, rpcEndpoints: {}, rpcUrl: null };
19
+ return { kind: 'none', file: null, profile: null, solc: null, autoDetectSolc: false, evmVersion: null, optimizerRuns: null, sourceDir: 'src', chainId: null, rpcEndpoints: {}, rpcUrl: null };
20
20
  }
21
21
  /** Enough TOML for foundry.toml: sections, dotted headers, scalars, one-line arrays, comments. */
22
22
  export function parseToml(text) {
@@ -125,6 +125,7 @@ export function readFoundryConfig(file, profile) {
125
125
  file,
126
126
  profile,
127
127
  solc: str('solc') ?? str('solc_version'),
128
+ autoDetectSolc: get('auto_detect_solc') === true,
128
129
  evmVersion: str('evm_version'),
129
130
  optimizerRuns: num('optimizer_runs'),
130
131
  sourceDir: str('src') ?? 'src',
@@ -166,6 +167,7 @@ export function readHardhatConfig(file, network) {
166
167
  file,
167
168
  profile: chosen,
168
169
  solc,
170
+ autoDetectSolc: false,
169
171
  evmVersion: evm ? evm[1] : null,
170
172
  optimizerRuns: runs ? Number(runs[1]) : null,
171
173
  sourceDir: contractsDir ? contractsDir[1].replace(/^\.\//, '') : 'contracts',
package/dist/gas.d.ts CHANGED
@@ -62,7 +62,24 @@ export interface GasReport {
62
62
  readonly added: readonly string[];
63
63
  readonly removed: readonly string[];
64
64
  } | null;
65
+ /** Testnet only: what the deployment rows cost in faucet claims, with pre-flight's 25% margin, at this quote. */
66
+ readonly faucet: FaucetDays | null;
65
67
  }
68
+ export interface FaucetDays {
69
+ /** What one FAUCETME claim pays, in test RBNT, and how often (read 15 September 2026). */
70
+ readonly perClaimRbnt: number;
71
+ readonly claimsPerDay: number;
72
+ /** Deployment gas summed over the rows, plus the 25% pre-flight's balance check adds. */
73
+ readonly gasWithMargin: bigint;
74
+ readonly rbnt: number;
75
+ readonly claims: number;
76
+ readonly days: number;
77
+ readonly pricedAt: string;
78
+ }
79
+ export declare const FAUCET_PER_CLAIM_RBNT = 500;
80
+ export declare const FAUCET_CLAIMS_PER_DAY = 1;
81
+ /** Faucet claims a project needs before its deploy: the deployment rows, 25% on top, at the quote's base fee and price. 153 only. */
82
+ export declare function faucetDays(rows: readonly PricedRow[], quote: GasQuote): FaucetDays | null;
66
83
  export interface GasOptions {
67
84
  /** A Foundry project, or a scaffold root (its contracts/ is used). Default: cwd. */
68
85
  project?: string;
package/dist/gas.js CHANGED
@@ -11,6 +11,21 @@ import { PRICE_FEED_DECIMALS, chainById, formatUnits, getLatestPrice, toCaller }
11
11
  import { run } from './proc.js';
12
12
  const require = createRequire(import.meta.url);
13
13
  export const GAS_VERSION = require('../package.json').version;
14
+ export const FAUCET_PER_CLAIM_RBNT = 500;
15
+ export const FAUCET_CLAIMS_PER_DAY = 1;
16
+ /** Faucet claims a project needs before its deploy: the deployment rows, 25% on top, at the quote's base fee and price. 153 only. */
17
+ export function faucetDays(rows, quote) {
18
+ if (quote.chain !== 153)
19
+ return null;
20
+ const deploys = rows.filter((r) => r.item === 'deployment');
21
+ if (deploys.length === 0)
22
+ return null;
23
+ const gas = deploys.reduce((a, r) => a + r.gas, 0n);
24
+ const gasWithMargin = gas + gas / 4n;
25
+ const rbnt = Number(gasWithMargin * quote.baseFeeWei) / 1e18;
26
+ const claims = Math.max(1, Math.ceil(rbnt / FAUCET_PER_CLAIM_RBNT));
27
+ return { perClaimRbnt: FAUCET_PER_CLAIM_RBNT, claimsPerDay: FAUCET_CLAIMS_PER_DAY, gasWithMargin, rbnt, claims, days: Math.ceil(claims / FAUCET_CLAIMS_PER_DAY), pricedAt: quote.priceTimestamp };
28
+ }
14
29
  // ---- parsing, pure ----
15
30
  const SNAPSHOT_LINE = /^([A-Za-z0-9_$]+):(\S.*?)\s+\((.*)\)\s*$/;
16
31
  /** `.gas-snapshot`: `Contract:test() (gas: N)`, fuzz lines by their mean (μ), invariant lines (no gas) skipped. */
@@ -175,6 +190,7 @@ export async function runGas(opts = {}) {
175
190
  quote,
176
191
  rows: priced.rows,
177
192
  diff: diffFile ? { file: diffFile, rows: before.length, added: priced.added, removed: priced.removed } : null,
193
+ faucet: faucetDays(priced.rows, quote),
178
194
  };
179
195
  }
180
196
  // ---- text ----
@@ -212,6 +228,8 @@ export function renderGasText(report) {
212
228
  lines.push('');
213
229
  if (deploys.length)
214
230
  lines.push(`deployment: ${deploys.map((d) => `${d.contract} ${num(d.gas)} gas = ${rbnt6(d.rbnt)} RBNT = US$${fixed(d.usd, 4)}`).join('; ')}. Pre-flight's balance check adds 25% on top; pass its --gas the figure here.`);
231
+ if (report.faucet)
232
+ lines.push(`faucet: ${num(report.faucet.gasWithMargin)} gas with the 25% margin = ${fixed(report.faucet.rbnt, 1)} test RBNT at this base fee = ${report.faucet.claims} claim${report.faucet.claims === 1 ? '' : 's'} of ${report.faucet.perClaimRbnt} (${report.faucet.days} day${report.faucet.days === 1 ? '' : 's'}, one claim a day) before you can deploy. Priced at ${report.faucet.pricedAt}; the base fee moves, so re-run on the day.`);
215
233
  lines.push(`Gas is priced in US dollars and converted to RBNT at execution from the feed, so the cents column is the stable one; the RBNT column moves with the price. Base fee only: the chain charges no priority fee.`);
216
234
  return lines.join('\n') + '\n';
217
235
  }
@@ -1,5 +1,5 @@
1
1
  import type { ShipOptions } from './ship.js';
2
- export declare const SHIP_HELP = "redbelly ship --chain <151|153> --account <keystore-name> [options]\n\nRuns pre-flight (seven checks) with the keystore's address, checks the Slither sidecar, runs\nforge test and the five-state suites, prices the gas report at the chain's base fee and feed\nprice, reads the deployer and the admin (isAllowed, Safe 1.4.1, threshold, owners), and writes\ndeployments/ship-<chain>-<date>.md with every check and its result, the addresses, the\nconstructor arguments and the verify command. Refuses to write when any check fails. The\ndeploy script refuses to broadcast on 151 without a report dated today; 153 warns.\n\n --chain <151|153> required\n --account <name> required; Foundry keystore name, resolved with cast wallet address\n --password-file <path> passed through to cast (or set ETH_PASSWORD)\n --admin <0x\u2026> the Safe that receives every role (or ADMIN_SAFE in .env); required on 151\n --gas <units> deployment gas for the balance check (default: the gas report's deployment row)\n --verifier <0x\u2026> the dApp's verifier (or VERIFIER in .env); required on 151\n --project <dir> Foundry project or scaffold root (default: current directory)\n --rpc <url> JSON-RPC endpoint (default: the governors RPC for --chain; a fork works)\n --out <path> write the report here instead\n --json print the report as JSON (the file is still written when checks pass)\n --version, --help\n";
2
+ export declare const SHIP_HELP = "redbelly ship --chain <151|153> --account <keystore-name> [options]\n (or --address <0x\u2026> in place of --account; DEPLOYER in .env also works)\n\nRuns pre-flight (seven checks) with the keystore's address, checks the Slither sidecar, runs\nforge test and the five-state suites, prices the gas report at the chain's base fee and feed\nprice, reads the deployer and the admin (isAllowed, Safe 1.4.1, threshold, owners), and writes\ndeployments/ship-<chain>-<date>.md with every check and its result, the addresses, the\nconstructor arguments and the verify command. Refuses to write when any check fails. The\ndeploy script refuses to broadcast on 151 without a report dated today; 153 warns.\n\n --chain <151|153> required\n --account <name> Foundry keystore name, resolved with cast wallet address. cast asks for the\n keystore password on the terminal, so run this in one (not from an editor's\n run button); without a terminal pass --password-file, or use --address\n --address <0x\u2026> the deployer's address, no cast call; the report says it came this way\n --password-file <path> passed through to cast (or set ETH_PASSWORD)\n --admin <0x\u2026> the Safe that receives every role (or ADMIN_SAFE in .env); required on 151\n --gas <units> deployment gas for the balance check (default: the gas report's deployment row)\n --verifier <0x\u2026> the dApp's verifier (or VERIFIER in .env); required on 151\n --project <dir> Foundry project or scaffold root (default: current directory)\n --rpc <url> JSON-RPC endpoint (default: the governors RPC for --chain; a fork works)\n --out <path> write the report here instead\n --json print the report as JSON (the file is still written when checks pass)\n --version, --help\n";
3
3
  export declare function parseShipArgs(argv: readonly string[]): (Partial<ShipOptions> & {
4
4
  json: boolean;
5
5
  help: boolean;
package/dist/ship-cli.js CHANGED
@@ -3,6 +3,7 @@
3
3
  // arguments. --json for agents. Never takes a key: --account names a keystore that cast reads.
4
4
  import { SHIP_VERSION, renderShipText, runShip, shipReportJson, ShipUsageError } from './ship.js';
5
5
  export const SHIP_HELP = `redbelly ship --chain <151|153> --account <keystore-name> [options]
6
+ (or --address <0x…> in place of --account; DEPLOYER in .env also works)
6
7
 
7
8
  Runs pre-flight (seven checks) with the keystore's address, checks the Slither sidecar, runs
8
9
  forge test and the five-state suites, prices the gas report at the chain's base fee and feed
@@ -12,7 +13,10 @@ constructor arguments and the verify command. Refuses to write when any check fa
12
13
  deploy script refuses to broadcast on 151 without a report dated today; 153 warns.
13
14
 
14
15
  --chain <151|153> required
15
- --account <name> required; Foundry keystore name, resolved with cast wallet address
16
+ --account <name> Foundry keystore name, resolved with cast wallet address. cast asks for the
17
+ keystore password on the terminal, so run this in one (not from an editor's
18
+ run button); without a terminal pass --password-file, or use --address
19
+ --address <0x…> the deployer's address, no cast call; the report says it came this way
16
20
  --password-file <path> passed through to cast (or set ETH_PASSWORD)
17
21
  --admin <0x…> the Safe that receives every role (or ADMIN_SAFE in .env); required on 151
18
22
  --gas <units> deployment gas for the balance check (default: the gas report's deployment row)
@@ -50,6 +54,9 @@ export function parseShipArgs(argv) {
50
54
  case '--account':
51
55
  o.account = next();
52
56
  break;
57
+ case '--address':
58
+ o.address = next();
59
+ break;
53
60
  case '--password-file':
54
61
  o.passwordFile = next();
55
62
  break;
@@ -91,9 +98,13 @@ export function parseShipArgs(argv) {
91
98
  if (!o.help && !o.version) {
92
99
  if (!o.chain)
93
100
  throw new Error(`--chain 151 or 153 is required\n\n${SHIP_HELP}`);
94
- if (!o.account)
95
- throw new Error(`--account <keystore-name> is required: the report carries the deployer's address and its isAllowed reading\n\n${SHIP_HELP}`);
96
- if (!/^[A-Za-z0-9._-]{1,64}$/.test(o.account))
101
+ if (!o.account && !o.address && !process.env['DEPLOYER'])
102
+ throw new Error(`--account <keystore-name> is required (or --address <0x…>, or DEPLOYER in the environment): the report carries the deployer's address and its isAllowed reading\n\n${SHIP_HELP}`);
103
+ if (o.account && o.address)
104
+ throw new Error('give --account or --address, not both');
105
+ if (o.address && !/^0x[0-9a-fA-F]{40}$/.test(o.address))
106
+ throw new Error('--address must be a 20-byte hex address');
107
+ if (o.account && !/^[A-Za-z0-9._-]{1,64}$/.test(o.account))
97
108
  throw new Error('--account: keystore names use letters, digits, dot, dash and underscore only');
98
109
  }
99
110
  return o;
package/dist/ship.d.ts CHANGED
@@ -7,8 +7,10 @@ export interface ShipOptions {
7
7
  /** Foundry project or scaffold root (its contracts/ is used). Default: cwd. */
8
8
  project?: string;
9
9
  chain: 151 | 153;
10
- /** Foundry keystore name; cast resolves the address, nothing else is read from it. */
11
- account: string;
10
+ /** Foundry keystore name; cast resolves the address, nothing else is read from it. One of account, address or DEPLOYER in .env. */
11
+ account?: string;
12
+ /** The deployer's address given directly: no cast call, no password prompt. */
13
+ address?: string;
12
14
  passwordFile?: string;
13
15
  /** The Safe that receives every role. Required on 151; ADMIN_SAFE in .env fills it in. */
14
16
  admin?: string;
package/dist/ship.js CHANGED
@@ -13,7 +13,7 @@ import { chainById, decodeWords, ethCall, isAllowed, toCaller } from '@gatedpath
13
13
  import { readProjectConfig } from './config.js';
14
14
  import { readDotEnv } from './dotenv.js';
15
15
  import { readAdmin } from './checks/admin.js';
16
- import { parseGasReportJson, priceRows, quoteGas } from './gas.js';
16
+ import { faucetDays, parseGasReportJson, priceRows, quoteGas } from './gas.js';
17
17
  import { run } from './proc.js';
18
18
  import { DEFAULT_GAS, runPreflight } from './run.js';
19
19
  import { findGatedSuites, summariseTests } from './suites.js';
@@ -151,7 +151,7 @@ export async function runShip(opts) {
151
151
  // 2. pre-flight, seven checks, with the keystore's address and the measured deployment gas
152
152
  const gasForBalance = opts.gas !== undefined ? BigInt(opts.gas) : (deploymentGas ?? DEFAULT_GAS);
153
153
  const admin = opts.admin ?? rootEnv['ADMIN_SAFE'];
154
- const preflight = await runPreflight({ project: dir, chain, rpc, account: opts.account, ...(opts.passwordFile ? { passwordFile: opts.passwordFile } : {}), ...(admin ? { admin } : {}), gas: gasForBalance, env });
154
+ const preflight = await runPreflight({ project: dir, chain, rpc, ...(opts.account ? { account: opts.account } : {}), ...(opts.address ? { address: opts.address } : {}), ...(opts.passwordFile ? { passwordFile: opts.passwordFile } : {}), ...(admin ? { admin } : {}), gas: gasForBalance, env });
155
155
  for (const c of preflight.checks)
156
156
  checks.push({ id: c.id, status: c.status, reason: c.reason, ...(c.data ? { data: c.data } : {}) });
157
157
  if (chain === 151 && !admin)
@@ -214,7 +214,7 @@ export async function runShip(opts) {
214
214
  const deployerCheck = preflight.checks.find((c) => c.id === 'deployer-verified');
215
215
  const deployer = {
216
216
  address: preflight.deployer,
217
- how: deployerCheck?.data?.['how'] ?? (opts.account ? `cast wallet address --account ${opts.account}` : 'none'),
217
+ how: deployerCheck?.data?.['how'] ?? (opts.account ? `cast wallet address --account ${opts.account}` : opts.address ? '--address' : 'none'),
218
218
  isAllowed: typeof deployerCheck?.data?.['allowed'] === 'boolean' ? deployerCheck.data['allowed'] : null,
219
219
  wellKnownDevAccount: deployerCheck?.data?.['wellKnownDevAccount'] === true,
220
220
  };
@@ -316,7 +316,7 @@ export function renderShipMarkdown(r) {
316
316
  L.push('## Contracts');
317
317
  L.push('');
318
318
  if (r.contracts.length === 0) {
319
- L.push(`No deployment record for chain ${r.chain} under \`deployments/\` yet. Deploy with \`forge script script/Deploy.s.sol --rpc-url ${r.network === 'mainnet' ? 'redbelly_mainnet' : 'redbelly_testnet'} --account <keystore-name> --broadcast\`, then run \`redbelly ship\` again today: this section fills in with the address, the constructor arguments and the exact verify command.`);
319
+ L.push(`No deployment record for chain ${r.chain} under \`deployments/\` yet. Deploy with \`forge script script/Deploy.s.sol --rpc-url ${r.network === 'mainnet' ? 'redbelly_mainnet' : 'redbelly_testnet'} --account <keystore-name> --sender ${r.deployer.address ?? '<your-address>'} --broadcast\`, then run \`redbelly ship\` again today: this section fills in with the address, the constructor arguments and the exact verify command.`);
320
320
  }
321
321
  else {
322
322
  for (const c of r.contracts) {
@@ -343,6 +343,9 @@ export function renderShipMarkdown(r) {
343
343
  const q = r.gas.quote;
344
344
  L.push(`Priced at block ${fmt(q.block)}: base fee ${(Number(q.baseFeeWei) / 1e9).toLocaleString('en-US', { maximumFractionDigits: 2 })} gwei, RBNT US$${q.usdPerRbnt} on the feed at ${q.priceFeed} (${q.priceTimestamp}). Gas is priced in US dollars on this chain and converted to RBNT at execution, so the cents column is the stable one.`);
345
345
  L.push('');
346
+ const faucet = faucetDays(r.gas.rows, r.gas.quote);
347
+ if (faucet)
348
+ L.push(`Faucet: the deployment rows with pre-flight's 25% margin come to ${fmt(faucet.gasWithMargin)} gas = ${faucet.rbnt.toFixed(1)} test RBNT at this base fee, ${faucet.claims} claim${faucet.claims === 1 ? '' : 's'} of ${faucet.perClaimRbnt} from the faucet (${faucet.days} day${faucet.days === 1 ? '' : 's'}, one claim a day). The base fee moves; re-run on the day.`, '');
346
349
  if (r.gas.deployment)
347
350
  L.push(`Deployment of ${r.gas.deployment.contract}: ${fmt(r.gas.deployment.gas)} gas = ${short(r.gas.deployment.rbnt)} RBNT = ${r.gas.deployment.cents.toFixed(2)} US cents. Pre-flight's balance check used ${fmt(BigInt(r.preflight.checks.find((c) => c.id === 'balance')?.data?.['gas'] ?? '0'))} gas with 25% on top.`);
348
351
  L.push('');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gatedpath/preflight",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "Pre-flight checks before deploying to Redbelly Network (151 mainnet, 153 testnet): chain ID, deployer verification, Safe admin, compiler pins, secrets in git history, RBNT balance, Slither report.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -40,8 +40,8 @@
40
40
  "prepack": "npm run build"
41
41
  },
42
42
  "dependencies": {
43
- "@gatedpath/agent-rules": "0.2.1",
44
- "@gatedpath/chains": "0.2.1"
43
+ "@gatedpath/agent-rules": "0.2.2",
44
+ "@gatedpath/chains": "0.2.2"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@types/node": "^22.20.2",