Created
August 20, 2024 15:06
-
-
Save rubpy/1db8114ce7d31110dcbf00d3b879e1ac to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// --- `@solana/web3.js` v1 --- | |
import web3 from '@solana/web3.js'; | |
(async (rpcUrl: string) => { | |
const rpc = new web3.Connection(rpcUrl); | |
const subject = new web3.PublicKey('j1oAbxxiDUWvoHxEDhWE7THLjEkDQW2cSHYn2vttxTF'); | |
const signatures = await rpc.getSignaturesForAddress(subject, { | |
limit: 1000, | |
}, 'finalized'); | |
const mevProbability = estimateMevProbability(signatures); | |
console.log( | |
`Estimated MEV probability for address "${subject}":\n`, | |
mevProbability, | |
); | |
// | |
// --- OUTPUT (as of: Aug 20 2024 15:04:22 UTC) --- | |
// | |
// Estimated MEV probability for address "j1oAbxxiDUWvoHxEDhWE7THLjEkDQW2cSHYn2vttxTF": | |
// 0.9999685386458833 | |
// | |
// | |
})(process.env.SOL_RPC_URL || 'https://mainnet.helius-rpc.com/?api-key=00000000-0000-0000-0000-000000000000'); | |
// ----------------------------------------------------------------------------- | |
/* | |
// --- `@solana/web3.js` v2: --- | |
import { createSolanaRpc, address } from '@solana/web3.js'; | |
(async (rpcUrl: string) => { | |
const rpc = createSolanaRpc(rpcUrl); | |
const subject = address('j1oAbxxiDUWvoHxEDhWE7THLjEkDQW2cSHYn2vttxTF'); | |
const signatures = await rpc.getSignaturesForAddress(subject, { | |
commitment: 'finalized', | |
limit: 1000, | |
}).send(); | |
const mevProbability = estimateMevProbability(signatures); | |
console.log( | |
`Estimated MEV probability for address "${subject}":\n`, | |
mevProbability, | |
); | |
})(process.env.SOL_RPC_URL || 'https://mainnet.helius-rpc.com/?api-key=00000000-0000-0000-0000-000000000000'); | |
*/ | |
// ----------------------------------------------------------------------------- | |
type GetSignaturesForAddressTransaction = | |
| { blockTime?: number | null; slot: number } | |
| { blockTime?: number | null; slot: bigint }; | |
// NOTE: signatures must be sorted chronologically (in either ascending or | |
// descending order, based on `blockTime`/`slot`). | |
function estimateMevProbability<T extends GetSignaturesForAddressTransaction>( | |
signatures: readonly T[], | |
useBlockTime = false, | |
): number { | |
const dists: number[] = []; | |
let last = 0; | |
for (const entry of signatures) { | |
const n = Number(useBlockTime ? entry.blockTime : entry.slot); | |
if (isNaN(n) || n <= 0) continue; | |
if (last !== 0) { | |
dists.push(Math.abs(last - n)); | |
} | |
last = n; | |
} | |
return _noiseToSignal(dists, useBlockTime ? 157.0 : 829.0, 2.0); | |
} | |
// ----------------------------------------------------------------------------- | |
function _noiseToSignal(xs: number[], targetRatio: number, stdCutoff = 2.0): number { | |
if (xs.length <= 1 || targetRatio <= 0.0 || stdCutoff <= 0.0) return NaN; | |
let mean = _mean(xs); | |
let std = _std(xs, _variance(xs, mean)); | |
const cutoff = stdCutoff * std; | |
xs = xs.filter(x => Math.abs(x - mean) < cutoff); | |
mean = _mean(xs); | |
std = _std(xs, _variance(xs, mean)); | |
const coeff = (mean * std) / xs.length; | |
return 1 - Math.tanh(coeff / targetRatio); | |
} | |
function _sum(xs: number[], f?: (x: number) => number): number { | |
if (xs.length <= 0) return 0.0; | |
let sum = 0.0, comp = 0.0, t = 0.0, y = 0.0; | |
for (const x of xs) { | |
y = (f ? f(x) : x) - comp; | |
t = sum + y; | |
comp = (t - sum) - y; | |
sum = t; | |
} | |
return sum; | |
} | |
function _mean(xs: number[]): number { | |
return xs.length > 0 ? _sum(xs) / xs.length : 0.0; | |
} | |
function _variance(xs: number[], mean: number = NaN): number { | |
if (xs.length <= 1) return 0.0; | |
mean = isNaN(mean) ? _mean(xs) : mean; | |
return _sum(xs, x => { x -= mean; return x * x }) / (xs.length - 1); | |
} | |
function _std(xs: number[], variance: number = NaN): number { | |
if (xs.length <= 1) return 0.0; | |
variance = isNaN(variance) ? _variance(xs, NaN) : variance; | |
return Math.sqrt(variance); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment