stake-ui/src/store/reducer.ts

197 lines
6.4 KiB
TypeScript

import { PublicKey } from '@solana/web3.js';
import { AccountInfo as TokenAccount } from '@solana/spl-token';
import { ProgramAccount as CommonProgramAccount } from '@project-serum/common';
import { Action, ActionType } from './actions';
import { networks, Network } from './config';
export enum BootstrapState {
NeedsBootstrap,
IsBootstrapping,
Bootstrapped,
}
export default function reducer(
state: State = initialState,
action: Action,
): State {
let newState = {
common: { ...state.common },
lockup: { ...state.lockup },
registry: { ...state.registry },
accounts: { ...state.accounts },
};
switch (action.type) {
// Common.
case ActionType.CommonAppWillBootstrap:
newState.common.bootstrapState = BootstrapState.IsBootstrapping;
newState.common.bootstrapTrigger = false;
return newState;
case ActionType.CommonAppDidBootstrap:
newState.common.bootstrapState = BootstrapState.Bootstrapped;
return newState;
case ActionType.CommonWalletSetProvider:
newState.common.walletProvider = action.item.walletProvider;
return newState;
case ActionType.CommonWalletDidConnect:
newState.common.isWalletConnected = true;
return newState;
case ActionType.CommonWalletDidDisconnect:
newState.common.isWalletConnected = false;
return newState;
case ActionType.CommonSetNetwork:
if (newState.common.network.label !== action.item.network.label) {
newState.common.network = action.item.network;
newState.common.bootstrapState = BootstrapState.NeedsBootstrap;
newState.common.shutdownTrigger = true;
const network = networks[action.item.networkKey];
newState.registry.registrar = Object.values(network.registrars)[0];
}
return newState;
case ActionType.CommonTriggerBootstrap:
newState.common.bootstrapState = BootstrapState.NeedsBootstrap;
newState.common.bootstrapTrigger = true;
return newState;
case ActionType.CommonTriggerShutdown:
newState.common.bootstrapState = BootstrapState.NeedsBootstrap;
newState.common.shutdownTrigger = true;
return newState;
case ActionType.CommonDidShutdown:
// Reset everything except network and registrar.
let s = {
...initialState,
};
s.common.network = newState.common.network;
s.registry.registrar = newState.registry.registrar;
return s;
case ActionType.CommonOwnedTokenAccountsSet:
newState.common.ownedTokenAccounts = action.item.ownedTokenAccounts;
return newState;
case ActionType.CommonOwnedTokenAccountsUpdate:
newState.common.ownedTokenAccounts = newState.common.ownedTokenAccounts.map(
programAccount => {
if (programAccount.publicKey.equals(action.item.account.publicKey)) {
return action.item.account;
} else {
return programAccount;
}
},
);
return newState;
// Lockup.
case ActionType.LockupSetVestings:
newState.lockup.vestings = action.item.vestingAccounts;
return newState;
case ActionType.LockupUpdateVesting:
newState.accounts[action.item.vesting.publicKey.toString()] =
action.item.vesting.account;
return newState;
case ActionType.LockupCreateVesting:
newState.lockup.vestings.unshift(action.item.vesting.publicKey);
newState.accounts[action.item.vesting.publicKey.toString()] =
action.item.vesting.account;
return newState;
// Registry.
case ActionType.RegistrySetMember:
// This should only be called on member creation. All other member
// member switches should route through `RegistrySetMember`.
newState.registry.member = action.item.member;
return newState;
case ActionType.RegistrySetRegistrar:
newState.registry.registrar = action.item.registrar;
newState.registry.member = action.item.member;
newState.registry.pendingWithdrawals = null;
return newState;
case ActionType.RegistrySetPendingWithdrawals:
action.item.pendingWithdrawals.forEach((pw: any) => {
newState.accounts[pw.publicKey.toString()] = pw.account;
});
newState.registry.pendingWithdrawals = action.item.pendingWithdrawals.map(
(pw: any) => pw.publicKey,
);
return newState;
case ActionType.RegistryCreatePendingWithdrawal:
newState.accounts[action.item.pendingWithdrawal.publicKey.toString()] =
action.item.pendingWithdrawal.account;
if (newState.registry.pendingWithdrawals === null) {
newState.registry.pendingWithdrawals = [];
}
newState.registry.pendingWithdrawals.unshift(
action.item.pendingWithdrawal.publicKey,
);
return newState;
case ActionType.RegistryUpdatePendingWithdrawal:
newState.accounts[action.item.pendingWithdrawal.publicKey.toString()] =
action.item.pendingWithdrawal.account;
return newState;
case ActionType.AccountAdd:
newState.accounts[action.item.account.publicKey.toString()] =
action.item.account.account;
return newState;
case ActionType.AccountUpdate:
newState.accounts[action.item.account.publicKey.toString()] =
action.item.account.account;
return newState;
default:
return newState;
}
}
export type State = {
common: CommonState;
lockup: LockupState;
registry: RegistryState;
accounts: { [pubkey: string]: any };
};
export type CommonState = {
walletProvider?: string;
isWalletConnected: boolean;
bootstrapTrigger: boolean;
bootstrapState: BootstrapState;
shutdownTrigger: boolean;
network: Network;
ownedTokenAccounts: ProgramAccount<TokenAccount>[];
};
export type LockupState = {
vestings: PublicKey[];
};
// All state associated with a single instance of a staking registrar.
export type RegistryState = {
registrar: PublicKey;
member?: PublicKey;
pendingWithdrawals: PublicKey[] | null;
};
export const initialState: State = {
common: {
bootstrapTrigger: false,
shutdownTrigger: false,
isWalletConnected: false,
walletProvider: 'https://www.sollet.io',
bootstrapState: BootstrapState.NeedsBootstrap,
network: networks.mainnet,
ownedTokenAccounts: [],
},
lockup: {
vestings: [],
},
registry: {
pendingWithdrawals: null,
registrar: networks.mainnet.registrars.srm,
},
accounts: {},
};
export type AsyncData<T> = {
isReady: boolean;
data?: T;
};
// Re-export.
export type ProgramAccount<T = any> = CommonProgramAccount<T>;