diff --git a/abis/ERC20.json b/abis/ERC20.json new file mode 100644 index 0000000..02214fe --- /dev/null +++ b/abis/ERC20.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } + ] \ No newline at end of file diff --git a/abis/ERC20NameBytes.json b/abis/ERC20NameBytes.json new file mode 100644 index 0000000..93e9abb --- /dev/null +++ b/abis/ERC20NameBytes.json @@ -0,0 +1,17 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + } + ] \ No newline at end of file diff --git a/abis/ERC20SymbolBytes.json b/abis/ERC20SymbolBytes.json new file mode 100644 index 0000000..f0bcf3e --- /dev/null +++ b/abis/ERC20SymbolBytes.json @@ -0,0 +1,17 @@ +[ + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + } + ] \ No newline at end of file diff --git a/schema.graphql b/schema.graphql index 0c2c4e9..49ac4f9 100644 --- a/schema.graphql +++ b/schema.graphql @@ -47,15 +47,23 @@ type Pool @entity { @derivedFrom(field: "poolAddress") } + type PoolToken @entity { - id: ID! # poolId + token address - poolId: Pool! - tokenId: Datatoken - tokenAddress: String - balance: BigDecimal! - denormWeight: BigDecimal! + id: ID! # poolId + token address + poolId: Pool! + isDatatoken: Boolean! + address: String + tokenId: Datatoken + tokenAddress: String + balance: BigDecimal! + denormWeight: BigDecimal! + symbol: String + name: String + decimals: Int } + + type PoolShare @entity { id: ID! # poolId + userAddress userAddress: User! diff --git a/src/helpers.ts b/src/helpers.ts index 33e0c6e..44e52df 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -22,6 +22,9 @@ import { } from './@types/schema' import { Pool } from './@types/templates/Pool/Pool' +import { ERC20 } from './@types/templates/Pool/ERC20' +import { ERC20SymbolBytes } from './@types/templates/Pool/ERC20SymbolBytes' +import { ERC20NameBytes } from './@types/templates/Pool/ERC20NameBytes' export const ZERO_BD = BigDecimal.fromString('0.0') export const MINUS_1_BD = BigDecimal.fromString('-1.0') @@ -103,6 +106,67 @@ export function decimalToBigInt(value: BigDecimal): BigInt { return value.digits.times(scale) } +export function isNullEthValue(value: string): boolean { + return ( + value == + '0x0000000000000000000000000000000000000000000000000000000000000001' + ) +} + +export function getTokenSymbol(tokenAddress: Address): string { + const contract = ERC20.bind(tokenAddress) + const contractSymbolBytes = ERC20SymbolBytes.bind(tokenAddress) + + // try types string and bytes32 for symbol + let symbolValue = 'unknown' + const symbolResult = contract.try_symbol() + if (symbolResult.reverted) { + const 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 getTokenName(tokenAddress: Address): string { + const contract = ERC20.bind(tokenAddress) + const contractNameBytes = ERC20NameBytes.bind(tokenAddress) + + // try types string and bytes32 for name + let nameValue = 'unknown' + const nameResult = contract.try_name() + if (nameResult.reverted) { + const 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 +} + +export function getTokenDecimals(tokenAddress: Address): i32 { + const contract = ERC20.bind(tokenAddress) + let decimals = 18 + const decimalCall = contract.try_decimals() + if (!decimalCall.reverted) { + decimals = decimalCall.value + } + return decimals +} + export function updatePoolTokenBalance( poolToken: PoolToken, balance: BigDecimal, @@ -118,7 +182,7 @@ export function updatePoolTokenBalance( 'EEEEEEEEEEEEEEEEE poolToken.balance < Zero: pool={}, poolToken={}, oldBalance={}, newBalance={}', [ poolToken.poolId, - poolToken.tokenAddress.toString(), + poolToken.address.toString(), poolToken.balance.toString(), balance.toString() ] @@ -153,16 +217,20 @@ export function createPoolShareEntity( export function createPoolTokenEntity( id: string, pool: string, - address: string + address: Address ): void { - const datatoken = Datatoken.load(address) + const datatoken = Datatoken.load(address.toHexString()) const poolToken = new PoolToken(id) poolToken.poolId = pool + poolToken.isDatatoken = !!datatoken poolToken.tokenId = datatoken ? datatoken.id : '' - poolToken.tokenAddress = address + poolToken.address = address.toHexString() poolToken.balance = ZERO_BD poolToken.denormWeight = ZERO_BD + poolToken.symbol = getTokenSymbol(address) + poolToken.name = getTokenName(address) + poolToken.decimals = getTokenDecimals(address) poolToken.save() } @@ -206,7 +274,7 @@ export function updatePoolTransactionToken( ptxTokenValues.poolToken = poolTokenId ptxTokenValues.poolAddress = poolToken.poolId ptxTokenValues.userAddress = ptx.userAddress - ptxTokenValues.tokenAddress = PoolToken.load(poolTokenId).tokenAddress + ptxTokenValues.tokenAddress = PoolToken.load(poolTokenId).address ptxTokenValues.value = amount ptxTokenValues.tokenReserve = balance diff --git a/src/mappings/pool.ts b/src/mappings/pool.ts index 724f94a..fec4d1f 100644 --- a/src/mappings/pool.ts +++ b/src/mappings/pool.ts @@ -107,7 +107,7 @@ export function _handleRebind( const poolTokenId = poolId.concat('-').concat(address.toHexString()) let poolToken = PoolToken.load(poolTokenId) if (poolToken == null) { - createPoolTokenEntity(poolTokenId, poolId, address.toHexString()) + createPoolTokenEntity(poolTokenId, poolId, address) poolToken = PoolToken.load(poolTokenId) pool.totalWeight = pool.totalWeight.plus(denormWeight) } else { diff --git a/subgraph.polygon.yaml b/subgraph.polygon.yaml index ccda4ee..3e4aac8 100644 --- a/subgraph.polygon.yaml +++ b/subgraph.polygon.yaml @@ -144,6 +144,12 @@ templates: file: ./abis/BPool.json - name: BToken file: ./abis/BToken.json + - name: ERC20 + file: ./abis/ERC20.json + - name: ERC20SymbolBytes + file: ./abis/ERC20SymbolBytes.json + - name: ERC20NameBytes + file: ./abis/ERC20NameBytes.json eventHandlers: - event: LOG_CALL(indexed bytes4,indexed address,bytes) topic0: '0x34e1990700000000000000000000000000000000000000000000000000000000' diff --git a/subgraph.rinkeby.yaml b/subgraph.rinkeby.yaml index 82576cb..94c7114 100644 --- a/subgraph.rinkeby.yaml +++ b/subgraph.rinkeby.yaml @@ -144,6 +144,12 @@ templates: file: ./abis/BPool.json - name: BToken file: ./abis/BToken.json + - name: ERC20 + file: ./abis/ERC20.json + - name: ERC20SymbolBytes + file: ./abis/ERC20SymbolBytes.json + - name: ERC20NameBytes + file: ./abis/ERC20NameBytes.json eventHandlers: - event: LOG_CALL(indexed bytes4,indexed address,bytes) topic0: '0x34e1990700000000000000000000000000000000000000000000000000000000' diff --git a/subgraph.ropsten.yaml b/subgraph.ropsten.yaml index e17942e..ea5390d 100644 --- a/subgraph.ropsten.yaml +++ b/subgraph.ropsten.yaml @@ -144,6 +144,12 @@ templates: file: ./abis/BPool.json - name: BToken file: ./abis/BToken.json + - name: ERC20 + file: ./abis/ERC20.json + - name: ERC20SymbolBytes + file: ./abis/ERC20SymbolBytes.json + - name: ERC20NameBytes + file: ./abis/ERC20NameBytes.json eventHandlers: - event: LOG_CALL(indexed bytes4,indexed address,bytes) topic0: '0x34e1990700000000000000000000000000000000000000000000000000000000' diff --git a/subgraph.yaml b/subgraph.yaml index da48e48..c476ab2 100644 --- a/subgraph.yaml +++ b/subgraph.yaml @@ -144,6 +144,12 @@ templates: file: ./abis/BPool.json - name: BToken file: ./abis/BToken.json + - name: ERC20 + file: ./abis/ERC20.json + - name: ERC20SymbolBytes + file: ./abis/ERC20SymbolBytes.json + - name: ERC20NameBytes + file: ./abis/ERC20NameBytes.json eventHandlers: - event: LOG_CALL(indexed bytes4,indexed address,bytes) topic0: '0x34e1990700000000000000000000000000000000000000000000000000000000'