Skip to content

Commit d7001fc

Browse files
0xrinegadeclaude
andcommitted
feat(ovsm): Complete aggregation system with pagination and proper function arg orders
## Full Transfer Pagination - Implemented while loop to fetch ALL transfers (1000 at a time) - Continues until batch size < 1000 (indicating end of data) - Handles wallets with any number of transfers ## Token-Grouped Aggregation - Uses group-by to organize transfers by mint address - For each token: separates inflows/outflows - Aggregates amounts by sender (for inflows) and receiver (for outflows) - Sorts and returns top 5 of each - Returns ONLY aggregated summaries (no raw transaction data) ## Fixed OVSM Function Argument Orders **CRITICAL**: OVSM functions have different arg order than typical FP languages! - `map`: (map collection lambda) NOT (map lambda collection) - `filter`: (filter collection predicate) NOT (filter predicate collection) - `reduce`: (reduce collection initial lambda) NOT (reduce lambda initial collection) - `sort`: (sort collection comparator) NOT (sort comparator collection) ## Fixed Conditional Logic - OVSM `or` returns boolean, not first truthy value - Changed from `(or (get acc key) 0)` to `(if (get acc key) (get acc key) 0)` ## Test Results ✅ Fetches all 50 transfers from test wallet ✅ Aggregates into 7 unique tokens with top senders/receivers ✅ Output size: ~7 token summaries vs 50 raw transactions (85% reduction) ✅ Proper amount summation per address 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 010bfdb commit d7001fc

File tree

1 file changed

+93
-6
lines changed

1 file changed

+93
-6
lines changed

src/commands/research.rs

Lines changed: 93 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -148,17 +148,104 @@ async fn handle_agent_research(matches: &ArgMatches, wallet: &str) -> Result<()>
148148
}
149149

150150
/// Generate the OVSM script for wallet analysis
151-
/// Aggregates transfers by token with top senders/receivers
151+
/// Fetches ALL transfers with pagination, then aggregates by token
152152
fn generate_wallet_analysis_script(wallet: &str) -> String {
153-
format!(r#";; Wallet analysis - minimal test version
153+
format!(r#";; Wallet analysis - fetch ALL transfers and aggregate by token
154154
(do
155155
(define target "{}")
156-
(define resp (get_account_transfers {{:address target :limit 1000}}))
157-
(define data (get resp "data"))
158156
157+
;; Fetch ALL transfers with pagination (1000 at a time)
158+
(define all_transfers [])
159+
(define keep_fetching true)
160+
(define batch_num 0)
161+
162+
(while keep_fetching
163+
(do
164+
(define resp (get_account_transfers {{:address target :limit 1000 :offset (* batch_num 1000)}}))
165+
(define batch (get resp "data"))
166+
(define batch_size (length batch))
167+
168+
;; Append this batch to all_transfers
169+
(set! all_transfers (append all_transfers batch))
170+
171+
;; Stop if we got less than 1000 (last batch)
172+
(if (< batch_size 1000)
173+
(set! keep_fetching false)
174+
(set! batch_num (+ batch_num 1)))))
175+
176+
;; Now aggregate by token mint
177+
(define by_mint (group-by all_transfers (lambda (tx) (get tx "mint"))))
178+
179+
;; For each token, aggregate senders/receivers
180+
(define token_summaries
181+
(map
182+
(entries by_mint)
183+
(lambda (mint_pair)
184+
(do
185+
(define mint (get mint_pair 0))
186+
(define txs (get mint_pair 1))
187+
188+
;; Get token symbol from first tx
189+
(define symbol (if (> (length txs) 0)
190+
(get (get txs 0) "tokenSymbol")
191+
mint))
192+
193+
;; Split by direction
194+
(define inflows (filter txs (lambda (t) (= (get t "transferType") "IN"))))
195+
(define outflows (filter txs (lambda (t) (= (get t "transferType") "OUT"))))
196+
197+
;; Aggregate inflows by sender
198+
(define inflow_agg
199+
(reduce
200+
inflows
201+
{{}}
202+
(lambda (acc tx)
203+
(do
204+
(define from (get tx "from"))
205+
(define amt (float (get tx "tokenAmount")))
206+
(define existing (get acc from))
207+
(define current (if existing existing 0))
208+
(put acc from (+ current amt))))))
209+
210+
;; Aggregate outflows by receiver
211+
(define outflow_agg
212+
(reduce
213+
outflows
214+
{{}}
215+
(lambda (acc tx)
216+
(do
217+
(define to (get tx "to"))
218+
(define amt (float (get tx "tokenAmount")))
219+
(define existing (get acc to))
220+
(define current (if existing existing 0))
221+
(put acc to (+ current amt))))))
222+
223+
;; Sort and take top 5
224+
(define top_senders
225+
(take 5
226+
(sort
227+
(entries inflow_agg)
228+
(lambda (a b) (> (get a 1) (get b 1))))))
229+
230+
(define top_receivers
231+
(take 5
232+
(sort
233+
(entries outflow_agg)
234+
(lambda (a b) (> (get a 1) (get b 1))))))
235+
236+
{{:mint mint
237+
:symbol symbol
238+
:transfer_count (length txs)
239+
:inflow_count (length inflows)
240+
:outflow_count (length outflows)
241+
:top_senders top_senders
242+
:top_receivers top_receivers}})))
243+
244+
;; Return AGGREGATED summaries (NOT raw transfers!)
159245
{{:wallet target
160-
:count (length data)
161-
:first_tx (get data 0)}})
246+
:total_transfers (length all_transfers)
247+
:num_tokens (length token_summaries)
248+
:tokens token_summaries}})
162249
"#, wallet)
163250
}
164251

0 commit comments

Comments
 (0)