import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { CurrencyDenom, DecCoin, DelegationWithEverything, Fee, FeeDetails, TransactionExecuteResult, } from '@nymproject/types'; import { DelegationContext } from '../delegations'; import { mockSleep } from './utils'; import { TPoolOption } from '../../components'; const SLEEP_MS = 1000; let mockDelegations: DelegationWithEverything[] = [ { mix_id: 1234, node_identity: 'FiojKW7oY9WQmLCiYAsCA21tpowZHS6zcUoyYm319p6Z', delegated_on_iso_datetime: new Date(2021, 1, 1).toDateString(), unclaimed_rewards: { amount: '0.05', denom: 'nym' }, amount: { amount: '10', denom: 'nym' }, owner: '', block_height: BigInt(100), cost_params: { profit_margin_percent: '0.04', interval_operating_cost: { amount: '20', denom: 'nym', }, }, stake_saturation: '0.2', avg_uptime_percent: 0.5, accumulated_by_delegates: { amount: '0', denom: 'nym' }, accumulated_by_operator: { amount: '0', denom: 'nym' }, uses_vesting_contract_tokens: false, pending_events: [], mixnode_is_unbonding: false, historical_node_identity: null, errors: null, }, { mix_id: 5678, node_identity: 'DT8S942S8AQs2zKHS9SVo1GyHmuca3pfL2uLhLksJ3D8', unclaimed_rewards: { amount: '0.1', denom: 'nym' }, amount: { amount: '100', denom: 'nym' }, delegated_on_iso_datetime: new Date(2021, 1, 2).toDateString(), owner: '', block_height: BigInt(4000), stake_saturation: '0.5', avg_uptime_percent: 0.1, cost_params: { profit_margin_percent: '0.04', interval_operating_cost: { amount: '60', denom: 'nym', }, }, accumulated_by_delegates: { amount: '0', denom: 'nym' }, accumulated_by_operator: { amount: '0', denom: 'nym' }, uses_vesting_contract_tokens: true, pending_events: [], mixnode_is_unbonding: false, historical_node_identity: null, errors: null, }, ]; export const MockDelegationContextProvider: FCWithChildren = ({ children }) => { const [trigger, setTrigger] = useState(new Date()); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(); const [delegations, setDelegations] = useState(); const [totalDelegations, setTotalDelegations] = useState(); const [totalRewards, setTotalRewards] = useState(); const [totalDelegationsAndRewards, setTotalDelegationsAndRewards] = useState(); const [lastUpdatedAtMs, setLastUpdatedAtMs] = useState(0); const [delegationItemErrors, setDelegationItemErrors] = useState<{ nodeId: string; errors: string }>(); const triggerStateUpdate = () => setTrigger(new Date()); const getDelegations = async (): Promise => mockDelegations.sort((a, b) => a.node_identity.localeCompare(b.node_identity)); const recalculate = async () => { const newDelegations = await getDelegations(); const newTotalDelegations = `${newDelegations.length * 100} NYM`; const rewardsSum = newDelegations.reduce((acc, d) => { const n = parseFloat(d.unclaimed_rewards?.amount ?? '0'); return acc + (Number.isFinite(n) ? n : 0); }, 0); const newTotalRewards = `${rewardsSum} nym`; setDelegations(newDelegations); setTotalDelegations(newTotalDelegations); setTotalRewards(newTotalRewards); setTotalDelegationsAndRewards(`${newTotalDelegations} + ${newTotalRewards}`); setLastUpdatedAtMs(Date.now()); }; const addDelegation = async ( data: { mix_id: number; amount: DecCoin }, _tokenPool: TPoolOption, _fee?: FeeDetails, ): Promise => { await mockSleep(SLEEP_MS); await recalculate(); triggerStateUpdate(); setTimeout(async () => { mockDelegations = mockDelegations.map((d) => { if (d.mix_id === data.mix_id) { return { ...d, isPending: undefined }; } return d; }); await recalculate(); triggerStateUpdate(); }, 3000); return { logs_json: '', msg_responses_json: '', gas_info: { gas_wanted: { gas_units: BigInt(1) }, gas_used: { gas_units: BigInt(1) }, }, transaction_hash: '55303CD4B91FAC4C2715E40EBB52BB3B92829D9431B3A279D37B5CC58432E354', fee: { amount: '1', denom: 'nym' }, }; }; const undelegate = async (mix_id: number, _fee?: Fee): Promise => { await mockSleep(SLEEP_MS); mockDelegations = mockDelegations.map((d) => { if (d.mix_id === mix_id) { return { ...d, isPending: { blockHeight: 5678, actionType: 'undelegate' } }; } return d; }); await recalculate(); triggerStateUpdate(); setTimeout(async () => { mockDelegations = mockDelegations.filter((d) => d.mix_id !== mix_id); await recalculate(); triggerStateUpdate(); }, 3000); return { logs_json: '', msg_responses_json: '', transaction_hash: '', gas_info: { gas_wanted: { gas_units: BigInt(1) }, gas_used: { gas_units: BigInt(1) }, }, fee: { amount: '1', denom: 'nym' as CurrencyDenom }, }; }; const undelegateVesting = async (_mix_id: number): Promise => ({ msg_responses_json: '', logs_json: '', transaction_hash: '', gas_info: { gas_wanted: { gas_units: BigInt(1) }, gas_used: { gas_units: BigInt(1) }, }, fee: { amount: '1', denom: 'nym' as CurrencyDenom }, }); const resetState = () => { setIsLoading(true); setError(undefined); setTotalDelegations(undefined); setTotalRewards(undefined); setTotalDelegationsAndRewards(undefined); setLastUpdatedAtMs(0); setDelegations([]); }; const refresh = useCallback(async () => { resetState(); setTimeout(async () => { try { await mockSleep(SLEEP_MS); await recalculate(); } catch (e) { setError((e as Error).message); } setIsLoading(false); }, 2000); }, []); useEffect(() => { resetState(); refresh(); }, []); const memoizedValue = useMemo( () => ({ delegationItemErrors, setDelegationItemErrors, isLoading, isFetching: isLoading, isError: Boolean(error), lastUpdatedAtMs, delegations, pendingDelegations: [], totalDelegations, totalRewards, totalDelegationsAndRewards, refresh, addDelegation, undelegate, undelegateVesting, }), [ isLoading, error, delegations, totalDelegations, totalRewards, totalDelegationsAndRewards, lastUpdatedAtMs, refresh, addDelegation, undelegate, undelegateVesting, delegationItemErrors, trigger, ], ); return {children}; };