メインコンテンツまでスキップ

lesson-2_Webサイトにウォレット連携ボタンを実装しよう!

🛍 ウォレットに接続するボタンをレンダリングする

WebアプリケーションからPhantom Walletへの接続を促すために、connectWalletボタンを作成します。

web3の世界では、ウォレット接続ボタンは「ログイン」ボタンの役割を果たします。

App.jsファイルを以下のとおり変更しましょう。

import React, { useEffect } from "react";
import twitterLogo from "./assets/twitter-logo.svg";
import "./App.css";

// 定数を宣言します。
const TWITTER_HANDLE = "あなたのTwitterハンドル";
const TWITTER_LINK = `https://twitter.com/${TWITTER_HANDLE}`;

const App = () => {
/*
* Phantom Walletが接続されているかどうかを確認するための関数です。
*/
const checkIfWalletIsConnected = async () => {
try {
const { solana } = window;

if (solana) {
if (solana.isPhantom) {
console.log("Phantom wallet found!");
const response = await solana.connect({ onlyIfTrusted: true });
console.log(
"Connected with Public Key:",
response.publicKey.toString()
);
}
} else {
alert("Solana object not found! Get a Phantom Wallet 👻");
}
} catch (error) {
console.error(error);
}
};

/*
* 「Connect to Wallet」ボタンを押したときに動作する関数です。(移行のSectionで変更するので、現状は内部処理がないまま進みます。)
*/
const connectWallet = async () => {};

/*
* ユーザーがWebアプリケーションをウォレットに接続していないときに表示するUIです。
*/
const renderNotConnectedContainer = () => (
<button
className="cta-button connect-wallet-button"
onClick={connectWallet}
>
Connect to Wallet
</button>
);

/*
* 初回のレンダリング時にのみ、Phantom Walletが接続されているかどうか確認します。
*/
useEffect(() => {
const onLoad = async () => {
await checkIfWalletIsConnected();
};
window.addEventListener("load", onLoad);
return () => window.removeEventListener("load", onLoad);
}, []);

return (
<div className="App">
<div className="container">
<div className="header-container">
<p className="header">🖼 GIF Portal</p>
<p className="sub-text">View your GIF collection ✨</p>
{/* ここでウォレットへの接続ボタンをレンダリングします。 */}
{renderNotConnectedContainer()}
</div>
<div className="footer-container">
<img alt="Twitter Logo" className="twitter-logo" src={twitterLogo} />
<a
className="footer-text"
href={TWITTER_LINK}
target="_blank"
rel="noreferrer"
>{`built on @${TWITTER_HANDLE}`}</a>
</div>
</div>
</div>
);
};

export default App;

Webアプリケーションに「Connect to Wallet」ボタンが表示されているかどうか、インタフェースを確認してみましょう。

ユーザーがウォレットを Web アプリケーションに接続していない場合のみ、Connect to Walletボタンが表示されます。

interface

次に、ReactのuseStateを用いてユーザーのウォレットアドレスのstateを管理し、Connect to Walletボタンを表示するかどうかを判断するためのフラグとして利用していきましょう。

まずは、App.jsの1行目でuseStateをインポートします。

import React, { useEffect, useState } from "react";

次に、checkIfWalletIsConnected関数のすぐ下にstateの宣言を追加します。

const [walletAddress, setWalletAddress] = useState(null);

これで、ユーザーのウォレットアドレスのstateを管理するための準備が整いました。

続いて、App.jsを以下のとおり修正していきましょう。

import React, { useEffect, useState } from "react";
import twitterLogo from "./assets/twitter-logo.svg";
import "./App.css";

// 定数を宣言します。
const TWITTER_HANDLE = "あなたのTwitterハンドル";
const TWITTER_LINK = `https://twitter.com/${TWITTER_HANDLE}`;

const App = () => {
// ユーザーのウォレットアドレスのstateを管理するためuseStateを使用する。
const [walletAddress, setWalletAddress] = useState(null);

/*
* Phantom Walletが接続されているかどうかを確認するための関数です。
*/
const checkIfWalletIsConnected = async () => {
try {
const { solana } = window;

if (solana) {
if (solana.isPhantom) {
console.log("Phantom wallet found!");
const response = await solana.connect({ onlyIfTrusted: true });
console.log(
"Connected with Public Key:",
response.publicKey.toString()
);

/*
* walletAddressにユーザーのウォレットアドレスのstateを更新します。
*/
setWalletAddress(response.publicKey.toString());
}
} else {
alert("Solana object not found! Get a Phantom Wallet 👻");
}
} catch (error) {
console.error(error);
}
};

const connectWallet = async () => {};

const renderNotConnectedContainer = () => (
<button
className="cta-button connect-wallet-button"
onClick={connectWallet}
>
Connect to Wallet
</button>
);

/*
* 初回のレンダリング時にのみ、Phantom Walletが接続されているかどうか確認します。
*/
useEffect(() => {
const onLoad = async () => {
await checkIfWalletIsConnected();
};
window.addEventListener("load", onLoad);
return () => window.removeEventListener("load", onLoad);
}, []);

return (
<div className="App">
<div className={walletAddress ? "authed-container" : "container"}>
<div className="header-container">
<p className="header">🖼 GIF Portal</p>
<p className="sub-text">View your GIF collection ✨</p>
{/* ウォレットアドレスを持っていない場合にのみ表示する条件をここに追加します。 */}
{!walletAddress && renderNotConnectedContainer()}
</div>
<div className="footer-container">
<img alt="Twitter Logo" className="twitter-logo" src={twitterLogo} />
<a
className="footer-text"
href={TWITTER_LINK}
target="_blank"
rel="noreferrer"
>{`built on @${TWITTER_HANDLE}`}</a>
</div>
</div>
</div>
);
};

export default App;

簡単に修正点を確認しましょう。

const checkIfWalletIsConnected = async () => {
try {
const { solana } = window;

if (solana) {
if (solana.isPhantom) {
console.log("Phantom wallet found!");
const response = await solana.connect({ onlyIfTrusted: true });
console.log(
"Connected with Public Key:",
response.publicKey.toString()
);

setWalletAddress(response.publicKey.toString());
}
} else {
alert("Solana object not found! Get a Phantom Wallet 👻");
}
} catch (error) {
console.error(error);
}
};

Phantom WalletがWebアプリケーションに接続されていた場合、ユーザーのウォレットアドレスのstateが更新されます。

更新されたstateは以下で利用します。

{
!walletAddress && renderNotConnectedContainer();
}

ここではstatewalletAddressが設定されていない場合のみ、renderNotConnectedContainer関数を呼び出すように記述しています。

したがって、ウォレットアドレスがない(ユーザーがウォレットを接続していない)場合は、ウォレットを接続するためのボタンを表示します(条件付きレンダリングと呼ばれる手法です)。

🔥 ウォレット接続する

今のままだとConnect to Walletボタンをクリックしても何も起こりません。

そのため、これからConnect to Walletボタンを押下した際に機能するconnectWallet関数のロジックをコーディングしていきます。

App.jsconnectWallet関数を下記のとおり修正しましょう。

const connectWallet = async () => {
const { solana } = window;

if (solana) {
const response = await solana.connect();
console.log("Connected with Public Key:", response.publicKey.toString());
setWalletAddress(response.publicKey.toString());
}
};

ユーザーがWebアプリケーションにPhantom Walletを接続したい場合、solanaオブジェクトのconnectメソッドを呼び出して、Phantom Wallet側でWebアプリケーションの接続を承認します。

そうすると、Webアプリケーションがユーザーのウォレット情報(ウォレットアドレスなど)にアクセスできるようになります。

ここまでできたらプラウザで動作を確認してみましょう。

まず、Webアプリケーションとウォレットを接続します。

Connect to Walletボタンを押すとPhantom Walletがポップアップを表示してくれるので、指示に従って接続しましょう。

接続後、Connect to Walletボタンが表示されていないことを確認します。

Connect to Walletボタンが表示されていないことを確認できたらWebアプリケーションを更新してみてください。

更新するとcheckIfWalletIsConnected関数が呼び出されるため、Connect to Walletボタンがすぐに消えるはずです(コンソールには接続済みのウォレットアドレスも出力されています)。

これで基本的なUIとユーザー認証が実装できました。

⚠️ 注意

Fantom Wallet の設定画面(歯車をクリック)に、[信頼済みアプリ]があります。

これを開くと、ウォレットと既に接続されている WEB アプリが一覧で表示され、[取り消し]ボタンを押下することで簡単に連携の解除をすることができます。

ローカルで実行している場合はlocalhost:3000のものが現在作成している Web アプリケーションです。

連携を解除したうえで Web アプリケーションを更新すると、Connect to Walletボタンが表示されるのでぜひ一度試してみてください。

🙋‍♂️ 質問する

ここまでの作業で何かわからないことがある場合は、Discordの#solanaで質問をしてください。

ヘルプをするときのフローが円滑になるので、エラーレポートには下記の4点を記載してください ✨

1. 質問が関連しているセクション番号とレッスン番号
2. 何をしようとしていたか
3. エラー文をコピー&ペースト
4. エラー画面のスクリーンショット

次のレッスンでは、WebアプリケーションにGIF画像を表示します!