Skip to content

Commit

Permalink
fix: radiant coupon
Browse files Browse the repository at this point in the history
  • Loading branch information
Picodes committed Apr 17, 2024
1 parent 5fb3d94 commit 563c3e4
Show file tree
Hide file tree
Showing 7 changed files with 1,324 additions and 12 deletions.
56 changes: 45 additions & 11 deletions contracts/coupons/RadiantCoupon.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: BUSL-1.1
/*

pragma solidity ^0.8.17;

Check warning on line 3 in contracts/coupons/RadiantCoupon.sol

View workflow job for this annotation

GitHub Actions / lint

Found more than One contract per file. 3 contracts found!

import { ERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
Expand All @@ -8,9 +8,35 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Met

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

Check warning on line 9 in contracts/coupons/RadiantCoupon.sol

View workflow job for this annotation

GitHub Actions / lint

global import of path ../utils/UUPSHelper.sol is not allowed. Specify names to import individually or bind all exports of the module into a name (import "path" as Name)

interface IDistributionCreator {
function distributor() external view returns (address);
function feeRecipient() external view returns (address);

Check failure on line 13 in contracts/coupons/RadiantCoupon.sol

View workflow job for this annotation

GitHub Actions / lint

Insert ⏎
}

interface IVesting {
function rdntToken() external view returns (address);

Check failure on line 17 in contracts/coupons/RadiantCoupon.sol

View workflow job for this annotation

GitHub Actions / lint

Insert ⏎
function vestTokens(address, uint256, bool) external returns (address);
}

/// @title Radiant Coupon
/// @dev This token can only be held by merkl distributor
/// @dev Transferring to the distributor will require transferring the underlying token to this contract
/// @dev Transferring from the distributor will trigger vesting action
/// @dev Transferring token to the distributor is permissionless so anyone could mint coupons - the only
/// impact would be to forfeit these tokens
contract RadiantCoupon is UUPSHelper, ERC20Upgradeable {
using SafeERC20 for IERC20;

// ================================= CONSTANTS =================================

IVesting public constant VESTING = IVesting(0x76ba3eC5f5adBf1C58c91e86502232317EeA72dE);
IDistributionCreator public constant DISTRIBUTOR_CREATOR =
IDistributionCreator(0x8BB4C975Ff3c250e0ceEA271728547f3802B36Fd);

address public immutable DISTRIBUTOR = DISTRIBUTOR_CREATOR.distributor();
address public immutable FEE_RECIPIENT = DISTRIBUTOR_CREATOR.feeRecipient();
address public immutable RADIANT = VESTING.rdntToken();

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

/// @notice `Core` contract handling access control
Expand All @@ -30,34 +56,43 @@ contract RadiantCoupon is UUPSHelper, ERC20Upgradeable {

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

function initialize() public initializer {
function initialize(ICore _core) public initializer onlyProxy {
__ERC20_init("RadiantCoupon", "cpRDNT");
__UUPSUpgradeable_init();
if (address(_core) == address(0)) revert ZeroAddress();
core = _core;
}

function _beforeTokenTransfer(address from, address to, uint256 amount) internal override {
// Needs an approval before hand, this is how mints are done
if (to == address(DISTRIBUTOR)) {
// Needs an RDNT approval beforehand, this is how mints of coupons are done
if (to == DISTRIBUTOR) {
IERC20(RADIANT).safeTransferFrom(from, address(this), amount);
_mint(from, amount); // These are then transfered to the distributor
}
// TODO: check allowance issue
if (to == address(FEE_MANAGER)) {
IERC20(RADIANT).safeTransferFrom(from, address(FEE_MANAGER), amount);

// Will be burn right after, to avoid having any token aside from on the distributor
if (to == FEE_RECIPIENT) {
IERC20(RADIANT).safeTransferFrom(from, FEE_RECIPIENT, amount);
_mint(from, amount); // These are then transferred to the fee manager
}
}

function _afterTokenTransfer(address from, address to, uint256 amount) internal override {
if (to == address(FEE_MANAGER)) {
if (to == FEE_RECIPIENT) {
_burn(to, amount); // To avoid having any token aside from on the distributor
} else if (from == address(DISTRIBUTOR)) {
}

if (from == DISTRIBUTOR) {
_burn(to, amount);
// HERE CALL THE VESTING CONTRACT TO STAKE ON BEHALF OF THE USER

// Vesting logic
IERC20(RADIANT).transfer(address(VESTING), amount);
VESTING.vestTokens(to, amount, true);
}
}

/// @notice Recovers any ERC20 token
/// @dev Governance only, to trigger only if something went wrong
function recoverERC20(address tokenAddress, address to, uint256 amountToRecover) external onlyGovernor {
IERC20(tokenAddress).safeTransfer(to, amountToRecover);
emit Recovered(tokenAddress, to, amountToRecover);
Expand All @@ -66,4 +101,3 @@ contract RadiantCoupon is UUPSHelper, ERC20Upgradeable {
/// @inheritdoc UUPSUpgradeable
function _authorizeUpgrade(address) internal view override onlyGovernorUpgrader(core) {}
}
*/
44 changes: 44 additions & 0 deletions deploy/coupon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { DistributionCreator__factory } from '@angleprotocol/sdk';
import { DeployFunction } from 'hardhat-deploy/types';
import yargs from 'yargs';
import { Distributor__factory } from '../typechain';

const argv = yargs.env('').boolean('ci').parseSync();

const func: DeployFunction = async ({ deployments, ethers, network }) => {
const { deploy } = deployments;
const { deployer } = await ethers.getNamedSigners();

const couponName = 'RadiantCoupon';
const distributionCreator = DistributionCreator__factory.connect('0x8BB4C975Ff3c250e0ceEA271728547f3802B36Fd', deployer)
const core = await distributionCreator.core()

console.log(`Deploying Coupon`);
console.log('Starting with the implementation');

await deploy(`${couponName}_Implementation`, {
contract: couponName,
from: deployer.address,
args: [],
log: !argv.ci,
});

const implementationAddress = (await ethers.getContract(`${couponName}_Implementation`)).address;

console.log('Starting with the implementation');

const distributorInterface = Distributor__factory.createInterface();

await deploy(`${couponName}_Proxy`, {
contract: 'ERC1967Proxy',
from: deployer.address,
args: [implementationAddress, distributorInterface.encodeFunctionData('initialize', [core])],
log: !argv.ci,
});

console.log(`Successfully deployed the contract ${couponName} at ${implementationAddress}`);
console.log('');
};

func.tags = ['coupon'];
export default func;
Loading

0 comments on commit 563c3e4

Please sign in to comment.