WIP Juno DEX#1
Draft
JakeHartnell wants to merge 34 commits into
Draft
Conversation
First commit on the juno/main trunk branched from upstream v5.13.1. Lands the planning/ folder skeleton with five docs: - 00-overview.md: index, status, operating posture (AI audit, permissionless v1, local-only trunk, no JunoClaw coordination) - 01-strip-list.md: canonical table of keep/defer/delete contracts - 03-whitelist-decision.md: ADR D2 — Neutron-strip vs replace vs drop; chose Neutron-strip - 04-incentives-types-decision.md: ADR D1 — keep packages/astroport/src/ incentives.rs as types-only; do not refactor factory's import - 05-toolchain-and-ci.md: Rust 1.81.0 pin, optimizer 0.17.0, cw-multi-test fork policy, cosmwasm-check capability flags 02 (juno-patches), 06 (deploy-runbook), 07 (audit-scope), 08 (test-matrix), 09 (roadmap), 10 (open-questions) materialize when their phases begin. Source code is untouched in this commit; subsequent commits perform the strip described in 01-strip-list.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…y-deferred pairs
Workspace [members] now lists the seven kept contracts + the three kept
packages (astroport, astroport_test, circular_buffer) explicitly. pair_stable
and pair_concentrated, plus astroport_pcl_common, are moved to [exclude] —
retained in-tree for the v1.1 (stable) and v1.2 (PCL) re-add targets but not
built in v1.
Contract directories deleted entirely:
- pair_concentrated_duality (Neutron dex precompile)
- pair_supervault_adapter (Neutron Supervault)
- pair_astro_converter (Terra burn-address cw20-ASTRO → TF migration)
- pair_xastro (xASTRO ↔ ASTRO swap)
- pair_transmuter (1:1 constant-sum; niche)
- pair_xyk_sale_tax (XYK + sale-tax; meme-launch flow is handled
orthogonally by cw-abc graduation per
memory/abc-graduation-architecture-astroport.md)
- pair_concentrated_sale_tax (PCL + sale tax; same reasoning)
See planning/01-strip-list.md for the canonical table.
Subsequent commits prune packages/astroport module exports, delete tokenomics/
and e2e/, Neutron-strip the whitelist contract, and rebuild router tests
against XYK pair only.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…crates.sh - contracts/tokenomics/ entirely (incentives, maker, staking, vesting, xastro_token). v1 ships with no native DEX token per memory/juno-defi-direction.md; the *types module* packages/astroport/src/incentives.rs is retained per ADR D1 (planning/04-incentives-types-decision.md). - e2e/ — Terra/Neutron-bound (@terra-money/feather.js + localterra-1 + localneutron-1). Juno-incompatible without a full rewrite; replaced by tests/juno_integration.rs in P3. - contracts/periphery/astro_converter and contracts/periphery/astro_converter_neutron — Terra cw20→TF migration contracts; no ASTRO on Juno. - scripts/publish_crates.sh — publishes under astroport-* crates.io ownership we don't have. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drop pub mod declarations and corresponding .rs files for modules whose contracts are deleted in v1: astro_converter, maker, pair_xastro, pair_xyk_sale_tax, pair_concentrated_sale_tax, pair_concentrated_duality, staking, vesting, xastro_token Also drops the now-dead `duality` feature flag. Kept: - incentives (types-only per ADR D1; the contracts/tokenomics/incentives contract is gone but contracts/factory/src/contract.rs:19 still imports the DeactivatePool message type, used in an unreachable generator_address: Some(_) code path) - pair_concentrated (types-only; the corresponding contract is excluded from workspace but retained in-tree as a v1.2 re-add target) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
packages/astroport: - Drop the `injective` feature flag and all #[cfg(feature = "injective")] branches in src/token_factory.rs. The Osmosis-style default path (/osmosis.tokenfactory.v1beta1.MsgCreateDenom etc.) is the canonical Cosmos-SDK pattern Juno's TokenFactory expects. packages/astroport_test: - Drop the `injective` feature flag from Cargo.toml + the matching #[cfg(feature = "injective")] branches in src/modules/stargate.rs. - Drop the `neutron-std` dep + delete src/modules/neutron_stargate.rs. This module was only used by the deleted Neutron pair tests; no live consumer in the kept set. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per ADR D2 (planning/03-whitelist-decision.md), restore vanilla cw1
semantics so the contract compiles on Juno's wasmd:
- Cargo.toml: drop neutron-sdk = "0.9.0" dependency.
- src/contract.rs:
- Drop neutron_sdk::bindings::msg::NeutronMsg + neutron_sdk::sudo::msg::
TransferSudoMsg imports.
- Drop the `sudo` entrypoint (only existed to satisfy Neutron's
IbcTransfer callback framework).
- Replace Response<NeutronMsg> with Response throughout.
- Drop the T: CustomMsg generic from execute_freeze and
execute_update_admins.
- ExecuteMsg<NeutronMsg> → ExecuteMsg<Empty> (proxy through standard
cosmos messages).
- src/ibc.rs: delete entirely (six unimplemented!() stubs that existed
only to satisfy Neutron IbcTransfer entrypoints).
- src/lib.rs: drop `pub mod ibc;`.
- Cargo.toml description updated to reflect Juno scope.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The router crate dev-depended on astroport-pair-concentrated. With PCL
excluded from the v1 workspace, both the dev-dep and the PCL-using test
scenarios must go.
contracts/router/Cargo.toml: drop astroport-pair-concentrated dev-dep.
contracts/router/tests/factory_helper.rs:
- Drop the pcl_contract Box::new block + pcl_code_id local.
- Drop PairConfig entries for PairType::Stable {} and
PairType::Custom("concentrated") from the factory's pair_configs vec.
Factory now only knows about Xyk in tests.
contracts/router/tests/router_integration.rs:
- Drop unused imports (Decimal, f64_to_dec, ConcentratedPoolParams).
- Replace two PairType::Stable {} scenarios (in router_does_not_enforce_
spread_assertion and route_through_pairs_with_natives) with XYK.
- Rewrite test_reverse_simulation to use PairType::Xyk {} + init_params:
None; the reverse-simulation behavior under test is independent of
pair-type semantics.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
contracts/pair/Cargo.toml:
- Drop dev-dep on astroport-incentives (the contract is deleted in v1).
- Drop the `injective` feature flag (astroport package no longer has one
to forward to).
- Drop the `metadata = { build_variants = ["injective"] }` line — that
was astroport-fi internal CI metadata, not used by cargo.
contracts/pair/tests/integration.rs:
- Drop the `store_generator_code` helper that stored the deleted
astroport-incentives contract code.
- Delete the `provide_liquidity_with_autostaking_to_generator` test
entirely (~210 lines). It exercised the auto-stake-on-provide path
where the pair calls generator.Deposit; v1 ships with
generator_address: None so that path is dead in production.
- Other tests that pass `generator_address: Some("generator")` to the
factory are untouched — they just register the address as a string
for the factory's Config, never instantiating the contract.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
contracts/periphery/oracle/Cargo.toml depended on astroport-pair-stable + astroport-pair + astroport-factory + astroport-test + astroport-native-coin-registry as dev-deps for its tests/integration.rs harness. pair-stable is excluded from the v1 workspace, breaking dependency resolution. Rather than rewrite the harness against the v1 keep set in isolation, delete the integration test entirely. Oracle's unit tests in src/testing.rs continue to cover the core math. Comprehensive oracle integration coverage (factory + pair + oracle TWAP queries) lands in P3's tests/juno_integration.rs at the workspace root, where the keep-set deploy sequence already exists. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
cargo update -w against the stripped workspace. Removes dependencies that came in only via deleted contracts: neutron-sdk, pyo3 (simulation tests in tokenomics/incentives), astroport-governance (vesting / staking), astroport-sims, and ~25 transitive crates. Kept on a separate commit so the strip diff above can be read without ~800 lines of lockfile churn. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two test-side fixups discovered during the first cargo test on the stripped workspace: - contracts/whitelist/examples/whitelist_schema.rs imported neutron_sdk::bindings::msg::NeutronMsg for the ExecuteMsg generic. After the Neutron-strip (commit 321e766), the schema-gen example fails to compile. Switch the ExecuteMsg<NeutronMsg> generic to ExecuteMsg<Empty>. - contracts/router/tests/router_integration.rs::test_reverse_simulation originally used PCL pairs (returns exact amounts). The rewritten XYK-only version of the test sees a 1-unit shortfall from integer- division flooring across a 2-hop ReverseSimulateSwapOperations → SimulateSwapOperations round-trip. Relax the assertion from `return_amount >= ask_amount` to `ask_amount - return_amount <= 1`. The test still verifies reverse simulation produces an offer amount that round-trips back to within 1 unit of the requested ask. All 4 router_integration tests and 7 factory_integration tests now pass on the stripped workspace. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… ceiling) scripts/check_artifacts_size.sh: 800 KB → 3072 KB. The 800 KB ceiling matched Terra's and Injective's wasmd MaxWasmCodeSize. Juno's wasmd default is ~3 MB; the tighter ceiling isn't ours. .github/workflows/check_artifacts.yml: - cosmwasm-check: drop `neutron` capability (Slinky/Neutron-dex precompile is not on Juno); add `cosmwasm_2_0` for forward compat with wasmvm v3.0.4 post-Juno-v30. Astroport v5.13.1 ships cosmwasm-std 1.5 → interface_version_8 which today's juno-1 already accepts; the v2.0 capability is preparatory. - actions/checkout@v3 → @v4. .github/workflows/code_coverage.yml: - Drop the codecov/codecov-action step (was tied to astroport-fi's CODECOV_TOKEN secret). - Replace deprecated actions-rs/toolchain@v1 with dtolnay/rust-toolchain@stable @ 1.81.0. - actions/checkout@v3 → @v4. .github/workflows/tests_and_checks.yml: - Replace deprecated actions-rs/{toolchain,cargo}@v1 actions with dtolnay/rust-toolchain + raw `cargo` commands. - Drop `--features tests-tube` from cargo test invocation. tests-tube was osmosis-test-tube integration; not in the stripped workspace. - Switch to `cargo test --workspace --no-fail-fast --locked` (explicit workspace scope). - styfle/cancel-workflow-action@0.11.0 → @0.12.1. - actions/checkout@v3 → @v4. .github/workflows/release_artifacts.yml: - actions/checkout@v3 → @v4. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- contracts/pair/tests/integration.rs: collapse the doubled blank line left behind by the autostake-test deletion (commit f4d7d06). cargo fmt --check on 1.81.0 was flagging it. - packages/circular_buffer/src/lib.rs: annotate the elided 'a lifetimes on Item<'a, BufferState> and Map<'a, u32, V> return types in CircularBuffer::state() / array(). Clippy on newer rustc surfaces these via the `mismatched_lifetime_syntaxes` lint; the explicit form is also clearer. Equivalent on 1.81.0. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pre-write the P2 ADR before the code lands so the audit narrative is in place. Covers: - Why the gate exists (cw-abc graduation flow MEV protection). - Gate-site discovery: native Swap and Cw20HookMsg::Swap both route through pair::swap(); single gate covers both. - Wire-protocol entry: extend XYKPoolParams with optional pool_unpause_at — backward-compatible deserialization, no factory edits. - File-by-file patch sites with rc0-tree line numbers. - Three-test plan: swap-rejects, LP-side-unaffected, unpause-elapses. - MIT shim crate (astroport-juno-types) design + drift defense. - Out-of-scope items (no factory edits, no UpdateConfig for the pause field, no LP-side gating). - Maps to the two-diff audit packaging (D3). Code commits follow this ADR in the planned sequence in ~/.claude/plans/great-let-s-make-a-sunny-kahan.md §"P2 execution commit sequence". Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Data-shape change only. No gate logic yet (lands in a separate commit so audit-diff B can isolate the actual fund-flow change). packages/astroport/src/pair.rs: - Extend XYKPoolParams with optional pool_unpause_at: Timestamp. - serde(default) so older callers omitting the field deserialize to None — backward-compatible wire format. contracts/pair/src/state.rs: - Extend Config with pool_unpause_at: Option<Timestamp>, persisted once at instantiate. No mutation path. - Import cosmwasm_std::Timestamp. contracts/pair/src/contract.rs: - In instantiate(), lift pool_unpause_at from decoded XYKPoolParams alongside track_asset_balances. Persist on Config alongside the existing fields. No swap-side gate yet. contracts/pair/src/testing.rs + contracts/pair/tests/integration.rs: - Mechanical field-add on existing Config literal and XYKPoolParams literals (test-only churn). All test bodies otherwise unchanged. cargo test -p astroport-pair --locked passes (26 unit + 13 integration). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
contracts/pair/src/error.rs:
- Add Timestamp to cosmwasm_std imports.
- Add PoolPaused { unpause_at: Timestamp } variant with thiserror
display "Pool is paused until {unpause_at}".
Variant is unused until the next commit wires the gate in swap().
Kept as its own commit so the error-enum extension is reviewable
independently of the fund-flow change.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
contracts/pair/src/contract.rs::swap():
- Immediately after `let mut config = CONFIG.load(deps.storage)?;`,
check `block.time < config.pool_unpause_at` and return
`ContractError::PoolPaused { unpause_at }` if the pool is still
paused.
One gate site covers both swap entry points:
- ExecuteMsg::Swap (native asset path, lines 249-273) calls swap()
directly.
- ExecuteMsg::Receive → Cw20HookMsg::Swap (cw20 path, lines 286-333)
dispatches into swap() after asset-info translation.
ProvideLiquidity and WithdrawLiquidity are intentionally not gated
— the graduation flow that consumes this primitive (cw-abc, see
memory/abc-graduation-architecture-astroport.md) seeds the pool
during the pause window and the LP cliff-locks in a DAO treasury
wrapper after unpause.
For pairs without a pause window (config.pool_unpause_at = None,
the wire-default for all v1 pair creations), the gate is bypassed
with zero behavior change vs upstream Astroport.
Existing pair tests pass (13 unit + 13 integration). Three new
tests covering the pause behavior land in the next commit.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
contracts/pair/tests/integration.rs:
- Add `Timestamp` to cosmwasm_std imports.
- New helper `instantiate_paused_pair(router, owner, unpause_at)` —
mirrors `instantiate_pair` but threads pool_unpause_at through
XYKPoolParams.
- New helper `seed_paused_pair(router, owner, pair)` — owner-provides
liquidity to a paused pair (intentionally exercises the LP entry
point during the pause window).
- New helper `pause_test_app()` — TestApp with sufficient bank
balances for the three scenarios.
Three new tests:
1. swap_during_pause_rejects — instantiate with pool_unpause_at =
now + 60s, provide liquidity, Swap must fail with
ContractError::PoolPaused { unpause_at: <same timestamp> }.
2. provide_and_withdraw_during_pause_succeeds — instantiate with
pool_unpause_at = now + 120s. Owner provides, Alice provides,
owner withdraws a slice. All three LP-side operations must
succeed. Final Swap during the same window still rejects —
confirms the gate is Swap-specific, not pair-wide.
3. unpause_elapses_then_swap_works — instantiate with pool_unpause_at
= now + 60s, provide liquidity, confirm Swap rejects, advance
block.time by 61s via app.update_block, confirm same Swap call
now succeeds.
16/16 pair integration tests pass on rustc 1.81.0.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
New workspace member at packages/astroport_juno_types/. Mirrors the wire types downstream CosmWasm consumers need to construct cross-contract calls into the deployed Astroport-Juno set, without inheriting GPL-3.0 via Rust linkage. Per ADR D4 (planning/02-juno-patches.md §"Patch 2"). Primary downstream consumer is the cw-abc graduation extension in dao-contracts (see memory/abc-graduation-architecture-astroport.md), which constructs a factory.CreatePair call with XYKPoolParams.pool_unpause_at set for MEV-protected graduation. Crate layout: - src/lib.rs — module exports + doc on the maintenance contract. - src/asset.rs — Asset, AssetInfo, PairInfo. - src/factory.rs — PairType, PairConfig, TrackerConfig, InstantiateMsg, ExecuteMsg::CreatePair, QueryMsg + response shapes. - src/pair.rs — XYKPoolParams (with the v0.1.1 pool_unpause_at field), InstantiateMsg, ExecuteMsg, Cw20HookMsg, QueryMsg + response shapes. - src/router.rs — SwapOperation, ExecuteMsg, Cw20HookMsg, QueryMsg + response shapes. Dependencies: cosmwasm-schema, cosmwasm-std, cw20. **No path-dep on astroport** — that would re-pull GPL transitively. Types are intentionally re-written (not re-exported). A CI drift gate lands in the next commit (P2.7) to fail builds where the JSON wire format diverges from packages/astroport. Cargo.lock updated to include the new workspace member. cargo build -p astroport-juno-types passes on 1.81.0. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two artifacts that together prove the MIT shim's wire format stays in
lock-step with packages/astroport (GPL):
packages/astroport_juno_types/examples/schema.rs:
- Emits JSON Schemas for each mirrored type under
packages/astroport_juno_types/schema/{asset,factory,pair,router}/.
- For IDE tooling and human review. Not load-bearing in CI.
packages/astroport_juno_types/tests/wire_drift.rs (THE drift gate):
- Dev-deps on the GPL astroport crate (scope is the test target only;
shipped library has zero GPL linkage).
- 9 round-trip tests covering Asset/AssetInfo, factory::PairType,
factory::PairConfig, factory::ExecuteMsg::CreatePair, pair::
XYKPoolParams (both with and without pool_unpause_at to verify
backward-compat for v0.1.0 callers), pair::ExecuteMsg::Swap, and
router::ExecuteMsg::ExecuteSwapOperations.
- Each test serializes a shim instance to JSON via cosmwasm_std::
to_json_string and asserts the upstream astroport type can
deserialize that JSON byte-for-byte.
No new CI workflow step required: the existing tests_and_checks.yml
runs `cargo test --workspace --no-fail-fast --locked` which picks up
the new test target automatically as part of the workspace.
9/9 drift tests green on rustc 1.81.0.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
cargo fmt --all collapsed the multi-line array literal in provide_and_withdraw_during_pause_succeeds (added in commit abc7abb) into a single-line form per workspace style. No semantic change. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…helper New crate at integration-tests/. Composability proof + deploy-runbook- in-code for the v1 Astroport-Juno keep-set. Not shipped (publish=false); the test target only. integration-tests/Cargo.toml: - name astroport-juno-integration-tests, license GPL-3.0 (transits the pair/factory/router deps). - Path-deps on the 6 kept contracts/packages + cw20-base + cw1-whitelist. integration-tests/src/lib.rs: - `mock_app()` — cw_multi_test StargateApp with realistic Juno-style bank balances pre-seeded for the deployer (1T ujuno + 1T mock_usdc + 1T mock_atom). - `deploy_keep_set(app)` — mirrors planning/06-deploy-runbook.md step-for-step. Stores 6 code IDs, instantiates native_coin_registry (registering ujuno=6, ibc/USDC=6, ibc/ATOM=6), whitelist (vanilla cw1 — proves post-Neutron-strip compiles + instantiates), factory (zero-maker-fee XYK config, permissionless), router. - `KeepSetHandles` struct returns all addresses + code_ids for the test files to consume. - `fund()` / `balance_of()` convenience wrappers. Cargo.toml: integration-tests added to workspace [members]. Cargo.lock regenerated to pick up the new workspace member. cargo build -p astroport-juno-integration-tests passes on 1.81.0. Test files (deploy_sequence / multi_hop_routing / paused_via_factory) land in subsequent commits. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
integration-tests/tests/deploy_sequence.rs — 2 tests:
1. deploy_keep_set_create_xyk_pair_and_round_trip — the full deploy
runbook end-to-end:
- bootstrap mock_app with Juno-style bank balances
- deploy_keep_set (registry seed, whitelist, factory, router)
- CreatePair(Xyk, [ujuno, mock_usdc])
- assert TF LP denom shape is exactly factory/{pair}/astroport/share
— this is what the UI relies on; not asserted as a string match
anywhere else.
- alice + bob each ProvideLiquidity 100B/100B
- assert total LP supply = sum of LP balances + the contract-side
MINIMUM_LIQUIDITY reserve
- alice swaps 1B ujuno → mock_usdc, assert non-zero return < offer
(constant product + 30 bps fee)
- alice WithdrawLiquidity 25%, assert ujuno+mock_usdc returned and
total LP supply decreased by exactly the burned amount
2. whitelist_post_neutron_strip_registers_under_expected_cw2_name —
explicit assertion that the post-Neutron-strip whitelist still
registers as `astroport-whitelist` in cw2. Downstream tooling that
greps for that contract name keeps working.
Adds cw2 = "1.1" as a direct dev-dep for the cw2 contract-info read.
2/2 tests pass on rustc 1.81.0.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
integration-tests/tests/multi_hop_routing.rs:
- Two pair seed: (ujuno, ibc/USDC) + (ibc/USDC, ibc/ATOM).
- One test, router_two_hop_ujuno_usdc_atom, exercising the three
router code paths sequentially:
1. SimulateSwapOperations for ujuno → ibc/USDC → ibc/ATOM. Assert
non-zero output.
2. ExecuteSwapOperations with the same path. Assert the trader's
ibc/ATOM balance increased by exactly the simulated amount
(deterministic pool state guarantees exact equality).
3. ReverseSimulateSwapOperations for the same path, ask_amount =
SWAP_INPUT/10. Assert non-zero offer requirement.
The per-contract router_integration::test_swap_route already covers
the math correctness; this test asserts the deploy-sequence wiring
(factory creates pairs that the router can find) actually works
end-to-end with Juno-shaped denoms.
Helper `create_pair_and_seed` is local to this test file — same
pattern will be needed in paused_via_factory.rs, may get lifted to
src/lib.rs in a refactor if it grows.
1/1 test passes on rustc 1.81.0.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
integration-tests/tests/paused_via_factory.rs — one test,
pool_unpause_at_threaded_through_factory_create_pair, asserting the
exact wire path the cw-abc graduation flow will use:
1. deploy_keep_set
2. factory.CreatePair { Xyk, [ujuno, mock_usdc], init_params: Some(
to_json_binary(&XYKPoolParams { pool_unpause_at: Some(now + 60),
... })?) }
3. lpwallet.ProvideLiquidity must succeed during the pause window —
the seeder needs LP entry points to fund the pool.
4. sniper.Swap must fail with ContractError::PoolPaused { unpause_at:
<exactly the timestamp passed via CreatePair's init_params> }.
This is the load-bearing assertion: it proves the field survives
the Binary pass-through through factory → pair instantiate → Config
→ swap() gate intact.
5. app.update_block advances time by 61s; the same sniper.Swap call
now succeeds.
The pair-side tests in P2.5 already cover the gate behavior with
directly-instantiated pairs. This test exists so the audit firm can
trace the wire path of one specific consumer (cw-abc graduation) in
a single test.
1/1 test passes on rustc 1.81.0.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mechanical cargo fmt --all sweep across the three test files and src/lib.rs (one-line vs multi-line array literal collapsing). No semantic change. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Refresh the status-at-a-glance table now that integration-tests have landed. P3 is additive to v0.1.1-juno-rc1 (no new tag) per the audit- diff packaging in 02-juno-patches.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Re-introduce astroport-incentives from upstream v5.13.1 (deleted in P0
as part of contracts/tokenomics/), strip its xASTRO/maker/vesting
tangle, and bind its admin-only SetupPools call to a DAO DAO gauge
adapter so the Juno DAO can vote on emissions allocation per pool.
Architecture (3 layers; bottom two are pre-existing):
- gauge-orchestrator (feat/gauges in dao-contracts) — voters allocate
weight across pool LP denoms each epoch
- astroport-incentives-adapter (new; in dao-contracts/feat/gauges) —
translates gauge tally to WasmMsg::Execute { SetupPools }; mirrors
gauge-budget-allocator's shape
- astroport-incentives (re-introduce + strip; this repo) — emits
ujuno per-second from its bank balance; LPs accrue passively via
the tokenfactory_tracker we kept in P0; permissionless external
incentives via Incentivize { lp_token, schedule } for any reward
token (native or cw20)
Two cw20 axes are independent and treated differently:
- cw20-as-LP — STRIPPED (Astroport-Juno LPs are TF-only per P0)
- cw20-as-reward-token — KEPT (Juno has real cw20 in circulation;
projects must be able to incentivize pools with their own token)
cw20 runtime dep stays.
Slot: P2.5, between rc1 and P4 audit handoff. New tag v0.1.2-juno-rc2.
Audit handoff becomes three diffs (mechanical strip / pool_unpause_at /
incentives re-add+strip) — actually better-shaped than two; each has
a clear cost basis.
Settled open questions (per Jake 2026-05-13):
- adapter location: dao-contracts/feat/gauges extension
- spam fee default: 100 ujuno (tunable via UpdateConfig)
- MAX_REWARD_TOKENS: 5 (upstream parity)
- adapter authority: cw_ownable (single owner = DAO core)
…ace)
git checkout v5.13.1 -- contracts/tokenomics/incentives/ — verbatim
restore of upstream Astroport incentives contract. Excluded from the
workspace [members] for now; the Juno modifications (strip cw20-LP
path, strip vesting/astro_converter/pair-stable deps, generalize
reward_token, add UpdateBudget) land in the following commits.
This restore exists for audit-diff readability: the auditor can diff
upstream verbatim against the Juno modifications without conflating
deletions ("strip") with semantic changes ("Juno specifics").
See planning/11-incentives-and-gauges.md.
This is the Juno-specific surgery on top of the verbatim upstream
restore in the previous commit. Three logical changes batched into one
commit so the workspace stays building:
1. **cw20-LP staking entry point stripped.** ExecuteMsg::Receive +
astroport::incentives::Cw20Msg deleted. Astroport-Juno LPs are TF-only
(P0 stance), so the cw20-LP deposit path is dead. The cw20 RUNTIME
dep stays — it's load-bearing for the reward-token side (cw20 funders
call Incentivize via cw20::IncreaseAllowance + TransferFrom, and
ClaimRewards dispatches cw20::Transfer outbound when reward is cw20).
Strip surface: ~20 LoC in execute.rs (Receive arm) + ~10 LoC in
packages/astroport/src/incentives.rs (Cw20Msg type + Receive variant).
2. **astroport-vesting dependency stripped.** Upstream incentives reads
each tick's emission from astroport-vesting; we deleted that whole
contract in P0. Replaced with: incentives holds the reward_token
budget directly in its own bank balance; claim_rewards() dispatches
the protocol payout via reward_token.with_balance(...).into_submsg(...)
instead of wasm_execute(&vesting_contract, vesting::Claim {...}).
This automatically handles native or cw20 reward tokens via AssetInfoExt.
Strip surface: vesting_contract field removed from InstantiateMsg /
Config / UpdateConfig; `use astroport::vesting` removed from utils.rs.
3. **ASTRO-specific naming generalized.** astro_token → reward_token,
astro_per_second → reward_per_second, disable_astro_rewards() →
disable_internal_rewards(), set_astro_rewards() → set_internal_rewards().
The internal reward token is now immutable post-instantiate (rotation
requires migration); upstream's UpdateConfig.astro_token field is gone.
Old upstream tests (tests/, examples/serialization_cost.rs) deleted —
they referenced astroport-vesting / astroport-pair-stable / astro-token-converter
(deleted in P0) and astroport-vesting_131 (no replacement). Integration
coverage will land in /workspace/astroport-core/integration-tests as
part of P2.5.6.
Dev-deps trimmed accordingly: astroport-vesting, astroport-vesting_131,
astro-token-converter, astroport-pair-stable, proptest all gone.
Workspace gate: build / clippy / test all green on rustc 1.81.0.
See planning/11-incentives-and-gauges.md.
added 4 commits
May 13, 2026 22:57
Mirrors the post-strip astroport::incentives types into the MIT shim so downstream consumers (the DAO DAO gauge adapter, project funding contracts, UIs) can construct cross-contract calls without taking a GPL-3.0 dep on `astroport`. New shim module: `packages/astroport_juno_types/src/incentives.rs`. ExecuteMsg variants mirrored (the downstream-callable subset): - SetupPools — dispatched by the gauge adapter each epoch close - ClaimRewards — for LPs / farm wrappers - Deposit / Withdraw — TF-LP stake / unstake (cw20-LP path NOT mirrored; it was stripped in P2.5) - SetTokensPerSecond — admin (owner) sets internal emission rate - Incentivize / IncentivizeMany — permissionless external incentives, native or cw20 reward tokens QueryMsg variants mirrored (UI / contract read surface): - Deposit, PendingRewards, RewardInfo, PoolInfo, ActivePools Plus the response types: RewardType, RewardInfo, PoolInfoResponse. Admin-only mutations (UpdateConfig, RemoveRewardFromPool, ClaimOrphanedRewards, UpdateBlockedTokenslist, ownership transfer, DeactivatePool, DeactivateBlockedPools) intentionally NOT mirrored — the shim is for downstream callers, not admin tooling. Wire-drift test coverage: 7 new round-trip tests in tests/wire_drift.rs (16 total). Highlights: - incentives_setup_pools_roundtrip — the load-bearing gauge wire path - incentives_incentivize_cw20_reward_roundtrip — proves the cw20-LP strip didn't break cw20-as-reward-token (audit regression gate) - incentives_pool_info_response_roundtrip — UI query response shape Schema example regenerated with an "incentives" subdirectory under packages/astroport_juno_types/schema/. Workspace gate: cargo build/clippy/test/fmt all green on rustc 1.81.0. Also includes formatter pass on utils.rs (reformatted the new into_submsg() call site in claim_rewards). See planning/11-incentives-and-gauges.md.
Three new test files under integration-tests/tests/ exercising the P2.5
incentives contract composability with the keep-set:
1. **incentives_setup_pools.rs** (2 tests) — admin-side gauge wire path:
- `incentives_setup_pools_internal_emission_accrues_to_lp` —
full deploy → CreatePair → Alice stakes → SetupPools + rate +
fund → advance 10s → ClaimRewards. Asserts ~100 ujuno/sec
accrued for the sole LP (±1 for Decimal256 flooring).
- `incentives_generator_controller_can_call_setup_pools` —
UpdateConfig wires a controller addr; controller can call
SetupPools, a random address cannot. This is the security
boundary the DAO DAO gauge adapter relies on.
2. **incentives_external_native.rs** (1 test) — third-party native
incentive flow: funder mints PROJECT_REWARD (a synthetic TF denom),
calls `Incentivize { ..., reward: native }` with info.funds. After
advancing past the schedule's epoch start, the LP claims and
receives the project reward via BankMsg::Send.
3. **incentives_external_cw20.rs** (1 test) — **AUDIT REGRESSION GATE**
for the cw20-LP strip. Deploys a cw20 reward token; funder grants
IncreaseAllowance; calls `Incentivize { ..., reward: Token { ... } }`;
contract pulls via cw20::TransferFrom; LP claims; contract dispatches
cw20::Transfer outbound. If the cw20-LP strip accidentally broke the
cw20-as-reward path, one of these three calls would fail. Test passes
→ strip didn't regress the reward-side.
Bech32 mode (load-bearing for these tests):
- Switched integration-tests/src/lib.rs to use MockApiBech32("juno") +
MockAddressGenerator so `addr_validate("factory/juno1xxx/astroport/share")`
correctly fails (slashes aren't valid bech32). This forces TF LP
denoms to be parsed as AssetInfo::NativeToken in determine_asset_info
rather than mis-classified as a cw20 contract address.
- Existing P3 tests updated to use `app.api().addr_make(...)` instead of
Addr::unchecked for canonical addresses. All 4 pre-existing integration
tests still pass (deploy_sequence×2, multi_hop_routing, paused_via_factory).
- New TestApp type alias replaces `astroport_test::modules::stargate::StargateApp`
(which is hardcoded to the default MockApi).
Keep-set tweak: `is_generator_disabled` flipped from `true` to `false`
on the XYK PairConfig so the factory's BlacklistedPairTypes query
doesn't reject XYK pools for incentives registration. This is the
correct posture now that incentives is v1 scope.
Workspace gate: build/clippy/test/fmt all green on rustc 1.81.0.
8 integration tests total (4 pre-existing + 4 P2.5).
See planning/11-incentives-and-gauges.md.
Per-decision rationale for the rc1→rc2 strip surface, intended to be
read alongside the audit diff. Covers:
- D6.1 No vesting (DAO holds budget directly via BankMsg)
- D6.2 Strip only cw20-LP entry point, NOT cw20 entirely
(cw20-as-reward-token preserved — Juno has real cw20 tokens)
- D6.3 reward_token immutable post-instantiate (rotation = migration)
- D6.4 ASTRO-token naming generalized to reward_token / internal
- D6.5 MAX_REWARD_TOKENS = 5 kept (worst-case gas profile documented)
- D6.6 Owner / generator_controller separation preserved (gauge fit)
- D6.7 incentivization_fee_info default None at instantiate
(DAO sets via UpdateConfig — suggested 100 ujuno)
- D6.8 Test infrastructure: bech32 mode mirrors production chain
- D6.9 Keep-set tweak: is_generator_disabled = false on XYK PairConfig
(was true in P0/P3 when incentives didn't exist)
Also references the AUDIT REGRESSION GATE
(integration-tests/tests/incentives_external_cw20.rs) and the wire
shim drift gate. Lists three open audit follow-up items.
Updated 00-overview.md document index to register the new ADR.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.