From 603d08a3c31b06623b5cffafe6465b5e9d2177fe Mon Sep 17 00:00:00 2001 From: g1nt0ki <99907941+g1nt0ki@users.noreply.github.com> Date: Mon, 23 Sep 2024 23:05:30 +0200 Subject: [PATCH] Add Hedgehog Markets P2P, Parimutuel, and Parlay Support (#11719) Co-authored-by: James Whaley Co-authored-by: jkdipeppe --- projects/hedgehog-markets/index.js | 114 ++++++++++++++++++ projects/helper/utils/solana/layout.js | 4 +- .../utils/solana/layouts/mixed-layout.js | 22 +++- 3 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 projects/hedgehog-markets/index.js diff --git a/projects/hedgehog-markets/index.js b/projects/hedgehog-markets/index.js new file mode 100644 index 000000000000..d7196b0ca08a --- /dev/null +++ b/projects/hedgehog-markets/index.js @@ -0,0 +1,114 @@ + +const { PublicKey } = require("@solana/web3.js"); +const { getProvider, sumTokens2, getConnection, decodeAccount, } = require("../helper/solana") +const { Program, } = require("@project-serum/anchor"); + +async function tvl(api) { + const provider = getProvider() + const connection = getConnection() + const tokenAccounts = [] + const owners= [] + await getClassicMarketTokenAccounts() + await addP2PBalances() + await addParlay() + // await addParimutuel() + + const balances = api.getBalances() + await sumTokens2({ owners, balances, }) + return sumTokens2({ tokenAccounts, balances, }) + + async function getClassicMarketTokenAccounts() { + + const classicMarketProgramId = "D8vMVKonxkbBtAXAxBwPPWyTfon8337ARJmHvwtsF98G" + const idl = await Program.fetchIdl(classicMarketProgramId, provider) + + const program = new Program(idl, classicMarketProgramId, provider) + const markets = await program.account.market.all() + const collateralAccounts = markets.map(({ account }) => account.marketCollateral) + tokenAccounts.push(...collateralAccounts) + } + + async function addParlay() { + const programId = new PublicKey('PLYaNRbQs9GWyVQdcLrzPvvZu7NH4W2sneyHcEimLr7') + const poolOwner = "8Y46GkrbUqXnbs6kPD6SWr44NjcKPEWYzvpAn8UB5duR" + owners.push(poolOwner) + + const accounts = await connection.getProgramAccounts(programId, { + // We only care about: + // - mint address (69..101) + // - entry count (101..105) + // - entry cost (105..113) + dataSlice: { offset: 69, length: 44 }, + filters: [ + // Market accounts have a discriminator of 3 at offset 0. + { memcmp: { offset: 0, bytes: "4" } }, + // Open markets have a state of 0 at offset 149. + { memcmp: { offset: 149, bytes: "1" } }, + ], + }) + + accounts.forEach(({ account }) => { + const data = decodeAccount('hhParlay', account) + + api.add(data.mint.toString(), Number(data.entryCount) * Number(data.entryCost)) + }) + } + + async function addP2PBalances() { + // https://github.com/Hedgehog-Markets/hedgehog-program-library/blob/master/p2p/idl.json + const programId = new PublicKey('P2PzLraW8YF87BxqZTZ5kgrfvzcrKGPnqUBNhqmcV9B') + const poolOwner = "J9EH18EWSo8s69gouHGNy5zFHkhcHRbb9zBZXwSG4cHy" + owners.push(poolOwner) + + const accounts = await connection.getProgramAccounts(programId, { + // We only care about: + // - mint address (73..105) + // - yes amount (113..121) + // - no amount (121..129) + dataSlice: { offset: 69, length: 56 }, + filters: [ + // Market accounts have a discriminator of 3 at offset 0. + { memcmp: { offset: 0, bytes: "4", } }, + // Open markets have a state of 0 at offset 129. + { memcmp: { offset: 129, bytes: "1"} }, + ], + }); + + accounts.forEach(({ account: { data } }) => { + const mint = new PublicKey(data.slice(0, 32)).toString() + const yesAmount = Number(data.readUInt8(40)); + const noAmount = Number(data.readUInt8(48)); + api.add(mint, yesAmount + noAmount) + }) + } + + + async function addParimutuel() { + const programId = new PublicKey('PARrVs6F5egaNuz8g6pKJyU4ze3eX5xGZCFb3GLiVvu') + const poolOwner = "3SAUPiGiATqv8TBgvzSJqpLxLGF6LbJamvimueJQT7WT" + owners.push(poolOwner) + + const accounts = await connection.getProgramAccounts(programId, { + dataSlice: { offset: 69, length: 70 }, + filters: [ + // Market accounts have a discriminator of 3 at offset 0. + { memcmp: { offset: 0, bytes: "4" } }, + // Open markets have a state of 0 at offset 149. + { memcmp: { offset: 149, bytes: "1" } }, + ], + }) + + accounts.forEach(({ account }) => { + const data = decodeAccount('hhPari', account) + const token = data.mint.toString() + const amounts = data.amounts.map(Number) + api.add(token, amounts) + }) + } +} + +module.exports = { + timetravel: false, + solana: { tvl }, + methodology: "TVL consists of deposits made into Hedgehog Markets.", +}; diff --git a/projects/helper/utils/solana/layout.js b/projects/helper/utils/solana/layout.js index b7523fd96eba..42e27acd27d9 100644 --- a/projects/helper/utils/solana/layout.js +++ b/projects/helper/utils/solana/layout.js @@ -5,7 +5,7 @@ const { parsePhoenix } = require('./layouts/phoenix-dex') const { RAYDIUM_LIQUIDITY_STATE_LAYOUT_CLMM, RAYDIUM_STABLE_STATE_LAYOUT_V1, } = require('./layouts/raydium-layout') const { INVESTIN_FUND_DATA, } = require('./layouts/investin-layout') const { MARKET_STATE_LAYOUT_V3, OPEN_ORDERS_LAYOUT_V2, MARKET_STATE_LAYOUT_V3_MINIMAL } = require('./layouts/openbook-layout') -const { ReserveLayout, ReserveLayoutLarix, MintLayout, AccountLayout, TokenSwapLayout, ESOLStakePoolLayout, } = require('./layouts/mixed-layout'); +const { ReserveLayout, ReserveLayoutLarix, MintLayout, AccountLayout, TokenSwapLayout, ESOLStakePoolLayout, PARLAY_LAYOUT_PARTIAL, HH_PARI_LAYOUT_PARTIAL, } = require('./layouts/mixed-layout'); const { SCN_STAKE_POOL, TOKEN_LAYOUT, } = require("./layouts/scnSOL"); const { SANCTUM_INFINITY } = require("./layouts/sanctum-infinity-layout"); const { parseSanctumLstStateList } = require("./layouts/sanctum-validators-lsts-layout"); @@ -63,6 +63,8 @@ const customDecoders = { sanctumValidatorLsts: parseSanctumLstStateList, stakePoolPartial: defaultParseLayout(STAKE_POOL_PARTIAL), stakePool: defaultParseLayout(STAKE_POOL_LAYOUT), + hhParlay: defaultParseLayout(PARLAY_LAYOUT_PARTIAL), + hhPari: defaultParseLayout(HH_PARI_LAYOUT_PARTIAL), } function decodeAccount(layout, accountInfo) { diff --git a/projects/helper/utils/solana/layouts/mixed-layout.js b/projects/helper/utils/solana/layouts/mixed-layout.js index 77e760154d53..53962af37c5f 100644 --- a/projects/helper/utils/solana/layouts/mixed-layout.js +++ b/projects/helper/utils/solana/layouts/mixed-layout.js @@ -250,7 +250,27 @@ const ESOLStakePoolLayout = BufferLayout.struct([ u32("maxValidatorYieldPerEpochNumerator") ]); + +const PARLAY_LAYOUT_PARTIAL = BufferLayout.struct([ + publicKey('mint'), + u32("entryCount"), + u64('entryCost'), +]); + +const HH_PARI_LAYOUT_PARTIAL = BufferLayout.struct([ + publicKey('mint'), + u64("closeTimestamp"), + u64("resolveTimestamp"), + u64("outcomeTimestamp"), + u16("creatorFee"), + u16("platformFee"), + u8('state'), + u8('outcome'), + BufferLayout.seq(u64(), u8().span, 'amounts'), +]); + module.exports = { - ReserveLayout, ReserveLayoutLarix, MintLayout, AccountLayout, TokenSwapLayout, ESOLStakePoolLayout, + ReserveLayout, ReserveLayoutLarix, MintLayout, AccountLayout, TokenSwapLayout, ESOLStakePoolLayout, + PARLAY_LAYOUT_PARTIAL, HH_PARI_LAYOUT_PARTIAL, }