diff --git a/README.md b/README.md
index 5a514080..4fdd8a09 100644
--- a/README.md
+++ b/README.md
@@ -46,10 +46,9 @@ The `nibijs` source code can be found in the `src` directory.
   - [Example: Creating a wallet](#example-creating-a-wallet)
   - [Example: Querying](#example-querying)
   - [Example: Sending funds](#example-sending-funds)
-  - [Example: Transaction with arbitrary messages](#example-transaction-with-arbitrary-messages)
 - [Codebase structure](#codebase-structure)
 - [Development Quick Start](#development-quick-start)
-- [🔓 License](#%F0%9F%94%93-license)
+- [🔓 License](#-license)
 
 To learn more about Nibiru, see [nibiru.fi/docs](https://nibiru.fi/docs)
 
@@ -100,14 +99,6 @@ console.log("balances: %o", balances)
 const blockHeight = 200000
 const block = await querier.getBlock(blockHeight)
 console.log("block: %o", block)
-
-// Query PERP markets
-const perpMarkets = await querier.nibiruExtensions.perp.markets()
-console.log("perpMarkets: %o", perpMarkets)
-
-// Query SPOT pools
-const spotPools = await querier.nibiruExtensions.spot.pools()
-console.log("spotPools: %o", spotPools)
 ```
 
 ### Example: Sending funds
@@ -151,63 +142,6 @@ balances = await querier.getAllBalances(exampleAddress)
 console.log("balances: %o", balances)
 ```
 
-### Example: Transaction with arbitrary messages
-
-```js
-import {
-  NibiruTxClient,
-  newSignerFromMnemonic,
-  Msg,
-  Testnet,
-  NibiruQuerier,
-} from "@nibiruchain/nibijs"
-import { coin } from "@cosmjs/proto-signing"
-
-const mnemonic = "Your mnemonic here"
-export const CHAIN = Testnet(2)
-const signer = await newSignerFromMnemonic(mnemonic)
-const querier = await NibiruQuerier.connect(CHAIN.endptTm)
-const txClient = await NibiruTxClient.connectWithSigner(CHAIN.endptTm, signer)
-const [{ address: fromAddr }] = await signer.getAccounts()
-const pair = "ubtc:unusd"
-
-// Construct tx msgs
-const msgs = [
-  Msg.perp.openPosition({
-    sender: fromAddr,
-    pair: pair,
-    quoteAssetAmount: 10,
-    leverage: 1,
-    goLong: true,
-    baseAssetAmountLimit: 0,
-  }),
-  Msg.perp.addMargin({
-    sender: fromAddr,
-    pair: pair,
-    margin: coin("20", "unusd"),
-  }),
-  Msg.perp.removeMargin({
-    sender: fromAddr,
-    pair: pair,
-    margin: coin("5", "unusd"),
-  }),
-  // final margin value of 10 (open) + 20 (add) - 5 (remove) = 25
-]
-
-// Broadcast tx
-const txResp = await txClient.signAndBroadcast(fromAddr, msgs, "auto")
-console.log(txResp)
-
-// Check your open PERP positions
-const delay = (ms) => new Promise((res) => setTimeout(res, ms))
-await delay(5000)
-
-const perpPositions = await querier.nibiruExtensions.perp.positions({
-  trader: fromAddr,
-})
-console.log("perpPositions: %o", perpPositions)
-```
-
 ## Codebase structure
 
 | Directories of `@nibiruchain/nibijs` | Purpose/Utility                                                                                                                          |
diff --git a/nibiru b/nibiru
index d71d67dc..3199ae53 160000
--- a/nibiru
+++ b/nibiru
@@ -1 +1 @@
-Subproject commit d71d67dcf4cd269c7d8d3be5b13a5cd8c4ee27b6
+Subproject commit 3199ae538bc2e1f4bb8d06727d0d10b96c6822a8
diff --git a/package.json b/package.json
index fa2ba827..935b8994 100644
--- a/package.json
+++ b/package.json
@@ -45,8 +45,8 @@
     "@cosmjs/tendermint-rpc": "^0.32.3",
     "bignumber.js": "^9.1.1",
     "cross-fetch": "4.0.0",
-    "graphql": "^16.7.1",
-    "graphql-ws": "^5.14.0",
+    "graphql": "^16.9.0",
+    "graphql-ws": "^5.16.0",
     "pako": "^2.1.0"
   },
   "peerDependencies": {
@@ -54,7 +54,7 @@
     "@cosmjs/proto-signing": "^0.32.3",
     "@cosmjs/stargate": "^0.32.3",
     "@cosmjs/tendermint-rpc": "^0.32.3",
-    "graphql": "^16.7.1"
+    "graphql": "^16.9.0"
   },
   "devDependencies": {
     "@bufbuild/buf": "^1.28.1",
diff --git a/src/gql/heart-monitor/heart-monitor.test.ts b/src/gql/heart-monitor/heart-monitor.test.ts
index b2c87c4e..30a5c1d8 100644
--- a/src/gql/heart-monitor/heart-monitor.test.ts
+++ b/src/gql/heart-monitor/heart-monitor.test.ts
@@ -139,10 +139,7 @@ const testFeatureFlags = async (fields: GQLFeatureFlags) => {
   if (resp.featureFlags) {
     const { featureFlags } = resp
 
-    checkFields(
-      [featureFlags],
-      ["gov", "oracle", "perp", "spot", "staking", "wasm"]
-    )
+    checkFields([featureFlags], ["gov", "oracle", "staking", "wasm"])
   }
 }
 
@@ -398,10 +395,7 @@ test("queryBatchHandler", async () => {
   if (resp.featureFlags) {
     const { featureFlags } = resp
 
-    checkFields(
-      [featureFlags],
-      ["gov", "oracle", "perp", "spot", "staking", "wasm"]
-    )
+    checkFields([featureFlags], ["gov", "oracle", "staking", "wasm"])
   }
 })
 
diff --git a/src/gql/utils/consts.test.ts b/src/gql/utils/consts.test.ts
index b62dfa85..a6ad8f81 100644
--- a/src/gql/utils/consts.test.ts
+++ b/src/gql/utils/consts.test.ts
@@ -37,10 +37,7 @@ describe("queryBatchHandler tests", () => {
     if (resp.featureFlags) {
       const { featureFlags } = resp
 
-      checkFields(
-        [featureFlags],
-        ["gov", "oracle", "perp", "spot", "staking", "wasm"]
-      )
+      checkFields([featureFlags], ["gov", "oracle", "staking", "wasm"])
     }
   })
 
diff --git a/src/gql/utils/defaultObjects.ts b/src/gql/utils/defaultObjects.ts
index 09ec535d..e419516a 100644
--- a/src/gql/utils/defaultObjects.ts
+++ b/src/gql/utils/defaultObjects.ts
@@ -14,18 +14,10 @@ import {
   GQLInflationDistribution,
   GQLInflationInfo,
   GQLInflationRewards,
-  GQLMarkPriceCandle,
   GQLOracleEntry,
   GQLOraclePrice,
-  GQLPerpLeaderboard,
-  GQLPerpMarket,
-  GQLPerpPosition,
-  GQLPerpPositionChange,
   GQLProxies,
   GQLRedelegation,
-  GQLSpotLpPosition,
-  GQLSpotPool,
-  GQLSpotPoolSwap,
   GQLStakingActionType,
   GQLStakingHistoryItem,
   GQLToken,
@@ -82,68 +74,6 @@ export const defaultActor: GQLUser = {
 
 export const defaultUser = defaultActor
 
-export const defaultPerpMarket: GQLPerpMarket = {
-  base_reserve: 0,
-  ecosystem_fund_fee_ratio: 0,
-  max_funding_rate: 0,
-  enabled: true,
-  exchange_fee_ratio: 0,
-  funding_rate_epoch_id: "",
-  index_price_twap: 0,
-  is_deleted: false,
-  latest_cumulative_premium_fraction: 0,
-  liquidation_fee_ratio: 0,
-  maintenance_margin_ratio: 0,
-  mark_price: 0,
-  mark_price_twap: 0,
-  max_leverage: 0,
-  pair: "",
-  partial_liquidation_ratio: 0,
-  prepaid_bad_debt: defaultToken,
-  price_multiplier: 0,
-  quote_reserve: 0,
-  sqrt_depth: 0,
-  total_long: 0,
-  total_short: 0,
-  twap_lookback_window: "",
-}
-
-export const defaultPerpPosition: GQLPerpPosition = {
-  bad_debt: 0,
-  last_updated_block: defaultBlock,
-  latest_cumulative_premium_fraction: 0,
-  margin: 0,
-  margin_ratio: 0,
-  open_notional: 0,
-  pair: "",
-  liquidation_price: 0,
-  position_notional: 0,
-  size: 0,
-  trader_address: "",
-  unrealized_funding_payment: 0,
-  unrealized_pnl: 0,
-}
-
-export const defaultPool: GQLSpotPool = {
-  amplification: 0,
-  created_block: defaultBlock,
-  exit_fee: 0,
-  swap_fee: 0,
-  pool_id: 0,
-  tokens: [defaultToken],
-  pool_type: "",
-  total_shares: defaultToken,
-  total_weight: 0,
-  weights: [defaultToken],
-}
-
-export const defaultSpotPool = {
-  block: defaultBlock,
-  pool: defaultPool,
-  pool_shares: defaultToken,
-  user: defaultUser,
-}
-
 export const defaultGovProposal: GQLGovProposal = {
   depositEndTime: "",
   finalTallyResultAbstain: 0,
@@ -176,50 +106,6 @@ export const defaultGovVote: GQLGovVote = {
   sender: defaultUser,
 }
 
-export const defaultMarkPriceCandles: GQLMarkPriceCandle = {
-  close: 0,
-  high: 0,
-  low: 0,
-  open: 0,
-  volume: 0,
-  volumeNotional: 0,
-  pair: "",
-  period: 0,
-  periodInterval: "",
-  periodStartTs: "",
-  indexPriceTwapClose: 0,
-}
-
-export const defaultPerpPositionChanges: GQLPerpPositionChange = {
-  badDebt: defaultToken,
-  block: defaultBlock,
-  changeReason: "",
-  eventSeqNo: 0,
-  exchangedNotional: 0,
-  exchangedSize: 0,
-  fundingPayment: 0,
-  latestCumulativePremiumFraction: 0,
-  margin: 0,
-  marginToUser: 0,
-  openNotional: 0,
-  pair: "",
-  positionNotional: 0,
-  realizedPnl: 0,
-  size: 0,
-  traderAddress: "",
-  transactionFee: defaultToken,
-  txSeqNo: 0,
-}
-
-export const defaultPerpLeaderboard: GQLPerpLeaderboard = {
-  avg_pct_pnl_rank: 0,
-  avg_pct_pnl: 0,
-  input_margin: 0,
-  raw_pnl: 0,
-  raw_pnl_with_unrealized: 0,
-  trader_address: "",
-}
-
 export const defaultGovernance: GQLGovernance = {
   govDeposits: [defaultGovDeposit],
   govProposals: [defaultGovProposal],
@@ -227,7 +113,7 @@ export const defaultGovernance: GQLGovernance = {
 }
 
 export const defaultDistributionCommission: GQLDistributionCommission = {
-  commission: [defaultToken],
+  commission: defaultToken,
   validator: defaultValidator,
 }
 
@@ -246,21 +132,6 @@ export const defaultRedelegations: GQLRedelegation = {
   creation_block: defaultBlock,
 }
 
-export const defaultSpotLpPosition: GQLSpotLpPosition = {
-  created_block: defaultBlock,
-  pool: defaultPool,
-  pool_shares: defaultToken,
-  user: defaultUser,
-}
-
-export const defaultSpotPoolSwap: GQLSpotPoolSwap = {
-  block: defaultBlock,
-  pool: defaultPool,
-  token_in: defaultToken,
-  token_out: defaultToken,
-  user: defaultUser,
-}
-
 export const defaultUnbondings: GQLUnbonding = {
   amount: 0,
   completion_time: "",
@@ -342,8 +213,6 @@ export const defaultInflationInfo: GQLInflationInfo = {
 export const defaultFeatureFlags: GQLFeatureFlags = {
   gov: true,
   oracle: true,
-  perp: false,
-  spot: false,
   staking: true,
   wasm: true,
 }
diff --git a/src/sdk/msg/eth.test.ts b/src/sdk/msg/eth.test.ts
index 50271945..ae548c26 100644
--- a/src/sdk/msg/eth.test.ts
+++ b/src/sdk/msg/eth.test.ts
@@ -11,6 +11,12 @@ describe("setupEthMsgExtension", () => {
     UpdateParams: jest.fn().mockResolvedValue({
       test: "Test",
     }),
+    CreateFunToken: jest.fn().mockResolvedValue({
+      test: "Test",
+    }),
+    ConvertCoinToEvm: jest.fn().mockResolvedValue({
+      test: "Test",
+    }),
   } as unknown as query.MsgClientImpl)
 
   test("should setup extension correctly", () => {
@@ -54,30 +60,62 @@ describe("setupEthMsgExtension", () => {
       const result = await extension.updateParams({
         authority: "",
         params: {
-          evmDenom: "",
           createFuntokenFee: "",
-          enableCreate: true,
-          enableCall: true,
           extraEips: [new Long(0)],
-          allowUnprotectedTxs: true,
-          activePrecompiles: [""],
           evmChannels: [""],
         },
       })
       expect(msgUpdateParams).toHaveBeenCalledWith({
         authority: "",
         params: {
-          evmDenom: "",
           createFuntokenFee: "",
-          enableCreate: true,
-          enableCall: true,
           extraEips: [new Long(0)],
-          allowUnprotectedTxs: true,
-          activePrecompiles: [""],
           evmChannels: [""],
         },
       })
       expect(result).toEqual({ test: "Test" })
     })
   })
+
+  describe("createFunToken", () => {
+    test("should call MsgCreateFunToken and return the response", async () => {
+      const msgCreateFunToken = jest
+        .spyOn(query.MsgCreateFunToken, "fromPartial")
+        .mockReturnValue({} as query.MsgCreateFunToken)
+
+      const extension = setupEthMsgExtension(mockBaseQueryClient)
+      const result = await extension.createFunToken({
+        fromBankDenom: "",
+        fromErc20: "",
+        sender: "",
+      })
+      expect(msgCreateFunToken).toHaveBeenCalledWith({
+        fromBankDenom: "",
+        fromErc20: "",
+        sender: "",
+      })
+      expect(result).toEqual({ test: "Test" })
+    })
+  })
+
+  describe("convertCoinToEVM", () => {
+    test("should call MsgConvertCoinToEvm and return the response", async () => {
+      const msgConvertCoinToEvm = jest
+        .spyOn(query.MsgConvertCoinToEvm, "fromPartial")
+        .mockReturnValue({} as query.MsgConvertCoinToEvm)
+
+      const extension = setupEthMsgExtension(mockBaseQueryClient)
+      const result = await extension.convertCoinToEVM({
+        toEthAddr: "",
+        bankCoin: { denom: "", amount: "" },
+        sender: "",
+      })
+      expect(msgConvertCoinToEvm).toHaveBeenCalledWith({
+        toEthAddr: "",
+        bankCoin: { denom: "", amount: "" },
+        sender: "",
+      })
+      expect(result).toEqual({ test: "Test" })
+    })
+  })
 })
diff --git a/src/sdk/msg/eth.ts b/src/sdk/msg/eth.ts
index dce30c0c..d93db7bf 100644
--- a/src/sdk/msg/eth.ts
+++ b/src/sdk/msg/eth.ts
@@ -1,15 +1,41 @@
 import { createProtobufRpcClient, QueryClient } from "@cosmjs/stargate"
 import {
+  MsgServiceName,
   MsgClientImpl,
+  MsgConvertCoinToEvm,
+  MsgConvertCoinToEvmResponse,
+  MsgCreateFunToken,
+  MsgCreateFunTokenResponse,
   MsgEthereumTx,
   MsgEthereumTxResponse,
   MsgUpdateParams,
   MsgUpdateParamsResponse,
 } from "../../protojs/eth/evm/v1/tx"
+import { GeneratedType } from "@cosmjs/proto-signing"
+
+export const ETH_MSG_TYPE_URLS = {
+  MsgEthereumTx: `/${MsgServiceName}EthereumTx`,
+  MsgUpdateParams: `/${MsgServiceName}UpdateParams`,
+  MsgCreateFunToken: `/${MsgServiceName}CreateFunToken`,
+  MsgConvertCoinToEvm: `/${MsgServiceName}ConvertCoinToEvm`,
+}
+
+export const ethTypes: ReadonlyArray<[string, GeneratedType]> = [
+  [ETH_MSG_TYPE_URLS.MsgEthereumTx, MsgEthereumTx],
+  [ETH_MSG_TYPE_URLS.MsgUpdateParams, MsgUpdateParams],
+  [ETH_MSG_TYPE_URLS.MsgCreateFunToken, MsgCreateFunToken],
+  [ETH_MSG_TYPE_URLS.MsgConvertCoinToEvm, MsgConvertCoinToEvm],
+]
 
 export interface EthMsgExtension {
   ethereumTx: (body: MsgEthereumTx) => Promise<MsgEthereumTxResponse>
   updateParams: (body: MsgUpdateParams) => Promise<MsgUpdateParamsResponse>
+  createFunToken: (
+    body: MsgCreateFunToken
+  ) => Promise<MsgCreateFunTokenResponse>
+  convertCoinToEVM: (
+    body: MsgConvertCoinToEvm
+  ) => Promise<MsgConvertCoinToEvmResponse>
 }
 
 export const setupEthMsgExtension = (base: QueryClient): EthMsgExtension => {
@@ -20,5 +46,9 @@ export const setupEthMsgExtension = (base: QueryClient): EthMsgExtension => {
       queryService.EthereumTx(MsgEthereumTx.fromPartial(body)),
     updateParams: async (body: MsgUpdateParams) =>
       queryService.UpdateParams(MsgUpdateParams.fromPartial(body)),
+    createFunToken: async (body: MsgCreateFunToken) =>
+      queryService.CreateFunToken(MsgCreateFunToken.fromPartial(body)),
+    convertCoinToEVM: async (body: MsgConvertCoinToEvm) =>
+      queryService.ConvertCoinToEvm(MsgConvertCoinToEvm.fromPartial(body)),
   }
 }
diff --git a/src/sdk/msg/tokenfactory.ts b/src/sdk/msg/tokenfactory.ts
index 2b6c1d85..0028c274 100644
--- a/src/sdk/msg/tokenfactory.ts
+++ b/src/sdk/msg/tokenfactory.ts
@@ -1,5 +1,6 @@
 import { createProtobufRpcClient, QueryClient } from "@cosmjs/stargate"
 import {
+  MsgServiceName,
   MsgCreateDenom,
   MsgClientImpl,
   MsgCreateDenomResponse,
@@ -16,6 +17,27 @@ import {
   MsgBurnNative,
   MsgBurnNativeResponse,
 } from "../../protojs/nibiru/tokenfactory/v1/tx"
+import { GeneratedType } from "@cosmjs/proto-signing"
+
+export const TOKENFACTORY_MSG_TYPE_URLS = {
+  MsgCreateDenom: `/${MsgServiceName}CreateDenom`,
+  MsgChangeAdmin: `/${MsgServiceName}ChangeAdmin`,
+  MsgUpdateModuleParams: `/${MsgServiceName}UpdateModuleParams`,
+  MsgMint: `/${MsgServiceName}Mint`,
+  MsgBurn: `/${MsgServiceName}Burn`,
+  MsgSetDenomMetadata: `/${MsgServiceName}SetDenomMetadata`,
+  MsgBurnNative: `/${MsgServiceName}BurnNative`,
+}
+
+export const tokenfactoryTypes: ReadonlyArray<[string, GeneratedType]> = [
+  [TOKENFACTORY_MSG_TYPE_URLS.MsgCreateDenom, MsgCreateDenom],
+  [TOKENFACTORY_MSG_TYPE_URLS.MsgChangeAdmin, MsgChangeAdmin],
+  [TOKENFACTORY_MSG_TYPE_URLS.MsgUpdateModuleParams, MsgUpdateModuleParams],
+  [TOKENFACTORY_MSG_TYPE_URLS.MsgMint, MsgMint],
+  [TOKENFACTORY_MSG_TYPE_URLS.MsgBurn, MsgBurn],
+  [TOKENFACTORY_MSG_TYPE_URLS.MsgSetDenomMetadata, MsgSetDenomMetadata],
+  [TOKENFACTORY_MSG_TYPE_URLS.MsgBurnNative, MsgBurnNative],
+]
 
 export interface TokenFactoryMsgExtension {
   createDenom: (body: MsgCreateDenom) => Promise<MsgCreateDenomResponse>
@@ -57,3 +79,21 @@ export const setupTokenFactoryMsgExtension = (
       queryService.BurnNative(MsgBurnNative.fromPartial(body)),
   }
 }
+
+export {
+  MsgCreateDenom,
+  MsgClientImpl,
+  MsgCreateDenomResponse,
+  MsgChangeAdmin,
+  MsgChangeAdminResponse,
+  MsgUpdateModuleParams,
+  MsgUpdateModuleParamsResponse,
+  MsgBurn,
+  MsgBurnResponse,
+  MsgMint,
+  MsgMintResponse,
+  MsgSetDenomMetadata,
+  MsgSetDenomMetadataResponse,
+  MsgBurnNative,
+  MsgBurnNativeResponse,
+}
diff --git a/src/sdk/query/eth.test.ts b/src/sdk/query/eth.test.ts
index d7d40dd7..59faddb7 100644
--- a/src/sdk/query/eth.test.ts
+++ b/src/sdk/query/eth.test.ts
@@ -36,6 +36,9 @@ describe("setupEpochsExtension", () => {
     TraceBlock: jest.fn().mockResolvedValue({
       traceBlock: "Test",
     }),
+    TraceCall: jest.fn().mockResolvedValue({
+      traceCall: "Test",
+    }),
     BaseFee: jest.fn().mockResolvedValue({
       baseFee: "Test",
     }),
@@ -58,6 +61,7 @@ describe("setupEpochsExtension", () => {
     expect(extension.estimateGas).toBeInstanceOf(Function)
     expect(extension.traceTx).toBeInstanceOf(Function)
     expect(extension.traceBlock).toBeInstanceOf(Function)
+    expect(extension.traceCall).toBeInstanceOf(Function)
     expect(extension.baseFee).toBeInstanceOf(Function)
     expect(extension.funTokenMapping).toBeInstanceOf(Function)
   })
@@ -244,7 +248,6 @@ describe("setupEpochsExtension", () => {
           limit: 0,
           enableMemory: true,
           enableReturnData: true,
-          tracerJsonConfig: "",
         },
         predecessors: [MsgEthereumTx.fromPartial({})],
         blockNumber: new Long(0),
@@ -267,7 +270,6 @@ describe("setupEpochsExtension", () => {
           limit: 0,
           enableMemory: true,
           enableReturnData: true,
-          tracerJsonConfig: "",
         },
         predecessors: [MsgEthereumTx.fromPartial({})],
         blockNumber: new Long(0),
@@ -300,7 +302,6 @@ describe("setupEpochsExtension", () => {
           limit: 0,
           enableMemory: true,
           enableReturnData: true,
-          tracerJsonConfig: "",
         },
         blockNumber: new Long(0),
         blockHash: "",
@@ -321,7 +322,6 @@ describe("setupEpochsExtension", () => {
           limit: 0,
           enableMemory: true,
           enableReturnData: true,
-          tracerJsonConfig: "",
         },
         blockNumber: new Long(0),
         blockHash: "",
@@ -334,6 +334,59 @@ describe("setupEpochsExtension", () => {
     })
   })
 
+  describe("traceCall", () => {
+    test("should call QueryTraceTxRequest and return the response", async () => {
+      const queryTraceTxRequest = jest
+        .spyOn(query.QueryTraceTxRequest, "fromPartial")
+        .mockReturnValue({} as query.QueryTraceTxRequest)
+
+      const extension = setupEthExtension(mockBaseQueryClient)
+      const result = await extension.traceCall({
+        msg: {
+          data: { typeUrl: "", value: new Uint8Array() },
+          size: 0,
+          hash: "",
+          from: "",
+        },
+        predecessors: [
+          {
+            data: { typeUrl: "", value: new Uint8Array() },
+            size: 0,
+            hash: "",
+            from: "",
+          },
+        ],
+        blockHash: "",
+        blockMaxGas: new Long(0),
+        proposerAddress: new Uint8Array(),
+        blockNumber: new Long(0),
+        chainId: new Long(0),
+      })
+      expect(queryTraceTxRequest).toHaveBeenCalledWith({
+        msg: {
+          data: { typeUrl: "", value: new Uint8Array() },
+          size: 0,
+          hash: "",
+          from: "",
+        },
+        predecessors: [
+          {
+            data: { typeUrl: "", value: new Uint8Array() },
+            size: 0,
+            hash: "",
+            from: "",
+          },
+        ],
+        blockHash: "",
+        blockMaxGas: new Long(0),
+        proposerAddress: new Uint8Array(),
+        blockNumber: new Long(0),
+        chainId: new Long(0),
+      })
+      expect(result).toEqual({ traceCall: "Test" })
+    })
+  })
+
   describe("baseFee", () => {
     test("should call QueryBaseFeeRequest and return the response", async () => {
       const queryBaseFeeRequest = jest
diff --git a/src/sdk/query/eth.ts b/src/sdk/query/eth.ts
index 262b8a8c..934560b0 100644
--- a/src/sdk/query/eth.ts
+++ b/src/sdk/query/eth.ts
@@ -39,6 +39,7 @@ export interface EthExtension {
   estimateGas: (args: EthCallRequest) => Promise<EstimateGasResponse>
   traceTx: (args: QueryTraceTxRequest) => Promise<QueryTraceTxResponse>
   traceBlock: (args: QueryTraceBlockRequest) => Promise<QueryTraceBlockResponse>
+  traceCall: (args: QueryTraceTxRequest) => Promise<QueryTraceTxResponse>
   baseFee: (args: QueryBaseFeeRequest) => Promise<QueryBaseFeeResponse>
   funTokenMapping: (
     request: QueryFunTokenMappingRequest
@@ -81,6 +82,9 @@ export const setupEthExtension = (base: QueryClient): EthExtension => {
     traceBlock: async (args: QueryTraceBlockRequest) =>
       queryService.TraceBlock(QueryTraceBlockRequest.fromPartial(args)),
 
+    traceCall: async (args: QueryTraceTxRequest) =>
+      queryService.TraceCall(QueryTraceTxRequest.fromPartial(args)),
+
     baseFee: async (args: QueryBaseFeeRequest) =>
       queryService.BaseFee(QueryBaseFeeRequest.fromPartial(args)),
 
diff --git a/src/sdk/tx/txClient.ts b/src/sdk/tx/txClient.ts
index 1f1c10fd..4c1ddec8 100644
--- a/src/sdk/tx/txClient.ts
+++ b/src/sdk/tx/txClient.ts
@@ -13,7 +13,12 @@ import {
 } from "@cosmjs/stargate"
 import { Tendermint37Client } from "@cosmjs/tendermint-rpc"
 import { setupWasmExtension } from "@cosmjs/cosmwasm-stargate"
-import { NibiruExtensions, setupNibiruExtension } from ".."
+import {
+  ethTypes,
+  NibiruExtensions,
+  setupNibiruExtension,
+  tokenfactoryTypes,
+} from ".."
 import { accountFromNibiru } from "./account"
 import {
   NibiSigningCosmWasmClient,
@@ -22,6 +27,8 @@ import {
 
 export const nibiruRegistryTypes: ReadonlyArray<[string, GeneratedType]> = [
   ...defaultRegistryTypes,
+  ...tokenfactoryTypes,
+  ...ethTypes,
 ]
 
 export class NibiruTxClient extends SigningStargateClient {
diff --git a/yarn.lock b/yarn.lock
index bfd407e7..12f6bb98 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4802,10 +4802,15 @@ graphql-ws@^5.14.0:
   resolved "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.14.0.tgz"
   integrity sha512-itrUTQZP/TgswR4GSSYuwWUzrE/w5GhbwM2GX3ic2U7aw33jgEsayfIlvaj7/GcIvZgNMzsPTrE5hqPuFUiE5g==
 
-graphql@^16.7.1:
-  version "16.8.0"
-  resolved "https://registry.npmjs.org/graphql/-/graphql-16.8.0.tgz"
-  integrity sha512-0oKGaR+y3qcS5mCu1vb7KG+a89vjn06C7Ihq/dDl3jA+A8B3TKomvi3CiEcVLJQGalbu8F52LxkOym7U5sSfbg==
+graphql-ws@^5.16.0:
+  version "5.16.0"
+  resolved "https://registry.yarnpkg.com/graphql-ws/-/graphql-ws-5.16.0.tgz#849efe02f384b4332109329be01d74c345842729"
+  integrity sha512-Ju2RCU2dQMgSKtArPbEtsK5gNLnsQyTNIo/T7cZNp96niC1x0KdJNZV0TIoilceBPQwfb5itrGl8pkFeOUMl4A==
+
+graphql@^16.9.0:
+  version "16.9.0"
+  resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.9.0.tgz#1c310e63f16a49ce1fbb230bd0a000e99f6f115f"
+  integrity sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==
 
 handlebars@^4.7.7:
   version "4.7.8"