> ## Documentation Index
> Fetch the complete documentation index at: https://docs.molpha.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Solana Program

> Canonical settlement, feed accounts, subscriptions, payload submission, and direct Rust verification.

Solana is Molpha's canonical settlement chain. It stores the node registry, plans, subscriptions, delegates, gateways, settlement records, agent escrows, and maintained `Feed` accounts.

## Network details

| Item                | Value                                          |
| ------------------- | ---------------------------------------------- |
| Program name        | `molpha`                                       |
| Program ID (devnet) | `MoLFGDpFoVnQgwbkTNScKPohCxhbfd61JjFrnotuwzh`  |
| Settlement asset    | USDC SPL token from `ProtocolConfig.usdc_mint` |
| Framework           | Anchor                                         |

## Account model

| Account                      | Seeds                                                                                                      | Purpose                                            |
| ---------------------------- | ---------------------------------------------------------------------------------------------------------- | -------------------------------------------------- |
| `ProtocolConfig`             | `["molpha_config"]`                                                                                        | Global config, treasury, fees, USDC mint           |
| `RegistryState`              | `["molpha_registry"]`                                                                                      | Current and previous registry metadata             |
| `Node`                       | `["molpha_node", index_le]`                                                                                | Registered node slot                               |
| `Plan`                       | `["molpha_plan", plan_type_u8]`                                                                            | Subscription tier                                  |
| `Subscription`               | `["molpha_subscription", owner]`                                                                           | Subscriber state                                   |
| `Delegate`                   | `["molpha_delegate", owner, delegate]`                                                                     | Delegated authority for subscription-backed rounds |
| `Feed`                       | `["molpha_feed", feed_id]`                                                                                 | Latest verified value for a feed                   |
| `Gateway`                    | `["molpha_gateway", gateway_authority]`                                                                    | Bonded gateway operator                            |
| `AgentEscrow`                | `["molpha_agent", authority, gateway]`                                                                     | x402 / self-funded agent escrow (lazy-created)     |
| `RoundReceiptRecord`         | `["molpha_round", consumer_authority, api_config_hash, signatures_required, timestamp_le]`                 | Subscription / delegate round settlement receipt   |
| `RoundReceiptRecord` (agent) | `["molpha_agent_round", authority, gateway, api_config_hash, signatures_required, canonical_timestamp_le]` | Agent round settlement receipt                     |

## Feed ID

```text theme={null}
feed_id = keccak256(
  "MOLPHA_JOB_V1" ||
  owner_pubkey ||
  api_config_hash ||
  signatures_required_u8
)
```

For subscription rounds, `owner` is the consumer authority. For agent rounds, `owner` is the agent payer/authority.

## `Feed` account

```rust theme={null}
#[account]
pub struct Feed {
    pub feed_id: [u8; 32],
    pub value: Vec<u8>,
    pub value_kind: FeedValueKind,
    pub canonical_timestamp: i64,
    pub signatures_required: u8,
    pub signers_bitmap: [u8; 32],
    pub registry_version: u32,
    pub bump: u8,
}
```

`value` stores the raw payload when it is 32 bytes or smaller. Longer payloads up to 256 bytes are stored as a keccak hash and marked with `FeedValueKind::Hash`.

## Main instructions

| Instruction                                    | Who        | Purpose                                                               |
| ---------------------------------------------- | ---------- | --------------------------------------------------------------------- |
| `subscribe(plan_type)`                         | Subscriber | Open a monthly USDC subscription                                      |
| `extend_subscription()`                        | Subscriber | Add one month and top up prepaid balance                              |
| `add_delegate(args)` / `remove_delegate(args)` | Subscriber | Manage delegated authorities                                          |
| `settle_round_receipt(args)`                   | Gateway    | Settle a subscription-backed round (writes a receipt, not the `Feed`) |
| `settle_agent_round(args)`                     | Gateway    | Settle an x402 agent round (writes a receipt, not the `Feed`)         |
| `finalize_round()`                             | Anyone     | Finalize a settled receipt after the dispute window                   |
| `dispute_round(agg_sig)`                       | Anyone     | Challenge a settled receipt with a verifying aggregate signature      |
| `submit_data_update(args)`                     | Anyone     | Verify a signed payload and write it to the `Feed`                    |

Only `submit_data_update` creates or updates the `Feed` account (`init_if_needed`). Settlement instructions write `RoundReceiptRecord` accounts for payment and dispute accounting; they do not write the feed value.

## Submit payload

```rust theme={null}
pub struct SubmitDataUpdateArgs {
    pub feed_id: [u8; 32],
    pub registry_version: u32,
    pub value: Vec<u8>,
    pub canonical_timestamp: i64,
    pub signatures_required: u8,
    pub agg_sig_s: [u8; 32],
    pub commitment_addr: [u8; 20],
    pub signers_bitmap: [u8; 32],
}
```

Checks:

* Full Schnorr verification through `molpha_verifier`.
* Signer bitmap is resolved against the requested registry version.
* New feed values must have a strictly newer `canonical_timestamp`.
* Value is encoded according to `Feed::encode_stored_value`.

## Direct verification with `molpha-verifier`

Use the Rust crate when you want to verify a signed payload without writing through `submit_data_update`.

```toml theme={null}
[dependencies]
molpha-verifier = "0.2"
```

High-level APIs:

| Function                        | Use when                                       |
| ------------------------------- | ---------------------------------------------- |
| `verify_data_update`            | You already resolved signer `(x, y)` pubkeys   |
| `verify_data_update_compressed` | You already resolved compressed signer pubkeys |
| `verify_data_update_resolved`   | You have `RegistryView` and `NodeEntry` values |
| `verify_aggregate_over_hash`    | Dispute path over an arbitrary hash            |

For Solana-program integrations, the caller must owner-check and deserialize registry/node accounts, copy them into plain `RegistryView` / `NodeEntry` values, then pass them to `verify_data_update_resolved`.

```rust theme={null}
use molpha_verifier::{
    verify_data_update_resolved, DataUpdate, NodeEntry, RegistryView,
};

verify_data_update_resolved(
    &payload,
    &registry_view,
    redundancy_buffer,
    clock_unix_timestamp,
    &node_entries,
)?;
```

The crate is pure verification logic. It does not perform account I/O, owner checks, or Anchor/Pinocchio account validation.

## PDA derivation reference

```ts theme={null}
import { web3 } from "@anchor-lang/core";

const PROGRAM_ID = new web3.PublicKey("MoLFGDpFoVnQgwbkTNScKPohCxhbfd61JjFrnotuwzh");

const findFeed = (feedId: Uint8Array) =>
  web3.PublicKey.findProgramAddressSync(
    [Buffer.from("molpha_feed"), Buffer.from(feedId)],
    PROGRAM_ID
  )[0];

const findSubscription = (owner: InstanceType<typeof web3.PublicKey>) =>
  web3.PublicKey.findProgramAddressSync(
    [Buffer.from("molpha_subscription"), owner.toBuffer()],
    PROGRAM_ID
  )[0];

const findAgentEscrow = (
  authority: InstanceType<typeof web3.PublicKey>,
  gateway: InstanceType<typeof web3.PublicKey>,
) =>
  web3.PublicKey.findProgramAddressSync(
    [Buffer.from("molpha_agent"), authority.toBuffer(), gateway.toBuffer()],
    PROGRAM_ID
  )[0];
```

## Consumer responsibilities

* Validate the `Feed` PDA from `["molpha_feed", feed_id]`.
* Enforce freshness with `canonical_timestamp`.
* Decode `value` according to the feed schema.
* Use `submit_data_update` before reading, or verify supplied payloads directly with `molpha-verifier`.
* Treat gateway and escrow status reads as advisory until settlement finalizes.

## Consumer-relevant errors

| Error                             | Meaning                                                         |
| --------------------------------- | --------------------------------------------------------------- |
| `SubscriptionNotActive`           | Subscription expired or missing                                 |
| `SubscriptionInactiveOrExhausted` | Subscription expired or round quota exhausted (settlement path) |
| `SignaturesExceedSubscriptionMax` | Requested quorum exceeds `subscription.max_signers`             |
| `SignaturesExceedDelegateMax`     | Requested quorum exceeds `delegate.max_signers`                 |
| `FeedNotNewer`                    | Submitted timestamp is not newer than stored timestamp          |
| `InvalidRegistryVersion`          | Payload registry version is not accepted                        |
| `InsufficientSigners`             | Signer bitmap has fewer signers than quorum                     |
| `InvalidAggregateSignature`       | Schnorr verification failed                                     |
| `MissingSignerAccount`            | Remaining accounts do not match signer bitmap                   |
| `InvalidValueLength`              | Submitted value exceeds `Feed::MAX_VALUE_LEN` (256)             |
