feat: токеновая подпись create_bet (8 аккаунтов по IDL) + дефолтный programId 9ALs

- 8 аккаунтов строго по порядку IDL: bettor/global/bet/clock/system_program/bettor_token/vault_token/token_program
- vault_token = ATA от PDA[global,vault]; bettor_token = ATA игрока (ASSOCIATED_TOKEN_PROGRAM_ID)
- minAmount: st.minAmountToken ?? st.minAmountLamports
- programId по умолчанию = 9ALsnx... (токеновый контракт)
This commit is contained in:
Caffeine
2026-09-10 02:36:36 +03:00
parent 41acef2238
commit 32470d89b2
2 changed files with 87 additions and 10 deletions
+70
View File
@@ -0,0 +1,70 @@
# TASK — Привести test-front под актуальную токеновую подпись create_bet
Репозиторий: `test-front`, файл `index.html`.
## Контекст
Контракт `smart-updown-token` переведён на SPL-токен (фантики). IDL (актуальная токеновая
версия) имеет для `create_bet` 8 аккаунтов в ТОЧНОМ порядке:
```
1 bettor (signer, writable) — кошелёк игрока
2 global (PDA [b"global"]) writable
3 bet (PDA [b"bet", id]) writable
4 clock (SysvarC1ock...) не writable
5 system_program (111111...) не writable
6 bettor_token (ATA игрока, getAssociatedTokenAddress(mint, bettor)) writable
7 vault_token (ATA ваулта, getAssociatedTokenAddress(mint, vaultPda)) writable
8 token_program (Tokenkeg.../TokenProgram.programId) не writable
```
Дискриминатор create_bet = [0xc5,0x2a,0x99,0x02,0x3b,0x3f,0x8f,0xf6] (уже зашит).
Сейчас в `index.html:#placeBet` ключи на позициях 0-4 верны, но позиции 5-6-7 — заглушка
(плейсхолдеры). Нужно добавить настоящие токен-аккаунты.
## Что исправить (только в `index.html`, функция `placeBet` + конфиг)
### 1. Конфиг-дефолты (шапка)
- `programId` по умолчанию: `9ALsnxXNzDBv3mokngCHbruRTWUZiWR7pf7vswS1fCpf` (токеновый контракт).
- `tokenMint`: оставить пустым (вводится), но в комментарий/README добавить, что на localnet
это созданный mint e.g. `8zd15Zoy1t3MDeCTT2eDa7y8jB1fBW8ynFD91ubKt2t3` (выдаётся вручную).
- RPC по умолчанию оставить (public; на localnet — http://127.0.0.1:8890).
### 2. `placeBet` — аккаунты create_bet (позиции 0..7)
Заменить массив `keys` на 8 элементов строго по порядку IDL:
```js
const vaultPda = web3.PublicKey.findProgramAddressSync(
[new TextEncoder().encode('global'), new TextEncoder().encode('vault')], c.programId)[0];
const vaultAta = web3.PublicKey.findProgramAddressSync(
[vaultPda.toBuffer(), web3.TokenProgram.programId.toBuffer(), ctx.mint.toBuffer()],
web3.ASSOCIATED_TOKEN_PROGRAM_ID)[0];
const bettorAta = web3.PublicKey.findProgramAddressSync(
[pubkey.toBuffer(), web3.TokenProgram.programId.toBuffer(), ctx.mint.toBuffer()],
web3.ASSOCIATED_TOKEN_PROGRAM_ID)[0];
const keys=[
{pubkey,isSigner:true,isWritable:true}, // 0 bettor
{pubkey:ctx.globalPda,isSigner:false,isWritable:true}, // 1 global
{pubkey:ctx.betPda(st.nextBetId),isSigner:false,isWritable:true},// 2 bet
{pubkey:new web3.PublicKey('SysvarC1ock11111111111111111111111111111111'),isSigner:false,isWritable:false}, // 3 clock
{pubkey:new web3.PublicKey('11111111111111111111111111111111'),isSigner:false,isWritable:false}, // 4 system_program
{pubkey:bettorAta,isSigner:false,isWritable:true}, // 5 bettor_token
{pubkey:vaultAta,isSigner:false,isWritable:true}, // 6 vault_token
{pubkey:web3.TokenProgram.programId,isSigner:false,isWritable:false}, // 7 token_program
];
```
(ваулт-ATA и бет-ATA считать через `getAssociatedTokenAddress`/findProgramAddress с
ASSOCIATED_TOKEN_PROGRAM_ID — как уже сделано для ATA игрока в refreshBalances).
### 3. Проверка minAmount
`st.minAmountLamports` (стр.196) — имя поля могло поменяться на токеновое. Читать поля
аккуратно (если `/api/state` отдаёт `minAmountToken` — использовать его). Не ломать при отсутствии.
### 4. amount
Уже в токен-единицах (умножается на 10^decimals) — ок, не менять.
## Гейт
- Файл корректный (нет JS-опечаток): открыть в браузере/`node -c` синтаксис.
- Аккаунты create_bet точно 8 и по порядку IDL.
## НЕ делать
- Не менять swap/балансы/подключение (работают).
- Не трогать бэкенд.
- Не коммитить без фразы пользователя.
+16 -9
View File
@@ -25,8 +25,10 @@
<legend>Конфигурация</legend>
<div class="row">
<label>API base</label><input id="apiBase" size="42" value="https://smart-updown.binom.pw"/>
<!-- RPC: по умолчанию public; на localnet — http://127.0.0.1:8890 -->
<label>RPC</label><input id="rpcUrl" size="34" value="https://rpc.solanatracker.io/public"/>
<label>Program</label><input id="programId" size="30" value="FMMDsmUKh5e4kYsofVA2jtzHGuY2kCfoh2NmMWSZr2f"/>
<label>Program</label><input id="programId" size="30" value="9ALsnxXNzDBv3mokngCHbruRTWUZiWR7pf7vswS1fCpf"/>
<!-- token mint вводится вручную; на localnet mint выдаётся вручную, e.g. 8zd15Zoy1t3MDeCTT2eDa7y8jB1fBW8ynFD91ubKt2t3 -->
<label>Token mint</label><input id="tokenMint" size="30" value=""/>
</div>
<div class="row">
@@ -193,16 +195,21 @@ async function placeBet(){
const ctx=await buildCtx();
const side=document.getElementById('betSide').value==='UP'?0:1;
const amt=BigInt(document.getElementById('betAmt').value)*BigInt(Math.pow(10,ctx.decimals));
if(amt<st.minAmountLamports) log.warn?.('сумма ниже min — контракт отклонит');
// 2) build create_bet instruction (TOKEN variant — TODO: подтвердить ключи под токен-программу)
const ata=web3.PublicKey.findProgramAddressSync([pubkey.toBuffer(), web3.TokenProgram.programId.toBuffer(), ctx.mint.toBuffer()], web3.ASSOCIATED_TOKEN_PROGRAM_ID)[0];
const minAmount = st.minAmountToken ?? st.minAmountLamports;
if(minAmount != null && amt < minAmount) log.warn?.('сумма ниже min — контракт отклонит');
// 2) build create_bet instruction (token: 8 аккаунтов строго по порядку IDL)
const vaultPda=web3.PublicKey.findProgramAddressSync([new TextEncoder().encode('global'), new TextEncoder().encode('vault')], c.programId)[0];
const vaultAta=web3.PublicKey.findProgramAddressSync([vaultPda.toBuffer(), web3.TokenProgram.programId.toBuffer(), ctx.mint.toBuffer()], web3.ASSOCIATED_TOKEN_PROGRAM_ID)[0];
const bettorAta=web3.PublicKey.findProgramAddressSync([pubkey.toBuffer(), web3.TokenProgram.programId.toBuffer(), ctx.mint.toBuffer()], web3.ASSOCIATED_TOKEN_PROGRAM_ID)[0];
const keys=[
{pubkey,isSigner:true,isWritable:true}, // 0 bettor
{pubkey:ctx.globalPda,isSigner:false,isWritable:true},
{pubkey:ctx.betPda(st.nextBetId),isSigner:false,isWritable:true},
{pubkey:new web3.PublicKey('SysvarC1ock11111111111111111111111111111111'),isSigner:false,isWritable:false},
{pubkey:new web3.PublicKey('11111111111111111111111111111111'),isSigner:false,isWritable:false},
// NOTE: при переводе на токен эти ключи изменятся (mint, ata ваулт, token program) — заглушка
{pubkey:ctx.globalPda,isSigner:false,isWritable:true}, // 1 global
{pubkey:ctx.betPda(st.nextBetId),isSigner:false,isWritable:true}, // 2 bet
{pubkey:new web3.PublicKey('SysvarC1ock11111111111111111111111111111111'),isSigner:false,isWritable:false}, // 3 clock
{pubkey:new web3.PublicKey('11111111111111111111111111111111'),isSigner:false,isWritable:false}, // 4 system_program
{pubkey:bettorAta,isSigner:false,isWritable:true}, // 5 bettor_token
{pubkey:vaultAta,isSigner:false,isWritable:true}, // 6 vault_token
{pubkey:web3.TokenProgram.programId,isSigner:false,isWritable:false}, // 7 token_program
];
const data=new Uint8Array(8+4*8); data.set(CREATE_BET_DISC,0); data.set(leU64(st.nextBetId),8); data.set(leU64(side),16); data.set(leU64(amt),24); data.set(leU64(st.entryPrice),32);
const ix=new web3.TransactionInstruction({programId:c.programId,keys,data});