Skip to content

Commit

Permalink
feat: support algo, ckb data & fix several issues OK-27484 OK-27478 (#…
Browse files Browse the repository at this point in the history
…4633)

* fix: ckb sign tx error

* fix: algo wallect conenct

* fix: algo wallect conenct

* chore: add octa chain

* fix: review issues

* fix: review issues
  • Loading branch information
weatherstar committed May 27, 2024
1 parent a7729d9 commit 50bd33c
Show file tree
Hide file tree
Showing 19 changed files with 328 additions and 146 deletions.
27 changes: 5 additions & 22 deletions packages/core/src/chains/ckb/CoreChainSoftware.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { blockchain } from '@ckb-lumos/base';
import { sealTransaction } from '@ckb-lumos/helpers';
import { bytesToHex } from '@noble/hashes/utils';

import { pubkeyToAddress } from '@onekeyhq/kit-bg/src/vaults/impls/ckb/utils/address';
import { getConfig } from '@onekeyhq/kit-bg/src/vaults/impls/ckb/utils/config';
import { serializeTransactionMessage } from '@onekeyhq/kit-bg/src/vaults/impls/ckb/utils/transaction';
import { OneKeyInternalError } from '@onekeyhq/shared/src/errors';
import bufferUtils from '@onekeyhq/shared/src/utils/bufferUtils';
import hexUtils from '@onekeyhq/shared/src/utils/hexUtils';

import { CoreChainApiBase } from '../../base/CoreChainApiBase';

import type { IEncodedTxCkb } from './types';
import { getConfig, pubkeyToAddress } from './sdkCkb';

import type {
ICoreApiGetAddressItem,
ICoreApiGetAddressQueryImported,
Expand All @@ -21,7 +15,6 @@ import type {
ICoreApiGetAddressesResult,
ICoreApiPrivateKeysMap,
ICoreApiSignBasePayload,
ICoreApiSignMsgPayload,
ICoreApiSignTxPayload,
ICurveName,
ISignedTxPro,
Expand All @@ -44,37 +37,27 @@ export default class CoreChainSoftware extends CoreChainApiBase {
payload: ICoreApiSignTxPayload,
): Promise<ISignedTxPro> {
const { unsignedTx } = payload;
const encodedTx = unsignedTx.encodedTx as IEncodedTxCkb;
const message = unsignedTx.rawTxUnsigned as string;
const signer = await this.baseGetSingleSigner({
payload,
curve,
});

const { txSkeleton: txSkeletonWithMessage, message } =
serializeTransactionMessage(encodedTx);

if (!message) {
throw new OneKeyInternalError('Unable to serialize transaction message.');
}

const [signature, recoveryParam] = await signer.sign(
Buffer.from(hexUtils.stripHexPrefix(message), 'hex'),
);

const recoveryParamHex = recoveryParam.toString(16).padStart(2, '0');
const sig = hexUtils.addHexPrefix(bytesToHex(signature) + recoveryParamHex);

const tx = sealTransaction(txSkeletonWithMessage, [sig]);
const signedTx = blockchain.Transaction.pack(tx);

return {
txid: '',
rawTx: bytesToHex(signedTx),
rawTx: sig,
encodedTx: unsignedTx.encodedTx,
};
}

override async signMessage(payload: ICoreApiSignMsgPayload): Promise<string> {
override async signMessage(): Promise<string> {
throw new Error('Method not implemented.');
}

Expand Down
54 changes: 54 additions & 0 deletions packages/core/src/chains/ckb/sdkCkb/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { utils } from '@ckb-lumos/base';
import { getConfig as getSDKConfig } from '@ckb-lumos/config-manager';
import { generateAddress, parseAddress } from '@ckb-lumos/helpers';

Check warning on line 3 in packages/core/src/chains/ckb/sdkCkb/index.ts

View workflow job for this annotation

GitHub Actions / lint (20.x)

'parseAddress' is defined but never used

import type { Script } from '@ckb-lumos/base';
import type { Config } from '@ckb-lumos/config-manager';
import type { Options } from '@ckb-lumos/helpers';

function blake160(publicKey: string): string {
return new utils.CKBHasher().update(publicKey).digestHex().slice(0, 42);
}

export function getConfig(chainId: string) {
const config = getSDKConfig();
if (chainId === 'mainnet' && config.PREFIX === 'ckb') {
return config;
}
if (chainId === 'testnet' && config.PREFIX === 'ckt') {
return config;
}

throw new Error('Invalid chainId');
}

export function scriptToAddress(
script: Script,
{ config = undefined }: Options = {},
): string {
// It needs to be replaced with encodeToAddress
return generateAddress(script, { config });
}

export function pubkeyToAddress(
publicKey: string,
{
config,
}: {
config: Config;
},
): string {
const args = blake160(publicKey);
const template = config.SCRIPTS.SECP256K1_BLAKE160;

if (!template) {
throw new Error('SECP256K1_BLAKE160 not found in config');
}

const lockScript = {
codeHash: template.CODE_HASH,
hashType: template.HASH_TYPE,
args,
};
return scriptToAddress(lockScript, { config });
}
10 changes: 8 additions & 2 deletions packages/core/src/chains/ckb/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
import type { TransactionSkeletonType } from '@ckb-lumos/helpers';
import type { Transaction } from '@ckb-lumos/base';

export type IEncodedTxCkb = TransactionSkeletonType;
export type IEncodedTxCkb = {
tx: Transaction;
feeInfo: {
price: string;
limit: string;
};
};
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { getSdkError } from '@walletconnect/utils';

import { backgroundMethod } from '@onekeyhq/shared/src/background/backgroundDecorators';
import { IMPL_EVM } from '@onekeyhq/shared/src/engine/engineConsts';
import { IMPL_ALGO, IMPL_EVM } from '@onekeyhq/shared/src/engine/engineConsts';
import { EModalRoutes } from '@onekeyhq/shared/src/routes';
import { EWalletConnectSessionEvents } from '@onekeyhq/shared/src/walletConnect/types';
import type { IWalletConnectSessionProposalResult } from '@onekeyhq/shared/types/dappConnection';

import walletConnectClient from '../../services/ServiceWalletConnect/walletConnectClient';
import walletConnectStorage from '../../services/ServiceWalletConnect/walletConnectStorage';

import { WalletConnectRequestProxyAlgo } from './WalletConnectRequestProxyAlgo';
import { WalletConnectRequestProxyEth } from './WalletConnectRequestProxyEth';

import type {
Expand All @@ -33,6 +34,9 @@ class ProviderApiWalletConnect {
[IMPL_EVM]: new WalletConnectRequestProxyEth({
client: this,
}),
[IMPL_ALGO]: new WalletConnectRequestProxyAlgo({
client: this,
}),
};

getRequestProxy({ networkImpl }: { networkImpl: string }) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { IInjectedProviderNames } from '@onekeyfe/cross-inpage-provider-types';

import { WalletConnectRequestProxy } from './WalletConnectRequestProxy';

export class WalletConnectRequestProxyAlgo extends WalletConnectRequestProxy {
override providerName = IInjectedProviderNames.algo;
}
3 changes: 0 additions & 3 deletions packages/kit-bg/src/services/ServiceSend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,6 @@ class ServiceSend extends ServiceBase {
}

const result: ISendTxOnSuccessData[] = [];

for (let i = 0, len = newUnsignedTxs.length; i < len; i += 1) {
const unsignedTx = newUnsignedTxs[i];
const signedTx = signOnly
Expand Down Expand Up @@ -515,7 +514,6 @@ class ServiceSend extends ServiceBase {
specifiedFeeRate,
});
}

if (swapInfo) {
newUnsignedTx.swapInfo = swapInfo;
}
Expand All @@ -540,7 +538,6 @@ class ServiceSend extends ServiceBase {
nonceInfo: { nonce },
});
}

return newUnsignedTx;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class ClientAlgo {
networkId: this.networkId,
body: [
{
route: 'algod',
route: 'client',
params: {
method: EAlgodMethods.GET_TRANSACTION_PARAMS,
params: [],
Expand Down
6 changes: 3 additions & 3 deletions packages/kit-bg/src/vaults/impls/cfx/KeyringHardware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export class KeyringHardware extends KeyringHardwareBase {

return this.basePrepareHdNormalAccounts(params, {
buildAddressesInfo: async ({ usedIndexes }) => {
const nearAddresses = await this.baseGetDeviceAccountAddresses({
const addresses = await this.baseGetDeviceAccountAddresses({
params,
usedIndexes,
sdkGetAddressFn: async ({
Expand Down Expand Up @@ -73,8 +73,8 @@ export class KeyringHardware extends KeyringHardwareBase {
});

const ret: ICoreApiGetAddressItem[] = [];
for (let i = 0; i < nearAddresses.length; i += 1) {
const item = nearAddresses[i];
for (let i = 0; i < addresses.length; i += 1) {
const item = addresses[i];
const { path, address } = item;
const { displayAddress } = await this.vault.validateAddress(
address ?? '',
Expand Down
28 changes: 20 additions & 8 deletions packages/kit-bg/src/vaults/impls/ckb/KeyringHardware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
} from '@ckb-lumos/helpers';
import { bytesToHex } from '@noble/hashes/utils';

import { getConfig } from '@onekeyhq/core/src/chains/ckb/sdkCkb';
import type { IEncodedTxCkb } from '@onekeyhq/core/src/chains/ckb/types';
import coreChainApi from '@onekeyhq/core/src/instance/coreChainApi';
import type {
Expand All @@ -20,8 +21,10 @@ import hexUtils from '@onekeyhq/shared/src/utils/hexUtils';

import { KeyringHardwareBase } from '../../base/KeyringHardwareBase';

import { getConfig } from './utils/config';
import { serializeTransactionMessage } from './utils/transaction';
import {
convertTxToTxSkeleton,
serializeTransactionMessage,
} from './utils/transaction';

import type { IDBAccount } from '../../../dbs/local/types';
import type {
Expand All @@ -39,7 +42,7 @@ export class KeyringHardware extends KeyringHardwareBase {
const config = getConfig(await this.getNetworkChainId());
return this.basePrepareHdNormalAccounts(params, {
buildAddressesInfo: async ({ usedIndexes }) => {
const nearAddresses = await this.baseGetDeviceAccountAddresses({
const addresses = await this.baseGetDeviceAccountAddresses({
params,
usedIndexes,
sdkGetAddressFn: async ({
Expand Down Expand Up @@ -67,8 +70,8 @@ export class KeyringHardware extends KeyringHardwareBase {
});

const ret: ICoreApiGetAddressItem[] = [];
for (let i = 0; i < nearAddresses.length; i += 1) {
const item = nearAddresses[i];
for (let i = 0; i < addresses.length; i += 1) {
const item = addresses[i];
const { path, address } = item;
const { normalizedAddress } = await this.vault.validateAddress(
address ?? '',
Expand Down Expand Up @@ -98,15 +101,24 @@ export class KeyringHardware extends KeyringHardwareBase {
const chainId = await this.getNetworkChainId();
const config = getConfig(chainId);

// @ts-ignore
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
const client = await this.vault.getClient();

const txSkeleton = await convertTxToTxSkeleton({
client,
transaction: encodedTx.tx,
});

const { txSkeleton: txSkeletonWithMessage } =
serializeTransactionMessage(encodedTx);
serializeTransactionMessage(txSkeleton);

const witnessHex = encodedTx.witnesses.get(0);
const witnessHex = txSkeleton.witnesses.get(0);
if (!witnessHex) {
throw new OneKeyInternalError('Transaction serialization failure');
}

const transaction = createTransactionFromSkeleton(encodedTx);
const transaction = createTransactionFromSkeleton(txSkeleton);

const serialize = blockchain.RawTransaction.pack(transaction);

Expand Down
45 changes: 44 additions & 1 deletion packages/kit-bg/src/vaults/impls/ckb/KeyringHd.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
import { blockchain } from '@ckb-lumos/base';
import { sealTransaction } from '@ckb-lumos/helpers';

import type { IEncodedTxCkb } from '@onekeyhq/core/src/chains/ckb/types';
import coreChainApi from '@onekeyhq/core/src/instance/coreChainApi';
import type { ISignedTxPro } from '@onekeyhq/core/src/types';
import { OneKeyInternalError } from '@onekeyhq/shared/src/errors';
import bufferUtils from '@onekeyhq/shared/src/utils/bufferUtils';

import { KeyringHdBase } from '../../base/KeyringHdBase';

import {
convertTxToTxSkeleton,
serializeTransactionMessage,
} from './utils/transaction';

import type IVaultCkb from './Vault';
import type { IDBAccount } from '../../../dbs/local/types';
import type {
IGetPrivateKeysParams,
Expand All @@ -29,7 +41,38 @@ export class KeyringHd extends KeyringHdBase {
override async signTransaction(
params: ISignTransactionParams,
): Promise<ISignedTxPro> {
return this.baseSignTransaction(params);
const { unsignedTx } = params;
const encodedTx = unsignedTx.encodedTx as IEncodedTxCkb;

const client = await (this.vault as IVaultCkb).getClient();

const txSkeleton = await convertTxToTxSkeleton({
client,
transaction: encodedTx.tx,
});

const { txSkeleton: txSkeletonWithMessage, message } =
serializeTransactionMessage(txSkeleton);

if (!message) {
throw new OneKeyInternalError('Unable to serialize transaction message.');
}

const result = await this.baseSignTransaction({
...params,
unsignedTx: {
...params.unsignedTx,
rawTxUnsigned: message,
},
});

const tx = sealTransaction(txSkeletonWithMessage, [result.rawTx]);
const signedTx = blockchain.Transaction.pack(tx);

return {
...result,
rawTx: bufferUtils.bytesToHex(signedTx),
};
}

override async signMessage(): Promise<string[]> {
Expand Down
Loading

0 comments on commit 50bd33c

Please sign in to comment.