UNPKG

@luffalab/luffa-tron-sdk

Version:

luffa tron ts sdk

299 lines (279 loc) 9.2 kB
import { AccountInfo, LuffaTronSdk, MethodName } from '../index'; import type { IMessageData, TronSDKEventListenersType, TronSDKEventPayload, TronSDKEventType } from './types'; import { TronSDKEvent, IResponseMessageData } from './types'; import { isLuffaMiniProgramWebview, isLuffaMiniProgram, isLuffa, networkMap, getChainIdByName } from '../utils'; export class PostMessage { private static _instance: PostMessage; callbacks: { [key: string]: (data: unknown) => void; } = {}; private listeners: TronSDKEventListenersType = {}; constructor() { if (PostMessage._instance) return PostMessage._instance; PostMessage._instance = this; if (isLuffa()) { window.tronWallet = { sendResponse: this.sendResponse.bind(this), }; } } // wallet emit sdk // SDK processing method itself private readonly receive = (msg: { data: IResponseMessageData }) => { const eventType = msg.data.methodName as TronSDKEventType | MethodName; // sdk callbacks if (this.callbacks[msg.data.uuid + eventType]) { this.callbacks[msg.data.uuid + eventType](msg.data.data); delete this.callbacks[msg.data.uuid + eventType]; } // Some events are being monitored by dapp and require running a monitoring callback switch (eventType) { case TronSDKEvent.NETWORK_CHANGE: { let network = msg.data.data.network; if (!network) break; if (isLuffaMiniProgram()) { network = msg.data.data; } this.emit(eventType, network); this.emit(TronSDKEvent.CHAIN_CHANGED, `0x${getChainIdByName(network)?.toString(16)}`); break; } // wallet to sdk send onAccountChange | connect // sdk to dapp send event // CONNECT and ACCOUNT_CHANGE return account as AccountAddress case TronSDKEvent.CONNECT: case TronSDKEvent.ACCOUNT_CHANGE: { const accountInfo: AccountInfo = { ...msg.data.data, }; if (msg?.data?.data?.account) { LuffaTronSdk.setAccountAddress(msg.data.data.account); } else { LuffaTronSdk.setAccountAddress(null); } this.emit(eventType, accountInfo); break; } case TronSDKEvent.DISCONNECT: { LuffaTronSdk.setAccountAddress(null); this.emit(eventType, msg.data.data); break; } default: this.emit(eventType as TronSDKEventType, msg.data.data); break; } }; readonly addListener = <K extends TronSDKEventType>( methodName: K, callback: (payload: TronSDKEventPayload<K>) => void ) => { if (!this.listeners[methodName]) { this.listeners[methodName] = []; } this.listeners[methodName].push(callback); }; readonly removeListener = <K extends TronSDKEventType>( methodName: K, callback?: (payload: TronSDKEventPayload<K>) => void ) => { if (callback) { const index = this.listeners[methodName]?.indexOf(callback) ?? -1; if (index > -1) { this.listeners?.[methodName]?.splice(index, 1); } } else { this.listeners[methodName] = []; } }; readonly emit = <K extends TronSDKEventType>(methodName: K, payload: TronSDKEventPayload<K>) => { this.listeners?.[methodName]?.forEach((d) => d(payload)); this.emitTronEvent(methodName, payload); }; private emitTronEvent<K extends TronSDKEventType>(methodName: K, payload: TronSDKEventPayload<K>) { if (typeof window === 'undefined' || !window.tron) return; let tronPayload: any; switch (methodName) { case TronSDKEvent.CONNECT: case TronSDKEvent.ACCOUNT_CHANGE: const account = (payload as AccountInfo)?.account || (payload as AccountInfo)?.address; tronPayload = { action: 'accountsChanged', data: { address: account, } }; break; case TronSDKEvent.DISCONNECT: tronPayload = undefined; break; default: tronPayload = payload; break; } try { const event = new MessageEvent('message', { data: { isTronLink: true, message: tronPayload, } }); window.dispatchEvent(event); } catch (error) { console.warn('Failed to emit tron event:', error); } } readonly sendMessage = (data: IMessageData, callback?: (data: any) => void) => { try { if (isLuffa()) { this.sendLuffaMessage(data, callback); return; } if (isLuffaMiniProgram() || isLuffaMiniProgramWebview()) { this.sendMiniProgramMessage(data, callback); return; } } catch (error) { console.error('sendMessage error: ', error); } }; private sendLuffaMessage(data: IMessageData, callback?: (data: any) => void) { const initData = data?.initData || LuffaTronSdk.getIninData(); (data.initData = { ...(initData || {}), network: networkMap[initData.network] ?? initData.network, }), (data.from = LuffaTronSdk.getAccountAddress()); if (callback) { this.callbacks[data.uuid + data.methodName] = callback; } console.log('luffa tron sendLuffaMessage: ', data); if (window?._tronWallet) { window._tronWallet?.sendMessage(JSON.stringify(data)); } else if (window?.webkit && window?.webkit?.messageHandlers?._tronWallet) { window.webkit.messageHandlers._tronWallet?.postMessage(data); } } private sendResponse(response: string) { console.log('luffa tron sendResponse: ', response); const responseData = JSON.parse(response); console.log('luffa tron responseData: ', responseData); this.receive({ data: responseData, }); } private sendMiniProgramMessage(data: IMessageData, callback?: (data: any) => void) { let funName = 'invokeNativePlugin'; const accountAddress = LuffaTronSdk.getAccountAddress(); const initData = LuffaTronSdk.getIninData(); let api_name = 'luffaWebRequest'; let params = { api_name, data: { func: data.methodName, chainType: 'endless', ...data, initData: { ...initData, network: networkMap[initData.network] ?? initData.network, }, from: accountAddress, }, }; let callbackSuccessFun = (res: any) => { callback && callback({ status: 'success', ...(res.data || {}), }); }; let callbackErrorFun = (res: any) => { callback && callback({ status: 'error', ...(res.data || {}), }); }; switch (data.methodName) { case MethodName.CONNECT: case MethodName.GETACCOUNT: callbackSuccessFun = (res) => { LuffaTronSdk.setAccountAddress(res.data.account); callback && callback({ account: res?.data?.address || '', ...(res.data || {}), }); }; callbackErrorFun = (res) => { callback && callback({ account: '', }); }; break; case MethodName.SIGN_MESSAGE: case MethodName.SIGN_TRANSACTION: case MethodName.SIGN_BUILD_TRANSACTION: case MethodName.SIGN_AND_SUBMIT_TRANSACTION: case MethodName.EVM_APPROVE: callbackSuccessFun = (res: any) => { callback && callback({ status: 'success', ...(res.data || {}), }); }; callbackErrorFun = (res: any) => { callback && callback({ status: 'error', ...(res.data || {}), }); }; break; default: break; } console.log('luffa tron funName: ', funName); console.log('luffa tron params: ', params); if (isLuffaMiniProgram()) { wx[funName]({ ...params, complete: (res: any) => { console.log(`luffa tron wx ${funName} res: `, res); if (res.status === undefined) { callback && callback({ ...res, }); } else if (res.status === 'success') { callbackSuccessFun(res); this.receive({ data: res, }); } else { callbackErrorFun(res); } }, }); } else if (isLuffaMiniProgramWebview()) { window.WeixinJSBridge?.invoke(funName, params, (res) => { console.log(`luffa tron WeixinJSBridge ${funName} res: `, res); if (res.status === undefined) { callback && callback({ ...res, }); } else if (res.status === 'success') { callbackSuccessFun(res); this.receive({ data: res, }); } else { callbackErrorFun(res); } }); } } }