├── theme.js
├── .eslintrc.json
├── .example.env.local
├── context.js
├── public
├── favicon.ico
├── close.svg
├── vercel.svg
├── create-post.svg
└── icon.svg
├── components
├── index.js
├── Button.js
├── Placeholders.js
├── SearchInput.js
└── CreatePostModal.js
├── next.config.js
├── styles
├── globals.css
└── Home.module.css
├── .gitignore
├── package.json
├── README.md
├── utils.js
├── api
├── index.js
├── mutations.js
└── queries.js
├── pages
├── edit-profile.js
├── profiles.js
├── index.js
├── _app.js
└── profile
│ └── [id].js
└── abi
├── lensperiphery.json
└── lenshub.json
/theme.js:
--------------------------------------------------------------------------------
1 | export const PINK = "249, 92, 255"
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/.example.env.local:
--------------------------------------------------------------------------------
1 | NEXT_PUBLIC_PROJECT_ID=XXX
2 | NEXT_PUBLIC_PROJECT_SECRET=XXX
--------------------------------------------------------------------------------
/context.js:
--------------------------------------------------------------------------------
1 | import { createContext } from 'react'
2 |
3 | export const AppContext = createContext()
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dabit3/lens-protocol-frontend/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/components/index.js:
--------------------------------------------------------------------------------
1 | export { Button } from './Button'
2 | export { SearchInput } from './SearchInput'
3 | export { Placeholders } from './Placeholders'
--------------------------------------------------------------------------------
/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {
3 | reactStrictMode: true,
4 | images: {
5 | domains: [
6 | 'ipfs.infura.io',
7 | 'statics-polygon-lens-staging.s3.eu-west-1.amazonaws.com',
8 | 'lens.infura-ipfs.io',
9 | ""
10 | ],
11 | },
12 | }
13 |
14 | module.exports = nextConfig
15 |
--------------------------------------------------------------------------------
/styles/globals.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap');
2 |
3 | html,
4 | body {
5 | padding: 0;
6 | margin: 0;
7 | background-color: rgba(0, 0, 0, .015);
8 | min-height: 100vh;
9 | }
10 |
11 | a {
12 | color: inherit;
13 | text-decoration: none;
14 | }
15 |
16 | * {
17 | box-sizing: border-box;
18 | font-family: 'Inter', sans-serif;
19 | }
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 | .pnpm-debug.log*
27 |
28 | # local env files
29 | .env*.local
30 |
31 | # vercel
32 | .vercel
33 |
--------------------------------------------------------------------------------
/components/Button.js:
--------------------------------------------------------------------------------
1 | import { css } from '@emotion/css'
2 | import { PINK } from '../theme'
3 |
4 | export function Button({
5 | buttonText,
6 | onClick
7 | }) {
8 | return (
9 |
13 | )
14 | }
15 |
16 | const buttonStyle = css`
17 | border: none;
18 | outline: none;
19 | margin-left: 15px;
20 | color: #340036;
21 | padding: 17px;
22 | border-radius: 25px;
23 | cursor: pointer;
24 | font-size: 14px;
25 | font-weight: 500;
26 | background-color: rgb(${PINK});
27 | transition: all .35s;
28 | width: 240px;
29 | letter-spacing: .75px;
30 | &:hover {
31 | background-color: rgba(${PINK}, .75);
32 | }
33 | `
--------------------------------------------------------------------------------
/components/Placeholders.js:
--------------------------------------------------------------------------------
1 | import { css, keyframes } from '@emotion/css'
2 |
3 | export function Placeholders({
4 | number
5 | }) {
6 | const rows = []
7 | for (let i = 0; i < number; i ++) {
8 | rows.push(
9 |
13 | )
14 | }
15 | return rows
16 | }
17 |
18 | const shimmer = keyframes`
19 | from {
20 | opacity: .2;
21 | }
22 |
23 | 50% {
24 | opacity: 1;
25 | }
26 |
27 | 100% {
28 | opacity: .2;
29 | }
30 | `
31 |
32 | const grayLoadingStyle = css`
33 | background-color: rgba(0, 0, 0, .1);
34 | height: 115px;
35 | width: 100%;
36 | margin-top: 13px;
37 | border-radius: 7px;
38 | animation: ${shimmer} 2s infinite linear;
39 | `
--------------------------------------------------------------------------------
/components/SearchInput.js:
--------------------------------------------------------------------------------
1 | import { css } from '@emotion/css'
2 |
3 | export function SearchInput({
4 | placeholder, onChange, value, onKeyDown = null
5 | }) {
6 | return (
7 |
14 | )
15 | }
16 |
17 | const inputStyle = css`
18 | outline: none;
19 | border: none;
20 | padding: 15px 20px;
21 | font-size: 16px;
22 | border-radius: 25px;
23 | border: 2px solid rgba(0, 0, 0, .04);
24 | transition: all .4s;
25 | width: 300px;
26 | background-color: #fafafa;
27 | &:focus {
28 | background-color: white;
29 | border: 2px solid rgba(0, 0, 0, .1);
30 | }
31 | `
32 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lens-example",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "dependencies": {
12 | "@emotion/css": "^11.9.0",
13 | "@rainbow-me/rainbowkit": "^0.1.0",
14 | "@urql/exchange-auth": "^0.1.7",
15 | "date-fns": "^2.28.0",
16 | "ethers": "^5.6.6",
17 | "graphql": "^16.5.0",
18 | "ipfs-http-client": "^59.0.0",
19 | "next": "12.1.6",
20 | "omit-deep": "^0.3.0",
21 | "react": "18.1.0",
22 | "react-dom": "18.1.0",
23 | "react-markdown": "^8.0.3",
24 | "react-modal": "^3.15.1",
25 | "urql": "^2.2.0",
26 | "uuid": "^8.3.2",
27 | "wagmi": "^0.4.4"
28 | },
29 | "devDependencies": {
30 | "eslint": "8.15.0",
31 | "eslint-config-next": "12.1.6"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/public/close.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/create-post.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/icon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Lens Protocol Front End Starter
2 |
3 | This is an example of how to build a front-end application on top of [Lens Protocol](https://docs.lens.xyz/docs).
4 |
5 | The main API calls used in this app are defined in __api/index.js__:
6 |
7 | 1. [recommendProfiles](https://docs.lens.xyz/docs/recommended-profiles#api-details) - Get popular profiles
8 |
9 | 2. [getProfiles](https://docs.lens.xyz/docs/get-profiles) - Get profiles by passing in an array of `profileIds`
10 |
11 | 3. [getPublications](https://docs.lens.xyz/docs/get-publications) - Returns a list of publications based on your request query
12 |
13 | 4. [searchProfiles](https://docs.lens.xyz/docs/search-profiles-and-publications) - Allows a user to search across hashtags on publications or profile handles. This query returns either a Post and Comment or Profile.
14 |
15 | 5. [follow](https://docs.lens.xyz/docs/functions#follow) - Follow a user
16 |
17 | 6. [burn](https://docs.lens.xyz/docs/functions#burn) - Unfollows a user
18 |
19 | 7. [timeline](https://docs.lens.xyz/docs/user-timeline) - Shows a feed of content tailored to a signed in user
20 |
21 | 8. [createSetProfileMetadataTypedData](https://docs.lens.xyz/docs/create-set-update-profile-metadata-typed-data) - Allows a user to update the metadata URI for their profile
22 |
23 | 9. [post](https://docs.lens.xyz/docs/functions#post) - Allows a user to publish content
24 |
25 | You can view all of the APIs [here](https://docs.lens.xyz/docs/introduction) and contract methods [here](https://docs.lens.xyz/docs/functions)
26 |
27 | ## Running this project
28 |
29 | > For this project to run, you must configure the **Infura project ID and project secret** in a file named `.env.local`. Check out .example.env.local for guidance.
30 |
31 | You can run this project by following these steps:
32 |
33 | 1. Clone the repo, change into the directory, and install the dependencies
34 |
35 | ```sh
36 | git clone git@github.com:dabit3/lens-protocol-frontend.git
37 |
38 | cd lens-protocol-frontend
39 |
40 | npm install
41 |
42 | # or
43 |
44 | yarn
45 | ```
46 |
47 | 2. Run the project
48 |
49 | ```sh
50 | npm run dev
51 | ```
52 |
53 | 3. Open the project in your browser at [localhost:3000](http://localhost:3000/)
--------------------------------------------------------------------------------
/utils.js:
--------------------------------------------------------------------------------
1 | import { basicClient, STORAGE_KEY } from './api'
2 | import { refresh as refreshMutation } from './api/mutations'
3 | import { ethers, utils } from 'ethers'
4 | import omitDeep from 'omit-deep'
5 |
6 | export function trimString(string, length) {
7 | if (!string) return null
8 | return string.length < length ? string : string.substr(0, length-1) + "..."
9 | }
10 |
11 | export function parseJwt (token) {
12 | var base64Url = token.split('.')[1];
13 | var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
14 | var jsonPayload = decodeURIComponent(atob(base64).split('').map(function(c) {
15 | return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
16 | }).join(''));
17 |
18 | return JSON.parse(jsonPayload);
19 | };
20 |
21 | export async function refreshAuthToken() {
22 | const token = JSON.parse(localStorage.getItem(STORAGE_KEY))
23 | if (!token) return
24 | try {
25 | const authData = await basicClient.mutation(refreshMutation, {
26 | refreshToken: token.refreshToken
27 | }).toPromise()
28 |
29 | if (!authData.data) return
30 |
31 | const { accessToken, refreshToken } = authData.data.refresh
32 | const exp = parseJwt(refreshToken).exp
33 |
34 | localStorage.setItem(STORAGE_KEY, JSON.stringify({
35 | accessToken, refreshToken, exp
36 | }))
37 |
38 | return {
39 | accessToken
40 | }
41 | } catch (err) {
42 | console.log('error:', err)
43 | }
44 | }
45 |
46 | export function getSigner() {
47 | const provider = new ethers.providers.Web3Provider(window.ethereum)
48 | return provider.getSigner();
49 | }
50 |
51 | export function signedTypeData (domain, types, value) {
52 | const signer = getSigner();
53 | return signer._signTypedData(
54 | omitDeep(domain, '__typename'),
55 | omitDeep(types, '__typename'),
56 | omitDeep(value, '__typename')
57 | )
58 | }
59 |
60 | export function splitSignature(signature) {
61 | return utils.splitSignature(signature)
62 | }
63 |
64 | export function generateRandomColor(){
65 | let maxVal = 0xFFFFFF; // 16777215
66 | let randomNumber = Math.random() * maxVal;
67 | randomNumber = Math.floor(randomNumber);
68 | randomNumber = randomNumber.toString(16);
69 | let randColor = randomNumber.padStart(6, 0);
70 | return `#${randColor.toUpperCase()}`
71 | }
72 |
--------------------------------------------------------------------------------
/styles/Home.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | padding: 0 2rem;
3 | }
4 |
5 | .main {
6 | min-height: 100vh;
7 | padding: 4rem 0;
8 | flex: 1;
9 | display: flex;
10 | flex-direction: column;
11 | justify-content: center;
12 | align-items: center;
13 | }
14 |
15 | .footer {
16 | display: flex;
17 | flex: 1;
18 | padding: 2rem 0;
19 | border-top: 1px solid #eaeaea;
20 | justify-content: center;
21 | align-items: center;
22 | }
23 |
24 | .footer a {
25 | display: flex;
26 | justify-content: center;
27 | align-items: center;
28 | flex-grow: 1;
29 | }
30 |
31 | .title a {
32 | color: #0070f3;
33 | text-decoration: none;
34 | }
35 |
36 | .title a:hover,
37 | .title a:focus,
38 | .title a:active {
39 | text-decoration: underline;
40 | }
41 |
42 | .title {
43 | margin: 0;
44 | line-height: 1.15;
45 | font-size: 4rem;
46 | }
47 |
48 | .title,
49 | .description {
50 | text-align: center;
51 | }
52 |
53 | .description {
54 | margin: 4rem 0;
55 | line-height: 1.5;
56 | font-size: 1.5rem;
57 | }
58 |
59 | .code {
60 | background: #fafafa;
61 | border-radius: 5px;
62 | padding: 0.75rem;
63 | font-size: 1.1rem;
64 | font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
65 | Bitstream Vera Sans Mono, Courier New, monospace;
66 | }
67 |
68 | .grid {
69 | display: flex;
70 | align-items: center;
71 | justify-content: center;
72 | flex-wrap: wrap;
73 | max-width: 800px;
74 | }
75 |
76 | .card {
77 | margin: 1rem;
78 | padding: 1.5rem;
79 | text-align: left;
80 | color: inherit;
81 | text-decoration: none;
82 | border: 1px solid #eaeaea;
83 | border-radius: 10px;
84 | transition: color 0.15s ease, border-color 0.15s ease;
85 | max-width: 300px;
86 | }
87 |
88 | .card:hover,
89 | .card:focus,
90 | .card:active {
91 | color: #0070f3;
92 | border-color: #0070f3;
93 | }
94 |
95 | .card h2 {
96 | margin: 0 0 1rem 0;
97 | font-size: 1.5rem;
98 | }
99 |
100 | .card p {
101 | margin: 0;
102 | font-size: 1.25rem;
103 | line-height: 1.5;
104 | }
105 |
106 | .logo {
107 | height: 1em;
108 | margin-left: 0.5rem;
109 | }
110 |
111 | @media (max-width: 600px) {
112 | .grid {
113 | width: 100%;
114 | flex-direction: column;
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/api/index.js:
--------------------------------------------------------------------------------
1 | import { createClient as createUrqlClient } from 'urql'
2 | import { getProfiles, getPublications } from './queries'
3 | import { createPostTypedData } from './mutations'
4 | import { refreshAuthToken, generateRandomColor, signedTypeData } from '../utils'
5 |
6 | export const APIURL = "https://api.lens.dev"
7 | export const STORAGE_KEY = "LH_STORAGE_KEY"
8 | export const LENS_HUB_CONTRACT_ADDRESS = "0xDb46d1Dc155634FbC732f92E853b10B288AD5a1d"
9 | export const PERIPHERY_CONTRACT_ADDRESS = "0xeff187b4190E551FC25a7fA4dFC6cf7fDeF7194f"
10 |
11 | export const basicClient = new createUrqlClient({
12 | url: APIURL
13 | })
14 |
15 | export async function fetchProfile(id) {
16 | try {
17 | const urqlClient = await createClient()
18 | const returnedProfile = await urqlClient.query(getProfiles, { id }).toPromise();
19 | const profileData = returnedProfile.data.profiles.items[0]
20 | profileData.color = generateRandomColor()
21 | const pubs = await urqlClient.query(getPublications, { id, limit: 50 }).toPromise()
22 | return {
23 | profile: profileData,
24 | publications: pubs.data.publications.items
25 | }
26 | } catch (err) {
27 | console.log('error fetching profile...', err)
28 | }
29 | }
30 |
31 | export async function createClient() {
32 | const storageData = JSON.parse(localStorage.getItem(STORAGE_KEY))
33 | if (storageData) {
34 | try {
35 | const { accessToken } = await refreshAuthToken()
36 | const urqlClient = new createUrqlClient({
37 | url: APIURL,
38 | fetchOptions: {
39 | headers: {
40 | 'x-access-token': `Bearer ${accessToken}`
41 | },
42 | },
43 | })
44 | return urqlClient
45 | } catch (err) {
46 | return basicClient
47 | }
48 | } else {
49 | return basicClient
50 | }
51 | }
52 |
53 | export async function createPostTypedDataMutation (request, token) {
54 | const { accessToken } = await refreshAuthToken()
55 | const urqlClient = new createUrqlClient({
56 | url: APIURL,
57 | fetchOptions: {
58 | headers: {
59 | 'x-access-token': `Bearer ${accessToken}`
60 | },
61 | },
62 | })
63 | const result = await urqlClient.mutation(createPostTypedData, {
64 | request
65 | }).toPromise()
66 |
67 | return result.data.createPostTypedData
68 | }
69 |
70 | export const signCreatePostTypedData = async (request, token) => {
71 | const result = await createPostTypedDataMutation(request, token)
72 | const typedData = result.typedData
73 | const signature = await signedTypeData(typedData.domain, typedData.types, typedData.value);
74 | return { result, signature };
75 | }
76 |
77 | export {
78 | recommendProfiles,
79 | getProfiles,
80 | getDefaultProfile,
81 | getPublications,
82 | searchProfiles,
83 | searchPublications,
84 | explorePublications,
85 | doesFollow,
86 | getChallenge,
87 | timeline
88 | } from './queries'
89 |
90 | export {
91 | followUser,
92 | authenticate,
93 | refresh,
94 | createUnfollowTypedData,
95 | broadcast,
96 | createProfileMetadataTypedData,
97 | createPostTypedData
98 | } from './mutations'
--------------------------------------------------------------------------------
/api/mutations.js:
--------------------------------------------------------------------------------
1 |
2 | const followUser = `
3 | mutation($request: FollowRequest!) {
4 | createFollowTypedData(request: $request) {
5 | id
6 | expiresAt
7 | typedData {
8 | domain {
9 | name
10 | chainId
11 | version
12 | verifyingContract
13 | }
14 | types {
15 | FollowWithSig {
16 | name
17 | type
18 | }
19 | }
20 | value {
21 | nonce
22 | deadline
23 | profileIds
24 | datas
25 | }
26 | }
27 | }
28 | }
29 | `
30 |
31 | const authenticate = `
32 | mutation Authenticate(
33 | $address: EthereumAddress!
34 | $signature: Signature!
35 | ) {
36 | authenticate(request: {
37 | address: $address,
38 | signature: $signature
39 | }) {
40 | accessToken
41 | refreshToken
42 | }
43 | }
44 | `
45 |
46 | const refresh = `
47 | mutation Refresh(
48 | $refreshToken: Jwt!
49 | ) {
50 | refresh(request: {
51 | refreshToken: $refreshToken
52 | }) {
53 | accessToken
54 | refreshToken
55 | }
56 | }
57 | `
58 |
59 | const broadcast = `
60 | mutation Broadcast($request: BroadcastRequest!) {
61 | broadcast(request: $request) {
62 | ... on RelayerResult {
63 | txHash
64 | }
65 | ... on RelayError {
66 | reason
67 | }
68 | }
69 | }
70 | `
71 |
72 | /* UnfollowRequest
73 | * const unfollowRequestData = { profile: ProfileId! }
74 | */
75 |
76 | const createUnfollowTypedData = `
77 | mutation($request: UnfollowRequest!) {
78 | createUnfollowTypedData(request: $request) {
79 | id
80 | expiresAt
81 | typedData {
82 | domain {
83 | name
84 | chainId
85 | version
86 | verifyingContract
87 | }
88 | types {
89 | BurnWithSig {
90 | name
91 | type
92 | }
93 | }
94 | value {
95 | nonce
96 | deadline
97 | tokenId
98 | }
99 | }
100 | }
101 | }
102 | `
103 |
104 | const createProfileMetadataTypedData = `
105 | mutation CreateSetProfileMetadataTypedData(
106 | $profileId: ProfileId!, $metadata: Url!
107 | ) {
108 | createSetProfileMetadataTypedData(request: { profileId: $profileId, metadata: $metadata }) {
109 | id
110 | expiresAt
111 | typedData {
112 | types {
113 | SetProfileMetadataURIWithSig {
114 | name
115 | type
116 | }
117 | }
118 | domain {
119 | name
120 | chainId
121 | version
122 | verifyingContract
123 | }
124 | value {
125 | nonce
126 | deadline
127 | profileId
128 | metadata
129 | }
130 | }
131 | }
132 | }
133 | `
134 |
135 | const createPostTypedData = `
136 | mutation createPostTypedData($request: CreatePublicPostRequest!) {
137 | createPostTypedData(request: $request) {
138 | id
139 | expiresAt
140 | typedData {
141 | types {
142 | PostWithSig {
143 | name
144 | type
145 | }
146 | }
147 | domain {
148 | name
149 | chainId
150 | version
151 | verifyingContract
152 | }
153 | value {
154 | nonce
155 | deadline
156 | profileId
157 | contentURI
158 | collectModule
159 | collectModuleInitData
160 | referenceModule
161 | referenceModuleInitData
162 | }
163 | }
164 | }
165 | }
166 | `
167 |
168 | export {
169 | followUser,
170 | authenticate,
171 | refresh,
172 | createUnfollowTypedData,
173 | broadcast,
174 | createProfileMetadataTypedData,
175 | createPostTypedData
176 | }
--------------------------------------------------------------------------------
/pages/edit-profile.js:
--------------------------------------------------------------------------------
1 | import { useState, useContext } from 'react'
2 | import { ethers } from 'ethers'
3 | import { AppContext } from '../context'
4 | import { css } from '@emotion/css'
5 | import { PINK } from '../theme'
6 | import { Button } from '../components'
7 | import { v4 as uuid } from 'uuid'
8 | import { create } from 'ipfs-http-client'
9 | import PERIPHERY from '../abi/lensperiphery.json'
10 | import {
11 | createProfileMetadataTypedData,
12 | createClient,
13 | PERIPHERY_CONTRACT_ADDRESS
14 | } from '../api'
15 | import { signedTypeData, splitSignature, getSigner } from '../utils'
16 |
17 | const projectId = process.env.NEXT_PUBLIC_PROJECT_ID
18 | const projectSecret = process.env.NEXT_PUBLIC_PROJECT_SECRET
19 | const auth = 'Basic ' + Buffer.from(projectId + ':' + projectSecret).toString('base64');
20 |
21 | const client = create({
22 | host: 'ipfs.infura.io',
23 | port: 5001,
24 | protocol: 'https',
25 | headers: {
26 | authorization: auth,
27 | },
28 | })
29 |
30 | export default function EditProfile() {
31 | const [updatedProfile, setUpdatedProfile] = useState()
32 | const context = useContext(AppContext)
33 | const { profile } = context
34 |
35 | async function updateProfile() {
36 | if (!updatedProfile) return
37 |
38 | if (updatedProfile.twitter) {
39 | const index = profile.attributes.findIndex(v => v.key === 'twitter')
40 | profile.attributes[index].value = updatedProfile.twitter
41 | }
42 |
43 | const newMeta = {
44 | name: profile.name,
45 | bio: profile.bio,
46 | attributes: profile.attributes,
47 | version: "1.0.0",
48 | metadata_id: uuid(),
49 | previousMetadata: profile.metadata,
50 | createdOn: new Date().toISOString(),
51 | appId: "NaderDabitLensStarter",
52 | ...updatedProfile,
53 | }
54 |
55 | if (profile.coverPicture) {
56 | newMeta.cover_picture = profile.coverPicture.original.url
57 | } else {
58 | newMeta.cover_picture = null
59 | }
60 |
61 | const added = await client.add(JSON.stringify(newMeta))
62 |
63 | const newMetadataURI = `https://ipfs.infura.io/ipfs/${added.path}`
64 |
65 | // using the GraphQL API may be unnecessary
66 | // if you are not using gasless transactions
67 | const urqlClient = await createClient()
68 | const data = await urqlClient.mutation(createProfileMetadataTypedData, {
69 | profileId: profile.id, metadata: newMetadataURI
70 | }).toPromise()
71 |
72 | const typedData = data.data.createSetProfileMetadataTypedData.typedData;
73 |
74 | const signature = await signedTypeData(typedData.domain, typedData.types, typedData.value)
75 | const { v, r, s } = splitSignature(signature);
76 |
77 | const contract = new ethers.Contract(
78 | PERIPHERY_CONTRACT_ADDRESS,
79 | PERIPHERY,
80 | getSigner()
81 | )
82 |
83 | const tx = await contract.setProfileMetadataURIWithSig({
84 | profileId: profile.id,
85 | metadata: newMetadataURI,
86 | sig: {
87 | v,
88 | r,
89 | s,
90 | deadline: typedData.value.deadline,
91 | },
92 | });
93 | console.log('tx: ', tx)
94 | }
95 |
96 | if (!profile) {
97 | return null
98 | }
99 |
100 | const meta = profile.attributes.reduce((acc, next) => {
101 | acc[next.key] = next.value
102 | return acc
103 | }, {})
104 |
105 | return (
106 |
107 |
Edit Profile
108 |
109 |
110 | setUpdatedProfile({ ...updatedProfile, name: e.target.value })}
114 | />
115 |
116 |
138 |
139 | )
140 | }
141 |
142 | const containerStyle = css`
143 | padding-top: 25px;
144 | `
145 |
146 | const inputStyle = css`
147 | width: 100%;
148 | border-radius: 12px;
149 | outline: none;
150 | border: 2px solid rgba(0, 0, 0, .05);
151 | padding: 12px 18px;
152 | font-size: 14px;
153 | border-color: transpaent;
154 | margin-top: 10px;
155 | margin-bottom: 30px;
156 | &:focus {
157 | border-color: rgb(${PINK});
158 | }
159 | `
160 |
161 | const textAreaStyle = css`
162 | ${inputStyle};
163 | height: 100px;
164 | `
165 |
166 | const labelStyle = css`
167 | font-weight: 600;
168 | `
169 |
170 | const formContainer = css`
171 | margin-top: 40px;
172 | `
--------------------------------------------------------------------------------
/pages/profiles.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from 'react'
2 | import { createClient, searchProfiles, recommendProfiles, getPublications } from '../api'
3 | import { css } from '@emotion/css'
4 | import { trimString, generateRandomColor } from '../utils'
5 | import { Button, SearchInput, Placeholders } from '../components'
6 | import Image from 'next/image'
7 | import Link from 'next/link'
8 |
9 | export default function Home() {
10 | const [profiles, setProfiles] = useState([])
11 | const [loadingState, setLoadingState] = useState('loading')
12 | const [searchString, setSearchString] = useState('')
13 |
14 | useEffect(() => {
15 | getRecommendedProfiles()
16 | }, [])
17 |
18 | async function getRecommendedProfiles() {
19 | try {
20 | const urqlClient = await createClient()
21 | const response = await urqlClient.query(recommendProfiles).toPromise()
22 | const profileData = await Promise.all(response.data.recommendedProfiles.map(async profile => {
23 | const pub = await urqlClient.query(getPublications, { id: profile.id, limit: 1 }).toPromise()
24 | profile.publication = pub.data.publications.items[0]
25 | profile.backgroundColor = generateRandomColor()
26 | return profile
27 | }))
28 | setProfiles(profileData)
29 | setLoadingState('loaded')
30 | } catch (err) {
31 | console.log('error fetching recommended profiles: ', err)
32 | }
33 | }
34 |
35 | async function searchForProfile() {
36 | if (!searchString) return
37 | try {
38 | const urqlClient = await createClient()
39 | const response = await urqlClient.query(searchProfiles, {
40 | query: searchString, type: 'PROFILE'
41 | }).toPromise()
42 | const profileData = await Promise.all(response.data.search.items.map(async profile => {
43 | const pub = await urqlClient.query(getPublications, { id: profile.profileId, limit: 1 }).toPromise()
44 | profile.id = profile.profileId
45 | profile.backgroundColor = generateRandomColor()
46 | profile.publication = pub.data.publications.items[0]
47 | return profile
48 | }))
49 |
50 | setProfiles(profileData)
51 | } catch (err) {
52 | console.log('error searching profiles...', err)
53 | }
54 | }
55 |
56 | function handleKeyDown(e) {
57 | if (e.key === 'Enter') {
58 | searchForProfile()
59 | }
60 | }
61 |
62 | return (
63 |
64 |
65 | setSearchString(e.target.value)}
68 | value={searchString}
69 | onKeyDown={handleKeyDown}
70 | />
71 |
75 |
76 |
120 |
121 | )
122 | }
123 |
124 | const searchContainerStyle = css`
125 | padding: 40px 0px 30px;
126 | `
127 |
128 | const latestPostStyle = css`
129 | margin: 23px 0px 5px;
130 | word-wrap: break-word;
131 | `
132 |
133 | const profileContainerStyle = css`
134 | display: flex;
135 | flex-direction: row;
136 | align-items: flex-start;
137 | `
138 |
139 | const profileImageStyle = css`
140 | border-radius: 21px;
141 | width: 42px;
142 | height: 42px;
143 | `
144 |
145 | const placeholderStyle = css`
146 | ${profileImageStyle};
147 | `
148 |
149 | const listItemContainerStyle = css`
150 | display: flex;
151 | flex-direction: column;
152 | `
153 |
154 | const listItemStyle = css`
155 | background-color: white;
156 | margin-top: 13px;
157 | border-radius: 10px;
158 | border: 1px solid rgba(0, 0, 0, .15);
159 | padding: 21px;
160 | `
161 |
162 | const profileInfoStyle = css`
163 | margin-left: 10px;
164 | `
165 |
166 | const nameStyle = css`
167 | margin: 0 0px 5px;
168 | `
169 |
170 | const handleStyle = css`
171 | margin: 0px 0px 5px;
172 | color: #b900c9;
173 | `
174 |
175 | const inputStyle = css`
176 | outline: none;
177 | border: none;
178 | padding: 15px 20px;
179 | font-size: 16px;
180 | border-radius: 25px;
181 | border: 2px solid rgba(0, 0, 0, .04);
182 | transition: all .4s;
183 | width: 300px;
184 | background-color: #fafafa;
185 | &:focus {
186 | background-color: white;
187 | border: 2px solid rgba(0, 0, 0, .1);
188 | }
189 | `
190 |
--------------------------------------------------------------------------------
/components/CreatePostModal.js:
--------------------------------------------------------------------------------
1 | import { useContext, useRef } from 'react'
2 | import { css } from '@emotion/css'
3 | import { ethers } from 'ethers'
4 | import { getSigner } from '../utils'
5 | import { LENS_HUB_CONTRACT_ADDRESS, signCreatePostTypedData } from '../api'
6 | import { AppContext } from '../context'
7 | import LENSHUB from '../abi/lenshub'
8 | import { create } from 'ipfs-http-client'
9 | import { v4 as uuid } from 'uuid'
10 | import { refreshAuthToken, splitSignature } from '../utils'
11 |
12 | const projectId = process.env.NEXT_PUBLIC_PROJECT_ID
13 | const projectSecret = process.env.NEXT_PUBLIC_PROJECT_SECRET
14 | const auth = 'Basic ' + Buffer.from(projectId + ':' + projectSecret).toString('base64');
15 |
16 | const client = create({
17 | host: 'ipfs.infura.io',
18 | port: 5001,
19 | protocol: 'https',
20 | headers: {
21 | authorization: auth,
22 | },
23 | })
24 |
25 | export default function CreatePostModal({
26 | setIsModalOpen
27 | }) {
28 | const { profile } = useContext(AppContext)
29 | const inputRef = useRef(null)
30 | async function uploadToIPFS() {
31 | const metaData = {
32 | version: '2.0.0',
33 | content: inputRef.current.innerHTML,
34 | description: inputRef.current.innerHTML,
35 | name: `Post by @${profile.handle}`,
36 | external_url: `https://lenster.xyz/u/${profile.handle}`,
37 | metadata_id: uuid(),
38 | mainContentFocus: 'TEXT_ONLY',
39 | attributes: [],
40 | locale: 'en-US',
41 | }
42 |
43 | const added = await client.add(JSON.stringify(metaData))
44 | const uri = `https://ipfs.infura.io/ipfs/${added.path}`
45 | return uri
46 | }
47 |
48 | async function savePost() {
49 | const contentURI = await uploadToIPFS()
50 | const { accessToken } = await refreshAuthToken()
51 | const createPostRequest = {
52 | profileId: profile.id,
53 | contentURI,
54 | collectModule: {
55 | freeCollectModule: { followerOnly: true }
56 | },
57 | referenceModule: {
58 | followerOnlyReferenceModule: false
59 | },
60 | }
61 |
62 | try {
63 | const signedResult = await signCreatePostTypedData(createPostRequest, accessToken)
64 | const typedData = signedResult.result.typedData
65 | const { v, r, s } = splitSignature(signedResult.signature)
66 |
67 | const contract = new ethers.Contract(
68 | LENS_HUB_CONTRACT_ADDRESS,
69 | LENSHUB,
70 | getSigner()
71 | )
72 |
73 | const tx = await contract.postWithSig({
74 | profileId: typedData.value.profileId,
75 | contentURI: typedData.value.contentURI,
76 | collectModule: typedData.value.collectModule,
77 | collectModuleInitData: typedData.value.collectModuleInitData,
78 | referenceModule: typedData.value.referenceModule,
79 | referenceModuleInitData: typedData.value.referenceModuleInitData,
80 | sig: {
81 | v,
82 | r,
83 | s,
84 | deadline: typedData.value.deadline,
85 | },
86 | })
87 |
88 | await tx.wait()
89 | console.log('successfully created post: tx hash', tx.hash)
90 | setIsModalOpen(false)
91 |
92 | } catch (err) {
93 | console.log('error: ', err)
94 | }
95 | }
96 | return (
97 |
98 |
99 |
100 |
101 |
102 | Create post
103 |
104 |
105 |
setIsModalOpen(false)}>
106 |

110 |
111 |
112 |
113 |
114 |
119 |
120 |
124 |
125 |
126 |
127 |
128 |
129 | )
130 | }
131 |
132 | const buttonStyle = css`
133 | border: none;
134 | outline: none;
135 | background-color: rgb(249, 92, 255);;
136 | padding: 13px 24px;
137 | color: #340036;
138 | border-radius: 10px;
139 | font-weight: 600;
140 | cursor: pointer;
141 | transition: all .35s;
142 | &:hover {
143 | background-color: rgba(249, 92, 255, .75);
144 | }
145 | `
146 |
147 | const buttonContainerStyle = css`
148 | display: flex;
149 | justify-content: flex-end;
150 | margin-top: 15px;
151 | `
152 |
153 | const postInputStyle = css`
154 | border: 1px solid rgba(0, 0, 0, .14);
155 | border-radius: 8px;
156 | width: 100%;
157 | min-height: 60px;
158 | padding: 12px 14px;
159 | font-weight: 500;
160 | `
161 |
162 | const bottomContentStyle = css`
163 | margin-top: 10px;
164 | max-height: 300px;
165 | overflow: scroll;
166 | `
167 |
168 | const topBarStyle = css`
169 | display: flex;
170 | align-items: flex-end;
171 | border-bottom: 1px solid rgba(0, 0, 0, .1);
172 | padding-bottom: 13px;
173 | padding: 15px 25px;
174 | `
175 |
176 | const topBarTitleStyle = css`
177 | flex: 1;
178 | p {
179 | margin: 0;
180 | font-weight: 600;
181 | }
182 | `
183 |
184 | const contentContainerStyle = css`
185 | background-color: white;
186 | border-radius: 10px;
187 | border: 1px solid rgba(0, 0, 0, .15);
188 | width: 700px;
189 | `
190 |
191 | const containerStyle = css`
192 | position: fixed;
193 | width: 100vw;
194 | height: 100vh;
195 | z-index: 10;
196 | top: 0;
197 | left: 0;
198 | display: flex;
199 | justify-content: center;
200 | align-items: center;
201 | background-color: rgba(0, 0, 0, .35);
202 | h1 {
203 | margin: 0;
204 | }
205 | `
206 |
207 | const contentStyle = css`
208 | padding: 15px 25px;
209 | `
210 |
211 | const createPostIconStyle = css`
212 | height: 20px;
213 | cursor: pointer;
214 | `
--------------------------------------------------------------------------------
/abi/lensperiphery.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "inputs": [
4 | {
5 | "internalType": "contract ILensHub",
6 | "name": "hub",
7 | "type": "address"
8 | }
9 | ],
10 | "stateMutability": "nonpayable",
11 | "type": "constructor"
12 | },
13 | {
14 | "inputs": [],
15 | "name": "ArrayMismatch",
16 | "type": "error"
17 | },
18 | {
19 | "inputs": [],
20 | "name": "FollowInvalid",
21 | "type": "error"
22 | },
23 | {
24 | "inputs": [],
25 | "name": "NotProfileOwnerOrDispatcher",
26 | "type": "error"
27 | },
28 | {
29 | "inputs": [],
30 | "name": "SignatureExpired",
31 | "type": "error"
32 | },
33 | {
34 | "inputs": [],
35 | "name": "SignatureInvalid",
36 | "type": "error"
37 | },
38 | {
39 | "inputs": [],
40 | "name": "TokenDoesNotExist",
41 | "type": "error"
42 | },
43 | {
44 | "inputs": [],
45 | "name": "HUB",
46 | "outputs": [
47 | {
48 | "internalType": "contract ILensHub",
49 | "name": "",
50 | "type": "address"
51 | }
52 | ],
53 | "stateMutability": "view",
54 | "type": "function"
55 | },
56 | {
57 | "inputs": [],
58 | "name": "NAME",
59 | "outputs": [
60 | {
61 | "internalType": "string",
62 | "name": "",
63 | "type": "string"
64 | }
65 | ],
66 | "stateMutability": "view",
67 | "type": "function"
68 | },
69 | {
70 | "inputs": [
71 | {
72 | "internalType": "uint256",
73 | "name": "profileId",
74 | "type": "uint256"
75 | }
76 | ],
77 | "name": "getProfileMetadataURI",
78 | "outputs": [
79 | {
80 | "internalType": "string",
81 | "name": "",
82 | "type": "string"
83 | }
84 | ],
85 | "stateMutability": "view",
86 | "type": "function"
87 | },
88 | {
89 | "inputs": [
90 | {
91 | "internalType": "uint256",
92 | "name": "profileId",
93 | "type": "uint256"
94 | },
95 | {
96 | "internalType": "string",
97 | "name": "metadata",
98 | "type": "string"
99 | }
100 | ],
101 | "name": "setProfileMetadataURI",
102 | "outputs": [],
103 | "stateMutability": "nonpayable",
104 | "type": "function"
105 | },
106 | {
107 | "inputs": [
108 | {
109 | "components": [
110 | {
111 | "internalType": "uint256",
112 | "name": "profileId",
113 | "type": "uint256"
114 | },
115 | {
116 | "internalType": "string",
117 | "name": "metadata",
118 | "type": "string"
119 | },
120 | {
121 | "components": [
122 | {
123 | "internalType": "uint8",
124 | "name": "v",
125 | "type": "uint8"
126 | },
127 | {
128 | "internalType": "bytes32",
129 | "name": "r",
130 | "type": "bytes32"
131 | },
132 | {
133 | "internalType": "bytes32",
134 | "name": "s",
135 | "type": "bytes32"
136 | },
137 | {
138 | "internalType": "uint256",
139 | "name": "deadline",
140 | "type": "uint256"
141 | }
142 | ],
143 | "internalType": "struct DataTypes.EIP712Signature",
144 | "name": "sig",
145 | "type": "tuple"
146 | }
147 | ],
148 | "internalType": "struct DataTypes.SetProfileMetadataWithSigData",
149 | "name": "vars",
150 | "type": "tuple"
151 | }
152 | ],
153 | "name": "setProfileMetadataURIWithSig",
154 | "outputs": [],
155 | "stateMutability": "nonpayable",
156 | "type": "function"
157 | },
158 | {
159 | "inputs": [
160 | {
161 | "internalType": "address",
162 | "name": "",
163 | "type": "address"
164 | }
165 | ],
166 | "name": "sigNonces",
167 | "outputs": [
168 | {
169 | "internalType": "uint256",
170 | "name": "",
171 | "type": "uint256"
172 | }
173 | ],
174 | "stateMutability": "view",
175 | "type": "function"
176 | },
177 | {
178 | "inputs": [
179 | {
180 | "internalType": "uint256[]",
181 | "name": "profileIds",
182 | "type": "uint256[]"
183 | },
184 | {
185 | "internalType": "bool[]",
186 | "name": "enables",
187 | "type": "bool[]"
188 | }
189 | ],
190 | "name": "toggleFollow",
191 | "outputs": [],
192 | "stateMutability": "nonpayable",
193 | "type": "function"
194 | },
195 | {
196 | "inputs": [
197 | {
198 | "components": [
199 | {
200 | "internalType": "address",
201 | "name": "follower",
202 | "type": "address"
203 | },
204 | {
205 | "internalType": "uint256[]",
206 | "name": "profileIds",
207 | "type": "uint256[]"
208 | },
209 | {
210 | "internalType": "bool[]",
211 | "name": "enables",
212 | "type": "bool[]"
213 | },
214 | {
215 | "components": [
216 | {
217 | "internalType": "uint8",
218 | "name": "v",
219 | "type": "uint8"
220 | },
221 | {
222 | "internalType": "bytes32",
223 | "name": "r",
224 | "type": "bytes32"
225 | },
226 | {
227 | "internalType": "bytes32",
228 | "name": "s",
229 | "type": "bytes32"
230 | },
231 | {
232 | "internalType": "uint256",
233 | "name": "deadline",
234 | "type": "uint256"
235 | }
236 | ],
237 | "internalType": "struct DataTypes.EIP712Signature",
238 | "name": "sig",
239 | "type": "tuple"
240 | }
241 | ],
242 | "internalType": "struct DataTypes.ToggleFollowWithSigData",
243 | "name": "vars",
244 | "type": "tuple"
245 | }
246 | ],
247 | "name": "toggleFollowWithSig",
248 | "outputs": [],
249 | "stateMutability": "nonpayable",
250 | "type": "function"
251 | }
252 | ]
--------------------------------------------------------------------------------
/pages/index.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect, useContext } from 'react'
2 | import { createClient, basicClient, searchPublications, explorePublications, timeline } from '../api'
3 | import { css } from '@emotion/css'
4 | import { ethers } from 'ethers'
5 | import { trimString, generateRandomColor } from '../utils'
6 | import { Button, SearchInput, Placeholders } from '../components'
7 | import { AppContext } from '../context'
8 | import Link from 'next/link'
9 |
10 | const typeMap = {
11 | Comment: "Comment",
12 | Mirror: "Mirror",
13 | Post: "Post"
14 | }
15 |
16 | export default function Home() {
17 | const [posts, setPosts] = useState([])
18 | const [loadingState, setLoadingState] = useState('loading')
19 | const [searchString, setSearchString] = useState('')
20 | const { profile } = useContext(AppContext)
21 |
22 | useEffect(() => {
23 | fetchPosts()
24 | }, [profile])
25 |
26 | async function fetchPosts() {
27 | const provider = new ethers.providers.Web3Provider(
28 | (window).ethereum
29 | )
30 | const addresses = await provider.listAccounts();
31 | if (profile) {
32 | try {
33 | const client = await createClient()
34 | const response = await client.query(timeline, {
35 | profileId: profile.id, limit: 15
36 | }).toPromise()
37 | let posts = response.data.timeline.items.filter(post => {
38 | if (post.profile) {
39 | post.backgroundColor = generateRandomColor()
40 | return post
41 | }
42 | })
43 | posts = posts.map(post => {
44 | let picture = post.profile.picture
45 | if (picture && picture.original && picture.original.url) {
46 | if (picture.original.url.startsWith('ipfs://')) {
47 | let result = picture.original.url.substring(7, picture.original.url.length)
48 | post.profile.picture.original.url = `http://lens.infura-ipfs.io/ipfs/${result}`
49 | }
50 | }
51 | return post
52 | })
53 | setPosts(posts)
54 | setLoadingState('loaded')
55 | } catch (error) {
56 | console.log({ error })
57 | }
58 | } else if (!addresses.length) {
59 | try {
60 | const response = await basicClient.query(explorePublications).toPromise()
61 | const posts = response.data.explorePublications.items.filter(post => {
62 | if (post.profile) {
63 | post.backgroundColor = generateRandomColor()
64 | return post
65 | }
66 | })
67 | setPosts(posts)
68 | setLoadingState('loaded')
69 | } catch (error) {
70 | console.log({ error })
71 | }
72 | }
73 | }
74 |
75 | async function searchForPost() {
76 | setLoadingState('')
77 | try {
78 | const urqlClient = await createClient()
79 | const response = await urqlClient.query(searchPublications, {
80 | query: searchString, type: 'PUBLICATION'
81 | }).toPromise()
82 | const postData = response.data.search.items.filter(post => {
83 | if (post.profile) {
84 | post.backgroundColor = generateRandomColor()
85 | return post
86 | }
87 | })
88 |
89 | setPosts(postData)
90 | if (!postData.length) {
91 | setLoadingState('no-results')
92 | }
93 | } catch (error) {
94 | console.log({ error })
95 | }
96 | }
97 |
98 | function handleKeyDown(e) {
99 | if (e.key === 'Enter') {
100 | searchForPost()
101 | }
102 | }
103 |
104 | return (
105 |
106 |
107 | setSearchString(e.target.value)}
110 | value={searchString}
111 | onKeyDown={handleKeyDown}
112 | />
113 |
117 |
118 |
163 |
164 | )
165 | }
166 |
167 | const searchContainerStyle = css`
168 | padding: 40px 0px 30px;
169 | `
170 |
171 | const latestPostStyle = css`
172 | margin: 23px 0px 5px;
173 | word-wrap: break-word;
174 | `
175 |
176 | const profileContainerStyle = css`
177 | display: flex;
178 | flex-direction: row;
179 | `
180 |
181 | const profileImageStyle = css`
182 | width: 42px;
183 | height: 42px;
184 | border-radius: 34px;
185 | `
186 |
187 | const placeholderStyle = css`
188 | ${profileImageStyle};
189 | `
190 |
191 | const listItemContainerStyle = css`
192 | display: flex;
193 | flex-direction: column;
194 | `
195 |
196 | const listItemStyle = css`
197 | background-color: white;
198 | margin-top: 13px;
199 | border-radius: 10px;
200 | border: 1px solid rgba(0, 0, 0, .15);
201 | padding: 21px;
202 | `
203 |
204 | const profileInfoStyle = css`
205 | margin-left: 10px;
206 | `
207 |
208 | const nameStyle = css`
209 | margin: 0 0px 5px;
210 | `
211 |
212 | const handleStyle = css`
213 | margin: 0px 0px 5px;
214 | color: #b900c9;
215 | `
216 |
217 | const itemTypeStyle = css`
218 | margin: 0;
219 | font-weight: 500;
220 | font-size: 14px;
221 | color: rgba(0, 0, 0, .45);
222 | margin-bottom: 16px;
223 | `
--------------------------------------------------------------------------------
/pages/_app.js:
--------------------------------------------------------------------------------
1 | import '../styles/globals.css'
2 | import { useState, useEffect } from 'react'
3 | import { ethers, providers } from 'ethers'
4 | import { css } from '@emotion/css'
5 | import Link from 'next/link'
6 | import { useRouter } from 'next/router'
7 | import { createClient, STORAGE_KEY, authenticate as authenticateMutation, getChallenge, getDefaultProfile } from '../api'
8 | import { parseJwt, refreshAuthToken } from '../utils'
9 | import { AppContext } from '../context'
10 | import Modal from '../components/CreatePostModal'
11 |
12 | function MyApp({ Component, pageProps }) {
13 | const [connected, setConnected] = useState(true)
14 | const [userAddress, setUserAddress] = useState()
15 | const [isModalOpen, setIsModalOpen] = useState(false)
16 | const [userProfile, setUserProfile] = useState()
17 | const router = useRouter()
18 |
19 | useEffect(() => {
20 | refreshAuthToken()
21 | async function checkConnection() {
22 | const provider = new ethers.providers.Web3Provider(
23 | (window).ethereum
24 | )
25 | const addresses = await provider.listAccounts();
26 | if (addresses.length) {
27 | setConnected(true)
28 | setUserAddress(addresses[0])
29 | getUserProfile(addresses[0])
30 | } else {
31 | setConnected(false)
32 | }
33 | }
34 | checkConnection()
35 | listenForRouteChangeEvents()
36 | }, [])
37 |
38 | async function getUserProfile(address) {
39 | try {
40 | const urqlClient = await createClient()
41 | const response = await urqlClient.query(getDefaultProfile, {
42 | address
43 | }).toPromise()
44 | setUserProfile(response.data.defaultProfile)
45 | } catch (err) {
46 | console.log('error fetching user profile...: ', err)
47 | }
48 | }
49 |
50 | async function listenForRouteChangeEvents() {
51 | router.events.on('routeChangeStart', () => {
52 | refreshAuthToken()
53 | })
54 | }
55 |
56 | async function signIn() {
57 | try {
58 | const accounts = await window.ethereum.send(
59 | "eth_requestAccounts"
60 | )
61 | setConnected(true)
62 | const account = accounts.result[0]
63 | setUserAddress(account)
64 | const urqlClient = await createClient()
65 | const response = await urqlClient.query(getChallenge, {
66 | address: account
67 | }).toPromise()
68 | const provider = new providers.Web3Provider(window.ethereum);
69 | const signer = provider.getSigner()
70 | const signature = await signer.signMessage(response.data.challenge.text)
71 | const authData = await urqlClient.mutation(authenticateMutation, {
72 | address: account, signature
73 | }).toPromise()
74 | const { accessToken, refreshToken } = authData.data.authenticate
75 | const accessTokenData = parseJwt(accessToken)
76 | getUserProfile(account)
77 | localStorage.setItem(STORAGE_KEY, JSON.stringify({
78 | accessToken, refreshToken, exp: accessTokenData.exp
79 | }))
80 | } catch (err) {
81 | console.log('error: ', err)
82 | }
83 | }
84 |
85 | return (
86 |
90 |
91 |
140 |
141 |
142 |
143 | {
144 | isModalOpen && (
145 |
148 | )
149 | }
150 |
151 |
152 | )
153 | }
154 |
155 | const appLayoutStyle = css`
156 | width: 900px;
157 | margin: 0 auto;
158 | padding: 78px 0px 50px;
159 | `
160 |
161 | const linkTextStyle = css`
162 | margin-right: 40px;
163 | font-weight: 600;
164 | font-size: 15px;
165 | `
166 |
167 | const iconStyle = css`
168 | height: 35px;
169 | margin-right: 40px;
170 | `
171 |
172 | const modalButtonStyle = css`
173 | background-color: transparent;
174 | outline: none;
175 | border: none;
176 | cursor: pointer;
177 | `
178 |
179 | const createPostStyle = css`
180 | height: 35px;
181 | margin-right: 5px;
182 | `
183 |
184 | const navStyle = css`
185 | background-color: white;
186 | padding: 15px 30px;
187 | display: flex;
188 | position: fixed;
189 | width: 100%;
190 | background-color: white;
191 | z-index: 1;
192 | border-bottom: 1px solid #ededed;
193 | `
194 |
195 | const navContainerStyle = css`
196 | width: 900px;
197 | margin: 0 auto;
198 | display: flex;
199 | `
200 |
201 | const linkContainerStyle = css`
202 | display: flex;
203 | align-items: center;
204 | `
205 |
206 | const buttonContainerStyle = css`
207 | display: flex;
208 | flex-direction: row;
209 | justify-content: flex-end;
210 | align-items: center;
211 | flex: 1;
212 | `
213 |
214 | const buttonStyle = css`
215 | border: none;
216 | outline: none;
217 | margin-left: 15px;
218 | background-color: black;
219 | color: #340036;
220 | padding: 13px;
221 | border-radius: 25px;
222 | cursor: pointer;
223 | font-size: 14px;
224 | font-weight: 500;
225 | background-color: rgb(249, 92, 255);
226 | transition: all .35s;
227 | width: 160px;
228 | letter-spacing: .75px;
229 | &:hover {
230 | background-color: rgba(249, 92, 255, .75);
231 | }
232 | `
233 |
234 | export default MyApp
235 |
--------------------------------------------------------------------------------
/pages/profile/[id].js:
--------------------------------------------------------------------------------
1 | import { useRouter } from 'next/router'
2 | import { useState, useEffect, useContext } from 'react'
3 | import {
4 | createClient,
5 | fetchProfile,
6 | doesFollow as doesFollowQuery,
7 | createUnfollowTypedData,
8 | LENS_HUB_CONTRACT_ADDRESS,
9 | } from '../../api'
10 | import { ethers } from 'ethers'
11 | import { css } from '@emotion/css'
12 | import { AppContext } from '../../context'
13 | import { getSigner } from '../../utils'
14 | import ReactMarkdown from 'react-markdown'
15 |
16 | import LENSHUB from '../../abi/lenshub'
17 |
18 | export default function Profile() {
19 | const [profile, setProfile] = useState()
20 | const [publications, setPublications] = useState([])
21 | const [doesFollow, setDoesFollow] = useState()
22 | const [loadedState, setLoadedState] = useState('')
23 | const router = useRouter()
24 | const context = useContext(AppContext)
25 | const { id } = router.query
26 | const { userAddress, profile: userProfile } = context
27 |
28 | useEffect(() => {
29 | if (id) {
30 | getProfile()
31 | }
32 | if (id && userAddress) {
33 | checkDoesFollow()
34 | }
35 | }, [id, userAddress])
36 |
37 | async function unfollow() {
38 | try {
39 | const client = await createClient()
40 | const response = await client.mutation(createUnfollowTypedData, {
41 | request: { profile: id }
42 | }).toPromise()
43 | const typedData = response.data.createUnfollowTypedData.typedData
44 | const contract = new ethers.Contract(
45 | typedData.domain.verifyingContract,
46 | LENSHUB,
47 | getSigner()
48 | )
49 | const tx = await contract.burn(typedData.value.tokenId)
50 | setTimeout(() => {
51 | setDoesFollow(false)
52 | }, 2500)
53 | await tx.wait()
54 | console.log(`successfully unfollowed ... ${profile.handle}`)
55 | } catch (err) {
56 | console.log('error:', err)
57 | }
58 | }
59 |
60 | async function getProfile() {
61 | try {
62 | const {
63 | profile: profileData, publications: publicationData
64 | } = await fetchProfile(id)
65 | setProfile(profileData)
66 | setPublications(publicationData)
67 | setLoadedState('loaded')
68 | } catch (err) {
69 | console.log('error fetching profile...', err)
70 | }
71 | }
72 |
73 | async function checkDoesFollow() {
74 | const urqlClient = await createClient()
75 | const response = await urqlClient.query(
76 | doesFollowQuery,
77 | {
78 | request: {
79 | followInfos: [{
80 | followerAddress: userAddress,
81 | profileId: id
82 | }]
83 | }
84 | }
85 | ).toPromise()
86 | setDoesFollow(response.data.doesFollow[0].follows)
87 | }
88 |
89 | async function followUser() {
90 | const contract = new ethers.Contract(
91 | LENS_HUB_CONTRACT_ADDRESS,
92 | LENSHUB,
93 | getSigner()
94 | )
95 |
96 | try {
97 | const tx = await contract.follow([id], [0x0])
98 | setTimeout(() => {
99 | setDoesFollow(true)
100 | }, 2500)
101 | await tx.wait()
102 | console.log(`successfully followed ... ${profile.handle}`)
103 | } catch (err) {
104 | console.log('error: ', err)
105 | }
106 | }
107 |
108 | function editProfile() {
109 | router.push('/edit-profile')
110 | }
111 |
112 | if (!profile) return null
113 |
114 | const profileOwner = userProfile?.id === id
115 |
116 | return (
117 |
118 |
125 |
126 |
127 |
128 |

134 |
{profile.name}
135 |
{profile.handle}
136 |
{profile.bio}
137 |
138 | {
139 | userAddress && !profileOwner ? (
140 | doesFollow ? (
141 |
145 | ) : (
146 |
150 | )
151 | ) : null
152 | }
153 | {
154 | profileOwner && (
155 |
159 | )
160 | }
161 |
162 |
163 |
164 |
Posts
165 | {
166 | publications.map((pub, index) => (
167 |
168 |
169 | {pub.metadata.content}
170 |
171 |
172 | ))
173 | }
174 | {
175 | loadedState === 'loaded' && !publications.length && (
176 |
177 |
178 | {profile.handle} has not posted yet!
179 |
180 |
181 | )
182 | }
183 |
184 |
185 |
186 | )
187 | }
188 |
189 | const bioStyle = css`
190 | font-weight: 500;
191 | `
192 |
193 | const emptyPostTextStyle = css`
194 | text-align: center;
195 | margin: 0;
196 | `
197 |
198 | const emptyPostContainerStyle = css`
199 | background-color: white;
200 | border: 1px solid rgba(0, 0, 0, .15);
201 | padding: 25px;
202 | border-radius: 8px;
203 | `
204 |
205 | const emptyPostHandleStyle = css`
206 | font-weight: 600;
207 | `
208 |
209 | const postHeaderStyle = css`
210 | margin: 0px 0px 15px;
211 | `
212 |
213 | const publicationWrapper = css`
214 | background-color: white;
215 | margin-bottom: 15px;
216 | padding: 5px 25px;
217 | border-radius: 15px;
218 | border: 1px solid #ededed;
219 | `
220 |
221 | const publicationContentStyle = css`
222 | line-height: 26px;
223 | `
224 |
225 | const nameStyle = css`
226 | margin: 15px 0px 5px;
227 | `
228 |
229 | const handleStyle = css`
230 | margin: 0px 0px 5px;
231 | color: #b900c9;
232 | `
233 |
234 | const headerStyle = css`
235 | width: 900px;
236 | max-height: 300px;
237 | height: 300px;
238 | overflow: hidden;
239 | background-size: cover;
240 | background-position: center;
241 | `
242 |
243 | const profileImageStyle = css`
244 | width: 200px;
245 | height: 200px;
246 | max-width: 200px;
247 | border: 10px solid white;
248 | border-radius: 12px;
249 | `
250 |
251 | const columnWrapperStyle = css`
252 | margin-top: 20px;
253 | display: flex;
254 | flex-direction: row;
255 | `
256 |
257 | const rightColumnStyle = css`
258 | margin-left: 20px;
259 | flex: 1;
260 | `
261 |
262 | const containerStyle = css`
263 | padding-top: 50px;
264 | `
265 |
266 | const buttonStyle = css`
267 | border: 2px solid rgb(249, 92, 255);
268 | outline: none;
269 | margin-top: 15px;
270 | color: rgb(249, 92, 255);
271 | padding: 13px;
272 | border-radius: 5px;
273 | cursor: pointer;
274 | font-size: 14px;
275 | font-weight: 500;
276 | transition: all .35s;
277 | font-weight: 700;
278 | width: 100%;
279 | letter-spacing: .75px;
280 | &:hover {
281 | background-color: rgb(249, 92, 255);
282 | color: white;
283 | }
284 | `
--------------------------------------------------------------------------------
/api/queries.js:
--------------------------------------------------------------------------------
1 | const recommendProfiles = `
2 | query RecommendedProfiles {
3 | recommendedProfiles {
4 | id
5 | name
6 | picture {
7 | ... on MediaSet {
8 | original {
9 | url
10 | }
11 | }
12 | }
13 | handle
14 | stats {
15 | totalFollowers
16 | }
17 | }
18 | }
19 | `
20 |
21 | const getProfiles = `
22 | query Profiles($id: ProfileId!) {
23 | profiles(request: { profileIds: [$id], limit: 25 }) {
24 | items {
25 | id
26 | name
27 | bio
28 | attributes {
29 | displayType
30 | traitType
31 | key
32 | value
33 | }
34 | metadata
35 | isDefault
36 | picture {
37 | ... on NftImage {
38 | contractAddress
39 | tokenId
40 | uri
41 | verified
42 | }
43 | ... on MediaSet {
44 | original {
45 | url
46 | mimeType
47 | }
48 | }
49 | __typename
50 | }
51 | handle
52 | coverPicture {
53 | ... on NftImage {
54 | contractAddress
55 | tokenId
56 | uri
57 | verified
58 | }
59 | ... on MediaSet {
60 | original {
61 | url
62 | mimeType
63 | }
64 | }
65 | __typename
66 | }
67 | ownedBy
68 | dispatcher {
69 | address
70 | canUseRelay
71 | }
72 | stats {
73 | totalFollowers
74 | totalFollowing
75 | totalPosts
76 | totalComments
77 | totalMirrors
78 | totalPublications
79 | totalCollects
80 | }
81 | }
82 | pageInfo {
83 | prev
84 | next
85 | totalCount
86 | }
87 | }
88 | }
89 | `
90 |
91 | const getDefaultProfile = `
92 | query DefaultProfile($address: EthereumAddress!) {
93 | defaultProfile(request: { ethereumAddress: $address}) {
94 | id
95 | name
96 | bio
97 | isDefault
98 | attributes {
99 | displayType
100 | traitType
101 | key
102 | value
103 | }
104 | followNftAddress
105 | metadata
106 | handle
107 | picture {
108 | ... on NftImage {
109 | contractAddress
110 | tokenId
111 | uri
112 | chainId
113 | verified
114 | }
115 | ... on MediaSet {
116 | original {
117 | url
118 | mimeType
119 | }
120 | }
121 | }
122 | coverPicture {
123 | ... on NftImage {
124 | contractAddress
125 | tokenId
126 | uri
127 | chainId
128 | verified
129 | }
130 | ... on MediaSet {
131 | original {
132 | url
133 | mimeType
134 | }
135 | }
136 | }
137 | ownedBy
138 | dispatcher {
139 | address
140 | canUseRelay
141 | }
142 | stats {
143 | totalFollowers
144 | totalFollowing
145 | totalPosts
146 | totalComments
147 | totalMirrors
148 | totalPublications
149 | totalCollects
150 | }
151 | followModule {
152 | ... on FeeFollowModuleSettings {
153 | type
154 | contractAddress
155 | amount {
156 | asset {
157 | name
158 | symbol
159 | decimals
160 | address
161 | }
162 | value
163 | }
164 | recipient
165 | }
166 | ... on ProfileFollowModuleSettings {
167 | type
168 | }
169 | ... on RevertFollowModuleSettings {
170 | type
171 | }
172 | }
173 | }
174 | }
175 |
176 | `
177 |
178 | const getPublications = `
179 | query Publications($id: ProfileId!, $limit: LimitScalar) {
180 | publications(request: {
181 | profileId: $id,
182 | publicationTypes: [POST],
183 | limit: $limit
184 | }) {
185 | items {
186 | __typename
187 | ... on Post {
188 | ...PostFields
189 | }
190 | }
191 | }
192 | }
193 |
194 | fragment PostFields on Post {
195 | id
196 | metadata {
197 | ...MetadataOutputFields
198 | }
199 | createdAt
200 | }
201 |
202 |
203 | fragment MetadataOutputFields on MetadataOutput {
204 | name
205 | description
206 | content
207 | media {
208 | original {
209 | ...MediaFields
210 | }
211 | }
212 | attributes {
213 | displayType
214 | traitType
215 | value
216 | }
217 | }
218 |
219 | fragment MediaFields on Media {
220 | url
221 | mimeType
222 | }
223 | `
224 |
225 | const searchPublications = `query Search($query: Search!, $type: SearchRequestTypes!) {
226 | search(request: {
227 | query: $query,
228 | type: $type,
229 | limit: 10
230 | }) {
231 | ... on PublicationSearchResult {
232 | __typename
233 | items {
234 | __typename
235 | ... on Comment {
236 | ...CommentFields
237 | }
238 | ... on Post {
239 | ...PostFields
240 | }
241 | }
242 | pageInfo {
243 | prev
244 | totalCount
245 | next
246 | }
247 | }
248 | }
249 | }
250 |
251 | fragment MediaFields on Media {
252 | url
253 | mimeType
254 | }
255 |
256 | fragment MirrorBaseFields on Mirror {
257 | id
258 | profile {
259 | ...ProfileFields
260 | }
261 | stats {
262 | ...PublicationStatsFields
263 | }
264 | metadata {
265 | ...MetadataOutputFields
266 | }
267 | createdAt
268 | collectModule {
269 | ...CollectModuleFields
270 | }
271 | referenceModule {
272 | ... on FollowOnlyReferenceModuleSettings {
273 | type
274 | }
275 | }
276 | appId
277 | }
278 |
279 | fragment ProfileFields on Profile {
280 | profileId: id,
281 | name
282 | bio
283 | attributes {
284 | displayType
285 | traitType
286 | key
287 | value
288 | }
289 | metadata
290 | isDefault
291 | handle
292 | picture {
293 | ... on NftImage {
294 | contractAddress
295 | tokenId
296 | uri
297 | verified
298 | }
299 | ... on MediaSet {
300 | original {
301 | ...MediaFields
302 | }
303 | }
304 | }
305 | coverPicture {
306 | ... on NftImage {
307 | contractAddress
308 | tokenId
309 | uri
310 | verified
311 | }
312 | ... on MediaSet {
313 | original {
314 | ...MediaFields
315 | }
316 | }
317 | }
318 | ownedBy
319 | dispatcher {
320 | address
321 | }
322 | stats {
323 | totalFollowers
324 | totalFollowing
325 | totalPosts
326 | totalComments
327 | totalMirrors
328 | totalPublications
329 | totalCollects
330 | }
331 | followModule {
332 | ... on FeeFollowModuleSettings {
333 | type
334 | amount {
335 | asset {
336 | name
337 | symbol
338 | decimals
339 | address
340 | }
341 | value
342 | }
343 | recipient
344 | }
345 | ... on ProfileFollowModuleSettings {
346 | type
347 | }
348 | ... on RevertFollowModuleSettings {
349 | type
350 | }
351 | }
352 | }
353 |
354 | fragment PublicationStatsFields on PublicationStats {
355 | totalAmountOfMirrors
356 | totalAmountOfCollects
357 | totalAmountOfComments
358 | }
359 |
360 | fragment MetadataOutputFields on MetadataOutput {
361 | name
362 | description
363 | content
364 | media {
365 | original {
366 | ...MediaFields
367 | }
368 | }
369 | attributes {
370 | displayType
371 | traitType
372 | value
373 | }
374 | }
375 |
376 | fragment Erc20Fields on Erc20 {
377 | name
378 | symbol
379 | decimals
380 | address
381 | }
382 |
383 | fragment CollectModuleFields on CollectModule {
384 | __typename
385 | ... on FreeCollectModuleSettings {
386 | type
387 | followerOnly
388 | contractAddress
389 | }
390 | ... on FeeCollectModuleSettings {
391 | type
392 | amount {
393 | asset {
394 | ...Erc20Fields
395 | }
396 | value
397 | }
398 | recipient
399 | referralFee
400 | }
401 | ... on LimitedFeeCollectModuleSettings {
402 | type
403 | collectLimit
404 | amount {
405 | asset {
406 | ...Erc20Fields
407 | }
408 | value
409 | }
410 | recipient
411 | referralFee
412 | }
413 | ... on LimitedTimedFeeCollectModuleSettings {
414 | type
415 | collectLimit
416 | amount {
417 | asset {
418 | ...Erc20Fields
419 | }
420 | value
421 | }
422 | recipient
423 | referralFee
424 | endTimestamp
425 | }
426 | ... on RevertCollectModuleSettings {
427 | type
428 | }
429 | ... on TimedFeeCollectModuleSettings {
430 | type
431 | amount {
432 | asset {
433 | ...Erc20Fields
434 | }
435 | value
436 | }
437 | recipient
438 | referralFee
439 | endTimestamp
440 | }
441 | }
442 |
443 | fragment PostFields on Post {
444 | id
445 | profile {
446 | ...ProfileFields
447 | }
448 | stats {
449 | ...PublicationStatsFields
450 | }
451 | metadata {
452 | ...MetadataOutputFields
453 | }
454 | createdAt
455 | collectModule {
456 | ...CollectModuleFields
457 | }
458 | referenceModule {
459 | ... on FollowOnlyReferenceModuleSettings {
460 | type
461 | }
462 | }
463 | appId
464 | }
465 |
466 | fragment CommentBaseFields on Comment {
467 | id
468 | profile {
469 | ...ProfileFields
470 | }
471 | stats {
472 | ...PublicationStatsFields
473 | }
474 | metadata {
475 | ...MetadataOutputFields
476 | }
477 | createdAt
478 | collectModule {
479 | ...CollectModuleFields
480 | }
481 | referenceModule {
482 | ... on FollowOnlyReferenceModuleSettings {
483 | type
484 | }
485 | }
486 | appId
487 | }
488 |
489 | fragment CommentFields on Comment {
490 | ...CommentBaseFields
491 | mainPost {
492 | ... on Post {
493 | ...PostFields
494 | }
495 | ... on Mirror {
496 | ...MirrorBaseFields
497 | mirrorOf {
498 | ... on Post {
499 | ...PostFields
500 | }
501 | ... on Comment {
502 | ...CommentMirrorOfFields
503 | }
504 | }
505 | }
506 | }
507 | }
508 |
509 | fragment CommentMirrorOfFields on Comment {
510 | ...CommentBaseFields
511 | mainPost {
512 | ... on Post {
513 | ...PostFields
514 | }
515 | ... on Mirror {
516 | ...MirrorBaseFields
517 | }
518 | }
519 | }
520 | `
521 |
522 | const searchProfiles = `
523 | query Search($query: Search!, $type: SearchRequestTypes!) {
524 | search(request: {
525 | query: $query,
526 | type: $type,
527 | limit: 10
528 | }) {
529 | ... on ProfileSearchResult {
530 | __typename
531 | items {
532 | ... on Profile {
533 | ...ProfileFields
534 | }
535 | }
536 | pageInfo {
537 | prev
538 | totalCount
539 | next
540 | }
541 | }
542 | }
543 | }
544 |
545 | fragment MediaFields on Media {
546 | url
547 | }
548 |
549 | fragment ProfileFields on Profile {
550 | profileId: id,
551 | name
552 | bio
553 | attributes {
554 | displayType
555 | traitType
556 | key
557 | value
558 | }
559 | metadata
560 | isDefault
561 | handle
562 | picture {
563 | ... on NftImage {
564 | contractAddress
565 | tokenId
566 | uri
567 | verified
568 | }
569 | ... on MediaSet {
570 | original {
571 | ...MediaFields
572 | }
573 | }
574 | }
575 |
576 | stats {
577 | totalFollowers
578 | totalFollowing
579 | }
580 | }
581 | `
582 |
583 | const explorePublications = `
584 | query {
585 | explorePublications(request: {
586 | sortCriteria: TOP_COMMENTED,
587 | publicationTypes: [POST, COMMENT, MIRROR],
588 | limit: 10
589 | }) {
590 | items {
591 | __typename
592 | ... on Post {
593 | ...PostFields
594 | }
595 | }
596 | }
597 | }
598 |
599 | fragment ProfileFields on Profile {
600 | id
601 | name
602 | bio
603 | attributes {
604 | displayType
605 | traitType
606 | key
607 | value
608 | }
609 | metadata
610 | isDefault
611 | handle
612 | picture {
613 | ... on NftImage {
614 | contractAddress
615 | tokenId
616 | uri
617 | verified
618 | }
619 | ... on MediaSet {
620 | original {
621 | ...MediaFields
622 | }
623 | small {
624 | ...MediaFields
625 | }
626 | medium {
627 | ...MediaFields
628 | }
629 | }
630 | }
631 | coverPicture {
632 | ... on NftImage {
633 | contractAddress
634 | tokenId
635 | uri
636 | verified
637 | }
638 | ... on MediaSet {
639 | original {
640 | ...MediaFields
641 | }
642 | small {
643 | ...MediaFields
644 | }
645 | medium {
646 | ...MediaFields
647 | }
648 | }
649 | }
650 | ownedBy
651 | dispatcher {
652 | address
653 | }
654 | stats {
655 | totalFollowers
656 | totalFollowing
657 | totalPosts
658 | totalComments
659 | totalMirrors
660 | totalPublications
661 | totalCollects
662 | }
663 | followModule {
664 | ... on FeeFollowModuleSettings {
665 | type
666 | amount {
667 | asset {
668 | name
669 | symbol
670 | decimals
671 | address
672 | }
673 | value
674 | }
675 | recipient
676 | }
677 | ... on ProfileFollowModuleSettings {
678 | type
679 | }
680 | ... on RevertFollowModuleSettings {
681 | type
682 | }
683 | }
684 | }
685 |
686 | fragment MediaFields on Media {
687 | url
688 | width
689 | height
690 | mimeType
691 | }
692 |
693 | fragment PublicationStatsFields on PublicationStats {
694 | totalAmountOfMirrors
695 | totalAmountOfCollects
696 | totalAmountOfComments
697 | }
698 |
699 | fragment MetadataOutputFields on MetadataOutput {
700 | name
701 | description
702 | content
703 | media {
704 | original {
705 | ...MediaFields
706 | }
707 | small {
708 | ...MediaFields
709 | }
710 | medium {
711 | ...MediaFields
712 | }
713 | }
714 | attributes {
715 | displayType
716 | traitType
717 | value
718 | }
719 | }
720 |
721 | fragment PostFields on Post {
722 | id
723 | profile {
724 | ...ProfileFields
725 | }
726 | stats {
727 | ...PublicationStatsFields
728 | }
729 | metadata {
730 | ...MetadataOutputFields
731 | }
732 | createdAt
733 | appId
734 | }
735 | `
736 |
737 | const getChallenge = `
738 | query Challenge($address: EthereumAddress!) {
739 | challenge(request: { address: $address }) {
740 | text
741 | }
742 | }
743 | `
744 |
745 | const doesFollow = `
746 | query($request: DoesFollowRequest!) {
747 | doesFollow(request: $request) {
748 | followerAddress
749 | profileId
750 | follows
751 | }
752 | }
753 | `
754 |
755 | const timeline = `
756 | query Timeline($profileId: ProfileId!, $limit: LimitScalar) {
757 | timeline(request: { profileId: $profileId, limit: $limit }) {
758 | items {
759 | __typename
760 | ... on Post {
761 | ...PostFields
762 | }
763 | ... on Comment {
764 | ...CommentFields
765 | }
766 | ... on Mirror {
767 | ...MirrorFields
768 | }
769 | }
770 | pageInfo {
771 | prev
772 | next
773 | totalCount
774 | }
775 | }
776 | }
777 |
778 | fragment MediaFields on Media {
779 | url
780 | mimeType
781 | }
782 |
783 | fragment ProfileFields on Profile {
784 | id
785 | name
786 | bio
787 | attributes {
788 | displayType
789 | traitType
790 | key
791 | value
792 | }
793 | isFollowedByMe
794 | isFollowing(who: null)
795 | followNftAddress
796 | metadata
797 | isDefault
798 | handle
799 | picture {
800 | ... on NftImage {
801 | contractAddress
802 | tokenId
803 | uri
804 | verified
805 | }
806 | ... on MediaSet {
807 | original {
808 | ...MediaFields
809 | }
810 | }
811 | }
812 | coverPicture {
813 | ... on NftImage {
814 | contractAddress
815 | tokenId
816 | uri
817 | verified
818 | }
819 | ... on MediaSet {
820 | original {
821 | ...MediaFields
822 | }
823 | }
824 | }
825 | ownedBy
826 | dispatcher {
827 | address
828 | }
829 | stats {
830 | totalFollowers
831 | totalFollowing
832 | totalPosts
833 | totalComments
834 | totalMirrors
835 | totalPublications
836 | totalCollects
837 | }
838 | followModule {
839 | ... on FeeFollowModuleSettings {
840 | type
841 | amount {
842 | asset {
843 | name
844 | symbol
845 | decimals
846 | address
847 | }
848 | value
849 | }
850 | recipient
851 | }
852 | ... on ProfileFollowModuleSettings {
853 | type
854 | }
855 | ... on RevertFollowModuleSettings {
856 | type
857 | }
858 | }
859 | }
860 |
861 | fragment PublicationStatsFields on PublicationStats {
862 | totalAmountOfMirrors
863 | totalAmountOfCollects
864 | totalAmountOfComments
865 | }
866 |
867 | fragment MetadataOutputFields on MetadataOutput {
868 | name
869 | description
870 | content
871 | media {
872 | original {
873 | ...MediaFields
874 | }
875 | }
876 | attributes {
877 | displayType
878 | traitType
879 | value
880 | }
881 | }
882 |
883 | fragment Erc20Fields on Erc20 {
884 | name
885 | symbol
886 | decimals
887 | address
888 | }
889 |
890 | fragment CollectModuleFields on CollectModule {
891 | __typename
892 | ... on FreeCollectModuleSettings {
893 | type
894 | followerOnly
895 | contractAddress
896 | }
897 | ... on FeeCollectModuleSettings {
898 | type
899 | amount {
900 | asset {
901 | ...Erc20Fields
902 | }
903 | value
904 | }
905 | recipient
906 | referralFee
907 | }
908 | ... on LimitedFeeCollectModuleSettings {
909 | type
910 | collectLimit
911 | amount {
912 | asset {
913 | ...Erc20Fields
914 | }
915 | value
916 | }
917 | recipient
918 | referralFee
919 | }
920 | ... on LimitedTimedFeeCollectModuleSettings {
921 | type
922 | collectLimit
923 | amount {
924 | asset {
925 | ...Erc20Fields
926 | }
927 | value
928 | }
929 | recipient
930 | referralFee
931 | endTimestamp
932 | }
933 | ... on RevertCollectModuleSettings {
934 | type
935 | }
936 | ... on TimedFeeCollectModuleSettings {
937 | type
938 | amount {
939 | asset {
940 | ...Erc20Fields
941 | }
942 | value
943 | }
944 | recipient
945 | referralFee
946 | endTimestamp
947 | }
948 | }
949 |
950 | fragment PostFields on Post {
951 | id
952 | profile {
953 | ...ProfileFields
954 | }
955 | stats {
956 | ...PublicationStatsFields
957 | }
958 | metadata {
959 | ...MetadataOutputFields
960 | }
961 | createdAt
962 | collectModule {
963 | ...CollectModuleFields
964 | }
965 | referenceModule {
966 | ... on FollowOnlyReferenceModuleSettings {
967 | type
968 | }
969 | }
970 | appId
971 | collectedBy {
972 | ...WalletFields
973 | }
974 | hidden
975 | reaction(request: null)
976 | mirrors(by: null)
977 | hasCollectedByMe
978 | }
979 |
980 | fragment MirrorBaseFields on Mirror {
981 | id
982 | profile {
983 | ...ProfileFields
984 | }
985 | stats {
986 | ...PublicationStatsFields
987 | }
988 | metadata {
989 | ...MetadataOutputFields
990 | }
991 | createdAt
992 | collectModule {
993 | ...CollectModuleFields
994 | }
995 | referenceModule {
996 | ... on FollowOnlyReferenceModuleSettings {
997 | type
998 | }
999 | }
1000 | appId
1001 | hidden
1002 | reaction(request: null)
1003 | hasCollectedByMe
1004 | }
1005 |
1006 | fragment MirrorFields on Mirror {
1007 | ...MirrorBaseFields
1008 | mirrorOf {
1009 | ... on Post {
1010 | ...PostFields
1011 | }
1012 | ... on Comment {
1013 | ...CommentFields
1014 | }
1015 | }
1016 | }
1017 |
1018 | fragment CommentBaseFields on Comment {
1019 | id
1020 | profile {
1021 | ...ProfileFields
1022 | }
1023 | stats {
1024 | ...PublicationStatsFields
1025 | }
1026 | metadata {
1027 | ...MetadataOutputFields
1028 | }
1029 | createdAt
1030 | collectModule {
1031 | ...CollectModuleFields
1032 | }
1033 | referenceModule {
1034 | ... on FollowOnlyReferenceModuleSettings {
1035 | type
1036 | }
1037 | }
1038 | appId
1039 | collectedBy {
1040 | ...WalletFields
1041 | }
1042 | hidden
1043 | reaction(request: null)
1044 | mirrors(by: null)
1045 | hasCollectedByMe
1046 | }
1047 |
1048 | fragment CommentFields on Comment {
1049 | ...CommentBaseFields
1050 | mainPost {
1051 | ... on Post {
1052 | ...PostFields
1053 | }
1054 | ... on Mirror {
1055 | ...MirrorBaseFields
1056 | mirrorOf {
1057 | ... on Post {
1058 | ...PostFields
1059 | }
1060 | ... on Comment {
1061 | ...CommentMirrorOfFields
1062 | }
1063 | }
1064 | }
1065 | }
1066 | }
1067 |
1068 | fragment CommentMirrorOfFields on Comment {
1069 | ...CommentBaseFields
1070 | mainPost {
1071 | ... on Post {
1072 | ...PostFields
1073 | }
1074 | ... on Mirror {
1075 | ...MirrorBaseFields
1076 | }
1077 | }
1078 | }
1079 |
1080 | fragment WalletFields on Wallet {
1081 | address,
1082 | defaultProfile {
1083 | ...ProfileFields
1084 | }
1085 | }
1086 | `
1087 |
1088 | /*
1089 | * const doesFollowRequest = {
1090 | * followInfos: [{ followerAddress: EthereumAddress!, profileId: ProfileId! }]
1091 | * }
1092 | */
1093 |
1094 | export {
1095 | recommendProfiles,
1096 | getProfiles,
1097 | getDefaultProfile,
1098 | getPublications,
1099 | searchProfiles,
1100 | searchPublications,
1101 | explorePublications,
1102 | doesFollow,
1103 | getChallenge,
1104 | timeline
1105 | }
1106 |
--------------------------------------------------------------------------------
/abi/lenshub.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "inputs": [
4 | {
5 | "internalType": "address",
6 | "name": "followNFTImpl",
7 | "type": "address"
8 | },
9 | {
10 | "internalType": "address",
11 | "name": "collectNFTImpl",
12 | "type": "address"
13 | }
14 | ],
15 | "stateMutability": "nonpayable",
16 | "type": "constructor"
17 | },
18 | {
19 | "inputs": [],
20 | "name": "CallerNotCollectNFT",
21 | "type": "error"
22 | },
23 | {
24 | "inputs": [],
25 | "name": "CallerNotFollowNFT",
26 | "type": "error"
27 | },
28 | {
29 | "inputs": [],
30 | "name": "CannotInitImplementation",
31 | "type": "error"
32 | },
33 | {
34 | "inputs": [],
35 | "name": "EmergencyAdminCannotUnpause",
36 | "type": "error"
37 | },
38 | {
39 | "inputs": [],
40 | "name": "InitParamsInvalid",
41 | "type": "error"
42 | },
43 | {
44 | "inputs": [],
45 | "name": "Initialized",
46 | "type": "error"
47 | },
48 | {
49 | "inputs": [],
50 | "name": "NotGovernance",
51 | "type": "error"
52 | },
53 | {
54 | "inputs": [],
55 | "name": "NotGovernanceOrEmergencyAdmin",
56 | "type": "error"
57 | },
58 | {
59 | "inputs": [],
60 | "name": "NotOwnerOrApproved",
61 | "type": "error"
62 | },
63 | {
64 | "inputs": [],
65 | "name": "NotProfileOwner",
66 | "type": "error"
67 | },
68 | {
69 | "inputs": [],
70 | "name": "NotProfileOwnerOrDispatcher",
71 | "type": "error"
72 | },
73 | {
74 | "inputs": [],
75 | "name": "Paused",
76 | "type": "error"
77 | },
78 | {
79 | "inputs": [],
80 | "name": "ProfileCreatorNotWhitelisted",
81 | "type": "error"
82 | },
83 | {
84 | "inputs": [],
85 | "name": "ProfileImageURILengthInvalid",
86 | "type": "error"
87 | },
88 | {
89 | "inputs": [],
90 | "name": "PublicationDoesNotExist",
91 | "type": "error"
92 | },
93 | {
94 | "inputs": [],
95 | "name": "PublishingPaused",
96 | "type": "error"
97 | },
98 | {
99 | "inputs": [],
100 | "name": "SignatureExpired",
101 | "type": "error"
102 | },
103 | {
104 | "inputs": [],
105 | "name": "SignatureInvalid",
106 | "type": "error"
107 | },
108 | {
109 | "inputs": [],
110 | "name": "ZeroSpender",
111 | "type": "error"
112 | },
113 | {
114 | "anonymous": false,
115 | "inputs": [
116 | {
117 | "indexed": true,
118 | "internalType": "address",
119 | "name": "owner",
120 | "type": "address"
121 | },
122 | {
123 | "indexed": true,
124 | "internalType": "address",
125 | "name": "approved",
126 | "type": "address"
127 | },
128 | {
129 | "indexed": true,
130 | "internalType": "uint256",
131 | "name": "tokenId",
132 | "type": "uint256"
133 | }
134 | ],
135 | "name": "Approval",
136 | "type": "event"
137 | },
138 | {
139 | "anonymous": false,
140 | "inputs": [
141 | {
142 | "indexed": true,
143 | "internalType": "address",
144 | "name": "owner",
145 | "type": "address"
146 | },
147 | {
148 | "indexed": true,
149 | "internalType": "address",
150 | "name": "operator",
151 | "type": "address"
152 | },
153 | {
154 | "indexed": false,
155 | "internalType": "bool",
156 | "name": "approved",
157 | "type": "bool"
158 | }
159 | ],
160 | "name": "ApprovalForAll",
161 | "type": "event"
162 | },
163 | {
164 | "anonymous": false,
165 | "inputs": [
166 | {
167 | "indexed": true,
168 | "internalType": "address",
169 | "name": "from",
170 | "type": "address"
171 | },
172 | {
173 | "indexed": true,
174 | "internalType": "address",
175 | "name": "to",
176 | "type": "address"
177 | },
178 | {
179 | "indexed": true,
180 | "internalType": "uint256",
181 | "name": "tokenId",
182 | "type": "uint256"
183 | }
184 | ],
185 | "name": "Transfer",
186 | "type": "event"
187 | },
188 | {
189 | "inputs": [
190 | {
191 | "internalType": "address",
192 | "name": "to",
193 | "type": "address"
194 | },
195 | {
196 | "internalType": "uint256",
197 | "name": "tokenId",
198 | "type": "uint256"
199 | }
200 | ],
201 | "name": "approve",
202 | "outputs": [],
203 | "stateMutability": "nonpayable",
204 | "type": "function"
205 | },
206 | {
207 | "inputs": [
208 | {
209 | "internalType": "address",
210 | "name": "owner",
211 | "type": "address"
212 | }
213 | ],
214 | "name": "balanceOf",
215 | "outputs": [
216 | {
217 | "internalType": "uint256",
218 | "name": "",
219 | "type": "uint256"
220 | }
221 | ],
222 | "stateMutability": "view",
223 | "type": "function"
224 | },
225 | {
226 | "inputs": [
227 | {
228 | "internalType": "uint256",
229 | "name": "tokenId",
230 | "type": "uint256"
231 | }
232 | ],
233 | "name": "burn",
234 | "outputs": [],
235 | "stateMutability": "nonpayable",
236 | "type": "function"
237 | },
238 | {
239 | "inputs": [
240 | {
241 | "internalType": "uint256",
242 | "name": "tokenId",
243 | "type": "uint256"
244 | },
245 | {
246 | "components": [
247 | {
248 | "internalType": "uint8",
249 | "name": "v",
250 | "type": "uint8"
251 | },
252 | {
253 | "internalType": "bytes32",
254 | "name": "r",
255 | "type": "bytes32"
256 | },
257 | {
258 | "internalType": "bytes32",
259 | "name": "s",
260 | "type": "bytes32"
261 | },
262 | {
263 | "internalType": "uint256",
264 | "name": "deadline",
265 | "type": "uint256"
266 | }
267 | ],
268 | "internalType": "struct DataTypes.EIP712Signature",
269 | "name": "sig",
270 | "type": "tuple"
271 | }
272 | ],
273 | "name": "burnWithSig",
274 | "outputs": [],
275 | "stateMutability": "nonpayable",
276 | "type": "function"
277 | },
278 | {
279 | "inputs": [
280 | {
281 | "internalType": "uint256",
282 | "name": "profileId",
283 | "type": "uint256"
284 | },
285 | {
286 | "internalType": "uint256",
287 | "name": "pubId",
288 | "type": "uint256"
289 | },
290 | {
291 | "internalType": "bytes",
292 | "name": "data",
293 | "type": "bytes"
294 | }
295 | ],
296 | "name": "collect",
297 | "outputs": [
298 | {
299 | "internalType": "uint256",
300 | "name": "",
301 | "type": "uint256"
302 | }
303 | ],
304 | "stateMutability": "nonpayable",
305 | "type": "function"
306 | },
307 | {
308 | "inputs": [
309 | {
310 | "components": [
311 | {
312 | "internalType": "address",
313 | "name": "collector",
314 | "type": "address"
315 | },
316 | {
317 | "internalType": "uint256",
318 | "name": "profileId",
319 | "type": "uint256"
320 | },
321 | {
322 | "internalType": "uint256",
323 | "name": "pubId",
324 | "type": "uint256"
325 | },
326 | {
327 | "internalType": "bytes",
328 | "name": "data",
329 | "type": "bytes"
330 | },
331 | {
332 | "components": [
333 | {
334 | "internalType": "uint8",
335 | "name": "v",
336 | "type": "uint8"
337 | },
338 | {
339 | "internalType": "bytes32",
340 | "name": "r",
341 | "type": "bytes32"
342 | },
343 | {
344 | "internalType": "bytes32",
345 | "name": "s",
346 | "type": "bytes32"
347 | },
348 | {
349 | "internalType": "uint256",
350 | "name": "deadline",
351 | "type": "uint256"
352 | }
353 | ],
354 | "internalType": "struct DataTypes.EIP712Signature",
355 | "name": "sig",
356 | "type": "tuple"
357 | }
358 | ],
359 | "internalType": "struct DataTypes.CollectWithSigData",
360 | "name": "vars",
361 | "type": "tuple"
362 | }
363 | ],
364 | "name": "collectWithSig",
365 | "outputs": [
366 | {
367 | "internalType": "uint256",
368 | "name": "",
369 | "type": "uint256"
370 | }
371 | ],
372 | "stateMutability": "nonpayable",
373 | "type": "function"
374 | },
375 | {
376 | "inputs": [
377 | {
378 | "components": [
379 | {
380 | "internalType": "uint256",
381 | "name": "profileId",
382 | "type": "uint256"
383 | },
384 | {
385 | "internalType": "string",
386 | "name": "contentURI",
387 | "type": "string"
388 | },
389 | {
390 | "internalType": "uint256",
391 | "name": "profileIdPointed",
392 | "type": "uint256"
393 | },
394 | {
395 | "internalType": "uint256",
396 | "name": "pubIdPointed",
397 | "type": "uint256"
398 | },
399 | {
400 | "internalType": "bytes",
401 | "name": "referenceModuleData",
402 | "type": "bytes"
403 | },
404 | {
405 | "internalType": "address",
406 | "name": "collectModule",
407 | "type": "address"
408 | },
409 | {
410 | "internalType": "bytes",
411 | "name": "collectModuleInitData",
412 | "type": "bytes"
413 | },
414 | {
415 | "internalType": "address",
416 | "name": "referenceModule",
417 | "type": "address"
418 | },
419 | {
420 | "internalType": "bytes",
421 | "name": "referenceModuleInitData",
422 | "type": "bytes"
423 | }
424 | ],
425 | "internalType": "struct DataTypes.CommentData",
426 | "name": "vars",
427 | "type": "tuple"
428 | }
429 | ],
430 | "name": "comment",
431 | "outputs": [
432 | {
433 | "internalType": "uint256",
434 | "name": "",
435 | "type": "uint256"
436 | }
437 | ],
438 | "stateMutability": "nonpayable",
439 | "type": "function"
440 | },
441 | {
442 | "inputs": [
443 | {
444 | "components": [
445 | {
446 | "internalType": "uint256",
447 | "name": "profileId",
448 | "type": "uint256"
449 | },
450 | {
451 | "internalType": "string",
452 | "name": "contentURI",
453 | "type": "string"
454 | },
455 | {
456 | "internalType": "uint256",
457 | "name": "profileIdPointed",
458 | "type": "uint256"
459 | },
460 | {
461 | "internalType": "uint256",
462 | "name": "pubIdPointed",
463 | "type": "uint256"
464 | },
465 | {
466 | "internalType": "bytes",
467 | "name": "referenceModuleData",
468 | "type": "bytes"
469 | },
470 | {
471 | "internalType": "address",
472 | "name": "collectModule",
473 | "type": "address"
474 | },
475 | {
476 | "internalType": "bytes",
477 | "name": "collectModuleInitData",
478 | "type": "bytes"
479 | },
480 | {
481 | "internalType": "address",
482 | "name": "referenceModule",
483 | "type": "address"
484 | },
485 | {
486 | "internalType": "bytes",
487 | "name": "referenceModuleInitData",
488 | "type": "bytes"
489 | },
490 | {
491 | "components": [
492 | {
493 | "internalType": "uint8",
494 | "name": "v",
495 | "type": "uint8"
496 | },
497 | {
498 | "internalType": "bytes32",
499 | "name": "r",
500 | "type": "bytes32"
501 | },
502 | {
503 | "internalType": "bytes32",
504 | "name": "s",
505 | "type": "bytes32"
506 | },
507 | {
508 | "internalType": "uint256",
509 | "name": "deadline",
510 | "type": "uint256"
511 | }
512 | ],
513 | "internalType": "struct DataTypes.EIP712Signature",
514 | "name": "sig",
515 | "type": "tuple"
516 | }
517 | ],
518 | "internalType": "struct DataTypes.CommentWithSigData",
519 | "name": "vars",
520 | "type": "tuple"
521 | }
522 | ],
523 | "name": "commentWithSig",
524 | "outputs": [
525 | {
526 | "internalType": "uint256",
527 | "name": "",
528 | "type": "uint256"
529 | }
530 | ],
531 | "stateMutability": "nonpayable",
532 | "type": "function"
533 | },
534 | {
535 | "inputs": [
536 | {
537 | "components": [
538 | {
539 | "internalType": "address",
540 | "name": "to",
541 | "type": "address"
542 | },
543 | {
544 | "internalType": "string",
545 | "name": "handle",
546 | "type": "string"
547 | },
548 | {
549 | "internalType": "string",
550 | "name": "imageURI",
551 | "type": "string"
552 | },
553 | {
554 | "internalType": "address",
555 | "name": "followModule",
556 | "type": "address"
557 | },
558 | {
559 | "internalType": "bytes",
560 | "name": "followModuleInitData",
561 | "type": "bytes"
562 | },
563 | {
564 | "internalType": "string",
565 | "name": "followNFTURI",
566 | "type": "string"
567 | }
568 | ],
569 | "internalType": "struct DataTypes.CreateProfileData",
570 | "name": "vars",
571 | "type": "tuple"
572 | }
573 | ],
574 | "name": "createProfile",
575 | "outputs": [
576 | {
577 | "internalType": "uint256",
578 | "name": "",
579 | "type": "uint256"
580 | }
581 | ],
582 | "stateMutability": "nonpayable",
583 | "type": "function"
584 | },
585 | {
586 | "inputs": [
587 | {
588 | "internalType": "address",
589 | "name": "wallet",
590 | "type": "address"
591 | }
592 | ],
593 | "name": "defaultProfile",
594 | "outputs": [
595 | {
596 | "internalType": "uint256",
597 | "name": "",
598 | "type": "uint256"
599 | }
600 | ],
601 | "stateMutability": "view",
602 | "type": "function"
603 | },
604 | {
605 | "inputs": [
606 | {
607 | "internalType": "uint256",
608 | "name": "profileId",
609 | "type": "uint256"
610 | },
611 | {
612 | "internalType": "uint256",
613 | "name": "pubId",
614 | "type": "uint256"
615 | },
616 | {
617 | "internalType": "uint256",
618 | "name": "collectNFTId",
619 | "type": "uint256"
620 | },
621 | {
622 | "internalType": "address",
623 | "name": "from",
624 | "type": "address"
625 | },
626 | {
627 | "internalType": "address",
628 | "name": "to",
629 | "type": "address"
630 | }
631 | ],
632 | "name": "emitCollectNFTTransferEvent",
633 | "outputs": [],
634 | "stateMutability": "nonpayable",
635 | "type": "function"
636 | },
637 | {
638 | "inputs": [
639 | {
640 | "internalType": "uint256",
641 | "name": "profileId",
642 | "type": "uint256"
643 | },
644 | {
645 | "internalType": "uint256",
646 | "name": "followNFTId",
647 | "type": "uint256"
648 | },
649 | {
650 | "internalType": "address",
651 | "name": "from",
652 | "type": "address"
653 | },
654 | {
655 | "internalType": "address",
656 | "name": "to",
657 | "type": "address"
658 | }
659 | ],
660 | "name": "emitFollowNFTTransferEvent",
661 | "outputs": [],
662 | "stateMutability": "nonpayable",
663 | "type": "function"
664 | },
665 | {
666 | "inputs": [
667 | {
668 | "internalType": "uint256",
669 | "name": "tokenId",
670 | "type": "uint256"
671 | }
672 | ],
673 | "name": "exists",
674 | "outputs": [
675 | {
676 | "internalType": "bool",
677 | "name": "",
678 | "type": "bool"
679 | }
680 | ],
681 | "stateMutability": "view",
682 | "type": "function"
683 | },
684 | {
685 | "inputs": [
686 | {
687 | "internalType": "uint256[]",
688 | "name": "profileIds",
689 | "type": "uint256[]"
690 | },
691 | {
692 | "internalType": "bytes[]",
693 | "name": "datas",
694 | "type": "bytes[]"
695 | }
696 | ],
697 | "name": "follow",
698 | "outputs": [
699 | {
700 | "internalType": "uint256[]",
701 | "name": "",
702 | "type": "uint256[]"
703 | }
704 | ],
705 | "stateMutability": "nonpayable",
706 | "type": "function"
707 | },
708 | {
709 | "inputs": [
710 | {
711 | "components": [
712 | {
713 | "internalType": "address",
714 | "name": "follower",
715 | "type": "address"
716 | },
717 | {
718 | "internalType": "uint256[]",
719 | "name": "profileIds",
720 | "type": "uint256[]"
721 | },
722 | {
723 | "internalType": "bytes[]",
724 | "name": "datas",
725 | "type": "bytes[]"
726 | },
727 | {
728 | "components": [
729 | {
730 | "internalType": "uint8",
731 | "name": "v",
732 | "type": "uint8"
733 | },
734 | {
735 | "internalType": "bytes32",
736 | "name": "r",
737 | "type": "bytes32"
738 | },
739 | {
740 | "internalType": "bytes32",
741 | "name": "s",
742 | "type": "bytes32"
743 | },
744 | {
745 | "internalType": "uint256",
746 | "name": "deadline",
747 | "type": "uint256"
748 | }
749 | ],
750 | "internalType": "struct DataTypes.EIP712Signature",
751 | "name": "sig",
752 | "type": "tuple"
753 | }
754 | ],
755 | "internalType": "struct DataTypes.FollowWithSigData",
756 | "name": "vars",
757 | "type": "tuple"
758 | }
759 | ],
760 | "name": "followWithSig",
761 | "outputs": [
762 | {
763 | "internalType": "uint256[]",
764 | "name": "",
765 | "type": "uint256[]"
766 | }
767 | ],
768 | "stateMutability": "nonpayable",
769 | "type": "function"
770 | },
771 | {
772 | "inputs": [
773 | {
774 | "internalType": "uint256",
775 | "name": "tokenId",
776 | "type": "uint256"
777 | }
778 | ],
779 | "name": "getApproved",
780 | "outputs": [
781 | {
782 | "internalType": "address",
783 | "name": "",
784 | "type": "address"
785 | }
786 | ],
787 | "stateMutability": "view",
788 | "type": "function"
789 | },
790 | {
791 | "inputs": [
792 | {
793 | "internalType": "uint256",
794 | "name": "profileId",
795 | "type": "uint256"
796 | },
797 | {
798 | "internalType": "uint256",
799 | "name": "pubId",
800 | "type": "uint256"
801 | }
802 | ],
803 | "name": "getCollectModule",
804 | "outputs": [
805 | {
806 | "internalType": "address",
807 | "name": "",
808 | "type": "address"
809 | }
810 | ],
811 | "stateMutability": "view",
812 | "type": "function"
813 | },
814 | {
815 | "inputs": [
816 | {
817 | "internalType": "uint256",
818 | "name": "profileId",
819 | "type": "uint256"
820 | },
821 | {
822 | "internalType": "uint256",
823 | "name": "pubId",
824 | "type": "uint256"
825 | }
826 | ],
827 | "name": "getCollectNFT",
828 | "outputs": [
829 | {
830 | "internalType": "address",
831 | "name": "",
832 | "type": "address"
833 | }
834 | ],
835 | "stateMutability": "view",
836 | "type": "function"
837 | },
838 | {
839 | "inputs": [],
840 | "name": "getCollectNFTImpl",
841 | "outputs": [
842 | {
843 | "internalType": "address",
844 | "name": "",
845 | "type": "address"
846 | }
847 | ],
848 | "stateMutability": "view",
849 | "type": "function"
850 | },
851 | {
852 | "inputs": [
853 | {
854 | "internalType": "uint256",
855 | "name": "profileId",
856 | "type": "uint256"
857 | },
858 | {
859 | "internalType": "uint256",
860 | "name": "pubId",
861 | "type": "uint256"
862 | }
863 | ],
864 | "name": "getContentURI",
865 | "outputs": [
866 | {
867 | "internalType": "string",
868 | "name": "",
869 | "type": "string"
870 | }
871 | ],
872 | "stateMutability": "view",
873 | "type": "function"
874 | },
875 | {
876 | "inputs": [
877 | {
878 | "internalType": "uint256",
879 | "name": "profileId",
880 | "type": "uint256"
881 | }
882 | ],
883 | "name": "getDispatcher",
884 | "outputs": [
885 | {
886 | "internalType": "address",
887 | "name": "",
888 | "type": "address"
889 | }
890 | ],
891 | "stateMutability": "view",
892 | "type": "function"
893 | },
894 | {
895 | "inputs": [],
896 | "name": "getDomainSeparator",
897 | "outputs": [
898 | {
899 | "internalType": "bytes32",
900 | "name": "",
901 | "type": "bytes32"
902 | }
903 | ],
904 | "stateMutability": "view",
905 | "type": "function"
906 | },
907 | {
908 | "inputs": [
909 | {
910 | "internalType": "uint256",
911 | "name": "profileId",
912 | "type": "uint256"
913 | }
914 | ],
915 | "name": "getFollowModule",
916 | "outputs": [
917 | {
918 | "internalType": "address",
919 | "name": "",
920 | "type": "address"
921 | }
922 | ],
923 | "stateMutability": "view",
924 | "type": "function"
925 | },
926 | {
927 | "inputs": [
928 | {
929 | "internalType": "uint256",
930 | "name": "profileId",
931 | "type": "uint256"
932 | }
933 | ],
934 | "name": "getFollowNFT",
935 | "outputs": [
936 | {
937 | "internalType": "address",
938 | "name": "",
939 | "type": "address"
940 | }
941 | ],
942 | "stateMutability": "view",
943 | "type": "function"
944 | },
945 | {
946 | "inputs": [],
947 | "name": "getFollowNFTImpl",
948 | "outputs": [
949 | {
950 | "internalType": "address",
951 | "name": "",
952 | "type": "address"
953 | }
954 | ],
955 | "stateMutability": "view",
956 | "type": "function"
957 | },
958 | {
959 | "inputs": [
960 | {
961 | "internalType": "uint256",
962 | "name": "profileId",
963 | "type": "uint256"
964 | }
965 | ],
966 | "name": "getFollowNFTURI",
967 | "outputs": [
968 | {
969 | "internalType": "string",
970 | "name": "",
971 | "type": "string"
972 | }
973 | ],
974 | "stateMutability": "view",
975 | "type": "function"
976 | },
977 | {
978 | "inputs": [],
979 | "name": "getGovernance",
980 | "outputs": [
981 | {
982 | "internalType": "address",
983 | "name": "",
984 | "type": "address"
985 | }
986 | ],
987 | "stateMutability": "view",
988 | "type": "function"
989 | },
990 | {
991 | "inputs": [
992 | {
993 | "internalType": "uint256",
994 | "name": "profileId",
995 | "type": "uint256"
996 | }
997 | ],
998 | "name": "getHandle",
999 | "outputs": [
1000 | {
1001 | "internalType": "string",
1002 | "name": "",
1003 | "type": "string"
1004 | }
1005 | ],
1006 | "stateMutability": "view",
1007 | "type": "function"
1008 | },
1009 | {
1010 | "inputs": [
1011 | {
1012 | "internalType": "uint256",
1013 | "name": "profileId",
1014 | "type": "uint256"
1015 | }
1016 | ],
1017 | "name": "getProfile",
1018 | "outputs": [
1019 | {
1020 | "components": [
1021 | {
1022 | "internalType": "uint256",
1023 | "name": "pubCount",
1024 | "type": "uint256"
1025 | },
1026 | {
1027 | "internalType": "address",
1028 | "name": "followModule",
1029 | "type": "address"
1030 | },
1031 | {
1032 | "internalType": "address",
1033 | "name": "followNFT",
1034 | "type": "address"
1035 | },
1036 | {
1037 | "internalType": "string",
1038 | "name": "handle",
1039 | "type": "string"
1040 | },
1041 | {
1042 | "internalType": "string",
1043 | "name": "imageURI",
1044 | "type": "string"
1045 | },
1046 | {
1047 | "internalType": "string",
1048 | "name": "followNFTURI",
1049 | "type": "string"
1050 | }
1051 | ],
1052 | "internalType": "struct DataTypes.ProfileStruct",
1053 | "name": "",
1054 | "type": "tuple"
1055 | }
1056 | ],
1057 | "stateMutability": "view",
1058 | "type": "function"
1059 | },
1060 | {
1061 | "inputs": [
1062 | {
1063 | "internalType": "string",
1064 | "name": "handle",
1065 | "type": "string"
1066 | }
1067 | ],
1068 | "name": "getProfileIdByHandle",
1069 | "outputs": [
1070 | {
1071 | "internalType": "uint256",
1072 | "name": "",
1073 | "type": "uint256"
1074 | }
1075 | ],
1076 | "stateMutability": "view",
1077 | "type": "function"
1078 | },
1079 | {
1080 | "inputs": [
1081 | {
1082 | "internalType": "uint256",
1083 | "name": "profileId",
1084 | "type": "uint256"
1085 | },
1086 | {
1087 | "internalType": "uint256",
1088 | "name": "pubId",
1089 | "type": "uint256"
1090 | }
1091 | ],
1092 | "name": "getPub",
1093 | "outputs": [
1094 | {
1095 | "components": [
1096 | {
1097 | "internalType": "uint256",
1098 | "name": "profileIdPointed",
1099 | "type": "uint256"
1100 | },
1101 | {
1102 | "internalType": "uint256",
1103 | "name": "pubIdPointed",
1104 | "type": "uint256"
1105 | },
1106 | {
1107 | "internalType": "string",
1108 | "name": "contentURI",
1109 | "type": "string"
1110 | },
1111 | {
1112 | "internalType": "address",
1113 | "name": "referenceModule",
1114 | "type": "address"
1115 | },
1116 | {
1117 | "internalType": "address",
1118 | "name": "collectModule",
1119 | "type": "address"
1120 | },
1121 | {
1122 | "internalType": "address",
1123 | "name": "collectNFT",
1124 | "type": "address"
1125 | }
1126 | ],
1127 | "internalType": "struct DataTypes.PublicationStruct",
1128 | "name": "",
1129 | "type": "tuple"
1130 | }
1131 | ],
1132 | "stateMutability": "view",
1133 | "type": "function"
1134 | },
1135 | {
1136 | "inputs": [
1137 | {
1138 | "internalType": "uint256",
1139 | "name": "profileId",
1140 | "type": "uint256"
1141 | }
1142 | ],
1143 | "name": "getPubCount",
1144 | "outputs": [
1145 | {
1146 | "internalType": "uint256",
1147 | "name": "",
1148 | "type": "uint256"
1149 | }
1150 | ],
1151 | "stateMutability": "view",
1152 | "type": "function"
1153 | },
1154 | {
1155 | "inputs": [
1156 | {
1157 | "internalType": "uint256",
1158 | "name": "profileId",
1159 | "type": "uint256"
1160 | },
1161 | {
1162 | "internalType": "uint256",
1163 | "name": "pubId",
1164 | "type": "uint256"
1165 | }
1166 | ],
1167 | "name": "getPubPointer",
1168 | "outputs": [
1169 | {
1170 | "internalType": "uint256",
1171 | "name": "",
1172 | "type": "uint256"
1173 | },
1174 | {
1175 | "internalType": "uint256",
1176 | "name": "",
1177 | "type": "uint256"
1178 | }
1179 | ],
1180 | "stateMutability": "view",
1181 | "type": "function"
1182 | },
1183 | {
1184 | "inputs": [
1185 | {
1186 | "internalType": "uint256",
1187 | "name": "profileId",
1188 | "type": "uint256"
1189 | },
1190 | {
1191 | "internalType": "uint256",
1192 | "name": "pubId",
1193 | "type": "uint256"
1194 | }
1195 | ],
1196 | "name": "getPubType",
1197 | "outputs": [
1198 | {
1199 | "internalType": "enum DataTypes.PubType",
1200 | "name": "",
1201 | "type": "uint8"
1202 | }
1203 | ],
1204 | "stateMutability": "view",
1205 | "type": "function"
1206 | },
1207 | {
1208 | "inputs": [
1209 | {
1210 | "internalType": "uint256",
1211 | "name": "profileId",
1212 | "type": "uint256"
1213 | },
1214 | {
1215 | "internalType": "uint256",
1216 | "name": "pubId",
1217 | "type": "uint256"
1218 | }
1219 | ],
1220 | "name": "getReferenceModule",
1221 | "outputs": [
1222 | {
1223 | "internalType": "address",
1224 | "name": "",
1225 | "type": "address"
1226 | }
1227 | ],
1228 | "stateMutability": "view",
1229 | "type": "function"
1230 | },
1231 | {
1232 | "inputs": [],
1233 | "name": "getState",
1234 | "outputs": [
1235 | {
1236 | "internalType": "enum DataTypes.ProtocolState",
1237 | "name": "",
1238 | "type": "uint8"
1239 | }
1240 | ],
1241 | "stateMutability": "view",
1242 | "type": "function"
1243 | },
1244 | {
1245 | "inputs": [
1246 | {
1247 | "internalType": "string",
1248 | "name": "name",
1249 | "type": "string"
1250 | },
1251 | {
1252 | "internalType": "string",
1253 | "name": "symbol",
1254 | "type": "string"
1255 | },
1256 | {
1257 | "internalType": "address",
1258 | "name": "newGovernance",
1259 | "type": "address"
1260 | }
1261 | ],
1262 | "name": "initialize",
1263 | "outputs": [],
1264 | "stateMutability": "nonpayable",
1265 | "type": "function"
1266 | },
1267 | {
1268 | "inputs": [
1269 | {
1270 | "internalType": "address",
1271 | "name": "owner",
1272 | "type": "address"
1273 | },
1274 | {
1275 | "internalType": "address",
1276 | "name": "operator",
1277 | "type": "address"
1278 | }
1279 | ],
1280 | "name": "isApprovedForAll",
1281 | "outputs": [
1282 | {
1283 | "internalType": "bool",
1284 | "name": "",
1285 | "type": "bool"
1286 | }
1287 | ],
1288 | "stateMutability": "view",
1289 | "type": "function"
1290 | },
1291 | {
1292 | "inputs": [
1293 | {
1294 | "internalType": "address",
1295 | "name": "collectModule",
1296 | "type": "address"
1297 | }
1298 | ],
1299 | "name": "isCollectModuleWhitelisted",
1300 | "outputs": [
1301 | {
1302 | "internalType": "bool",
1303 | "name": "",
1304 | "type": "bool"
1305 | }
1306 | ],
1307 | "stateMutability": "view",
1308 | "type": "function"
1309 | },
1310 | {
1311 | "inputs": [
1312 | {
1313 | "internalType": "address",
1314 | "name": "followModule",
1315 | "type": "address"
1316 | }
1317 | ],
1318 | "name": "isFollowModuleWhitelisted",
1319 | "outputs": [
1320 | {
1321 | "internalType": "bool",
1322 | "name": "",
1323 | "type": "bool"
1324 | }
1325 | ],
1326 | "stateMutability": "view",
1327 | "type": "function"
1328 | },
1329 | {
1330 | "inputs": [
1331 | {
1332 | "internalType": "address",
1333 | "name": "profileCreator",
1334 | "type": "address"
1335 | }
1336 | ],
1337 | "name": "isProfileCreatorWhitelisted",
1338 | "outputs": [
1339 | {
1340 | "internalType": "bool",
1341 | "name": "",
1342 | "type": "bool"
1343 | }
1344 | ],
1345 | "stateMutability": "view",
1346 | "type": "function"
1347 | },
1348 | {
1349 | "inputs": [
1350 | {
1351 | "internalType": "address",
1352 | "name": "referenceModule",
1353 | "type": "address"
1354 | }
1355 | ],
1356 | "name": "isReferenceModuleWhitelisted",
1357 | "outputs": [
1358 | {
1359 | "internalType": "bool",
1360 | "name": "",
1361 | "type": "bool"
1362 | }
1363 | ],
1364 | "stateMutability": "view",
1365 | "type": "function"
1366 | },
1367 | {
1368 | "inputs": [
1369 | {
1370 | "internalType": "uint256",
1371 | "name": "tokenId",
1372 | "type": "uint256"
1373 | }
1374 | ],
1375 | "name": "mintTimestampOf",
1376 | "outputs": [
1377 | {
1378 | "internalType": "uint256",
1379 | "name": "",
1380 | "type": "uint256"
1381 | }
1382 | ],
1383 | "stateMutability": "view",
1384 | "type": "function"
1385 | },
1386 | {
1387 | "inputs": [
1388 | {
1389 | "components": [
1390 | {
1391 | "internalType": "uint256",
1392 | "name": "profileId",
1393 | "type": "uint256"
1394 | },
1395 | {
1396 | "internalType": "uint256",
1397 | "name": "profileIdPointed",
1398 | "type": "uint256"
1399 | },
1400 | {
1401 | "internalType": "uint256",
1402 | "name": "pubIdPointed",
1403 | "type": "uint256"
1404 | },
1405 | {
1406 | "internalType": "bytes",
1407 | "name": "referenceModuleData",
1408 | "type": "bytes"
1409 | },
1410 | {
1411 | "internalType": "address",
1412 | "name": "referenceModule",
1413 | "type": "address"
1414 | },
1415 | {
1416 | "internalType": "bytes",
1417 | "name": "referenceModuleInitData",
1418 | "type": "bytes"
1419 | }
1420 | ],
1421 | "internalType": "struct DataTypes.MirrorData",
1422 | "name": "vars",
1423 | "type": "tuple"
1424 | }
1425 | ],
1426 | "name": "mirror",
1427 | "outputs": [
1428 | {
1429 | "internalType": "uint256",
1430 | "name": "",
1431 | "type": "uint256"
1432 | }
1433 | ],
1434 | "stateMutability": "nonpayable",
1435 | "type": "function"
1436 | },
1437 | {
1438 | "inputs": [
1439 | {
1440 | "components": [
1441 | {
1442 | "internalType": "uint256",
1443 | "name": "profileId",
1444 | "type": "uint256"
1445 | },
1446 | {
1447 | "internalType": "uint256",
1448 | "name": "profileIdPointed",
1449 | "type": "uint256"
1450 | },
1451 | {
1452 | "internalType": "uint256",
1453 | "name": "pubIdPointed",
1454 | "type": "uint256"
1455 | },
1456 | {
1457 | "internalType": "bytes",
1458 | "name": "referenceModuleData",
1459 | "type": "bytes"
1460 | },
1461 | {
1462 | "internalType": "address",
1463 | "name": "referenceModule",
1464 | "type": "address"
1465 | },
1466 | {
1467 | "internalType": "bytes",
1468 | "name": "referenceModuleInitData",
1469 | "type": "bytes"
1470 | },
1471 | {
1472 | "components": [
1473 | {
1474 | "internalType": "uint8",
1475 | "name": "v",
1476 | "type": "uint8"
1477 | },
1478 | {
1479 | "internalType": "bytes32",
1480 | "name": "r",
1481 | "type": "bytes32"
1482 | },
1483 | {
1484 | "internalType": "bytes32",
1485 | "name": "s",
1486 | "type": "bytes32"
1487 | },
1488 | {
1489 | "internalType": "uint256",
1490 | "name": "deadline",
1491 | "type": "uint256"
1492 | }
1493 | ],
1494 | "internalType": "struct DataTypes.EIP712Signature",
1495 | "name": "sig",
1496 | "type": "tuple"
1497 | }
1498 | ],
1499 | "internalType": "struct DataTypes.MirrorWithSigData",
1500 | "name": "vars",
1501 | "type": "tuple"
1502 | }
1503 | ],
1504 | "name": "mirrorWithSig",
1505 | "outputs": [
1506 | {
1507 | "internalType": "uint256",
1508 | "name": "",
1509 | "type": "uint256"
1510 | }
1511 | ],
1512 | "stateMutability": "nonpayable",
1513 | "type": "function"
1514 | },
1515 | {
1516 | "inputs": [],
1517 | "name": "name",
1518 | "outputs": [
1519 | {
1520 | "internalType": "string",
1521 | "name": "",
1522 | "type": "string"
1523 | }
1524 | ],
1525 | "stateMutability": "view",
1526 | "type": "function"
1527 | },
1528 | {
1529 | "inputs": [
1530 | {
1531 | "internalType": "uint256",
1532 | "name": "tokenId",
1533 | "type": "uint256"
1534 | }
1535 | ],
1536 | "name": "ownerOf",
1537 | "outputs": [
1538 | {
1539 | "internalType": "address",
1540 | "name": "",
1541 | "type": "address"
1542 | }
1543 | ],
1544 | "stateMutability": "view",
1545 | "type": "function"
1546 | },
1547 | {
1548 | "inputs": [
1549 | {
1550 | "internalType": "address",
1551 | "name": "spender",
1552 | "type": "address"
1553 | },
1554 | {
1555 | "internalType": "uint256",
1556 | "name": "tokenId",
1557 | "type": "uint256"
1558 | },
1559 | {
1560 | "components": [
1561 | {
1562 | "internalType": "uint8",
1563 | "name": "v",
1564 | "type": "uint8"
1565 | },
1566 | {
1567 | "internalType": "bytes32",
1568 | "name": "r",
1569 | "type": "bytes32"
1570 | },
1571 | {
1572 | "internalType": "bytes32",
1573 | "name": "s",
1574 | "type": "bytes32"
1575 | },
1576 | {
1577 | "internalType": "uint256",
1578 | "name": "deadline",
1579 | "type": "uint256"
1580 | }
1581 | ],
1582 | "internalType": "struct DataTypes.EIP712Signature",
1583 | "name": "sig",
1584 | "type": "tuple"
1585 | }
1586 | ],
1587 | "name": "permit",
1588 | "outputs": [],
1589 | "stateMutability": "nonpayable",
1590 | "type": "function"
1591 | },
1592 | {
1593 | "inputs": [
1594 | {
1595 | "internalType": "address",
1596 | "name": "owner",
1597 | "type": "address"
1598 | },
1599 | {
1600 | "internalType": "address",
1601 | "name": "operator",
1602 | "type": "address"
1603 | },
1604 | {
1605 | "internalType": "bool",
1606 | "name": "approved",
1607 | "type": "bool"
1608 | },
1609 | {
1610 | "components": [
1611 | {
1612 | "internalType": "uint8",
1613 | "name": "v",
1614 | "type": "uint8"
1615 | },
1616 | {
1617 | "internalType": "bytes32",
1618 | "name": "r",
1619 | "type": "bytes32"
1620 | },
1621 | {
1622 | "internalType": "bytes32",
1623 | "name": "s",
1624 | "type": "bytes32"
1625 | },
1626 | {
1627 | "internalType": "uint256",
1628 | "name": "deadline",
1629 | "type": "uint256"
1630 | }
1631 | ],
1632 | "internalType": "struct DataTypes.EIP712Signature",
1633 | "name": "sig",
1634 | "type": "tuple"
1635 | }
1636 | ],
1637 | "name": "permitForAll",
1638 | "outputs": [],
1639 | "stateMutability": "nonpayable",
1640 | "type": "function"
1641 | },
1642 | {
1643 | "inputs": [
1644 | {
1645 | "components": [
1646 | {
1647 | "internalType": "uint256",
1648 | "name": "profileId",
1649 | "type": "uint256"
1650 | },
1651 | {
1652 | "internalType": "string",
1653 | "name": "contentURI",
1654 | "type": "string"
1655 | },
1656 | {
1657 | "internalType": "address",
1658 | "name": "collectModule",
1659 | "type": "address"
1660 | },
1661 | {
1662 | "internalType": "bytes",
1663 | "name": "collectModuleInitData",
1664 | "type": "bytes"
1665 | },
1666 | {
1667 | "internalType": "address",
1668 | "name": "referenceModule",
1669 | "type": "address"
1670 | },
1671 | {
1672 | "internalType": "bytes",
1673 | "name": "referenceModuleInitData",
1674 | "type": "bytes"
1675 | }
1676 | ],
1677 | "internalType": "struct DataTypes.PostData",
1678 | "name": "vars",
1679 | "type": "tuple"
1680 | }
1681 | ],
1682 | "name": "post",
1683 | "outputs": [
1684 | {
1685 | "internalType": "uint256",
1686 | "name": "",
1687 | "type": "uint256"
1688 | }
1689 | ],
1690 | "stateMutability": "nonpayable",
1691 | "type": "function"
1692 | },
1693 | {
1694 | "inputs": [
1695 | {
1696 | "components": [
1697 | {
1698 | "internalType": "uint256",
1699 | "name": "profileId",
1700 | "type": "uint256"
1701 | },
1702 | {
1703 | "internalType": "string",
1704 | "name": "contentURI",
1705 | "type": "string"
1706 | },
1707 | {
1708 | "internalType": "address",
1709 | "name": "collectModule",
1710 | "type": "address"
1711 | },
1712 | {
1713 | "internalType": "bytes",
1714 | "name": "collectModuleInitData",
1715 | "type": "bytes"
1716 | },
1717 | {
1718 | "internalType": "address",
1719 | "name": "referenceModule",
1720 | "type": "address"
1721 | },
1722 | {
1723 | "internalType": "bytes",
1724 | "name": "referenceModuleInitData",
1725 | "type": "bytes"
1726 | },
1727 | {
1728 | "components": [
1729 | {
1730 | "internalType": "uint8",
1731 | "name": "v",
1732 | "type": "uint8"
1733 | },
1734 | {
1735 | "internalType": "bytes32",
1736 | "name": "r",
1737 | "type": "bytes32"
1738 | },
1739 | {
1740 | "internalType": "bytes32",
1741 | "name": "s",
1742 | "type": "bytes32"
1743 | },
1744 | {
1745 | "internalType": "uint256",
1746 | "name": "deadline",
1747 | "type": "uint256"
1748 | }
1749 | ],
1750 | "internalType": "struct DataTypes.EIP712Signature",
1751 | "name": "sig",
1752 | "type": "tuple"
1753 | }
1754 | ],
1755 | "internalType": "struct DataTypes.PostWithSigData",
1756 | "name": "vars",
1757 | "type": "tuple"
1758 | }
1759 | ],
1760 | "name": "postWithSig",
1761 | "outputs": [
1762 | {
1763 | "internalType": "uint256",
1764 | "name": "",
1765 | "type": "uint256"
1766 | }
1767 | ],
1768 | "stateMutability": "nonpayable",
1769 | "type": "function"
1770 | },
1771 | {
1772 | "inputs": [
1773 | {
1774 | "internalType": "address",
1775 | "name": "from",
1776 | "type": "address"
1777 | },
1778 | {
1779 | "internalType": "address",
1780 | "name": "to",
1781 | "type": "address"
1782 | },
1783 | {
1784 | "internalType": "uint256",
1785 | "name": "tokenId",
1786 | "type": "uint256"
1787 | }
1788 | ],
1789 | "name": "safeTransferFrom",
1790 | "outputs": [],
1791 | "stateMutability": "nonpayable",
1792 | "type": "function"
1793 | },
1794 | {
1795 | "inputs": [
1796 | {
1797 | "internalType": "address",
1798 | "name": "from",
1799 | "type": "address"
1800 | },
1801 | {
1802 | "internalType": "address",
1803 | "name": "to",
1804 | "type": "address"
1805 | },
1806 | {
1807 | "internalType": "uint256",
1808 | "name": "tokenId",
1809 | "type": "uint256"
1810 | },
1811 | {
1812 | "internalType": "bytes",
1813 | "name": "_data",
1814 | "type": "bytes"
1815 | }
1816 | ],
1817 | "name": "safeTransferFrom",
1818 | "outputs": [],
1819 | "stateMutability": "nonpayable",
1820 | "type": "function"
1821 | },
1822 | {
1823 | "inputs": [
1824 | {
1825 | "internalType": "address",
1826 | "name": "operator",
1827 | "type": "address"
1828 | },
1829 | {
1830 | "internalType": "bool",
1831 | "name": "approved",
1832 | "type": "bool"
1833 | }
1834 | ],
1835 | "name": "setApprovalForAll",
1836 | "outputs": [],
1837 | "stateMutability": "nonpayable",
1838 | "type": "function"
1839 | },
1840 | {
1841 | "inputs": [
1842 | {
1843 | "internalType": "uint256",
1844 | "name": "profileId",
1845 | "type": "uint256"
1846 | }
1847 | ],
1848 | "name": "setDefaultProfile",
1849 | "outputs": [],
1850 | "stateMutability": "nonpayable",
1851 | "type": "function"
1852 | },
1853 | {
1854 | "inputs": [
1855 | {
1856 | "components": [
1857 | {
1858 | "internalType": "address",
1859 | "name": "wallet",
1860 | "type": "address"
1861 | },
1862 | {
1863 | "internalType": "uint256",
1864 | "name": "profileId",
1865 | "type": "uint256"
1866 | },
1867 | {
1868 | "components": [
1869 | {
1870 | "internalType": "uint8",
1871 | "name": "v",
1872 | "type": "uint8"
1873 | },
1874 | {
1875 | "internalType": "bytes32",
1876 | "name": "r",
1877 | "type": "bytes32"
1878 | },
1879 | {
1880 | "internalType": "bytes32",
1881 | "name": "s",
1882 | "type": "bytes32"
1883 | },
1884 | {
1885 | "internalType": "uint256",
1886 | "name": "deadline",
1887 | "type": "uint256"
1888 | }
1889 | ],
1890 | "internalType": "struct DataTypes.EIP712Signature",
1891 | "name": "sig",
1892 | "type": "tuple"
1893 | }
1894 | ],
1895 | "internalType": "struct DataTypes.SetDefaultProfileWithSigData",
1896 | "name": "vars",
1897 | "type": "tuple"
1898 | }
1899 | ],
1900 | "name": "setDefaultProfileWithSig",
1901 | "outputs": [],
1902 | "stateMutability": "nonpayable",
1903 | "type": "function"
1904 | },
1905 | {
1906 | "inputs": [
1907 | {
1908 | "internalType": "uint256",
1909 | "name": "profileId",
1910 | "type": "uint256"
1911 | },
1912 | {
1913 | "internalType": "address",
1914 | "name": "dispatcher",
1915 | "type": "address"
1916 | }
1917 | ],
1918 | "name": "setDispatcher",
1919 | "outputs": [],
1920 | "stateMutability": "nonpayable",
1921 | "type": "function"
1922 | },
1923 | {
1924 | "inputs": [
1925 | {
1926 | "components": [
1927 | {
1928 | "internalType": "uint256",
1929 | "name": "profileId",
1930 | "type": "uint256"
1931 | },
1932 | {
1933 | "internalType": "address",
1934 | "name": "dispatcher",
1935 | "type": "address"
1936 | },
1937 | {
1938 | "components": [
1939 | {
1940 | "internalType": "uint8",
1941 | "name": "v",
1942 | "type": "uint8"
1943 | },
1944 | {
1945 | "internalType": "bytes32",
1946 | "name": "r",
1947 | "type": "bytes32"
1948 | },
1949 | {
1950 | "internalType": "bytes32",
1951 | "name": "s",
1952 | "type": "bytes32"
1953 | },
1954 | {
1955 | "internalType": "uint256",
1956 | "name": "deadline",
1957 | "type": "uint256"
1958 | }
1959 | ],
1960 | "internalType": "struct DataTypes.EIP712Signature",
1961 | "name": "sig",
1962 | "type": "tuple"
1963 | }
1964 | ],
1965 | "internalType": "struct DataTypes.SetDispatcherWithSigData",
1966 | "name": "vars",
1967 | "type": "tuple"
1968 | }
1969 | ],
1970 | "name": "setDispatcherWithSig",
1971 | "outputs": [],
1972 | "stateMutability": "nonpayable",
1973 | "type": "function"
1974 | },
1975 | {
1976 | "inputs": [
1977 | {
1978 | "internalType": "address",
1979 | "name": "newEmergencyAdmin",
1980 | "type": "address"
1981 | }
1982 | ],
1983 | "name": "setEmergencyAdmin",
1984 | "outputs": [],
1985 | "stateMutability": "nonpayable",
1986 | "type": "function"
1987 | },
1988 | {
1989 | "inputs": [
1990 | {
1991 | "internalType": "uint256",
1992 | "name": "profileId",
1993 | "type": "uint256"
1994 | },
1995 | {
1996 | "internalType": "address",
1997 | "name": "followModule",
1998 | "type": "address"
1999 | },
2000 | {
2001 | "internalType": "bytes",
2002 | "name": "followModuleInitData",
2003 | "type": "bytes"
2004 | }
2005 | ],
2006 | "name": "setFollowModule",
2007 | "outputs": [],
2008 | "stateMutability": "nonpayable",
2009 | "type": "function"
2010 | },
2011 | {
2012 | "inputs": [
2013 | {
2014 | "components": [
2015 | {
2016 | "internalType": "uint256",
2017 | "name": "profileId",
2018 | "type": "uint256"
2019 | },
2020 | {
2021 | "internalType": "address",
2022 | "name": "followModule",
2023 | "type": "address"
2024 | },
2025 | {
2026 | "internalType": "bytes",
2027 | "name": "followModuleInitData",
2028 | "type": "bytes"
2029 | },
2030 | {
2031 | "components": [
2032 | {
2033 | "internalType": "uint8",
2034 | "name": "v",
2035 | "type": "uint8"
2036 | },
2037 | {
2038 | "internalType": "bytes32",
2039 | "name": "r",
2040 | "type": "bytes32"
2041 | },
2042 | {
2043 | "internalType": "bytes32",
2044 | "name": "s",
2045 | "type": "bytes32"
2046 | },
2047 | {
2048 | "internalType": "uint256",
2049 | "name": "deadline",
2050 | "type": "uint256"
2051 | }
2052 | ],
2053 | "internalType": "struct DataTypes.EIP712Signature",
2054 | "name": "sig",
2055 | "type": "tuple"
2056 | }
2057 | ],
2058 | "internalType": "struct DataTypes.SetFollowModuleWithSigData",
2059 | "name": "vars",
2060 | "type": "tuple"
2061 | }
2062 | ],
2063 | "name": "setFollowModuleWithSig",
2064 | "outputs": [],
2065 | "stateMutability": "nonpayable",
2066 | "type": "function"
2067 | },
2068 | {
2069 | "inputs": [
2070 | {
2071 | "internalType": "uint256",
2072 | "name": "profileId",
2073 | "type": "uint256"
2074 | },
2075 | {
2076 | "internalType": "string",
2077 | "name": "followNFTURI",
2078 | "type": "string"
2079 | }
2080 | ],
2081 | "name": "setFollowNFTURI",
2082 | "outputs": [],
2083 | "stateMutability": "nonpayable",
2084 | "type": "function"
2085 | },
2086 | {
2087 | "inputs": [
2088 | {
2089 | "components": [
2090 | {
2091 | "internalType": "uint256",
2092 | "name": "profileId",
2093 | "type": "uint256"
2094 | },
2095 | {
2096 | "internalType": "string",
2097 | "name": "followNFTURI",
2098 | "type": "string"
2099 | },
2100 | {
2101 | "components": [
2102 | {
2103 | "internalType": "uint8",
2104 | "name": "v",
2105 | "type": "uint8"
2106 | },
2107 | {
2108 | "internalType": "bytes32",
2109 | "name": "r",
2110 | "type": "bytes32"
2111 | },
2112 | {
2113 | "internalType": "bytes32",
2114 | "name": "s",
2115 | "type": "bytes32"
2116 | },
2117 | {
2118 | "internalType": "uint256",
2119 | "name": "deadline",
2120 | "type": "uint256"
2121 | }
2122 | ],
2123 | "internalType": "struct DataTypes.EIP712Signature",
2124 | "name": "sig",
2125 | "type": "tuple"
2126 | }
2127 | ],
2128 | "internalType": "struct DataTypes.SetFollowNFTURIWithSigData",
2129 | "name": "vars",
2130 | "type": "tuple"
2131 | }
2132 | ],
2133 | "name": "setFollowNFTURIWithSig",
2134 | "outputs": [],
2135 | "stateMutability": "nonpayable",
2136 | "type": "function"
2137 | },
2138 | {
2139 | "inputs": [
2140 | {
2141 | "internalType": "address",
2142 | "name": "newGovernance",
2143 | "type": "address"
2144 | }
2145 | ],
2146 | "name": "setGovernance",
2147 | "outputs": [],
2148 | "stateMutability": "nonpayable",
2149 | "type": "function"
2150 | },
2151 | {
2152 | "inputs": [
2153 | {
2154 | "internalType": "uint256",
2155 | "name": "profileId",
2156 | "type": "uint256"
2157 | },
2158 | {
2159 | "internalType": "string",
2160 | "name": "imageURI",
2161 | "type": "string"
2162 | }
2163 | ],
2164 | "name": "setProfileImageURI",
2165 | "outputs": [],
2166 | "stateMutability": "nonpayable",
2167 | "type": "function"
2168 | },
2169 | {
2170 | "inputs": [
2171 | {
2172 | "components": [
2173 | {
2174 | "internalType": "uint256",
2175 | "name": "profileId",
2176 | "type": "uint256"
2177 | },
2178 | {
2179 | "internalType": "string",
2180 | "name": "imageURI",
2181 | "type": "string"
2182 | },
2183 | {
2184 | "components": [
2185 | {
2186 | "internalType": "uint8",
2187 | "name": "v",
2188 | "type": "uint8"
2189 | },
2190 | {
2191 | "internalType": "bytes32",
2192 | "name": "r",
2193 | "type": "bytes32"
2194 | },
2195 | {
2196 | "internalType": "bytes32",
2197 | "name": "s",
2198 | "type": "bytes32"
2199 | },
2200 | {
2201 | "internalType": "uint256",
2202 | "name": "deadline",
2203 | "type": "uint256"
2204 | }
2205 | ],
2206 | "internalType": "struct DataTypes.EIP712Signature",
2207 | "name": "sig",
2208 | "type": "tuple"
2209 | }
2210 | ],
2211 | "internalType": "struct DataTypes.SetProfileImageURIWithSigData",
2212 | "name": "vars",
2213 | "type": "tuple"
2214 | }
2215 | ],
2216 | "name": "setProfileImageURIWithSig",
2217 | "outputs": [],
2218 | "stateMutability": "nonpayable",
2219 | "type": "function"
2220 | },
2221 | {
2222 | "inputs": [
2223 | {
2224 | "internalType": "enum DataTypes.ProtocolState",
2225 | "name": "newState",
2226 | "type": "uint8"
2227 | }
2228 | ],
2229 | "name": "setState",
2230 | "outputs": [],
2231 | "stateMutability": "nonpayable",
2232 | "type": "function"
2233 | },
2234 | {
2235 | "inputs": [
2236 | {
2237 | "internalType": "address",
2238 | "name": "",
2239 | "type": "address"
2240 | }
2241 | ],
2242 | "name": "sigNonces",
2243 | "outputs": [
2244 | {
2245 | "internalType": "uint256",
2246 | "name": "",
2247 | "type": "uint256"
2248 | }
2249 | ],
2250 | "stateMutability": "view",
2251 | "type": "function"
2252 | },
2253 | {
2254 | "inputs": [
2255 | {
2256 | "internalType": "bytes4",
2257 | "name": "interfaceId",
2258 | "type": "bytes4"
2259 | }
2260 | ],
2261 | "name": "supportsInterface",
2262 | "outputs": [
2263 | {
2264 | "internalType": "bool",
2265 | "name": "",
2266 | "type": "bool"
2267 | }
2268 | ],
2269 | "stateMutability": "view",
2270 | "type": "function"
2271 | },
2272 | {
2273 | "inputs": [],
2274 | "name": "symbol",
2275 | "outputs": [
2276 | {
2277 | "internalType": "string",
2278 | "name": "",
2279 | "type": "string"
2280 | }
2281 | ],
2282 | "stateMutability": "view",
2283 | "type": "function"
2284 | },
2285 | {
2286 | "inputs": [
2287 | {
2288 | "internalType": "uint256",
2289 | "name": "index",
2290 | "type": "uint256"
2291 | }
2292 | ],
2293 | "name": "tokenByIndex",
2294 | "outputs": [
2295 | {
2296 | "internalType": "uint256",
2297 | "name": "",
2298 | "type": "uint256"
2299 | }
2300 | ],
2301 | "stateMutability": "view",
2302 | "type": "function"
2303 | },
2304 | {
2305 | "inputs": [
2306 | {
2307 | "internalType": "uint256",
2308 | "name": "tokenId",
2309 | "type": "uint256"
2310 | }
2311 | ],
2312 | "name": "tokenDataOf",
2313 | "outputs": [
2314 | {
2315 | "components": [
2316 | {
2317 | "internalType": "address",
2318 | "name": "owner",
2319 | "type": "address"
2320 | },
2321 | {
2322 | "internalType": "uint96",
2323 | "name": "mintTimestamp",
2324 | "type": "uint96"
2325 | }
2326 | ],
2327 | "internalType": "struct IERC721Time.TokenData",
2328 | "name": "",
2329 | "type": "tuple"
2330 | }
2331 | ],
2332 | "stateMutability": "view",
2333 | "type": "function"
2334 | },
2335 | {
2336 | "inputs": [
2337 | {
2338 | "internalType": "address",
2339 | "name": "owner",
2340 | "type": "address"
2341 | },
2342 | {
2343 | "internalType": "uint256",
2344 | "name": "index",
2345 | "type": "uint256"
2346 | }
2347 | ],
2348 | "name": "tokenOfOwnerByIndex",
2349 | "outputs": [
2350 | {
2351 | "internalType": "uint256",
2352 | "name": "",
2353 | "type": "uint256"
2354 | }
2355 | ],
2356 | "stateMutability": "view",
2357 | "type": "function"
2358 | },
2359 | {
2360 | "inputs": [
2361 | {
2362 | "internalType": "uint256",
2363 | "name": "tokenId",
2364 | "type": "uint256"
2365 | }
2366 | ],
2367 | "name": "tokenURI",
2368 | "outputs": [
2369 | {
2370 | "internalType": "string",
2371 | "name": "",
2372 | "type": "string"
2373 | }
2374 | ],
2375 | "stateMutability": "view",
2376 | "type": "function"
2377 | },
2378 | {
2379 | "inputs": [],
2380 | "name": "totalSupply",
2381 | "outputs": [
2382 | {
2383 | "internalType": "uint256",
2384 | "name": "",
2385 | "type": "uint256"
2386 | }
2387 | ],
2388 | "stateMutability": "view",
2389 | "type": "function"
2390 | },
2391 | {
2392 | "inputs": [
2393 | {
2394 | "internalType": "address",
2395 | "name": "from",
2396 | "type": "address"
2397 | },
2398 | {
2399 | "internalType": "address",
2400 | "name": "to",
2401 | "type": "address"
2402 | },
2403 | {
2404 | "internalType": "uint256",
2405 | "name": "tokenId",
2406 | "type": "uint256"
2407 | }
2408 | ],
2409 | "name": "transferFrom",
2410 | "outputs": [],
2411 | "stateMutability": "nonpayable",
2412 | "type": "function"
2413 | },
2414 | {
2415 | "inputs": [
2416 | {
2417 | "internalType": "address",
2418 | "name": "collectModule",
2419 | "type": "address"
2420 | },
2421 | {
2422 | "internalType": "bool",
2423 | "name": "whitelist",
2424 | "type": "bool"
2425 | }
2426 | ],
2427 | "name": "whitelistCollectModule",
2428 | "outputs": [],
2429 | "stateMutability": "nonpayable",
2430 | "type": "function"
2431 | },
2432 | {
2433 | "inputs": [
2434 | {
2435 | "internalType": "address",
2436 | "name": "followModule",
2437 | "type": "address"
2438 | },
2439 | {
2440 | "internalType": "bool",
2441 | "name": "whitelist",
2442 | "type": "bool"
2443 | }
2444 | ],
2445 | "name": "whitelistFollowModule",
2446 | "outputs": [],
2447 | "stateMutability": "nonpayable",
2448 | "type": "function"
2449 | },
2450 | {
2451 | "inputs": [
2452 | {
2453 | "internalType": "address",
2454 | "name": "profileCreator",
2455 | "type": "address"
2456 | },
2457 | {
2458 | "internalType": "bool",
2459 | "name": "whitelist",
2460 | "type": "bool"
2461 | }
2462 | ],
2463 | "name": "whitelistProfileCreator",
2464 | "outputs": [],
2465 | "stateMutability": "nonpayable",
2466 | "type": "function"
2467 | },
2468 | {
2469 | "inputs": [
2470 | {
2471 | "internalType": "address",
2472 | "name": "referenceModule",
2473 | "type": "address"
2474 | },
2475 | {
2476 | "internalType": "bool",
2477 | "name": "whitelist",
2478 | "type": "bool"
2479 | }
2480 | ],
2481 | "name": "whitelistReferenceModule",
2482 | "outputs": [],
2483 | "stateMutability": "nonpayable",
2484 | "type": "function"
2485 | }
2486 | ]
--------------------------------------------------------------------------------