Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: operations refactoring #2772

Open
wants to merge 56 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 45 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
edff5ec
refactor: rearrange of wallet select feature, removed some modules co…
johnthecat Nov 6, 2024
89b05f2
Merge branch 'dev' into feat/flexible-multisig
johnthecat Nov 7, 2024
ab16ebc
feat: proxy pallet (#2590)
johnthecat Nov 7, 2024
e468428
Merge branch 'dev' into feat/flexible-multisig
johnthecat Nov 8, 2024
7751986
fix: after merge
johnthecat Nov 8, 2024
93f31e7
feat: changed proxy type from enum to string union (#2620)
johnthecat Nov 11, 2024
5e7bf9e
feat: select multisig flow (#2577)
sokolova-an Nov 12, 2024
600e663
Merge branch 'dev' into feat/flexible-multisig
johnthecat Nov 12, 2024
e2d82f7
Merge dev into feat/flexible-multisig
johnthecat Nov 12, 2024
aec30e4
fix: wallet card layout
johnthecat Nov 12, 2024
f683a39
feat: add flexible multisig wallet and account types (#2636)
johnthecat Nov 12, 2024
85c7d84
Merge branch 'dev' into feat/flexible-multisig
johnthecat Nov 13, 2024
eb6f21e
Merge branch 'dev' into feat/flexible-multisig
johnthecat Nov 13, 2024
37925ea
Feat: Input refactoring (#2592)
tuul-wq Nov 14, 2024
4980dcc
Merge dev into feat/flexible-multisig
johnthecat Nov 14, 2024
0b8cc72
Merge dev into feat/flexible-multisig
johnthecat Nov 15, 2024
fa2b071
Merge branch 'dev' into feat/flexible-multisig
johnthecat Nov 15, 2024
6749c67
Fix: Multisig select (#2626)
tuul-wq Nov 15, 2024
2c3f5f7
Fix: Multisig single chain view (#2649)
tuul-wq Nov 15, 2024
cdf8a1b
chore: merge dev
tuul-wq Nov 18, 2024
8554f51
chore: merge dev
tuul-wq Nov 18, 2024
55ba8e7
Merge branch 'dev' into feat/flexible-multisig
johnthecat Nov 18, 2024
c19d200
Merge dev into feat/flexible-multisig
johnthecat Nov 19, 2024
8da82dd
feat: flexible multisig discovery (#2635)
johnthecat Nov 19, 2024
16aed7e
feat: add batch transaction for flexible multisig (#2672)
sokolova-an Nov 20, 2024
17ce551
Merge branch 'dev' into feat/flexible-multisig
johnthecat Nov 20, 2024
560271f
Merge dev into feat/flexible-multisig
johnthecat Nov 20, 2024
9ae460f
Merge branch 'dev' into feat/flexible-multisig
johnthecat Nov 21, 2024
9ec514c
feat: update types and checks for multisigs (#2693)
sokolova-an Nov 21, 2024
458a35d
feat: add existential deposit (#2706)
sokolova-an Nov 21, 2024
32b6a2e
Merge branch 'dev' into feat/flexible-multisig
johnthecat Nov 21, 2024
9f5f1e9
Merge dev into feat/flexible-multisig
johnthecat Nov 22, 2024
e707339
fix: fields
johnthecat Nov 22, 2024
dd98571
Merge branch 'dev' into feat/flexible-multisig
johnthecat Nov 22, 2024
ec82d29
fix: merge
johnthecat Nov 22, 2024
5fc7f33
Merge branch 'dev' into feat/flexible-multisig
johnthecat Nov 22, 2024
e37e903
feat: update flexible multisig (#2709)
sokolova-an Nov 22, 2024
4fc5599
Merge branch 'dev' into feat/flexible-multisig
johnthecat Nov 25, 2024
855c0ef
Merge branch 'dev' into feat/flexible-multisig
johnthecat Nov 27, 2024
b80fcc7
Merge dev into feat/flexible-multisig
johnthecat Nov 28, 2024
c22314c
Feat: new multisig operations subscription service (#2654)
Asmadek Nov 28, 2024
6206e5c
Merge dev into feat/flexible-multisig
johnthecat Dec 3, 2024
b8e393e
Merge branch 'dev' of https://github.com/nova-wallet/omni-enterprise …
Asmadek Dec 4, 2024
bff2be1
feat: add transfer details
Asmadek Dec 4, 2024
a14c63b
feat: register feature
johnthecat Dec 5, 2024
7796984
Merge branch 'dev' into feat/flexible-multisig
johnthecat Dec 6, 2024
6372bb9
feat: support proxy, governance operations
Asmadek Dec 6, 2024
14ac87a
chore: turned off flexible multisig search
johnthecat Dec 6, 2024
a546119
Merge branch 'dev' into feat/flexible-multisig
johnthecat Dec 6, 2024
fbd450f
feat: add unknown operation titile
Asmadek Dec 6, 2024
ffd863b
Merge branch 'feat/flexible-multisig' of https://github.com/nova-wall…
Asmadek Dec 6, 2024
f48b087
chore: turned off flexible multisig create flow
johnthecat Dec 6, 2024
5fc2ad9
fix: ui issues
Asmadek Dec 6, 2024
ed3ab11
chore: fix provide events to effector
Asmadek Dec 9, 2024
8531080
chore: fix comment
Asmadek Dec 9, 2024
37569ec
Merge branch 'feat/flexible-multisig' of https://github.com/nova-wall…
Asmadek Dec 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
10 changes: 9 additions & 1 deletion jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,15 @@ const config: Config = {
'^dexie$': '<rootDir>/node_modules/dexie/dist/dexie.js',
'^lottie': 'lottie-react',
},
modulePathIgnorePatterns: ['<rootDir>/tests'],
modulePathIgnorePatterns: [
'<rootDir>/tests',

// Files, excluded because of cyclic dependecies with OperationSign
'<rootDir>/src/renderer/features/proxy-add/model/__tests__/add-proxy-model.test.ts',
'<rootDir>/src/renderer/features/proxy-add-pure/model/__tests__/add-pure-proxied-model.test.ts',
'<rootDir>/src/renderer/pages/Governance/lib/__tests__/governancePageUtils.test.ts',
'<rootDir>/src/renderer/pages/Onboarding/Vault/ManageVault/model/__tests__/manage-vault-model.test.ts',
],
collectCoverageFrom: [
'src/renderer/**/*.{js,ts}',
'!src/renderer/pages/**/*.{js,ts}',
Expand Down
2 changes: 0 additions & 2 deletions src/renderer/app/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { Paths } from '@/shared/routes';
import { walletModel } from '@/entities/wallet';
import { navigationModel } from '@/features/navigation';
import { CreateWalletProvider } from '@/widgets/CreateWallet';
import { WalletDetailsProvider } from '@/widgets/WalletDetails';
import { ROUTES_CONFIG } from '@/pages/index';

import { initModel } from './modelInit';
Expand Down Expand Up @@ -39,7 +38,6 @@ export const App = () => {
<GraphqlProvider>
{appRoutes}
<CreateWalletProvider />
<WalletDetailsProvider />
</GraphqlProvider>
</StatusModalProvider>
</ConfirmDialogProvider>
Expand Down
25 changes: 22 additions & 3 deletions src/renderer/app/modelInit.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
/* eslint-disable import-x/max-dependencies */

import { kernelModel } from '@/shared/core';
import { registerFeatures } from '@/shared/effector';
import { basketModel } from '@/entities/basket';
import { governanceModel } from '@/entities/governance';
import { networkModel } from '@/entities/network';
Expand All @@ -12,13 +15,29 @@ import { contactsNavigationFeature } from '@/features/contacts-navigation';
import { fellowshipNavigationFeature } from '@/features/fellowship-navigation';
import { governanceNavigationFeature } from '@/features/governance-navigation';
import { notificationsNavigationFeature } from '@/features/notifications-navigation';
import * as operationDetails from '@/features/operation-details';
import { operationsNavigationFeature } from '@/features/operations-navigation';
import { proxiesModel } from '@/features/proxies';
import { settingsNavigationFeature } from '@/features/settings-navigation';
import { stakingNavigationFeature } from '@/features/staking-navigation';
import { walletsSelectFeature } from '@/features/wallets-select';
import { walletSelectFeature } from '@/features/wallet-select';

export const initModel = () => {
registerFeatures([
assetsNavigationFeature,
stakingNavigationFeature,
governanceNavigationFeature,
fellowshipNavigationFeature,
operationsNavigationFeature,
contactsNavigationFeature,
notificationsNavigationFeature,
settingsNavigationFeature,
walletSelectFeature.feature,
operationDetails.transferOperationDetailFeature,
operationDetails.bondOperationDetailFeature,
operationDetails.walletOperationDetailsFeature,
]);

assetsNavigationFeature.start();
stakingNavigationFeature.start();
governanceNavigationFeature.start();
Expand All @@ -28,7 +47,7 @@ export const initModel = () => {
notificationsNavigationFeature.start();
settingsNavigationFeature.start();

walletsSelectFeature.start();
walletSelectFeature.feature.start();

kernelModel.events.appStarted();
governanceModel.events.governanceStarted();
Expand All @@ -39,5 +58,5 @@ export const initModel = () => {
assetsSettingsModel.events.assetsStarted();
notificationModel.events.notificationsStarted();
basketModel.events.basketStarted();
multisigsModel.events.multisigsDiscoveryStarted();
multisigsModel.events.subscribe();
};
12 changes: 6 additions & 6 deletions src/renderer/domains/collectives/model/members/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,17 @@ const {
} = createDataSubscription<CollectivesStruct<(Member | CoreMember)[]>, RequestParams, (Member | CoreMember)[]>({
initial: {},
fn: ({ api, palletType }, callback) => {
let currentAbortController = new AbortController();
let abortController = new AbortController();

const fn = async () => {
currentAbortController.abort();
currentAbortController = new AbortController();
abortController.abort();
abortController = new AbortController();

const collectiveMembers = await collectivePallet.storage.members(palletType, api);
if (currentAbortController.signal.aborted) return;
if (abortController.signal.aborted) return;

const coreMembers = await collectiveCorePallet.storage.member(palletType, api);
if (currentAbortController.signal.aborted) return;
if (abortController.signal.aborted) return;

const result: Member[] = [];

Expand Down Expand Up @@ -71,7 +71,7 @@ const {

// TODO check if section name is correct
return polkadotjsHelpers.subscribeSystemEvents({ api, section: `${palletType}Core` }, fn).then(fn => () => {
currentAbortController.abort();
abortController.abort();
fn();
});
},
Expand Down
12 changes: 6 additions & 6 deletions src/renderer/domains/collectives/model/referendum/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,19 @@ const { pending, subscribe, unsubscribe, received, fulfilled } = createDataSubsc
>({
initial: $list,
fn: ({ api, palletType }, callback) => {
let currectAbortController = new AbortController();
let abortController = new AbortController();

const fetchPages = createPagesHandler({
fn: () => referendaPallet.storage.referendumInfoForPaged(palletType, api, 200),
map: mapReferendums,
});

fetchPages(currectAbortController, callback);
fetchPages(abortController, callback);

const fn = () => {
currectAbortController.abort();
currectAbortController = new AbortController();
fetchPages(currectAbortController, callback);
abortController.abort();
abortController = new AbortController();
fetchPages(abortController, callback);
};

/**
Expand All @@ -47,7 +47,7 @@ const { pending, subscribe, unsubscribe, received, fulfilled } = createDataSubsc
* @see https://github.com/paritytech/polkadot-sdk/blob/43cd6fd4370d3043272f64a79aeb9e6dc0edd13f/substrate/frame/collective/src/lib.rs#L459
*/
return polkadotjsHelpers.subscribeSystemEvents({ api, section: `${palletType}Referenda` }, fn).then(fn => () => {
currectAbortController.abort();
abortController.abort();
fn();
});
},
Expand Down
7 changes: 7 additions & 0 deletions src/renderer/domains/multisig/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { multisigsDomainModel } from './model/multisigs/model';

export const multisigDomain = {
multisigs: multisigsDomainModel,
};

export type { Multisig } from './model/multisigs/types';
6 changes: 6 additions & 0 deletions src/renderer/domains/multisig/model/multisigs/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const MultisigEventFieldIndex = {
ACCOUNT_ID: 0,
TIMEPOINT: 1,
MULTISIG: 2,
CALL_HASH: 3,
};
153 changes: 153 additions & 0 deletions src/renderer/domains/multisig/model/multisigs/model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import { type ApiPromise } from '@polkadot/api';
import { type Event } from '@polkadot/types/interfaces/system';
import { createStore } from 'effector';
import { cloneDeep } from 'lodash';

import { type CallHash, type ChainId, type HexString } from '@/shared/core';
import { createDataSource, createDataSubscription } from '@/shared/effector';
import { nullable, setNestedValue } from '@/shared/lib/utils';
import { multisigPallet } from '@/shared/pallet/multisig';
import { polkadotjsHelpers } from '@/shared/polkadotjs-helpers';
import { type AccountId } from '@/shared/polkadotjs-schemas';

import { MultisigEventFieldIndex } from './constants';
import { multisigOperationService } from './service';
import { type Multisig, type MultisigEvent } from './types';

type Store = Record<ChainId, Record<AccountId, Multisig[]>>;

type RequestParams = {
accountId: AccountId;
api: ApiPromise;
};

const $multisigOperations = createStore<Store>({});

const { request } = createDataSource<Store, RequestParams[], Record<ChainId, Multisig[]>>({
initial: $multisigOperations,
async fn(inputs) {
const result: Record<ChainId, Multisig[]> = {};

for (const { api, accountId } of inputs) {
const response = await multisigPallet.storage.multisigs(api, accountId);
const chainId = api.genesisHash.toHex();

for (const multisig of response) {
if (nullable(multisig.multisig)) continue;
result[chainId] = result[chainId] || [];

result[chainId].push({
status: 'pending',
accountId: multisig.key.accountId,
callHash: multisig.key.callHash as HexString,
depositor: multisig.multisig.depositor,
events: multisig.multisig.approvals.map(accountId => ({
accountId,
status: 'approved',
blockCreated: multisig.multisig!.when.height,
indexCreated: multisig.multisig!.when.index,
})),
blockCreated: multisig.multisig.when.height,
indexCreated: multisig.multisig.when.index,
deposit: multisig.multisig.deposit,
});
}
}

return result;
},
map(store, { params, result }) {
let newStore = {};

for (const { api, accountId } of params) {
const chainId = api.genesisHash.toHex();
const oldOperations = store[chainId]?.[accountId] || [];
const newOperations = result[chainId] || [];
const multisigOperations = multisigOperationService.mergeMultisigOperations(oldOperations, newOperations);

newStore = setNestedValue(store, chainId, accountId, multisigOperations);
}

return newStore;
},
});

const { subscribe, unsubscribe } = createDataSubscription<
Store,
RequestParams[],
{ callHash: CallHash; multisigId: AccountId; chainId: ChainId } & MultisigEvent
>({
initial: $multisigOperations,
fn: (params, callback) => {
const unsubscribeFns: Promise<void | VoidFunction>[] = [];

for (const { accountId, api } of params) {
const subscribeEventCallback = (event: Event) => {
if (event.data[MultisigEventFieldIndex.MULTISIG]?.toHex() !== accountId) return;

const blockCreated = (event.data[MultisigEventFieldIndex.TIMEPOINT] as any).height.toNumber();

Check warning on line 88 in src/renderer/domains/multisig/model/multisigs/model.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type
const indexCreated = (event.data[MultisigEventFieldIndex.TIMEPOINT] as any).index.toNumber();

Check warning on line 89 in src/renderer/domains/multisig/model/multisigs/model.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type

callback({
done: true,
value: {
multisigId: accountId,
chainId: api.genesisHash.toHex(),
callHash: event.data[MultisigEventFieldIndex.CALL_HASH]!.toHex(),
accountId: event.data[MultisigEventFieldIndex.ACCOUNT_ID]!.toHex() as AccountId,
status: event.method === 'MultisigCancelled' ? 'rejected' : 'approved',
indexCreated,
blockCreated,
},
});
};

const unsubscribeFn = polkadotjsHelpers
.subscribeSystemEvents(
{
api,
section: `multisig`,
// TODO: add NewMultisig event
methods: ['MultisigApproval', 'MultisigExecuted', 'MultisigCancelled'],
},
subscribeEventCallback,
)
.then(unsubscribe => unsubscribe());

unsubscribeFns.push(unsubscribeFn);
}

return () => {
Promise.all(unsubscribeFns);
};
},
map: (store, { result: { callHash, multisigId, chainId, ...event } }) => {
const newStore = cloneDeep(store);

if (!newStore[chainId]) {
newStore[chainId] = {};
}

if (!newStore[chainId][multisigId]) {
newStore[chainId][multisigId] = [];
}

const multisig = newStore[chainId][multisigId].find(
multisig => multisig.callHash === callHash && multisig.status === 'pending',
);

if (multisig) {
multisig.events = multisigOperationService.mergeEvents(multisig.events, [event]);
}

return newStore;
},
});

export const multisigsDomainModel = {
$multisigOperations,

request,
subscribe,
unsubscribe,
};
47 changes: 47 additions & 0 deletions src/renderer/domains/multisig/model/multisigs/service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { cloneDeep } from 'lodash';

import { type Multisig, type MultisigEvent } from './types';

export const multisigOperationService = {
isSameMultisig,
isSameEvent,
mergeEvents,
mergeMultisigOperations,
};

function isSameMultisig(a: Multisig, b: Multisig) {
const isSameCallHash = a.callHash === b.callHash;
const isSameTimepoint = a.blockCreated === b.blockCreated && a.indexCreated === b.indexCreated;
const isSameAccount = a.accountId === b.accountId;

return isSameCallHash && isSameTimepoint && isSameAccount;
}

function isSameEvent(a: MultisigEvent, b: MultisigEvent) {
const isSameAccount = a.accountId === b.accountId;
const isSameTimepoint = a.blockCreated === b.blockCreated && a.indexCreated === b.indexCreated;

return isSameAccount && isSameTimepoint;
}

function mergeEvents(oldEvents: MultisigEvent[], events: MultisigEvent[]) {
const newEvents = events.filter(e => !oldEvents.some(o => isSameEvent(o, e)));

return [...oldEvents, ...newEvents];
}

function mergeMultisigOperations(oldMultisigs: Multisig[], newMultisigs: Multisig[]): Multisig[] {
const result = cloneDeep(oldMultisigs);

for (const newMultisig of newMultisigs) {
const oldMultisig = result.find(m => isSameMultisig(m, newMultisig));

if (oldMultisig) {
oldMultisig.events = mergeEvents(oldMultisig.events, newMultisig.events);
} else {
result.push(newMultisig);
}
}

return result;
}
Loading
Loading