forked from polkadot-js/apps
-
Notifications
You must be signed in to change notification settings - Fork 0
/
equilibrium.ts
162 lines (133 loc) · 4.98 KB
/
equilibrium.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// Copyright 2017-2023 @polkadot/apps-config authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Observable } from 'rxjs';
import type { ApiInterfaceRx, AugmentedQuery, RxResult } from '@polkadot/api/types';
import type { AccountData, AccountId, AccountIndex, Address, Balance } from '@polkadot/types/interfaces';
import type { Codec, OverrideBundleDefinition } from '@polkadot/types/types';
import { equilibrium, equilibriumNext } from '@equilab/definitions';
import { map } from 'rxjs';
import { Enum } from '@polkadot/types';
import { BN } from '@polkadot/util';
interface SignedBalance extends Enum {
readonly isPositive: boolean;
readonly asPositive: Balance;
readonly isNegative: boolean;
readonly asNegative: Balance;
}
interface Currency extends Enum {
readonly isUnknown: boolean;
readonly isUsd: boolean;
readonly isEq: boolean;
readonly isEth: boolean;
readonly isBtc: boolean;
readonly isEos: boolean;
readonly isDot: boolean;
}
type CommonBalanceMap = ApiInterfaceRx['query']['balances']['account'];
type EqBalanceDoubleMap<T> = AugmentedQuery<
'rxjs',
(key1: AccountIndex | AccountId | Address | string, key2: T | string) => Observable<SignedBalance>,
[AccountId, Currency]
>
export const u64FromCurrency = (currency: string): number => {
const buf = Buffer.from(currency.toLowerCase());
const size = buf.length;
return buf.reduce(
(val, digit, i) => val + Math.pow(256, size - 1 - i) * digit,
0
);
};
const transformBalanceStorage = <T>(
query: EqBalanceDoubleMap<T>,
currency: string,
transform: <SB extends Enum>(data: SB) => AccountData,
currencyToAsset: (arg: string, api?: ApiInterfaceRx) => T,
api?: ApiInterfaceRx
): CommonBalanceMap => {
const arg = currencyToAsset(currency, api);
// HACK as we cannot properly transform queryMulti result, define AccountData getters on standard Enum
if (!(Enum as { hacked?: boolean }).hacked) {
(Enum as { hacked?: boolean }).hacked = true;
for (const prop of ['free', 'reserved', 'miscFrozen', 'feeFrozen'] as Array<keyof AccountData>) {
Object.defineProperty(Enum.prototype, prop, {
get () {
const accData: AccountData = transform(this as Enum);
return accData[prop];
},
set () {
// Do nothing
}
});
}
}
// Transform result if we call the func normally
const boundFunction = (account: AccountIndex | AccountId | Address | string) =>
query(account, arg).pipe(map(transform));
// Bind currency as second key for doubleMap for queryMulti
const boundCreator = (account: AccountIndex | AccountId | Address | string) =>
query.creator([account, arg]);
Object.assign(boundCreator, { ...query.creator });
return Object.assign(boundFunction, { ...query, creator: boundCreator } as unknown as CommonBalanceMap);
};
const signedBalancePredicate = (raw: Codec): raw is SignedBalance =>
['asNegative', 'asPositive', 'isNegative', 'isPositive'].some((key) =>
Object.prototype.hasOwnProperty.call(raw, key)
);
export const createCustomAccount = <A = string>(currency: string, currencyToAsset: (curr: string, api?: ApiInterfaceRx) => A, accountDataType = 'AccountData'):
(instanceId: string, api: ApiInterfaceRx) => RxResult<(arg: string | Uint8Array | AccountId) => Observable<AccountData>> => (instanceId: string, api: ApiInterfaceRx) => {
const registry = api.registry;
const transform = <SB extends Enum>(balance: SB): AccountData => {
let free = registry.createType('Balance');
const reserved = registry.createType('Balance');
const miscFrozen = registry.createType('Balance');
const feeFrozen = registry.createType('Balance');
if (signedBalancePredicate(balance)) {
if (balance.isPositive) {
free = registry.createType('Balance', balance.asPositive);
} else if (balance.isNegative) {
free = registry.createType('Balance', balance.asNegative.mul(new BN(-1)));
}
}
return registry.createType(accountDataType as 'AccountData', { feeFrozen, free, miscFrozen, reserved });
};
return transformBalanceStorage(
api.query.eqBalances.account as unknown as EqBalanceDoubleMap<A>,
currency,
transform,
currencyToAsset,
api
);
};
const definitions: OverrideBundleDefinition = {
derives: {
...equilibrium.instances.balances.reduce(
(all, cur) => ({
...all,
[cur]: {
customAccount: createCustomAccount(cur, (currency: string, api?: ApiInterfaceRx) => {
let assetsEnabled = true;
try {
api?.registry.createType('AssetIdInnerType' as any);
} catch (_) {
assetsEnabled = false;
}
return assetsEnabled ? { 0: u64FromCurrency(currency) } : currency;
})
}
}),
{}
)
},
instances: equilibrium.instances,
types: [
{
minmax: [0, 264],
types: equilibrium.types
},
{
minmax: [265, undefined],
types: equilibriumNext.types
}
]
};
export default definitions;