@1001-digital/layers.evm 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/components/EvmTransactionFlow.vue +123 -139
- package/package.json +1 -1
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<slot
|
|
2
|
+
<slot
|
|
3
|
+
:start="start"
|
|
4
|
+
:step="step"
|
|
5
|
+
:open="open"
|
|
6
|
+
name="start"
|
|
7
|
+
></slot>
|
|
3
8
|
|
|
4
9
|
<Dialog
|
|
5
10
|
v-model:open="open"
|
|
@@ -11,12 +16,21 @@
|
|
|
11
16
|
|
|
12
17
|
<h1 v-if="text.title[step]">{{ text.title[step] }}</h1>
|
|
13
18
|
|
|
19
|
+
<Loading
|
|
20
|
+
v-if="step === 'requesting' || step === 'waiting'"
|
|
21
|
+
spinner
|
|
22
|
+
txt=""
|
|
23
|
+
/>
|
|
24
|
+
|
|
14
25
|
<div class="text">
|
|
15
26
|
<p v-if="text.lead[step]">{{ text.lead[step] }}</p>
|
|
16
27
|
<p v-if="error">{{ error }}</p>
|
|
17
28
|
</div>
|
|
18
29
|
|
|
19
|
-
<slot
|
|
30
|
+
<slot
|
|
31
|
+
:name="step"
|
|
32
|
+
:cancel="cancel"
|
|
33
|
+
></slot>
|
|
20
34
|
|
|
21
35
|
<Button
|
|
22
36
|
v-if="step === 'waiting'"
|
|
@@ -24,59 +38,75 @@
|
|
|
24
38
|
target="_blank"
|
|
25
39
|
class="block-explorer"
|
|
26
40
|
>
|
|
27
|
-
|
|
28
|
-
<span>View on Block Explorer</span>
|
|
41
|
+
View on Block Explorer
|
|
29
42
|
</Button>
|
|
30
43
|
|
|
31
44
|
<Actions v-if="step === 'chain'">
|
|
32
|
-
<Button
|
|
45
|
+
<Button
|
|
46
|
+
@click="cancel"
|
|
47
|
+
class="secondary"
|
|
48
|
+
>Cancel</Button
|
|
49
|
+
>
|
|
33
50
|
</Actions>
|
|
34
51
|
|
|
35
52
|
<Actions v-if="step === 'confirm' || step === 'error'">
|
|
36
|
-
<Button
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
53
|
+
<Button
|
|
54
|
+
@click="cancel"
|
|
55
|
+
class="secondary"
|
|
56
|
+
>Cancel</Button
|
|
57
|
+
>
|
|
58
|
+
<Button @click="() => initializeRequest()">
|
|
59
|
+
{{ text.action[step] || 'Execute' }}
|
|
60
|
+
</Button>
|
|
40
61
|
</Actions>
|
|
41
62
|
</Dialog>
|
|
42
63
|
</template>
|
|
43
64
|
|
|
44
65
|
<script setup lang="ts">
|
|
45
|
-
import { waitForTransactionReceipt, watchChainId } from
|
|
46
|
-
import type { Config } from
|
|
47
|
-
import type { TransactionReceipt, Hash } from
|
|
66
|
+
import { waitForTransactionReceipt, watchChainId } from '@wagmi/core'
|
|
67
|
+
import type { Config } from '@wagmi/vue'
|
|
68
|
+
import type { TransactionReceipt, Hash } from 'viem'
|
|
48
69
|
|
|
49
70
|
interface TextConfig {
|
|
50
|
-
title: Record<string, string
|
|
51
|
-
lead: Record<string, string
|
|
52
|
-
action: Record<string, string
|
|
71
|
+
title: Record<string, string>
|
|
72
|
+
lead: Record<string, string>
|
|
73
|
+
action: Record<string, string>
|
|
53
74
|
}
|
|
54
75
|
|
|
55
|
-
|
|
76
|
+
type Step =
|
|
77
|
+
| 'idle'
|
|
78
|
+
| 'confirm'
|
|
79
|
+
| 'chain'
|
|
80
|
+
| 'requesting'
|
|
81
|
+
| 'waiting'
|
|
82
|
+
| 'complete'
|
|
83
|
+
| 'error'
|
|
84
|
+
|
|
85
|
+
const checkChain = useEnsureChainIdCheck()
|
|
56
86
|
|
|
57
|
-
const { $wagmi } = useNuxtApp()
|
|
58
|
-
const blockExplorer = useBlockExplorer()
|
|
87
|
+
const { $wagmi } = useNuxtApp()
|
|
88
|
+
const blockExplorer = useBlockExplorer()
|
|
59
89
|
|
|
60
90
|
const props = withDefaults(
|
|
61
91
|
defineProps<{
|
|
62
|
-
text?: TextConfig
|
|
63
|
-
request?: () => Promise<Hash
|
|
64
|
-
delayAfter?: number
|
|
65
|
-
delayAutoclose?: number
|
|
66
|
-
skipConfirmation?: boolean
|
|
67
|
-
autoCloseSuccess?: boolean
|
|
68
|
-
dismissable?: boolean
|
|
92
|
+
text?: TextConfig
|
|
93
|
+
request?: () => Promise<Hash>
|
|
94
|
+
delayAfter?: number
|
|
95
|
+
delayAutoclose?: number
|
|
96
|
+
skipConfirmation?: boolean
|
|
97
|
+
autoCloseSuccess?: boolean
|
|
98
|
+
dismissable?: boolean
|
|
69
99
|
}>(),
|
|
70
100
|
{
|
|
71
101
|
text: () => ({
|
|
72
102
|
title: {
|
|
73
|
-
confirm:
|
|
103
|
+
confirm: 'Confirm Transaction',
|
|
74
104
|
},
|
|
75
105
|
lead: {
|
|
76
|
-
confirm:
|
|
106
|
+
confirm: 'Please review and confirm this transaction.',
|
|
77
107
|
},
|
|
78
108
|
action: {
|
|
79
|
-
confirm:
|
|
109
|
+
confirm: 'Execute',
|
|
80
110
|
},
|
|
81
111
|
}),
|
|
82
112
|
delayAfter: 2000,
|
|
@@ -85,147 +115,112 @@ const props = withDefaults(
|
|
|
85
115
|
autoCloseSuccess: true,
|
|
86
116
|
dismissable: true,
|
|
87
117
|
},
|
|
88
|
-
)
|
|
118
|
+
)
|
|
89
119
|
|
|
90
120
|
const emit = defineEmits<{
|
|
91
|
-
complete: [receipt: TransactionReceipt]
|
|
92
|
-
cancel: []
|
|
93
|
-
}>()
|
|
121
|
+
complete: [receipt: TransactionReceipt]
|
|
122
|
+
cancel: []
|
|
123
|
+
}>()
|
|
124
|
+
|
|
125
|
+
const step = ref<Step>('idle')
|
|
94
126
|
|
|
95
|
-
const open =
|
|
127
|
+
const open = computed({
|
|
128
|
+
get: () => step.value !== 'idle',
|
|
129
|
+
set: (v) => {
|
|
130
|
+
if (!v) step.value = 'idle'
|
|
131
|
+
},
|
|
132
|
+
})
|
|
96
133
|
|
|
97
|
-
const switchChain = ref(false);
|
|
98
134
|
watchChainId($wagmi as Config, {
|
|
99
135
|
async onChange() {
|
|
100
|
-
if (
|
|
136
|
+
if (step.value !== 'chain') return
|
|
101
137
|
|
|
102
138
|
if (await checkChain()) {
|
|
103
|
-
|
|
104
|
-
initializeRequest();
|
|
105
|
-
} else {
|
|
106
|
-
switchChain.value = true;
|
|
139
|
+
initializeRequest()
|
|
107
140
|
}
|
|
108
141
|
},
|
|
109
|
-
})
|
|
142
|
+
})
|
|
110
143
|
|
|
111
|
-
const cachedRequest = ref(props.request)
|
|
144
|
+
const cachedRequest = ref(props.request)
|
|
112
145
|
watch(
|
|
113
146
|
() => props.request,
|
|
114
|
-
() => {
|
|
115
|
-
cachedRequest.value =
|
|
147
|
+
(v) => {
|
|
148
|
+
cachedRequest.value = v
|
|
116
149
|
},
|
|
117
|
-
)
|
|
118
|
-
|
|
119
|
-
const requesting = ref(false);
|
|
120
|
-
const waiting = ref(false);
|
|
121
|
-
const complete = ref(false);
|
|
122
|
-
const error = ref("");
|
|
123
|
-
const tx = ref<Hash | null>(null);
|
|
124
|
-
const receipt = ref<TransactionReceipt | null>(null);
|
|
125
|
-
const txLink = computed(() => `${blockExplorer}/tx/${tx.value}`);
|
|
126
|
-
|
|
127
|
-
const step = computed(() => {
|
|
128
|
-
if (
|
|
129
|
-
open.value &&
|
|
130
|
-
!requesting.value &&
|
|
131
|
-
!switchChain.value &&
|
|
132
|
-
!waiting.value &&
|
|
133
|
-
!complete.value
|
|
134
|
-
) {
|
|
135
|
-
return "confirm";
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
if (switchChain.value) {
|
|
139
|
-
return "chain";
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
if (requesting.value) {
|
|
143
|
-
return "requesting";
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
if (waiting.value) {
|
|
147
|
-
return "waiting";
|
|
148
|
-
}
|
|
150
|
+
)
|
|
149
151
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
return "error";
|
|
155
|
-
});
|
|
152
|
+
const error = ref('')
|
|
153
|
+
const tx = ref<Hash | null>(null)
|
|
154
|
+
const receipt = ref<TransactionReceipt | null>(null)
|
|
155
|
+
const txLink = computed(() => `${blockExplorer}/tx/${tx.value}`)
|
|
156
156
|
|
|
157
157
|
const canDismiss = computed(
|
|
158
|
-
() =>
|
|
159
|
-
|
|
158
|
+
() =>
|
|
159
|
+
props.dismissable &&
|
|
160
|
+
step.value !== 'requesting' &&
|
|
161
|
+
step.value !== 'waiting',
|
|
162
|
+
)
|
|
160
163
|
|
|
161
164
|
const initializeRequest = async (request = cachedRequest.value) => {
|
|
162
|
-
cachedRequest.value = request
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
receipt.value = null;
|
|
165
|
+
cachedRequest.value = request
|
|
166
|
+
error.value = ''
|
|
167
|
+
tx.value = null
|
|
168
|
+
receipt.value = null
|
|
169
|
+
step.value = 'confirm'
|
|
168
170
|
|
|
169
171
|
if (!(await checkChain())) {
|
|
170
|
-
|
|
171
|
-
return
|
|
172
|
-
} else {
|
|
173
|
-
switchChain.value = false;
|
|
172
|
+
step.value = 'chain'
|
|
173
|
+
return
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
-
if (requesting.value) return;
|
|
177
|
-
|
|
178
176
|
try {
|
|
179
|
-
|
|
180
|
-
tx.value = await request!()
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
complete.value = true;
|
|
177
|
+
step.value = 'requesting'
|
|
178
|
+
tx.value = await request!()
|
|
179
|
+
step.value = 'waiting'
|
|
180
|
+
const receiptObject = await waitForTransactionReceipt($wagmi as Config, {
|
|
181
|
+
hash: tx.value,
|
|
182
|
+
})
|
|
183
|
+
await delay(props.delayAfter)
|
|
184
|
+
receipt.value = receiptObject
|
|
185
|
+
emit('complete', receiptObject)
|
|
186
|
+
step.value = 'complete'
|
|
190
187
|
} catch (e: unknown) {
|
|
191
|
-
const err = e as { cause?: { code?: number }; shortMessage?: string }
|
|
188
|
+
const err = e as { cause?: { code?: number }; shortMessage?: string }
|
|
192
189
|
if (err?.cause?.code === 4001) {
|
|
193
|
-
|
|
190
|
+
step.value = 'idle'
|
|
194
191
|
} else {
|
|
195
|
-
error.value = err.shortMessage ||
|
|
192
|
+
error.value = err.shortMessage || 'Error submitting transaction request.'
|
|
193
|
+
step.value = 'error'
|
|
196
194
|
}
|
|
197
|
-
console.log(e)
|
|
195
|
+
console.log(e)
|
|
198
196
|
}
|
|
199
197
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
await delay(props.delayAutoclose);
|
|
205
|
-
open.value = false;
|
|
206
|
-
await delay(300);
|
|
198
|
+
if (props.autoCloseSuccess && step.value === 'complete') {
|
|
199
|
+
await delay(props.delayAutoclose)
|
|
200
|
+
step.value = 'idle'
|
|
201
|
+
await delay(300)
|
|
207
202
|
}
|
|
208
203
|
|
|
209
|
-
return receipt.value
|
|
210
|
-
}
|
|
204
|
+
return receipt.value
|
|
205
|
+
}
|
|
211
206
|
|
|
212
207
|
const start = () => {
|
|
213
|
-
if (props.skipConfirmation &&
|
|
214
|
-
initializeRequest()
|
|
208
|
+
if (props.skipConfirmation && step.value === 'idle') {
|
|
209
|
+
initializeRequest()
|
|
210
|
+
return
|
|
215
211
|
}
|
|
216
212
|
|
|
217
|
-
|
|
218
|
-
}
|
|
213
|
+
step.value = 'confirm'
|
|
214
|
+
}
|
|
219
215
|
|
|
220
216
|
const cancel = () => {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
};
|
|
217
|
+
step.value = 'idle'
|
|
218
|
+
emit('cancel')
|
|
219
|
+
}
|
|
225
220
|
|
|
226
221
|
defineExpose({
|
|
227
222
|
initializeRequest,
|
|
228
|
-
})
|
|
223
|
+
})
|
|
229
224
|
</script>
|
|
230
225
|
|
|
231
226
|
<style>
|
|
@@ -233,22 +228,11 @@ defineExpose({
|
|
|
233
228
|
display: grid;
|
|
234
229
|
gap: var(--spacer);
|
|
235
230
|
|
|
236
|
-
.spinner {
|
|
237
|
-
width: var(--size-7);
|
|
238
|
-
height: var(--size-7);
|
|
239
|
-
margin: calc(-1 * var(--size-4)) 0 var(--size-3);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
231
|
.text {
|
|
243
232
|
width: 100%;
|
|
244
233
|
height: min-content;
|
|
245
234
|
}
|
|
246
235
|
|
|
247
|
-
h1 {
|
|
248
|
-
font-size: var(--font-lg);
|
|
249
|
-
margin-bottom: var(--size-4);
|
|
250
|
-
}
|
|
251
|
-
|
|
252
236
|
p {
|
|
253
237
|
white-space: pre-wrap;
|
|
254
238
|
width: 100%;
|