diff --git a/packages/ccc/CHANGELOG.md b/packages/ccc/CHANGELOG.md index 17cd572bf..d94727e03 100644 --- a/packages/ccc/CHANGELOG.md +++ b/packages/ccc/CHANGELOG.md @@ -1,5 +1,11 @@ # @ckb-ccc/ccc +## 1.1.22 +### Patch Changes + +- Updated dependencies []: + - @ckb-ccc/shell@1.1.22 + ## 1.1.21 ### Patch Changes diff --git a/packages/ccc/package.json b/packages/ccc/package.json index 61219eb9e..6c17e0ef7 100644 --- a/packages/ccc/package.json +++ b/packages/ccc/package.json @@ -1,6 +1,6 @@ { "name": "@ckb-ccc/ccc", - "version": "1.1.21", + "version": "1.1.22", "description": "CCC - CKBer's Codebase. Common Chains Connector.", "author": "Hanssen0 ", "license": "MIT", diff --git a/packages/ckb-ccc/CHANGELOG.md b/packages/ckb-ccc/CHANGELOG.md index 7461441d1..37628e5fc 100644 --- a/packages/ckb-ccc/CHANGELOG.md +++ b/packages/ckb-ccc/CHANGELOG.md @@ -1,5 +1,11 @@ # ckb-ccc +## 1.0.30 +### Patch Changes + +- Updated dependencies []: + - @ckb-ccc/ccc@1.1.22 + ## 1.0.29 ### Patch Changes diff --git a/packages/ckb-ccc/package.json b/packages/ckb-ccc/package.json index 559cd6dd1..8e2a6153c 100644 --- a/packages/ckb-ccc/package.json +++ b/packages/ckb-ccc/package.json @@ -1,6 +1,6 @@ { "name": "ckb-ccc", - "version": "1.0.29", + "version": "1.0.30", "description": "CCC - CKBer's Codebase. Common Chains Connector.", "author": "Hanssen0 ", "license": "MIT", diff --git a/packages/connector-react/CHANGELOG.md b/packages/connector-react/CHANGELOG.md index 88c89cab9..7d70d3073 100644 --- a/packages/connector-react/CHANGELOG.md +++ b/packages/connector-react/CHANGELOG.md @@ -1,5 +1,18 @@ # @ckb-ccc/connector-react +## 1.0.31 +### Patch Changes + + + +- [#335](https://github.com/ckb-devrel/ccc/pull/335) [`ea7e626`](https://github.com/ckb-devrel/ccc/commit/ea7e626a81ad4fb78142f0d948843de84478debf) Thanks [@Hanssen0](https://github.com/Hanssen0)! - chore: bump version of react + +## 1.0.30 +### Patch Changes + +- Updated dependencies []: + - @ckb-ccc/connector@1.0.30 + ## 1.0.29 ### Patch Changes diff --git a/packages/connector-react/package.json b/packages/connector-react/package.json index 2e706f02b..857ca71bc 100644 --- a/packages/connector-react/package.json +++ b/packages/connector-react/package.json @@ -1,6 +1,6 @@ { "name": "@ckb-ccc/connector-react", - "version": "1.0.29", + "version": "1.0.31", "description": "CCC - CKBer's Codebase. Common Chains Connector UI Component for React", "author": "Hanssen0 ", "license": "MIT", @@ -25,7 +25,7 @@ }, "devDependencies": { "@eslint/js": "^9.34.0", - "@types/react": "^19.1.12", + "@types/react": "^19.2.7", "eslint": "^9.34.0", "eslint-config-prettier": "^10.1.8", "eslint-plugin-prettier": "^5.5.4", diff --git a/packages/connector/CHANGELOG.md b/packages/connector/CHANGELOG.md index af6e1b5bc..82fe323cf 100644 --- a/packages/connector/CHANGELOG.md +++ b/packages/connector/CHANGELOG.md @@ -1,5 +1,11 @@ # @ckb-ccc/connector +## 1.0.30 +### Patch Changes + +- Updated dependencies []: + - @ckb-ccc/ccc@1.1.22 + ## 1.0.29 ### Patch Changes diff --git a/packages/connector/package.json b/packages/connector/package.json index f48055120..40a31fdd6 100644 --- a/packages/connector/package.json +++ b/packages/connector/package.json @@ -1,6 +1,6 @@ { "name": "@ckb-ccc/connector", - "version": "1.0.29", + "version": "1.0.30", "description": "CCC - CKBer's Codebase. Common Chains Connector UI", "author": "Hanssen0 ", "license": "MIT", diff --git a/packages/core/src/signer/btc/index.ts b/packages/core/src/signer/btc/index.ts index d0aa15884..694ff7250 100644 --- a/packages/core/src/signer/btc/index.ts +++ b/packages/core/src/signer/btc/index.ts @@ -1,3 +1,4 @@ +export * from "./psbt.js"; export * from "./signerBtc.js"; export * from "./signerBtcPublicKeyReadonly.js"; export * from "./verify.js"; diff --git a/packages/core/src/signer/btc/psbt.ts b/packages/core/src/signer/btc/psbt.ts new file mode 100644 index 000000000..77ac646f7 --- /dev/null +++ b/packages/core/src/signer/btc/psbt.ts @@ -0,0 +1,56 @@ +/** + * Options for signing a PSBT (Partially Signed Bitcoin Transaction) + */ +export type SignPsbtOptions = { + /** + * Whether to finalize the PSBT after signing. + * Default is true. + */ + autoFinalized?: boolean; + /** + * Array of inputs to sign + */ + toSignInputs?: ToSignInput[]; +}; + +/** + * Specification for an input to sign in a PSBT. + * Must specify at least one of: address or pubkey. + */ +export type ToSignInput = { + /** + * Which input to sign (index in the PSBT inputs array) + */ + index: number; + /** + * (Optional) Sighash types to use for signing. + */ + sighashTypes?: number[]; + /** + * (Optional) When signing and unlocking Taproot addresses, the tweakSigner is used by default + * for signature generation. Setting this to true allows for signing with the original private key. + * Default value is false. + */ + disableTweakSigner?: boolean; +} & ( + | { + /** + * The address whose corresponding private key to use for signing. + */ + address: string; + /** + * The public key whose corresponding private key to use for signing. + */ + publicKey?: string; + } + | { + /** + * The address whose corresponding private key to use for signing. + */ + address?: string; + /** + * The public key whose corresponding private key to use for signing. + */ + publicKey: string; + } +); diff --git a/packages/core/src/signer/btc/signerBtc.ts b/packages/core/src/signer/btc/signerBtc.ts index 64112a74a..6dd8ba4c6 100644 --- a/packages/core/src/signer/btc/signerBtc.ts +++ b/packages/core/src/signer/btc/signerBtc.ts @@ -5,6 +5,7 @@ import { KnownScript } from "../../client/index.js"; import { HexLike, hexFrom } from "../../hex/index.js"; import { numToBytes } from "../../num/index.js"; import { Signer, SignerSignType, SignerType } from "../signer/index.js"; +import { SignPsbtOptions } from "./psbt.js"; import { btcEcdsaPublicKeyHash } from "./verify.js"; /** @@ -22,6 +23,32 @@ export abstract class SignerBtc extends Signer { return SignerSignType.BtcEcdsa; } + /** + * Whether the wallet supports a single call to sign + broadcast (combined flow). + * Default false; override in implementations like Xverse/JoyID. + */ + get supportsSingleCallSignAndBroadcast(): boolean { + return false; + } + + /** + * Sign and broadcast a PSBT in one call when supported, otherwise falls back + * to sign then push. Prefer this over manual sign+push to avoid double popups. + */ + async signAndPushPsbt( + psbtHex: string, + options?: SignPsbtOptions, + ): Promise { + if (this.supportsSingleCallSignAndBroadcast) { + // Wallet handles sign+broadcast internally (e.g., Xverse/JoyID) + return this.pushPsbt(psbtHex, options); + } + + // Split-mode wallets: sign first, then broadcast + const signedPsbt = await this.signPsbt(psbtHex, options); + return this.pushPsbt(signedPsbt, options); + } + /** * Gets the Bitcoin account associated with the signer. * @@ -123,4 +150,32 @@ export abstract class SignerBtc extends Signer { tx.setWitnessArgsAt(info.position, witness); return tx; } + + /** + * Signs a Partially Signed Bitcoin Transaction (PSBT). + * + * @param psbtHex - The hex string of PSBT to sign + * @param options - Options for signing the PSBT + * @returns A promise that resolves to the signed PSBT hex string + */ + abstract signPsbt( + psbtHex: string, + options?: SignPsbtOptions, + ): Promise; + + /** + * Pushes a PSBT to the Bitcoin network. + * + * For wallets that support a single call for signing and broadcasting (where `supportsSingleCallSignAndBroadcast` is true), + * this method takes an **unsigned** PSBT, signs it, and broadcasts it. + * For other wallets, this method takes a **signed** PSBT and only broadcasts it. + * + * @param psbtHex - The hex string of the PSBT to push. Can be signed or unsigned depending on the wallet's capabilities. + * @param options - Options for signing the PSBT. Only used by wallets that perform signing in this step. + * @returns A promise that resolves to the transaction ID. + */ + abstract pushPsbt( + psbtHex: string, + options?: SignPsbtOptions, + ): Promise; } diff --git a/packages/core/src/signer/btc/signerBtcPublicKeyReadonly.ts b/packages/core/src/signer/btc/signerBtcPublicKeyReadonly.ts index 50096db7e..f5293a952 100644 --- a/packages/core/src/signer/btc/signerBtcPublicKeyReadonly.ts +++ b/packages/core/src/signer/btc/signerBtcPublicKeyReadonly.ts @@ -1,5 +1,6 @@ import { Client } from "../../client/index.js"; import { Hex, HexLike, hexFrom } from "../../hex/index.js"; +import { SignPsbtOptions } from "./psbt.js"; import { SignerBtc } from "./signerBtc.js"; /** @@ -70,4 +71,12 @@ export class SignerBtcPublicKeyReadonly extends SignerBtc { async getBtcPublicKey(): Promise { return this.publicKey; } + + async signPsbt(_: string, __?: SignPsbtOptions): Promise { + throw new Error("Read-only signer does not support signPsbt"); + } + + async pushPsbt(_: string, __?: SignPsbtOptions): Promise { + throw new Error("Read-only signer does not support pushPsbt"); + } } diff --git a/packages/demo/eslint.config.mjs b/packages/demo/eslint.config.mjs index aacfd2aeb..48fe8d310 100644 --- a/packages/demo/eslint.config.mjs +++ b/packages/demo/eslint.config.mjs @@ -2,6 +2,8 @@ import { dirname } from "path"; import { fileURLToPath } from "url"; import { FlatCompat } from "@eslint/eslintrc"; import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended"; +import nextVitals from "eslint-config-next/core-web-vitals"; +import nextTs from "eslint-config-next/typescript"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); @@ -11,7 +13,8 @@ const compat = new FlatCompat({ }); export default [ - ...compat.extends("next/core-web-vitals", "next/typescript"), + ...nextVitals, + ...nextTs, { ignores: [ "node_modules/**", @@ -36,4 +39,4 @@ export default [ }, }, eslintPluginPrettierRecommended, -]; \ No newline at end of file +]; diff --git a/packages/demo/package.json b/packages/demo/package.json index f58b0b29d..b96bf67a2 100644 --- a/packages/demo/package.json +++ b/packages/demo/package.json @@ -17,12 +17,12 @@ }, "dependencies": { "@lit/react": "^1.0.8", - "@next/third-parties": "^15.5.2", + "@next/third-parties": "^16.0.10", "@uiw/react-json-view": "2.0.0-alpha.37", "lucide-react": "^0.542.0", - "next": "15.5.2", - "react": "^19.1.1", - "react-dom": "^19.1.1" + "next": "16.0.10", + "react": "^19.2.3", + "react-dom": "^19.2.3" }, "devDependencies": { "@ckb-ccc/connector-react": "workspace:*", @@ -40,10 +40,10 @@ "@scure/bip39": "^2.0.0", "@tailwindcss/postcss": "^4.1.12", "@types/node": "^24.3.0", - "@types/react": "^19.1.12", - "@types/react-dom": "^19.1.8", + "@types/react": "^19.2.7", + "@types/react-dom": "^19.2.3", "eslint": "^9.34.0", - "eslint-config-next": "15.5.2", + "eslint-config-next": "16.0.10", "eslint-config-prettier": "^10.1.8", "eslint-plugin-prettier": "^5.5.4", "postcss": "^8.5.6", diff --git a/packages/demo/src/app/connected/(tools)/Sign/page.tsx b/packages/demo/src/app/connected/(tools)/Sign/page.tsx index 6ce0f5829..55f36a374 100644 --- a/packages/demo/src/app/connected/(tools)/Sign/page.tsx +++ b/packages/demo/src/app/connected/(tools)/Sign/page.tsx @@ -5,6 +5,7 @@ import { ButtonsPanel } from "@/src/components/ButtonsPanel"; import { Textarea } from "@/src/components/Textarea"; import { useApp } from "@/src/context"; import { ccc } from "@ckb-ccc/connector-react"; +import { CopyIcon } from "lucide-react"; import { useState } from "react"; export default function Sign() { @@ -21,6 +22,24 @@ export default function Sign() { placeholder="Message to sign and verify" state={[messageToSign, setMessageToSign]} /> +