Skip to content
This repository has been archived by the owner on Nov 5, 2023. It is now read-only.

Wallet recovery #342

Merged
merged 17 commits into from
Dec 15, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 95 additions & 3 deletions extension/source/background/KeyringController.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { BlsWalletWrapper } from 'bls-wallet-clients';
import { ethers } from 'ethers';
import { keccak256 } from 'ethers/lib/utils';
import {
BlsWalletWrapper,
// eslint-disable-next-line camelcase
VerificationGateway__factory,
} from 'bls-wallet-clients';
import { ethers, BigNumberish } from 'ethers';
import { solidityPack, keccak256 } from 'ethers/lib/utils';
import generateRandomHex from '../helpers/generateRandomHex';
import QuillStorageCells from '../QuillStorageCells';
import assert from '../helpers/assert';
Expand Down Expand Up @@ -154,6 +158,76 @@ export default class KeyringController {

await this.keyring.update({ wallets: newWallets });
},

/**
* Recovers an existing BLS wallet and adds the new
* recovered wallet to the keyring
* @param recoveryWalletAddress Smart contract address
* of wallet being recovered
* @param recoverySaltHash Salt used to set the recovery
* hash on the wallet that is being recovered
*/
addRecoveryWallet: async ({
params: [recoveryWalletAddress, recoverySaltHash],
}) => {
const netCfg = getNetworkConfig(
await this.network.read(),
this.multiNetworkConfig,
);

// eslint-disable-next-line camelcase
const verificationGatewayContract = VerificationGateway__factory.connect(
netCfg.addresses.verificationGateway,
await this.ethersProvider.read(),
);

const recoveryWalletHash =
await verificationGatewayContract.hashFromWallet(recoveryWalletAddress);

// Create new private key for the wallet we are recovering to.
const newPrivateKey = generateRandomHex(256);

const addressSignature = await this.signWalletAddress(
recoveryWalletAddress,
newPrivateKey,
);

// Get instance of the new wallet, so we can get the public key
// to pass to the recoverWallet method.
const newWalletWrapper = await this.BlsWalletWrapper(newPrivateKey);

const signerPublicKeyHash = await this.selectedPublicKeyHash.read();

assert(
signerPublicKeyHash !== undefined,
() => new Error('Selected public key hash not found'),
);

const tx = {
from: signerPublicKeyHash,
to: verificationGatewayContract.address,
value: '0',
data: verificationGatewayContract.interface.encodeFunctionData(
'recoverWallet',
[
addressSignature,
recoveryWalletHash,
recoverySaltHash,
newWalletWrapper.PublicKey(),
],
),
};

this.InternalRpc().eth_sendTransaction({
kautukkundan marked this conversation as resolved.
Show resolved Hide resolved
...tx,
gas: undefined,
gasPrice: undefined,
data: undefined,
});

// Add new private key
await this.InternalRpc().addAccount(newPrivateKey);
kautukkundan marked this conversation as resolved.
Show resolved Hide resolved
},
});

async BlsWalletWrapper(privateKey: string): Promise<BlsWalletWrapper> {
Expand Down Expand Up @@ -214,4 +288,22 @@ export default class KeyringController {
{},
);
}

async signWalletAddress(
senderAddress: string,
signerPrivateKey: string,
): Promise<[BigNumberish, BigNumberish]> {
const netCfg = getNetworkConfig(
await this.network.read(),
this.multiNetworkConfig,
);

const addressMessage = solidityPack(['address'], [senderAddress]);
const wallet = await BlsWalletWrapper.connect(
signerPrivateKey,
netCfg.addresses.verificationGateway,
await this.ethersProvider.read(),
);
return wallet.signMessage(addressMessage);
}
}
1 change: 1 addition & 0 deletions extension/source/background/QuillController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ export default class QuillController {
lookupPrivateKey: this.keyringController.rpc.lookupPrivateKey,
pkHashToAddress: this.keyringController.rpc.pkHashToAddress,
removeAccount: this.keyringController.rpc.removeAccount,
addRecoveryWallet: this.keyringController.rpc.addRecoveryWallet,

// TransactionsController
createTransaction: this.transactionsController.rpc.createTransaction,
Expand Down
5 changes: 5 additions & 0 deletions extension/source/types/Rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,11 @@ export const rpcMap = {
Params: io.tuple([io.string]),
Response: io.void,
},
addRecoveryWallet: {
origin: '<quill>',
Params: io.tuple([io.string, io.string]),
Response: io.void,
},

// TransactionController

Expand Down