diff --git a/src/apps/rocket-pool/contracts/abis/rocket-minipool-manager.json b/src/apps/rocket-pool/contracts/abis/rocket-minipool-manager.json new file mode 100644 index 000000000..77d308169 --- /dev/null +++ b/src/apps/rocket-pool/contracts/abis/rocket-minipool-manager.json @@ -0,0 +1,9 @@ +[ + { + "inputs": [{ "internalType": "address", "name": "_nodeAddress", "type": "address" }], + "name": "getNodeActiveMinipoolCount", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + } +] diff --git a/src/apps/rocket-pool/contracts/ethers/RocketMinipoolManager.ts b/src/apps/rocket-pool/contracts/ethers/RocketMinipoolManager.ts new file mode 100644 index 000000000..03d2b9f7e --- /dev/null +++ b/src/apps/rocket-pool/contracts/ethers/RocketMinipoolManager.ts @@ -0,0 +1,64 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +import type { BaseContract, BigNumber, BytesLike, CallOverrides, PopulatedTransaction, Signer, utils } from 'ethers'; +import type { FunctionFragment, Result } from '@ethersproject/abi'; +import type { Listener, Provider } from '@ethersproject/providers'; +import type { TypedEventFilter, TypedEvent, TypedListener, OnEvent } from './common'; + +export interface RocketMinipoolManagerInterface extends utils.Interface { + functions: { + 'getNodeActiveMinipoolCount(address)': FunctionFragment; + }; + + getFunction(nameOrSignatureOrTopic: 'getNodeActiveMinipoolCount'): FunctionFragment; + + encodeFunctionData(functionFragment: 'getNodeActiveMinipoolCount', values: [string]): string; + + decodeFunctionResult(functionFragment: 'getNodeActiveMinipoolCount', data: BytesLike): Result; + + events: {}; +} + +export interface RocketMinipoolManager extends BaseContract { + connect(signerOrProvider: Signer | Provider | string): this; + attach(addressOrName: string): this; + deployed(): Promise; + + interface: RocketMinipoolManagerInterface; + + queryFilter( + event: TypedEventFilter, + fromBlockOrBlockhash?: string | number | undefined, + toBlock?: string | number | undefined, + ): Promise>; + + listeners(eventFilter?: TypedEventFilter): Array>; + listeners(eventName?: string): Array; + removeAllListeners(eventFilter: TypedEventFilter): this; + removeAllListeners(eventName?: string): this; + off: OnEvent; + on: OnEvent; + once: OnEvent; + removeListener: OnEvent; + + functions: { + getNodeActiveMinipoolCount(_nodeAddress: string, overrides?: CallOverrides): Promise<[BigNumber]>; + }; + + getNodeActiveMinipoolCount(_nodeAddress: string, overrides?: CallOverrides): Promise; + + callStatic: { + getNodeActiveMinipoolCount(_nodeAddress: string, overrides?: CallOverrides): Promise; + }; + + filters: {}; + + estimateGas: { + getNodeActiveMinipoolCount(_nodeAddress: string, overrides?: CallOverrides): Promise; + }; + + populateTransaction: { + getNodeActiveMinipoolCount(_nodeAddress: string, overrides?: CallOverrides): Promise; + }; +} diff --git a/src/apps/rocket-pool/contracts/ethers/factories/RocketMinipoolManager__factory.ts b/src/apps/rocket-pool/contracts/ethers/factories/RocketMinipoolManager__factory.ts new file mode 100644 index 000000000..b07764b49 --- /dev/null +++ b/src/apps/rocket-pool/contracts/ethers/factories/RocketMinipoolManager__factory.ts @@ -0,0 +1,39 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ + +import { Contract, Signer, utils } from 'ethers'; +import type { Provider } from '@ethersproject/providers'; +import type { RocketMinipoolManager, RocketMinipoolManagerInterface } from '../RocketMinipoolManager'; + +const _abi = [ + { + inputs: [ + { + internalType: 'address', + name: '_nodeAddress', + type: 'address', + }, + ], + name: 'getNodeActiveMinipoolCount', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, +]; + +export class RocketMinipoolManager__factory { + static readonly abi = _abi; + static createInterface(): RocketMinipoolManagerInterface { + return new utils.Interface(_abi) as RocketMinipoolManagerInterface; + } + static connect(address: string, signerOrProvider: Signer | Provider): RocketMinipoolManager { + return new Contract(address, _abi, signerOrProvider) as RocketMinipoolManager; + } +} diff --git a/src/apps/rocket-pool/contracts/ethers/factories/index.ts b/src/apps/rocket-pool/contracts/ethers/factories/index.ts index efd5b8097..28ac19b18 100644 --- a/src/apps/rocket-pool/contracts/ethers/factories/index.ts +++ b/src/apps/rocket-pool/contracts/ethers/factories/index.ts @@ -2,4 +2,5 @@ /* tslint:disable */ /* eslint-disable */ export { RocketDaoNodeTrusted__factory } from './RocketDaoNodeTrusted__factory'; +export { RocketMinipoolManager__factory } from './RocketMinipoolManager__factory'; export { RocketNodeStaking__factory } from './RocketNodeStaking__factory'; diff --git a/src/apps/rocket-pool/contracts/ethers/index.ts b/src/apps/rocket-pool/contracts/ethers/index.ts index b3e79a1b0..690c3b08c 100644 --- a/src/apps/rocket-pool/contracts/ethers/index.ts +++ b/src/apps/rocket-pool/contracts/ethers/index.ts @@ -2,7 +2,9 @@ /* tslint:disable */ /* eslint-disable */ export type { RocketDaoNodeTrusted } from './RocketDaoNodeTrusted'; +export type { RocketMinipoolManager } from './RocketMinipoolManager'; export type { RocketNodeStaking } from './RocketNodeStaking'; export * as factories from './factories'; export { RocketDaoNodeTrusted__factory } from './factories/RocketDaoNodeTrusted__factory'; +export { RocketMinipoolManager__factory } from './factories/RocketMinipoolManager__factory'; export { RocketNodeStaking__factory } from './factories/RocketNodeStaking__factory'; diff --git a/src/apps/rocket-pool/contracts/index.ts b/src/apps/rocket-pool/contracts/index.ts index fccf60096..6b47e1e5a 100644 --- a/src/apps/rocket-pool/contracts/index.ts +++ b/src/apps/rocket-pool/contracts/index.ts @@ -5,6 +5,7 @@ import { ContractFactory } from '~contract/contracts'; import { Network } from '~types/network.interface'; import { RocketDaoNodeTrusted__factory } from './ethers'; +import { RocketMinipoolManager__factory } from './ethers'; import { RocketNodeStaking__factory } from './ethers'; // eslint-disable-next-line @@ -19,10 +20,14 @@ export class RocketPoolContractFactory extends ContractFactory { rocketDaoNodeTrusted({ address, network }: ContractOpts) { return RocketDaoNodeTrusted__factory.connect(address, this.appToolkit.getNetworkProvider(network)); } + rocketMinipoolManager({ address, network }: ContractOpts) { + return RocketMinipoolManager__factory.connect(address, this.appToolkit.getNetworkProvider(network)); + } rocketNodeStaking({ address, network }: ContractOpts) { return RocketNodeStaking__factory.connect(address, this.appToolkit.getNetworkProvider(network)); } } export type { RocketDaoNodeTrusted } from './ethers'; +export type { RocketMinipoolManager } from './ethers'; export type { RocketNodeStaking } from './ethers'; diff --git a/src/apps/rocket-pool/ethereum/rocket-pool.balance-fetcher.ts b/src/apps/rocket-pool/ethereum/rocket-pool.balance-fetcher.ts index dc1b3d6e9..fd67b7f11 100644 --- a/src/apps/rocket-pool/ethereum/rocket-pool.balance-fetcher.ts +++ b/src/apps/rocket-pool/ethereum/rocket-pool.balance-fetcher.ts @@ -10,6 +10,10 @@ import { Network } from '~types/network.interface'; import { RocketPoolContractFactory } from '../contracts'; import { ROCKET_POOL_DEFINITION } from '../rocket-pool.definition'; +import { + rocketMinipoolManagerAddress, + rocketNodeStakingAddress, +} from './rocket-pool.staking.contract-position-fetcher'; const network = Network.ETHEREUM_MAINNET; @@ -21,11 +25,35 @@ export class EthereumRocketPoolBalanceFetcher implements BalanceFetcher { ) {} async getStakedBalances(address: string) { + return [await this.getStakedEthBalance(address), await this.getStakedRplBalance(address)].flat(); + } + + async getStakedEthBalance(address: string) { + return this.appToolkit.helpers.contractPositionBalanceHelper.getContractPositionBalances({ + address, + appId: ROCKET_POOL_DEFINITION.id, + groupId: ROCKET_POOL_DEFINITION.groups.staking.id, + network: Network.ETHEREUM_MAINNET, + filter: p => p.address == rocketMinipoolManagerAddress, + resolveBalances: async ({ address, contractPosition }) => { + const token = contractPosition.tokens.find(isSupplied)!; + const contract = this.rocketPoolContractFactory.rocketMinipoolManager(contractPosition); + const minipoolCount = (await contract.getNodeActiveMinipoolCount(address)).toNumber(); + const minipoolDepositSize = 16 * 10 ** 18; // 16 ETH + const balanceRaw = minipoolCount * minipoolDepositSize; + const tokenBalance = drillBalance(token, balanceRaw.toString()); + return [tokenBalance]; + }, + }); + } + + async getStakedRplBalance(address: string) { return this.appToolkit.helpers.contractPositionBalanceHelper.getContractPositionBalances({ address, appId: ROCKET_POOL_DEFINITION.id, groupId: ROCKET_POOL_DEFINITION.groups.staking.id, network: Network.ETHEREUM_MAINNET, + filter: p => p.address == rocketNodeStakingAddress, resolveBalances: async ({ address, contractPosition }) => { const token = contractPosition.tokens.find(isSupplied)!; const contract = this.rocketPoolContractFactory.rocketNodeStaking(contractPosition); diff --git a/src/apps/rocket-pool/ethereum/rocket-pool.staking.contract-position-fetcher.ts b/src/apps/rocket-pool/ethereum/rocket-pool.staking.contract-position-fetcher.ts index 0609680a0..142e5431f 100644 --- a/src/apps/rocket-pool/ethereum/rocket-pool.staking.contract-position-fetcher.ts +++ b/src/apps/rocket-pool/ethereum/rocket-pool.staking.contract-position-fetcher.ts @@ -1,6 +1,7 @@ import { Inject } from '@nestjs/common'; import { IAppToolkit, APP_TOOLKIT } from '~app-toolkit/app-toolkit.interface'; +import { ZERO_ADDRESS } from '~app-toolkit/constants/address'; import { Register } from '~app-toolkit/decorators'; import { getImagesFromToken } from '~app-toolkit/helpers/presentation/image.present'; import { ContractType } from '~position/contract.interface'; @@ -11,11 +12,13 @@ import { Network } from '~types/network.interface'; import { ROCKET_POOL_DEFINITION } from '../rocket-pool.definition'; +export const rocketNodeStakingAddress = '0x3019227b2b8493e45bf5d25302139c9a2713bf15'; +export const rocketMinipoolManagerAddress = '0x6293B8abC1F36aFB22406Be5f96D893072A8cF3a'; +export const rocketTokenRPLAddress = '0xd33526068d116ce69f19a9ee46f0bd304f21a51f'; + const appId = ROCKET_POOL_DEFINITION.id; const groupId = ROCKET_POOL_DEFINITION.groups.staking.id; const network = Network.ETHEREUM_MAINNET; -const rocketNodeStakingAddress = '0x3019227b2b8493e45bf5d25302139c9a2713bf15'; -const rocketTokenRPLAddress = '0xd33526068d116ce69f19a9ee46f0bd304f21a51f'; @Register.ContractPositionFetcher({ appId, groupId, network }) export class EthereumRocketPoolStakingContractPositionFetcher implements PositionFetcher { @@ -23,9 +26,24 @@ export class EthereumRocketPoolStakingContractPositionFetcher implements Positio async getPositions() { const baseTokens = await this.appToolkit.getBaseTokenPrices(network); + const eth = baseTokens.find(v => v.address === ZERO_ADDRESS)!; const rpl = baseTokens.find(v => v.address === rocketTokenRPLAddress)!; - const position: ContractPosition = { + const ethposition: ContractPosition = { + type: ContractType.POSITION, + address: rocketMinipoolManagerAddress, + network, + appId, + groupId, + tokens: [supplied(eth)], + dataProps: {}, + displayProps: { + label: `Staked ETH`, + images: getImagesFromToken(eth), + }, + }; + + const rplposition: ContractPosition = { type: ContractType.POSITION, address: rocketNodeStakingAddress, network, @@ -39,6 +57,6 @@ export class EthereumRocketPoolStakingContractPositionFetcher implements Positio }, }; - return [position]; + return [ethposition, rplposition]; } }