-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
c8c3e06
commit da63c60
Showing
12 changed files
with
346 additions
and
98 deletions.
There are no files selected for viewing
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,89 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.20; | ||
|
||
import "@openzeppelin/contracts/utils/Strings.sol"; | ||
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; | ||
import "@openzeppelin/contracts/utils/Base64.sol"; | ||
|
||
contract MyNFT is ERC721URIStorage { | ||
uint256 private _tokenId = 0; | ||
|
||
string[] zeekColors = [ | ||
"#FF5733", | ||
"#FFBD33", | ||
"#FFFF33", | ||
"#33FF57", | ||
"#33FFF6", | ||
"#3380FF", | ||
"#8E33FF", | ||
"#FF33F0", | ||
"#FF33B8", | ||
"#FF3384", | ||
"#FFC133", | ||
"#D4FF33", | ||
"#33FFAC", | ||
"#33FFDA", | ||
"#333EFF", | ||
"#FF5A33", | ||
"#FF33A5", | ||
"#FF3358", | ||
"#FFF633", | ||
"#AFFF33" | ||
]; | ||
event NewNFTMinted(address sender, uint256 tokenId); | ||
|
||
constructor() ERC721 ("ZeekNFT", "ZEEKS") {} | ||
|
||
function pickColor(uint256 tokenId) public view returns (string memory) { | ||
uint256 rand = fakeRandom(string(abi.encodePacked("ZEEK_SWEATER_COLOR", Strings.toString(tokenId)))); | ||
rand = rand % zeekColors.length; | ||
return zeekColors[rand]; | ||
} | ||
|
||
function fakeRandom(string memory input) internal pure returns (uint256) { | ||
return uint256(keccak256(abi.encodePacked(input))); | ||
} | ||
|
||
function mintZeek() public { | ||
uint256 newItemId = _tokenId; | ||
string memory color = pickColor(newItemId); | ||
string memory finalSvg = getZeekSVG(color); | ||
string memory json = Base64.encode( | ||
bytes( | ||
string( | ||
abi.encodePacked( | ||
'{"name": "', | ||
abi.encodePacked("Zeek NFT"), | ||
'", "image": "data:image/svg+xml;base64,', | ||
Base64.encode(bytes(finalSvg)), | ||
'"}' | ||
) | ||
) | ||
) | ||
); | ||
|
||
bytes memory encoded = abi.encodePacked("data:application/json;base64,", json); | ||
string memory finalTokenUri = string(encoded); | ||
|
||
_mint(msg.sender, newItemId); | ||
|
||
_setTokenURI(newItemId, finalTokenUri); | ||
|
||
_tokenId = _tokenId + 1; | ||
|
||
emit NewNFTMinted(msg.sender, newItemId); | ||
} | ||
|
||
function getZeekSVG(string memory color) internal pure returns (string memory){ | ||
string memory a = | ||
'<svg viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg"> <g transform="matrix(1, 0, 0, 1, 1.7300360202789307, 4.777588844299316)"> <path style="stroke: rgb(38, 33, 34); fill: '; | ||
string memory b = | ||
'; stroke-width: 10px;" d="M 64.317 163.963 C 64.317 163.963 59.978 128.007 59.978 127.786 C 59.978 127.564 52.664 91.336 53.195 73.015 C 53.776 52.98 63.985 13.806 63.985 13.806 L 90.85 22.9 C 90.85 22.9 120.743 34.328 129.305 40.744 C 160.276 63.949 163.142 80.444 163.302 80.444 C 163.463 80.444 123.677 105.362 123.677 105.362 L 88.557 135.994 L 64.317 163.963 Z"> <title>Left Ear</title> </path> <path style="stroke: rgb(38, 33, 34); fill: '; | ||
string memory c = | ||
'; stroke-width: 10px; transform-box: fill-box; transform-origin: 50% 50%;" d="M 346.378 12.887 C 346.378 12.887 342.039 48.843 342.039 49.065 C 342.039 49.287 334.725 85.514 335.256 103.835 C 335.838 123.87 346.047 163.045 346.047 163.045 L 372.911 153.95 C 372.911 153.95 402.804 142.522 411.367 136.106 C 442.337 112.901 445.203 96.406 445.364 96.406 C 445.524 96.406 405.738 71.488 405.738 71.488 L 370.618 40.856 L 346.378 12.887 Z" transform="matrix(-1, 0, 0, -1, -0.00004, -0.000042)"> <title>Left Ear</title> </path> <ellipse style="paint-order: stroke; stroke: rgb(38, 33, 34); stroke-width: 18px; fill: rgb(255, 211, 146);" cx="249.094" cy="270.025" rx="222.913" ry="203.58"> <title>Head</title> </ellipse> <path class="cls-19" d="M 218.858 336.829 C 212.799 341.366 207.077 346.444 200.644 350.373 C 185.543 359.614 168.819 363.035 151.212 362.459 C 128.799 360.189 109.399 351.691 93.792 335.135 C 81.703 322.338 74.084 307.136 71.272 290.037 C 66.092 258.346 76.084 231.497 99.781 209.894 C 111.733 199.027 125.921 192.051 141.868 189.65 C 180.298 183.892 214.291 199.569 233.52 234.272 C 235.18 237.288 236.433 238.304 240.19 237.321 C 248.012 235.289 256.036 235.526 264.06 237.965 C 269.716 225.911 277.638 215.753 287.93 207.593 C 304.182 194.761 322.464 188.33 343.489 188.668 C 370.102 189.108 391.907 199.162 408.938 219.24 C 422.512 235.257 429.151 253.844 429.084 275.175 C 428.981 308.524 414.119 333.104 386.524 350.609 C 377.28 356.466 366.954 359.818 356.12 361.511 C 355.205 361.645 354.359 362.086 353.478 362.391 C 340.138 362.661 326.968 362.459 314.138 357.788 C 302.014 353.351 291.383 346.883 282.175 337.946 C 281.158 336.963 280.041 336.117 278.991 335.236 C 271.407 326.603 265.178 317.123 261.217 306.255 C 257.084 294.945 254.95 283.3 255.357 271.212 C 255.392 269.79 254.716 267.625 253.701 267.047 C 249.028 264.474 243.339 267.827 243.645 273.041 C 244.526 288.988 240.935 303.884 233.012 317.598 C 229.256 324.133 224.311 329.987 219.91 336.117 L 219.943 336.117 C 219.605 336.321 219.301 336.558 218.961 336.793 L 218.858 336.829 Z M 201.253 213.384 C 200.948 213.079 200.678 212.808 200.373 212.504 C 200.033 212.097 199.798 211.554 199.357 211.25 C 181.989 199.333 162.521 196.115 142.443 199.974 C 117.119 204.852 98.359 219.544 87.355 243.076 C 78.013 263.017 77.436 283.435 86.001 303.918 C 87.187 306.83 88.033 309.979 89.626 312.654 C 103.81 336.151 124.498 349.865 151.957 352.03 C 174.64 353.791 194.618 346.139 210.633 330.158 C 228.951 311.807 236.534 289.327 232.504 263.424 C 229.425 243.618 220.451 227.095 203.963 215.109 C 203.589 214.805 203.219 214.5 202.845 214.196 L 202.879 214.196 C 202.304 213.925 201.727 213.654 201.152 213.348 L 201.219 213.348 L 201.253 213.384 Z M 387.439 213.348 C 387.065 212.977 386.794 212.469 386.355 212.165 C 369.425 199.907 350.163 196.421 330.151 199.466 C 288.233 205.834 260.471 245.514 266.565 286.109 C 267.582 292.779 270.323 299.213 272.253 305.747 L 272.253 305.68 C 272.525 306.425 272.829 307.136 273.1 307.88 C 276.893 313.872 279.973 320.441 284.545 325.759 C 308.99 354.232 350.296 361.035 382.124 341.096 C 407.514 325.181 420.178 301.822 418.824 271.313 C 418.113 255.4 412.73 241.383 403.419 228.755 C 399.457 223.37 395.701 217.549 388.894 215.109 C 388.387 214.533 387.911 213.96 387.403 213.384 L 387.439 213.348 Z M 257.592 256.685 C 258.1 254.825 258.507 252.625 259.252 250.558 C 260.201 247.884 258.845 246.596 256.61 246.564 C 251.228 246.461 245.846 246.767 239.714 246.902 C 240.73 251.1 241.477 254.149 242.086 256.685 L 257.592 256.685 Z" style="fill: '; | ||
string memory d = | ||
';"> <title>Glasses</title> </path> <path class="cls-20" d="M 257.219 367.402 C 256.951 373.834 260.438 377.321 268.09 377.525 C 274.927 377.695 281.835 377.321 288.64 376.679 C 293.79 376.205 297.377 371.636 297.681 366.151 C 297.951 361.137 299.136 359.749 302.962 359.818 C 306.62 359.886 308.008 361.645 307.804 366.52 C 307.364 377.118 300.119 385.991 289.181 386.836 C 280.92 387.48 272.557 387.345 264.296 386.666 C 260.201 386.328 256.24 383.958 251.669 382.298 C 240.359 389.308 227.02 388.429 213.682 386.905 C 202.065 385.584 195.16 374.378 195.262 365.744 C 195.296 361.782 197.158 359.918 200.644 359.818 C 204.775 359.681 205.454 362.052 205.454 365.506 C 205.419 371.6 210.091 376.611 216.217 376.78 C 223.973 376.982 231.726 376.95 239.479 376.78 C 244.627 376.645 247.232 373.091 246.556 367.434 C 243.815 367.434 241.004 367.503 238.228 367.434 C 232.437 367.266 228.305 364.084 226.749 358.665 C 225.462 354.266 230.336 347.392 235.485 347.256 C 246.183 346.952 256.914 346.952 267.614 347.256 C 272.626 347.392 276.013 352.301 275.808 357.788 C 275.574 363.306 271.509 367.064 265.178 367.434 C 262.671 367.571 260.133 367.434 257.254 367.434 L 257.219 367.402 Z" style="fill: rgb(37, 33, 34);"> <title>Mouth</title> </path> </g> </svg>'; | ||
|
||
return string(abi.encodePacked(a, color, b, color, c, color, d)); | ||
} | ||
} |
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,25 @@ | ||
import { Wallet, Provider } from 'zksync-ethers'; | ||
import type { HardhatRuntimeEnvironment } from 'hardhat/types'; | ||
import { Deployer } from '@matterlabs/hardhat-zksync-deploy'; | ||
|
||
// load env file | ||
import dotenv from 'dotenv'; | ||
dotenv.config(); | ||
|
||
const DEPLOYER_PRIVATE_KEY = process.env.WALLET_PRIVATE_KEY || ''; | ||
|
||
export default async function (hre: HardhatRuntimeEnvironment) { | ||
// @ts-expect-error target config file which can be testnet or local | ||
const provider = new Provider(hre.network.config.url); | ||
const wallet = new Wallet(DEPLOYER_PRIVATE_KEY, provider); | ||
const deployer = new Deployer(hre, wallet); | ||
const artifact = await deployer.loadArtifact('MyNFT'); | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const constructorArguments: any[] = []; | ||
const contract = await deployer.deploy(artifact, constructorArguments); | ||
console.log('CONTRACT ADDRESS: ', await contract.getAddress()); | ||
|
||
const tx = await contract.mintZeek(); | ||
await tx.wait(); | ||
console.log('DONE MINTING: '); | ||
} |
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
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,92 @@ | ||
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
import { Provider } from 'zksync-ethers'; | ||
import { getDataToSign, signAndSend } from '../../utils/sign'; | ||
import { getTransaction } from '../../utils/getTransaction'; | ||
import React from 'react'; | ||
import { Layout } from '../components/Layout'; | ||
import { buttonStyles } from '.'; | ||
import { containerStyles } from './register'; | ||
import { ethers } from 'ethers'; | ||
import { authenticate } from '../../utils/webauthn'; | ||
import * as NFT_ABI_JSON from '../../../contracts/artifacts-zk/contracts/MyNFT.sol/MyNFT.json'; | ||
|
||
// Update this with your deployed smart contract account address and NFT contract address | ||
const ACCOUNT_ADDRESS = '0x<YOUR_ACCOUNT_ADDRESS>'; | ||
const NFT_CONTRACT_ADDRESS = '0x<YOUR_NFT_CONTRACT_ADDRESS>'; | ||
|
||
export default function Mint() { | ||
const [mintedSVG, setMintedSVG] = React.useState<string | null>(null); | ||
const provider = new Provider('http://localhost:8011'); | ||
|
||
async function mint(e: any) { | ||
e.preventDefault(); | ||
try { | ||
const contract = new ethers.Contract(NFT_CONTRACT_ADDRESS, NFT_ABI_JSON.abi, provider); | ||
const functionName = 'mintZeek'; | ||
const functionArgs: any[] = []; | ||
const data = contract.interface.encodeFunctionData(functionName, functionArgs); | ||
const transferValue = '0'; | ||
const tx = await getTransaction(NFT_CONTRACT_ADDRESS, ACCOUNT_ADDRESS, transferValue, data, provider); | ||
const signedTxHash = getDataToSign(tx); | ||
const authResponse = await authenticate(signedTxHash.toString()); | ||
const receipt = await signAndSend(provider, tx, authResponse); | ||
console.log('RECEIPT:', receipt); | ||
const foundLog = receipt.logs.find((log: any) => { | ||
try { | ||
const parsedLog = contract.interface.parseLog(log); | ||
if (parsedLog.name === 'NewNFTMinted') { | ||
return true; | ||
} | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
} catch (_error) { | ||
// ignore error | ||
} | ||
return false; | ||
}); | ||
const dataFromLog = foundLog?.data; | ||
const parsedData = dataFromLog ? contract.interface.decodeEventLog('NewNFTMinted', dataFromLog) : null; | ||
const nftURI = await contract.tokenURI(parsedData?.tokenId); | ||
const prefix = 'data:application/json;base64,'; | ||
const base64NFTData = nftURI.slice(prefix.length); | ||
const json = atob(base64NFTData); | ||
const svg = JSON.parse(json).image; | ||
setMintedSVG(svg); | ||
} catch (error) { | ||
console.log('ERROR:', error); | ||
} | ||
} | ||
|
||
return ( | ||
<Layout> | ||
<div style={{ ...containerStyles, marginBottom: '2rem' }}> | ||
<button | ||
style={buttonStyles} | ||
onClick={mint} | ||
> | ||
Mint a Zeek NFT | ||
</button> | ||
</div> | ||
{mintedSVG && ( | ||
<> | ||
<h3 style={{ textAlign: 'center' }}>🎉 You minted a ZEEK NFT! 🎉</h3> | ||
<div | ||
style={{ | ||
display: 'flex', | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
flexDirection: 'column', | ||
maxWidth: '400px', | ||
maxHeight: '400px', | ||
margin: '2rem auto', | ||
}} | ||
> | ||
<img | ||
src={mintedSVG} | ||
alt="Minted NFT" | ||
/> | ||
</div> | ||
</> | ||
)} | ||
</Layout> | ||
); | ||
} |
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
Oops, something went wrong.