@elgora/cli 7.5.0 → 8.0.0

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.
Files changed (3) hide show
  1. package/README.md +15 -7
  2. package/dist/cli.js +238 -37
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -41,7 +41,8 @@ answer.
41
41
  on ElgoraHub.
42
42
  - `guardian:deliver-key` wraps one Solver–Submission content key for delivery
43
43
  so the funding Poster can retrieve the winning work; idempotent, and accepted
44
- only for the pair ElgoraHub currently records or the finalized winner.
44
+ only for the pair ElgoraHub currently records or the finalized winner. While
45
+ a settlement is not yet finalized it delivers nothing and exits `75`.
45
46
  - `claim` prepares or sends the winning Solver's reserved award or the
46
47
  Poster's queued refund, as selected from finalized ElgoraHub state.
47
48
  - `verification-record` is a plain, unauthenticated GET that fetches or lazily
@@ -79,6 +80,11 @@ needs.
79
80
 
80
81
  ## Deployment configuration
81
82
 
83
+ Since 8.0.0 the default deployment is **Base mainnet** (`base`, chain `8453`),
84
+ which escrows real USDC. Elgora's staging deployment runs on **Base Sepolia**
85
+ (`base-sepolia`, chain `84532`) behind `https://staging.elgora.ai`. A run that
86
+ selects no network prints one stderr line saying it used the default.
87
+
82
88
  Every command accepts `--network <name|chain id>`, which selects the deployment
83
89
  for that invocation without touching the environment. It takes a network name
84
90
  (`base`, `base-sepolia`, `local`) or that network's chain id (`8453`, `84532`,
@@ -86,9 +92,10 @@ for that invocation without touching the environment. It takes a network name
86
92
  passed — for that run only:
87
93
 
88
94
  ```sh
89
- elgora-cli guardian:judgeable # the default deployment
90
- elgora-cli claim --network base-sepolia 7 # one invocation, by name
95
+ elgora-cli guardian:judgeable # Base mainnet, the default
96
+ elgora-cli claim --network base-sepolia 7 # staging, by name
91
97
  elgora-cli claim --network 84532 7 # the same, by chain id
98
+ export ELGORA_CHAIN_ID=84532 # staging for every run in this shell
92
99
  ```
93
100
 
94
101
  The chain's public RPC, the ElgoraHub address, the escrow token, and the subgraph
@@ -101,10 +108,11 @@ and which values it defaults. Supply a complete, coherent configuration when
101
108
  targeting a deployment this CLI release does not know about, and do not mix
102
109
  addresses or endpoints from different deployments.
103
110
 
104
- Commands that use the public API accept `--api-base-url <url>`. That is a
105
- separate choice from the chain: it names one API deployment, and the flag wins
106
- over `ELGORA_API_BASE_URL` for that invocation. Point it at an API serving the
107
- deployment you selected.
111
+ The API follows the chain too: `https://elgora.ai` for `base` and
112
+ `https://staging.elgora.ai` for `base-sepolia`. Commands that use the public API
113
+ accept `--api-base-url <url>`, which wins over `ELGORA_API_BASE_URL` and that
114
+ default for one invocation — for example to reach a Vercel preview. Point it at
115
+ an API serving the deployment you selected.
108
116
 
109
117
  Protected API reads and writes use one EIP-712 approval per request. The
110
118
  signature is bound to the method, path, body, query, API host, and a recent
package/dist/cli.js CHANGED
@@ -532,7 +532,7 @@ var AES_GCM_TAG_BITS = 128;
532
532
  var BASE64URL_RE = /^[A-Za-z0-9_-]+$/;
533
533
  var SOLVER_SUBMISSION_NAME_RE = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
534
534
  var MEDIA_TYPE_RE = /^[a-z0-9][a-z0-9!#$&^_.+-]*\/[a-z0-9][a-z0-9!#$&^_.+-]*$/;
535
- var KEY_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._:-]*$/;
535
+ var KEY_ID_RE = /^[A-Za-z0-9][ -~]*$/;
536
536
  var base64UrlSchema = z3.string().regex(BASE64URL_RE);
537
537
  var lowerAddressSchema = z3.string().refine(isLowercaseHexAddress);
538
538
  var bytes32Schema2 = z3.string().refine(isLowercaseBytes32);
@@ -1352,8 +1352,8 @@ function readFrontmatter(markdown, issues) {
1352
1352
  return null;
1353
1353
  }
1354
1354
  }
1355
- function resolveProfile(declared, fallback, issues) {
1356
- const pinned = getProtocolProfile(declared) ?? (declared === fallback.profile ? fallback : null);
1355
+ function resolveProfile(declared, fallback2, issues) {
1356
+ const pinned = getProtocolProfile(declared) ?? (declared === fallback2.profile ? fallback2 : null);
1357
1357
  if (pinned === null) {
1358
1358
  issues.push({
1359
1359
  code: "profile_unknown",
@@ -1486,19 +1486,30 @@ function parseInlineList(value) {
1486
1486
  }
1487
1487
 
1488
1488
  // ../../packages/core/src/deployments.ts
1489
- import { baseSepolia as baseSepolia2 } from "viem/chains";
1489
+ import { base as base2, baseSepolia as baseSepolia2 } from "viem/chains";
1490
1490
  var DEPLOYMENTS = {
1491
+ [base2.id]: {
1492
+ ELGORA_HUB_ADDRESS: "0x8f80d1183cd983b01b0c9ac6777cc732ec9800de",
1493
+ ELGORA_ESCROW_TOKEN_ADDRESS: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
1494
+ payoutSchemeAddress: "0x36d304993cb1575a2f9b8a0388b18aa5ec6d7a61",
1495
+ ELGORA_SUBGRAPH_ENDPOINT: "https://api.goldsky.com/api/public/project_cmtu7wslg04s501ovc2je3beh/subgraphs/elgora-elgorahub-base/production/gn",
1496
+ ELGORA_API_BASE_URL: "https://elgora.ai",
1497
+ deployBlock: 51752389,
1498
+ deployTransaction: "0xd62f407b770c8fca82a9704b30ed0605d9e3ed2b56278dcca152958063f7f469",
1499
+ sourceCommit: "8d40270d617a63dd5a7a35045db0d9ea3ddd9093"
1500
+ },
1491
1501
  [baseSepolia2.id]: {
1492
1502
  ELGORA_HUB_ADDRESS: "0x2f97b5f616495c2e923f39a46648eb783c053ad7",
1493
1503
  ELGORA_ESCROW_TOKEN_ADDRESS: "0x036cbd53842c5426634e7929541ec2318f3dcf7e",
1494
1504
  payoutSchemeAddress: "0x752d4305b8567b777d479dfa9847dc4f5ffb5750",
1495
1505
  ELGORA_SUBGRAPH_ENDPOINT: "https://api.goldsky.com/api/public/project_cmtu7wslg04s501ovc2je3beh/subgraphs/elgora-elgorahub/testnet-production/gn",
1506
+ ELGORA_API_BASE_URL: "https://staging.elgora.ai",
1496
1507
  deployBlock: 46353511,
1497
1508
  deployTransaction: "0xed3d3c8af3c69f9f8d4ec47da7179fe4b89bd4a4cd8d8232dbbd3d3f3d38e74b",
1498
1509
  sourceCommit: "1377da5c38dc5c90d8608ffa3cb15ad6f8567a01"
1499
1510
  }
1500
1511
  };
1501
- var DEFAULT_CHAIN_ID = baseSepolia2.id;
1512
+ var DEFAULT_CHAIN_ID = base2.id;
1502
1513
  function getDeployment(chainId) {
1503
1514
  return DEPLOYMENTS[chainId];
1504
1515
  }
@@ -4716,20 +4727,52 @@ function invalidWrittenVerdict(path5, message) {
4716
4727
  import {
4717
4728
  createPublicClient,
4718
4729
  createWalletClient,
4730
+ fallback,
4719
4731
  http
4720
4732
  } from "viem";
4733
+
4734
+ // ../../packages/core/src/auth/freshness.ts
4735
+ var API_REQUEST_APPROVAL_ANCHOR_LAG_SECONDS = 6;
4736
+ var FALLBACK_BLOCK_TIME_MS = 2e3;
4737
+ function blockTimeMsFor(chainId) {
4738
+ const chain = chainId === void 0 ? void 0 : SUPPORTED_CHAINS[chainId];
4739
+ return chain?.blockTime ?? FALLBACK_BLOCK_TIME_MS;
4740
+ }
4741
+ function blocksForSeconds(seconds, chainId) {
4742
+ const blocks = Math.ceil(seconds * 1e3 / blockTimeMsFor(chainId));
4743
+ return BigInt(Math.max(1, blocks));
4744
+ }
4745
+ function apiRequestApprovalAnchorLagBlocks(chainId) {
4746
+ return blocksForSeconds(API_REQUEST_APPROVAL_ANCHOR_LAG_SECONDS, chainId);
4747
+ }
4748
+
4749
+ // ../../packages/core/src/chain-client.ts
4721
4750
  var RPC_RETRY_COUNT = 3;
4751
+ function createChainTransport(chainId, rpcUrl) {
4752
+ const publicRpcUrl = resolveSupportedChain(chainId).rpcUrls.default.http[0];
4753
+ const configuredRpcUrl = rpcUrl?.trim() || publicRpcUrl;
4754
+ if (!publicRpcUrl || configuredRpcUrl === publicRpcUrl) {
4755
+ return http(configuredRpcUrl, { retryCount: RPC_RETRY_COUNT });
4756
+ }
4757
+ return fallback(
4758
+ [
4759
+ http(configuredRpcUrl, { retryCount: 0 }),
4760
+ http(publicRpcUrl, { retryCount: 0 })
4761
+ ],
4762
+ { retryCount: RPC_RETRY_COUNT }
4763
+ );
4764
+ }
4722
4765
  function createChainPublicClient(chainId, rpcUrl) {
4723
4766
  return createPublicClient({
4724
4767
  chain: resolveSupportedChain(chainId),
4725
- transport: http(rpcUrl, { retryCount: RPC_RETRY_COUNT })
4768
+ transport: createChainTransport(chainId, rpcUrl)
4726
4769
  });
4727
4770
  }
4728
4771
  function createChainWalletClient(chainId, rpcUrl, account) {
4729
4772
  return createWalletClient({
4730
4773
  account,
4731
4774
  chain: resolveSupportedChain(chainId),
4732
- transport: http(rpcUrl, { retryCount: RPC_RETRY_COUNT })
4775
+ transport: createChainTransport(chainId, rpcUrl)
4733
4776
  });
4734
4777
  }
4735
4778
  function assertChainId(actual, expected) {
@@ -4737,10 +4780,10 @@ function assertChainId(actual, expected) {
4737
4780
  throw new Error(`RPC returned chain_id ${actual}, expected ${expected}`);
4738
4781
  }
4739
4782
  }
4740
- var SIGNING_BLOCK_OFFSET = 3n;
4741
4783
  async function fetchSignableBlock(client) {
4784
+ const offset = apiRequestApprovalAnchorLagBlocks(client.chain?.id);
4742
4785
  const head = await client.getBlockNumber();
4743
- const anchorNumber = head > SIGNING_BLOCK_OFFSET ? head - SIGNING_BLOCK_OFFSET : 0n;
4786
+ const anchorNumber = head > offset ? head - offset : 0n;
4744
4787
  const anchor = await client.getBlock({ blockNumber: anchorNumber });
4745
4788
  return { number: anchor.number, hash: anchor.hash };
4746
4789
  }
@@ -5032,7 +5075,6 @@ function loadClaimConfig(env, claimantAddress) {
5032
5075
  }
5033
5076
 
5034
5077
  // ../../packages/core/src/api-client-config.ts
5035
- var PRODUCTION_API_BASE_URL = "https://elgora.vercel.app";
5036
5078
  var LOCAL_DEV_API_BASE_URL = "http://127.0.0.1:3000";
5037
5079
  var API_BASE_URL_FLAG = "--api-base-url";
5038
5080
  function loadApiClientConfig(env, apiBaseUrlOverride) {
@@ -5060,7 +5102,15 @@ function resolveApiBaseUrl(env, override) {
5060
5102
  return value;
5061
5103
  }
5062
5104
  function defaultApiBaseUrl(env) {
5063
- return env.NODE_ENV === "development" ? LOCAL_DEV_API_BASE_URL : PRODUCTION_API_BASE_URL;
5105
+ if (env.NODE_ENV === "development") return LOCAL_DEV_API_BASE_URL;
5106
+ const chainId = Number(env.ELGORA_CHAIN_ID?.trim() || DEFAULT_CHAIN_ID);
5107
+ const recorded = getDeployment(chainId)?.ELGORA_API_BASE_URL;
5108
+ if (!recorded) {
5109
+ throw new Error(
5110
+ `No Elgora API is recorded for chain ${chainId}; set ELGORA_API_BASE_URL or pass --api-base-url`
5111
+ );
5112
+ }
5113
+ return recorded;
5064
5114
  }
5065
5115
 
5066
5116
  // ../../packages/core/src/api-client.ts
@@ -5581,6 +5631,7 @@ function readGuardianPrivateKeys(env) {
5581
5631
  }
5582
5632
 
5583
5633
  // src/guardian-deliver-key.ts
5634
+ var PENDING_FINALITY_EXIT_CODE = 75;
5584
5635
  var USAGE = "Usage: elgora-cli guardian:deliver-key <bounty_id> <solver> <submission_commitment>";
5585
5636
  async function main4(env = process.env, argv = process.argv.slice(2)) {
5586
5637
  const { apiBaseUrl, argv: positionalArgs } = extractApiBaseUrlFlag(argv);
@@ -5595,6 +5646,33 @@ async function main4(env = process.env, argv = process.argv.slice(2)) {
5595
5646
  "ELGORA_GUARDIAN_ACCOUNT_PRIVATE_KEY must be a 32-byte hex private key"
5596
5647
  );
5597
5648
  }
5649
+ const guardianPrivateKeys = readGuardianPrivateKeys(env);
5650
+ const publicClient = createChainPublicClient(config.chainId, rpcUrl);
5651
+ const finality = await readSettlementFinality(
5652
+ publicClient,
5653
+ config.hubAddress,
5654
+ bountyId
5655
+ );
5656
+ if (finality.latestStatus === "no_valid_submission" || finality.latestStatus === "timed_out") {
5657
+ throw new Error(
5658
+ `Bounty ${bountyId.toString()} settled ${finality.latestStatus}; there is no winning key to deliver`
5659
+ );
5660
+ }
5661
+ if (finality.pending) {
5662
+ console.log(
5663
+ JSON.stringify({
5664
+ event: "guardian_deliver_key.pending_finality",
5665
+ bounty_id: bountyId.toString(),
5666
+ solver,
5667
+ submission_commitment: submissionCommitment,
5668
+ latest_status: finality.latestStatus,
5669
+ finalized_status: finality.finalizedStatus,
5670
+ message: "Settlement is not behind the chain's finalized tag yet; nothing was delivered. Retry in 10-20 minutes."
5671
+ })
5672
+ );
5673
+ process.exitCode = PENDING_FINALITY_EXIT_CODE;
5674
+ return;
5675
+ }
5598
5676
  const account = privateKeyToAccount4(guardianAccountPrivateKey);
5599
5677
  const wrapped = await wrapWinningSolutionKey({
5600
5678
  config,
@@ -5605,8 +5683,8 @@ async function main4(env = process.env, argv = process.argv.slice(2)) {
5605
5683
  privateKey: guardianAccountPrivateKey,
5606
5684
  address: account.address
5607
5685
  },
5608
- publicClient: createChainPublicClient(config.chainId, rpcUrl),
5609
- guardianPrivateKeys: readGuardianPrivateKeys(env)
5686
+ publicClient,
5687
+ guardianPrivateKeys
5610
5688
  });
5611
5689
  console.log(
5612
5690
  JSON.stringify({
@@ -5618,6 +5696,30 @@ async function main4(env = process.env, argv = process.argv.slice(2)) {
5618
5696
  })
5619
5697
  );
5620
5698
  }
5699
+ async function readSettlementFinality(publicClient, hubAddress, bountyId) {
5700
+ const finalizedBlock = await publicClient.getBlock({
5701
+ blockTag: "finalized"
5702
+ });
5703
+ const readStatus = async (blockNumber) => {
5704
+ const [, state] = await publicClient.readContract({
5705
+ address: hubAddress,
5706
+ abi: ELGORA_HUB_BOUNTY_READ_ABI,
5707
+ functionName: "getBounty",
5708
+ args: [bountyId],
5709
+ ...blockNumber === void 0 ? {} : { blockNumber }
5710
+ });
5711
+ return decodeBountyStatus(state.status);
5712
+ };
5713
+ const [latestStatus, finalizedStatus] = await Promise.all([
5714
+ readStatus(),
5715
+ readStatus(finalizedBlock.number)
5716
+ ]);
5717
+ return {
5718
+ pending: latestStatus === "awarded" && finalizedStatus === "open",
5719
+ latestStatus,
5720
+ finalizedStatus
5721
+ };
5722
+ }
5621
5723
  function readArgs(argv) {
5622
5724
  const [bountyId, solver, submissionCommitment] = argv;
5623
5725
  if (!bountyId || !isNumeric(bountyId) || !solver || !isHexAddress(solver) || !submissionCommitment || !isHexBytes32(submissionCommitment)) {
@@ -5754,6 +5856,13 @@ var BOUNTY_DETAIL_QUERY = `
5754
5856
  reportCommitments
5755
5857
  awardedPayoutData
5756
5858
  timedOutRefundAmount
5859
+ settledLogIndex
5860
+ claimsQueued(first: 1, orderBy: queuedLogIndex, orderDirection: desc) {
5861
+ recipient
5862
+ amount
5863
+ queuedTxHash
5864
+ queuedLogIndex
5865
+ }
5757
5866
  guardianRoster {
5758
5867
  ${GUARDIAN_ROSTER_SNAPSHOT_FIELDS}
5759
5868
  }
@@ -6131,8 +6240,17 @@ function mapAnalyticsGuardianRoster(row) {
6131
6240
  }
6132
6241
  function mapBountyDetail(row) {
6133
6242
  const record = readRecord(row);
6243
+ const allocation = record.claimsQueued == null ? null : asArray(record.claimsQueued, "claimsQueued")[0];
6244
+ let guardianFeeAmount = null;
6245
+ if ((record.status === "Awarded" || record.status === "NoValidSubmission") && allocation && record.settledTxHash && record.settledLogIndex != null) {
6246
+ const claim = readRecord(allocation);
6247
+ if (asHex(claim.recipient, "recipient") === asHex(record.guardianFeeRecipient, "guardianFeeRecipient") && asHex(claim.queuedTxHash, "queuedTxHash") === asHex(record.settledTxHash, "settledTxHash") && asNumber(claim.queuedLogIndex, "queuedLogIndex") + 1 === asNumber(record.settledLogIndex, "settledLogIndex")) {
6248
+ guardianFeeAmount = asString(claim.amount, "amount");
6249
+ }
6250
+ }
6134
6251
  return {
6135
6252
  ...mapBounty(record),
6253
+ guardianFeeAmount,
6136
6254
  guardianRosterAdmin: asHex(
6137
6255
  record.guardianRosterAdmin,
6138
6256
  "guardianRosterAdmin"
@@ -6586,7 +6704,10 @@ function parseChallenge(text) {
6586
6704
 
6587
6705
  // src/guardian-verdict.ts
6588
6706
  import { readFile as readFile3 } from "fs/promises";
6589
- import { zeroAddress as zeroAddress4 } from "viem";
6707
+ import {
6708
+ BaseError as BaseError2,
6709
+ zeroAddress as zeroAddress4
6710
+ } from "viem";
6590
6711
  import { privateKeyToAccount as privateKeyToAccount6 } from "viem/accounts";
6591
6712
  var OUTCOME = {
6592
6713
  no_valid_submission: 0,
@@ -6797,20 +6918,66 @@ async function main7(env = process.env, argv = process.argv.slice(2)) {
6797
6918
  functionName: "commitVerdict",
6798
6919
  args: contractArgs
6799
6920
  });
6921
+ const replacements = [];
6800
6922
  const receipt = await publicClient.waitForTransactionReceipt({
6801
- hash: transactionHash
6923
+ hash: transactionHash,
6924
+ onReplaced: (replacement) => replacements.push(replacement)
6802
6925
  });
6926
+ if (receipt.transactionHash !== transactionHash && replacements.at(-1)?.reason !== "repriced") {
6927
+ throw new Error(
6928
+ `commitVerdict transaction ${transactionHash} was ${replacements.at(-1)?.reason ?? "replaced"} by ${receipt.transactionHash}; this Verdict was not recorded`
6929
+ );
6930
+ }
6803
6931
  if (receipt.status !== "success") {
6804
- throw new Error(`commitVerdict transaction reverted: ${transactionHash}`);
6932
+ throw new Error(
6933
+ `commitVerdict transaction reverted: ${receipt.transactionHash}`
6934
+ );
6805
6935
  }
6806
- const recorded = await publicClient.readContract({
6807
- address: config.hubAddress,
6808
- abi: ELGORA_HUB_VERDICT_WRITE_ABI,
6809
- functionName: "verdicts",
6810
- args: [args.bountyId, account.address]
6811
- });
6812
- if (!recorded[0] || recorded[1] !== contractArgs[1] || recorded[2].toLowerCase() !== contractArgs[2].toLowerCase() || recorded[3].toLowerCase() !== contractArgs[3].toLowerCase() || recorded[4].toLowerCase() !== reportCommitment || recorded[5].toLowerCase() !== "0x") {
6813
- throw new Error("ElgoraHub did not record the expected on-chain Verdict");
6936
+ let readbackIssue;
6937
+ try {
6938
+ const recorded = await publicClient.readContract({
6939
+ address: config.hubAddress,
6940
+ abi: ELGORA_HUB_VERDICT_WRITE_ABI,
6941
+ functionName: "verdicts",
6942
+ args: [args.bountyId, account.address],
6943
+ blockNumber: receipt.blockNumber
6944
+ });
6945
+ if (!recorded[0] || recorded[1] !== contractArgs[1] || recorded[2].toLowerCase() !== contractArgs[2].toLowerCase() || recorded[3].toLowerCase() !== contractArgs[3].toLowerCase() || recorded[4].toLowerCase() !== reportCommitment || recorded[5].toLowerCase() !== "0x") {
6946
+ readbackIssue = {
6947
+ observed: {
6948
+ committed: recorded[0],
6949
+ outcome: recorded[1],
6950
+ winner: recorded[2],
6951
+ awarded_submission_commitment: recorded[3],
6952
+ report_commitment: recorded[4],
6953
+ payout_data: recorded[5]
6954
+ }
6955
+ };
6956
+ }
6957
+ } catch (error) {
6958
+ readbackIssue = {
6959
+ error: error instanceof BaseError2 ? error.walk().name : error instanceof Error ? error.name : "UnknownError"
6960
+ };
6961
+ }
6962
+ if (readbackIssue) {
6963
+ console.warn(
6964
+ JSON.stringify({
6965
+ event: "guardian_verdict.readback_unconfirmed",
6966
+ bounty_id: args.bountyId.toString(),
6967
+ guardian: account.address.toLowerCase(),
6968
+ tx_hash: receipt.transactionHash,
6969
+ block_number: receipt.blockNumber.toString(),
6970
+ expected: {
6971
+ committed: true,
6972
+ outcome: contractArgs[1],
6973
+ winner: contractArgs[2],
6974
+ awarded_submission_commitment: contractArgs[3],
6975
+ report_commitment: reportCommitment,
6976
+ payout_data: "0x"
6977
+ },
6978
+ ...readbackIssue
6979
+ })
6980
+ );
6814
6981
  }
6815
6982
  console.log(
6816
6983
  JSON.stringify({
@@ -6823,7 +6990,7 @@ async function main7(env = process.env, argv = process.argv.slice(2)) {
6823
6990
  awarded_submission_commitment: args.awardedSubmissionCommitment
6824
6991
  } : {},
6825
6992
  report_commitment: reportCommitment,
6826
- tx_hash: transactionHash,
6993
+ tx_hash: receipt.transactionHash,
6827
6994
  block_number: receipt.blockNumber.toString()
6828
6995
  })
6829
6996
  );
@@ -6874,14 +7041,40 @@ function usageError() {
6874
7041
  }
6875
7042
 
6876
7043
  // src/network-flag.ts
6877
- import { base as base2, baseSepolia as baseSepolia3, foundry as foundry3 } from "viem/chains";
7044
+ import { base as base3, baseSepolia as baseSepolia3, foundry as foundry3 } from "viem/chains";
6878
7045
  var NETWORK_FLAG = "--network";
6879
- var NETWORK_CHAIN_IDS = {
6880
- base: base2.id,
6881
- "base-sepolia": baseSepolia3.id,
6882
- local: foundry3.id
6883
- };
6884
- var NETWORK_NAMES_HINT = Object.entries(NETWORK_CHAIN_IDS).map(([name, chainId]) => `${name} (${chainId})`).join(", ");
7046
+ var NETWORKS = [
7047
+ { name: "base", chainId: base3.id, label: "Base mainnet" },
7048
+ {
7049
+ name: "base-sepolia",
7050
+ chainId: baseSepolia3.id,
7051
+ label: "Base Sepolia testnet, Elgora's staging deployment"
7052
+ },
7053
+ { name: "local", chainId: foundry3.id, label: "a local Anvil stack" }
7054
+ ];
7055
+ var NETWORK_CHAIN_IDS = Object.fromEntries(
7056
+ NETWORKS.map(({ name, chainId }) => [name, chainId])
7057
+ );
7058
+ var STAGING_NETWORK = NETWORKS.find(
7059
+ ({ chainId }) => chainId === baseSepolia3.id
7060
+ );
7061
+ var NETWORK_NAMES_HINT = NETWORKS.map(
7062
+ ({ name, chainId }) => `${name} (${chainId})`
7063
+ ).join(", ");
7064
+ function describeChain(chainId) {
7065
+ const network = NETWORKS.find((candidate) => candidate.chainId === chainId);
7066
+ return network ? `${network.name} (${network.label})` : `chain ${chainId}`;
7067
+ }
7068
+ var STAGING_HINT = `add ${NETWORK_FLAG} ${STAGING_NETWORK.name} or set ELGORA_CHAIN_ID=${STAGING_NETWORK.chainId}`;
7069
+ var DEFAULT_NETWORK_HELP_LINES = [
7070
+ `Default: ${describeChain(DEFAULT_CHAIN_ID)}.`,
7071
+ `Staging: ${describeChain(STAGING_NETWORK.chainId)};`,
7072
+ ` ${STAGING_HINT}.`
7073
+ ];
7074
+ function defaultNetworkNotice(env) {
7075
+ if (env.ELGORA_CHAIN_ID?.trim()) return void 0;
7076
+ return `elgora-cli: using the default network, ${describeChain(DEFAULT_CHAIN_ID)}. For staging, ${STAGING_HINT}.`;
7077
+ }
6885
7078
  function applyNetworkFlag(env, argv) {
6886
7079
  const present = argv.some(
6887
7080
  (arg) => arg === NETWORK_FLAG || arg.startsWith(`${NETWORK_FLAG}=`)
@@ -6907,7 +7100,7 @@ function resolveChainId(selector) {
6907
7100
  }
6908
7101
 
6909
7102
  // src/version.ts
6910
- var CLI_VERSION = true ? "7.5.0" : "0.0.0-dev";
7103
+ var CLI_VERSION = true ? "8.0.0" : "0.0.0-dev";
6911
7104
  var CLI_NODE_ENGINES = true ? ">=24 <25" : ">=24 <25";
6912
7105
 
6913
7106
  // src/node-engines.ts
@@ -7476,8 +7669,9 @@ function parseRosterAddGuardianArgs(argv) {
7476
7669
  if (!KEY_ID_RE.test(name)) {
7477
7670
  throw new Error(
7478
7671
  // A Solver's CLI seals private artifacts against this exact string as
7479
- // the Guardian's key_id, so it can't contain spaces or punctuation the
7480
- // wire format rejects — no display-only rendering happens in between.
7672
+ // the Guardian's key_id, so it must be non-empty, start with an
7673
+ // alphanumeric, and stay within printable ASCII (no control/formatting
7674
+ // characters, no leading whitespace).
7481
7675
  `name must match ${KEY_ID_RE.source} (it becomes this Guardian's private-artifact key_id)`
7482
7676
  );
7483
7677
  }
@@ -8403,7 +8597,7 @@ var COMMAND_HELP = {
8403
8597
  "guardian:deliver-key": {
8404
8598
  usage: "elgora-cli guardian:deliver-key <bounty_id> <solver> <submission_commitment>",
8405
8599
  title: "Deliver the finalized winner's content key for Poster retrieval.",
8406
- description: "Required after a bounty finalizes `awarded`: wrap the winning\n Submission's key so the funding Poster can retrieve the work. Read the\n winning Solver and Submission from ElgoraHub's finalized state (the\n subgraph), not from a local Verdict, and pass exactly that pair. The\n API rechecks against ElgoraHub and accepts only the current active or\n finalized winner; written Verdicts and local state authorize nothing.\n Idempotent \u2014 safe to re-run and safe if another Guardian already did it.",
8600
+ description: "Required after a bounty finalizes `awarded`: wrap the winning\n Submission's key so the funding Poster can retrieve the work. Read the\n winning Solver and Submission from ElgoraHub's finalized state (the\n subgraph), not from a local Verdict, and pass exactly that pair. The\n API rechecks against ElgoraHub and accepts only the current active or\n finalized winner; written Verdicts and local state authorize nothing.\n Idempotent \u2014 safe to re-run and safe if another Guardian already did it.\n Until the settlement block is behind the chain's finalized tag (about\n 10-20 minutes after settlement) it delivers nothing, prints\n guardian_deliver_key.pending_finality, and exits 75; retry later.",
8407
8601
  required: [
8408
8602
  "ELGORA_GUARDIAN_ACCOUNT_PRIVATE_KEY",
8409
8603
  "ELGORA_GUARDIAN_PRIVATE_KEYS_JSON"
@@ -8545,6 +8739,11 @@ async function run(rawArgv) {
8545
8739
  process.exitCode = 1;
8546
8740
  return;
8547
8741
  }
8742
+ const networkNotice = COMMAND_HELP[subcommand]?.defaulted?.includes(
8743
+ "ELGORA_CHAIN_ID"
8744
+ ) ? defaultNetworkNotice(env) : void 0;
8745
+ if (networkNotice) process.stderr.write(`${networkNotice}
8746
+ `);
8548
8747
  const missing = missingRequiredEnv(
8549
8748
  COMMAND_HELP[subcommand]?.required ?? [],
8550
8749
  env
@@ -8579,6 +8778,7 @@ function printUsage() {
8579
8778
  "",
8580
8779
  `Every command accepts ${NETWORK_FLAG} <name|chain id> to select the`,
8581
8780
  `deployment for that invocation. Supported: ${NETWORK_NAMES_HINT}.`,
8781
+ ...DEFAULT_NETWORK_HELP_LINES,
8582
8782
  "",
8583
8783
  "Run `elgora-cli help <command>` for exact arguments and configuration.",
8584
8784
  "Run `elgora-cli --version` to print this release's version."
@@ -8614,7 +8814,8 @@ function printCommandHelpOrUsage(name) {
8614
8814
  "",
8615
8815
  `Accepts ${NETWORK_FLAG} <name|chain id>; it sets ELGORA_CHAIN_ID for`,
8616
8816
  "this invocation, winning over the environment.",
8617
- `Supported: ${NETWORK_NAMES_HINT}.`
8817
+ `Supported: ${NETWORK_NAMES_HINT}.`,
8818
+ ...DEFAULT_NETWORK_HELP_LINES
8618
8819
  );
8619
8820
  }
8620
8821
  if (help.apiBaseUrlFlag) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elgora/cli",
3
- "version": "7.5.0",
3
+ "version": "8.0.0",
4
4
  "description": "Command-line client for Elgora, a decentralized bounty marketplace for science. Lets Posters, Solvers, and Guardians interact with Elgora's public API and on-chain contracts.",
5
5
  "type": "module",
6
6
  "license": "MIT",