@arcanetech/privacy-sdk-automatization-service keeps no state of its own. You pass ports: small objects whose methods the service calls. Every port method returns a Promise, except NoteDeriver.derive.
serviceAccount is the Stellar account that signs each submitted transaction envelope. serviceScalar is the key that owns the pinned notes. Keep serviceScalar on the service host.
Where the implementations live
The
/stellar entry runs on Node.js. See Wire the Stellar ports.
NoteDeriver
Returns the commitment and nullifier hash of a note plaintext.compose calls it for every pinned note, so derive each locked note for the service scalar. derive is synchronous because Plan editing calls it on every change.
createStellarNoteDeriver(config) from /stellar. It derives every note from your service secret and a note salt. Persist the salt: a new salt changes every commitment, so Plans confirmed under the old salt no longer match.
PlanStore
Keeps confirmed Plans and everything needed to run them.PlanStore is seven role interfaces. Each use case takes only the roles it calls.
stepKey is ${rowIndex}:${role}. read throws PlanNotFoundError for an unknown id. rememberExecutedAt and recordAcceptedInitialQuote keep the first value they receive.
Combine the roles with composePlanStore. Its cancel marks the Plan cancelled, then calls discard to drop the Plan’s Deposit authorizations and prepared Deposits.
Each role ships as a memory part. Replace any part with your own:
createMemoryPlanStore() keeps everything in memory and numbers ids from plan-1. clear() empties it. To keep Plans across restarts, see Persist Plans.
Clock
Returns the current time. Intervals and execution times use the same unit.systemClock returns Date.now(), so intervals are milliseconds.
FeeQuotes
Quotes the fee for one Step. The service skips a Step whose quote is above its Free tokens. A changed quote before the Initial Deposit runs cancels the Plan.createKytFeeQuotes(config) from /stellar asks your compliance service for the required fee and caches each quote for one minute.
CurrentRoot and Presence
CurrentRoot returns the pool’s current Merkle root. Presence reports which pinned nullifier hashes are consumed and which pinned commitments are in the pool tree. runDueSteps reads one report for every Plan in the store.
createSorobanPoolReader(config) from /stellar returns both ports. It reads the pool contract and the pinned notes of every Plan in the store, and caches each read for two seconds. Call forget() to read again at once.
Proofs
Builds the pool transaction for one Step. The request carries the Step’s pinned notes, the fee note, the Unspent note, the public amounts, and the recipient.confirm and authorizeDeposit throw DepositAuthorizationMismatchError.
SDK implementation: createStellarStepTransactions(config).proofs from /stellar.
FreshScalars
Returns a new owner scalar for each Unspent note. The service stores the scalar with the note.createStellarStepTransactions(config).freshScalars from /stellar.
Inspection
Runs the compliance check on a transaction before the service submits it. A refused Step is not submitted.createStellarStepTransactions(config).inspection from /stellar.
PoolSubmission
Submits a transaction to the pool. For a Deposit, the service passes the depositor’s authorization. Returnok: false when the pool does not accept it. The Step stays unsubmitted, and the next run tries again.
createStellarStepTransactions(config).pool from /stellar.
DepositSigning
Returns the Soroban authorization entries the depositor signs for a Deposit.depositToSign calls it after the proof and the compliance check.
createStellarStepTransactions(config).depositSigning from /stellar. Call setDepositor(account) first, so the Deposit spends from the depositor’s account.
NoteOwnership
Reports whether the service scalar owns a pinned note.confirm calls it for every locked note and throws UnownedNoteError when it returns false. Notes with no lock are skipped.
createDerivedNoteOwnership(notes, serviceScalar) derives the note again with your NoteDeriver and compares the commitment and nullifier hash.
Test without a pool
createInMemoryPool(store) from /testing returns every pool port: currentRoot, presence, feeQuotes, freshScalars, proofs, inspection, pool, and depositSigning. It accepts every transaction and reports submitted notes as present. Pair it with inMemoryNoteDeriver.