Closed jay-benzatine closed 1 year ago
I have the exact same problem. Did you even manage to connect your wallet with the new package? Because my wallet is opening, but no request is shown to connect. Im really need a solution urgently, because by app relies on that code too...
In the example dapp, this is how I send a transaction:
static Future<dynamic> ethSendTransaction({
required Web3App web3App,
required String topic,
required String chainId,
required EthereumTransaction transaction,
}) async {
return await web3App.request(
topic: topic,
chainId: chainId,
request: SessionRequestParams(
method: methods[EIP155Methods.ethSendTransaction]!,
params: [transaction.toJson()],
),
);
}
And the EthereumTransaction class:
@JsonSerializable(includeIfNull: false)
class EthereumTransaction {
final String from;
final String to;
final String value;
final String? nonce;
final String? gasPrice;
final String? maxFeePerGas;
final String? maxPriorityFeePerGas;
final String? gas;
final String? gasLimit;
final String? data;
EthereumTransaction({
required this.from,
required this.to,
required this.value,
this.nonce,
this.gasPrice,
this.maxFeePerGas,
this.maxPriorityFeePerGas,
this.gas,
this.gasLimit,
this.data,
});
factory EthereumTransaction.fromJson(Map<String, dynamic> json) =>
_$EthereumTransactionFromJson(json);
Map<String, dynamic> toJson() => _$EthereumTransactionToJson(this);
@override
String toString() {
return 'WCEthereumTransaction(from: $from, to: $to, nonce: $nonce, gasPrice: $gasPrice, maxFeePerGas: $maxFeePerGas, maxPriorityFeePerGas: $maxPriorityFeePerGas, gas: $gas, gasLimit: $gasLimit, value: $value, data: $data)';
}
}
I built the EthereumTransaction myself. You might be able to use Web3Dart library and serialize it to JSON that way.
I have the exact same problem. Did you even manage to connect your wallet with the new package? Because my wallet is opening, but no request is shown to connect. Im really need a solution urgently, because by app relies on that code too...
@Jens05 - if the wallet app opens but there is no request - double check you have encoded the URI. With V2 there are [] in the URI that need to be properly encoded.
There is code in this ticket https://github.com/WalletConnect/WalletConnectFlutterV2/issues/113#issuecomment-1614202796
Perhaps you can use this repo:
https://pub.dev/packages/walletconnect_modal_flutter
And call the launchCurrentWallet
function to open the currently connected wallet.
Either way, you can use that repo as an example of how to launch the currently connected wallet.
I understand opening the wallet is not the issue.
Your issue is that the URI is not encoded properly. I dealt with this while building this package https://pub.dev/packages/walletconnect_modal_flutter
Here is the code I use to build the proper URI:
@override
Uri? formatNativeUrl(String? appUrl, String wcUri) {
if (appUrl == null || appUrl.isEmpty) return null;
if (isHttpUrl(appUrl)) {
return formatUniversalUrl(appUrl, wcUri);
}
String safeAppUrl = appUrl;
if (!safeAppUrl.contains('://')) {
safeAppUrl = appUrl.replaceAll('/', '').replaceAll(':', '');
safeAppUrl = '$safeAppUrl://';
}
String encodedWcUrl = Uri.encodeComponent(wcUri);
LoggerUtil.logger.i('Encoded WC URL: $encodedWcUrl');
return Uri.parse('${safeAppUrl}wc?uri=$encodedWcUrl');
}
@override
Uri? formatUniversalUrl(String? appUrl, String wcUri) {
if (appUrl == null || appUrl.isEmpty) return null;
if (!isHttpUrl(appUrl)) {
return formatNativeUrl(appUrl, wcUri);
}
String plainAppUrl = appUrl;
if (appUrl.endsWith('/')) {
plainAppUrl = appUrl.substring(0, appUrl.length - 1);
}
String encodedWcUrl = Uri.encodeComponent(wcUri);
LoggerUtil.logger.i('Encoded WC URL: $encodedWcUrl');
return Uri.parse('$plainAppUrl/wc?uri=$encodedWcUrl');
}
Again, you can find this code and use it in the above repo.
@Jens05
You have so many different issues going on dude.
Please open different issue requests for each one, stop hijacking other people's issues with your own stuff.
same trouble
In the example dapp, this is how I send a transaction:
static Future<dynamic> ethSendTransaction({ required Web3App web3App, required String topic, required String chainId, required EthereumTransaction transaction, }) async { return await web3App.request( topic: topic, chainId: chainId, request: SessionRequestParams( method: methods[EIP155Methods.ethSendTransaction]!, params: [transaction.toJson()], ), ); }
And the EthereumTransaction class:
@JsonSerializable(includeIfNull: false) class EthereumTransaction { final String from; final String to; final String value; final String? nonce; final String? gasPrice; final String? maxFeePerGas; final String? maxPriorityFeePerGas; final String? gas; final String? gasLimit; final String? data; EthereumTransaction({ required this.from, required this.to, required this.value, this.nonce, this.gasPrice, this.maxFeePerGas, this.maxPriorityFeePerGas, this.gas, this.gasLimit, this.data, }); factory EthereumTransaction.fromJson(Map<String, dynamic> json) => _$EthereumTransactionFromJson(json); Map<String, dynamic> toJson() => _$EthereumTransactionToJson(this); @override String toString() { return 'WCEthereumTransaction(from: $from, to: $to, nonce: $nonce, gasPrice: $gasPrice, maxFeePerGas: $maxFeePerGas, maxPriorityFeePerGas: $maxPriorityFeePerGas, gas: $gas, gasLimit: $gasLimit, value: $value, data: $data)'; } }
I built the EthereumTransaction myself. You might be able to use Web3Dart library and serialize it to JSON that way.
How can i make an interaction with a contract than using this package?
In the example dapp, this is how I send a transaction:
static Future<dynamic> ethSendTransaction({ required Web3App web3App, required String topic, required String chainId, required EthereumTransaction transaction, }) async { return await web3App.request( topic: topic, chainId: chainId, request: SessionRequestParams( method: methods[EIP155Methods.ethSendTransaction]!, params: [transaction.toJson()], ), ); }
And the EthereumTransaction class:
@JsonSerializable(includeIfNull: false) class EthereumTransaction { final String from; final String to; final String value; final String? nonce; final String? gasPrice; final String? maxFeePerGas; final String? maxPriorityFeePerGas; final String? gas; final String? gasLimit; final String? data; EthereumTransaction({ required this.from, required this.to, required this.value, this.nonce, this.gasPrice, this.maxFeePerGas, this.maxPriorityFeePerGas, this.gas, this.gasLimit, this.data, }); factory EthereumTransaction.fromJson(Map<String, dynamic> json) => _$EthereumTransactionFromJson(json); Map<String, dynamic> toJson() => _$EthereumTransactionToJson(this); @override String toString() { return 'WCEthereumTransaction(from: $from, to: $to, nonce: $nonce, gasPrice: $gasPrice, maxFeePerGas: $maxFeePerGas, maxPriorityFeePerGas: $maxPriorityFeePerGas, gas: $gas, gasLimit: $gasLimit, value: $value, data: $data)'; } }
I built the EthereumTransaction myself. You might be able to use the Web3Dart library and serialize it to JSON that way.
This transaction is working but this transaction method doesn't work with contract call, I mean how to integrate custom contract call with this method?
@Luzzotica Look here is old library "https://pub.dev/packages/walletconnect_dart" code how can do this in this library "https://pub.dev/packages/walletconnect_flutter_v2"?
https://github.com/RootSoft/walletconnect-dart-sdk/tree/master/lib
@Luzzotica I want WalletConnectEthereumCredentials Form connect session how can get that from the new library???
@Luzzotica Hello,
Can you please let me know how can I do transactions using a custom contract using https://pub.dev/packages/walletconnect_flutter_v2 this lib?
If you have a demo then let me know or send an example code for that.
Hello,
I have a solution for that.
You can call the custom contract call using the default web3App.request method in walletconnect_flutter_v2.
For the call custom contract, you need to use the library.
hex.encode(List<int>.from(transaction.data!)),
Here is my full example for the token approval...
Future<bool> getMCTApproval({required double price}) async {
String? transactionId;
try {
/// MAKE TRANSACTION USING web3dart
Transaction transaction = Transaction.callContract(
from: EthereumAddress.fromHex(uData.walletAddress ?? ""),
contract: contractService.mctContract,
function:
contractService.mctContract.function(ContractFunctionsName.approve),
parameters: [
EthereumAddress.fromHex(ContractAddressConstant.marketplaceAddress),
BigInt.from((price) * pow(10, 18))
],
);
/// MAKE ETERUM TRANSACTION USING THE walletconnect_flutter_v2
EthereumTransaction ethereumTransaction = EthereumTransaction(
from: uData.walletAddress ?? "",
to: ContractAddressConstant.mctAddress,
value: "0x0",
data: hex.encode(List<int>.from(transaction.data!)), /// ENCODE TRANSACTION USING convert LIB
);
await _initGoToWallet();
/// REQUEST TO WALLET FOR TRANSACTION USING vwalletconnect_flutter_v2
transactionId = await MyApp.walletConnectHelper.web3App?.request(
topic: MyApp.walletConnectHelper.sessionData?.topic ?? "",
chainId: MyApp.walletConnectHelper.chain.chainId,
request: SessionRequestParams(
method: EIP155.methods[EIP155Methods.ethSendTransaction] ?? "",
params: [ethereumTransaction.toJson()],
),
);
Debug.printLog("TRANSACTION ID", transactionId.toString());
} on Exception catch (_, e) {
e.printError();
Debug.printLog("Catch E", e.toString());
}
return transactionId != null;
}
Hello everyone! I will briefly describe how to send a transaction through Metamask.
1) Initialize WalletConnect
static Web3App? _walletConnect;
Future<void> _initWalletConnect() async {
_walletConnect = await Web3App.createInstance(
projectId: 'c4f79cc821944d9680842e34466bfb',
metadata: const PairingMetadata(
name: 'Flutter WalletConnect',
description: 'Flutter WalletConnect Dapp Example',
url: 'https://walletconnect.com/',
icons: [
'https://walletconnect.com/walletconnect-logo.png',
],
),
);
}
2) Create session with Metamask
static const String launchError = 'Metamask wallet not installed';
static const String kShortChainId = 'eip155';
static const String kFullChainId = 'eip155:80001';
static String? _url;
static SessionData? _sessionData;
String get deepLinkUrl => 'metamask://wc?uri=$_url';
Future<String?> createSession() async {
final bool isInstalled = await metamaskIsInstalled();
if (!isInstalled) {
return Future.error(launchError);
}
if (_walletConnect == null) {
await _initWalletConnect();
}
final ConnectResponse connectResponse = await _walletConnect!.connect(
requiredNamespaces: {
kShortChainId: const RequiredNamespace(
chains: [kFullChainId],
methods: [
'eth_sign',
'eth_signTransaction',
'eth_sendTransaction',
],
events: [
'chainChanged',
'accountsChanged',
],
),
},
);
final Uri? uri = connectResponse.uri;
if (uri != null) {
final String encodedUrl = Uri.encodeComponent('$uri');
_url = encodedUrl;
await launchUrlString(
deepLinkUrl,
mode: LaunchMode.externalApplication,
);
_sessionData = await connectResponse.session.future;
final String account = NamespaceUtils.getAccount(
_sessionData!.namespaces.values.first.accounts.first,
);
return account;
}
return null;
}
3) Create custom EthereumTransaction model
class EthereumTransaction {
const EthereumTransaction({
required this.from,
required this.to,
required this.value,
this.data,
});
final String from;
final String to;
final String value;
final String? data;
Map<String, dynamic> toJson() => {
'from': from,
'to': to,
'value': value,
'data': data,
};
}
4) Create instance of EthereumTransaction
Future<EthereumTransaction> generateTransaction({
required String userId,
required String reseiverId,
}) async {
final EthereumTransaction transaction = EthereumTransaction(
from: userId,
to: reseiverId,
value: '1',
);
return transaction;
}
5) Sign and send transaction with Metamask
Future<Stream<dynamic>?> sendTransaction({
required EthereumTransaction transaction,
}) async {
await launchUrlString(
deepLinkUrl,
mode: LaunchMode.externalApplication,
);
final Future<dynamic> signResponse = _walletConnect!.request(
topic: _sessionData!.topic,
chainId: kFullChainId,
request: SessionRequestParams(
method: 'eth_sendTransaction',
params: [transaction.toJson()],
),
);
return signResponse.asStream();
}
6) You can check info from request() like this
final Stream<dynamic>? stream = await sendTransaction(
transaction: transaction,
);
if (stream != null) {
stream.listen((event) {
log('$event', name: 'Stream event');
});
}
@jay-benzatine From which library is this method?
hex.encode(List<int>.from(transaction.data!))
@ContrastPro
I used this lib for encoding transactions.
convert: ^3.1.1 (https://pub.dev/packages/convert)
I appreciate all the efforts used to answer this issue. But I can see most of you having different solutions which isn't bad. But I guess the solution I will provide is a close answer to what the issue was created for. I think this will be helpful for others coming on this issue to get a simple answer.
WalletConnectEthereumCredentials (Just copy this class):
// ignore: implementation_imports
import 'package:web3dart/crypto.dart';
import 'package:web3dart/src/crypto/secp256k1.dart';
import 'dart:typed_data';
import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart';
import 'package:web3dart/web3dart.dart';
class WalletConnectEthereumCredentials extends CustomTransactionSender {
WalletConnectEthereumCredentials(
{required this.wcClient, required this.session});
final Web3App wcClient;
final SessionData session;
@override
Future<String> sendTransaction(Transaction transaction) async {
final from = await extractAddress();
final signResponse = await wcClient.request(
topic: session.topic,
chainId: 'eip155:80001',
request: SessionRequestParams(
method: 'eth_sendTransaction',
params: [
{
'from': from.hex,
'to': transaction.to?.hex,
'gas': '0x${transaction.maxGas!.toRadixString(16)}',
'gasPrice':
'0x${transaction.gasPrice?.getInWei.toRadixString(16) ?? '0'}',
'value':
'0x${transaction.value?.getInWei.toRadixString(16) ?? '0'}',
'data':
transaction.data != null ? bytesToHex(transaction.data!) : null,
'nonce': transaction.nonce,
}
],
),
);
return signResponse.toString();
}
@override
EthereumAddress get address => EthereumAddress.fromHex(
session.namespaces.values.first.accounts.first.split(':').last);
@override
Future<EthereumAddress> extractAddress() =>
Future(() => EthereumAddress.fromHex(
session.namespaces.values.first.accounts.first.split(':').last));
@override
MsgSignature signToEcSignature(Uint8List payload,
{int? chainId, bool isEIP1559 = false}) {
// TODO: implement signToEcSignature
throw UnimplementedError();
}
@override
Future<MsgSignature> signToSignature(Uint8List payload,
{int? chainId, bool isEIP1559 = false}) {
// TODO: implement signToSignature
throw UnimplementedError();
}
}
Example (Usage):
///Deploys a smart contract using mobile wallet
Future<String> deployContract(
{required Web3App walletConnect,
required SessionData session,
required Uri walletURI,
...
}) async {
//Getting credentials from the provider
var credentials = WalletConnectEthereumCredentials(
wcClient: walletConnect,
session: session,
);
//Constructing web3 client
var web3 = EthInitial();
//Initializing web3 client
await web3.initWeb3(ethereumCredentials: credentials, chainNetwork: chain);
....
//Creating a transaction
final Transaction transaction = Transaction(
...
from: web3.credentials.address,
....
);
//Launching the mobile wallet (Metamask)
launchUrl(walletURI, mode: LaunchMode.externalApplication);
//Getting transaction hash
final String transactionHash =
await credentials.sendTransaction(transaction);
//Getting a receipt through transaction hash
final receipt = await web3.client.getTransactionReceipt(transactionHash);
}
Example for Custom contract call:
///Mints NFT to the specified collection address
Future<String> mintNFT({
required String dataUri,
required int royaltyPercentage,
required Web3App walletConnector,
required SessionData session,
required Uri walletUri,
required Chain chain,
String? collectionAddress,
}) async {
//Getting credentials from the provider
var credentials = WalletConnectEthereumCredentials(
wcClient: walletConnector,
session: session,
);
//Constructing a web3 client
var web3 = EthInitial();
//Initializing web3 client
await web3.initWeb3(ethereumCredentials: credentials, chainNetwork: chain);
//Getting the deployed contract using ABI and contract address
final contract = DeployedContract(
ContractAbi.fromJson(NFTContract.contractABI, ''),
EthereumAddress.fromHex(collectionAddress!),
);
//Create a minting function
final mintFunction = contract.function('mint');
//Create a transaction from contract, mint function and data uri.
var transaction = Transaction.callContract(
contract: contract,
function: mintFunction,
.....
parameters: [dataUri, BigInt.from(royaltyPercentage)],
);
....
}
Hope, this solves the issue. Thanks.
Hello,
I have a solution for that.
You can call the custom contract call using the default web3App.request method in walletconnect_flutter_v2.
For the call custom contract, you need to use the library.
- walletconnect_flutter_v2 => For connect wallet
- web3dart => To make a transaction and send this transaction into the web3App.request method with encoding.
hex.encode(List<int>.from(transaction.data!)),
Here is my full example for the token approval...
Future<bool> getMCTApproval({required double price}) async { String? transactionId; try { /// MAKE TRANSACTION USING web3dart Transaction transaction = Transaction.callContract( from: EthereumAddress.fromHex(uData.walletAddress ?? ""), contract: contractService.mctContract, function: contractService.mctContract.function(ContractFunctionsName.approve), parameters: [ EthereumAddress.fromHex(ContractAddressConstant.marketplaceAddress), BigInt.from((price) * pow(10, 18)) ], ); /// MAKE ETERUM TRANSACTION USING THE walletconnect_flutter_v2 EthereumTransaction ethereumTransaction = EthereumTransaction( from: uData.walletAddress ?? "", to: ContractAddressConstant.mctAddress, value: "0x0", data: hex.encode(List<int>.from(transaction.data!)), /// ENCODE TRANSACTION USING convert LIB ); await _initGoToWallet(); /// REQUEST TO WALLET FOR TRANSACTION USING vwalletconnect_flutter_v2 transactionId = await MyApp.walletConnectHelper.web3App?.request( topic: MyApp.walletConnectHelper.sessionData?.topic ?? "", chainId: MyApp.walletConnectHelper.chain.chainId, request: SessionRequestParams( method: EIP155.methods[EIP155Methods.ethSendTransaction] ?? "", params: [ethereumTransaction.toJson()], ), ); Debug.printLog("TRANSACTION ID", transactionId.toString()); } on Exception catch (_, e) { e.printError(); Debug.printLog("Catch E", e.toString()); } return transactionId != null; }
@jay-benzatine
await _initGoToWallet();
How do i go to the wallet ? is it with the createInstance url ?
Hello,
I have used this library https://pub.dev/packages/walletconnect_dart in my current project and it will not work anymore due to the wallet connect v2 version.
I have changed my code as given by the official doc. And I implemented this library https://pub.dev/packages/walletconnect_flutter_v2.
In my, there is functionality like a custom smart contract method call with dynamic parameters and open Metmask or any wallet for allowance or transaction. In library https://pub.dev/packages/walletconnect_flutter_v2 send transaction method is available but it will not support the custom contract call method how can I do that with this package?
So for that solution, I used this library https://pub.dev/packages/web3dart for custom contract calls.
But in this contract call method, he wants Credentials-WalletConnectEthereumCredentials to verify users.
In this https://pub.dev/packages/walletconnect_flutter_v2 library not getting WalletConnectEthereumCredentials like this lib https://pub.dev/packages/walletconnect_dart.
Here is my custom contract call function for Token Approval. But in that code, I have not gotten Credentials from walletconnect_flutter_v2 2.0.12 new library so how can I do that?
Anyone, can you help me with this how can I do this? My project is stopped working. I want a solution urgently.