@wagmi/core
Version:
VanillaJS library for Ethereum
280 lines • 11.4 kB
JavaScript
import { numberToHex, SwitchChainError, UserRejectedRequestError, withRetry, } from 'viem';
import { parseAccount } from 'viem/utils';
import { createConnector } from '../connectors/createConnector.js';
import { ChainNotConfiguredError } from '../errors/config.js';
const tempoWalletIcon = 'data:image/svg+xml,<svg width="269" height="269" viewBox="0 0 269 269" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="269" height="269" fill="black"/><path d="M123.273 190.794H93.445L121.09 105.318H85.7334L93.445 80.2642H191.95L184.238 105.318H150.773L123.273 190.794Z" fill="white"/></svg>';
/**
* Connector for the Tempo Wallet dialog.
*/
export function tempoWallet(parameters = {}) {
const { dialog: dialogOption, host, icon = tempoWalletIcon, name, rdns, theme, ...providerParameters } = parameters;
return _setup({
createAdapter(accounts) {
return accounts.dialog({
dialog: dialogOption,
host,
icon,
name,
rdns,
theme,
});
},
icon,
id: rdns ?? 'xyz.tempo',
name: name ?? 'Tempo Wallet',
providerParameters,
rdns: rdns ?? 'xyz.tempo',
type: 'injected',
});
}
webAuthn.type = 'webAuthn';
/**
* Connector for a WebAuthn EOA.
*/
export function webAuthn(parameters = {}) {
const { authUrl, ceremony, icon, name, rdns, ...providerParameters } = parameters;
return _setup({
createAdapter(accounts) {
return ceremony
? accounts.webAuthn({ ceremony, icon, name, rdns })
: accounts.webAuthn({ authUrl, icon, name, rdns });
},
icon,
id: 'webAuthn',
name: name ?? 'EOA (WebAuthn)',
providerParameters,
rdns,
type: 'webAuthn',
});
}
dangerous_secp256k1.type = 'dangerous_secp256k1';
/**
* Connector for a Secp256k1 EOA.
*
* WARNING: NOT RECOMMENDED FOR PRODUCTION USAGE.
* This connector stores private keys in clear text, and are bound to the session
* length of the storage used.
*/
export function dangerous_secp256k1(parameters = {}) {
const { icon, name, privateKey, rdns, ...providerParameters } = parameters;
return _setup({
createAdapter(accounts) {
return accounts.dangerous_secp256k1({ icon, name, privateKey, rdns });
},
icon,
id: 'secp256k1',
name: name ?? 'EOA (Secp256k1)',
providerParameters,
rdns,
type: 'secp256k1',
});
}
function _setup(parameters) {
return createConnector((config) => {
const chains = config.chains;
let providerPromise;
let accountsChanged;
let chainChanged;
let connect;
let disconnect;
async function getAccountsModule() {
return await import('accounts').catch(() => {
throw new Error('dependency "accounts" not found');
});
}
async function getProvider() {
providerPromise ??= (async () => {
const accounts = await getAccountsModule();
return accounts.Provider.create({
...parameters.providerParameters,
adapter: parameters.createAdapter(accounts),
chains: config.chains,
transports: config.transports,
});
})();
return await providerPromise;
}
return {
icon: parameters.icon,
id: parameters.id,
name: parameters.name,
rdns: parameters.rdns,
type: parameters.type,
async connect(connectParameters = {}) {
const { chainId, isReconnecting, withCapabilities } = connectParameters;
const capabilities = 'capabilities' in connectParameters
? connectParameters.capabilities
: undefined;
let accounts = [];
let currentChainId;
if (isReconnecting) {
accounts = await this.getAccounts()
.then((accounts) => accounts.map((address) => ({ address, capabilities: {} })))
.catch(() => []);
}
try {
if (!accounts.length && !isReconnecting) {
const provider = await getProvider();
const response = (await provider.request({
method: 'wallet_connect',
params: [
{
...(chainId ? { chainId } : {}),
...(capabilities ? { capabilities } : {}),
},
],
}));
accounts = response.accounts;
}
currentChainId ??= await this.getChainId();
if (!currentChainId)
throw new ChainNotConfiguredError();
const provider = await getProvider();
if (connect) {
provider.removeListener('connect', connect);
connect = undefined;
}
if (!accountsChanged) {
accountsChanged = this.onAccountsChanged.bind(this);
provider.on('accountsChanged', accountsChanged);
}
if (!chainChanged) {
chainChanged = this.onChainChanged.bind(this);
provider.on('chainChanged', chainChanged);
}
if (!disconnect) {
disconnect = this.onDisconnect.bind(this);
provider.on('disconnect', disconnect);
}
return {
accounts: (withCapabilities
? accounts
: accounts.map((account) => account.address)),
chainId: currentChainId,
};
}
catch (error) {
const rpcError = error;
if (rpcError.code === UserRejectedRequestError.code)
throw new UserRejectedRequestError(rpcError);
throw rpcError;
}
},
async disconnect() {
const provider = await getProvider();
if (chainChanged) {
provider.removeListener('chainChanged', chainChanged);
chainChanged = undefined;
}
if (disconnect) {
provider.removeListener('disconnect', disconnect);
disconnect = undefined;
}
if (!connect) {
connect = this.onConnect?.bind(this);
if (connect)
provider.on('connect', connect);
}
await provider.request({ method: 'wallet_disconnect' });
},
async getAccounts() {
const provider = await getProvider();
return await provider.request({ method: 'eth_accounts' });
},
async getChainId() {
const provider = await getProvider();
return Number(await provider.request({ method: 'eth_chainId' }));
},
async getClient({ chainId } = {}) {
const provider = await getProvider();
// Always provide a JSON-RPC account; the SDK provider performs
// access key orchestration internally before signing.
const { address } = provider.getAccount({ accessKey: false });
return Object.assign(provider.getClient({ chainId }), {
account: parseAccount(address),
});
},
async getProvider() {
return await getProvider();
},
async isAuthorized() {
try {
const accounts = await withRetry(() => this.getAccounts());
return !!accounts.length;
}
catch {
return false;
}
},
onAccountsChanged(accounts) {
config.emitter.emit('change', {
accounts: accounts,
});
},
onChainChanged(chain) {
config.emitter.emit('change', { chainId: Number(chain) });
},
async onConnect(connectInfo) {
const accounts = await this.getAccounts();
if (accounts.length === 0)
return;
const chainId = Number(connectInfo.chainId);
config.emitter.emit('connect', { accounts, chainId });
const provider = await getProvider();
if (connect) {
provider.removeListener('connect', connect);
connect = undefined;
}
if (!accountsChanged) {
accountsChanged = this.onAccountsChanged.bind(this);
provider.on('accountsChanged', accountsChanged);
}
if (!chainChanged) {
chainChanged = this.onChainChanged.bind(this);
provider.on('chainChanged', chainChanged);
}
if (!disconnect) {
disconnect = this.onDisconnect.bind(this);
provider.on('disconnect', disconnect);
}
},
async onDisconnect(_error) {
const provider = await getProvider();
config.emitter.emit('disconnect');
if (chainChanged) {
provider.removeListener('chainChanged', chainChanged);
chainChanged = undefined;
}
if (disconnect) {
provider.removeListener('disconnect', disconnect);
disconnect = undefined;
}
if (!connect) {
connect = this.onConnect?.bind(this);
if (connect)
provider.on('connect', connect);
}
},
async setup() {
if (!connect) {
const provider = await getProvider();
connect = this.onConnect?.bind(this);
if (connect)
provider.on('connect', connect);
}
},
async switchChain({ chainId }) {
const chain = chains.find((chain) => chain.id === chainId);
if (!chain)
throw new SwitchChainError(new ChainNotConfiguredError());
const provider = await getProvider();
await provider.request({
method: 'wallet_switchEthereumChain',
params: [{ chainId: numberToHex(chainId) }],
});
return chain;
},
};
});
}
//# sourceMappingURL=Connectors.js.map