Skip to content

Instantly share code, notes, and snippets.

@riskers
Forked from jeftarmascarenhas/BinanceWallet.ts
Created May 5, 2023 14:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save riskers/b9d9050e83816a42251a0f5110d2b27e to your computer and use it in GitHub Desktop.
Save riskers/b9d9050e83816a42251a0f5110d2b27e to your computer and use it in GitHub Desktop.
Connector to Binance on Wagmi
import {
ConnectorNotFoundError,
UserRejectedRequestError,
RpcError,
ResourceUnavailableError,
SwitchChainNotSupportedError,
} from "wagmi";
import { InjectedConnector } from "wagmi/connectors/injected";
import { Chain, Ethereum } from "@wagmi/core";
import { hexValue } from "ethers/lib/utils.js";
declare global {
interface Window {
BinanceChain?: {
bnbSign?: (
address: string,
message: string
) => Promise<{ publicKey: string; signature: string }>;
switchNetwork?: (networkId: string) => Promise<string>;
} & Ethereum;
}
}
const mappingNetwork: Record<number, string> = {
1: "eth-mainnet",
56: "bsc-mainnet",
97: "bsc-testnet",
};
const _binanceChainListener = async () => {
new Promise<void>((resolve) =>
Object.defineProperty(window, "BinanceChain", {
get() {
return this.bsc;
},
set(bsc) {
this.bcs = bsc;
resolve();
},
})
);
};
export class BinanceWalletConnector extends InjectedConnector {
readonly id = "bsc";
readonly ready = typeof window !== "undefined";
provider?: Window["BinanceChain"];
constructor({ chains: _chains }: { chains: Chain[] }) {
const options = {
name: "Binance",
shimDisconnect: false,
shimChainChangedDisconnect: true,
};
const chains = _chains.filter((chain) => !!mappingNetwork[chain.id]);
super({ chains, options });
}
async connect({ chainId }: { chainId?: number } = {}) {
try {
const provider = await this.getProvider();
if (!provider) throw new ConnectorNotFoundError();
if (provider.on) {
provider.on("accountsChanged", this.onAccountsChanged);
provider.on("chainChanged", this.onChainChanged);
provider.on("disconnect", this.onDisconnect);
}
this.emit("message", { type: "connecting" });
const account = await this.getAccount();
// Switch to chain if provided
let id = await this.getChainId();
let unsupported = this.isChainUnsupported(id);
if (chainId && id !== chainId) {
const chain = await this.switchChain(chainId);
id = chain.id;
unsupported = this.isChainUnsupported(id);
}
return { account, chain: { id, unsupported }, provider };
} catch (error) {
if (this.isUserRejectedRequestError(error))
throw new UserRejectedRequestError(error);
//Sobre RPC - Remote Procedure Call (Chamada de Procedimento Remoto https://deinfo.uepg.br/~alunoso/2017/RPC/
if ((<RpcError>error).code === -32002)
throw new ResourceUnavailableError(error);
throw error;
}
}
async getProvider() {
if (typeof window !== "undefined") {
if (window.BinanceChain) {
this.provider = window.BinanceChain;
} else {
await _binanceChainListener();
this.provider = window.BinanceChain;
}
}
return this.provider;
}
async switchChain(chainId: number): Promise<Chain> {
const provider = await this.getProvider();
if (!provider) throw new ConnectorNotFoundError();
const id = hexValue(chainId);
if (mappingNetwork[chainId]) {
try {
await provider.switchNetwork?.(mappingNetwork[chainId]);
return (
this.chains.find((chain) => chain.id === chainId) || {
id: chainId,
name: `Chain ${id}`,
network: `${id}`,
nativeCurrency: { decimals: 18, name: "BNB", symbol: "BNB" },
rpcUrls: { public: { http: [""] }, default: { http: [""] } },
}
);
} catch (error) {
if ((error as any).error === "user rejected") {
throw new UserRejectedRequestError(error);
}
}
}
throw new SwitchChainNotSupportedError({ connector: this });
}
}
/**
Usage example:
const client = createClient({
autoConnect: true,
connectors: [
new MetaMaskConnector({
chains,
options: {
UNSTABLE_shimOnConnectSelectAccount: true,
},
}),
new BinanceWalletConnector({
chains,
}),
],
provider,
webSocketProvider,
});
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment