— ON-CHAIN ACCOUNT VALUE PROTOCOL —
A slot is not just a login key. A slot is the account itself — and every content token consumed within it permanently proves its value on-chain, transparently. 슬롯은 단순한 로그인 키가 아닙니다. 슬롯은 계정 그 자체이며, 그 안의 컨텐츠 토큰 소비 기록은 계정의 가치를 온체인에서 투명하게 증명합니다.
DeOAuth's Content Token system works just like in-app purchases on the Google Play Store. Every time a user buys an item in-game, that spending record (used_balances) is accumulated on-chain — permanently, immutably, and publicly queryable by anyone.
DeOAuth의 컨텐츠 토큰 시스템은 구글 플레이스토어의 인앱 결제와 동일한 개념입니다. 사용자가 게임에서 아이템을 구매할 때마다 그 소비 기록(used_balances)이 온체인에 누적됩니다. 이 누적값은 영구적이고 불변이며, 외부에서 누구나 조회할 수 있습니다.
To participate in the Content Token system, your application must first be tied to a verified owner. There is no public REST endpoint for provider registration. It is currently done in the Developer Center with Verify Ownership, which proves ownership with your developer AA wallet. 컨텐츠 토큰 시스템에 참여하려면 먼저 앱이 인증된 소유자와 연결되어 있어야 합니다. Provider 등록용 공개 REST 엔드포인트는 없습니다. 현재는 개발자센터의 Verify Ownership(소유권 인증)으로 처리하며, 개발자 AA 지갑으로 소유권을 증명합니다.
| Step | Where | What happens |
|---|---|---|
| 1 | Sign up회원가입 | Verify your email and set a 6-digit PIN. Your developer AA wallet is created automatically.이메일 인증 후 6자리 PIN 을 정하면 개발자 AA 지갑이 자동으로 만들어집니다. |
| 2 | Register App | Register your application and receive its client_id.앱을 등록하고 client_id 를 받습니다. |
| 3 | My Applications → Verify Ownership | Enter your PIN. The platform checks it against your AA wallet and records the wallet as the app owner (OWNER VERIFIED (AA) badge).PIN 을 입력하면 플랫폼이 AA 지갑으로 검증한 뒤 그 지갑을 앱 소유자로 기록합니다(OWNER VERIFIED (AA) 배지). |
| 4 | My Applications → ⛓ Register on-chain | Enter your PIN again. The platform registers the provider on the contract on your behalf, and the on-chain owner is your developer AA wallet (ON-CHAIN badge).PIN 을 한 번 더 입력하면 플랫폼이 대신 컨트랙트에 Provider 를 등록합니다. 온체인 owner 는 개발자 AA 지갑입니다(ON-CHAIN 배지). |
A cuid is a content identifier issued by the Provider. When a single Provider operates multiple games, each game uses its own cuid. The slot's used_balances is tracked per cuid.
cuid는 Provider가 발급하는 컨텐츠 식별자입니다. 하나의 Provider가 여러 게임을 운영할 때 각 게임마다 별도 cuid를 사용합니다. 슬롯의 used_balances는 cuid 단위로 추적됩니다.
You do not call the contract yourself and you do not need MetaMask. When you press Register on-chain, the platform key sends init_permission_provider(owner, provider, cuid) with owner set to your developer AA wallet address. Only the platform can register a provider, so nobody can claim your app's slot on the contract first.
컨트랙트를 직접 호출하지 않으며 MetaMask 도 필요 없습니다. Register on-chain 을 누르면 플랫폼 키가 owner 를 개발자 AA 지갑 주소로 넣어 init_permission_provider(owner, provider, cuid) 를 보냅니다. Provider 등록은 플랫폼만 할 수 있어 다른 사람이 내 앱 자리를 컨트랙트에 먼저 차지할 수 없습니다.
Order matters. Verify Ownership first, then Register on-chain. Apps registered before developer wallets existed have no owner record, so set up your wallet and run both steps once per existing app. Card sales and payouts for registered apps appear in the Settlements menu. 순서가 중요합니다. 먼저 Verify Ownership, 그다음 Register on-chain 입니다. 개발자 지갑 도입 전에 등록한 앱은 소유자 기록이 없으므로, 지갑을 설정한 뒤 기존 앱마다 두 단계를 한 번씩 실행하세요. 등록된 앱의 카드 매출과 지급 내역은 정산 메뉴에서 볼 수 있습니다.
buy_content_token
컨텐츠 토큰 구매 — buy_content_token
When a user pays XOTN, the smart contract instantly distributes revenue to Platform and Provider, then issues content tokens to the slot. 사용자가 XOTN을 지불하면, 스마트 컨트랙트가 즉시 Platform과 Provider에게 수익을 분배하고, 슬롯에 컨텐츠 토큰을 발급합니다.
| Parameter | Type | Required | Description |
|---|---|---|---|
| client_id | string | Required | Provider client IDProvider 클라이언트 ID |
| user_dbkey | string | Required | User DB key (slot identifier)사용자 DB 키 (슬롯 식별자) |
| amount | string | Required | XOTN amount to pay (wei or ether string)구매할 XOTN 금액 (단위: wei 또는 ether string) |
| cuid | string | Required | Content unique identifier컨텐츠 고유 식별자 |
// Buy content token — user pays 0.01 XOTN | 컨텐츠 토큰 구매 — 사용자가 0.01 XOTN 지불
const response = await fetch('/v1/development-api/user_buy_content_token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
client_id: 'your-client-id',
user_dbkey: 'user-uuid-12345',
amount: '10000000000000000', // 0.01 XOTN (wei)
cuid: 'game-rpg-2026'
})
});
const data = await response.json();
// data.tx_hash — purchase transaction hash | 구매 트랜잭션 해시
// data.token_amount — content tokens issued | 지급된 컨텐츠 토큰 수량
curl -X POST /v1/development-api/user_buy_content_token \
-H "Content-Type: application/json" \
-d '{
"client_id": "your-client-id",
"user_dbkey": "user-uuid-12345",
"amount": "10000000000000000",
"cuid": "game-rpg-2026"
}'
{
"success": true,
"tx_hash": "0x1a2b3c4d5e6f...",
"token_amount": "100",
"xotn_paid": "10000000000000000",
"platform_fee": "1500000000000000",
"provider_received": "8500000000000000"
}
increaseUsedBal
소비 기록 — increaseUsedBal
increaseUsedBal.increaseUsedBal을 호출하세요.
Called from the Provider's server when a user consumes in-game items. Deducts from the content token balance while permanently accumulating the same amount in used_balances.
사용자가 게임 내 아이템을 소비할 때 Provider 서버에서 호출합니다. 컨텐츠 토큰 잔액에서 차감되며, 동시에 used_balances에 같은 금액이 영구 누적됩니다.
| Parameter | Type | Required | Description |
|---|---|---|---|
| client_id | string | Required | Provider client IDProvider 클라이언트 ID |
| user_dbkey | string | Required | User DB key (slot identifier)사용자 DB 키 (슬롯 식별자) |
| amount | string | Required | Content token amount to consume소비할 컨텐츠 토큰 수량 |
| cuid | string | Required | Content unique identifier컨텐츠 고유 식별자 |
| encrypted_message | string | Required | AES-256-CTR encrypted payloadAES-256-CTR 암호화된 페이로드 |
increaseUsedBal must never be called directly from the client (browser/app). It must be called from the Provider's backend server with an AES-256-CTR encrypted payload. If the encryption key is exposed, spending records can be arbitrarily manipulated.
increaseUsedBal은 클라이언트(브라우저/앱)에서 직접 호출해서는 안 됩니다. Provider의 백엔드 서버에서 AES-256-CTR 암호화 페이로드와 함께 호출해야 합니다. 암호화 키가 노출되면 임의 소비 기록 조작이 가능합니다.
// Record spending — user consumes 100 tokens on item (called from Provider server)
// 소비 기록 — 사용자가 아이템 100토큰 소비 (Provider 서버에서 호출)
import crypto from 'crypto';
function encryptPayload(payload, key, iv) {
// AES-256-CTR encryption | AES-256-CTR 암호화
const cipher = crypto.createCipheriv('aes-256-ctr',
Buffer.from(key, 'hex'),
Buffer.from(iv, 'hex')
);
let encrypted = cipher.update(JSON.stringify(payload), 'utf8', 'hex');
encrypted += cipher.final('hex');
return encrypted;
}
const payload = {
client_id: 'your-client-id',
user_dbkey: 'user-uuid-12345',
amount: '100', // token amount to consume | 소비할 토큰 수량
cuid: 'game-rpg-2026'
};
const response = await fetch('/v1/development-api/increase_used_content_token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
encrypted_message: encryptPayload(payload,
process.env.DEAUTH_KEY,
process.env.DEAUTH_IV
)
})
});
// After this call: slot's used_balances += 100 (permanently recorded on-chain)
// 이 호출 후 슬롯의 used_balances += 100 (온체인에 영구 기록)
balanceAdex
계정 가치 조회 — balanceAdex
When trading accounts on a marketplace, buyers can verify a slot's investment history through balanceAdex — no login required.
마켓플레이스에서 계정을 거래할 때, 구매자는 balanceAdex를 통해 로그인 없이도 계정의 투자 내역을 검증할 수 있습니다.
(balance, used_balances)// Public query — no auth required, anyone can call | 공개 조회 — 인증 불필요, 누구나 호출 가능
const slotAddress = '0xUserSlotAddress...';
const response = await fetch(
`/v1/development-api/balance_adex/${slotAddress}`
);
const data = await response.json();
// data.balance — current content token balance | 현재 컨텐츠 토큰 잔액
// data.used_balances — total spent (= account investment history) | 총 소비 누적값 (= 계정 투자 내역)
console.log(`Balance: ${data.balance} tokens`); // 잔액
console.log(`Total invested: ${data.used_balances} tokens spent`); // 총 투자
{
"success": true,
"slot": "0xUserSlotAddress...",
"balance": "900",
"used_balances": "3200",
"cuid": "game-rpg-2026"
}
Account trading platforms can use balanceAdex to automatically estimate account value.
계정 거래 플랫폼에서 balanceAdex를 활용해 계정 가치를 자동 산정할 수 있습니다.
// Marketplace — auto-estimate account price | 마켓플레이스 — 계정 가격 자동 산정
async function estimateAccountValue(slotAddress, pricePerToken = 0.001) {
const { used_balances } = await fetchBalanceAdex(slotAddress);
// Minimum guaranteed value based on spending history | 소비 기록 기반 최소 보증 가치 산정
const minGuaranteedValue = Number(used_balances) * pricePerToken;
return {
used_balances,
min_value_xotn: minGuaranteedValue,
verified: true, // on-chain verified | 온체인 검증 완료
requires_login: false // no login needed | 로그인 불필요
};
}
releaseUsedBal
Provider 정산 — releaseUsedBal
Providers can receive additional settlement through releaseUsedBal, based on the slot's used_balances. This is a separate settlement mechanism from the 85% revenue share at purchase time.
Provider는 releaseUsedBal을 통해 슬롯의 used_balances를 기반으로 추가 정산을 받을 수 있습니다. 이는 구매 시점의 수익 분배(85%)와는 별도의 정산 메커니즘입니다.
releaseUsedBal only works when the Platform sets _cuid_releaseTokenEnabled[cuid] = true for that cuid. Disabled by default. Contact the AltsCodex admin team to request activation.
releaseUsedBal은 Platform이 해당 cuid에 대해 _cuid_releaseTokenEnabled[cuid] = true로 설정한 경우에만 동작합니다. 기본값은 비활성화입니다. 활성화 요청은 AltsCodex 관리팀에 문의하세요.
| Parameter | Type | Required | Description |
|---|---|---|---|
| client_id | string | Required | Provider client IDProvider 클라이언트 ID |
| cuid | string | Required | Content unique identifier컨텐츠 고유 식별자 |
| slot | string | Required | Target slot address for settlement정산 대상 슬롯 주소 |
// Provider settlement call | Provider 정산 호출
const response = await fetch('/v1/development-api/release_used_balance', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
client_id: 'your-client-id',
cuid: 'game-rpg-2026',
slot: '0xUserSlotAddress...'
})
});
const data = await response.json();
// data.released_amount — settled token amount | 정산된 토큰 수량
// data.tx_hash — settlement transaction hash | 정산 트랜잭션 해시
The complete flow from content token issuance to account value verification. 컨텐츠 토큰의 발급부터 계정 가치 검증까지 전체 흐름입니다.
Sensitive API calls like increaseUsedBal require AES-256-CTR encryption. Use the DEAUTH_KEY (32 bytes) and DEAUTH_IV (16 bytes) issued at Provider registration.
increaseUsedBal 등 민감한 API 호출에는 AES-256-CTR 암호화가 필요합니다. Provider 등록 시 발급되는 DEAUTH_KEY(32바이트)와 DEAUTH_IV(16바이트)를 사용합니다.
Store encryption keys and IVs in environment variables or a secrets manager (AWS Secrets Manager, HashiCorp Vault). Never hardcode them in client code or commit them to version control. 암호화 키와 IV는 반드시 환경변수 또는 시크릿 매니저(AWS Secrets Manager, HashiCorp Vault)에 저장하세요. 클라이언트 코드에 하드코딩하거나 버전 관리에 커밋하지 마세요.
// Node.js — AES-256-CTR Encryption | AES-256-CTR 암호화
import crypto from 'crypto';
/**
* Encrypts a JSON payload with AES-256-CTR.
* AES-256-CTR로 JSON 페이로드를 암호화합니다.
* @param {object} payload - object to encrypt | 암호화할 객체
* @param {string} key - 32-byte hex key (DEAUTH_KEY) | 32바이트 hex 키
* @param {string} iv - 16-byte hex IV (DEAUTH_IV) | 16바이트 hex IV
* @returns {string} hex-encoded encrypted string | hex 인코딩된 암호화 문자열
*/
function encryptPayload(payload, key, iv) {
const cipher = crypto.createCipheriv('aes-256-ctr',
Buffer.from(key, 'hex'),
Buffer.from(iv, 'hex')
);
let encrypted = cipher.update(JSON.stringify(payload), 'utf8', 'hex');
encrypted += cipher.final('hex');
return encrypted;
}
// Usage example | 사용 예시
const encrypted = encryptPayload(
{ client_id: 'xxx', user_dbkey: 'yyy', amount: '100', cuid: 'game-rpg-2026' },
process.env.DEAUTH_KEY,
process.env.DEAUTH_IV
);
# Python — AES-256-CTR Encryption | AES-256-CTR 암호화
# pip install pycryptodome
import json
from Crypto.Cipher import AES
import binascii
def encrypt_payload(payload: dict, key: str, iv: str) -> str:
"""
Encrypts a dict payload with AES-256-CTR.
AES-256-CTR로 dict 페이로드를 암호화합니다.
key: 32-byte hex string | 32바이트 hex 문자열
iv: 16-byte hex string | 16바이트 hex 문자열
"""
key_bytes = bytes.fromhex(key)
iv_bytes = bytes.fromhex(iv)
cipher = AES.new(key_bytes, AES.MODE_CTR,
nonce=iv_bytes[:8], # CTR nonce (8 bytes)
initial_value=iv_bytes[8:]) # counter initial value | 카운터 초기값
plaintext = json.dumps(payload).encode('utf-8')
encrypted = cipher.encrypt(plaintext)
return binascii.hexlify(encrypted).decode('ascii')
# Usage example | 사용 예시
encrypted = encrypt_payload(
{'client_id': 'xxx', 'user_dbkey': 'yyy', 'amount': '100', 'cuid': 'game-rpg-2026'},
os.environ['DEAUTH_KEY'],
os.environ['DEAUTH_IV']
)
// Verify encryption implementation against server result | 암호화 구현 검증 — 서버의 암호화 결과와 비교
async function verifyEncryption(testString) {
// 1. Encrypt on server | 서버에서 암호화
const serverRes = await fetch('/v1/development-api/test_encryption', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
client_id: 'your-client-id',
test_string: testString
})
});
const { encrypted_string: serverEncrypted } = await serverRes.json();
// 2. Encrypt locally | 로컬에서 암호화
const localEncrypted = encryptPayload(
testString,
process.env.DEAUTH_KEY,
process.env.DEAUTH_IV
);
// 3. Compare | 비교
const matches = localEncrypted === serverEncrypted;
console.log('Verify:', matches ? '✅ Match' : '❌ Mismatch'); // 암호화 검증
return matches;
}
await verifyEncryption('Hello DeOAuth');