Skip to content

Joob 풀 설정(계약 기준)

작업 진행 중

v3.0 차원 모델을 적용했다. 아래 매핑이 갱신본이다. pool_type, lp_issuance_model, collateral_type enum을 쓰던 v2.x 페이로드는 폐기됐다.

SSA 계약(EV3: FJOS/ShardLab, EV4: Henon/Hashed)과 Investment Memo에서 뽑은 풀 생성 파라미터를 v3.0 차원에 매핑했다.

🚧 DPD에서 OJK NAV 상각으로 이어지는 자동화는 보류됐다 (2026-07-01)

대출별 DPD를 받아 OJK 상각 스케줄을 NAV에 적용하려던 v3-13 자동 파이프라인은 만들어지지 않았다. Joob의 대출별 데이터에 막혀 있다(guest API는 집계 DPD 구간만 노출한다. 펀드 라우트는 30/60/90, 마스터 라우트는 30/60과 /risk/nonperforming이고, 대출별 원금이 없다). 현재 report.scheduler.fetch는 DPD·RNI·NPL을 표시용 관측값으로 기록만 하고, loan_writeoffs에는 라이터가 없으며, NAV 상각은 POST /nav-changes수동으로 한다. Writedown & NAV → DPD 자동 상각 참조.

이와 별개로 표시·반입 구간 모델을 고정 30/60/90에서 관할이 정의하는 동적 구간(pool_dpd_buckets 자식 테이블)으로 일반화하는 중이다. 그래야 Joob이 아닌 규제 체계(예: OJK 90/120/180)를 받을 수 있다. v3-59 참조(🚧 구현 예정).

Joob 풀을 만들 때 이 문서를 볼 것

아래 값들은 v3.0 차원 모델에서 pools 테이블 컬럼에 그대로 대응된다. 시나리오 둘을 문서화했다.

  1. Joob 신규 투자자 풀: 신규 투자자가 USDC를 예치하고 Aset이 LP를 민팅하며 파트너 잔여분이 Joob의 fund_wallet으로 간다.
  2. Joob 레거시 보유분(미러 커스터디): 기존 ShardLab/Hashed의 RPS 포지션을 플랫폼에 보여 주되 투자는 할 수 없다. custody_mode = 'MIRROR'(0199)다. ⚠️ 이 시나리오는 0203 전까지 is_display_only = true라고 적혀 있었다. 그 컬럼은 이제 is_showcase이고 v3-40 마케팅 등급만 담는데, 그러면 이 풀이 보여 주려고 존재하는 Fund Data 탭이 숨겨진다.

Guest API 표면: 펀드와 마스터 (문서 "Master Only", 2026-08-19 반영)

guest API는 같은 네 개념을 두 라우트 계열로 제공하고, 풀은 pools.external_entity_type(FUND 기본 | MASTER, 마이그레이션 0194)으로 하나를 고른다. 현재 모든 매핑이 FUND이고 저절로 바뀌는 것은 없다.

FUND(/api/guest/fund/{id})MASTER(/api/guest/master/{id})
발견whoami.fundIdsAuthorizedwhoami.masterIdsAuthorized. 마스터는 당신의 펀드를 활성 서브펀드로 보유하고 있을 때만 나타난다
/summaryfund + snapshot + fxRatemaster(compositionVersion, subfundCount), position(이 LP의 ownershipShare, grossReturn, converted), fxRate.mixed/lpCurrency/fundCurrency가 더해진다
/historysource(chain|ledger)trigger(daily|attach|detach|manual|backfill)와 compositionVersion. UTC 일자당 한 행으로 병합된다
/risk/dpd/{b}30 · 60 · 9030 · 60만. 90은 400을 답한다(dpd-exclude-90)
90일 이상 모집단구간 90/risk/nonperformingpendingWriteOff(장부에 있음) + writtenOff(상각됨)

마스터 라우트가 보고하는 것은 이 풀의 펀드가 아니다. 실제로 마스터 2는 서브펀드 둘을 연결하므로 DPD-30 노출이 719,308,325 EFIDR인데 펀드 1은 1,075,925다. master.totalSubscribed는 17,525,000,000이고 펀드는 8,950,000,000이다. position.ownershipShare(실측 0.2386)는 마스터 AUM에 대한 LP의 몫이고 백분율이 아니라 분수다. 그러므로 풀을 MASTER로 바꾸면 보고 가치가 덮는 범위가 달라지고, 이 풀이 직접 권한을 갖지 않은 서브펀드까지 포함된다. 마이그레이션 기본값이 아니라 의도적인 결정이어야 한다.

실제로 물리는 계약 사항:

  • 모든 응답이 HTTP 200이다. 성공이든 실패든 그렇고, 결과는 본문의 code에 있다. 전송 상태로 분기하면 401/403/400/503을 데이터 없는 성공으로 읽게 된다.
  • snapshot, startDate, endDate, snapshotDate, 그리고 마스터의 fundValue/totalRninullable이다. null은 "기록되지 않음"이지 0이 아니다. 실제 마스터 history는 225일 중 20일이 null 값이다.
  • /history는 호출당 366일로 제한되고, 해당 엔티티의 시작일보다 이른 from을 거부한다. to는 미래일 수 없다(UTC). 셋 다 클램프하지 않고 400을 답한다.
  • 마스터의 DPD와 nonperforming은 일이 아니라 (YYYY-MM) 단위로 키잉된다.
  • 금액은 이미 사람이 읽는 단위로 스케일된 소수 문자열이고 wei가 아니다. 1e18로 더 나눌 필요가 없다.
  • webhook이 없고(폴링만) 클라이언트 캐싱도 없으며, 라우트별 503 킬 스위치가 있는데(masterSummaryEnabled / masterHistoryEnabled / masterDpdEnabled) Retry-After가 없다. 그래서 지수 백오프를 쓴다.

시나리오 1: Joob 신규 투자자 풀 (v3.0 활성 풀)

차원출처비고
name"Joob IDN Private Credit 1"Investment Memo
chain_id1(Ethereum 메인넷)Joob/HenonOneSafe를 통한 메인넷 USDC
fund_walletJoob의 OneSafe 주소Joob 운영입금의 파트너 잔여분이 여기로 간다
is_showcasefalse투자 가능한 풀
partner_idJoob UUID플랫폼 설정
NAV 처리Aset 오라클 Lambdav3-15NAV는 항상 Aset이 판단한다(nav_data_source 차원 없음). DPD→OJK 자동 상각(v3-13)은 보류돼 있고 만들어지지 않았다. 아래 주의 참조. DPD는 표시용으로만 캐시되고 NAV는 POST /nav-changes로 수동 설정한다.
트랜치단독(tranche_group_id 없음)v3-14단일 풀이고 Senior/Junior가 없다. 트랜치 상품은 tranche_group_id를 공유하는 별도 풀들을 쓴다.
maturity_modelFIXED_TERMSSA Schedule 212개월 기간
lockup_days90SSA Schedule 2 §4.23개월 락업
maturity_days365SSA Schedule 2 §4.112개월
target_size500000SSA EV3 + EV4 확인25만 달러(ShardLab) + 25만 달러(Hashed) = 50만 달러
target_size_maxnull아직 확정 상한 없음
min_investment100000Investment Memo10만 달러
apy_rate15SSA §2.3(13~17% 범위)중간값
apy_disclosure"Target 13–17% APY; actual varies with asset utilization, product mix, and NPL"Investment Memo
reserve_bps1000v3.0 기본값Pool 컨트랙트에 보유하는 상환 유동성 reserve(1000 bps = 10%)다. first-loss 버퍼가 아니다(R8). 이 단독 풀의 first-loss는 운용사 equity 버퍼(R6)이고 그 요율은 아직 계약 확인 대기 중이다
penalty_typeYIELD_BASEDSSA §4.2배당 50% 몰수
penalty_rate_bps5000SSA §4.2발생 수익의 50%(5000 bps)
yield_frequency"QUARTERLY"SSA §1.2
yield_trigger(v3-20에서 삭제)SSA §1.1–1.2컬럼이 제거됐다. 수익은 기본이 수동 청구이고, FJO가 선언하면 Aset이 그다음에 depositYield를 실행한다
collateral_description"100% collateralized by Indonesian loan receivables (BCA Wholesale Loans, EWA, etc.)"Investment Memov3.0에서는 자유 텍스트
collateral_ratio100Investment Memo100% 담보
kyc_level_requiredKYC플랫폼 기본값개인 리테일 가능
jurisdiction_whitelist[]모든 관할 허용
accepted_currencies{USDC}JoobEthereum 메인넷의 USDC
redemption_gating_bpsnull회차별 상한 없음
is_pausedfalse
is_emergency_frozenfalse
npl_threshold_days902026-07-24 Joob 통화90 DPD 이상 대출은 부실이지만 장부에 남는다(npl_ratio에 들어간다). 상각은 별개이고 나중이다(아래)
write_off_policy"약 6개월(≈180 DPD)에 상각"2026-07-24 Joob 통화대출이 장부에서 제거돼 실현 손실이 되고 cumulative_loss에 들어간다(Joob의 "상각됨 / 회수 중" 항목). 90 DPD의 NPL 표시와는 별개다. 펀드 가치 기준 참조
lifecycle_statusDRAFTUPCOMINGACTIVE스케줄러배포 이후

수익 계산

Joob의 total_rni는 수수료를 떼기 총액이다. Aset Lambda가 Pool.settleYield()를 위해 net을 계산해야 한다.

net_yield = total_rni
          − admin_fee (연 1%, 분기 지급)
          − performance_fee (15% hurdle 초과 수익의 20%, 만기에)

성과 수수료는 만기에만 발생한다. 분기 분배에는 gross_rni − admin_fee만 쓴다.

펀드 가치 기준과 손실 인식: 2026-07-24 Joob 통화

  • current_fund_value는 현금 수취 기준이고 Aset은 그대로 미러링한다. Joob이 보고하는 펀드 가치는 실제로 수취한 이자만 세고 승인됐지만 미수취인(미수) 이자는 세지 않는다. 승인에서 수취까지 시차가 1~2일 정도라(15% APY에서 하루치 이자, 약 0.04%로 NAV 표시 정밀도 아래다) Aset은 NAV를 원금 + 현금 + 미수 − 손실로 재구성하는 대신 현금 기준 fund_value를 그대로 받는다. accrued_income 요청은 철회했고 그 스냅샷 컬럼(마이그레이션 0068)은 휴면 상태로 둔다. 분기 단위 등 유의미한 발생 불일치가 나타나면 다시 검토한다. Joob은 펀드 가치도 DPD처럼 매일 09:00 EOD 갱신으로 옮기고 있어서 반입이 하루 한 번 이뤄진다.
  • 90에 NPL, 약 180 DPD에 상각이고 둘은 별개다. Joob은 대출을 90 DPD에 부실로 분류하고(장부에 남아 DPD-90 구간에 있으며 npl_ratio에 들어간다) 약 6개월(≈180 DPD)에 상각해 실현 cumulative_loss로 넘긴다(Joob의 별도 "상각됨 / 회수 중" 항목). 그래서 npl_threshold_days = 90write_off_policy ≈ 180합쳐지지 않는다. 실제로 90~180 DPD의 장부상 NPL 구간이 있고, 리스크 배지의 선행 NPL 신호가 정상적으로 작동한다.

Writedown & NAV → NPL과 누적 손실v3-90 참조.

패널티 유형 정리

SSA §4.2의 패널티 산식은 B = 상환일까지 지급된 배당의 50%다. v3.0 용어로는 penalty_type = YIELD_BASED, penalty_rate_bps = 5000(50%)이다.

상환 시점에 배당이 지급된 적이 없으면, SSA 단서에 따라 NPL 손실(청약금의 최대 5%)이 상환 가격에 더해진다. Pool.approveRedemption()을 호출하기 전에 Aset Lambda에서 오프체인으로 처리한다.

시나리오 2: Joob 레거시 보유분(표시 전용)

ShardLab과 Hashed의 기존 RPS 포지션이 Kaia에 있다(0x3f9c024E948Ae2A6554331563D5197f7E6441403). 투자자가 볼 수 있도록 플랫폼에 표시하되 Aset을 통한 입금이나 상환은 되지 않는다.

차원비고
custody_mode'MIRROR'우리를 통한 자본 유출입 경로가 없다. 읽기 모델은 다른 풀과 동일하다
is_showcasefalsev3-40 마케팅 등급은 Performance와 Fund Data를 숨긴다. 이 풀에는 맞지 않는다
chain_id8217(Kaia)기존 RPS 토큰
lp_token_address0x3f9c024E948Ae2A6554331563D5197f7E6441403외부 RPS 컨트랙트
fund_wallet해당 없음입금이 없다
NAV 출처Joob API(읽기 전용 미러)제안이 아니라 기록이다. derive 단계가 attested_off_chain = truenav_history를 쓰고(0201) updateNAV를 보내지 않는다
모든 플로우 차원해당 없음Aset을 통한 입금·상환이 없다

표시 전용 풀은 잔액, NAV, 발생 수익을 보여 준다. 입금이나 상환 CTA는 없다.

풀 생성 페이로드 (v3.0)

json
{
  "name": "Joob IDN Private Credit 1",
  "chain_id": 1,
  "fund_wallet": "0x...joob_onesafe_address...",
  "is_showcase": false,
  "partner_id": "<joob-uuid>",
  "maturity_model": "FIXED_TERM",
  "lockup_days": 90,
  "maturity_days": 365,
  "target_size": 500000,
  "min_investment": 100000,
  "apy_rate": 15,
  "apy_disclosure": "Target 13–17% APY; actual varies with asset utilization, product mix, and NPL",
  "reserve_bps": 1000,
  "penalty_type": "YIELD_BASED",
  "penalty_rate_bps": 5000,
  "yield_frequency": "QUARTERLY",
  "collateral_description": "100% collateralized by Indonesian loan receivables",
  "collateral_ratio": 100,
  "kyc_level_required": "KYC",
  "jurisdiction_whitelist": [],
  "accepted_currencies": ["USDC"],
  "lifecycle_status": "DRAFT"
}

미해결 항목

  • target_size는 50만 달러다(ShardLab 25만 + Hashed 25만 확인). 현재 어드민 패널의 capacity($534,997.01)는 이전 추정치의 EFIDR/USD 환산이 반영된 값이므로, 다음 동기화 때 50만으로 맞춰야 한다.
  • 어드민의 활성 TVL($573K)에는 PM과 백엔드 개발자의 1만 달러 테스트 입금 두 건이 포함돼 있다(실제 투자자 자본이 아니다). 실제 투자자 자본은 50만 달러다.
  • start_dateend_date는 실제 SSA 완료일에 따라 정한다.
  • fund_wallet: 배포 전에 Joob의 OneSafe Ethereum 메인넷 주소를 확인해야 한다.
  • partner_id: 파트너 엔티티를 먼저 생성해야 한다.

v2.x → v3.0 매핑

v2.xv3.0
pool_type: FUND_POOL(fund_walletpartner_id에서 파생)
lp_issuance_model: FUND_ISSUED제거됨. LP는 항상 Aset이 민팅
lp_token_address: 0x3f9c...Kaiacustody_mode = 'MIRROR' 레거시 풀에만 해당
collateral_type: FULLY_COLLATERALIZEDcollateral_description + collateral_ratio: 100
penalty_type: CUSTOMpenalty_type: YIELD_BASED, penalty_rate_bps: 5000
yield_trigger: MANUAL_CLAIMv3-20에서 필드 삭제. 수동 청구가 모든 v3.0 풀의 기본 동작이다
operating_currency: EFIDR / fx_rate: 16730오프체인 Lambda의 관심사이고 pools 테이블에 저장하지 않는다