feat(contract): возврат залога при ничьей (exit_price == entry_price)
Раньше при равенстве цен close_bet делал `return Ok(())` — ставка навсегда оставалась в статусе open, а залог запирался в ваулте (замер: 33.6% окон). Из-за правила «одна открытая ставка на адрес» игрок получал 409 пожизненно. Теперь ничья возвращает залог целиком (без множителя) и финализирует ставку: - constants.rs: STATUS_REFUNDED = 3 (0/1/2 не тронуты — зашиты в шлюз и в цепи) - close_bet.rs: CPI-перевод amount из ваулта беттору под сидами ваулт-PDA, запись exit_price/status, событие BetClosed(status=3, payout=amount) - settle.ts: STATUS_REFUNDED, statusName "refunded", статус 3 в условии финализации - check.ts: проверка формы события refunded - тест close_bet_equal_price_stays_open → close_bet_equal_price_refunds (+ повторное закрытие отклоняется) Проверено: cargo test-sbf 10/10, npm run typecheck EXIT=0, две мутации (снятие статуса, снятие перевода) валят именно новый тест. Задеплоено: программа 9ALs… (хэш из цепи совпал побайтово), шлюз rev 15.
This commit is contained in:
@@ -441,7 +441,7 @@ async fn close_bet_house_wins_down() {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn close_bet_equal_price_stays_open() {
|
||||
async fn close_bet_equal_price_refunds() {
|
||||
let (mut ctx, admin) = setup().await;
|
||||
initialize(&mut ctx, &admin).await;
|
||||
let mint = create_token_env(&mut ctx, &admin).await;
|
||||
@@ -449,21 +449,35 @@ async fn close_bet_equal_price_stays_open() {
|
||||
|
||||
set_clock(&mut ctx, START_TIME + EXPIRY_SECONDS + 1).await;
|
||||
let before = read_token_balance(&mut ctx, &ata).await;
|
||||
let payout = amount * MULTIPLIER_BPS / 10_000;
|
||||
|
||||
let equal_ix = make_close_ix(0, entry_price, admin.pubkey(), bettor.pubkey(), &ata);
|
||||
run_close_tx(&mut ctx, &admin, &equal_ix).await.expect("equal close");
|
||||
assert_eq!(read_bet_typed(&read_account_data(&ctx.banks_client, &bet_pda(0)).await).status, 0);
|
||||
assert_eq!(read_token_balance(&mut ctx, &ata).await, before);
|
||||
run_close_tx(
|
||||
&mut ctx,
|
||||
&admin,
|
||||
&make_close_ix(0, entry_price, admin.pubkey(), bettor.pubkey(), &ata),
|
||||
)
|
||||
.await
|
||||
.expect("equal close");
|
||||
|
||||
let exit_price = entry_price + 1_000;
|
||||
let second_ix = make_close_ix(0, exit_price, admin.pubkey(), bettor.pubkey(), &ata);
|
||||
run_close_tx(&mut ctx, &admin, &second_ix).await.expect("second close");
|
||||
let b = read_bet_typed(&read_account_data(&ctx.banks_client, &bet_pda(0)).await);
|
||||
assert_eq!(b.status, 3, "expected status REFUNDED=3");
|
||||
assert_eq!(b.exit_price, entry_price, "exit_price must be recorded as entry_price");
|
||||
assert_eq!(read_token_balance(&mut ctx, &ata).await, before + amount, "bettor +amount");
|
||||
assert_eq!(
|
||||
read_token_balance(&mut ctx, &ata).await,
|
||||
before + payout
|
||||
read_token_balance(&mut ctx, &vault_pda()).await,
|
||||
VAULT_TOKEN_SUPPLY,
|
||||
"vault -amount"
|
||||
);
|
||||
assert_eq!(read_bet_typed(&read_account_data(&ctx.banks_client, &bet_pda(0)).await).status, 1);
|
||||
|
||||
// Повторный close по той же ставке → ошибка BetAlreadyFinalized.
|
||||
// exit_price чуть другой, иначе banks дедуплицирует транзакцию
|
||||
// (тот же signer + тот же blockhash + те же данные икса → Ok без перезапуска).
|
||||
let res = run_close_tx(
|
||||
&mut ctx,
|
||||
&admin,
|
||||
&make_close_ix(0, entry_price + 1, admin.pubkey(), bettor.pubkey(), &ata),
|
||||
)
|
||||
.await;
|
||||
assert!(res.is_err(), "expected second close after refund to be rejected");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
Reference in New Issue
Block a user