Skip to content

Commit

Permalink
Merge branch 'dao-withdraw-phase-1'
Browse files Browse the repository at this point in the history
  • Loading branch information
doitian committed Dec 27, 2023
2 parents e53a7ac + c28bfcf commit 4cadea2
Show file tree
Hide file tree
Showing 12 changed files with 343 additions and 89 deletions.
2 changes: 1 addition & 1 deletion src/actions/deposit.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { parseUnit } from "@ckb-lumos/bi";
import { depositDao } from "@/lib/cobuild/publishers";
import { configFromEnv } from "@/lib/config";

export default async function transfer(_prevState, formData, config) {
export default async function deposit(_prevState, formData, config) {
config = config ?? configFromEnv(process.env);

const from = formData.get("from");
Expand Down
5 changes: 4 additions & 1 deletion src/actions/get-cell.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@ export async function getCellWithoutCache(outPoint, config) {
}

const txResp = await rpc.getTransaction(outPoint.txHash, "0x1", true);
const blockHash = txResp.txStatus.blockHash;
const headerResp = await rpc.getHeader(blockHash);

return {
outPoint,
blockHash,
blockNumber: headerResp.number,
cellOutput: liveCellResp.cell.output,
data: liveCellResp.cell.data.content,
blockHash: txResp.txStatus.blockHash,
};
}

Expand Down
19 changes: 19 additions & 0 deletions src/actions/withdraw.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"use server";

import { withdrawDao } from "@/lib/cobuild/publishers";
import { configFromEnv } from "@/lib/config";

export default async function withdraw(from, cell, config) {
config = config ?? configFromEnv(process.env);

try {
const buildingPacket = await withdrawDao(config)({ from, cell });
return {
buildingPacket,
};
} catch (err) {
return {
error: err.toString(),
};
}
}
73 changes: 71 additions & 2 deletions src/app/accounts/[address]/dao-cells.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export function DepositRow({ address, cell, tipHeader }) {
<td>{dao.duration(depositHeader, tipHeader).humanize()}</td>
<td>
<DaoCycleProgress
progress={dao.currentCycleProgress(depositHeader, tipHeader)}
progress={dao.currentCycleProgress(tipHeader, depositHeader)}
/>
</td>
</>
Expand Down Expand Up @@ -76,13 +76,82 @@ export function DepositsTable({ address, cells, tipHeader }) {
);
}

export function WithdrawRow({ address, cell, tipHeader }) {
const depositBlockNumber = dao.getDepositBlockNumberFromWithdrawCell(cell);
const depositHeader = useHeaderByNumber(depositBlockNumber);
const withdrawHeader = useHeaderByNumber(cell.blockNumber);
const waitingDuration =
tipHeader && depositHeader && withdrawHeader
? dao.estimateWithdrawWaitingDurationUntil(
tipHeader,
depositHeader,
withdrawHeader,
)
: null;
const key = cellKey(cell);

return (
<tr key={key}>
<td>
<Capacity value={cell.cellOutput.capacity} />
</td>
<td>
{tipHeader && depositHeader ? (
<>
+<Capacity value={dao.reward(cell, depositHeader, tipHeader)} />
</>
) : (
<Loading />
)}
</td>
<td>
{waitingDuration ? (
<p>Waiting for {waitingDuration.humanize()}</p>
) : (
<Button
as={Link}
color="green"
href={`/accounts/${address}/claim/${key}`}
className="not-prose inline-block"
>
Claim
</Button>
)}
</td>
</tr>
);
}

export function WithdrawsTable({ address, cells, tipHeader }) {
return (
<table className="table-auto">
<thead>
<tr>
<th>Base</th>
<th>Reward</th>
<th>&nbsp;</th>
</tr>
</thead>
<tbody>
{cells.map((cell) => WithdrawRow({ address, cell, tipHeader }))}
</tbody>
</table>
);
}

export default function DaoCells({ address, daoCells }) {
const tipHeader = useTipHeader();
const { deposits } = daoCells;
const { deposits, withdraws } = daoCells;
return (
<>
<h3>Deposits</h3>
<DepositsTable address={address} cells={deposits} tipHeader={tipHeader} />
<h3>Withdraws</h3>
<WithdrawsTable
address={address}
cells={withdraws}
tipHeader={tipHeader}
/>
</>
);
}
134 changes: 134 additions & 0 deletions src/app/accounts/[address]/withdraw/[txHash]/[index]/form.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
"use client";

import { useState } from "react";
import { useRouter } from "next/navigation";
import { Alert, Button } from "flowbite-react";

import withdraw from "@/actions/withdraw";
import useTipHeader from "@/hooks/use-tip-header";
import useHeader from "@/hooks/use-header";
import useCell from "@/hooks/use-cell";

import Capacity from "@/components/capacity";
import {
DaoCycleProgress,
DaoCycleProgressHint,
daoCycleProgressColor,
} from "@/components/dao-cycle-progress";
import * as dao from "@/lib/dao";
import Loading from "./loading";
import SignForm from "../../../sign-form";
import SubmitBuildingPacket from "../../../submit-building-packet";

function CellDetailsDisplay({ progress, cell, depositHeader, tipHeader }) {
return (
<dl>
<dd className="px-0">
<DaoCycleProgressHint progress={progress} />
</dd>
<dt>Base</dt>
<dd>
<Capacity value={cell.cellOutput.capacity} />
</dd>
<dt>Reward</dt>
<dd>
+<Capacity value={dao.reward(cell, depositHeader, tipHeader)} />
</dd>
<dt>Duration</dt>
<dd>{dao.duration(depositHeader, tipHeader).humanize()}</dd>
<dt>Current Cycle</dt>
<dd>
<DaoCycleProgress progress={progress} />
</dd>
</dl>
);
}

function CellDetails({ cell, pending, onConfirm }) {
const tipHeader = useTipHeader();
const depositHeader = useHeader(cell.blockHash);

if (!tipHeader || !depositHeader) {
return <Loading />;
}

const progress = dao.currentCycleProgress(tipHeader, depositHeader);
const color = daoCycleProgressColor(progress);

return (
<>
<p>
<Button
color={color}
isProcessing={pending}
disabled={pending}
onClick={() => onConfirm(cell)}
>
Confirm Withdraw
</Button>
</p>
<CellDetailsDisplay {...{ progress, cell, tipHeader, depositHeader }} />
</>
);
}

function LoadCell({ outPoint, pending, onConfirm }) {
const cell = useCell(outPoint);
const childProps = { cell, pending, onConfirm };
return cell ? <CellDetails {...childProps} /> : <Loading />;
}

export default function WithdrawForm({ address, outPoint, config }) {
const router = useRouter();
const [formState, setFormState] = useState({});
const [pending, setPending] = useState(false);
const [signedBuildingPacket, setSignedBuildingPacket] = useState(null);
const back = () => router.back();
const onConfirm = async (cell) => {
setPending(true);
try {
setFormState(await withdraw(address, cell));
} catch (err) {
setFormState({ error: err.toString() });
}
setPending(false);
};

if (
formState.buildingPacket === null ||
formState.buildingPacket === undefined
) {
const childProps = { outPoint, pending, onConfirm };
return (
<>
{formState.error ? (
<Alert className="mb-5" color="failure">
{formState.error}
</Alert>
) : null}
<LoadCell {...childProps} />
</>
);
} else if (
signedBuildingPacket === null ||
signedBuildingPacket === undefined
) {
return (
<SignForm
address={address}
buildingPacket={formState.buildingPacket}
ckbChainConfig={config.ckbChainConfig}
onSubmit={setSignedBuildingPacket}
onCancel={back}
/>
);
} else {
return (
<SubmitBuildingPacket
buildingPacket={signedBuildingPacket}
ckbChainConfig={config.ckbChainConfig}
onClose={back}
/>
);
}
}
80 changes: 10 additions & 70 deletions src/app/accounts/[address]/withdraw/[txHash]/[index]/page.js
Original file line number Diff line number Diff line change
@@ -1,84 +1,24 @@
"use client";
import { configFromEnv } from "@/lib/config";

import { Button } from "flowbite-react";
import WithdrawForm from "./form";

import useTipHeader from "@/hooks/use-tip-header";
import useHeader from "@/hooks/use-header";
import useCell from "@/hooks/use-cell";
export default function Withdraw({
params: { address, txHash, index },
config,
}) {
config = config ?? configFromEnv(process.env);

import Capacity from "@/components/capacity";
import DaoCycleProgress, {
WARNING_THRESHOLD,
} from "@/components/dao-cycle-progress";
import * as dao from "@/lib/dao";
import Loading from "./loading";

function WithdrawHint({ progress }) {
const waitingDuration = dao.estimateWithdrawWaitingDuration(progress);

if (progress >= WARNING_THRESHOLD) {
return (
<p>
The current cycle is about to finish in {waitingDuration.humanize()}. If
the chain fails to accept your withdraw request before the cycle
finishes, you have to wait another cycle to claim the withdraw.
</p>
);
} else {
return (
<p>
You have to wait for {waitingDuration.humanize()} before claiming the
withdraw. You won't get reward during this waiting period.
</p>
);
}
}

function CellLoaded({ address, cell }) {
const tipHeader = useTipHeader();
const depositHeader = useHeader(cell.blockHash);

if (!tipHeader || !depositHeader) {
return <Loading />;
}

const progress = dao.currentCycleProgress(depositHeader, tipHeader);

return (
<dl>
<dd className="px-0">
<Button>Confirm Withdraw</Button>
</dd>
<dt>Base</dt>
<dd>
<Capacity value={cell.cellOutput.capacity} />
</dd>
<dt>Reward</dt>
<dd>
+<Capacity value={dao.reward(cell, depositHeader, tipHeader)} />
</dd>
<dt>Duration</dt>
<dd>{dao.duration(depositHeader, tipHeader).humanize()}</dd>
<dt>Current Cycle</dt>
<dd>
<DaoCycleProgress progress={progress} />
<WithdrawHint progress={progress} />
</dd>
</dl>
);
}

export default function Withdraw({ params: { address, txHash, index } }) {
const outPoint = {
txHash: `0x${txHash}`,
index: `0x${index.toString(16)}`,
};
const cell = useCell(outPoint);

const childProps = { address, outPoint, config };

return (
<main>
<h2>Withdraw</h2>
{cell ? <CellLoaded address={address} cell={cell} /> : <Loading />}
<WithdrawForm {...childProps} />
</main>
);
}
Loading

0 comments on commit 4cadea2

Please sign in to comment.