Hi all, I am trying to figure out why my webform can’t upload a jpg to IPFS. Quick details: react-dropzone for frontend webform & nft.storage (this an NFTHack project) for IPFS pinning.
When I upload an image via nft.storage/new-file/ everything works as expected (~5MB): ipfs://bafybeidndzo5rwfe4a7ryhbnriiffp5nwy72cz63un6xytuifrlz3lm3t4/
When using my broken code, it seems that the hash of the image is the only thing written to IPFS (~12MB):
ipfs://bafybeiffhp3sfb4qa4o5t63po6prxvvskrkpxlnx32muvqdthtlekby6fe/
(these both used the same .jpg from my computer, so I have absolutely no idea why the text-only upload is twice the size?)
I’m pretty new to programming in general so I’m just going to copy/paste the parts that I think might be causing this trouble.
web3.js
const getFileBuffer = async (file) => { return new Promise((res, rej) => { let reader = new FileReader(); reader.addEventListener("loadend", (e) => res(e.target.result)); reader.addEventListener("error", rej); reader.readAsArrayBuffer(file); });
};
//…
const mintMedia = async (media, name, description, royalty, royalties) => {console.log(royalties); const metadataJSON = generateMetadata("zora-20210101", { description: description, mimeType: media.type, name: name, version: "zora-20210101", }); const mediaBuffer = await getFileBuffer(media); const contentHash = sha256FromBuffer(Buffer.from(mediaBuffer)); const metadataHash = sha256FromBuffer(Buffer.from(metadataJSON)); let formData = new FormData(); formData.append("media", media); formData.append("name", name); formData.append("metadata", metadataJSON); const upload = await axios.post("/api/upload", formData, { headers: { "Content-Type": "multipart/form-data", }, }); const { mediaCID, metadataCID } = upload.data; const mediaUrl = `https://${mediaCID}.ipfs.dweb.link`; const metadataUrl = `https://${metadataCID}.ipfs.dweb.link`; const mediaData = constructMediaData( mediaUrl, metadataUrl, contentHash, metadataHash );
/pages/mint.js
const Mint = () => {
const { acceptedFiles, getRootProps, getInputProps } = useDropzone({
maxFiles: 1,
});
const [loading, setLoading] = useState(false);
const { mintMedia } = web3.useContainer();
const router = useRouter();
const { address } = router.query;
const { control, register, handleSubmit, errors } = useForm();
const { fields, append, remove } = useFieldArray({
control, name: "royalties",
});
const onSubmit = async (data) => {
setLoading(true); try { await mintMedia( acceptedFiles[0], data.name, data.description, data.royalty, data.royalties ); router.push(`/${address}/success`); } catch (e) { console.log(e); } setLoading(false);
};
const onAppend = () => append({ collaborator: “”, shares: “” });
/pages/api/upload.js
import { NFTStorage, Blob } from “nft.storage”;
import { promisify } from “util”;
import fs from “fs”;
import formidable from “formidable”;
const readFileAsync = promisify(fs.readFile);
const handler = async (req, res) => {
const form = new formidable.IncomingForm({ keepExtensions: true });
console.log(“line11”);
const data = await new Promise((res, rej) => {
form.parse(req, (err, fields, files) => { if (err) return rej(err); console.log("line16"); res({ fields, files }); console.log("line18"); });
});
const { metadata, name } = data.fields;
const { media } = data.files;
const mediaData = await readFileAsync(media.path);
console.log(“done reading media”);
if (mediaData && metadata && name) {
const client = new NFTStorage({ token: process.env.NFT_STORAGE_KEY }); const mediaContent = new Blob(mediaData); const mediaCID = await client.storeBlob(mediaContent); const metadataContent = new Blob(metadata); const metadataCID = await client.storeBlob(metadataContent); res.send({ mediaCID, metadataCID });
} else {
res.status(501);
}
};
export const config = {
api: {
bodyParser: false,
},
};
If that’s not enough info, the whole project can be viewed here.
I really think the mimetype needs to be appended somewhere but I have no clue where to do that.