From 28ace32c170020881f150ec0072a21ac96a6e2ea Mon Sep 17 00:00:00 2001 From: microwavedcola1 Date: Tue, 30 Jul 2024 20:45:51 +0200 Subject: [PATCH] use live data to estimate cu Signed-off-by: microwavedcola1 --- ts/client/scripts/manageFeeWs.ts | 90 +++++++++++++++++++++++++ ts/client/scripts/sb-on-demand-crank.ts | 46 ++++++++----- ts/client/scripts/update-risk-params.ts | 4 +- 3 files changed, 123 insertions(+), 17 deletions(-) create mode 100644 ts/client/scripts/manageFeeWs.ts diff --git a/ts/client/scripts/manageFeeWs.ts b/ts/client/scripts/manageFeeWs.ts new file mode 100644 index 000000000..f4a72227f --- /dev/null +++ b/ts/client/scripts/manageFeeWs.ts @@ -0,0 +1,90 @@ +import WebSocket from 'ws'; + +export function manageFeeWebSocket( + wsUrl: string, + rollingWindowSize: number = 120, + onMeanCalculated: (mean: number | null) => void, +): () => void { + let ws: WebSocket | null = null; + const recentValues: number[] = []; + + function calculateRollingMean(values: number[]): number | null { + if (values.length === 0) return null; + const sum = values.reduce((acc, val) => acc + val, 0); + return Math.floor(sum / values.length); + } + + function connectWebSocket(): void { + try { + ws = new WebSocket(wsUrl); + + ws.addEventListener('open', () => { + try { + // console.log('Fee WebSocket opened'); + const message = JSON.stringify({ + jsonrpc: '2.0', + id: 1, + method: 'blockPrioritizationFeesSubscribe', + interval: 30, + }); + ws?.send(message); + } catch (error) { + console.error('Error in open event:', error); + onMeanCalculated(null); + } + }); + + ws.addEventListener('close', () => { + // console.log('Fee WebSocket closed'); + ws = null; + // Attempt to reconnect after a delay + setTimeout(connectWebSocket, 5000); + }); + + ws.addEventListener('error', (error) => { + console.log('Fee WebSocket error:', error); + onMeanCalculated(-1); + ws?.close(); + }); + + ws.addEventListener('message', (event: MessageEvent): void => { + try { + const parsedData = JSON.parse(event.data as string); + const value = parsedData?.params?.result?.value.by_tx[15]; + + if (value !== undefined && typeof value === 'number') { + recentValues.push(value); + if (recentValues.length > rollingWindowSize) { + recentValues.shift(); + } + + const rollingMean = calculateRollingMean(recentValues); + onMeanCalculated(rollingMean); + } + } catch (error) { + console.error('Error processing message:', error); + onMeanCalculated(-1); + } + }); + } catch (error) { + console.error('Error in connectWebSocket:', error); + onMeanCalculated(-1); + // Attempt to reconnect after a delay + setTimeout(connectWebSocket, 5000); + } + } + + // Start the WebSocket connection + connectWebSocket(); + + // Return a function to close the WebSocket + return () => { + if (ws) { + try { + ws.close(); + } catch (error) { + console.error('Error closing WebSocket:', error); + } + } + }; +} diff --git a/ts/client/scripts/sb-on-demand-crank.ts b/ts/client/scripts/sb-on-demand-crank.ts index 5be5c9de5..dcba6b580 100644 --- a/ts/client/scripts/sb-on-demand-crank.ts +++ b/ts/client/scripts/sb-on-demand-crank.ts @@ -27,24 +27,35 @@ import { MangoClient } from '../src/client'; import { MANGO_V4_ID, MANGO_V4_MAIN_GROUP } from '../src/constants'; import { ZERO_I80F48 } from '../src/numbers/I80F48'; import { createComputeBudgetIx } from '../src/utils/rpc'; +import { manageFeeWebSocket } from './manageFeeWs'; const CLUSTER: Cluster = (process.env.CLUSTER_OVERRIDE as Cluster) || 'mainnet-beta'; const CLUSTER_URL = process.env.CLUSTER_URL_OVERRIDE || process.env.MB_CLUSTER_URL; -const CLUSTER_URL_2 = - process.env.CLUSTER_URL_OVERRIDE || process.env.MB_CLUSTER_URL_2; -const LITE_RPC_URL = process.env.MB_CLUSTER_URL; +const CLUSTER_URL_2 = process.env.MB_CLUSTER_URL_2; +const LITE_RPC_URL = process.env.LITE_RPC_URL; const USER_KEYPAIR = process.env.USER_KEYPAIR_OVERRIDE || process.env.MB_PAYER_KEYPAIR; const GROUP = process.env.GROUP_OVERRIDE || MANGO_V4_MAIN_GROUP.toBase58(); -const SLEEP_MS = Number(process.env.SLEEP_MS) || 50_000; // -const COMPUTE_UNIT_PRICE = Number(process.env.COMPUTE_UNIT_PRICE) || 150_000; // +const SLEEP_MS = Number(process.env.SLEEP_MS) || 50_000; -console.log(`Starting with ${SLEEP_MS}`); -console.log(`${CLUSTER_URL}`); +console.log( + `Starting with sleep ${SLEEP_MS}ms, cluster ${CLUSTER_URL}, cluster2 ${CLUSTER_URL_2}, liteRpcUrl ${LITE_RPC_URL}`, +); -// TODO use mangolana to send txs +let lamportsPerCu: number | null = null; +try { + const wsUrl = new URL( + process.env.LITE_RPC_URL!.replace('https', 'wss'), + ).toString(); + + manageFeeWebSocket(wsUrl, 10, (mean) => { + lamportsPerCu = mean; + }); +} catch (error) { + console.error('Error in main execution:', error); +} interface OracleInterface { oracle: { @@ -137,20 +148,25 @@ interface OracleInterface { const ixsChunks = chunk(shuffle(pullIxs), 2, false); try { - // use dont await, fire and forget + // dont await, fire and forget sendSignAndConfirmTransactions({ connection, wallet: new Wallet(user), backupConnections: [ - new Connection(LITE_RPC_URL!, 'recent'), - new Connection(CLUSTER_URL_2!, 'recent'), + ...(CLUSTER_URL_2 + ? [new Connection(LITE_RPC_URL!, 'recent')] + : []), + ...(CLUSTER_URL_2 + ? [new Connection(CLUSTER_URL_2!, 'recent')] + : []), ], transactionInstructions: ixsChunks.map((txChunk) => ({ instructionsSet: [ { signers: [], - transactionInstruction: - createComputeBudgetIx(COMPUTE_UNIT_PRICE), + transactionInstruction: createComputeBudgetIx( + Math.max(lamportsPerCu ?? 150_000, 150_000), + ), }, ...txChunk.map((tx) => ({ signers: [], @@ -168,14 +184,14 @@ interface OracleInterface { callbacks: { afterEveryTxSend: function (data) { console.log( - ` - https://solscan.io/tx/${data['txid']}, in ${(Date.now() - start) / 1000}s`, + ` - https://solscan.io/tx/${data['txid']}, in ${(Date.now() - start) / 1000}s, lamportsPerCu ${lamportsPerCu}`, ); }, }, }); } catch (error) { console.log( - `Error in sending tx, ${JSON.stringify(error.message)}, https://solscan.io/tx/${error['txid']}, in ${(Date.now() - start) / 1000}s`, + `Error in sending tx, ${JSON.stringify(error.message)}, https://solscan.io/tx/${error['txid']}, in ${(Date.now() - start) / 1000}s, lamportsPerCu ${lamportsPerCu}`, ); } diff --git a/ts/client/scripts/update-risk-params.ts b/ts/client/scripts/update-risk-params.ts index a554f262d..b69e9f695 100644 --- a/ts/client/scripts/update-risk-params.ts +++ b/ts/client/scripts/update-risk-params.ts @@ -226,7 +226,7 @@ async function updateTokenParams(): Promise { ); if (maybeSbOracle.length > 0) { console.log(` - ${bank.name} ${maybeSbOracle[0][0]}`); - builder.fallbackOracle(new PublicKey(maybeSbOracle[0][1])); + builder.fallbackOracle(PublicKey.default); change = true; } else { return; @@ -572,7 +572,7 @@ async function updateTokenParams(): Promise { tokenOwnerRecord, PROPOSAL_TITLE ? PROPOSAL_TITLE - : 'Set sb on demand oracles as fallback oracles in mango-v4', + : 'Reset sb on demand oracles as fallback oracles in mango-v4', PROPOSAL_LINK ?? '', Object.values(proposals).length, instructions,