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:
- Marketplace Fee (20%) is deducted and sent to WasiAI
- 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.
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:
receive¶
Allows the contract to receive native tokens (not used for USDC).
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.
Events¶
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:
- Payment is sent to the model's splitter address
- Splitter accumulates USDC
distribute()is called (manually or automatically)- 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¶
- Initialization Guard: Can only be initialized once
- Fixed Split: 80% creator / 20% marketplace
- No Zero Addresses: All recipients must be valid
- Push Pattern: Funds are automatically pushed to recipients
- Anyone Can Distribute: No access control on distribute() for reliability