@molpha/sdk 0.2.0-dev-20260913100330 → 0.2.0-dev-20261001084453

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -45,8 +45,8 @@ Every signed attestation commits to the same message across chains:
45
45
 
46
46
  ```text
47
47
  message = keccak256(
48
- keccak256("MOLPHA_MESSAGE_V1") || sourceId || u32be(registryVersion) ||
49
- u32be(signaturesRequired) || signersBitmap || value || u64be(canonicalTimestamp)
48
+ keccak256("MOLPHA_MESSAGE_V1") || value || sourceId || u32be(registryVersion) ||
49
+ u8(signaturesRequired) || u64be(canonicalTimestamp) || signersBitmap
50
50
  )
51
51
  ```
52
52
 
@@ -290,6 +290,13 @@ The returned `DataUpdateResult` includes `sourceId`, the signed value, canonical
290
290
  const { signature, feed } = await sdk.solana.submitAttestation(result);
291
291
  ```
292
292
 
293
+ If the signed 32-byte value is the keccak digest of a longer preimage, provide the
294
+ preimage explicitly (up to 256 bytes). The SDK verifies the digest before sending:
295
+
296
+ ```ts
297
+ const { signature, feed } = await sdk.solana.submitAttestation(result, { rawValue });
298
+ ```
299
+
293
300
  Then read the feed this wallet wrote for that source and quorum:
294
301
 
295
302
  ```ts
@@ -455,90 +462,120 @@ Supported network ids (selection helpers only): `evm-sepolia`, `arbitrum-sepolia
455
462
 
456
463
  ### Build verifier arguments
457
464
 
465
+ The verifier's entrypoint is
466
+ `verify(Attestation attestation, uint64 maxAge) returns (bool success, uint8 code)`.
467
+
458
468
  ```ts
459
469
  import { buildEvmVerifierArgs } from "@molpha/sdk";
460
470
 
461
471
  const result = await sdk.gateway.requestSignedData({ apiConfig, signaturesRequired });
462
472
 
463
- const { dataUpdate, signature } = buildEvmVerifierArgs(result);
473
+ const { attestation, maxAge } = buildEvmVerifierArgs(result, { maxAge: 300 });
464
474
  ```
465
475
 
466
- The generated tuples match the Molpha EVM verifier ABI:
476
+ `maxAge` is required. It is the freshness window in seconds: the verifier reports an older
477
+ attestation as `STALE`, and one dated after `block.timestamp` as `MALFORMED`. `0` disables the
478
+ check entirely — pass it only when your contract enforces freshness or ordering itself, because
479
+ a stateless verifier otherwise accepts a correctly signed attestation forever.
467
480
 
468
- ```ts
469
- // dataUpdate:
470
- // [bytes32 sourceId,
471
- // uint32 registryVersion,
472
- // uint32 signaturesRequired,
473
- // bytes32 valuePacked,
474
- // uint64 timestamp]
481
+ The generated object matches the Solidity `IVerifier.Attestation` struct, using viem's
482
+ primitive types so it passes straight into `readContract` or an ethers `Contract`. Member
483
+ order is ABI order (and the signed message's order), so it differs from `DataUpdateResult`:
475
484
 
476
- // signature:
477
- // [bytes32 s,
478
- // address commitment,
479
- // uint256 signersBitmap]
485
+ ```ts
486
+ attestation:
487
+ {
488
+ payload: {
489
+ value: `0x${string}`, // bytes32 (result.valuePacked)
490
+ sourceId: `0x${string}`, // bytes32
491
+ registryVersion: number, // uint32
492
+ signaturesRequired: number, // uint8
493
+ canonicalTimestamp: bigint, // uint64 (result.timestamp)
494
+ },
495
+ signature: {
496
+ signature: `0x${string}`, // bytes32 (result.s)
497
+ commitment: `0x${string}`, // address (result.commitmentAddr)
498
+ signersBitmap: bigint, // uint256
499
+ },
500
+ }
501
+ maxAge: bigint // uint64
480
502
  ```
481
503
 
482
- Note: the deployed contract's source names the first struct field `jobId`; the SDK ABI names it `sourceId` (component names do not affect encoding) and the value is the 32-byte source id.
504
+ The builder range-checks every integer against its Solidity type. Out-of-range calldata never
505
+ reaches `verify`: the ABI decoder reverts on it instead of returning a result code.
483
506
 
484
- ### ethers
507
+ ### viem
485
508
 
486
509
  ```ts
487
- import { Contract } from "ethers";
510
+ import { createPublicClient, http } from "viem";
488
511
  import {
489
512
  buildEvmVerifierArgs,
513
+ MOLPHA_VERIFIER_ABI,
490
514
  MOLPHA_VERIFIER_ADDRESS,
515
+ parseEvmVerifyResult,
491
516
  } from "@molpha/sdk";
492
517
 
493
- const verifier = new Contract(
494
- MOLPHA_VERIFIER_ADDRESS,
495
- abi,
496
- signer,
497
- );
518
+ const client = createPublicClient({ chain, transport: http() });
519
+ const { attestation, maxAge } = buildEvmVerifierArgs(result, { maxAge: 300 });
498
520
 
499
- const { dataUpdate, signature } = buildEvmVerifierArgs(result);
521
+ const returned = await client.readContract({
522
+ address: MOLPHA_VERIFIER_ADDRESS,
523
+ abi: MOLPHA_VERIFIER_ABI,
524
+ functionName: "verify",
525
+ args: [attestation, maxAge],
526
+ });
500
527
 
501
- await verifier.verify(dataUpdate, signature);
528
+ const { success, code, reason } = parseEvmVerifyResult(returned);
529
+ // { success: true, code: 0, reason: "OK" }
530
+ // { success: false, code: 10, reason: "STALE" }
502
531
  ```
503
532
 
504
- ### viem
533
+ ### ethers
505
534
 
506
535
  ```ts
507
- import { createPublicClient, http } from "viem";
536
+ import { Contract } from "ethers";
508
537
  import {
509
538
  buildEvmVerifierArgs,
510
539
  MOLPHA_VERIFIER_ABI,
511
540
  MOLPHA_VERIFIER_ADDRESS,
541
+ parseEvmVerifyResult,
512
542
  } from "@molpha/sdk";
513
543
 
514
- const client = createPublicClient({
515
- chain,
516
- transport: http(),
517
- });
544
+ const verifier = new Contract(MOLPHA_VERIFIER_ADDRESS, MOLPHA_VERIFIER_ABI, provider);
545
+ const { attestation, maxAge } = buildEvmVerifierArgs(result, { maxAge: 300 });
518
546
 
519
- const { dataUpdate, signature } = buildEvmVerifierArgs(result);
547
+ const { success, code, reason } = parseEvmVerifyResult(await verifier.verify(attestation, maxAge));
548
+ ```
520
549
 
521
- await client.readContract({
522
- address: MOLPHA_VERIFIER_ADDRESS,
523
- abi: MOLPHA_VERIFIER_ABI,
524
- functionName: "verify",
525
- args: [
526
- {
527
- sourceId: dataUpdate[0],
528
- registryVersion: dataUpdate[1],
529
- signaturesRequired: dataUpdate[2],
530
- value: dataUpdate[3],
531
- canonicalTimestamp: BigInt(dataUpdate[4]),
532
- },
533
- {
534
- signature: signature[0],
535
- commitment: signature[1],
536
- signersBitmap: signature[2],
537
- },
538
- ],
539
- });
550
+ ### Raw `eth_call`
551
+
552
+ `encodeEvmVerifyCalldata` produces the full calldata (selector `0x67e2907b` plus nine static
553
+ words), and `parseEvmVerifyResult` also accepts the raw 64-byte return data:
554
+
555
+ ```ts
556
+ import { buildEvmVerifierArgs, encodeEvmVerifyCalldata, parseEvmVerifyResult } from "@molpha/sdk";
557
+
558
+ const args = buildEvmVerifierArgs(result, { maxAge: 300 });
559
+ const returnData = await provider.call({ to: verifierAddress, data: encodeEvmVerifyCalldata(args) });
560
+
561
+ const { success, code, reason } = parseEvmVerifyResult(returnData);
540
562
  ```
541
563
 
564
+ `verify` never reverts; a rejection is a result code from the shared `VERIFY_CODES` table (see
565
+ [the Starknet section](#call-verify-and-read-the-result) for the full list). The EVM verifier
566
+ returns `MALFORMED` for a zero `signaturesRequired`, a zero or out-of-range signature scalar, a
567
+ zero commitment, or fewer set bitmap bits than `signaturesRequired`. `parseEvmVerifyResult`
568
+ throws when `success` and `code` disagree, which means the call did not reach a Molpha verifier
569
+ of this interface.
570
+
571
+ ### Registry reads
572
+
573
+ `MOLPHA_VERIFIER_ABI` also covers every read-only registry view — `getRegistryVersion`,
574
+ `getTotalNodes`, `redundancyBuffer`, `getRegistryRoot` / `getRegistryPointer` (current or per
575
+ version), `activatesAt`, `retiredAt`, `isLatestVersion`, `nodeStatus`, `isNode` — and the
576
+ `InvalidRegistryVersion` error the per-version views revert with. Owner-only mutators are not
577
+ included.
578
+
542
579
  Lower-level helpers are also exported for manual integrations:
543
580
 
544
581
  ```ts
@@ -746,7 +783,7 @@ Current scope:
746
783
  - Solana attestation submission and feed/registry reads;
747
784
  - private API encryption helpers (pre-production);
748
785
  - caller-funded x402 payments for paywalled API sources (Base USDC, pre-production);
749
- - EVM and Starknet verifier argument building, Starknet `verify` calldata encoding and result decoding;
786
+ - EVM and Starknet verifier argument building, `verify` calldata encoding and result decoding;
750
787
  - deployed testnet verifier address helpers.
751
788
 
752
789
  Known limitations:
@@ -779,6 +816,10 @@ Solana paths such as selection bitmap and `submit_attestation` remaining-account
779
816
  | `buildStarknetVerifierArgs(result)` → `{ dataUpdate, signature }` | `buildStarknetVerifierArgs(result, { maxAge })` → `{ attestation, maxAge }` for `verify(attestation, max_age)` |
780
817
  | `StarknetDataUpdate` (`signatures_required: u32`) | `StarknetAttestationPayload` (`signatures_required: u8`, `value` first), nested in `StarknetAttestation` |
781
818
  | Starknet `verify` returns `bool` | returns `(bool, u8)` — decode with `parseStarknetVerifyResult` |
819
+ | `buildEvmVerifierArgs(result)` → `{ dataUpdate, signature }` tuples | `buildEvmVerifierArgs(result, { maxAge })` → `{ attestation, maxAge }` for `verify(attestation, maxAge)` |
820
+ | `EvmDataUpdateTuple` / `EvmSchnorrSignatureTuple` (positional) | `EvmAttestationPayload` / `EvmSchnorrSignature` objects (`value` first, `signaturesRequired: uint8`, `canonicalTimestamp: bigint`), nested in `EvmAttestation` |
821
+ | EVM `verify(DataUpdate, SchnorrSignature)` returns `bool` | `verify(Attestation, uint64)` returns `(bool, uint8)` — decode with `parseEvmVerifyResult` |
822
+ | `attestationMessageHash`: `sourceId ‖ u32 rv ‖ u32 sigReq ‖ bitmap ‖ value ‖ u64 ts` | `value ‖ sourceId ‖ u32 rv ‖ u8 sigReq ‖ u64 ts ‖ bitmap` (what nodes sign and every verifier checks) |
782
823
  | `resolveRegistryIndexForVersion`, `VIRTUAL_INDEX`, `nodePda(index)` | removed — signer accounts are `registry.nodes[bit]`; `nodePda(owner)` |
783
824
 
784
825
  ## Develop