diff --git a/bin/use-env.sh b/bin/use-env.sh index c794482..4cb22b6 100755 --- a/bin/use-env.sh +++ b/bin/use-env.sh @@ -25,6 +25,7 @@ esac JOYID_INFO_FILE="$(ls migrations/joyid/*.json | grep -v deployment | head -n 1)" OMNILOCK_INFO_FILE="$(ls migrations/omnilock/*.json | grep -v deployment | head -n 1)" +DAO_ACTION_VERIFIER_INFO_FILE="$(ls migrations/dao-action-verifier/*.json | grep -v deployment | head -n 1)" sed -n \ -e 's/,$//' \ @@ -45,3 +46,13 @@ sed -n \ -e 's/,$//' \ -e 's/^ *"tx_hash": /NEXT_PUBLIC_OMNILOCK_TX_HASH=/p' \ "$OMNILOCK_INFO_FILE" | tail -1 + +sed -n \ + -e 's/,$//' \ + -e 's/^ *"type_id": "/NEXT_PUBLIC_DAO_ACTION_VERIFIER_CODE_HASH="/p' \ + "$DAO_ACTION_VERIFIER_INFO_FILE" | head -1 + +sed -n \ + -e 's/,$//' \ + -e 's/^ *"tx_hash": /NEXT_PUBLIC_DAO_ACTION_VERIFIER_TX_HASH=/p' \ + "$DAO_ACTION_VERIFIER_INFO_FILE" | tail -1 diff --git a/docs/packing-verifier.md b/docs/packing-verifier.md new file mode 100644 index 0000000..a8150a2 --- /dev/null +++ b/docs/packing-verifier.md @@ -0,0 +1 @@ +# Packing Verifier diff --git a/src/actions/claim.js b/src/actions/claim.js index 5e12b02..01a10f7 100644 --- a/src/actions/claim.js +++ b/src/actions/claim.js @@ -4,12 +4,16 @@ import { claimDao } from "@/lib/cobuild/publishers"; import { getConfig } from "@/lib/config"; import { prepareLockActions } from "@/lib/cobuild/lock-actions"; import { payFee } from "@/lib/cobuild/fee-manager"; +import { prepareVerifier } from "@/lib/papps/dao/verifier"; -export default async function withdraw(from, cell, config) { +export default async function withdraw(from, cell, shouldPackVerifier, config) { config = config ?? getConfig(); try { let buildingPacket = await claimDao(config)({ cell }); + if (shouldPackVerifier) { + buildingPacket = await prepareVerifier(buildingPacket, from, config); + } buildingPacket = await payFee( buildingPacket, [{ address: from, feeRate: 1200 }], diff --git a/src/actions/deposit.js b/src/actions/deposit.js index 19341bc..b7f8a47 100644 --- a/src/actions/deposit.js +++ b/src/actions/deposit.js @@ -1,18 +1,22 @@ "use server"; -import { parseUnit } from "@ckb-lumos/bi"; import { depositDao } from "@/lib/cobuild/publishers"; import { getConfig } from "@/lib/config"; import { prepareLockActions } from "@/lib/cobuild/lock-actions"; import { payFee } from "@/lib/cobuild/fee-manager"; +import { prepareVerifier } from "@/lib/papps/dao/verifier"; export default async function deposit(_prevState, formData, config) { config = config ?? getConfig(); const from = formData.get("from"); + const shouldPackVerifier = formData.get("packVerifier") !== undefined; try { let buildingPacket = await depositDao(config)(formData); + if (shouldPackVerifier) { + buildingPacket = await prepareVerifier(buildingPacket, from, config); + } buildingPacket = await payFee( buildingPacket, [{ address: from, feeRate: 1200 }], diff --git a/src/actions/get-verifier-cells.js b/src/actions/get-verifier-cells.js new file mode 100644 index 0000000..38d200c --- /dev/null +++ b/src/actions/get-verifier-cells.js @@ -0,0 +1,29 @@ +"use server"; + +import { cache } from "react"; +import { getConfig, buildScript } from "@/lib/config"; +import { addressToScript } from "@ckb-lumos/helpers"; +import { Indexer } from "@ckb-lumos/ckb-indexer"; + +function buildVerifierScript(ckbChainConfig) { + return buildScript(ckbChainConfig.SCRIPTS.DAO_ACTION_VERIFIER, "0x"); +} + +export async function getVerifierCellsWithoutCache(lockAddress, config) { + const { ckbRpcUrl, ckbChainConfig } = config ?? getConfig(); + const indexer = new Indexer(ckbRpcUrl); + + const lock = addressToScript(lockAddress, { config: ckbChainConfig }); + const collector = indexer.collector({ + lock, + argsLen: (lock.args.length - 2) / 2, + type: buildVerifierScript(ckbChainConfig), + }); + const verifierCells = []; + for await (const cell of collector.collect()) { + verifierCells.push(cell); + } + return verifierCells; +} + +export const getVerifierCellsWithCache = cache(getVerifierCellsWithoutCache); diff --git a/src/actions/reclaim.js b/src/actions/reclaim.js new file mode 100644 index 0000000..9cbd559 --- /dev/null +++ b/src/actions/reclaim.js @@ -0,0 +1,29 @@ +"use server"; + +import { reclaimDaoVerifiers } from "@/lib/cobuild/publishers"; +import { getConfig } from "@/lib/config"; +import { prepareLockActions } from "@/lib/cobuild/lock-actions"; +import { payFee } from "@/lib/cobuild/fee-manager"; + +export default async function reclaim(from, config) { + config = config ?? getConfig(); + + try { + let buildingPacket = await reclaimDaoVerifiers(config)({ from }); + buildingPacket = await payFee( + buildingPacket, + [{ address: from, feeRate: 1200 }], + config, + ); + buildingPacket = prepareLockActions(buildingPacket, config.ckbChainConfig); + + return { + buildingPacket, + }; + } catch (err) { + console.error(err.stack); + return { + error: err.toString(), + }; + } +} diff --git a/src/actions/withdraw.js b/src/actions/withdraw.js index bb2db8c..68ae07d 100644 --- a/src/actions/withdraw.js +++ b/src/actions/withdraw.js @@ -4,12 +4,16 @@ import { withdrawDao } from "@/lib/cobuild/publishers"; import { getConfig } from "@/lib/config"; import { prepareLockActions } from "@/lib/cobuild/lock-actions"; import { payFee } from "@/lib/cobuild/fee-manager"; +import { prepareVerifier } from "@/lib/papps/dao/verifier"; -export default async function withdraw(from, cell, config) { +export default async function withdraw(from, cell, shouldPackVerifier, config) { config = config ?? getConfig(); try { let buildingPacket = await withdrawDao(config)({ cell }); + if (shouldPackVerifier) { + buildingPacket = await prepareVerifier(buildingPacket, from, config); + } buildingPacket = await payFee( buildingPacket, [{ address: from, feeRate: 1200 }], diff --git a/src/app/u/[wallet]/[connection]/assets.js b/src/app/u/[wallet]/[connection]/assets.js index 9190655..f4e4868 100644 --- a/src/app/u/[wallet]/[connection]/assets.js +++ b/src/app/u/[wallet]/[connection]/assets.js @@ -1,7 +1,10 @@ -import Link from "next/link"; +import { BI, formatUnit } from "@ckb-lumos/bi"; import { Button } from "flowbite-react"; -import Capacity from "@/components/capacity"; +import Link from "next/link"; + import { fetchAssetsWithCache } from "@/actions/fetch-assets"; +import Capacity from "@/components/capacity"; +import PackingVerifierHelpText from "@/components/packing-verifier-help-text"; import DaoCells from "./dao-cells"; import Loading from "./loading"; @@ -25,7 +28,38 @@ export function CkbSection({ wallet, connection, address, ckbBalance }) { ); } -export function DaoSection({ wallet, connection, address, daoCells }) { +export function VerifierCells({ wallet, connection, verifierCells }) { + let lockedCapacity = BI.from(0); + for (const cell of verifierCells) { + lockedCapacity = lockedCapacity.add(BI.from(cell.cellOutput.capacity)); + } + return ( + <> +
+ You have {formatUnit(lockedCapacity, "ckb")} CKB locked in DAO action + verifier cells. You can reclaim them by destroy the verifier cells. +
+ + > + ); +} + +export function DaoSection({ + wallet, + connection, + address, + daoCells, + verifierCells, +}) { return (+ +
+ {lockedCapacity.gt(0) ? ( ++ You can reclaim {formatUnit(lockedCapacity, "ckb")} CKB from{" "} + {verifierCells.length} {verifierCells.length == 1 ? "cell" : "cells"}. +
+ ) : null} + > + ); +} + +export default function WithdrawForm({ wallet, connection, address, config }) { + const router = useRouter(); + const verifierCells = useVerifierCells(address); + const [formState, setFormState] = useState({}); + const [pending, setPending] = useState(false); + const [signedBuildingPacket, setSignedBuildingPacket] = useState(null); + const back = () => router.back(); + const onConfirm = async () => { + setPending(true); + try { + setFormState(await reclaim(address)); + } catch (err) { + setFormState({ error: err.toString() }); + } + setPending(false); + }; + + if ( + formState.buildingPacket === null || + formState.buildingPacket === undefined + ) { + const childProps = { + pending, + onConfirm, + verifierCells, + }; + return ( + <> + {formState.error ? ( +{JSON.stringify(buildingPacket, null, 2)} @@ -564,10 +563,10 @@ function collectAssets( } } else if (isDaoDepositCell(cellOutput, cellData, ckbChainConfig)) { assets.daoWithdrawn = assets.daoWithdrawn.add(cellCapacity); - } else if (isNoneDaoTypedCell(cellOutput, cellData, ckbChainConfig)) { + } else if (isNoneDaoTypedCell(cellOutput, ckbChainConfig)) { assets.destroyedTypedCells.push({ cellOutput, - outPoint: buildingPacket.value.packet.inputs[i].previousOutput, + outPoint: buildingPacket.value.payload.inputs[i].previousOutput, data: cellData, }); } @@ -580,9 +579,9 @@ function collectAssets( if (isDaoDepositCell(cellOutput, cellData, ckbChainConfig)) { assets.daoDeposited = assets.daoDeposited.add(cellCapacity); - } else if (isNoneDaoTypedCell(cellOutput, cellData, ckbChainConfig)) { + } else if (isNoneDaoTypedCell(cellOutput, ckbChainConfig)) { assets.createdTypedCells.push({ - outPoint: buildingPacket.value.packet.inputs[i].previousOutput, + outPoint: buildingPacket.value.payload.outputs[i].previousOutput, data: cellData, }); } diff --git a/src/lib/config.js b/src/lib/config.js index fb04a8a..d0f69b0 100644 --- a/src/lib/config.js +++ b/src/lib/config.js @@ -27,6 +27,16 @@ const CKB_CHAINS_CONFIGS = { INDEX: "0x0", DEP_TYPE: "code", }, + + DAO_ACTION_VERIFIER: { + CODE_HASH: + "0xbdca5b74e5d0c913fed19d8482a99af1ef8a639541438b2e00189f5e18907ef9", + HASH_TYPE: "type", + TX_HASH: + "0x9157bcc278176ba9e823a50d72631be9e9b964e7a5ca11db2782c059c4c788ad", + INDEX: "0x0", + DEP_TYPE: "code", + }, }, }, }; @@ -66,6 +76,15 @@ function buildCkbChainConfig(ckbChain) { TX_HASH: presence(process.env.NEXT_PUBLIC_OMNILOCK_TX_HASH), }, ); + const DAO_ACTION_VERIFIER = assign( + { ...template.SCRIPTS.DAO_ACTION_VERIFIER }, + { + CODE_HASH: presence( + process.env.NEXT_PUBLIC_DAO_ACTION_VERIFIER_CODE_HASH, + ), + TX_HASH: presence(process.env.NEXT_PUBLIC_DAO_ACTION_VERIFIER_TX_HASH), + }, + ); const tx0 = presence(process.env.NEXT_PUBLIC_CKB_GENESIS_TX_0) ?? @@ -80,6 +99,7 @@ function buildCkbChainConfig(ckbChain) { SCRIPTS: { JOYID, OMNILOCK_CUSTOM, + DAO_ACTION_VERIFIER, DAO: { ...template.SCRIPTS.DAO, TX_HASH: tx0, @@ -126,3 +146,21 @@ export function getTestnetConfig() { ckbChainConfig: CKB_CHAINS_CONFIGS[DEFAULT_CKB_CHAIN], }; } + +export function buildCellDep(scriptInfo) { + return { + outPoint: { + txHash: scriptInfo.TX_HASH, + index: scriptInfo.INDEX, + }, + depType: scriptInfo.DEP_TYPE, + }; +} + +export function buildScript(scriptInfo, args) { + return { + codeHash: scriptInfo.CODE_HASH, + hashType: scriptInfo.HASH_TYPE, + args, + }; +} diff --git a/src/lib/lumos-adapter/create-lumos-ckb-builder.js b/src/lib/lumos-adapter/create-lumos-ckb-builder.js index 6acea5b..bbe0fa5 100644 --- a/src/lib/lumos-adapter/create-lumos-ckb-builder.js +++ b/src/lib/lumos-adapter/create-lumos-ckb-builder.js @@ -1,15 +1,16 @@ -import { Indexer } from "@ckb-lumos/ckb-indexer"; -import { TransactionSkeleton } from "@ckb-lumos/helpers"; -import { common as commonScripts } from "@ckb-lumos/common-scripts"; - +import { buildCellDep, buildScript } from "@/lib/config"; +import { getDaoPappRegistry } from "@/lib/papps/dao/registry"; import { - createBuildingPacketByFormDataCreator, createBuildingPacketByCreator, + createBuildingPacketByFormDataCreator, } from "@/lib/papps/papp"; -import { getDaoPappRegistry } from "@/lib/papps/dao/registry"; +import { BI } from "@ckb-lumos/bi"; +import { Indexer } from "@ckb-lumos/ckb-indexer"; +import { common as commonScripts } from "@ckb-lumos/common-scripts"; +import { TransactionSkeleton, addressToScript } from "@ckb-lumos/helpers"; -import initLumosCommonScripts from "./init-lumos-common-scripts"; import createBuildingPacketFromSkeleton from "./create-building-packet-from-skeleton"; +import initLumosCommonScripts from "./init-lumos-common-scripts"; export default function createLumosCkbBuilder(config) { const { ckbRpcUrl, ckbChainConfig } = config; @@ -58,5 +59,49 @@ export default function createLumosCkbBuilder(config) { cellPointer: cell.outPoint, }); }, + + reclaimDaoVerifiers: async function ({ from }) { + let txSkeleton = TransactionSkeleton({ + cellProvider: indexer, + }); + + const verifierScript = buildScript( + ckbChainConfig.SCRIPTS.DAO_ACTION_VERIFIER, + "0x", + ); + const lock = addressToScript(from, { config: ckbChainConfig }); + const collector = indexer.collector({ + lock, + argsLen: (lock.args.length - 2) / 2, + type: verifierScript, + }); + let outputCapacity = BI.from(0); + for await (const cell of collector.collect()) { + outputCapacity = outputCapacity.add(BI.from(cell.cellOutput.capacity)); + txSkeleton = await commonScripts.setupInputCell( + txSkeleton, + cell, + from, + { + config: ckbChainConfig, + }, + ); + } + txSkeleton = txSkeleton.update("outputs", (outputs) => + outputs.clear().push({ + cellOutput: { + lock, + capacity: outputCapacity.toHexString(), + }, + data: "0x", + }), + ); + + txSkeleton = txSkeleton.update("cellDeps", (cellDeps) => + cellDeps.push(buildCellDep(ckbChainConfig.SCRIPTS.DAO_ACTION_VERIFIER)), + ); + + return createBuildingPacketFromSkeleton(txSkeleton); + }, }; } diff --git a/src/lib/lumos-adapter/init-lumos-common-scripts.js b/src/lib/lumos-adapter/init-lumos-common-scripts.js index 32d6010..4f1564e 100644 --- a/src/lib/lumos-adapter/init-lumos-common-scripts.js +++ b/src/lib/lumos-adapter/init-lumos-common-scripts.js @@ -1,6 +1,7 @@ +import { buildCellDep } from "@/lib/config"; import { - parseFromInfo, common as commonScripts, + parseFromInfo, } from "@ckb-lumos/common-scripts"; import { addCellDep } from "@ckb-lumos/common-scripts/lib/helper"; @@ -105,21 +106,9 @@ export function buildLockInfo(ckbChainConfig, scriptInfo, extraScripts) { // II. CellDeps //=========================== // The helper method addCellDep avoids adding duplicated cell deps. - addCellDep(txMutable, { - outPoint: { - txHash: scriptInfo.TX_HASH, - index: scriptInfo.INDEX, - }, - depType: scriptInfo.DEP_TYPE, - }); + addCellDep(txMutable, buildCellDep(scriptInfo)); for (const extraScriptInfo of extraScripts) { - addCellDep(txMutable, { - outPoint: { - txHash: extraScriptInfo.TX_HASH, - index: extraScriptInfo.INDEX, - }, - depType: extraScriptInfo.DEP_TYPE, - }); + addCellDep(txMutable, buildCellDep(extraScriptInfo)); } return txMutable.asImmutable(); diff --git a/src/lib/papps/dao/action-creators.js b/src/lib/papps/dao/action-creators.js index f8a8c81..e22023c 100644 --- a/src/lib/papps/dao/action-creators.js +++ b/src/lib/papps/dao/action-creators.js @@ -11,13 +11,6 @@ function addressToScriptOpt(address, lumosOptions) { return undefined; } -function buildSingleOperation(operation) { - return { - type: "SingleOperation", - value: operation, - }; -} - export function depositWithFormData(config, formData) { const lumosOptions = { config: config.ckbChainConfig }; diff --git a/src/lib/papps/dao/lumos-callbacks.js b/src/lib/papps/dao/lumos-callbacks.js index 792440d..6c3e069 100644 --- a/src/lib/papps/dao/lumos-callbacks.js +++ b/src/lib/papps/dao/lumos-callbacks.js @@ -1,10 +1,3 @@ -import { RPC } from "@ckb-lumos/rpc"; -import { BI } from "@ckb-lumos/bi"; -import { common as commonScripts, dao } from "@ckb-lumos/common-scripts"; -import { blockchain } from "@ckb-lumos/base"; -import { bytes, number } from "@ckb-lumos/codec"; -import * as lumosHelpers from "@ckb-lumos/helpers"; - import { getCellWithoutCache } from "@/actions/get-cell"; import { getDepositBlockNumberFromWithdrawCell, @@ -12,24 +5,21 @@ import { } from "@/lib/dao"; import { mergeBuildingPacketFromSkeleton } from "@/lib/lumos-adapter/create-building-packet-from-skeleton"; import createSkeletonFromBuildingPacket from "@/lib/lumos-adapter/create-skeleton-from-building-packet"; +import { blockchain } from "@ckb-lumos/base"; +import { BI } from "@ckb-lumos/bi"; +import { bytes, number } from "@ckb-lumos/codec"; +import { common as commonScripts, dao } from "@ckb-lumos/common-scripts"; +import * as lumosHelpers from "@ckb-lumos/helpers"; +import { RPC } from "@ckb-lumos/rpc"; +import { buildCellDep } from "@/lib/config"; import { DaoActionData } from "./schema"; import { - getDaoScriptInfo, getDaoScriptHash, + getDaoScriptInfo, getDaoScriptInfoHash, } from "./script-info"; -function buildCellDep(scriptInfo) { - return { - outPoint: { - txHash: scriptInfo.TX_HASH, - index: scriptInfo.INDEX, - }, - depType: scriptInfo.DEP_TYPE, - }; -} - function addDistinctCellDep(list, ...items) { return pushDistinctBy( list, diff --git a/src/lib/papps/dao/script-info.js b/src/lib/papps/dao/script-info.js index 8f957c3..489a4cf 100644 --- a/src/lib/papps/dao/script-info.js +++ b/src/lib/papps/dao/script-info.js @@ -1,4 +1,4 @@ -import { getConfig } from "@/lib/config"; +import { getConfig, buildScript } from "@/lib/config"; import { createScriptInfoFromHumanTemplate, computeScriptInfoHash, @@ -21,11 +21,7 @@ export function getDaoHumanScriptInfoTemplate() { function getDaoScriptHashFromConfig(config) { const daoInfo = config.ckbChainConfig.SCRIPTS.DAO; - const daoScript = { - codeHash: daoInfo.CODE_HASH, - hashType: daoInfo.HASH_TYPE, - args: "0x", - }; + const daoScript = buildScript(daoInfo, "0x"); return computeScriptHash(daoScript); } diff --git a/src/lib/papps/dao/verifier.js b/src/lib/papps/dao/verifier.js new file mode 100644 index 0000000..bcc7e09 --- /dev/null +++ b/src/lib/papps/dao/verifier.js @@ -0,0 +1,98 @@ +import { buildCellDep, buildScript } from "@/lib/config"; +import { mergeBuildingPacketFromSkeleton } from "@/lib/lumos-adapter/create-building-packet-from-skeleton"; +import createSkeletonFromBuildingPacket from "@/lib/lumos-adapter/create-skeleton-from-building-packet"; +import { Indexer } from "@ckb-lumos/ckb-indexer"; +import { common as commonScripts } from "@ckb-lumos/common-scripts"; +import { + addressToScript, + minimalCellCapacityCompatible, +} from "@ckb-lumos/helpers"; + +export async function prepareVerifier(buildingPacket, fromAddress, config) { + let txSkeleton = createSkeletonFromBuildingPacket(buildingPacket, config); + + const { ckbChainConfig, ckbRpcUrl } = config; + const indexer = new Indexer(ckbRpcUrl); + const verifierTypeScript = buildScript( + ckbChainConfig.SCRIPTS.DAO_ACTION_VERIFIER, + "0x", + ); + const from = addressToScript(fromAddress, { config: ckbChainConfig }); + + const verifierCollector = indexer.collector({ + lock: from, + argsLen: (from.args.length - 2) / 2, + type: verifierTypeScript, + data: "0x", + }); + const verifierCell = (await verifierCollector.collect().next()).value; + if (verifierCell === null || verifierCell === undefined) { + const newVerifierCell = { + cellOutput: { + capacity: "0x0", + lock: from, + type: verifierTypeScript, + }, + data: "0x", + outPoint: undefined, + blockHash: undefined, + }; + const minimalCapacity = minimalCellCapacityCompatible(newVerifierCell); + newVerifierCell.cellOutput.capacity = minimalCapacity.toHexString(); + + // create a new verifier cell + txSkeleton = await commonScripts.injectCapacity( + txSkeleton, + [fromAddress], + minimalCapacity, + fromAddress, + undefined, + { config: ckbChainConfig }, + ); + txSkeleton = txSkeleton.update("outputs", (outputs) => + outputs.push(newVerifierCell), + ); + } else { + txSkeleton = await commonScripts.setupInputCell( + txSkeleton, + verifierCell, + fromAddress, + { + config: ckbChainConfig, + }, + ); + } + + // exchange change output and verifier cell + const changeOutputIndex = buildingPacket.value.changeOutput; + const outputsSize = txSkeleton.get("outputs").size; + + if ( + changeOutputIndex !== undefined && + changeOutputIndex !== null && + changeOutputIndex < outputsSize - 1 + ) { + // exchange change cell and verifier cell to avoid multiple change cells + txSkeleton = txSkeleton.update("outputs", (outputs) => { + const verifierCell = outputs.get(outputsSize - 1); + const changeCell = outputs.get(changeOutputIndex); + return outputs + .set(changeOutputIndex, verifierCell) + .set(outputsSize - 1, changeCell); + }); + txSkeleton = txSkeleton.update("fixedEntries", (fixedEntries) => + fixedEntries.push({ field: "outputs", index: outputsSize - 2 }), + ); + } else { + // no change output, fixed all outputs + txSkeleton = txSkeleton.update("fixedEntries", (fixedEntries) => + fixedEntries.push({ field: "outputs", index: outputsSize - 1 }), + ); + } + + txSkeleton = txSkeleton.update("cellDeps", (cellDeps) => + cellDeps.push(buildCellDep(ckbChainConfig.SCRIPTS.DAO_ACTION_VERIFIER)), + ); + + return mergeBuildingPacketFromSkeleton(buildingPacket, txSkeleton); +} diff --git a/src/lib/wallet/btc-wallet.js b/src/lib/wallet/btc-wallet.js index f17fa58..e02860d 100644 --- a/src/lib/wallet/btc-wallet.js +++ b/src/lib/wallet/btc-wallet.js @@ -1,5 +1,6 @@ import { bytes } from "@ckb-lumos/codec"; import * as lumosHelpers from "@ckb-lumos/helpers"; +import { buildScript } from "@/lib/config"; import { bech32 } from "bech32"; import * as bs58 from "bs58"; import { packOmnilockWitnessLock } from "./omni-lock"; @@ -49,11 +50,7 @@ export function btcAddressToCkbAddress(btcAddress, scriptInfo, ckbChainConfig) { } args += "00"; - const script = { - codeHash: scriptInfo.CODE_HASH, - hashType: scriptInfo.HASH_TYPE, - args: args, - }; + const script = buildScript(scriptInfo, args); return lumosHelpers.encodeToAddress(script, { config: ckbChainConfig, }); diff --git a/src/lib/wallet/joyid.js b/src/lib/wallet/joyid.js index 135e9a8..ce67994 100644 --- a/src/lib/wallet/joyid.js +++ b/src/lib/wallet/joyid.js @@ -1,8 +1,9 @@ -import * as joyid from "@joyid/ckb"; import { bytes } from "@ckb-lumos/codec"; import * as lumosHelpers from "@ckb-lumos/helpers"; +import * as joyid from "@joyid/ckb"; import { urlSafeBase64Decode } from "../base64"; +import { buildScript } from "../config"; export const title = "Joyid"; export const lockScriptName = "Joyid Lock"; @@ -19,11 +20,7 @@ export function address(connection, ckbChainConfig) { config: ckbChainConfig, }); const scriptInfo = ckbChainConfig.SCRIPTS.JOYID; - const script = { - codeHash: scriptInfo.CODE_HASH, - hashType: scriptInfo.HASH_TYPE, - args, - }; + const script = buildScript(scriptInfo, args); return lumosHelpers.encodeToAddress(script, { config: ckbChainConfig, });