playnance-wallet-connect
v1.3.3
Published
A secure communication protocol for Playnance wallet connect.
Downloads
54
Readme
Playnance Wallet Connect
A lightweight TypeScript library that facilitates secure communication between a parent web application and an iframe-based wallet application. This library enables wallet connections, balance management, transactions, and more through message passing between a main app and an iframe wallet.
Table of Contents
Installation
npm install playnance-wallet-connectFeatures
- Secure cross-origin communication between main app and iframe
- Support for multiple wallet providers (MetaMask, Coinbase, Social Wallet)
- Transaction handling (regular transactions, transfers, and contract interactions)
- Balance management and updates
- Wallet connection status monitoring
- TypeScript support with full type definitions
Usage
Main App Implementation
import { PlaynanceMainApp } from 'playnance-wallet-connect';
import { JsonRpcProvider } from 'ethers';
class MainAppImplementation {
private iframeWindow: Window;
private currentWalletAddress: string | null = null;
private provider: JsonRpcProvider | null = null;
constructor() {
this.initializeApp();
this.setupEventListeners();
}
private initializeApp() {
// Initialize with configuration
PlaynanceMainApp.init({
allowedIframeOrigins: [
'https://your-iframe-origin.com',
'https://your-other-iframe.com'
],
socialWalletRpcUrl: 'https://your-social-wallet-rpc-url.com',
walletProviderName: 'metamask'
});
// Set up the iframe reference
const iframe = document.getElementById('wallet-iframe') as HTMLIFrameElement;
this.iframeWindow = iframe.contentWindow!;
}
private setupEventListeners() {
// Handle messages from iframe
window.addEventListener('message', (event) => {
PlaynanceMainApp.handleIncomingMessage(
event,
this.iframeWindow,
this.currentWalletAddress
);
});
// Handle wallet connection events
window.ethereum?.on('accountsChanged', (accounts: string[]) => {
this.currentWalletAddress = accounts[0] || null;
PlaynanceMainApp.sendWalletAddressToIframe(
this.iframeWindow,
this.currentWalletAddress
);
});
// Handle network changes
window.ethereum?.on('chainChanged', () => {
this.updateProvider();
});
}
public async connectWallet() {
try {
const accounts = await window.ethereum?.request({
method: 'eth_requestAccounts'
});
this.currentWalletAddress = accounts[0];
this.updateProvider();
// Update wallet info in iframe
PlaynanceMainApp.updateWalletProvider('metamask', this.iframeWindow);
PlaynanceMainApp.sendWalletAddressToIframe(
this.iframeWindow,
this.currentWalletAddress
);
} catch (error) {
console.error('Failed to connect wallet:', error);
}
}
private async updateProvider() {
if (window.ethereum) {
this.provider = new JsonRpcProvider(window.ethereum);
await PlaynanceMainApp.initSigner(this.provider);
}
}
public startBalanceUpdates() {
// Set up periodic balance updates
PlaynanceMainApp.startLiveBalanceUpdates(
this.iframeWindow,
() => {
// Implement your balance calculation logic
return this.getCurrentBalance();
}
);
}
private async getCurrentBalance(): number {
if (this.currentWalletAddress && this.provider) {
const balance = await this.provider.getBalance(this.currentWalletAddress);
return Number(balance) / 1e18; // Convert from Wei to ETH
}
return 0;
}
public sendCustomData(data: any) {
PlaynanceMainApp.sendCustomDataToIframe(this.iframeWindow, data);
}
}
// Usage
const mainApp = new MainAppImplementation();
mainApp.connectWallet();
mainApp.startBalanceUpdates();Iframe App Implementation
import { PlaynanceIframeApp } from 'playnance-wallet-connect';
import { Contract } from 'ethers';
class IframeAppImplementation {
private connected: boolean = false;
private currentBalance: number = 0;
constructor() {
this.initializeApp();
this.setupMessageHandling();
}
private initializeApp() {
PlaynanceIframeApp.init({
useMetaMask: true,
allowedMainAppOrigin: 'https://your-main-app-origin.com',
allowedIframeOrigin: 'https://your-iframe-origin.com',
walletProviderName: 'metamask'
});
// Start periodic wallet connection checks
PlaynanceIframeApp.startWalletConnectionCheck(5000);
}
private setupMessageHandling() {
window.addEventListener('message', (event) => {
PlaynanceIframeApp.handleIncomingMessage(event, (message) => {
switch (message.type) {
case 'WALLET_CONNECTED':
this.connected = true;
this.handleWalletConnection(message.address);
break;
case 'WALLET_DISCONNECTED':
this.connected = false;
this.handleWalletDisconnection();
break;
case 'BALANCE_UPDATE':
this.currentBalance = message.balance || 0;
this.updateBalanceUI();
break;
case 'TRANSACTION_SUCCESS':
this.handleTransactionSuccess(message.data);
break;
case 'TRANSACTION_FAILED':
this.handleTransactionError(message.error);
break;
case 'INSUFFICIENT_FUNDS':
this.handleInsufficientFunds();
break;
case 'WALLET_PROVIDER_CHANGED':
this.handleProviderChange(message.walletProviderName);
break;
}
});
});
}
// Transaction Methods
public async placeBet(direction: string, poolId: string, amount: number) {
if (!this.connected) {
PlaynanceIframeApp.openConnectWallet();
return;
}
if (this.currentBalance < amount) {
this.handleInsufficientFunds();
return;
}
PlaynanceIframeApp.requestTransaction(
direction,
poolId,
amount,
false // demo_mode
);
}
public async transfer(recipient: string, amount: number, token: string) {
if (!this.connected) {
PlaynanceIframeApp.openConnectWallet();
return;
}
PlaynanceIframeApp.requestTransferTransaction(recipient, amount, token);
}
public async interactWithContract(
contractAddress: string,
abi: any[],
methodName: string,
params: any[]
) {
try {
await PlaynanceIframeApp.requestContractTransaction(
contractAddress,
abi,
methodName,
params,
false // isReadOnly
);
} catch (error) {
console.error('Contract interaction failed:', error);
}
}
// Balance Management
public requestBalanceRefresh() {
PlaynanceIframeApp.requestBalanceUpdate();
}
// UI Update Methods
private updateBalanceUI() {
const balanceElement = document.getElementById('balance');
if (balanceElement) {
balanceElement.textContent = `${this.currentBalance.toFixed(4)} ETH`;
}
}
private handleWalletConnection(address: string | null) {
const statusElement = document.getElementById('connection-status');
if (statusElement) {
statusElement.textContent = address
? `Connected: ${address.slice(0, 6)}...${address.slice(-4)}`
: 'Not Connected';
}
}
private handleWalletDisconnection() {
this.connected = false;
this.currentBalance = 0;
this.updateBalanceUI();
this.handleWalletConnection(null);
}
private handleTransactionSuccess(data: any) {
// Implement transaction success UI updates
console.log('Transaction successful:', data);
// Request a balance update after successful transaction
this.requestBalanceRefresh();
}
private handleTransactionError(error: string) {
// Implement error handling UI updates
console.error('Transaction failed:', error);
}
private handleInsufficientFunds() {
// Implement insufficient funds UI feedback
console.error('Insufficient funds for transaction');
}
private handleProviderChange(providerName: string | null) {
// Handle wallet provider changes
console.log('Wallet provider changed to:', providerName);
}
}
// Usage
const iframeApp = new IframeAppImplementation();
// Example button click handlers
document.getElementById('bet-button')?.addEventListener('click', () => {
iframeApp.placeBet('UP', 'pool-1', 0.1);
});
document.getElementById('transfer-button')?.addEventListener('click', () => {
iframeApp.transfer('0xRecipientAddress', 0.5, 'ETH');
});
document.getElementById('refresh-balance')?.addEventListener('click', () => {
iframeApp.requestBalanceRefresh();
});API Reference
PlaynanceMainApp
- init(options: PlaynanceMainAppOptions): Initialize the main app
- handleIncomingMessage(event, iframeWindow, walletAddress): Process messages from iframe
- updateWalletProvider(walletProviderName, iframeWindow): Update the wallet provider
- sendBalanceToIframe(iframeWindow, balance): Send balance updates to iframe
- sendWalletAddressToIframe(iframeWindow, address): Send wallet address to iframe
- startLiveBalanceUpdates(iframeWindow, balanceUpdater): Start periodic balance updates
- sendCustomDataToIframe(iframeWindow, data): Send custom data to iframe
PlaynanceIframeApp
- init(options: PlaynanceIframeAppOptions): Initialize the iframe app
- handleIncomingMessage(event, callback): Process messages from main app
- requestTransaction(dir, poolId, bid, demo_mode): Request a transaction
- requestTransferTransaction(to, amount, token): Request a transfer
- requestContractTransaction(address, abi, method, params, isReadOnly): Request contract interaction
- requestBalanceUpdate(): Request balance update from main app
- checkWalletConnection(): Check wallet connection status
- startWalletConnectionCheck(interval): Start periodic connection checks
- stopWalletConnectionCheck(): Stop connection checks
- openConnectWallet(): Trigger wallet connection
Message Types
WALLET_ADDRESS: Wallet connection statusWALLET_PROVIDER_CHANGED: Wallet provider updatesREQUEST_BALANCE_UPDATE: Balance update requestsTRANSACTION_SUCCESS: Successful transactionsTRANSACTION_FAILED: Failed transactionsINSUFFICIENT_FUNDS: Balance checksCONTRACT_TRANSACTION: Contract interactionsCUSTOM_DATA: Custom data exchange
Security Considerations
- Origin Validation: Always specify and validate allowed origins
- Message Validation: Validate all incoming messages
- Provider Security: Secure handling of wallet providers
- Balance Verification: Double-check balances before transactions
- Error Handling: Proper error handling for all operations
License
MIT License
Author
Created by Or Konstantin
