Installation
Install the Fraction SDK using your preferred package manager:Copy
pnpm install @sendaifun/fraction
Quick Start
Initialize Client
Copy
import { Fraction } from '@sendaifun/fraction';
import { Connection, Keypair } from '@solana/web3.js';
const connection = new Connection('https://api.devnet.solana.com');
const payer = Keypair.generate();
// Initialize client
const client = new Fraction(
'https://api.devnet.solana.com', // RPC endpoint
payer.publicKey // Transaction payer
);
Create Revenue Split Configuration
Copy
const participants = [
{ wallet: teamMember1.publicKey, shareBps: 4000 }, // 40%
{ wallet: teamMember2.publicKey, shareBps: 3000 }, // 30%
{ wallet: teamMember3.publicKey, shareBps: 2000 }, // 20%
{ wallet: teamMember4.publicKey, shareBps: 1000 }, // 10%
];
const { tx, fractionConfigPda } = await client.createFraction({
participants,
authority: authority.publicKey,
name: 'team-revenue-split',
botWallet: distributionAgent.publicKey
});
Execute Distribution
Copy
// Agent triggers distribution
const tx = await client.claimAndDistribute(
fractionConfigPda, // Configuration account
usdcMint // Token mint to distribute
);
API Reference
Client Class
Constructor
Copy
new Fraction(rpc?: string, payer?: PublicKey)
RPC endpoint URL (defaults to mainnet-beta)
Transaction fee payer (only required for versioned transactions)
Methods
Show createFraction
Show createFraction
Configuration for the new fraction setup
Copy
type CreatorFractionInputArgs = {
participants: Participant[];
authority: PublicKey;
name?: string;
botWallet: PublicKey;
}
Promise<{ tx: Transaction | VersionedTransaction, fractionConfigPda: PublicKey }>
Creates a new revenue split configuration with the specified participants and settings.Show updateFraction
Show updateFraction
The fraction configuration account to update
Updated configuration parameters
Copy
type UpdateFractionInputArgs = {
participants: Participant[];
botWallet?: PublicKey;
}
Promise<Transaction | VersionedTransaction>
Updates an existing fraction configuration with new participants or agent wallet.Show claimAndDistribute
Show claimAndDistribute
State Queries
Show getFractionsByParticipant
Show getFractionsByParticipant
Wallet address of the participant
Promise<FractionConfig[]>
Retrieves all fraction configurations where the specified wallet is a participant.Show getFractionsByConfig
Show getFractionsByConfig
The fraction configuration account
Promise<FractionConfig>
Retrieves the details of a specific fraction configuration account.Show getFractionBalance
Show getFractionBalance
The fraction configuration account
Promise<FractionConfig>
Gets the current treasury balance for the specified configuration.Advanced Usage
Low-Level Instructions
For advanced users who need fine-grained control over transaction building:Copy
import { createFractionIx, getProgram } from '@sendaifun/fraction';
const program = getProgram(connection);
// Create instruction
const { ix, fractionConfigPda } = await createFractionIx(program, {
participants: participants,
authority: authority.publicKey,
botWallet: agent.publicKey
});
// Build composite transaction
const tx = new Transaction()
.add(setupInstruction)
.add(ix)
.add(followupInstruction);
Treasury Management
Calculate and manage treasury accounts:Copy
import { getAssociatedTokenAddressSync } from '@solana/spl-token';
// Calculate treasury address
const treasuryAddress = getAssociatedTokenAddressSync(
tokenMint, // Token to be distributed
fractionConfigPda, // Treasury owner (PDA)
true // Allow off-curve addresses
);
// Fund treasury
await transfer(
connection,
payer,
sourceTokenAccount,
treasuryAddress,
authority,
amount
);
Examples
Enterprise Revenue Distribution
Copy
import { Fraction } from '@sendaifun/fraction';
import { Connection, Keypair } from '@solana/web3.js';
const connection = new Connection('https://api.mainnet-beta.solana.com');
const client = new Fraction(connection.rpcEndpoint, authority.publicKey);
// Define revenue allocation
const participants = [
{ wallet: founder.publicKey, shareBps: 4000 }, // 40% founder
{ wallet: team.publicKey, shareBps: 3000 }, // 30% team
{ wallet: investors.publicKey, shareBps: 2000 }, // 20% investors
{ wallet: operations.publicKey, shareBps: 1000 } // 10% operations
];
// Deploy configuration
const { tx, fractionConfigPda } = await client.createFraction({
participants,
authority: company.publicKey,
name: 'quarterly-revenue-2024',
botWallet: automatedAgent.publicKey
});
// Sign and submit
await connection.sendTransaction(tx, [authority]);
Multi-Token Distribution
Copy
const tokens = [
{ mint: usdcMint, name: 'USDC Revenue' },
{ mint: solMint, name: 'SOL Rewards' },
{ mint: projectToken, name: 'Token Emissions' }
];
// Distribute multiple tokens using same configuration
for (const token of tokens) {
const distributionTx = await client.claimAndDistribute(
fractionConfigPda,
token.mint
);
await connection.sendTransaction(distributionTx, [agent]);
console.log(`Distributed ${token.name}`);
}
Dynamic Updates
Copy
// Quarterly rebalancing
const newAllocation = [
{ wallet: founder.publicKey, shareBps: 3500 }, // Reduced to 35%
{ wallet: team.publicKey, shareBps: 3500 }, // Increased to 35%
{ wallet: investors.publicKey, shareBps: 2000 }, // Maintained 20%
{ wallet: operations.publicKey, shareBps: 1000 } // Maintained 10%
];
const updateTx = await client.updateFraction(fractionConfigPda, {
participants: newAllocation,
botWallet: newAgent.publicKey // Optional: update agent
});
await connection.sendTransaction(updateTx, [authority]);
Error Handling
Common Validation Errors
The SDK implements client-side validation with clear error messages:Error | Description |
---|---|
InvalidShareDistribution | Participant shares don’t sum to 10,000 BPS |
NoFundsToDistribute | Treasury account is empty |
DuplicateParticipantWallet | Same wallet appears multiple times |
BotWalletConflict | Agent wallet matches participant wallet |
SystemProgramParticipant | System program cannot have non-zero shares |
Error Handling Pattern
Copy
async function safeDistribution(config: PublicKey, mint: PublicKey) {
try {
const tx = await client.claimAndDistribute(config, mint);
const signature = await connection.sendTransaction(tx, [agent]);
return { success: true, signature };
} catch (error) {
if (error.message.includes('NoFundsToDistribute')) {
return { success: false, reason: 'Treasury empty' };
}
throw error; // Re-throw unexpected errors
}
}
Type Definitions
Core Types
Copy
type Participant = {
wallet: PublicKey;
shareBps: number; // 0-10,000 basis points (0-100%)
}
type FractionConfig = {
authority: PublicKey;
name: string;
participants: Participant[];
botWallet: PublicKey;
incentiveBps: number;
bump: number;
}
Basis Points (BPS): Share allocations use basis points where 10,000 BPS = 100%. For example, 4000 BPS = 40%.
Configuration Derivation
Copy
import { PublicKey } from '@solana/web3.js';
// Derive configuration PDA
const [configPda, bump] = PublicKey.findProgramAddressSync(
[
Buffer.from("fraction_config"),
authority.toBuffer(),
Buffer.from(configurationName)
],
programId
);
Program IDL
The complete Interface Description Language (IDL) for the Fraction protocol:Copy
{
"address": "FracVQuBhSeBvbw1qNrJKkDmcdPcFYWdneoKbJa3HMrj",
"metadata": {
"name": "fraction",
"version": "0.1.0",
"spec": "0.1.0",
"description": "Created with Anchor"
},
"instructions": [
{
"name": "claim_and_distribute",
"discriminator": [3],
"accounts": [
{ "name": "bot_wallet", "writable": true, "signer": true },
{ "name": "authority" },
{
"name": "fraction_config",
"writable": true,
"pda": {
"seeds": [
{
"kind": "const",
"value": [
102, 114, 97, 99, 116, 105, 111, 110, 95, 99, 111, 110, 102,
105, 103
]
},
{
"kind": "account",
"path": "fraction_config.authority",
"account": "FractionConfig"
},
{
"kind": "account",
"path": "fraction_config.name",
"account": "FractionConfig"
}
]
}
},
{
"name": "treasury",
"writable": true,
"pda": {
"seeds": [
{ "kind": "account", "path": "fraction_config" },
{ "kind": "account", "path": "token_program" },
{ "kind": "account", "path": "treasury_mint" }
],
"program": {
"kind": "const",
"value": [
140, 151, 37, 143, 78, 36, 137, 241, 187, 61, 16, 41, 20, 142,
13, 131, 11, 90, 19, 153, 218, 255, 16, 132, 4, 142, 123, 216,
219, 233, 248, 89
]
}
}
},
{ "name": "treasury_mint" },
{ "name": "bot_token_account", "writable": true },
{ "name": "participant_token_account_0", "writable": true },
{ "name": "participant_token_account_1", "writable": true },
{ "name": "participant_token_account_2", "writable": true },
{ "name": "participant_token_account_3", "writable": true },
{ "name": "participant_token_account_4", "writable": true },
{ "name": "token_program" },
{
"name": "system_program",
"address": "11111111111111111111111111111111"
}
],
"args": []
},
{
"name": "initialize_fraction",
"discriminator": [1],
"accounts": [
{ "name": "authority", "writable": true, "signer": true },
{
"name": "fraction_config",
"writable": true,
"pda": {
"seeds": [
{
"kind": "const",
"value": [
102, 114, 97, 99, 116, 105, 111, 110, 95, 99, 111, 110, 102,
105, 103
]
},
{ "kind": "account", "path": "authority" },
{ "kind": "arg", "path": "name" }
]
}
},
{
"name": "system_program",
"address": "11111111111111111111111111111111"
}
],
"args": [
{ "name": "name", "type": "string" },
{
"name": "participants",
"type": { "array": [{ "defined": { "name": "Participant" } }, 5] }
},
{ "name": "bot_wallet", "type": "pubkey" }
]
},
{
"name": "update_fraction",
"discriminator": [2],
"accounts": [
{
"name": "authority",
"signer": true,
"relations": ["fraction_config"]
},
{
"name": "fraction_config",
"writable": true,
"pda": {
"seeds": [
{
"kind": "const",
"value": [
102, 114, 97, 99, 116, 105, 111, 110, 95, 99, 111, 110, 102,
105, 103
]
},
{
"kind": "account",
"path": "fraction_config.authority",
"account": "FractionConfig"
},
{
"kind": "account",
"path": "fraction_config.name",
"account": "FractionConfig"
}
]
}
}
],
"args": [
{
"name": "participants",
"type": { "array": [{ "defined": { "name": "Participant" } }, 5] }
},
{ "name": "bot_wallet", "type": "pubkey" }
]
}
],
"accounts": [{ "name": "FractionConfig", "discriminator": [1] }],
"errors": [
{
"code": 6000,
"name": "InvalidShareDistribution",
"msg": "Invalid share distribution - must sum to 10,000"
},
{ "code": 6001, "name": "NameTooLong", "msg": "Name too long" },
{
"code": 6002,
"name": "NoFundsToDistribute",
"msg": "No funds to distribute"
},
{
"code": 6003,
"name": "ArithmeticOverflow",
"msg": "Arithmetic overflow"
},
{
"code": 6004,
"name": "DuplicateParticipantWallet",
"msg": "Duplicate participant wallet detected"
},
{
"code": 6005,
"name": "BotWalletConflict",
"msg": "Bot wallet cannot be the same as any participant wallet"
},
{
"code": 6006,
"name": "InvalidAuthority",
"msg": "Invalid authority provided"
},
{ "code": 6007, "name": "InvalidBot", "msg": "Invalid bot wallet" },
{
"code": 6008,
"name": "SystemProgramParticipant",
"msg": "System program cannot be a participant wallet"
},
{ "code": 6009, "name": "InvalidAccount", "msg": "Invalid account owner" }
],
"types": [
{
"name": "FractionConfig",
"type": {
"kind": "struct",
"fields": [
{ "name": "authority", "type": "pubkey" },
{ "name": "name", "type": "string" },
{
"name": "participants",
"type": { "array": [{ "defined": { "name": "Participant" } }, 5] }
},
{ "name": "bot_wallet", "type": "pubkey" },
{ "name": "incentive_bps", "type": "u8" },
{ "name": "bump", "type": "u8" }
]
}
},
{
"name": "Participant",
"type": {
"kind": "struct",
"fields": [
{ "name": "wallet", "type": "pubkey" },
{ "name": "share_bps", "type": "u16" }
]
}
}
]
}
Program Address: The Fraction protocol is deployed at
Ck2PtB73t36kjk4mLUztwsBV9jvq7q3mGfSNmQevwFgg
. This IDL can be used with Anchor clients or other Solana development tools for direct program interaction.Best Practices
Share Distribution: Always ensure participant shares sum to exactly 10,000 BPS (100%) to avoid validation errors.
Agent Selection: Choose reliable agents for distribution triggers. Consider using services like Clockwork for automated scheduling.
Authority Security: The authority can update configurations and should use secure key management practices.
Multi-Token Support: The same configuration can distribute different SPL tokens - just call
claimAndDistribute
with different mint addresses.