There is a website with a built-in dapp. There are two buttons: {account info} and {contract info}. When you click on the first button, the code implies loading addresses and balance through window.ethereum.request({ method: "eth_requestAccounts" }) and window.ethereum.request({ method: "eth_getBalance", params: [selectedAccount] }).
On the computer it works great:
But on mobile metamask browser not working (button is not pressed):
Second button works fine both on computer and mobile (contains vanilla text without functions). Earlier I used web3.js and with functions that loaded when loading the page was not problems. Now, I use window.ethereum and think the problem can be from the window onload, with whom I do not know how to contact. Hook provider:
const provider = await detectEthereumProvider()
if (provider) {
web3 = new Web3(window.ethereum);
document.getElementById("status_connect").innerHTML = ""
} else {
document.querySelector("#status_wallet").style.display = "block";
}
I do not know what the problem is, tell me, please
Related
Metamask Confirm button not working, couldn't confirm transaction for a smart contract.
I use JS and WalletConnectProvider (website project). Connecting to Metamask by WalletConnect, then call transfer function for custom token contract. I use the same code on desktop and it works and transferring token. Exactly the same code doesn't work on mobile (for Metamask Mobile app). Checked IOS and also Android - the same issue.
Please tell me what is wrong with my code:
<script src="https://cdn.jsdelivr.net/npm/#walletconnect/web3-provider#1.8.0/dist/umd/index.min.js"></script>
<script src="https://[mywebsitescriptspath]/web3.min.js"></script> // 1.8.0
<script type="text/javascript">
var contract
var accountFrom
const ABI = "... abi here....."
var provider = new WalletConnectProvider.default({
infuraId: 'my infura id',
rpc: {
1: "https://mainnet.infura.io/v3/[myinfuraid]",
56: "https://bsc-dataseed.binance.org/"
},
})
const contractAddress = '0xcontraddresshere'
const receiver = '0xreceiveraddresshere'
var connect = async () => {
await provider.enable()
var web3 = new Web3(provider)
web3.givenProvider = web3.currentProvider
web3.eth.givenProvider = web3.currentProvider
web3.eth.accounts.givenProvider = web3.currentProvider
window.w3 = web3
contract = new w3.eth.Contract(ABI, contractAddress)
await w3.eth.getAccounts().then(accounts => {
accountFrom = accounts[0]
})
}
connect()
// function called after the button click
var sendtransaction = async () => {
let vall = 100
let calcAmount = w3.utils.toWei(vall.toString())
let transfer = await contract.methods.transfer(receiver, calcAmount);
await transfer.send({from: accountFrom})
.on('transactionHash', function(hash){
console.log(hash)
})
}
</script>
I tried many different things but it doesn't work.
Tested on wifi, on 4g, on different mobile browsers, on different smartphones (android and IOS).
no success.
The problem started from 5.9.0 Metamask app version.
UPDATE:
Now at 5.10.0 version it doesn't recognize custom contract token. For example when I want to transfer 1 token, it shows 1 BNB.
Last version was better :))
There are open issues on github:
https://github.com/MetaMask/metamask-mobile/issues/5193
https://github.com/MetaMask/metamask-mobile/issues/5235
https://github.com/MetaMask/metamask-mobile/issues/5260
No solution till now - after 14 days.
Change version metamask, working me version - 5.7.0
This issue was solved with the Metamask 5.11.0 updated for IOS 16.1.1. Update your Metamask app to 5.11.0.
Reference: https://github.com/MetaMask/metamask-mobile/issues/5260
Yes, actually they didn't resolve the issue.
In my case, different ERC20 tokens have different result.
On this token, the blue confirm button doesn't work.
https://etherscan.io/token/0x377e0c5d3738FAcd2D4c1CA192c774e978E8e95b#writeContract
But on USDC (0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48)
It works well.
iOS ver 16.1.2
MetaMask v5.12.0
I'm hoping to migrate from using WebUSB to SerialAPI (which is explained nicely here).
Current Code:
try {
let device = await navigator.usb.requestDevice({
filters: [{
usbVendorId: RECEIVER_VENDOR_ID
}]
})
this.connect(device)
} catch (error) {
console.log(DEVICE_NAME + ': Permission Denied')
}
New Code:
try {
let device = await navigator.serial.requestPort({
filters: [{
usbVendorId: RECEIVER_VENDOR_ID
}]
})
this.connect(device)
} catch (error) {
console.log(DEVICE_NAME + ': Permission Denied')
}
The new code appears to work, but I think it's because the browser has already requested the device via the old code.
I've tried restarting Chrome as well as clearing all of the browsing history. Even closed the USB-claiming page and claimed the device with another app (during which it returns the DOMException: Unable to claim interface error), but Chrome doesn't seem to want to ask again. It just happily streams the data with the previous connection.
My hope was that using SerialAPI would be a way to avoid fighting over the USB with other processes, or at least losing to them.
Update
I had forgotten about:
Failed to execute 'requestPort' on 'Serial': "Must be handling a user gesture to show a permission request"
Does this mean that the user will need to use a button to connect to the device via SerialUSB? I think with WebUSB I was able to make the connect window automatically pop up.
For both APIs, as is noted in the update, a user gesture is required in order to call the requestDevice() or requestPort() method. It is not possible to automatically pop up this prompt. (If there is that's a bug so please let the Chrome team know so we can fix it.)
Permissions granted to a site through the WebUSB API and Web Serial API are currently tracked separately so permission to access a device through one will not automatically translate into the other.
There is not currently a way to programatically forget a device permission. That would require the navigator.permissions.revoke() method which has been abandoned. You can however manually revoke permission to access the device by clicking on the "lock" icon in the address bar while visiting the site or going to chrome://settings/content/usbDevices (for USB devices) and chrome://settings/content/serialPorts (for serial ports).
To get Chrome to "forget" the WebUSB device previously paired via navigator.usb.requestDevice API:
Open the page paired to the device you want to forget
Click on the icon in the address bar
Click x next to device. If nothing is listed, then there are no paired devices for this web page.
The new code was NOT working. It just appeared to be because Chrome was already paired with the port via the old code. There is no way the "new code" could have worked because, as noted in Kalido's comment, the SerialAPI (due to its power) requires a user gesture to connect.
The code I'm using to actually connect and get data is basically built up from a few pieces from the above links in the OP:
navigator.serial.addEventListener('connect', e => {
// Add |e.target| to the UI or automatically connect.
console.log("connected");
});
navigator.serial.addEventListener('disconnect', e => {
// Remove |e.target| from the UI. If the device was open the disconnection can
// also be observed as a stream error.
console.log("disconnected");
});
console.log(navigator.serial);
document.addEventListener('DOMContentLoaded', async () => {
const connectButton = document.querySelector('#connect') as HTMLInputElement;
if (connectButton) {
connectButton.addEventListener('click', async () => {
try {
// Request Keiser Receiver from the user.
const port = await navigator.serial.requestPort({
filters: [{ usbVendorId: 0x2341, usbProductId: not_required }]
});
try {
// Open and begin reading.
await port.open({ baudRate: 115200 });
} catch (e) {
console.log(e);
}
while (port.readable) {
const reader = port.readable.getReader();
try {
while (true) {
const { value, done } = await reader.read();
if (done) {
// Allow the serial port to be closed later.
reader.releaseLock();
break;
}
if (value) {
console.log(value);
}
}
} catch (error) {
// TODO: Handle non-fatal read error.
console.log(error);
}
}
} catch (e) {
console.log("Permission to access a device was denied implicitly or explicitly by the user.");
console.log(e);
console.log(port);
}
}
}
The device-specific Vendor and Product IDs would obviously change from device to device. In the above example I have inserted an Arduino vendor ID.
It doesn't answer the question of how to get Chrome to "forget", but I'm not sure if that's relevant when using SerialAPI because of the required gesture.
Hopefully someone with more experience will be able to post a more informative answer.
everyone!
I'm new to TestCafe and I need some help on something I want to achieve.
I have a React website where I put a Facebook Login. Normally, when you enter the page and click on Login with facebook a popup window opens and enter your credentials normally. After that, you are redirected to the page and the token is saved in a localStorage variable for the page to consult later on.
However, when I run test for login process, Testcafe instead of opening a popup window, opens the facebook form on the same page and never redirects to the page.
Also, I tried to set some dummy token on the localstorage using the ClientFunction (and also Roles) and my website can never reach that token because testcafe seems to put this variable on a key called hammerhead
So, my question here is, how could I enter this token on the test or manually so my website can read it and make some functions with it?
This is what I have so far.
/* global test, fixture */
import { WelcomePage } from './pages/welcome-page'
import {ClientFunction, Role} from 'testcafe';
const welcomePage = new WelcomePage()
const setLocalStorageItem = ClientFunction((prop, value) => {
localStorage.setItem(prop, value);
});
const facebookAccUser = Role(`https//mypage.net/`, async t => {
await setLocalStorageItem('token', 'my-token');
}, { preserveUrl: true });
fixture`Check certain elements`.page(`https//mypage.net/`)
test('Check element is there', async (t) => {
await t
.navigateTo(`https//mypage.net/`)
.wait(4000)
.useRole(facebookAccUser)
.expect(cetainElementIfLoggedIn)
.eql(certainValue)
.wait(10000)
})
Any help would be highly appreciated
Thanks for your time.
UPDATE FROM FEB 2021
TestCafe now supports multiple browser windows and you can log-in via the Facebook popup form without any issues. Refer to the Multiple Browser Windows topic for more information.
Currently, TestCafe does not support multiple browser windows. So it's impossible to log in via the Facebook popup form.
However, there is a workaround. Please refer to the following thread https://github.com/DevExpress/testcafe-hammerhead/issues/1428.
My working test look like this:
import { Selector, ClientFunction } from 'testcafe';
const patchAuth = ClientFunction(() => {
window['op' + 'en'] = function (url) {
var iframe = document.createElement('iframe');
iframe.style.position = 'fixed';
iframe.style.left = '200px';
iframe.style.top = '150px';
iframe.style.width = '400px';
iframe.style.height = '300px';
iframe.style['z-index'] = '99999999';
iframe.src = url;
iframe.id = 'auth-iframe';
document.body.appendChild(iframe);
};
});
fixture `fixture`
.page `https://www.soudfa.com/signup`;
test('test', async t => {
await patchAuth();
await t
.click('button.facebook')
.switchToIframe('#auth-iframe')
.typeText('#email', '****')
.typeText('#pass', '****')
.click('#u_0_0')
.wait(30e3);
});
Please keep in mind that manipulations with x-frame-options in the testcafe-hammerhead module are required.
In addition, I would like to mention that Testing in Multiple browser windows is one of our priority tasks, which is a part of TestCafe Roadmap
I am building an app, using polymer starter kit & cordova to wrap the project. Now, since I use firebase as a database for storing data, I ended up using two native firebase javascript function to find user data:
getAuth()
var ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com");
var authData = ref.getAuth();
if (authData) {
console.log("Authenticated user with uid:", authData.uid);
}
onAuth()
var ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com");
ref.onAuth(function(authData) {
if (authData) {
console.log("Authenticated with uid:", authData.uid);
} else {
console.log("Client unauthenticated.")
}
});
Those two functions require a reload to bring back data from firebase, but :
window.location.reload();
doesn't work
Alos looked for a Cordova plugin: webview-reloader, installed it but redirect and reload still not working.
When i use the reload() function the screen of my android phone is going white and the application stop working. Need to close the app and open it again.
Since Cordova is a wrapper around a browser window:
window.location.reload(true);
It works for the browser windows as well as a Cordova app.
This works for iOS and Android (at least with 2016 platform versions).
// keep startup url (in case your app is an SPA with html5 url routing)
var initialHref = window.location.href;
function restartApplication() {
// Show splash screen (useful if your app takes time to load)
navigator.splashscreen.show();
// Reload original app url (ie your index.html file)
window.location = initialHref;
}
if (this.cordovaService) { // is cordova
this.window.location.href = `${this.window.location.protocol}//${this.window.location.host}`;
} else {
this.window.location.reload();
}
Similar questions have been asked, but the solutions to those problems don't seem to help me.
I've got a local development site set up running on a virtual machine: http://lamp.site
When the index.php loads, I've got this javascript running (with the correct appId):
/* facebook auth */
window.fbAsyncInit = function() {
FB.init({
appId: '01234567890',
channelUrl: 'http://lamp.site/channel.html'
});
};
// Load the SDK Asynchronously
(function(d){
var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
if (d.getElementById(id)) {return;}
js = d.createElement('script'); js.id = id; js.async = true;
js.src = "//connect.facebook.net/en_US/all.js";
ref.parentNode.insertBefore(js, ref);
}(document));
Then when a button is clicked, this javascript function is triggered:
#HTML
<li><a class="btn" href="#" ng-click="connectToFacebook()">Connect with Facebook</a></li>
#Snippet in AngularJS Controller
$scope.connectToFacebook = function() {
facebookConnect.authenticate(
function(reason) { // fail
console.log(reason);
},
function(user) { // success
console.log('logged in',user);
//Session.login();
});
return false;
}
#Factory in AngularJS module
.factory('facebookConnect', function() {
return {
authenticate: function(fail, success) {
FB.login(function(response) {
console.log(response);
if (response.authResponse) {
FB.api('/me', success);
} else {
fail('User cancelled login or did not fully authorize.');
}
});
}
}
If I press the button in Firefox, it works! Lovely, I get all the right things back from Facebook.
If I use Chrome or Safari on my PC, or Safari Mobile on my iPhone, I get the facebook login window popup with the message "An error occurred. Please try again later.", and the following console data:
Unsafe JavaScript attempt to access frame with URL
https://www.facebook.com/dialog/permissions.request from frame with URL
http://lamp.site/index.php?page=login. Domains, protocols and ports must match.
Object
authResponse: null
status: "not_authorized"
__proto__: Object
User cancelled login or did not fully authorize.
I've got my local testing URL added into the facebook app in the developer section, that works because it logs in with Firefox. This is my channels file, stored at http://lamp.site/channel.html
<script src="http://connect.facebook.net/en_US/all.js"></script>
I've tried having the channel file with and without http: in the src= tag.
The facebook app has the following settings:
App domains: lamp.site
Site URL: http://lamp.site
Mobile site URL: http://lamp.site
So it works in Firefox, what the hell am I doing wrong. I can't just enable cross site scripting as users wouldn't do that and this is going into a mobile site.
Anyone else managed to solve this problem recently?
All the other similar questions have gone unanswered... someone must have fixed this!
EDIT: I've made a simplified version, new app ID, on my website.
http://dev.willshawmedia.com/fb/
Here is the screen shot with the app ID from Facebook Dev application panel
You can look at the source code, it's copied straight from here:
https://developers.facebook.com/docs/guides/web/
And the channel file does exist:
http://dev.willshawmedia.com/fb/channel.html
I can't make it any simpler, I still get the "An error occurred. Please try again later." message, but now it just forwards onto Facebook instead of authenticating and closing.
Edit: I was missing the site URLs, I've added those, the simple example is working.
As it's working on my live site, it must be to do with my local domains. But I've got this line in my /etc/hosts/ file:
192.168.0.13 lamp.site
That's the IP address of the VirtualBox Ubuntu server running on my laptop. I can browse that site fine.
Sandbox Mode must be disabled for it to work in Chrome. That's it, that's all it took.
I enabled that mode as I thought that would stop it showing up in searches, which I don't want. And as it worked in Firefox I couldn't see that being a problem. But there you go, I switched off sandbox mode and it started working immediately.
I don't under stand that why that is stopping Chrome though.
Your factory has some strange JavaScript: return new function() ... outside of that I don't see an issue. I'm using this same basic technique and I don't have any problems in Chrome.
Be sure your Facebook application is set up to your domain (let's call it "mydomain.com")... THEN, to test locally, you'll need to edit your hosts file to point mydomain.com to 127.0.0.1... so the URL in the browser location matches what Facebook is expecting.
That's probably the only difference between what I'm doing and what you're doing.
... also make sure your App ID is the proper App ID from setting up your Facebook Application. Double check it. BS "test" App ID's will give you the error message as well.
-
-
EDIT : on the new function(){ } front... which I don't think is your problem.... I want to explain a little more:
var x = new function() { this.foo = 'test'; };
is the same as
var x = { foo: 'test' };
Because the new keyword is used to call a function as an object constructor, and you're using new on an anonymous function that you can't use again, so there is no reason to declare it.
So your snippet could (and probably should) be:
.factory('facebookConnect', function() {
return {
authenticate: function(fail, success) {
FB.login(function(response) {
console.log(response);
if (response.authResponse) {
FB.api('/me', success);
} else {
fail('User cancelled login or did not fully authorize.');
}
});
}
}
});