how get metamask ethereum object when install both metamask and coinbase chrome extension? - coinbase-api

when I installed both metamask and coinbase chrome extension. ethereum object not work well.

just use code like this:
async function findMetaMaskProvider() {
const { providers } = (window as any).ethereum;
let selectedProvider: any;
for (const provider of providers || []) {
if (provider.isMetaMask) {
selectedProvider = provider;
}
}
if (selectedProvider) {
(window as any).ethereum.setSelectedProvider(selectedProvider);
return selectedProvider;
}
return (window as any).ethereum;
}

Related

Undefined contract address when using useDapp's useCall hook

Docs referenced: https://usedapp.readthedocs.io/en/latest/guide.html#custom-hooks
Version of usedapp in package.json: "#usedapp/core": "^0.11.0"
Im using the useCall hook to call one of my functions that returns an integer that shows total supply. Here is the my custom hook:
import { useCall } from "#usedapp/core"
import { Contract } from '#ethersproject/contracts'
const useTotalSupply = (contractAddress, ethInterface) => {
const ethContract = new Contract(contractAddress, ethInterface)
console.log("Found address for contract object: " + ethContract.address)
const { value, error } = useCall(
ethContract,
'getTotalCurrentSupply',
[]) ?? {}
if (error) {
console.error(error.message)
return -1
}
return value?.[0]
}
export default useTotalSupply
This is how I'm using the hook in my component
const MintCounter = () => {
const totalSupply = useTotalSupply(ethContractAddress, ethInterface)
return (
<Box>
<Stat>
<StatLabel>Total Mints</StatLabel>
<StatNumber>{totalSupply}</StatNumber>
</Stat>
</Box>
)
}
After building my app, I'm seeing the following error:
Error screenshot
I'm a bit confused by this error since I'm passing in the contract instance and I can see that the contract.address value has been set and I am seeing the address string on the console output. Is there something that I am missing in using this hook? Thanks in advance
I was able to show the supply replacing useCall part:
const {value: message} = useCall({
contract: ethContract,
method: "totalSupply",
args: []
}) ?? {}
return String(message)
environment: ERC721 contract, local hardhat node (31337), usedapp 0.12

How to call a REST API endpoint inside TypeScript and get its results

Inside my React SPFx web part, i need to get the current SharePoint Page Title, to do so i need to run this API Call:-
let listTitle: string = this.props.context.pageContext.list.title;
let pageItemId: number = this.props.context.pageContext.listItem.id;
let url = `${this.props.context.pageContext.web.absoluteUrl}/_api/lists/getbytitle('${listTitle}')/items(${pageItemId})?$select=ID,Title`;
so how i can call the above URL and get the string it should return?
Thanks
I tried the following but the function will return null
private GetPageTitle()
{ let listTitle: string = this.props.context.pageContext.list.title;
let pageItemId: number = this.props.context.pageContext.listItem.id;
let url = `${this.props.context.pageContext.web.absoluteUrl}/_api/lists/getbytitle('${listTitle}')/items(${pageItemId})?$Title`;
return (RelatedTopics.getSPData(this.client, url));
}
you can use either pnp js package to make Sharepoint Api call or build in spHttpClient.
PNP JS:
https://pnp.github.io/pnpjs/sp/items/
import { sp } from '#pnp/sp';
let url = await sp.web.lists.getByTitle(listTitle).items.getById(pageItemId).select('ID','Title').get();
spHttpClient:
import { ISPHttpClientOptions, SPHttpClient, SPHttpClientResponse } from '#microsoft/sp-http';
let url: string = '[endpoint url]';
this.props.context.spHttpClient.get(url, SPHttpClient.configurations.v1, httpClientOptions).then((response: SPHttpClientResponse) => {
if (response.ok) {
return response.json();
} else {
reject(error);
}});

How to keep MetaMask connection to the UI persistent with Web3-react?

I am working with web3-react and I cannot figure out how to keep the connection to the MetaMask wallet persistent upon browser refreshes.
This is the code:
// define the injectedConnectors
const injectedConnector = new InjectedConnector({
supportedChainIds: [
1, // Mainet
3, // Ropsten
4, // Rinkeby
5, // Goerli
42, // Kovan
],
})
const { chainId, account, activate, active } = useWeb3React()
// activate the wallet
activate(injectedConnector)
console.log(account)
// all good.
Up to here all is working and I activate my MetaMask wallet as well as I get the account correctly logged, and the active variable is a boolean that changes to true.
The problem is that when I refresh the page the active turns to false and I lose the connection between the UI to the MetaMask wallet. Of course saving active into the browser does not change anything because the connection relies on the active boolean value.
The docs are lacking such information.
Finally found a solution!
I was trying to use the example in the official library using ... but for some reason it wasn't working though no error came out.
Then I stumbled upon some guy who had the same issue and posted on reddit and got a good answer that works for me.
This is the link to the post: https://www.reddit.com/r/ethdev/comments/nw7iyv/displaying_connected_wallet_after_browser_refresh/h5uxl88/?context=3
and this is the code from that post:
First create a file that holds the injectedConnector called connectors.js:
import { InjectedConnector } from '#web3-react/injected-connector'
export const Injected = new InjectedConnector({ supportedNetworks: [1, 3, 4, 5, 42] })
Then create a component that checks if the user already activated the wallet:
import React, { useEffect, useState } from 'react'
import { injected } from '../connectors'
import { useWeb3React } from '#web3-react/core'
function MetamaskProvider({ children }) {
const { active: networkActive, error: networkError, activate: activateNetwork } = useWeb3React()
const [loaded, setLoaded] = useState(false)
useEffect(() => {
injected
.isAuthorized()
.then((isAuthorized) => {
setLoaded(true)
if (isAuthorized && !networkActive && !networkError) {
activateNetwork(injected)
}
})
.catch(() => {
setLoaded(true)
})
}, [activateNetwork, networkActive, networkError])
if (loaded) {
return children
}
return <>Loading</>
}
export default MetamaskProvider
And wrap MetamaskProvider around the components you want the wallet to be activated upon refresh:
return (
<ThemeProvider theme={darkMode ? darkTheme : lightTheme}>
<StylesProvider injectFirst>
<Paper>
<Router>
<Web3ReactProvider getLibrary={getLibrary}>
<MetamaskProvider>
{...children components}
</MetamaskProvider>
</Web3ReactProvider>
</Router>
</Paper>
</StylesProvider>
</ThemeProvider>
);
Its actually really simple. You can just store the connect address in local storage and when the user clicks the disconnect button then remove the address from local storage. basically we use the condition that if there is an acccount in local storage then we connect on load and if not then we have to manually click the connect button. Consider the code below. Note that ideally you should write the logic as a hook and use the hook in the main app then pass in the props the "active" status which is returned from useWeb3React(). but for the purpose of this example i just keep the connect logic in one file to make it read easier
import React, { useState, useEffect } from 'react';
import Web3 from 'web3';
import detectEthereumProvider from '#metamask/detect-provider';
import { useWeb3React } from "#web3-react/core"
import { InjectedConnector } from '#web3-react/injected-connector'
//declare supportated chains
export const injected = new InjectedConnector({
supportedChainIds: [1, 3, 4, 5, 42, 1337, 43114],
})
export default function connButton() {
var web3;
var accounts;
var connected
const [loading, setLoading] = useState(false)
//here we can destructure out various things from web3React such as
//active (which is true if the user is connected and false otherwise)
//activate and deactiveate which we use to instansiate and break the users
//connection
const { active, account, library, connector, activate, deactivate } = useWeb3React()
//set up an elemnt in local storage that we use to hold the connected account
var acc = localStorage.getItem("account")
//function that initialises web3.js
const connectWalletHandler = () => {
if (window.ethereum && window.ethereum.isMetaMask) {
console.log('MetaMask Here!');
web3 = new Web3(window.ethereum);
window.ethereum.request({ method: 'eth_requestAccounts'})
} else {
console.log('Need to install MetaMask');
// setErrorMessage('Please install MetaMask browser extension to interact');
}
console.log(web3.eth.currentProvider)
}
//function that is called on page load if and only if their exists and
//item for the user accoun tin local storage
async function connectOnLoad() {
try {
//here we use activate to create the connection
await activate(injected)
connected = true
} catch (ex) {
console.log(ex)
}
//we use web3.eth to get the accounts to store it in local storage
var accounts1 = await web3.eth.getAccounts();
acc = localStorage.setItem("account", accounts1);
}
//here we use a useEffect so that on page load we can check if there is
//an account in local storage. if there is we call the connect onLoad func
//above which allows us to presist the connection and i also call connectWalletHandler
which sets up web3.js so we can call web3.eth.getAccounts()
useEffect(() => {
if (acc != null) {
connectOnLoad()
}
connectWalletHandler()
}, [])
//however in the case where there is no item in local storage we use this
//function to connect which is called when we click the connect button. its
//essentially the same but we check if local storage is null if it is we activate
//if its not then we disconnect. And when we disconnect we remove the acccount from local storage
async function connectOnClick() {
if (localStorage.getItem("account") == null) {
setLoading(true);
try {
await activate(injected)
connected = true
} catch (ex) {
console.log(ex)
}
// window.location.reload();
var accounts1 = await web3.eth.getAccounts();
console.log(accounts1)
acc = localStorage.setItem("account", accounts1);
console.log(acc)
setTimeout(function(){
setLoading(false)
}, 1600);//wait 2 seconds
} else {
disconnect();
connected = false
}
}
async function disconnect() {
try {
deactivate()
localStorage.removeItem("account");
} catch (ex) {
console.log(ex)
}
}
return (
//remember the active boolean from useReactWeb3() stores a bool
//depending on if the user is or is not connected there for we can
//use this as a conditon to render the button saying "Connect Wallet"
or displaying their address as the text.
<div>
{active ? <button onClick={connectOnClick}>{account.substring(0, 6)}...{account.substring(account.length - 4)}</button> : <button onClick={connectOnClick}>Connect Wallet</button>}
</div>
);
}
then in your app.js remember to wrap your entire app in the tag. remember this means you need to import web3React into your app.js also

[Unhandled promise rejection: TypeError: undefined is not an object (evaluating 'Expo.Facebook.logInWithReadPermissionsAsync')]

I want to create a signUp with Facebook. The code should work so far. I compared it with different sources and they use it like I did.
loginWithFacebook = async () => {
const { type, token } = await Expo.Facebook.logInWithReadPermissionsAsync(
'449579609085368',
{ permissions: ['email', 'public_profile'] }
);
if (type === 'success') {
const credentials = f.auth().FacebookAuthProvider.credential(token);
f.auth.signInWithCredential(credentials).catch((error) => 'Error logging in Facebook', error);
}
}
I am very happy about any kind of help.
Just so it's easier to see for other people, I moved my answer in the comment here.
You are probably importing Expo.Facebook wrongly. Maybe import it like this
import * as Facebook from 'expo-facebook';
and then use it like this:
const { type, token } = await Facebook.logInWithReadPermissionsAsync(
'449579609085368',
{ permissions: ['email', 'public_profile'] }
);
install expo-facebook by
expo install expo-facebook
then use this code
import * as Facebook from 'expo-facebook';
const login=async ()=>{
await Facebook.initializeAsync('<APP_ID>');
const { type, token } = await Facebook.logInWithReadPermissionsAsync(
{ permissions:['public_profile', 'email'] },
);
}
Facebook has been removed from Expo and moved to expo-facebook.
Follow this document https://docs.expo.io/versions/latest/sdk/facebook/

Is it possible to connect non component Class to redux store?

So I am using a react-redux boilerplate that has an ApiClient helper. It looks like this:
export default class ApiClient {
constructor(req) {
/* eslint-disable no-return-assign */
methods.forEach((method) =>
this[method] = (path, withCredentials, { params, data } = {}) => new Promise((resolve, reject) => {
const request = superagent[method](formatUrl(path))
if (withCredentials) {
console.log('first of all, its true')
console.log(this)
}
if (params) {
request.query(params)
}
if (__SERVER__ && req.get('cookie')) {
request.set('cookie', req.get('cookie'))
}
if (data) {
request.send(data)
}
request.end((err, { body } = {}) => {
return err ? reject(body || err) : resolve(body)
})
}))
/* eslint-enable no-return-assign */
}
/*
* There's a V8 bug where, when using Babel, exporting classes with only
* constructors sometimes fails. Until it's patched, this is a solution to
* "ApiClient is not defined" from issue #14.
* https://github.com/erikras/react-redux-universal-hot-example/issues/14
*
* Relevant Babel bug (but they claim it's V8): https://phabricator.babeljs.io/T2455
*
* Remove it at your own risk.
*/
empty() {}
}
I want to connect this to my auth so that I can prepend headers to protected endpoints, like so:
#connect(state => ({ jwt: state.auth.jwt }))
export default class ApiClient {
...
However, when I do this, I get the error: Cannot read property 'store' of undefined. What's going on here? Why can't I connect a regular Class to the redux store?
Update: here's my login function, which uses the ApiClient helper:
export function loginAndGetFullInto(email, password) {
return dispatch => {
return dispatch(login(email, password))
.then(() => {
return dispatch(loadUserWithAuth())
})
}
}
I need some way to either pass the store, or the jwt, into the loadUserWithAuth function...
The connect function is not going to work with anything other than React components. What you can do is pass your store instance to your class and call store.dispatch, store.getState, and store.subscribe directly.
Keep in mind that if you subscribe, you should also have functionality to unsubscribe, otherwise your store will be holding a reference to your class instance forever, creating a memory leak.

Resources