If using the OneKey device via air gap mode, the main steps are as follows:
OneKey hardware provides the extened public key to the wallet via a QR code, then the wallet generates an address to query balance and other information.
The wallet creates unsigned transaction data or a message that needs to be signed, then generates a QR code. The OneKey device scans the QR code to receive the content that needs to be signed.
The OneKey device will parse and sign the data, then display the result through a QR code.
The wallet obtains the signed result by scanning the QR code from the OneKey device.
Install SDK
First, we need to install the SDK for air gap.
# Install via NPMnpminstall--save@onekeyfe/hd-air-gap-sdk# Install via YARNyarnadd@onekeyfe/hd-air-gap-sdk
Add Hardware Account To Wallet
Then, we need to add the hardware account to the software.
Through the steps above, you will obtain a QR code. Parsing this QR code with software will give you an extended public key, which can then be used to derive the respective addresses.
Scan QR Code
First, your software needs to be capable of scanning QR codes to retrieve the information they contain.
Sometimes, the data to be transferred can be very large, and a single QR code may not be able to display all the required data at once. Therefore, it may need to continuously switch between different QR codes dynamically to transfer all the data.
import { URDecoder } from'@onekeyfe/hd-air-gap-sdk';// A new urDecoder object is needed for each QR code parsing session.consturDecoder=newURDecoder();constonQrcodeScan= (data:string) => {try {if (!data) {return; }// Each piece of scanned data is parsed using urDecoder.urDecoder.receivePart(data);// Obtain the data reception progress.urDecoder.estimatedPercentComplete();// Check whether all data has been completely received.if (urDecoder.isComplete()) {constresult=urDecoder.resultUR();// At this point, result contains the data received, including the data type and the specific data. } } catch (e) {console.log(e); }}<CameraView onBarcodeScanned={({ data }) => onQrcodeScan(data)} />
Parse Account Data
Through the steps above, we have obtained the account information. Next, we can parse the data and derive the account.
import { CryptoHDKey, RegistryTypes } from'@onekeyfe/hd-air-gap-sdk';import HDKey from"hdkey";import { toChecksumAddress, publicToAddress, stripHexPrefix,} from"@ethereumjs/util";constDEFAULT_CHILDREN_PATH="0/*";// pseudo-codeconstresult=urDecoder.resultUR();if (result.type !==RegistryTypes.CRYPTO_HDKEY.getType()) {// error qr code}constcryptoHDKey=CryptoHDKey.fromCBOR(result.cbor);constname=cryptoHDKey.getName();constnote=cryptoHDKey.getNote();constextendPubKey=hdKey.getKey();constchainCode=hdKey.getChainCode();constxpub=hdKey.getBip32Key();constchildrenPath=hdKey.getChildren()?.getPath() ??DEFAULT_CHILDREN_PATH;consthdPath=`m/${cryptoHDKey.getOrigin().getPath()}`;// This parameter is required for subsequent eth sign request assembly.constxfp=cryptoHDKey.getOrigin().getSourceFingerprint()?.toString("hex");// derive childconstaccountIndex=0constderivePath= childrenPath.replace("*",String(accountIndex)).replace(/\*/g,"0");consthdk=HDKey.fromExtendedKey(xpub);constdkey=hdk.derive(`m/${derivePath}`);constaddress="0x"+publicToAddress(dkey.publicKey,true).toString("hex");constaddressWithChecksum=toChecksumAddress(address);console.log("address:", addressWithChecksum);
For more details, you can refer to the documentation below.
The first step requires the wallet to generate the transaction that needs to be signed.
The unsigned transaction needs to be converted into a QR code for the OneKey device to scan.
After signing, the OneKey device displays a QR code. The wallet scans the QR code on the device to obtain the signed result.
Generate transaction
import { Transaction, FeeMarketEIP1559Transaction } from'@ethereumjs/tx';import Common, { Hardfork } from'@ethereumjs/common';import { BN } from'ethereumjs-util';import*as uuid from"uuid";import { CryptoHDKey, EthSignRequest, DataType, ETHSignature,} from'@onekeyfe/hd-air-gap-sdk';constcommon=Common.forCustomChain('mainnet', { chainId:this._networkId },Hardfork.London);consteip1559Tx=FeeMarketEIP1559Transaction.fromTxData(txParams, { common });// generate the unsigned transaction bytesconstunsignedBuffer=Buffer.from(eip1559Tx.getMessageToSign(false));constrequestId=uuid.v4();constaddressPath="m/44'/60'/0'/0/0"constethSignRequest=EthSignRequest.constructETHRequest( unsignedBuffer,DataType.typedTransaction,// legacy transaction use DataType.transaction addressPath, xfp,// See Previous Step How do I get this parameter requestId,1,// chainId"from address",);// each chunk Number in single QR CodeconstmaxChunkNumber=200;// get the ur encoderconsturEncoder=ethSignRequest.toUREncoder(maxChunkNumber);while (ture) {delay(200);renderQR(urEncoder.nextPart());}
For more details, you can refer to the documentation below.
import { CryptoHDKey, RegistryTypes } from'@onekeyfe/hd-air-gap-sdk';import { Transaction } from'@ethereumjs/tx';// pseudo-codeconstresult=urDecoder.resultUR();if (result.type !==RegistryTypes.ETH_SIGNATURE.getType()) {// Invalid QR code type}constethSignature=ETHSignature.fromCBOR(result.cbor);// Extract the request ID, signatureconstrequestIdBuffer=ethSignature.getRequestId();constsignature=ethSignature.getSignature();// its components (r, s, v) from the decoded signatureconstr=signature.slice(0,32);consts=signature.slice(32,64);constv=signature.slice(64);// Assuming you have the transaction details and the signature componentsconsttxData= { nonce:'0x00', gasPrice:'0x09184e72a000', gasLimit:'0x2710', to:'0x0000000000000000000000000000000000000000', value:'0x00', data:'0x00',// Add the signature components to the transaction data v: v, r: r, s: s};// Create a new transaction object with the provided dataconsttransaction=Transaction.fromTxData(txData);// Serialize the transaction to get the raw transactionconstrawTx=transaction.serialize();// The raw transaction can now be submitted to the blockchain networkconsole.log("Raw transaction:",rawTx.toString('hex'));
For more details, you can refer to the documentation below.