UNPKG

@luffalab/luffa-tron-sdk

Version:

luffa tron ts sdk

373 lines (350 loc) 11.4 kB
/* import { Buffer } from 'buffer'; globalThis.Buffer = Buffer; */ import { PostMessage } from './message'; import { IInitData, UserResponse, AccountInfo, UserResponseStatus, EndlessSignMessageInput, EndlessSignMessageOutput, EndlessSignAndSubmitTransactionInput, EndlessWalletTransactionType, UserRejection, NetworkInfo, ChainData, } from './types'; // web and WebView /// #if BUILD_PLATFORM !== 'MINIPROGRAM' /// #endif import { isApproveTx, isLuffa, isLuffaMiniProgram, isLuffaMiniProgramWebview } from './utils'; import { TronWebOptions } from 'tronWeb/lib/esm/types'; import { EndLessSDKEvent, EndLessSDKEventPayload, EndLessSDKEventType, IRequestData } from './message/types'; export { isLuffa, isLuffaMiniProgram, isLuffaMiniProgramWebview } from './utils'; export interface Metadata { title: string; url: string; origin: string; icon: string; gameId: string; userId: string; walletAddress: string; } export interface TronRequestParams { method: 'eth_requestAccounts' | string; params?: any; } export { EndLessSDKEvent } from './message/types'; export { UserResponseStatus, EndlessSendTransactionType, EndlessWalletTransactionType } from './types'; export type { UserResponse, AccountInfo, EndlessSignAndSubmitTransactionInput } from './types'; export enum MethodName { CONNECT = 'connect', GETACCOUNT = 'getAccount', DISCONNECT = 'disconnect', NETWORK_CHANGE = 'luffa_switchChain', SIGN_MESSAGE = 'signMessage', SEND_TRANSACTION = 'sendTransaction', SIGN_AND_SUBMIT_TRANSACTION = 'signAndSubmitTransaction', SIGN_TRANSACTION = 'signTransaction', SIGN_BUILD_TRANSACTION = 'signBuildTransaction', EVM_APPROVE = 'evmApprove', ACCOUNT_CHANGE = 'accountChange', } export class LuffaTronSdk { static readonly version: string = '1.0.4'; private static _instance: LuffaTronSdk; private message: PostMessage | null = null; private _metadata: Metadata = {} as Metadata; private _initData: IInitData = {} as IInitData; private accountAddress: string | null = null; private _wallet: any | null = null; static getIninData = (): IInitData => { if (LuffaTronSdk._instance) { return LuffaTronSdk._instance._initData; } else { return {} as IInitData; } }; static getAccountAddress = () => { if (LuffaTronSdk._instance) { return LuffaTronSdk._instance.accountAddress; } else { return null; } }; static setAccountAddress = (accountAddress: string | null) => { if (LuffaTronSdk._instance) { LuffaTronSdk._instance.accountAddress = accountAddress; } }; constructor(initData: TronWebOptions & { network: string }) { if (LuffaTronSdk._instance) return LuffaTronSdk._instance; this.message = new PostMessage(); this.getMetadata(); this.initConfig(initData); LuffaTronSdk._instance = this; } private initConfig(initData: TronWebOptions & { network: string }) { this._initData.callbackWalletName = 'tronWallet'; this._initData.network = initData.network; if (isLuffaMiniProgram()) { return; } // web and WebView /// #if BUILD_PLATFORM !== 'MINIPROGRAM' this._wallet = new window.TronWeb.TronWeb(initData); this._wallet.trx.sign = this.sendTransaction.bind(this); this._wallet.trx.signTransaction = this.sendTransaction.bind(this); const tronProvider = Object.freeze({ isTronLink: false, request: async (params: TronRequestParams) => { switch (params.method) { case 'eth_requestAccounts': return this.connect(); default: return { code: 4200, message: 'Unknown method called' }; } }, tronWeb: this._wallet, on: this.on, removeListener: this.off, }); Object.defineProperty(globalThis, 'tronWeb', { value: this._wallet, writable: false, configurable: false, enumerable: true }); Object.defineProperty(globalThis, 'tron', { value: tronProvider, writable: false, configurable: false, enumerable: true }); /// #endif } async sendTransaction(params: any) { if (!this.accountAddress) { const res = await this.connect(); this.accountAddress = res[0]; } const { isApprove, spender } = isApproveTx(params); console.log('isApprove: ', isApprove, spender); if (isApprove) { params.to = spender; return this.signTransaction(params, MethodName.EVM_APPROVE) } else { return this.signTransaction(params) } } changeNetwork(chainData: ChainData) { this.message?.sendMessage({ uuid: new Date().getTime().toString(), methodName: MethodName.NETWORK_CHANGE, metadata: this._metadata, data: { ...chainData, }, }); } private getMetadata() { if (!window) { return; } const iconLink = document.querySelector('link[rel="icon"]') || document.querySelector('link[rel="shortcut icon"]'); let iconUrl = iconLink?.getAttribute('href') || ''; if (iconUrl && !iconUrl.startsWith('http')) { iconUrl = new URL(iconUrl, window.location.origin).href; } this._metadata.title = window.document.title; this._metadata.url = window.location.href; this._metadata.origin = window.location.origin; this._metadata.icon = iconUrl; } request = (data: IRequestData, callback?: (data: unknown) => void) => { this.message?.sendMessage( { uuid: new Date().getTime().toString(), methodName: data.method, metadata: this._metadata, data: data.data, initData: data?.initData, }, callback ); }; getAccount = (): Promise<string[]> => { return new Promise((resolve) => { this.message?.sendMessage( { uuid: new Date().getTime().toString(), methodName: MethodName.GETACCOUNT, metadata: this._metadata, data: {}, }, (data) => { if (data?.account) { this.accountAddress = data.account; resolve([data.account]); } else { const res: UserResponse<AccountInfo> = { status: UserResponseStatus.REJECTED, message: data?.message || 'Wallet is not connected', }; resolve([]); } } ); }); }; connect = (): Promise<[string]> => { return new Promise((resolve, reject) => { this.message?.sendMessage( { uuid: new Date().getTime().toString(), methodName: MethodName.CONNECT, metadata: this._metadata, data: {}, }, (data) => { let res; if (data?.account) { this._wallet.setAddress(data.account); this.accountAddress = data.account; res = [data.account] as [string]; resolve(res); } else { res = { code: 4001, message: 'User rejected the request.', }; reject(res); } } ); }); }; disconnect = (callback?: (data: unknown) => void): Promise<void> => { return new Promise((resolve, reject) => { this.message?.sendMessage( { uuid: new Date().getTime().toString(), methodName: MethodName.DISCONNECT, metadata: this._metadata, data: {}, }, (data: unknown) => { this.accountAddress = null; if (callback) callback(data); resolve(); } ); }); }; signMessage = ( data: EndlessSignMessageInput, callback?: (data: unknown) => void ): Promise<UserResponse<EndlessSignMessageOutput>> => { return new Promise((resolve) => { this.message?.sendMessage( { uuid: new Date().getTime().toString(), methodName: MethodName.SIGN_MESSAGE, metadata: this._metadata, data: data, }, (res) => { console.log('signMessage res: ', res); if (res?.signature) { const result: UserResponse<EndlessSignMessageOutput> = { status: UserResponseStatus.APPROVED, args: { fullMessage: data.message, signature: res.signature, publicKey: res.publicKey, nonce: '', message: data.message, prefix: 'Endless', }, }; resolve(result); } else { const result: UserRejection = { status: UserResponseStatus.REJECTED, message: res?.message }; resolve(result); } if (callback) callback(res); } ); }); }; on = <K extends EndLessSDKEventType>(methodName: K, callback: (payload: EndLessSDKEventPayload<K>) => void) => { if (this.message?.addListener) { this.message?.addListener(methodName, callback); } }; off = <K extends EndLessSDKEventType>(methodName: K, callback?: (payload: EndLessSDKEventPayload<K>) => void) => { if (this.message?.removeListener) { this.message?.removeListener(methodName, callback); } }; signAndSubmitTransaction = (params: any): Promise<any> => { console.log('signAndSubmitTransaction data: ', params); return new Promise(async (resolve) => { this.message?.sendMessage( { uuid: new Date().getTime().toString(), methodName: MethodName.SIGN_AND_SUBMIT_TRANSACTION, metadata: this._metadata, data: params }, (res) => { if (res?.hash) { resolve(res.hash); } else { resolve({ code: 4001, message: res?.message }); } } ); }); }; signTransaction = (params: any, methodName = MethodName.SIGN_BUILD_TRANSACTION): Promise<any> => { return new Promise(async (resolve, reject) => { const data: { raw_data_hex: string; to?: string } = { raw_data_hex: params.raw_data_hex } if (params.to) { data.to = params.to; } this.message?.sendMessage( { uuid: new Date().getTime().toString(), methodName, metadata: this._metadata, data, }, (res) => { const signature = res?.signature?.split(',') || []; console.log('luffa tron signature: ', signature); if (Array.isArray(signature) && signature.length > 0) { const result = { ...params, signature }; resolve(result); } else { reject('Confirmation declined by user'); } } ); }); }; onAccountChange = (callback: (data: AccountInfo) => void) => { this.on(EndLessSDKEvent.ACCOUNT_CHANGE, callback); }; onNetworkChange = (callback: (data: NetworkInfo) => void) => { this.on(EndLessSDKEvent.NETWORK_CHANGE, callback); }; }