메인 콘텐츠로 건너뛰기
고정이율 볼트는 설정된 APR과 경과 시간으로 share당 기초 자산 가치를 계산합니다. 사용자가 보유한 shares 수량은 이자 때문에 늘어나지 않고, shares를 자산으로 환산하는 **환율(rate)**이 올라갑니다. 기본 APR은 **연 2%**이며, 정기 환율 갱신의 운영 목표는 USDT(6 decimals) 24시간마다, JPYC(18 decimals) 1시간마다입니다. 이 페이지는 구조와 운영 방식을 설명합니다. 주소·승인 대상·함수 호출·테스트 방법은 고정이율 볼트 연동 가이드를 참고하세요.
이 주기는 오프체인 keeper의 운영 목표입니다. 컨트랙트가 decimals를 보고 주기를 자동 선택하거나 시간이 되면 스스로 실행되는 것은 아닙니다. keeper의 poke 트랜잭션이 성공해야 확정 환율이 바뀝니다. Kairos 테스트넷에서는 자동 keeper를 운영하지 않으므로 환율 갱신과 출금 체결 테스트를 SuperEarn 팀과 조율해야 합니다.

자금과 컨트랙트 구조

사용자는 입금할 때 Router를 호출하고, 출금할 때 Queue에 요청을 등록합니다. 자산을 운용하는 경로와 사용자 shares의 환율을 결정하는 경로는 분리되어 있습니다. 위 그림은 자산 이동을 요약합니다. Router가 Teller를 호출하면 Teller가 Vault에 shares 발행을 지시합니다. keeper는 Gateway를 통해 운용 자산을 이동·회수합니다. Gateway는 CustomVault shares를 보유하고, 입금 중에는 기초 자산도 일시 보유합니다. CustomVault의 정상 출금 자산은 Vault로 직접 돌아옵니다. 일반 사용자의 입금 경로는 VedaRouter → Teller → Vault이고, 환율 갱신 경로는 VedaKeeper.poke → Controller.poke → Accountant.updateExchangeRate입니다. Manager와 권한 설정은 Vault 자산 이동에 허용된 호출을 제한합니다. 고정 환율은 전략의 실제 NAV(순자산가치)를 그대로 복사하지 않습니다. 전략 수익률이 변해도 Controller는 설정된 APR 공식을 사용합니다. 운영자는 이 환율로 출금할 수 있도록 자산과 유동성을 관리해야 합니다. rate를 올리는 호출 자체가 토큰이나 실제 운용 수익을 만드는 것은 아닙니다.

고정 APR이 적용되는 방식

목표 APY는 2%입니다(거버넌스 변경 가능). 환율은 절대 시간에 고정(anchor)된 곡선을 따르므로, keeper가 poke를 호출하면 다음 값으로 설정됩니다.
  • anchorRate, anchorTime: 고정 기준점(마지막 rate 변경 또는 배포 시점)으로, 직전 rate가 아닙니다.
  • ratePerSecond: 목표 APY에서 역산한 초당 복리 계수(27자리 고정소수점). ratePerSecond^(365 days) = 1 + APY가 성립합니다. 정수 거듭제곱(rpow)으로 계산하고 소수 부분은 버립니다(내림).
  • now - anchorTime: anchor 이후의 절대 경과 초 — 유일한 시간 입력값입니다.
  • lastPokeAt: 마지막 성공한 push 시각. keeper의 최소 간격 게이트일 뿐 환율 값에는 영향이 없습니다.
환율이 절대 경과 시간에만 의존하므로 poke 주기는 실현 APY를 바꾸지 않습니다. 늦거나 불규칙한 poke도 동일한 곡선 위에 확정 환율을 올려놓으며 drift가 없습니다. aprBps() / targetApyBps()는 실효 APY(2%)를 온체인에서 되읽어 줍니다. share당 가치는 Accountant의 base 자산 최소 단위로 표시됩니다. Accountant.decimals()는 base 토큰의 decimals와 같습니다. JPYC 기반 볼트의 rate는 18 decimals, USDT 기반 볼트의 rate는 6 decimals입니다. 이는 두 볼트의 shares가 모두 18 decimals인 것과 별개입니다. shares 수량을 자산 가치로 환산할 때는 두 경우 모두 floor(shares × rate / 10^18)을 사용하며, 결과는 해당 base 자산의 최소 단위입니다. 기본 목표 APY는 2%이지만 거버넌스가 setRatePerSecond로 변경할 수 있습니다. 경과 시간이 있으면 먼저 기존 rate로 그 기간을 정산한 뒤, 재-anchor하고 새 rate를 앞으로만 적용하므로 변경이 소급 적용되지 않습니다. 따라서 거버넌스 변경은 정기 갱신 시각 외에 환율을 갱신할 수 있습니다. 실현 연간 상승률은 poke 스케줄과 무관하게 설정한 APY와 같습니다. 정수 절삭은 rate 바닥에서 단위 미만만 깎을 뿐입니다.

기존 PPS와 다른 계단식 갱신

기존 변동 수익형 볼트의 PPS는 조회 시점의 free funds와 발행량으로 계산합니다. 전략 수익이 보고된 뒤에는 lastReport와 lockedProfitDegradation에 따른 수익 잠금 해제가 계산에 반영되어, 새 보고 트랜잭션 없이도 조회 시점에 따라 PPS가 변할 수 있습니다. 수익 잠금 해제 기간은 설정에 따라 달라집니다. 이것도 보고 전 전략 수익까지 모두 실시간 확정한다는 의미는 아닙니다. 자세한 내용은 가치 평가·수익 보고·발생주의 회계를 참고하세요. 고정이율 볼트의 Accountant.getRate()는 저장된 숫자를 반환합니다. 시간이 지나거나 사용자가 조회·입금·출금 요청을 해도 그 호출만으로 rate가 증가하지 않습니다. 정기 poke가 성공하는 시점에 경과 기간의 이자가 한 번에 반영됩니다.
확정 환율은 0~24시간 동안 유지되고 24시간과 48시간 checkpoint에서 상승합니다. 예상 환율은 두 checkpoint 사이에도 증가하지만 확정 환율과 구분됩니다.

실선은 확정 환율, 점선은 해당 시각에 poke했을 때의 예상값입니다. 이 그림과 아래 표는 연 2%, 6-decimal 자산, 초기 rate 1,000,000, 24시간 주기의 예시입니다. JPYC에는 더 짧은 갱신 주기를 적용합니다.

이 방식은 사용자별 입금 시각부터 따로 이자를 계산하는 방식이 아닙니다. 입금은 그 시점의 확정 rate를 사용하고 Router가 자동으로 poke하지 않습니다. 다음 checkpoint의 rate는 모든 shares에 공통 적용되므로, 갱신 직전 입금에도 해당 checkpoint의 환율 변화가 적용됩니다. 앱에서 개인 보유 시간에 따라 계산한 이자와 계약의 확정 가치를 동일하게 표시하지 마세요. 새 요청은 safeUpdateAtomicRequest에 공식 Accountant와 discount=0을 전달해 등록합니다. 요청 실행 시점의 확정 rate를 읽어 저장하며, 이 호출 자체가 poke를 실행하지는 않습니다. 취소는 수량 0으로 일반 updateAtomicRequest를 호출합니다. 출금 요청의 atomicPrice도 요청 시 저장한 값입니다. 이후 rate가 올라가도 이미 등록한 요청의 지급액은 자동으로 올라가지 않습니다. 새 환율로 요청하려면 원하지 않는 기존 요청을 취소하고 최신 확정 rate로 다시 등록해야 합니다.

기본 keeper 운영 규칙

정기 환율 갱신 주기는 base 자산의 정밀도에 따라 구분합니다. 아래 주기는 출금 대기 기간이나 체결 보장 시간이 아니며, 환율 갱신과 출금 체결은 별도의 작업입니다. 1시간·24시간 주기는 운영 스케줄이며, 현재 컨트랙트가 그 간격에 맞춰 자동 갱신을 강제하지 않습니다. minInterval은 호출 가능한 최소 간격이고 자동 실행 기능이 아닙니다. 짧은 주기로 운영하려면 Controller의 minInterval과 Accountant의 minimumUpdateDelayInSeconds가 모두 해당 주기의 갱신을 허용해야 합니다. 정밀도가 높아도 이 제한이나 pause·변동 한계를 우회하지는 못합니다. 실제 가격 변경 여부는 시간표가 아니라 성공한 온체인 checkpoint로 확인하세요. 특정 UTC 시각의 실행이나 해당 주기 내 출금 완료를 약속하는 의미도 아닙니다. poke가 Accountant의 변동 한계를 벗어나거나 pause 조건에 걸리면 전체 트랜잭션이 revert하여 rate와 checkpoint 시각도 유지됩니다. 장기간 미실행 뒤 갱신할 때는 누적 변동이 한계를 넘을 수 있으므로 운영팀의 확인이 필요합니다. 성공하지 않은 갱신을 UI에서 반영하지 마세요. 출금 체결은 자동으로 poke하지 않습니다. 새 환율로 출금 테스트를 하려면 poke 성공 → 최신 rate 조회 → 사용자 요청 등록 → 체결 순서로 진행합니다. 이미 열린 요청은 자신의 고정 가격으로 처리될 수 있으며, 갱신을 기다린다는 이유만으로 보호되지는 않습니다.

USDT: 6 decimals와 24시간 주기

확정 환율은 절대 경과 시간의 함수이므로 poke 주기는 실현 APY를 바꾸지 않습니다 — 1시간마다, 24시간마다, 또는 오래 밀린 뒤 한 번에 따라잡아도 모두 같은 곡선 위에 놓입니다. 다음 표는 초기 rate 1_000_000, 목표 APY 2%, 365일, 중간 변경 없음 기준입니다. 어떤 주기든 같은 확정 환율에 도달합니다(여기서는 1_000_000 → 1_019_999). “첫 poke” 열은 계단 크기만 다를 뿐 연간 총합에는 영향이 없습니다. 이 6-decimal 규모에서 정수 절삭은 주기에 따른 손실이 아니라 각 조회 시점의 단위 미만 바닥값일 뿐이며, rate가 최소 1 오르는 시점은 anchor 이후 약 1,593초입니다. rate가 오르지 않아도 성공한 poke는 lastPokeAt을 갱신합니다. 24시간 기본값은 APY 보호가 아니라 가스와 하루 단위 계단을 위한 선택입니다.

JPYC: 18 decimals와 1시간 주기

JPYC는 rate가 약 10^18일 때 각 조회에서 버리는 단위 미만이 1 share당 10^-18 JPYC 미만이라 짧은 주기에서도 사실상 손실이 없습니다. 초기 rate 10^18, 목표 APY 2%에서 정확히 1시간 후 첫 증가량은 2_260_576_447_357 rate 단위, 즉 1 share당 0.000002260576447357 JPYC입니다. 기본 운영 목표는 1시간마다 poke이며, 10분 간격도 정밀도상 가능하지만 호출 제한·가스·운영 비용을 함께 고려합니다. 곡선이 절대 시간에 anchor되어 있으므로 1시간마다, 10분마다, 또는 밀린 뒤 갱신해도 **365일 기준 동일한 약 2.000%**가 됩니다 — 주기에 따라 복리가 달라지거나 목표에서 벗어나지 않습니다. 더 자주 갱신해도 getRate()는 성공한 poke 사이에서는 그대로입니다. JPYC도 실시간 연속 가격이 아니라 1시간 주기를 목표로 하는 계단식 가격이며, 기존 출금 요청의 atomicPrice가 자동으로 바뀌지도 않습니다.

연동 화면과 테스트에서 표시할 것

  • 확정 환율과 마지막 갱신 시각: getRate()와 lastPokeAt()를 함께 표시합니다. 차트도 실제 checkpoint 사이를 수평으로 연결합니다.
  • 현재까지의 예상 환율: previewNextRate()는 예상값으로 별도 표시합니다. 확정 잔액·입금 견적·지급 완료 금액으로 대신 사용하지 않습니다.
  • 다음 정기 갱신 예상 시각: 마지막 checkpoint에 해당 볼트의 운영 주기(USDT 24시간, JPYC 1시간)를 더해 예상값으로 표시할 수 있습니다. 주기는 배포별 운영 설정으로 관리하고, decimals나 minInterval만 보고 자동 실행을 추정하지 마세요. 시간이 됐다는 이유로 확정 rate를 올리지 않습니다. 자동 keeper가 없는 Kairos에는 정기 실행 예정 시각을 표시하지 않습니다.
  • 갱신 지연과 출금 대기: 갱신 주기를 넘겼다면 마지막 성공 시각과 지연 상태를 표시합니다. 앱의 견적 허용 경과 시간은 별도로 정하고, 오래된 rate를 사용할지 운영팀과 확인합니다. 출금은 요청 확인·체결 대기·지급 완료 상태를 구분합니다.
Kairos에서는 mockUSDT 발행·입금·요청·조회는 직접 할 수 있습니다. 환율 갱신 또는 redeem 체결은 테스트넷 연동 안내에 따라 contact@superearn.io로 조율하세요. 메인넷 주소는 정식 배포 후 연동 가이드에 추가됩니다.