Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interact with Smart Contrat #246

Closed
david-dyn opened this issue Jan 10, 2024 · 35 comments
Closed

Interact with Smart Contrat #246

david-dyn opened this issue Jan 10, 2024 · 35 comments

Comments

@david-dyn
Copy link

Hello

I need to send transaction with currency other then default in network
For example Pri in Binance Smart Chain
I need to send 0.001 PRI not 0.001 BNB
IMG_20240110_103401

@sargiskocharyan
Copy link

will follow up

@quetool
Copy link
Collaborator

quetool commented Jan 10, 2024

Hello! Tokens are smart contracts so in order to do what you are asking for you should leverage the transfer/transferFrom functions from Privateum smart contract https://bscscan.com/address/0xb10be3f4c7e1f870d86ed6cfd412fed6615feb6f#writeContract

As per how to interact with smart contracts, there's no direct way on our SDK but you can do it through web3dart package, which is a dependency of our SDK.

Here it is an example directly from web3dart repo https://github.com/xclud/web3dart/blob/10151b108fde49dfa7f4f1a5452e38837639df5f/example/contracts.dart

Here it is an example from Celo academy https://celo.academy/t/interact-with-celo-blockchain-using-web3dart/183

And here it is a really simple example on how to read from a Contract using web3dart inside of our Web3Modal package https://docs.walletconnect.com/web3modal/flutter/actions#how-to-read-a-contract

I hope this helps for now. We are working on an more user friendly interaction with contracts from our own SDKs!

@quetool quetool closed this as completed Jan 10, 2024
@david-dyn
Copy link
Author

david-dyn commented Jan 11, 2024

Thank you for your response and solution that you suggested.,
But the solution uses private key, it can cause security issues.

How can we avoid using private key?
Thanks in advance.

@quetool
Copy link
Collaborator

quetool commented Jan 17, 2024

Hello @david-dyn! As of today, the only way to interact with a Smart Contract is through web3dart, which indeed uses private key. We will start soon to work on our own way to interact with Smart Contract without relying on web3dart.

In the meantime you can refer to this Bob's answer here as well #219 (comment)

@quetool quetool pinned this issue Jan 19, 2024
@quetool quetool changed the title Custom transaction with different currency Interact with Smart Contrat Jan 19, 2024
@Mash-Woo
Copy link

Hi, I'll just leave it here

  static Future<dynamic> transfer({
    required W3MService w3mService,
    required EthereumAddress contractAddress,
    required String tokenName,
    required EthereumAddress to,
    required BigInt amount,
  }) async {
    
    final ethClient = Web3Client(
      W3MChainPresets.chains[w3mService.session?.chainId]!.rpcUrl,
      http.Client(),
    );

    final contract = await ContractDetails.getContract(address: contractAddress, name: tokenName);
    final transfer = contract.function('transfer');

    Credentials credentials = WalletConnectEip155Credentials(
        signEngine: w3mService.web3App!.signEngine,
        sessionTopic: w3mService.session!.topic!,
        chainId: w3mService.selectedChain!.namespace,
        credentialAddress:
            EthereumAddress.fromHex(w3mService.session!.address!));

    final transaction = Transaction.callContract(
      contract: contract,
      function: transfer,
      parameters: [
        to,
        amount,
      ],
    );

    final result = ethClient.sendTransaction(
      credentials,
      transaction,
      chainId: int.parse(w3mService.session!.chainId)
    );

    w3mService.launchConnectedWallet();

    return result;
  }

We were helped by Bob's https://gitlab.com/graflr/flutter_web3_demo/-/blob/main/lib/model/wallet_connect_eip155_credential.dart?ref_type=heads

So sorry, but why I can't user WalletConnectEip155Credentials? Can I know what your package is?

@Rudo-dyn
Copy link

I was integrated WalletConnectEip155Credentials in wallet connect example project, and it worked perfectly, web3dart package.

@Mash-Woo
Copy link

I tried, but it does not direct me to metamask with w3mService.launchConnectedWallet();

I was integrated WalletConnectEip155Credentials in wallet connect example project, and it worked perfectly, web3dart package.

@Rudo-dyn
Copy link

Before transaction you need to connect wallet to your dApp, you can check example project.

@quetool
Copy link
Collaborator

quetool commented Jan 20, 2024

I don't see the comment quoted by @Mash-Woo anymore, wasn't it good?

@quetool quetool unpinned this issue Jan 20, 2024
@Rudo-dyn
Copy link

I was delete it, tomorrow I will refactor it, that everyone can understand it 🙃

@Mash-Woo
Copy link

Before transaction you need to connect the wallet to your dApp, you can check example project.

Thank you. Now, I fixed a bit and it worked with my code, but do you know how to let user automatically change the chain to the chain that deployed the contract. My contract is on Arbitrum but when I click send transaction it often direct user to Ethereum chain

@Mash-Woo
Copy link

Hello @david-dyn! As of today, the only way to interact with a Smart Contract is through web3dart, which indeed uses private key. We will start soon to work on our own way to interact with Smart Contract without relying on web3dart.

In the meantime you can refer to this Bob's answer here as well #219 (comment)

Hi @quetool , I tried many different ways, but if I use web3dart to send transactions, how can I get user's private key with web3modal, I am seeing that I can't get the user's private key if they use a decentralized wallet such as Metamask

@Rudo-dyn
Copy link

Rudo-dyn commented Jan 23, 2024

class CustomCredentialsSender extends CustomTransactionSender {
  CustomCredentialsSender({
    required this.signingEngine,
    required this.sessionTopic,
    required this.chainId,
    required this.credentialsAddress,
  });

  final ISignEngine signingEngine;
  final String sessionTopic;
  final String chainId;
  final EthereumAddress credentialsAddress;

  @override
  EthereumAddress get address => credentialsAddress;

  @override
  Future<String> sendTransaction(Transaction transaction) async {
    if (kDebugMode) {
      print(
          'CustomCredentialsSender: sendTransaction - transaction: ${transaction.prettyPrint}');
    }

    if (!signingEngine.getActiveSessions().keys.contains(sessionTopic)) {
      if (kDebugMode) {
        print(
            'sendTransaction - called with invalid sessionTopic: $sessionTopic');
      }
      return 'Internal Error - sendTransaction - called with invalid sessionTopic';
    }

    SessionRequestParams sessionRequestParams = SessionRequestParams(
      method: 'eth_sendTransaction',
      params: [
        {
          'from': transaction.from?.hex ?? credentialsAddress.hex,
          'to': transaction.to?.hex,
          'data':
              (transaction.data != null) ? bytesToHex(transaction.data!) : null,
          if (transaction.value != null)
            'value':
                '0x${transaction.value?.getInWei.toRadixString(16) ?? '0'}',
          if (transaction.maxGas != null)
            'gas': '0x${transaction.maxGas?.toRadixString(16)}',
          if (transaction.gasPrice != null)
            'gasPrice': '0x${transaction.gasPrice?.getInWei.toRadixString(16)}',
          if (transaction.nonce != null) 'nonce': transaction.nonce,
        }
      ],
    );

    if (kDebugMode) {
      print(
          'CustomCredentialsSender: sendTransaction - blockchain $chainId, sessionRequestParams: ${sessionRequestParams.toJson()}');
    }

    final hash = await signingEngine.request(
      topic: sessionTopic,
      chainId: chainId,
      request: sessionRequestParams,
    );
    return hash;
  }

  @override
  Future<EthereumAddress> extractAddress() {
    // TODO: implement extractAddress
    throw UnimplementedError();
  }

  @override
  Future<MsgSignature> signToSignature(Uint8List payload,
      {int? chainId, bool isEIP1559 = false}) {
    // TODO: implement signToSignature
    throw UnimplementedError();
  }

  @override
  MsgSignature signToEcSignature(Uint8List payload,
      {int? chainId, bool isEIP1559 = false}) {
    // TODO: implement signToEcSignature
    throw UnimplementedError();
  }
}

You can use this custom credentials class instead of using private key, you need to create this class object in your transfer function like this:

Credentials credentials = CustomCredentialsSender(
  signingEngine: w3mService.web3App!.signEngine,
  sessionTopic: w3mService.session!.topic!,
  chainId: w3mService.selectedChain!.namespace,
  credentialsAddress: EthereumAddress.fromHex(w3mService.session!.address!),
);

After it you can use this credentials in your sendTransaction method.

@Mash-Woo
Copy link

Credentials credentials = CustomCredentialsSender(
signEngine: w3mService.web3App!.signEngine,
sessionTopic: w3mService.session!.topic!,
chainId: w3mService.selectedChain!.namespace,
credentialAddress:
EthereumAddress.fromHex(w3mService.session!.address!));

Thank you, I tested it, and it can be sent. However, instead of sending my token according to my contract, it sends Eth. And besides that, if the user rejects it, it will cause bugs. Exception has occurred.
_$JsonRpcErrorImpl (JsonRpcError(code: 5000, message: User rejected the transaction))

@Rudo-dyn
Copy link

Are you use contract abi, and your custom token contract address? Can you share your transfer method code here?

@Mash-Woo
Copy link

Mash-Woo commented Jan 23, 2024

Are you use contract abi and your custom token contract address? Can you share your transfer method code here?

Yes, I tried to use contract details like you, but it does not work for me, so now I am using this

final scAddress = EthereumAddress.fromHex(dotenv.env['WEB3_SC_ADDRESS']!);

Future<void> transferWalletConnect() async {
  String abi = await rootBundle.loadString('backend/contract/namecontract.abi.json');

  final contract =
      DeployedContract(ContractAbi.fromJson(abi, 'nameToken'), scAddress);
  final transfer = contract.function('safeTransferFromFee'); //function from the contract
  log('Check contract ${contract.address}');

  Credentials credentials = CustomCredentialsSender(
      signEngine: w3mService.web3App!.signEngine,
      sessionTopic: w3mService.session!.topic!,
      chainId: w3mService.selectedChain!.namespace,
      credentialAddress:
          EthereumAddress.fromHex(w3mService.address!));

  final transaction = Transaction.callContract(
      contract: contract,
      function: transfer,
      parameters: [
        EthereumAddress.fromHex('$myaddress'),
        EthereumAddress.fromHex('$receiveraddress'),
        BigInt.parse(authProvider.userData!.profile!.mintId!.toString()),
        BigInt.one,
        Uint8List.fromList([])
      ]);
  log('Check credentials $credentials');
  log('Check transaction $transaction');
  final result = ethClient.sendTransaction(credentials, transaction,
      chainId: int.parse(w3mService.selectedChain!.chainId));
  w3mService.launchConnectedWallet();
  w3mService.addListener(() {
    result;
  });
  w3mService.notifyListeners();
}

@Rudo-dyn
Copy link

if your abi is json, use

final contract =
    DeployedContract(ContractAbi.fromJson(jsonEncode(abi), 'nameToken'), scAddress);

And try to use w3mService.session!.chainId instead of w3mService.selectedChain!.chainId

if these steps don't help you, please share your contract address of token I will try reproduce it.

@Mash-Woo
Copy link

if your abi is json, use

final contract =
    DeployedContract(ContractAbi.fromJson(jsonEncode(abi), 'nameToken'), scAddress);

And try to use w3mService.session!.chainId instead of w3mService.selectedChain!.chainId

if these steps don't help you, please share your contract address of token I will try reproduce it.

Somehow my package only can use w3mService.selectedChain!.chainId or maybe I will set a String such as '42161' the chain id of Arbitrum

@Rudo-dyn
Copy link

Rudo-dyn commented Jan 23, 2024

if your abi is json, use

final contract =
    DeployedContract(ContractAbi.fromJson(jsonEncode(abi), 'nameToken'), scAddress);

And try to use w3mService.session!.chainId instead of w3mService.selectedChain!.chainId
if these steps don't help you, please share your contract address of token I will try reproduce it.

Somehow my package only can use w3mService.selectedChain!.chainId or maybe I will set a String such as '42161' the chain id of Arbitrum

Where is your ethClient init? And can you share rpcUrl that you use?

@Mash-Woo
Copy link

if your abi is json, use

final contract =
    DeployedContract(ContractAbi.fromJson(jsonEncode(abi), 'nameToken'), scAddress);

And try to use w3mService.session!.chainId instead of w3mService.selectedChain!.chainId
if these steps don't help you, please share your contract address of token I will try reproduce it.

Somehow my package only can use w3mService.selectedChain!.chainId or maybe I will set a String such as '42161' the chain id of Arbitrum

Where is your ethClient init? And can you share rpcUrl that you use?

I put it in main, my rpcUrl, I am facing this Error

Exception has occurred.
_$WalletConnectErrorImpl (WalletConnectError(code: 5100, message: Unsupported chains. The chain eip155:42161 is not supported, data: null))

@quetool quetool pinned this issue Jan 24, 2024
@quetool quetool unpinned this issue Jan 24, 2024
@Rudo-dyn
Copy link

if your abi is json, use

final contract =
    DeployedContract(ContractAbi.fromJson(jsonEncode(abi), 'nameToken'), scAddress);

And try to use w3mService.session!.chainId instead of w3mService.selectedChain!.chainId
if these steps don't help you, please share your contract address of token I will try reproduce it.

Somehow my package only can use w3mService.selectedChain!.chainId or maybe I will set a String such as '42161' the chain id of Arbitrum

Where is your ethClient init? And can you share rpcUrl that you use?

I put it in main, my rpcUrl, I am facing this Error

Exception has occurred. _$WalletConnectErrorImpl (WalletConnectError(code: 5100, message: Unsupported chains. The chain eip155:42161 is not supported, data: null))

Your chain id is 42161, use it instead of eip155:42161

@Mash-Woo
Copy link

if your abi is json, use

final contract =
    DeployedContract(ContractAbi.fromJson(jsonEncode(abi), 'nameToken'), scAddress);

And try to use w3mService.session!.chainId instead of w3mService.selectedChain!.chainId
if these steps don't help you, please share your contract address of token I will try reproduce it.

Somehow my package only can use w3mService.selectedChain!.chainId or maybe I will set a String such as '42161' the chain id of Arbitrum

Where is your ethClient init? And can you share rpcUrl that you use?

I put it in main, my rpcUrl, I am facing this Error
Exception has occurred. _$WalletConnectErrorImpl (WalletConnectError(code: 5100, message: Unsupported chains. The chain eip155:42161 is not supported, data: null))

Your chain id is 42161, use it instead of eip155:42161

I changed but still facing this problem

@quetool
Copy link
Collaborator

quetool commented Jan 24, 2024

@Mash-Woo could you share the contract address and your code where you send the transaction?

@Mash-Woo
Copy link

Mash-Woo commented Jan 24, 2024

@Mash-Woo could you share the contract address and your code where you send the transaction?

This is my set-up config

void initializedW3MService() async {
  W3MChainPresets.chains.putIfAbsent(
    'eip155:${dotenv.get('CHAIN_ID')}',
    () => W3MChainInfo(
      chainName: 'Arbitrum Sepolia Testnet',
      chainId: dotenv.get('CHAIN_ID'),
      namespace: 'eip155:${dotenv.get('CHAIN_ID')}',
      tokenName: 'ETH',
      rpcUrl: 'https://sepolia-rollup.arbitrum.io/rpc',
      blockExplorer: W3MBlockExplorer(
        name: 'Arbitrum Sepolia Testnet',
        url: 'https://sepolia.arbiscan.io/',
      ),
    ),
  );
  await w3mService.init();
  w3mService.notifyListeners();
}

I just want to add this config and use it, it can work on metamask but not on trust wallet

@Mash-Woo
Copy link

In Metamask, I am facing this #176

@quetool
Copy link
Collaborator

quetool commented Jan 24, 2024

I meant a whole reproducible code, including contract Abi, contract address, and everything that could be useful to test. it's pretty difficult otherwise.

@quetool
Copy link
Collaborator

quetool commented Jan 24, 2024

Also, is your custom chain (Arbitrum Sepolia) added in your Wallet? If not, are you requesting wallet_addEthereumChain?

@Mash-Woo
Copy link

Also, is your custom chain (Arbitrum Sepolia) added in your Wallet? If not, are you requesting wallet_addEthereumChain?

I added it to my wallet

@Mash-Woo
Copy link

I meant a whole reproducible code, including contract Abi, contract address, and everything that could be useful to test. it's pretty difficult otherwise.

Hmm, actually I completed solving this, and now my bug is Exception has occurred. _$WalletConnectErrorImpl (WalletConnectError(code: 5100, message: Unsupported chains. The chain eip155:421614 is not supported, data: null))

It cause when I work with Trust Wallet, except for Metamask

@quetool
Copy link
Collaborator

quetool commented Jan 25, 2024

It means Trust wallet does not support that chain. Try a different wallet or a different chain on Trust.

@Mash-Woo
Copy link

It means Trust wallet does not support that chain. Try a different wallet or a different chain on Trust.

Thank you, I changed to another network and it worked, but sometime, if user rejected transaction, I will meet this problem Exception has occurred.
_$JsonRpcErrorImpl (JsonRpcError(code: 5001, message: User disapproved requested methods))

@quetool
Copy link
Collaborator

quetool commented Jan 25, 2024

Indeed that means the user rejected the request

@Mash-Woo
Copy link

Indeed that means the user rejected the request

Would you happen to have any solution, such as if the user rejects the request, it will redirect to my app?

@quetool
Copy link
Collaborator

quetool commented Jan 26, 2024

It's up to the wallet to redirect to your dapp. You can't do anything from your dapp to get back to your dapp from the wallet.
All you can do is to catch the error and do whatever you need to do.

In any case I just realized you are implementing Web3Modal and this is WalletConnectFlutterV2 repo so please if you have any other issue open a new one in the proper repository. Thanks!

@quetool
Copy link
Collaborator

quetool commented Feb 1, 2024

Hello all! Glad to announce that a new beta is out for WalletConnectFlutterV2 with Smart Contract interaction based on the proposed solution from @bobwith2bees. Thank you Bob! And thank you @Rudo-dyn for bringing this to my attention!

For any issue with this beta please follow up on this new thread

In the PR description you will find how to interact with the new functionality, hopefully it's easy enough.

For the time being, if you are willing to try this with Web3Modal (such as your case @Mash-Woo), you'll need to override walletconnect_flutter_v2 dependency as follows:

dependency_overrides:
  walletconnect_flutter_v2: ^2.2.0-beta01

And then make your requests leveraging web3app instance of w3mService

return w3mService.web3App!.requestWriteContract(.....)
// OR
return w3mService.web3App!.requestReadContract(.....)

Bear in mind that this is a beta release and things might slightly change in the near future.
Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants