# Приём депозитов для обменников
Пошаговое руководство по настройке приёма USDT от пользователей вашей платформы.
## Сценарий
Вы — обменник или биржа. Ваши пользователи хотят пополнить баланс в USDT:
1. Пользователь запрашивает адрес для пополнения
2. Ваша система создаёт уникальный кошелёк
3. Пользователь отправляет USDT
4. Lumo проводит AML-проверку
5. Вы получаете webhook о зачислении
## Преимущества
- **Без блокчейн-кода** — не нужно работать с TRON напрямую
- **AML из коробки** — автоматическая проверка входящих транзакций
- **Автопересылка** — средства собираются на вашем treasury
- **Webhooks** — real-time уведомления
## Шаг 1: Настройка webhook
Сначала настройте endpoint для получения уведомлений:
```javascript
const crypto = require('crypto');
app.post('/webhooks/lumo', (req, res) => {
// Верификация подписи
const signature = req.headers['x-lumo-signature'];
const expected = crypto
.createHmac('sha256', process.env.WEBHOOK_SECRET)
.update(JSON.stringify(req.body))
.digest('hex');
if (signature !== expected) {
return res.status(401).send('Invalid signature');
}
// Обработка события
handleWebhook(req.body);
res.status(200).send('OK');
});
function handleWebhook(payload) {
const { event, externalId, amount, status } = payload;
switch (event) {
case 'deposit.completed':
creditUserBalance(externalId, amount);
break;
case 'deposit.aml_failed':
notifySupport(payload);
break;
}
}
```
Обновите профиль компании:
```bash
curl -X PATCH 'https://b2b.lumowallet.io/auth/company/profile' \
-H 'X-API-Key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"webhookUrl": "https://your-server.com/webhooks/lumo"
}'
```
## Шаг 2: Создание кошелька для пользователя
Когда пользователь запрашивает адрес для пополнения:
```javascript
async function getDepositAddress(userId) {
const response = await fetch('https://b2b.lumowallet.io/user-wallets', {
method: 'POST',
headers: {
'X-API-Key': process.env.LUMO_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
externalId: userId // Ваш внутренний ID пользователя
})
});
const wallet = await response.json();
return wallet.address;
}
```
Ответ:
```json
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"companyId": "660e8400-e29b-41d4-a716-446655440001",
"externalId": "user-12345",
"address": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE",
"isBlocked": false,
"lastUsdtBalance": 0,
"createdAt": "2026-03-10T12:00:00Z"
}
```
> 💡 **Идемпотентность:** Повторный запрос с тем же `externalId` вернёт существующий кошелёк.
## Шаг 3: Показ адреса пользователю
```jsx
function DepositPage({ userId }) {
const [address, setAddress] = useState(null);
useEffect(() => {
getDepositAddress(userId).then(setAddress);
}, [userId]);
return (
Пополнение баланса
Отправьте USDT (TRC-20) на адрес:
{address}
⚠️ Отправляйте только USDT в сети TRON (TRC-20)
);
}
```
## Шаг 4: Обработка депозита
Когда пользователь отправляет USDT, вы получаете webhooks:
### 4.1 Депозит обнаружен
```json
{
"event": "deposit.created",
"depositId": "770e8400-e29b-41d4-a716-446655440002",
"externalId": "user-12345",
"txHash": "abc123...",
"walletAddress": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE",
"amount": 100.00,
"status": "new"
}
```
Действие: Показать пользователю "Депозит обнаружен, ожидает подтверждения"
### 4.2 AML-проверка
```json
{
"event": "deposit.aml_pending",
"depositId": "770e8400-e29b-41d4-a716-446655440002",
"externalId": "user-12345",
"status": "aml_pending"
}
```
Действие: Показать "Проверка безопасности..."
### 4.3 Депозит завершён
```json
{
"event": "deposit.completed",
"depositId": "770e8400-e29b-41d4-a716-446655440002",
"externalId": "user-12345",
"amount": 100.00,
"status": "completed"
}
```
Действие: Зачислить средства на баланс пользователя
```javascript
async function creditUserBalance(externalId, amount) {
await db.users.update({
where: { id: externalId },
data: {
balance: { increment: amount },
lastDepositAt: new Date()
}
});
// Уведомить пользователя
await notifyUser(externalId, {
type: 'deposit_success',
amount: amount
});
}
```
## Шаг 5: Обработка AML-блокировок
При `aml_failed`:
```javascript
function handleAmlFailed(payload) {
const { externalId, amount, depositId } = payload;
// Уведомить пользователя
notifyUser(externalId, {
type: 'deposit_blocked',
message: 'Депозит заблокирован для проверки'
});
// Создать тикет для поддержки
createSupportTicket({
type: 'aml_review',
userId: externalId,
depositId: depositId,
amount: amount
});
}
```
## Шаг 6: Просмотр истории депозитов
```javascript
async function getUserDeposits(userId) {
const response = await fetch(
`https://b2b.lumowallet.io/user-wallets/deposits?externalId=${userId}`,
{ headers: { 'X-API-Key': process.env.LUMO_API_KEY } }
);
return response.json();
}
```
## Блокировка кошелька
При подозрительной активности заблокируйте кошелёк:
```javascript
async function blockUserWallet(walletId, reason) {
await fetch(`https://b2b.lumowallet.io/user-wallets/${walletId}/block`, {
method: 'POST',
headers: {
'X-API-Key': process.env.LUMO_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({ reason })
});
}
```
## Замена кошелька
Если пользователь просит новый адрес:
```javascript
async function replaceUserWallet(walletId) {
const response = await fetch(
`https://b2b.lumowallet.io/user-wallets/${walletId}/replace`,
{
method: 'POST',
headers: {
'X-API-Key': process.env.LUMO_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({ reason: 'User requested new address' })
}
);
const newWallet = await response.json();
return newWallet.address; // Новый адрес
}
```
## Полный пример
```javascript
class DepositService {
constructor(apiKey, webhookSecret) {
this.apiKey = apiKey;
this.webhookSecret = webhookSecret;
this.baseUrl = 'https://b2b.lumowallet.io';
}
async getOrCreateWallet(userId) {
const response = await fetch(`${this.baseUrl}/user-wallets`, {
method: 'POST',
headers: {
'X-API-Key': this.apiKey,
'Content-Type': 'application/json'
},
body: JSON.stringify({ externalId: userId })
});
return response.json();
}
verifyWebhook(body, signature) {
const expected = crypto
.createHmac('sha256', this.webhookSecret)
.update(JSON.stringify(body))
.digest('hex');
return signature === expected;
}
async handleWebhook(payload) {
switch (payload.event) {
case 'deposit.completed':
await this.onDepositCompleted(payload);
break;
case 'deposit.aml_failed':
await this.onAmlFailed(payload);
break;
}
}
async onDepositCompleted({ externalId, amount }) {
// Зачисляем баланс
await db.users.increment(externalId, 'balance', amount);
// Уведомляем пользователя
await notifications.send(externalId, {
title: 'Депозит зачислен',
body: `+${amount} USDT`
});
}
async onAmlFailed({ externalId, depositId }) {
await notifications.send(externalId, {
title: 'Депозит на проверке',
body: 'Свяжитесь с поддержкой'
});
}
}
```
## Чек-лист интеграции
- [ ] Настроен webhook endpoint
- [ ] Webhook URL обновлён в профиле
- [ ] Верификация подписи webhook
- [ ] Создание кошельков для пользователей
- [ ] UI для показа адреса + QR-код
- [ ] Обработка `deposit.completed`
- [ ] Обработка `deposit.aml_failed`
- [ ] Зачисление баланса пользователю
- [ ] Уведомления пользователю
- [ ] Логирование всех событий