VaultsDocs

Suede Artist Vaults: Docs

Same product, four explanations. Pick your depth and skip the rest.

1. The plain-English version

Imagine an artist needs $10,000 to record their next album.

Instead of signing a label deal that takes a permanent cut of everything they ever make, they open a vault — a transparent online piggy bank. Fans deposit US dollars (in the form of USDC, a digital dollar that lives on the internet) into the vault. In return, each fan owns a small slice of the album's future revenue.

The artist also locks up some SUEDE tokens in the same vault. Think of those as a deposit — proof that the artist isn't going to take the money and ghost the project. The more SUEDE they lock, the higher their tier (Seed, Studio, Featured, Premier).

When the album makes money — streams, licensing deals, sync placements — the income flows back into the vault. Fans can pull their share out anytime by clicking Claim. They get paid in the same digital dollars they put in.

When the project term ends, the artist can request to unlock their SUEDE deposit. Suede operators check that the artist held up their end (delivered the work, kept enough SUEDE locked through the term), and approve the release.

Three places you can use this:

That's it. No middlemen taking a permanent cut. Every number visible on chain. If you want to see how it actually works under the hood, keep scrolling — the next sections get progressively nerdier.

2. The operator / PM version

Three actors

Vault lifecycle

A vault moves through five statuses. The first four are sequential; the fifth (Paused) is orthogonal — it can suspend any non-Closed state.

  1. Draft — vault deployed, no deposits, no revenue routing. Operator review state.
  2. Funding — supporters can deposit until maxRaise is hit. Artist can lock SUEDE.
  3. Active — funding window closed; revenue routes through the router; supporters claim as revenue accrues.
  4. Closed — terminal state; no further deposits or ingestion. Final claims still permissionless.
  5. Paused — emergency stop. Blocks deposits, lockSuede, and revenue ingestion. Claim path stays open.

Splits

At creation the artist sets three basis-point splits that define how incoming revenue divides. They must sum to ≤ 10000 bps (100%); anything left over stays in the vault as undistributed reserve.

Tier table

Tier is computed live from lockStrength (locked SUEDE weighted by lock duration). Defaults:

TierThreshold (SUEDE)
Seed0
Studio10,000
Featured50,000
Premier250,000

Two revenue paths

  1. Router-driven (canonical). A registry license fee in the main app is paid by an agent or licensee against a workId; the registry calls router.routeUsdcFee(workId, amount); the router looks up vaultForWork[workId], takes a platform skim (default 500 bps), and pushes the rest into the vault via vault.receiveRevenue(...). Operator wires this once per work via /vaults/admin/router.
  2. Direct push. Anyone with USDC can call vault.receiveRevenue(amount) directly. Useful for backfilling off-platform royalties, sponsor donations, or manual registry-event reconciliation. Available per-row on /vaults/admin (operator-gated UI; permissionless on chain).

Cross-chain entry

Vaults are Base-USDC-only at the contract layer. To bring funds in from any other chain, supporters route through the LI.FI widget at /swap. There's no in-vault bridge — by design, the deposit path stays atomic and audit-tight.

UI map

RouteAudienceWhat it does
/vaultsPublicLive aggregation index
/vaults/[projectId]PublicPer-vault detail + deposit + claim + lockSuede (artist-only)
/vaults/createArtistSelf-serve vault deployment
/vaults/adminOperatorStatus transitions, metadata, exits, manual revenue push
/vaults/admin/routerOperatorWire workIds → vaults, set platform skim
/swapPublicCross-chain entry into Base USDC (LI.FI)

3. The engineer version

Three contracts

ArtistVaultFactory   ── deploys + administrates ──>  ArtistVault (per project)
VaultRoyaltyRouter   ── pushes revenue       ──>  ArtistVault (per work link)

Status machine

            openFunding       activate       close
   Draft ─────────────► Funding ─────────► Active ─────► Closed
                          │                  │
                          └──── close ──────►│
                          ▲                  │
                          │   (no path)      ▼
                       Funding           Closed (terminal)

  Paused is orthogonal: pauseVault / unpauseVault from any non-terminal state
  blocks deposit / lockSuede / receiveRevenue. claim() stays open.

Reward-debt accumulator (claim math)

The claim path uses a MasterChef-style accumulator. State variables on the vault:

On deposit(amount):

minted = amount;                          // 1:1 with USDC wei (6 decimals)
shares[msg.sender]   += minted;
totalSupporterShares += minted;
totalDeposited       += amount;
rewardDebt[msg.sender] += minted * accRevenuePerShare / ACC_PRECISION;

On receiveRevenue(amount):

if (totalSupporterShares > 0) {
  accRevenuePerShare += amount * ACC_PRECISION / totalSupporterShares;
}
totalRevenueReceived += amount;
// USDC pulled from msg.sender via SafeERC20.transferFrom

On claim() (and the claimable(supporter) view):

accrued = shares[supporter] * accRevenuePerShare / ACC_PRECISION;
owed    = accrued > rewardDebt[supporter]
          ? accrued - rewardDebt[supporter]
          : 0;
rewardDebt[supporter] = accrued;          // advance to current tip
usdc.safeTransfer(msg.sender, owed);

Late entrants don't retroactively claim revenue that landed before their deposit because their rewardDebt is set to the current tip on join. Revenue that arrives while totalSupporterShares == 0 is undistributable and accumulates as vault-locked USDC; this is intentional v1 behavior (the alternative — refund or burn — adds attack surface).

Lock strength + tier

lockStrength()       = artistSuedeLocked * commitmentScore()
commitmentScore()    = f(daysLocked)         // monotonically non-decreasing
tierForStrength(s)   = 3 if s >= premier
                       2 if s >= featured
                       1 if s >= studio
                       0 otherwise

Modifier matrix (key external functions)

FunctionCaller gateState guard
vault.depositFunding, !paused, totalDeposited+amount ≤ maxRaise
vault.claimowed > 0
vault.lockSuedeonlyArtist!paused
vault.receiveRevenue!paused
vault.withdrawArtistSuedeonlyFactoryartistSuedeLocked − amount ≥ floor
vault.setStatusonlyFactory
factory.createVault!paused, projectId unused
factory.openFunding/activate/close/pause*onlyOwner
factory.authorizeArtistSuedeWithdrawalonlyOwner
router.linkWorkToVault/unlinkWork/setPlatform*onlyOwner
router.routeUsdcFeevaultForWork[workId] != 0, amount > 0

Reentrancy + token safety

Events

ContractEvent
ArtistVaultInitialized, StatusChanged, Deposited, SuedeLocked, SuedeUnlocked, RevenueReceived, Claimed, MetadataUpdated
ArtistVaultFactoryVaultCreated, TierThresholdsUpdated, ProtocolTreasuryUpdated
VaultRoyaltyRouterWorkLinked, WorkUnlinked, FeeRouted, PlatformBpsUpdated, PlatformWalletUpdated

Test coverage

33 / 33 passing in base-contracts/test/: 16 across ArtistVault (deposit, share minting, claim math, late entrants, lockSuede, withdraw with floor enforcement, pause / status guards, cap enforcement) plus 17 across VaultRoyaltyRouter (link / unlink, platform skim arithmetic incl. zero-skim, owner gating, state-change emissions, back-to-back fee routing).

Frontend integration

4. The whitepaper

Abstract

Suede Artist Vaults are a non-custodial primitive for artist-led rights factoring on Base. Each vault is a per-project on-chain escrow with three economic positions: a supporter pool that earns pro-rata USDC revenue against the project's future income, an artist position that locks SUEDE as a commitment bond and receives a configurable artist share of routed revenue, and a protocol position that takes a configurable skim. Trust is minimised: deposits and claims are permissionless; status transitions are gated by an operator role that cannot move funds arbitrarily; share accounting is enforced by a reward-debt accumulator with no privileged write paths.

Problem

Independent creators face three financing options today, all structurally hostile:

  1. Royalty advances from labels, distributors, or specialised lenders carry implicit APRs of 30–60% once the recoupable cut and term are accounted for. Worse, advances often collateralise the entire artist's catalog rather than the specific work being funded.
  2. Equity rounds dilute the creative entity in perpetuity, invert the artist's incentive toward exit-driven outcomes, and assume an institutional cap-table apparatus most independent artists don't want.
  3. Subscription / patronage generates real revenue but distributes it on a recurring basis with no commitment from either side; supporters who would happily fund the production phase have no way to translate that into ongoing share of revenue.

Vaults are the missing primitive: project-bounded, time-bounded, revenue-routing.

Mechanism

Vault formation

An artist deploys a vault by calling factory.createVault(projectId, targetRaise, maxRaise, artistRevenueBps, supporterRevenueBps, protocolFeeBps, metadataURI). projectId is a freely-chosen bytes32 (typically keccak256(slug)); targetRaise and maxRaise bound the cap; the three basis-point fields declare how routed revenue divides. The vault is born in Draft; the operator promotes to Funding after off-chain review (KYC / project-validity / tier policy).

Supporter share accounting

Deposits during Funding mint non-transferable supporter shares 1:1 with deposited USDC wei. The vault tracks a single accumulator accRevenuePerShare (scaled by ACC_PRECISION = 1e18) that is incremented on every revenue ingestion event. Claim entitlement at any tip is:

claimable(s) = max(0, shares(s) * accRevenuePerShare / ACC_PRECISION
                   - rewardDebt(s))

On deposit, rewardDebt advances to the current tip, ensuring late entrants cannot retroactively claim revenue that arrived before they joined. On claim, rewardDebt re-anchors to the current tip and the difference is paid out in USDC. This is the standard MasterChef-style accumulator, audited and battle-tested across the DeFi ecosystem; we add no novel math to that sub-component.

Revenue ingestion

Two paths feed the accumulator. The canonical path is via the VaultRoyaltyRouter: a registry workId is wired to a vault by the operator (linkWorkToVault), then any caller — including agent-commerce flows from the main app — can pay a license fee against that work via routeUsdcFee(workId, amount). The router takes a configurable platform skim (default 500 bps) to a designated platformWallet, then forwards the residual to the vault via vault.receiveRevenue(net). The fallback path is permissionless direct push to vault.receiveRevenue(amount), used by operators for backfills, sponsors for direct support, or rights holders for off-platform royalty rebates.

Artist commitment bond

Artists lock SUEDE in the same vault via lockSuede(amount). Locked SUEDE is non-circulating for the duration of the lock; it counts toward a tier ladder (Seed / Studio / Featured / Premier) with thresholds set by the factory owner. Tier influences external visibility (presentation in the index, sort priority, etc.) but does not gate the contracts themselves — every vault can transact regardless of tier.

Locked SUEDE leaves the vault only via factory.authorizeArtistSuedeWithdrawal(vault, amount, floor): the factory owner approves a specific withdrawal amount with a specific authorized floor; the vault then enforces on chain that artistSuedeLocked − amount ≥ floor before transferring SUEDE to the artist. The floor is the lever that lets the operator demand artist commitment over a project term: e.g., set floor = studioThreshold until the term completes, then drop to zero for full unlock.

Trust model

Comparable systems

SystemCustodyGranularityArtist bond
Royalty ExchangeCustodialWhole catalogNone
Audius / streaming-tokensNon-custodialPer streamImplicit (token holdings)
Royalty advances (labels)CustodialWhole careerRecoupable, not bonded
Patreon / SubstackCustodialPer periodNone
Suede VaultsNon-custodialPer projectExplicit SUEDE bond

Future work

Status

Contracts: 33 / 33 tests passing locally on Hardhat. Frontend: fully wired, all surfaces shipping at suedeai.ai. Mainnet deployment of ArtistVaultFactory, ArtistVault instances, and VaultRoyaltyRouter pending operational sign-off and the LayerZero / Stargate DVN security move from 1/1 to 2/2 on the adjacent OFT stack.

Source: base-contracts/contracts/{ArtistVaultFactory,ArtistVault,VaultRoyaltyRouter}.sol · Tests: base-contracts/test/{ArtistVault,VaultRoyaltyRouter}.test.cjs · Frontend: suede-home/src/{lib,app/vaults}/.