3.9 KiB
TASK — Фикс: сделать vault_token обычным ATA-токен-счётом (убрать seeds = PDA)
Репозиторий: smart-updown-token. Файлы: program/programs/smart-updown/src/instructions/create_bet.rs
и .../close_bet.rs.
Проблема (обнаружено на localnet E2E)
Токен-аккаунт ваулта объявлен так:
#[account(
mut,
seeds = [GLOBAL_SEED, VAULT_SEED], // ← требует адрес == PDA([global,vault])
)]
pub vault_token: Account<'info, TokenAccount>
Anchor проверяет, что адрес vault_token == PDA([global,vault]). Но казённый
(escrow) токен-счёт у нас — это ATA от владельца vaultPda: адрес
getAssociatedTokenAddress(mint, vaultPda), который НЕ равен PDA. Отсюда
Error Code: ConstraintSeeds — перевод в ваулт невозможен.
У bettor_token такой проблемы нет (там обычный Account<TokenAccount>, адрес = ATA игрока).
Что исправить
1. create_bet.rs
У vault_token убрать блок seeds = [GLOBAL_SEED, VAULT_SEED] — оставить просто:
#[account(mut)]
pub vault_token: Account<'info, TokenAccount>,
(оставить поле bump больше не нужно — удалить его из struct, если он был).
Это сделает адрес любого токен-счёта (ATA ваулта) приемлемым.
2. close_bet.rs
То же самое: у vault_token убрать seeds = [...]. НО: раз адрес больше не фиксируется
seeds, передавать/подписывать перевод нужно от владельца-пользователя (vaultPda).
В close_bet AUTHORITY перевода остаётся владелец аккаунта (поле owner токен-счёта).
Проверить: signer_seeds [GLOBAL_SEED, VAULT_SEED, bump] должны по-прежнему давать
vaultPda (это и есть владелец ATA). Так как сигнатура от PDA не меняется, seed-фразы
в close_bet.rs (для подписи CPI) СТАВЯТСЯ из ctx.accounts.vault_token owner.
Возможно понадобится отдельный аккаунт vault_authority: PDA([global,vault]), чтобы
передать в signer seeds — оценить и сделать аккуратно (стандартный Anchor escrow).
3. Пересборка и проверка
anchor buildзелёный.- IDL перегенерировать (
anchor idl build), синхронизироватьrelayer/idl/smart_updown.json. npm run typecheck/npm testвrelayer/— зелёные (если тесты проверяют seeds — обновить).
Важно (архитектурно)
vault_token — это ATA от владельца vaultPda (адрес getAssociatedTokenAddress(mint, vaultPda)).
Контракт НЕ должен требовать конкретного адреса — только владельца-подпись для withdraw.
Всё, что нужно — чтобы в close_bet authority (тот, кто подписывает перевод из ваулта)
был vaultPda (владелец ATA), а не адрес аккаунта.
НЕ делать
- Не трогать логику ставок/цен.
- Не трогать релейер (он уже передаёт правильный ATA-адрес).
- Не коммитить.
Проверка успеха
anchor build+ IDL обновлён.- На localnet: передача
vault_token= ATA (getAssociatedTokenAddress(mint, vaultPda)), create_bet принимает ставку, close_bet выплачивает (signer — vaultPda). E2E проходит.