Skip to content

Commit

Permalink
✨ Pack verifier for depositing
Browse files Browse the repository at this point in the history
  • Loading branch information
doitian committed Feb 9, 2024
1 parent ec967c3 commit 7a068d9
Show file tree
Hide file tree
Showing 12 changed files with 236 additions and 23 deletions.
11 changes: 11 additions & 0 deletions bin/use-env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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/,$//' \
Expand All @@ -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
6 changes: 5 additions & 1 deletion src/actions/deposit.js
Original file line number Diff line number Diff line change
@@ -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 }],
Expand Down
15 changes: 11 additions & 4 deletions src/app/u/[wallet]/[connection]/deposit/form.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
"use client";

import { Alert, Checkbox, Label, Popover, TextInput } from "flowbite-react";
import { useRouter } from "next/navigation";
import { useEffect, useState } from "react";
import { useFormState } from "react-dom";
import { useRouter } from "next/navigation";
import { Label, TextInput, Alert } from "flowbite-react";

import deposit from "@/actions/deposit";
import { fetchAssetsWithCache } from "@/actions/fetch-assets";
import Capacity from "@/components/capacity";
import PackingVerifierHelpText from "@/components/packing-verifier-help-text";
import SubmitButton from "@/components/submit-button";
import { fetchAssetsWithCache } from "@/actions/fetch-assets";
import deposit from "@/actions/deposit";
import Loading from "../loading";
import SignForm from "../sign-form";
import SubmitBuildingPacket from "../submit-building-packet";
Expand Down Expand Up @@ -52,6 +53,12 @@ export function TransactionForm({ formAction, formState, address }) {
}
/>
</div>
<div>
<Checkbox className="mr-2" id="packVerifier" name="packVerifier" />
<Label htmlFor="packVerifier">
Pack Verifier (<PackingVerifierHelpText />)
</Label>
</div>
<SubmitButton>Deposit</SubmitButton>
</form>
);
Expand Down
5 changes: 4 additions & 1 deletion src/app/u/[wallet]/[connection]/sign-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ export default function SignForm({
ckbChainConfig,
);
onSubmit(
finalizeWitnesses(applyLockAction(buildingPacket, lockAction, seal)),
finalizeWitnesses(
applyLockAction(buildingPacket, lockAction, seal),
ckbChainConfig,
),
);
} catch (err) {
console.error(err.stack);
Expand Down
11 changes: 11 additions & 0 deletions src/components/packing-verifier-help-text.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default function PackingVerifierHelpText() {
return (
<a
target="_blank"
className="hover:cursor-pointer"
href="https://github.com/cryptape/ckb-dao-cobuild-poc/blob/develop/docs/packing-verifier.md"
>
What's This?
</a>
);
}
15 changes: 13 additions & 2 deletions src/lib/cobuild/fee-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export async function payFee(buildingPacket, feePayments, config) {
),
buildingPacket,
),
config.ckbChainConfig,
);

const buildingPacketHavePaidFee = await payFeeWithBuildingPacket(
Expand Down Expand Up @@ -55,7 +56,12 @@ function storeWitnessForFeeEstimation(
return generalLockActions.storeWitnessForFeeEstimation(
buildingPacket,
scriptHash,
inputIndices,
{
type: "WitnessArgsStore",
value: {
inputIndices,
},
},
// Variable length, but 500 is usually enough.
() => bytes.hexify(new Uint8Array(500)),
);
Expand All @@ -65,7 +71,12 @@ function storeWitnessForFeeEstimation(
return generalLockActions.storeWitnessForFeeEstimation(
buildingPacket,
scriptHash,
inputIndices,
{
type: "WitnessArgsStore",
value: {
inputIndices,
},
},
// 85 = 65 signature in OmnilockWitnessLock
() => `0x${"0".repeat(85 * 2)}`,
);
Expand Down
6 changes: 3 additions & 3 deletions src/lib/cobuild/general-lock-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,13 @@ export function prepareLockActionWithWitnessStore(
export function storeWitnessForFeeEstimation(
buildingPacket,
scriptHash,
inputIndices,
witnessStore,
createSealPlaceHolder,
) {
buildingPacket = prepareLockAction(
buildingPacket = prepareLockActionWithWitnessStore(
buildingPacket,
scriptHash,
inputIndices,
witnessStore,
createSealPlaceHolder,
);
const lockAction = buildingPacket.value.lockActions.find(
Expand Down
42 changes: 40 additions & 2 deletions src/lib/cobuild/lock-actions.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import { utils as lumosBaseUtils } from "@ckb-lumos/base";
import { bytes } from "@ckb-lumos/codec";

import * as generalLockActions from "./general-lock-actions";
import { parseWitnessType } from "./types";
import { groupByLock } from "./script-group";
import { parseWitnessType, WitnessLayout } from "./types";

const { computeScriptHash } = lumosBaseUtils;

// Generate lockActions.
//
// Do not set any witness in payload to use the Cobuild layout.
export function prepareLockActions(buildingPacket, ckbChainConfig) {
buildingPacket = finalizeWitnesses(buildingPacket, ckbChainConfig);

const groups = groupByLock(buildingPacket.value.resolvedInputs.outputs);
return Object.entries(groups).reduce(
(acc, [scriptHash, inputs]) =>
Expand All @@ -23,20 +26,35 @@ export function prepareLockActions(buildingPacket, ckbChainConfig) {
);
}

export function finalizeWitnesses(buildingPacket) {
function hasVerifierCell(buildingPacket, ckbChainConfig) {
const template = ckbChainConfig.SCRIPTS.DAO_ACTION_VERIFIER;
for (const output of buildingPacket.value.payload.outputs) {
if (output.type.codeHash === template.CODE_HASH) {
return true;
}
}

return false;
}

export function finalizeWitnesses(buildingPacket, ckbChainConfig) {
// fill holes
const witnesses = Array.from(buildingPacket.value.payload.witnesses).map(
(w) => w ?? "0x",
);

let hasSighashAll = false;
// If there's no SighashAll before SighashAllOnly, replace the first SighashAllOnly with SighashAll
for (const i of witnesses.keys()) {
if (witnesses[i] === "0x") {
continue;
}
const witnessType = parseWitnessType(witnesses[i]);
if (witnessType === "SighashAll") {
hasSighashAll = true;
break;
} else if (witnessType === "SighashAllOnly") {
hasSighashAll = true;
const witness = WitnessLayout.unpack(witnesses[i]);
witnesses[i] = bytes.hexify(
WitnessLayout.pack({
Expand All @@ -50,6 +68,26 @@ export function finalizeWitnesses(buildingPacket) {
}
}

// if there's a verifier cell, pack the Cobuild message into witness
if (!hasSighashAll && hasVerifierCell(buildingPacket, ckbChainConfig)) {
for (
let i = witnesses.length;
i < buildingPacket.value.payload.inputs.length;
++i
) {
witnesses[i] = "0x";
}
witnesses[buildingPacket.value.payload.inputs.length] = bytes.hexify(
WitnessLayout.pack({
type: "SighashAll",
value: {
seal: "0x",
message: buildingPacket.value.message,
},
}),
);
}

return {
type: buildingPacket.type,
value: {
Expand Down
6 changes: 3 additions & 3 deletions src/lib/cobuild/react/building-packet-review.js
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ export function TxSection({

return (
<dl className="divide-y divide-gray-100">
{process.env.DEBUG !== undefined ? (
{process.env.NODE_ENV === "development" ? (
<div className="py-3 sm:grid sm:grid-cols-3">
<dt className="leading-6 text-gray-900">Hash</dt>
<dd className="text-gray-700 sm:col-span-2 sm:mt-0 break-all">
Expand Down Expand Up @@ -567,7 +567,7 @@ function collectAssets(
} else if (isNoneDaoTypedCell(cellOutput, cellData, ckbChainConfig)) {
assets.destroyedTypedCells.push({
cellOutput,
outPoint: buildingPacket.value.packet.inputs[i].previousOutput,
outPoint: buildingPacket.value.payload.inputs[i].previousOutput,
data: cellData,
});
}
Expand All @@ -582,7 +582,7 @@ function collectAssets(
assets.daoDeposited = assets.daoDeposited.add(cellCapacity);
} else if (isNoneDaoTypedCell(cellOutput, cellData, ckbChainConfig)) {
assets.createdTypedCells.push({
outPoint: buildingPacket.value.packet.inputs[i].previousOutput,
outPoint: buildingPacket.value.payload.outputs[i].previousOutput,
data: cellData,
});
}
Expand Down
20 changes: 20 additions & 0 deletions src/lib/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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",
},
},
},
};
Expand Down Expand Up @@ -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) ??
Expand All @@ -80,6 +99,7 @@ function buildCkbChainConfig(ckbChain) {
SCRIPTS: {
JOYID,
OMNILOCK_CUSTOM,
DAO_ACTION_VERIFIER,
DAO: {
...template.SCRIPTS.DAO,
TX_HASH: tx0,
Expand Down
7 changes: 0 additions & 7 deletions src/lib/papps/dao/action-creators.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 };

Expand Down
Loading

0 comments on commit 7a068d9

Please sign in to comment.