Contract Name:
BeetsNftDescriptor
Contract Source Code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
import "openzeppelin-contracts/contracts/utils/Strings.sol";
import "../interfaces/INFTDescriptor.sol";
import "../interfaces/IReliquary.sol";
contract BeetsNftDescriptor is INFTDescriptor {
using Strings for uint256;
string private constant S3 = "https://beethoven-assets.s3.eu-central-1.amazonaws.com/reliquary/sonic";
string public constant termsOfService = "https://beets.fi/terms-of-service";
IReliquary public immutable reliquary;
constructor(IReliquary _reliquary) {
reliquary = _reliquary;
}
/// @notice Returns a link to the stored image
function constructTokenURI(uint256 relicId) external view override returns (string memory uri) {
PositionInfo memory position = reliquary.getPositionForId(relicId);
uri = string.concat(S3, "/", position.level.toString(), ".png");
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
// Inspired by OraclizeAPI's implementation - MIT licence
// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
interface INFTDescriptor {
function constructTokenURI(uint relicId) external view returns (string memory);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
import "openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
/**
* @notice Info for each Reliquary position.
* `amount` LP token amount the position owner has provided.
* `rewardDebt` Amount of reward token accumalated before the position's entry or last harvest.
* `rewardCredit` Amount of reward token owed to the user on next harvest.
* `entry` Used to determine the maturity of the position.
* `poolId` ID of the pool to which this position belongs.
* `level` Index of this position's level within the pool's array of levels.
*/
struct PositionInfo {
uint amount;
uint rewardDebt;
uint rewardCredit;
uint entry; // position owner's relative entry into the pool.
uint poolId; // ensures that a single Relic is only used for one pool.
uint level;
}
/**
* @notice Info of each Reliquary pool.
* `accRewardPerShare` Accumulated reward tokens per share of pool (1 / 1e12).
* `lastRewardTime` Last timestamp the accumulated reward was updated.
* `allocPoint` Pool's individual allocation - ratio of the total allocation.
* `name` Name of pool to be displayed in NFT image.
*/
struct PoolInfo {
uint accRewardPerShare;
uint lastRewardTime;
uint allocPoint;
string name;
}
/**
* @notice Info for each level in a pool that determines how maturity is rewarded.
* `requiredMaturities` The minimum maturity (in seconds) required to reach each Level.
* `multipliers` Multiplier for each level applied to amount of incentivized token when calculating rewards in the pool.
* This is applied to both the numerator and denominator in the calculation such that the size of a user's position
* is effectively considered to be the actual number of tokens times the multiplier for their level.
* Also note that these multipliers do not affect the overall emission rate.
* `balance` Total (actual) number of tokens deposited in positions at each level.
*/
struct LevelInfo {
uint[] requiredMaturities;
uint[] multipliers;
uint[] balance;
}
/**
* @notice Object representing pending rewards and related data for a position.
* `relicId` The NFT ID of the given position.
* `poolId` ID of the pool to which this position belongs.
* `pendingReward` pending reward amount for a given position.
*/
struct PendingReward {
uint relicId;
uint poolId;
uint pendingReward;
}
interface IReliquary is IERC721Enumerable {
function setEmissionCurve(address _emissionCurve) external;
function addPool(
uint allocPoint,
address _poolToken,
address _rewarder,
uint[] calldata requiredMaturity,
uint[] calldata allocPoints,
string memory name,
address _nftDescriptor
) external;
function modifyPool(
uint pid,
uint allocPoint,
address _rewarder,
string calldata name,
address _nftDescriptor,
bool overwriteRewarder
) external;
function massUpdatePools(uint[] calldata pids) external;
function updatePool(uint pid) external;
function deposit(uint amount, uint relicId) external;
function withdraw(uint amount, uint relicId) external;
function harvest(uint relicId, address harvestTo) external;
function withdrawAndHarvest(uint amount, uint relicId, address harvestTo) external;
function emergencyWithdraw(uint relicId) external;
function updatePosition(uint relicId) external;
function getPositionForId(uint) external view returns (PositionInfo memory);
function getPoolInfo(uint) external view returns (PoolInfo memory);
function getLevelInfo(uint) external view returns (LevelInfo memory);
function pendingRewardsOfOwner(address owner) external view returns (PendingReward[] memory pendingRewards);
function relicPositionsOfOwner(
address owner
) external view returns (uint[] memory relicIds, PositionInfo[] memory positionInfos);
function isApprovedOrOwner(address, uint) external view returns (bool);
function createRelicAndDeposit(address to, uint pid, uint amount) external returns (uint id);
function split(uint relicId, uint amount, address to) external returns (uint newId);
function shift(uint fromId, uint toId, uint amount) external;
function merge(uint fromId, uint toId) external;
function burn(uint tokenId) external;
function pendingReward(uint relicId) external view returns (uint pending);
function levelOnUpdate(uint relicId) external view returns (uint level);
function poolLength() external view returns (uint);
function rewardToken() external view returns (address);
function nftDescriptor(uint) external view returns (address);
function emissionCurve() external view returns (address);
function poolToken(uint) external view returns (address);
function rewarder(uint) external view returns (address);
function totalAllocPoint() external view returns (uint);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol)
pragma solidity ^0.8.0;
import "../IERC721.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
interface IERC721Enumerable is IERC721 {
/**
* @dev Returns the total amount of tokens stored by the contract.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns a token ID owned by `owner` at a given `index` of its token list.
* Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
*/
function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
/**
* @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
* Use along with {totalSupply} to enumerate all tokens.
*/
function tokenByIndex(uint256 index) external view returns (uint256);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 tokenId
) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool _approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}