Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .agents/context/crates/magicblock-chainlink.md
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ Chainlink has special handling for associated token accounts and ephemeral ATAs:
- It subscribes to both ATA and eATA using `SubscriptionReason::AtaProjection`.
- If the eATA exists, has a delegation record for this validator, and can be projected, Chainlink clones a projected delegated ATA into the local bank.
- Projection preserves the base ATA's owner and data length, which is important for Token-2022 extensions.
- eATA subscription updates do not overwrite an already-delegated base ATA, except for delegated rent-pending ATA markers detected by `try_get_rent_pending_ata_info`; projecting those markers clears the rent-pending close-authority sentinel while preserving delegated local execution state.
- Missing eATAs can be remembered in `known_empty_eatas`, but only after confirmed `NotFound` while an eATA subscription is live.
- Raw eATA PDAs are not marked delegated directly; their state is projected into the corresponding base ATA.

Expand Down
22 changes: 22 additions & 0 deletions .agents/context/crates/magicblock-committor-service.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,21 @@ IntentExecutorImpl::execute

For committed accounts with `data.len() > COMMIT_STATE_SIZE_THRESHOLD` (`256`), the task builder fetches the base account and may use diff-in-args delivery. If the base-account fetch fails, it falls back to full state args and logs a warning. This can increase transaction size and trigger buffer/ALT strategy later.

Rent-pending ATA materialization metadata is handled before normal DLP commit
tasks. For each metadata entry, `TaskBuilderImpl::commit_tasks` prepends an
e-token initialize-eATA task and a delegate-eATA-to-this-validator task. The
task builder still fetches the eATA commit nonce; it defaults missing base DLP
metadata to current nonce `0` only for rent-pending eATAs, otherwise it uses the
fetched base nonce. If an eATA already exists and is delegated to another
validator, the e-token delegate task is the expected validator-mismatch failure
gate before any DLP commit/undelegation task is allowed to succeed.
Only explicit scheduled materialization metadata authorizes this path; eATA
shape alone is treated as a normal commit input and missing base metadata
remains an error.
Commit-and-undelegate reimbursement also fetches existing base DLP metadata
first; it defaults rent reimbursement to the validator only when rent-pending
eATA metadata is actually missing.

### Delivery preparation and cleanup flow

`TransactionPreparatorImpl::prepare_for_strategy` first compiles against dummy lookup tables to fail early if the message cannot fit. It then calls `DeliveryPreparator::prepare_for_delivery`:
Expand All @@ -225,6 +240,13 @@ Cleanup closes prepared buffers and releases TableMania pubkeys. `IntentExecutio

`IntentExecutorImpl` resets cached nonces according to execution certainty. On any execution error, it resets all committed pubkeys because it cannot know what landed on chain. On successful undelegation paths, it resets only the pubkeys returned by `get_undelegate_intent_pubkeys()` and `get_commit_finalize_and_undelegate_intent_pubkeys()`. Other successfully committed pubkeys keep their incremented cached nonce, which avoids a chain re-fetch racing the just-landed finalize and reusing a stale nonce/buffer PDA.

When `fetch_next_commit_nonces_with_missing_as_zero` defaults a rent-pending
eATA with missing base metadata to zero, the cache records that the nonce came
from missing metadata. The next fetch for that pubkey must re-check the inner
fetcher instead of treating the entry as a normal cache hit, so a successfully
materialized base metadata account clears the recovery marker and does not
generate duplicate init/delegate materialization tasks.

Do not remove sorted lock acquisition or the retiring map without replacing the deadlock/race prevention. Commit nonce races can cause base-layer commit failures and stuck undelegations.

### `min_context_slot` and freshness
Expand Down
3 changes: 2 additions & 1 deletion .agents/context/crates/magicblock-core.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ Use `CoordinationMode::current()`, `needs_validator_signer()`, `should_schedule_

### Execution TLS

`tls::ExecutionTlsStash` is a thread-local queue currently used for `TaskRequest`s emitted by Magic Program task scheduling/cancel instructions. The processor clears the stash around execution and drains it after a successful transaction path. Do not use it as a cross-thread channel or persistent store.
`tls::ExecutionTlsStash` is a thread-local queue currently used for `TaskRequest`s emitted by Magic Program task scheduling/cancel instructions, newly created rent-pending ATA pubkeys that need post-execution validation, and rent-pending ATA materialization pubkeys recorded during scheduling. The processor clears the stash around execution, drains scheduled tasks after a successful transaction path, and verifies newly created rent-pending ATAs before local state is committed. The materialization marker lets that verifier accept a rent-pending ATA that was created, funded, recorded for materialization, and then marked undelegating in the same transaction. Do not use TLS as a cross-thread channel or persistent store.

### Token/eATA helpers

Expand All @@ -147,6 +147,7 @@ Use `CoordinationMode::current()`, `needs_validator_signer()`, `should_schedule_
- eATA derivation: `derive_eata`, `try_derive_eata_address_and_bump`.
- ATA detection/remapping: `is_ata`, `try_remap_ata_to_eata`.
- eATA projection: `EphemeralAta` projection helpers require a real base ATA layout and do not synthesize legacy SPL Token accounts from raw eATA data.
- Rent-pending ATA helpers: `RENT_PENDING_ATA_CLOSE_AUTHORITY` is the rent sysvar sentinel, and `try_get_rent_pending_ata_info` recognizes only canonical delegated non-native SPL Token/Token-2022 ATAs that are not ephemeral, confined, or undelegating. Rent-pending detection builds materialization metadata for Magic Program scheduling; it is not a close authority or settlement bypass.
- Native-token local projection: `normalize_native_token_account_for_local_clone` strips `is_native` and claimable lamports only for canonical delegated ATA clones, and supports both legacy SPL Token native mint and Token-2022 native mint while preserving Token-2022 account layout/extensions.
- Projected ATA local safety: `normalize_projected_token_account_for_local_clone` makes virtual projected ATAs uncloseable with `close_authority = Some(Pubkey::default())`; closure/materialization belongs in settlement, not local projection.

Expand Down
20 changes: 17 additions & 3 deletions .agents/context/crates/magicblock-magic-program-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ Use `crate::compat::{Instruction, AccountMeta, AccountInfo, Signature}` and `cra

`instruction.rs` defines:

- `MagicBlockInstruction`: the primary bincode-serialized instruction enum for the Magic Program. Variants cover account modification, legacy and bundled commit scheduling, task scheduling/canceling, executable-check toggles, no-op uniqueness, ephemeral account create/resize/close, clone/chunk/cleanup, program finalization, callback attachment, account eviction, and crank execution.
- `MagicBlockInstruction`: the primary bincode-serialized instruction enum for the Magic Program. Variants cover account modification, legacy and bundled commit scheduling, task scheduling/canceling, executable-check toggles, no-op uniqueness, ephemeral account create/resize/close, local rent-pending ATA creation, clone/chunk/cleanup, program finalization, callback attachment, account eviction, and crank execution.
- `CallbackInstruction`: instruction enum for the callback executor built-in. Current variant is `ExecuteCallback { instruction }`.
- `PostDelegationActionExecutorInstruction`: instruction enum for the post-delegation action executor built-in. Current variant is `Execute { cloned_account_pubkey, actions }`.
- `AccountCloneFields`: clone metadata (`lamports`, `owner`, `executable`, `delegated`, `confined`, `remote_slot`) that must preserve remote/local account semantics across clone instructions.
Expand Down Expand Up @@ -183,7 +183,19 @@ magicblock-account-cloner
3. `programs/magicblock/src/ephemeral_accounts` applies rent math using `EPHEMERAL_RENT_PER_BYTE` and account static-size overhead.
4. Processor tests assert sponsor/vault lamport movement, signer requirements, PDA sponsor rules, and close/resize behavior.

Changing the rent constant, vault pubkey, or account-meta shape affects user-visible balance semantics and tests.
`CreateRentPendingAta { wallet_owner, mint, token_program }` lives next to the
ephemeral-account instructions but creates a local canonical token ATA, not a
generic ephemeral account. Its account metas are payer signer, writable ATA,
mint, and token program. It reuses the former `Unused` bincode slot, so do not
insert another variant in that position or assume an unused discriminant remains
there.
For Token-2022, rent-pending creation supports default account state plus
marker-only account extensions such as `ImmutableOwner`,
`NonTransferableAccount`, and `PausableAccount`; reject required stateful account
extensions such as `TransferFeeAmount` or `TransferHookAccount` until settlement
preserves extension state.

Changing the rent constant, vault pubkey, rent-pending ATA instruction shape, or account-meta shape affects user-visible balance semantics and tests.

### Task scheduling flow

Expand Down Expand Up @@ -214,7 +226,9 @@ Do not add user-controlled signer bits to `ShortAccountMeta`; callback signer ha

All major public structs/enums derive `Serialize` and `Deserialize` and are serialized with `bincode`. Enum variant order and struct field order matter. Adding fields without compatibility handling, removing variants, or reordering variants can break old transactions, persisted contexts, integration programs, or callback decoders.

The `Unused` instruction variant is intentionally retained as an unused slot after a removed `ScheduleCommitFinalize` path. Do not delete or repurpose it casually; doing so changes discriminants or semantics.
The former `Unused` instruction slot after the removed `ScheduleCommitFinalize`
path is now `CreateRentPendingAta`. Treat that discriminant as live wire/API
surface. Do not delete, reorder, or repurpose it casually.

### Secure vs legacy action scheduling

Expand Down
50 changes: 50 additions & 0 deletions .agents/specs/validator-specification.md
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,56 @@ Magic Program instructions:
- `ResizeEphemeralAccount { new_data_len }`
- `CloseEphemeralAccount`

## Rent-pending ATA materialization

Rent-pending ATAs are local canonical token accounts that let the ER accept
tokens before the corresponding base-layer eATA exists. They are not generic
ephemeral accounts. The Magic Program creates them locally through
`CreateRentPendingAta { wallet_owner, mint, token_program }` and recognizes
them only when the local token account is canonical, owned by SPL Token or
Token-2022, non-native, delegated, not confined, not undelegating, not
ephemeral, and has close authority set to the rent sysvar sentinel. Ordinary
projected ATAs still use `Pubkey::default()` as the uncloseable close authority;
that marker is not rent-pending.

New local rent-pending ATA creation is free, but the same transaction must leave
the newly created account with a positive token amount. The processor rejects
and rolls back a creation transaction that leaves a newly created rent-pending
ATA at zero balance. The same transaction may also schedule commit-and-undelegate
for that newly created ATA after materialization metadata has been recorded; in
that case the post-creation verifier accepts the undelegating token-account shape
only because the execution TLS materialization marker proves scheduling already
captured the rent-pending metadata.

When a rent-pending ATA is scheduled for commit or commit-and-undelegate, the
Magic Program records explicit materialization metadata, charges the delegated
payer into the magic fee vault for each materialization, and still remaps the
committed ATA to its eATA form. The committor prepends e-token idempotent eATA
initialize and delegate-to-this-validator instructions before the normal DLP
commit task. If the eATA was created after local rent-pending creation and is
already delegated to another validator, the e-token delegation instruction is
the expected validator-mismatch failure gate; the DLP commit/undelegation must
not be treated as successful.

For commit-and-undelegate scheduling paths, fee-vault charging and commit-limit
checks must happen before local accounts are marked undelegating, because the
local mutation clears the `delegated` flag and the payer can also be one of the
undelegated accounts. Token-2022 rent-pending ATA initialization must mirror the
mint's default account state extension; a mint whose `DefaultAccountState` is
`Frozen` must create a frozen local rent-pending ATA rather than an initialized
one. Token-2022 rent-pending ATAs must include `ImmutableOwner` in addition to
supported marker-only account extensions. Required stateful account extensions
such as `TransferFeeAmount` or `TransferHookAccount` are rejected until
settlement preserves their state. Rent-pending eATA fee calculation must use an
existing base commit nonce when delegation metadata already exists, and default
the nonce to zero only when that metadata is actually missing.
Commit-and-undelegate rent reimbursement must use an existing base metadata rent
payer when present, defaulting to the validator only when rent-pending eATA
metadata is actually missing.
The committor must not infer rent-pending materialization from eATA account
shape alone; without explicit scheduled materialization metadata, missing base
metadata remains an error.

## RPC and router specification

The MagicBlock Router API implements most standard Solana JSON-RPC methods and adds MagicBlock-specific methods.
Expand Down
5 changes: 5 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ solana-transaction-context = { git = "https://github.com/magicblock-labs/magicbl
] }
solana-transaction-error = { version = "3.0" }
solana-transaction-status = { version = "4.0" }
solana-transaction-status-client-types = "4.0"
solana-transaction-status-client-types = "=4.0.0"
solana-zk-elgamal-proof-program = { version = "=4.0.0", features = [
"agave-unstable-api",
] }
Expand Down Expand Up @@ -195,7 +195,7 @@ serde_with = "3.16"
serial_test = "3.2"
sha3 = "0.10.8"
solana-account = { git = "https://github.com/magicblock-labs/magicblock-svm.git", rev = "190146af2ac0890848b50e8fc9d6c926c8205b5e" }
solana-account-decoder = { version = "4.0" }
solana-account-decoder = { version = "=4.0.0" }
solana-account-decoder-client-types = { version = "4.0" }
solana-account-info = { version = "3.1" }
solana-address-lookup-table-interface = { version = "3.0" }
Expand Down
Loading
Loading