Skip to content

feat: Clone Factory, Registry, Metadata Hash & Event Sequence Numbers - #549

Open
Sundriveauto wants to merge 5 commits into
Stellar-split:mainfrom
Sundriveauto:main
Open

feat: Clone Factory, Registry, Metadata Hash & Event Sequence Numbers#549
Sundriveauto wants to merge 5 commits into
Stellar-split:mainfrom
Sundriveauto:main

Conversation

@Sundriveauto

Copy link
Copy Markdown
Contributor

Closes #494
Closes #495
Closes #496
Closes #497

Summary

This PR implements four features to improve StellarSplit's contract deployment, discovery, storage efficiency, and event reliability.

1. Clone Factory Pattern (contracts/factory/)

Deploying a fresh WASM instance per invoice is gas-intensive. A clone factory pattern deploys minimal-proxy clones pointing to a single canonical WASM blob.

  • deploy_invoice_contract(creator, wasm_hash, salt, init_args) using env.deployer().with_current_contract(salt)
  • Duplicate salts for the same creator are rejected
  • ContractDeployed(creator, contract_address) event emitted
  • Per-creator deployment limit (10,000) to prevent DoS
  • Integration test deploys via factory
  • Workspace Cargo.toml updated with new member

2. Registry Contract (contracts/registry/)

An on-chain index of all deployed split contract instances for frontend discovery.

  • register(creator, contract) appends contract to creator's list
  • get_contracts(creator) returns all registered addresses
  • Duplicate registrations rejected
  • Per-creator limit (5,000) bounds storage and prevents DoS
  • ContractRegistered(creator, contract) event emitted
  • is_registered() and get_contract_count() query helpers

3. Metadata Hash (InvoiceCore)

Storing full invoice descriptions on-chain is expensive. A 32-byte hash (IPFS CID / SHA-256) is now stored with each invoice.

  • metadata_hash: Option<BytesN<32>> added to InvoiceCore and Invoice structs
  • Accepted as optional parameter in create_invoice via InvoiceOptions2
  • get_invoice returns the metadata_hash field
  • update_metadata_hash rejects updates on Finalised/Cancelled invoices (creator-only)
  • MetadataHashUpdated event emitted on every successful update

4. Event Sequence Numbers

Under certain conditions the same event could be emitted multiple times, confusing indexers. Each event now carries a monotonically increasing sequence number.

  • event_seq: u64 field appended to all invoice-scoped event data tuples
  • Counter stored in storage::temporary — resets between transactions
  • Sequence is scoped per invoice (independent counters)
  • Internal next_seq() helper computes the next value atomically
  • Key events updated: invoice_created, payment_received, invoice_released, invoice_refunded, and more

CI Checks

All CI checks target:

  • cargo build --target wasm32-unknown-unknown
  • cargo test
  • cargo clippy

…contract deployment

Implement a clone factory pattern in contracts/factory/ that deploys
minimal-proxy clones pointing to a single canonical WASM blob.

- deploy_invoice_contract(creator, wasm_hash, salt, init_args) using
  env.deployer().with_current_contract(salt)
- Reject duplicate salts per creator
- Emit ContractDeployed(creator, contract_address) event
- Per-creator deploy limit (10k) to prevent DoS
- Registration in DeployedContracts(creator) persistent storage
- Added to workspace Cargo.toml as new member

Issue: Clone Factory Pattern
Create contracts/registry/ as a new workspace member that maintains
a searchable map from creator address to their list of deployed
split contract addresses.

- register(creator, contract) appends to creator's list
- get_contracts(creator) returns all registered addresses
- Duplicate registrations for same contract address rejected
- Per-creator limit (5k) to bound storage and prevent DoS
- ContractRegistered(creator, contract) event emitted
- is_registered(creator, contract) query helper

Issue: Registry Contract
Store a 32-byte hash (IPFS CID / SHA-256) with each invoice so clients
can retrieve extended details without inflating on-chain storage.

- Add metadata_hash: Option<BytesN<32>> to InvoiceCore struct
- Add field to Invoice struct and invoice assembly/disassembly
- Populate metadata_hash in load_invoice from persistent storage
- create_invoice already accepts and stores optional 32-byte hash
- get_invoice now returns the metadata_hash field via InvoiceCore
- update_metadata_hash rejects updates on Finalised/Cancelled invoices
- MetadataHashUpdated event already emitted on successful update

Issue: Metadata Hash
Each emitted event now carries a monotonically increasing event_seq
field to allow indexers to detect and discard duplicates.

- Add next_seq(env, invoice_id) helper using storage::temporary
- Counter resets automatically between transactions
- Sequence is scoped per invoice (independent counters)
- Event data tuples append event_seq as the last field
- Key invoice-scoped events updated: invoice_created,
  payment_received, payment_committed, milestone_released,
  surplus_claimed, invoice_released, invoice_refunded,
  condition_verified, invoice_expired, recipient_whitelisted,
  recipient_removed_from_whitelist, payer_refunded,
  recipient_added, split_adjusted, recipients_rebalanced,
  invoice_archived

Issue: Event Sequence Numbers
feat: Clone Factory, Registry, Metadata Hash & Event Sequence Numbers
@drips-wave

drips-wave Bot commented Jul 28, 2026

Copy link
Copy Markdown

@Sundriveauto Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

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.

Event Replay Protection Invoice Metadata Hash Storage Contract Registry Lookup Split Contract Clone Factory for Per-Invoice Deployment

1 participant