Repository navigation
[PROPOSAL] RFP-005 — Accord: private-by-default M-of-N multisig with an encrypted coordination room #222
Description
RFP ID
RFP-005 — Multisig and Coordination
Your Project Name
Accord
Team or Organization Name
Antumbra
Primary Contact
Telegram https://t.me/edenbdn or edenbaud1@gmail.com. Either reaches both of us within a day.
Team Members
Eden Baudin, engineer, privacy & ZK
- GitHub: https://github.com/edenbd1
- X: https://x.com/edenbdn
- Telegram: https://t.me/edenbdn
- LinkedIn: https://www.linkedin.com/in/edenbdn/
- Role: the multisig program and its proving path, approval verification and its benchmark, the private and public postures, selective disclosure, the coordination-room protocol, the CLI, CI and the evidence trail.
- Availability: full time, for the whole grant.
- λPrize LP-0005, Private Balance Attestation: won. Solution PR Solution: LP-0005 — Private Balance Attestation lambda-prize#64 merged on 2026-08-02 by the Logos team; the solution file is in the official repository at https://github.com/logos-co/lambda-prize/blob/master/solutions/LP-0005.md. Code: https://github.com/edenbd1/lp-0005-private-token-balance-attestation
- Built a private M-of-N multisig on LEZ (v0.2): RISC0 membership proofs verified on the privacy-preserving path, a treasury that pays out at threshold, spending tiers and configuration rotation, 131 tests, real-proving measurements. Described under Relevant Experience, including why this proposal does not reuse its approval model.
- Built Logos Forum, a serverless forum for Basecamp on Logos Delivery and Storage, with its own module catalog, run as a permanent node on the public network.
- 15+ hackathon wins. Ex-DevRel @ iExec in privacy across RWA and DeFi. Incubated at the Berkeley Blockchain Xcelerator.
Nada Ahmadi, engineer, DeFi
- GitHub: https://github.com/nadaamd
- LinkedIn: https://www.linkedin.com/in/nada-ahmadi/
- Role: the Logos multisig module and its API, the SDK and the action decoder behind U.6, the Basecamp mini-app and its designs, the room client, wallet integration.
- Availability: full time, for the whole grant.
- ETHGlobal Lisbon 2026, Umbra: 3rd place, Uniswap Foundation "Best Uniswap API Integration" (showcase), an autonomous circuit breaker for DeFi positions, backtested over 48,000 real swaps.
- Full-stack developer at XRPL Commons (LinkedIn above). Member of DeVinci Blockchain, ESILV.
Continuity. Both of us can build, deploy and drive the program. Every deployment we make ships with a runbook from a clean checkout and a script that re-checks it against the chain, as in antumbra-lez/docs/deploy-v03.md and scripts/verify-onchain.sh. The same discipline applies here: what the program does and why lives in the repository and its decision log, not in one person's head.
Project Summary
Verifiable from a clean clone, from the prototype repository https://github.com/edenbd1/lez-accord (program
accord_multisig, built on LEZ v0.3.0 and run on the v0.3.1 public testnet, CLIaccord):git clone https://github.com/edenbd1/lez-accord && cd lez-accord cargo test --manifest-path programs/accord/Cargo.toml -p accord-core # 28 host tests: every rule cargo test --release --manifest-path executor-tests/Cargo.toml # 20 tests: the committed binary through lee::V03State cargo run --release --manifest-path executor-tests/Cargo.toml --bin measure # approval cost vs M python3 scripts/check-idl.py # the IDL decodes the program's own borsh ./scripts/verify-onchain.sh --manifest evidence/testnet/public.tsv --rpc https://testnet.lez.logos.co # the public testnet run, re-checked # with a local LEZ v0.3.1 sequencer and the v0.3.0 wallet running (README.md, docs/LOCAL.md): DEPLOY=1 PAYER=<a funded account> ./scripts/e2e.sh # 28 steps, writes the manifest ./scripts/verify-onchain.sh --manifest evidence/v03/local-e2e.tsv --rpc http://127.0.0.1:3040
- The committed binary runs through the v0.3 state machine the sequencer applies:
executor-tests/tests/program.rsdrivesartifacts/programs/v0.3/accord_multisig.binwith the real native and token programs, real timestamp windows and the 10M gas cap, through every hard requirement the RFP names a test for: below threshold refused, a configuration change invalidating pending approvals (R.2), a vault that cannot be drained before initialisation, plusevery_refusal_code_fires_on_chain, which fires all 17 refusal codes.- The whole lifecycle on a local v0.3 sequencer, through the CLI:
scripts/e2e.shran 28 steps, 27 of them transactions (create, activation, queue, time-locked execute, spending limits, a configuration change, stale and removed-member approvals refused, a veto, the registry), andscripts/verify-onchain.shre-checks the manifestevidence/v03/local-e2e.tsvagainst the chain:34 checks pass, 0 fail(our output). The commands to stand up the sequencer are inREADME.mdanddocs/LOCAL.md.- A private vault on the same sequencer:
scripts/e2e-private.shfunds a private PDA of the program privately, shows that a holder of the group keys alone is refused, then spends and executes an M-of-N action out of it in privacy-preserving transactions (evidence/v03/local-private.tsv: 6 applied, 1 refused as expected, 0 failures).- Approval cost, measured (
docs/BENCHMARKS.md): about 275,000 cycles per approval; M = 5 in 1.70M cycles, 17% of the 10M cap; M = 32 in 9.18M. Real proving of the approval check: 71.5 s for M = 1, 381 s for M = 16, receipt about 225 kB.- The whole private transaction, measured on the public testnet (
docs/PRIVATE-TX-MEASURED.md): M = 1, 3, 5 and 10 signatures checked inside one privacy-preservingspend --private-vault: 160.6 to 188.6 s, 6.5 to 7.9 GB peak RAM, about 249 kB, hashes in §4.- Approvals collected through a Logos chat-module group:
scripts/e2e-chat.sh, three members onchat_module0.3.0, a 2-of-3 reaches quorum with packages that only travelled through the MLS group, a forged approval is dropped, and the action executes on chain (19 checks, 0 failures).- A read-only mini-app in Basecamp 0.3.0 (
app/): the multisig and its approval packages, each decoded from the bytes its approvals sign; it holds no keys.- Design and decision log:
DESIGN.md,docs/DECISIONS.md.- On the public LEZ testnet (v0.3.1): the program is deployed at
CehtqLan7gii…, ImageID24a69044…, the committed binary, which CI rebuilds byte for byte. The whole public lifecycle ran there (evidence/testnet/public.tsv: 12 applied, 16 refused as expected, 0 failures; the verifier:34 checks pass, 0 fail), and so did the private vault, funded, spent within its limit and through an M-of-N action in privacy-preserving transactions, with the group keys alone refused (evidence/testnet/private.tsv:9 checks pass, 0 fail). Every transaction is linked inevidence/testnet/links.md. On 14 October the explorer was indexing about 3,000 blocks behind the sequencer, so the verifier, which asks the sequencer directly, is the check to run (evidence/testnet/README.md).
Requested: $70,000 over about 20 weeks (the RFP estimates 6 months; a working prototype already exists), in eight milestones paid on acceptance. The external audit is a separate line item (Supportability #13): a $50,000 allowance (not a vendor quote), with Cantina (Spearbit as the alternative), contracted and paid by Logos directly, outside our $70,000 request. Our remediation work is milestone M7.
In two sentences. A multisig whose configuration, vault and activity live in LEZ private accounts, whose approvals are signatures by named members collected inside an end-to-end-encrypted Logos chat room, and whose program checks those M signatures inside its own private execution, so the chain learns that a valid quorum acted and nothing about who or on what (a private transaction's size still tracks how many, §6).
The RFP's open question, answered. Approval verification fits a public transaction: in the prototype, M = 5 uses 17% of a transaction's cycle budget, and M = 32 still fits. A whole privacy-preserving spend checking M = 1 to 10 signatures proves in about three minutes at every M on the public testnet (§4).
Every production multisig today makes the same trade: to let the chain enforce a quorum, it publishes the quorum. Members, threshold, every approval and every pending action are public state, and the two largest multisig losses of the last two years were attacks on exactly that visible signing layer. LEZ removes the trade. The same program can run over private accounts, where the chain stores a commitment to the post-state and a validity proof; the quorum is still enforced by the program, but the program's inputs are not published.
This proposal builds that program, and the room where its members coordinate. Approvals are attributed: each is a signature by one member's approval key over the exact action, and at execution the program verifies M distinct, current members' signatures on exactly that action (R.1). That is a deliberate departure from anonymous threshold proofs, which prove that some M members approved without saying which; the RFP asks for a verifiable record of who authorised an action, and so does any organisation that answers to an auditor. Attribution is to the members and to whoever they disclose to, not to the chain.
What already exists, and what does not. We have shipped LEZ programs on both runtime generations: a private multisig on v0.2.4 with real-proving benchmarks, and a vesting program ported to v0.3 within a day of the v0.3.0 release, with its full lifecycle driven on the public testnet the day after, claims into private accounts included, and a verifier anyone can run. We run a Basecamp module and its own catalog on Logos Delivery. This program is a fresh design, as the RFP asks, and a working prototype of it already exists: the box above is what can be checked today, and the milestone table states, piece by piece, what is built and what is priced as remaining work. What carries over is the toolchain, the proving and benchmarking harness, the deploy-and-verify pattern, the Basecamp packaging, and the mistakes we have already made once.
Technical Approach
1. Members, keys and roles (F.6, Privacy-1)
A member is an entry in the configuration, set at creation and changed only through the M-of-N flow (F.5):
| Field | What it is |
|---|---|
| Approval key | a BIP-340 (secp256k1, x-only) public key used only for this multisig |
| Roles | three independent bits: propose, approve, execute |
| Weight | 1 by default; a threshold is a minimum cumulative weight (soft F.1) |
The approval key is the same key type as a LEZ account key, so the wallet's tooling makes and stores it, but it never signs a LEZ transaction. Proposals, approvals and the execute authorisation are BIP-340 signatures over domain-separated digests ("propose", "approve", "execute"), verified by the program itself. A member's LEZ account therefore never appears in a multisig transaction; the only LEZ signer is a fee payer, who can be anyone (Privacy-1).
What each role guarantees, enforced by the program, and what it cannot prevent (documented as F.6 requires):
| Role | The program refuses | It cannot prevent |
|---|---|---|
| propose | a Queue whose proposer signature is not from a current member with propose |
a proposer sharing their key |
| approve | a signature from a key without approve, from a non-member, twice from one key, or over another digest or epoch |
approvers colluding |
| execute | an Execute without an execute member's signature over ("execute", digest) |
an executor choosing when to execute inside the window |
A proposing key need not be an approving key: the roles are independent bits.
2. Accounts and the two postures (F.10, Privacy, Privacy Architecture)
Every account is a PDA of the program's header account; multi-seed PDAs follow SPEL's rule (one seed direct, several hashed with SHA-256), as in our vesting program.
| Account | Seeds | Holds |
|---|---|---|
| configuration | [multisig_id] |
members, threshold, time lock, spending limits, epoch, initialised, counters |
| vault | [multisig_id, "vault"] |
nothing in this program's shard; its native and token shards hold the funds |
| queued action | [multisig_id, digest] |
the digest, the epoch it was approved under, quorum_at, expiry, the time-lock snapshot, the approvers, the status |
| registry entry | ["registry", program, idl_sha256] |
program, ImageID, IDL hash, name, registrant |
v0.3 has no program-owned accounts: the vault is a PDA nobody holds a key for, and the only way to debit it is a chained call to which this program attaches the vault's seed, which it does only after verifying the quorum.
Public posture (operator-selectable at creation): configuration, vault and queued records are public PDAs, and anyone can inspect configuration, holdings and activity at all times. Even then, no member's LEZ account appears in a transaction, and pending proposals stay in the room.
Private posture (the default the RFP asks for): the same records are private PDAs of this program, bound to a group nullifier key through AccountId::for_private_pda(program_id, seed, npk), the group-owned private-account feature of the shared-private-account journey (logos-docs#321). Members obtain the group keys from a Group Master Secret sealed to each member at creation. This is the design's central choice, so it is stated plainly: the group keys let a member read the multisig and build a transaction against it; they do not let a member spend. A debit still needs the program to attach the vault's seed, and the program does that only after verifying the quorum; approval verification then runs inside the privacy-preserving circuit, and the chain sees commitments, nullifiers and a proof. Prototype status: the private vault is built and exercised on a local v0.3 sequencer (scripts/e2e-private.sh, evidence/v03/local-private.tsv): the vault is funded privately, a transaction built with the group keys and no quorum is refused and moves nothing, a spend and an M-of-N execute pay out of it in privacy-preserving transactions, and the vault's balance is visible to the members and not publicly. Still to build: the configuration and the queued records as private accounts too (in the prototype they are public), and approval verification composed inside the privacy-preserving circuit for those.
The ten data items of the Privacy Architecture, under each posture:
| Item | Private posture | Public posture |
|---|---|---|
| Existence of the multisig | commitment only | public account |
| Member set, threshold, roles | inside the private configuration | public configuration |
| Per-signer approval attribution | private input to execution, and the room | the queued record, public |
| Pending-proposal metadata | room only | room only |
| Action payload | private input; the target program's own effects follow the target's accounts | public in Execute |
| Vault balance | private | public |
| Execution linkage | a privacy-preserving transaction with no member account | a public Execute with a fee payer |
| Coordination content | E2EE room | E2EE room |
| Co-signing social graph | not readable from chain state | readable from the configuration |
U.5's documentation is generated from this table for the configured posture, and each row names the test or transaction that shows it.
Selective disclosure and ongoing assurance (Privacy Architecture 2 and 3). A private multisig discloses by sharing the viewing key of its account family with an audience: one auditor, or every DAO member alike, since a viewing key is a value to hand over. The audience decrypts configuration, vault and activity and follows every later change, with no spending power. Ongoing assurance follows from the same key: the audience re-reads current state from chain whenever it wants, so a member who joins in month six gets current evidence, not a claim made at setup. What an audience unavoidably learns, and keeps learning until the members re-key the multisig into fresh private accounts through the M-of-N flow, is documented with it. Mixed postures (soft #3) are delivered as the combinations this account split supports without a second program, private configuration with a public vault and the reverse, each with its table.
3. The action, its digest, and the lifecycle (F.1, F.2, F.3, F.5, F.7, R.1, R.2)
An action is one of: a list of calls to any programs (F.3), a configuration change (a full replacement of members, threshold, time lock and limits, F.5), or a veto of a queued action. Action set (F.1). The configuration also holds an action set, fixed at creation and changed only through F.5: a list of allowed (target program, instruction discriminator) pairs, empty meaning any program. Queue refuses an action with a call outside it, under its own refusal code (built in M1). Its digest is
SHA-256("accord_multisig/v1/action" ‖ configuration account ‖ epoch ‖ expires_at ‖ borsh(action))
so everything a signer approves is in those bytes: the multisig, the configuration it was approved under, the expiry, the target programs, every account each call touches and which shard it selects, and the raw instruction data. The program recomputes the digest from the action it is about to run and never trusts one a caller supplies.
Approvals are collected off-chain, in the room (F.2), so a pending proposal and its approvals are never on chain in either posture, and reaching quorum costs one transaction rather than M + 1.
- Propose. A
proposemember builds the action, computes the digest under the current epoch and an expiry, signs("propose", digest), and posts the package (action bytes, epoch, expiry, signatures so far) to the room. - Approve or reject. Each
approvemember's client decodes the action from the package bytes (§5), checks the digest, shows it, and signs("approve", digest). A rejection is a signed message the room tallies; the program never needs it. A proposal is shown dead once rejections make the threshold unreachable. An approval, once shared, cannot be withdrawn: it stays usable until expiry or an epoch change, and the documentation says so. - Queue. Anyone holding the proposer's signature and approvals summing to the threshold weight submits
Queue. The program checks that the multisig is initialised, that the epoch named is the current one, that the proposer is a currentproposemember, and that every approval is a valid BIP-340 signature by a distinct currentapprovemember over this digest, with their weights summing to the stored threshold. It writes the queued record once, withquorum_at. - Execute. After the time lock, an
executemember signs("execute", digest)and anyone submitsExecutewith the action. The program checks the executor and thatquorum_at + time_lock ≤ at < expires_at, then makes the action's chained calls with the vault's seed attached. A digest executes once.
v0.3's two-phase execution shapes where each check lives. A v0.3 program plans a call without reading stored data, then applies each effect against one account's current bytes. So an instruction carries what the caller claims (the epoch, the digest, the time); the plan acts on it; apply checks every claim against the stored configuration and panics on a mismatch, which fails the whole transaction, chained calls included. It is the pattern our vesting program uses on the public testnet.
Time is bounded by the chain, not the caller. A zkVM guest has no clock, but a v0.3 plan can bound the block timestamp at which its transaction is valid, and the sequencer refuses it outside that window, public and private alike. Every instruction that names a time at is valid only in [at, at + 10 min). Ten minutes, not two, because a private transaction is proved on the member's machine before it is sent, and a two-minute window lost a real private-vault spend to proving time in the prototype (decision D4). Every time rule is enforced pessimistically against that window: a non-zero time lock counts from the end of the queue's window, so it is never shorter than configured, and an instruction whose window would reach the expiry is refused, so nothing lands after it. The queued record snapshots the time lock, so lowering it does not shorten a delay already running.
Signer authority does not leak into actions. A public account that signs a v0.3 transaction is authorised in every call the transaction makes, so an action whose call named the fee payer's account would spend the payer's funds with the payer's own signature. The program refuses any action whose calls name a root-authorised account or the program itself: the only authority an action carries is the vault's seed.
R.1, precisely. A signature counts only for the digest it signs, and the digest commits to the multisig, the epoch and the expiry, so it cannot be moved to another proposal, another multisig or another configuration. Distinctness is checked on member keys, so one member's two signatures count once, and the count is checked against the threshold stored in the configuration, never one the caller names.
The R.2 cutoff, precisely. A configuration change increments epoch, and Queue refuses a digest whose epoch is not current, so an approval signed under an older configuration never counts after the change. The cutoff is the Queue transaction, the moment an action enters its time-lock delay: a queued action keeps the quorum that was verified when it was a valid quorum and may still execute after its delay. A member removed while an action they approved sits in its delay does not unqueue it; the remaining members can veto it with a CancelQueued action at the new threshold, and a veto is exempt from the time lock so it can always land first. Configuration changes are serialised: a change executes only if its epoch is still current, so two changes queued under one configuration cannot both apply.
Spending limit (F.8). A limit names a set of spender keys, a sub-quorum min_signers, an asset, an amount per period and a period length. Spend pays from the vault to one destination with min_signers spender signatures over the limit, a per-limit use counter (so a spend signature cannot be replayed), the destination, the asset and the amount. The period restarts against the chain-bounded time. A spend can only move value out of the vault to one destination; it cannot call another program or touch the configuration.
Initialisation (Supportability #7). Create writes the configuration with initialised = false. The vault address exists from that moment, but every debit path refuses an uninitialised multisig. Activate requires approvals from current approve members summing to the threshold over ("activate", configuration, epoch), so the members confirm the configuration they are bound by before it can move funds.
Errors (U.7). Every refusal is a stable code with a name and a meaning (no multisig, not initialised, wrong epoch, already exists, bad role, below threshold, forbidden account, time-locked, expired, not queued, bad signature, bad configuration, limit exceeded, among 17), published with the IDL.
4. Approval verification: measured, and it fits (P.1, P.2)
Every approval is one BIP-340 verification inside the program. LEZ verifies BIP-340 host-side for its own witness sets and does not expose that to programs, so the program carries its own verifier. With the stock k256 crate it does not fit at all: activation with two signatures, and queue with a single approval, both exceed the 10M-cycle budget of one transaction. With RISC Zero's accelerated k256 fork (its bigint2 curve arithmetic), it fits comfortably (decision D2). Measured in the prototype through lee::V03State, the state machine the v0.3 sequencer applies, from the committed binary (docs/BENCHMARKS.md, reproducible with one command):
| M (approvals) | queue cycles |
share of the 10M cap |
|---|---|---|
| 1 | 601,700 | 6.0% |
| 3 | 1,148,829 | 11.5% |
| 5 | 1,704,538 | 17.0% |
| 10 | 3,103,377 | 31.0% |
| 16 | 4,755,001 | 47.6% |
| 32 | 9,181,398 | 91.8% |
About 275,000 cycles per approval, linear in M. M = 5, the RFP's line, uses 17% of the budget; M = 32, the most members a configuration may hold, still fits one transaction. A queue carries 96 bytes per approval (key and signature): 480 bytes at M = 5.
Block limits. On LEZ v0.3.1 the 10,000,000-gas cap bounds both one public transaction's gas_limit and all public execution in a block: a public M = 5 queue (1.70M) leaves room for five per block, and M = 32 (9.18M) fills a block alone; the client sets gas_limit from this table (about 275,000 per approval), not the wallet's 2M default. Private transactions are not metered at v0.3.1; they are bounded by block bytes, about 250 kB each (248,233 bytes for our testnet execute-private), so a 1 MiB block holds about four. Largest viable M: 32 under the public posture (the member cap); under the private posture, measured to M = 10 below with neither time nor size near a limit, and M = 32 would be about 254 kB at the measured 192 bytes per approval; M0 measures it.
Real proving (RISC0_DEV_MODE=0, never development mode), of the step that verifies the approvals, on an Apple M4 Pro with CPU proving: 71.5 s for M = 1, 93 s for M = 3, 152 s for M = 5, 381 s for M = 16, about 20 s per approval, with a succinct receipt of about 225 kB that barely grows with M (about 340 bytes per approval); these figures are the program's own receipt, not a whole private transaction.
The whole private transaction, measured on the public testnet on 16 October (docs/PRIVATE-TX-MEASURED.md, driver scripts/measure-private-m.sh, raw output in docs/raw/). What runs is accord spend --private-vault under a spending limit whose sub-quorum is M: the program verifies M BIP-340 signatures (valid, distinct, spenders of the limit) inside a privacy-preserving transaction that spends the private vault as a nullifier and a new commitment, real proving on the CPU. Apple M4 Pro, 14 cores (10 performance, 4 efficiency), 24 GiB; program CehtqLan7gii…, the committed binary 24a69044…:
| M | prove and submit (s) | peak RAM | tx bytes | testnet transaction (block) |
|---|---|---|---|---|
| 1 | 160.6 | 6.52 GB | 248,012 | fda6307341be61c3… (25552) |
| 3 | 188.6 | 7.87 GB | 248,396 | 804ce7d1513c59d5… (25471) |
| 5 | 165.3 | 7.21 GB | 248,780 | 5e8f7d3ad6f9e467… (25498) |
| 10 | 165.1 | 6.61 GB | 249,740 | 6b3bad982da1b7cd… (25523) |
Each hash resolves through the sequencer's getTransaction as a privacy-preserving transaction; tx bytes count it as the sequencer returns it, and peak RAM is the largest process, prover included. Proving time is flat in M: the privacy circuit dominates, and the spread between runs is larger than the cost of nine more signatures. The receipt-only figures above do not add to it; at M = 10 the whole transaction (165 s) is faster than the bench's receipt alone (251.7 s), which M0 explains before either table is restated. Size grows by 192 bytes per approval, on about 247.8 kB. Peak memory is 6 to 8 GB with no trend in M, so a member needs about 8 GB free to prove. A local v0.3.1 sequencer gives the same sizes and 164 to 179 s.
What this covers, and what it does not. It measures spend, which checks M signatures. queue checks M + 1 (the proposer and M approvals) and is sent only as a public transaction from the CLI today, because the queued record it writes is public in the prototype; execute-private checks one executor signature. M2 makes the queued record private (§2), and with it queue becomes a privacy-preserving transaction checking as many signatures as a private spend at M + 1, so this table brackets it up to M = 9; M2 measures it the same way.
The window's start at is chosen by the client and the program reads no clock. These runs opened it 60 s after the chain clock (ACCORD_AT_DELAY_MS, a client option that changes no on-chain rule) so slow inclusion could not run it out, and the whole transaction fits the ten-minute window with minutes to spare; M0 fixes the window length from these figures, before the code freeze.
Proving takes minutes, so the mini-app and the CLI treat Queue and Execute as background jobs with visible progress and a resumable state, never as a request that blocks a screen.
5. Arbitrary actions and the registry (F.3, F.4, U.6)
Execute makes the action's chained calls to any program deployed in the LEZ, with the vault's seed attached, so the vault can pay natively, call the token program, or act as an admin authority of another program.
The registry is append-only: Register { program, image_id, idl_sha256, name } writes an entry naming who registered it. A client (1) reads the target's header account and checks that its program_loader record holds the ImageID the entry names, (2) fetches the IDL from anywhere and checks that it hashes to idl_sha256, and (3) shows which registrants vouch for the entry and whether independent registrants agree. No single server is trusted for either the bytes or the IDL. The native token program, the token program and this program are decoded by built-in IDLs.
Each multisig stores the registrants it trusts, changed only through F.5; a client marks a target decoded only when a trusted registrant signed its entry, and labels which one.
When a target is not registered (F.4), the client displays the target header, the ImageID read from the chain, the raw instruction bytes in hex with their length, every account the call touches and the shard it selects, and the warning "This program is not in the registry: the action cannot be decoded." The mini-app will not let a member sign it from the default view. For a registered target, U.6's display is decoded from the exact bytes the approval signs, never from the proposer's description, which is shown separately and marked as the proposer's.
6. The coordination room (F.9, Coordination Architecture, Privacy-2, Privacy-3)
Transport. One end-to-end-encrypted group conversation per multisig per epoch, on the Logos chat module (create_group_conversation, add_group_member), over Logos Delivery. It carries deliberation and the approval packages.
Prototype status. The prototype's room, accord room (docs/ROOM.md), already carries approval packages and deliberation end to end encrypted over Logos Delivery, the layer the chat module runs on: a room secret per epoch sealed to each member's approval key, a topic that names nothing about the multisig and is unrelated across epochs, frames signed with the sender's approval key over the multisig, the epoch and the content, and a listener that drops non-members and keeps only approvals that verify over the recomputed digest. The same packages also travel through a chat-module group conversation: in scripts/e2e-chat.sh three members on chat_module 0.3.0 reach a 2-of-3 quorum with approvals collected only through the MLS group, and a forged approval is dropped at merge. Driving that group's membership from the configuration, the binding statement, and Store-backed history for members who were offline, is M3.
The LEZ-to-chat binding. No such binding exists today, so we define one. F.9 speaks of binding each member's LEZ account; we bind the member's approval key instead, on purpose: under Privacy-1 a member's LEZ account never appears in the multisig, so binding it to a chat identity would publish, to every member, the very link Privacy-1 keeps out of view, while the approval key is already the member's identity in the configuration. Each member signs, with the approval key, ("bind", configuration, epoch, chat identity). The room admits a chat identity only with a binding signed by a key in the current configuration, which any member's client verifies against the chain (public posture) or against the private configuration it can decrypt (private posture). The binding never goes on chain. Provisioning: the creator's client opens the group conversation and posts its binding; it invites each member's chat identity; each member accepts, posts a binding and checks the others; a participant without a valid binding for the current epoch is shown as unverified and nothing they post counts. The chat module's identities are currently ephemeral (an instance mints a new identity on restart), so a member who restarts posts a new binding, and the old one stops counting.
The room carries no trust for validity: every proposal and approval is a signature the program verifies (R.1). What a room participant can do, and how it is detected or tolerated, as required:
| Behaviour | Effect | Defence |
|---|---|---|
| Withhold an approval or a package | delays quorum | liveness only: any member can re-post, and the program needs any M, not specific ones |
| Reorder | none | packages are independent; each digest stands alone |
| Replay an approval | none | the digest binds the multisig, the epoch and the expiry; the queued record is written once |
| Inject a forged approval | none | the program verifies every signature against the configuration |
| Show different members different packages | a member may sign a digest the others did not see | the signer's client decodes the exact bytes it signs (U.6), so a member never approves something other than what they were shown; the room is only a transport |
Reconciliation with program membership. A new epoch opens a new room from the new member set, and members' clients close the old room when they see the epoch move. Until then, a removed member can still read deliberation in the old room but cannot approve anything that counts, because their key is not in the configuration the program checks. Nothing posted in the new room reaches them. Under the private posture a removed member also still holds the group keys: they can read the configuration and vault, but cannot spend, because every debit needs a quorum of the current configuration. Their read access ends when the members re-key the multisig into fresh private accounts with a new group secret, through one M-of-N action the removal proposal schedules; until then it is documented as residual visibility.
Correlations left observable (Privacy-3). Documented in full in the privacy-properties document, at minimum: the timing between room traffic and Queue/Execute transactions; the fee payer of public transactions (clients use a fresh payer); the size of a Queue transaction, which grows with M, and of a private transaction, which grows by 192 bytes per approval and so tells the chain how many signed (padding the approval list to a fixed length is evaluated in M0); the room's message cadence as seen by Delivery nodes; the program id where a private transaction names it, and whether an immutable header removes it (checked in M0); the timestamp window, which clients round to a coarse bucket; the number of private accounts per transaction; the chat module's own transport metadata (group identifiers in envelopes, MLS epoch, group size from join bursts, key-package lookups), captured on the wire in M3; and the LEZ-to-chat binding, which lives only inside the room and links a chat identity to an approval key for room members, which is why approval keys are single-purpose. For each: which signal carries it, why it remains, and what an observer of both layers can infer.
7. Module, CLI, IDL, mini-app (U.1 to U.7)
- Logos multisig module with a documented API other modules call: create, propose, approve, reject, queue, execute, manage members and policies, disclose. Its C ABI sits on the same core crate the guest runs, so types, digests and checks cannot drift between the program and its clients.
- CLI on the Logos core headless framework, covering every essential operation including configuration changes and the room's provisioning.
- IDL in SPEL's JSON shape. SPEL does not support v0.3 yet, so, as in our vesting program, the IDL is maintained by hand in SPEL's format with a CI check that decodes the program's own borsh vectors using only the IDL and fails on any drift; it switches to generated output when SPEL supports the target runtime.
- Basecamp mini-app (QML), loadable from the git repository with build instructions and downloadable assets: the proposal list with its room alongside, the decode-before-sign screen of U.6, queued actions with their time lock, the posture and disclosure screens, and a background job view for proving. Figma designs for the proposal list and the room are delivered in M5.
- Errors (U.7): every refusal is a stable code with an actionable message; the module checks the refusals a member can hit by mistake (expired, wrong epoch, below threshold, outside the spending allowance) before proving anything, so a member does not wait minutes for a predictable refusal.
- Catalog (Supportability Create RFP-008 for Private NFT Marketplace #12): the modules are published in our own module catalog built from the Logos module catalog template, as we already do for Logos Forum; the module and mini-app ship as signed packages, verified at install.
8. Testnet 0.3 and 0.4 (Supportability #3)
Testnet 0.4 is announced with actors and messages and a new LEZ Core Module API, and it breaks programs written for 0.3. We absorb that by construction:
- The logic lives in a runtime-agnostic core crate: digests, signature verification, epoch rules, policy evaluation, the privacy table. Host tests run it without any runtime. The runtime shell (plan and apply on 0.3, actors and messages on 0.4) is thin and is the only part that ports.
- We have done this port before, quickly: our vesting program moved from v0.2.4 to v0.3 within a day of the release, and redeploys at the same program id after a testnet reset, because the header and segment accounts are kept by the deploying wallet.
- Milestone M6 is the 0.4 port: rebuild, redeploy, re-drive the whole lifecycle, restate every benchmark with real proving, against 0.4. Until 0.4 ships, every milestone is accepted on 0.3.
9. Tests, CI and evidence (Supportability #4 to #10, #14, Performance)
- Every Functionality, Usability and Reliability requirement maps to at least one named test in a traceability table generated from the test names, including the three the RFP names: an action cannot execute below threshold, R.2's cutoff on every branch, and a vault cannot be drained before initialisation.
- An end-to-end suite runs against a standalone LEZ sequencer in CI, with no skip path: a gate that cannot reach the sequencer fails rather than passes. The prototype's workflow (
.github/workflows/ci.yml) already defines the jobs: host tests and the IDL check, the committed binary throughlee::V03Statewith the cycle table, a clean rebuild compared with the committed binary, the CLI and room tests, and the full lifecycle on a standalone v0.3 sequencer. - The benchmark harness is committed and reproducible with real proving; development-mode figures are never reported.
- Deployments on the public testnet ship with a manifest of every transaction and a verifier script anyone can run from a clean clone, as in our existing programs.
- Design decision log in the repository from day one, in the RFP's form (context, options, choice, rationale, trade-offs), current at every milestone delivery. Our vesting program's log records 38 decisions this way (
docs/DECISIONS.md).
10. Audit programme (Supportability #13)
- Firm: Cantina (Spearbit as the alternative), engaged for the multisig program, the approval-verification path, the configuration-change and time-lock logic, and the spending-limit policy, plus the room protocol's validity assumptions.
- Budget line item: a $50,000 allowance, not a vendor quote, contracted and paid by Logos directly to the firm, outside our $70,000 request. The scope is compact, one guest program and its CLI-facing interface plus the room's validity assumptions, which we size at about two auditor-weeks at published tier-1 rates of $20,000 to $25,000 per engineer-week, covering the review and a re-check of the remediation. We ask the firm for a scoping estimate during M0; if it is higher than the allowance, we raise it with Logos at the M0 gate, before any commitment. The final scope and cost are confirmed with the firm before the code freeze. Our side, M7, is remediation of every finding and re-verification.
- Timeline, ahead of any mainnet recommendation: the audit slot is booked mid-project, during M4; the audit runs on the code frozen at the end of M5, during M6; the remediation re-check closes in M7. The 0.4 runtime shell is part of the firm's remediation re-check in M7, so no code path ships unreviewed. No deployment beyond testnet is recommended before that re-check is complete.
- Publication: the audit report and our remediation notes are published in the repository with the codebase before any production deployment of the software.
11. Risks, stated
- Approval verification inside the private circuit. Measured on the public testnet: a private-vault spend checking M = 1 to 10 signatures inside a privacy-preserving transaction proves in 160.6 to 188.6 s, at 6 to 8 GB peak memory and about 250 kB (§4). Still to measure: the private
queue, which checks M + 1 and needs the private queued record (M2), and M above 10; if either changes the picture, the fallback is splittingqueueover a committed partial set, discussed with the numbers. - Private PDAs and group keys on 0.3. Shown for the vault on the public testnet (group keys alone are refused); still to be shown for the configuration and queued records.
- Chat identities are ephemeral today, and nothing yet binds a chat address to a member. The prototype's chat-module group is opened and grown by hand. Handled by the binding statement and re-binding (§6), priced as M3; the room never carries validity, so a lost room costs time, not funds.
- 0.4 breaks programs. Isolated in the runtime shell and priced as M6.
- Concurrent private writes. Every private transaction consumes the private accounts it reads, so two concurrent operations on one private configuration conflict and the later one re-proves. Members' clients serialise operations through the room, and
SpendandExecutestay off the configuration account where the design allows; M0 confirms the cost. - Proving time. Minutes per transaction on a laptop (about three for a private spend at any M up to 10); the UX treats it as a background job, and we report real figures, including the slow ones.
12. Requirement traceability
| Requirement | Where in this proposal | Milestone |
|---|---|---|
| F.1 M-of-N, configurable at creation | §1, §3 | M1 |
| F.2 lifecycle, expiry, off-chain collection | §3, §6 | M1, M3 |
| F.3 any program | §3, §5 | M1 |
| F.4 registry, unregistered targets | §5 | M2 |
| F.5 configuration through M-of-N | §3 | M1 |
| F.6 role separation and its guarantees | §1 | M1 |
| F.7 time lock | §3 | M1 |
| F.8 spending limit | §3 | M2 |
| F.9 coordination room and binding | §6 | M3 |
| F.10 private by default, public posture, disclosure | §2 | M1, M2 |
| U.1–U.4 module, mini-app, CLI, IDL | §7 | M4, M5 |
| U.5 public/private split per posture | §2 | M1, M6 |
| U.6 decode before signing | §5, §7 | M5 |
| U.7 actionable errors | §3, §7 | M1, M4 |
| R.1 M distinct current members, exact action | §3 | M1 |
R.2 epoch cutoff at Queue, removed member during delay |
§3 | M1 |
| P.1 cost, size and proving time per operation, real proving | §4 (the whole private spend measured on testnet), §9 | M0, M6 |
| P.2 verification cost vs M, M ≥ 5 | §4: cycles to M = 32, receipt proving to M = 16, the whole private transaction at M = 1, 3, 5, 10 on testnet | M0, M2 (private queue), M6 |
| S.1–S.2 LEZ private accounts, chat module | §2, §6 | M1, M3 |
| S.3 testnet 0.3 and 0.4 | §8 | M1, M6 |
| S.4–S.7 testnet deployment, sequencer e2e in CI, green CI, a test per requirement | §9 | M1–M6 |
| S.8–S.11 README, API and CLI docs, Figma | §7, §9 | M4–M6 |
| S.12 own module catalog | §7 | M6 |
| S.13 audit programme: Cantina (Spearbit alternative); line item a $50,000 allowance (not a quote), paid by Logos directly, outside our request; scoping estimate checked at the M0 gate; timeline before any mainnet recommendation; report published with the codebase | §10, milestone table | M7 (audit during M6) |
| S.14 design decision log | §9 | M0 onward |
| Privacy-1 no member account in a transaction | §1 | M1 |
| Privacy-2 room metadata | §6 | M3 |
| Privacy-3 cross-layer correlations | §6 | M3 |
| Soft F.1 weighted approvals | §1, §3 | M2 |
| Soft F.3 mixed postures | §2 | M2 |
| Soft F.2 proof of holding | not delivered; a design note in the decision log at M2 | M2 |
Milestones, Payout and Timeline
Eight milestones over about 20 weeks, shorter than the RFP's six-month estimate because a working prototype already exists. The team is two people on two tracks; the critical path is M0 → M1 → M3 → M5 → M6 → M7 (about 19 weeks), with M2 and M4 on the second track. Each milestone says what is built today, with the test, script or transaction that shows it, and what remains; the payouts price what remains. M0 keeps the phase the RFP invites: the composed private transaction is now measured for a spend (§4) and does not change the picture; if M0's remaining measurements do, the scope and price of M1 to M7 are revisited at its acceptance. Every milestone is accepted on evidence anyone can re-run. Ramp-up: none is priced for the program track, which is productive on LEZ v0.3 today (the deployment above); the Logos module SDK and QML ramp-up of the client track is inside M4's and M5's effort.
| # | Deliverable | Effort | Status today | Payout |
|---|---|---|---|---|
| M0 | Approval-verification benchmark, design and threat model | 2 wk | partial: cycle table, real-proving table, the whole private transaction at M = 1 to 10 on testnet, scheme chosen | $5,000 |
| M1 | Core program on testnet 0.3 | 3 wk | partial: deployed on the public testnet 0.3 and its lifecycle run there, public and private | $13,000 |
| M2 | Private posture complete, policies, disclosure | 4 wk | partial: private vault, spending limits and the registry built | $10,000 |
| M3 | Coordination room on the Logos chat module | 5 wk | partial: approvals collected through a chat-module group, end to end | $12,000 |
| M4 | Logos multisig module, CLI on the headless framework, IDL | 3 wk | partial: CLI and IDL with drift check built | $9,000 |
| M5 | Basecamp mini-app and designs | 4 wk | partial: a read-only view loads in Basecamp 0.3.0 | $10,000 |
| M6 | Testnet 0.4, end-to-end CI, benchmarks, documentation, catalog | 3 wk | partial: CI workflow and end-to-end scripts written | $7,000 |
| M7 | Audit remediation and re-verification | 2 wk | to build | $4,000 |
| Eight milestones, paid on acceptance | about 20 wk | $70,000 | ||
| External audit, Cantina (Spearbit alternative): separate line item, contracted and paid by Logos directly, not part of our request | during M6, before any mainnet recommendation | $50,000 allowance |
M0: Approval-verification benchmark, design and threat model. 2 weeks, $5,000
The P.2 table with real proving for M = 1 to the largest viable, re-run on a quiet machine; the whole privacy-preserving transaction, measured today for a spend at M = 1 to 10 on the testnet, extended to the largest viable M and reconciled with the receipt-only table; the room's threat model and the privacy-properties outline; the decision log brought current. Accepted when the benchmark harness reproduces the published tables from a clean clone, and the design and decision log are merged.
Status today: partial. The cycle table through lee::V03State (docs/BENCHMARKS.md, cargo run --bin measure), the real-proving table of the approval check (--bin prove), the whole private transaction at M = 1, 3, 5, 10 on the public testnet (docs/PRIVATE-TX-MEASURED.md), the scheme choice and why the stock k256 cannot work (decisions D1 and D2 in docs/DECISIONS.md), the account model, digest format and R.2 cutoff (DESIGN.md). Remaining: the composed private transaction above M = 10, proving time for every other on-chain operation (P.1), the threat model.
M1: Core program on testnet 0.3. 3 weeks, $13,000
Create, activate, queue, execute (F.3 chained calls), expiry, time lock, configuration changes with epochs (F.5, R.2), veto, role separation (F.6), R.1 verification, the initialisation guard and the 17 refusal codes, deployed on the public testnet and the whole lifecycle driven there. Accepted when the verifier script passes against the public deployment from a clean clone, and every F.1–F.3, F.5–F.7, R.1 and R.2 requirement has a named test or on-chain transaction in the traceability table.
Status today: partial. All of it is built and tested: 28 host tests in programs/accord/core, 20 executor tests of the committed binary in executor-tests/tests/program.rs (including an_action_cannot_execute_below_threshold, a_configuration_change_invalidates_pending_approvals, a_vault_cannot_be_drained_before_it_is_fully_initialised and every_refusal_code_fires_on_chain), and 28 steps (27 transactions) on a local v0.3 sequencer re-checked at 34 checks, 0 failures (evidence/v03/local-verify.txt). Remaining: the action set (F.1) and the hardening the threat model asks for.
M2: Private posture complete, policies, disclosure. 4 weeks, $10,000
The configuration and queued records as private PDAs alongside the vault, with approval verification inside the privacy-preserving circuit (F.10); viewing-key disclosure and ongoing assurance; weighted approvals (soft #1) with tests; the mixed postures this design supports (soft #3) with their tables; the spending-limit policy (F.8) and the registry (F.4) on the public testnet. Accepted when each is exercised on testnet and covered by tests, the private queue is measured per M as the private spend is today, and a disclosed audience reads a private multisig's current state from a clean machine.
Status today: partial. The private vault: funded privately, refused to a holder of the group keys, spent and executed through the program in privacy-preserving transactions on a local v0.3 sequencer (evidence/v03/local-private.tsv). Spending limits with sub-quorums and single-use spend signatures (spending_limits_pay_small_amounts_without_the_quorum, a_spend_signature_is_good_once), and the append-only registry (the_registry_is_append_only). Remaining: the private configuration and queued records, disclosure, weighted-approval tests, mixed postures.
M3: Coordination room on the Logos chat module. 5 weeks, $12,000
The room as a chat-module group conversation per epoch with membership driven by the configuration; the binding statement and its verification; invite and accept; approval collection through the room; reconciliation on configuration change; history for offline members; the adversarial cases of §6 as tests; the privacy-properties document (Privacy-1 to 3). Accepted when a multisig on testnet reaches quorum with approvals collected only through the room, a removed member is shown to receive nothing posted after the change, and the adversarial tests pass.
Status today: partial. The room runs on the chat module itself: scripts/e2e-chat.sh starts three members, each a headless Logos Core with chat_module 0.3.0 from the official catalog and its own approval key; Alice opens an MLS group for the epoch and adds Bob and Carol, the package is proposed, decoded from its bytes, approved and posted back only through the group, a copy with a forged approval is dropped at merge, and the merged package is queued and executed on chain (19 checks, 0 failures, evidence/v03/local-chat-transcript.txt, on a local v0.3 sequencer with the logos.dev Delivery fleet). A transport-agnostic fallback, accord room, carries the same packages over Logos Delivery with its own sealing (docs/ROOM.md). Remaining: group membership driven by the configuration (the next epoch's group on a configuration change, a removed member left out), the binding statement between a chat identity and an approval key, Store-backed history, the adversarial tests, the run on testnet.
M4: Logos multisig module, CLI on the headless framework, IDL. 3 weeks, $9,000
The module and its API documentation (U.1, S.9); the CLI on the Logos core headless framework and its documentation (U.3, S.10); the IDL with its drift check (U.4). Accepted when the CLI drives the whole lifecycle including configuration changes against testnet, and the module and CLI test suites pass in CI.
Status today: partial. The accord CLI covers keys, create, activate, propose, decode, approve, queue, execute, spend, register, show, the room and the private vault, and sent every transaction above; the IDL in SPEL's shape is checked by scripts/check-idl.py against 15 borsh vectors. Remaining: the Logos module and its C ABI, the CLI on the headless framework with reject, the docs.
M5: Basecamp mini-app and designs. 4 weeks, $10,000
Proposal list with its room alongside, decode-before-sign (U.6) through the registry, queued actions and time locks, posture and disclosure screens, background proving jobs, errors (U.7); Figma designs; loadable in Basecamp from the git repository. Accepted when a member approves and executes from the mini-app on testnet, and an unregistered target cannot be signed from the default view. The code is frozen for the audit at the end of M5.
Status today: partial. A read-only mini-app, packaged with the Logos module builder (app/), loads in Basecamp 0.3.0 and shows a multisig from the chain: its configuration, members and roles, spending limits, and each approval package decoded from the exact bytes its approvals sign, with who has approved, the time lock against the chain's clock, and the command for whoever's turn it is; a tampered package is refused as a digest mismatch (screenshot). Its reader is checked against the Rust program in app/tests/chain_test.cpp (13 checks). It holds no keys and signs nothing. Remaining: signing and execution from the app, background proving jobs, the posture and disclosure screens, the registry check before signing (U.6), the Figma designs.
M6: Testnet 0.4, end-to-end CI, benchmarks, documentation, catalog. 3 weeks, $7,000
The port to testnet 0.4 and the lifecycle re-driven there; the standalone-sequencer suite green in CI; P.1 and P.2 restated with real proving on 0.4; README end to end, API and CLI docs; modules published in our own catalog. Accepted when CI is green on the default branch with every step executed and the verifier passes against the 0.4 deployment.
Status today: partial. The CI workflow (.github/workflows/ci.yml) is green on the default branch today, including the full lifecycle on a standalone v0.3 sequencer (run 38614584481); the 0.4 port, the catalog and the documentation remain.
M7: Audit remediation and re-verification. 2 weeks, $4,000
Remediation of every audit finding, re-verification on testnet, report published with the codebase. Accepted when the report is in the repository with every finding resolved or explained.
Status today: to build.
Total Requested Budget (USD)
$70,000, plus the external audit as a separate $50,000 allowance paid by Logos directly: $120,000 all-in.
Relevant Experience
A private M-of-N multisig on LEZ, prior work built for the v0.2 runtime: members hold shielded accounts, approvals are RISC0 membership proofs verified on LEZ's privacy-preserving path, the configuration is anchored by address so a lowered threshold resolves to an account nobody initialised, and reaching the threshold pays out of the multisig's treasury. Spending tiers and configuration rotation, 131 tests (84 of them against the built verifier through the sequencer's own executor), a full lifecycle with real proofs in CI, cycle and wall-clock measurements, a Basecamp module. Its approvals are anonymous by design, which is why this proposal does not build on it: R.1 asks for approvals attributable to current members, and the RFP is right that the two models differ. What we take from it is what it taught: the threshold bypass that every individual check missed (approvals for one multisig presented under another), why a configuration must be anchored rather than read, and how to benchmark proving honestly.
A vesting program on LEZ v0.3: https://github.com/edenbd1/antumbra-lez. Ported to v0.3's plan-and-apply model within a day of the v0.3.0 release; custody through program PDAs, claims into private accounts, time bounded by the block timestamp, a reproducible build checked in CI, and a verifier that re-checks the whole testnet run from a clean clone. The block-timestamp windows behind this proposal's time lock and expiry are the ones it uses.
λPrize LP-0005, Private Balance Attestation: won. logos-co/lambda-prize#64, merged 2026-08-02. RISC0 threshold proofs over shielded accounts, verified on chain and off chain over Logos Messaging.
Logos Forum: https://github.com/edenbd1/lp-0026-forum, a serverless forum module for Basecamp over Logos Delivery and Storage, published in its own catalog (https://github.com/edenbd1/logos-forum-catalog) and run as a permanent node on the public network. The transport, the module packaging and the catalog path of this proposal's room and mini-app are ones we already ship.
How this maps to the recommended team profile.
| The RFP asks for | Where it already exists |
|---|---|
| Multisig or threshold custody design | the LEZ multisig above: threshold enforcement, anchored configuration, rotation, spending tiers, a treasury that pays at threshold |
| Rust for a RISC-V or zkVM target (Risc0) | three RISC0 programs on LEZ across v0.2 and v0.3, built reproducibly |
| Applied cryptography and ZK | threshold balance attestation (LP-0005), private claims (vesting) |
| Secure signing UX | the decode-before-sign and disclosure screens of the vesting mini-app's claim flow, carried here into U.6 |
| Front end for custody or wallet apps | Basecamp modules for the multisig, the vesting program and the forum; Nada Ahmadi's Umbra front end and full-stack work at XRPL Commons |
Post-Delivery Plan
Maintained by the two of us for twelve months from final delivery:
- Security issues acknowledged within 48 hours, with a fix or a documented mitigation; a multisig holds other people's funds, so this one is not best-effort.
- Platform tracking: kept building and deployed on the current testnet across LEZ, chat-module and SPEL releases, and re-driven after every reset with the replay script.
- Public issues answered on GitHub.
- Handover: MIT OR Apache-2.0, no private build step, a deployment anyone can verify from the committed artifact, and a decision log that explains every choice, so the ecosystem can take it over without us.
We have not priced an operating line because the RFP delivers software rather than an operated service; if Logos wants a defined operating commitment, we will scope one.
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
edenbd1 commentedon Oct 15, 2026
Demo film, in my own voice
accord-multisig-rfp005-demo.mp4
4 min 15, narrated by me, subtitled. Everything on screen runs from a clean clone of edenbd1/lez-accord against the program deployed on the public LEZ testnet (
CehtqLan…, ImageID24a69044…, the reproducible build):lee::V03State, including every refusal code fired on chainverify-onchain.shat 34 checks, 0 failuresedenbd1 commentedon Oct 16, 2026
Update: the whole private transaction, measured on the public testnet.
The proposal said the composed private transaction was unmeasured and left to M0. It is now measured:
accord spend --private-vaultunder a spending limit whose sub-quorum is M, so the program verifies M BIP-340 signatures inside a privacy-preserving transaction that spends the private vault as a nullifier and a new commitment. Real proving on the CPU, Apple M4 Pro (14 cores, 24 GiB), the committed binary24a69044….fda6307341be61c353127f1871035c54339ad0225b9543d463748d2c37863b2b(25552)804ce7d1513c59d57b97d7b2667aa7cbdb4822fead88ec7b5df559bd90e77556(25471)5e8f7d3ad6f9e4679922c20d55815fc0a6cc5233e36fa15e8dc1f3675dc68cdd(25498)6b3bad982da1b7cd53d80a74f662f1199eb84b27dc51d6c34a41597d11f013c6(25523)Proving time is flat in M; size grows by 192 bytes per approval; peak memory stays under 8 GB. Each hash resolves through the sequencer's
getTransactionas a privacy-preserving transaction. Method and raw output:docs/PRIVATE-TX-MEASURED.md.Scope, plainly: this is
spend, which checks M signatures.queuechecks M + 1 and is public-only from the CLI today; M2 makes the queued record private and measures the privatequeuethe same way. A private transaction's size reveals how many signed, which joins the Privacy-3 list.edenbd1 commentedon Oct 19, 2026
Budget note: the external audit allowance is raised from $35,000 to $50,000. Sized against published tier-1 rates ($20,000 to $25,000 per engineer-week), $35,000 bought less than two auditor-weeks, which is what a careful review of the audited surface (the guest program, the approval digest and the room's validity rules, about 1.5k to 2.5k lines at code freeze, on a platform the auditor has to learn) plus a fix review needs. Cantina is now the primary firm, with Spearbit as the alternative. Our $70,000 request and the milestones are unchanged; the audit stays a separate line item paid by Logos directly, confirmed with the firm's written quote at the M0 gate.