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

Commit

Permalink
feat(hakuswap): Integrate Hakuswap (#1155)
Browse files Browse the repository at this point in the history
  • Loading branch information
crypslato committed Aug 12, 2022
1 parent 6f5cd84 commit 3431579
Show file tree
Hide file tree
Showing 19 changed files with 4,510 additions and 0 deletions.
70 changes: 70 additions & 0 deletions src/apps/hakuswap/avalanche/hakuswap.balance-fetcher.ts
@@ -0,0 +1,70 @@
import { Inject } from '@nestjs/common';

import { APP_TOOLKIT, IAppToolkit } 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 { HakuswapContractFactory, HakuswapMasterchef } from '../contracts';
import { HAKUSWAP_DEFINITION } from '../hakuswap.definition';

const appId = HAKUSWAP_DEFINITION.id;
const network = Network.AVALANCHE_MAINNET;

@Register.BalanceFetcher(HAKUSWAP_DEFINITION.id, network)
export class AvalancheHakuswapBalanceFetcher implements BalanceFetcher {
constructor(
@Inject(APP_TOOLKIT) private readonly appToolkit: IAppToolkit,
@Inject(HakuswapContractFactory) private readonly contractFactory: HakuswapContractFactory,
) {}

async getPoolBalances(address: string) {
return this.appToolkit.helpers.tokenBalanceHelper.getTokenBalances({
address,
network,
appId,
groupId: HAKUSWAP_DEFINITION.groups.pool.id,
});
}

async getFarmBalances(address: string) {
return this.appToolkit.helpers.masterChefContractPositionBalanceHelper.getBalances<HakuswapMasterchef>({
address,
appId,
groupId: HAKUSWAP_DEFINITION.groups.farm.id,
network,
resolveChefContract: ({ contractAddress }) =>
this.contractFactory.hakuswapMasterchef({ network, address: contractAddress }),
resolveStakedTokenBalance: this.appToolkit.helpers.masterChefDefaultStakedBalanceStrategy.build({
resolveStakedBalance: ({ contract, multicall, contractPosition }) =>
multicall
.wrap(contract)
.userInfo(contractPosition.dataProps.poolIndex, address)
.then(v => v.amount),
}),
resolveClaimableTokenBalances: this.appToolkit.helpers.masterChefDefaultClaimableBalanceStrategy.build({
resolveClaimableBalance: ({ multicall, contract, contractPosition, address }) =>
multicall.wrap(contract).pendingCake(contractPosition.dataProps.poolIndex, address),
}),
});
}

async getBalances(address: string) {
const [poolBalances, farmBalances] = await Promise.all([
this.getPoolBalances(address),
this.getFarmBalances(address),
]);

return presentBalanceFetcherResponse([
{
label: 'Pools',
assets: poolBalances,
},
{
label: 'Farms',
assets: farmBalances,
},
]);
}
}
@@ -0,0 +1,49 @@
import { Inject } from '@nestjs/common';

import { IAppToolkit, APP_TOOLKIT } from '~app-toolkit/app-toolkit.interface';
import { Register } from '~app-toolkit/decorators';
import { PositionFetcher } from '~position/position-fetcher.interface';
import { ContractPosition } from '~position/position.interface';
import { Network } from '~types/network.interface';

import { HakuswapContractFactory, HakuswapMasterchef } from '../contracts';
import { HAKUSWAP_DEFINITION } from '../hakuswap.definition';

const appId = HAKUSWAP_DEFINITION.id;
const groupId = HAKUSWAP_DEFINITION.groups.farm.id;
const network = Network.AVALANCHE_MAINNET;

@Register.ContractPositionFetcher({ appId, groupId, network })
export class AvalancheHakuswapFarmContractPositionFetcher implements PositionFetcher<ContractPosition> {
constructor(
@Inject(APP_TOOLKIT) private readonly appToolkit: IAppToolkit,
@Inject(HakuswapContractFactory) private readonly hakuswapContractFactory: HakuswapContractFactory,
) {}

async getPositions() {
return this.appToolkit.helpers.masterChefContractPositionHelper.getContractPositions<HakuswapMasterchef>({
address: '0xba438a6f03c03fb1cf86567f6bb866ccfc9b2da7',
appId,
groupId,
network,
dependencies: [{ appId, groupIds: [HAKUSWAP_DEFINITION.groups.pool.id], network }],
resolveContract: ({ address, network }) => this.hakuswapContractFactory.hakuswapMasterchef({ address, network }),
resolvePoolLength: ({ multicall, contract }) => multicall.wrap(contract).poolLength(),
resolveDepositTokenAddress: ({ poolIndex, contract, multicall }) =>
multicall
.wrap(contract)
.poolInfo(poolIndex)
.then(v => v.lpToken),
resolveRewardTokenAddresses: ({ multicall, contract }) => multicall.wrap(contract).cake(),
resolveRewardRate: this.appToolkit.helpers.masterChefDefaultRewardsPerBlockStrategy.build({
resolvePoolAllocPoints: async ({ poolIndex, contract, multicall }) =>
multicall
.wrap(contract)
.poolInfo(poolIndex)
.then(v => v.allocPoint),
resolveTotalAllocPoints: ({ multicall, contract }) => multicall.wrap(contract).totalAllocPoint(),
resolveTotalRewardRate: ({ multicall, contract }) => multicall.wrap(contract).cakePerSecond(),
}),
});
}
}
57 changes: 57 additions & 0 deletions src/apps/hakuswap/avalanche/hakuswap.pool.token-fetcher.ts
@@ -0,0 +1,57 @@
import { Inject } from '@nestjs/common';

import { IAppToolkit, APP_TOOLKIT } from '~app-toolkit/app-toolkit.interface';
import { Register } from '~app-toolkit/decorators';
import { UniswapV2OnChainPoolTokenAddressStrategy, UniswapV2PoolTokenHelper } from '~apps/uniswap-v2';
import { PositionFetcher } from '~position/position-fetcher.interface';
import { AppTokenPosition } from '~position/position.interface';
import { Network } from '~types/network.interface';

import { HakuswapContractFactory } from '../contracts';
import { HAKUSWAP_DEFINITION } from '../hakuswap.definition';

const appId = HAKUSWAP_DEFINITION.id;
const groupId = HAKUSWAP_DEFINITION.groups.pool.id;
const network = Network.AVALANCHE_MAINNET;

@Register.TokenPositionFetcher({ appId, groupId, network })
export class AvalancheHakuswapPoolTokenFetcher implements PositionFetcher<AppTokenPosition> {
constructor(
@Inject(APP_TOOLKIT) private readonly appToolkit: IAppToolkit,
@Inject(HakuswapContractFactory) private readonly hakuswapContractFactory: HakuswapContractFactory,
@Inject(UniswapV2PoolTokenHelper) private readonly poolTokenHelper: UniswapV2PoolTokenHelper,
@Inject(UniswapV2OnChainPoolTokenAddressStrategy)
private readonly uniswapV2OnChainPoolTokenAddressStrategy: UniswapV2OnChainPoolTokenAddressStrategy,
) {}

async getPositions() {
return this.poolTokenHelper.getTokens({
network,
appId,
groupId,
minLiquidity: 10000,
fee: 0.003,
factoryAddress: '0x2db46feb38c57a6621bca4d97820e1fc1de40f41',
resolveFactoryContract: ({ address, network }) =>
this.hakuswapContractFactory.hakuswapFactory({
address,
network,
}),
resolvePoolContract: ({ address, network }) => this.hakuswapContractFactory.hakuswapPool({ address, network }),
resolvePoolTokenAddresses: this.uniswapV2OnChainPoolTokenAddressStrategy.build({
resolvePoolsLength: ({ multicall, factoryContract }) => multicall.wrap(factoryContract).allPairsLength(),
resolvePoolAddress: ({ multicall, factoryContract, poolIndex }) =>
multicall.wrap(factoryContract).allPairs(poolIndex),
}),
resolvePoolTokenSymbol: ({ multicall, poolContract }) => multicall.wrap(poolContract).symbol(),
resolvePoolTokenSupply: ({ multicall, poolContract }) => multicall.wrap(poolContract).totalSupply(),
resolvePoolReserves: async ({ multicall, poolContract }) => {
const reserves = await multicall.wrap(poolContract).getReserves();
return [reserves[0], reserves[1]];
},
resolvePoolUnderlyingTokenAddresses: async ({ multicall, poolContract }) => {
return Promise.all([multicall.wrap(poolContract).token0(), multicall.wrap(poolContract).token1()]);
},
});
}
}
97 changes: 97 additions & 0 deletions src/apps/hakuswap/contracts/abis/hakuswap-factory.json
@@ -0,0 +1,97 @@
[
{
"inputs": [{ "internalType": "address", "name": "_feeToSetter", "type": "address" }],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{ "indexed": true, "internalType": "address", "name": "token0", "type": "address" },
{ "indexed": true, "internalType": "address", "name": "token1", "type": "address" },
{ "indexed": false, "internalType": "address", "name": "pair", "type": "address" },
{ "indexed": false, "internalType": "uint256", "name": "", "type": "uint256" }
],
"name": "PairCreated",
"type": "event"
},
{
"inputs": [],
"name": "INIT_CODE_PAIR_HASH",
"outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
"name": "allPairs",
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "allPairsLength",
"outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{ "internalType": "address", "name": "tokenA", "type": "address" },
{ "internalType": "address", "name": "tokenB", "type": "address" }
],
"name": "createPair",
"outputs": [{ "internalType": "address", "name": "pair", "type": "address" }],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{ "internalType": "address", "name": "token0", "type": "address" },
{ "internalType": "address", "name": "token1", "type": "address" }
],
"name": "expectPairFor",
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "feeTo",
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "feeToSetter",
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{ "internalType": "address", "name": "", "type": "address" },
{ "internalType": "address", "name": "", "type": "address" }
],
"name": "getPair",
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [{ "internalType": "address", "name": "_feeTo", "type": "address" }],
"name": "setFeeTo",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [{ "internalType": "address", "name": "_feeToSetter", "type": "address" }],
"name": "setFeeToSetter",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]

0 comments on commit 3431579

Please sign in to comment.