From 0a3681d498c4f964abc0e4e0dc68db7e44acb2bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=A5=E5=9B=BD=E5=AE=87?= <841185308@qq.com> Date: Wed, 19 Jul 2023 00:24:19 +0800 Subject: [PATCH 1/6] chore(CI): Use pr branch for checkout. (#2774) --- .github/workflows/package_for_test.yml | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/.github/workflows/package_for_test.yml b/.github/workflows/package_for_test.yml index e8e7677cca..150df84948 100644 --- a/.github/workflows/package_for_test.yml +++ b/.github/workflows/package_for_test.yml @@ -53,19 +53,11 @@ jobs: uses: actions/checkout@v3 if: ${{ github.event_name == 'push' }} - - name: Get PR Branch - if: github.event_name == 'issue_comment' - id: comment-branch - uses: yanguoyu/pull-request-comment-branch@v2.1.0-beta - with: - repo_token: ${{ secrets.GITHUB_TOKEN }} - - name: Checkout for PR uses: actions/checkout@v3 if: ${{ github.event_name == 'issue_comment' }} with: - repository: ${{ steps.comment-branch.outputs.head_owner }}/${{ steps.comment-branch.outputs.head_repo }} - ref: ${{ steps.comment-branch.outputs.head_ref }} + ref: refs/pull/${{ github.event.issue.number }}/merge - name: Setup Node uses: actions/setup-node@v3 From 92867981659e6baf43dbd2657af231781a118189 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=A5=E5=9B=BD=E5=AE=87?= <841185308@qq.com> Date: Thu, 20 Jul 2023 13:47:54 +0800 Subject: [PATCH 2/6] chore: Use `startsWith` to replace slash-command-action (#2778) --- .github/workflows/package_for_test.yml | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/.github/workflows/package_for_test.yml b/.github/workflows/package_for_test.yml index 150df84948..1a014d36c8 100644 --- a/.github/workflows/package_for_test.yml +++ b/.github/workflows/package_for_test.yml @@ -6,25 +6,8 @@ on: push: jobs: - check_command: - runs-on: ubuntu-latest - ## skip if trigger by issue comment but not pr comment - if: ${{ (github.event_name == 'issue_comment' && github.event.issue.pull_request) || github.event_name == 'push' }} - permissions: - pull-requests: write - steps: - - name: Check for package command - uses: xt0rted/slash-command-action@v1 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - command: package - reaction: "true" - reaction-type: "eyes" - allow-edits: "true" - permission-level: write - packaging: - needs: [check_command] + if: ${{ (github.event_name == 'issue_comment' && github.event.issue.pull_request && startsWith(github.event.comment.body, '/package')) || github.event_name == 'push' }} strategy: matrix: From 3936b8e21e218f73292b167feb4b6f3a43f86aa5 Mon Sep 17 00:00:00 2001 From: Shinya Date: Thu, 20 Jul 2023 13:48:45 +0800 Subject: [PATCH 3/6] fix: address book abbreviation not right (#2775) --- .../src/components/Receive/multiAddressReceive.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/neuron-ui/src/components/Receive/multiAddressReceive.tsx b/packages/neuron-ui/src/components/Receive/multiAddressReceive.tsx index cfa505a8f5..35005a4deb 100644 --- a/packages/neuron-ui/src/components/Receive/multiAddressReceive.tsx +++ b/packages/neuron-ui/src/components/Receive/multiAddressReceive.tsx @@ -88,12 +88,12 @@ const MultiAddressReceive = ({ title: t('addresses.address'), dataIndex: 'address', align: 'left', - render(v: string) { + render(itemAddress: string) { return ( - {v} + + {itemAddress} } @@ -101,9 +101,9 @@ const MultiAddressReceive = ({ isTriggerNextToChild >
- {address.slice(0, -6)} + {itemAddress.slice(0, -6)} ... - {address.slice(-6)} + {itemAddress.slice(-6)}
) From 54c5f67bf55711e321a181ccf7bc728049602cf6 Mon Sep 17 00:00:00 2001 From: Shinya Date: Thu, 20 Jul 2023 13:49:06 +0800 Subject: [PATCH 4/6] Refactor: replace 'HexUtils' with lumos functionalities (#2718) --- .../NervosDAODetail/CellsCard/index.tsx | 10 +- .../src/components/NervosDAODetail/index.tsx | 10 +- packages/neuron-wallet/package.json | 1 + .../sync/light-connector.ts | 6 +- .../src/database/address/meta.ts | 3 +- .../src/models/asset-account-info.ts | 42 ++-- .../neuron-wallet/src/models/chain/input.ts | 4 +- .../src/models/chain/out-point.ts | 4 +- .../neuron-wallet/src/models/chain/output.ts | 7 +- .../neuron-wallet/src/models/chain/script.ts | 14 +- .../src/models/chain/transaction.ts | 4 +- .../src/models/transaction-size.ts | 8 +- .../src/services/hardware/ledger.ts | 19 +- packages/neuron-wallet/src/services/node.ts | 4 +- .../src/services/transaction-sender.ts | 6 +- .../src/services/tx/transaction-generator.ts | 11 +- packages/neuron-wallet/src/utils/hex.ts | 34 --- .../light-connector.test.ts | 220 ++++++++++++------ .../tests/models/chain/block-header.test.ts | 9 +- .../tests/models/transaction-size.test.ts | 4 +- .../tests/services/cells.test.ts | 11 +- .../services/tx/transaction-generator.test.ts | 40 ++-- .../services/tx/transaction-sender.test.ts | 30 ++- 23 files changed, 307 insertions(+), 194 deletions(-) delete mode 100644 packages/neuron-wallet/src/utils/hex.ts diff --git a/packages/neuron-ui/src/components/NervosDAODetail/CellsCard/index.tsx b/packages/neuron-ui/src/components/NervosDAODetail/CellsCard/index.tsx index 2a786ddecc..b9b5e1f709 100644 --- a/packages/neuron-ui/src/components/NervosDAODetail/CellsCard/index.tsx +++ b/packages/neuron-ui/src/components/NervosDAODetail/CellsCard/index.tsx @@ -11,10 +11,12 @@ import LockInfoDialog from 'components/LockInfoDialog' import { useState as useGlobalState } from 'states' import styles from './cellsCard.module.scss' -const TabsVariantWithCellsCard: FC> = ({ tabs, selectedTab, onTabChange }) => { +const TabsVariantWithCellsCard: FC< + VariantProps<{ + title: string + cells: (State.DetailedInput | State.DetailedOutput)[] + }> +> = ({ tabs, selectedTab, onTabChange }) => { const [t] = useTranslation() const { chain: { networkID }, diff --git a/packages/neuron-ui/src/components/NervosDAODetail/index.tsx b/packages/neuron-ui/src/components/NervosDAODetail/index.tsx index e8f0b421e4..712274d0ac 100644 --- a/packages/neuron-ui/src/components/NervosDAODetail/index.tsx +++ b/packages/neuron-ui/src/components/NervosDAODetail/index.tsx @@ -24,10 +24,12 @@ import styles from './nervosDAODetail.module.scss' import hooks from './hooks' import CellsCard from './CellsCard' -const TabsVariantWithTxTypes: FC> = ({ tabs, selectedTab, onTabChange }) => { +const TabsVariantWithTxTypes: FC< + VariantProps<{ + title: string + hash: string + }> +> = ({ tabs, selectedTab, onTabChange }) => { const [t] = useTranslation() const [transaction, setTransaction] = useState(transactionState) const [error, setError] = useState() diff --git a/packages/neuron-wallet/package.json b/packages/neuron-wallet/package.json index c9860150b8..5a95b76015 100644 --- a/packages/neuron-wallet/package.json +++ b/packages/neuron-wallet/package.json @@ -38,6 +38,7 @@ }, "dependencies": { "@ckb-lumos/base": "0.20.0-alpha.3", + "@ckb-lumos/bi": "0.20.0-alpha.3", "@ckb-lumos/ckb-indexer": "0.20.0-alpha.3", "@ckb-lumos/codec": "0.20.0-alpha.3", "@ckb-lumos/rpc": "0.20.0-alpha.3", diff --git a/packages/neuron-wallet/src/block-sync-renderer/sync/light-connector.ts b/packages/neuron-wallet/src/block-sync-renderer/sync/light-connector.ts index 5cf8ed6625..86c145809e 100644 --- a/packages/neuron-wallet/src/block-sync-renderer/sync/light-connector.ts +++ b/packages/neuron-wallet/src/block-sync-renderer/sync/light-connector.ts @@ -1,3 +1,4 @@ +import { BI } from '@ckb-lumos/bi' import { Subject } from 'rxjs' import { queue, QueueObject } from 'async' import { HexString, QueryOptions } from '@ckb-lumos/base' @@ -10,7 +11,6 @@ import SyncProgressService from '../../services/sync-progress' import { BlockTips, LumosCellQuery, Connector, AppendScript } from './connector' import { scriptToHash } from '@nervosnetwork/ckb-sdk-utils' import { FetchTransactionReturnType, LightRPC, LightScriptFilter } from '../../utils/ckb-rpc' -import HexUtils from '../../utils/hex' import Multisig from '../../services/multisig' import { SyncAddressType } from '../../database/chain/entities/sync-progress' import WalletService from '../../services/wallets' @@ -118,7 +118,7 @@ export default class LightConnector extends Connector { hashType: v.hashType, args: v.args, }, - blockRange: [HexUtils.toHex(v.blockStartNumber), HexUtils.toHex(v.blockEndNumber)], + blockRange: [BI.from(v.blockStartNumber).toHexString(), BI.from(v.blockEndNumber).toHexString()], scriptType: v.scriptType, cursor: v.cursor, }) @@ -135,7 +135,7 @@ export default class LightConnector extends Connector { ) { this.syncQueue.push({ script: syncScript.script, - blockRange: [HexUtils.toHex(syncStatus.blockEndNumber), syncScript.blockNumber], + blockRange: [BI.from(syncStatus.blockEndNumber).toHexString(), syncScript.blockNumber], scriptType: syncScript.scriptType, cursor: undefined, }) diff --git a/packages/neuron-wallet/src/database/address/meta.ts b/packages/neuron-wallet/src/database/address/meta.ts index 56f2c05a1b..3fd8f99abc 100644 --- a/packages/neuron-wallet/src/database/address/meta.ts +++ b/packages/neuron-wallet/src/database/address/meta.ts @@ -1,3 +1,4 @@ +import { bytes } from '@ckb-lumos/codec' import { Address, AddressVersion } from '../../models/address' import { AddressType } from '../../models/keys/address' import Script from '../../models/chain/script' @@ -116,6 +117,6 @@ export default class AddressMeta implements Address { public generateChequeLockScriptWithReceiverLockHash(): Script { const defaultLockScript = this.generateDefaultLockScript() const assetAccountInfo = new AssetAccountInfo() - return assetAccountInfo.generateChequeScript(defaultLockScript.computeHash(), '0'.repeat(40)) + return assetAccountInfo.generateChequeScript(defaultLockScript.computeHash(), bytes.hexify(Buffer.alloc(20))) } } diff --git a/packages/neuron-wallet/src/models/asset-account-info.ts b/packages/neuron-wallet/src/models/asset-account-info.ts index dac6d3722a..af97883dad 100644 --- a/packages/neuron-wallet/src/models/asset-account-info.ts +++ b/packages/neuron-wallet/src/models/asset-account-info.ts @@ -1,11 +1,12 @@ +import { bytes, molecule } from '@ckb-lumos/codec' import CellDep, { DepType } from './chain/cell-dep' import Script, { ScriptHashType } from './chain/script' import OutPoint from './chain/out-point' import NetworksService from '../services/networks' import Transaction from './chain/transaction' -import HexUtils from '../utils/hex' import SystemScriptInfo from './system-script-info' import { Address } from './address' +import { createFixedHexBytesCodec } from '@ckb-lumos/codec/lib/blockchain' export interface ScriptCellInfo { cellDep: CellDep @@ -244,9 +245,7 @@ export default class AssetAccountInfo { } public generateChequeScript(receiverLockHash: string, senderLockHash: string): Script { - const receiverLockHash20 = HexUtils.removePrefix(receiverLockHash).slice(0, 40) - const senderLockHash20 = HexUtils.removePrefix(senderLockHash).slice(0, 40) - const args = `0x${receiverLockHash20}${senderLockHash20}` + const args = bytes.hexify(bytes.concat(receiverLockHash.slice(0, 42), senderLockHash.slice(0, 42))) const info = this.chequeInfo return new Script(info.codeHash, args, info.hashType) } @@ -286,20 +285,31 @@ export default class AssetAccountInfo { } public static findSignPathForCheque(addressInfos: Address[], chequeLockArgs: string) { - const receiverLockHash = HexUtils.removePrefix(chequeLockArgs).slice(0, 40) - const senderLockHash = HexUtils.removePrefix(chequeLockArgs).slice(40) + const Bytes20 = createFixedHexBytesCodec(20) + const ChequeLockArgsCodec = molecule.struct( + { + receiverLockHash: Bytes20, + senderLockHash: Bytes20, + }, + ['receiverLockHash', 'senderLockHash'] + ) - for (const lockHash20 of [receiverLockHash, senderLockHash]) { - const foundAddressInfo = addressInfos.find(info => { - const defaultLockScript = SystemScriptInfo.generateSecpScript(info.blake160) - const addressLockHash20 = HexUtils.removePrefix(defaultLockScript.computeHash()).slice(0, 40) - return lockHash20 === addressLockHash20 - }) - if (foundAddressInfo) { - return foundAddressInfo - } + const { receiverLockHash, senderLockHash } = ChequeLockArgsCodec.unpack(chequeLockArgs) + + const foundReceiver = addressInfos.find(info => { + const target = bytes.bytify(SystemScriptInfo.generateSecpScript(info.blake160).computeHash()).slice(0, 20) + return bytes.equal(target, receiverLockHash) + }) + + if (foundReceiver) { + return foundReceiver } - return null + const foundSender = addressInfos.find(info => { + const target = bytes.bytify(SystemScriptInfo.generateSecpScript(info.blake160).computeHash()).slice(0, 20) + return bytes.equal(target, senderLockHash) + }) + + return foundSender || null } } diff --git a/packages/neuron-wallet/src/models/chain/input.ts b/packages/neuron-wallet/src/models/chain/input.ts index ec3dacece7..9c00015ede 100644 --- a/packages/neuron-wallet/src/models/chain/input.ts +++ b/packages/neuron-wallet/src/models/chain/input.ts @@ -1,6 +1,6 @@ import OutPoint from './out-point' import Script from './script' -import HexUtils from '../../utils/hex' +import { BI } from '@ckb-lumos/bi' import TypeChecker from '../../utils/type-checker' export default class Input { @@ -112,7 +112,7 @@ export default class Input { public toSDK(): CKBComponents.CellInput { return { - since: HexUtils.toHex(this.since!), + since: BI.from(this.since || 0).toHexString(), previousOutput: this.previousOutput?.toSDK() || null, } } diff --git a/packages/neuron-wallet/src/models/chain/out-point.ts b/packages/neuron-wallet/src/models/chain/out-point.ts index 1f889e7f16..4b7f050791 100644 --- a/packages/neuron-wallet/src/models/chain/out-point.ts +++ b/packages/neuron-wallet/src/models/chain/out-point.ts @@ -1,4 +1,4 @@ -import HexUtils from '../../utils/hex' +import { BI } from '@ckb-lumos/bi' import TypeChecker from '../../utils/type-checker' export default class OutPoint { @@ -21,7 +21,7 @@ export default class OutPoint { public toSDK(): CKBComponents.OutPoint { return { txHash: this.txHash, - index: HexUtils.toHex(this.index), + index: BI.from(this.index).toHexString(), } } diff --git a/packages/neuron-wallet/src/models/chain/output.ts b/packages/neuron-wallet/src/models/chain/output.ts index 071a3f24e3..5a8e2f568f 100644 --- a/packages/neuron-wallet/src/models/chain/output.ts +++ b/packages/neuron-wallet/src/models/chain/output.ts @@ -1,6 +1,7 @@ import Script from './script' import OutPoint from './out-point' -import HexUtils from '../../utils/hex' +import { bytes as byteUtils } from '@ckb-lumos/codec' +import { BI } from '@ckb-lumos/bi' import TypeChecker from '../../utils/type-checker' // sent: pending transaction's output @@ -203,7 +204,7 @@ export default class Output { } public calculateBytesize(): number { - let bytesize = 8 + HexUtils.byteLength(this.data) + this.lock.calculateBytesize() + let bytesize = 8 + byteUtils.bytify(this.data).byteLength + this.lock.calculateBytesize() if (this.type) { bytesize += this.type.calculateBytesize() } @@ -212,7 +213,7 @@ export default class Output { public toSDK(): CKBComponents.CellOutput { return { - capacity: HexUtils.toHex(this.capacity), + capacity: BI.from(this.capacity).toHexString(), lock: this.lock.toSDK(), type: this.type ? this.type.toSDK() : this.type, } diff --git a/packages/neuron-wallet/src/models/chain/script.ts b/packages/neuron-wallet/src/models/chain/script.ts index 09a341e039..609b8802c0 100644 --- a/packages/neuron-wallet/src/models/chain/script.ts +++ b/packages/neuron-wallet/src/models/chain/script.ts @@ -1,5 +1,5 @@ import { scriptToHash } from '@nervosnetwork/ckb-sdk-utils' -import HexUtils from '../../utils/hex' +import { bytes as byteUtils } from '@ckb-lumos/codec' import TypeChecker from '../../utils/type-checker' export enum ScriptHashType { @@ -34,12 +34,18 @@ export default class Script { } public computeHash(): string { - const hash: string = scriptToHash(this.toSDK()) - return HexUtils.addPrefix(hash) + return scriptToHash(this.toSDK()) } + /** + * @deprecated please move to `calculateOccupiedByteSize` + */ public calculateBytesize(): number { - return 1 + HexUtils.byteLength(this.codeHash) + HexUtils.byteLength(this.args) + return this.calculateOccupiedByteSize() + } + + public calculateOccupiedByteSize(): number { + return 1 + byteUtils.concat(this.args, this.codeHash).byteLength } public toSDK(): CKBComponents.Script { diff --git a/packages/neuron-wallet/src/models/chain/transaction.ts b/packages/neuron-wallet/src/models/chain/transaction.ts index d128270a8f..b78f59d5ae 100644 --- a/packages/neuron-wallet/src/models/chain/transaction.ts +++ b/packages/neuron-wallet/src/models/chain/transaction.ts @@ -2,7 +2,7 @@ import CellDep from './cell-dep' import Input from './input' import Output from './output' import WitnessArgs from './witness-args' -import HexUtils from '../../utils/hex' +import { BI } from '@ckb-lumos/bi' import { serializeWitnessArgs, rawTransactionToHash } from '@nervosnetwork/ckb-sdk-utils' import BlockHeader from './block-header' import TypeCheckerUtils from '../../utils/type-checker' @@ -273,7 +273,7 @@ export default class Transaction { public toSDKRawTransaction(): CKBComponents.RawTransaction { return { - version: HexUtils.toHex(this.version), + version: BI.from(this.version).toHexString(), inputs: this.inputs.map(i => i.toSDK()), outputs: this.outputs.map(o => o.toSDK()), cellDeps: this.cellDeps.map(cd => cd.toSDK()), diff --git a/packages/neuron-wallet/src/models/transaction-size.ts b/packages/neuron-wallet/src/models/transaction-size.ts index 4bdca0deb3..61832d221c 100644 --- a/packages/neuron-wallet/src/models/transaction-size.ts +++ b/packages/neuron-wallet/src/models/transaction-size.ts @@ -1,5 +1,4 @@ import { serializeOutput, serializeWitnessArgs } from '@nervosnetwork/ckb-sdk-utils/lib/serialization/transaction' -import HexUtils from '../utils/hex' import { serializeFixVec } from '@nervosnetwork/ckb-sdk-utils/lib/serialization' import Output from './chain/output' import WitnessArgs from './chain/witness-args' @@ -7,6 +6,7 @@ import Transaction from './chain/transaction' import Multisig from './multisig' import Script, { ScriptHashType } from './chain/script' import BufferUtils from '../utils/buffer' +import { bytes as byteUtils } from '@ckb-lumos/codec' export default class TransactionSize { public static SERIALIZED_OFFSET_BYTESIZE = 4 @@ -29,7 +29,7 @@ export default class TransactionSize { public static output(output: Output): number { const bytes = serializeOutput(output.toSDK()) - return HexUtils.byteLength(bytes) + TransactionSize.SERIALIZED_OFFSET_BYTESIZE + return byteUtils.bytify(bytes).byteLength + TransactionSize.SERIALIZED_OFFSET_BYTESIZE } public static ckbAnyoneCanPayOutput(): number { @@ -56,7 +56,7 @@ export default class TransactionSize { public static outputData(data: string): number { const bytes = serializeFixVec(data) - return HexUtils.byteLength(bytes) + TransactionSize.SERIALIZED_OFFSET_BYTESIZE + return byteUtils.bytify(bytes).byteLength + TransactionSize.SERIALIZED_OFFSET_BYTESIZE } // TODO: and here @@ -68,7 +68,7 @@ export default class TransactionSize { public static witness(witness: WitnessArgs | string): number { const wit: string = typeof witness === 'string' ? witness : serializeWitnessArgs(witness.toSDK()) const bytes = serializeFixVec(wit) - return HexUtils.byteLength(bytes) + TransactionSize.SERIALIZED_OFFSET_BYTESIZE + return byteUtils.bytify(bytes).byteLength + TransactionSize.SERIALIZED_OFFSET_BYTESIZE } public static secpLockWitness(): number { diff --git a/packages/neuron-wallet/src/services/hardware/ledger.ts b/packages/neuron-wallet/src/services/hardware/ledger.ts index 7620b19a46..6366cd1494 100644 --- a/packages/neuron-wallet/src/services/hardware/ledger.ts +++ b/packages/neuron-wallet/src/services/hardware/ledger.ts @@ -9,7 +9,6 @@ import { takeUntil, filter, scan } from 'rxjs/operators' import Transaction from '../../models/chain/transaction' import NodeService from '../../services/node' import Address, { AddressType } from '../../models/keys/address' -import HexUtils from '../../utils/hex' import logger from '../../utils/logger' import NetworksService from '../../services/networks' import { generateRPC } from '../../utils/ckb-rpc' @@ -76,13 +75,13 @@ export default class Ledger extends Hardware { } async signMessage(path: string, messageHex: string) { - const message = HexUtils.removePrefix(messageHex) + const message = this.removePrefix(messageHex) const signed = await this.ledgerCKB!.signMessage( path === Address.pathForReceiving(0) ? this.defaultPath : path, message, false ) - return HexUtils.addPrefix(signed) + return this.addPrefix(signed) } async getAppVersion(): Promise { @@ -149,4 +148,18 @@ export default class Ledger extends Hardware { .catch(() => [] as DeviceInfo[]) ) } + + private removePrefix(hex: string): string { + if (hex.startsWith('0x')) { + return hex.slice(2) + } + return hex + } + + private addPrefix(hex: string): string { + if (hex.startsWith('0x')) { + return hex + } + return `0x${hex}` + } } diff --git a/packages/neuron-wallet/src/services/node.ts b/packages/neuron-wallet/src/services/node.ts index b8e38df6d3..c998d5331b 100644 --- a/packages/neuron-wallet/src/services/node.ts +++ b/packages/neuron-wallet/src/services/node.ts @@ -1,5 +1,6 @@ import fs from 'fs' import path from 'path' +import { BI } from '@ckb-lumos/bi' import { app as electronApp, dialog, shell } from 'electron' import { t } from 'i18next' import { interval, BehaviorSubject, merge } from 'rxjs' @@ -17,7 +18,6 @@ import logger from '../utils/logger' import redistCheck from '../utils/redist-check' import { rpcRequest } from '../utils/rpc-request' import { generateRPC } from '../utils/ckb-rpc' -import HexUtils from '..//utils/hex' import startMonitor from './monitor' import { CKBLightRunner } from './light-runner' @@ -119,7 +119,7 @@ class NodeService { if (!this.delayTime) { this.delayTime = 0 } - const tip: string = HexUtils.toDecimal(tipNumber) + const tip: string = BI.from(tipNumber).toString() this._tipBlockNumber = tip this.tipNumberSubject.next(tip) }, diff --git a/packages/neuron-wallet/src/services/transaction-sender.ts b/packages/neuron-wallet/src/services/transaction-sender.ts index beb800eacf..b82f87a6c4 100644 --- a/packages/neuron-wallet/src/services/transaction-sender.ts +++ b/packages/neuron-wallet/src/services/transaction-sender.ts @@ -21,7 +21,7 @@ import Script from '../models/chain/script' import Multisig from '../models/multisig' import Blake2b from '../models/blake2b' import logger from '../utils/logger' -import HexUtils from '../utils/hex' +import { bytes as byteUtils } from '@ckb-lumos/codec' import SystemScriptInfo from '../models/system-script-info' import AddressParser from '../models/address-parser' import HardwareWalletService from './hardware' @@ -400,7 +400,7 @@ export default class TransactionSender { lock: `0x` + serializedMultiSign.slice(2) + '0'.repeat(130 * m), }) const serializedEmptyWitness = serializeWitnessArgs(emptyWitness.toSDK()) - const serializedEmptyWitnessSize = HexUtils.byteLength(serializedEmptyWitness) + const serializedEmptyWitnessSize = byteUtils.bytify(serializedEmptyWitness).byteLength const blake2b = new Blake2b() blake2b.update(txHash) blake2b.update(toUint64Le(`0x${serializedEmptyWitnessSize.toString(16)}`)) @@ -408,7 +408,7 @@ export default class TransactionSender { restWitnesses.forEach(w => { const wit: string = typeof w === 'string' ? w : serializeWitnessArgs(w.toSDK()) - const byteLength = HexUtils.byteLength(wit) + const byteLength = byteUtils.bytify(wit).byteLength blake2b.update(toUint64Le(`0x${byteLength.toString(16)}`)) blake2b.update(wit) }) diff --git a/packages/neuron-wallet/src/services/tx/transaction-generator.ts b/packages/neuron-wallet/src/services/tx/transaction-generator.ts index 701a726e92..99c0dfc867 100644 --- a/packages/neuron-wallet/src/services/tx/transaction-generator.ts +++ b/packages/neuron-wallet/src/services/tx/transaction-generator.ts @@ -1,3 +1,4 @@ +import { bytes } from '@ckb-lumos/codec' import CellsService from '../../services/cells' import { CapacityTooSmall, @@ -713,7 +714,7 @@ export class TransactionGenerator { public static async generateDestroyAssetAccountTx( walletId: string, - asssetAccountInputs: Input[], + assetAccountInputs: Input[], changeBlake160: string, isCKBAccount: boolean ) { @@ -721,7 +722,7 @@ export class TransactionGenerator { const assetAccountInfo = new AssetAccountInfo() const cellDeps = [secpCellDep, assetAccountInfo.anyoneCanPayCellDep] - if (asssetAccountInputs.some(v => v.type && v.data !== '0x' && BigInt(v.data || 0) !== BigInt(0))) { + if (assetAccountInputs.some(v => v.type && v.data !== '0x' && BigInt(v.data || 0) !== BigInt(0))) { throw new SudtAcpHaveDataError() } if (!isCKBAccount) { @@ -737,13 +738,13 @@ export class TransactionGenerator { version: '0', headerDeps: [], cellDeps, - inputs: asssetAccountInputs, + inputs: assetAccountInputs, outputs: [output], outputsData: [output.data], witnesses: [], }) - let allCapacities = asssetAccountInputs.reduce((a, b) => { + let allCapacities = assetAccountInputs.reduce((a, b) => { return a + BigInt(b.capacity as string) }, BigInt(0)) tx.fee = TransactionFee.fee(TransactionSize.tx(tx), BigInt(1e4)).toString() @@ -1026,7 +1027,7 @@ export class TransactionGenerator { const chequeCellTmp = Output.fromObject({ capacity: BigInt(162 * 10 ** 8).toString(), - lock: assetAccountInfo.generateChequeScript('0'.repeat(40), '0'.repeat(40)), + lock: assetAccountInfo.generateChequeScript(bytes.hexify(Buffer.alloc(20)), bytes.hexify(Buffer.alloc(20))), type: assetAccountInfo.generateSudtScript(assetAccount.tokenID), }) diff --git a/packages/neuron-wallet/src/utils/hex.ts b/packages/neuron-wallet/src/utils/hex.ts deleted file mode 100644 index 9f3cdf3d63..0000000000 --- a/packages/neuron-wallet/src/utils/hex.ts +++ /dev/null @@ -1,34 +0,0 @@ -export default class HexUtils { - public static toDecimal(hex: string): string { - return BigInt(hex).toString() - } - - public static toHex(num: string | number, padStartCount: number = 0): string { - if (typeof num === 'string' && num.startsWith('0x')) { - return num - } - return `0x${(typeof num === 'string' ? BigInt(num) : num).toString(16).padStart(padStartCount, '0')}` - } - - public static removePrefix(hex: string): string { - if (hex.startsWith('0x')) { - return hex.slice(2) - } - return hex - } - - public static addPrefix(hex: string): string { - if (hex.startsWith('0x')) { - return hex - } - return `0x${hex}` - } - - public static byteLength(hex: string): number { - return Buffer.byteLength(HexUtils.removePrefix(hex), 'hex') - } - - public static fromBuffer(buffer: Buffer): string { - return '0x' + buffer.toString('hex') - } -} diff --git a/packages/neuron-wallet/tests/block-sync-renderer/light-connector.test.ts b/packages/neuron-wallet/tests/block-sync-renderer/light-connector.test.ts index 779a7f366e..34f574438c 100644 --- a/packages/neuron-wallet/tests/block-sync-renderer/light-connector.test.ts +++ b/packages/neuron-wallet/tests/block-sync-renderer/light-connector.test.ts @@ -1,7 +1,7 @@ import { scriptToHash } from '@nervosnetwork/ckb-sdk-utils' import LightConnector from '../../src/block-sync-renderer/sync/light-connector' import SyncProgress from '../../src/database/chain/entities/sync-progress' -import HexUtils from '../../src/utils/hex' +import { BI } from '@ckb-lumos/bi' import AddressMeta from '../../src/database/address/meta' const getSyncStatusMock = jest.fn() @@ -56,13 +56,15 @@ jest.mock('../../src/services/sync-progress', () => { static updateSyncStatus: any = (hash: string, update: any) => updateSyncStatusMock(hash, update) static updateSyncProgressFlag: any = (walletIds: string[]) => updateSyncProgressFlagMock(walletIds) static getWalletMinBlockNumber: any = () => getWalletMinBlockNumberMock() - static removeByHashesAndAddressType: any = (type: number, scripts: CKBComponents.Script[]) => removeByHashesAndAddressType(type, scripts) + static removeByHashesAndAddressType: any = (type: number, scripts: CKBComponents.Script[]) => + removeByHashesAndAddressType(type, scripts) + static getOtherTypeSyncProgress: any = () => getOtherTypeSyncProgressMock() } }) jest.mock('../../src/utils/ckb-rpc', () => ({ - LightRPC: function() { + LightRPC: function () { return { setScripts: setScriptsMock, getScripts: getScriptsMock, @@ -70,11 +72,11 @@ jest.mock('../../src/utils/ckb-rpc', () => ({ getTransactions: getTransactionsMock, createBatchRequest: () => ({ exec: createBatchRequestMock }), } - } + }, })) jest.mock('../../src/services/multisig', () => ({ - getMultisigConfigForLight: () => getMultisigConfigForLightMock() + getMultisigConfigForLight: () => getMultisigConfigForLightMock(), })) jest.mock('../../src/services/wallets', () => ({ @@ -83,19 +85,19 @@ jest.mock('../../src/services/wallets', () => ({ getCurrent: walletGetCurrentMock, getAll: walletGetAllMock, } - } + }, })) jest.mock('timers/promises', () => ({ scheduler: { wait: (delay: number) => schedulerWaitMock(delay), - } + }, })) const script: CKBComponents.Script = { args: '0x403f0d4e833b2a8d372772a63facaa310dfeef92', codeHash: '0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8', - hashType: 'type' + hashType: 'type', } const scriptHash = scriptToHash(script) const address = 'ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsq2q8ux5aqem92xnwfmj5cl6e233phlwlysqhjx5w' @@ -135,7 +137,7 @@ describe('test light connector', () => { const syncProgress = SyncProgress.fromObject({ script, scriptType: 'lock', - walletId: 'walletId1' + walletId: 'walletId1', }) syncProgress.blockStartNumber = 0 syncProgress.blockEndNumber = 1 @@ -152,11 +154,14 @@ describe('test light connector', () => { script: { codeHash: syncProgress.codeHash, hashType: syncProgress.hashType, - args: syncProgress.args + args: syncProgress.args, }, - blockRange: [HexUtils.toHex(syncProgress.blockStartNumber), HexUtils.toHex(syncProgress.blockEndNumber)], + blockRange: [ + BI.from(syncProgress.blockStartNumber).toHexString(), + BI.from(syncProgress.blockEndNumber).toHexString(), + ], scriptType: syncProgress.scriptType, - cursor: syncProgress.cursor + cursor: syncProgress.cursor, }) }) it('some script sync cursor is not empty but is in sync queue', async () => { @@ -164,7 +169,7 @@ describe('test light connector', () => { const syncProgress = SyncProgress.fromObject({ script, scriptType: 'lock', - walletId: 'walletId1' + walletId: 'walletId1', }) syncProgress.blockStartNumber = 0 syncProgress.blockEndNumber = 1 @@ -183,15 +188,17 @@ describe('test light connector', () => { expect(connector.syncQueue.length()).toBe(0) }) it('some script sync to new block', async () => { - getScriptsMock.mockResolvedValue([{ - script, - scriptType: 'lock', - blockNumber: '0xaa' - }]) + getScriptsMock.mockResolvedValue([ + { + script, + scriptType: 'lock', + blockNumber: '0xaa', + }, + ]) const syncProgress = SyncProgress.fromObject({ script, scriptType: 'lock', - walletId: 'walletId1' + walletId: 'walletId1', }) syncProgress.blockStartNumber = 0 syncProgress.blockEndNumber = 1 @@ -207,39 +214,41 @@ describe('test light connector', () => { script: { codeHash: syncProgress.codeHash, hashType: syncProgress.hashType, - args: syncProgress.args + args: syncProgress.args, }, - blockRange: [HexUtils.toHex(syncProgress.blockEndNumber), HexUtils.toHex('0xaa')], + blockRange: [BI.from(syncProgress.blockEndNumber).toHexString(), BI.from('0xaa').toHexString()], scriptType: syncProgress.scriptType, - cursor: syncProgress.cursor + cursor: syncProgress.cursor, }) }), - it('some script sync to new block but is in sync queue', async () => { - getScriptsMock.mockResolvedValue([{ - script, - scriptType: 'lock', - blockNumber: '0xaa' - }]) - const syncProgress = SyncProgress.fromObject({ - script, - scriptType: 'lock', - walletId: 'walletId1' + it('some script sync to new block but is in sync queue', async () => { + getScriptsMock.mockResolvedValue([ + { + script, + scriptType: 'lock', + blockNumber: '0xaa', + }, + ]) + const syncProgress = SyncProgress.fromObject({ + script, + scriptType: 'lock', + walletId: 'walletId1', + }) + syncProgress.blockStartNumber = 0 + syncProgress.blockEndNumber = 1 + getAllSyncStatusToMapMock.mockResolvedValue(new Map([[scriptHash, syncProgress]])) + const connector = new LightConnector([], '') + // @ts-ignore: private-method + connector.syncInQueue.set(scriptHash, {}) + // @ts-ignore: private-method + connector.subscribeSync = jest.fn() + // @ts-ignore: private-method + connector.syncQueue.pause() + // @ts-ignore: private-method + await connector.synchronize() + // @ts-ignore: private-method + expect(connector.syncQueue.length()).toBe(0) }) - syncProgress.blockStartNumber = 0 - syncProgress.blockEndNumber = 1 - getAllSyncStatusToMapMock.mockResolvedValue(new Map([[scriptHash, syncProgress]])) - const connector = new LightConnector([], '') - // @ts-ignore: private-method - connector.syncInQueue.set(scriptHash, {}) - // @ts-ignore: private-method - connector.subscribeSync = jest.fn() - // @ts-ignore: private-method - connector.syncQueue.pause() - // @ts-ignore: private-method - await connector.synchronize() - // @ts-ignore: private-method - expect(connector.syncQueue.length()).toBe(0) - }) }) describe('test subscribeSync', () => { @@ -254,7 +263,7 @@ describe('test light connector', () => { // @ts-ignore: private-method expect(connector.blockTipsSubject.next).toBeCalledWith({ cacheTipNumber: 100, - indexerTipNumber: 170 + indexerTipNumber: 170, }) }) }) @@ -273,19 +282,41 @@ describe('test light connector', () => { await connect.initSyncProgress([{ walletId: 'walletId', script, addressType: 1, scriptType: 'lock' }]) expect(getScriptsMock).toBeCalledTimes(1) expect(setScriptsMock).toBeCalledWith([ - { script, scriptType: 'lock', walletId: 'walletId', blockNumber: '0x0', addressType: 1, }, + { script, scriptType: 'lock', walletId: 'walletId', blockNumber: '0x0', addressType: 1 }, ]) }) it('there is not exist sync scripts with light client', async () => { getScriptsMock.mockResolvedValue([{ script, blockNumber: '0xaa' }]) - const addressMeta = AddressMeta.fromObject({ walletId: 'walletId', address, path: '', addressIndex: 10, addressType: 0, blake160: script.args }) + const addressMeta = AddressMeta.fromObject({ + walletId: 'walletId', + address, + path: '', + addressIndex: 10, + addressType: 0, + blake160: script.args, + }) const connect = new LightConnector([addressMeta], '') //@ts-ignore await connect.initSyncProgress() expect(setScriptsMock).toBeCalledWith([ - { script: addressMeta.generateDefaultLockScript().toSDK(), scriptType: 'lock', walletId: 'walletId', blockNumber: '0xaa' }, - { script: addressMeta.generateACPLockScript().toSDK(), scriptType: 'lock', walletId: 'walletId', blockNumber: '0x0' }, - { script: addressMeta.generateLegacyACPLockScript().toSDK(), scriptType: 'lock', walletId: 'walletId', blockNumber: '0x0' }, + { + script: addressMeta.generateDefaultLockScript().toSDK(), + scriptType: 'lock', + walletId: 'walletId', + blockNumber: '0xaa', + }, + { + script: addressMeta.generateACPLockScript().toSDK(), + scriptType: 'lock', + walletId: 'walletId', + blockNumber: '0x0', + }, + { + script: addressMeta.generateLegacyACPLockScript().toSDK(), + scriptType: 'lock', + walletId: 'walletId', + blockNumber: '0x0', + }, ]) expect(resetSyncProgressMock).toBeCalledWith([ { script: addressMeta.generateDefaultLockScript().toSDK(), scriptType: 'lock', walletId: 'walletId' }, @@ -296,29 +327,73 @@ describe('test light connector', () => { }) it('set new script with the synced min block number', async () => { getScriptsMock.mockResolvedValue([]) - const addressMeta = AddressMeta.fromObject({ walletId: 'walletId', address, path: '', addressIndex: 10, addressType: 0, blake160: script.args }) - getWalletMinBlockNumberMock.mockResolvedValue({ 'walletId': 170}) + const addressMeta = AddressMeta.fromObject({ + walletId: 'walletId', + address, + path: '', + addressIndex: 10, + addressType: 0, + blake160: script.args, + }) + getWalletMinBlockNumberMock.mockResolvedValue({ walletId: 170 }) const connect = new LightConnector([addressMeta], '') //@ts-ignore await connect.initSyncProgress() expect(setScriptsMock).toBeCalledWith([ - { script: addressMeta.generateDefaultLockScript().toSDK(), scriptType: 'lock', walletId: 'walletId', blockNumber: '0xaa' }, - { script: addressMeta.generateACPLockScript().toSDK(), scriptType: 'lock', walletId: 'walletId', blockNumber: '0xaa' }, - { script: addressMeta.generateLegacyACPLockScript().toSDK(), scriptType: 'lock', walletId: 'walletId', blockNumber: '0xaa' }, + { + script: addressMeta.generateDefaultLockScript().toSDK(), + scriptType: 'lock', + walletId: 'walletId', + blockNumber: '0xaa', + }, + { + script: addressMeta.generateACPLockScript().toSDK(), + scriptType: 'lock', + walletId: 'walletId', + blockNumber: '0xaa', + }, + { + script: addressMeta.generateLegacyACPLockScript().toSDK(), + scriptType: 'lock', + walletId: 'walletId', + blockNumber: '0xaa', + }, ]) }) it('set new script with start block number in wallet', async () => { getScriptsMock.mockResolvedValue([]) - const addressMeta = AddressMeta.fromObject({ walletId: 'walletId', address, path: '', addressIndex: 10, addressType: 0, blake160: script.args }) + const addressMeta = AddressMeta.fromObject({ + walletId: 'walletId', + address, + path: '', + addressIndex: 10, + addressType: 0, + blake160: script.args, + }) getWalletMinBlockNumberMock.mockResolvedValue({}) walletGetAllMock.mockReturnValue([{ id: 'walletId', startBlockNumberInLight: '0xaa' }]) const connect = new LightConnector([addressMeta], '') //@ts-ignore await connect.initSyncProgress() expect(setScriptsMock).toBeCalledWith([ - { script: addressMeta.generateDefaultLockScript().toSDK(), scriptType: 'lock', walletId: 'walletId', blockNumber: '0xaa' }, - { script: addressMeta.generateACPLockScript().toSDK(), scriptType: 'lock', walletId: 'walletId', blockNumber: '0xaa' }, - { script: addressMeta.generateLegacyACPLockScript().toSDK(), scriptType: 'lock', walletId: 'walletId', blockNumber: '0xaa' }, + { + script: addressMeta.generateDefaultLockScript().toSDK(), + scriptType: 'lock', + walletId: 'walletId', + blockNumber: '0xaa', + }, + { + script: addressMeta.generateACPLockScript().toSDK(), + scriptType: 'lock', + walletId: 'walletId', + blockNumber: '0xaa', + }, + { + script: addressMeta.generateLegacyACPLockScript().toSDK(), + scriptType: 'lock', + walletId: 'walletId', + blockNumber: '0xaa', + }, ]) }) }) @@ -362,8 +437,17 @@ describe('test light connector', () => { const connect = new LightConnector([], '') //@ts-ignore await connect.syncNextWithScript({ script, scriptType: 'lock', blockRange: ['0xaa', '0xbb'] }) - expect(getTransactionsMock).toBeCalledWith({ script, blockRange: ['0xaa', '0xbb'], scriptType: 'lock' }, 'asc', '0x64', undefined) - expect(updateSyncStatusMock).toBeCalledWith(scriptHash, { blockStartNumber: 187, blockEndNumber: 187, cursor: undefined }) + expect(getTransactionsMock).toBeCalledWith( + { script, blockRange: ['0xaa', '0xbb'], scriptType: 'lock' }, + 'asc', + '0x64', + undefined + ) + expect(updateSyncStatusMock).toBeCalledWith(scriptHash, { + blockStartNumber: 187, + blockEndNumber: 187, + cursor: undefined, + }) }) it('there are some txs in blockRange but no more', async () => { const syncProgress = SyncProgress.fromObject({ script, scriptType: 'lock', walletId: 'walletId' }) @@ -421,7 +505,9 @@ describe('test light connector', () => { const connect = new LightConnector([], '') //@ts-ignore connect.initSync = mockFn - mockFn.mockImplementation(() => { throw new Error('error') }) + mockFn.mockImplementation(() => { + throw new Error('error') + }) expect(connect.connect()).rejects.toThrowError(new Error('error')) }) }) @@ -438,7 +524,7 @@ describe('test light connector', () => { }) describe('test notifyCurrentBlockNumberProcessed', () => { - it ('hash is not in syncInQueue', async () => { + it('hash is not in syncInQueue', async () => { const connect = new LightConnector([], '') const mockFn = jest.fn() //@ts-ignore @@ -447,7 +533,7 @@ describe('test light connector', () => { expect(updateSyncStatusMock).toBeCalledTimes(0) expect(mockFn).toBeCalledTimes(1) }) - it ('hash is in syncInQueue', async () => { + it('hash is in syncInQueue', async () => { const connect = new LightConnector([], '') //@ts-ignore connect.subscribeSync = jest.fn() diff --git a/packages/neuron-wallet/tests/models/chain/block-header.test.ts b/packages/neuron-wallet/tests/models/chain/block-header.test.ts index a6b1680124..c959958bbc 100644 --- a/packages/neuron-wallet/tests/models/chain/block-header.test.ts +++ b/packages/neuron-wallet/tests/models/chain/block-header.test.ts @@ -1,5 +1,4 @@ import BlockHeader from '../../../src/models/chain/block-header' -import HexUtils from '../../../src/utils/hex' describe('BlockHeader', () => { const sdkHeader: CKBComponents.BlockHeader = { @@ -19,11 +18,11 @@ describe('BlockHeader', () => { it('fromSDK', () => { const result: BlockHeader = BlockHeader.fromSDK(sdkHeader) - expect(result.version).toEqual(HexUtils.toDecimal(sdkHeader.version)) - expect(result.timestamp).toEqual(HexUtils.toDecimal(sdkHeader.timestamp)) + expect(result.version).toEqual('0') // 0x0 + expect(result.timestamp).toEqual('1557311767') // 0x5cd2b117 expect(result.hash).toEqual(sdkHeader.hash) expect(result.parentHash).toEqual(sdkHeader.parentHash) - expect(result.number).toEqual(HexUtils.toDecimal(sdkHeader.number)) - expect(result.epoch).toEqual(HexUtils.toDecimal(sdkHeader.epoch)) + expect(result.number).toEqual('1024') // 0x400 + expect(result.epoch).toEqual('1979121332649985') // 0x7080018000001 }) }) diff --git a/packages/neuron-wallet/tests/models/transaction-size.test.ts b/packages/neuron-wallet/tests/models/transaction-size.test.ts index de105ce411..26371673b8 100644 --- a/packages/neuron-wallet/tests/models/transaction-size.test.ts +++ b/packages/neuron-wallet/tests/models/transaction-size.test.ts @@ -1,5 +1,5 @@ import TransactionSize from '../../src/models/transaction-size' -import HexUtils from '../../src/utils/hex' +import { bytes as byteUtils } from '@ckb-lumos/codec' import Script, { ScriptHashType } from '../../src/models/chain/script' import WitnessArgs from '../../src/models/chain/witness-args' import Transaction from '../../src/models/chain/transaction' @@ -25,7 +25,7 @@ describe('TransactionSize', () => { it('witnessArgs', () => { const result = TransactionSize.witness(witnessArgs) - expect(result).toEqual(HexUtils.byteLength('0x10000000100000001000000010000000') + 4 + 4) + expect(result).toEqual(byteUtils.bytify('0x10000000100000001000000010000000').byteLength + 4 + 4) }) it('witnessArgs only lock', () => { diff --git a/packages/neuron-wallet/tests/services/cells.test.ts b/packages/neuron-wallet/tests/services/cells.test.ts index aa1e47b7f2..a617a0eba5 100644 --- a/packages/neuron-wallet/tests/services/cells.test.ts +++ b/packages/neuron-wallet/tests/services/cells.test.ts @@ -1,5 +1,6 @@ import { getConnection } from 'typeorm' import { scriptToAddress } from '@nervosnetwork/ckb-sdk-utils' +import { bytes } from '@ckb-lumos/codec' import { initConnection } from '../../src/database/chain/ormconfig' import OutputEntity from '../../src/database/chain/entities/output' import { OutputStatus } from '../../src/models/chain/output' @@ -1144,8 +1145,14 @@ describe('CellsService', () => { lockScript: multiSignLockScript, } - const receiverChequeLock = assetAccountInfo.generateChequeScript(bobDefaultLock.computeHash(), '0'.repeat(40)) - const senderChequeLock = assetAccountInfo.generateChequeScript('0'.repeat(40), bobDefaultLock.computeHash()) + const receiverChequeLock = assetAccountInfo.generateChequeScript( + bobDefaultLock.computeHash(), + bytes.hexify(Buffer.alloc(20)) + ) + const senderChequeLock = assetAccountInfo.generateChequeScript( + bytes.hexify(Buffer.alloc(20)), + bobDefaultLock.computeHash() + ) const acpLock = assetAccountInfo.generateAnyoneCanPayScript('0x') const sudtType = new Script(assetAccountInfo.getSudtCodeHash(), '0x', ScriptHashType.Type) diff --git a/packages/neuron-wallet/tests/services/tx/transaction-generator.test.ts b/packages/neuron-wallet/tests/services/tx/transaction-generator.test.ts index 5cdfbb5d42..0e99769455 100644 --- a/packages/neuron-wallet/tests/services/tx/transaction-generator.test.ts +++ b/packages/neuron-wallet/tests/services/tx/transaction-generator.test.ts @@ -1,5 +1,6 @@ import { when } from 'jest-when' import { getConnection } from 'typeorm' +import { bytes } from '@ckb-lumos/codec' import { initConnection } from '../../../src/database/chain/ormconfig' import OutputEntity from '../../../src/database/chain/entities/output' import InputEntity from '../../../src/database/chain/entities/input' @@ -2204,7 +2205,7 @@ describe('TransactionGenerator', () => { it('creates cheque output', () => { const chequeOutput = tx.outputs[0] expect(chequeOutput.lock.computeHash()).toEqual(expectedChequeOutput.lockHash) - expect(chequeOutput.lock.args.length).toEqual(82) + expect(bytes.bytify(chequeOutput.lock.args).byteLength).toEqual(40) }) it('sender lock hash equals to one of default lock inputs', () => { const defaultLockInput = tx.inputs.find(input => { @@ -2368,7 +2369,10 @@ describe('TransactionGenerator', () => { senderDefaultLockInputEntity = createInput(senderDefaultLock, undefined, transaction.hash) - const chequeLock = assetAccountInfo.generateChequeScript('0x' + '0'.repeat(40), senderDefaultLock.computeHash()) + const chequeLock = assetAccountInfo.generateChequeScript( + bytes.hexify(Buffer.alloc(20)), + senderDefaultLock.computeHash() + ) chequeOutputEntity = createOutput( chequeLock, typeScript, @@ -2810,12 +2814,12 @@ describe('TransactionGenerator', () => { describe('CKB account', () => { it('capacity not enough for fee', async () => { const input = createInput(alice.lockScript, undefined, '0x' + '0'.repeat(64)) - const asssetAccountInput = input.toModel() - asssetAccountInput.capacity = toShannon('61') + const assetAccountInput = input.toModel() + assetAccountInput.capacity = toShannon('61') await expect( TransactionGenerator.generateDestroyAssetAccountTx( 'walletId', - [asssetAccountInput], + [assetAccountInput], bob.publicKeyInBlake160, true ) @@ -2823,13 +2827,13 @@ describe('TransactionGenerator', () => { }) it('account capacity not enough for fee need other address', async () => { const input = createInput(alice.lockScript, undefined, '0x' + '0'.repeat(64)) - const asssetAccountInput = input.toModel() - asssetAccountInput.capacity = toShannon('61') + const assetAccountInput = input.toModel() + assetAccountInput.capacity = toShannon('61') const cell: OutputEntity = generateCell(toShannon('62'), OutputStatus.Live, false, null, alice) await getConnection().manager.save(cell) const res = await TransactionGenerator.generateDestroyAssetAccountTx( alice.walletId, - [asssetAccountInput], + [assetAccountInput], bob.publicKeyInBlake160, true ) @@ -2840,11 +2844,11 @@ describe('TransactionGenerator', () => { }) it('account capacity enough for fee', async () => { const input = createInput(alice.lockScript, undefined, '0x' + '0'.repeat(64)) - const asssetAccountInput = input.toModel() - asssetAccountInput.capacity = toShannon('62') + const assetAccountInput = input.toModel() + assetAccountInput.capacity = toShannon('62') const res = await TransactionGenerator.generateDestroyAssetAccountTx( alice.walletId, - [asssetAccountInput], + [assetAccountInput], bob.publicKeyInBlake160, true ) @@ -2860,13 +2864,13 @@ describe('TransactionGenerator', () => { ScriptHashType.Type ) const input = createInput(alice.lockScript, typeScript, '0x' + '0'.repeat(64)) - const asssetAccountInput = input.toModel() - asssetAccountInput.capacity = toShannon('142') - asssetAccountInput.data = BufferUtils.writeBigUInt128LE(BigInt('10')) + const assetAccountInput = input.toModel() + assetAccountInput.capacity = toShannon('142') + assetAccountInput.data = BufferUtils.writeBigUInt128LE(BigInt('10')) await expect( TransactionGenerator.generateDestroyAssetAccountTx( alice.walletId, - [asssetAccountInput], + [assetAccountInput], bob.publicKeyInBlake160, false ) @@ -2879,11 +2883,11 @@ describe('TransactionGenerator', () => { ScriptHashType.Type ) const input = createInput(alice.lockScript, typeScript, '0x' + '0'.repeat(64)) - const asssetAccountInput = input.toModel() - asssetAccountInput.capacity = toShannon('142') + const assetAccountInput = input.toModel() + assetAccountInput.capacity = toShannon('142') const res = await TransactionGenerator.generateDestroyAssetAccountTx( alice.walletId, - [asssetAccountInput], + [assetAccountInput], bob.publicKeyInBlake160, false ) diff --git a/packages/neuron-wallet/tests/services/tx/transaction-sender.test.ts b/packages/neuron-wallet/tests/services/tx/transaction-sender.test.ts index 19b64eef66..e750b13ce4 100644 --- a/packages/neuron-wallet/tests/services/tx/transaction-sender.test.ts +++ b/packages/neuron-wallet/tests/services/tx/transaction-sender.test.ts @@ -1,3 +1,5 @@ +import { bytes } from '@ckb-lumos/codec' + const stubbedRPCServiceConstructor = jest.fn() const stubbedWalletsServiceConstructor = jest.fn() const stubbedGetLiveCell = jest.fn() @@ -131,7 +133,7 @@ jest.doMock('services/hardware', () => ({ })) jest.doMock('@nervosnetwork/ckb-sdk-core', () => { - return function() { + return function () { return { calculateDaoMaximumWithdraw: stubbedCalculateDaoMaximumWithdraw, } @@ -141,13 +143,13 @@ jest.doMock('@nervosnetwork/ckb-sdk-core', () => { jest.doMock('utils/ckb-rpc.ts', () => ({ generateRPC() { return { - sendTransaction: stubbedSendTransaction + sendTransaction: stubbedSendTransaction, } - } + }, })) jest.doMock('services/cells', () => ({ - getLiveCell: stubbedGetLiveCell + getLiveCell: stubbedGetLiveCell, })) import Transaction from '../../../src/models/chain/transaction' @@ -452,7 +454,10 @@ describe('TransactionSender Test', () => { }) describe('when matched receiver lock hash', () => { beforeEach(() => { - const chequeLock = assetAccountInfo.generateChequeScript(receiverDefaultLock.computeHash(), '0'.repeat(40)) + const chequeLock = assetAccountInfo.generateChequeScript( + receiverDefaultLock.computeHash(), + bytes.hexify(Buffer.alloc(20)) + ) tx.inputs[0].lock = chequeLock }) it('success', async () => { @@ -464,7 +469,10 @@ describe('TransactionSender Test', () => { }) describe('when not matched receiver lock hash', () => { beforeEach(() => { - const chequeLock = assetAccountInfo.generateChequeScript('0'.repeat(40), '0'.repeat(40)) + const chequeLock = assetAccountInfo.generateChequeScript( + bytes.hexify(Buffer.alloc(20)), + bytes.hexify(Buffer.alloc(20)) + ) tx.inputs[0].lock = chequeLock }) it('throws', async () => { @@ -502,7 +510,10 @@ describe('TransactionSender Test', () => { }) describe('when matched sender lock hash', () => { beforeEach(() => { - const chequeLock = assetAccountInfo.generateChequeScript('0'.repeat(40), senderDefaultLock.computeHash()) + const chequeLock = assetAccountInfo.generateChequeScript( + bytes.hexify(Buffer.alloc(20)), + senderDefaultLock.computeHash() + ) tx.inputs[0].lock = chequeLock }) it('success', async () => { @@ -513,7 +524,10 @@ describe('TransactionSender Test', () => { }) describe('when not matched sender lock hash', () => { beforeEach(() => { - const chequeLock = assetAccountInfo.generateChequeScript('0'.repeat(40), '0'.repeat(40)) + const chequeLock = assetAccountInfo.generateChequeScript( + bytes.hexify(Buffer.alloc(20)), + bytes.hexify(Buffer.alloc(20)) + ) tx.inputs[0].lock = chequeLock }) it('throws', async () => { From 034d3457e3dc7fdb4c11bacf687e574c1f9387f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=A5=E5=9B=BD=E5=AE=87?= <841185308@qq.com> Date: Thu, 20 Jul 2023 16:45:37 +0800 Subject: [PATCH 5/6] chore: Add action to update assume valid target (#2773) * chore: Add action to update assume valid target * chore: Ignore scripts code style * fix: Use fetch to to replace node:http * chore: Use github context --- .github/workflows/check-code-style.yml | 2 +- .github/workflows/update_valid_target.yml | 87 +++++++++++++++++++++++ package.json | 3 +- scripts/update-valid-target.js | 34 +++++++++ 4 files changed, 124 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/update_valid_target.yml create mode 100644 scripts/update-valid-target.js diff --git a/.github/workflows/check-code-style.yml b/.github/workflows/check-code-style.yml index 5ed1158ded..61aa93474a 100644 --- a/.github/workflows/check-code-style.yml +++ b/.github/workflows/check-code-style.yml @@ -33,7 +33,7 @@ jobs: id: changed-files uses: tj-actions/changed-files@v37 with: - files: "**/*.{js,cjs,mjs,jsx,ts,tsx,css,scss}" + files: "packages/**/*.{js,cjs,mjs,jsx,ts,tsx,css,scss}" - name: Prettier Check if: steps.changed-files.outputs.any_changed == 'true' diff --git a/.github/workflows/update_valid_target.yml b/.github/workflows/update_valid_target.yml new file mode 100644 index 0000000000..4b2cd85462 --- /dev/null +++ b/.github/workflows/update_valid_target.yml @@ -0,0 +1,87 @@ +name: Update ckb node assume valid target + +on: + pull_request: + types: [ready_for_review] + branches: + - master + +jobs: + ready-for-release: + name: Update ckb node assume valid target + runs-on: ubuntu-latest + steps: + - name: Create Branch + uses: peterjgrainger/action-create-branch@v2.2.0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + branch: 'chore-update-valid-target/${{github.head_ref}}' + sha: '${{ github.event.pull_request.head.sha }}' + + - name: Checkout + uses: actions/checkout@v3 + with: + ref: 'chore-update-valid-target/${{github.head_ref}}' + + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 18.12.0 + + - name: Write env file + run: | + npm run update:valid-target + + - name: Commit env file + uses: actions/github-script@v6 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BASE: ${{ github.head_ref }} + with: + script: | + const fs = require('node:fs') + const { BASE, HEAD } = process.env + const envFilePath = 'packages/neuron-wallet/.env' + const destinationBranch = `chore-update-valid-target/${BASE}` + const { data } = await github.rest.repos.getContent({ + owner: context.repo.owner, + repo: context.repo.repo, + path: envFilePath, + ref: destinationBranch, + }) + await github.rest.repos.createOrUpdateFileContents({ + owner: context.repo.owner, + repo: context.repo.repo, + path: envFilePath, + message: `chore: Update ckb node assume valid target for ${BASE}.`, + content: fs.readFileSync(envFilePath).toString('base64'), + sha: data.sha, + branch: destinationBranch, + }) + + - name: Create PR + uses: actions/github-script@v6 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BASE: ${{github.head_ref}} + HEAD: chore-update-valid-target/${{github.head_ref}} + REPO: ${{github.repository}} + with: + script: | + const { BASE, HEAD, REPO } = process.env + const { data: pulls } = await github.rest.pulls.list({ + owner: context.repo.owner, + repo: context.repo.repo, + }) + if (pulls.some(pull => pull.head.ref === HEAD)) { + return + } + github.rest.pulls.create({ + owner: context.repo.owner, + repo: context.repo.repo, + head: HEAD, + base: BASE, + title: 'chore: Update ckb node assume valid target', + body: `This PR uses to update ckb node assume valid target for PR https://github.com/${REPO}/pull/${context.issue.number}`, + }) diff --git a/package.json b/package.json index e8577a2c72..26b658aa21 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,8 @@ "test:ci": "yarn build:main && yarn test", "lint": "lerna run --stream lint", "postinstall": "husky install", - "db:chain": "node ./node_modules/.bin/typeorm" + "db:chain": "node ./node_modules/.bin/typeorm", + "update:valid-target": "node ./scripts/update-valid-target.js" }, "devDependencies": { "@babel/core": "7.22.5", diff --git a/scripts/update-valid-target.js b/scripts/update-valid-target.js new file mode 100644 index 0000000000..78d2fbac0f --- /dev/null +++ b/scripts/update-valid-target.js @@ -0,0 +1,34 @@ +const fs = require('node:fs') +const path = require('node:path') + +async function rpcRequest(method, params = []) { + const result = await fetch( + 'https://mainnet.ckb.dev/rpc', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + id: 0, + jsonrpc: '2.0', + method, + params, + }), + timeout: 10000, + } + ) + return result.json() +} + +const ESTIMATE_BLOCK_COUNT_PER_DAY = 8_000 +const envFilePath = path.resolve(__dirname, '../packages/neuron-wallet/.env') +const validTargetReg = /(CKB_NODE_ASSUME_VALID_TARGET=)[\S]*/ + +;(async function () { + const tipBlockNumber = (await rpcRequest('get_tip_block_number')).result + const validTargetBlockNumber = `0x${(BigInt(tipBlockNumber) - BigInt(ESTIMATE_BLOCK_COUNT_PER_DAY)).toString(16)}` + const blockHash = (await rpcRequest('get_block_hash', [validTargetBlockNumber])).result + const originEnvContent = fs.readFileSync(envFilePath).toString('utf-8') + fs.writeFileSync(envFilePath, originEnvContent.replace(validTargetReg, `CKB_NODE_ASSUME_VALID_TARGET='${blockHash}'`)) +})() From b4f9a2603ac1ef45971f9bebb8c596fb03129f7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=A5=E5=9B=BD=E5=AE=87?= <841185308@qq.com> Date: Thu, 20 Jul 2023 16:49:50 +0800 Subject: [PATCH 6/6] fix: Use common tips style. (#2777) --- .../src/components/PricePanel/index.tsx | 31 +++++++------ .../PricePanel/pricePanel.module.scss | 45 ++++--------------- .../src/components/Send/send.module.scss | 9 ++++ 3 files changed, 36 insertions(+), 49 deletions(-) diff --git a/packages/neuron-ui/src/components/PricePanel/index.tsx b/packages/neuron-ui/src/components/PricePanel/index.tsx index b3c9e68c5f..ddefb8f77b 100644 --- a/packages/neuron-ui/src/components/PricePanel/index.tsx +++ b/packages/neuron-ui/src/components/PricePanel/index.tsx @@ -1,4 +1,3 @@ -/* eslint-disable no-console */ import React, { useCallback, useEffect, useMemo, useState } from 'react' import { localNumberFormatter, shannonToCKBFormatter } from 'utils' import RingProgressBar from 'widgets/RingProgressBar' @@ -10,6 +9,7 @@ import { useTranslation } from 'react-i18next' import { appState, useState as useGlobalState } from 'states' import { FeeRateValueArrayItemType, useGetBatchGeneratedTx } from 'components/Send/hooks' import { batchGenerateExperimental } from 'components/SUDTSend/hooks' +import Tooltip from 'widgets/Tooltip' import styles from './pricePanel.module.scss' @@ -144,19 +144,24 @@ const PricePanel: React.FunctionComponent = ({ - + + {isStandard ? (
diff --git a/packages/neuron-ui/src/components/PricePanel/pricePanel.module.scss b/packages/neuron-ui/src/components/PricePanel/pricePanel.module.scss index 30cc3de735..b1b07a97b2 100644 --- a/packages/neuron-ui/src/components/PricePanel/pricePanel.module.scss +++ b/packages/neuron-ui/src/components/PricePanel/pricePanel.module.scss @@ -9,6 +9,7 @@ .transferSwitch { display: flex; + align-items: center; color: var(--secondary-text-color); } } @@ -29,46 +30,18 @@ svg > path { fill: var(--primary-color); } - - &::after { - position: absolute; - display: inline-block; - left: 50%; - transform: translate(-50%, -99%); - padding: 12px; - border-radius: 8px; - overflow-wrap: break-word; - background-color: var(--tooltip-background-color); - color: var(--tooltip-font-color); - user-select: text; - white-space: nowrap; - text-align: center; - content: attr(data-content); - } - &::before { - content: ''; - user-select: text; - border-width: 9px; - border-style: solid; - border-color: transparent; - display: inline-block; - border-top-color: var(--tooltip-background-color); - transform: translate(-50%, -70%); - left: 50%; - position: absolute; - } } } .dropdownBox { margin: 4px 0px 19px 0px; - --tag-red-bg-color: #FFE8E8; - --tag-green-bg-color: #EFFAF7; - --tag-blue-bg-color: #E8FAFF; + --tag-red-bg-color: #ffe8e8; + --tag-green-bg-color: #effaf7; + --tag-blue-bg-color: #e8faff; @media (prefers-color-scheme: dark) { --tag-red-bg-color: #322929; - --tag-green-bg-color: #2E3735; - --tag-blue-bg-color: #2D3638; + --tag-green-bg-color: #2e3735; + --tag-blue-bg-color: #2d3638; } } .suffix { @@ -104,15 +77,15 @@ line-height: 17px; } .green { - color: #00C891; + color: #00c891; background: var(--tag-green-bg-color); } .blue { - color: #23BFF0; + color: #23bff0; background: var(--tag-blue-bg-color); } .red { - color: #FF5656; + color: #ff5656; background: var(--tag-red-bg-color); } } diff --git a/packages/neuron-ui/src/components/Send/send.module.scss b/packages/neuron-ui/src/components/Send/send.module.scss index f2587e529a..206eff257e 100644 --- a/packages/neuron-ui/src/components/Send/send.module.scss +++ b/packages/neuron-ui/src/components/Send/send.module.scss @@ -60,6 +60,15 @@ $headerHeight: 104px; .content { padding: 16px; + /** + These styles are for showing the full tips, because of content needs to scroll on the y-axis. + Then the overflow property that is set as scroll will truncate the tips overflow of the content. + So I need to expand the content's left to show the full tips. + */ + position: relative; + left: -48px; + padding-left: 64px; + width: calc(100% - 32px); } .rightFooter {