forked from DimensionDev/Maskbook
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathuniswap.ts
More file actions
164 lines (144 loc) · 6.32 KB
/
uniswap.ts
File metadata and controls
164 lines (144 loc) · 6.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
import JSBI from 'jsbi'
import { memoize } from 'lodash-unified'
import BigNumber from 'bignumber.js'
import { Currency, Token, CurrencyAmount, TradeType, Percent, Price, Ether } from '@uniswap/sdk-core'
import type { Trade } from '@uniswap/v2-sdk'
import {
formatEthereumAddress,
ChainId,
EthereumTokenType,
FungibleTokenDetailed,
isSameAddress,
} from '@masknet/web3-shared-evm'
import { pow10, isGreaterThan } from '@masknet/web3-shared-base'
import { ONE_HUNDRED_PERCENT, WNATIVE, ZERO_PERCENT } from '../constants'
export function swapErrorToUserReadableMessage(error: any): string {
let reason: string | undefined
while (error) {
reason = error.reason ?? error.message ?? reason
error = error.error ?? error.data?.originalError
}
if (reason?.startsWith('execution reverted: ')) reason = reason.substr('execution reverted: '.length)
switch (reason) {
case 'UniswapV2Router: EXPIRED':
return 'The transaction could not be sent because the deadline has passed. Please check that your transaction deadline is not too low.'
case 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT':
case 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT':
return 'This transaction will not succeed either due to price movement or fee on transfer.'
case 'TransferHelper: TRANSFER_FROM_FAILED':
return 'The input token cannot be transferred. There may be an issue with the input token.'
case 'UniswapV2: TRANSFER_FAILED':
return 'The output token cannot be transferred. There may be an issue with the output token.'
case 'UniswapV2: K':
return 'The Uniswap invariant x*y=k was not satisfied by the swap. This usually means one of the tokens you are swapping incorporates custom behavior on transfer.'
case 'Too little received':
case 'Too much requested':
case 'STF':
return 'This transaction will not succeed due to price movement.'
case 'TF':
return 'The output token cannot be transferred. There may be an issue with the output token.'
default:
if (reason?.includes('undefined is not an object')) {
console.error(error, reason)
return 'An error occurred when trying to execute this swap. You may need to increase your slippage tolerance. If that does not work, there may be an incompatibility with the token you are trading.'
}
return `Unknown error${reason ? `: "${reason}"` : ''}.`
}
}
export function toUniswapChainId(chainId: ChainId) {
return chainId as number
}
export function toUniswapPercent(numerator: number, denominator: number) {
return new Percent(JSBI.BigInt(numerator), JSBI.BigInt(denominator))
}
export function toUniswapCurrency(chainId: ChainId, token?: FungibleTokenDetailed): Currency | undefined {
try {
if (!token) return
const extendedEther = ExtendedEther.onChain(chainId)
const weth = toUniswapToken(chainId, WNATIVE[chainId])
if (weth && isSameAddress(token.address, weth.address)) return weth
return token.type === EthereumTokenType.Native ? extendedEther : toUniswapToken(chainId, token)
} catch {
return
}
}
export function toUniswapToken(chainId: ChainId, token: FungibleTokenDetailed) {
return new Token(
toUniswapChainId(chainId),
formatEthereumAddress(token.address),
token.decimals,
token.symbol,
token.name,
)
}
export function toUniswapCurrencyAmount(chainId: ChainId, token?: FungibleTokenDetailed, amount?: string) {
if (!token || !amount) return
const currency = toUniswapCurrency(chainId, token)
if (!currency) return
try {
if (isGreaterThan(amount, 0)) return CurrencyAmount.fromRawAmount(currency, JSBI.BigInt(amount))
} catch {
return
}
return
}
export function uniswapChainIdTo(chainId: number) {
return chainId as ChainId
}
export function uniswapPercentTo(percent: Percent) {
return new BigNumber(percent.toFixed(2)).dividedBy(100)
}
export function uniswapPriceTo(price: Price<Currency, Currency>) {
return new BigNumber(price.scalar.numerator.toString()).dividedBy(price.scalar.denominator.toString())
}
export function uniswapTokenTo(token: Token) {
return {
type: ['eth', 'matic', 'bnb', 'metis'].includes(token.name?.toLowerCase() ?? '')
? EthereumTokenType.Native
: EthereumTokenType.ERC20,
name: token.name,
symbol: token.symbol,
decimals: token.decimals,
address: formatEthereumAddress(token.address),
chainId: uniswapChainIdTo(token.chainId),
} as FungibleTokenDetailed
}
export function uniswapCurrencyAmountTo(currencyAmount: CurrencyAmount<Currency>) {
return pow10(currencyAmount.currency.decimals).multipliedBy(currencyAmount.toFixed())
}
export function isTradeBetter(
tradeA?: Trade<Currency, Currency, TradeType> | null,
tradeB?: Trade<Currency, Currency, TradeType> | null,
minimumDelta: Percent = ZERO_PERCENT,
): boolean | undefined {
if (tradeA && !tradeB) return false
if (tradeB && !tradeA) return true
if (!tradeA || !tradeB) return undefined
if (
tradeA.tradeType !== tradeB.tradeType ||
!tradeA.inputAmount.currency.equals(tradeB.inputAmount.currency) ||
!tradeB.outputAmount.currency.equals(tradeB.outputAmount.currency)
) {
throw new Error('Comparing incomparable trades')
}
if (minimumDelta.equalTo(ZERO_PERCENT)) {
return tradeA.executionPrice.lessThan(tradeB.executionPrice)
} else {
return tradeA.executionPrice.asFraction
.multiply(minimumDelta.add(ONE_HUNDRED_PERCENT))
.lessThan(tradeB.executionPrice)
}
}
export class ExtendedEther extends Ether {
public override get wrapped(): Token {
if (this.chainId in WNATIVE) return ExtendedEther.wrapEther(this.chainId)
throw new Error('Unsupported chain ID')
}
private static _cachedEther: Record<number, ExtendedEther> = {}
public static override onChain(chainId: number): ExtendedEther {
return this._cachedEther[chainId] ?? (this._cachedEther[chainId] = new ExtendedEther(chainId))
}
public static wrapEther: (chainID: ChainId) => Token = memoize((chainId: ChainId) =>
toUniswapToken(chainId, WNATIVE[chainId]),
)
}