pragma solidity =0.8.24;
import {IPostClaimHandler} from "../../src/interfaces/IPostClaimHandler.sol";
import {IERC20} from "@openzeppelin/interfaces/IERC20.sol";
import {SafeERC20} from "@openzeppelin/token/ERC20/utils/SafeERC20.sol";
import {Context} from "@openzeppelin/utils/Context.sol";
error InvalidCaller();
contract ClaimAndBurnHandler is IPostClaimHandler, Context {
using SafeERC20 for IERC20;
// some token implementation reject sending tokens to 0x00.00 address, so using 0xcc..cc here which is just as much unrecoverable as 0x00.00
address private constant BURN_ADDRESS = 0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC;
address public immutable vesterContract;
IERC20 public immutable burnToken;
address donationRecipient;
constructor(address vesterContract_, IERC20 burnToken_, address donationRecipient_) {
vesterContract = vesterContract_;
burnToken = burnToken_;
donationRecipient = donationRecipient_;
}
function handlePostClaim(
IERC20 claimToken,
uint256 amount,
address originalBeneficiary,
address withdrawalAddress,
string memory allocationId,
bytes memory extraData
) external {
if (_msgSender() != vesterContract) {
revert InvalidCaller();
}
bool sendDonation = abi.decode(extraData, (bool));
// 1. burn token is transferred from withdrawalAddress instead of originalBeneficiary for safety reasons
// 2. instead of calling the burn function which might not be implemented for all IERC20 tokens, tokens are sent to an unrecoverable BURN_ADDRESS address
burnToken.safeTransferFrom(withdrawalAddress, BURN_ADDRESS, amount);
if (sendDonation) {
uint256 donationAmount = amount / 10;
claimToken.safeTransfer(donationRecipient, donationAmount);
claimToken.safeTransfer(withdrawalAddress, amount - donationAmount);
} else {
claimToken.safeTransfer(withdrawalAddress, amount);
}
}
}