Skip to content

feat(rights): MuzixRightsOffering — on-chain term-sheet registry + Sapta pilot#37

Merged
abhicris merged 4 commits into
mainfrom
feat/rights-offering
May 25, 2026
Merged

feat(rights): MuzixRightsOffering — on-chain term-sheet registry + Sapta pilot#37
abhicris merged 4 commits into
mainfrom
feat/rights-offering

Conversation

@abhicris
Copy link
Copy Markdown
Contributor

Summary

Ship the on-chain "term sheet" registry that lets an artist publish a draft offering of distribution / sync / master-licensing / publishing rights (single album or whole catalogue), and lets labels / IP buyers / distributors / sync agencies submit counters — either accept the base outright or propose modified economics. The artist picks one counter to accept; the on-chain record is the commitment, and downstream settlement contracts execute payment + rights transfer against it.

  • `src/MuzixRightsOffering.sol` — core contract (Ownable-free, per-offering artist; ReentrancyGuard + SafeERC20).
  • `test/MuzixRightsOffering.t.sol` — 31 Foundry tests.
  • `script/DeploySaptaPilot.s.sol` — deploys the contract and seeds two Sapta drafts.
  • `docs/sapta-pilot.md` — bidder-facing walkthrough.

The contract is settlement-token-agnostic (`IERC20`), so it deploys unchanged against MUSD on whichever L1 holds the token — create-protocol L1 in production (where MUSD lives for agentic operations + Switchboard payments) or muzix L1 for early testnet runs.

Sapta pilot drafts

Draft Term Upfront Min Guarantee Artist Royalty Reply Window
Album (exclusive distribution, worldwide) 3 yrs $25,000 $50,000 65% 30 days
Catalogue (exclusive full rights, worldwide) 5 yrs $150,000 $400,000 70% 45 days

Numbers are placeholders for the pilot bootstrap; tune in the script or update via `updateDraft` before publishing.

What's on-chain

  • Authoring lifecycle: `createOffering` → `updateDraft` (Draft only) → `publishOffering` → `acceptCounter` | `withdrawOffering` | `markExpired` (permissionless after deadline).
  • Counters: `submitCounter` (custom `Economics`) or `acceptBaseTerms` (shortcut for "I take exactly what you posted"). Optional MUSD bond as earnest; minimum bond enforced per offering.
  • Acceptance: `acceptCounter` flips status to `Accepted`, records `acceptedCounterId`, refunds winner's bond (bond is earnest, not payment). Losing counters stay Pending until each bidder calls `withdrawCounter`.
  • Rejection: `rejectCounter` for explicit "no" with bond refund; offering stays Open for more bids.

Out of scope (downstream contracts wire these against an accepted offering's terms)

Test plan

  • `forge build` clean
  • `forge test` — 46/46 passing (31 new + 15 existing across MUSD / MuzixCatalog / MuzixAIProvenance)
  • Coverage: full lifecycle, bond accounting on all close paths (accept / reject / withdraw / expire / offering-withdrawn), `acceptBaseTerms` shortcut, zero-bond branch, below-min-bond rejection, deadline-passed submission rejection, access control on every privileged call, counter listing
  • Deploy to OP Sepolia against a test MUSD (follow-up — coordinated with Sapta's wallet)

…pta pilot

Artist publishes a draft offering of distribution / sync / master /
publishing rights (single asset or whole catalogue) with base economics.
Labels, IP buyers, distributors, and sync agencies submit counters: either
accept the base outright via acceptBaseTerms, or propose modified
Economics with an off-chain memo. Counters can post a refundable MUSD
bond as earnest. Artist picks one counter to accept; offering flips to
Accepted and acceptedCounterId is the canonical on-chain commitment
reference. Losing counters remain Pending until each bidder calls
withdrawCounter to recover their bond.

Contract is settlement-token-agnostic (IERC20 + SafeERC20), so it deploys
unchanged against MUSD on whichever L1 holds the token — create-protocol
L1 in production or muzix L1 for early testnet runs.

Sapta pilot ships two drafts via script/DeploySaptaPilot.s.sol:
  - Album: 3-yr exclusive distribution, $25K upfront / $50K MG / 6500 bps
    to artist, worldwide, 30-day reply window.
  - Catalogue: 5-yr exclusive full rights, $150K upfront / $400K MG /
    7000 bps to artist, worldwide, 45-day reply window.

Numbers are placeholders for the pilot bootstrap — tune in the script or
update the draft via updateDraft before publishing. docs/sapta-pilot.md
walks bidders through how to participate (acceptBaseTerms vs
submitCounter), how acceptance works, and how the off-chain subject
manifest hooks into the on-chain subjectHash + subjectURI fields.

Out of scope (downstream contracts wire these against an accepted
offering's terms): upfront / MG settlement, royalty execution against
MuzixStreamingOracle data, KYC gating, rights NFT issuance.

31 new Foundry tests cover authoring lifecycle (create/update/publish/
withdraw/expire), counter intake (custom terms + acceptBaseTerms +
zero-bond + below-minimum-bond), acceptance/rejection flows with
bond accounting, and access control (NotArtist / NotBidder paths).
Full suite: 46/46 passing.
abhicris added 3 commits May 24, 2026 17:35
New `/contracts` route in the explorer UI: pick a template, edit
parties / splits / terms in a visual editor, watch a plain-English
draft assemble live, then deploy the encoded calls from a wallet.

Templates (all map to existing primitives — no new Solidity required):
- Recording royalty split → MuzixCatalog.mintMusic + setRoyaltySplit
- Featured-artist add     → MuzixCatalog.setRoyaltySplit (re-split)
- AI training license     → MuzixAIProvenance.setProvenance
- Sync license (film/TV)  → mint+split with off-chain JSON terms

Pieces:
- lib/contract-templates.ts — typed schema + 4 templates with
  validate() / draft() / onchain() functions per template.
- lib/contracts.ts — minimal ABI fragments + env-driven addresses
  (NEXT_PUBLIC_MUZIX_CATALOG, NEXT_PUBLIC_MUZIX_AI_PROVENANCE,
  NEXT_PUBLIC_MUZIX_CHAIN_ID).
- components/ContractBuilder.tsx — parties editor with live bps
  gauge + auto-balance, term fields, side-by-side prose draft,
  on-chain plan preview.
- components/DeployPanel.tsx — viem v2 wallet flow (custom
  transport via window.ethereum), late-binds the minted tokenId
  from the Transfer event so step 2 (setRoyaltySplit) can use it,
  computes provenanceHash via the on-chain pure helper's binding,
  gracefully degrades to "copy calldata" when contracts aren't
  configured or no wallet is present.
- /contracts gallery + builder route, nav link, homepage CTA.
The static prerender of /contracts/[slug] renders the encoded-calldata
preview, which calls resolveCall before any tokenId exists. Throwing
broke the build. Preview path now substitutes 0n for the placeholder
tokenId; the live deploy loop still throws if it ever hits the same
state at runtime.
abhicris pushed a commit that referenced this pull request May 25, 2026
… minter (#48)

Introduce LABELTON, the rights-tokenization product of the Muzix protocol.

A `Master` is the canonical rights record for a piece of music — it anchors
industry identifiers (ISRC, UPC, ISWC), commits to off-chain MIR / legal /
financial-ID payloads by content-hash, and pins an immutable cap-table.

A `Variant` is an ERC-1155 token class derived from a master (Master, Single,
Album, Remix, Stem, SyncEdit, Cover, Instrumental, Live, Other). Every variant
mints 10000 units fanned across the master's cap-table proportionally to each
holder's basis-point share. ERC-1155 balance IS the share — no parallel
cap-table mapping needed.

Issuance is wallet-sovereign: the artist or any cap-table member calls
`registerMaster` / `mintVariant` directly. The protocol owner (Muzix DAO) does
not gate issuance — it only configures which variant kinds are mintable, the
verifier addresses, and the pause switch.

The root mint of a master always lands at the same set of wallet holders
defined by the cap-table; variants of that master inherit the cap-table by
construction.

Off-chain payloads (MIR fingerprint, legal-entity dossier, financial-routing
record) are referenced by content-hash; the on-chain record commits to those
hashes at master registration and is immutable thereafter. Replacing a hash
means registering a new master.

Integration with the existing muzix contracts (MUSD, MuzixCatalog,
MuzixRightsOffering #37, MuzixStreamingOracle #36, MuzixAIProvenance) is
documented in docs/labelton-architecture.md and tracked as follow-up issues.

This commit ships:
- src/Labelton.sol (401 LoC) — the contract
- docs/labelton-architecture.md — integration story + open design questions

Out of scope here (tracked as follow-up issues):
- MUSD distribution wired against Labelton.capTableOf
- MuzixCatalog cleanup now that LABELTON owns cap-tables
- MuzixRightsOffering -> Labelton handoff after counter accept
- Oracle consumer rewire
- AIProvenance ERC-1155 owner-check path
- Foundry test suite for Labelton.sol
- Verifier signature enforcement

forge build: clean (13_098 bytes deployed)
forge test: 15/15 existing tests pass — no regressions

Co-authored-by: Pattermesh <173408993+Pattermesh@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@abhicris abhicris merged commit cad4017 into main May 25, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant