Skip to main content
Create your own

Dividend Distribution with Pull-Over-Push for Enhanced Security

Welcome back. In our previous lessons, we focused on building the essential compliance and administrative controls for our SecurityToken, culminating in the implementation of a forcedTransfer function. With these foundational safety features in place, we can now turn our attention to one of the primary functions of a security: distributing profits to its holders.

This lesson is dedicated to designing a dividend distribution mechanism. Your experience with asset management software has likely exposed you to the complexities of calculating and processing periodic payouts. On the blockchain, these challenges are compounded by gas costs and unique security vulnerabilities. Our goal is to architect a system that is not only correct in its accounting but also secure and efficient in the distributed environment of Ethereum.

We will tackle the learning outcome of designing a dividend model using the pull-over-push pattern. This industry-standard approach avoids the pitfalls of naive implementations and forms the backbone of most on-chain value distribution systems. We will explore the architectural choices, the accounting logic, and the critical security considerations needed before writing a single line of Solidity code.

The Core Problem: Why Pushing Dividends Fails

The most intuitive way to pay dividends would be for the contract to iterate through a list of all token holders and send each their respective share. This is known as a "push" system. In traditional software, this is a standard batch process. On a blockchain, however, this approach is fundamentally broken for several reasons:

  • Gas Limits: A transaction can only consume a finite amount of gas. If there are thousands of token holders, the gas required to loop through them all and execute a transfer for each would exceed the block gas limit, causing the entire transaction to fail.
  • Transaction Failure: If a single transfer fails (e.g., to a contract that cannot receive tokens), the entire dividend distribution transaction would revert. This would lock up the process and require complex, manual intervention.
  • Cost: The entity initiating the distribution would bear the enormous and unpredictable gas cost for every single holder's transfer.

To solve this, the standard on-chain pattern is to invert the responsibility.

The Solution: The "Pull" Pattern

Instead of the contract "pushing" funds out to everyone, token holders will "pull" their funds from the contract. This is the essence of the pull-over-push pattern.

The workflow is as follows:

  1. An administrator deposits the total dividend amount (e.g., in a stablecoin like USDC) into a designated contract or fund pool.
  2. The contract records this deposit and makes it available for withdrawal.
  3. Each token holder becomes responsible for calling a claim or withdraw function to receive their pro-rata share.

This design elegantly solves all the problems of the push model: gas costs are shifted to the individual claimants, the process is not blocked by a single failed transaction, and there's no large, complex loop.

How to Implement Dividend Distribution for Tokenized Assets

This guide from ChainScore Labs provides an excellent technical overview of the dividend distribution challenge and the pull pattern solution.

As you read, focus on these key concepts: The introduction's explanation of the pull-over-push mechanism and why it's used. Under "Standard ERC-20 Dividend Distribution," review the list of key functions, which typically include a deposit and a claim function. In the "Frequently Asked Questions" section, reinforce your understanding of why a pull-based system is more gas-efficient than a push-based one.

Architectural Design: Integrated vs. Modular

There are two primary ways to structure our dividend logic:

  1. Integrated Model: Add the dividend functionality directly into our existing SecurityToken.sol contract. This is simpler to implement and manage for a single asset.
  2. Modular Model: Create a separate IncomeVault contract dedicated solely to managing dividend deposits and claims. The SecurityToken contract would then interact with this vault.

While we will proceed with an integrated design in this course for simplicity, the modular IncomeVault approach is common in production systems as it offers better separation of concerns. This is particularly useful if the dividend management logic is complex or if multiple assets need to share the same distribution infrastructure.

The UML diagram below illustrates such a modular architecture, which should be familiar from your work with enterprise software design. It shows an IncomeVault contract that inherits from various specialized and restricted components, clearly defining its role within a larger system.

This UML diagram from the CMTAT standard shows a modular design for an `IncomeVault` contract. It separates concerns like internal logic, access restrictions, and storage into different abstract contracts, promoting reusability and security.

Designing the Accounting Logic

The central challenge is to calculate each holder's share accurately and efficiently. The most common method for security tokens is the pro-rata snapshot model.

The logic is straightforward:

  • A snapshot of all token balances is taken at a specific point in time (or a specific block number). This freezes the ownership state for a given dividend distribution.
  • An administrator deposits the total dividend amount for that period.
  • A token holder's claimable amount is calculated with a simple formula:

This approach is fair and prevents "dividend sniping"—where users could buy tokens just before a dividend is paid and sell them immediately after.

The following resource from Taurus provides a concrete example of this workflow and calculation in action within the CMTAT security token framework.

Equity Tokenization: How to Pay Dividend On-Chain Using CMTAT

This article explains the practical implementation of a dividend vault using a snapshot-based pull model.

First, review the four-step dividend distribution workflow, from registering a snapshot to a holder claiming their share. Then, carefully study the computation formula and the accompanying example. This is precisely the logic we will aim to implement.

The image below illustrates a similar incremental accounting process. After an initial deposit of $1000, Alice, with a 15% share, can claim $150. After a second deposit brings the total to $2000, she can claim another $150 based on the new income of $1000. Our snapshot model will achieve the same result by creating distinct dividend periods.

This diagram shows how a participant's dividend withdrawal is calculated proportionally to their share for two distinct income events. This visualizes the core principle of calculating shares based on a defined distribution amount.

Security Considerations and Workflow

A secure design must anticipate and mitigate potential exploits.

1. Preventing Double-Claims:
A user must not be able to claim their dividend for the same distribution period more than once. A simple and effective way to prevent this is to use a mapping to track claims. For each dividend period, we can record that a user has claimed their share.

// Example state variable
// mapping(uint256 => mapping(address => bool)) public hasClaimed;
// hasClaimed[dividendId][msg.sender] = true;

2. Reentrancy Attacks:
The withdrawDividends function will involve an external call when it transfers tokens to the user. This creates a potential reentrancy vulnerability. An attacker could create a malicious contract that, upon receiving the dividend tokens, immediately calls back into the withdrawDividends function before the first transaction has finished, potentially draining the fund.

The defense against this is the Checks-Effects-Interactions pattern:

  • Checks: First, perform all validation (e.g., has the user already claimed?).
  • Effects: Second, update the contract's state (e.g., set hasClaimed to true).
  • Interactions: Finally, interact with the external contract (e.g., transfer the tokens).

We will solidify this protection in the next lesson by using OpenZeppelin's ReentrancyGuard. The CMTAT resource you reviewed also explicitly mentions this safeguard.

Equity Tokenization: How to Pay Dividend On-Chain Using CMTAT

This short section on adversarial cases highlights key security measures.

Read the part about a dividend being claimed several times. Note the two defenses mentioned: a boolean flag to track claims and the nonReentrant modifier to prevent reentrancy attacks.

Conclusion

In this lesson, we have laid the conceptual groundwork for a robust dividend distribution mechanism. By moving from high-level architecture down to specific security details, we have designed a system ready for implementation.

Key Takeaways:

  • The pull pattern is the industry standard for on-chain value distribution, as it is more secure and gas-efficient than the naive push pattern.
  • The pro-rata snapshot model provides a fair and manipulation-resistant way to calculate each token holder's share of a dividend. The formula is (userBalance / totalSupply) * totalDividend.
  • Security is paramount. Our design must explicitly prevent double-claiming (with a tracking flag) and reentrancy attacks (using the Checks-Effects-Interactions pattern).
  • Administrative functions like depositing dividends must be protected with role-based access control, a concept you are already familiar with.

In our next lesson, we will translate this design into practice. You will implement the depositDividends and withdrawDividends functions directly within our SecurityToken contract, add the necessary state variables for accounting, and secure the withdrawal function with ReentrancyGuard.

Can't find a good explanation? Sign up and we'll make it for you

Sign up