mutable.filter.ts 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. import { Filter, FilterResult } from './pool-filters';
  2. import { Connection } from '@solana/web3.js';
  3. import { LiquidityPoolKeysV4 } from '@raydium-io/raydium-sdk';
  4. import { getPdaMetadataKey } from '@raydium-io/raydium-sdk';
  5. import { MetadataAccountData, MetadataAccountDataArgs } from '@metaplex-foundation/mpl-token-metadata';
  6. import { Serializer } from '@metaplex-foundation/umi/serializers';
  7. import { logger } from '../helpers';
  8. export class MutableFilter implements Filter {
  9. private readonly errorMessage: string[] = [];
  10. constructor(
  11. private readonly connection: Connection,
  12. private readonly metadataSerializer: Serializer<MetadataAccountDataArgs, MetadataAccountData>,
  13. private readonly checkMutable: boolean,
  14. private readonly checkSocials: boolean,
  15. ) {
  16. if (this.checkMutable) {
  17. this.errorMessage.push('mutable');
  18. }
  19. if (this.checkSocials) {
  20. this.errorMessage.push('socials');
  21. }
  22. }
  23. async execute(poolKeys: LiquidityPoolKeysV4): Promise<FilterResult> {
  24. try {
  25. const metadataPDA = getPdaMetadataKey(poolKeys.baseMint);
  26. const metadataAccount = await this.connection.getAccountInfo(metadataPDA.publicKey, this.connection.commitment);
  27. if (!metadataAccount?.data) {
  28. return { ok: false, message: 'Mutable -> Failed to fetch account data' };
  29. }
  30. const deserialize = this.metadataSerializer.deserialize(metadataAccount.data);
  31. const mutable = !this.checkMutable || deserialize[0].isMutable;
  32. const hasSocials = !this.checkSocials || (await this.hasSocials(deserialize[0]));
  33. const ok = !mutable && hasSocials;
  34. const message: string[] = [];
  35. if (mutable) {
  36. message.push('metadata can be changed');
  37. }
  38. if (!hasSocials) {
  39. message.push('has no socials');
  40. }
  41. return { ok: ok, message: ok ? undefined : `MutableSocials -> Token ${message.join(' and ')}` };
  42. } catch (e) {
  43. logger.error({ mint: poolKeys.baseMint }, `MutableSocials -> Failed to check ${this.errorMessage.join(' and ')}`);
  44. }
  45. return {
  46. ok: false,
  47. message: `MutableSocials -> Failed to check ${this.errorMessage.join(' and ')}`,
  48. };
  49. }
  50. private async hasSocials(metadata: MetadataAccountData) {
  51. const response = await fetch(metadata.uri);
  52. const data = await response.json();
  53. return Object.values(data?.extensions ?? {}).some((value: any) => value !== null && value.length > 0);
  54. }
  55. }