Solidity

Pull Payment

Pull payment is a payout pattern where a contract records owed funds and lets recipients withdraw later.

Pull payment means users claim their money instead of the contract pushing it to them during another action.

Pull Payment Explained in Detail

Pull payment records an owed balance and lets the recipient withdraw it in a separate call. The main flow does not depend on sending funds to an untrusted recipient immediately.

This pattern is common for refunds, auctions, rewards, and settlement systems.

{
    "preset": "comparison",
    "autoplaySecs": 5.0,
    "edges": [
        {"idx": 0, "stepReveal": 1},
        {"idx": 1, "stepReveal": 2},
        {"idx": 2, "stepReveal": 1},
        {"idx": 3, "stepReveal": 2}
    ],
    "steps": [
        {"title": "Step 1 - Main flow chooses when to send", "desc": "Push payments send during the main action; pull payments only record owed balances.", "activeNodes": ["push-action", "pull-action"], "activeEdges": [], "tone": "info", "navLabel": "Step 1 - Main flow chooses when to send"},
        {"title": "Step 2 - External calls move to the edge", "desc": "Pull payments move recipient interaction into a separate withdraw call.", "activeNodes": ["push-call", "pull-withdraw"], "activeEdges": [0, 2], "tone": "warning", "navLabel": "Step 2 - External calls move to the edge"},
        {"title": "Step 3 - Failure scope changes", "desc": "A push payout can block a whole batch; a pull withdrawal should only fail for that recipient.", "activeNodes": ["push-block", "pull-isolate"], "activeEdges": [1, 3], "tone": "success", "navLabel": "Step 3 - Failure scope changes"},
        {"title": "Audit lesson", "desc": "Pull payment reduces global payout DoS, but the withdrawal function still needs safe state ordering and reentrancy protection.", "activeNodes": ["pull-withdraw", "pull-isolate"], "activeEdges": [3], "tone": "success", "navLabel": "Audit lesson"}
    ]
}
  
Payout Pattern

Push payout risk vs pull payout isolation

Compare the risky flow that sends during the main action with the safer flow that records debt and lets each recipient withdraw.

Push payout
Pull payout
PMain ActionLoops payouts
Inline payout
The protocol sends funds while processing the main action.
Risky path
!External CallRecipient code
Untrusted code
A recipient can revert or reenter during the main operation.
Risky path
XGlobal BlockProgress stops
Payout DoS
One bad recipient can block the whole batch or settlement.
Risky path
RMain ActionRecords debt
Accounting first
The protocol records what each recipient can claim later.
Safer path
WWithdrawSeparate call
Isolated transfer
The recipient claims funds in a separate withdrawal function.
Safer path
OKLocal FailureOnly caller fails
Failure isolation
A reverting recipient should not block unrelated users or protocol progress.
Safer path

Smart contract example

pendingWithdrawals[user] += amount;

The user later calls a withdrawal function.

Pull Payment in Auditing

Pull payment reduces the chance that one reverting or malicious recipient blocks the whole protocol. It also makes external-call risk easier to isolate.

Auditors still check withdrawal reentrancy and state-update order.

Red flags in code

  • Owed balance is cleared after the external transfer.

  • Withdrawal has no reentrancy protection or safe state ordering.

  • Anyone can redirect another user's withdrawal.

  • Accounting can be credited twice.

  • Tokens with transfer fees are treated as exact-value payouts.

How to test or review it

  • Use a recipient that reverts in receive().

  • Verify only that recipient's withdrawal fails, not global progress.

  • Confirm owed balance is cleared before transfer.

  • Test reentrant withdrawal attempts.

  • Check events and final balances after successful and failed withdrawals.

Practice this in real audit scenarios

Definitions help, but auditors need reps. SCH turns concepts like Pull Payment into exploit labs, code review habits, and report-writing practice.

Start the free trial or see the full smart contract auditing course.

Sources