-
Notifications
You must be signed in to change notification settings - Fork 779
/
Copy pathhelpers.ts
214 lines (184 loc) Β· 7.32 KB
/
helpers.ts
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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
/* eslint-disable prefer-const */
import { log, BigInt, BigDecimal, Address, ethereum } from '@graphprotocol/graph-ts'
import { ERC20 } from '../types/Factory/ERC20'
import { ERC20SymbolBytes } from '../types/Factory/ERC20SymbolBytes'
import { ERC20NameBytes } from '../types/Factory/ERC20NameBytes'
import { User, Bundle, Token, LiquidityPosition, LiquidityPositionSnapshot, Pair } from '../types/schema'
import { Factory as FactoryContract } from '../types/templates/Pair/Factory'
import { TokenDefinition } from './tokenDefinition'
export const ADDRESS_ZERO = '0x0000000000000000000000000000000000000000'
export const FACTORY_ADDRESS = '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f'
export let ZERO_BI = BigInt.fromI32(0)
export let ONE_BI = BigInt.fromI32(1)
export let ZERO_BD = BigDecimal.fromString('0')
export let ONE_BD = BigDecimal.fromString('1')
export let BI_18 = BigInt.fromI32(18)
export let factoryContract = FactoryContract.bind(Address.fromString(FACTORY_ADDRESS))
// rebass tokens, dont count in tracked volume
export let UNTRACKED_PAIRS: string[] = ['0x9ea3b5b4ec044b70375236a281986106457b20ef']
export function exponentToBigDecimal(decimals: BigInt): BigDecimal {
let bd = BigDecimal.fromString('1')
for (let i = ZERO_BI; i.lt(decimals as BigInt); i = i.plus(ONE_BI)) {
bd = bd.times(BigDecimal.fromString('10'))
}
return bd
}
export function bigDecimalExp18(): BigDecimal {
return BigDecimal.fromString('1000000000000000000')
}
export function convertEthToDecimal(eth: BigInt): BigDecimal {
return eth.toBigDecimal().div(exponentToBigDecimal(18))
}
export function convertTokenToDecimal(tokenAmount: BigInt, exchangeDecimals: BigInt): BigDecimal {
if (exchangeDecimals == ZERO_BI) {
return tokenAmount.toBigDecimal()
}
return tokenAmount.toBigDecimal().div(exponentToBigDecimal(exchangeDecimals))
}
export function equalToZero(value: BigDecimal): boolean {
const formattedVal = parseFloat(value.toString())
const zero = parseFloat(ZERO_BD.toString())
if (zero == formattedVal) {
return true
}
return false
}
export function isNullEthValue(value: string): boolean {
return value == '0x0000000000000000000000000000000000000000000000000000000000000001'
}
export function fetchTokenSymbol(tokenAddress: Address): string {
// static definitions overrides
let staticDefinition = TokenDefinition.fromAddress(tokenAddress)
if (staticDefinition != null) {
return (staticDefinition as TokenDefinition).symbol
}
let contract = ERC20.bind(tokenAddress)
let contractSymbolBytes = ERC20SymbolBytes.bind(tokenAddress)
// try types string and bytes32 for symbol
let symbolValue = 'unknown'
let symbolResult = contract.try_symbol()
if (symbolResult.reverted) {
let symbolResultBytes = contractSymbolBytes.try_symbol()
if (!symbolResultBytes.reverted) {
// for broken pairs that have no symbol function exposed
if (!isNullEthValue(symbolResultBytes.value.toHexString())) {
symbolValue = symbolResultBytes.value.toString()
}
}
} else {
symbolValue = symbolResult.value
}
return symbolValue
}
export function fetchTokenName(tokenAddress: Address): string {
// static definitions overrides
let staticDefinition = TokenDefinition.fromAddress(tokenAddress)
if (staticDefinition != null) {
return (staticDefinition as TokenDefinition).name
}
let contract = ERC20.bind(tokenAddress)
let contractNameBytes = ERC20NameBytes.bind(tokenAddress)
// try types string and bytes32 for name
let nameValue = 'unknown'
let nameResult = contract.try_name()
if (nameResult.reverted) {
let nameResultBytes = contractNameBytes.try_name()
if (!nameResultBytes.reverted) {
// for broken exchanges that have no name function exposed
if (!isNullEthValue(nameResultBytes.value.toHexString())) {
nameValue = nameResultBytes.value.toString()
}
}
} else {
nameValue = nameResult.value
}
return nameValue
}
// HOT FIX: we cant implement try catch for overflow catching so skip total supply parsing on these tokens that overflow
// TODO: find better way to handle overflow
let SKIP_TOTAL_SUPPLY: string[] = [
"0x0000000000bf2686748e1c0255036e7617e7e8a5",
"0x000000000000b91b6956fead1dda24c66aa6b972",
"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
]
export function fetchTokenTotalSupply(tokenAddress: Address): BigInt {
if (SKIP_TOTAL_SUPPLY.includes(tokenAddress.toHexString())) {
return BigInt.fromI32(0)
}
let contract = ERC20.bind(tokenAddress)
let totalSupplyValue = null
let totalSupplyResult = contract.try_totalSupply()
if (!totalSupplyResult.reverted) {
totalSupplyValue = totalSupplyResult as i32
}
return BigInt.fromI32(totalSupplyValue as i32)
}
export function fetchTokenDecimals(tokenAddress: Address): BigInt {
if (SKIP_TOTAL_SUPPLY.includes(tokenAddress.toHexString())) {
return BigInt.fromI32(0)
}
// static definitions overrides
let staticDefinition = TokenDefinition.fromAddress(tokenAddress)
if (staticDefinition != null) {
return (staticDefinition as TokenDefinition).decimals
}
let contract = ERC20.bind(tokenAddress)
// try types uint8 for decimals
let decimalValue = null
let decimalResult = contract.try_decimals()
if (!decimalResult.reverted) {
decimalValue = decimalResult.value
}
return BigInt.fromI32(decimalValue as i32)
}
export function createLiquidityPosition(exchange: Address, user: Address): LiquidityPosition {
let id = exchange
.toHexString()
.concat('-')
.concat(user.toHexString())
let liquidityTokenBalance = LiquidityPosition.load(id)
if (liquidityTokenBalance === null) {
let pair = Pair.load(exchange.toHexString())
pair.liquidityProviderCount = pair.liquidityProviderCount.plus(ONE_BI)
liquidityTokenBalance = new LiquidityPosition(id)
liquidityTokenBalance.liquidityTokenBalance = ZERO_BD
liquidityTokenBalance.pair = exchange.toHexString()
liquidityTokenBalance.user = user.toHexString()
liquidityTokenBalance.save()
pair.save()
}
if (liquidityTokenBalance === null) log.error('LiquidityTokenBalance is null', [id])
return liquidityTokenBalance as LiquidityPosition
}
export function createUser(address: Address): void {
let user = User.load(address.toHexString())
if (user === null) {
user = new User(address.toHexString())
user.usdSwapped = ZERO_BD
user.save()
}
}
export function createLiquiditySnapshot(position: LiquidityPosition, event: ethereum.Event): void {
let timestamp = event.block.timestamp.toI32()
let bundle = Bundle.load('1')
let pair = Pair.load(position.pair)
let token0 = Token.load(pair.token0)
let token1 = Token.load(pair.token1)
// create new snapshot
let snapshot = new LiquidityPositionSnapshot(position.id.concat(timestamp.toString()))
snapshot.liquidityPosition = position.id
snapshot.timestamp = timestamp
snapshot.block = event.block.number.toI32()
snapshot.user = position.user
snapshot.pair = position.pair
snapshot.token0PriceUSD = token0.derivedETH.times(bundle.ethPrice)
snapshot.token1PriceUSD = token1.derivedETH.times(bundle.ethPrice)
snapshot.reserve0 = pair.reserve0
snapshot.reserve1 = pair.reserve1
snapshot.reserveUSD = pair.reserveUSD
snapshot.liquidityTokenTotalSupply = pair.totalSupply
snapshot.liquidityTokenBalance = position.liquidityTokenBalance
snapshot.liquidityPosition = position.id
snapshot.save()
position.save()
}