LtbLightning / bdk-flutter

Bitcoin Development Kit - Flutter Package
MIT License
60 stars 27 forks source link

createWallet overrides previous wallet data even if called in a new BdkFlutter instance #19

Open MrUnfunny opened 1 year ago

MrUnfunny commented 1 year ago

Hey @BitcoinZavior,

If we create multiple instances of BdkFlutter for creating multiple wallets, each createWallet call will override the last wallet even in another BdkFlutter instance.

  var  wallet1 = BdkFlutter();
  var wallet2 = BdkFlutter();
  var wallet3 = BdkFlutter();

  wallet1.createWallet(...);
  wallet2.createWallet(...);
  wallet3.createWallet(...);

After this, we should have three different wallets in wallet1, wallet2, and wallet3. But if I call any method like getBalance, getNewAddress etc, it will return data for wallet3 only. This means that wallet1 and wallet2 have been overwritten despite them being different object than wallet3.

I've created a sample repo for this. Please update bdk-flutter path in pubspec.yaml to run the app.

aniketambore commented 1 year ago

If you want to create multiple wallet instances, you can do something like this:

=> wallet.dart

import 'package:bdk_flutter/bdk_flutter.dart';

class Wallet {
  List<BdkFlutter> wallets = [
    BdkFlutter(),
    BdkFlutter(),
    BdkFlutter(),
  ];

  Future<String> mnemonic() async {
    final response = await generateMnemonic();
    return response;
  }

  Future<void> create(BdkFlutter bdkInstance, String mnemonic) async {
    final wallet = await bdkInstance.createWallet(mnemonic: mnemonic);
  }
}

Inside of your UI infrastructure you can use it as:

  // Create an instance of your wallet
  final wallet = Wallet();

  Future<void> createWallet() async {
    for (int i = 0; i < wallet.wallets.length; i++) {
      final bdk = wallet.wallets[i];
      final mnemonic = await wallet.mnemonic();
      await wallet.create(bdk, mnemonic);
      print('[+] Mnemonic: $mnemonic');
      print('[+] Wallet $i created');
    }
  }

  Future<void> getWallet(int i) async {
    final wallets = wallet.wallets;
    final address = await wallets[i].getNewAddress();
    print('Wallet $i address is $address');
  }

Calling the above method as:

Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            ElevatedButton(
              onPressed: () => createWallet(),
              child: const Text("Create Wallet"),
            ),
            ElevatedButton(
              onPressed: () => getWallet(0),
              child: const Text("First Wallet"),
            ),
            ElevatedButton(
              onPressed: () => getWallet(1),
              child: const Text("Second Wallet"),
            ),
            ElevatedButton(
              onPressed: () => getWallet(2),
              child: const Text("Third Wallet"),
            ),
          ],
        ),

=> OUTPUT:

I/flutter ( 5811): [+] Mnemonic: isolate consider oak **** **** **** **** **** **** **** fetch envelope
I/flutter ( 5811): [+] Wallet 0 created
I/flutter ( 5811): [+] Mnemonic: fever zebra clock **** **** **** **** **** **** **** doctor zoo
I/flutter ( 5811): [+] Wallet 1 created
I/flutter ( 5811): [+] Mnemonic: crystal blind punch **** **** **** **** **** **** **** wife simple
I/flutter ( 5811): [+] Wallet 2 created
I/flutter ( 5811): Wallet 0 address is tb1q4wrsxlj5knv************wryksy8x7ujda36
I/flutter ( 5811): Wallet 1 address is tb1qgmdpk6gv********************vhv93l2n28g
I/flutter ( 5811): Wallet 2 address is tb1qtd3v4q8vkjj************tcf7jwffr77uv2

I hope this is what you're trying to achieve.

MrUnfunny commented 1 year ago

Hey @aniketambore, Here different addresses are returned because getNewAddress will generate different addresses even for the same wallet.

If you try any API which returns fixed data for a specific wallet, you will understand this issue. Can you try the same with getPublicDescriptor API? For different wallets, it should return different descriptors for each wallet, but I guess it will return the same descriptor(the one belonging to wallet 2) for all three wallets.

Please note that after I opened this issue, some changes were pushed to this repository. So, it might be possible that this issue has been resolved. I'm unable to test this right now but will get back after I get the chance to test it again.

aniketambore commented 1 year ago

Got it 👍

What I think is even if we create separate instances of BdkFlutter(), still it holds the same object - not a new instance. I tried cloning the object, but it still points to the same instance.

MrUnfunny commented 1 year ago

Yes, that is the issue. It is essentially acting as a singleton pointing to the latest instance only.

BitcoinZavior commented 1 year ago

We should have a PR for this in a week's time, allowing for multiple unique wallet instances.

aniketambore commented 1 year ago

Hello, I just wanted to share an update on this issue #19, I recently revisited this issue and conducted some tests with the current implementation of the bdk_flutter plugin. It appears that we are now able to generate multiple wallets successfully. To demonstrate this, I created an example (https://github.com/aniketambore/bdk-flutter/blob/multiple-wallets/example/lib/main.dart) where I generated three different wallet instances. I then sent some tBTC to each of these wallets and retrieved the balance for each one. The functionality seems to be working fine with the current plugin implementation. I believe it's safe to close this issue.