gitcoin address: https://gitcoin.co/issue/29523
front-page address : https://hackathon-web3-storage.vercel.app/
youtube link : https://youtu.be/-cDZH83SQ6Y
Technology stack and dependencies that i used in this project:
- web3.storage platform
- next.js
- react.js
- tailwindcss
- solidity
- hardhat
- ether.js
- openzeppelin(ERC721)
- ploygon test net Mumbai
This is a gitcoin hackathon NFTs project based on web3.storage and other dependencies above.User can mint a NFT which is generate by themself.
Users can generate a unique svg avatar image by choosing various attributes.After click the attributes buttons you can get the result avatar image real-time because of react hooks.Furthormore, you can upload the image which is generated by yourself to our web3.storage platform.Once the upload process is finished,js sdk return a CID which is a IPFS address to our browser client.Finnaly we can mint the NFT with the cid and the attributes config json.
You can view your mint result on OpenSea test net like this:
smart contract address
Ploygon Mumbai: 0xDe3C417aDc211e0b0a4140BA704a333E3A824dBF
smart contract content
https://github.com/coffiasd/hackathon-web3-storage/blob/main/contract/contracts/W3s.sol
install hardhat tools
cd contract
npm install
set hardhat.config.js file
module.exports = {
solidity: "0.8.9",
networks: {
mumbai: {
url: process.env.TESTNET_RPC,
accounts: [process.env.PRIVATE_KEY]
},
},
etherscan: {
apiKey: {
polygonMumbai: process.env.POLYGONSCAN_API_KEY
}
}
};
deploy smart contract to mumbai net using hardhat tool
npx hardhat --network mumbai run ./script/deploy.js
After deploy the smart contract we'll get a contract address which is used in front-end config file.Furthormore we'll generate a ABI json file,move it to front-end utils directory. https://github.com/coffiasd/hackathon-web3-storage/blob/main/utils/mint.json
Team member
- front-end:@coffiasd
- back-end:@coffiasd
- ui/ux:@coffiasd
Contact
- mail: coiiasd88@gmail.com
- twitter: @coffiasse
- github: @coffiasd
https://github.com/coffiasd/hackathon-web3-storage/blob/main/components/AvatarEditor.js
init a new client instance with env config token
/// get web3.storage config token
function getAccessToken() {
return process.env.NEXT_PUBLIC_WEB3_STORAGE_TOKEN
}
/// get a new web3.storage client
function makeStorageClient() {
return new Web3Storage({ token: getAccessToken() })
}
store user image
/// store your pic
async function storeWithProgress() {
// set btn state
setIsLoading("loading");
setUpLoadBtn("uploading");
//get image info
const scale = 2;
const node = document.getElementById("myAvatar");
const blob = await domtoimage.toBlob(node, {
height: node.offsetHeight * scale,
style: {
transform: `scale(${scale}) translate(${node.offsetWidth / 2 / scale}px, ${node.offsetHeight / 2 / scale}px)`,
"border-radius": 0
},
width: node.offsetWidth * scale
});
//set loading timeout
setTimeout(() => {
setIsLoading("");
}, 7000);
//add file
const files = [
new File([blob], 'avatar.png'),
]
// when each chunk is stored, update the percentage complete and display
const totalSize = files.map(f => f.size).reduce((a, b) => a + b, 0)
let uploaded = 0
const onStoredChunk = size => {
uploaded += size
const pct = 100 * (uploaded / totalSize)
console.log(`Uploading... ${pct.toFixed(2)}% complete`)
//change btn state
setIsLoading("");
setReadyMint(true);
alertService.info("upload success", options);
}
// show the root cid as soon as it's ready
const onRootCidReady = (cid) => {
setCid(cid);
console.log('uploading files with cid:', cid)
}
// makeStorageClient returns an authorized web3.storage client instance
const client = makeStorageClient()
// client.put will invoke our callbacks during the upload
// and return the root cid when the upload completes
return client.put(files, { onRootCidReady, onStoredChunk })
}
get file status by cid
/// check <cid> status
async function checkStatus() {
setStatusIsLoading("loading");
const client = makeStorageClient()
const status = await client.status(cid)
console.log(status);
if (status) {
alertService.info("Status:" + status.pins[0].status + ",PeerId:" + status.pins[0].peerId, options);
} else {
alertService.info("not ready", options);
}
setStatusIsLoading("");
}