分享 教你代币安全监测

aaa · 2024年10月15日 · 152 次阅读

炒币的时候经常会遇到一些盘,如果你盲目的冲进去,可能就完蛋了。比如说 https://dexscreener.com/solana/36kqsauU1HLRxecizvXWMosV1t1mQEeaeXDEfZLvkRY4 这个盘,最高的时候涨到 773.2M,然后迅速砸盘,一切都发生在三个小时以内。这就是因为他的 mint authority 还存在,每当有人买入,他就迅速冻结那个人币,导致别人只能买不能卖。你现在看这个盘可能发现 mint authority 已经是 none 了,但是之前是还有的,他修改 authority 是https://solscan.io/tx/3v3EuUm19Vii9vNNfexvgg7rFgy1wcmtGQemRZ94yUsk1awY9eLRGPpVUPMPxmL5WsDUi5Du8a5Ray4V1eCb55ot这个交易。

本文将简单判断代币是否是貔貅盘以及计算计算 LP 燃烧的比例。判断代币是否还有 mint 权限是看mint authority ,判断代币是否是貔貅盘,本质上是看代币的 freeze authority是否还在。计算 LP 燃烧的比例则是直接通过 pool 的 address,来看这个池子里的 lp 供应量(supply)和 储备量,来计算整个的比例判断 burn 了的比例 先引入一些包

import { nu64, struct, u32, u8, Layout } from "@solana/buffer-layout";
import { Connection, PublicKey } from "@solana/web3.js";
import type { ParsedAccountData } from "@solana/web3.js";
import { LIQUIDITY_STATE_LAYOUT_V4 } from "@raydium-io/raydium-sdk";
import dotenv from "dotenv";
import { logger } from "./logger";

然后自定义 boollayout 以及 publickeylayout 类,这两个的作用主要是定义在 buffer 中如何读取和存储这两个类型的数据

class PublicKeyLayout extends Layout<PublicKey> {
  constructor(property: string) {
    super(32, property);
  }

  decode(buffer: Buffer, offset = 0): PublicKey {
    return new PublicKey(buffer.slice(offset, offset + this.span));
  }

  encode(src: PublicKey, buffer: Buffer, offset = 0): number {
    buffer.set(src.toBytes(), offset);
    return this.span;
  }
}

const publicKey = (property: string) => new PublicKeyLayout(property);

class BoolLayout extends Layout<boolean> {
  constructor(property: string) {
    super(1, property);
  }

  decode(buffer: Buffer, offset = 0): boolean {
    return buffer[offset] === 1;
  }

  encode(src: boolean, buffer: Buffer, offset = 0): number {
    buffer[offset] = src ? 1 : 0;
    return this.span;
  }
}

const bool = (property: string) => new BoolLayout(property);

接下来就是定义 token 的结构

export interface Token {
  mintAuthorityOption: 1 | 0;
  mintAuthority: PublicKey;
  supply: bigint;
  decimals: number;
  isInitialized: boolean;
  freezeAuthorityOption: 1 | 0;
  freezeAuthority: PublicKey;
}

export const MintLayout = struct<Token>([
  u32("mintAuthorityOption"),
  publicKey("mintAuthority"),
  nu64("supply"),
  u8("decimals"),
  bool("isInitialized"),
  u32("freezeAuthorityOption"),
  publicKey("freezeAuthority"),
]);

解析直接调用 decode 方法即可

export const fetchAndParseMint = async (
  mint: PublicKey,
  solanaConnection: Connection
): Promise<Token | null> => {
  try {
    let { data } = (await solanaConnection.getAccountInfo(mint)) || {};
    if (!data) return null;

    return MintLayout.decode(data);
  } catch {
    return null;
  }
};

获取池子的信息 然后计算比例

export const fetchLiqudityPoolState = async (
  pool: PublicKey,
  solanaConnection: Connection
) => {
  try {
    const acc = await solanaConnection.getMultipleAccountsInfo([
      new PublicKey(pool),
    ]);
    const parsed = acc.map((v: any) =>
      LIQUIDITY_STATE_LAYOUT_V4.decode(v.data)
    );

    const lpMint = parsed[0].lpMint;
    const lpReserve = parsed[0].lpReserve;

    const accInfo = await solanaConnection.getParsedAccountInfo(
      new PublicKey(lpMint)
    );
    const mintInfo = (accInfo.value?.data as ParsedAccountData)?.parsed?.info;

    const lpReserve2 = lpReserve / Math.pow(10, mintInfo?.decimals);
    const actualSupply = mintInfo?.supply / Math.pow(10, mintInfo?.decimals);

    //Calculate burn percentage
    const maxLpSupply = Math.max(actualSupply, lpReserve - 1);
    const burnAmt = lpReserve - actualSupply;
    const burnPct = (burnAmt / lpReserve) * 100;

    return burnPct;
  } catch {
    return null;
  }
};

完整的代码可以参考我的 github

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请 注册新账号