주소의 거래 상대는 어떻게 가져옵니까: /graph 또는 /walk?

주소 · 노드와 엣지로 된 에고 하위 그래프, 또는 홉 단위 탐색 — 한 번에 토큰 하나, 주소 500개의 탐색 경계, 그리고 응답이 밝히는 기간 범위

  • API 가이드
  • 10분
  • 중급
  • 개발자
  • GET …/graph
  • GET …/walk

ACHIVX Academy 원문 (영어) ↗

/v1/addresses/{address}/graph?chain=&token=&hops=는 주소 주변의 정산 그래프를 nodes[]와 edges[](엣지별 거래량, 노드별 라벨, motifs[])로 반환합니다. 최신 스냅샷이 저장되어 있으면 그것으로 만들고, 무거운 그래프가 아직 없으면 202 building으로 답합니다. /v1/addresses/{address}/walk?chain=&token=&hops=는 같은 이웃을 홉 단위로 반환하며, 요청마다 새로 만들고 stop_at_attributed와 stop_on_sanctioned 스위치를 가집니다. 두 라우트 모두 token을 전달하십시오. 그래프는 스테이블코인별로 만들어집니다. 무언가가 없다는 것에서 결론을 내리기 전에 window_from을 읽으십시오.

그래프

curl -s 'https://stablescan.achivx.com/v1/addresses/0x28C6c06298d514Db089934071355E5743bf21d60/graph?chain=1&token=USDT&hops=1'

2026-10-24 바이낸스(Binance) 핫월렛의 USDT 이웃입니다. 노드 484개와 엣지 484개이며, 앞부분만 잘라 보여 줍니다.

{
  "address": "0x28c6c06298d514db089934071355e5743bf21d60",
  "chain_id": 1,
  "token": "USDT",
  "decimals": 6,
  "window": "all",
  "window_from": "2026-10-03",
  "edge_source": "daily",
  "max_hops": 1,
  "frontier_cap": 500,
  "start_key": "addr:28c6c06298d514db089934071355e5743bf21d60",
  "nodes": [
    {"key": "addr:28c6…1d60", "address": "0x28c6…1d60", "hop": 0, "volume": 0, "volume_usd6": 0, "score": 1, "attributed": false, "sanctioned": false,
     "name": "Binance", "category": "exchange_hot", "is_service": true},
    {"key": "addr:5754…b949", "address": "0x5754…b949", "hop": 1, "direction": "out", "volume": 500000000000000, "volume_usd6": 500000000000000, "score": 0.0431,
     "attributed": false, "sanctioned": false, "name": "Tether: Treasury", "category": "issuer", "is_service": true}
  ],
  "edges": [
    {"from": "addr:28c6…1d60", "to": "addr:5754…b949", "volume": 500000000000000, "volume_usd6": 500000000000000, "tx_count": 1}
  ],
  "motifs": [],
  "extraction": {"hops": 1, "nodes_explored": 484, "frontier_truncated": true, "stop_at_attributed": true, "edges_omitted": false},
  "built_at": "2026-10-24T08:22:06Z",
  "snapshot_served": true,
  "snapshot_age_seconds": 8696
}

nodes[] — key와 address, 노드에 도달한 hop, direction(in: 대상에게 지급함, out: 대상이 지급함), 토큰 최소 단위의 volume과 volume_usd6, score(대상의 흐름 중 노드의 몫, 대상 자신은 1), attributed와 sanctioned, 그리고 라벨이 있으면 라벨이 들어 있습니다. edges[] — from, to, 거래량, tx_count. motifs[] — 자금 세탁 형태 적중으로, 섀도 신호이며 여기서는 비어 있습니다. extraction — 그림이 어떻게 잘렸는지를 나타냅니다. frontier_truncated: true는 홉 1이 frontier_cap(기본값이자 최댓값 500)보다 넓어서 가장 큰 거래 상대들만 남겼다는 뜻입니다.

edge_source, window, window_from — 그래프를 무엇으로 만들었는지를 나타냅니다. lifetime은 지금까지 인덱싱된 모든 날의 전체 기간 합계입니다(조용한 주소인 제재 대상 예시는 노드 하나, 엣지 없이 edge_source: "lifetime"으로 답했습니다). daily는 일 단위이며, 이때 window_from이 시작 지점을 알려 줍니다. 요청은 window=all이었지만 여기서는 2026-10-03입니다. 연결 수 기준을 넘는 메가 허브는 항상 daily입니다. lifetime_deferred: true는 전체 이력이 백그라운드에서 만들어지는 중인, 기간 all에 대한 일 단위 응답을 표시합니다.

snapshot_served, snapshot_age_seconds, built_at — 이 그림은 저장된 것이며 2.4시간 지난 것입니다. 그래프가 저장되어 있지 않고 기한 안에 만들어지지 않는 무거운 주소는 {"status": "building", "retry_after_seconds": 5, …}와 Retry-After: 5로 202를 답합니다. 그래프도 아니고 오류도 아닙니다. 기다린 뒤 같은 요청을 반복하십시오. 노드를 읽기 전에 상태를 확인하십시오. X-Degraded 헤더와 함께 오는 degraded_reason은 응답의 일부가 빠졌다는 뜻이며, 그 응답은 no-store입니다.

hops는 0–4(기본값 1)이고, window는 1h, 24h, 7d, 30d, 90d, 1y, all 중 하나이며, frontier는 너비의 상한을 정합니다(0이거나 파싱할 수 없으면 500 유지). token이 없으면 네트워크의 기본 스테이블코인이 쓰이므로 전달하십시오.

탐색

curl -s 'https://stablescan.achivx.com/v1/addresses/0x28C6c06298d514Db089934071355E5743bf21d60/walk?chain=1&token=USDC&hops=1&frontier_cap=20'
{
  "address": "0x28c6c06298d514db089934071355e5743bf21d60",
  "chain_id": 1,
  "token": "USDC",
  "decimals": 6,
  "token_source": "explicit",
  "window": "all",
  "window_from": "2026-10-03",
  "max_hops": 1,
  "frontier_cap": 20,
  "stop_at_attributed": true,
  "stop_on_sanctioned": false,
  "start_key": "addr:28c6c06298d514db089934071355e5743bf21d60",
  "self_sanctioned": false,
  "hops": [
    {"hop": 1, "nodes": [
      {"key": "addr:6a36…d9aa", "address": "0x6a36…d9aa", "direction": "in", "volume": 99200000, "volume_usd6": 99200000, "score": 0.6005, "attributed": false, "service": false, "sanctioned": false},
      {"key": "addr:b03f…2337", "address": "0xb03f…2337", "direction": "in", "volume": 66000000, "volume_usd6": 66000000, "score": 0.3995, "attributed": false, "service": false, "sanctioned": false}
    ]}
  ],
  "nodes_explored": 2,
  "frontier_truncated": false
}

탐색은 노드를 hops[]별로 묶고 스위치 값을 그대로 돌려줍니다. stop_at_attributed(기본값 true: 라벨이 붙은 서비스는 경계이며, 확인은 하지만 통과해 탐색하지 않음), stop_on_sanctioned(기본값 false), frontier_cap 1–500, hops 0–4(기본값 2)입니다. token_source는 토큰이 여러분이 지정한 것(explicit)인지 네트워크 기본값인지 알려 줍니다. self_sanctioned는 대상 자신이 목록에 올라 있는지입니다. 요청마다 새로 만들어지므로 마지막 집계 처리 시점의 일 단위 데이터를 반영합니다. 솔라나(Solana)에서는 채움이 끝나면 다음 처리(약 10분) 후 walk에 나타나고, graph에는 그 이후 그래프가 새로 만들어져야 나타납니다.

첫 요청의 세 가지 헬퍼로 같은 호출을 하면 다음과 같습니다.

Python

import time
g = scan(f"/v1/addresses/{addr}/graph", chain=1, token="USDT", hops=1)
if g.get("status") == "building":         # a 202 — urllib does not raise on it
    time.sleep(g["retry_after_seconds"]); g = scan(f"/v1/addresses/{addr}/graph", chain=1, token="USDT", hops=1)
print(g.get("window_from"), g["extraction"]["nodes_explored"], "nodes;", len(g["edges"]), "edges")
top = sorted((n for n in g["nodes"] if n["hop"] == 1), key=lambda n: -n["volume_usd6"])[:5]
for n in top:
    print(" ", n["direction"], n.get("name") or n["address"], n["volume_usd6"] / 1e6)

Go

var g struct {
	Status     string `json:"status"` // "building" on a 202
	WindowFrom string `json:"window_from"`
	Nodes      []struct {
		Address   string  `json:"address"`
		Hop       int     `json:"hop"`
		Direction string  `json:"direction"`
		VolumeUSD float64 `json:"volume_usd6"`
		Name      string  `json:"name"`
	} `json:"nodes"`
	Edges []struct {
		From, To string
		TxCount  int `json:"tx_count"`
	} `json:"edges"`
}
err := get("/v1/addresses/"+addr+"/graph", url.Values{"chain": {"1"}, "token": {"USDT"}, "hops": {"1"}}, &g)
if err != nil {
	return err
}
if g.Status == "building" {
	time.Sleep(5 * time.Second) // then repeat the same request
}

TypeScript

type Node = { address: string; hop: number; direction?: "in" | "out"; volume_usd6: number; name?: string; sanctioned: boolean };
type Graph = { status?: "building"; retry_after_seconds?: number; window_from?: string; nodes: Node[]; edges: { from: string; to: string; tx_count: number }[] };
let g = await scan<Graph>(`/v1/addresses/${addr}/graph`, { chain: 1, token: "USDT", hops: 1 });
if (g.status === "building") {
  await new Promise((r) => setTimeout(r, (g.retry_after_seconds ?? 5) * 1000));
  g = await scan<Graph>(`/v1/addresses/${addr}/graph`, { chain: 1, token: "USDT", hops: 1 });
}

Python의 urllib는 202를 성공으로 처리하므로, 만들어지는 중인 그래프와 실제 그래프를 구분해 주는 것은 위의 status 확인입니다. Go와 TypeScript 헬퍼도 202가 400 미만이므로 같은 방식으로 동작합니다.

무엇을 호출할 것인가

  • 그림 — 노드, 엣지, 거래량, 가장 활발한 거래 상대: /graph. 저장된 것이므로 반복 호출이 저렴하며, 몇 시간 지난 것일 수 있습니다(snapshot_age_seconds, 최대 6시간, 빌드 실패 시 대체용은 72시간).
  • 경로에 대한 질문 — 홉 2에 누가 있는가, 탐색이 서비스에서 멈췄는가, 경로상에 제재 대상이 있는가: /walk. 목록에 오른 첫 노드에서 멈추려면 stop_on_sanctioned=true를 씁니다. 요청마다 만들어지며 frontier_cap으로 제한됩니다.
  • 거래 상대가 의미하는 바에 대한 판정: 둘 다 아닙니다. /exposure가 오염 출발점까지 역방향으로 탐색하고 분류를 답합니다. 여기의 두 라우트는 그림만 그립니다.

이런 것이 보이면 …

  • window=all 요청에 "window_from": "2026-10-03" — 일 단위 데이터는 고정된 기간 범위만큼 보관됩니다(/v1/methodology에서는 이를 edge_grain_horizon이라고 부릅니다). 응답은 그 구간만 다룹니다. 그 안에 없는 거래 상대를 그 날짜 이전에도 없었던 것으로 취급하지 마십시오.
  • "frontier_truncated": true — 홉이 상한보다 넓었습니다. 가장 큰 거래 상대만 남았고 나머지는 그림에 없습니다. window를 좁히거나 특정 token으로 /walk를 요청하십시오.
  • token "USDC" is not indexed on chain 728126428과 함께 400 bad_request — 해당 스테이블코인이 이 네트워크의 레지스트리에 없습니다. 무엇이 있는지는 /v1/tokens?chain=이 나열합니다.
  • 솔라나 — 대상의 coverage_status가 함께 옵니다. pending은 그림이 더 커질 수 있다는 뜻입니다.

Stablecoin scanner ACHIVX에서

출처

더 알아보기

주소 · GET …/graph · GET …/walk · 2026-10-24 작성, openapi.json, agents.md 및 당일 실제 호출 기준. 응답 형태는 인용이며, 수치는 날짜 기준이고 인덱스에 따라 달라집니다.

이 페이지는 ACHIVX Academy 영어 원문을 한국어로 옮긴 것입니다. 번역과 원문이 다르면 영어 원문이 기준입니다.