Add mappings for BFactory and BPool events with handlers

This commit is contained in:
ssallam 2020-11-20 13:12:02 +01:00
parent 3f79ce7918
commit 49461245d4
14 changed files with 91908 additions and 1 deletions

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
*.sol linguist-language=Solidity

61
.gitignore vendored Normal file
View File

@ -0,0 +1,61 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# next.js build output
.next

View File

@ -1 +1,31 @@
# ocean.subgraph
# Ocean Protocol Subgraph
## Running locally
* Install the Graph: `https://thegraph.com/docs/quick-start`
* You can skip running ganache-cli and connect directly to `mainnet` using Infura
```bash
git clone https://github.com/graphprotocol/graph-node/
cd graph-node/docker
./setup.sh
# Update this line in the `docker-compose.yml` file with your Infura ProjectId
# ethereum: 'mainnet:https://mainnet.infura.io/v3/INFURA_PROJECT_ID'
docker-compose up
```
* Install Graph CLI globally with npm
```bash
npm install -g @graphprotocol/graph-cli
```
* Once the graph node is ready, do the following to deploy the ocean-subgraph to the local graph-node
```bash
git clone https://github.com/oceanprotocol/ocean-subgraph/
cd ocean-subgraph
npm i
npm run codegen
npm run create:local
npm run deploy:local
```

3034
abis/BFactory.json Normal file

File diff suppressed because one or more lines are too long

66949
abis/BPool.json Normal file

File diff suppressed because one or more lines are too long

14010
abis/BToken.json Normal file

File diff suppressed because one or more lines are too long

6919
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

25
package.json Normal file
View File

@ -0,0 +1,25 @@
{
"name": "oceanpools",
"version": "0.1.0",
"scripts": {
"create": "graph create oceanprotocol/ocean-subgraph --node https://api.thegraph.com/deploy/",
"create:local": "graph create oceanprotocol/ocean-subgraph --node http://127.0.0.1:8020",
"codegen": "graph codegen --output-dir src/types/",
"build": "graph build",
"deploy": "graph deploy oceanprotocol/oceanpools --ipfs https://api.thegraph.com/ipfs/ --node https://api.thegraph.com/deploy/",
"deploy:beta": "graph deploy oceanprotocol/oceanpools-beta --ipfs https://api.thegraph.com/ipfs/ --node https://api.thegraph.com/deploy/",
"deploy:local": "graph deploy oceanprotocol/ocean-subgraph subgraph.yaml --debug --ipfs http://localhost:5001 --node http://127.0.0.1:8020"
},
"devDependencies": {
"@graphprotocol/graph-cli": "^0.18.0",
"@graphprotocol/graph-ts": "^0.18.1"
},
"dependencies": {
"babel-polyfill": "^6.26.0",
"babel-register": "^6.26.0",
"keytar": "^5.0.0",
"truffle": "^5.1.0",
"truffle-contract": "^4.0.5",
"truffle-hdwallet-provider": "^1.0.4"
}
}

117
schema.graphql Normal file
View File

@ -0,0 +1,117 @@
type OceanPools @entity {
id: ID!
color: String! # Bronze, Silver, Gold
poolCount: Int! # Number of pools
finalizedPoolCount: Int! # Number of finalized pools
pools: [Pool!] @derivedFrom(field: "factoryID")
txCount: BigInt! # Number of txs
totalLiquidity: BigDecimal! # All the pools liquidity value in Ocean
totalSwapVolume: BigDecimal! # All the swap volume in Ocean
totalSwapFee: BigDecimal! # All the swap fee in Ocean
}
type Pool @entity {
id: ID! # Pool address
controller: Bytes! # Controller address
publicSwap: Boolean! # isPublicSwap
finalized: Boolean! # isFinalized
symbol: String # Pool token symbol
name: String # Pool token name
cap: BigInt # Maximum supply if any
active: Boolean! # isActive
swapFee: BigDecimal! # Swap Fees
totalWeight: BigDecimal!
totalShares: BigDecimal! # Total pool token shares
totalSwapVolume: BigDecimal! # Total swap volume in OCEAN
totalSwapFee: BigDecimal! # Total swap fee in OCEAN
liquidity: BigDecimal! # Pool liquidity value in OCEAN
tokensList: [Bytes!]! # Temp workaround until graph supports filtering on derived field
tokens: [PoolToken!] @derivedFrom(field: "poolId")
shares: [PoolShare!] @derivedFrom(field: "poolId")
createTime: Int! # Block time pool was created
tokensCount: BigInt! # Number of tokens in the pool
holdersCount: BigInt! # Number of addresses holding a positive balance of BPT
joinsCount: BigInt! # liquidity has been added
exitsCount: BigInt! # liquidity has been removed
swapsCount: BigInt!
factoryID: OceanPools!
tx: Bytes # Pool creation transaction id
swaps: [Swap!] @derivedFrom(field: "poolAddress")
}
type PoolToken @entity {
id: ID! # poolId + token address
poolId: Pool!
symbol: String
name: String
decimals: Int!
address: String!
balance: BigDecimal!
denormWeight: BigDecimal!
}
type PoolShare @entity {
id: ID! # poolId + userAddress
userAddress: User!
poolId: Pool!
balance: BigDecimal!
}
type User @entity {
id: ID!
sharesOwned: [PoolShare!] @derivedFrom(field: "userAddress")
txs: [Transaction!] @derivedFrom(field: "userAddress")
swaps: [Swap!] @derivedFrom(field: "userAddress")
}
type Swap @entity {
id: ID! #
caller: Bytes! #
tokenIn: Bytes! #
tokenInSym: String! #
tokenOut: Bytes! #
tokenOutSym: String! #
tokenAmountIn: BigDecimal! #
tokenAmountOut: BigDecimal! #
poolAddress: Pool
userAddress: User # User address that initiates the swap
value: BigDecimal! # Swap value in OCEAN
feeValue: BigDecimal! # Swap fee value in OCEAN
poolTotalSwapVolume: BigDecimal! # Total pool swap volume in OCEAN
poolTotalSwapFee: BigDecimal! # Total pool swap fee in OCEAN
poolLiquidity: BigDecimal! # Pool liquidity value in OCEAN
timestamp: Int!
}
type Transaction @entity {
id: ID! # Log ID
tx: Bytes!
event: String
block: Int!
timestamp: Int!
gasUsed: BigDecimal!
gasPrice: BigDecimal!
poolAddress: Pool
userAddress: User
action: SwapType
sender: Bytes
}
type TokenPrice @entity {
id: ID!
symbol: String
name: String
decimals: Int!
price: BigDecimal!
poolLiquidity: BigDecimal!
poolTokenId: String
}
enum SwapType {
swapExactAmountIn,
swapExactAmountOut,
joinswapExternAmountIn,
joinswapPoolAmountOut,
exitswapPoolAmountIn,
exitswapExternAmountOut
}

52
src/mappings/factory.ts Normal file
View File

@ -0,0 +1,52 @@
import { Address, BigInt, BigDecimal } from '@graphprotocol/graph-ts'
import { BPoolRegistered } from '../types/Factory/Factory'
import { OceanPools, Pool } from '../types/schema'
import { Pool as PoolContract } from '../types/templates'
import {
ZERO_BD,
} from './helpers'
import { log } from '@graphprotocol/graph-ts'
export function handleNewPool(event: BPoolRegistered): void {
let factory = OceanPools.load('1')
// if no factory yet, set up blank initial
if (factory == null) {
factory = new OceanPools('1')
factory.color = 'Bronze'
factory.poolCount = 0
factory.finalizedPoolCount = 0
factory.txCount = BigInt.fromI32(0)
factory.totalLiquidity = ZERO_BD
factory.totalSwapVolume = ZERO_BD
factory.totalSwapFee = ZERO_BD
}
let pool = new Pool(event.params.bpoolAddress.toHexString())
log.error('************************ handleNewPool: poolId {}', [pool.id.toString()])
pool.controller = event.params.registeredBy
pool.publicSwap = false
pool.finalized = false
pool.active = true
pool.swapFee = BigDecimal.fromString('0.000001')
pool.totalWeight = ZERO_BD
pool.totalShares = ZERO_BD
pool.totalSwapVolume = ZERO_BD
pool.totalSwapFee = ZERO_BD
pool.liquidity = ZERO_BD
pool.createTime = event.block.timestamp.toI32()
pool.tokensCount = BigInt.fromI32(0)
pool.holdersCount = BigInt.fromI32(0)
pool.joinsCount = BigInt.fromI32(0)
pool.exitsCount = BigInt.fromI32(0)
pool.swapsCount = BigInt.fromI32(0)
pool.factoryID = event.address.toHexString()
pool.tokensList = []
pool.tx = event.transaction.hash
pool.save()
factory.poolCount = factory.poolCount + 1
factory.save()
PoolContract.create(event.params.bpoolAddress)
}

230
src/mappings/helpers.ts Normal file
View File

@ -0,0 +1,230 @@
import {
BigDecimal,
Address,
BigInt,
Bytes,
dataSource,
ethereum
} from '@graphprotocol/graph-ts'
import {
Pool,
User,
PoolToken,
PoolShare,
TokenPrice,
Transaction,
OceanPools
} from '../types/schema'
import { BToken } from '../types/templates/Pool/BToken'
import { log } from '@graphprotocol/graph-ts'
export let ZERO_BD = BigDecimal.fromString('0')
let network = dataSource.network()
export let OCEAN: string = (network == 'mainnet')
? '0x967da4048cD07aB37855c090aAF366e4ce1b9F48'
: '0x8967BCF84170c91B0d24D4302C2376283b0B3a07'
export function hexToDecimal(hexString: String, decimals: i32): BigDecimal {
let bytes = Bytes.fromHexString(hexString).reverse() as Bytes
let bi = BigInt.fromUnsignedBytes(bytes)
let scale = BigInt.fromI32(10).pow(decimals as u8).toBigDecimal()
return bi.divDecimal(scale)
}
export function bigIntToDecimal(amount: BigInt, decimals: i32): BigDecimal {
let scale = BigInt.fromI32(10).pow(decimals as u8).toBigDecimal()
return amount.toBigDecimal().div(scale)
}
export function tokenToDecimal(amount: BigDecimal, decimals: i32): BigDecimal {
let scale = BigInt.fromI32(10).pow(decimals as u8).toBigDecimal()
return amount.div(scale)
}
export function createPoolShareEntity(id: string, pool: string, user: string): void {
let poolShare = new PoolShare(id)
createUserEntity(user)
poolShare.userAddress = user
poolShare.poolId = pool
poolShare.balance = ZERO_BD
poolShare.save()
}
export function createPoolTokenEntity(id: string, pool: string, address: string): void {
let token = BToken.bind(Address.fromString(address))
let symbol = ''
let name = ''
let decimals = 18
// COMMENT THE LINES BELOW OUT FOR LOCAL DEV ON KOVAN
let symbolCall = token.try_symbol()
let nameCall = token.try_name()
if (!symbolCall.reverted) {
symbol = symbolCall.value
}
if (!nameCall.reverted) {
name = nameCall.value
}
// COMMENT THE LINES ABOVE OUT FOR LOCAL DEV ON KOVAN
// !!! COMMENT THE LINES BELOW OUT FOR NON-LOCAL DEPLOYMENT
// This code allows Symbols to be added when testing on local Kovan
/*
if(address == '0xd0a1e359811322d97991e03f863a0c30c2cf029c')
symbol = 'WETH';
else if(address == '0x1528f3fcc26d13f7079325fb78d9442607781c8c')
symbol = 'DAI'
else if(address == '0xef13c0c8abcaf5767160018d268f9697ae4f5375')
symbol = 'MKR'
else if(address == '0x2f375e94fc336cdec2dc0ccb5277fe59cbf1cae5')
symbol = 'USDC'
else if(address == '0x1f1f156e0317167c11aa412e3d1435ea29dc3cce')
symbol = 'BAT'
else if(address == '0x86436bce20258a6dcfe48c9512d4d49a30c4d8c4')
symbol = 'SNX'
else if(address == '0x8c9e6c40d3402480ace624730524facc5482798c')
symbol = 'REP'
*/
// !!! COMMENT THE LINES ABOVE OUT FOR NON-LOCAL DEPLOYMENT
let poolToken = new PoolToken(id)
poolToken.poolId = pool
poolToken.address = address
poolToken.name = name
poolToken.symbol = symbol
poolToken.decimals = decimals
poolToken.balance = ZERO_BD
poolToken.denormWeight = ZERO_BD
poolToken.save()
}
export function updatePoolLiquidity(id: string): void {
let pool = Pool.load(id)
let tokensList: Array<Bytes> = pool.tokensList
if (!tokensList || pool.tokensCount.lt(BigInt.fromI32(2)) || !pool.publicSwap) return
// Find pool liquidity
let hasPrice = false
let hasOceanPrice = false
let poolLiquidity = ZERO_BD
// if (tokensList.includes(Address.fromString(OCEAN))) {
// let oceanPoolTokenId = id.concat('-').concat(OCEAN)
// let oceanPoolToken = PoolToken.load(oceanPoolTokenId)
// poolLiquidity = oceanPoolToken.balance.div(oceanPoolToken.denormWeight).times(pool.totalWeight)
// hasPrice = true
// hasOceanPrice = true
// } else {
// let DT = tokensList[1].toHexString()
// let dtTokenPrice = TokenPrice.load(DT)
// if (dtTokenPrice !== null) {
// let poolTokenId = id.concat('-').concat(DT)
// let poolToken = PoolToken.load(poolTokenId)
// poolLiquidity = wethTokenPrice.price.times(poolToken.balance).div(poolToken.denormWeight).times(pool.totalWeight)
// hasPrice = true
// }
// }
//
// // Create or update token price
//
// if (hasPrice) {
// for (let i: i32 = 0; i < tokensList.length; i++) {
// let tokenPriceId = tokensList[i].toHexString()
// let tokenPrice = TokenPrice.load(tokenPriceId)
// if (tokenPrice == null) {
// tokenPrice = new TokenPrice(tokenPriceId)
// tokenPrice.poolTokenId = ''
// tokenPrice.poolLiquidity = ZERO_BD
// }
//
// let poolTokenId = id.concat('-').concat(tokenPriceId)
// let poolToken = PoolToken.load(poolTokenId)
//
// if (
// (tokenPrice.poolTokenId == poolTokenId || poolLiquidity.gt(tokenPrice.poolLiquidity)) &&
// (tokenPriceId != WETH.toString() || (pool.tokensCount.equals(BigInt.fromI32(2)) && hasUsdPrice))
// ) {
// tokenPrice.price = ZERO_BD
//
// if (poolToken.balance.gt(ZERO_BD)) {
// tokenPrice.price = poolLiquidity.div(pool.totalWeight).times(poolToken.denormWeight).div(poolToken.balance)
// }
//
// tokenPrice.symbol = poolToken.symbol
// tokenPrice.name = poolToken.name
// tokenPrice.decimals = poolToken.decimals
// tokenPrice.poolLiquidity = poolLiquidity
// tokenPrice.poolTokenId = poolTokenId
// tokenPrice.save()
// }
// }
// }
// Update pool liquidity
let liquidity = ZERO_BD
let denormWeight = ZERO_BD
for (let i: i32 = 0; i < tokensList.length; i++) {
let tokenPriceId = tokensList[i].toHexString()
let tokenPrice = TokenPrice.load(tokenPriceId)
if (tokenPrice !== null) {
let poolTokenId = id.concat('-').concat(tokenPriceId)
let poolToken = PoolToken.load(poolTokenId)
if (poolToken.denormWeight.gt(denormWeight)) {
denormWeight = poolToken.denormWeight
liquidity = tokenPrice.price.times(poolToken.balance).div(poolToken.denormWeight).times(pool.totalWeight)
}
}
}
let factory = OceanPools.load('1')
factory.totalLiquidity = factory.totalLiquidity.minus(pool.liquidity).plus(liquidity)
factory.save()
pool.liquidity = liquidity
pool.save()
}
export function decrPoolCount(finalized: boolean): void {
let factory = OceanPools.load('1')
factory.poolCount -= 1
if (finalized) factory.finalizedPoolCount -= 1
factory.save()
}
export function saveTransaction(event: ethereum.Event, eventName: string): void {
let tx = event.transaction.hash.toHexString().concat('-').concat(event.logIndex.toString())
let userAddress = event.transaction.from.toHex()
let transaction = Transaction.load(tx)
if (transaction == null) {
transaction = new Transaction(tx)
}
transaction.event = eventName
transaction.poolAddress = event.address.toHex()
transaction.userAddress = userAddress
transaction.gasUsed = event.transaction.gasUsed.toBigDecimal()
transaction.gasPrice = event.transaction.gasPrice.toBigDecimal()
transaction.tx = event.transaction.hash
transaction.timestamp = event.block.timestamp.toI32()
transaction.block = event.block.number.toI32()
transaction.save()
createUserEntity(userAddress)
}
export function createUserEntity(address: string): void {
if (User.load(address) == null) {
let user = new User(address)
user.save()
}
}

397
src/mappings/pool.ts Normal file
View File

@ -0,0 +1,397 @@
import { BigInt, Address, Bytes, store, BigDecimal } from '@graphprotocol/graph-ts'
import { LOG_CALL, LOG_JOIN, LOG_EXIT, LOG_SWAP, Transfer, GulpCall } from '../types/templates/Pool/Pool'
import { Pool as BPool } from '../types/templates/Pool/Pool'
import { log } from '@graphprotocol/graph-ts'
import {
OceanPools,
Pool,
PoolToken,
PoolShare,
Swap,
TokenPrice
} from '../types/schema'
import {
hexToDecimal,
bigIntToDecimal,
tokenToDecimal,
createPoolShareEntity,
createPoolTokenEntity,
updatePoolLiquidity,
saveTransaction,
ZERO_BD,
decrPoolCount
} from './helpers'
/************************************
********** Pool Controls ***********
************************************/
export function handleSetSwapFee(event: LOG_CALL, swapFeeStr: string=null): void {
let poolId = event.address.toHex()
let pool = Pool.load(poolId)
if (!swapFeeStr) {
swapFeeStr = event.params.data.toHexString().slice(-40)
}
pool.swapFee = hexToDecimal(swapFeeStr, 18)
pool.save()
saveTransaction(event, 'setSwapFee')
}
export function handleSetController(event: LOG_CALL): void {
let poolId = event.address.toHex()
let pool = Pool.load(poolId)
let controller = Address.fromString(event.params.data.toHexString().slice(-40))
pool.controller = controller
pool.save()
saveTransaction(event, 'setController')
}
export function handleSetPublicSwap(event: LOG_CALL): void {
let poolId = event.address.toHex()
let pool = Pool.load(poolId)
let publicSwap = event.params.data.toHexString().slice(-1) == '1'
pool.publicSwap = publicSwap
pool.save()
saveTransaction(event, 'setPublicSwap')
}
export function handleFinalize(event: LOG_CALL): void {
let poolId = event.address.toHex()
let pool = Pool.load(poolId)
// let balance = BigDecimal.fromString('100')
pool.finalized = true
pool.symbol = 'BPT'
pool.publicSwap = true
// pool.totalShares = balance
pool.save()
/*
let poolShareId = poolId.concat('-').concat(event.params.caller.toHex())
let poolShare = PoolShare.load(poolShareId)
if (poolShare == null) {
createPoolShareEntity(poolShareId, poolId, event.params.caller.toHex())
poolShare = PoolShare.load(poolShareId)
}
poolShare.balance = balance
poolShare.save()
*/
let factory = OceanPools.load('1')
factory.finalizedPoolCount = factory.finalizedPoolCount + 1
factory.save()
saveTransaction(event, 'finalize')
}
export function handleSetup(event: LOG_CALL): void {
let poolId = event.address.toHex()
let data = event.params.data.toHexString()
let dataTokenAddress = data.slice(34,74)
let dataTokenAmount = data.slice(98,162)
let dataTokenWeight = data.slice(162,226)
let baseTokenAddress = data.slice(226, 290-24)
let baseTokenAmount = data.slice(290,354)
let baseTokenWeight = data.slice(354,418)
let swapFee = data.slice(418)
_handleRebind(event, poolId, dataTokenAddress, dataTokenAmount, dataTokenWeight)
_handleRebind(event, poolId, baseTokenAddress, baseTokenAmount, baseTokenWeight)
handleSetSwapFee(event, swapFee)
handleFinalize(event)
saveTransaction(event, 'setup')
}
export function _handleRebind(event: LOG_CALL, poolId: string, tokenAddress: string, balanceStr: string, denormWeightStr: string): void {
let pool = Pool.load(poolId)
let tokenBytes = Bytes.fromHexString(tokenAddress) as Bytes
let tokensList = pool.tokensList || []
if (tokensList.indexOf(tokenBytes) == -1 ) {
tokensList.push(tokenBytes)
}
pool.tokensList = tokensList
pool.tokensCount = BigInt.fromI32(tokensList.length)
let address = Address.fromString(tokenAddress)
let denormWeight = hexToDecimal(denormWeightStr, 18)
let poolTokenId = poolId.concat('-').concat(address.toHexString())
let poolToken = PoolToken.load(poolTokenId)
if (poolToken == null) {
createPoolTokenEntity(poolTokenId, poolId, address.toHexString())
poolToken = PoolToken.load(poolTokenId)
pool.totalWeight += denormWeight
} else {
let oldWeight = poolToken.denormWeight
if (denormWeight > oldWeight) {
pool.totalWeight = pool.totalWeight + (denormWeight - oldWeight)
} else {
pool.totalWeight = pool.totalWeight - (oldWeight - denormWeight)
}
}
let balance = hexToDecimal(balanceStr, poolToken.decimals)
poolToken.balance = balance
poolToken.denormWeight = denormWeight
poolToken.save()
if (balance.equals(ZERO_BD)) {
decrPoolCount(pool.finalized)
pool.active = false
}
pool.save()
updatePoolLiquidity(poolId)
}
export function handleRebind(event: LOG_CALL): void {
let poolId = event.address.toHex()
_handleRebind(
event,
poolId,
event.params.data.toHexString().slice(34,74),
event.params.data.toHexString().slice(74,138),
event.params.data.toHexString().slice(138)
)
saveTransaction(event, 'rebind')
}
/************************************
********** JOINS & EXITS ***********
************************************/
export function handleJoinPool(event: LOG_JOIN): void {
let poolId = event.address.toHex()
let pool = Pool.load(poolId)
pool.joinsCount = pool.joinsCount.plus(BigInt.fromI32(1))
pool.save()
let address = event.params.tokenIn.toHex()
let poolTokenId = poolId.concat('-').concat(address.toString())
let poolToken = PoolToken.load(poolTokenId)
if (!poolToken) {
return
}
poolToken.decimals = BigInt.fromI32(18).toI32()
let tokenAmountIn = tokenToDecimal(event.params.tokenAmountIn.toBigDecimal(), poolToken.decimals)
poolToken.balance = poolToken.balance.plus(tokenAmountIn)
poolToken.save()
updatePoolLiquidity(poolId)
saveTransaction(event, 'join')
}
export function handleExitPool(event: LOG_EXIT): void {
let poolId = event.address.toHex()
let address = event.params.tokenOut.toHex()
let poolTokenId = poolId.concat('-').concat(address.toString())
let poolToken = PoolToken.load(poolTokenId)
if (!poolToken) {
return
}
let tokenAmountOut = tokenToDecimal(event.params.tokenAmountOut.toBigDecimal(), poolToken.decimals)
let newAmount = poolToken.balance.minus(tokenAmountOut)
poolToken.balance = newAmount
poolToken.save()
let pool = Pool.load(poolId)
pool.exitsCount = pool.exitsCount.plus(BigInt.fromI32(1))
if (newAmount.equals(ZERO_BD)) {
decrPoolCount(pool.finalized)
pool.active = false
}
pool.save()
updatePoolLiquidity(poolId)
saveTransaction(event, 'exit')
}
/************************************
************** SWAPS ***************
************************************/
export function handleSwap(event: LOG_SWAP): void {
let poolId = event.address.toHex()
let tokenIn = event.params.tokenIn.toHex()
let poolTokenInId = poolId.concat('-').concat(tokenIn.toString())
let poolTokenIn = PoolToken.load(poolTokenInId)
if (!poolTokenIn) {
return
}
let tokenAmountIn = tokenToDecimal(event.params.tokenAmountIn.toBigDecimal(), poolTokenIn.decimals)
let newAmountIn = poolTokenIn.balance.plus(tokenAmountIn)
poolTokenIn.balance = newAmountIn
poolTokenIn.save()
let tokenOut = event.params.tokenOut.toHex()
let poolTokenOutId = poolId.concat('-').concat(tokenOut.toString())
let poolTokenOut = PoolToken.load(poolTokenOutId)
let tokenAmountOut = tokenToDecimal(event.params.tokenAmountOut.toBigDecimal(), poolTokenOut.decimals)
let newAmountOut = poolTokenOut.balance.minus(tokenAmountOut)
poolTokenOut.balance = newAmountOut
poolTokenOut.save()
updatePoolLiquidity(poolId)
let swapId = event.transaction.hash.toHexString().concat('-').concat(event.logIndex.toString())
let swap = Swap.load(swapId)
if (swap == null) {
swap = new Swap(swapId)
}
let pool = Pool.load(poolId)
let tokensList: Array<Bytes> = pool.tokensList
let tokenOutPriceValue = ZERO_BD
let tokenOutPrice = TokenPrice.load(tokenOut)
if (tokenOutPrice != null) {
tokenOutPriceValue = tokenOutPrice.price
} else {
for (let i: i32 = 0; i < tokensList.length; i++) {
let tokenPriceId = tokensList[i].toHexString()
if (!tokenOutPriceValue.gt(ZERO_BD) && tokenPriceId !== tokenOut) {
let tokenPrice = TokenPrice.load(tokenPriceId)
if (tokenPrice !== null && tokenPrice.price.gt(ZERO_BD)) {
let poolTokenId = poolId.concat('-').concat(tokenPriceId)
let poolToken = PoolToken.load(poolTokenId)
tokenOutPriceValue = tokenPrice.price
.times(poolToken.balance)
.div(poolToken.denormWeight)
.times(poolTokenOut.denormWeight)
.div(poolTokenOut.balance)
}
}
}
}
let totalSwapVolume = pool.totalSwapVolume
let totalSwapFee = pool.totalSwapFee
let liquidity = pool.liquidity
let swapValue = ZERO_BD
let swapFeeValue = ZERO_BD
if (tokenOutPriceValue.gt(ZERO_BD)) {
swapValue = tokenOutPriceValue.times(tokenAmountOut)
swapFeeValue = swapValue.times(pool.swapFee)
totalSwapVolume = totalSwapVolume.plus(swapValue)
totalSwapFee = totalSwapFee.plus(swapFeeValue)
let factory = OceanPools.load('1')
factory.totalSwapVolume = factory.totalSwapVolume.plus(swapValue)
factory.totalSwapFee = factory.totalSwapFee.plus(swapFeeValue)
factory.save()
pool.totalSwapVolume = totalSwapVolume
pool.totalSwapFee = totalSwapFee
}
pool.swapsCount += BigInt.fromI32(1)
if (newAmountIn.equals(ZERO_BD) || newAmountOut.equals(ZERO_BD)) {
decrPoolCount(pool.finalized)
pool.active = false
}
pool.save()
swap.caller = event.params.caller
swap.tokenIn = event.params.tokenIn
swap.tokenInSym = poolTokenIn.symbol
swap.tokenOut = event.params.tokenOut
swap.tokenOutSym = poolTokenOut.symbol
swap.tokenAmountIn = tokenAmountIn
swap.tokenAmountOut = tokenAmountOut
swap.poolAddress = event.address.toHex()
swap.userAddress = event.transaction.from.toHex()
swap.poolTotalSwapVolume = totalSwapVolume
swap.poolTotalSwapFee = totalSwapFee
swap.poolLiquidity = liquidity
swap.value = swapValue
swap.feeValue = swapFeeValue
swap.timestamp = event.block.timestamp.toI32()
swap.save()
saveTransaction(event, 'swap')
}
/************************************
*********** POOL SHARES ************
************************************/
export function handleTransfer(event: Transfer): void {
let poolId = event.address.toHex()
let ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
let isMint = event.params.from.toHex() == ZERO_ADDRESS
let isBurn = event.params.to.toHex() == ZERO_ADDRESS
let poolShareFromId = poolId.concat('-').concat(event.params.from.toHex())
let poolShareFrom = PoolShare.load(poolShareFromId)
let poolShareFromBalance = poolShareFrom == null ? ZERO_BD : poolShareFrom.balance
let poolShareToId = poolId.concat('-').concat(event.params.to.toHex())
let poolShareTo = PoolShare.load(poolShareToId)
let poolShareToBalance = poolShareTo == null ? ZERO_BD : poolShareTo.balance
let pool = Pool.load(poolId)
if (isMint) {
if (poolShareTo == null) {
createPoolShareEntity(poolShareToId, poolId, event.params.to.toHex())
poolShareTo = PoolShare.load(poolShareToId)
}
poolShareTo.balance += tokenToDecimal(event.params.value.toBigDecimal(), 18)
poolShareTo.save()
pool.totalShares += tokenToDecimal(event.params.value.toBigDecimal(), 18)
} else if (isBurn) {
if (poolShareFrom == null) {
createPoolShareEntity(poolShareFromId, poolId, event.params.from.toHex())
poolShareFrom = PoolShare.load(poolShareFromId)
}
poolShareFrom.balance -= tokenToDecimal(event.params.value.toBigDecimal(), 18)
poolShareFrom.save()
pool.totalShares -= tokenToDecimal(event.params.value.toBigDecimal(), 18)
} else {
if (poolShareTo == null) {
createPoolShareEntity(poolShareToId, poolId, event.params.to.toHex())
poolShareTo = PoolShare.load(poolShareToId)
}
poolShareTo.balance += tokenToDecimal(event.params.value.toBigDecimal(), 18)
poolShareTo.save()
if (poolShareFrom == null) {
createPoolShareEntity(poolShareFromId, poolId, event.params.from.toHex())
poolShareFrom = PoolShare.load(poolShareFromId)
}
poolShareFrom.balance -= tokenToDecimal(event.params.value.toBigDecimal(), 18)
poolShareFrom.save()
}
if (
poolShareTo !== null
&& poolShareTo.balance.notEqual(ZERO_BD)
&& poolShareToBalance.equals(ZERO_BD)
) {
pool.holdersCount += BigInt.fromI32(1)
}
if (
poolShareFrom !== null
&& poolShareFrom.balance.equals(ZERO_BD)
&& poolShareFromBalance.notEqual(ZERO_BD)
) {
pool.holdersCount -= BigInt.fromI32(1)
}
pool.save()
}

76
subgraph.yaml Normal file
View File

@ -0,0 +1,76 @@
specVersion: 0.0.2
description: Ocean provides data sharing through IDOs
repository: https://github.com/oceanprotocol/ocean-subgraph
schema:
file: ./schema.graphql
dataSources:
- kind: ethereum/contract
name: Factory
network: mainnet
source:
address: "0xbe0083053744ECb871510C88dC0f6b77Da162706"
abi: Factory
startBlock: 11105585
mapping:
kind: ethereum/events
apiVersion: 0.0.4
language: wasm/assemblyscript
file: ./src/mappings/factory.ts
entities:
- OceanPools
abis:
- name: Factory
file: ./abis/BFactory.json
eventHandlers:
- event: BPoolRegistered(address,indexed address)
handler: handleNewPool
templates:
- kind: ethereum/contract
name: Pool
network: mainnet
source:
abi: Pool
mapping:
kind: ethereum/events
apiVersion: 0.0.4
language: wasm/assemblyscript
file: ./src/mappings/pool.ts
entities:
- Pool
- OceanPools
- Swap
abis:
- name: Pool
file: ./abis/BPool.json
- name: BToken
file: ./abis/BToken.json
eventHandlers:
- event: LOG_CALL(indexed bytes4,indexed address,bytes)
topic0: "0x34e1990700000000000000000000000000000000000000000000000000000000"
handler: handleSetSwapFee
- event: LOG_CALL(indexed bytes4,indexed address,bytes)
topic0: "0x92eefe9b00000000000000000000000000000000000000000000000000000000"
handler: handleSetController
- event: LOG_CALL(indexed bytes4,indexed address,bytes)
topic0: "0x49b5955200000000000000000000000000000000000000000000000000000000"
handler: handleSetPublicSwap
- event: LOG_CALL(indexed bytes4,indexed address,bytes)
topic0: "0x4bb278f300000000000000000000000000000000000000000000000000000000"
handler: handleFinalize
- event: LOG_CALL(indexed bytes4,indexed address,bytes)
topic0: "0xd1d7bc9100000000000000000000000000000000000000000000000000000000"
handler: handleSetup
- event: LOG_CALL(indexed bytes4,indexed address,bytes)
topic0: "0x3fdddaa200000000000000000000000000000000000000000000000000000000"
handler: handleRebind
- event: LOG_CALL(indexed bytes4,indexed address,bytes)
topic0: "0xe4e1e53800000000000000000000000000000000000000000000000000000000"
handler: handleRebind
- event: LOG_JOIN(indexed address,indexed address,uint256)
handler: handleJoinPool
- event: LOG_EXIT(indexed address,indexed address,uint256)
handler: handleExitPool
- event: LOG_SWAP(indexed address,indexed address,indexed address,uint256,uint256)
handler: handleSwap
- event: Transfer(indexed address,indexed address,uint256)
handler: handleTransfer

6
tsconfig.json Normal file
View File

@ -0,0 +1,6 @@
{
"extends": "./node_modules/@graphprotocol/graph-ts/tsconfig.json",
"compilerOptions": {
"types": ["@graphprotocol/graph-ts"]
}
}