# Phoenix — account identity, capabilities, and delegation

This file explains owner authority, trader PDAs, position authority, byte-level header checks, and key-risk evidence. Public protocol addresses are distinguished from account addresses; no individual account identifiers appear here.

## TL;DR

1. Owner wallet, trader PDA, and position authority are different identities.
2. Solana base58 addresses are case-sensitive canonical 32-byte encodings.
3. Verify binding from both signer identity and the raw on-chain trader header.
4. Frozen or reduce-only capabilities describe restrictions, not a different owner.
5. Delegate collateral risk is broader than permission names alone suggest; SwapNative analysis remains experimental.

## 1. Account model and base58

A trader PDA derives from owner authority, PDA index, subaccount index, and program. Subaccount zero is cross margin; nonzero subaccounts are isolated according to the SDK. Gate/onboarding restrictions and registration flows are outside the account-decoder implementation.

Preserve base58 case. Validate canonical decoding to exactly 32 bytes; a signature uses 64 decoded bytes. Lowercasing an address can identify another key or invalid bytes. Extra leading `1` characters add leading zero bytes and are not harmless formatting.

The ordinary trade instruction uses the owner's trader PDA while position authority signs. Do not derive a new trader account from the delegate key. Permission-account delegated instruction variants serve a different model and must not be substituted merely because a separate signer is present.

## 2. Trader header and capabilities

The 224-byte prefix uses the account discriminator `sha256('account:trader')[0..8]`. Verify that the Solana account owner is the Phoenix program before parsing. Relevant offsets are:

| Offset | Field |
|---|---|
| 56..88 | Owner authority |
| 88 | Signed i64 collateral quote lots |
| 96 | u32 capability bits |
| 112 | u32 maximum positions |
| 116 | u32 preference bits |
| 120..152 | Position authority |
| 154, 155 | PDA index, subaccount index |

Header layout was read on-chain on 2026-09-23 and 2026-09-24 and compared with public Rust source. Collateral is a balance, not portfolio equity; it can be negative.

Capability bits are HOT 1, LIMIT 2, MARKET 4, RISK 8, DEPOSIT 16, WITHDRAW 32. Zero is uninitialized; 62 is cold and 63 hot-active. Frozen and reduce-only combinations restrict risk-increasing actions according to protocol capability rules. Do not treat every restriction as lost delegation.

The first limit placement can activate a cold account inside that instruction. IoC need not activate it. Empty books and positions can return it to cold. These behaviors were observed or simulated on 2026-09-24; a successful cancel on cold may be a no-op.

## 3. Delegation and binding

`DelegateTrader` sets position authority and is signed by the owner, not the new delegate. Setting it back to owner resets delegation according to public program source. A registered trader account is required.

The experimental unsigned delegation builder takes the delegate as a caller argument, reads and validates the header, builds the owner-signable transaction, and can simulate without signature verification. Building or simulating it does not authorize signing/submission.

Compare signer health identity with expected owner, delegate, PDA, and indices, then independently parse the raw header. Wrong owner/program/PDA/index is a configuration error. A replaced or revoked delegate is confirmed binding loss. A failed read is unknown.

A binding gate starts unknown and blocks writes until delegation is verified. After a proved verdict, it retains that last known verdict when the next read fails; only confirmed loss changes it to lost, and only confirmed restoration changes it back. This does not make unknown information fresh, and current read availability remains separately reported.

## 4. Global configuration and key risk

Global-configuration decoding validates the program owner, discriminator, and prefix length before comparing REST transaction keys with on-chain fields. Public protocol constants are:

```text
Program: EtrnLzgbS7nMMy5fbD42kXiUzGg8XQzJ972Xtk1cjWih
Log authority: GdxfTLSsdSY37G6fZoYtdGDSfgFnbT2EmRpuePZxWShS
Global configuration: 2zskx2iyCvb6Stg7RBZkt1f6MrF4dpYtMG3yMvKwqtUZ
```

These are public exchange accounts from Rise 0.5.28, not user wallets. Check current deployment constants before sending a transaction.

**Experimental source analysis:** public SwapNative code allows a position authority to invoke a native-collateral swap path subject to exchange/trader flags, withdrawal throttling, and margin checks. A signer-selected route/minimum output means “cannot call ordinary withdrawal” is not proof of harmlessness if the delegate is compromised. The attack path itself was not executed or independently demonstrated.

The trader preference `disable_position_authority_swap` is bit `1 << 1` at header preference offset 116. Exchange spot-collateral flags are read from global configuration; the disable-position-authority-swap bit is `1 << 2`, while native SOL activation uses `1 << 0`. The key-risk helper reports open/closed/unknown combinations with provenance instead of asserting a proven exploit.

## Pitfalls

| What breaks | Why | Correct approach |
|---|---|---|
| Binding passes for another address | Address case normalized | Exact canonical base58 |
| Header data appears valid under another program | Owner/discriminator omitted | Validate both first |
| Frozen account called foreign | Capabilities mixed with identity | Separate restrictions and binding |
| Delegate assumes zero collateral risk | Ordinary withdrawal rules overgeneralized | Inspect source-based SwapNative verdict |
| Failed RPC clears a confirmed loss | Unknown overwrote verdict | Preserve last known state |

## Open questions / not verified

- SwapNative attack feasibility in all capability/margin combinations.
- Delegate creation/funding of isolated child accounts.
- Whether the application replaces an existing position authority during a user action; always verify the header rather than infer the cause.

## Sources

[Accounts](https://docs.phoenix.trade/sdk/accounts); [Native SOL collateral](https://docs.phoenix.trade/sdk/native-sol-collateral); [Rise public source](https://github.com/Ellipsis-Labs/rise-public) (trader/global-configuration layout, capabilities, preferences, spot-collateral, native-SOL, and delegation Rust source). Public header/config checks: 2026-09-24. Key-risk verdict is experimental source analysis, not an observed drain.

<!-- license-footer -->
_© markpaper authors. Licensed under [CC BY 4.0](LICENSE.md): when publishing or adapting this material, credit “markpaper — Phoenix knowledge base” and link to the original and the license._
