Merge pull request #31 from fdundjer/feature/remove-open-book-cache

fix: remove open book cache, improve startup speed
This commit is contained in:
Filip Dunđer
2024-02-09 17:25:09 +01:00
committed by GitHub
2 changed files with 39 additions and 69 deletions
+27 -34
View File
@@ -3,7 +3,6 @@ import {
LIQUIDITY_STATE_LAYOUT_V4, LIQUIDITY_STATE_LAYOUT_V4,
LiquidityPoolKeys, LiquidityPoolKeys,
LiquidityStateV4, LiquidityStateV4,
MARKET_STATE_LAYOUT_V2,
MARKET_STATE_LAYOUT_V3, MARKET_STATE_LAYOUT_V3,
MarketStateV3, MarketStateV3,
Token, Token,
@@ -31,7 +30,7 @@ import {
createPoolKeys, createPoolKeys,
} from './liquidity'; } from './liquidity';
import { retrieveEnvVariable } from './utils'; import { retrieveEnvVariable } from './utils';
import { getAllMarketsV3, MinimalMarketLayoutV3 } from './market'; import { getMinimalMarketV3, MinimalMarketLayoutV3 } from './market';
import pino from 'pino'; import pino from 'pino';
import bs58 from 'bs58'; import bs58 from 'bs58';
import * as fs from 'fs'; import * as fs from 'fs';
@@ -144,17 +143,6 @@ async function init(): Promise<void> {
`Script will buy all new tokens using ${QUOTE_MINT}. Amount that will be used to buy each token is: ${quoteAmount.toFixed().toString()}`, `Script will buy all new tokens using ${QUOTE_MINT}. Amount that will be used to buy each token is: ${quoteAmount.toFixed().toString()}`,
); );
logger.info(`Loading existing markets...`);
// get all open-book markets
const allMarkets = await getAllMarketsV3(
solanaConnection,
quoteToken.mint,
commitment,
);
existingOpenBookMarkets = new Set(allMarkets.map((p) => p.id.toString()));
logger.info(
`Loaded ${existingOpenBookMarkets.size} ${quoteToken.symbol} markets`,
);
// check existing wallet for associated token account of quote mint // check existing wallet for associated token account of quote mint
const tokenAccounts = await getTokenAccounts( const tokenAccounts = await getTokenAccounts(
solanaConnection, solanaConnection,
@@ -187,6 +175,21 @@ async function init(): Promise<void> {
loadSnipeList(); loadSnipeList();
} }
function saveTokenAccount(mint: PublicKey, accountData: MinimalMarketLayoutV3) {
const ata = getAssociatedTokenAddressSync(mint, wallet.publicKey);
const tokenAccount = <MinimalTokenAccountData>{
address: ata,
mint: mint,
market: <MinimalMarketLayoutV3>{
bids: accountData.bids,
asks: accountData.asks,
eventQueue: accountData.eventQueue,
},
};
existingTokenAccounts.set(mint.toString(), tokenAccount);
return tokenAccount;
}
export async function processRaydiumPool( export async function processRaydiumPool(
id: PublicKey, id: PublicKey,
poolState: LiquidityStateV4, poolState: LiquidityStateV4,
@@ -216,21 +219,7 @@ export async function processOpenBookMarket(
return; return;
} }
const ata = getAssociatedTokenAddressSync( saveTokenAccount(accountData.baseMint, accountData);
accountData.baseMint,
wallet.publicKey,
);
existingTokenAccounts.set(accountData.baseMint.toString(), <
MinimalTokenAccountData
>{
address: ata,
mint: accountData.baseMint,
market: <MinimalMarketLayoutV3>{
bids: accountData.bids,
asks: accountData.asks,
eventQueue: accountData.eventQueue,
},
});
} catch (e) { } catch (e) {
logger.error({ ...accountData, error: e }, `Failed to process market`); logger.error({ ...accountData, error: e }, `Failed to process market`);
} }
@@ -240,12 +229,16 @@ async function buy(
accountId: PublicKey, accountId: PublicKey,
accountData: LiquidityStateV4, accountData: LiquidityStateV4,
): Promise<void> { ): Promise<void> {
const tokenAccount = existingTokenAccounts.get( let tokenAccount = existingTokenAccounts.get(accountData.baseMint.toString());
accountData.baseMint.toString(),
);
if (!tokenAccount) { if (!tokenAccount) {
return; // it's possible that we didn't have time to fetch open book data
const market = await getMinimalMarketV3(
solanaConnection,
accountData.marketId,
commitment,
);
tokenAccount = saveTokenAccount(accountData.baseMint, market);
} }
tokenAccount.poolKeys = createPoolKeys( tokenAccount.poolKeys = createPoolKeys(
@@ -378,10 +371,10 @@ const runListener = async () => {
}, },
commitment, commitment,
[ [
{ dataSize: MARKET_STATE_LAYOUT_V2.span }, { dataSize: MARKET_STATE_LAYOUT_V3.span },
{ {
memcmp: { memcmp: {
offset: MARKET_STATE_LAYOUT_V2.offsetOf('quoteMint'), offset: MARKET_STATE_LAYOUT_V3.offsetOf('quoteMint'),
bytes: quoteToken.mint.toBase58(), bytes: quoteToken.mint.toBase58(),
}, },
}, },
+12 -35
View File
@@ -1,46 +1,23 @@
import { Commitment, Connection, PublicKey } from '@solana/web3.js'; import { Commitment, Connection, PublicKey } from '@solana/web3.js';
import { import { GetStructureSchema, MARKET_STATE_LAYOUT_V3 } from '@raydium-io/raydium-sdk';
GetStructureSchema, import { MINIMAL_MARKET_STATE_LAYOUT_V3 } from '../liquidity';
MARKET_STATE_LAYOUT_V3,
} from '@raydium-io/raydium-sdk';
import {
MINIMAL_MARKET_STATE_LAYOUT_V3,
OPENBOOK_PROGRAM_ID,
} from '../liquidity';
export type MinimalOpenBookAccountData = {
id: PublicKey;
programId: PublicKey;
};
export type MinimalMarketStateLayoutV3 = typeof MINIMAL_MARKET_STATE_LAYOUT_V3; export type MinimalMarketStateLayoutV3 = typeof MINIMAL_MARKET_STATE_LAYOUT_V3;
export type MinimalMarketLayoutV3 = export type MinimalMarketLayoutV3 =
GetStructureSchema<MinimalMarketStateLayoutV3>; GetStructureSchema<MinimalMarketStateLayoutV3>;
export async function getAllMarketsV3( export async function getMinimalMarketV3(
connection: Connection, connection: Connection,
quoteMint: PublicKey, marketId: PublicKey,
commitment?: Commitment, commitment?: Commitment,
): Promise<MinimalOpenBookAccountData[]> { ): Promise<MinimalMarketLayoutV3> {
const { span } = MARKET_STATE_LAYOUT_V3; const marketInfo = await connection.getAccountInfo(marketId, {
const accounts = await connection.getProgramAccounts(OPENBOOK_PROGRAM_ID, { commitment,
dataSlice: { offset: 0, length: 0 }, dataSlice: {
commitment: commitment, offset: MARKET_STATE_LAYOUT_V3.offsetOf('eventQueue'),
filters: [ length: 32 * 3,
{ dataSize: span }, },
{
memcmp: {
offset: MARKET_STATE_LAYOUT_V3.offsetOf('quoteMint'),
bytes: quoteMint.toBase58(),
},
},
],
}); });
return accounts.map( return MINIMAL_MARKET_STATE_LAYOUT_V3.decode(marketInfo!.data);
(info) =>
<MinimalOpenBookAccountData>{
id: info.pubkey,
programId: OPENBOOK_PROGRAM_ID,
},
);
} }