메인 콘텐츠로 건너뛰기
EarnUSDT는 Super Vault가 뒷받침하는 수익형 USDT(지분 토큰)입니다. USDT를 예치하면 EarnUSDT를 받고, 수익이 쌓일수록 지분 가치가 상승합니다. 통합 방식은 두 가지입니다:
  1. 컨트랙트 통합: 자체 컨트랙트가 SuperEarn에 예치/출금.
  2. 프론트엔드 통합: 사용자의 지갑에서 SuperEarn을 직접 호출.
온체인 쓰기(예치/리딤) 흐름만 다르고, **읽기(GraphQL)**는 동일하며 accountAddress만 바뀝니다.

공통 준비물

필요한 주소(자세한 주소는 스마트컨트랙트 참고):
  • SUPEREARN_ROUTER (ISuperEarnRouter)
  • SUPER_VAULT (EarnUSDT Super Vault, 지분 ERC‑20)
  • USDT (Kaia USDT)
주요 라우터 함수(요약):
  • deposit(superVault, amount, minSharesOut) / deposit(superVault, amount, receiver, minSharesOut)
  • depositWithPermit(...)
  • previewDeposit(superVault, amount) → 예상 지분
  • previewRedeem(superVault, shares) → 예상 자산
  • redeem(superVault, shares, minAssetsOut [, receiver]) → 리딤 요청(쿨다운 후 클레임)
Super Vault의 언더라이잉은 CooldownVault 지분이며 쿨다운 로직은 CooldownVault에 있습니다. 모든 예치·출금은 SuperEarnRouter를 통해야 하고 CooldownVault 직접 호출은 제한(클레임은 퍼미션리스지만 보통 키퍼가 배치 실행). CooldownVault 주소는 Super Vault에서 조회:
address cooldownVault = IVault(SUPER_VAULT).token();

1. 컨트랙트 통합(래퍼 컨트랙트)

사용 사례: CEX/월렛/프로토콜이 자체 컨트랙트에 자금을 보관하고 EarnUSDT를 대신 관리할 때.
ISuperEarnRouter constant ROUTER = ISuperEarnRouter(SUPEREARN_ROUTER);
IERC20            constant USDT   = IERC20(USDT_ADDRESS);
IERC20            constant SHARES = IERC20(SUPER_VAULT); // EarnUSDT

1-1. 예치(USDT → EarnUSDT)

흐름: (1) 사용자 USDT를 컨트랙트로 수취 → (2) 라우터에 approve → (3) deposit 호출 → (4) 지분을 수령(일반적으로 래퍼) → (5) 내부 회계 반영.
function depositIntoSuperVault(uint256 amountUSDT, address user) external {
    USDT.transferFrom(user, address(this), amountUSDT);
    USDT.approve(address(ROUTER), amountUSDT);
    uint256 shares = ROUTER.deposit(SUPER_VAULT, amountUSDT, address(this), 0);
    userShares[user] += shares;
}
// 사전 예상
uint256 expectedShares = ROUTER.previewDeposit(SUPER_VAULT, amountUSDT);

1-2. 출금/리딤(EarnUSDT → USDT)

리딤은 요청 → 쿨다운 → 클레임 2단계입니다(클레임은 보통 키퍼가 배치). 흐름: (1) 내부 지분 차감 → (2) EarnUSDT approve → (3) previewRedeem(옵션) → (4) redeem(...) 호출 → (5) 반환된 requestId를 보관 → (6) 클레임 시점 처리.
function redeemFromSuperVault(uint256 shares, address user) external returns (uint256 requestId) {
    userShares[user] -= shares;
    SHARES.approve(address(ROUTER), shares);
    uint256 minAssetsOut = 0; // 필요 시 슬리피지 설정
    requestId = ROUTER.redeem(SUPER_VAULT, shares, address(this), minAssetsOut);
    userPendingRequest[user] = requestId;
}
// 예상 자산
uint256 expectedAssets = ROUTER.previewRedeem(SUPER_VAULT, shares);

1-3. 쿨다운 후 클레임

키퍼가 주기적으로 클레임하거나, 직접 호출 가능.
function claimFromCooldown(uint256 requestId, address receiver) external {
    (bool ready, uint256 maxOut) = ROUTER.previewClaim(SUPER_VAULT, requestId);
    require(ready, "not claimable");
    (uint256 assets,) = ROUTER.claim(SUPER_VAULT, requestId, receiver, msg.sender);
    // 필요 시 내부 회계 업데이트
}

1-4. 에러·슬리피지

  • minSharesOut, minAssetsOut으로 슬리피지 보호.
  • 커스텀 에러: InsufficientShares, InsufficientAssets, InvalidReceiver, InvalidPrice 등.

2. 프론트엔드 통합(지갑 직호출)

사용 사례: dApp/지갑이 사용자 소유 키로 직접 SuperEarn을 호출할 때.
차이는 승인 주체토큰 보유자가 사용자라는 점뿐이며, 라우터 API는 동일합니다.

2-1. 예치

  1. USDT approve → 2) deposit 호출 → 3) 수령 지분은 사용자 지갑.
    UI에서 previewDeposit 결과를 보여주고 minSharesOut를 설정하세요(EIP‑2612 지원 시 depositWithPermit 가능).

2-2. 리딤

  1. redeem(superVault, shares, receiver, minAssetsOut) 호출 → 2) requestId 저장 → 3) 쿨다운 이후 claim 호출(또는 키퍼가 처리).
    previewRedeem, previewClaim으로 예상 수량·상태를 표시합니다.

2-3. UX 팁

  • 쿨다운 알림: 예상 완료 시간/타임라인을 UI에 노출.
  • 리베이스 아님: EarnUSDT는 지분 가격 모델이므로 잔액은 고정, 가치만 증가.
  • 슬리피지 입력: minSharesOut, minAssetsOut 필수.

3. GraphQL 데이터 조회

쓰기 경로와 무관하게 서브그래프 스키마는 동일하며 accountAddress만 사용자/컨트랙트로 다르게 전달합니다.
자세한 예시는 서브그래프 참고.
주요 조회:
  • EarnUSDT 지분 가격: SuperVault.pricePerShare
  • 사용자 포지션: userPosition (예치/리딤 이력, 대기 요청)
  • 쿨다운/리딤 큐: CooldownVault.pendingWithdrawals, RedemptionRequest
  • 크로스체인 상태: OriginVault.assetsInTransit, RemoteVault.pendingWithdrawals

4. 베스트 프랙티스

  • 모든 예치/리딤은 라우터 경유: CooldownVault 직접 호출 금지.
  • 쿨다운 고려: 리딤은 두 단계이므로 requestId 추적, 완료 시점 안내.
  • 슬리피지 보호: 사용자 입력으로 minSharesOut, minAssetsOut 설정.
  • 가치 계산: EarnUSDT는 리베이스되지 않으므로 pricePerShare로 환산.
  • 보수적 표시: 크로스체인 회계 특성상 짧은 기간 수치가 보수적으로 보일 수 있음.

5. 참고 링크