From 8d6b007d84d1e804b59774e6a1ab318c162db904 Mon Sep 17 00:00:00 2001 From: Max Korsunov Date: Tue, 28 Jan 2025 12:56:03 +0400 Subject: [PATCH] feat(storage): #1989: add subaccount filter to `getOwnedPositionIds` method --- packages/storage/src/indexed-db/index.ts | 20 ++++++-- .../src/indexed-db/indexed-db.test-data.ts | 4 ++ .../storage/src/indexed-db/indexed-db.test.ts | 46 +++++++++++++------ 3 files changed, 54 insertions(+), 16 deletions(-) diff --git a/packages/storage/src/indexed-db/index.ts b/packages/storage/src/indexed-db/index.ts index 77d83969da..d4af1427d9 100644 --- a/packages/storage/src/indexed-db/index.ts +++ b/packages/storage/src/indexed-db/index.ts @@ -570,6 +570,7 @@ export class IndexedDb implements IndexedDbInterface { async *getOwnedPositionIds( positionState: PositionState | undefined, tradingPair: TradingPair | undefined, + subaccount: AddressIndex | undefined, ) { yield* new ReadableStream({ start: async cont => { @@ -578,7 +579,10 @@ export class IndexedDb implements IndexedDbInterface { const position = Position.fromJson(cursor.value.position); if ( (!positionState || positionState.equals(position.state)) && - (!tradingPair || tradingPair.equals(position.phi?.pair)) + (!tradingPair || tradingPair.equals(position.phi?.pair)) && + (!subaccount || + (cursor.value.subaccount && + subaccount.equals(AddressIndex.fromJson(cursor.value.subaccount)))) ) { cont.enqueue(PositionId.fromJson(cursor.value.id)); } @@ -589,16 +593,25 @@ export class IndexedDb implements IndexedDbInterface { }); } - async addPosition(positionId: PositionId, position: Position): Promise { + async addPosition( + positionId: PositionId, + position: Position, + subaccount?: AddressIndex, + ): Promise { assertPositionId(positionId); const positionRecord = { id: positionId.toJson() as Jsonified, position: position.toJson() as Jsonified, + subaccount: subaccount && (subaccount.toJson() as Jsonified), }; await this.u.update({ table: 'POSITIONS', value: positionRecord }); } - async updatePosition(positionId: PositionId, newState: PositionState): Promise { + async updatePosition( + positionId: PositionId, + newState: PositionState, + subaccount?: AddressIndex, + ): Promise { assertPositionId(positionId); const key = uint8ArrayToBase64(positionId.inner); const positionRecord = await this.db.get('POSITIONS', key); @@ -615,6 +628,7 @@ export class IndexedDb implements IndexedDbInterface { value: { id: positionId.toJson() as Jsonified, position: position.toJson() as Jsonified, + subaccount: subaccount ? (subaccount.toJson() as Jsonified) : undefined, }, }); } diff --git a/packages/storage/src/indexed-db/indexed-db.test-data.ts b/packages/storage/src/indexed-db/indexed-db.test-data.ts index 614b024e5b..26a4b323df 100644 --- a/packages/storage/src/indexed-db/indexed-db.test-data.ts +++ b/packages/storage/src/indexed-db/indexed-db.test-data.ts @@ -11,6 +11,7 @@ import { Transaction } from '@penumbra-zone/protobuf/penumbra/core/transaction/v import type { ScanBlockResult } from '@penumbra-zone/types/state-commitment-tree'; import { base64ToUint8Array } from '@penumbra-zone/types/base64'; import { StateCommitment } from '@penumbra-zone/protobuf/penumbra/crypto/tct/v1/tct_pb'; +import { AddressIndex } from '@penumbra-zone/protobuf/penumbra/core/keys/v1/keys_pb'; const hash3312332298 = base64ToUint8Array('JbOzRkf0VKm4eIM0DS27N5igX8jxvPhAMpBWSr2bj/Q='); @@ -717,3 +718,6 @@ export const epoch3 = new Epoch({ index: 3n, startHeight: 300n, }); + +export const mainAccount = new AddressIndex({ account: 0 }); +export const firstSubaccount = new AddressIndex({ account: 1 }); diff --git a/packages/storage/src/indexed-db/indexed-db.test.ts b/packages/storage/src/indexed-db/indexed-db.test.ts index 9716d2846f..492bf19f8a 100644 --- a/packages/storage/src/indexed-db/indexed-db.test.ts +++ b/packages/storage/src/indexed-db/indexed-db.test.ts @@ -28,6 +28,8 @@ import { tradingPairGmGn, transaction, transactionId, + mainAccount, + firstSubaccount, } from './indexed-db.test-data.js'; import { AddressIndex, WalletId } from '@penumbra-zone/protobuf/penumbra/core/keys/v1/keys_pb'; import { @@ -496,13 +498,13 @@ describe('IndexedDb', () => { it('position should be added and their state should change', async () => { const db = await IndexedDb.initialize({ ...generateInitialProps() }); - await db.addPosition(positionIdGmPenumbraBuy, positionGmPenumbraBuy); + await db.addPosition(positionIdGmPenumbraBuy, positionGmPenumbraBuy, mainAccount); await db.updatePosition( positionIdGmPenumbraBuy, new PositionState({ state: PositionState_PositionStateEnum.CLOSED }), ); const ownedPositions: PositionId[] = []; - for await (const positionId of db.getOwnedPositionIds(undefined, undefined)) { + for await (const positionId of db.getOwnedPositionIds(undefined, undefined, undefined)) { ownedPositions.push(positionId as PositionId); } expect(ownedPositions.length).toBe(1); @@ -521,12 +523,12 @@ describe('IndexedDb', () => { it('should get all position ids', async () => { const db = await IndexedDb.initialize({ ...generateInitialProps() }); - await db.addPosition(positionIdGmPenumbraBuy, positionGmPenumbraBuy); - await db.addPosition(positionIdGnPenumbraSell, positionGnPenumbraSell); - await db.addPosition(positionIdGmGnSell, positionGmGnSell); + await db.addPosition(positionIdGmPenumbraBuy, positionGmPenumbraBuy, mainAccount); + await db.addPosition(positionIdGnPenumbraSell, positionGnPenumbraSell, mainAccount); + await db.addPosition(positionIdGmGnSell, positionGmGnSell, firstSubaccount); const ownedPositions: PositionId[] = []; - for await (const positionId of db.getOwnedPositionIds(undefined, undefined)) { + for await (const positionId of db.getOwnedPositionIds(undefined, undefined, undefined)) { ownedPositions.push(positionId as PositionId); } expect(ownedPositions.length).toBe(3); @@ -534,14 +536,15 @@ describe('IndexedDb', () => { it('should get all position with given position state', async () => { const db = await IndexedDb.initialize({ ...generateInitialProps() }); - await db.addPosition(positionIdGmPenumbraBuy, positionGmPenumbraBuy); - await db.addPosition(positionIdGnPenumbraSell, positionGnPenumbraSell); - await db.addPosition(positionIdGmGnSell, positionGmGnSell); + await db.addPosition(positionIdGmPenumbraBuy, positionGmPenumbraBuy, mainAccount); + await db.addPosition(positionIdGnPenumbraSell, positionGnPenumbraSell, mainAccount); + await db.addPosition(positionIdGmGnSell, positionGmGnSell, firstSubaccount); const ownedPositions: PositionId[] = []; for await (const positionId of db.getOwnedPositionIds( new PositionState({ state: PositionState_PositionStateEnum.CLOSED }), undefined, + undefined, )) { ownedPositions.push(positionId as PositionId); } @@ -550,16 +553,33 @@ describe('IndexedDb', () => { it('should get all position with given trading pair', async () => { const db = await IndexedDb.initialize({ ...generateInitialProps() }); - await db.addPosition(positionIdGmPenumbraBuy, positionGmPenumbraBuy); - await db.addPosition(positionIdGnPenumbraSell, positionGnPenumbraSell); - await db.addPosition(positionIdGmGnSell, positionGmGnSell); + await db.addPosition(positionIdGmPenumbraBuy, positionGmPenumbraBuy, mainAccount); + await db.addPosition(positionIdGnPenumbraSell, positionGnPenumbraSell, mainAccount); + await db.addPosition(positionIdGmGnSell, positionGmGnSell, firstSubaccount); const ownedPositions: PositionId[] = []; - for await (const positionId of db.getOwnedPositionIds(undefined, tradingPairGmGn)) { + for await (const positionId of db.getOwnedPositionIds( + undefined, + tradingPairGmGn, + undefined, + )) { ownedPositions.push(positionId as PositionId); } expect(ownedPositions.length).toBe(1); }); + + it('should get all position with given subaccount index', async () => { + const db = await IndexedDb.initialize({ ...generateInitialProps() }); + await db.addPosition(positionIdGmPenumbraBuy, positionGmPenumbraBuy, mainAccount); + await db.addPosition(positionIdGnPenumbraSell, positionGnPenumbraSell, mainAccount); + await db.addPosition(positionIdGmGnSell, positionGmGnSell, firstSubaccount); + + const ownedPositions: PositionId[] = []; + for await (const positionId of db.getOwnedPositionIds(undefined, undefined, mainAccount)) { + ownedPositions.push(positionId as PositionId); + } + expect(ownedPositions.length).toBe(2); + }); }); describe('prices', () => {