Skip to content

Commit

Permalink
Add osTokenVaultEscrow
Browse files Browse the repository at this point in the history
  • Loading branch information
tsudmi committed Nov 21, 2024
1 parent 0d77bf7 commit 47d80d8
Show file tree
Hide file tree
Showing 8 changed files with 257 additions and 39 deletions.
2 changes: 1 addition & 1 deletion src/config/gnosis.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"multicall": "0xcA11bde05977b3631167028862bE2a173976CA11",
"assetsUsdPriceFeed": "0x22441d81416430A54336aB28765abd31a792Ad37",
"daiUsdPriceFeed": "0x678df3415fc31947dA4324eC63212874be5a82f8",
"usdcUsdPriceFeed": "0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6",
"usdcUsdPriceFeed": "0x26C31ac71010aF62E6B486D1132E266D6298857D",
"eurUsdPriceFeed": "0xab70BCB260073d036d1660201e9d5405F5829b7a",
"gbpUsdPriceFeed": "0x0000000000000000000000000000000000000000",
"strategiesRegistry": "0x0000000000000000000000000000000000000000",
Expand Down
24 changes: 16 additions & 8 deletions src/entities/leverageStrategy.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
import { Address, BigInt, ethereum } from '@graphprotocol/graph-ts'
import { ExitRequest, LeverageStrategyPosition, LeverageStrategyPositionSnapshot, Vault } from '../../generated/schema'
import {
ExitRequest,
LeverageStrategyPosition,
LeverageStrategyPositionSnapshot,
OsTokenExitRequest,
Vault,
} from '../../generated/schema'
import { AavePool } from '../../generated/AaveLeverageStrategy/AavePool'
import { AaveOracle } from '../../generated/AaveLeverageStrategy/AaveOracle'
import { StrategiesRegistry } from '../../generated/AaveLeverageStrategy/StrategiesRegistry'
import { AaveLeverageStrategy } from '../../generated/Aave/AaveLeverageStrategy'
import { OsTokenVaultEscrow } from '../../generated/AaveLeverageStrategy/OsTokenVaultEscrow'
import {
AAVE_LEVERAGE_STRATEGY,
AAVE_ORACLE,
AAVE_POOL,
ASSET_TOKEN,
GENESIS_VAULT,
OS_TOKEN,
OS_TOKEN_VAULT_ESCROW,
STRATEGIES_REGISTRY,
WAD,
} from '../helpers/constants'
Expand Down Expand Up @@ -84,11 +88,15 @@ export function updateLeverageStrategyPosition(position: LeverageStrategyPositio
let stakedAssets = proxyAllocator.assets

if (position.exitRequest !== null) {
const exitRequest = ExitRequest.load(position.exitRequest as string) as ExitRequest
const osTokenVaultEscrow = OsTokenVaultEscrow.bind(OS_TOKEN_VAULT_ESCROW)
const response = osTokenVaultEscrow.getPosition(vaultAddress, exitRequest.positionTicket)
stakedAssets = stakedAssets.plus(exitRequest.totalAssets)
mintedOsTokenShares = mintedOsTokenShares.plus(response.getValue2())
const osTokenExitRequest = OsTokenExitRequest.load(position.exitRequest as string) as OsTokenExitRequest
if (osTokenExitRequest.exitedAssets !== null) {
stakedAssets = stakedAssets.plus(osTokenExitRequest.exitedAssets as BigInt)
} else {
// exit request and osToken exit request have the same id format
const exitRequest = ExitRequest.load(position.exitRequest as string) as ExitRequest
stakedAssets = stakedAssets.plus(exitRequest.totalAssets)
}
mintedOsTokenShares = mintedOsTokenShares.plus(osTokenExitRequest.osTokenShares)
}

const aaveLtv = getAaveLeverageLtv()
Expand Down
67 changes: 67 additions & 0 deletions src/entities/osTokenVaultEscrow.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { Address, BigDecimal, BigInt } from '@graphprotocol/graph-ts'
import { ExitRequest, OsToken, OsTokenExitRequest, Vault } from '../../generated/schema'
import { convertOsTokenSharesToAssets, createOrLoadOsToken } from './osToken'
import { GENESIS_VAULT, OS_TOKEN_VAULT_ESCROW } from '../helpers/constants'
import { createOrLoadV2Pool } from './v2pool'
import { OsTokenVaultEscrow } from '../../generated/OsTokenVaultEscrow/OsTokenVaultEscrow'

export function createOrLoadOsTokenExitRequest(vault: Address, positionTicket: BigInt): OsTokenExitRequest {
const exitRequestId = `${vault.toHex()}-${positionTicket.toString()}`
let osTokenExitRequest = OsTokenExitRequest.load(exitRequestId)
if (osTokenExitRequest == null) {
osTokenExitRequest = new OsTokenExitRequest(exitRequestId)
osTokenExitRequest.owner = Address.zero()
osTokenExitRequest.vault = vault.toHex()
osTokenExitRequest.positionTicket = positionTicket
osTokenExitRequest.osTokenShares = BigInt.zero()
osTokenExitRequest.ltv = BigDecimal.zero()
osTokenExitRequest.save()
}

return osTokenExitRequest
}

export function getExitRequestLtv(osTokenExitRequest: OsTokenExitRequest, osToken: OsToken): BigDecimal {
const mintedOsTokenAssets = convertOsTokenSharesToAssets(osToken, osTokenExitRequest.osTokenShares)

// use processed assets if available
let depositedAssets: BigInt
if (osTokenExitRequest.exitedAssets !== null) {
depositedAssets = osTokenExitRequest.exitedAssets as BigInt
} else {
const exitRequestId = `${osTokenExitRequest.vault}-${osTokenExitRequest.positionTicket.toString()}`
const exitRequest = ExitRequest.load(exitRequestId) as ExitRequest
depositedAssets = exitRequest.totalAssets
}
if (depositedAssets.isZero() || mintedOsTokenAssets.isZero()) {
return BigDecimal.zero()
}

return mintedOsTokenAssets.divDecimal(depositedAssets.toBigDecimal())
}

export function updateOsTokenExitRequests(vault: Vault): void {
if (Address.fromString(vault.id).equals(GENESIS_VAULT)) {
const v2Pool = createOrLoadV2Pool()
if (!v2Pool.migrated) {
// wait for the migration
return
}
}
const osToken = createOrLoadOsToken()
const vaultAddress = Address.fromString(vault.id)
const osTokenVaultEscrow = OsTokenVaultEscrow.bind(OS_TOKEN_VAULT_ESCROW)

let osTokenExitRequest: OsTokenExitRequest
const osTokenExitRequests: Array<OsTokenExitRequest> = vault.osTokenExitRequests.load()
for (let i = 0; i < osTokenExitRequests.length; i++) {
osTokenExitRequest = osTokenExitRequests[i]
if (osTokenExitRequest.osTokenShares.isZero()) {
continue
}
const response = osTokenVaultEscrow.getPosition(vaultAddress, osTokenExitRequest.positionTicket)
osTokenExitRequest.osTokenShares = response.getValue2()
osTokenExitRequest.ltv = getExitRequestLtv(osTokenExitRequest, osToken)
osTokenExitRequest.save()
}
}
1 change: 1 addition & 0 deletions src/entities/vaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,5 +262,6 @@ export function snapshotVault(vault: Vault, assetsDiff: BigInt, rewardsTimestamp
vaultSnapshot.vault = vault.id
vaultSnapshot.earnedAssets = assetsDiff
vaultSnapshot.totalAssets = vault.totalAssets
vaultSnapshot.totalShares = vault.totalShares
vaultSnapshot.save()
}
12 changes: 11 additions & 1 deletion src/mappings/keeper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,20 @@ import {
getAllocatorLtvStatus,
} from '../entities/allocator'
import { createOrLoadNetwork, isGnosisNetwork } from '../entities/network'
import { ConfigUpdated, Harvested, RewardsUpdated, ValidatorsApproval, OwnershipTransferred } from '../../generated/Keeper/Keeper'
import {
ConfigUpdated,
Harvested,
RewardsUpdated,
ValidatorsApproval,
OwnershipTransferred,
} from '../../generated/Keeper/Keeper'
import { convertSharesToAssets, getVaultStateUpdate, snapshotVault, updateVaultApy } from '../entities/vaults'
import { createOrLoadV2Pool, getPoolStateUpdate, updatePoolApy } from '../entities/v2pool'
import { createOrLoadOsTokenConfig } from '../entities/osTokenConfig'
import { updateExitRequests } from '../entities/exitRequests'
import { updateRewardSplitters } from '../entities/rewardSplitter'
import { updateLeverageStrategyPositions } from '../entities/leverageStrategy'
import { updateOsTokenExitRequests } from '../entities/osTokenVaultEscrow'

const IS_PRIVATE_KEY = 'isPrivate'
const IS_ERC20_KEY = 'isErc20'
Expand Down Expand Up @@ -460,6 +467,9 @@ export function updateRewards(
// update reward splitters
updateRewardSplitters(vault)

// update osToken exit requests
updateOsTokenExitRequests(vault)

// update leverage strategy positions
updateLeverageStrategyPositions(vault, vault.rewardsTimestamp as BigInt)
}
Expand Down
142 changes: 118 additions & 24 deletions src/mappings/osTokenVaultEscrow.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,32 @@
import { BigInt, log } from '@graphprotocol/graph-ts'
import { PositionCreated, ExitedAssetsClaimed } from '../../generated/OsTokenVaultEscrow/OsTokenVaultEscrow'
import { BigInt, ethereum, log } from '@graphprotocol/graph-ts'
import {
ExitedAssetsClaimed,
ExitedAssetsProcessed,
OsTokenLiquidated,
OsTokenRedeemed,
PositionCreated,
} from '../../generated/OsTokenVaultEscrow/OsTokenVaultEscrow'
import { Vault } from '../../generated/schema'
import {
AllocatorActionType,
createAllocatorAction,
createOrLoadAllocator,
getAllocatorLtv,
getAllocatorLtvStatus,
getAllocatorOsTokenMintApy,
} from '../entities/allocator'
import { convertOsTokenSharesToAssets, createOrLoadOsToken, snapshotOsToken } from '../entities/osToken'
import { createOrLoadOsTokenConfig } from '../entities/osTokenConfig'
import { createTransaction } from '../entities/transaction'
import {
createOrLoadOsTokenExitRequest,
getExitRequestLtv,
updateOsTokenExitRequests,
} from '../entities/osTokenVaultEscrow'
import { createOrLoadNetwork } from '../entities/network'

export function handlePositionCreated(event: PositionCreated): void {
const params = event.params
const vaultAddress = params.vault
const owner = params.owner
const osTokenShares = params.osTokenShares
const vaultAddress = event.params.vault
const owner = event.params.owner
const osTokenShares = event.params.osTokenShares
const exitPositionTicket = event.params.exitPositionTicket

const vault = Vault.load(vaultAddress.toHex()) as Vault
const osToken = createOrLoadOsToken()
Expand All @@ -32,34 +41,119 @@ export function handlePositionCreated(event: PositionCreated): void {
allocator.osTokenMintApy = getAllocatorOsTokenMintApy(allocator, osToken.apy, osToken, osTokenConfig)
allocator.save()

log.info('[OsTokenVaultEscrow] PositionCreated vault={} owner={} shares={}', [
const osTokenExitRequest = createOrLoadOsTokenExitRequest(vaultAddress, exitPositionTicket)
osTokenExitRequest.owner = owner
osTokenExitRequest.osTokenShares = osTokenShares
osTokenExitRequest.ltv = getExitRequestLtv(osTokenExitRequest, osToken)
osTokenExitRequest.save()

log.info('[OsTokenVaultEscrow] PositionCreated vault={} owner={} exitPositionTicket={}', [
vaultAddress.toHex(),
owner.toHex(),
osTokenShares.toString(),
exitPositionTicket.toHex(),
])
}

export function handleExitedAssetsProcessed(event: ExitedAssetsProcessed): void {
const vaultAddress = event.params.vault
const exitPositionTicket = event.params.exitPositionTicket
const exitedAssets = event.params.exitedAssets

const osTokenExitRequest = createOrLoadOsTokenExitRequest(vaultAddress, exitPositionTicket)
const osToken = createOrLoadOsToken()

osTokenExitRequest.exitedAssets = exitedAssets
osTokenExitRequest.ltv = getExitRequestLtv(osTokenExitRequest, osToken)
osTokenExitRequest.save()

log.info('[OsTokenVaultEscrow] ExitedAssetsProcessed vault={} exitPositionTicket={} exitedAssets={}', [
vaultAddress.toHex(),
exitPositionTicket.toHex(),
exitedAssets.toHex(),
])
}

export function handleExitedAssetsClaimed(event: ExitedAssetsClaimed): void {
const params = event.params
const holder = params.receiver
const shares = params.osTokenShares
const vaultAddress = params.vault
const vaultAddress = event.params.vault
const exitPositionTicket = event.params.exitPositionTicket
const osTokenShares = event.params.osTokenShares
const withdrawnAssets = event.params.assets

const osToken = createOrLoadOsToken()
const assets = convertOsTokenSharesToAssets(osToken, shares)
osToken.totalAssets = osToken.totalAssets.minus(assets)
osToken.totalSupply = osToken.totalSupply.minus(shares)
osToken.totalAssets = osToken.totalAssets.minus(convertOsTokenSharesToAssets(osToken, osTokenShares))
osToken.totalSupply = osToken.totalSupply.minus(osTokenShares)
osToken.save()
snapshotOsToken(osToken, BigInt.zero(), event.block.timestamp)

const txHash = event.transaction.hash.toHex()
createTransaction(txHash)
const osTokenExitRequest = createOrLoadOsTokenExitRequest(vaultAddress, exitPositionTicket)
osTokenExitRequest.osTokenShares = osTokenExitRequest.osTokenShares.minus(osTokenShares)
osTokenExitRequest.exitedAssets = osTokenExitRequest.exitedAssets!.minus(withdrawnAssets)
osTokenExitRequest.ltv = getExitRequestLtv(osTokenExitRequest, osToken)
osTokenExitRequest.save()

log.info('[OsTokenVaultEscrow] ExitedAssetsClaimed( vault={} exitPositionTicket={} osTokenShares={}', [
vaultAddress.toHex(),
exitPositionTicket.toHex(),
osTokenShares.toHex(),
])
}

createAllocatorAction(event, vaultAddress, AllocatorActionType.OsTokenBurned, holder, assets, shares)
export function handleOsTokenLiquidated(event: OsTokenLiquidated): void {
const vaultAddress = event.params.vault
const exitPositionTicket = event.params.exitPositionTicket
const osTokenShares = event.params.osTokenShares
const withdrawnAssets = event.params.receivedAssets

log.info('[OsTokenVaultEscrow] ExitedAssetsClaimed vault={} holder={} shares={}', [
const osToken = createOrLoadOsToken()
osToken.totalAssets = osToken.totalAssets.minus(convertOsTokenSharesToAssets(osToken, osTokenShares))
osToken.totalSupply = osToken.totalSupply.minus(osTokenShares)
osToken.save()
snapshotOsToken(osToken, BigInt.zero(), event.block.timestamp)

const osTokenExitRequest = createOrLoadOsTokenExitRequest(vaultAddress, exitPositionTicket)
osTokenExitRequest.osTokenShares = osTokenExitRequest.osTokenShares.minus(osTokenShares)
osTokenExitRequest.exitedAssets = osTokenExitRequest.exitedAssets!.minus(withdrawnAssets)
osTokenExitRequest.ltv = getExitRequestLtv(osTokenExitRequest, osToken)
osTokenExitRequest.save()

log.info('[OsTokenVaultEscrow] OsTokenLiquidated vault={} exitPositionTicket={} osTokenShares={}', [
vaultAddress.toHex(),
exitPositionTicket.toHex(),
osTokenShares.toHex(),
])
}

export function handleOsTokenRedeemed(event: OsTokenRedeemed): void {
const vaultAddress = event.params.vault
const exitPositionTicket = event.params.exitPositionTicket
const osTokenShares = event.params.osTokenShares
const withdrawnAssets = event.params.receivedAssets

const osToken = createOrLoadOsToken()
osToken.totalAssets = osToken.totalAssets.minus(convertOsTokenSharesToAssets(osToken, osTokenShares))
osToken.totalSupply = osToken.totalSupply.minus(osTokenShares)
osToken.save()
snapshotOsToken(osToken, BigInt.zero(), event.block.timestamp)

const osTokenExitRequest = createOrLoadOsTokenExitRequest(vaultAddress, exitPositionTicket)
osTokenExitRequest.osTokenShares = osTokenExitRequest.osTokenShares.minus(osTokenShares)
osTokenExitRequest.exitedAssets = osTokenExitRequest.exitedAssets!.minus(withdrawnAssets)
osTokenExitRequest.ltv = getExitRequestLtv(osTokenExitRequest, osToken)
osTokenExitRequest.save()

log.info('[OsTokenVaultEscrow] OsTokenRedeemed vault={} exitPositionTicket={} osTokenShares={}', [
vaultAddress.toHex(),
holder.toHex(),
shares.toString(),
exitPositionTicket.toHex(),
osTokenShares.toHex(),
])
}

export function handleOsTokenExitRequests(block: ethereum.Block): void {
const network = createOrLoadNetwork()
let vault: Vault
for (let i = 0; i < network.vaultIds.length; i++) {
vault = Vault.load(network.vaultIds[i]) as Vault
updateOsTokenExitRequests(vault)
}
log.info('[OsTokenExitRequests] Sync osToken exit requests at block={}', [block.number.toString()])
}
28 changes: 28 additions & 0 deletions src/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,9 @@ type Vault @entity {
"The vault leverage strategy positions"
leveragePositions: [LeverageStrategyPosition!]! @derivedFrom(field: "vault")

"The vault OsToken exit request positions"
osTokenExitRequests: [OsTokenExitRequest!]! @derivedFrom(field: "vault")

"The total number of shares"
totalShares: BigInt!

Expand Down Expand Up @@ -660,6 +663,29 @@ type OsTokenConfig @entity {
liqThresholdPercent: BigInt!
}

type OsTokenExitRequest @entity {
"<Vault ID>-<Exit queue id>"
id: ID!

"The address that can claim the exit"
owner: Bytes!

"The vault where assets are exiting"
vault: Vault!

"The exit request position ticket"
positionTicket: BigInt!

"The processed assets from the exit request. Will be null if the exit request is not processed."
exitedAssets: BigInt

"The total amount of osToken shares exiting"
osTokenShares: BigInt!

"The position's LTV percent"
ltv: BigDecimal!
}

"""
The LeverageStrategy position
"""
Expand Down Expand Up @@ -773,6 +799,7 @@ type VaultSnapshot @entity(timeseries: true) {
vault: Vault!
earnedAssets: BigInt!
totalAssets: BigInt!
totalShares: BigInt!
}

"""
Expand All @@ -784,6 +811,7 @@ type VaultStats @aggregation(intervals: ["day"], source: "VaultSnapshot") {
vault: Vault!
earnedAssets: BigInt! @aggregate(fn: "sum", arg: "earnedAssets")
totalAssets: BigInt! @aggregate(fn: "last", arg: "totalAssets")
totalShares: BigInt! @aggregate(fn: "last", arg: "totalShares")
}

"""
Expand Down
Loading

0 comments on commit 47d80d8

Please sign in to comment.