> For the complete documentation index, see [llms.txt](https://jayjiang.gitbook.io/web3book/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://jayjiang.gitbook.io/web3book/alchemy-road-to-web3/di-shi-zhou-shi-yong-lens-chuang-jian-yi-ge-qu-zhong-xin-hua-de-tui-te.md).

# 第十周 使用Lens创建一个去中心化的推特

官方资料 https\://docs.alchemy.com/docs/how-to-create-a-decentralized-twitter-with-lens-protocol

关注我的推特(<https://twitter.com/SoullessL>) ，及时获取Alchemy 教程的最新信息。

### 初始化项目

进入<https://replit.com/>，如果没有账号，可以注册一个

![](https://3474605129-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLWLTncuPjdgdA8s2gM6C%2Fuploads%2FoaigvzQxEH7NR79gHt6e%2Fimage.png?alt=media\&token=f6236f08-2728-4dcf-8d99-cf0bd7dd7839)

点击创建一个Node.js的项目

创建成功以后在shell里输入如下代码，其中road-to-lens为你的项目名字，可以随意

```
npx create-next-app road-to-lens
```

![](https://3474605129-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLWLTncuPjdgdA8s2gM6C%2Fuploads%2FVtQtFC1V3pUNHt1QLtba%2Fimage.png?alt=media\&token=0d32436a-0580-4464-a606-40eb22f64cb1)

输入成功以后，提示 'Ok to processed'，输入y，等待下载项目所需的安装包并创建项目。

![](https://3474605129-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLWLTncuPjdgdA8s2gM6C%2Fuploads%2FoTmkfAcyMxPSzr7pJTC8%2Fimage.png?alt=media\&token=55198bc6-ebc3-4c2b-99f1-137c9fbe0c75)

然后我们在Shell里输入 cd road-to-lens 切换到项目所在路径下。

因为我们的项目是在一个子文件夹下面的，所以我们需要修改启动项

![](https://3474605129-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLWLTncuPjdgdA8s2gM6C%2Fuploads%2FS54daejUhPvyNJ6gV0mM%2Fimage.png?alt=media\&token=81ea2cf0-5fe7-4b88-89a5-4362484d2972)

首先显示隐藏文件

![](https://3474605129-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLWLTncuPjdgdA8s2gM6C%2Fuploads%2F00Wp3jHYAHd6KfB5UYNg%2Fimage.png?alt=media\&token=9a1c4e8e-c84f-4d65-a3c8-516d2571eeea)

然后我们打开.replit文件，删除原有内容，然后添加下面的两行内容，其中road-to-lens为你创建项目的名称

```
run = 'npm --prefix ./road-to-lens run dev'
entrypoint = './road-to-lens/pages/index.jsx'
```

![](https://3474605129-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLWLTncuPjdgdA8s2gM6C%2Fuploads%2Fw1wmS3V0BcSyh3tchLYz%2Fimage.png?alt=media\&token=991c80df-ec9a-4d48-aa58-f7923842a8e5)

然后我们点击“Run” 按钮，最终出现如上界面就是项目编译成功

### 代码更新

![](https://3474605129-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLWLTncuPjdgdA8s2gM6C%2Fuploads%2FHpFZZOhmR1OWy0DsfZzU%2Fimage.png?alt=media\&token=dd74cf6f-e09a-4577-8db4-5fc084c206f0)

然后我们回到Shell里，输入命令 npm install @apollo/client graphql 安装graphql包。

![](https://3474605129-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLWLTncuPjdgdA8s2gM6C%2Fuploads%2FBlTh1aeOizZGWV0cjnjV%2Fimage.png?alt=media\&token=754c0c57-1a29-4e29-b1ad-db518f2ed6c7)

然后我们回到road-to-lens文件夹下面，右键Add File，创建一个叫apollo-client.js的文件，并且在文件里面添加以下代码。

```
// ./apollo-client.js

import { ApolloClient, InMemoryCache } from "@apollo/client";

const client = new ApolloClient({
    uri: "https://api.lens.dev",
    cache: new InMemoryCache(),
});

export default client;
```

![](https://3474605129-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLWLTncuPjdgdA8s2gM6C%2Fuploads%2F1XYNDUvdujmBzNw3FqKQ%2Fimage.png?alt=media\&token=f1a96a3a-595d-4d8b-bf12-46d42258eb33)

然后我们找到pages/\_app.js文件，用以下代码替换文件内容

```
// pages/_app.js

import '../styles/globals.css'
import { ApolloProvider } from "@apollo/client";
import client from "../apollo-client";

function MyApp({ Component, pageProps }) {
  return (
    <ApolloProvider client={client}>
      <Component {...pageProps} />
    </ApolloProvider>
  );
}

export default MyApp
```

再找到pages/index.js，用以下代码替换文件内容

```
import { useQuery, gql } from "@apollo/client";

const recommendProfiles = gql`
  query RecommendedProfiles {
    recommendedProfiles {
          id
        name
        bio
        attributes {
          displayType
          traitType
          key
          value
        }
          followNftAddress
        metadata
        isDefault
        picture {
          ... on NftImage {
            contractAddress
            tokenId
            uri
            verified
          }
          ... on MediaSet {
            original {
              url
              mimeType
            }
          }
          __typename
        }
        handle
        coverPicture {
          ... on NftImage {
            contractAddress
            tokenId
            uri
            verified
          }
          ... on MediaSet {
            original {
              url
              mimeType
            }
          }
          __typename
        }
        ownedBy
        dispatcher {
          address
          canUseRelay
        }
        stats {
          totalFollowers
          totalFollowing
          totalPosts
          totalComments
          totalMirrors
          totalPublications
          totalCollects
        }
        followModule {
          ... on FeeFollowModuleSettings {
            type
            amount {
              asset {
                symbol
                name
                decimals
                address
              }
              value
            }
            recipient
          }
          ... on ProfileFollowModuleSettings {
          type
          }
          ... on RevertFollowModuleSettings {
          type
          }
        }
    }
  }
`;

export default function Home() {
  const {loading, error, data} = useQuery(recommendProfiles);

  if (loading) return 'Loading..';
  if (error) return `Error! ${error.message}`;

  return (
    <div>
      Hello
      {data.recommendedProfiles.map((profile, index) => {
        console.log(`Profile ${index}:`, profile);
        return (
          <div>
            <h1>{profile.name}</h1>
            <p>{profile.bio}</p>
            <div>{profile.attributes.map((attr, idx) => {
              if (attr.key === "website") {
                return <div><a href={`${attr.value}`}>{attr.value}</a><br/></div>
              } else if (attr.key === "twitter") {
                return <div><a href={`https://twitter.com/${attr.value}`}>@{attr.value}</a><br/></div>;
              }
              return(<div>{attr.value}</div>);
            })}</div>
          </div>
        );
      })}
    </div>
  )
}
```

![](https://3474605129-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLWLTncuPjdgdA8s2gM6C%2Fuploads%2FbNPdf9LgpMKMiCwxFFea%2Fimage.png?alt=media\&token=fc6ec6b9-8184-459c-a742-9e9671f02aca)

然后我们回到road-to-lens下面，新建一个queries文件夹，并在下面新建一个recommendedProfilesQuery.js文件，然后在recommendedProfilesQuery.js下面添加如下代码。

```
// queries/recommendedProfilesQuery.js

import {gql} from '@apollo/client';

export default gql`
  query RecommendedProfiles {
    recommendedProfiles {
          id
        name
        bio
        attributes {
          displayType
          traitType
          key
          value
        }
          followNftAddress
        metadata
        isDefault
        picture {
          ... on NftImage {
            contractAddress
            tokenId
            uri
            verified
          }
          ... on MediaSet {
            original {
              url
              mimeType
            }
          }
          __typename
        }
        handle
        coverPicture {
          ... on NftImage {
            contractAddress
            tokenId
            uri
            verified
          }
          ... on MediaSet {
            original {
              url
              mimeType
            }
          }
          __typename
        }
        ownedBy
        dispatcher {
          address
          canUseRelay
        }
        stats {
          totalFollowers
          totalFollowing
          totalPosts
          totalComments
          totalMirrors
          totalPublications
          totalCollects
        }
        followModule {
          ... on FeeFollowModuleSettings {
            type
            amount {
              asset {
                symbol
                name
                decimals
                address
              }
              value
            }
            recipient
          }
          ... on ProfileFollowModuleSettings {
          type
          }
          ... on RevertFollowModuleSettings {
          type
          }
        }
    }
  }
`;
```

![](https://3474605129-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLWLTncuPjdgdA8s2gM6C%2Fuploads%2FiflzIXSNUXrXwpzTwp9F%2Fimage.png?alt=media\&token=49642af6-e2fd-4d2a-b51b-f111a02c3539)

然后我们在road-to-lens文件夹下面，新建components文件夹，并且在文件夹下面新建一个名为Profile.js的文件，然后把下面的代码复制到文件里。

```
// components/Profile.js

import Link from "next/link";
export default function Profile(props) {
  const profile = props.profile;

  // When displayFullProfile is true, we show more info.
  const displayFullProfile = props.displayFullProfile;

  return (
    <div className="p-8">
      <Link href={`/profile/${profile.id}`}>
        <div className="max-w-md mx-auto bg-white rounded-xl shadow-md overflow-hidden md:max-w-2xl">
          <div className="md:flex">
            <div className="md:shrink-0">
              {profile.picture ? (
                <img
                  src={
                    profile.picture.original
                      ? profile.picture.original.url
                      : profile.picture.uri
                  }
                  className="h-48 w-full object-cover md:h-full md:w-48"
                />
              ) : (
                <div
                  style={{
                    backgrondColor: "gray",
                  }}
                  className="h-48 w-full object-cover md:h-full md:w-48"
                />
              )}
            </div>
            <div className="p-8">
              <div className="uppercase tracking-wide text-sm text-indigo-500 font-semibold">
                {profile.handle}
                {displayFullProfile &&
                  profile.name &&
                  " (" + profile.name + ")"}
              </div>
              <div className="block mt-1 text-sm leading-tight font-medium text-black hover:underline">
                {profile.bio}
              </div>
              <div className="mt-2 text-sm text-slate-900">{profile.ownedBy}</div>
              <p className="mt-2 text-xs text-slate-500">
                following: {profile.stats.totalFollowing} followers:{" "}
                {profile.stats.totalFollowers}
              </p>
            </div>
          </div>
        </div>
      </Link>
    </div>
  );
}
```

然后我们修改pages/index.js文件，把里面的内容替换为如下内容

```
import { useQuery, gql } from "@apollo/client";
import recommendedProfilesQuery from '../queries/recommendedProfilesQuery.js';
import Profile from '../components/Profile.js';

export default function Home() {
  const {loading, error, data} = useQuery(recommendedProfilesQuery);

  if (loading) return 'Loading..';
  if (error) return `Error! ${error.message}`;

  return (
    <div>
      {data.recommendedProfiles?.map((profile, index) => {
        console.log(`Profile ${index}:`, profile);
        return <Profile key={profile.id} profile={profile} displayFullProfile={false} />;
      })}
    </div>
  )
}
```

![](https://3474605129-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLWLTncuPjdgdA8s2gM6C%2Fuploads%2FurO8pTtYFDkfrvogwxtN%2Fimage.png?alt=media\&token=03585b49-19ae-4a5f-9838-8483ea673785)

然后点击页面上面绿色的Run按钮把项目跑起来，预览大概如图所示，会有一些lens的数据，但是还没有样式。

![](https://3474605129-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLWLTncuPjdgdA8s2gM6C%2Fuploads%2FVyRYwjMqRb1jZ4bdB2WY%2Fimage.png?alt=media\&token=565d1ee9-aab2-4d22-95f1-acb8bb5e5c74)

然后我们回到Shell终端，输入下面的命令安装样式库 tailwindcss

```
npm install -D tailwindcss postcss autoprefixer
```

安装完再输入如下命令初始化tailwindcss&#x20;

```
npx tailwindcss init -p
```

![](https://3474605129-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLWLTncuPjdgdA8s2gM6C%2Fuploads%2F97CdPFMQMPoFVXgSUuGf%2Fimage.png?alt=media\&token=dad48161-fa48-46dc-ba64-4f6e3cd09180)

然后我们进入road-to-lens根目录，找到文件 tailwind.config.js，用以下的内容替换文件内容

```
// tailwind.config.js

module.exports = {
  content: [
    "./pages/**/*.{js,ts,jsx,tsx}",
    "./components/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
```

![](https://3474605129-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLWLTncuPjdgdA8s2gM6C%2Fuploads%2FGq4c2tlD8yhUrVjlRq1f%2Fimage.png?alt=media\&token=d68c8f8f-6238-4647-9133-9664bcca9535)

接着我们找到styles/globals.css文件，用以下内容替换文件内容。

```
html,
body {
  padding: 0;
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
    Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
}

a {
  color: inherit;
  text-decoration: none;
}

* {
  box-sizing: border-box;
}

@media (prefers-color-scheme: dark) {
  html {
    color-scheme: dark;
  }
  body {
    color: white;
    background: black;
  }
}
/* ./styles/globals.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
```

![](https://3474605129-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLWLTncuPjdgdA8s2gM6C%2Fuploads%2F9yEYLVLgEMbFiv88r4t6%2Fimage.png?alt=media\&token=245e2b00-749a-4871-9047-ec07d710c861)

然后我们的界面大概是这样的。

![](https://3474605129-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLWLTncuPjdgdA8s2gM6C%2Fuploads%2FVK8wtTsWyaaizCioxf1i%2Fimage.png?alt=media\&token=8227d81d-74a9-4586-a39c-6a00a1096213)

然后我们再pages下面新建一个profile文件夹，然后在下面新建一个\[id].js文件，这个页面用来显示用户的详情页，并在文件里添加如下内容

```
import { useQuery, useMutation } from "@apollo/client";
import { useRouter } from "next/router";
import fetchProfileQuery from "../../queries/fetchProfileQuery.js";
import Profile from "../../components/Profile.js";
import Post from "../../components/Post.js";

export default function ProfilePage() {
  const router = useRouter();
  const { id } = router.query;

  console.log("fetching profile for", id);
  const { loading, error, data } = useQuery(fetchProfileQuery, {
    variables: {
      request: { profileId: id },
      publicationsRequest: {
        profileId: id,
        publicationTypes: ["POST"],
      },
    },
  });

  if (loading) return "Loading..";
  if (error) return `Error! ${error.message}`;

  return (
    <div className="flex flex-col p-8 items-center">
      <Profile profile={data.profile} displayFullProfile={true} />
      {data.publications.items.map((post, idx) => {
        return <Post key={idx} post={post}/>;
      })}
    </div>
  );
}
```

![](https://3474605129-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLWLTncuPjdgdA8s2gM6C%2Fuploads%2FalrrvW5IQKAO8FB6kJRj%2Fimage.png?alt=media\&token=5fe4f752-540a-4ddd-93ed-85b6a79e867b)

然后我们在queries文件夹下面新增文件fetchProfileQuery.js，这个用来获取用户详情数据，并在文件里添加如下内容

```
import { gql } from "@apollo/client";

export default gql`
  query (
    $request: SingleProfileQueryRequest!
    $publicationsRequest: PublicationsQueryRequest!
  ) {
    publications( request: $publicationsRequest) {
      items {
        __typename
        ... on Post {
          ...PostFields
        }
        ... on Comment {
          ...CommentFields
        }
        ... on Mirror {
          ...MirrorFields
        }
      }
      pageInfo {
        prev
        next
        totalCount
      }
    }
    profile(request: $request) {
      id
      name
      bio
      attributes {
        displayType
        traitType
        key
        value
      }
      followNftAddress
      metadata
      isDefault
      picture {
        ... on NftImage {
          contractAddress
          tokenId
          uri
          verified
        }
        ... on MediaSet {
          original {
            url
            mimeType
          }
        }
        __typename
      }
      handle
      coverPicture {
        ... on NftImage {
          contractAddress
          tokenId
          uri
          verified
        }
        ... on MediaSet {
          original {
            url
            mimeType
          }
        }
        __typename
      }
      ownedBy
      dispatcher {
        address
        canUseRelay
      }
      stats {
        totalFollowers
        totalFollowing
        totalPosts
        totalComments
        totalMirrors
        totalPublications
        totalCollects
      }
      followModule {
        ... on FeeFollowModuleSettings {
          type
          amount {
            asset {
              symbol
              name
              decimals
              address
            }
            value
          }
          recipient
        }
        ... on ProfileFollowModuleSettings {
          type
        }
        ... on RevertFollowModuleSettings {
          type
        }
      }
    }
  }

  fragment MediaFields on Media {
    url
    mimeType
  }

  fragment ProfileFields on Profile {
    id
    name
    bio
    attributes {
      displayType
      traitType
      key
      value
    }
    isFollowedByMe
    isFollowing(who: null)
    followNftAddress
    metadata
    isDefault
    handle
    picture {
      ... on NftImage {
        contractAddress
        tokenId
        uri
        verified
      }
      ... on MediaSet {
        original {
          ...MediaFields
        }
      }
    }
    coverPicture {
      ... on NftImage {
        contractAddress
        tokenId
        uri
        verified
      }
      ... on MediaSet {
        original {
          ...MediaFields
        }
      }
    }
    ownedBy
    dispatcher {
      address
    }
    stats {
      totalFollowers
      totalFollowing
      totalPosts
      totalComments
      totalMirrors
      totalPublications
      totalCollects
    }
    followModule {
      ... on FeeFollowModuleSettings {
        type
        amount {
          asset {
            name
            symbol
            decimals
            address
          }
          value
        }
        recipient
      }
      ... on ProfileFollowModuleSettings {
        type
      }
      ... on RevertFollowModuleSettings {
        type
      }
    }
  }

  fragment PublicationStatsFields on PublicationStats {
    totalAmountOfMirrors
    totalAmountOfCollects
    totalAmountOfComments
  }

  fragment MetadataOutputFields on MetadataOutput {
    name
    description
    content
    media {
      original {
        ...MediaFields
      }
    }
    attributes {
      displayType
      traitType
      value
    }
  }

  fragment Erc20Fields on Erc20 {
    name
    symbol
    decimals
    address
  }

  fragment CollectModuleFields on CollectModule {
    __typename
    ... on FreeCollectModuleSettings {
      type
      followerOnly
      contractAddress
    }
    ... on FeeCollectModuleSettings {
      type
      amount {
        asset {
          ...Erc20Fields
        }
        value
      }
      recipient
      referralFee
    }
    ... on LimitedFeeCollectModuleSettings {
      type
      collectLimit
      amount {
        asset {
          ...Erc20Fields
        }
        value
      }
      recipient
      referralFee
    }
    ... on LimitedTimedFeeCollectModuleSettings {
      type
      collectLimit
      amount {
        asset {
          ...Erc20Fields
        }
        value
      }
      recipient
      referralFee
      endTimestamp
    }
    ... on RevertCollectModuleSettings {
      type
    }
    ... on TimedFeeCollectModuleSettings {
      type
      amount {
        asset {
          ...Erc20Fields
        }
        value
      }
      recipient
      referralFee
      endTimestamp
    }
  }

  fragment PostFields on Post {
    id
    profile {
      ...ProfileFields
    }
    stats {
      ...PublicationStatsFields
    }
    metadata {
      ...MetadataOutputFields
    }
    createdAt
    collectModule {
      ...CollectModuleFields
    }
    referenceModule {
      ... on FollowOnlyReferenceModuleSettings {
        type
      }
    }
    appId
    hidden
    mirrors(by: null)
    hasCollectedByMe
  }

  fragment MirrorBaseFields on Mirror {
    id
    profile {
      ...ProfileFields
    }
    stats {
      ...PublicationStatsFields
    }
    metadata {
      ...MetadataOutputFields
    }
    createdAt
    collectModule {
      ...CollectModuleFields
    }
    referenceModule {
      ... on FollowOnlyReferenceModuleSettings {
        type
      }
    }
    appId
    hidden
    hasCollectedByMe
  }

  fragment MirrorFields on Mirror {
    ...MirrorBaseFields
    mirrorOf {
      ... on Post {
        ...PostFields
      }
      ... on Comment {
        ...CommentFields
      }
    }
  }

  fragment CommentBaseFields on Comment {
    id
    profile {
      ...ProfileFields
    }
    stats {
      ...PublicationStatsFields
    }
    metadata {
      ...MetadataOutputFields
    }
    createdAt
    collectModule {
      ...CollectModuleFields
    }
    referenceModule {
      ... on FollowOnlyReferenceModuleSettings {
        type
      }
    }
    appId
    hidden
    mirrors(by: null)
    hasCollectedByMe
  }

  fragment CommentFields on Comment {
    ...CommentBaseFields
    mainPost {
      ... on Post {
        ...PostFields
      }
      ... on Mirror {
        ...MirrorBaseFields
        mirrorOf {
          ... on Post {
            ...PostFields
          }
          ... on Comment {
            ...CommentMirrorOfFields
          }
        }
      }
    }
  }

  fragment CommentMirrorOfFields on Comment {
    ...CommentBaseFields
    mainPost {
      ... on Post {
        ...PostFields
      }
      ... on Mirror {
        ...MirrorBaseFields
      }
    }
  }
`;
```

![](https://3474605129-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLWLTncuPjdgdA8s2gM6C%2Fuploads%2FFIBJGdQXQFhAEuiB83OX%2Fimage.png?alt=media\&token=2af5f474-ce37-4c0b-b8f0-d02093365688)

然后我们在components下面新建一个Post.js，并添加如下内容到文件中。

```
// components/Post.js
export default function Post(props) {
  const post = props.post;

  return (
    <div className="p-8">
      <div className="max-w-md mx-auto bg-white rounded-xl shadow-md overflow-hidden md:max-w-2xl">
        <div className="md:flex">
          <div className="p-8">
            <p className="mt-2 text-xs text-slate-500 whitespace-pre-line">
              {post.metadata.content}
            </p>
          </div>
        </div>
      </div>
    </div>
  );
}
```

![](https://3474605129-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLWLTncuPjdgdA8s2gM6C%2Fuploads%2FFcJSeodmMYfmWdHkN3OJ%2Fimage.png?alt=media\&token=e27000dc-a053-4524-92fc-baec61457719)

如果出现这个界面，则说明我们样式也加好了。有时候因为这个在线版本的开发工具会有点卡，导致界面加载不出来，你可以把网站关了，过个十几分钟再过来试一下，可能就好了。

然后我们点击上面截图里右上角那个按钮，可以重新打开一个窗口来预览我们的项目。

![](https://3474605129-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLWLTncuPjdgdA8s2gM6C%2Fuploads%2FuTnMfyihoJZZhcr4twfG%2Fimage.png?alt=media\&token=e60db93e-388e-4566-a3ca-f3156bc6d8db)

我们可以点击某个lens用户，进入详情页。

![](https://3474605129-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLWLTncuPjdgdA8s2gM6C%2Fuploads%2F4jkubQ5D5GtuNFmYhbTS%2Fimage.png?alt=media\&token=0c124168-603e-42ad-8ff0-92ce084b3954)

### 发布和填表

![](https://3474605129-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLWLTncuPjdgdA8s2gM6C%2Fuploads%2FxR5KDyAwZcVrGR9ZaOec%2Fimage.png?alt=media\&token=9be7a339-974d-4ca8-bf6c-4c0da002e2da)

然后你可以点击publish来把项目发布出去，具体的流程可以参考第四周最后的教程，记住你发布以后的网址，在填表的时候使用。

填表地址 <https://alchemyapi.typeform.com/roadtoweekten> 这个是老地址已经关闭了，不确定以后会不会再开。

另外NFT领取地址等待快照（快照时间不固定），然后上 <https://mintkudos.xyz/> 连接进钱包，进入profile，会有一个to claim菜单，就是可以领取的NFT，如果没有则说明还没有快照。
