export default class MagicWeb3Connector extends AbstractWeb3Connector {
type = 'MagicLink';
async activate({ email, apiKey, network }) {
let magic = null;
let ether = null;
try {
await this.deactivate();
} catch (error) {
// Do nothing
}
if (!email) {
throw new Error('"email" not provided, please provide Email');
}
if (!apiKey) {
throw new Error('"apiKey" not provided, please provide Api Key');
}
if (!network) {
throw new Error('"network" not provided, please provide network');
}
Thanks for the input, totally sharp, I was looking at an older version. However, I’m using the correct version in my bare bone test setup from https://unpkg.com/moralis/dist/moralis.js
Still throws the same error, caused by callingMoralis.enableWeb3({ provider: "magicLink" }) when a user has been found. Not only after login, but also on reloading the page and user session.
Ok so I was calling enableWeb() right after authenticate(), which is not needed I found out, as authenticate already adds Moralis.web3.
So logging in is fine now, but when I refresh or come back to an existing user session, I’m already authenticated so I need to call enableWeb().
How do I know the provider options for the current user session?
I cannot call it with just await Moralis.enableWeb3({provider: state.provider}), this will always throw ‘missing clientId’ or ‘email’ or any params you need to set when connecting to an alternative provider.
whichever way I look at the code, Moralis.enableWeb3() is always wanting to do a new login and I have to provide all options. So basically there is no session that can be restored on refresh, it’s always forcing a new login and forcing those options.
For example for Magic Link there’s magic.user.isLoggedIn() to check a valid session https://magic.crisp.help/en/article/how-are-sessions-handled-with-magic-1h92t2s/
But what the MagicWeb3Connector does is always log in again when calling enableWeb3().
Can 100% confirm now I have have WC working, session is restored on refresh, transactions all good, can switch back and forth between a WC and Metamask user without issues
If the RPC stays healthy, should be fine. I did loose connection one time between the mobile and website and had to logout and login again. Will see later if I can catch that somehow to warn the user.
As for Web3Auth and Magic Link, the main issue remains that I cannot call Moralis.enableWeb3() when a user is found on refresh. Unlike WC, it’s asking for all options to be passed, not only the provider name.
As discussed already in this thread, this does not work for both Web3Auth and Magic:
function loginMagic() {
Moralis.authenticate({
provider: 'magicLink',
email: '[email protected]',
apiKey: 'pk_live_xxx',
network: 'rinkeby',
})
.then((user) => {
// all fine
console.log('Magic user', user);
console.log(user.get('ethAddress'))
})
}
// enable web3 if user present
window.addEventListener('load',
async function() {
if (Moralis.User.current()) {
const web3 = await Moralis.enableWeb3({ provider: 'magicLink' })
// throws error missing options
}
}
})
Looking at the code, I would suggest to check for magic.user.isLoggedIn() and call magic.auth.loginWithMagicLink() when no user session has been found?
Hard to debug the rest if I cant refresh properly, but have been able to done some tx.
It’s crazy this Magic Link… there are no confirmation windows, no wallet(?), it just goes wow…Feels funny. Question is, can I see my wallet elsewhere or should I build additional wallet features inside my app?
It’s working now. Found out that I have to save the user email myself when signing up with Magic Link and also save the used provider to the User object. This way I can enabledWeb() with the right params on reload. Here’s some boilerplate to set up and test multiple auth options for Rinkeby:
const serverUrl = 'xxx';
const appId = 'xxx';
Moralis.start({ serverUrl, appId });
// metamask
async function loginMM() {
let user = Moralis.User.current();
if (!user) {
try {
await Moralis.authenticate()
initUser()
} catch(error) {
console.log(error)
}
}
}
// wallet connect
async function loginWC() {
if (!Moralis.User.current()) {
Moralis.authenticate({ provider: 'walletconnect', chainId: 4 })
.then((user) => {
// save the provider to User object, optionally check if already set
user.set('provider', 'walletconnect')
user.save()
initUser()
})
}
}
// magic link
function loginMagic() {
if (!Moralis.User.current()) {
const email = document.getElementById('email').value
Moralis.authenticate({
provider: 'magicLink',
email: email,
apiKey: 'xxx',
network: 'rinkeby',
})
.then((user) => {
// save the email and provider to User object, optionally check if already set
user.set('email', email)
user.set('provider', 'magicLink')
user.save()
initUser()
})
}
}
// set web3 and get user balance to test it
async function initUser () {
const user = Moralis.User.current()
if (user) {
if (!Moralis.ensureWeb3IsInstalled()) {
const userProvider = user.get('provider')
let providerOptions
switch (userProvider) {
case 'magicLink':
providerOptions = {
provider: 'magicLink',
email: user.get('email'),
apiKey: 'xxx',
network: 'rinkeby',
}
break
case 'walletconnect':
providerOptions = {
provider: 'walletconnect',
chainId: 4,
}
break
default:
// metamask
providerOptions = null
}
try {
await Moralis.enableWeb3(providerOptions)
} catch (err) {
console.log(err);
}
}
Moralis.web3.getBalance(user.get('ethAddress'))
.then((balance) => {
document.getElementById('balance').firstElementChild.textContent = Moralis.web3Library.utils.formatEther(balance)
})
}
}
async function logOut() {
await Moralis.User.logOut();
document.getElementById('balance').firstElementChild.textContent = 'logged out'
}
document.getElementById('btn-loginMM').onclick = loginMM;
document.getElementById('btn-loginWC').onclick = loginWC;
document.getElementById('btn-loginMagic').onclick = loginMagic;
document.getElementById('btn-logout').onclick = logOut;
// init user on reload
window.addEventListener('load', initUser);
Not sure why Moralis implementation doesn’t save the email or set a provider. Maybe the React boilerplate does this already, but I’m allergic to anything related to FB
await Moralis.enableWeb3(providerOptions) This doesn’t work for wallet connect. Isn’t web3 supposed to be enabled for desktop browser wallet transactions like metamask.
How can you keep the same log-in authenticated state as someone who logs in with a mobile wallet with wallet connect?