Skip to content

Commit

Permalink
feat: operations model in multisig domain (#2879)
Browse files Browse the repository at this point in the history
  • Loading branch information
johnthecat authored Dec 19, 2024
1 parent bdda454 commit 25d96b1
Show file tree
Hide file tree
Showing 14 changed files with 349 additions and 256 deletions.
9 changes: 6 additions & 3 deletions src/renderer/domains/multisig/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { multisigsDomainModel } from './model/multisigs/model';
import { operationsDomainModel } from './model/operations/model';
import { operationsService } from './model/operations/service';

export const multisigDomain = {
multisigs: multisigsDomainModel,
operations: operationsDomainModel,

operationsService,
};

export type { Multisig } from './model/multisigs/types';
export type { MultisigOperation, MultisigEvent } from './model/operations/types';
153 changes: 0 additions & 153 deletions src/renderer/domains/multisig/model/multisigs/model.ts

This file was deleted.

47 changes: 0 additions & 47 deletions src/renderer/domains/multisig/model/multisigs/service.ts

This file was deleted.

154 changes: 154 additions & 0 deletions src/renderer/domains/multisig/model/operations/model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import { type ApiPromise } from '@polkadot/api';
import { combine, createStore } from 'effector';
import { spread } from 'patronum';

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

import { multisigEvent } from './schema';
import { operationsService } from './service';
import { type MultisigEvent, type MultisigOperation } from './types';

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

const $operations = createStore<Record<ChainId, MultisigOperation[]>>({});
const $events = createStore<Record<ChainId, MultisigEvent[]>>({});

const { request: requestOperations } = createDataSource({
source: combine({ operations: $operations, events: $events }),
target: spread({ operations: $operations, events: $events }),
async fn({ api, accountId }: RequestParams) {
const operations: MultisigOperation[] = [];
let events: MultisigEvent[] = [];

const response = await multisigPallet.storage.multisigs(api, accountId);
const chainId = api.genesisHash.toHex();

for (const { key, multisig } of response) {
if (nullable(multisig)) continue;

operations.push({
chainId,
status: 'pending',
accountId: key.accountId,
callHash: key.callHash,
depositor: multisig.depositor,
blockCreated: multisig.when.height,
indexCreated: multisig.when.index,
deposit: multisig.deposit,
});

events = events.concat(
multisig.approvals.map(accountId => ({
chainId,
accountId,
status: 'approved',
callHash: key.callHash,
blockCreated: multisig.when.height,
indexCreated: multisig.when.index,
})),
);
}

return { operations, events };
},
map({ operations, events }, { params: { api }, result }) {
const chainId = api.genesisHash.toHex();

const oldOperations = operations[chainId] ?? [];
const newOperations = operationsService.mergeMultisigOperations(oldOperations, result.operations);

const oldEvents = events[chainId] ?? [];
const newEvents = operationsService.mergeEvents(oldEvents, result.events);

return {
operations: {
...operations,
[chainId]: newOperations,
},
events: {
...events,
[chainId]: newEvents,
},
};
},
});

const { subscribe: subscribeEvents, unsubscribe: unsubscribeEvents } = createDataSubscription<
Record<ChainId, MultisigEvent[]>,
RequestParams[],
{ event: MultisigEvent; chainId: ChainId }
>({
initial: $events,
fn: (params, callback) => {
const unsubscribeFns: Promise<VoidFunction>[] = [];

for (const { accountId, api } of params) {
const chainId = api.genesisHash.toHex();

const unsubscribeFn = polkadotjsHelpers.subscribeSystemEvents(
{
api,
section: 'multisig',
// TODO support 'NewMultisig' event
methods: ['MultisigApproval', 'MultisigExecuted', 'MultisigCancelled'],
},
event => {
const data = multisigEvent.parse(event.data);

if (data.multisig !== accountId) return;

callback({
done: true,
value: {
chainId: api.genesisHash.toHex(),
event: {
chainId,
accountId: data.account,
status: event.method === 'MultisigCancelled' ? 'rejected' : 'approved',
callHash: data.callHash,
indexCreated: data.timepoint.index,
blockCreated: data.timepoint.height,
},
},
});
},
);

unsubscribeFns.push(unsubscribeFn);
}

return () => {
Promise.all(unsubscribeFns).then(fns => {
for (const fn of fns) {
fn();
}
});
};
},
map: (store, { result: { chainId, event } }) => {
const oldEvents = store[chainId] ?? [];
const newEvents = operationsService.mergeEvents(oldEvents, [event]);

return {
...store,
[chainId]: newEvents,
};
},
});

export const operationsDomainModel = {
$operations,
$events,

requestOperations,
subscribeEvents,
unsubscribeEvents,
};
12 changes: 12 additions & 0 deletions src/renderer/domains/multisig/model/operations/schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { type z } from 'zod';

import { multisigPallet } from '@/shared/pallet/multisig';
import { pjsSchema } from '@/shared/polkadotjs-schemas';

export type MultisigEvent = z.infer<typeof multisigEvent>;
export const multisigEvent = pjsSchema.tupleMap(
['account', pjsSchema.accountId],
['timepoint', multisigPallet.schema.multisigTimepoint],
['multisig', pjsSchema.accountId],
['callHash', pjsSchema.hex],
);
Loading

0 comments on commit 25d96b1

Please sign in to comment.