@foreverrbum/ethsign
Version:
This package will allow you to electronically sign documents within your application
258 lines (237 loc) • 8.52 kB
JavaScript
import { ethers } from 'ethers';
import Fortmatic from 'fortmatic';
import Torus from "@toruslabs/torus-embed";
import {getChain, getFortmaticChainOptions, getTorusChainOptions, getTorusChainSwitchOptions, isTestnet} from '../chains'
import Ethsign from '../../artifacts/EthSign.json';
import { Biconomy } from '@biconomy/mexa';
import * as Sentry from '@sentry/react';
const fortmatic_key = 'pk_live_6D2FFF6E41301BF0';
const fortmatic_test_key = 'pk_test_F4BDDED1F885923E';
export const updateNetwork = async (provider, handleNetwork) => {
try {
await provider.getNetwork().then((network)=>{
const chain = getChain(network.chainId);
handleNetwork(chain);
})
} catch(err) {
handleNetwork(null);
return;
}
}
export const initializeProvider = async (handleProvider, handleNetwork, handleWalletName) => {
const name = getWallet();
if (name){
window.ethereum.request({ method: 'eth_requestAccounts' }).then(async()=>{
const provider = new ethers.providers.Web3Provider(window.ethereum)
handleWalletName(name)
handleProvider(provider)
await updateNetwork(provider, handleNetwork);
})
}
}
export const getWallet = () => {
if (typeof window !== "undefined" && typeof window.ethereum !== "undefined" ) {
if (window.ethereum.isMetaMask){
return 'Metamask'
}
if (window.ethereum.isTorus) {
return 'Torus'
}
if (window.ethereum.isImToken) {
return 'imToken'
}
}
return null
}
export const renderProviderText = (account) => {
if(account && account.address) {
const providerTextList = {
Metamask: 'Add to Metamask',
imToken: 'Add to imToken',
Wallet: 'Add to Wallet'
}
return providerTextList[getProvider()]
} else {
return 'Connect wallet'
}
}
const toHex = (num) => {
return '0x'+num.toString(16)
}
export const connectNetwork = async (chain, provider, handleProvider, handleContract, handleNetwork, walletName, handleFm, torus, handleTorus, finishedCallback) => {
let ethAccount = null;
try {
ethAccount = await provider.getSigner().getAddress();
} catch (err) {
console.log(err);
return;
}
if(walletName === 'Fortmatic') {
let fm = null;
if(chain.chainId == 1) {
fm = new Fortmatic(fortmatic_key);
} else {
fm = new Fortmatic(isTestnet(chain.chainId) ? fortmatic_test_key : fortmatic_key, getFortmaticChainOptions(chain.chainId))
}
let provider = new ethers.providers.Web3Provider(fm.getProvider());
const networkId = (await provider.getNetwork()).chainId;
const deployedNetwork = Ethsign.networks[networkId];
const contract = new ethers.Contract(deployedNetwork.address, Ethsign.abi, provider);
if (handleFm) {
handleFm(fm)
}
if(handleProvider) {
handleProvider(provider);
}
if(handleContract) {
handleContract(contract);
}
if(handleNetwork) {
handleNetwork(chain);
}
if(finishedCallback) {
finishedCallback(true);
}
return chain;
} else if(walletName === 'Torus') {
if(!torus) {
torus = new Torus();
await torus.init(getTorusChainOptions(chain.chainId));
await torus.login();
} else {
await torus.setProvider(getTorusChainSwitchOptions(chain.chainId));
}
let provider = new ethers.providers.Web3Provider(torus.provider);
const networkId = (await provider.getNetwork()).chainId;
const deployedNetwork = Ethsign.networks[networkId];
const contract = new ethers.Contract(deployedNetwork.address, Ethsign.abi, provider);
if (handleTorus) {
handleTorus(torus)
}
if(handleProvider) {
handleProvider(provider);
}
if(handleNetwork) {
handleNetwork(chain);
}
if(handleContract) {
handleContract(contract);
}
if(finishedCallback) {
finishedCallback(true);
}
return chain;
} else {
const params = {
chainId: toHex(chain.chainId), // A 0x-prefixed hexadecimal string
chainName: chain.name,
nativeCurrency: {
name: chain.nativeCurrency.name,
symbol: chain.nativeCurrency.symbol, // 2-6 characters long
decimals: chain.nativeCurrency.decimals,
},
rpcUrls: chain.rpc,
blockExplorerUrls: [ ((chain.explorers && chain.explorers.length > 0 && chain.explorers[0].url) ? chain.explorers[0].url : chain.infoURL) ]
}
try {
let res = await window.ethereum.request({
method: 'wallet_switchEthereumChain',
params: [{chainId: params.chainId}],
});
connectNetworkRequestResult(chain, handleProvider, handleContract, handleNetwork, finishedCallback);
} catch (err) {
// This error code indicates that the chain has not been added to MetaMask.
if(err.code === 4902) {
try {
let res = window.ethereum.request({
method: 'wallet_addEthereumChain',
params: [params, ethAccount],
});
connectNetworkRequestResult(chain, handleProvider, handleContract, handleNetwork, finishedCallback);
} catch(error) {
console.log(error)
if(finishedCallback) {
finishedCallback(true);
}
Sentry.captureException(error);
return error;
}
} else {
// this is some other network switch error
console.log(err)
if(finishedCallback) {
finishedCallback(true);
}
Sentry.captureException(err);
return err;
}
}
return chain;
}
}
export const connectNetworkRequestResult = async (chain, handleProvider, handleContract, handleNetwork, finishedCallback) => {
let provider = new ethers.providers.Web3Provider(window.ethereum);
handleProvider(provider)
if (handleContract){
const deployedNetwork = Ethsign.networks[chain.chainId];
const contract = new ethers.Contract(deployedNetwork.address, Ethsign.abi, provider);
handleContract(contract);
}
if(finishedCallback) {
finishedCallback(true);
}
if (handleNetwork){
handleNetwork(chain)
}
}
// This function supports only torus, imtoken and metamask wallets because we currently don't support network switch for fortmatic
export const resetContractAndProvider = async (chainId, handleProvider, handleContract, torus) => {
let biconomy = null;
let provider = null;
if(torus) {
if(getChain(await torus.ethereum.request({ method: 'eth_chainId' }))?.biconomySupport) {
let originalProvider = new ethers.providers.Web3Provider(torus.ethereum);
biconomy = new Biconomy(originalProvider, { apiKey: getChain(await torus.ethereum.request({ method: 'eth_chainId' })).biconomyKey });
provider = new ethers.providers.Web3Provider(biconomy);
} else {
provider = new ethers.providers.Web3Provider(torus.ethereum);
}
handleProvider(provider)
} else if(window.ethereum != null && window.ethereum != undefined) {
if(getChain(await window.ethereum.request({ method: 'eth_chainId' }))?.biconomySupport) {
let originalProvider = new ethers.providers.Web3Provider(window.ethereum);
biconomy = new Biconomy(originalProvider, { apiKey: getChain(await window.ethereum.request({ method: 'eth_chainId' })).biconomyKey });
provider = new ethers.providers.Web3Provider(biconomy);
} else {
provider = new ethers.providers.Web3Provider(window.ethereum);
}
handleProvider(provider)
}
// Handle the contract
const deployedNetwork = Ethsign.networks[chainId];
const signer = await provider.getSigner(); // signer == current logged in user
const account = await signer.getAddress();
let contract = null;
if (biconomy == null) {
contract = new ethers.Contract(deployedNetwork.address, Ethsign.abi, provider);
console.log("EthSign: Initialized normally.")
} else {
await new Promise((resolve, reject) => {
biconomy.onEvent(biconomy.READY, async () => {
contract = new ethers.Contract(
deployedNetwork.address,
Ethsign.abi,
biconomy.getSignerByAddress(account)
);
console.log("EthSign: Initialized with Mexa.")
resolve();
}).onEvent(biconomy.ERROR, (error, message) => {
console.log("EthSign: Failed to initialize with Mexa.")
console.log(message);
console.log(error);
reject();
});
});
}
handleContract(contract);
}