Skip to content

feat(splitter): add optional payment reference to pay, pay_many, pay_many_multi - #288

Open
Justjoseph0 wants to merge 2 commits into
tributary-protocol:mainfrom
Justjoseph0:feat/payment-reference
Open

feat(splitter): add optional payment reference to pay, pay_many, pay_many_multi#288
Justjoseph0 wants to merge 2 commits into
tributary-protocol:mainfrom
Justjoseph0:feat/payment-reference

Conversation

@Justjoseph0

Copy link
Copy Markdown

Closes #263

No way to tag a payment with an order/invoice id before this. Integrator pays a marketplace split for order A-1234, has nothing to attach that to on-chain.

What I did:

  • SplitPaid gets a reference: Option<BytesN<32>> field, plain data not a topic, so it doesn't cost a topic slot
  • pay() takes an optional reference now, passed straight into the event. None costs nothing extra
  • pay_many() takes references: Vec<Option<BytesN<32>>>, paired with ids/amounts. Empty vec = no reference for anyone in the batch, skips the length check entirely so callers who don't care pay zero extra cost. Non-empty has to match ids.len() exactly or it's LengthMismatch, checked before any transfers so the batch reverts clean on mismatch
  • pay_many_multi() gets the same treatment. Issue only names pay/pay_many but this one's the same shape just with per-item tokens, would've been a weird gap to leave it out
  • deposit() untouched on purpose. Issue said "consider" it, not required, and it opens its own questions (does a deposit reference need to survive into distribute, how do multiple deposits reconcile) that deserve their own issue instead of getting bundled in here
  • indexer/index.mjs: turns out event decoding already copies fields generically so reference flows through for free, but found a real bug while I was in there — BytesN<32> decodes to a Buffer and JSON.stringify was mangling it into {"0":...,"1":...}. Added a normalizeValue() helper that hex-encodes byte arrays, kept the existing bigint handling as-is
  • export-csv.mjs: added reference to the COLUMNS list since it's a fixed allowlist, checked end to end that rows with a ref show hex and rows without leave it blank
  • sdk/src/index.ts: regenerated with the real stellar CLI, not hand-rolled XDR. pay_many_multi wasn't even in the SDK before this. Verified at runtime that funcArgsToScVals encodes reference correctly for present/undefined/mixed-array/empty-array cases across all three functions, checked down to the ScVal level that Some encodes as scvBytes and None as scvVoid

Testing: cargo test (the repo's own recipe) — 35/35 passing, 8 new tests covering with/without reference, empty vec, and mismatched length rejection with revert checks. Indexer tests pass. SDK tsc builds clean.

Flagging pay_many_multi since the issue text didn't name it explicitly — added it for consistency, let me know if that's not wanted.

…many_multiIntegrators had no way to tag a payment with an external id (order/invoice)for reconciliation. Adds an optional reference: Option<BytesN<32>> to pay,and references: Vec<Option<BytesN<32>>> to pay_many/pay_many_multi (emptyvec means no reference for any split in the batch, non-empty must matchids.len() exactly or returns LengthMismatch).Carried through into the SplitPaid event as a plain data field (not atopic, to avoid spending a topic slot). Indexer and export-csv.mjs updatedto decode and surface it. SDK regenerated via the stellar CLI and exposesreference as an optional argument on all three functions.deposit() intentionally left untouched — separate design question, outof scope here.
@Justjoseph0
Justjoseph0 requested a review from Spagero763 as a code owner July 18, 2026 01:27
…tionalcargo fmt --all --check was failing on two multi-line call sites in test.rs,pure formatting, no behavior change.The generated SDK interface marked reference/references as required keys(value type Option<T>, but the key itself was mandatory), which brokePaySplit.tsx, an existing caller that predates this feature and doesn'tpass a reference. Made reference/references actual optional TS keys, andadded a small constructor-level patch so the base ContractClient alwaysreceives the key with a sensible default (undefined for reference, [] forreferences) when the caller omits it — verified at the ScVal encodinglevel that omitted still resolves to None/empty and explicit values stillpass through byte-identical.
@Spagero763

Copy link
Copy Markdown
Contributor

contract fails to compile: error[E0061]: this method takes 5 arguments but 4 arguments were supplied. Looks like a call site wasn't updated after a signature change elsewhere in this PR — worth a check for all callers of that method.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add an optional payment reference so integrators can reconcile payments

2 participants