@metamask-previews/eth-qr-keyring 0.0.0-36c61e7 → 0.0.0-a621908
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/dist/device.cjs +3 -4
- package/dist/device.cjs.map +1 -1
- package/dist/device.d.cts.map +1 -1
- package/dist/device.d.mts.map +1 -1
- package/dist/device.mjs +3 -4
- package/dist/device.mjs.map +1 -1
- package/dist/index.cjs +9 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -2
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +3 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +3 -2
- package/dist/index.mjs.map +1 -1
- package/dist/qr-keyring-deferred-promise-bridge.cjs.map +1 -1
- package/dist/qr-keyring-deferred-promise-bridge.d.cts +2 -2
- package/dist/qr-keyring-deferred-promise-bridge.d.cts.map +1 -1
- package/dist/qr-keyring-deferred-promise-bridge.d.mts +2 -2
- package/dist/qr-keyring-deferred-promise-bridge.d.mts.map +1 -1
- package/dist/qr-keyring-deferred-promise-bridge.mjs.map +1 -1
- package/dist/qr-keyring.cjs +1 -1
- package/dist/qr-keyring.cjs.map +1 -1
- package/dist/qr-keyring.mjs +1 -1
- package/dist/qr-keyring.mjs.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
package/dist/device.cjs
CHANGED
|
@@ -198,11 +198,10 @@ class Device {
|
|
|
198
198
|
const dataType = transaction.type === tx_1.TransactionType.Legacy
|
|
199
199
|
? bc_ur_registry_eth_1.DataType.transaction
|
|
200
200
|
: bc_ur_registry_eth_1.DataType.typedTransaction;
|
|
201
|
-
const messageToSign =
|
|
202
|
-
|
|
203
|
-
: transaction.getMessageToSign());
|
|
201
|
+
const messageToSign = transaction.getMessageToSign();
|
|
202
|
+
const rawTransaction = Buffer.from(Array.isArray(messageToSign) ? rlp_1.RLP.encode(messageToSign) : messageToSign);
|
|
204
203
|
const requestId = (0, uuid_1.v4)();
|
|
205
|
-
const ethSignRequestUR = bc_ur_registry_eth_1.EthSignRequest.constructETHRequest(
|
|
204
|
+
const ethSignRequestUR = bc_ur_registry_eth_1.EthSignRequest.constructETHRequest(rawTransaction, dataType, this.pathFromAddress(address), __classPrivateFieldGet(this, _Device_pairedDevice, "f").xfp, requestId, Number(transaction.common.chainId())).toUR();
|
|
206
205
|
const { r, s, v } = await __classPrivateFieldGet(this, _Device_instances, "m", _Device_requestSignature).call(this, {
|
|
207
206
|
requestId,
|
|
208
207
|
payload: {
|
package/dist/device.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"device.cjs","sourceRoot":"","sources":["../src/device.ts"],"names":[],"mappings":"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","sourcesContent":["import { RLP } from '@ethereumjs/rlp';\nimport {\n type TypedTransaction,\n TransactionType,\n type TypedTxData,\n type FeeMarketEIP1559Transaction,\n TransactionFactory,\n} from '@ethereumjs/tx';\nimport { publicToAddress } from '@ethereumjs/util';\nimport {\n CryptoAccount,\n CryptoHDKey,\n DataType,\n ETHSignature,\n EthSignRequest,\n URRegistryDecoder,\n} from '@keystonehq/bc-ur-registry-eth';\nimport type { MessageTypes, TypedMessage } from '@metamask/eth-sig-util';\nimport { add0x, getChecksumAddress, remove0x, type Hex } from '@metamask/utils';\n// eslint-disable-next-line @typescript-eslint/naming-convention\nimport HdKey from 'hdkey';\nimport { stringify, v4 as uuidv4 } from 'uuid';\n\nimport {\n QrScanRequestType,\n type QrKeyringBridge,\n type QrSignatureRequest,\n type SerializedUR,\n} from './qr-keyring';\n\nexport const SUPPORTED_UR_TYPE = {\n CRYPTO_HDKEY: 'crypto-hdkey',\n CRYPTO_ACCOUNT: 'crypto-account',\n ETH_SIGNATURE: 'eth-signature',\n};\n\nexport enum DeviceMode {\n HD = 'hd',\n ACCOUNT = 'account',\n}\n\nconst DEFAULT_CHILDREN_PATH = '0/*';\n\nconst MAX_INDEX = 1_000;\n\n/**\n * Common details for the device source, which can be either a CryptoAccount or CryptoHDKey.\n */\nexport type CommonDeviceDetails = {\n /**\n * Value take out from the device note field, if available.\n */\n keyringAccount: string;\n /**\n * The name of the device\n */\n name: string;\n /**\n * The device fingerprint, hex-encoded\n */\n xfp: string;\n /**\n * Indexes of the accounts derived from the device\n * in the form of a map from address to index\n */\n indexes: Record<Hex, number>;\n};\n\n/**\n * Details for the HD mode of the Device. This mode derives\n * accounts from a root public key (xpub) and a derivation path.\n */\nexport type HDModeDeviceDetails = {\n /**\n * The device mode is HD, indicating that it derives accounts from a\n * root public key (xpub) and a derivation path.\n */\n keyringMode: DeviceMode.HD;\n /**\n * The xpub of the HD key\n */\n xpub: string;\n /**\n * The derivation path of the HD key\n */\n hdPath: string;\n /**\n * The path used to derive child accounts\n */\n childrenPath: string;\n};\n\n/**\n * Details for the Account mode of the Device. This mode derives\n * accounts from a set of addresses and their corresponding paths.\n */\nexport type AccountModeDeviceDetails = {\n /**\n * The device mode is ACCOUNT, indicating that it derives accounts from\n * a set of addresses and their corresponding paths.\n */\n keyringMode: DeviceMode.ACCOUNT;\n /**\n * The derivation paths for each hex-encoded address in the device\n */\n paths: Record<Hex, string>;\n};\n\n/**\n * An address with its corresponding index.\n */\nexport type IndexedAddress = {\n address: Hex;\n index: number;\n};\n\n/**\n * The details of the source CryptoAccount or CryptoHDKey\n * that the Device uses to derive accounts.\n */\nexport type DeviceDetails = CommonDeviceDetails &\n (HDModeDeviceDetails | AccountModeDeviceDetails);\n\nexport type DeviceOptions = {\n /**\n * The requestScan function to scan the QR code\n */\n requestScan: QrKeyringBridge['requestScan'];\n /**\n * The source of the device, which can be of type `DeviceDetails`,\n * `string`, or `SerializedUR`.\n *\n * When a `string` or `SerializedUR` is provided, the Device will\n * initialize itself from the UR.\n */\n source: DeviceDetails | string | SerializedUR;\n};\n\n/**\n * Get the fingerprint of the source CryptoAccount or CryptoHDKey\n *\n * @param source - The source CryptoAccount or CryptoHDKey\n * @returns The fingerprint of the source\n */\nfunction getFingerprintFromSource(source: CryptoAccount | CryptoHDKey): string {\n return source instanceof CryptoAccount\n ? source.getMasterFingerprint()?.toString('hex')\n : source.getParentFingerprint()?.toString('hex');\n}\n\n/**\n * Get fingerprint, account paths and names from the a CryptoAccount\n *\n * Note: This function emulates the behavior of the `@keystonehq/base-eth-keyring`\n * library when dealing with CryptoAccount objects (for backwards compatibility\n * reasons). Though, the way it retrieves `name` and `keyringAccount` is questionable,\n * as `name` and `keyringAccount` are updated after each descriptor discovery, effectively\n * returning the last descriptor's `name` and `keyringAccount`.\n *\n * @param source - The source CryptoAccount\n * @returns The paths\n */\nfunction readCryptoAccountOutputDescriptors(source: CryptoAccount): {\n xfp: string;\n paths: Record<Hex, string>;\n name: string;\n keyringAccount: string;\n} {\n const descriptors = source.getOutputDescriptors();\n\n if (!descriptors || descriptors.length === 0) {\n throw new Error('No output descriptors found in CryptoAccount');\n }\n\n let name = '';\n let keyringAccount = '';\n const paths = descriptors.reduce(\n (descriptorsPaths: Record<Hex, string>, current) => {\n const hdKey = current.getHDKey();\n if (hdKey) {\n const path = `M/${hdKey.getOrigin().getPath()}`;\n const address = getChecksumAddress(\n add0x(\n Buffer.from(publicToAddress(hdKey.getKey(), true)).toString('hex'),\n ),\n );\n descriptorsPaths[address] = path;\n name = hdKey.getName();\n keyringAccount = hdKey.getNote();\n }\n return descriptorsPaths;\n },\n {},\n );\n\n return {\n paths,\n name,\n keyringAccount,\n xfp: getFingerprintFromSource(source),\n };\n}\n\nexport class Device {\n readonly #requestScan: QrKeyringBridge['requestScan'];\n\n readonly #pairedDevice: DeviceDetails;\n\n /**\n * Create a new Device instance.\n *\n * @param options - The options for the Device, including the requestScan function\n * and the source of the device details.\n * @param options.requestScan - The function to request a scan of the QR code.\n * @param options.source - The source of the device details, which can be a\n * UR string, a `SerializedUR`, or a `DeviceDetails` object.\n */\n constructor({ requestScan, source }: DeviceOptions) {\n this.#requestScan = requestScan;\n this.#pairedDevice =\n typeof source === 'string' || 'cbor' in source\n ? this.#deviceDetailsFromUR(source)\n : source;\n }\n\n /**\n * Derive an address from the source at a given index\n *\n * @param index - The index to derive the address from\n * @returns The derived address in hex format\n * @throws Will throw an error if the source is not initialized\n */\n addressFromIndex(index: number): Hex {\n if (this.#pairedDevice.keyringMode === DeviceMode.ACCOUNT) {\n const address = Object.keys(this.#pairedDevice.paths)[index];\n if (!address) {\n throw new Error(`Address not found for index ${index}`);\n }\n return add0x(address);\n }\n const childPath = `m/${this.#pairedDevice.childrenPath.replace(\n '*',\n index.toString(),\n )}`;\n\n const hdKey = HdKey.fromExtendedKey(this.#pairedDevice.xpub);\n const childKey = hdKey.derive(childPath);\n\n const address = Buffer.from(\n publicToAddress(childKey.publicKey, true),\n ).toString('hex');\n\n const normalizedAddress = getChecksumAddress(add0x(address));\n\n this.#pairedDevice.indexes[normalizedAddress] = index;\n\n return normalizedAddress;\n }\n\n /**\n * Retrieve the path of an address derived from the source.\n *\n * @param address - The address to retrieve the path for\n * @returns The path of the address\n */\n pathFromAddress(address: Hex): string {\n const normalizedAddress = getChecksumAddress(add0x(address));\n\n if (this.#pairedDevice.keyringMode === DeviceMode.ACCOUNT) {\n const path = this.#pairedDevice.paths[normalizedAddress];\n if (path === undefined) {\n throw new Error(`Unknown address ${normalizedAddress}`);\n }\n return path;\n }\n\n let index = this.#pairedDevice.indexes[normalizedAddress];\n if (index === undefined) {\n for (let i = 0; i < MAX_INDEX; i++) {\n const derivedAddress = this.addressFromIndex(i);\n if (derivedAddress === normalizedAddress) {\n index = i;\n break;\n }\n }\n if (index === undefined) {\n throw new Error(`Unknown address ${normalizedAddress}`);\n }\n }\n\n return `${this.#pairedDevice.hdPath}/${this.#pairedDevice.childrenPath\n .replace('*', index.toString())\n .replace(/\\*/gu, '0')}`;\n }\n\n /**\n * Get a page of addresses derived from the source.\n *\n * @param page - The page number to retrieve\n * @param pageSize - The number of addresses per page\n * @returns An array of IndexedAddress objects, each containing the address and its index\n * @throws Will throw an error if the source is not initialized\n */\n getAddressesPage(page: number, pageSize = 5): IndexedAddress[] {\n const startIndex = page * pageSize;\n const endIndex = startIndex + pageSize;\n const addresses: IndexedAddress[] = [];\n\n for (let i = startIndex; i < endIndex; i++) {\n const address = this.addressFromIndex(i);\n addresses.push({ address, index: i });\n }\n\n return addresses;\n }\n\n /**\n * Retrieve the details of the paired device.\n *\n * @returns Thea paired device details\n */\n getDeviceDetails(): DeviceDetails {\n return this.#pairedDevice;\n }\n\n /**\n * Sign a transaction. This is equivalent to the `eth_signTransaction`\n * Ethereum JSON-RPC method. See the Ethereum JSON-RPC API documentation for\n * more details.\n *\n * @param address - The address of the account to use for signing.\n * @param transaction - The transaction to sign.\n * @returns The signed transaction.\n */\n async signTransaction(\n address: Hex,\n transaction: TypedTransaction,\n ): Promise<TypedTxData> {\n const dataType =\n transaction.type === TransactionType.Legacy\n ? DataType.transaction\n : DataType.typedTransaction;\n\n const messageToSign = Buffer.from(\n transaction.type === TransactionType.Legacy\n ? RLP.encode(transaction.getMessageToSign())\n : (transaction as FeeMarketEIP1559Transaction).getMessageToSign(),\n );\n\n const requestId = uuidv4();\n const ethSignRequestUR = EthSignRequest.constructETHRequest(\n messageToSign,\n dataType,\n this.pathFromAddress(address),\n this.#pairedDevice.xfp,\n requestId,\n Number(transaction.common.chainId()),\n ).toUR();\n\n const { r, s, v } = await this.#requestSignature({\n requestId,\n payload: {\n type: ethSignRequestUR.type,\n cbor: ethSignRequestUR.cbor.toString('hex'),\n },\n requestTitle: 'Scan with your hardware wallet',\n requestDescription:\n 'After your device has signed this message, click on \"Scan\" to receive the signature',\n });\n\n return TransactionFactory.fromTxData(\n {\n ...transaction.toJSON(),\n r,\n s,\n v,\n },\n {\n common: transaction.common,\n },\n );\n }\n\n /**\n * Sign a message. This is equivalent to the `eth_signTypedData` v4 Ethereum\n * JSON-RPC method.\n *\n * @param address - The address of the account to use for signing.\n * @param data - The data to sign.\n * @returns The signed message.\n */\n async signTypedData<Types extends MessageTypes>(\n address: Hex,\n data: TypedMessage<Types>,\n ): Promise<string> {\n const requestId = uuidv4();\n const ethSignRequestUR = EthSignRequest.constructETHRequest(\n Buffer.from(JSON.stringify(data), 'utf8'),\n DataType.typedData,\n this.pathFromAddress(address),\n this.#pairedDevice.xfp,\n requestId,\n undefined,\n address,\n ).toUR();\n\n const { r, s, v } = await this.#requestSignature({\n requestId,\n payload: {\n type: ethSignRequestUR.type,\n cbor: ethSignRequestUR.cbor.toString('hex'),\n },\n });\n\n return add0x(\n Buffer.concat([\n Uint8Array.from(r),\n Uint8Array.from(s),\n Uint8Array.from(v),\n ]).toString('hex'),\n );\n }\n\n /**\n * Sign a message. This is equivalent to the `eth_sign` Ethereum JSON-RPC\n * method, which is exposed by MetaMask as the method `personal_sign`. See\n * the Ethereum JSON-RPC API documentation for more details.\n *\n * For more information about this method and why we call it `personal_sign`,\n * see the {@link https://docs.metamask.io/guide/signing-data.html|MetaMask Docs}.\n *\n * @param address - The address of the account to use for signing.\n * @param message - The message to sign.\n * @returns The signed message.\n */\n async signPersonalMessage(address: Hex, message: Hex): Promise<string> {\n const requestId = uuidv4();\n const ethSignRequestUR = EthSignRequest.constructETHRequest(\n Buffer.from(remove0x(message), 'hex'),\n DataType.personalMessage,\n this.pathFromAddress(address),\n this.#pairedDevice.xfp,\n requestId,\n undefined,\n address,\n ).toUR();\n\n const { r, s, v } = await this.#requestSignature({\n requestId,\n payload: {\n type: ethSignRequestUR.type,\n cbor: ethSignRequestUR.cbor.toString('hex'),\n },\n });\n\n return add0x(\n Buffer.concat([\n Uint8Array.from(r),\n Uint8Array.from(s),\n Uint8Array.from(v),\n ]).toString('hex'),\n );\n }\n\n /**\n * Derive the device details from a UR string\n *\n * @param ur - The UR string to set the root account from\n * @returns The device details derived from the UR\n */\n #deviceDetailsFromUR(ur: string | SerializedUR): DeviceDetails {\n const source = this.#decodeUR(ur);\n const fingerprint = getFingerprintFromSource(source);\n\n if (source instanceof CryptoAccount) {\n const { name, xfp, paths, keyringAccount } =\n readCryptoAccountOutputDescriptors(source);\n return {\n keyringMode: DeviceMode.ACCOUNT,\n keyringAccount,\n name,\n xfp,\n paths,\n indexes: {},\n };\n }\n\n const { getBip32Key, getOrigin, getChildren, getName, getNote } = source;\n return {\n keyringMode: DeviceMode.HD,\n keyringAccount: getNote(),\n name: getName(),\n xfp: fingerprint,\n hdPath: `m/${getOrigin().getPath()}`,\n childrenPath: getChildren()?.getPath() || DEFAULT_CHILDREN_PATH,\n xpub: getBip32Key(),\n indexes: {},\n };\n }\n\n /**\n * Request a signature for a transaction or message.\n *\n * @param request - The signature request containing the data to sign.\n * @returns The signature as an object containing r, s, and v values.\n */\n async #requestSignature(\n request: QrSignatureRequest,\n ): Promise<{ r: Buffer; s: Buffer; v: Buffer }> {\n const response = await this.#requestScan({\n type: QrScanRequestType.SIGN,\n request,\n });\n const signatureEnvelope = ETHSignature.fromCBOR(\n Buffer.from(response.cbor, 'hex'),\n );\n const signature = signatureEnvelope.getSignature();\n const requestId = signatureEnvelope.getRequestId();\n\n if (!requestId) {\n throw new Error('Signature request ID is missing.');\n }\n\n if (request.requestId !== stringify(requestId)) {\n throw new Error(\n `Signature request ID mismatch. Expected: ${\n request.requestId\n }, received: ${requestId.toString('hex')}`,\n );\n }\n\n return {\n r: signature.subarray(0, 32),\n s: signature.subarray(32, 64),\n v: signature.subarray(64),\n };\n }\n\n /**\n * Decodes a UR\n *\n * @param ur - The UR to decode\n * @returns The decoded CryptoAccount or CryptoHDKey\n * @throws Will throw an error if the UR type is not supported\n */\n #decodeUR(ur: string | SerializedUR): CryptoAccount | CryptoHDKey {\n const decodedUR =\n typeof ur === 'string'\n ? URRegistryDecoder.decode(ur)\n : {\n type: ur.type,\n cbor: Buffer.from(ur.cbor, 'hex'),\n };\n\n const { type, cbor } = decodedUR;\n\n switch (type) {\n case SUPPORTED_UR_TYPE.CRYPTO_HDKEY:\n return CryptoHDKey.fromCBOR(cbor);\n case SUPPORTED_UR_TYPE.CRYPTO_ACCOUNT:\n return CryptoAccount.fromCBOR(cbor);\n default:\n throw new Error('Unsupported UR type');\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"device.cjs","sourceRoot":"","sources":["../src/device.ts"],"names":[],"mappings":"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","sourcesContent":["import { RLP } from '@ethereumjs/rlp';\nimport {\n type TypedTransaction,\n TransactionType,\n type TypedTxData,\n TransactionFactory,\n} from '@ethereumjs/tx';\nimport { publicToAddress } from '@ethereumjs/util';\nimport {\n CryptoAccount,\n CryptoHDKey,\n DataType,\n ETHSignature,\n EthSignRequest,\n URRegistryDecoder,\n} from '@keystonehq/bc-ur-registry-eth';\nimport type { MessageTypes, TypedMessage } from '@metamask/eth-sig-util';\nimport { add0x, getChecksumAddress, remove0x, type Hex } from '@metamask/utils';\n// eslint-disable-next-line @typescript-eslint/naming-convention\nimport HdKey from 'hdkey';\nimport { stringify, v4 as uuidv4 } from 'uuid';\n\nimport {\n QrScanRequestType,\n type QrKeyringBridge,\n type QrSignatureRequest,\n type SerializedUR,\n} from './qr-keyring';\n\nexport const SUPPORTED_UR_TYPE = {\n CRYPTO_HDKEY: 'crypto-hdkey',\n CRYPTO_ACCOUNT: 'crypto-account',\n ETH_SIGNATURE: 'eth-signature',\n};\n\nexport enum DeviceMode {\n HD = 'hd',\n ACCOUNT = 'account',\n}\n\nconst DEFAULT_CHILDREN_PATH = '0/*';\n\nconst MAX_INDEX = 1_000;\n\n/**\n * Common details for the device source, which can be either a CryptoAccount or CryptoHDKey.\n */\nexport type CommonDeviceDetails = {\n /**\n * Value take out from the device note field, if available.\n */\n keyringAccount: string;\n /**\n * The name of the device\n */\n name: string;\n /**\n * The device fingerprint, hex-encoded\n */\n xfp: string;\n /**\n * Indexes of the accounts derived from the device\n * in the form of a map from address to index\n */\n indexes: Record<Hex, number>;\n};\n\n/**\n * Details for the HD mode of the Device. This mode derives\n * accounts from a root public key (xpub) and a derivation path.\n */\nexport type HDModeDeviceDetails = {\n /**\n * The device mode is HD, indicating that it derives accounts from a\n * root public key (xpub) and a derivation path.\n */\n keyringMode: DeviceMode.HD;\n /**\n * The xpub of the HD key\n */\n xpub: string;\n /**\n * The derivation path of the HD key\n */\n hdPath: string;\n /**\n * The path used to derive child accounts\n */\n childrenPath: string;\n};\n\n/**\n * Details for the Account mode of the Device. This mode derives\n * accounts from a set of addresses and their corresponding paths.\n */\nexport type AccountModeDeviceDetails = {\n /**\n * The device mode is ACCOUNT, indicating that it derives accounts from\n * a set of addresses and their corresponding paths.\n */\n keyringMode: DeviceMode.ACCOUNT;\n /**\n * The derivation paths for each hex-encoded address in the device\n */\n paths: Record<Hex, string>;\n};\n\n/**\n * An address with its corresponding index.\n */\nexport type IndexedAddress = {\n address: Hex;\n index: number;\n};\n\n/**\n * The details of the source CryptoAccount or CryptoHDKey\n * that the Device uses to derive accounts.\n */\nexport type DeviceDetails = CommonDeviceDetails &\n (HDModeDeviceDetails | AccountModeDeviceDetails);\n\nexport type DeviceOptions = {\n /**\n * The requestScan function to scan the QR code\n */\n requestScan: QrKeyringBridge['requestScan'];\n /**\n * The source of the device, which can be of type `DeviceDetails`,\n * `string`, or `SerializedUR`.\n *\n * When a `string` or `SerializedUR` is provided, the Device will\n * initialize itself from the UR.\n */\n source: DeviceDetails | string | SerializedUR;\n};\n\n/**\n * Get the fingerprint of the source CryptoAccount or CryptoHDKey\n *\n * @param source - The source CryptoAccount or CryptoHDKey\n * @returns The fingerprint of the source\n */\nfunction getFingerprintFromSource(source: CryptoAccount | CryptoHDKey): string {\n return source instanceof CryptoAccount\n ? source.getMasterFingerprint()?.toString('hex')\n : source.getParentFingerprint()?.toString('hex');\n}\n\n/**\n * Get fingerprint, account paths and names from the a CryptoAccount\n *\n * Note: This function emulates the behavior of the `@keystonehq/base-eth-keyring`\n * library when dealing with CryptoAccount objects (for backwards compatibility\n * reasons). Though, the way it retrieves `name` and `keyringAccount` is questionable,\n * as `name` and `keyringAccount` are updated after each descriptor discovery, effectively\n * returning the last descriptor's `name` and `keyringAccount`.\n *\n * @param source - The source CryptoAccount\n * @returns The paths\n */\nfunction readCryptoAccountOutputDescriptors(source: CryptoAccount): {\n xfp: string;\n paths: Record<Hex, string>;\n name: string;\n keyringAccount: string;\n} {\n const descriptors = source.getOutputDescriptors();\n\n if (!descriptors || descriptors.length === 0) {\n throw new Error('No output descriptors found in CryptoAccount');\n }\n\n let name = '';\n let keyringAccount = '';\n const paths = descriptors.reduce(\n (descriptorsPaths: Record<Hex, string>, current) => {\n const hdKey = current.getHDKey();\n if (hdKey) {\n const path = `M/${hdKey.getOrigin().getPath()}`;\n const address = getChecksumAddress(\n add0x(\n Buffer.from(publicToAddress(hdKey.getKey(), true)).toString('hex'),\n ),\n );\n descriptorsPaths[address] = path;\n name = hdKey.getName();\n keyringAccount = hdKey.getNote();\n }\n return descriptorsPaths;\n },\n {},\n );\n\n return {\n paths,\n name,\n keyringAccount,\n xfp: getFingerprintFromSource(source),\n };\n}\n\nexport class Device {\n readonly #requestScan: QrKeyringBridge['requestScan'];\n\n readonly #pairedDevice: DeviceDetails;\n\n /**\n * Create a new Device instance.\n *\n * @param options - The options for the Device, including the requestScan function\n * and the source of the device details.\n * @param options.requestScan - The function to request a scan of the QR code.\n * @param options.source - The source of the device details, which can be a\n * UR string, a `SerializedUR`, or a `DeviceDetails` object.\n */\n constructor({ requestScan, source }: DeviceOptions) {\n this.#requestScan = requestScan;\n this.#pairedDevice =\n typeof source === 'string' || 'cbor' in source\n ? this.#deviceDetailsFromUR(source)\n : source;\n }\n\n /**\n * Derive an address from the source at a given index\n *\n * @param index - The index to derive the address from\n * @returns The derived address in hex format\n * @throws Will throw an error if the source is not initialized\n */\n addressFromIndex(index: number): Hex {\n if (this.#pairedDevice.keyringMode === DeviceMode.ACCOUNT) {\n const address = Object.keys(this.#pairedDevice.paths)[index];\n if (!address) {\n throw new Error(`Address not found for index ${index}`);\n }\n return add0x(address);\n }\n const childPath = `m/${this.#pairedDevice.childrenPath.replace(\n '*',\n index.toString(),\n )}`;\n\n const hdKey = HdKey.fromExtendedKey(this.#pairedDevice.xpub);\n const childKey = hdKey.derive(childPath);\n\n const address = Buffer.from(\n publicToAddress(childKey.publicKey, true),\n ).toString('hex');\n\n const normalizedAddress = getChecksumAddress(add0x(address));\n\n this.#pairedDevice.indexes[normalizedAddress] = index;\n\n return normalizedAddress;\n }\n\n /**\n * Retrieve the path of an address derived from the source.\n *\n * @param address - The address to retrieve the path for\n * @returns The path of the address\n */\n pathFromAddress(address: Hex): string {\n const normalizedAddress = getChecksumAddress(add0x(address));\n\n if (this.#pairedDevice.keyringMode === DeviceMode.ACCOUNT) {\n const path = this.#pairedDevice.paths[normalizedAddress];\n if (path === undefined) {\n throw new Error(`Unknown address ${normalizedAddress}`);\n }\n return path;\n }\n\n let index = this.#pairedDevice.indexes[normalizedAddress];\n if (index === undefined) {\n for (let i = 0; i < MAX_INDEX; i++) {\n const derivedAddress = this.addressFromIndex(i);\n if (derivedAddress === normalizedAddress) {\n index = i;\n break;\n }\n }\n if (index === undefined) {\n throw new Error(`Unknown address ${normalizedAddress}`);\n }\n }\n\n return `${this.#pairedDevice.hdPath}/${this.#pairedDevice.childrenPath\n .replace('*', index.toString())\n .replace(/\\*/gu, '0')}`;\n }\n\n /**\n * Get a page of addresses derived from the source.\n *\n * @param page - The page number to retrieve\n * @param pageSize - The number of addresses per page\n * @returns An array of IndexedAddress objects, each containing the address and its index\n * @throws Will throw an error if the source is not initialized\n */\n getAddressesPage(page: number, pageSize = 5): IndexedAddress[] {\n const startIndex = page * pageSize;\n const endIndex = startIndex + pageSize;\n const addresses: IndexedAddress[] = [];\n\n for (let i = startIndex; i < endIndex; i++) {\n const address = this.addressFromIndex(i);\n addresses.push({ address, index: i });\n }\n\n return addresses;\n }\n\n /**\n * Retrieve the details of the paired device.\n *\n * @returns Thea paired device details\n */\n getDeviceDetails(): DeviceDetails {\n return this.#pairedDevice;\n }\n\n /**\n * Sign a transaction. This is equivalent to the `eth_signTransaction`\n * Ethereum JSON-RPC method. See the Ethereum JSON-RPC API documentation for\n * more details.\n *\n * @param address - The address of the account to use for signing.\n * @param transaction - The transaction to sign.\n * @returns The signed transaction.\n */\n async signTransaction(\n address: Hex,\n transaction: TypedTransaction,\n ): Promise<TypedTxData> {\n const dataType =\n transaction.type === TransactionType.Legacy\n ? DataType.transaction\n : DataType.typedTransaction;\n\n const messageToSign = transaction.getMessageToSign();\n const rawTransaction = Buffer.from(\n Array.isArray(messageToSign) ? RLP.encode(messageToSign) : messageToSign,\n );\n\n const requestId = uuidv4();\n const ethSignRequestUR = EthSignRequest.constructETHRequest(\n rawTransaction,\n dataType,\n this.pathFromAddress(address),\n this.#pairedDevice.xfp,\n requestId,\n Number(transaction.common.chainId()),\n ).toUR();\n\n const { r, s, v } = await this.#requestSignature({\n requestId,\n payload: {\n type: ethSignRequestUR.type,\n cbor: ethSignRequestUR.cbor.toString('hex'),\n },\n requestTitle: 'Scan with your hardware wallet',\n requestDescription:\n 'After your device has signed this message, click on \"Scan\" to receive the signature',\n });\n\n return TransactionFactory.fromTxData(\n {\n ...transaction.toJSON(),\n r,\n s,\n v,\n },\n {\n common: transaction.common,\n },\n );\n }\n\n /**\n * Sign a message. This is equivalent to the `eth_signTypedData` v4 Ethereum\n * JSON-RPC method.\n *\n * @param address - The address of the account to use for signing.\n * @param data - The data to sign.\n * @returns The signed message.\n */\n async signTypedData<Types extends MessageTypes>(\n address: Hex,\n data: TypedMessage<Types>,\n ): Promise<string> {\n const requestId = uuidv4();\n const ethSignRequestUR = EthSignRequest.constructETHRequest(\n Buffer.from(JSON.stringify(data), 'utf8'),\n DataType.typedData,\n this.pathFromAddress(address),\n this.#pairedDevice.xfp,\n requestId,\n undefined,\n address,\n ).toUR();\n\n const { r, s, v } = await this.#requestSignature({\n requestId,\n payload: {\n type: ethSignRequestUR.type,\n cbor: ethSignRequestUR.cbor.toString('hex'),\n },\n });\n\n return add0x(\n Buffer.concat([\n Uint8Array.from(r),\n Uint8Array.from(s),\n Uint8Array.from(v),\n ]).toString('hex'),\n );\n }\n\n /**\n * Sign a message. This is equivalent to the `eth_sign` Ethereum JSON-RPC\n * method, which is exposed by MetaMask as the method `personal_sign`. See\n * the Ethereum JSON-RPC API documentation for more details.\n *\n * For more information about this method and why we call it `personal_sign`,\n * see the {@link https://docs.metamask.io/guide/signing-data.html|MetaMask Docs}.\n *\n * @param address - The address of the account to use for signing.\n * @param message - The message to sign.\n * @returns The signed message.\n */\n async signPersonalMessage(address: Hex, message: Hex): Promise<string> {\n const requestId = uuidv4();\n const ethSignRequestUR = EthSignRequest.constructETHRequest(\n Buffer.from(remove0x(message), 'hex'),\n DataType.personalMessage,\n this.pathFromAddress(address),\n this.#pairedDevice.xfp,\n requestId,\n undefined,\n address,\n ).toUR();\n\n const { r, s, v } = await this.#requestSignature({\n requestId,\n payload: {\n type: ethSignRequestUR.type,\n cbor: ethSignRequestUR.cbor.toString('hex'),\n },\n });\n\n return add0x(\n Buffer.concat([\n Uint8Array.from(r),\n Uint8Array.from(s),\n Uint8Array.from(v),\n ]).toString('hex'),\n );\n }\n\n /**\n * Derive the device details from a UR string\n *\n * @param ur - The UR string to set the root account from\n * @returns The device details derived from the UR\n */\n #deviceDetailsFromUR(ur: string | SerializedUR): DeviceDetails {\n const source = this.#decodeUR(ur);\n const fingerprint = getFingerprintFromSource(source);\n\n if (source instanceof CryptoAccount) {\n const { name, xfp, paths, keyringAccount } =\n readCryptoAccountOutputDescriptors(source);\n return {\n keyringMode: DeviceMode.ACCOUNT,\n keyringAccount,\n name,\n xfp,\n paths,\n indexes: {},\n };\n }\n\n const { getBip32Key, getOrigin, getChildren, getName, getNote } = source;\n return {\n keyringMode: DeviceMode.HD,\n keyringAccount: getNote(),\n name: getName(),\n xfp: fingerprint,\n hdPath: `m/${getOrigin().getPath()}`,\n childrenPath: getChildren()?.getPath() || DEFAULT_CHILDREN_PATH,\n xpub: getBip32Key(),\n indexes: {},\n };\n }\n\n /**\n * Request a signature for a transaction or message.\n *\n * @param request - The signature request containing the data to sign.\n * @returns The signature as an object containing r, s, and v values.\n */\n async #requestSignature(\n request: QrSignatureRequest,\n ): Promise<{ r: Buffer; s: Buffer; v: Buffer }> {\n const response = await this.#requestScan({\n type: QrScanRequestType.SIGN,\n request,\n });\n const signatureEnvelope = ETHSignature.fromCBOR(\n Buffer.from(response.cbor, 'hex'),\n );\n const signature = signatureEnvelope.getSignature();\n const requestId = signatureEnvelope.getRequestId();\n\n if (!requestId) {\n throw new Error('Signature request ID is missing.');\n }\n\n if (request.requestId !== stringify(requestId)) {\n throw new Error(\n `Signature request ID mismatch. Expected: ${\n request.requestId\n }, received: ${requestId.toString('hex')}`,\n );\n }\n\n return {\n r: signature.subarray(0, 32),\n s: signature.subarray(32, 64),\n v: signature.subarray(64),\n };\n }\n\n /**\n * Decodes a UR\n *\n * @param ur - The UR to decode\n * @returns The decoded CryptoAccount or CryptoHDKey\n * @throws Will throw an error if the UR type is not supported\n */\n #decodeUR(ur: string | SerializedUR): CryptoAccount | CryptoHDKey {\n const decodedUR =\n typeof ur === 'string'\n ? URRegistryDecoder.decode(ur)\n : {\n type: ur.type,\n cbor: Buffer.from(ur.cbor, 'hex'),\n };\n\n const { type, cbor } = decodedUR;\n\n switch (type) {\n case SUPPORTED_UR_TYPE.CRYPTO_HDKEY:\n return CryptoHDKey.fromCBOR(cbor);\n case SUPPORTED_UR_TYPE.CRYPTO_ACCOUNT:\n return CryptoAccount.fromCBOR(cbor);\n default:\n throw new Error('Unsupported UR type');\n }\n }\n}\n"]}
|
package/dist/device.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"device.d.cts","sourceRoot":"","sources":["../src/device.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,gBAAgB,EAErB,KAAK,WAAW,
|
|
1
|
+
{"version":3,"file":"device.d.cts","sourceRoot":"","sources":["../src/device.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,gBAAgB,EAErB,KAAK,WAAW,EAEjB,uBAAuB;AAUxB,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,+BAA+B;AACzE,OAAO,EAAuC,KAAK,GAAG,EAAE,wBAAwB;AAKhF,OAAO,EAEL,KAAK,eAAe,EAEpB,KAAK,YAAY,EAClB,yBAAqB;AAEtB,eAAO,MAAM,iBAAiB;;;;CAI7B,CAAC;AAEF,oBAAY,UAAU;IACpB,EAAE,OAAO;IACT,OAAO,YAAY;CACpB;AAMD;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC;;OAEG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;CAC9B,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC;;;OAGG;IACH,WAAW,EAAE,UAAU,CAAC,EAAE,CAAC;IAC3B;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC;;;OAGG;IACH,WAAW,EAAE,UAAU,CAAC,OAAO,CAAC;IAChC;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;CAC5B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,EAAE,GAAG,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,mBAAmB,GAC7C,CAAC,mBAAmB,GAAG,wBAAwB,CAAC,CAAC;AAEnD,MAAM,MAAM,aAAa,GAAG;IAC1B;;OAEG;IACH,WAAW,EAAE,eAAe,CAAC,aAAa,CAAC,CAAC;IAC5C;;;;;;OAMG;IACH,MAAM,EAAE,aAAa,GAAG,MAAM,GAAG,YAAY,CAAC;CAC/C,CAAC;AAmEF,qBAAa,MAAM;;IAKjB;;;;;;;;OAQG;gBACS,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,aAAa;IAQlD;;;;;;OAMG;IACH,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG;IA2BpC;;;;;OAKG;IACH,eAAe,CAAC,OAAO,EAAE,GAAG,GAAG,MAAM;IA8BrC;;;;;;;OAOG;IACH,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,SAAI,GAAG,cAAc,EAAE;IAa9D;;;;OAIG;IACH,gBAAgB,IAAI,aAAa;IAIjC;;;;;;;;OAQG;IACG,eAAe,CACnB,OAAO,EAAE,GAAG,EACZ,WAAW,EAAE,gBAAgB,GAC5B,OAAO,CAAC,WAAW,CAAC;IA6CvB;;;;;;;OAOG;IACG,aAAa,CAAC,KAAK,SAAS,YAAY,EAC5C,OAAO,EAAE,GAAG,EACZ,IAAI,EAAE,YAAY,CAAC,KAAK,CAAC,GACxB,OAAO,CAAC,MAAM,CAAC;IA6BlB;;;;;;;;;;;OAWG;IACG,mBAAmB,CAAC,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC;CAkIvE"}
|
package/dist/device.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"device.d.mts","sourceRoot":"","sources":["../src/device.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,gBAAgB,EAErB,KAAK,WAAW,
|
|
1
|
+
{"version":3,"file":"device.d.mts","sourceRoot":"","sources":["../src/device.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,gBAAgB,EAErB,KAAK,WAAW,EAEjB,uBAAuB;AAUxB,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,+BAA+B;AACzE,OAAO,EAAuC,KAAK,GAAG,EAAE,wBAAwB;AAKhF,OAAO,EAEL,KAAK,eAAe,EAEpB,KAAK,YAAY,EAClB,yBAAqB;AAEtB,eAAO,MAAM,iBAAiB;;;;CAI7B,CAAC;AAEF,oBAAY,UAAU;IACpB,EAAE,OAAO;IACT,OAAO,YAAY;CACpB;AAMD;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC;;OAEG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;CAC9B,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC;;;OAGG;IACH,WAAW,EAAE,UAAU,CAAC,EAAE,CAAC;IAC3B;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC;;;OAGG;IACH,WAAW,EAAE,UAAU,CAAC,OAAO,CAAC;IAChC;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;CAC5B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,EAAE,GAAG,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,mBAAmB,GAC7C,CAAC,mBAAmB,GAAG,wBAAwB,CAAC,CAAC;AAEnD,MAAM,MAAM,aAAa,GAAG;IAC1B;;OAEG;IACH,WAAW,EAAE,eAAe,CAAC,aAAa,CAAC,CAAC;IAC5C;;;;;;OAMG;IACH,MAAM,EAAE,aAAa,GAAG,MAAM,GAAG,YAAY,CAAC;CAC/C,CAAC;AAmEF,qBAAa,MAAM;;IAKjB;;;;;;;;OAQG;gBACS,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,aAAa;IAQlD;;;;;;OAMG;IACH,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG;IA2BpC;;;;;OAKG;IACH,eAAe,CAAC,OAAO,EAAE,GAAG,GAAG,MAAM;IA8BrC;;;;;;;OAOG;IACH,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,SAAI,GAAG,cAAc,EAAE;IAa9D;;;;OAIG;IACH,gBAAgB,IAAI,aAAa;IAIjC;;;;;;;;OAQG;IACG,eAAe,CACnB,OAAO,EAAE,GAAG,EACZ,WAAW,EAAE,gBAAgB,GAC5B,OAAO,CAAC,WAAW,CAAC;IA6CvB;;;;;;;OAOG;IACG,aAAa,CAAC,KAAK,SAAS,YAAY,EAC5C,OAAO,EAAE,GAAG,EACZ,IAAI,EAAE,YAAY,CAAC,KAAK,CAAC,GACxB,OAAO,CAAC,MAAM,CAAC;IA6BlB;;;;;;;;;;;OAWG;IACG,mBAAmB,CAAC,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC;CAkIvE"}
|
package/dist/device.mjs
CHANGED
|
@@ -199,11 +199,10 @@ export class Device {
|
|
|
199
199
|
const dataType = transaction.type === TransactionType.Legacy
|
|
200
200
|
? DataType.transaction
|
|
201
201
|
: DataType.typedTransaction;
|
|
202
|
-
const messageToSign =
|
|
203
|
-
|
|
204
|
-
: transaction.getMessageToSign());
|
|
202
|
+
const messageToSign = transaction.getMessageToSign();
|
|
203
|
+
const rawTransaction = Buffer.from(Array.isArray(messageToSign) ? RLP.encode(messageToSign) : messageToSign);
|
|
205
204
|
const requestId = uuidv4();
|
|
206
|
-
const ethSignRequestUR = EthSignRequest.constructETHRequest(
|
|
205
|
+
const ethSignRequestUR = EthSignRequest.constructETHRequest(rawTransaction, dataType, this.pathFromAddress(address), __classPrivateFieldGet(this, _Device_pairedDevice, "f").xfp, requestId, Number(transaction.common.chainId())).toUR();
|
|
207
206
|
const { r, s, v } = await __classPrivateFieldGet(this, _Device_instances, "m", _Device_requestSignature).call(this, {
|
|
208
207
|
requestId,
|
|
209
208
|
payload: {
|
package/dist/device.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"device.mjs","sourceRoot":"","sources":["../src/device.ts"],"names":[],"mappings":"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","sourcesContent":["import { RLP } from '@ethereumjs/rlp';\nimport {\n type TypedTransaction,\n TransactionType,\n type TypedTxData,\n type FeeMarketEIP1559Transaction,\n TransactionFactory,\n} from '@ethereumjs/tx';\nimport { publicToAddress } from '@ethereumjs/util';\nimport {\n CryptoAccount,\n CryptoHDKey,\n DataType,\n ETHSignature,\n EthSignRequest,\n URRegistryDecoder,\n} from '@keystonehq/bc-ur-registry-eth';\nimport type { MessageTypes, TypedMessage } from '@metamask/eth-sig-util';\nimport { add0x, getChecksumAddress, remove0x, type Hex } from '@metamask/utils';\n// eslint-disable-next-line @typescript-eslint/naming-convention\nimport HdKey from 'hdkey';\nimport { stringify, v4 as uuidv4 } from 'uuid';\n\nimport {\n QrScanRequestType,\n type QrKeyringBridge,\n type QrSignatureRequest,\n type SerializedUR,\n} from './qr-keyring';\n\nexport const SUPPORTED_UR_TYPE = {\n CRYPTO_HDKEY: 'crypto-hdkey',\n CRYPTO_ACCOUNT: 'crypto-account',\n ETH_SIGNATURE: 'eth-signature',\n};\n\nexport enum DeviceMode {\n HD = 'hd',\n ACCOUNT = 'account',\n}\n\nconst DEFAULT_CHILDREN_PATH = '0/*';\n\nconst MAX_INDEX = 1_000;\n\n/**\n * Common details for the device source, which can be either a CryptoAccount or CryptoHDKey.\n */\nexport type CommonDeviceDetails = {\n /**\n * Value take out from the device note field, if available.\n */\n keyringAccount: string;\n /**\n * The name of the device\n */\n name: string;\n /**\n * The device fingerprint, hex-encoded\n */\n xfp: string;\n /**\n * Indexes of the accounts derived from the device\n * in the form of a map from address to index\n */\n indexes: Record<Hex, number>;\n};\n\n/**\n * Details for the HD mode of the Device. This mode derives\n * accounts from a root public key (xpub) and a derivation path.\n */\nexport type HDModeDeviceDetails = {\n /**\n * The device mode is HD, indicating that it derives accounts from a\n * root public key (xpub) and a derivation path.\n */\n keyringMode: DeviceMode.HD;\n /**\n * The xpub of the HD key\n */\n xpub: string;\n /**\n * The derivation path of the HD key\n */\n hdPath: string;\n /**\n * The path used to derive child accounts\n */\n childrenPath: string;\n};\n\n/**\n * Details for the Account mode of the Device. This mode derives\n * accounts from a set of addresses and their corresponding paths.\n */\nexport type AccountModeDeviceDetails = {\n /**\n * The device mode is ACCOUNT, indicating that it derives accounts from\n * a set of addresses and their corresponding paths.\n */\n keyringMode: DeviceMode.ACCOUNT;\n /**\n * The derivation paths for each hex-encoded address in the device\n */\n paths: Record<Hex, string>;\n};\n\n/**\n * An address with its corresponding index.\n */\nexport type IndexedAddress = {\n address: Hex;\n index: number;\n};\n\n/**\n * The details of the source CryptoAccount or CryptoHDKey\n * that the Device uses to derive accounts.\n */\nexport type DeviceDetails = CommonDeviceDetails &\n (HDModeDeviceDetails | AccountModeDeviceDetails);\n\nexport type DeviceOptions = {\n /**\n * The requestScan function to scan the QR code\n */\n requestScan: QrKeyringBridge['requestScan'];\n /**\n * The source of the device, which can be of type `DeviceDetails`,\n * `string`, or `SerializedUR`.\n *\n * When a `string` or `SerializedUR` is provided, the Device will\n * initialize itself from the UR.\n */\n source: DeviceDetails | string | SerializedUR;\n};\n\n/**\n * Get the fingerprint of the source CryptoAccount or CryptoHDKey\n *\n * @param source - The source CryptoAccount or CryptoHDKey\n * @returns The fingerprint of the source\n */\nfunction getFingerprintFromSource(source: CryptoAccount | CryptoHDKey): string {\n return source instanceof CryptoAccount\n ? source.getMasterFingerprint()?.toString('hex')\n : source.getParentFingerprint()?.toString('hex');\n}\n\n/**\n * Get fingerprint, account paths and names from the a CryptoAccount\n *\n * Note: This function emulates the behavior of the `@keystonehq/base-eth-keyring`\n * library when dealing with CryptoAccount objects (for backwards compatibility\n * reasons). Though, the way it retrieves `name` and `keyringAccount` is questionable,\n * as `name` and `keyringAccount` are updated after each descriptor discovery, effectively\n * returning the last descriptor's `name` and `keyringAccount`.\n *\n * @param source - The source CryptoAccount\n * @returns The paths\n */\nfunction readCryptoAccountOutputDescriptors(source: CryptoAccount): {\n xfp: string;\n paths: Record<Hex, string>;\n name: string;\n keyringAccount: string;\n} {\n const descriptors = source.getOutputDescriptors();\n\n if (!descriptors || descriptors.length === 0) {\n throw new Error('No output descriptors found in CryptoAccount');\n }\n\n let name = '';\n let keyringAccount = '';\n const paths = descriptors.reduce(\n (descriptorsPaths: Record<Hex, string>, current) => {\n const hdKey = current.getHDKey();\n if (hdKey) {\n const path = `M/${hdKey.getOrigin().getPath()}`;\n const address = getChecksumAddress(\n add0x(\n Buffer.from(publicToAddress(hdKey.getKey(), true)).toString('hex'),\n ),\n );\n descriptorsPaths[address] = path;\n name = hdKey.getName();\n keyringAccount = hdKey.getNote();\n }\n return descriptorsPaths;\n },\n {},\n );\n\n return {\n paths,\n name,\n keyringAccount,\n xfp: getFingerprintFromSource(source),\n };\n}\n\nexport class Device {\n readonly #requestScan: QrKeyringBridge['requestScan'];\n\n readonly #pairedDevice: DeviceDetails;\n\n /**\n * Create a new Device instance.\n *\n * @param options - The options for the Device, including the requestScan function\n * and the source of the device details.\n * @param options.requestScan - The function to request a scan of the QR code.\n * @param options.source - The source of the device details, which can be a\n * UR string, a `SerializedUR`, or a `DeviceDetails` object.\n */\n constructor({ requestScan, source }: DeviceOptions) {\n this.#requestScan = requestScan;\n this.#pairedDevice =\n typeof source === 'string' || 'cbor' in source\n ? this.#deviceDetailsFromUR(source)\n : source;\n }\n\n /**\n * Derive an address from the source at a given index\n *\n * @param index - The index to derive the address from\n * @returns The derived address in hex format\n * @throws Will throw an error if the source is not initialized\n */\n addressFromIndex(index: number): Hex {\n if (this.#pairedDevice.keyringMode === DeviceMode.ACCOUNT) {\n const address = Object.keys(this.#pairedDevice.paths)[index];\n if (!address) {\n throw new Error(`Address not found for index ${index}`);\n }\n return add0x(address);\n }\n const childPath = `m/${this.#pairedDevice.childrenPath.replace(\n '*',\n index.toString(),\n )}`;\n\n const hdKey = HdKey.fromExtendedKey(this.#pairedDevice.xpub);\n const childKey = hdKey.derive(childPath);\n\n const address = Buffer.from(\n publicToAddress(childKey.publicKey, true),\n ).toString('hex');\n\n const normalizedAddress = getChecksumAddress(add0x(address));\n\n this.#pairedDevice.indexes[normalizedAddress] = index;\n\n return normalizedAddress;\n }\n\n /**\n * Retrieve the path of an address derived from the source.\n *\n * @param address - The address to retrieve the path for\n * @returns The path of the address\n */\n pathFromAddress(address: Hex): string {\n const normalizedAddress = getChecksumAddress(add0x(address));\n\n if (this.#pairedDevice.keyringMode === DeviceMode.ACCOUNT) {\n const path = this.#pairedDevice.paths[normalizedAddress];\n if (path === undefined) {\n throw new Error(`Unknown address ${normalizedAddress}`);\n }\n return path;\n }\n\n let index = this.#pairedDevice.indexes[normalizedAddress];\n if (index === undefined) {\n for (let i = 0; i < MAX_INDEX; i++) {\n const derivedAddress = this.addressFromIndex(i);\n if (derivedAddress === normalizedAddress) {\n index = i;\n break;\n }\n }\n if (index === undefined) {\n throw new Error(`Unknown address ${normalizedAddress}`);\n }\n }\n\n return `${this.#pairedDevice.hdPath}/${this.#pairedDevice.childrenPath\n .replace('*', index.toString())\n .replace(/\\*/gu, '0')}`;\n }\n\n /**\n * Get a page of addresses derived from the source.\n *\n * @param page - The page number to retrieve\n * @param pageSize - The number of addresses per page\n * @returns An array of IndexedAddress objects, each containing the address and its index\n * @throws Will throw an error if the source is not initialized\n */\n getAddressesPage(page: number, pageSize = 5): IndexedAddress[] {\n const startIndex = page * pageSize;\n const endIndex = startIndex + pageSize;\n const addresses: IndexedAddress[] = [];\n\n for (let i = startIndex; i < endIndex; i++) {\n const address = this.addressFromIndex(i);\n addresses.push({ address, index: i });\n }\n\n return addresses;\n }\n\n /**\n * Retrieve the details of the paired device.\n *\n * @returns Thea paired device details\n */\n getDeviceDetails(): DeviceDetails {\n return this.#pairedDevice;\n }\n\n /**\n * Sign a transaction. This is equivalent to the `eth_signTransaction`\n * Ethereum JSON-RPC method. See the Ethereum JSON-RPC API documentation for\n * more details.\n *\n * @param address - The address of the account to use for signing.\n * @param transaction - The transaction to sign.\n * @returns The signed transaction.\n */\n async signTransaction(\n address: Hex,\n transaction: TypedTransaction,\n ): Promise<TypedTxData> {\n const dataType =\n transaction.type === TransactionType.Legacy\n ? DataType.transaction\n : DataType.typedTransaction;\n\n const messageToSign = Buffer.from(\n transaction.type === TransactionType.Legacy\n ? RLP.encode(transaction.getMessageToSign())\n : (transaction as FeeMarketEIP1559Transaction).getMessageToSign(),\n );\n\n const requestId = uuidv4();\n const ethSignRequestUR = EthSignRequest.constructETHRequest(\n messageToSign,\n dataType,\n this.pathFromAddress(address),\n this.#pairedDevice.xfp,\n requestId,\n Number(transaction.common.chainId()),\n ).toUR();\n\n const { r, s, v } = await this.#requestSignature({\n requestId,\n payload: {\n type: ethSignRequestUR.type,\n cbor: ethSignRequestUR.cbor.toString('hex'),\n },\n requestTitle: 'Scan with your hardware wallet',\n requestDescription:\n 'After your device has signed this message, click on \"Scan\" to receive the signature',\n });\n\n return TransactionFactory.fromTxData(\n {\n ...transaction.toJSON(),\n r,\n s,\n v,\n },\n {\n common: transaction.common,\n },\n );\n }\n\n /**\n * Sign a message. This is equivalent to the `eth_signTypedData` v4 Ethereum\n * JSON-RPC method.\n *\n * @param address - The address of the account to use for signing.\n * @param data - The data to sign.\n * @returns The signed message.\n */\n async signTypedData<Types extends MessageTypes>(\n address: Hex,\n data: TypedMessage<Types>,\n ): Promise<string> {\n const requestId = uuidv4();\n const ethSignRequestUR = EthSignRequest.constructETHRequest(\n Buffer.from(JSON.stringify(data), 'utf8'),\n DataType.typedData,\n this.pathFromAddress(address),\n this.#pairedDevice.xfp,\n requestId,\n undefined,\n address,\n ).toUR();\n\n const { r, s, v } = await this.#requestSignature({\n requestId,\n payload: {\n type: ethSignRequestUR.type,\n cbor: ethSignRequestUR.cbor.toString('hex'),\n },\n });\n\n return add0x(\n Buffer.concat([\n Uint8Array.from(r),\n Uint8Array.from(s),\n Uint8Array.from(v),\n ]).toString('hex'),\n );\n }\n\n /**\n * Sign a message. This is equivalent to the `eth_sign` Ethereum JSON-RPC\n * method, which is exposed by MetaMask as the method `personal_sign`. See\n * the Ethereum JSON-RPC API documentation for more details.\n *\n * For more information about this method and why we call it `personal_sign`,\n * see the {@link https://docs.metamask.io/guide/signing-data.html|MetaMask Docs}.\n *\n * @param address - The address of the account to use for signing.\n * @param message - The message to sign.\n * @returns The signed message.\n */\n async signPersonalMessage(address: Hex, message: Hex): Promise<string> {\n const requestId = uuidv4();\n const ethSignRequestUR = EthSignRequest.constructETHRequest(\n Buffer.from(remove0x(message), 'hex'),\n DataType.personalMessage,\n this.pathFromAddress(address),\n this.#pairedDevice.xfp,\n requestId,\n undefined,\n address,\n ).toUR();\n\n const { r, s, v } = await this.#requestSignature({\n requestId,\n payload: {\n type: ethSignRequestUR.type,\n cbor: ethSignRequestUR.cbor.toString('hex'),\n },\n });\n\n return add0x(\n Buffer.concat([\n Uint8Array.from(r),\n Uint8Array.from(s),\n Uint8Array.from(v),\n ]).toString('hex'),\n );\n }\n\n /**\n * Derive the device details from a UR string\n *\n * @param ur - The UR string to set the root account from\n * @returns The device details derived from the UR\n */\n #deviceDetailsFromUR(ur: string | SerializedUR): DeviceDetails {\n const source = this.#decodeUR(ur);\n const fingerprint = getFingerprintFromSource(source);\n\n if (source instanceof CryptoAccount) {\n const { name, xfp, paths, keyringAccount } =\n readCryptoAccountOutputDescriptors(source);\n return {\n keyringMode: DeviceMode.ACCOUNT,\n keyringAccount,\n name,\n xfp,\n paths,\n indexes: {},\n };\n }\n\n const { getBip32Key, getOrigin, getChildren, getName, getNote } = source;\n return {\n keyringMode: DeviceMode.HD,\n keyringAccount: getNote(),\n name: getName(),\n xfp: fingerprint,\n hdPath: `m/${getOrigin().getPath()}`,\n childrenPath: getChildren()?.getPath() || DEFAULT_CHILDREN_PATH,\n xpub: getBip32Key(),\n indexes: {},\n };\n }\n\n /**\n * Request a signature for a transaction or message.\n *\n * @param request - The signature request containing the data to sign.\n * @returns The signature as an object containing r, s, and v values.\n */\n async #requestSignature(\n request: QrSignatureRequest,\n ): Promise<{ r: Buffer; s: Buffer; v: Buffer }> {\n const response = await this.#requestScan({\n type: QrScanRequestType.SIGN,\n request,\n });\n const signatureEnvelope = ETHSignature.fromCBOR(\n Buffer.from(response.cbor, 'hex'),\n );\n const signature = signatureEnvelope.getSignature();\n const requestId = signatureEnvelope.getRequestId();\n\n if (!requestId) {\n throw new Error('Signature request ID is missing.');\n }\n\n if (request.requestId !== stringify(requestId)) {\n throw new Error(\n `Signature request ID mismatch. Expected: ${\n request.requestId\n }, received: ${requestId.toString('hex')}`,\n );\n }\n\n return {\n r: signature.subarray(0, 32),\n s: signature.subarray(32, 64),\n v: signature.subarray(64),\n };\n }\n\n /**\n * Decodes a UR\n *\n * @param ur - The UR to decode\n * @returns The decoded CryptoAccount or CryptoHDKey\n * @throws Will throw an error if the UR type is not supported\n */\n #decodeUR(ur: string | SerializedUR): CryptoAccount | CryptoHDKey {\n const decodedUR =\n typeof ur === 'string'\n ? URRegistryDecoder.decode(ur)\n : {\n type: ur.type,\n cbor: Buffer.from(ur.cbor, 'hex'),\n };\n\n const { type, cbor } = decodedUR;\n\n switch (type) {\n case SUPPORTED_UR_TYPE.CRYPTO_HDKEY:\n return CryptoHDKey.fromCBOR(cbor);\n case SUPPORTED_UR_TYPE.CRYPTO_ACCOUNT:\n return CryptoAccount.fromCBOR(cbor);\n default:\n throw new Error('Unsupported UR type');\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"device.mjs","sourceRoot":"","sources":["../src/device.ts"],"names":[],"mappings":"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","sourcesContent":["import { RLP } from '@ethereumjs/rlp';\nimport {\n type TypedTransaction,\n TransactionType,\n type TypedTxData,\n TransactionFactory,\n} from '@ethereumjs/tx';\nimport { publicToAddress } from '@ethereumjs/util';\nimport {\n CryptoAccount,\n CryptoHDKey,\n DataType,\n ETHSignature,\n EthSignRequest,\n URRegistryDecoder,\n} from '@keystonehq/bc-ur-registry-eth';\nimport type { MessageTypes, TypedMessage } from '@metamask/eth-sig-util';\nimport { add0x, getChecksumAddress, remove0x, type Hex } from '@metamask/utils';\n// eslint-disable-next-line @typescript-eslint/naming-convention\nimport HdKey from 'hdkey';\nimport { stringify, v4 as uuidv4 } from 'uuid';\n\nimport {\n QrScanRequestType,\n type QrKeyringBridge,\n type QrSignatureRequest,\n type SerializedUR,\n} from './qr-keyring';\n\nexport const SUPPORTED_UR_TYPE = {\n CRYPTO_HDKEY: 'crypto-hdkey',\n CRYPTO_ACCOUNT: 'crypto-account',\n ETH_SIGNATURE: 'eth-signature',\n};\n\nexport enum DeviceMode {\n HD = 'hd',\n ACCOUNT = 'account',\n}\n\nconst DEFAULT_CHILDREN_PATH = '0/*';\n\nconst MAX_INDEX = 1_000;\n\n/**\n * Common details for the device source, which can be either a CryptoAccount or CryptoHDKey.\n */\nexport type CommonDeviceDetails = {\n /**\n * Value take out from the device note field, if available.\n */\n keyringAccount: string;\n /**\n * The name of the device\n */\n name: string;\n /**\n * The device fingerprint, hex-encoded\n */\n xfp: string;\n /**\n * Indexes of the accounts derived from the device\n * in the form of a map from address to index\n */\n indexes: Record<Hex, number>;\n};\n\n/**\n * Details for the HD mode of the Device. This mode derives\n * accounts from a root public key (xpub) and a derivation path.\n */\nexport type HDModeDeviceDetails = {\n /**\n * The device mode is HD, indicating that it derives accounts from a\n * root public key (xpub) and a derivation path.\n */\n keyringMode: DeviceMode.HD;\n /**\n * The xpub of the HD key\n */\n xpub: string;\n /**\n * The derivation path of the HD key\n */\n hdPath: string;\n /**\n * The path used to derive child accounts\n */\n childrenPath: string;\n};\n\n/**\n * Details for the Account mode of the Device. This mode derives\n * accounts from a set of addresses and their corresponding paths.\n */\nexport type AccountModeDeviceDetails = {\n /**\n * The device mode is ACCOUNT, indicating that it derives accounts from\n * a set of addresses and their corresponding paths.\n */\n keyringMode: DeviceMode.ACCOUNT;\n /**\n * The derivation paths for each hex-encoded address in the device\n */\n paths: Record<Hex, string>;\n};\n\n/**\n * An address with its corresponding index.\n */\nexport type IndexedAddress = {\n address: Hex;\n index: number;\n};\n\n/**\n * The details of the source CryptoAccount or CryptoHDKey\n * that the Device uses to derive accounts.\n */\nexport type DeviceDetails = CommonDeviceDetails &\n (HDModeDeviceDetails | AccountModeDeviceDetails);\n\nexport type DeviceOptions = {\n /**\n * The requestScan function to scan the QR code\n */\n requestScan: QrKeyringBridge['requestScan'];\n /**\n * The source of the device, which can be of type `DeviceDetails`,\n * `string`, or `SerializedUR`.\n *\n * When a `string` or `SerializedUR` is provided, the Device will\n * initialize itself from the UR.\n */\n source: DeviceDetails | string | SerializedUR;\n};\n\n/**\n * Get the fingerprint of the source CryptoAccount or CryptoHDKey\n *\n * @param source - The source CryptoAccount or CryptoHDKey\n * @returns The fingerprint of the source\n */\nfunction getFingerprintFromSource(source: CryptoAccount | CryptoHDKey): string {\n return source instanceof CryptoAccount\n ? source.getMasterFingerprint()?.toString('hex')\n : source.getParentFingerprint()?.toString('hex');\n}\n\n/**\n * Get fingerprint, account paths and names from the a CryptoAccount\n *\n * Note: This function emulates the behavior of the `@keystonehq/base-eth-keyring`\n * library when dealing with CryptoAccount objects (for backwards compatibility\n * reasons). Though, the way it retrieves `name` and `keyringAccount` is questionable,\n * as `name` and `keyringAccount` are updated after each descriptor discovery, effectively\n * returning the last descriptor's `name` and `keyringAccount`.\n *\n * @param source - The source CryptoAccount\n * @returns The paths\n */\nfunction readCryptoAccountOutputDescriptors(source: CryptoAccount): {\n xfp: string;\n paths: Record<Hex, string>;\n name: string;\n keyringAccount: string;\n} {\n const descriptors = source.getOutputDescriptors();\n\n if (!descriptors || descriptors.length === 0) {\n throw new Error('No output descriptors found in CryptoAccount');\n }\n\n let name = '';\n let keyringAccount = '';\n const paths = descriptors.reduce(\n (descriptorsPaths: Record<Hex, string>, current) => {\n const hdKey = current.getHDKey();\n if (hdKey) {\n const path = `M/${hdKey.getOrigin().getPath()}`;\n const address = getChecksumAddress(\n add0x(\n Buffer.from(publicToAddress(hdKey.getKey(), true)).toString('hex'),\n ),\n );\n descriptorsPaths[address] = path;\n name = hdKey.getName();\n keyringAccount = hdKey.getNote();\n }\n return descriptorsPaths;\n },\n {},\n );\n\n return {\n paths,\n name,\n keyringAccount,\n xfp: getFingerprintFromSource(source),\n };\n}\n\nexport class Device {\n readonly #requestScan: QrKeyringBridge['requestScan'];\n\n readonly #pairedDevice: DeviceDetails;\n\n /**\n * Create a new Device instance.\n *\n * @param options - The options for the Device, including the requestScan function\n * and the source of the device details.\n * @param options.requestScan - The function to request a scan of the QR code.\n * @param options.source - The source of the device details, which can be a\n * UR string, a `SerializedUR`, or a `DeviceDetails` object.\n */\n constructor({ requestScan, source }: DeviceOptions) {\n this.#requestScan = requestScan;\n this.#pairedDevice =\n typeof source === 'string' || 'cbor' in source\n ? this.#deviceDetailsFromUR(source)\n : source;\n }\n\n /**\n * Derive an address from the source at a given index\n *\n * @param index - The index to derive the address from\n * @returns The derived address in hex format\n * @throws Will throw an error if the source is not initialized\n */\n addressFromIndex(index: number): Hex {\n if (this.#pairedDevice.keyringMode === DeviceMode.ACCOUNT) {\n const address = Object.keys(this.#pairedDevice.paths)[index];\n if (!address) {\n throw new Error(`Address not found for index ${index}`);\n }\n return add0x(address);\n }\n const childPath = `m/${this.#pairedDevice.childrenPath.replace(\n '*',\n index.toString(),\n )}`;\n\n const hdKey = HdKey.fromExtendedKey(this.#pairedDevice.xpub);\n const childKey = hdKey.derive(childPath);\n\n const address = Buffer.from(\n publicToAddress(childKey.publicKey, true),\n ).toString('hex');\n\n const normalizedAddress = getChecksumAddress(add0x(address));\n\n this.#pairedDevice.indexes[normalizedAddress] = index;\n\n return normalizedAddress;\n }\n\n /**\n * Retrieve the path of an address derived from the source.\n *\n * @param address - The address to retrieve the path for\n * @returns The path of the address\n */\n pathFromAddress(address: Hex): string {\n const normalizedAddress = getChecksumAddress(add0x(address));\n\n if (this.#pairedDevice.keyringMode === DeviceMode.ACCOUNT) {\n const path = this.#pairedDevice.paths[normalizedAddress];\n if (path === undefined) {\n throw new Error(`Unknown address ${normalizedAddress}`);\n }\n return path;\n }\n\n let index = this.#pairedDevice.indexes[normalizedAddress];\n if (index === undefined) {\n for (let i = 0; i < MAX_INDEX; i++) {\n const derivedAddress = this.addressFromIndex(i);\n if (derivedAddress === normalizedAddress) {\n index = i;\n break;\n }\n }\n if (index === undefined) {\n throw new Error(`Unknown address ${normalizedAddress}`);\n }\n }\n\n return `${this.#pairedDevice.hdPath}/${this.#pairedDevice.childrenPath\n .replace('*', index.toString())\n .replace(/\\*/gu, '0')}`;\n }\n\n /**\n * Get a page of addresses derived from the source.\n *\n * @param page - The page number to retrieve\n * @param pageSize - The number of addresses per page\n * @returns An array of IndexedAddress objects, each containing the address and its index\n * @throws Will throw an error if the source is not initialized\n */\n getAddressesPage(page: number, pageSize = 5): IndexedAddress[] {\n const startIndex = page * pageSize;\n const endIndex = startIndex + pageSize;\n const addresses: IndexedAddress[] = [];\n\n for (let i = startIndex; i < endIndex; i++) {\n const address = this.addressFromIndex(i);\n addresses.push({ address, index: i });\n }\n\n return addresses;\n }\n\n /**\n * Retrieve the details of the paired device.\n *\n * @returns Thea paired device details\n */\n getDeviceDetails(): DeviceDetails {\n return this.#pairedDevice;\n }\n\n /**\n * Sign a transaction. This is equivalent to the `eth_signTransaction`\n * Ethereum JSON-RPC method. See the Ethereum JSON-RPC API documentation for\n * more details.\n *\n * @param address - The address of the account to use for signing.\n * @param transaction - The transaction to sign.\n * @returns The signed transaction.\n */\n async signTransaction(\n address: Hex,\n transaction: TypedTransaction,\n ): Promise<TypedTxData> {\n const dataType =\n transaction.type === TransactionType.Legacy\n ? DataType.transaction\n : DataType.typedTransaction;\n\n const messageToSign = transaction.getMessageToSign();\n const rawTransaction = Buffer.from(\n Array.isArray(messageToSign) ? RLP.encode(messageToSign) : messageToSign,\n );\n\n const requestId = uuidv4();\n const ethSignRequestUR = EthSignRequest.constructETHRequest(\n rawTransaction,\n dataType,\n this.pathFromAddress(address),\n this.#pairedDevice.xfp,\n requestId,\n Number(transaction.common.chainId()),\n ).toUR();\n\n const { r, s, v } = await this.#requestSignature({\n requestId,\n payload: {\n type: ethSignRequestUR.type,\n cbor: ethSignRequestUR.cbor.toString('hex'),\n },\n requestTitle: 'Scan with your hardware wallet',\n requestDescription:\n 'After your device has signed this message, click on \"Scan\" to receive the signature',\n });\n\n return TransactionFactory.fromTxData(\n {\n ...transaction.toJSON(),\n r,\n s,\n v,\n },\n {\n common: transaction.common,\n },\n );\n }\n\n /**\n * Sign a message. This is equivalent to the `eth_signTypedData` v4 Ethereum\n * JSON-RPC method.\n *\n * @param address - The address of the account to use for signing.\n * @param data - The data to sign.\n * @returns The signed message.\n */\n async signTypedData<Types extends MessageTypes>(\n address: Hex,\n data: TypedMessage<Types>,\n ): Promise<string> {\n const requestId = uuidv4();\n const ethSignRequestUR = EthSignRequest.constructETHRequest(\n Buffer.from(JSON.stringify(data), 'utf8'),\n DataType.typedData,\n this.pathFromAddress(address),\n this.#pairedDevice.xfp,\n requestId,\n undefined,\n address,\n ).toUR();\n\n const { r, s, v } = await this.#requestSignature({\n requestId,\n payload: {\n type: ethSignRequestUR.type,\n cbor: ethSignRequestUR.cbor.toString('hex'),\n },\n });\n\n return add0x(\n Buffer.concat([\n Uint8Array.from(r),\n Uint8Array.from(s),\n Uint8Array.from(v),\n ]).toString('hex'),\n );\n }\n\n /**\n * Sign a message. This is equivalent to the `eth_sign` Ethereum JSON-RPC\n * method, which is exposed by MetaMask as the method `personal_sign`. See\n * the Ethereum JSON-RPC API documentation for more details.\n *\n * For more information about this method and why we call it `personal_sign`,\n * see the {@link https://docs.metamask.io/guide/signing-data.html|MetaMask Docs}.\n *\n * @param address - The address of the account to use for signing.\n * @param message - The message to sign.\n * @returns The signed message.\n */\n async signPersonalMessage(address: Hex, message: Hex): Promise<string> {\n const requestId = uuidv4();\n const ethSignRequestUR = EthSignRequest.constructETHRequest(\n Buffer.from(remove0x(message), 'hex'),\n DataType.personalMessage,\n this.pathFromAddress(address),\n this.#pairedDevice.xfp,\n requestId,\n undefined,\n address,\n ).toUR();\n\n const { r, s, v } = await this.#requestSignature({\n requestId,\n payload: {\n type: ethSignRequestUR.type,\n cbor: ethSignRequestUR.cbor.toString('hex'),\n },\n });\n\n return add0x(\n Buffer.concat([\n Uint8Array.from(r),\n Uint8Array.from(s),\n Uint8Array.from(v),\n ]).toString('hex'),\n );\n }\n\n /**\n * Derive the device details from a UR string\n *\n * @param ur - The UR string to set the root account from\n * @returns The device details derived from the UR\n */\n #deviceDetailsFromUR(ur: string | SerializedUR): DeviceDetails {\n const source = this.#decodeUR(ur);\n const fingerprint = getFingerprintFromSource(source);\n\n if (source instanceof CryptoAccount) {\n const { name, xfp, paths, keyringAccount } =\n readCryptoAccountOutputDescriptors(source);\n return {\n keyringMode: DeviceMode.ACCOUNT,\n keyringAccount,\n name,\n xfp,\n paths,\n indexes: {},\n };\n }\n\n const { getBip32Key, getOrigin, getChildren, getName, getNote } = source;\n return {\n keyringMode: DeviceMode.HD,\n keyringAccount: getNote(),\n name: getName(),\n xfp: fingerprint,\n hdPath: `m/${getOrigin().getPath()}`,\n childrenPath: getChildren()?.getPath() || DEFAULT_CHILDREN_PATH,\n xpub: getBip32Key(),\n indexes: {},\n };\n }\n\n /**\n * Request a signature for a transaction or message.\n *\n * @param request - The signature request containing the data to sign.\n * @returns The signature as an object containing r, s, and v values.\n */\n async #requestSignature(\n request: QrSignatureRequest,\n ): Promise<{ r: Buffer; s: Buffer; v: Buffer }> {\n const response = await this.#requestScan({\n type: QrScanRequestType.SIGN,\n request,\n });\n const signatureEnvelope = ETHSignature.fromCBOR(\n Buffer.from(response.cbor, 'hex'),\n );\n const signature = signatureEnvelope.getSignature();\n const requestId = signatureEnvelope.getRequestId();\n\n if (!requestId) {\n throw new Error('Signature request ID is missing.');\n }\n\n if (request.requestId !== stringify(requestId)) {\n throw new Error(\n `Signature request ID mismatch. Expected: ${\n request.requestId\n }, received: ${requestId.toString('hex')}`,\n );\n }\n\n return {\n r: signature.subarray(0, 32),\n s: signature.subarray(32, 64),\n v: signature.subarray(64),\n };\n }\n\n /**\n * Decodes a UR\n *\n * @param ur - The UR to decode\n * @returns The decoded CryptoAccount or CryptoHDKey\n * @throws Will throw an error if the UR type is not supported\n */\n #decodeUR(ur: string | SerializedUR): CryptoAccount | CryptoHDKey {\n const decodedUR =\n typeof ur === 'string'\n ? URRegistryDecoder.decode(ur)\n : {\n type: ur.type,\n cbor: Buffer.from(ur.cbor, 'hex'),\n };\n\n const { type, cbor } = decodedUR;\n\n switch (type) {\n case SUPPORTED_UR_TYPE.CRYPTO_HDKEY:\n return CryptoHDKey.fromCBOR(cbor);\n case SUPPORTED_UR_TYPE.CRYPTO_ACCOUNT:\n return CryptoAccount.fromCBOR(cbor);\n default:\n throw new Error('Unsupported UR type');\n }\n }\n}\n"]}
|
package/dist/index.cjs
CHANGED
|
@@ -1,19 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
|
|
18
|
-
|
|
3
|
+
exports.QrScanRequestType = exports.QR_KEYRING_TYPE = exports.QrKeyring = exports.QrKeyringDeferredPromiseBridge = exports.QrKeyringScannerBridge = void 0;
|
|
4
|
+
var qr_keyring_scanner_bridge_1 = require("./qr-keyring-scanner-bridge.cjs");
|
|
5
|
+
Object.defineProperty(exports, "QrKeyringScannerBridge", { enumerable: true, get: function () { return qr_keyring_scanner_bridge_1.QrKeyringScannerBridge; } });
|
|
6
|
+
var qr_keyring_deferred_promise_bridge_1 = require("./qr-keyring-deferred-promise-bridge.cjs");
|
|
7
|
+
Object.defineProperty(exports, "QrKeyringDeferredPromiseBridge", { enumerable: true, get: function () { return qr_keyring_deferred_promise_bridge_1.QrKeyringDeferredPromiseBridge; } });
|
|
8
|
+
var qr_keyring_1 = require("./qr-keyring.cjs");
|
|
9
|
+
Object.defineProperty(exports, "QrKeyring", { enumerable: true, get: function () { return qr_keyring_1.QrKeyring; } });
|
|
10
|
+
Object.defineProperty(exports, "QR_KEYRING_TYPE", { enumerable: true, get: function () { return qr_keyring_1.QR_KEYRING_TYPE; } });
|
|
11
|
+
Object.defineProperty(exports, "QrScanRequestType", { enumerable: true, get: function () { return qr_keyring_1.QrScanRequestType; } });
|
|
19
12
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.cjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,6EAGqC;AAFnC,mIAAA,sBAAsB,OAAA;AAGxB,+FAG8C;AAF5C,oJAAA,8BAA8B,OAAA;AAGhC,+CASsB;AARpB,uGAAA,SAAS,OAAA;AACT,6GAAA,eAAe,OAAA;AACf,+GAAA,iBAAiB,OAAA","sourcesContent":["export {\n QrKeyringScannerBridge,\n type QrKeyringScannerBridgeOptions,\n} from './qr-keyring-scanner-bridge';\nexport {\n QrKeyringDeferredPromiseBridge,\n type QrKeyringDeferredPromiseBridgeOptions,\n} from './qr-keyring-deferred-promise-bridge';\nexport {\n QrKeyring,\n QR_KEYRING_TYPE,\n QrScanRequestType,\n type QrScanRequest,\n type QrKeyringBridge,\n type QrKeyringOptions,\n type QrSignatureRequest,\n type SerializedQrKeyringState,\n} from './qr-keyring';\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export
|
|
2
|
-
export
|
|
1
|
+
export { QrKeyringScannerBridge, type QrKeyringScannerBridgeOptions, } from "./qr-keyring-scanner-bridge.cjs";
|
|
2
|
+
export { QrKeyringDeferredPromiseBridge, type QrKeyringDeferredPromiseBridgeOptions, } from "./qr-keyring-deferred-promise-bridge.cjs";
|
|
3
|
+
export { QrKeyring, QR_KEYRING_TYPE, QrScanRequestType, type QrScanRequest, type QrKeyringBridge, type QrKeyringOptions, type QrSignatureRequest, type SerializedQrKeyringState, } from "./qr-keyring.cjs";
|
|
3
4
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,KAAK,6BAA6B,GACnC,wCAAoC;AACrC,OAAO,EACL,8BAA8B,EAC9B,KAAK,qCAAqC,GAC3C,iDAA6C;AAC9C,OAAO,EACL,SAAS,EACT,eAAe,EACf,iBAAiB,EACjB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,GAC9B,yBAAqB"}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export
|
|
2
|
-
export
|
|
1
|
+
export { QrKeyringScannerBridge, type QrKeyringScannerBridgeOptions, } from "./qr-keyring-scanner-bridge.mjs";
|
|
2
|
+
export { QrKeyringDeferredPromiseBridge, type QrKeyringDeferredPromiseBridgeOptions, } from "./qr-keyring-deferred-promise-bridge.mjs";
|
|
3
|
+
export { QrKeyring, QR_KEYRING_TYPE, QrScanRequestType, type QrScanRequest, type QrKeyringBridge, type QrKeyringOptions, type QrSignatureRequest, type SerializedQrKeyringState, } from "./qr-keyring.mjs";
|
|
3
4
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,KAAK,6BAA6B,GACnC,wCAAoC;AACrC,OAAO,EACL,8BAA8B,EAC9B,KAAK,qCAAqC,GAC3C,iDAA6C;AAC9C,OAAO,EACL,SAAS,EACT,eAAe,EACf,iBAAiB,EACjB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,GAC9B,yBAAqB"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export
|
|
2
|
-
export
|
|
1
|
+
export { QrKeyringScannerBridge } from "./qr-keyring-scanner-bridge.mjs";
|
|
2
|
+
export { QrKeyringDeferredPromiseBridge } from "./qr-keyring-deferred-promise-bridge.mjs";
|
|
3
|
+
export { QrKeyring, QR_KEYRING_TYPE, QrScanRequestType } from "./qr-keyring.mjs";
|
|
3
4
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EAEvB,wCAAoC;AACrC,OAAO,EACL,8BAA8B,EAE/B,iDAA6C;AAC9C,OAAO,EACL,SAAS,EACT,eAAe,EACf,iBAAiB,EAMlB,yBAAqB","sourcesContent":["export {\n QrKeyringScannerBridge,\n type QrKeyringScannerBridgeOptions,\n} from './qr-keyring-scanner-bridge';\nexport {\n QrKeyringDeferredPromiseBridge,\n type QrKeyringDeferredPromiseBridgeOptions,\n} from './qr-keyring-deferred-promise-bridge';\nexport {\n QrKeyring,\n QR_KEYRING_TYPE,\n QrScanRequestType,\n type QrScanRequest,\n type QrKeyringBridge,\n type QrKeyringOptions,\n type QrSignatureRequest,\n type SerializedQrKeyringState,\n} from './qr-keyring';\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qr-keyring-deferred-promise-bridge.cjs","sourceRoot":"","sources":["../src/qr-keyring-deferred-promise-bridge.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAA8E;AAC9E,6CAAoC;AA0BpC;;;GAGG;AACH,MAAa,8BAA8B;IAWzC,YAAY,EACV,eAAe,EACf,cAAc,EACd,cAAc,
|
|
1
|
+
{"version":3,"file":"qr-keyring-deferred-promise-bridge.cjs","sourceRoot":"","sources":["../src/qr-keyring-deferred-promise-bridge.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAA8E;AAC9E,6CAAoC;AA0BpC;;;GAGG;AACH,MAAa,8BAA8B;IAWzC,YAAY,EACV,eAAe,EACf,cAAc,EACd,cAAc,MAC2B,EAAE;QAdpC,+CAAQ,IAAI,mBAAK,EAAE,EAAC;QAEpB,kEAAkE;QAElE,iEAA+D;QAE/D,iEAAuD;QAEhE,8DAAoD;QAOlD,uBAAA,IAAI,mDAAoB,eAAe,MAAA,CAAC;QACxC,uBAAA,IAAI,kDAAmB,cAAc,MAAA,CAAC;QACtC,uBAAA,IAAI,kDAAmB,cAAc,MAAA,CAAC;IACxC,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,WAAW,CAAC,OAAsB;QACtC,OAAO,uBAAA,IAAI,4CAAM,CAAC,YAAY,CAAC,KAAK,IAAI,EAAE;YACxC,MAAM,eAAe,GAAG,IAAA,6BAAqB,GAAgB,CAAC;YAC9D,uBAAA,IAAI,+CAAgB,eAAe,MAAA,CAAC;YACpC,uBAAA,IAAI,uDAAiB,EAAE,KAAvB,IAAI,EAAoB,OAAO,CAAC,CAAC;YACjC,OAAO,eAAe,CAAC,OAAO,CAAC;QACjC,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;OAIG;IACH,kBAAkB,CAAC,MAAoB;QACrC,IAAI,CAAC,uBAAA,IAAI,mDAAa,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;QACjD,CAAC;QACD,uBAAA,IAAI,mDAAa,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAClC,uBAAA,IAAI,+CAAgB,IAAI,MAAA,CAAC;QACzB,uBAAA,IAAI,sDAAgB,EAAE,KAAtB,IAAI,EAAmB,MAAM,CAAC,CAAC;IACjC,CAAC;IAED;;;;OAIG;IACH,iBAAiB,CAAC,KAAY;QAC5B,IAAI,CAAC,uBAAA,IAAI,mDAAa,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAChD,CAAC;QACD,uBAAA,IAAI,mDAAa,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAChC,uBAAA,IAAI,+CAAgB,IAAI,MAAA,CAAC;QACzB,uBAAA,IAAI,sDAAgB,EAAE,KAAtB,IAAI,EAAmB,KAAK,CAAC,CAAC;IAChC,CAAC;CACF;AA/DD,wEA+DC","sourcesContent":["import { type DeferredPromise, createDeferredPromise } from '@metamask/utils';\nimport { Mutex } from 'async-mutex';\n\nimport type {\n QrKeyringBridge,\n QrScanRequest,\n SerializedUR,\n} from './qr-keyring';\n\nexport type QrKeyringDeferredPromiseBridgeOptions = {\n /**\n * Callback invoked when a scan request is made.\n * This can be used to trigger the actual scanning process.\n */\n onScanRequested?: (request: QrScanRequest) => void;\n /**\n * Callback invoked when a scan is successfully resolved.\n * This can be used to handle the result of the scan.\n */\n onScanResolved?: (result: SerializedUR) => void;\n /**\n * Callback invoked when a scan is rejected with an error.\n * This can be used to handle errors that occur during the scan.\n */\n onScanRejected?: (error: Error) => void;\n};\n\n/**\n * A bridge that turns the scan request into a deferred promise, allowing\n * the consumer to control the resolution and rejection of the scan.\n */\nexport class QrKeyringDeferredPromiseBridge implements QrKeyringBridge {\n readonly #lock = new Mutex();\n\n readonly #onScanRequested?: ((request: QrScanRequest) => void) | undefined;\n\n readonly #onScanResolved?: ((result: SerializedUR) => void) | undefined;\n\n readonly #onScanRejected?: ((error: Error) => void) | undefined;\n\n #pendingScan?: DeferredPromise<SerializedUR> | null;\n\n constructor({\n onScanRequested,\n onScanResolved,\n onScanRejected,\n }: QrKeyringDeferredPromiseBridgeOptions = {}) {\n this.#onScanRequested = onScanRequested;\n this.#onScanResolved = onScanResolved;\n this.#onScanRejected = onScanRejected;\n }\n\n /**\n * Request a QR code scan, obtaining a CBOR and a type as response.\n *\n * @param request - The type of QR scan request.\n * @returns A promise that resolves with the scanned data as a serialized UR.\n */\n async requestScan(request: QrScanRequest): Promise<SerializedUR> {\n return this.#lock.runExclusive(async () => {\n const deferredPromise = createDeferredPromise<SerializedUR>();\n this.#pendingScan = deferredPromise;\n this.#onScanRequested?.(request);\n return deferredPromise.promise;\n });\n }\n\n /**\n * Resolve the pending scan with the given result.\n *\n * @param result - The scanned data as a serialized UR.\n */\n resolvePendingScan(result: SerializedUR): void {\n if (!this.#pendingScan) {\n throw new Error('No pending scan to resolve.');\n }\n this.#pendingScan.resolve(result);\n this.#pendingScan = null;\n this.#onScanResolved?.(result);\n }\n\n /**\n * Reject the pending scan with the given error.\n *\n * @param error - The error to reject the scan with.\n */\n rejectPendingScan(error: Error): void {\n if (!this.#pendingScan) {\n throw new Error('No pending scan to reject.');\n }\n this.#pendingScan.reject(error);\n this.#pendingScan = null;\n this.#onScanRejected?.(error);\n }\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { QrKeyringBridge, QrScanRequest, SerializedUR } from "./qr-keyring.cjs";
|
|
2
|
-
export type
|
|
2
|
+
export type QrKeyringDeferredPromiseBridgeOptions = {
|
|
3
3
|
/**
|
|
4
4
|
* Callback invoked when a scan request is made.
|
|
5
5
|
* This can be used to trigger the actual scanning process.
|
|
@@ -22,7 +22,7 @@ export type QrKeyringScannerOptions = {
|
|
|
22
22
|
*/
|
|
23
23
|
export declare class QrKeyringDeferredPromiseBridge implements QrKeyringBridge {
|
|
24
24
|
#private;
|
|
25
|
-
constructor({ onScanRequested, onScanResolved, onScanRejected, }?:
|
|
25
|
+
constructor({ onScanRequested, onScanResolved, onScanRejected, }?: QrKeyringDeferredPromiseBridgeOptions);
|
|
26
26
|
/**
|
|
27
27
|
* Request a QR code scan, obtaining a CBOR and a type as response.
|
|
28
28
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qr-keyring-deferred-promise-bridge.d.cts","sourceRoot":"","sources":["../src/qr-keyring-deferred-promise-bridge.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,eAAe,EACf,aAAa,EACb,YAAY,EACb,yBAAqB;AAEtB,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"qr-keyring-deferred-promise-bridge.d.cts","sourceRoot":"","sources":["../src/qr-keyring-deferred-promise-bridge.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,eAAe,EACf,aAAa,EACb,YAAY,EACb,yBAAqB;AAEtB,MAAM,MAAM,qCAAqC,GAAG;IAClD;;;OAGG;IACH,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAC;IACnD;;;OAGG;IACH,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,CAAC;IAChD;;;OAGG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACzC,CAAC;AAEF;;;GAGG;AACH,qBAAa,8BAA+B,YAAW,eAAe;;gBAWxD,EACV,eAAe,EACf,cAAc,EACd,cAAc,GACf,GAAE,qCAA0C;IAM7C;;;;;OAKG;IACG,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IAShE;;;;OAIG;IACH,kBAAkB,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IAS9C;;;;OAIG;IACH,iBAAiB,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;CAQtC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { QrKeyringBridge, QrScanRequest, SerializedUR } from "./qr-keyring.mjs";
|
|
2
|
-
export type
|
|
2
|
+
export type QrKeyringDeferredPromiseBridgeOptions = {
|
|
3
3
|
/**
|
|
4
4
|
* Callback invoked when a scan request is made.
|
|
5
5
|
* This can be used to trigger the actual scanning process.
|
|
@@ -22,7 +22,7 @@ export type QrKeyringScannerOptions = {
|
|
|
22
22
|
*/
|
|
23
23
|
export declare class QrKeyringDeferredPromiseBridge implements QrKeyringBridge {
|
|
24
24
|
#private;
|
|
25
|
-
constructor({ onScanRequested, onScanResolved, onScanRejected, }?:
|
|
25
|
+
constructor({ onScanRequested, onScanResolved, onScanRejected, }?: QrKeyringDeferredPromiseBridgeOptions);
|
|
26
26
|
/**
|
|
27
27
|
* Request a QR code scan, obtaining a CBOR and a type as response.
|
|
28
28
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qr-keyring-deferred-promise-bridge.d.mts","sourceRoot":"","sources":["../src/qr-keyring-deferred-promise-bridge.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,eAAe,EACf,aAAa,EACb,YAAY,EACb,yBAAqB;AAEtB,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"qr-keyring-deferred-promise-bridge.d.mts","sourceRoot":"","sources":["../src/qr-keyring-deferred-promise-bridge.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,eAAe,EACf,aAAa,EACb,YAAY,EACb,yBAAqB;AAEtB,MAAM,MAAM,qCAAqC,GAAG;IAClD;;;OAGG;IACH,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAC;IACnD;;;OAGG;IACH,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,CAAC;IAChD;;;OAGG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACzC,CAAC;AAEF;;;GAGG;AACH,qBAAa,8BAA+B,YAAW,eAAe;;gBAWxD,EACV,eAAe,EACf,cAAc,EACd,cAAc,GACf,GAAE,qCAA0C;IAM7C;;;;;OAKG;IACG,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IAShE;;;;OAIG;IACH,kBAAkB,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IAS9C;;;;OAIG;IACH,iBAAiB,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;CAQtC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qr-keyring-deferred-promise-bridge.mjs","sourceRoot":"","sources":["../src/qr-keyring-deferred-promise-bridge.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,OAAO,EAAwB,qBAAqB,EAAE,wBAAwB;AAC9E,OAAO,EAAE,KAAK,EAAE,oBAAoB;AA0BpC;;;GAGG;AACH,MAAM,OAAO,8BAA8B;IAWzC,YAAY,EACV,eAAe,EACf,cAAc,EACd,cAAc,
|
|
1
|
+
{"version":3,"file":"qr-keyring-deferred-promise-bridge.mjs","sourceRoot":"","sources":["../src/qr-keyring-deferred-promise-bridge.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,OAAO,EAAwB,qBAAqB,EAAE,wBAAwB;AAC9E,OAAO,EAAE,KAAK,EAAE,oBAAoB;AA0BpC;;;GAGG;AACH,MAAM,OAAO,8BAA8B;IAWzC,YAAY,EACV,eAAe,EACf,cAAc,EACd,cAAc,MAC2B,EAAE;QAdpC,+CAAQ,IAAI,KAAK,EAAE,EAAC;QAEpB,kEAAkE;QAElE,iEAA+D;QAE/D,iEAAuD;QAEhE,8DAAoD;QAOlD,uBAAA,IAAI,mDAAoB,eAAe,MAAA,CAAC;QACxC,uBAAA,IAAI,kDAAmB,cAAc,MAAA,CAAC;QACtC,uBAAA,IAAI,kDAAmB,cAAc,MAAA,CAAC;IACxC,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,WAAW,CAAC,OAAsB;QACtC,OAAO,uBAAA,IAAI,4CAAM,CAAC,YAAY,CAAC,KAAK,IAAI,EAAE;YACxC,MAAM,eAAe,GAAG,qBAAqB,EAAgB,CAAC;YAC9D,uBAAA,IAAI,+CAAgB,eAAe,MAAA,CAAC;YACpC,uBAAA,IAAI,uDAAiB,EAAE,KAAvB,IAAI,EAAoB,OAAO,CAAC,CAAC;YACjC,OAAO,eAAe,CAAC,OAAO,CAAC;QACjC,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;OAIG;IACH,kBAAkB,CAAC,MAAoB;QACrC,IAAI,CAAC,uBAAA,IAAI,mDAAa,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;QACjD,CAAC;QACD,uBAAA,IAAI,mDAAa,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAClC,uBAAA,IAAI,+CAAgB,IAAI,MAAA,CAAC;QACzB,uBAAA,IAAI,sDAAgB,EAAE,KAAtB,IAAI,EAAmB,MAAM,CAAC,CAAC;IACjC,CAAC;IAED;;;;OAIG;IACH,iBAAiB,CAAC,KAAY;QAC5B,IAAI,CAAC,uBAAA,IAAI,mDAAa,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAChD,CAAC;QACD,uBAAA,IAAI,mDAAa,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAChC,uBAAA,IAAI,+CAAgB,IAAI,MAAA,CAAC;QACzB,uBAAA,IAAI,sDAAgB,EAAE,KAAtB,IAAI,EAAmB,KAAK,CAAC,CAAC;IAChC,CAAC;CACF","sourcesContent":["import { type DeferredPromise, createDeferredPromise } from '@metamask/utils';\nimport { Mutex } from 'async-mutex';\n\nimport type {\n QrKeyringBridge,\n QrScanRequest,\n SerializedUR,\n} from './qr-keyring';\n\nexport type QrKeyringDeferredPromiseBridgeOptions = {\n /**\n * Callback invoked when a scan request is made.\n * This can be used to trigger the actual scanning process.\n */\n onScanRequested?: (request: QrScanRequest) => void;\n /**\n * Callback invoked when a scan is successfully resolved.\n * This can be used to handle the result of the scan.\n */\n onScanResolved?: (result: SerializedUR) => void;\n /**\n * Callback invoked when a scan is rejected with an error.\n * This can be used to handle errors that occur during the scan.\n */\n onScanRejected?: (error: Error) => void;\n};\n\n/**\n * A bridge that turns the scan request into a deferred promise, allowing\n * the consumer to control the resolution and rejection of the scan.\n */\nexport class QrKeyringDeferredPromiseBridge implements QrKeyringBridge {\n readonly #lock = new Mutex();\n\n readonly #onScanRequested?: ((request: QrScanRequest) => void) | undefined;\n\n readonly #onScanResolved?: ((result: SerializedUR) => void) | undefined;\n\n readonly #onScanRejected?: ((error: Error) => void) | undefined;\n\n #pendingScan?: DeferredPromise<SerializedUR> | null;\n\n constructor({\n onScanRequested,\n onScanResolved,\n onScanRejected,\n }: QrKeyringDeferredPromiseBridgeOptions = {}) {\n this.#onScanRequested = onScanRequested;\n this.#onScanResolved = onScanResolved;\n this.#onScanRejected = onScanRejected;\n }\n\n /**\n * Request a QR code scan, obtaining a CBOR and a type as response.\n *\n * @param request - The type of QR scan request.\n * @returns A promise that resolves with the scanned data as a serialized UR.\n */\n async requestScan(request: QrScanRequest): Promise<SerializedUR> {\n return this.#lock.runExclusive(async () => {\n const deferredPromise = createDeferredPromise<SerializedUR>();\n this.#pendingScan = deferredPromise;\n this.#onScanRequested?.(request);\n return deferredPromise.promise;\n });\n }\n\n /**\n * Resolve the pending scan with the given result.\n *\n * @param result - The scanned data as a serialized UR.\n */\n resolvePendingScan(result: SerializedUR): void {\n if (!this.#pendingScan) {\n throw new Error('No pending scan to resolve.');\n }\n this.#pendingScan.resolve(result);\n this.#pendingScan = null;\n this.#onScanResolved?.(result);\n }\n\n /**\n * Reject the pending scan with the given error.\n *\n * @param error - The error to reject the scan with.\n */\n rejectPendingScan(error: Error): void {\n if (!this.#pendingScan) {\n throw new Error('No pending scan to reject.');\n }\n this.#pendingScan.reject(error);\n this.#pendingScan = null;\n this.#onScanRejected?.(error);\n }\n}\n"]}
|
package/dist/qr-keyring.cjs
CHANGED
|
@@ -112,12 +112,12 @@ class QrKeyring {
|
|
|
112
112
|
for (let i = 0; i < accountsToAdd; i++) {
|
|
113
113
|
const index = __classPrivateFieldGet(this, _QrKeyring_accountToUnlock, "f") ?? __classPrivateFieldGet(this, _QrKeyring_accounts, "f").length + i;
|
|
114
114
|
const address = __classPrivateFieldGet(this, _QrKeyring_device, "f").addressFromIndex(index);
|
|
115
|
+
this.setAccountToUnlock(index + 1);
|
|
115
116
|
if (__classPrivateFieldGet(this, _QrKeyring_accounts, "f").includes(address)) {
|
|
116
117
|
continue;
|
|
117
118
|
}
|
|
118
119
|
__classPrivateFieldGet(this, _QrKeyring_accounts, "f").push(address);
|
|
119
120
|
newAccounts.push(address);
|
|
120
|
-
this.setAccountToUnlock(index + 1);
|
|
121
121
|
}
|
|
122
122
|
return newAccounts;
|
|
123
123
|
}
|
package/dist/qr-keyring.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qr-keyring.cjs","sourceRoot":"","sources":["../src/qr-keyring.ts"],"names":[],"mappings":"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","sourcesContent":["import { type TypedTransaction, type TypedTxData } from '@ethereumjs/tx';\nimport type { TypedMessage, MessageTypes } from '@metamask/eth-sig-util';\nimport type { Keyring } from '@metamask/keyring-utils';\nimport { type Hex, add0x, assert, getChecksumAddress } from '@metamask/utils';\n\nimport {\n type DeviceDetails,\n type IndexedAddress,\n Device,\n DeviceMode,\n} from './device';\n\nexport const QR_KEYRING_TYPE = 'QR Hardware Wallet Device';\n\nexport enum QrScanRequestType {\n /**\n * Request a scan for a QR code containing a UR\n * with information related to a hardware wallet.\n */\n PAIR = 'pair',\n /**\n * Request a scan for a QR code containing a\n * UR-encoded transaction signature.\n */\n SIGN = 'sign',\n}\n\nexport type QrSignatureRequest = {\n requestId: string;\n payload: SerializedUR;\n requestTitle?: string;\n requestDescription?: string;\n};\n\nexport type QrScanRequest = {\n type: QrScanRequestType;\n request?: QrSignatureRequest;\n};\n\nexport type SerializedUR = {\n type: string;\n cbor: string;\n};\n\nexport type QrKeyringBridge = {\n requestScan: (request: QrScanRequest) => Promise<SerializedUR>;\n};\n\nexport type QrKeyringOptions = {\n ur?: string;\n bridge: QrKeyringBridge;\n};\n\n/**\n * The state of the QrKeyring\n *\n * @property accounts - The accounts in the QrKeyring\n */\nexport type SerializedQrKeyringState = {\n version?: number;\n accounts?: string[];\n currentAccount?: number;\n} & (\n | {\n initialized?: false;\n }\n | ({\n initialized: true;\n } & DeviceDetails)\n);\n\n/**\n * Returns the default serialized state of the QrKeyring.\n *\n * @returns The default serialized state.\n */\nexport const getDefaultSerializedQrKeyringState =\n (): SerializedQrKeyringState => ({\n initialized: false,\n accounts: [],\n });\n\n/**\n * Normalizes an address to a 0x-prefixed checksum address.\n *\n * @param address - The address to normalize.\n * @returns The normalized address as a Hex string.\n */\nfunction normalizeAddress(address: string): Hex {\n return getChecksumAddress(add0x(address));\n}\n\nexport class QrKeyring implements Keyring {\n static type = QR_KEYRING_TYPE;\n\n readonly type = QR_KEYRING_TYPE;\n\n readonly bridge: QrKeyringBridge;\n\n #device?: Device | undefined;\n\n #accounts: Hex[] = [];\n\n #accountToUnlock?: number | undefined;\n\n #currentPage: number = 0;\n\n constructor(options: QrKeyringOptions) {\n this.bridge = options.bridge;\n\n if (options?.ur) {\n this.pairDevice(options.ur);\n }\n }\n\n /**\n * Serializes the QrKeyring state\n *\n * @returns The serialized state\n */\n async serialize(): Promise<SerializedQrKeyringState> {\n const deviceDetails = this.#device\n ? this.#device.getDeviceDetails()\n : undefined;\n\n if (\n !deviceDetails ||\n ![DeviceMode.HD, DeviceMode.ACCOUNT].includes(deviceDetails.keyringMode)\n ) {\n // the keyring has not initialized with a deviceDetails device yet\n return getDefaultSerializedQrKeyringState();\n }\n\n return {\n ...deviceDetails,\n initialized: true,\n accounts: this.#accounts.slice(),\n };\n }\n\n /**\n * Deserializes the QrKeyring state\n *\n * @param state - The serialized state to deserialize\n */\n async deserialize(state: SerializedQrKeyringState): Promise<void> {\n if (!state.initialized) {\n this.#accounts = [];\n this.#device = undefined;\n return;\n }\n\n this.#device = new Device({\n requestScan: this.bridge.requestScan.bind(this.bridge),\n source: state,\n });\n this.#accounts = (state.accounts ?? []).map(normalizeAddress);\n }\n\n /**\n * Adds accounts to the QrKeyring\n *\n * @param accountsToAdd - The number of accounts to add\n * @returns The accounts added\n */\n async addAccounts(accountsToAdd: number): Promise<Hex[]> {\n if (!this.#device) {\n throw new Error('No device paired.');\n }\n\n const newAccounts: Hex[] = [];\n\n for (let i = 0; i < accountsToAdd; i++) {\n const index = this.#accountToUnlock ?? this.#accounts.length + i;\n const address = this.#device.addressFromIndex(index);\n\n if (this.#accounts.includes(address)) {\n continue;\n }\n\n this.#accounts.push(address);\n newAccounts.push(address);\n this.setAccountToUnlock(index + 1);\n }\n\n return newAccounts;\n }\n\n /**\n * Gets the accounts in the QrKeyring\n *\n * @returns The accounts in the QrKeyring\n */\n async getAccounts(): Promise<Hex[]> {\n return this.#accounts.slice();\n }\n\n /**\n * Remove an account from the keyring\n *\n * @param address - The address of the account to remove\n */\n removeAccount(address: Hex): void {\n const normalizedAddress = normalizeAddress(address);\n this.#accounts = this.#accounts.filter(\n (account) => account !== normalizedAddress,\n );\n }\n\n /**\n * Pair a QR-based Hardware Device from a CBOR encoded UR to the QrKeyring\n *\n * @param ur - The CBOR encoded UR\n */\n pairDevice(ur: string | SerializedUR): void {\n this.#device = new Device({\n requestScan: this.bridge.requestScan.bind(this.bridge),\n source: ur,\n });\n }\n\n /**\n * Sets the next account index to unlock\n *\n * @param index - The index of the account to unlock\n */\n setAccountToUnlock(index: number): void {\n this.#accountToUnlock = index;\n }\n\n /**\n * Get the name of the paired device or the keyring type\n * if unavailable.\n *\n * @returns The name of the paired device or the keyring type.\n */\n getName(): string {\n if (!this.#device) {\n return QR_KEYRING_TYPE;\n }\n const source = this.#device.getDeviceDetails();\n return source.name;\n }\n\n /**\n * Fetch the first page of accounts. If the keyring is not currently initialized,\n * it will trigger a scan request to initialize it.\n *\n * @returns The first page of accounts as an array of Hex strings.\n */\n async getFirstPage(): Promise<IndexedAddress[]> {\n this.#currentPage = 0;\n return this.getCurrentPage();\n }\n\n /**\n * Fetch the next page of accounts. If the keyring is not currently initialized,\n * it will trigger a scan request to initialize it.\n *\n * @returns The next page of accounts as an array of IndexedAddress objects.\n */\n async getNextPage(): Promise<IndexedAddress[]> {\n this.#currentPage += 1;\n return this.getCurrentPage();\n }\n\n /**\n * Fetch the previous page of accounts. If the keyring is not currently initialized,\n * it will trigger a scan request to initialize it.\n *\n * @returns The previous page of accounts as an array of IndexedAddress objects.\n */\n async getPreviousPage(): Promise<IndexedAddress[]> {\n if (this.#currentPage > 0) {\n this.#currentPage -= 1;\n } else {\n this.#currentPage = 0;\n }\n return this.getCurrentPage();\n }\n\n /**\n * Fetch the current page of accounts. If the keyring is not currently initialized,\n * it will trigger a scan request to initialize it.\n *\n * @returns The current page of accounts as an array of IndexedAddress objects.\n */\n async getCurrentPage(): Promise<IndexedAddress[]> {\n if (!this.#device) {\n await this.#scanAndInitialize();\n }\n assert(\n this.#device,\n 'A device is expected to be paired before fetching accounts.',\n );\n return this.#device.getAddressesPage(this.#currentPage);\n }\n\n /**\n * Clear the keyring state and forget any paired device or accounts.\n */\n async forgetDevice(): Promise<void> {\n this.#device = undefined;\n this.#accounts = [];\n this.#accountToUnlock = undefined;\n this.#currentPage = 0;\n }\n\n /**\n * Sign a transaction. This is equivalent to the `eth_signTransaction`\n * Ethereum JSON-RPC method. See the Ethereum JSON-RPC API documentation for\n * more details.\n *\n * @param address - The address of the account to use for signing.\n * @param transaction - The transaction to sign.\n * @returns The signed transaction.\n */\n async signTransaction(\n address: Hex,\n transaction: TypedTransaction,\n ): Promise<TypedTxData> {\n if (!this.#device) {\n throw new Error('No device paired.');\n }\n return this.#device.signTransaction(address, transaction);\n }\n\n /**\n * Sign a message. This is equivalent to the `eth_signTypedData` v4 Ethereum\n * JSON-RPC method.\n *\n * @param address - The address of the account to use for signing.\n * @param data - The data to sign.\n * @returns The signed message.\n */\n async signTypedData<Types extends MessageTypes>(\n address: Hex,\n data: TypedMessage<Types>,\n ): Promise<string> {\n if (!this.#device) {\n throw new Error('No device paired.');\n }\n return this.#device.signTypedData(address, data);\n }\n\n /**\n * Sign a message. This is equivalent to the `eth_sign` Ethereum JSON-RPC\n * method, which is exposed by MetaMask as the method `personal_sign`. See\n * the Ethereum JSON-RPC API documentation for more details.\n *\n * For more information about this method and why we call it `personal_sign`,\n * see the {@link https://docs.metamask.io/guide/signing-data.html|MetaMask Docs}.\n *\n * @param address - The address of the account to use for signing.\n * @param message - The message to sign.\n * @returns The signed message.\n */\n async signPersonalMessage(address: Hex, message: Hex): Promise<string> {\n if (!this.#device) {\n throw new Error('No device paired.');\n }\n return this.#device.signPersonalMessage(address, message);\n }\n\n /**\n * Scan for a QR code and initialize the keyring with the\n * scanned UR.\n */\n async #scanAndInitialize(): Promise<void> {\n this.pairDevice(\n await this.bridge.requestScan({ type: QrScanRequestType.PAIR }),\n );\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"qr-keyring.cjs","sourceRoot":"","sources":["../src/qr-keyring.ts"],"names":[],"mappings":"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","sourcesContent":["import { type TypedTransaction, type TypedTxData } from '@ethereumjs/tx';\nimport type { TypedMessage, MessageTypes } from '@metamask/eth-sig-util';\nimport type { Keyring } from '@metamask/keyring-utils';\nimport { type Hex, add0x, assert, getChecksumAddress } from '@metamask/utils';\n\nimport {\n type DeviceDetails,\n type IndexedAddress,\n Device,\n DeviceMode,\n} from './device';\n\nexport const QR_KEYRING_TYPE = 'QR Hardware Wallet Device';\n\nexport enum QrScanRequestType {\n /**\n * Request a scan for a QR code containing a UR\n * with information related to a hardware wallet.\n */\n PAIR = 'pair',\n /**\n * Request a scan for a QR code containing a\n * UR-encoded transaction signature.\n */\n SIGN = 'sign',\n}\n\nexport type QrSignatureRequest = {\n requestId: string;\n payload: SerializedUR;\n requestTitle?: string;\n requestDescription?: string;\n};\n\nexport type QrScanRequest = {\n type: QrScanRequestType;\n request?: QrSignatureRequest;\n};\n\nexport type SerializedUR = {\n type: string;\n cbor: string;\n};\n\nexport type QrKeyringBridge = {\n requestScan: (request: QrScanRequest) => Promise<SerializedUR>;\n};\n\nexport type QrKeyringOptions = {\n ur?: string;\n bridge: QrKeyringBridge;\n};\n\n/**\n * The state of the QrKeyring\n *\n * @property accounts - The accounts in the QrKeyring\n */\nexport type SerializedQrKeyringState = {\n version?: number;\n accounts?: string[];\n currentAccount?: number;\n} & (\n | {\n initialized?: false;\n }\n | ({\n initialized: true;\n } & DeviceDetails)\n);\n\n/**\n * Returns the default serialized state of the QrKeyring.\n *\n * @returns The default serialized state.\n */\nexport const getDefaultSerializedQrKeyringState =\n (): SerializedQrKeyringState => ({\n initialized: false,\n accounts: [],\n });\n\n/**\n * Normalizes an address to a 0x-prefixed checksum address.\n *\n * @param address - The address to normalize.\n * @returns The normalized address as a Hex string.\n */\nfunction normalizeAddress(address: string): Hex {\n return getChecksumAddress(add0x(address));\n}\n\nexport class QrKeyring implements Keyring {\n static type = QR_KEYRING_TYPE;\n\n readonly type = QR_KEYRING_TYPE;\n\n readonly bridge: QrKeyringBridge;\n\n #device?: Device | undefined;\n\n #accounts: Hex[] = [];\n\n #accountToUnlock?: number | undefined;\n\n #currentPage: number = 0;\n\n constructor(options: QrKeyringOptions) {\n this.bridge = options.bridge;\n\n if (options?.ur) {\n this.pairDevice(options.ur);\n }\n }\n\n /**\n * Serializes the QrKeyring state\n *\n * @returns The serialized state\n */\n async serialize(): Promise<SerializedQrKeyringState> {\n const deviceDetails = this.#device\n ? this.#device.getDeviceDetails()\n : undefined;\n\n if (\n !deviceDetails ||\n ![DeviceMode.HD, DeviceMode.ACCOUNT].includes(deviceDetails.keyringMode)\n ) {\n // the keyring has not initialized with a deviceDetails device yet\n return getDefaultSerializedQrKeyringState();\n }\n\n return {\n ...deviceDetails,\n initialized: true,\n accounts: this.#accounts.slice(),\n };\n }\n\n /**\n * Deserializes the QrKeyring state\n *\n * @param state - The serialized state to deserialize\n */\n async deserialize(state: SerializedQrKeyringState): Promise<void> {\n if (!state.initialized) {\n this.#accounts = [];\n this.#device = undefined;\n return;\n }\n\n this.#device = new Device({\n requestScan: this.bridge.requestScan.bind(this.bridge),\n source: state,\n });\n this.#accounts = (state.accounts ?? []).map(normalizeAddress);\n }\n\n /**\n * Adds accounts to the QrKeyring\n *\n * @param accountsToAdd - The number of accounts to add\n * @returns The accounts added\n */\n async addAccounts(accountsToAdd: number): Promise<Hex[]> {\n if (!this.#device) {\n throw new Error('No device paired.');\n }\n\n const newAccounts: Hex[] = [];\n\n for (let i = 0; i < accountsToAdd; i++) {\n const index = this.#accountToUnlock ?? this.#accounts.length + i;\n const address = this.#device.addressFromIndex(index);\n this.setAccountToUnlock(index + 1);\n\n if (this.#accounts.includes(address)) {\n continue;\n }\n\n this.#accounts.push(address);\n newAccounts.push(address);\n }\n\n return newAccounts;\n }\n\n /**\n * Gets the accounts in the QrKeyring\n *\n * @returns The accounts in the QrKeyring\n */\n async getAccounts(): Promise<Hex[]> {\n return this.#accounts.slice();\n }\n\n /**\n * Remove an account from the keyring\n *\n * @param address - The address of the account to remove\n */\n removeAccount(address: Hex): void {\n const normalizedAddress = normalizeAddress(address);\n this.#accounts = this.#accounts.filter(\n (account) => account !== normalizedAddress,\n );\n }\n\n /**\n * Pair a QR-based Hardware Device from a CBOR encoded UR to the QrKeyring\n *\n * @param ur - The CBOR encoded UR\n */\n pairDevice(ur: string | SerializedUR): void {\n this.#device = new Device({\n requestScan: this.bridge.requestScan.bind(this.bridge),\n source: ur,\n });\n }\n\n /**\n * Sets the next account index to unlock\n *\n * @param index - The index of the account to unlock\n */\n setAccountToUnlock(index: number): void {\n this.#accountToUnlock = index;\n }\n\n /**\n * Get the name of the paired device or the keyring type\n * if unavailable.\n *\n * @returns The name of the paired device or the keyring type.\n */\n getName(): string {\n if (!this.#device) {\n return QR_KEYRING_TYPE;\n }\n const source = this.#device.getDeviceDetails();\n return source.name;\n }\n\n /**\n * Fetch the first page of accounts. If the keyring is not currently initialized,\n * it will trigger a scan request to initialize it.\n *\n * @returns The first page of accounts as an array of Hex strings.\n */\n async getFirstPage(): Promise<IndexedAddress[]> {\n this.#currentPage = 0;\n return this.getCurrentPage();\n }\n\n /**\n * Fetch the next page of accounts. If the keyring is not currently initialized,\n * it will trigger a scan request to initialize it.\n *\n * @returns The next page of accounts as an array of IndexedAddress objects.\n */\n async getNextPage(): Promise<IndexedAddress[]> {\n this.#currentPage += 1;\n return this.getCurrentPage();\n }\n\n /**\n * Fetch the previous page of accounts. If the keyring is not currently initialized,\n * it will trigger a scan request to initialize it.\n *\n * @returns The previous page of accounts as an array of IndexedAddress objects.\n */\n async getPreviousPage(): Promise<IndexedAddress[]> {\n if (this.#currentPage > 0) {\n this.#currentPage -= 1;\n } else {\n this.#currentPage = 0;\n }\n return this.getCurrentPage();\n }\n\n /**\n * Fetch the current page of accounts. If the keyring is not currently initialized,\n * it will trigger a scan request to initialize it.\n *\n * @returns The current page of accounts as an array of IndexedAddress objects.\n */\n async getCurrentPage(): Promise<IndexedAddress[]> {\n if (!this.#device) {\n await this.#scanAndInitialize();\n }\n assert(\n this.#device,\n 'A device is expected to be paired before fetching accounts.',\n );\n return this.#device.getAddressesPage(this.#currentPage);\n }\n\n /**\n * Clear the keyring state and forget any paired device or accounts.\n */\n async forgetDevice(): Promise<void> {\n this.#device = undefined;\n this.#accounts = [];\n this.#accountToUnlock = undefined;\n this.#currentPage = 0;\n }\n\n /**\n * Sign a transaction. This is equivalent to the `eth_signTransaction`\n * Ethereum JSON-RPC method. See the Ethereum JSON-RPC API documentation for\n * more details.\n *\n * @param address - The address of the account to use for signing.\n * @param transaction - The transaction to sign.\n * @returns The signed transaction.\n */\n async signTransaction(\n address: Hex,\n transaction: TypedTransaction,\n ): Promise<TypedTxData> {\n if (!this.#device) {\n throw new Error('No device paired.');\n }\n return this.#device.signTransaction(address, transaction);\n }\n\n /**\n * Sign a message. This is equivalent to the `eth_signTypedData` v4 Ethereum\n * JSON-RPC method.\n *\n * @param address - The address of the account to use for signing.\n * @param data - The data to sign.\n * @returns The signed message.\n */\n async signTypedData<Types extends MessageTypes>(\n address: Hex,\n data: TypedMessage<Types>,\n ): Promise<string> {\n if (!this.#device) {\n throw new Error('No device paired.');\n }\n return this.#device.signTypedData(address, data);\n }\n\n /**\n * Sign a message. This is equivalent to the `eth_sign` Ethereum JSON-RPC\n * method, which is exposed by MetaMask as the method `personal_sign`. See\n * the Ethereum JSON-RPC API documentation for more details.\n *\n * For more information about this method and why we call it `personal_sign`,\n * see the {@link https://docs.metamask.io/guide/signing-data.html|MetaMask Docs}.\n *\n * @param address - The address of the account to use for signing.\n * @param message - The message to sign.\n * @returns The signed message.\n */\n async signPersonalMessage(address: Hex, message: Hex): Promise<string> {\n if (!this.#device) {\n throw new Error('No device paired.');\n }\n return this.#device.signPersonalMessage(address, message);\n }\n\n /**\n * Scan for a QR code and initialize the keyring with the\n * scanned UR.\n */\n async #scanAndInitialize(): Promise<void> {\n this.pairDevice(\n await this.bridge.requestScan({ type: QrScanRequestType.PAIR }),\n );\n }\n}\n"]}
|
package/dist/qr-keyring.mjs
CHANGED
|
@@ -108,12 +108,12 @@ export class QrKeyring {
|
|
|
108
108
|
for (let i = 0; i < accountsToAdd; i++) {
|
|
109
109
|
const index = __classPrivateFieldGet(this, _QrKeyring_accountToUnlock, "f") ?? __classPrivateFieldGet(this, _QrKeyring_accounts, "f").length + i;
|
|
110
110
|
const address = __classPrivateFieldGet(this, _QrKeyring_device, "f").addressFromIndex(index);
|
|
111
|
+
this.setAccountToUnlock(index + 1);
|
|
111
112
|
if (__classPrivateFieldGet(this, _QrKeyring_accounts, "f").includes(address)) {
|
|
112
113
|
continue;
|
|
113
114
|
}
|
|
114
115
|
__classPrivateFieldGet(this, _QrKeyring_accounts, "f").push(address);
|
|
115
116
|
newAccounts.push(address);
|
|
116
|
-
this.setAccountToUnlock(index + 1);
|
|
117
117
|
}
|
|
118
118
|
return newAccounts;
|
|
119
119
|
}
|
package/dist/qr-keyring.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qr-keyring.mjs","sourceRoot":"","sources":["../src/qr-keyring.ts"],"names":[],"mappings":"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","sourcesContent":["import { type TypedTransaction, type TypedTxData } from '@ethereumjs/tx';\nimport type { TypedMessage, MessageTypes } from '@metamask/eth-sig-util';\nimport type { Keyring } from '@metamask/keyring-utils';\nimport { type Hex, add0x, assert, getChecksumAddress } from '@metamask/utils';\n\nimport {\n type DeviceDetails,\n type IndexedAddress,\n Device,\n DeviceMode,\n} from './device';\n\nexport const QR_KEYRING_TYPE = 'QR Hardware Wallet Device';\n\nexport enum QrScanRequestType {\n /**\n * Request a scan for a QR code containing a UR\n * with information related to a hardware wallet.\n */\n PAIR = 'pair',\n /**\n * Request a scan for a QR code containing a\n * UR-encoded transaction signature.\n */\n SIGN = 'sign',\n}\n\nexport type QrSignatureRequest = {\n requestId: string;\n payload: SerializedUR;\n requestTitle?: string;\n requestDescription?: string;\n};\n\nexport type QrScanRequest = {\n type: QrScanRequestType;\n request?: QrSignatureRequest;\n};\n\nexport type SerializedUR = {\n type: string;\n cbor: string;\n};\n\nexport type QrKeyringBridge = {\n requestScan: (request: QrScanRequest) => Promise<SerializedUR>;\n};\n\nexport type QrKeyringOptions = {\n ur?: string;\n bridge: QrKeyringBridge;\n};\n\n/**\n * The state of the QrKeyring\n *\n * @property accounts - The accounts in the QrKeyring\n */\nexport type SerializedQrKeyringState = {\n version?: number;\n accounts?: string[];\n currentAccount?: number;\n} & (\n | {\n initialized?: false;\n }\n | ({\n initialized: true;\n } & DeviceDetails)\n);\n\n/**\n * Returns the default serialized state of the QrKeyring.\n *\n * @returns The default serialized state.\n */\nexport const getDefaultSerializedQrKeyringState =\n (): SerializedQrKeyringState => ({\n initialized: false,\n accounts: [],\n });\n\n/**\n * Normalizes an address to a 0x-prefixed checksum address.\n *\n * @param address - The address to normalize.\n * @returns The normalized address as a Hex string.\n */\nfunction normalizeAddress(address: string): Hex {\n return getChecksumAddress(add0x(address));\n}\n\nexport class QrKeyring implements Keyring {\n static type = QR_KEYRING_TYPE;\n\n readonly type = QR_KEYRING_TYPE;\n\n readonly bridge: QrKeyringBridge;\n\n #device?: Device | undefined;\n\n #accounts: Hex[] = [];\n\n #accountToUnlock?: number | undefined;\n\n #currentPage: number = 0;\n\n constructor(options: QrKeyringOptions) {\n this.bridge = options.bridge;\n\n if (options?.ur) {\n this.pairDevice(options.ur);\n }\n }\n\n /**\n * Serializes the QrKeyring state\n *\n * @returns The serialized state\n */\n async serialize(): Promise<SerializedQrKeyringState> {\n const deviceDetails = this.#device\n ? this.#device.getDeviceDetails()\n : undefined;\n\n if (\n !deviceDetails ||\n ![DeviceMode.HD, DeviceMode.ACCOUNT].includes(deviceDetails.keyringMode)\n ) {\n // the keyring has not initialized with a deviceDetails device yet\n return getDefaultSerializedQrKeyringState();\n }\n\n return {\n ...deviceDetails,\n initialized: true,\n accounts: this.#accounts.slice(),\n };\n }\n\n /**\n * Deserializes the QrKeyring state\n *\n * @param state - The serialized state to deserialize\n */\n async deserialize(state: SerializedQrKeyringState): Promise<void> {\n if (!state.initialized) {\n this.#accounts = [];\n this.#device = undefined;\n return;\n }\n\n this.#device = new Device({\n requestScan: this.bridge.requestScan.bind(this.bridge),\n source: state,\n });\n this.#accounts = (state.accounts ?? []).map(normalizeAddress);\n }\n\n /**\n * Adds accounts to the QrKeyring\n *\n * @param accountsToAdd - The number of accounts to add\n * @returns The accounts added\n */\n async addAccounts(accountsToAdd: number): Promise<Hex[]> {\n if (!this.#device) {\n throw new Error('No device paired.');\n }\n\n const newAccounts: Hex[] = [];\n\n for (let i = 0; i < accountsToAdd; i++) {\n const index = this.#accountToUnlock ?? this.#accounts.length + i;\n const address = this.#device.addressFromIndex(index);\n\n if (this.#accounts.includes(address)) {\n continue;\n }\n\n this.#accounts.push(address);\n newAccounts.push(address);\n this.setAccountToUnlock(index + 1);\n }\n\n return newAccounts;\n }\n\n /**\n * Gets the accounts in the QrKeyring\n *\n * @returns The accounts in the QrKeyring\n */\n async getAccounts(): Promise<Hex[]> {\n return this.#accounts.slice();\n }\n\n /**\n * Remove an account from the keyring\n *\n * @param address - The address of the account to remove\n */\n removeAccount(address: Hex): void {\n const normalizedAddress = normalizeAddress(address);\n this.#accounts = this.#accounts.filter(\n (account) => account !== normalizedAddress,\n );\n }\n\n /**\n * Pair a QR-based Hardware Device from a CBOR encoded UR to the QrKeyring\n *\n * @param ur - The CBOR encoded UR\n */\n pairDevice(ur: string | SerializedUR): void {\n this.#device = new Device({\n requestScan: this.bridge.requestScan.bind(this.bridge),\n source: ur,\n });\n }\n\n /**\n * Sets the next account index to unlock\n *\n * @param index - The index of the account to unlock\n */\n setAccountToUnlock(index: number): void {\n this.#accountToUnlock = index;\n }\n\n /**\n * Get the name of the paired device or the keyring type\n * if unavailable.\n *\n * @returns The name of the paired device or the keyring type.\n */\n getName(): string {\n if (!this.#device) {\n return QR_KEYRING_TYPE;\n }\n const source = this.#device.getDeviceDetails();\n return source.name;\n }\n\n /**\n * Fetch the first page of accounts. If the keyring is not currently initialized,\n * it will trigger a scan request to initialize it.\n *\n * @returns The first page of accounts as an array of Hex strings.\n */\n async getFirstPage(): Promise<IndexedAddress[]> {\n this.#currentPage = 0;\n return this.getCurrentPage();\n }\n\n /**\n * Fetch the next page of accounts. If the keyring is not currently initialized,\n * it will trigger a scan request to initialize it.\n *\n * @returns The next page of accounts as an array of IndexedAddress objects.\n */\n async getNextPage(): Promise<IndexedAddress[]> {\n this.#currentPage += 1;\n return this.getCurrentPage();\n }\n\n /**\n * Fetch the previous page of accounts. If the keyring is not currently initialized,\n * it will trigger a scan request to initialize it.\n *\n * @returns The previous page of accounts as an array of IndexedAddress objects.\n */\n async getPreviousPage(): Promise<IndexedAddress[]> {\n if (this.#currentPage > 0) {\n this.#currentPage -= 1;\n } else {\n this.#currentPage = 0;\n }\n return this.getCurrentPage();\n }\n\n /**\n * Fetch the current page of accounts. If the keyring is not currently initialized,\n * it will trigger a scan request to initialize it.\n *\n * @returns The current page of accounts as an array of IndexedAddress objects.\n */\n async getCurrentPage(): Promise<IndexedAddress[]> {\n if (!this.#device) {\n await this.#scanAndInitialize();\n }\n assert(\n this.#device,\n 'A device is expected to be paired before fetching accounts.',\n );\n return this.#device.getAddressesPage(this.#currentPage);\n }\n\n /**\n * Clear the keyring state and forget any paired device or accounts.\n */\n async forgetDevice(): Promise<void> {\n this.#device = undefined;\n this.#accounts = [];\n this.#accountToUnlock = undefined;\n this.#currentPage = 0;\n }\n\n /**\n * Sign a transaction. This is equivalent to the `eth_signTransaction`\n * Ethereum JSON-RPC method. See the Ethereum JSON-RPC API documentation for\n * more details.\n *\n * @param address - The address of the account to use for signing.\n * @param transaction - The transaction to sign.\n * @returns The signed transaction.\n */\n async signTransaction(\n address: Hex,\n transaction: TypedTransaction,\n ): Promise<TypedTxData> {\n if (!this.#device) {\n throw new Error('No device paired.');\n }\n return this.#device.signTransaction(address, transaction);\n }\n\n /**\n * Sign a message. This is equivalent to the `eth_signTypedData` v4 Ethereum\n * JSON-RPC method.\n *\n * @param address - The address of the account to use for signing.\n * @param data - The data to sign.\n * @returns The signed message.\n */\n async signTypedData<Types extends MessageTypes>(\n address: Hex,\n data: TypedMessage<Types>,\n ): Promise<string> {\n if (!this.#device) {\n throw new Error('No device paired.');\n }\n return this.#device.signTypedData(address, data);\n }\n\n /**\n * Sign a message. This is equivalent to the `eth_sign` Ethereum JSON-RPC\n * method, which is exposed by MetaMask as the method `personal_sign`. See\n * the Ethereum JSON-RPC API documentation for more details.\n *\n * For more information about this method and why we call it `personal_sign`,\n * see the {@link https://docs.metamask.io/guide/signing-data.html|MetaMask Docs}.\n *\n * @param address - The address of the account to use for signing.\n * @param message - The message to sign.\n * @returns The signed message.\n */\n async signPersonalMessage(address: Hex, message: Hex): Promise<string> {\n if (!this.#device) {\n throw new Error('No device paired.');\n }\n return this.#device.signPersonalMessage(address, message);\n }\n\n /**\n * Scan for a QR code and initialize the keyring with the\n * scanned UR.\n */\n async #scanAndInitialize(): Promise<void> {\n this.pairDevice(\n await this.bridge.requestScan({ type: QrScanRequestType.PAIR }),\n );\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"qr-keyring.mjs","sourceRoot":"","sources":["../src/qr-keyring.ts"],"names":[],"mappings":"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","sourcesContent":["import { type TypedTransaction, type TypedTxData } from '@ethereumjs/tx';\nimport type { TypedMessage, MessageTypes } from '@metamask/eth-sig-util';\nimport type { Keyring } from '@metamask/keyring-utils';\nimport { type Hex, add0x, assert, getChecksumAddress } from '@metamask/utils';\n\nimport {\n type DeviceDetails,\n type IndexedAddress,\n Device,\n DeviceMode,\n} from './device';\n\nexport const QR_KEYRING_TYPE = 'QR Hardware Wallet Device';\n\nexport enum QrScanRequestType {\n /**\n * Request a scan for a QR code containing a UR\n * with information related to a hardware wallet.\n */\n PAIR = 'pair',\n /**\n * Request a scan for a QR code containing a\n * UR-encoded transaction signature.\n */\n SIGN = 'sign',\n}\n\nexport type QrSignatureRequest = {\n requestId: string;\n payload: SerializedUR;\n requestTitle?: string;\n requestDescription?: string;\n};\n\nexport type QrScanRequest = {\n type: QrScanRequestType;\n request?: QrSignatureRequest;\n};\n\nexport type SerializedUR = {\n type: string;\n cbor: string;\n};\n\nexport type QrKeyringBridge = {\n requestScan: (request: QrScanRequest) => Promise<SerializedUR>;\n};\n\nexport type QrKeyringOptions = {\n ur?: string;\n bridge: QrKeyringBridge;\n};\n\n/**\n * The state of the QrKeyring\n *\n * @property accounts - The accounts in the QrKeyring\n */\nexport type SerializedQrKeyringState = {\n version?: number;\n accounts?: string[];\n currentAccount?: number;\n} & (\n | {\n initialized?: false;\n }\n | ({\n initialized: true;\n } & DeviceDetails)\n);\n\n/**\n * Returns the default serialized state of the QrKeyring.\n *\n * @returns The default serialized state.\n */\nexport const getDefaultSerializedQrKeyringState =\n (): SerializedQrKeyringState => ({\n initialized: false,\n accounts: [],\n });\n\n/**\n * Normalizes an address to a 0x-prefixed checksum address.\n *\n * @param address - The address to normalize.\n * @returns The normalized address as a Hex string.\n */\nfunction normalizeAddress(address: string): Hex {\n return getChecksumAddress(add0x(address));\n}\n\nexport class QrKeyring implements Keyring {\n static type = QR_KEYRING_TYPE;\n\n readonly type = QR_KEYRING_TYPE;\n\n readonly bridge: QrKeyringBridge;\n\n #device?: Device | undefined;\n\n #accounts: Hex[] = [];\n\n #accountToUnlock?: number | undefined;\n\n #currentPage: number = 0;\n\n constructor(options: QrKeyringOptions) {\n this.bridge = options.bridge;\n\n if (options?.ur) {\n this.pairDevice(options.ur);\n }\n }\n\n /**\n * Serializes the QrKeyring state\n *\n * @returns The serialized state\n */\n async serialize(): Promise<SerializedQrKeyringState> {\n const deviceDetails = this.#device\n ? this.#device.getDeviceDetails()\n : undefined;\n\n if (\n !deviceDetails ||\n ![DeviceMode.HD, DeviceMode.ACCOUNT].includes(deviceDetails.keyringMode)\n ) {\n // the keyring has not initialized with a deviceDetails device yet\n return getDefaultSerializedQrKeyringState();\n }\n\n return {\n ...deviceDetails,\n initialized: true,\n accounts: this.#accounts.slice(),\n };\n }\n\n /**\n * Deserializes the QrKeyring state\n *\n * @param state - The serialized state to deserialize\n */\n async deserialize(state: SerializedQrKeyringState): Promise<void> {\n if (!state.initialized) {\n this.#accounts = [];\n this.#device = undefined;\n return;\n }\n\n this.#device = new Device({\n requestScan: this.bridge.requestScan.bind(this.bridge),\n source: state,\n });\n this.#accounts = (state.accounts ?? []).map(normalizeAddress);\n }\n\n /**\n * Adds accounts to the QrKeyring\n *\n * @param accountsToAdd - The number of accounts to add\n * @returns The accounts added\n */\n async addAccounts(accountsToAdd: number): Promise<Hex[]> {\n if (!this.#device) {\n throw new Error('No device paired.');\n }\n\n const newAccounts: Hex[] = [];\n\n for (let i = 0; i < accountsToAdd; i++) {\n const index = this.#accountToUnlock ?? this.#accounts.length + i;\n const address = this.#device.addressFromIndex(index);\n this.setAccountToUnlock(index + 1);\n\n if (this.#accounts.includes(address)) {\n continue;\n }\n\n this.#accounts.push(address);\n newAccounts.push(address);\n }\n\n return newAccounts;\n }\n\n /**\n * Gets the accounts in the QrKeyring\n *\n * @returns The accounts in the QrKeyring\n */\n async getAccounts(): Promise<Hex[]> {\n return this.#accounts.slice();\n }\n\n /**\n * Remove an account from the keyring\n *\n * @param address - The address of the account to remove\n */\n removeAccount(address: Hex): void {\n const normalizedAddress = normalizeAddress(address);\n this.#accounts = this.#accounts.filter(\n (account) => account !== normalizedAddress,\n );\n }\n\n /**\n * Pair a QR-based Hardware Device from a CBOR encoded UR to the QrKeyring\n *\n * @param ur - The CBOR encoded UR\n */\n pairDevice(ur: string | SerializedUR): void {\n this.#device = new Device({\n requestScan: this.bridge.requestScan.bind(this.bridge),\n source: ur,\n });\n }\n\n /**\n * Sets the next account index to unlock\n *\n * @param index - The index of the account to unlock\n */\n setAccountToUnlock(index: number): void {\n this.#accountToUnlock = index;\n }\n\n /**\n * Get the name of the paired device or the keyring type\n * if unavailable.\n *\n * @returns The name of the paired device or the keyring type.\n */\n getName(): string {\n if (!this.#device) {\n return QR_KEYRING_TYPE;\n }\n const source = this.#device.getDeviceDetails();\n return source.name;\n }\n\n /**\n * Fetch the first page of accounts. If the keyring is not currently initialized,\n * it will trigger a scan request to initialize it.\n *\n * @returns The first page of accounts as an array of Hex strings.\n */\n async getFirstPage(): Promise<IndexedAddress[]> {\n this.#currentPage = 0;\n return this.getCurrentPage();\n }\n\n /**\n * Fetch the next page of accounts. If the keyring is not currently initialized,\n * it will trigger a scan request to initialize it.\n *\n * @returns The next page of accounts as an array of IndexedAddress objects.\n */\n async getNextPage(): Promise<IndexedAddress[]> {\n this.#currentPage += 1;\n return this.getCurrentPage();\n }\n\n /**\n * Fetch the previous page of accounts. If the keyring is not currently initialized,\n * it will trigger a scan request to initialize it.\n *\n * @returns The previous page of accounts as an array of IndexedAddress objects.\n */\n async getPreviousPage(): Promise<IndexedAddress[]> {\n if (this.#currentPage > 0) {\n this.#currentPage -= 1;\n } else {\n this.#currentPage = 0;\n }\n return this.getCurrentPage();\n }\n\n /**\n * Fetch the current page of accounts. If the keyring is not currently initialized,\n * it will trigger a scan request to initialize it.\n *\n * @returns The current page of accounts as an array of IndexedAddress objects.\n */\n async getCurrentPage(): Promise<IndexedAddress[]> {\n if (!this.#device) {\n await this.#scanAndInitialize();\n }\n assert(\n this.#device,\n 'A device is expected to be paired before fetching accounts.',\n );\n return this.#device.getAddressesPage(this.#currentPage);\n }\n\n /**\n * Clear the keyring state and forget any paired device or accounts.\n */\n async forgetDevice(): Promise<void> {\n this.#device = undefined;\n this.#accounts = [];\n this.#accountToUnlock = undefined;\n this.#currentPage = 0;\n }\n\n /**\n * Sign a transaction. This is equivalent to the `eth_signTransaction`\n * Ethereum JSON-RPC method. See the Ethereum JSON-RPC API documentation for\n * more details.\n *\n * @param address - The address of the account to use for signing.\n * @param transaction - The transaction to sign.\n * @returns The signed transaction.\n */\n async signTransaction(\n address: Hex,\n transaction: TypedTransaction,\n ): Promise<TypedTxData> {\n if (!this.#device) {\n throw new Error('No device paired.');\n }\n return this.#device.signTransaction(address, transaction);\n }\n\n /**\n * Sign a message. This is equivalent to the `eth_signTypedData` v4 Ethereum\n * JSON-RPC method.\n *\n * @param address - The address of the account to use for signing.\n * @param data - The data to sign.\n * @returns The signed message.\n */\n async signTypedData<Types extends MessageTypes>(\n address: Hex,\n data: TypedMessage<Types>,\n ): Promise<string> {\n if (!this.#device) {\n throw new Error('No device paired.');\n }\n return this.#device.signTypedData(address, data);\n }\n\n /**\n * Sign a message. This is equivalent to the `eth_sign` Ethereum JSON-RPC\n * method, which is exposed by MetaMask as the method `personal_sign`. See\n * the Ethereum JSON-RPC API documentation for more details.\n *\n * For more information about this method and why we call it `personal_sign`,\n * see the {@link https://docs.metamask.io/guide/signing-data.html|MetaMask Docs}.\n *\n * @param address - The address of the account to use for signing.\n * @param message - The message to sign.\n * @returns The signed message.\n */\n async signPersonalMessage(address: Hex, message: Hex): Promise<string> {\n if (!this.#device) {\n throw new Error('No device paired.');\n }\n return this.#device.signPersonalMessage(address, message);\n }\n\n /**\n * Scan for a QR code and initialize the keyring with the\n * scanned UR.\n */\n async #scanAndInitialize(): Promise<void> {\n this.pairDevice(\n await this.bridge.requestScan({ type: QrScanRequestType.PAIR }),\n );\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metamask-previews/eth-qr-keyring",
|
|
3
|
-
"version": "0.0.0-
|
|
3
|
+
"version": "0.0.0-a621908",
|
|
4
4
|
"description": "A simple standard interface for a series of Ethereum private keys.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ethereum",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"@ethereumjs/util": "^9.1.0",
|
|
54
54
|
"@keystonehq/bc-ur-registry-eth": "^0.19.1",
|
|
55
55
|
"@metamask/eth-sig-util": "^8.2.0",
|
|
56
|
-
"@metamask/keyring-utils": "3.
|
|
56
|
+
"@metamask/keyring-utils": "3.1.0",
|
|
57
57
|
"@metamask/utils": "^11.1.0",
|
|
58
58
|
"async-mutex": "^0.5.0",
|
|
59
59
|
"hdkey": "^2.1.0",
|