-
Notifications
You must be signed in to change notification settings - Fork 47
Conversation
* added UI for entering recovery hash * added ui for salt * completed workflow for wallet recovery * lint: fix * updated hex conversion of salt * using temp wallet for recovery * replace address after recovery
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.
Tested locally and works well. Was able to recover a wallet successfully from the instant wallet into Quill.
I'm not too confident reviewing the changes in the KeyringController.ts
as it's quite a lot of new stuff for me, so would be good to get a second opinion on that specific file :)
const RecoverWalletModal = () => { | ||
const [modalIsOpen, setIsOpen] = useState(false); | ||
const [pageIndex, setPageIndex] = useState(0); | ||
const [walletPrivateKey, setWalletPrivateKey] = useState<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.
Do we need to explicitly add the type here? Can see that we're letting typescript infer the type for the above useState's
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.
My personal preference is to have explicit typing everywhere. Copied the above 2 lines from somewhere else in the codebase so missed adding type to 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.
I may lean towards letting typescript infer the type but don't have a strong opinion either way, so happy with either option as long as we're being consistent :)
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.
@kautukkundan Are you sure that's your preference in this case where TypeScript is correctly inferring the type? Would you also add <boolean>
and <number>
to the previous lines?
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.
@voltrevo Fine with me as is in this particular case.
The problem starts happening when using complex types. eg - let's say a new Address
type is defined as a string that always starts with "0x". In this case initializing with default '' would also work as it'll infer type string, but may break code later when things get complex. This had been the case earlier when using sol.G1 and sol.G2 types in the HubbleBLS library.
So looking at broader picture and anticipating future I prefer being explicit even with simpler types to maintain consistency, If that makes sense.
<br /> | ||
<div className="text-[10pt] text-grey-700 leading-loose font-bold mt-2"> | ||
Do not close this modal until you have completed all the steps that | ||
follows else you will lose access to your original keys! |
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.
Thoughts on:
"...steps that follow, else you..."
}> = ({ onComplete, walletPrivateKey }) => { | ||
const { rpc } = useQuill(); | ||
|
||
const [salt, setSalt] = useState<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.
Similar point here and line below, do we want to explicitly state the type?
</div> | ||
<div className="mt-4 bg-grey-900 bg-opacity-25 rounded-md p-5"> | ||
{loading ? ( | ||
<div className="flex gap-4 text-[12pt] items-center "> |
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.
Tiny bit of whitespace :)
* of wallet being recovered | ||
* @param recoverySaltHash Salt used to set the recovery | ||
* hash on the wallet that is being recovered | ||
* @param signerWalletPrivateKey the private key of the wallet that is used |
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.
Nitpicky but just asking for consistency's sake, should the word "the" after signerWalletPrivateKey
be capitalised here? Or should the capitalised words after the param names above this be uncapitalised?
const addressSignature = await this.signWalletAddress( | ||
recoveryWalletAddress, | ||
newPrivateKey, | ||
); |
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.
Might not be fully understanding here, my two questions are:
-
Is this creating a signature using a randomly generated private key and an already generated contract address?
-
If so, how is this linking an already created address to a randomly generated private key? My knowledge of ECDSA cryptography is that the address must be derived from the public key, which is derived from the private key. But I admit my knowledge may be lacking here as these are smart contract wallets and we're not using ECDSA? And I don't fully understand how they are instantiated.
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.
@JohnGuilding good question
-
Yeah it is. It's the smart contract address of the 'instant wallet'. So the wallet we are recovering. Signed by the newly generated private key that will become the new private key for the address we are recovering.
-
I may not be the best at explaining this but this is my understanding. This signature is basically how the trusted wallet (the one that was set in the recovery hash) says that this private key now has permission to act on behalf of the instant wallet address. When the recovery happens this private key will create a new public key but instead of deterministically generating an address the public key will map to the existing instant wallet address. This signature is a way of verifying and setting this PK as the PK to the old address without revealing the private key.
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 for the answer, have a better understanding now. Will make sure to re-read your recovery article too
@@ -110,6 +115,19 @@ export default class KeyringController { | |||
return networkData.address; | |||
}, | |||
|
|||
createTempAccount: async (_request) => { |
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.
Same question for addRecoveryWallet()
, do we need to add unit tests for this new logic? I'm assuming as this is the extension which isn't meant to be production code, we are happy with not adding tests?
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.
@JohnGuilding We generally don't have tests for the extension as they would be complicated to setup & manage. However, as extension gets more stable might make sense to add some e2e tests for more common paths. Would save us some regression testing as well.
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.
It might also be beneficial to move some of the functionality into the clients lib so that other wallets/dApps can take advantage of this functionality, similar to #220 . But I would be okay if that's follow up work.
}; | ||
|
||
createWallet(); | ||
// eslint-disable-next-line react-hooks/exhaustive-deps |
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 are deps disabled here? Should just be rpc
.
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 sometimes don't understand these deps. Like it's not possible to change some deps without explicit reload which is gonna rerender anyway.
But yeah, let's add rpc 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.
Useful comment on this issue with links for further reading from Dan Abramov
facebook/create-react-app#6880 (comment)
) : ( | ||
<div className="flex justify-between"> | ||
<div className="font-mono text-[11pt]">{walletAddress}</div> | ||
{/* eslint-disable-next-line */} |
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 rule was disabled here? Better to disable a specific rule than all linting rules.
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.
it wanted to also have a "keyboard input" for the copy button which didn't make much sense to me.
@@ -110,6 +115,19 @@ export default class KeyringController { | |||
return networkData.address; | |||
}, | |||
|
|||
createTempAccount: async (_request) => { |
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.
@JohnGuilding We generally don't have tests for the extension as they would be complicated to setup & manage. However, as extension gets more stable might make sense to add some e2e tests for more common paths. Would save us some regression testing as well.
@@ -110,6 +115,19 @@ export default class KeyringController { | |||
return networkData.address; | |||
}, | |||
|
|||
createTempAccount: async (_request) => { | |||
const pKey = generateRandomHex(256); |
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.
Use a BN254
spaced key instead of just a random hex. See https://github.com/thehubbleproject/hubble-bls/blob/master/src/mcl.ts#L186 . We should expose that via the signer in the client library somewhere.
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.
@jacque006 Ahh interesting we do generateRandomHex
a couple of other places in the keyring controller which is where I copied this from. Should I also switch those?
Also, just curious, what is the benefit of BN254
over a random hex?
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.
Just want to double check that this is the right way to call that function?
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.
yeah makes sense
what is the benefit of BN254 over a random hex?
If I understand correctly, The random number generated might sometimes lie outside the range of the BN curve we are using. This function ensures it's in range.
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.
@kautukkundan correct. If the key is out of range, we just hash it into a key that is in range. I have a bucklist item/change that will be more explicit about this in the future thehubbleproject/hubble-bls#30
const netCfg = getNetworkConfig(network, this.multiNetworkConfig); | ||
|
||
// Create new private key for the wallet we are recovering to. | ||
const newPrivateKey = generateRandomHex(256); |
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.
See above comment on BLS private key gen.
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.
LGTM 🚀
Merging is blocked by #367
What is this PR doing?
Video demo of recovery
https://www.loom.com/share/34e84b23cd8647058dc92afc43a9ed28
How can these changes be manually tested?
[email protected]
Does this PR resolve or contribute to any issues?
#281
Checklist
Guidelines
resolve conversation
button is for reviewers, not authors