This guide provides step-by-step instructions for integrating the ImpactsX wallet functionality into your website without using the @ixo/jambo-wallet-sdk
. By following this guide, you'll be able to connect to the wallet, retrieve keys, and sign transactions using the impactsX
window object.
- You have a basic understanding of JavaScript and web development.
- Your website is whitelisted by Ixo for ImpactsX wallet access.
To start using the ImpactsX wallet, you need to connect to the desired blockchain network and validate your site against the whitelist. Use the enable
method to achieve this:
// Method signature: (chainNameOrId: string, chainNetwork?: ChainNetwork) => Promise<void>
// Option 1: Connect using the chainId
const chainId = 'ixo-5'; // The chain ID corresponding to the active app chain
await impactsX.enable(chainId);
// Option 2: Connect using the chainName and chainNetwork
const chainName = 'impacthub'; // The chain name from Cosmos chain registry
const chainNetwork = 'mainnet'; // or 'testnet', 'devnet'
await impactsX.enable(chainName, chainNetwork);
Please note:
- You can choose either the
chainId
or the combination ofchainName
andchainNetwork
to connect. - This step enables your site's connection to specific chain keys and signing but is currently limited to the current chain and chain network active in the app. If the site's chain doesn't match the app's, the connection will be rejected.
- This step also validates your site against the whitelist. It's crucial to call
impactsX.enable
before any other method, or the other methods will error out. - The whitelist validation remains effective only while the site is present in the Impacts X app browser. Navigating away from the site, even briefly, will reset the permissions, requiring the site to call
impactsX.enable
again upon re-entry.
You can retrieve keys associated with a specific chain (currently only the active chain in the app) using the impactsX.getKey
method:
const chainId = 'ixo-5'; // The chain ID you're connected to
const includeDid = true; // Set to true if you want to include DID information
const key = await impactsX.getKey(chainId, includeDid);
// key = {
// name: string
// algo: Algo
// pubKey: string
// address: string
// bech32Address: string
// isNanoLedger: boolean
// isKeystone: boolean
// did?: string
// }
Please note:
- If you expected
pubKey
andaddress
to be of type Uint8Array, you're correct. The ImpactsX Wallet can only accept and return string values. Thus, theaddress
andpubKey
values in the returned key object are Uint8Array values encoded to strings using thetoHex
function from the@cosmjs/encoding
package. To obtain the appropriate Uint8Array values, decode these values as follows:
import { fromHex } from '@cosmjs/encoding';
// ...
const pubKey = fromHex(key.pubKey);
To sign transactions, you'll need an offlineSigner. However, using the offlineSigner directly from the impactsX
window object will cause unexpected errors. Similar to step 2, the methods inside offlineSigner can only accept and return strings. Thus, you'll need to create your own offline signer with the impactsX.getAccounts
and the impactsX.signDirect
methods and encode or decode the values where necessary.
// Method signature: (chainId: string) => Promise<{ address: string; algo: Algo; pubkey: string; }[]>
import { fromHex } from '@cosmjs/encoding';
const chainId = 'ixo-5';
// create new `getAccounts` that decodes hex values to Uint8Array and removes chainId param
const getAccounts = async () => {
const accounts = await impactsX.getAccounts(chainId);
const decodedAccounts = accounts.map((account) => ({ ...account, pubKey: fromHex(account.pubkey) }));
return decodedAccounts;
};
Please note:
- In the offlineSigner, the
getAccounts
methods require no chainId, whereasimpactsX.getAccounts
requires the chainId for it to function as needed. Hence, it's pre-generated and passed in when we recreate the getAccounts method. - With
impactsX.getAccounts
, the pubkey is a hex-encoded Uint8Array value. All other values are correct, and only the pubkey must be decoded.
// Method signature: (signerAddress: string, signDoc: { bodyBytes: string, authInfoBytes: string, chainId: string, accountNumber: string }): Promise<{ signed: { bodyBytes: string, authInfoBytes: string, chainId: string, accountNumber: string }, signature: { signature: string, pub_key: { type: string, value: any } } }>
import { toHex } from '@cosmjs/encoding';
// create new `signDirect` that encodes `Uint8Array` values from the params and decodes hex values to `Uint8Array` from the response
const signDirect = async (signerAddress, signDoc) => {
const encodedSignDoc = {
...signDoc,
bodyBytes: toHex(signDoc.bodyBytes),
authInfoBytes: toHex(signDoc.authInfoBytes),
accountNumber: signDoc.accountNumber.toString(),
};
const response = await impactsX.signDirect(encodedSignDoc);
const decodedResponse = {
...response,
signed: signDoc,
};
return decodedResponse;
};
Please note:
- The signDoc passed into
impactsX.signDirect
must have all its Uint8Array values encoded to hex strings via@cosmjs/encoding
. - The response from
impactsX.signDirect
will contain Uint8Array encoded values which should be decoded. - The signing won't happen automatically; it requires user biometric authentication.
Now you can create your own offlineSigner with the getAccounts and signDirect functions you just created and pass this offlineSigner to the signing client to sign and broadcast transactions.
const offlineSigner = { getAccounts, signDirect };
const client = await createSigningClient(chainRpcEndpoint, offlineSigner);
// sendTransaction(SigningClient, SignerAddress, { trx: msg[], chainId: string; fee: StdFee; memo?: string })
const result = await sendTransaction(client, address, payload);
console.log(result.hash); // Transaction hash
Impacts X will under no circumstances hand over a user's mnemonic or private keys, so there's no use in trying to extract them.
By following these integration steps, you'll be able to seamlessly incorporate ImpactsX wallet functionality into your website. Feel free to use the @ixo/jambo-wallet-sdk for automatic encryption/decryption and easier integration.