Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
18 changes: 18 additions & 0 deletions _raw/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -919,6 +919,24 @@
"QR__code": {
"message": "QR code"
},
"Get__Signature": {
"message": "Get Signature"
},
"KesytoneMismatchedSignId": {
"message": "Incongruent transaction data. Please check the transaction details."
},
"KeystoneSignRequestSubtitle": {
"message": "Scan the QR code on the Keystone hardware wallet"
},
"unknownQrCode": {
"message": "Error: We couldn't identify that QR code"
},
"KeystoneUnknownWalletQRCode": {
"message": "Invalid QR code. Please scan the sync QR code of the hardware wallet."
},
"KeystoneSignRequestDescription": {
"message": "After you’ve signed with your wallet, click on 'Get Signature' to receive the signature"
},
"URL": {
"message": "URL"
},
Expand Down
18 changes: 18 additions & 0 deletions _raw/_locales/zh_CN/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -915,6 +915,24 @@
"QR__code": {
"message": "二维码"
},
"Get__Signature": {
"message": "获取签名"
},
"KesytoneMismatchedSignId": {
"message": "扫描的签名二维码不属于当前交易,请检查交易详情后重试。"
},
"KeystoneSignRequestSubtitle": {
"message": "用硬件钱包扫描二维码"
},
"unknownQrCode": {
"message": "错误:无法识别该二维码"
},
"KeystoneUnknownWalletQRCode": {
"message": "请扫描硬件钱包的同步二维码。"
},
"KeystoneSignRequestDescription": {
"message": "硬件钱包扫描上方二维码完成签名后,点击“获取签名”按钮扫描已签名的二维码"
},
"URL": {
"message": "链接"
},
Expand Down
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
"@rabby-wallet/eth-simple-keyring": "^4.2.1",
"@rabby-wallet/eth-trezor-keyring": "^1.0.12",
"@rabby-wallet/eth-walletconnect-keyring": "^1.1.0",
"@keystonehq/metamask-airgapped-keyring": "^0.2.5-alpha.0",
"@zxing/browser": "^0.0.10",
"@ngraveio/bc-ur": "^1.1.6",
"uuid": "^8.3.2",
"@rabby-wallet/eth-watch-keyring": "^1.0.0",
"@rabby-wallet/gnosis-sdk": "^1.2.0",
"@rabby-wallet/widgets": "^1.0.8",
Expand Down
74 changes: 69 additions & 5 deletions src/background/controller/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,7 @@ import { ContactBookItem } from '../service/contactBook';
import { openIndexPage } from 'background/webapi/tab';
import { CacheState } from 'background/service/pageStateCache';
import i18n from 'background/service/i18n';
import keyring, {
KEYRING_CLASS,
DisplayedKeryring,
} from 'background/service/keyring';
import { KEYRING_CLASS, DisplayedKeryring } from 'background/service/keyring';
import providerController from './provider/controller';
import BaseController from './base';
import {
Expand Down Expand Up @@ -54,6 +51,10 @@ import GnosisKeyring, {
TransactionBuiltEvent,
TransactionConfirmedEvent,
} from '../service/keyring/eth-gnosis-keyring';
import KeystoneKeyring, {
AcquireMemeStoreData,
MemStoreDataReady,
} from '../service/keyring/eth-keystone-keyring';

const stashKeyrings: Record<string, any> = {};

Expand Down Expand Up @@ -973,6 +974,69 @@ export class WalletController extends BaseController {
return stashKeyringId;
};

acquireKeystoneMemStoreData = async () => {
const keyringType = KEYRING_CLASS.QRCODE;
const keyring: KeystoneKeyring = this._getKeyringByType(keyringType);
if (keyring) {
keyring.getInteraction().on(MemStoreDataReady, (request) => {
eventBus.emit(EVENTS.broadcastToUI, {
method: EVENTS.QRHARDWARE.ACQUIRE_MEMSTORE_SUCCEED,
params: {
request,
},
});
});
keyring.getInteraction().emit(AcquireMemeStoreData);
}
};

submitQRHardwareCryptoHDKey = async (cbor: string) => {
let keyring;
let stashKeyringId: number | null = null;
const keyringType = KEYRING_CLASS.QRCODE;
try {
keyring = this._getKeyringByType(keyringType);
} catch {
const keystoneKeyring = keyringService.getKeyringClassForType(
keyringType
);
keyring = new keystoneKeyring();
stashKeyringId = Object.values(stashKeyrings).length;
stashKeyrings[stashKeyringId] = keyring;
}
keyring.readKeyring();
await keyring.submitCryptoHDKey(cbor);
return stashKeyringId;
};

submitQRHardwareCryptoAccount = async (cbor: string) => {
let keyring;
let stashKeyringId: number | null = null;
const keyringType = KEYRING_CLASS.QRCODE;
try {
keyring = this._getKeyringByType(keyringType);
} catch {
const keystoneKeyring = keyringService.getKeyringClassForType(
keyringType
);
keyring = new keystoneKeyring();
stashKeyringId = Object.values(stashKeyrings).length;
stashKeyrings[stashKeyringId] = keyring;
}
keyring.readKeyring();
await keyring.submitCryptoAccount(cbor);
return stashKeyringId;
};

submitQRHardwareSignature = async (requestId: string, cbor: string) => {
const account = await preferenceService.getCurrentAccount();
const keyring = await keyringService.getKeyringForAccount(
account!.address,
KEYRING_CLASS.QRCODE
);
return await keyring.submitSignature(requestId, cbor);
};

signPersonalMessage = async (
type: string,
from: string,
Expand Down Expand Up @@ -1004,7 +1068,7 @@ export class WalletController extends BaseController {
options?: any
) => {
const keyring = await keyringService.getKeyringForAccount(from, type);
return keyringService.signTransaction(keyring, data, options);
return keyringService.signTransaction(keyring, data, from, options);
};

requestKeyring = (type, methodName, keyringId: number | null, ...params) => {
Expand Down
64 changes: 64 additions & 0 deletions src/background/service/keyring/eth-keystone-keyring.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { MetaMaskKeyring } from '@keystonehq/metamask-airgapped-keyring';
import { toChecksumAddress } from 'ethereumjs-util';
import { Transaction as LegacyTransaction } from 'ethereumjs-tx';
import { Transaction } from '@ethereumjs/tx';

const pathBase = 'm';

export const AcquireMemeStoreData = 'AcquireMemeStoreData';
export const MemStoreDataReady = 'MemStoreDataReady';

export type RequestSignPayload = {
requestId: string;
payload: {
type: string;
cbor: string;
};
};

export default class KeystoneKeyring extends MetaMaskKeyring {
perPage = 10;
memStoreData: RequestSignPayload | undefined;
constructor() {
super();
this.getMemStore().subscribe((data) => {
const request = data.sign?.request;
this.getInteraction().once(AcquireMemeStoreData, () => {
if (request) {
this.getInteraction().emit(MemStoreDataReady, request);
}
});
});
}

async getAddresses(start: number, end: number) {
if (!this.initialized) {
await this.readKeyring();
}
const accounts: {
address: string;
balance: number | null;
index: number;
}[] = [];
for (let i = start; i < end; i++) {
const address = await this.__addressFromIndex(pathBase, i);
accounts.push({
address,
balance: null,
index: i,
});
this.indexes[toChecksumAddress(address)] = i;
}
return accounts;
}

async signTransaction(address: string, tx: any): Promise<any> {
let ethTx = tx;
if (tx.type === undefined) {
ethTx = Transaction.fromSerializedTx(
(tx as LegacyTransaction).serialize()
);
}
return super.signTransaction(address, ethTx);
}
}
3 changes: 3 additions & 0 deletions src/background/service/keyring/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import TrezorKeyring from '@rabby-wallet/eth-trezor-keyring';
import OnekeyKeyring from './eth-onekey-keyring';
import LatticeKeyring from '@rabby-wallet/eth-lattice-keyring';
import WatchKeyring from '@rabby-wallet/eth-watch-keyring';
import KeystoneKeyring from './eth-keystone-keyring';
import WalletConnectKeyring from '@rabby-wallet/eth-walletconnect-keyring';
import GnosisKeyring, {
TransactionBuiltEvent,
Expand All @@ -42,6 +43,7 @@ export const KEYRING_SDK_TYPES = {
WalletConnectKeyring,
GnosisKeyring,
LatticeKeyring,
KeystoneKeyring,
};

export const KEYRING_CLASS = {
Expand All @@ -57,6 +59,7 @@ export const KEYRING_CLASS = {
WATCH: WatchKeyring.type,
WALLETCONNECT: WalletConnectKeyring.type,
GNOSIS: GnosisKeyring.type,
QRCODE: KeystoneKeyring.type,
};

interface MemStoreState {
Expand Down
25 changes: 25 additions & 0 deletions src/constant/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ import IconMnemonicWhite from 'ui/assets/walletlogo/IconMnemonic-white.svg';
import LogoLedgerDark from 'ui/assets/walletlogo/ledgerdark.png';
import LogoLedgerWhite from 'ui/assets/walletlogo/ledgerwhite.png';
import IconGridPlus from 'ui/assets/walletlogo/gridplus.png';
import LogoKeystone from 'ui/assets/walletlogo/keystone.png';
import LogoKeystoneWithBorder from 'ui/assets/walletlogo/keystone-border.png';

export enum CHAINS_ENUM {
ETH = 'ETH',
Expand Down Expand Up @@ -592,6 +594,7 @@ export const KEYRING_CLASS = {
LEDGER: 'Ledger Hardware',
ONEKEY: 'Onekey Hardware',
GRIDPLUS: 'GridPlus Hardware',
KEYSTONE: 'QR Hardware Wallet Device',
},
WATCH: 'Watch Address',
WALLETCONNECT: 'WalletConnect',
Expand All @@ -608,6 +611,7 @@ export const SUPPORT_1559_KEYRING_TYPE = [
KEYRING_CLASS.HARDWARE.GRIDPLUS,
KEYRING_CLASS.PRIVATE_KEY,
KEYRING_CLASS.MNEMONIC,
KEYRING_CLASS.HARDWARE.KEYSTONE,
];

export const KEYRING_TYPE_TEXT = {
Expand All @@ -631,6 +635,7 @@ export const BRAND_ALIAN_TYPE_TEXT = {
[KEYRING_CLASS.HARDWARE.BITBOX02]: 'BitBox02',
[KEYRING_CLASS.GNOSIS]: 'Gnosis',
[KEYRING_CLASS.HARDWARE.GRIDPLUS]: 'GridPlus',
[KEYRING_CLASS.HARDWARE.KEYSTONE]: 'Keystone',
};
export const HARDWARE_KEYRING_TYPES = {
BitBox02: {
Expand All @@ -653,6 +658,10 @@ export const HARDWARE_KEYRING_TYPES = {
type: 'GridPlus Hardware',
brandName: 'GridPlus',
},
Keystone: {
type: 'QR Hardware Wallet Device',
brandName: 'Keystone',
},
};

export enum TX_TYPE_ENUM {
Expand Down Expand Up @@ -772,6 +781,7 @@ export enum BRAND_WALLET_CONNECT_TYPE {
TrezorConnect = 'TrezorConnect',
GnosisConnect = 'GnosisConnect',
GridPlusConnect = 'GridPlusConnect',
QRCodeBase = 'QR Hardware Wallet Device',
}

export const WALLETCONNECT_STATUS_MAP = {
Expand Down Expand Up @@ -806,6 +816,9 @@ export const EVENTS = {
TX_BUILT: 'TransactionBuilt',
TX_CONFIRMED: 'TransactionConfirmed',
},
QRHARDWARE: {
ACQUIRE_MEMSTORE_SUCCEED: 'ACQUIRE_MEMSTORE_SUCCEED',
},
};

export enum WALLET_BRAND_TYPES {
Expand All @@ -824,6 +837,7 @@ export enum WALLET_BRAND_TYPES {
GNOSIS = 'Gnosis',
GRIDPLUS = 'GRIDPLUS',
METAMASK = 'MetaMask',
KEYSTONE = 'Keystone',
}

export const WALLET_BRAND_CONTENT = {
Expand Down Expand Up @@ -891,6 +905,14 @@ export const WALLET_BRAND_CONTENT = {
image: LogoJade,
connectType: BRAND_WALLET_CONNECT_TYPE.WalletConnect,
},
[WALLET_BRAND_TYPES.KEYSTONE]: {
id: 15,
name: 'Keystone',
brand: WALLET_BRAND_TYPES.KEYSTONE,
icon: LogoKeystone,
image: LogoKeystone,
connectType: BRAND_WALLET_CONNECT_TYPE.QRCodeBase,
},
[WALLET_BRAND_TYPES.LEDGER]: {
id: 4,
name: 'Ledger',
Expand Down Expand Up @@ -958,6 +980,7 @@ export const KEYRING_ICONS = {
[HARDWARE_KEYRING_TYPES.Onekey.type]: LogoOnekey,
[HARDWARE_KEYRING_TYPES.Trezor.type]: IconTrezor24,
[HARDWARE_KEYRING_TYPES.GridPlus.type]: IconGridPlus,
[HARDWARE_KEYRING_TYPES.Keystone.type]: LogoKeystone,
};

export const KEYRING_ICONS_WHITE = {
Expand All @@ -969,6 +992,7 @@ export const KEYRING_ICONS_WHITE = {
[HARDWARE_KEYRING_TYPES.Onekey.type]: LogoOnekey,
[HARDWARE_KEYRING_TYPES.Trezor.type]: IconTrezor24,
[HARDWARE_KEYRING_TYPES.GridPlus.type]: IconGridPlus,
[HARDWARE_KEYRING_TYPES.Keystone.type]: LogoKeystone,
};
export const KEYRING_PURPLE_LOGOS = {
[KEYRING_CLASS.MNEMONIC]: IconMnemonicPurple,
Expand All @@ -985,6 +1009,7 @@ export const KEYRINGS_LOGOS = {
[HARDWARE_KEYRING_TYPES.Onekey.type]: IconOneKey18,
[HARDWARE_KEYRING_TYPES.Trezor.type]: IconTrezor24Border,
[HARDWARE_KEYRING_TYPES.GridPlus.type]: IconGridPlus,
[HARDWARE_KEYRING_TYPES.Keystone.type]: LogoKeystone,
};

export const NOT_CLOSE_UNFOCUS_LIST: string[] = [
Expand Down
Binary file added src/ui/assets/walletlogo/keystone-border.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/ui/assets/walletlogo/keystone.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading