Set ethers provider to use any injected web3 providers - web3js

Using MetaMask provider to detect MetaMask as provider and Etherprojects provider to set provider.
import { ExternalProvider, Web3Provider } from '#ethersproject/providers';
import detectEthereumProvider from '#metamask/detect-provider';
Checking for MetaMask provider only and setting metamask as provider.
export default class Dapp extends React.Component<Props, State> {
provider!: Web3Provider;
componentDidMount = async () => {
const browserProvider = await detectEthereumProvider() as ExternalProvider;
if (browserProvider?.isMetaMask !== true) {
this.setError(
);
}
this.provider = new ethers.providers.Web3Provider(browserProvider);
this.registerWalletEvents(browserProvider);
await this.initWallet();
}
I had resolved this issue to detect any injected web3 provider last week accidentally I couldn't save the code now I cannot figure how I got it to work with any web3 provider wallets like Trust Wallet or Brave Wallet.

Related

how to i establish socket.io connection only AFTER logging in , REACT + socket.io

can i get help with something im stuck on for awhile
im establishing a socket .io connection in my frontend with react context,
but the connection is triggered as soon as my web load, i want it to connect only AFTER i login
im running a jwt auth on my socket connection and what happens is it fails to auth because i dont have a chance to login before it checks it
and then after i log in it wont establish connection untill i manually reload the page...
😦
client:
import React from 'react';
import io from 'socket.io-client'
import { SOCKET_IO_URL } from '../api/config';
const jwt = JSON.parse(localStorage.getItem('profile'))?.token
console.log(jwt)
export const socket = io.connect(SOCKET_IO_URL, {query: {token: jwt}});
export const SocketContext = React.createContext()
server:
io.on('connection', (socket => {
const token = socket.handshake.query.token;
try {
if (!token) throw new Error("TOKEN NOT FOUND")
jwt.verify(token,'secret')
} catch (error) {
console.log('VERIFICATION FAILED')
socket.disconnect()
}
console.log('socket conected', socket.id)
socket.on('request_fetch', () => {
socket.broadcast.emit('response_fetch')
})
}))
You can import the socket / use the socket only in areas where you are logged in.
And lazy import those components
const Dashboard = lazy(() => import('./pages/Dashboard'))
that way the token will always be available when loading those components
According to the docs in the client options, there is an option autoConnect
Client Options
Set this to false as it defaults to true then manually try to connect after you have logged in with socket.connect

Should I declare contract every time in React.js?

I created my first React - Solidity application. It uses ethers library and I can successfully
Check and connect to Metamask
Get Provider + Signer
Get contract using my contract address + ABI and either the provider or signer.
then execute functions in my contract. My understanding is that provider = readOnly and signer = write, so I'm wondering whether you should declare a new contract object/instance every time before you call functions? Or do you reuse it and keep it in a state?
The best is to create one every time using let so the user dont hold the contract object all the time and yes the provider for read and signer for write and pay
I really like to use this hook:
import { Contract } from '#ethersproject/contracts'
import { ethers } from 'ethers'
import { useEffect, useState } from 'react'
import { CONTRACT_ADDRESS } from '../constants'
import { IContract, Artifact } from '../contract'
import { useProvider } from '../hooks'
export const useContract = () => {
const [contract, setContract] = useState<IContract>()
const provider = useProvider()
useEffect(() => {
;(async function () {
const _contract = new Contract(
CONTRACT_ADDRESS,
Artifact.abi,
provider?.getSigner() || ethers.getDefaultProvider('rinkeby')
) as IContract
setContract(_contract)
})()
}, [provider])
return contract
}
The useProvider hook is a part of the web3-react library which is an industry standard, developed by the tech lead of Uniswap.

TypeError: Cannot read properties of undefined (reading 'Contract') - Next.js, web3.0

I'm trying to create a small web3.0 app, using next.js.
I have deployed my contract on rinkeby test network, and I am able to check the functionalities using Remix, work properly. I have also worked on similar projects on react, they also work as exepected.
But when I try to connect I am currently facing the following issue (maybe this has something to do with Server side rendering of next.js or HttpProvider, I'm not sure):
TypeError: Cannot read properties of undefined (reading 'Contract')
3 | import address from './build/campaignHubAddress.json';
4 |
> 5 | const instance = new web3.eth.Contract(contract.abi, address.campaignHubAddress);
| ^
6 | export default instance;
web3.js
import Web3 from 'web3';
let web3;
if (typeof window !== 'undefined' && typeof window.ethereum !== 'undefined') {
window.ethereum.request({ method: "eth_requestAccounts" });
web3 = new Web3(window.ethereum);
} else {
const provider = new Web3.providers.HttpProvider(
'https://rinkeby.infura.io/v3/3ed112ee6c4d42a09e485ddb5eec5fa2'
);
web3 = new Web3(provider);
}
export default web3;
instance.js
import web3 from 'web3';
import contract from './build/CampaignHub.json';
import address from './build/campaignHubAddress.json';
const instance = new web3.eth.Contract(contract.abi, address.campaignHubAddress);
export default instance;
index.js
import React from 'react';
import web3 from '../web3';
import instance from '../instance';
class Index extends React.Component{
static async getInitialProps(){
const campaigns = await instance.methods.getCampaigns().call();
return { campaigns };
}
render() {
return (
<>
<p>Hello, this is the test page for now.</p>
<p>Web3 version: {web3.version}</p>
<p>List of all the running campaigns: {this.props.campaigns} </p>
</>
);
}
}
export default Index;
This seems basic, but I have been stuck at it for some time now.
You already create instance of your web3 in web3.js
you can use it directly without using the "new"
import web3 from 'web3';
import contract from './build/CampaignHub.json';
import address from './build/campaignHubAddress.json';
const instance = web3.eth.Contract(contract.abi, address.campaignHubAddress);
export default instance;
After scratching a lot of head, I found that the error was in instance.js. While importing import web3 from 'web3'; I should have done import web3 from './web3';

The operation is insecure in React using MQTT package from npm

I have a little app that gets sensor data and i want to use mqtt to distribute them. I've found this package on npm called MQTT, with this i can make a client in the browser, if i'm using an http insecure connection it works fine but when i use https i get an error in the create-react-app development server saying that this:
this.client = mqtt.connect();
It's an 'Insecure operation', someone had this problem or know any solution?
Also, in the wiki there is not an entry for a secure connection or something similar.
EDIT: the component code:
import React from 'react';
import mqtt from 'mqtt'
class MqttComponent extends React.Component {
constructor(props) {
super(props);
this.client = mqtt.connect();
this.client.on('connect', () => {
console.log(`connected`);
})
this.client.on('message', (topic, message) => {
let payload = JSON.parse(message);
let payloadKey = topic.substring(1);
console.log('message');
this.props.actualizarPorMensaje(payload, payloadKey);
});
}
componentDidUpdate(prevProps) {
Object.keys(this.props.equipos)
.filter(numeroSerie => !(numeroSerie in prevProps.equipos))
.map(numeroSerie => (
this.client.subscribe(`/${numeroSerie}`)
)
);
}
render() {
return;
}
}
export default MqttComponent;

Integrating web3 from Metamask in React

I am new to ReactJS.
Seem to be having trouble integrating web3 from Metamask in React.
Metamask version: web3#1.0.0-beta.34
import Web3 from 'web3'
let web3;
window.addEventListener('load', function () {
if (typeof window.web3 !== 'undefined') {
web3 = new Web3(window.web3.currentProvider);
} else {
// No web 3 provider
console.log("Please install Metamask");
}
});
export default web3;
Getting the following error:
window is not defined
ReferenceError: window is not defined
at Object../lib/getWeb3.js (lib/getWeb3.js:5:0)
window is not defined on Server, only in client's browser, hence you can't use MetaMask server-side. However, you can connect to INFURA when you want to use web3 in your React component server-side or without MetaMask support.
The simplest way is to use react-web3-provider component.
Add the Web3Provider to your root React component:
import Web3Provider from 'react-web3-provider';
ReactDOM.render(
<Web3Provider
defaultWeb3Provider="https://mainnet.infura.io/YOUR_API_KEY"
loading="Loading..."
>
<App />
</Web3Provider>
)
Then in component where you want to use Web3:
import { withWeb3 } from 'react-web3-provider';
class MyComponent {
render() {
const { web3 } = this.props;
web3.eth.getAccounts(console.log);
// Version 1.0.0-beta.35
return "Web3 version: {web3.version}";
}
}
export default withWeb3(MyComponent);

Resources