-
Notifications
You must be signed in to change notification settings - Fork 44
Conversation
# Conflicts: # contracts/clients/package.json # extension/package.json # extension/yarn.lock
import { mcl } from "@thehubbleproject/bls"; | ||
|
||
export default (): string => { | ||
return `0x${mcl.randFr().serializeToHexStr()}`; |
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 originally put this here because we know that mcl
has been initialised inside the signer directory. However, logically I'm thinking now that I should pull this out of the signer. Curious to hear your thoughts. Right now if you want to call this you have to create a wallet wrapper first like so. You probably shouldn't have to create a wallet to get a new PK.
const wallet = await this.BlsWalletWrapper(pk);
const newPk = wallet.getRandomBlsPrivateKey();
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.
Agree creating a new wallet to get a random private key is not optimal, unsure on the best place to put this. But could it be a static method somewhere? Similar to how we have static methods for an address on BlsWalletWrapper.
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.
Yeah the more that I think about it, I'm gonna move it.
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.
Looks good!
All comments are minor/non-blocking so approving
return this.blsWalletSigner.getRandomBlsPrivateKey(); | ||
} | ||
|
||
async getBundleSetRecoveryHash( |
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.
To check my understanding, this method sets the recovery hash and then returns
10000
that bundle?
Was originally thrown off by the naming here but not convinced there's anything better.
getSetRecoveryHashBundle
/getRecoverWalletBundle
reads more like a sentence but not a fan of "get" and "set" next to each other for the first method.createSetRecoveryHashBundle
/createRecoverWalletBundle
reads better than "get" prefix to me, but prefer the "get" prefix semanticallysignSetRecoveryHashOperation
/signRecoverWalletOperation
think this reads well but using bundle instead of operation makes more sense to mesetRecoveryHash
/recoverWallet
is misleading as the method is only creating the bundle and not executing it
Happy with to go with original (or one of 4 options if you think any make more sense) as I've spent far too long thinking about this lol
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.
Yeah I spent some time thinking about this. I ended up going with what I had cause I figured getBundle{FUNCTION_NAME}
could be a good naming pattern.
I think your first one might be the most readable though so I might switch to that.
try { | ||
return ethers.utils.formatBytes32String(salt); | ||
} catch (e) { | ||
throw new Error("Error convirting salt string to bytes 32 string."); |
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.
Making an assumption here, but is this error handling to ensure we have a more helpful error message when an invalid salt is passed in?
This is more of a question than a suggestion, but if so, would it be helpful to also surface the ethers error too as part of the error message?
Also nitpick but while I'm here, noticed a tiny typo in the error message :)
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.
Yeah, this is a good shout. After thinking about it, this private method is unnecessary and we can just go with the default error
import { mcl } from "@thehubbleproject/bls"; | ||
|
||
export default (): string => { | ||
return `0x${mcl.randFr().serializeToHexStr()}`; |
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.
Agree creating a new wallet to get a random private key is not optimal, unsure on the best place to put this. But could it be a static method somewhere? Similar to how we have static methods for an address on BlsWalletWrapper.
import * as mcl from 'mcl-wasm'; | ||
import { hexlify, randomBytes } from 'ethers/lib/utils'; | ||
|
||
export default async function randFr(): Promise<mcl.Fr> { |
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.
Are there any differences between this function, and the randFr
function used in getRandomBlsPrivateKey
?
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.
No they are meant to do the same thing. That randFr function comes from the hubble library. I added this file a while back by copying the logic from the hubble project
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.
gotcha cheers
salt: string, | ||
recoverWalletAddress: string, | ||
): Promise<Bundle> { | ||
const saltBytes32String = BlsWalletWrapper.saltToBytes32String(salt); |
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.
What was the reason for changing references of this from saltHash
/recoverySaltHash
to saltBytes32String
?
Don't have a strong opinion, but wondering if saltHash
would read better than having the type in the name?
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.
No particular reason. I think in a lot of my code I called it saltBytes32String
to copy the function name and Kautuk called it saltHash in other places. I might switch to saltHash
expect(await vg.hashFromWallet(wallet4.address)).to.eql(newHash); | ||
expect(await vg.walletFromHash(newHash)).to.eql(wallet4.address); |
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.
General recovery question - my understanding of this scenario is that wallet 3 should not be able to send transactions after being recovered to wallet 4, is that correct?
If so, do you see value in a test that checks wallet 3 cannot send transactions after being recovered? That might be covered by existing assertions/not be desirable, curious on your thoughts here.
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.
So in this situation, wallet 3 is actually the trusted wallet for wallet 4. I've been using the term trusted wallet recently because I think that makes more sense then what I've been calling it. In this situation, we can assume that it was actually wallet 4 that lost it's private key and needs to recover to a new one. Wallet 3 is the trusted wallet that can call the recover wallet function to swap the PK for wallet 4.
After the recovery is done, wallet 4's old private key should no longer be able to send txs. But the new private key that now maps to wallet 4's public key should be able to send transactions for that hash. That's why here I check that the public key hash for the new private key is the same as the hash that maps to wallet 4's address. If that's the case, the new private key can send txs for that address.
With regard to the test. We already have a decent amount of recovery tests in here which is why I just wanted to add a test to check that the bundle created from the new functions works. I just looked though and it doesn't look like we have a test that explicitly checks that the old private key doesn't work anymore. So I think that would be a valuable test.
I could add an extra line to this test to check that the old private key no longer maps to any public key hash. Which would mean it can't send any txs. When a recovery happens we just zero out the hash that the private key maps to in the mapping stored in the verification gateway. So that private key can't do anything anymore.
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.
Yeah think I was confused about how this was working. I've got a good grasp now, thanks for clearing that up!
Trusted wallet as a term also makes sense. Wondering if renaming blsWallet3
to something like trustedBlsWallet
would improve readability?
Makes sense in regards to additional test case.
@@ -120,6 +127,15 @@ export default class BlsWalletWrapper { | |||
return this.ExpectedAddress(verificationGateway, pubKeyHash); | |||
} | |||
|
|||
static async getRandomBlsPrivateKey(): Promise<string> { | |||
await mcl.init(mcl.BN_SNARK1); |
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.
Hey @jacque006, I was curious to get your thoughts on this. I want the getRandomBlsPrivateKey
function to be static but I need to make sure .init
has been called on mcl. Looks like the only way we can guarantee that right now is if I put this code in the signer (I originally did that and then pulled it out because I didn't think it makes sense). Do you think it's an issue if I import the mcl library in this file?
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 would try to keep any logic like this in the signer dir, and I would use @thehubbleproject/bls
over a direct mcl-wasm
import.
You should be able to do something like this:
./contracts/clients/signers/getRandomPrivateKey.ts
import { mcl } from "@thehubbleproject/bls";
export default function getRandomPrivateKey(): Promise<string> {
await mcl.init();
return `0x${mcl.randFr().serializeToHexStr()}`;
}
Then add as an export to ./contracts/clients/signers/index.ts
and consume here.
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.
You might run into issues running mcl.init
twice. If that happens will have to try another 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.
This worked for me. Thanks, @jacque006 !
What is this PR doing?
Adding the logic used recover an instant wallet to quill to the bls client module. There's probably room to add some more recovery functionality. This is just the logic that is currently used to recover from an Instant wallet to Quill.
How can these changes be manually tested?
Added tests to the contracts tests to make sure it works. Also, you could try recovering an instant wallet.
Does this PR resolve or contribute to any issues?
#220
#442
Checklist
Guidelines
resolve conversation
button is for reviewers, not authors