50 Commits

Author SHA1 Message Date
Ricardo Guilherme Schmidt
5229855d57 fix(ata)!: namespace accounts by token program
ATA accounts are now namespaced by token program, so callers must
explicitly pass the token_program_id when invoking ATA::Transfer.

BREAKING CHANGE: `Instruction::Transfer`, `Instruction::Burn`, `Instruction::Create` now requires a
`token_program_id` field. Any existing call site that omits it will
fail to compile.

Closes #83
2026-05-18 12:53:07 +02:00
r4bbit
29b4c01739 fix(integration_tests) remove no longer needed program ID 2026-05-18 12:22:06 +02:00
Ricardo Guilherme Schmidt
f8cbcc6956 fix(ata): lock down ATA::Transfer recipient contract
Enforce at the ATA layer that the recipient token holding is already
initialized, owned by the same token program as the sender ATA, decodes
to a valid `TokenHolding`, and points at the same token definition as
the sender. Align the core instruction doc and guest wrapper doc with
that contract, and cover the boundary with unit tests (default,
foreign-owned, malformed, mismatched-definition recipients, plus the
missing-owner-auth and happy paths) and end-to-end integration tests
(default and mismatched-definition recipients).

Without this, the downstream `token::Transfer` default-recipient
`Claim::Authorized` path was reachable through ATA, so integrators had
to reverse-engineer recipient semantics from token/runtime internals.
2026-05-13 13:32:09 +02:00
Ricardo Guilherme Schmidt
0b078b2dde fix(stablecoin): address open position review feedback 2026-05-13 12:23:20 +02:00
Ricardo Guilherme Schmidt
d6082d0c81 docs(stablecoin): improve documentation for OpenPosition instruction 2026-05-13 12:23:20 +02:00
Ricardo Guilherme Schmidt
e63d09f793 docs(stablecoin): list all five OpenPosition accounts and qualify size_of_val
The `Instruction::OpenPosition` doc claimed four required accounts but the
handler and IDL take five — the collateral token definition was missing.
Update the list to match the actual contract.

Also fully qualify `std::mem::size_of_val` in `From<&Position> for Data`
so the call no longer relies on Rust 1.80+ prelude additions for the
2021 edition.
2026-05-13 12:23:20 +02:00
Ricardo Guilherme Schmidt
f4f7b45bd4 feat(stablecoin): implement open_position
Adds the `open_position` instruction to the Stablecoin Program. The instruction
claims a per-owner `Position` PDA, initializes a collateral vault token holding
via a chained `Token::InitializeAccount` under the vault's PDA authority, and
moves `collateral_amount` from the user's holding into the vault with a chained
`Token::Transfer`. `Position` is persisted with `collateral_amount` and
`debt_amount = 0`; the debt path is deferred to `generate_debt`.

- Add `Position` struct, `OpenPosition` instruction variant, and
  `compute_position_pda{,_seed}` / `compute_position_vault_pda{,_seed}` helpers
  in `stablecoin_core` with domain-separated PDA seeds.
- Implement `open_position::open_position` mirroring the ATA `create` and AMM
  `new_definition` patterns: authorization and uninitialized-state asserts, PDA
  verification, and same-transaction chained `InitializeAccount` + `Transfer`.
- Wire the new instruction through the SPEL guest and regenerate the stablecoin
  IDL artifact.
- Cover the happy path, all assertion paths, and PDA determinism /
  non-collision in 11 new unit tests.
2026-05-13 12:23:20 +02:00
Andrea Franz
22b41bdb3d chore(amm-ui): reorganize liquidity page components 2026-05-12 16:11:24 +02:00
Andrea Franz
9375129c9e chore(amm-ui): add layout and reorganize swap UI files 2026-05-12 16:11:24 +02:00
Ricardo Guilherme Schmidt
8005c74e26 feat(token): verify definition ownership via self_program_id in initialize and mint
Pass `ctx.self_program_id` from `ProgramContext` into `initialize_account`
and `mint`, which now assert that the token definition account is owned by
the token program. This prevents callers from supplying a foreign-owned
account as the definition.

See https://github.com/logos-co/spel/issues/172
2026-05-12 16:10:40 +02:00
r4bbit
ceb8a4b597 chore: update spel
This updates the spel dependency, which introduces a breaking change.
To make reviewing changes easier from other changes, this update comes
in a separate commit.
2026-05-12 11:47:35 +02:00
r4bbit
f4a0aaf8d0 feat: make use of spel's [#account_type] directive
This annotates custom account data as [#account_type], to allow for deserializing abritrary LEZ account data.

Closes #49
2026-05-12 10:04:22 +02:00
r4bbit
e7a69f619f chore: update LEZ to v0.2.0-rc3 2026-05-12 08:46:36 +02:00
Andrea Franz
4178406fda feat(stablecoin): initial stablecoin scaffold
closes #86
2026-05-11 16:53:04 +02:00
Andrea Franz
6eed55d7e4 chore(amm-ui): add SlippageToleranceControl 2026-05-11 10:15:52 +02:00
Andrea Franz
476087a36b chore(amm-ui): swap form activates exact input or output based on the fields updated
closes #56
2026-05-11 10:15:52 +02:00
Andrea Franz
3df3c3d7c4 feat(amm/ui): show swap summary under the swap card 2026-05-11 10:15:52 +02:00
r4bbit
c8a192e377 chore(amm): validate fee tier in sync_reserves
All other entry functions validate the pools fee tier, except for this
function. This is likely because it doesn't make use of the fees.

To make the code consistent (and auditing easier), we're now validating
the fees in `sync_reserves` the same way.
2026-05-08 12:58:01 +02:00
r4bbit
0d532a8fd3 chore(amm): add defensive check for lp token solvency
This check is added to fulfill the program invariant that no more tokens
than owned can be burned. This was not a bug before, because the `token`
program will revert on `Transfer::Burn` when one tries to burn more
tokens than available.

So this change is merely for making the invariant explicit.
2026-05-08 12:43:22 +02:00
r4bbit
e69c9107f0 fix(amm): validate user deposit accounts are owned by vault's token program
An attacker could pass user holding accounts owned by a malicious token
program. Since chained calls are dispatched to the program_owner of the
user holding account, a fake program could accept the transfer instruction
without actually moving tokens.

Add assertions in add_liquidity, remove_liquidity, swap_exact_input, and
swap_exact_output that user_holding_a and user_holding_b must share the
same program_owner as vault_a. The vault accounts are PDA-verified via
their account_id, making vault_a's program_owner the authenticated
reference. new_definition already validated that both user holdings use
the same program.

Adds 8 regression tests covering the wrong-program case for each
operation and each user holding slot.

Closes #69
2026-05-08 12:10:06 +02:00
r4bbit
6b21c3695a feat(amm)!: add transaction deadlines to swap and liquidity instructions
All mutable AMM instructions now require a `deadline: u64` field (Unix
timestamp in milliseconds). Enforcement uses the LEZ-native timestamp
validity window set on ProgramOutput; the runtime rejects the
transaction if the sequencer submission timestamp is at or past the
deadline.

BREAKING CHANGE: AddLiquidity, RemoveLiquidity, SwapExactInput,
SwapExactOutput, and NewDefinition instruction variants now require a
`deadline` field.

Closes #8
2026-05-06 13:26:11 +02:00
Andrea Franz
5a61cf39f2 chore(amm-ui): add swap confirmation modal
closes #58
2026-05-05 17:29:37 +02:00
Andrea Franz
37fc2ea088 chore(amm-ui): update styles to match the liquidity page 2026-04-30 12:42:43 +02:00
r4bbit
06a141ef6e chore: fix RISC-V guest build on macOS 26
Add .cargo/config.toml setting CFLAGS_riscv32im_risc0_zkvm_elf to
"-march=rv32im -nostdlib". This prevents cc-rs from injecting
macOS-specific flags (-arch arm64, -mmacosx-version-min) into the
riscv32-unknown-elf-gcc cross-compiler when building C dependencies
(e.g. ring) for the guest target, which causes build failures on
macOS 26 Tahoe.
2026-04-29 10:12:09 +02:00
Ricardo Guilherme Schmidt
a3bdc964c7 feat(amm/ui): add mock confirmation flow (#64)
Fixes #64
2026-04-28 16:11:30 +02:00
Ricardo Guilherme Schmidt
d92a61fd9b feat(amm/ui): add slippage min received controls (#63)
Fixes #63
2026-04-28 16:11:30 +02:00
Ricardo Guilherme Schmidt
bf9001c363 feat(amm/ui): add remove-liquidity preview (#62)
Fixes #62
2026-04-28 16:11:30 +02:00
Ricardo Guilherme Schmidt
67b1e501e8 feat(amm/ui): add liquidity deposit preview (#61)
Fixes #61
2026-04-28 16:11:30 +02:00
Ricardo Guilherme Schmidt
f5a01063ed feat(amm/ui): add pool position summary (#60)
Fixes #60
2026-04-28 16:11:30 +02:00
r4bbit
0cec2e2573 feat(amm-ui): add navbar to switch between views 2026-04-28 16:11:30 +02:00
Andrea Franz
e18f0f3c32 chore(amm-ui): add basic swap UI for Token Pair Selector & Swap Direction
closes #55
2026-04-28 14:11:53 +02:00
Andrea Franz
29d949d75a feat(amm/ui): add initial AMM UI module 2026-04-22 10:52:48 +02:00
Ricardo Guilherme Schmidt
471abef719 refactor!: Update dependencies and implement new required features across multiple modules
- Updated `nssa_core` and `spel-framework` dependencies to their respective release candidates in `Cargo.toml` and `Cargo.lock` files for `amm`, `ata`, and `token` modules.
- Enhanced the `new_definition` function in `amm/src/new_definition.rs` to include new claim logic and updated PDA seed calculations.
- Modified tests in `integration_tests/tests/amm.rs`, `integration_tests/tests/ata.rs`, and `integration_tests/tests/token.rs` to accommodate changes in transaction handling and account initialization.
- Refactored account initialization logic in `ata/src/create.rs` and `token/src/initialize.rs` to include authorization claims.
- Updated various functions in `token/src/mint.rs`, `token/src/new_definition.rs`, and `token/src/transfer.rs` to utilize the new claim system for account states.
- Adjusted the IDL generation tool to use the latest version of `spel-framework-core`.
2026-04-20 12:25:59 +02:00
Ricardo Guilherme Schmidt
6c86b5b9ce feat(amm): apply trading fees to LP accounting
Implement Uniswap V2-style fees-in-reserves: the full swap_amount_in is
deposited into the reserve (growing k = reserve_a * reserve_b), while
only the fee-adjusted effective_amount_in is used to compute the output
amount. This means LPs earn fees proportionally on every removal via
k-growth rather than through a separate vault surplus.

- swap_logic: add fee_bps parameter; compute effective_amount_in for
  output formula only; return full swap_amount_in as the reserve deposit
- Fix all integration test fixture values to match fees-in-reserves math
- Remove dead-code vault_a/b_init_zero helpers from unit tests
2026-04-20 11:29:00 +02:00
Andrea Franz
1f8eea8442 chore(amm): new_definition allows only uninitialized pools 2026-04-14 13:10:09 +02:00
Ricardo Guilherme Schmidt
4a9a441ccd refactor(amm)!: derive pool active state from LP supply instead of explicit flag
Remove the `active: bool` field from `PoolDefinition` and replace it with an
implicit invariant: a pool is considered active when
`liquidity_pool_supply >= MINIMUM_LIQUIDITY`.

BREAKING CHANGE: `PoolDefinition` Borsh serialization format has changed.
Existing on-chain pool accounts encoded with the `active` field are
incompatible with this version.

Closes #25
2026-04-14 11:57:26 +02:00
r4bbit
94f14ae305 ci: add IDL freshness check and consolidate artifacts
Move IDL files to artifacts/ and add a convention-based CI check that
discovers all programs via */methods/guest/src/bin/*.rs and fails if
any program is missing its IDL or has one that is out of date.
2026-04-14 11:22:24 +02:00
Ricardo Guilherme Schmidt
9824cd8f90 feat(amm): add configurable fee tiers
- accept a supported fee tier in pool creation
- store fee tiers in AMM pool state and validate them
- update AMM tests and IDL for the new pool creation argument
2026-04-10 13:16:05 +02:00
r4bbit
d0f398814c test(ata): add integration for private accounts create public ATAs 2026-04-09 19:13:03 +02:00
Andrea Franz
36f78a21aa fix(amm): use checked mul/add/sub to avoid overflows/underflows 2026-04-09 19:11:36 +02:00
Andrea Franz
4419e1e9a0 chore(amm)!: rename Swap instruction to SwapExactInput
Renames the Swap instruction and its guest handler to SwapExactInput to
distinguish it from the newly added SwapExactOutput, and to make the
intent of each variant explicit at the call site.

BREAKING CHANGE: the Swap instruction variant and swap() function are
renamed to SwapExactInput and swap_exact_input(). Callers must update
instruction construction and any IDL-generated bindings.
2026-04-09 19:11:36 +02:00
Andrea Franz
664fd849bd feat(amm): add swap exact output instruction
Adds SwapExactOutput to the AMM, allowing callers to specify the exact
desired output amount while the protocol computes the required input
(ceiling division to prevent rounding in the protocol's favour).

The swap-exact-output success tests now use a dedicated small-pool
fixture (reserve_a=1_000, reserve_b=500) rather than the shared
pool_definition_init, which had its reserves bumped to 5_000/2_500 in a
later commit to satisfy the MINIMUM_LIQUIDITY invariant introduced for
new_definition. Using a dedicated fixture keeps each test self-contained
and avoids hardcoded expected values silently breaking when shared
baselines change.
2026-04-09 19:11:36 +02:00
Ricardo Guilherme Schmidt
e61cd594b5 feat(amm): add SyncReserves instruction
Adds a new `SyncReserves` instruction that updates a pool's recorded
reserves to match the actual vault balances. This allows the pool to
absorb donations (direct token transfers to vaults) without breaking
the invariant — only upward adjustments are permitted; vaults may
not be under-collateralized relative to reserves.

Vault reading helpers (`read_fungible_holding`,
`read_vault_fungible_balances`) are implemented in `amm_core` so they
can be shared across instructions without crossing crate boundaries.
2026-04-09 14:48:35 +02:00
Ricardo Guilherme Schmidt
fddd6e15bd feat(amm)!: introduce minimum liquidity lock on pool initialization
Permanently lock `MINIMUM_LIQUIDITY` (1_000) LP tokens in a dedicated
LP-lock holding PDA on pool creation, following the Uniswap v2 "dead
shares" pattern. The pool creator receives `initial_lp - MINIMUM_LIQUIDITY`
tokens instead of the full initial_lp amount.

Adds `compute_lp_lock_holding_pda` and `LP_LOCK_HOLDING_PDA_SEED` to
amm_core, updates new_definition to emit two sequential chained calls
(create LP definition + lock holding, then mint user share), and adjusts
remove liquidity to account for the permanently locked floor.

BREAKING CHANGE: NewDefinition instruction requires an additional LP-lock
holding account derived via `compute_lp_lock_holding_pda(amm_program_id, pool_id)`.
2026-04-09 14:33:49 +02:00
r4bbit
f89a8f9865 chore: update spel and logos-execution-zone dependencies
This removes the need to depend on a custom version, since the necessary
changes have landed in `spel` upstream.
2026-04-01 17:19:36 +02:00
r4bbit
9ebd9fcc12 cleanup(ata): remove redundant test directive 2026-04-01 17:11:51 +02:00
r4bbit
cb8426cbf1 skills: update spel-cli references to use spel 2026-04-01 12:17:52 +02:00
r4bbit
6287bd9df9 chore(ata): add IDL for ata program 2026-04-01 12:17:26 +02:00
r4bbit
45ed284825 chore: initial repository setup for programs 2026-03-30 23:58:43 +02:00
r4bbit
d61d02adf6
Initial commit 2026-03-17 10:18:51 +01:00