@elgora/cli 8.0.0 → 9.1.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.
- package/README.md +7 -2
- package/dist/cli.js +493 -284
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -27,10 +27,15 @@ answer.
|
|
|
27
27
|
|
|
28
28
|
## Commands
|
|
29
29
|
|
|
30
|
-
- `poster:
|
|
31
|
-
|
|
30
|
+
- `poster:review` checks a bounty page and saves its readiness certificate
|
|
31
|
+
with `--signoff-out <file>`. Rejected pages print the full issue list and exit 2.
|
|
32
|
+
- `poster:publish-fund` requires `--signoff <file>`, publishes those exact
|
|
33
|
+
approved `bounty_challenge.md` bytes, and funds the new bounty without another AI review.
|
|
32
34
|
- `poster:open-winning-submission` retrieves the finalized winning Submission
|
|
33
35
|
for the funding Poster and decrypts it locally.
|
|
36
|
+
- `check-page <bounty_challenge_md_path|->` checks structural conformance offline,
|
|
37
|
+
returns an issue list and exits non-zero on failure. It needs no wallet or
|
|
38
|
+
network and does not replace hosted semantic readiness review.
|
|
34
39
|
- `spec-commitment` reproduces the challenge's `spec_commitment` offline.
|
|
35
40
|
- `solver:submit` encrypts a Submission for the bounty's pinned Guardian roster
|
|
36
41
|
and prepares or sends the exact ElgoraHub transaction.
|
package/dist/cli.js
CHANGED
|
@@ -384,36 +384,107 @@ function isBountyChallengeFrontmatterKey(value) {
|
|
|
384
384
|
}
|
|
385
385
|
|
|
386
386
|
// ../../packages/core/src/bounty-publication-response.ts
|
|
387
|
-
import { isHex as
|
|
387
|
+
import { isHex as isHex3 } from "viem";
|
|
388
|
+
import { z as z3 } from "zod";
|
|
389
|
+
|
|
390
|
+
// ../../packages/core/src/auth/readiness-signoff.ts
|
|
391
|
+
import {
|
|
392
|
+
isAddressEqual,
|
|
393
|
+
isHex as isHex2,
|
|
394
|
+
recoverTypedDataAddress,
|
|
395
|
+
size as size2
|
|
396
|
+
} from "viem";
|
|
388
397
|
import { z as z2 } from "zod";
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
var
|
|
392
|
-
var
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
398
|
+
|
|
399
|
+
// ../../packages/core/src/auth/eip712.ts
|
|
400
|
+
var API_REQUEST_APPROVAL_PRIMARY_TYPE = "ApiRequestApproval";
|
|
401
|
+
var API_REQUEST_APPROVAL_TYPES = {
|
|
402
|
+
ApiRequestApproval: [
|
|
403
|
+
{ name: "endpointId", type: "string" },
|
|
404
|
+
{ name: "audience", type: "string" },
|
|
405
|
+
{ name: "bodyHash", type: "bytes32" },
|
|
406
|
+
{ name: "query", type: "string" },
|
|
407
|
+
{ name: "blockNumber", type: "uint256" },
|
|
408
|
+
{ name: "blockHash", type: "bytes32" }
|
|
409
|
+
]
|
|
410
|
+
};
|
|
411
|
+
function buildElgoraEip712Domain(params) {
|
|
412
|
+
return {
|
|
413
|
+
name: "Elgora",
|
|
414
|
+
version: "1",
|
|
415
|
+
chainId: params.chainId,
|
|
416
|
+
verifyingContract: params.hubAddress
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
function buildApiRequestApprovalTypedData(params) {
|
|
420
|
+
return {
|
|
421
|
+
domain: buildElgoraEip712Domain({
|
|
422
|
+
chainId: params.chainId,
|
|
423
|
+
hubAddress: params.hubAddress
|
|
424
|
+
}),
|
|
425
|
+
types: API_REQUEST_APPROVAL_TYPES,
|
|
426
|
+
primaryType: API_REQUEST_APPROVAL_PRIMARY_TYPE,
|
|
427
|
+
message: params.message
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
function endpointIdFor(input) {
|
|
431
|
+
return `${input.method.toUpperCase()} ${input.path}`;
|
|
432
|
+
}
|
|
433
|
+
function audienceFor(host) {
|
|
434
|
+
return host.toLowerCase();
|
|
435
|
+
}
|
|
436
|
+
function queryFor(query) {
|
|
437
|
+
return new URLSearchParams(query).toString();
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// ../../packages/core/src/auth/readiness-signoff.ts
|
|
441
|
+
var READINESS_APPROVAL_VALIDITY_SECONDS = 7 * 24 * 60 * 60;
|
|
442
|
+
var bytes32Schema = z2.string().refine(isHexBytes32).transform((value) => value);
|
|
443
|
+
var timestampSchema = z2.number().int().nonnegative().max(9999999999);
|
|
444
|
+
var readinessSignoffMessageSchema = z2.object({
|
|
445
|
+
audience: z2.string().min(1).max(512),
|
|
446
|
+
spec_commitment: bytes32Schema,
|
|
447
|
+
reviewer_hash: bytes32Schema,
|
|
448
|
+
model: z2.string().min(1).max(256),
|
|
449
|
+
issued_at: timestampSchema,
|
|
450
|
+
expires_at: timestampSchema
|
|
451
|
+
}).strict();
|
|
452
|
+
var signatureSchema = z2.string().refine((value) => isHex2(value) && size2(value) === 65).transform((value) => value);
|
|
453
|
+
var readinessSignoffSchema = readinessSignoffMessageSchema.extend({ signature: signatureSchema }).refine((signoff) => signoff.expires_at > signoff.issued_at, {
|
|
454
|
+
path: ["expires_at"],
|
|
455
|
+
message: "Must expire after issuance"
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
// ../../packages/core/src/bounty-publication-response.ts
|
|
459
|
+
var addressSchema = z3.string().refine(isHexAddress, "Must be a 20-byte EVM address").transform((value) => value);
|
|
460
|
+
var bytes32Schema2 = z3.string().refine(isHexBytes32, "Must be a bytes32 hex string").transform((value) => value);
|
|
461
|
+
var hexBytesSchema = z3.string().refine(isHex3, "Must be hex-encoded calldata").transform((value) => value);
|
|
462
|
+
var bountyChallengeContentRecordSchema = z3.object({
|
|
463
|
+
content_kind: z3.literal("bounty_challenge_spec"),
|
|
464
|
+
spec_commitment: bytes32Schema2,
|
|
465
|
+
byte_length: z3.number().int().positive(),
|
|
466
|
+
token_address: addressSchema,
|
|
467
|
+
created_at: z3.string().datetime({ offset: true })
|
|
468
|
+
}).strict();
|
|
469
|
+
var bountyPublicationResponseSchema = z3.object({
|
|
470
|
+
content_record: bountyChallengeContentRecordSchema,
|
|
471
|
+
create_bounty_transaction: z3.object({
|
|
472
|
+
chain_id: z3.number().int().positive(),
|
|
402
473
|
to: addressSchema,
|
|
403
|
-
value:
|
|
474
|
+
value: z3.literal("0"),
|
|
404
475
|
data: hexBytesSchema,
|
|
405
|
-
function_name:
|
|
406
|
-
args:
|
|
407
|
-
spec_commitment:
|
|
408
|
-
escrow_amount:
|
|
409
|
-
submission_deadline:
|
|
476
|
+
function_name: z3.literal("create_bounty"),
|
|
477
|
+
args: z3.object({
|
|
478
|
+
spec_commitment: bytes32Schema2,
|
|
479
|
+
escrow_amount: z3.string().refine(isPositiveInteger),
|
|
480
|
+
submission_deadline: z3.number().int().positive()
|
|
410
481
|
}).strict()
|
|
411
482
|
}).strict(),
|
|
412
|
-
protocol_fee_policy:
|
|
483
|
+
protocol_fee_policy: z3.object({
|
|
413
484
|
treasury_recipient: addressSchema,
|
|
414
|
-
treasury_fee_bps:
|
|
485
|
+
treasury_fee_bps: z3.number().int().min(0).max(1e4),
|
|
415
486
|
guardian_fee_recipient: addressSchema,
|
|
416
|
-
guardian_fee_bps:
|
|
487
|
+
guardian_fee_bps: z3.number().int().min(0).max(1e4)
|
|
417
488
|
}).strict()
|
|
418
489
|
}).strict().superRefine((response, context) => {
|
|
419
490
|
if (response.content_record.spec_commitment !== response.create_bounty_transaction.args.spec_commitment) {
|
|
@@ -424,6 +495,47 @@ var bountyPublicationResponseSchema = z2.object({
|
|
|
424
495
|
});
|
|
425
496
|
}
|
|
426
497
|
});
|
|
498
|
+
var priorIssueSchema = z3.object({
|
|
499
|
+
issue_index: z3.number().int().nonnegative(),
|
|
500
|
+
message: z3.string().trim().min(1).max(1500)
|
|
501
|
+
}).strict();
|
|
502
|
+
var priorIssueStatusSchema = priorIssueSchema.extend({
|
|
503
|
+
status: z3.enum(["resolved", "open"])
|
|
504
|
+
}).strict();
|
|
505
|
+
var readinessFindingSchema = z3.object({
|
|
506
|
+
path: z3.string().trim().min(1).max(120),
|
|
507
|
+
message: z3.string().trim().min(1).max(1500),
|
|
508
|
+
code: z3.string().min(1).optional(),
|
|
509
|
+
anchor: z3.string().trim().min(1).max(120).optional(),
|
|
510
|
+
hazard: z3.boolean().optional()
|
|
511
|
+
});
|
|
512
|
+
var MAX_READINESS_FINDINGS = 20;
|
|
513
|
+
var bountyReviewResponseSchema = z3.object({
|
|
514
|
+
content_record: bountyChallengeContentRecordSchema,
|
|
515
|
+
readiness: z3.object({
|
|
516
|
+
decision: z3.literal("ready"),
|
|
517
|
+
signoff: readinessSignoffSchema,
|
|
518
|
+
// The dissenting pass's findings on a ready check; never blocking.
|
|
519
|
+
// Optional because servers before three-pass review do not send it.
|
|
520
|
+
warnings: z3.array(readinessFindingSchema).max(MAX_READINESS_FINDINGS).optional(),
|
|
521
|
+
prior_issues_resolved: z3.array(priorIssueSchema),
|
|
522
|
+
prior_issues_open: z3.array(priorIssueSchema)
|
|
523
|
+
})
|
|
524
|
+
}).superRefine((response, context) => {
|
|
525
|
+
if (response.readiness.signoff.spec_commitment.toLowerCase() !== response.content_record.spec_commitment.toLowerCase()) {
|
|
526
|
+
context.addIssue({
|
|
527
|
+
code: "custom",
|
|
528
|
+
path: ["readiness", "signoff", "spec_commitment"],
|
|
529
|
+
message: "Must match content_record.spec_commitment"
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
});
|
|
533
|
+
var readinessSignerResponseSchema = z3.object({
|
|
534
|
+
signer_address: addressSchema,
|
|
535
|
+
reviewer_hash: bytes32Schema2,
|
|
536
|
+
configured_model: z3.string().min(1),
|
|
537
|
+
audience: z3.string().min(1)
|
|
538
|
+
}).strict();
|
|
427
539
|
|
|
428
540
|
// ../../packages/core/src/chain-registry.ts
|
|
429
541
|
import { base, baseSepolia, foundry } from "viem/chains";
|
|
@@ -447,7 +559,7 @@ var FOUNDRY_CHAIN_ID = foundry.id;
|
|
|
447
559
|
import { Aes256Gcm, CipherSuite, HkdfSha256 } from "@hpke/core";
|
|
448
560
|
import { DhkemX25519HkdfSha256 } from "@hpke/dhkem-x25519";
|
|
449
561
|
import { concatBytes, keccak256 as keccak2562, toBytes as toBytes2 } from "viem";
|
|
450
|
-
import { z as
|
|
562
|
+
import { z as z4 } from "zod";
|
|
451
563
|
|
|
452
564
|
// ../../packages/core/src/base64.ts
|
|
453
565
|
var BASE64_ENCODE_CHUNK_BYTES = 3 * 16384;
|
|
@@ -533,42 +645,42 @@ var BASE64URL_RE = /^[A-Za-z0-9_-]+$/;
|
|
|
533
645
|
var SOLVER_SUBMISSION_NAME_RE = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
534
646
|
var MEDIA_TYPE_RE = /^[a-z0-9][a-z0-9!#$&^_.+-]*\/[a-z0-9][a-z0-9!#$&^_.+-]*$/;
|
|
535
647
|
var KEY_ID_RE = /^[A-Za-z0-9][ -~]*$/;
|
|
536
|
-
var base64UrlSchema =
|
|
537
|
-
var lowerAddressSchema =
|
|
538
|
-
var
|
|
539
|
-
var sha256HexSchema =
|
|
540
|
-
var keyIdSchema =
|
|
541
|
-
var artifactNameSchema =
|
|
648
|
+
var base64UrlSchema = z4.string().regex(BASE64URL_RE);
|
|
649
|
+
var lowerAddressSchema = z4.string().refine(isLowercaseHexAddress);
|
|
650
|
+
var bytes32Schema3 = z4.string().refine(isLowercaseBytes32);
|
|
651
|
+
var sha256HexSchema = z4.string().refine(isSha256Hex);
|
|
652
|
+
var keyIdSchema = z4.string().min(1).max(128).regex(KEY_ID_RE);
|
|
653
|
+
var artifactNameSchema = z4.string().max(
|
|
542
654
|
MAX_SOLVER_SUBMISSION_NAME_CHARACTERS,
|
|
543
655
|
`Artifact filename exceeds ${MAX_SOLVER_SUBMISSION_NAME_CHARACTERS} ASCII characters (including extension). Solvers may shorten it only if the published challenge permits, before the deadline.`
|
|
544
656
|
).regex(SOLVER_SUBMISSION_NAME_RE);
|
|
545
|
-
var mediaTypeSchema =
|
|
546
|
-
var bountyIdSchema =
|
|
547
|
-
var chainIdSchema =
|
|
548
|
-
var privateArtifactContextSchema =
|
|
549
|
-
type:
|
|
657
|
+
var mediaTypeSchema = z4.string().regex(MEDIA_TYPE_RE);
|
|
658
|
+
var bountyIdSchema = z4.string().refine(isBountyId);
|
|
659
|
+
var chainIdSchema = z4.number().int().positive().lte(Number.MAX_SAFE_INTEGER);
|
|
660
|
+
var privateArtifactContextSchema = z4.strictObject({
|
|
661
|
+
type: z4.literal("solver_submission"),
|
|
550
662
|
chain_id: chainIdSchema,
|
|
551
663
|
hub_address: lowerAddressSchema,
|
|
552
664
|
bounty_id: bountyIdSchema,
|
|
553
665
|
actor_address: lowerAddressSchema
|
|
554
666
|
});
|
|
555
|
-
var guardianRecipientSchema =
|
|
667
|
+
var guardianRecipientSchema = z4.strictObject({
|
|
556
668
|
key_id: keyIdSchema,
|
|
557
|
-
suite:
|
|
669
|
+
suite: z4.literal(PRIVATE_ARTIFACT_HPKE_SUITE),
|
|
558
670
|
public_key: base64UrlSchema.length(
|
|
559
671
|
43,
|
|
560
672
|
"public_key must encode a 32-byte X25519 public key"
|
|
561
673
|
)
|
|
562
674
|
});
|
|
563
|
-
var guardianRecipientPrivateKeySchema =
|
|
675
|
+
var guardianRecipientPrivateKeySchema = z4.strictObject({
|
|
564
676
|
key_id: keyIdSchema,
|
|
565
|
-
suite:
|
|
677
|
+
suite: z4.literal(PRIVATE_ARTIFACT_HPKE_SUITE),
|
|
566
678
|
private_key: base64UrlSchema.length(
|
|
567
679
|
43,
|
|
568
680
|
"private_key must encode a 32-byte X25519 private key"
|
|
569
681
|
)
|
|
570
682
|
});
|
|
571
|
-
var guardianRecipientsSchema =
|
|
683
|
+
var guardianRecipientsSchema = z4.array(guardianRecipientSchema).min(1).superRefine((recipients, ctx) => {
|
|
572
684
|
const seen = /* @__PURE__ */ new Set();
|
|
573
685
|
for (const recipient of recipients) {
|
|
574
686
|
if (seen.has(recipient.key_id)) {
|
|
@@ -581,24 +693,24 @@ var guardianRecipientsSchema = z3.array(guardianRecipientSchema).min(1).superRef
|
|
|
581
693
|
seen.add(recipient.key_id);
|
|
582
694
|
}
|
|
583
695
|
});
|
|
584
|
-
var guardianRecipientPrivateKeysSchema =
|
|
585
|
-
var artifactManifestEntrySchema =
|
|
696
|
+
var guardianRecipientPrivateKeysSchema = z4.array(guardianRecipientPrivateKeySchema).min(1);
|
|
697
|
+
var artifactManifestEntrySchema = z4.strictObject({
|
|
586
698
|
name: artifactNameSchema,
|
|
587
699
|
media_type: mediaTypeSchema,
|
|
588
|
-
size_bytes:
|
|
700
|
+
size_bytes: z4.number().int().nonnegative().lte(Number.MAX_SAFE_INTEGER),
|
|
589
701
|
sha256: sha256HexSchema
|
|
590
702
|
});
|
|
591
|
-
var privateArtifactPublicManifestSchema =
|
|
592
|
-
kind:
|
|
703
|
+
var privateArtifactPublicManifestSchema = z4.strictObject({
|
|
704
|
+
kind: z4.literal(PRIVATE_ARTIFACT_PUBLIC_MANIFEST_KIND),
|
|
593
705
|
context: privateArtifactContextSchema
|
|
594
706
|
});
|
|
595
707
|
var encryptedBundleArtifactSchema = artifactManifestEntrySchema.extend({
|
|
596
708
|
bytes: base64UrlSchema
|
|
597
709
|
});
|
|
598
|
-
var privateArtifactEncryptedBundleSchema =
|
|
599
|
-
kind:
|
|
710
|
+
var privateArtifactEncryptedBundleSchema = z4.strictObject({
|
|
711
|
+
kind: z4.literal(PRIVATE_ARTIFACT_ENCRYPTED_BUNDLE_KIND),
|
|
600
712
|
context: privateArtifactContextSchema,
|
|
601
|
-
artifacts:
|
|
713
|
+
artifacts: z4.array(encryptedBundleArtifactSchema).min(1).max(
|
|
602
714
|
MAX_SOLVER_SUBMISSION_FILES,
|
|
603
715
|
`Submission exceeds the maximum of ${MAX_SOLVER_SUBMISSION_FILES} files.`
|
|
604
716
|
).refine(
|
|
@@ -606,33 +718,33 @@ var privateArtifactEncryptedBundleSchema = z3.strictObject({
|
|
|
606
718
|
"artifact names must be unique case-insensitively"
|
|
607
719
|
)
|
|
608
720
|
});
|
|
609
|
-
var privateArtifactRevealPolicySchema =
|
|
610
|
-
kind:
|
|
611
|
-
network:
|
|
612
|
-
chain_hash:
|
|
613
|
-
round:
|
|
614
|
-
not_before:
|
|
721
|
+
var privateArtifactRevealPolicySchema = z4.strictObject({
|
|
722
|
+
kind: z4.literal(PRIVATE_ARTIFACT_REVEAL_POLICY_KIND),
|
|
723
|
+
network: z4.string().min(1),
|
|
724
|
+
chain_hash: z4.string().min(1),
|
|
725
|
+
round: z4.string().refine(isPositiveInteger),
|
|
726
|
+
not_before: z4.number().int().nonnegative().lte(Number.MAX_SAFE_INTEGER)
|
|
615
727
|
});
|
|
616
|
-
var wrappedRecipientKeySchema =
|
|
728
|
+
var wrappedRecipientKeySchema = z4.strictObject({
|
|
617
729
|
key_id: keyIdSchema,
|
|
618
|
-
suite:
|
|
730
|
+
suite: z4.literal(PRIVATE_ARTIFACT_HPKE_SUITE),
|
|
619
731
|
enc: base64UrlSchema,
|
|
620
732
|
ciphertext: base64UrlSchema
|
|
621
733
|
});
|
|
622
|
-
var wrappedKeyBagSchema =
|
|
623
|
-
kind:
|
|
624
|
-
keys:
|
|
734
|
+
var wrappedKeyBagSchema = z4.strictObject({
|
|
735
|
+
kind: z4.literal(PRIVATE_ARTIFACT_WRAPPED_KEY_BAG_KIND),
|
|
736
|
+
keys: z4.array(wrappedRecipientKeySchema).min(1)
|
|
625
737
|
});
|
|
626
|
-
var privateArtifactEnvelopeSchema =
|
|
627
|
-
kind:
|
|
628
|
-
alg:
|
|
738
|
+
var privateArtifactEnvelopeSchema = z4.strictObject({
|
|
739
|
+
kind: z4.literal(PRIVATE_ARTIFACT_ENVELOPE_KIND),
|
|
740
|
+
alg: z4.literal(SUBMISSION_ENCRYPTION_TYPE),
|
|
629
741
|
context: privateArtifactContextSchema,
|
|
630
742
|
public_manifest: privateArtifactPublicManifestSchema,
|
|
631
743
|
public_manifest_sha256: sha256HexSchema,
|
|
632
744
|
encrypted_bundle_sha256: sha256HexSchema,
|
|
633
745
|
ciphertext_sha256: sha256HexSchema,
|
|
634
746
|
guardian_recipients: guardianRecipientsSchema,
|
|
635
|
-
guardian_recipients_commitment:
|
|
747
|
+
guardian_recipients_commitment: bytes32Schema3,
|
|
636
748
|
reveal_policy: privateArtifactRevealPolicySchema,
|
|
637
749
|
envelope_nonce: base64UrlSchema.length(
|
|
638
750
|
22,
|
|
@@ -640,7 +752,7 @@ var privateArtifactEnvelopeSchema = z3.strictObject({
|
|
|
640
752
|
),
|
|
641
753
|
iv: base64UrlSchema.length(16, "iv must encode 12 bytes"),
|
|
642
754
|
wrapped_key_bag: base64UrlSchema,
|
|
643
|
-
ciphertext_locator:
|
|
755
|
+
ciphertext_locator: z4.string().min(1)
|
|
644
756
|
});
|
|
645
757
|
function parsePrivateArtifactEnvelope(input) {
|
|
646
758
|
return privateArtifactEnvelopeSchema.parse(input);
|
|
@@ -698,11 +810,11 @@ var x25519PrivateKeySchema = base64UrlSchema.length(
|
|
|
698
810
|
43,
|
|
699
811
|
"must encode a 32-byte X25519 private key"
|
|
700
812
|
);
|
|
701
|
-
var winningSolutionDeliveryContextSchema =
|
|
813
|
+
var winningSolutionDeliveryContextSchema = z4.strictObject({
|
|
702
814
|
chain_id: chainIdSchema,
|
|
703
815
|
hub_address: lowerAddressSchema,
|
|
704
816
|
bounty_id: bountyIdSchema,
|
|
705
|
-
submission_commitment:
|
|
817
|
+
submission_commitment: bytes32Schema3
|
|
706
818
|
});
|
|
707
819
|
async function generateX25519KeyPair(input) {
|
|
708
820
|
const suite = createHpkeSuite();
|
|
@@ -779,7 +891,7 @@ function buildWinningSolutionDeliveryInfo(contextCommitment) {
|
|
|
779
891
|
var GUARDIAN_ROSTER_KEY_PROOF_INFO = "elgora/guardian-roster-key-proof/hpke-fixture/v0";
|
|
780
892
|
var GUARDIAN_ROSTER_KEY_PROOF_MESSAGE_TYPE = "elgora_guardian_roster_key_proof_v0";
|
|
781
893
|
var GUARDIAN_ROSTER_KEY_PROOF_FIXTURE_BYTES = 32;
|
|
782
|
-
var guardianRosterKeyProofContextSchema =
|
|
894
|
+
var guardianRosterKeyProofContextSchema = z4.strictObject({
|
|
783
895
|
chain_id: chainIdSchema,
|
|
784
896
|
hub_address: lowerAddressSchema,
|
|
785
897
|
proposed_account: lowerAddressSchema,
|
|
@@ -1107,7 +1219,7 @@ async function wrapAesKeyForRecipients(input) {
|
|
|
1107
1219
|
}
|
|
1108
1220
|
async function openAesKeyForRecipient(input) {
|
|
1109
1221
|
const suite = createHpkeSuite();
|
|
1110
|
-
const wrappedKeys =
|
|
1222
|
+
const wrappedKeys = z4.array(wrappedRecipientKeySchema).parse(input.wrappedKeys);
|
|
1111
1223
|
const privateKeys = guardianRecipientPrivateKeysSchema.parse(
|
|
1112
1224
|
input.privateKeys
|
|
1113
1225
|
);
|
|
@@ -3818,7 +3930,7 @@ function settlementAmounts(escrowAmount, treasuryFeeBps, guardianFeeBps) {
|
|
|
3818
3930
|
import { zeroAddress } from "viem";
|
|
3819
3931
|
|
|
3820
3932
|
// ../../packages/core/src/api/bounty-preparation.ts
|
|
3821
|
-
import { ZodError, z as
|
|
3933
|
+
import { ZodError, z as z5 } from "zod";
|
|
3822
3934
|
|
|
3823
3935
|
// ../../packages/core/src/submission-timelock.ts
|
|
3824
3936
|
import {
|
|
@@ -4079,7 +4191,7 @@ import {
|
|
|
4079
4191
|
getAbiItem as getAbiItem2,
|
|
4080
4192
|
parseAbi,
|
|
4081
4193
|
parseSignature,
|
|
4082
|
-
recoverTypedDataAddress
|
|
4194
|
+
recoverTypedDataAddress as recoverTypedDataAddress2
|
|
4083
4195
|
} from "viem";
|
|
4084
4196
|
var ELGORA_HUB_ERRORS = ELGORA_HUB_ABI.filter(
|
|
4085
4197
|
(item) => item.type === "error"
|
|
@@ -4236,7 +4348,7 @@ async function prepareAuthorizedCreateBountyTransaction(input) {
|
|
|
4236
4348
|
if (unsupported) return null;
|
|
4237
4349
|
throw error;
|
|
4238
4350
|
}
|
|
4239
|
-
if ((await
|
|
4351
|
+
if ((await recoverTypedDataAddress2({ ...authorization, signature })).toLowerCase() !== poster.toLowerCase()) {
|
|
4240
4352
|
throw new Error("USDC authorization was not signed by the funding Poster.");
|
|
4241
4353
|
}
|
|
4242
4354
|
const { r, s, yParity } = parseSignature(signature);
|
|
@@ -4312,14 +4424,14 @@ var BoundaryValidationError = class extends Error {
|
|
|
4312
4424
|
this.issues = issues;
|
|
4313
4425
|
}
|
|
4314
4426
|
};
|
|
4315
|
-
var artifactUploadUrlRequestSchema =
|
|
4316
|
-
ciphertext_sha256:
|
|
4317
|
-
ciphertext_byte_length:
|
|
4427
|
+
var artifactUploadUrlRequestSchema = z5.object({
|
|
4428
|
+
ciphertext_sha256: z5.string().refine(isSha256Hex),
|
|
4429
|
+
ciphertext_byte_length: z5.number().int().positive().max(MAX_SOLVER_SUBMISSION_CIPHERTEXT_BYTES)
|
|
4318
4430
|
}).strict();
|
|
4319
4431
|
|
|
4320
4432
|
// ../../packages/core/src/api/config.ts
|
|
4321
4433
|
import { createHash } from "crypto";
|
|
4322
|
-
import { z as
|
|
4434
|
+
import { z as z6 } from "zod";
|
|
4323
4435
|
function withDeploymentEnvDefaults(env) {
|
|
4324
4436
|
const merged = { ...env };
|
|
4325
4437
|
const setIfBlank = (key, value) => {
|
|
@@ -4340,11 +4452,11 @@ function withDeploymentEnvDefaults(env) {
|
|
|
4340
4452
|
setIfBlank("ELGORA_SUBGRAPH_ENDPOINT", deployment?.ELGORA_SUBGRAPH_ENDPOINT);
|
|
4341
4453
|
return merged;
|
|
4342
4454
|
}
|
|
4343
|
-
var chainIdField =
|
|
4455
|
+
var chainIdField = z6.coerce.number().int().positive().refine((chainId) => SUPPORTED_CHAINS[chainId] !== void 0, {
|
|
4344
4456
|
message: `ELGORA_CHAIN_ID must be a supported chain: ${Object.keys(SUPPORTED_CHAINS).join(", ")}`
|
|
4345
4457
|
});
|
|
4346
|
-
var hubAddressField =
|
|
4347
|
-
var publicDeploymentEnvSchema =
|
|
4458
|
+
var hubAddressField = z6.string().refine(isHexAddress, "ELGORA_HUB_ADDRESS must be a 20-byte EVM address").transform((value) => value.toLowerCase());
|
|
4459
|
+
var publicDeploymentEnvSchema = z6.object({
|
|
4348
4460
|
ELGORA_CHAIN_ID: chainIdField,
|
|
4349
4461
|
ELGORA_HUB_ADDRESS: hubAddressField
|
|
4350
4462
|
});
|
|
@@ -4360,40 +4472,50 @@ function loadPublicDeploymentConfig(env = process.env) {
|
|
|
4360
4472
|
var envShape = {
|
|
4361
4473
|
ELGORA_CHAIN_ID: chainIdField,
|
|
4362
4474
|
ELGORA_HUB_ADDRESS: hubAddressField,
|
|
4363
|
-
ELGORA_ESCROW_TOKEN_ADDRESS:
|
|
4475
|
+
ELGORA_ESCROW_TOKEN_ADDRESS: z6.string().refine(
|
|
4364
4476
|
isHexAddress,
|
|
4365
4477
|
"ELGORA_ESCROW_TOKEN_ADDRESS must be a 20-byte EVM address"
|
|
4366
4478
|
).transform((value) => value.toLowerCase()),
|
|
4367
|
-
ELGORA_TIMELOCK_REVEAL_DELAY_SECONDS:
|
|
4368
|
-
ELGORA_RPC_URL:
|
|
4479
|
+
ELGORA_TIMELOCK_REVEAL_DELAY_SECONDS: z6.coerce.number().int().nonnegative().default(DEFAULT_TIMELOCK_REVEAL_DELAY_SECONDS),
|
|
4480
|
+
ELGORA_RPC_URL: z6.string().min(1, "ELGORA_RPC_URL is required"),
|
|
4369
4481
|
/**
|
|
4370
4482
|
* Only consulted for a chain with no recorded deployment — a local anvil
|
|
4371
4483
|
* stack, whose addresses change on every deploy. A recorded deployment's
|
|
4372
4484
|
* scheme always wins, because settlement validation compares against it.
|
|
4373
4485
|
*/
|
|
4374
|
-
ELGORA_PAYOUT_SCHEME_ADDRESS:
|
|
4486
|
+
ELGORA_PAYOUT_SCHEME_ADDRESS: z6.string().refine(
|
|
4375
4487
|
isHexAddress,
|
|
4376
4488
|
"ELGORA_PAYOUT_SCHEME_ADDRESS must be a 20-byte EVM address"
|
|
4377
4489
|
).transform((value) => value.toLowerCase()).optional(),
|
|
4378
|
-
ELGORA_DATABASE_URL:
|
|
4379
|
-
ELGORA_SUBGRAPH_ENDPOINT:
|
|
4380
|
-
ELGORA_ARTIFACT_STORAGE_ENDPOINT:
|
|
4381
|
-
ELGORA_ARTIFACT_STORAGE_REGION:
|
|
4382
|
-
ELGORA_ARTIFACT_STORAGE_BUCKET:
|
|
4383
|
-
ELGORA_ARTIFACT_STORAGE_ACCESS_KEY_ID:
|
|
4384
|
-
ELGORA_ARTIFACT_STORAGE_SECRET_ACCESS_KEY:
|
|
4385
|
-
ELGORA_DELIVERY_PUBLIC_KEY:
|
|
4386
|
-
ELGORA_DELIVERY_PRIVATE_KEY:
|
|
4490
|
+
ELGORA_DATABASE_URL: z6.string().min(1, "ELGORA_DATABASE_URL is required"),
|
|
4491
|
+
ELGORA_SUBGRAPH_ENDPOINT: z6.string().min(1, "ELGORA_SUBGRAPH_ENDPOINT is required"),
|
|
4492
|
+
ELGORA_ARTIFACT_STORAGE_ENDPOINT: z6.string().min(1, "ELGORA_ARTIFACT_STORAGE_ENDPOINT is required"),
|
|
4493
|
+
ELGORA_ARTIFACT_STORAGE_REGION: z6.string().min(1, "ELGORA_ARTIFACT_STORAGE_REGION is required"),
|
|
4494
|
+
ELGORA_ARTIFACT_STORAGE_BUCKET: z6.string().min(1, "ELGORA_ARTIFACT_STORAGE_BUCKET is required"),
|
|
4495
|
+
ELGORA_ARTIFACT_STORAGE_ACCESS_KEY_ID: z6.string().min(1, "ELGORA_ARTIFACT_STORAGE_ACCESS_KEY_ID is required"),
|
|
4496
|
+
ELGORA_ARTIFACT_STORAGE_SECRET_ACCESS_KEY: z6.string().min(1, "ELGORA_ARTIFACT_STORAGE_SECRET_ACCESS_KEY is required"),
|
|
4497
|
+
ELGORA_DELIVERY_PUBLIC_KEY: z6.string().min(1, "ELGORA_DELIVERY_PUBLIC_KEY is required"),
|
|
4498
|
+
ELGORA_DELIVERY_PRIVATE_KEY: z6.string().min(1, "ELGORA_DELIVERY_PRIVATE_KEY is required")
|
|
4387
4499
|
};
|
|
4500
|
+
var readinessAudienceSchema = z6.string().trim().toLowerCase().min(1).max(512).refine((host) => {
|
|
4501
|
+
try {
|
|
4502
|
+
const url = new URL(`https://${host}`);
|
|
4503
|
+
return url.host === host && url.pathname === "/" && !url.username && !url.password && !url.search && !url.hash;
|
|
4504
|
+
} catch {
|
|
4505
|
+
return false;
|
|
4506
|
+
}
|
|
4507
|
+
}, "Must be a canonical hostname with optional port, without a URL path");
|
|
4388
4508
|
var publicationEnvShape = {
|
|
4389
4509
|
ELGORA_CHAIN_ID: envShape.ELGORA_CHAIN_ID,
|
|
4390
4510
|
ELGORA_HUB_ADDRESS: envShape.ELGORA_HUB_ADDRESS,
|
|
4391
4511
|
ELGORA_ESCROW_TOKEN_ADDRESS: envShape.ELGORA_ESCROW_TOKEN_ADDRESS,
|
|
4392
4512
|
ELGORA_DATABASE_URL: envShape.ELGORA_DATABASE_URL,
|
|
4393
|
-
ELGORA_SUBGRAPH_ENDPOINT: envShape.ELGORA_SUBGRAPH_ENDPOINT
|
|
4513
|
+
ELGORA_SUBGRAPH_ENDPOINT: envShape.ELGORA_SUBGRAPH_ENDPOINT,
|
|
4514
|
+
ELGORA_PUBLICATION_REVIEW_ENABLED: z6.string().trim().toLowerCase().pipe(z6.enum(["true", "false"])).default("true").transform((value) => value === "true"),
|
|
4515
|
+
ELGORA_READINESS_TIMEOUT_MS: z6.coerce.number().int().min(1).max(12e4).default(12e4)
|
|
4394
4516
|
};
|
|
4395
|
-
var envSchema =
|
|
4396
|
-
var bountyPublicationEnvSchema =
|
|
4517
|
+
var envSchema = z6.object(envShape);
|
|
4518
|
+
var bountyPublicationEnvSchema = z6.object(publicationEnvShape);
|
|
4397
4519
|
|
|
4398
4520
|
// ../../packages/core/src/api/elgora-hub-error-catalog.ts
|
|
4399
4521
|
import { decodeErrorResult } from "viem";
|
|
@@ -4407,55 +4529,12 @@ var ELGORA_HUB_FEE_POLICY_ABI = [
|
|
|
4407
4529
|
getAbiItem3({ abi: ELGORA_HUB_ABI, name: "guardianFeeBps" })
|
|
4408
4530
|
];
|
|
4409
4531
|
|
|
4410
|
-
// ../../packages/core/src/api/orchestrator-readiness.ts
|
|
4411
|
-
import { z as z6 } from "zod";
|
|
4412
|
-
var MAX_ORCHESTRATOR_ISSUES = 20;
|
|
4413
|
-
var readinessIssueSchema = z6.object({
|
|
4414
|
-
path: z6.string().trim().min(1).max(120),
|
|
4415
|
-
message: z6.string().trim().min(1).max(1500),
|
|
4416
|
-
code: z6.enum([
|
|
4417
|
-
"acceptance_undecidable",
|
|
4418
|
-
"winner_unresolved",
|
|
4419
|
-
"source_unidentified",
|
|
4420
|
-
"domain_underspecified",
|
|
4421
|
-
"platform_conflict",
|
|
4422
|
-
"operative_instruction",
|
|
4423
|
-
"placeholder_unreplaced",
|
|
4424
|
-
"unsafe_content"
|
|
4425
|
-
]),
|
|
4426
|
-
anchor: z6.string().trim().min(1).max(120),
|
|
4427
|
-
hazard: z6.boolean()
|
|
4428
|
-
}).strict();
|
|
4429
|
-
var readinessResponseSchema = z6.object({
|
|
4430
|
-
issues: z6.array(readinessIssueSchema).max(MAX_ORCHESTRATOR_ISSUES),
|
|
4431
|
-
judgeable: z6.boolean()
|
|
4432
|
-
}).strict();
|
|
4433
|
-
var READINESS_OUTPUT_JSON_SCHEMA = z6.toJSONSchema(readinessResponseSchema, {
|
|
4434
|
-
override: ({ jsonSchema }) => {
|
|
4435
|
-
delete jsonSchema.minLength;
|
|
4436
|
-
delete jsonSchema.maxLength;
|
|
4437
|
-
delete jsonSchema.maxItems;
|
|
4438
|
-
}
|
|
4439
|
-
});
|
|
4440
|
-
delete READINESS_OUTPUT_JSON_SCHEMA.$schema;
|
|
4441
|
-
var providerMessageSchema = z6.object({
|
|
4442
|
-
id: z6.string().optional(),
|
|
4443
|
-
choices: z6.array(
|
|
4444
|
-
z6.object({
|
|
4445
|
-
message: z6.object({
|
|
4446
|
-
content: z6.string().nullable().optional()
|
|
4447
|
-
}).passthrough(),
|
|
4448
|
-
finish_reason: z6.string().nullable().optional()
|
|
4449
|
-
}).passthrough()
|
|
4450
|
-
).min(1)
|
|
4451
|
-
}).passthrough();
|
|
4452
|
-
|
|
4453
4532
|
// ../../packages/core/src/api/solver-submission-responses.ts
|
|
4454
|
-
import { isHex as
|
|
4533
|
+
import { isHex as isHex4 } from "viem";
|
|
4455
4534
|
import { z as z7 } from "zod";
|
|
4456
4535
|
var hexAddressSchema = z7.string().refine(isHexAddress, "Must be a hex-encoded address");
|
|
4457
4536
|
var hexBytes32Schema = z7.string().refine(isHexBytes32, "Must be 32-byte hex");
|
|
4458
|
-
var hexDataSchema = z7.string().refine((value) =>
|
|
4537
|
+
var hexDataSchema = z7.string().refine((value) => isHex4(value), "Must be hex-encoded calldata");
|
|
4459
4538
|
var artifactUploadUrlResponseSchema = z7.object({
|
|
4460
4539
|
locator: z7.string().min(1),
|
|
4461
4540
|
upload_url: z7.string().min(1),
|
|
@@ -4609,7 +4688,7 @@ var FRONTMATTER_DELIMITER2 = "---";
|
|
|
4609
4688
|
var decimalSchema = z10.string().regex(/^[1-9][0-9]*$/, "Must be a positive integer").transform(Number).refine(Number.isSafeInteger, "Must be a safe integer");
|
|
4610
4689
|
var bountyIdSchema2 = z10.string().regex(/^(0|[1-9][0-9]*)$/, "Must be a non-negative integer");
|
|
4611
4690
|
var addressSchema2 = z10.string().refine(isHexAddress, "Must be a hex-encoded address").refine((value) => value === value.toLowerCase(), "Must use lowercase hex").transform((value) => value);
|
|
4612
|
-
var
|
|
4691
|
+
var bytes32Schema4 = z10.string().refine(isHexBytes32, "Must be 32-byte hex").refine((value) => value === value.toLowerCase(), "Must use lowercase hex").transform((value) => value);
|
|
4613
4692
|
var commonFields = {
|
|
4614
4693
|
format_version: z10.literal(WRITTEN_VERDICT_FORMAT_VERSION.toString()).transform(() => WRITTEN_VERDICT_FORMAT_VERSION),
|
|
4615
4694
|
chain_id: decimalSchema,
|
|
@@ -4625,7 +4704,7 @@ var writtenVerdictSchema = z10.discriminatedUnion("outcome", [
|
|
|
4625
4704
|
(value) => value !== zeroAddress2,
|
|
4626
4705
|
"Must not be the zero address"
|
|
4627
4706
|
),
|
|
4628
|
-
awarded_submission_commitment:
|
|
4707
|
+
awarded_submission_commitment: bytes32Schema4.refine(
|
|
4629
4708
|
(value) => value !== ZERO_BYTES32,
|
|
4630
4709
|
"Must not be zero bytes"
|
|
4631
4710
|
)
|
|
@@ -5115,6 +5194,9 @@ function defaultApiBaseUrl(env) {
|
|
|
5115
5194
|
|
|
5116
5195
|
// ../../packages/core/src/api-client.ts
|
|
5117
5196
|
var ApiRequestError = class extends Error {
|
|
5197
|
+
issues;
|
|
5198
|
+
priorIssuesResolved;
|
|
5199
|
+
priorIssuesOpen;
|
|
5118
5200
|
status;
|
|
5119
5201
|
code;
|
|
5120
5202
|
retryAfterMs;
|
|
@@ -5123,15 +5205,20 @@ var ApiRequestError = class extends Error {
|
|
|
5123
5205
|
`Request to ${input.url} failed with ${input.status}: ${formatApiError(input.body)}`
|
|
5124
5206
|
);
|
|
5125
5207
|
this.name = "ApiRequestError";
|
|
5208
|
+
this.issues = readApiErrorIssues(input.body);
|
|
5209
|
+
const error = input.body && typeof input.body === "object" && "error" in input.body ? input.body.error : void 0;
|
|
5210
|
+
const fields = error && typeof error === "object" ? error : {};
|
|
5211
|
+
this.priorIssuesResolved = priorIssueSchema.array().safeParse(fields.prior_issues_resolved).data ?? [];
|
|
5212
|
+
this.priorIssuesOpen = priorIssueSchema.array().safeParse(fields.prior_issues_open).data ?? [];
|
|
5126
5213
|
this.status = input.status;
|
|
5127
5214
|
this.code = readApiErrorCode(input.body);
|
|
5128
5215
|
this.retryAfterMs = input.retryAfterMs;
|
|
5129
5216
|
}
|
|
5130
5217
|
};
|
|
5131
|
-
async function postText(url, body, contentType, authorization) {
|
|
5218
|
+
async function postText(url, body, contentType, authorization, headers = {}) {
|
|
5132
5219
|
const response = await fetch(url, {
|
|
5133
5220
|
method: "POST",
|
|
5134
|
-
headers: { "content-type": contentType, authorization },
|
|
5221
|
+
headers: { ...headers, "content-type": contentType, authorization },
|
|
5135
5222
|
body
|
|
5136
5223
|
});
|
|
5137
5224
|
return parseJsonResponse(url, response);
|
|
@@ -5236,12 +5323,11 @@ function formatApiError(body) {
|
|
|
5236
5323
|
if (body && typeof body === "object" && "error" in body && body.error && typeof body.error === "object" && "message" in body.error) {
|
|
5237
5324
|
const apiError = body.error;
|
|
5238
5325
|
const parts = [String(apiError.message)];
|
|
5239
|
-
|
|
5240
|
-
|
|
5241
|
-
|
|
5242
|
-
|
|
5243
|
-
|
|
5244
|
-
}
|
|
5326
|
+
for (const issue of readApiErrorIssues(body)) {
|
|
5327
|
+
let line = `${issue.anchor || issue.path || "request"}: ${issue.message}`;
|
|
5328
|
+
if (issue.code) line += ` [${issue.code}]`;
|
|
5329
|
+
if (issue.hazard !== void 0) line += ` (hazard: ${issue.hazard})`;
|
|
5330
|
+
parts.push(line);
|
|
5245
5331
|
}
|
|
5246
5332
|
if (apiError.next_action !== void 0 && apiError.next_action !== null) {
|
|
5247
5333
|
parts.push(`next action: ${String(apiError.next_action)}`);
|
|
@@ -5264,6 +5350,13 @@ async function assertResponseOk(url, response) {
|
|
|
5264
5350
|
retryAfterMs: readRetryAfterMs(response)
|
|
5265
5351
|
});
|
|
5266
5352
|
}
|
|
5353
|
+
function readApiErrorIssues(body) {
|
|
5354
|
+
if (!body || typeof body !== "object" || !("error" in body) || !body.error || typeof body.error !== "object" || !("issues" in body.error) || !Array.isArray(body.error.issues))
|
|
5355
|
+
return [];
|
|
5356
|
+
return body.error.issues.filter(
|
|
5357
|
+
(issue) => issue && typeof issue === "object" && typeof issue.path === "string" && typeof issue.message === "string" && (issue.code === void 0 || typeof issue.code === "string") && (issue.anchor === void 0 || typeof issue.anchor === "string") && (issue.hazard === void 0 || typeof issue.hazard === "boolean")
|
|
5358
|
+
);
|
|
5359
|
+
}
|
|
5267
5360
|
function readApiErrorCode(body) {
|
|
5268
5361
|
if (!body || typeof body !== "object" || !("error" in body) || !body.error || typeof body.error !== "object" || !("code" in body.error) || typeof body.error.code !== "string") {
|
|
5269
5362
|
return void 0;
|
|
@@ -5285,7 +5378,7 @@ function toArrayBuffer(bytes) {
|
|
|
5285
5378
|
import { privateKeyToAccount as privateKeyToAccount2 } from "viem/accounts";
|
|
5286
5379
|
|
|
5287
5380
|
// ../../packages/core/src/auth/authorization-header.ts
|
|
5288
|
-
import { isAddress as isAddress3, isHex as
|
|
5381
|
+
import { isAddress as isAddress3, isHex as isHex5 } from "viem";
|
|
5289
5382
|
var ELGORA_APPROVAL_AUTH_SCHEME = "Elgora-Approval";
|
|
5290
5383
|
var FIELD_SEPARATOR = "~";
|
|
5291
5384
|
function encodeApiRequestApprovalHeader(fields) {
|
|
@@ -5298,59 +5391,27 @@ function encodeApiRequestApprovalHeader(fields) {
|
|
|
5298
5391
|
return `${ELGORA_APPROVAL_AUTH_SCHEME} ${btoa(payload)}`;
|
|
5299
5392
|
}
|
|
5300
5393
|
|
|
5301
|
-
// ../../packages/core/src/auth/
|
|
5302
|
-
var
|
|
5303
|
-
|
|
5304
|
-
|
|
5305
|
-
|
|
5306
|
-
|
|
5307
|
-
|
|
5308
|
-
{ name: "query", type: "string" },
|
|
5309
|
-
{ name: "blockNumber", type: "uint256" },
|
|
5310
|
-
{ name: "blockHash", type: "bytes32" }
|
|
5311
|
-
]
|
|
5312
|
-
};
|
|
5313
|
-
function buildElgoraEip712Domain(params) {
|
|
5314
|
-
return {
|
|
5315
|
-
name: "Elgora",
|
|
5316
|
-
version: "1",
|
|
5317
|
-
chainId: params.chainId,
|
|
5318
|
-
verifyingContract: params.hubAddress
|
|
5319
|
-
};
|
|
5320
|
-
}
|
|
5321
|
-
function buildApiRequestApprovalTypedData(params) {
|
|
5322
|
-
return {
|
|
5323
|
-
domain: buildElgoraEip712Domain({
|
|
5324
|
-
chainId: params.chainId,
|
|
5325
|
-
hubAddress: params.hubAddress
|
|
5326
|
-
}),
|
|
5327
|
-
types: API_REQUEST_APPROVAL_TYPES,
|
|
5328
|
-
primaryType: API_REQUEST_APPROVAL_PRIMARY_TYPE,
|
|
5329
|
-
message: params.message
|
|
5330
|
-
};
|
|
5331
|
-
}
|
|
5332
|
-
function endpointIdFor(input) {
|
|
5333
|
-
return `${input.method.toUpperCase()} ${input.path}`;
|
|
5334
|
-
}
|
|
5335
|
-
function audienceFor(host) {
|
|
5336
|
-
return host.toLowerCase();
|
|
5337
|
-
}
|
|
5338
|
-
function queryFor(query) {
|
|
5339
|
-
return new URLSearchParams(query).toString();
|
|
5394
|
+
// ../../packages/core/src/auth/readiness-signoff-header.ts
|
|
5395
|
+
var ELGORA_READINESS_SIGNOFF_HEADER = "Elgora-Readiness-Signoff";
|
|
5396
|
+
function encodeReadinessSignoffHeader(signoff) {
|
|
5397
|
+
const bytes = new TextEncoder().encode(
|
|
5398
|
+
JSON.stringify(readinessSignoffSchema.parse(signoff))
|
|
5399
|
+
);
|
|
5400
|
+
return btoa(String.fromCharCode(...bytes));
|
|
5340
5401
|
}
|
|
5341
5402
|
|
|
5342
5403
|
// ../../packages/core/src/auth/request-approval.ts
|
|
5343
5404
|
import {
|
|
5344
5405
|
hashTypedData,
|
|
5345
|
-
isAddressEqual as
|
|
5406
|
+
isAddressEqual as isAddressEqual3,
|
|
5346
5407
|
keccak256 as keccak2565,
|
|
5347
5408
|
toBytes as toBytes4
|
|
5348
5409
|
} from "viem";
|
|
5349
5410
|
|
|
5350
5411
|
// ../../packages/core/src/auth/signature.ts
|
|
5351
5412
|
import {
|
|
5352
|
-
isAddressEqual,
|
|
5353
|
-
recoverTypedDataAddress as
|
|
5413
|
+
isAddressEqual as isAddressEqual2,
|
|
5414
|
+
recoverTypedDataAddress as recoverTypedDataAddress3
|
|
5354
5415
|
} from "viem";
|
|
5355
5416
|
|
|
5356
5417
|
// ../../packages/core/src/auth/request-approval-header.ts
|
|
@@ -6011,9 +6072,10 @@ function createElgoraSubgraphClient(options) {
|
|
|
6011
6072
|
);
|
|
6012
6073
|
raw = await response.text();
|
|
6013
6074
|
} catch (cause) {
|
|
6075
|
+
const code = transportErrorCode(cause);
|
|
6014
6076
|
throw new SubgraphReadError(
|
|
6015
6077
|
"transport_failed",
|
|
6016
|
-
|
|
6078
|
+
`Subgraph request did not complete${code ? ` (${code})` : ""}`,
|
|
6017
6079
|
{ cause }
|
|
6018
6080
|
);
|
|
6019
6081
|
}
|
|
@@ -6166,6 +6228,17 @@ function createElgoraSubgraphClient(options) {
|
|
|
6166
6228
|
}
|
|
6167
6229
|
};
|
|
6168
6230
|
}
|
|
6231
|
+
function transportErrorCode(error, depth = 0) {
|
|
6232
|
+
if (depth > 4 || typeof error !== "object" || error === null)
|
|
6233
|
+
return void 0;
|
|
6234
|
+
const { code, cause, errors } = error;
|
|
6235
|
+
if (typeof code === "string" && /^[A-Z][A-Z0-9_]*$/.test(code)) return code;
|
|
6236
|
+
for (const inner of [cause, ...Array.isArray(errors) ? errors : []]) {
|
|
6237
|
+
const found = transportErrorCode(inner, depth + 1);
|
|
6238
|
+
if (found) return found;
|
|
6239
|
+
}
|
|
6240
|
+
return void 0;
|
|
6241
|
+
}
|
|
6169
6242
|
var defaultFetch = (endpoint, body) => fetch(endpoint, {
|
|
6170
6243
|
method: "POST",
|
|
6171
6244
|
headers: { "content-type": "application/json" },
|
|
@@ -7100,7 +7173,7 @@ function resolveChainId(selector) {
|
|
|
7100
7173
|
}
|
|
7101
7174
|
|
|
7102
7175
|
// src/version.ts
|
|
7103
|
-
var CLI_VERSION = true ? "
|
|
7176
|
+
var CLI_VERSION = true ? "9.1.0" : "0.0.0-dev";
|
|
7104
7177
|
var CLI_NODE_ENGINES = true ? ">=24 <25" : ">=24 <25";
|
|
7105
7178
|
|
|
7106
7179
|
// src/node-engines.ts
|
|
@@ -7307,26 +7380,99 @@ function required3(env, name) {
|
|
|
7307
7380
|
}
|
|
7308
7381
|
|
|
7309
7382
|
// src/publish-fund.ts
|
|
7310
|
-
import { readFile as
|
|
7311
|
-
import { text as readStdinText3 } from "stream/consumers";
|
|
7383
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
7312
7384
|
import {
|
|
7313
7385
|
decodeFunctionData,
|
|
7314
7386
|
parseAbi as parseAbi2,
|
|
7315
7387
|
parseEventLogs
|
|
7316
7388
|
} from "viem";
|
|
7317
7389
|
import { privateKeyToAccount as privateKeyToAccount8 } from "viem/accounts";
|
|
7318
|
-
|
|
7390
|
+
|
|
7391
|
+
// src/poster-request.ts
|
|
7392
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
7393
|
+
import { text as readStdinText3 } from "stream/consumers";
|
|
7394
|
+
function loadPosterConfig(env, apiBaseUrlOverride) {
|
|
7395
|
+
const defaults = withDeploymentDefaults(env);
|
|
7396
|
+
const clientConfig = loadClientDeploymentConfig(defaults, apiBaseUrlOverride);
|
|
7397
|
+
const rpcUrl = defaults.ELGORA_RPC_URL?.trim();
|
|
7398
|
+
if (!rpcUrl) throw new Error("ELGORA_RPC_URL is required");
|
|
7399
|
+
const privateKey = env.ELGORA_POSTER_PRIVATE_KEY?.trim();
|
|
7400
|
+
if (!privateKey || !isHexBytes32(privateKey)) {
|
|
7401
|
+
throw new Error(
|
|
7402
|
+
"ELGORA_POSTER_PRIVATE_KEY must be a 32-byte hex private key"
|
|
7403
|
+
);
|
|
7404
|
+
}
|
|
7405
|
+
return {
|
|
7406
|
+
...clientConfig,
|
|
7407
|
+
rpcUrl,
|
|
7408
|
+
posterPrivateKey: privateKey
|
|
7409
|
+
};
|
|
7410
|
+
}
|
|
7411
|
+
function takeFlag(argv, flag, usage) {
|
|
7412
|
+
const uses = argv.filter(
|
|
7413
|
+
(arg) => arg === flag || arg.startsWith(`${flag}=`)
|
|
7414
|
+
).length;
|
|
7415
|
+
const extracted = extractFlagValue(argv, flag);
|
|
7416
|
+
if (uses > 1 || uses === 1 && (!extracted.value || extracted.value.startsWith("--")))
|
|
7417
|
+
throw new Error(usage);
|
|
7418
|
+
return extracted;
|
|
7419
|
+
}
|
|
7420
|
+
async function readBountyChallengeMarkdown2(path5) {
|
|
7421
|
+
return path5 === "-" ? readStdinText3(process.stdin) : readFile4(path5, "utf8");
|
|
7422
|
+
}
|
|
7423
|
+
async function signPosterRequest(input) {
|
|
7424
|
+
return buildAuthorizationHeader({
|
|
7425
|
+
requestUrl: input.requestUrl.toString(),
|
|
7426
|
+
method: "POST",
|
|
7427
|
+
body: input.markdown,
|
|
7428
|
+
chainId: input.config.chainId,
|
|
7429
|
+
hubAddress: input.config.hubAddress,
|
|
7430
|
+
address: input.account.address,
|
|
7431
|
+
block: await fetchSignableBlock(input.publicClient),
|
|
7432
|
+
sign: (typedData) => input.account.signTypedData(typedData)
|
|
7433
|
+
});
|
|
7434
|
+
}
|
|
7435
|
+
|
|
7436
|
+
// src/publish-fund.ts
|
|
7437
|
+
var PUBLISH_FUND_USAGE = "Usage: elgora-cli poster:publish-fund <bounty_challenge_md_path|-> --signoff <file>";
|
|
7319
7438
|
var usdcAbi = parseAbi2([
|
|
7320
7439
|
"function approve(address spender,uint256 value) returns (bool)",
|
|
7321
7440
|
"function balanceOf(address account) view returns (uint256)"
|
|
7322
7441
|
]);
|
|
7323
7442
|
async function main9(env = process.env, argv = process.argv.slice(2)) {
|
|
7324
|
-
const { apiBaseUrl: apiBaseUrlOverride, argv:
|
|
7325
|
-
const
|
|
7326
|
-
|
|
7327
|
-
|
|
7443
|
+
const { apiBaseUrl: apiBaseUrlOverride, argv: afterApiBaseUrl } = extractApiBaseUrlFlag(argv);
|
|
7444
|
+
const { value: signoffPath, argv: remainingArgv } = takeFlag(
|
|
7445
|
+
afterApiBaseUrl,
|
|
7446
|
+
"--signoff",
|
|
7447
|
+
PUBLISH_FUND_USAGE
|
|
7328
7448
|
);
|
|
7329
|
-
|
|
7449
|
+
if (!signoffPath || remainingArgv.length !== 1 || !remainingArgv[0])
|
|
7450
|
+
throw new Error(PUBLISH_FUND_USAGE);
|
|
7451
|
+
const config = loadPosterConfig(env, apiBaseUrlOverride);
|
|
7452
|
+
const escrowTokenAddress = withDeploymentDefaults(env).ELGORA_ESCROW_TOKEN_ADDRESS?.trim();
|
|
7453
|
+
if (!escrowTokenAddress || !isHexAddress(escrowTokenAddress)) {
|
|
7454
|
+
throw new Error(
|
|
7455
|
+
"ELGORA_ESCROW_TOKEN_ADDRESS must be a 20-byte EVM address"
|
|
7456
|
+
);
|
|
7457
|
+
}
|
|
7458
|
+
const tokenAddress = escrowTokenAddress.toLowerCase();
|
|
7459
|
+
const bountyChallengeMarkdown = await readBountyChallengeMarkdown2(
|
|
7460
|
+
remainingArgv[0]
|
|
7461
|
+
);
|
|
7462
|
+
const localSpecCommitment = deriveBountyChallengeContentCommitment(
|
|
7463
|
+
bountyChallengeMarkdown
|
|
7464
|
+
);
|
|
7465
|
+
const signoff = readinessSignoffSchema.parse(
|
|
7466
|
+
JSON.parse(await readFile5(signoffPath, "utf8"))
|
|
7467
|
+
);
|
|
7468
|
+
if (signoff.spec_commitment.toLowerCase() !== localSpecCommitment) {
|
|
7469
|
+
throw new Error(
|
|
7470
|
+
"Readiness sign-off does not match the exact bounty_challenge.md bytes. Run poster:review again."
|
|
7471
|
+
);
|
|
7472
|
+
}
|
|
7473
|
+
if (signoff.expires_at <= Math.floor(Date.now() / 1e3)) {
|
|
7474
|
+
throw new Error("Readiness sign-off has expired. Run poster:review again.");
|
|
7475
|
+
}
|
|
7330
7476
|
const account = privateKeyToAccount8(config.posterPrivateKey);
|
|
7331
7477
|
const publicClient = createChainPublicClient(config.chainId, config.rpcUrl);
|
|
7332
7478
|
const walletClient = createChainWalletClient(
|
|
@@ -7340,31 +7486,25 @@ async function main9(env = process.env, argv = process.argv.slice(2)) {
|
|
|
7340
7486
|
config.apiBaseUrl
|
|
7341
7487
|
);
|
|
7342
7488
|
requestUrl.searchParams.set("poster_address", account.address);
|
|
7343
|
-
const
|
|
7344
|
-
|
|
7345
|
-
|
|
7346
|
-
|
|
7347
|
-
|
|
7348
|
-
|
|
7349
|
-
hubAddress: config.hubAddress,
|
|
7350
|
-
address: account.address,
|
|
7351
|
-
block,
|
|
7352
|
-
sign: (typedData) => account.signTypedData(typedData)
|
|
7489
|
+
const authorization = await signPosterRequest({
|
|
7490
|
+
requestUrl,
|
|
7491
|
+
markdown: bountyChallengeMarkdown,
|
|
7492
|
+
config,
|
|
7493
|
+
account,
|
|
7494
|
+
publicClient
|
|
7353
7495
|
});
|
|
7354
7496
|
const prepared = await requestPreparePublication({
|
|
7355
7497
|
requestUrl: requestUrl.toString(),
|
|
7356
7498
|
markdown: bountyChallengeMarkdown,
|
|
7357
|
-
authorization
|
|
7499
|
+
authorization,
|
|
7500
|
+
signoff: encodeReadinessSignoffHeader(signoff)
|
|
7358
7501
|
});
|
|
7359
|
-
const localSpecCommitment = deriveBountyChallengeContentCommitment(
|
|
7360
|
-
bountyChallengeMarkdown
|
|
7361
|
-
);
|
|
7362
7502
|
if (prepared.content_record.spec_commitment !== localSpecCommitment) {
|
|
7363
7503
|
throw new Error(
|
|
7364
7504
|
"Elgora API returned a spec_commitment that does not match the locally submitted bounty_challenge.md"
|
|
7365
7505
|
);
|
|
7366
7506
|
}
|
|
7367
|
-
if (prepared.create_bounty_transaction.chain_id !== config.chainId || prepared.create_bounty_transaction.to !== config.hubAddress || prepared.content_record.token_address !==
|
|
7507
|
+
if (prepared.create_bounty_transaction.chain_id !== config.chainId || prepared.create_bounty_transaction.to !== config.hubAddress || prepared.content_record.token_address !== tokenAddress) {
|
|
7368
7508
|
throw new Error(
|
|
7369
7509
|
"Elgora API returned a create_bounty_transaction that does not match the locally configured deployment (chain id, hub address, or escrow token)"
|
|
7370
7510
|
);
|
|
@@ -7386,7 +7526,7 @@ async function main9(env = process.env, argv = process.argv.slice(2)) {
|
|
|
7386
7526
|
const [ethBalance, usdcBalance] = await Promise.all([
|
|
7387
7527
|
publicClient.getBalance({ address: account.address }),
|
|
7388
7528
|
publicClient.readContract({
|
|
7389
|
-
address:
|
|
7529
|
+
address: tokenAddress,
|
|
7390
7530
|
abi: usdcAbi,
|
|
7391
7531
|
functionName: "balanceOf",
|
|
7392
7532
|
args: [account.address]
|
|
@@ -7402,7 +7542,7 @@ async function main9(env = process.env, argv = process.argv.slice(2)) {
|
|
|
7402
7542
|
}
|
|
7403
7543
|
const authorized = await prepareAuthorizedCreateBountyTransaction({
|
|
7404
7544
|
transaction: prepared.create_bounty_transaction,
|
|
7405
|
-
tokenAddress
|
|
7545
|
+
tokenAddress,
|
|
7406
7546
|
poster: account.address,
|
|
7407
7547
|
publicClient,
|
|
7408
7548
|
sign: (typedData) => account.signTypedData(typedData)
|
|
@@ -7423,7 +7563,7 @@ async function main9(env = process.env, argv = process.argv.slice(2)) {
|
|
|
7423
7563
|
});
|
|
7424
7564
|
} else {
|
|
7425
7565
|
const approveHash = await walletClient.writeContract({
|
|
7426
|
-
address:
|
|
7566
|
+
address: tokenAddress,
|
|
7427
7567
|
abi: usdcAbi,
|
|
7428
7568
|
functionName: "approve",
|
|
7429
7569
|
args: [config.hubAddress, escrowAmount]
|
|
@@ -7497,60 +7637,115 @@ async function requestPreparePublication(input) {
|
|
|
7497
7637
|
new URL(input.requestUrl),
|
|
7498
7638
|
input.markdown,
|
|
7499
7639
|
"text/markdown",
|
|
7500
|
-
input.authorization
|
|
7640
|
+
input.authorization,
|
|
7641
|
+
{ [ELGORA_READINESS_SIGNOFF_HEADER]: input.signoff }
|
|
7501
7642
|
);
|
|
7502
7643
|
return bountyPublicationResponseSchema.parse(body);
|
|
7503
7644
|
}
|
|
7504
|
-
|
|
7505
|
-
|
|
7506
|
-
|
|
7507
|
-
|
|
7508
|
-
}
|
|
7509
|
-
if (path5 === "-") {
|
|
7510
|
-
return readStdinText3(process.stdin);
|
|
7511
|
-
}
|
|
7512
|
-
return readFile4(path5, "utf8");
|
|
7645
|
+
|
|
7646
|
+
// src/required-env.ts
|
|
7647
|
+
function missingRequiredEnv(required4, env) {
|
|
7648
|
+
return required4.filter((envName) => !env[envName]?.trim());
|
|
7513
7649
|
}
|
|
7514
|
-
|
|
7515
|
-
|
|
7516
|
-
|
|
7517
|
-
|
|
7518
|
-
|
|
7519
|
-
|
|
7520
|
-
|
|
7521
|
-
|
|
7522
|
-
|
|
7523
|
-
|
|
7650
|
+
|
|
7651
|
+
// src/review.ts
|
|
7652
|
+
import { writeFile as writeFile3 } from "fs/promises";
|
|
7653
|
+
import { resolve } from "path";
|
|
7654
|
+
import { privateKeyToAccount as privateKeyToAccount9 } from "viem/accounts";
|
|
7655
|
+
var USAGE2 = "Usage: elgora-cli poster:review <path|-> [--previous <commitment>] [--signoff-out <file>]";
|
|
7656
|
+
async function main10(env = process.env, argv = process.argv.slice(2)) {
|
|
7657
|
+
const { apiBaseUrl, argv: args } = extractApiBaseUrlFlag(argv);
|
|
7658
|
+
const { value: previous, argv: afterPrevious } = takeFlag(
|
|
7659
|
+
args,
|
|
7660
|
+
"--previous",
|
|
7661
|
+
"--previous must be one bytes32 page commitment"
|
|
7662
|
+
);
|
|
7663
|
+
if (previous && !isHexBytes32(previous))
|
|
7664
|
+
throw new Error("--previous must be one bytes32 page commitment");
|
|
7665
|
+
const { value: signoffOut, argv: paths } = takeFlag(
|
|
7666
|
+
afterPrevious,
|
|
7667
|
+
"--signoff-out",
|
|
7668
|
+
USAGE2
|
|
7669
|
+
);
|
|
7670
|
+
if (paths.length !== 1 || !paths[0] || paths[0].startsWith("--"))
|
|
7671
|
+
throw new Error(USAGE2);
|
|
7672
|
+
if (signoffOut && paths[0] !== "-" && resolve(signoffOut) === resolve(paths[0]))
|
|
7673
|
+
throw new Error("--signoff-out must not overwrite the bounty draft");
|
|
7674
|
+
const config = loadPosterConfig(env, apiBaseUrl);
|
|
7675
|
+
const markdown = await readBountyChallengeMarkdown2(paths[0]);
|
|
7676
|
+
const commitment = deriveBountyChallengeContentCommitment(markdown);
|
|
7677
|
+
const account = privateKeyToAccount9(config.posterPrivateKey);
|
|
7678
|
+
const publicClient = createChainPublicClient(config.chainId, config.rpcUrl);
|
|
7679
|
+
await assertHubDeployment(publicClient, config.chainId, config.hubAddress);
|
|
7680
|
+
const requestUrl = new URL(
|
|
7681
|
+
"/api/bounty-challenge-specs/review",
|
|
7682
|
+
config.apiBaseUrl
|
|
7683
|
+
);
|
|
7684
|
+
requestUrl.searchParams.set("poster_address", account.address);
|
|
7685
|
+
if (previous)
|
|
7686
|
+
requestUrl.searchParams.set(
|
|
7687
|
+
"previous_spec_commitment",
|
|
7688
|
+
previous.toLowerCase()
|
|
7524
7689
|
);
|
|
7690
|
+
const authorization = await signPosterRequest({
|
|
7691
|
+
requestUrl,
|
|
7692
|
+
markdown,
|
|
7693
|
+
config,
|
|
7694
|
+
account,
|
|
7695
|
+
publicClient
|
|
7696
|
+
});
|
|
7697
|
+
let response;
|
|
7698
|
+
try {
|
|
7699
|
+
response = bountyReviewResponseSchema.parse(
|
|
7700
|
+
await postText(requestUrl, markdown, "text/markdown", authorization)
|
|
7701
|
+
);
|
|
7702
|
+
} catch (error) {
|
|
7703
|
+
if (error instanceof ApiRequestError && error.code === "bounty_challenge_not_ready") {
|
|
7704
|
+
console.log(
|
|
7705
|
+
JSON.stringify({
|
|
7706
|
+
event: "review.not_ready",
|
|
7707
|
+
issues: error.issues,
|
|
7708
|
+
prior_issues_resolved: error.priorIssuesResolved,
|
|
7709
|
+
prior_issues_open: error.priorIssuesOpen
|
|
7710
|
+
})
|
|
7711
|
+
);
|
|
7712
|
+
process.exitCode = 2;
|
|
7713
|
+
return;
|
|
7714
|
+
}
|
|
7715
|
+
throw error;
|
|
7525
7716
|
}
|
|
7526
|
-
|
|
7527
|
-
if (!escrowTokenAddress || !isHexAddress(escrowTokenAddress)) {
|
|
7717
|
+
if (response.content_record.spec_commitment !== commitment) {
|
|
7528
7718
|
throw new Error(
|
|
7529
|
-
"
|
|
7719
|
+
"Elgora API returned a review for different bounty_challenge.md bytes"
|
|
7530
7720
|
);
|
|
7531
7721
|
}
|
|
7532
|
-
|
|
7533
|
-
|
|
7534
|
-
|
|
7535
|
-
|
|
7536
|
-
|
|
7537
|
-
|
|
7538
|
-
|
|
7539
|
-
|
|
7540
|
-
|
|
7541
|
-
|
|
7542
|
-
|
|
7722
|
+
if (signoffOut)
|
|
7723
|
+
await writeFile3(
|
|
7724
|
+
signoffOut,
|
|
7725
|
+
`${JSON.stringify(response.readiness.signoff, null, 2)}
|
|
7726
|
+
`
|
|
7727
|
+
);
|
|
7728
|
+
console.log(
|
|
7729
|
+
JSON.stringify({
|
|
7730
|
+
event: "review.ready",
|
|
7731
|
+
spec_commitment: commitment,
|
|
7732
|
+
signoff: response.readiness.signoff,
|
|
7733
|
+
warnings: response.readiness.warnings ?? [],
|
|
7734
|
+
prior_issues_resolved: response.readiness.prior_issues_resolved,
|
|
7735
|
+
prior_issues_open: response.readiness.prior_issues_open
|
|
7736
|
+
})
|
|
7737
|
+
);
|
|
7543
7738
|
}
|
|
7544
7739
|
|
|
7545
7740
|
// src/roster-add-guardian.ts
|
|
7546
7741
|
import { isAddress as isAddress4 } from "viem";
|
|
7547
|
-
import { privateKeyToAccount as
|
|
7742
|
+
import { privateKeyToAccount as privateKeyToAccount10 } from "viem/accounts";
|
|
7548
7743
|
var ROSTER_ADMIN_ADDRESS_FLAG = "--roster-admin-address";
|
|
7549
7744
|
var ENCRYPTION_PUBLIC_KEY_RE = /^[A-Za-z0-9_-]{43}$/;
|
|
7550
|
-
async function
|
|
7745
|
+
async function main11(env = process.env, argv = process.argv.slice(2)) {
|
|
7551
7746
|
const args = parseRosterAddGuardianArgs(argv);
|
|
7552
7747
|
const config = loadRosterAddGuardianConfig(env, args.rosterAdminAddress);
|
|
7553
|
-
const account = config.rosterAdminPrivateKey ?
|
|
7748
|
+
const account = config.rosterAdminPrivateKey ? privateKeyToAccount10(config.rosterAdminPrivateKey) : null;
|
|
7554
7749
|
const rosterAdmin = account?.address ?? args.rosterAdminAddress;
|
|
7555
7750
|
if (!rosterAdmin) throw new Error("Roster admin address is required");
|
|
7556
7751
|
const normalizedRosterAdmin = rosterAdmin.toLowerCase();
|
|
@@ -7718,7 +7913,7 @@ function usageError2() {
|
|
|
7718
7913
|
// src/roster-prepare-guardian-proof.ts
|
|
7719
7914
|
import { isAddress as isAddress5 } from "viem";
|
|
7720
7915
|
var ENCRYPTION_PUBLIC_KEY_RE2 = /^[A-Za-z0-9_-]{43}$/;
|
|
7721
|
-
async function
|
|
7916
|
+
async function main12(env = process.env, argv = process.argv.slice(2)) {
|
|
7722
7917
|
const args = parseArgs(argv);
|
|
7723
7918
|
const envWithDefaults = withDeploymentDefaults(env);
|
|
7724
7919
|
const { chainId, hubAddress } = loadPublicDeploymentConfig(envWithDefaults);
|
|
@@ -7765,17 +7960,17 @@ function usageError3() {
|
|
|
7765
7960
|
}
|
|
7766
7961
|
|
|
7767
7962
|
// src/roster-verify-guardian-proof.ts
|
|
7768
|
-
import { readFile as
|
|
7769
|
-
import { isAddress as isAddress6, isHex as
|
|
7770
|
-
async function
|
|
7963
|
+
import { readFile as readFile6 } from "fs/promises";
|
|
7964
|
+
import { isAddress as isAddress6, isHex as isHex6, recoverMessageAddress } from "viem";
|
|
7965
|
+
async function main13(_env = process.env, argv = process.argv.slice(2)) {
|
|
7771
7966
|
const [preparedPath, responsePath] = argv;
|
|
7772
7967
|
if (!preparedPath || !responsePath) {
|
|
7773
7968
|
throw new Error(
|
|
7774
7969
|
"Usage: elgora-cli roster:verify-guardian-proof <prepared_json_path> <response_json_path>"
|
|
7775
7970
|
);
|
|
7776
7971
|
}
|
|
7777
|
-
const prepared = parsePrepared(await
|
|
7778
|
-
const response = parseResponse(await
|
|
7972
|
+
const prepared = parsePrepared(await readFile6(preparedPath, "utf8"));
|
|
7973
|
+
const response = parseResponse(await readFile6(responsePath, "utf8"));
|
|
7779
7974
|
const fixture = base64UrlToBytes(prepared.fixture);
|
|
7780
7975
|
const signedPayload = buildGuardianRosterKeyProofSignedPayload(
|
|
7781
7976
|
prepared.message,
|
|
@@ -7839,7 +8034,7 @@ function parseResponse(text) {
|
|
|
7839
8034
|
}
|
|
7840
8035
|
const guardianAccount = get(parsed, "guardian_account");
|
|
7841
8036
|
const signature = get(parsed, "signature");
|
|
7842
|
-
if (typeof guardianAccount !== "string" || !isAddress6(guardianAccount) || typeof signature !== "string" || !
|
|
8037
|
+
if (typeof guardianAccount !== "string" || !isAddress6(guardianAccount) || typeof signature !== "string" || !isHex6(signature) || signature.length !== 132) {
|
|
7843
8038
|
throw new Error(
|
|
7844
8039
|
"Guardian response JSON must be the unmodified stdout of guardian:prove-roster-key"
|
|
7845
8040
|
);
|
|
@@ -7857,10 +8052,10 @@ function get(value, key) {
|
|
|
7857
8052
|
}
|
|
7858
8053
|
|
|
7859
8054
|
// src/spec-commitment.ts
|
|
7860
|
-
import { readFile as
|
|
8055
|
+
import { readFile as readFile7 } from "fs/promises";
|
|
7861
8056
|
import { text as readStdinText4 } from "stream/consumers";
|
|
7862
8057
|
var SPEC_COMMITMENT_USAGE = "Usage: elgora-cli spec-commitment <bounty_challenge_md_path>\n or: elgora-cli spec-commitment -";
|
|
7863
|
-
async function
|
|
8058
|
+
async function main14(_env = process.env, argv = process.argv.slice(2)) {
|
|
7864
8059
|
const markdown = await readBountyChallengeMarkdown3(argv);
|
|
7865
8060
|
const specCommitment = deriveBountyChallengeContentCommitment(markdown);
|
|
7866
8061
|
console.log(
|
|
@@ -7879,23 +8074,23 @@ async function readBountyChallengeMarkdown3(argv) {
|
|
|
7879
8074
|
if (path5 === "-") {
|
|
7880
8075
|
return readStdinText4(process.stdin);
|
|
7881
8076
|
}
|
|
7882
|
-
return
|
|
8077
|
+
return readFile7(path5, "utf8");
|
|
7883
8078
|
}
|
|
7884
8079
|
|
|
7885
8080
|
// src/submit.ts
|
|
7886
|
-
import { readdir, readFile as
|
|
8081
|
+
import { readdir, readFile as readFile8, stat } from "fs/promises";
|
|
7887
8082
|
import path3 from "path";
|
|
7888
8083
|
import { createInterface } from "readline";
|
|
7889
8084
|
import { isAddress as isAddress7 } from "viem";
|
|
7890
|
-
import { privateKeyToAccount as
|
|
8085
|
+
import { privateKeyToAccount as privateKeyToAccount11 } from "viem/accounts";
|
|
7891
8086
|
|
|
7892
8087
|
// src/external-api-approval-signer.ts
|
|
7893
|
-
import { isHex as
|
|
8088
|
+
import { isHex as isHex7 } from "viem";
|
|
7894
8089
|
function createExternalApiApprovalSigner(input) {
|
|
7895
8090
|
return async (typedData) => {
|
|
7896
8091
|
input.writePrompt(input.renderPrompt(typedData));
|
|
7897
8092
|
const signature = (await input.readSignature())?.trim();
|
|
7898
|
-
if (!signature || signature === "0x" || !
|
|
8093
|
+
if (!signature || signature === "0x" || !isHex7(signature)) {
|
|
7899
8094
|
throw new Error(
|
|
7900
8095
|
"External signer must return one non-empty 0x-prefixed hex signature line on stdin"
|
|
7901
8096
|
);
|
|
@@ -7937,13 +8132,13 @@ var MEDIA_TYPE_BY_EXTENSION = {
|
|
|
7937
8132
|
diff: "text/x-diff"
|
|
7938
8133
|
};
|
|
7939
8134
|
var DEFAULT_MEDIA_TYPE = "application/octet-stream";
|
|
7940
|
-
async function
|
|
8135
|
+
async function main15(env = process.env, argv = process.argv.slice(2)) {
|
|
7941
8136
|
const { solverAddress, argv: argvWithoutSolverAddress } = extractSolverAddressFlag(argv);
|
|
7942
8137
|
const { apiBaseUrl: apiBaseUrlOverride, argv: remainingArgv } = extractApiBaseUrlFlag(argvWithoutSolverAddress);
|
|
7943
8138
|
const config = loadSubmitConfig(env, apiBaseUrlOverride, solverAddress);
|
|
7944
8139
|
const args = readSubmitArgs(remainingArgv);
|
|
7945
8140
|
const bountyIdText = args.bountyId.toString();
|
|
7946
|
-
const account = config.solverPrivateKey ?
|
|
8141
|
+
const account = config.solverPrivateKey ? privateKeyToAccount11(config.solverPrivateKey) : null;
|
|
7947
8142
|
const solverAddressFromConfig = account?.address ?? config.solverAddress;
|
|
7948
8143
|
if (!solverAddressFromConfig) throw new Error("Solver address is required");
|
|
7949
8144
|
const solver = solverAddressFromConfig.toLowerCase();
|
|
@@ -8335,7 +8530,7 @@ async function readArtifactDirectory(artifactDir) {
|
|
|
8335
8530
|
}
|
|
8336
8531
|
return Promise.all(
|
|
8337
8532
|
entries.map(async (entry) => {
|
|
8338
|
-
const bytes = await
|
|
8533
|
+
const bytes = await readFile8(path3.join(artifactDir, entry.name));
|
|
8339
8534
|
return {
|
|
8340
8535
|
name: entry.name,
|
|
8341
8536
|
media_type: guessMediaType(entry.name),
|
|
@@ -8404,7 +8599,7 @@ async function requestPrepareSubmission(input) {
|
|
|
8404
8599
|
})
|
|
8405
8600
|
);
|
|
8406
8601
|
}
|
|
8407
|
-
await new Promise((
|
|
8602
|
+
await new Promise((resolve2) => setTimeout(resolve2, retryDelay));
|
|
8408
8603
|
}
|
|
8409
8604
|
}
|
|
8410
8605
|
}
|
|
@@ -8448,7 +8643,7 @@ function readTimelockRevealDelaySeconds(env) {
|
|
|
8448
8643
|
|
|
8449
8644
|
// src/verification-record.ts
|
|
8450
8645
|
var VERIFICATION_RECORD_USAGE = "Usage: elgora-cli verification-record <bounty_id>";
|
|
8451
|
-
async function
|
|
8646
|
+
async function main16(env = process.env, argv = process.argv.slice(2)) {
|
|
8452
8647
|
const { apiBaseUrl: apiBaseUrlOverride, argv: remainingArgv } = extractApiBaseUrlFlag(argv);
|
|
8453
8648
|
const args = readVerificationRecordArgs(remainingArgv);
|
|
8454
8649
|
const envWithDefaults = withDeploymentDefaults(env);
|
|
@@ -8533,15 +8728,16 @@ var COMMANDS = {
|
|
|
8533
8728
|
"guardian:verdict": main7,
|
|
8534
8729
|
"guardian:deliver-key": main4,
|
|
8535
8730
|
"poster:open-winning-submission": main8,
|
|
8731
|
+
"poster:review": main10,
|
|
8536
8732
|
"poster:publish-fund": main9,
|
|
8537
|
-
"roster:add-guardian":
|
|
8538
|
-
"roster:prepare-guardian-proof":
|
|
8539
|
-
"roster:verify-guardian-proof":
|
|
8540
|
-
"solver:submit":
|
|
8733
|
+
"roster:add-guardian": main11,
|
|
8734
|
+
"roster:prepare-guardian-proof": main12,
|
|
8735
|
+
"roster:verify-guardian-proof": main13,
|
|
8736
|
+
"solver:submit": main15,
|
|
8541
8737
|
claim: main2,
|
|
8542
8738
|
"check-page": main,
|
|
8543
|
-
"spec-commitment":
|
|
8544
|
-
"verification-record":
|
|
8739
|
+
"spec-commitment": main14,
|
|
8740
|
+
"verification-record": main16
|
|
8545
8741
|
};
|
|
8546
8742
|
var COMMAND_HELP = {
|
|
8547
8743
|
"guardian:judgeable": {
|
|
@@ -8610,10 +8806,23 @@ var COMMAND_HELP = {
|
|
|
8610
8806
|
],
|
|
8611
8807
|
apiBaseUrlFlag: true
|
|
8612
8808
|
},
|
|
8809
|
+
"poster:review": {
|
|
8810
|
+
usage: "elgora-cli poster:review <path|-> [--previous <commitment>] [--signoff-out <file>]",
|
|
8811
|
+
title: "Review a bounty page and save its readiness certificate.",
|
|
8812
|
+
description: "Send the exact Markdown for a signed readiness review. Ready prints\n review.ready; --signoff-out saves the certificate for publication.\n Not-ready prints all issues and exits 2; other failures exit 1.\n --previous sends the previous page commitment with the signed request.",
|
|
8813
|
+
required: ["ELGORA_POSTER_PRIVATE_KEY"],
|
|
8814
|
+
defaulted: [
|
|
8815
|
+
"ELGORA_CHAIN_ID",
|
|
8816
|
+
"ELGORA_HUB_ADDRESS",
|
|
8817
|
+
"ELGORA_RPC_URL",
|
|
8818
|
+
"ELGORA_API_BASE_URL"
|
|
8819
|
+
],
|
|
8820
|
+
apiBaseUrlFlag: true
|
|
8821
|
+
},
|
|
8613
8822
|
"poster:publish-fund": {
|
|
8614
|
-
usage: "elgora-cli poster:publish-fund <bounty_challenge_md_path|->",
|
|
8823
|
+
usage: "elgora-cli poster:publish-fund <bounty_challenge_md_path|-> --signoff <file>",
|
|
8615
8824
|
title: "Publish an approved challenge and fund its bounty.",
|
|
8616
|
-
description: "Read the exact approved bounty_challenge.md bytes and
|
|
8825
|
+
description: "Read the exact approved bounty_challenge.md bytes and its saved certificate.\n Publishing checks the certificate and never runs another AI review.\n Eligible wallets sign a USDC authorization, then send\n one funding transaction and pay gas. No new allowance is required;\n this authorization path does not revoke existing allowances.\n Unsupported accounts use approval then creation. Pass '-' to read stdin.",
|
|
8617
8826
|
required: ["ELGORA_POSTER_PRIVATE_KEY"],
|
|
8618
8827
|
defaulted: [
|
|
8619
8828
|
"ELGORA_CHAIN_ID",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elgora/cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "9.1.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",
|