-
Notifications
You must be signed in to change notification settings - Fork 5
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
fix: import all accounts for wallet #605
base: dev
Are you sure you want to change the base?
Conversation
a1c4667
to
422c9c8
Compare
apps/mobile/package.json
Outdated
@@ -61,14 +61,15 @@ | |||
"@rnx-kit/metro-config": "1.3.14", | |||
"@rnx-kit/metro-resolver-symlinks": "0.1.35", | |||
"@scure/bip32": "1.5.0", | |||
"@scure/bip39": "1.4.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added this for mnemonicToSeedSync
in mnemonicToRootNode
but maybe we have a different way on mobile?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
both of these methods exist in @leather.io/crypto
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## dev #605 +/- ##
==========================================
+ Coverage 24.07% 24.65% +0.57%
==========================================
Files 164 165 +1
Lines 6085 6133 +48
Branches 333 346 +13
==========================================
+ Hits 1465 1512 +47
- Misses 4620 4621 +1
|
3f10840
to
3004452
Compare
apps/mobile/src/store/key-store.ts
Outdated
console.info('Found account activity at higher index', { recursiveActivityIndex }); | ||
// dispatch(stxChainSlice.actions.restoreAccountIndex(recursiveActivityIndex)); | ||
console.log('recursiveActivityIndex', recursiveActivityIndex); | ||
this.createNewAccountOfWallet(fingerprint, recursiveActivityIndex); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the extension stx-chain.slice.ts
for stxChainSlice.actions.restoreAccountIndex(recursiveActivityIndex)
it is using highestAccountIndex
which gets incremented in createNewAccount
so maybe that's where I am going wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There should not be side effects in this callback.
The idea of this recursive look up is that we give it a callback to determine whether there's activity or not. Then, the return value (which isn't used here because of void recurseAccountsForActivity
) tells you the highest account index that has activity.
Later, you use that index to know how many accounts should be created.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see here you're try to recurse as well, but that isn't needed because all the recursion is handled internally to this function, it's way easier that way
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I based this code on the extension code commented out above it. That was using dispatch(stxChainSlice.actions.restoreAccountIndex(recursiveActivityIndex))
to restore accounts.
I could be mistaken, but when I debug this, it seems like in .then
the recursiveActivityIndex
is always 0
so this code is never reached (on extension or copied version). See extension draft .
I think accounts are actually created further on by:
if (legacyAccountActivityLookup !== 0)
// dispatch(stxChainSlice.actions.restoreAccountIndex(legacyAccountActivityLookup)); -> extension
this.createNewAccountOfWallet(fingerprint, legacyAccountActivityLookup);
legacyAccountActivityLookup
is determined by checkForLegacyGaiaConfigWithKnownGeneratedAccountIndex
which I think is actually what is determining how many accounts to create.
What I think I can get to work is to run this.createNewAccountOfWallet
inside of the recursive function if there is a balance
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does it always return 0? Does the account have activity you're testing with? It's quite slow, so are you waiting until the end?
What I think I can get to work is to run this.createNewAccountOfWallet inside of the recursive function if there is a balance
I really don't think this is the way to do it. The purpose of recurseAccountsForActivity
is to handle the recursion of the look up. If you have to do additional recursion outside that fn, then either your implementation misses the point of the function, or the implementation of recurseAccountsForActivity
doesn't work and needs fixing. It's been a while since I wrote this, and can likely be improved, it's v slow for example.
Happy to run through in more detail the gist of this function, but really its just a look up function that stops after n false values and returns a number.
Also, let's remove all the gaia stuff so we don't need to worry about legacy account look up code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks Kyran. I will do more testing and then implement the best solution using your recommendations.
I'm not sure if it's working as we think in the extension right now. I am testing with my personal wallet and the leather dev wallet and in both cases accounts are created only if if (legacyAccountActivityLookup !== 0)
.
We have two calls to add accounts:
-
in
recurseAccountsForActivity.then
dispatch(stxChainSlice.actions.restoreAccountIndex(recursiveActivityIndex));
-
after a check for
if (legacyAccountActivityLookup !== 0)
:
dispatch(stxChainSlice.actions.restoreAccountIndex(legacyAccountActivityLookup));
-
If I remove the
dispatch
after thelegacyAccountActivityLookup
check, no accounts are created apart from the first one. -
If I add a debugger in
recurseAccountsForActivity.then
it never gets hit.
Here's the full code.
try {
void recurseAccountsForActivity({
async doesAddressHaveActivityFn(index) {
....
return hasStxBalance || hasNames || hasBtcBalance;
},
}).then(recursiveActivityIndex => {
if (recursiveActivityIndex <= legacyAccountActivityLookup) return;
logger.info('Found account activity at higher index', { recursiveActivityIndex });
dispatch(stxChainSlice.actions.restoreAccountIndex(recursiveActivityIndex));
});
} catch (e) {
// Errors during account restore are non-critical and can fail silently
}
....
if (legacyAccountActivityLookup !== 0)
dispatch(stxChainSlice.actions.restoreAccountIndex(legacyAccountActivityLookup));
};
If I change this code to be:
const accountsWithBalances = recurseAccountsForActivity({
async doesAddressHaveActivityFn(index) {
....
return hasStxBalance || hasNames || hasBtcBalance;
},
})
accountsWithBalances
is always 0
. If I add logs inside of there I can see it finding accounts with balances but I think it's not working as we expect.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Upon further investigation into this, it seems like the recursion we are using does not generate any accounts. They are in fact all generated initially based on the count returned from checkForLegacyGaiaConfigWithKnownGeneratedAccountIndex
Here is a demo PR from the extension showing that: leather-io/extension#5945
apps/mobile/package.json
Outdated
@@ -61,14 +61,15 @@ | |||
"@rnx-kit/metro-config": "1.3.14", | |||
"@rnx-kit/metro-resolver-symlinks": "0.1.35", | |||
"@scure/bip32": "1.5.0", | |||
"@scure/bip39": "1.4.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
both of these methods exist in @leather.io/crypto
apps/mobile/package.json
Outdated
@@ -142,7 +143,7 @@ | |||
"babel-plugin-macros": "3.1.0", | |||
"babel-preset-expo": "11.0.6", | |||
"concurrently": "8.2.2", | |||
"eslint": "8.53.0", | |||
"eslint": "9.14.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unintended I imagine
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I saw some warnings about it being out of date so updated it. I should have removed from here
@@ -0,0 +1,79 @@ | |||
// from extension src/app/common/account-restoration/account-restore.ts |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this shouldn't be added directly to mobile, instead though of as a distinct module that I think should like in /crypto
pkg, the refactored out to extension
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will do this once I can get it to work properly
apps/mobile/src/store/key-store.ts
Outdated
const legacyAccountActivityLookup = | ||
legacyAccountActivityLookupGaia === 0 ? 123 : legacyAccountActivityLookupGaia; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggest we don't add any of the gaia checks here, resolving the import issue, check stacks/bitcoin balances only
apps/mobile/src/store/key-store.ts
Outdated
console.info('Found account activity at higher index', { recursiveActivityIndex }); | ||
// dispatch(stxChainSlice.actions.restoreAccountIndex(recursiveActivityIndex)); | ||
console.log('recursiveActivityIndex', recursiveActivityIndex); | ||
this.createNewAccountOfWallet(fingerprint, recursiveActivityIndex); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There should not be side effects in this callback.
The idea of this recursive look up is that we give it a callback to determine whether there's activity or not. Then, the return value (which isn't used here because of void recurseAccountsForActivity
) tells you the highest account index that has activity.
Later, you use that index to know how many accounts should be created.
pseudo code we need here // user restores mnemonic
const mnemonic = 'abandon …';
async function doesStacksAddressHaveBalance (index) {
// derive address
// look up api for balances, return true if found
}
async function doesNativeSegwitAddressHaveBalance (index) {
// derive address
// look up api for balances, return true if found
}
const highestAccountIndex = await recurseAccountsForActivity({
async doesAddressHaveActivityFn(index) {
const hasStacksBal = await doesStacksAddressHaveBalance(index);
const hasNsBal = await doesNativeSegwitAddressHaveBalance(index)
// this tells the inner lookup function to keep looking, or not
// using callbacks like this means that the inner fn isn't aware of any specific chain related
// details, all it is told is whether it needs to keep looking or not
return hasStacksBal ?? hasNsBal;
}
})
// now we know that `highestAccountIndex` is the account with the farthest known balance
const newAccountsToAdd = createNullArrayOf(highestAccountIndex).map(index => {
return generateTheAccountOfThisIndex();
})
// redux store method to add all of these to the store
// should be single action with many, not many actions with a single item
dispatch(etc) This look up can take some time though, so ideally we want some way of handling this in the background. I would first get the slow version implemented before tackling that though. |
apps/mobile/src/store/key-store.ts
Outdated
} | ||
|
||
// on the extension dev wallet this is where most accounts are created | ||
if (legacyAccountActivityLookup !== 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I try restore one of my personal wallets on the extension
the accounts also get generated here.
That account is from 2023 at the earliest so I don't think it should be considered legacy?
Thanks! |
c4bf59e
to
ea86391
Compare
ea86391
to
06aaadf
Compare
apps/mobile/src/store/key-store.ts
Outdated
// not sure why this is needed? | ||
// don't think I need to pass in the same keychain for each account |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the keychain is different for every account
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @kyranjamie 👍
I realised I have more work to do as I was hitting issues in bitcoin-keychains.read.ts
with undefined nativeSegwit taproot
.
@@ -32,6 +32,12 @@ export const bitcoinKeychainSlice = createSlice({ | |||
handleEntityActionWith(adapter.addMany, payload => payload.withKeychains.bitcoin) | |||
) | |||
|
|||
// NOTE: need to adapt this to add multiple accounts |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Curious about this comment. This adapter already uses addMany
, not addOne
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a new action userAddsAccounts
to add many accounts at once so I think I need to adapt this to also handle their keychains as that's not working fully and the accounts seem incomplete.
I am hitting issues with undefined keyOrigin
so I think I missed some things during account creation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Solved this. I'm passing an array of account creation data so needed a flatMap
here
289c689
to
401a641
Compare
const mostRecentAccount = await recurseUntilGeneratorDone(checkForMostRecentAccount()); | ||
const accountsToRestore = mostRecentAccount; | ||
return accountsToRestore; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
odd reassignments here
const mostRecentAccount = await recurseUntilGeneratorDone(checkForMostRecentAccount()); | |
const accountsToRestore = mostRecentAccount; | |
return accountsToRestore; | |
const accountsToRestore = await recurseUntilGeneratorDone(checkForMostRecentAccount()); | |
return accountsToRestore; |
import z from 'zod'; | ||
|
||
// FIXME fix this deprecated import | ||
import { mnemonicToRootNode } from '@leather.io/bitcoin'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is in crypto pkg
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll be removing this whole file in favour of the newer balance queries we have
da597d2
to
1932126
Compare
I wonder how we're going to manage this functionality, because in the case of lots of accounts, it's going to take ages |
I will think about this a bit more. The latest version of this is still messy but it's working at least. If I try and restore the Leather I had a call with @alexp3y about this yesterday in relation to the The flow for determining active keychains and creating accounts now is to:
I will be looking into Or if on first load when we are trying to calculate the I'll keep thinking about this. Also wondering if we should add the |
This PR contains a working draft of importing multiple accounts from a seed.
It is based on previous extension code but some more work is needed.
When importing the
dev
wallet account it takes quite a while and the resulting UI is very laggy (maybe as we have no controls in place on the max limits of the accounts)