尚未检测到更新。GitHub 发布版本后会显示在这里。
find a new fren
翻译准备中
正在加载完整 README。
查看完整 README ↗Read and write Farcaster straight from a Snapchain / Hypersnap node. No API key, no Neynar, no indexer: just the node's HTTP API, with the paging quirks handled for you, and gasless app keys for posting.
Any machine with Python 3.10+. No API key and no node of your own: it reads from a public node by default. To run your own node, the microsite quickstart does it in three commands: rent a server, start the node, read from it.
pip install git+https://github.com/Ramitphi/phunk-client
phunk whois dwr # a profile
phunk feed dwr --hide warpcast # last 24h from everyone dwr follows, minus one app
If pip says "externally-managed-environment" (macOS with Homebrew, Ubuntu
24.04, Debian 12), make a virtual environment first:
python3 -m venv ~/.phunk && . ~/.phunk/bin/activate.
$ phunk whois dwr
fid 3
username dwr
display_name Dan Romero
bio Interested in technology and other stuff.
url https://danromero.org
eth_address 0x6Ce09Ed5526DE4aFe4a981AD86d17B2F5c92feA5
phunk feed prints one line per cast: the time, who posted, the app that
signed it ([own key] when it's their own key), and the text. To read from
your own node instead, follow the
microsite quickstart and see
Which node.
In Python:
import asyncio
from phunk import Hub
async def main():
async with Hub() as hub: # public node by default
fid = await hub.fid_by_name("dwr")
print(await hub.user(fid))
async for cast in hub.casts(fid, limit=5):
app = await hub.app_of(cast) # which app signed it
print(cast.time, await hub.app_name(app), cast.text[:60])
asyncio.run(main())
New to reading from a node? Start with the tutorial, or read it on the microsite with the quickstart and short concept pages.
pip install git+https://github.com/Ramitphi/phunk-client
Python 3.10+. Reading needs only aiohttp. Writing needs three more
(Ed25519, BLAKE3 and Ethereum signing):
pip install 'phunk-client[write] @ git+https://github.com/Ramitphi/phunk-client'
| Method | Endpoint | Returns |
|---|---|---|
fid_by_name(name) | /v1/userNameProofByName | fid |
user(fid), user_by_name(name) | /v1/userDataByFid | User: username, display name, pfp, bio, primary addresses |
following(fid, newest_first=) | /v1/linksByFid | Follows, oldest follow first (or newest first) |
followers(fid) | /v1/linksByTargetFid | Follows |
casts(fid, since=, limit=) | /v1/castsByFid | Casts, newest first; deleted casts left out |
cast(fid, hash) | /v1/castById | one Cast |
replies(fid, hash) | /v1/castsByParent | Casts |
channel(url, since=, limit=) | /v1/castsByParent?url= | Casts in a channel |
mentions(fid) | /v1/castsByMention | Casts |
reactions(fid, "like" | "recast") | /v1/reactionsByFid | Reactions |
keys(fid) | /v1/onChainEventsByFid, /v1/signersByFid | Keys: every key add / remove, and the app that asked for each |
app_of(message), app_name(app_fid) | which app signed a cast, like or follow | |
feed(fid, since=, limit=, follows=) | /v1/linksByFid + /v1/castsByFid | recent casts from everyone fid follows (or just follows), newest first |
recommend.suggest(hub, fid) | /v1/linksByFid, /v1/castsByFid, |
Everything that lists things is an async iterator, so you can stop early
(limit=) or stream through a whole history. Every dataclass keeps the
node's original message in .raw.
Cast lists skip deleted casts. Some accounts have deleted thousands, so a
cast list with a limit reads at most 5 pages and may return fewer casts.
decode_key_request(metadata) decodes the ABI-encoded
SignedKeyRequestMetadata from a key ADD event on its own, if you're reading
on-chain events some other way.
phunk.write adds an app key to an account and posts with it. The key is
gasless: a KEY_ADD message authorized by the custody key's EIP-712
signature. No transaction, no gas.
import asyncio, getpass
from phunk import Hub
from phunk.write import Custody, Writer, add_app_key
async def main():
custody = Custody.from_mnemonic(getpass.getpass("seed phrase (test account): "))
async with Hub("http://localhost:3381") as hub:
fid, key = await add_app_key(hub, custody) # key.private_hex: keep it secret
await asyncio.sleep(5) # let the KEY_ADD land in a block
me = Writer(hub, fid, key)
h = await me.cast("hello from my own node")
await me.follow(3)
asyncio.run(main())
以上为 README 的开头部分。其余内容请阅读原文。 查看完整 README ↗
/v1/castsByParent| people to follow: friends of friends and shared channels, each with its reasons |
path.paths(hub, start, end, avoid=) | /v1/linksByFid (+ casts and reactions, to rank) | who could introduce whom: the shortest paths of mutual follows, up to 3 steps, warmest first |
fid_by_address(address) | /v1/onChainIdRegistryEventByAddress | the fid a custody address owns |
eth_addresses(fid) | /v1/verificationsByFid | every Ethereum address the account verified (the primary one is just one of them) |
signers(fid, requester_fids=) | /v1/signersByFid | active keys, currentUserNonce, and each app's nonce (requesterFidNonces) |
submit(msg), validate(msg) | POST /v1/submitMessage, /v1/validateMessage | send a signed message, or just check it |
info() | /v1/info | node stats |
get(path, params), pages(...), collect(...) | any | raw JSON, for endpoints not wrapped here |