@mictonode/widget 0.3.17 → 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.
- package/dist/{main-465ae991.js → main-bbea3e54.js} +83 -83
- package/dist/ping-widget.js +2 -2
- package/dist/ping-widget.umd.cjs +15 -15
- package/dist/{query.lcd-d9c6163c.js → query.lcd-88036522.js} +1 -1
- package/dist/{query.rpc.Query-a479e6f9.js → query.rpc.Query-3a2b14f8.js} +1 -1
- package/dist/{tx.rpc.msg-7444045d.js → tx.rpc.msg-39f0b824.js} +1 -1
- package/lib/components/ConnectWallet/index.vue +8 -8
- package/lib/components/TokenConvert/index.vue +10 -10
- package/lib/components/TxDialog/index.vue +422 -422
- package/lib/components/TxDialog/messages/Delegate.vue +4 -4
- package/lib/components/TxDialog/messages/Deposit.vue +3 -3
- package/lib/components/TxDialog/messages/Redelegate.vue +5 -5
- package/lib/components/TxDialog/messages/Send.vue +5 -5
- package/lib/components/TxDialog/messages/Transfer.vue +6 -6
- package/lib/components/TxDialog/messages/Unbond.vue +3 -3
- package/lib/components/TxDialog/messages/Vote.vue +1 -1
- package/lib/components/TxDialog/messages/Withdraw.vue +1 -1
- package/lib/components/TxDialog/messages/WithdrawCommission.vue +1 -1
- package/lib/components/TxDialog/wasm/ClearAdmin.vue +2 -2
- package/lib/components/TxDialog/wasm/ExecuteContract.vue +5 -5
- package/lib/components/TxDialog/wasm/InstantiateContract.vue +6 -6
- package/lib/components/TxDialog/wasm/MigrateContract.vue +4 -4
- package/lib/components/TxDialog/wasm/MigrateContract2.vue +4 -4
- package/lib/components/TxDialog/wasm/StoreCode.vue +2 -2
- package/lib/components/TxDialog/wasm/UpdateAdmin.vue +3 -3
- package/lib/main.css +500 -41
- package/lib/main.ts +1 -0
- package/package.json +3 -4
- package/src/App.vue +6 -6
- package/src/styles/design-system.css +35 -1
- package/tailwind.config.js +1 -54
|
@@ -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
|
|
297
|
-
<label :for="type" class="btn
|
|
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
|
|
319
|
-
<select v-model="feeDenom"
|
|
320
|
-
class="select input
|
|
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
|
|
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
|
|
373
|
-
class="cursor-pointer dark:text-gray-400">Advance</label>
|
|
374
|
-
</div>
|
|
375
|
-
<button class="btn btn-primary
|
|
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>
|