Skip to content

Commit

Permalink
adds PufToken and PufferStakingPool
Browse files Browse the repository at this point in the history
  • Loading branch information
WalidOfNow committed Jun 13, 2024
1 parent 87c4a20 commit 9460dcf
Show file tree
Hide file tree
Showing 2 changed files with 182 additions and 0 deletions.
87 changes: 87 additions & 0 deletions mainnet-contracts/src/based-contracts/PufToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.0 <0.9.0;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
import "@openzeppelin/contracts/access/manager/AccessManaged.sol";

contract PufToken is ERC20, ERC20Permit {
address public immutable originalToken;
address public immutable depositorContract;

// Custom error definitions
error TransferFailed();
error InsufficientBalance();
error ApprovalFailed();
error DepositAmountMustBeGreaterThanZero();
error Unauthorized();

constructor(string memory name, string memory symbol, address _originalToken, address _depositorContract)
ERC20(name, symbol)
ERC20Permit(name)
{
originalToken = _originalToken;
depositorContract = _depositorContract;
}

modifier onlyDepositor() {
if (msg.sender != depositorContract) {
revert Unauthorized();
}
_;
}

function depositFor(address user, uint256 amount) external onlyDepositor {
if (amount == 0) {
revert DepositAmountMustBeGreaterThanZero();
}

if (!IERC20(originalToken).transferFrom(user, address(this), amount)) {
revert TransferFailed();
}

_mint(user, amount);
}

function withdrawFor(address user, uint256 amount) external onlyDepositor {
if (balanceOf(user) < amount) {
revert InsufficientBalance();
}

_burn(user, amount);

if (!IERC20(originalToken).transfer(user, amount)) {
revert TransferFailed();
}
}

function migrateFor(address user, address migrator, address destination, uint256 amount) external onlyDepositor {
if (balanceOf(user) < amount) {
revert InsufficientBalance();
}

_burn(user, amount);

if (!IERC20(originalToken).approve(migrator, amount)) {
revert ApprovalFailed();
}

IMigrator(migrator).migrate(user, originalToken, destination, amount);
}

function deposit(uint256 amount) external {
if (amount == 0) {
revert DepositAmountMustBeGreaterThanZero();
}

if (!IERC20(originalToken).transferFrom(msg.sender, address(this), amount)) {
revert TransferFailed();
}

_mint(msg.sender, amount);
}
}

interface IMigrator {
function migrate(address depositor, address token, address destination, uint256 amount) external;
}
95 changes: 95 additions & 0 deletions mainnet-contracts/src/based-contracts/PufferStakingPool.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.0 <0.9.0;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/access/manager/AccessManaged.sol";
import "./PufToken.sol";

contract PufferStakingPool is AccessManaged {
using Address for address;

struct Asset {
address tokenAddress;
address derivativeTokenAddress;
}

mapping(address => Asset) public allowlistedAssets;
address[] public assetList;

mapping(address migrator => bool isAllowed) public allowedMigrators;

// Custom error definitions
error Unauthorized();
error AssetAlreadyAdded();
error AssetNotAllowlisted();
error InvalidMigratorContract();

event AssetAdded(address indexed tokenAddress, address indexed derivativeTokenAddress);
event Deposit(address indexed user, address indexed tokenAddress, uint256 amount);
event Withdraw(address indexed user, address indexed tokenAddress, uint256 amount);
event Migrated(address indexed user, address indexed tokenAddress, address destination, uint256 amount);
event SetIsMigratorAllowed(address indexed migrator, bool isAllowed);

constructor(address addressManager) AccessManaged(addressManager) { }

function addAsset(address tokenAddress, string calldata name, string calldata symbol) external restricted {
if (allowlistedAssets[tokenAddress].tokenAddress != address(0)) {
revert AssetAlreadyAdded();
}

address derivativeToken = address(new PufToken(name, symbol, tokenAddress, address(this)));

allowlistedAssets[tokenAddress] = Asset({ tokenAddress: tokenAddress, derivativeTokenAddress: derivativeToken });

assetList.push(tokenAddress);

emit AssetAdded(tokenAddress, derivativeToken);
}

function deposit(address tokenAddress, uint256 amount) external {
Asset memory asset = allowlistedAssets[tokenAddress];
if (asset.tokenAddress == address(0)) {
revert AssetNotAllowlisted();
}

PufToken(asset.derivativeTokenAddress).depositFor(msg.sender, amount);
emit Deposit(msg.sender, tokenAddress, amount);
}

function withdraw(address tokenAddress, uint256 amount) external {
Asset memory asset = allowlistedAssets[tokenAddress];
if (asset.tokenAddress == address(0)) {
revert AssetNotAllowlisted();
}

PufToken(asset.derivativeTokenAddress).withdrawFor(msg.sender, amount);
emit Withdraw(msg.sender, tokenAddress, amount);
}

function migrate(address tokenAddress, address destination, uint256 amount, address migratorAddress) external {
Asset memory asset = allowlistedAssets[tokenAddress];
if (asset.tokenAddress == address(0)) {
revert AssetNotAllowlisted();
}

if (!allowedMigrators[migratorAddress]) {
revert InvalidMigratorContract();
}

PufToken(asset.derivativeTokenAddress).migrateFor(msg.sender, migratorAddress, destination, amount);
emit Migrated(msg.sender, tokenAddress, destination, amount);
}

/**
* @dev Restricted to Puffer Multisig
*/
function setMigrator(address migrator, bool allowed) external restricted {
if (migrator == address(0)) {
revert InvalidMigratorContract();
}

allowedMigrators[migrator] = allowed;
emit SetIsMigratorAllowed(migrator, allowed);
}
}

0 comments on commit 9460dcf

Please sign in to comment.