Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/PROPOSAL-plotlink.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ Chains a new plot to an existing storyline. Access-controlled to the storyline w
1. Validates writer identity (`msg.sender == writer`)
2. Validates CID length (46–100 bytes)
3. Checks storyline is not sunset
4. Enforces 72h deadline if enabled (`block.timestamp <= lastPlotTime + 72 hours`)
4. Enforces mandatory 7-day deadline (`block.timestamp <= lastPlotTime + 168 hours`)
5. Increments `plotCount` and updates `lastPlotTime`
6. Emits `PlotChained` event

Expand Down Expand Up @@ -122,7 +122,7 @@ struct Storyline {
address token; // storyline token address on Mint Club
uint256 plotCount; // total plots chained (genesis = 1)
uint256 lastPlotTime; // timestamp of last plot
bool hasDeadline; // whether 72h deadline is enabled
bool hasDeadline; // mandatory 7-day deadline (always true)
bool sunset; // true if deadline expired
}
```
Expand Down
6 changes: 3 additions & 3 deletions docs/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ Safety net for when the inline indexer misses a plot.

### P2-4: StoryFactory — chainPlot()

**Context**: §4.3 — access-controlled to the storyline writer. Validates CID length (46–100 bytes), checks the storyline isn't sunset, enforces 72h deadline if enabled. Increments plotCount and lastPlotTime. Emits PlotChained event with CID + contentHash. Measured gas: 39,826 (below the ~47k estimate).
**Context**: §4.3 — access-controlled to the storyline writer. Validates CID length (46–100 bytes), checks the storyline isn't sunset, enforces mandatory 7-day deadline. Increments plotCount and lastPlotTime. Emits PlotChained event with CID + contentHash. Measured gas: 39,826 (below the ~47k estimate).

**Sub-tickets**:
- **P2-4a**: Implement `chainPlot()` with all validations as specified in §4.3.
Expand Down Expand Up @@ -275,7 +275,7 @@ After gas measurements are available, update the proposal document.

### P3-2: Create Storyline Flow

**Context**: §4.1 (Write Flow) + §3.7 (Deadline). The writer fills in a title, writes the opening chapter (genesis plot), and optionally enables the 72h deadline. The publishing flow has 5 UX states defined in §4.1: uploading → confirm in wallet → publishing to Base → indexing → published. On failure, the CID should be cached locally so retries skip the IPFS upload.
**Context**: §4.1 (Write Flow) + §3.7 (Deadline). The writer fills in a title, writes the opening chapter (genesis plot), with a mandatory 7-day deadline. The publishing flow has 5 UX states defined in §4.1: uploading → confirm in wallet → publishing to Base → indexing → published. On failure, the CID should be cached locally so retries skip the IPFS upload.

**Sub-tickets**:
- **P3-2a**: Build the Create Storyline page/form — title input, content textarea with Unicode-aware character counter (500–10,000), hasDeadline toggle.
Expand All @@ -300,7 +300,7 @@ After gas measurements are available, update the proposal document.

**Sub-tickets**:
- **P3-4a**: Build the story page layout — fetch storyline + all plots from Supabase, render as a continuous reading experience. Show writer address, plot count, title.
- **P3-4b**: Add deadline countdown component — if `has_deadline` is true, show remaining time until sunset based on `last_plot_time + 72h`.
- **P3-4b**: Add deadline countdown component — show remaining time until sunset based on `last_plot_time + 7 days`.
- **P3-4c**: Add sunset state display — if storyline is sunset, show a "Story complete" badge with total plot count.

---
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/commands/status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ export function registerStatus(program: Command): void {
console.log(`Last plot: ${new Date(dbRow.last_plot_time).toISOString()}`);
}

// Deadline remaining (72h from last plot)
// Deadline remaining (7 days from last plot)
if (dbRow.has_deadline && dbRow.last_plot_time && !dbRow.sunset) {
const DEADLINE_HOURS = 168;
const deadlineMs =
Expand Down
15 changes: 11 additions & 4 deletions src/components/ClaimRoyalties.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useWriteContract } from "wagmi";
import { useQuery } from "@tanstack/react-query";
import { formatUnits, type Address } from "viem";
import { publicClient } from "../../lib/rpc";
import { mcv2BondAbi } from "../../lib/price";
import { mcv2BondAbi, getTokenTVL } from "../../lib/price";
import { MCV2_BOND, IS_TESTNET, EXPLORER_URL } from "../../lib/contracts/constants";

type TxState = "idle" | "confirming" | "pending" | "done" | "error";
Expand Down Expand Up @@ -42,6 +42,13 @@ export function ClaimRoyalties({ tokenAddress, plotCount, beneficiary }: ClaimRo
refetchInterval: 30000,
});

// Fetch reserve token decimals dynamically
const { data: tvlData } = useQuery({
queryKey: ["claim-decimals", tokenAddress],
queryFn: () => getTokenTVL(tokenAddress),
});
const decimals = tvlData?.decimals ?? 18;

const unclaimed = royaltyInfo?.unclaimed ?? BigInt(0);
const eligible = plotCount >= 2;
const canClaim = eligible && unclaimed > BigInt(0);
Expand Down Expand Up @@ -107,14 +114,14 @@ export function ClaimRoyalties({ tokenAddress, plotCount, beneficiary }: ClaimRo
Chain at least 2 plots ({plotCount}/2)
</li>
<li>
Unclaimed &gt; 0 ({formatUnits(unclaimed, 18)} {reserveLabel})
Unclaimed &gt; 0 ({formatUnits(unclaimed, decimals)} {reserveLabel})
</li>
</ul>
</div>
)}
</div>
<span className="text-foreground ml-1">
{formatUnits(unclaimed, 18)} {reserveLabel}
{formatUnits(unclaimed, decimals)} {reserveLabel}
</span>
</div>
<button
Expand All @@ -128,7 +135,7 @@ export function ClaimRoyalties({ tokenAddress, plotCount, beneficiary }: ClaimRo
{txState === "idle" && "Claim"}
{txState === "confirming" && "Confirm..."}
{txState === "pending" && "Pending..."}
{txState === "done" && `Claimed ${formatUnits(claimedAmount, 18)} ${reserveLabel}`}
{txState === "done" && `Claimed ${formatUnits(claimedAmount, decimals)} ${reserveLabel}`}
{txState === "error" && "Retry"}
</button>
</div>
Expand Down
Loading