Skip to content

Commit 5e27c43

Browse files
authored
Merge pull request #67 from chainapsis/osmosis-update
Add experimental features on osmosis tab
2 parents 8ebc732 + c571e74 commit 5e27c43

File tree

3 files changed

+221
-41
lines changed

3 files changed

+221
-41
lines changed

src/components/EvmTab.tsx

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useState, useEffect } from "react";
1+
import React, { useState, useEffect, useMemo } from "react";
22
import { Dec, DecUtils } from "@keplr-wallet/unit";
33
import { isAddress } from "@ethersproject/address";
44
import {
@@ -22,9 +22,10 @@ export const EvmTab: React.FC = () => {
2222
const [keplrEip6963ProviderInfo, setKeplrEip6963ProviderInfo] =
2323
useState<any>();
2424

25-
// Check for experimental=true in URL
26-
const searchParams = new URLSearchParams(window.location.search);
27-
const isExperimental = searchParams.get("experimental") === "true";
25+
const isExperimental = useMemo(() => {
26+
const searchParams = new URLSearchParams(window.location.search);
27+
return searchParams.get("experimental") === "true";
28+
}, []);
2829

2930
useEffect(() => {
3031
const init = async () => {
@@ -56,7 +57,7 @@ export const EvmTab: React.FC = () => {
5657
return () => {
5758
window.removeEventListener(
5859
"eip6963:announceProvider",
59-
handleAnnounceProvider
60+
handleAnnounceProvider,
6061
);
6162
};
6263
}, []);
@@ -130,7 +131,7 @@ const WalletData: React.FC = () => {
130131
{method}
131132
</button>
132133
</div>
133-
)
134+
),
134135
)}
135136
<div>Result: {result}</div>
136137
</div>
@@ -173,7 +174,7 @@ const RpcData: React.FC = () => {
173174
{method}
174175
</button>
175176
</div>
176-
)
177+
),
177178
)}
178179
<div>Result: {result}</div>
179180
</div>
@@ -333,7 +334,7 @@ const SendNativeToken: React.FC = () => {
333334

334335
const currentChainId = window.keplr?.ethereum?._currentChainId;
335336
const currentChainInfo = await window.keplr?.getChainInfoWithoutEndpoints(
336-
currentChainId
337+
currentChainId,
337338
);
338339

339340
if (currentChainInfo === undefined) {
@@ -345,7 +346,7 @@ const SendNativeToken: React.FC = () => {
345346
const amountValue = `0x${parseInt(
346347
new Dec(parsedAmount)
347348
.mulTruncate(DecUtils.getTenExponentN(mainCurrency.coinDecimals))
348-
.toString()
349+
.toString(),
349350
).toString(16)}`;
350351

351352
const tx = {
@@ -683,7 +684,7 @@ const EIP5792: React.FC = () => {
683684
const renderResult = (
684685
result: any,
685686
resultKey: string,
686-
allowTruncate: boolean = true
687+
allowTruncate: boolean = true,
687688
) => {
688689
const showFull = showFullResults[resultKey] || false;
689690

@@ -750,7 +751,7 @@ const EIP5792: React.FC = () => {
750751
}
751752
return value;
752753
},
753-
2
754+
2,
754755
)}
755756
</pre>
756757
</div>
@@ -774,10 +775,10 @@ const EIP5792: React.FC = () => {
774775
const updateCall = (
775776
idx: number,
776777
field: "address" | "amount",
777-
value: string
778+
value: string,
778779
) => {
779780
setCalls(
780-
calls.map((call, i) => (i === idx ? { ...call, [field]: value } : call))
781+
calls.map((call, i) => (i === idx ? { ...call, [field]: value } : call)),
781782
);
782783
};
783784

src/components/OsmosisTab.tsx

Lines changed: 149 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import React, { useEffect, useState } from "react";
1+
import React, { useCallback, useEffect, useMemo, useState } from "react";
22
import { Dec, DecUtils } from "@keplr-wallet/unit";
3-
import { OsmosisChainInfo } from "../constants";
3+
import { OsmosisChainInfo, OsmosisTestnetChainInfo } from "../constants";
44
import { Balances } from "../types/balance";
55
import { api } from "../util/api";
66
import { sendMsgs } from "../util/sendMsgs";
@@ -12,39 +12,71 @@ export const OsmosisTab: React.FC = () => {
1212
const [balance, setBalance] = useState<string>("");
1313
const [recipient, setRecipient] = useState<string>("");
1414
const [amount, setAmount] = useState<string>("");
15+
const [skipSimulation, setSkipSimulation] = useState<boolean>(false);
16+
const [targetChainId, setTargetChainId] = useState<string>(
17+
OsmosisTestnetChainInfo.chainId,
18+
);
19+
20+
const isExperimental = useMemo(() => {
21+
const searchParams = new URLSearchParams(window.location.search);
22+
return searchParams.get("experimental") === "true";
23+
}, []);
24+
25+
const chains = useMemo(
26+
() => [
27+
{
28+
id: OsmosisTestnetChainInfo.chainId,
29+
label: "Osmosis Testnet",
30+
info: OsmosisTestnetChainInfo,
31+
},
32+
{
33+
id: OsmosisChainInfo.chainId,
34+
label: "Osmosis",
35+
info: OsmosisChainInfo,
36+
},
37+
],
38+
[],
39+
);
1540

16-
const init = async () => {
41+
const selectedChain = useMemo(
42+
() => chains.find((c) => c.id === targetChainId) ?? chains[0],
43+
[chains, targetChainId],
44+
);
45+
46+
const init = useCallback(async () => {
1747
const keplr = window.keplr;
1848
if (keplr) {
1949
try {
20-
await keplr.experimentalSuggestChain(OsmosisChainInfo);
50+
// Ensure the selected chain is available in Keplr and enabled
51+
await keplr.experimentalSuggestChain(selectedChain.info as any);
52+
await keplr.enable(selectedChain.id);
2153
} catch (e) {
2254
if (e instanceof Error) {
2355
console.log(e.message);
2456
}
2557
}
2658
}
27-
};
59+
}, [selectedChain]);
2860

2961
const getKeyFromKeplr = async () => {
30-
const key = await window.keplr?.getKey(OsmosisChainInfo.chainId);
62+
const key = await window.keplr?.getKey(selectedChain.id);
3163
if (key) {
3264
setAddress(key.bech32Address);
3365
}
3466
};
3567

3668
const getBalance = async () => {
37-
const key = await window.keplr?.getKey(OsmosisChainInfo.chainId);
69+
const key = await window.keplr?.getKey(selectedChain.id);
3870

3971
if (key) {
40-
const uri = `${OsmosisChainInfo.rest}/cosmos/bank/v1beta1/balances/${key.bech32Address}?pagination.limit=1000`;
72+
const uri = `${selectedChain.info.rest}/cosmos/bank/v1beta1/balances/${key.bech32Address}?pagination.limit=1000`;
4173

4274
const data = await api<Balances>(uri);
4375
const balance = data.balances.find(
44-
(balance) => balance.denom === "uosmo"
76+
(balance) => balance.denom === "uosmo",
4577
);
46-
const osmoDecimal = OsmosisChainInfo.currencies.find(
47-
(currency) => currency.coinMinimalDenom === "uosmo"
78+
const osmoDecimal = selectedChain.info.currencies.find(
79+
(currency) => currency.coinMinimalDenom === "uosmo",
4880
)?.coinDecimals;
4981

5082
if (balance) {
@@ -58,7 +90,7 @@ export const OsmosisTab: React.FC = () => {
5890

5991
const sendBalance = async () => {
6092
if (window.keplr) {
61-
const key = await window.keplr?.getKey(OsmosisChainInfo.chainId);
93+
const key = await window.keplr?.getKey(selectedChain.id);
6294
const protoMsgs = {
6395
typeUrl: "/cosmos.bank.v1beta1.MsgSend",
6496
value: MsgSend.encode({
@@ -77,24 +109,39 @@ export const OsmosisTab: React.FC = () => {
77109
};
78110

79111
try {
80-
const gasUsed = await simulateMsgs(
81-
OsmosisChainInfo,
82-
key.bech32Address,
83-
[protoMsgs],
84-
[{ denom: "uosmo", amount: "236" }]
85-
);
86-
87-
if (gasUsed) {
112+
if (isExperimental && skipSimulation) {
113+
// Use a safe default gas when skipping simulation
114+
const defaultGas = "200000";
88115
await sendMsgs(
89116
window.keplr,
90-
OsmosisChainInfo,
117+
selectedChain.info as any,
91118
key.bech32Address,
92119
[protoMsgs],
93120
{
94121
amount: [{ denom: "uosmo", amount: "236" }],
95-
gas: Math.floor(gasUsed * 1.5).toString(),
96-
}
122+
gas: defaultGas,
123+
},
97124
);
125+
} else {
126+
const gasUsed = await simulateMsgs(
127+
selectedChain.info as any,
128+
key.bech32Address,
129+
[protoMsgs],
130+
[{ denom: "uosmo", amount: "236" }],
131+
);
132+
133+
if (gasUsed) {
134+
await sendMsgs(
135+
window.keplr,
136+
selectedChain.info as any,
137+
key.bech32Address,
138+
[protoMsgs],
139+
{
140+
amount: [{ denom: "uosmo", amount: "236" }],
141+
gas: Math.floor(gasUsed * 1.5).toString(),
142+
},
143+
);
144+
}
98145
}
99146
} catch (e) {
100147
if (e instanceof Error) {
@@ -105,16 +152,43 @@ export const OsmosisTab: React.FC = () => {
105152
};
106153

107154
useEffect(() => {
108-
init();
109-
}, []);
155+
void init();
156+
// Reset displayed data on chain change
157+
setAddress("");
158+
setBalance("");
159+
}, [init]);
110160

111161
return (
112162
<>
113163
<h2 style={{ marginTop: "30px" }}>
114-
Request to Osmosis Testnet via Keplr Provider
164+
Request to {selectedChain.label} via Keplr Provider
115165
</h2>
116166

117167
<div className="item-container">
168+
{isExperimental && (
169+
<div className="item">
170+
<div className="item-title">Switch Cosmos Chain</div>
171+
<div className="item-content">
172+
<div style={{ display: "flex", flexDirection: "column" }}>
173+
Chain:
174+
<select
175+
value={targetChainId}
176+
onChange={(e) => setTargetChainId(e.target.value)}
177+
>
178+
{chains.map((c) => (
179+
<option key={c.id} value={c.id}>
180+
{c.label}
181+
</option>
182+
))}
183+
</select>
184+
</div>
185+
<div style={{ marginTop: "10px" }}>
186+
Current Chain ID: {selectedChain.id}
187+
</div>
188+
</div>
189+
</div>
190+
)}
191+
118192
<div className="item">
119193
<div className="item-title">Get OSMO Address</div>
120194

@@ -172,6 +246,55 @@ export const OsmosisTab: React.FC = () => {
172246
/>
173247
</div>
174248

249+
{isExperimental && (
250+
<div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
251+
<div style={{ fontSize: 14, opacity: 0.9 }}>
252+
Skip gas simulation
253+
</div>
254+
<div
255+
role="switch"
256+
aria-checked={skipSimulation}
257+
onClick={() => setSkipSimulation((v) => !v)}
258+
style={{
259+
display: "inline-flex",
260+
alignItems: "center",
261+
gap: 8,
262+
cursor: "pointer",
263+
userSelect: "none",
264+
}}
265+
>
266+
<div
267+
style={{
268+
position: "relative",
269+
width: 44,
270+
height: 24,
271+
borderRadius: 9999,
272+
background: skipSimulation ? "#4ade80" : "#cbd5e1",
273+
transition: "background-color 150ms ease",
274+
boxShadow: "inset 0 0 0 1px rgba(0,0,0,0.05)",
275+
}}
276+
>
277+
<span
278+
style={{
279+
position: "absolute",
280+
top: 2,
281+
left: skipSimulation ? 22 : 2,
282+
width: 20,
283+
height: 20,
284+
borderRadius: 9999,
285+
background: "#fff",
286+
boxShadow: "0 1px 3px rgba(0,0,0,0.2)",
287+
transition: "left 150ms ease",
288+
}}
289+
/>
290+
</div>
291+
<span style={{ fontSize: 12, color: "#334155" }}>
292+
{skipSimulation ? "On" : "Off"}
293+
</span>
294+
</div>
295+
</div>
296+
)}
297+
175298
<button className="keplr-button" onClick={sendBalance}>
176299
Send
177300
</button>

0 commit comments

Comments
 (0)