-
Notifications
You must be signed in to change notification settings - Fork 230
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: xp nfts contract skeleton #164
Merged
Merged
Changes from 10 commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
e50d2ae
ZetaXP
andresaiello 98b7744
add test
andresaiello d65cb8d
add test
andresaiello 3825781
Update packages/zevm-app-contracts/test/xp-nft/xp-nft.ts
andresaiello 63cd619
Update packages/zevm-app-contracts/contracts/xp-nft/xpNFT.sol
andresaiello 3888ee9
Update packages/zevm-app-contracts/contracts/xp-nft/xpNFT.sol
andresaiello b6cf391
renames
andresaiello 5108de2
rename and add logic
andresaiello d288a04
refactor
andresaiello ec6702b
add upgradable
andresaiello aec9cbe
Update packages/zevm-app-contracts/test/xp-nft/xp-nft.ts
andresaiello 2c36fc1
renames and test
andresaiello File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
10 changes: 10 additions & 0 deletions
10
packages/zevm-app-contracts/contracts/xp-nft/test/xpNFTV2.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.7; | ||
|
||
import "../xpNFT.sol"; | ||
|
||
contract ZetaXPV2 is ZetaXP { | ||
function version() public pure override returns (string memory) { | ||
return "2.0.0"; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.7; | ||
|
||
import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; | ||
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; | ||
|
||
contract ZetaXP is ERC721Upgradeable, OwnableUpgradeable { | ||
/* An ECDSA signature. */ | ||
struct Signature { | ||
uint8 v; | ||
bytes32 r; | ||
bytes32 s; | ||
} | ||
|
||
struct UpdateData { | ||
address to; | ||
uint256 tokenId; | ||
Signature signature; | ||
uint256 sigTimestamp; | ||
uint256 signedUp; | ||
} | ||
|
||
mapping(uint256 => uint256) lastUpdateTimestampByTokenId; | ||
mapping(uint256 => uint256) signedUpByTokenId; | ||
|
||
// Base URL for NFT images | ||
string public baseTokenURI; | ||
address public signerAddress; | ||
|
||
// Event for New Mint | ||
event NewNFTMinted(address indexed sender, uint256 indexed tokenId); | ||
// Event for NFT Update | ||
event NFTUpdated(address indexed sender, uint256 indexed tokenId); | ||
|
||
error InvalidSigner(); | ||
error LengthMismatch(); | ||
error TransferNotAllowed(); | ||
error OutdatedSignature(); | ||
|
||
function initialize( | ||
string memory name, | ||
string memory symbol, | ||
string memory baseTokenURI_, | ||
address signerAddress_ | ||
) public initializer { | ||
__ERC721_init(name, symbol); | ||
__Ownable_init(); | ||
baseTokenURI = baseTokenURI_; | ||
signerAddress = signerAddress_; | ||
} | ||
andresaiello marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
function version() public pure virtual returns (string memory) { | ||
return "1.0.0"; | ||
} | ||
|
||
// The following functions are overrides required by Solidity. | ||
function tokenURI(uint256 tokenId) public view override(ERC721Upgradeable) returns (string memory) { | ||
_requireMinted(tokenId); | ||
|
||
return string(abi.encodePacked(baseTokenURI, _uint2str(tokenId))); | ||
} | ||
Comment on lines
+57
to
+61
Check failure Code scanning / Slither ABI encodePacked Collision High
ZetaXP.tokenURI(uint256) calls abi.encodePacked() with multiple dynamic arguments:
- string(abi.encodePacked(baseTokenURI,Strings.toString(tokenId)))
andresaiello marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
function supportsInterface(bytes4 interfaceId) public view override(ERC721Upgradeable) returns (bool) { | ||
return super.supportsInterface(interfaceId); | ||
} | ||
|
||
// Helper function to convert uint to string | ||
function _uint2str(uint _i) internal pure returns (string memory _uintAsString) { | ||
if (_i == 0) { | ||
return "0"; | ||
} | ||
uint j = _i; | ||
uint len; | ||
while (j != 0) { | ||
len++; | ||
j /= 10; | ||
} | ||
bytes memory bstr = new bytes(len); | ||
uint k = len; | ||
while (_i != 0) { | ||
k = k - 1; | ||
uint8 temp = (uint8(48 + (_i % 10))); | ||
bstr[k] = bytes1(temp); | ||
_i /= 10; | ||
} | ||
return string(bstr); | ||
} | ||
|
||
function _verify(UpdateData memory updateData) private view { | ||
bytes32 payloadHash = _calculateHash(updateData); | ||
bytes32 messageHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", payloadHash)); | ||
|
||
address messageSigner = ecrecover( | ||
messageHash, | ||
updateData.signature.v, | ||
updateData.signature.r, | ||
updateData.signature.s | ||
); | ||
|
||
if (signerAddress != messageSigner) revert InvalidSigner(); | ||
if (updateData.sigTimestamp <= lastUpdateTimestampByTokenId[updateData.tokenId]) revert OutdatedSignature(); | ||
} | ||
|
||
// Function to compute the hash of the data and tasks for a token | ||
function _calculateHash(UpdateData memory updateData) private pure returns (bytes32) { | ||
bytes memory encodedData = abi.encode( | ||
updateData.to, | ||
updateData.tokenId, | ||
updateData.sigTimestamp, | ||
updateData.signedUp | ||
); | ||
|
||
return keccak256(encodedData); | ||
} | ||
|
||
function _updateNFT(UpdateData memory updateData) internal { | ||
_verify(updateData); | ||
lastUpdateTimestampByTokenId[updateData.tokenId] = updateData.sigTimestamp; | ||
signedUpByTokenId[updateData.tokenId] = updateData.signedUp; | ||
} | ||
|
||
// External mint function | ||
function mintNFT(UpdateData calldata mintData) external { | ||
_mint(mintData.to, mintData.tokenId); | ||
|
||
_updateNFT(mintData); | ||
|
||
emit NewNFTMinted(mintData.to, mintData.tokenId); | ||
} | ||
|
||
// External mint function | ||
function updateNFT(UpdateData memory updateData) external { | ||
address owner = ownerOf(updateData.tokenId); | ||
updateData.to = owner; | ||
_updateNFT(updateData); | ||
|
||
emit NFTUpdated(owner, updateData.tokenId); | ||
} | ||
|
||
// Set the base URI for tokens | ||
function setBaseURI(string calldata _uri) external onlyOwner { | ||
|
||
baseTokenURI = _uri; | ||
} | ||
|
||
function _transfer(address from, address to, uint256 tokenId) internal override { | ||
revert TransferNotAllowed(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; | ||
import { ethers } from "hardhat"; | ||
|
||
export interface Signature { | ||
r: string; | ||
s: string; | ||
v: number; | ||
} | ||
|
||
export interface NFT { | ||
signedUp: number; | ||
to: string; | ||
tokenId: number; | ||
} | ||
|
||
export interface UpdateParam extends NFT { | ||
sigTimestamp: number; | ||
signature: Signature; | ||
} | ||
|
||
export const getSignature = async ( | ||
signer: SignerWithAddress, | ||
timestamp: number, | ||
to: string, | ||
tokenId: number, | ||
nft: NFT | ||
) => { | ||
let payload = ethers.utils.defaultAbiCoder.encode( | ||
["address", "uint256", "uint256", "uint256"], | ||
[to, tokenId, timestamp, nft.signedUp] | ||
); | ||
|
||
const payloadHash = ethers.utils.keccak256(payload); | ||
|
||
// This adds the message prefix | ||
const signature = await signer.signMessage(ethers.utils.arrayify(payloadHash)); | ||
return ethers.utils.splitSignature(signature); | ||
}; | ||
andresaiello marked this conversation as resolved.
Show resolved
Hide resolved
|
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Check notice
Code scanning / Slither
Missing zero address validation Low