Page cover

Revenue Splitter: Automated Revenue Distribution

1.1 Revenue Splitter Overview

Revenue Splitter tool in the CapsureLabs platform allows creators to automate revenue distribution among contributors, collaborators, or stakeholders according to pre-defined rules. By leveraging smart contracts, this tool provides a transparent and efficient mechanism to split income based on roles or shares, ensuring that all collaborators are compensated fairly and automatically upon receiving funds.


1.2 Key Smart Contract Features for Revenue Splitting

  • Roles and Percentages: Define roles (e.g., “Creator,” “Developer,” “Marketer”) and their associated percentages of total revenue.

  • Automatic Splitting: Funds are automatically divided according to roles when received.

  • Withdrawals: Each collaborator can withdraw their allocated portion based on the defined role percentages.

  • Event Logging: Transactions are logged for auditing purposes.


1.3 Smart Contract

Below is a sample Solidity contract that implements role-based revenue splitting. This contract defines each collaborator’s role, their revenue percentage, and allows them to withdraw their allocated revenue.

RevenueSplitter.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract RevenueSplitter {
    struct Recipient {
        uint256 share;            // Share percentage (e.g., 30 means 30%)
        uint256 balance;          // Balance available for withdrawal
    }

    mapping(address => Recipient) public recipients;
    address[] public recipientAddresses;
    uint256 public totalShares;

    event RevenueReceived(uint256 amount);
    event Withdrawn(address indexed recipient, uint256 amount);

    modifier onlyRecipient() {
        require(recipients[msg.sender].share > 0, "Not an authorized recipient");
        _;
    }

    constructor(address[] memory _recipients, uint256[] memory _shares) {
        require(_recipients.length == _shares.length, "Recipients and shares length mismatch");

        for (uint256 i = 0; i < _recipients.length; i++) {
            recipients[_recipients[i]] = Recipient({
                share: _shares[i],
                balance: 0
            });
            recipientAddresses.push(_recipients[i]);
            totalShares += _shares[i];
        }
    }

    // Receive funds and distribute based on shares
    receive() external payable {
        require(msg.value > 0, "No funds sent");
        uint256 totalAmount = msg.value;
        emit RevenueReceived(totalAmount);

        for (uint256 i = 0; i < recipientAddresses.length; i++) {
            address recipientAddr = recipientAddresses[i];
            uint256 recipientShare = (totalAmount * recipients[recipientAddr].share) / totalShares;
            recipients[recipientAddr].balance += recipientShare;
        }
    }

    // Withdraw funds allocated to the caller
    function withdraw() external onlyRecipient {
        uint256 amount = recipients[msg.sender].balance;
        require(amount > 0, "No balance available for withdrawal");

        recipients[msg.sender].balance = 0;
        (bool success, ) = msg.sender.call{value: amount}("");
        require(success, "Transfer failed");

        emit Withdrawn(msg.sender, amount);
    }

    // Get recipient share percentage
    function getShare(address _recipient) public view returns (uint256) {
        return recipients[_recipient].share;
    }

    // Get recipient balance available for withdrawal
    function getBalance(address _recipient) public view returns (uint256) {
        return recipients[_recipient].balance;
    }
}

1.4 Usage and Deployment

Initializing the Contract

To deploy this contract, initialize with:

  • A list of recipient addresses.

  • A list of corresponding shares for each recipient.

// Deploy contract with recipients and shares
address[] memory addresses = [address1, address2, address3];
uint256[] memory shares = [50, 30, 20]; // Totals to 100%
RevenueSplitter splitter = new RevenueSplitter(addresses, shares);

Receiving and Distributing Revenue

When funds are sent to the contract address, they are distributed automatically to each recipient’s balance based on their share.

// Send funds to contract (distributes automatically)
address(splitter).transfer(amount);

Withdrawing Funds

Each recipient can call the withdraw() function to claim their balance.

// Recipient calls to withdraw funds
splitter.withdraw();

Viewing Allocation

Each recipient’s share and balance can be viewed with getShare() and getBalance() functions, respectively.

// Check recipient’s share and balance
splitter.getShare(recipientAddress);
splitter.getBalance(recipientAddress);

1.5 Best Practices and Security Considerations

  1. Accurate Role Definition: Ensure roles and shares add up correctly to prevent errors in allocation.

  2. Avoid Overflows: Use safe math operations if Solidity <0.8 is in use to avoid overflow errors.

  3. Access Control: Only allow recipients to withdraw their allocated balance.

  4. Event Logging: Use emit events to log deposits and withdrawals for clear transaction records.

  5. Testing: Thoroughly test for various scenarios, especially with multiple recipients or varying balances.

Last updated