Skip to content

fix(#1024,#1023): fee-split edge cases and metadata URI validation - #1037

Merged
Ejirowebfi merged 2 commits into
Favourorg:mainfrom
Bigg770:fix/issue-1023-metadata-uri-validation
Jul 23, 2026
Merged

fix(#1024,#1023): fee-split edge cases and metadata URI validation#1037
Ejirowebfi merged 2 commits into
Favourorg:mainfrom
Bigg770:fix/issue-1023-metadata-uri-validation

Conversation

@Bigg770

@Bigg770 Bigg770 commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Issue #1024 — fee-split distribution:

  • Add MAX_FEE_SPLIT_RECIPIENTS=10 cap; reject bps==0 entries in set_fee_split
  • Implement largest-remainder allocation in distribute_fee to guarantee every recipient with non-zero bps receives >= floor share; sum always equals fee amount even for tiny (1-stroop) fees
  • Add new errors: TooManyFeeSplitRecipients (19), ZeroFeeSplitEntry (20)
  • Emit split_set / split_clr events on configuration changes
  • Tests: dust amounts, sum invariant, cap enforcement, zero-bps rejection
  • Extend fuzz_fee_arithmetic with multi-recipient split configurations

Issue #1023 — metadata URI validation and mutability:

  • Validate ipfs:// prefix, non-empty CID, and max 128-byte length; new error InvalidMetadataUri (18)
  • Replace write-once model with governed update path: creators may update up to METADATA_MAX_UPDATES (5) times; auto-freeze on exhaustion
  • Add freeze_metadata(), is_metadata_frozen(), get_metadata_version()
  • New error MetadataFrozen (21); new DataKeys MetadataVersion/MetadataFrozen
  • meta event now carries version number for on-chain history
  • Tests: scheme rejection, length bounds, update-then-freeze flow, unauthorized freeze, idempotent freeze, version tracking
  • Update fuzz_set_metadata to cover validation + freeze logic
  • Update ABI docs: errors table, events table, set_metadata spec
    closes 🟡 On-chain metadata URI is write-once and completely unvalidated #1023

… URI validation

Issue Favourorg#1024 — fee-split distribution:
- Add MAX_FEE_SPLIT_RECIPIENTS=10 cap; reject bps==0 entries in set_fee_split
- Implement largest-remainder allocation in distribute_fee to guarantee
  every recipient with non-zero bps receives >= floor share; sum always
  equals fee amount even for tiny (1-stroop) fees
- Add new errors: TooManyFeeSplitRecipients (19), ZeroFeeSplitEntry (20)
- Emit split_set / split_clr events on configuration changes
- Tests: dust amounts, sum invariant, cap enforcement, zero-bps rejection
- Extend fuzz_fee_arithmetic with multi-recipient split configurations

Issue Favourorg#1023 — metadata URI validation and mutability:
- Validate ipfs:// prefix, non-empty CID, and max 128-byte length;
  new error InvalidMetadataUri (18)
- Replace write-once model with governed update path: creators may update
  up to METADATA_MAX_UPDATES (5) times; auto-freeze on exhaustion
- Add freeze_metadata(), is_metadata_frozen(), get_metadata_version()
- New error MetadataFrozen (21); new DataKeys MetadataVersion/MetadataFrozen
- meta event now carries version number for on-chain history
- Tests: scheme rejection, length bounds, update-then-freeze flow,
  unauthorized freeze, idempotent freeze, version tracking
- Update fuzz_set_metadata to cover validation + freeze logic
- Update ABI docs: errors table, events table, set_metadata spec
Resolve conflicts between the fee-split/metadata-URI PR and main's
persistent-storage (Favourorg#1034), exact-fee (Favourorg#1035), whitelist (Favourorg#1033) and
merge-repair (Favourorg#1041) changes:

- Error enum: keep main's published 18/19/20 discriminants and append the
  PR's new variants as InvalidMetadataUri=21, ZeroFeeSplitEntry=22,
  MetadataFrozen=23.
- set_metadata: keep the PR's URI validation and versioned-update/freeze
  semantics on top of main's persistent storage (migrate_addr_keyed /
  set_persistent), reentrancy lock, and charge-exactly-metadata_fee rule.
- Rewrite the ipfs:// prefix check with String::copy_into_slice — the
  PR's String::get(i) does not exist in soroban-sdk 27.
- freeze_metadata / views: migrate-aware persistent reads.
- distribute_fee: keep the PR's largest-remainder allocation; update the
  Favourorg#918 tests to the new remainder policy (remainder goes to the
  largest-frac recipient, not treasury) and drop the PR's duplicate
  test_set_fee_split_too_many_recipients_rejected.
- fuzz_fee_arithmetic: keep main's harness and invariants; rewrite
  model_distribute_fee to mirror the largest-remainder algorithm.
- Fix the PR's uri-too-long fixture (was 115 bytes, comment claimed 129).
- docs/contract-abi.md: merge both sides' set_metadata/set_fee_split
  sections, unified error table (18-23), union event table.

cargo fmt / clippy -D warnings clean; 158 contract tests pass; fuzz
workspace compiles.
@Ejirowebfi
Ejirowebfi merged commit 116d025 into Favourorg:main Jul 23, 2026
32 of 34 checks passed
github-actions Bot pushed a commit that referenced this pull request Jul 27, 2026
# [1.3.0](v1.2.0...v1.3.0) (2026-07-27)

### Bug Fixes

* **#1024,#1023:** fee-split edge cases and metadata URI validation ([#1036](#1036)) ([e3174cb](e3174cb)), closes [#1024](#1024) [#1023](#1023) [#1024](#1024) [#1023](#1023)
* **#1024,#1023:** fee-split edge cases and metadata URI validation ([#1037](#1037)) ([116d025](116d025)), closes [#1024](#1024) [#1023](#1023) [#1024](#1024) [#1023](#1023)
* align adm_upd topic and add CI drift detection ([#1032](#1032)) ([872baa9](872baa9))
* **contracts:** add distribute_fee test coverage at realistic split sizes ([#918](#918)) ([#1025](#1025)) ([f9ec953](f9ec953)), closes [#919](#919)
* **contracts:** charge exactly the required fee, not fee_payment ([#1035](#1035)) ([8654767](8654767)), closes [#1007](#1007) [#1007](#1007) [#1008](#1008) [#1008](#1008)
* **contracts:** make token-factory initialize atomic with deployment ([#1029](#1029)) ([3e12de2](3e12de2)), closes [#1005](#1005)
* **contracts:** move per-token bookkeeping to persistent storage ([#1034](#1034)) ([51c52bd](51c52bd)), closes [#1007](#1007) [#1007](#1007)
* **contracts:** prove multi-step migrate pattern with synthetic v2 tests ([#919](#919)) ([#1026](#1026)) ([f9ef384](f9ef384)), closes [#918](#918) [#918](#918)
* **contracts:** repair broken merge artifacts on main ([#1041](#1041)) ([6524e58](6524e58)), closes [1034/#1035](#1035) [#1033](#1033) [#1034](#1034) [#1025](#1025)
* **contracts:** seed max-supply counter with initial_supply ([#1006](#1006)) ([#1031](#1031)) ([4a3e90d](4a3e90d))
* **frontend:** resolve token identity from contract, not events ([#1018](#1018)) ([#1030](#1030)) ([66bcb19](66bcb19))
* **security:** validate uploaded image content, not client-declared M… ([#1055](#1055)) ([ab1f253](ab1f253)), closes [#1002](#1002) [#1002](#1002) [#1056](#1056) [#1057](#1057)
* **token-factory:** bound fee-split recipient count to prevent resource-exhaustion griefing ([#1027](#1027)) ([becd28f](becd28f))

### Features

* **frontend:** implement paginated global token listing (getAllTokens) ([#1028](#1028)) ([0e1b51e](0e1b51e)), closes [#1017](#1017)
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 1.3.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🟡 On-chain metadata URI is write-once and completely unvalidated

2 participants