Skip to main content

Overview

Engage with the iStory community through social actions that reward creators and build connections. All interactions are on-chain or blockchain-verified, ensuring transparency and authenticity.
You must connect your wallet to perform any engagement action.

Like Stories

Show appreciation for stories that resonate with you.
1

Click the Heart Icon

Tap the heart button on any story card in the feed or detail view.
2

Optimistic UI Update

The like count increments immediately — no waiting for blockchain confirmation.
3

Backend Sync

Your like is recorded in the database and the author receives a notification.

How It Works

// Source: app/api/social/like/route.ts:23-30
const { data: existingLike } = await admin
  .from("likes")
  .select("id")
  .eq("user_id", authenticatedUserId)
  .eq("story_id", storyId)
  .maybeSingle();
Likes are atomic toggle operations:
  • First click: Insert like record, increment story likes count
  • Second click: Delete like record, decrement count (floor at 0)
The author receives a notification: “[Your name] liked your story” (source: app/api/social/like/route.ts:106-112)

Frontend Implementation

// Source: app/social/SocialPageClient.tsx:285-329
const handleLike = async (storyNumericId: string) => {
  // Optimistic update
  setStories((prev) =>
    prev.map((s, i) =>
      i === storyIndex
        ? {
            ...s,
            isLiked: !isCurrentlyLiked,
            likes: isCurrentlyLiked ? s.likes - 1 : s.likes + 1,
          }
        : s
    )
  );
  // ... API call + error rollback
};
Likes are free and instant — no gas fees, no transaction signing.

Follow Creators

Build your personalized feed by following writers you love.
1

Connect Your Wallet

Ensure your wallet is connected to verify ownership.
2

Click Follow Button

Tap “Follow” on any author card or story header.
3

Optimistic Update

Button changes to “Following” and follower count increments.
4

Server Confirmation

API verifies wallet ownership and updates the database.

Follow API

// Source: app/api/social/follow/route.ts:99-103
const ownsWallet = await validateWalletOwnership(
  authenticatedUserId,
  followerWallet
);
if (!ownsWallet) {
  return NextResponse.json({ error: "Forbidden" }, { status: 403 });
}
Security: The API validates that the authenticated user owns the follower wallet address before allowing follow/unfollow actions.

Follower Count Updates

// Source: app/api/social/follow/route.ts:158-165
const { data: userData } = await admin
  .from("users")
  .select("followers_count")
  .eq("wallet_address", followedWallet)
  .single();

await admin
  .from("users")
  .update({ followers_count: (userData?.followers_count || 0) + 1 })
  .eq("wallet_address", followedWallet);
The followed creator receives a notification: “[Your name] started following you” (source: app/api/social/follow/route.ts:180-186)

Following Tab

Access your personalized feed:
  1. Navigate to /social
  2. Click the “Following” tab
  3. View stories only from creators you follow
You cannot follow yourself — the system prevents this automatically.

Share Stories

Amplify great stories to your network.

Native Sharing

// Source: app/social/SocialPageClient.tsx:397-405
const handleShare = (id: string) => {
  const url = `${window.location.origin}/story/${id}`;
  if (navigator.share) {
    navigator.share({ title: "Check out this story!", url });
  } else {
    navigator.clipboard.writeText(url);
    toast.success("Link copied to clipboard");
  }
};
1

Click Share Button

Tap the share icon (arrow-up) on any story card.
2

Choose Platform (Mobile)

On mobile devices, the native share sheet appears with options for Twitter, WhatsApp, etc.
3

Copy Link (Desktop)

On desktop, the story URL is copied to your clipboard automatically.
Shared links point to /story/[id] with rich OpenGraph metadata for previews.

Tip Creators

Reward creators with $STORY tokens for exceptional content.

Tipping Flow

1

Adjust Tip Amount

Use the slider (1-50 $STORY) next to the “Tip” button.
2

Approve Tokens

First-time tippers must approve the StoryProtocol contract to spend tokens:
// Source: app/hooks/useIStoryToken.ts:31-44
const approveProtocol = async (amount: string) => {
  writeContract({
    address: STORY_TOKEN_ADDRESS,
    abi: STORY_TOKEN_ABI,
    functionName: "approve",
    args: [STORY_PROTOCOL_ADDRESS, parseEther(amount)],
  });
};
3

Send Tip

Click “Tip [amount]” to execute the on-chain transaction:
// Source: contracts/StoryProtocol.sol:30-38
function tipCreator(address creator, uint256 amount, uint256 storyId) 
  external nonReentrant whenNotPaused {
  require(amount > 0, "Amount must be > 0");
  storyToken.safeTransferFrom(msg.sender, creator, amount);
  emit TipSent(msg.sender, creator, amount, storyId);
}
4

Confirm in Wallet

Sign the transaction in MetaMask or your connected wallet.
5

Success

Tokens are transferred directly to the creator’s wallet.

Smart Contract Events

The TipSent event is emitted for indexing:
// Source: contracts/StoryProtocol.sol:17
event TipSent(
  address indexed from, 
  address indexed to, 
  uint256 amount, 
  uint256 indexed storyId
);
Backend services can listen to this event to:
  • Update creator earnings dashboards
  • Send notifications
  • Track engagement metrics
Tips are direct creator payments — no platform fees, no intermediaries. 100% goes to the author.

Allowance Check

Before tipping, the frontend verifies sufficient allowance:
// Source: app/hooks/useStoryProtocol.ts:24-32
const tipCreator = async (creatorAddress: string, amount: number, storyId: string) => {
  const amountWei = parseEther(amount.toString());
  if (!allowance || allowance < amountWei) {
    toast.error("Please approve tokens first (via Token Hook)");
    return;
  }
  // ... execute tip
};

Interaction Stats

Track your engagement impact:
  • Likes Given: Visible in your profile under “Activity”
  • Following Count: Displayed on your profile header
  • Tips Sent: Tracked in wallet transaction history
  • Shares: Increments the story’s shares count

Technical Implementation

Optimistic UI Pattern

All engagement actions use optimistic updates:
  1. Immediate UI change (like count +1, button state change)
  2. API call to persist change
  3. Success: Keep optimistic state
  4. Failure: Rollback UI to original state
// Source: app/social/SocialPageClient.tsx:331-395
const handleFollow = async (authorWallet: string) => {
  // Optimistic toggle
  setStories((prev) =>
    prev.map((s) =>
      s.author_wallet?.wallet_address?.toLowerCase() === authorWallet.toLowerCase()
        ? { ...s, author_wallet: { ...s.author_wallet, isFollowing: !s.author_wallet.isFollowing } }
        : s
    )
  );

  try {
    const res = await fetch("/api/social/follow", { method: "POST", ... });
    const { isFollowing, followers_count } = await res.json();
    // Update with server state
  } catch (error) {
    // Revert optimistic update
    setStories((prev) => /* rollback */);
  }
};

Rate Limiting

Engagement APIs are protected:
// Source: middleware.ts (Auth endpoints: 20 req/min)
if (pathname.startsWith('/api/social')) {
  // Rate limit: 20 requests per minute
}
Excessive API calls will result in 429 Too Many Requests responses.

Next Steps

Earning $STORY

Learn how to monetize your stories and earn from tips

NFT Minting

Turn your story collections into tradable NFTs

Build docs developers (and LLMs) love