Closed Temitope3665 closed 3 weeks ago
Hello! I checked your issue and did not find any connection problems.
Device: iphone 13 OS: ios 17.5.1 browser: Safari
Hello, @Temitope3665. Can you give us some more details of your problem?
aepp-sdk
your project is using?Are you having trouble connecting to the native app or the web version on mobile devices?
If it is possible maybe share the link to your project.
"@aeternity/aepp-sdk": "^13.2.2"
I tried using deeplink but whenever I want to make a transaction, I keep getting I'm not connected to the wallet.
Could you share the code that works generally instead here? or Below is the function that I'm using to connect wallet, if you can help update it with the correct, I would be happy.
export const connectWallet = async ({ setConnectingToWallet, setEnableIFrameWallet, setUser, address, setConnectionError, setOpenModal, isHome, walletObj = { info: { name: '', type: '' } }, aeSdk, }: ConnectWalletParams) => { setConnectingToWallet(true); let addressDeepLink: any;
if ((IS_MOBILE || isSafariBrowser()) && !IN_FRAME) {
if (address) {
setConnectingToWallet(false);
return;
}
if (isHome) {
const domainName =
typeof window !== 'undefined' && window.location.origin;
const dashboardURL = ${domainName}/${DASHBOARD_URL}/
;
addressDeepLink = createDeepLinkUrl({
type: 'address',
'x-success': ${ dashboardURL.split('?')[0] }?address={address}&networkId={networkId}
,
'x-cancel': dashboardURL.split('?')[0],
});
} else {
addressDeepLink = createDeepLinkUrl({
type: 'address',
'x-success': ${ window.location.href.split('?')[0] }?address={address}&networkId={networkId}
,
'x-cancel': window.location.href.split('?')[0],
});
}
if (typeof window !== 'undefined') {
window.location.replace(addressDeepLink);
}
} else {
try {
await resolveWithTimeout(30000, async () => {
const webWalletTimeout = IS_MOBILE
? 0
: setTimeout(() => setEnableIFrameWallet(true), 15000);
let resolve: any = null;
let rejected = (e: any) => {
throw e;
};
let stopScan: any = null;
const connectWallet = async (wallet: any) => {
try {
const { networkId } = await aeSdk.connectToWallet(
wallet.getConnection()
);
const ret = await aeSdk.subscribeAddress('subscribe', 'connected');
const {
address: { current },
} = ret;
const currentAccountAddress = Object.keys(current)[0];
if (!currentAccountAddress) return;
stopScan?.();
const user = { address: currentAccountAddress, isConnected: true };
setUser(user);
aeSdks = aeSdk;
// localStorage.setItem('user', JSON.stringify(user));
resolve?.(currentAccountAddress);
setOpenModal(false);
} catch (e: any) {
if (!(e instanceof RpcRejectedByUserError)) {
alert('error occured');
}
if (e.message === 'Operation rejected by user') {
toast.error(e.message);
resolve = null;
rejected = (e: any) => {
throw e;
};
stopScan = null;
}
console.log(e.message);
rejected(e);
}
};
if (walletObj.getConnection) {
await connectWallet(walletObj);
} else {
const handleWallet = async ({ wallets }: any) => {
const detectedWalletObject = Object.values(wallets).find(
(wallet: any) => wallet.info.name === walletObj.info.name
);
if (!detectedWalletObject) return;
clearInterval(webWalletTimeout);
await connectWallet(detectedWalletObject);
};
const scannerConnection = new BrowserWindowMessageConnection();
stopScan = walletDetector(scannerConnection, handleWallet);
await new Promise((_resolve: any, _rejected: any) => {
resolve = _resolve;
rejected = _rejected;
});
}
});
} catch (error) {
if (walletObj.info.name === 'Superhero') {
setConnectionError({
type: 'denied',
message:
'Login with your wallet has failed. Please make sure that you are logged into your wallet.',
});
} else {
setConnectionError({
type: 'timeout',
message: `Connection to ${walletObj.info.name} has been timeout, please try again later.`,
});
}
}
} };
`export const connectWallet = async ({ setConnectingToWallet, setEnableIFrameWallet, setUser, address, setConnectionError, setOpenModal, isHome, walletObj = { info: { name: '', type: '' } }, aeSdk, }: ConnectWalletParams) => { setConnectingToWallet(true); let addressDeepLink: any;
if ((IS_MOBILE || isSafariBrowser()) && !IN_FRAME) {
if (address) {
setConnectingToWallet(false);
return;
}
if (isHome) {
const domainName =
typeof window !== 'undefined' && window.location.origin;
const dashboardURL = ${domainName}/${DASHBOARD_URL}/
;
addressDeepLink = createDeepLinkUrl({
type: 'address',
'x-success': ${ dashboardURL.split('?')[0] }?address={address}&networkId={networkId}
,
'x-cancel': dashboardURL.split('?')[0],
});
} else {
addressDeepLink = createDeepLinkUrl({
type: 'address',
'x-success': ${ window.location.href.split('?')[0] }?address={address}&networkId={networkId}
,
'x-cancel': window.location.href.split('?')[0],
});
}
if (typeof window !== 'undefined') {
window.location.replace(addressDeepLink);
}
} else {
try {
await resolveWithTimeout(30000, async () => {
const webWalletTimeout = IS_MOBILE
? 0
: setTimeout(() => setEnableIFrameWallet(true), 15000);
let resolve: any = null;
let rejected = (e: any) => {
throw e;
};
let stopScan: any = null;
const connectWallet = async (wallet: any) => {
try {
const { networkId } = await aeSdk.connectToWallet(
wallet.getConnection()
);
const ret = await aeSdk.subscribeAddress('subscribe', 'connected');
const {
address: { current },
} = ret;
const currentAccountAddress = Object.keys(current)[0];
if (!currentAccountAddress) return;
stopScan?.();
const user = { address: currentAccountAddress, isConnected: true };
setUser(user);
aeSdks = aeSdk;
// localStorage.setItem('user', JSON.stringify(user));
resolve?.(currentAccountAddress);
setOpenModal(false);
} catch (e: any) {
if (!(e instanceof RpcRejectedByUserError)) {
alert('error occured');
}
if (e.message === 'Operation rejected by user') {
toast.error(e.message);
resolve = null;
rejected = (e: any) => {
throw e;
};
stopScan = null;
}
console.log(e.message);
rejected(e);
}
};
if (walletObj.getConnection) {
await connectWallet(walletObj);
} else {
const handleWallet = async ({ wallets }: any) => {
const detectedWalletObject = Object.values(wallets).find(
(wallet: any) => wallet.info.name === walletObj.info.name
);
if (!detectedWalletObject) return;
clearInterval(webWalletTimeout);
await connectWallet(detectedWalletObject);
};
const scannerConnection = new BrowserWindowMessageConnection();
stopScan = walletDetector(scannerConnection, handleWallet);
await new Promise((_resolve: any, _rejected: any) => {
resolve = _resolve;
rejected = _rejected;
});
}
});
} catch (error) {
if (walletObj.info.name === 'Superhero') {
setConnectionError({
type: 'denied',
message:
'Login with your wallet has failed. Please make sure that you are logged into your wallet.',
});
} else {
setConnectionError({
type: 'timeout',
message: `Connection to ${walletObj.info.name} has been timeout, please try again later.`,
});
}
}
} };`
I think the problem might be in the sdk version. Version 13.3.1
containing an invisible breaking change. Since the version of the protocol for mainnet node was raised to 7.0.0 and the previous sdk is not supporting it.
https://github.com/aeternity/aepp-sdk-js/releases/tag/v13.3.1
What fix would you suggest?
The potential fixes are listed in the aepp-sdk
release description. Our wallet currently using version version 13.3.1
.
Alright, I will check out the release description.
Hi, @Temitope3665. Were you able to resolve your issue?
No. It has not been resolved yet
Hi, @Temitope3665. I have few more clarification questions:
Yes, it's connecting successfully, and here is the deep link it's generating below Deeplink URL result
Attached below is the response during the connection.
But the issue here is that, whenever we want to make a transaction or initiate an activity with the wallet, it keeps saying, wallet not connected. Here is a sample of how the error
In order to sign/send transaction on mobile, you are to create a new deeplink with the transaction details as such. https://github.com/superhero-com/superhero-wallet/issues/2679#issuecomment-1921008234 Currently we don't have any docs regarding deeplink creation. It seems that we need to create such (judging from this issue).
Alright. I will check the thread. That should help with the issue.
Could you help with how best to go about it especially when interacting with contract? We're building a DAO system, by interacting with the contract, I mean creating a dao, creating a proposal, etc...
This is a small example.
const createDeepLinkUrl = ({ type, callbackUrl, ...params }) => {
const url = new URL(`https;//wallet.superhero.com/${type}`);
if (callbackUrl) {
url.searchParams.set('x-success', callbackUrl);
url.searchParams.set('x-cancel', callbackUrl);
}
Object.entries(params)
.filter(([, value]) => ![undefined, null].includes(value))
.forEach(([name, value]) => url.searchParams.set(name, value));
return url;
};
const contract = await aeSdk.initializeContract(
{
aci,
address,
},
);
const result = await contract[method](
...methodArgs,
{
callStatic: true,
// Instead of `onAccount` property you can use `replace-caller` flag in the deep link
onAccount: createOnAccountObject(address),
},
);
const encodedTx = result.rawTx;
const currentUrl = new URL(window.location.href);
// reset url
currentUrl.searchParams.delete('transaction');
currentUrl.searchParams.delete('transaction-status');
// append transaction parameter for success case
const successUrl = new URL(currentUrl.href);
successUrl.searchParams.set('transaction', '{transaction}');
// append transaction parameter for failed case
const cancelUrl = new URL(currentUrl.href);
cancelUrl.searchParams.set('transaction-status', 'cancelled');
return createDeepLinkUrl({
type: 'sign-transaction',
transaction: encodedTx,
networkId,
// decode these urls because they will be encoded again
'x-success': decodeURI(successUrl.href),
'x-cancel': decodeURI(cancelUrl.href),
});
Here's the deep link scheme we use. https://github.com/superhero-com/superhero-wallet/blob/develop/docs/deep-link-schema.md
Thank you Cedrink. I was able to do it just like you suggested. Here is the code below. But I keep getting an error relating to pubkey in my console. Could you help me if I'm doing anything wrong or requires an update?
export const createDeepLinkUrl = ({ type, callbackUrl, ...params }: DeepLinkParams): URL => { const url = new URL(
${process.env.NEXT_PUBLIC_WALLET_URL}/${type}`);
if (callbackUrl) { url.searchParams.set('x-success', callbackUrl); url.searchParams.set('x-cancel', callbackUrl); }
Object.entries(params) .filter(([, value]) => value !== undefined && value !== null) // Filter out undefined and null values .forEach(([name, value]) => url.searchParams.set(name, value as string)); // Assert value as string
return url; };
const generateKey: any = () => { const secretKey = CryptoJS.lib.WordArray.random(64).toString(); return secretKey; };
const node = new Node('https://testnet.aeternity.io'); // ideally host your own node const account = new MemoryAccount(generateKey()); const newUserAccount = MemoryAccount.generate();
const aeSdk: any = new AeSdk({ nodes: [{ name: 'testnet', instance: node }], accounts: [account, newUserAccount], // onCompiler: compiler, // remove if step #2 skipped });
const createDeepLinkUrl2 = async ({ type, callbackUrl, ...params }: any) => {
const url = new URL(${process.env.NEXT_PUBLIC_WALLET_URL}/${type}
);
if (callbackUrl) {
url.searchParams.set('x-success', callbackUrl);
url.searchParams.set('x-cancel', callbackUrl);
}
Object.entries(params) .filter(([, value]) => value !== undefined && value !== null) // Filter out undefined and null values .forEach(([name, value]) => url.searchParams.set(name, value as string)); // Assert value as string // Object.entries(params) // .filter(([, value]) => ![undefined, null].includes(value)) // .forEach(([name, value]) => url.searchParams.set(name, value)); return url; };
const createOnAccountObject = () => { const accountObject = aeSdk.addresses()[0]; return accountObject; };
export const contractInterract = async (payload: any) => { const contract = await aeSdk.initializeContract({ aci: basicDAOAci, address: payload.daoContractAddress, });
const result = await contract['createProposal']( payload.proposalType, payload.description, payload.value, payload.target, payload.info, { callStatic: true, onAccount: createOnAccountObject(), } );
const encodedTx = result.rawTx;
const currentUrl = new URL(window.location.href); // reset url currentUrl.searchParams.delete('transaction'); currentUrl.searchParams.delete('transaction-status');
// append transaction parameter for success case const successUrl = new URL(currentUrl.href); successUrl.searchParams.set('transaction', '{transaction}');
// append transaction parameter for failed case const cancelUrl = new URL(currentUrl.href); cancelUrl.searchParams.set('transaction-status', 'cancelled');
return createDeepLinkUrl2({ type: 'sign-transaction', transaction: encodedTx, networkId: 'ae_uat', // decode these urls because they will be encoded again 'x-success': decodeURI(successUrl.href), 'x-cancel': decodeURI(cancelUrl.href), }); }; `
This is the example of createOnAccountObject
function. I think this place might be the reason of the issue. And in general you can take a look at the the dex-ui
implementation of the whole connection feature.
https://github.com/aeternity/dex-ui/blob/main/src/lib/utils.js#L80
Awesome!. Thank you for this. But I noticed a few things after I confirmed, which are;
You should also set flag broadcast
to true in deep link creation if you want wallet to push it to the node.
Yeah. That solves the problem. Thank you. I have a question again, I noticed when redirecting to the success page, that it disconnected the wallet. Is there a way that can be prevented?
You can store user's address in localStorage
.
Yes. That's perfect. Thank you
I think that's problem solved, now that we have a deeplink scheme and an actual example of creating a such in JS. Feel free to open the issue back up if there are any unresolved issues or additional questions.
@CedrikNikita I want to switch the network from our app, although it's switched successfully on our app but, it does not switch on super hero wallet. How can we go about it?
Hi. This is not possible currently. If the user is connected to other dapps in case wallet will change the network for one of them it will change the network for each. It can be frustrated to the users. The only supported wallet api methods are: https://github.com/aeternity/aepp-sdk-js/blob/c8fbffebab588389f088f9a836de457d4d8afa00/src/aepp-wallet-communication/rpc/types.ts#L34-L95 You can explain to the user how to change the network in the wallet manually. If this is not what you need, and it is an important feature for you, please post the use case. You can also propose to have a such api method in the sdk issues https://github.com/aeternity/aepp-sdk-js/issues.
Alright. Thank you. I will do that.
Describe the bug I can connect the wallet to my project on my web but after mobile responsiveness was updated on the project, I could not connect the wallet on mobile phones.
To Reproduce Steps to reproduce the behavior:
Expected behavior I should be able to connect to my wallet on my smartphones exactly how it worked well on the web.
Screenshots Attached screenshot
Desktop (please complete the following information):
Smartphone (please complete the following information):
Additional context Add any other context about the problem here.