This repository has been archived by the owner on Jan 24, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 382
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(dhedge-v2): Add dHEDGE V2 (#683)
- Loading branch information
Showing
9 changed files
with
316 additions
and
0 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { Injectable, Inject } from '@nestjs/common'; | ||
|
||
import { IAppToolkit, APP_TOOLKIT } from '~app-toolkit/app-toolkit.interface'; | ||
import { ContractFactory } from '~contract/contracts'; | ||
import { Network } from '~types/network.interface'; | ||
// eslint-disable-next-line | ||
type ContractOpts = { address: string; network: Network }; | ||
|
||
@Injectable() | ||
export class DhedgeV2ContractFactory extends ContractFactory { | ||
constructor(@Inject(APP_TOOLKIT) protected readonly appToolkit: IAppToolkit) { | ||
super((network: Network) => appToolkit.getNetworkProvider(network)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import { Register } from '~app-toolkit/decorators'; | ||
import { appDefinition, AppDefinition } from '~app/app.definition'; | ||
import { AppAction, AppTag, GroupType } from '~app/app.interface'; | ||
import { Network } from '~types/network.interface'; | ||
|
||
export const DHEDGE_V_2_DEFINITION = appDefinition({ | ||
id: 'dhedge-v2', | ||
name: 'dHEDGE V2', | ||
description: 'Non-custodial, decentralized, social asset management on EVM chains.', | ||
url: 'https://www.dhedge.org/', | ||
|
||
groups: { | ||
pool: { | ||
id: 'pool', | ||
type: GroupType.TOKEN, | ||
label: 'Pools', | ||
}, | ||
}, | ||
|
||
tags: [AppTag.ASSET_MANAGEMENT], | ||
keywords: [], | ||
links: {}, | ||
|
||
supportedNetworks: { | ||
[Network.POLYGON_MAINNET]: [AppAction.VIEW], | ||
[Network.OPTIMISM_MAINNET]: [AppAction.VIEW], | ||
}, | ||
|
||
primaryColor: '#fff', | ||
}); | ||
|
||
@Register.AppDefinition(DHEDGE_V_2_DEFINITION.id) | ||
export class DhedgeV2AppDefinition extends AppDefinition { | ||
constructor() { | ||
super(DHEDGE_V_2_DEFINITION); | ||
} | ||
} | ||
|
||
export default DHEDGE_V_2_DEFINITION; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { Register } from '~app-toolkit/decorators'; | ||
import { AbstractApp } from '~app/app.dynamic-module'; | ||
|
||
import { DhedgeV2ContractFactory } from './contracts'; | ||
import { DhedgeV2AppDefinition, DHEDGE_V_2_DEFINITION } from './dhedge-v2.definition'; | ||
import { OptimismDhedgeV2BalanceFetcher } from './optimism/dhedge-v2.balance-fetcher'; | ||
import { OptimismDhedgeV2PoolTokenFetcher } from './optimism/dhedge-v2.pool.token-fetcher'; | ||
import { PolygonDhedgeV2BalanceFetcher } from './polygon/dhedge-v2.balance-fetcher'; | ||
import { PolygonDhedgeV2PoolTokenFetcher } from './polygon/dhedge-v2.pool.token-fetcher'; | ||
|
||
@Register.AppModule({ | ||
appId: DHEDGE_V_2_DEFINITION.id, | ||
providers: [ | ||
DhedgeV2AppDefinition, | ||
DhedgeV2ContractFactory, | ||
OptimismDhedgeV2BalanceFetcher, | ||
OptimismDhedgeV2PoolTokenFetcher, | ||
PolygonDhedgeV2BalanceFetcher, | ||
PolygonDhedgeV2PoolTokenFetcher, | ||
], | ||
}) | ||
export class DhedgeV2AppModule extends AbstractApp() {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export { DHEDGE_V_2_DEFINITION, DhedgeV2AppDefinition } from './dhedge-v2.definition'; | ||
export { DhedgeV2AppModule } from './dhedge-v2.module'; | ||
export { DhedgeV2ContractFactory } from './contracts'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { Inject } from '@nestjs/common'; | ||
|
||
import { IAppToolkit, APP_TOOLKIT } from '~app-toolkit/app-toolkit.interface'; | ||
import { Register } from '~app-toolkit/decorators'; | ||
import { presentBalanceFetcherResponse } from '~app-toolkit/helpers/presentation/balance-fetcher-response.present'; | ||
import { BalanceFetcher } from '~balance/balance-fetcher.interface'; | ||
import { Network } from '~types/network.interface'; | ||
|
||
import { DHEDGE_V_2_DEFINITION } from '../dhedge-v2.definition'; | ||
|
||
const appId = DHEDGE_V_2_DEFINITION.id; | ||
const network = Network.OPTIMISM_MAINNET; | ||
|
||
@Register.BalanceFetcher(DHEDGE_V_2_DEFINITION.id, network) | ||
export class OptimismDhedgeV2BalanceFetcher implements BalanceFetcher { | ||
constructor(@Inject(APP_TOOLKIT) private readonly appToolkit: IAppToolkit) {} | ||
|
||
async getTokenBalances(address: string) { | ||
return await this.appToolkit.helpers.tokenBalanceHelper.getTokenBalances({ | ||
address, | ||
appId, | ||
groupId: DHEDGE_V_2_DEFINITION.groups.pool.id, | ||
network, | ||
}); | ||
} | ||
|
||
async getBalances(address: string) { | ||
const assets = await this.getTokenBalances(address); | ||
return presentBalanceFetcherResponse([ | ||
{ | ||
label: 'Pools', | ||
assets, | ||
}, | ||
]); | ||
} | ||
} |
64 changes: 64 additions & 0 deletions
64
src/apps/dhedge-v2/optimism/dhedge-v2.pool.token-fetcher.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import { Inject } from '@nestjs/common'; | ||
import { gql } from 'graphql-request'; | ||
|
||
import { IAppToolkit, APP_TOOLKIT } from '~app-toolkit/app-toolkit.interface'; | ||
import { Register } from '~app-toolkit/decorators'; | ||
import { Erc20 } from '~contract/contracts'; | ||
import { PositionFetcher } from '~position/position-fetcher.interface'; | ||
import { AppTokenPosition } from '~position/position.interface'; | ||
import { Network } from '~types/network.interface'; | ||
|
||
import { DhedgeV2ContractFactory } from '../contracts'; | ||
import { DHEDGE_V_2_DEFINITION } from '../dhedge-v2.definition'; | ||
|
||
const appId = DHEDGE_V_2_DEFINITION.id; | ||
const groupId = DHEDGE_V_2_DEFINITION.groups.pool.id; | ||
const network = Network.OPTIMISM_MAINNET; | ||
|
||
const query = gql` | ||
query getPools { | ||
pools { | ||
id | ||
name | ||
tokenPrice | ||
} | ||
} | ||
`; | ||
|
||
interface DHedgeResponse { | ||
pools: { | ||
id: string; | ||
name: string; | ||
tokenPrice: string; | ||
}[]; | ||
} | ||
|
||
@Register.TokenPositionFetcher({ appId, groupId, network }) | ||
export class OptimismDhedgeV2PoolTokenFetcher implements PositionFetcher<AppTokenPosition> { | ||
constructor( | ||
@Inject(APP_TOOLKIT) private readonly appToolkit: IAppToolkit, | ||
@Inject(DhedgeV2ContractFactory) private readonly contractFactory: DhedgeV2ContractFactory, | ||
) {} | ||
|
||
async getPositions() { | ||
const endpoint = 'https://api.thegraph.com/subgraphs/name/dhedge/dhedge-v2-optimism'; | ||
const { pools } = await this.appToolkit.helpers.theGraphHelper.request<DHedgeResponse>({ endpoint, query }); | ||
|
||
const baseTokens = await this.appToolkit.getBaseTokenPrices(network); | ||
const sUSD = baseTokens.find(t => t.symbol === 'sUSD')!; | ||
|
||
return await this.appToolkit.helpers.vaultTokenHelper.getTokens<Erc20>({ | ||
appId, | ||
groupId, | ||
network, | ||
resolveVaultAddresses: () => pools.map(p => p.id.toLowerCase()), | ||
resolveContract: ({ address, network }) => this.contractFactory.erc20({ address, network }), | ||
resolveUnderlyingTokenAddress: () => sUSD.address, // TODO: get actual underlying tokens | ||
resolveReserve: () => 0, | ||
resolvePricePerShare: async ({ underlyingToken, contract }) => { | ||
const pool = pools.find(p => p.id.toLowerCase() === contract.address)!; | ||
return Number(pool.tokenPrice) / 10 ** underlyingToken.decimals; | ||
}, | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { Inject } from '@nestjs/common'; | ||
|
||
import { IAppToolkit, APP_TOOLKIT } from '~app-toolkit/app-toolkit.interface'; | ||
import { Register } from '~app-toolkit/decorators'; | ||
import { presentBalanceFetcherResponse } from '~app-toolkit/helpers/presentation/balance-fetcher-response.present'; | ||
import { BalanceFetcher } from '~balance/balance-fetcher.interface'; | ||
import { Network } from '~types/network.interface'; | ||
|
||
import { DHEDGE_V_2_DEFINITION } from '../dhedge-v2.definition'; | ||
|
||
const appId = DHEDGE_V_2_DEFINITION.id; | ||
const network = Network.POLYGON_MAINNET; | ||
|
||
@Register.BalanceFetcher(DHEDGE_V_2_DEFINITION.id, network) | ||
export class PolygonDhedgeV2BalanceFetcher implements BalanceFetcher { | ||
constructor(@Inject(APP_TOOLKIT) private readonly appToolkit: IAppToolkit) {} | ||
|
||
async getTokenBalances(address: string) { | ||
return await this.appToolkit.helpers.tokenBalanceHelper.getTokenBalances({ | ||
address, | ||
appId, | ||
groupId: DHEDGE_V_2_DEFINITION.groups.pool.id, | ||
network, | ||
}); | ||
} | ||
|
||
async getBalances(address: string) { | ||
const assets = await this.getTokenBalances(address); | ||
return presentBalanceFetcherResponse([ | ||
{ | ||
label: 'Pools', | ||
assets, | ||
}, | ||
]); | ||
} | ||
} |
102 changes: 102 additions & 0 deletions
102
src/apps/dhedge-v2/polygon/dhedge-v2.pool.token-fetcher.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
import { Inject } from '@nestjs/common'; | ||
import { gql } from 'graphql-request'; | ||
import { filter } from 'lodash'; | ||
|
||
import { IAppToolkit, APP_TOOLKIT } from '~app-toolkit/app-toolkit.interface'; | ||
import { Register } from '~app-toolkit/decorators'; | ||
import { getAppImg } from '~app-toolkit/helpers/presentation/image.present'; | ||
import { ContractType } from '~position/contract.interface'; | ||
import { PositionFetcher } from '~position/position-fetcher.interface'; | ||
import { AppTokenPosition } from '~position/position.interface'; | ||
import { BaseToken } from '~position/token.interface'; | ||
import { Network } from '~types/network.interface'; | ||
|
||
import { DhedgeV2ContractFactory } from '../contracts'; | ||
import { DHEDGE_V_2_DEFINITION } from '../dhedge-v2.definition'; | ||
|
||
const appId = DHEDGE_V_2_DEFINITION.id; | ||
const groupId = DHEDGE_V_2_DEFINITION.groups.pool.id; | ||
const network = Network.POLYGON_MAINNET; | ||
|
||
const query = gql` | ||
query getPools { | ||
pools { | ||
id | ||
name | ||
tokenPrice | ||
assets { | ||
id | ||
} | ||
} | ||
} | ||
`; | ||
|
||
interface DHedgeResponse { | ||
pools: { | ||
id: string; | ||
name: string; | ||
tokenPrice: string; | ||
assets: { id: string }[]; | ||
}[]; | ||
} | ||
|
||
@Register.TokenPositionFetcher({ appId, groupId, network }) | ||
export class PolygonDhedgeV2PoolTokenFetcher implements PositionFetcher<AppTokenPosition> { | ||
constructor( | ||
@Inject(APP_TOOLKIT) private readonly appToolkit: IAppToolkit, | ||
@Inject(DhedgeV2ContractFactory) private readonly contractFactory: DhedgeV2ContractFactory, | ||
) {} | ||
|
||
async getPositions() { | ||
const endpoint = 'https://api.thegraph.com/subgraphs/name/dhedge/dhedge-v2-polygon'; | ||
const { pools } = await this.appToolkit.helpers.theGraphHelper.request<DHedgeResponse>({ endpoint, query }); | ||
|
||
const baseTokens = await this.appToolkit.getBaseTokenPrices(network); | ||
const dUSD = baseTokens.find(t => t.address === '0xbae28251b2a4e621aa7e20538c06dee010bc06de')!; | ||
|
||
const multicall = this.appToolkit.getMulticall(network); | ||
|
||
const tokens = await Promise.all( | ||
pools.map(async pool => { | ||
const address = pool.id.toLowerCase(); | ||
const contract = this.contractFactory.erc20({ address, network }); | ||
|
||
const [symbol, decimals, supplyRaw] = await Promise.all([ | ||
multicall.wrap(contract).symbol(), | ||
multicall.wrap(contract).decimals(), | ||
multicall.wrap(contract).totalSupply(), | ||
]); | ||
const supply = Number(supplyRaw) / 10 ** decimals; | ||
const tokens = filter( | ||
pool.assets.map(asset => baseTokens.find(t => t.address === asset.id.toLowerCase())), | ||
) as BaseToken[]; | ||
const pricePerShare = Number(pool.tokenPrice) / 10 ** decimals; | ||
const price = pricePerShare * dUSD.price; | ||
const images = [getAppImg(DHEDGE_V_2_DEFINITION.id)]; | ||
|
||
const token: AppTokenPosition = { | ||
type: ContractType.APP_TOKEN, | ||
appId, | ||
groupId, | ||
address, | ||
network, | ||
symbol, | ||
decimals, | ||
supply, | ||
tokens, | ||
price, | ||
pricePerShare, | ||
dataProps: {}, | ||
displayProps: { | ||
label: pool.name, | ||
images, | ||
}, | ||
}; | ||
|
||
return token; | ||
}), | ||
); | ||
|
||
return tokens; | ||
} | ||
} |