Use contributions derive (#5792)

* Use contributions derive

* Lint fixes

* Refresh own funds on events

* Bump
This commit is contained in:
Jaco 2021-07-08 12:13:34 +03:00 committed by GitHub
parent ead297d655
commit df798fac83
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 87 additions and 240 deletions

View File

@ -12,13 +12,13 @@
"packages/*"
],
"resolutions": {
"@polkadot/api": "^4.17.2-12",
"@polkadot/api-contract": "^4.17.2-12",
"@polkadot/api": "^4.17.2-14",
"@polkadot/api-contract": "^4.17.2-14",
"@polkadot/hw-ledger": "^6.11.2-10",
"@polkadot/keyring": "^6.11.2-10",
"@polkadot/networks": "^6.11.2-10",
"@polkadot/phishing": "^0.6.220",
"@polkadot/types": "^4.17.2-12",
"@polkadot/types": "^4.17.2-14",
"@polkadot/util": "^6.11.2-10",
"@polkadot/util-crypto": "^6.11.2-10",
"@polkadot/wasm-crypto": "^4.1.1",
@ -74,7 +74,7 @@
"@crustio/crust-pin": "^0.0.1",
"@pinata/sdk": "^1.1.23",
"@polkadot/dev": "^0.62.52",
"@polkadot/ts": "^0.4.3",
"@polkadot/ts": "^0.4.4",
"@types/bn.js": "^4.11.6",
"@types/chart.js": "^2.9.32",
"@types/file-saver": "^2.0.2",

View File

@ -6,6 +6,6 @@
"license": "Apache-2.0",
"dependencies": {
"@babel/runtime": "^7.14.6",
"@polkadot/api-contract": "^4.17.2-12"
"@polkadot/api-contract": "^4.17.2-14"
}
}

View File

@ -31,12 +31,12 @@ interface LastChange {
prevLength: number;
}
function Fund ({ bestHash, bestNumber, className, isOdd, isOngoing, leasePeriod, value: { childKey, info: { cap, depositor, end, firstPeriod, lastPeriod, raised, verifier }, isCapped, isEnded, isWinner, paraId } }: Props): React.ReactElement<Props> {
function Fund ({ bestHash, bestNumber, className, isOdd, isOngoing, leasePeriod, value: { info: { cap, depositor, end, firstPeriod, lastPeriod, raised, verifier }, isCapped, isEnded, isWinner, paraId } }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const { isAccount } = useAccounts();
const endpoints = useParaEndpoints(paraId);
const { blockHash: contribHash, contributorsHex, myAccounts, myAccountsHex, myContributions } = useContributions(paraId, childKey);
const { blockHash, contributorsHex, hasLoaded, myAccounts, myAccountsHex, myContributions } = useContributions(paraId);
const [lastChange, setLastChange] = useState<LastChange>(() => ({ prevHash: '', prevLength: 0 }));
const isDepositor = useMemo(
@ -73,10 +73,10 @@ function Fund ({ bestHash, bestNumber, className, isOdd, isOngoing, leasePeriod,
const prevLength = contributorsHex.length;
return prev.prevLength !== prevLength
? { prevHash: contribHash, prevLength }
? { prevHash: blockHash, prevLength }
: prev;
});
}, [contributorsHex, contribHash]);
}, [contributorsHex, blockHash]);
return (
<tr className={`${className || ''} ${isOdd ? 'isOdd' : 'isEven'}`}>
@ -132,7 +132,7 @@ function Fund ({ bestHash, bestNumber, className, isOdd, isOngoing, leasePeriod,
)}
</td>
<td className='number together media--1100'>
{contribHash === '-'
{!hasLoaded
? <Spinner noLabel />
: (
<>

View File

@ -1,195 +1,55 @@
// Copyright 2017-2021 @polkadot/app-parachains authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { ApiPromise } from '@polkadot/api';
import type { StorageKey } from '@polkadot/types';
import type { Balance, EventRecord, ParaId } from '@polkadot/types/interfaces';
import type { DeriveContributions, DeriveOwnContributions } from '@polkadot/api-derive/types';
import type { Balance, ParaId } from '@polkadot/types/interfaces';
import { useCallback, useEffect, useState } from 'react';
import { useEffect, useState } from 'react';
import { useAccounts, useApi, useEventTrigger, useIsMountedRef } from '@polkadot/react-hooks';
import { useAccounts, useApi, useCall } from '@polkadot/react-hooks';
import { encodeAddress } from '@polkadot/util-crypto';
interface Contributions {
contributorsHex: string[];
contributorsMap: Record<string, boolean>;
hasKeys: boolean;
interface Result extends DeriveContributions {
hasLoaded: boolean;
myAccounts: string[];
myAccountsHex: string[];
myContributions: Record<string, Balance>;
}
interface Result extends Contributions {
blockHash: string;
}
const NO_CONTRIB: Result = {
blockHash: '-',
contributorsHex: [],
contributorsMap: {},
hasKeys: false,
hasLoaded: false,
myAccounts: [],
myAccountsHex: [],
myContributions: {}
};
function extractContributors (keys: StorageKey[], { myContributions }: Contributions, allAccountsHex: string[], ss58Format?: number): Contributions {
const contributorsMap: Record<string, boolean> = {};
keys.forEach((k): void => {
contributorsMap[k.toHex()] = true;
});
const myAccountsHex = allAccountsHex.filter((h) => contributorsMap[h]);
return {
contributorsHex: Object.keys(contributorsMap),
contributorsMap,
hasKeys: true,
myAccounts: myAccountsHex.map((a) => encodeAddress(a, ss58Format)),
myAccountsHex,
myContributions
};
}
function extractDelta (api: ApiPromise, records: EventRecord[], { contributorsMap, hasKeys, myContributions }: Contributions, allAccountsHex: string[], ss58Format?: number): Contributions {
records.forEach((record): void => {
const hex = record.event.data[0].toHex();
if (api.events.crowdloan.Withdrew.is(record.event)) {
delete contributorsMap[hex];
} else {
contributorsMap[hex] = true;
}
});
const myAccountsHex = allAccountsHex.filter((h) => contributorsMap[h]);
return {
contributorsHex: Object.keys(contributorsMap),
contributorsMap,
hasKeys,
myAccounts: myAccountsHex.map((a) => encodeAddress(a, ss58Format)),
myAccountsHex,
myContributions
};
}
function useMyContributions (paraId: ParaId, childKey: string, keys: string[]): Record<string, Balance> {
export default function useContributions (paraId: ParaId): Result {
const { api } = useApi();
const { allAccountsHex } = useAccounts();
const mountedRef = useIsMountedRef();
const [state, setState] = useState<Record<string, Balance>>({});
const trigger = useEventTrigger([
api.events.crowdloan.Contributed,
api.events.crowdloan.Withdrew
], useCallback(
({ event: { data: [accountId, eventParaId] } }: EventRecord) =>
eventParaId.eq(paraId) &&
allAccountsHex.some((a) => accountId.eq(a)),
[allAccountsHex, paraId]
));
const [state, setState] = useState<Result>(() => NO_CONTRIB);
const derive = useCall<DeriveContributions>(api.derive.crowdloan.contributions, [paraId]);
const myContributions = useCall<DeriveOwnContributions>(api.derive.crowdloan.ownContributions, [paraId, state.myAccountsHex]);
useEffect((): void => {
if (trigger && keys.length) {
Promise
.all(keys.map((k) => api.rpc.childstate.getStorage(childKey, k)))
.then((values) =>
mountedRef.current && setState(
values
.map((v) => api.createType('Option<StorageData>', v))
.map((o) =>
o.isSome
? api.createType('Balance', o.unwrap())
: api.createType('Balance')
)
.reduce((all, b, index) => ({ ...all, [keys[index]]: b }), {})
)
)
.catch(console.error);
} else {
setState({});
}
}, [api, childKey, keys, mountedRef, trigger]);
derive && setState((prev): Result => {
let myAccountsHex = derive.contributorsHex.filter((h) => allAccountsHex.includes(h));
let myAccounts: string[];
return state;
}
if (myAccountsHex.length === prev.myAccountsHex.length) {
myAccountsHex = prev.myAccountsHex;
myAccounts = prev.myAccounts;
} else {
myAccounts = myAccountsHex.map((a) => encodeAddress(a, api.registry.chainSS58));
}
export default function useContributions (paraId: ParaId, childKey: string): Result {
const { api } = useApi();
const { allAccountsHex } = useAccounts();
const mountedRef = useIsMountedRef();
const [state, _setState] = useState<Result>(() => NO_CONTRIB);
const myContributions = useMyContributions(paraId, childKey, state.myAccountsHex);
return { ...prev, ...derive, hasLoaded: true, myAccounts, myAccountsHex };
});
}, [api, allAccountsHex, derive]);
// these trigger a full refresh of the keys [ParaId]
const triggerAll = useEventTrigger([
api.events.crowdloan.Dissolved,
api.events.crowdloan.AllRefunded,
api.events.crowdloan.PartiallyRefunded
], useCallback(
({ event: { data: [eventParaId] } }: EventRecord) =>
eventParaId.eq(paraId),
[paraId]
));
// these trigger a delta adjustment [AccountId, ParaId, Balance]
const triggerDelta = useEventTrigger([
api.events.crowdloan.Contributed,
api.events.crowdloan.Withdrew
], useCallback(
({ event: { data: [, eventParaId] } }: EventRecord) =>
eventParaId.eq(paraId),
[paraId]
));
const setState = useCallback(
(blockHash: string, fn: (prev: Contributions) => Contributions) =>
_setState((prev) => {
const { contributorsHex, contributorsMap, hasKeys, myAccounts, myAccountsHex } = fn(prev);
return hasKeys
? {
...prev,
blockHash,
contributorsHex,
contributorsMap,
hasKeys,
...(prev.myAccounts.length === myAccounts.length
? {}
: { myAccounts, myAccountsHex }
)
}
: prev;
}),
[]
);
// first just adjust deltas
useEffect((): void => {
mountedRef.current && triggerDelta && triggerDelta.events.length &&
setState(triggerDelta.blockHash, (prev) =>
extractDelta(api, triggerDelta.events, prev, allAccountsHex, api.registry.chainSS58)
);
}, [api, allAccountsHex, mountedRef, setState, triggerDelta]);
// refreshing the whole map, all keys
useEffect((): void => {
triggerAll &&
api.rpc.childstate
.getKeys(childKey, '0x')
.then((keys) =>
mountedRef.current && setState(triggerAll.blockHash, (prev) =>
extractContributors(keys, prev, allAccountsHex, api.registry.chainSS58)
)
)
.catch(console.error);
}, [allAccountsHex, api, childKey, mountedRef, setState, triggerAll]);
// update when the contribution amounts have changed
useEffect((): void => {
_setState((prev) => ({
myContributions && setState((prev) => ({
...prev,
myContributions
}));

View File

@ -49,7 +49,6 @@ export interface Campaigns {
}
export interface Campaign extends WinnerData {
childKey: string;
info: FundInfo;
isCapped?: boolean;
isEnded?: boolean;

View File

@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
import type { Option, StorageKey } from '@polkadot/types';
import type { AccountId, BalanceOf, BlockNumber, FundInfo, ParaId, TrieIndex } from '@polkadot/types/interfaces';
import type { AccountId, BalanceOf, BlockNumber, FundInfo, ParaId } from '@polkadot/types/interfaces';
import type { ITuple } from '@polkadot/types/types';
import type { Campaign, Campaigns } from './types';
@ -10,8 +10,8 @@ import BN from 'bn.js';
import { useEffect, useState } from 'react';
import { useApi, useBestNumber, useCall, useEventTrigger, useIsMountedRef, useMapKeys } from '@polkadot/react-hooks';
import { BN_ZERO, u8aConcat, u8aToHex } from '@polkadot/util';
import { blake2AsU8a, encodeAddress } from '@polkadot/util-crypto';
import { BN_ZERO, u8aConcat } from '@polkadot/util';
import { encodeAddress } from '@polkadot/util-crypto';
import { CROWD_PREFIX } from './constants';
@ -37,17 +37,6 @@ function hasLease (paraId: ParaId, leased: ParaId[]): boolean {
return leased.some((l) => l.eq(paraId));
}
function createChildKey (trieIndex: TrieIndex): string {
return u8aToHex(
u8aConcat(
':child_storage:default:',
blake2AsU8a(
u8aConcat('crowdloan', trieIndex.toU8a())
)
)
);
}
// map into a campaign
function updateFund (bestNumber: BN, minContribution: BN, data: Campaign, leased: ParaId[]): Campaign {
data.isCapped = data.info.cap.sub(data.info.raised).lt(minContribution);
@ -129,7 +118,6 @@ const optFundMulti = {
.filter((v): v is [ParaId, FundInfo] => !!v[1])
.map(([paraId, info]): Campaign => ({
accountId: encodeAddress(createAddress(paraId)),
childKey: createChildKey(info.trieIndex),
firstSlot: info.firstPeriod,
info,
isCrowdloan: true,

View File

@ -6,7 +6,7 @@
"license": "Apache-2.0",
"dependencies": {
"@babel/runtime": "^7.14.6",
"@polkadot/api": "^4.17.2-12",
"@polkadot/api": "^4.17.2-14",
"@polkadot/extension-dapp": "^0.38.8",
"@substrate/connect": "^0.3.10",
"fflate": "^0.7.1",

View File

@ -2264,50 +2264,50 @@ __metadata:
languageName: node
linkType: hard
"@polkadot/api-contract@npm:^4.17.2-12":
version: 4.17.2-12
resolution: "@polkadot/api-contract@npm:4.17.2-12"
"@polkadot/api-contract@npm:^4.17.2-14":
version: 4.17.2-14
resolution: "@polkadot/api-contract@npm:4.17.2-14"
dependencies:
"@babel/runtime": ^7.14.6
"@polkadot/api": 4.17.2-12
"@polkadot/types": 4.17.2-12
"@polkadot/api": 4.17.2-14
"@polkadot/types": 4.17.2-14
"@polkadot/util": ^6.11.2-10
rxjs: ^7.2.0
checksum: f068a3bb42be626df618964e00564744ac881c6299d60b0cff8885ec4cbaaeeb9e5dbbda1e7c13bdd2dafe81ca4715ac922a32ea0d0ff2441c432091fdced37f
checksum: 145c3c8b32acfb2f25d0936340ad3c77368ea66e0c7473679156bdaae2296a436068185dc321ae53741ac063c09e7c1035a9eb897ca4498e3e413d5e1b440159
languageName: node
linkType: hard
"@polkadot/api-derive@npm:4.17.2-12":
version: 4.17.2-12
resolution: "@polkadot/api-derive@npm:4.17.2-12"
"@polkadot/api-derive@npm:4.17.2-14":
version: 4.17.2-14
resolution: "@polkadot/api-derive@npm:4.17.2-14"
dependencies:
"@babel/runtime": ^7.14.6
"@polkadot/api": 4.17.2-12
"@polkadot/rpc-core": 4.17.2-12
"@polkadot/types": 4.17.2-12
"@polkadot/api": 4.17.2-14
"@polkadot/rpc-core": 4.17.2-14
"@polkadot/types": 4.17.2-14
"@polkadot/util": ^6.11.2-10
"@polkadot/util-crypto": ^6.11.2-10
rxjs: ^7.2.0
checksum: c4c6251cc33f913cb21b0f24c7a4166b455e4e2b717cd8d905d2dfb79327aa059be733bb72f798227badd9efc5427a23a0b99ce1d3de5ca188ce5b6d3a49f8ee
checksum: 46b4eb46433ff627a392647a7d25788810c2f0572c1df9e5ab698cfd08c69d9fe89502d4266bb66d4ebcc05ba53356cc596912ce2692edafe7c3c722afe3ce3b
languageName: node
linkType: hard
"@polkadot/api@npm:^4.17.2-12":
version: 4.17.2-12
resolution: "@polkadot/api@npm:4.17.2-12"
"@polkadot/api@npm:^4.17.2-14":
version: 4.17.2-14
resolution: "@polkadot/api@npm:4.17.2-14"
dependencies:
"@babel/runtime": ^7.14.6
"@polkadot/api-derive": 4.17.2-12
"@polkadot/api-derive": 4.17.2-14
"@polkadot/keyring": ^6.11.2-10
"@polkadot/rpc-core": 4.17.2-12
"@polkadot/rpc-provider": 4.17.2-12
"@polkadot/types": 4.17.2-12
"@polkadot/types-known": 4.17.2-12
"@polkadot/rpc-core": 4.17.2-14
"@polkadot/rpc-provider": 4.17.2-14
"@polkadot/types": 4.17.2-14
"@polkadot/types-known": 4.17.2-14
"@polkadot/util": ^6.11.2-10
"@polkadot/util-crypto": ^6.11.2-10
eventemitter3: ^4.0.7
rxjs: ^7.2.0
checksum: 3461a2fdce26635e2685c684f53afdfd57d3952b8e32900ea7a6a5419e5f0ff1f5f36359c4461f59b58ddc4fdc1c29180f5e5a2e84bf1f2a9728e49ff24a12c4
checksum: e79c899b37f8fafebd9f723489d721474de9c40e7e24e59b24870a1cb2fa051bc88fee6118f36fb2873b5833fcd62a96b7b9e1cf11fe48b08199599aecfcac5f
languageName: node
linkType: hard
@ -2380,7 +2380,7 @@ __metadata:
resolution: "@polkadot/app-contracts@workspace:packages/page-contracts"
dependencies:
"@babel/runtime": ^7.14.6
"@polkadot/api-contract": ^4.17.2-12
"@polkadot/api-contract": ^4.17.2-14
languageName: unknown
linkType: soft
@ -2849,7 +2849,7 @@ __metadata:
resolution: "@polkadot/react-api@workspace:packages/react-api"
dependencies:
"@babel/runtime": ^7.14.6
"@polkadot/api": ^4.17.2-12
"@polkadot/api": ^4.17.2-14
"@polkadot/extension-dapp": ^0.38.8
"@substrate/connect": ^0.3.10
fflate: ^0.7.1
@ -2981,32 +2981,32 @@ __metadata:
languageName: unknown
linkType: soft
"@polkadot/rpc-core@npm:4.17.2-12":
version: 4.17.2-12
resolution: "@polkadot/rpc-core@npm:4.17.2-12"
"@polkadot/rpc-core@npm:4.17.2-14":
version: 4.17.2-14
resolution: "@polkadot/rpc-core@npm:4.17.2-14"
dependencies:
"@babel/runtime": ^7.14.6
"@polkadot/rpc-provider": 4.17.2-12
"@polkadot/types": 4.17.2-12
"@polkadot/rpc-provider": 4.17.2-14
"@polkadot/types": 4.17.2-14
"@polkadot/util": ^6.11.2-10
rxjs: ^7.2.0
checksum: aa8996f45fa5011d5edbffd9e920d86e3e42f15e1230b6eaf86394095c0ccdb53fa617060fc24eab52b5614aa50d96c764d746e37021be25811b45ac6eee97c8
checksum: 8a4647b956db1b3a5b69e85f8abb4e6436461bffb623f250ef368e0112c14b661e510d209d2748fa842dbc0b6c4529b82c6298135b15bd5f01510a1d340bee9b
languageName: node
linkType: hard
"@polkadot/rpc-provider@npm:4.17.2-12":
version: 4.17.2-12
resolution: "@polkadot/rpc-provider@npm:4.17.2-12"
"@polkadot/rpc-provider@npm:4.17.2-14":
version: 4.17.2-14
resolution: "@polkadot/rpc-provider@npm:4.17.2-14"
dependencies:
"@babel/runtime": ^7.14.6
"@polkadot/types": 4.17.2-12
"@polkadot/types": 4.17.2-14
"@polkadot/util": ^6.11.2-10
"@polkadot/util-crypto": ^6.11.2-10
"@polkadot/x-fetch": ^6.11.2-10
"@polkadot/x-global": ^6.11.2-10
"@polkadot/x-ws": ^6.11.2-10
eventemitter3: ^4.0.7
checksum: fb2168d9d4fa1136861130870a189e595376a3148db363a18bf8e677c3b04877801a26609434965707527b14c2b1dbd3682937b0135fa78b0faa4260e80acc98
checksum: 84cd7345fc061b13ee153d598e99247130f7033edce1bc6a7e4fff79c8961d5ecab2ffc988de7208a83287c51436d7340137828663870e956cc2374d2a65c217
languageName: node
linkType: hard
@ -3037,36 +3037,36 @@ __metadata:
languageName: unknown
linkType: soft
"@polkadot/ts@npm:^0.4.3":
version: 0.4.3
resolution: "@polkadot/ts@npm:0.4.3"
"@polkadot/ts@npm:^0.4.4":
version: 0.4.4
resolution: "@polkadot/ts@npm:0.4.4"
dependencies:
"@types/chrome": ^0.0.145
checksum: cf04c92473aebe13d89f7ddd7bff44ba334c7156fcc6e89ec0a1a91743149320010e3527e7ea7b224a215616d1c9e2abdc5c79c761b2654f0a4a105b1f38e80e
checksum: ef4cd0e3978b2e9e5b6ffb9d1e482c5f4ad800c7d570037df2472e9f34a07c2812b14e84ffd9272c09ae6afeb2c686b98a1baa302b5428afbd9c8140c46cca72
languageName: node
linkType: hard
"@polkadot/types-known@npm:4.17.2-12":
version: 4.17.2-12
resolution: "@polkadot/types-known@npm:4.17.2-12"
"@polkadot/types-known@npm:4.17.2-14":
version: 4.17.2-14
resolution: "@polkadot/types-known@npm:4.17.2-14"
dependencies:
"@babel/runtime": ^7.14.6
"@polkadot/networks": ^6.11.2-10
"@polkadot/types": 4.17.2-12
"@polkadot/types": 4.17.2-14
"@polkadot/util": ^6.11.2-10
checksum: 5baf9641358406cf8d3a7eee27c3685ab1baab8d528732e2d8090d002862f027b3f0f8854700adf5256f67cbb6c37019e88c3afa3525b90eb6b231d1ef4605fd
checksum: 6e0b8a2e09e2e53d0fee303b35e0284c6d9c15624aa1e68dfee4a7cbaa6307d626bce0b35b8c101a07aa552eacf85ab777bdfebceb8f783028b6fee3aaffbeb2
languageName: node
linkType: hard
"@polkadot/types@npm:^4.17.2-12":
version: 4.17.2-12
resolution: "@polkadot/types@npm:4.17.2-12"
"@polkadot/types@npm:^4.17.2-14":
version: 4.17.2-14
resolution: "@polkadot/types@npm:4.17.2-14"
dependencies:
"@babel/runtime": ^7.14.6
"@polkadot/util": ^6.11.2-10
"@polkadot/util-crypto": ^6.11.2-10
rxjs: ^7.2.0
checksum: ab49b94cb81d1da66a37b988caacacaf46f0384780cb96c4a73d5ce86a8bdc5c86cfc43f5208c7c3317cfd0d1f4ac176a97459c9665fb22adf5ffc19e24ea7e5
checksum: 3ae418ae98d5430dc08e40be31fb1305fd80fb228fa1c13e865602797c0f31f7d2bccb9beb7c91da1426bbd015b92df533371bc77cc1fe5656da069401518e72
languageName: node
linkType: hard
@ -15318,7 +15318,7 @@ __metadata:
"@crustio/crust-pin": ^0.0.1
"@pinata/sdk": ^1.1.23
"@polkadot/dev": ^0.62.52
"@polkadot/ts": ^0.4.3
"@polkadot/ts": ^0.4.4
"@types/bn.js": ^4.11.6
"@types/chart.js": ^2.9.32
"@types/file-saver": ^2.0.2