> For the complete documentation index, see [llms.txt](https://docs.northstar.sonicsvm.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.northstar.sonicsvm.org/reference/portal-program.md).

# Portal Program Reference

The Portal is the on-chain program that mints sessions, manages delegation, and enforces TTL + fee constraints. It's the warden — every session lives or dies by Portal's rules.

**Program ID (devnet):** `74iiMCqFw1afWyp3tdh9pUqfRfCRq7gfdC2YZoNGpovt`

## Instruction set

<table><thead><tr><th width="148.70703125">Discriminator</th><th width="186.4296875">Name</th><th>Purpose</th></tr></thead><tbody><tr><td><code>0</code></td><td><code>OpenSession</code></td><td>Mint a new session at <code>(owner, grid_id)</code>. Creates session PDA + fee_vault.</td></tr><tr><td><code>1</code></td><td><em>reserved</em></td><td></td></tr><tr><td><code>2</code></td><td><code>DepositFee</code></td><td>Add lamports to the <code>fee_vault</code> for a session.</td></tr><tr><td><code>3</code></td><td><code>Delegate</code></td><td>Bind an account to a session.</td></tr><tr><td><code>4</code></td><td><code>Undelegate</code></td><td>Release an account from a session (callable post-TTL by owner).</td></tr></tbody></table>

## OpenSession (discriminator 0)

```
data: u8(0) | u64 grid_id | u64 ttl_slots | u64 fee_cap

accounts (writable, signer):
  [0] owner          (signer, writable) — pays rent for session + fee_vault
  [1] session_pda    (writable)         — sessionPda(portal, owner, grid_id)
  [2] fee_vault_pda  (writable)         — feeVaultPda(portal, owner)
  [3] system_program
```

**Failure modes:**

* "account already in use" — fee\_vault already exists from a prior session for the same owner. Portal does not currently support reusing the fee\_vault; use a different owner or wait for `CloseSession` to release it.
* "invalid grid\_id" — grid\_id <= 0 is rejected.

## Delegate (discriminator 3)

Used both for PDAs (via the owning program's `delegate_to_portal` CPI) and for raw keypair-owned accounts (called directly).

For keypair accounts:

```
data: u8(3) | u64 grid_id

accounts:
  [0] owner               (signer, writable)
  [1] account             (signer, writable) — the keypair being delegated
  [2] system_program
  [3] delegation_record   (writable) — delegationRecordPda(portal, account)
  [4] system_program (again — Portal's calling convention)
  [5] buffer              (writable, ephemeral) — rent buffer for the dance
```

For PDAs delegated through their owning program (the `delegate_to_portal` hook), the program issues this CPI with the appropriate program-derived signer.

## Undelegate (discriminator 4)

```
data: u8(4)

accounts (for keypair accounts):
  [0] owner               (signer, writable)
  [1] account             (signer, writable)
  [2] system_program
  [3] delegation_record   (writable)
  [4] system_program
```

For PDA accounts the calling program issues the analogous CPI through its program-derived signer.

## Account schemas

### Session (`sessionPda(portal, owner, grid_id)`)

| Field           | Type     | Notes                                 |
| --------------- | -------- | ------------------------------------- |
| `discriminator` | `u8`     | Always `1`                            |
| `session_owner` | `Pubkey` | Owner keypair that opened the session |
| `grid_id`       | `u64`    |                                       |
| `ttl_slots`     | `u64`    |                                       |
| `fee_cap`       | `u64`    | Lamports                              |
| `created_at`    | `u64`    | Slot when OpenSession landed          |
| `nonce`         | `u64`    | Reserved                              |
| `bump`          | `u8`     |                                       |

Total: 82 bytes.

### DelegationRecord (`delegationRecordPda(portal, account)`)

| Field           | Type     | Notes                                                      |
| --------------- | -------- | ---------------------------------------------------------- |
| `discriminator` | `u8`     | Always `4` for delegation records (5 for deposit receipts) |
| `owner_program` | `Pubkey` | The program that originally owned the account              |
| `grid_id`       | `u64`    |                                                            |
| `bump`          | `u8`     |                                                            |

Total: 42 bytes.

### FeeVault (`feeVaultPda(portal, owner)`)

Lamports-only account; no decoded fields beyond standard `AccountInfo`.

## PDA derivations

```typescript
import { PublicKey } from "@solana/web3.js";

const SESSION_SEED = Buffer.from("session", "utf8");
const FEE_VAULT_SEED = Buffer.from("fee_vault", "utf8");
const DELEGATION_RECORD_SEED = Buffer.from("delegation", "utf8");

function sessionPda(portal: PublicKey, owner: PublicKey, gridId: bigint): PublicKey {
  const buf = Buffer.alloc(8);
  buf.writeBigUInt64LE(gridId);
  return PublicKey.findProgramAddressSync(
    [SESSION_SEED, owner.toBuffer(), buf],
    portal,
  )[0];
}

function feeVaultPda(portal: PublicKey, owner: PublicKey): PublicKey {
  return PublicKey.findProgramAddressSync(
    [FEE_VAULT_SEED, owner.toBuffer()],
    portal,
  )[0];
}

function delegationRecordPda(portal: PublicKey, account: PublicKey): PublicKey {
  return PublicKey.findProgramAddressSync(
    [DELEGATION_RECORD_SEED, account.toBuffer()],
    portal,
  )[0];
}
```

## See also

* [Sessions](https://github.com/mirrorworld-universe/northstar-docs/blob/main/concepts/sessions/README.md)
* [Account delegation](https://github.com/mirrorworld-universe/northstar-docs/blob/main/concepts/delegation/README.md)
* [Account schemas (full)](https://github.com/mirrorworld-universe/northstar-docs/blob/main/reference/account-schemas/README.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.northstar.sonicsvm.org/reference/portal-program.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
