From 8662902bc73669be1264b30838d94c310e94bf84 Mon Sep 17 00:00:00 2001 From: manangouhari <31039184+manangouhari@users.noreply.github.com> Date: Sat, 6 Mar 2021 03:05:45 +0530 Subject: [PATCH] Store Cryptobot images to IPFS, and token metadata (#214) * progress on saving image to bot metadata * storing bot image to token metadata, 90% done. * feat: update contract to edonet * feat: implement api endpoint for uploading json * feat: update indexer logic Co-authored-by: Bhaskar Singh --- src/defaults.js | 7 +- src/pages/auth.js | 9 +- src/pages/tezos/claim-transaction.js | 14 ++- src/pages/tezos/customizebot.js | 153 ++++++++++++++++++++------- src/utils/indexer.js | 65 ++++++++---- src/utils/wallet.js | 15 +-- 6 files changed, 173 insertions(+), 90 deletions(-) diff --git a/src/defaults.js b/src/defaults.js index 761a3ae2..cf12153c 100644 --- a/src/defaults.js +++ b/src/defaults.js @@ -1,6 +1,9 @@ +import { NetworkType } from '@airgap/beacon-sdk'; +// NetworkType.DELPHINET : NetworkType.MAINNET; export const APP_NAME = 'Cryptocodeschool'; // allowed: 'mainnet', 'carthagenet', 'labnet' or 'sandbox'(http://localhost:8732) https://delphinet.smartpy.io -export const NETWORK = 'delphinet'; +export const NETWORK = NetworkType.EDONET; +export const INDEXER_NETWORK = 'edo2net'; -export const CONTRACT_ADDRESS = 'KT19XZU3pRi6fd1dZinsXDGoKe2QdrU9ePjk'; +export const CONTRACT_ADDRESS = 'KT1CTXcSov9xMmQjrKYw5KYP9BbB4v8SqrkQ'; diff --git a/src/pages/auth.js b/src/pages/auth.js index cca96f3a..de5e4bc5 100644 --- a/src/pages/auth.js +++ b/src/pages/auth.js @@ -15,16 +15,11 @@ import { verifyUser, batchUpdateProgress, } from '../api'; -import { NetworkType } from '@airgap/beacon-sdk'; import { Magic } from 'magic-sdk'; import { NETWORK } from 'src/defaults'; import { MdClose } from 'react-icons/md'; -// To connect to Delphinet, change this to NetworkType.DELPHINET -const network = - NETWORK === 'delphinet' ? NetworkType.DELPHINET : NetworkType.MAINNET; - function isBrowserSupported() { if (typeof window !== 'undefined') { const chrome = @@ -313,7 +308,7 @@ const AuthPage = ({ location }) => { async function connectWallet() { const acc = await beacon.client.getActiveAccount({ network: { - type: network, + type: NETWORK, }, }); console.log(acc); @@ -325,7 +320,7 @@ const AuthPage = ({ location }) => { try { const resp = await beacon.client.requestPermissions({ network: { - type: network, + type: NETWORK, }, }); if (!resp.address) throw new Error(); diff --git a/src/pages/tezos/claim-transaction.js b/src/pages/tezos/claim-transaction.js index c686764a..ca1f1f22 100644 --- a/src/pages/tezos/claim-transaction.js +++ b/src/pages/tezos/claim-transaction.js @@ -146,7 +146,8 @@ function Transaction({ location }) { const [opHash, setOpHash] = useState(null); const [networkFeeEstimate, setNetworkFeeEstimate] = useState(0); // const xtzPrice = location.state ? location.state.xtzPrice : null; - const uri = location.state ? location.state.uri : false; + const modelURI = location.state ? location.state.modelURI : null; + const jsonURI = location.state ? location.state.jsonURI : null; console.log(location.state); const { width, height } = useWindowSize(); const [xtzPrice, updateXtzPrice] = useState(null); @@ -205,7 +206,7 @@ function Transaction({ location }) { await connectToBeacon(beacon); const metadata = MichelsonMap.fromLiteral({ - uri: uri, + '': jsonURI, }); const RnId = (deepness = 10) => @@ -265,7 +266,9 @@ function Transaction({ location }) { style={{ width: '100%', height: '100%' }} camera-controls alt="3D Cryptobot" - src={`https://cloudflare-ipfs.com/ipfs/${uri ? uri : ''}`} + src={`https://cloudflare-ipfs.com/ipfs/${ + modelURI ? modelURI : '' + }`} >
@@ -517,11 +520,6 @@ function Transaction({ location }) {
- {!uri && ( -
- -
- )} ); } diff --git a/src/pages/tezos/customizebot.js b/src/pages/tezos/customizebot.js index 5a6d63e9..50d3964b 100644 --- a/src/pages/tezos/customizebot.js +++ b/src/pages/tezos/customizebot.js @@ -8,7 +8,7 @@ import React, { import NavBar from '../../components/NavBar'; import Button from '../../components/Buttons'; import { navigate, Link } from 'gatsby'; -import { Canvas, useFrame } from 'react-three-fiber'; +import { Canvas, useFrame, useThree } from 'react-three-fiber'; import { ContactShadows, Environment, @@ -30,7 +30,6 @@ import cryptobots from 'src/images/crypto-modal.png'; import GLTFExporter from 'three-gltf-exporter'; -import { NetworkType } from '@airgap/beacon-sdk'; import { NETWORK } from 'src/defaults'; import ChevronRightIcon from '@material-ui/icons/ChevronRight'; @@ -38,8 +37,6 @@ import { BeaconContext } from 'src/context/beacon-context'; import { createUser, batchUpdateProgress } from 'src/api'; import { trackEvent } from 'src/utils/analytics'; -const network = - NETWORK === 'delphinet' ? NetworkType.DELPHINET : NetworkType.MAINNET; import head1 from '../../assets/CryptobotImages/Head/01xhead.png'; import head2 from '../../assets/CryptobotImages/Head/02xhead.png'; import head3 from '../../assets/CryptobotImages/Head/03xhead.png'; @@ -156,7 +153,7 @@ const Bot = ({ onPointerMissed={() => (state.current = null)} onPointerDown={e => { e.stopPropagation(); - console.log(e.object.name); + setBotColors(current => { const copy = { ...current }; copy.current = getMeshName(e.object.name); @@ -231,7 +228,7 @@ const WelcomeModal = ({ close, isUser }) => { let acc = await beacon.client.getActiveAccount({ network: { - type: network, + type: NETWORK, }, }); @@ -298,6 +295,18 @@ const WelcomeModal = ({ close, isUser }) => { ); }; +const CustomAmbientLight = ({ setImage, grabImage }) => { + const canvas = useThree().gl.domElement; + + useEffect(() => { + if (grabImage) { + setImage(canvas.toDataURL('image/png')); + } + }, [grabImage]); + + return ; +}; + const Customizer = () => { const [selectPart, setselectPart] = useState(1); const [headCount, setHeadCount] = useState(0); @@ -306,7 +315,9 @@ const Customizer = () => { const [legCount, setLegCount] = useState(0); const [isModalOpen, setIsModalOpen] = useState(true); - + const [claimButtonClicked, setClaimButtonClicked] = useState(false); + const [image, setImage] = useState(''); + const [grabImage, setGrabImage] = useState(false); const [showSavingBotModel, setShowSavingBotModel] = useState(false); const [shininess, setShininess] = useState(0); const [showColorPicker, updateShowColorPicker] = useState(false); @@ -365,8 +376,35 @@ const Customizer = () => { }, }); + function uploadData() { + upload3dModel( + state.items.head, + state.items.arm, + state.items.body, + state.items.leg, + ); + } + const [isUser] = useAtom(isUserAtom); + useEffect(() => { + if (claimButtonClicked) { + /* + 1. Upload 3d model to ipfs. + 2. Upload Cryptobot image to ipfs + 3. Navigate to /claim-transaction with ipfsHash of image and 3d model as state + */ + setGrabImage(true); + } + }, [claimButtonClicked]); + + useEffect(() => { + if (image !== '') { + // console.log('image -> ', image); + uploadData(); + } + }, [image]); + const getMeshName = name => { const filterType = Object.keys(botColors.items); @@ -454,33 +492,72 @@ const Customizer = () => { { binary: true }, ); - function upload(blob) { + async function upload(blob) { setShowSavingBotModel(true); - var fd = new FormData(); - // fd.append('bot', blob, 'bot.glb'); - fd.append('file', blob); - fetch( + + var fdModel = new FormData(); + + fdModel.append('file', blob); + const res = await fetch( 'https://cryptoverse-wars-backend-nfjp.onrender.com/api/upload-3d-model-to-ipfs', { method: 'post', - body: fd, + body: fdModel, }, - ) - .then(res => { - // console.log(res) - return res.json(); - }) - .then(res => { - console.log(res.body.ipfsHash); - console.log('yo', res); - navigate('/tezos/claim-transaction', { - state: { uri: res.body.ipfsHash }, - }); - }) - .catch(err => { - console.log(err); - setShowSavingBotModel(false); - }); + ); + + const resJSON = await res.json(); + + var fdImage = new FormData(); + // console.log('img before converting to blob 🔥->', image); + const imageBlob = new Blob([image], { + type: 'image/png', + }); + // console.log('blob 🔥', imageBlob); + fdImage.append('file', imageBlob); + // console.log('fdImage 🔥', fdImage); + // ('https://cryptoverse-wars-backend-nfjp.onrender.com/api/upload-image-to-ipfs'); + const resImage = await fetch( + 'https://cryptoverse-wars-backend-nfjp.onrender.com/api/upload-image-to-ipfs', + { + method: 'post', + body: fdImage, + }, + ); + + const resImageJSON = await resImage.json(); + + // console.log('resImageJSON', resImageJSON); + // console.log('resJSON', resJSON); + + const resMetadata = await fetch( + 'https://cryptoverse-wars-backend-nfjp.onrender.com/api/upload-json-metadata-to-ipfs', + { + method: 'post', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + artifactURI: resJSON.body.ipfsHash, + displayURI: resImageJSON.body.ipfsHash, + }), + }, + ); + + const jsonMetadata = await resMetadata.json(); + + // console.log('jsonMetadata', jsonMetadata); + + // console.log('3d model hash --> 🔥', await resJSON.body.ipfsHash); + // console.log('image hash -> 🔥', await resImageJSON.body.ipfsHash); + // console.log('yo', await resJSON); + navigate('/tezos/claim-transaction', { + state: { + modelURI: resJSON.body.ipfsHash, + jsonURI: jsonMetadata.ipfsHash, + }, + }); } }; @@ -791,8 +868,13 @@ const Customizer = () => { concurrent pixelRatio={[1, 1.5]} camera={{ position: [0, 0, 5.75], fov: 80 }} + gl={{ preserveDrawingBuffer: true }} > - + { namedColors[ Math.floor(Math.random() * namedColors.length) ]; - console.log(elm, item); + copy.items[elm] = item.hex; }); return copy; @@ -850,18 +932,12 @@ const Customizer = () => {