8000 feat: implement Listen as World Mini-app by piotrostr · Pull Request #166 · piotrostr/listen · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

feat: implement Listen as World Mini-app #166

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 42 commits into from
May 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
50bce6d
start on contextualizing
piotrostr May 8, 2025
a666e91
redirect to other apps
piotrostr May 9, 2025
e5ae16c
more world
piotrostr May 9, 2025
97acf7d
redirect on click anywhere on the worldappredirect
piotrostr May 9, 2025
c35c89a
add worldchain tools
piotrostr May 9, 2025
6441c4d
nit
piotrostr May 9, 2025
a369be1
nit
piotrostr May 9, 2025
4e79eb5
nit
piotrostr May 9, 2025
58805df
nit
piotrostr May 9, 2025
6dc4734
nit
piotrostr May 9, 2025
76c48f7
nit
piotrostr May 10, 2025
d4e47bd
start on permit2 lifi swaps
piotrostr May 11, 2025
0e1e09d
nit
piotrostr May 11, 2025
6647610
implement permit2, remove pwa for world app
piotrostr May 11, 2025
bb7b399
nit
piotrostr May 11, 2025
b329380
nit
piotrostr May 11, 2025
f4b77b2
add wld flag
piotrostr May 11, 2025
78cf381
add wld login
piotrostr May 11, 2025
355b761
eruda in wld
piotrostr May 11, 2025
de79179
prevent null return
piotrostr May 11, 2025
ba5780b
8000 hard-set world enabled
piotrostr May 11, 2025
9a7dafc
add dex search tool
piotrostr May 11, 2025
84280ef
only display wld inside of miniapps
piotrostr May 11, 2025
52b3cc0
allow swaps with world txs
piotrostr May 11, 2025
3579354
fetch folio for world
piotrostr May 11, 2025
12787c4
try persist login
piotrostr May 11, 2025
3a5a0ed
nit
piotrostr May 11, 2025
14af620
nit
piotrostr May 11, 2025
6d15d3a
hardcode for wld
piotrostr May 11, 2025
ed7e366
debug
piotrostr May 11, 2025
928384c
verbose err
piotrostr May 11, 2025
a03d9bf
nit
piotrostr May 11, 2025
7c4445c
nit
piotrostr May 11, 2025
22660be
use dexscreener for images of tokens on worldchain
piotrostr May 11, 2025
b322897
nit
piotrostr May 11, 2025
1a5a7f1
nit
piotrostr May 11, 2025
20ed627
log more
piotrostr May 11, 2025
fa36218
fallback to dex image
piotrostr May 11, 2025
a67f7ee
try fix invalid params err
piotrostr May 11, 2025
a9b887b
use another abi
piotrostr May 11, 2025
f0416d4
move miniapp fork into a separate subfolder
piotrostr May 12, 2025
0fd338d
checkout from main
piotrostr May 12, 2025
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 lifi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,8 @@ mod tests {
)
.await;

println!("{:#?}", quote);

assert!(quote.is_ok(), "{:?}", quote);
}

Expand Down
4 changes: 2 additions & 2 deletions listen-analytics/tx-stats/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ console.log("ethereum: ", ethereumWallets.length);
const connection = new Connection(process.env.SOLANA_RPC_URL!);

// Process Solana wallets
await processSolanaWallets(solanaWallets, connection);
// await processSolanaWallets(solanaWallets, connection);

// Process Ethereum and other EVM wallets
// await processEVMWallets(ethereumWallets, process.env.ALCHEMY_API_KEY!);
await processEVMWallets(ethereumWallets, process.env.ALCHEMY_API_KEY!);
2 changes: 1 addition & 1 deletion listen-analytics/tx-stats/solana.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export const processWalletsInChunks = async (
export const processSolanaWallets = async (
solanaWallets: Wallet[],
connection: Connection,
concurrencyLimit = 30,
concurrencyLimit = 50,
): Promise<WalletTransactionResult[]> => {
console.log(
`Starting to process ${solanaWallets.length} Solana wallets with concurrency limit of ${concurrencyLimit}`,
Expand Down
6 changes: 1 addition & 5 deletions listen-kit/examples/solana_agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,7 @@ async fn main() -> anyhow::Result<()> {
let signer = LocalSolanaSigner::new(env("SOLANA_PRIVATE_KEY"));

SignerContext::with_signer(Arc::new(signer), async {
let features = Features {
autonomous: false,
deep_research: false,
memory: false,
};
let features = Features::default();
let model = match std::env::var("MODEL").unwrap_or_default().as_str()
{
"gemini" => Model::Gemini(Arc::new(create_solana_agent_gemini(
Expand Down
48 changes: 41 additions & 7 deletions listen-kit/src/agent.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::data::evm_fallback_tools::{
FetchPriceActionAnalysisEvm, FetchTokenMetadataEvm,
FetchTopTokensByCategory, FetchTopTokensByChainId,
FetchPriceActionAnalysisEvm, FetchTopTokensByCategory,
FetchTopTokensByChainId,
};
use crate::evm::tools::{GetErc20Balance, GetEthBalance};
use crate::solana::tools::{
Expand All @@ -12,9 +12,8 @@ use crate::agents::research::ViewImage;
use crate::common::{openrouter_agent_builder, OpenRouterAgent};
use crate::cross_chain::tools::{GetQuote, Swap};
use crate::data::{
AnalyzePageContent, FetchPriceActionAnalysis, FetchTokenMetadata,
FetchTopTokens, FetchXPost, GetToken, ResearchXProfile, SearchTweets,
SearchWeb,
AnalyzePageContent, FetchPriceActionAnalysis, FetchTopTokens, FetchXPost,
GetToken, ResearchXProfile, SearchTweets, SearchWeb,
};
use crate::dexscreener::tools::SearchOnDexScreener;
use crate::faster100x::AnalyzeHolderDistribution;
Expand All @@ -26,18 +25,20 @@ use rig::agent::AgentBuilder;
use rig::streaming::StreamingCompletionModel;
use serde::{Deserialize, Serialize};

#[derive(Default, Serialize, Deserialize, Clone)]
#[derive(Serialize, Deserialize, Clone, Default)]
pub struct Features {
pub autonomous: bool,
pub deep_research: bool,
#[serde(default)]
pub memory: bool,
#[serde(default)]
pub worldchain: bool,
}

pub fn model_to_versioned_model(model_type: String) -> String {
match model_type.as_str() {
// FIXME implement proper rate lims on claude
"claude" => "deepseek/deepseek-chat-v3-0324".to_string(), // "anthropic/claude-3.7-sonnet".to_string(),
"claude" => "anthropic/claude-3.5-sonnet".to_string(), // "anthropic/claude-3.7-sonnet".to_string(),
"gemini" => "google/gemini-2.0-flash-001".to_string(),
"deepseek" => "deepseek/deepseek-chat-v3-0324".to_string(),
"openai" => "openai/gpt-4o-mini".to_string(),
Expand Down Expand Up @@ -92,6 +93,25 @@ pub fn equip_with_evm_tools<M: StreamingCompletionModel>(
.tool(FetchTopTokensByCategory)
}

pub fn equip_with_worldchain_tools<M: StreamingCompletionModel>(
agent_builder: AgentBuilder<M>,
) -> AgentBuilder<M> {
agent_builder
.tool(Think)
.tool(FetchTopTokensByChainId)
.tool(GetQuote)
.tool(GetToken)
.tool(GetEthBalance)
.tool(GetErc20Balance)
.tool(ResearchXProfile)
.tool(FetchXPost)
.tool(SearchTweets)
.tool(SearchWeb)
.tool(ViewImage)
.tool(AnalyzePageContent)
.tool(SearchOnDexScreener)
}

pub fn equip_with_autonomous_tools<M: StreamingCompletionModel>(
agent_builder: AgentBuilder<M>,
) -> AgentBuilder<M> {
Expand All @@ -104,6 +124,10 @@ pub fn create_listen_agent(
features: Features,
locale: String,
) -> OpenRouterAgent {
if features.worldchain {
return create_worldchain_agent(preamble);
}

let preamble = preamble.unwrap_or("".to_string());

if features.deep_research {
Expand All @@ -121,3 +145,13 @@ pub fn create_listen_agent(

agent.build()
}

pub fn create_worldchain_agent(preamble: Option<String>) -> OpenRouterAgent {
let preamble = preamble.unwrap_or("".to_string());
let model = Some("google/gemini-2.5-flash-preview".to_string());

let agent = equip_with_worldchain_tools(openrouter_agent_builder(model))
.preamble(&preamble);

agent.build()
}
4 changes: 4 additions & 0 deletions listen-kit/src/cross_chain/tools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,15 @@ Supported from_chain values:
- arbitrum: \"42161\"
- base: \"8453\"
- bsc: \"56\"
- worldchain: \"480\"

Supported to_chain values:
- solana: \"1151111081099710\"
- mainnet: \"1\"
- arbitrum: \"42161\"
- base: \"8453\"
- bsc: \"56\"
- worldchain: \"480\"

Special Case: from_token_address/to_token_address for ethereum (any chain) is just \"ETH\"
Solana Address: \"So11111111111111111111111111111111111111112\"
Expand Down Expand Up @@ -157,13 +159,15 @@ Supported from_chain values:
- mainnet: \"1\"
- base: \"8453\"
- bsc: \"56\"
- worldchain: \"480\"

Supported to_chain values:
- solana: \"1151111081099710\"
- arbitrum: \"42161\"
- mainnet: \"1\"
- base: \"8453\"
- bsc: \"56\"
- worldchain: \"480\"

Example:
{{
Expand Down
2 changes: 2 additions & 0 deletions listen-kit/src/data/listen_api_tools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ pub async fn fetch_token_price(mint: String) -> Result<f64> {
#[tool(description = "
Fetch top Solana tokens based on volume from the Listen API.

This tool is great for finding the most viral tokens on Solana.

Parameters:
- limit (optional, string): number of tokens to return (default: 4)
- min_market_cap (optional, string): minimum market cap filter (default: 1000000)
Expand Down
4 changes: 4 additions & 0 deletions listen-kit/src/evm/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ pub fn chain_id_to_rpc_url(chain_id: u64) -> String {
"https://arb-mainnet.g.alchemy.com/v2/{}",
alchemy_api_key
),
480 => format!(
"https://worldchain-mainnet.g.alchemy.com/v2/{}",
alchemy_api_key
),
_ => panic!("Unsupported chain ID: {}", chain_id),
}
}
Expand Down
1 change: 1 addition & 0 deletions listen-kit/src/evm_fallback/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub fn map_chain_id_to_network(chain_id: u64) -> Result<&'static str> {
56 => Ok("bsc"),
42161 => Ok("arbitrum"),
8453 => Ok("base"),
480 => Ok("world-chain"),
_ => Err(anyhow!("Unsupported chain ID: {}", chain_id)),
}
}
Expand Down
6 changes: 6 additions & 0 deletions listen-miniapp/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules
dist
.git
.gitignore
README.md
.env
3 changes: 3 additions & 0 deletions listen-miniapp/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
VITE_ANTHROPIC_API_KEY=<secret>
VITE_RPC_URL=<secret (or https://api.mainnet-beta.solana.com/)>
VITE_ALCHEMY_API_KEY
33 changes: 33 additions & 0 deletions listen-miniapp/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
dev-dist
debug*
stats.html
dist/*.gz
dist/stats.html

# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
!package.json
!tsconfig.json
.vercel
14 changes: 14 additions & 0 deletions listen-miniapp/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Build stage
FROM oven/bun:1 as builder

WORKDIR /app

COPY package.json bun.lockb ./
RUN bun install

COPY . .
RUN bun run build

EXPOSE 4173

CMD ["bun", "run", "preview"]
50 changes: 50 additions & 0 deletions listen-miniapp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# React + TypeScript + Vite

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.

Currently, two official plugins are available:

- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh

## Expanding the ESLint configuration

If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:

- Configure the top-level `parserOptions` property like this:

```js
export default tseslint.config({
languageOptions: {
// other options...
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
},
})
```

- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked`
- Optionally add `...tseslint.configs.stylisticTypeChecked`
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config:

```js
// eslint.config.js
import react from 'eslint-plugin-react'

export default tseslint.config({
// Set the react version
settings: { react: { version: '18.3' } },
plugins: {
// Add the react plugin
react,
},
rules: {
// other rules...
// Enable its recommended rules
...react.configs.recommended.rules,
...react.configs['jsx-runtime'].rules,
},
})
```
Binary file added listen-miniapp/bun.lockb
Binary file not shown.
28 changes: 28 additions & 0 deletions listen-miniapp/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'

export default tseslint.config(
{ ignores: ['dist'] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ['**/*.{ts,tsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
},
)
21 changes: 21 additions & 0 deletions listen-miniapp/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/png" href="/listen-icon.png" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
<!-- Force browsers to check for updates -->
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<title>Listen</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</body>
</html>
Loading
0