Build a Reddit Clone with Tipping
This guide is currently incomplete, and may not work as intended yet!
In this guide, we'll build a decentralized social app where users can:
- Create and view posts that are stored off-chain
- Tip any poster with $1 USDC on-chain
- View all posts and tips received by each poster
Step 1: Create Your App on the Tarobase Console
Before you start coding, you need to create an app on the Tarobase Console.
- Go to the Tarobase Console.
- Sign in with your account or create a new one.
- Click on "Create New App" and follow the instructions to set up your new app. You may give your project a name like
TarobaseQuickstart
and use the default authentication and chain selections. - Once your app is created, you will receive an App ID. Keep this ID handy as you will need it later.
Step 2: Initialize Your Project
You can use any TypeScript or JavaScript framework to build with Tarobase. Here we'll use Create React App, but feel free to use Next.js, Vue, or any other framework you prefer.
First, open a terminal and create a new React project:
npx create-react-app my-tipping-app
cd my-tipping-app
Install the Tarobase SDK:
npm install @tarobase/js-sdk
# or
yarn add @tarobase/js-sdk
Replace the contents of src/App.js
with this basic setup:
import { TarobaseClient } from '@tarobase/js-sdk';
init({ appId: `INSERT_YOUR_TAROBASE_APP_ID_HERE` });
function App() {
// Initialize Tarobase SDK
return (
<div className="App">
<h1>My Tipping App</h1>
</div>
);
}
export default App;
Note: Replace 'INSERT_YOUR_TAROBASE_APP_ID_HERE' with the App ID you obtained from the Tarobase Console.
Start the development server:
npm start
# or
yarn start
Step 3: Add Authentication
Let's add wallet authentication to allow users to connect their own wallet to your app, providing a way to identify users.
Update your src/App.js
to include login functionality:
import React from 'react';
import { init, useAuth } from '@tarobase/js-sdk';
init({ appId: 'INSERT_YOUR_TAROBASE_APP_ID_HERE' });
function App() {
const { login, user } = useAuth();
const handleLogin = async () => {
await login(); // This will trigger the wallet connection prompt
};
return (
<div className="App">
<h1>My Tipping App</h1>
{user ? (
<p>Connected as: {user.address}</p>
) : (
<button onClick={handleLogin}>Connect Wallet</button>
)}
</div>
);
}
export default App;
Try clicking the "Connect Wallet" button now to see the wallet connection prompt.
Step 4: Allow Posts to be Created and Read
Now, let's allow users to create and view posts. We'll start by setting up a Tarobase policy for our app.
What is a Policy in Tarobase?
A policy in Tarobase is a set of rules that define who can read and write data in your application. It acts as a security layer that protects your data and ensures that only authorized users can perform specific actions.
Set Up a Tarobase Policy for Posts
- Navigate to your project in the Tarobase Console
- Go to the "Policy" section under Project Details.
- Replace the existing policy with the following:
{
"posts/$postId": {
"rules": {
"read": "true",
"write": "@prevState == null && newState.text != null && @newState.createdBy == @walletAddress"
}
}
}
Policy Explanation:
posts/$postId
Defines a collection calledposts
with documents identified by$postId
."read": "true"
: Allows any user to read posts"write": "...conditions..."
: Permits writing (creating) a new post if:- The post does not alreadyt exist (
@prevState == null
) - The new post contains text (
@newState.text != null
) ThecreatedBy
field matches the user's wallet address (@newState.createdBy == @walletAddress
)
- The post does not alreadyt exist (
Step 5: Add Tipping Support
Lets now make it so that any user of the app can tip a creator of a post $1 of USDC. This will allow for an on-chain action to occur on your app, so lets make some changes to our policy on the Tarobase console (https://console.tarobase.com) to reflect the tipping functionality we are looking for.
{
"posts/$postId": {
"rules": {
"read": "true",
"write": "@prevState == null && newState.text != null && @newState.createdBy == @walletAddress"
}
},
"posts/$postId/tips/$tipId": {
"rules": {
"read": "true",
"write": "@prevState == null && @newState != null && @newState.sender == @walletAddress"
},
"onchain": "true,
"fields": {
"sender": "Types.Address",
"receiver": "Types.Address"
},
"triggers": [
"create:@TokenPlugin.transfer(@TokenPlugin.USDC, @newState.sender, @newState.receiver, 1)"
]
}
}
The policy now includes a new path posts/$postId/tips/$tipId
which allows users to create $1 tips for posts and stores all tips on-chain. Let's break down all of what was added, including the new on-chain concepts added to support tipping:
-
A new path for tips under each post that allows:
- Read access to everyone (
"read": "true"
) - Write access only for new tips (
"write": "@prevState == null && @newState != null"
)
- Read access to everyone (
-
A new
"onchain": "true"
field was added which indicates that any tips that are created are available publically on-chain. -
The new
fields
key lets Tarobase know what fields should be allowed to be stored on-chain for each tip. Specifying what fields are allowed is required for all on-chain tarobase policies so an appropriate smart contract can be setup and deployed on your app's behalf. Required fields for tips:sender
: The wallet address of who's sending the tipreceiver
: The wallet address of who's receiving the tip
-
There is a new
triggers
array which specifies extra actions to be taken if a write was successful to the data store. Triggers allow you to usePlugins
which are a Tarobase feature that allow your generated smart contracts to use more complex on-chain functionality. In our example, we are using the Tarobase provided@TokenPlugin
to make a token transfer of USDC whenever a creation of a new Tip data object was successful. More details on plugins can be found here.
This policy ensures tips can only be created (not modified or deleted) and automatically handles the USDC transfer between users when a tip is created.
Step 5: Add Posts and Tipping to the UI
Lets go back to our UI and now add the abillity to interact with our Tarobase app in more ways than just logging in. Our goal in this section is to support users to create posts, view posts, and send $1 USDC tips.
To start, lets update our App to now listen for changes to posts, and place any changes on the screen.
import { TarobaseClient, useAuth, subscribe, set } from '@tarobase/js-sdk';
import { useState, useEffect } from 'react';
init({ appId: `INSERT_YOUR_TAROBASE_APP_ID_HERE` });
function App() {
const { login, user } = useAuth();
const [posts, setPosts] = useState([]);
const [newPostText, setNewPostText] = useState('');
useEffect(() => {
const unsubscribe = subscribe('posts', 'show all posts', setPosts);
return () => unsubscribe();
}, []);
const handleCreatePost = async () => {
if (!newPostText.trim()) return;
try {
await set('posts', {
createdBy: user.address,
text: newPostText
});
setNewPostText('');
} catch (error) {
console.error('Error creating post:', error);
}
};
if (!user) {
return <button onClick={login}>Connect Wallet</button>;
}
return (
<div className="App">
<p>Connected as: {user.address}</p>
<div style={{ margin: '20px 0' }}>
<textarea
value={newPostText}
onChange={e => setNewPostText(e.target.value)}
placeholder="What's on your mind?"
style={{ width: '100%', minHeight: '100px' }}
/>
<button onClick={handleCreatePost}>Create Post</button>
</div>
<div>
<h2>Posts</h2>
{posts.map((post, index) => (
<div key={index} style={{ border: '1px solid #ccc', margin: '10px 0', padding: '10px' }}>
<p><strong>From:</strong> {post.createdBy}</p>
<p>{post.text}</p>
</div>
))}
</div>
</div>
);
}
export default App;
Next Steps
- Add loading states and error handling
- Implement pagination for posts
- Add post categories or tags
- Create a user profile page showing their posts and received tips
- Add real-time updates using Tarobase's subscription features
This quickstart demonstrates how to use Tarobase to build a decentralized social tipping system. The posts and tips are stored on-chain, while comments are stored off-chain. The policy ensures proper access control and automatically handles USDC transfers when tips are created.