本記事は下記の翻訳となります。
『Social Login dApp with Particle Network on Berachain Testnet』
Berachain Artio テストネット導入ガイド
Berachain の Artio テストネットのローンチは、コミュニティに大きな波紋を呼び起こしています。Artio はユーザー間で類を見ない注目を集めており、Proof-of-Liquidity コンセンサスメカニズムの強力な実装を基盤としていることから、開発者やチームがテストネットへのデプロイを開始することへの期待が高まっています!
Berachain の Artio テストネットのローンチ直後、Particle Network はSmart Wallet-as-a-Serviceのサポートを開始しました。これにより、Berachain で構築する開発者は、EOA と関連するスマートアカウント(現在はSimpleAccount 実装)の作成と管理にソーシャルログインを活用したアプリケーションのプロトタイプ作成をすぐに始めることができます。
この記事は、Particle Network の DevRel チームの*Tabasco*との共同制作です。dAppテンプレートを一から作成する際のサポートに深く感謝します!🤝 🐻
前提条件
- Node.js 20 以上と最新の npm。必要な場合は以下のガイドを参照してください:https://docs.npmjs.com/downloading-and-installing-node-js-and-npm
- VScode、Replit などの IDE
- $BERA:Berachain のネイティブガストークン。デモで使用する新規作成ウォレットに必要です。(https://artio.faucet.berachain.com)
- $HONEY:Berachain のネイティブステーブルコイン。公式 Berachain の Dex/Bex から入手できます。(https://artio.bex.berachain.com)
- Particle Network の開発者ダッシュボードへのアクセス。(https://dashboard.particle.network/)
Particle Auth Core によるソーシャルログイン
🤔 なぜソーシャルログインなのか?
ソーシャルベースのログインは、特に Web2 アプリを主に使用してきたユーザーにとって、「より簡単な Web3 オンボーディング」という考えに一歩近づいたものであることが証明されています。
ソーシャルログインを活用することで、ユーザーは好みのソーシャルメディアアカウントを使用して簡単に認証を行うことができ、オンボーディングプロセスが簡素化されます。Web3 dApps とやり取りするにはウォレットが必要であることは周知の通りです。ここで Particle Network が、ユーザーが正常に認証された後にユーザーのアカウントに関連付けられた Web3 ウォレットアドレスを取得できるようにすることで、そのギャップを埋めています。
🛠️ 何を構築するのか?
このチュートリアルでは、Particle Auth Core と Particle の AA SDK を通じて、Berachain Artio テストネット上にスマート WaaS 対応アプリケーションを構築することに焦点を当てます。このアプリケーションは、上記の組み込み dApp で示された機能を再現します。
このガイドではフロントエンドには焦点を当てませんが、フロントエンドのコードも共有します。主に以下のことを行います:
- ソーシャルログインの開始(この例では、Google または X、および一般的な認証モーダルを通じて)
- 結果として得られる EOA(ソーシャルログインを通じて生成)に SimpleAccount を割り当てる
- ガスレスバーントランザクション(0.001 $BERA)の実行
- Berachain のネイティブステーブルコインである 1 $HONEY のバーンの実行
これが完了すると、ここで示された構造と利用フローを活用して、Berachain でのプロジェクトに Particle Auth Core を実装する方法、あるいは単純に Berachain テストネット上でソーシャルログインテンプレートを取得する方法について、良い理解が得られるはずです。
アプリケーションの基礎構築
- プロジェクトの初期化: Vite を使用して新しい React-typescript アプリケーションを作成します。
npm create vite@latest berachain-particleTest -- --react-ts;
# 期待される出力
# Need to install the following packages:
# create-vite@5.2.1
# Ok to proceed? (y) y
# ✔ Package name: … berachain-particletest
# ✔ Select a framework: › React
# ✔ Select a variant: › TypeScript
# Scaffolding project in /Users/dethebera/BeraWork/berachain-particle-testterminal/berachain-particleTest...
# Done. Now run:
# cd berachain-particleTest
# npm install
# npm run dev
cd berachain-particleTest;
npm install;
# 期待される出力
# added 219 packages, and audited 220 packages in 8s
# 41 packages are looking for funding
# run `npm fund` for details
# found 0 vulnerabilities
- このプロジェクトの依存関係をインストール
npm install @types/events antd buffer react-dom
# 期待される出力
# added 71 packages, and audited 291 packages in 5s
# 45 packages are looking for funding
# run `npm fund` for details
# found 0 vulnerabilities
npm i ethers@5.7.2
# 期待される出力
# added 44 packages, and audited 335 packages in 4s
# 76 packages are looking for funding
# run `npm fund` for details
# found 0 vulnerabilities
-
Particle ライブラリのインストール: このデモを構築し、Particle Auth Core の実装プロセスを探るために、設定に使用する重要なライブラリをいくつかインストールする必要があります。具体的には、以下をインストールする必要があります:
-
@particle-network/auth-core-modal
- 以前の@particle-network/auth
から名前が変更された、Particle Auth Core を実装するための中心的な SDK -
@particle-network/aa
- SimpleAccount の割り当てと、Ethers でスマートアカウントを制御するためのカスタム AA 対応 EIP-1193 プロバイダーオブジェクトの生成のため -
@particle-network/chains
- BerachainArtio 固有の情報を含むオブジェクトで Particle Auth Core を設定するため
その後、以下のいずれかのコマンドをプロジェクトのルートでコピーして実行し、Yarn または npm を通じて両方の SDK をインストールします(pnpm などの他のパッケージマネージャーも同様の構文に従います):
yarn add @particle-network/auth-core-modal @particle-network/chains @particle-network/aa;
# または(どちらか一方を使用し、両方は使用しないでください)
npm install @particle-network/auth-core-modal @particle-network/chains @particle-network/aa;
# 期待される出力
# added 368 packages, and audited 703 packages in 41s
# 109 packages are looking for funding
# run `npm fund` for details
# 8 moderate severity vulnerabilities
# To address issues that do not require attention, run:
# npm audit fix
# Some issues need review, and may require choosing
# a different dependency.
# Run `npm audit` for details.
Particle ダッシュボードからキーを取得
AuthCoreContextProvider
を構築する前に、Particle Auth Core を初期化するための 3 つの値が必要です。Particle Auth Core、Particle Connect、またはParticle の AA SDKなど、Particle Network の任意の SDK を設定する際には、Particle ダッシュボードからプロジェクト ID、クライアントキー、アプリ ID を取得する必要があります。
これらの値は、アプリケーションを Particle ダッシュボード上のプロジェクトにリンクし、API リクエストの認証、ユーザーの追跡、ノーコードモーダルのカスタマイズなどを可能にします。
- particlenetwork.comに移動し、右上隅の「Dashboard」をクリックします。
Particle Network のホームページ
- 「Add New Project」をクリックし、任意のプロジェクト名を入力して「Save」をクリックします。
ダッシュボードのホームページ
- これで「Project ID」と「Client Key」にアクセスできるようになります。
アプリケーション画面
- 「App ID」を取得するには、「Your Apps」タブの下の「Web」をクリックし、「Ok」をクリックします。
アプリケーションでハイライトされた Web アプリセクション
- 「App Name」に任意の名前を入力します。ドメインには「google.com」を入力するか、アプリケーションがすでにホストされている場合は、そのドメインを入力します。
App ID の取得
- 「Your Apps」セクションの下に「App ID」が表示されるはずです。
Your Apps の下の App ID
これらのライブラリがインストールされたら、設定プロセスを進める準備が整いました。
Particle Auth Core を通じたソーシャルログインの実装:
Particle Auth Core は、AuthCoreContextProvider
(@particle-network/auth-core-modal
からインポート)を通じて設定を管理します。これはindex
ファイル内で主要なApp
コンポーネント(または同等のもの)をラップするために使用されるオブジェクトです。これには Particle Auth のインスタンスを認証し、ソーシャルログインや組み込みウォレットモーダルの基本的なカスタマイズを可能にする重要な値が含まれています。
Particle ダッシュボードを通じてプロジェクトとアプリケーションをセットアップしたら、AuthCoreContextProvider
の設定準備が整います。
ファイル: ./src/index.tsx
// インポート
// ========================================================
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BerachainArtio } from '@particle-network/chains';
import { AuthCoreContextProvider } from '@particle-network/auth-core-modal';
import App from './App';
import('buffer').then(({ Buffer }) => {
window.Buffer = Buffer;
});
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<AuthCoreContextProvider
options={{
projectId: process.env.REACT_APP_PROJECT_ID, // YOUR_PROJECT_ID_HEREを実際のプロジェクトIDに置き換えてください
clientKey: process.env.REACT_APP_CLIENT_KEY, // YOUR_CLIENT_KEY_HEREを実際のクライアントキーに置き換えてください
appId: process.env.REACT_APP_CLIENT_KEY, // YOUR_APP_ID_HEREを実際のアプリIDに置き換えてください
erc4337: {
name: 'SIMPLE', // モーダルに表示されるスマートアカウントの名前
version: '1.0.0',
},
wallet: {
visible: true, // Particleウォレットモーダルを表示するかどうかを決定するブール値
customStyle: {
supportChains: [BerachainArtio], // Particleウォレットモーダル(visibleがtrueの場合)がロックされるチェーンの配列
},
},
}}
>
<App />
</AuthCoreContextProvider>
</React.StrictMode>
);
注:特定の環境変数の制約により、キーを.env ファイルではなく直接文字列として渡しています。
スマートアカウントの設定
AuthCoreContextProvider
が設定され、Particle Auth Core が初期化されたら、主要なアプリケーションコンポーネント(上記の例ではApp
)の実装に移ることができます。
トランザクションを実行する前に、まずスマートアカウントを設定する必要があります。
このセットアップでは、Particle Auth Core を使用してソーシャルログインを開始し EOA を生成します。その後、Particle の AA SDK(@particle-network/aa
)がスマートアカウントの割り当てとやり取りを担当します。
上記のプロセスの例を以下に示します。
ファイル: ./src/App.tsx
// インポート
// ========================================================
import { BerachainArtio } from "@particle-network/chains";
import {
AAWrapProvider,
SendTransactionMode,
SmartAccount,
} from "@particle-network/aa";
import {
useEthereum
} from "@particle-network/auth-core-modal";
// Appのインポート
// ========================================================
import "./App.css";
const App = () => {
const { provider } = useEthereum();
const { connect, disconnect } = useConnect();
const { userInfo } = useAuthCore();
const [balance, setBalance] = useState(null);
// スマートアカウントの設定
// ========================================================
const smartAccount = new SmartAccount(provider, {
projectId: "YOUR_PROJECT_ID_HERE", // YOUR_PROJECT_ID_HEREを実際のプロジェクトIDに置き換えてください
clientKey: "YOUR_CLIENT_KEY_HERE", // YOUR_CLIENT_KEY_HEREを実際のクライアントキーに置き換えてください
appId: "YOUR_APP_ID_HERE", // YOUR_APP_ID_HEREを実際のアプリIDに置き換えてください
aaOptions: {
accountContracts: {
SIMPLE: [{ chainIds: [BerachainArtio.id], version: '1.0.0' }],
}
}
});
Ethers のセットアップ
上記の例のSmartAccount
のインスタンスは、AAWrapProvider
内で直接使用して、新しいethers.providers.Web3Provider
インスタンス(または v6 を使用している場合はethers.BrowserProvider
)内で使用する AA 対応プロバイダーオブジェクトを構築できます。同じ構造を Web3.js や viem にも適用できます。
AAWrapProvider
内でSendTransactionMode.Gasless
を使用します。これにより、このプロバイダーオブジェクトを通じて送信されるトランザクションは、Paymaster 内で設定した条件を満たせば(この例では条件はないため、トランザクションは無差別にスポンサーされます)、スポンサーシップの対象となります。
カスタム Ethers プロバイダーは以下のようになります:
ファイル: ./src/App.tsx
// インポート
// ========================================================
import { BerachainArtio } from "@particle-network/chains";
import {
AAWrapProvider,
SendTransactionMode,
SmartAccount,
} from "@particle-network/aa";
import {
useEthereum
} from "@particle-network/auth-core-modal";
// Appのインポート
// ========================================================
import "./App.css";
const App = () => {
const { provider } = useEthereum();
const { connect, disconnect } = useConnect();
const { userInfo } = useAuthCore();
const [balance, setBalance] = useState(null);
// スマートアカウントの設定
// ========================================================
const smartAccount = new SmartAccount(provider, {
projectId: "YOUR_PROJECT_ID_HERE",
clientKey: "YOUR_CLIENT_KEY_HERE",
appId: "YOUR_APP_ID_HERE",
aaOptions: {
accountContracts: {
SIMPLE: [{ chainIds: [BerachainArtio.id], version: '1.0.0' }],
}
}
});
// Ethersプロバイダーのセットアップ
const customProvider = new ethers.providers.Web3Provider(new AAWrapProvider(smartAccount, SendTransactionMode.Gasless), "any");
このオブジェクト(この場合はcustomProvider
)が初期化されると、Particle を通じてトランザクション、残高の取得、メッセージ署名などを行うことができます。ただし、これらのいずれかを行う前に、まずソーシャルログインを行う必要があります — これが次に説明する内容です。
ソーシャルログインのセットアップ
Particle Auth Core でのソーシャルログインは簡単で、useConnect
フックから得られるconnect
とdisconnect
の 2 つの関数によって制御されます。connect
を呼び出すと、すぐにソーシャルログインが開始され、ユーザーは指定されたソーシャルログインメカニズムのログインプロセスを実行します。同様にdisconnect
の場合、ユーザーは呼び出し時にアカウントから切断されます。
また、@particle-network/auth-core からインポートされた特定のタイプSocialAuthType
も必要です。(これはインポートに含まれます)。
ファイル: ./src/App.tsx
// インポート
// ========================================================
import { BerachainArtio } from "@particle-network/chains";
import {
AAWrapProvider,
SendTransactionMode,
SmartAccount,
} from "@particle-network/aa";
import {
useEthereum
} from "@particle-network/auth-core-modal";
// 新しいインポートの追加- SocialAuthType
// ========================================================
import { SocialAuthType } from "@particle-network/auth-core";
// Appのインポート
// ========================================================
import "./App.css";
const App = () => {
const { provider } = useEthereum();
const { connect, disconnect } = useConnect();
const { userInfo } = useAuthCore();
const [balance, setBalance] = useState(null);
// スマートアカウントの設定
// ========================================================
const smartAccount = new SmartAccount(provider, {
projectId: "YOUR_PROJECT_ID_HERE",
clientKey: "YOUR_CLIENT_KEY_HERE",
appId: "YOUR_APP_ID_HERE",
aaOptions: {
accountContracts: {
SIMPLE: [{ chainIds: [BerachainArtio.id], version: '1.0.0' }],
}
}
});
// Ethersプロバイダーのセットアップ
const customProvider = new ethers.providers.Web3Provider(new AAWrapProvider(smartAccount, SendTransactionMode.Gasless), "any");
// ログインのセットアップ
// ========================================================
const handleLogin = async (authType: SocialAuthType) => { // フロントエンドで「Googleでサインイン」「Xでサインイン」およびその他のボタンにマッピングできます。connectにソーシャルタイプを渡すだけで変更できます
if (!userInfo) {
await connect({
socialType: authType, // 使用する特定の認証タイプを示す文字列('google'、'twitter'など)
chain: BerachainArtio, // 接続したい特定のチェーン。これはBerachainArtioである必要があります
});
}
};
カスタム Ethers オブジェクトを構築し、ユーザーが(connect
を通じて)ログインすると、Particle の組み込みウォレットを通じて直接トランザクションリクエストを行うことができます。前述のように、これは前述の Ethers オブジェクト(ここではcustomProvider
)のメソッドを通じて直接行われ、Particle での動作のために特別な設定は必要ありません。
BERA のバーントランザクションの設定
このデモでは 2 つのトランザクションを行い、さらに 1 つの$HONEY をバーンするトランザクションを行います。
最初のトランザクションでは、0.001 $BERAのガスレスバーンを実行します。これは本質的に$BERA をデッドアドレス(通常は0x000000000000000000000000000000000000dEaD
)に送信することを意味します。
このトランザクションはプログラム的にはかなり単純で、以下のような構造になります:
ファイル: ./src/App.tsx
// インポート
// ========================================================
import { BerachainArtio } from "@particle-network/chains";
import {
AAWrapProvider,
SendTransactionMode,
SmartAccount,
} from "@particle-network/aa";
import {
useEthereum
} from "@particle-network/auth-core-modal";
// 新しいインポートの追加 - SocialAuthType
// ========================================================
import { SocialAuthType } from "@particle-network/auth-core";
// Appのインポート
// ========================================================
import "./App.css";
const App = () => {
const { provider } = useEthereum();
const { connect, disconnect } = useConnect();
const { userInfo } = useAuthCore();
const [balance, setBalance] = useState(null);
// スマートアカウントの設定
// ========================================================
const smartAccount = new SmartAccount(provider, {
projectId: "YOUR_PROJECT_ID_HERE",
clientKey: "YOUR_CLIENT_KEY_HERE",
appId: "YOUR_APP_ID_HERE",
aaOptions: {
accountContracts: {
SIMPLE: [{ chainIds: [BerachainArtio.id], version: '1.0.0' }],
}
}
});
// Ethersプロバイダーのセットアップ
const customProvider = new ethers.providers.Web3Provider(new AAWrapProvider(smartAccount, SendTransactionMode.Gasless), "any");
// ログインのセットアップ
// ========================================================
const handleLogin = async (authType: SocialAuthType) => {
if (!userInfo) {
await connect({
socialType: authType,
chain: BerachainArtio,
});
}
};
// 0.001 $BERAのバーン
// ========================================================
const executeUserOp = async () => {
const signer = customProvider.getSigner();
const tx = {
to: "0x000000000000000000000000000000000000dEaD",
value: ethers.utils.parseEther("0.001"), // weiに変換される必要のある$BERAの値
};
const txResponse = await signer.sendTransaction(tx); // sendTransactionメソッド
const txReceipt = await txResponse.wait();
notification.success({
message: "トランザクション成功",
description: (
<div>
トランザクションハッシュ:{" "}
<a
href={`https://artio.beratrail.io/tx/${txReceipt.transactionHash}`}
target="_blank"
rel="noopener noreferrer"
>
{txReceipt.transactionHash}
</a>
</div>
),
});
};
$HONEY のバーントランザクションの設定
注意: $HONEYを持っていないが、この機能をテストしたい場合は、BerachainのDEXで$BERA と$HONEY をスワップできます。
2 番目のトランザクション、つまり Berachain のネイティブステーブルコインである 1 $HONEYのバーンについても、同様のアプローチを取ることができます。ただし、signer
のメソッドを直接呼び出す代わりに、$HONEY のコントラクトオブジェクトを作成し、そこで transfer メソッドを呼び出す必要があります。
これは、0x7EeCA4205fF31f947EdBd49195a7A88E6A91161B
(Berachain Artio の$HONEY コントラクトアドレス)と ABI を渡してethers.Contract
を初期化するだけで行えます。(参照)
ファイル: ./src/App.tsx
// インポート
// ========================================================
[前述のインポートは同じ];
const App = () => {
[前述の設定は同じ];
// 1 $HONEYのバーン
// ========================================================
const executeUserOpHONEY = async () => {
const signer = customProvider.getSigner();
const tokenContract = new ethers.Contract(
'0x7EeCA4205fF31f947EdBd49195a7A88E6A91161B', // 公式の$HONEYコントラクトアドレス
['function transfer(address to, uint256 amount)'],
signer // {your ethers object}.getSignerを通じて取得
);
const txResponse = await tokenContract.transfer(
'0x000000000000000000000000000000000000dEaD',
ethers.utils.parseEther('1') // $HONEYの量
);
const txReceipt = await txResponse.wait();
notification.success({
message: 'トランザクション成功',
description: (
<div>
トランザクションハッシュ:{' '}
<a
href={`https://artio.beratrail.io/tx/${txReceipt.transactionHash}`}
target="_blank"
rel="noopener noreferrer"
>
{txReceipt.transactionHash}
</a>
</div>
),
});
};
const executeUserOp = async () => {
const signer = customProvider.getSigner();
const tx = {
to: '0x000000000000000000000000000000000000dEaD',
value: ethers.utils.parseEther('0.001'),
};
const txResponse = await signer.sendTransaction(tx);
const txReceipt = await txResponse.wait();
notification.success({
message: 'トランザクション成功',
description: (
<div>
トランザクションハッシュ:{' '}
<a
href={`https://artio.beratrail.io/tx/${txReceipt.transactionHash}`}
target="_blank"
rel="noopener noreferrer"
>
{txReceipt.transactionHash}
</a>
</div>
),
});
};
const executeUserOpHONEY = async () => {
const signer = customProvider.getSigner();
const tokenContract = new ethers.Contract(
'0x7EeCA4205fF31f947EdBd49195a7A88E6A91161B',
['function transfer(address to, uint256 amount)'],
signer
);
const txResponse = await tokenContract.transfer(
'0x000000000000000000000000000000000000dEaD',
ethers.utils.parseEther('1')
);
const txReceipt = await txResponse.wait();
notification.success({
message: 'トランザクション成功',
description: (
<div>
トランザクションハッシュ:{' '}
<a
href={`https://artio.beratrail.io/tx/${txReceipt.transactionHash}`}
target="_blank"
rel="noopener noreferrer"
>
{txReceipt.transactionHash}
</a>
</div>
),
});
};
return (
<div className="App">
<div className="logo-section">
<img src="https://i.imgur.com/EerK7MS.png" alt="Logo 1" className="logo logo-big" />
<img src="https://i.imgur.com/OdR3YLW.png" alt="Logo 2" className="logo" />
</div>
{!userInfo ? (
<div className="login-section">
<button className="sign-button google-button" onClick={() => handleLogin('google')}>
<img src="https://i.imgur.com/nIN9P4A.png" alt="Google" className="icon" />
Googleでサインイン
</button>
<button className="sign-button twitter-button" onClick={() => handleLogin('twitter')}>
<img src="https://i.imgur.com/afIaQJC.png" alt="Twitter" className="icon" />
Xでサインイン
</button>
</div>
) : (
<div className="profile-card">
<h2>{userInfo.name}</h2>
<div className="balance-section">
<small>{balance} BERA</small>
<button className="sign-message-button" onClick={executeUserOp}>
0.001 $BERAをバーン
</button>
<button className="sign-message-button honey" onClick={executeUserOpHONEY}>
1 $HONEYをバーン
</button>
<button className="disconnect-button" onClick={() => disconnect()}>
ログアウト
</button>
</div>
</div>
)}
</div>
);
};
export default App;
../src/App.css
https://github.com/berachain/guides/tree/main/apps/particle-auth-core-viteからテンプレートの既存のコードを使用してください!
{!userInfo ? (
<div className="login-section">
<button
className="sign-button google-button"
onClick={() => handleLogin("google")}
>
<img
src="https://i.imgur.com/nIN9P4A.png"
alt="Google"
className="icon"
/>
Googleでサインイン
</button>
<button
className="sign-button twitter-button"
onClick={() => handleLogin("twitter")}
>
<img
src="https://i.imgur.com/afIaQJC.png"
alt="Twitter"
className="icon"
/>
Xでサインイン
</button>
</div>
) : (
<div className="profile-card">
<h2>{userInfo.name}</h2>
<div className="balance-section">
<small>{balance} BERA</small>
<button className="sign-message-button" onClick={executeUserOp}>
0.001 $BERAをバーン
</button>
<button
className="sign-message-button honey"
onClick={executeUserOpHONEY}
>
1 $HONEYをバーン
</button>
<button className="disconnect-button" onClick={() => disconnect()}>
ログアウト
</button>
</div>
</div>
)}
</div>
);
};
export default App;
../src/App.css
https://github.com/berachain/guides/tree/main/apps/particle-auth-core-viteからテンプレートの既存のコードを使用してください!
さらなる dApp と開発サポートについて
Berachain についてさらに理解し開発を進めたい場合は、公式ガイドリポジトリで提供されているさまざまなサンプルリポジトリを試してみてください —
guides/apps/particle-auth-core-vite at main · berachain/guides
Berachain の開発者ドキュメントには、Hardhat、Foundry などの主要ツールに関する複数のスターターガイドも用意されています。以下のリンクからドキュメントの開発者セクションにアクセスしてください。
開発者サポートを受けるには?
⚠️ まだ問題が解決しない、または質問がありますか?Berachain の公式 Discordに参加し、以下の gif のようにチケットを作成してください!
DevRel チームがサポートいたします!🤝
開発ベアの皆さん、さようなら!🐻
【Sunrise とは】
Sunrise は Proof of Liquidity(PoL)と Fee Abstraction(手数料抽象化)を備えたデータ可用性レイヤーです。 私たちは DA の体験を再構築し、多様なエコシステムからのモジュラー型流動性を活用してロールアップを立ち上げています。
【Social Links】
【お問合せ】
Sunrise へのお問い合わせはこちらから 👉 Google Form