@mictonode/widget 0.3.16 → 0.3.18

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.
Files changed (69) hide show
  1. package/.github/FUNDING.yml +3 -3
  2. package/.github/workflows/npm-publish.yml +34 -34
  3. package/.prettierrc.json +9 -9
  4. package/.vscode/extensions.json +3 -3
  5. package/LICENSE +674 -674
  6. package/README.md +41 -41
  7. package/dist/{main-d0e5d1e4.js → main-bbea3e54.js} +155 -153
  8. package/dist/ping-widget.js +2 -2
  9. package/dist/ping-widget.umd.cjs +18 -18
  10. package/dist/{query.lcd-3d4d3495.js → query.lcd-88036522.js} +1 -1
  11. package/dist/{query.rpc.Query-b7807c29.js → query.rpc.Query-3a2b14f8.js} +1 -1
  12. package/dist/{tx.rpc.msg-59c3408a.js → tx.rpc.msg-39f0b824.js} +1 -1
  13. package/example/.vscode/extensions.json +3 -3
  14. package/example/README.md +7 -7
  15. package/example/index.html +12 -12
  16. package/example/package.json +19 -19
  17. package/example/pnpm-lock.yaml +465 -465
  18. package/example/public/cdn.html +19 -19
  19. package/example/src/App.vue +73 -73
  20. package/example/src/main.js +4 -4
  21. package/example/vite.config.js +7 -7
  22. package/index.html +12 -12
  23. package/lib/components/ConnectWallet/index.vue +262 -262
  24. package/lib/components/TokenConvert/index.vue +1033 -1033
  25. package/lib/components/TokenConvert/tokens.ts +36 -36
  26. package/lib/components/TxDialog/index.vue +422 -422
  27. package/lib/components/TxDialog/messages/Delegate.vue +174 -174
  28. package/lib/components/TxDialog/messages/Deposit.vue +96 -96
  29. package/lib/components/TxDialog/messages/Redelegate.vue +160 -160
  30. package/lib/components/TxDialog/messages/Send.vue +142 -142
  31. package/lib/components/TxDialog/messages/Transfer.vue +248 -248
  32. package/lib/components/TxDialog/messages/Unbond.vue +103 -103
  33. package/lib/components/TxDialog/messages/Vote.vue +62 -62
  34. package/lib/components/TxDialog/messages/Withdraw.vue +55 -55
  35. package/lib/components/TxDialog/messages/WithdrawCommission.vue +74 -74
  36. package/lib/components/TxDialog/wasm/ClearAdmin.vue +55 -55
  37. package/lib/components/TxDialog/wasm/ExecuteContract.vue +98 -98
  38. package/lib/components/TxDialog/wasm/InstantiateContract.vue +108 -108
  39. package/lib/components/TxDialog/wasm/MigrateContract.vue +76 -76
  40. package/lib/components/TxDialog/wasm/MigrateContract2.vue +76 -76
  41. package/lib/components/TxDialog/wasm/StoreCode.vue +100 -100
  42. package/lib/components/TxDialog/wasm/UpdateAdmin.vue +74 -74
  43. package/lib/main.css +591 -7
  44. package/lib/main.ts +24 -23
  45. package/lib/utils/TokenUnitConverter.ts +44 -44
  46. package/lib/utils/format.ts +16 -16
  47. package/lib/utils/http.ts +154 -154
  48. package/lib/utils/type.ts +56 -56
  49. package/lib/wallet/EthermintMessageAdapter.ts +135 -135
  50. package/lib/wallet/UniClient.ts +144 -144
  51. package/lib/wallet/Wallet.ts +142 -142
  52. package/lib/wallet/wallets/KeplerWallet.ts +141 -141
  53. package/lib/wallet/wallets/LeapWallet.ts +141 -141
  54. package/lib/wallet/wallets/LedgerWallet.ts +202 -202
  55. package/lib/wallet/wallets/MetamaskSnapWallet.ts +105 -105
  56. package/lib/wallet/wallets/MetamaskWallet.ts +173 -173
  57. package/lib/wallet/wallets/OKXWallet.ts +202 -202
  58. package/lib/wallet/wallets/UnisatWallet.ts +198 -198
  59. package/package.json +5 -6
  60. package/postcss.config.js +6 -6
  61. package/src/App.vue +225 -225
  62. package/src/main.ts +7 -4
  63. package/src/styles/design-system.css +184 -0
  64. package/src/vite-env.d.ts +1 -1
  65. package/tailwind.config.js +158 -34
  66. package/tsconfig.json +25 -25
  67. package/tsconfig.node.json +10 -10
  68. package/vite.config.ts +62 -62
  69. package/vue-shim.d.ts +6 -6
@@ -1,422 +1,422 @@
1
- <script setup lang="ts">
2
- import { ref, computed } from 'vue';
3
- import {
4
- getAccount,
5
- getBalance,
6
- getBalanceMetadata,
7
- getIBCDenomMetadata,
8
- getLatestBlock,
9
- getStakingParam,
10
- getTxByHash,
11
- } from '../../utils/http';
12
- import { BroadcastMode, Coin, CoinMetadata } from '../../utils/type';
13
- import { WalletName, readWallet, isEvmChain } from '../../../lib/wallet/Wallet';
14
- import { UniClient } from '../../../lib/wallet/UniClient';
15
-
16
- // cosmos sdk messages
17
- import Delegate from './messages/Delegate.vue';
18
- import Deposit from './messages/Deposit.vue';
19
- import Redelegate from './messages/Redelegate.vue';
20
- import Send from './messages/Send.vue';
21
- import Transfer from './messages/Transfer.vue';
22
- import Unbond from './messages/Unbond.vue';
23
- import Vote from './messages/Vote.vue';
24
- import Withdraw from './messages/Withdraw.vue';
25
- import WithdrawCommission from './messages/WithdrawCommission.vue';
26
-
27
- // wasm msgs
28
- import StoreCode from './wasm/StoreCode.vue';
29
- import ExecuteContract from './wasm/ExecuteContract.vue';
30
- import InstantiateContract from './wasm/InstantiateContract.vue';
31
- import ChainRegistryClient from '@ping-pub/chain-registry-client';
32
- import MigrateContract from './wasm/MigrateContract.vue';
33
- import UpdateAdmin from './wasm/UpdateAdmin.vue';
34
- import ClearAdmin from './wasm/ClearAdmin.vue';
35
-
36
- const props = defineProps({
37
- type: String,
38
- endpoint: { type: String, required: true },
39
- sender: { type: String, required: true },
40
- hdPath: String,
41
- registryName: String,
42
- params: String,
43
- });
44
-
45
- const msgType = computed(() => {
46
- switch (props.type?.toLowerCase()) {
47
- case 'send':
48
- return Send;
49
- case 'delegate':
50
- return Delegate;
51
- case 'withdraw':
52
- return Withdraw;
53
- case 'withdraw_commission':
54
- return WithdrawCommission;
55
- case 'redelegate':
56
- return Redelegate;
57
- case 'transfer':
58
- return Transfer;
59
- case 'unbond':
60
- return Unbond;
61
- case 'vote':
62
- return Vote;
63
- case 'deposit':
64
- return Deposit;
65
- case 'wasm_store_code':
66
- return StoreCode;
67
- case 'wasm_execute_contract':
68
- return ExecuteContract;
69
- case 'wasm_instantiate_contract':
70
- return InstantiateContract;
71
- case 'wasm_migrate_contract':
72
- return MigrateContract;
73
- case 'wasm_update_admin':
74
- return UpdateAdmin;
75
- case 'wasm_clear_admin':
76
- return ClearAdmin;
77
- default:
78
- return Send;
79
- }
80
- });
81
-
82
- const advance = ref(false);
83
- const sending = ref(false);
84
- const balance = ref([] as Coin[]);
85
- const metadatas = ref({} as Record<string, CoinMetadata>);
86
- const emit = defineEmits(['submited', 'confirmed', 'view']);
87
-
88
- // functional variable
89
- const p = ref({} as { fees: Coin });
90
- const view = ref('input'); // input, submitting
91
- const open = ref(false);
92
- const error = ref('');
93
-
94
- // input field
95
- const msgBox = ref({
96
- msgs: [],
97
- isValid: { ok: false, error: '' },
98
- initial: function () { },
99
- });
100
- const feeAmount = ref(2000);
101
- const feeDenom = ref('');
102
- const gasInfo = ref(200000);
103
- const memo = ref('');
104
- const chainId = ref('cosmoshub-4');
105
- // const chainId = ref('taproot-1');
106
- const broadcast = ref(BroadcastMode.SYNC);
107
-
108
- async function initData() {
109
- if (open.value && props.endpoint && props.sender) {
110
- metadatas.value = {}
111
- view.value = 'input';
112
- p.value = JSON.parse(props.params || '{}')
113
- memo.value = props.type?.toLowerCase() === 'send' ? '' : 'mictonode.com'
114
-
115
- feeAmount.value = Number(p.value?.fees?.amount || 2000)
116
- feeDenom.value = balance.value[0]?.denom;
117
-
118
- try {
119
- getBalance(props.endpoint, props.sender).then((x) => {
120
- balance.value = x.balances;
121
- x.balances?.forEach((coin) => {
122
- // only load for native tokens
123
- if (coin.denom.length < 12)
124
- getBalanceMetadata(props.endpoint, coin.denom).then(
125
- (meta) => {
126
- if(meta.metadata) metadatas.value[coin.denom] = meta.metadata;
127
- }
128
- ).catch(()=>{});
129
- if(coin.denom.startsWith('ibc/')) {
130
- getIBCDenomMetadata(coin.denom).then(
131
- (meta) => {
132
- if(meta) metadatas.value[coin.denom] = meta;
133
- }
134
- ).catch(()=>{});
135
- }
136
- });
137
- });
138
-
139
- // load metadata from registry
140
- if (props.registryName && Object.keys(metadatas.value).length === 0) {
141
- const client = new ChainRegistryClient()
142
- client.fetchAssetsList(props.registryName).then(x => {
143
- x.assets.forEach(a => {
144
- metadatas.value[a.base] = a as CoinMetadata
145
- })
146
- }).catch(() => {
147
- console.log(`Chain: ${props.registryName } was not found on Cosmos Registry`)
148
- })
149
- }
150
- getLatestBlock(props.endpoint).then((x) => {
151
- chainId.value = x.block.header.chain_id;
152
- // Set higher default fee for EVM chains (Warden, Evmos, etc.)
153
- if (isEvmChain(chainId.value) && feeAmount.value < 250000) {
154
- feeAmount.value = 250000;
155
- }
156
- });
157
-
158
- // Every sub component should have a initial function
159
- if (msgBox.value && msgBox.value.initial) msgBox.value.initial();
160
-
161
- // load fee denom
162
- getStakingParam(props.endpoint).then((res) => {
163
- feeDenom.value = res?.params?.bond_denom;
164
- })
165
- } catch (err) {
166
- error.value = String(err);
167
- }
168
-
169
- // account.value = await getAccount(props.endpoint, props.sender).then(x => x.account);
170
- sending.value = false;
171
- }
172
- }
173
- async function sendTx() {
174
- try {
175
- if (!props.sender) throw new Error('Sender should not be empty!');
176
- if (!props.endpoint) throw new Error('Endpoint is empty');
177
- if (!feeDenom.value) throw new Error('Fee Denom is empty');
178
- if (!msgBox.value.isValid.ok)
179
- throw new Error(msgBox.value.isValid.error);
180
-
181
- sending.value = true; // disable sending btn
182
-
183
- const acc = await getAccount(props.endpoint, props.sender);
184
- const messages = msgBox.value.msgs;
185
-
186
- const tx = {
187
- chainId: chainId.value,
188
- signerAddress: props.sender,
189
- messages,
190
- fee: {
191
- gas: "400000",
192
- amount: [
193
- { amount: String(feeAmount.value), denom: feeDenom.value },
194
- ],
195
- },
196
- memo: memo.value,
197
- signerData: {
198
- accountNumber: Number(acc.account.account_number),
199
- sequence: Number(acc.account.sequence),
200
- chainId: chainId.value,
201
- },
202
- };
203
- // console.log('tx:', tx);
204
- const current = readWallet(props.hdPath);
205
- const wallet = current ? current.wallet : WalletName.Keplr;
206
- const client = new UniClient(wallet, {
207
- chainId: chainId.value,
208
- hdPath: current.hdPath,
209
- });
210
-
211
- if(!advance.value) {
212
- await client.simulate(props.endpoint, tx, broadcast.value).then(gas => {
213
- // update tx gas
214
- tx.fee.gas = (gas * 1.25).toFixed()
215
- }).catch(() => {
216
- // sending.value = false;
217
- // error.value = "Failed to simulate tx gas: " + err;
218
- advance.value = true;
219
- })
220
- } else {
221
- tx.fee.gas = gasInfo.value.toString()
222
- }
223
-
224
- const txRaw = await client.sign(tx);
225
- const response = await client.broadcastTx(props.endpoint, txRaw, broadcast.value);
226
- // show submitting view
227
- hash.value = response.tx_response.txhash
228
- showResult(response.tx_response.txhash);
229
-
230
- emit('submited', {
231
- hash: response.tx_response.txhash,
232
- eventType: props.type,
233
- });
234
- } catch (e) {
235
- sending.value = false;
236
- error.value = String(e);
237
- }
238
- }
239
-
240
- function viewTransaction() {
241
- emit('view', {
242
- hash: hash.value,
243
- eventType: props.type,
244
- });
245
- open.value = false
246
- }
247
-
248
- function showTitle() {
249
- return (props.type || 'Sending Transaction').replace(/\_/g, ' ');
250
- }
251
-
252
- const delay = ref(0);
253
- const step = ref(0);
254
- const msg = ref('');
255
- const sleep = 6000;
256
- const hash = ref('')
257
-
258
- function showResult(hash: string) {
259
- view.value = 'submitting';
260
- delay.value = 1;
261
- step.value = 20;
262
- error.value = '';
263
- msg.value = 'Proccessing...';
264
- setTimeout(() => {
265
- fetchTx(hash);
266
- }, sleep);
267
- }
268
-
269
- function fetchTx(tx: string) {
270
- delay.value += 1;
271
- step.value += 20;
272
- getTxByHash(props.endpoint, tx)
273
- .then((res) => {
274
- step.value = 100;
275
- if (res.tx_response.code > 0) {
276
- error.value = res.tx_response.raw_log;
277
- } else {
278
- msg.value = `Congratulations! ${showTitle()} completed successfully.`;
279
- emit('confirmed', { hash: tx, eventType: props.type });
280
- }
281
- })
282
- .catch(() => {
283
- if (delay.value < 5) {
284
- setTimeout(() => fetchTx(tx), sleep);
285
- } else {
286
- error.value = 'Timeout';
287
- }
288
- });
289
- }
290
- </script>
291
- <template>
292
- <div class="text-gray-600">
293
- <!-- Put this part before </body> tag -->
294
- <input v-model="open" type="checkbox" :id="type" class="modal-toggle" @change="initData()" />
295
- <label :for="type" class="modal cursor-pointer">
296
- <label class="modal-box relative p-5 dark:bg-[#1c1f2e]" :class="{ '!w-11/12 !max-w-5xl': String(type).startsWith('wasm') }" for="">
297
- <label :for="type" class="btn dark:bg-[#1f67f5] dark:hover:bg-[#1c1f2e] btn-sm btn-circle absolute right-4 top-4">✕</label>
298
- <h3 class="text-lg font-bold capitalize dark:text-gray-300">
299
- {{ showTitle() }}
300
- </h3>
301
-
302
- <div v-if="!sender" class="text-center h-16 items-center">
303
- No wallet connected!
304
- </div>
305
-
306
- <div v-if="sender">
307
- <div v-if="view === 'input'">
308
- <component :is="msgType" ref="msgBox" :endpoint="endpoint" :sender="sender" :balances="balance"
309
- :metadata="metadatas" :params="props.params" />
310
- <form class="space-y-6" action="#" method="POST">
311
- <div :class="advance ? '' : 'hidden'">
312
- <div class="form-control">
313
- <label class="label">
314
- <span class="label-text">Fees</span>
315
- </label>
316
- <label class="input-group flex items-center">
317
- <input v-model="feeAmount" type="text" placeholder="0.001"
318
- class="input border border-gray-300 dark:border-[#aac7fc] flex-1 w-0 dark:text-gray-300" />
319
- <select v-model="feeDenom"
320
- class="select input border border-gray-300 dark:border-[#aac7fc] w-[200px]">
321
- <option disabled selected>
322
- Select Fee Token
323
- </option>
324
- <option v-for="t in balance">
325
- {{ t.denom }}
326
- </option>
327
- </select>
328
- </label>
329
- </div>
330
- <div class="form-control">
331
- <label class="label">
332
- <span class="label-text">Gas</span>
333
- </label>
334
- <input v-model="gasInfo" type="number" placeholder="2000000"
335
- class="input border border-gray-300 dark:border-[#aac7fc] dark:text-gray-300" />
336
- </div>
337
- <div class="form-control">
338
- <label class="label">
339
- <span class="label-text">Memo</span>
340
- </label>
341
- <input v-model="memo" type="text" placeholder="Memo"
342
- class="input border border-gray-300 dark:border-[#aac7fc] dark:text-gray-300" />
343
- </div>
344
- <div class="form-control">
345
- <label class="label">
346
- <span class="label-text">Broadcast Mode</span>
347
- </label>
348
- <select v-model="broadcast"
349
- class="select input border border-gray-300 dark:border-[#aac7fc] w-[200px]">
350
- <option :value="BroadcastMode.SYNC">Sync</option>
351
- <option :value="BroadcastMode.ASYNC">Async</option>
352
- <option :value="BroadcastMode.BLOCK">Block</option>
353
- </select>
354
- </div>
355
- </div>
356
- </form>
357
-
358
- <div v-show="error" class="mt-5 alert alert-error shadow-lg" @click="error = ''">
359
- <div class="flex">
360
- <svg xmlns="http://www.w3.org/2000/svg" class="stroke-current flex-shrink-0 h-6 w-6"
361
- fill="none" viewBox="0 0 24 24">
362
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
363
- d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" />
364
- </svg>
365
- <span>{{ error }}.</span>
366
- </div>
367
- </div>
368
-
369
- <div class="modal-action flex justify-between items-center">
370
- <div class="flex items-center cursor-pointer">
371
- <input v-model="advance" type="checkbox" :id="`${type}-advance`"
372
- class="checkbox checkbox-sm checkbox-primary mr-2" /><label :for="`${type}-advance`"
373
- class="cursor-pointer dark:text-gray-400">Advance</label>
374
- </div>
375
- <button class="btn btn-primary dark:bg-[#1f67f5]" @click="sendTx()" :disabled="sending">
376
- <span v-if="sending" class="loading loading-spinner"></span>
377
- Send
378
- </button>
379
- </div>
380
- </div>
381
-
382
- <div v-if="view === 'submitting'">
383
- <div class="my-10">
384
- <div v-if="error" class="my-5 text-center text-red-500">
385
- {{ error }}
386
- </div>
387
- <div v-else class="my-5 text-center text-lg text-green-500">
388
- {{ msg }}
389
- </div>
390
- <div class="overflow-hidden h-5 mb-2 text-xs flex rounded bg-green-100">
391
- <div :style="`width: ${step}%`"
392
- class="shadow-none flex flex-col text-center whitespace-nowrap text-white justify-center bg-green-400">
393
- </div>
394
- </div>
395
- <div class="flex items-center justify-between">
396
- <div>
397
- <span
398
- class="text-xs font-semibold inline-block py-1 px-2 rounded text-gray-600 dark:text-white">
399
- Submitted
400
- </span>
401
- </div>
402
- <div class="text-right">
403
- <span class="text-xs font-semibold inline-block text-gray-600 dark:text-white">
404
- {{ step }}%
405
- </span>
406
- </div>
407
- </div>
408
- </div>
409
- <label class="mt-10 flex justify-center text-sm" @click="viewTransaction">
410
- <span>View Transaction</span>
411
- </label>
412
- </div>
413
- </div>
414
- </label>
415
- </label>
416
- </div>
417
- </template>
418
- <script lang="ts">
419
- export default {
420
- name: 'TxDialog',
421
- };
422
- </script>
1
+ <script setup lang="ts">
2
+ import { ref, computed } from 'vue';
3
+ import {
4
+ getAccount,
5
+ getBalance,
6
+ getBalanceMetadata,
7
+ getIBCDenomMetadata,
8
+ getLatestBlock,
9
+ getStakingParam,
10
+ getTxByHash,
11
+ } from '../../utils/http';
12
+ import { BroadcastMode, Coin, CoinMetadata } from '../../utils/type';
13
+ import { WalletName, readWallet, isEvmChain } from '../../../lib/wallet/Wallet';
14
+ import { UniClient } from '../../../lib/wallet/UniClient';
15
+
16
+ // cosmos sdk messages
17
+ import Delegate from './messages/Delegate.vue';
18
+ import Deposit from './messages/Deposit.vue';
19
+ import Redelegate from './messages/Redelegate.vue';
20
+ import Send from './messages/Send.vue';
21
+ import Transfer from './messages/Transfer.vue';
22
+ import Unbond from './messages/Unbond.vue';
23
+ import Vote from './messages/Vote.vue';
24
+ import Withdraw from './messages/Withdraw.vue';
25
+ import WithdrawCommission from './messages/WithdrawCommission.vue';
26
+
27
+ // wasm msgs
28
+ import StoreCode from './wasm/StoreCode.vue';
29
+ import ExecuteContract from './wasm/ExecuteContract.vue';
30
+ import InstantiateContract from './wasm/InstantiateContract.vue';
31
+ import ChainRegistryClient from '@ping-pub/chain-registry-client';
32
+ import MigrateContract from './wasm/MigrateContract.vue';
33
+ import UpdateAdmin from './wasm/UpdateAdmin.vue';
34
+ import ClearAdmin from './wasm/ClearAdmin.vue';
35
+
36
+ const props = defineProps({
37
+ type: String,
38
+ endpoint: { type: String, required: true },
39
+ sender: { type: String, required: true },
40
+ hdPath: String,
41
+ registryName: String,
42
+ params: String,
43
+ });
44
+
45
+ const msgType = computed(() => {
46
+ switch (props.type?.toLowerCase()) {
47
+ case 'send':
48
+ return Send;
49
+ case 'delegate':
50
+ return Delegate;
51
+ case 'withdraw':
52
+ return Withdraw;
53
+ case 'withdraw_commission':
54
+ return WithdrawCommission;
55
+ case 'redelegate':
56
+ return Redelegate;
57
+ case 'transfer':
58
+ return Transfer;
59
+ case 'unbond':
60
+ return Unbond;
61
+ case 'vote':
62
+ return Vote;
63
+ case 'deposit':
64
+ return Deposit;
65
+ case 'wasm_store_code':
66
+ return StoreCode;
67
+ case 'wasm_execute_contract':
68
+ return ExecuteContract;
69
+ case 'wasm_instantiate_contract':
70
+ return InstantiateContract;
71
+ case 'wasm_migrate_contract':
72
+ return MigrateContract;
73
+ case 'wasm_update_admin':
74
+ return UpdateAdmin;
75
+ case 'wasm_clear_admin':
76
+ return ClearAdmin;
77
+ default:
78
+ return Send;
79
+ }
80
+ });
81
+
82
+ const advance = ref(false);
83
+ const sending = ref(false);
84
+ const balance = ref([] as Coin[]);
85
+ const metadatas = ref({} as Record<string, CoinMetadata>);
86
+ const emit = defineEmits(['submited', 'confirmed', 'view']);
87
+
88
+ // functional variable
89
+ const p = ref({} as { fees: Coin });
90
+ const view = ref('input'); // input, submitting
91
+ const open = ref(false);
92
+ const error = ref('');
93
+
94
+ // input field
95
+ const msgBox = ref({
96
+ msgs: [],
97
+ isValid: { ok: false, error: '' },
98
+ initial: function () { },
99
+ });
100
+ const feeAmount = ref(2000);
101
+ const feeDenom = ref('');
102
+ const gasInfo = ref(200000);
103
+ const memo = ref('');
104
+ const chainId = ref('cosmoshub-4');
105
+ // const chainId = ref('taproot-1');
106
+ const broadcast = ref(BroadcastMode.SYNC);
107
+
108
+ async function initData() {
109
+ if (open.value && props.endpoint && props.sender) {
110
+ metadatas.value = {}
111
+ view.value = 'input';
112
+ p.value = JSON.parse(props.params || '{}')
113
+ memo.value = props.type?.toLowerCase() === 'send' ? '' : 'mictonode.com'
114
+
115
+ feeAmount.value = Number(p.value?.fees?.amount || 2000)
116
+ feeDenom.value = balance.value[0]?.denom;
117
+
118
+ try {
119
+ getBalance(props.endpoint, props.sender).then((x) => {
120
+ balance.value = x.balances;
121
+ x.balances?.forEach((coin) => {
122
+ // only load for native tokens
123
+ if (coin.denom.length < 12)
124
+ getBalanceMetadata(props.endpoint, coin.denom).then(
125
+ (meta) => {
126
+ if(meta.metadata) metadatas.value[coin.denom] = meta.metadata;
127
+ }
128
+ ).catch(()=>{});
129
+ if(coin.denom.startsWith('ibc/')) {
130
+ getIBCDenomMetadata(coin.denom).then(
131
+ (meta) => {
132
+ if(meta) metadatas.value[coin.denom] = meta;
133
+ }
134
+ ).catch(()=>{});
135
+ }
136
+ });
137
+ });
138
+
139
+ // load metadata from registry
140
+ if (props.registryName && Object.keys(metadatas.value).length === 0) {
141
+ const client = new ChainRegistryClient()
142
+ client.fetchAssetsList(props.registryName).then(x => {
143
+ x.assets.forEach(a => {
144
+ metadatas.value[a.base] = a as CoinMetadata
145
+ })
146
+ }).catch(() => {
147
+ console.log(`Chain: ${props.registryName } was not found on Cosmos Registry`)
148
+ })
149
+ }
150
+ getLatestBlock(props.endpoint).then((x) => {
151
+ chainId.value = x.block.header.chain_id;
152
+ // Set higher default fee for EVM chains (Warden, Evmos, etc.)
153
+ if (isEvmChain(chainId.value) && feeAmount.value < 250000) {
154
+ feeAmount.value = 250000;
155
+ }
156
+ });
157
+
158
+ // Every sub component should have a initial function
159
+ if (msgBox.value && msgBox.value.initial) msgBox.value.initial();
160
+
161
+ // load fee denom
162
+ getStakingParam(props.endpoint).then((res) => {
163
+ feeDenom.value = res?.params?.bond_denom;
164
+ })
165
+ } catch (err) {
166
+ error.value = String(err);
167
+ }
168
+
169
+ // account.value = await getAccount(props.endpoint, props.sender).then(x => x.account);
170
+ sending.value = false;
171
+ }
172
+ }
173
+ async function sendTx() {
174
+ try {
175
+ if (!props.sender) throw new Error('Sender should not be empty!');
176
+ if (!props.endpoint) throw new Error('Endpoint is empty');
177
+ if (!feeDenom.value) throw new Error('Fee Denom is empty');
178
+ if (!msgBox.value.isValid.ok)
179
+ throw new Error(msgBox.value.isValid.error);
180
+
181
+ sending.value = true; // disable sending btn
182
+
183
+ const acc = await getAccount(props.endpoint, props.sender);
184
+ const messages = msgBox.value.msgs;
185
+
186
+ const tx = {
187
+ chainId: chainId.value,
188
+ signerAddress: props.sender,
189
+ messages,
190
+ fee: {
191
+ gas: "400000",
192
+ amount: [
193
+ { amount: String(feeAmount.value), denom: feeDenom.value },
194
+ ],
195
+ },
196
+ memo: memo.value,
197
+ signerData: {
198
+ accountNumber: Number(acc.account.account_number),
199
+ sequence: Number(acc.account.sequence),
200
+ chainId: chainId.value,
201
+ },
202
+ };
203
+ // console.log('tx:', tx);
204
+ const current = readWallet(props.hdPath);
205
+ const wallet = current ? current.wallet : WalletName.Keplr;
206
+ const client = new UniClient(wallet, {
207
+ chainId: chainId.value,
208
+ hdPath: current.hdPath,
209
+ });
210
+
211
+ if(!advance.value) {
212
+ await client.simulate(props.endpoint, tx, broadcast.value).then(gas => {
213
+ // update tx gas
214
+ tx.fee.gas = (gas * 1.25).toFixed()
215
+ }).catch(() => {
216
+ // sending.value = false;
217
+ // error.value = "Failed to simulate tx gas: " + err;
218
+ advance.value = true;
219
+ })
220
+ } else {
221
+ tx.fee.gas = gasInfo.value.toString()
222
+ }
223
+
224
+ const txRaw = await client.sign(tx);
225
+ const response = await client.broadcastTx(props.endpoint, txRaw, broadcast.value);
226
+ // show submitting view
227
+ hash.value = response.tx_response.txhash
228
+ showResult(response.tx_response.txhash);
229
+
230
+ emit('submited', {
231
+ hash: response.tx_response.txhash,
232
+ eventType: props.type,
233
+ });
234
+ } catch (e) {
235
+ sending.value = false;
236
+ error.value = String(e);
237
+ }
238
+ }
239
+
240
+ function viewTransaction() {
241
+ emit('view', {
242
+ hash: hash.value,
243
+ eventType: props.type,
244
+ });
245
+ open.value = false
246
+ }
247
+
248
+ function showTitle() {
249
+ return (props.type || 'Sending Transaction').replace(/\_/g, ' ');
250
+ }
251
+
252
+ const delay = ref(0);
253
+ const step = ref(0);
254
+ const msg = ref('');
255
+ const sleep = 6000;
256
+ const hash = ref('')
257
+
258
+ function showResult(hash: string) {
259
+ view.value = 'submitting';
260
+ delay.value = 1;
261
+ step.value = 20;
262
+ error.value = '';
263
+ msg.value = 'Proccessing...';
264
+ setTimeout(() => {
265
+ fetchTx(hash);
266
+ }, sleep);
267
+ }
268
+
269
+ function fetchTx(tx: string) {
270
+ delay.value += 1;
271
+ step.value += 20;
272
+ getTxByHash(props.endpoint, tx)
273
+ .then((res) => {
274
+ step.value = 100;
275
+ if (res.tx_response.code > 0) {
276
+ error.value = res.tx_response.raw_log;
277
+ } else {
278
+ msg.value = `Congratulations! ${showTitle()} completed successfully.`;
279
+ emit('confirmed', { hash: tx, eventType: props.type });
280
+ }
281
+ })
282
+ .catch(() => {
283
+ if (delay.value < 5) {
284
+ setTimeout(() => fetchTx(tx), sleep);
285
+ } else {
286
+ error.value = 'Timeout';
287
+ }
288
+ });
289
+ }
290
+ </script>
291
+ <template>
292
+ <div class="text-gray-600">
293
+ <!-- Put this part before </body> tag -->
294
+ <input v-model="open" type="checkbox" :id="type" class="modal-toggle" @change="initData()" />
295
+ <label :for="type" class="modal cursor-pointer">
296
+ <label class="modal-box relative p-5" :class="{ '!w-11/12 !max-w-5xl': String(type).startsWith('wasm') }" for="">
297
+ <label :for="type" class="btn btn-sm btn-circle absolute right-4 top-4">✕</label>
298
+ <h3 class="text-lg font-bold capitalize">
299
+ {{ showTitle() }}
300
+ </h3>
301
+
302
+ <div v-if="!sender" class="text-center h-16 items-center">
303
+ No wallet connected!
304
+ </div>
305
+
306
+ <div v-if="sender">
307
+ <div v-if="view === 'input'">
308
+ <component :is="msgType" ref="msgBox" :endpoint="endpoint" :sender="sender" :balances="balance"
309
+ :metadata="metadatas" :params="props.params" />
310
+ <form class="space-y-6" action="#" method="POST">
311
+ <div :class="advance ? '' : 'hidden'">
312
+ <div class="form-control">
313
+ <label class="label">
314
+ <span class="label-text">Fees</span>
315
+ </label>
316
+ <label class="input-group flex items-center">
317
+ <input v-model="feeAmount" type="text" placeholder="0.001"
318
+ class="input flex-1 w-0" />
319
+ <select v-model="feeDenom"
320
+ class="select input w-[200px]">
321
+ <option disabled selected>
322
+ Select Fee Token
323
+ </option>
324
+ <option v-for="t in balance">
325
+ {{ t.denom }}
326
+ </option>
327
+ </select>
328
+ </label>
329
+ </div>
330
+ <div class="form-control">
331
+ <label class="label">
332
+ <span class="label-text">Gas</span>
333
+ </label>
334
+ <input v-model="gasInfo" type="number" placeholder="2000000"
335
+ class="input" />
336
+ </div>
337
+ <div class="form-control">
338
+ <label class="label">
339
+ <span class="label-text">Memo</span>
340
+ </label>
341
+ <input v-model="memo" type="text" placeholder="Memo"
342
+ class="input" />
343
+ </div>
344
+ <div class="form-control">
345
+ <label class="label">
346
+ <span class="label-text">Broadcast Mode</span>
347
+ </label>
348
+ <select v-model="broadcast"
349
+ class="select input w-[200px]">
350
+ <option :value="BroadcastMode.SYNC">Sync</option>
351
+ <option :value="BroadcastMode.ASYNC">Async</option>
352
+ <option :value="BroadcastMode.BLOCK">Block</option>
353
+ </select>
354
+ </div>
355
+ </div>
356
+ </form>
357
+
358
+ <div v-show="error" class="mt-5 alert alert-error shadow-lg" @click="error = ''">
359
+ <div class="flex">
360
+ <svg xmlns="http://www.w3.org/2000/svg" class="stroke-current flex-shrink-0 h-6 w-6"
361
+ fill="none" viewBox="0 0 24 24">
362
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
363
+ d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" />
364
+ </svg>
365
+ <span>{{ error }}.</span>
366
+ </div>
367
+ </div>
368
+
369
+ <div class="modal-action flex justify-between items-center">
370
+ <div class="flex items-center cursor-pointer">
371
+ <input v-model="advance" type="checkbox" :id="`${type}-advance`"
372
+ class="checkbox checkbox-sm mr-2" /><label :for="`${type}-advance`"
373
+ class="cursor-pointer dark:text-gray-400">Advance</label>
374
+ </div>
375
+ <button class="btn btn-primary" @click="sendTx()" :disabled="sending">
376
+ <span v-if="sending" class="loading loading-spinner"></span>
377
+ Send
378
+ </button>
379
+ </div>
380
+ </div>
381
+
382
+ <div v-if="view === 'submitting'">
383
+ <div class="my-10">
384
+ <div v-if="error" class="my-5 text-center text-red-500">
385
+ {{ error }}
386
+ </div>
387
+ <div v-else class="my-5 text-center text-lg text-green-500">
388
+ {{ msg }}
389
+ </div>
390
+ <div class="overflow-hidden h-5 mb-2 text-xs flex rounded bg-green-100">
391
+ <div :style="`width: ${step}%`"
392
+ class="shadow-none flex flex-col text-center whitespace-nowrap text-white justify-center bg-green-400">
393
+ </div>
394
+ </div>
395
+ <div class="flex items-center justify-between">
396
+ <div>
397
+ <span
398
+ class="text-xs font-semibold inline-block py-1 px-2 rounded text-gray-600 dark:text-white">
399
+ Submitted
400
+ </span>
401
+ </div>
402
+ <div class="text-right">
403
+ <span class="text-xs font-semibold inline-block text-gray-600 dark:text-white">
404
+ {{ step }}%
405
+ </span>
406
+ </div>
407
+ </div>
408
+ </div>
409
+ <label class="mt-10 flex justify-center text-sm" @click="viewTransaction">
410
+ <span>View Transaction</span>
411
+ </label>
412
+ </div>
413
+ </div>
414
+ </label>
415
+ </label>
416
+ </div>
417
+ </template>
418
+ <script lang="ts">
419
+ export default {
420
+ name: 'TxDialog',
421
+ };
422
+ </script>