-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
87c4a20
commit 9460dcf
Showing
2 changed files
with
182 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
95
mainnet-contracts/src/based-contracts/PufferStakingPool.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |