Skip to content

[PROPOSAL] RFP-016 — Synarton LBP #196

Description

@icedevera

RFP ID

RFP-016 — Token Launchpad: LBP

Your Project Name

Synarton LBP

Team or Organization Name

VacuumLabs

Primary Contact

peter.hucik@vacuumlabs.com

Team Members

# Name / pseudonym Social links Role Status
1 Boris Hristov GitHub / CV Tech lead / Senior Full-stack Engineer Full-time
2 Ladislav Dubravský GitHub / CV Senior Full-stack Engineer Full-time
3 Goktug Gurbuzturk GitHub / CV Senior Full-stack Engineer Full-time
4 Marek Roštár GitHub / CV Project Manager / Utility Dev Full-time
5 0xcr1st0f CV Advisor Part-time
6 Uroš Kočišević GitHub / CV Chief Product Officer Full-time

Project Summary

We propose Synarton LBP, a time-limited Liquidity Bootstrapping Pool on the Logos Execution Zone (LEZ). The work includes the on-chain program. The typed SDK, CLI, sale analytics, and Basecamp mini-app all share one Rust client core.

Pool state stays public. Every buyer sees the same reserves, weights, price, and sale progress. A buyer can buy directly from a public account or privately through a fresh, single-use account. The SDK manages setup, deshield, buy, recovery, and mandatory re-shield as one resumable user action. An optional ZK Merkle allowlist proves eligibility without publishing the credential or eligibility set.

Synarton LBP starts with a high scheduled price and uses time-driven weights to lower it unless demand pushes it back up. Each sale has a fixed end time, an optional sale-wide per-block token ceiling, a pause that leaves the weight schedule running, and one protocol fee collected at withdrawal. After settlement, an optional adapter can pass creator proceeds or unsold tokens to a separate vesting program without changing the private buyer flow or bringing vesting logic into Synarton LBP.

RFP-015 is a separate submission and a separate delivery — its own scope, milestones, timeline and budget, deliverable on its own. Where both are awarded, the two run as one Synarton product, with an LBP option and a bonding-curve option. Reuse between them is opportunistic rather than a dependency.

Technical Approach

Citations below use path:line at these revisions: logos-execution-zone 3e1412ee6afe, lez-programs 09f3d594a750, SPEL 0cb7e0980535, and the RFP checkout 6446600ce3a3. Milestone 0 replaces them with one compatible testnet 0.2 release and records source revisions, deployed program IDs, and artifact hashes.

1. Architecture

Basecamp mini-app        CLI        External integrators
        \                 |                 /
         +------ Rust SDK and client core -------+
                       |
                  SPEL IDL
                       |
              LBP program on LEZ
                 |      |      |
                 |      |      +-- private allowlist authorization
                 |      +--------- CLOCK_01
                 +---------------- ATA program -> token program

The SPEL-annotated program is the source of the IDL. Generated SPEL instruction clients feed the hand-written Rust core. The core owns quotes, call construction, account validation, private-operation recovery, typed errors, analytics reads, FFI, typed queries, and CLI and QML integration. The SDK exposes that core to external integrators; the CLI and QML backend use it directly.

The LBP program owns sale state. Token balances sit in canonical token-program ATAs at a Sale PDA. Every transfer goes through the ATA program and then the token program. For pool transfers, the LBP authorizes the Sale PDA with LBP seeds, and the ATA program authorizes the holding with ATA seeds.

2. Platform fit

RFP-016's dependency list does not fully describe the pinned mainline. The table records the reading used for this proposal.

Dependency RFP text Pinned code Decision
LEZ clock Delivered as an on-chain timestamp source (RFP-016 L560-566). CLOCK_01 refreshes every block (lez/programs/clock/src/main.rs:3-8,82). The sequencer appends the clock transaction after user work (lez/sequencer/core/src/lib.rs:1053-1178), so a buy reads the preceding-block timestamp. Production creates blocks from one fixed timer (lez/sequencer/service/src/lib.rs:132,183-194) and does not accelerate under load. A 30 August 2026 live-testnet sample at head 30,678 found a 60.2-second mean interval; 7,571 of 7,581 sampled consecutive pairs were exactly 60 seconds. Clamp the readable clock to the sale endpoints before interpolation. Enforce a seven-day minimum sale duration on the pinned release and disclose the bound in creator and buyer quotes. Rerun the interval measurement and price table in M0.
LP-0015 chained calls Closed and delivered for protected continuations (RFP-016 L568-576). MAX_NUMBER_CHAINED_CALLS = 10 (lee/state_machine/src/state/mod.rs:21). Public execution checks chain_calls_counter <= 10 before increment (lee/state_machine/src/validated_state_diff/mod.rs:108-112). The private host prover rejects at chain_calls_counter >= 10 (lee/state_machine/src/privacy_preserving_transaction/circuit/mod.rs:107-109). Limit every program path to ten total executions, the tighter private-path bound. Publish decoded traces before the core build starts.
Private execution The allowlist should use ZK set membership (RFP-016 L161-166). Public messages include instruction data (lee/state_machine/src/public_transaction/message.rs:13-19), while private messages expose public post-states rather than instruction data (lee/state_machine/src/privacy_preserving_transaction/message.rs:20-27). Receipt assumptions and env::verify are available on the privacy-preserving path (lee/state_machine/src/privacy_preserving_transaction/circuit/mod.rs:126-128; lee/privacy_preserving_circuit/src/execution_state.rs:143-155). Keep the Merkle leaf and path in a private witness. A privacy-preserving authorization entrypoint writes a short-lived one-use public authorization record for a later public Buy.
LP-0013 token authority The dependency section calls LP-0013 an open transfer-authority blocker (RFP-016 L537-543), while Resources calls it mint authority (RFP-016 L616). The prize is closed and delivered a mint-authority model (lez-programs/programs/token/core/src/lib.rs:20-31,60-80). Token Transfer still requires sender.is_authorized (lez-programs/programs/token/src/transfer.rs:7-12). Per-call pda_seeds grant that authorization (lee/state_machine/src/validated_state_diff/mod.rs:133-141). Hold both reserves in token-program ATAs at the Sale PDA. Keep later authority helpers behind small adapters.
LP-0014 ATAs Required for every token interaction (RFP-016 L252-255). ATA::Transfer requires an initialized recipient and then chains a token Transfer with PDA seeds (lez-programs/programs/ata/src/transfer.rs:7-70). ATA::Create can claim a default owner (lez-programs/programs/ata/src/create.rs:14-17,55-68). Derive and validate every token account. Initialize or native-fund a fresh owner before creating its ATAs, and pre-create both buyer ATAs before deshield.
LP-0012 events Listed as closed (RFP-016 L578-584). The accepted solution defines emit_event and getTransactionReceipt. Those names are absent from the pinned LEZ tree. Define event schemas behind an adapter. Poll sale state and transaction ranges until the event interface lands.
RFP-001 and RFP-002 Closed, with libraries in development (RFP-016 L545-552). Both RFPs are status: closed. The pinned SPEL tree has no require_admin or freeze-authority library. Keep fee configuration and pause authorization behind separate adapters. Integrate the awarded interfaces by M4 when available. If either remains unavailable, M4 requires an explicit written Logos waiver.
User-paid gas U1 and U7 require collateral and gas handling for the private path (RFP-016 L259-266, L292-296). Public execution is capped at 32M cycles with TODO: Make this variable when fees are implemented (lee/state_machine/src/program/mod.rs:13-15). Testnet 0.2 exposes no client fee-estimation RPC. Build the gas leg and preflight against a deterministic fixture. Activate live estimation when the network exposes it.
Basecamp packaging The mini-app must load through a git repository and include local build instructions and assets (RFP-016 L267-275). Basecamp installs core modules and UI plugins as separate packages (logos-docs/docs/basecamp/install-and-load-a-module-in-logos-basecamp.md:20-29,45-60). Scaffold requires packages.<system>.lgx; #lgx targets scaffold-managed installs and #lgx-portable targets hand-loaded AppImage artifacts (scaffold/docs/basecamp-module-requirements.md:11-18,62-76,161-180). Ship separate Synarton LBP core-module and QML UI-plugin packages. Both expose lgx and lgx-portable. The client core pins the LEZ monorepo revision used by the sequencer, and the UI pins its core dependency. Test managed and portable load paths in dependency order from a clean clone.
Testnet 0.3 and mainnet Separate milestones are required (RFP-016 L326-329, L347-348). Their release dates are outside our control. Keep both deployments as fixed-scope milestones triggered by platform availability.

The adapters keep public program and client interfaces stable while dependencies change. Initial authority-library compliance is still an M4 gate, through integration or a written Logos waiver.

3. Sale state and custody

The program uses four bounded account types:

  • GlobalConfig stores the admin adapter, freeze adapter, current protocol fee rate, current treasury ATA, and configuration version.
  • Sale stores the token pair, program IDs, weight schedule, start and end times, tracked reserves, creator collateral seed, cumulative collateral contributed by successful buys, optional allowlist root, optional per-block ceiling, last accepted clock value, block counter, dashboard weight snapshot, pause state, and withdrawal state.
  • Authorization stores an allowlist root, sale ID, fresh buyer key, nonce, expiry, and consumed flag.
  • SaleIndex uses paged PDAs for active and completed sale discovery. No account grows without a bound.

A sale moves through Pending, Active, Ended, and Withdrawn. Runtime validity windows enforce the start and end boundary. Pause controls only whether Buy accepts a transaction; it does not freeze time or weights.

The weighted-pool formula is undefined when either initial reserve is zero. A nonzero collateral reserve is therefore a safety precondition for the RFP's specified mechanism, not an optional sale feature. As part of CreateSale, the creator funds the project-token reserve and a positive collateral reserve; the program rejects either zero amount before transfer. The initial collateral is recorded as the creator seed and returned at withdrawal.

Tracked reserves set the price. Only successful sale operations change them. The program counts buy contributions separately from the seed and reads reserve ATAs before each operation. It rejects an observed balance below the tracked amount. An unsolicited transfer can increase an ATA balance, but cannot change the price or total raised.

RFP-016 describes the fee base once as collateral_balance (L183) and elsewhere as collateral raised (L233-235). Synarton LBP resolves that inconsistency in favor of collateral raised: the fee base is cumulative collateral contributed by successful buys only, excluding the creator seed and unsolicited excess. Withdraw reads the current fee rate and treasury from GlobalConfig, so an admin update applies uniformly to open and future sales as required by RFP-016 L192-195. The program rejects fee_rate > fee_scale:

fee = ceil(cumulative_collateral_in * current_fee_rate / fee_scale)
creator_proceeds = actual_collateral_balance - fee

M0 freezes and publishes the accounting vectors for this rule.

4. Weights, pricing, and integer arithmetic

w_token(t) = w_start + (w_end - w_start) * (t - t_start) / (t_end - t_start)
w_collateral(t) = 1 - w_token(t)

spot = (reserve_collateral * w_token) /
       (reserve_token * w_collateral)

tokens_out = reserve_token *
             (1 - (reserve_collateral /
             (reserve_collateral + C_in)) ^
             (w_collateral / w_token))

This is the RFP's Balancer-style reference. Weights use Q64.64 fixed point and remain between 1% and 99%. The program derives w_collateral as SCALE - w_token, so the pair cannot drift. Reserves and token amounts use u128. Multiplication and division use U256 intermediates with checked conversion back to u128.

The exponent kernel computes pow(x, y) = exp2(y * log2(x)). For each buy, the program derives sound fixed-point intervals for both x = reserve_collateral / (reserve_collateral + C_in) and y = w_collateral / w_token. Because pow increases with x and, for 0 < x < 1, decreases with y, the adverse corner is the upper bound of x and the lower bound of y. The kernel then takes the approximation's upper bound, clamps it to [0, 1], subtracts from one, and floors the final multiplication by reserve_token. This maximizes pow, minimizes tokens_out, and rounds against the buyer.

M0 publishes the minimum supported x, or an equivalent maximum C_in / reserve_collateral ratio, with coefficients, error bounds, overflow envelope, guest size, and cycle cost. Buy rejects an input outside that proven domain before any transfer. It also rejects tokens_out == 0 unconditionally before checking min_tokens_out, so a caller cannot opt into a zero-output trade by setting the minimum to zero. Differential tests compare the full interval calculation with a high-precision reference across the accepted domain. Property tests cover weight endpoints, monotonic weight movement, traded-state reserve updates, conservation, zero-output rejection, and every rounding boundary.

Equal AMM weights do not create a fixed price because reserve changes still move the spot. The soft fixed-price mode in RFP-016 L442-446 needs a separate rational quote function. It is included only if M0 shows that it can reuse the same custody and client flows without delaying the LBP. It has no payout of its own.

Buy derives weights from CLOCK_01 for every transaction. Poke writes only a dashboard snapshot, so a missing or stale poke cannot change the execution price. The weight uses the preceding-block timestamp, the finest account-visible time in the pinned LEZ release, not the exact current transaction time. Before interpolation, the program clamps that readable timestamp to [t_start, t_end]. A transaction accepted just after t_start therefore uses w_start rather than extrapolating above it, and a post-end snapshot cannot move below w_end.

A live-testnet sample taken on 30 August 2026 at head 30,678 found a 60.2-second mean block interval, with 7,571 of 7,581 sampled consecutive pairs exactly 60 seconds. The production service schedules ProduceBlock from one fixed interval, so load does not shorten that interval. The normal CLOCK_01 age is therefore about 0 to 60 seconds.

For clock age delta_t and sale duration T, token-weight lag is bounded by abs(w_end - w_start) * delta_t / T. Applying 60.2 seconds to the full 99/1 to 1/99 schedule gives this conservative marginal spot-price overstatement at either endpoint:

Sale duration Endpoint marginal price overstatement
7 days 0.99%
3 days 2.30%
12 hours 13.81%

These figures are modelled from the RFP formula, not measured execution quotes. A finite trade's output difference also depends on its size and the reserves. M0 reruns the interval measurement on the pinned release and publishes quote differences at both endpoints, the midpoint, and three trade sizes.

The error peaks at both sale endpoints because weight sensitivity is proportional to 1 / (w * (1 - w)). It is also one-directional: because token weight decreases over time, an older readable weight is higher. With reserves held equal, the buyer receives no more than under the exact-time weight. Lazy computation therefore satisfies RFP-016 L507-519 by removing stale stored-weight arbitrage; the remaining preceding-block error is bounded quote inaccuracy and a fairness issue, not an extractable discount.

Synarton LBP enforces a seven-day minimum sale duration on the pinned 60-second release, keeping the endpoint marginal bound near 1%. M0 recomputes that minimum if the measured interval changes. The creator view shows the interval assumption and worst endpoint bound before sale creation. Every pre-buy quote shows the readable clock age and its modelled drift bound. min_tokens_out protects changes between the client quote and execution; it does not remove clock lag.

The program accepts equal clock timestamps within one block and rejects a clock value below the last accepted value. Quotes are computed against the current readable CLOCK_01 value and protected at execution by min_tokens_out.

5. Buy flow and execution budget

A public buy performs these steps in one LEZ transaction:

  1. Validate the Sale PDA, signer, program IDs, token definitions, pre-created ATAs, pause state, and withdrawal state.
  2. If allowlisted, validate an unconsumed Authorization against the sale root, sale ID, signer key, nonce, and expiry.
  3. Set the ProgramOutput timestamp validity window to [t_start, t_end) for a direct buy, or [t_start, min(t_end, authorization_expiry)) for an allowlisted buy, for runtime enforcement against the current block timestamp.
  4. Read tracked reserves and confirm that reserve ATAs cover them.
  5. Clamp the readable CLOCK_01 timestamp to [t_start, t_end], derive weights, compute the conservative output, check the proven input domain, require tokens_out > 0, and check min_tokens_out.
  6. Apply the optional sale-wide per-block ceiling.
  7. Transfer collateral into the reserve ATA.
  8. Transfer project tokens to the buyer's pre-created project-token ATA.
  9. Update reserves and counters, and consume the authorization when present.

A failed validation, authorization, transfer, ceiling, domain, or slippage check leaves both buyer and sale unchanged.

The per-block ceiling reads CLOCK_01.block_id. The sale stores last_block_id and tokens_sold_in_block. A new block ID resets the counter. A repeated ID adds the new output and rejects before transfer if the total would exceed the configured ceiling. Because the clock updates after user transactions, every buy in one block reads the same preceding block ID, so the counter groups them consistently. The ceiling applies to the sale, and rotating buyer accounts does not bypass it.

Path Design budget
CreateSale 9 executions
Private allowlist authorization 1 privacy-preserving execution
Buy 5 executions
Allowlisted Buy after separate authorization 5 executions
Direct Withdraw 7 executions
Withdraw with optional post-end vesting handoff 8 executions
Close 1 execution
Poke, Pause, or Resume 1 execution

The standard buy is the root Buy, two ATA calls, and two token transfers. CreateSale budgets one root, two ATA creates, two token-account initializations, and two funded ATA transfers with their two token transfers. Direct Withdraw is one root plus three transfers of two executions each: fee to treasury, proceeds to creator, and unsold tokens. The private authorization is a separate privacy-preserving transaction outside the public Buy call chain. These are design budgets. M0 publishes generated call graphs and decoded traces for CreateSale, private authorization, direct Buy, authorized Buy, direct Withdraw, handoff Withdraw, Close, Poke, Pause, and Resume.

6. Private buy flow

The SDK exposes the private path as one resumable user operation:

  1. Generate a fresh public key and durable local journal entry.
  2. Initialize or native-fund the owner before any ATA::Create.
  3. Pre-create canonical collateral and project-token ATAs for that owner.
  4. Authorize the allowlist operation if the sale requires it.
  5. Deshield collateral and the required native balance. The network may require separate private transfers for different programs.
  6. Immediately before Buy, require the collateral ATA to equal the exact expected collateral amount and the owner account to equal the exact expected native balance.
  7. Submit the public Buy from the fresh account.
  8. Re-shield purchased project tokens, unused collateral, and remaining native value to validated shielded destinations. Use separate private transfers where the involved programs require them.
  9. Retire the public key only after chain state confirms the public accounts are empty.

Private Buy re-shield is mandatory. The operation has no successful terminal state before every required re-shield completes. The optional post-end vesting adapter never replaces this step.

The full private flow is not one chain transaction. The SDK records each intended submission in a durable local journal before sending it. Recovery reconciles that journal with chain state, including account balances, transaction inclusion, sale counters, and authorization consumption. It does not retry Buy or re-shield from the local stage alone. The exact-balance guard, atomic execution of each submitted leg, and resumable recovery meet the private funding and recovery requirements without requiring the entire multi-program flow to fit in one transaction.

The SDK treats any extra inbound collateral-token or native transfer as a privacy failure. If either pre-buy balance differs from the exact expected value, it does not submit Buy and enters recovery. This is client-enforced. A custom client can bypass the check, reuse the key, or leave assets public.

Testnet 0.2 does not charge user gas. The SDK still includes the native leg and checks it against a deterministic nonzero-fee fixture. When user-paid fees ship, the same path uses a live estimate. If fees arrive before an estimator, the SDK uses a documented upper bound derived from measured cycles and labels it as an estimate.

Collateral and native funding, and later recovery of project tokens, collateral, and native value, may require separate private transfers because they use different programs. The mini-app still presents one indivisible user action. A re-shield proof commits to the actual post-buy state, so the design expects at least the buy and re-shield to require sequential block inclusions rather than promising a one-block private flow. M0 tests the real initialization, ATA creation, authorization, deshield, exact-balance, buy, and re-shield order. It records which legs can share a privacy-preserving transaction and measures end-to-end wall-clock time from confirmation through verified re-shield, including proof generation, block inclusion, retries, transaction count, and private-buy throughput under idle and saturated sequencer loads. The deployed max_num_tx_in_block value is not externally confirmed; any capacity result remains conditional until Logos confirms that configuration.

For a private buy, the chain reveals the pool, time, collateral amount, token output, fresh account, setup transactions, public Buy, authorization record, and aggregate pool state. There is no protocol-created address link between separate fresh accounts. Timing, amount, network, setup, credential issuance, and outside data can still associate operations.

7. Optional ZK allowlist

The creator fixes one Merkle root when the sale is created. The Merkle leaf and path remain private witness data in a privacy-preserving LBP authorization entrypoint.

The authorization entrypoint proves membership and emits a public action that creates a short-lived, one-use Authorization record bound to the allowlist root, sale ID, fresh buyer key, fresh nonce, and expiry. The program caps expiry at both a protocol maximum age and the sale end. The later public Buy checks that the signer matches the buyer key, that root and sale ID match Sale, that the nonce is the requested nonce, and that the record has not been consumed. Its runtime timestamp validity window ends at the earlier of the authorization expiry and sale end, so the current block timestamp enforces expiry exactly. A successful Buy consumes the record atomically.

Repeat purchases require a fresh proof, nonce, and authorization record. There is no stable per-credential public nullifier. RFP-016 does not limit one credential holder to one purchase, and a stable sale-wide credential nullifier would either reject later purchases or link them.

The proof hides the credential and Merkle path. It does not hide the public authorization record, public buy, or the fact that the fresh account proved eligibility. Credential issuance and outside information can reduce the practical anonymity set.

F7 is a hard requirement whether or not a given sale enables it. M0 measures the private authorization's proof time, transaction size, guest size, cycles, public-action shape, expiry behavior, and one-use consumption. If it cannot fit the pinned LEZ limits, we stop before the core build and return to Logos with the measurements and an alternative private design. A failed M0 measurement is a design issue to settle with Logos, not a waiver of F7.

8. Pause, sale end, withdrawal, and fee

Pause prevents Buy from accepting a transaction. It does not change t_start, t_end, or any weight, as required by RFP-016 L168-176. Resume reopens the sale at the weight implied by the current readable clock. Pause does not freeze the schedule.

The freeze adapter applies only to Buy. Poke, Resume, end recognition, and post-end withdrawal remain available. Migration and authorization tests cover both local adapters and the awarded RFP-001 and RFP-002 interfaces. M4 requires those interfaces when available, or an explicit written Logos waiver if either is still unavailable.

Direct Buy uses the runtime timestamp validity window [t_start, t_end). An allowlisted Buy narrows the upper bound to the authorization expiry when it comes first. Close and Withdraw use an end-or-later window [t_end, unbounded). The runtime checks these windows against the current block timestamp (lee/state_machine/src/validated_state_diff/mod.rs:202-208; lee/state_machine/core/src/program/mod.rs:430-447,497-525). Close is permissionless and idempotent, while time alone determines that the sale has ended.

After t_end, the creator withdraws atomically. The fee is the rounded-up amount on cumulative collateral from buys under the current global fee rate. The creator receives the actual collateral balance minus that fee, so the seed and unsolicited excess return without a protocol fee. The current global treasury receives the fee. Unsold project tokens return directly or, under the optional handoff, enter the awarded vesting interface.

The RFP-017 adapter is a non-gating, no-cost stretch deliverable behind production flags. It applies only during post-end Withdraw, for creator proceeds or unsold tokens. It is enabled only when the awarded interface supports the configured flow and its eight-execution trace fits the pinned release. Core M4 acceptance and payment do not depend on that interface or adapter.

9. SDK, CLI, Basecamp, and analytics

The Rust client core exposes the full lifecycle:

  • Participants discover active and completed sales, request a quote against current readable CLOCK_01, buy through either account path, call query_position, inspect local receipts, and recover an interrupted private operation.
  • Creators create a sale, configure optional controls, monitor it, pause and resume buys, close the sale, and withdraw.

For public purchases, query_position reconstructs the caller's purchases on demand from transaction ranges and local receipts; it reports the current project-token ATA balance separately because that balance may include transfers unrelated to the sale. For private purchases, it derives the position only from the user's durable local journal and shielded wallet data. The protocol does not create a public participant index or infer ownership across fresh accounts.

The participant view shows live price, current weights, time remaining, successful-buy count, total raised, pool composition, and local purchase history. It supports active and completed sales and renders a historical price series and chart. Before each buy, it runs the same interval and rounding rules as the program. The confirmation shows the readable clock value and age, modelled drift bound, expected output, price impact, collateral spent, min_tokens_out, and the privacy disclosure.

The creator view covers every sale parameter and lifecycle action. Before creation, it enforces the seven-day minimum and shows the block-interval assumption and worst endpoint drift bound. It also shows the current global fee rate and treasury, warns that admin updates apply to open sales, and shows pause state, current weight, and post-end token policy.

The mini-app repository contains two sub-flakes: a Synarton LBP core module and a QML UI plugin whose metadata declares the core dependency. Each exposes packages.<system>.lgx for scaffold-managed development and packages.<system>.lgx-portable for hand-loaded AppImage artifacts. The Rust client core pins the same LEZ monorepo revision used by the standalone sequencer, and the UI sub-flake pins the core module. Reviewers install #lgx builds through scaffold, load #lgx-portable artifacts in core-then-UI order, and complete both role flows from a clean clone.

Analytics read aggregate sale state, reserve ATAs, and transaction ranges. Until event RPCs exist, an observer polls those sources. The analytics schema and UI contain no participant account IDs, transaction-to-account linkage fields, participant identity index, or cross-buy ownership inference. A private user's history stays in local SDK data.

One typed error set reaches the SDK, CLI, and mini-app. It covers insufficient shielded balance, unexpected ephemeral balance, invalid ATA, sale not started, sale ended, sale paused, allowlist rejection, expired or consumed authorization, block ceiling exceeded, input outside the proven arithmetic domain, slippage exceeded, invalid shielded destination, and resumable private-operation failures.

10. Scope

The base scope includes:

  • the LBP program and all hard controls,
  • public and private buy paths,
  • the ZK allowlist,
  • the SDK, CLI, Basecamp mini-app, analytics, and IDL,
  • deployment and verification on testnet 0.2,
  • event-gated testnet 0.3 and mainnet milestones,
  • an external security audit and remediation, and
  • privacy, deployment, benchmark, and operator documentation.

The RFP's fixed-price soft requirement is conditional. Section 4 states the M0 test that decides it, and it carries no payout of its own.

Out of scope Reason
Token creation and metadata The creator supplies an existing token pair.
A second launch mechanism This proposal implements the RFP-016 LBP.
Hosted analytics service The observer ships as client code.
Protocol-level identity or per-wallet caps Fresh accounts remove the stable identity those controls require, as RFP-016 notes at L429-440.
New vesting logic The stretch adapter targets only the post-sale boundary in RFP-016 L610-611.

11. Design validation and risks

Milestone 0 is a two-week design-validation phase. It produces ten evidence packages before the full build:

# Question Work product Pass condition
1 Can the environment be rebuilt exactly? Pin file for LEZ, lez-programs, SPEL, Basecamp tooling, deployed program IDs, and artifact hashes A reviewer rebuilds the environment from a clean clone and matches the artifacts.
2 Does integer exponentiation fit LEZ? Kernel, sound x and y intervals, adverse-corner proof, x_min or max-input ratio, coefficients, error report, vectors, guest size, bytes, and cycle benchmark Every accepted input fits, Buy rejects outside the domain before transfer, and output rounds against the buyer.
3 Do all operations fit the execution cap? Generated call graphs and decoded traces for every row in section 5 Every required path uses at most ten total executions.
4 Do custody and fresh-account setup work in the required order? Traces for owner initialization or native funding, both ATA creates, authorization, deshield, exact-balance checks, Buy, and separate re-shield legs Every token account is canonical and the real fresh-account sequence passes.
5 Can private funding and recovery handle collateral and native value at usable latency? Zero-fee trace, deterministic nonzero-fee fixture, sequential-block trace, interruption matrix, chain-state reconciliation, separate-transfer fallback, deployed-cap confirmation request, and end-to-end timing and capacity report under idle and saturated loads Exact pre-buy balances, atomic submitted legs, and recovery tests satisfy the funding and recovery requirements. Every interruption remains resumable. Measured latency is published, and capacity is labelled conditional until Logos confirms max_num_tx_in_block.
6 Does private allowlist authorization fit? Privacy-preserving authorization spike with proof time, size, cycles, public action, expiry, replay, consumption, and later Buy trace The witness stays private, the record is correctly bound and one-use, and both transactions fit.
7 Do generated clients reach Basecamp through the Rust core? IDL, generated instruction client, FFI, hand-written Rust core, separate core and QML sub-flakes, client-and-sequencer LEZ pin, and both .lgx variants A reviewer installs the #lgx pair through scaffold and hand-loads the #lgx-portable pair in dependency order from a clean clone.
8 Do the fee and seed accounting rules hold? Buy-contribution fee vectors, configuration snapshots, withdrawal vectors, positive-reserve rejection, seed return, and unsolicited-transfer cases Every vector follows the stated collateral-raised fee rule and preserves the creator seed.
9 Does the measured clock bound remain acceptable? Reproducible live interval measurement, clamped-boundary vectors, endpoint price table, finite-trade quote table, seven-day minimum-duration check, same-block ceiling trace, and runtime-window boundary tests The measured interval supports the published minimum duration and quote disclosures, no timestamp extrapolates outside the configured weights, and no stale-time buyer discount exists.
10 Are authority and audit plans executable? Adapter interfaces, awarded-library migration plan, authorization tests, audit brief, and procurement record The M4 integration-or-waiver gate is testable and audit fieldwork is booked for the M3 code freeze.

If the arithmetic kernel, required call graph, private authorization, clock acceptance, or fresh-account flow fails its pass condition, M1 does not start. We publish the result and agree a revised design with Logos.

Risk Handling
Audit lead time Start engagement and procurement during M0. Fieldwork begins at the feature-complete M3 code freeze. M4 is remediation and regression.
Testnet 0.3 and mainnet timing Start those milestones only when Logos releases each environment.
Authority libraries Integrate the awarded interfaces by M4 when available, or obtain an explicit written Logos waiver.
Fixed-price mode Drop it if M0 shows separate audit work or schedule impact.
Optional vesting handoff Keep it disabled and outside core acceptance until the awarded interface and measured trace are available.

12. Testing

Every change runs the automated suite against a standalone LEZ sequencer in dev mode. Default-branch CI also runs one named lifecycle with RISC0_DEV_MODE=0. Release CI runs the full manifest with real proofs, including clean-clone SDK, CLI, and Basecamp walkthroughs.

The automated suite includes high-precision arithmetic differential tests, zero-output rejection even when min_tokens_out is zero, traded-state and conservation vectors, field-by-field configuration rejection, seven-day duration rejection, start and end clock-clamp vectors, competing buys in one block, ceiling boundaries, runtime validity windows, failure injection at each chained execution with byte-for-byte state comparison, public and private buys, private-flow timing and saturated-load capacity, authorization replay and expiry, interrupted-operation recovery from chain state and journal, external token and native transfers before and after deshield, pause across clock updates, exact fee and withdrawal checks, authority migration, and analytics schema and UI assertions.

LEZ exposes RISC Zero cycle and transaction measurements rather than Solana compute units. The P3 cost report labels the native metrics and their mapping to the RFP's CU terminology.

Every F, U, R, and P requirement has an executable test. The five named S3 cases are happy_path_buy, slippage_revert, allowlist_accept_and_reject, close_before_end_time, and poke_at_multiple_schedule_points. Other IDs pass their stated reviewer checks.

13. Requirement traceability

The table maps 36 numbered hard requirements plus the unnumbered Supportability milestone mandate (S0) and the open-source requirement (O1) to implementation, milestone, and reviewer check.

ID Requirement Implementation Milestone Reviewer check
F1 Two-asset LBP with linearly shifting creator-set weights Sale stores the schedule. Buy applies the weighted formula with conservative interval arithmetic and tracked reserve updates. M1 Run no-trade and traded-state formula vectors at start, middle, and end; check conservation, reserve updates, and every rounding boundary.
F2 Creator configures pair, weights, times, deposit, block ceiling, and allowlist CreateSale validates every field, enforces the seven-day minimum duration on the pinned release, funds both reserves from the creator's token deposit and collateral seed, and stores optional controls. M1, M2 Run a field-by-field invalid matrix for token pair, reserve amounts, weight sum and bounds, time ordering, minimum duration, ceiling bounds, fee bounds, and malformed allowlist configuration; test every valid option on and off.
F3 Public buy and private deshield -> buy -> re-shield One public Buy instruction has direct and resumable private client flows. Private completion requires re-shield. M1, M2 Complete both paths and interrupt the private path at every submission boundary.
F4 Permissionless poke and correct time-derived weights Poke writes only a snapshot. Buy clamps preceding-block CLOCK_01 to the configured endpoints before interpolation; runtime windows enforce exact sale boundaries. M1 Buy without a poke, just after t_start with a pre-start readable clock, and after a stale poke; confirm clamping and compare with the published drift bound.
F5 Post-end fee, creator proceeds, and unsold tokens in one transaction Withdraw charges cumulative buy collateral under the current global fee settings and performs every disposition atomically after t_end. M1 Check seed, unsolicited excess, buy contributions, ceil rounding, an admin update before close, the selected treasury, and all destination balances.
F6 Pause and resume without stopping weight progression Pause gates only Buy. M1 Pause, advance time, resume, and check the later clock-derived weight.
F7 Optional allowlist with documented privacy properties A private witness creates a bound, expiring, one-use authorization record that public Buy consumes. M0, M2 Accept a member; reject a non-member, wrong root, wrong sale, wrong signer, wrong nonce, expired record, overlong expiry, and replay. Confirm no stable credential nullifier.
F8 Minimum-output slippage protection Buy requires tokens_out > 0 and then checks min_tokens_out before any transfer. M1 Submit passing and failing boundary cases across clock updates, including a dust input with min_tokens_out = 0.
F9 ATAs for every token interaction Program and clients derive, pre-create, and validate every ATA in the safe owner-first order. M1 Compare canonical derivations, reject substitutions, and inspect ATA and token executions.
U1 Full-lifecycle SDK for both roles and both account paths The shared core exposes discovery, clock-bound quotes, buy, query_position, recovery, creation, pause, resume, close, and withdrawal. M1, M2, M3, M5 Run public and private lifecycles with the 0.2 fee fixture, all M3 clients, and live fees when available.
U2 Basecamp mini-app with both views, local build, and assets A pinned flake and downloadable .lgx packages ship from the public repository. M3 Install from git, build from a clean clone, and complete both role flows.
U3 CLI for participant and creator operations SPEL-generated instruction clients and typed queries feed the shared core. M3 Run the documented CLI lifecycle from a clean clone.
U4 Pre-buy price, output, impact, and spend The client runs the same interval and rounding rules and shows clock age, the modelled drift bound, and min_tokens_out. M3 Compare display and execution at both endpoints, the midpoint, three trade sizes, and across a clock update.
U5 Privacy disclosure before a private buy One disclosure lists public data, protected data, setup transactions, correlation limits, and client-only guarantees. M2, M3 Compare rendered text with public traces and the final privacy document.
U6 Prevent external funding of the ephemeral account The SDK requires exact collateral-token and native balances immediately before Buy; any mismatch aborts into recovery. M2, M3 Inject external token and native transfers before and after deshield. Confirm that no Buy is submitted and recovery starts.
U7 Check collateral and gas before deshield The SDK checks shielded balances and the fee adapter before submission, then verifies exact public balances. M2, M3, M5 Test zero-fee behavior, the nonzero fixture, all clients, and the first live-fee release.
U8 Sale analytics without participant identities Aggregate readers support active and completed sales, total raised, successful-buy count, pool composition, and historical price series/chart. M3 Assert schema and UI contain every metric and no participant account ID, identity index, or linkage field.
U9 SPEL IDL Generate and commit the IDL from the annotated program. M3 Regenerate the IDL and require a clean diff.
U10 Actionable errors for rejected buys One typed error set serves all clients. M1, M3 Trigger every rejection and compare its public error code and rendered guidance.
R1 Consistent state under concurrent buys LEZ serial application and atomic updates move reserves, fee counters, authorizations, and ceiling counters together. M1 Submit competing buys and check conservation, authorization consumption, and the block ceiling.
R2 Failed buy consumes no collateral and changes no pool state The full public call graph validates before state application. M1 Inject each failure and compare all accounts byte for byte.
R3 Idempotent pokes Poke overwrites only the timestamp-derived snapshot. M1 Repeat Poke at one timestamp and compare state bytes.
P1 Buy completes within one LEZ transaction Buy and token continuations form one public transaction; allowlist authorization is a prior private transaction. M1 Publish one transaction ID and five-execution trace for direct and authorized buys.
P2 Poke completes within one LEZ transaction Poke is one program execution. M1 Record one transaction ID and resulting snapshot.
P3 Cost report for every operation and LEZ version Benchmarks publish CU mapping, cycles, guest size, bytes, and call depth. M0, M4, M5, M6 Rerun the command for create sale, authorize, buy, poke weights, pause, resume, close sale, and withdraw on each tagged environment.
S0 Separate testnet 0.2, testnet 0.3, and mainnet milestones M1, M5, and M6 are separate acceptance units. Proposal Check the milestone schedule.
S1 Deploy and test on testnet 0.2 Deploy the core and exercise public and private flows. M1, M2 Verify addresses and rerun public and private smoke scripts.
S2 Standalone-sequencer tests in green default-branch CI Every change runs the automated dev-mode suite. Default branch and release lanes add real proofs. M1 onward Inspect CI lanes and proof output.
S3 Test every F/U/R/P requirement and the named RFP cases The automated manifest maps each required executable test to this table. M1 through M4 Match every F/U/R/P ID and the five named cases to passing executable tests; confirm other IDs pass their stated reviewer checks.
S4 README with deployment, addresses, CLI, and mini-app steps One operator runbook includes expected output. M3, M6 Follow it from a clean clone without private instructions.
S5 Privacy and anonymisation properties document Publish visibility, guarantees, trust boundaries, bypass behavior, authorization semantics, and correlation limits. M2, M4 Compare each claim with client code, schema, and public traces.
S6 Update and verify on testnet 0.3 Port after Logos tags 0.3 and rerun every gate. M5 Verify deployment, full requirement manifest, traces, and updated costs.
S7 Deploy to mainnet Deploy the audited release after mainnet becomes available. M6 Verify addresses, artifacts, smoke transactions, and mainnet costs.
Pr1 SDK and mini-app support both paths and make re-shield non-skippable The private operation has no completed state before every re-shield leg succeeds. M2, M3 Interrupt after Buy, restart, reconcile chain state, and complete recovery.
Pr2 Private pre-buy summary states public and private data SDK and mini-app render the same qualified disclosure. M2, M3 Compare rendered text with setup, authorization, buy, and re-shield traces.
Pr3 SDK validates a shielded destination Typed validation runs before the private operation starts. M2 Pass a public destination and confirm that no transaction is sent.
Pr4 Fresh ephemeral account for every private buy Generate one random key per operation and retire it after verified empty state. M2 Run repeated buys and restart tests; compare all public keys and histories.
O1 MIT and Apache 2.0 dual license Publish all deliverables under both licenses. M1 Inspect repository license files and package metadata.

Milestones, Payout and Timeline

Three engineering streams run in parallel: the LBP program and math, privacy and client infrastructure, and Basecamp and product delivery. M0 through M4 run 14 calendar weeks. M5 and M6 add one calendar week each when their platform gates open. Total planned engineering across all seven milestones is 48 engineer-weeks for three engineers. Project management and advisory work are additional to those engineer-weeks and included in the requested budget. The external audit is billed separately at cost.

Milestone Deliverable Duration Payout
M0 Validate the design and freeze interfaces 2 calendar weeks $15,000
M1 Core LBP and public path on testnet 0.2 4 calendar weeks $30,000
M2 Private path and ZK allowlist 3 calendar weeks $22,500
M3 SDK, CLI, Basecamp, and analytics 3 calendar weeks $22,500
M4 Hardening, audit remediation, and release freeze 2 calendar weeks $15,000
Active total M0-M4 14 calendar weeks $105,000
M5 (gated) Testnet 0.3 port and verification 1 calendar week after release $7,500
M6 (gated) Mainnet deployment 1 calendar week after availability $7,500
External audit Independent security review, passed through at cost Scheduled with the auditor Billed separately at cost

M0: Validate the design and freeze interfaces

Duration: 2 calendar weeks

Payout: $15,000

Deliverables: the ten evidence packages in section 11, account and instruction schemas, complete design-budget traces, the first cost table, and audit engagement and procurement.

Done gate: a reviewer rebuilds the pinned environment and reruns the arithmetic comparison, domain and zero-output rejection, every section 5 trace, owner-first ATA flow, collateral and native fixtures, private authorization and public consumption, private-flow timing and capacity test, both Basecamp package variants, fee and seed vectors, clock drift table, and authority migration plan. Logos accepts the clock fairness bound before Sale state freezes.

M1: Core LBP and public path on testnet 0.2

Duration: 4 calendar weeks

Payout: $30,000

Deliverables: sale creation, lifecycle, integer LBP math, public buy, slippage, optional per-block ceiling, permissionless poke, pause and resume, withdrawal, global fee routing, ATA custody, typed public errors, SDK and CLI public flows, and the public testnet 0.2 deployment.

Done gate: the standalone-sequencer automated suite passes in dev mode. The default branch completes the named public lifecycle with RISC0_DEV_MODE=0. M1 closes F1, F4-F6, F8, F9, R1-R3, P1, P2, O1, and the public parts of F2, F3, S1, U1, and U10.

M2: Private path and ZK allowlist

Duration: 3 calendar weeks

Payout: $22,500

Deliverables: owner-first fresh-account setup, pre-created ATAs, resumable deshield -> buy -> re-shield, durable journal and chain-state recovery, exact token and native balance enforcement, shielded-target validation, gas fixture, private allowlist authorization, one-use public consumption, and the first privacy properties document.

Done gate: reviewers complete public, private, allowlisted, and rejected buys on testnet 0.2. Restart tests recover after each interruption. External token and native transfers before and after deshield prevent Buy. The nonzero-fee fixture proves the insufficient-gas branch. M2 closes F2, F3, F7, S1, and the private parts of U1, U5-U7, and Pr1-Pr4.

M3: SDK, CLI, Basecamp, and analytics

Duration: 3 calendar weeks

Payout: $22,500

Deliverables: the generated SPEL IDL, typed SDK, full CLI, participant and creator Basecamp views, query_position, exact pre-buy summary, active and completed sale analytics, historical price chart, successful-buy count, total raised, pool composition, local private receipts, reproducible core-module and QML UI-plugin builds in lgx and lgx-portable variants, downloadable packages, and operator README.

Done gate: a reviewer starts from a clean clone, regenerates the IDL with no diff, installs both #lgx packages through scaffold, hand-loads both #lgx-portable packages in dependency order, and completes both role walkthroughs. Analytics schema and UI assertions show no participant identifiers or linkage fields. M3 closes U1-U4 and U7-U10, and the M3 client and UI portions of U5 and U6. Live-fee activation remains for M5 if testnet 0.2 is fee-free.

M4: Hardening, audit remediation, and release freeze

Duration: 2 calendar weeks. Audit engagement and procurement start in M0. Fieldwork begins at the feature-complete M3 code freeze; M4 is remediation and regression.

Payout: $15,000

External audit pass-through: billed separately at cost

Deliverables: the final threat model, final privacy and anonymisation properties document, full benchmark report, complete requirement test manifest, audit report, fixes, regression tests, and integration with the awarded RFP-001 and RFP-002 interfaces when available. If either interface is still unavailable, the deliverable is an explicit written Logos waiver plus the tested adapter and migration plan. The post-end vesting adapter may ship as a no-cost stretch item behind disabled production flags, but it is not an M4 deliverable or gate.

Done gate: all requirements due through M4 pass their reviewer checks. Every audit finding is fixed or has written Logos acceptance. Authority-interface integration passes migration and authorization tests, or Logos has issued the explicit waiver. S6 and S7 are not part of this gate.

M5: Testnet 0.3 port and verification

Duration: 1 calendar week after Logos tags testnet 0.3

Payout: $7,500

Deliverables: the 0.3 port, deployment, full applicable requirement-manifest rerun, updated call traces, updated costs, and live gas-preflight activation if the network charges user fees.

Done gate: published addresses, a passing full applicable manifest against deployed 0.3 artifacts, green dev-mode CI, a green production-proof lifecycle, and a rerunnable real-proof release manifest.

M6: Mainnet deployment

Duration: 1 calendar week after LEZ mainnet becomes available

Payout: $7,500

Deliverables: the audited mainnet build, reproducible artifacts, deployment, published addresses, smoke tests, final operator documentation, and mainnet cost report.

Done gate: the audit gate is closed. Reviewers verify artifacts, addresses, and costs, then run the documented create, pause, resume, buy, close, and withdrawal smoke path.

Total Requested Budget (USD)

$120,000

Relevant Experience

Production launchpad delivery. Vacuumlabs has delivered a production bonding-curve launchpad across EVM and Solana. The work covered on-chain sale programs, PDA and ATA custody, transaction construction, launch analytics, and graduation into a constant-product DEX pool. The client is under NDA, so this is capability-level. We can walk Logos through the architecture and delivery record directly.

A second Solana launchpad. Vacuumlabs designed and built Syndicate, a decentralized fair launchpad, including its frontend and backend.

Open-source ZK tooling. midnight-cli-tools contains ZK contracts and client tooling for anonymous voting, Merkle membership, nullifiers, wallet operations, state observation, and a standalone local network. The work also produced midnightntwrk/compact#20, an upstream report for a reproduced runtime issue.

AMM invariant work. Vacuumlabs worked on the production WingRiders Cardano DEX and published the WingRiders V2 security audit. The work covered on-chain liquidity, transaction construction, fee handling, and invariant-level review, including an independent check of on-chain pricing against live transaction data.

Analytics from chain data. CARP, built with dcSpark, reconstructs application-level state from raw chain data. Synarton LBP's analytics use the same approach while the event interface is unavailable.

Rust, ZK, and client systems. Vacuumlabs has delivered Merkle-verified withdrawals, off-chain proof generation, validator commitments, and event monitoring on Midnight. Production SDK and blockchain infrastructure work for API3, FunKit, and Autonom is the client, integration, and Rust systems work this project needs.

Post-Delivery Plan

Vacuumlabs maintains the project as a team, so support is not tied to any single individual. Support runs through the public repository and the primary contact above. Delivery includes the deployment runbook, program addresses, pin file, generated IDL, audit report, privacy properties document, and versioned benchmark results.

We provide a six-month support window from acceptance of the final available deployment milestone. The window covers:

  • reproducible defects within the delivered scope,
  • security reports through a documented disclosure process,
  • compatibility updates for the pinned LEZ and SPEL interfaces. Where a release affects the program or the client surface we port it and publish a compatibility delta within 10 business days; independently of releases we publish a compatibility status at least quarterly, for which "no action required" is a valid status.
  • maintenance of integrated authority and event adapters, and
  • integration support for early teams that use the program.

Support commercial treatment: included in the total requested budget.

New launch mechanisms, hosted services, and product extensions are separate work.

We can operate Synarton, not only deliver it. Everything above covers the software itself - maintenance, defects, compatibility, and disclosure. Operating a launchpad is a separate responsibility: holding the relevant admin authority, monitoring live sales, and responding when something goes wrong.

If Logos would like us to take on that operational role, we are happy to scope and price it as a separate engagement. The people who would carry this responsibility will be the same team listed above - Uroš as CPO, 0xcr1st0f on business development and the rest of the development team. This same team covers Synarton's bonding-curve and LBP mechanisms if both are awarded to us.

Permissions and Consent

  • I/We confirm Logos may contact me using the primary contact information provided above for follow-ups and next steps.
  • I/We consent to Logos using information from this proposal publicly such as blogs case studies social posts or analytical reporting. Redactions can be requested at any time.

Program Requirements

  • I/We have read and agree to the Logos RFP Terms and Conditions and I understand that no Grant is awarded and no right to payment arises unless a Grant Agreement is executed.
  • I/We understand that RFP specifications are proposals rather than instructions, that Logos makes no representations as to their legal or regulatory treatment, and that we are responsible for assessing what we build, deploy or operate and for complying with the laws that apply to us.
  • I/We understand this project must be open-sourced under the MIT and Apache 2.0 Licenses unless explicitly approved otherwise.
  • I/We are prepared to deliver milestone-based outcomes.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

RFP-016Proposals for RFP-016proposalProposal submitted for an RFP

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions