@talismn/balances-react 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,36 @@
1
+ # @talismn/balances-react
2
+
3
+ ## 0.1.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Fixed publish config
8
+ - Updated dependencies
9
+ - @talismn/balances@0.1.1
10
+ - @talismn/balances-evm-erc20@0.1.1
11
+ - @talismn/balances-evm-native@0.1.1
12
+ - @talismn/balances-example@0.1.1
13
+ - @talismn/balances-substrate-native@0.1.1
14
+ - @talismn/balances-substrate-orml@0.1.1
15
+ - @talismn/chain-connector@0.1.1
16
+ - @talismn/chaindata-provider@0.1.1
17
+ - @talismn/chaindata-provider-extension@0.1.1
18
+
19
+ ## 0.1.0
20
+
21
+ ### Minor Changes
22
+
23
+ - 43c1a3a: Initial release
24
+
25
+ ### Patch Changes
26
+
27
+ - Updated dependencies [43c1a3a]
28
+ - @talismn/balances@0.1.0
29
+ - @talismn/balances-evm-erc20@0.1.0
30
+ - @talismn/balances-evm-native@0.1.0
31
+ - @talismn/balances-example@0.1.0
32
+ - @talismn/balances-substrate-native@0.1.0
33
+ - @talismn/balances-substrate-orml@0.1.0
34
+ - @talismn/chain-connector@0.1.0
35
+ - @talismn/chaindata-provider@0.1.0
36
+ - @talismn/chaindata-provider-extension@0.1.0
package/README.md ADDED
@@ -0,0 +1 @@
1
+ # @talismn/balances-react
@@ -0,0 +1,2 @@
1
+ export * from "./useBalances";
2
+ export * from "./useChaindata";
@@ -0,0 +1,2 @@
1
+ export * from "./useBalances";
2
+ export * from "./useChaindata";
@@ -0,0 +1,8 @@
1
+ import { AddressesByToken, BalanceJson, BalanceModule, Balances } from "@talismn/balances";
2
+ import { ChaindataProvider, Token } from "@talismn/chaindata-provider";
3
+ import { Dexie } from "dexie";
4
+ export declare function useBalances(balanceModules: Array<BalanceModule<any, any, any, any>>, chaindataProvider: ChaindataProvider | null, addressesByToken: AddressesByToken<Token> | null): Balances | undefined;
5
+ export declare class BalancesDatabase extends Dexie {
6
+ balances: Dexie.Table<BalanceJson, string>;
7
+ constructor();
8
+ }
@@ -0,0 +1,77 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { Balances, balances as balancesFn, } from "@talismn/balances";
11
+ import { ChainConnector } from "@talismn/chain-connector";
12
+ import { Dexie } from "dexie";
13
+ import { useLiveQuery } from "dexie-react-hooks";
14
+ import { useEffect, useState } from "react";
15
+ import { useDebounce } from "react-use";
16
+ import log from "../log";
17
+ import { useChains, useEvmNetworks, useTokens } from "./useChaindata";
18
+ export function useBalances(
19
+ // TODO: Make this array of BalanceModules more type-safe
20
+ balanceModules, chaindataProvider, addressesByToken) {
21
+ const chainConnector = useChainConnector(chaindataProvider);
22
+ useEffect(() => {
23
+ if (chainConnector === null)
24
+ return;
25
+ if (chaindataProvider === null)
26
+ return;
27
+ if (addressesByToken === null)
28
+ return;
29
+ const unsubscribePromises = balanceModules.map((balanceModule) => balancesFn(balanceModule, chainConnector, chaindataProvider, addressesByToken, (error, balances) => {
30
+ if (error)
31
+ return log.error(`Failed to fetch ${balanceModule.type} balances`, error);
32
+ if (!balances)
33
+ return;
34
+ db.transaction("rw", db.balances, () => __awaiter(this, void 0, void 0, function* () {
35
+ yield db.balances.bulkPut(Object.entries(balances.toJSON()).map(([id, balance]) => (Object.assign({ id }, balance))));
36
+ }));
37
+ }));
38
+ // TODO: Set balances status to cache on unmount
39
+ return () => {
40
+ unsubscribePromises.forEach((unsubscribePromise) => unsubscribePromise.then((unsub) => unsub()));
41
+ };
42
+ }, [addressesByToken, chainConnector]);
43
+ const chains = useChains(chaindataProvider);
44
+ const evmNetworks = useEvmNetworks(chaindataProvider);
45
+ const tokens = useTokens(chaindataProvider);
46
+ const balances = useLiveQuery(() => __awaiter(this, void 0, void 0, function* () { return new Balances(yield db.balances.toArray(), { chains, evmNetworks, tokens }); }), [chains, evmNetworks, tokens]);
47
+ // debounce every 100ms to prevent hammering UI with updates
48
+ const [debouncedBalances, setDebouncedBalances] = useState(balances);
49
+ useDebounce(() => balances && setDebouncedBalances(balances), 100, [balances]);
50
+ return debouncedBalances;
51
+ }
52
+ // TODO: Allow advanced users of this library to provide their own chain connector
53
+ function useChainConnector(chaindataProvider) {
54
+ const [chainConnector, setChainConnector] = useState(null);
55
+ useEffect(() => {
56
+ if (chaindataProvider === null)
57
+ return;
58
+ setChainConnector(new ChainConnector(chaindataProvider));
59
+ }, [chaindataProvider]);
60
+ return chainConnector;
61
+ }
62
+ export class BalancesDatabase extends Dexie {
63
+ constructor() {
64
+ super("Balances");
65
+ // https://dexie.org/docs/Tutorial/Design#database-versioning
66
+ this.version(1).stores({
67
+ // You only need to specify properties that you wish to index.
68
+ // The object store will allow any properties on your stored objects but you can only query them by indexed properties
69
+ // https://dexie.org/docs/API-Reference#declare-database
70
+ //
71
+ // Never index properties containing images, movies or large (huge) strings. Store them in IndexedDB, yes! but just don’t index them!
72
+ // https://dexie.org/docs/Version/Version.stores()#warning
73
+ balances: "id, source, status, address, tokenId",
74
+ });
75
+ }
76
+ }
77
+ const db = new BalancesDatabase();
@@ -0,0 +1,22 @@
1
+ import { Chain, ChainId, ChainList, ChaindataProvider, EvmNetwork, EvmNetworkId, EvmNetworkList, Token, TokenId, TokenList } from "@talismn/chaindata-provider";
2
+ export declare function useChaindata(): (ChaindataProvider & {
3
+ generation?: number | undefined;
4
+ }) | null;
5
+ export declare function useChains(chaindata: (ChaindataProvider & {
6
+ generation?: number;
7
+ }) | null): ChainList;
8
+ export declare function useChain(chaindata: (ChaindataProvider & {
9
+ generation?: number;
10
+ }) | null, chainId?: ChainId): Chain | null | undefined;
11
+ export declare function useEvmNetworks(chaindata: (ChaindataProvider & {
12
+ generation?: number;
13
+ }) | null): EvmNetworkList;
14
+ export declare function useEvmNetwork(chaindata: (ChaindataProvider & {
15
+ generation?: number;
16
+ }) | null, evmNetworkId?: EvmNetworkId): EvmNetwork | null | undefined;
17
+ export declare function useTokens(chaindata: (ChaindataProvider & {
18
+ generation?: number;
19
+ }) | null): TokenList;
20
+ export declare function useToken(chaindata: (ChaindataProvider & {
21
+ generation?: number;
22
+ }) | null, tokenId?: TokenId): Token | null | undefined;
@@ -0,0 +1,120 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { ChaindataProviderExtension } from "@talismn/chaindata-provider-extension";
11
+ import { useEffect, useState } from "react";
12
+ import log from "../log";
13
+ export function useChaindata() {
14
+ const [chaindataProvider, setChaindataProvider] = useState(null);
15
+ // this number is incremented each time the chaindataProvider has fetched new data
16
+ const [generation, setGeneration] = useState(0);
17
+ useEffect(() => {
18
+ const chaindataProvider = new ChaindataProviderExtension();
19
+ let shouldHydrate = true;
20
+ const timer = 300000; // 300_000ms = 300s = 5 minutes
21
+ const hydrate = () => __awaiter(this, void 0, void 0, function* () {
22
+ if (!shouldHydrate)
23
+ return;
24
+ try {
25
+ const updated = yield chaindataProvider.hydrate();
26
+ if (updated)
27
+ setGeneration((generation) => (generation + 1) % Number.MAX_SAFE_INTEGER);
28
+ setTimeout(hydrate, timer);
29
+ }
30
+ catch (error) {
31
+ const retryTimeout = 5000; // 5_000ms = 5 seconds
32
+ log.error(`Failed to fetch chaindata, retrying in ${Math.round(retryTimeout / 1000)} seconds`, error);
33
+ setTimeout(hydrate, retryTimeout);
34
+ }
35
+ });
36
+ setChaindataProvider(chaindataProvider);
37
+ hydrate();
38
+ return () => {
39
+ shouldHydrate = false;
40
+ };
41
+ }, []);
42
+ if (chaindataProvider)
43
+ chaindataProvider.generation = generation;
44
+ return chaindataProvider;
45
+ }
46
+ export function useChains(chaindata) {
47
+ const [chains, setChains] = useState();
48
+ useEffect(() => {
49
+ if (!chaindata)
50
+ return;
51
+ const thisGeneration = chaindata.generation;
52
+ chaindata.chains().then((chains) => {
53
+ if (thisGeneration !== chaindata.generation)
54
+ return;
55
+ setChains(chains);
56
+ });
57
+ }, [chaindata === null || chaindata === void 0 ? void 0 : chaindata.generation]);
58
+ return chains || {};
59
+ }
60
+ export function useChain(chaindata, chainId) {
61
+ const [chain, setChain] = useState();
62
+ useEffect(() => {
63
+ if (chaindata === null)
64
+ return;
65
+ if (!chainId)
66
+ return;
67
+ chaindata.getChain(chainId).then(setChain);
68
+ }, [chaindata === null || chaindata === void 0 ? void 0 : chaindata.generation]);
69
+ return chain;
70
+ }
71
+ export function useEvmNetworks(chaindata) {
72
+ const [evmNetworks, setEvmNetworks] = useState();
73
+ useEffect(() => {
74
+ if (!chaindata)
75
+ return;
76
+ const thisGeneration = chaindata.generation;
77
+ chaindata.evmNetworks().then((evmNetworks) => {
78
+ if (thisGeneration !== chaindata.generation)
79
+ return;
80
+ setEvmNetworks(evmNetworks);
81
+ });
82
+ }, [chaindata === null || chaindata === void 0 ? void 0 : chaindata.generation]);
83
+ return evmNetworks || {};
84
+ }
85
+ export function useEvmNetwork(chaindata, evmNetworkId) {
86
+ const [evmNetwork, setEvmNetwork] = useState();
87
+ useEffect(() => {
88
+ if (chaindata === null)
89
+ return;
90
+ if (!evmNetworkId)
91
+ return;
92
+ chaindata.getEvmNetwork(evmNetworkId).then(setEvmNetwork);
93
+ }, [chaindata === null || chaindata === void 0 ? void 0 : chaindata.generation]);
94
+ return evmNetwork;
95
+ }
96
+ export function useTokens(chaindata) {
97
+ const [tokens, setTokens] = useState();
98
+ useEffect(() => {
99
+ if (!chaindata)
100
+ return;
101
+ const thisGeneration = chaindata.generation;
102
+ chaindata.tokens().then((tokens) => {
103
+ if (thisGeneration !== chaindata.generation)
104
+ return;
105
+ setTokens(tokens);
106
+ });
107
+ }, [chaindata === null || chaindata === void 0 ? void 0 : chaindata.generation]);
108
+ return tokens || {};
109
+ }
110
+ export function useToken(chaindata, tokenId) {
111
+ const [token, setToken] = useState();
112
+ useEffect(() => {
113
+ if (chaindata === null)
114
+ return;
115
+ if (!tokenId)
116
+ return;
117
+ chaindata.getToken(tokenId).then(setToken);
118
+ }, [chaindata === null || chaindata === void 0 ? void 0 : chaindata.generation]);
119
+ return token;
120
+ }
@@ -0,0 +1 @@
1
+ export * from "./hooks";
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export * from "./hooks";
package/dist/log.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ declare const _default: import("anylogger").Logger<import("anylogger").BaseLevels>;
2
+ export default _default;
package/dist/log.js ADDED
@@ -0,0 +1,5 @@
1
+ import anylogger from "anylogger";
2
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
3
+ const { name } = require("../package.json");
4
+ // import { name } from "../package.json"
5
+ export default anylogger(name);
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "@talismn/balances-react",
3
+ "version": "0.1.1",
4
+ "author": "Talisman",
5
+ "homepage": "https://talisman.xyz",
6
+ "license": "UNLICENSED",
7
+ "publishConfig": {
8
+ "access": "public"
9
+ },
10
+ "repository": {
11
+ "directory": "packages/balances-react",
12
+ "type": "git",
13
+ "url": "https://github.com/talismansociety/talisman.git"
14
+ },
15
+ "main": "dist/index.js",
16
+ "types": "dist/index.d.ts",
17
+ "files": [
18
+ "/dist"
19
+ ],
20
+ "engines": {
21
+ "node": ">=14"
22
+ },
23
+ "scripts": {
24
+ "dev": "tsc --watch --declarationMap",
25
+ "build": "tsc --declarationMap",
26
+ "build:packages:prod": "rm -rf dist && tsc",
27
+ "prepack": "yarn build:packages:prod",
28
+ "test": "jest",
29
+ "lint": "eslint . --max-warnings 0",
30
+ "clean": "rm -rf dist && rm -rf .turbo rm -rf node_modules"
31
+ },
32
+ "dependencies": {
33
+ "@talismn/balances": "^0.1.1",
34
+ "@talismn/balances-evm-erc20": "^0.1.1",
35
+ "@talismn/balances-evm-native": "^0.1.1",
36
+ "@talismn/balances-example": "^0.1.1",
37
+ "@talismn/balances-substrate-native": "^0.1.1",
38
+ "@talismn/balances-substrate-orml": "^0.1.1",
39
+ "@talismn/chain-connector": "^0.1.1",
40
+ "@talismn/chaindata-provider": "^0.1.1",
41
+ "@talismn/chaindata-provider-extension": "^0.1.1",
42
+ "anylogger": "^1.0.11",
43
+ "dexie": "^3.2.2",
44
+ "dexie-react-hooks": "^1.1.1",
45
+ "react-use": "^17.4.0"
46
+ },
47
+ "devDependencies": {
48
+ "@talismn/eslint-config": "^0.0.0",
49
+ "@talismn/tsconfig": "^0.0.0",
50
+ "@types/jest": "^27.5.1",
51
+ "@types/react": "^18.0.17",
52
+ "eslint": "^8.4.0",
53
+ "jest": "^28.1.0",
54
+ "react": "^18.2.0",
55
+ "ts-jest": "^28.0.2",
56
+ "typescript": "^4.6.4"
57
+ },
58
+ "peerDependencies": {
59
+ "react": "*",
60
+ "react-dom": "*"
61
+ },
62
+ "eslintConfig": {
63
+ "root": true,
64
+ "extends": [
65
+ "@talismn/eslint-config"
66
+ ]
67
+ }
68
+ }