From e24b24c5f83055a2b8e098acaaafab782b0b8513 Mon Sep 17 00:00:00 2001 From: baha Date: Thu, 8 Jan 2026 15:26:22 +0300 Subject: [PATCH 01/12] feat(background): add lattice1 keyring support --- packages/background/src/index.ts | 3 + .../background/src/keyring-cosmos/service.ts | 24 +++++- .../src/keyring-ethereum/service.ts | 6 +- .../background/src/keyring-lattice1/index.ts | 2 + .../src/keyring-lattice1/internal.ts | 1 + .../src/keyring-lattice1/service.ts | 84 +++++++++++++++++++ .../background/src/keyring-lattice1/types.ts | 27 ++++++ packages/background/src/keyring/handler.ts | 23 +++++ packages/background/src/keyring/init.ts | 2 + packages/background/src/keyring/messages.ts | 44 ++++++++++ packages/background/src/keyring/service.ts | 57 +++++++++++++ packages/stores-core/src/core/keyring.ts | 21 ++++- 12 files changed, 288 insertions(+), 6 deletions(-) create mode 100644 packages/background/src/keyring-lattice1/index.ts create mode 100644 packages/background/src/keyring-lattice1/internal.ts create mode 100644 packages/background/src/keyring-lattice1/service.ts create mode 100644 packages/background/src/keyring-lattice1/types.ts diff --git a/packages/background/src/index.ts b/packages/background/src/index.ts index 25fc4dbb02..25a510baf6 100644 --- a/packages/background/src/index.ts +++ b/packages/background/src/index.ts @@ -20,6 +20,7 @@ import * as KeyRingV2 from "./keyring/internal"; import * as KeyRingMnemonic from "./keyring-mnemonic/internal"; import * as KeyRingLedger from "./keyring-ledger/internal"; import * as KeyRingKeystone from "./keyring-keystone/internal"; +import * as KeyRingLattice1 from "./keyring-lattice1/internal"; import * as KeyRingPrivateKey from "./keyring-private-key/internal"; import * as KeyRingCosmos from "./keyring-cosmos/internal"; import * as KeyRingEthereum from "./keyring-ethereum/internal"; @@ -51,6 +52,7 @@ export * from "./keyring-cosmos"; export * from "./keyring-ethereum"; export * from "./keyring-starknet"; export * from "./keyring-keystone"; +export * from "./keyring-lattice1"; export * from "./keyring-bitcoin"; export * from "./token-scan"; export * from "./recent-send-history"; @@ -209,6 +211,7 @@ export function init( new KeyRingLedger.KeyRingLedgerService(), new KeyRingPrivateKey.KeyRingPrivateKeyService(vaultService), new KeyRingKeystone.KeyRingKeystoneService(), + new KeyRingLattice1.KeyRingLattice1Service(), ] ); const keyRingCosmosService = new KeyRingCosmos.KeyRingCosmosService( diff --git a/packages/background/src/keyring-cosmos/service.ts b/packages/background/src/keyring-cosmos/service.ts index 51c62dcc91..d702585ac4 100644 --- a/packages/background/src/keyring-cosmos/service.ts +++ b/packages/background/src/keyring-cosmos/service.ts @@ -318,7 +318,11 @@ export class KeyRingCosmosService { let signature: Uint8Array; - if (keyInfo.type === "ledger" || keyInfo.type === "keystone") { + if ( + keyInfo.type === "ledger" || + keyInfo.type === "keystone" || + keyInfo.type === "lattice1" + ) { if (!res.signature || res.signature.length === 0) { throw new Error("Frontend should provide signature"); } @@ -797,7 +801,11 @@ export class KeyRingCosmosService { let signature: Uint8Array; - if (keyInfo.type === "ledger" || keyInfo.type === "keystone") { + if ( + keyInfo.type === "ledger" || + keyInfo.type === "keystone" || + keyInfo.type === "lattice1" + ) { if (!res.signature || res.signature.length === 0) { throw new Error("Frontend should provide signature"); } @@ -893,7 +901,11 @@ export class KeyRingCosmosService { let signature: Uint8Array; // XXX: 참고로 어차피 현재 ledger app이 direct signing을 지원하지 않는다. 그냥 일단 처리해놓은 것. - if (keyInfo.type === "ledger" || keyInfo.type === "keystone") { + if ( + keyInfo.type === "ledger" || + keyInfo.type === "keystone" || + keyInfo.type === "lattice1" + ) { if (!res.signature || res.signature.length === 0) { throw new Error("Frontend should provide signature"); } @@ -1038,7 +1050,11 @@ export class KeyRingCosmosService { let signature: Uint8Array; // XXX: 참고로 어차피 현재 ledger app이 direct signing을 지원하지 않는다. 그냥 일단 처리해놓은 것. - if (keyInfo.type === "ledger" || keyInfo.type === "keystone") { + if ( + keyInfo.type === "ledger" || + keyInfo.type === "keystone" || + keyInfo.type === "lattice1" + ) { if (!res.signature || res.signature.length === 0) { throw new Error("Frontend should provide signature"); } diff --git a/packages/background/src/keyring-ethereum/service.ts b/packages/background/src/keyring-ethereum/service.ts index 7c56586be7..c0a71eaea3 100644 --- a/packages/background/src/keyring-ethereum/service.ts +++ b/packages/background/src/keyring-ethereum/service.ts @@ -148,7 +148,11 @@ export class KeyRingEthereumService { }, async (res: { signingData: Uint8Array; signature?: Uint8Array }) => { const { signature, signingData } = await (async () => { - if (keyInfo.type === "ledger" || keyInfo.type === "keystone") { + if ( + keyInfo.type === "ledger" || + keyInfo.type === "keystone" || + keyInfo.type === "lattice1" + ) { if (!res.signature || res.signature.length === 0) { throw new Error("Frontend should provide signature"); } diff --git a/packages/background/src/keyring-lattice1/index.ts b/packages/background/src/keyring-lattice1/index.ts new file mode 100644 index 0000000000..4593a61f8b --- /dev/null +++ b/packages/background/src/keyring-lattice1/index.ts @@ -0,0 +1,2 @@ +export * from "./service"; +export * from "./types"; diff --git a/packages/background/src/keyring-lattice1/internal.ts b/packages/background/src/keyring-lattice1/internal.ts new file mode 100644 index 0000000000..6261f89636 --- /dev/null +++ b/packages/background/src/keyring-lattice1/internal.ts @@ -0,0 +1 @@ +export * from "./service"; diff --git a/packages/background/src/keyring-lattice1/service.ts b/packages/background/src/keyring-lattice1/service.ts new file mode 100644 index 0000000000..362a65cdab --- /dev/null +++ b/packages/background/src/keyring-lattice1/service.ts @@ -0,0 +1,84 @@ +import { PlainObject, Vault } from "../vault"; +import { Buffer } from "buffer/"; +import { PubKeySecp256k1 } from "@keplr-wallet/crypto"; +import { KeyRingService } from "../keyring"; +import { Lattice1Accounts } from "./types"; + +export class KeyRingLattice1Service { + async init(): Promise { + // No-op. Lattice1 uses frontend signing with stored credentials. + } + + supportedKeyRingType(): string { + return "lattice1"; + } + + createKeyRingVault( + lattice1Accounts: Lattice1Accounts + ): Promise<{ + insensitive: PlainObject; + sensitive: PlainObject; + }> { + const keys: PlainObject = {}; + lattice1Accounts.keys.forEach((k) => { + keys[k.path] = { + pubKey: k.publicKey, + chain: k.chain, + name: k.name, + }; + }); + const creds: PlainObject = { + deviceId: lattice1Accounts.creds.deviceId, + password: lattice1Accounts.creds.password, + endpoint: lattice1Accounts.creds.endpoint, + }; + + return Promise.resolve({ + insensitive: { + deviceId: lattice1Accounts.deviceId, + walletUid: lattice1Accounts.walletUid, + walletName: lattice1Accounts.walletName, + endpoint: lattice1Accounts.endpoint, + connectionType: lattice1Accounts.connectionType ?? "WIFI", + keys, + bip44Path: lattice1Accounts.bip44Path, + creds, + }, + sensitive: {}, + }); + } + + getPubKey(vault: Vault, purpose: number, coinType: number): PubKeySecp256k1 { + let bytes: Buffer; + if (vault.insensitive["keys"]) { + const path = Object.keys(vault.insensitive["keys"]).find((path) => { + const result = KeyRingService.parseBIP44Path(path); + return result.purpose === purpose && result.coinType === coinType; + }); + if (!path) { + throw new Error( + `Purpose ${purpose} and CoinType ${coinType} is not supported.` + ); + } + bytes = Buffer.from( + ((vault.insensitive["keys"] as PlainObject)[path] as PlainObject)[ + "pubKey" + ] as string, + "hex" + ); + } else { + throw new Error(`Lattice1 is not initialized.`); + } + return new PubKeySecp256k1(bytes); + } + + sign(): { + readonly r: Uint8Array; + readonly s: Uint8Array; + readonly v: number | null; + } { + throw new Error( + "Lattice1 can't sign message in background. You should provide the signature from frontend." + ); + } +} diff --git a/packages/background/src/keyring-lattice1/types.ts b/packages/background/src/keyring-lattice1/types.ts new file mode 100644 index 0000000000..21e05248d4 --- /dev/null +++ b/packages/background/src/keyring-lattice1/types.ts @@ -0,0 +1,27 @@ +export interface Lattice1Credentials { + deviceId: string; + password: string; + endpoint?: string; +} + +export interface Lattice1Account { + chain: string; + path: string; + publicKey: string; + name?: string; +} + +export interface Lattice1Accounts { + keys: Lattice1Account[]; + bip44Path: { + account: number; + change: number; + addressIndex: number; + }; + deviceId: string; + walletUid?: string; + walletName?: string; + endpoint?: string; + connectionType?: "WIFI"; + creds: Lattice1Credentials; +} diff --git a/packages/background/src/keyring/handler.ts b/packages/background/src/keyring/handler.ts index 9386bceffc..7d14d2a9c5 100644 --- a/packages/background/src/keyring/handler.ts +++ b/packages/background/src/keyring/handler.ts @@ -26,6 +26,7 @@ import { ExportKeyRingDataMsg, CheckLegacyKeyRingPasswordMsg, NewKeystoneKeyMsg, + NewLattice1KeyMsg, CheckPasswordMsg, GetLegacyKeyRingInfosMsg, ShowSensitiveLegacyKeyRingDataMsg, @@ -68,6 +69,11 @@ export const getHandler: (service: KeyRingService) => Handler = ( return handleNewLedgerKeyMsg(service)(env, msg as NewLedgerKeyMsg); case NewKeystoneKeyMsg: return handleNewKeystoneKeyMsg(service)(env, msg as NewKeystoneKeyMsg); + case NewLattice1KeyMsg: + return handleNewLattice1KeyMsg(service)( + env, + msg as NewLattice1KeyMsg + ); case NewPrivateKeyKeyMsg: return handleNewPrivateKeyKeyMsg(service)( env, @@ -273,6 +279,23 @@ const handleNewKeystoneKeyMsg: ( }; }; +const handleNewLattice1KeyMsg: ( + service: KeyRingService +) => InternalHandler = (service) => { + return async (_, msg) => { + const vaultId = await service.createLattice1KeyRing( + msg.lattice1Accounts, + msg.name, + msg.password + ); + return { + vaultId, + status: service.keyRingStatus, + keyInfos: service.getKeyInfos(), + }; + }; +}; + const handleNewPrivateKeyKeyMsg: ( service: KeyRingService ) => InternalHandler = (service) => { diff --git a/packages/background/src/keyring/init.ts b/packages/background/src/keyring/init.ts index d3803d3d44..9abf11c9f2 100644 --- a/packages/background/src/keyring/init.ts +++ b/packages/background/src/keyring/init.ts @@ -20,6 +20,7 @@ import { ExportKeyRingDataMsg, CheckLegacyKeyRingPasswordMsg, NewKeystoneKeyMsg, + NewLattice1KeyMsg, CheckPasswordMsg, GetLegacyKeyRingInfosMsg, ShowSensitiveLegacyKeyRingDataMsg, @@ -39,6 +40,7 @@ export function init(router: Router, service: KeyRingService): void { router.registerMessage(NewMnemonicKeyMsg); router.registerMessage(NewLedgerKeyMsg); router.registerMessage(NewKeystoneKeyMsg); + router.registerMessage(NewLattice1KeyMsg); router.registerMessage(NewPrivateKeyKeyMsg); router.registerMessage(AppendLedgerKeyAppMsg); router.registerMessage(AppendLedgerExtendedKeysMsg); diff --git a/packages/background/src/keyring/messages.ts b/packages/background/src/keyring/messages.ts index d8ccccb8ea..15d329950b 100644 --- a/packages/background/src/keyring/messages.ts +++ b/packages/background/src/keyring/messages.ts @@ -12,6 +12,7 @@ import { import { PlainObject } from "../vault"; import * as Legacy from "./legacy"; import { MultiAccounts } from "../keyring-keystone"; +import { Lattice1Accounts } from "../keyring-lattice1"; export class GetIsLockedMsg extends Message { public static type() { @@ -283,6 +284,49 @@ export class NewKeystoneKeyMsg extends Message<{ } } +export class NewLattice1KeyMsg extends Message<{ + vaultId: string; + status: KeyRingStatus; + keyInfos: KeyInfo[]; +}> { + public static type() { + return "new-lattice1-key"; + } + + constructor( + public readonly lattice1Accounts: Lattice1Accounts, + public readonly name: string, + public readonly password?: string + ) { + super(); + } + + validateBasic(): void { + if (!this.lattice1Accounts || this.lattice1Accounts.keys.length === 0) { + throw new Error("pub key not set"); + } + + if ( + !this.lattice1Accounts.creds?.deviceId || + !this.lattice1Accounts.creds?.password + ) { + throw new Error("device credentials not set"); + } + + if (!this.name) { + throw new Error("name not set"); + } + } + + route(): string { + return ROUTE; + } + + type(): string { + return NewLattice1KeyMsg.type(); + } +} + export class NewPrivateKeyKeyMsg extends Message<{ vaultId: string; status: KeyRingStatus; diff --git a/packages/background/src/keyring/service.ts b/packages/background/src/keyring/service.ts index 1eba4e7ed9..a977034dae 100644 --- a/packages/background/src/keyring/service.ts +++ b/packages/background/src/keyring/service.ts @@ -27,6 +27,7 @@ import { Buffer } from "buffer/"; import * as Legacy from "./legacy"; import { ChainsUIForegroundService, ChainsUIService } from "../chains-ui"; import { MultiAccounts } from "../keyring-keystone"; +import { Lattice1Accounts } from "../keyring-lattice1"; import { AnalyticsService } from "../analytics"; import { Primitive } from "utility-types"; import { runIfOnlyAppStart } from "../utils"; @@ -857,6 +858,62 @@ export class KeyRingService { return id; } + async createLattice1KeyRing( + lattice1Accounts: Lattice1Accounts, + name: string, + password?: string + ): Promise { + if (!this.vaultService.isSignedUp) { + if (!password) { + throw new Error("Must provide password to sign in to vault"); + } + + await this.vaultService.signUp(password); + } + + lattice1Accounts.keys.forEach((key) => { + const result = KeyRingService.parseBIP44Path(key.path); + KeyRingService.validateBIP44Path(result.path); + }); + + const keyRing = this.getKeyRing("lattice1"); + const vaultData = await keyRing.createKeyRingVault(lattice1Accounts); + + // Finalize coin type if only one coin type exists. + const coinTypes: Record = {}; + const chainInfos = this.chainsService.getChainInfos(); + for (const chainInfo of chainInfos) { + if ( + !chainInfo.alternativeBIP44s || + chainInfo.alternativeBIP44s.length === 0 + ) { + const coinTypeTag = `keyRing-${ + ChainIdHelper.parse(chainInfo.chainId).identifier + }-coinType`; + coinTypes[coinTypeTag] = chainInfo.bip44.coinType; + } + } + + const id = this.vaultService.addVault( + "keyRing", + { + ...vaultData.insensitive, + ...coinTypes, + keyRingName: name, + keyRingType: keyRing.supportedKeyRingType(), + }, + vaultData.sensitive + ); + + runInAction(() => { + this._selectedVaultId = id; + }); + + this.interactionService.dispatchEvent(WEBPAGE_PORT, "keystore-changed", {}); + + return id; + } + async createPrivateKeyKeyRing( privateKey: Uint8Array, meta: PlainObject, diff --git a/packages/stores-core/src/core/keyring.ts b/packages/stores-core/src/core/keyring.ts index 836bf6dcc8..51544c9c9d 100644 --- a/packages/stores-core/src/core/keyring.ts +++ b/packages/stores-core/src/core/keyring.ts @@ -26,6 +26,7 @@ import { KeyRingStatus, LockKeyRingMsg, NewKeystoneKeyMsg, + NewLattice1KeyMsg, NewLedgerKeyMsg, NewMnemonicKeyMsg, NewPrivateKeyKeyMsg, @@ -35,7 +36,7 @@ import { ShowSensitiveKeyRingDataMsg, UnlockKeyRingMsg, } from "@keplr-wallet/background"; -import type { MultiAccounts } from "@keplr-wallet/background"; +import type { Lattice1Accounts, MultiAccounts } from "@keplr-wallet/background"; import { ChainInfo } from "@keplr-wallet/types"; import { ChainIdHelper } from "@keplr-wallet/cosmos"; @@ -288,6 +289,24 @@ export class KeyRingStore { return result.vaultId; } + @flow + *newLattice1Key( + lattice1Accounts: Lattice1Accounts, + name: string, + password: string | undefined + ) { + const msg = new NewLattice1KeyMsg(lattice1Accounts, name, password); + const result = yield* toGenerator( + this.requester.sendMessage(BACKGROUND_PORT, msg) + ); + this._status = result.status; + this._keyInfos = result.keyInfos; + + this.eventDispatcher.dispatchEvent("keplr_keystorechange"); + + return result.vaultId; + } + @flow *newPrivateKeyKey( privateKey: Uint8Array, From 79b62a75e3b2e149cd5f5cd7f8ff6534c6f6ea72 Mon Sep 17 00:00:00 2001 From: baha Date: Thu, 8 Jan 2026 15:26:47 +0300 Subject: [PATCH 02/12] feat(extension): add lattice1 onboarding and UI --- apps/extension/package.json | 1 + .../src/components/icon/lattice1.tsx | 35 ++ .../src/hooks/key-info/use-key-info-sort.ts | 20 + apps/extension/src/languages/en.json | 13 + apps/extension/src/languages/ko.json | 13 + apps/extension/src/languages/zh-cn.json | 13 + .../main/components/account-icon/index.tsx | 38 ++ .../pages/register/connect-hardware/index.tsx | 14 + .../pages/register/connect-lattice1/index.tsx | 336 +++++++++++ .../pages/register/enable-chains/index.tsx | 9 + .../src/pages/register/finalize-key/index.tsx | 11 +- apps/extension/src/pages/register/index.tsx | 6 + .../register/name-password-hardware/index.tsx | 48 +- apps/extension/src/pages/setting/index.tsx | 4 +- .../src/pages/wallet/select/index.tsx | 9 + apps/extension/src/stores/chain/index.tsx | 33 +- apps/extension/src/utils/index.ts | 1 + apps/extension/src/utils/lattice1.ts | 229 ++++++++ yarn.lock | 537 +++++++++++++++++- 19 files changed, 1338 insertions(+), 32 deletions(-) create mode 100644 apps/extension/src/components/icon/lattice1.tsx create mode 100644 apps/extension/src/pages/register/connect-lattice1/index.tsx create mode 100644 apps/extension/src/utils/lattice1.ts diff --git a/apps/extension/package.json b/apps/extension/package.json index f1dfc538ef..a1b47f9544 100644 --- a/apps/extension/package.json +++ b/apps/extension/package.json @@ -71,6 +71,7 @@ "color": "^4.2.3", "crypto-browserify": "^3.12.0", "delay": "^4.4.0", + "gridplus-sdk": "^4.0.0", "https-browserify": "^1.0.0", "joi": "^17.5.0", "js-yaml": "^4.1.0", diff --git a/apps/extension/src/components/icon/lattice1.tsx b/apps/extension/src/components/icon/lattice1.tsx new file mode 100644 index 0000000000..a806c2500c --- /dev/null +++ b/apps/extension/src/components/icon/lattice1.tsx @@ -0,0 +1,35 @@ +import React, { FunctionComponent } from "react"; +import { IconProps } from "./types"; + +export const Lattice1Icon: FunctionComponent = ({ + width = "auto", + height = "1.5rem", + color, +}) => { + const colors: { [key: string]: { color1: string; color2: string } } = { + dark: { + color1: "#f5f8ff", + color2: "#3d71ff", + }, + light: { + color1: "#000000", + color2: "#1f5aff", + }, + }; + + const color1 = color && color in colors ? colors[color].color1 : color; + const color2 = color && color in colors ? colors[color].color2 : color; + + return ( + + + + + ); +}; diff --git a/apps/extension/src/hooks/key-info/use-key-info-sort.ts b/apps/extension/src/hooks/key-info/use-key-info-sort.ts index d19a8950f6..edc806af28 100644 --- a/apps/extension/src/hooks/key-info/use-key-info-sort.ts +++ b/apps/extension/src/hooks/key-info/use-key-info-sort.ts @@ -6,6 +6,7 @@ export const KEY_INFO_SORT_KEY = { MNEMONIC: "sort-mnemonic", PRIVATE_KEY: "sort-private-key", LEDGER: "sort-ledger", + LATTICE1: "sort-lattice1", KEYSTONE: "sort-keystone", UNKNOWN: "sort-unknown", }; @@ -85,6 +86,12 @@ export const useGetKeyInfosSeparatedByType = (keyInfos: KeyInfo[]) => { }); }, [keyInfos]); + const lattice1Keys = useMemo(() => { + return keyInfos.filter((keyInfo) => { + return keyInfo.type === "lattice1"; + }); + }, [keyInfos]); + const keystoneKeys = useMemo(() => { return keyInfos.filter((keyInfo) => { return keyInfo.type === "keystone"; @@ -94,6 +101,7 @@ export const useGetKeyInfosSeparatedByType = (keyInfos: KeyInfo[]) => { const unknownKeys = useMemo(() => { const knownKeys = mnemonicKeys .concat(ledgerKeys) + .concat(lattice1Keys) .concat(privateKeyInfos) .concat(socialPrivateKeyInfos) .concat(keystoneKeys); @@ -103,6 +111,7 @@ export const useGetKeyInfosSeparatedByType = (keyInfos: KeyInfo[]) => { }, [ keyInfos, ledgerKeys, + lattice1Keys, mnemonicKeys, privateKeyInfos, socialPrivateKeyInfos, @@ -161,6 +170,7 @@ export const useGetKeyInfosSeparatedByType = (keyInfos: KeyInfo[]) => { socialPrivateKeyInfoByType, privateKeyInfos, ledgerKeys, + lattice1Keys, keystoneKeys, unknownKeys, }; @@ -173,6 +183,7 @@ export const useGetAllSortedKeyInfos = (keyInfos: KeyInfo[]) => { socialPrivateKeyInfoByType, privateKeyInfos, ledgerKeys, + lattice1Keys, keystoneKeys, unknownKeys, } = useGetKeyInfosSeparatedByType(keyInfos); @@ -222,6 +233,14 @@ export const useGetAllSortedKeyInfos = (keyInfos: KeyInfo[]) => { res.push(...sortKeyInfos(ledgerKeys, indexMap)); } + if (lattice1Keys.length > 0) { + const indexMap = + uiConfigStore.selectWalletConfig.getKeyToSortVaultIdsMapIndex( + KEY_INFO_SORT_KEY.LATTICE1 + ); + res.push(...sortKeyInfos(lattice1Keys, indexMap)); + } + if (keystoneKeys.length > 0) { const indexMap = uiConfigStore.selectWalletConfig.getKeyToSortVaultIdsMapIndex( @@ -243,6 +262,7 @@ export const useGetAllSortedKeyInfos = (keyInfos: KeyInfo[]) => { socialPrivateKeyInfoByType, privateKeyInfos, ledgerKeys, + lattice1Keys, keystoneKeys, unknownKeys, uiConfigStore.selectWalletConfig, diff --git a/apps/extension/src/languages/en.json b/apps/extension/src/languages/en.json index 9642d0aea1..c99f61253a 100644 --- a/apps/extension/src/languages/en.json +++ b/apps/extension/src/languages/en.json @@ -83,6 +83,7 @@ "pages.register.connect-hardware.content.title": "Select a hardware wallet that you would like to use with Keplr", "pages.register.connect-hardware.connect-ledger-button": "Connect Ledger", "pages.register.connect-hardware.connect-keystone-button": "Connect Keystone", + "pages.register.connect-hardware.connect-lattice1-button": "Connect Lattice1", "pages.register.new-mnemonic.title": "New Recovery Phrase", "pages.register.new-mnemonic.12-words-tab": "12 words", @@ -139,6 +140,13 @@ "pages.register.connect-ledger.use-hid-confirm-title": "Unable to use Web HID", "pages.register.connect-ledger.use-hid-confirm-paragraph": "Please enable ‘experimental web platform features’ to use Web HID", + "pages.register.connect-lattice1.title": "Connect your Lattice1", + "pages.register.connect-lattice1.paragraph": "Pair your Lattice1 over Wi-Fi and approve public key export.", + "pages.register.connect-lattice1.step-1": "Open Lattice Connect to pair your device.", + "pages.register.connect-lattice1.step-2": "Unlock your Lattice1 and confirm the connection.", + "pages.register.connect-lattice1.step-3": "Approve public key export on your Lattice1.", + "pages.register.connect-lattice1.error-title": "Unable to connect to Lattice1", + "pages.register.connect-keystone.paragraph": "Please unlock your Keystone device and connect it to your computer via USB.", "pages.register.connect-keystone.step-text": "Step {num}", "pages.register.connect-keystone.step-1": "Tap “Connect Software Wallet” at the bottom left corner on the Keystone device.", @@ -588,6 +596,11 @@ "page.sign.components.ledger-guide.box.sign-on-ledger-title": "Sign on Ledger", "page.sign.components.ledger-guide.box.sign-on-ledger-paragraph": "To proceed, please review and approve the transaction on your Ledger device.", + "page.sign.components.lattice1-guide.box.error-title": "Error", + "page.sign.components.lattice1-guide.box.sign-on-lattice1-title": "Sign on Lattice1", + "page.sign.components.lattice1-guide.box.sign-on-lattice1-paragraph": "Review and approve the request on your Lattice1.", + "page.sign.components.lattice1-guide.box.connect-lattice1-paragraph": "Make sure your Lattice1 is unlocked and on the same Wi-Fi network.", + "page.sign.keystone.title": "Scan the QR Code", "page.sign.keystone.scan-qrcode": "Scan the QR code via your Keystone device", "page.sign.keystone.click-get-signature": "Click on the 'Get Signature' button after signing the transaction with your Keystone device.", diff --git a/apps/extension/src/languages/ko.json b/apps/extension/src/languages/ko.json index 0e64eb1799..d90656679f 100644 --- a/apps/extension/src/languages/ko.json +++ b/apps/extension/src/languages/ko.json @@ -83,6 +83,7 @@ "pages.register.connect-hardware.content.title": "케플러와 연결하고 싶은 하드웨어 지갑을 선택해주세요.", "pages.register.connect-hardware.connect-ledger-button": "렛저 계정 연결하기", "pages.register.connect-hardware.connect-keystone-button": "키스톤 계정 연결하기", + "pages.register.connect-hardware.connect-lattice1-button": "Lattice1 연결하기", "pages.register.new-mnemonic.title": "새로운 복구 문구", "pages.register.new-mnemonic.12-words-tab": "12 단어", @@ -140,6 +141,13 @@ "pages.register.connect-ledger.use-hid-confirm-title": "웹 HID를 사용할 수 없습니다.", "pages.register.connect-ledger.use-hid-confirm-paragraph": "웹 HID를 사용하시려면, ‘실험적 웹 플랫폼 기능’을 활성화해야 합니다.", + "pages.register.connect-lattice1.title": "Lattice1을 연결하세요", + "pages.register.connect-lattice1.paragraph": "Wi-Fi로 Lattice1을 페어링하고 공개키 내보내기를 승인하세요.", + "pages.register.connect-lattice1.step-1": "Lattice Connect를 열어 기기를 페어링하세요.", + "pages.register.connect-lattice1.step-2": "Lattice1을 잠금 해제하고 연결을 승인하세요.", + "pages.register.connect-lattice1.step-3": "Lattice1에서 공개키 내보내기를 승인하세요.", + "pages.register.connect-lattice1.error-title": "Lattice1에 연결할 수 없습니다", + "pages.register.connect-keystone.title": "하드웨어 지갑을 연결해주세요.", "pages.register.connect-keystone.step-text": "{num} 단계", "pages.register.connect-keystone.step-1": "키스톤 장치 왼쪽 하단의 “소프트웨어 지갑 연결” 버튼을 누르세요.", @@ -570,6 +578,11 @@ "page.sign.components.ledger-guide.box.sign-on-ledger-title": "렛저에서 서명하기", "page.sign.components.ledger-guide.box.sign-on-ledger-paragraph": "계속 하시려면, 렛저에서 트랜잭션을 확인하고 승인해야 합니다.", + "page.sign.components.lattice1-guide.box.error-title": "오류", + "page.sign.components.lattice1-guide.box.sign-on-lattice1-title": "Lattice1에서 서명하기", + "page.sign.components.lattice1-guide.box.sign-on-lattice1-paragraph": "Lattice1에서 요청 내용을 확인하고 승인하세요.", + "page.sign.components.lattice1-guide.box.connect-lattice1-paragraph": "Lattice1이 잠금 해제되어 있고 동일한 Wi-Fi 네트워크에 있는지 확인하세요.", + "page.sign.keystone.title": "QR 코드를 스캔하세요", "page.sign.keystone.scan-qrcode": "키스톤 장치로 QR 코드를 스캔하세요", "page.sign.keystone.click-get-signature": "키스톤 장치에서 트랜잭션을 서명한 후, '서명정보 받아오기' 버튼을 누르세요.", diff --git a/apps/extension/src/languages/zh-cn.json b/apps/extension/src/languages/zh-cn.json index cce0b0ede9..7b5b46b3e3 100644 --- a/apps/extension/src/languages/zh-cn.json +++ b/apps/extension/src/languages/zh-cn.json @@ -82,6 +82,7 @@ "pages.register.connect-hardware.content.title": "选择你想要与Keplr一起使用的硬件钱包", "pages.register.connect-hardware.connect-ledger-button": "连接Ledger", "pages.register.connect-hardware.connect-keystone-button": "连接Keystone", + "pages.register.connect-hardware.connect-lattice1-button": "连接Lattice1", "pages.register.new-mnemonic.title": "新助记词", "pages.register.new-mnemonic.12-words-tab": "12个词", @@ -137,6 +138,13 @@ "pages.register.connect-ledger.use-hid-confirm-title": "无法使用Web HID", "pages.register.connect-ledger.use-hid-confirm-paragraph": "请启用“实验性Web平台功能”以使用Web HID", + "pages.register.connect-lattice1.title": "连接你的Lattice1", + "pages.register.connect-lattice1.paragraph": "通过 Wi-Fi 配对 Lattice1 并批准导出公钥。", + "pages.register.connect-lattice1.step-1": "打开 Lattice Connect 以配对设备。", + "pages.register.connect-lattice1.step-2": "解锁你的 Lattice1 并确认连接。", + "pages.register.connect-lattice1.step-3": "在 Lattice1 上批准导出公钥。", + "pages.register.connect-lattice1.error-title": "无法连接到 Lattice1", + "pages.register.connect-keystone.title": "请连接你的硬件钱包", "pages.register.connect-keystone.step-text": "步骤 {num}", "pages.register.connect-keystone.step-1": "点击Keystone设备左下角的“连接软件钱包”。", @@ -537,6 +545,11 @@ "page.sign.components.ledger-guide.box.sign-on-ledger-title": "Ledger签名", "page.sign.components.ledger-guide.box.sign-on-ledger-paragraph": "要继续,请在你的Ledger设备上查看并确认交易。", + "page.sign.components.lattice1-guide.box.error-title": "错误", + "page.sign.components.lattice1-guide.box.sign-on-lattice1-title": "在 Lattice1 上签名", + "page.sign.components.lattice1-guide.box.sign-on-lattice1-paragraph": "请在你的 Lattice1 上查看并批准请求。", + "page.sign.components.lattice1-guide.box.connect-lattice1-paragraph": "请确保你的 Lattice1 已解锁并连接到同一 Wi-Fi 网络。", + "page.sign.keystone.title": "扫描二维码", "page.sign.keystone.scan-qrcode": "通过你的Keystone设备扫描二维码", "page.sign.keystone.click-get-signature": "使用Keystone设备签名交易后,点击“获取签名”按钮。", diff --git a/apps/extension/src/pages/main/components/account-icon/index.tsx b/apps/extension/src/pages/main/components/account-icon/index.tsx index bcf8666d45..acd95059f5 100644 --- a/apps/extension/src/pages/main/components/account-icon/index.tsx +++ b/apps/extension/src/pages/main/components/account-icon/index.tsx @@ -27,6 +27,12 @@ export const AccountNameIcon = ({ switch (keyInfoType) { case "ledger": return theme.mode === "light" ? <_LedgerIconLM /> : <_LedgerIconDM />; + case "lattice1": + return theme.mode === "light" ? ( + <_Lattice1IconLM /> + ) : ( + <_Lattice1IconDM /> + ); case "keystone": return theme.mode === "light" ? ( <_KeystoneIconLM /> @@ -161,3 +167,35 @@ const _KeystoneIconDM = () => { ); }; + +const _Lattice1IconLM = () => { + return ( + + + + + + ); +}; + +const _Lattice1IconDM = () => { + return ( + + + + + + ); +}; diff --git a/apps/extension/src/pages/register/connect-hardware/index.tsx b/apps/extension/src/pages/register/connect-hardware/index.tsx index 903ed972ec..12dcf14b41 100644 --- a/apps/extension/src/pages/register/connect-hardware/index.tsx +++ b/apps/extension/src/pages/register/connect-hardware/index.tsx @@ -13,6 +13,7 @@ import { Box } from "../../../components/box"; import { FormattedMessage, useIntl } from "react-intl"; import { useTheme } from "styled-components"; import { KeystoneIcon } from "../../../components/icon/keystone"; +import { Lattice1Icon } from "../../../components/icon/lattice1"; export const ConnectHardwareWalletScene: FunctionComponent = () => { const sceneTransition = useSceneTransition(); @@ -85,6 +86,19 @@ export const ConnectHardwareWalletScene: FunctionComponent = () => { }); }} /> +