Conversation
6ca4756 to
773f339
Compare
- Update deps: @solana/kit, solana-kite, @staratlas/dev-sage - Remove: @solana/web3.js, @coral-xyz/anchor, @staratlas/sage - Rewrite: connection, wallet, tx sending with Kit patterns - Delete: anchor.ts, programs.ts (no longer needed) - Add: C4 migration plan in docs/
- Add account-registry.ts with discriminator-based decoding - Add account-fetcher.ts with fetchAllAccounts/fetchAccount utils - Add types.ts with AccountWithKey and C4 type re-exports - Rewrite user-account.ts with Profile/Character/KeyPairSigner - Rewrite game.ts to use account-fetcher - Rewrite fleet-state types for __kind discriminators - Update coordinates.ts to use bigint (no more BN) - Update transform-sector/time for bigint - Delete obsolete type-guard files (replaced by __kind)
Rewrote core fleet actions using dev-sage instruction functions: - dock/undock: getIdleToDockedInstruction, getDockedToIdleInstruction - move/end-move/stop-subwarp: getWarpToCoordinateInstruction, getStartSubwarpInstruction, getTheOneFleetStateHandlerInstruction, getStopSubwarpInstruction - mine/end-mine: getStartMiningAsteroidInstruction, getStopMiningAsteroidInstruction - cargo: getTransferCargoToFleetInstruction with cargoId-based transfers Deleted ix/ folder (23 files) - inlined into act layer Removed non-core act files (create-fleet, deposit-cargo, etc.) Patterns: AccountWithKey<T>, KeyPairSigner, Address, fleet.state.__kind Error reduction: 588 -> 392 (33%)
- Rewrite fleet-cargo.ts: cargo now on Fleet struct directly - Rewrite user-fleets.ts: use fetchAllAccounts pattern - Delete cargo-types.ts, cargo-stats-definition.ts, get-fleet-ships.ts: obsolete in C4 - Rewrite starbases.ts: starbase now embedded in StarSystem - Rewrite starbase-by-*.ts: use StarSystem with starbase field - Rewrite starbase-player.ts: use findStarbasePlayerPda pattern - Rewrite planets*.ts: Planet -> CelestialBody - Rewrite resources.ts, mine-items.ts: resource data embedded in CelestialBody - Rewrite world-map.ts: new WorldMap structure for C4 - Stub profile.ts, pod-cleanup.ts, get-random-fleet.ts: TODO for C4 - Fix ships.ts: remove legacy imports - Update util.ts, show-fleet-*.ts, settle-fleet.ts: use C4 types Error count: 433 -> 317 (~27% reduction)
- Migrate all FSM files to C4 types (kind, Docked, coordinates) - Update strategy files: Game → AccountWithKey<Game> - Fix resource refs: game.data.mints → resource config - Remove legacy R4 code: src/lib/, fleetbot/, airdrop/, service/fleet, service/gm - Fix priority fee types: IInstruction → Instruction - Clean compile with 0 errors
- Rewrite airdrop.ts using Kit types (Address, KeyPairSigner) - Use superagent directly for airdrop requests - Integrate with C4 player context for profile checking
Remove deleted fleetbot entry from tsup.config.ts, package.json script, and docker/bin/fleetbot.sh to fix CI/CD build failures.
7a8500c to
a0d9bb9
Compare
C4 stores coordinates as fixed-point with 56 fractional bits. Use .toNumber() and Math.round() for display/matching. Add .toRawTuple() for on-chain instructions.
- Add pre-flight validation for move/dock/undock (state, fuel, cooldown) - Wrap transactions in try-catch, return success/failure instead of throwing - Don't retry TransactionFailedError - on-chain failures won't succeed - Fix fuel level reading from fleet.fuelTank instead of cargoHold - Use character.playerProfile consistently for SAGE instructions - Fix dynamic ship ID lookup in getRandomFleet
- implement tx simulation for compute unit estimation - batch ship deposits to stay under 1232 byte tx limit - handle C4 state struct changes (from/to, duration) - reduce max fleet size 145→100 for safety margin - skip sending txs that fail simulation with program error
…ort pairing - Strategy now uses actual fleet locations to assign mining/transport pairs - Added recovery logic for fleets stuck at incompatible (wrong faction) starbases - Transports deliver to their paired miner's actual location - Added findNearestCompatibleStarbase for recovery to faction-owned starbases - Self-destruct fallback when no compatible starbase is reachable - Fixed cargo availability checks before attempting refuel operations - Improved logging for stuck fleets with location context - Fixed lint/prettier issues with negated conditions
…System The disband was failing with "System mismatch" because it passed player.homeSystem but the fleet could be docked at a different nearby starbase (within fuzzy match radius). Now uses the actual fleetInfo.fleetState.data.system.
When starbase has insufficient crew for fleet creation, automatically add crew using devAddCrew instruction (available on dev/test networks). This allows the bot to create fleets without manually depositing crew.
- Recognize R4 mint addresses (fuel, ammo, food, tool) in resolveCargoId - Skip move to exact coordinates if distance is negligible (< 0.01) - Handle already-docked fleets gracefully in fsmDock - Revert devAddCrew attempt (requires admin key)
Add preciseDistanceFrom method to Coordinates that uses full raw coordinate precision instead of integer-rounded values. This fixes the "Not within range" error when a fleet is close to (but not exactly at) starbase coordinates - the integer distance appeared < 1 unit but the precise distance was ~0.4 units.
Treat "Status mismatch - expected X actual Y" errors as success when the fleet is already in the target state (Docked for dock, Idle for undock). This handles race conditions where the fleet state changed between fetching and transaction execution.
- Add game-resources.ts to derive R4 mints from game.cargoDefinitions - Use known cargo IDs (fuel/ammo from fleet, food=4, tool=5) - Remove dependency on FUEL_MINT, AMMO_MINT, FOOD_MINT, TOOL_MINT config - Update strategies to use getR4MintSet(game) instead of config mints - Simplify resource.ts (only keep atlas mint) This fixes the "R4 cargo IDs empty" error when config mints don't match the game's cargo definitions (e.g., atlasnet vs mainnet).
- Remove FUEL_MINT, AMMO_MINT, FOOD_MINT, TOOL_MINT, ATLAS_MINT from config - Delete resource.ts (R4 mints now come from game data) - R4 resources obtained via getR4MintSet() from game.cargoDefinitions
- Get R4 resources (fuel, ammo, food, tool) from game.resources - Catch all SimulationProgramError gracefully (Status mismatch, Insufficient amount, UnbalancedInstruction) - Catch TransactionFailedError for on-chain failures - Remove verbose error/debug logging for expected failures - Return false/failure instead of throwing exceptions - Add clear warnings when fleets waiting for resources
C4 has no self-destruct instruction. Fleets stuck at incompatible starbases will remain stuck until: 1. Starbase is conquered by player's faction 2. Fleet is destroyed in combat Updated warnings to clearly explain the situation instead of calling a non-existent function.
There was a problem hiding this comment.
Pull request overview
Migrates the codebase toward Star Atlas “C4” by replacing legacy Solana/web3.js + Anchor + older StarAtlas SDK usage with @solana/kit + @staratlas/dev-* packages, while removing deprecated fleetbot/refill/telegram/Gm-market components.
Changes:
- Replace wallet/keypair + instruction building with
@solana/kitand@solana-program/*primitives. - Introduce discriminator-based account fetching/typing for
dev-sageaccounts and update fleet/state/strategy modules accordingly. - Remove legacy fleetbot entrypoint and a large set of R3-era market/refill/telegram modules; update build, Docker, and CI to match.
Reviewed changes
Copilot reviewed 197 out of 200 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| tsup.config.ts | Removes fleetbot build entry from bundling targets |
| src/service/wallet/resource.ts | Removes legacy mint constants tied to removed config fields |
| src/service/wallet/init-keypair.ts | Migrates keypair loading/derivation to @solana/kit and introduces promise-based init |
| src/service/wallet/index.ts | Stops exporting removed wallet resource module |
| src/service/sol/priority-fee/priority-fee-instruction.ts | Replaces web3.js compute budget IX creation with @solana-program/compute-budget |
| src/service/sol/priority-fee/bloxroute-tip-instruction.ts | Migrates SOL transfer instruction creation to @solana-program/system |
| src/service/sol/get-account.ts | Migrates ATA derivation to @solana-program/token PDA helpers |
| src/service/sol/const/market-program.ts | Moves program address parsing to @solana/kit address helper |
| src/service/sol/const/fleet-program.ts | Moves program address parsing to @solana/kit address helper |
| src/service/sol/const/connection.ts | Replaces web3.js Connection with solana-kite connect |
| src/service/sol/anchor.ts | Removes Anchor provider (legacy SDK path) |
| src/service/gm/market.ts | Removes legacy GM market/refill purchasing logic |
| src/service/gm/index.ts | Removes legacy GM exports |
| src/service/fleet/refill-fleet.ts | Removes legacy fleet refilling instruction builder |
| src/service/fleet/index.ts | Removes legacy fleet service exports |
| src/service/fleet/const/index.ts | Removes legacy fleet const re-exports |
| src/service/fleet/const/amounts.ts | Removes legacy refill Amounts type |
| src/main/fleetbot/index.ts | Removes legacy fleetbot entrypoint |
| src/main/fleetbot/fleetbot.ts | Removes legacy fleetbot runtime/cron wiring |
| src/main/basedbot/lib/util/pod-cleanup.ts | Stubs cargo pod cleanup for C4 pending confirmation/implementation |
| src/main/basedbot/lib/types.ts | Adds common typed wrappers and re-exports for dev-sage/dev-profile packages |
| src/main/basedbot/lib/sage/util.ts | Reworks name extraction utilities for C4 account shapes |
| src/main/basedbot/lib/sage/state/user-fleets.ts | Migrates fleet querying/state aggregation to C4 fetcher + dev-sage types |
| src/main/basedbot/lib/sage/state/starbase-by-key.ts | Migrates starbase lookup to StarSystem-based model |
| src/main/basedbot/lib/sage/state/starbase-by-coordinates.ts | Adds coordinate-based StarSystem lookup with tolerance + precise coordinate helpers |
| src/main/basedbot/lib/sage/state/show-fleet-info.ts | Updates fleet-state display logic for C4 state kinds and system/body lookups |
| src/main/basedbot/lib/sage/state/show-fleet-cargo-info.ts | Updates cargo display for new C4 cargo model fields |
| src/main/basedbot/lib/sage/state/settle-fleet.ts | Updates settlement logic for C4 actions and new handler calls |
| src/main/basedbot/lib/sage/state/planets.ts | Renames/aliases planets → celestial bodies for C4 |
| src/main/basedbot/lib/sage/state/planets-by-coordinates.ts | Finds celestial bodies via StarSystem coordinate mapping |
| src/main/basedbot/lib/sage/state/planet-by-key.ts | Migrates planet lookup to CelestialBody lookup |
| src/main/basedbot/lib/sage/state/mine-items.ts | Replaces MineItem accounts with CelestialBody-based mining model |
| src/main/basedbot/lib/sage/state/get-fleet-ships.ts | Removes legacy FleetShips lookup (R3 model) |
| src/main/basedbot/lib/sage/state/game.ts | Adds Game singleton fetching via new account fetcher |
| src/main/basedbot/lib/sage/state/game-resources.ts | Adds game-derived resource mint discovery (R4) with caching helpers |
| src/main/basedbot/lib/sage/state/cargo-types.ts | Removes legacy cargo type resolution logic |
| src/main/basedbot/lib/sage/state/cargo-stats-definition.ts | Removes legacy cargo stats definition fetcher |
| src/main/basedbot/lib/sage/ships.ts | Shifts ship data sourcing to API-only stub for C4 with TODO for on-chain sizing |
| src/main/basedbot/lib/sage/ix/withdraw-cargo.ts | Removes legacy IX builder |
| src/main/basedbot/lib/sage/ix/warp.ts | Removes legacy IX builder |
| src/main/basedbot/lib/sage/ix/unload-cargo.ts | Removes legacy IX builder |
| src/main/basedbot/lib/sage/ix/undock.ts | Removes legacy IX builder |
| src/main/basedbot/lib/sage/ix/subwarp.ts | Removes legacy IX builder |
| src/main/basedbot/lib/sage/ix/stop-warp.ts | Removes legacy IX builder |
| src/main/basedbot/lib/sage/ix/stop-subwarp.ts | Removes legacy IX builder |
| src/main/basedbot/lib/sage/ix/stop-mining.ts | Removes legacy IX builder |
| src/main/basedbot/lib/sage/ix/start-mining.ts | Removes legacy IX builder |
| src/main/basedbot/lib/sage/ix/movement-subwarp-handler.ts | Removes legacy IX builder |
| src/main/basedbot/lib/sage/ix/load-cargo.ts | Removes legacy IX builder |
| src/main/basedbot/lib/sage/ix/idle-to-respawn.ts | Removes legacy IX builder |
| src/main/basedbot/lib/sage/ix/force-drop-fleet-cargo.ts | Removes legacy IX builder |
| src/main/basedbot/lib/sage/ix/fleet-state-handler.ts | Removes legacy mining handler IX builder |
| src/main/basedbot/lib/sage/ix/exit-respawn.ts | Removes legacy IX builder |
| src/main/basedbot/lib/sage/ix/dock.ts | Removes legacy IX builder |
| src/main/basedbot/lib/sage/ix/disbanded-fleet-to-escrow.ts | Removes legacy IX builder |
| src/main/basedbot/lib/sage/ix/disband-fleet.ts | Removes legacy IX builder |
| src/main/basedbot/lib/sage/ix/deposit-cargo.ts | Removes legacy IX builder |
| src/main/basedbot/lib/sage/ix/create-fleet.ts | Removes legacy IX builder |
| src/main/basedbot/lib/sage/ix/close-disbanded-fleet.ts | Removes legacy IX builder |
| src/main/basedbot/lib/sage/ix/add-ship-to-fleet.ts | Removes legacy IX builder |
| src/main/basedbot/lib/sage/ix/add-ship-escrow.ts | Removes legacy IX builder |
| src/main/basedbot/lib/sage/act/withdraw-cargo.ts | Removes legacy action implementation |
| src/main/basedbot/lib/sage/act/unload-all-cargo.ts | Re-exports unloadAllCargo for compatibility |
| src/main/basedbot/lib/sage/act/undock.ts | Implements undock using dev-sage instructions with validation and error handling |
| src/main/basedbot/lib/sage/act/stop-subwarp.ts | Implements stop-subwarp via dev-sage instruction |
| src/main/basedbot/lib/sage/act/self-destruct.ts | Stubs self-destruct for C4 (TODO) |
| src/main/basedbot/lib/sage/act/refuel.ts | Implements refuel via generic loadCargo (C4 cargo IDs) |
| src/main/basedbot/lib/sage/act/rearm.ts | Implements rearm via generic loadCargo (C4 cargo IDs) |
| src/main/basedbot/lib/sage/act/mine.ts | Implements start-mining via dev-sage instruction and asteroid resource ID extraction |
| src/main/basedbot/lib/sage/act/exit-respawn.ts | Removes legacy exit-respawn implementation |
| src/main/basedbot/lib/sage/act/end-move.ts | Implements end-move via TheOneFleetStateHandler and adds arrival-time helpers |
| src/main/basedbot/lib/sage/act/disband-fleet.ts | Implements disband via dev-sage instruction gated on Docked state |
| src/main/basedbot/lib/programs.ts | Removes legacy Anchor Program construction / program ID map |
| src/main/basedbot/lib/fleet-state/types.ts | Updates fleet state discriminators/data types for C4 state model |
| src/main/basedbot/lib/fleet-state/type-guard/starbase-loading-bay.ts | Removes legacy raw type guards |
| src/main/basedbot/lib/fleet-state/type-guard/respawn.ts | Removes legacy raw type guards |
| src/main/basedbot/lib/fleet-state/type-guard/move-warp.ts | Removes legacy raw type guards |
| src/main/basedbot/lib/fleet-state/type-guard/move-sub-warp.ts | Removes legacy raw type guards |
| src/main/basedbot/lib/fleet-state/type-guard/mine-asteroid.ts | Removes legacy raw type guards |
| src/main/basedbot/lib/fleet-state/type-guard/idle.ts | Removes legacy raw type guards |
| src/main/basedbot/lib/fleet-state/transform/transform-time.ts | Updates timestamp transform to accept bigint/number |
| src/main/basedbot/lib/fleet-state/transform/transform-sector.ts | Adds C4 fixed-point coordinate parsing with raw precision preservation |
| src/main/basedbot/lib/account-registry.ts | Adds centralized registry for discriminator + decoder based account fetching |
| src/main/basedbot/lib/account-fetcher.ts | Adds fetch helpers using solana-kite connection factories |
| src/main/basedbot/index.ts | Adds Node workaround for isSecureContext expectation from bundled browser build |
| src/main/basedbot/fsm/info.ts | Updates FSM info state handling for C4 state kinds/data fields |
| src/main/basedbot/fsm/configs/mine/mine.ts | Updates mine config selection for C4 mineable shape + safety checks |
| src/main/basedbot/fsm/configs/mine/mine-titanium-ore.ts | Adds null checks and uses typed imports |
| src/main/basedbot/fsm/configs/mine/mine-silicia.ts | Adds null checks and uses typed imports |
| src/main/basedbot/fsm/configs/mine/mine-rochinol.ts | Adds null checks and uses typed imports |
| src/main/basedbot/fsm/configs/mine/mine-nitrogen.ts | Adds null checks and uses typed imports |
| src/main/basedbot/fsm/configs/mine/mine-lumanite.ts | Adds null checks and uses typed imports |
| src/main/basedbot/fsm/configs/mine/mine-iron-ore.ts | Adds null checks and uses typed imports |
| src/main/basedbot/fsm/configs/mine/mine-hydrogen.ts | Adds null checks and uses typed imports |
| src/main/basedbot/fsm/configs/mine/mine-diamond.ts | Adds null checks and uses typed imports |
| src/main/basedbot/fsm/configs/mine/mine-copper-ore.ts | Adds null checks and uses typed imports |
| src/main/basedbot/fsm/configs/mine/mine-carbon.ts | Adds null checks and uses typed imports |
| src/main/basedbot/fsm/configs/mine/mine-biomass.ts | Adds null checks (but includes a coordinate mismatch bug; see suggestions) |
| src/main/basedbot/fleet-strategies/strategy-config.ts | Updates fleet ship typing to new C4 create-fleet API |
| src/main/basedbot/fleet-strategies/mainnet-lu-strategy.ts | Updates Game type to AccountWithKey wrapper |
| src/main/basedbot/fleet-strategies/mainnet-gellsn-strategy.ts | Updates Game type to AccountWithKey wrapper |
| src/main/basedbot/fleet-strategies/get-fleet-strategy.ts | Switches player identifier usage and threads existing fleets |
| src/main/basedbot/fleet-strategies/disband-all-strategy.ts | Updates Game type to AccountWithKey wrapper |
| src/main/basedbot/fleet-strategies/destruct-all-strategy.ts | Updates Game type to AccountWithKey wrapper |
| src/main/basedbot/fleet-strategies/atlasnet-qt-strategy.ts | Uses game-derived R4 mint set and updated fleet selection signature |
| src/main/basedbot/fleet-strategies/atlasnet-lu-strategy.ts | Updates Game type to AccountWithKey wrapper |
| src/main/airdrop/airdrop.ts | Migrates airdrop logic to kit signers + C4 player context; adds faucet request helper |
| src/lib/telegram/telegram-bot.ts | Removes telegram bot implementation |
| src/lib/telegram/response/wrong-param-count.ts | Removes legacy telegram response helper |
| src/lib/telegram/response/unknown-wallet.ts | Removes legacy telegram response helper |
| src/lib/telegram/response/unauthorized.ts | Removes legacy telegram response helper |
| src/lib/telegram/response/index.ts | Removes telegram response exports |
| src/lib/telegram/response/auth-pending.ts | Removes legacy telegram response helper |
| src/lib/telegram/response/already-registered.ts | Removes legacy telegram response helper |
| src/lib/telegram/middleware/params.ts | Removes telegram params middleware |
| src/lib/telegram/middleware/index.ts | Removes telegram middleware exports |
| src/lib/telegram/middleware/auth.ts | Removes telegram auth middleware |
| src/lib/telegram/index.ts | Removes telegram module exports |
| src/lib/telegram/context-message-update.ts | Removes telegram context type |
| src/lib/telegram/commands/withdraw.ts | Removes telegram command |
| src/lib/telegram/commands/verify.ts | Removes telegram command |
| src/lib/telegram/commands/transactions.ts | Removes telegram command |
| src/lib/telegram/commands/tip.ts | Removes telegram command |
| src/lib/telegram/commands/support.ts | Removes telegram command |
| src/lib/telegram/commands/stats.ts | Removes telegram command |
| src/lib/telegram/commands/refills.ts | Removes telegram command |
| src/lib/telegram/commands/refill.ts | Removes telegram command |
| src/lib/telegram/commands/meme/wen.ts | Removes telegram command |
| src/lib/telegram/commands/meme/porn.ts | Removes telegram command |
| src/lib/telegram/commands/meme/kitten.ts | Removes telegram command |
| src/lib/telegram/commands/meme/index.ts | Removes telegram meme exports |
| src/lib/telegram/commands/logout.ts | Removes telegram command |
| src/lib/telegram/commands/index.ts | Removes telegram command exports |
| src/lib/telegram/commands/help.ts | Removes telegram command |
| src/lib/telegram/commands/enable.ts | Removes telegram command |
| src/lib/telegram/commands/enable-notify.ts | Removes telegram command |
| src/lib/telegram/commands/disable.ts | Removes telegram command |
| src/lib/telegram/commands/disable-notify.ts | Removes telegram command |
| src/lib/refill.ts | Removes legacy refill cron implementation |
| src/lib/refill-strategy/refill-strategy.ts | Removes legacy refill strategy type |
| src/lib/refill-strategy/optimal-refill-strategy.ts | Removes legacy refill strategy implementation |
| src/lib/refill-strategy/index.ts | Removes legacy refill strategy exports |
| src/lib/refill-strategy/full-refill-strategy.ts | Removes legacy refill strategy implementation |
| src/lib/refill-player.ts | Removes legacy refill player implementation |
| src/lib/index.ts | Removes legacy lib barrel exports |
| src/lib/get-price.ts | Removes legacy price helper |
| src/lib/fleet-depletion-info.ts | Removes legacy depletion helper |
| src/lib/ensure-wallet.ts | Removes legacy wallet upsert helper |
| src/lib/const/max.ts | Removes legacy Big.js helper |
| src/lib/const/index.ts | Removes legacy const exports |
| src/lib/const/fleet-refill.ts | Removes legacy refill const typing |
| src/lib/check-transactions.ts | Removes legacy transaction scanning |
| src/lib/check-r4-transactions.ts | Removes legacy R4 scanning |
| src/lib/check-atlas-transactions.ts | Removes legacy ATLAS scanning |
| src/lib/airdrop.ts | Removes legacy airdrop helper (replaced in main module) |
| src/db/entities/tx-cache.ts | Keeps entity but relaxes transaction json typing |
| src/config/config.ts | Removes mint envs and adds default faction/character config for C4 |
| package.json | Replaces dependencies with kit/dev-sage stack; updates scripts |
| eslint.config.mjs | Ignores contrib directory |
| docker/Dockerfile | Removes fleetbot artifact from image |
| contrib/solana-dev-skill | Adds submodule reference for Solana development skill docs |
| .github/workflows/cicd.yml | Passes NPM token into install/build steps |
| .github/actions/install/action.yml | Adds optional npm token input and writes .npmrc for auth |
| .github/actions/docker-buildx/action.yml | Threads npm token into docker build secrets |
| .cursor/rules/wait-for-instructions.mdc | Adds Cursor rule doc |
| .cursor/rules/solana-dev.mdc | Adds Cursor rule doc |
| .cursor/rules/reference-code.mdc | Adds Cursor rule doc |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const result = await rpcFetch({ | ||
| jsonrpc: '2.0', | ||
| id: 1, | ||
| method: 'getRecentPrioritizationFees', | ||
| params: [[]], | ||
| }) | ||
|
|
||
| const feeData = (result as any).result.result as Array<{ | ||
| const feeData = (result as any).result as Array<{ | ||
| slot: number | ||
| prioritizationFee: number | ||
| }> |
There was a problem hiding this comment.
This changes both the request shape and the response parsing for getRecentPrioritizationFees. Previously the code parsed result.result.result, and the params included at least one relevant account/program id; now it sends params: [[]] and reads result.result. Unless rpcFetch already unwraps envelopes, this is likely to break fee parsing and/or always fall back. Align the request/response with the actual JSON-RPC payload returned by rpcFetch, and include a meaningful account list (or correctly omit params) so the RPC can return non-empty fee estimates.
| const allFleets = await fetchAllAccounts('Fleet') | ||
| return allFleets.filter( | ||
| (f) => f.ownerProfile === player.character.playerProfile, | ||
| ) |
There was a problem hiding this comment.
Fetching all Fleet accounts and filtering client-side will become very expensive on shared clusters. If solana-kite supports it, prefer server-side filtering (memcmp / indexed fields) or a dedicated query/factory that fetches only fleets owned by ownerProfile.
| if (typeof coord === 'object' && 'raw' in coord) { | ||
| const raw = (coord as RawCoord).raw | ||
| // Assume 56 fractional bits for I8F56 format | ||
| const fractionalBits = 56 | ||
| const scale = 1n << BigInt(fractionalBits) | ||
| return Math.round(Number(raw) / Number(scale)) | ||
| } |
There was a problem hiding this comment.
Converting raw and scale bigints to Number can lose precision (and can overflow for large magnitudes), leading to incorrect coordinate rounding—exactly what this helper is trying to avoid. Compute the integer part using bigint division first (e.g., raw / scale) and only then convert the quotient to number for display.
| role: item.attributes.spec as ShipRole, | ||
| mint: new PublicKey(item.mint), | ||
| mint: item.mint as Address, | ||
| make: item.attributes.make as ShipMake, | ||
| model: (item.attributes.model as ShipModel) || 'Unknown', |
There was a problem hiding this comment.
Casting item.mint to Address bypasses validation and can allow malformed/invalid addresses to flow into on-chain instruction building later. Prefer parsing/validating with address(item.mint) (or an equivalent safe constructor) and handling failures explicitly.
| await Promise.all( | ||
| config.app.airdropWallets.map((w) => | ||
| airdropOrCreateProfile(new PublicKey(w)), | ||
| airdropOrCreateProfile(w as Address, keys), | ||
| ), | ||
| ) |
There was a problem hiding this comment.
Casting config values to Address skips validation; an invalid address string will either fail later in a less obvious way or be sent to the faucet incorrectly. Parse upfront with address(w) (and log/skip invalid entries) so failures are immediate and actionable.
- Fix mine-biomass coordinate mismatch (resource lookup used wrong coords) - Fix bigint precision loss in transform-sector (use bigint division before Number conversion) - Fix priority-fee response parsing (correct rpcFetch envelope unwrapping, add fleet program to params) - Fix init-keypair race condition (replace mutable export with async getKeyPair accessor) - Fix fetchAccount perf (use fetchEncodedAccount for single getAccountInfo call instead of fetching all) - Fix getUserFleets perf (use getProgramAccounts with memcmp filter on ownerProfile at offset 42) - Guard isSecureContext assignment with typeof check + Object.defineProperty - Validate addresses with address() instead of unsafe casts in ships.ts and airdrop.ts - Fix pod-cleanup stub return type from never[] to unknown[] Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 197 out of 200 changed files in this pull request and generated 10 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const derivedKey = derivePath(path, seed.toString('hex')).key | ||
|
|
||
| logger.debug(`${path} => ${keypair.publicKey.toBase58()}`) | ||
| const signer = await createKeyPairSignerFromPrivateKeyBytes(derivedKey) | ||
|
|
||
| if (keypair.publicKey.equals(pubKey)) { | ||
| logger.info(`Found keypair for ${pubKey.toBase58()} at ${path}`) | ||
| logger.debug(`${path} => ${signer.address}`) | ||
|
|
||
| return keypair | ||
| if (signer.address === pubKey) { | ||
| logger.info(`Found keypair for ${pubKey} at ${path}`) | ||
| return signer |
There was a problem hiding this comment.
derivePath(...).key from ed25519-hd-key is typically a 32-byte seed (same shape that Keypair.fromSeed() expected). createKeyPairSignerFromPrivateKeyBytes() generally expects private key bytes (often 64-byte secret key), so this is very likely to derive the wrong address or throw. Prefer using a “from seed” constructor (if available in @solana/kit) or explicitly expand the 32-byte seed into the expected private-key format before creating the signer.
| const systems = await fetchAllAccounts('StarSystem') | ||
|
|
||
| return ( | ||
| systems.find((system) => { | ||
| const sysCoords = system.coordinates as unknown as [ | ||
| C4Coord, | ||
| C4Coord, | ||
| ] | ||
| const sysX = Math.round(sysCoords[0].toNumber()) | ||
| const sysY = Math.round(sysCoords[1].toNumber()) | ||
| if (tolerance === 0) { | ||
| return sysX === coordinates.x && sysY === coordinates.y | ||
| } | ||
| // Fuzzy match within tolerance | ||
| const dx = Math.abs(sysX - coordinates.x) | ||
| const dy = Math.abs(sysY - coordinates.y) | ||
| return dx <= tolerance && dy <= tolerance | ||
| }) ?? null | ||
| ) |
There was a problem hiding this comment.
Fetching all StarSystem accounts on every coordinate lookup will be a major bottleneck as the number of systems grows, especially since this is likely run frequently during FSM ticks. Consider introducing an in-memory cache/index keyed by (x,y) (and maybe a tolerance-aware lookup) that is built once per process (or periodically refreshed) rather than re-querying and re-scanning for each call.
| // Cached resources from game | ||
| let cachedResources: GameResources | null = null |
There was a problem hiding this comment.
cachedResources is global and not keyed by game.key (or cluster). If this process ever loads a different Game (tests, multiple environments, hot reload, etc.), getGameResources() can return mints for the wrong game. Cache should be keyed by game.key (or removed), or at least cleared when game.key changes.
There was a problem hiding this comment.
probably not an issue here. one bot won't run on multiple games / clusters at the same time.
| export function getGameResources( | ||
| game: AccountWithKey<Game>, | ||
| _fleet?: AccountWithKey<Fleet>, | ||
| ): GameResources { | ||
| // Use cached if available | ||
| if (cachedResources) { | ||
| return cachedResources | ||
| } |
There was a problem hiding this comment.
cachedResources is global and not keyed by game.key (or cluster). If this process ever loads a different Game (tests, multiple environments, hot reload, etc.), getGameResources() can return mints for the wrong game. Cache should be keyed by game.key (or removed), or at least cleared when game.key changes.
| export const getCleanPodsByStarbasePlayerAccounts = async ( | ||
| connection: Connection, | ||
| cargoProgram: CargoIDLProgram, | ||
| starbasePlayer: PublicKey, | ||
| _starbasePlayer: Address, | ||
| ): Promise<PodCleanup | undefined> => { | ||
| const cargoPods = await getCargoPodsByAuthority( | ||
| connection, | ||
| cargoProgram, | ||
| starbasePlayer, | ||
| ) | ||
| if (cargoPods.length > 1) { | ||
| let podsToClean = cargoPods.map((cargoPod) => { | ||
| if (cargoPod.type === 'error') | ||
| throw new Error('Error reading CargoPod account') | ||
| return cargoPod.data | ||
| }) | ||
| const mainPod = podsToClean.reduce((prev, current) => { | ||
| return prev.data.openTokenAccounts > current.data.openTokenAccounts | ||
| ? prev | ||
| : current | ||
| }) | ||
| podsToClean = podsToClean.filter((it) => !it.key.equals(mainPod.key)) | ||
| const podsAndTokensToClean: Array<[PublicKey, Account[]]> = | ||
| await Promise.all( | ||
| podsToClean.map(async (thisPod) => { | ||
| const podTokenAccounts = | ||
| await getParsedTokenAccountsByOwner( | ||
| connection, | ||
| thisPod.key, | ||
| ) | ||
| return [thisPod.key, podTokenAccounts] | ||
| }), | ||
| ) | ||
|
|
||
| return { | ||
| mainPod: mainPod.key, | ||
| podsAndTokensToClean, | ||
| cargoSeqId: mainPod.data.seqId, | ||
| } | ||
| } | ||
| // In C4, cargo pod handling may be different | ||
| // Return undefined to indicate no cleanup needed for now | ||
| return undefined | ||
| } |
There was a problem hiding this comment.
These functions preserve the old API surface but now silently no-op, which can hide functional regressions (callers will “succeed” without cleaning). If cleanup is intentionally disabled for C4, consider making this explicit via a feature flag in config, or throw a clear “Not implemented for C4” error so behavior is unambiguous in production.
There was a problem hiding this comment.
this can be removed entirely.
| export const getPodCleanupInstructions = ( | ||
| podCleanup: PodCleanup, | ||
| sageProgram: SageIDLProgram, | ||
| cargoProgram: CargoIDLProgram, | ||
| starbasePlayer: PublicKey, | ||
| starbase: PublicKey, | ||
| playerProfile: PublicKey, | ||
| profileFaction: PublicKey, | ||
| cargoStatsDefinition: PublicKey, | ||
| gameId: PublicKey, | ||
| gameState: PublicKey, | ||
| key: AsyncSigner, | ||
| keyIndex: number, | ||
| ) => { | ||
| const cleanInstructions: InstructionReturn[] = [] | ||
| const newTokenAccounts: string[] = [] | ||
| if (podCleanup.podsAndTokensToClean.length > 1) { | ||
| for ( | ||
| let index2 = 0; | ||
| index2 < podCleanup.podsAndTokensToClean.length; | ||
| index2++ | ||
| ) { | ||
| const element = podCleanup.podsAndTokensToClean[index2] | ||
| const thisPodKey = element[0] | ||
| const podTokenAccounts = element[1] | ||
| if (podTokenAccounts.length > 0) { | ||
| for ( | ||
| let index3 = 0; | ||
| index3 < podTokenAccounts.length; | ||
| index3++ | ||
| ) { | ||
| const tokenData = podTokenAccounts[index3] | ||
| const cargoType = CargoType.findAddress( | ||
| cargoProgram, | ||
| cargoStatsDefinition, | ||
| tokenData.mint, | ||
| podCleanup.cargoSeqId, | ||
| )[0] | ||
| if (Number(tokenData.delegatedAmount) > 0) { | ||
| const tokenTo = createAssociatedTokenAccountIdempotent( | ||
| tokenData.mint, | ||
| podCleanup.mainPod, | ||
| true, | ||
| TOKEN_PROGRAM_ID, | ||
| ) | ||
| const tokenToBase58 = tokenTo.address.toBase58() | ||
| if (!newTokenAccounts.includes(tokenToBase58)) { | ||
| newTokenAccounts.push(tokenToBase58) | ||
| cleanInstructions.push(tokenTo.instructions) | ||
| } | ||
| const transferIx = | ||
| StarbasePlayer.transferCargoAtStarbase( | ||
| sageProgram, | ||
| cargoProgram, | ||
| starbasePlayer, | ||
| key, | ||
| 'funder', | ||
| playerProfile, | ||
| profileFaction, | ||
| starbase, | ||
| thisPodKey, | ||
| podCleanup.mainPod, | ||
| cargoType, | ||
| cargoStatsDefinition, | ||
| tokenData.address, | ||
| tokenTo.address, | ||
| tokenData.mint, | ||
| gameId, | ||
| gameState, | ||
| { | ||
| amount: new BN( | ||
| tokenData.delegatedAmount.toString(), | ||
| ), | ||
| keyIndex, | ||
| }, | ||
| ) | ||
| cleanInstructions.push(transferIx) | ||
| } else { | ||
| const closeIx = | ||
| StarbasePlayer.closeStarbaseCargoTokenAccount( | ||
| sageProgram, | ||
| cargoProgram, | ||
| starbasePlayer, | ||
| key, | ||
| 'funder', | ||
| playerProfile, | ||
| profileFaction, | ||
| starbase, | ||
| thisPodKey, | ||
| cargoType, | ||
| cargoStatsDefinition, | ||
| tokenData.address, | ||
| tokenData.mint, | ||
| gameId, | ||
| gameState, | ||
| { | ||
| keyIndex, | ||
| }, | ||
| ) | ||
| cleanInstructions.push(closeIx) | ||
| } | ||
| } | ||
| } | ||
| cleanInstructions.push( | ||
| StarbasePlayer.removeCargoPod( | ||
| sageProgram, | ||
| cargoProgram, | ||
| starbasePlayer, | ||
| key, | ||
| playerProfile, | ||
| profileFaction, | ||
| 'funder', | ||
| starbase, | ||
| thisPodKey, | ||
| gameId, | ||
| gameState, | ||
| { | ||
| keyIndex, | ||
| }, | ||
| ), | ||
| ) | ||
| } | ||
| } | ||
| return cleanInstructions | ||
| _podCleanup: PodCleanup, | ||
| ): unknown[] => { | ||
| // Return empty array - no cleanup instructions for now | ||
| return [] | ||
| } |
There was a problem hiding this comment.
These functions preserve the old API surface but now silently no-op, which can hide functional regressions (callers will “succeed” without cleaning). If cleanup is intentionally disabled for C4, consider making this explicit via a feature flag in config, or throw a clear “Not implemented for C4” error so behavior is unambiguous in production.
src/main/basedbot/index.ts
Outdated
| if (typeof (globalThis as any).isSecureContext === 'undefined') { | ||
| Object.defineProperty(globalThis, 'isSecureContext', { | ||
| value: true, | ||
| writable: false, | ||
| configurable: true, | ||
| enumerable: true, | ||
| }) | ||
| } |
There was a problem hiding this comment.
Setting globalThis.isSecureContext = true globally can affect unrelated libraries/logic that use this flag for security-sensitive decisions. Prefer scoping the workaround as narrowly as possible (e.g., a dedicated polyfill module imported only by the specific entrypoints that need @staratlas/dev-sage, and/or set it to a value derived from runtime conditions rather than always true).
There was a problem hiding this comment.
afaik, this was solved upsteam already, but needs to be tested.
| export function getFuelNeeded(fleet: AccountWithKey<Fleet>): number { | ||
| const currentFuel = Number(fleet.fuelTank?.amount ?? 0n) | ||
| const maxFuel = Number(fleet.stats?.cargoStats?.fuelCapacity ?? 0) | ||
| return Math.max(0, maxFuel - currentFuel) | ||
| } |
There was a problem hiding this comment.
Converting bigint amounts to number can lose precision if values exceed Number.MAX_SAFE_INTEGER (and can produce incorrect deltas if capacities/amounts scale up). This computation is safer as bigint arithmetic end-to-end (return bigint needed), converting to number only at the final boundary where the downstream instruction strictly requires it.
| export function getAmmoNeeded(fleet: AccountWithKey<Fleet>): number { | ||
| const currentAmmo = Number(fleet.ammoBank?.amount ?? 0n) | ||
| const maxAmmo = Number(fleet.stats?.cargoStats?.ammoCapacity ?? 0) | ||
| return Math.max(0, maxAmmo - currentAmmo) | ||
| } |
There was a problem hiding this comment.
Same issue as refuel: converting bigint balances to number can truncate/overflow and miscompute the needed amount. Prefer bigint arithmetic and only coerce at the API boundary if required.
| export const createPriorityFeeInstruction = async ( | ||
| instructions: TransactionInstruction[], | ||
| ): Promise<TransactionInstruction> => { | ||
| const transaction = getDummyTransaction(instructions, keyPair.publicKey, []) | ||
| let encodedTx: string | undefined | ||
| try { | ||
| encodedTx = base58.encode(transaction.serialize()) | ||
| } catch (e) { | ||
| logger.error((e as any).message) | ||
| } | ||
|
|
||
| _instructions: Instruction[], | ||
| ): Promise<Instruction> => { |
There was a problem hiding this comment.
The function still accepts instructions but no longer uses them (it’s now only fetching fees scoped to fleetProgram). Consider removing this parameter (or renaming the function) to reflect current behavior, or re-introduce instruction-based scoping if callers expect the fee estimation to depend on the transaction content.
- Remove pod-cleanup.ts entirely (no consumers, no longer needed in C4) - Remove unused _instructions param from createPriorityFeeInstruction - Use bigint arithmetic in refuel/rearm to avoid precision loss on large values - Cache StarSystem accounts in starbase-by-coordinates (5min TTL) - Remove isSecureContext workaround (solved upstream in dev-sage) Co-authored-by: Cursor <cursoragent@cursor.com>
No description provided.