まいにちDapps6日目の今日は、トークンゲートの実装について考察したいと思います。「トークンゲート」とは、特定のトークンを保有しているユーザーのみがアクセスできるコンテンツやサービスを提供する仕組みのことを指します。ここでいうトークンはNFTやERC20トークンのことを指します。トークンゲートを用いることで特定のコミュニティやサービスに対するエクスクルーシブなアクセスを提供することができ、これにより新しいビジネスモデルやマネタイゼーション戦略が可能になります。
Thirdweb Auth
まずは自分で実装をしてみる方法ですが、Thirdwebが出している公式記事やそれを和訳したユウキさんの記事が参考になります。
https://blog.thirdweb.com/guides/nft-gated-website/
https://zenn.dev/yuki2020/articles/77f0f452bdbea4
ポイントとしてはgetServersideProps内でNFTの保有確認をしているので、バックエンド側で確認をしているということですね。
// Instantiate our SDK
const sdk = ThirdwebSDK.fromPrivateKey(
process.env.THIRDWEB_AUTH_PRIVATE_KEY,
"mumbai"
);
// Check to see if the user has an NFT
const hasNft = await checkBalance(sdk, user.address);
// If they don't have an NFT, redirect them to the login page
if (!hasNft) {
console.log("User", user.address, "doesn't have an NFT! Redirecting...");
return {
redirect: {
destination: "/login",
permanent: false,
},
};
}
また、注意として上記記事・コードはNext.jsのPagesディレクトリの仕様を想定されていて、appsディレクトリだと期待通りの挙動をしないのでご注意ください。
![Image](/_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2Ffrqcsxz2%2Fproduction%2Ff6803257fde11b765c8b7990a840a5a053eed94b-1712x408.png%3Fw%3D1712%26auto%3Dformat&w=3840&q=75)
Lit Protocol
Lit Protocolは、暗号鍵ペアの作成と管理を分散して行うことで、条件付き暗号化やプログラムによる署名の実現を目的としたプロトコルです。
分散型鍵管理ネットワークとして機能するLit Protocolは、集中型鍵保管サービスや他の鍵管理ソリューションの代わりとして利用できます。
Lit ProtocolのSDKを使ってトークンゲートを作成するチュートリアルがあったので紹介します
https://medium.com/coinmonks/token-gating-with-lit-protocol-b27ef6141696
nextjsのプロジェクトを立ち上げ、必要なモジュールをインストールします。
yarn add @lit-protocol/lit-node-client
yarn add cookies js-cookie uuid
yarn add -D @types/cookies @types/js-cookie @types/uuid
チュートリアルをより簡略化してこのようなコードにしました。
"use client";
import * as LitJsSdk from "@lit-protocol/lit-node-client";
import { useState } from "react";
import Cookies from "js-cookie";
import { v4 as uuid } from "uuid";
export default function Home() {
const [connected, setConnected] = useState(false);
const [isVerified, setIsverified] = useState(false);
const id = uuid();
const accessControlConditions = [
{
contractAddress: "0xE71eE93Ad57c8b355e1bCDFe435B05673d8B4930",
standardContractType: "ERC721",
chain: "mumbai",
method: "balanceOf",
parameters: [":userAddress"],
returnValueTest: {
comparator: ">",
value: "0",
},
},
];
async function connect() {
const resourceId = {
baseUrl: "http://localhost:3000",
path: "/contactus",
orgId: "",
role: "",
extraData: id,
};
const client = new LitJsSdk.LitNodeClient({ alertWhenUnauthorized: false });
await client.connect();
if (client) {
console.log("Am Connected");
}
const authSig = await LitJsSdk.checkAndSignAuthMessage({ chain: "mumbai" });
await client.saveSigningCondition({
accessControlConditions,
chain: "mumbai",
authSig,
resourceId,
});
try {
const jwt = await client.getSignedToken({
accessControlConditions,
chain: "mumbai",
authSig,
resourceId: resourceId,
});
/**
* Store retrieve jwt in cookies with the name lit-auth
*/
Cookies.set("lit-auth", jwt, { expires: 1 });
const { verified, payload } = LitJsSdk.verifyJwt({ jwt });
setIsverified(verified);
} catch (err) {
console.log("error: ", err);
}
setConnected(true);
}
return (
<main className="flex min-h-screen flex-col items-center justify-between p-24">
{connected ? (
<>{isVerified ? <>secret content</> : <>not an NFT holder</>}</>
) : (
<button onClick={connect}>Connect</button>
)}
</main>
);
}
サインインするとこのようになります。
![Image](/_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2Ffrqcsxz2%2Fproduction%2Fa7f260c35206cd6c0d946ed9a8aee6638e8bd24a-1038x632.png%3Fw%3D1038%26auto%3Dformat&w=3840&q=75)
Collab.Land
Collab.Landはweb3界隈のdiscordユーザーなら一度は触ったことのあるツールだと思います。Discordをトークンホルダー限定にするツールとして人気ですね。その方法については記事がたくさんあるのでここでは割愛するとして、APIを使って自分のサイトをトークンゲート化することもできるみたいです。
https://dev.collab.land/docs/tutorials/token-gating-tutorial
https://dev-portal.collab.land/signin からログインしてAPI Keyを入手する必要があります。
![Image](/_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2Ffrqcsxz2%2Fproduction%2F9a605e583d98b92bc85a13a6dfb2739b837e0250-2922x1546.png%3Fw%3D2000%26auto%3Dformat&w=3840&q=75)
無料でもある程度のAPI Callができて、なかなか使い勝手が良さそうだなと思いました!
Pinata Submarine
pinataというIPFSのマネジメントを代行してくれるPinningサービスの1機能にSubmarineという機能があり、それを使ってトークンゲート付きのコンテンツを作成することができます。
有料アカウントにしないと試せないため、今回は紹介だけに留めます。
Decir
Decirというサービスを使ってみます。テストネットは以下のURLです。
https://testnet.decir.io/token-gated/new-draft
![Image](/_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2Ffrqcsxz2%2Fproduction%2F3998295872c472cdb9087207bfdc7e8bf2b70839-2940x1594.png%3Fw%3D2000%26auto%3Dformat&w=3840&q=75)
ホルダー限定のコンテンツを設定します。
![Image](/_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2Ffrqcsxz2%2Fproduction%2F7038e72f3d7eafcb67534c9b5c3fac7537079ca5-1438x1518.png%3Fw%3D1438%26auto%3Dformat&w=3840&q=75)
トークンゲートの設定をします。
![Image](/_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2Ffrqcsxz2%2Fproduction%2Fc4f01746b2e4e95a4c6837ae2a297770ec51319c-1388x1134.png%3Fw%3D1388%26auto%3Dformat&w=3840&q=75)
トークンゲート付きのリンクが生成できました。ログインするまでは閲覧できません。
https://testnet.decir.io/token-gated/content/68b84bf2-ae8c-400a-b3b4-b2fd56bf6d8c
![Image](/_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2Ffrqcsxz2%2Fproduction%2Fda821675acd69298540b3dc5e45718ca6fa7704c-2906x1522.png%3Fw%3D2000%26auto%3Dformat&w=3840&q=75)
トークンを保有していないウォレットで接続すると以下のようにコンテンツを表示できません。
![Image](/_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2Ffrqcsxz2%2Fproduction%2F2e20c11a23a59853a176521ee300290dc815444a-2560x1410.png%3Fw%3D2000%26auto%3Dformat&w=3840&q=75)
認証後のURLを見るとbackground-imgに画像を設定するという少し手の込んだことをしていましたが、画像自体はgoogleのstorageに保管されており、認証付きのURLが表示されているようです。
![Image](/_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2Ffrqcsxz2%2Fproduction%2Fb0706a3c5dfb4fcfc0344008262bd1e2df12bab7-950x256.png%3Fw%3D950%26auto%3Dformat&w=3840&q=75)
まとめ
トークンゲートを実現するいくつかのサービス・実装方法をご紹介しました。個人的にはThirdweb Authで実装する方法か、Lit Protocolを利用する方法がおすすめだと思います。
弊社Pontechはweb3に関わる開発を得意とするテック企業です。サービス開発に関するご相談はこちらのフォームからお願いいたします。
また、受託開発案件に共に取り組むメンバーを募集しています!ご興味のある方はぜひお話させてください!