diff --git a/apps/hyperdrive-trading/src/hyperdrive/positionsSnapshot.ts b/apps/hyperdrive-trading/src/hyperdrive/positionsSnapshot.ts new file mode 100644 index 000000000..7a2de400e --- /dev/null +++ b/apps/hyperdrive-trading/src/hyperdrive/positionsSnapshot.ts @@ -0,0 +1,598 @@ +import type { Long, OpenShort } from "@delvtech/hyperdrive-js"; +import type { Address } from "viem"; + +export interface SnapshotLongPosition extends Long { + accountAddress: Address; + chainId: number; + hyperdriveAddress: Address; +} + +export interface SnapshotShortPosition extends OpenShort { + accountAddress: `0x${string}`; + chainId: number; +} + +// Snapshot of on-chain positions as of September 5, 2025 +export const POSITIONS_SNAPSHOT: { + longs: SnapshotLongPosition[]; + shorts: SnapshotShortPosition[]; +} = { + longs: [ + { + chainId: 1, + hyperdriveAddress: "0x324395d5d835f84a02a75aa26814f6fd22f25698", + accountAddress: "0xcb41546c449987cA614C41BfC0735dDFEEC4cE11", + assetId: + 452312848583266388373324160190187140051835877600158453279131187532667347456n, + bondAmount: 20878014869412418978965n, + maturity: 1756684800n, + baseAmountPaid: 20000000000000000000000n, + }, + { + chainId: 1, + hyperdriveAddress: "0x324395d5d835f84a02a75aa26814f6fd22f25698", + accountAddress: "0xcb41546c449987cA614C41BfC0735dDFEEC4cE11", + assetId: + 452312848583266388373324160190187140051835877600158453279131187532667088256n, + bondAmount: 10949196320051186570601n, + maturity: 1756425600n, + baseAmountPaid: 10402593928187285514074n, + }, + { + chainId: 1, + hyperdriveAddress: "0x324395d5d835f84a02a75aa26814f6fd22f25698", + accountAddress: "0xdf4f526Fc2aCc685f22e2ebE512d0F9864D9B2d0", + assetId: + 452312848583266388373324160190187140051835877600158453279131187532668902656n, + bondAmount: 19225216100893836115389n, + maturity: 1758240000n, + baseAmountPaid: 18412883032175685956637n, + }, + { + chainId: 1, + hyperdriveAddress: "0xd7e470043241c10970953bd8374ee6238e77d735", + accountAddress: "0x73a5DEa042aEB13E9e9F81246281173f3Ae3b0c3", + assetId: + 452312848583266388373324160190187140051835877600158453279131187532668816256n, + bondAmount: 22448223454451360658n, + maturity: 1758153600n, + baseAmountPaid: 22000000000000000000n, + }, + { + chainId: 1, + hyperdriveAddress: "0xd7e470043241c10970953bd8374ee6238e77d735", + accountAddress: "0x40C59CFaF8Aa17a43EB2f1D50384c95ff50aDef9", + assetId: + 452312848583266388373324160190187140051835877600158453279131187532667174656n, + bondAmount: 1030882367666428457n, + maturity: 1756512000n, + baseAmountPaid: 999999999999999999n, + }, + { + chainId: 1, + hyperdriveAddress: "0xd7e470043241c10970953bd8374ee6238e77d735", + accountAddress: "0x20A690167060542EfFF10A947958286C31c7fF41", + assetId: + 452312848583266388373324160190187140051835877600158453279131187532667174656n, + bondAmount: 815076736513231897n, + maturity: 1756512000n, + baseAmountPaid: 790884816317464477n, + }, + { + chainId: 1, + hyperdriveAddress: "0xd7e470043241c10970953bd8374ee6238e77d735", + accountAddress: "0x6a946845A742a80a07Ce1181E68d91D3F0232EC0", + assetId: + 452312848583266388373324160190187140051835877600158453279131187532648512256n, + bondAmount: 50761253249503417n, + maturity: 1737849600n, + baseAmountPaid: 50000000000000000n, + }, + { + chainId: 1, + hyperdriveAddress: "0x158ed87d7e529cfe274f3036ade49975fb10f030", + accountAddress: "0x717d4C567Cf5D404e1ACA61959e7a14AD3a3C166", + assetId: + 452312848583266388373324160190187140051835877600158453279131187532668211456n, + bondAmount: 2052833976262706n, + maturity: 1757548800n, + baseAmountPaid: 2000000000000000n, + }, + { + chainId: 1, + hyperdriveAddress: "0x158ed87d7e529cfe274f3036ade49975fb10f030", + accountAddress: "0x376D5C3a16E9d015e8C584bB2d278E25F0ccb27B", + assetId: + 452312848583266388373324160190187140051835877600158453279131187532668384256n, + bondAmount: 1022928444267393465n, + maturity: 1757721600n, + baseAmountPaid: 1000000000000000000n, + }, + { + chainId: 1, + hyperdriveAddress: "0x8f2ac104e07d94488a1821e5a393351fca9239aa", + accountAddress: "0x335a6dDf1E5a06dDfA93Da993c0b638F2EF7A8E8", + assetId: + 452312848583266388373324160190187140051835877600158453279131187532668297856n, + bondAmount: 8696953455442414165890n, + maturity: 1757635200n, + baseAmountPaid: 8344030737554970632000n, + }, + { + chainId: 1, + hyperdriveAddress: "0xf1232dc21eadaf503d82f1e1361cff2bbf40394d", + accountAddress: "0x09229be5011e073165C87B788c8407390c61a43F", + assetId: + 452312848583266388373324160190187140051835877600158453279131187532668816256n, + bondAmount: 10525689539727414096354n, + maturity: 1758153600n, + baseAmountPaid: 10001157573767820734198n, + }, + { + chainId: 100, + hyperdriveAddress: "0xee9bff933add313c4289e98da80fefbf9d5cd9ba", + accountAddress: "0xeC9200551a328495CA51C1a7b95D17995B8935e6", + assetId: + 452312848583266388373324160190187140051835877600158453279131187532662854656n, + bondAmount: 2091222020062592226n, + maturity: 1752192000n, + baseAmountPaid: 2000000000000000000n, + }, + { + chainId: 100, + hyperdriveAddress: "0xee9bff933add313c4289e98da80fefbf9d5cd9ba", + accountAddress: "0x09229be5011e073165C87B788c8407390c61a43F", + assetId: + 452312848583266388373324160190187140051835877600158453279131187532668297856n, + bondAmount: 2089419700596227289164n, + maturity: 1757635200n, + baseAmountPaid: 2000000000000000000000n, + }, + { + chainId: 100, + hyperdriveAddress: "0x9248f874aaa2c53ad9324d7a2d033ea133443874", + accountAddress: "0x376D5C3a16E9d015e8C584bB2d278E25F0ccb27B", + assetId: + 452312848583266388373324160190187140051835877600158453279131187532668557056n, + bondAmount: 10515505907781250334933n, + maturity: 1757894400n, + baseAmountPaid: 10000000000000000000000n, + }, + { + chainId: 8453, + hyperdriveAddress: "0x9badb6a21fba04ee94fde3e85f7d170e90394c89", + accountAddress: "0x83c60309A690EAEBc238D6526dA72d6eb531Dc02", + assetId: + 452312848583266388373324160190187140051835877600158453279131187532657325056n, + bondAmount: 147947972421n, + maturity: 1746662400n, + baseAmountPaid: 125000000000n, + }, + { + chainId: 8453, + hyperdriveAddress: "0x9badb6a21fba04ee94fde3e85f7d170e90394c89", + accountAddress: "0x810816a0F73590D43160d6ec14399ACB8124E4bB", + assetId: + 452312848583266388373324160190187140051835877600158453279131187532656720256n, + bondAmount: 22256470799n, + maturity: 1746057600n, + baseAmountPaid: 20000000000n, + }, + { + chainId: 8453, + hyperdriveAddress: "0xdd8e1b14a04cbdd98dfcaf3f0db84a80bfb8fc25", + accountAddress: "0x236aFB3C32c8A68D5CE9d82e6b18Ff0D5D6A5016", + assetId: + 452312848583266388373324160190187140051835877600158453279131187532669161856n, + bondAmount: 105940436n, + maturity: 1758499200n, + baseAmountPaid: 100000000n, + }, + { + chainId: 8453, + hyperdriveAddress: "0x1243c06146aca2d4aaf8f9860f6d8d59d636d46c", + accountAddress: "0xB10a8378644343B6De1160E863B70A8a6Ea5C6f5", + assetId: + 452312848583266388373324160190187140051835877600158453279131187532642809856n, + bondAmount: 1035151765396664660003n, + maturity: 1732147200n, + baseAmountPaid: 1000000000000000000000n, + }, + { + chainId: 59144, + hyperdriveAddress: "0xb56e0bf37c4747abbc3aa9b8084b0d9b9a336777", + accountAddress: "0xCEFFF3aE8798F7A7aCb19Ad814EBB4E3fd2C041f", + assetId: + 452312848583266388373324160190187140051835877600158453279131187532654992256n, + bondAmount: 4476470881630894n, + maturity: 1744329600n, + baseAmountPaid: 4000000000000000n, + }, + { + chainId: 59144, + hyperdriveAddress: "0xb56e0bf37c4747abbc3aa9b8084b0d9b9a336777", + accountAddress: "0x9eB168Ab44B7c479431681558FdF34230c969DE9", + assetId: + 452312848583266388373324160190187140051835877600158453279131187532652313856n, + bondAmount: 2039838038721974n, + maturity: 1741651200n, + baseAmountPaid: 2000000000000000n, + }, + { + chainId: 59144, + hyperdriveAddress: "0x1cb0e96c07910fee9a22607bb9228c73848903a3", + accountAddress: "0x9eB168Ab44B7c479431681558FdF34230c969DE9", + assetId: + 452312848583266388373324160190187140051835877600158453279131187532652313856n, + bondAmount: 2130254339553114n, + maturity: 1741651200n, + baseAmountPaid: 2089122700018744n, + }, + ], + shorts: [ + { + chainId: 1, + hyperdriveAddress: "0x8f2ac104e07d94488a1821e5a393351fca9239aa", + accountAddress: "0x9eB168Ab44B7c479431681558FdF34230c969DE9", + assetId: + 904625697166532776746648320380374280103671755200316906558262375063571011712n, + bondAmount: 10000000000000000000n, + maturity: 1749686400n, + baseAmountPaid: 379969646879854842n, + baseProceeds: 9622530353120145160n, + checkpointTime: 1733961600n, + fixedRatePaid: 50774892611285808775n, + openedTimestamp: 1734019379n, + }, + { + chainId: 1, + hyperdriveAddress: "0xf1232dc21eadaf503d82f1e1361cff2bbf40394d", + accountAddress: "0x9eB168Ab44B7c479431681558FdF34230c969DE9", + assetId: + 904625697166532776746648320380374280103671755200316906558262375063567901312n, + bondAmount: 9700000000000000000n, + maturity: 1746576000n, + baseAmountPaid: 533485132170026382n, + baseProceeds: 6757439754927838877n, + checkpointTime: 1730851200n, + fixedRatePaid: 34459058169418218679n, + openedTimestamp: 1730919167n, + }, + { + chainId: 1, + hyperdriveAddress: "0x05b65fa90ad702e6fd0c3bd7c4c9c47bab2bea6b", + accountAddress: "0x9eB168Ab44B7c479431681558FdF34230c969DE9", + assetId: + 904625697166532776746648320380374280103671755200316906558262375063571098112n, + bondAmount: 14000000000000000000n, + maturity: 1749772800n, + baseAmountPaid: 1251409011637018853n, + baseProceeds: 12752090988362981149n, + checkpointTime: 1734048000n, + fixedRatePaid: 20430753608297256461n, + openedTimestamp: 1734068495n, + }, + { + chainId: 1, + hyperdriveAddress: "0x05b65fa90ad702e6fd0c3bd7c4c9c47bab2bea6b", + accountAddress: "0x9eB168Ab44B7c479431681558FdF34230c969DE9", + assetId: + 904625697166532776746648320380374280103671755200316906558262375063566864512n, + bondAmount: 8150000000000000000n, + maturity: 1745539200n, + baseAmountPaid: 467515140889363758n, + baseProceeds: 7684522359110636243n, + checkpointTime: 1729814400n, + fixedRatePaid: 32955469943030531578n, + openedTimestamp: 1729893743n, + }, + { + chainId: 1, + hyperdriveAddress: "0xd41225855a5c5ba1c672ccf4d72d1822a5686d30", + accountAddress: "0x5BE217bCF537377d0D5dB025f0ddD57CefF8dA84", + assetId: + 904625697166532776746648320380374280103671755200316906558262375063566086912n, + bondAmount: 75070000000000000000n, + maturity: 1744761600n, + baseAmountPaid: 2480255903187611128n, + baseProceeds: 72608511596812388872n, + checkpointTime: 1729036800n, + fixedRatePaid: 58694884166715619858n, + openedTimestamp: 1729056839n, + }, + { + chainId: 1, + hyperdriveAddress: "0xa4090183878d5b7b6ad104863743dd7e58985321", + accountAddress: "0x9eB168Ab44B7c479431681558FdF34230c969DE9", + assetId: + 904625697166532776746648320380374280103671755200316906558262375063571098112n, + bondAmount: 25000000000000000000n, + maturity: 1749772800n, + baseAmountPaid: 1442289226636782045n, + baseProceeds: 23563960773363217957n, + checkpointTime: 1734048000n, + fixedRatePaid: 32756855314087796801n, + openedTimestamp: 1734068327n, + }, + { + chainId: 1, + hyperdriveAddress: "0x4c3054e51b46be3191be9a05e73d73f1a2147854", + accountAddress: "0xC13Dbe26e27f3702A71664cc026FA3d4DB56c3Bb", + assetId: + 904625697166532776746648320380374280103671755200316906558262375063561853312n, + bondAmount: 1000000000000000n, + maturity: 1740528000n, + baseAmountPaid: 17533153849379n, + baseProceeds: 982977551246908n, + checkpointTime: 1724803200n, + fixedRatePaid: 112377492304692957860n, + openedTimestamp: 1724885699n, + }, + { + chainId: 100, + hyperdriveAddress: "0xee9bff933add313c4289e98da80fefbf9d5cd9ba", + accountAddress: "0x91cfD910E0B93911482706e9f1523541C6c1f837", + assetId: + 904625697166532776746648320380374280103671755200316906558262375063562630912n, + bondAmount: 4000000000000000000n, + maturity: 1741305600n, + baseAmountPaid: 149079827621512927n, + baseProceeds: 3851920172378487074n, + checkpointTime: 1725580800n, + fixedRatePaid: 51804455170221466678n, + openedTimestamp: 1725590995n, + }, + { + chainId: 100, + hyperdriveAddress: "0xee9bff933add313c4289e98da80fefbf9d5cd9ba", + accountAddress: "0xeC9200551a328495CA51C1a7b95D17995B8935e6", + assetId: + 904625697166532776746648320380374280103671755200316906558262375063571098112n, + bondAmount: 1000000000000000000n, + maturity: 1749772800n, + baseAmountPaid: 40134193869095578n, + baseProceeds: 960119225310509107n, + checkpointTime: 1734048000n, + fixedRatePaid: 47964227373952310276n, + openedTimestamp: 1734084935n, + }, + { + chainId: 100, + hyperdriveAddress: "0xee9bff933add313c4289e98da80fefbf9d5cd9ba", + accountAddress: "0xE83bAb2A2b8cA0B3A3941689a2336b3d5F3C3b5a", + assetId: + 904625697166532776746648320380374280103671755200316906558262375063572307712n, + bondAmount: 5000000000000000000000n, + maturity: 1750982400n, + baseAmountPaid: 211663762592976374034n, + baseProceeds: 4789586237407023625968n, + checkpointTime: 1735257600n, + fixedRatePaid: 45369041431273676332n, + openedTimestamp: 1735340345n, + }, + { + chainId: 100, + hyperdriveAddress: "0xee9bff933add313c4289e98da80fefbf9d5cd9ba", + accountAddress: "0xeC9200551a328495CA51C1a7b95D17995B8935e6", + assetId: + 904625697166532776746648320380374280103671755200316906558262375063573517312n, + bondAmount: 50000000000000000000n, + maturity: 1752192000n, + baseAmountPaid: 2235471039381719092n, + baseProceeds: 47777028960618280910n, + checkpointTime: 1736467200n, + fixedRatePaid: 42850700680312512511n, + openedTimestamp: 1736533930n, + }, + { + chainId: 100, + hyperdriveAddress: "0xee9bff933add313c4289e98da80fefbf9d5cd9ba", + accountAddress: "0xe9805eCAB212EAbf696cf458d2C4840A619Ee6De", + assetId: + 904625697166532776746648320380374280103671755200316906558262375063577146112n, + bondAmount: 1000000000000000000n, + maturity: 1755820800n, + baseAmountPaid: 44114348333382980n, + baseProceeds: 956135651666617021n, + checkpointTime: 1740096000n, + fixedRatePaid: 43455780142347741926n, + openedTimestamp: 1740141045n, + }, + { + chainId: 100, + hyperdriveAddress: "0xee9bff933add313c4289e98da80fefbf9d5cd9ba", + accountAddress: "0x9eB168Ab44B7c479431681558FdF34230c969DE9", + assetId: + 904625697166532776746648320380374280103671755200316906558262375063577405312n, + bondAmount: 1000000000000000000n, + maturity: 1756080000n, + baseAmountPaid: 44153347820723233n, + baseProceeds: 956096652179276769n, + checkpointTime: 1740355200n, + fixedRatePaid: 43415625397744929207n, + openedTimestamp: 1740412695n, + }, + { + chainId: 100, + hyperdriveAddress: "0xee9bff933add313c4289e98da80fefbf9d5cd9ba", + accountAddress: "0xf0cC4CDCA895C67E49C37E034B24f73f13EBf066", + assetId: + 904625697166532776746648320380374280103671755200316906558262375063577664512n, + bondAmount: 50000000000000000000n, + maturity: 1756339200n, + baseAmountPaid: 2303241824824498036n, + baseProceeds: 47709258175175501966n, + checkpointTime: 1740614400n, + fixedRatePaid: 41530848137278574791n, + openedTimestamp: 1740616010n, + }, + { + chainId: 100, + hyperdriveAddress: "0xee9bff933add313c4289e98da80fefbf9d5cd9ba", + accountAddress: "0x4FfD0A59a26cB2Aa76D403215e4cC2845C053994", + assetId: + 904625697166532776746648320380374280103671755200316906558262375063577664512n, + bondAmount: 18000000000000000000n, + maturity: 1756339200n, + baseAmountPaid: 831263695244854057n, + baseProceeds: 17174713645152753815n, + checkpointTime: 1740614400n, + fixedRatePaid: 41421039463690731969n, + openedTimestamp: 1740648000n, + }, + { + chainId: 100, + hyperdriveAddress: "0xee9bff933add313c4289e98da80fefbf9d5cd9ba", + accountAddress: "0xe6244D07E327b55442a5fb19C651cf8DbD4a0126", + assetId: + 904625697166532776746648320380374280103671755200316906558262375063578874112n, + bondAmount: 500000000000000000000n, + maturity: 1757548800n, + baseAmountPaid: 22325627732665033511n, + baseProceeds: 477800745833670583295n, + checkpointTime: 1741824000n, + fixedRatePaid: 42909132969016098310n, + openedTimestamp: 1741909290n, + }, + { + chainId: 100, + hyperdriveAddress: "0xee9bff933add313c4289e98da80fefbf9d5cd9ba", + accountAddress: "0xDba550Ce272d50C37c9b5cFd8cfA595fa365E439", + assetId: + 904625697166532776746648320380374280103671755200316906558262375063579219712n, + bondAmount: 408000000000000000000n, + maturity: 1757894400n, + baseAmountPaid: 13228573500449142721n, + baseProceeds: 394882711976751007276n, + checkpointTime: 1742169600n, + fixedRatePaid: 59848624399614723875n, + openedTimestamp: 1742217460n, + }, + { + chainId: 100, + hyperdriveAddress: "0xee9bff933add313c4289e98da80fefbf9d5cd9ba", + accountAddress: "0xd0E0aE3cF01c560d9874656bE6982813A98Cebf9", + assetId: + 904625697166532776746648320380374280103671755200316906558262375063579219712n, + bondAmount: 480000000000000000000n, + maturity: 1757894400n, + baseAmountPaid: 15888489502457442197n, + baseProceeds: 464250930788207673193n, + checkpointTime: 1742169600n, + fixedRatePaid: 58581596702167080689n, + openedTimestamp: 1742224515n, + }, + { + chainId: 100, + hyperdriveAddress: "0xee9bff933add313c4289e98da80fefbf9d5cd9ba", + accountAddress: "0x50F8CCCE9A2842a9e092D7D6089c76dfDd790836", + assetId: + 904625697166532776746648320380374280103671755200316906558262375063579306112n, + bondAmount: 150000000000000000000n, + maturity: 1757980800n, + baseAmountPaid: 5050441952695223533n, + baseProceeds: 144992750326524130320n, + checkpointTime: 1742256000n, + fixedRatePaid: 57558436461702876609n, + openedTimestamp: 1742320320n, + }, + { + chainId: 100, + hyperdriveAddress: "0xee9bff933add313c4289e98da80fefbf9d5cd9ba", + accountAddress: "0x8559a4ce46500A8C05D43A5cAcEeEb00B321276b", + assetId: + 904625697166532776746648320380374280103671755200316906558262375063579392512n, + bondAmount: 188000000000000000000n, + maturity: 1758067200n, + baseAmountPaid: 7143525063338006336n, + baseProceeds: 180915385078380892978n, + checkpointTime: 1742342400n, + fixedRatePaid: 50774185511024977203n, + openedTimestamp: 1742399655n, + }, + { + chainId: 100, + hyperdriveAddress: "0xee9bff933add313c4289e98da80fefbf9d5cd9ba", + accountAddress: "0x15FeDE541a4a3759Bf19D0b609dDFD95F072Ad9a", + assetId: + 904625697166532776746648320380374280103671755200316906558262375063579392512n, + bondAmount: 51000000000000000000n, + maturity: 1758067200n, + baseAmountPaid: 1942561991084684612n, + baseProceeds: 49073566551293415811n, + checkpointTime: 1742342400n, + fixedRatePaid: 50646734998444629275n, + openedTimestamp: 1742401535n, + }, + { + chainId: 100, + hyperdriveAddress: "0xee9bff933add313c4289e98da80fefbf9d5cd9ba", + accountAddress: "0x1F874A360996E85f3597C5a9CA2816c38378817C", + assetId: + 904625697166532776746648320380374280103671755200316906558262375063579392512n, + bondAmount: 2600000000000000000n, + maturity: 1758067200n, + baseAmountPaid: 99212951116451410n, + baseProceeds: 2501737469993429258n, + checkpointTime: 1742342400n, + fixedRatePaid: 50551008003592596755n, + openedTimestamp: 1742421490n, + }, + { + chainId: 100, + hyperdriveAddress: "0xee9bff933add313c4289e98da80fefbf9d5cd9ba", + accountAddress: "0xaF09b7A08764b0CaB6d38f6f4aB43F9B8b99A03d", + assetId: + 904625697166532776746648320380374280103671755200316906558262375063579565312n, + bondAmount: 22000000000000000000n, + maturity: 1758240000n, + baseAmountPaid: 985117644496147157n, + baseProceeds: 21021597788803073289n, + checkpointTime: 1742515200n, + fixedRatePaid: 42781926943489277519n, + openedTimestamp: 1742540625n, + }, + { + chainId: 8453, + hyperdriveAddress: "0x9badb6a21fba04ee94fde3e85f7d170e90394c89", + accountAddress: "0x83c60309A690EAEBc238D6526dA72d6eb531Dc02", + assetId: + 904625697166532776746648320380374280103671755200316906558262375063568074112n, + bondAmount: 243000000000n, + maturity: 1746748800n, + baseAmountPaid: 40191501202n, + baseProceeds: 202838873799n, + checkpointTime: 1738886400n, + fixedRatePaid: 20239668479302204264n, + openedTimestamp: 1738949379n, + }, + { + chainId: 8453, + hyperdriveAddress: "0x9badb6a21fba04ee94fde3e85f7d170e90394c89", + accountAddress: "0x83c60309A690EAEBc238D6526dA72d6eb531Dc02", + assetId: + 904625697166532776746648320380374280103671755200316906558262375063567987712n, + bondAmount: 203800000000n, + maturity: 1746662400n, + baseAmountPaid: 29912691932n, + baseProceeds: 173912783069n, + checkpointTime: 1738800000n, + fixedRatePaid: 23316526757161562970n, + openedTimestamp: 1738803265n, + }, + { + chainId: 59144, + hyperdriveAddress: "0xb56e0bf37c4747abbc3aa9b8084b0d9b9a336777", + accountAddress: "0xCEFFF3aE8798F7A7aCb19Ad814EBB4E3fd2C041f", + assetId: + 904625697166532776746648320380374280103671755200316906558262375063565654912n, + bondAmount: 17000000000000000n, + maturity: 1744329600n, + baseAmountPaid: 1065145759275170n, + baseProceeds: 15939104240724831n, + checkpointTime: 1728604800n, + fixedRatePaid: 30002713100389503482n, + openedTimestamp: 1728679681n, + }, + ], +}; diff --git a/apps/hyperdrive-trading/src/ui/hyperdrive/longs/StatusCell.tsx b/apps/hyperdrive-trading/src/ui/hyperdrive/StatusCell.tsx similarity index 93% rename from apps/hyperdrive-trading/src/ui/hyperdrive/longs/StatusCell.tsx rename to apps/hyperdrive-trading/src/ui/hyperdrive/StatusCell.tsx index 401a51340..c73b2bfa1 100644 --- a/apps/hyperdrive-trading/src/ui/hyperdrive/longs/StatusCell.tsx +++ b/apps/hyperdrive-trading/src/ui/hyperdrive/StatusCell.tsx @@ -29,7 +29,7 @@ export function StatusCell({ className={classNames("flex w-28 items-center gap-2 font-inter", { "rounded-md border border-accent/20 bg-accent/20 px-[6px] py-[2px] text-accent": isTermComplete, - [statusCellClassName || "text-neutral-content"]: !isTermComplete, + [statusCellClassName || ""]: !isTermComplete, })} > {isTermComplete ? : null} diff --git a/apps/hyperdrive-trading/src/ui/hyperdrive/hooks/useAssetBalance.ts b/apps/hyperdrive-trading/src/ui/hyperdrive/hooks/useAssetBalance.ts new file mode 100644 index 000000000..98dff7a5c --- /dev/null +++ b/apps/hyperdrive-trading/src/ui/hyperdrive/hooks/useAssetBalance.ts @@ -0,0 +1,53 @@ +import { hyperdriveAbi } from "@delvtech/hyperdrive-js"; +import { QueryStatus, useQuery } from "@tanstack/react-query"; +import { makeQueryKey2 } from "src/base/makeQueryKey"; +import { useDrift } from "src/ui/drift/useDrift"; +import { Address } from "viem"; + +export function useAssetBalance({ + account, + assetId, + hyperdriveAddress, + chainId, +}: { + account: Address | undefined; + assetId: bigint; + hyperdriveAddress: Address; + chainId: number; +}): { + assetBalance: bigint | undefined; + assetBalanceStatus: QueryStatus; +} { + const drift = useDrift({ chainId }); + const queryEnabled = !!account && !!drift; + const { data, status } = useQuery({ + queryKey: makeQueryKey2({ + namespace: "hyperdrive", + queryId: "assetBalance", + params: { + account, + assetId, + chainId, + hyperdriveAddress, + }, + }), + queryFn: queryEnabled + ? async () => + drift.read({ + address: hyperdriveAddress, + abi: hyperdriveAbi, + fn: "balanceOf", + args: { + owner: account, + tokenId: assetId, + }, + }) + : undefined, + enabled: queryEnabled, + }); + + return { + assetBalance: data, + assetBalanceStatus: status, + }; +} diff --git a/apps/hyperdrive-trading/src/ui/hyperdrive/longs/CloseLongForm/CloseLongForm.tsx b/apps/hyperdrive-trading/src/ui/hyperdrive/longs/CloseLongForm/CloseLongForm.tsx index 599529901..b06be923a 100644 --- a/apps/hyperdrive-trading/src/ui/hyperdrive/longs/CloseLongForm/CloseLongForm.tsx +++ b/apps/hyperdrive-trading/src/ui/hyperdrive/longs/CloseLongForm/CloseLongForm.tsx @@ -21,10 +21,11 @@ import { formatBalance } from "src/ui/base/formatting/formatBalance"; import { useActiveItem } from "src/ui/base/hooks/useActiveItem"; import { useNumericInput } from "src/ui/base/hooks/useNumericInput"; import { SwitchNetworksButton } from "src/ui/chains/SwitchChainButton/SwitchChainButton"; +import { useAssetBalance } from "src/ui/hyperdrive/hooks/useAssetBalance"; import { InvalidTransactionButton } from "src/ui/hyperdrive/InvalidTransactionButton"; import { useCloseLong } from "src/ui/hyperdrive/longs/hooks/useCloseLong"; import { usePreviewCloseLong } from "src/ui/hyperdrive/longs/hooks/usePreviewCloseLong"; -import { StatusCell } from "src/ui/hyperdrive/longs/StatusCell"; +import { StatusCell } from "src/ui/hyperdrive/StatusCell"; import { TransactionView } from "src/ui/hyperdrive/TransactionView"; import { useCloseLongZap } from "src/ui/hyperdrive/zaps/hooks/useCloseLongZap"; import { ApproveTokenChoices } from "src/ui/token/ApproveTokenChoices"; @@ -61,6 +62,12 @@ export function CloseLongForm({ hyperdriveChainId: hyperdrive.chainId, appConfig, }); + const { assetBalance = 0n } = useAssetBalance({ + account, + assetId: long.assetId, + hyperdriveAddress: hyperdrive.address, + chainId: hyperdrive.chainId, + }); const { isFlagEnabled: isZapsEnabled } = useFeatureFlag("zaps"); @@ -183,7 +190,7 @@ export function CloseLongForm({ } // You can't close an amount that's larger than the position size const isAmountLargerThanPositionSize = !!( - bondAmountAsBigInt && bondAmountAsBigInt > long.bondAmount + bondAmountAsBigInt && bondAmountAsBigInt > assetBalance ); const { closeLongZap } = useCloseLongZap({ @@ -232,7 +239,7 @@ export function CloseLongForm({ token={`hy${baseToken.symbol}`} value={bondAmount ?? ""} maxValue={ - long ? formatUnits(long.bondAmount, hyperdrive.decimals) : "" + long ? formatUnits(assetBalance, hyperdrive.decimals) : "" } onChange={(newAmount) => { window.plausible("formChange", { @@ -250,9 +257,9 @@ export function CloseLongForm({ bottomRightElement={
{`Balance: ${formatBalance({ - balance: long.bondAmount, + balance: assetBalance, decimals: hyperdrive.decimals, - places: baseToken.places, + places: 4, })}`}
} diff --git a/apps/hyperdrive-trading/src/ui/hyperdrive/queryKeys.ts b/apps/hyperdrive-trading/src/ui/hyperdrive/queryKeys.ts index 733f55652..7dbcd5135 100644 --- a/apps/hyperdrive-trading/src/ui/hyperdrive/queryKeys.ts +++ b/apps/hyperdrive-trading/src/ui/hyperdrive/queryKeys.ts @@ -1,6 +1,12 @@ import "src/base/makeQueryKey"; import { Address } from "viem"; interface HyperdriveQueryKeys { + assetBalance: { + account: Address | undefined; + assetId: bigint; + hyperdriveAddress: Address; + chainId: number; + }; unpausedPools: { chainId: number; filterPoolsWithoutRewards?: boolean; diff --git a/apps/hyperdrive-trading/src/ui/hyperdrive/shorts/CloseShortForm/CloseShortForm.tsx b/apps/hyperdrive-trading/src/ui/hyperdrive/shorts/CloseShortForm/CloseShortForm.tsx index 320379f0f..06e723307 100644 --- a/apps/hyperdrive-trading/src/ui/hyperdrive/shorts/CloseShortForm/CloseShortForm.tsx +++ b/apps/hyperdrive-trading/src/ui/hyperdrive/shorts/CloseShortForm/CloseShortForm.tsx @@ -15,10 +15,11 @@ import { formatBalance } from "src/ui/base/formatting/formatBalance"; import { useActiveItem } from "src/ui/base/hooks/useActiveItem"; import { useNumericInput } from "src/ui/base/hooks/useNumericInput"; import { SwitchNetworksButton } from "src/ui/chains/SwitchChainButton/SwitchChainButton"; +import { useAssetBalance } from "src/ui/hyperdrive/hooks/useAssetBalance"; import { InvalidTransactionButton } from "src/ui/hyperdrive/InvalidTransactionButton"; -import { StatusCell } from "src/ui/hyperdrive/longs/StatusCell"; import { useCloseShort } from "src/ui/hyperdrive/shorts/hooks/useCloseShort"; import { usePreviewCloseShort } from "src/ui/hyperdrive/shorts/hooks/usePreviewCloseShort"; +import { StatusCell } from "src/ui/hyperdrive/StatusCell"; import { TransactionView } from "src/ui/hyperdrive/TransactionView"; import { useTokenBalance } from "src/ui/token/hooks/useTokenBalance"; import { useTokenFiatPrice } from "src/ui/token/hooks/useTokenFiatPrice"; @@ -60,6 +61,13 @@ export function CloseShortForm({ defaultItems.push(sharesToken); } + const { assetBalance = 0n } = useAssetBalance({ + account, + assetId: short.assetId, + hyperdriveAddress: hyperdrive.address, + chainId: hyperdrive.chainId, + }); + const { balance: baseTokenBalance } = useTokenBalance({ account, tokenAddress: baseToken.address, @@ -88,7 +96,7 @@ export function CloseShortForm({ // You can't close an amount that's larger than the position size const isAmountLargerThanPositionSize = !!( - amountAsBigInt && amountAsBigInt > short.bondAmount + amountAsBigInt && amountAsBigInt > assetBalance ); const { amountOut, flatPlusCurveFee, previewCloseShortStatus } = usePreviewCloseShort({ @@ -158,7 +166,7 @@ export function CloseShortForm({ token={`hy${baseToken.symbol}`} value={amount ?? ""} maxValue={ - short ? formatUnits(short.bondAmount, hyperdrive.decimals) : "" + short ? formatUnits(assetBalance, hyperdrive.decimals) : "" } onChange={(newAmount) => { window.plausible("formChange", { @@ -177,9 +185,9 @@ export function CloseShortForm({
{short ? `Balance: ${formatBalance({ - balance: short.bondAmount, + balance: assetBalance, decimals: hyperdrive.decimals, - places: baseToken?.places, + places: 4, })}` : undefined}
diff --git a/apps/hyperdrive-trading/src/ui/portfolio/CurrentBalanceCell.tsx b/apps/hyperdrive-trading/src/ui/portfolio/CurrentBalanceCell.tsx new file mode 100644 index 000000000..da86219ec --- /dev/null +++ b/apps/hyperdrive-trading/src/ui/portfolio/CurrentBalanceCell.tsx @@ -0,0 +1,55 @@ +import { getBaseToken, HyperdriveConfig } from "@delvtech/hyperdrive-appconfig"; +import { + type OpenLongPositionReceived, + type OpenShort, +} from "@delvtech/hyperdrive-js"; +import { ReactElement } from "react"; +import Skeleton from "react-loading-skeleton"; +import { useAppConfigForConnectedChain } from "src/ui/appconfig/useAppConfigForConnectedChain"; +import { formatBalance } from "src/ui/base/formatting/formatBalance"; +import { useAssetBalance } from "src/ui/hyperdrive/hooks/useAssetBalance"; +import type { Address } from "viem"; + +export function CurrentBalanceCell({ + row, + account, + hyperdrive, +}: { + row: + | OpenLongPositionReceived + | (OpenShort & { hyperdrive: HyperdriveConfig }); + account: Address; + hyperdrive: HyperdriveConfig; +}): ReactElement { + const { assetBalance, assetBalanceStatus } = useAssetBalance({ + account, + assetId: row.assetId, + hyperdriveAddress: hyperdrive.address, + chainId: hyperdrive.chainId, + }); + const appConfig = useAppConfigForConnectedChain(); + const baseToken = getBaseToken({ + hyperdriveChainId: hyperdrive.chainId, + hyperdriveAddress: hyperdrive.address, + appConfig, + }); + + if (assetBalanceStatus === "loading") { + return ( +
+ +
+ ); + } + + return ( +
+ {formatBalance({ + balance: assetBalance || 0n, + decimals: baseToken.decimals, + places: baseToken.places, + })}{" "} + hy{baseToken.symbol} +
+ ); +} diff --git a/apps/hyperdrive-trading/src/ui/portfolio/longs/LongsContainer.tsx b/apps/hyperdrive-trading/src/ui/portfolio/longs/LongsContainer.tsx index 94256d8bb..d06cdc346 100644 --- a/apps/hyperdrive-trading/src/ui/portfolio/longs/LongsContainer.tsx +++ b/apps/hyperdrive-trading/src/ui/portfolio/longs/LongsContainer.tsx @@ -5,7 +5,7 @@ import { ExternalLink } from "src/ui/analytics/ExternalLink"; import { useAppConfigForConnectedChain } from "src/ui/appconfig/useAppConfigForConnectedChain"; import LoadingState from "src/ui/base/components/LoadingState"; import { NonIdealState } from "src/ui/base/components/NonIdealState"; -import { usePortfolioLongsData } from "src/ui/portfolio/longs/usePortfolioLongsData"; +import { usePortfolioLongsSnapshotData } from "src/ui/portfolio/longs/usePortfolioLongsSnapshotData"; import { NoWalletConnected } from "src/ui/portfolio/NoWalletConnected"; import { PositionContainer } from "src/ui/portfolio/PositionContainer"; import { Address } from "viem"; @@ -17,9 +17,10 @@ export function OpenLongsContainer({ account: Address | undefined; }): ReactElement { const appConfig = useAppConfigForConnectedChain(); - const { openLongPositions, openLongPositionsStatus } = usePortfolioLongsData({ - account, - }); + const { openLongPositions, openLongPositionsStatus } = + usePortfolioLongsSnapshotData({ + account, + }); const hyperdrivesByChainAndYieldSource = groupBy( appConfig.hyperdrives, @@ -75,7 +76,7 @@ export function OpenLongsContainer({ return ( {Object.entries(hyperdrivesByChainAndYieldSource).map( - ([key, hyperdrives], i) => ( + ([, hyperdrives], i) => ( { return ( - +
+ + +
); }, }), diff --git a/apps/hyperdrive-trading/src/ui/portfolio/longs/usePortfolioLongsSnapshotData.ts b/apps/hyperdrive-trading/src/ui/portfolio/longs/usePortfolioLongsSnapshotData.ts new file mode 100644 index 000000000..0fb9aced0 --- /dev/null +++ b/apps/hyperdrive-trading/src/ui/portfolio/longs/usePortfolioLongsSnapshotData.ts @@ -0,0 +1,188 @@ +import { HyperdriveConfig } from "@delvtech/hyperdrive-appconfig"; +import { + hyperdriveAbi, + OpenLongPositionReceived, +} from "@delvtech/hyperdrive-js"; +import { useQuery } from "@tanstack/react-query"; +import { makeQueryKey, makeQueryKey2 } from "src/base/makeQueryKey"; +import { getDrift } from "src/drift/getDrift"; +import { POSITIONS_SNAPSHOT } from "src/hyperdrive/positionsSnapshot"; +import { useAppConfigForConnectedChain } from "src/ui/appconfig/useAppConfigForConnectedChain"; +import type { OpenLongPositionsData } from "src/ui/portfolio/longs/usePortfolioLongsData"; +import { Address } from "viem"; + +export function usePortfolioLongsSnapshotData({ + account, +}: { + account: Address | undefined; +}): { + openLongPositions: OpenLongPositionsData | undefined; + openLongPositionsStatus: "error" | "success" | "loading"; +} { + const appConfigForConnectedChain = useAppConfigForConnectedChain(); + const queryEnabled = !!account && !!appConfigForConnectedChain; + const { data: openLongPositions, status: openLongPositionsStatus } = useQuery( + { + queryKey: makeQueryKey("portfolioLongs", { account }), + enabled: queryEnabled, + queryFn: queryEnabled + ? async () => { + const openLongsByHyperdrive = new Map< + HyperdriveConfig, + { + hyperdrive: HyperdriveConfig; + openLongs: OpenLongPositionReceived[]; + } + >(); + + await Promise.all( + POSITIONS_SNAPSHOT.longs.map(async (long) => { + if ( + long.accountAddress.toLowerCase() !== account.toLowerCase() + ) { + return; + } + + const hyperdrive = appConfigForConnectedChain.hyperdrives.find( + (h) => + h.chainId === long.chainId && + h.address.toLowerCase() === + long.hyperdriveAddress.toLowerCase(), + ); + if (!hyperdrive) { + return; + } + + const drift = await getDrift({ chainId: long.chainId }); + const currentBalance = await drift.read({ + abi: hyperdriveAbi, + address: long.hyperdriveAddress, + fn: "balanceOf", + args: { + owner: long.accountAddress, + tokenId: long.assetId, + }, + }); + if (!currentBalance) { + return; + } + + if (!openLongsByHyperdrive.has(hyperdrive)) { + openLongsByHyperdrive.set(hyperdrive, { + hyperdrive, + openLongs: [], + }); + } + + openLongsByHyperdrive.get(hyperdrive)!.openLongs.push({ + assetId: long.assetId, + maturity: long.maturity, + value: long.bondAmount, + details: { + assetId: long.assetId, + baseAmountPaid: long.baseAmountPaid, + bondAmount: long.bondAmount, + maturity: long.maturity, + }, + }); + }), + ); + + return Array.from(openLongsByHyperdrive.values()); + } + : undefined, + }, + ); + + return { + openLongPositions, + openLongPositionsStatus, + }; +} + +export function usePortfolioLongsSnapshotDataFromHyperdrives({ + hyperdrives, + account, +}: { + hyperdrives: HyperdriveConfig[]; + account: Address | undefined; +}): { + openLongPositions: + | (OpenLongPositionReceived & { hyperdrive: HyperdriveConfig })[] + | undefined; + openLongPositionsStatus: "error" | "success" | "loading"; +} { + const queryEnabled = !!account && !!hyperdrives.length; + const { data: openLongPositions, status: openLongPositionsStatus } = useQuery( + { + queryKey: makeQueryKey2({ + namespace: "portfolio", + queryId: "openLongPositions", + params: { account, hyperdrives }, + }), + queryFn: queryEnabled + ? async () => { + const openLongs: (OpenLongPositionReceived & { + hyperdrive: HyperdriveConfig; + })[] = []; + + await Promise.all( + POSITIONS_SNAPSHOT.longs.map(async (long) => { + if ( + long.accountAddress.toLowerCase() !== + account.toLocaleLowerCase() + ) { + return; + } + + const hyperdrive = hyperdrives.find( + (h) => + h.chainId === long.chainId && + h.address.toLowerCase() === + long.hyperdriveAddress.toLowerCase(), + ); + if (!hyperdrive) { + return; + } + + const drift = await getDrift({ chainId: long.chainId }); + const currentBalance = await drift.read({ + abi: hyperdriveAbi, + address: long.hyperdriveAddress, + fn: "balanceOf", + args: { + owner: long.accountAddress, + tokenId: long.assetId, + }, + }); + if (!currentBalance) { + return; + } + + openLongs.push({ + hyperdrive, + assetId: long.assetId, + maturity: long.maturity, + value: long.bondAmount, + details: { + assetId: long.assetId, + baseAmountPaid: long.baseAmountPaid, + bondAmount: long.bondAmount, + maturity: long.maturity, + }, + }); + }), + ); + + return openLongs; + } + : undefined, + enabled: queryEnabled, + }, + ); + + return { + openLongPositions, + openLongPositionsStatus, + }; +} diff --git a/apps/hyperdrive-trading/src/ui/portfolio/shorts/OpenShortsTable/OpenShortsTableDesktop.tsx b/apps/hyperdrive-trading/src/ui/portfolio/shorts/OpenShortsTable/OpenShortsTableDesktop.tsx index 137fe3824..fab975538 100644 --- a/apps/hyperdrive-trading/src/ui/portfolio/shorts/OpenShortsTable/OpenShortsTableDesktop.tsx +++ b/apps/hyperdrive-trading/src/ui/portfolio/shorts/OpenShortsTable/OpenShortsTableDesktop.tsx @@ -1,7 +1,6 @@ import { AppConfig, getBaseToken, - getOpenShortRewardConfigs, HyperdriveConfig, } from "@delvtech/hyperdrive-appconfig"; import { OpenShort } from "@delvtech/hyperdrive-js"; @@ -21,15 +20,16 @@ import { ConnectWalletButton } from "src/ui/base/components/ConnectWallet"; import { NonIdealState } from "src/ui/base/components/NonIdealState"; import { Pagination } from "src/ui/base/components/Pagination"; import { formatBalance } from "src/ui/base/formatting/formatBalance"; -import { StatusCell } from "src/ui/hyperdrive/longs/StatusCell"; import { MaturesOnCell } from "src/ui/hyperdrive/MaturesOnCell/MaturesOnCell"; import { CloseShortModalButton } from "src/ui/hyperdrive/shorts/CloseShortModalButton/CloseShortModalButton"; +import { StatusCell } from "src/ui/hyperdrive/StatusCell"; +import { CurrentBalanceCell } from "src/ui/portfolio/CurrentBalanceCell"; import { PositionTableHeading } from "src/ui/portfolio/PositionTableHeading"; import { CurrentShortsValueCell } from "src/ui/portfolio/shorts/OpenShortsTable/CurrentShortsValueCell"; import { ManageShortButton } from "src/ui/portfolio/shorts/OpenShortsTable/ManageShortButton"; import { ShortRateAndSizeCell } from "src/ui/portfolio/shorts/OpenShortsTable/ShortRateAndSizeCell"; import { TotalOpenShortsValue } from "src/ui/portfolio/shorts/OpenShortsTable/TotalOpenShortsValue"; -import { usePortfolioShortsDataFromHyperdrives } from "src/ui/portfolio/shorts/usePortfolioShortsData"; +import { usePortfolioShortsSnapshotDataFromHyperdrives } from "src/ui/portfolio/shorts/usePortfolioShortsSnapshotData"; import { Address } from "viem"; export function OpenShortsTableDesktop({ @@ -40,7 +40,7 @@ export function OpenShortsTableDesktop({ account: Address | undefined; }): ReactElement | null { const appConfig = useAppConfigForConnectedChain(); - const { openShortPositions } = usePortfolioShortsDataFromHyperdrives({ + const { openShortPositions } = usePortfolioShortsSnapshotDataFromHyperdrives({ hyperdrives, account, }); @@ -62,14 +62,6 @@ export function OpenShortsTableDesktop({ getSortedRowModel: getSortedRowModel(), getPaginationRowModel: getPaginationRowModel(), }); - const poolHasRewards = hyperdrives.some((hyperdrive) => { - const rewardConfigs = getOpenShortRewardConfigs({ - appConfig, - chainId: hyperdrive.chainId, - hyperdriveAddress: hyperdrive.address, - }); - return !!rewardConfigs?.length; - }); if (!account) { return ( @@ -108,15 +100,15 @@ export function OpenShortsTableDesktop({ />
{/* Modal needs to be rendered outside of the table so that dialog can be used. Otherwise react throws a dom nesting error */} - {tableInstance.getRowModel().rows.map((row) => { - const modalId = `${row.original.hyperdriveAddress}-${row.original.assetId}`; + {tableInstance.getRowModel().rows.map(({ original }) => { + const modalId = `${original.hyperdrive.address}-${original.assetId}`; return ( ); })} @@ -288,13 +280,20 @@ function getColumns({ }), columnHelper.display({ id: "status", - header: `Status`, + header: "Status / Current Balance", cell: ({ row }) => { return ( - +
+ + +
); }, }), diff --git a/apps/hyperdrive-trading/src/ui/portfolio/shorts/ShortsContainer.tsx b/apps/hyperdrive-trading/src/ui/portfolio/shorts/ShortsContainer.tsx index a393b35b4..b687e7e7a 100644 --- a/apps/hyperdrive-trading/src/ui/portfolio/shorts/ShortsContainer.tsx +++ b/apps/hyperdrive-trading/src/ui/portfolio/shorts/ShortsContainer.tsx @@ -8,7 +8,7 @@ import { NonIdealState } from "src/ui/base/components/NonIdealState"; import { NoWalletConnected } from "src/ui/portfolio/NoWalletConnected"; import { PositionContainer } from "src/ui/portfolio/PositionContainer"; import { OpenShortsTableDesktop } from "src/ui/portfolio/shorts/OpenShortsTable/OpenShortsTableDesktop"; -import { usePortfolioShortsData } from "src/ui/portfolio/shorts/usePortfolioShortsData"; +import { usePortfolioShortsSnapshotData } from "src/ui/portfolio/shorts/usePortfolioShortsSnapshotData"; import { Address } from "viem"; export function OpenShortsContainer({ @@ -17,7 +17,7 @@ export function OpenShortsContainer({ account: Address | undefined; }): ReactElement | null { const { openShortPositions, openShortPositionsStatus } = - usePortfolioShortsData({ account }); + usePortfolioShortsSnapshotData({ account }); const appConfig = useAppConfigForConnectedChain(); const hyperdrivesByChainAndYieldSource = groupBy( appConfig.hyperdrives, diff --git a/apps/hyperdrive-trading/src/ui/portfolio/shorts/usePortfolioShortsSnapshotData.ts b/apps/hyperdrive-trading/src/ui/portfolio/shorts/usePortfolioShortsSnapshotData.ts new file mode 100644 index 000000000..3dd8121f0 --- /dev/null +++ b/apps/hyperdrive-trading/src/ui/portfolio/shorts/usePortfolioShortsSnapshotData.ts @@ -0,0 +1,182 @@ +import { HyperdriveConfig } from "@delvtech/hyperdrive-appconfig"; +import { hyperdriveAbi, OpenShort } from "@delvtech/hyperdrive-js"; +import { useQuery } from "@tanstack/react-query"; +import { makeQueryKey, makeQueryKey2 } from "src/base/makeQueryKey"; +import { getDrift } from "src/drift/getDrift"; +import { POSITIONS_SNAPSHOT } from "src/hyperdrive/positionsSnapshot"; +import { useAppConfigForConnectedChain } from "src/ui/appconfig/useAppConfigForConnectedChain"; +import type { OpenShortPositionsData } from "src/ui/portfolio/shorts/usePortfolioShortsData"; +import { Address } from "viem"; + +export function usePortfolioShortsSnapshotData({ + account, +}: { + account: Address | undefined; +}): { + openShortPositions: OpenShortPositionsData | undefined; + openShortPositionsStatus: "error" | "success" | "loading"; +} { + const appConfigForConnectedChain = useAppConfigForConnectedChain(); + const queryEnabled = !!account && !!appConfigForConnectedChain; + + const { data: openShortPositions, status: openShortPositionsStatus } = + useQuery({ + queryKey: makeQueryKey("portfolioShorts", { account }), + enabled: queryEnabled, + queryFn: queryEnabled + ? async () => { + const openShortsByHyperdrive = new Map< + HyperdriveConfig, + { + hyperdrive: HyperdriveConfig; + openShorts: OpenShort[]; + } + >(); + + await Promise.all( + POSITIONS_SNAPSHOT.shorts.map(async (short) => { + if ( + short.accountAddress.toLowerCase() !== account.toLowerCase() + ) { + return; + } + + const hyperdrive = appConfigForConnectedChain.hyperdrives.find( + (h) => + h.chainId === short.chainId && + h.address.toLowerCase() === + short.hyperdriveAddress.toLowerCase(), + ); + if (!hyperdrive) { + return; + } + + const drift = await getDrift({ chainId: short.chainId }); + const currentBalance = await drift.read({ + abi: hyperdriveAbi, + address: short.hyperdriveAddress, + fn: "balanceOf", + args: { + owner: short.accountAddress, + tokenId: short.assetId, + }, + }); + if (!currentBalance) { + return; + } + + if (!openShortsByHyperdrive.has(hyperdrive)) { + openShortsByHyperdrive.set(hyperdrive, { + hyperdrive, + openShorts: [], + }); + } + + openShortsByHyperdrive.get(hyperdrive)!.openShorts.push({ + assetId: short.assetId, + baseAmountPaid: short.baseAmountPaid, + baseProceeds: short.baseProceeds, + bondAmount: short.bondAmount, + checkpointTime: short.checkpointTime, + fixedRatePaid: short.fixedRatePaid, + hyperdriveAddress: short.hyperdriveAddress, + maturity: short.maturity, + openedTimestamp: short.openedTimestamp, + }); + }), + ); + + return Array.from(openShortsByHyperdrive.values()); + } + : undefined, + }); + return { + openShortPositions, + openShortPositionsStatus, + }; +} + +export function usePortfolioShortsSnapshotDataFromHyperdrives({ + hyperdrives, + account, +}: { + hyperdrives: HyperdriveConfig[]; + account: Address | undefined; +}): { + openShortPositions: + | (OpenShort & { hyperdrive: HyperdriveConfig })[] + | undefined; + openShortPositionsStatus: "error" | "success" | "loading"; +} { + const queryEnabled = !!account && !!hyperdrives.length; + const { data: openShortPositions, status: openShortPositionsStatus } = + useQuery({ + queryKey: makeQueryKey2({ + namespace: "portfolio", + queryId: "openShortPositions", + params: { account, hyperdrives }, + }), + queryFn: queryEnabled + ? async () => { + const openShorts: (OpenShort & { + hyperdrive: HyperdriveConfig; + })[] = []; + + await Promise.all( + POSITIONS_SNAPSHOT.shorts.map(async (short) => { + if ( + short.accountAddress.toLowerCase() !== account.toLowerCase() + ) { + return; + } + + const hyperdrive = hyperdrives.find( + (h) => + h.chainId === short.chainId && + h.address.toLowerCase() === + short.hyperdriveAddress.toLowerCase(), + ); + if (!hyperdrive) { + return; + } + + const drift = await getDrift({ chainId: short.chainId }); + const currentBalance = await drift.read({ + abi: hyperdriveAbi, + address: short.hyperdriveAddress, + fn: "balanceOf", + args: { + owner: short.accountAddress, + tokenId: short.assetId, + }, + }); + if (!currentBalance) { + return; + } + + openShorts.push({ + hyperdrive, + assetId: short.assetId, + baseAmountPaid: short.baseAmountPaid, + baseProceeds: short.baseProceeds, + bondAmount: short.bondAmount, + checkpointTime: short.checkpointTime, + fixedRatePaid: short.fixedRatePaid, + hyperdriveAddress: short.hyperdriveAddress, + maturity: short.maturity, + openedTimestamp: short.openedTimestamp, + }); + }), + ); + + return openShorts; + } + : undefined, + enabled: queryEnabled, + }); + + return { + openShortPositions, + openShortPositionsStatus, + }; +}