Skip to content

Commit

Permalink
🤖🌒 ↝ Merge pull request #10 from Signal-K/wb3-8-add-createpost-lib-co…
Browse files Browse the repository at this point in the history
…mponent

🤖🐤 ↝ Finished creating post lib/hook controller. Discovered issues wh…
  • Loading branch information
Gizmotronn authored Jan 9, 2023
2 parents c83a6cd + c950d66 commit 3bd30c5
Show file tree
Hide file tree
Showing 6 changed files with 277 additions and 49 deletions.
Binary file modified .DS_Store
Binary file not shown.
166 changes: 122 additions & 44 deletions lib/useCreatePost.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,125 @@
import { useMutation } from "@tanstack/react-query";
import { useSDK } from "@thirdweb-dev/react";
import { useCreatePostTypedDataMutation } from "../graphql/generated";
import { useSDK, useStorageUpload } from "@thirdweb-dev/react";
import { PublicationMainFocus, useCreatePostTypedDataMutation } from "../graphql/generated";
import useLensUser from "./auth/useLensUser";
import { signTypedDataWithOmittedTypename } from "./helpers";

export default function useCreatePost() {
const { mutateAsync: requestTypedData } = useCreatePostTypedDataMutation();
const { profileQuery } = useLensUser();
const sdk = useSDK();

async function createPost(
image: File,
title: string,
description: string,
content: string,
classificationMetadata: string
) {
const typedData = await requestTypedData({
request: {
collectModule: { // Set this to be custom DAO contract?
freeCollectModule: {
followerOnly: false,
},
},
contentURI: 'todo', // IPFS Hash (upload ALL content to IPFS)
profileId: profileQuery.data?.defaultProfile?.id,
},
});

const {domain, types, value} = typedData.createPostTypedData.typedData;
if (!sdk) return;

// Sign typed data
const signature = await signTypedDataWithOmittedTypename(
sdk,
domain,
types,
value
);

// Send the transaction data & ipfs hash to the custom publication module
// todo
}

//return useMutation(createPost);
import { signTypedDataWithOmittedTypename, splitSignature } from "./helpers";
import { v4 as uuidv4 } from "uuid";
import { LENS_CONTRACT_ABI, LENS_CONTRACT_ADDRESS } from "../constants/contracts";
import useLogin from "./auth/useLogin";

type CreatePostArgs = {
image: File;
title: string;
description: string;
content: string;
};

export function useCreatePost() {
const { mutateAsync: requestTypedData } = useCreatePostTypedDataMutation();
const { mutateAsync: uploadToIpfs } = useStorageUpload();
const { profileQuery } = useLensUser();
const sdk = useSDK();
const { mutateAsync: loginUser } = useLogin();

async function createPost({
image,
title,
description,
content,
}: CreatePostArgs) {
console.log("createPost", image, title, description, content);
// 0. Login
await loginUser();

// 0. Upload the image to IPFS
const imageIpfsUrl = (await uploadToIpfs({ data: [image] }))[0];

console.log("imageIpfsUrl", imageIpfsUrl);
const postMetadata = {
version: "2.0.0",
mainContentFocus: PublicationMainFocus.TextOnly,
metadata_id: uuidv4(),
description: description,
locale: "en-US",
content: content,
external_url: null,
image: imageIpfsUrl,
imageMimeType: null,
name: title,
attributes: [],
tags: [],
};

const postMetadataIpfsUrl = (
await uploadToIpfs({ data: [postMetadata] })
)[0];

console.log("postMetadataIpfsUrl", postMetadataIpfsUrl);

// 1. Ask Lens to give us the typed data
const typedData = await requestTypedData({
request: {
collectModule: {
freeCollectModule: {
followerOnly: false,
},
},
referenceModule: {
followerOnlyReferenceModule: false,
},
contentURI: postMetadataIpfsUrl,
profileId: profileQuery.data?.defaultProfile?.id,
},
});

const { domain, types, value } = typedData.createPostTypedData.typedData;

if (!sdk) return;

// 2. Sign the typed data
const signature = await signTypedDataWithOmittedTypename(
sdk,
domain,
types,
value
);

const { v, r, s } = splitSignature(signature.signature);

// 3. Use the signed typed data to send the transaction to the smart contract
const lensHubContract = await sdk.getContractFromAbi(
LENS_CONTRACT_ADDRESS,
LENS_CONTRACT_ABI
);

// Destructure the stuff we need out of the typedData.value field
const {
collectModule,
collectModuleInitData,
contentURI,
deadline,
profileId,
referenceModule,
referenceModuleInitData,
} = typedData.createPostTypedData.typedData.value;

const result = await lensHubContract.call("postWithSig", {
profileId: profileId,
contentURI: contentURI,
collectModule,
collectModuleInitData,
referenceModule,
referenceModuleInitData,
sig: {
v,
r,
s,
deadline: deadline,
},
});

console.log(result);
}

return useMutation(createPost);
}
119 changes: 119 additions & 0 deletions lib/useCreatePostProposalEdit.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { useMutation } from "@tanstack/react-query";
import { useSDK, useStorageUpload } from "@thirdweb-dev/react";
import { PublicationMainFocus, useCreatePostTypedDataMutation } from "../graphql/generated";
import useLensUser from "./auth/useLensUser";
import { signTypedDataWithOmittedTypename, splitSignature } from "./helpers";
import { v4 as uuidv4 } from "uuid";
import { LENS_CONTRACT_ABI, LENS_CONTRACT_ADDRESS } from "../constants/contracts";
import useLogin from "./auth/useLogin";

type CreatePostArgs = {
image: File;
title: string;
description: string;
content: string;
classificationMetadata: string;
}

export default function useCreatePost() {
const { mutateAsync: requestTypedData } = useCreatePostTypedDataMutation();
const { mutateAsync: uploadToIpfs } = useStorageUpload();
const { mutateAsync: loginUser } = useLogin();
const { profileQuery } = useLensUser();
const sdk = useSDK();

async function createPost({
image,
title,
description,
content,
classificationMetadata
}: CreatePostArgs) {
// Require login
await loginUser();
// Upload contents/image to IPFS
const imageIpfsUrl = (await uploadToIpfs({ data: [image] }))[0]; // Array of strings. Currently only getting the first item (which will be the image). To-Do: Remove the indexer and replace that when requesting the content on the IPFS hash when returning post[s] [content]
// Upload publication content to IPFS (contains image field as well)
const postMetadata = {
version: '2.0.0',
mainContentFocus: PublicationMainFocus.TextOnly, // This can be changed -> what post type is being created?
matadata_id: uuidv4(),
description: description,
locale: 'en-us',
content: content,
external_url: null,
image: imageIpfsUrl,
imageMimeType: null,
name: title,
attributes: [],
classificationMetadata: classificationMetadata,
tags: ['0xed6e837Fda815FBf78E8E7266482c5Be80bC4bF9'],
appId: 'ssk_example',
};
const postMetadataIpfsUrl = (await uploadToIpfs({ data: [ postMetadata ] }))[0];

// Lens provides typed data for request
const typedData = await requestTypedData({
request: {
collectModule: { // Set this to be custom DAO contract?
freeCollectModule: {
followerOnly: false,
},
},
contentURI: 'todo', // IPFS Hash (upload ALL content to IPFS)
profileId: profileQuery.data?.defaultProfile?.id,
referenceModule: {
followerOnlyReferenceModule: false,
}
},
});

const {domain, types, value} = typedData.createPostTypedData.typedData;
if (!sdk) return;

// Sign typed data
const signature = await signTypedDataWithOmittedTypename(
sdk,
domain,
types,
value
);

const { v, r, s } = splitSignature(signature.signature);

// Send the transaction data & ipfs hash to the custom publication module
const lensHubContract = await sdk.getContractFromAbi(
LENS_CONTRACT_ADDRESS,
LENS_CONTRACT_ABI,
);

// Destructure value fields
const {
collectModule,
collectModuleInitData,
contentURI,
deadline,
nonce,
profileId,
referenceModule,
referenceModuleInitData
} = typedData.createPostTypedData.typedData.value
const result = await lensHubContract.call("postWithSig", {
profileId: profileId,
contentURI: contentURI,
collectModule,
collectModuleInitData,
referenceModule,
referenceModuleInitData,
sig: {
v,
r,
s,
deadline: deadline,
},
});
console.log(result);
}

return useMutation(createPost);
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"react-moralis": "^1.4.2",
"react-syntax-highlighter": "^15.5.0",
"uuid": "^9.0.0",
"uuidv4": "^6.2.13",
"web3uikit": "^1.0.4"
},
"devDependencies": {
Expand Down
17 changes: 17 additions & 0 deletions pages/publications/create.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { Web3Button } from '@thirdweb-dev/react';
import React, { useState } from 'react';
import styles from '../../styles/Create.module.css';
import { useCreatePost } from '../../lib/useCreatePost';
import { LENS_CONTRACT_ABI, LENS_CONTRACT_ADDRESS } from '../../constants/contracts';

export default function Create() {
const [image, setImage] = useState<File | null>(null);
const [title, setTitle] = useState<string>("");
const [description, setDescription] = useState<string>("");
const [classificationMetadata, setClassificationMetadata] = useState<string>(""); // Token id (rendering template will add the contract address)
const [content, setContent] = useState('');
const { mutateAsync: createPost } = useCreatePost();

return (
<div className={styles.container}>
Expand Down Expand Up @@ -44,6 +48,19 @@ export default function Create() {
onChange={(e) => setClassificationMetadata(e.target.value)}
/>
</div>
<Web3Button
contractAddress={LENS_CONTRACT_ADDRESS}
contractAbi={LENS_CONTRACT_ABI}
action={ async () => {
if (!image) return;
return await createPost({
image,
title,
description,
content,
})}
}
>Create Post</Web3Button>
</div>
</div>
)
Expand Down
23 changes: 18 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4082,6 +4082,11 @@
resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d"
integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==

"@types/[email protected]":
version "8.3.4"
resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc"
integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==

"@types/ws@^7.4.4":
version "7.4.7"
resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702"
Expand Down Expand Up @@ -11945,21 +11950,29 @@ util@^0.12.0, util@^0.12.4:
is-typed-array "^1.1.3"
which-typed-array "^1.1.2"

[email protected], uuid@^8.3.2:
version "8.3.2"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==

uuid@^3.3.2:
version "3.4.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==

uuid@^8.3.2:
version "8.3.2"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==

uuid@^9.0.0:
version "9.0.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5"
integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==

uuidv4@^6.2.13:
version "6.2.13"
resolved "https://registry.yarnpkg.com/uuidv4/-/uuidv4-6.2.13.tgz#8f95ec5ef22d1f92c8e5d4c70b735d1c89572cb7"
integrity sha512-AXyzMjazYB3ovL3q051VLH06Ixj//Knx7QnUSi1T//Ie3io6CpsPu9nVMOx5MoLWh6xV0B9J0hIaxungxXUbPQ==
dependencies:
"@types/uuid" "8.3.4"
uuid "8.3.2"

uvu@^0.5.0:
version "0.5.6"
resolved "https://registry.yarnpkg.com/uvu/-/uvu-0.5.6.tgz#2754ca20bcb0bb59b64e9985e84d2e81058502df"
Expand Down

0 comments on commit 3bd30c5

Please sign in to comment.