주소의 제재 대상 자금이나 해킹 자금 노출은 어떻게 측정합니까?

주소 · 가장 가까운 오염 출발점까지의 역방향 탐색: 분류, 도달한 출발점, 비율, 그리고 탐색이 어디까지 갔는지

  • API 가이드
  • 8분
  • 중급
  • 개발자
  • GET /v1/addresses/{address}/exposure

ACHIVX Academy 원문 (영어) ↗

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
negligible0.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에서

출처

더 알아보기

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

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