# GH0ST-paid on-chain requests

The selected developer route is **GH0ST-funded requests on Robinhood → isolated ICP Qwen inference → a signed result recorded on Robinhood**. The SDK, payment candidate, worker and browser component are implementation artifacts. They do not establish an active public paid service.

Public admission remains pending until reviewed contracts, isolated canisters, operator permissions, funding, prices and acceptance/refund terms are deployed and independently checked. An incomplete or candidate deployment manifest disables the client before any RPC or wallet call. There is no hosted chat URL to substitute for this route.

## First-pilot access

This first client requires an admitted owner wallet and a **pre-registered agent ID**. It does not provide open signup, automatic agent registration or executor delegation. Another wallet cannot spend the owner's registered agent budget through this UI.

Every prompt and answer on this route is public on-chain. Do not include private information. The browser displays this notice before wallet submission and requires acknowledgement before preparing a request.

## Payment steps

1. **Inspect a reviewed deployment.** Verify the chain, token runtime, payment/gateway runtime hashes, pinned model/artifact/signer, contract relationships and current admission state.
2. **Read the on-chain quote.** Display the complete service reservation, protected acceptance charge, refund amounts, current agent balance, spending limit and required confirmations. No price is supplied by the browser.
3. **Approve only the required shortfall.** If the agent lacks enough funds for one request, approve no more than that shortfall to the reviewed payment contract. Approval alone does not move funds or fund a request.
4. **Deposit separately.** A second reviewed transaction moves that exact amount into the owner's agent budget.
5. **Request separately.** A third reviewed transaction publishes the prompt, reserves the quoted GH0ST amount and creates the gateway request. The request key is an idempotency identifier; it is not a claim that an external event was independently verified.
6. **Track the result.** Read request and payment status. Display answer text only after a canonical confirmed `InferenceFulfilled` receipt matches the stored answer hash and usage limits.
7. **Refund and withdraw where eligible.** Expired or gateway-cancelled work can return its refundable reservation to `agent.available`. The owner can then withdraw available, unlocked funds in a separate transaction.

Robinhood network gas is paid separately in **ETH**. It is not included in the GH0ST quote. The UI does not invent a gas estimate; the wallet supplies its estimate before signing.

## Acceptance and refunds

The payment contract reserves the full on-chain `serviceFee`, composed of `providerFee + protocolFee`. The configured operator must accept the request on-chain before invoking paid compute.

- Cancellation or expiry before operator acceptance returns the full reservation to the agent budget.
- Cancellation or expiry after acceptance returns `serviceFee - acceptanceFee`. The disclosed `acceptanceFee` remains payable to the provider even if no answer is delivered.
- A successfully fulfilled and settled request charges the full service quote.
- Refunds credit the agent budget. They do not automatically transfer GH0ST back to the wallet.

An acceptance event proves the configured operator accepted work. It does not prove that compute was performed. These terms and the operator role must be reviewed before public activation. New-request pauses or revoked gateway admission do not disable the contract's owner withdrawals or eligible refunds; the SDK preserves those exits while the pinned deployment identities still match.

## JavaScript SDK

Use the packed release from the project download. There is no claim that this alpha has been published to the npm registry.

```js
import { BrowserProvider } from 'ethers';
import { GH0STPaidClient } from '@gh0st/agent-kit/paid';
import { inspectPaidManifest } from '@gh0st/agent-kit/paid/manifest';

const inspection = inspectPaidManifest(reviewedDeploymentManifest);
if (!inspection.activationReady) {
  // Show access pending and its blockers. Do not connect a wallet.
  throw new Error(inspection.blockers.join('; '));
}

// Run only after the user clicks Connect.
await window.ethereum.request({ method: 'eth_requestAccounts' });
const provider = new BrowserProvider(window.ethereum, undefined, { cacheTimeout: -1 });
const signer = await provider.getSigner();
const paid = new GH0STPaidClient({ provider, signer, manifest: inspection.manifest });
const quote = await paid.getQuote(registeredAgentId);
```

`quote.source` is `on-chain`. Amounts use uint256 decimal strings in GH0ST base units, with verified 18 decimals. A quote includes its canonical block identity. `quote.blockers` explains closed admission, wrong ownership, insufficient per-job limits or capacity. `quote.fundingShortfallWei` is the additional funding required for one job.

Prepare each step without sending a transaction:

```js
const approval = await paid.prepareApproval({
  agentId: registeredAgentId,
  amountWei: quote.fundingShortfallWei,
});

// Render approval.review, chainId, from and to for the user.
// Only a subsequent explicit confirmation invokes the wallet:
const confirmed = await paid.executeTransaction(approval, {
  execute: true,
  onSubmitted: ({ transactionHash, confirmations }) => {
    // Record the hash and show the required confirmation depth.
  },
});
```

Skip approval when an existing allowance already covers the exact deposit. After its confirmation, prepare and separately confirm `prepareDeposit({ agentId, amountWei })`. Read a fresh quote before requesting.

```js
const request = await paid.prepareRequest({
  agentId: registeredAgentId,
  eventId: uniqueRequestKey,
  prompt: publicPrompt,
  maxTokens: chosenOutputLimit,
  deadline: chosenUnixDeadline,
  maxServiceFeeWei: freshQuote.serviceFeeWei,
  acceptedPublicPrompt: true,
});
```

The deadline and output limit must satisfy the actual contract settings. The SDK rejects reserved role delimiters and prompts exceeding 4,096 UTF-8 bytes. Preparation does not submit a transaction.

The SDK executes only plans produced by that same client instance. Plans are frozen, bounded, short-lived and single-use. Immediately before a wallet call, it rereads deployment and account state and reconstructs the intent. Account/network changes, quote changes, excessive approvals and stale or cloned plans fail closed. Receipts must be canonical, sufficiently confirmed and consistent with the exact transaction and expected event. Uncertain broadcasts are not retried automatically: retain and inspect the returned transaction hash before doing anything else.

## Result and refund reads

```js
const status = await paid.getRequest(requestId, {
  fromBlock: confirmedRequestBlock,
  // Optional when the callback transaction is already known:
  // fulfillmentTransactionHash: confirmedCallbackHash,
});

if (status.resultVerified) displayPublicText(status.answer);
if (status.refundEligible) {
  const refund = await paid.prepareRefund(requestId);
  // Display refund.review.refundAmountWei and its agent-budget destination.
  // Confirm it through executeTransaction only after the user's next action.
}
```

`getRequest` bounds receipt discovery to 2,000 blocks per call, in batches of at most 250 blocks. If `nextScanBlock` is returned, continue from that block on a later read. Supplying a known fulfillment transaction hash avoids scanning. Unconfirmed fulfillment is reported as `ResultConfirming`, with no answer text presented as verified. A fulfilled request may still await fee settlement by the operator.

`prepareWithdrawal({ agentId, amountWei })` permits only owner withdrawals of available funds, with its own explicit confirmation. No model output can invoke wallet actions or change this flow.

## Browser component

`public/paid-request-panel.mjs` is browser-native and contains no bare package imports, endpoint guesses or wallet side effects on import. `mountPaidRequestPanel` accepts an injected manifest validator and SDK factory. `src/paid-browser.mjs` wires it to `BrowserProvider` and `GH0STPaidClient`; bundle this entry with locally installed dependencies before serving it. Do not serve its bare `ethers` import directly.

```js
import { mountGH0STPaidPanel } from './your-local-paid-bundle.mjs';

mountGH0STPaidPanel(document.getElementById('paid-request-root'), {
  manifest: reviewedDeploymentManifest,
  agentId: registeredAgentId,
  ethereum: window.ethereum,
});
```

With no reviewed active manifest, the component renders access pending with **no wallet or transaction buttons**, and performs no wallet or RPC calls. With valid configuration, the user explicitly connects first; transaction controls appear only after on-chain deployment/quote checks succeed. Account, network and disconnect events discard reviewed plans. The component offers manual status refresh; no transaction is sent by a timer or page load.

The public release can ship the inactive component before deployment. Turning a manifest status field to `active` is not a substitute for backend readiness, funding, receipt evidence or the owner's deployment review.

## Trust and validation

The signed result authenticates the configured canister signer and the declared artifact. It is not a zero-knowledge proof of every model operation or a guarantee of answer correctness. Public RPCs and upgrade/controller policy remain part of the system's trust assumptions.

Run focused source-checkout tests with:

```sh
node --test test/paid-client.test.mjs test/paid-flow.test.mjs
```

The client and controller tests use explicit fixtures. The payment-contract tests exercise local EVM execution separately. Passing tests do not establish a public deployment, funded operator, current service availability, or a completed paid public request.
