This relaxes some of the rules introduced in the previous commit.
To simplify testing, building and formatting locally and on CI, we also
introduce a dedicated makefile
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
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.
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.
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.
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
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.
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.
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.
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
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
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.
- 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`.
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
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
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.