Інтеграція гри з блокчейн-кошельком
Інтеграція кошелька — це UX-проблема не менше, ніж технічна. Користувачі приходять грати, а не розбиратися з gas, approve транзакціями та seed phrases. Задача розробника — зробити так, щоб блокчейн був невидим для гравця, поки він йому не потрібен.
Методи підключення
Зовнішні кошельки (MetaMask, Phantom)
Стандарт для крипто-нативної аудиторії. Через Wagmi (React) або WalletConnect AppKit:
import { useConnect, useAccount, useSignMessage } from "wagmi";
function WalletConnect() {
const { connect, connectors } = useConnect();
const { address, isConnected } = useAccount();
if (isConnected) return <GameLobby address={address} />;
return (
<div>
<button onClick={() => connect({ connector: injected() })}>
MetaMask
</button>
</div>
);
}
Embedded wallets (Privy, Web3Auth) для масової аудиторії
Для casual ігор — користувачі не хочуть встановлювати розширення. Embedded wallet створюється автоматично при реєстрації через Google/Apple:
import { usePrivy, useWallets } from "@privy-io/react-auth";
function GameAuth() {
const { login, authenticated } = usePrivy();
const { wallets } = useWallets();
if (!authenticated) {
return <button onClick={login}>Играть</button>;
}
return <Game />;
}
Session Keys: Автоматичні транзакції
Головна UX проблема GameFi — кожна дія вимагає підпису в MetaMask. Session keys вирішують це: користувач авторизує один раз, гра використовує session key для автоматичних транзакцій.
Unity Інтеграція
WebGL: JSLib Bridge
// Plugins/WebGL/wallet.jslib
mergeInto(LibraryManager.library, {
ConnectWallet: async function() {
const accounts = await window.ethereum.request({
method: 'eth_requestAccounts'
});
unityInstance.SendMessage('WalletManager', 'OnWalletConnected', accounts[0]);
}
});
Mobile: WalletConnect Deep Links
using WalletConnectSharp.Unity;
public class MobileWalletConnect : MonoBehaviour {
private WalletConnect _wc;
async void Start() {
_wc = GetComponent<WalletConnect>();
await _wc.Connect();
}
}
Обробка транзакцій
Optimistic UI Updates
Не можна чекати 10–30 секунд для finality. Використовуємо optimistic updates: показуємо результат одразу, відкатуємо якщо транзакція падає.
async function purchaseItem(itemId: number, price: bigint) {
// 1. Показуємо одразу
gameState.addItemOptimistic(itemId);
try {
// 2. Відправляємо транзакцію
const txHash = await marketplace.write.buyItem([itemId], { value: price });
// 3. Чекаємо confirmation в фоні
const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
if (receipt.status === "reverted") {
// 4. Відкатуємо якщо помилка
gameState.removeItem(itemId);
showError("Transaction failed");
}
} catch (err) {
gameState.removeItem(itemId);
showError("Transaction rejected");
}
}
Batching транзакцій
Account Abstraction дозволяє кілька операцій в одній транзакції:
const txHash = await smartAccountClient.sendUserOperation({
calls: [
{
to: TOKEN_ADDRESS,
abi: erc20Abi,
functionName: "approve",
args: [MARKETPLACE_ADDRESS, price],
},
{
to: MARKETPLACE_ADDRESS,
abi: marketplaceAbi,
functionName: "buyItem",
args: [itemId],
},
],
});
Типові проблеми
| Проблема | Рішення |
|---|---|
| Користувач закрив MetaMask popup | Transaction queue + recovery pending state |
| Gas estimation failure | Статичні ліміти + fallback RPC |
| Network mismatch | Авто switch через wallet_switchEthereumChain |
| Користувач відхилив | Graceful fallback, збереження прогресу off-chain |
| Pending tx застряг | Replace з більш високим gas |
Ключевий принцип: блокчейн асинхронний, гра синхронна. Дизайніруйте UI так, щоб pending стан був явним, failure — recoverable.







