---
title: 'Distribution Precompile'
sidebarTitle: 'Distribution'
description: "Withdraw staking rewards and manage validator commissions from EVM contracts using the distribution precompile."
keywords: ['distribution precompile', 'staking rewards', 'validator commissions', 'paxeer rewards', 'evm staking', 'cosmos distribution']
---

> **For AI agents:** the complete documentation index is at [llms.txt](/llms.txt). Append `.md` to any page URL for its markdown version.

**Address**: `0x0000000000000000000000000000000000001007`

The distribution precompile provides EVM access to Cosmos SDK's distribution module. Smart contracts can manage staking rewards, validator commissions, and withdrawal addresses. This precompile is essential for DeFi applications that need to handle staking rewards programmatically.

## Key Features

- **Reward Management**: Withdraw delegation rewards from validators
- **Commission Handling**: Validators can withdraw earned commissions
- **Batch Operations**: Withdraw from multiple validators efficiently
- **Flexible Withdrawals**: Set custom withdrawal addresses
- **Comprehensive Queries**: Access detailed reward information

## Interface Overview

```solidity
interface IDistr {
    // Events
    event WithdrawAddressSet(address indexed delegator, address withdrawAddr);
    event DelegationRewardsWithdrawn(address indexed delegator, string validator, uint256 amount);
    event MultipleDelegationRewardsWithdrawn(address indexed delegator, string[] validators, uint256[] amounts);
    event ValidatorCommissionWithdrawn(string indexed validator, uint256 amount);

    // Transaction Methods
    function setWithdrawAddress(address withdrawAddr) external returns (bool);
    function withdrawDelegationRewards(string memory validator) external returns (bool);
    function withdrawMultipleDelegationRewards(string[] memory validators) external returns (bool);
    function withdrawValidatorCommission() external returns (bool);

    // Query Methods
    function rewards(address delegatorAddress) external view returns (Rewards);
}
```

## Events

The distribution precompile emits events for all state-changing operations, allowing off-chain services to track reward distributions and configuration changes.

### WithdrawAddressSet

Emitted when a delegator changes their reward withdrawal address.

```solidity
event WithdrawAddressSet(address indexed delegator, address withdrawAddr);
```

**Parameters:**

- `delegator` (indexed): The EVM address of the delegator changing their settings
- `withdrawAddr`: The new address where rewards will be sent

**Example usage:**

```typescript
// Listen for withdrawal address changes
distrContract.on('WithdrawAddressSet', (delegator, withdrawAddr) => {
  console.log(`${delegator} set withdrawal address to ${withdrawAddr}`);
});
```

### DelegationRewardsWithdrawn

Emitted when a delegator withdraws rewards from a single validator.

```solidity
event DelegationRewardsWithdrawn(address indexed delegator, string validator, uint256 amount);
```

**Parameters:**

- `delegator` (indexed): The EVM address of the delegator withdrawing rewards
- `validator`: The Paxeer validator address (e.g., "paxvaloper1...")
- `amount`: The amount of rewards withdrawn (in uhpx, 6 decimal precision)

**Example usage:**

```typescript
// Track individual reward withdrawals
distrContract.on('DelegationRewardsWithdrawn', (delegator, validator, amount) => {
  const paxAmount = Number(amount) / 1e6;
  console.log(`${delegator} withdrew ${paxAmount} HPX from ${validator}`);
});
```

### MultipleDelegationRewardsWithdrawn

Emitted when a delegator withdraws rewards from multiple validators in a single transaction.

```solidity
event MultipleDelegationRewardsWithdrawn(address indexed delegator, string[] validators, uint256[] amounts);
```

**Parameters:**

- `delegator` (indexed): The EVM address of the delegator withdrawing rewards
- `validators`: Array of Paxeer validator addresses
- `amounts`: Array of reward amounts corresponding to each validator (in uhpx, 6 decimal precision)

**Example usage:**

```typescript
// Track batch reward withdrawals
distrContract.on('MultipleDelegationRewardsWithdrawn', (delegator, validators, amounts) => {
  for (let i = 0; i < validators.length; i++) {
    const paxAmount = Number(amounts[i]) / 1e6;
    console.log(`${delegator} withdrew ${paxAmount} HPX from ${validators[i]}`);
  }
});
```

### ValidatorCommissionWithdrawn

Emitted when a validator operator withdraws their earned commission.

```solidity
event ValidatorCommissionWithdrawn(string indexed validator, uint256 amount);
```

**Parameters:**

- `validator` (indexed): The Paxeer validator address
- `amount`: The commission amount withdrawn (in uhpx, 6 decimal precision)

**Example usage:**

```typescript
// Track validator commission withdrawals
distrContract.on('ValidatorCommissionWithdrawn', (validator, amount) => {
  const paxAmount = Number(amount) / 1e6;
  console.log(`Validator ${validator} withdrew ${paxAmount} HPX commission`);
});
```

<Info>**Event Amounts**: All event amounts use 6 decimal precision (uhpx), matching the actual withdrawn token amounts. This differs from the `rewards()` query which returns 18 decimal precision.</Info>

## Transaction Methods

### setWithdrawAddress

Sets the withdrawal address for staking rewards. By default, rewards are sent to the delegator's address, but this can be customized.

```solidity
function setWithdrawAddress(address withdrawAddr) external returns (bool success);
```

**Parameters:**

- `withdrawAddr`: EVM address where future rewards should be sent

**Gas Cost**: ~30,000 gas

**Example:**

```solidity
// Set rewards to go to a treasury contract
bool success = DISTR_CONTRACT.setWithdrawAddress(0x742d35Cc6634C0532925a3b8D4C9db96590c6C8C);
require(success, "Failed to set withdraw address");
```

### withdrawDelegationRewards

Withdraws accumulated rewards from a specific validator.

```solidity
function withdrawDelegationRewards(string memory validator) external returns (bool success);
```

**Parameters:**

- `validator`: Paxeer validator address (e.g., "paxvaloper1...")

**Gas Cost**: ~50,000-80,000 gas (varies by reward amount)

**Example:**

```solidity
string memory validator = "paxvaloper1xyz...";
bool success = DISTR_CONTRACT.withdrawDelegationRewards(validator);
require(success, "Failed to withdraw rewards");
```

### withdrawMultipleDelegationRewards

Efficiently withdraws rewards from multiple validators in a single transaction.

```solidity
function withdrawMultipleDelegationRewards(string[] memory validators) external returns (bool success);
```

**Parameters:**

- `validators`: Array of Paxeer validator addresses

**Gas Cost**: ~40,000 + (30,000 × number of validators)

**Example:**

```solidity
string[] memory validators = new string[](3);
validators[0] = "paxvaloper1abc...";
validators[1] = "paxvaloper1def...";
validators[2] = "paxvaloper1ghi...";

bool success = DISTR_CONTRACT.withdrawMultipleDelegationRewards(validators);
require(success, "Failed to withdraw multiple rewards");
```

<Info>**Batch Efficiency**: Using `withdrawMultipleDelegationRewards` is significantly more gas-efficient than multiple individual calls, especially when withdrawing from 3+ validators.</Info>

### withdrawValidatorCommission

Allows validators to withdraw their earned commission. Only callable by the validator operator address.

```solidity
function withdrawValidatorCommission() external returns (bool success);
```

**Parameters:** None - the validator is automatically determined from the caller's associated Paxeer address.

**Gas Cost**: ~60,000-90,000 gas

**Example:**

```solidity
// Only works if caller is the validator operator
bool success = DISTR_CONTRACT.withdrawValidatorCommission();
require(success, "Failed to withdraw commission");
```

<Warning>**Validator Only**: This method can only be called by the validator's operator address. The precompile automatically identifies the validator based on the caller's associated Paxeer address. If the caller is not a validator operator, the call will fail.</Warning>

## Query Methods

### rewards

Retrieves comprehensive reward information for a delegator across all validators.

```solidity
function rewards(address delegatorAddress) external view returns (Rewards rewards);
```

**Data Structures:**

```solidity
struct Coin {
    uint256 amount;    // Token amount in 18 decimal precision (DecCoins)
    uint256 decimals;  // Always 18 - decimal precision for the amount
    string denom;      // Token denomination (e.g., "uhpx")
}

struct Reward {
    Coin[] coins;              // Reward coins from this validator
    string validator_address;  // Validator's Paxeer address
}

struct Rewards {
    Reward[] rewards;  // Per-validator breakdown
    Coin[] total;      // Total rewards across all validators
}
```

<Warning>
**Critical: Decimal Precision for Rewards**

The `rewards()` query returns amounts with **18 decimal precision** (`DecCoins` from Cosmos SDK).

This is different from the actual withdrawn reward amounts, which use **6 decimal precision** (`sdk.Coins`).

**To convert pending rewards to HPX for display:**

```javascript
const pendingRewardsPax = amount / 1e18; // rewards() query uses 18 decimals
```

**Withdrawn rewards are in uhpx (6 decimals):**

```javascript
const withdrawnPax = withdrawnAmount / 1e6; // actual withdrawals use 6 decimals
```

</Warning>

**Example:**

```solidity
Rewards memory userRewards = DISTR_CONTRACT.rewards(msg.sender);

// Check total rewards - uses 18 decimal precision
for (uint i = 0; i < userRewards.total.length; i++) {
    Coin memory coin = userRewards.total[i];
    // coin.decimals is always 18 for rewards
    uint256 displayAmount = coin.amount / (10 ** coin.decimals);
    // Process reward amount for coin.denom
}

// Check per-validator rewards
for (uint i = 0; i < userRewards.rewards.length; i++) {
    Reward memory reward = userRewards.rewards[i];
    // Process rewards from reward.validator_address
}
```

## Understanding Decimal Precision

The distribution precompile has **different decimal precision for queries vs actual withdrawals** due to how rewards are tracked in the Cosmos SDK:

| Function | Type | Decimal Precision | Conversion to HPX |
| --- | --- | --- | --- |
| **rewards()** | Query (pending rewards) | 18 decimals (DecCoins) | `amount / 1e18` |
| **withdrawDelegationRewards()** | Withdrawn amount (event) | 6 decimals (uhpx) | `amount / 1e6` |
| **withdrawMultipleDelegationRewards()** | Withdrawn amount (event) | 6 decimals (uhpx) | `amount / 1e6` |
| **withdrawValidatorCommission()** | Withdrawn amount (event) | 6 decimals (uhpx) | `amount / 1e6` |


### Why Different Precisions?

1. **Pending Rewards (18 decimals)**: The Cosmos SDK tracks pending rewards using `DecCoins` (decimal coins) with 18 decimal precision for higher accuracy during reward accumulation.

2. **Withdrawn Rewards (6 decimals)**: When rewards are actually withdrawn, they are converted to `sdk.Coins` (uhpx) with 6 decimal precision to match Paxeer's native token units.

### Conversion Helper Functions

```typescript
// Convert pending rewards (18 decimals) to HPX
function pendingRewardsToPax(amount: bigint): number {
  return Number(amount) / 1e18;
}

// Convert withdrawn rewards (6 decimals) to HPX
function withdrawnRewardsToPax(amount: bigint): number {
  return Number(amount) / 1e6;
}

// Example usage
const pendingRewards = await distrContract.rewards(delegatorAddress);
const pendingPax = pendingRewardsToPax(pendingRewards.total[0].amount);
console.log(`Pending rewards: ${pendingPax} HPX`);
```

<Info>**Note**: When reconciling pending rewards with actual withdrawals, be aware of the 12-decimal difference (10^12 factor) between query results and withdrawal amounts.</Info>

## Practical Examples

### DeFi Yield Aggregator

```solidity
contract YieldAggregator {
    IDistr constant DISTR = IDistr(0x0000000000000000000000000000000000001007);

    mapping(address => string[]) public userValidators;

    function harvestRewards() external {
        string[] memory validators = userValidators[msg.sender];
        require(validators.length > 0, "No validators to harvest from");

        // Efficiently withdraw from all validators
        bool success = DISTR.withdrawMultipleDelegationRewards(validators);
        require(success, "Harvest failed");

        // Additional logic to compound or distribute rewards
    }

    function checkPendingRewards(address user) external view returns (uint256 totalPax) {
        Rewards memory rewards = DISTR.rewards(user);

        for (uint i = 0; i < rewards.total.length; i++) {
            if (keccak256(bytes(rewards.total[i].denom)) == keccak256(bytes("uhpx"))) {
                totalPax = rewards.total[i].amount;
                break;
            }
        }
    }
}
```

### Validator Commission Manager

```solidity
contract ValidatorManager {
    IDistr constant DISTR = IDistr(0x0000000000000000000000000000000000001007);

    address public treasury;

    constructor(address _treasury) {
        treasury = _treasury;

        // Set commission withdrawals to go to treasury
        DISTR.setWithdrawAddress(treasury);
    }

    // Only callable by the validator operator
    function withdrawCommission() external {
        bool success = DISTR.withdrawValidatorCommission();
        require(success, "Commission withdrawal failed");
    }
}
```

## Error Handling

Common error scenarios and how to handle them:

```solidity
contract SafeDistribution {
    IDistr constant DISTR = IDistr(0x0000000000000000000000000000000000001007);

    function safeWithdrawRewards(string memory validator) external returns (bool) {
        // Check if there are rewards to withdraw first
        Rewards memory rewards = DISTR.rewards(msg.sender);

        bool hasRewards = false;
        for (uint i = 0; i < rewards.rewards.length; i++) {
            if (keccak256(bytes(rewards.rewards[i].validator_address)) ==
                keccak256(bytes(validator))) {
                hasRewards = rewards.rewards[i].coins.length > 0;
                break;
            }
        }

        if (!hasRewards) {
            return false; // No rewards to withdraw
        }

        try DISTR.withdrawDelegationRewards(validator) returns (bool success) {
            return success;
        } catch {
            return false; // Handle withdrawal failure gracefully
        }
    }
}
```

## Gas Optimization Tips

1. **Batch Operations**: Use `withdrawMultipleDelegationRewards` for multiple validators
2. **Check Before Withdraw**: Query rewards first to avoid unnecessary transactions
3. **Set Withdraw Address Once**: Avoid repeated `setWithdrawAddress` calls
4. **Commission Timing**: Withdraw validator commission when amounts are substantial

## Integration Patterns

### Auto-Compounding Strategy

```solidity
// Automatically reinvest rewards back into staking
function autoCompound() external {
    // 1. Withdraw rewards
    DISTR.withdrawMultipleDelegationRewards(getMyValidators());

    // 2. Use staking precompile to re-delegate
    // (Implementation depends on staking precompile integration)
}
```

### Treasury Management

```solidity
// Route all rewards to a DAO treasury
function setupTreasuryWithdrawals(address treasury) external onlyOwner {
    DISTR.setWithdrawAddress(treasury);
}
```

<Info>View the complete distribution precompile source code and ABI [here](https://github.com/paxeer-network/paxeer-chain/tree/main/precompiles/distribution).</Info>
