Skip to main content



Inspired by:

Allows an owner to distribute any reward ERC20 to claimants according to Merkle roots. The owner can specify multiple Merkle roots distributions with customized reward currencies.

The Merkle trees are not validated in any way, so the system assumes the contract owner behaves honestly.


setWindow(uint256 rewardsToDeposit, address rewardToken, bytes32 merkleRoot, string ipfsHash) (external)

Set merkle root for the next available window index and seed allocations. Callable only by owner of this contract. Caller must have approved this contract to transfer rewardsToDeposit amount of rewardToken or this call will fail. Importantly, we assume that the owner of this contract correctly chooses an amount rewardsToDeposit that is sufficient to cover all claims within the merkleRoot.


  • rewardsToDeposit: amount of rewards to deposit to seed this allocation.
  • rewardToken: ERC20 reward token.
  • merkleRoot: merkle root describing allocation.
  • ipfsHash: hash of IPFS object, conveniently stored for clients
deleteWindow(uint256 windowIndex) (external)

Delete merkle root at window index.

Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state.


  • windowIndex: merkle root index to delete.
withdrawRewards(contract IERC20 rewardCurrency, uint256 amount) (external)

Emergency method that transfers rewards out of the contract if the contract was configured improperly.

Callable only by owner.


  • rewardCurrency: rewards to withdraw from contract.
  • amount: amount of rewards to withdraw.
claimMulti(struct MerkleDistributor.Claim[] claims) (external)

Batch claims to reduce gas versus individual submitting all claims. Method will fail if any individual claims within the batch would fail.

Optimistically tries to batch together consecutive claims for the same account and same reward token to reduce gas. Therefore, the most gas-cost-optimal way to use this method is to pass in an array of claims sorted by account and reward currency. It also reverts when any of individual _claim's amount exceeds remainingAmount for its window.


  • claims: array of claims to claim.
claim(struct MerkleDistributor.Claim _claim) (external)

Claim amount of reward tokens for account, as described by Claim input object.

If the _claim's amount, accountIndex, and account do not exactly match the values stored in the merkle root for the _claim's windowIndex this method will revert. It also reverts when _claim's amount exceeds remainingAmount for the window.


  • _claim: claim object describing amount, accountIndex, account, window index, and merkle proof.
isClaimed(uint256 windowIndex, uint256 accountIndex) โ†’ bool (public)

Returns True if the claim for accountIndex has already been completed for the Merkle root at windowIndex.

This method will only work as intended if all accountIndex's are unique for a given windowIndex. The onus is on the Owner of this contract to submit only valid Merkle roots.


  • windowIndex: merkle root to check.
  • accountIndex: account index to check within window index.
verifyClaim(struct MerkleDistributor.Claim _claim) โ†’ bool valid (public)

Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given window index.


  • _claim: claim object describing amount, accountIndex, account, window index, and merkle proof.
constructor() (internal)

Initializes the contract setting the deployer as the initial owner.

owner() โ†’ address (public)

Returns the address of the current owner.

renounceOwnership() (public)

Leaves the contract without owner. It will not be possible to call onlyOwner functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.

transferOwnership(address newOwner) (public)

Transfers ownership of the contract to a new account (newOwner). Can only be called by the current owner.

_transferOwnership(address newOwner) (internal)

Transfers ownership of the contract to a new account (newOwner). Internal function without access restriction.

_msgSender() โ†’ address (internal)
_msgData() โ†’ bytes (internal)


Claimed(address caller, uint256 windowIndex, address account, uint256 accountIndex, uint256 amount, address rewardToken)
CreatedWindow(uint256 windowIndex, uint256 rewardsDeposited, address rewardToken, address owner)
WithdrawRewards(address owner, uint256 amount, address currency)
DeleteWindow(uint256 windowIndex, address owner)
OwnershipTransferred(address previousOwner, address newOwner)



Throws if called by any account other than the owner.