diff --git a/.changeset/fuzzy-poems-train.md b/.changeset/fuzzy-poems-train.md
new file mode 100644
index 0000000000..76743bf26d
--- /dev/null
+++ b/.changeset/fuzzy-poems-train.md
@@ -0,0 +1,9 @@
+---
+'@penumbra-zone/storage': major
+'@penumbra-zone/services': minor
+'@penumbra-zone/query': minor
+'@penumbra-zone/types': minor
+'@penumbra-zone/wasm': minor
+---
+
+Modify GasPrices storage to support multi-asset fees
diff --git a/packages/query/src/block-processor.ts b/packages/query/src/block-processor.ts
index 4659d24207..b2dcdb225e 100644
--- a/packages/query/src/block-processor.ts
+++ b/packages/query/src/block-processor.ts
@@ -45,6 +45,7 @@ import { processActionDutchAuctionEnd } from './helpers/process-action-dutch-auc
 import { processActionDutchAuctionSchedule } from './helpers/process-action-dutch-auction-schedule';
 import { processActionDutchAuctionWithdraw } from './helpers/process-action-dutch-auction-withdraw';
 import { RootQuerier } from './root-querier';
+import { GasPrices } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/fee/v1/fee_pb';
 
 declare global {
   // eslint-disable-next-line no-var
@@ -162,12 +163,18 @@ export class BlockProcessor implements BlockProcessorInterface {
         await this.indexedDb.saveFmdParams(compactBlock.fmdParameters);
       }
       if (compactBlock.gasPrices) {
-        // TODO #1310 pre-populate assetId for native GasPrices using stakingTokenAssetId
-        await this.indexedDb.saveGasPrices(compactBlock.gasPrices);
+        await this.indexedDb.saveGasPrices(
+          new GasPrices({
+            assetId: this.stakingAssetId,
+            ...compactBlock.gasPrices,
+          }),
+        );
+      }
+      if (compactBlock.altGasPrices.length) {
+        for (const gasPrice of compactBlock.altGasPrices) {
+          await this.indexedDb.saveGasPrices(gasPrice);
+        }
       }
-      // if (compactBlock.altGasPrices) {
-      // TODO #1310 save altGasPrices to indexed-db
-      // }
 
       // wasm view server scan
       // - decrypts new notes
diff --git a/packages/services/src/test-utils.ts b/packages/services/src/test-utils.ts
index 6e4670f506..9ea7437946 100644
--- a/packages/services/src/test-utils.ts
+++ b/packages/services/src/test-utils.ts
@@ -9,7 +9,8 @@ export interface IndexedDbMock {
   constants?: Mock;
   getAppParams?: Mock;
   getAssetsMetadata?: Mock;
-  getGasPrices?: Mock;
+  getNativeGasPrices?: Mock;
+  getAltGasPrices?: Mock;
   getFmdParams?: Mock;
   getFullSyncHeight?: Mock;
   getNotesForVoting?: Mock;
diff --git a/packages/services/src/view-service/gas-prices.test.ts b/packages/services/src/view-service/gas-prices.test.ts
index d918b09b46..abe9ad62cc 100644
--- a/packages/services/src/view-service/gas-prices.test.ts
+++ b/packages/services/src/view-service/gas-prices.test.ts
@@ -20,7 +20,8 @@ describe('GasPrices request handler', () => {
     vi.resetAllMocks();
 
     mockIndexedDb = {
-      getGasPrices: vi.fn(),
+      getNativeGasPrices: vi.fn(),
+      getAltGasPrices: vi.fn(),
     };
     mockServices = {
       getWalletServices: vi.fn(() =>
@@ -40,7 +41,7 @@ describe('GasPrices request handler', () => {
   });
 
   test('should successfully get gas prices when idb has them', async () => {
-    mockIndexedDb.getGasPrices?.mockResolvedValue(testData);
+    mockIndexedDb.getNativeGasPrices?.mockResolvedValue(testData);
     const gasPricesResponse = new GasPricesResponse(
       await gasPrices(new GasPricesRequest(), mockCtx),
     );
@@ -48,7 +49,7 @@ describe('GasPrices request handler', () => {
   });
 
   test('should fail to get gas prices when idb has none', async () => {
-    mockIndexedDb.getGasPrices?.mockResolvedValue(undefined);
+    mockIndexedDb.getNativeGasPrices?.mockResolvedValue(undefined);
     await expect(gasPrices(new GasPricesRequest(), mockCtx)).rejects.toThrow(
       'Gas prices is not available',
     );
diff --git a/packages/services/src/view-service/gas-prices.ts b/packages/services/src/view-service/gas-prices.ts
index 1125a508db..454e8b78e4 100644
--- a/packages/services/src/view-service/gas-prices.ts
+++ b/packages/services/src/view-service/gas-prices.ts
@@ -23,11 +23,12 @@ import { Code, ConnectError } from '@connectrpc/connect';
 export const gasPrices: Impl['gasPrices'] = async (_, ctx) => {
   const services = await ctx.values.get(servicesCtx)();
   const { indexedDb } = await services.getWalletServices();
-  const gasPrices = await indexedDb.getGasPrices();
+  const gasPrices = await indexedDb.getNativeGasPrices();
+  const altGasPRices = await indexedDb.getAltGasPrices();
   if (!gasPrices) throw new ConnectError('Gas prices is not available', Code.NotFound);
 
   return {
     gasPrices,
-    // TODO #1310 add altGasPrices
+    altGasPRices,
   };
 };
diff --git a/packages/services/src/view-service/transaction-planner/index.test.ts b/packages/services/src/view-service/transaction-planner/index.test.ts
index b17bf773fc..6ecb9df69f 100644
--- a/packages/services/src/view-service/transaction-planner/index.test.ts
+++ b/packages/services/src/view-service/transaction-planner/index.test.ts
@@ -35,7 +35,7 @@ describe('TransactionPlanner request handler', () => {
     mockIndexedDb = {
       getFmdParams: vi.fn(),
       getAppParams: vi.fn(),
-      getGasPrices: vi.fn(),
+      getNativeGasPrices: vi.fn(),
       constants: vi.fn(),
       stakingTokenAssetId: vi.fn(),
       hasStakingAssetBalance: vi.fn(),
@@ -92,7 +92,7 @@ describe('TransactionPlanner request handler', () => {
         }),
       }),
     );
-    mockIndexedDb.getGasPrices?.mockResolvedValueOnce(
+    mockIndexedDb.getNativeGasPrices?.mockResolvedValueOnce(
       new GasPrices({
         verificationPrice: 22n,
         executionPrice: 222n,
diff --git a/packages/services/src/view-service/transaction-planner/index.ts b/packages/services/src/view-service/transaction-planner/index.ts
index 627aaa8853..6cd09336a7 100644
--- a/packages/services/src/view-service/transaction-planner/index.ts
+++ b/packages/services/src/view-service/transaction-planner/index.ts
@@ -14,7 +14,7 @@ export const transactionPlanner: Impl['transactionPlanner'] = async (req, ctx) =
   const { indexedDb } = await services.getWalletServices();
 
   // Query IndexedDB directly to check for the existence of staking token
-  const nativeToken = await indexedDb.hasStakingAssetBalance();
+  const nativeToken = await indexedDb.hasStakingAssetBalance(req.source);
 
   // Initialize the gas fee token using the native staking token's asset ID
   // If there is no native token balance, extract and use an alternate gas fee token
@@ -28,7 +28,7 @@ export const transactionPlanner: Impl['transactionPlanner'] = async (req, ctx) =
   if (!chainId) throw new ConnectError('ChainId not available', Code.FailedPrecondition);
 
   // Wasm planner needs the presence of gas prices in the db to work
-  const gasPrices = await indexedDb.getGasPrices();
+  const gasPrices = await indexedDb.getNativeGasPrices();
   if (!gasPrices) throw new ConnectError('Gas prices is not available', Code.FailedPrecondition);
 
   const idbConstants = indexedDb.constants();
diff --git a/packages/storage/src/indexed-db/config.ts b/packages/storage/src/indexed-db/config.ts
index 8a028dd485..637aff2283 100644
--- a/packages/storage/src/indexed-db/config.ts
+++ b/packages/storage/src/indexed-db/config.ts
@@ -2,4 +2,4 @@
  * The version number for the IndexedDB schema. This version number is used to manage
  * database upgrades and ensure that the correct schema version is applied.
  */
-export const IDB_VERSION = 43;
+export const IDB_VERSION = 44;
diff --git a/packages/storage/src/indexed-db/index.ts b/packages/storage/src/indexed-db/index.ts
index 7cf7cd5db9..7240d67909 100644
--- a/packages/storage/src/indexed-db/index.ts
+++ b/packages/storage/src/indexed-db/index.ts
@@ -119,7 +119,7 @@ export class IndexedDb implements IndexedDbInterface {
         db.createObjectStore('SWAPS', {
           keyPath: 'swapCommitment.inner',
         }).createIndex('nullifier', 'nullifier.inner');
-        db.createObjectStore('GAS_PRICES');
+        db.createObjectStore('GAS_PRICES', { keyPath: 'assetId.inner' });
         db.createObjectStore('POSITIONS', { keyPath: 'id.inner' });
         db.createObjectStore('EPOCHS', { autoIncrement: true });
         db.createObjectStore('VALIDATOR_INFOS');
@@ -385,21 +385,26 @@ export class IndexedDb implements IndexedDbInterface {
     return SwapRecord.fromJson(json);
   }
 
-  // TODO #1310 'getGasPrices()' should be renamed to 'getNativeGasPrice()'
-  async getGasPrices(): Promise<GasPrices | undefined> {
-    // TODO #1310 use this.stakingTokenAssetId as the key for the query
-    const jsonGasPrices = await this.db.get('GAS_PRICES', 'gas_prices');
+  async getNativeGasPrices(): Promise<GasPrices | undefined> {
+    const jsonGasPrices = await this.db.get(
+      'GAS_PRICES',
+      uint8ArrayToBase64(this.stakingTokenAssetId.inner),
+    );
     if (!jsonGasPrices) return undefined;
     return GasPrices.fromJson(jsonGasPrices);
   }
 
-  // TODO #1310 implement getAltGasPrices()
+  async getAltGasPrices(): Promise<GasPrices[]> {
+    const allGasPrices = await this.db.getAll('GAS_PRICES');
+    return allGasPrices
+      .map(gp => GasPrices.fromJson(gp))
+      .filter(gp => !gp.assetId?.equals(this.stakingTokenAssetId));
+  }
 
   async saveGasPrices(value: PartialMessage<GasPrices>): Promise<void> {
     await this.u.update({
       table: 'GAS_PRICES',
       value: new GasPrices(value).toJson() as Jsonified<GasPrices>,
-      key: 'gas_prices',
     });
   }
 
@@ -815,7 +820,7 @@ export class IndexedDb implements IndexedDbInterface {
     };
   }
 
-  async hasStakingAssetBalance(): Promise<boolean> {
+  async hasStakingAssetBalance(addressIndex: AddressIndex | undefined): Promise<boolean> {
     const spendableUMNotes = await this.db.getAllFromIndex(
       'SPENDABLE_NOTES',
       'assetId',
@@ -824,7 +829,11 @@ export class IndexedDb implements IndexedDbInterface {
 
     return spendableUMNotes.some(note => {
       const umNote = SpendableNoteRecord.fromJson(note);
-      return umNote.heightSpent === 0n && !isZero(getAmountFromRecord(umNote));
+      return (
+        umNote.heightSpent === 0n &&
+        !isZero(getAmountFromRecord(umNote)) &&
+        umNote.addressIndex?.equals(addressIndex)
+      );
     });
   }
 }
diff --git a/packages/storage/src/indexed-db/indexed-db.test.ts b/packages/storage/src/indexed-db/indexed-db.test.ts
index e00dce25fe..4c0c2b0a0e 100644
--- a/packages/storage/src/indexed-db/indexed-db.test.ts
+++ b/packages/storage/src/indexed-db/indexed-db.test.ts
@@ -393,13 +393,14 @@ describe('IndexedDb', () => {
       const db = await IndexedDb.initialize({ ...generateInitialProps() });
 
       const gasPrices = new GasPrices({
+        assetId: db.stakingTokenAssetId,
         blockSpacePrice: 0n,
         compactBlockSpacePrice: 0n,
         verificationPrice: 0n,
         executionPrice: 0n,
       });
       await db.saveGasPrices(gasPrices);
-      const savedPrices = await db.getGasPrices();
+      const savedPrices = await db.getNativeGasPrices();
 
       expect(gasPrices.equals(savedPrices)).toBeTruthy();
     });
diff --git a/packages/types/src/indexed-db.ts b/packages/types/src/indexed-db.ts
index a6d4af249f..d5ef7faa44 100644
--- a/packages/types/src/indexed-db.ts
+++ b/packages/types/src/indexed-db.ts
@@ -88,8 +88,8 @@ export interface IndexedDbInterface {
   getSwapByNullifier(nullifier: Nullifier): Promise<SwapRecord | undefined>;
   saveSwap(note: SwapRecord): Promise<void>;
   getSwapByCommitment(commitment: StateCommitment): Promise<SwapRecord | undefined>;
-  getGasPrices(): Promise<GasPrices | undefined>;
-  // TODO #1310 add getAltGasPrices()
+  getNativeGasPrices(): Promise<GasPrices | undefined>;
+  getAltGasPrices(): Promise<GasPrices[]>;
   saveGasPrices(value: PartialMessage<GasPrices>): Promise<void>;
   getNotesForVoting(
     addressIndex: AddressIndex | undefined,
@@ -146,7 +146,7 @@ export interface IndexedDbInterface {
     auctionId: AuctionId,
   ): Promise<{ input: Value; output: Value } | undefined>;
 
-  hasStakingAssetBalance(): Promise<boolean>;
+  hasStakingAssetBalance(addressIndex: AddressIndex | undefined): Promise<boolean>;
 }
 
 export interface PenumbraDb extends DBSchema {
@@ -231,9 +231,8 @@ export interface PenumbraDb extends DBSchema {
       nullifier: Jsonified<Required<SwapRecord>['nullifier']['inner']>; // base64
     };
   };
-  // TODO #1310 use the assetId as key
   GAS_PRICES: {
-    key: 'gas_prices';
+    key: Jsonified<Required<GasPrices>['assetId']['inner']>; // base64
     value: Jsonified<GasPrices>;
   };
   POSITIONS: {
diff --git a/packages/wasm/crate/src/planner.rs b/packages/wasm/crate/src/planner.rs
index fb35877de8..989fbcd1d4 100644
--- a/packages/wasm/crate/src/planner.rs
+++ b/packages/wasm/crate/src/planner.rs
@@ -1,13 +1,11 @@
-use crate::metadata::customize_symbol_inner;
-use crate::note_record::SpendableNoteRecord;
-use crate::storage::{IndexedDBStorage, OutstandingReserves};
-use crate::utils;
-use crate::{error::WasmResult, swap_record::SwapRecord};
+use std::collections::BTreeMap;
+use std::mem;
+
 use anyhow::anyhow;
 use ark_ff::UniformRand;
 use decaf377::{Fq, Fr};
 use penumbra_asset::asset::{Id, Metadata};
-use penumbra_asset::{Value, STAKING_TOKEN_ASSET_ID};
+use penumbra_asset::Value;
 use penumbra_auction::auction::dutch::actions::ActionDutchAuctionWithdrawPlan;
 use penumbra_auction::auction::dutch::{
     ActionDutchAuctionEnd, ActionDutchAuctionSchedule, DutchAuctionDescription,
@@ -38,11 +36,15 @@ use penumbra_transaction::ActionList;
 use penumbra_transaction::{plan::MemoPlan, ActionPlan, TransactionParameters};
 use prost::Message;
 use rand_core::{OsRng, RngCore};
-use std::collections::BTreeMap;
-use std::mem;
 use wasm_bindgen::prelude::wasm_bindgen;
 use wasm_bindgen::JsValue;
 
+use crate::metadata::customize_symbol_inner;
+use crate::note_record::SpendableNoteRecord;
+use crate::storage::{IndexedDBStorage, OutstandingReserves};
+use crate::utils;
+use crate::{error::WasmResult, swap_record::SwapRecord};
+
 /// Prioritize notes to spend to release value of a specific transaction.
 ///
 /// Various logic is possible for note selection. Currently, this method
@@ -181,13 +183,15 @@ pub async fn plan_transaction(
 
     let chain_id: String = app_parameters.chain_id;
 
+    // Decode the gas fee token into an `Id` type
+    let fee_asset_id: Id = Id::decode(gas_fee_token)?;
+
     // Request information about current gas prices
-    // TODO #1310 GasPrices record may not exist for alternative fee assets
-    let mut gas_prices: GasPrices = {
+    let gas_prices: GasPrices = {
         let gas_prices: penumbra_proto::core::component::fee::v1::GasPrices =
             serde_wasm_bindgen::from_value(
                 storage
-                    .get_gas_prices()
+                    .get_gas_prices_by_asset_id(fee_asset_id)
                     .await?
                     .ok_or_else(|| anyhow!("GasPrices not available"))?,
             )?;
@@ -202,28 +206,12 @@ pub async fn plan_transaction(
         }
     };
 
-    // Decode the gas fee token into an `Id` type
-    let alt_gas: Id = Id::decode(gas_fee_token)?;
-
-    // Check if the decoded gas fee token is different from the staking token asset ID.
-    // If the gas fee token is different, use the alternative gas fee token with a 10x
-    // multiplier.
-    if alt_gas != *STAKING_TOKEN_ASSET_ID {
-        gas_prices = GasPrices {
-            asset_id: alt_gas,
-            block_space_price: gas_prices.block_space_price * 10,
-            compact_block_space_price: gas_prices.compact_block_space_price * 10,
-            verification_price: gas_prices.verification_price * 10,
-            execution_price: gas_prices.execution_price * 10,
-        };
-    };
-
     let mut transaction_parameters = TransactionParameters {
         chain_id,
         expiry_height,
         ..Default::default()
     };
-    transaction_parameters.fee.0.asset_id = alt_gas;
+    transaction_parameters.fee.0.asset_id = fee_asset_id;
 
     let mut actions_list = ActionList::default();
 
diff --git a/packages/wasm/crate/src/storage.rs b/packages/wasm/crate/src/storage.rs
index 9c7b5b361f..eff821d981 100644
--- a/packages/wasm/crate/src/storage.rs
+++ b/packages/wasm/crate/src/storage.rs
@@ -323,14 +323,15 @@ impl IndexedDBStorage {
             .transpose()?)
     }
 
-    // TODO #1310 should be changed to get GasPrices by assetId
-    pub async fn get_gas_prices(&self) -> WasmResult<Option<JsValue>> {
+    pub async fn get_gas_prices_by_asset_id(&self, asset_id: Id) -> WasmResult<Option<JsValue>> {
         let tx = self
             .db
             .transaction_on_one(&self.constants.tables.gas_prices)?;
         let store = tx.object_store(&self.constants.tables.gas_prices)?;
 
-        Ok(store.get_owned("gas_prices")?.await?)
+        Ok(store
+            .get_owned(byte_array_to_base64(&asset_id.to_proto().inner))?
+            .await?)
         // TODO GasPrices is missing domain type impl, requiring this
         // .map(serde_wasm_bindgen::from_value)
         // .transpose()?)
@@ -387,7 +388,7 @@ impl IndexedDBStorage {
     }
 }
 
-fn byte_array_to_base64(byte_array: &Vec<u8>) -> String {
+pub fn byte_array_to_base64(byte_array: &Vec<u8>) -> String {
     base64::Engine::encode(&base64::engine::general_purpose::STANDARD, byte_array)
 }
 
diff --git a/packages/wasm/crate/tests/build.rs b/packages/wasm/crate/tests/build.rs
index d436abd578..0db507f4ac 100644
--- a/packages/wasm/crate/tests/build.rs
+++ b/packages/wasm/crate/tests/build.rs
@@ -36,6 +36,7 @@ mod tests {
     use wasm_bindgen_test::*;
 
     use penumbra_wasm::planner::plan_transaction;
+    use penumbra_wasm::storage::byte_array_to_base64;
     use penumbra_wasm::{
         build::build_action,
         keys::load_proving_key,
@@ -372,7 +373,9 @@ mod tests {
             serde_wasm_bindgen::to_value(&"last_forgotten").unwrap();
         let fmd_json_key: JsValue = serde_wasm_bindgen::to_value(&"params").unwrap();
         let app_json_key: JsValue = serde_wasm_bindgen::to_value(&"params").unwrap();
-        let gas_json_key: JsValue = serde_wasm_bindgen::to_value(&"gas_prices").unwrap();
+        let gas_json_key: JsValue = JsValue::from_str(&byte_array_to_base64(
+            &STAKING_TOKEN_ASSET_ID.to_proto().inner,
+        ));
 
         store_note.put_val(&spendable_note_json).unwrap();
         store_tree_commitments
diff --git a/scripts/pack-public.sh b/scripts/pack-public.sh
old mode 100644
new mode 100755