import { getAccount } from '@solana/spl-token'; import { ComputeBudgetProgram, Connection, Keypair } from '@solana/web3.js'; import { BN } from '@staratlas/anchor'; import { CargoType } from '@staratlas/cargo'; import { ixToIxReturn, keypairToAsyncSigner, mintToTokenAccount, readFromRPCOrError, stringToByteArray, transferToTokenAccount, } from '@staratlas/data-source'; import { Fleet, Sector, ShipStats, SurveyDataUnitTracker, sectorDataEquals, surveyDataUnitTrackerDataEquals, } from '../src'; import { SageGameTest, checkTokenBalance } from './helpers'; describe('Survey Data Units', () => { const connection = new Connection('http://localhost:8899', 'confirmed'); const walletKeypair = Keypair.generate(); const walletSigner = keypairToAsyncSigner(walletKeypair); let sageGameTest: SageGameTest; beforeAll(async () => { const airdropTx = await connection.requestAirdrop( walletSigner.publicKey(), 500_000_000_000, ); await connection.confirmTransaction(airdropTx); sageGameTest = await SageGameTest.createGame({ funder: walletKeypair, connection, }); }); const _tracker = keypairToAsyncSigner(Keypair.generate()); it('can register a tracker', async () => { if (!sageGameTest.mints) { throw 'mints not registered'; } const trackerConfig = { coordinatesRange: [new BN(-10), new BN(10)], cssCoordinates: [ [new BN(-400), new BN(300)], [new BN(400), new BN(300)], [new BN(0), new BN(-390)], ], originCoordinates: [new BN(0), new BN(0)], cssMaxDistance: 5000, originMaxDistance: 10000, distanceWeighting: 500, tMax: new BN(100), xMul: 1000, yMul: 2500, zMul: 15, sduMaxPerSector: 2500, scanChanceRegenPeriod: 10, }; await sageGameTest.sendToChain( SurveyDataUnitTracker.registerSurveyDataUnitTracker( sageGameTest.program, sageGameTest.profiles.superuser.key, sageGameTest.profiles.superuser.profile, _tracker, sageGameTest.mints[SageGameTest.FOOD] /** intentionally wrong */, sageGameTest.mints[SageGameTest.FOOD] /** intentionally wrong */, sageGameTest.gameId, { ...trackerConfig, keyIndex: sageGameTest.profiles.superuser.index, }, ), ); const tracker = await readFromRPCOrError( sageGameTest.connection, sageGameTest.program, _tracker.publicKey(), SurveyDataUnitTracker, 'confirmed', ); const expected = { ...trackerConfig, version: 0, gameId: sageGameTest.gameId, sduMint: sageGameTest.mints[SageGameTest.FOOD] /** intentionally wrong */, resourceMint: sageGameTest.mints[SageGameTest.FOOD] /** intentionally wrong */, signer: tracker.data.signer, signerBump: tracker.data.signerBump, }; expect(surveyDataUnitTrackerDataEquals(expected, tracker.data)).toBe(true); }); it('can update a tracker', async () => { if (!sageGameTest.mints) { throw 'mints not registered'; } const newTrackerConfig = SageGameTest.getDefaultSDUTrackerStats(); await sageGameTest.sendToChain( SurveyDataUnitTracker.updateSurveyDataUnitTracker( sageGameTest.program, sageGameTest.profiles.superuser.key, sageGameTest.profiles.superuser.profile, _tracker.publicKey(), sageGameTest.gameId, { ...newTrackerConfig, keyIndex: sageGameTest.profiles.superuser.index, }, { sduMint: sageGameTest.mints[SageGameTest.SDU], resourceMint: sageGameTest.mints[SageGameTest.REPAIR_KIT], }, ), ); const tracker = await readFromRPCOrError( sageGameTest.connection, sageGameTest.program, _tracker.publicKey(), SurveyDataUnitTracker, 'confirmed', ); const expected = { ...newTrackerConfig, version: tracker.data.version, gameId: tracker.data.gameId, sduMint: sageGameTest.mints[SageGameTest.SDU], resourceMint: sageGameTest.mints[SageGameTest.REPAIR_KIT], signer: tracker.data.signer, signerBump: tracker.data.signerBump, }; expect(surveyDataUnitTrackerDataEquals(expected, tracker.data)).toBe(true); expect( tracker.data.sduMint.equals(sageGameTest.mints[SageGameTest.SDU]), ).toBe(true); expect( tracker.data.resourceMint.equals( sageGameTest.mints[SageGameTest.REPAIR_KIT], ), ).toBe(true); await sageGameTest.sendToChain( SurveyDataUnitTracker.updateSurveyDataUnitTracker( sageGameTest.program, sageGameTest.profiles.superuser.key, sageGameTest.profiles.superuser.profile, _tracker.publicKey(), sageGameTest.gameId, { scanChanceRegenPeriod: 101, sduMaxPerSector: 1501, keyIndex: sageGameTest.profiles.superuser.index, }, ), ); const tracker2 = await readFromRPCOrError( sageGameTest.connection, sageGameTest.program, _tracker.publicKey(), SurveyDataUnitTracker, 'confirmed', ); const expected2 = { ...expected, scanChanceRegenPeriod: 101, sduMaxPerSector: 1501, }; expect(surveyDataUnitTrackerDataEquals(expected2, tracker2.data)).toBe( true, ); }); it('can fund SDU bank', async () => { if (!sageGameTest.mints) { throw 'mints not registered'; } const tracker = await readFromRPCOrError( sageGameTest.connection, sageGameTest.program, _tracker.publicKey(), SurveyDataUnitTracker, 'confirmed', ); const amount = 1_000_000; const sduTokenFrom = await sageGameTest.getOrCreateAssociatedTokenAccount( sageGameTest.mints[SageGameTest.SDU], sageGameTest.profiles.superuser.key.publicKey(), true, ); const bankToken = await sageGameTest.getOrCreateAssociatedTokenAccount( sageGameTest.mints[SageGameTest.SDU], tracker.data.signer, true, ); await sageGameTest.sendToChain([ mintToTokenAccount( sageGameTest.profiles.superuser.key, sageGameTest.mints[SageGameTest.SDU], sduTokenFrom, amount, ), SurveyDataUnitTracker.fundSurveyDataUnitTrackerBank( tracker.data, sageGameTest.profiles.superuser.key, sduTokenFrom, amount, ), ]); await checkTokenBalance(bankToken, new BN(amount), sageGameTest.connection); }); it('can drain SDU bank', async () => { if (!sageGameTest.mints) { throw 'mints not registered'; } const tracker = await readFromRPCOrError( sageGameTest.connection, sageGameTest.program, _tracker.publicKey(), SurveyDataUnitTracker, 'confirmed', ); const sduTokenTo = await sageGameTest.getOrCreateAssociatedTokenAccount( sageGameTest.mints[SageGameTest.SDU], sageGameTest.profiles.superuser.key.publicKey(), true, ); const bankToken = await sageGameTest.getOrCreateAssociatedTokenAccount( sageGameTest.mints[SageGameTest.SDU], tracker.data.signer, true, ); await sageGameTest.sendToChain([ SurveyDataUnitTracker.drainSurveyDataUnitsBank( sageGameTest.program, sageGameTest.profiles.superuser.key, sageGameTest.profiles.superuser.profile, 'funder', _tracker.publicKey(), sageGameTest.gameId, bankToken, sduTokenTo, { keyIndex: sageGameTest.profiles.superuser.index, }, ), ]); expect(await connection.getAccountInfo(bankToken, 'processed')).toBeNull; // fund again to have tokens for the other tests const amount = 1_000_000; await sageGameTest.sendToChain( transferToTokenAccount( sageGameTest.profiles.superuser.key, sduTokenTo, bankToken, amount, ), ); await checkTokenBalance(bankToken, new BN(amount), sageGameTest.connection); }); it('can scan', async () => { if ( !sageGameTest.gameState || !sageGameTest.cargoStatsDefinition || !sageGameTest.mints || !sageGameTest.pointCategories || !sageGameTest.fleets ) { throw 'mints not registered'; } const trackerBefore = await readFromRPCOrError( sageGameTest.connection, sageGameTest.program, _tracker.publicKey(), SurveyDataUnitTracker, 'confirmed', ); const fleet = sageGameTest.fleets[0]; const fleetAccountBefore = await readFromRPCOrError( sageGameTest.connection, sageGameTest.program, fleet, Fleet, 'confirmed', ); if (!fleetAccountBefore.state.Idle) { throw 'Fleet should be in idle state'; } const coordinates = fleetAccountBefore.state.Idle.sector as [BN, BN]; const sectorKey = Sector.findAddress( sageGameTest.program, sageGameTest.gameId, coordinates, )[0]; const sectorData = await readFromRPCOrError( sageGameTest.connection, sageGameTest.program, sectorKey, Sector, 'confirmed', ); expect(sectorData.data.lastScanTime.eq(new BN(0))).toBe(true); expect(sectorData.data.lastScanChance).toBe(0); const sduTokenFrom = await sageGameTest.getOrCreateAssociatedTokenAccount( sageGameTest.mints[SageGameTest.SDU], trackerBefore.data.signer, true, ); const repairKitTokenFrom = await sageGameTest.getOrCreateAssociatedTokenAccount( sageGameTest.mints[SageGameTest.REPAIR_KIT], fleetAccountBefore.data.cargoHold, true, ); const sduTokenTo = await sageGameTest.getOrCreateAssociatedTokenAccount( sageGameTest.mints[SageGameTest.SDU], fleetAccountBefore.data.cargoHold, true, ); const repairKitTokenFromAccountBefore = await getAccount( connection, repairKitTokenFrom, 'confirmed', ); const dataRunningXpBefore = ( await sageGameTest.loadUserPoints( sageGameTest.pointCategories.dataRunningXpCategory, ) ).data.earnedPoints; const councilRankXpBefore = ( await sageGameTest.loadUserPoints( sageGameTest.pointCategories.councilRankXpCategory, ) ).data.earnedPoints; await sageGameTest.sendToChain( SurveyDataUnitTracker.scanForSurveyDataUnits( sageGameTest.program, sageGameTest.cargoProgram, sageGameTest.pointsProgram, sageGameTest.profiles.player1.key, sageGameTest.profiles.player1.profile, sageGameTest.getProfileFactionAddress( sageGameTest.profiles.player1.profile, ), fleet, sectorKey, _tracker.publicKey(), fleetAccountBefore.data.cargoHold, CargoType.findAddress( sageGameTest.cargoProgram, sageGameTest.cargoStatsDefinition, sageGameTest.mints[SageGameTest.SDU], 0, )[0], CargoType.findAddress( sageGameTest.cargoProgram, sageGameTest.cargoStatsDefinition, sageGameTest.mints[SageGameTest.REPAIR_KIT], 0, )[0], sageGameTest.cargoStatsDefinition, sduTokenFrom, sduTokenTo, repairKitTokenFrom, sageGameTest.mints[SageGameTest.REPAIR_KIT], sageGameTest.getUserPointsAccountAddress( sageGameTest.pointCategories.dataRunningXpCategory, ), sageGameTest.pointCategories.dataRunningXpCategory, sageGameTest.getPointsModifierAddress( sageGameTest.pointCategories.dataRunningXpCategory, ), sageGameTest.getUserPointsAccountAddress( sageGameTest.pointCategories.councilRankXpCategory, ), sageGameTest.pointCategories.councilRankXpCategory, sageGameTest.getPointsModifierAddress( sageGameTest.pointCategories.councilRankXpCategory, ), sageGameTest.gameId, sageGameTest.gameState, { keyIndex: sageGameTest.profiles.player1.index, }, ), ); const sectorDataAfter = await readFromRPCOrError( sageGameTest.connection, sageGameTest.program, sectorKey, Sector, 'confirmed', ); expect( sectorDataAfter.data.lastScanTime.gte(sectorData.data.lastScanTime), ).toBe(true); expect(sectorDataAfter.data.lastScanChance).toBeGreaterThanOrEqual( sectorData.data.lastScanChance, ); const fleetAccountAfter = await readFromRPCOrError( sageGameTest.connection, sageGameTest.program, fleet, Fleet, 'confirmed', ); expect( fleetAccountAfter.data.scanCooldownExpiresAt.gt( fleetAccountBefore.data.scanCooldownExpiresAt, ), ).toBe(true); const repairKitTokenFromAccountAfter = await getAccount( connection, repairKitTokenFrom, 'confirmed', ); expect( Number( repairKitTokenFromAccountBefore.delegatedAmount - repairKitTokenFromAccountAfter.delegatedAmount, ), ).toBe((fleetAccountAfter.data.stats).miscStats.scanCost); const dataRunningXpAfter = ( await sageGameTest.loadUserPoints( sageGameTest.pointCategories.dataRunningXpCategory, ) ).data.earnedPoints; const councilRankXpAfter = ( await sageGameTest.loadUserPoints( sageGameTest.pointCategories.councilRankXpCategory, ) ).data.earnedPoints; expect(dataRunningXpAfter.gt(dataRunningXpBefore)).toBe(true); expect(councilRankXpAfter.gt(councilRankXpBefore)).toBe(true); // scan during fleet scan cooldown works and does not reset cooldown timer await sageGameTest.sendToChain( SurveyDataUnitTracker.scanForSurveyDataUnits( sageGameTest.program, sageGameTest.cargoProgram, sageGameTest.pointsProgram, sageGameTest.profiles.player1.key, sageGameTest.profiles.player1.profile, sageGameTest.getProfileFactionAddress( sageGameTest.profiles.player1.profile, ), fleet, sectorKey, _tracker.publicKey(), fleetAccountBefore.data.cargoHold, CargoType.findAddress( sageGameTest.cargoProgram, sageGameTest.cargoStatsDefinition, sageGameTest.mints[SageGameTest.SDU], 0, )[0], CargoType.findAddress( sageGameTest.cargoProgram, sageGameTest.cargoStatsDefinition, sageGameTest.mints[SageGameTest.REPAIR_KIT], 0, )[0], sageGameTest.cargoStatsDefinition, sduTokenFrom, sduTokenTo, repairKitTokenFrom, sageGameTest.mints[SageGameTest.REPAIR_KIT], sageGameTest.getUserPointsAccountAddress( sageGameTest.pointCategories.dataRunningXpCategory, ), sageGameTest.pointCategories.dataRunningXpCategory, sageGameTest.getPointsModifierAddress( sageGameTest.pointCategories.dataRunningXpCategory, ), sageGameTest.getUserPointsAccountAddress( sageGameTest.pointCategories.councilRankXpCategory, ), sageGameTest.pointCategories.councilRankXpCategory, sageGameTest.getPointsModifierAddress( sageGameTest.pointCategories.councilRankXpCategory, ), sageGameTest.gameId, sageGameTest.gameState, { keyIndex: sageGameTest.profiles.player1.index, }, ), ); const fleetAccountAfter2 = await readFromRPCOrError( sageGameTest.connection, sageGameTest.program, fleet, Fleet, 'confirmed', ); expect( fleetAccountAfter2.data.scanCooldownExpiresAt.eq( fleetAccountAfter.data.scanCooldownExpiresAt, ), ).toBe(true); }); it('scanning works okay when fleet cargo capacity is exceeded', async () => { if ( !sageGameTest.gameState || !sageGameTest.cargoStatsDefinition || !sageGameTest.mints || !sageGameTest.sectors || !sageGameTest.ships || !sageGameTest.pointCategories || !sageGameTest.fleets ) { throw 'mints not registered'; } // create a new fleet whose cargo hold is almost full const sectorData = sageGameTest.sectors[0]; const starBase = sectorData.starbases[0]; const starBasePlayerData = sectorData.starbasePlayers[0]; const ship = sageGameTest.getShips()[0]; const numShips = 4; const shipAccount = await sageGameTest.loadShip(ship); const fleetCargoStats = Fleet.multiplyCargoStats( (shipAccount.data.stats).cargoStats, numShips, ); const fleetResult = await sageGameTest.quickCreateFleet( starBase, starBasePlayerData.starbasePlayer, numShips /** numShips */, fleetCargoStats.fuelCapacity /** fuel amount */, undefined, undefined, fleetCargoStats.cargoCapacity /** fill cargo hold with repair kits */, ); const tracker = await readFromRPCOrError( sageGameTest.connection, sageGameTest.program, _tracker.publicKey(), SurveyDataUnitTracker, 'confirmed', ); const sduTokenFrom = await sageGameTest.getOrCreateAssociatedTokenAccount( sageGameTest.mints[SageGameTest.SDU], tracker.data.signer, true, ); const sduTokenTo = await sageGameTest.getOrCreateAssociatedTokenAccount( sageGameTest.mints[SageGameTest.SDU], fleetResult.cargoHoldKey, true, ); const repairKitTokenFrom = await sageGameTest.getOrCreateAssociatedTokenAccount( sageGameTest.mints[SageGameTest.REPAIR_KIT], fleetResult.cargoHoldKey, true, ); // sector scan timestamp changes if SDUs found const sduTokenToBefore = await getAccount( connection, sduTokenTo, 'confirmed', ); // move to an un-scanned location const toSector = [new BN(0), new BN(-1)] as [BN, BN]; await sageGameTest.warpToCoordinate( fleetResult.fleetKey, fleetResult.fuelTankKey, toSector, ); // Sleep to allow the Warp movement to complete const expectedTravelTime = Math.floor( Fleet.calculateWarpTimeWithCoords( shipAccount.data.stats, SageGameTest.defaultSector, toSector, ), ); await new Promise((f) => setTimeout(f, expectedTravelTime * 1000)); const sectorResults = Sector.registerSector( sageGameTest.program, sageGameTest.profiles.superuser.key, sageGameTest.profiles.superuser.profile, sageGameTest.profiles.superuser.profile, sageGameTest.gameId, toSector, toSector.toString(), sageGameTest.profiles.superuser.index, ); await sageGameTest.sendManyToChain([ ixToIxReturn( ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 426 }), ), ixToIxReturn( ComputeBudgetProgram.setComputeUnitLimit({ units: 1_400_000 }), ), ...sageGameTest.moveWarpHandlerInstructions(fleetResult.fleetKey), sectorResults.instructions, ]); const sectorData0 = await readFromRPCOrError( sageGameTest.connection, sageGameTest.program, sectorResults.sectorKey[0], Sector, 'confirmed', ); // in case we get SDUs we don't get an error that cargo space is exceeded await sageGameTest.sendManyToChain( [ ixToIxReturn( ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 426 }), ), ixToIxReturn( ComputeBudgetProgram.setComputeUnitLimit({ units: 1_400_000 }), ), SurveyDataUnitTracker.scanForSurveyDataUnits( sageGameTest.program, sageGameTest.cargoProgram, sageGameTest.pointsProgram, sageGameTest.profiles.player1.key, sageGameTest.profiles.player1.profile, sageGameTest.getProfileFactionAddress( sageGameTest.profiles.player1.profile, ), fleetResult.fleetKey, sectorResults.sectorKey[0], _tracker.publicKey(), fleetResult.cargoHoldKey, CargoType.findAddress( sageGameTest.cargoProgram, sageGameTest.cargoStatsDefinition, sageGameTest.mints[SageGameTest.SDU], 0, )[0], CargoType.findAddress( sageGameTest.cargoProgram, sageGameTest.cargoStatsDefinition, sageGameTest.mints[SageGameTest.REPAIR_KIT], 0, )[0], sageGameTest.cargoStatsDefinition, sduTokenFrom, sduTokenTo, repairKitTokenFrom, sageGameTest.mints[SageGameTest.REPAIR_KIT], sageGameTest.getUserPointsAccountAddress( sageGameTest.pointCategories.dataRunningXpCategory, ), sageGameTest.pointCategories.dataRunningXpCategory, sageGameTest.getPointsModifierAddress( sageGameTest.pointCategories.dataRunningXpCategory, ), sageGameTest.getUserPointsAccountAddress( sageGameTest.pointCategories.councilRankXpCategory, ), sageGameTest.pointCategories.councilRankXpCategory, sageGameTest.getPointsModifierAddress( sageGameTest.pointCategories.councilRankXpCategory, ), sageGameTest.gameId, sageGameTest.gameState, { keyIndex: sageGameTest.profiles.player1.index, }, ), ], true, ); const sduTokenToAfter = await getAccount( connection, sduTokenTo, 'confirmed', ); if (sduTokenToAfter.delegatedAmount > sduTokenToBefore.delegatedAmount) { const sectorData1 = await readFromRPCOrError( sageGameTest.connection, sageGameTest.program, sectorResults.sectorKey[0], Sector, 'confirmed', ); expect( sectorData1.data.lastScanTime.gte(sectorData0.data.lastScanTime), ).toBe(true); } }); it('cannot scan outside of the coordinates range', async () => { if ( !sageGameTest.gameState || !sageGameTest.cargoStatsDefinition || !sageGameTest.mints || !sageGameTest.pointCategories || !sageGameTest.fleets ) { throw 'mints not registered'; } // create a new fleet in a new sector that is outside the coordinates range const coordinates = [new BN(333), new BN(0)] as [BN, BN]; await sageGameTest.createSector({ coordinates, numCrewForPlayer: 3 }); const tracker = await readFromRPCOrError( sageGameTest.connection, sageGameTest.program, _tracker.publicKey(), SurveyDataUnitTracker, 'confirmed', ); const fleet = sageGameTest.fleets[2]; const fleetAccountBefore = await readFromRPCOrError( sageGameTest.connection, sageGameTest.program, fleet, Fleet, 'confirmed', ); const sectorKey = Sector.findAddress( sageGameTest.program, sageGameTest.gameId, coordinates, )[0]; const sduTokenFrom = await sageGameTest.getOrCreateAssociatedTokenAccount( sageGameTest.mints[SageGameTest.SDU], tracker.data.signer, true, ); const sduTokenTo = await sageGameTest.getOrCreateAssociatedTokenAccount( sageGameTest.mints[SageGameTest.SDU], fleetAccountBefore.data.cargoHold, true, ); const repairKitTokenFrom = await sageGameTest.getOrCreateAssociatedTokenAccount( sageGameTest.mints[SageGameTest.REPAIR_KIT], fleetAccountBefore.data.cargoHold, true, ); let success = true; try { await sageGameTest.sendToChain( SurveyDataUnitTracker.scanForSurveyDataUnits( sageGameTest.program, sageGameTest.cargoProgram, sageGameTest.pointsProgram, sageGameTest.profiles.player1.key, sageGameTest.profiles.player1.profile, sageGameTest.getProfileFactionAddress( sageGameTest.profiles.player1.profile, ), fleet, sectorKey, _tracker.publicKey(), fleetAccountBefore.data.cargoHold, CargoType.findAddress( sageGameTest.cargoProgram, sageGameTest.cargoStatsDefinition, sageGameTest.mints[SageGameTest.SDU], 0, )[0], CargoType.findAddress( sageGameTest.cargoProgram, sageGameTest.cargoStatsDefinition, sageGameTest.mints[SageGameTest.REPAIR_KIT], 0, )[0], sageGameTest.cargoStatsDefinition, sduTokenFrom, sduTokenTo, repairKitTokenFrom, sageGameTest.mints[SageGameTest.REPAIR_KIT], sageGameTest.getUserPointsAccountAddress( sageGameTest.pointCategories.dataRunningXpCategory, ), sageGameTest.pointCategories.dataRunningXpCategory, sageGameTest.getPointsModifierAddress( sageGameTest.pointCategories.dataRunningXpCategory, ), sageGameTest.getUserPointsAccountAddress( sageGameTest.pointCategories.councilRankXpCategory, ), sageGameTest.pointCategories.councilRankXpCategory, sageGameTest.getPointsModifierAddress( sageGameTest.pointCategories.councilRankXpCategory, ), sageGameTest.gameId, sageGameTest.gameState, { keyIndex: sageGameTest.profiles.player1.index, }, ), ); } catch (err) { expect(JSON.stringify(err as Error)).toContain('InvalidSector'); success = false; } expect(success).toBe(false); }); it('can discover a new sector', async () => { if ( !sageGameTest.gameState || !sageGameTest.cargoStatsDefinition || !sageGameTest.mints || !sageGameTest.pointCategories || !sageGameTest.fleets ) { throw 'mints not registered'; } const fleet = sageGameTest.fleets[2]; const fleetAccount = await readFromRPCOrError( sageGameTest.connection, sageGameTest.program, fleet, Fleet, 'confirmed', ); if (!fleetAccount.state.Idle) { throw 'Fleet should be in idle state'; } const coordinates = [new BN(333), new BN(1)] as [BN, BN]; // move to undiscovered sector await sageGameTest.warpToCoordinate( fleet, fleetAccount.data.fuelTank, coordinates, ); // Sleep to allow the Warp movement to complete const expectedTravelTime = Math.floor( Fleet.calculateWarpTimeWithCoords( fleetAccount.data.stats, fleetAccount.state.Idle.sector as [BN, BN], coordinates, ), ); await new Promise((f) => setTimeout(f, (expectedTravelTime + 1) * 1000)); // discover the new Sector const sectorResult = Sector.discoverSector( sageGameTest.program, sageGameTest.profiles.player1.key, sageGameTest.profiles.player1.profile, sageGameTest.getProfileFactionAddress( sageGameTest.profiles.player1.profile, ), fleet, sageGameTest.gameId, sageGameTest.gameState, coordinates, sageGameTest.profiles.player1.index, ); await sageGameTest.sendManyToChain([ ...sageGameTest.moveWarpHandlerInstructions(fleet), sectorResult.instructions, ]); const sectorData = await readFromRPCOrError( sageGameTest.connection, sageGameTest.program, sectorResult.sectorKey[0], Sector, 'confirmed', ); const expectedSector = { version: 0, gameId: sageGameTest.gameId, coordinates, discoverer: sageGameTest.profiles.player1.profile, name: stringToByteArray('Sector [333, 1]', 64), numStars: 0, numPlanets: 0, numMoons: 0, numConnections: 0, numAsteroidBelts: 0, lastScanTime: new BN(0), lastScanChance: 0, bump: sectorResult.sectorKey[1], }; expect(sectorDataEquals(sectorData.data, expectedSector)).toBe(true); expect(sectorData.connections.length).toBe(0); }); it('can deregister a tracker', async () => { const trackerBefore = await readFromRPCOrError( sageGameTest.connection, sageGameTest.program, _tracker.publicKey(), SurveyDataUnitTracker, 'confirmed', ); await sageGameTest.sendToChain( SurveyDataUnitTracker.deregisterSurveyDataUnitTracker( sageGameTest.program, sageGameTest.profiles.superuser.key, sageGameTest.profiles.superuser.profile, _tracker.publicKey(), 'funder', sageGameTest.gameId, { keyIndex: sageGameTest.profiles.superuser.index, }, ), ); const tracker = await sageGameTest.connection.getAccountInfo( _tracker.publicKey(), 'processed', ); const trackerSigner = await sageGameTest.connection.getAccountInfo( trackerBefore.data.signer, 'processed', ); expect(tracker).toBeNull; expect(trackerSigner).toBeNull; }); });