@creit.tech/stellar-wallets-kit
Version:
A kit to handle all Stellar Wallets at once
208 lines (204 loc) • 8.37 kB
JavaScript
;
var TrezorConnect = require('@trezor/connect-web');
var connectPluginStellar = require('@trezor/connect-plugin-stellar');
var stellarBase = require('@stellar/stellar-base');
var rxjs = require('rxjs');
var store = require('../state/store.cjs');
var types = require('../types.cjs');
var utils = require('../utils.cjs');
const TREZOR_ID = 'TREZOR';
class TrezorModule {
constructor(params) {
this.TrezorConnect = 'default' in TrezorConnect ? TrezorConnect.default : TrezorConnect;
this._isAvailable = false;
this.moduleType = types.ModuleType.HW_WALLET;
this.productId = TREZOR_ID;
this.productName = 'Trezor';
this.productUrl = 'https://www.trezor.com/';
this.productIcon = 'https://stellar.creit.tech/wallet-icons/trezor.png';
this.TrezorConnect.init({
manifest: {
appUrl: params.appUrl,
email: params.email,
},
// More advanced options
debug: params.debug || false,
lazyLoad: params.lazyLoad || false,
coreMode: params.coreMode || 'auto',
}).then(() => {
console.log('Trezor is ready');
this._isAvailable = true;
});
}
async disconnect() {
store.removeMnemonicPath();
store.removeHardwareWalletPaths();
}
/**
* `TrezorConnect` needs to be started before we can use it but because users most likely
* won't use their devices as soon as the site loads, we return `true` since it should be already started
* once the user needs to interact with it.
*/
async isAvailable() {
return true;
}
async runChecks() {
if (!this._isAvailable) {
throw utils.parseError(new Error('Trezor connection has not been started yet.'));
}
}
async getAddress(opts) {
await this.runChecks();
try {
const mnemonicPath = opts?.path || (await rxjs.firstValueFrom(store.mnemonicPath$));
if (!mnemonicPath) {
const result = await this.openAccountSelector();
return { address: result.publicKey };
}
else {
const result = await this.TrezorConnect.stellarGetAddress({ path: mnemonicPath, showOnTrezor: false });
if (!result.success) {
throw utils.parseError(new Error(result.payload.error));
}
return { address: result.payload.address };
}
}
catch (e) {
throw utils.parseError(e);
}
}
/**
* This method is used by the Wallets Kit itself, if you're a dApp developer, most likely you don't need to use this method.
* @param page - {Number}
*/
async getAddresses(page = 0) {
const startIndex = page * 10;
const bundle = new Array(10)
.fill(undefined)
.map((_, i) => ({
path: `m/44'/148'/${i + startIndex}'`,
showOnTrezor: false,
}));
const result = await this.TrezorConnect.stellarGetAddress({ bundle });
if (!result.success) {
throw utils.parseError(new Error(result.payload.error));
}
const results = result.payload.map((item, i) => ({
publicKey: item.address,
index: i + startIndex,
}));
store.setHardwareWalletPaths(results);
return results;
}
/**
* This method is used by the Wallets Kit itself, if you're a dApp developer, most likely you don't need to use this method.
*/
async openAccountSelector() {
return new Promise((resolve, reject) => {
const el = document.createElement('stellar-accounts-selector');
el.setAttribute('showModal', '');
el.setAttribute('loadingAccounts', '');
document.body.appendChild(el);
this.getAddresses()
.then(addressesData => {
el.setAttribute('accounts', JSON.stringify(addressesData));
el.removeAttribute('loadingAccounts');
})
.catch(err => {
el.remove();
reject(err);
});
const listener = (event) => {
const { publicKey, index } = event.detail;
store.setMnemonicPath(`44'/148'/${index}'`);
resolve({ publicKey, index });
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
el.removeEventListener('account-selected', listener, false);
document.body.removeChild(el);
};
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
el.addEventListener('account-selected', listener, false);
const errorListener = (event) => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
el.removeEventListener('account-selected', listener, false);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
el.removeEventListener('account-selector-closed', errorListener, false);
document.body.removeChild(el);
reject(event.detail);
};
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
el.addEventListener('account-selector-closed', errorListener, false);
});
}
async signTransaction(xdr, opts) {
await this.runChecks();
let mnemonicPath;
let account;
if (opts?.path) {
mnemonicPath = opts.path;
const result = await this.TrezorConnect.stellarGetAddress({ path: mnemonicPath, showOnTrezor: false });
if (!result.success) {
throw new Error(result.payload.error);
}
account = result.payload.address;
}
else if (opts?.address) {
const paths = await rxjs.firstValueFrom(store.hardwareWalletPaths$);
const target = paths.find(p => p.publicKey === opts.address);
if (!target)
throw utils.parseError(new Error('This address has not been loaded from this device'));
mnemonicPath = `m/44'/148'/${target.index}'`;
account = target.publicKey;
}
else {
mnemonicPath = await rxjs.firstValueFrom(store.mnemonicPath$);
if (!mnemonicPath)
throw utils.parseError(new Error('There is no path available, please call the `getAddress` method first.'));
const result = await this.TrezorConnect.stellarGetAddress({ path: mnemonicPath, showOnTrezor: false });
if (!result.success) {
throw new Error(result.payload.error);
}
account = result.payload.address;
}
const network = opts?.networkPassphrase || (await rxjs.firstValueFrom(store.selectedNetwork$));
if (!network)
throw utils.parseError(new Error('You need to provide or set a network passphrase'));
const tx = new stellarBase.Transaction(xdr, network);
const parsedTx = connectPluginStellar.transformTransaction(mnemonicPath, tx);
const result = await this.TrezorConnect.stellarSignTransaction(parsedTx);
if (!result.success) {
throw utils.parseError(new Error(result.payload.error));
}
tx.addSignature(account, Buffer.from(result.payload.signature, 'hex').toString('base64'));
return {
signedTxXdr: tx.toXDR(),
signerAddress: account,
};
}
async signAuthEntry() {
throw {
code: -3,
message: 'Trezor Wallets do not support the "signAuthEntry" method',
};
}
async signMessage() {
throw {
code: -3,
message: 'Trezor Wallets do not support the "signMessage" method',
};
}
async getNetwork() {
throw {
code: -3,
message: 'Trezor Wallets do not support the "getNetwork" method',
};
}
}
exports.TREZOR_ID = TREZOR_ID;
exports.TrezorModule = TrezorModule;
//# sourceMappingURL=trezor.module.cjs.map