본문으로 이동

오라클 소수 자릿수 불일치

소수 자릿수 불일치로 오라클 응답값, 토큰 수량, 래퍼 교환율 또는 프로토콜 값에 잘못된 단위 배율이 적용되면 차입, 발행, 상환 및 청산에서 자릿수 단위의 오류가 발생합니다.

업데이트

교육 목적으로만 제공되며 투자 조언이 아닙니다. 투자에는 손실이 발생할 수 있습니다.

핵심 답변

오라클 소수 자릿수 불일치는 컨트랙트가 원시 정수를 잘못된 단위 지수, 가격 방향 또는 내부 스케일로 해석할 때 발생합니다. 피드 소수 자릿수, 토큰 소수 자릿수, 호가 토큰 소수 자릿수, 래퍼 또는 지분의 교환율 스케일, 프로토콜의 WAD나 RAY 관행은 서로 독립적입니다. 프런트엔드 표시가 올바르게 보인다고 해서 소비자 컨트랙트가 같은 계산을 수행한다는 뜻은 아닙니다.

기준 토큰 원시 수량 A_raw의 소수 자릿수를 d_t, 기준 토큰 한 단위의 가격을 호가 토큰으로 나타내는 양의 피드 응답값 P_raw의 소수 자릿수를 d_p라고 하겠습니다. 소수 자릿수가 d_q인 호가 토큰 원시 수량은 V_raw = round(A_raw * P_raw * 10^d_q / 10^(d_t + d_p))입니다. 이 식은 명시한 호가 방향에만 유효하며 피드, 단위, 자료형 및 반올림 규칙을 검증해야 합니다. 어댑터가 이미 값을 정규화했다면 다시 스케일을 적용해서는 안 됩니다.

ERC-20의 decimals()는 선택적 표시 메타데이터이지 모든 토큰이 소수 18자리를 쓴다는 보장이 아닙니다. 피드의 decimals()는 해당 피드 응답값의 소수 자릿수를 나타내며 토큰이나 프로토콜 스케일을 나타내지 않습니다. 검사 산술은 오버플로 시 되돌리기로 중단할 수 있지만 차원이 잘못된 식은 감지하지 못합니다. 또한 중간 곱이 오버플로하면 최종값은 표현 가능하더라도 서비스 거부 상태가 생길 수 있습니다.

작동 방식

  1. 체인, 블록, 소비자 컨트랙트, 어댑터, 피드 프록시와 집계기, 토큰 또는 볼트, 컴파일러와 수학 라이브러리 버전 및 업그레이드 상태를 고정합니다.
  2. 모든 정수의 자료형과 단위를 목록화합니다. 토큰 원시 수량, 토큰 소수 자릿수, 부호 있는 피드 응답값, 피드 소수 자릿수, 기준 및 호가 방향, 래퍼 또는 지분 교환율, 프로토콜 내부 스케일, 출력 토큰 소수 자릿수를 포함합니다.
  3. 변환 전에 출처를 검증합니다. 올바른 주소와 방향, 양의 응답값, 타임스탬프와 상태, 허용 가능한 경과 시간과 범위, 대체 값의 의미, 필요한 경우 L2 시퀀서 유예 규칙을 확인합니다.
  4. 입력 원시 단위에서 출력 원시 단위로 이어지는 하나의 차원식으로 도출합니다. 스케일을 올리거나 내리는 경우를 명시적으로 분기하고, 모든 10의 거듭제곱 지수를 제한하며, 각 항을 정확히 한 번만 정규화합니다.
  5. 검증된 전정밀도 곱셈-나눗셈 또는 범위가 제한된 약분 방식을 사용합니다. 나눗셈 우선으로 인한 절삭, 검사되는 중간 곱의 오버플로, 검사되지 않은 순환, 안전하지 않은 부호 변환이나 좁은 자료형으로의 캐스팅을 피합니다.
  6. 경제 행위마다 내림, 올림 또는 최근접 반올림을 지정합니다. 담보, 부채, 차입, 발행, 상환, 수수료, 청산 및 볼트 지분 변환에는 서로 다른 보수적 방향이 필요할 수 있습니다.
  7. 극단적 수량, 소수 자릿수 조합, 역수, 복합 피드, 0, 음수 및 오래된 응답값, 업그레이드와 잔여 단위에 대해 골든 벡터와 속성 검사를 수행합니다. 온체인 결과를 독립적인 고정밀 모델과 대조하고 영향을 받을 수 있는 익스포저에 한도를 둡니다.

정규화는 표시 형식이 아니라 차원 분석입니다. BTC/USDUSD/BTC에는 역수식이 필요하며 표지만 바꾼다고 가격이 뒤집히지 않습니다. 복합 피드에는 각 항의 스케일과 타임스탬프가 필요합니다. Solidity 정수 나눗셈은 0을 향해 절삭하므로 대수적으로 같은 식이라도 순서를 바꾸면 온체인 결과가 달라질 수 있습니다. 전정밀도 mulDiv는 중간값 비트 폭 문제를 해결하지만, 호출자는 여전히 올바른 분자, 분모, 단위, 한계 및 반올림 방향을 제공해야 합니다.

계산 예시

  • 8자리와 18자리. BTC/USD 피드가 6,000,000,000,000을 반환하고 소수 자릿수가 d_p = 8이면 가격은 60,000 USD/BTC입니다. 원시 응답값을 소수 18자리로 해석하면 0.000006 USD/BTC가 되어 10^10배 과소평가되며, 이는 10^9배가 아닙니다. 가격을 WAD로 변환하면 6,000,000,000,000 * 10^(18 - 8) = 60,000,000,000,000,000,000,000입니다.
  • 수량, 가격 및 출력 단위. A_raw = 2,500,0002.5토큰을 나타내고 소수 자릿수는 d_t = 6입니다. P_raw = 200,000,0002호가 토큰을 나타내고 소수 자릿수는 d_p = 8입니다. 소수 18자리 내부 호가값은 2,500,000 * 200,000,000 * 10^18 / 10^(6 + 8) = 5,000,000,000,000,000,000, 즉 5 quote tokens입니다. 토큰 분모를 빼면 포지션이 10^6배 과대평가됩니다.
  • 역수와 절삭. WAD 스케일의 ETH/USD는 2,000 * 10^18입니다. 같은 스케일의 USD/ETH는 floor(10^36 / (2,000 * 10^18)) = 500,000,000,000,000, 즉 0.0005 ETH/USD입니다. 별도로 A_raw = 999,999, d_t = 6, 가격이 2 * 10^18이면 전정밀도 곱셈-나눗셈 결과는 1,999,998,000,000,000,000입니다. 수량을 먼저 10^6으로 나누면 0이 되어 가치를 모두 잃습니다.
  • 중간 오버플로와 반올림. x = 2^200, y = 2^100, 분모를 2^100으로 둡니다. 정확한 결과 2^200uint256에 들어가지만 x * y = 2^300은 들어가지 않습니다. 검사 곱셈은 되돌리고 비검사 곱셈은 순환하지만, 전정밀도 mulDiv2^200을 반환합니다. 정수 5 / 2는 내림하면 2, 올림하면 3이므로 반올림 규칙은 경제적 불변조건의 일부입니다.

위험

  • 체인, 피드, 프록시, 어댑터, 토큰, 볼트 또는 소비자 컨트랙트 주소가 잘못되었습니다.
  • 역수 변환 없이 기준 자산과 호가 자산 방향을 뒤집습니다.
  • 토큰 소수 자릿수를 18로 가정하거나 선택적 메타데이터를 읽을 수 없거나 잘못되어 있습니다.
  • 피드에서 읽어 고정하지 않고 피드 소수 자릿수를 8로 가정합니다.
  • 호가 토큰 소수 자릿수와 프로토콜 WAD, RAY, 시장 또는 회계 스케일을 혼동합니다.
  • 래퍼, 지분, 지수 또는 교환율 소수 자릿수를 빠뜨립니다.
  • 어댑터가 이미 정규화한 값에 스케일 인자를 두 번 적용합니다.
  • 필요한 스케일 인자나 분모를 빠뜨립니다.
  • 응답값이 양수인지 확인하기 전에 부호 있는 값을 부호 없는 자료형으로 변환합니다.
  • 0, 오래된 값, 미완료 값, 상한에 걸린 값 또는 무효한 피드 결과를 받아들입니다.
  • 소수 자릿수 지수나 10의 거듭제곱 계산이 언더플로, 오버플로 또는 한계 초과를 일으킵니다.
  • 최종 몫은 범위 안에 들지만 곱셈 중간값이 오버플로합니다.
  • 비검사 산술, 비트 시프트 또는 명시적 축소 변환이 조용히 순환하거나 절삭합니다.
  • 곱셈 전 나눗셈이 정밀도를 없애거나 잔여 단위를 0으로 만듭니다.
  • 경제 행위에 맞지 않는 내림, 올림 또는 최근접 반올림을 사용합니다.
  • 반복 변환으로 정밀도 손실이나 체계적인 가치 누출이 누적됩니다.
  • 가격, 상한, 비율, 백분율, 베이시스포인트, WAD 및 RAY 값을 서로 다른 단위로 비교합니다.
  • 피드, 토큰, 프록시, 어댑터 또는 볼트 업그레이드로 저장된 소수 자릿수 가정이 무효화됩니다.
  • 프런트엔드, 지갑, RPC 또는 인덱서 형식이 다른 온체인 계산을 가립니다.
  • 오평가가 차입, 발행, 상환, 청산, 상한, 부실채권 또는 불공정한 지분 발행을 증폭합니다.

흔한 오해

  • “모든 ERC-20 토큰은 소수 18자리를 사용한다.” ERC-20 메타데이터 메서드는 선택 사항이며 실제 자산은 서로 다른 값과 동작을 사용합니다.
  • “모든 USD 가격 피드는 소수 8자리를 사용한다.” 피드 정밀도는 정확한 배포본의 인터페이스 속성이므로 직접 읽고 버전을 고정해야 합니다.
  • “원시 정수가 크면 조작의 증거다.” 단위, 방향, 소수 자릿수, 타임스탬프 및 소비자 스케일이 없으면 원시 크기는 의미가 없습니다.
  • “Solidity 0.8이면 스케일링도 정확해진다.” 검사 오버플로는 되돌릴 수 있지만 잘못된 단위, 절삭, 캐스팅 또는 반올림 정책을 고치지는 않습니다.
  • “항상 먼저 곱하거나 소수 자릿수를 늘리면 정확도가 높아진다.” 오버플로, 이중 스케일링 또는 잘못된 단위 보존이 발생할 수 있습니다. 전정밀도 연산에도 올바른 식이 필요합니다.

관련 주제

출처

탐색

위키 검색...