-
Notifications
You must be signed in to change notification settings - Fork 424
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a44fa27
commit c4463b7
Showing
15 changed files
with
556 additions
and
122 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export const useEnvironment = () => { | ||
return { environment: "mainnet" as const }; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
import type { EncodeObject } from "@cosmjs/proto-signing"; | ||
import { DEFAULT_VS_CURRENCY, superjson } from "@osmosis-labs/server"; | ||
import { | ||
InsufficientBalanceForFeeError, | ||
SwapRequiresError, | ||
} from "@osmosis-labs/stores"; | ||
import { | ||
estimateGasFee, | ||
getRegistry, | ||
getSmartAccountExtensionOptions, | ||
QuoteStdFee, | ||
} from "@osmosis-labs/tx"; | ||
import { CoinPretty, Dec, DecUtils, PricePretty } from "@osmosis-labs/unit"; | ||
import { isNil } from "@osmosis-labs/utils"; | ||
import { QueryClient, useQuery, useQueryClient } from "@tanstack/react-query"; | ||
import { useMemo } from "react"; | ||
|
||
import { useWallets } from "~/hooks/use-wallets"; | ||
import { getCachedAssetListAndChains } from "~/utils/asset-lists"; | ||
import { api } from "~/utils/trpc"; | ||
|
||
interface QueryResult { | ||
gasUsdValueToPay: PricePretty; | ||
gasAmount: CoinPretty; | ||
gasLimit: string; | ||
amount: QuoteStdFee["amount"]; | ||
} | ||
|
||
async function estimateTxFeesQueryFn({ | ||
messages, | ||
apiUtils, | ||
chainId, | ||
queryClient, | ||
address, | ||
authenticatorId, | ||
}: { | ||
chainId: string; | ||
messages: EncodeObject[]; | ||
apiUtils: ReturnType<typeof api.useUtils>; | ||
queryClient: QueryClient; | ||
address: string | undefined; | ||
authenticatorId: string | undefined; | ||
}): Promise<QueryResult> { | ||
if (!messages.length) throw new Error("No messages"); | ||
if (!address) throw new Error("No address"); | ||
|
||
const registry = await getRegistry(); | ||
const encodedMessages = messages.map((m) => registry.encodeAsAny(m)); | ||
|
||
const { chainList } = await getCachedAssetListAndChains({ | ||
queryClient, | ||
environment: "mainnet", | ||
}); | ||
|
||
const { amount, gas } = await estimateGasFee({ | ||
chainId, | ||
chainList, | ||
bech32Address: address, | ||
body: { | ||
messages: encodedMessages, | ||
nonCriticalExtensionOptions: authenticatorId | ||
? await getSmartAccountExtensionOptions({ | ||
authenticatorId, | ||
}) | ||
: undefined, | ||
}, | ||
gasMultiplier: 1.5, | ||
}); | ||
|
||
const fee = amount[0]; | ||
const asset = await getCachedAssetWithPrice(apiUtils, fee.denom); | ||
|
||
if (!fee || !asset?.currentPrice) { | ||
throw new Error("Failed to estimate fees"); | ||
} | ||
|
||
const coinAmountDec = new Dec(fee.amount); | ||
const usdValue = coinAmountDec | ||
.quo(DecUtils.getTenExponentN(asset.coinDecimals)) | ||
.mul(asset.currentPrice.toDec()); | ||
const gasUsdValueToPay = new PricePretty(DEFAULT_VS_CURRENCY, usdValue); | ||
|
||
return { | ||
gasUsdValueToPay, | ||
gasAmount: new CoinPretty(asset, coinAmountDec), | ||
gasLimit: gas, | ||
amount, | ||
}; | ||
} | ||
|
||
export function useEstimateTxFees({ | ||
messages, | ||
chainId, | ||
enabled = true, | ||
}: { | ||
messages: EncodeObject[] | undefined; | ||
chainId: string; | ||
enabled?: boolean; | ||
}) { | ||
const apiUtils = api.useUtils(); | ||
const { currentWallet } = useWallets(); | ||
const queryClient = useQueryClient(); | ||
|
||
const queryResult = useQuery<QueryResult, Error, QueryResult, string[]>({ | ||
queryKey: ["estimate-tx-fees", superjson.stringify(messages)], | ||
queryFn: () => { | ||
return estimateTxFeesQueryFn({ | ||
messages: messages!, | ||
apiUtils, | ||
chainId, | ||
queryClient, | ||
address: currentWallet?.address, | ||
authenticatorId: | ||
currentWallet?.type === "smart-account" | ||
? currentWallet?.authenticatorId | ||
: undefined, | ||
}); | ||
}, | ||
staleTime: 3_000, // 3 seconds | ||
cacheTime: 3_000, // 3 seconds | ||
retry: false, | ||
enabled: | ||
enabled && | ||
!isNil(messages) && | ||
Array.isArray(messages) && | ||
messages.length > 0 && | ||
currentWallet?.type === "smart-account" && | ||
currentWallet?.authenticatorId !== undefined && | ||
currentWallet?.address !== undefined && | ||
typeof currentWallet?.address === "string", | ||
}); | ||
|
||
const specificError = useMemo(() => { | ||
if ( | ||
queryResult.error instanceof Error && | ||
(queryResult.error.message.includes( | ||
"No fee tokens found with sufficient balance on account" | ||
) || | ||
queryResult.error.message.includes( | ||
"Insufficient alternative balance for transaction fees" | ||
) || | ||
queryResult.error.message.includes("insufficient funds")) | ||
) { | ||
return new InsufficientBalanceForFeeError(queryResult.error.message); | ||
} | ||
|
||
if ( | ||
queryResult.error instanceof Error && | ||
(queryResult.error.message.includes("Swap requires") || | ||
queryResult.error.message.includes("is greater than max amount")) | ||
) { | ||
return new SwapRequiresError(queryResult.error.message); | ||
} | ||
|
||
return queryResult.error; | ||
}, [queryResult.error]); | ||
|
||
return { ...queryResult, error: specificError }; | ||
} | ||
|
||
function getCachedAssetWithPrice( | ||
apiUtils: ReturnType<typeof api.useUtils>, | ||
coinMinimalDenom: string | ||
) { | ||
return apiUtils.local.assets.getAssetWithPrice.ensureData( | ||
{ | ||
findMinDenomOrSymbol: coinMinimalDenom, | ||
}, | ||
{ | ||
staleTime: 1000 * 10, // 10 seconds | ||
cacheTime: 1000 * 10, // 10 seconds | ||
} | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import { Chain } from "@osmosis-labs/types"; | ||
|
||
export function useOsmosisChain(): Chain { | ||
return { | ||
chain_name: "osmosis", | ||
status: "live", | ||
network_type: "mainnet", | ||
pretty_name: "Osmosis", | ||
chain_id: "osmosis-1", | ||
bech32_prefix: "osmo", | ||
bech32_config: { | ||
bech32PrefixAccAddr: "osmo", | ||
bech32PrefixAccPub: "osmopub", | ||
bech32PrefixValAddr: "osmovaloper", | ||
bech32PrefixValPub: "osmovaloperpub", | ||
bech32PrefixConsAddr: "osmovalcons", | ||
bech32PrefixConsPub: "osmovalconspub", | ||
}, | ||
slip44: 118, | ||
fees: { | ||
fee_tokens: [ | ||
{ | ||
denom: "uosmo", | ||
fixed_min_gas_price: 0.0025, | ||
low_gas_price: 0.0025, | ||
average_gas_price: 0.025, | ||
high_gas_price: 0.04, | ||
}, | ||
], | ||
}, | ||
staking: { | ||
staking_tokens: [ | ||
{ | ||
denom: "uosmo", | ||
}, | ||
], | ||
lock_duration: { | ||
time: "1209600s", | ||
}, | ||
}, | ||
description: | ||
"Osmosis (OSMO) is the premier DEX and cross-chain DeFi hub within the Cosmos ecosystem, a network of over 50 sovereign, interoperable blockchains seamlessly connected through the Inter-Blockchain Communication Protocol (IBC). Pioneering in its approach, Osmosis offers a dynamic trading and liquidity provision experience, integrating non-IBC assets from other ecosystems, including Ethereum, Solana, Avalanche, and Polkadot. Initially adopting Balancer-style pools, Osmosis now also features a concentrated liquidity model that is orders of magnitude more capital efficient, meaning that significantly less liquidity is required to handle the same amount of trading volume with minimal slippage.\n\nAs a true appchain, Osmosis has greater control over the full blockchain stack than traditional smart contract DEXs, which must follow the code of the parent chain that it is built on. This fine-grained control has enabled, for example, the development of Superfluid Staking, an extension of Proof of Stake that allows assets at the application layer to be staked to secure the chain. The customizability of appchains also allows implementing features like the Protocol Revenue module, which enables Osmosis to conduct on-chain arbitrage on behalf of OSMO stakers, balancing prices across pools while generating real yield revenue from this volume. Additionally, as a sovereign appchain, Osmosis governance can vote on upgrades to the protocol. One example of this was the introduction of a Taker Fee, which switched on the collection of exchange fees to generate diverse yield from Osmosis volume and distribute it to OSMO stakers.\n\nOsmosis is bringing the full centralized exchange experience to the decentralized world by building a cross-chain native DEX and trading suite that connects all chains over IBC, including Ethereum and Bitcoin. To reach this goal, Osmosis hosts an ever-expanding suite of DeFi applications aimed at providing a one-stop experience that includes lending, credit, margin, DeFi strategy vaults, power perps, fiat on-ramps, NFTs, stablecoins, and more — all of the functionalities that centralized exchange offer and more, in the trust-minimized environment of decentralized finance.", | ||
apis: { | ||
rpc: [ | ||
{ | ||
address: "https://rpc-osmosis.keplr.app", | ||
}, | ||
], | ||
rest: [ | ||
{ | ||
address: "https://lcd-osmosis.keplr.app", | ||
}, | ||
], | ||
}, | ||
explorers: [ | ||
{ | ||
tx_page: "https://www.mintscan.io/osmosis/txs/{txHash}", | ||
}, | ||
], | ||
logoURIs: { | ||
svg: "https://raw.githubusercontent.com/cosmos/chain-registry/master/osmosis/images/osmo.svg", | ||
png: "https://raw.githubusercontent.com/cosmos/chain-registry/master/osmosis/images/osmo.png", | ||
theme: { | ||
primary_color_hex: "#760dbb", | ||
}, | ||
}, | ||
features: [ | ||
"ibc-go", | ||
"ibc-transfer", | ||
"cosmwasm", | ||
"wasmd_0.24+", | ||
"osmosis-txfees", | ||
], | ||
}; | ||
} |
Oops, something went wrong.