Skip to content

Commit

Permalink
feat: pull token wrapper
Browse files Browse the repository at this point in the history
  • Loading branch information
sogipec committed Oct 31, 2024
1 parent 1b70a88 commit 024bac1
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 2 deletions.
83 changes: 83 additions & 0 deletions contracts/partners/tokenWrappers/PullTokenWrapper.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// SPDX-License-Identifier: BUSL-1.1

pragma solidity ^0.8.17;

import { ERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "../../DistributionCreator.sol";

import "../../utils/UUPSHelper.sol";

/// @title PullTokenWrapper
/// @notice Wrapper for a reward token on Merkl so campaigns do not have to be prefunded
contract PullTokenWrapper is UUPSHelper, ERC20Upgradeable {
using SafeERC20 for IERC20;

// ================================= VARIABLES =================================

/// @notice `Core` contract handling access control
IAccessControlManager public core;

// Could be put as immutable in a non upgradeable contract
address public token;
address public holder;
address public distributor;
address public distributionCreator;

// ================================= MODIFIERS =================================

/// @notice Checks whether the `msg.sender` has the governor role or the guardian role
modifier onlyHolderOrGovernor() {
if (msg.sender != holder && !core.isGovernor(msg.sender)) revert NotAllowed();
_;
}

// ================================= FUNCTIONS =================================

function initialize(
address underlyingToken,
address _core,
address _distributionCreator,
address _holder,
string memory name,
string memory symbol
) public initializer {
__ERC20_init(string.concat(name), string.concat(symbol));
__UUPSUpgradeable_init();
if (underlyingToken == address(0) || holder == address(0)) revert ZeroAddress();
IAccessControlManager(_core).isGovernor(msg.sender);
distributor = DistributionCreator(_distributionCreator).distributor();
token = underlyingToken;
distributionCreator = _distributionCreator;
holder = _holder;
core = IAccessControlManager(_core);
}

function _beforeTokenTransfer(address from, address to, uint256 amount) internal override {
// During claim transactions, tokens are pulled and transferred to the `to` address
if (from == distributor || to == _getFeeRecipient()) IERC20(token).safeTransferFrom(holder, to, amount);
}

function _afterTokenTransfer(address, address to, uint256 amount) internal override {
// No leftover tokens can be kept except on the holder address
if (to != address(distributor) && to != holder) _burn(to, amount);
}

function _getFeeRecipient() internal view returns (address feeRecipient) {
address _distributionCreator = distributionCreator;
feeRecipient = DistributionCreator(_distributionCreator).feeRecipient();
feeRecipient = feeRecipient == address(0) ? _distributionCreator : feeRecipient;
}

function setHolder(address _newHolder) external onlyHolderOrGovernor {
holder = _newHolder;
}

function mint(uint256 amount) external onlyHolderOrGovernor {
_mint(holder, amount);
}

/// @inheritdoc UUPSUpgradeable
function _authorizeUpgrade(address) internal view override onlyGovernorUpgrader(core) {}
}
1 change: 1 addition & 0 deletions contracts/utils/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ error InvalidReward();
error InvalidSignature();
error NoDispute();
error NoOverrideForCampaign();
error NotAllowed();
error NotGovernor();
error NotGovernorOrGuardian();
error NotSigned();
Expand Down
4 changes: 2 additions & 2 deletions scripts/mintMockToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import { MockToken__factory } from '../typechain';
async function main() {
const { deployer } = await ethers.getNamedSigners();

const MockToken = MockToken__factory.connect('0xA7c167f58833c5e25848837f45A1372491A535eD', deployer);
const MockToken = MockToken__factory.connect('0xC011882d0f7672D8942e7fE2248C174eeD640c8f', deployer);

console.log(`Minting MockToken to ${deployer.address}...`);
await (
await MockToken.mint(deployer.address, parseUnits('100000', 6), {
await MockToken.mint('0x81Dd955D02D337DB81BA6c9C5F6213E647672052', parseUnits('1000', 18), {
// gasLimit: 300_000,
// maxPriorityFeePerGas: 100e9,
// maxFeePerGas: 700e9,
Expand Down

0 comments on commit 024bac1

Please sign in to comment.