Skip to content

Commit 714be08

Browse files
committed
Update docs
1 parent ff5bb15 commit 714be08

File tree

8 files changed

+734
-457
lines changed

8 files changed

+734
-457
lines changed
3.86 MB
Loading

apps/docs/src/content/components/memory-abi-loader.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import {
99
// Create an in-memory cache for the ABIs
1010
const abiCache = new Map<string, ContractABI>()
1111

12-
// ABI store implementation with caching and multiple resolution strategies
1312
const abiStore: VanillaAbiStore = {
1413
strategies: [
1514
// List of stratagies to resolve new ABIs

apps/docs/src/content/components/memory-contract-loader.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
```ts title="index.ts"
22
import type { ContractData, VanillaContractMetaStore } from '@3loop/transaction-decoder'
3-
import { ERC20RPCStrategyResolver } from '@3loop/transaction-decoder'
3+
import { ERC20RPCStrategyResolver, NFTRPCStrategyResolver } from '@3loop/transaction-decoder'
44

55
// Create an in-memory cache for the contract meta-information
66
const contractMetaCache = new Map<string, ContractData>()
77

8-
// Contract metadata store implementation with in-memory caching
98
const contractMetaStore: VanillaContractMetaStore = {
10-
strategies: [ERC20RPCStrategyResolver],
9+
strategies: [ERC20RPCStrategyResolver, NFTRPCStrategyResolver],
1110

1211
get: async ({ address, chainID }) => {
1312
const key = `${address}-${chainID}`.toLowerCase()
Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
---
2+
title: Build a Farcaster Bot for On-Chain Alerts
3+
description: Create a Farcaster bot that monitors blockchain transactions and posts human-readable casts
4+
sidebar:
5+
order: 2
6+
---
7+
8+
import { Content as MemoryAbiLoader } from '../../components/memory-abi-loader.md'
9+
import { Content as MemoryContractLoader } from '../../components/memory-contract-loader.md'
10+
import { Steps } from '@astrojs/starlight/components'
11+
12+
In this guide, you will learn how to create a Farcaster bot that sends human-readable alerts about transactions happening on-chain. You can customize this bot for any EVM-compatible blockchain, and you don't need any specific knowledge about EVM transaction decoding and interpretation.
13+
14+
:::tip
15+
Jump to the repo to view the full code example [3loop/farcaster-onchain-alerts-bot](https://github.com/3loop/farcaster-onchain-alerts-bot)
16+
:::
17+
18+
:::note
19+
This example tracks AAVE trades on Base Mainnet. You can easily adapt it to monitor any contract on any EVM chain.
20+
:::
21+
22+
![Final result](../../../assets/fc-bot.png)
23+
24+
## Guide
25+
26+
### Step 0: Prerequisites
27+
28+
- Bun installed (see installation guide [here](https://bun.sh/docs/installation))
29+
- Alchemy account (sign up [here](https://www.alchemy.com/))
30+
- Basescan API Key (sign up [here](https://basescan.org/register))
31+
- Farcaster account (can be yours or a separate one for your bot)
32+
33+
### Step 1: Clone the Repository
34+
35+
Clone the bot [repository](https://github.com/3loop/farcaster-onchain-alerts-bot) and install dependencies:
36+
37+
```bash
38+
git clone https://github.com/3loop/farcaster-onchain-alerts-bot
39+
cd farcaster-onchain-alerts-bot
40+
bun i
41+
```
42+
43+
### Step 2: Configure Environment Variables
44+
45+
Copy the `.env.example` file to `.env` and add your API keys:
46+
47+
```bash
48+
cp .env.example .env
49+
vim .env
50+
```
51+
52+
For the Farcaster bot you need to specify:
53+
54+
- `ALCHEMY_API_KEY` - Alchemy API key to monitor new transactions via WebSocket
55+
- `ETHERSCAN_API_KEY` - Basescan API key, used to fetch and cache ABIs
56+
- `ARCHIVE_RPC_URL` - Archive RPC URL for Base (required for transaction tracing)
57+
- `SIGNER_PRIVATE_KEY` and `ACCOUNT_FID` - Farcaster credentials (see Step 3)
58+
59+
### Step 3: Create a Farcaster Account Key (Signer)
60+
61+
A Farcaster signer is a separate Ed25519 public and private key pair connected to your Farcaster account that you need for posting messages on your behalf. To connect the key pair, you have to send a transaction from your Farcaster wallet to the Key Registry Farcaster smart contract. At the moment of writing this guide, there was no simple way to create and connect the signer without using 3rd party APIs. So we made a script to generate the required transaction, and to run it you need to do the following:
62+
63+
<Steps>
64+
65+
1. **Fund your Farcaster custody wallet on Optimism:**: You need some ETH on the Optimism chain to pay for the gas. A few dollars would be enough. Click on the 3 dots near your profile, press "About," and there you will find your custody address.
66+
2. **Get your Farcaster recovery phrase**: On your phone, go to settings -> advanced -> recovery phrase, and write this recovery phrase into the `MNEMONIC` variable in the `scripts/create-signer.ts` file.
67+
3. **Run the script**: Run the following command `bun run scripts/create-signer.ts`. The result of this script will be an Optimism transaction like [this](https://optimistic.etherscan.io/tx/0x9eecacefceb6f120c3ef50222eabb15d86fd5feac6dae3fdf09dccb7687c70d4), and a public and private key printed in the console. Do not share the private key.
68+
4. **Add env variables**: Add the private key generated from the script and the bot's account FID into the `SIGNER_PRIVATE_KEY` and `ACCOUNT_FID` variables.
69+
70+
</Steps>
71+
72+
### Step 4: Setup the Transaction Decoder
73+
74+
Loop Decoder requires three components: an RPC provider, ABI store, and contract metadata store. Let's set up each one:
75+
76+
#### RPC Provider
77+
78+
Configure your RPC provider in `constants.ts` for Base Mainnet (chain ID 8453). We use `traceAPI: 'geth'` for transaction tracing:
79+
80+
```ts title="src/constants.ts"
81+
export const RPC = {
82+
8453: {
83+
archiveUrl: process.env.ARCHIVE_RPC_URL,
84+
traceAPI: 'geth',
85+
},
86+
}
87+
```
88+
89+
```ts title="src/decoder/decoder.ts"
90+
const getPublicClient = (chainId: number) => {
91+
const rpc = RPC[chainId as keyof typeof RPC]
92+
if (!rpc) throw new Error(`Missing RPC provider for chain ID ${chainId}`)
93+
94+
return {
95+
client: createPublicClient({ transport: http(rpc.archiveUrl) }),
96+
config: { traceAPI: rpc.traceAPI },
97+
}
98+
}
99+
```
100+
101+
#### ABI Store
102+
103+
Set up an in-memory ABI cache with Basescan and 4byte.directory strategies:
104+
105+
<MemoryAbiLoader />
106+
107+
#### Contract Metadata Store
108+
109+
Set up contract metadata resolution for token or NFT information (name, decimals, symbol):
110+
111+
<MemoryContractLoader />
112+
113+
#### Create Decoder Instance
114+
115+
Combine all components into a `TransactionDecoder` instance:
116+
117+
```ts title="src/decoder/decoder.ts"
118+
import { TransactionDecoder } from '@3loop/transaction-decoder'
119+
120+
const decoder = new TransactionDecoder({
121+
getPublicClient,
122+
abiStore,
123+
contractMetaStore,
124+
})
125+
```
126+
127+
### Step 5: Decode and Interpret Transactions
128+
129+
With the decoder set up, you can now decode transactions and make them human-readable:
130+
131+
```ts title="src/index.ts"
132+
// 1. Decode the transaction
133+
const decoded = await decoder.decodeTransaction({
134+
chainID: CHAIN_ID,
135+
hash: txHash,
136+
})
137+
138+
// 2. Interpret it (make it human-readable)
139+
const interpreted = interpretTx(decoded)
140+
141+
// 3. Use the result
142+
console.log(interpreted.action) // e.g., "Alice bought 5 shares of Bob for 0.1 ETH"
143+
```
144+
145+
View a [decoded AAVE transaction example](https://loop-decoder-web.vercel.app/interpret/1/0xc0bd04d7e94542e58709f51879f64946ff4a744e1c37f5f920cea3d478e115d7) in our playground. You can test the `interpretTx` function by pasting it into the Interpretation field.
146+
147+
### Step 6: Monitor AAVE Transactions
148+
149+
Set up real-time monitoring for AAVE trades. Configure the contract address in `constants.ts`:
150+
151+
```ts title="src/constants.ts"
152+
export const CONTRACT_ADDRESS = '0xa238dd80c259a72e81d7e4664a9801593f98d1c5'
153+
export const CHAIN_ID = 8453
154+
```
155+
156+
Subscribe to new transactions and process them:
157+
158+
```ts title="src/index.ts"
159+
const wsClient = createPublicClient({
160+
transport: webSocket(ALCHEMY_WS_RPC_URL),
161+
})
162+
163+
// Subscribe to AAVE transactions
164+
wsClient.transport.subscribe({
165+
method: 'eth_subscribe',
166+
params: [
167+
'alchemy_minedTransactions',
168+
{
169+
addresses: [{ to: CONTRACT_ADDRESS }],
170+
includeRemoved: false,
171+
hashesOnly: true,
172+
},
173+
],
174+
onData: (data: any) => {
175+
const hash = data?.result?.transaction?.hash
176+
if (hash) handleTransaction(hash)
177+
},
178+
})
179+
180+
// Process each transaction
181+
async function handleTransaction(txHash: string) {
182+
try {
183+
// 1. Decode
184+
const decoded = await decoder.decodeTransaction({
185+
chainID: CHAIN_ID,
186+
hash: txHash,
187+
})
188+
189+
if (!decoded) return
190+
191+
// 2. Interpret
192+
const interpreted = interpretTx(decoded)
193+
194+
// 3. Format message
195+
const text = `New trade: ${interpreted.trader} ${interpreted.isBuy ? 'Bought' : 'Sold'} ${
196+
interpreted.shareAmount
197+
} shares of ${interpreted.subject} for ${interpreted.price} ETH`
198+
199+
// 4. Post to Farcaster
200+
await publishToFarcaster({
201+
text,
202+
url: `https://basescan.org/tx/${txHash}`,
203+
})
204+
} catch (e) {
205+
console.error(e)
206+
}
207+
}
208+
```
209+
210+
### Step 7: Publish to Farcaster
211+
212+
Use the `@standard-crypto/farcaster-js-hub-rest` package to publish casts:
213+
214+
```ts title="src/index.ts"
215+
async function publishToFarcaster(cast: { text: string; url: string }) {
216+
await client.submitCast(
217+
{
218+
text: cast.text,
219+
embeds: [{ url: cast.url }],
220+
},
221+
Number(fid),
222+
signerPrivateKey,
223+
)
224+
}
225+
```
226+
227+
### Step 8: Run the Bot
228+
229+
Start the bot locally:
230+
231+
```bash
232+
bun run src/index.ts
233+
```
234+
235+
The bot will now monitor AAVE transactions and post casts to your Farcaster account.
236+
237+
## Next Steps
238+
239+
You've built a Farcaster bot that:
240+
241+
- Monitors specific contracts in real-time
242+
- Decodes transactions automatically
243+
- Generates human-readable descriptions
244+
- Posts alerts to Farcaster
245+
246+
**Customize it further:**
247+
248+
- Track different contracts by updating `CONTRACT_ADDRESS`
249+
- Modify the cast format in `handleTransaction`
250+
- Add filters for specific transaction types or amounts
251+
- Deploy to a server for 24/7 monitoring
252+
253+
---
254+
255+
Need help? Reach out on X/Twitter [@3loop_io](https://x.com/3loop_io) or check the [full code example](https://github.com/3loop/farcaster-onchain-alerts-bot).

0 commit comments

Comments
 (0)