DChain single-node blockchain + React Native messenger client. Core: - PBFT consensus with multi-sig validator admission + equivocation slashing - BadgerDB + schema migration scaffold (CurrentSchemaVersion=0) - libp2p gossipsub (tx/v1, blocks/v1, relay/v1, version/v1) - Native Go contracts (username_registry) alongside WASM (wazero) - WebSocket gateway with topic-based fanout + Ed25519-nonce auth - Relay mailbox with NaCl envelope encryption (X25519 + Ed25519) - Prometheus /metrics, per-IP rate limit, body-size cap Deployment: - Single-node compose (deploy/single/) with Caddy TLS + optional Prometheus - 3-node dev compose (docker-compose.yml) with mocked internet topology - 3-validator prod compose (deploy/prod/) for federation - Auto-update from Gitea via /api/update-check + systemd timer - Build-time version injection (ldflags → node --version) - UI / Swagger toggle flags (DCHAIN_DISABLE_UI, DCHAIN_DISABLE_SWAGGER) Client (client-app/): - Expo / React Native / NativeWind - E2E NaCl encryption, typing indicator, contact requests - Auto-discovery of canonical contracts, chain_id aware, WS reconnect on node switch Documentation: - README.md, CHANGELOG.md, CONTEXT.md - deploy/single/README.md with 6 operator scenarios - deploy/UPDATE_STRATEGY.md with 4-layer forward-compat design - docs/contracts/*.md per contract
214 lines
6.9 KiB
Markdown
214 lines
6.9 KiB
Markdown
# auction
|
||
|
||
English auction с on-chain token escrow. Ставки хранятся в contract treasury. При перебивании ставки предыдущий топ-биддер получает автоматический refund.
|
||
|
||
## Жизненный цикл
|
||
|
||
```
|
||
seller buyer-1 buyer-2 anyone
|
||
│ │ │ │
|
||
│─ create ──────▶│ │ │
|
||
│ (min_bid, │ │ │
|
||
│ duration) │ │ │
|
||
│ │ │ │
|
||
│ │─ bid(500) ───▶│ │
|
||
│ │ treasury ←500│ │
|
||
│ │ │ │
|
||
│ │ │─ bid(800) ───▶│
|
||
│ │ refund→500 │ treasury ←800│
|
||
│ │ │ │
|
||
│ │ │ │ [end_block reached]
|
||
│ │ │ │
|
||
│◀─────────────────────────────────── settle ────│
|
||
│ treasury→800 │ │ │
|
||
│ (seller gets │ │ │
|
||
│ winning bid) │ │ │
|
||
```
|
||
|
||
**Статусы:** `open` → `settled` / `cancelled`
|
||
|
||
## Auction ID
|
||
|
||
Формат: `<block_height>:<seq>`, например `42:0`, `42:1`.
|
||
Генерируется автоматически при `create`, логируется как `created: <id>`.
|
||
|
||
## Методы
|
||
|
||
### `create`
|
||
|
||
Создать новый аукцион.
|
||
|
||
**Аргументы:**
|
||
| # | Имя | Тип | Описание |
|
||
|---|-----|-----|---------|
|
||
| 0 | `title` | string | Описание лота (max 128 байт) |
|
||
| 1 | `min_bid` | uint64 | Минимальная ставка в µT |
|
||
| 2 | `duration` | uint64 | Длительность в блоках |
|
||
|
||
**Поведение:**
|
||
- Сохраняет seller = caller
|
||
- `end_block = current_block + duration`
|
||
- Лог: `created: <auction_id>`
|
||
|
||
```bash
|
||
# Аукцион: мин. ставка 1 T, длительность 100 блоков
|
||
client call-contract --method create \
|
||
--arg "Rare NFT #42" --arg64 1000000 --arg64 100 \
|
||
--contract $AUC_ID --key /keys/node1.json \
|
||
--gas 20000 --node http://node1:8080
|
||
```
|
||
|
||
---
|
||
|
||
### `bid`
|
||
|
||
Поставить ставку. Средства переводятся из кошелька caller в treasury контракта.
|
||
|
||
**Аргументы:**
|
||
| # | Имя | Тип | Описание |
|
||
|---|-----|-----|---------|
|
||
| 0 | `auction_id` | string | ID аукциона |
|
||
| 1 | `amount` | uint64 | Ставка в µT |
|
||
|
||
**Проверки:**
|
||
- Аукцион в статусе `open`
|
||
- `current_block ≤ end_block`
|
||
- `amount > current_top_bid` (или `amount ≥ min_bid` если ставок нет)
|
||
|
||
**Поведение:**
|
||
- Переводит `amount` с caller → treasury
|
||
- Если был предыдущий топ-биддер → refund ему его ставки из treasury
|
||
- Обновляет `top_bidder` и `top_bid`
|
||
- Лог: `bid: <auction_id>`
|
||
|
||
```bash
|
||
client call-contract --method bid \
|
||
--arg "42:0" --arg64 2000000 \
|
||
--contract $AUC_ID --key /keys/node1.json \
|
||
--gas 30000 --node http://node1:8080
|
||
```
|
||
|
||
---
|
||
|
||
### `settle`
|
||
|
||
Завершить аукцион после истечения `end_block`. Переводит топ-ставку продавцу.
|
||
|
||
**Аргументы:**
|
||
| # | Имя | Тип |
|
||
|---|-----|-----|
|
||
| 0 | `auction_id` | string |
|
||
|
||
**Проверки:** `current_block > end_block`, статус `open`
|
||
|
||
**Поведение:**
|
||
- Если есть ставки: переводит `top_bid` из treasury → seller, статус → `settled`
|
||
- Если ставок нет: статус → `cancelled`
|
||
- Лог: `settled: <id>` или `cancelled: <id> (no bids)`
|
||
- Может вызвать **любой** (не только seller)
|
||
|
||
```bash
|
||
client call-contract --method settle --arg "42:0" \
|
||
--contract $AUC_ID --key /keys/node1.json \
|
||
--gas 20000 --node http://node1:8080
|
||
```
|
||
|
||
---
|
||
|
||
### `cancel`
|
||
|
||
Отменить аукцион без ставок. Только seller.
|
||
|
||
**Аргументы:**
|
||
| # | Имя | Тип |
|
||
|---|-----|-----|
|
||
| 0 | `auction_id` | string |
|
||
|
||
**Проверки:** статус `open`, ставок нет, `caller == seller`
|
||
|
||
```bash
|
||
client call-contract --method cancel --arg "42:0" \
|
||
--contract $AUC_ID --key /keys/node1.json \
|
||
--gas 10000 --node http://node1:8080
|
||
```
|
||
|
||
---
|
||
|
||
### `info`
|
||
|
||
Запросить состояние аукциона.
|
||
|
||
**Аргументы:**
|
||
| # | Имя | Тип |
|
||
|---|-----|-----|
|
||
| 0 | `auction_id` | string |
|
||
|
||
**Логи:**
|
||
```
|
||
seller: <pubkey>
|
||
title: <title>
|
||
top_bid: <amount>
|
||
end_block: <block>
|
||
status: open|settled|cancelled
|
||
```
|
||
|
||
```bash
|
||
client call-contract --method info --arg "42:0" \
|
||
--contract $AUC_ID --key /keys/node1.json \
|
||
--gas 5000 --node http://node1:8080
|
||
```
|
||
|
||
---
|
||
|
||
## State Layout
|
||
|
||
```
|
||
cstate:<contractID>:seq → uint64 (глобальный счётчик аукционов)
|
||
cstate:<contractID>:a:<id>:s → seller pubkey
|
||
cstate:<contractID>:a:<id>:t → title
|
||
cstate:<contractID>:a:<id>:b → top_bid (uint64 big-endian)
|
||
cstate:<contractID>:a:<id>:e → end_block (uint64 big-endian)
|
||
cstate:<contractID>:a:<id>:w → top_bidder pubkey
|
||
cstate:<contractID>:a:<id>:x → status byte ('o', 's', 'c')
|
||
```
|
||
|
||
## Полный пример сценария
|
||
|
||
```bash
|
||
# 1. Alice создаёт аукцион
|
||
docker exec node1 client call-contract \
|
||
--key /keys/node1.json --contract $AUC_ID \
|
||
--method create \
|
||
--arg "Special Edition #1" --arg64 500000 --arg64 50 \
|
||
--gas 20000 --node http://node1:8080
|
||
# Лог: created: 5:0
|
||
|
||
AUC_ITEM="5:0"
|
||
|
||
# 2. Bob делает ставку 1 T
|
||
docker exec node1 client call-contract \
|
||
--key /tmp/bob.json --contract $AUC_ID \
|
||
--method bid --arg $AUC_ITEM --arg64 1000000 \
|
||
--gas 30000 --node http://node1:8080
|
||
|
||
# 3. Charlie перебивает ставку — Bob получает refund автоматически
|
||
docker exec node1 client call-contract \
|
||
--key /tmp/charlie.json --contract $AUC_ID \
|
||
--method bid --arg $AUC_ITEM --arg64 1500000 \
|
||
--gas 30000 --node http://node1:8080
|
||
|
||
# 4. Проверить статус
|
||
docker exec node1 client call-contract \
|
||
--key /keys/node1.json --contract $AUC_ID \
|
||
--method info --arg $AUC_ITEM \
|
||
--gas 5000 --node http://node1:8080
|
||
|
||
# 5. После end_block — завершить (любой может)
|
||
docker exec node1 client call-contract \
|
||
--key /keys/node1.json --contract $AUC_ID \
|
||
--method settle --arg $AUC_ITEM \
|
||
--gas 20000 --node http://node1:8080
|
||
# Лог: settled: 5:0
|
||
# Alice получает 1.5 T на кошелёк
|
||
```
|