├── .eslintrc.js ├── .gitignore ├── .husky └── pre-commit ├── .npmignore ├── .prettierrc.json ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── src ├── assets │ └── abi │ │ ├── follow-nft.json │ │ └── lenshub.json ├── context │ └── LensContext.tsx ├── hooks │ ├── api │ │ ├── broadcast.ts │ │ ├── collect.ts │ │ ├── comment.ts │ │ ├── follow.ts │ │ ├── indexer.ts │ │ ├── login.ts │ │ ├── mirror.ts │ │ ├── post.ts │ │ ├── profile.ts │ │ ├── publication.ts │ │ └── search.ts │ ├── combined │ │ ├── collect.ts │ │ ├── comment.ts │ │ ├── follow.ts │ │ ├── mirror.ts │ │ └── post.ts │ ├── contract │ │ ├── collect.ts │ │ ├── comment.ts │ │ ├── follow.ts │ │ ├── index.ts │ │ ├── mirror.ts │ │ ├── post.ts │ │ └── profile.ts │ └── utils │ │ ├── broadcast.ts │ │ ├── contract.ts │ │ └── sign.ts ├── index.ts ├── types │ ├── error.ts │ ├── lens.ts │ ├── metadata.ts │ ├── modules.ts │ └── on.ts └── utils │ ├── omit-deep.ts │ └── tx.ts └── tsconfig.json /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | es2021: true, 5 | }, 6 | extends: ["eslint:recommended", "plugin:react/recommended", "standard-with-typescript", "prettier"], 7 | overrides: [], 8 | parserOptions: { 9 | ecmaVersion: "latest", 10 | sourceType: "module", 11 | project: "tsconfig.json", 12 | }, 13 | plugins: ["simple-import-sort", "react"], 14 | rules: { 15 | "react/react-in-jsx-scope": ["off"], 16 | "@typescript-eslint/strict-boolean-expressions": ["off"], 17 | "simple-import-sort/imports": "error", 18 | "simple-import-sort/exports": "error", 19 | "react/no-unescaped-entities": ["off"], 20 | }, 21 | settings: { 22 | react: { version: "detect" }, 23 | }, 24 | }; 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | dist 4 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx lint-staged 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .husky 2 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "trailingComma": "all", 4 | "singleQuote": false, 5 | "printWidth": 120, 6 | "tabWidth": 2, 7 | "bracketSameLine": true, 8 | "endOfLine": "auto" 9 | } 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 memester 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

lens-use 🌱

2 | 3 |

Deprecation Notice

4 | 5 |

6 | Lens Protocol is working on their own React SDK which should be used instead of this library. 7 |

8 | 9 |

React Hooks for Lens Protocol

10 | 11 | 12 |

13 | React 🤝 Lens Protocol 14 |

15 | 16 | **Standing on the shoulders of these chads (aka, dependencies):** 17 | 18 | - [Apollo GraphQL](https://www.apollographql.com/docs/) 19 | - [wagmi](https://wagmi.sh/) 20 | - [ethers](https://docs.ethers.io/v5/) 21 | 22 | **Jump straight to the [Hooks Reference](#hooks-reference)** 23 | 24 | # Example 25 | 26 | ```typescript 27 | const { data: profileResponse } = useProfile("stani.lens"); 28 | 29 | const { data: publicationsResponse } = usePublications(profileResponse?.profile?.id); 30 | 31 | const { collect } = useCollect(publicationsResponse?.publications?.items[0].id); 32 | 33 | const onClick = () => { 34 | collect(); 35 | }; 36 | ``` 37 | 38 | # Installation 39 | 40 | ```bash 41 | # npm 42 | npm install --save @memester-xyz/lens-use 43 | 44 | # yarn 45 | yarn add @memester-xyz/lens-use 46 | 47 | # pnpm 48 | pnpm add @memester-xyz/lens-use 49 | ``` 50 | 51 | # Usage 52 | 53 | ## Basic 54 | 55 | 1. Your app must first be wrapped in a Wagmi context and a Apollo context (connected to the Lens API). e.g.: 56 | 57 | ```typescript 58 | function App() { 59 | return ( 60 | 61 | 62 | 63 | 64 | 65 | ); 66 | } 67 | ``` 68 | 69 | 2. You can then use the Lens hooks in any components inside of your DApp component: 70 | 71 | ```typescript 72 | import { useProfile } from "@memester-xyz/lens-use"; 73 | 74 | // ... 75 | 76 | const { data } = useProfile("stani.lens"); 77 | ``` 78 | 79 | 3. The return value of any API hook (e.g. `useProfile`, `useChallenge`) is a typed Apollo GraphQL return value. i.e. 80 | 81 | - [`QueryResult`](https://www.apollographql.com/docs/react/api/react/hooks/#result) for queries 82 | - [`MutationTuple`](https://www.apollographql.com/docs/react/api/react/hooks/#mutationtupletdata-tvariables-result-tuple) for mutations. 83 | 84 | 4. The return value of any contract hook (e.g. `useContractProfile`, `useContractCollect`) is a modification of a normal Wagmi [`useContractRead`](https://wagmi.sh/docs/hooks/useContractRead#return-value) or [`useContractWrite`](https://wagmi.sh/docs/hooks/useContractWrite#return-value). 85 | 86 | 5. The return value of any action hook (e.g. `useCollect`) is an object containing: 87 | - a write method with the same name as the hook action (e.g. `collect()`) 88 | - a loading boolean when the request is in flight `loading` 89 | - an Error object or undefined `error` 90 | 91 | Full API specification is below in the [hooks](#hooks) section. 92 | 93 | ## Advanced 94 | 95 | By default we use the currently known Polygon Mainnet Lens Hub Proxy address. There are two ways to override this but both require adding our `LensProvider` context to your app. 96 | 97 | 1. You can use the currently known Mumbai (testnet) address: 98 | 99 | ```typescript 100 | function App() { 101 | return ( 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | ); 110 | } 111 | ``` 112 | 113 | 2. You can pass a custom Lens Hub contract address: 114 | 115 | ```typescript 116 | function App() { 117 | return ( 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | ); 126 | } 127 | ``` 128 | 129 | # Hooks Reference 130 | 131 | - [Login](#login) 132 | - [useChallenge](#useChallenge) 133 | - [useAuthenticate](#useAuthenticate) 134 | - [useRefresh](#useRefresh) 135 | - [Query](#query) 136 | - [useProfile](#useProfile) 137 | - [useProfiles](#useProfiles) 138 | - [useDefaultProfile](#useDefaultProfile) 139 | - [useProfilePicture](#useProfilePicture) 140 | - [useProfileHasDispatcher](#useProfileHasDispatcher) 141 | - [usePublication](#usePublication) 142 | - [usePublications](#usePublications) 143 | - [usePublicationComments](#usePublicationComments) 144 | - [useSearch](#useSearch) 145 | - [Write](#write) 146 | - [useCollect](#useCollect) 147 | - [useComment](#useComment) 148 | - [useFollow](#useFollow) 149 | - [useUnfollow](#useUnfollow) 150 | - [useMirror](#useMirror) 151 | - [usePost](#usePost) 152 | - [Contract](#contract) 153 | - [useContractCollect](#useContractCollect) 154 | - [useContractComment](#useContractComment) 155 | - [useContractFollow](#useContractFollow) 156 | - [useContractUnfollow](#useContractUnfollow) 157 | - [useContractMirror](#useContractMirror) 158 | - [useContractPost](#useContractPost) 159 | - [useContractProfile](#useContractProfile) 160 | 161 | ## Login 162 | 163 | Hooks to help with authenticating against the Lens API. 164 | 165 | ### useChallenge 166 | 167 | _[Lens Reference](https://docs.lens.xyz/docs/login#challenge)_ 168 | 169 | Get a challenge to be signed by the user 170 | 171 | ```typescript 172 | const { data: challengeData } = useChallenge(address); 173 | 174 | // challengeData.challenge.text must be signed by the user's wallet 175 | ``` 176 | 177 | ### useAuthenticate 178 | 179 | _[Lens Reference](https://docs.lens.xyz/docs/login#authenticate)_ 180 | 181 | Authenticate the signed challenge 182 | 183 | ```typescript 184 | const [authenticate, { data: authenticateData }] = useAuthenticate(address, signedChallenge); 185 | 186 | // Call this method to start the authentication request 187 | authenticate(); 188 | 189 | // After the request is complete 190 | // authenticateData.authenticate.accessToken has access token 191 | // authenticateData.authenticate.refreshToken has refresh token 192 | ``` 193 | 194 | ### useRefresh 195 | 196 | _[Lens Reference](https://docs.lens.xyz/docs/refresh-jwt)_ 197 | 198 | Refresh the JWT 199 | 200 | ```typescript 201 | const [refresh, { data: refreshData }] = useRefresh(refreshToken); 202 | 203 | // Call this method to start the refresh request 204 | refresh(); 205 | 206 | // After the request is complete 207 | // refreshData.refresh.accessToken has access token 208 | // refreshData.refresh.refreshToken has refresh token 209 | ``` 210 | 211 | ## Query 212 | 213 | Hooks to query the Lens API. Note, some of these require authentication, check the Lens Reference. 214 | 215 | ### useProfile 216 | 217 | _[Lens Reference](https://docs.lens.xyz/docs/get-profile#get-by-handle)_ 218 | 219 | Get a profile by handle 220 | 221 | ```typescript 222 | const { data } = useProfile(handle); 223 | ``` 224 | 225 | ### useProfiles 226 | 227 | _[Lens Reference](https://docs.lens.xyz/docs/get-profiles#get-by-owned-by)_ 228 | 229 | Get all profiles owned by an address 230 | 231 | ```typescript 232 | const { data } = useProfiles(address); 233 | ``` 234 | 235 | ### useDefaultProfile 236 | 237 | _[Lens Reference](https://docs.lens.xyz/docs/get-default-profile)_ 238 | 239 | Get default profile by address 240 | 241 | ```typescript 242 | const defaultProfile = useDefaultProfile(address); 243 | ``` 244 | 245 | ### useProfilePicture 246 | 247 | The response body from `useProfile` and `useDefaultProfile` is slightly different, so this method helps to pull out the profile picture from one of those. 248 | 249 | ```typescript 250 | const defaultProfile = useDefaultProfile(address); 251 | const pfpURL = useProfilePicture(defaultProfile); 252 | ``` 253 | 254 | ### useProfileHasDispatcher 255 | 256 | A simple utility which returns `true` if the profile has the dispatcher enabled. 257 | 258 | ```typescript 259 | const dispatch = useProfileHasDispatcher(profileId); 260 | ``` 261 | 262 | ### usePublication 263 | 264 | _[Lens Reference](https://docs.lens.xyz/docs/get-publication)_ 265 | 266 | Retrieve details for a specific publication 267 | 268 | ```typescript 269 | const { data } = usePublication(publicationId); 270 | 271 | // Pass in profileId to get the mirrored status in your publication results 272 | const { data } = usePublication(publicationId, profileId); 273 | ``` 274 | 275 | ### usePublications 276 | 277 | _[Lens Reference](https://docs.lens.xyz/docs/get-publications)_ 278 | 279 | Retrieve publications based on various parameters 280 | 281 | ```typescript 282 | // Get posts from a specific profile 283 | const { data } = usePublications(profileId); 284 | 285 | // Get posts and comments from a specific profile 286 | const { data } = usePublications(profileId, [PublicationType.POST, PublicationType.COMMENT]); 287 | 288 | // Get posts from a specific profile and source 289 | const { data } = usePublications(profileId, [PublicationType.POST], ["memester"]); 290 | ``` 291 | 292 | ### usePublicationComments 293 | 294 | _[Lens Reference](https://docs.lens.xyz/docs/get-publications)_ 295 | 296 | Retrieve publications based on various parameters 297 | 298 | ```typescript 299 | // Get comments for a specific publication 300 | const { data } = usePublicationComments(publicationId); 301 | ``` 302 | 303 | ### useSearch 304 | 305 | _[Lens Reference](https://docs.lens.xyz/docs/search-profiles-and-publications#search-across-profiles)_ 306 | 307 | Search profiles 308 | 309 | ```typescript 310 | const { data } = useSearch("stani"); 311 | ``` 312 | 313 | ## Write 314 | 315 | Hooks to write to Lens using the [dispatcher](https://docs.lens.xyz/docs/dispatcher) if enabled or the [broadcaster](https://docs.lens.xyz/docs/broadcast-transaction) if not. Note, your Apollo GraphQL client must be [authenticated](https://docs.lens.xyz/docs/authentication-quickstart)! 316 | 317 | All write hooks take an optional final parameter which allows you to specify callback functions. An example is given for `useCollect` but the same applies to all hooks in this section. 318 | 319 | ### useCollect 320 | 321 | Collect a publication using the API 322 | 323 | ```typescript 324 | const { collect, loading, error } = useCollect(publicationId); 325 | 326 | // Call this method to start the collect request 327 | collect(); 328 | 329 | // You can also pass in callback functions 330 | const { collect, loading, error } = useCollect(publicationId, { 331 | onBroadcasted(receipt) { 332 | // ... 333 | }, 334 | onCompleted(receipt) { 335 | // receipt will be undefined if the request errored for some reason 336 | }, 337 | }); 338 | ``` 339 | 340 | ### useComment 341 | 342 | Comment on a publication. Requires a URL with the comment metadata already uploaded 343 | 344 | ```typescript 345 | const { collect, loading, error } = useComment(profileId, publicationId, commentURL); 346 | 347 | // Call this method to start the comment request 348 | comment(); 349 | ``` 350 | 351 | ### useFollow 352 | 353 | Follow a profile 354 | 355 | ```typescript 356 | const { follow, loading, error } = useFollow(profileIdToFollow); 357 | 358 | // Call this method to start the follow request 359 | follow(); 360 | ``` 361 | 362 | ### useUnfollow 363 | 364 | Unfollow a profile 365 | 366 | ```typescript 367 | const { unfollow, loading, error } = useUnfollow(profileIdToUnfollow); 368 | 369 | // Call this method to start the unfollow request 370 | unfollow(); 371 | ``` 372 | 373 | ### useMirror 374 | 375 | Mirror a publication 376 | 377 | ```typescript 378 | const { mirror, loading, error } = useMirror(profileId, publicationId); 379 | 380 | // Call this method to start the mirror request 381 | mirror(); 382 | ``` 383 | 384 | ### usePost 385 | 386 | Post. Requires a URL with the post metadata already uploaded 387 | 388 | ```typescript 389 | const { post, loading, error } = usePost(profileId, postURL); 390 | 391 | // Call this method to start the post request 392 | post(); 393 | ``` 394 | 395 | ## Contract 396 | 397 | ### useContractCollect 398 | 399 | _[Lens Reference](https://docs.lens.xyz/docs/functions#collect)_ 400 | 401 | Collect a publication using the Lens Hub Contract 402 | 403 | ```typescript 404 | const { write, data, prepareError, writeError, status } = useContractCollect(profileId, publicationId); 405 | 406 | // Call this method to invoke the users connected wallet 407 | write(); 408 | ``` 409 | 410 | ### useContractComment 411 | 412 | _[Lens Reference](https://docs.lens.xyz/docs/functions#comment)_ 413 | 414 | Comment on a publication using the Lens Hub Contract 415 | 416 | ```typescript 417 | const { write, data, prepareError, writeError, status } = useContractCollect( 418 | profileId, 419 | contentURI, 420 | profileIdPointed, 421 | pubIdPointed, 422 | collectModule, 423 | collectModuleInitData, 424 | referenceModule, 425 | referenceModuleInitData, 426 | referenceModuleData, 427 | ); 428 | 429 | // Call this method to invoke the users connected wallet 430 | write(); 431 | ``` 432 | 433 | ### useContractFollow 434 | 435 | _[Lens Reference](https://docs.lens.xyz/docs/functions#follow)_ 436 | 437 | Follow profiles using the Lens Hub Contract 438 | 439 | ```typescript 440 | const { write, data, prepareError, writeError, status } = useContractFollow(profileIds); 441 | 442 | // Call this method to invoke the users connected wallet 443 | write(); 444 | ``` 445 | 446 | ### useContractUnfollow 447 | 448 | _[Lens Reference](https://docs.lens.xyz/docs/follow)_ 449 | 450 | Unfollow a profile by burning the specific Follow NFT. You must pass in the relevant follow NFT address and tokenId 451 | 452 | ```typescript 453 | const { write, data, prepareError, writeError, status } = useContractUnfollow(followNFTAddress, tokenId); 454 | 455 | // Call this method to invoke the users connected wallet 456 | write(); 457 | ``` 458 | 459 | ### useContractMirror 460 | 461 | _[Lens Reference](https://docs.lens.xyz/docs/functions#mirror)_ 462 | 463 | Mirror a publication using the Lens Hub Contract 464 | 465 | ```typescript 466 | const { write, data, prepareError, writeError, status } = useContractMirror( 467 | profileId, 468 | profileIdPointed, 469 | pubIdPointed, 470 | referenceModuleData, 471 | referenceModule, 472 | referenceModuleInitData, 473 | ); 474 | 475 | // Call this method to invoke the users connected wallet 476 | write(); 477 | ``` 478 | 479 | ### useContractPost 480 | 481 | _[Lens Reference](https://docs.lens.xyz/docs/functions#post)_ 482 | 483 | Post using the Lens Hub Contract 484 | 485 | ```typescript 486 | const { write, data, prepareError, writeError, status } = useContractPost( 487 | profileId?, 488 | contentURI, 489 | collectModule, 490 | collectModuleInitData, 491 | referenceModule, 492 | referenceModuleInitData, 493 | ); 494 | 495 | // Call this method to invoke the users connected wallet 496 | write(); 497 | ``` 498 | 499 | ### useContractProfile 500 | 501 | _[Lens Reference](https://docs.lens.xyz/docs/view-functions#getprofile)_ 502 | 503 | Read profile from the Lens Hub Contract 504 | 505 | ```typescript 506 | const { data } = useContractProfile(profileId); 507 | ``` 508 | 509 | --- 510 | 511 | _Made with 🫡 by [memester.xyz](https://memester.xyz)_ 512 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@memester-xyz/lens-use", 3 | "version": "0.1.1", 4 | "description": "React hooks for Lens Protocol", 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/memester-xyz/lens-use.git" 10 | }, 11 | "scripts": { 12 | "prepublish": "tsc", 13 | "format": "prettier --check 'src/**/*.ts*'", 14 | "format:write": "prettier --write 'src/**/*.ts*'", 15 | "lint": "eslint 'src/**/*.ts*'", 16 | "lint:fix": "eslint --fix 'src/**/*.ts*'", 17 | "prepare": "husky install" 18 | }, 19 | "lint-staged": { 20 | "*.ts*": [ 21 | "eslint --fix", 22 | "prettier --write" 23 | ] 24 | }, 25 | "dependencies": { 26 | "@apollo/client": "^3.7.1", 27 | "ethers": "^5.7.0", 28 | "wagmi": "^0.6.4" 29 | }, 30 | "devDependencies": { 31 | "@types/react": "^18.0.17", 32 | "@typescript-eslint/eslint-plugin": "^5.36.2", 33 | "eslint": "^8.23.0", 34 | "eslint-config-prettier": "^8.5.0", 35 | "eslint-config-standard-with-typescript": "^22.0.0", 36 | "eslint-plugin-import": "^2.26.0", 37 | "eslint-plugin-n": "^15.2.5", 38 | "eslint-plugin-promise": "^6.0.1", 39 | "eslint-plugin-react": "^7.31.8", 40 | "eslint-plugin-simple-import-sort": "^8.0.0", 41 | "husky": "^8.0.1", 42 | "lint-staged": "^13.0.3", 43 | "prettier": "^2.7.1", 44 | "typescript": "^4.8.3" 45 | }, 46 | "author": "Devan Non ", 47 | "license": "MIT" 48 | } 49 | -------------------------------------------------------------------------------- /src/assets/abi/follow-nft.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "address", 6 | "name": "hub", 7 | "type": "address" 8 | } 9 | ], 10 | "stateMutability": "nonpayable", 11 | "type": "constructor" 12 | }, 13 | { 14 | "inputs": [], 15 | "name": "BlockNumberInvalid", 16 | "type": "error" 17 | }, 18 | { 19 | "inputs": [], 20 | "name": "InitParamsInvalid", 21 | "type": "error" 22 | }, 23 | { 24 | "inputs": [], 25 | "name": "Initialized", 26 | "type": "error" 27 | }, 28 | { 29 | "inputs": [], 30 | "name": "NotHub", 31 | "type": "error" 32 | }, 33 | { 34 | "inputs": [], 35 | "name": "NotOwnerOrApproved", 36 | "type": "error" 37 | }, 38 | { 39 | "inputs": [], 40 | "name": "SignatureExpired", 41 | "type": "error" 42 | }, 43 | { 44 | "inputs": [], 45 | "name": "SignatureInvalid", 46 | "type": "error" 47 | }, 48 | { 49 | "inputs": [], 50 | "name": "TokenDoesNotExist", 51 | "type": "error" 52 | }, 53 | { 54 | "inputs": [], 55 | "name": "ZeroSpender", 56 | "type": "error" 57 | }, 58 | { 59 | "anonymous": false, 60 | "inputs": [ 61 | { 62 | "indexed": true, 63 | "internalType": "address", 64 | "name": "owner", 65 | "type": "address" 66 | }, 67 | { 68 | "indexed": true, 69 | "internalType": "address", 70 | "name": "approved", 71 | "type": "address" 72 | }, 73 | { 74 | "indexed": true, 75 | "internalType": "uint256", 76 | "name": "tokenId", 77 | "type": "uint256" 78 | } 79 | ], 80 | "name": "Approval", 81 | "type": "event" 82 | }, 83 | { 84 | "anonymous": false, 85 | "inputs": [ 86 | { 87 | "indexed": true, 88 | "internalType": "address", 89 | "name": "owner", 90 | "type": "address" 91 | }, 92 | { 93 | "indexed": true, 94 | "internalType": "address", 95 | "name": "operator", 96 | "type": "address" 97 | }, 98 | { 99 | "indexed": false, 100 | "internalType": "bool", 101 | "name": "approved", 102 | "type": "bool" 103 | } 104 | ], 105 | "name": "ApprovalForAll", 106 | "type": "event" 107 | }, 108 | { 109 | "anonymous": false, 110 | "inputs": [ 111 | { 112 | "indexed": true, 113 | "internalType": "address", 114 | "name": "from", 115 | "type": "address" 116 | }, 117 | { 118 | "indexed": true, 119 | "internalType": "address", 120 | "name": "to", 121 | "type": "address" 122 | }, 123 | { 124 | "indexed": true, 125 | "internalType": "uint256", 126 | "name": "tokenId", 127 | "type": "uint256" 128 | } 129 | ], 130 | "name": "Transfer", 131 | "type": "event" 132 | }, 133 | { 134 | "inputs": [], 135 | "name": "HUB", 136 | "outputs": [ 137 | { 138 | "internalType": "address", 139 | "name": "", 140 | "type": "address" 141 | } 142 | ], 143 | "stateMutability": "view", 144 | "type": "function" 145 | }, 146 | { 147 | "inputs": [ 148 | { 149 | "internalType": "address", 150 | "name": "to", 151 | "type": "address" 152 | }, 153 | { 154 | "internalType": "uint256", 155 | "name": "tokenId", 156 | "type": "uint256" 157 | } 158 | ], 159 | "name": "approve", 160 | "outputs": [], 161 | "stateMutability": "nonpayable", 162 | "type": "function" 163 | }, 164 | { 165 | "inputs": [ 166 | { 167 | "internalType": "address", 168 | "name": "owner", 169 | "type": "address" 170 | } 171 | ], 172 | "name": "balanceOf", 173 | "outputs": [ 174 | { 175 | "internalType": "uint256", 176 | "name": "", 177 | "type": "uint256" 178 | } 179 | ], 180 | "stateMutability": "view", 181 | "type": "function" 182 | }, 183 | { 184 | "inputs": [ 185 | { 186 | "internalType": "uint256", 187 | "name": "tokenId", 188 | "type": "uint256" 189 | } 190 | ], 191 | "name": "burn", 192 | "outputs": [], 193 | "stateMutability": "nonpayable", 194 | "type": "function" 195 | }, 196 | { 197 | "inputs": [ 198 | { 199 | "internalType": "uint256", 200 | "name": "tokenId", 201 | "type": "uint256" 202 | }, 203 | { 204 | "components": [ 205 | { 206 | "internalType": "uint8", 207 | "name": "v", 208 | "type": "uint8" 209 | }, 210 | { 211 | "internalType": "bytes32", 212 | "name": "r", 213 | "type": "bytes32" 214 | }, 215 | { 216 | "internalType": "bytes32", 217 | "name": "s", 218 | "type": "bytes32" 219 | }, 220 | { 221 | "internalType": "uint256", 222 | "name": "deadline", 223 | "type": "uint256" 224 | } 225 | ], 226 | "internalType": "struct DataTypes.EIP712Signature", 227 | "name": "sig", 228 | "type": "tuple" 229 | } 230 | ], 231 | "name": "burnWithSig", 232 | "outputs": [], 233 | "stateMutability": "nonpayable", 234 | "type": "function" 235 | }, 236 | { 237 | "inputs": [ 238 | { 239 | "internalType": "address", 240 | "name": "delegatee", 241 | "type": "address" 242 | } 243 | ], 244 | "name": "delegate", 245 | "outputs": [], 246 | "stateMutability": "nonpayable", 247 | "type": "function" 248 | }, 249 | { 250 | "inputs": [ 251 | { 252 | "internalType": "address", 253 | "name": "delegator", 254 | "type": "address" 255 | }, 256 | { 257 | "internalType": "address", 258 | "name": "delegatee", 259 | "type": "address" 260 | }, 261 | { 262 | "components": [ 263 | { 264 | "internalType": "uint8", 265 | "name": "v", 266 | "type": "uint8" 267 | }, 268 | { 269 | "internalType": "bytes32", 270 | "name": "r", 271 | "type": "bytes32" 272 | }, 273 | { 274 | "internalType": "bytes32", 275 | "name": "s", 276 | "type": "bytes32" 277 | }, 278 | { 279 | "internalType": "uint256", 280 | "name": "deadline", 281 | "type": "uint256" 282 | } 283 | ], 284 | "internalType": "struct DataTypes.EIP712Signature", 285 | "name": "sig", 286 | "type": "tuple" 287 | } 288 | ], 289 | "name": "delegateBySig", 290 | "outputs": [], 291 | "stateMutability": "nonpayable", 292 | "type": "function" 293 | }, 294 | { 295 | "inputs": [ 296 | { 297 | "internalType": "uint256", 298 | "name": "tokenId", 299 | "type": "uint256" 300 | } 301 | ], 302 | "name": "exists", 303 | "outputs": [ 304 | { 305 | "internalType": "bool", 306 | "name": "", 307 | "type": "bool" 308 | } 309 | ], 310 | "stateMutability": "view", 311 | "type": "function" 312 | }, 313 | { 314 | "inputs": [ 315 | { 316 | "internalType": "uint256", 317 | "name": "tokenId", 318 | "type": "uint256" 319 | } 320 | ], 321 | "name": "getApproved", 322 | "outputs": [ 323 | { 324 | "internalType": "address", 325 | "name": "", 326 | "type": "address" 327 | } 328 | ], 329 | "stateMutability": "view", 330 | "type": "function" 331 | }, 332 | { 333 | "inputs": [ 334 | { 335 | "internalType": "uint256", 336 | "name": "blockNumber", 337 | "type": "uint256" 338 | } 339 | ], 340 | "name": "getDelegatedSupplyByBlockNumber", 341 | "outputs": [ 342 | { 343 | "internalType": "uint256", 344 | "name": "", 345 | "type": "uint256" 346 | } 347 | ], 348 | "stateMutability": "view", 349 | "type": "function" 350 | }, 351 | { 352 | "inputs": [], 353 | "name": "getDomainSeparator", 354 | "outputs": [ 355 | { 356 | "internalType": "bytes32", 357 | "name": "", 358 | "type": "bytes32" 359 | } 360 | ], 361 | "stateMutability": "view", 362 | "type": "function" 363 | }, 364 | { 365 | "inputs": [ 366 | { 367 | "internalType": "address", 368 | "name": "user", 369 | "type": "address" 370 | }, 371 | { 372 | "internalType": "uint256", 373 | "name": "blockNumber", 374 | "type": "uint256" 375 | } 376 | ], 377 | "name": "getPowerByBlockNumber", 378 | "outputs": [ 379 | { 380 | "internalType": "uint256", 381 | "name": "", 382 | "type": "uint256" 383 | } 384 | ], 385 | "stateMutability": "view", 386 | "type": "function" 387 | }, 388 | { 389 | "inputs": [ 390 | { 391 | "internalType": "uint256", 392 | "name": "profileId", 393 | "type": "uint256" 394 | } 395 | ], 396 | "name": "initialize", 397 | "outputs": [], 398 | "stateMutability": "nonpayable", 399 | "type": "function" 400 | }, 401 | { 402 | "inputs": [ 403 | { 404 | "internalType": "address", 405 | "name": "owner", 406 | "type": "address" 407 | }, 408 | { 409 | "internalType": "address", 410 | "name": "operator", 411 | "type": "address" 412 | } 413 | ], 414 | "name": "isApprovedForAll", 415 | "outputs": [ 416 | { 417 | "internalType": "bool", 418 | "name": "", 419 | "type": "bool" 420 | } 421 | ], 422 | "stateMutability": "view", 423 | "type": "function" 424 | }, 425 | { 426 | "inputs": [ 427 | { 428 | "internalType": "address", 429 | "name": "to", 430 | "type": "address" 431 | } 432 | ], 433 | "name": "mint", 434 | "outputs": [ 435 | { 436 | "internalType": "uint256", 437 | "name": "", 438 | "type": "uint256" 439 | } 440 | ], 441 | "stateMutability": "nonpayable", 442 | "type": "function" 443 | }, 444 | { 445 | "inputs": [ 446 | { 447 | "internalType": "uint256", 448 | "name": "tokenId", 449 | "type": "uint256" 450 | } 451 | ], 452 | "name": "mintTimestampOf", 453 | "outputs": [ 454 | { 455 | "internalType": "uint256", 456 | "name": "", 457 | "type": "uint256" 458 | } 459 | ], 460 | "stateMutability": "view", 461 | "type": "function" 462 | }, 463 | { 464 | "inputs": [], 465 | "name": "name", 466 | "outputs": [ 467 | { 468 | "internalType": "string", 469 | "name": "", 470 | "type": "string" 471 | } 472 | ], 473 | "stateMutability": "view", 474 | "type": "function" 475 | }, 476 | { 477 | "inputs": [ 478 | { 479 | "internalType": "uint256", 480 | "name": "tokenId", 481 | "type": "uint256" 482 | } 483 | ], 484 | "name": "ownerOf", 485 | "outputs": [ 486 | { 487 | "internalType": "address", 488 | "name": "", 489 | "type": "address" 490 | } 491 | ], 492 | "stateMutability": "view", 493 | "type": "function" 494 | }, 495 | { 496 | "inputs": [ 497 | { 498 | "internalType": "address", 499 | "name": "spender", 500 | "type": "address" 501 | }, 502 | { 503 | "internalType": "uint256", 504 | "name": "tokenId", 505 | "type": "uint256" 506 | }, 507 | { 508 | "components": [ 509 | { 510 | "internalType": "uint8", 511 | "name": "v", 512 | "type": "uint8" 513 | }, 514 | { 515 | "internalType": "bytes32", 516 | "name": "r", 517 | "type": "bytes32" 518 | }, 519 | { 520 | "internalType": "bytes32", 521 | "name": "s", 522 | "type": "bytes32" 523 | }, 524 | { 525 | "internalType": "uint256", 526 | "name": "deadline", 527 | "type": "uint256" 528 | } 529 | ], 530 | "internalType": "struct DataTypes.EIP712Signature", 531 | "name": "sig", 532 | "type": "tuple" 533 | } 534 | ], 535 | "name": "permit", 536 | "outputs": [], 537 | "stateMutability": "nonpayable", 538 | "type": "function" 539 | }, 540 | { 541 | "inputs": [ 542 | { 543 | "internalType": "address", 544 | "name": "owner", 545 | "type": "address" 546 | }, 547 | { 548 | "internalType": "address", 549 | "name": "operator", 550 | "type": "address" 551 | }, 552 | { 553 | "internalType": "bool", 554 | "name": "approved", 555 | "type": "bool" 556 | }, 557 | { 558 | "components": [ 559 | { 560 | "internalType": "uint8", 561 | "name": "v", 562 | "type": "uint8" 563 | }, 564 | { 565 | "internalType": "bytes32", 566 | "name": "r", 567 | "type": "bytes32" 568 | }, 569 | { 570 | "internalType": "bytes32", 571 | "name": "s", 572 | "type": "bytes32" 573 | }, 574 | { 575 | "internalType": "uint256", 576 | "name": "deadline", 577 | "type": "uint256" 578 | } 579 | ], 580 | "internalType": "struct DataTypes.EIP712Signature", 581 | "name": "sig", 582 | "type": "tuple" 583 | } 584 | ], 585 | "name": "permitForAll", 586 | "outputs": [], 587 | "stateMutability": "nonpayable", 588 | "type": "function" 589 | }, 590 | { 591 | "inputs": [ 592 | { 593 | "internalType": "address", 594 | "name": "from", 595 | "type": "address" 596 | }, 597 | { 598 | "internalType": "address", 599 | "name": "to", 600 | "type": "address" 601 | }, 602 | { 603 | "internalType": "uint256", 604 | "name": "tokenId", 605 | "type": "uint256" 606 | } 607 | ], 608 | "name": "safeTransferFrom", 609 | "outputs": [], 610 | "stateMutability": "nonpayable", 611 | "type": "function" 612 | }, 613 | { 614 | "inputs": [ 615 | { 616 | "internalType": "address", 617 | "name": "from", 618 | "type": "address" 619 | }, 620 | { 621 | "internalType": "address", 622 | "name": "to", 623 | "type": "address" 624 | }, 625 | { 626 | "internalType": "uint256", 627 | "name": "tokenId", 628 | "type": "uint256" 629 | }, 630 | { 631 | "internalType": "bytes", 632 | "name": "_data", 633 | "type": "bytes" 634 | } 635 | ], 636 | "name": "safeTransferFrom", 637 | "outputs": [], 638 | "stateMutability": "nonpayable", 639 | "type": "function" 640 | }, 641 | { 642 | "inputs": [ 643 | { 644 | "internalType": "address", 645 | "name": "operator", 646 | "type": "address" 647 | }, 648 | { 649 | "internalType": "bool", 650 | "name": "approved", 651 | "type": "bool" 652 | } 653 | ], 654 | "name": "setApprovalForAll", 655 | "outputs": [], 656 | "stateMutability": "nonpayable", 657 | "type": "function" 658 | }, 659 | { 660 | "inputs": [ 661 | { 662 | "internalType": "address", 663 | "name": "", 664 | "type": "address" 665 | } 666 | ], 667 | "name": "sigNonces", 668 | "outputs": [ 669 | { 670 | "internalType": "uint256", 671 | "name": "", 672 | "type": "uint256" 673 | } 674 | ], 675 | "stateMutability": "view", 676 | "type": "function" 677 | }, 678 | { 679 | "inputs": [ 680 | { 681 | "internalType": "bytes4", 682 | "name": "interfaceId", 683 | "type": "bytes4" 684 | } 685 | ], 686 | "name": "supportsInterface", 687 | "outputs": [ 688 | { 689 | "internalType": "bool", 690 | "name": "", 691 | "type": "bool" 692 | } 693 | ], 694 | "stateMutability": "view", 695 | "type": "function" 696 | }, 697 | { 698 | "inputs": [], 699 | "name": "symbol", 700 | "outputs": [ 701 | { 702 | "internalType": "string", 703 | "name": "", 704 | "type": "string" 705 | } 706 | ], 707 | "stateMutability": "view", 708 | "type": "function" 709 | }, 710 | { 711 | "inputs": [ 712 | { 713 | "internalType": "uint256", 714 | "name": "index", 715 | "type": "uint256" 716 | } 717 | ], 718 | "name": "tokenByIndex", 719 | "outputs": [ 720 | { 721 | "internalType": "uint256", 722 | "name": "", 723 | "type": "uint256" 724 | } 725 | ], 726 | "stateMutability": "view", 727 | "type": "function" 728 | }, 729 | { 730 | "inputs": [ 731 | { 732 | "internalType": "uint256", 733 | "name": "tokenId", 734 | "type": "uint256" 735 | } 736 | ], 737 | "name": "tokenDataOf", 738 | "outputs": [ 739 | { 740 | "components": [ 741 | { 742 | "internalType": "address", 743 | "name": "owner", 744 | "type": "address" 745 | }, 746 | { 747 | "internalType": "uint96", 748 | "name": "mintTimestamp", 749 | "type": "uint96" 750 | } 751 | ], 752 | "internalType": "struct IERC721Time.TokenData", 753 | "name": "", 754 | "type": "tuple" 755 | } 756 | ], 757 | "stateMutability": "view", 758 | "type": "function" 759 | }, 760 | { 761 | "inputs": [ 762 | { 763 | "internalType": "address", 764 | "name": "owner", 765 | "type": "address" 766 | }, 767 | { 768 | "internalType": "uint256", 769 | "name": "index", 770 | "type": "uint256" 771 | } 772 | ], 773 | "name": "tokenOfOwnerByIndex", 774 | "outputs": [ 775 | { 776 | "internalType": "uint256", 777 | "name": "", 778 | "type": "uint256" 779 | } 780 | ], 781 | "stateMutability": "view", 782 | "type": "function" 783 | }, 784 | { 785 | "inputs": [ 786 | { 787 | "internalType": "uint256", 788 | "name": "tokenId", 789 | "type": "uint256" 790 | } 791 | ], 792 | "name": "tokenURI", 793 | "outputs": [ 794 | { 795 | "internalType": "string", 796 | "name": "", 797 | "type": "string" 798 | } 799 | ], 800 | "stateMutability": "view", 801 | "type": "function" 802 | }, 803 | { 804 | "inputs": [], 805 | "name": "totalSupply", 806 | "outputs": [ 807 | { 808 | "internalType": "uint256", 809 | "name": "", 810 | "type": "uint256" 811 | } 812 | ], 813 | "stateMutability": "view", 814 | "type": "function" 815 | }, 816 | { 817 | "inputs": [ 818 | { 819 | "internalType": "address", 820 | "name": "from", 821 | "type": "address" 822 | }, 823 | { 824 | "internalType": "address", 825 | "name": "to", 826 | "type": "address" 827 | }, 828 | { 829 | "internalType": "uint256", 830 | "name": "tokenId", 831 | "type": "uint256" 832 | } 833 | ], 834 | "name": "transferFrom", 835 | "outputs": [], 836 | "stateMutability": "nonpayable", 837 | "type": "function" 838 | } 839 | ] 840 | -------------------------------------------------------------------------------- /src/assets/abi/lenshub.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { "internalType": "address", "name": "followNFTImpl", "type": "address" }, 5 | { "internalType": "address", "name": "collectNFTImpl", "type": "address" } 6 | ], 7 | "stateMutability": "nonpayable", 8 | "type": "constructor" 9 | }, 10 | { "inputs": [], "name": "CallerNotCollectNFT", "type": "error" }, 11 | { "inputs": [], "name": "CallerNotFollowNFT", "type": "error" }, 12 | { "inputs": [], "name": "CannotInitImplementation", "type": "error" }, 13 | { "inputs": [], "name": "EmergencyAdminCannotUnpause", "type": "error" }, 14 | { "inputs": [], "name": "InitParamsInvalid", "type": "error" }, 15 | { "inputs": [], "name": "Initialized", "type": "error" }, 16 | { "inputs": [], "name": "NotGovernance", "type": "error" }, 17 | { "inputs": [], "name": "NotGovernanceOrEmergencyAdmin", "type": "error" }, 18 | { "inputs": [], "name": "NotOwnerOrApproved", "type": "error" }, 19 | { "inputs": [], "name": "NotProfileOwner", "type": "error" }, 20 | { "inputs": [], "name": "NotProfileOwnerOrDispatcher", "type": "error" }, 21 | { "inputs": [], "name": "Paused", "type": "error" }, 22 | { "inputs": [], "name": "ProfileCreatorNotWhitelisted", "type": "error" }, 23 | { "inputs": [], "name": "ProfileImageURILengthInvalid", "type": "error" }, 24 | { "inputs": [], "name": "PublicationDoesNotExist", "type": "error" }, 25 | { "inputs": [], "name": "PublishingPaused", "type": "error" }, 26 | { "inputs": [], "name": "SignatureExpired", "type": "error" }, 27 | { "inputs": [], "name": "SignatureInvalid", "type": "error" }, 28 | { "inputs": [], "name": "ZeroSpender", "type": "error" }, 29 | { 30 | "anonymous": false, 31 | "inputs": [ 32 | { "indexed": true, "internalType": "address", "name": "owner", "type": "address" }, 33 | { "indexed": true, "internalType": "address", "name": "approved", "type": "address" }, 34 | { "indexed": true, "internalType": "uint256", "name": "tokenId", "type": "uint256" } 35 | ], 36 | "name": "Approval", 37 | "type": "event" 38 | }, 39 | { 40 | "anonymous": false, 41 | "inputs": [ 42 | { "indexed": true, "internalType": "address", "name": "owner", "type": "address" }, 43 | { "indexed": true, "internalType": "address", "name": "operator", "type": "address" }, 44 | { "indexed": false, "internalType": "bool", "name": "approved", "type": "bool" } 45 | ], 46 | "name": "ApprovalForAll", 47 | "type": "event" 48 | }, 49 | { 50 | "anonymous": false, 51 | "inputs": [ 52 | { "indexed": true, "internalType": "address", "name": "from", "type": "address" }, 53 | { "indexed": true, "internalType": "address", "name": "to", "type": "address" }, 54 | { "indexed": true, "internalType": "uint256", "name": "tokenId", "type": "uint256" } 55 | ], 56 | "name": "Transfer", 57 | "type": "event" 58 | }, 59 | { 60 | "inputs": [ 61 | { "internalType": "address", "name": "to", "type": "address" }, 62 | { "internalType": "uint256", "name": "tokenId", "type": "uint256" } 63 | ], 64 | "name": "approve", 65 | "outputs": [], 66 | "stateMutability": "nonpayable", 67 | "type": "function" 68 | }, 69 | { 70 | "inputs": [{ "internalType": "address", "name": "owner", "type": "address" }], 71 | "name": "balanceOf", 72 | "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], 73 | "stateMutability": "view", 74 | "type": "function" 75 | }, 76 | { 77 | "inputs": [{ "internalType": "uint256", "name": "tokenId", "type": "uint256" }], 78 | "name": "burn", 79 | "outputs": [], 80 | "stateMutability": "nonpayable", 81 | "type": "function" 82 | }, 83 | { 84 | "inputs": [ 85 | { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, 86 | { 87 | "components": [ 88 | { "internalType": "uint8", "name": "v", "type": "uint8" }, 89 | { "internalType": "bytes32", "name": "r", "type": "bytes32" }, 90 | { "internalType": "bytes32", "name": "s", "type": "bytes32" }, 91 | { "internalType": "uint256", "name": "deadline", "type": "uint256" } 92 | ], 93 | "internalType": "struct DataTypes.EIP712Signature", 94 | "name": "sig", 95 | "type": "tuple" 96 | } 97 | ], 98 | "name": "burnWithSig", 99 | "outputs": [], 100 | "stateMutability": "nonpayable", 101 | "type": "function" 102 | }, 103 | { 104 | "inputs": [ 105 | { "internalType": "uint256", "name": "profileId", "type": "uint256" }, 106 | { "internalType": "uint256", "name": "pubId", "type": "uint256" }, 107 | { "internalType": "bytes", "name": "data", "type": "bytes" } 108 | ], 109 | "name": "collect", 110 | "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], 111 | "stateMutability": "nonpayable", 112 | "type": "function" 113 | }, 114 | { 115 | "inputs": [ 116 | { 117 | "components": [ 118 | { "internalType": "address", "name": "collector", "type": "address" }, 119 | { "internalType": "uint256", "name": "profileId", "type": "uint256" }, 120 | { "internalType": "uint256", "name": "pubId", "type": "uint256" }, 121 | { "internalType": "bytes", "name": "data", "type": "bytes" }, 122 | { 123 | "components": [ 124 | { "internalType": "uint8", "name": "v", "type": "uint8" }, 125 | { "internalType": "bytes32", "name": "r", "type": "bytes32" }, 126 | { "internalType": "bytes32", "name": "s", "type": "bytes32" }, 127 | { "internalType": "uint256", "name": "deadline", "type": "uint256" } 128 | ], 129 | "internalType": "struct DataTypes.EIP712Signature", 130 | "name": "sig", 131 | "type": "tuple" 132 | } 133 | ], 134 | "internalType": "struct DataTypes.CollectWithSigData", 135 | "name": "vars", 136 | "type": "tuple" 137 | } 138 | ], 139 | "name": "collectWithSig", 140 | "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], 141 | "stateMutability": "nonpayable", 142 | "type": "function" 143 | }, 144 | { 145 | "inputs": [ 146 | { 147 | "components": [ 148 | { "internalType": "uint256", "name": "profileId", "type": "uint256" }, 149 | { "internalType": "string", "name": "contentURI", "type": "string" }, 150 | { "internalType": "uint256", "name": "profileIdPointed", "type": "uint256" }, 151 | { "internalType": "uint256", "name": "pubIdPointed", "type": "uint256" }, 152 | { "internalType": "bytes", "name": "referenceModuleData", "type": "bytes" }, 153 | { "internalType": "address", "name": "collectModule", "type": "address" }, 154 | { "internalType": "bytes", "name": "collectModuleInitData", "type": "bytes" }, 155 | { "internalType": "address", "name": "referenceModule", "type": "address" }, 156 | { "internalType": "bytes", "name": "referenceModuleInitData", "type": "bytes" } 157 | ], 158 | "internalType": "struct DataTypes.CommentData", 159 | "name": "vars", 160 | "type": "tuple" 161 | } 162 | ], 163 | "name": "comment", 164 | "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], 165 | "stateMutability": "nonpayable", 166 | "type": "function" 167 | }, 168 | { 169 | "inputs": [ 170 | { 171 | "components": [ 172 | { "internalType": "uint256", "name": "profileId", "type": "uint256" }, 173 | { "internalType": "string", "name": "contentURI", "type": "string" }, 174 | { "internalType": "uint256", "name": "profileIdPointed", "type": "uint256" }, 175 | { "internalType": "uint256", "name": "pubIdPointed", "type": "uint256" }, 176 | { "internalType": "bytes", "name": "referenceModuleData", "type": "bytes" }, 177 | { "internalType": "address", "name": "collectModule", "type": "address" }, 178 | { "internalType": "bytes", "name": "collectModuleInitData", "type": "bytes" }, 179 | { "internalType": "address", "name": "referenceModule", "type": "address" }, 180 | { "internalType": "bytes", "name": "referenceModuleInitData", "type": "bytes" }, 181 | { 182 | "components": [ 183 | { "internalType": "uint8", "name": "v", "type": "uint8" }, 184 | { "internalType": "bytes32", "name": "r", "type": "bytes32" }, 185 | { "internalType": "bytes32", "name": "s", "type": "bytes32" }, 186 | { "internalType": "uint256", "name": "deadline", "type": "uint256" } 187 | ], 188 | "internalType": "struct DataTypes.EIP712Signature", 189 | "name": "sig", 190 | "type": "tuple" 191 | } 192 | ], 193 | "internalType": "struct DataTypes.CommentWithSigData", 194 | "name": "vars", 195 | "type": "tuple" 196 | } 197 | ], 198 | "name": "commentWithSig", 199 | "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], 200 | "stateMutability": "nonpayable", 201 | "type": "function" 202 | }, 203 | { 204 | "inputs": [ 205 | { 206 | "components": [ 207 | { "internalType": "address", "name": "to", "type": "address" }, 208 | { "internalType": "string", "name": "handle", "type": "string" }, 209 | { "internalType": "string", "name": "imageURI", "type": "string" }, 210 | { "internalType": "address", "name": "followModule", "type": "address" }, 211 | { "internalType": "bytes", "name": "followModuleInitData", "type": "bytes" }, 212 | { "internalType": "string", "name": "followNFTURI", "type": "string" } 213 | ], 214 | "internalType": "struct DataTypes.CreateProfileData", 215 | "name": "vars", 216 | "type": "tuple" 217 | } 218 | ], 219 | "name": "createProfile", 220 | "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], 221 | "stateMutability": "nonpayable", 222 | "type": "function" 223 | }, 224 | { 225 | "inputs": [{ "internalType": "address", "name": "wallet", "type": "address" }], 226 | "name": "defaultProfile", 227 | "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], 228 | "stateMutability": "view", 229 | "type": "function" 230 | }, 231 | { 232 | "inputs": [ 233 | { "internalType": "uint256", "name": "profileId", "type": "uint256" }, 234 | { "internalType": "uint256", "name": "pubId", "type": "uint256" }, 235 | { "internalType": "uint256", "name": "collectNFTId", "type": "uint256" }, 236 | { "internalType": "address", "name": "from", "type": "address" }, 237 | { "internalType": "address", "name": "to", "type": "address" } 238 | ], 239 | "name": "emitCollectNFTTransferEvent", 240 | "outputs": [], 241 | "stateMutability": "nonpayable", 242 | "type": "function" 243 | }, 244 | { 245 | "inputs": [ 246 | { "internalType": "uint256", "name": "profileId", "type": "uint256" }, 247 | { "internalType": "uint256", "name": "followNFTId", "type": "uint256" }, 248 | { "internalType": "address", "name": "from", "type": "address" }, 249 | { "internalType": "address", "name": "to", "type": "address" } 250 | ], 251 | "name": "emitFollowNFTTransferEvent", 252 | "outputs": [], 253 | "stateMutability": "nonpayable", 254 | "type": "function" 255 | }, 256 | { 257 | "inputs": [{ "internalType": "uint256", "name": "tokenId", "type": "uint256" }], 258 | "name": "exists", 259 | "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], 260 | "stateMutability": "view", 261 | "type": "function" 262 | }, 263 | { 264 | "inputs": [ 265 | { "internalType": "uint256[]", "name": "profileIds", "type": "uint256[]" }, 266 | { "internalType": "bytes[]", "name": "datas", "type": "bytes[]" } 267 | ], 268 | "name": "follow", 269 | "outputs": [{ "internalType": "uint256[]", "name": "", "type": "uint256[]" }], 270 | "stateMutability": "nonpayable", 271 | "type": "function" 272 | }, 273 | { 274 | "inputs": [ 275 | { 276 | "components": [ 277 | { "internalType": "address", "name": "follower", "type": "address" }, 278 | { "internalType": "uint256[]", "name": "profileIds", "type": "uint256[]" }, 279 | { "internalType": "bytes[]", "name": "datas", "type": "bytes[]" }, 280 | { 281 | "components": [ 282 | { "internalType": "uint8", "name": "v", "type": "uint8" }, 283 | { "internalType": "bytes32", "name": "r", "type": "bytes32" }, 284 | { "internalType": "bytes32", "name": "s", "type": "bytes32" }, 285 | { "internalType": "uint256", "name": "deadline", "type": "uint256" } 286 | ], 287 | "internalType": "struct DataTypes.EIP712Signature", 288 | "name": "sig", 289 | "type": "tuple" 290 | } 291 | ], 292 | "internalType": "struct DataTypes.FollowWithSigData", 293 | "name": "vars", 294 | "type": "tuple" 295 | } 296 | ], 297 | "name": "followWithSig", 298 | "outputs": [{ "internalType": "uint256[]", "name": "", "type": "uint256[]" }], 299 | "stateMutability": "nonpayable", 300 | "type": "function" 301 | }, 302 | { 303 | "inputs": [{ "internalType": "uint256", "name": "tokenId", "type": "uint256" }], 304 | "name": "getApproved", 305 | "outputs": [{ "internalType": "address", "name": "", "type": "address" }], 306 | "stateMutability": "view", 307 | "type": "function" 308 | }, 309 | { 310 | "inputs": [ 311 | { "internalType": "uint256", "name": "profileId", "type": "uint256" }, 312 | { "internalType": "uint256", "name": "pubId", "type": "uint256" } 313 | ], 314 | "name": "getCollectModule", 315 | "outputs": [{ "internalType": "address", "name": "", "type": "address" }], 316 | "stateMutability": "view", 317 | "type": "function" 318 | }, 319 | { 320 | "inputs": [ 321 | { "internalType": "uint256", "name": "profileId", "type": "uint256" }, 322 | { "internalType": "uint256", "name": "pubId", "type": "uint256" } 323 | ], 324 | "name": "getCollectNFT", 325 | "outputs": [{ "internalType": "address", "name": "", "type": "address" }], 326 | "stateMutability": "view", 327 | "type": "function" 328 | }, 329 | { 330 | "inputs": [], 331 | "name": "getCollectNFTImpl", 332 | "outputs": [{ "internalType": "address", "name": "", "type": "address" }], 333 | "stateMutability": "view", 334 | "type": "function" 335 | }, 336 | { 337 | "inputs": [ 338 | { "internalType": "uint256", "name": "profileId", "type": "uint256" }, 339 | { "internalType": "uint256", "name": "pubId", "type": "uint256" } 340 | ], 341 | "name": "getContentURI", 342 | "outputs": [{ "internalType": "string", "name": "", "type": "string" }], 343 | "stateMutability": "view", 344 | "type": "function" 345 | }, 346 | { 347 | "inputs": [{ "internalType": "uint256", "name": "profileId", "type": "uint256" }], 348 | "name": "getDispatcher", 349 | "outputs": [{ "internalType": "address", "name": "", "type": "address" }], 350 | "stateMutability": "view", 351 | "type": "function" 352 | }, 353 | { 354 | "inputs": [], 355 | "name": "getDomainSeparator", 356 | "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], 357 | "stateMutability": "view", 358 | "type": "function" 359 | }, 360 | { 361 | "inputs": [{ "internalType": "uint256", "name": "profileId", "type": "uint256" }], 362 | "name": "getFollowModule", 363 | "outputs": [{ "internalType": "address", "name": "", "type": "address" }], 364 | "stateMutability": "view", 365 | "type": "function" 366 | }, 367 | { 368 | "inputs": [{ "internalType": "uint256", "name": "profileId", "type": "uint256" }], 369 | "name": "getFollowNFT", 370 | "outputs": [{ "internalType": "address", "name": "", "type": "address" }], 371 | "stateMutability": "view", 372 | "type": "function" 373 | }, 374 | { 375 | "inputs": [], 376 | "name": "getFollowNFTImpl", 377 | "outputs": [{ "internalType": "address", "name": "", "type": "address" }], 378 | "stateMutability": "view", 379 | "type": "function" 380 | }, 381 | { 382 | "inputs": [{ "internalType": "uint256", "name": "profileId", "type": "uint256" }], 383 | "name": "getFollowNFTURI", 384 | "outputs": [{ "internalType": "string", "name": "", "type": "string" }], 385 | "stateMutability": "view", 386 | "type": "function" 387 | }, 388 | { 389 | "inputs": [], 390 | "name": "getGovernance", 391 | "outputs": [{ "internalType": "address", "name": "", "type": "address" }], 392 | "stateMutability": "view", 393 | "type": "function" 394 | }, 395 | { 396 | "inputs": [{ "internalType": "uint256", "name": "profileId", "type": "uint256" }], 397 | "name": "getHandle", 398 | "outputs": [{ "internalType": "string", "name": "", "type": "string" }], 399 | "stateMutability": "view", 400 | "type": "function" 401 | }, 402 | { 403 | "inputs": [{ "internalType": "uint256", "name": "profileId", "type": "uint256" }], 404 | "name": "getProfile", 405 | "outputs": [ 406 | { 407 | "components": [ 408 | { "internalType": "uint256", "name": "pubCount", "type": "uint256" }, 409 | { "internalType": "address", "name": "followModule", "type": "address" }, 410 | { "internalType": "address", "name": "followNFT", "type": "address" }, 411 | { "internalType": "string", "name": "handle", "type": "string" }, 412 | { "internalType": "string", "name": "imageURI", "type": "string" }, 413 | { "internalType": "string", "name": "followNFTURI", "type": "string" } 414 | ], 415 | "internalType": "struct DataTypes.ProfileStruct", 416 | "name": "", 417 | "type": "tuple" 418 | } 419 | ], 420 | "stateMutability": "view", 421 | "type": "function" 422 | }, 423 | { 424 | "inputs": [{ "internalType": "string", "name": "handle", "type": "string" }], 425 | "name": "getProfileIdByHandle", 426 | "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], 427 | "stateMutability": "view", 428 | "type": "function" 429 | }, 430 | { 431 | "inputs": [ 432 | { "internalType": "uint256", "name": "profileId", "type": "uint256" }, 433 | { "internalType": "uint256", "name": "pubId", "type": "uint256" } 434 | ], 435 | "name": "getPub", 436 | "outputs": [ 437 | { 438 | "components": [ 439 | { "internalType": "uint256", "name": "profileIdPointed", "type": "uint256" }, 440 | { "internalType": "uint256", "name": "pubIdPointed", "type": "uint256" }, 441 | { "internalType": "string", "name": "contentURI", "type": "string" }, 442 | { "internalType": "address", "name": "referenceModule", "type": "address" }, 443 | { "internalType": "address", "name": "collectModule", "type": "address" }, 444 | { "internalType": "address", "name": "collectNFT", "type": "address" } 445 | ], 446 | "internalType": "struct DataTypes.PublicationStruct", 447 | "name": "", 448 | "type": "tuple" 449 | } 450 | ], 451 | "stateMutability": "view", 452 | "type": "function" 453 | }, 454 | { 455 | "inputs": [{ "internalType": "uint256", "name": "profileId", "type": "uint256" }], 456 | "name": "getPubCount", 457 | "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], 458 | "stateMutability": "view", 459 | "type": "function" 460 | }, 461 | { 462 | "inputs": [ 463 | { "internalType": "uint256", "name": "profileId", "type": "uint256" }, 464 | { "internalType": "uint256", "name": "pubId", "type": "uint256" } 465 | ], 466 | "name": "getPubPointer", 467 | "outputs": [ 468 | { "internalType": "uint256", "name": "", "type": "uint256" }, 469 | { "internalType": "uint256", "name": "", "type": "uint256" } 470 | ], 471 | "stateMutability": "view", 472 | "type": "function" 473 | }, 474 | { 475 | "inputs": [ 476 | { "internalType": "uint256", "name": "profileId", "type": "uint256" }, 477 | { "internalType": "uint256", "name": "pubId", "type": "uint256" } 478 | ], 479 | "name": "getPubType", 480 | "outputs": [{ "internalType": "enum DataTypes.PubType", "name": "", "type": "uint8" }], 481 | "stateMutability": "view", 482 | "type": "function" 483 | }, 484 | { 485 | "inputs": [ 486 | { "internalType": "uint256", "name": "profileId", "type": "uint256" }, 487 | { "internalType": "uint256", "name": "pubId", "type": "uint256" } 488 | ], 489 | "name": "getReferenceModule", 490 | "outputs": [{ "internalType": "address", "name": "", "type": "address" }], 491 | "stateMutability": "view", 492 | "type": "function" 493 | }, 494 | { 495 | "inputs": [], 496 | "name": "getState", 497 | "outputs": [{ "internalType": "enum DataTypes.ProtocolState", "name": "", "type": "uint8" }], 498 | "stateMutability": "view", 499 | "type": "function" 500 | }, 501 | { 502 | "inputs": [ 503 | { "internalType": "string", "name": "name", "type": "string" }, 504 | { "internalType": "string", "name": "symbol", "type": "string" }, 505 | { "internalType": "address", "name": "newGovernance", "type": "address" } 506 | ], 507 | "name": "initialize", 508 | "outputs": [], 509 | "stateMutability": "nonpayable", 510 | "type": "function" 511 | }, 512 | { 513 | "inputs": [ 514 | { "internalType": "address", "name": "owner", "type": "address" }, 515 | { "internalType": "address", "name": "operator", "type": "address" } 516 | ], 517 | "name": "isApprovedForAll", 518 | "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], 519 | "stateMutability": "view", 520 | "type": "function" 521 | }, 522 | { 523 | "inputs": [{ "internalType": "address", "name": "collectModule", "type": "address" }], 524 | "name": "isCollectModuleWhitelisted", 525 | "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], 526 | "stateMutability": "view", 527 | "type": "function" 528 | }, 529 | { 530 | "inputs": [{ "internalType": "address", "name": "followModule", "type": "address" }], 531 | "name": "isFollowModuleWhitelisted", 532 | "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], 533 | "stateMutability": "view", 534 | "type": "function" 535 | }, 536 | { 537 | "inputs": [{ "internalType": "address", "name": "profileCreator", "type": "address" }], 538 | "name": "isProfileCreatorWhitelisted", 539 | "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], 540 | "stateMutability": "view", 541 | "type": "function" 542 | }, 543 | { 544 | "inputs": [{ "internalType": "address", "name": "referenceModule", "type": "address" }], 545 | "name": "isReferenceModuleWhitelisted", 546 | "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], 547 | "stateMutability": "view", 548 | "type": "function" 549 | }, 550 | { 551 | "inputs": [{ "internalType": "uint256", "name": "tokenId", "type": "uint256" }], 552 | "name": "mintTimestampOf", 553 | "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], 554 | "stateMutability": "view", 555 | "type": "function" 556 | }, 557 | { 558 | "inputs": [ 559 | { 560 | "components": [ 561 | { "internalType": "uint256", "name": "profileId", "type": "uint256" }, 562 | { "internalType": "uint256", "name": "profileIdPointed", "type": "uint256" }, 563 | { "internalType": "uint256", "name": "pubIdPointed", "type": "uint256" }, 564 | { "internalType": "bytes", "name": "referenceModuleData", "type": "bytes" }, 565 | { "internalType": "address", "name": "referenceModule", "type": "address" }, 566 | { "internalType": "bytes", "name": "referenceModuleInitData", "type": "bytes" } 567 | ], 568 | "internalType": "struct DataTypes.MirrorData", 569 | "name": "vars", 570 | "type": "tuple" 571 | } 572 | ], 573 | "name": "mirror", 574 | "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], 575 | "stateMutability": "nonpayable", 576 | "type": "function" 577 | }, 578 | { 579 | "inputs": [ 580 | { 581 | "components": [ 582 | { "internalType": "uint256", "name": "profileId", "type": "uint256" }, 583 | { "internalType": "uint256", "name": "profileIdPointed", "type": "uint256" }, 584 | { "internalType": "uint256", "name": "pubIdPointed", "type": "uint256" }, 585 | { "internalType": "bytes", "name": "referenceModuleData", "type": "bytes" }, 586 | { "internalType": "address", "name": "referenceModule", "type": "address" }, 587 | { "internalType": "bytes", "name": "referenceModuleInitData", "type": "bytes" }, 588 | { 589 | "components": [ 590 | { "internalType": "uint8", "name": "v", "type": "uint8" }, 591 | { "internalType": "bytes32", "name": "r", "type": "bytes32" }, 592 | { "internalType": "bytes32", "name": "s", "type": "bytes32" }, 593 | { "internalType": "uint256", "name": "deadline", "type": "uint256" } 594 | ], 595 | "internalType": "struct DataTypes.EIP712Signature", 596 | "name": "sig", 597 | "type": "tuple" 598 | } 599 | ], 600 | "internalType": "struct DataTypes.MirrorWithSigData", 601 | "name": "vars", 602 | "type": "tuple" 603 | } 604 | ], 605 | "name": "mirrorWithSig", 606 | "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], 607 | "stateMutability": "nonpayable", 608 | "type": "function" 609 | }, 610 | { 611 | "inputs": [], 612 | "name": "name", 613 | "outputs": [{ "internalType": "string", "name": "", "type": "string" }], 614 | "stateMutability": "view", 615 | "type": "function" 616 | }, 617 | { 618 | "inputs": [{ "internalType": "uint256", "name": "tokenId", "type": "uint256" }], 619 | "name": "ownerOf", 620 | "outputs": [{ "internalType": "address", "name": "", "type": "address" }], 621 | "stateMutability": "view", 622 | "type": "function" 623 | }, 624 | { 625 | "inputs": [ 626 | { "internalType": "address", "name": "spender", "type": "address" }, 627 | { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, 628 | { 629 | "components": [ 630 | { "internalType": "uint8", "name": "v", "type": "uint8" }, 631 | { "internalType": "bytes32", "name": "r", "type": "bytes32" }, 632 | { "internalType": "bytes32", "name": "s", "type": "bytes32" }, 633 | { "internalType": "uint256", "name": "deadline", "type": "uint256" } 634 | ], 635 | "internalType": "struct DataTypes.EIP712Signature", 636 | "name": "sig", 637 | "type": "tuple" 638 | } 639 | ], 640 | "name": "permit", 641 | "outputs": [], 642 | "stateMutability": "nonpayable", 643 | "type": "function" 644 | }, 645 | { 646 | "inputs": [ 647 | { "internalType": "address", "name": "owner", "type": "address" }, 648 | { "internalType": "address", "name": "operator", "type": "address" }, 649 | { "internalType": "bool", "name": "approved", "type": "bool" }, 650 | { 651 | "components": [ 652 | { "internalType": "uint8", "name": "v", "type": "uint8" }, 653 | { "internalType": "bytes32", "name": "r", "type": "bytes32" }, 654 | { "internalType": "bytes32", "name": "s", "type": "bytes32" }, 655 | { "internalType": "uint256", "name": "deadline", "type": "uint256" } 656 | ], 657 | "internalType": "struct DataTypes.EIP712Signature", 658 | "name": "sig", 659 | "type": "tuple" 660 | } 661 | ], 662 | "name": "permitForAll", 663 | "outputs": [], 664 | "stateMutability": "nonpayable", 665 | "type": "function" 666 | }, 667 | { 668 | "inputs": [ 669 | { 670 | "components": [ 671 | { "internalType": "uint256", "name": "profileId", "type": "uint256" }, 672 | { "internalType": "string", "name": "contentURI", "type": "string" }, 673 | { "internalType": "address", "name": "collectModule", "type": "address" }, 674 | { "internalType": "bytes", "name": "collectModuleInitData", "type": "bytes" }, 675 | { "internalType": "address", "name": "referenceModule", "type": "address" }, 676 | { "internalType": "bytes", "name": "referenceModuleInitData", "type": "bytes" } 677 | ], 678 | "internalType": "struct DataTypes.PostData", 679 | "name": "vars", 680 | "type": "tuple" 681 | } 682 | ], 683 | "name": "post", 684 | "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], 685 | "stateMutability": "nonpayable", 686 | "type": "function" 687 | }, 688 | { 689 | "inputs": [ 690 | { 691 | "components": [ 692 | { "internalType": "uint256", "name": "profileId", "type": "uint256" }, 693 | { "internalType": "string", "name": "contentURI", "type": "string" }, 694 | { "internalType": "address", "name": "collectModule", "type": "address" }, 695 | { "internalType": "bytes", "name": "collectModuleInitData", "type": "bytes" }, 696 | { "internalType": "address", "name": "referenceModule", "type": "address" }, 697 | { "internalType": "bytes", "name": "referenceModuleInitData", "type": "bytes" }, 698 | { 699 | "components": [ 700 | { "internalType": "uint8", "name": "v", "type": "uint8" }, 701 | { "internalType": "bytes32", "name": "r", "type": "bytes32" }, 702 | { "internalType": "bytes32", "name": "s", "type": "bytes32" }, 703 | { "internalType": "uint256", "name": "deadline", "type": "uint256" } 704 | ], 705 | "internalType": "struct DataTypes.EIP712Signature", 706 | "name": "sig", 707 | "type": "tuple" 708 | } 709 | ], 710 | "internalType": "struct DataTypes.PostWithSigData", 711 | "name": "vars", 712 | "type": "tuple" 713 | } 714 | ], 715 | "name": "postWithSig", 716 | "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], 717 | "stateMutability": "nonpayable", 718 | "type": "function" 719 | }, 720 | { 721 | "inputs": [ 722 | { "internalType": "address", "name": "from", "type": "address" }, 723 | { "internalType": "address", "name": "to", "type": "address" }, 724 | { "internalType": "uint256", "name": "tokenId", "type": "uint256" } 725 | ], 726 | "name": "safeTransferFrom", 727 | "outputs": [], 728 | "stateMutability": "nonpayable", 729 | "type": "function" 730 | }, 731 | { 732 | "inputs": [ 733 | { "internalType": "address", "name": "from", "type": "address" }, 734 | { "internalType": "address", "name": "to", "type": "address" }, 735 | { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, 736 | { "internalType": "bytes", "name": "_data", "type": "bytes" } 737 | ], 738 | "name": "safeTransferFrom", 739 | "outputs": [], 740 | "stateMutability": "nonpayable", 741 | "type": "function" 742 | }, 743 | { 744 | "inputs": [ 745 | { "internalType": "address", "name": "operator", "type": "address" }, 746 | { "internalType": "bool", "name": "approved", "type": "bool" } 747 | ], 748 | "name": "setApprovalForAll", 749 | "outputs": [], 750 | "stateMutability": "nonpayable", 751 | "type": "function" 752 | }, 753 | { 754 | "inputs": [{ "internalType": "uint256", "name": "profileId", "type": "uint256" }], 755 | "name": "setDefaultProfile", 756 | "outputs": [], 757 | "stateMutability": "nonpayable", 758 | "type": "function" 759 | }, 760 | { 761 | "inputs": [ 762 | { 763 | "components": [ 764 | { "internalType": "address", "name": "wallet", "type": "address" }, 765 | { "internalType": "uint256", "name": "profileId", "type": "uint256" }, 766 | { 767 | "components": [ 768 | { "internalType": "uint8", "name": "v", "type": "uint8" }, 769 | { "internalType": "bytes32", "name": "r", "type": "bytes32" }, 770 | { "internalType": "bytes32", "name": "s", "type": "bytes32" }, 771 | { "internalType": "uint256", "name": "deadline", "type": "uint256" } 772 | ], 773 | "internalType": "struct DataTypes.EIP712Signature", 774 | "name": "sig", 775 | "type": "tuple" 776 | } 777 | ], 778 | "internalType": "struct DataTypes.SetDefaultProfileWithSigData", 779 | "name": "vars", 780 | "type": "tuple" 781 | } 782 | ], 783 | "name": "setDefaultProfileWithSig", 784 | "outputs": [], 785 | "stateMutability": "nonpayable", 786 | "type": "function" 787 | }, 788 | { 789 | "inputs": [ 790 | { "internalType": "uint256", "name": "profileId", "type": "uint256" }, 791 | { "internalType": "address", "name": "dispatcher", "type": "address" } 792 | ], 793 | "name": "setDispatcher", 794 | "outputs": [], 795 | "stateMutability": "nonpayable", 796 | "type": "function" 797 | }, 798 | { 799 | "inputs": [ 800 | { 801 | "components": [ 802 | { "internalType": "uint256", "name": "profileId", "type": "uint256" }, 803 | { "internalType": "address", "name": "dispatcher", "type": "address" }, 804 | { 805 | "components": [ 806 | { "internalType": "uint8", "name": "v", "type": "uint8" }, 807 | { "internalType": "bytes32", "name": "r", "type": "bytes32" }, 808 | { "internalType": "bytes32", "name": "s", "type": "bytes32" }, 809 | { "internalType": "uint256", "name": "deadline", "type": "uint256" } 810 | ], 811 | "internalType": "struct DataTypes.EIP712Signature", 812 | "name": "sig", 813 | "type": "tuple" 814 | } 815 | ], 816 | "internalType": "struct DataTypes.SetDispatcherWithSigData", 817 | "name": "vars", 818 | "type": "tuple" 819 | } 820 | ], 821 | "name": "setDispatcherWithSig", 822 | "outputs": [], 823 | "stateMutability": "nonpayable", 824 | "type": "function" 825 | }, 826 | { 827 | "inputs": [{ "internalType": "address", "name": "newEmergencyAdmin", "type": "address" }], 828 | "name": "setEmergencyAdmin", 829 | "outputs": [], 830 | "stateMutability": "nonpayable", 831 | "type": "function" 832 | }, 833 | { 834 | "inputs": [ 835 | { "internalType": "uint256", "name": "profileId", "type": "uint256" }, 836 | { "internalType": "address", "name": "followModule", "type": "address" }, 837 | { "internalType": "bytes", "name": "followModuleInitData", "type": "bytes" } 838 | ], 839 | "name": "setFollowModule", 840 | "outputs": [], 841 | "stateMutability": "nonpayable", 842 | "type": "function" 843 | }, 844 | { 845 | "inputs": [ 846 | { 847 | "components": [ 848 | { "internalType": "uint256", "name": "profileId", "type": "uint256" }, 849 | { "internalType": "address", "name": "followModule", "type": "address" }, 850 | { "internalType": "bytes", "name": "followModuleInitData", "type": "bytes" }, 851 | { 852 | "components": [ 853 | { "internalType": "uint8", "name": "v", "type": "uint8" }, 854 | { "internalType": "bytes32", "name": "r", "type": "bytes32" }, 855 | { "internalType": "bytes32", "name": "s", "type": "bytes32" }, 856 | { "internalType": "uint256", "name": "deadline", "type": "uint256" } 857 | ], 858 | "internalType": "struct DataTypes.EIP712Signature", 859 | "name": "sig", 860 | "type": "tuple" 861 | } 862 | ], 863 | "internalType": "struct DataTypes.SetFollowModuleWithSigData", 864 | "name": "vars", 865 | "type": "tuple" 866 | } 867 | ], 868 | "name": "setFollowModuleWithSig", 869 | "outputs": [], 870 | "stateMutability": "nonpayable", 871 | "type": "function" 872 | }, 873 | { 874 | "inputs": [ 875 | { "internalType": "uint256", "name": "profileId", "type": "uint256" }, 876 | { "internalType": "string", "name": "followNFTURI", "type": "string" } 877 | ], 878 | "name": "setFollowNFTURI", 879 | "outputs": [], 880 | "stateMutability": "nonpayable", 881 | "type": "function" 882 | }, 883 | { 884 | "inputs": [ 885 | { 886 | "components": [ 887 | { "internalType": "uint256", "name": "profileId", "type": "uint256" }, 888 | { "internalType": "string", "name": "followNFTURI", "type": "string" }, 889 | { 890 | "components": [ 891 | { "internalType": "uint8", "name": "v", "type": "uint8" }, 892 | { "internalType": "bytes32", "name": "r", "type": "bytes32" }, 893 | { "internalType": "bytes32", "name": "s", "type": "bytes32" }, 894 | { "internalType": "uint256", "name": "deadline", "type": "uint256" } 895 | ], 896 | "internalType": "struct DataTypes.EIP712Signature", 897 | "name": "sig", 898 | "type": "tuple" 899 | } 900 | ], 901 | "internalType": "struct DataTypes.SetFollowNFTURIWithSigData", 902 | "name": "vars", 903 | "type": "tuple" 904 | } 905 | ], 906 | "name": "setFollowNFTURIWithSig", 907 | "outputs": [], 908 | "stateMutability": "nonpayable", 909 | "type": "function" 910 | }, 911 | { 912 | "inputs": [{ "internalType": "address", "name": "newGovernance", "type": "address" }], 913 | "name": "setGovernance", 914 | "outputs": [], 915 | "stateMutability": "nonpayable", 916 | "type": "function" 917 | }, 918 | { 919 | "inputs": [ 920 | { "internalType": "uint256", "name": "profileId", "type": "uint256" }, 921 | { "internalType": "string", "name": "imageURI", "type": "string" } 922 | ], 923 | "name": "setProfileImageURI", 924 | "outputs": [], 925 | "stateMutability": "nonpayable", 926 | "type": "function" 927 | }, 928 | { 929 | "inputs": [ 930 | { 931 | "components": [ 932 | { "internalType": "uint256", "name": "profileId", "type": "uint256" }, 933 | { "internalType": "string", "name": "imageURI", "type": "string" }, 934 | { 935 | "components": [ 936 | { "internalType": "uint8", "name": "v", "type": "uint8" }, 937 | { "internalType": "bytes32", "name": "r", "type": "bytes32" }, 938 | { "internalType": "bytes32", "name": "s", "type": "bytes32" }, 939 | { "internalType": "uint256", "name": "deadline", "type": "uint256" } 940 | ], 941 | "internalType": "struct DataTypes.EIP712Signature", 942 | "name": "sig", 943 | "type": "tuple" 944 | } 945 | ], 946 | "internalType": "struct DataTypes.SetProfileImageURIWithSigData", 947 | "name": "vars", 948 | "type": "tuple" 949 | } 950 | ], 951 | "name": "setProfileImageURIWithSig", 952 | "outputs": [], 953 | "stateMutability": "nonpayable", 954 | "type": "function" 955 | }, 956 | { 957 | "inputs": [{ "internalType": "enum DataTypes.ProtocolState", "name": "newState", "type": "uint8" }], 958 | "name": "setState", 959 | "outputs": [], 960 | "stateMutability": "nonpayable", 961 | "type": "function" 962 | }, 963 | { 964 | "inputs": [{ "internalType": "address", "name": "", "type": "address" }], 965 | "name": "sigNonces", 966 | "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], 967 | "stateMutability": "view", 968 | "type": "function" 969 | }, 970 | { 971 | "inputs": [{ "internalType": "bytes4", "name": "interfaceId", "type": "bytes4" }], 972 | "name": "supportsInterface", 973 | "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], 974 | "stateMutability": "view", 975 | "type": "function" 976 | }, 977 | { 978 | "inputs": [], 979 | "name": "symbol", 980 | "outputs": [{ "internalType": "string", "name": "", "type": "string" }], 981 | "stateMutability": "view", 982 | "type": "function" 983 | }, 984 | { 985 | "inputs": [{ "internalType": "uint256", "name": "index", "type": "uint256" }], 986 | "name": "tokenByIndex", 987 | "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], 988 | "stateMutability": "view", 989 | "type": "function" 990 | }, 991 | { 992 | "inputs": [{ "internalType": "uint256", "name": "tokenId", "type": "uint256" }], 993 | "name": "tokenDataOf", 994 | "outputs": [ 995 | { 996 | "components": [ 997 | { "internalType": "address", "name": "owner", "type": "address" }, 998 | { "internalType": "uint96", "name": "mintTimestamp", "type": "uint96" } 999 | ], 1000 | "internalType": "struct IERC721Time.TokenData", 1001 | "name": "", 1002 | "type": "tuple" 1003 | } 1004 | ], 1005 | "stateMutability": "view", 1006 | "type": "function" 1007 | }, 1008 | { 1009 | "inputs": [ 1010 | { "internalType": "address", "name": "owner", "type": "address" }, 1011 | { "internalType": "uint256", "name": "index", "type": "uint256" } 1012 | ], 1013 | "name": "tokenOfOwnerByIndex", 1014 | "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], 1015 | "stateMutability": "view", 1016 | "type": "function" 1017 | }, 1018 | { 1019 | "inputs": [{ "internalType": "uint256", "name": "tokenId", "type": "uint256" }], 1020 | "name": "tokenURI", 1021 | "outputs": [{ "internalType": "string", "name": "", "type": "string" }], 1022 | "stateMutability": "view", 1023 | "type": "function" 1024 | }, 1025 | { 1026 | "inputs": [], 1027 | "name": "totalSupply", 1028 | "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], 1029 | "stateMutability": "view", 1030 | "type": "function" 1031 | }, 1032 | { 1033 | "inputs": [ 1034 | { "internalType": "address", "name": "from", "type": "address" }, 1035 | { "internalType": "address", "name": "to", "type": "address" }, 1036 | { "internalType": "uint256", "name": "tokenId", "type": "uint256" } 1037 | ], 1038 | "name": "transferFrom", 1039 | "outputs": [], 1040 | "stateMutability": "nonpayable", 1041 | "type": "function" 1042 | }, 1043 | { 1044 | "inputs": [ 1045 | { "internalType": "address", "name": "collectModule", "type": "address" }, 1046 | { "internalType": "bool", "name": "whitelist", "type": "bool" } 1047 | ], 1048 | "name": "whitelistCollectModule", 1049 | "outputs": [], 1050 | "stateMutability": "nonpayable", 1051 | "type": "function" 1052 | }, 1053 | { 1054 | "inputs": [ 1055 | { "internalType": "address", "name": "followModule", "type": "address" }, 1056 | { "internalType": "bool", "name": "whitelist", "type": "bool" } 1057 | ], 1058 | "name": "whitelistFollowModule", 1059 | "outputs": [], 1060 | "stateMutability": "nonpayable", 1061 | "type": "function" 1062 | }, 1063 | { 1064 | "inputs": [ 1065 | { "internalType": "address", "name": "profileCreator", "type": "address" }, 1066 | { "internalType": "bool", "name": "whitelist", "type": "bool" } 1067 | ], 1068 | "name": "whitelistProfileCreator", 1069 | "outputs": [], 1070 | "stateMutability": "nonpayable", 1071 | "type": "function" 1072 | }, 1073 | { 1074 | "inputs": [ 1075 | { "internalType": "address", "name": "referenceModule", "type": "address" }, 1076 | { "internalType": "bool", "name": "whitelist", "type": "bool" } 1077 | ], 1078 | "name": "whitelistReferenceModule", 1079 | "outputs": [], 1080 | "stateMutability": "nonpayable", 1081 | "type": "function" 1082 | } 1083 | ] 1084 | -------------------------------------------------------------------------------- /src/context/LensContext.tsx: -------------------------------------------------------------------------------- 1 | import { createContext, useContext, useMemo } from "react"; 2 | 3 | interface LensStorage { 4 | lensHubAddress?: string; 5 | network?: "mainnet" | "testnet"; 6 | } 7 | 8 | const LensContext = createContext({ 9 | lensHubAddress: undefined, 10 | network: "mainnet", 11 | }); 12 | 13 | export interface LensProviderProps { 14 | lensHubAddress?: string; 15 | network?: "mainnet" | "testnet"; 16 | } 17 | 18 | function LensProvider({ children, lensHubAddress, network }: React.PropsWithChildren): JSX.Element { 19 | const contextValue = useMemo(() => { 20 | return { lensHubAddress, network }; 21 | }, [lensHubAddress, network]); 22 | 23 | return {children}; 24 | } 25 | 26 | const useLensHubAddress = (): string => { 27 | const context = useContext(LensContext); 28 | 29 | if (context?.lensHubAddress) { 30 | return context.lensHubAddress; 31 | } 32 | 33 | if (context?.network === "testnet") { 34 | return "0x60Ae865ee4C725cd04353b5AAb364553f56ceF82"; 35 | } 36 | 37 | return "0xDb46d1Dc155634FbC732f92E853b10B288AD5a1d"; 38 | }; 39 | 40 | export { LensContext, LensProvider, useLensHubAddress }; 41 | -------------------------------------------------------------------------------- /src/hooks/api/broadcast.ts: -------------------------------------------------------------------------------- 1 | import { gql, MutationTuple, useMutation } from "@apollo/client"; 2 | 3 | import { RelayErrorReasons } from "../../types/error"; 4 | 5 | interface BroadcastRequest { 6 | request: { 7 | id?: string; 8 | signature?: string; 9 | }; 10 | } 11 | 12 | export interface SuccessfulBroadcast { 13 | txId: string; 14 | txHash: string; 15 | } 16 | export interface FailedBroadcast { 17 | reason: RelayErrorReasons; 18 | } 19 | 20 | export const wasSuccessfulBroadcast = ( 21 | broadcast: SuccessfulBroadcast | FailedBroadcast, 22 | ): broadcast is SuccessfulBroadcast => (broadcast as SuccessfulBroadcast).txId !== undefined; 23 | 24 | export const wasFailedBroadcast = (broadcast: SuccessfulBroadcast | FailedBroadcast): broadcast is FailedBroadcast => 25 | (broadcast as FailedBroadcast).reason !== undefined; 26 | 27 | // more: https://docs.lens.xyz/docs/broadcast-transaction 28 | interface BroadcastResponse { 29 | broadcast: SuccessfulBroadcast | FailedBroadcast; 30 | } 31 | 32 | const BROADCAST = gql` 33 | mutation Broadcast($request: BroadcastRequest!) { 34 | broadcast(request: $request) { 35 | ... on RelayerResult { 36 | txHash 37 | txId 38 | } 39 | ... on RelayError { 40 | reason 41 | } 42 | } 43 | } 44 | `; 45 | 46 | export const useBroadcast = (id?: string, signature?: string): MutationTuple => { 47 | return useMutation(BROADCAST, { 48 | variables: { 49 | request: { 50 | id, 51 | signature, 52 | }, 53 | }, 54 | }); 55 | }; 56 | -------------------------------------------------------------------------------- /src/hooks/api/collect.ts: -------------------------------------------------------------------------------- 1 | import { gql, MutationTuple, useMutation } from "@apollo/client"; 2 | 3 | import { TypedDataResponse } from "../../types/lens"; 4 | 5 | interface CollectRequest { 6 | request: { 7 | publicationId?: string; 8 | }; 9 | } 10 | 11 | // more: https://docs.lens.xyz/docs/create-collected-typed-data 12 | interface CollectResponse { 13 | createCollectTypedData: TypedDataResponse; 14 | } 15 | 16 | const COLLECT = gql` 17 | mutation ($request: CreateCollectRequest!) { 18 | createCollectTypedData(request: $request) { 19 | id 20 | expiresAt 21 | typedData { 22 | types { 23 | CollectWithSig { 24 | name 25 | type 26 | } 27 | } 28 | domain { 29 | name 30 | chainId 31 | version 32 | verifyingContract 33 | } 34 | value { 35 | nonce 36 | deadline 37 | profileId 38 | pubId 39 | data 40 | } 41 | } 42 | } 43 | } 44 | `; 45 | 46 | export const useCreateCollectTypedData = (publicationId?: string): MutationTuple => { 47 | return useMutation(COLLECT, { 48 | variables: { 49 | request: { 50 | publicationId, 51 | }, 52 | }, 53 | }); 54 | }; 55 | -------------------------------------------------------------------------------- /src/hooks/api/comment.ts: -------------------------------------------------------------------------------- 1 | import { gql, MutationTuple, useMutation } from "@apollo/client"; 2 | 3 | import { TypedDataResponse } from "../../types/lens"; 4 | import { CollectModule, ReferenceModule } from "../../types/modules"; 5 | import { FailedBroadcast, SuccessfulBroadcast } from "./broadcast"; 6 | 7 | interface CreateCommentTypedDataRequest { 8 | request: { 9 | profileId?: string; 10 | publicationId?: string; 11 | contentURI?: string; 12 | collectModule?: CollectModule; 13 | referenceModule?: ReferenceModule; 14 | }; 15 | } 16 | 17 | // more: https://docs.lens.xyz/docs/create-comment-typed-data 18 | interface CreateCommentTypedDataResponse { 19 | createCommentTypedData?: TypedDataResponse; 20 | } 21 | 22 | const CREATE_COMMENT_TYPED_DATA = gql` 23 | mutation ($request: CreatePublicCommentRequest!) { 24 | createCommentTypedData(request: $request) { 25 | id 26 | expiresAt 27 | typedData { 28 | types { 29 | CommentWithSig { 30 | name 31 | type 32 | } 33 | } 34 | domain { 35 | name 36 | chainId 37 | version 38 | verifyingContract 39 | } 40 | value { 41 | nonce 42 | deadline 43 | profileId 44 | profileIdPointed 45 | pubIdPointed 46 | contentURI 47 | collectModule 48 | collectModuleInitData 49 | referenceModule 50 | referenceModuleInitData 51 | referenceModuleData 52 | } 53 | } 54 | } 55 | } 56 | `; 57 | 58 | export const useCreateCommentTypedData = ( 59 | profileId?: string, 60 | publicationId?: string, 61 | contentURI?: string, 62 | collectModule?: CollectModule, 63 | referenceModule?: ReferenceModule, 64 | ): MutationTuple => { 65 | return useMutation(CREATE_COMMENT_TYPED_DATA, { 66 | variables: { 67 | request: { 68 | profileId, 69 | publicationId, 70 | contentURI, 71 | collectModule, 72 | referenceModule, 73 | }, 74 | }, 75 | }); 76 | }; 77 | 78 | const CREATE_COMMENT_VIA_DISPATCHER = gql` 79 | mutation ($request: CreatePublicCommentRequest!) { 80 | createCommentViaDispatcher(request: $request) { 81 | ... on RelayerResult { 82 | txHash 83 | txId 84 | } 85 | ... on RelayError { 86 | reason 87 | } 88 | } 89 | } 90 | `; 91 | 92 | interface CreateCommentViaDispatcherResponse { 93 | createCommentViaDispatcher: SuccessfulBroadcast | FailedBroadcast; 94 | } 95 | 96 | export const useCreateCommentViaDispatcher = ( 97 | profileId?: string, 98 | publicationId?: string, 99 | contentURI?: string, 100 | collectModule?: CollectModule, 101 | referenceModule?: ReferenceModule, 102 | ): MutationTuple => { 103 | return useMutation(CREATE_COMMENT_VIA_DISPATCHER, { 104 | variables: { 105 | request: { 106 | profileId, 107 | publicationId, 108 | contentURI, 109 | collectModule, 110 | referenceModule, 111 | }, 112 | }, 113 | }); 114 | }; 115 | -------------------------------------------------------------------------------- /src/hooks/api/follow.ts: -------------------------------------------------------------------------------- 1 | import { gql, MutationTuple, useMutation } from "@apollo/client"; 2 | 3 | import { TypedDataResponse } from "../../types/lens"; 4 | 5 | interface FollowRequest { 6 | request: { 7 | follow?: Array<{ 8 | profile?: string; 9 | // TODO: Support follow modules 10 | // followModule: string; 11 | }>; 12 | }; 13 | } 14 | 15 | // more: https://docs.lens.xyz/docs/create-follow-typed-data 16 | interface FollowResponse { 17 | createFollowTypedData: TypedDataResponse; 18 | } 19 | 20 | const FOLLOW = gql` 21 | mutation ($request: FollowRequest!) { 22 | createFollowTypedData(request: $request) { 23 | id 24 | expiresAt 25 | typedData { 26 | domain { 27 | name 28 | chainId 29 | version 30 | verifyingContract 31 | } 32 | types { 33 | FollowWithSig { 34 | name 35 | type 36 | } 37 | } 38 | value { 39 | nonce 40 | deadline 41 | profileIds 42 | datas 43 | } 44 | } 45 | } 46 | } 47 | `; 48 | 49 | export const useCreateFollowTypedData = (profile?: string): MutationTuple => { 50 | return useMutation(FOLLOW, { 51 | variables: { 52 | request: { 53 | follow: [ 54 | { 55 | profile, 56 | }, 57 | ], 58 | }, 59 | }, 60 | }); 61 | }; 62 | 63 | interface UnfollowRequest { 64 | request: { 65 | profile?: string; 66 | }; 67 | } 68 | 69 | // more: https://docs.lens.xyz/docs/create-unfollow-typed-data 70 | interface UnfollowResponse { 71 | createUnfollowTypedData: TypedDataResponse; 72 | } 73 | 74 | const UNFOLLOW = gql` 75 | mutation ($request: UnfollowRequest!) { 76 | createUnfollowTypedData(request: $request) { 77 | id 78 | expiresAt 79 | typedData { 80 | domain { 81 | name 82 | chainId 83 | version 84 | verifyingContract 85 | } 86 | types { 87 | BurnWithSig { 88 | name 89 | type 90 | } 91 | } 92 | value { 93 | nonce 94 | deadline 95 | tokenId 96 | } 97 | } 98 | } 99 | } 100 | `; 101 | 102 | export const useCreateUnfollowTypedData = (profile?: string): MutationTuple => { 103 | return useMutation(UNFOLLOW, { 104 | variables: { 105 | request: { 106 | profile, 107 | }, 108 | }, 109 | }); 110 | }; 111 | -------------------------------------------------------------------------------- /src/hooks/api/indexer.ts: -------------------------------------------------------------------------------- 1 | import { gql, QueryResult, useQuery } from "@apollo/client"; 2 | import { TransactionReceipt } from "@ethersproject/abstract-provider"; 3 | 4 | interface IndexerRequest { 5 | request: { 6 | txId?: string; 7 | }; 8 | } 9 | 10 | // more: https://docs.lens.xyz/docs/has-transaction-been-indexed 11 | interface IndexerResponse { 12 | hasTxHashBeenIndexed?: { 13 | indexed: boolean; 14 | txReceipt: TransactionReceipt; 15 | metadataStatus: { 16 | status: "NOT_FOUND" | "PENDING" | "METADATA_VALIDATION_FAILED" | "SUCCESS"; 17 | reason: string; 18 | }; 19 | }; 20 | } 21 | 22 | const INDEXED = gql` 23 | query ($request: HasTxHashBeenIndexedRequest!) { 24 | hasTxHashBeenIndexed(request: $request) { 25 | ... on TransactionIndexedResult { 26 | indexed 27 | txReceipt { 28 | to 29 | from 30 | contractAddress 31 | transactionIndex 32 | root 33 | gasUsed 34 | logsBloom 35 | blockHash 36 | transactionHash 37 | blockNumber 38 | confirmations 39 | cumulativeGasUsed 40 | effectiveGasPrice 41 | byzantium 42 | type 43 | status 44 | logs { 45 | blockNumber 46 | blockHash 47 | transactionIndex 48 | removed 49 | address 50 | data 51 | topics 52 | transactionHash 53 | logIndex 54 | } 55 | } 56 | metadataStatus { 57 | status 58 | reason 59 | } 60 | } 61 | ... on TransactionError { 62 | reason 63 | txReceipt { 64 | to 65 | from 66 | contractAddress 67 | transactionIndex 68 | root 69 | gasUsed 70 | logsBloom 71 | blockHash 72 | transactionHash 73 | blockNumber 74 | confirmations 75 | cumulativeGasUsed 76 | effectiveGasPrice 77 | byzantium 78 | type 79 | status 80 | logs { 81 | blockNumber 82 | blockHash 83 | transactionIndex 84 | removed 85 | address 86 | data 87 | topics 88 | transactionHash 89 | logIndex 90 | } 91 | } 92 | } 93 | __typename 94 | } 95 | } 96 | `; 97 | 98 | export const useIndexed = (txId?: string, broadcasting?: boolean): QueryResult => { 99 | return useQuery(INDEXED, { 100 | variables: { 101 | request: { 102 | txId, 103 | }, 104 | }, 105 | pollInterval: 500, 106 | fetchPolicy: "network-only", 107 | skip: !txId || !broadcasting, 108 | }); 109 | }; 110 | -------------------------------------------------------------------------------- /src/hooks/api/login.ts: -------------------------------------------------------------------------------- 1 | import { gql, MutationTuple, QueryResult, useMutation, useQuery } from "@apollo/client"; 2 | 3 | interface ChallengeRequest { 4 | request: { 5 | address?: string; 6 | }; 7 | } 8 | 9 | interface ChallengeResponse { 10 | challenge: { 11 | text: string; 12 | }; 13 | } 14 | 15 | const GET_CHALLENGE = gql` 16 | query ($request: ChallengeRequest!) { 17 | challenge(request: $request) { 18 | text 19 | } 20 | } 21 | `; 22 | 23 | export const useChallenge = (address?: string): QueryResult => { 24 | return useQuery(GET_CHALLENGE, { 25 | variables: { 26 | request: { 27 | address, 28 | }, 29 | }, 30 | skip: !address, 31 | }); 32 | }; 33 | 34 | interface AuthenticateRequest { 35 | request: { 36 | address?: string; 37 | signature?: string; 38 | }; 39 | } 40 | 41 | interface AuthenticateResponse { 42 | authenticate: { 43 | accessToken: string; 44 | refreshToken: string; 45 | }; 46 | } 47 | 48 | const AUTHENTICATE = gql` 49 | mutation ($request: SignedAuthChallenge!) { 50 | authenticate(request: $request) { 51 | accessToken 52 | refreshToken 53 | } 54 | } 55 | `; 56 | 57 | export const useAuthenticate = ( 58 | address?: string, 59 | signature?: string, 60 | ): MutationTuple => { 61 | return useMutation(AUTHENTICATE, { 62 | variables: { 63 | request: { 64 | address, 65 | signature, 66 | }, 67 | }, 68 | }); 69 | }; 70 | 71 | interface RefreshRequest { 72 | request: { 73 | refreshToken?: string; 74 | }; 75 | } 76 | 77 | interface RefreshResponse { 78 | refresh: { 79 | accessToken: string; 80 | refreshToken: string; 81 | }; 82 | } 83 | 84 | const REFRESH_AUTHENTICATION = gql` 85 | mutation ($request: RefreshRequest!) { 86 | refresh(request: $request) { 87 | accessToken 88 | refreshToken 89 | } 90 | } 91 | `; 92 | 93 | export const useRefresh = (refreshToken?: string): MutationTuple => { 94 | return useMutation(REFRESH_AUTHENTICATION, { 95 | variables: { 96 | request: { 97 | refreshToken, 98 | }, 99 | }, 100 | }); 101 | }; 102 | -------------------------------------------------------------------------------- /src/hooks/api/mirror.ts: -------------------------------------------------------------------------------- 1 | import { gql, MutationTuple, useMutation } from "@apollo/client"; 2 | 3 | import { TypedDataResponse } from "../../types/lens"; 4 | import { ReferenceModule } from "../../types/modules"; 5 | import { FailedBroadcast, SuccessfulBroadcast } from "./broadcast"; 6 | 7 | interface MirrorRequest { 8 | request: { 9 | profileId?: string; 10 | publicationId?: string; 11 | referenceModule?: ReferenceModule; 12 | }; 13 | } 14 | 15 | // more: https://docs.lens.xyz/docs/create-mirror-typed-data 16 | interface MirrorResponse { 17 | createMirrorTypedData: TypedDataResponse; 18 | } 19 | 20 | const MIRROR = gql` 21 | mutation ($request: CreateMirrorRequest!) { 22 | createMirrorTypedData(request: $request) { 23 | id 24 | expiresAt 25 | typedData { 26 | types { 27 | MirrorWithSig { 28 | name 29 | type 30 | } 31 | } 32 | domain { 33 | name 34 | chainId 35 | version 36 | verifyingContract 37 | } 38 | value { 39 | nonce 40 | deadline 41 | profileId 42 | profileIdPointed 43 | pubIdPointed 44 | referenceModule 45 | referenceModuleData 46 | referenceModuleInitData 47 | } 48 | } 49 | } 50 | } 51 | `; 52 | 53 | export const useCreateMirrorTypedData = ( 54 | profileId?: string, 55 | publicationId?: string, 56 | referenceModule?: ReferenceModule, 57 | ): MutationTuple => { 58 | return useMutation(MIRROR, { 59 | variables: { 60 | request: { 61 | profileId, 62 | publicationId, 63 | referenceModule, 64 | }, 65 | }, 66 | }); 67 | }; 68 | 69 | const CREATE_MIRROR_VIA_DISPATCHER = gql` 70 | mutation ($request: CreateMirrorRequest!) { 71 | createMirrorViaDispatcher(request: $request) { 72 | ... on RelayerResult { 73 | txHash 74 | txId 75 | } 76 | ... on RelayError { 77 | reason 78 | } 79 | } 80 | } 81 | `; 82 | 83 | interface CreateMirrorViaDispatcherResponse { 84 | createMirrorViaDispatcher: SuccessfulBroadcast | FailedBroadcast; 85 | } 86 | 87 | export const useCreateMirrorViaDispatcher = ( 88 | profileId?: string, 89 | publicationId?: string, 90 | referenceModule?: ReferenceModule, 91 | ): MutationTuple => { 92 | return useMutation(CREATE_MIRROR_VIA_DISPATCHER, { 93 | variables: { 94 | request: { 95 | profileId, 96 | publicationId, 97 | referenceModule, 98 | }, 99 | }, 100 | }); 101 | }; 102 | -------------------------------------------------------------------------------- /src/hooks/api/post.ts: -------------------------------------------------------------------------------- 1 | import { gql, MutationTuple, useMutation } from "@apollo/client"; 2 | 3 | import { TypedDataResponse } from "../../types/lens"; 4 | import { CollectModule, ReferenceModule } from "../../types/modules"; 5 | import { FailedBroadcast, SuccessfulBroadcast } from "./broadcast"; 6 | 7 | interface CreatePostTypedDataRequest { 8 | request: { 9 | profileId?: string; 10 | contentURI?: string; 11 | collectModule?: CollectModule; 12 | referenceModule?: ReferenceModule; 13 | }; 14 | } 15 | 16 | // more: https://docs.lens.xyz/docs/create-post-typed-data 17 | interface CreatePostTypedDataResponse { 18 | createPostTypedData?: TypedDataResponse; 19 | } 20 | 21 | const CREATE_POST_TYPED_DATA = gql` 22 | mutation ($request: CreatePublicPostRequest!) { 23 | createPostTypedData(request: $request) { 24 | id 25 | expiresAt 26 | typedData { 27 | types { 28 | PostWithSig { 29 | name 30 | type 31 | } 32 | } 33 | domain { 34 | name 35 | chainId 36 | version 37 | verifyingContract 38 | } 39 | value { 40 | nonce 41 | deadline 42 | profileId 43 | contentURI 44 | collectModule 45 | collectModuleInitData 46 | referenceModule 47 | referenceModuleInitData 48 | } 49 | } 50 | } 51 | } 52 | `; 53 | 54 | export const useCreatePostTypedData = ( 55 | profileId?: string, 56 | contentURI?: string, 57 | collectModule?: CollectModule, 58 | referenceModule?: ReferenceModule, 59 | ): MutationTuple => { 60 | return useMutation(CREATE_POST_TYPED_DATA, { 61 | variables: { 62 | request: { 63 | profileId, 64 | contentURI, 65 | collectModule, 66 | referenceModule, 67 | }, 68 | }, 69 | }); 70 | }; 71 | 72 | const CREATE_POST_VIA_DISPATCHER = gql` 73 | mutation ($request: CreatePublicPostRequest!) { 74 | createPostViaDispatcher(request: $request) { 75 | ... on RelayerResult { 76 | txHash 77 | txId 78 | } 79 | ... on RelayError { 80 | reason 81 | } 82 | } 83 | } 84 | `; 85 | 86 | interface CreatePostViaDispatcherResponse { 87 | createPostViaDispatcher: SuccessfulBroadcast | FailedBroadcast; 88 | } 89 | 90 | export const useCreatePostViaDispatcher = ( 91 | profileId?: string, 92 | contentURI?: string, 93 | collectModule?: CollectModule, 94 | referenceModule?: ReferenceModule, 95 | ): MutationTuple => { 96 | return useMutation(CREATE_POST_VIA_DISPATCHER, { 97 | variables: { 98 | request: { 99 | profileId, 100 | contentURI, 101 | collectModule, 102 | referenceModule, 103 | }, 104 | }, 105 | }); 106 | }; 107 | -------------------------------------------------------------------------------- /src/hooks/api/profile.ts: -------------------------------------------------------------------------------- 1 | import { gql, QueryResult, useQuery } from "@apollo/client"; 2 | import { useEffect, useState } from "react"; 3 | 4 | import { DefaultProfile } from "../../types/lens"; 5 | 6 | interface ProfilesRequest { 7 | request: { 8 | ownedBy?: string; 9 | }; 10 | } 11 | 12 | // more: https://docs.lens.xyz/docs/get-profiles 13 | interface ProfilesResponse { 14 | profiles?: { 15 | items: DefaultProfile[]; 16 | }; 17 | } 18 | 19 | const GET_PROFILES = gql` 20 | query ($request: ProfileQueryRequest!) { 21 | profiles(request: $request) { 22 | items { 23 | id 24 | name 25 | bio 26 | attributes { 27 | displayType 28 | traitType 29 | key 30 | value 31 | } 32 | followNftAddress 33 | metadata 34 | isDefault 35 | picture { 36 | ... on NftImage { 37 | contractAddress 38 | tokenId 39 | uri 40 | verified 41 | } 42 | ... on MediaSet { 43 | original { 44 | url 45 | mimeType 46 | } 47 | } 48 | __typename 49 | } 50 | handle 51 | coverPicture { 52 | ... on NftImage { 53 | contractAddress 54 | tokenId 55 | uri 56 | verified 57 | } 58 | ... on MediaSet { 59 | original { 60 | url 61 | mimeType 62 | } 63 | } 64 | __typename 65 | } 66 | ownedBy 67 | dispatcher { 68 | address 69 | canUseRelay 70 | } 71 | stats { 72 | totalFollowers 73 | totalFollowing 74 | totalPosts 75 | totalComments 76 | totalMirrors 77 | totalPublications 78 | totalCollects 79 | } 80 | followModule { 81 | ... on FeeFollowModuleSettings { 82 | type 83 | amount { 84 | asset { 85 | symbol 86 | name 87 | decimals 88 | address 89 | } 90 | value 91 | } 92 | recipient 93 | } 94 | ... on ProfileFollowModuleSettings { 95 | type 96 | } 97 | ... on RevertFollowModuleSettings { 98 | type 99 | } 100 | } 101 | } 102 | pageInfo { 103 | prev 104 | next 105 | totalCount 106 | } 107 | } 108 | } 109 | `; 110 | 111 | export const useProfiles = (ownedBy?: string): QueryResult => { 112 | return useQuery(GET_PROFILES, { 113 | variables: { 114 | request: { 115 | ownedBy, 116 | }, 117 | }, 118 | skip: !ownedBy, 119 | }); 120 | }; 121 | 122 | interface DefaultProfileRequest { 123 | request: { 124 | ethereumAddress?: string; 125 | }; 126 | } 127 | 128 | // more: https://docs.lens.xyz/docs/get-default-profile 129 | interface DefaultProfileResponse { 130 | defaultProfile?: DefaultProfile; 131 | } 132 | 133 | const GET_DEFAULT_PROFILE = gql` 134 | query ($request: DefaultProfileRequest!) { 135 | defaultProfile(request: $request) { 136 | id 137 | name 138 | bio 139 | attributes { 140 | displayType 141 | traitType 142 | key 143 | value 144 | } 145 | followNftAddress 146 | metadata 147 | isDefault 148 | picture { 149 | ... on NftImage { 150 | contractAddress 151 | tokenId 152 | uri 153 | verified 154 | } 155 | ... on MediaSet { 156 | original { 157 | url 158 | mimeType 159 | } 160 | } 161 | __typename 162 | } 163 | handle 164 | coverPicture { 165 | ... on NftImage { 166 | contractAddress 167 | tokenId 168 | uri 169 | verified 170 | } 171 | ... on MediaSet { 172 | original { 173 | url 174 | mimeType 175 | } 176 | } 177 | __typename 178 | } 179 | ownedBy 180 | dispatcher { 181 | address 182 | canUseRelay 183 | } 184 | stats { 185 | totalFollowers 186 | totalFollowing 187 | totalPosts 188 | totalComments 189 | totalMirrors 190 | totalPublications 191 | totalCollects 192 | } 193 | followModule { 194 | ... on FeeFollowModuleSettings { 195 | type 196 | amount { 197 | asset { 198 | symbol 199 | name 200 | decimals 201 | address 202 | } 203 | value 204 | } 205 | recipient 206 | } 207 | ... on ProfileFollowModuleSettings { 208 | type 209 | } 210 | ... on RevertFollowModuleSettings { 211 | type 212 | } 213 | } 214 | } 215 | } 216 | `; 217 | 218 | // TODO: Allow selecting profile 219 | export const useDefaultProfile = (ethereumAddress?: string): DefaultProfileResponse => { 220 | const [response, setResponse] = useState({ defaultProfile: undefined }); 221 | 222 | const defaultProfileQuery = useQuery(GET_DEFAULT_PROFILE, { 223 | variables: { 224 | request: { 225 | ethereumAddress, 226 | }, 227 | }, 228 | skip: !ethereumAddress, 229 | }); 230 | 231 | const profilesQuery = useProfiles(ethereumAddress); 232 | 233 | useEffect(() => { 234 | if (defaultProfileQuery.data?.defaultProfile) { 235 | setResponse({ defaultProfile: defaultProfileQuery.data?.defaultProfile }); 236 | } else if (profilesQuery.data?.profiles?.items && profilesQuery.data?.profiles?.items.length > 0) { 237 | setResponse({ defaultProfile: profilesQuery.data?.profiles?.items[0] }); 238 | } 239 | }, [ethereumAddress, profilesQuery, defaultProfileQuery]); 240 | 241 | return response; 242 | }; 243 | 244 | interface ProfileRequest { 245 | request: { 246 | handle?: string; 247 | }; 248 | } 249 | 250 | // more: https://docs.lens.xyz/docs/get-profile 251 | interface ProfileResponse { 252 | profile?: DefaultProfile; 253 | } 254 | 255 | const GET_PROFILE = gql` 256 | query ($request: SingleProfileQueryRequest!) { 257 | profile(request: $request) { 258 | id 259 | name 260 | bio 261 | attributes { 262 | displayType 263 | traitType 264 | key 265 | value 266 | } 267 | followNftAddress 268 | metadata 269 | isDefault 270 | picture { 271 | ... on NftImage { 272 | contractAddress 273 | tokenId 274 | uri 275 | verified 276 | } 277 | ... on MediaSet { 278 | original { 279 | url 280 | mimeType 281 | } 282 | } 283 | __typename 284 | } 285 | handle 286 | coverPicture { 287 | ... on NftImage { 288 | contractAddress 289 | tokenId 290 | uri 291 | verified 292 | } 293 | ... on MediaSet { 294 | original { 295 | url 296 | mimeType 297 | } 298 | } 299 | __typename 300 | } 301 | ownedBy 302 | isFollowedByMe 303 | dispatcher { 304 | address 305 | canUseRelay 306 | } 307 | stats { 308 | totalFollowers 309 | totalFollowing 310 | totalPosts 311 | totalComments 312 | totalMirrors 313 | totalPublications 314 | totalCollects 315 | } 316 | followModule { 317 | ... on FeeFollowModuleSettings { 318 | type 319 | amount { 320 | asset { 321 | symbol 322 | name 323 | decimals 324 | address 325 | } 326 | value 327 | } 328 | recipient 329 | } 330 | ... on ProfileFollowModuleSettings { 331 | type 332 | } 333 | ... on RevertFollowModuleSettings { 334 | type 335 | } 336 | } 337 | } 338 | } 339 | `; 340 | 341 | export const useProfile = (handle?: string): QueryResult => { 342 | return useQuery(GET_PROFILE, { 343 | variables: { 344 | request: { handle }, 345 | }, 346 | skip: !handle, 347 | }); 348 | }; 349 | 350 | interface DispatcherRequest { 351 | request: { 352 | profileId?: string; 353 | }; 354 | } 355 | 356 | // more: https://docs.lens.xyz/docs/dispatcher 357 | interface DispatcherResponse { 358 | profile?: { 359 | dispatcher?: { 360 | address: string; 361 | canUseRelay: boolean; 362 | }; 363 | }; 364 | } 365 | 366 | const HAS_DISPATCHER = gql` 367 | query ($request: SingleProfileQueryRequest!) { 368 | profile(request: $request) { 369 | id 370 | dispatcher { 371 | address 372 | canUseRelay 373 | } 374 | } 375 | } 376 | `; 377 | 378 | export const useProfileHasDispatcher = (profileId?: string): boolean => { 379 | const [dispatch, setDispatch] = useState(false); 380 | 381 | const { data } = useQuery(HAS_DISPATCHER, { 382 | variables: { 383 | request: { profileId }, 384 | }, 385 | skip: !profileId, 386 | }); 387 | 388 | useEffect(() => { 389 | setDispatch(data?.profile?.dispatcher?.canUseRelay ?? false); 390 | }, [data]); 391 | 392 | return dispatch; 393 | }; 394 | 395 | function isDefaultProfileResponse( 396 | response: ProfileResponse | DefaultProfileResponse, 397 | ): response is DefaultProfileResponse { 398 | return (response as DefaultProfileResponse).defaultProfile !== undefined; 399 | } 400 | 401 | function isProfileResponse(response: ProfileResponse | DefaultProfileResponse): response is ProfileResponse { 402 | return (response as ProfileResponse).profile !== undefined; 403 | } 404 | 405 | export const useProfilePicture = (response?: ProfileResponse | DefaultProfileResponse): string | undefined => { 406 | if (response) { 407 | if (isProfileResponse(response)) { 408 | return response.profile?.picture?.original?.url; 409 | } else if (isDefaultProfileResponse(response)) { 410 | return response.defaultProfile?.picture?.original?.url; 411 | } 412 | } 413 | }; 414 | -------------------------------------------------------------------------------- /src/hooks/api/publication.ts: -------------------------------------------------------------------------------- 1 | import { gql, QueryResult, useQuery } from "@apollo/client"; 2 | 3 | import { PageInfo, Post, PublicationType } from "../../types/lens"; 4 | import { PublicationMainFocus } from "../../types/metadata"; 5 | 6 | interface GetPublicationRequest { 7 | request: { 8 | publicationId?: string; 9 | }; 10 | profileId?: string; 11 | } 12 | 13 | // more: https://docs.lens.xyz/docs/get-publication 14 | interface GetPublicationResponse { 15 | publication?: Post; 16 | } 17 | 18 | const GET_PUBLICATION = gql` 19 | query ($request: PublicationQueryRequest!, $profileId: ProfileId) { 20 | publication(request: $request) { 21 | __typename 22 | ... on Post { 23 | ...PostFields 24 | } 25 | ... on Comment { 26 | ...CommentFields 27 | } 28 | ... on Mirror { 29 | ...MirrorFields 30 | } 31 | } 32 | } 33 | 34 | fragment MediaFields on Media { 35 | url 36 | mimeType 37 | } 38 | 39 | fragment ProfileFields on Profile { 40 | id 41 | name 42 | bio 43 | attributes { 44 | displayType 45 | traitType 46 | key 47 | value 48 | } 49 | isFollowedByMe 50 | isFollowing(who: null) 51 | followNftAddress 52 | metadata 53 | isDefault 54 | handle 55 | picture { 56 | ... on NftImage { 57 | contractAddress 58 | tokenId 59 | uri 60 | verified 61 | } 62 | ... on MediaSet { 63 | original { 64 | ...MediaFields 65 | } 66 | } 67 | } 68 | coverPicture { 69 | ... on NftImage { 70 | contractAddress 71 | tokenId 72 | uri 73 | verified 74 | } 75 | ... on MediaSet { 76 | original { 77 | ...MediaFields 78 | } 79 | } 80 | } 81 | ownedBy 82 | dispatcher { 83 | address 84 | } 85 | stats { 86 | totalFollowers 87 | totalFollowing 88 | totalPosts 89 | totalComments 90 | totalMirrors 91 | totalPublications 92 | totalCollects 93 | } 94 | followModule { 95 | ... on FeeFollowModuleSettings { 96 | type 97 | amount { 98 | asset { 99 | name 100 | symbol 101 | decimals 102 | address 103 | } 104 | value 105 | } 106 | recipient 107 | } 108 | ... on ProfileFollowModuleSettings { 109 | type 110 | } 111 | ... on RevertFollowModuleSettings { 112 | type 113 | } 114 | } 115 | } 116 | 117 | fragment PublicationStatsFields on PublicationStats { 118 | totalAmountOfMirrors 119 | totalAmountOfCollects 120 | totalAmountOfComments 121 | } 122 | 123 | fragment MetadataOutputFields on MetadataOutput { 124 | name 125 | description 126 | content 127 | media { 128 | original { 129 | ...MediaFields 130 | } 131 | } 132 | attributes { 133 | displayType 134 | traitType 135 | value 136 | } 137 | tags 138 | } 139 | 140 | fragment Erc20Fields on Erc20 { 141 | name 142 | symbol 143 | decimals 144 | address 145 | } 146 | 147 | fragment CollectModuleFields on CollectModule { 148 | __typename 149 | ... on FreeCollectModuleSettings { 150 | type 151 | followerOnly 152 | contractAddress 153 | } 154 | ... on FeeCollectModuleSettings { 155 | type 156 | amount { 157 | asset { 158 | ...Erc20Fields 159 | } 160 | value 161 | } 162 | recipient 163 | referralFee 164 | } 165 | ... on LimitedFeeCollectModuleSettings { 166 | type 167 | collectLimit 168 | amount { 169 | asset { 170 | ...Erc20Fields 171 | } 172 | value 173 | } 174 | recipient 175 | referralFee 176 | } 177 | ... on LimitedTimedFeeCollectModuleSettings { 178 | type 179 | collectLimit 180 | amount { 181 | asset { 182 | ...Erc20Fields 183 | } 184 | value 185 | } 186 | recipient 187 | referralFee 188 | endTimestamp 189 | } 190 | ... on RevertCollectModuleSettings { 191 | type 192 | } 193 | ... on TimedFeeCollectModuleSettings { 194 | type 195 | amount { 196 | asset { 197 | ...Erc20Fields 198 | } 199 | value 200 | } 201 | recipient 202 | referralFee 203 | endTimestamp 204 | } 205 | } 206 | 207 | fragment PostFields on Post { 208 | id 209 | profile { 210 | ...ProfileFields 211 | } 212 | stats { 213 | ...PublicationStatsFields 214 | } 215 | metadata { 216 | ...MetadataOutputFields 217 | } 218 | createdAt 219 | collectModule { 220 | ...CollectModuleFields 221 | } 222 | referenceModule { 223 | ... on FollowOnlyReferenceModuleSettings { 224 | type 225 | } 226 | } 227 | appId 228 | hidden 229 | reaction(request: null) 230 | mirrors(by: $profileId) 231 | hasCollectedByMe 232 | } 233 | 234 | fragment MirrorBaseFields on Mirror { 235 | id 236 | profile { 237 | ...ProfileFields 238 | } 239 | stats { 240 | ...PublicationStatsFields 241 | } 242 | metadata { 243 | ...MetadataOutputFields 244 | } 245 | createdAt 246 | collectModule { 247 | ...CollectModuleFields 248 | } 249 | referenceModule { 250 | ... on FollowOnlyReferenceModuleSettings { 251 | type 252 | } 253 | } 254 | appId 255 | hidden 256 | reaction(request: null) 257 | hasCollectedByMe 258 | } 259 | 260 | fragment MirrorFields on Mirror { 261 | ...MirrorBaseFields 262 | mirrorOf { 263 | ... on Post { 264 | ...PostFields 265 | } 266 | ... on Comment { 267 | ...CommentFields 268 | } 269 | } 270 | } 271 | 272 | fragment CommentBaseFields on Comment { 273 | id 274 | profile { 275 | ...ProfileFields 276 | } 277 | stats { 278 | ...PublicationStatsFields 279 | } 280 | metadata { 281 | ...MetadataOutputFields 282 | } 283 | createdAt 284 | collectModule { 285 | ...CollectModuleFields 286 | } 287 | referenceModule { 288 | ... on FollowOnlyReferenceModuleSettings { 289 | type 290 | } 291 | } 292 | appId 293 | hidden 294 | reaction(request: null) 295 | mirrors(by: null) 296 | hasCollectedByMe 297 | } 298 | 299 | fragment CommentFields on Comment { 300 | ...CommentBaseFields 301 | mainPost { 302 | ... on Post { 303 | ...PostFields 304 | } 305 | ... on Mirror { 306 | ...MirrorBaseFields 307 | mirrorOf { 308 | ... on Post { 309 | ...PostFields 310 | } 311 | ... on Comment { 312 | ...CommentMirrorOfFields 313 | } 314 | } 315 | } 316 | } 317 | } 318 | 319 | fragment CommentMirrorOfFields on Comment { 320 | ...CommentBaseFields 321 | mainPost { 322 | ... on Post { 323 | ...PostFields 324 | } 325 | ... on Mirror { 326 | ...MirrorBaseFields 327 | } 328 | } 329 | } 330 | `; 331 | 332 | export const usePublication = ( 333 | publicationId?: string, 334 | profileId?: string, 335 | ): QueryResult => { 336 | return useQuery(GET_PUBLICATION, { 337 | variables: { 338 | request: { 339 | publicationId, 340 | }, 341 | profileId, 342 | }, 343 | skip: !publicationId, 344 | }); 345 | }; 346 | 347 | interface GetPublicationsRequest { 348 | request: { 349 | profileId?: string; 350 | commentsOf?: string; 351 | publicationTypes?: PublicationType[]; 352 | metadata?: { 353 | tags?: { 354 | oneOf: string[]; 355 | }; 356 | mainContentFocus?: PublicationMainFocus; 357 | }; 358 | sources?: string[]; 359 | cursor?: string; 360 | }; 361 | } 362 | 363 | // more: https://docs.lens.xyz/docs/get-publications 364 | interface GetPublicationsResponse { 365 | publications?: { 366 | items: Post[]; 367 | pageInfo: PageInfo; 368 | }; 369 | } 370 | 371 | const GET_PUBLICATIONS = gql` 372 | query ($request: PublicationsQueryRequest!) { 373 | publications(request: $request) { 374 | items { 375 | __typename 376 | ... on Post { 377 | ...PostFields 378 | } 379 | ... on Comment { 380 | ...CommentFields 381 | } 382 | ... on Mirror { 383 | ...MirrorFields 384 | } 385 | } 386 | pageInfo { 387 | prev 388 | next 389 | totalCount 390 | } 391 | } 392 | } 393 | fragment MediaFields on Media { 394 | url 395 | mimeType 396 | } 397 | fragment ProfileFields on Profile { 398 | id 399 | name 400 | bio 401 | attributes { 402 | displayType 403 | traitType 404 | key 405 | value 406 | } 407 | isFollowedByMe 408 | isFollowing(who: null) 409 | followNftAddress 410 | metadata 411 | isDefault 412 | handle 413 | picture { 414 | ... on NftImage { 415 | contractAddress 416 | tokenId 417 | uri 418 | verified 419 | } 420 | ... on MediaSet { 421 | original { 422 | ...MediaFields 423 | } 424 | } 425 | } 426 | coverPicture { 427 | ... on NftImage { 428 | contractAddress 429 | tokenId 430 | uri 431 | verified 432 | } 433 | ... on MediaSet { 434 | original { 435 | ...MediaFields 436 | } 437 | } 438 | } 439 | ownedBy 440 | dispatcher { 441 | address 442 | } 443 | stats { 444 | totalFollowers 445 | totalFollowing 446 | totalPosts 447 | totalComments 448 | totalMirrors 449 | totalPublications 450 | totalCollects 451 | } 452 | followModule { 453 | ... on FeeFollowModuleSettings { 454 | type 455 | amount { 456 | asset { 457 | name 458 | symbol 459 | decimals 460 | address 461 | } 462 | value 463 | } 464 | recipient 465 | } 466 | ... on ProfileFollowModuleSettings { 467 | type 468 | } 469 | ... on RevertFollowModuleSettings { 470 | type 471 | } 472 | } 473 | } 474 | fragment PublicationStatsFields on PublicationStats { 475 | totalAmountOfMirrors 476 | totalAmountOfCollects 477 | totalAmountOfComments 478 | } 479 | fragment MetadataOutputFields on MetadataOutput { 480 | name 481 | description 482 | content 483 | media { 484 | original { 485 | ...MediaFields 486 | } 487 | } 488 | attributes { 489 | displayType 490 | traitType 491 | value 492 | } 493 | } 494 | fragment Erc20Fields on Erc20 { 495 | name 496 | symbol 497 | decimals 498 | address 499 | } 500 | fragment CollectModuleFields on CollectModule { 501 | __typename 502 | ... on FreeCollectModuleSettings { 503 | type 504 | followerOnly 505 | contractAddress 506 | } 507 | ... on FeeCollectModuleSettings { 508 | type 509 | amount { 510 | asset { 511 | ...Erc20Fields 512 | } 513 | value 514 | } 515 | recipient 516 | referralFee 517 | } 518 | ... on LimitedFeeCollectModuleSettings { 519 | type 520 | collectLimit 521 | amount { 522 | asset { 523 | ...Erc20Fields 524 | } 525 | value 526 | } 527 | recipient 528 | referralFee 529 | } 530 | ... on LimitedTimedFeeCollectModuleSettings { 531 | type 532 | collectLimit 533 | amount { 534 | asset { 535 | ...Erc20Fields 536 | } 537 | value 538 | } 539 | recipient 540 | referralFee 541 | endTimestamp 542 | } 543 | ... on RevertCollectModuleSettings { 544 | type 545 | } 546 | ... on TimedFeeCollectModuleSettings { 547 | type 548 | amount { 549 | asset { 550 | ...Erc20Fields 551 | } 552 | value 553 | } 554 | recipient 555 | referralFee 556 | endTimestamp 557 | } 558 | } 559 | fragment PostFields on Post { 560 | id 561 | profile { 562 | ...ProfileFields 563 | } 564 | stats { 565 | ...PublicationStatsFields 566 | } 567 | metadata { 568 | ...MetadataOutputFields 569 | } 570 | createdAt 571 | collectModule { 572 | ...CollectModuleFields 573 | } 574 | referenceModule { 575 | ... on FollowOnlyReferenceModuleSettings { 576 | type 577 | } 578 | } 579 | appId 580 | hidden 581 | reaction(request: null) 582 | mirrors(by: null) 583 | hasCollectedByMe 584 | } 585 | fragment MirrorBaseFields on Mirror { 586 | id 587 | profile { 588 | ...ProfileFields 589 | } 590 | stats { 591 | ...PublicationStatsFields 592 | } 593 | metadata { 594 | ...MetadataOutputFields 595 | } 596 | createdAt 597 | collectModule { 598 | ...CollectModuleFields 599 | } 600 | referenceModule { 601 | ... on FollowOnlyReferenceModuleSettings { 602 | type 603 | } 604 | } 605 | appId 606 | hidden 607 | reaction(request: null) 608 | hasCollectedByMe 609 | } 610 | fragment MirrorFields on Mirror { 611 | ...MirrorBaseFields 612 | mirrorOf { 613 | ... on Post { 614 | ...PostFields 615 | } 616 | ... on Comment { 617 | ...CommentFields 618 | } 619 | } 620 | } 621 | fragment CommentBaseFields on Comment { 622 | id 623 | profile { 624 | ...ProfileFields 625 | } 626 | stats { 627 | ...PublicationStatsFields 628 | } 629 | metadata { 630 | ...MetadataOutputFields 631 | } 632 | createdAt 633 | collectModule { 634 | ...CollectModuleFields 635 | } 636 | referenceModule { 637 | ... on FollowOnlyReferenceModuleSettings { 638 | type 639 | } 640 | } 641 | appId 642 | hidden 643 | reaction(request: null) 644 | mirrors(by: null) 645 | hasCollectedByMe 646 | } 647 | fragment CommentFields on Comment { 648 | ...CommentBaseFields 649 | mainPost { 650 | ... on Post { 651 | ...PostFields 652 | } 653 | ... on Mirror { 654 | ...MirrorBaseFields 655 | mirrorOf { 656 | ... on Post { 657 | ...PostFields 658 | } 659 | ... on Comment { 660 | ...CommentMirrorOfFields 661 | } 662 | } 663 | } 664 | } 665 | } 666 | fragment CommentMirrorOfFields on Comment { 667 | ...CommentBaseFields 668 | mainPost { 669 | ... on Post { 670 | ...PostFields 671 | } 672 | ... on Mirror { 673 | ...MirrorBaseFields 674 | } 675 | } 676 | } 677 | `; 678 | 679 | export const usePublications = ( 680 | profileId?: string, 681 | publicationTypes: PublicationType[] = [PublicationType.POST], 682 | sources?: [string], 683 | ): QueryResult => { 684 | return useQuery(GET_PUBLICATIONS, { 685 | variables: { 686 | request: { 687 | profileId, 688 | publicationTypes, 689 | sources, 690 | }, 691 | }, 692 | skip: !profileId, 693 | }); 694 | }; 695 | 696 | export const usePublicationComments = ( 697 | publicationId?: string, 698 | ): QueryResult => { 699 | return useQuery(GET_PUBLICATIONS, { 700 | variables: { 701 | request: { 702 | commentsOf: publicationId, 703 | }, 704 | }, 705 | skip: !publicationId, 706 | }); 707 | }; 708 | -------------------------------------------------------------------------------- /src/hooks/api/search.ts: -------------------------------------------------------------------------------- 1 | import { gql, QueryResult, useQuery } from "@apollo/client"; 2 | 3 | import { Profile } from "../../types/lens"; 4 | 5 | interface ProfileSearchRequest { 6 | request: { 7 | query?: string; 8 | type: "PROFILE"; 9 | limit: number; 10 | }; 11 | } 12 | 13 | // more: https://docs.lens.xyz/docs/search-profiles-and-publications 14 | interface ProfileSearchResponse { 15 | search?: { 16 | items: Profile[]; 17 | }; 18 | } 19 | 20 | const SEARCH = gql` 21 | query ($request: SearchQueryRequest!) { 22 | search(request: $request) { 23 | ... on PublicationSearchResult { 24 | __typename 25 | items { 26 | __typename 27 | ... on Comment { 28 | ...CommentFields 29 | } 30 | ... on Post { 31 | ...PostFields 32 | } 33 | } 34 | pageInfo { 35 | prev 36 | totalCount 37 | next 38 | } 39 | } 40 | ... on ProfileSearchResult { 41 | __typename 42 | items { 43 | ... on Profile { 44 | ...ProfileFields 45 | } 46 | } 47 | pageInfo { 48 | prev 49 | totalCount 50 | next 51 | } 52 | } 53 | } 54 | } 55 | 56 | fragment MediaFields on Media { 57 | url 58 | mimeType 59 | } 60 | 61 | fragment MirrorBaseFields on Mirror { 62 | id 63 | profile { 64 | ...ProfileFields 65 | } 66 | stats { 67 | ...PublicationStatsFields 68 | } 69 | metadata { 70 | ...MetadataOutputFields 71 | } 72 | createdAt 73 | collectModule { 74 | ...CollectModuleFields 75 | } 76 | referenceModule { 77 | ... on FollowOnlyReferenceModuleSettings { 78 | type 79 | } 80 | } 81 | appId 82 | } 83 | 84 | fragment ProfileFields on Profile { 85 | profileId: id 86 | name 87 | bio 88 | attributes { 89 | displayType 90 | traitType 91 | key 92 | value 93 | } 94 | isFollowedByMe 95 | isFollowing(who: null) 96 | metadataUrl: metadata 97 | isDefault 98 | handle 99 | picture { 100 | ... on NftImage { 101 | contractAddress 102 | tokenId 103 | uri 104 | verified 105 | } 106 | ... on MediaSet { 107 | original { 108 | ...MediaFields 109 | } 110 | } 111 | } 112 | coverPicture { 113 | ... on NftImage { 114 | contractAddress 115 | tokenId 116 | uri 117 | verified 118 | } 119 | ... on MediaSet { 120 | original { 121 | ...MediaFields 122 | } 123 | } 124 | } 125 | ownedBy 126 | dispatcher { 127 | address 128 | } 129 | stats { 130 | totalFollowers 131 | totalFollowing 132 | totalPosts 133 | totalComments 134 | totalMirrors 135 | totalPublications 136 | totalCollects 137 | } 138 | followModule { 139 | ... on FeeFollowModuleSettings { 140 | type 141 | amount { 142 | asset { 143 | name 144 | symbol 145 | decimals 146 | address 147 | } 148 | value 149 | } 150 | recipient 151 | } 152 | ... on ProfileFollowModuleSettings { 153 | type 154 | } 155 | ... on RevertFollowModuleSettings { 156 | type 157 | } 158 | } 159 | } 160 | 161 | fragment PublicationStatsFields on PublicationStats { 162 | totalAmountOfMirrors 163 | totalAmountOfCollects 164 | totalAmountOfComments 165 | } 166 | 167 | fragment MetadataOutputFields on MetadataOutput { 168 | name 169 | description 170 | content 171 | media { 172 | original { 173 | ...MediaFields 174 | } 175 | } 176 | attributes { 177 | displayType 178 | traitType 179 | value 180 | } 181 | } 182 | 183 | fragment Erc20Fields on Erc20 { 184 | name 185 | symbol 186 | decimals 187 | address 188 | } 189 | 190 | fragment CollectModuleFields on CollectModule { 191 | __typename 192 | ... on FreeCollectModuleSettings { 193 | type 194 | followerOnly 195 | contractAddress 196 | } 197 | ... on FeeCollectModuleSettings { 198 | type 199 | amount { 200 | asset { 201 | ...Erc20Fields 202 | } 203 | value 204 | } 205 | recipient 206 | referralFee 207 | } 208 | ... on LimitedFeeCollectModuleSettings { 209 | type 210 | collectLimit 211 | amount { 212 | asset { 213 | ...Erc20Fields 214 | } 215 | value 216 | } 217 | recipient 218 | referralFee 219 | } 220 | ... on LimitedTimedFeeCollectModuleSettings { 221 | type 222 | collectLimit 223 | amount { 224 | asset { 225 | ...Erc20Fields 226 | } 227 | value 228 | } 229 | recipient 230 | referralFee 231 | endTimestamp 232 | } 233 | ... on RevertCollectModuleSettings { 234 | type 235 | } 236 | ... on TimedFeeCollectModuleSettings { 237 | type 238 | amount { 239 | asset { 240 | ...Erc20Fields 241 | } 242 | value 243 | } 244 | recipient 245 | referralFee 246 | endTimestamp 247 | } 248 | } 249 | 250 | fragment PostFields on Post { 251 | id 252 | profile { 253 | ...ProfileFields 254 | } 255 | stats { 256 | ...PublicationStatsFields 257 | } 258 | metadata { 259 | ...MetadataOutputFields 260 | } 261 | createdAt 262 | collectModule { 263 | ...CollectModuleFields 264 | } 265 | referenceModule { 266 | ... on FollowOnlyReferenceModuleSettings { 267 | type 268 | } 269 | } 270 | appId 271 | hidden 272 | reaction(request: null) 273 | mirrors(by: null) 274 | hasCollectedByMe 275 | } 276 | 277 | fragment CommentBaseFields on Comment { 278 | id 279 | profile { 280 | ...ProfileFields 281 | } 282 | stats { 283 | ...PublicationStatsFields 284 | } 285 | metadata { 286 | ...MetadataOutputFields 287 | } 288 | createdAt 289 | collectModule { 290 | ...CollectModuleFields 291 | } 292 | referenceModule { 293 | ... on FollowOnlyReferenceModuleSettings { 294 | type 295 | } 296 | } 297 | appId 298 | hidden 299 | reaction(request: null) 300 | mirrors(by: null) 301 | hasCollectedByMe 302 | } 303 | 304 | fragment CommentFields on Comment { 305 | ...CommentBaseFields 306 | mainPost { 307 | ... on Post { 308 | ...PostFields 309 | } 310 | ... on Mirror { 311 | ...MirrorBaseFields 312 | mirrorOf { 313 | ... on Post { 314 | ...PostFields 315 | } 316 | ... on Comment { 317 | ...CommentMirrorOfFields 318 | } 319 | } 320 | } 321 | } 322 | } 323 | 324 | fragment CommentMirrorOfFields on Comment { 325 | ...CommentBaseFields 326 | mainPost { 327 | ... on Post { 328 | ...PostFields 329 | } 330 | ... on Mirror { 331 | ...MirrorBaseFields 332 | } 333 | } 334 | } 335 | `; 336 | 337 | export const useSearch = ( 338 | query?: string, 339 | limit: number = 9, 340 | ): QueryResult => { 341 | return useQuery(SEARCH, { 342 | variables: { 343 | request: { 344 | query, 345 | type: "PROFILE", 346 | limit, 347 | }, 348 | }, 349 | skip: !query, 350 | }); 351 | }; 352 | -------------------------------------------------------------------------------- /src/hooks/combined/collect.ts: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | 3 | import { OnFunctions } from "../../types/on"; 4 | import { useCreateCollectTypedData } from "../api/collect"; 5 | import { useBroadcastAPIHook } from "../utils/broadcast"; 6 | import { useSignTypedData } from "../utils/sign"; 7 | 8 | export const useCollect = ( 9 | publicationId: string | undefined, 10 | onFunctions?: OnFunctions, 11 | ): { collect: () => void; loading: boolean; error: Error | null } => { 12 | const [createCollectTypedData, { data: collectTypedData }] = useCreateCollectTypedData(publicationId); 13 | 14 | const signReturn = useSignTypedData(collectTypedData?.createCollectTypedData?.typedData); 15 | 16 | const { 17 | start: collect, 18 | loading, 19 | error, 20 | } = useBroadcastAPIHook(collectTypedData?.createCollectTypedData?.id, undefined, signReturn, onFunctions); 21 | 22 | useEffect(() => { 23 | loading && createCollectTypedData().catch(console.error); 24 | }, [publicationId, loading]); 25 | 26 | return { collect, loading, error }; 27 | }; 28 | -------------------------------------------------------------------------------- /src/hooks/combined/comment.ts: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | 3 | import { OnFunctions } from "../../types/on"; 4 | import { useCreateCommentTypedData, useCreateCommentViaDispatcher } from "../api/comment"; 5 | import { useProfileHasDispatcher } from "../api/profile"; 6 | import { useBroadcastAPIHook } from "../utils/broadcast"; 7 | import { useSignTypedData } from "../utils/sign"; 8 | 9 | export const useComment = ( 10 | profileId: string | undefined, 11 | publicationId: string | undefined, 12 | commentURL: string | undefined, 13 | onFunctions?: OnFunctions, 14 | ): { comment: () => void; loading: boolean; error: Error | null } => { 15 | const dispatch = useProfileHasDispatcher(profileId); 16 | 17 | const [createCommentTypedData, { data: commentTypedData, reset: resetTypedData }] = useCreateCommentTypedData( 18 | profileId, 19 | publicationId, 20 | commentURL, 21 | { 22 | freeCollectModule: { 23 | followerOnly: false, 24 | }, 25 | }, 26 | ); 27 | 28 | const [createCommentViaDispatcher, { data: commentViaDispatcher, reset: resetViaDispatcher }] = 29 | useCreateCommentViaDispatcher(profileId, publicationId, commentURL, { 30 | freeCollectModule: { 31 | followerOnly: false, 32 | }, 33 | }); 34 | 35 | const signReturn = useSignTypedData(commentTypedData?.createCommentTypedData?.typedData); 36 | 37 | const { 38 | start: comment, 39 | loading, 40 | error, 41 | } = useBroadcastAPIHook( 42 | commentTypedData?.createCommentTypedData?.id, 43 | commentViaDispatcher?.createCommentViaDispatcher, 44 | signReturn, 45 | onFunctions, 46 | ); 47 | 48 | useEffect(() => { 49 | resetTypedData(); 50 | resetViaDispatcher(); 51 | }, [commentURL]); 52 | 53 | useEffect(() => { 54 | if (loading && commentURL) { 55 | if (dispatch) { 56 | createCommentViaDispatcher().catch(console.error); 57 | } else { 58 | createCommentTypedData().catch(console.error); 59 | } 60 | } 61 | }, [commentURL, loading]); 62 | 63 | return { comment, loading, error }; 64 | }; 65 | -------------------------------------------------------------------------------- /src/hooks/combined/follow.ts: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | 3 | import { OnFunctions } from "../../types/on"; 4 | import { useCreateFollowTypedData, useCreateUnfollowTypedData } from "../api/follow"; 5 | import { useBroadcastAPIHook } from "../utils/broadcast"; 6 | import { useSignTypedData } from "../utils/sign"; 7 | 8 | export const useFollow = ( 9 | profileId: string, 10 | onFunctions?: OnFunctions, 11 | ): { follow: () => void; loading: boolean; error: Error | null } => { 12 | const [createFollowTypedData, { data: followTypedData }] = useCreateFollowTypedData(profileId); 13 | 14 | const signReturn = useSignTypedData(followTypedData?.createFollowTypedData?.typedData); 15 | 16 | const { 17 | start: follow, 18 | loading, 19 | error, 20 | } = useBroadcastAPIHook(followTypedData?.createFollowTypedData?.id, undefined, signReturn, onFunctions); 21 | 22 | useEffect(() => { 23 | loading && createFollowTypedData().catch(console.error); 24 | }, [profileId, loading]); 25 | 26 | return { follow, loading, error }; 27 | }; 28 | 29 | export const useUnfollow = ( 30 | profileId: string, 31 | onFunctions: OnFunctions, 32 | ): { unfollow: () => void; loading: boolean; error: Error | null } => { 33 | const [createUnfollowTypedData, { data: unfollowTypedData }] = useCreateUnfollowTypedData(profileId); 34 | 35 | const signReturn = useSignTypedData(unfollowTypedData?.createUnfollowTypedData?.typedData); 36 | 37 | const { 38 | start: unfollow, 39 | loading, 40 | error, 41 | } = useBroadcastAPIHook(unfollowTypedData?.createUnfollowTypedData?.id, undefined, signReturn, onFunctions); 42 | 43 | useEffect(() => { 44 | loading && createUnfollowTypedData().catch(console.error); 45 | }, [profileId, loading]); 46 | 47 | return { unfollow, loading, error }; 48 | }; 49 | -------------------------------------------------------------------------------- /src/hooks/combined/mirror.ts: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | 3 | import { OnFunctions } from "../../types/on"; 4 | import { useCreateMirrorTypedData, useCreateMirrorViaDispatcher } from "../api/mirror"; 5 | import { useProfileHasDispatcher } from "../api/profile"; 6 | import { useBroadcastAPIHook } from "../utils/broadcast"; 7 | import { useSignTypedData } from "../utils/sign"; 8 | 9 | export const useMirror = ( 10 | profileId: string | undefined, 11 | publicationId: string | undefined, 12 | onFunctions?: OnFunctions, 13 | ): { mirror: () => void; loading: boolean; error: Error | null } => { 14 | const dispatch = useProfileHasDispatcher(profileId); 15 | const [createMirrorTypedData, { data: mirrorTypedData }] = useCreateMirrorTypedData(profileId, publicationId); 16 | 17 | const [createMirrorViaDispatcher, { data: mirrorViaDispatcher }] = useCreateMirrorViaDispatcher( 18 | profileId, 19 | publicationId, 20 | ); 21 | 22 | const signReturn = useSignTypedData(mirrorTypedData?.createMirrorTypedData?.typedData); 23 | 24 | const { 25 | start: mirror, 26 | loading, 27 | error, 28 | } = useBroadcastAPIHook( 29 | mirrorTypedData?.createMirrorTypedData?.id, 30 | mirrorViaDispatcher?.createMirrorViaDispatcher, 31 | signReturn, 32 | onFunctions, 33 | ); 34 | 35 | useEffect(() => { 36 | if (loading) { 37 | if (dispatch) { 38 | createMirrorViaDispatcher().catch(console.error); 39 | } else { 40 | createMirrorTypedData().catch(console.error); 41 | } 42 | } 43 | }, [profileId, publicationId, loading]); 44 | 45 | return { mirror, loading, error }; 46 | }; 47 | -------------------------------------------------------------------------------- /src/hooks/combined/post.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | 3 | import { OnFunctions } from "../../types/on"; 4 | import { publicationIdFromReceipt } from "../../utils/tx"; 5 | import { useCreatePostTypedData, useCreatePostViaDispatcher } from "../api/post"; 6 | import { useProfileHasDispatcher } from "../api/profile"; 7 | import { useBroadcastAPIHook } from "../utils/broadcast"; 8 | import { useSignTypedData } from "../utils/sign"; 9 | 10 | export const usePost = ( 11 | profileId: string | undefined, 12 | postURL: string | undefined, 13 | { onBroadcasted, onCompleted }: OnFunctions = { onBroadcasted: undefined, onCompleted: undefined }, 14 | ): { 15 | post: () => void; 16 | loading: boolean; 17 | error: Error | null; 18 | publicationId: string | undefined; 19 | } => { 20 | const dispatch = useProfileHasDispatcher(profileId); 21 | 22 | const [publicationId, setPublicationId] = useState(undefined); 23 | 24 | const [createPostTypedData, { data: postTypedData, reset: resetTypedData }] = useCreatePostTypedData( 25 | profileId, 26 | postURL, 27 | { 28 | freeCollectModule: { 29 | followerOnly: false, 30 | }, 31 | }, 32 | ); 33 | 34 | const [createPostViaDispatcher, { data: postViaDispatcher, reset: resetViaDispatcher }] = useCreatePostViaDispatcher( 35 | profileId, 36 | postURL, 37 | { 38 | freeCollectModule: { 39 | followerOnly: false, 40 | }, 41 | }, 42 | ); 43 | 44 | const signReturn = useSignTypedData(postTypedData?.createPostTypedData?.typedData); 45 | 46 | const { 47 | start: post, 48 | loading, 49 | error, 50 | } = useBroadcastAPIHook( 51 | postTypedData?.createPostTypedData?.id, 52 | postViaDispatcher?.createPostViaDispatcher, 53 | signReturn, 54 | { 55 | onCompleted(receipt) { 56 | const parsedPublicationId = publicationIdFromReceipt(receipt); 57 | setPublicationId(parsedPublicationId); 58 | onCompleted?.(receipt); 59 | }, 60 | onBroadcasted, 61 | }, 62 | ); 63 | 64 | useEffect(() => { 65 | resetTypedData(); 66 | resetViaDispatcher(); 67 | }, [postURL]); 68 | 69 | useEffect(() => { 70 | if (loading && postURL) { 71 | if (dispatch) { 72 | createPostViaDispatcher().catch(console.error); 73 | } else { 74 | createPostTypedData().catch(console.error); 75 | } 76 | } 77 | }, [postURL, loading]); 78 | 79 | return { post, loading, error, publicationId }; 80 | }; 81 | -------------------------------------------------------------------------------- /src/hooks/contract/collect.ts: -------------------------------------------------------------------------------- 1 | import { useContractWrite, usePrepareContractWrite } from "wagmi"; 2 | 3 | import LensHubAbi from "../../assets/abi/lenshub.json"; 4 | import { useLensHubAddress } from "../../context/LensContext"; 5 | import { ContractReturn } from "."; 6 | 7 | export const useContractCollect = (profileId?: string, pubId?: string, dataBytes?: string): ContractReturn => { 8 | const addressOrName = useLensHubAddress(); 9 | 10 | const { config, error: prepareError } = usePrepareContractWrite({ 11 | addressOrName, 12 | contractInterface: LensHubAbi, 13 | functionName: "collect", 14 | args: [profileId, pubId, dataBytes], 15 | enabled: profileId !== undefined && pubId !== undefined, 16 | }); 17 | 18 | const { write, data, error: writeError, status } = useContractWrite(config); 19 | 20 | return { write, data, prepareError, writeError, status }; 21 | }; 22 | -------------------------------------------------------------------------------- /src/hooks/contract/comment.ts: -------------------------------------------------------------------------------- 1 | import { useContractWrite, usePrepareContractWrite } from "wagmi"; 2 | 3 | import LensHubAbi from "../../assets/abi/lenshub.json"; 4 | import { useLensHubAddress } from "../../context/LensContext"; 5 | import { ContractReturn } from "."; 6 | 7 | export const useContractComment = ( 8 | profileId?: string, 9 | contentURI?: string, 10 | profileIdPointed?: string, 11 | pubIdPointed?: string, 12 | collectModule?: string, 13 | collectModuleInitData?: string, 14 | referenceModule?: string, 15 | referenceModuleInitData?: string, 16 | referenceModuleData?: string, 17 | ): ContractReturn => { 18 | const addressOrName = useLensHubAddress(); 19 | 20 | const { config, error: prepareError } = usePrepareContractWrite({ 21 | addressOrName, 22 | contractInterface: LensHubAbi, 23 | functionName: "comment", 24 | args: [ 25 | { 26 | profileId, 27 | contentURI, 28 | profileIdPointed, 29 | pubIdPointed, 30 | collectModule, 31 | collectModuleInitData, 32 | referenceModule, 33 | referenceModuleInitData, 34 | referenceModuleData, 35 | }, 36 | ], 37 | enabled: 38 | profileId !== undefined && 39 | contentURI !== undefined && 40 | profileIdPointed !== undefined && 41 | pubIdPointed !== undefined && 42 | collectModule !== undefined && 43 | collectModuleInitData !== undefined && 44 | referenceModule !== undefined && 45 | referenceModuleInitData !== undefined && 46 | referenceModuleData !== undefined, 47 | }); 48 | 49 | const { write, data, error: writeError, status } = useContractWrite(config); 50 | 51 | return { write, data, prepareError, writeError, status }; 52 | }; 53 | -------------------------------------------------------------------------------- /src/hooks/contract/follow.ts: -------------------------------------------------------------------------------- 1 | import { useContractWrite, usePrepareContractWrite } from "wagmi"; 2 | 3 | import FollowNFTAbi from "../../assets/abi/follow-nft.json"; 4 | import LensHubAbi from "../../assets/abi/lenshub.json"; 5 | import { useLensHubAddress } from "../../context/LensContext"; 6 | import { ContractReturn } from "."; 7 | 8 | export const useContractFollow = (profileIds?: string[], datas?: string[]): ContractReturn => { 9 | const addressOrName = useLensHubAddress(); 10 | 11 | const { config, error: prepareError } = usePrepareContractWrite({ 12 | addressOrName, 13 | contractInterface: LensHubAbi, 14 | functionName: "follow", 15 | args: [profileIds, datas], 16 | enabled: profileIds !== undefined && profileIds.length > 0 && datas !== undefined && datas.length > 0, 17 | }); 18 | 19 | const { write, data, error: writeError, status } = useContractWrite(config); 20 | 21 | return { write, data, prepareError, writeError, status }; 22 | }; 23 | 24 | export const useContractUnfollow = (followNFTAddress?: string, tokenId?: string): ContractReturn => { 25 | const { config, error: prepareError } = usePrepareContractWrite({ 26 | contractInterface: FollowNFTAbi, 27 | addressOrName: followNFTAddress ?? "", 28 | functionName: "burn", 29 | args: [tokenId], 30 | enabled: followNFTAddress !== undefined && tokenId !== undefined, 31 | }); 32 | 33 | const { write, data, error: writeError, status } = useContractWrite(config); 34 | 35 | return { write, data, prepareError, writeError, status }; 36 | }; 37 | -------------------------------------------------------------------------------- /src/hooks/contract/index.ts: -------------------------------------------------------------------------------- 1 | import { useContractWrite, useSignTypedData } from "wagmi"; 2 | 3 | export interface ContractReturn { 4 | data: import("@wagmi/core").SendTransactionResult | undefined; 5 | status: ReturnType["status"]; 6 | prepareError: Error | null; 7 | writeError: Error | null; 8 | write: ReturnType["write"]; 9 | } 10 | 11 | export interface SignReturn { 12 | data: string | undefined; 13 | status: ReturnType["status"]; 14 | error: Error | null; 15 | signTypedData: ReturnType["signTypedData"]; 16 | } 17 | -------------------------------------------------------------------------------- /src/hooks/contract/mirror.ts: -------------------------------------------------------------------------------- 1 | import { useContractWrite, usePrepareContractWrite } from "wagmi"; 2 | 3 | import LensHubAbi from "../../assets/abi/lenshub.json"; 4 | import { useLensHubAddress } from "../../context/LensContext"; 5 | import { ContractReturn } from "."; 6 | 7 | export const useContractMirror = ( 8 | profileId?: string, 9 | profileIdPointed?: string, 10 | pubIdPointed?: string, 11 | referenceModuleData?: string, 12 | referenceModule?: string, 13 | referenceModuleInitData?: string, 14 | ): ContractReturn => { 15 | const addressOrName = useLensHubAddress(); 16 | 17 | const { config, error: prepareError } = usePrepareContractWrite({ 18 | addressOrName, 19 | contractInterface: LensHubAbi, 20 | functionName: "mirror", 21 | args: [ 22 | { profileId, profileIdPointed, pubIdPointed, referenceModuleData, referenceModule, referenceModuleInitData }, 23 | ], 24 | enabled: 25 | profileId !== undefined && 26 | profileIdPointed !== undefined && 27 | pubIdPointed !== undefined && 28 | referenceModuleData !== undefined && 29 | referenceModule !== undefined && 30 | referenceModuleInitData !== undefined, 31 | }); 32 | 33 | const { write, data, error: writeError, status } = useContractWrite(config); 34 | 35 | return { write, data, prepareError, writeError, status }; 36 | }; 37 | -------------------------------------------------------------------------------- /src/hooks/contract/post.ts: -------------------------------------------------------------------------------- 1 | import { useContractWrite, usePrepareContractWrite } from "wagmi"; 2 | 3 | import LensHubAbi from "../../assets/abi/lenshub.json"; 4 | import { useLensHubAddress } from "../../context/LensContext"; 5 | import { ContractReturn } from "."; 6 | 7 | export const useContractPost = ( 8 | profileId?: string, 9 | contentURI?: string, 10 | collectModule?: string, 11 | collectModuleInitData?: string, 12 | referenceModule?: string, 13 | referenceModuleInitData?: string, 14 | ): ContractReturn => { 15 | const addressOrName = useLensHubAddress(); 16 | 17 | const { config, error: prepareError } = usePrepareContractWrite({ 18 | addressOrName, 19 | contractInterface: LensHubAbi, 20 | functionName: "post", 21 | args: [ 22 | { 23 | profileId, 24 | contentURI, 25 | collectModule, 26 | collectModuleInitData, 27 | referenceModule, 28 | referenceModuleInitData, 29 | }, 30 | ], 31 | enabled: 32 | profileId !== undefined && 33 | contentURI !== undefined && 34 | collectModule !== undefined && 35 | collectModuleInitData !== undefined && 36 | referenceModule !== undefined && 37 | referenceModuleInitData !== undefined, 38 | }); 39 | 40 | const { write, data, error: writeError, status } = useContractWrite(config); 41 | 42 | return { write, data, prepareError, writeError, status }; 43 | }; 44 | -------------------------------------------------------------------------------- /src/hooks/contract/profile.ts: -------------------------------------------------------------------------------- 1 | import { useContractRead } from "wagmi"; 2 | 3 | import LensHubAbi from "../../assets/abi/lenshub.json"; 4 | import { useLensHubAddress } from "../../context/LensContext"; 5 | 6 | export const useContractProfile = (profileId?: string): ReturnType => { 7 | const addressOrName = useLensHubAddress(); 8 | 9 | return useContractRead({ 10 | addressOrName, 11 | contractInterface: LensHubAbi, 12 | functionName: "getProfile", 13 | args: [profileId], 14 | enabled: profileId !== undefined, 15 | }); 16 | }; 17 | -------------------------------------------------------------------------------- /src/hooks/utils/broadcast.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | 3 | import { OnFunctions } from "../../types/on"; 4 | import { FailedBroadcast, SuccessfulBroadcast, useBroadcast, wasSuccessfulBroadcast } from "../api/broadcast"; 5 | import { useIndexed } from "../api/indexer"; 6 | import { SignReturn } from "../contract"; 7 | 8 | export const useBroadcastAPIHook = ( 9 | id: string | undefined, 10 | dispatchBroadcast: SuccessfulBroadcast | FailedBroadcast | undefined, 11 | { signTypedData, error: signError, data, status }: SignReturn, 12 | { onBroadcasted, onCompleted }: OnFunctions = { onBroadcasted: undefined, onCompleted: undefined }, 13 | ): { start: () => void; loading: boolean; error: Error | null } => { 14 | const [loading, setLoading] = useState(false); 15 | const [writing, setWriting] = useState(false); 16 | const [broadcasting, setBroadcasting] = useState(false); 17 | const [error, setError] = useState(null); 18 | const [txId, setTxId] = useState(); 19 | 20 | const [broadcast, { data: broadcastData }] = useBroadcast(id, data); 21 | 22 | const { data: indexedData } = useIndexed(txId, broadcasting); 23 | 24 | useEffect(() => { 25 | if (loading && !writing && id && signTypedData) { 26 | setWriting(true); 27 | signTypedData(); 28 | } 29 | }, [signTypedData, loading, id]); 30 | 31 | useEffect(() => { 32 | if (status === "error") { 33 | setError(signError); 34 | } 35 | }, [signError]); 36 | 37 | useEffect(() => { 38 | if (status === "error") { 39 | setLoading(false); 40 | setWriting(false); 41 | setBroadcasting(false); 42 | } 43 | }, [status]); 44 | 45 | useEffect(() => { 46 | if (!broadcasting) { 47 | if (dispatchBroadcast && wasSuccessfulBroadcast(dispatchBroadcast)) { 48 | setBroadcasting(true); 49 | setTxId(dispatchBroadcast.txId); 50 | } else if (id && data) { 51 | setBroadcasting(true); 52 | broadcast().catch(console.error); 53 | } 54 | } 55 | }, [id, data, dispatchBroadcast]); 56 | 57 | useEffect(() => { 58 | if (broadcastData?.broadcast && broadcasting) { 59 | if (wasSuccessfulBroadcast(broadcastData.broadcast)) { 60 | setTxId(broadcastData.broadcast.txId); 61 | } else { 62 | setBroadcasting(false); 63 | setLoading(false); 64 | setWriting(false); 65 | setError(new Error(broadcastData.broadcast.reason)); 66 | onCompleted?.(); 67 | } 68 | } 69 | }, [broadcastData]); 70 | 71 | useEffect(() => { 72 | if (txId && broadcasting) { 73 | if (indexedData?.hasTxHashBeenIndexed?.txReceipt) { 74 | onBroadcasted?.(indexedData?.hasTxHashBeenIndexed?.txReceipt); 75 | } 76 | 77 | if (indexedData?.hasTxHashBeenIndexed?.indexed) { 78 | setBroadcasting(false); 79 | setLoading(false); 80 | setWriting(false); 81 | if (indexedData?.hasTxHashBeenIndexed?.metadataStatus?.status === "METADATA_VALIDATION_FAILED") { 82 | setError(new Error(indexedData.hasTxHashBeenIndexed.metadataStatus.reason)); 83 | } else { 84 | onCompleted?.(indexedData.hasTxHashBeenIndexed.txReceipt); 85 | } 86 | } 87 | } 88 | }, [indexedData]); 89 | 90 | const start = (): void => { 91 | setLoading(true); 92 | }; 93 | 94 | return { start, loading, error }; 95 | }; 96 | -------------------------------------------------------------------------------- /src/hooks/utils/contract.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | 3 | import { ContractReturn } from "../contract"; 4 | 5 | export const useContractAPIHook = ( 6 | { write, writeError, prepareError, data, status }: ContractReturn, 7 | onCompleted?: (hash?: string) => void, 8 | ): { start: () => void; loading: boolean; error: Error | null } => { 9 | const [loading, setLoading] = useState(false); 10 | const [writing, setWriting] = useState(false); 11 | const [error, setError] = useState(null); 12 | 13 | useEffect(() => { 14 | if (loading && !writing && write) { 15 | setWriting(true); 16 | write(); 17 | } 18 | }, [write, loading]); 19 | 20 | useEffect(() => { 21 | if (status === "error") { 22 | setError(writeError); 23 | } 24 | }, [writeError]); 25 | 26 | useEffect(() => { 27 | if (status === "error") { 28 | setError(prepareError); 29 | } 30 | }, [prepareError]); 31 | 32 | useEffect(() => { 33 | if (status === "error") { 34 | setLoading(false); 35 | setWriting(false); 36 | } 37 | }, [status]); 38 | 39 | useEffect(() => { 40 | data 41 | ?.wait(1) 42 | .then((receipt) => { 43 | setLoading(false); 44 | setWriting(false); 45 | onCompleted?.(receipt.transactionHash); 46 | }) 47 | .catch((error) => { 48 | setLoading(false); 49 | setWriting(false); 50 | setError(error); 51 | onCompleted?.(); 52 | }); 53 | }, [data]); 54 | 55 | const start = (): void => { 56 | setLoading(true); 57 | }; 58 | 59 | return { start, loading, error }; 60 | }; 61 | -------------------------------------------------------------------------------- /src/hooks/utils/sign.ts: -------------------------------------------------------------------------------- 1 | import { useSignTypedData as useSignTypedDataWagmi } from "wagmi"; 2 | 3 | import { TypedData } from "../../types/lens"; 4 | import { omitDeep } from "../../utils/omit-deep"; 5 | import { SignReturn } from "../contract"; 6 | 7 | export const useSignTypedData = (toSign: TypedData | undefined): SignReturn => { 8 | return useSignTypedDataWagmi({ 9 | domain: omitDeep(toSign?.domain, "__typename"), 10 | types: omitDeep(toSign?.types, "__typename"), 11 | value: omitDeep(toSign?.value, "__typename"), 12 | }); 13 | }; 14 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { useAuthenticate, useChallenge, useRefresh } from "./hooks/api/login"; 2 | import { 3 | useDefaultProfile, 4 | useProfile, 5 | useProfileHasDispatcher, 6 | useProfilePicture, 7 | useProfiles, 8 | } from "./hooks/api/profile"; 9 | import { usePublication, usePublicationComments, usePublications } from "./hooks/api/publication"; 10 | import { useSearch } from "./hooks/api/search"; 11 | import { useCollect } from "./hooks/combined/collect"; 12 | import { useComment } from "./hooks/combined/comment"; 13 | import { useFollow, useUnfollow } from "./hooks/combined/follow"; 14 | import { useMirror } from "./hooks/combined/mirror"; 15 | import { usePost } from "./hooks/combined/post"; 16 | import { useContractCollect } from "./hooks/contract/collect"; 17 | import { useContractComment } from "./hooks/contract/comment"; 18 | import { useContractFollow, useContractUnfollow } from "./hooks/contract/follow"; 19 | import { useContractMirror } from "./hooks/contract/mirror"; 20 | import { useContractPost } from "./hooks/contract/post"; 21 | import { useContractProfile } from "./hooks/contract/profile"; 22 | import { PublicationType } from "./types/lens"; 23 | 24 | export { 25 | PublicationType, 26 | useAuthenticate, 27 | useChallenge, 28 | useCollect, 29 | useComment, 30 | useContractCollect, 31 | useContractComment, 32 | useContractFollow, 33 | useContractMirror, 34 | useContractPost, 35 | useContractProfile, 36 | useContractUnfollow, 37 | useDefaultProfile, 38 | useFollow, 39 | useMirror, 40 | usePost, 41 | useProfile, 42 | useProfileHasDispatcher, 43 | useProfilePicture, 44 | useProfiles, 45 | usePublication, 46 | usePublicationComments, 47 | usePublications, 48 | useRefresh, 49 | useSearch, 50 | useUnfollow, 51 | }; 52 | -------------------------------------------------------------------------------- /src/types/error.ts: -------------------------------------------------------------------------------- 1 | export type MetamaskError = Error & { 2 | code: "ACTION_REJECTED"; 3 | reason: string; 4 | }; 5 | 6 | export enum RelayErrorReasons { 7 | REJECTED = "REJECTED", 8 | EXPIRED = "EXPIRED", 9 | WRONG_WALLET_SIGNED = "WRONG_WALLET_SIGNED", 10 | NOT_ALLOWED = "NOT_ALLOWED", 11 | } 12 | -------------------------------------------------------------------------------- /src/types/lens.ts: -------------------------------------------------------------------------------- 1 | import { MetadataResponse } from "./metadata"; 2 | 3 | export interface Profile { 4 | profileId: string; 5 | name?: string; 6 | handle: string; 7 | picture?: { 8 | original?: { 9 | url?: string; 10 | }; 11 | }; 12 | ownedBy: string; 13 | isFollowedByMe?: boolean; 14 | stats: { 15 | totalFollowers: number; 16 | totalFollowing: number; 17 | totalPosts: number; 18 | totalComments: number; 19 | totalMirrors: number; 20 | totalPublications: number; 21 | totalCollects: number; 22 | }; 23 | } 24 | 25 | export interface DefaultProfile extends Omit { 26 | id: string; 27 | } 28 | 29 | export enum PublicationSortCriteria { 30 | TOP_COMMENTED = "TOP_COMMENTED", 31 | TOP_COLLECTED = "TOP_COLLECTED", 32 | TOP_MIRRORED = "TOP_MIRRORED", 33 | CURATED_PROFILES = "CURATED_PROFILES", 34 | LATEST = "LATEST", 35 | } 36 | 37 | export enum PublicationType { 38 | POST = "POST", 39 | COMMENT = "COMMENT", 40 | MIRROR = "MIRROR", 41 | } 42 | 43 | export enum TimelineTypes { 44 | POST = "POST", 45 | COMMENT = "COMMENT", 46 | MIRROR = "MIRROR", 47 | COLLECT_POST = "COLLECT_POST", 48 | COLLECT_COMMENT = "COLLECT_COMMENT", 49 | } 50 | 51 | // Relevant data from a post 52 | export interface Post { 53 | id: string; 54 | profile: Profile; 55 | stats: { 56 | totalAmountOfMirrors: number; 57 | totalAmountOfCollects: number; 58 | totalAmountOfComments: number; 59 | }; 60 | metadata: MetadataResponse; 61 | createdAt: string; 62 | collectedBy: { 63 | address: string; 64 | }; 65 | hasCollectedByMe?: boolean; 66 | mirrors?: string[]; 67 | mirrorOf?: Post; 68 | appId?: string; 69 | } 70 | 71 | export interface PostWithMedia extends Post { 72 | metadata: MetadataResponse; 73 | } 74 | 75 | export function postHasMedia(post: Post): post is PostWithMedia { 76 | return (post as PostWithMedia).metadata.media !== undefined && (post as PostWithMedia).metadata.media.length > 0; 77 | } 78 | 79 | export interface PageInfo { 80 | prev: string; 81 | next: string; 82 | totalCount: number; 83 | } 84 | 85 | export interface TypedData { 86 | types: any; 87 | domain: any; 88 | value: any; 89 | } 90 | 91 | export interface TypedDataResponse { 92 | id: string; 93 | expiresAt: string; 94 | typedData: TypedData; 95 | } 96 | -------------------------------------------------------------------------------- /src/types/metadata.ts: -------------------------------------------------------------------------------- 1 | export interface PublicationMetadataMedia { 2 | item: string; 3 | /** 4 | * This is the mime type of media 5 | */ 6 | type?: string | null; 7 | 8 | /** 9 | * The alt tags for accessibility 10 | */ 11 | altTag?: string | null; 12 | 13 | /** 14 | * The cover for any video or audio you attached 15 | */ 16 | cover?: string | null; 17 | } 18 | 19 | export enum PublicationMetadataVersions { 20 | one = "1.0.0", 21 | // please use metadata v2 when doing anything! v1 is supported but discontinued. 22 | two = "2.0.0", 23 | } 24 | 25 | export enum PublicationMetadataDisplayType { 26 | number = "number", 27 | string = "string", 28 | date = "date", 29 | } 30 | 31 | export interface PublicationMetadataAttribute { 32 | displayType?: PublicationMetadataDisplayType | undefined | null; 33 | traitType?: string | undefined | null; 34 | value: string; 35 | } 36 | 37 | export enum PublicationContentWarning { 38 | NSFW = "NSFW", 39 | SENSITIVE = "SENSITIVE", 40 | SPOILER = "SPOILER", 41 | } 42 | 43 | export enum PublicationMainFocus { 44 | VIDEO = "VIDEO", 45 | IMAGE = "IMAGE", 46 | ARTICLE = "ARTICLE", 47 | TEXT_ONLY = "TEXT_ONLY", 48 | AUDIO = "AUDIO", 49 | LINK = "LINK", 50 | EMBED = "EMBED", 51 | } 52 | 53 | export interface Metadata { 54 | /** 55 | * The metadata version. 56 | */ 57 | version: PublicationMetadataVersions; 58 | 59 | /** 60 | * The metadata lens_id can be anything but if your uploading to ipfs 61 | * you will want it to be random.. using uuid could be an option! 62 | */ 63 | metadata_id: string; 64 | 65 | /** 66 | * A human-readable description of the item. Can be markdown. 67 | */ 68 | description?: string | undefined | null; 69 | 70 | /** 71 | * The content of a publication. Can be markdown. If this is blank `media` must be defined or its out of spec. 72 | */ 73 | content?: string | undefined | null; 74 | 75 | /** 76 | * IOS 639-1 language code aka en or it and ISO 3166-1 alpha-2 region code aka US or IT aka en-US or it-IT 77 | * Full spec > https://tools.ietf.org/search/bcp47 78 | */ 79 | locale: string; 80 | 81 | /** 82 | * Ability to tag your publication 83 | */ 84 | tags?: string[] | undefined | null; 85 | 86 | /** 87 | * Ability to add a content warning 88 | */ 89 | contentWarning?: PublicationContentWarning | undefined | null; 90 | 91 | /** 92 | * Main content focus that for this publication 93 | */ 94 | mainContentFocus: PublicationMainFocus; 95 | 96 | /** 97 | * This is the URL that will appear below the asset's image on OpenSea and others etc 98 | * and will allow users to leave OpenSea and view the item on the site. 99 | */ 100 | external_url?: string | undefined | null; 101 | 102 | /** 103 | * Name of the item. 104 | */ 105 | name: string; 106 | 107 | /** 108 | * These are the attributes for the item, which will show up on the OpenSea and others NFT trading websites on the 109 | item. 110 | */ 111 | attributes: PublicationMetadataAttribute[]; 112 | 113 | /** 114 | * legacy to support OpenSea will store any NFT image here. 115 | */ 116 | image?: string | undefined | null; 117 | 118 | /** 119 | * This is the mime type of image. This is used if you uploading more advanced cover images 120 | * as sometimes IPFS does not emit the content header so this solves the pr 121 | */ 122 | imageMimeType?: string | undefined | null; 123 | 124 | /** 125 | * This is lens supported attached media items to the publication 126 | */ 127 | media?: PublicationMetadataMedia[] | undefined | null; 128 | 129 | /** 130 | * In spec for OpenSea and other providers - also used when using EMBED main publication focus 131 | * A URL to a multi-media attachment for the item. The file extensions GLTF, GLB, WEBM, MP4, M4V, OGV, 132 | * and OGG are supported, along with the audio-only extensions MP3, WAV, and OGA. 133 | * Animation_url also supports HTML pages, allowing you to build rich experiences and interactive NFTs using JavaScript canvas, 134 | * WebGL, and more. Scripts and relative paths within the HTML page are now supported. However, access to browser extensions is not supported. 135 | 136 | */ 137 | animation_url?: string | undefined | null; 138 | 139 | /** 140 | * This is the appId the content belongs to 141 | */ 142 | appId?: string | undefined | null; 143 | } 144 | 145 | // Media object returned from Lens API is different than what is submitted 146 | export interface MetadataResponse extends Omit { 147 | media: Array<{ 148 | original: { 149 | url?: string; 150 | width?: number; 151 | height?: number; 152 | mimeType?: string; 153 | }; 154 | }>; 155 | } 156 | -------------------------------------------------------------------------------- /src/types/modules.ts: -------------------------------------------------------------------------------- 1 | export interface CollectModule { 2 | freeCollectModule?: { 3 | followerOnly: boolean; 4 | }; 5 | feeCollectModule?: { 6 | amount: { 7 | currency: string; 8 | value: string; 9 | }; 10 | recipient: string; 11 | referralFee: number; 12 | followerOnly: boolean; 13 | }; 14 | } 15 | 16 | export interface ReferenceModule { 17 | followerOnlyReferenceModule: boolean; 18 | } 19 | -------------------------------------------------------------------------------- /src/types/on.ts: -------------------------------------------------------------------------------- 1 | import { TransactionReceipt } from "@ethersproject/abstract-provider"; 2 | 3 | export type OnBroadcastedFunction = ((receipt: TransactionReceipt) => void) | undefined; 4 | export type OnCompletedFunction = ((receipt?: TransactionReceipt) => void) | undefined; 5 | 6 | export interface OnFunctions { 7 | onBroadcasted?: OnBroadcastedFunction; 8 | onCompleted?: OnCompletedFunction; 9 | } 10 | -------------------------------------------------------------------------------- /src/utils/omit-deep.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | function has(obj: any, prop: any): boolean { 3 | return Function.prototype.bind.call(Function.call, Object.prototype.hasOwnProperty)(obj, prop); 4 | } 5 | 6 | function isUnsafeKey(key: any) { 7 | return key === "__proto__" || key === "constructor" || key === "prototype"; 8 | } 9 | 10 | function validateKey(key: any) { 11 | if (isUnsafeKey(key)) { 12 | throw new Error(`Cannot set unsafe key: "${key}"`); 13 | } 14 | } 15 | 16 | function unset(obj: any, prop: any) { 17 | if (!isObject(obj)) { 18 | throw new TypeError("expected an object."); 19 | } 20 | 21 | var isArray = Array.isArray(prop); 22 | 23 | if (!isArray && obj.hasOwnProperty(prop)) { 24 | delete obj[prop]; 25 | return true; 26 | } 27 | 28 | if (has(obj, prop)) { 29 | var segs = isArray ? prop.slice() : prop.split("."); 30 | var last = segs.pop(); 31 | while (segs.length && segs[segs.length - 1].slice(-1) === "\\") { 32 | last = segs.pop().slice(0, -1) + "." + last; 33 | } 34 | while (segs.length) { 35 | prop = segs.shift(); 36 | validateKey(prop); 37 | obj = obj[prop]; 38 | } 39 | return delete obj[last]; 40 | } 41 | return true; 42 | } 43 | 44 | function isObject(o: any) { 45 | return Object.prototype.toString.call(o) === "[object Object]"; 46 | } 47 | 48 | function isPlainObject(o: any) { 49 | var ctor, prot; 50 | 51 | if (isObject(o) === false) return false; 52 | 53 | // If has modified constructor 54 | ctor = o.constructor; 55 | if (ctor === undefined) return true; 56 | 57 | // If has modified prototype 58 | prot = ctor.prototype; 59 | if (isObject(prot) === false) return false; 60 | 61 | // If constructor does not have an Object-specific method 62 | if (prot.hasOwnProperty("isPrototypeOf") === false) { 63 | return false; 64 | } 65 | 66 | // Most likely a plain Object 67 | return true; 68 | } 69 | 70 | export function omitDeep(value: any, keys: any) { 71 | if (typeof value === "undefined") { 72 | return {}; 73 | } 74 | 75 | if (Array.isArray(value)) { 76 | for (var i = 0; i < value.length; i++) { 77 | value[i] = omitDeep(value[i], keys); 78 | } 79 | return value; 80 | } 81 | 82 | if (!isPlainObject(value)) { 83 | return value; 84 | } 85 | 86 | if (typeof keys === "string") { 87 | keys = [keys]; 88 | } 89 | 90 | if (!Array.isArray(keys)) { 91 | return value; 92 | } 93 | 94 | for (var j = 0; j < keys.length; j++) { 95 | unset(value, keys[j]); 96 | } 97 | 98 | for (var key in value) { 99 | if (value.hasOwnProperty(key)) { 100 | value[key] = omitDeep(value[key], keys); 101 | } 102 | } 103 | 104 | return value; 105 | } 106 | -------------------------------------------------------------------------------- /src/utils/tx.ts: -------------------------------------------------------------------------------- 1 | import { TransactionReceipt } from "@ethersproject/abstract-provider"; 2 | import { ethers } from "ethers"; 3 | 4 | export const publicationIdFromReceipt = (receipt: TransactionReceipt | undefined): string | undefined => { 5 | if (receipt?.logs[0] && receipt.logs[0].topics.length === 3) { 6 | let profileId = ethers.utils.hexStripZeros(receipt?.logs[0].topics[1]); 7 | if (profileId.length % 2 === 1) { 8 | profileId = `${profileId.substring(0, 2)}0${profileId.substring(2)}`; 9 | } 10 | let postId = ethers.utils.hexStripZeros(receipt?.logs[0].topics[2]); 11 | if (postId.length % 2 === 1) { 12 | postId = `${postId.substring(0, 2)}0${postId.substring(2)}`; 13 | } 14 | 15 | return `${profileId}-${postId}`; 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": false, 4 | "allowSyntheticDefaultImports": true, 5 | "declaration": true, 6 | "esModuleInterop": false, 7 | "forceConsistentCasingInFileNames": true, 8 | "isolatedModules": true, 9 | "jsx": "react-jsx", 10 | "lib": ["es2019", "es2017", "dom"], 11 | "module": "commonjs", 12 | "moduleResolution": "node", 13 | "outDir": "dist", 14 | "resolveJsonModule": true, 15 | "skipLibCheck": true, 16 | "strict": true, 17 | "target": "es2021", 18 | "useDefineForClassFields": true 19 | }, 20 | "exclude": ["node_modules", "**/dist/**"], 21 | "include": ["./src/**/*.ts", "./src/**/*.tsx"] 22 | } 23 | --------------------------------------------------------------------------------