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
2 changes: 2 additions & 0 deletions lib/contracts/abi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const plotChainedEvent = {
{ name: "storylineId", type: "uint256", indexed: true },
{ name: "plotIndex", type: "uint256", indexed: true },
{ name: "writer", type: "address", indexed: true },
{ name: "title", type: "string", indexed: false },
{ name: "contentCID", type: "string", indexed: false },
{ name: "contentHash", type: "bytes32", indexed: false },
],
Expand Down Expand Up @@ -68,6 +69,7 @@ export const chainPlotFunction = {
stateMutability: "nonpayable",
inputs: [
{ name: "storylineId", type: "uint256" },
{ name: "title", type: "string" },
{ name: "contentCID", type: "string" },
{ name: "contentHash", type: "bytes32" },
],
Expand Down
2 changes: 1 addition & 1 deletion lib/contracts/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const EXPLORER_URL = IS_TESTNET
/** StoryFactory — storyline + plot management */
export const STORY_FACTORY = (process.env.NEXT_PUBLIC_CONTRACT_ADDRESS ??
(IS_TESTNET
? "0x05C4d59529807316D6fA09cdaA509adDfe85b474"
? "0x6B8d38af1773dd162Ebc6f4A8eb923F3c669605d"
: "0x0000000000000000000000000000000000000000")) as `0x${string}`;

/** ZapPlotLinkMCV2 — one-click buy (ETH/USDC/HUNT -> storyline token) */
Expand Down
5 changes: 3 additions & 2 deletions packages/cli/src/commands/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ export function registerChain(program: Command): void {
.description("Chain a new plot onto an existing storyline")
.requiredOption("-s, --storyline <id>", "Storyline ID")
.requiredOption("-f, --file <path>", "Path to content file (plain text)")
.action(async (opts: { storyline: string; file: string }) => {
.option("-t, --title <title>", "Chapter title", "")
.action(async (opts: { storyline: string; file: string; title: string }) => {
try {
const content = readFileSync(opts.file, "utf-8");
const storylineId = BigInt(opts.storyline);
const client = buildClient({ ipfs: true });

console.log(`Chaining plot onto storyline ${storylineId}...`);
const result = await client.chainPlot(storylineId, content);
const result = await client.chainPlot(storylineId, content, opts.title);

console.log("Plot chained!");
console.log(` TX: ${result.txHash}`);
Expand Down
2 changes: 2 additions & 0 deletions packages/sdk/src/abi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const storyFactoryAbi = [
{ name: "storylineId", type: "uint256", indexed: true },
{ name: "plotIndex", type: "uint256", indexed: true },
{ name: "writer", type: "address", indexed: true },
{ name: "title", type: "string", indexed: false },
{ name: "contentCID", type: "string", indexed: false },
{ name: "contentHash", type: "bytes32", indexed: false },
],
Expand Down Expand Up @@ -63,6 +64,7 @@ export const storyFactoryAbi = [
stateMutability: "nonpayable",
inputs: [
{ name: "storylineId", type: "uint256" },
{ name: "title", type: "string" },
{ name: "contentCID", type: "string" },
{ name: "contentHash", type: "bytes32" },
],
Expand Down
4 changes: 3 additions & 1 deletion packages/sdk/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,11 +254,13 @@ export class PlotLink {
*
* @param storylineId - The storyline to chain onto
* @param content - Plot content (plain text)
* @param title - Optional chapter title (defaults to empty string)
* @returns Transaction hash and IPFS CID
*/
async chainPlot(
storylineId: bigint,
content: string,
title = "",
): Promise<ChainPlotResult> {
this.requireFilebase();
validateNonEmpty("content", content);
Expand All @@ -272,7 +274,7 @@ export class PlotLink {
address: this.storyFactory,
abi: storyFactoryAbi,
functionName: "chainPlot",
args: [storylineId, contentCid, contentHash],
args: [storylineId, title, contentCid, contentHash],
});

const txHash = await this.walletClient.writeContract(request);
Expand Down
2 changes: 1 addition & 1 deletion packages/sdk/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const SUPPORTED_CHAIN_IDS = new Set([BASE_SEPOLIA_CHAIN_ID, BASE_MAINNET_

/** StoryFactory — storyline + plot management. */
export const STORY_FACTORY_ADDRESS =
"0x05C4d59529807316D6fA09cdaA509adDfe85b474" as const;
"0x6B8d38af1773dd162Ebc6f4A8eb923F3c669605d" as const;

/** MCV2_Bond — bonding curve trading, token creation, royalty distribution. */
export const MCV2_BOND_ADDRESS =
Expand Down
20 changes: 19 additions & 1 deletion src/app/chain/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ async function fetchWriterStorylines(address: string): Promise<Storyline[]> {
export default function ChainPlotPage() {
const { address, isConnected } = useAccount();
const [storylineId, setStorylineId] = useState<number | null>(null);
const [title, setTitle] = useState("");
const [content, setContent] = useState("");

const { data: storylines = [], isLoading: loadingStorylines } = useQuery({
Expand Down Expand Up @@ -103,7 +104,7 @@ export default function ChainPlotPage() {
<form
onSubmit={(e) => {
e.preventDefault();
if (canSubmit) chainPlot(storylineId, content);
if (canSubmit) chainPlot(storylineId, content, title);
}}
className="mt-8 space-y-6"
>
Expand Down Expand Up @@ -135,6 +136,23 @@ export default function ChainPlotPage() {
)}
</div>

{/* Chapter title */}
<div>
<label className="text-foreground mb-2 block text-sm">
Chapter Title <span className="text-muted">(optional)</span>
</label>
<input
type="text"
value={title}
onChange={(e) => setTitle(e.target.value.slice(0, 100))}
disabled={busy || noStoryline}
placeholder={noStoryline ? "Select a storyline first" : "e.g. The Awakening"}
maxLength={100}
className="border-border bg-surface text-foreground placeholder:text-muted w-full rounded border px-3 py-2 text-sm focus:border-accent focus:outline-none disabled:opacity-50"
/>
<span className="text-muted mt-1 block text-xs">{title.length}/100</span>
</div>

{/* Content */}
<div>
<label className="text-foreground mb-2 block text-sm">
Expand Down
4 changes: 2 additions & 2 deletions src/hooks/useChainPlot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export function useChainPlot() {
const { state, error, txHash, execute, reset } = usePublish();

const chainPlot = useCallback(
async (storylineId: number, content: string) => {
async (storylineId: number, content: string, title = "") => {
await execute({
content,
uploadKeyPrefix: `plotlink/plots/${storylineId}`,
Expand All @@ -22,7 +22,7 @@ export function useChainPlot() {
address: STORY_FACTORY,
abi: storyFactoryAbi as unknown as [],
functionName: "chainPlot",
args: [BigInt(storylineId), cid, contentHash],
args: [BigInt(storylineId), title, cid, contentHash],
}),
});
},
Expand Down
Loading