Repository navigation
Conversation
A small fork-only project shared by a signer service (e.g. an AWS Lambda holding
the seed) and its client, so both sides stay in lockstep:
- SparkSignerContract: POST /spark/{op} routes, request records, envelope, version.
- RemoteSparkSigner: client ISparkSigner over a pluggable transport.
- SparkSignerHttpHandler + SparkSignerDispatcher + SparkSignerPolicy: service side,
pinning the operator set and threshold, allowlisting receivers, refusing
adaptor signatures; nonce, key-export and ECIES ops are not served at all.
- Golden request fixtures and end-to-end contract tests against a real SparkSigner.
Jossec101
marked this pull request as ready for review
October 10, 2026 09:49
- SparkTransfer.Leaves: the leaves a transfer moves, so a claimed transfer says exactly what it brought in. - GetLightningReceiveRequestAsync: the SSP's receive request with the transfer that paid it (spark_id, total). The UserRequest query is now named as the reference SDK names it. - WithdrawLeavesAsync: exit exactly the given leaves in one cooperative exit. They already add up, so the SSP is never asked to swap leaves, and a remote signer, which serves no adaptor signatures, can sign it. Leaves that are not owned or spendable are refused before anything moves (SparkLeavesNotSpendableException).
The operators renew a leaf in place, keeping its id; the split node a node renewal adds is a new parent, not a new leaf. So the leaf ids a transfer reported stay the ones to exit: a leaf is not spendable only when it is spent, locked, frozen, or due a renewal that failed.
A zero-timelock renewal leaves a leaf with a node transaction at timelock 0 and a direct node transaction.
For such a leaf the operators' cooperative-exit check takes both direct refunds or none, and requires them;
only a claim exempts a zero-timelock node from the direct refund. Signing just the direct-from-CPFP refund,
as the reference SDK does, got the exit refused ("both direct refund txs are required when either direct
refund tx is provided"), so a renewed root leaf could never be exited. A cooperative exit now signs a direct
refund whenever the leaf has a direct node transaction. Verified against the local operators and SSP by
NodeGuard's renewal E2E.
The SSP prices a cooperative exit per speed (the same user fee, plus an L1 broadcast fee at the fee rate the speed targets) and request_coop_exit takes the speed, but NSpark always quoted and asked for FAST. Every withdrawal (WithdrawAsync, WithdrawLeavesAsync, WithdrawAllAsync, QuoteWithdrawAllAsync) and GetFeeQuoteAsync now take an ExitSpeed, FAST by default: the quote, the fee bound and the request use it. A speed the SSP has no estimate for is refused.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
NSpark.RemoteSigner, so the Spark keys can live in a separate service (like an AWS Lambda).WithdrawLeavesAsync: exits exactly the given leaves (for example what one payment brought in), with no leaf swap, so a remote signer can sign it.ExitSpeed.Fast, the default,MediumorSlow): the fee is quoted at that speed and the SSP is asked for it.Slowis the cheapest and confirms last.Stack created with GitHub Stacks CLI • Give Feedback 💬