How to integrate Phantom wallet in react project? - reactjs

I actually desire to integrate phantom wallets into my custom hand website. Since I'm new to the web 3, I've just used Metamask and am unsure of what Solana and Phantom Wallets are.

Write a provider and then wrap your _app with this provider:
import {
ConnectionProvider,
WalletProvider,
} from '#solana/wallet-adapter-react'
import { WalletModalProvider } from '#solana/wallet-adapter-react-ui'
import { PhantomWalletAdapter } from '#solana/wallet-adapter-wallets'
import { useMemo } from 'react'
const WalletConnectionProvider = ({ children }) => {
const endpoint = useMemo(() => 'https://api.devnet.solana.com', [])
const wallets = useMemo(() => [new PhantomWalletAdapter()], [])
return (
<ConnectionProvider endpoint={endpoint}>
<WalletProvider wallets={wallets} autoConnect>
<WalletModalProvider>{children}</WalletModalProvider>
</WalletProvider>
</ConnectionProvider>
)
}
export default WalletConnectionProvider
or you manually check for window.solana the way you connect to window.ethereum
const isWalletConnected = async () => {
try {
const { solana } = window;
if (solana) {
if (solana.isPhantom) {
console.log("phantom wallet found");
// When using this flag, Phantom will only connect and emit a connect event if the application is trusted. Therefore, this can be safely called on page load for new users, as they won't be bothered by a pop-up window even if they have never connected to Phantom before.
// if user already connected, { onlyIfTrusted: true }
const response = await solana.connect({ onlyIfTrusted: false });
console.log(
"public key",
response.publicKey.toString()
);
setWalletAddress(response.publicKey.toString());
} else {
alert("Please install phantom wallet");
}
}
} catch (error) {
console.log(error);
}
};

Related

Getting c.trim error form google oauth2 web client requestAccessToken function

I am using google Oauth2 client script but in that "requestAccessToken" function geving me 2 error. See on bellow image
Here I am loading the 'https://accounts.google.com/gsi/client' script dynamically and after it been loaded I am createing a tokenClient by using initTokenClient funciton.
When user click on the button I am checking is token is allready avaiable or not if not then I am sending a request for google auth popup
tokenClient.current.requestAccessToken({ prompt: 'consent' });
But this requestAccessToken funciton giveing me a error called c.trim() is not a funciton. As per as I found it's comming form the internal implementation of this funciton
I am also getting another CORS error in the same place.
Reproduce Link: https://codesandbox.io/s/nostalgic-ives-wngw3v?file=/src/Picker.jsx
Error Image
import React, { useEffect, useRef, useState } from 'react';
import loadScript from 'load-script';
const GOOGLE_INDENTITY_URL = 'https://accounts.google.com/gsi/client';
const clientId = '865996907937-t2ca9nu95hv87f204t11gikb2rqm3s4v.apps.googleusercontent.com';
const scope = ['https://www.googleapis.com/auth/drive.readonly'];
let scriptLoadingStarted = false;
export default function TryPicker() {
const tokenClient = useRef();
const isGoogleAuthReady = () => {
return !!window.google?.accounts?.oauth2;
};
const doAuth = () => {
console.log('yea', tokenClient.current, tokenClient.current.requestAccessToken);
// // Use Google Identity Services to request an access token
tokenClient.current.requestAccessToken({ prompt: 'consent' });
};
const onChoose = () => {
if (!isGoogleAuthReady()) {
return null;
}
doAuth();
return undefined;
};
const onAuthLoad = () => {
tokenClient.current = window.google.accounts.oauth2.initTokenClient({
client_id: clientId,
scope,
callback: async response => {
if (response.error !== undefined) {
throw response;
}
console.log(response);
},
});
};
useEffect(() => {
if (isGoogleAuthReady()) {
// google api is already exists
// init immediately
onAuthLoad();
} else if (!scriptLoadingStarted) {
// load google api and the init
scriptLoadingStarted = true;
loadScript(GOOGLE_INDENTITY_URL, onAuthLoad);
} else {
// is loading
}
});
return (
<div>
<button className="text-darker" onClick={onChoose} type="button">
Get access token
</button>
</div>
);
}
As mentioned by yash, it's probably cuz you are using array. This is how used it for multiple scopes.
scope: 'https://www.googleapis.com/auth/user.birthday.read \
https://www.googleapis.com/auth/profile.agerange.read \
https://www.googleapis.com/auth/user.gender.read',
```

Web3 error when trying to call contract methods

I encounter the following error while trying to run a dapp made using React, Truffle & Ganache. I'm also using web3 version 1.7.1. The problem is that the code enters in a catch(error) sequence of a try/catch and then displays what it is intended correctly. Why is this happening and why does the following error appears?
index.js:1 TypeError: Cannot read properties of undefined (reading 'methods')
at HomePage.componentDidMount
What the code should do: Display something like "Address is: 0x0D05b3220E9cC7A90623fc506cEB64Ab885FD6C6"
What the code does: It shows me the prompt "Failed to load web3, accounts, or contract. Check console for details" AND THEN "Address is: 0x0D05b3220E9cC7A90623fc506cEB64Ab885FD6C6"
The code is the following:
import React, { Component } from "react";
import MySmartContract from "../contracts/MySmartContract.json";
import getWeb3 from "../getWeb3";
//Importing components
class HomePage extends Component {
constructor(props) {
super(props);
this.state = {
ContractInstance: undefined,
account: null,
web3: null,
isOwner: false
}
}
componentDidMount = async () => {
// For refreshing the page a single time
// so that web3 and instance is loaded every time
if (!window.location.hash) {
window.location = window.location + '#loaded';
window.location.reload();
}
try {
// Get network provider and web3 instance.
const web3 = await getWeb3();
// Use web3 to get the user's accounts.
const accounts = await web3.eth.getAccounts();
// Get the contract instance.
const networkId = await web3.eth.net.getId();
const deployedNetwork = MySmartContract.networks[networkId];
const instance = new web3.eth.Contract(
MySmartContract.abi,
deployedNetwork && deployedNetwork.address,
);
// Set web3, accounts, and contract to the state, and then proceed with an
// example of interacting with the contract's methods.
this.setState({ ContractInstance: instance, web3: web3, account: accounts[0] });
const owner = await this.state.ContractInstance.methods.getOwnerAddress().call();
if (this.state.account === owner) {
this.setState({ isOwner: true });
}
} catch (error) {
// Catch any errors for any of the above operations.
alert(
`Failed to load web3, accounts, or contract. Check console for details.`,
);
console.error(error);
}
};
render() {
if (!this.state.web3) {
return (
<h1>
Loading Web3, accounts and contract...
</h1>
)
}
return (
<div><h1>Address is: {this.state.account}</h1></div>
)
}
}
export default HomePage;
The content of getWeb3.js is the following:
import Web3 from "web3";
const getWeb3 = () =>
new Promise((resolve, reject) => {
// Wait for loading completion to avoid race conditions with web3 injection timing.
window.addEventListener("load", async () => {
// Modern dapp browsers...
if (window.ethereum) {
const web3 = new Web3(window.ethereum);
try {
// Request account access if needed
await window.ethereum.enable();
// Accounts now exposed
resolve(web3);
} catch (error) {
reject(error);
}
}
// Legacy dapp browsers...
else if (window.web3) {
// Use Mist/MetaMask's provider.
const web3 = window.web3;
console.log("Injected web3 detected.");
resolve(web3);
}
// Fallback to localhost; use dev console port by default...
else {
const provider = new Web3.providers.HttpProvider(
"http://127.0.0.1:8545"
);
const web3 = new Web3(provider);
console.log("No web3 instance injected, using Local web3.");
resolve(web3);
}
});
});
export default getWeb3;
This code seems to be wrong!
this.setState({ ContractInstance: instance, web3: web3, account: accounts[0] });
const owner = await this.state.ContractInstance.methods.getOwnerAddress().call();
You should not try to use state value as soon as you set up.
So you need to call your function in the second line like this:
const owner = await instance.methods.getOwnerAddress().call();
Injected connector code sample
const ConnectToInjected = async () => {
let provider = null;
if (typeof window.ethereum !== 'undefined') {
provider = window.ethereum;
try {
await provider.request({ method: 'eth_requestAccounts' })
} catch (error) {
throw new Error("User Rejected");
}
} else if (window.web3) {
provider = window.web3.currentProvider;
} else if (window.celo) {
provider = window.celo;
} else {
throw new Error("No Web3 Provider found");
}
return provider;
};
export default ConnectToInjected;
Usage:
const provider = await ConnectToInjected();
// Open metamask
await provider.request({ method: 'eth_requestAccounts' });
const web3 = new Web3(provider)

Socket.io and Next.Js

I am working on a project for an interview and have been asked to create a NextJS app using Socket.io for realtime chat. I have the chat functionality working, but one of my requirements is to have an area where a user can see a list of current users. While I've found examples for Express servers, I cannot seem to work out how to do this using Next's API system. I have two connected issues:
Maintaining a list of users with chosen display names (not just the socket id)
Accessing and returning a current user list whenever a user joins or leaves.
I haven't had any luck scanning the docs.
Here is the server function:
import { NextApiRequest } from 'next';
import { NextApiResponseServerIO } from '../../types/next';
import { Server as ServerIO } from 'socket.io';
import { Server as NetServer } from 'http';
export const config = {
api: {
bodyParser: false
}
}
export default async (req: NextApiRequest, res: NextApiResponseServerIO) => {
if (!res.socket.server.io) {
console.log("** New Socket.io server **")
// adapts the Next net server to http server
const httpServer: NetServer = res.socket.server as any;
const io = new ServerIO(httpServer, {
path: '/api/socketio'
})
io.on('connect', async (socket) => {
socket.join('main')
// where I plan to put the code to send a current list
})
io.on('disconnect', socket => {
socket.leave('main')
})
res.socket.server.io = io;
}
res.end();
}
And the related client code:
useEffect((): any => {
const url = process.env.NEXT_BASE_URL as string | "";
// connect to socket server
const socket = io(url, {
path: "/api/socketio",
});
// log socket connection
socket.on("connect", () => {
dispatch(connect(socket.id));
dispatch(updateId(socket.id))
});
//updates chat on message dispatch
socket.on("message", (message: IMsg) => {
dispatch(receive(message));
});
socket.on('updateUsersList', (users) => {
console.log("Is this the users", users)
})
//server disconnect on unmount
if (socket) return () => dispatch(disconnect(socket));
}, []);

How to avoid reconnections with socket.io-client and React app?

I tried to connect React client to my Socket.IO server. I noticed Socket.IO client reconnects every +/- 5s. When I try do the same thing with vanilla html/js simple app everything works crrectly.
Inside React component:
useEffect(() => {
const s = getChatClient();
}, []);
Inside socket.io-client module:
var chatClient;
export function getChatClient(
token = "secret"
) {
if (!chatClient) {
chatClient = io("http://localhost:5000/chat", {
query: {
token,
},
});
chatClient
.on("connect", () => {
chatClient.emit("textMessage", "123cos");
})
.on("hello", (msg) => {
console.log("12");
});
}
return chatClient;
}
BTW: I know I can do it export const etc (I've changed to this version becouse I thought it'll help).
I tried different ways to resolve this problem, but I got in stuck. Any ideas?
Log from the server when I open html/js simple client:
15:30:00 User Ilona connected to the socket.io server on /
and when I quit:
15:29:12 User Ilona disconnected
With React App:
15:30:00 User Ilona connected to the socket.io server on '/'
15:30:05 User Ilona disconnected
15:30:10 User Ilona connected to the socket.io server on '/'
15:30:15 User Ilona disconnected
15:30:20 User Ilona connected to the socket.io server on '/'
15:30:25 User Ilona disconnected
The problem isn't related with component rerender or something like this.
I'm working on MacOS Big Sur.
Consider creating, and then consuming from a context:
SocketContext.jsx :
import { createContext, useState } from 'react';
export const SocketContext = createContext();
export default function SocketContextProvider(props) {
const [sock, setSocket] = useState(null);
let socket = async () => {
if (sock) {
return Promise.resolve(sock); // If already exists resolve
}
return new Promise((resolve, reject) => {
let newSock = io('URL'),
{
query: {
// Options
},
}; // Try to connect
let didntConnectTimeout = setTimeout(() => {
reject();
}, 15000) // Reject if didn't connect within 15 seconds
newSock.once('connect', () => {
clearTimeout(didntConnectTimeout); // It's connected so we don't need to keep waiting 15 seconds
setSocket(newSock); // Set the socket
resolve(newSock); // Return the socket
})
});
};
return (
<SocketContext.Provider value={{ socket }}>
{props.children}
</SocketContext.Provider>
);
}
Component.jsx :
import { useContext, useState, useEffect } from 'react';
import { SocketContext } from './SocketContext.jsx';
export default function MyComponent() {
const { socket } = useContext(SocketContext);
const [sock, setSock] = useState(null);
useEffect(() => {
socket()
.then((resultSocket) => setSock(resultSocket))
.catch(() => {
/* Catch any errors here */
console.log('Couldn\'t connect the socket!')
});
}, []);
return (
<div>
<code>I'm a context consumer...</code>
</div>
);
}

AWS Cognito not working for IE 11, but works for every other browser

So I am trying to use cognito to manage authentication in my react application, with the identity provider being SAML. This is working very smoothly in Chrome and Firefox, but not in IE 11. Here is I set up my Auth:
import { Component } from 'react';
import { connect } from 'react-redux';
import { CognitoAuth } from 'amazon-cognito-auth-js';
import { signIn, signOutSuccess } from '../store/auth';
import { setupAxios } from '../axios';
import {
AWS_COGNITO_CLIENT_ID,
AWS_COGNITO_USER_POOL_ID,
AWS_COGNITO_REDIRECT_SIGN_IN,
AWS_COGNITO_REDIRECT_SIGN_OUT,
AWS_COGNITO_APP_WEB_DOMAIN
} from '../env';
const cognitoSetup = props => {
//as per documentation
const authData = {
ClientId: AWS_COGNITO_CLIENT_ID,
TokenScopesArray: ['email', 'openid', 'profile'],
RedirectUriSignIn: AWS_COGNITO_REDIRECT_SIGN_IN,
RedirectUriSignOut: AWS_COGNITO_REDIRECT_SIGN_OUT,
AppWebDomain: AWS_COGNITO_APP_WEB_DOMAIN,
IdentityProvider: 'SAML',
UserPoolId: AWS_COGNITO_USER_POOL_ID
};
const auth = new CognitoAuth(authData);
auth.useCodeGrantFlow(); //getting the refresh token
auth.userhandler = {
onSuccess: result => {
const { profile, name, family_name, email } = result.idToken.payload;
//passes role to store for use in the rest of the app
const username = result.idToken.payload.identities[0].userId;
const fullName = `${name} ${family_name}`;
props.signIn({ username, profile, fullName, email });
},
onFailure: function(err) {
console.error(err);
throw err;
}
};
return auth;
};
export class AuthService extends Component {
constructor(props) {
super(props);
this.authService = cognitoSetup(this.props);
//passes the auth to axios to check for token on request
setupAxios(this.authService);
}
componentDidMount() {
const curUrl = window.location.href;
if (curUrl.includes('?code=')) {
this.authService.parseCognitoWebResponse(curUrl);
} else if (!curUrl.includes('?error')) {
this.authService.getSession();
}
}
signOut = async () => {
await this.authService.signOut();
};
async componentDidUpdate(prevProps) {
if (prevProps.shouldSignOut !== this.props.shouldSignOut) {
if (this.props.shouldSignOut) {
await this.signOut();
this.props.signOutSuccess();
}
}
}
//render nothing
render() {
return null;
}
}
const mapState = state => ({
username: state.auth.username,
signedIn: state.auth.signedIn,
shouldSignOut: state.auth.shouldSignOut
});
const mapDispatch = dispatch => ({
signIn: (username, profile) => dispatch(signIn(username, profile)),
signOutSuccess: () => dispatch(signOutSuccess())
});
export default connect(mapState, mapDispatch)(AuthService);
This AuthService.js is rendered upon loading the application. However When loading in IE11, there is an error var jsonDataObject = JSON.parse(jsonData); invalid character.
I have no idea why this is happening. I have investigated and came to the conclusion that this is going on within the package amazon-cognito-auth-js. I'm under the impression this package was made by amazon so I believe the package is not at fault, but I cannot see anyone else with this issue. Does anyone have any suggestions?
EDIT: I do have a polyfill
I saw you used arrow functions => in your code which is not supported by IE. You could use babel to compile it and any other ES6 syntax to ES5. For example, compile:
const cognitoSetup = props => {
...
}
to:
var cognitoSetup = function cognitoSetup(props) {
...
}
Besides, have you imported react-app-polyfill at the first line in your src/index.js? This is required for react app to run in IE 11. You could refer to the answer in this thread for detailed steps.

Resources