+
+
{{ $t('swap.counterparty') }}
From 1923237d2771c1ed42ad700548c7f65555b28157 Mon Sep 17 00:00:00 2001
From: hassnian <44554284+hassnian@users.noreply.github.com>
Date: Thu, 7 Nov 2024 09:46:26 +0500
Subject: [PATCH 11/40] add(swaps): swap middleware & review step
---
components/swap/DestinationProfile.vue | 11 ++++-------
components/swap/GridList.vue | 2 ++
components/swap/YourProfile.vue | 17 +++++++++--------
components/swap/review.vue | 17 ++++++++++++++++-
middleware/swap.ts | 23 +++++++++++++++++++++++
pages/[prefix]/swap/[id]/index.vue | 1 +
pages/[prefix]/swap/[id]/offer.vue | 1 +
pages/[prefix]/swap/[id]/review.vue | 1 +
stores/atomicSwaps.ts | 5 ++---
9 files changed, 59 insertions(+), 19 deletions(-)
create mode 100644 middleware/swap.ts
diff --git a/components/swap/DestinationProfile.vue b/components/swap/DestinationProfile.vue
index d68c906ac1..6101034598 100644
--- a/components/swap/DestinationProfile.vue
+++ b/components/swap/DestinationProfile.vue
@@ -8,7 +8,10 @@
/>
-
+
{
await navigateTo({ name: 'prefix-swap-id-offer', params: { id: route.params.id } })
}
-
-onBeforeMount(() => {
- if (!lastSwap.value) {
- atomicSwapsStore.createSwap()
- }
-})
diff --git a/components/swap/GridList.vue b/components/swap/GridList.vue
index c501ba5f0c..2fa1cc608b 100644
--- a/components/swap/GridList.vue
+++ b/components/swap/GridList.vue
@@ -3,6 +3,7 @@
:search="query"
grid-size="medium"
:grid-section="gridSection"
+ :hide-hover-action="!selectable"
/>
@@ -13,5 +14,6 @@ const gridSection = GridSection.PROFILE_GALLERY
defineProps<{
query: Record
+ selectable?: boolean
}>()
diff --git a/components/swap/YourProfile.vue b/components/swap/YourProfile.vue
index 08991292f4..7302e146e4 100644
--- a/components/swap/YourProfile.vue
+++ b/components/swap/YourProfile.vue
@@ -8,7 +8,10 @@
/>
-
+
@@ -23,7 +27,6 @@
diff --git a/components/swap/review.vue b/components/swap/review.vue
index e5bf81fca3..0346b2f5cc 100644
--- a/components/swap/review.vue
+++ b/components/swap/review.vue
@@ -26,8 +26,13 @@
{{ $t('swap.reviewSelected') }}
+
+
-
+
{{ $t('swap.reviewCounterpartyAccept') }}
+
+
@@ -55,5 +65,10 @@
diff --git a/middleware/swap.ts b/middleware/swap.ts
new file mode 100644
index 0000000000..fbfc77db0d
--- /dev/null
+++ b/middleware/swap.ts
@@ -0,0 +1,23 @@
+export default defineNuxtRouteMiddleware((to) => {
+ const { toast } = useToast()
+ const atomicSwapsStore = useAtomicSwapsStore()
+ const { lastSwap, counterparty } = storeToRefs(atomicSwapsStore)
+
+ const id = to.params.id?.toString()
+
+ if (!id) {
+ return navigateTo({ name: 'prefix-swap' })
+ }
+
+ counterparty.value = id
+
+ if (to.name === 'prefix-swap-id' && !lastSwap.value) {
+ atomicSwapsStore.createSwap()
+ return
+ }
+
+ if (!lastSwap.value) {
+ toast('First select the NFTs you want to offer')
+ return navigateTo({ name: 'prefix-swap-id', params: { id } })
+ }
+})
diff --git a/pages/[prefix]/swap/[id]/index.vue b/pages/[prefix]/swap/[id]/index.vue
index 5cfb562e5c..36e190dc1e 100644
--- a/pages/[prefix]/swap/[id]/index.vue
+++ b/pages/[prefix]/swap/[id]/index.vue
@@ -5,5 +5,6 @@
diff --git a/pages/[prefix]/swap/[id]/offer.vue b/pages/[prefix]/swap/[id]/offer.vue
index 423b8a153d..fec12ce6a8 100644
--- a/pages/[prefix]/swap/[id]/offer.vue
+++ b/pages/[prefix]/swap/[id]/offer.vue
@@ -5,5 +5,6 @@
diff --git a/pages/[prefix]/swap/[id]/review.vue b/pages/[prefix]/swap/[id]/review.vue
index 4c2a4be72a..2802fd2a61 100644
--- a/pages/[prefix]/swap/[id]/review.vue
+++ b/pages/[prefix]/swap/[id]/review.vue
@@ -5,5 +5,6 @@
diff --git a/stores/atomicSwaps.ts b/stores/atomicSwaps.ts
index 0f82fc5c25..63ffa2bbf6 100644
--- a/stores/atomicSwaps.ts
+++ b/stores/atomicSwaps.ts
@@ -29,10 +29,8 @@ export const useAtomicSwapsStore = defineStore('atomicSwaps', () => {
const { accountId } = useAuth()
const { urlPrefix } = usePrefix()
const getItems = computed(() => items.value)
- const route = useRoute()
- // make a ref
- const counterparty = computed(() => route.params.id.toString() as string)
+ const counterparty = ref()
const lastSwap = computed(() => {
const atomicSwaps = items.value
@@ -63,6 +61,7 @@ export const useAtomicSwapsStore = defineStore('atomicSwaps', () => {
return {
// state
items,
+ counterparty,
// getters
chain,
count,
From 6e0c279b33830439fe644ea8137d6126260ddb99 Mon Sep 17 00:00:00 2001
From: hassnian <44554284+hassnian@users.noreply.github.com>
Date: Thu, 7 Nov 2024 16:28:34 +0500
Subject: [PATCH 12/40] add(swaps): pesist store and step
---
.../items/ItemsGrid/useAtomicSwapAction.ts | 21 +++++-----
components/swap/DestinationProfile.vue | 13 ++++---
components/swap/YourProfile.vue | 9 +++--
components/swap/review.vue | 6 +--
middleware/swap.ts | 18 +++++++--
stores/atomicSwaps.ts | 39 ++++++++++++++-----
6 files changed, 70 insertions(+), 36 deletions(-)
diff --git a/components/items/ItemsGrid/useAtomicSwapAction.ts b/components/items/ItemsGrid/useAtomicSwapAction.ts
index 964c779c97..57ef86d707 100644
--- a/components/items/ItemsGrid/useAtomicSwapAction.ts
+++ b/components/items/ItemsGrid/useAtomicSwapAction.ts
@@ -8,42 +8,41 @@ export const ATOMIC_SWAP_PAGES = [
export default (nft: NFTWithMetadata) => {
const route = useRoute()
- const { lastSwap } = storeToRefs(useAtomicSwapsStore())
+ const { swap, step } = storeToRefs(useAtomicSwapsStore())
const routeName = computed(() => route.name?.toString() as string)
const showAtomicSwapAction = computed(() => ATOMIC_SWAP_PAGES.includes(routeName.value))
- const isDesiredSelection = computed(() => routeName.value === 'prefix-swap-id')
- const isOfferedSelection = computed(() => routeName.value === 'prefix-swap-id-offer')
-
const itemsKey = computed(() => {
- if (isDesiredSelection.value) {
+ if (step.value === SwapStep.DESIRED) {
return 'desired'
}
- if (isOfferedSelection.value) {
+ if (step.value === SwapStep.OFFERED) {
return 'offered'
}
})
const items = computed(() => {
- const items = lastSwap.value?.[itemsKey.value || '']
+ const items = swap.value?.[itemsKey.value || '']
return items
})
- const isItemSelected = computed(() => items.value?.some(item => item.id === nft.id))
+ const isItemSelected = computed(() => {
+ return step.value === SwapStep.REVIEW ? false : items.value?.some(item => item.id === nft.id)
+ })
const onAtomicSwapSelect = () => {
- if (!itemsKey.value || !lastSwap.value) {
+ if (!itemsKey.value || !swap.value) {
return
}
if (isItemSelected.value) {
- lastSwap.value[itemsKey.value] = items.value.filter(item => item.id !== nft.id)
+ swap.value[itemsKey.value] = items.value.filter(item => item.id !== nft.id)
}
else {
- lastSwap.value[itemsKey.value].push(nft)
+ swap.value[itemsKey.value].push(nft)
}
}
diff --git a/components/swap/DestinationProfile.vue b/components/swap/DestinationProfile.vue
index 6101034598..dbca3c8faf 100644
--- a/components/swap/DestinationProfile.vue
+++ b/components/swap/DestinationProfile.vue
@@ -15,12 +15,15 @@
{
+ if (swap) {
+ swap.desired = []
+ }
+ }"
/>
@@ -31,7 +34,7 @@ const { accountId } = useAuth()
const route = useRoute()
const atomicSwapsStore = useAtomicSwapsStore()
-const { lastSwap } = storeToRefs(atomicSwapsStore)
+const { swap } = storeToRefs(atomicSwapsStore)
const query = reactive({
currentOwner_eq: route.params.id,
diff --git a/components/swap/YourProfile.vue b/components/swap/YourProfile.vue
index 7302e146e4..39d04f4ec2 100644
--- a/components/swap/YourProfile.vue
+++ b/components/swap/YourProfile.vue
@@ -15,10 +15,11 @@
@@ -27,7 +28,7 @@
diff --git a/middleware/swap.ts b/middleware/swap.ts
index fbfc77db0d..64c856a4e9 100644
--- a/middleware/swap.ts
+++ b/middleware/swap.ts
@@ -1,7 +1,8 @@
export default defineNuxtRouteMiddleware((to) => {
const { toast } = useToast()
+ const { accountId } = useAuth()
const atomicSwapsStore = useAtomicSwapsStore()
- const { lastSwap, counterparty } = storeToRefs(atomicSwapsStore)
+ const { swap, counterparty } = storeToRefs(atomicSwapsStore)
const id = to.params.id?.toString()
@@ -11,12 +12,21 @@ export default defineNuxtRouteMiddleware((to) => {
counterparty.value = id
- if (to.name === 'prefix-swap-id' && !lastSwap.value) {
- atomicSwapsStore.createSwap()
+ watchEffect(() => {
+ if (swap.value) {
+ atomicSwapsStore.updateItem({
+ ...swap.value,
+ creator: accountId.value ? accountId.value : undefined,
+ })
+ }
+ })
+
+ if (to.name === 'prefix-swap-id' && !swap.value) {
+ atomicSwapsStore.createSwap(id)
return
}
- if (!lastSwap.value) {
+ if (!swap.value) {
toast('First select the NFTs you want to offer')
return navigateTo({ name: 'prefix-swap-id', params: { id } })
}
diff --git a/stores/atomicSwaps.ts b/stores/atomicSwaps.ts
index 63ffa2bbf6..c494ecea87 100644
--- a/stores/atomicSwaps.ts
+++ b/stores/atomicSwaps.ts
@@ -3,16 +3,23 @@ import { computed } from 'vue'
export type AtomicSwap = {
counterparty: string
- offerer: string
+ creator?: string
offered: SwapItem[]
desired: SwapItem[]
createdAt: number
+ surcharge: { receive?: string, send?: string }
} & CartItem
type SwapItem = {
id: string
}
+export enum SwapStep {
+ DESIRED = 'desired',
+ OFFERED = 'offered',
+ REVIEW = 'review',
+}
+
export const useAtomicSwapsStore = defineStore('atomicSwaps', () => {
const {
items,
@@ -30,27 +37,40 @@ export const useAtomicSwapsStore = defineStore('atomicSwaps', () => {
const { urlPrefix } = usePrefix()
const getItems = computed(() => items.value)
+ const route = useRoute()
+ const routeName = computed(() => route.name?.toString())
+
+ const step = computed(() => {
+ return routeName.value
+ ? {
+ 'prefix-swap-id': SwapStep.DESIRED,
+ 'prefix-swap-id-offer': SwapStep.OFFERED,
+ 'prefix-swap-id-review': SwapStep.REVIEW,
+ }[routeName.value]
+ : undefined
+ })
+
const counterparty = ref()
- const lastSwap = computed(() => {
+ const swap = computed
(() => {
const atomicSwaps = items.value
.filter(item =>
item.counterparty === counterparty.value
- && item.urlPrefix === urlPrefix.value
- && item.offerer === accountId.value,
+ && item.urlPrefix === urlPrefix.value,
).sort((a, b) => b.createdAt - a.createdAt)
return atomicSwaps[0]
})
- const createSwap = () => {
+ const createSwap = (counterparty: string) => {
const newAtomicSwap: AtomicSwap = {
id: window.crypto.randomUUID(),
- counterparty: counterparty.value,
- offerer: accountId.value,
+ counterparty,
offered: [],
desired: [],
createdAt: Date.now(),
urlPrefix: urlPrefix.value,
+ surcharge: {},
+ creator: accountId.value ? accountId.value : undefined,
}
setItem(newAtomicSwap)
@@ -67,13 +87,14 @@ export const useAtomicSwapsStore = defineStore('atomicSwaps', () => {
count,
itemsInChain,
getItems,
+ step,
// actions
getItem,
- lastSwap,
+ swap,
setItem,
updateItem,
removeItem,
clear,
createSwap,
}
-})
+}, { persist: true })
From d0d6ad3493fd8a5b307499df95362a3b50b142e2 Mon Sep 17 00:00:00 2001
From: hassnian <44554284+hassnian@users.noreply.github.com>
Date: Sat, 9 Nov 2024 16:21:18 +0500
Subject: [PATCH 13/40] add(swaps): init `createSwap` transaction
---
components/items/ItemsGrid/ItemsGridImage.vue | 2 +-
.../items/ItemsGrid/useAtomicSwapAction.ts | 8 +-
components/offer/OfferExpirationSelector.vue | 13 ++-
components/swap/DestinationProfile.vue | 11 ++-
components/swap/Preview.vue | 18 +++++
components/swap/YourProfile.vue | 11 ++-
components/swap/review.vue | 74 ++++++++++++++++-
.../transaction/transactionCreateSwap.ts | 80 +++++++++++++++++++
composables/transaction/transactionOffer.ts | 2 +-
composables/transaction/types.ts | 24 ++++++
composables/transaction/utils.ts | 3 +
composables/useTransaction.ts | 10 +++
locales/en.json | 4 +
stores/atomicSwaps.ts | 12 ++-
utils/shoppingActions.ts | 1 +
15 files changed, 257 insertions(+), 16 deletions(-)
create mode 100644 composables/transaction/transactionCreateSwap.ts
diff --git a/components/items/ItemsGrid/ItemsGridImage.vue b/components/items/ItemsGrid/ItemsGridImage.vue
index 070c419f1a..eabddf547d 100644
--- a/components/items/ItemsGrid/ItemsGridImage.vue
+++ b/components/items/ItemsGrid/ItemsGridImage.vue
@@ -28,7 +28,7 @@
#action
>
{
swap.value[itemsKey.value] = items.value.filter(item => item.id !== nft.id)
}
else {
- swap.value[itemsKey.value].push(nft)
+ swap.value[itemsKey.value].push({
+ id: nft.id,
+ collectionId: nft.collection.id,
+ sn: nft.sn,
+ name: nft.name,
+ meta: nft.meta,
+ })
}
}
diff --git a/components/offer/OfferExpirationSelector.vue b/components/offer/OfferExpirationSelector.vue
index b644913bd8..0904d3b89f 100644
--- a/components/offer/OfferExpirationSelector.vue
+++ b/components/offer/OfferExpirationSelector.vue
@@ -3,7 +3,7 @@
v-model="selected"
aria-role="list"
:triggers="['click']"
- position="bottom-left"
+ :position="position"
append-to-body
close-menu-on-move
class="w-full"
@@ -54,9 +54,14 @@ const options = EXPIRATION_DAYS_LIST.map(value => ({
const selectedItem = computed(() => options.find(option => option.value === selected.value))
-const props = defineProps<{
- modelValue?: number
-}>()
+const props = withDefaults(
+ defineProps<{
+ modelValue?: number
+ position?: string
+ }>(), {
+ position: 'bottom-left',
+ },
+)
const emit = defineEmits(['update:modelValue'])
diff --git a/components/swap/DestinationProfile.vue b/components/swap/DestinationProfile.vue
index dbca3c8faf..a0af27587a 100644
--- a/components/swap/DestinationProfile.vue
+++ b/components/swap/DestinationProfile.vue
@@ -1,5 +1,5 @@
-
+
{
if (swap) {
@@ -45,4 +48,10 @@ const query = reactive({
const onNext = async () => {
await navigateTo({ name: 'prefix-swap-id-offer', params: { id: route.params.id } })
}
+
+const onSurchargeUpdate = (amount: string) => {
+ if (swap.value) {
+ swap.value.surcharge = amount ? { amount, direction: 'Receive' } : undefined
+ }
+}
diff --git a/components/swap/Preview.vue b/components/swap/Preview.vue
index 0e4dafb586..bbf7833895 100644
--- a/components/swap/Preview.vue
+++ b/components/swap/Preview.vue
@@ -48,6 +48,20 @@