@bigmi/client
Version:
Reactive primitives for Bitcoin apps.
130 lines (129 loc) • 5.76 kB
JavaScript
import { createConnector } from "../factories/createConnector.js";
import { debounce } from "../utils/debounce.js";
import { ChainId, MethodNotSupportedRpcError, ProviderNotFoundError, UserRejectedRequestError, base64ToHex, hexToBase64 } from "@bigmi/core";
//#region src/connectors/xverse.ts
function xverse(parameters = {}) {
const XverseBitcoinChainIdMap = {
Mainnet: ChainId.BITCOIN_MAINNET,
Testnet: ChainId.BITCOIN_TESTNET,
Testnet4: ChainId.BITCOIN_TESTNET4,
Signet: ChainId.BITCOIN_SIGNET
};
const { shimDisconnect = true } = parameters;
let accountChange;
let chainChange;
return createConnector((config) => ({
id: "XverseProviders.BitcoinProvider",
name: "Xverse Wallet",
type: xverse.type,
icon: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MDAiIGhlaWdodD0iNjAwIj48ZyBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGZpbGw9IiMxNzE3MTciIGQ9Ik0wIDBoNjAwdjYwMEgweiIvPjxwYXRoIGZpbGw9IiNGRkYiIGZpbGwtcnVsZT0ibm9uemVybyIgZD0iTTQ0MCA0MzUuNHYtNTFjMC0yLS44LTMuOS0yLjItNS4zTDIyMCAxNjIuMmE3LjYgNy42IDAgMCAwLTUuNC0yLjJoLTUxLjFjLTIuNSAwLTQuNiAyLTQuNiA0LjZ2NDcuM2MwIDIgLjggNCAyLjIgNS40bDc4LjIgNzcuOGE0LjYgNC42IDAgMCAxIDAgNi41bC03OSA3OC43Yy0xIC45LTEuNCAyLTEuNCAzLjJ2NTJjMCAyLjQgMiA0LjUgNC42IDQuNUgyNDljMi42IDAgNC42LTIgNC42LTQuNlY0MDVjMC0xLjIuNS0yLjQgMS40LTMuM2w0Mi40LTQyLjJhNC42IDQuNiAwIDAgMSA2LjQgMGw3OC43IDc4LjRhNy42IDcuNiAwIDAgMCA1LjQgMi4yaDQ3LjVjMi41IDAgNC42LTIgNC42LTQuNloiLz48cGF0aCBmaWxsPSIjRUU3QTMwIiBmaWxsLXJ1bGU9Im5vbnplcm8iIGQ9Ik0zMjUuNiAyMjcuMmg0Mi44YzIuNiAwIDQuNiAyLjEgNC42IDQuNnY0Mi42YzAgNCA1IDYuMSA4IDMuMmw1OC43LTU4LjVjLjgtLjggMS4zLTIgMS4zLTMuMnYtNTEuMmMwLTIuNi0yLTQuNi00LjYtNC42TDM4NCAxNjBjLTEuMiAwLTIuNC41LTMuMyAxLjNsLTU4LjQgNTguMWE0LjYgNC42IDAgMCAwIDMuMiA3LjhaIi8+PC9nPjwvc3ZnPg==",
async setup() {},
async getInternalProvider() {
if (typeof window === "undefined") return;
if ("XverseProviders" in window) return window.XverseProviders.BitcoinProvider;
},
async getProvider() {
const internalProvider = await this.getInternalProvider();
if (!internalProvider) return;
return { request: this.request.bind(internalProvider) };
},
async request({ method, params }) {
switch (method) {
case "signPsbt": {
const { psbt, ...options } = params;
const psbtBase64 = hexToBase64(psbt);
const signInputs = options.inputsToSign.reduce((signInputs, input) => {
if (!signInputs[input.address]) signInputs[input.address] = [];
signInputs[input.address].push(...input.signingIndexes);
return signInputs;
}, {});
const signedPsbt = await this.request("signPsbt", {
psbt: psbtBase64,
allowedSignHash: 1,
signInputs,
broadcast: options.finalize
});
if (signedPsbt?.error) throw signedPsbt?.error;
return base64ToHex(signedPsbt?.result?.psbt);
}
default: throw new MethodNotSupportedRpcError(method);
}
},
async connect({ isReconnecting } = {}) {
const provider = await this.getInternalProvider();
if (!provider) throw new ProviderNotFoundError();
if (!isReconnecting) {
const connected = await provider.request("wallet_requestPermissions");
if (connected.error) throw new UserRejectedRequestError(connected.error.message);
}
const accounts = await this.getAccounts();
const chainId = await this.getChainId();
if (!accountChange) {
accountChange = this.onAccountsChanged.bind(this);
provider.addListener("accountChange", accountChange);
}
if (!chainChange) {
chainChange = debounce((event) => this.onChainChanged(XverseBitcoinChainIdMap[event.bitcoin.name]), 300);
provider.addListener("networkChange", chainChange);
}
if (shimDisconnect) await Promise.all([config.storage?.setItem(`${this.id}.connected`, true), config.storage?.removeItem(`${this.id}.disconnected`)]);
return {
accounts,
chainId
};
},
async disconnect() {
const provider = await this.getInternalProvider();
if (!provider) throw new ProviderNotFoundError();
if (accountChange) {
provider.removeListener?.("accountChange", accountChange);
accountChange = void 0;
}
if (chainChange) {
provider.removeListener?.("networkChange", chainChange);
chainChange.cancel?.();
chainChange = void 0;
}
if (shimDisconnect) await Promise.all([config.storage?.setItem(`${this.id}.disconnected`, true), config.storage?.removeItem(`${this.id}.connected`)]);
},
async getAccounts() {
const provider = await this.getInternalProvider();
if (!provider) throw new ProviderNotFoundError();
const accounts = await provider.request("getAddresses", { purposes: ["payment"] });
if (!accounts.result) throw new UserRejectedRequestError(accounts.error?.message);
return accounts.result.addresses;
},
async getChainId() {
const provider = await this.getInternalProvider();
if (!provider) throw new ProviderNotFoundError();
const network = await provider.request("wallet_getNetwork");
if (!network.result) throw new UserRejectedRequestError(network.error?.message ?? "Unknown error");
return XverseBitcoinChainIdMap[network.result.bitcoin.name];
},
async isAuthorized() {
try {
return shimDisconnect && Boolean(await config.storage?.getItem(`${this.id}.connected`));
} catch {
return false;
}
},
async onAccountsChanged() {
const { accounts } = await this.connect();
config.emitter.emit("change", { accounts });
},
async onChainChanged() {
const { accounts, chainId } = await this.connect();
config.emitter.emit("change", {
chainId,
accounts
});
},
async onDisconnect(_error) {
config.emitter.emit("disconnect");
}
}));
}
xverse.type = "UTXO";
//#endregion
export { xverse };
//# sourceMappingURL=xverse.js.map