feat: /faucet/{address} в шлюз — налив SOL+фантиков на произвольный адрес (localnet)
This commit is contained in:
+64
-12
@@ -15,6 +15,9 @@
|
||||
* Ответ: {tx, id, bettor, entryPrice}
|
||||
* POST /close {id} — close_bet по текущей цене (подпись relayer)
|
||||
* GET /balance/{address} — {sol, solLamports, tokenUnits, tokenHuman}
|
||||
* GET /faucet/{address} — налив SOL + фантиков на произвольный адрес
|
||||
* (только localnet, allowAirdrop=1; иначе 403). Ответ:
|
||||
* {address, sol, solLamports, tokenUnits, tokenHuman}
|
||||
*
|
||||
* Запуск: npm run gateway (ts-node src/gateway.ts)
|
||||
* Env: GW_PORT (default 8895), GW_BETTOR_KEYSTORE, SMART_* (как у релейера).
|
||||
@@ -299,11 +302,17 @@ async function handleClose(ctx: Ctx, body: Record<string, unknown>): Promise<Htt
|
||||
return { status: 200, body: bodyOut };
|
||||
}
|
||||
|
||||
async function handleBalance(ctx: Ctx, address: string): Promise<HttpJson> {
|
||||
const pub = parsePubkey(address);
|
||||
if (!pub) {
|
||||
return { status: 400, body: { error: "address is not a valid Solana pubkey" } };
|
||||
}
|
||||
/** Балансы адреса (SOL + фантики в ATA по нашему mint) — переиспользуется
|
||||
* и /balance, и /faucet (реальные значения после налива). */
|
||||
async function readBalances(
|
||||
ctx: Ctx,
|
||||
pub: PublicKey
|
||||
): Promise<{
|
||||
sol: number;
|
||||
solLamports: number;
|
||||
tokenUnits: string;
|
||||
tokenHuman: string;
|
||||
}> {
|
||||
const [lamports, tokenUnits] = await Promise.all([
|
||||
ctx.connection.getBalance(pub),
|
||||
(async (): Promise<string> => {
|
||||
@@ -316,14 +325,52 @@ async function handleBalance(ctx: Ctx, address: string): Promise<HttpJson> {
|
||||
}
|
||||
})(),
|
||||
]);
|
||||
return {
|
||||
sol: lamports / LAMPORTS_PER_SOL_NUM,
|
||||
solLamports: lamports,
|
||||
tokenUnits,
|
||||
tokenHuman: humanize(tokenUnits, ctx.decimals),
|
||||
};
|
||||
}
|
||||
|
||||
async function handleBalance(ctx: Ctx, address: string): Promise<HttpJson> {
|
||||
const pub = parsePubkey(address);
|
||||
if (!pub) {
|
||||
return { status: 400, body: { error: "address is not a valid Solana pubkey" } };
|
||||
}
|
||||
return { status: 200, body: await readBalances(ctx, pub) };
|
||||
}
|
||||
|
||||
/**
|
||||
* Налив фантиков/SOL на ПРОИЗВОЛЬНЫЙ адрес (Phantom и т.п.) — только localnet.
|
||||
* Переиспользует готовые функции ops.ts без дублирования логики:
|
||||
* - SOL (рента/комиссия) — тот же airdrop, что fundBettor;
|
||||
* - фантики — mintTo в ATA адреса (до startBalance, дефолт = maxAmount),
|
||||
* та же функция, которой /bet фандит ATA (ensureBettorTokenAccount).
|
||||
* Ответ — адрес + реальные балансы после налива (readBalances, как в /balance).
|
||||
*/
|
||||
async function handleFaucet(ctx: Ctx, address: string): Promise<HttpJson> {
|
||||
if (!ctx.cfg.allowAirdrop) {
|
||||
return { status: 403, body: { error: "faucet only on localnet" } };
|
||||
}
|
||||
const pub = parsePubkey(address);
|
||||
if (!pub) {
|
||||
return { status: 400, body: { error: "address is not a valid Solana pubkey" } };
|
||||
}
|
||||
// SOL под ренту/комиссию — тот же airdrop, что fundBettor.
|
||||
await fundBettor(ctx.connection, pub);
|
||||
// Фантики — mintTo в ATA адреса до startBalance (дефолт = maxAmount из Global).
|
||||
await ensureBettorTokenAccount(
|
||||
ctx.connection,
|
||||
ctx.admin,
|
||||
ctx.cfg.tokenMint,
|
||||
pub,
|
||||
BigInt(ctx.cfg.startBalance)
|
||||
);
|
||||
const balances = await readBalances(ctx, pub);
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
sol: lamports / LAMPORTS_PER_SOL_NUM,
|
||||
solLamports: lamports,
|
||||
tokenUnits,
|
||||
tokenHuman: humanize(tokenUnits, ctx.decimals),
|
||||
},
|
||||
body: { address: pub.toBase58(), ...balances },
|
||||
};
|
||||
}
|
||||
|
||||
@@ -435,6 +482,9 @@ async function main(): Promise<void> {
|
||||
} else if (m === "GET" && p.startsWith("/balance/")) {
|
||||
const address = decodeURIComponent(p.slice("/balance/".length));
|
||||
result = await handleBalance(ctx, address);
|
||||
} else if (m === "GET" && p.startsWith("/faucet/")) {
|
||||
const address = decodeURIComponent(p.slice("/faucet/".length));
|
||||
result = await handleFaucet(ctx, address);
|
||||
} else {
|
||||
result = { status: 404, body: { error: "not found" } };
|
||||
}
|
||||
@@ -461,7 +511,9 @@ async function main(): Promise<void> {
|
||||
|
||||
server.listen(port, "0.0.0.0", () => {
|
||||
console.log(`gateway: listening on 0.0.0.0:${port} (RPC ${cfg.rpcUrl}, mint ${cfg.tokenMint.toBase58()})`);
|
||||
console.log(`gateway: endpoints: GET /state, POST /bet, POST /close, GET /balance/{address}`);
|
||||
console.log(
|
||||
`gateway: endpoints: GET /state, POST /bet, POST /close, GET /balance/{address}, GET /faucet/{address}`
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user