Files
smart-updown-token/TASK-vault-contract-fix.md

3.9 KiB
Raw Permalink Blame History

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 проходит.