주소의 제재 대상 자금이나 해킹 자금 노출은 어떻게 측정합니까?
주소 · 가장 가까운 오염 출발점까지의 역방향 탐색: 분류, 도달한 출발점, 비율, 그리고 탐색이 어디까지 갔는지
- API 가이드
- 8분
- 중급
- 개발자
- GET /v1/addresses/{address}/exposure
GET /v1/addresses/{address}/exposure?chain=&hops=는 주소에서 거래 상대를 거쳐 가장 가까운 오염 출발점(taint root) — OFAC 목록에 오른 주소, 또는 해킹·드레이너·믹서 라벨이 붙은 주소 — 을 향해 hops(기본값 3)까지 역방향으로 탐색하고 exposure를 답합니다. 값은 sanctioned, direct, indirect, negligible, none, unknown 중 하나이며, reached_roots[], exposure_fraction, min_hops, 그리고 탐색 자체에 대한 기록(hops_completed, nodes_explored, frontier_truncated, truncation_reason)이 함께 옵니다. 판정 /risk는 이 탐색을 바탕으로 만들어집니다. 출발점과 경로 길이가 필요할 때 이 라우트를 호출하십시오.
요청
curl -s 'https://stablescan.achivx.com/v1/addresses/0x098B716B8Aaf21512996dC57EB0615e2383E2f96/exposure?chain=1&hops=2'2026-10-24의 제재 대상 예시입니다. 출발점은 주소 자신입니다.
{
"address": "0x098b716b8aaf21512996dc57eb0615e2383e2f96",
"chain_id": 1,
"exposure": "sanctioned",
"min_hops": 0,
"exposure_fraction": 1,
"reached_roots": [
{"address": "0x098b716b8aaf21512996dc57eb0615e2383e2f96", "kind": "sanctioned", "hops": 0, "exposure_fraction": 1}
],
"nodes_explored": 0,
"frontier_truncated": false,
"hops_requested": 2,
"hops_completed": 0,
"incomplete_reasons": [],
"data_vintage": "2026-09-10T00:00:11Z",
"sanctions_list_as_of": "2026-10-24T04:00:04Z",
"peg_reliable": true,
"note": "Bounded backward BFS over the EDGE_MIN_USD6-floored value graph to the nearest taint root (OFAC-sanctioned + hack/drainer/mixer labels). 'none' = assessed over sufficient coverage, nothing found; 'unknown' = we could NOT complete the assessment …",
"computed_at": "2026-10-24T10:46:33Z",
"snapshot_served": false,
"freshness_seconds": 202
}기본값 세 홉에서의 바이낸스(Binance) 핫월렛입니다. 탐색은 예산이 바닥나기 전에 아무 데도 가지 못했습니다.
{
"exposure": "unknown",
"exposure_fraction": 0,
"reached_roots": [],
"nodes_explored": 0,
"frontier_truncated": true,
"truncation_reason": "time_budget",
"hops_requested": 3,
"hops_completed": 0,
"incomplete_reasons": ["time_budget"]
}첫 요청의 세 가지 헬퍼로 같은 호출을 하면 다음과 같습니다.
Python
exp = scan(f"/v1/addresses/{addr}/exposure", chain=1, hops=3)
print(exp["exposure"], exp["min_hops"], exp["exposure_fraction"])
for root in exp["reached_roots"]:
print(" ", root["kind"], root["address"], root["hops"], "hops", f'{root["exposure_fraction"]:.2%}')Go
var exp struct {
Exposure string `json:"exposure"`
MinHops *int `json:"min_hops"`
ExposureFraction float64 `json:"exposure_fraction"`
ReachedRoots []struct {
Address string `json:"address"`
Kind string `json:"kind"`
Hops int `json:"hops"`
} `json:"reached_roots"`
TruncationReason string `json:"truncation_reason"`
HopsCompleted int `json:"hops_completed"`
}
if err := get("/v1/addresses/"+addr+"/exposure", url.Values{"chain": {"1"}, "hops": {"3"}}, &exp); err != nil {
return err
}TypeScript
type Exposure = {
exposure: "sanctioned" | "direct" | "indirect" | "negligible" | "none" | "unknown";
min_hops: number | null; exposure_fraction: number;
reached_roots: { address: string; kind: string; hops: number; exposure_fraction: number }[];
hops_requested: number; hops_completed: number; frontier_truncated: boolean; truncation_reason?: string;
incomplete_reasons: string[];
};
const exp = await scan<Exposure>(`/v1/addresses/${addr}/exposure`, { chain: 1, hops: 3 });필드별 설명
exposure — 분류와 각 분류가 주장하는 내용입니다.
| 분류 | 주장 | 설정되는 위험 등급 |
|---|---|---|
sanctioned | 무관용 기준을 넘는 OFAC 연관성. min_hops: 0이면 주소 자체가 목록에 올라 있음 | severe |
direct | 해킹 / 드레이너 / 믹서 출발점에서 한 단계 거쳐 받은 스테이블코인이 중요성 하한을 넘음 | high |
indirect | 그런 출발점이 중개자를 거쳐 도달 범위 안에 있으며 하한을 넘음 | medium |
negligible | 0.5 % 중요성 하한 미만의 실제 적중 — 실제 흔적이 절대 숨겨지지 않도록 표시됨 | 없음, 증거로 기록됨 |
none | 탐색이 충분한 집계 범위에서 완료되었고 아무것도 찾지 못함 | 없음 |
unknown | 평가를 완료할 수 없었음 — 이유는 incomplete_reasons에 있음 | 등급을 미완료로 표시 |
reached_roots[] — 탐색이 도달한 모든 출발점입니다. address, kind(sanctioned, hack, drainer, mixer), hops, 그리고 유입액 중 해당 출발점의 몫이 들어 있습니다. min_hops는 그중 어느 것까지든 가장 짧은 경로입니다(도달한 것이 없으면 null). exposure_fraction은 주소의 관측된 유입액 중 오염된 경로에 배분된 몫입니다. 금액에 비례한 헤어컷(haircut)이며, 코인 개수도 아니고 제재 판정도 아닙니다(방법론 자체의 표현입니다).
hops_requested, hops_completed, nodes_explored, frontier_truncated, truncation_reason — 탐색 자체에 대한 기록입니다. truncation_reason은 time_budget(요청 기한 안에 머물기 위해 잘림, 덜 붐비는 시점에는 완료될 수 있음), frontier_cap(주소 500개보다 넓은 홉 — 주소의 속성이므로 매 호출마다 반복됨), 또는 frontier_cap+time_budget입니다. 잘린 탐색은 절대 깨끗하다고 답하지 않습니다. 잘리기 전에 도달한 출발점이 이미 sanctioned, direct, indirect를 설정했다면 그것이 유지되고, 그렇지 않으면 exposure는 unknown입니다. 따라서 truncation_reason만 보지 말고 exposure를 읽으십시오.
peg_reliable — 비율 뒤에 있는 달러 환산이 유효했다는 뜻입니다(페그 1에서 USDC == USD).
snapshot_served, snapshot_age_seconds, degraded_reason — 탐색은 저장된 것일 수 있으며(15분 미만, 지금 로드된 OFAC 목록 기준으로 실행됨), 그 경우 실행 시각인 computed_at과 함께 응답 그 자체로 제공됩니다. 실시간 탐색을 실행할 수 없을 때는 최대 6시간 된 저장 탐색이 degraded_reason: "live_build_busy" 또는 "live_build_timeout"과 함께 대신 제공됩니다. 그 응답은 no-store이며 절대 재사용되지 않습니다.
hops 고르기
기본값은 3이며 위험 판정이 쓰는 깊이입니다. 홉이 적을수록 활발한 주소에서 더 자주 완료됩니다. hops=1은 이 주소가 출발점에서 직접 받았는가만 묻습니다. 홉이 많을수록 indirect가 의미할 수 있는 범위가 넓어집니다. hops=1에서 none으로 완료된 탐색은 hops=3에서 잘려 unknown이 된 탐색보다 강한 진술입니다. 앞의 것은 한 단계를 확인했고 아무것도 없음이고, 뒤의 것은 확인할 수 없었음입니다.
이런 것이 보이면 …
- 거래소가 아닌 지갑에서
"exposure": "unknown"— 생각보다 흔합니다. 서비스 라벨이 없는 고연결 주소가 2홉 또는 3홉 이웃에 하나라도 있으면 탐색은 예산을 다 씁니다. 라벨이 붙은 서비스는 확인만 하고 통과해 탐색하지 않습니다. 비용을 만드는 것은 라벨 없는 허브입니다. - 60 대신
Cache-Control: max-age=10— 탐색이 잘렸습니다. 10초 안에 다시 요청하면 같은 응답이 돌아옵니다. "incomplete_reasons": ["short_history"]— 관측된 유입액이 1달러 미만이며, 탐색할 것이 없습니다."ofac_list_stale"— 목록이 7일보다 오래되었습니다(sanctions_list_as_of). 도달한 출발점은 여전히 유효하며, 깨끗한 탐색은unknown으로 읽힙니다.
Stablecoin scanner ACHIVX에서
- 0홉에서 출발점에 도달하는 탐색: /v1/addresses/0x098B…2f96/exposure?chain=1.
- 페이지에서의 같은 탐색 — nearest root · haircut · ended within N levels 줄이 있는 노출 카드: /ethereum/address/0x098B…2f96.
- 스캐너 자체 표현으로 된 용어 — 헤어컷, 귀속 중단, 노이만 수렴: /v1/methodology.
출처
- REST 인터페이스의 OpenAPI 3.1 명세(API 1.4.0)
- 에이전트 매뉴얼 — agents.md(버전 2026-10-05)
- GET /v1/methodology (stablscan-methodology-v0.5.0)
더 알아보기
관련 질문
- 주소에 대한 단일 위험 판정은 어떻게 얻고, 언제 unknown이 됩니까?
- 주소의 거래 상대는 어떻게 가져옵니까: /graph 또는 /walk?
- 응답은 어떻게 읽습니까: unknown, null, 빈 목록, no-store
주소 · GET /v1/addresses/{address}/exposure · 2026-10-24 작성, openapi.json, agents.md 및 당일 실제 호출 기준. 응답 형태는 인용이며, 수치는 날짜 기준이고 인덱스에 따라 달라집니다.
이 페이지는 ACHIVX Academy 영어 원문을 한국어로 옮긴 것입니다. 번역과 원문이 다르면 영어 원문이 기준입니다.