UNPKG

@luffalab/luffa-endless-sdk

Version:

luffa endless ts sdk

382 lines (361 loc) 12.2 kB
import { PostMessage } from './message'; import type { IRequestData } from './message/types'; import type { EndLessSDKEventType, EndLessSDKEventPayload } from './message/types'; import { EndLessSDKEvent } from './message/types'; import { IInitData, UserResponse, AccountInfo, UserResponseStatus, EndlessSignMessageInput, EndlessSignMessageOutput, EndlessSignAndSubmitTransactionInput, EndlessWalletTransactionType, UserRejection, NetworkInfo, } from './types'; // web and WebView /// #if BUILD_PLATFORM !== 'MINIPROGRAM' import { Endless, EndlessConfig, } from '@endlesslab/endless-ts-sdk'; /// #endif import { isLuffa, isLuffaMiniProgram, isLuffaMiniProgramWebview } from './utils'; export { isLuffa, isLuffaMiniProgram, isLuffaMiniProgramWebview } from './utils'; export interface Metadata { title: string; url: string; origin: string; icon: string; gameId: string; userId: string; walletAddress: string; } 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 = 'switchNetwork', SIGN_MESSAGE = 'signMessage', SEND_TRANSACTION = 'sendTransaction', SIGN_AND_SUBMIT_TRANSACTION = 'signAndSubmitTransaction', SIGN_BUILD_TRANSACTION = 'signBuildTransaction', ACCOUNT_CHANGE = 'accountChange', } export class EndlessLuffaSdk { static readonly version: string = '1.0.5'; private static _instance: EndlessLuffaSdk; private message: PostMessage | null = null; private _metadata: Metadata = {} as Metadata; private _initData: IInitData = {} as IInitData; private _endless: any | null = null; private _endlessConfig: EndlessConfig | null = null; private accountAddress: string | null = null; static getIninData = (): IInitData => { if (EndlessLuffaSdk._instance) { return EndlessLuffaSdk._instance._initData; } else { return {} as IInitData; } }; static getAccountAddress = () => { if (EndlessLuffaSdk._instance) { return EndlessLuffaSdk._instance.accountAddress; } else { return null; } }; static setAccountAddress = (accountAddress: string | null) => { if (EndlessLuffaSdk._instance) { EndlessLuffaSdk._instance.accountAddress = accountAddress; } }; constructor(initData: IInitData) { if (EndlessLuffaSdk._instance) return EndlessLuffaSdk._instance; this.message = new PostMessage(); this.initWalletEvent(); this.getMetadata(); this.initConfig(initData); EndlessLuffaSdk._instance = this; } private initConfig(initData: IInitData) { if (isLuffaMiniProgram()) { this._initData.network = initData.network; return; } // web and WebView /// #if BUILD_PLATFORM !== 'MINIPROGRAM' this._initData.network = initData.network; this._endlessConfig = new EndlessConfig({ network: initData.network as unknown as any, miniprogram: initData.miniprogram }); this._endless = new Endless(this._endlessConfig); /// #endif } private initWalletEvent() { this.on(EndLessSDKEvent.NETWORK_CHANGE, (payload) => { this.initConfig({ network: payload.name, }); }); } changeNetwork(initData: IInitData) { this.message?.sendMessage({ uuid: new Date().getTime().toString(), methodName: MethodName.NETWORK_CHANGE, metadata: this._metadata, data: { ...this._initData, ...initData, }, }); } 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<UserResponse<AccountInfo>> => { 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; const res: UserResponse<AccountInfo> = { status: UserResponseStatus.APPROVED, args: { ...data }, }; resolve(res); } else { const res: UserResponse<AccountInfo> = { status: UserResponseStatus.REJECTED, message: data?.message || 'Wallet is not connected', }; resolve(res); } } ); }); }; connect = (callback?: (data: AccountInfo) => void): Promise<UserResponse<AccountInfo>> => { return new Promise((resolve) => { this.message?.sendMessage( { uuid: new Date().getTime().toString(), methodName: MethodName.CONNECT, metadata: this._metadata, data: {}, }, (data) => { if (data.account) { this.accountAddress = data.account; const res: UserResponse<AccountInfo> = { status: UserResponseStatus.APPROVED, args: { ...data }, }; resolve(res); } else { const res: UserResponse<AccountInfo> = { status: UserResponseStatus.REJECTED, message: data?.message }; resolve(res); } if (callback) callback({ ...data }); } ); }); }; 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 = (data: EndlessSignAndSubmitTransactionInput): Promise<UserResponse<{ hash: string }>> => { return new Promise(async (resolve) => { if (!this.accountAddress) { const result: UserRejection = { status: UserResponseStatus.REJECTED, message: 'Wallet not linked' }; resolve(result); return; } let transaction; if (isLuffa() || isLuffaMiniProgramWebview()) { if (!this._endless) { const result: UserRejection = { status: UserResponseStatus.REJECTED, message: 'Wallet not linked' }; resolve(result); return; } transaction = await this._endless.transaction.build.simple({ sender: this.accountAddress, data: data.payload, options: { ...(data.options || {}), }, }); transaction = transaction.bcsToHex().toString(); } else if (isLuffaMiniProgram()) { // TODO MiniProgram build transaction transaction = data; } this.message?.sendMessage( { uuid: new Date().getTime().toString(), methodName: MethodName.SIGN_AND_SUBMIT_TRANSACTION, metadata: this._metadata, data: { serializedTransaction: { data: transaction, sender: this.accountAddress, }, }, }, (res) => { console.log('signAndSubmitTransaction res: ', res); if (res.hash) { const result: UserResponse<{ hash: string }> = { status: UserResponseStatus.APPROVED, args: { hash: res.hash, }, }; resolve(result); } else { const result: UserRejection = { status: UserResponseStatus.REJECTED, message: res?.message }; resolve(result); } } ); }); }; signTransaction = ( transactionHex: string, transactionType: EndlessWalletTransactionType = EndlessWalletTransactionType.SIMPLE ): Promise<UserResponse<{ data: string }>> => { return new Promise(async (resolve) => { if (!this.accountAddress || !this._endless) { const result: UserRejection = { status: UserResponseStatus.REJECTED, message: 'Wallet not linked' }; resolve(result); return; } this.message?.sendMessage( { uuid: new Date().getTime().toString(), methodName: MethodName.SIGN_BUILD_TRANSACTION, metadata: this._metadata, data: { transactionData: transactionHex, sender: this.accountAddress, type: transactionType }, }, (res) => { if (res.signature) { const result = { status: UserResponseStatus.APPROVED, args: { data: res.signature }, }; resolve(result); } else { const result: UserRejection = { status: UserResponseStatus.REJECTED, message: res?.message }; resolve(result); } } ); }); }; onAccountChange = (callback: (data: AccountInfo) => void) => { this.on(EndLessSDKEvent.ACCOUNT_CHANGE, callback); }; onNetworkChange = (callback: (data: NetworkInfo) => void) => { this.on(EndLessSDKEvent.NETWORK_CHANGE, callback); }; }