Skip to content

Commit

Permalink
add YieldToken.sol (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
eyqs authored Sep 22, 2024
1 parent 500b896 commit 5ab99d8
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 22 deletions.
20 changes: 0 additions & 20 deletions smart-wallets/src/interfaces/IAssetToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,7 @@ import { IYieldDistributionToken } from "./IYieldDistributionToken.sol";

interface IAssetToken is IYieldDistributionToken {

function setTotalValue(uint256 totalValue) external;
function enableWhitelist() external;
function addToWhitelist(address user) external;
function removeFromWhitelist(address user) external;
function mint(address user, uint256 assetTokenAmount) external;
function depositYield(uint256 timestamp, uint256 currencyTokenAmount) external;

function getTotalValue() external view returns (uint256 totalValue);
function isWhitelistEnabled() external view returns (bool enabled);
function getWhitelist() external view returns (address[] memory whitelist);
function isAddressWhitelisted(address user) external view returns (bool whitelisted);
function getHolders() external view returns (address[] memory holders);
function hasBeenHolder(address user) external view returns (bool held);
function getPricePerToken() external view returns (uint256 price);
function getBalanceAvailable(address user) external view returns (uint256 balanceAvailable);

function totalYield() external view returns (uint256 amount);
function claimedYield() external view returns (uint256 amount);
function unclaimedYield() external view returns (uint256 amount);
function totalYield(address user) external view returns (uint256 amount);
function claimedYield(address user) external view returns (uint256 amount);
function unclaimedYield(address user) external view returns (uint256 amount);

}
2 changes: 0 additions & 2 deletions smart-wallets/src/interfaces/IYieldDistributionToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

interface IYieldDistributionToken is IERC20 {

function setTokenURI(string memory tokenURI) external;
function getCurrencyToken() external returns (ERC20 currencyToken);
function getTokenURI() external returns (string memory tokenURI);
function claimYield(address user) external returns (ERC20 currencyToken, uint256 currencyTokenAmount);
function accrueYield(address user) external;

Expand Down
12 changes: 12 additions & 0 deletions smart-wallets/src/interfaces/IYieldReceiver.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";

import { IAssetToken } from "./IAssetToken.sol";

interface IYieldReceiver {

function receiveYield(IAssetToken assetToken, ERC20 currencyToken, uint256 currencyTokenAmount) external;

}
7 changes: 7 additions & 0 deletions smart-wallets/src/interfaces/IYieldToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import { IYieldDistributionToken } from "./IYieldDistributionToken.sol";
import { IYieldReceiver } from "./IYieldReceiver.sol";

interface IYieldToken is IYieldDistributionToken, IYieldReceiver { }
114 changes: 114 additions & 0 deletions smart-wallets/src/token/YieldToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";

import { IAssetToken } from "../interfaces/IAssetToken.sol";
import { ISmartWallet } from "../interfaces/ISmartWallet.sol";
import { IYieldToken } from "../interfaces/IYieldToken.sol";
import { YieldDistributionToken } from "./YieldDistributionToken.sol";

/**
* @title YieldToken
* @author Eugene Y. Q. Shen
* @notice ERC20 token that receives yield redistributions from an AssetToken
*/
contract YieldToken is YieldDistributionToken, IYieldToken {

// Storage

/// @custom:storage-location erc7201:plume.storage.YieldToken
struct YieldTokenStorage {
/// @dev AssetToken that redistributes yield to the YieldToken
IAssetToken assetToken;
}

// keccak256(abi.encode(uint256(keccak256("plume.storage.YieldToken")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant YIELD_TOKEN_STORAGE_LOCATION =
0xe0df32b9dab2596a95926c5b17cc961f10a49277c3685726d2657c9ac0b50e00;

function _getYieldTokenStorage() private pure returns (YieldTokenStorage storage $) {
assembly {
$.slot := YIELD_TOKEN_STORAGE_LOCATION
}
}

// Constants

// Base that is used to divide all price inputs in order to represent e.g. 1.000001 as 1000001e12
uint256 private constant _BASE = 1e18;

// Errors

/**
* @notice Indicates a failure because the given CurrencyToken does not match the actual CurrencyToken
* @param invalidCurrencyToken CurrencyToken that does not match the actual CurrencyToken
* @param currencyToken Actual CurrencyToken used to mint and burn the AggregateToken
*/
error InvalidCurrencyToken(ERC20 invalidCurrencyToken, ERC20 currencyToken);

/**
* @notice Indicates a failure because the given AssetToken does not match the actual AssetToken
* @param invalidAssetToken AssetToken that does not match the actual AssetToken
* @param assetToken Actual AssetToken that redistributes yield to the YieldToken
*/
error InvalidAssetToken(IAssetToken invalidAssetToken, IAssetToken assetToken);

// Constructor

/**
* @notice Construct the YieldToken
* @param owner Address of the owner of the YieldToken
* @param name Name of the YieldToken
* @param symbol Symbol of the YieldToken
* @param currencyToken Token in which the yield is deposited and denominated
* @param decimals_ Number of decimals of the YieldToken
* @param tokenURI_ URI of the YieldToken metadata
* @param assetToken AssetToken that redistributes yield to the YieldToken
* @param initialSupply Initial supply of the YieldToken
*/
constructor(
address owner,
string memory name,
string memory symbol,
ERC20 currencyToken,
uint8 decimals_,
string memory tokenURI_,
IAssetToken assetToken,
uint256 initialSupply
) YieldDistributionToken(owner, name, symbol, currencyToken, decimals_, tokenURI_) {
if (currencyToken != assetToken.getCurrencyToken()) {
revert InvalidCurrencyToken(currencyToken, assetToken.getCurrencyToken());
}
_getYieldTokenStorage().assetToken = assetToken;
_mint(owner, initialSupply);
}

/**
* @notice Mint new YieldTokens to the user
* @dev Only the owner can call this function
* @param user Address of the user to mint YieldTokens to
* @param yieldTokenAmount Amount of YieldTokens to mint
*/
function mint(address user, uint256 yieldTokenAmount) external onlyOwner {
_mint(user, yieldTokenAmount);
}

/**
* @notice Receive yield into the YieldToken
* @dev Anyone can call this function to deposit yield from their AssetTokens into the YieldToken
* @param assetToken AssetToken that redistributes yield to the YieldToken
* @param currencyToken CurrencyToken in which the yield is deposited and denominated
* @param currencyTokenAmount Amount of CurrencyTokens to deposit as yield
*/
function receiveYield(IAssetToken assetToken, ERC20 currencyToken, uint256 currencyTokenAmount) external {
if (assetToken != _getYieldTokenStorage().assetToken) {
revert InvalidAssetToken(assetToken, _getYieldTokenStorage().assetToken);
}
if (currencyToken != _getYieldDistributionTokenStorage().currencyToken) {
revert InvalidCurrencyToken(currencyToken, _getYieldDistributionTokenStorage().currencyToken);
}
_depositYield(block.timestamp, currencyTokenAmount);
}

}

0 comments on commit 5ab99d8

Please sign in to comment.