164 lines
4.6 KiB
Solidity
164 lines
4.6 KiB
Solidity
|
// SPDX-License-Identifier: CC0-1.0
|
||
|
pragma solidity ^0.8.17;
|
||
|
|
||
|
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
|
||
|
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||
|
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||
|
import "@openzeppelin/contracts/access/Ownable.sol";
|
||
|
import "@openzeppelin/contracts/utils/Counters.sol";
|
||
|
import "./IERC5725.sol";
|
||
|
|
||
|
abstract contract ERC5725 is IERC5725, ERC721 {
|
||
|
using SafeERC20 for IERC20;
|
||
|
|
||
|
/// @dev mapping for claimed payouts
|
||
|
mapping(uint256 => uint256) /*tokenId*/ /*claimed*/
|
||
|
internal _payoutClaimed;
|
||
|
|
||
|
/**
|
||
|
* @notice Checks if the tokenId exists and its valid
|
||
|
* @param tokenId The NFT token id
|
||
|
*/
|
||
|
modifier validToken(uint256 tokenId) {
|
||
|
require(_exists(tokenId), "ERC5725: invalid token ID");
|
||
|
_;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @dev See {IERC5725}.
|
||
|
*/
|
||
|
function claim(uint256 tokenId) external override(IERC5725) validToken(tokenId) {
|
||
|
require(ownerOf(tokenId) == msg.sender, "Not owner of NFT");
|
||
|
uint256 amountClaimed = claimablePayout(tokenId);
|
||
|
require(amountClaimed > 0, "ERC5725: No pending payout");
|
||
|
|
||
|
emit PayoutClaimed(tokenId, msg.sender, amountClaimed);
|
||
|
|
||
|
_payoutClaimed[tokenId] += amountClaimed;
|
||
|
IERC20(payoutToken(tokenId)).safeTransfer(msg.sender, amountClaimed);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @dev See {IERC5725}.
|
||
|
*/
|
||
|
function vestedPayout(uint256 tokenId) public view override(IERC5725) returns (uint256 payout) {
|
||
|
return vestedPayoutAtTime(tokenId, block.timestamp);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @dev See {IERC5725}.
|
||
|
*/
|
||
|
function vestedPayoutAtTime(uint256 tokenId, uint256 timestamp)
|
||
|
public
|
||
|
view
|
||
|
virtual
|
||
|
override(IERC5725)
|
||
|
returns (uint256 payout);
|
||
|
|
||
|
/**
|
||
|
* @dev See {IERC5725}.
|
||
|
*/
|
||
|
function vestingPayout(uint256 tokenId)
|
||
|
public
|
||
|
view
|
||
|
override(IERC5725)
|
||
|
validToken(tokenId)
|
||
|
returns (uint256 payout)
|
||
|
{
|
||
|
return _payout(tokenId) - vestedPayout(tokenId);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @dev See {IERC5725}.
|
||
|
*/
|
||
|
function claimablePayout(uint256 tokenId)
|
||
|
public
|
||
|
view
|
||
|
override(IERC5725)
|
||
|
validToken(tokenId)
|
||
|
returns (uint256 payout)
|
||
|
{
|
||
|
return vestedPayout(tokenId) - _payoutClaimed[tokenId];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @dev See {IERC5725}.
|
||
|
*/
|
||
|
function claimedPayout(uint256 tokenId)
|
||
|
public
|
||
|
view
|
||
|
override(IERC5725)
|
||
|
validToken(tokenId)
|
||
|
returns (uint256 payout)
|
||
|
{
|
||
|
return _payoutClaimed[tokenId];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @dev See {IERC5725}.
|
||
|
*/
|
||
|
function vestingPeriod(uint256 tokenId)
|
||
|
public
|
||
|
view
|
||
|
override(IERC5725)
|
||
|
validToken(tokenId)
|
||
|
returns (uint256 vestingStart, uint256 vestingEnd)
|
||
|
{
|
||
|
return (_startTime(tokenId), _endTime(tokenId));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @dev See {IERC5725}.
|
||
|
*/
|
||
|
function payoutToken(uint256 tokenId) public view override(IERC5725) validToken(tokenId) returns (address token) {
|
||
|
return _payoutToken(tokenId);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @dev See {IERC165-supportsInterface}.
|
||
|
* IERC5725 interfaceId = 0x7c89676d
|
||
|
*/
|
||
|
function supportsInterface(bytes4 interfaceId)
|
||
|
public
|
||
|
view
|
||
|
virtual
|
||
|
override(ERC721, IERC165)
|
||
|
returns (bool supported)
|
||
|
{
|
||
|
return interfaceId == type(IERC5725).interfaceId || super.supportsInterface(interfaceId);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @dev Internal function to get the payout token of a given vesting NFT
|
||
|
*
|
||
|
* @param tokenId on which to check the payout token address
|
||
|
* @return address payout token address
|
||
|
*/
|
||
|
function _payoutToken(uint256 tokenId) internal view virtual returns (address);
|
||
|
|
||
|
/**
|
||
|
* @dev Internal function to get the total payout of a given vesting NFT.
|
||
|
* @dev This is the total that will be paid out to the NFT owner, including historical tokens.
|
||
|
*
|
||
|
* @param tokenId to check
|
||
|
* @return uint256 the total payout of a given vesting NFT
|
||
|
*/
|
||
|
function _payout(uint256 tokenId) internal view virtual returns (uint256);
|
||
|
|
||
|
/**
|
||
|
* @dev Internal function to get the start time of a given vesting NFT
|
||
|
*
|
||
|
* @param tokenId to check
|
||
|
* @return uint256 the start time in epoch timestamp
|
||
|
*/
|
||
|
function _startTime(uint256 tokenId) internal view virtual returns (uint256);
|
||
|
|
||
|
/**
|
||
|
* @dev Internal function to get the end time of a given vesting NFT
|
||
|
*
|
||
|
* @param tokenId to check
|
||
|
* @return uint256 the end time in epoch timestamp
|
||
|
*/
|
||
|
function _endTime(uint256 tokenId) internal view virtual returns (uint256);
|
||
|
}
|