The SignX SDK provides an easy way to integrate mobile-to-web authentication and transaction signing using the IXO blockchain in your applications.
This repo and product is intentionally managed as Open Source and we aim to use this guide to light our way https://opensource.guide/. Let us know how we are doing!
📝 Description
The SignX SDK orchestrates a seamless and secure interaction between client applications, a mobile app, and a server, encapsulating the complexities of mobile-to-web authentication and transaction signing on the IXO blockchain. The flow is initiated when a client application triggers a login request through the SDK, which in turn generates a unique identifier and a secure hash. This information is encoded into a QR code that is displayed to the user. Upon scanning this QR code with the mobile app, the user's account details are securely transmitted to the server.
During this phase, the SDK engages in a polling mechanism, continually checking the server for the authentication response corresponding to the QR code data. This ensures that the client application is updated in near real-time once the user has completed the scanning process. The SDK has built-in error handling and timeout features to manage scenarios where the response from the server is delayed or unsuccessful. Upon receiving a successful response from the server, the SDK triggers an event notifying the client application of the successful login, and provides the user's account details for further interactions.
With the user now authenticated, the SDK facilitates transaction operations. When a transaction is initiated through the SDK, it packages the necessary transaction data and securely transmits this, along with a unique transaction hash, to the server. Similar to the login flow, a QR code is generated for the user to scan using the mobile app. This QR code encodes information required for the mobile app to retrieve the transaction data from the server, sign the transaction, and broadcast it to the IXO blockchain.
Post the QR code generation, the SDK re-engages its polling mechanism, constantly checking the server for updates regarding the transaction status. The mobile app, after broadcasting the transaction, uploads the transaction response to the server. Once the server processes this response, it updates the transaction status which is then picked up by the SDK in one of its polling iterations. Upon receiving a successful or failed transaction response, the SDK emits an event to inform the client application of the outcome, thus completing the transaction flow.
Through this orchestrated flow, the SignX SDK abstracts the technical intricacies, providing a straightforward and secure way for client applications to leverage mobile-to-web authentication and transaction signing on the IXO blockchain.
The SDK is crafted to interact harmoniously with a designated server, which handles the storage and provides the necessary endpoints for polling data during the authentication and transaction processes. To fully leverage the SDK's capabilities and ensure a streamlined operation, it is essential to set up and utilize the accompanying server, the source code for which can be found here.
🔨 Install
npminstall@ixo/signx-sdkyarnadd@ixo/signx-sdk
💻 Usage
This SDK exposes a client class SignX which can be instantiated in your client applications to interact with the SignX server and mobile app for various operations.
Import and initialize the SignX client in your application:
TRANSACT_DTO: The data transfer object for transactions:
typeTRANSACT_DTO= { address:string,// bech32 encoded address, as received from login (eg ixo123) did:string,// base64 encoded did, as received from login (eg did:x:1234) pubkey:string,// hex encoded pubkey, as receivced from login txBodyHex: string, // hex encoded raw txBodyBytes which can be encoded from the registry exported from @ixo/impactxclient-sdk npm package (eg registry.encodeTxBody({ messages, memo }))
timestamp: string, // stringified utc DateTime, add uniqueness for tx hash to prevent duplicates (eg new Date().toISOString())
};
Class SignX
Properties
timeout: The timeout for polling in milliseconds (default is 2 minutes).
pollingInterval: The interval between polling requests in milliseconds (default is 2.5 seconds).
network: The network type.
endpoint: The endpoint URL of the SignX server.
sitename: The name of your site. (shown on mobile app on request)
Methods
login: Initiates a login request and starts polling.
transact: Initiates a transaction and starts polling.
stopPolling: Stops the polling process.
📱 Examples
Example used in a React project:
let signXClient:SignX;let signXInitializing =false;exportconstinitializeSignX=async ( chainInfo:KEPLR_CHAIN_INFO_TYPE, walletUser?:USER,):Promise<USER|undefined> => {if (signXInitializing) return; signXInitializing =true;lethandleClose: () =>void;try {if (!chainInfo ||!chainInfo.chainId) thrownewError('No chain info found to initialize SignX');if (chainInfo.chainName !=='ixo') thrownewError('SignX only works on ixo chain'); signXClient =newSignX({ endpoint:'https://signx.devnet.ixo.earth', network:chainInfo.chainNetwork ||'mainnet', sitename:config.siteName ??'JAMBO dApp', });// if user already has an address or pubkey(already signed in), returnif (walletUser?.address ||walletUser?.pubKey) return walletUser;// get login data from client to display QR code and start pollingconstdata=awaitsignXClient.login({ pollingInterval:2000 });constcloseModal= () => {signXClient.off(SIGN_X_LOGIN_ERROR, () => {});signXClient.off(SIGN_X_LOGIN_SUCCESS, () => {});signXClient.stopPolling('Login cancelled',SIGN_X_LOGIN_ERROR); }; handleClose =renderModal( <SignXModaltitle='SignX Login'subtitle='Scan QR with your ImpactsX wallet'data={JSON.stringify(data)}timeout={signXClient.timeout} />, closeModal, );consteventData:any=awaitnewPromise((resolve, reject) => {consthandleSuccess= (data:any) => {signXClient.off(SIGN_X_LOGIN_ERROR, handleError); // Remove error listener once successfulresolve(data); };consthandleError= (error:any) => {signXClient.off(SIGN_X_LOGIN_SUCCESS, handleSuccess); // Remove success listener on errorreject(error); };signXClient.on(SIGN_X_LOGIN_SUCCESS, handleSuccess);signXClient.on(SIGN_X_LOGIN_ERROR, handleError); });handleClose(); // manually close the modal after event emittedreturn { name:eventData.data.name, address:eventData.data.address, pubKey:fromHex(eventData.data.pubKey), did:eventData.data.did, algo:eventData.data.algo, }; } catch (e) {console.error('ERROR::initializeSignX::', e);// handle error like sign out of walletconstevent=newEvent(EVENT_LISTENER_TYPE.wallet_logout);window.dispatchEvent(event); } finally { signXInitializing =false;if (handleClose) handleClose(); }};let signXBroadCastMessageBusy =false;exportconstsignXBroadCastMessage=async ( msgs:TRX_MSG[], memo ='', chainInfo:KEPLR_CHAIN_INFO_TYPE, wallet:WALLET,):Promise<string|null> => {if (signXBroadCastMessageBusy) returnnull; signXBroadCastMessageBusy =true;lethandleClose: () =>void;try {if (!chainInfo ||!chainInfo.chainId) thrownewError('No chain info found');if (chainInfo.chainName !=='ixo') thrownewError('SignX only works on ixo chain');if (!wallet.user) thrownewError('No user found to broadcast transaction');if (!signXClient) thrownewError('No signXClient found to broadcast transaction');constregistry=createRegistry();// get login data from client to display QR code and start pollingconstdata=awaitsignXClient.transact({ address:wallet.user.address, did:wallet.user.did!, pubkey:toHex(wallet.user.pubKey), timestamp:newDate().toISOString(), txBodyHex:toHex(registry.encodeTxBody({ messages: msgs asany, memo })), });constcloseModal= () => {signXClient.off(SIGN_X_TRANSACT_ERROR, () => {});signXClient.off(SIGN_X_TRANSACT_SUCCESS, () => {});signXClient.stopPolling('Transaction cancelled',SIGN_X_TRANSACT_ERROR); }; handleClose =renderModal( <SignXModaltitle='SignX Transaction'subtitle='Scan QR with your ImpactsX wallet'data={JSON.stringify(data)}timeout={signXClient.timeout} />, closeModal, );consteventData:any=awaitnewPromise((resolve, reject) => {consthandleSuccess= (data:any) => {signXClient.off(SIGN_X_TRANSACT_ERROR, handleError); // Remove error listener once successfulresolve(data); };consthandleError= (error:any) => {signXClient.off(SIGN_X_TRANSACT_SUCCESS, handleSuccess); // Remove success listener on errorreject(error); };signXClient.on(SIGN_X_TRANSACT_SUCCESS, handleSuccess);signXClient.on(SIGN_X_TRANSACT_ERROR, handleError); });handleClose(); // manually close the modal after event emittedconsole.log({ eventData });returneventData.data?.transactionHash; } catch (e) {console.error('ERROR::signXBroadCastMessage::', e);Toast.errorToast(`Transaction Failed`);returnnull; } finally { signXBroadCastMessageBusy =false;if (handleClose) handleClose(); }};
📃 License
This SDK is licensed under the Apache 2 License. See the LICENSE file for more information.