¡El código fuente de este contrato está verificado!
Metadatos del Contrato
Compilador
0.8.18+commit.87f61d96
Idioma
Solidity
Código Fuente del Contrato
Archivo 1 de 6: IERC165.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)pragmasolidity ^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}.
*/interfaceIERC165{
/**
* @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.
*/functionsupportsInterface(bytes4 interfaceId) externalviewreturns (bool);
}
Código Fuente del Contrato
Archivo 2 de 6: IERC721.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol)pragmasolidity ^0.8.0;import"../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/interfaceIERC721isIERC165{
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/eventTransfer(addressindexedfrom, addressindexed to, uint256indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/eventApproval(addressindexed owner, addressindexed approved, uint256indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/eventApprovalForAll(addressindexed owner, addressindexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/functionbalanceOf(address owner) externalviewreturns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/functionownerOf(uint256 tokenId) externalviewreturns (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.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId,
bytescalldata 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.
*/functionsafeTransferFrom(addressfrom,
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.
*/functiontransferFrom(addressfrom,
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.
*/functionapprove(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.
*/functionsetApprovalForAll(address operator, bool _approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/functiongetApproved(uint256 tokenId) externalviewreturns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/functionisApprovedForAll(address owner, address operator) externalviewreturns (bool);
}
// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity ^0.8.18;import"../../interfaces/IStakingNFT.sol";
import"../../interfaces/IStakingNFTDescriptor.sol";
import"../../libraries/StakingPoolLibrary.sol";
/// @dev Based on Solmate https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.solcontractStakingNFTisIStakingNFT{
structTokenInfo {
uint96 poolId;
address owner;
}
stringpublic name;
stringpublic symbol;
mapping(uint=> TokenInfo) internal _tokenInfo;
mapping(address=>uint) internal _balanceOf;
mapping(uint=>address) public getApproved;
mapping(address=>mapping(address=>bool)) public isApprovedForAll;
uint96internal _totalSupply;
addresspublic operator;
addresspublic nftDescriptor;
addresspublicimmutable stakingPoolFactory;
modifieronlyOperator{
if (msg.sender!= operator) revert NotOperator();
_;
}
constructor(stringmemory _name,
stringmemory _symbol,
address _stakingPoolFactory,
address _operator,
address _nftDescriptor
) {
name = _name;
symbol = _symbol;
stakingPoolFactory = _stakingPoolFactory;
operator = _operator;
nftDescriptor = _nftDescriptor;
}
// operator functionsfunctionchangeOperator(address newOperator) publiconlyOperator{
if (newOperator ==address(0)) revert InvalidNewOperatorAddress();
operator = newOperator;
}
functionchangeNFTDescriptor(address newNFTDescriptor) publiconlyOperator{
if (newNFTDescriptor ==address(0)) revert InvalidNewNFTDescriptorAddress();
nftDescriptor = newNFTDescriptor;
}
// minting and supplyfunctionmint(uint poolId, address to) publicreturns (uint id) {
if (msg.sender!= StakingPoolLibrary.getAddress(stakingPoolFactory, poolId)) {
revert NotStakingPool();
}
if (to ==address(0)) revert InvalidRecipient();
// counter overflow is incredibly unrealisticunchecked {
id =++_totalSupply;
_balanceOf[to]++;
}
_tokenInfo[id].owner = to;
_tokenInfo[id].poolId =uint96(poolId);
emit Transfer(address(0), to, id);
}
functiontotalSupply() publicviewreturns (uint) {
return _totalSupply;
}
// infofunctiontokenInfo(uint tokenId) publicviewreturns (uint poolId, address owner) {
poolId = _tokenInfo[tokenId].poolId;
owner = _tokenInfo[tokenId].owner;
if (owner ==address(0)) revert NotMinted();
}
functionstakingPoolOf(uint tokenId) publicviewreturns (uint poolId) {
poolId = _tokenInfo[tokenId].poolId;
if (poolId ==0) revert NotMinted();
}
// ERC165functionsupportsInterface(bytes4 interfaceId) publicpurereturns (bool) {
return
interfaceId ==0x01ffc9a7||// ERC165 Interface ID for ERC165
interfaceId ==0x80ac58cd||// ERC165 Interface ID for ERC721
interfaceId ==0x5b5e139f; // ERC165 Interface ID for ERC721Metadata
}
// ERC721functiontokenURI(uint id) publicviewvirtualreturns (stringmemory uri) {
if (_tokenInfo[id].owner ==address(0)) revert NotMinted();
return IStakingNFTDescriptor(nftDescriptor).tokenURI(id);
}
functionownerOf(uint id) publicviewreturns (address owner) {
owner = _tokenInfo[id].owner;
if (owner ==address(0)) revert NotMinted();
}
functionbalanceOf(address owner) publicviewreturns (uint) {
if (owner ==address(0)) revert NotMinted();
return _balanceOf[owner];
}
functionapprove(address spender, uint id) public{
address owner = ownerOf(id);
if (msg.sender!= owner &&!isApprovedForAll[owner][msg.sender]) revert NotAuthorized();
getApproved[id] = spender;
emit Approval(owner, spender, id);
}
functionsetApprovalForAll(address spender, bool approved) public{
isApprovedForAll[msg.sender][spender] = approved;
emit ApprovalForAll(msg.sender, spender, approved);
}
/// @dev `ownerOf` and `getApproved` throw if the token doesn't exist as per ERC721 spec/// @dev as a consequence this function will throw as well in that casefunctionisApprovedOrOwner(address spender, uint id) externalviewreturns (bool) {
address owner = ownerOf(id);
return spender == owner || isApprovedForAll[owner][spender] || spender == getApproved[id];
}
functiontransferFrom(addressfrom, address to, uint id) public{
if (from!= ownerOf(id)) revert WrongFrom();
if (to ==address(0)) revert InvalidRecipient();
if (msg.sender!=from&&!isApprovedForAll[from][msg.sender] &&msg.sender!= getApproved[id]) {
revert NotAuthorized();
}
// underflow of the sender's balance is impossible because we check for// ownership above and the recipient's balance can't realistically overflowunchecked {
_balanceOf[from]--;
_balanceOf[to]++;
}
_tokenInfo[id].owner = to;
delete getApproved[id];
emit Transfer(from, to, id);
}
functionsafeTransferFrom(addressfrom, address to, uint id) public{
transferFrom(from, to, id);
if (to.code.length!=0&& ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "") != ERC721TokenReceiver.onERC721Received.selector) {
revert UnsafeRecipient();
}
}
functionsafeTransferFrom(addressfrom,
address to,
uint id,
bytescalldata data
) public{
transferFrom(from, to, id);
if (to.code.length!=0&& ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) != ERC721TokenReceiver.onERC721Received.selector) {
revert UnsafeRecipient();
}
}
}
/// @notice A generic interface for a contract which properly accepts ERC721 tokens./// @dev Based on Solmate https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.solabstractcontractERC721TokenReceiver{
functiononERC721Received(address, address, uint, bytescalldata) externalvirtualreturns
(bytes4) {
return ERC721TokenReceiver.onERC721Received.selector;
}
}
Código Fuente del Contrato
Archivo 6 de 6: StakingPoolLibrary.sol
// SPDX-License-Identifier: GPL-3.0-onlypragmasolidity ^0.8.18;/**
* @dev Simple library to derive the staking pool address from the pool id without external calls
*/libraryStakingPoolLibrary{
functiongetAddress(address factory, uint poolId) internalpurereturns (address) {
bytes32 hash =keccak256(
abi.encodePacked(
hex'ff',
factory,
poolId, // salt// init code hash of the MinimalBeaconProxy// updated using patch-staking-pool-library.js scripthex'1eb804b66941a2e8465fa0951be9c8b855b7794ee05b0789ab22a02ee1298ebe'// init code hash
)
);
// cast last 20 bytes of hash to addressreturnaddress(uint160(uint(hash)));
}
}