mirror of
https://github.com/vacp2p/staking-reward-streamer.git
synced 2026-01-09 21:18:01 -05:00
chore(XPNFTToken): add base XPNFTToken
This commit is contained in:
128
src/XPNFTToken.sol
Normal file
128
src/XPNFTToken.sol
Normal file
@@ -0,0 +1,128 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
import { Base64 } from "@openzeppelin/contracts/utils/Base64.sol";
|
||||
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
|
||||
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
|
||||
|
||||
interface IERC20 {
|
||||
function balanceOf(address account) external view returns (uint256);
|
||||
}
|
||||
|
||||
contract XPNFTToken is Ownable {
|
||||
error XPNFT__TransferNotAllowed();
|
||||
error XPNFT__InvalidTokenId();
|
||||
|
||||
string private _name = "XPNFT";
|
||||
string private _symbol = "XPNFT";
|
||||
string private _imagePrefix = "";
|
||||
string private _imageSuffix = "";
|
||||
|
||||
IERC20 private _xpToken;
|
||||
|
||||
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
|
||||
|
||||
modifier onlyValidTokenId(uint256 tokenId) {
|
||||
if (tokenId > type(uint160).max) {
|
||||
revert XPNFT__InvalidTokenId();
|
||||
}
|
||||
_;
|
||||
}
|
||||
|
||||
constructor(address xpTokenAddress, string memory imagePrefix, string memory imageSuffix) Ownable(msg.sender) {
|
||||
_xpToken = IERC20(xpTokenAddress);
|
||||
_imagePrefix = imagePrefix;
|
||||
_imageSuffix = imageSuffix;
|
||||
}
|
||||
|
||||
function setImageStrings(string memory imagePrefix, string memory imageSuffix) external onlyOwner {
|
||||
_imagePrefix = imagePrefix;
|
||||
_imageSuffix = imageSuffix;
|
||||
}
|
||||
|
||||
function name() external view returns (string memory) {
|
||||
return _name;
|
||||
}
|
||||
|
||||
function symbol() external view returns (string memory) {
|
||||
return _symbol;
|
||||
}
|
||||
|
||||
function mint() external {
|
||||
emit Transfer(msg.sender, msg.sender, uint256(uint160(msg.sender)));
|
||||
}
|
||||
|
||||
function balanceOf(address) external pure returns (uint256) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
function ownerOf(uint256 tokenId) external pure onlyValidTokenId(tokenId) returns (address) {
|
||||
address owner = address(uint160(tokenId));
|
||||
return owner;
|
||||
}
|
||||
|
||||
function safeTransferFrom(address, address, uint256, bytes calldata) external pure {
|
||||
revert XPNFT__TransferNotAllowed();
|
||||
}
|
||||
|
||||
function safeTransferFrom(address, address, uint256) external pure {
|
||||
revert XPNFT__TransferNotAllowed();
|
||||
}
|
||||
|
||||
function transferFrom(address, address, uint256) external pure {
|
||||
revert XPNFT__TransferNotAllowed();
|
||||
}
|
||||
|
||||
function approve(address, uint256) external pure {
|
||||
revert XPNFT__TransferNotAllowed();
|
||||
}
|
||||
|
||||
function setApprovalForAll(address, bool) external pure {
|
||||
revert XPNFT__TransferNotAllowed();
|
||||
}
|
||||
|
||||
function getApproved(uint256) external pure returns (address) {
|
||||
return address(0);
|
||||
}
|
||||
|
||||
function isApprovedForAll(address, address) external pure returns (bool) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function tokenURI(uint256 tokenId) external view onlyValidTokenId(tokenId) returns (string memory) {
|
||||
address owner = address(uint160(tokenId));
|
||||
return _createTokenURI(owner);
|
||||
}
|
||||
|
||||
function _createTokenURI(address owner) internal view returns (string memory) {
|
||||
string memory baseName = "XPNFT Token ";
|
||||
string memory baseDescription = "This is a XPNFT token for address ";
|
||||
uint256 balance = _xpToken.balanceOf(owner) / 1e18;
|
||||
|
||||
string memory propName = string(abi.encodePacked(baseName, Strings.toHexString(owner)));
|
||||
string memory propDescription = string(
|
||||
abi.encodePacked(baseDescription, Strings.toHexString(owner), " with balance ", Strings.toString(balance))
|
||||
);
|
||||
string memory image = _generateImage(balance);
|
||||
|
||||
bytes memory json = abi.encodePacked(
|
||||
"{\"name\":\"",
|
||||
propName,
|
||||
"\",\"description\":\"",
|
||||
propDescription,
|
||||
"\",\"image\":\"data:image/svg+xml;base64,",
|
||||
image,
|
||||
"\"}"
|
||||
);
|
||||
|
||||
string memory jsonBase64 = Base64.encode(json);
|
||||
return string(abi.encodePacked("data:application/json;base64,", jsonBase64));
|
||||
}
|
||||
|
||||
function _generateImage(uint256 balance) internal view returns (string memory) {
|
||||
string memory text = Strings.toString(balance);
|
||||
bytes memory svg = abi.encodePacked(_imagePrefix, text, _imageSuffix);
|
||||
|
||||
return Base64.encode(svg);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
import { Test, console } from "forge-std/Test.sol";
|
||||
import { Test } from "forge-std/Test.sol";
|
||||
import { RewardsStreamer } from "../src/RewardsStreamer.sol";
|
||||
import { MockToken } from "./mocks/MockToken.sol";
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
import { Test, console } from "forge-std/Test.sol";
|
||||
import { Test } from "forge-std/Test.sol";
|
||||
import { RewardsStreamerMP } from "../src/RewardsStreamerMP.sol";
|
||||
import { MockToken } from "./mocks/MockToken.sol";
|
||||
import "forge-std/console.sol";
|
||||
|
||||
contract RewardsStreamerMPTest is Test {
|
||||
MockToken rewardToken;
|
||||
|
||||
32
test/XPNFTToken.t.sol
Normal file
32
test/XPNFTToken.t.sol
Normal file
@@ -0,0 +1,32 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
import { Test, console } from "forge-std/Test.sol";
|
||||
import { MockToken } from "./mocks/MockToken.sol";
|
||||
import { XPNFTToken } from "../src/XPNFTToken.sol";
|
||||
|
||||
contract XPNFTTokenTest is Test {
|
||||
MockToken erc20Token;
|
||||
XPNFTToken nft;
|
||||
|
||||
address alice = makeAddr("alice");
|
||||
|
||||
string imagePrefix =
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" height="200" width="200"><rect width="100%" height="100%" fill="blue"/><text x="50%" y="50%" fill="white" font-size="20" text-anchor="middle">';
|
||||
string imageSuffix = "</text></svg>";
|
||||
|
||||
function setUp() public {
|
||||
erc20Token = new MockToken("Test", "TEST");
|
||||
nft = new XPNFTToken(address(erc20Token), imagePrefix, imageSuffix);
|
||||
|
||||
address[1] memory users = [alice];
|
||||
for (uint256 i = 0; i < users.length; i++) {
|
||||
erc20Token.mint(users[i], 10e18);
|
||||
}
|
||||
}
|
||||
|
||||
function test() public {
|
||||
string memory metadata = nft.tokenURI(uint256(uint160(alice)));
|
||||
console.log(metadata);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user