Mesh LogoMesh

Payment Splitter

Automatically split payments equally among multiple recipients

The Payment Splitter contract distributes funds equally among a predefined list of payees. Send lovelace to the contract, and any payee can trigger a payout that splits the balance evenly among all recipients.

Use Cases

  • Shared project donation addresses
  • Revenue splitting for collaborators
  • Team payment distribution
  • Royalty sharing agreements
  • Automated expense splitting

Quick Start

Install the Package

npm install @meshsdk/contract @meshsdk/core

Initialize the Contract

import { MeshPaymentSplitterContract } from "@meshsdk/contract";
import { BlockfrostProvider, MeshTxBuilder } from "@meshsdk/core";

const provider = new BlockfrostProvider("<Your-API-Key>");

const meshTxBuilder = new MeshTxBuilder({
  fetcher: provider,
  submitter: provider,
});

const payees = [
  "addr_test1qp...alice_address",
  "addr_test1qp...bob_address",
  "addr_test1qp...charlie_address",
  "addr_test1qp...diana_address",
];

const contract = new MeshPaymentSplitterContract(
  {
    mesh: meshTxBuilder,
    fetcher: provider,
    wallet: wallet,
    networkId: 0,
  },
  payees
);

Configuration Parameters

ParameterTypeDescription
payeesstring[]Array of Bech32 addresses that receive payments

Contract Logic

The Payment Splitter enforces equal distribution:

RuleDescription
Fixed PayeesRecipients are defined at contract initialization
Equal SplitAll payees receive exactly the same amount
Payee TriggerOnly a payee can trigger the payout
Full DistributionThe entire contract balance is distributed

Split Calculation

amount_per_payee = total_balance / number_of_payees

For example, with 4 payees and 100 ADA in the contract:

  • Each payee receives: 100 ADA / 4 = 25 ADA

Validation Rules

  1. Transaction must be signed by one of the payees
  2. All outputs must go to payee addresses
  3. All payees must receive equal amounts
  4. The sum must equal the contract balance (minus fees)

Available Actions

Send Lovelace to Splitter

Deposit lovelace into the payment splitter contract.

Method Signature

contract.sendLovelaceToSplitter(lovelaceAmount: number): Promise<string>

Parameters

ParameterTypeDescription
lovelaceAmountnumberAmount of lovelace to send to the contract

Code Example

import { MeshPaymentSplitterContract } from "@meshsdk/contract";
import { BlockfrostProvider, MeshTxBuilder } from "@meshsdk/core";

// Initialize provider and contract
const provider = new BlockfrostProvider("<Your-API-Key>");

const meshTxBuilder = new MeshTxBuilder({
  fetcher: provider,
  submitter: provider,
});

const payees = [
  "addr_test1qp...alice",
  "addr_test1qp...bob",
  "addr_test1qp...charlie",
  "addr_test1qp...diana",
];

const contract = new MeshPaymentSplitterContract(
  {
    mesh: meshTxBuilder,
    fetcher: provider,
    wallet: wallet,
    networkId: 0,
  },
  payees
);

// Send 20 ADA to the splitter (will be split 4 ways = 5 ADA each)
const lovelaceAmount = 20000000; // 20 ADA

const tx = await contract.sendLovelaceToSplitter(lovelaceAmount);
const signedTx = await wallet.signTx(tx);
const txHash = await wallet.submitTx(signedTx);

console.log("Funds deposited. Transaction hash:", txHash);

What Happens on Success

  • Lovelace transfers from your wallet to the contract address
  • Funds accumulate until a payee triggers payout
  • Anyone can send funds to the contract (not just payees)

Trigger Payout

Distribute the contract balance equally among all payees.

Method Signature

contract.triggerPayout(): Promise<string>

Parameters

None. The contract distributes its entire balance.

Code Example

import { MeshPaymentSplitterContract } from "@meshsdk/contract";
import { BlockfrostProvider, MeshTxBuilder } from "@meshsdk/core";

// Initialize provider and contract (must be a payee's wallet)
const provider = new BlockfrostProvider("<Your-API-Key>");

const meshTxBuilder = new MeshTxBuilder({
  fetcher: provider,
  submitter: provider,
});

const payees = [
  "addr_test1qp...alice",
  "addr_test1qp...bob",
  "addr_test1qp...charlie",
  "addr_test1qp...diana",
];

const contract = new MeshPaymentSplitterContract(
  {
    mesh: meshTxBuilder,
    fetcher: provider,
    wallet: payeeWallet, // Must be one of the payees
    networkId: 0,
  },
  payees
);

// Trigger the payout
const tx = await contract.triggerPayout();
const signedTx = await payeeWallet.signTx(tx, true);
const txHash = await payeeWallet.submitTx(signedTx);

console.log("Payout triggered. Transaction hash:", txHash);

What Happens on Success

  • Contract balance is divided equally among all payees
  • Each payee receives their share
  • Contract balance becomes zero
  • New deposits can be made and split again

Full Working Example

import { MeshPaymentSplitterContract } from "@meshsdk/contract";
import { BlockfrostProvider, MeshTxBuilder } from "@meshsdk/core";
import { MeshCardanoBrowserWallet } from "@meshsdk/wallet";

async function paymentSplitterDemo() {
  // Connect wallet
  const wallet = await MeshCardanoBrowserWallet.enable("eternl");

  // Initialize provider
  const provider = new BlockfrostProvider("<Your-API-Key>");

  const meshTxBuilder = new MeshTxBuilder({
    fetcher: provider,
    submitter: provider,
  });

  // Define payees (4 team members)
  const payees = [
    "addr_test1qp...alice",
    "addr_test1qp...bob",
    "addr_test1qp...charlie",
    "addr_test1qp...diana",
  ];

  // Initialize contract
  const contract = new MeshPaymentSplitterContract(
    {
      mesh: meshTxBuilder,
      fetcher: provider,
      wallet: wallet,
      networkId: 0,
    },
    payees
  );

  // Step 1: Donor sends 16 ADA to the splitter
  const depositTx = await contract.sendLovelaceToSplitter(16000000);
  const signedDepositTx = await wallet.signTx(depositTx);
  const depositTxHash = await wallet.submitTx(signedDepositTx);

  console.log("Deposited:", depositTxHash);

  // Wait for confirmation
  await new Promise((resolve) => setTimeout(resolve, 60000));

  // Step 2: A payee triggers the payout (each gets 4 ADA)
  // In production, switch to a payee's wallet
  const payoutTx = await contract.triggerPayout();
  const signedPayoutTx = await wallet.signTx(payoutTx, true);
  const payoutTxHash = await wallet.submitTx(signedPayoutTx);

  console.log("Payout triggered:", payoutTxHash);
  console.log("Each payee receives: 4 ADA");
}

paymentSplitterDemo().catch(console.error);

Accumulating Donations

The contract can receive multiple deposits before triggering a payout:

// Donation 1: 10 ADA
await contract.sendLovelaceToSplitter(10000000);

// Donation 2: 5 ADA
await contract.sendLovelaceToSplitter(5000000);

// Donation 3: 5 ADA
await contract.sendLovelaceToSplitter(5000000);

// Total in contract: 20 ADA
// Trigger payout: each of 4 payees gets 5 ADA
await contract.triggerPayout();

Minimum Payout Considerations

Ensure the contract balance is large enough to cover:

  1. Minimum UTxO value for each output (approximately 1 ADA per payee)
  2. Transaction fees
const minPerPayee = 1000000; // 1 ADA minimum
const numPayees = 4;
const minDeposit = minPerPayee * numPayees + 500000; // 4.5 ADA minimum

// Always deposit at least this amount
await contract.sendLovelaceToSplitter(minDeposit);

Troubleshooting

Common Errors

ErrorCauseSolution
Script validation failedUnequal distributionContract enforces equal splits; check calculations
Missing required signerNon-payee triggeringOnly payees can trigger payouts
Insufficient fundsBalance too lowEnsure enough funds for all payees + fees
Output below minimumBalance divided too smallDeposit more funds before payout

Debugging Tips

  1. Verify payee list: Ensure all payee addresses are correct and match initialization
  2. Check wallet is a payee: The wallet triggering payout must be in the payee list
  3. Calculate minimum deposit: (min_utxo * num_payees) + fees
  4. Use partial signing: Always pass true to signTx() for payout transactions

Calculating Split Amounts

const contractBalance = 20000000; // 20 ADA
const numPayees = 4;
const estimatedFees = 200000; // ~0.2 ADA

const distributableAmount = contractBalance - estimatedFees;
const amountPerPayee = Math.floor(distributableAmount / numPayees);

console.log(`Each payee receives: ${amountPerPayee / 1000000} ADA`);
// Output: Each payee receives: 4.95 ADA

On this page