Skip to content
Launch App >

Technical steps to integrate and earn from the affiliate program.

  1. Choose an Affiliate Code

    Select a unique identifier (max 32 bytes):

    // Convert string to bytes
    function stringToAffiliateCode(code: string): Uint8Array {
    const encoder = new TextEncoder();
    const bytes = encoder.encode(code);
    if (bytes.length > 32) {
    throw new Error('Affiliate code too long');
    }
    // Pad to 32 bytes
    const padded = new Uint8Array(32);
    padded.set(bytes);
    return padded;
    }
    const affiliateCode = stringToAffiliateCode('your-brand');
  2. Register as Affiliate

    Call create_affiliate instruction:

    const [affiliatePda] = PublicKey.findProgramAddressSync(
    [Buffer.from('Affiliate'), affiliateCode],
    PROGRAM_ID
    );
    await program.methods
    .createAffiliate({
    affiliateCode: Array.from(affiliateCode),
    feeShareBps: 1000, // 10% of protocol fees
    })
    .accounts({
    signer: wallet.publicKey,
    affiliate: affiliatePda,
    settings: settingsPda,
    systemProgram: SystemProgram.programId,
    })
    .rpc();
  3. Create Token Accounts

    For each token you want to receive earnings in:

    const [affiliateTokenAccount] = PublicKey.findProgramAddressSync(
    [
    affiliatePda.toBuffer(),
    TOKEN_PROGRAM_ID.toBuffer(),
    mint.toBuffer(),
    ],
    ASSOCIATED_TOKEN_PROGRAM_ID
    );
    await program.methods
    .createAffiliateTokenAccount({})
    .accounts({
    signer: wallet.publicKey,
    affiliate: affiliatePda,
    affiliateTokenAccount,
    mint,
    tokenProgram: TOKEN_PROGRAM_ID,
    associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
    systemProgram: SystemProgram.programId,
    })
    .rpc();
  4. Pass Affiliate Code in Transactions

    Include your affiliate PDA in deposit/withdraw transactions:

    // When building deposit instruction
    await program.methods
    .deposit({
    commitment: Array.from(commitment),
    amount: new BN(amount),
    })
    .accounts({
    // ... standard accounts
    affiliate: affiliatePda, // Your affiliate account
    })
    .rpc();
  5. Withdraw Earnings

    Claim accumulated fees:

    await program.methods
    .withdrawAffiliate()
    .accounts({
    signer: wallet.publicKey,
    affiliate: affiliatePda,
    affiliateTokenAccount,
    destinationTokenAccount: yourWalletTokenAccount,
    tokenProgram: TOKEN_PROGRAM_ID,
    })
    .rpc();
import { Program, AnchorProvider, BN } from '@coral-xyz/anchor';
import { PublicKey, SystemProgram } from '@solana/web3.js';
import { TOKEN_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID } from '@solana/spl-token';
const PROGRAM_ID = new PublicKey('FGKoWNsvTTDCGW9JyR2DJWNzSXpejWk7yXcKsFFj9GQp');
class AffiliateManager {
private program: Program;
private affiliateCode: Uint8Array;
private affiliatePda: PublicKey;
constructor(program: Program, affiliateCodeString: string) {
this.program = program;
this.affiliateCode = this.stringToBytes(affiliateCodeString);
[this.affiliatePda] = PublicKey.findProgramAddressSync(
[Buffer.from('Affiliate'), this.affiliateCode],
PROGRAM_ID
);
}
private stringToBytes(str: string): Uint8Array {
const bytes = new TextEncoder().encode(str);
const padded = new Uint8Array(32);
padded.set(bytes.slice(0, 32));
return padded;
}
async register(feeShareBps: number = 1000): Promise<string> {
const [settings] = PublicKey.findProgramAddressSync(
[Buffer.from('Settings')],
PROGRAM_ID
);
const tx = await this.program.methods
.createAffiliate({
affiliateCode: Array.from(this.affiliateCode),
feeShareBps,
})
.accounts({
signer: this.program.provider.publicKey,
affiliate: this.affiliatePda,
settings,
systemProgram: SystemProgram.programId,
})
.rpc();
return tx;
}
async createTokenAccount(mint: PublicKey): Promise<string> {
const [tokenAccount] = PublicKey.findProgramAddressSync(
[
this.affiliatePda.toBuffer(),
TOKEN_PROGRAM_ID.toBuffer(),
mint.toBuffer(),
],
ASSOCIATED_TOKEN_PROGRAM_ID
);
const tx = await this.program.methods
.createAffiliateTokenAccount({})
.accounts({
signer: this.program.provider.publicKey,
affiliate: this.affiliatePda,
affiliateTokenAccount: tokenAccount,
mint,
tokenProgram: TOKEN_PROGRAM_ID,
associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
systemProgram: SystemProgram.programId,
})
.rpc();
return tx;
}
async getEarnings(): Promise<{ total: BN; pending: BN }> {
const account = await this.program.account.affiliate.fetch(this.affiliatePda);
return {
total: account.totalEarnings,
pending: account.pendingWithdraw,
};
}
async withdraw(mint: PublicKey, destination: PublicKey): Promise<string> {
const [tokenAccount] = PublicKey.findProgramAddressSync(
[
this.affiliatePda.toBuffer(),
TOKEN_PROGRAM_ID.toBuffer(),
mint.toBuffer(),
],
ASSOCIATED_TOKEN_PROGRAM_ID
);
const tx = await this.program.methods
.withdrawAffiliate()
.accounts({
signer: this.program.provider.publicKey,
affiliate: this.affiliatePda,
affiliateTokenAccount: tokenAccount,
destinationTokenAccount: destination,
tokenProgram: TOKEN_PROGRAM_ID,
})
.rpc();
return tx;
}
getAffiliatePda(): PublicKey {
return this.affiliatePda;
}
}
// Usage
const affiliate = new AffiliateManager(program, 'my-app');
await affiliate.register(1000); // 10% fee share
await affiliate.createTokenAccount(usdcMint);
// Check earnings
const { pending } = await affiliate.getEarnings();
console.log('Pending:', pending.toString());
// Withdraw
if (pending.gt(new BN(0))) {
await affiliate.withdraw(usdcMint, myWalletTokenAccount);
}
PracticeReason
Store affiliate code securelyLosing it means losing access to earnings
Create token accounts proactivelyFor all tokens your users might use
Monitor earnings regularlyCatch any issues early
Withdraw periodicallyDon’t let large balances accumulate
ErrorCauseSolution
AffiliateAlreadyExistsCode already registeredChoose different code
InvalidFeeShareFee share out of rangeUse 0-10000 bps
NoEarningsToWithdrawZero balanceWait for user activity
TokenAccountNotFoundMissing token accountCreate it first