
Token wrappers
Deploy a token wrapper contract, mint wrapper tokens, and use them as the reward token of a Merkl campaign
A token wrapper is an ERC-20 contract that you use as the reward token of a campaign. When a user claims, the wrapper runs custom logic and delivers the final asset. With a pull-based wrapper, the underlying tokens stay in your address until the claim.
This page covers the technical setup. For the principle and the use cases, read Keep Custody with Token Wrappers.
Templates
Merkl provides audited templates in the merkl-contracts repository:
Pull-on-Claim Wrapper
aToken Unwrapper (Aave)
Auto-Vault Wrapper (ERC-4626)
| Wrapper | Contract | Constructor arguments |
|---|---|---|
| Pull-on-Claim | PullTokenWrapperAllowImmutable | _token, _distributionCreator, _holder |
| aToken Unwrapper (Aave) | PullTokenWrapperWithdrawImmutable | _token (the aToken), _distributionCreator, _holder |
| Auto-Vault (ERC-4626) | PullTokenWrapperVaultImmutable | _token, _distributionCreator, _holder, _vault |
| Native Token Unwrapper | NativeTokenUnwrapperImmutable | _wrappedNative, _distributionCreator, _holder, _name, _symbol |
_distributionCreatoris the MerklDistributionCreatorcontract on the target chain. Find its address in Chains and contracts._holderis the address that holds the underlying tokens, typically your multisig.
Deploy
Deploy the wrapper from Merkl Studio with a connected wallet. You can also deploy it with your own tooling from the merkl-contracts repository.
After deployment, Studio gives a forge verify-contract command. Run it from the merkl-contracts repository to verify the wrapper on Etherscan:
forge verify-contract <WRAPPER_ADDRESS> contracts/partners/tokenWrappers/PullTokenWrapperAllowImmutable.sol:PullTokenWrapperAllowImmutable \
--chain-id <CHAIN_ID> \
--constructor-args $(cast abi-encode "constructor(address,address,address)" <TOKEN> <DISTRIBUTION_CREATOR> <HOLDER>) \
--etherscan-api-key <YOUR_API_KEY>
Whitelisting is mandatory. You cannot use a wrapper in a campaign before Merkl whitelists it. Submit a whitelisting request after deployment.
Create the campaign
- From the holder address, call
mint(address to, uint256 amount)on the wrapper. Mint the campaign budget to the address that creates the campaign. - From the creator address, approve the wrapper token to the
DistributionCreatorcontract. - Create the campaign with the wrapper token as the reward token. Follow the usual flow: configuration, payloads, and transactions.
Enable claims
- From the holder address, approve the wrapper contract to spend the underlying token.
- Keep the holder balance and allowance above the expected claims.
When a user claims, the wrapper calls transferFrom on the underlying token, from the holder to the user. If the holder balance or allowance is lower than the claimed amount, the claim reverts.
To stop claims, revoke the allowance.
Read wrappers from the API
The API links each wrapper to the token it pays out with the underlyingTokenId field. See Resolving a wrapper's underlying token.