Skip to content
This repository has been archived by the owner on Jan 24, 2024. It is now read-only.

Commit

Permalink
feat(cozy-finance): Support Cozy Finance (#534)
Browse files Browse the repository at this point in the history
  • Loading branch information
immasandwich committed May 28, 2022
1 parent 8b2a4c2 commit 8199a2d
Show file tree
Hide file tree
Showing 12 changed files with 384 additions and 2 deletions.
4 changes: 2 additions & 2 deletions src/apps/compound/helper/compound.supply.token-helper.ts
Expand Up @@ -3,7 +3,7 @@ import { BigNumberish } from 'ethers';
import _ from 'lodash';

import { APP_TOOLKIT, IAppToolkit } from '~app-toolkit/app-toolkit.interface';
import { ZERO_ADDRESS } from '~app-toolkit/constants/address';
import { ETH_ADDR_ALIAS, ZERO_ADDRESS } from '~app-toolkit/constants/address';
import { BLOCKS_PER_DAY } from '~app-toolkit/constants/blocks';
import {
buildDollarDisplayItem,
Expand Down Expand Up @@ -93,7 +93,7 @@ export class CompoundSupplyTokenHelper {
const contract = getTokenContract({ address, network });

const underlyingAddress = await getUnderlyingAddress({ contract, multicall })
.then(t => t.toLowerCase())
.then(t => t.toLowerCase().replace(ETH_ADDR_ALIAS, ZERO_ADDRESS))
.catch(() => ZERO_ADDRESS);

const underlyingToken = allTokens.find(v => v.address === underlyingAddress);
Expand Down
70 changes: 70 additions & 0 deletions src/apps/cozy-finance/arbitrum/cozy-finance.balance-fetcher.ts
@@ -0,0 +1,70 @@
import { Inject } from '@nestjs/common';

import { Register } from '~app-toolkit/decorators';
import { presentBalanceFetcherResponse } from '~app-toolkit/helpers/presentation/balance-fetcher-response.present';
import {
CompoundBorrowBalanceHelper,
CompoundContractFactory,
CompoundLendingMetaHelper,
CompoundSupplyBalanceHelper,
} from '~apps/compound';
import { BalanceFetcher } from '~balance/balance-fetcher.interface';
import { Network } from '~types/network.interface';

import { COZY_FINANCE_DEFINITION } from '../cozy-finance.definition';

const appId = COZY_FINANCE_DEFINITION.id;
const network = Network.ARBITRUM_MAINNET;

@Register.BalanceFetcher(COZY_FINANCE_DEFINITION.id, network)
export class ArbitrumCozyFinanceBalanceFetcher implements BalanceFetcher {
constructor(
@Inject(CompoundBorrowBalanceHelper)
private readonly compoundBorrowBalanceHelper: CompoundBorrowBalanceHelper,
@Inject(CompoundSupplyBalanceHelper)
private readonly compoundSupplyBalanceHelper: CompoundSupplyBalanceHelper,
@Inject(CompoundLendingMetaHelper)
private readonly compoundLendingMetaHelper: CompoundLendingMetaHelper,
@Inject(CompoundContractFactory)
private readonly compoundContractFactory: CompoundContractFactory,
) {}

async getSupplyBalances(address: string) {
return this.compoundSupplyBalanceHelper.getBalances({
address,
appId,
groupId: COZY_FINANCE_DEFINITION.groups.supply.id,
network,
getTokenContract: ({ address, network }) => this.compoundContractFactory.compoundCToken({ address, network }),
getBalanceRaw: ({ contract, address, multicall }) => multicall.wrap(contract).balanceOf(address),
});
}

async getBorrowBalances(address: string) {
return this.compoundBorrowBalanceHelper.getBalances({
address,
appId,
groupId: COZY_FINANCE_DEFINITION.groups.borrow.id,
network,
getTokenContract: ({ address, network }) => this.compoundContractFactory.compoundCToken({ address, network }),
getBorrowBalanceRaw: ({ contract, address, multicall }) => multicall.wrap(contract).borrowBalanceCurrent(address),
});
}

async getBalances(address: string) {
const [supplyBalances, borrowBalances] = await Promise.all([
this.getSupplyBalances(address),
this.getBorrowBalances(address),
]);

const meta = this.compoundLendingMetaHelper.getMeta({ balances: [...supplyBalances, ...borrowBalances] });

return presentBalanceFetcherResponse([
{
label: 'Lending',
assets: [...supplyBalances, ...borrowBalances],
meta,
},
]);
}
}
@@ -0,0 +1,30 @@
import { Inject } from '@nestjs/common';

import { Register } from '~app-toolkit/decorators';
import { CompoundBorrowContractPositionHelper } from '~apps/compound';
import { PositionFetcher } from '~position/position-fetcher.interface';
import { ContractPosition } from '~position/position.interface';
import { Network } from '~types/network.interface';

import { COZY_FINANCE_DEFINITION } from '../cozy-finance.definition';

const appId = COZY_FINANCE_DEFINITION.id;
const groupId = COZY_FINANCE_DEFINITION.groups.borrow.id;
const network = Network.ARBITRUM_MAINNET;

@Register.ContractPositionFetcher({ appId, groupId, network })
export class ArbitrumCozyFinanceBorrowContractPositionFetcher implements PositionFetcher<ContractPosition> {
constructor(
@Inject(CompoundBorrowContractPositionHelper)
private readonly compoundBorrowContractPositionHelper: CompoundBorrowContractPositionHelper,
) {}

async getPositions() {
return this.compoundBorrowContractPositionHelper.getPositions({
network,
appId,
groupId,
supplyGroupId: COZY_FINANCE_DEFINITION.groups.supply.id,
});
}
}
@@ -0,0 +1,45 @@
import { Inject } from '@nestjs/common';

import { Register } from '~app-toolkit/decorators';
import { CompoundContractFactory, CompoundSupplyTokenHelper } from '~apps/compound';
import { PositionFetcher } from '~position/position-fetcher.interface';
import { AppTokenPosition } from '~position/position.interface';
import { Network } from '~types/network.interface';

import COZY_FINANCE_DEFINITION from '../cozy-finance.definition';

const appId = COZY_FINANCE_DEFINITION.id;
const groupId = COZY_FINANCE_DEFINITION.groups.supply.id;
const network = Network.ARBITRUM_MAINNET;

@Register.TokenPositionFetcher({ appId, groupId, network })
export class ArbitrumCozyFinanceSupplyTokenFetcher implements PositionFetcher<AppTokenPosition> {
constructor(
@Inject(CompoundContractFactory) private readonly compoundContractFactory: CompoundContractFactory,
@Inject(CompoundSupplyTokenHelper) private readonly compoundSupplyTokenHelper: CompoundSupplyTokenHelper,
) {}

async getPositions() {
return this.compoundSupplyTokenHelper.getTokens({
network,
appId,
groupId,
comptrollerAddress: '0x895879b2c1fbb6ccfcd101f2d3f3c76363664f92',
getComptrollerContract: ({ address, network }) =>
this.compoundContractFactory.compoundComptroller({ address, network }),
getTokenContract: ({ address, network }) => this.compoundContractFactory.compoundCToken({ address, network }),
getAllMarkets: ({ contract, multicall }) => multicall.wrap(contract).getAllMarkets(),
getExchangeRate: ({ contract, multicall }) => multicall.wrap(contract).exchangeRateCurrent(),
getSupplyRate: ({ contract, multicall }) => multicall.wrap(contract).supplyRatePerBlock(),
getBorrowRate: ({ contract, multicall }) => multicall.wrap(contract).borrowRatePerBlock(),
getUnderlyingAddress: ({ contract, multicall }) => multicall.wrap(contract).underlying(),
getExchangeRateMantissa: ({ underlyingTokenDecimals }) => underlyingTokenDecimals + 10,
getDisplayLabel: async ({ contract, multicall, underlyingToken }) => {
const [symbol, name] = await Promise.all([multicall.wrap(contract).symbol(), multicall.wrap(contract).name()]);
if (!name.startsWith(`${symbol}-`)) return underlyingToken.symbol;
const triggerLabel = name.replace(`${symbol}-`, '');
return `${underlyingToken.symbol} - ${triggerLabel}`;
},
});
}
}
Binary file added src/apps/cozy-finance/assets/logo.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions src/apps/cozy-finance/contracts/index.ts
@@ -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 CozyFinanceContractFactory extends ContractFactory {
constructor(@Inject(APP_TOOLKIT) protected readonly appToolkit: IAppToolkit) {
super((network: Network) => appToolkit.getNetworkProvider(network));
}
}
45 changes: 45 additions & 0 deletions src/apps/cozy-finance/cozy-finance.definition.ts
@@ -0,0 +1,45 @@
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 COZY_FINANCE_DEFINITION = appDefinition({
id: 'cozy-finance',
name: 'Cozy Finance',
description: 'Cozy is an autonomous protocol for protecting DeFi deposits.',
url: 'https://www.cozy.finance/',

groups: {
supply: {
id: 'supply',
type: GroupType.TOKEN,
label: 'Supply',
},

borrow: {
id: 'borrow',
type: GroupType.TOKEN,
label: 'Borrow',
},
},

tags: [AppTag.INSURANCE],
keywords: [],
links: {},

supportedNetworks: {
[Network.ETHEREUM_MAINNET]: [AppAction.VIEW],
[Network.ARBITRUM_MAINNET]: [AppAction.VIEW],
},

primaryColor: '#fff',
});

@Register.AppDefinition(COZY_FINANCE_DEFINITION.id)
export class CozyFinanceAppDefinition extends AppDefinition {
constructor() {
super(COZY_FINANCE_DEFINITION);
}
}

export default COZY_FINANCE_DEFINITION;
30 changes: 30 additions & 0 deletions src/apps/cozy-finance/cozy-finance.module.ts
@@ -0,0 +1,30 @@
import { Register } from '~app-toolkit/decorators';
import { AbstractApp } from '~app/app.dynamic-module';
import { CompoundAppModule } from '~apps/compound';

import { ArbitrumCozyFinanceBalanceFetcher } from './arbitrum/cozy-finance.balance-fetcher';
import { ArbitrumCozyFinanceBorrowContractPositionFetcher } from './arbitrum/cozy-finance.borrow.contract-position-fetcher';
import { ArbitrumCozyFinanceSupplyTokenFetcher } from './arbitrum/cozy-finance.supply.token-fetcher';
import { CozyFinanceContractFactory } from './contracts';
import { CozyFinanceAppDefinition, COZY_FINANCE_DEFINITION } from './cozy-finance.definition';
import { EthereumCozyFinanceBalanceFetcher } from './ethereum/cozy-finance.balance-fetcher';
import { EthereumCozyFinanceBorrowContractPositionFetcher } from './ethereum/cozy-finance.borrow.contract-position-fetcher';
import { EthereumCozyFinanceSupplyTokenFetcher } from './ethereum/cozy-finance.supply.token-fetcher';

@Register.AppModule({
appId: COZY_FINANCE_DEFINITION.id,
imports: [CompoundAppModule],
providers: [
CozyFinanceAppDefinition,
CozyFinanceContractFactory,
// Arbitrum
ArbitrumCozyFinanceBalanceFetcher,
ArbitrumCozyFinanceBorrowContractPositionFetcher,
ArbitrumCozyFinanceSupplyTokenFetcher,
// Ethereum
EthereumCozyFinanceBalanceFetcher,
EthereumCozyFinanceBorrowContractPositionFetcher,
EthereumCozyFinanceSupplyTokenFetcher,
],
})
export class CozyFinanceAppModule extends AbstractApp() {}
70 changes: 70 additions & 0 deletions src/apps/cozy-finance/ethereum/cozy-finance.balance-fetcher.ts
@@ -0,0 +1,70 @@
import { Inject } from '@nestjs/common';

import { Register } from '~app-toolkit/decorators';
import { presentBalanceFetcherResponse } from '~app-toolkit/helpers/presentation/balance-fetcher-response.present';
import {
CompoundBorrowBalanceHelper,
CompoundContractFactory,
CompoundLendingMetaHelper,
CompoundSupplyBalanceHelper,
} from '~apps/compound';
import { BalanceFetcher } from '~balance/balance-fetcher.interface';
import { Network } from '~types/network.interface';

import { COZY_FINANCE_DEFINITION } from '../cozy-finance.definition';

const appId = COZY_FINANCE_DEFINITION.id;
const network = Network.ETHEREUM_MAINNET;

@Register.BalanceFetcher(COZY_FINANCE_DEFINITION.id, network)
export class EthereumCozyFinanceBalanceFetcher implements BalanceFetcher {
constructor(
@Inject(CompoundBorrowBalanceHelper)
private readonly compoundBorrowBalanceHelper: CompoundBorrowBalanceHelper,
@Inject(CompoundSupplyBalanceHelper)
private readonly compoundSupplyBalanceHelper: CompoundSupplyBalanceHelper,
@Inject(CompoundLendingMetaHelper)
private readonly compoundLendingMetaHelper: CompoundLendingMetaHelper,
@Inject(CompoundContractFactory)
private readonly compoundContractFactory: CompoundContractFactory,
) {}

async getSupplyBalances(address: string) {
return this.compoundSupplyBalanceHelper.getBalances({
address,
appId,
groupId: COZY_FINANCE_DEFINITION.groups.supply.id,
network,
getTokenContract: ({ address, network }) => this.compoundContractFactory.compoundCToken({ address, network }),
getBalanceRaw: ({ contract, address, multicall }) => multicall.wrap(contract).balanceOf(address),
});
}

async getBorrowBalances(address: string) {
return this.compoundBorrowBalanceHelper.getBalances({
address,
appId,
groupId: COZY_FINANCE_DEFINITION.groups.borrow.id,
network,
getTokenContract: ({ address, network }) => this.compoundContractFactory.compoundCToken({ address, network }),
getBorrowBalanceRaw: ({ contract, address, multicall }) => multicall.wrap(contract).borrowBalanceCurrent(address),
});
}

async getBalances(address: string) {
const [supplyBalances, borrowBalances] = await Promise.all([
this.getSupplyBalances(address),
this.getBorrowBalances(address),
]);

const meta = this.compoundLendingMetaHelper.getMeta({ balances: [...supplyBalances, ...borrowBalances] });

return presentBalanceFetcherResponse([
{
label: 'Lending',
assets: [...supplyBalances, ...borrowBalances],
meta,
},
]);
}
}
@@ -0,0 +1,30 @@
import { Inject } from '@nestjs/common';

import { Register } from '~app-toolkit/decorators';
import { CompoundBorrowContractPositionHelper } from '~apps/compound';
import { PositionFetcher } from '~position/position-fetcher.interface';
import { ContractPosition } from '~position/position.interface';
import { Network } from '~types/network.interface';

import { COZY_FINANCE_DEFINITION } from '../cozy-finance.definition';

const appId = COZY_FINANCE_DEFINITION.id;
const groupId = COZY_FINANCE_DEFINITION.groups.borrow.id;
const network = Network.ETHEREUM_MAINNET;

@Register.ContractPositionFetcher({ appId, groupId, network })
export class EthereumCozyFinanceBorrowContractPositionFetcher implements PositionFetcher<ContractPosition> {
constructor(
@Inject(CompoundBorrowContractPositionHelper)
private readonly compoundBorrowContractPositionHelper: CompoundBorrowContractPositionHelper,
) {}

async getPositions() {
return this.compoundBorrowContractPositionHelper.getPositions({
network,
appId,
groupId,
supplyGroupId: COZY_FINANCE_DEFINITION.groups.supply.id,
});
}
}

0 comments on commit 8199a2d

Please sign in to comment.