Files
dchain/docs/contracts/escrow.md
vsecoder 7e7393e4f8 chore: initial commit for v0.0.1
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
2026-04-17 14:16:44 +03:00

7.4 KiB
Raw Blame History

escrow

Двусторонний trustless escrow. Buyer блокирует средства в contract treasury. Seller выполняет условие. Buyer подтверждает или открывает спор. При споре admin-арбитр решает исход.

Жизненный цикл

buyer           seller          admin
  │               │               │
  │─ create ─────▶│               │   treasury ← amount (locked)
  │  (seller,     │               │   status: active
  │   amount)     │               │
  │               │               │
  │ [seller delivered]            │
  │               │               │
  │─ release ────▶│               │   treasury → seller
  │               │               │   status: released
  
  OR:
  
  │─ dispute ────▶│               │   status: disputed
  │               │─ dispute ────▶│   (either party can)
  │               │               │
  │               │               │─ resolve(winner=buyer) ──▶
  │               │               │   treasury → buyer
  │               │               │   status: refunded
  │               │               │
  │               │               │─ resolve(winner=seller) ──▶
  │               │               │   treasury → seller
  │               │               │   status: released

  OR:

  │               │─ refund ─────▶│   treasury → buyer (voluntary)
  │               │               │   status: refunded

Статусы: activereleased / refunded / disputed

Методы

init

Установить caller как admin (арбитр споров).

Аргументы: нет

Вызывается один раз после деплоя (deploy-скрипт делает автоматически).

client call-contract --method init \
  --contract $ESC_ID --key /keys/node1.json \
  --gas 5000 --node http://node1:8080

create

Buyer создаёт escrow и блокирует средства.

Аргументы:

# Имя Тип Описание
0 id string Уникальный ID эскроу (задаёт пользователь)
1 seller string Pubkey продавца (hex)
2 amount uint64 Сумма в µT

Поведение:

  • Переводит amount с caller (buyer) → treasury
  • Сохраняет buyer, seller, amount, status=active
  • Лог: created: <id>

Ограничения:

  • ID должен быть уникальным — если cstate[e:<id>:b] уже есть, tx отклоняется
client call-contract --method create \
  --arg "deal-001" \
  --arg <SELLER_PUBKEY> \
  --arg64 10000000 \
  --contract $ESC_ID --key /tmp/buyer.json \
  --gas 30000 --node http://node1:8080

release

Buyer подтверждает получение и освобождает средства seller'у.

Аргументы:

# Имя Тип
0 id string

Права: только buyer.
Статус: должен быть active.

Поведение:

  • Переводит amount с treasury → seller
  • Статус → released
  • Лог: released: <id>
client call-contract --method release --arg "deal-001" \
  --contract $ESC_ID --key /tmp/buyer.json \
  --gas 20000 --node http://node1:8080

refund

Seller добровольно возвращает деньги buyer'у.

Аргументы:

# Имя Тип
0 id string

Права: только seller.
Статус: должен быть active.

Поведение:

  • Переводит amount с treasury → buyer
  • Статус → refunded
  • Лог: refunded: <id>
client call-contract --method refund --arg "deal-001" \
  --contract $ESC_ID --key /tmp/seller.json \
  --gas 20000 --node http://node1:8080

dispute

Открыть спор. Может вызвать buyer или seller.

Аргументы:

# Имя Тип
0 id string

Статус: должен быть active.

Поведение:

  • Статус → disputed
  • Лог: disputed: <id>
  • Средства остаются заблокированы в treasury
client call-contract --method dispute --arg "deal-001" \
  --contract $ESC_ID --key /tmp/buyer.json \
  --gas 10000 --node http://node1:8080

resolve

Admin разрешает спор.

Аргументы:

# Имя Тип Значения
0 id string ID эскроу
1 winner string buyer или seller

Права: только admin.
Статус: должен быть disputed.

Поведение:

  • winner=buyer → treasury → buyer, статус → refunded
  • winner=seller → treasury → seller, статус → released
  • Лог: resolved: <id>
# Admin решает в пользу buyer
client call-contract --method resolve \
  --arg "deal-001" --arg buyer \
  --contract $ESC_ID --key /keys/node1.json \
  --gas 20000 --node http://node1:8080

# Admin решает в пользу seller
client call-contract --method resolve \
  --arg "deal-001" --arg seller \
  --contract $ESC_ID --key /keys/node1.json \
  --gas 20000 --node http://node1:8080

info

Запросить состояние эскроу.

Аргументы:

# Имя Тип
0 id string

Логи:

buyer: <pubkey>
seller: <pubkey>
amount: <µT>
status: active|released|refunded|disputed
client call-contract --method info --arg "deal-001" \
  --contract $ESC_ID --key /keys/node1.json \
  --gas 5000 --node http://node1:8080

State Layout

cstate:<contractID>:admin        →  admin pubkey
cstate:<contractID>:e:<id>:b     →  buyer pubkey
cstate:<contractID>:e:<id>:s     →  seller pubkey
cstate:<contractID>:e:<id>:a     →  amount (uint64 big-endian)
cstate:<contractID>:e:<id>:x     →  status byte ('a'=active, 'd'=disputed, 'r'=released, 'f'=refunded)

Полный сценарий с dispute

# Параметры
BUYER_KEY=/tmp/buyer.json
SELLER_KEY=/tmp/seller.json
ADMIN_KEY=/keys/node1.json
ID="escrow-001"

# 1. Buyer создаёт эскроу на 5 T
docker exec node1 client call-contract \
  --key $BUYER_KEY --contract $ESC_ID \
  --method create \
  --arg $ID --arg $SELLER_PUB --arg64 5000000 \
  --gas 30000 --node http://node1:8080

# 2. Проверить статус
docker exec node1 client call-contract \
  --key $BUYER_KEY --contract $ESC_ID \
  --method info --arg $ID \
  --gas 5000 --node http://node1:8080
# status: active

# 3. Buyer не доволен — открывает спор
docker exec node1 client call-contract \
  --key $BUYER_KEY --contract $ESC_ID \
  --method dispute --arg $ID \
  --gas 10000 --node http://node1:8080

# 4. Admin рассматривает дело и решает в пользу seller
docker exec node1 client call-contract \
  --key $ADMIN_KEY --contract $ESC_ID \
  --method resolve --arg $ID --arg seller \
  --gas 20000 --node http://node1:8080
# Лог: resolved: escrow-001
# Seller получает 5 T