@elgora/cli 8.0.0 → 9.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.
- package/README.md +7 -2
- package/dist/cli.js +459 -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,28 @@ var bountyPublicationResponseSchema = z2.object({
|
|
|
424
495
|
});
|
|
425
496
|
}
|
|
426
497
|
});
|
|
498
|
+
var priorIssueSchema = z3.object({ anchor: z3.string().min(1), code: z3.string().min(1) }).strict();
|
|
499
|
+
var bountyReviewResponseSchema = z3.object({
|
|
500
|
+
content_record: bountyChallengeContentRecordSchema,
|
|
501
|
+
readiness: z3.object({
|
|
502
|
+
decision: z3.literal("ready"),
|
|
503
|
+
signoff: readinessSignoffSchema,
|
|
504
|
+
prior_issues_resolved: z3.array(priorIssueSchema),
|
|
505
|
+
prior_issues_open: z3.array(priorIssueSchema)
|
|
506
|
+
}).strict()
|
|
507
|
+
}).strict().superRefine((response, context) => {
|
|
508
|
+
if (response.readiness.signoff.spec_commitment.toLowerCase() !== response.content_record.spec_commitment.toLowerCase()) {
|
|
509
|
+
context.addIssue({
|
|
510
|
+
code: "custom",
|
|
511
|
+
path: ["readiness", "signoff", "spec_commitment"],
|
|
512
|
+
message: "Must match content_record.spec_commitment"
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
});
|
|
516
|
+
var readinessSignerResponseSchema = z3.object({
|
|
517
|
+
signer_address: addressSchema,
|
|
518
|
+
audience: z3.string().min(1)
|
|
519
|
+
}).strict();
|
|
427
520
|
|
|
428
521
|
// ../../packages/core/src/chain-registry.ts
|
|
429
522
|
import { base, baseSepolia, foundry } from "viem/chains";
|
|
@@ -447,7 +540,7 @@ var FOUNDRY_CHAIN_ID = foundry.id;
|
|
|
447
540
|
import { Aes256Gcm, CipherSuite, HkdfSha256 } from "@hpke/core";
|
|
448
541
|
import { DhkemX25519HkdfSha256 } from "@hpke/dhkem-x25519";
|
|
449
542
|
import { concatBytes, keccak256 as keccak2562, toBytes as toBytes2 } from "viem";
|
|
450
|
-
import { z as
|
|
543
|
+
import { z as z4 } from "zod";
|
|
451
544
|
|
|
452
545
|
// ../../packages/core/src/base64.ts
|
|
453
546
|
var BASE64_ENCODE_CHUNK_BYTES = 3 * 16384;
|
|
@@ -533,42 +626,42 @@ var BASE64URL_RE = /^[A-Za-z0-9_-]+$/;
|
|
|
533
626
|
var SOLVER_SUBMISSION_NAME_RE = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
534
627
|
var MEDIA_TYPE_RE = /^[a-z0-9][a-z0-9!#$&^_.+-]*\/[a-z0-9][a-z0-9!#$&^_.+-]*$/;
|
|
535
628
|
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 =
|
|
629
|
+
var base64UrlSchema = z4.string().regex(BASE64URL_RE);
|
|
630
|
+
var lowerAddressSchema = z4.string().refine(isLowercaseHexAddress);
|
|
631
|
+
var bytes32Schema3 = z4.string().refine(isLowercaseBytes32);
|
|
632
|
+
var sha256HexSchema = z4.string().refine(isSha256Hex);
|
|
633
|
+
var keyIdSchema = z4.string().min(1).max(128).regex(KEY_ID_RE);
|
|
634
|
+
var artifactNameSchema = z4.string().max(
|
|
542
635
|
MAX_SOLVER_SUBMISSION_NAME_CHARACTERS,
|
|
543
636
|
`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
637
|
).regex(SOLVER_SUBMISSION_NAME_RE);
|
|
545
|
-
var mediaTypeSchema =
|
|
546
|
-
var bountyIdSchema =
|
|
547
|
-
var chainIdSchema =
|
|
548
|
-
var privateArtifactContextSchema =
|
|
549
|
-
type:
|
|
638
|
+
var mediaTypeSchema = z4.string().regex(MEDIA_TYPE_RE);
|
|
639
|
+
var bountyIdSchema = z4.string().refine(isBountyId);
|
|
640
|
+
var chainIdSchema = z4.number().int().positive().lte(Number.MAX_SAFE_INTEGER);
|
|
641
|
+
var privateArtifactContextSchema = z4.strictObject({
|
|
642
|
+
type: z4.literal("solver_submission"),
|
|
550
643
|
chain_id: chainIdSchema,
|
|
551
644
|
hub_address: lowerAddressSchema,
|
|
552
645
|
bounty_id: bountyIdSchema,
|
|
553
646
|
actor_address: lowerAddressSchema
|
|
554
647
|
});
|
|
555
|
-
var guardianRecipientSchema =
|
|
648
|
+
var guardianRecipientSchema = z4.strictObject({
|
|
556
649
|
key_id: keyIdSchema,
|
|
557
|
-
suite:
|
|
650
|
+
suite: z4.literal(PRIVATE_ARTIFACT_HPKE_SUITE),
|
|
558
651
|
public_key: base64UrlSchema.length(
|
|
559
652
|
43,
|
|
560
653
|
"public_key must encode a 32-byte X25519 public key"
|
|
561
654
|
)
|
|
562
655
|
});
|
|
563
|
-
var guardianRecipientPrivateKeySchema =
|
|
656
|
+
var guardianRecipientPrivateKeySchema = z4.strictObject({
|
|
564
657
|
key_id: keyIdSchema,
|
|
565
|
-
suite:
|
|
658
|
+
suite: z4.literal(PRIVATE_ARTIFACT_HPKE_SUITE),
|
|
566
659
|
private_key: base64UrlSchema.length(
|
|
567
660
|
43,
|
|
568
661
|
"private_key must encode a 32-byte X25519 private key"
|
|
569
662
|
)
|
|
570
663
|
});
|
|
571
|
-
var guardianRecipientsSchema =
|
|
664
|
+
var guardianRecipientsSchema = z4.array(guardianRecipientSchema).min(1).superRefine((recipients, ctx) => {
|
|
572
665
|
const seen = /* @__PURE__ */ new Set();
|
|
573
666
|
for (const recipient of recipients) {
|
|
574
667
|
if (seen.has(recipient.key_id)) {
|
|
@@ -581,24 +674,24 @@ var guardianRecipientsSchema = z3.array(guardianRecipientSchema).min(1).superRef
|
|
|
581
674
|
seen.add(recipient.key_id);
|
|
582
675
|
}
|
|
583
676
|
});
|
|
584
|
-
var guardianRecipientPrivateKeysSchema =
|
|
585
|
-
var artifactManifestEntrySchema =
|
|
677
|
+
var guardianRecipientPrivateKeysSchema = z4.array(guardianRecipientPrivateKeySchema).min(1);
|
|
678
|
+
var artifactManifestEntrySchema = z4.strictObject({
|
|
586
679
|
name: artifactNameSchema,
|
|
587
680
|
media_type: mediaTypeSchema,
|
|
588
|
-
size_bytes:
|
|
681
|
+
size_bytes: z4.number().int().nonnegative().lte(Number.MAX_SAFE_INTEGER),
|
|
589
682
|
sha256: sha256HexSchema
|
|
590
683
|
});
|
|
591
|
-
var privateArtifactPublicManifestSchema =
|
|
592
|
-
kind:
|
|
684
|
+
var privateArtifactPublicManifestSchema = z4.strictObject({
|
|
685
|
+
kind: z4.literal(PRIVATE_ARTIFACT_PUBLIC_MANIFEST_KIND),
|
|
593
686
|
context: privateArtifactContextSchema
|
|
594
687
|
});
|
|
595
688
|
var encryptedBundleArtifactSchema = artifactManifestEntrySchema.extend({
|
|
596
689
|
bytes: base64UrlSchema
|
|
597
690
|
});
|
|
598
|
-
var privateArtifactEncryptedBundleSchema =
|
|
599
|
-
kind:
|
|
691
|
+
var privateArtifactEncryptedBundleSchema = z4.strictObject({
|
|
692
|
+
kind: z4.literal(PRIVATE_ARTIFACT_ENCRYPTED_BUNDLE_KIND),
|
|
600
693
|
context: privateArtifactContextSchema,
|
|
601
|
-
artifacts:
|
|
694
|
+
artifacts: z4.array(encryptedBundleArtifactSchema).min(1).max(
|
|
602
695
|
MAX_SOLVER_SUBMISSION_FILES,
|
|
603
696
|
`Submission exceeds the maximum of ${MAX_SOLVER_SUBMISSION_FILES} files.`
|
|
604
697
|
).refine(
|
|
@@ -606,33 +699,33 @@ var privateArtifactEncryptedBundleSchema = z3.strictObject({
|
|
|
606
699
|
"artifact names must be unique case-insensitively"
|
|
607
700
|
)
|
|
608
701
|
});
|
|
609
|
-
var privateArtifactRevealPolicySchema =
|
|
610
|
-
kind:
|
|
611
|
-
network:
|
|
612
|
-
chain_hash:
|
|
613
|
-
round:
|
|
614
|
-
not_before:
|
|
702
|
+
var privateArtifactRevealPolicySchema = z4.strictObject({
|
|
703
|
+
kind: z4.literal(PRIVATE_ARTIFACT_REVEAL_POLICY_KIND),
|
|
704
|
+
network: z4.string().min(1),
|
|
705
|
+
chain_hash: z4.string().min(1),
|
|
706
|
+
round: z4.string().refine(isPositiveInteger),
|
|
707
|
+
not_before: z4.number().int().nonnegative().lte(Number.MAX_SAFE_INTEGER)
|
|
615
708
|
});
|
|
616
|
-
var wrappedRecipientKeySchema =
|
|
709
|
+
var wrappedRecipientKeySchema = z4.strictObject({
|
|
617
710
|
key_id: keyIdSchema,
|
|
618
|
-
suite:
|
|
711
|
+
suite: z4.literal(PRIVATE_ARTIFACT_HPKE_SUITE),
|
|
619
712
|
enc: base64UrlSchema,
|
|
620
713
|
ciphertext: base64UrlSchema
|
|
621
714
|
});
|
|
622
|
-
var wrappedKeyBagSchema =
|
|
623
|
-
kind:
|
|
624
|
-
keys:
|
|
715
|
+
var wrappedKeyBagSchema = z4.strictObject({
|
|
716
|
+
kind: z4.literal(PRIVATE_ARTIFACT_WRAPPED_KEY_BAG_KIND),
|
|
717
|
+
keys: z4.array(wrappedRecipientKeySchema).min(1)
|
|
625
718
|
});
|
|
626
|
-
var privateArtifactEnvelopeSchema =
|
|
627
|
-
kind:
|
|
628
|
-
alg:
|
|
719
|
+
var privateArtifactEnvelopeSchema = z4.strictObject({
|
|
720
|
+
kind: z4.literal(PRIVATE_ARTIFACT_ENVELOPE_KIND),
|
|
721
|
+
alg: z4.literal(SUBMISSION_ENCRYPTION_TYPE),
|
|
629
722
|
context: privateArtifactContextSchema,
|
|
630
723
|
public_manifest: privateArtifactPublicManifestSchema,
|
|
631
724
|
public_manifest_sha256: sha256HexSchema,
|
|
632
725
|
encrypted_bundle_sha256: sha256HexSchema,
|
|
633
726
|
ciphertext_sha256: sha256HexSchema,
|
|
634
727
|
guardian_recipients: guardianRecipientsSchema,
|
|
635
|
-
guardian_recipients_commitment:
|
|
728
|
+
guardian_recipients_commitment: bytes32Schema3,
|
|
636
729
|
reveal_policy: privateArtifactRevealPolicySchema,
|
|
637
730
|
envelope_nonce: base64UrlSchema.length(
|
|
638
731
|
22,
|
|
@@ -640,7 +733,7 @@ var privateArtifactEnvelopeSchema = z3.strictObject({
|
|
|
640
733
|
),
|
|
641
734
|
iv: base64UrlSchema.length(16, "iv must encode 12 bytes"),
|
|
642
735
|
wrapped_key_bag: base64UrlSchema,
|
|
643
|
-
ciphertext_locator:
|
|
736
|
+
ciphertext_locator: z4.string().min(1)
|
|
644
737
|
});
|
|
645
738
|
function parsePrivateArtifactEnvelope(input) {
|
|
646
739
|
return privateArtifactEnvelopeSchema.parse(input);
|
|
@@ -698,11 +791,11 @@ var x25519PrivateKeySchema = base64UrlSchema.length(
|
|
|
698
791
|
43,
|
|
699
792
|
"must encode a 32-byte X25519 private key"
|
|
700
793
|
);
|
|
701
|
-
var winningSolutionDeliveryContextSchema =
|
|
794
|
+
var winningSolutionDeliveryContextSchema = z4.strictObject({
|
|
702
795
|
chain_id: chainIdSchema,
|
|
703
796
|
hub_address: lowerAddressSchema,
|
|
704
797
|
bounty_id: bountyIdSchema,
|
|
705
|
-
submission_commitment:
|
|
798
|
+
submission_commitment: bytes32Schema3
|
|
706
799
|
});
|
|
707
800
|
async function generateX25519KeyPair(input) {
|
|
708
801
|
const suite = createHpkeSuite();
|
|
@@ -779,7 +872,7 @@ function buildWinningSolutionDeliveryInfo(contextCommitment) {
|
|
|
779
872
|
var GUARDIAN_ROSTER_KEY_PROOF_INFO = "elgora/guardian-roster-key-proof/hpke-fixture/v0";
|
|
780
873
|
var GUARDIAN_ROSTER_KEY_PROOF_MESSAGE_TYPE = "elgora_guardian_roster_key_proof_v0";
|
|
781
874
|
var GUARDIAN_ROSTER_KEY_PROOF_FIXTURE_BYTES = 32;
|
|
782
|
-
var guardianRosterKeyProofContextSchema =
|
|
875
|
+
var guardianRosterKeyProofContextSchema = z4.strictObject({
|
|
783
876
|
chain_id: chainIdSchema,
|
|
784
877
|
hub_address: lowerAddressSchema,
|
|
785
878
|
proposed_account: lowerAddressSchema,
|
|
@@ -1107,7 +1200,7 @@ async function wrapAesKeyForRecipients(input) {
|
|
|
1107
1200
|
}
|
|
1108
1201
|
async function openAesKeyForRecipient(input) {
|
|
1109
1202
|
const suite = createHpkeSuite();
|
|
1110
|
-
const wrappedKeys =
|
|
1203
|
+
const wrappedKeys = z4.array(wrappedRecipientKeySchema).parse(input.wrappedKeys);
|
|
1111
1204
|
const privateKeys = guardianRecipientPrivateKeysSchema.parse(
|
|
1112
1205
|
input.privateKeys
|
|
1113
1206
|
);
|
|
@@ -3818,7 +3911,7 @@ function settlementAmounts(escrowAmount, treasuryFeeBps, guardianFeeBps) {
|
|
|
3818
3911
|
import { zeroAddress } from "viem";
|
|
3819
3912
|
|
|
3820
3913
|
// ../../packages/core/src/api/bounty-preparation.ts
|
|
3821
|
-
import { ZodError, z as
|
|
3914
|
+
import { ZodError, z as z5 } from "zod";
|
|
3822
3915
|
|
|
3823
3916
|
// ../../packages/core/src/submission-timelock.ts
|
|
3824
3917
|
import {
|
|
@@ -4079,7 +4172,7 @@ import {
|
|
|
4079
4172
|
getAbiItem as getAbiItem2,
|
|
4080
4173
|
parseAbi,
|
|
4081
4174
|
parseSignature,
|
|
4082
|
-
recoverTypedDataAddress
|
|
4175
|
+
recoverTypedDataAddress as recoverTypedDataAddress2
|
|
4083
4176
|
} from "viem";
|
|
4084
4177
|
var ELGORA_HUB_ERRORS = ELGORA_HUB_ABI.filter(
|
|
4085
4178
|
(item) => item.type === "error"
|
|
@@ -4236,7 +4329,7 @@ async function prepareAuthorizedCreateBountyTransaction(input) {
|
|
|
4236
4329
|
if (unsupported) return null;
|
|
4237
4330
|
throw error;
|
|
4238
4331
|
}
|
|
4239
|
-
if ((await
|
|
4332
|
+
if ((await recoverTypedDataAddress2({ ...authorization, signature })).toLowerCase() !== poster.toLowerCase()) {
|
|
4240
4333
|
throw new Error("USDC authorization was not signed by the funding Poster.");
|
|
4241
4334
|
}
|
|
4242
4335
|
const { r, s, yParity } = parseSignature(signature);
|
|
@@ -4312,14 +4405,14 @@ var BoundaryValidationError = class extends Error {
|
|
|
4312
4405
|
this.issues = issues;
|
|
4313
4406
|
}
|
|
4314
4407
|
};
|
|
4315
|
-
var artifactUploadUrlRequestSchema =
|
|
4316
|
-
ciphertext_sha256:
|
|
4317
|
-
ciphertext_byte_length:
|
|
4408
|
+
var artifactUploadUrlRequestSchema = z5.object({
|
|
4409
|
+
ciphertext_sha256: z5.string().refine(isSha256Hex),
|
|
4410
|
+
ciphertext_byte_length: z5.number().int().positive().max(MAX_SOLVER_SUBMISSION_CIPHERTEXT_BYTES)
|
|
4318
4411
|
}).strict();
|
|
4319
4412
|
|
|
4320
4413
|
// ../../packages/core/src/api/config.ts
|
|
4321
4414
|
import { createHash } from "crypto";
|
|
4322
|
-
import { z as
|
|
4415
|
+
import { z as z6 } from "zod";
|
|
4323
4416
|
function withDeploymentEnvDefaults(env) {
|
|
4324
4417
|
const merged = { ...env };
|
|
4325
4418
|
const setIfBlank = (key, value) => {
|
|
@@ -4340,11 +4433,11 @@ function withDeploymentEnvDefaults(env) {
|
|
|
4340
4433
|
setIfBlank("ELGORA_SUBGRAPH_ENDPOINT", deployment?.ELGORA_SUBGRAPH_ENDPOINT);
|
|
4341
4434
|
return merged;
|
|
4342
4435
|
}
|
|
4343
|
-
var chainIdField =
|
|
4436
|
+
var chainIdField = z6.coerce.number().int().positive().refine((chainId) => SUPPORTED_CHAINS[chainId] !== void 0, {
|
|
4344
4437
|
message: `ELGORA_CHAIN_ID must be a supported chain: ${Object.keys(SUPPORTED_CHAINS).join(", ")}`
|
|
4345
4438
|
});
|
|
4346
|
-
var hubAddressField =
|
|
4347
|
-
var publicDeploymentEnvSchema =
|
|
4439
|
+
var hubAddressField = z6.string().refine(isHexAddress, "ELGORA_HUB_ADDRESS must be a 20-byte EVM address").transform((value) => value.toLowerCase());
|
|
4440
|
+
var publicDeploymentEnvSchema = z6.object({
|
|
4348
4441
|
ELGORA_CHAIN_ID: chainIdField,
|
|
4349
4442
|
ELGORA_HUB_ADDRESS: hubAddressField
|
|
4350
4443
|
});
|
|
@@ -4360,40 +4453,50 @@ function loadPublicDeploymentConfig(env = process.env) {
|
|
|
4360
4453
|
var envShape = {
|
|
4361
4454
|
ELGORA_CHAIN_ID: chainIdField,
|
|
4362
4455
|
ELGORA_HUB_ADDRESS: hubAddressField,
|
|
4363
|
-
ELGORA_ESCROW_TOKEN_ADDRESS:
|
|
4456
|
+
ELGORA_ESCROW_TOKEN_ADDRESS: z6.string().refine(
|
|
4364
4457
|
isHexAddress,
|
|
4365
4458
|
"ELGORA_ESCROW_TOKEN_ADDRESS must be a 20-byte EVM address"
|
|
4366
4459
|
).transform((value) => value.toLowerCase()),
|
|
4367
|
-
ELGORA_TIMELOCK_REVEAL_DELAY_SECONDS:
|
|
4368
|
-
ELGORA_RPC_URL:
|
|
4460
|
+
ELGORA_TIMELOCK_REVEAL_DELAY_SECONDS: z6.coerce.number().int().nonnegative().default(DEFAULT_TIMELOCK_REVEAL_DELAY_SECONDS),
|
|
4461
|
+
ELGORA_RPC_URL: z6.string().min(1, "ELGORA_RPC_URL is required"),
|
|
4369
4462
|
/**
|
|
4370
4463
|
* Only consulted for a chain with no recorded deployment — a local anvil
|
|
4371
4464
|
* stack, whose addresses change on every deploy. A recorded deployment's
|
|
4372
4465
|
* scheme always wins, because settlement validation compares against it.
|
|
4373
4466
|
*/
|
|
4374
|
-
ELGORA_PAYOUT_SCHEME_ADDRESS:
|
|
4467
|
+
ELGORA_PAYOUT_SCHEME_ADDRESS: z6.string().refine(
|
|
4375
4468
|
isHexAddress,
|
|
4376
4469
|
"ELGORA_PAYOUT_SCHEME_ADDRESS must be a 20-byte EVM address"
|
|
4377
4470
|
).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:
|
|
4471
|
+
ELGORA_DATABASE_URL: z6.string().min(1, "ELGORA_DATABASE_URL is required"),
|
|
4472
|
+
ELGORA_SUBGRAPH_ENDPOINT: z6.string().min(1, "ELGORA_SUBGRAPH_ENDPOINT is required"),
|
|
4473
|
+
ELGORA_ARTIFACT_STORAGE_ENDPOINT: z6.string().min(1, "ELGORA_ARTIFACT_STORAGE_ENDPOINT is required"),
|
|
4474
|
+
ELGORA_ARTIFACT_STORAGE_REGION: z6.string().min(1, "ELGORA_ARTIFACT_STORAGE_REGION is required"),
|
|
4475
|
+
ELGORA_ARTIFACT_STORAGE_BUCKET: z6.string().min(1, "ELGORA_ARTIFACT_STORAGE_BUCKET is required"),
|
|
4476
|
+
ELGORA_ARTIFACT_STORAGE_ACCESS_KEY_ID: z6.string().min(1, "ELGORA_ARTIFACT_STORAGE_ACCESS_KEY_ID is required"),
|
|
4477
|
+
ELGORA_ARTIFACT_STORAGE_SECRET_ACCESS_KEY: z6.string().min(1, "ELGORA_ARTIFACT_STORAGE_SECRET_ACCESS_KEY is required"),
|
|
4478
|
+
ELGORA_DELIVERY_PUBLIC_KEY: z6.string().min(1, "ELGORA_DELIVERY_PUBLIC_KEY is required"),
|
|
4479
|
+
ELGORA_DELIVERY_PRIVATE_KEY: z6.string().min(1, "ELGORA_DELIVERY_PRIVATE_KEY is required")
|
|
4387
4480
|
};
|
|
4481
|
+
var readinessAudienceSchema = z6.string().trim().toLowerCase().min(1).max(512).refine((host) => {
|
|
4482
|
+
try {
|
|
4483
|
+
const url = new URL(`https://${host}`);
|
|
4484
|
+
return url.host === host && url.pathname === "/" && !url.username && !url.password && !url.search && !url.hash;
|
|
4485
|
+
} catch {
|
|
4486
|
+
return false;
|
|
4487
|
+
}
|
|
4488
|
+
}, "Must be a canonical hostname with optional port, without a URL path");
|
|
4388
4489
|
var publicationEnvShape = {
|
|
4389
4490
|
ELGORA_CHAIN_ID: envShape.ELGORA_CHAIN_ID,
|
|
4390
4491
|
ELGORA_HUB_ADDRESS: envShape.ELGORA_HUB_ADDRESS,
|
|
4391
4492
|
ELGORA_ESCROW_TOKEN_ADDRESS: envShape.ELGORA_ESCROW_TOKEN_ADDRESS,
|
|
4392
4493
|
ELGORA_DATABASE_URL: envShape.ELGORA_DATABASE_URL,
|
|
4393
|
-
ELGORA_SUBGRAPH_ENDPOINT: envShape.ELGORA_SUBGRAPH_ENDPOINT
|
|
4494
|
+
ELGORA_SUBGRAPH_ENDPOINT: envShape.ELGORA_SUBGRAPH_ENDPOINT,
|
|
4495
|
+
ELGORA_PUBLICATION_REVIEW_ENABLED: z6.string().trim().toLowerCase().pipe(z6.enum(["true", "false"])).default("true").transform((value) => value === "true"),
|
|
4496
|
+
ELGORA_READINESS_TIMEOUT_MS: z6.coerce.number().int().min(1).max(12e4).default(12e4)
|
|
4394
4497
|
};
|
|
4395
|
-
var envSchema =
|
|
4396
|
-
var bountyPublicationEnvSchema =
|
|
4498
|
+
var envSchema = z6.object(envShape);
|
|
4499
|
+
var bountyPublicationEnvSchema = z6.object(publicationEnvShape);
|
|
4397
4500
|
|
|
4398
4501
|
// ../../packages/core/src/api/elgora-hub-error-catalog.ts
|
|
4399
4502
|
import { decodeErrorResult } from "viem";
|
|
@@ -4407,55 +4510,12 @@ var ELGORA_HUB_FEE_POLICY_ABI = [
|
|
|
4407
4510
|
getAbiItem3({ abi: ELGORA_HUB_ABI, name: "guardianFeeBps" })
|
|
4408
4511
|
];
|
|
4409
4512
|
|
|
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
4513
|
// ../../packages/core/src/api/solver-submission-responses.ts
|
|
4454
|
-
import { isHex as
|
|
4514
|
+
import { isHex as isHex4 } from "viem";
|
|
4455
4515
|
import { z as z7 } from "zod";
|
|
4456
4516
|
var hexAddressSchema = z7.string().refine(isHexAddress, "Must be a hex-encoded address");
|
|
4457
4517
|
var hexBytes32Schema = z7.string().refine(isHexBytes32, "Must be 32-byte hex");
|
|
4458
|
-
var hexDataSchema = z7.string().refine((value) =>
|
|
4518
|
+
var hexDataSchema = z7.string().refine((value) => isHex4(value), "Must be hex-encoded calldata");
|
|
4459
4519
|
var artifactUploadUrlResponseSchema = z7.object({
|
|
4460
4520
|
locator: z7.string().min(1),
|
|
4461
4521
|
upload_url: z7.string().min(1),
|
|
@@ -4609,7 +4669,7 @@ var FRONTMATTER_DELIMITER2 = "---";
|
|
|
4609
4669
|
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
4670
|
var bountyIdSchema2 = z10.string().regex(/^(0|[1-9][0-9]*)$/, "Must be a non-negative integer");
|
|
4611
4671
|
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
|
|
4672
|
+
var bytes32Schema4 = z10.string().refine(isHexBytes32, "Must be 32-byte hex").refine((value) => value === value.toLowerCase(), "Must use lowercase hex").transform((value) => value);
|
|
4613
4673
|
var commonFields = {
|
|
4614
4674
|
format_version: z10.literal(WRITTEN_VERDICT_FORMAT_VERSION.toString()).transform(() => WRITTEN_VERDICT_FORMAT_VERSION),
|
|
4615
4675
|
chain_id: decimalSchema,
|
|
@@ -4625,7 +4685,7 @@ var writtenVerdictSchema = z10.discriminatedUnion("outcome", [
|
|
|
4625
4685
|
(value) => value !== zeroAddress2,
|
|
4626
4686
|
"Must not be the zero address"
|
|
4627
4687
|
),
|
|
4628
|
-
awarded_submission_commitment:
|
|
4688
|
+
awarded_submission_commitment: bytes32Schema4.refine(
|
|
4629
4689
|
(value) => value !== ZERO_BYTES32,
|
|
4630
4690
|
"Must not be zero bytes"
|
|
4631
4691
|
)
|
|
@@ -5115,6 +5175,7 @@ function defaultApiBaseUrl(env) {
|
|
|
5115
5175
|
|
|
5116
5176
|
// ../../packages/core/src/api-client.ts
|
|
5117
5177
|
var ApiRequestError = class extends Error {
|
|
5178
|
+
issues;
|
|
5118
5179
|
status;
|
|
5119
5180
|
code;
|
|
5120
5181
|
retryAfterMs;
|
|
@@ -5123,15 +5184,16 @@ var ApiRequestError = class extends Error {
|
|
|
5123
5184
|
`Request to ${input.url} failed with ${input.status}: ${formatApiError(input.body)}`
|
|
5124
5185
|
);
|
|
5125
5186
|
this.name = "ApiRequestError";
|
|
5187
|
+
this.issues = readApiErrorIssues(input.body);
|
|
5126
5188
|
this.status = input.status;
|
|
5127
5189
|
this.code = readApiErrorCode(input.body);
|
|
5128
5190
|
this.retryAfterMs = input.retryAfterMs;
|
|
5129
5191
|
}
|
|
5130
5192
|
};
|
|
5131
|
-
async function postText(url, body, contentType, authorization) {
|
|
5193
|
+
async function postText(url, body, contentType, authorization, headers = {}) {
|
|
5132
5194
|
const response = await fetch(url, {
|
|
5133
5195
|
method: "POST",
|
|
5134
|
-
headers: { "content-type": contentType, authorization },
|
|
5196
|
+
headers: { ...headers, "content-type": contentType, authorization },
|
|
5135
5197
|
body
|
|
5136
5198
|
});
|
|
5137
5199
|
return parseJsonResponse(url, response);
|
|
@@ -5236,12 +5298,11 @@ function formatApiError(body) {
|
|
|
5236
5298
|
if (body && typeof body === "object" && "error" in body && body.error && typeof body.error === "object" && "message" in body.error) {
|
|
5237
5299
|
const apiError = body.error;
|
|
5238
5300
|
const parts = [String(apiError.message)];
|
|
5239
|
-
|
|
5240
|
-
|
|
5241
|
-
|
|
5242
|
-
|
|
5243
|
-
|
|
5244
|
-
}
|
|
5301
|
+
for (const issue of readApiErrorIssues(body)) {
|
|
5302
|
+
let line = `${issue.anchor || issue.path || "request"}: ${issue.message}`;
|
|
5303
|
+
if (issue.code) line += ` [${issue.code}]`;
|
|
5304
|
+
if (issue.hazard !== void 0) line += ` (hazard: ${issue.hazard})`;
|
|
5305
|
+
parts.push(line);
|
|
5245
5306
|
}
|
|
5246
5307
|
if (apiError.next_action !== void 0 && apiError.next_action !== null) {
|
|
5247
5308
|
parts.push(`next action: ${String(apiError.next_action)}`);
|
|
@@ -5264,6 +5325,13 @@ async function assertResponseOk(url, response) {
|
|
|
5264
5325
|
retryAfterMs: readRetryAfterMs(response)
|
|
5265
5326
|
});
|
|
5266
5327
|
}
|
|
5328
|
+
function readApiErrorIssues(body) {
|
|
5329
|
+
if (!body || typeof body !== "object" || !("error" in body) || !body.error || typeof body.error !== "object" || !("issues" in body.error) || !Array.isArray(body.error.issues))
|
|
5330
|
+
return [];
|
|
5331
|
+
return body.error.issues.filter(
|
|
5332
|
+
(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")
|
|
5333
|
+
);
|
|
5334
|
+
}
|
|
5267
5335
|
function readApiErrorCode(body) {
|
|
5268
5336
|
if (!body || typeof body !== "object" || !("error" in body) || !body.error || typeof body.error !== "object" || !("code" in body.error) || typeof body.error.code !== "string") {
|
|
5269
5337
|
return void 0;
|
|
@@ -5285,7 +5353,7 @@ function toArrayBuffer(bytes) {
|
|
|
5285
5353
|
import { privateKeyToAccount as privateKeyToAccount2 } from "viem/accounts";
|
|
5286
5354
|
|
|
5287
5355
|
// ../../packages/core/src/auth/authorization-header.ts
|
|
5288
|
-
import { isAddress as isAddress3, isHex as
|
|
5356
|
+
import { isAddress as isAddress3, isHex as isHex5 } from "viem";
|
|
5289
5357
|
var ELGORA_APPROVAL_AUTH_SCHEME = "Elgora-Approval";
|
|
5290
5358
|
var FIELD_SEPARATOR = "~";
|
|
5291
5359
|
function encodeApiRequestApprovalHeader(fields) {
|
|
@@ -5298,59 +5366,27 @@ function encodeApiRequestApprovalHeader(fields) {
|
|
|
5298
5366
|
return `${ELGORA_APPROVAL_AUTH_SCHEME} ${btoa(payload)}`;
|
|
5299
5367
|
}
|
|
5300
5368
|
|
|
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();
|
|
5369
|
+
// ../../packages/core/src/auth/readiness-signoff-header.ts
|
|
5370
|
+
var ELGORA_READINESS_SIGNOFF_HEADER = "Elgora-Readiness-Signoff";
|
|
5371
|
+
function encodeReadinessSignoffHeader(signoff) {
|
|
5372
|
+
const bytes = new TextEncoder().encode(
|
|
5373
|
+
JSON.stringify(readinessSignoffSchema.parse(signoff))
|
|
5374
|
+
);
|
|
5375
|
+
return btoa(String.fromCharCode(...bytes));
|
|
5340
5376
|
}
|
|
5341
5377
|
|
|
5342
5378
|
// ../../packages/core/src/auth/request-approval.ts
|
|
5343
5379
|
import {
|
|
5344
5380
|
hashTypedData,
|
|
5345
|
-
isAddressEqual as
|
|
5381
|
+
isAddressEqual as isAddressEqual3,
|
|
5346
5382
|
keccak256 as keccak2565,
|
|
5347
5383
|
toBytes as toBytes4
|
|
5348
5384
|
} from "viem";
|
|
5349
5385
|
|
|
5350
5386
|
// ../../packages/core/src/auth/signature.ts
|
|
5351
5387
|
import {
|
|
5352
|
-
isAddressEqual,
|
|
5353
|
-
recoverTypedDataAddress as
|
|
5388
|
+
isAddressEqual as isAddressEqual2,
|
|
5389
|
+
recoverTypedDataAddress as recoverTypedDataAddress3
|
|
5354
5390
|
} from "viem";
|
|
5355
5391
|
|
|
5356
5392
|
// ../../packages/core/src/auth/request-approval-header.ts
|
|
@@ -6011,9 +6047,10 @@ function createElgoraSubgraphClient(options) {
|
|
|
6011
6047
|
);
|
|
6012
6048
|
raw = await response.text();
|
|
6013
6049
|
} catch (cause) {
|
|
6050
|
+
const code = transportErrorCode(cause);
|
|
6014
6051
|
throw new SubgraphReadError(
|
|
6015
6052
|
"transport_failed",
|
|
6016
|
-
|
|
6053
|
+
`Subgraph request did not complete${code ? ` (${code})` : ""}`,
|
|
6017
6054
|
{ cause }
|
|
6018
6055
|
);
|
|
6019
6056
|
}
|
|
@@ -6166,6 +6203,17 @@ function createElgoraSubgraphClient(options) {
|
|
|
6166
6203
|
}
|
|
6167
6204
|
};
|
|
6168
6205
|
}
|
|
6206
|
+
function transportErrorCode(error, depth = 0) {
|
|
6207
|
+
if (depth > 4 || typeof error !== "object" || error === null)
|
|
6208
|
+
return void 0;
|
|
6209
|
+
const { code, cause, errors } = error;
|
|
6210
|
+
if (typeof code === "string" && /^[A-Z][A-Z0-9_]*$/.test(code)) return code;
|
|
6211
|
+
for (const inner of [cause, ...Array.isArray(errors) ? errors : []]) {
|
|
6212
|
+
const found = transportErrorCode(inner, depth + 1);
|
|
6213
|
+
if (found) return found;
|
|
6214
|
+
}
|
|
6215
|
+
return void 0;
|
|
6216
|
+
}
|
|
6169
6217
|
var defaultFetch = (endpoint, body) => fetch(endpoint, {
|
|
6170
6218
|
method: "POST",
|
|
6171
6219
|
headers: { "content-type": "application/json" },
|
|
@@ -7100,7 +7148,7 @@ function resolveChainId(selector) {
|
|
|
7100
7148
|
}
|
|
7101
7149
|
|
|
7102
7150
|
// src/version.ts
|
|
7103
|
-
var CLI_VERSION = true ? "
|
|
7151
|
+
var CLI_VERSION = true ? "9.0.0" : "0.0.0-dev";
|
|
7104
7152
|
var CLI_NODE_ENGINES = true ? ">=24 <25" : ">=24 <25";
|
|
7105
7153
|
|
|
7106
7154
|
// src/node-engines.ts
|
|
@@ -7307,26 +7355,99 @@ function required3(env, name) {
|
|
|
7307
7355
|
}
|
|
7308
7356
|
|
|
7309
7357
|
// src/publish-fund.ts
|
|
7310
|
-
import { readFile as
|
|
7311
|
-
import { text as readStdinText3 } from "stream/consumers";
|
|
7358
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
7312
7359
|
import {
|
|
7313
7360
|
decodeFunctionData,
|
|
7314
7361
|
parseAbi as parseAbi2,
|
|
7315
7362
|
parseEventLogs
|
|
7316
7363
|
} from "viem";
|
|
7317
7364
|
import { privateKeyToAccount as privateKeyToAccount8 } from "viem/accounts";
|
|
7318
|
-
|
|
7365
|
+
|
|
7366
|
+
// src/poster-request.ts
|
|
7367
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
7368
|
+
import { text as readStdinText3 } from "stream/consumers";
|
|
7369
|
+
function loadPosterConfig(env, apiBaseUrlOverride) {
|
|
7370
|
+
const defaults = withDeploymentDefaults(env);
|
|
7371
|
+
const clientConfig = loadClientDeploymentConfig(defaults, apiBaseUrlOverride);
|
|
7372
|
+
const rpcUrl = defaults.ELGORA_RPC_URL?.trim();
|
|
7373
|
+
if (!rpcUrl) throw new Error("ELGORA_RPC_URL is required");
|
|
7374
|
+
const privateKey = env.ELGORA_POSTER_PRIVATE_KEY?.trim();
|
|
7375
|
+
if (!privateKey || !isHexBytes32(privateKey)) {
|
|
7376
|
+
throw new Error(
|
|
7377
|
+
"ELGORA_POSTER_PRIVATE_KEY must be a 32-byte hex private key"
|
|
7378
|
+
);
|
|
7379
|
+
}
|
|
7380
|
+
return {
|
|
7381
|
+
...clientConfig,
|
|
7382
|
+
rpcUrl,
|
|
7383
|
+
posterPrivateKey: privateKey
|
|
7384
|
+
};
|
|
7385
|
+
}
|
|
7386
|
+
function takeFlag(argv, flag, usage) {
|
|
7387
|
+
const uses = argv.filter(
|
|
7388
|
+
(arg) => arg === flag || arg.startsWith(`${flag}=`)
|
|
7389
|
+
).length;
|
|
7390
|
+
const extracted = extractFlagValue(argv, flag);
|
|
7391
|
+
if (uses > 1 || uses === 1 && (!extracted.value || extracted.value.startsWith("--")))
|
|
7392
|
+
throw new Error(usage);
|
|
7393
|
+
return extracted;
|
|
7394
|
+
}
|
|
7395
|
+
async function readBountyChallengeMarkdown2(path5) {
|
|
7396
|
+
return path5 === "-" ? readStdinText3(process.stdin) : readFile4(path5, "utf8");
|
|
7397
|
+
}
|
|
7398
|
+
async function signPosterRequest(input) {
|
|
7399
|
+
return buildAuthorizationHeader({
|
|
7400
|
+
requestUrl: input.requestUrl.toString(),
|
|
7401
|
+
method: "POST",
|
|
7402
|
+
body: input.markdown,
|
|
7403
|
+
chainId: input.config.chainId,
|
|
7404
|
+
hubAddress: input.config.hubAddress,
|
|
7405
|
+
address: input.account.address,
|
|
7406
|
+
block: await fetchSignableBlock(input.publicClient),
|
|
7407
|
+
sign: (typedData) => input.account.signTypedData(typedData)
|
|
7408
|
+
});
|
|
7409
|
+
}
|
|
7410
|
+
|
|
7411
|
+
// src/publish-fund.ts
|
|
7412
|
+
var PUBLISH_FUND_USAGE = "Usage: elgora-cli poster:publish-fund <bounty_challenge_md_path|-> --signoff <file>";
|
|
7319
7413
|
var usdcAbi = parseAbi2([
|
|
7320
7414
|
"function approve(address spender,uint256 value) returns (bool)",
|
|
7321
7415
|
"function balanceOf(address account) view returns (uint256)"
|
|
7322
7416
|
]);
|
|
7323
7417
|
async function main9(env = process.env, argv = process.argv.slice(2)) {
|
|
7324
|
-
const { apiBaseUrl: apiBaseUrlOverride, argv:
|
|
7325
|
-
const
|
|
7326
|
-
|
|
7327
|
-
|
|
7418
|
+
const { apiBaseUrl: apiBaseUrlOverride, argv: afterApiBaseUrl } = extractApiBaseUrlFlag(argv);
|
|
7419
|
+
const { value: signoffPath, argv: remainingArgv } = takeFlag(
|
|
7420
|
+
afterApiBaseUrl,
|
|
7421
|
+
"--signoff",
|
|
7422
|
+
PUBLISH_FUND_USAGE
|
|
7423
|
+
);
|
|
7424
|
+
if (!signoffPath || remainingArgv.length !== 1 || !remainingArgv[0])
|
|
7425
|
+
throw new Error(PUBLISH_FUND_USAGE);
|
|
7426
|
+
const config = loadPosterConfig(env, apiBaseUrlOverride);
|
|
7427
|
+
const escrowTokenAddress = withDeploymentDefaults(env).ELGORA_ESCROW_TOKEN_ADDRESS?.trim();
|
|
7428
|
+
if (!escrowTokenAddress || !isHexAddress(escrowTokenAddress)) {
|
|
7429
|
+
throw new Error(
|
|
7430
|
+
"ELGORA_ESCROW_TOKEN_ADDRESS must be a 20-byte EVM address"
|
|
7431
|
+
);
|
|
7432
|
+
}
|
|
7433
|
+
const tokenAddress = escrowTokenAddress.toLowerCase();
|
|
7434
|
+
const bountyChallengeMarkdown = await readBountyChallengeMarkdown2(
|
|
7435
|
+
remainingArgv[0]
|
|
7436
|
+
);
|
|
7437
|
+
const localSpecCommitment = deriveBountyChallengeContentCommitment(
|
|
7438
|
+
bountyChallengeMarkdown
|
|
7439
|
+
);
|
|
7440
|
+
const signoff = readinessSignoffSchema.parse(
|
|
7441
|
+
JSON.parse(await readFile5(signoffPath, "utf8"))
|
|
7328
7442
|
);
|
|
7329
|
-
|
|
7443
|
+
if (signoff.spec_commitment.toLowerCase() !== localSpecCommitment) {
|
|
7444
|
+
throw new Error(
|
|
7445
|
+
"Readiness sign-off does not match the exact bounty_challenge.md bytes. Run poster:review again."
|
|
7446
|
+
);
|
|
7447
|
+
}
|
|
7448
|
+
if (signoff.expires_at <= Math.floor(Date.now() / 1e3)) {
|
|
7449
|
+
throw new Error("Readiness sign-off has expired. Run poster:review again.");
|
|
7450
|
+
}
|
|
7330
7451
|
const account = privateKeyToAccount8(config.posterPrivateKey);
|
|
7331
7452
|
const publicClient = createChainPublicClient(config.chainId, config.rpcUrl);
|
|
7332
7453
|
const walletClient = createChainWalletClient(
|
|
@@ -7340,31 +7461,25 @@ async function main9(env = process.env, argv = process.argv.slice(2)) {
|
|
|
7340
7461
|
config.apiBaseUrl
|
|
7341
7462
|
);
|
|
7342
7463
|
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)
|
|
7464
|
+
const authorization = await signPosterRequest({
|
|
7465
|
+
requestUrl,
|
|
7466
|
+
markdown: bountyChallengeMarkdown,
|
|
7467
|
+
config,
|
|
7468
|
+
account,
|
|
7469
|
+
publicClient
|
|
7353
7470
|
});
|
|
7354
7471
|
const prepared = await requestPreparePublication({
|
|
7355
7472
|
requestUrl: requestUrl.toString(),
|
|
7356
7473
|
markdown: bountyChallengeMarkdown,
|
|
7357
|
-
authorization
|
|
7474
|
+
authorization,
|
|
7475
|
+
signoff: encodeReadinessSignoffHeader(signoff)
|
|
7358
7476
|
});
|
|
7359
|
-
const localSpecCommitment = deriveBountyChallengeContentCommitment(
|
|
7360
|
-
bountyChallengeMarkdown
|
|
7361
|
-
);
|
|
7362
7477
|
if (prepared.content_record.spec_commitment !== localSpecCommitment) {
|
|
7363
7478
|
throw new Error(
|
|
7364
7479
|
"Elgora API returned a spec_commitment that does not match the locally submitted bounty_challenge.md"
|
|
7365
7480
|
);
|
|
7366
7481
|
}
|
|
7367
|
-
if (prepared.create_bounty_transaction.chain_id !== config.chainId || prepared.create_bounty_transaction.to !== config.hubAddress || prepared.content_record.token_address !==
|
|
7482
|
+
if (prepared.create_bounty_transaction.chain_id !== config.chainId || prepared.create_bounty_transaction.to !== config.hubAddress || prepared.content_record.token_address !== tokenAddress) {
|
|
7368
7483
|
throw new Error(
|
|
7369
7484
|
"Elgora API returned a create_bounty_transaction that does not match the locally configured deployment (chain id, hub address, or escrow token)"
|
|
7370
7485
|
);
|
|
@@ -7386,7 +7501,7 @@ async function main9(env = process.env, argv = process.argv.slice(2)) {
|
|
|
7386
7501
|
const [ethBalance, usdcBalance] = await Promise.all([
|
|
7387
7502
|
publicClient.getBalance({ address: account.address }),
|
|
7388
7503
|
publicClient.readContract({
|
|
7389
|
-
address:
|
|
7504
|
+
address: tokenAddress,
|
|
7390
7505
|
abi: usdcAbi,
|
|
7391
7506
|
functionName: "balanceOf",
|
|
7392
7507
|
args: [account.address]
|
|
@@ -7402,7 +7517,7 @@ async function main9(env = process.env, argv = process.argv.slice(2)) {
|
|
|
7402
7517
|
}
|
|
7403
7518
|
const authorized = await prepareAuthorizedCreateBountyTransaction({
|
|
7404
7519
|
transaction: prepared.create_bounty_transaction,
|
|
7405
|
-
tokenAddress
|
|
7520
|
+
tokenAddress,
|
|
7406
7521
|
poster: account.address,
|
|
7407
7522
|
publicClient,
|
|
7408
7523
|
sign: (typedData) => account.signTypedData(typedData)
|
|
@@ -7423,7 +7538,7 @@ async function main9(env = process.env, argv = process.argv.slice(2)) {
|
|
|
7423
7538
|
});
|
|
7424
7539
|
} else {
|
|
7425
7540
|
const approveHash = await walletClient.writeContract({
|
|
7426
|
-
address:
|
|
7541
|
+
address: tokenAddress,
|
|
7427
7542
|
abi: usdcAbi,
|
|
7428
7543
|
functionName: "approve",
|
|
7429
7544
|
args: [config.hubAddress, escrowAmount]
|
|
@@ -7497,60 +7612,106 @@ async function requestPreparePublication(input) {
|
|
|
7497
7612
|
new URL(input.requestUrl),
|
|
7498
7613
|
input.markdown,
|
|
7499
7614
|
"text/markdown",
|
|
7500
|
-
input.authorization
|
|
7615
|
+
input.authorization,
|
|
7616
|
+
{ [ELGORA_READINESS_SIGNOFF_HEADER]: input.signoff }
|
|
7501
7617
|
);
|
|
7502
7618
|
return bountyPublicationResponseSchema.parse(body);
|
|
7503
7619
|
}
|
|
7504
|
-
|
|
7505
|
-
|
|
7506
|
-
|
|
7507
|
-
|
|
7508
|
-
}
|
|
7509
|
-
if (path5 === "-") {
|
|
7510
|
-
return readStdinText3(process.stdin);
|
|
7511
|
-
}
|
|
7512
|
-
return readFile4(path5, "utf8");
|
|
7620
|
+
|
|
7621
|
+
// src/required-env.ts
|
|
7622
|
+
function missingRequiredEnv(required4, env) {
|
|
7623
|
+
return required4.filter((envName) => !env[envName]?.trim());
|
|
7513
7624
|
}
|
|
7514
|
-
|
|
7515
|
-
|
|
7516
|
-
|
|
7517
|
-
|
|
7518
|
-
|
|
7519
|
-
|
|
7520
|
-
|
|
7521
|
-
|
|
7522
|
-
|
|
7523
|
-
|
|
7625
|
+
|
|
7626
|
+
// src/review.ts
|
|
7627
|
+
import { writeFile as writeFile3 } from "fs/promises";
|
|
7628
|
+
import { resolve } from "path";
|
|
7629
|
+
import { privateKeyToAccount as privateKeyToAccount9 } from "viem/accounts";
|
|
7630
|
+
var USAGE2 = "Usage: elgora-cli poster:review <path|-> [--previous <commitment>] [--signoff-out <file>]";
|
|
7631
|
+
async function main10(env = process.env, argv = process.argv.slice(2)) {
|
|
7632
|
+
const { apiBaseUrl, argv: args } = extractApiBaseUrlFlag(argv);
|
|
7633
|
+
const { value: previous, argv: afterPrevious } = takeFlag(
|
|
7634
|
+
args,
|
|
7635
|
+
"--previous",
|
|
7636
|
+
"--previous must be one bytes32 page commitment"
|
|
7637
|
+
);
|
|
7638
|
+
if (previous && !isHexBytes32(previous))
|
|
7639
|
+
throw new Error("--previous must be one bytes32 page commitment");
|
|
7640
|
+
const { value: signoffOut, argv: paths } = takeFlag(
|
|
7641
|
+
afterPrevious,
|
|
7642
|
+
"--signoff-out",
|
|
7643
|
+
USAGE2
|
|
7644
|
+
);
|
|
7645
|
+
if (paths.length !== 1 || !paths[0] || paths[0].startsWith("--"))
|
|
7646
|
+
throw new Error(USAGE2);
|
|
7647
|
+
if (signoffOut && paths[0] !== "-" && resolve(signoffOut) === resolve(paths[0]))
|
|
7648
|
+
throw new Error("--signoff-out must not overwrite the bounty draft");
|
|
7649
|
+
const config = loadPosterConfig(env, apiBaseUrl);
|
|
7650
|
+
const markdown = await readBountyChallengeMarkdown2(paths[0]);
|
|
7651
|
+
const commitment = deriveBountyChallengeContentCommitment(markdown);
|
|
7652
|
+
const account = privateKeyToAccount9(config.posterPrivateKey);
|
|
7653
|
+
const publicClient = createChainPublicClient(config.chainId, config.rpcUrl);
|
|
7654
|
+
await assertHubDeployment(publicClient, config.chainId, config.hubAddress);
|
|
7655
|
+
const requestUrl = new URL(
|
|
7656
|
+
"/api/bounty-challenge-specs/review",
|
|
7657
|
+
config.apiBaseUrl
|
|
7658
|
+
);
|
|
7659
|
+
requestUrl.searchParams.set("poster_address", account.address);
|
|
7660
|
+
if (previous)
|
|
7661
|
+
requestUrl.searchParams.set("previous_spec_commitment", previous);
|
|
7662
|
+
const authorization = await signPosterRequest({
|
|
7663
|
+
requestUrl,
|
|
7664
|
+
markdown,
|
|
7665
|
+
config,
|
|
7666
|
+
account,
|
|
7667
|
+
publicClient
|
|
7668
|
+
});
|
|
7669
|
+
let response;
|
|
7670
|
+
try {
|
|
7671
|
+
response = bountyReviewResponseSchema.parse(
|
|
7672
|
+
await postText(requestUrl, markdown, "text/markdown", authorization)
|
|
7524
7673
|
);
|
|
7674
|
+
} catch (error) {
|
|
7675
|
+
if (error instanceof ApiRequestError && error.code === "bounty_challenge_not_ready") {
|
|
7676
|
+
console.log(
|
|
7677
|
+
JSON.stringify({ event: "review.not_ready", issues: error.issues })
|
|
7678
|
+
);
|
|
7679
|
+
process.exitCode = 2;
|
|
7680
|
+
return;
|
|
7681
|
+
}
|
|
7682
|
+
throw error;
|
|
7525
7683
|
}
|
|
7526
|
-
|
|
7527
|
-
if (!escrowTokenAddress || !isHexAddress(escrowTokenAddress)) {
|
|
7684
|
+
if (response.content_record.spec_commitment !== commitment) {
|
|
7528
7685
|
throw new Error(
|
|
7529
|
-
"
|
|
7686
|
+
"Elgora API returned a review for different bounty_challenge.md bytes"
|
|
7530
7687
|
);
|
|
7531
7688
|
}
|
|
7532
|
-
|
|
7533
|
-
|
|
7534
|
-
|
|
7535
|
-
|
|
7536
|
-
|
|
7537
|
-
|
|
7538
|
-
|
|
7539
|
-
|
|
7540
|
-
|
|
7541
|
-
|
|
7542
|
-
|
|
7689
|
+
if (signoffOut)
|
|
7690
|
+
await writeFile3(
|
|
7691
|
+
signoffOut,
|
|
7692
|
+
`${JSON.stringify(response.readiness.signoff, null, 2)}
|
|
7693
|
+
`
|
|
7694
|
+
);
|
|
7695
|
+
console.log(
|
|
7696
|
+
JSON.stringify({
|
|
7697
|
+
event: "review.ready",
|
|
7698
|
+
spec_commitment: commitment,
|
|
7699
|
+
signoff: response.readiness.signoff,
|
|
7700
|
+
prior_issues_resolved: response.readiness.prior_issues_resolved,
|
|
7701
|
+
prior_issues_open: response.readiness.prior_issues_open
|
|
7702
|
+
})
|
|
7703
|
+
);
|
|
7543
7704
|
}
|
|
7544
7705
|
|
|
7545
7706
|
// src/roster-add-guardian.ts
|
|
7546
7707
|
import { isAddress as isAddress4 } from "viem";
|
|
7547
|
-
import { privateKeyToAccount as
|
|
7708
|
+
import { privateKeyToAccount as privateKeyToAccount10 } from "viem/accounts";
|
|
7548
7709
|
var ROSTER_ADMIN_ADDRESS_FLAG = "--roster-admin-address";
|
|
7549
7710
|
var ENCRYPTION_PUBLIC_KEY_RE = /^[A-Za-z0-9_-]{43}$/;
|
|
7550
|
-
async function
|
|
7711
|
+
async function main11(env = process.env, argv = process.argv.slice(2)) {
|
|
7551
7712
|
const args = parseRosterAddGuardianArgs(argv);
|
|
7552
7713
|
const config = loadRosterAddGuardianConfig(env, args.rosterAdminAddress);
|
|
7553
|
-
const account = config.rosterAdminPrivateKey ?
|
|
7714
|
+
const account = config.rosterAdminPrivateKey ? privateKeyToAccount10(config.rosterAdminPrivateKey) : null;
|
|
7554
7715
|
const rosterAdmin = account?.address ?? args.rosterAdminAddress;
|
|
7555
7716
|
if (!rosterAdmin) throw new Error("Roster admin address is required");
|
|
7556
7717
|
const normalizedRosterAdmin = rosterAdmin.toLowerCase();
|
|
@@ -7718,7 +7879,7 @@ function usageError2() {
|
|
|
7718
7879
|
// src/roster-prepare-guardian-proof.ts
|
|
7719
7880
|
import { isAddress as isAddress5 } from "viem";
|
|
7720
7881
|
var ENCRYPTION_PUBLIC_KEY_RE2 = /^[A-Za-z0-9_-]{43}$/;
|
|
7721
|
-
async function
|
|
7882
|
+
async function main12(env = process.env, argv = process.argv.slice(2)) {
|
|
7722
7883
|
const args = parseArgs(argv);
|
|
7723
7884
|
const envWithDefaults = withDeploymentDefaults(env);
|
|
7724
7885
|
const { chainId, hubAddress } = loadPublicDeploymentConfig(envWithDefaults);
|
|
@@ -7765,17 +7926,17 @@ function usageError3() {
|
|
|
7765
7926
|
}
|
|
7766
7927
|
|
|
7767
7928
|
// src/roster-verify-guardian-proof.ts
|
|
7768
|
-
import { readFile as
|
|
7769
|
-
import { isAddress as isAddress6, isHex as
|
|
7770
|
-
async function
|
|
7929
|
+
import { readFile as readFile6 } from "fs/promises";
|
|
7930
|
+
import { isAddress as isAddress6, isHex as isHex6, recoverMessageAddress } from "viem";
|
|
7931
|
+
async function main13(_env = process.env, argv = process.argv.slice(2)) {
|
|
7771
7932
|
const [preparedPath, responsePath] = argv;
|
|
7772
7933
|
if (!preparedPath || !responsePath) {
|
|
7773
7934
|
throw new Error(
|
|
7774
7935
|
"Usage: elgora-cli roster:verify-guardian-proof <prepared_json_path> <response_json_path>"
|
|
7775
7936
|
);
|
|
7776
7937
|
}
|
|
7777
|
-
const prepared = parsePrepared(await
|
|
7778
|
-
const response = parseResponse(await
|
|
7938
|
+
const prepared = parsePrepared(await readFile6(preparedPath, "utf8"));
|
|
7939
|
+
const response = parseResponse(await readFile6(responsePath, "utf8"));
|
|
7779
7940
|
const fixture = base64UrlToBytes(prepared.fixture);
|
|
7780
7941
|
const signedPayload = buildGuardianRosterKeyProofSignedPayload(
|
|
7781
7942
|
prepared.message,
|
|
@@ -7839,7 +8000,7 @@ function parseResponse(text) {
|
|
|
7839
8000
|
}
|
|
7840
8001
|
const guardianAccount = get(parsed, "guardian_account");
|
|
7841
8002
|
const signature = get(parsed, "signature");
|
|
7842
|
-
if (typeof guardianAccount !== "string" || !isAddress6(guardianAccount) || typeof signature !== "string" || !
|
|
8003
|
+
if (typeof guardianAccount !== "string" || !isAddress6(guardianAccount) || typeof signature !== "string" || !isHex6(signature) || signature.length !== 132) {
|
|
7843
8004
|
throw new Error(
|
|
7844
8005
|
"Guardian response JSON must be the unmodified stdout of guardian:prove-roster-key"
|
|
7845
8006
|
);
|
|
@@ -7857,10 +8018,10 @@ function get(value, key) {
|
|
|
7857
8018
|
}
|
|
7858
8019
|
|
|
7859
8020
|
// src/spec-commitment.ts
|
|
7860
|
-
import { readFile as
|
|
8021
|
+
import { readFile as readFile7 } from "fs/promises";
|
|
7861
8022
|
import { text as readStdinText4 } from "stream/consumers";
|
|
7862
8023
|
var SPEC_COMMITMENT_USAGE = "Usage: elgora-cli spec-commitment <bounty_challenge_md_path>\n or: elgora-cli spec-commitment -";
|
|
7863
|
-
async function
|
|
8024
|
+
async function main14(_env = process.env, argv = process.argv.slice(2)) {
|
|
7864
8025
|
const markdown = await readBountyChallengeMarkdown3(argv);
|
|
7865
8026
|
const specCommitment = deriveBountyChallengeContentCommitment(markdown);
|
|
7866
8027
|
console.log(
|
|
@@ -7879,23 +8040,23 @@ async function readBountyChallengeMarkdown3(argv) {
|
|
|
7879
8040
|
if (path5 === "-") {
|
|
7880
8041
|
return readStdinText4(process.stdin);
|
|
7881
8042
|
}
|
|
7882
|
-
return
|
|
8043
|
+
return readFile7(path5, "utf8");
|
|
7883
8044
|
}
|
|
7884
8045
|
|
|
7885
8046
|
// src/submit.ts
|
|
7886
|
-
import { readdir, readFile as
|
|
8047
|
+
import { readdir, readFile as readFile8, stat } from "fs/promises";
|
|
7887
8048
|
import path3 from "path";
|
|
7888
8049
|
import { createInterface } from "readline";
|
|
7889
8050
|
import { isAddress as isAddress7 } from "viem";
|
|
7890
|
-
import { privateKeyToAccount as
|
|
8051
|
+
import { privateKeyToAccount as privateKeyToAccount11 } from "viem/accounts";
|
|
7891
8052
|
|
|
7892
8053
|
// src/external-api-approval-signer.ts
|
|
7893
|
-
import { isHex as
|
|
8054
|
+
import { isHex as isHex7 } from "viem";
|
|
7894
8055
|
function createExternalApiApprovalSigner(input) {
|
|
7895
8056
|
return async (typedData) => {
|
|
7896
8057
|
input.writePrompt(input.renderPrompt(typedData));
|
|
7897
8058
|
const signature = (await input.readSignature())?.trim();
|
|
7898
|
-
if (!signature || signature === "0x" || !
|
|
8059
|
+
if (!signature || signature === "0x" || !isHex7(signature)) {
|
|
7899
8060
|
throw new Error(
|
|
7900
8061
|
"External signer must return one non-empty 0x-prefixed hex signature line on stdin"
|
|
7901
8062
|
);
|
|
@@ -7937,13 +8098,13 @@ var MEDIA_TYPE_BY_EXTENSION = {
|
|
|
7937
8098
|
diff: "text/x-diff"
|
|
7938
8099
|
};
|
|
7939
8100
|
var DEFAULT_MEDIA_TYPE = "application/octet-stream";
|
|
7940
|
-
async function
|
|
8101
|
+
async function main15(env = process.env, argv = process.argv.slice(2)) {
|
|
7941
8102
|
const { solverAddress, argv: argvWithoutSolverAddress } = extractSolverAddressFlag(argv);
|
|
7942
8103
|
const { apiBaseUrl: apiBaseUrlOverride, argv: remainingArgv } = extractApiBaseUrlFlag(argvWithoutSolverAddress);
|
|
7943
8104
|
const config = loadSubmitConfig(env, apiBaseUrlOverride, solverAddress);
|
|
7944
8105
|
const args = readSubmitArgs(remainingArgv);
|
|
7945
8106
|
const bountyIdText = args.bountyId.toString();
|
|
7946
|
-
const account = config.solverPrivateKey ?
|
|
8107
|
+
const account = config.solverPrivateKey ? privateKeyToAccount11(config.solverPrivateKey) : null;
|
|
7947
8108
|
const solverAddressFromConfig = account?.address ?? config.solverAddress;
|
|
7948
8109
|
if (!solverAddressFromConfig) throw new Error("Solver address is required");
|
|
7949
8110
|
const solver = solverAddressFromConfig.toLowerCase();
|
|
@@ -8335,7 +8496,7 @@ async function readArtifactDirectory(artifactDir) {
|
|
|
8335
8496
|
}
|
|
8336
8497
|
return Promise.all(
|
|
8337
8498
|
entries.map(async (entry) => {
|
|
8338
|
-
const bytes = await
|
|
8499
|
+
const bytes = await readFile8(path3.join(artifactDir, entry.name));
|
|
8339
8500
|
return {
|
|
8340
8501
|
name: entry.name,
|
|
8341
8502
|
media_type: guessMediaType(entry.name),
|
|
@@ -8404,7 +8565,7 @@ async function requestPrepareSubmission(input) {
|
|
|
8404
8565
|
})
|
|
8405
8566
|
);
|
|
8406
8567
|
}
|
|
8407
|
-
await new Promise((
|
|
8568
|
+
await new Promise((resolve2) => setTimeout(resolve2, retryDelay));
|
|
8408
8569
|
}
|
|
8409
8570
|
}
|
|
8410
8571
|
}
|
|
@@ -8448,7 +8609,7 @@ function readTimelockRevealDelaySeconds(env) {
|
|
|
8448
8609
|
|
|
8449
8610
|
// src/verification-record.ts
|
|
8450
8611
|
var VERIFICATION_RECORD_USAGE = "Usage: elgora-cli verification-record <bounty_id>";
|
|
8451
|
-
async function
|
|
8612
|
+
async function main16(env = process.env, argv = process.argv.slice(2)) {
|
|
8452
8613
|
const { apiBaseUrl: apiBaseUrlOverride, argv: remainingArgv } = extractApiBaseUrlFlag(argv);
|
|
8453
8614
|
const args = readVerificationRecordArgs(remainingArgv);
|
|
8454
8615
|
const envWithDefaults = withDeploymentDefaults(env);
|
|
@@ -8533,15 +8694,16 @@ var COMMANDS = {
|
|
|
8533
8694
|
"guardian:verdict": main7,
|
|
8534
8695
|
"guardian:deliver-key": main4,
|
|
8535
8696
|
"poster:open-winning-submission": main8,
|
|
8697
|
+
"poster:review": main10,
|
|
8536
8698
|
"poster:publish-fund": main9,
|
|
8537
|
-
"roster:add-guardian":
|
|
8538
|
-
"roster:prepare-guardian-proof":
|
|
8539
|
-
"roster:verify-guardian-proof":
|
|
8540
|
-
"solver:submit":
|
|
8699
|
+
"roster:add-guardian": main11,
|
|
8700
|
+
"roster:prepare-guardian-proof": main12,
|
|
8701
|
+
"roster:verify-guardian-proof": main13,
|
|
8702
|
+
"solver:submit": main15,
|
|
8541
8703
|
claim: main2,
|
|
8542
8704
|
"check-page": main,
|
|
8543
|
-
"spec-commitment":
|
|
8544
|
-
"verification-record":
|
|
8705
|
+
"spec-commitment": main14,
|
|
8706
|
+
"verification-record": main16
|
|
8545
8707
|
};
|
|
8546
8708
|
var COMMAND_HELP = {
|
|
8547
8709
|
"guardian:judgeable": {
|
|
@@ -8610,10 +8772,23 @@ var COMMAND_HELP = {
|
|
|
8610
8772
|
],
|
|
8611
8773
|
apiBaseUrlFlag: true
|
|
8612
8774
|
},
|
|
8775
|
+
"poster:review": {
|
|
8776
|
+
usage: "elgora-cli poster:review <path|-> [--previous <commitment>] [--signoff-out <file>]",
|
|
8777
|
+
title: "Review a bounty page and save its readiness certificate.",
|
|
8778
|
+
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.",
|
|
8779
|
+
required: ["ELGORA_POSTER_PRIVATE_KEY"],
|
|
8780
|
+
defaulted: [
|
|
8781
|
+
"ELGORA_CHAIN_ID",
|
|
8782
|
+
"ELGORA_HUB_ADDRESS",
|
|
8783
|
+
"ELGORA_RPC_URL",
|
|
8784
|
+
"ELGORA_API_BASE_URL"
|
|
8785
|
+
],
|
|
8786
|
+
apiBaseUrlFlag: true
|
|
8787
|
+
},
|
|
8613
8788
|
"poster:publish-fund": {
|
|
8614
|
-
usage: "elgora-cli poster:publish-fund <bounty_challenge_md_path|->",
|
|
8789
|
+
usage: "elgora-cli poster:publish-fund <bounty_challenge_md_path|-> --signoff <file>",
|
|
8615
8790
|
title: "Publish an approved challenge and fund its bounty.",
|
|
8616
|
-
description: "Read the exact approved bounty_challenge.md bytes and
|
|
8791
|
+
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
8792
|
required: ["ELGORA_POSTER_PRIVATE_KEY"],
|
|
8618
8793
|
defaulted: [
|
|
8619
8794
|
"ELGORA_CHAIN_ID",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elgora/cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "9.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",
|