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

# Build an attested on-chain app

> Pattern for apps that hold value in a chain contract and pay out based on a Gora result.

# Build an attested on-chain app

The starter templates show off-chain results and mobile signing.

A real on-chain app that moves money usually needs:

* a chain contract that holds value
* a way for users to register
* a Gora-attested decision that names a winner / recipient / outcome
* a single on-chain settlement transaction that pays out the winner

This page describes the recommended pattern. The reference implementation is in `examples/apps/raffle-app`.

## One operator-signed hop

```text theme={null}
gora result -> operator tx -> contract records (round, winner, attestation) AND transfers payout
```

The operator hop is what makes the result on-chain-verifiable: an attestation hash from the off-chain Gora app is written to the same contract storage slot as the winner. The contract pays the winner in the same transaction, so the winner does not have to sign or claim anything — funds land in their wallet automatically.

The Gora node stays key-less. The operator key is the only thing that can move funds, and it can only do so by also recording the matching attestation.

## Minimum on-chain interface

Whatever chain you target, the contract should expose:

| Function                                       | Signer      | What it does                                                                                              |
| ---------------------------------------------- | ----------- | --------------------------------------------------------------------------------------------------------- |
| `register()`                                   | participant | adds caller to the participant set                                                                        |
| `fund()`                                       | anyone      | deposits native token into the treasury                                                                   |
| `settleWinner(round, winner, attestationHash)` | operator    | stores the result of one round **and** transfers `payoutBps` of the treasury to `winner` in the same call |

The operator address is set at deploy time and is held by whoever orchestrates the Gora invoke (typically a script on the dev VM).

## Off-chain app shape

The Gora app runs off-chain and returns JSON. For an on-chain app it should return:

```json theme={null}
{
  "type": "raffle_draw",
  "schema_version": 1,
  "app_id": "my_app",
  "request_id": "round_001",
  "round": 1,
  "winner": { "chain": "base", "address": "0x..." },
  "registry_hash": "<sha256 of sorted participants>",
  "decision": { "status": "approved" },
  "chain": "base",
  "settle_instruction": {
    "schema_version": 1,
    "chain": "base",
    "kind": "auto_settle",
    "contract_ref": "0x...",
    "winner": "0x...",
    "human_summary": "Round 1: 5% of the base treasury will be sent to 0x... automatically."
  }
}
```

Two things matter:

* `winner` is the canonical attested result.
* `settle_instruction` is purely informational. The orchestrator script computes a `sha256` over the deterministic parts of this output (`app_id`, `request_id`, `round`, `winner`, `registry_hash`) and passes that hash to `settleWinner`. Any committee member can re-run the off-chain app on the same input and reproduce the same hash byte-for-byte.

## Operator orchestration

A small script ties everything together:

```text theme={null}
participants list (from chain or local config)
        ↓
gora invoke my_app --input round_N.json
        ↓
attestation_hash = sha256(canonical(result))
        ↓
chain.settleWinner(round, winner, attestation_hash)   # operator signs
        ↓
contract transfers payout to winner inside the same tx
```

The reference is `scripts/raffle.mjs draw` in `examples/apps/raffle-app`.

## Determinism

Validators reproduce non-deterministic AI outputs by re-running prompts (see MVP §10). For a deterministic app like a raffle, make the selection itself deterministic so a validator committee can verify exact byte-equality:

```ts theme={null}
const seed = `${appName}|round=${round}|registry=${JSON.stringify(sortedParticipants)}`;
const mac  = createHmac("sha256", "domain-tag").update(seed).digest();
const index = bigIntFromBytes(mac.slice(0, 16)) % BigInt(sortedParticipants.length);
```

Document the domain tag and the sort order so anyone can recompute the result from the published registry.

## Trust assumptions to call out in your policy

* The operator key can lie about the winner. Mitigate by running the off-chain app under a Gora committee quorum so multiple committee members independently sign the attestation before the operator broadcasts the settlement.
* The contract must not pay out more than the configured share. Cap by `payoutBps` and never accept an externally-supplied payout amount in `settleWinner`.
* Compute the payout from the live treasury balance inside the contract, not from the off-chain output. The contract is the source of truth for how much money is currently held.

## What to copy

Open `examples/apps/raffle-app` and copy:

* `gora.app.json` and `policy.json` for the multi-chain manifest shape
* `src/index.ts` for the deterministic winner-picker
* `contracts/{base,solana,algorand}/*` for the single-settlement payout pattern
* `scripts/raffle.mjs` for the orchestration CLI
* `test-wallets/` for a safe way to keep devnet keys out of git

Next: [Devnet quickstart](../launch/devnet-js-ts-quickstart).
