TWAP(시간가중평균가격) 오라클과 담보가치평가 엔진을 처음부터 직접 구현했습니다. Tectonic 사건(토큰 가격을 20분 만에 100배로 펌핑 → 과대담보로 과대차입)을 그대로 재현하고 막는 코드입니다. 지금은 전부 무료로 공개합니다.
2026년 8월 30일, Cronos 최대 대출 프로토콜 Tectonic에서 공격자가 유동성 적은 거버넌스 토큰 가격을 약 20분 만에 100배로 펌핑했습니다. 그 뒤 부풀려진 토큰을 담보로 예치해서 실제 가치보다 훨씬 많은 금액을 빌려나갔습니다 — "가격이 곧 담보가치"라는 전제를 역이용한 공격입니다.
TWAP 기반 오라클 — 순간적인 스팟가격 조작을 무시하고 일정 기간 평균가격을 기준값으로 사용.
// TWAP(시간가중평균가격) 오라클 — 순간 스팟가격 조작 방어
class PriceOracleGuard {
constructor({ windowMs = 1200000, maxDeviation = 0.1 } = {}) {
this.history = []; // {price, time}
this.windowMs = windowMs; // 기본 20분
this.maxDeviation = maxDeviation; // TWAP 대비 허용 변동폭 10%
}
pushPrice(spotPrice) {
const now = Date.now();
this.history.push({ price: spotPrice, time: now });
this.history = this.history.filter(p => now - p.time < this.windowMs);
}
twap() {
if (!this.history.length) return 0;
const sum = this.history.reduce((s, p) => s + p.price, 0);
return sum / this.history.length;
}
getSafePrice(spotPrice) {
this.pushPrice(spotPrice);
const twap = this.twap();
const deviation = Math.abs(spotPrice - twap) / (twap || spotPrice);
if (deviation > this.maxDeviation) {
return { price: twap, flagged: true, reason: 'spot_deviation_exceeded', spotPrice, twap };
}
return { price: spotPrice, flagged: false };
}
}
담보가치평가 + 자산별 차입한도(LTV) 로직 — 위 오라클을 가격 소스로 주입받아 사용.
// 담보가치평가 + 차입한도 로직 (Tectonic 사건 대응)
class CollateralEngine {
constructor(getPrice, { ltv = 0.7 } = {}) {
this.getPrice = getPrice; // 오라클 가격 조회 함수 주입
this.ltv = ltv; // 담보인정비율 70%
this.positions = {};
}
deposit(user, token, amount) {
this.positions[user] = this.positions[user] || { collateral: {}, borrowed: 0 };
this.positions[user].collateral[token] = (this.positions[user].collateral[token] || 0) + amount;
}
collateralValue(user) {
const pos = this.positions[user];
if (!pos) return 0;
return Object.entries(pos.collateral)
.reduce((sum, [token, amt]) => sum + amt * this.getPrice(token), 0);
}
borrow(user, amount) {
const maxBorrow = this.collateralValue(user) * this.ltv;
const pos = this.positions[user];
if (pos.borrowed + amount > maxBorrow) {
return { status: 'rejected', reason: 'insufficient_collateral', maxBorrow };
}
pos.borrowed += amount;
return { status: 'approved', borrowed: pos.borrowed };
}
}
이 상품에 대한 피드백이나 질문이 있으면 알려주세요. 회신을 원하시면 이메일을 남겨주세요(선택).