
Security News
PHP Patches Critical RCE Vulnerabilities, Organizations Urged to Take Unpatched Sites Offline
PHP releases emergency patches for two critical RCE vulnerabilities as agencies urge organizations to take unpatched sites offline.
@idosgames/wallet
Advanced tools
Wallet-bridge companion to @idosgames/core: connect browser & mobile wallets (EVM via wagmi/viem/WalletConnect, Solana via wallet-adapter) and move tokens/NFTs in and out of the game through client.blockchain.
The on-chain half of the iDosGames blockchain flow. @idosgames/core's
client.blockchain is deliberately report-only: it verifies deposits and
issues signed withdrawals but never signs or broadcasts a transaction. This
package is the missing piece — it connects browser & mobile wallets and
runs the exact RewardPool contract calls, threading them through the
request → submit → confirm / approve → deposit → report lifecycle so a
player can move tokens and NFTs in and out of the game.
@solana/wallet-adapter for connection; the on-chain
instruction building is delegated to a small SolanaProgramAdapter you
implement with your program's IDL (see Solana).Everything stays server-authoritative: the bridge only submits what the backend signed/verified and mirrors the confirmed result into the core cache.
npm i @idosgames/wallet @idosgames/core
# EVM peer deps:
npm i wagmi viem @tanstack/react-query
# Solana peer deps (only if you support Solana networks):
npm i @solana/web3.js @solana/wallet-adapter-react @solana/wallet-adapter-base @solana/wallet-adapter-wallets
Entry points:
@idosgames/wallet — framework-agnostic bridge functions (viem +
@solana/web3.js only). Use these directly if you're not on React.@idosgames/wallet/react — wagmi/React hooks + providers. Everything below
uses these.@idosgames/wallet/react/solana — the Solana React bindings, kept off
/react so an EVM-only game doesn't bundle the Solana adapters.@idosgames/wallet/react/lazy — LazyWalletLogin /
LazySolanaWalletLogin / LazyWalletPanel: the sign-in buttons and the
in-game deposit/withdraw panel, but each fetches the wallet machinery on
demand (LazyWalletLogin on the player's first tap; LazyWalletPanel on
mount). This is the only entry with no Reown AppKit in its module graph,
which is what makes it safe to render on a login screen or in-game in
sandboxed/preview bundlers where AppKit isn't installable. It also re-exports
the supported chains as plain objects, so you never have to import the
wagmi/chains / viem/chains barrel.createEvmWalletConfig is memoised per WalletConnect project id: the
sign-in button and the wallet panel both call it and get the same wagmi
Config object, and a wagmi Config carries the connection in its own store. So
a wallet connected on the login screen is already connected in the in-game
panel — no reconnect, no second modal. For that to hold, keep both on the same
chain set; both default to DEFAULT_EVM_CHAINS, so the simplest correct thing
is to pass no chains to either. LazyWalletPanel takes the authenticated
client as a prop (like the login button), plus optional appName /
onClose / style / walletConnectProjectId.
LazyWalletPanel is ONE panel for both chains: it reads the title's networks
and loads the EVM panel (WalletPanel) or the Solana one (SolanaWalletPanel,
/react/solana). Both render the same form (walletPanelView.tsx: connect,
network, token, in-game balance, amount, Deposit / Withdraw) — a chain only
supplies how it connects and moves tokens. On Solana that is Reown AppKit for
the wallet and createPlatformPoolAdapter (deposit_spl / withdraw_spl
against the platform pool, network.RewardPoolAddress from the engine only);
transactions go to the title's cluster (ChainID 103 → devnet, else mainnet).
createSolanaWalletConfig is memoised per project id too, so a Solana wallet
connected at sign-in stays connected in the panel.
Inside the idosgames.com frame a game's wallet button calls
openPlatformWalletPanel() (also on /react/lazy, with isEmbeddedInPlatform
/ isEmbeddedOnForeignSite): the site shows its own wallet card — crypto in a
frame goes through the site only.
Every subpath declares a browser export condition pointing at the ESM build.
That is load-bearing, not cosmetic: some browser bundlers (CodeSandbox's
classic Sandpack bundler among them) rank the require condition above
import and would otherwise take the CommonJS build — where a dynamic
import() cannot survive, so the lazy entry would eagerly require AppKit.
The updated RewardPool contract tags each operation with a string category
(default "game_topup"; "community_reward" is the other known value).
Deposits read it back from the on-chain tx; withdrawals sign it into the hash,
so it must be submitted on-chain verbatim — the bridge handles that. Pass a
category to any deposit/withdraw call, or omit it for "game_topup". Constants
live in @idosgames/core as BlockchainOperationCategory.
createEvmWalletConfig builds a wagmi config wired for both browser and mobile
wallets. Wrap your app with IDosGamesWalletProvider (WagmiProvider +
react-query) once.
import { polygon } from "viem/chains";
import {
createEvmWalletConfig,
IDosGamesWalletProvider,
} from "@idosgames/wallet/react";
const wagmiConfig = createEvmWalletConfig({
chains: [polygon], // match the EVM networks in your title's blockchain config
walletConnectProjectId: "<your walletconnect cloud id>", // enables MOBILE wallets
appName: "My Game",
});
export function Root() {
return (
<IDosGamesWalletProvider wagmiConfig={wagmiConfig}>
<App />
</IDosGamesWalletProvider>
);
}
Connect/disconnect with wagmi's own hooks (useConnect, useAccount,
useDisconnect) — the injected() connector covers MetaMask & browser
extensions, walletConnect() opens the QR/deep-link modal for phones.
useEvmBridge(client, titleID) binds the connected wallet to the four flows.
Amounts are raw on-chain units — scale with viem's parseUnits.
import { parseUnits } from "viem";
import { useEvmBridge } from "@idosgames/wallet/react";
import type { BlockchainNetworkDefinition } from "@idosgames/core";
function DepositButton({ client, network, usdtAddress }) {
const bridge = useEvmBridge(client, "my-title-id");
async function deposit() {
// approve → depositERC20(token, amount, userID, titleID, category) → report to backend
const res = await bridge.depositToken({
network, // BlockchainNetworkDefinition from getDefinitions()
tokenAddress: usdtAddress, // ERC-20 contract
amount: parseUnits("25", 6), // 25 USDT (6 decimals) as raw units
// category defaults to "game_topup"
});
if (!res.ok) return alert(`${res.stage}: ${res.error}`);
// core cache balance is already updated; res.data is DepositTokenResponse
}
return (
<button disabled={!bridge.connected} onClick={deposit}>
Deposit 25 USDT
</button>
);
}
const res = await bridge.withdrawToken({
currencyID: "usdt",
networkID: "polygon",
walletAddress: bridge.account!, // destination — usually the connected wallet
amount: "25.00", // human decimal; server scales & signs raw units
});
if (!res.ok) {
// If it failed AFTER the debit, res.titleTransactionID is set — recover with
// retryWithdrawal (while Pending) or confirmWithdrawal, NEVER a fresh request.
console.error(res.stage, res.error, res.titleTransactionID);
}
The bridge runs requestTokenWithdrawal (debits in-game) → withdrawERC20
on-chain → confirmWithdrawal. A BridgeFailure tells you exactly where it
stopped via stage (request / withdraw-onchain / confirm) so you can
recover correctly — see Failure & recovery.
// Deposit: safeTransferFrom(account, pool, id, amount, abi.encode(userID,titleID,category))
await bridge.depositNft({
network,
nftContractAddress,
tokenId: 42n,
amount: 1n,
});
// Withdraw: requestNFTWithdrawal → withdrawERC1155 → confirmWithdrawal
await bridge.withdrawNft({
itemID,
networkID: "polygon",
walletAddress: bridge.account!,
amount: "1",
});
The Solana RewardPool is a custom program whose instruction/account layout
isn't in this SDK — so you provide a SolanaProgramAdapter (two methods:
depositSpl and submitWithdrawal) built with your program's IDL /
@solana/web3.js and the connected wallet from @solana/wallet-adapter-react.
The SDK-side orchestration is identical to EVM.
import {
SolanaWalletBridgeProvider,
useSolanaBridge,
} from "@idosgames/wallet/react";
import { PhantomWalletAdapter } from "@solana/wallet-adapter-wallets";
import type { SolanaProgramAdapter } from "@idosgames/wallet";
// Wrap (alongside IDosGamesWalletProvider if you also support EVM):
<SolanaWalletBridgeProvider
endpoint="https://api.mainnet-beta.solana.com"
wallets={[new PhantomWalletAdapter()]}
>
<App />
</SolanaWalletBridgeProvider>;
// Your program integration:
const adapter: SolanaProgramAdapter = {
async depositSpl({ mint, amountRaw, userID, titleID, category }) {
/* build + send the DepositSpl tx with your IDL; return the signature */
},
async submitWithdrawal(sig) {
/* build + send withdraw_spl with the ed25519 sig-verify ix; return the signature */
},
};
function Screen({ client }) {
const bridge = useSolanaBridge(client, "my-title-id", adapter);
// bridge.depositToken({ network, mint, amountRaw }) / bridge.withdrawToken({ currencyID, networkID, amount })
}
Every bridge call resolves to a BridgeResult<T>:
type BridgeResult<T> =
| { ok: true; onChainTxHash: string; data: T }
| {
ok: false;
stage: BridgeStage; // where it stopped
error: string;
onChainTxHash?: string; // set if the asset-moving tx already landed
titleTransactionID?: string; // set if a withdrawal already debited in-game
};
Recovery rules (the bridge never double-charges, but you drive the retry):
stage: "approve" | "deposit-onchain" — nothing was reported; safe to
retry the whole deposit.stage: "report" — the on-chain tx (onChainTxHash) landed but the
backend didn't credit it; retry client.blockchain.depositToken/depositNFT
with that hash.stage: "withdraw-onchain" with a titleTransactionID — the withdrawal
was already debited in-game but not submitted on-chain. Get a fresh signature
with client.blockchain.retryWithdrawal(titleTransactionID) (while Pending)
and submit it with submitEvmTokenWithdrawal / submitEvmNftWithdrawal —
never call withdrawToken again (that debits twice).stage: "confirm" with onChainTxHash + titleTransactionID — the tx
landed but the backend confirm didn't stick; retry
client.blockchain.confirmWithdrawal(titleTransactionID, onChainTxHash).A game embedded in an idosgames.com iframe cannot reach the player's wallet on
its own — deposit/withdraw goes through the buttons in the site's wallet card
next to the game. The @idosgames/wallet/react/lazy components handle this by
themselves:
LazyWalletLogin / LazySolanaWalletLogin stay a normal "Sign in with
wallet" button. Inside the platform's frame the tap goes to
loginWithWalletViaPlatform: the SITE's already-connected wallet signs the
engine's login message (the site connects one first if needed), so the
wallet prompt comes from idosgames.com, and the game exchanges the signature
for a session as usual. The site signs nothing but the engine's login
template for its own page's title. (2026-09-23 — before that the button was
replaced by a notice and wallet sign-in inside the frame was simply gone.)LazyWalletPanel renders nothing in a frame — no notice either.idosgames.com/embed/{id} (two
frames deep, isEmbeddedOnForeignSite()) the sign-in button renders nothing
too: that page has no wallet of ours to sign with.Every bridge and login flow that talks to the wallet directly
(depositTokenEvm, withdrawTokenEvm, loginWithWalletEvm, their Solana
equivalents, payWithWalletEvm) refuses with error: WALLET_USE_SITE_PANEL if
called inside a frame anyway, so a game that rolls its own UI can check
isEmbeddedInPlatform() up front — and call loginWithWalletViaPlatform({ client, networkID, family: "evm" | "solana" }) for sign-in:
import {
isEmbeddedInPlatform,
onWalletBalanceChanged,
} from "@idosgames/wallet";
if (isEmbeddedInPlatform()) {
// hide your own wallet UI — the player uses the site's panel instead
}
// Refresh the on-screen balance once the player finishes an operation there:
const unsubscribe = onWalletBalanceChanged(() => {
client.blockchain.getUserState();
});
A game opened by its own direct link (not embedded) is unaffected — every flow works exactly as before there.
When a title's login mode requires a token balance (cfg.Blockchain.PlayAccess,
AnyWithLinkedWallet), a player who signed in by e-mail or through the site
attaches a wallet to the account by signature — not a second login. Every
sign-in button has a link mode:
<LazyWalletLogin
mode="link"
client={client}
networkID="bsc"
onLinked={(pass) => (pass?.Granted ? enterGame() : showWhyNot(pass))}
/>
Framework-agnostic: linkWalletEvm, linkWalletSolana, and
linkWalletViaPlatform (inside the idosgames.com frame — the site's wallet
signs). The server checks the balance against exactly the linked wallet and
returns the pass as data.PlayAccess. The host template wires this into its
play-access screen already (renderWalletLink in src/walletLogin.tsx).
Not on React? Import the same flows from @idosgames/wallet and pass viem
clients yourself:
import { depositTokenEvm, withdrawTokenEvm } from "@idosgames/wallet";
const clients = { publicClient, walletClient, account }; // your viem clients
await depositTokenEvm({
client,
clients,
network,
tokenAddress,
amount,
titleID,
});
RewardPoolEvmV2 signing
(field order/names of withdrawERC20/withdrawERC1155/depositERC20 must
match, or signatures fail on-chain).client.data.user.state.Blockchain (pending list, stats) is not — call
client.blockchain.getUserState() to refresh it. See the blockchain-system
skill for the full server-side surface, withdrawal gates, and gotchas.FAQs
Wallet-bridge companion to @idosgames/core: connect browser & mobile wallets (EVM via wagmi/viem/WalletConnect, Solana via wallet-adapter) and move tokens/NFTs in and out of the game through client.blockchain.
The npm package @idosgames/wallet receives a total of 182 weekly downloads. As such, @idosgames/wallet popularity was classified as not popular.
We found that @idosgames/wallet demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
PHP releases emergency patches for two critical RCE vulnerabilities as agencies urge organizations to take unpatched sites offline.

Threat Research
/Security News
A supply chain attack compromised LiteLLM 1.107.0 on PyPI and Docker, spreading malware that steals cloud credentials, developer secrets, and AI provider keys.

Security News
vlt 1.5.0 links skills from JavaScript dependencies to coding agents, with lockfile versioning and Socket data to filter out known malicious packages.