토큰 계약은 잔액과 전송량을 정수로 기록합니다. decimals는 앱이 그 정수에서 소수점을 어디에 표시할지 알려 주는 선택적 메타데이터입니다. decimals가 6인 토큰에서 원장 값 1,000,000은 화면의 1단위이고, 18인 토큰에서는 10의 18제곱이 1단위입니다. 심볼이나 다른 토큰의 decimals를 대신 적용하면 수량을 크게 잘못 읽을 수 있습니다.
원장에는 소수 대신 정수가 기록된다
스마트 계약의 balanceOf와 transfer 수량은 정수입니다. 컴퓨터 화면에 1.25 토큰이 보이더라도 계약 저장소에 소수 1.25가 그대로 들어가는 것은 아닙니다. decimals가 6이면 1.25를 1,250,000이라는 기본 단위로 표현합니다. 앱은 원장 값을 10의 decimals 제곱으로 나눠 사람이 읽는 수량을 만듭니다.
이 구조는 회계 계산에서 부동소수점 오차를 피하는 데 도움이 됩니다. 그러나 표시 계층이 잘못된 decimals를 읽으면 원장 잔액은 정상이어도 화면 수량이 백만 배 또는 그 이상 달라 보일 수 있습니다. 거래 전에는 토큰 심볼이 아니라 현재 네트워크의 계약 주소가 반환하는 메타데이터를 확인해야 합니다.
| decimals | 화면 1단위 | 화면 0.5단위 |
|---|---|---|
| 0 | 1 | 정수만 가능 |
| 6 | 1,000,000 | 500,000 |
| 8 | 100,000,000 | 50,000,000 |
| 18 | 1,000,000,000,000,000,000 | 500,000,000,000,000,000 |
ERC-20에서 decimals는 선택적 표시 메타데이터다
ERC-20 표준은 name, symbol, decimals를 선택적 함수로 설명합니다. 토큰 전송의 핵심은 transfer와 balanceOf 같은 함수이고 decimals가 없더라도 표준의 필수 동작 자체가 사라지는 것은 아닙니다. 앱은 decimals 호출 실패나 비표준 반환값을 처리할 방법이 있어야 하며 임의로 18이라고 가정해서는 안 됩니다.
OpenZeppelin 문서는 decimals가 사용자 표현에만 쓰이고 계약 산술은 정수로 수행된다고 설명합니다. 기본 구현은 흔히 18을 사용하지만 개발자가 다른 값을 재정의할 수 있습니다. 'ERC-20은 모두 18자리'라는 규칙은 없습니다. 스테이블코인과 오래된 토큰, 브리지 버전은 서로 다른 값을 사용할 수 있습니다.
decimals는 원장 수량을 바꾸지 않고 사람이 보는 소수점 위치를 정한다.
JOBCOIN 해설
전송 입력은 화면값을 기본 단위로 바꾼다
지갑에서 2.5 토큰을 입력하면 앱은 2.5 × 10^decimals를 계산해 transfer의 정수 인자로 넣습니다. decimals 6이면 2,500,000이고 decimals 18이면 2,500,000,000,000,000,000입니다. 계약 호출 데이터에서 큰 16진 정수가 보이는 것은 이 기본 단위 표현 때문일 수 있습니다.
직접 스크립트를 작성할 때 JavaScript Number 같은 부동소수점 타입으로 큰 값을 계산하면 정밀도를 잃을 수 있습니다. 문자열 파서나 임의 정밀도 정수 라이브러리로 소수 입력을 기본 단위 정수로 변환하고, 허용 소수 자릿수를 넘는 입력은 반올림 규칙을 명시하거나 거부해야 합니다.
- 현재 체인과 토큰 계약 주소를 확인한다.
- 계약의 decimals 반환값을 확인한다.
- 화면 수량을 기본 단위 정수로 변환해 다시 계산한다.
- 전송·approve 호출 데이터의 정수 인자를 대조한다.
승인 수량도 같은 기본 단위를 사용한다
approve의 amount도 화면 토큰 수가 아니라 기본 단위 정수입니다. decimals 6 토큰의 100단위 승인은 100,000,000으로 기록됩니다. 탐색기가 이를 잘못된 decimals로 표시하거나 토큰 메타데이터를 아직 불러오지 못하면 사람이 의도한 승인량과 다르게 보일 수 있습니다. 무제한 승인은 매우 큰 정수로 나타나며 decimals와 별개로 권한 범위가 큽니다.
승인 화면에서 '100'이라는 문구만 보지 말고 대상 spender, 토큰 계약 주소, 원시 amount와 앱의 표시값을 함께 확인합니다. 같은 심볼의 모방 토큰은 다른 decimals를 사용해 혼동을 만들 수 있습니다. 승인 취소도 해당 계약의 allowance를 0으로 바꾸는 거래인지 확인합니다.
가격 계산에는 토큰 단위와 화폐 단위를 함께 맞춘다
온체인 가격 오라클이나 풀 준비금도 각기 다른 decimals를 사용할 수 있습니다. 토큰 A 잔액 정수와 토큰 B 잔액 정수를 그대로 나누면 표시 단위 차이가 가격에 섞입니다. 먼저 각 잔액을 토큰 단위로 정규화하고, 가격 피드 자체의 decimals도 별도로 적용해야 합니다. 토큰 decimals와 오라클 decimals가 같다고 가정하면 안 됩니다.
예를 들어 6자리 토큰과 18자리 토큰의 원시 준비금 비율에는 10의 12제곱 차이가 포함됩니다. UI에서는 정상 가격처럼 보여도 컨트랙트 통합 코드가 배율을 틀리면 담보 평가와 최소 수령량이 크게 어긋날 수 있습니다. 테스트에는 0자리, 6자리, 8자리, 18자리 토큰을 포함해 경계를 확인합니다.
잔액이 이상하면 원시값부터 역산한다
지갑 잔액이 갑자기 0.000001 또는 백만 단위로 보이면 거래 실패로 단정하기 전에 탐색기에서 계약 주소와 balanceOf 원시값을 확인합니다. 원시값을 10^decimals로 나눠 수동 계산하고 다른 신뢰할 수 있는 앱의 표시와 비교합니다. 토큰 계약이 업그레이드되거나 프록시 메타데이터가 바뀌는 구조인지도 확인합니다.
전송 후에는 보낸 원시 amount, 수취인의 balanceOf 변화, Transfer 이벤트 값을 같은 기본 단위로 비교합니다. UI 반올림 때문에 마지막 자리 일부가 숨겨질 수 있으므로 회계나 전체 잔액 전송은 표시 소수만 복사하지 않습니다. 정확한 정수와 계약 주소가 최종 기준입니다.
자주 묻는 질문
ERC-20 토큰은 모두 decimals 18인가요?
아닙니다. 18이 흔하지만 decimals는 선택적 메타데이터이고 계약이 다른 값을 사용할 수 있습니다.
decimals가 6이면 토큰 총량이 적은가요?
그렇지 않습니다. decimals는 표시 단위를 정할 뿐이며 총공급량은 totalSupply 정수와 함께 해석해야 합니다.
decimals를 바꾸면 보유 토큰 가치도 바뀌나요?
일반적인 고정 메타데이터 토큰에서는 임의 변경을 전제로 하지 않습니다. 표시값 변경 가능성이 있는 업그레이드 구조라면 계약 권한과 구현을 별도로 검토해야 합니다.



