@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.
- package/.github/FUNDING.yml +3 -3
- package/.github/workflows/npm-publish.yml +34 -34
- package/.prettierrc.json +9 -9
- package/.vscode/extensions.json +3 -3
- package/LICENSE +674 -674
- package/README.md +41 -41
- package/dist/{main-d0e5d1e4.js → main-bbea3e54.js} +155 -153
- package/dist/ping-widget.js +2 -2
- package/dist/ping-widget.umd.cjs +18 -18
- package/dist/{query.lcd-3d4d3495.js → query.lcd-88036522.js} +1 -1
- package/dist/{query.rpc.Query-b7807c29.js → query.rpc.Query-3a2b14f8.js} +1 -1
- package/dist/{tx.rpc.msg-59c3408a.js → tx.rpc.msg-39f0b824.js} +1 -1
- package/example/.vscode/extensions.json +3 -3
- package/example/README.md +7 -7
- package/example/index.html +12 -12
- package/example/package.json +19 -19
- package/example/pnpm-lock.yaml +465 -465
- package/example/public/cdn.html +19 -19
- package/example/src/App.vue +73 -73
- package/example/src/main.js +4 -4
- package/example/vite.config.js +7 -7
- package/index.html +12 -12
- package/lib/components/ConnectWallet/index.vue +262 -262
- package/lib/components/TokenConvert/index.vue +1033 -1033
- package/lib/components/TokenConvert/tokens.ts +36 -36
- package/lib/components/TxDialog/index.vue +422 -422
- package/lib/components/TxDialog/messages/Delegate.vue +174 -174
- package/lib/components/TxDialog/messages/Deposit.vue +96 -96
- package/lib/components/TxDialog/messages/Redelegate.vue +160 -160
- package/lib/components/TxDialog/messages/Send.vue +142 -142
- package/lib/components/TxDialog/messages/Transfer.vue +248 -248
- package/lib/components/TxDialog/messages/Unbond.vue +103 -103
- package/lib/components/TxDialog/messages/Vote.vue +62 -62
- package/lib/components/TxDialog/messages/Withdraw.vue +55 -55
- package/lib/components/TxDialog/messages/WithdrawCommission.vue +74 -74
- package/lib/components/TxDialog/wasm/ClearAdmin.vue +55 -55
- package/lib/components/TxDialog/wasm/ExecuteContract.vue +98 -98
- package/lib/components/TxDialog/wasm/InstantiateContract.vue +108 -108
- package/lib/components/TxDialog/wasm/MigrateContract.vue +76 -76
- package/lib/components/TxDialog/wasm/MigrateContract2.vue +76 -76
- package/lib/components/TxDialog/wasm/StoreCode.vue +100 -100
- package/lib/components/TxDialog/wasm/UpdateAdmin.vue +74 -74
- package/lib/main.css +591 -7
- package/lib/main.ts +24 -23
- package/lib/utils/TokenUnitConverter.ts +44 -44
- package/lib/utils/format.ts +16 -16
- package/lib/utils/http.ts +154 -154
- package/lib/utils/type.ts +56 -56
- package/lib/wallet/EthermintMessageAdapter.ts +135 -135
- package/lib/wallet/UniClient.ts +144 -144
- package/lib/wallet/Wallet.ts +142 -142
- package/lib/wallet/wallets/KeplerWallet.ts +141 -141
- package/lib/wallet/wallets/LeapWallet.ts +141 -141
- package/lib/wallet/wallets/LedgerWallet.ts +202 -202
- package/lib/wallet/wallets/MetamaskSnapWallet.ts +105 -105
- package/lib/wallet/wallets/MetamaskWallet.ts +173 -173
- package/lib/wallet/wallets/OKXWallet.ts +202 -202
- package/lib/wallet/wallets/UnisatWallet.ts +198 -198
- package/package.json +5 -6
- package/postcss.config.js +6 -6
- package/src/App.vue +225 -225
- package/src/main.ts +7 -4
- package/src/styles/design-system.css +184 -0
- package/src/vite-env.d.ts +1 -1
- package/tailwind.config.js +158 -34
- package/tsconfig.json +25 -25
- package/tsconfig.node.json +10 -10
- package/vite.config.ts +62 -62
- package/vue-shim.d.ts +6 -6
|
@@ -1,1033 +1,1033 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { computed, onMounted, ref } from 'vue';
|
|
3
|
-
import { Icon } from '@iconify/vue';
|
|
4
|
-
import { fromBech32, toBech32, toHex } from '@cosmjs/encoding';
|
|
5
|
-
import { sha256 } from '@cosmjs/crypto';
|
|
6
|
-
import ChainRegistryClient from '@ping-pub/chain-registry-client';
|
|
7
|
-
import {
|
|
8
|
-
Asset,
|
|
9
|
-
Chain,
|
|
10
|
-
IBCInfo,
|
|
11
|
-
IBCPath,
|
|
12
|
-
} from '@ping-pub/chain-registry-client/dist/types';
|
|
13
|
-
import {
|
|
14
|
-
getBalance,
|
|
15
|
-
getStakingParam,
|
|
16
|
-
getOsmosisPools,
|
|
17
|
-
getLatestBlock,
|
|
18
|
-
getAccount,
|
|
19
|
-
getTxByHash,
|
|
20
|
-
} from '../../utils/http';
|
|
21
|
-
import {
|
|
22
|
-
Account,
|
|
23
|
-
ConnectedWallet,
|
|
24
|
-
WalletName,
|
|
25
|
-
createWallet,
|
|
26
|
-
readWallet,
|
|
27
|
-
writeWallet,
|
|
28
|
-
} from '../../wallet/Wallet';
|
|
29
|
-
import { Coin } from '../../utils/type';
|
|
30
|
-
import { osmosis, ibc, getSigningOsmosisClient } from 'osmojs';
|
|
31
|
-
import { tokens, type TokenConfig } from './tokens';
|
|
32
|
-
import { decimal2percent } from '../../utils/format';
|
|
33
|
-
import { StdFee, coin } from '@cosmjs/stargate';
|
|
34
|
-
import Long from 'long';
|
|
35
|
-
import { UniClient } from '../../wallet/UniClient';
|
|
36
|
-
|
|
37
|
-
const props = defineProps({
|
|
38
|
-
chainName: { type: String, required: true },
|
|
39
|
-
endpoint: { type: String, required: true },
|
|
40
|
-
hdPath: String,
|
|
41
|
-
});
|
|
42
|
-
const OSMOSIS_RPC = 'https://rpc.osmosis.zone';
|
|
43
|
-
const OSMOSIS_REST = 'https://lcd.osmosis.zone';
|
|
44
|
-
const DEFAULT_HDPATH = "m/44'/118/0'/0/0";
|
|
45
|
-
|
|
46
|
-
const view = ref('connect'); // [connect, swap, deposit, withdraw]
|
|
47
|
-
|
|
48
|
-
function switchView(v: string) {
|
|
49
|
-
view.value = v;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// variables
|
|
53
|
-
const direction = ref('buy');
|
|
54
|
-
const sending = ref(false); // show status on send tx
|
|
55
|
-
const open = ref(false);
|
|
56
|
-
const error = ref('');
|
|
57
|
-
const chains = ref([] as IBCPath[]);
|
|
58
|
-
const osmosisPath = ref({} as IBCPath | undefined);
|
|
59
|
-
const osmosisPathInfo = ref({} as IBCInfo);
|
|
60
|
-
const defaultDenom = ref('');
|
|
61
|
-
const sender = ref({} as ConnectedWallet);
|
|
62
|
-
const localBalances = ref([] as Coin[]);
|
|
63
|
-
const osmoBalances = ref([] as Coin[]);
|
|
64
|
-
const localChainInfo = ref({} as Chain);
|
|
65
|
-
const localCoinInfo = ref([] as Asset[]);
|
|
66
|
-
const swapIn = ref({} as TokenConfig | undefined);
|
|
67
|
-
const swapOut = ref({} as TokenConfig | undefined);
|
|
68
|
-
const amountIn = ref('');
|
|
69
|
-
const allPools = ref([] as any[]);
|
|
70
|
-
const client = new ChainRegistryClient();
|
|
71
|
-
|
|
72
|
-
// swap logic
|
|
73
|
-
|
|
74
|
-
async function initData() {
|
|
75
|
-
error.value = ''; //reset error
|
|
76
|
-
sender.value = readWallet(props.hdPath);
|
|
77
|
-
if (!sender.value.cosmosAddress) {
|
|
78
|
-
view.value = 'connect';
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
if (open.value) {
|
|
82
|
-
view.value = 'swap';
|
|
83
|
-
localChainInfo.value = {} as Chain;
|
|
84
|
-
localCoinInfo.value = [];
|
|
85
|
-
recipient.value = localAddress(sender.value.cosmosAddress)
|
|
86
|
-
await client
|
|
87
|
-
.fetchChainInfo(props.chainName)
|
|
88
|
-
.then((res) => {
|
|
89
|
-
localChainInfo.value = res;
|
|
90
|
-
if (Number(res.slip44) !== 118) {
|
|
91
|
-
error.value === `Coin type ${res.slip44} is not supported`;
|
|
92
|
-
}
|
|
93
|
-
})
|
|
94
|
-
.catch(() => {
|
|
95
|
-
error.value = 'Not found IBC Path';
|
|
96
|
-
});
|
|
97
|
-
getBalance(OSMOSIS_REST, osmoAddress(sender.value.cosmosAddress)).then(
|
|
98
|
-
(res) => {
|
|
99
|
-
osmoBalances.value = res.balances.filter(
|
|
100
|
-
(x) => !x.denom.startsWith('gamm')
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
);
|
|
104
|
-
getBalance(
|
|
105
|
-
props.endpoint,
|
|
106
|
-
localAddress(sender.value.cosmosAddress)
|
|
107
|
-
).then((res) => {
|
|
108
|
-
localBalances.value = res.balances;
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
client.fetchAssetsList(props.chainName).then((al) => {
|
|
112
|
-
localCoinInfo.value = al.assets;
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
getStakingParam(props.endpoint).then((x) => {
|
|
116
|
-
defaultDenom.value = x.params.bond_denom;
|
|
117
|
-
});
|
|
118
|
-
getOsmosisPools(OSMOSIS_REST).then((res) => {
|
|
119
|
-
allPools.value = res.pools;
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
client.fetchIBCPaths().then((paths) => {
|
|
123
|
-
chains.value = paths.filter(
|
|
124
|
-
(x) => x.from === props.chainName || x.to === props.chainName
|
|
125
|
-
);
|
|
126
|
-
const path = chains.value.find(
|
|
127
|
-
(x) => x.from === 'osmosis' || x.to === 'osmosis'
|
|
128
|
-
);
|
|
129
|
-
if (path) {
|
|
130
|
-
osmosisPath.value = path;
|
|
131
|
-
client.fetchIBCPathInfo(path.path).then((info) => {
|
|
132
|
-
osmosisPathInfo.value = info;
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
function osmoAddress(addr?: string) {
|
|
140
|
-
if (!addr) return '';
|
|
141
|
-
const { data } = fromBech32(addr);
|
|
142
|
-
return toBech32('osmo', data);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function localAddress(addr?: string) {
|
|
146
|
-
if (!addr) return '';
|
|
147
|
-
const { data } = fromBech32(addr);
|
|
148
|
-
const prefix = localChainInfo.value?.bech32_prefix || 'cosmos';
|
|
149
|
-
return toBech32(prefix, data);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
function showBalance(denom?: string, decimal = 0) {
|
|
153
|
-
const bal = osmoBalances.value.find((x) => x.denom === denom || '');
|
|
154
|
-
if (bal) {
|
|
155
|
-
return Number(bal.amount) / 10 ** decimal;
|
|
156
|
-
}
|
|
157
|
-
return 0;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
function findlocalCoinDecimal(denom: string) {
|
|
161
|
-
const localCoin = localCoinInfo.value.find((x) => x.base === denom);
|
|
162
|
-
if (localCoin) {
|
|
163
|
-
const unit = localCoin.denom_units.find(
|
|
164
|
-
(x) => x.denom === localCoin.symbol.toLowerCase()
|
|
165
|
-
);
|
|
166
|
-
if (unit) return unit.exponent;
|
|
167
|
-
}
|
|
168
|
-
return 0;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
function findTokenUrl(coinInfo?: Asset) {
|
|
172
|
-
const url =
|
|
173
|
-
coinInfo?.logo_URIs?.svg ||
|
|
174
|
-
coinInfo?.logo_URIs?.png ||
|
|
175
|
-
coinInfo?.logo_URIs?.jpeg;
|
|
176
|
-
return url
|
|
177
|
-
? url.replace(
|
|
178
|
-
'https://raw.githubusercontent.com/cosmos/chain-registry/master',
|
|
179
|
-
'https://registry.ping.pub'
|
|
180
|
-
)
|
|
181
|
-
: '';
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
const localTokenOnOsmosis = computed(() => {
|
|
185
|
-
const channel = osmosisPathInfo.value.channels?.find(
|
|
186
|
-
(x) => x.chain_1.port_id === 'transfer'
|
|
187
|
-
);
|
|
188
|
-
const channelId =
|
|
189
|
-
osmosisPathInfo.value.chain_1?.chain_name === 'osmosis'
|
|
190
|
-
? channel?.chain_1.channel_id
|
|
191
|
-
: channel?.chain_2.channel_id;
|
|
192
|
-
const ibcDenom = toHex(
|
|
193
|
-
sha256(
|
|
194
|
-
new TextEncoder().encode(
|
|
195
|
-
`transfer/${channelId}/${defaultDenom.value}`
|
|
196
|
-
)
|
|
197
|
-
)
|
|
198
|
-
).toUpperCase();
|
|
199
|
-
return localCoinInfo.value?.map((localCoin) => ({
|
|
200
|
-
denom: defaultDenom.value,
|
|
201
|
-
symbol: localCoin.symbol || '',
|
|
202
|
-
ibcDenom: `ibc/${ibcDenom}`,
|
|
203
|
-
sourceChannelId: channelId,
|
|
204
|
-
decimals: findlocalCoinDecimal(defaultDenom.value),
|
|
205
|
-
coinImageUrl: findTokenUrl(localCoin),
|
|
206
|
-
}));
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
const localSourceChannelID = computed(() => {
|
|
210
|
-
const channel = osmosisPathInfo.value.channels?.find(
|
|
211
|
-
(x) => x.chain_1.port_id === 'transfer'
|
|
212
|
-
);
|
|
213
|
-
const channelId =
|
|
214
|
-
osmosisPathInfo.value.chain_1?.chain_name === 'osmosis'
|
|
215
|
-
? channel?.chain_2.channel_id
|
|
216
|
-
: channel?.chain_1.channel_id;
|
|
217
|
-
return channelId;
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
const withdrawable = computed(() => {
|
|
221
|
-
return (
|
|
222
|
-
localTokenOnOsmosis.value.findIndex(
|
|
223
|
-
(x) => x.denom === swapOut.value?.denom
|
|
224
|
-
) > -1
|
|
225
|
-
);
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
const depositable = computed(() => {
|
|
229
|
-
return (
|
|
230
|
-
localTokenOnOsmosis.value.findIndex(
|
|
231
|
-
(x) => x.denom === swapIn.value?.denom
|
|
232
|
-
) > -1
|
|
233
|
-
);
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
const inTokens = computed(() => {
|
|
237
|
-
if (direction.value === 'buy') {
|
|
238
|
-
swapIn.value = tokens[0];
|
|
239
|
-
return tokens;
|
|
240
|
-
} else {
|
|
241
|
-
swapIn.value = localTokenOnOsmosis.value[0];
|
|
242
|
-
return localTokenOnOsmosis.value;
|
|
243
|
-
}
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
const outTokens = computed(() => {
|
|
247
|
-
if (direction.value === 'buy') {
|
|
248
|
-
swapOut.value = localTokenOnOsmosis.value[0];
|
|
249
|
-
return localTokenOnOsmosis.value;
|
|
250
|
-
} else {
|
|
251
|
-
swapOut.value = tokens[0];
|
|
252
|
-
return tokens;
|
|
253
|
-
}
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
function selectInput(v) {
|
|
257
|
-
swapIn.value = v;
|
|
258
|
-
amountIn.value = '';
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
function selectOutput(v) {
|
|
262
|
-
swapOut.value = v;
|
|
263
|
-
amountIn.value = '';
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
const pool = computed(() => {
|
|
267
|
-
// find the available pools and sort by liquidity depth
|
|
268
|
-
const a = allPools.value
|
|
269
|
-
.filter(
|
|
270
|
-
(x) =>
|
|
271
|
-
x.pool_assets?.findIndex(
|
|
272
|
-
(a) => a.token.denom === swapIn.value?.ibcDenom
|
|
273
|
-
) > -1
|
|
274
|
-
)
|
|
275
|
-
.filter(
|
|
276
|
-
(x) =>
|
|
277
|
-
x.pool_assets?.findIndex(
|
|
278
|
-
(a) => a.token.denom === swapOut.value?.ibcDenom
|
|
279
|
-
) > -1
|
|
280
|
-
)
|
|
281
|
-
.sort(
|
|
282
|
-
(a, b) =>
|
|
283
|
-
Number(b.total_shares.amount) - Number(a.total_shares.amount)
|
|
284
|
-
);
|
|
285
|
-
// console.log(a)
|
|
286
|
-
return a.length > 0 ? a[0] : null;
|
|
287
|
-
});
|
|
288
|
-
|
|
289
|
-
function switchDirection() {
|
|
290
|
-
direction.value = direction.value === 'buy' ? 'sell' : 'buy';
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
const disabled = computed(() => {
|
|
294
|
-
const amount = Number(amountIn.value || 0);
|
|
295
|
-
if (amount <= 0 || outAmount.value <= 0) return true;
|
|
296
|
-
const token = swapIn.value;
|
|
297
|
-
const b = osmoBalances.value.find((x) => x.denom === token?.ibcDenom || '');
|
|
298
|
-
if (b && token) {
|
|
299
|
-
return Number(b.amount) < amount * 10 ** token.decimals;
|
|
300
|
-
}
|
|
301
|
-
return true;
|
|
302
|
-
});
|
|
303
|
-
|
|
304
|
-
const outAmount = computed(() => {
|
|
305
|
-
// tokenBalanceOut * [1 - { tokenBalanceIn / (tokenBalanceIn + (1 - swapFee) * tokenAmountIn)} ^ (tokenWeightIn / tokenWeightOut)]
|
|
306
|
-
const p = pool.value;
|
|
307
|
-
if (p) {
|
|
308
|
-
const tokenBalanceOut = p.pool_assets?.find(
|
|
309
|
-
(x) => x.token.denom === swapOut.value?.ibcDenom
|
|
310
|
-
);
|
|
311
|
-
const tokenBalanceIn = p.pool_assets?.find(
|
|
312
|
-
(x) => x.token.denom === swapIn.value?.ibcDenom
|
|
313
|
-
);
|
|
314
|
-
if (tokenBalanceIn && tokenBalanceOut) {
|
|
315
|
-
const balanceOut = Number(tokenBalanceOut.token.amount);
|
|
316
|
-
const balanceIn = Number(tokenBalanceIn.token.amount);
|
|
317
|
-
const weightOut = Number(tokenBalanceOut.weight);
|
|
318
|
-
const weightIn = Number(tokenBalanceIn.weight);
|
|
319
|
-
const swapFee = Number(p.pool_params.swap_fee);
|
|
320
|
-
const amount = Number(amountIn.value) * (1 - swapFee);
|
|
321
|
-
const out =
|
|
322
|
-
balanceOut *
|
|
323
|
-
(1 -
|
|
324
|
-
balanceIn / (balanceIn + amount) ** (weightIn / weightOut));
|
|
325
|
-
return out;
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
return 0;
|
|
329
|
-
});
|
|
330
|
-
|
|
331
|
-
async function doSwap() {
|
|
332
|
-
sending.value = true;
|
|
333
|
-
try {
|
|
334
|
-
const latest = await getLatestBlock(OSMOSIS_REST);
|
|
335
|
-
|
|
336
|
-
const stargateClient = await getSigningOsmosisClient({
|
|
337
|
-
rpcEndpoint: OSMOSIS_RPC,
|
|
338
|
-
// @ts-ignore
|
|
339
|
-
signer: window.getOfflineSigner(latest.block.header.chain_id),
|
|
340
|
-
});
|
|
341
|
-
const address = osmoAddress(sender.value.cosmosAddress);
|
|
342
|
-
|
|
343
|
-
if (!swapIn.value || !swapOut.value || !address) return;
|
|
344
|
-
const { swapExactAmountIn } =
|
|
345
|
-
osmosis.gamm.v1beta1.MessageComposer.withTypeUrl;
|
|
346
|
-
|
|
347
|
-
const amount = Number(amountIn.value || 0);
|
|
348
|
-
const msg = swapExactAmountIn({
|
|
349
|
-
sender: address,
|
|
350
|
-
routes: [
|
|
351
|
-
{
|
|
352
|
-
poolId: Long.fromNumber(pool.value.id),
|
|
353
|
-
tokenOutDenom: swapOut.value.ibcDenom,
|
|
354
|
-
},
|
|
355
|
-
],
|
|
356
|
-
tokenIn: {
|
|
357
|
-
amount: (amount * 10 ** swapIn.value.decimals).toFixed(),
|
|
358
|
-
denom: swapIn.value.ibcDenom,
|
|
359
|
-
},
|
|
360
|
-
tokenOutMinAmount: (
|
|
361
|
-
outAmount.value *
|
|
362
|
-
0.99 *
|
|
363
|
-
10 ** swapOut.value.decimals
|
|
364
|
-
).toFixed(), // slippage: 1%
|
|
365
|
-
});
|
|
366
|
-
|
|
367
|
-
const gas = await stargateClient.simulate(address, [msg], '');
|
|
368
|
-
|
|
369
|
-
const fee: StdFee = {
|
|
370
|
-
amount: [
|
|
371
|
-
{
|
|
372
|
-
denom: 'uosmo',
|
|
373
|
-
amount: '864',
|
|
374
|
-
},
|
|
375
|
-
],
|
|
376
|
-
gas: (gas * 1.25).toFixed(),
|
|
377
|
-
};
|
|
378
|
-
const response = await stargateClient.signAndBroadcast(
|
|
379
|
-
address,
|
|
380
|
-
[msg],
|
|
381
|
-
fee,
|
|
382
|
-
'Token Convert from mictonode.com'
|
|
383
|
-
);
|
|
384
|
-
if (response.code === 0) {
|
|
385
|
-
await showResult(response.transactionHash)
|
|
386
|
-
await getBalance(
|
|
387
|
-
OSMOSIS_REST,
|
|
388
|
-
osmoAddress(sender.value.cosmosAddress)
|
|
389
|
-
).then((res) => {
|
|
390
|
-
osmoBalances.value = res.balances.filter(
|
|
391
|
-
(x) => !x.denom.startsWith('gamm')
|
|
392
|
-
);
|
|
393
|
-
});
|
|
394
|
-
} else {
|
|
395
|
-
if (response.rawLog) error.value = response.rawLog;
|
|
396
|
-
}
|
|
397
|
-
} catch (err) {
|
|
398
|
-
error.value = err;
|
|
399
|
-
}
|
|
400
|
-
sending.value = false;
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
// deposit logic
|
|
404
|
-
const depositAmount = ref('');
|
|
405
|
-
|
|
406
|
-
function showLocalBalance(denom = '', decimals = 0) {
|
|
407
|
-
const b = localBalances.value?.find((x) => x.denom === denom);
|
|
408
|
-
if (b) {
|
|
409
|
-
return Number(b.amount) / 10 ** decimals;
|
|
410
|
-
}
|
|
411
|
-
return 0;
|
|
412
|
-
}
|
|
413
|
-
const disableDeposit = computed(() => {
|
|
414
|
-
const token = swapIn.value;
|
|
415
|
-
if (token) {
|
|
416
|
-
const b = localBalances.value?.find((x) => x.denom === token.denom);
|
|
417
|
-
if (b) {
|
|
418
|
-
const amount = Number(depositAmount.value || 0);
|
|
419
|
-
return (
|
|
420
|
-
amount <= 0 || Number(b.amount) < amount * 10 ** token.decimals
|
|
421
|
-
);
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
return true;
|
|
425
|
-
});
|
|
426
|
-
|
|
427
|
-
async function doDeposit() {
|
|
428
|
-
sending.value = true;
|
|
429
|
-
|
|
430
|
-
const address = localAddress(sender.value.cosmosAddress);
|
|
431
|
-
|
|
432
|
-
if (!swapIn.value || !address) return;
|
|
433
|
-
|
|
434
|
-
const latest = await getLatestBlock(props.endpoint);
|
|
435
|
-
const acc = await getAccount(props.endpoint, address);
|
|
436
|
-
|
|
437
|
-
const chainId = latest.block.header.chain_id;
|
|
438
|
-
const timeout = Date.now() + new Date().getTimezoneOffset() + 3600000;
|
|
439
|
-
const amount = Number(depositAmount.value || 0) * 10 ** swapIn.value.decimals;
|
|
440
|
-
const tx = {
|
|
441
|
-
chainId,
|
|
442
|
-
signerAddress: address,
|
|
443
|
-
messages: [
|
|
444
|
-
{
|
|
445
|
-
typeUrl: '/ibc.applications.transfer.v1.MsgTransfer',
|
|
446
|
-
value: {
|
|
447
|
-
sourcePort: 'transfer',
|
|
448
|
-
sourceChannel: localSourceChannelID.value || '',
|
|
449
|
-
token: {
|
|
450
|
-
amount: String(amount),
|
|
451
|
-
denom: swapIn.value.denom,
|
|
452
|
-
},
|
|
453
|
-
sender: address,
|
|
454
|
-
receiver: osmoAddress(address),
|
|
455
|
-
timeoutTimestamp: `${timeout}000000`,
|
|
456
|
-
},
|
|
457
|
-
},
|
|
458
|
-
],
|
|
459
|
-
fee: {
|
|
460
|
-
gas: '200000',
|
|
461
|
-
amount: [{ amount: '5000', denom: swapIn.value.denom }],
|
|
462
|
-
},
|
|
463
|
-
memo: '',
|
|
464
|
-
signerData: {
|
|
465
|
-
chainId: chainId.value,
|
|
466
|
-
accountNumber: Number(acc.account.account_number),
|
|
467
|
-
sequence: Number(acc.account.sequence),
|
|
468
|
-
},
|
|
469
|
-
};
|
|
470
|
-
|
|
471
|
-
try {
|
|
472
|
-
const client = new UniClient(WalletName.Keplr, { chainId });
|
|
473
|
-
|
|
474
|
-
// console.log("gasInfo:", gasInfo)
|
|
475
|
-
const txRaw = await client.sign(tx);
|
|
476
|
-
const response = await client.broadcastTx(props.endpoint, txRaw);
|
|
477
|
-
if (response.tx_response?.code === 0) {
|
|
478
|
-
setTimeout(async () => {
|
|
479
|
-
await getBalance(
|
|
480
|
-
OSMOSIS_REST,
|
|
481
|
-
osmoAddress(sender.value.cosmosAddress)
|
|
482
|
-
).then((res) => {
|
|
483
|
-
osmoBalances.value = res.balances.filter(
|
|
484
|
-
(x) => !x.denom.startsWith('gamm')
|
|
485
|
-
);
|
|
486
|
-
});
|
|
487
|
-
await getBalance(
|
|
488
|
-
props.endpoint,
|
|
489
|
-
localAddress(sender.value.cosmosAddress)
|
|
490
|
-
).then((res) => {
|
|
491
|
-
localBalances.value = res.balances;
|
|
492
|
-
});
|
|
493
|
-
}, 6000);
|
|
494
|
-
}
|
|
495
|
-
} catch (e) {
|
|
496
|
-
sending.value = false;
|
|
497
|
-
error.value = e;
|
|
498
|
-
setTimeout(() => (error.value = ''), 5000);
|
|
499
|
-
}
|
|
500
|
-
sending.value = false;
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
// withdraw logic
|
|
504
|
-
const withdrawAmount = ref('');
|
|
505
|
-
const recipient = ref(localAddress(sender.value.cosmosAddress))
|
|
506
|
-
const disableWithdraw = computed(() => {
|
|
507
|
-
const token = swapOut.value;
|
|
508
|
-
if (token) {
|
|
509
|
-
const b = osmoBalances.value?.find((x) => x.denom === token.ibcDenom);
|
|
510
|
-
if (b) {
|
|
511
|
-
const amount = Number(withdrawAmount.value || 0);
|
|
512
|
-
return (
|
|
513
|
-
amount <= 0 || Number(b.amount) < amount * 10 ** token.decimals
|
|
514
|
-
);
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
return true;
|
|
518
|
-
});
|
|
519
|
-
async function doWithdraw() {
|
|
520
|
-
sending.value = true;
|
|
521
|
-
try {
|
|
522
|
-
const latest = await getLatestBlock(OSMOSIS_REST);
|
|
523
|
-
|
|
524
|
-
const stargateClient = await getSigningOsmosisClient({
|
|
525
|
-
rpcEndpoint: OSMOSIS_RPC,
|
|
526
|
-
// @ts-ignore
|
|
527
|
-
signer: window.getOfflineSigner(latest.block.header.chain_id),
|
|
528
|
-
});
|
|
529
|
-
const address = osmoAddress(sender.value.cosmosAddress);
|
|
530
|
-
|
|
531
|
-
if (!swapIn.value || !swapOut.value || !address) return;
|
|
532
|
-
|
|
533
|
-
const timeout = Date.now() + new Date().getTimezoneOffset() + 3600000;
|
|
534
|
-
const amount = Number(withdrawAmount.value || 0);
|
|
535
|
-
const { transfer } =
|
|
536
|
-
ibc.applications.transfer.v1.MessageComposer.withTypeUrl;
|
|
537
|
-
const msg = transfer({
|
|
538
|
-
sender: address,
|
|
539
|
-
sourceChannel: swapOut.value.sourceChannelId || '',
|
|
540
|
-
sourcePort: 'transfer',
|
|
541
|
-
token: {
|
|
542
|
-
amount: (amount * 10 ** swapOut.value.decimals).toFixed(),
|
|
543
|
-
denom: swapOut.value.ibcDenom,
|
|
544
|
-
},
|
|
545
|
-
receiver: recipient.value,
|
|
546
|
-
timeoutTimestamp: Long.fromString(`${timeout}000000`),
|
|
547
|
-
timeoutHeight: {
|
|
548
|
-
revisionHeight: Long.fromNumber(0),
|
|
549
|
-
revisionNumber: Long.fromNumber(0),
|
|
550
|
-
},
|
|
551
|
-
memo: '',
|
|
552
|
-
});
|
|
553
|
-
|
|
554
|
-
const gas = await stargateClient.simulate(address, [msg], '');
|
|
555
|
-
|
|
556
|
-
const fee: StdFee = {
|
|
557
|
-
amount: [
|
|
558
|
-
{
|
|
559
|
-
denom: 'uosmo',
|
|
560
|
-
amount: '1864',
|
|
561
|
-
},
|
|
562
|
-
],
|
|
563
|
-
gas: (gas * 1.25).toFixed(),
|
|
564
|
-
};
|
|
565
|
-
const response = await stargateClient.signAndBroadcast(
|
|
566
|
-
address,
|
|
567
|
-
[msg],
|
|
568
|
-
fee,
|
|
569
|
-
'Convert on ping.pub'
|
|
570
|
-
);
|
|
571
|
-
if (response.code === 0) {
|
|
572
|
-
await getBalance(
|
|
573
|
-
OSMOSIS_REST,
|
|
574
|
-
osmoAddress(sender.value.cosmosAddress)
|
|
575
|
-
).then((res) => {
|
|
576
|
-
osmoBalances.value = res.balances.filter(
|
|
577
|
-
(x) => !x.denom.startsWith('gamm')
|
|
578
|
-
);
|
|
579
|
-
});
|
|
580
|
-
await getBalance(
|
|
581
|
-
props.endpoint,
|
|
582
|
-
localAddress(sender.value.cosmosAddress)
|
|
583
|
-
).then((res) => {
|
|
584
|
-
localBalances.value = res.balances;
|
|
585
|
-
});
|
|
586
|
-
} else {
|
|
587
|
-
if (response.rawLog) error.value = response.rawLog;
|
|
588
|
-
}
|
|
589
|
-
} catch (err) {
|
|
590
|
-
error.value = err
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
sending.value = false;
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
async function connect() {
|
|
597
|
-
sending.value = true;
|
|
598
|
-
let accounts = [] as Account[];
|
|
599
|
-
try {
|
|
600
|
-
const latest = await getLatestBlock(props.endpoint);
|
|
601
|
-
const wa = createWallet(WalletName.Keplr, {
|
|
602
|
-
chainId: latest.block.header.chain_id,
|
|
603
|
-
hdPath: props.hdPath || DEFAULT_HDPATH,
|
|
604
|
-
});
|
|
605
|
-
await wa
|
|
606
|
-
.getAccounts()
|
|
607
|
-
.then((x) => {
|
|
608
|
-
accounts = x;
|
|
609
|
-
if (accounts.length > 0) {
|
|
610
|
-
const [first] = accounts;
|
|
611
|
-
const connected = {
|
|
612
|
-
wallet: WalletName.Keplr,
|
|
613
|
-
cosmosAddress: first.address,
|
|
614
|
-
hdPath: props.hdPath || DEFAULT_HDPATH,
|
|
615
|
-
};
|
|
616
|
-
writeWallet(connected, props.hdPath || DEFAULT_HDPATH);
|
|
617
|
-
}
|
|
618
|
-
})
|
|
619
|
-
.catch((e) => {
|
|
620
|
-
error.value = e;
|
|
621
|
-
});
|
|
622
|
-
initData();
|
|
623
|
-
view.value = 'swap'
|
|
624
|
-
} catch (e) {
|
|
625
|
-
error.value = e.message;
|
|
626
|
-
}
|
|
627
|
-
sending.value = false;
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
// Excuting result
|
|
631
|
-
const delay = ref(0);
|
|
632
|
-
const step = ref(0);
|
|
633
|
-
const msg = ref('');
|
|
634
|
-
const sleep = 6000;
|
|
635
|
-
const emit = defineEmits(['completed']);
|
|
636
|
-
|
|
637
|
-
function showResult(hash: string) {
|
|
638
|
-
view.value = 'submitting';
|
|
639
|
-
delay.value = 1;
|
|
640
|
-
step.value = 20;
|
|
641
|
-
error.value = '';
|
|
642
|
-
msg.value = 'Proccessing...';
|
|
643
|
-
setTimeout(() => {
|
|
644
|
-
fetchTx(hash);
|
|
645
|
-
}, sleep);
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
function fetchTx(tx: string) {
|
|
649
|
-
delay.value += 1;
|
|
650
|
-
step.value += 20;
|
|
651
|
-
getTxByHash(OSMOSIS_REST, tx)
|
|
652
|
-
.then((res) => {
|
|
653
|
-
step.value = 100;
|
|
654
|
-
if (res.tx_response.code > 0) {
|
|
655
|
-
error.value = res.tx_response.raw_log;
|
|
656
|
-
} else {
|
|
657
|
-
msg.value = `Congratulations! Swap completed successfully.`;
|
|
658
|
-
emit('completed', { hash: tx, });
|
|
659
|
-
}
|
|
660
|
-
})
|
|
661
|
-
.catch(() => {
|
|
662
|
-
if (delay.value < 5) {
|
|
663
|
-
setTimeout(() => fetchTx(tx), sleep);
|
|
664
|
-
} else {
|
|
665
|
-
error.value = 'Timeout';
|
|
666
|
-
}
|
|
667
|
-
});
|
|
668
|
-
}
|
|
669
|
-
</script>
|
|
670
|
-
<template>
|
|
671
|
-
<div>
|
|
672
|
-
<!-- modal content -->
|
|
673
|
-
<input v-model="open" type="checkbox" id="PingTokenConvert" class="modal-toggle" @change="initData()" />
|
|
674
|
-
|
|
675
|
-
<label for="PingTokenConvert" class="modal cursor-pointer">
|
|
676
|
-
<label class="modal-box
|
|
677
|
-
<div v-show="view === 'swap'">
|
|
678
|
-
<div class="absolute right-4 top-4 dropdown dropdown-end dropdown-hover">
|
|
679
|
-
<label tabindex="0" class="text-info">
|
|
680
|
-
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
|
681
|
-
class="w-6 h-6 stroke-current">
|
|
682
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
|
683
|
-
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
|
684
|
-
</svg>
|
|
685
|
-
</label>
|
|
686
|
-
<div tabindex="0"
|
|
687
|
-
class="card
|
|
688
|
-
<div class="card-body">
|
|
689
|
-
<ul class="text-right">
|
|
690
|
-
<li>Liquidity is provided by Osmosis</li>
|
|
691
|
-
<li>Powered by Ping.pub</li>
|
|
692
|
-
</ul>
|
|
693
|
-
</div>
|
|
694
|
-
</div>
|
|
695
|
-
</div>
|
|
696
|
-
<h3 class="text-xl font-semibold">Token Convert</h3>
|
|
697
|
-
<div v-if="!osmosisPath || chainName === 'osmosis'" class="text-error mt-3">
|
|
698
|
-
<span>This feature is not available [{{
|
|
699
|
-
chainName
|
|
700
|
-
}}]</span>
|
|
701
|
-
</div>
|
|
702
|
-
<div
|
|
703
|
-
class="flex items-center relative h-14 bg-gray-100 dark:bg-[#
|
|
704
|
-
<div class="dropdown">
|
|
705
|
-
<label tabindex="0" class="flex items-center h-12 px-4 cursor-pointer">
|
|
706
|
-
<img :src="swapIn?.coinImageUrl" class="w-8 h-8 mr-3 rounded-full" />
|
|
707
|
-
<div class="text-lg font-semibold mr-2">
|
|
708
|
-
{{ swapIn?.symbol }}
|
|
709
|
-
</div>
|
|
710
|
-
<Icon icon="mdi:chevron-down" class="text-lg" />
|
|
711
|
-
</label>
|
|
712
|
-
<div tabindex="0" class="dropdown-content shadow
|
|
713
|
-
<div class="py-2">
|
|
714
|
-
<div v-for="(item, index) in inTokens" :key="index"
|
|
715
|
-
class="flex items-center px-4 py-2 hover:bg-gray-200 dark:hover:bg-
|
|
716
|
-
@click="selectInput(item)">
|
|
717
|
-
<img class="w-7 h-7 rounded-full mr-2" :src="item.coinImageUrl" />
|
|
718
|
-
<div class="flex-1 text-sm">
|
|
719
|
-
{{ item.symbol }}
|
|
720
|
-
</div>
|
|
721
|
-
<div class="text-sm font-semibold text-gray-600">
|
|
722
|
-
{{
|
|
723
|
-
showBalance(
|
|
724
|
-
item.ibcDenom || item.denom,
|
|
725
|
-
item.decimals
|
|
726
|
-
)
|
|
727
|
-
}}
|
|
728
|
-
</div>
|
|
729
|
-
</div>
|
|
730
|
-
</div>
|
|
731
|
-
</div>
|
|
732
|
-
</div>
|
|
733
|
-
<input v-model="amountIn" type="number" placeholder="1"
|
|
734
|
-
class="input bg-transparent flex-1 h-14 text-right text-lg font-bold" />
|
|
735
|
-
</div>
|
|
736
|
-
|
|
737
|
-
<div class="flex items-center py-2 px-4 bg-gray-200 dark:bg-
|
|
738
|
-
<div class="mr-3 text-sm">Balance:</div>
|
|
739
|
-
<div class="text-base font-semibold">
|
|
740
|
-
{{
|
|
741
|
-
showBalance(swapIn?.ibcDenom, swapIn?.decimals)
|
|
742
|
-
}}
|
|
743
|
-
</div>
|
|
744
|
-
<Icon v-if="depositable" icon="mdi:plus-box-outline" class="ml-2 cursor-pointer"
|
|
745
|
-
@click="switchView('deposit')" />
|
|
746
|
-
</div>
|
|
747
|
-
|
|
748
|
-
<!-- switch btn -->
|
|
749
|
-
<div class="flex items-center justify-center -mt-3 -mb-3">
|
|
750
|
-
<div class="inline-block px-4 cursor-pointer" @click="switchDirection">
|
|
751
|
-
<Icon icon="mdi:arrow-down-circle" color="#676cf6"
|
|
752
|
-
class="text-4xl dark:bg-gray-50 rounded-full origin-center duration-300 transform hover:rotate-180" />
|
|
753
|
-
</div>
|
|
754
|
-
</div>
|
|
755
|
-
|
|
756
|
-
<div class="flex items-center h-14 rounded-tl-lg rounded-tr-lg bg-gray-100 dark:bg-[#
|
|
757
|
-
<div v-if="outTokens.length === 0">
|
|
758
|
-
<span v-if="error" class="text-red-500">No tradable tokens found.</span>
|
|
759
|
-
<button v-else class="btn btn-ghost" :class="{ 'loading relative start-0': sending }">
|
|
760
|
-
loading...
|
|
761
|
-
</button>
|
|
762
|
-
</div>
|
|
763
|
-
<div v-if="outTokens && outTokens.length > 0" class="dropdown">
|
|
764
|
-
<label tabindex="0" class="flex items-center h-12 px-4 cursor-pointer">
|
|
765
|
-
<img :src="swapOut?.coinImageUrl" class="w-8 h-8 mr-3 rounded-full" />
|
|
766
|
-
<div class="text-lg font-semibold mr-2">
|
|
767
|
-
{{ swapOut?.symbol }}
|
|
768
|
-
</div>
|
|
769
|
-
<Icon icon="mdi:chevron-down" class="text-lg" />
|
|
770
|
-
</label>
|
|
771
|
-
<div tabindex="0" class="
|
|
772
|
-
<div class="py-2 max-h-40 overflow-y-auto">
|
|
773
|
-
<div v-for="(item, index) in outTokens" :key="index" @click="selectOutput(item)"
|
|
774
|
-
class="flex items-center px-4 py-2 max-h-36 overflow-y-auto hover:bg-gray-200 dark:hover:bg-
|
|
775
|
-
<img class="w-7 h-7 rounded-full mr-2" :src="item.coinImageUrl" />
|
|
776
|
-
<div class="flex-1 text-sm">
|
|
777
|
-
{{ item.symbol }}
|
|
778
|
-
</div>
|
|
779
|
-
<div class="text-sm font-semibold text-gray-600">
|
|
780
|
-
{{
|
|
781
|
-
showBalance(
|
|
782
|
-
item.ibcDenom || item.denom,
|
|
783
|
-
item.decimals
|
|
784
|
-
)
|
|
785
|
-
}}
|
|
786
|
-
</div>
|
|
787
|
-
</div>
|
|
788
|
-
</div>
|
|
789
|
-
</div>
|
|
790
|
-
</div>
|
|
791
|
-
<div class="flex-1 w-0 text-xl text-right font-semibold text-gray-600 dark:text-gray-50 pr-4">
|
|
792
|
-
{{ `≈ ${parseFloat(outAmount.toFixed(6))}` }}
|
|
793
|
-
</div>
|
|
794
|
-
</div>
|
|
795
|
-
|
|
796
|
-
<div class="flex items-center py-2 px-4 bg-gray-200 dark:bg-
|
|
797
|
-
<div class="mr-3 text-sm dark:text-gray-400">
|
|
798
|
-
Balance:
|
|
799
|
-
</div>
|
|
800
|
-
<div class="text-base font-semibold dark:text-gray-200">
|
|
801
|
-
{{
|
|
802
|
-
showBalance(
|
|
803
|
-
swapOut?.ibcDenom,
|
|
804
|
-
swapOut?.decimals
|
|
805
|
-
)
|
|
806
|
-
}}
|
|
807
|
-
</div>
|
|
808
|
-
<Icon v-if="withdrawable" icon="mdi:minus-box-outline" class="ml-2 cursor-pointer"
|
|
809
|
-
@click="switchView('withdraw')" />
|
|
810
|
-
</div>
|
|
811
|
-
|
|
812
|
-
<div class="px-4 mt-4">
|
|
813
|
-
<div class="flex items-center justify-between">
|
|
814
|
-
<div class="text-sm text-gray-600 dark:text-gray-400">
|
|
815
|
-
Swap Fee
|
|
816
|
-
</div>
|
|
817
|
-
<div class="text-base text-gray-800 dark:text-gray-200">
|
|
818
|
-
{{
|
|
819
|
-
decimal2percent(pool?.pool_params.swap_fee)
|
|
820
|
-
}}%
|
|
821
|
-
</div>
|
|
822
|
-
</div>
|
|
823
|
-
</div>
|
|
824
|
-
|
|
825
|
-
<div v-if="error" class="text-error mt-3">
|
|
826
|
-
<span>{{ error }}.</span>
|
|
827
|
-
</div>
|
|
828
|
-
|
|
829
|
-
<div class="mt-5">
|
|
830
|
-
<button class="btn btn-primary w-full ping-connect-confirm capitalize text-base"
|
|
831
|
-
:disabled="disabled" @click="doSwap">
|
|
832
|
-
<span v-if="sending" class="loading loading-spinner"></span>
|
|
833
|
-
Convert
|
|
834
|
-
</button>
|
|
835
|
-
</div>
|
|
836
|
-
</div>
|
|
837
|
-
<!-- deposit -->
|
|
838
|
-
<div v-show="view === 'deposit'">
|
|
839
|
-
<h3 class="text-xl font-semibold flex">
|
|
840
|
-
<Icon class="mt-1" icon="mdi:chevron-left" @click="switchView('swap')"></Icon>
|
|
841
|
-
Deposit
|
|
842
|
-
</h3>
|
|
843
|
-
|
|
844
|
-
<div class="form-control">
|
|
845
|
-
<label class="label">
|
|
846
|
-
<span class="label-text">Deposit assets into Osmosis:</span>
|
|
847
|
-
<span class="lable-text">{{
|
|
848
|
-
showBalance(swapIn?.ibcDenom, swapIn?.decimals)
|
|
849
|
-
}}</span>
|
|
850
|
-
</label>
|
|
851
|
-
<input :value="osmoAddress(sender.cosmosAddress)" readonly type="text"
|
|
852
|
-
class="input
|
|
853
|
-
</div>
|
|
854
|
-
<div
|
|
855
|
-
class="flex items-center relative h-14 bg-gray-100 dark:bg-[#
|
|
856
|
-
<label tabindex="0" class="flex items-center h-12 px-4 cursor-pointer">
|
|
857
|
-
<img :src="swapIn?.coinImageUrl" class="w-8 h-8 mr-3 rounded-full" />
|
|
858
|
-
<div class="text-lg font-semibold mr-2">
|
|
859
|
-
{{ swapIn?.symbol }}
|
|
860
|
-
</div>
|
|
861
|
-
</label>
|
|
862
|
-
<input v-model="depositAmount" type="number" placeholder="1"
|
|
863
|
-
class="input bg-transparent flex-1 h-14 text-right text-lg font-bold" />
|
|
864
|
-
</div>
|
|
865
|
-
|
|
866
|
-
<div
|
|
867
|
-
class="flex flex-row-reverse items-center py-2 px-4 bg-gray-200 dark:bg-
|
|
868
|
-
<div class="text-base font-semibold">
|
|
869
|
-
{{
|
|
870
|
-
showLocalBalance(
|
|
871
|
-
swapIn?.denom,
|
|
872
|
-
swapIn?.decimals
|
|
873
|
-
)
|
|
874
|
-
}}
|
|
875
|
-
</div>
|
|
876
|
-
<div class="mr-3 text-sm">Balance:</div>
|
|
877
|
-
</div>
|
|
878
|
-
|
|
879
|
-
<div v-if="error" class="text-error mt-3">
|
|
880
|
-
<span>{{ error }}.</span>
|
|
881
|
-
</div>
|
|
882
|
-
|
|
883
|
-
<div class="mt-5 flex">
|
|
884
|
-
<label class="btn
|
|
885
|
-
<svg fill="#ffffff" height="20px" width="20px" version="1.1" id="Layer_1"
|
|
886
|
-
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
887
|
-
viewBox="0 0 330 330" xml:space="preserve">
|
|
888
|
-
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
|
|
889
|
-
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>
|
|
890
|
-
<g id="SVGRepo_iconCarrier">
|
|
891
|
-
<path id="XMLID_6_"
|
|
892
|
-
d="M165,0C74.019,0,0,74.019,0,165s74.019,165,165,165s165-74.019,165-165S255.981,0,165,0z M205.606,234.394 c5.858,5.857,5.858,15.355,0,21.213C202.678,258.535,198.839,260,195,260s-7.678-1.464-10.606-4.394l-80-79.998 c-2.813-2.813-4.394-6.628-4.394-10.606c0-3.978,1.58-7.794,4.394-10.607l80-80.002c5.857-5.858,15.355-5.858,21.213,0 c5.858,5.857,5.858,15.355,0,21.213l-69.393,69.396L205.606,234.394z">
|
|
893
|
-
</path>
|
|
894
|
-
</g>
|
|
895
|
-
</svg>
|
|
896
|
-
</label>
|
|
897
|
-
<button class="btn btn-primary grow ping-connect-confirm capitalize text-base"
|
|
898
|
-
:disabled="disableDeposit" @click="doDeposit">
|
|
899
|
-
<span v-if="sending" class="loading loading-spinner"></span>
|
|
900
|
-
Deposit
|
|
901
|
-
</button>
|
|
902
|
-
</div>
|
|
903
|
-
</div>
|
|
904
|
-
|
|
905
|
-
<!-- withdraw -->
|
|
906
|
-
<div v-show="view === 'withdraw'">
|
|
907
|
-
<h3 class="text-xl font-semibold flex">
|
|
908
|
-
<Icon class="mt-1" icon="mdi:chevron-left" @click="switchView('swap')"></Icon>
|
|
909
|
-
Withdraw
|
|
910
|
-
</h3>
|
|
911
|
-
|
|
912
|
-
<div
|
|
913
|
-
class="flex justify-between j items-center py-2 px-4 bg-gray-200 dark:bg-
|
|
914
|
-
<div class="text-sm">Withdrawable Balance:</div>
|
|
915
|
-
<div class="text-base font-semibold">
|
|
916
|
-
{{
|
|
917
|
-
showBalance(
|
|
918
|
-
swapOut?.ibcDenom,
|
|
919
|
-
swapOut?.decimals
|
|
920
|
-
)
|
|
921
|
-
}}
|
|
922
|
-
</div>
|
|
923
|
-
</div>
|
|
924
|
-
<div class="flex items-center relative h-14 bg-gray-100 dark:bg-[#
|
|
925
|
-
<label tabindex="0" class="flex items-center h-12 px-4 cursor-pointer">
|
|
926
|
-
<img :src="swapOut?.coinImageUrl" class="w-8 h-8 mr-3 rounded-full" />
|
|
927
|
-
<div class="text-lg font-semibold mr-2">
|
|
928
|
-
{{ swapOut?.symbol }}
|
|
929
|
-
</div>
|
|
930
|
-
</label>
|
|
931
|
-
<input v-model="withdrawAmount" type="number" placeholder="1"
|
|
932
|
-
class="input bg-transparent flex-1 h-14 text-right text-lg font-bold" />
|
|
933
|
-
</div>
|
|
934
|
-
|
|
935
|
-
<div class="form-control">
|
|
936
|
-
<label class="label">
|
|
937
|
-
<span class="label-text">Recipient on
|
|
938
|
-
{{ localChainInfo.pretty_name }}</span>
|
|
939
|
-
<span class="lable-text">{{
|
|
940
|
-
showLocalBalance(
|
|
941
|
-
swapOut?.denom,
|
|
942
|
-
swapOut?.decimals
|
|
943
|
-
)
|
|
944
|
-
}}</span>
|
|
945
|
-
</label>
|
|
946
|
-
<input v-model="recipient" type="text" class="input
|
|
947
|
-
</div>
|
|
948
|
-
<div v-if="error" class="text-error mt-3">
|
|
949
|
-
<span>{{ error }}.</span>
|
|
950
|
-
</div>
|
|
951
|
-
|
|
952
|
-
<div class="mt-5 flex">
|
|
953
|
-
<label class="btn
|
|
954
|
-
<svg fill="#ffffff" height="20px" width="20px" version="1.1" id="Layer_1"
|
|
955
|
-
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
956
|
-
viewBox="0 0 330 330" xml:space="preserve">
|
|
957
|
-
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
|
|
958
|
-
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>
|
|
959
|
-
<g id="SVGRepo_iconCarrier">
|
|
960
|
-
<path id="XMLID_6_"
|
|
961
|
-
d="M165,0C74.019,0,0,74.019,0,165s74.019,165,165,165s165-74.019,165-165S255.981,0,165,0z M205.606,234.394 c5.858,5.857,5.858,15.355,0,21.213C202.678,258.535,198.839,260,195,260s-7.678-1.464-10.606-4.394l-80-79.998 c-2.813-2.813-4.394-6.628-4.394-10.606c0-3.978,1.58-7.794,4.394-10.607l80-80.002c5.857-5.858,15.355-5.858,21.213,0 c5.858,5.857,5.858,15.355,0,21.213l-69.393,69.396L205.606,234.394z">
|
|
962
|
-
</path>
|
|
963
|
-
</g>
|
|
964
|
-
</svg>
|
|
965
|
-
</label>
|
|
966
|
-
<button class="btn btn-primary
|
|
967
|
-
:disabled="disableWithdraw" @click="doWithdraw()">
|
|
968
|
-
<span v-if="sending" class="loading loading-spinner"></span>
|
|
969
|
-
Withdraw
|
|
970
|
-
</button>
|
|
971
|
-
</div>
|
|
972
|
-
</div>
|
|
973
|
-
|
|
974
|
-
<!-- Connect Wallet -->
|
|
975
|
-
<div v-show="view === 'connect'">
|
|
976
|
-
<h3 class="text-xl font-semibold flex dark:text-white">Connect Wallet</h3>
|
|
977
|
-
<div class="form-control mt-5 dark:bg-[#
|
|
978
|
-
<select class="select">
|
|
979
|
-
<option>Keplr</option>
|
|
980
|
-
</select>
|
|
981
|
-
</div>
|
|
982
|
-
|
|
983
|
-
<div v-if="error" class="text-error mt-3">
|
|
984
|
-
<span>{{ error }}.</span>
|
|
985
|
-
</div>
|
|
986
|
-
|
|
987
|
-
<div class="mt-5">
|
|
988
|
-
<button class="btn btn-primary
|
|
989
|
-
<span v-if="sending" class="loading loading-spinner"></span>
|
|
990
|
-
Connect
|
|
991
|
-
</button>
|
|
992
|
-
</div>
|
|
993
|
-
</div>
|
|
994
|
-
|
|
995
|
-
<div v-show="view === 'submitting'">
|
|
996
|
-
<div class="mt-10 mb-6">
|
|
997
|
-
<div v-if="error" class="my-5 text-center text-red-500">
|
|
998
|
-
{{ error }}
|
|
999
|
-
</div>
|
|
1000
|
-
<div v-else class="my-5 text-center text-lg text-green-500">
|
|
1001
|
-
{{ msg }}
|
|
1002
|
-
</div>
|
|
1003
|
-
<div class="overflow-hidden h-5 mb-2 text-xs flex rounded bg-green-100">
|
|
1004
|
-
<div :style="`width: ${step}%`"
|
|
1005
|
-
class="shadow-none flex flex-col text-center whitespace-nowrap text-white justify-center bg-green-400">
|
|
1006
|
-
</div>
|
|
1007
|
-
</div>
|
|
1008
|
-
<div class="flex items-center justify-between">
|
|
1009
|
-
<div>
|
|
1010
|
-
<span
|
|
1011
|
-
class="text-xs font-semibold inline-block py-1 px-2 rounded text-gray-600 dark:text-white">
|
|
1012
|
-
Submitted
|
|
1013
|
-
</span>
|
|
1014
|
-
</div>
|
|
1015
|
-
<div class="text-right">
|
|
1016
|
-
<span class="text-xs font-semibold inline-block text-gray-600 dark:text-white">
|
|
1017
|
-
{{ step }}%
|
|
1018
|
-
</span>
|
|
1019
|
-
</div>
|
|
1020
|
-
</div>
|
|
1021
|
-
</div>
|
|
1022
|
-
<div class="mb-0 text-center">
|
|
1023
|
-
<label class="btn btn-link" @click="view = 'swap'">Continue</label>
|
|
1024
|
-
</div>
|
|
1025
|
-
</div>
|
|
1026
|
-
</label>
|
|
1027
|
-
</label>
|
|
1028
|
-
</div></template>
|
|
1029
|
-
<script lang="ts">
|
|
1030
|
-
export default {
|
|
1031
|
-
name: 'TokenConvert',
|
|
1032
|
-
};
|
|
1033
|
-
</script>
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, onMounted, ref } from 'vue';
|
|
3
|
+
import { Icon } from '@iconify/vue';
|
|
4
|
+
import { fromBech32, toBech32, toHex } from '@cosmjs/encoding';
|
|
5
|
+
import { sha256 } from '@cosmjs/crypto';
|
|
6
|
+
import ChainRegistryClient from '@ping-pub/chain-registry-client';
|
|
7
|
+
import {
|
|
8
|
+
Asset,
|
|
9
|
+
Chain,
|
|
10
|
+
IBCInfo,
|
|
11
|
+
IBCPath,
|
|
12
|
+
} from '@ping-pub/chain-registry-client/dist/types';
|
|
13
|
+
import {
|
|
14
|
+
getBalance,
|
|
15
|
+
getStakingParam,
|
|
16
|
+
getOsmosisPools,
|
|
17
|
+
getLatestBlock,
|
|
18
|
+
getAccount,
|
|
19
|
+
getTxByHash,
|
|
20
|
+
} from '../../utils/http';
|
|
21
|
+
import {
|
|
22
|
+
Account,
|
|
23
|
+
ConnectedWallet,
|
|
24
|
+
WalletName,
|
|
25
|
+
createWallet,
|
|
26
|
+
readWallet,
|
|
27
|
+
writeWallet,
|
|
28
|
+
} from '../../wallet/Wallet';
|
|
29
|
+
import { Coin } from '../../utils/type';
|
|
30
|
+
import { osmosis, ibc, getSigningOsmosisClient } from 'osmojs';
|
|
31
|
+
import { tokens, type TokenConfig } from './tokens';
|
|
32
|
+
import { decimal2percent } from '../../utils/format';
|
|
33
|
+
import { StdFee, coin } from '@cosmjs/stargate';
|
|
34
|
+
import Long from 'long';
|
|
35
|
+
import { UniClient } from '../../wallet/UniClient';
|
|
36
|
+
|
|
37
|
+
const props = defineProps({
|
|
38
|
+
chainName: { type: String, required: true },
|
|
39
|
+
endpoint: { type: String, required: true },
|
|
40
|
+
hdPath: String,
|
|
41
|
+
});
|
|
42
|
+
const OSMOSIS_RPC = 'https://rpc.osmosis.zone';
|
|
43
|
+
const OSMOSIS_REST = 'https://lcd.osmosis.zone';
|
|
44
|
+
const DEFAULT_HDPATH = "m/44'/118/0'/0/0";
|
|
45
|
+
|
|
46
|
+
const view = ref('connect'); // [connect, swap, deposit, withdraw]
|
|
47
|
+
|
|
48
|
+
function switchView(v: string) {
|
|
49
|
+
view.value = v;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// variables
|
|
53
|
+
const direction = ref('buy');
|
|
54
|
+
const sending = ref(false); // show status on send tx
|
|
55
|
+
const open = ref(false);
|
|
56
|
+
const error = ref('');
|
|
57
|
+
const chains = ref([] as IBCPath[]);
|
|
58
|
+
const osmosisPath = ref({} as IBCPath | undefined);
|
|
59
|
+
const osmosisPathInfo = ref({} as IBCInfo);
|
|
60
|
+
const defaultDenom = ref('');
|
|
61
|
+
const sender = ref({} as ConnectedWallet);
|
|
62
|
+
const localBalances = ref([] as Coin[]);
|
|
63
|
+
const osmoBalances = ref([] as Coin[]);
|
|
64
|
+
const localChainInfo = ref({} as Chain);
|
|
65
|
+
const localCoinInfo = ref([] as Asset[]);
|
|
66
|
+
const swapIn = ref({} as TokenConfig | undefined);
|
|
67
|
+
const swapOut = ref({} as TokenConfig | undefined);
|
|
68
|
+
const amountIn = ref('');
|
|
69
|
+
const allPools = ref([] as any[]);
|
|
70
|
+
const client = new ChainRegistryClient();
|
|
71
|
+
|
|
72
|
+
// swap logic
|
|
73
|
+
|
|
74
|
+
async function initData() {
|
|
75
|
+
error.value = ''; //reset error
|
|
76
|
+
sender.value = readWallet(props.hdPath);
|
|
77
|
+
if (!sender.value.cosmosAddress) {
|
|
78
|
+
view.value = 'connect';
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (open.value) {
|
|
82
|
+
view.value = 'swap';
|
|
83
|
+
localChainInfo.value = {} as Chain;
|
|
84
|
+
localCoinInfo.value = [];
|
|
85
|
+
recipient.value = localAddress(sender.value.cosmosAddress)
|
|
86
|
+
await client
|
|
87
|
+
.fetchChainInfo(props.chainName)
|
|
88
|
+
.then((res) => {
|
|
89
|
+
localChainInfo.value = res;
|
|
90
|
+
if (Number(res.slip44) !== 118) {
|
|
91
|
+
error.value === `Coin type ${res.slip44} is not supported`;
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
.catch(() => {
|
|
95
|
+
error.value = 'Not found IBC Path';
|
|
96
|
+
});
|
|
97
|
+
getBalance(OSMOSIS_REST, osmoAddress(sender.value.cosmosAddress)).then(
|
|
98
|
+
(res) => {
|
|
99
|
+
osmoBalances.value = res.balances.filter(
|
|
100
|
+
(x) => !x.denom.startsWith('gamm')
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
);
|
|
104
|
+
getBalance(
|
|
105
|
+
props.endpoint,
|
|
106
|
+
localAddress(sender.value.cosmosAddress)
|
|
107
|
+
).then((res) => {
|
|
108
|
+
localBalances.value = res.balances;
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
client.fetchAssetsList(props.chainName).then((al) => {
|
|
112
|
+
localCoinInfo.value = al.assets;
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
getStakingParam(props.endpoint).then((x) => {
|
|
116
|
+
defaultDenom.value = x.params.bond_denom;
|
|
117
|
+
});
|
|
118
|
+
getOsmosisPools(OSMOSIS_REST).then((res) => {
|
|
119
|
+
allPools.value = res.pools;
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
client.fetchIBCPaths().then((paths) => {
|
|
123
|
+
chains.value = paths.filter(
|
|
124
|
+
(x) => x.from === props.chainName || x.to === props.chainName
|
|
125
|
+
);
|
|
126
|
+
const path = chains.value.find(
|
|
127
|
+
(x) => x.from === 'osmosis' || x.to === 'osmosis'
|
|
128
|
+
);
|
|
129
|
+
if (path) {
|
|
130
|
+
osmosisPath.value = path;
|
|
131
|
+
client.fetchIBCPathInfo(path.path).then((info) => {
|
|
132
|
+
osmosisPathInfo.value = info;
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function osmoAddress(addr?: string) {
|
|
140
|
+
if (!addr) return '';
|
|
141
|
+
const { data } = fromBech32(addr);
|
|
142
|
+
return toBech32('osmo', data);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function localAddress(addr?: string) {
|
|
146
|
+
if (!addr) return '';
|
|
147
|
+
const { data } = fromBech32(addr);
|
|
148
|
+
const prefix = localChainInfo.value?.bech32_prefix || 'cosmos';
|
|
149
|
+
return toBech32(prefix, data);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function showBalance(denom?: string, decimal = 0) {
|
|
153
|
+
const bal = osmoBalances.value.find((x) => x.denom === denom || '');
|
|
154
|
+
if (bal) {
|
|
155
|
+
return Number(bal.amount) / 10 ** decimal;
|
|
156
|
+
}
|
|
157
|
+
return 0;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function findlocalCoinDecimal(denom: string) {
|
|
161
|
+
const localCoin = localCoinInfo.value.find((x) => x.base === denom);
|
|
162
|
+
if (localCoin) {
|
|
163
|
+
const unit = localCoin.denom_units.find(
|
|
164
|
+
(x) => x.denom === localCoin.symbol.toLowerCase()
|
|
165
|
+
);
|
|
166
|
+
if (unit) return unit.exponent;
|
|
167
|
+
}
|
|
168
|
+
return 0;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function findTokenUrl(coinInfo?: Asset) {
|
|
172
|
+
const url =
|
|
173
|
+
coinInfo?.logo_URIs?.svg ||
|
|
174
|
+
coinInfo?.logo_URIs?.png ||
|
|
175
|
+
coinInfo?.logo_URIs?.jpeg;
|
|
176
|
+
return url
|
|
177
|
+
? url.replace(
|
|
178
|
+
'https://raw.githubusercontent.com/cosmos/chain-registry/master',
|
|
179
|
+
'https://registry.ping.pub'
|
|
180
|
+
)
|
|
181
|
+
: '';
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const localTokenOnOsmosis = computed(() => {
|
|
185
|
+
const channel = osmosisPathInfo.value.channels?.find(
|
|
186
|
+
(x) => x.chain_1.port_id === 'transfer'
|
|
187
|
+
);
|
|
188
|
+
const channelId =
|
|
189
|
+
osmosisPathInfo.value.chain_1?.chain_name === 'osmosis'
|
|
190
|
+
? channel?.chain_1.channel_id
|
|
191
|
+
: channel?.chain_2.channel_id;
|
|
192
|
+
const ibcDenom = toHex(
|
|
193
|
+
sha256(
|
|
194
|
+
new TextEncoder().encode(
|
|
195
|
+
`transfer/${channelId}/${defaultDenom.value}`
|
|
196
|
+
)
|
|
197
|
+
)
|
|
198
|
+
).toUpperCase();
|
|
199
|
+
return localCoinInfo.value?.map((localCoin) => ({
|
|
200
|
+
denom: defaultDenom.value,
|
|
201
|
+
symbol: localCoin.symbol || '',
|
|
202
|
+
ibcDenom: `ibc/${ibcDenom}`,
|
|
203
|
+
sourceChannelId: channelId,
|
|
204
|
+
decimals: findlocalCoinDecimal(defaultDenom.value),
|
|
205
|
+
coinImageUrl: findTokenUrl(localCoin),
|
|
206
|
+
}));
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
const localSourceChannelID = computed(() => {
|
|
210
|
+
const channel = osmosisPathInfo.value.channels?.find(
|
|
211
|
+
(x) => x.chain_1.port_id === 'transfer'
|
|
212
|
+
);
|
|
213
|
+
const channelId =
|
|
214
|
+
osmosisPathInfo.value.chain_1?.chain_name === 'osmosis'
|
|
215
|
+
? channel?.chain_2.channel_id
|
|
216
|
+
: channel?.chain_1.channel_id;
|
|
217
|
+
return channelId;
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
const withdrawable = computed(() => {
|
|
221
|
+
return (
|
|
222
|
+
localTokenOnOsmosis.value.findIndex(
|
|
223
|
+
(x) => x.denom === swapOut.value?.denom
|
|
224
|
+
) > -1
|
|
225
|
+
);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
const depositable = computed(() => {
|
|
229
|
+
return (
|
|
230
|
+
localTokenOnOsmosis.value.findIndex(
|
|
231
|
+
(x) => x.denom === swapIn.value?.denom
|
|
232
|
+
) > -1
|
|
233
|
+
);
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
const inTokens = computed(() => {
|
|
237
|
+
if (direction.value === 'buy') {
|
|
238
|
+
swapIn.value = tokens[0];
|
|
239
|
+
return tokens;
|
|
240
|
+
} else {
|
|
241
|
+
swapIn.value = localTokenOnOsmosis.value[0];
|
|
242
|
+
return localTokenOnOsmosis.value;
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
const outTokens = computed(() => {
|
|
247
|
+
if (direction.value === 'buy') {
|
|
248
|
+
swapOut.value = localTokenOnOsmosis.value[0];
|
|
249
|
+
return localTokenOnOsmosis.value;
|
|
250
|
+
} else {
|
|
251
|
+
swapOut.value = tokens[0];
|
|
252
|
+
return tokens;
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
function selectInput(v) {
|
|
257
|
+
swapIn.value = v;
|
|
258
|
+
amountIn.value = '';
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function selectOutput(v) {
|
|
262
|
+
swapOut.value = v;
|
|
263
|
+
amountIn.value = '';
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const pool = computed(() => {
|
|
267
|
+
// find the available pools and sort by liquidity depth
|
|
268
|
+
const a = allPools.value
|
|
269
|
+
.filter(
|
|
270
|
+
(x) =>
|
|
271
|
+
x.pool_assets?.findIndex(
|
|
272
|
+
(a) => a.token.denom === swapIn.value?.ibcDenom
|
|
273
|
+
) > -1
|
|
274
|
+
)
|
|
275
|
+
.filter(
|
|
276
|
+
(x) =>
|
|
277
|
+
x.pool_assets?.findIndex(
|
|
278
|
+
(a) => a.token.denom === swapOut.value?.ibcDenom
|
|
279
|
+
) > -1
|
|
280
|
+
)
|
|
281
|
+
.sort(
|
|
282
|
+
(a, b) =>
|
|
283
|
+
Number(b.total_shares.amount) - Number(a.total_shares.amount)
|
|
284
|
+
);
|
|
285
|
+
// console.log(a)
|
|
286
|
+
return a.length > 0 ? a[0] : null;
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
function switchDirection() {
|
|
290
|
+
direction.value = direction.value === 'buy' ? 'sell' : 'buy';
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const disabled = computed(() => {
|
|
294
|
+
const amount = Number(amountIn.value || 0);
|
|
295
|
+
if (amount <= 0 || outAmount.value <= 0) return true;
|
|
296
|
+
const token = swapIn.value;
|
|
297
|
+
const b = osmoBalances.value.find((x) => x.denom === token?.ibcDenom || '');
|
|
298
|
+
if (b && token) {
|
|
299
|
+
return Number(b.amount) < amount * 10 ** token.decimals;
|
|
300
|
+
}
|
|
301
|
+
return true;
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
const outAmount = computed(() => {
|
|
305
|
+
// tokenBalanceOut * [1 - { tokenBalanceIn / (tokenBalanceIn + (1 - swapFee) * tokenAmountIn)} ^ (tokenWeightIn / tokenWeightOut)]
|
|
306
|
+
const p = pool.value;
|
|
307
|
+
if (p) {
|
|
308
|
+
const tokenBalanceOut = p.pool_assets?.find(
|
|
309
|
+
(x) => x.token.denom === swapOut.value?.ibcDenom
|
|
310
|
+
);
|
|
311
|
+
const tokenBalanceIn = p.pool_assets?.find(
|
|
312
|
+
(x) => x.token.denom === swapIn.value?.ibcDenom
|
|
313
|
+
);
|
|
314
|
+
if (tokenBalanceIn && tokenBalanceOut) {
|
|
315
|
+
const balanceOut = Number(tokenBalanceOut.token.amount);
|
|
316
|
+
const balanceIn = Number(tokenBalanceIn.token.amount);
|
|
317
|
+
const weightOut = Number(tokenBalanceOut.weight);
|
|
318
|
+
const weightIn = Number(tokenBalanceIn.weight);
|
|
319
|
+
const swapFee = Number(p.pool_params.swap_fee);
|
|
320
|
+
const amount = Number(amountIn.value) * (1 - swapFee);
|
|
321
|
+
const out =
|
|
322
|
+
balanceOut *
|
|
323
|
+
(1 -
|
|
324
|
+
balanceIn / (balanceIn + amount) ** (weightIn / weightOut));
|
|
325
|
+
return out;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
return 0;
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
async function doSwap() {
|
|
332
|
+
sending.value = true;
|
|
333
|
+
try {
|
|
334
|
+
const latest = await getLatestBlock(OSMOSIS_REST);
|
|
335
|
+
|
|
336
|
+
const stargateClient = await getSigningOsmosisClient({
|
|
337
|
+
rpcEndpoint: OSMOSIS_RPC,
|
|
338
|
+
// @ts-ignore
|
|
339
|
+
signer: window.getOfflineSigner(latest.block.header.chain_id),
|
|
340
|
+
});
|
|
341
|
+
const address = osmoAddress(sender.value.cosmosAddress);
|
|
342
|
+
|
|
343
|
+
if (!swapIn.value || !swapOut.value || !address) return;
|
|
344
|
+
const { swapExactAmountIn } =
|
|
345
|
+
osmosis.gamm.v1beta1.MessageComposer.withTypeUrl;
|
|
346
|
+
|
|
347
|
+
const amount = Number(amountIn.value || 0);
|
|
348
|
+
const msg = swapExactAmountIn({
|
|
349
|
+
sender: address,
|
|
350
|
+
routes: [
|
|
351
|
+
{
|
|
352
|
+
poolId: Long.fromNumber(pool.value.id),
|
|
353
|
+
tokenOutDenom: swapOut.value.ibcDenom,
|
|
354
|
+
},
|
|
355
|
+
],
|
|
356
|
+
tokenIn: {
|
|
357
|
+
amount: (amount * 10 ** swapIn.value.decimals).toFixed(),
|
|
358
|
+
denom: swapIn.value.ibcDenom,
|
|
359
|
+
},
|
|
360
|
+
tokenOutMinAmount: (
|
|
361
|
+
outAmount.value *
|
|
362
|
+
0.99 *
|
|
363
|
+
10 ** swapOut.value.decimals
|
|
364
|
+
).toFixed(), // slippage: 1%
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
const gas = await stargateClient.simulate(address, [msg], '');
|
|
368
|
+
|
|
369
|
+
const fee: StdFee = {
|
|
370
|
+
amount: [
|
|
371
|
+
{
|
|
372
|
+
denom: 'uosmo',
|
|
373
|
+
amount: '864',
|
|
374
|
+
},
|
|
375
|
+
],
|
|
376
|
+
gas: (gas * 1.25).toFixed(),
|
|
377
|
+
};
|
|
378
|
+
const response = await stargateClient.signAndBroadcast(
|
|
379
|
+
address,
|
|
380
|
+
[msg],
|
|
381
|
+
fee,
|
|
382
|
+
'Token Convert from mictonode.com'
|
|
383
|
+
);
|
|
384
|
+
if (response.code === 0) {
|
|
385
|
+
await showResult(response.transactionHash)
|
|
386
|
+
await getBalance(
|
|
387
|
+
OSMOSIS_REST,
|
|
388
|
+
osmoAddress(sender.value.cosmosAddress)
|
|
389
|
+
).then((res) => {
|
|
390
|
+
osmoBalances.value = res.balances.filter(
|
|
391
|
+
(x) => !x.denom.startsWith('gamm')
|
|
392
|
+
);
|
|
393
|
+
});
|
|
394
|
+
} else {
|
|
395
|
+
if (response.rawLog) error.value = response.rawLog;
|
|
396
|
+
}
|
|
397
|
+
} catch (err) {
|
|
398
|
+
error.value = err;
|
|
399
|
+
}
|
|
400
|
+
sending.value = false;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// deposit logic
|
|
404
|
+
const depositAmount = ref('');
|
|
405
|
+
|
|
406
|
+
function showLocalBalance(denom = '', decimals = 0) {
|
|
407
|
+
const b = localBalances.value?.find((x) => x.denom === denom);
|
|
408
|
+
if (b) {
|
|
409
|
+
return Number(b.amount) / 10 ** decimals;
|
|
410
|
+
}
|
|
411
|
+
return 0;
|
|
412
|
+
}
|
|
413
|
+
const disableDeposit = computed(() => {
|
|
414
|
+
const token = swapIn.value;
|
|
415
|
+
if (token) {
|
|
416
|
+
const b = localBalances.value?.find((x) => x.denom === token.denom);
|
|
417
|
+
if (b) {
|
|
418
|
+
const amount = Number(depositAmount.value || 0);
|
|
419
|
+
return (
|
|
420
|
+
amount <= 0 || Number(b.amount) < amount * 10 ** token.decimals
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
return true;
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
async function doDeposit() {
|
|
428
|
+
sending.value = true;
|
|
429
|
+
|
|
430
|
+
const address = localAddress(sender.value.cosmosAddress);
|
|
431
|
+
|
|
432
|
+
if (!swapIn.value || !address) return;
|
|
433
|
+
|
|
434
|
+
const latest = await getLatestBlock(props.endpoint);
|
|
435
|
+
const acc = await getAccount(props.endpoint, address);
|
|
436
|
+
|
|
437
|
+
const chainId = latest.block.header.chain_id;
|
|
438
|
+
const timeout = Date.now() + new Date().getTimezoneOffset() + 3600000;
|
|
439
|
+
const amount = Number(depositAmount.value || 0) * 10 ** swapIn.value.decimals;
|
|
440
|
+
const tx = {
|
|
441
|
+
chainId,
|
|
442
|
+
signerAddress: address,
|
|
443
|
+
messages: [
|
|
444
|
+
{
|
|
445
|
+
typeUrl: '/ibc.applications.transfer.v1.MsgTransfer',
|
|
446
|
+
value: {
|
|
447
|
+
sourcePort: 'transfer',
|
|
448
|
+
sourceChannel: localSourceChannelID.value || '',
|
|
449
|
+
token: {
|
|
450
|
+
amount: String(amount),
|
|
451
|
+
denom: swapIn.value.denom,
|
|
452
|
+
},
|
|
453
|
+
sender: address,
|
|
454
|
+
receiver: osmoAddress(address),
|
|
455
|
+
timeoutTimestamp: `${timeout}000000`,
|
|
456
|
+
},
|
|
457
|
+
},
|
|
458
|
+
],
|
|
459
|
+
fee: {
|
|
460
|
+
gas: '200000',
|
|
461
|
+
amount: [{ amount: '5000', denom: swapIn.value.denom }],
|
|
462
|
+
},
|
|
463
|
+
memo: '',
|
|
464
|
+
signerData: {
|
|
465
|
+
chainId: chainId.value,
|
|
466
|
+
accountNumber: Number(acc.account.account_number),
|
|
467
|
+
sequence: Number(acc.account.sequence),
|
|
468
|
+
},
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
try {
|
|
472
|
+
const client = new UniClient(WalletName.Keplr, { chainId });
|
|
473
|
+
|
|
474
|
+
// console.log("gasInfo:", gasInfo)
|
|
475
|
+
const txRaw = await client.sign(tx);
|
|
476
|
+
const response = await client.broadcastTx(props.endpoint, txRaw);
|
|
477
|
+
if (response.tx_response?.code === 0) {
|
|
478
|
+
setTimeout(async () => {
|
|
479
|
+
await getBalance(
|
|
480
|
+
OSMOSIS_REST,
|
|
481
|
+
osmoAddress(sender.value.cosmosAddress)
|
|
482
|
+
).then((res) => {
|
|
483
|
+
osmoBalances.value = res.balances.filter(
|
|
484
|
+
(x) => !x.denom.startsWith('gamm')
|
|
485
|
+
);
|
|
486
|
+
});
|
|
487
|
+
await getBalance(
|
|
488
|
+
props.endpoint,
|
|
489
|
+
localAddress(sender.value.cosmosAddress)
|
|
490
|
+
).then((res) => {
|
|
491
|
+
localBalances.value = res.balances;
|
|
492
|
+
});
|
|
493
|
+
}, 6000);
|
|
494
|
+
}
|
|
495
|
+
} catch (e) {
|
|
496
|
+
sending.value = false;
|
|
497
|
+
error.value = e;
|
|
498
|
+
setTimeout(() => (error.value = ''), 5000);
|
|
499
|
+
}
|
|
500
|
+
sending.value = false;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// withdraw logic
|
|
504
|
+
const withdrawAmount = ref('');
|
|
505
|
+
const recipient = ref(localAddress(sender.value.cosmosAddress))
|
|
506
|
+
const disableWithdraw = computed(() => {
|
|
507
|
+
const token = swapOut.value;
|
|
508
|
+
if (token) {
|
|
509
|
+
const b = osmoBalances.value?.find((x) => x.denom === token.ibcDenom);
|
|
510
|
+
if (b) {
|
|
511
|
+
const amount = Number(withdrawAmount.value || 0);
|
|
512
|
+
return (
|
|
513
|
+
amount <= 0 || Number(b.amount) < amount * 10 ** token.decimals
|
|
514
|
+
);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
return true;
|
|
518
|
+
});
|
|
519
|
+
async function doWithdraw() {
|
|
520
|
+
sending.value = true;
|
|
521
|
+
try {
|
|
522
|
+
const latest = await getLatestBlock(OSMOSIS_REST);
|
|
523
|
+
|
|
524
|
+
const stargateClient = await getSigningOsmosisClient({
|
|
525
|
+
rpcEndpoint: OSMOSIS_RPC,
|
|
526
|
+
// @ts-ignore
|
|
527
|
+
signer: window.getOfflineSigner(latest.block.header.chain_id),
|
|
528
|
+
});
|
|
529
|
+
const address = osmoAddress(sender.value.cosmosAddress);
|
|
530
|
+
|
|
531
|
+
if (!swapIn.value || !swapOut.value || !address) return;
|
|
532
|
+
|
|
533
|
+
const timeout = Date.now() + new Date().getTimezoneOffset() + 3600000;
|
|
534
|
+
const amount = Number(withdrawAmount.value || 0);
|
|
535
|
+
const { transfer } =
|
|
536
|
+
ibc.applications.transfer.v1.MessageComposer.withTypeUrl;
|
|
537
|
+
const msg = transfer({
|
|
538
|
+
sender: address,
|
|
539
|
+
sourceChannel: swapOut.value.sourceChannelId || '',
|
|
540
|
+
sourcePort: 'transfer',
|
|
541
|
+
token: {
|
|
542
|
+
amount: (amount * 10 ** swapOut.value.decimals).toFixed(),
|
|
543
|
+
denom: swapOut.value.ibcDenom,
|
|
544
|
+
},
|
|
545
|
+
receiver: recipient.value,
|
|
546
|
+
timeoutTimestamp: Long.fromString(`${timeout}000000`),
|
|
547
|
+
timeoutHeight: {
|
|
548
|
+
revisionHeight: Long.fromNumber(0),
|
|
549
|
+
revisionNumber: Long.fromNumber(0),
|
|
550
|
+
},
|
|
551
|
+
memo: '',
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
const gas = await stargateClient.simulate(address, [msg], '');
|
|
555
|
+
|
|
556
|
+
const fee: StdFee = {
|
|
557
|
+
amount: [
|
|
558
|
+
{
|
|
559
|
+
denom: 'uosmo',
|
|
560
|
+
amount: '1864',
|
|
561
|
+
},
|
|
562
|
+
],
|
|
563
|
+
gas: (gas * 1.25).toFixed(),
|
|
564
|
+
};
|
|
565
|
+
const response = await stargateClient.signAndBroadcast(
|
|
566
|
+
address,
|
|
567
|
+
[msg],
|
|
568
|
+
fee,
|
|
569
|
+
'Convert on ping.pub'
|
|
570
|
+
);
|
|
571
|
+
if (response.code === 0) {
|
|
572
|
+
await getBalance(
|
|
573
|
+
OSMOSIS_REST,
|
|
574
|
+
osmoAddress(sender.value.cosmosAddress)
|
|
575
|
+
).then((res) => {
|
|
576
|
+
osmoBalances.value = res.balances.filter(
|
|
577
|
+
(x) => !x.denom.startsWith('gamm')
|
|
578
|
+
);
|
|
579
|
+
});
|
|
580
|
+
await getBalance(
|
|
581
|
+
props.endpoint,
|
|
582
|
+
localAddress(sender.value.cosmosAddress)
|
|
583
|
+
).then((res) => {
|
|
584
|
+
localBalances.value = res.balances;
|
|
585
|
+
});
|
|
586
|
+
} else {
|
|
587
|
+
if (response.rawLog) error.value = response.rawLog;
|
|
588
|
+
}
|
|
589
|
+
} catch (err) {
|
|
590
|
+
error.value = err
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
sending.value = false;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
async function connect() {
|
|
597
|
+
sending.value = true;
|
|
598
|
+
let accounts = [] as Account[];
|
|
599
|
+
try {
|
|
600
|
+
const latest = await getLatestBlock(props.endpoint);
|
|
601
|
+
const wa = createWallet(WalletName.Keplr, {
|
|
602
|
+
chainId: latest.block.header.chain_id,
|
|
603
|
+
hdPath: props.hdPath || DEFAULT_HDPATH,
|
|
604
|
+
});
|
|
605
|
+
await wa
|
|
606
|
+
.getAccounts()
|
|
607
|
+
.then((x) => {
|
|
608
|
+
accounts = x;
|
|
609
|
+
if (accounts.length > 0) {
|
|
610
|
+
const [first] = accounts;
|
|
611
|
+
const connected = {
|
|
612
|
+
wallet: WalletName.Keplr,
|
|
613
|
+
cosmosAddress: first.address,
|
|
614
|
+
hdPath: props.hdPath || DEFAULT_HDPATH,
|
|
615
|
+
};
|
|
616
|
+
writeWallet(connected, props.hdPath || DEFAULT_HDPATH);
|
|
617
|
+
}
|
|
618
|
+
})
|
|
619
|
+
.catch((e) => {
|
|
620
|
+
error.value = e;
|
|
621
|
+
});
|
|
622
|
+
initData();
|
|
623
|
+
view.value = 'swap'
|
|
624
|
+
} catch (e) {
|
|
625
|
+
error.value = e.message;
|
|
626
|
+
}
|
|
627
|
+
sending.value = false;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
// Excuting result
|
|
631
|
+
const delay = ref(0);
|
|
632
|
+
const step = ref(0);
|
|
633
|
+
const msg = ref('');
|
|
634
|
+
const sleep = 6000;
|
|
635
|
+
const emit = defineEmits(['completed']);
|
|
636
|
+
|
|
637
|
+
function showResult(hash: string) {
|
|
638
|
+
view.value = 'submitting';
|
|
639
|
+
delay.value = 1;
|
|
640
|
+
step.value = 20;
|
|
641
|
+
error.value = '';
|
|
642
|
+
msg.value = 'Proccessing...';
|
|
643
|
+
setTimeout(() => {
|
|
644
|
+
fetchTx(hash);
|
|
645
|
+
}, sleep);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
function fetchTx(tx: string) {
|
|
649
|
+
delay.value += 1;
|
|
650
|
+
step.value += 20;
|
|
651
|
+
getTxByHash(OSMOSIS_REST, tx)
|
|
652
|
+
.then((res) => {
|
|
653
|
+
step.value = 100;
|
|
654
|
+
if (res.tx_response.code > 0) {
|
|
655
|
+
error.value = res.tx_response.raw_log;
|
|
656
|
+
} else {
|
|
657
|
+
msg.value = `Congratulations! Swap completed successfully.`;
|
|
658
|
+
emit('completed', { hash: tx, });
|
|
659
|
+
}
|
|
660
|
+
})
|
|
661
|
+
.catch(() => {
|
|
662
|
+
if (delay.value < 5) {
|
|
663
|
+
setTimeout(() => fetchTx(tx), sleep);
|
|
664
|
+
} else {
|
|
665
|
+
error.value = 'Timeout';
|
|
666
|
+
}
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
</script>
|
|
670
|
+
<template>
|
|
671
|
+
<div>
|
|
672
|
+
<!-- modal content -->
|
|
673
|
+
<input v-model="open" type="checkbox" id="PingTokenConvert" class="modal-toggle" @change="initData()" />
|
|
674
|
+
|
|
675
|
+
<label for="PingTokenConvert" class="modal cursor-pointer">
|
|
676
|
+
<label class="modal-box rounded-lg" for="">
|
|
677
|
+
<div v-show="view === 'swap'">
|
|
678
|
+
<div class="absolute right-4 top-4 dropdown dropdown-end dropdown-hover">
|
|
679
|
+
<label tabindex="0" class="text-info">
|
|
680
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
|
681
|
+
class="w-6 h-6 stroke-current">
|
|
682
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
|
683
|
+
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
|
684
|
+
</svg>
|
|
685
|
+
</label>
|
|
686
|
+
<div tabindex="0"
|
|
687
|
+
class="card dropdown-content bg-slate-300 shadow-lg rounded-lg w-64 z-40">
|
|
688
|
+
<div class="card-body">
|
|
689
|
+
<ul class="text-right">
|
|
690
|
+
<li>Liquidity is provided by Osmosis</li>
|
|
691
|
+
<li>Powered by Ping.pub</li>
|
|
692
|
+
</ul>
|
|
693
|
+
</div>
|
|
694
|
+
</div>
|
|
695
|
+
</div>
|
|
696
|
+
<h3 class="text-xl font-semibold">Token Convert</h3>
|
|
697
|
+
<div v-if="!osmosisPath || chainName === 'osmosis'" class="text-error mt-3">
|
|
698
|
+
<span>This feature is not available [{{
|
|
699
|
+
chainName
|
|
700
|
+
}}]</span>
|
|
701
|
+
</div>
|
|
702
|
+
<div
|
|
703
|
+
class="flex items-center relative h-14 bg-gray-100 dark:bg-[#0f1419] rounded-tl-lg rounded-tr-lg mt-4">
|
|
704
|
+
<div class="dropdown">
|
|
705
|
+
<label tabindex="0" class="flex items-center h-12 px-4 cursor-pointer">
|
|
706
|
+
<img :src="swapIn?.coinImageUrl" class="w-8 h-8 mr-3 rounded-full" />
|
|
707
|
+
<div class="text-lg font-semibold mr-2">
|
|
708
|
+
{{ swapIn?.symbol }}
|
|
709
|
+
</div>
|
|
710
|
+
<Icon icon="mdi:chevron-down" class="text-lg" />
|
|
711
|
+
</label>
|
|
712
|
+
<div tabindex="0" class="dropdown-content shadow rounded-lg w-64 z-40">
|
|
713
|
+
<div class="py-2">
|
|
714
|
+
<div v-for="(item, index) in inTokens" :key="index"
|
|
715
|
+
class="flex items-center px-4 py-2 hover:bg-gray-200 dark:hover:bg-neutral-800 cursor-pointer"
|
|
716
|
+
@click="selectInput(item)">
|
|
717
|
+
<img class="w-7 h-7 rounded-full mr-2" :src="item.coinImageUrl" />
|
|
718
|
+
<div class="flex-1 text-sm">
|
|
719
|
+
{{ item.symbol }}
|
|
720
|
+
</div>
|
|
721
|
+
<div class="text-sm font-semibold text-gray-600">
|
|
722
|
+
{{
|
|
723
|
+
showBalance(
|
|
724
|
+
item.ibcDenom || item.denom,
|
|
725
|
+
item.decimals
|
|
726
|
+
)
|
|
727
|
+
}}
|
|
728
|
+
</div>
|
|
729
|
+
</div>
|
|
730
|
+
</div>
|
|
731
|
+
</div>
|
|
732
|
+
</div>
|
|
733
|
+
<input v-model="amountIn" type="number" placeholder="1"
|
|
734
|
+
class="input bg-transparent flex-1 h-14 text-right text-lg font-bold" />
|
|
735
|
+
</div>
|
|
736
|
+
|
|
737
|
+
<div class="flex items-center py-2 px-4 bg-gray-200 dark:bg-neutral-900 rounded-bl-lg rounded-br-lg">
|
|
738
|
+
<div class="mr-3 text-sm">Balance:</div>
|
|
739
|
+
<div class="text-base font-semibold">
|
|
740
|
+
{{
|
|
741
|
+
showBalance(swapIn?.ibcDenom, swapIn?.decimals)
|
|
742
|
+
}}
|
|
743
|
+
</div>
|
|
744
|
+
<Icon v-if="depositable" icon="mdi:plus-box-outline" class="ml-2 cursor-pointer"
|
|
745
|
+
@click="switchView('deposit')" />
|
|
746
|
+
</div>
|
|
747
|
+
|
|
748
|
+
<!-- switch btn -->
|
|
749
|
+
<div class="flex items-center justify-center -mt-3 -mb-3">
|
|
750
|
+
<div class="inline-block px-4 cursor-pointer" @click="switchDirection">
|
|
751
|
+
<Icon icon="mdi:arrow-down-circle" color="#676cf6"
|
|
752
|
+
class="text-4xl dark:bg-gray-50 rounded-full origin-center duration-300 transform hover:rotate-180" />
|
|
753
|
+
</div>
|
|
754
|
+
</div>
|
|
755
|
+
|
|
756
|
+
<div class="flex items-center h-14 rounded-tl-lg rounded-tr-lg bg-gray-100 dark:bg-[#0f1419]">
|
|
757
|
+
<div v-if="outTokens.length === 0">
|
|
758
|
+
<span v-if="error" class="text-red-500">No tradable tokens found.</span>
|
|
759
|
+
<button v-else class="btn btn-ghost" :class="{ 'loading relative start-0': sending }">
|
|
760
|
+
loading...
|
|
761
|
+
</button>
|
|
762
|
+
</div>
|
|
763
|
+
<div v-if="outTokens && outTokens.length > 0" class="dropdown">
|
|
764
|
+
<label tabindex="0" class="flex items-center h-12 px-4 cursor-pointer">
|
|
765
|
+
<img :src="swapOut?.coinImageUrl" class="w-8 h-8 mr-3 rounded-full" />
|
|
766
|
+
<div class="text-lg font-semibold mr-2">
|
|
767
|
+
{{ swapOut?.symbol }}
|
|
768
|
+
</div>
|
|
769
|
+
<Icon icon="mdi:chevron-down" class="text-lg" />
|
|
770
|
+
</label>
|
|
771
|
+
<div tabindex="0" class="dropdown-content shadow w-64 rounded-lg">
|
|
772
|
+
<div class="py-2 max-h-40 overflow-y-auto">
|
|
773
|
+
<div v-for="(item, index) in outTokens" :key="index" @click="selectOutput(item)"
|
|
774
|
+
class="flex items-center px-4 py-2 max-h-36 overflow-y-auto hover:bg-gray-200 dark:hover:bg-neutral-800 cursor-pointer">
|
|
775
|
+
<img class="w-7 h-7 rounded-full mr-2" :src="item.coinImageUrl" />
|
|
776
|
+
<div class="flex-1 text-sm">
|
|
777
|
+
{{ item.symbol }}
|
|
778
|
+
</div>
|
|
779
|
+
<div class="text-sm font-semibold text-gray-600">
|
|
780
|
+
{{
|
|
781
|
+
showBalance(
|
|
782
|
+
item.ibcDenom || item.denom,
|
|
783
|
+
item.decimals
|
|
784
|
+
)
|
|
785
|
+
}}
|
|
786
|
+
</div>
|
|
787
|
+
</div>
|
|
788
|
+
</div>
|
|
789
|
+
</div>
|
|
790
|
+
</div>
|
|
791
|
+
<div class="flex-1 w-0 text-xl text-right font-semibold text-gray-600 dark:text-gray-50 pr-4">
|
|
792
|
+
{{ `≈ ${parseFloat(outAmount.toFixed(6))}` }}
|
|
793
|
+
</div>
|
|
794
|
+
</div>
|
|
795
|
+
|
|
796
|
+
<div class="flex items-center py-2 px-4 bg-gray-200 dark:bg-neutral-900 rounded-bl-lg rounded-br-lg">
|
|
797
|
+
<div class="mr-3 text-sm dark:text-gray-400">
|
|
798
|
+
Balance:
|
|
799
|
+
</div>
|
|
800
|
+
<div class="text-base font-semibold dark:text-gray-200">
|
|
801
|
+
{{
|
|
802
|
+
showBalance(
|
|
803
|
+
swapOut?.ibcDenom,
|
|
804
|
+
swapOut?.decimals
|
|
805
|
+
)
|
|
806
|
+
}}
|
|
807
|
+
</div>
|
|
808
|
+
<Icon v-if="withdrawable" icon="mdi:minus-box-outline" class="ml-2 cursor-pointer"
|
|
809
|
+
@click="switchView('withdraw')" />
|
|
810
|
+
</div>
|
|
811
|
+
|
|
812
|
+
<div class="px-4 mt-4">
|
|
813
|
+
<div class="flex items-center justify-between">
|
|
814
|
+
<div class="text-sm text-gray-600 dark:text-gray-400">
|
|
815
|
+
Swap Fee
|
|
816
|
+
</div>
|
|
817
|
+
<div class="text-base text-gray-800 dark:text-gray-200">
|
|
818
|
+
{{
|
|
819
|
+
decimal2percent(pool?.pool_params.swap_fee)
|
|
820
|
+
}}%
|
|
821
|
+
</div>
|
|
822
|
+
</div>
|
|
823
|
+
</div>
|
|
824
|
+
|
|
825
|
+
<div v-if="error" class="text-error mt-3">
|
|
826
|
+
<span>{{ error }}.</span>
|
|
827
|
+
</div>
|
|
828
|
+
|
|
829
|
+
<div class="mt-5">
|
|
830
|
+
<button class="btn btn-primary w-full ping-connect-confirm capitalize text-base"
|
|
831
|
+
:disabled="disabled" @click="doSwap">
|
|
832
|
+
<span v-if="sending" class="loading loading-spinner"></span>
|
|
833
|
+
Convert
|
|
834
|
+
</button>
|
|
835
|
+
</div>
|
|
836
|
+
</div>
|
|
837
|
+
<!-- deposit -->
|
|
838
|
+
<div v-show="view === 'deposit'">
|
|
839
|
+
<h3 class="text-xl font-semibold flex">
|
|
840
|
+
<Icon class="mt-1" icon="mdi:chevron-left" @click="switchView('swap')"></Icon>
|
|
841
|
+
Deposit
|
|
842
|
+
</h3>
|
|
843
|
+
|
|
844
|
+
<div class="form-control">
|
|
845
|
+
<label class="label">
|
|
846
|
+
<span class="label-text">Deposit assets into Osmosis:</span>
|
|
847
|
+
<span class="lable-text">{{
|
|
848
|
+
showBalance(swapIn?.ibcDenom, swapIn?.decimals)
|
|
849
|
+
}}</span>
|
|
850
|
+
</label>
|
|
851
|
+
<input :value="osmoAddress(sender.cosmosAddress)" readonly type="text"
|
|
852
|
+
class="input" />
|
|
853
|
+
</div>
|
|
854
|
+
<div
|
|
855
|
+
class="flex items-center relative h-14 bg-gray-100 dark:bg-[#0f1419] rounded-tl-lg rounded-tr-lg mt-4">
|
|
856
|
+
<label tabindex="0" class="flex items-center h-12 px-4 cursor-pointer">
|
|
857
|
+
<img :src="swapIn?.coinImageUrl" class="w-8 h-8 mr-3 rounded-full" />
|
|
858
|
+
<div class="text-lg font-semibold mr-2">
|
|
859
|
+
{{ swapIn?.symbol }}
|
|
860
|
+
</div>
|
|
861
|
+
</label>
|
|
862
|
+
<input v-model="depositAmount" type="number" placeholder="1"
|
|
863
|
+
class="input bg-transparent flex-1 h-14 text-right text-lg font-bold" />
|
|
864
|
+
</div>
|
|
865
|
+
|
|
866
|
+
<div
|
|
867
|
+
class="flex flex-row-reverse items-center py-2 px-4 bg-gray-200 dark:bg-neutral-900 rounded-bl-lg rounded-br-lg">
|
|
868
|
+
<div class="text-base font-semibold">
|
|
869
|
+
{{
|
|
870
|
+
showLocalBalance(
|
|
871
|
+
swapIn?.denom,
|
|
872
|
+
swapIn?.decimals
|
|
873
|
+
)
|
|
874
|
+
}}
|
|
875
|
+
</div>
|
|
876
|
+
<div class="mr-3 text-sm">Balance:</div>
|
|
877
|
+
</div>
|
|
878
|
+
|
|
879
|
+
<div v-if="error" class="text-error mt-3">
|
|
880
|
+
<span>{{ error }}.</span>
|
|
881
|
+
</div>
|
|
882
|
+
|
|
883
|
+
<div class="mt-5 flex">
|
|
884
|
+
<label class="btn mr-1" @click="switchView('swap')">
|
|
885
|
+
<svg fill="#ffffff" height="20px" width="20px" version="1.1" id="Layer_1"
|
|
886
|
+
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
887
|
+
viewBox="0 0 330 330" xml:space="preserve">
|
|
888
|
+
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
|
|
889
|
+
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>
|
|
890
|
+
<g id="SVGRepo_iconCarrier">
|
|
891
|
+
<path id="XMLID_6_"
|
|
892
|
+
d="M165,0C74.019,0,0,74.019,0,165s74.019,165,165,165s165-74.019,165-165S255.981,0,165,0z M205.606,234.394 c5.858,5.857,5.858,15.355,0,21.213C202.678,258.535,198.839,260,195,260s-7.678-1.464-10.606-4.394l-80-79.998 c-2.813-2.813-4.394-6.628-4.394-10.606c0-3.978,1.58-7.794,4.394-10.607l80-80.002c5.857-5.858,15.355-5.858,21.213,0 c5.858,5.857,5.858,15.355,0,21.213l-69.393,69.396L205.606,234.394z">
|
|
893
|
+
</path>
|
|
894
|
+
</g>
|
|
895
|
+
</svg>
|
|
896
|
+
</label>
|
|
897
|
+
<button class="btn btn-primary grow ping-connect-confirm capitalize text-base"
|
|
898
|
+
:disabled="disableDeposit" @click="doDeposit">
|
|
899
|
+
<span v-if="sending" class="loading loading-spinner"></span>
|
|
900
|
+
Deposit
|
|
901
|
+
</button>
|
|
902
|
+
</div>
|
|
903
|
+
</div>
|
|
904
|
+
|
|
905
|
+
<!-- withdraw -->
|
|
906
|
+
<div v-show="view === 'withdraw'">
|
|
907
|
+
<h3 class="text-xl font-semibold flex">
|
|
908
|
+
<Icon class="mt-1" icon="mdi:chevron-left" @click="switchView('swap')"></Icon>
|
|
909
|
+
Withdraw
|
|
910
|
+
</h3>
|
|
911
|
+
|
|
912
|
+
<div
|
|
913
|
+
class="flex justify-between j items-center py-2 px-4 bg-gray-200 dark:bg-neutral-900 rounded-tl-lg rounded-tr-lg mt-4">
|
|
914
|
+
<div class="text-sm">Withdrawable Balance:</div>
|
|
915
|
+
<div class="text-base font-semibold">
|
|
916
|
+
{{
|
|
917
|
+
showBalance(
|
|
918
|
+
swapOut?.ibcDenom,
|
|
919
|
+
swapOut?.decimals
|
|
920
|
+
)
|
|
921
|
+
}}
|
|
922
|
+
</div>
|
|
923
|
+
</div>
|
|
924
|
+
<div class="flex items-center relative h-14 bg-gray-100 dark:bg-[#0f1419] rounded-bl-lg rounded-br-lg">
|
|
925
|
+
<label tabindex="0" class="flex items-center h-12 px-4 cursor-pointer">
|
|
926
|
+
<img :src="swapOut?.coinImageUrl" class="w-8 h-8 mr-3 rounded-full" />
|
|
927
|
+
<div class="text-lg font-semibold mr-2">
|
|
928
|
+
{{ swapOut?.symbol }}
|
|
929
|
+
</div>
|
|
930
|
+
</label>
|
|
931
|
+
<input v-model="withdrawAmount" type="number" placeholder="1"
|
|
932
|
+
class="input bg-transparent flex-1 h-14 text-right text-lg font-bold" />
|
|
933
|
+
</div>
|
|
934
|
+
|
|
935
|
+
<div class="form-control">
|
|
936
|
+
<label class="label">
|
|
937
|
+
<span class="label-text">Recipient on
|
|
938
|
+
{{ localChainInfo.pretty_name }}</span>
|
|
939
|
+
<span class="lable-text">{{
|
|
940
|
+
showLocalBalance(
|
|
941
|
+
swapOut?.denom,
|
|
942
|
+
swapOut?.decimals
|
|
943
|
+
)
|
|
944
|
+
}}</span>
|
|
945
|
+
</label>
|
|
946
|
+
<input v-model="recipient" type="text" class="input" />
|
|
947
|
+
</div>
|
|
948
|
+
<div v-if="error" class="text-error mt-3">
|
|
949
|
+
<span>{{ error }}.</span>
|
|
950
|
+
</div>
|
|
951
|
+
|
|
952
|
+
<div class="mt-5 flex">
|
|
953
|
+
<label class="btn mr-1" @click="switchView('swap')">
|
|
954
|
+
<svg fill="#ffffff" height="20px" width="20px" version="1.1" id="Layer_1"
|
|
955
|
+
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
956
|
+
viewBox="0 0 330 330" xml:space="preserve">
|
|
957
|
+
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
|
|
958
|
+
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>
|
|
959
|
+
<g id="SVGRepo_iconCarrier">
|
|
960
|
+
<path id="XMLID_6_"
|
|
961
|
+
d="M165,0C74.019,0,0,74.019,0,165s74.019,165,165,165s165-74.019,165-165S255.981,0,165,0z M205.606,234.394 c5.858,5.857,5.858,15.355,0,21.213C202.678,258.535,198.839,260,195,260s-7.678-1.464-10.606-4.394l-80-79.998 c-2.813-2.813-4.394-6.628-4.394-10.606c0-3.978,1.58-7.794,4.394-10.607l80-80.002c5.857-5.858,15.355-5.858,21.213,0 c5.858,5.857,5.858,15.355,0,21.213l-69.393,69.396L205.606,234.394z">
|
|
962
|
+
</path>
|
|
963
|
+
</g>
|
|
964
|
+
</svg>
|
|
965
|
+
</label>
|
|
966
|
+
<button class="btn btn-primary grow ping-connect-confirm capitalize text-base"
|
|
967
|
+
:disabled="disableWithdraw" @click="doWithdraw()">
|
|
968
|
+
<span v-if="sending" class="loading loading-spinner"></span>
|
|
969
|
+
Withdraw
|
|
970
|
+
</button>
|
|
971
|
+
</div>
|
|
972
|
+
</div>
|
|
973
|
+
|
|
974
|
+
<!-- Connect Wallet -->
|
|
975
|
+
<div v-show="view === 'connect'">
|
|
976
|
+
<h3 class="text-xl font-semibold flex dark:text-white">Connect Wallet</h3>
|
|
977
|
+
<div class="form-control mt-5 dark:bg-[#0f1419]">
|
|
978
|
+
<select class="select">
|
|
979
|
+
<option>Keplr</option>
|
|
980
|
+
</select>
|
|
981
|
+
</div>
|
|
982
|
+
|
|
983
|
+
<div v-if="error" class="text-error mt-3">
|
|
984
|
+
<span>{{ error }}.</span>
|
|
985
|
+
</div>
|
|
986
|
+
|
|
987
|
+
<div class="mt-5">
|
|
988
|
+
<button class="btn btn-primary w-full ping-connect-confirm capitalize text-base" @click="connect()">
|
|
989
|
+
<span v-if="sending" class="loading loading-spinner"></span>
|
|
990
|
+
Connect
|
|
991
|
+
</button>
|
|
992
|
+
</div>
|
|
993
|
+
</div>
|
|
994
|
+
|
|
995
|
+
<div v-show="view === 'submitting'">
|
|
996
|
+
<div class="mt-10 mb-6">
|
|
997
|
+
<div v-if="error" class="my-5 text-center text-red-500">
|
|
998
|
+
{{ error }}
|
|
999
|
+
</div>
|
|
1000
|
+
<div v-else class="my-5 text-center text-lg text-green-500">
|
|
1001
|
+
{{ msg }}
|
|
1002
|
+
</div>
|
|
1003
|
+
<div class="overflow-hidden h-5 mb-2 text-xs flex rounded bg-green-100">
|
|
1004
|
+
<div :style="`width: ${step}%`"
|
|
1005
|
+
class="shadow-none flex flex-col text-center whitespace-nowrap text-white justify-center bg-green-400">
|
|
1006
|
+
</div>
|
|
1007
|
+
</div>
|
|
1008
|
+
<div class="flex items-center justify-between">
|
|
1009
|
+
<div>
|
|
1010
|
+
<span
|
|
1011
|
+
class="text-xs font-semibold inline-block py-1 px-2 rounded text-gray-600 dark:text-white">
|
|
1012
|
+
Submitted
|
|
1013
|
+
</span>
|
|
1014
|
+
</div>
|
|
1015
|
+
<div class="text-right">
|
|
1016
|
+
<span class="text-xs font-semibold inline-block text-gray-600 dark:text-white">
|
|
1017
|
+
{{ step }}%
|
|
1018
|
+
</span>
|
|
1019
|
+
</div>
|
|
1020
|
+
</div>
|
|
1021
|
+
</div>
|
|
1022
|
+
<div class="mb-0 text-center">
|
|
1023
|
+
<label class="btn btn-link" @click="view = 'swap'">Continue</label>
|
|
1024
|
+
</div>
|
|
1025
|
+
</div>
|
|
1026
|
+
</label>
|
|
1027
|
+
</label>
|
|
1028
|
+
</div></template>
|
|
1029
|
+
<script lang="ts">
|
|
1030
|
+
export default {
|
|
1031
|
+
name: 'TokenConvert',
|
|
1032
|
+
};
|
|
1033
|
+
</script>
|