🌐
Worldcoin Mini Appの開発
Worldcoin
AIと人間を区別することができるアカウント基盤を提供するブロックチェーン上のサービスです。アカウントに対してAIと人間を区別することができる機能がついています。
Worldcoin Mini App
Worldcoinのアプリ内で利用することができるミニアプリの総称です。
ドキュメント
サクッと試せるテンプレート
Next.jsのテンプレが環境崩れしづらくて一番触りやすい印象
各所解説
Worldcoin Mini Appなどミニアプリ系は、アクセスする際に本体アプリと接続することになるので、一番外側(最初に呼び出される部分)がコアになります。
minikit-provider.tsx
Worldcoinの機能は全てMiniKitがインストール済みでないと始まらないので、最初にMiniKit.install()
を呼び、各所でMiniKit.isInstalled()
を呼びながらフラグチェックをしつつ処理を書いていきます。
"use client"; // Required for Next.js
import { MiniKit } from "@worldcoin/minikit-js";
import { ReactNode, useEffect } from "react";
export default function MiniKitProvider({ children }: { children: ReactNode }) {
useEffect(() => {
MiniKit.install();
console.log(MiniKit.isInstalled());
}, []);
return <>{children}</>;
}
Mini App特別機能 command
コマンド名 | 説明 |
---|---|
Verify | Orb認証をしているか確認する |
Pay | 仮想通貨を支払う |
Wallet Auth | ウォレット接続 |
Send Transaction | トランザクションの送信 |
Sign Message | 署名 |
Sign Typed Data | 署名 |
Share Social Graph(coming soon) | ユーザーの連絡先の公開? |
Notifications(coming soon) | デバイスへの通知? |
使い方は色々あるので今回はPayを解説します。
Payは3つのフェーズで実行します。
- nonceの生成
- 入力情報の生成(金額と通貨)
- コマンドの送信
nonceの生成
const res = await fetch(`/api/initiate-payment`, {
method: "POST",
});
const { id } = await res.json();
console.log(id);
入力情報の生成
const payload: PayCommandInput = {
reference: id,
to: "0x0c892815f0B058E69987920A23FBb33c834289cf", // Test address
tokens: [
{
symbol: Tokens.WLD,
token_amount: tokenToDecimals(0.5, Tokens.WLD).toString(),
},
{
symbol: Tokens.USDCE,
token_amount: tokenToDecimals(0.1, Tokens.USDCE).toString(),
},
],
description: "Watch this is a test",
};
コマンドの送信
if (MiniKit.isInstalled()) {
return await MiniKit.commandsAsync.pay(payload);
}
ログイン処理の検討
ログイン処理を実装するには2つの方法があります。
- OIDCを使った方法
- Wallet Authを使った方法
認証方法 | World認証 | ブロックチェーン処理 |
---|---|---|
OIDC | ○ | △(Payは使える) |
Wallet Auth | △(他のコマンドとの組み合わせて補完できる) | ○ |
基本的にブロックチェーンでの処理を行わない場合(AIと人間を区別するためだけに使う)は1を使用して、ブロックチェーンの処理を行う場合は2を使うのが良いです。
OIDCを用いたログイン処理の実装例
OIDCを用いる場合はNextAuthを用いて実装するのが手軽です。
認証側
app/api/auth/[...nextauth]/route.ts
import NextAuth, { NextAuthOptions } from "next-auth";
const authOptions: NextAuthOptions = {
secret: process.env.NEXTAUTH_SECRET,
providers: [
{
id: "worldcoin",
name: "Worldcoin",
type: "oauth",
wellKnown: "https://id.worldcoin.org/.well-known/openid-configuration",
authorization: { params: { scope: "openid" } },
clientId: process.env.WLD_CLIENT_ID,
clientSecret: process.env.WLD_CLIENT_SECRET,
idToken: true,
checks: ["state", "nonce", "pkce"],
profile(profile) {
return {
id: profile.sub,
name: profile.sub,
verificationLevel:
profile["https://id.worldcoin.org/v1"].verification_level,
};
},
},
],
callbacks: {
async signIn({ user }) {
return true;
},
},
debug: process.env.NODE_ENV === "development",
};
const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };
ログイン処理側
components/SignIn/index.tsx
"use client";
import { signIn, signOut, useSession } from "next-auth/react";
export const SignIn = () => {
const { data: session } = useSession();
if (session) {
return (
<>
Signed in as {session?.user?.name?.slice(0, 10)} <br />
<button onClick={() => signOut()}>Sign out</button>
</>
);
} else {
return (
<>
Not signed in <br />
<button onClick={() => signIn()}>Sign in</button>
</>
);
}
};
参考
Wallet Authを用いたログイン処理の実装例
認証API側
app/api/session/route.ts
import { cookies } from "next/headers";
import { NextResponse } from "next/server";
export async function POST(request: Request) {
const { walletAddress } = await request.json();
// セッションクッキーを設定(24時間有効)
cookies().set("wallet_session", walletAddress, {
httpOnly: true,
secure: process.env.NODE_ENV === "production",
sameSite: "strict",
maxAge: 60 * 60 * 24, // 24時間
path: "/",
});
return NextResponse.json({ status: "success" });
}
export async function GET() {
const walletSession = cookies().get("wallet_session");
return NextResponse.json({
walletAddress: walletSession?.value || null,
});
}
export async function DELETE() {
cookies().delete("wallet_session");
return NextResponse.json({ status: "success" });
}
ログイン処理側
components/minikit-provider.tsx
"use client"; // Required for Next.js
import { useWalletStore } from "@/store/wallet";
import { signInWithWallet } from "@/utils/signInWithWallet";
import { MiniKit } from "@worldcoin/minikit-js";
import { ReactNode, useEffect } from "react";
export default function MiniKitProvider({ children }: { children: ReactNode }) {
const setWalletAddress = useWalletStore((state: any) => state.setWalletAddress);
// 初期化時にセッションをチェック
useEffect(() => {
const f = async () => {
const res: any = await signInWithWallet()
if (res?.status === 'success') {
const walletAddress = MiniKit.walletAddress
if (!walletAddress) return
setWalletAddress(walletAddress)
}
}
const checkSession = async () => {
const response = await fetch('/api/session');
const { walletAddress } = await response.json();
if (walletAddress) {
setWalletAddress(walletAddress);
} else {
f();
}
};
const timer = setTimeout(() => {
checkSession();
}, 1000);
return () => clearTimeout(timer);
}, [MiniKit.isInstalled()]);
useEffect(() => {
MiniKit.install();
console.log(MiniKit.isInstalled());
}, []);
return <>{children}</>;
}
バグが出て解決しない場合はすぐtelegramのdeveloperグループで聞こう
Worldcoin Mini Appはまだ発展途上のためバグがかなり多いです。そのためコードの問題ではなくSDKの問題であることも多々あります。そのためtelegramのdeveloper groupとdiscordに参加しておくのをお勧めします。
Worldcoin Discord
Worldcoin Telegram
Discussion