diff --git a/components/collection/CollectionSwaps.vue b/components/collection/CollectionTrades.vue
similarity index 92%
rename from components/collection/CollectionSwaps.vue
rename to components/collection/CollectionTrades.vue
index 8a96140457..be9de7d98c 100644
--- a/components/collection/CollectionSwaps.vue
+++ b/components/collection/CollectionTrades.vue
@@ -19,8 +19,11 @@
 
 <script setup lang="ts">
 import { type TradeTableQuery } from '@/components/trade/TradeActivityTable.vue'
+import type { TradeType } from '@/components/trade/types'
 
-const tradeType = TradeType.SWAP
+defineProps<{
+  tradeType: TradeType
+}>()
 
 const route = useRoute()
 
diff --git a/components/common/BaseCartItemDetailsSkeleton.vue b/components/common/BaseCartItemDetailsSkeleton.vue
new file mode 100644
index 0000000000..6556cce639
--- /dev/null
+++ b/components/common/BaseCartItemDetailsSkeleton.vue
@@ -0,0 +1,42 @@
+<template>
+  <div class="w-full h-[50px]">
+    <div class="flex justify-between">
+      <div class="flex">
+        <div>
+          <NeoSkeleton
+            no-margin
+            height="48px"
+            width="48px"
+            :rounded="false"
+          />
+        </div>
+
+        <div class="flex flex-col justify-between ml-4 w-[100px] md:w-[170px]">
+          <NeoSkeleton
+            no-margin
+            :rounded="false"
+            width="130px"
+          />
+
+          <NeoSkeleton
+            no-margin
+            :rounded="false"
+            width="90px"
+          />
+        </div>
+      </div>
+
+      <div class="flex items-end">
+        <NeoSkeleton
+          no-margin
+          :rounded="false"
+          width="60px"
+        />
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { NeoSkeleton } from '@kodadot1/brick'
+</script>
diff --git a/components/common/ConnectWallet/WalletAsset.vue b/components/common/ConnectWallet/WalletAsset.vue
index 313637d2c7..38db7d6649 100644
--- a/components/common/ConnectWallet/WalletAsset.vue
+++ b/components/common/ConnectWallet/WalletAsset.vue
@@ -7,7 +7,10 @@
       <MultipleBalances />
     </div>
 
-    <WalletAssetMenu />
+    <div class="h-full flex flex-col justify-end gap-5">
+      <WalletAssetTrades v-if="tradeVisible(urlPrefix) && vm === walletVm" />
+      <WalletAssetMenu />
+    </div>
   </div>
 </template>
 
@@ -15,7 +18,9 @@
 import WalletAssetIdentity from './WalletAssetIdentity.vue'
 import WalletAssetNfts from './WalletAssetNfts.vue'
 import WalletAssetMenu from './WalletAssetMenu.vue'
+import WalletAssetTrades from './WalletAssetTrades.vue'
 import { useIdentityStore } from '@/stores/identity'
+import { tradeVisible } from '@/utils/config/permission.config'
 
 const MultipleBalances = defineAsyncComponent(
   () => import('@/components/balance/MultipleBalances.vue'),
@@ -23,6 +28,9 @@ const MultipleBalances = defineAsyncComponent(
 
 const identityStore = useIdentityStore()
 const { $consola } = useNuxtApp()
+const { urlPrefix } = usePrefix()
+const { vm } = useChain()
+const { getWalletVM: walletVm } = storeToRefs(useWalletStore())
 
 if (identityStore.getAuthAddress) {
   $consola.log('fetching balance...')
diff --git a/components/common/ConnectWallet/WalletAssetMenu.vue b/components/common/ConnectWallet/WalletAssetMenu.vue
index 29e5911e08..3501cf5a4e 100644
--- a/components/common/ConnectWallet/WalletAssetMenu.vue
+++ b/components/common/ConnectWallet/WalletAssetMenu.vue
@@ -1,79 +1,77 @@
 <template>
-  <div class="h-full flex flex-col justify-end">
-    <div
-      :class="{ 'border-t': filteredMenus.length }"
-      class="wallet-asset-container flex flex-col"
-      data-testid="sidebar-wallet-container"
-    >
-      <div>
-        <a
-          v-for="menu in filteredMenus"
-          :key="menu.label"
-          v-safe-href="menu.to"
-          class="wallet-asset-menu"
-        >
-          <span>{{ menu.label }}</span>
-          <NeoIcon
-            icon="angle-right"
-            size="medium"
-            class="text-k-grey"
-          />
-        </a>
-      </div>
-      <div class="wallet-asset-footer flex py-5 text-xs text-k-grey">
-        <!-- light/dark mode -->
-        <ColorModeSwitch />
-
-        <!-- language -->
-        <div
-          data-testid="sidebar-language"
-          class="language-selector"
+  <div
+    :class="{ 'border-t': filteredMenus.length }"
+    class="wallet-asset-container flex flex-col"
+    data-testid="sidebar-wallet-container"
+  >
+    <div>
+      <a
+        v-for="menu in filteredMenus"
+        :key="menu.label"
+        v-safe-href="menu.to"
+        class="wallet-asset-menu"
+      >
+        <span>{{ menu.label }}</span>
+        <NeoIcon
+          icon="angle-right"
+          size="medium"
+          class="text-k-grey"
+        />
+      </a>
+    </div>
+    <div class="wallet-asset-footer flex py-5 text-xs text-k-grey">
+      <!-- light/dark mode -->
+      <ColorModeSwitch />
+
+      <!-- language -->
+      <div
+        data-testid="sidebar-language"
+        class="language-selector"
+      >
+        <NeoDropdown
+          position="top-left"
+          aria-role="menu"
+          mobile-modal
         >
-          <NeoDropdown
-            position="top-left"
-            aria-role="menu"
-            mobile-modal
+          <template #trigger>
+            <div class="flex items-center">
+              <NeoIcon
+                icon="globe"
+                size="medium"
+              />
+              <span class="is-hidden-mobile ml-1">
+                {{ $t('profileMenu.language') }}
+              </span>
+            </div>
+          </template>
+
+          <NeoDropdownItem
+            v-for="lang in langsFlags"
+            :key="lang.value"
+            aria-role="listitem"
+            :data-testid="`sidebar-language-${lang.value}`"
+            :value="lang.value"
+            :class="{ 'is-active': $i18n.locale === lang.value }"
+            @click="usePreferencesStore().setUserLocale(lang.value)"
           >
-            <template #trigger>
-              <div class="flex items-center">
-                <NeoIcon
-                  icon="globe"
-                  size="medium"
-                />
-                <span class="is-hidden-mobile ml-1">
-                  {{ $t('profileMenu.language') }}
-                </span>
-              </div>
-            </template>
-
-            <NeoDropdownItem
-              v-for="lang in langsFlags"
-              :key="lang.value"
-              aria-role="listitem"
-              :data-testid="`sidebar-language-${lang.value}`"
-              :value="lang.value"
-              :class="{ 'is-active': $i18n.locale === lang.value }"
-              @click="usePreferencesStore().setUserLocale(lang.value)"
-            >
-              <span>{{ lang.flag }} {{ lang.label }}</span>
-            </NeoDropdownItem>
-          </NeoDropdown>
-        </div>
-
-        <!-- settings -->
-        <nuxt-link
-          to="/settings"
-          class="text-k-grey items-center"
-          data-testid="sidebar-link-settings"
-          @click="closeModal"
-        >
-          <NeoIcon
-            icon="gear"
-            size="medium"
-          />
-          <span class="is-hidden-mobile">{{ $t('settings') }}</span>
-        </nuxt-link>
+            <span>{{ lang.flag }} {{ lang.label }}</span>
+          </NeoDropdownItem>
+        </NeoDropdown>
       </div>
+
+      <!-- settings -->
+      <nuxt-link
+        to="/settings"
+        class="text-k-grey items-center"
+        data-testid="sidebar-link-settings"
+        @click="closeModal"
+      >
+        <NeoIcon
+          icon="gear"
+          size="medium"
+        />
+        <span class="is-hidden-mobile">{{ $t('settings') }}</span>
+      </nuxt-link>
     </div>
   </div>
 </template>
@@ -99,7 +97,7 @@ const menus = ref<{ label: string, to: string, check: (v: Prefix) => boolean }[]
     check: teleportVisible,
   },
   {
-    label: $i18n.t('swap.swap'),
+    label: $i18n.t('swap.createSwap'),
     to: `/${urlPrefix.value}/swap`,
     check: swapVisible,
   },
diff --git a/components/common/ConnectWallet/WalletAssetTrades.vue b/components/common/ConnectWallet/WalletAssetTrades.vue
new file mode 100644
index 0000000000..d09e6850e9
--- /dev/null
+++ b/components/common/ConnectWallet/WalletAssetTrades.vue
@@ -0,0 +1,213 @@
+<template>
+  <div class="wallet-asset-container">
+    <div
+      v-if="loading"
+      class="flex flex-col gap-4"
+    >
+      <NeoSkeleton
+        no-margin
+        height="123px"
+      />
+
+      <div class="flex items-center justify-between">
+        <NeoSkeleton
+          no-margin
+          width="60px"
+          class="!w-[60px]"
+          height="14px"
+        />
+        <NeoSkeleton
+          no-margin
+          class="!w-[99px]"
+          width="99px"
+          border-radius="10px"
+          height="24px"
+        />
+      </div>
+    </div>
+    <div
+      v-else-if="trades.length"
+      class="flex flex-col gap-4"
+    >
+      <div
+        class="border border-border-color rounded-lg !p-4 w-full"
+      >
+        <div class="flex justify-between items-center">
+          <p class="capitalize">
+            {{ $t('trades.incomingTrades') }}
+          </p>
+
+          <NeoButton
+            variant="icon"
+            @click="refetch"
+          >
+            <NeoIcon
+              icon="refresh"
+            />
+          </NeoButton>
+        </div>
+
+        <hr class="my-3">
+
+        <div class="flex flex-col gap-2">
+          <ul>
+            <li
+              v-for="trade in trades.slice(0, 2)"
+              :key="trade.id"
+              class="flex items-center justify-between"
+            >
+              <div class="flex items-center gap-2 max-w-[calc(100%-25px)]">
+                <NeoIcon
+                  class="text-k-grey opacity-20 !text-[0.4rem]"
+                  icon="circle"
+                  pack="fass"
+                  size="small"
+                />
+                <div class="flex items-center gap-2 text-sm truncate">
+                  <nuxt-link
+                    v-if="trade.type === TradeType.SWAP"
+                    :to="`${urlPrefix}/gallery/${trade.offered.id}`"
+                  >
+                    <span>
+                      {{ trade.offered.name }}
+                    </span>
+                  </nuxt-link>
+                  <Money
+                    v-else
+                    :value="trade.price"
+                    inline
+                  />
+
+                  <span class="text-k-grey capitalize">
+                    {{ $t('for') }}
+                  </span>
+
+                  <nuxt-link
+                    v-if="trade.desired"
+                    :to="`${urlPrefix}/gallery/${trade.desired.id}`"
+                  >
+                    <span>
+                      {{ trade.desired.name }}
+                    </span>
+                  </nuxt-link>
+                  <nuxt-link
+                    v-else
+                    :to="`${urlPrefix}/collection/${trade.considered.id}`"
+                  >
+                    <span>
+                      {{ trade.considered.name }}
+                    </span>
+                  </nuxt-link>
+                </div>
+              </div>
+              <span class="text-k-grey text-sm">
+                {{ formatDistanceToNow(trade.createdAt) }}
+              </span>
+            </li>
+          </ul>
+        </div>
+      </div>
+
+      <div class="flex items-center justify-between">
+        <div class="text-sm flex gap-2">
+          <span class="text-k-grey">
+            {{ $t('count') }}:
+          </span>
+          <span> {{ trades.length }} </span>
+        </div>
+
+        <NeoButton
+          variant="pill"
+          size="small"
+          class="px-4 py-1"
+          icon="arrow-right"
+          @click="viewAll"
+        >
+          {{ $t('helper.viewAll') }}
+        </NeoButton>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { NeoIcon, NeoButton, NeoSkeleton } from '@kodadot1/brick'
+import { TradeType, type TradeNftItem } from '@/components/trade/types'
+import { TRADE_TYPE_TO_PROFILE_TAB_MAP } from '@/components/profile/utils'
+import { formatDistanceToNow } from '@/utils/datetime'
+
+const tradeTypes = [
+  TradeType.OFFER,
+  TradeType.SWAP,
+]
+
+const trades = ref<TradeNftItem[]>([])
+const loadings = ref<boolean[]>([])
+const refetches = ref<ReturnType<typeof useTrades>['refetch'][]>([])
+
+const { accountId } = useAuth()
+const { urlPrefix } = usePrefix()
+const { data: ownedCollections, isFetching, isPending } = useOwnedCollections(accountId)
+
+const loadingOwnedCollections = computed(() => isPending.value || isFetching.value)
+const disabledTrades = computed(() => loadingOwnedCollections.value)
+const where = computed(() => buildIncomingTradesQuery(accountId.value, ownedCollections.value?.map(({ id }) => id) || []))
+const loading = computed(() => loadings.value.some(Boolean) || loadingOwnedCollections.value)
+
+const clear = () => {
+  loadings.value = new Array(tradeTypes.length).fill(true)
+  trades.value = []
+}
+
+const refetch = async () => {
+  clear()
+  await Promise.all(refetches.value.map(refetch => refetch()))
+}
+
+const getTradeTypeWithMoreIncomingTrades = (): TradeType | null => {
+  const groups = Object.groupBy(trades.value, item => item.type)
+
+  const swapLength = groups[TradeType.SWAP]?.length || 0
+  const offerLength = groups[TradeType.OFFER]?.length || 0
+
+  if (swapLength == offerLength) {
+    return null
+  }
+
+  return (swapLength > offerLength)
+    ? TradeType.SWAP
+    : TradeType.OFFER
+}
+
+const viewAll = () => {
+  const tab = TRADE_TYPE_TO_PROFILE_TAB_MAP[getTradeTypeWithMoreIncomingTrades() || trades.value[0].type]
+
+  navigateTo(`/${urlPrefix.value}/u/${accountId.value}?tab=${tab}&filter=incoming`)
+}
+
+const init = () => {
+  clear()
+
+  tradeTypes.forEach((tradeType, index) => {
+    const { items, loading: tradeLoading, refetch } = useTrades({
+      where: where,
+      disabled: disabledTrades,
+      type: tradeType,
+      minimal: true,
+    })
+
+    refetches.value[index] = refetch
+
+    watch([tradeLoading, items], ([isLoading, items]) => {
+      if (!isLoading) {
+        trades.value = [...trades.value, ...items]
+          .filter((trade, index, self) => index === self.findIndex(t => t.id === trade.id))
+          .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime())
+        loadings.value[index] = false
+      }
+    }, { immediate: true })
+  })
+}
+
+onBeforeMount(init)
+</script>
diff --git a/components/common/SearchInput.vue b/components/common/SearchInput.vue
new file mode 100644
index 0000000000..6795eaa7c2
--- /dev/null
+++ b/components/common/SearchInput.vue
@@ -0,0 +1,73 @@
+<template>
+  <div>
+    <NeoAutocomplete
+      v-model="search"
+      :data="data"
+      root-class="neo-input"
+      debounce-typing="300"
+      open-on-focus
+      clearable
+      item-class="hover:!bg-k-accent-light"
+      :placeholder="placeholder"
+      @typing="onSearchFn"
+      @select="onSelect"
+    >
+      <template
+        v-if="loading"
+        #header
+      >
+        <div class="!text-k-grey">
+          {{ $t('loading') }}...
+        </div>
+      </template>
+      <template
+        v-else-if="!data?.length"
+        #empty
+      >
+        <div class="!text-k-grey">
+          {{ $t('general.searchNoResults') }}
+        </div>
+      </template>
+      <template
+        v-else
+        #default="{ option }"
+      >
+        <slot :item="option" />
+      </template>
+    </NeoAutocomplete>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { NeoAutocomplete } from '@kodadot1/brick'
+
+const emit = defineEmits(['select'])
+const props = defineProps<{
+  placeholder?: string
+  onSearch: (search: string) => Promise<any[]>
+}>()
+
+const search = ref('')
+const loading = ref(false)
+const items = ref()
+const data = computed(() => loading.value ? [] : items.value)
+
+const onSearchFn = async () => {
+  loading.value = true
+  const response = await props.onSearch(search.value)
+  items.value = response
+  loading.value = false
+}
+
+const onSelect = (selected) => {
+  emit('select', selected)
+}
+
+onBeforeMount(onSearchFn)
+</script>
+
+<style lang="scss" scoped>
+.search-input {
+  @apply w-full;
+}
+</style>
diff --git a/components/explore/tab/TabOnCollection.vue b/components/explore/tab/TabOnCollection.vue
index ecdf0e1a0b..a9737bfa25 100644
--- a/components/explore/tab/TabOnCollection.vue
+++ b/components/explore/tab/TabOnCollection.vue
@@ -12,11 +12,15 @@
       :to="`${collectionRute}/activity`"
       data-testid="collection-tab-activity"
     />
+    <TabItem
+      :active="route.name === 'prefix-collection-id-offers'"
+      :text="`${$t('offers')}`"
+      :to="`${collectionRute}/offers`"
+    />
     <TabItem
       :active="route.name === 'prefix-collection-id-swaps'"
       :text="`${$t('swaps')}`"
       :to="`${collectionRute}/swaps`"
-      data-testid="collection-tab-swaps"
     />
   </div>
 </template>
diff --git a/components/gallery/GalleryItemTabsPanel/GalleryItemOffers.vue b/components/gallery/GalleryItemTabsPanel/GalleryItemOffers.vue
index 50c0d61e96..6bb0fe60ac 100644
--- a/components/gallery/GalleryItemTabsPanel/GalleryItemOffers.vue
+++ b/components/gallery/GalleryItemTabsPanel/GalleryItemOffers.vue
@@ -9,7 +9,7 @@
 
 <script setup lang="ts">
 import GalleryItemTradesTable from './GalleryItemTradesTable.vue'
-import { TradeType } from '@/composables/useTrades'
+import { TradeType } from '@/components/trade/types'
 
 defineProps<{
   nftId: string
diff --git a/components/gallery/GalleryItemTabsPanel/GalleryItemSwaps.vue b/components/gallery/GalleryItemTabsPanel/GalleryItemSwaps.vue
index a22cff1fc5..28ec2a87d1 100644
--- a/components/gallery/GalleryItemTabsPanel/GalleryItemSwaps.vue
+++ b/components/gallery/GalleryItemTabsPanel/GalleryItemSwaps.vue
@@ -9,7 +9,7 @@
 
 <script setup lang="ts">
 import GalleryItemTradesTable from './GalleryItemTradesTable.vue'
-import { TradeType } from '@/composables/useTrades'
+import { TradeType } from '@/components/trade/types'
 
 defineProps<{
   nftId: string
diff --git a/components/gallery/GalleryItemTabsPanel/GalleryItemTradesTable.vue b/components/gallery/GalleryItemTabsPanel/GalleryItemTradesTable.vue
index bdd7466268..84379a8a2b 100644
--- a/components/gallery/GalleryItemTabsPanel/GalleryItemTradesTable.vue
+++ b/components/gallery/GalleryItemTabsPanel/GalleryItemTradesTable.vue
@@ -14,8 +14,8 @@
       />
     </div>
     <NeoTable
-      v-else-if="offers.length"
-      :data="offers"
+      v-else-if="trades.length"
+      :data="trades"
       hoverable
       class="py-5 max-md:!top-0"
     >
@@ -113,7 +113,7 @@
         <TradeOwnerButton
           class="max-md:!w-full"
           :trade="row as TradeNftItem"
-          @click="selectOffer"
+          @click:main="selectOffer"
         />
       </NeoTableColumn>
     </NeoTable>
@@ -126,9 +126,9 @@
   </div>
 
   <TradeOverviewModal
-    v-model="isWithdrawTradeModalOpen"
+    v-model="isTradeModalOpen"
     :trade="selectedTrade!"
-    @close="closeTradeOverviewModal"
+    @close="closeTradeModal"
   />
 </template>
 
@@ -138,8 +138,7 @@ import {
   NeoTable,
   NeoTableColumn,
 } from '@kodadot1/brick'
-import type { UnwrapRef } from 'vue'
-import { TradeType } from '@/composables/useTrades'
+import { type TradeNftItem, TradeType } from '@/components/trade/types'
 import { formatToNow } from '@/utils/format/time'
 import Identity from '@/components/identity/IdentityIndex.vue'
 import useSubscriptionGraphql from '@/composables/useSubscriptionGraphql'
@@ -153,11 +152,15 @@ const props = defineProps<{
 const { urlPrefix } = usePrefix()
 const { format } = useFormatAmount()
 
-const isWithdrawTradeModalOpen = ref(false)
-const loading = ref(false)
-const offers = ref<UnwrapRef<ReturnType<typeof useTrades>['items']>>([])
+const isTradeModalOpen = ref(false)
 const selectedTrade = ref<TradeNftItem>()
-const stopWatch = ref(() => {})
+const tradeIds = ref()
+
+const { items: trades, loading } = useTrades({
+  where: computed(() => ({ id_in: tradeIds.value })),
+  disabled: computed(() => !Array.isArray(tradeIds.value)),
+  type: props.type,
+})
 
 useSubscriptionGraphql({
   query: `
@@ -168,28 +171,17 @@ useSubscriptionGraphql({
     id
   }`,
   onChange: ({ data }) => {
-    stopWatch.value?.()
-    offers.value = []
-
-    const { items: offersData, loading: offersLoading } = useTrades({
-      where: { id_in: data.items?.map(offer => offer.id) },
-      type: props.type,
-    })
-
-    stopWatch.value = watchEffect(() => {
-      loading.value = offersLoading.value
-      offers.value = offersData.value
-    })
+    tradeIds.value = data.items?.map(trade => trade.id)
   },
 })
 
 const selectOffer = (offer: TradeNftItem) => {
   selectedTrade.value = offer
-  isWithdrawTradeModalOpen.value = true
+  isTradeModalOpen.value = true
 }
 
-const closeTradeOverviewModal = () => {
-  isWithdrawTradeModalOpen.value = false
+const closeTradeModal = () => {
+  isTradeModalOpen.value = false
   selectedTrade.value = undefined
 }
 </script>
diff --git a/components/profile/ProfileDetail.vue b/components/profile/ProfileDetail.vue
index 93cd5043ee..ad2d062991 100644
--- a/components/profile/ProfileDetail.vue
+++ b/components/profile/ProfileDetail.vue
@@ -433,7 +433,7 @@
         />
 
         <TradeActivityTable
-          v-if="[ProfileTab.SWAPS, ProfileTab.OFFERS].includes(activeTab)"
+          v-if="[ProfileTab.SWAPS, ProfileTab.OFFERS].includes(activeTab) && tradeQuery"
           :key="activeTab"
           :query="tradeQuery"
           :type="{
@@ -481,7 +481,7 @@ import { openProfileCreateModal } from '@/components/profile/create/openProfileM
 import { getHigherResolutionCloudflareImage } from '@/utils/ipfs'
 import { offerVisible, swapVisible } from '@/utils/config/permission.config'
 import { type TradeTableQuery } from '@/components/trade/TradeActivityTable.vue'
-import { TradeType } from '@/composables/useTrades'
+import { TradeType } from '@/components/trade/types'
 import { doAfterCheckCurrentChainVM } from '@/components/common/ConnectWallet/openReconnectWalletModal'
 
 const NuxtImg = resolveComponent('NuxtImg')
@@ -523,9 +523,11 @@ const { isSub } = useIsChain(urlPrefix)
 const listingCartStore = useListingCartStore()
 const { vm } = useChain()
 const { params } = useRoute()
-
+const id = computed(() => route.params.id.toString() || '')
 const { hasProfile, userProfile, isFetchingProfile } = useProfile(computed(() => params?.id as string))
 
+const { data: ownedCollections } = useOwnedCollections(id)
+
 const { data: followers, refresh: refreshFollowers } = useAsyncData(
   `followersof${route.params.id}`,
   () =>
@@ -547,10 +549,14 @@ const refresh = ({ fetchFollowing = true } = {}) => {
 const followersCount = computed(() => followers.value?.totalCount ?? 0)
 const followingCount = computed(() => following.value?.totalCount ?? 0)
 
-const tradeQuery = computed<TradeTableQuery>(() => ({
-  incoming: `{ status_eq: ACTIVE, desired: { currentOwner_eq: "${id.value}" } }`,
-  outgoing: `{ status_in: [ACTIVE, EXPIRED], caller_eq: "${id.value}" }`,
-}))
+const tradeQuery = computed<TradeTableQuery | null>(() => {
+  return ownedCollections.value
+    ? {
+        incoming: `${buildIncomingTradesQuery(id.value, ownedCollections.value.map(({ id }) => id), { stringify: true })}`,
+        outgoing: `{ status_in: [ACTIVE, EXPIRED], caller_eq: "${id.value}" }`,
+      }
+    : null
+})
 
 const editProfileConfig: ButtonConfig = {
   label: $i18n.t('profile.editProfile'),
@@ -574,7 +580,6 @@ const followButton = ref()
 const counts = ref({})
 const hasAssetPrefixMap = ref<Partial<Record<ProfileTab, Prefix[]>>>({})
 const loadingOtherNetwork = ref(false)
-const id = computed(() => route.params.id.toString() || '')
 const email = ref('')
 const twitter = ref('')
 const displayName = ref('')
diff --git a/components/profile/utils.ts b/components/profile/utils.ts
index 4c1f95b847..0362898b3a 100644
--- a/components/profile/utils.ts
+++ b/components/profile/utils.ts
@@ -1,3 +1,6 @@
+import { ProfileTab } from './types'
+import { TradeType } from '@/components/trade/types'
+
 type LinkableBlock = {
   id: string
   regex: RegExp
@@ -37,3 +40,8 @@ export const getBioWithLinks = (text: string): string => {
     .map(processSegment)
     .join('')
 }
+
+export const TRADE_TYPE_TO_PROFILE_TAB_MAP: Record<TradeType, ProfileTab> = {
+  [TradeType.OFFER]: ProfileTab.OFFERS,
+  [TradeType.SWAP]: ProfileTab.SWAPS,
+}
diff --git a/components/shared/filters/Filters.vue b/components/shared/filters/Filters.vue
index 6b2520fa64..c7f3391c82 100644
--- a/components/shared/filters/Filters.vue
+++ b/components/shared/filters/Filters.vue
@@ -34,7 +34,7 @@
   />
 
   <TradeFilter
-    v-if="isCollectionSwaps"
+    v-if="isCollectionTrades"
     expanded
     fluid-padding
   />
@@ -52,7 +52,7 @@ const route = useRoute()
 
 const isCollectionItems = computed(() => route.name === 'prefix-collection-id')
 const isCollectionActivity = computed(() => route.name === 'prefix-collection-id-activity')
-const isCollectionSwaps = computed(() => route.name === 'prefix-collection-id-swaps')
+const isCollectionTrades = computed(() => ['prefix-collection-id-swaps', 'prefix-collection-id-offers'].includes(route.name))
 const isExploreItems = computed(() => route.name === 'prefix-explore-items')
 const isPageWithItems = computed(() => isExploreItems.value || isCollectionItems.value)
 </script>
diff --git a/components/shared/filters/modules/TradeFilter.vue b/components/shared/filters/modules/TradeFilter.vue
index 5bcf35a439..1ebc0be6f7 100644
--- a/components/shared/filters/modules/TradeFilter.vue
+++ b/components/shared/filters/modules/TradeFilter.vue
@@ -1,6 +1,6 @@
 <template>
   <SiderbarFilterSection
-    :title="$t('filters.tradeType', [$t('swap.swap')])"
+    :title="$t('filters.tradeType', [tradeName])"
     :expanded="expanded"
     :fluid-padding="fluidPadding"
   >
@@ -9,7 +9,7 @@
         v-model="entire_collection"
         data-testid="filter-checkbox-buynow"
       >
-        {{ $t('filters.tradeCollection', [$t('swaps')]) }}
+        {{ $t('filters.tradeCollection', [tradeName]) }}
       </NeoCheckbox>
     </NeoField>
   </SiderbarFilterSection>
@@ -31,9 +31,12 @@ withDefaults(
 )
 
 const route = useRoute()
+const { $i18n } = useNuxtApp()
 
 const { replaceUrl: replaceURL } = useReplaceUrl()
 
+const tradeName = computed(() => route.name === 'prefix-collection-id-swaps' ? $i18n.t('swaps') : $i18n.t('offers'))
+
 const entire_collection = computed({
   get: () => route.query?.trade_collection?.toString() === 'true',
   set: value => applyToUrl({ trade_collection: String(value) }),
diff --git a/components/swap/landing.vue b/components/swap/landing.vue
index 28a0f7ded4..607397a367 100644
--- a/components/swap/landing.vue
+++ b/components/swap/landing.vue
@@ -34,40 +34,88 @@
         </p>
       </div>
 
-      <form @submit.prevent="handleSubmit">
-        <AddressInput
-          v-model="traderAddress"
-          :is-invalid="isYourAddress"
-          :icon-right="!isTraderAddressValid || isYourAddress ? 'close' : undefined"
-          placeholder="Enter wallet address"
-          with-address-check
-          @check="handleAddressCheck"
-        />
-
-        <NeoButton
-          type="submit"
-          :label="label"
-          size="large"
-          class="text-base my-5 capitalize"
-          expanded
-          :disabled="disabled"
-          native-type="submit"
-          variant="primary"
-        />
-      </form>
+      <div class="flex flex-col gap-7">
+        <form @submit.prevent="handleSubmit">
+          <AddressInput
+            v-model="traderAddress"
+            :is-invalid="isYourAddress"
+            :icon-right="!isTraderAddressValid || isYourAddress ? 'close' : undefined"
+            placeholder="Enter wallet address"
+            with-address-check
+            @check="handleAddressCheck"
+          />
+
+          <NeoButton
+            type="submit"
+            :label="label"
+            size="large"
+            class="text-base mt-5 capitalize"
+            :class="{
+              'mb-5': !showIncomingTrades,
+            }"
+            expanded
+            :disabled="disabled"
+            native-type="submit"
+            variant="primary"
+          />
+        </form>
+
+        <div
+          v-if="showIncomingTrades"
+          class="flex justify-center"
+        >
+          <NeoSkeleton
+            v-if="isLoadingIncomingTrades"
+            no-margin
+            class="!w-[226px]"
+            width="226px"
+            border-radius="20px"
+            height="40px"
+          />
+
+          <NeoButton
+            v-else
+            :tag="NuxtLink"
+            :to="`/${urlPrefix}/u/${accountId}?tab=swaps`"
+            variant="outlined-rounded"
+          >
+            {{ $t('swap.yourSwapOffers') }}
+
+            <span class="text-k-grey">
+              ({{ swapOffersCount }})
+            </span>
+
+            <NeoIcon
+              class="ml-2"
+              icon="arrow-right"
+            />
+          </NeoButton>
+        </div>
+      </div>
     </div>
   </div>
 </template>
 
 <script lang="ts" setup>
-import { NeoButton } from '@kodadot1/brick'
+import { NeoButton, NeoIcon, NeoSkeleton } from '@kodadot1/brick'
 
-const { isCurrentAccount } = useAuth()
+const NuxtLink = resolveComponent('NuxtLink')
+
+const { isCurrentAccount, accountId } = useAuth()
 const { $i18n } = useNuxtApp()
+const { urlPrefix } = usePrefix()
 
 const traderAddress = ref('')
 const isTraderAddressValid = ref(false)
 const isYourAddress = ref(false)
+const isLoadingSwapOffersCount = ref(true)
+const swapOffersCount = ref<number>()
+const swapOfferSubscription = ref(() => {})
+
+const { data: ownedCollections, isPending: isLoadingOwnedCollections } = useOwnedCollections(accountId)
+
+const isLoadingIncomingTrades = computed(() => isLoadingSwapOffersCount.value || isLoadingOwnedCollections.value)
+const showIncomingTrades = computed(() => Boolean(accountId.value) && (isLoadingIncomingTrades.value || Boolean(swapOffersCount.value)))
 
 const isAddressEmpty = computed(() => !traderAddress.value)
 const disabled = computed(() => isAddressEmpty.value || isYourAddress.value || !isTraderAddressValid.value)
@@ -96,4 +144,33 @@ const handleAddressCheck = (isValid: boolean) => {
 const handleSubmit = async () => {
   await navigateTo({ name: 'prefix-swap-id', params: { id: traderAddress.value } })
 }
+
+watch([ownedCollections, accountId], ([ownedCollections, account]) => {
+  swapOffersCount.value = undefined
+
+  if (!account) {
+    return
+  }
+
+  if (ownedCollections !== undefined && ownedCollections.length) {
+    isLoadingSwapOffersCount.value = true
+    swapOfferSubscription.value = useSubscriptionGraphql<{ swapsConnection: { totalCount: number } }>({
+      query: `swapsConnection(
+      orderBy: blockNumber_DESC,
+      where: {
+        OR: [
+          ${buildIncomingTradesQuery(accountId.value, ownedCollections.map(({ id }) => id) || [], { stringify: true })},
+          { caller_eq: "${accountId.value}" , status_in: [ACTIVE, EXPIRED ]}
+        ]
+      }) {
+      totalCount
+      }`,
+      onChange: ({ data: { swapsConnection: { totalCount } } }) => {
+        isLoadingSwapOffersCount.value = false
+        swapOffersCount.value = totalCount
+        swapOfferSubscription.value()
+      },
+    })
+  }
+}, { immediate: true })
 </script>
diff --git a/components/trade/TradeActivityTable.vue b/components/trade/TradeActivityTable.vue
index 1c8270a2fc..3327a0f833 100644
--- a/components/trade/TradeActivityTable.vue
+++ b/components/trade/TradeActivityTable.vue
@@ -86,6 +86,11 @@
 
 <script lang="ts" setup>
 import { NeoButton } from '@kodadot1/brick'
+import type {
+  TradeType,
+  Swap,
+  TradeNftItem,
+} from '@/components/trade/types'
 
 type TradeTabType = 'outgoing' | 'incoming'
 export type TradeTableQuery = Record<TradeTabType, string>
diff --git a/components/trade/TradeActivityTableRow.vue b/components/trade/TradeActivityTableRow.vue
index a3b0c3de79..1127e0a0f3 100644
--- a/components/trade/TradeActivityTableRow.vue
+++ b/components/trade/TradeActivityTableRow.vue
@@ -202,6 +202,13 @@ import {
 import EventTag from '@/components/collection/activity/events/eventRow/EventTag.vue'
 import { TradeInteraction } from '@/composables/collectionActivity/types'
 import { fetchNft } from '@/components/items/ItemsGrid/useNftActions'
+import {
+  type TradeToken,
+  type TradeConsidered,
+  type TradeNftItem,
+  TradeType,
+  TradeDesiredTokenType,
+} from '@/components/trade/types'
 
 const EXPIRATION_FORMAT = 'dd.MM. HH:MM'
 
@@ -218,10 +225,10 @@ const getRowConfig = () => {
   return props.target === 'from'
     ? {
         item: props.trade.offered,
-        desiredType: TradeDesiredType.TOKEN,
+        desiredType: TradeDesiredTokenType.SPECIFIC,
       }
     : {
-        item: props.trade.isEntireCollectionDesired ? props.trade.considered : props.trade.desired as TradeToken,
+        item: props.trade.isAnyTokenInCollectionDesired ? props.trade.considered : props.trade.desired as TradeToken,
         desiredType: props.trade.desiredType,
       }
 }
@@ -242,13 +249,17 @@ const animationUrl = ref()
 
 const isDesktop = computed(() => props.variant === 'Desktop')
 
-const isTradeCollection = computed(() => desiredType === TradeDesiredType.COLLECTION)
-const itemPath = computed(() => isTradeCollection.value ? `/${urlPrefix.value}/collection/${item.id}` : `/${urlPrefix.value}/gallery/${item.id}`)
+const isItemCollection = computed(() => desiredType === TradeDesiredTokenType.ANY_IN_COLLECTION)
+const itemPath = computed(() => isItemCollection.value ? `/${urlPrefix.value}/collection/${item.id}` : `/${urlPrefix.value}/gallery/${item.id}`)
 
 const targetAddress = computed(() => props.target === 'to' ? item.currentOwner : props.trade.caller)
 const interactionName = computed(() => interactionNameMap()[interaction])
 
 const getAvatar = async (nft) => {
+  if (!nft.metadata) {
+    return
+  }
+
   const meta = await getNftMetadata(nft)
   image.value = meta.image
   animationUrl.value = meta.animationUrl
@@ -257,8 +268,8 @@ const getAvatar = async (nft) => {
 // TODO imporve nft fetching
 onBeforeMount(() => {
   const fetchImageMap = {
-    [TradeDesiredType.TOKEN]: (item: Item) => fetchNft(item.id).then(getAvatar),
-    [TradeDesiredType.COLLECTION]: (item: Item) => image.value = sanitizeIpfsUrl(item.image),
+    [TradeDesiredTokenType.SPECIFIC]: (item: Item) => fetchNft(item.id).then(getAvatar),
+    [TradeDesiredTokenType.ANY_IN_COLLECTION]: (item: Item) => image.value = sanitizeIpfsUrl(item.image),
   }
 
   fetchImageMap[desiredType]?.(item)
diff --git a/components/trade/TradeOwnerButton.vue b/components/trade/TradeOwnerButton.vue
index ea00bf2dd7..1634e77ef6 100644
--- a/components/trade/TradeOwnerButton.vue
+++ b/components/trade/TradeOwnerButton.vue
@@ -7,7 +7,7 @@
       :button="buttonConfig"
     />
 
-    <template v-if="isTargetOfTrade && detailed && trade.type === TradeType.SWAP">
+    <template v-if="isTargetOfTrade && detailed && trade.type === TradeType.SWAP && !trade.isAnyTokenInCollectionDesired">
       <NeoTooltip
         position="top"
         content-class="capitalize"
@@ -15,7 +15,6 @@
       >
         <NeoButton
           variant="icon"
-          :disabled="trade.isEntireCollectionDesired"
           @click="emit('click:counter-swap')"
         >
           <NeoIcon
@@ -30,12 +29,14 @@
 <script setup lang="ts">
 import { NeoButton, NeoIcon, NeoTooltip } from '@kodadot1/brick'
 import type { ButtonConfig } from '../profile/types'
-import { TradeType } from '@/composables/useTrades'
+import { TradeType, type TradeNftItem } from '@/components/trade/types'
 
 const emit = defineEmits(['click:main', 'click:counter-swap'])
 const props = defineProps<{
   trade: TradeNftItem
   loading?: boolean
+  disabled?: boolean
+  label?: string
   mainClass?: string
   detailed?: boolean
 }>()
@@ -60,7 +61,7 @@ const details = {
   },
 }
 
-const buttonConfig = computed<ButtonConfig | null>(() => {
+const tradeButtonConfig = computed<ButtonConfig | null>(() => {
   if (props.trade.isExpired) {
     return isCreatorOfTrade.value
       ? {
@@ -87,4 +88,18 @@ const buttonConfig = computed<ButtonConfig | null>(() => {
 
   return null
 })
+
+const buttonConfig = computed<ButtonConfig | null>(() => {
+  if (!tradeButtonConfig.value) {
+    return null
+  }
+
+  const config = { ...tradeButtonConfig.value }
+
+  Object.assign(config, { disabled: props.disabled })
+
+  props.label && Object.assign(config, { label: props.label })
+
+  return config
+})
 </script>
diff --git a/components/trade/overviewModal/CollectionItemDetails.vue b/components/trade/overviewModal/CollectionItemDetails.vue
new file mode 100644
index 0000000000..a0aa2f52f5
--- /dev/null
+++ b/components/trade/overviewModal/CollectionItemDetails.vue
@@ -0,0 +1,16 @@
+<template>
+  <BaseCartItemDetails
+    :name="trade.considered.name"
+    :second-name="$t('collection')"
+    :image="sanitizeIpfsUrl(trade.considered.image)"
+  />
+</template>
+
+<script setup lang="ts">
+import { sanitizeIpfsUrl } from '@/utils/ipfs'
+import { type TradeNftItem } from '@/components/trade/types'
+
+defineProps<{
+  trade: TradeNftItem
+}>()
+</script>
diff --git a/components/trade/overviewModal/Content.vue b/components/trade/overviewModal/Content.vue
new file mode 100644
index 0000000000..ceaf112c76
--- /dev/null
+++ b/components/trade/overviewModal/Content.vue
@@ -0,0 +1,67 @@
+<template>
+  <div
+    class="py-5"
+  >
+    <div
+      class="flex flex-col gap-5"
+      :class="{
+        'flex-col-reverse': isMyTrade && isSwap,
+      }"
+    >
+      <!-- Desired  -->
+      <TokenInCollection
+        v-if="trade.isAnyTokenInCollectionDesired"
+        :trade="trade"
+        :send-item="sendItem"
+        @send-item:select="$emit('send-item:select', $event)"
+        @send-item:clear="$emit('send-item:clear')"
+      />
+      <TokenItemDetails
+        v-else-if="desired"
+        :nft="desired"
+      />
+
+      <template v-if="isSwap">
+        <NeoIcon
+          class="rotate-90"
+          icon="arrow-right-arrow-left"
+        />
+
+        <!-- Offered -->
+        <TokenItemDetails
+          :nft="offered"
+        />
+      </template>
+    </div>
+
+    <hr class="!my-5">
+
+    <TradeOverviewModalDetails
+      :trade="trade"
+      :desired="desired"
+    />
+  </div>
+</template>
+
+<script setup lang="ts">
+import { NeoIcon } from '@kodadot1/brick'
+import { useIsTradeOverview } from './utils'
+import TokenItemDetails from './TokenItemDetails.vue'
+import TokenInCollection from './TokenInCollection.vue'
+import {
+  type TradeNftItem,
+  TradeType,
+} from '@/components/trade/types'
+import type { NFT } from '@/types'
+
+defineEmits(['send-item:select', 'send-item:clear'])
+const props = defineProps<{
+  desired?: NFT
+  offered: NFT
+  trade: TradeNftItem
+  sendItem?: NFT | null
+}>()
+
+const { isMyTrade } = useIsTradeOverview(computed(() => props.trade))
+const isSwap = computed(() => props.trade.type === TradeType.SWAP)
+</script>
diff --git a/components/trade/overviewModal/Details.vue b/components/trade/overviewModal/Details.vue
index 869521ff69..18c8f1acab 100644
--- a/components/trade/overviewModal/Details.vue
+++ b/components/trade/overviewModal/Details.vue
@@ -28,7 +28,7 @@
     </div>
 
     <div
-      v-if="isIncomingTrade"
+      v-if="isIncomingTrade && desired"
       class="flex justify-between items-center"
     >
       <span class="text-k-grey text-xs">
@@ -45,6 +45,8 @@
 <script setup lang="ts">
 import { useIsTradeOverview } from './utils'
 import { formatToNow } from '@/utils/format/time'
+import { blank } from '@/components/collection/activity/events/eventRow/common'
+import { type TradeNftItem } from '@/components/trade/types'
 import type { NFT } from '@/types'
 
 const props = defineProps<{
@@ -56,6 +58,14 @@ const { decimals, chainSymbol } = useChain()
 const { isMyTrade, isIncomingTrade } = useIsTradeOverview(computed(() => props.trade))
 
 const getFormattedDifference = (a: number, b: number) => {
+  if (b === 0 && a === 0) {
+    return blank
+  }
+
+  if (b === 0 && a > 0) {
+    return '+100%'
+  }
+
   const diff = ((b - a) / b) * 100
 
   return diff > 0
@@ -63,7 +73,7 @@ const getFormattedDifference = (a: number, b: number) => {
     : `+${Math.abs(diff).toFixed()}%`
 }
 
-const floorPrice = computed(() => Number(props.desired?.collection.floorPrice[0].price) || 0)
+const floorPrice = computed(() => Number(props.desired?.collection.floorPrice[0]?.price) || 0)
 const diff = computed(() => getFormattedDifference(Number(props.trade.price || 0), floorPrice.value))
 
 const { formatted: formmatedOffer, usd: offerUsd } = useAmount(
diff --git a/components/trade/overviewModal/SubmitButton.vue b/components/trade/overviewModal/SubmitButton.vue
new file mode 100644
index 0000000000..76c2b6d385
--- /dev/null
+++ b/components/trade/overviewModal/SubmitButton.vue
@@ -0,0 +1,22 @@
+<template>
+  <div
+    v-if="trade"
+    class="!pt-5"
+  >
+    <TradeOwnerButton
+      class="!w-full"
+      :trade="trade"
+      @click="$emit('submit')"
+    />
+  </div>
+</template>
+
+<script setup lang="ts">
+import { type TradeNftItem } from '@/components/trade/types'
+
+defineEmits(['submit'])
+defineProps<{
+  trade: TradeNftItem
+  disabled?: boolean
+}>()
+</script>
diff --git a/components/trade/overviewModal/TokenInCollection.vue b/components/trade/overviewModal/TokenInCollection.vue
new file mode 100644
index 0000000000..70f643cc0b
--- /dev/null
+++ b/components/trade/overviewModal/TokenInCollection.vue
@@ -0,0 +1,76 @@
+<template>
+  <div
+    class="flex flex-col gap-4"
+  >
+    <div class="flex flex-col gap-2">
+      <div class="text-sm font-semibold capitalize">
+        Any in collection
+      </div>
+      <CollectionItemDetails
+        :trade="trade"
+      />
+    </div>
+    <div
+      v-if="isTargetOfTrade"
+      class="flex flex-col gap-2"
+    >
+      <div class="flex justify-between items-center h-[1.5rem]">
+        <div class="text-sm font-semibold capitalize">
+          To trade
+        </div>
+
+        <NeoButton
+          v-if="sendItem"
+          variant="icon"
+          @click="() => {
+            selected = undefined
+            $emit('send-item:clear')
+          }"
+        >
+          <NeoIcon
+            icon="close"
+            size="small"
+          />
+        </NeoButton>
+      </div>
+
+      <TokenItemDetails
+        v-if="selected"
+        :nft="sendItem"
+      />
+
+      <TokenSearchInput
+        v-else
+        :where="{
+          currentOwner_eq: accountId,
+          collection: {
+            id_eq: trade.considered.id,
+          },
+        }"
+        @select="sendItem => {
+          selected = sendItem
+          $emit('send-item:select', sendItem)
+        }"
+      />
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { NeoButton, NeoIcon } from '@kodadot1/brick'
+import CollectionItemDetails from './CollectionItemDetails.vue'
+import TokenSearchInput from './TokenSearchInput.vue'
+import TokenItemDetails from './TokenItemDetails.vue'
+import type { NFT } from '@/types'
+import { type TradeNftItem } from '@/components/trade/types'
+
+defineEmits(['send-item:select', 'send-item:clear'])
+const props = defineProps<{
+  sendItem?: NFT | null
+  trade: TradeNftItem
+}>()
+
+const selected = ref()
+const { accountId } = useAuth()
+const { isTargetOfTrade } = useIsTrade(computed(() => props.trade), accountId)
+</script>
diff --git a/components/trade/overviewModal/TokenItemDetails.vue b/components/trade/overviewModal/TokenItemDetails.vue
new file mode 100644
index 0000000000..711d65c797
--- /dev/null
+++ b/components/trade/overviewModal/TokenItemDetails.vue
@@ -0,0 +1,36 @@
+<template>
+  <CartItemDetails
+    v-if="nft"
+    :nft="nftToOfferItem(nft)"
+  >
+    <template #right>
+      <div class="flex items-end flex-shrink-0">
+        {{ formattedPrice }}
+      </div>
+    </template>
+  </CartItemDetails>
+  <BaseCartItemDetailsSkeleton v-else />
+</template>
+
+<script setup lang="ts">
+import { nftToOfferItem } from '@/components/common/shoppingCart/utils'
+import type { NFT } from '@/types'
+
+const props = defineProps<{
+  nft?: NFT | null
+}>()
+
+const formattedPrice = ref()
+const { decimals, chainSymbol } = useChain()
+
+watchEffect(() => {
+  const nft = props.nft
+  if (nft) {
+    formattedPrice.value = useAmount(
+      computed(() => nft.price),
+      decimals,
+      chainSymbol,
+    ).formatted.value
+  }
+})
+</script>
diff --git a/components/trade/overviewModal/TokenSearchInput.vue b/components/trade/overviewModal/TokenSearchInput.vue
new file mode 100644
index 0000000000..7b213cd761
--- /dev/null
+++ b/components/trade/overviewModal/TokenSearchInput.vue
@@ -0,0 +1,59 @@
+<template>
+  <SearchInput
+    placeholder="Search by name"
+    :on-search="onSearch"
+    @select="s => $emit('select', s)"
+  >
+    <template
+      #default="{ item }"
+    >
+      <div
+        :key="item.id"
+        class="flex items-center gap-2"
+      >
+        <BaseMediaItem
+          class="border border-border-color w-8 h-8"
+          :src="sanitizeIpfsUrl(item.meta.image)"
+          :alt="item.name"
+        />
+        <div class="flex flex-col">
+          <div class="text-sm font-semibold text-text-color">
+            {{ item.name }}
+          </div>
+          <div class="text-xs text-k-grey">
+            {{ item.collection?.name }}
+          </div>
+        </div>
+      </div>
+    </template>
+  </SearchInput>
+</template>
+
+<script setup lang="ts">
+import { sanitizeIpfsUrl } from '@/utils/ipfs'
+
+defineEmits(['select'])
+const props = defineProps<{
+  where: Record<string, unknown>
+}>()
+
+const onSearch = async (searchKey: string) => {
+  const search = {
+    name_containsInsensitive: searchKey,
+  }
+
+  if (props.where) {
+    Object.assign(search, props.where)
+  }
+
+  const { data } = await useAsyncGraphql({
+    query: 'nftListWithSearch',
+    variables: {
+      search: search,
+      first: 5,
+    },
+  })
+
+  return data.value.nFTEntities
+}
+</script>
diff --git a/components/trade/overviewModal/TradeOverviewModal.vue b/components/trade/overviewModal/TradeOverviewModal.vue
index f9cc3d785b..a0b0d36bba 100644
--- a/components/trade/overviewModal/TradeOverviewModal.vue
+++ b/components/trade/overviewModal/TradeOverviewModal.vue
@@ -19,31 +19,28 @@
         :loading="loading"
         @close="onClose"
       >
-        <div>
-          <ModalIdentityItem />
-
-          <template v-if="trade && nft">
-            <TradeOverviewModalTypeSwap
-              v-if="trade.type === TradeType.SWAP"
-              :desired="nft.desired"
-              :offered="nft.offered"
-              :trade="trade"
-            />
-            <TradeOverviewModalTypeOffer
-              v-if="trade.type === TradeType.OFFER && nft.desired"
-              :desired="nft.desired"
-              :trade="trade"
-            />
-          </template>
-        </div>
+        <ModalIdentityItem />
+
+        <TradeOverviewModalContent
+          v-if="trade && nft"
+          :key="session"
+          :desired="nft.desired"
+          :offered="nft.offered"
+          :trade="trade"
+          :send-item="sendItem"
+          @send-item:select="selectSendItem"
+          @send-item:clear="clearSendItem"
+        />
 
         <div
           v-if="trade"
           class="!pt-5"
         >
           <TradeOwnerButton
-            main-class="!w-full"
+            main-class="!w-full capitalize"
             :trade="trade"
+            :label="label"
+            :disabled="disabled"
             @click:main="execTransaction"
           />
         </div>
@@ -54,12 +51,21 @@
 
 <script setup lang="ts">
 import { NeoModal } from '@kodadot1/brick'
-import { useIsTradeOverview, type OverviewMode } from './utils'
+import { useQuery } from '@tanstack/vue-query'
+import {
+  type OverviewMode,
+  type ExecTxParams,
+  useIsTradeOverview,
+  TradeTypeTx,
+} from './utils'
 import ModalBody from '@/components/shared/modals/ModalBody.vue'
 import ModalIdentityItem from '@/components/shared/ModalIdentityItem.vue'
-import nftById from '@/queries/subsquid/general/nftById.graphql'
-import { TradeType } from '@/composables/useTrades'
+import {
+  type TradeNftItem,
+  TradeType,
+} from '@/components/trade/types'
 import type { NFT } from '@/types'
+import { fetchNft } from '@/components/items/ItemsGrid/useNftActions'
 
 type OverviewModeDetails = {
   title: string
@@ -74,24 +80,7 @@ type Details = {
 
 type TradeNFTs = { desired?: NFT, offered: NFT }
 
-type ExecTxParams = {
-  trade: TradeNftItem
-}
-
-const emit = defineEmits(['close'])
-const props = defineProps<{
-  modelValue: boolean
-  trade?: TradeNftItem
-}>()
-
-const vModel = useVModel(props, 'modelValue')
-
-const { accountId } = useAuth()
-const { urlPrefix, client } = usePrefix()
-const { transaction, status, isError, isLoading } = useTransaction({ disableSuccessNotification: true })
 const { $i18n } = useNuxtApp()
-const { notification, lastSessionId, updateSession } = useLoadingNotfication()
-const { mode } = useIsTradeOverview(computed(() => props.trade))
 
 const TradeTypeOverviewModeDetails: Record<TradeType, Record<OverviewMode, OverviewModeDetails>> = {
   [TradeType.SWAP]: {
@@ -131,51 +120,32 @@ const TradeTypeDetails: Record<TradeType, Details> = {
   },
 }
 
-const TradeTypeTx: Record<TradeType, Record<OverviewMode, (params: ExecTxParams) => void>> = {
-  [TradeType.SWAP]: {
-    owner: ({ trade }) => {
-      transaction({
-        interaction: ShoppingActions.CANCEL_SWAP,
-        urlPrefix: urlPrefix.value,
-        offeredId: trade.offered.sn,
-        offeredCollectionId: trade.offered.collection.id,
-      })
-    },
-    incoming: ({ trade }) => {
-      transaction({
-        interaction: ShoppingActions.ACCEPT_SWAP,
-        urlPrefix: urlPrefix.value,
-        receiveItem: trade.offered.sn,
-        receiveCollection: trade.offered.collection.id,
-        sendCollection: trade.considered.id,
-        sendItem: trade.desired?.sn,
-        price: trade.price,
-        surcharge: (trade as TradeNftItem<Swap>).surcharge,
-      })
-    },
-  },
-  [TradeType.OFFER]: {
-    owner: ({ trade }) => {
-      transaction({
-        interaction: ShoppingActions.CANCEL_OFFER,
-        urlPrefix: urlPrefix.value,
-        offeredId: trade.offered.sn,
-      })
-    },
-    incoming: ({ trade }) => {
-      transaction({
-        interaction: ShoppingActions.ACCEPT_OFFER,
-        urlPrefix: urlPrefix.value,
-        receiveItem: trade.offered.sn,
-        sendCollection: trade.considered.id,
-        sendItem: trade.desired?.sn,
-        price: trade.price,
-      })
-    },
-  },
-}
+const emit = defineEmits(['close'])
+const props = defineProps<{
+  modelValue: boolean
+  trade?: TradeNftItem
+}>()
+
+const selectedSendItemId = ref<string>()
+const session = ref<string>()
+const vModel = useVModel(props, 'modelValue')
+
+const { accountId } = useAuth()
+const { urlPrefix } = usePrefix()
+const { transaction, status, isError, isLoading } = useTransaction({ disableSuccessNotification: true })
+const { notification, lastSessionId, updateSession } = useLoadingNotfication()
+const { mode, isIncomingTrade } = useIsTradeOverview(computed(() => props.trade))
 
 const trade = computed(() => props.trade)
+const needsToSelectSendItem = computed(() => isIncomingTrade.value && !sendItem.value && Boolean(trade.value?.isAnyTokenInCollectionDesired))
+const disabled = computed(() => needsToSelectSendItem.value)
+
+const label = computed<string | undefined>(() => {
+  if (needsToSelectSendItem.value) {
+    return $i18n.t('trade.selectSendItem')
+  }
+  return undefined
+})
 
 const details = computed<Details & OverviewModeDetails>(() =>
   trade.value
@@ -191,48 +161,54 @@ const details = computed<Details & OverviewModeDetails>(() =>
         transactionSuccessTab: '',
       })
 
-const { data: nft, pending: nftLoading } = await useAsyncData<TradeNFTs | null>(`tarde-nft-id-${trade.value?.id}`, async () => {
-  if (!trade.value) {
-    return null
-  }
+const { data: nft, isLoading: nftLoading } = useQuery<TradeNFTs | null>({
+  queryKey: ['trade-nft', computed(() => trade.value?.id)],
+  queryFn: async () => {
+    if (!trade.value) {
+      return null
+    }
 
-  const promises = [
-    useAsyncQuery<{ nftEntity: NFT }>({
-      query: nftById,
-      variables: {
-        id: trade.value.offered.id,
-      },
-      clientId: client.value,
-    }),
-  ]
-
-  if (trade.value.desired) {
-    promises.push(
-      useAsyncQuery<{ nftEntity: NFT }>({
-        query: nftById,
-        variables: {
-          id: trade.value.desired.id,
-        },
-        clientId: client.value,
-      }),
-    )
-  }
+    const promises = [
+      fetchNft(trade.value.offered.id),
+    ]
 
-  const [offered, desired] = await Promise.all(promises)
+    if (trade.value.desired) {
+      promises.push(fetchNft(trade.value.desired.id))
+    }
 
-  return {
-    offered: offered.data.value?.nftEntity,
-    desired: desired?.data.value?.nftEntity,
-  }
-}, { watch: [trade] })
+    const [offered, desired] = await Promise.all(promises)
+
+    return {
+      offered,
+      desired,
+    }
+  },
+})
+
+const { data: sendItem } = useQuery({
+  queryKey: ['send-item', selectedSendItemId],
+  queryFn: async () => {
+    if (!selectedSendItemId.value) {
+      return null
+    }
+    return await fetchNft(selectedSendItemId.value)
+  },
+})
 
 const loading = computed(() => nftLoading.value || !nft.value)
 
+const selectSendItem = item => selectedSendItemId.value = item.id
+const clearSendItem = () => selectedSendItemId.value = undefined
+
 const onClose = () => {
   vModel.value = false
   onModalAnimation(() => emit('close'))
 }
 
+const reset = () => {
+  clearSendItem()
+}
+
 const execTransaction = () => {
   if (!nft.value || !trade.value) {
     return
@@ -240,11 +216,27 @@ const execTransaction = () => {
 
   vModel.value = false
 
-  TradeTypeTx[trade.value.type][mode.value]({
-    trade: props.trade,
-  } as ExecTxParams)
+  const params: ExecTxParams = {
+    trade: trade.value,
+    transaction,
+    urlPrefix: urlPrefix.value,
+    sendItem: trade.value.desired?.sn || sendItem.value?.sn as string,
+  }
+
+  TradeTypeTx[trade.value.type][mode.value](params)
 }
 
+const initSession = () => {
+  session.value = window.crypto.randomUUID()
+  reset()
+}
+
+useModalIsOpenTracker({
+  isOpen: vModel,
+  onClose: false,
+  onChange: initSession,
+})
+
 useTransactionNotification({
   status,
   isError,
diff --git a/components/trade/overviewModal/TypeOffer.vue b/components/trade/overviewModal/TypeOffer.vue
deleted file mode 100644
index 3b50bd86a4..0000000000
--- a/components/trade/overviewModal/TypeOffer.vue
+++ /dev/null
@@ -1,40 +0,0 @@
-<template>
-  <div
-    class="py-5"
-  >
-    <CartItemDetails
-      :nft="nftToOfferItem(desired)"
-    >
-      <template #right>
-        <div class="flex items-end flex-shrink-0">
-          {{ desiredFormatted }}
-        </div>
-      </template>
-    </CartItemDetails>
-
-    <hr class="!my-5">
-
-    <TradeOverviewModalDetails
-      :trade="trade"
-      :desired="desired"
-    />
-  </div>
-</template>
-
-<script setup lang="ts">
-import { nftToOfferItem } from '@/components/common/shoppingCart/utils'
-import type { NFT } from '@/types'
-
-const props = defineProps<{
-  desired: NFT
-  trade: TradeNftItem
-}>()
-
-const { decimals, chainSymbol } = useChain()
-
-const { formatted: desiredFormatted } = useAmount(
-  computed(() => props.desired.price),
-  decimals,
-  chainSymbol,
-)
-</script>
diff --git a/components/trade/overviewModal/TypeSwap.vue b/components/trade/overviewModal/TypeSwap.vue
deleted file mode 100644
index b7f02a72c5..0000000000
--- a/components/trade/overviewModal/TypeSwap.vue
+++ /dev/null
@@ -1,84 +0,0 @@
-<template>
-  <div
-    class="py-5"
-  >
-    <div
-      class="flex flex-col gap-5"
-      :class="{
-        'flex-col-reverse': isMyTrade,
-      }"
-    >
-      <BaseCartItemDetails
-        v-if="trade.isEntireCollectionDesired"
-        :name="trade.considered.name"
-        :second-name="$t('collection')"
-        :image="sanitizeIpfsUrl(trade.considered.image)"
-      />
-      <CartItemDetails
-        v-else-if="desired"
-        :nft="nftToOfferItem(desired)"
-      >
-        <template #right>
-          <div class="flex items-end flex-shrink-0">
-            {{ desiredFormatted }}
-          </div>
-        </template>
-      </CartItemDetails>
-
-      <NeoIcon
-        class="rotate-90"
-        icon="arrow-right-arrow-left"
-      />
-
-      <CartItemDetails
-        :nft="nftToOfferItem(offered)"
-      >
-        <template #right>
-          <div class="flex items-end flex-shrink-0">
-            {{ oferredFormatted }}
-          </div>
-        </template>
-      </CartItemDetails>
-    </div>
-
-    <hr class="!my-5">
-
-    <TradeOverviewModalDetails
-      :trade="trade"
-      :desired="desired"
-    />
-  </div>
-</template>
-
-<script setup lang="ts">
-import { NeoIcon } from '@kodadot1/brick'
-import { useIsTradeOverview } from './utils'
-import { nftToOfferItem } from '@/components/common/shoppingCart/utils'
-import { sanitizeIpfsUrl } from '@/utils/ipfs'
-import type { NFT } from '@/types'
-
-const props = defineProps<{
-  desired?: NFT
-  offered: NFT
-  trade: TradeNftItem
-}>()
-
-const desiredFormatted = ref('')
-
-const { isMyTrade } = useIsTradeOverview(computed(() => props.trade))
-const { decimals, chainSymbol } = useChain()
-
-if (!props.trade.isEntireCollectionDesired) {
-  desiredFormatted.value = useAmount(
-    computed(() => props.desired?.price),
-    decimals,
-    chainSymbol,
-  ).formatted.value
-}
-
-const { formatted: oferredFormatted } = useAmount(
-  computed(() => props.offered.price),
-  decimals,
-  chainSymbol,
-)
-</script>
diff --git a/components/trade/overviewModal/utils.ts b/components/trade/overviewModal/utils.ts
index 2b43eecf52..b5bef60d42 100644
--- a/components/trade/overviewModal/utils.ts
+++ b/components/trade/overviewModal/utils.ts
@@ -1,3 +1,10 @@
+import type { Prefix } from '@kodadot1/static'
+import {
+  type Swap,
+  type TradeNftItem,
+  TradeType,
+} from '@/components/trade/types'
+
 export type OverviewMode = 'owner' | 'incoming'
 
 export const useIsTradeOverview = (trade: ComputedRef<TradeNftItem | undefined>) => {
@@ -15,3 +22,54 @@ export const useIsTradeOverview = (trade: ComputedRef<TradeNftItem | undefined>)
     mode,
   }
 }
+
+export type ExecTxParams = {
+  trade: TradeNftItem
+  sendItem?: string
+  transaction: ReturnType<typeof useTransaction>['transaction']
+  urlPrefix: Prefix
+}
+
+export const TradeTypeTx: Record<TradeType, Record<OverviewMode, (params: ExecTxParams) => void>> = {
+  [TradeType.SWAP]: {
+    owner: ({ trade, urlPrefix, transaction }) => {
+      transaction({
+        interaction: ShoppingActions.CANCEL_SWAP,
+        urlPrefix: urlPrefix,
+        offeredId: trade.offered.sn,
+        offeredCollectionId: trade.offered.collection.id,
+      })
+    },
+    incoming: ({ trade, sendItem, urlPrefix, transaction }) => {
+      transaction({
+        interaction: ShoppingActions.ACCEPT_SWAP,
+        urlPrefix: urlPrefix,
+        receiveItem: trade.offered.sn,
+        receiveCollection: trade.offered.collection.id,
+        sendCollection: trade.considered.id,
+        sendItem: sendItem,
+        price: trade.price,
+        surcharge: (trade as TradeNftItem<Swap>).surcharge,
+      })
+    },
+  },
+  [TradeType.OFFER]: {
+    owner: ({ trade, transaction, urlPrefix }) => {
+      transaction({
+        interaction: ShoppingActions.CANCEL_OFFER,
+        urlPrefix: urlPrefix,
+        offeredId: trade.offered.sn,
+      })
+    },
+    incoming: ({ trade, sendItem, transaction, urlPrefix }) => {
+      transaction({
+        interaction: ShoppingActions.ACCEPT_OFFER,
+        urlPrefix: urlPrefix,
+        receiveItem: trade.offered.sn,
+        sendCollection: trade.considered.id,
+        sendItem: sendItem,
+        price: trade.price,
+      })
+    },
+  },
+}
diff --git a/components/trade/types.ts b/components/trade/types.ts
index cc8c213060..da0e2c3d86 100644
--- a/components/trade/types.ts
+++ b/components/trade/types.ts
@@ -18,3 +18,69 @@ export type MakingOfferItem = {
   metadata: string
   sn: string
 }
+
+export enum TradeStatus {
+  ACTIVE = 'ACTIVE',
+  EXPIRED = 'EXPIRED',
+  WITHDRAWN = 'WITHDRAWN',
+  ACCEPTED = 'ACCEPTED',
+}
+
+export type TradeToken = {
+  id: string
+  name: string
+  sn: string
+  currentOwner: string
+  image: string
+  collection: {
+    id: string
+  }
+  meta: Record<string, unknown>
+}
+
+export type TradeConsidered = {
+  id: string
+  name: string
+  currentOwner: string
+  image: string
+}
+
+export type BaseTrade = {
+  id: string
+  price: string
+  expiration: string
+  blockNumber: string
+  status: TradeStatus
+  caller: string
+  offered: TradeToken
+  desired: TradeToken | null
+  considered: TradeConsidered
+  createdAt: Date
+}
+
+export enum TradeDesiredTokenType {
+  SPECIFIC,
+  ANY_IN_COLLECTION,
+}
+
+export enum TradeType {
+  SWAP = 'swap',
+  OFFER = 'offer',
+}
+
+export type Swap = BaseTrade & {
+  surcharge: string | null
+}
+
+export type Offer = BaseTrade
+
+type Trade = Swap | Offer
+
+export type TradeNftItem<T = Trade> = T & {
+  expirationDate: Date
+  type: TradeType
+  desiredType: TradeDesiredTokenType
+  isAnyTokenInCollectionDesired: boolean
+  targets: string[]
+  isExpired: boolean
+}
diff --git a/composables/transaction/transactionMintToken.ts b/composables/transaction/transactionMintToken.ts
index f21e3a48cb..ff9b98b3c7 100644
--- a/composables/transaction/transactionMintToken.ts
+++ b/composables/transaction/transactionMintToken.ts
@@ -1,9 +1,9 @@
+import type { Prefix } from '@kodadot1/static'
 import type { MintTokenParams, SubstrateMintTokenParams } from './types'
 import { execMintStatemine } from './mintToken/transactionMintStatemine'
 
 export function execMintToken({ item, ...params }: MintTokenParams) {
-  // item.urlPrefix === 'ahr'
-  if (item.urlPrefix === 'ahk' || item.urlPrefix === 'ahp') {
+  if (isAssetHub(item.urlPrefix as Prefix)) {
     return execMintStatemine({
       item,
       ...params,
diff --git a/composables/transaction/transactionOffer.ts b/composables/transaction/transactionOffer.ts
index 178cf410ef..bdd4115bd7 100644
--- a/composables/transaction/transactionOffer.ts
+++ b/composables/transaction/transactionOffer.ts
@@ -17,7 +17,8 @@ export const getOfferCollectionId = (prefix: Prefix) => {
 
 export const OFFER_MINT_PRICE = 5e8
 
-export const BLOCKS_PER_DAY = 300 * 24 // 12sec /block --> 300blocks/hr
+export const BLOCKS_PER_HOUR = 300
+export const BLOCKS_PER_DAY = BLOCKS_PER_HOUR * 24 // 12sec /block --> 300blocks/hr
 
 async function execMakingOffer(item: ActionOffer, api: ApiPromise, executeTransaction) {
   const { accountId } = useAuth()
diff --git a/composables/transaction/utils.ts b/composables/transaction/utils.ts
index deee6ad00b..e51583bf2c 100644
--- a/composables/transaction/utils.ts
+++ b/composables/transaction/utils.ts
@@ -60,7 +60,7 @@ export function isActionValid(action: Actions): boolean {
     [ShoppingActions.ACCEPT_SWAP]: (action: ActionAcceptSwap) =>
       Boolean(action.receiveItem) && Boolean(action.receiveCollection) && Boolean(action.sendItem) && Boolean(action.sendCollection),
     [ShoppingActions.ACCEPT_OFFER]: (action: ActionAcceptOffer) =>
-      Boolean(action.sendItem && action.sendCollection && action.price && action.receiveItem),
+      Boolean(action.sendCollection && action.price && action.receiveItem),
     [Interaction.MINT]: (action: ActionMintCollection) =>
       Boolean(action.collection),
     [Collections.DELETE]: (action: ActionDeleteCollection) =>
diff --git a/composables/useIsTrade.ts b/composables/useIsTrade.ts
index 77e6ebbea2..bc9ce176ed 100644
--- a/composables/useIsTrade.ts
+++ b/composables/useIsTrade.ts
@@ -1,6 +1,8 @@
+import type { TradeNftItem } from '@/components/trade/types'
+
 export default function (trade: ComputedRef<TradeNftItem | undefined>, target: MaybeRef<string>) {
   const isCreatorOfTrade = computed(() => trade.value?.caller === unref(target))
-  const isTargetOfTrade = computed(() => (trade.value?.isEntireCollectionDesired ? trade.value?.considered : trade.value?.desired)?.currentOwner === unref(target))
+  const isTargetOfTrade = computed(() => trade.value?.targets.includes(unref(target)))
 
   return {
     isCreatorOfTrade,
diff --git a/composables/useOwnedCollections.ts b/composables/useOwnedCollections.ts
new file mode 100644
index 0000000000..2c2425e706
--- /dev/null
+++ b/composables/useOwnedCollections.ts
@@ -0,0 +1,23 @@
+import { useQuery } from '@tanstack/vue-query'
+import collectionIdList from '@/queries/subsquid/general/collectionIdList.graphql'
+
+export function useOwnedCollections(id: Ref<string>, { client = usePrefix().client } = {}) {
+  return useQuery({
+    queryKey: ['ownedCollections', id],
+    queryFn: async () => {
+      const { data } = await useAsyncQuery<{ collectionEntities: { id: string }[] }>({
+        query: collectionIdList,
+        variables: {
+          search: {
+            nfts_some: {
+              currentOwner_eq: id.value,
+            },
+          },
+        },
+        clientId: client.value,
+      })
+
+      return data.value.collectionEntities
+    },
+  })
+}
diff --git a/composables/useSubscriptionGraphql.ts b/composables/useSubscriptionGraphql.ts
index 1460d3b3ac..8d82899429 100644
--- a/composables/useSubscriptionGraphql.ts
+++ b/composables/useSubscriptionGraphql.ts
@@ -1,7 +1,7 @@
 import isEqual from 'lodash/isEqual'
 import { apolloClientConfig } from '@/utils/constants'
 
-export default function ({
+export default function useSubscriptionGraphql<T = any>({
   clientName = '',
   query,
   onChange,
@@ -12,7 +12,7 @@ export default function ({
 }: {
   clientName?: string
   query: string
-  onChange: (data) => void
+  onChange: (data: { data: T }) => void
   onError?: (error) => void
   pollingInterval?: number
   disabled?: ComputedRef<boolean>
@@ -27,7 +27,7 @@ export default function ({
     return () => {}
   }
 
-  let lastQueryResult = null
+  let lastQueryResult: T | null = null
   let intervalId: number | null = null
 
   const isPolling = ref(false)
@@ -45,7 +45,7 @@ export default function ({
         },
       })
 
-      const newResult = response.data as any
+      const newResult = response.data as T
 
       if (!isEqual(newResult, lastQueryResult)) {
         if (!lastQueryResult ? immediate : true) {
diff --git a/composables/useTrades.ts b/composables/useTrades.ts
index 4d7a12b8f9..ce14b3abc6 100644
--- a/composables/useTrades.ts
+++ b/composables/useTrades.ts
@@ -1,69 +1,24 @@
 import type { DocumentNode } from 'graphql'
-import { addHours } from 'date-fns'
+import { addSeconds, subSeconds } from 'date-fns'
 import swapsList from '@/queries/subsquid/general/swapsList.graphql'
 import offersList from '@/queries/subsquid/general/offersList.graphql'
-
-export enum TradeStatus {
-  ACTIVE = 'ACTIVE',
-  EXPIRED = 'EXPIRED',
-  WITHDRAWN = 'WITHDRAWN',
-  ACCEPTED = 'ACCEPTED',
-}
-
-export type TradeToken = {
+import { BLOCKS_PER_HOUR } from '@/composables/transaction/transactionOffer'
+import {
+  type Offer,
+  type Swap,
+  type BaseTrade,
+  type TradeNftItem,
+  TradeType,
+  TradeDesiredTokenType,
+  TradeStatus,
+} from '@/components/trade/types'
+
+type CollectionWithTokenOwners = {
   id: string
-  name: string
-  sn: string
-  currentOwner: string
-  image: string
-  collection: {
+  nfts: {
     id: string
-  }
-  meta: Record<string, unknown>
-}
-
-export type TradeConsidered = {
-  id: string
-  name: string
-  currentOwner: string
-  image: string
-}
-
-type BaseTrade = {
-  id: string
-  price: string
-  expiration: string
-  blockNumber: string
-  status: TradeStatus
-  caller: string
-  offered: TradeToken
-  desired: TradeToken | null
-  considered: TradeConsidered
-}
-
-export enum TradeDesiredType {
-  TOKEN,
-  COLLECTION,
-}
-
-export enum TradeType {
-  SWAP,
-  OFFER,
-}
-
-export type Swap = BaseTrade & {
-  surcharge: string | null
-}
-
-type Offer = BaseTrade
-
-type Trade = Swap | Offer
-
-export type TradeNftItem<T = Trade> = T & {
-  expirationDate?: Date
-  type: TradeType
-  desiredType: TradeDesiredType
-  isEntireCollectionDesired: boolean
+    currentOwner: string
+  }[]
   isExpired: boolean
 }
 
@@ -78,58 +33,131 @@ export const TRADES_QUERY_MAP: Record<TradeType, { queryDocument: DocumentNode,
   },
 }
 
-const BLOCKS_PER_HOUR = 300
+const SECONDS_PER_BLOCK = 3600 / BLOCKS_PER_HOUR
 
-export default function ({ where = {}, limit = 100, disabled = computed(() => false), type = TradeType.SWAP }: {
-  where?: MaybeRef<Record<string, unknown>>
+export type UseTradesParams = {
+  where?: MaybeRef<Record<string, unknown> | string>
   limit?: number
   disabled?: ComputedRef<boolean>
   type?: TradeType
-}) {
+  minimal?: boolean
+  orderBy?: string[]
+}
+
+export default function ({
+  where = {},
+  limit = 100,
+  disabled = computed(() => false),
+  type = TradeType.SWAP,
+  minimal = false,
+  orderBy = ['blockNumber_DESC'],
+}: UseTradesParams) {
   const { queryDocument, dataKey } = TRADES_QUERY_MAP[type]
 
+  const items = ref<TradeNftItem[]>([])
+  const targetsOfTrades = ref<Map<string, string[]>>()
+  const ownersSubscription = ref(() => { })
+
   const { client } = usePrefix()
   const currentBlock = useCurrentBlock()
 
-  const variables = computed(() => ({
-    where: unref(where),
-    limit: limit,
-  }))
-
   const {
     result: data,
     loading: fetching,
+    refetch,
   } = useQuery<{ offers: Offer[] } | { swpas: Swap[] }>(
     queryDocument,
-    variables,
+    computed(() => ({
+      where: unref(where),
+      limit: limit,
+      orderBy: orderBy,
+    })),
     computed(() => ({
       enabled: !disabled.value,
       clientId: client.value,
     })),
   )
 
-  const items = computed<TradeNftItem[]>(() => {
-    return data.value?.[dataKey]?.map((trade) => {
-      const desiredType = trade.desired ? TradeDesiredType.TOKEN : TradeDesiredType.COLLECTION
+  const dataItems = computed<Offer[] | Swap[]>(() => data.value?.[dataKey] || [])
+  const hasTargetsOfTrades = computed(() => Boolean(targetsOfTrades.value))
+  const tradeKeys = computed<string>(() => dataItems.value.map(item => item.id).join('-'))
+  const needsToSubscribe = computed(() => minimal ? false : !hasTargetsOfTrades.value)
+  const loading = computed(() => !currentBlock.value || fetching.value || needsToSubscribe.value)
+
+  const subscribeToTargetsOfTrades = (trades: BaseTrade[]) => {
+    ownersSubscription.value = useSubscriptionGraphql<{ collections: CollectionWithTokenOwners[] }>({
+      query: `
+        collections: collectionEntities(where: {
+          id_in: ${JSON.stringify(trades.map(item => item.considered.id))}
+        }) {
+          id
+          nfts {
+            id
+            currentOwner
+          }
+        }
+      `,
+      onChange: ({ data: { collections } }) => {
+        const map = new Map()
+
+        const collectionMap: Record<string, CollectionWithTokenOwners['nfts']> = Object.fromEntries(
+          collections.map(collection => [collection.id, collection.nfts]),
+        )
+
+        trades.forEach((trade) => {
+          const tradeDesired = trade.desired
+          map.set(trade.id,
+            tradeDesired
+              ? [collectionMap[tradeDesired.collection.id].find(nft => nft.id === tradeDesired.id)?.currentOwner]
+              : collectionMap[trade.considered.id].map(nft => nft.currentOwner),
+          )
+        })
+
+        targetsOfTrades.value = map
+      },
+    })
+  }
+
+  if (!minimal) {
+    watch([tradeKeys, () => Boolean(data.value)], ([newTradeKeys, hasFetched], [oldTradeKeys]) => {
+      const hasSubscription = targetsOfTrades.value !== undefined
+      const tradeKeysChanged = newTradeKeys !== oldTradeKeys
+
+      if (hasFetched && (!hasSubscription || tradeKeysChanged)) {
+        ownersSubscription.value()
+        targetsOfTrades.value = undefined
+        subscribeToTargetsOfTrades(dataItems.value)
+      }
+    })
+  }
+
+  watchEffect(() => {
+    if (needsToSubscribe.value || !currentBlock.value) {
+      return
+    }
+
+    items.value = dataItems.value.map((trade) => {
+      const desiredType = trade.desired ? TradeDesiredTokenType.SPECIFIC : TradeDesiredTokenType.ANY_IN_COLLECTION
 
       return {
         ...trade,
-        expirationDate: currentBlock.value ? addHours(new Date(), (Number(trade.expiration) - currentBlock.value) / BLOCKS_PER_HOUR) : undefined,
+        expirationDate: addSeconds(new Date(), ((Number(trade.expiration) - currentBlock.value) * SECONDS_PER_BLOCK)),
         offered: trade.nft,
         desiredType: desiredType,
-        isEntireCollectionDesired: desiredType === TradeDesiredType.COLLECTION,
+        isAnyTokenInCollectionDesired: desiredType === TradeDesiredTokenType.ANY_IN_COLLECTION,
         // Check block number to handle trades that are expired but not yet updated in indexer
         // @see https://github.com/kodadot/stick/blob/9eac12938c47bf0e66e93760231208e4249d8637/src/mappings/utils/cache.ts#L127
         isExpired: trade.status === TradeStatus.EXPIRED || currentBlock.value > Number(trade.expiration),
         type,
+        targets: targetsOfTrades.value?.get(trade.id) || [],
+        createdAt: subSeconds(new Date(), ((currentBlock.value - Number(trade.blockNumber)) * SECONDS_PER_BLOCK)),
       } as TradeNftItem
-    }) || []
+    })
   })
 
-  const loading = computed(() => !currentBlock.value || fetching.value)
-
   return {
     items,
     loading,
+    refetch,
   }
 }
diff --git a/i18n/locales/en.json b/i18n/locales/en.json
index 0434ab0940..2b53a36ac0 100644
--- a/i18n/locales/en.json
+++ b/i18n/locales/en.json
@@ -285,6 +285,7 @@
     "decline": "Decline",
     "notice": "We use cookies for better service, see {0} for details."
   },
+  "count": "Count",
   "create": "Create",
   "create collection": "Create Collection",
   "createDropdown": {
@@ -930,6 +931,7 @@
     "resending": "Resending",
     "resetAll": "Reset All",
     "search": "Search",
+    "searchNoResults": "No results",
     "searchNoResultsText": "Give it another shot with different parameters or check back later - New awesome NFTs are added all the time",
     "searchNoResultsTitle": "Whoops, Couldn't find anything matching your search",
     "searchPlaceholder": "Search by Collection or NFT",
@@ -1530,6 +1532,7 @@
     "invalidPrice": "Your offer must greater than 0.0001",
     "manageOffers": "Manage Offers",
     "newOffer": "New Offer",
+    "offer": "Offer",
     "offerAccept": "Accepting Offer",
     "offerCancellation": "Offer Cancellation",
     "offerCreation": "Offer Creation",
@@ -1842,6 +1845,7 @@
     "connectTraderInfo": "Enter the wallet address of the trader you want to engage with, and we’ll guide you through the secure process of making a swap offer.",
     "counterSwap": "Counter Swap",
     "counterparty": "Counterparty",
+    "createSwap": "Create Swap",
     "created": "Swap Created",
     "creatingSwap": "Creating Swap",
     "incomingSwap": "Incoming Swap",
@@ -1870,7 +1874,8 @@
     "yourAddress": "Your Address",
     "yourOffer": "Your offer",
     "yourSwap": "Your Swap",
-    "yourSwapList": "Your Swap List"
+    "yourSwapList": "Your Swap List",
+    "yourSwapOffers": "Your Swap Offers"
   },
   "swaps": "Swaps",
   "tabs": {
@@ -2001,6 +2006,8 @@
       "week": "7D"
     }
   },
+  "trade": { "selectSendItem": "Select NFT First" },
+  "trades": { "incomingTrades": "Incoming Offers/Trades" },
   "transaction": {
     "acceptOffer": "Accept Offer",
     "acceptSwap": "Accept Swap",
diff --git a/pages/[prefix]/collection/[id]/offers.vue b/pages/[prefix]/collection/[id]/offers.vue
new file mode 100644
index 0000000000..e07c28f4c7
--- /dev/null
+++ b/pages/[prefix]/collection/[id]/offers.vue
@@ -0,0 +1,13 @@
+<template>
+  <ExploreLayoutWithSidebar>
+    <CollectionTrades :trade-type="TradeType.OFFER" />
+  </ExploreLayoutWithSidebar>
+</template>
+
+<script setup lang="ts">
+import { TradeType } from '@/components/trade/types'
+
+definePageMeta({
+  layout: 'explore-layout',
+})
+</script>
diff --git a/pages/[prefix]/collection/[id]/swaps.vue b/pages/[prefix]/collection/[id]/swaps.vue
index d2bb971e23..ed4fe5e20c 100644
--- a/pages/[prefix]/collection/[id]/swaps.vue
+++ b/pages/[prefix]/collection/[id]/swaps.vue
@@ -1,10 +1,12 @@
 <template>
   <ExploreLayoutWithSidebar>
-    <CollectionSwaps />
+    <CollectionTrades :trade-type="TradeType.SWAP" />
   </ExploreLayoutWithSidebar>
 </template>
 
 <script setup lang="ts">
+import { TradeType } from '@/components/trade/types'
+
 definePageMeta({
   layout: 'explore-layout',
 })
diff --git a/queries/subsquid/general/collectionIdList.graphql b/queries/subsquid/general/collectionIdList.graphql
new file mode 100644
index 0000000000..1b81b8aaba
--- /dev/null
+++ b/queries/subsquid/general/collectionIdList.graphql
@@ -0,0 +1,11 @@
+query collectionIdList(
+  $search: CollectionEntityWhereInput
+  $orderBy: [CollectionEntityOrderByInput!] = [blockNumber_DESC]
+) {
+  collectionEntities(
+    orderBy: $orderBy
+    where: $search
+  ) {
+      id
+  }
+}
diff --git a/utils/datetime.ts b/utils/datetime.ts
index 22f445447b..b2702ef7d9 100644
--- a/utils/datetime.ts
+++ b/utils/datetime.ts
@@ -1,4 +1,5 @@
-import { isWithinInterval, subDays } from 'date-fns'
+import { isWithinInterval, subDays, formatDistanceToNow as dfnsFormatDistanceToNow } from 'date-fns'
+import { enUS } from 'date-fns/locale'
 
 export function parseDate(ts: number | Date): string {
   return new Date(ts).toLocaleString()
@@ -9,3 +10,25 @@ export const isDateWithinLastDays = (date: Date, days: number) =>
     start: subDays(new Date(), days),
     end: new Date(),
   })
+
+export const formatDistanceToNow = (date: Date) => {
+  return dfnsFormatDistanceToNow(date, {
+    addSuffix: false,
+    locale: {
+      ...enUS,
+      formatDistance: (token, count) => {
+        const formats = {
+          xSeconds: count => `${count}s`,
+          xMinutes: count => `${count}m`,
+          xHours: count => `${count}h`,
+          xDays: count => `${count}d`,
+          lessThanXSeconds: count => `<${count}s`,
+          lessThanXMinutes: count => `<${count}m`,
+          aboutXHours: count => `${count}h`,
+        }
+
+        return formats[token](count)
+      },
+    },
+  })
+}
diff --git a/utils/swap.ts b/utils/swap.ts
index 7326fbca94..d2a638b655 100644
--- a/utils/swap.ts
+++ b/utils/swap.ts
@@ -1,4 +1,5 @@
 import { SwapStep } from '@/components/swap/types'
+import type { TradeToken } from '@/components/trade/types'
 import type { NFT } from '@/types'
 
 export const SWAP_ROUTE_NAME_STEP_MAP = {
diff --git a/utils/trades.ts b/utils/trades.ts
new file mode 100644
index 0000000000..cf82da020e
--- /dev/null
+++ b/utils/trades.ts
@@ -0,0 +1,33 @@
+export const buildIncomingTradesQuery = (address: string, considereds: string[], { stringify = false } = {}) => {
+  const query = {
+    AND: [
+      {
+        status_eq: 'ACTIVE',
+        caller_not_eq: address,
+      },
+      {
+        OR: [
+          { desired: { currentOwner_eq: address } },
+          {
+            considered: {
+              id_in: considereds,
+            },
+            desired_isNull: true,
+          },
+        ],
+      },
+    ],
+  }
+
+  // Both version of this query are needed, one as string and one as object
+  // super hacky, but it works
+  if (stringify) {
+    return JSON.stringify(query)
+      // Remove quotes around keys (e.g., "status_eq": becomes status_eq:)
+      .replace(/"(\w+)":/g, '$1:')
+      // Remove quotes around uppercase values (e.g., "ACTIVE" becomes ACTIVE)
+      .replace(/"([A-Z]+)"/g, '$1')
+  }
+
+  return query
+}