Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support algo, ckb data & fix several issues OK-27484 OK-27478 #4633

Merged
merged 8 commits into from
May 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading