WHITEPAPER · TECHNICAL SPECIFICATION

실내외 날씨 데이터 생태계와
온체인 데이터 거래 인프라

전국 단위 IoT 날씨 측정망 — 실내(IAQ)와 실외(OAQ) 두 계층 — 으로 생활 환경 데이터를 수집해 가전 제조사의 R&D·마케팅과 환경 서비스에 공급하고, 기여자에게는 온체인 보상을 돌려주는 선순환 생태계. Part 1은 사업 백서, Part 2 이후는 이를 구현하는 XRPL DePIN · x402 기술 사양이다.

IAQ PM · CO₂ · TVOC · 온습도 OAQ PM · O₃ · NO₂ · SO₂ · CO XLS-20 기기 라이선스 IOU Wellbian(WLBN) 보상 토큰 XLS-30 AMM 유동성 HTTP 402 데이터 API 과금

백서 1 개요

현대인은 하루의 90% 이상을 실내에서 생활하며, 실내 날씨과 기후 환경은 개인의 건강과 직결된다. 그러나 대부분의 실내 공조 가전(공기청정기, 제습기, 에어컨 등)은 출하 시 설정된 표준 알고리즘에 의존해 작동한다.

본 프로젝트는 전국 단위의 IoT 실내 날씨 측정망을 통해 사용자의 실제 거주 환경 데이터를 실시간으로 수집하고, 이를 가전 제조사에 제공하여 기술 발전과 초개인화 마케팅을 지원하는 '실내 기후 데이터 플랫폼 생태계'를 구축하는 것을 목적으로 한다.

90%+
현대인의 하루 중 실내 체류 비중
0
제조사가 확보한 출하 후 실거주 환경 데이터
6+7종
노드가 상시 측정하는 지표 — 실내 IAQ 6종 · 실외 OAQ 7종
문서 구성

Part 1(백서)은 생태계의 사업 구조를 기술한다. Part 2~3(기술 개요 · 날씨 데이터 사양)과 Step 1~6 · 운영 섹션은 이 구조를 XRPL 위에 구현하기 위한 데이터 스키마, 라이선스·보상 설계, 비식별화 파이프라인, API 과금 프로토콜, 그리고 단계별 구현 지침을 다룬다. 백서의 각 장은 대응하는 기술 섹션으로 연결된다.

백서 2 문제 제기 및 시장의 한계

Problem 01
제조사의 실데이터 부재
가전 제조사는 제품 판매 이후 실제 소비자의 가정 내 날씨 변화, 계절별 기기 사용 패턴, 주거 환경(평형, 위치, 채광)에 따른 공조 효율 데이터를 확보하기 어렵다.
Problem 02
획일화된 제품 개발 및 마케팅
지역별·주거 형태별로 요구되는 제습량이나 공기 정화 능력이 다름에도 불구하고, 천편일률적인 스펙 경쟁과 광범위한 마케팅에 의존하고 있다.
데이터 공백이 만드는 비용

제조사는 실환경 데이터가 없어 최악 조건 기준으로 과설계하거나, 반대로 특정 주거 형태에서 성능이 미달하는 제품을 출하한다. 마케팅 측면에서는 "제습이 필요한 가구"를 식별할 수단이 없어 전 고객 대상 브로드캐스트에 의존하며, 이는 곧 리드 획득 단가 상승으로 이어진다. 본 생태계는 이 두 공백을 각각 R&D 데이터와 코호트 API로 메운다.

백서 3 플랫폼 생태계 구조

본 생태계는 세 주체로 구성되며, 데이터의 수집–정제–활용이 선순환을 이룬다.

DATA PROVIDER 데이터 기여자 가정 · 사무실 · 상업시설 IAQ 측정 IoT 디바이스 설치 기여도 기반 리워드 획득 PLATFORM HUB 플랫폼 허브 원시 데이터 온체인 무결성 보장 개인정보 비식별화 처리 메타데이터 가공 · 품질 평가 XRPL + 클라우드 인프라 DATA CONSUMER 가전 제조사 에어컨 · 제습기 · 공기청정기 환기 시스템 · 스마트홈 플랫폼 구매 또는 구독형 API 원시 측정값 정제 메타데이터 데이터 이용료 기여 보상 실선 = 데이터 흐름 · 점선 = 가치 흐름 보상은 가전 구매 할인 · 필터 구독 결제로 재유입되어 생태계 내에서 순환
Fig 0. 3주체 선순환 구조

3.1 데이터 기여자 (Data Provider)

  • 가정·사무실·상업시설에 실내(IAQ) 측정기를, 옥상·가로변·학교 등에 실외(OAQ) 측정기를 설치한 사용자.
  • 실시간 환경 데이터를 플랫폼에 제공하고, 기여도에 따라 리워드(보상)를 획득한다.

3.2 플랫폼 허브 (Data Platform Hub)

  • 수집된 원시 데이터(Raw Data)를 블록체인 및 클라우드 인프라를 통해 위변조 없이 안전하게 저장한다.
  • 개인정보를 비식별화(익명화) 처리한 후, 제조사가 활용할 수 있는 형태의 메타데이터로 가공한다.

3.3 데이터 수요자 (Appliance Manufacturers)

  • 에어컨, 제습기, 공기청정기, 환기 시스템 등을 제조하는 기업.
  • 정제된 데이터를 구매하거나 구독형 API 형태로 제공받아 R&D 및 마케팅에 활용한다.
기술 대응

기여자 자격 증명 → XLS-20 라이선스 NFT · 원시 데이터 무결성 → 오라클 배치 머클루트 · 비식별화 → 5단계 파이프라인 · 수요자 과금 → x402 데이터 상품.

백서 4 수집 데이터 및 핵심 활용 방안

수집된 데이터는 수요기업의 목적에 맞게 기술적 데이터(R&D)와 마케팅 데이터(CRM/Sales)로 분류되어 제공된다.

4.1 실내(IAQ) 지표 — 가전 R&D · 마케팅

수집 지표연관 가전제품기술적 활용 방안 (R&D)마케팅 활용 방안 (Sales)
온·습도 (상대습도 · 절대습도 환산)제습기, 에어컨 주거 형태별 최적 제습 알고리즘 개발, 결로 방지 예측 모델링 구축 장마철 고습도 유지 가구 타겟팅 제습기 프로모션, 건조 가구 대상 가습기 교체 시기 알림
미세먼지·초미세먼지 (PM10 / PM2.5)공기청정기, 청소기 필터 수명 예측 모델 고도화, 오염도 급증 시 팬 속도 자동 제어 로직 설계 대기오염도와 실내 오염도가 비례하는 가구 추출, 대용량 프리미엄 공기청정기 타겟 광고
이산화탄소 (CO₂)환기 청정기 (전열교환기) 밀폐 공간 내 CO2 농도 변화율 기반 AI 환기 시점 예측 기술 개발 환기 부족 다중이용시설 및 영유아 가구 대상 스마트 환기 시스템 도입 제안
TVOC (총휘발성유기화합물)새집증후군 제거기 건축 자재별 배출 가스 패턴 분석, 센서 감도 최적화 신축 아파트 입주 및 인테리어 시공 가구 대상 특화 필터 마케팅
온도 / 체감온도에어컨, 난방기기체감 기반 목표온도 제어 로직 설계, 계절별 냉난방 부하 프로파일 구축혹서·혹한 체감 구간이 지속되는 가구 대상 냉난방 기기 교체 제안

4.2 실외(OAQ) 지표 — 환경 서비스 · 외기 연동 제어

실외 지표는 수요자 구성이 다르다. 실내 지표가 가전 제조사 한 축이라면, 실외는 지자체·환경 서비스가 1차 수요자이고 가전 제조사는 "외기 조건에 반응하는 제어"라는 형태로 2차 수요자가 된다.

수집 지표주 활용 주체기술적 활용 방안 (R&D)서비스 활용 방안
미세먼지·초미세먼지 (PM10 / PM2.5)가전 제조사 · 지자체 격자별 침투율(I/O ratio) 산출, 외기 연동 선제 급기·차단 제어 알고리즘 개발 외기 악화 예보 기반 창문 닫기·공기청정기 예약 가동 알림
오존 (O₃)지자체 · 보건 광화학 생성 패턴 분석, 환기 금지 시간대 판정 모델 구축 오존주의보 구간 환기 억제 권고 — 환기형 청정기에 제어 신호 전달
이산화질소 (NO₂)지자체 · 교통 도로변 배출 기여도 분리, 가로변 노출 지도 작성 통학로·보행로 저노출 경로 안내
아황산가스 (SO₂)산업단지 · 환경 산업 배출원 영향 반경 추정, 풍향별 확산 모델 검증 인근 주거지 대상 배출 이벤트 알림
일산화탄소 (CO)지자체 · 안전 교통 정체 구간 축적 패턴 분석 밀집 구역 단기 노출 경보
풍속 · 풍향전 주체 오염물질 이동·확산 방향 추정, 배출원 역추적 인접 격자로부터의 오염 유입 예측
두 표를 잇는 값은 PM2.5다

4.1과 4.2에서 PM2.5만 양쪽에 등장한다. 같은 물질을 같은 광산란 방식으로 실내외에서 동시에 측정하기 때문이다. 나머지 지표는 한쪽에만 존재하므로 단독 상품이지만, PM2.5는 두 관측망을 곱해 침투율이라는 파생 지표를 만든다. 이 파생 지표가 Phase 3에서 가장 비싼 데이터가 되는 이유이며, 실외를 기상 관측으로 두었다면 존재하지 않았을 값이다.

마케팅 활용의 전제 조건

위 표의 마케팅 항목은 모두 "특정 조건을 만족하는 가구를 추출"하는 형태다. 이는 개인을 직접 식별하지 않고 코호트 단위 카운트만 반환하는 API로 구현해야 하며, 실제 광고 도달은 플랫폼이 중개하고 제조사에는 대상자 목록을 넘기지 않는다. 구체적 설계는 비식별화 파이프라인과 코호트 API 절에서 다룬다.

백서 5 데이터 보상 메커니즘

광범위하고 유의미한 데이터를 지속적으로 확보하려면 사용자의 자발적인 IoT 디바이스 운영이 필수적이다.

Earn
기여 보상
24시간 끊김 없이 양질의 데이터를 전송하는 노드(측정기)에 매일(에폭 = 1일, KST 자정 기준) 정량으로 Wellbian 토큰(WLBN) 리워드를 지급한다. 일일 리워드는 기본 7개 × 0.78^(단계−1) × 품질 등급(0~1.2)으로 수량만 정의되며, 가치는 정의하지 않는다.
Spend
생태계 소비
획득한 보상은 가전제품 구매 할인, 필터 교체 구독 서비스 결제, 혹은 플랫폼 내 제휴 마켓에서 사용 가능하도록 설계하여 이탈을 방지한다.
"양질의 데이터"를 정량화해야 하는 이유

제출 건수에만 비례해 보상하면 센서를 방치하거나 조작해 건수만 채우는 것이 최적 전략이 된다. 본 사양은 전송률 게이트와 가동률·이상치율·인근 노드 상관·캘리브레이션 경과일을 합산한 품질 점수(Quality Score)로 품질 등급(0 · 1.0 · 1.2)을 매기고, 에폭 예산을 고정한 뒤 등급별 정량으로 지급하며 미지급분은 재분배하거나 소각한다. 방출 총량은 단계 게이트와 10단계 누적 상한(26.65억개)으로 사전 확정된다.

법적 고지

WLBN과 라이선스 NFT는 회사 지분·배당·이익분배·원리금 상환을 청구할 권리를 표창하지 않는다. 보상은 검증된 데이터 기여의 품질에 따라 배분되는 유틸리티 토큰이며, 지급 수량·가치·환금성은 보장되지 않는다. 본 문서의 모든 수치는 설계·검증용 가정이며 어떤 경우에도 수익에 대한 예측이나 약속이 아니다. 기기 구매는 데이터 수집 장비의 구매이며 투자 계약이 아니다.

백서 6 비즈니스 수익 모델

Revenue 01
B2B 데이터 API 구독료
가전 제조사 및 스마트홈 플랫폼(SmartThings, ThinQ 등)을 대상으로 지역별 실내 날씨 통계 API를 월간/연간 구독 형태로 제공.
Revenue 02
타겟팅 광고 수수료
가전 제조사가 플랫폼의 데이터를 기반으로 특정 환경 요건을 갖춘 사용자에게 맞춤형 제품을 광고할 때 발생하는 리드(Lead) 당 수수료 부과.
Revenue 03
인사이트 리포트 판매
건설사 및 인테리어 기업을 대상으로 평면 및 자재에 따른 실내 공조 효율성 분석 리포트 판매.

세 수익원은 모두 x402 데이터 상품으로 매핑된다 — 구독료는 선불 크레딧, 리드 수수료는 코호트 API 건당 과금, 리포트는 LLM 추론 건당 과금이다. 과금 수단이 하나의 프로토콜로 통일되므로 별도 빌링 시스템 없이 정산이 가능하다. 여기에 수요자가 먼저 금액을 예치하고 데이터를 요청하는 역방향 채널로 데이터 바운티가 더해진다.

백서 6+ 데이터 바운티 — 생명을 연장하는 데이터

현대인은 하루의 약 90%를 실내에서 보내며, WHO는 실내 공기 오염에 따른 조기 사망을 연간 수백만 명 규모로 추산한다. 실내 날씨 측정은 편의 기능이 아니라 호흡기·심혈관 질환의 예방이 시작되는 지점이다. 노드 운영자가 매일 쌓는 1분 단위 데이터는 "측정되지 않아 개입되지 못했던" 생활 공간을 관리 가능한 공간으로 바꾸는 공중보건 인프라이며, 본 생태계의 보상은 단순한 채굴 개념이 아니라 그 기여에 대한 대가다. 데이터 바운티는 이 기여를 필요로 하는 곳과 데이터 제공자를 직접 연결하는 장치다.

Bounty 01
선입금 에스크로
데이터가 필요한 기업·기관(가전 제조사, 공조·환기 솔루션사, 연구기관, 지자체)이 XRP 또는 RLUSD를 먼저 예치하고 바운티를 개설한다. 온체인 입금이 확인된 바운티만 노드에게 공개되어 지급 불이행 위험을 구조적으로 낮춘다.
Bounty 02
배타적 데이터 사용권
누구나 구매 가능한 공개 API와 달리, 예치를 마치고 바운티에 가입한 스폰서에게만 전용 접근 키가 1회 발급되며 이 키로만 참여 노드들의 바운티 기간 데이터에 접근할 수 있다. 조회 범위는 동의한 참여 노드 × 바운티 기간 × 노드별 참여 시점 이후로 한정되고, 참여 노드는 기본 에폭 보상 위에 바운티 보상을 추가로 수령한다.
Bounty 03
청정 솔루션 프로모션
참여 시 마케팅 수신에 동의(옵트인)한 노드에게는 스폰서의 실내 날씨(날씨) 개선 솔루션(공기청정기·환기 시스템·필터 구독 등) 프로모션이 제공될 수 있다. 동의는 바운티 단위이며 언제든 철회 가능하다.
바운티가 완성하는 수익 순환

백서 6의 세 수익원이 플랫폼이 만든 상품을 판매하는 순방향 흐름이라면, 데이터 바운티는 수요자가 금액을 걸고 데이터를 요청하는 역방향 흐름이며, 그 대가는 단순 API 호출권이 아니라 가입 스폰서에게만 귀속되는 기간 한정 데이터 사용권이다. 스폰서 예치금은 XRPL 메인넷 온체인에서 투명하게 확인되고, 바운티 기간 종료 시 참여 기여도에 따라 정산된다. 측정하는 사람은 더 벌고, 필요한 곳은 검증된 실측 데이터를 얻고, 그 위에서 청정 솔루션이 필요한 가정에 정확히 닿는다 — 데이터가 건강 개입으로 이어지는 완결 구조다. 바운티 보드는 실행 플랫폼 wellbian.io/data에서 운영된다.

백서 7 향후 발전 로드맵

PHASE 1
초기 IoT 인프라 구축 및 얼리 어답터 대상 데이터 수집망 확보 — 완료 (2026-08 XRPL 메인넷 가동)
디바이스 라이선스 NFT 발급 체계, 텔레메트리 수집 파이프라인, 품질 점수 기반 보상 엔진을 XRPL 메인넷에서 가동 중. 기술 사양의 Step 1~4에 해당한다.
PHASE 2
메이저 가전 제조사와의 MOU 체결 및 데이터 API 상용 연동 (진행 중)
비식별화 파이프라인 검증, 코호트 API·집계 API 개설, x402 과금 게이트웨이(RLUSD) 연동. Step 5~6 및 B2B 상품 설계에 해당한다.
PHASE 3
실외 OAQ 관측망과 결합해 실내외 연동 스마트홈 제어 솔루션으로 확장
같은 격자의 실외 날씨과 실내 날씨을 함께 확보해 예측 기반 선제 공조 제어를 제공. 두 관측망은 동일한 라이선스·보상·과금 인프라를 공유하며 NFTokenTaxon으로만 구분된다.
Phase 3의 기술적 의미

실외 OAQ는 선행 지표, 실내 IAQ는 결과 지표다. 특히 PM2.5는 두 관측망이 같은 물질을 측정하므로, 같은 격자에서 두 시계열을 함께 확보하면 "외기 PM이 X일 때 이 주거 형태의 실내 PM이 Y로 변한다"는 침투율(I/O ratio) 전이 함수를 직접 학습할 수 있다. 이는 실외를 기상 관측으로 두었을 때는 얻을 수 없는 값이며, 제조사가 살 수 있는 가장 비싼 형태의 데이터가 된다. 본 기술 사양이 두 관측망을 하나의 원장·하나의 과금 체계 위에 올린 이유다.

기술 개요 플랫폼 개요

백서의 3주체 구조를 온체인으로 구현하면 두 개의 경제 루프가 하나의 원장 위에서 연결된다. 공급 측은 IAQ 노드가 실내 환경 데이터를 올리고 토큰 보상을 받는 DePIN 루프이고, 수요 측은 가전 제조사와 AI 에이전트가 데이터 API를 호출하며 토큰을 지불하는 x402 루프다. 두 루프는 동일 원장의 AMM 풀을 통해 유동성이 연결된다.

Supply Loop · DePIN
데이터를 올리면 토큰을 받는다
인가된 IoT 기기(NFT 라이선스 보유)가 IAQ 측정값을 전송하면, 품질 점수를 산출해 1일(KST) 에폭 단위로 적립하고, 24시간 홀드 후 Hot Wallet(운영 지갑)이 WLBN을 지급한다. 노드 확산 = 관측망 밀도 증가.
Demand Loop · x402
데이터를 쓰면 토큰을 낸다
제조사·AI 에이전트가 집계·코호트·리포트 API를 호출하면 HTTP 402로 결제를 요구하고, 온체인 트랜잭션 해시 검증 후 응답을 반환한다. 호출량 = 토큰 수요.

두 관측망, 하나의 인프라

실내 IAQ 관측망과 실외 OAQ 관측망은 센서 구성과 데이터 스키마만 다를 뿐, 라이선스 발급·보상 지급·데이터 과금 경로는 완전히 동일하다. 구현상으로는 NFTokenTaxon과 텔레메트리 스키마 버전으로만 구분되며, 지갑·토큰·AMM·x402 게이트웨이는 단일 인스턴스를 공유한다.

구분실내 IAQ 관측망실외 OAQ 관측망
측정 지표PM2.5/10, CO₂(NDIR), TVOC, 온·습도(체감온도 유도)PM2.5/10, O₃, NO₂, SO₂, CO, 온·습도, 풍속·풍향
설치 주체일반 가구 · 사무실 · 상업시설건물 옥상 · 가로변 · 학교 · 산업단지 인근
NFTokenTaxon30262026
주 수요자가전 제조사 · 스마트홈 플랫폼지자체 · 환경 서비스 · AI 에이전트
공유 인프라Issuer/Hot 지갑 · WLBN·RLUSD · AMM 풀 · x402 게이트웨이 · 소각 배치동일 (단일 인스턴스 공유)

메인넷에서 검증된 5가지 명제

#명제검증 수단XRPL 기능
1기기 신원을 온체인으로 위조 불가능하게 증명할 수 있다 verifyDeviceLicense() 온체인 조회XLS-20 NFT
2데이터 기여에 대한 마이크로 보상을 무인 자동화할 수 있다 에폭 정산 → 배치 Payment (24h 클레임 홀드)Issued Asset (IOU)
3토큰과 스테이블코인 간 스왑이 원장 내에서 가능하다 Mainnet AMM 풀에서 RLUSD ↔ WLBN 실거래 스왑XLS-30 AMM
4AI 에이전트가 사람 개입 없이 API 사용료를 결제할 수 있다 402 응답 → 결제 → 재요청 → 200Payment + tx 조회
5개인을 식별하지 않고도 제조사가 쓸 만한 코호트를 추출할 수 있다 k-익명성 미달 시 응답 거부, 카운트만 반환오프체인 (온체인 미기록)
왜 XRPL인가

마이크로페이먼트가 성립하려면 수수료가 결제 금액보다 압도적으로 작아야 한다. XRPL의 기본 트랜잭션 비용은 10 drops(0.00001 XRP)이고 확정(finality)까지 3~5초다. 0.002 RLUSD 단위의 집계 API 과금과, 수만 개 노드에 대한 에폭 배치 보상 지급이 수수료에 잡아먹히지 않고 성립하는 이유이며, NFT·IOU·AMM이 스마트컨트랙트 없이 네이티브 트랜잭션 타입으로 제공되어 감사 대상 코드 표면이 작아 운영 리스크가 낮다.

기술 개요 시스템 아키텍처

오프체인 3계층(기기 · 게이트웨이 · 소비자)과 온체인 1계층(XRPL 원장)으로 구성된다.

PHYSICAL BACKEND CONSUMER LEDGER 실내 IAQ 노드 PM·CO₂·TVOC·온습도 실외 OAQ 노드 PM·O₃·NO₂·SO₂·CO Device Wallet NFT 라이선스 보유 DePIN Oracle API GET api.wellbianlabs.io/v1/c license → quality → reward x402 Gateway /api/data/* · /api/v1/* 402 → verify tx → 200 집계 · 코호트 · LLM 비식별화 · k-익명성 게이트 인사이트 리포트 생성 가전 제조사 · AI Agent x402 자율 결제 클라이언트 스마트홈 플랫폼 RLUSD → WLBN 스왑 Hot Wallet(운영 지갑) rhTTtx8…web1 — 보상 지급 · 결제 수취 · 소각 배치 XRP LEDGER XLS-20 NFT 기기 라이선스 WLBN / RLUSD Issued Asset + TrustLine XLS-30 AMM WLBN ↔ RLUSD 풀 Issuer (Cold) 발행 · 소각 수취 기기 서명 verify NFT reward / burn swap payment
Fig 1. 4계층 아키텍처 — 파란선 = DePIN 공급 루프, 녹색선 = x402 수요 루프

지갑 역할 분리

지갑역할키 보관주요 트랜잭션
Issuer (Cold)
rDJz8WJhsKgydqJzSZXMpsJot3eRmSkR5
Wellbian(WLBN) 발행 주체, NFT 발행자, 소각 수취처. RLUSD는 Ripple 발행(rMxCKbEDwqr76QuheSUMdEGf4B9xJ8m5De)을 TrustLine으로 수용. 오프라인 / HSM 가정AccountSet, NFTokenMint, 최초 Payment
Hot Wallet(운영 지갑)
rhTTtx8YyKzcmPDsoroYXuHdGMThrnweb1
에폭 보상 지급, x402 결제 수취, 소각 배치 실행 서버 환경변수 (KMS 권장)Payment, AMMDeposit
IoT Device (ARC-600DA)기기 지갑, 라이선스 NFT 보유자 기기 시큐어 엘리먼트 가정TrustSet, NFTokenAcceptOffer
AI Agent · 제조사 클라이언트x402 클라이언트, API 사용료 지불자 에이전트 로컬TrustSet, Payment
Cold / Hot 분리 원칙

Issuer 키가 유출되면 무제한 발행이 가능하므로, 런타임 서버는 절대 Issuer 시드를 로드하지 않는다. 발행은 1회성 부트스트랩 스크립트에서만 수행하고, 이후 모든 상시 트랜잭션은 Hot Wallet(운영 지갑)이 담당한다. 이 경계는 코드 레벨(모듈 분리 + 별도 키 주입)로 강제되며, 운영 서버는 Issuer 시드를 로드하지 않는다.

기술 개요 기술 스택 & 네트워크

Language
TypeScript / Node.js 20+
Vercel Runtime에서 실행된다. 본 문서는 TS 기준으로 기술한다.
XRPL SDK
xrpl.js v3+
WebSocket Client, Wallet, autofill/sign/submitAndWait 사용.
API
Next.js 15 App Router (Vercel)
x402 게이트웨이는 Route Handler 미들웨어로 구현. 배치·에폭 정산은 Vercel Cron.

네트워크 파라미터

항목값비고
WebSocketwss://xrplcluster.comMainnet 공용 클러스터 노드
JSON-RPChttps://xrplcluster.com단발 조회용
계정 활성화Payment (외부 입금)계정 활성화 · Base Reserve 이상 XRP 사전 입금(Faucet 없음)
Explorerlivenet.xrpl.orgtx / account 시각 검증
Base Reserve1 XRPMainnet 기준 계정 유지 최소 잔액
Owner Reserve0.2 XRP / 오브젝트TrustLine · NFT Offer · AMM 등 각각 차감
Finality3~5초비동기 대기 및 폴링 설계 필수

통화 코드 인코딩

XRPL의 currency 필드는 3자리 ASCII이거나 40자리 hex(160-bit)여야 한다. WLBN·RLUSD 모두 3자를 초과하므로 hex 인코딩이 필수다. 이 값을 상수로 고정해두지 않으면 TrustSet과 Payment의 통화가 불일치해 tecNO_LINE / tecPATH_DRY가 발생한다.

src/config/currency.tstypescript

// ASCII → 20-byte hex (right-padded with zeros)
export const toCurrencyHex = (code: string): string => {
  if (code.length <= 3) return code;              // 3 chars or fewer pass through
  return Buffer.from(code, 'ascii').toString('hex').toUpperCase().padEnd(40, '0');
};

export const WLBN  = toCurrencyHex('WLBN');   // 574C424E00000000000000000000000000000000
export const RLUSD = toCurrencyHex('RLUSD');  // 524C555344000000000000000000000000000000

환경 변수

.env.exampledotenv

XRPL_ENDPOINT=wss://xrplcluster.com
XRPL_NETWORK=mainnet

# Cold — bootstrap script only. Never inject into the runtime server
ISSUER_SEED=sEd..............................

# Hot — API server runtime
HOT_SEED=sEd..............................
HOT_WALLET_ADDRESS=r..............................

# Counterparties
TREASURY_ADDRESS=rPZFY2yLgqjmBrxtxWHXnB1doBt7gu7xin
RLUSD_ISSUER_ADDRESS=rMxCKbEDwqr76QuheSUMdEGf4B9xJ8m5De

# Pricing policy (RLUSD)
X402_PRICE_AGGREGATE_RLUSD=0.002
X402_PRICE_COHORT_RLUSD=0.05
X402_PRICE_REPORT_RLUSD=0.5
X402_DEST_TAG=402001

# Reward policy
REWARD_BASE_DAILY_WLBN=7
PHASE_DECAY=0.78
EXCELLENT_BONUS_WLBN=1.4
NODE_DAILY_CAP_WLBN=10.5
BUDGET_PER_NODE_WLBN=7.14
CLAIM_HOLD_HOURS=24
BURN_RATIO=0.5
시드 취급

.env는 반드시 .gitignore에 등록한다. 운영(Mainnet) 시드를 커밋하면 저장소가 노출되는 순간 서명 권한이 유출된다. 운영 전환 시에는 .env 대신 KMS/Vault에서 런타임 주입하고, 서명은 Hot Wallet 키에 한정한다.

기술 개요 모듈 구조

각 XRPL 기능을 독립 모듈로 분리해 단계별 테스트와 교체가 가능하도록 한다.

src/ ├─ config/ │ ├─ env.ts # env loading + validation (zod) │ └─ currency.ts # WLBN / RLUSD hex constants ├─ xrpl/ │ ├─ client.ts # Client singleton · reconnect · graceful shutdown │ ├─ wallet.ts # Step 1 — wallet create / load / fund │ ├─ token.ts # Step 2 — AccountSet · TrustSet · IOU Payment │ ├─ nft.ts # Step 3 — Mint / Offer / Accept / verifyDeviceLicense │ ├─ amm.ts # Step 5 — AMMCreate · AMMDeposit · path swap │ └─ submit.ts # shared autofill→sign→submitAndWait + tes check ├─ services/ │ ├─ oracle.ts # Step 4 — telemetry intake · validation · reward │ ├─ x402.ts # Step 6 — 402 challenge · tx verification │ ├─ llm.ts # IAQ insight report generation (0.5 RLUSD) │ └─ burn.ts # Step 6 — 50% burn batch job ├─ api/ │ ├─ route.ingest.ts # GET /v1/c?<base64> (Supabase Edge Function proxy) │ ├─ route.data.ts # GET /api/data/aggregates (x402) │ └─ middleware.x402.ts# 402 gate middleware ├─ scripts/ │ ├─ 01-bootstrap-wallets.ts │ ├─ 02-issue-tokens.ts │ ├─ 03-mint-license.ts │ ├─ 05-create-amm.ts │ └─ x402-client.ts # reference x402 client └─ server.ts

공통 제출 헬퍼

모든 트랜잭션이 tesSUCCESS인지, 그리고 validated: true인지 한 곳에서 검증한다. 이 래퍼를 강제하지 않으면 "제출은 됐지만 원장에 반영되지 않은" 상태를 성공으로 오인하게 된다.

src/xrpl/submit.tstypescript

import { Client, Wallet, SubmittableTransaction, TxResponse } from 'xrpl';

export class TxError extends Error {
  constructor(public code: string, public hash?: string) {
    super(`XRPL tx failed: ${code}${hash ? ` (${hash})` : ''}`);
  }
}

/** autofill → sign → submitAndWait → verify tesSUCCESS + validated */
export async function submit(
  client: Client, wallet: Wallet, tx: SubmittableTransaction,
): Promise<TxResponse> {
  const prepared = await client.autofill(tx);
  const signed = wallet.sign(prepared);
  const res = await client.submitAndWait(signed.tx_blob);

  const meta = res.result.meta;
  const code = typeof meta === 'object' && meta !== null
    ? (meta as { TransactionResult: string }).TransactionResult
    : 'UNKNOWN';

  if (code !== 'tesSUCCESS') throw new TxError(code, res.result.hash);
  if (res.result.validated !== true) throw new TxError('NOT_VALIDATED', res.result.hash);
  return res;
}

날씨 데이터 사양 센서 · 텔레메트리 스키마

백서 4장의 지표를 실제 노드가 측정 가능한 물리량과 페이로드 형식으로 확정한다. 실내(IAQ)와 실외(OAQ) 스키마는 지표 목록만 다르고 동일한 봉투(envelope) 구조를 공유하며, 각각 버전 필드를 갖는다.

측정 지표 사양

지표필드센서 방식측정 범위목표 정확도
미세먼지pm25 pm10 광산란 (PMS)0 ~ 1000 µg/m³±10% (≥100 구간)
이산화탄소co2 NDIR400 ~ 5000 ppm±(50 ppm + 3%)
총휘발성유기화합물tvoc MOX 반도체식0 ~ 60000 ppb상대 지수 (절대값 비보증)
온도tempC 디지털 온습도 복합−10 ~ 60 °C±0.3 °C
상대습도rh 정전용량식0 ~ 100 %RH±2 %RH
체감온도 유도feelsLikeC 온도 + 상대습도에서 계산−10 ~ 60 °C입력 오차 전파
절대습도 유도ah 온도 + 상대습도에서 계산0 ~ 60 g/m³입력 오차 전파

실외 OAQ 센서 사양

실외 노드는 대기환경기준 물질을 측정한다. PM2.5·PM10은 실내 노드와 같은 물질을 같은 방식으로 측정하므로, 같은 격자의 실내외 값을 직접 비교해 침투율(I/O ratio)을 산출할 수 있다.

지표필드센서 방식측정 범위tier
미세먼지pm25 pm10광산란 (PMS)0 ~ 1000 µg/m³oaq-standard
오존o3전기화학식0 ~ 500 ppboaq-standard
이산화질소no2전기화학식0 ~ 500 ppboaq-standard
온도 · 상대습도tempC rh디지털 복합−30 ~ 60 °C / 0 ~ 100 %RHoaq-standard
아황산가스so2전기화학식0 ~ 200 ppboaq-pro
일산화탄소co전기화학식0 ~ 50 ppmoaq-pro
풍속 · 풍향wind windDir초음파식0 ~ 60 m/s / 0 ~ 360°oaq-pro
실외 센서는 보정 부담이 훨씬 크다

전기화학식 가스 센서(O₃·NO₂·SO₂·CO)는 온도·습도에 강하게 교차 반응하고 수명이 1~2년으로 짧다. 실내 노드보다 드리프트가 빠르므로 품질 점수의 보정(calibration, 15점)·상관(correlation, 20점) 가중을 실외에 더 크게 적용하고, 인근 국가 측정망(에어코리아) 값과의 상관을 보정 계수 산출에 함께 쓴다.

실내 1단계 기본 리워드는 일 7개(정상 등급)이며, 실외 라인은 기존 홀더에게 우선 제안된다. 실외 리워드 수량은 실외 모델 출시 시 공표한다.

절대습도는 왜 유도해야 하는가

백서 4장이 첫 번째 지표로 절대습도를 명시한 것은 정확한 선택이다. 상대습도는 온도 종속량이라 제습 부하 계산에 직접 쓸 수 없다. 같은 60 %RH라도 20 °C에서는 약 10.3 g/m³, 30 °C에서는 약 18.2 g/m³로 실제 수분량이 1.8배 차이난다. 제습기가 뽑아내야 할 물의 양은 후자가 압도적으로 많다. 따라서 노드는 상대습도를 전송하되, 서버는 수신 즉시 절대습도를 유도해 저장한다.

src/services/iaq/humidity.tstypescript

/**
 * Absolute humidity (g/m³) via the Magnus approximation.
 * Dehumidification algorithms and condensation prediction take this, not relative humidity.
 */
export function absoluteHumidity(tempC: number, rh: number): number {
  const es = 6.112 * Math.exp((17.67 * tempC) / (tempC + 243.5));  // saturation vapor pressure, hPa
  const e = es * (rh / 100);                                        // actual vapor pressure, hPa
  return (216.7 * e) / (tempC + 273.15);                            // g/m³
}

/** Dew point (°C) — direct input to the condensation-prevention model */
export function dewPoint(tempC: number, rh: number): number {
  const gamma = (17.67 * tempC) / (tempC + 243.5) + Math.log(rh / 100);
  return (243.5 * gamma) / (17.67 - gamma);
}

// absoluteHumidity(20, 60) → 10.35    absoluteHumidity(30, 60) → 18.21

텔레메트리 페이로드

노드는 1분 주기로 측정·전송하며, 서버는 시간 단위 집계(TelemetryHourly)를 생성하고 원시 데이터는 7일 보관한다. 전송 단위마다 기기 키로 서명하며, 서버는 서명자 주소와 deviceAddress가 일치하는지 확인한 뒤 라이선스 NFT를 조회한다. 서명이 없으면 NFT를 보유한 주소를 사칭한 임의 페이로드를 막을 수 없다.

GET https://api.wellbianlabs.io/v1/c?<base64>json

{
  "schema": "wellbian-iaq-telemetry/v1",
  "deviceAddress": "rDeviceWalletAddress...",
  "signature": "3045022100...",
  "batch": [
    {
      "ts": 1786195200,
      "pm25": 11.4, "pm10": 15.8,
      "co2": 812, "tvoc": 143,
      "tempC": 23.4, "rh": 58.1, "feelsLikeC": 24.1
    },
    {
      "ts": 1786195260,
      "pm25": 11.1, "pm10": 15.2,
      "co2": 845, "tvoc": 139,
      "tempC": 23.4, "rh": 58.4, "feelsLikeC": 24.2
    }
  ]
}

수신 검증 순서

#검증실패 시비고
1서명이 deviceAddress의 공개키와 일치401 BAD_SIGNATURE온체인 조회 없음 — 가장 싼 검사를 먼저
2배치 내 ts가 단조 증가, 서버 시각 ±10분 이내422 TIMESTAMP_SKEW과거 데이터 재전송(리플레이) 차단
3각 지표가 물리적 범위 이내422 OUT_OF_RANGE센서 고장·조작 1차 필터
4직전 값 대비 급변율이 임계 이내이상치 플래그거부하지 않고 품질 점수에 반영
5라이선스 NFT 보유 (캐시 60초)403 NO_VALID_LICENSE가장 비싼 검사를 마지막에
6제출 주기 하한 준수429 RATE_LIMITED보상 파밍 방지
원시 데이터는 온체인에 올리지 않는다

1분 해상도 × 노드 수만큼의 측정값을 원장에 기록하는 것은 비용·성능 모두 불가능하다. 원시 데이터는 오프체인 저장소에 두고, 정산 주기마다 배치 머클루트만 XRPL 트랜잭션의 Memos 필드에 기록한다. 이후 특정 측정값의 무결성이 다투어지면 머클 증명으로 "그 시점 배치에 이 값이 포함되어 있었다"를 검증할 수 있다. 백서 3.2의 "위변조 없이 저장"은 이 방식으로 달성된다.

날씨 데이터 사양 라이선스 계층 · 품질 점수

백서 5장의 "양질의 데이터"를 정량화하고, 리워드를 수량으로만 정의해 방출 총량이 단계 게이트와 10단계 누적 상한(26.65억개)으로 사전 확정되도록 한다.

Taxon 및 티어 체계

라이선스 NFT는 NFTokenTaxon으로 관측망을 구분하고, 메타데이터의 license.tier로 센서 구성 등급을 표현한다. 티어는 센서 구성과 접근 가능한 데이터 상품을 구분하며, 리워드 수량은 티어가 아니라 단계와 품질 등급으로 정해진다.

Taxon관측망Tier필수 센서리워드
3026실내 IAQiaq-litePM2.5/10, 온·습도미정 (출시 시 확정)
3026실내 IAQiaq-standardPM2.5, PM10, CO₂(NDIR), TVOC, 온·습도 (ARC-600DA)1단계 기본 일 7개 (정상 등급 · 지급 보장 아님)
3026실내 IAQiaq-pro추가 센서 미정 (출시 시 확정)동일 규칙 (단계 × 품질 등급)
2026실외 OAQoaq-standardPM2.5/10, O₃, NO₂, 온·습도미정 (실외 출시 시 확정)
2026실외 OAQoaq-pro+ SO₂, CO, 풍속·풍향미정 (실외 출시 시 확정)

디바이스 메타데이터 (IPFS)

주거 환경 속성은 백서 2장이 지적한 "평형·위치·채광에 따른 공조 효율" 분석에 필수적이다. 다만 이 속성들의 조합은 그 자체로 가구를 특정할 수 있으므로, 메타데이터 단계에서부터 연속값이 아닌 버킷으로만 기록한다.

ipfs://Qm…/iaq-device.jsonjson

{
  "schema": "wellbian-iaq-device/v1",
  "name": "Wellbian IAQ Node #10427",
  "description": "Indoor Air Quality license",
  "device": {
    "serial": "KW-IAQ-10427",
    "model": "ARC-600DA",
    "sensors": ["pm25", "pm10", "co2", "tvoc", "temp", "rh"],
    "installed_at": "2026-05-02"
  },
  "context": {
    "geohash5": "wydm9",
    "space_type": "residential",
    "area_bucket": "60-85sqm",
    "floor_bucket": "5-10F",
    "build_year_bucket": "2010-2019",
    "orientation": "S"
  },
  "license": { "tier": "iaq-standard", "valid_until": "2029-05-02" }
}
메타데이터는 공개된다

NFT의 URI는 온체인에 기록되고 IPFS 콘텐츠는 누구나 조회할 수 있다. 따라서 정확한 주소·동호수·연속 좌표를 여기에 넣으면 영구히 공개된다. geohash5(약 4.9 km 격자)와 버킷 값만 기록하고, 정밀 주소는 수집·저장하지 않는다. 위치는 동(洞) 단위로만 보관하며 좌표는 반올림해 저장한다.

품질 점수 (Quality Score)

백서 5장의 "24시간 끊김 없이 양질의 데이터"를 4개 관측 가능한 지표로 분해한다. 특히 인근 노드 상관계수는 센서를 실외에 방치하거나 값을 합성하는 조작을 잡아내는 핵심 항목이다 — 같은 지역의 다른 노드와 온도·PM 추세가 전혀 맞지 않으면 그 노드의 데이터는 신뢰할 수 없다.

src/services/iaq/quality.tstypescript

export interface QualityInputs {
  uptimeRatio: number;    // actual submissions / expected submissions, last 24h
  outlierRatio: number;   // share of out-of-range + sudden-jump outliers
  neighborCorr: number;   // temp/PM trend correlation with nodes within 2km (-1 to 1)
  calibrationAgeDays: number;  // days since last calibration
}

const clamp01 = (x: number) => Math.min(1, Math.max(0, x));

/** 0 to 1. Weights sum to 1.0 */
export function qualityScore(q: QualityInputs): number {
  const uptime = clamp01(q.uptimeRatio);
  if (uptime < 0.2) return 0;                            // 가동률 20% 미만이면 점수 0
  const clean  = clamp01(1 - q.outlierRatio * 4);        // 25% outliers scores zero
  const agree  = clamp01((q.neighborCorr - 0.3) / 0.6);  // zero below 0.3, full marks at 0.9
  const fresh  = clamp01(1 - q.calibrationAgeDays / 365);         // zero after a year without calibration

  const score = 0.40 * uptime + 0.25 * clean + 0.20 * agree + 0.15 * fresh;
  return Math.round(score * 1000) / 1000;
}

고정 예산 배분 (Emission Cap)

노드 1대당 금액을 지급하면 시세에 따라 방출이 요동친다. 대신 수량을 고정한다 — 에폭 예산은 활성 지점 수 × 7.14 × 단계 계수로 정해지고, 각 노드는 품질 등급에 따라 정상 7 · 우수 8.4 · 미달 0을 1차 지급받는다. 미지급분은 가중치 비례로 재분배하되 지점당 10.5개를 상한으로 하고 초과분은 소각한다.

src/services/iaq/reward.tstypescript

import { qualityScore, QualityInputs } from './quality';

export const BASE_DAILY      = 7;      // 정상 등급 1차 지급 (수량 · 시세 무관)
export const EXCELLENT_DAILY = 8.4;    // 품질 상위 10% (+1.4)
export const NODE_CAP        = 10.5;   // 재분배 후 지점당 상한 — 초과분 소각
export const BUDGET_PER_NODE = 7.14;   // 에폭 예산 = 활성 지점 × 7.14 × 단계 계수
export const PHASE_DECAY     = 0.78;   // 단계마다 22% 체감

export type Grade = 0 | 1 | 1.2;
export interface NodeEpochStats { address: string; quality: QualityInputs; txRate: number; licenseHeld: boolean; }

/** 전송률 게이트 → 품질 점수 상위 10% 우수. 게이트 미달은 0 */
export function grade(n: NodeEpochStats, top10Cut: number): Grade {
  if (n.txRate < 0.8) return 0;
  return qualityScore(n.quality) >= top10Cut ? 1.2 : 1;
}

/** 에폭 정산: 총 지급 + 소각 = 예산 (항상 성립) */
export function distribute(nodes: NodeEpochStats[], phase: number) {
  const factor = Math.pow(PHASE_DECAY, phase - 1);
  const active = nodes.filter((n) => n.licenseHeld);
  const budget = active.length * BUDGET_PER_NODE * factor;
  const cut = percentile(active.map((n) => qualityScore(n.quality)), 0.9);

  // 1) 1차 지급 — 정상 7 · 우수 8.4 · 미달 0 (80~95% 전송률은 선형 감액)
  const paid = active.map((n) => {
    const g = grade(n, cut);
    const ramp = n.txRate >= 0.95 ? 1 : n.txRate < 0.8 ? 0 : (n.txRate - 0.8) / 0.15;
    return { address: n.address, g, amount: BASE_DAILY * g * ramp * factor };
  });
  const unpaid = budget - paid.reduce((s, p) => s + p.amount, 0);

  // 2) 미지급분 재분배 — 가중치 비례, 지점당 상한 10.5 × factor, 초과분 소각
  const w = paid.reduce((s, p) => s + p.g, 0);
  let burn = 0;
  for (const p of paid) {
    if (p.g === 0 || w === 0) continue;
    const target = Math.min(p.amount + unpaid * (p.g / w), NODE_CAP * factor);
    burn += p.amount + unpaid * (p.g / w) - target;
    p.amount = target;
  }
  return { paid, burn, budget };   // Σ paid.amount + burn === budget
}
잔여 리스크 "보상 인플레이션" 해소

이 설계로 잔여 리스크 표의 보상 인플레이션 항목이 구조적으로 닫힌다. 10단계 누적 방출은 26.65억개로 사전 확정되고(리워드 1기 버킷 28억 이내), 단계 체감 22%로 지점이 늘수록 지점당 수량이 줄어든다. 품질 미달분은 지급하지 않고 소각하므로 품질이 나쁠수록 총 방출이 준다. 단계 진입에는 수요 조건이 병기되어 수요 없이 방출만 늘어나는 경로가 없다.

배치 지급으로 전환됨

고정 예산 배분은 에폭 종료 시점에 전체 노드의 점수를 알아야 계산할 수 있다. 따라서 Step 4의 요청당 즉시 지급 방식은 IAQ 관측망에서는 사용하지 않는다. 텔레메트리 수신은 202 Accepted로 즉시 응답하고, 보상은 에폭(1일, KST 자정 마감) 배치로 distribute() 결과를 적립하고, 적립분은 24시간 홀드 후 클레임할 수 있다. 이는 Sequence 경합 대응과도 자연스럽게 맞물린다.

날씨 데이터 사양 비식별화 파이프라인

백서 3.2의 "개인정보를 비식별화 처리한 후 메타데이터로 가공"을 5단계 변환으로 구체화한다. 실내 데이터는 재실 여부·생활 패턴이 그대로 드러나는 민감 정보이므로, 실외 날씨 데이터보다 훨씬 강한 처리가 필요하다.

실내 데이터가 노출하는 것

CO₂ 농도 시계열 하나만으로 재실 인원수, 취침·기상 시각, 부재 기간이 상당히 정확하게 추정된다. PM2.5 급등은 조리 시각을, TVOC 패턴은 청소·인테리어 시공을 드러낸다. 이 데이터가 정확한 위치와 결합되면 사실상 특정 가구의 생활 로그가 된다. 따라서 정밀 위치·원시 시간해상도·개별 노드 식별자가 동시에 외부로 나가는 경로는 존재해서는 안 된다.

5단계 변환

#단계원시공개
P1공간 일반화동(洞) 단위 위치 · 반올림 좌표geohash5 — 약 4.9 km 격자
P2시간 집계1분 해상도 측정값1시간 단위 평균·최대·분산
P3식별자 치환rDeviceAddress…HMAC(NFTokenID, epochSalt) — 에폭마다 회전
P4k-익명성 게이트—버킷 내 노드 < 5이면 상위 격자로 롤업, 그래도 미달이면 응답 거부
P5속성 일반화평형 84.3 m², 7층60-85sqm, 5-10F

P3의 에폭마다 회전하는 salt가 중요하다. 고정 salt로 해시하면 가명 ID가 영구 식별자가 되어 장기 추적이 가능해진다. 에폭마다 salt를 교체하면 에폭 간 연결이 끊긴다. 다만 이 경우 장기 시계열 분석이 불가능해지므로, 장기 분석은 가명 ID가 아닌 버킷 단위 집계로만 제공한다.

src/services/iaq/anonymize.tstypescript

export const K_MIN = 5;

export interface NodeSummary { geohash5: string; tier: string; hourly: HourlyStats; }
export interface Bucket { geohash: string; precision: number; n: number; stats: HourlyStats; }

/**
 * P4 — roll up to coarser cells until k-anonymity is satisfied.
 * If geohash3 (~156km) is still short, return null and the API refuses to respond.
 */
export function rollupToKAnonymous(nodes: NodeSummary[], geohash: string): Bucket | null {
  for (let precision = Math.min(5, geohash.length); precision >= 3; precision--) {
    const prefix = geohash.slice(0, precision);
    const members = nodes.filter((n) => n.geohash5.startsWith(prefix));

    if (members.length >= K_MIN) {
      return { geohash: prefix, precision, n: members.length, stats: aggregate(members) };
    }
  }
  return null;
}

/** P3 — derive a pseudonymous ID from a salt rotated each epoch */
export function pseudonym(nftokenId: string, epochSalt: string): string {
  return createHmac('sha256', epochSalt).update(nftokenId).digest('hex').slice(0, 16);
}

차분 공격 방어

k-익명성만으로는 부족하다. 필터를 조금씩 바꿔가며 반복 질의하면 두 결과의 차이로 개별 가구를 분리해낼 수 있다. 예를 들어 "평형 60-85 & 5-10층" 코호트와 "평형 60-85 & 5-10층 & 남향" 코호트의 차이가 1이면 그 1가구의 속성이 그대로 드러난다.

방어규칙효과
카운트 반올림응답 코호트 크기를 5 단위로 반올림차이가 1인 질의쌍이 같은 값을 반환
필터 개수 상한동시 적용 가능한 속성 필터 최대 3개조합 폭발로 인한 좁은 코호트 생성 차단
질의 로그 · 예산구매자별 일일 질의 수 상한, 유사 질의 반복 탐지반복 차분 시도 자체를 제한
최소 코호트반올림 후에도 25 미만이면 거부k=5보다 보수적인 실질 하한

데이터 접근 권한 매트릭스

데이터기여자 본인가전 제조사공개 API
자기 노드 측정 원시값 (보관 기간 한정)전체불가불가
동 단위 위치 · 반올림 좌표(정밀 주소 미보관)전체불가불가
격자 1시간 집계전체구독제한 공개 (지연 24h)
코호트 카운트—건당 과금불가
대상자 연락처 · 노드 목록—불가불가
광고 도달은 플랫폼이 중개한다

백서 6장의 "타겟팅 광고 수수료" 모델에서 제조사에 넘어가는 것은 코호트 크기와 광고 소재뿐이다. 대상자 목록은 절대 이전되지 않는다. 제조사는 "조건 X를 만족하는 가구 1,240곳에 이 소재를 노출" 요청을 넣고, 플랫폼이 자체 앱·알림 채널로 도달시킨 뒤 리드 수만 정산한다. 이 경계가 무너지면 생태계 전체가 개인정보 처리 리스크에 직접 노출된다.

법적 검토 필요

본 절은 기술적 설계이며 법률 자문이 아니다. 국내 서비스 시 실내 환경 데이터의 개인정보 해당 여부, 가명정보 처리 요건, 수집·이용 동의 문구, 제3자 제공과 위탁의 구분, 그리고 보상 지급이 대가성 있는 데이터 판매로 해석될 여지에 대해 착수 전 개인정보 전문 법률 검토가 반드시 선행되어야 한다.

날씨 데이터 사양 B2B 데이터 상품 · 과금 설계

백서 6장의 세 수익원을 x402 프로토콜 위의 세 가지 상품으로 매핑한다. 과금 수단이 하나로 통일되므로 별도 빌링 시스템 없이 온체인 정산이 성립한다.

수익원 (백서 6장)엔드포인트응답과금참고 단가
API 구독료GET https://wellbian.io/api/data/aggregates 격자·시간대별 지표 집계선불 크레딧 차감0.002 RLUSD / call
타겟팅 광고 수수료POST https://wellbian.io/api/data/cohort (planned) 조건 만족 코호트 크기만건당 결제0.05 RLUSD / query
인사이트 리포트POST https://wellbian.io/api/data/report (planned) LLM 분석 리포트건당 결제0.5 RLUSD
(R&D 데이터셋)POST https://wellbian.io/api/data/dataset (planned) 비식별 학습셋 스냅샷 URL건당 결제 (고액)협의 · 계약 기반

코호트 API — 개인을 노출하지 않는 타겟팅

백서 4장의 마케팅 활용은 전부 이 엔드포인트 하나로 수렴한다. 핵심은 응답에 노드 목록이 없다는 것이다. 크기와 대표 통계만 반환한다.

POST /api/data/cohortjson

{
  "region": "wydm",
  "window": { "from": "2026-08-01", "to": "2026-08-31" },
  "filters": [
    { "metric": "ah", "op": "gte", "value": 14.0, "duty": 0.6 },
    { "metric": "area_bucket", "op": "in", "value": ["60-85sqm", "85-135sqm"] }
  ]
}
200 OK — monsoon high-humidity households (WP ch.4 dehumidifier scenario)json

{
  "cohortSize": 1240,
  "rounding": 5,
  "kAnonymity": { "min": 5, "satisfied": true, "effectiveMin": 25 },
  "profile": {
    "ah_p50": 15.8, "ah_p90": 19.2,
    "hours_above_threshold_p50": 431,
    "top_area_bucket": "60-85sqm"
  },
  "reachable": true,
  "note": "No subject list is provided. Ad delivery is brokered by the platform."
}
422 — cohort too narrowjson

{
  "error": "COHORT_TOO_NARROW",
  "minimum": 25,
  "hint": "Relax the filters or reduce region precision. The actual size is not returned."
}

구독형을 x402 위에 올리는 법 — 선불 크레딧

원 x402는 호출 1건 = 결제 1건이다. 집계 API처럼 초당 수십 회 호출되는 상품에 이를 그대로 적용하면 매 호출마다 3~5초의 원장 확정을 기다려야 해 성립하지 않는다. 따라서 402 응답에 건당 결제와 선불 크레딧 두 가지 scheme을 동시에 제시하고, 구독 고객은 후자를 택하게 한다.

HTTP/1.1 402 — two payment schemes offeredjson

{
  "x402Version": 1,
  "resource": "/api/data/aggregates",
  "accepts": [
    {
      "scheme": "xrpl-payment",
      "network": "xrpl-mainnet",
      "payTo": "rhTTtx8YyKzcmPDsoroYXuHdGMThrnweb1",
      "asset": { "currency": "RLUSD", "issuer": "rMxCKbEDwqr76QuheSUMdEGf4B9xJ8m5De", "value": "0.002" },
      "destinationTag": 402010,
      "maxTimeoutSeconds": 120
    },
    {
      "scheme": "xrpl-credit",
      "network": "xrpl-mainnet",
      "payTo": "rhTTtx8YyKzcmPDsoroYXuHdGMThrnweb1",
      "topUpMinimum": { "currency": "RLUSD", "issuer": "rMxCKbEDwqr76QuheSUMdEGf4B9xJ8m5De", "value": "100" },
      "destinationTag": 402011,
      "unitPrice": "0.002",
      "authScheme": "x402-credit .."
    }
  ]
}

크레딧 충전은 온체인 Payment 1건으로 이뤄지고, 이후 호출은 서명으로만 인증된다. 서명 대상에 nonce를 포함시켜 재전송을 막고, nonce는 단조 증가를 강제한다.

src/services/x402.credit.tstypescript

import { verify } from 'ripple-keypairs';
import { verifyPayment } from './x402';

interface CreditAccount { balance: number; currency: 'RLUSD' | 'WLBN'; lastNonce: number; publicKey: string; }
const credits = new Map<string, CreditAccount>();   // use a persistent store in production

/** Top-up — reuses the existing on-chain verification logic as-is */
export async function topUp(txHash: string) {
  const res = await verifyPayment(txHash);          // replay + delivered-amount checks already applied here
  if (!res.ok) return res;

  const acc = credits.get(res.payer) ?? { balance: 0, currency: res.currency, lastNonce: 0, publicKey: res.publicKey };
  acc.balance += Number(res.value);
  credits.set(res.payer, acc);
  return { ok: true as const, balance: acc.balance };
}

/** Call — signature + balance only, no on-chain round trip (~1ms) */
export function spend(header: string, method: string, path: string, unitPrice: number) {
  const [payer, nonceStr, signature] = header.split('.');
  const acc = credits.get(payer);
  if (!acc) return { ok: false as const, reason: 'NO_CREDIT_ACCOUNT' };

  const nonce = Number(nonceStr);
  if (!Number.isInteger(nonce) || nonce <= acc.lastNonce) return { ok: false as const, reason: 'BAD_NONCE' };

  const message = Buffer.from(`${method}:${path}:${nonce}`, 'utf8').toString('hex').toUpperCase();
  if (!verify(message, signature, acc.publicKey)) return { ok: false as const, reason: 'BAD_SIGNATURE' };

  if (acc.balance < unitPrice) return { ok: false as const, reason: 'INSUFFICIENT_CREDIT' };

  acc.balance -= unitPrice;
  acc.lastNonce = nonce;
  return { ok: true as const, remaining: acc.balance };
}
두 scheme의 역할 분담

xrpl-payment는 저빈도·고단가 상품(코호트 질의, 인사이트 리포트)에, xrpl-credit은 고빈도·저단가 상품(집계 API)에 쓴다. 크레딧 잔액이 소진되면 서버가 다시 402를 반환하므로, 구매자 에이전트 입장에서는 충전과 사용이 동일한 프로토콜 흐름 안에서 처리된다.

리워드 소비와 결제 구조

백서 5장의 "생태계 소비"(가전 구매 할인·필터 구독 결제·제휴 마켓)는 제휴 마켓 개설 시 별도 사양으로 공표한다. 결제 구조는 공표 정책을 따른다 — 기업 고객은 원화·RLUSD, AI 에이전트는 자동 결제(x402), 프로토콜 내부는 매출 일부로 WLBN을 매입해 소각한다. 고객에게 토큰을 사서 결제하라고 요구하지 않으며, 배분 비율은 사전 공표한다.

가치 흐름 요약

fund flow over one epochlog

[IN ]  Enterprise    → Hot           RLUSD / KRW  (aggregate credit · cohort · report · dataset)
[IN ]  AI agent      → Hot           RLUSD / WLBN (per-call x402 payment)
[OUT]  Hot           → points        WLBN   7 × 0.78^(phase−1) × grade   ← quantity, never value
[BURN] Hot           → Issuer        WLBN   quality shortfall (redistribution excess)
[BURN] Treasury      → Issuer        WLBN   scheduled 2.5B in 4 tranches · buyback from revenue (2.465B)
[LP  ] Treasury      → AMM           WLBN/RLUSD   20% of participation fees on sale

STEP 01 XRPL 기반 & 지갑 셋업

Mainnet(wss://xrplcluster.com) 클라이언트 모듈과 3개 지갑(Issuer 콜드 · Hot · Treasury)을 준비하고, 각 계정에 Reserve용 XRP를 사전 예치한다.

산출물

  • xrpl/client.ts — 재사용 가능한 연결 싱글턴
  • xrpl/wallet.ts — 시드 기반 로드 + 신규 생성/펀딩
  • scripts/01-bootstrap-wallets.ts — 실행 시 .env에 붙여넣을 값 출력
src/xrpl/client.tstypescript

import { Client } from 'xrpl';
import { env } from '../config/env';

let client: Client | null = null;

export async function getClient(): Promise<Client> {
  if (client?.isConnected()) return client;
  client = new Client(env.XRPL_ENDPOINT, { connectionTimeout: 10_000 });
  client.on('disconnected', (code) => console.warn('[xrpl] disconnected', code));
  await client.connect();
  return client;
}

export async function closeClient(): Promise<void> {
  if (client?.isConnected()) await client.disconnect();
  client = null;
}
src/scripts/01-bootstrap-wallets.tstypescript

import { Wallet } from 'xrpl';
import { getClient, closeClient } from '../xrpl/client';
import { env } from '../config/env';

const ROLES = ['ISSUER', 'HOT', 'TREASURY'] as const;
const MIN_RESERVE_XRP = 5;
// ISSUER(cold) rDJz8WJhsKgydqJzSZXMpsJot3eRmSkR5
// HOT          rhTTtx8YyKzcmPDsoroYXuHdGMThrnweb1
// TREASURY     rPZFY2yLgqjmBrxtxWHXnB1doBt7gu7xin

async function main() {
  const client = await getClient();

  for (const role of ROLES) {
    // Mainnet: 시드로 로드하고 잔액을 확인한다 (Faucet 없음)
    const wallet = Wallet.fromSeed(env[`${role}_SEED`]);
    const info = await client.request({
      command: 'account_info', account: wallet.classicAddress, ledger_index: 'validated',
    });
    const balance = Number(info.result.account_data.Balance) / 1_000_000;
    if (balance < MIN_RESERVE_XRP) throw new Error(`${role} underfunded: ${balance} XRP`);
    console.log(`\n# ${role}`);
    // 시드는 출력하지 않는다 — .env에서만 관리한다
    console.log(`${role}_ADDRESS=${wallet.classicAddress}   # balance ${balance} XRP`);
  }

  await closeClient();
}

main().catch((e) => { console.error(e); process.exit(1); });
Reserve 계산

각 계정은 Base Reserve 1 XRP를 묶어두고, TrustLine·NFT Offer·AMM 오브젝트마다 0.2 XRP씩 추가로 잠긴다. Hot 지갑은 WLBN + RLUSD TrustLine 2개 = 0.4 XRP가 추가로 필요하므로, 각 계정에 최소 5 XRP 이상을 사전 예치하고 대량 기기 등록 시에는 사전 잔액 점검 로직을 넣는다.

STEP 02 Wellbian 토큰(WLBN) 발행 (Issued Asset)

Issuer(콜드)가 Wellbian 토큰(WLBN)을 발행하고, 보유 지갑들이 WLBN 및 실제 RLUSD TrustLine을 설정한다.

발행 절차

  1. Issuer 계정 설정 — AccountSet으로 asfDefaultRipple 활성화, TransferRate(선택) 설정
  2. 보유자 TrustLine — Hot·Treasury·사용자 지갑이 TrustSet으로 한도 설정
  3. 초기 발행 — Issuer → Treasury/Hot으로 Payment를 보내면 그 금액만큼 토큰이 존재하게 됨 (IOU는 별도 mint 트랜잭션이 없음)
Default Ripple은 발행자에서 켠다

XRPL에서 IOU는 항상 발행자 계정을 경유해 이동한다. 따라서 발행자 계정은 asfDefaultRipple을 ON으로 설정해야 한다. 이 플래그가 꺼져 있으면 보유자 간 전송(Hot → 사용자 지갑)이 tecPATH_DRY로 실패하고, Step 4의 보상 지급과 Step 5의 AMM이 모두 성립하지 않는다.

의도치 않은 유동성 전이 방지는 보유자 측 TrustLine에 tfSetNoRipple을 적용해 달성한다. 이 조합은 "발행자를 경유한 정상 전송"은 허용하고 "보유자 계정을 브릿지로 삼는 제3자 경로"는 차단한다.

src/xrpl/token.tstypescript

import { Client, Wallet, AccountSetAsfFlags, TrustSetFlags, IssuedCurrencyAmount } from 'xrpl';
import { submit } from './submit';

/** Issuer account setup — DefaultRipple ON so IOUs can move between holders */
export async function configureIssuer(client: Client, issuer: Wallet) {
  await submit(client, issuer, {
    TransactionType: 'AccountSet',
    Account: issuer.classicAddress,
    SetFlag: AccountSetAsfFlags.asfDefaultRipple,
    Domain: Buffer.from('wellbian.io').toString('hex').toUpperCase(),
  });
}

/** Holder TrustLine — NoRipple blocks third-party bridge routing */
export async function setTrustLine(
  client: Client, holder: Wallet, issuerAddress: string,
  currency: string, limit = '1000000000',
) {
  await submit(client, holder, {
    TransactionType: 'TrustSet',
    Account: holder.classicAddress,
    LimitAmount: { currency, issuer: issuerAddress, value: limit },
    Flags: TrustSetFlags.tfSetNoRipple,
  });
}

/** IOU transfer — from the Issuer it is issuance; between holders it is circulation */
export async function sendIOU(
  client: Client, from: Wallet, destination: string,
  amount: IssuedCurrencyAmount, destinationTag?: number,
) {
  return submit(client, from, {
    TransactionType: 'Payment',
    Account: from.classicAddress,
    Destination: destination,
    Amount: amount,
    ...(destinationTag !== undefined ? { DestinationTag: destinationTag } : {}),
  });
}

토큰 정의

토큰Currency (hex)역할초기 공급
WLBN574C424E0000…DePIN 보상 · API 사용료 결제 수단10,000,000,000 (총 발행)
RLUSD524C5553440000…스테이블 페어 · 기관 결제 유입 통화 (Issuer rMxCKbEDwqr76QuheSUMdEGf4B9xJ8m5De)외부 발행 (Ripple) — 자체 발행 없음

공급 총 발행량은 100억 WLBN이다. XRPL IOU에는 총량 필드가 없으므로, 공급량은 Issuer가 내보낸 채무(gateway_balances의 obligations)의 합으로 정의된다. 2026-09-01 기준 배분은 트레저리 99억 9,995만, 핫월렛(보상 재원) 약 5만, 유통 약 5이다.

방출 스케줄 — 단계 체감

총 발행은 100억이지만 한 번에 유통시키지 않는다. 방출 기준치는 실내 1단계 지점당 일 7 WLBN · 월 213 · 연 2,555(정상 등급)이며, 단계가 오를 때마다 22% 체감한다(7 × 0.78^(단계−1)). 이는 계획값이며 지급을 약속하는 수치가 아니다. 실제 수령량은 품질 등급과 재분배 결과에 따라 달라진다.

단계일 기본1단계 대비단계 방출량
1 국내 실내 (25,000 지점)7.00개100%0.64억
34.26개61%1.87억
52.59개37%3.31억
71.58개23%3.74억
100.75개11%2.73억
10단계 누적26.65억 (리워드 1기 28억 이내)

목표 규모 1단계는 국내 실내 25,000 지점(제네시스 한정 모집)이다. 이후 실내 → 실외로 넓히며 기존 홀더에게 실외 라인을 우선 제안하고, 최종 목표는 실내를 포함한 통합 관측망 100만 지점이다. 단계 진입은 지점 수와 수요 조건을 함께 만족하는 마일스톤 게이트로만 열린다.

배분 총 발행 100억 중 노드 홀더 리워드는 1기 28억(28%)과 10단계 게이트 통과 시에만 열리는 2기 18억(18%)이다. 소각 예정 25억, LP 리워드 8억, 팀 6억, 생태계 5억, 전략 투자 5억, 유동성·준비금 5억 — 전체 표는 토크노믹스 정책 절에 있다.

체감 시간 기반 반감기는 쓰지 않는다. 해마다 반으로 줄면 계획 방출 기준이 흔들린다. 대신 지점 수 게이트로 정의된 단계마다 22% 체감하며, 브레이크는 시간이 아니라 게이트(수요 조건)와 10단계 누적 상한이다.

상한 지점당 1차 지급은 등급별 정량(정상 7 · 우수 8.4 · 미달 0)이고, 미지급분 재분배 후에도 지점당 10.5개를 넘지 않는다. 초과분은 지급하지 않고 소각하므로 어떤 경우에도 총 지급 + 소각 = 에폭 예산이다.

참고 실제 RLUSD는 Ripple이 발행하는 스테이블코인이다. 서비스 대금(x402)은 이 RLUSD로만 수취하며, Issuer 주소는 rMxCKbEDwqr76QuheSUMdEGf4B9xJ8m5De로 상수에 고정한다. 자체 발행 모의 RLUSD는 사용하지 않는다.

STEP 03 IoT 라이선스 NFT (XLS-20)

기기 1대 = NFT 1개. 온체인에서 라이선스 보유 여부를 조회해 데이터 제출 권한을 판정한다.

리딤 4단계 — ① 사전 구매·프로모션 시 코드가 미결합(UNBOUND) 상태로 발급된다 (WLBN-XXXX-XXXX-XXXX). ② 사용자가 wellbian.io/redeem에서 코드와 기기 시리얼을 입력하면 코드가 해당 기기에 결합된다. ③ Hot 지갑이 NFT를 민팅하고(Issuer는 콜드 지갑) NFTokenCreateOffer(Amount=0)를 사용자 주소로 생성한다. ④ 사용자가 NFTokenAcceptOffer로 수령을 확정한다. 지원 지갑은 간편지갑(아이디·비밀번호 또는 구글 로그인), D'CENT 모바일 인앱, Xaman, GemWallet, Crossmark이다.

발행 → 전송 흐름

NFTokenMint Hot 서명 · Issuer=콜드(NFTokenMinter) NFTokenCreateOffer Hot · Amount=0 · Destination=사용자 NFTokenAcceptOffer 사용자 지갑 · 수령 확정 account_nfts verifyDeviceLicense() NFTokenID OfferIndex 소유권 이전 Amount=0 판매 오퍼 + Destination 지정 → 리딤으로 확인된 사용자 계정만 수령 가능 (무상 발급)
Fig 2. XLS-20 라이선스 발급 시퀀스
src/xrpl/nft.tstypescript

import { Client, Wallet, NFTokenMintFlags, NFTokenCreateOfferFlags, convertStringToHex } from 'xrpl';
import { submit } from './submit';

export const TAXON = {
  OBS_GENESIS: 1001, OBS_REGION: 1002, OBS_BIZ: 1003,          // 관측소 NFT (계정당 1개)
  VOUCHER: 1010,                                               // 사전예약 바우처 (테스트 900010)
  OAQ: 2026, IAQ: 3026, AI: 4026, RADAR: 5026, SAT: 6026,      // 스테이션 NFT (기기당 1개)
} as const;

/** Mint a license NFT → returns the NFTokenID */
export async function mintLicense(
  client: Client, hot: Wallet, metadataUri: string, taxon: number = TAXON.IAQ,
) {
  // 서명자는 Hot 지갑, 발행 주체(Issuer)는 콜드 지갑 — NFTokenMinter로 위임
  const res = await submit(client, hot, {
    TransactionType: 'NFTokenMint',
    Account: hot.classicAddress,
    Issuer: env.ISSUER_ADDRESS,
    URI: convertStringToHex(metadataUri),      // ipfs://Qm...
    NFTokenTaxon: taxon,
    Flags: NFTokenMintFlags.tfTransferable,
  });

  // meta.nftoken_id is populated by rippled
  const meta = res.result.meta as { nftoken_id?: string };
  if (!meta.nftoken_id) throw new Error('NFTokenID not found in metadata');
  return meta.nftoken_id;
}

/** Create a zero-price sell offer restricted to one recipient */
export async function offerLicenseTo(
  client: Client, hot: Wallet, nftokenId: string, destination: string,
) {
  const res = await submit(client, hot, {
    TransactionType: 'NFTokenCreateOffer',
    Account: hot.classicAddress,
    NFTokenID: nftokenId,
    Amount: '0',
    Destination: destination,                  // 리딤으로 확인된 사용자 계정만 수락 가능
    Flags: NFTokenCreateOfferFlags.tfSellNFToken,
  });

  const meta = res.result.meta as { offer_id?: string };
  if (!meta.offer_id) throw new Error('OfferID not found in metadata');
  return meta.offer_id;
}

/** User wallet accepts the offer → ownership transfers.
 *  D'CENT 펜딩 오퍼 폴백은 설정 플래그 allowPendingOffer(기본 false)로 제어한다. */
export async function acceptLicense(client: Client, user: Wallet, offerId: string) {
  return submit(client, user, {
    TransactionType: 'NFTokenAcceptOffer',
    Account: user.classicAddress,
    NFTokenSellOffer: offerId,
  });
}

온체인 라이선스 검증

오라클 엔드포인트가 매 요청마다 호출하는 핵심 함수다. Issuer 주소와 Taxon을 함께 확인해야 임의의 제3자가 발행한 위조 NFT를 거를 수 있다.

src/xrpl/nft.ts (continued)typescript

import { env } from '../config/env';

export interface LicenseInfo {
  valid: boolean;
  nftokenId?: string;
  uri?: string;
  taxon?: number;
}

/** Verify on-chain that the address holds a valid license NFT for this network */
export async function verifyDeviceLicense(
  client: Client, walletAddress: string, taxon: number = TAXON.IAQ,
): Promise<LicenseInfo> {
  const res = await client.request({
    command: 'account_nfts',
    account: walletAddress,
    ledger_index: 'validated',
  });

  const hit = res.result.account_nfts.find(
    (n) => n.Issuer === env.ISSUER_ADDRESS && n.NFTokenTaxon === taxon,
  );
  if (!hit) return { valid: false };

  return {
    valid: true,
    nftokenId: hit.NFTokenID,
    taxon: hit.NFTokenTaxon,
    uri: hit.URI ? Buffer.from(hit.URI, 'hex').toString('utf8') : undefined,
  };
}

메타데이터 스키마 (IPFS) — 실외 OAQ 예시

ipfs://Qm…/oaq-device.jsonjson

{
  "schema": "wellbian-oaq-device/v1",
  "name": "Wellbian OAQ Node #0042",
  "description": "Outdoor Air Quality station license",
  "device": {
    "serial": "KW-OAQ-0042",
    "model": "TBD",
    "sensors": ["pm25", "pm10", "o3", "no2", "temp", "rh"],
    "installed_at": "2026-03-11"
  },
  "context": { "geohash5": "wydm9", "space_type": "outdoor" },
  "license": { "tier": "oaq-standard", "valid_until": "2029-03-11" }
}

실내 IAQ 노드의 메타데이터는 주거 환경 버킷을 추가로 포함한다 — 라이선스 계층 · 품질 점수 절의 wellbian-iaq-device/v1 스키마 참고. 두 스키마 모두 정밀 좌표를 넣지 않는다는 규칙을 공유한다.

캐싱과 폐기(Revocation)

account_nfts를 요청마다 호출하면 텔레메트리 처리량이 원장 조회에 묶인다. 결과를 주소 단위로 30~60초 TTL 캐싱하고, 라이선스 폐기가 필요하면 NFT를 회수(재오퍼)하거나, tfBurnable로 발행한 뒤 발행 권한을 가진 콜드 Issuer가 NFTokenBurn으로 소각하는 정책을 함께 정의해야 한다. tfTransferable만 설정하면 발행자가 강제 회수할 수 없다는 점에 유의한다.

STEP 04 DePIN 오라클 & 보상 엔진

텔레메트리 수신 → 라이선스 검증 → WLBN 보상 지급까지의 무인 파이프라인.

API 명세

항목내용
EndpointGET https://api.wellbianlabs.io/v1/c?<base64> (Supabase Edge Function proxy)
Body{ schema, deviceAddress, token, batch: [ { ts, pm25, co2, tvoc, tempC, rh, … } ] }
202{ accepted: 5 } — 수신 확인. 보상은 일 1회 에폭 정산에서 적립되며, 24시간 홀드 후 클레임 시 지급
401{ error: "BAD_TOKEN" } — 수집 토큰 불일치 (기기별 토큰으로 전환 중, 페이로드 서명 검증은 로드맵)
403{ error: "NO_VALID_LICENSE" } — 라이선스 NFT 미보유
422{ error: "OUT_OF_RANGE" } — 기기 시각이 10분 초과로 어긋나면 거부하지 않고 서버 수신 시각(KST)으로 보정 후 수용
429{ error: "RATE_LIMITED" } — 제출 주기 위반
src/services/oracle.tstypescript

import { getClient } from '../xrpl/client';
import { verifyDeviceLicense } from '../xrpl/nft';
import { env } from '../config/env';

import { absoluteHumidity } from './iaq/humidity';
import { TAXON } from '../xrpl/nft';

export interface IaqReading {
  ts: number;
  pm25: number; pm10: number;
  co2: number; tvoc: number;
  tempC: number; rh: number;
}

const RANGES: Record<keyof IaqReading, [number, number]> = {
  ts: [0, Number.MAX_SAFE_INTEGER],
  pm25: [0, 1000], pm10: [0, 1000],
  co2: [350, 5000], tvoc: [0, 60000],
  tempC: [-10, 60], rh: [0, 100],
};

const lastSeen = new Map<string, number>();
const MIN_INTERVAL_MS = 4 * 60_000;      // 1-minute transmit cadence; floor keeps slack

export async function ingest(deviceAddress: string, batch: IaqReading[]) {
  // 1) submission interval floor — prevents reward farming
  const prev = lastSeen.get(deviceAddress) ?? 0;
  if (Date.now() - prev < MIN_INTERVAL_MS) throw new HttpError(429, 'RATE_LIMITED');

  // 2) physical plausibility — check the whole batch
  for (const reading of batch) {
    for (const [k, [lo, hi]] of Object.entries(RANGES)) {
      const v = reading[k as keyof IaqReading];
      if (typeof v !== 'number' || v < lo || v > hi) throw new HttpError(422, 'OUT_OF_RANGE');
    }
  }

  // 3) on-chain license check (IAQ Taxon, 60s TTL cache)
  const client = await getClient();
  const license = await verifyDeviceLicense(client, deviceAddress, TAXON.IAQ);
  if (!license.valid) throw new HttpError(403, 'NO_VALID_LICENSE');

  // 4) derive absolute humidity, store off-chain — only the batch Merkle root goes on-ledger
  const enriched = batch.map((r) => ({ ...r, ah: absoluteHumidity(r.tempC, r.rh) }));
  await saveTelemetry(deviceAddress, enriched, license.nftokenId!);

  // 5) accrual only — the daily epoch settles accruals; payout happens on claim
  await accrueForEpoch(deviceAddress, license, enriched);

  lastSeen.set(deviceAddress, Date.now());
  return { accepted: batch.length };      // HTTP 202
}

보상 엔진 파라미터

항목정책 값현행 구현 (2026-09)
에폭1일 · KST 자정 경계동일
일일 리워드7 × 0.78^(단계−1) × 품질 등급(0 · 1.0 · 1.2)1단계 정상 7 정액 적립
에폭 예산활성 지점 × 7.14 × 단계 계수지점당 7 상한으로 동일 효과
재분배미지급분 가중치 비례 · 지점당 상한 10.5 · 초과분 소각거버넌스 변수로 반영 예정
품질 등급전송률 95%+ 전액 · 80~95% 선형 · 80% 미만 0 · 품질 점수 상위 10% 우수품질 점수(uptime 40 · outlier 25 · correlation 20 · calibration 15) 산출 중 · uptime < 0.2이면 0
클레임 홀드24시간동일
방출 상한10단계 누적 26.65억 (리워드 1기 28억 이내)보상 풀 소진 시 적립 중단
IAQ 관측망은 배치 정산을 사용한다

요청당 1 Payment를 발생시키면 3~5초의 원장 확정 대기가 HTTP 응답에 포함되고, 노드가 늘수록 Sequence 경합이 심해진다. 더 근본적으로, 고정 예산 배분은 에폭 종료 시점에 전체 노드의 품질 점수를 알아야 계산할 수 있으므로 즉시 지급 자체가 성립하지 않는다.

따라서 수신은 202 Accepted로 즉시 응답하고, 에폭은 KST 자정을 경계로 하는 1일 고정 단위다. 정산은 5분 주기의 재개 가능 스텝 러너 크론이 수행하며, 핫월렛 트랜잭션은 아웃박스 패턴으로 발행된다. 보상은 적립되고 지급은 클레임 시점에 이루어진다. 실외 OAQ 관측망의 보상 tier는 아직 미정이다.

Sequence 경합

Hot Wallet(운영 지갑) 하나가 동시에 여러 Payment를 서명하면 Sequence 번호가 충돌해 tefPAST_SEQ / terPRE_SEQ가 발생한다. Hot Wallet의 트랜잭션 제출은 아웃박스 패턴으로 기록 후 단일 워커가 순차 제출하며, 크론이 중단되어도 미완료 아웃박스부터 재개한다.

STEP 05 AMM 유동성 풀 (XLS-30)

WLBN ↔ RLUSD 풀을 생성해 원장 내에서 즉시 스왑이 가능하게 한다. AMM은 스왑 편의 전용이며 Wellbian(WLBN)의 가격 발견·가치 평가 기능을 하지 않는다.

AMMCreate
풀 생성
두 자산의 초기 예치 비율이 스왑 교환비를 결정한다. 특별 수수료(= Owner Reserve, 메인넷 0.2 XRP)가 부과된다.
AMMDeposit
유동성 공급
단일 자산 / 양방향 예치 모두 가능. LPToken을 수령한다.
Payment + Paths
스왑 실행
별도 swap 트랜잭션이 없다. 크로스-커런시 Payment가 AMM/오더북을 자동 경유한다.
src/xrpl/amm.tstypescript

import { Client, Wallet, AMMDepositFlags } from 'xrpl';
import { submit } from './submit';
import { WLBN, RLUSD } from '../config/currency';
import { env } from '../config/env';

const wlbn  = (value: string) => ({ currency: WLBN,  issuer: env.ISSUER_ADDRESS, value });
const rlusd = (value: string) => ({ currency: RLUSD, issuer: env.RLUSD_ISSUER_ADDRESS, value });

/** AMM pool deposit 100,000 WLBN : 1,000 RLUSD — 예시 값. 예치 비율은 스왑 교환비 산정용일 뿐
 *  WLBN의 가치·법정화폐 환산을 의미하지 않는다. */
export async function createAmm(client: Client, lp: Wallet) {
  return submit(client, lp, {
    TransactionType: 'AMMCreate',
    Account: lp.classicAddress,
    Amount:  wlbn('100000'),
    Amount2: rlusd('1000'),
    TradingFee: 500,          // 0.5% (unit: 1/100,000)
  });
}

/** Two-asset deposit */
export async function depositBoth(client: Client, lp: Wallet, a: string, b: string) {
  return submit(client, lp, {
    TransactionType: 'AMMDeposit',
    Account: lp.classicAddress,
    Asset:  { currency: WLBN,  issuer: env.ISSUER_ADDRESS },
    Asset2: { currency: RLUSD, issuer: env.RLUSD_ISSUER_ADDRESS },
    Amount: wlbn(a),
    Amount2: rlusd(b),
    Flags: AMMDepositFlags.tfTwoAsset,
  });
}

/** RLUSD → WLBN swap: fixed target amount + max spend cap (slippage defense) */
export async function swapRlusdForWlbn(
  client: Client, buyer: Wallet, targetWlbn: string, maxRlusd: string,
) {
  const paths = await client.request({
    command: 'path_find', subcommand: 'create',
    source_account: buyer.classicAddress,
    destination_account: buyer.classicAddress,
    destination_amount: wlbn(targetWlbn),
    source_currencies: [{ currency: RLUSD, issuer: env.RLUSD_ISSUER_ADDRESS }],
  } as never);

  return submit(client, buyer, {
    TransactionType: 'Payment',
    Account: buyer.classicAddress,
    Destination: buyer.classicAddress,     // to yourself = currency conversion
    Amount: wlbn(targetWlbn),
    SendMax: rlusd(maxRlusd),              // slippage cap
    Paths: (paths.result as { alternatives: { paths_computed: unknown }[] })
      .alternatives[0]?.paths_computed as never,
    Flags: 0,                              // tfPartialPayment 미사용
  });
}

/** Query pool state */
export async function getPoolState(client: Client) {
  const res = await client.request({
    command: 'amm_info',
    asset:  { currency: WLBN,  issuer: env.ISSUER_ADDRESS },
    asset2: { currency: RLUSD, issuer: env.RLUSD_ISSUER_ADDRESS },
  } as never);
  return res.result;
}
스왑 시 주의점
  • 자기 자신에게 보내는 Payment가 XRPL의 통화 변환 관용구다. Destination을 본인 주소로 둔다.
  • SendMax를 반드시 지정한다. 없으면 풀 상태에 따라 예상보다 훨씬 많은 RLUSD가 소진될 수 있다.
  • tfPartialPayment를 켜면 목표량 미달로도 성공 처리되므로, 결제 검증 로직에서 실제 전달액(delivered_amount)을 확인해야 한다. Step 6의 검증에서 이 필드를 쓰는 이유다.
  • 양쪽 자산 모두 매수자에게 TrustLine이 설정돼 있어야 한다.

STEP 06 x402 자율 결제 게이트웨이

메인넷 운영 중인 자율 결제 게이트웨이. 외부 AI 에이전트가 사람 개입 없이 HTTP 402 응답을 읽고, 온체인 결제 후 재요청해 데이터를 얻는다.

AI Agent x402 Gateway XRPL ① GET /api/data/aggregates (결제 헤더 없음) ② 402 Payment Required + 결제 조건 JSON ③ RLUSD·WLBN 호출당 결제 수취 → Hot Wallet (DestinationTag) ④ tesSUCCESS · tx_hash (3~5s finality) ⑤ 재요청 X-Payment-Tx: <tx_hash> ⑥ nonce 중복 확인 후 tx 조회 ⑦ Destination · Amount · tesSUCCESS ⑧ 200 OK + LLM 추론 결과 실패 시 → 409 (원장 미반영, Retry-After) / 402 (조건 불일치 · 해시 재사용)
Fig 3. x402 챌린지–결제–검증 시퀀스

1차 요청 — 402 챌린지

HTTP/1.1 402 Payment Requiredhttp

HTTP/1.1 402 Payment Required
Content-Type: application/json
WWW-Authenticate: x402 realm="wellbian-data", network="xrpl-mainnet"

{
  "x402Version": 1,
  "resource": "/api/data/aggregates",
  "accepts": [
    {
      "scheme": "xrpl-payment",
      "network": "xrpl-mainnet",
      "payTo": "rhTTtx8YyKzcmPDsoroYXuHdGMThrnweb1",
      "asset": { "currency": "WLBN", "issuer": "rDJz8WJhsKgydqJzSZXMpsJot3eRmSkR5", "value": "<수량>" },   // 수량 기준 단가 · RLUSD/법정화폐 환산 아님
      "destinationTag": 402001,
      "maxTimeoutSeconds": 120
    },
    {
      "scheme": "xrpl-payment",
      "network": "xrpl-mainnet",
      "payTo": "rhTTtx8YyKzcmPDsoroYXuHdGMThrnweb1",
      "asset": { "currency": "RLUSD", "issuer": "rMxCKbEDwqr76QuheSUMdEGf4B9xJ8m5De", "value": "0.002" },
      "destinationTag": 402001,
      "maxTimeoutSeconds": 120
    }
  ],
  "description": "Wellbian IAQ 집계 데이터 — 호출당 과금"
}

2차 요청 — 트랜잭션 검증

src/services/x402.tstypescript

import { getClient } from '../xrpl/client';
import { WLBN, RLUSD } from '../config/currency';
import { env } from '../config/env';

const usedHashes = new Set<string>();     // replace with Redis SETNX + TTL in production

export type VerifyResult =
  | { ok: true; currency: 'WLBN' | 'RLUSD'; value: string }
  | { ok: false; reason: string };

const PRICES = {
  [WLBN]:  { label: 'WLBN'  as const, min: Number(env.X402_PRICE_WLBN)  },
  [RLUSD]: { label: 'RLUSD' as const, min: Number(env.X402_PRICE_RLUSD) },
};

export async function verifyPayment(txHash: string): Promise<VerifyResult> {
  // 0) block reuse — stops unlimited calls with the same hash
  if (usedHashes.has(txHash)) return { ok: false, reason: 'HASH_ALREADY_USED' };

  const client = await getClient();
  let res;
  try {
    res = await client.request({ command: 'tx', transaction: txHash, binary: false });
  } catch {
    return { ok: false, reason: 'TX_NOT_FOUND' };   // may not have propagated yet → prompt a retry
  }

  const tx = res.result.tx_json ?? (res.result as never as Record<string, unknown>);
  const meta = res.result.meta as { TransactionResult: string; delivered_amount?: unknown };

  // 1) ledger finality + success
  if (res.result.validated !== true) return { ok: false, reason: 'NOT_VALIDATED' };
  if (meta.TransactionResult !== 'tesSUCCESS') return { ok: false, reason: meta.TransactionResult };
  if ((tx as { TransactionType: string }).TransactionType !== 'Payment')
    return { ok: false, reason: 'NOT_A_PAYMENT' };

  // 2) recipient matches
  if ((tx as { Destination: string }).Destination !== env.HOT_WALLET_ADDRESS)
    return { ok: false, reason: 'WRONG_DESTINATION' };

  // 3) check actual delivered amount — trust delivered_amount to block PartialPayment bypass
  const delivered = meta.delivered_amount as
    { currency: string; issuer: string; value: string } | string | undefined;
  if (!delivered || typeof delivered === 'string')
    return { ok: false, reason: 'XRP_NOT_ACCEPTED' };

  const price = PRICES[delivered.currency];
  if (!price) return { ok: false, reason: 'UNSUPPORTED_CURRENCY' };
  const EXPECTED_ISSUER = { [WLBN]: env.ISSUER_ADDRESS, [RLUSD]: env.RLUSD_ISSUER_ADDRESS };
  if (delivered.issuer !== EXPECTED_ISSUER[delivered.currency])
    return { ok: false, reason: 'WRONG_ISSUER' };
  if (Number(delivered.value) < price.min) return { ok: false, reason: 'INSUFFICIENT_AMOUNT' };

  usedHashes.add(txHash);
  return { ok: true, currency: price.label, value: delivered.value };
}

게이트웨이 미들웨어

src/api/middleware.x402.tstypescript

import { RequestHandler } from 'express';
import { verifyPayment } from '../services/x402';
import { buildChallenge } from '../services/x402.challenge';

export const x402Gate: RequestHandler = async (req, res, next) => {
  const payTx = req.header('x-payment-tx');            // 선불 크레딧은 x-api-key 경로로 별도 처리
  const match = payTx?.match(/^([A-F0-9]{64})$/i);

  if (!match) {
    res.setHeader('WWW-Authenticate', 'x402 realm="wellbian-data", network="xrpl-mainnet"');
    return res.status(402).json(buildChallenge(req.path));
  }

  const result = await verifyPayment(match[1]);
  if (!result.ok) {
    // not yet in the ledger → prompt retry; otherwise reissue 402
    const retryable = result.reason === 'TX_NOT_FOUND' || result.reason === 'NOT_VALIDATED';
    if (retryable) { res.setHeader('Retry-After', '3'); return res.status(409).json(result); }
    return res.status(402).json({ ...buildChallenge(req.path), error: result.reason });
  }

  res.setHeader('X-Payment-Response', JSON.stringify({ settled: true, ...result }));
  next();
};

AI 에이전트 클라이언트 예제

src/scripts/agent-example.tstypescript

import { getClient } from '../xrpl/client';
import { sendIOU } from '../xrpl/token';
import { agentWallet, env } from '../config/env';
import { toCurrencyHex } from '../config/currency';

const API = 'https://wellbian.io/api/data/aggregates';
const query = new URLSearchParams({ taxon: 'IAQ', geohash: 'wydm6', from: '2026-08-31T00:00:00+09:00', to: '2026-09-01T00:00:00+09:00' });

async function call(headers: Record<string, string> = {}) {
  return fetch(`${API}?${query}`, { method: 'GET', headers });
}

async function main() {
  // (1) call without payment → receive 402 + payment terms
  const challenge = await call();
  if (challenge.status !== 402) throw new Error(`expected 402, got ${challenge.status}`);
  const terms = await challenge.json();
  const option = terms.accepts.find((a: { asset: { currency: string } }) => a.asset.currency === 'WLBN');
  console.log('[agent] terms received:', option.asset.value, option.asset.currency);

  // (2) pay on-chain — the agent decides and pays on its own
  const client = await getClient();
  const tx = await sendIOU(
    client, agentWallet, option.payTo,
    { currency: toCurrencyHex(option.asset.currency), issuer: option.asset.issuer, value: option.asset.value },
    option.destinationTag,
  );
  const hash = tx.result.hash;
  console.log('[agent] payment settled:', hash);

  // (3) retry with tx_hash attached (retries absorb propagation delay)
  for (let i = 0; i < 5; i++) {
    const res = await call({ 'x-payment-tx': hash });
    if (res.status === 200) { console.log('[agent] response:', await res.json()); return; }
    if (res.status !== 409) throw new Error(`failed ${res.status}: ${await res.text()}`);
    await new Promise((r) => setTimeout(r, 3000));
  }
  throw new Error('verification timed out');
}

main().catch((e) => { console.error(e); process.exit(1); });

소각 정책 — 총 50억 · 수량과 트랜잭션 공개

예정 소각 25억(마일스톤 4회 분할)과 매입 소각 24.65억(사업 수익으로 시장에서 매입)을 합해 총 발행량의 50%를 소각한다. 여기에 품질 미달 재분배 초과분과 10단계 게이트 미통과 시 2기 리워드 18억이 더해진다. 소각은 IOU를 Issuer로 되돌리는 방식이며, 소각 수량과 트랜잭션은 사후 공표하고 매입 시점·가격은 공개하지 않는다.

src/services/burn.tstypescript

import { getClient } from '../xrpl/client';
import { sendIOU } from '../xrpl/token';
import { WLBN } from '../config/currency';
import { env, hotWallet, treasuryWallet } from '../config/env';

export type BurnReason = 'scheduled' | 'buyback' | 'quality-shortfall' | 'round2-unopened';

/** Return WLBN to the Issuer = burn. Quantity and tx hash are published; buyback timing/price are not. */
export async function burn(amountWlbn: string, reason: BurnReason) {
  if (Number(amountWlbn) <= 0) return { burned: '0' };
  const from = reason === 'quality-shortfall' ? hotWallet : treasuryWallet;
  const client = await getClient();
  const res = await sendIOU(client, from, env.ISSUER_ADDRESS, {
    currency: WLBN, issuer: env.ISSUER_ADDRESS, value: amountWlbn,
  });
  await publishBurn({ reason, amount: amountWlbn, tx: res.result.hash });   // 수량·tx만 공표
  return { burned: amountWlbn, txHash: res.result.hash };
}
XRPL의 "소각"은 스마트컨트랙트 burn과 다르다

IOU는 발행자의 부채 기록이다. 보유자가 발행자에게 되돌려 보내면 TrustLine 잔액이 상계되어 유통량이 실제로 감소한다. 별도의 burn 함수는 필요 없다. 다만 Issuer 계정이 여전히 DefaultRipple과 발행 권한을 갖고 있으므로 "재발행 불가"를 담보하려면 별도의 blackhole 계정(regular key를 rrrrrrrrrrrrrrrrrrrrrhoLvTp로 설정하고 마스터키 비활성화)을 쓰는 것이 더 강한 보증이다. 현재는 Issuer 반환에 의한 상계 방식을 사용하며, blackhole 계정 전환 여부는 별도로 고지한다.

운영 토크노믹스 정책

정량 지급 · 총량 100억 · 소각 50억. 본 절은 tokenomics.wellbianlabs.io에 공표된 정책과 동일하며, 수량만 정의하고 가치는 정의하지 않는다.

출금 개시 — 상장 전 시장가격 형성 차단

원칙 적립된 WLBN은 DEX 상장 전까지 온체인으로 이전되지 않는다. 정산은 매일 이뤄지고 수량은 계정에 그대로 쌓이지만, 실제 트랜잭션은 발생시키지 않는다. 사이트 계정 안의 포인트로만 존재한다.

이유 상장 전에 토큰이 유통되면 장외에서 가격이 먼저 형성된다. 유통량이 극히 적은 상태에서 만들어진 가격은 네트워크의 실제 가치를 반영하지 못하고, 최초 상장가의 기준을 왜곡한다. 출금을 묶어두는 것은 최초 상장 시점에 제 가치를 받기 위한 조치다.

보장 적립은 중단되지 않으며 쌓인 포인트는 절대 사라지지 않는다. 개시일은 재단이 정해 별도 공지하며, 개시 이후 보유 수량 전액을 온체인으로 인출할 수 있다.

우선순위 이 정책은 재단이 정한 최상위 정책으로, 지급·인출에 관한 다른 절의 서술에 우선한다.

단 하나의 원칙 — 정량 지급

약속하는 것
하루 7개
개수는 사전 공표한 그대로 지급한다. 시세가 오르내려도 지급 개수는 변하지 않으며, 총 방출량은 10단계 누적 26.65억개로 확정된다.
약속하지 않는 것
그 7개가 얼마인지
토큰의 가치를 보장하지도 증명하지도 않는다. 가격은 거래소에서 거래하는 참여자들이 정하며, 이 문서 어디에도 목표가·수익률·회수 기간은 없다.
항목금액 기준이었다면정량 지급 (WLBN)
지급 단위「하루 얼마어치」 — 개수가 매일 변동「하루 7개」 — 개수 고정
시세가 내리면지급 개수가 늘어남 — 방출 폭증·악순환개수 그대로 · 방출 불변
시세가 오르면지급 개수가 줄어 참여자 이득 없음개수 그대로 · 참여자 이득
총 방출량예측 불가10단계 누적 26.65억개 확정
대가의 성격가치 보장 암시데이터 제공에 대한 역무의 대가
WLBN 유통 공급량 관측 지점 확산 라이선스 NFT 1장 = 지점 1개 데이터 품질·밀도 ↑ 관측망 커버리지 확대 데이터 매출 ↑ 기업 고객 · AI 에이전트 결제 매입 소각 + 예정 소각 = 50억 유통량 감소 · 수량으로만 공표 관측 데이터 제출 일 7개 × 0.78^(단계−1) × 품질 등급 — 수량으로만 정의 데이터 상품성 향상 매출 일부로 WLBN 매입 소각 → 유통량 ↓ 보조금 → 고객 매출로 재원 전환 (자립)
Fig 4. 공급–수요–소각 순환 · 방출은 단계 체감, 소각은 매입·예정 분할

총량 100억 배분

버킷수량비중해제 조건 · 베스팅
노드 홀더 리워드 1기 (Phase 1~10)28억28%목표 유통량 규칙에 따라 에폭마다 방출
노드 홀더 리워드 2기 (Phase 11~)18억18%10단계 게이트 통과 시에만 개방 · 미통과 시 소각 전환
소각 예정25억25%마일스톤 분할 소각 · 매입 24.65억과 합해 총 50억
LP 리워드 (유동성 마이닝)8억8%수량 고정 지급 · 최소 예치 기간 · 조기 인출 시 몰수
팀 · 기여자6억6%12개월 클리프 + 48개월 선형 · 일정 전체 공개
생태계 · 지역 파트너5억5%권역 진입 마일스톤마다 조건부 해제
전략 투자 · 프라이빗5억5%6~12개월 클리프 + 24~36개월 베스팅 · TGE 언락 0
유동성 · 준비금5억5%AMM 시드와 매수벽 · 매입분은 전량 소각
합계100억100%제네시스 전량 발행 후 발행 권한 소각 — 추가 발행은 불가능하다

일일 리워드 — 단계마다 22% 체감

reward rulelog

daily reward  = base 7 × 0.78^(phase − 1) × quality grade (0 ~ 1.2)
epoch budget  = active points × 7.14 WLBN × phase factor

가격과 무관하게 수량만으로 정의된다. 단계는 연차가 아니라 지점 수와 수요 조건을 함께 만족하는 게이트로 넘어가며, 단계가 오를 때마다 지점당 수량이 22% 줄어든다.

단계일 기본월연1단계 대비단계 방출량참여 시점별 누적 수령
1 국내 실내7.00개213개2,555개100%0.64억10,646개 (제네시스)
34.26개130개1,554개61%1.87억6,098개 (57%)
52.59개79개946개37%3.31억3,331개 (31%)
71.58개48개575개23%3.74억1,647개 (15%)
100.75개23개273개11%2.73억—
10단계 누적26.65억리워드 1기 예산 28억 이내
제네시스의 이득은 수량으로만 말한다

제네시스 홀더는 7단계 참여자의 6.5배 수량을 받는다. 참여 기간이 길어서만이 아니라 단계마다 지급 수량 자체가 줄기 때문이다. 그 수량이 나중에 얼마가 될지는 말할 수 없다.

품질 게이트 — 예산은 고정, 배분은 경쟁

quality gatelog

first pass     normal 7 · excellent 8.4 · failing 0
redistribute   unpaid share pro rata by weight · cap 10.5 per point · excess burned
전송률 미달률유효 지점미지급분정상 최종우수 최종소각총 지급
0%1000개7.00개8.40개0개714개
10%9071.4개7.78개9.33개0개714개
20%80142.8개8.75개10.50개 (상한)0개714개
40%60285.6개10.50개10.50개84개630개

100지점 예시(예산 714 = 100 × 7.14). 모든 행에서 총 지급 + 소각 = 예산이다. 품질이 나쁠수록 총 방출이 줄어든다.

항목규칙
지급 조건전송률 95%+ 전액 · 80~95% 선형 감액 · 80% 미만 무지급
우수 보너스데이터 품질 상위 10%에 +1.4개 — 공기가 좋은 곳이 아니라 측정이 정확한 곳
품질 등급 산출전송률 게이트를 통과한 지점에 대해 품질 점수(가동률·이상치·인근 상관·보정)를 매기고, 상위 10%가 우수(1.2), 나머지가 정상(1.0), 게이트 미달이 0
부정 방지설치 사진은 진입 관문 · 지속 검증은 CO₂ 일주기 패턴
구현 상태 (2026-09)

현행 정산 엔진은 1단계 기준으로 지점당 일 7개를 적립하고 24시간 홀드 후 클레임한다. 우수 보너스(8.4)·미지급분 재분배·단계 계수 0.78은 본 정책의 확정 사항으로, 엔진의 거버넌스 변수로 순차 반영한다. 반영 전까지 실제 지급은 1차 지급 규칙(정상 7 · 미달 0)만 적용된다.

소각 50억 — 총 발행량의 절반

구분수량방식
예정 소각25억마일스톤 분할 · 사전 공표된 4회
매입 소각24.65억사업 수익으로 시장에서 매입 후 소각
합계50억총 발행량의 50%
원칙내용
목표 유통량 추종유통 비율 목표를 정하고, 넘으면 사들여 태운다
매입분 전량 소각되사서 다시 파는 구조는 방어가 아니라 자전거래다
품질 미달분 소각재분배 상한을 넘긴 물량은 지급하지 않고 소각한다
2기 미개방분 소각10단계 게이트 미통과 시 18억이 소각 대상으로 전환된다
사후 공표소각 수량과 트랜잭션을 공개한다 — 매입 시점과 가격은 공개하지 않는다

소각은 「이번 분기 방출 0.9억개 · 소각 1.1억개」처럼 수량으로만 공표한다. 「소각으로 가격이 오른다」는 말은 하지 않는다 — 검증할 수 없는 주장이기 때문이다.

마일스톤 게이트 — 연차가 아니라 달성으로

게이트공급 조건수요 조건보상 가중치소각거래소
G0 개시 전등록·검증 시스템유료 고객 1건——상장 금지
G1 제네시스 개시모집 시작—품질없음금지
G2 유동성 확보초기 물량 판매—품질없음금지
G3 수요 증명5,000장B2B 3건 + 재구매+ 희소성없음금지
G4 완판25,000장 · 가동률 80% 3개월국내 매출 발생품질 + 희소성없음DEX 개시
G5 해외 1호60,000해외 매출 발생동일없음지역 거래소 검토
G6 실외 라인12만연매출 10억+ 실사용없음—
G7 소각 개시22만연매출 20억3요소개시—
G8 전환기35만연매출 40억동일본격—
G9 자립65만사업 수익이 리워드 재원을 전액 부담동일가속글로벌 거래소 검토
G10 성숙100만잉여 수익 발생동일최대—

수요 조건을 못 채우면 다음 게이트가 열리지 않는다. 미달 시 대응은 단계 진입 보류와 방출 축소다.

보조금에서 고객 자금으로

국면지점단계 방출량재원
1~4단계2.5만 → 22만늘어남보조금 — 하드웨어 사업 수익이 부담
5~6단계35만 → 50만정점 후 감소전환기 — 데이터 매출이 상당 부분 부담
7단계~65만 →계속 감소자립 — 고객 매출이 전액 부담 · 잉여는 소각
왜 교차하는가

방출은 단계 체감 22% 때문에 6단계에서 정점을 찍고 줄어드는데 데이터 매출은 지점 수에 비례해 계속 늘어난다. 두 곡선이 만나는 지점부터 신규 참여금이 아니라 고객이 낸 돈으로 리워드를 지급한다. 자립 시점은 데이터 단가에 달려 있고, 그 단가는 아직 검증 중이다. 1단계에서 실제 계약으로 확인한 뒤 재산정하며, 달성을 약속하는 것이 아니라 목표로 제시한다.

제네시스 모집 구조

① 실물 기기
실내 날씨 측정기
PM · CO₂ · VOC · 온습도 측정 · 실물 자산으로 남는다
② 관측 지점 자격
민간기상스테이션 라이선스
NFT 1장 = 관측 지점 1개 · 권리 분리 판매 불가
③ 데이터 제공 리워드
일 7개 WLBN
품질 등급 반영 · 단계마다 22% 체감
④ 구매 순번
후속 프로젝트 우선 구매권
실외 라인 우선 제안 · 수익권이 아닌 순번이다
모집 트랙1인 물량25,000장 기준공략 대상
개인 50%1장12,500명가정 · 1인 가구 · 육아 가구
다지점 사업자 30%6장1,250명카페 · 학원 · 병원 · 헬스장 — 밀도의 핵심
기관 · 건물 20%40장125곳아파트 단지 · 학교 재단 · 오피스

1인당 보유 상한은 개인 5장 / 사업자 50장이다. 미설치 NFT는 리워드가 없다 — 보유가 아니라 가동이 조건이다.

운영 원칙과 공개 정책

유동성 투입 우선순위기간수혜
① 거래 깊이영구거래하는 모두
② 매입 소각영구남은 홀더 전원
③ 매수 완충일시그 순간 판 사람

참여금의 20%가 판매 즉시 유동성으로 들어간다. 결제 구조는 기업 고객 원화·RLUSD, AI 에이전트 자동 결제, 프로토콜 내부는 매출 일부로 WLBN 매입이다. 고객에게 토큰을 사서 결제하라고 요구하지 않으며, 배분 비율은 사전 공표한다.

항목공개비공개
유동성풀 잔고 온체인 상시 · 투입 규칙 · 소각 실적매수 주문 가격 · 매입 시점
베스팅일정 전체 · 언락 수량과 시점—
리워드지급 수량 · 품질 기준 · 재분배 결과—

공개된 매수 주문은 시장에 무료 풋옵션을 주는 것이라, 장기 홀더가 아닌 단기 트레이더에게 재원이 흘러간다. 하지 않는 다섯 가지: 노드 수를 KPI로 삼기 · 수요 없이 다음 단계 열기 · 조기 거래소 상장 · 모든 데이터에 같은 보상 · 보조금 영구화.

우리가 보는 지표는 토큰 가격이 아니라 완판 · 가동률 · 데이터 매출이다. 판매가 목표에 미달하면 가격을 방어하는 것이 아니라 방출을 줄인다.

운영 방출 시뮬레이션 — 단계 체감 모델

10단계 누적 방출과 자립 교차점을 단계 체감 모델로 계산한다. 모든 수치는 공표된 정책 파라미터(기본 7개 · 체감 0.78 · 게이트별 지점 수)에서 유도되며, 보상 수준이나 수익에 대한 예측·약속이 아니다. 실제 수령량은 품질 등급과 재분배 결과에 따라 달라진다.

결론 먼저

Finding 01
방출 정점은 6단계다
지점 수는 늘지만 지점당 수량이 단계마다 22% 줄어, 단계 방출량은 6단계(3.74억 부근)에서 정점을 찍고 감소한다. 데이터 매출은 지점 수에 비례해 계속 늘어난다.
Finding 02
제네시스 = 7단계의 6.5배 수량
1단계 참여자의 누적 수령은 10,646개, 7단계 진입자는 1,647개다. 차이는 참여 기간보다 단계별 지급 수량 감소에서 온다.
Finding 03
품질이 나쁠수록 총 방출이 준다
에폭 예산은 고정이지만 미지급분 재분배에 지점당 10.5개 상한이 걸려, 미달 지점이 40%면 예산의 12%가 소각된다. 총 지급 + 소각 = 예산.
Finding 04
수요가 없으면 방출도 없다
단계 진입은 지점 수와 수요 조건을 동시에 요구한다. 수요 미달 시 단계를 보류하고 방출을 줄이므로, 노드가 먼저 늘어 공급이 앞서는 상황이 구조적으로 막힌다.

모델 구조

core model equationslog

reward(p, g)   = 7 × 0.78^(p − 1) × g               g ∈ { 0, 1.0, 1.2 }
budget(p, n)   = n_active × 7.14 × 0.78^(p − 1)       fixed per epoch
redistribute   = unpaid × w_i / Σw                     cap 10.5 per point · excess → burn
emission(p)    = Σ_epochs budget(p, n) − burn(p)
Σ p=1..10      = 2.665B  ≤  2.8B (round-1 reward bucket)

확정 파라미터

항목확정값근거
기본 리워드일 7개 (정상 등급)사전 공표 수량 · 시세와 무관
단계 체감0.78 (22%)10단계 누적을 리워드 1기 예산 28억 이내로 맞추는 값
품질 등급0 · 1.0 · 1.2미달 · 정상 · 우수(상위 10%, +1.4개)
재분배 상한지점당 10.5개소수 독점 방지 · 초과분 소각
1단계 지점 수25,000국내 실내 · 제네시스 한정 모집
10단계 누적 상한26.65억개리워드 1기 버킷 28억 이내
2기 리워드18억10단계 게이트 통과 시에만 개방 · 미통과 시 소각
전제를 밝힌다

자립 시점은 데이터 단가에 달려 있고, 그 단가는 아직 검증 중이다. 1단계에서 실제 계약으로 확인한 뒤 재산정한다. 표의 값은 위 식에 게이트별 지점 수를 대입해 얻으며 공표 데크와 동일하다. 달성을 약속하는 것이 아니라 목표로 제시한다.

운영 잔여 리스크

구현 중 인지하고 관리해야 할 항목들.

항목리스크대응우선순위
기기 신원 NFT 보유만 검증하면 시드 탈취 시 위조 데이터 무제한 주입 페이로드 서명 검증 + 시계열 이상탐지 + 인근 노드 교차검증권장
오라클 신뢰 오프체인 API가 단일 신뢰점 — 데이터가 원장에 남지 않음 배치 단위 머클루트를 Memos에 기록해 사후 감사 가능성 확보권장
Reserve 고갈 TrustLine·Offer 누적으로 Hot wallet XRP 부족 → 전 트랜잭션 실패 잔액 임계 모니터링 + 미체결 Offer 정리 배치권장
가격 변동받는 수량은 고정이지만 그 수량의 가치는 오르내린다. 하락 위험은 전적으로 보유자가 부담한다정량 지급 · 가치 보장 없음 · 목표가·수익률 미제시인지
사업 미달데이터가 팔리지 않으면 다음 단계가 열리지 않고 리워드 수량이 줄어든다게이트에 수요 조건 병기 · 미달 시 방출 축소필수
가동 의무미설치·미가동 지점은 리워드가 지급되지 않는다. 전송률 80% 미만도 무지급이다등급별 차등 · 사전 공표된 기준 · 설치 사진과 CO₂ 일주기 검증필수
초기 거래 여건개시 직후에는 거래가 얕아 적은 거래로도 시세가 크게 움직일 수 있다유동성 깊이 우선 투입 · 대량 거래 분리 · 조기 상장 금지권장
실내 데이터 민감성 CO₂·PM 시계열에서 재실 인원·취침 시각·부재 기간이 추정됨 5단계 비식별화 + k-익명성 + 차분 공격 방어. 개인정보 법률 검토 선행 필수필수
규제 변화가상자산 규제는 관할마다 다르고 바뀐다법률 의견서 확보 후 각 권역 진입 · 유틸리티 성격 유지(지분·배당 없음)필수
핫월렛 키 관리Hot Wallet 시드 유출 시 보상 풀 잔액이 즉시 유출됨KMS 기반 서명 분리 · 잔액 상한 유지 · Issuer(cold) 시드는 런타임 미로드필수
RLUSD 발행자 의존RLUSD 발행자(rMxCK…)의 동결·정책 변경이 결제·정산 경로를 차단할 수 있음TrustLine 상태 모니터링 + 대체 결제 통화 경로 사전 정의권장
아웃박스 중복 지급크론 재시작 시 미확정 트랜잭션을 재제출하면 이중 지급 위험아웃박스 멱등키 + 제출 전 tx 조회 + reconcile 크론 대조필수
클레임 홀드 중 장애24시간 홀드 구간에서 정산 장애가 나면 적립분이 클레임 불가 상태로 남음적립 원장과 온체인 결과를 reconcile 크론이 대조해 미지급분 자동 복구필수
센서 캘리브레이션 드리프트 저가 MOX·광산란 센서는 수개월 단위로 편차가 누적되어 데이터 상품성이 하락 품질 점수의 calibration(15점) 항목 + 인근 노드 상관 기반 자동 보정 계수권장
x402 요청 헤더 본 구현은 X-Payment-Tx: <hash> 커스텀 헤더를 쓰며, 선불 크레딧(X-Api-Key · /api/data/topup) 경로를 병행한다 표준 x402는 X-PAYMENT 헤더를 쓴다. 응답 바디는 이미 표준 스키마이므로, 헤더만 교체하면 정합 완료인지

운영 실행 체크리스트

각 Step은 승인 후 다음 단계로 진행한다. 완료 판정 기준을 함께 명시했다.

Step 1 — XRPL 기반 & 지갑

  • 메인넷 WebSocket(wss://xrplcluster.com) 클라이언트 싱글턴 + 재연결 처리
    완료 기준: server_info 응답 수신
  • Issuer(cold, rDJz8…) / Hot(rhTTt…) / Treasury(rPZFY…) 3개 지갑 준비 및 XRP Reserve 확보
  • .env + .env.example 구성, .gitignore 등록, zod 검증
  • 공통 submit() 래퍼로 tesSUCCESS + validated 강제

Step 2 — Wellbian 토큰

  • currency hex 상수 확정 (WLBN / RLUSD)
  • Issuer AccountSet — asfDefaultRipple 활성화
  • Hot·Treasury·사용자 지갑 TrustSet — tfSetNoRipple 적용
  • 총 100억 WLBN 발행 완료 확인 (추가 발행 없음)
    완료 기준: account_lines에서 잔액 확인

Step 3 — 라이선스 NFT

  • IPFS 메타데이터 스키마 확정 및 업로드 (실 URI 고정)
  • mintLicense → offerLicenseTo → acceptLicense 전체 흐름
  • verifyDeviceLicense() — Issuer + Taxon 이중 확인
  • 미보유 주소가 valid:false로 판정되는 네거티브 테스트

Step 4 — 오라클 & 보상

  • GET /v1/c 수집 프록시 구현 + 5단계 수신 검증
  • 기기 서명 검증 → 라이선스 조회 순서 준수 (싼 검사 우선)
  • 라이선스 검증 실패 시 403, 보상 미지급 확인
  • 절대습도·이슬점 유도 후 저장
    완료 기준: absoluteHumidity(20,60)≈10.35, (30,60)≈18.21
  • 일 정산 — 총 지급 + 소각 = 에폭 예산(활성 지점 × 7.14 × 단계 계수), 지점당 10.5개 이내
    완료 기준: 전송률 미달 지점 비율을 0~40%로 바꿔도 총 지급 + 소각 = 예산
  • 클레임 API — 24시간 홀드 경과분만 1건의 WLBN Payment로 합산 지급
  • reconcile 크론 — 온체인 결과와 적립·지급 원장 대조, 불일치 자동 복구
  • 배치 머클루트를 Memos에 기록, 머클 증명 검증
  • 핫월렛 아웃박스 패턴 적용 · 크론 중단 후 재개 검증
    완료 기준: 재개 시 중복 지급 0건, Sequence 오류 0건

Step 5 — AMM

  • AMMCreate WLBN/RLUSD 메인넷 풀 생성 완료 (TradingFee 0.5%, 스왑 전용)
  • AMMDeposit 추가 유동성 공급 및 LPToken 수령 확인
  • path_find + SendMax 기반 RLUSD→WLBN 스왑
  • 스왑 전후 amm_info 풀 비율 변화 기록

Step 6 — x402 게이트웨이

  • 헤더 없는 요청 → 402 + accepts 배열 결제 조건
  • verifyPayment() — 수취인·발행자·통화·전달액·tesSUCCESS 검증
  • delivered_amount 기반 판정 (PartialPayment 방어)
  • tx_hash 재사용 차단 nonce 스토어
  • 에이전트 E2E(메인넷 실결제): 402 → 결제 → 재요청 → 200
    완료 기준: 스크립트 1회 실행으로 전 과정 무인 완료
  • 소각 배치 잡(예정 · 매입 · 품질 미달분) 실행 및 소각 수량·tx 공표, 유통량 감소 검증

IAQ 사양 — 데이터 계층

  • IAQ 텔레메트리 스키마 v1 확정 + 기기 서명 규격
  • Taxon 분리 (IAQ 3026 / OAQ 2026), 품질 등급(0 · 1.0 · 1.2) 적용
  • qualityScore() 4개 항목 산출 — 특히 인근 노드 상관
  • 비식별화 P1~P5 파이프라인, 에폭 salt 회전 확인
  • k-익명성 롤업 — geohash3에서도 미달 시 응답 거부
    완료 기준: 노드 4개 격자 질의가 상위 격자로 롤업되거나 거부됨
  • 차분 공격 방어 4종 (반올림·필터 상한·질의 예산·최소 코호트)
  • 코호트 응답에 노드 목록이 포함되지 않음을 스키마 레벨에서 보장
  • 선불 크레딧 — 충전·서명 차감·nonce 단조 증가
    완료 기준: 동일 nonce 재전송이 BAD_NONCE로 거부됨
  • 미지급분 재분배 — 지점당 10.5개 상한, 초과분 소각 검증
운영 검증 시나리오
  1. 미인가 주소로 IAQ 텔레메트리 전송 → 403 (라이선스 없음)
  2. NFT 발급 후 동일 주소 재전송 → 202 Accepted, 절대습도 유도값 확인
  3. 에폭 배치 실행 → 노드별 품질 점수와 가중치 배분 출력, 총액 = 예산 확인
  4. 노드 수를 10배로 복제 후 재실행 → 예산 = 활성 지점 × 7.14 × 단계 계수로 비례 증가, 지점당 수량 불변
  5. 제조사가 코호트 질의 → 402, 결제 후 재요청 → 200 + 크기만 반환
  6. 필터를 좁혀 재질의 → 422 COHORT_TOO_NARROW (실제 크기 미노출)
  7. 같은 tx_hash로 재호출 → 402 (HASH_ALREADY_USED)
  8. 소각 배치 → Issuer TrustLine 상계로 유통량 감소 확인

운영 용어집

용어설명
DePINDecentralized Physical Infrastructure Network. 물리 인프라(센서·기지국 등)의 구축·운영을 토큰 인센티브로 분산화하는 모델.
XLS-20XRPL의 네이티브 NFT 표준. NFTokenMint 등 전용 트랜잭션 타입을 제공하며 스마트컨트랙트가 불필요하다.
XLS-30XRPL 네이티브 AMM 표준. 오더북과 AMM 유동성이 자동으로 합산 라우팅된다.
Issued Asset (IOU)발행자 계정에 대한 채권 형태의 토큰. 별도 mint 트랜잭션 없이 발행자가 Payment를 보내면 생성된다.
TrustLine보유자가 특정 발행자의 특정 통화를 얼마까지 받을지 선언하는 온체인 관계. 없으면 tecNO_LINE.
Rippling동일 통화의 TrustLine들을 연결해 잔액이 자동 이동하는 XRPL 고유 메커니즘. 발행자 경유 전송의 기반이자 오남용 위험 요소.
x402HTTP 402 Payment Required를 실사용하는 M2M 결제 프로토콜. 서버가 결제 조건을 제시하고 클라이언트가 온체인 결제 증빙을 붙여 재요청한다.
delivered_amount트랜잭션 메타데이터에 기록된 실제 전달 금액. PartialPayment 우회를 막기 위해 검증은 이 값으로만 수행한다.
Destination TagPayment에 붙이는 32비트 정수 식별자. 동일 수취 주소로 들어오는 결제의 용도·고객을 구분한다.
IAQIndoor Air Quality. 실내 날씨(날씨). 본 문서에서는 PM2.5·PM10·CO₂·TVOC·온도·습도 6종 지표의 총칭.
절대습도 (AH)단위 부피당 실제 수증기 질량(g/m³). 온도 종속인 상대습도와 달리 제습 부하를 직접 나타내므로, 제습 알고리즘·결로 예측의 입력값이 된다.
TVOC총휘발성유기화합물. MOX 센서는 상대 지수를 내므로 절대 농도로 해석하지 않고 추세·급변 탐지에 사용한다.
geohash위경도를 문자열로 인코딩하는 격자 체계. 자릿수가 짧을수록 넓은 영역을 뜻한다 (5자리 ≈ 4.9km, 3자리 ≈ 156km).
k-익명성어떤 속성 조합으로도 최소 k명 미만으로 좁혀지지 않도록 보장하는 성질. 본 사양은 k=5를 하한, 반올림 후 25를 실질 하한으로 둔다.
차분 공격필터를 조금씩 바꾼 반복 질의의 결과 차이로 개별 대상을 분리해내는 공격. 카운트 반올림·필터 개수 상한·질의 예산으로 방어한다.
에폭 (Epoch)보상 정산 주기. KST 자정을 경계로 하는 1일 고정 단위이며, 이 단위로 에폭 예산(활성 지점 × 7.14 × 단계 계수)을 품질 등급에 따라 지급·재분배한다.
선불 크레딧온체인 결제 1건으로 잔액을 충전하고 이후 호출은 서명으로만 차감하는 방식. 고빈도 API에서 원장 확정 지연을 회피한다.
RLUSD본 생태계의 정산 통화. 발행자는 rMxCKbEDwqr76QuheSUMdEGf4B9xJ8m5De이며 WLBN Issuer와 다르다.
Issuer · Hot · Treasury 지갑Issuer(cold, rDJz8WJhsKgydqJzSZXMpsJot3eRmSkR5)는 발행 전용으로 런타임 미로드, Hot(rhTTtx8YyKzcmPDsoroYXuHdGMThrnweb1)은 지급·수취, Treasury(rPZFY2yLgqjmBrxtxWHXnB1doBt7gu7xin)는 보관을 담당한다.
클레임 홀드에폭 정산으로 적립된 보상이 클레임 가능해지기까지의 24시간 대기 구간. 홀드 경과분은 1건의 WLBN Payment로 합산 지급된다.
아웃박스 패턴핫월렛 트랜잭션을 먼저 아웃박스에 기록하고 단일 워커가 순차 제출하는 방식. 크론이 중단돼도 미완료 항목부터 재개해 이중 지급을 막는다.
Taxon 체계관측소 1001·1002·1003, 스테이션 IAQ 3026 · OAQ 2026 · AI 인프라 4026 · 레이더 5026 · 위성 6026, 예매권 1010.
지원 지갑간편지갑(아이디·비밀번호 / 구글), D'CENT 모바일 인앱, Xaman, GemWallet, Crossmark.
단계 (Phase) · 단계 계수지점 수와 수요 조건을 함께 만족하는 게이트로 넘어가는 방출 구간. 단계 계수 0.78^(단계−1)이 지점당 수량에 곱해져 단계마다 22% 체감한다.
품질 등급전송률 게이트와 품질 점수로 정해지는 0 · 1.0 · 1.2의 계수. 미달 0, 정상 1.0(일 7개), 상위 10% 우수 1.2(일 8.4개).
재분배에폭 예산 중 1차 지급 후 남은 미지급분을 가중치 비례로 나누는 절차. 지점당 10.5개를 상한으로 하고 초과분은 소각해 총 지급 + 소각 = 예산을 유지한다.
마일스톤 게이트G0~G10의 단계 진입 조건. 공급(지점 수·가동률)과 수요(유료 고객·매출) 조건을 병기하며, 수요 미달 시 단계를 보류하고 방출을 줄인다.
매입 소각사업 수익으로 시장에서 WLBN을 매입해 Issuer로 되돌리는 소각. 매입분은 전량 소각하며 수량·트랜잭션만 공표하고 시점·가격은 공개하지 않는다.
목표 유통량 추종유통 비율 목표를 정하고 이를 넘으면 매입·소각으로 되돌리는 운영 규칙. 소각 총량 50억(예정 25억 + 매입 24.65억)의 집행 기준이다.
Blackhole 계정Regular Key를 무효 주소로 설정하고 마스터키를 비활성화해 영구히 서명 불가하게 만든 계정. 본 시스템의 Issuer는 blackhole이 아니며, 소각은 Issuer 반환에 의한 상계 방식이다.