Skip to content

ModelSplitter

The ModelSplitter contract handles automatic revenue distribution for a single model. It receives USDC payments (from x402 inference or license sales) and splits them between the creator and marketplace.


Contract Information

Property Value
Deployed Via SplitterFactory (EIP-1167 clones)
Solidity Version ^0.8.24
License MIT
Pattern Initializable (proxy-compatible)

Overview

Each model on WasiAI has its own ModelSplitter contract. When payments are received:

  1. Marketplace Fee (20%) is deducted and sent to WasiAI
  2. Creator Share (80%) goes to the model creator
Payment Received ($1.00 USDC)
┌─────────────────────────────────────┐
│         ModelSplitter               │
│                                     │
│  Marketplace Fee (20%): $0.20 ─────►  WasiAI Wallet
│  Creator Share (80%): $0.80 ───────►  Creator Wallet
│                                     │
└─────────────────────────────────────┘

State Variables

address public usdc;              // USDC token address
address public creator;           // Model creator
address public marketplaceWallet; // WasiAI fee recipient
uint256 public marketplaceBps;    // Marketplace fee (2000 = 20%)
bool public initialized;          // Initialization flag

Functions

Initialization

initialize

Called by SplitterFactory when deploying a clone.

function initialize(
    address _usdc,
    address _creator,
    address _marketplaceWallet,
    uint256 _marketplaceBps
) external

Parameters:

Name Type Description
_usdc address USDC token address
_creator address Model creator
_marketplaceWallet address WasiAI fee recipient
_marketplaceBps uint256 Marketplace fee (2000 = 20%)

Requirements: - Can only be called once - All addresses must be non-zero - BPS values must be within limits


Revenue Distribution

distribute

Distributes all USDC in the contract to recipients.

function distribute() external

Distribution Logic:

uint256 balance = IERC20(usdc).balanceOf(address(this));

// 1. Marketplace fee (20%)
uint256 marketplaceFee = (balance * marketplaceBps) / MAX_BPS;
IERC20(usdc).transfer(marketplaceWallet, marketplaceFee);

// 2. Creator gets the rest (80%)
uint256 creatorShare = balance - marketplaceFee;
IERC20(usdc).transfer(creator, creatorShare);

Example:

// Anyone can call distribute to trigger payout
await modelSplitter.distribute()

receive

Allows the contract to receive native tokens (not used for USDC).

receive() external payable

Configuration

getConfig

Returns the current splitter configuration.

function getConfig() external view returns (
    address _creator,
    address _marketplaceWallet,
    uint256 _marketplaceBps
)

getPendingBalance

Returns the USDC balance waiting to be distributed.

function getPendingBalance() external view returns (uint256)

Events

event Distributed(
    uint256 total,
    uint256 marketplaceFee,
    uint256 creatorShare
);

Revenue Split

All payments are split 80% to Creator / 20% to Marketplace:

Payment Marketplace (20%) Creator (80%)
$1.00 $0.20 $0.80
$10.00 $2.00 $8.00
$100.00 $20.00 $80.00

Integration with x402

When a user pays for inference via x402:

  1. Payment is sent to the model's splitter address
  2. Splitter accumulates USDC
  3. distribute() is called (manually or automatically)
  4. Funds flow to creator (80%) and marketplace (20%)

Payment Flow:

User signs USDC authorization
Facilitator calls transferWithAuthorization()
USDC transferred to ModelSplitter
distribute() called
         ├──► Marketplace Wallet (20%)
         └──► Creator Wallet (80%)


Integration Examples

Check Pending Balance

const balance = await publicClient.readContract({
  address: splitterAddress,
  abi: ModelSplitterABI,
  functionName: 'getPendingBalance',
  args: []
})

console.log(`Pending: ${balance / 1e6} USDC`)

Trigger Distribution

const hash = await walletClient.writeContract({
  address: splitterAddress,
  abi: ModelSplitterABI,
  functionName: 'distribute',
  args: []
})

Get Configuration

const config = await publicClient.readContract({
  address: splitterAddress,
  abi: ModelSplitterABI,
  functionName: 'getConfig',
  args: []
})

console.log({
  creator: config._creator,
  marketplaceBps: Number(config._marketplaceBps) / 100 + '%'
})

Security Considerations

  1. Initialization Guard: Can only be initialized once
  2. Fixed Split: 80% creator / 20% marketplace
  3. No Zero Addresses: All recipients must be valid
  4. Push Pattern: Funds are automatically pushed to recipients
  5. Anyone Can Distribute: No access control on distribute() for reliability