@bigmi/client
Version:
Reactive primitives for Bitcoin apps.
130 lines • 5.28 kB
JavaScript
import { base64ToHex, hexToBase64 } from '@bigmi/core';
import { MethodNotSupportedRpcError, UserRejectedRequestError, } from '@bigmi/core';
import { ProviderNotFoundError } from '../errors/connectors.js';
import { createConnector } from '../factories/createConnector.js';
dynamic.type = 'UTXO';
export function dynamic(parameters) {
const { chainId, shimDisconnect = true, wallet } = parameters;
let accountChanged;
return createConnector((config) => ({
id: wallet.connector.providerId,
name: wallet.connector.name,
type: dynamic.type,
icon: wallet.connector._metadata?.icon,
emitter: config.emitter,
async isAuthorized() {
return wallet.isAuthenticated;
},
async request({ method, params }) {
switch (method) {
case 'signPsbt': {
try {
const { psbt, ...options } = params;
const allowedSighash = options.inputsToSign.map((input) => Number(input.sigHash));
const psbtBase64 = hexToBase64(psbt);
const response = await wallet.signPsbt({
allowedSighash,
unsignedPsbtBase64: psbtBase64,
signature: options.inputsToSign,
});
if (!response) {
throw new Error('Error signing the transaction');
}
const { signedPsbt } = response;
const signedPsbtHex = base64ToHex(signedPsbt);
return signedPsbtHex;
}
catch (error) {
throw new UserRejectedRequestError(error.message);
}
}
default:
throw new MethodNotSupportedRpcError();
}
},
async setup() {
//
},
async getProvider() {
const internalProvider = await this.getInternalProvider();
if (!internalProvider) {
throw new ProviderNotFoundError();
}
const provider = {
request: this.request.bind(internalProvider),
};
return provider;
},
async connect() {
if (!wallet.connector) {
throw new Error('DynamicWalletConnector not defined');
}
try {
const accounts = await this.getAccounts();
const chainId = await this.getChainId();
if (!accountChanged) {
accountChanged = this.onAccountsChanged.bind(this);
wallet.connector.addListener('accountChange', ({ accounts }) => accountChanged?.(accounts));
}
// Remove disconnected shim if it exists
if (shimDisconnect) {
await Promise.all([
config.storage?.setItem(`${this.id}.connected`, true),
config.storage?.removeItem(`${this.id}.disconnected`),
]);
}
return { accounts, chainId };
}
catch (error) {
throw new UserRejectedRequestError(error.message);
}
},
async disconnect() {
const provider = wallet.connector;
if (accountChanged) {
provider.removeListener('accountChange', ({ accounts }) => accountChanged?.(accounts));
accountChanged = undefined;
}
if (shimDisconnect) {
await Promise.all([
config.storage?.setItem(`${this.id}.disconnected`, true),
config.storage?.removeItem(`${this.id}.connected`),
]);
}
},
async getAccounts() {
const paymentAdress = wallet.additionalAddresses.find((wallet) => wallet.type === 'payment');
if (!paymentAdress) {
throw new Error('Please connect a wallet with a segwit address');
}
return [paymentAdress.address];
},
async getChainId() {
return chainId;
},
async getInternalProvider() {
return wallet.connector;
},
async onAccountsChanged(accounts) {
if (accounts.length === 0) {
this.onDisconnect();
}
else {
config.emitter.emit('change', {
accounts: accounts,
});
}
},
onChainChanged(chain) {
const chainId = Number(chain);
config.emitter.emit('change', { chainId });
},
async onDisconnect(_error) {
// No need to remove `${this.id}.disconnected` from storage because `onDisconnect` is typically
// only called when the wallet is disconnected through the wallet's interface, meaning the wallet
// actually disconnected and we don't need to simulate it.
config.emitter.emit('disconnect');
},
}));
}
//# sourceMappingURL=dynamic.js.map