@ledgerhq/coin-polkadot 0.0.2
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/.eslintrc.js +57 -0
- package/.turbo/turbo-build.log +4 -0
- package/CHANGELOG.md +12 -0
- package/jest.config.js +10 -0
- package/lib/account.d.ts +15 -0
- package/lib/account.d.ts.map +1 -0
- package/lib/account.js +133 -0
- package/lib/account.js.map +1 -0
- package/lib/address.d.ts +7 -0
- package/lib/address.d.ts.map +1 -0
- package/lib/address.js +28 -0
- package/lib/address.js.map +1 -0
- package/lib/api/bisontrails.d.ts +11 -0
- package/lib/api/bisontrails.d.ts.map +1 -0
- package/lib/api/bisontrails.js +351 -0
- package/lib/api/bisontrails.js.map +1 -0
- package/lib/api/common.d.ts +12 -0
- package/lib/api/common.d.ts.map +1 -0
- package/lib/api/common.js +41 -0
- package/lib/api/common.js.map +1 -0
- package/lib/api/index.d.ts +3 -0
- package/lib/api/index.d.ts.map +1 -0
- package/lib/api/index.js +53 -0
- package/lib/api/index.js.map +1 -0
- package/lib/api/sidecar.d.ts +193 -0
- package/lib/api/sidecar.d.ts.map +1 -0
- package/lib/api/sidecar.js +844 -0
- package/lib/api/sidecar.js.map +1 -0
- package/lib/api/sidecar.types.d.ts +163 -0
- package/lib/api/sidecar.types.d.ts.map +1 -0
- package/lib/api/sidecar.types.js +3 -0
- package/lib/api/sidecar.types.js.map +1 -0
- package/lib/api/subscan.d.ts +6 -0
- package/lib/api/subscan.d.ts.map +1 -0
- package/lib/api/subscan.js +375 -0
- package/lib/api/subscan.js.map +1 -0
- package/lib/api/websocket.d.ts +92 -0
- package/lib/api/websocket.d.ts.map +1 -0
- package/lib/api/websocket.js +759 -0
- package/lib/api/websocket.js.map +1 -0
- package/lib/bridge/js.d.ts +6 -0
- package/lib/bridge/js.d.ts.map +1 -0
- package/lib/bridge/js.js +120 -0
- package/lib/bridge/js.js.map +1 -0
- package/lib/bridge.integration.test.d.ts +4 -0
- package/lib/bridge.integration.test.d.ts.map +1 -0
- package/lib/bridge.integration.test.js +795 -0
- package/lib/bridge.integration.test.js.map +1 -0
- package/lib/cache.d.ts +65 -0
- package/lib/cache.d.ts.map +1 -0
- package/lib/cache.js +182 -0
- package/lib/cache.js.map +1 -0
- package/lib/cli-transaction.d.ts +44 -0
- package/lib/cli-transaction.d.ts.map +1 -0
- package/lib/cli-transaction.js +148 -0
- package/lib/cli-transaction.js.map +1 -0
- package/lib/deviceTransactionConfig.d.ts +16 -0
- package/lib/deviceTransactionConfig.d.ts.map +1 -0
- package/lib/deviceTransactionConfig.js +171 -0
- package/lib/deviceTransactionConfig.js.map +1 -0
- package/lib/errors.d.ts +37 -0
- package/lib/errors.d.ts.map +1 -0
- package/lib/errors.js +17 -0
- package/lib/errors.js.map +1 -0
- package/lib/hw-getAddress.d.ts +4 -0
- package/lib/hw-getAddress.d.ts.map +1 -0
- package/lib/hw-getAddress.js +64 -0
- package/lib/hw-getAddress.js.map +1 -0
- package/lib/js-buildTransaction.d.ts +25 -0
- package/lib/js-buildTransaction.d.ts.map +1 -0
- package/lib/js-buildTransaction.js +265 -0
- package/lib/js-buildTransaction.js.map +1 -0
- package/lib/js-createTransaction.d.ts +9 -0
- package/lib/js-createTransaction.d.ts.map +1 -0
- package/lib/js-createTransaction.js +22 -0
- package/lib/js-createTransaction.js.map +1 -0
- package/lib/js-estimateMaxSpendable.d.ts +15 -0
- package/lib/js-estimateMaxSpendable.d.ts.map +1 -0
- package/lib/js-estimateMaxSpendable.js +89 -0
- package/lib/js-estimateMaxSpendable.js.map +1 -0
- package/lib/js-getFeesForTransaction.d.ts +14 -0
- package/lib/js-getFeesForTransaction.d.ts.map +1 -0
- package/lib/js-getFeesForTransaction.js +94 -0
- package/lib/js-getFeesForTransaction.js.map +1 -0
- package/lib/js-getTransactionStatus.d.ts +18 -0
- package/lib/js-getTransactionStatus.d.ts.map +1 -0
- package/lib/js-getTransactionStatus.js +316 -0
- package/lib/js-getTransactionStatus.js.map +1 -0
- package/lib/js-prepareTransaction.d.ts +9 -0
- package/lib/js-prepareTransaction.d.ts.map +1 -0
- package/lib/js-prepareTransaction.js +83 -0
- package/lib/js-prepareTransaction.js.map +1 -0
- package/lib/js-signOperation.d.ts +27 -0
- package/lib/js-signOperation.d.ts.map +1 -0
- package/lib/js-signOperation.js +235 -0
- package/lib/js-signOperation.js.map +1 -0
- package/lib/js-synchronisation.d.ts +3 -0
- package/lib/js-synchronisation.d.ts.map +1 -0
- package/lib/js-synchronisation.js +104 -0
- package/lib/js-synchronisation.js.map +1 -0
- package/lib/logic.d.ts +107 -0
- package/lib/logic.d.ts.map +1 -0
- package/lib/logic.js +242 -0
- package/lib/logic.js.map +1 -0
- package/lib/platformAdapter.d.ts +11 -0
- package/lib/platformAdapter.d.ts.map +1 -0
- package/lib/platformAdapter.js +25 -0
- package/lib/platformAdapter.js.map +1 -0
- package/lib/platformAdapter.test.d.ts +2 -0
- package/lib/platformAdapter.test.d.ts.map +1 -0
- package/lib/platformAdapter.test.js +51 -0
- package/lib/platformAdapter.test.js.map +1 -0
- package/lib/polkadot-crypto.d.ts +2 -0
- package/lib/polkadot-crypto.d.ts.map +1 -0
- package/lib/polkadot-crypto.js +14 -0
- package/lib/polkadot-crypto.js.map +1 -0
- package/lib/preload.d.ts +14 -0
- package/lib/preload.d.ts.map +1 -0
- package/lib/preload.js +173 -0
- package/lib/preload.js.map +1 -0
- package/lib/serialization.d.ts +4 -0
- package/lib/serialization.d.ts.map +1 -0
- package/lib/serialization.js +51 -0
- package/lib/serialization.js.map +1 -0
- package/lib/specs.d.ts +7 -0
- package/lib/specs.d.ts.map +1 -0
- package/lib/specs.js +274 -0
- package/lib/specs.js.map +1 -0
- package/lib/speculos-deviceActions.d.ts +4 -0
- package/lib/speculos-deviceActions.d.ts.map +1 -0
- package/lib/speculos-deviceActions.js +85 -0
- package/lib/speculos-deviceActions.js.map +1 -0
- package/lib/transaction.d.ts +15 -0
- package/lib/transaction.d.ts.map +1 -0
- package/lib/transaction.js +51 -0
- package/lib/transaction.js.map +1 -0
- package/lib/types.d.ts +96 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +3 -0
- package/lib/types.js.map +1 -0
- package/lib/validators.d.ts +3 -0
- package/lib/validators.d.ts.map +1 -0
- package/lib/validators.js +7 -0
- package/lib/validators.js.map +1 -0
- package/package.json +95 -0
- package/src/account.ts +170 -0
- package/src/address.ts +28 -0
- package/src/api/bisontrails.ts +343 -0
- package/src/api/common.ts +52 -0
- package/src/api/index.ts +38 -0
- package/src/api/sidecar.ts +735 -0
- package/src/api/sidecar.types.ts +162 -0
- package/src/api/subscan.ts +362 -0
- package/src/api/websocket.ts +535 -0
- package/src/bridge/js.ts +81 -0
- package/src/bridge.integration.test.ts +764 -0
- package/src/cache.ts +202 -0
- package/src/cli-transaction.ts +184 -0
- package/src/deviceTransactionConfig.ts +209 -0
- package/src/errors.ts +39 -0
- package/src/hw-getAddress.ts +14 -0
- package/src/js-buildTransaction.ts +206 -0
- package/src/js-createTransaction.ts +22 -0
- package/src/js-estimateMaxSpendable.ts +37 -0
- package/src/js-getFeesForTransaction.ts +41 -0
- package/src/js-getTransactionStatus.ts +350 -0
- package/src/js-prepareTransaction.ts +27 -0
- package/src/js-signOperation.ts +232 -0
- package/src/js-synchronisation.ts +57 -0
- package/src/logic.ts +266 -0
- package/src/platformAdapter.test.ts +61 -0
- package/src/platformAdapter.ts +29 -0
- package/src/polkadot-crypto.ts +10 -0
- package/src/preload.ts +148 -0
- package/src/serialization.ts +48 -0
- package/src/specs.ts +305 -0
- package/src/speculos-deviceActions.ts +84 -0
- package/src/transaction.ts +64 -0
- package/src/types.ts +118 -0
- package/src/validators.ts +2 -0
- package/tsconfig.json +21 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import type { HexString } from "@polkadot/util/types";
|
|
2
|
+
|
|
3
|
+
interface IAt {
|
|
4
|
+
hash: string;
|
|
5
|
+
height: string;
|
|
6
|
+
}
|
|
7
|
+
interface IBalanceLock {
|
|
8
|
+
id: string;
|
|
9
|
+
amount: string;
|
|
10
|
+
}
|
|
11
|
+
interface IPallet {
|
|
12
|
+
at: IAt;
|
|
13
|
+
pallet: string;
|
|
14
|
+
palletIndex: number;
|
|
15
|
+
}
|
|
16
|
+
interface IUnlocking {
|
|
17
|
+
value: string;
|
|
18
|
+
era: string;
|
|
19
|
+
}
|
|
20
|
+
interface IStakingLedger {
|
|
21
|
+
stash: string;
|
|
22
|
+
total: string;
|
|
23
|
+
active: string;
|
|
24
|
+
unlocking: IUnlocking[];
|
|
25
|
+
claimedRewards: string[];
|
|
26
|
+
}
|
|
27
|
+
interface ITarget {
|
|
28
|
+
address: string;
|
|
29
|
+
value: string;
|
|
30
|
+
status: "active" | "inactive" | "waiting" | null;
|
|
31
|
+
}
|
|
32
|
+
interface IIdentity {
|
|
33
|
+
display?: string;
|
|
34
|
+
displayParent?: string;
|
|
35
|
+
email?: string;
|
|
36
|
+
image?: string;
|
|
37
|
+
legal?: string;
|
|
38
|
+
other?: Record<string, any>;
|
|
39
|
+
parent?: string;
|
|
40
|
+
pgp?: string;
|
|
41
|
+
riot?: string;
|
|
42
|
+
twitter?: string;
|
|
43
|
+
web?: string;
|
|
44
|
+
judgements: Array<[string, Record<string, any>]>;
|
|
45
|
+
}
|
|
46
|
+
interface IValidatorExposure {
|
|
47
|
+
who: string;
|
|
48
|
+
value: string;
|
|
49
|
+
}
|
|
50
|
+
interface IValidator {
|
|
51
|
+
at?: IAt;
|
|
52
|
+
accountId: string;
|
|
53
|
+
controllerId?: string | null;
|
|
54
|
+
identity: IIdentity;
|
|
55
|
+
own: string;
|
|
56
|
+
total: string;
|
|
57
|
+
nominatorsCount: string;
|
|
58
|
+
nominators?: IValidatorExposure[];
|
|
59
|
+
commission: string;
|
|
60
|
+
rewardsPoints: string | null;
|
|
61
|
+
isElected: boolean;
|
|
62
|
+
isOversubscribed: boolean;
|
|
63
|
+
}
|
|
64
|
+
interface IChainType {
|
|
65
|
+
isDevelopment?: boolean;
|
|
66
|
+
isLocal?: boolean;
|
|
67
|
+
isLive?: boolean;
|
|
68
|
+
isCustom?: boolean;
|
|
69
|
+
asCustom?: Text;
|
|
70
|
+
}
|
|
71
|
+
interface IChainProperties {
|
|
72
|
+
ss58Format: string;
|
|
73
|
+
tokenDecimals: string;
|
|
74
|
+
tokenSymbol: string;
|
|
75
|
+
}
|
|
76
|
+
export interface SidecarAccountBalanceInfo {
|
|
77
|
+
at: IAt;
|
|
78
|
+
tokenSymbol: string;
|
|
79
|
+
nonce: string;
|
|
80
|
+
free: string;
|
|
81
|
+
reserved: string;
|
|
82
|
+
miscFrozen: string;
|
|
83
|
+
feeFrozen: string;
|
|
84
|
+
locks: IBalanceLock[];
|
|
85
|
+
}
|
|
86
|
+
export interface SidecarPallet {
|
|
87
|
+
at: IAt;
|
|
88
|
+
tokenSymbol: string;
|
|
89
|
+
nonce: string;
|
|
90
|
+
free: string;
|
|
91
|
+
reserved: string;
|
|
92
|
+
miscFrozen: string;
|
|
93
|
+
feeFrozen: string;
|
|
94
|
+
locks: IBalanceLock[];
|
|
95
|
+
}
|
|
96
|
+
export interface SidecarPalletStorageItem extends IPallet {
|
|
97
|
+
storageItem: string;
|
|
98
|
+
keys?: string[];
|
|
99
|
+
key1?: string;
|
|
100
|
+
key2?: string;
|
|
101
|
+
value?: any;
|
|
102
|
+
}
|
|
103
|
+
export interface SidecarStakingInfo {
|
|
104
|
+
at: IAt;
|
|
105
|
+
controller: string;
|
|
106
|
+
rewardDestination: string;
|
|
107
|
+
numSlashingSpans: string;
|
|
108
|
+
staking: IStakingLedger;
|
|
109
|
+
}
|
|
110
|
+
export interface SidecarNominations {
|
|
111
|
+
at?: IAt;
|
|
112
|
+
submittedIn: string | null;
|
|
113
|
+
targets: ITarget[];
|
|
114
|
+
}
|
|
115
|
+
export interface SidecarConstants {
|
|
116
|
+
at: IAt;
|
|
117
|
+
consts: Record<string, any>;
|
|
118
|
+
}
|
|
119
|
+
export type SidecarValidatorsParamStatus = "all" | "elected" | "waiting";
|
|
120
|
+
export type SidecarValidatorsParamAddresses = string[];
|
|
121
|
+
export type SidecarValidators = IValidator[];
|
|
122
|
+
export interface SidecarPalletStakingProgress {
|
|
123
|
+
at: IAt;
|
|
124
|
+
idealValidatorCount?: string | null;
|
|
125
|
+
activeEra: string | null;
|
|
126
|
+
forceEra: string;
|
|
127
|
+
nextActiveEraEstimate?: string;
|
|
128
|
+
nextSessionEstimate: string | null;
|
|
129
|
+
unappliedSlashes: string[] | null;
|
|
130
|
+
electionStatus?: {
|
|
131
|
+
status: Record<string, any>;
|
|
132
|
+
toggleEstimate: string | null;
|
|
133
|
+
};
|
|
134
|
+
validatorSet?: string[] | null;
|
|
135
|
+
}
|
|
136
|
+
export interface SidecarTransactionMaterial {
|
|
137
|
+
at: IAt;
|
|
138
|
+
genesisHash: string;
|
|
139
|
+
chainName: string;
|
|
140
|
+
specName: string;
|
|
141
|
+
specVersion: string;
|
|
142
|
+
txVersion: string;
|
|
143
|
+
metadata?: HexString;
|
|
144
|
+
}
|
|
145
|
+
export interface SidecarTransactionBroadcast {
|
|
146
|
+
hash: string;
|
|
147
|
+
}
|
|
148
|
+
export interface SidecarPaymentInfo {
|
|
149
|
+
weight: string;
|
|
150
|
+
class: string;
|
|
151
|
+
partialFee: string;
|
|
152
|
+
}
|
|
153
|
+
export interface SidecarRuntimeSpec {
|
|
154
|
+
at: IAt;
|
|
155
|
+
authoringVersion: string;
|
|
156
|
+
transactionVersion: string;
|
|
157
|
+
implVersion: string;
|
|
158
|
+
specName: string;
|
|
159
|
+
specVersion: string;
|
|
160
|
+
chainType: IChainType;
|
|
161
|
+
properties: IChainProperties;
|
|
162
|
+
}
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
/*
|
|
2
|
+
|
|
3
|
+
THIS FILE IS UNUSED AND PROVIDED AS EXAMPLE FOR USING SUBSCAN INDEXER.
|
|
4
|
+
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/* eslint-disable */
|
|
8
|
+
|
|
9
|
+
/* istanbul ignore file */
|
|
10
|
+
import uniqBy from "lodash/uniqBy";
|
|
11
|
+
import camelCase from "lodash/camelCase";
|
|
12
|
+
import type { Operation } from "@ledgerhq/types-live";
|
|
13
|
+
import network from "@ledgerhq/coin-framework/network";
|
|
14
|
+
import { BigNumber } from "bignumber.js";
|
|
15
|
+
import { getEnv } from "@ledgerhq/coin-framework/env";
|
|
16
|
+
import { encodeAddress } from "@polkadot/util-crypto";
|
|
17
|
+
import { getOperationType } from "./common";
|
|
18
|
+
import type { PolkadotValidator } from "../types";
|
|
19
|
+
|
|
20
|
+
const getBaseApiUrl = () => getEnv("API_POLKADOT_INDEXER");
|
|
21
|
+
|
|
22
|
+
const DOT_REDOMINATION_BLOCK = 1248328;
|
|
23
|
+
const SUBSCAN_MULTIPLIER = 10000000000;
|
|
24
|
+
const SUBSCAN_ROW = 100;
|
|
25
|
+
const SUBSCAN_VALIDATOR_OVERSUBSCRIBED = 128;
|
|
26
|
+
const SUBSCAN_VALIDATOR_COMISSION_RATIO = 1000000000;
|
|
27
|
+
|
|
28
|
+
const encodePolkadotAddr = (addr) => {
|
|
29
|
+
return encodeAddress(
|
|
30
|
+
"0x" + addr,
|
|
31
|
+
/* SS58FORMAT= */
|
|
32
|
+
0
|
|
33
|
+
);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const getExtra = (type, extrinsic) => {
|
|
37
|
+
let extra: {
|
|
38
|
+
transferAmount?: BigNumber;
|
|
39
|
+
palletMethod: string;
|
|
40
|
+
bondedAmount?: BigNumber;
|
|
41
|
+
unbondedAmount?: BigNumber;
|
|
42
|
+
amount?: BigNumber;
|
|
43
|
+
withdrawUnbondedAmount?: any;
|
|
44
|
+
validatorStash?: any;
|
|
45
|
+
validators?: any;
|
|
46
|
+
} = {
|
|
47
|
+
palletMethod: extrinsic.call_module
|
|
48
|
+
? `${extrinsic.call_module}.${camelCase(extrinsic.call_module_function)}`
|
|
49
|
+
: `${extrinsic.module_id}.${camelCase(extrinsic.event_id)}`,
|
|
50
|
+
};
|
|
51
|
+
const params = JSON.parse(extrinsic.params);
|
|
52
|
+
let valueParam;
|
|
53
|
+
|
|
54
|
+
switch (type) {
|
|
55
|
+
case "OUT":
|
|
56
|
+
valueParam = params.find((p) => p.name === "value")?.value;
|
|
57
|
+
extra = { ...extra, transferAmount: new BigNumber(valueParam || 0) };
|
|
58
|
+
break;
|
|
59
|
+
|
|
60
|
+
case "BOND":
|
|
61
|
+
valueParam =
|
|
62
|
+
params.find((p) => p.name === "value")?.value ||
|
|
63
|
+
params.find((p) => p.name === "max_additional")?.value;
|
|
64
|
+
extra = { ...extra, bondedAmount: new BigNumber(valueParam || 0) };
|
|
65
|
+
break;
|
|
66
|
+
|
|
67
|
+
case "UNBOND":
|
|
68
|
+
extra = {
|
|
69
|
+
...extra,
|
|
70
|
+
unbondedAmount: new BigNumber(
|
|
71
|
+
params.find((p) => p.name === "value")?.value || 0
|
|
72
|
+
),
|
|
73
|
+
};
|
|
74
|
+
break;
|
|
75
|
+
|
|
76
|
+
case "SLASH":
|
|
77
|
+
case "REWARD_PAYOUT":
|
|
78
|
+
extra = {
|
|
79
|
+
...extra,
|
|
80
|
+
validatorStash: encodePolkadotAddr(
|
|
81
|
+
params.find((p) => p.type === "AccountId").value
|
|
82
|
+
),
|
|
83
|
+
amount: new BigNumber(params.find((p) => p.type === "Balance").value),
|
|
84
|
+
};
|
|
85
|
+
break;
|
|
86
|
+
|
|
87
|
+
case "NOMINATE":
|
|
88
|
+
extra = {
|
|
89
|
+
...extra,
|
|
90
|
+
validators: params
|
|
91
|
+
.find((t) => t.name === "targets")
|
|
92
|
+
.value.reduce((old, current) => {
|
|
93
|
+
return current ? [...old, encodePolkadotAddr(current)] : old;
|
|
94
|
+
}, []),
|
|
95
|
+
};
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return extra;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const subscanAmountToPlanck = (amount, blockHeight) => {
|
|
103
|
+
if (blockHeight >= DOT_REDOMINATION_BLOCK) {
|
|
104
|
+
return new BigNumber(amount).multipliedBy(SUBSCAN_MULTIPLIER);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return new BigNumber(amount)
|
|
108
|
+
.multipliedBy(100)
|
|
109
|
+
.multipliedBy(SUBSCAN_MULTIPLIER);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const mapSubscanReward = ({ accountId }, reward): Partial<Operation> => {
|
|
113
|
+
const type = reward.event_id === "Reward" ? "REWARD_PAYOUT" : "SLASH";
|
|
114
|
+
const hash = reward.extrinsic_hash || reward.event_index; // Slashes are not extrinsics
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
id: `${accountId}-${hash}-${type}`,
|
|
118
|
+
accountId,
|
|
119
|
+
fee: new BigNumber(0),
|
|
120
|
+
value: new BigNumber(reward.amount),
|
|
121
|
+
type,
|
|
122
|
+
hash: reward.extrinsic_hash,
|
|
123
|
+
blockHeight: reward.block_num,
|
|
124
|
+
date: new Date(reward.block_timestamp * 1000),
|
|
125
|
+
recipients: [],
|
|
126
|
+
senders: [],
|
|
127
|
+
extra: getExtra(type, reward),
|
|
128
|
+
};
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const mapSubscanTransfer = (
|
|
132
|
+
{ addr, accountId },
|
|
133
|
+
transfer
|
|
134
|
+
): Partial<Operation> | null => {
|
|
135
|
+
const type = transfer.from === addr ? "OUT" : "IN";
|
|
136
|
+
const amount = subscanAmountToPlanck(transfer.amount, transfer.block_num);
|
|
137
|
+
return {
|
|
138
|
+
id: `${accountId}-${transfer.hash}-${type}`,
|
|
139
|
+
accountId,
|
|
140
|
+
fee: new BigNumber(transfer.fee),
|
|
141
|
+
value: !transfer.success ? new BigNumber(0) : amount,
|
|
142
|
+
type,
|
|
143
|
+
hash: transfer.hash,
|
|
144
|
+
blockHeight: transfer.block_num,
|
|
145
|
+
date: new Date(transfer.block_timestamp * 1000),
|
|
146
|
+
extra: {
|
|
147
|
+
palletMethod: "balances.transfer",
|
|
148
|
+
// FIXME subscan plz
|
|
149
|
+
transferAmount: amount,
|
|
150
|
+
},
|
|
151
|
+
senders: [transfer.from],
|
|
152
|
+
recipients: [transfer.to],
|
|
153
|
+
hasFailed: !transfer.success,
|
|
154
|
+
};
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const mapSubscanExtrinsic = (
|
|
158
|
+
{ addr, accountId },
|
|
159
|
+
extrinsic
|
|
160
|
+
): Partial<Operation> => {
|
|
161
|
+
const pallet = extrinsic.call_module;
|
|
162
|
+
const palletMethod = camelCase(extrinsic.call_module_function);
|
|
163
|
+
const type = getOperationType(pallet, palletMethod);
|
|
164
|
+
// FIXME subscan WTF
|
|
165
|
+
const params = JSON.parse(extrinsic.params);
|
|
166
|
+
const paramRecipient = params.find((p) => p.name === "dest");
|
|
167
|
+
const paramAmount = params.find((p) => p.name === "value");
|
|
168
|
+
const recipient = paramRecipient && encodePolkadotAddr(paramRecipient.value);
|
|
169
|
+
// All successful transfers, but not self transfers (which only burn fees)
|
|
170
|
+
const value =
|
|
171
|
+
type === "OUT" && extrinsic.success && recipient !== addr && paramAmount
|
|
172
|
+
? new BigNumber(paramAmount.value).plus(extrinsic.fee)
|
|
173
|
+
: new BigNumber(extrinsic.fee);
|
|
174
|
+
return {
|
|
175
|
+
id: `${accountId}-${extrinsic.extrinsic_hash}-${type}`,
|
|
176
|
+
accountId,
|
|
177
|
+
fee: new BigNumber(extrinsic.fee),
|
|
178
|
+
value,
|
|
179
|
+
type,
|
|
180
|
+
hash: extrinsic.extrinsic_hash,
|
|
181
|
+
blockHeight: extrinsic.block_num,
|
|
182
|
+
date: new Date(extrinsic.block_timestamp * 1000),
|
|
183
|
+
senders: [addr],
|
|
184
|
+
recipients: recipient ? [recipient] : [],
|
|
185
|
+
extra: getExtra(type, extrinsic),
|
|
186
|
+
hasFailed: !extrinsic.success,
|
|
187
|
+
transactionSequenceNumber:
|
|
188
|
+
extrinsic.signer === addr ? extrinsic.nonce : undefined,
|
|
189
|
+
};
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
const fetchSubscanList = async (
|
|
193
|
+
resourceName,
|
|
194
|
+
url,
|
|
195
|
+
mapFn,
|
|
196
|
+
mapArgs,
|
|
197
|
+
startAt,
|
|
198
|
+
page = 0,
|
|
199
|
+
prevOperations = []
|
|
200
|
+
) => {
|
|
201
|
+
let operations;
|
|
202
|
+
|
|
203
|
+
if (prevOperations.length) {
|
|
204
|
+
const oldestBlockHeight = (
|
|
205
|
+
prevOperations[prevOperations.length - 1] as { blockHeight: number }
|
|
206
|
+
).blockHeight;
|
|
207
|
+
|
|
208
|
+
if (oldestBlockHeight < startAt) {
|
|
209
|
+
return prevOperations.filter(
|
|
210
|
+
(o) => (o as { blockHeight: number }).blockHeight >= startAt
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
try {
|
|
216
|
+
const { data } = await network({
|
|
217
|
+
method: "POST",
|
|
218
|
+
url: `${getBaseApiUrl()}${url}`,
|
|
219
|
+
data: {
|
|
220
|
+
address: mapArgs.addr,
|
|
221
|
+
row: SUBSCAN_ROW,
|
|
222
|
+
page,
|
|
223
|
+
},
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
if (data.code !== 0) {
|
|
227
|
+
throw new Error(`SUBSCAN: ${data.message} - code ${data.code}`);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const list = data.data[resourceName] || [];
|
|
231
|
+
const count = data.data.count;
|
|
232
|
+
// console.log(`${url} - ${prevOperations.length} / ${count}`);
|
|
233
|
+
operations = [...prevOperations, ...list.map(mapFn.bind(null, mapArgs))];
|
|
234
|
+
return operations.length < count
|
|
235
|
+
? fetchSubscanList(
|
|
236
|
+
resourceName,
|
|
237
|
+
url,
|
|
238
|
+
mapFn,
|
|
239
|
+
mapArgs,
|
|
240
|
+
startAt,
|
|
241
|
+
page + 1,
|
|
242
|
+
operations
|
|
243
|
+
)
|
|
244
|
+
: operations;
|
|
245
|
+
} catch (e) {
|
|
246
|
+
console.error(e);
|
|
247
|
+
throw e;
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
export const getOperations = async (
|
|
252
|
+
accountId: string,
|
|
253
|
+
addr: string,
|
|
254
|
+
startAt: number = 0
|
|
255
|
+
) => {
|
|
256
|
+
const mapArgs = {
|
|
257
|
+
addr,
|
|
258
|
+
accountId,
|
|
259
|
+
};
|
|
260
|
+
const [extrinsicsOp, transfersOp, rewardsOp] = await Promise.all([
|
|
261
|
+
fetchSubscanList(
|
|
262
|
+
"extrinsics",
|
|
263
|
+
"/api/scan/extrinsics",
|
|
264
|
+
mapSubscanExtrinsic,
|
|
265
|
+
mapArgs,
|
|
266
|
+
startAt
|
|
267
|
+
),
|
|
268
|
+
fetchSubscanList(
|
|
269
|
+
"transfers",
|
|
270
|
+
"/api/scan/transfers",
|
|
271
|
+
mapSubscanTransfer,
|
|
272
|
+
mapArgs,
|
|
273
|
+
startAt
|
|
274
|
+
),
|
|
275
|
+
fetchSubscanList(
|
|
276
|
+
"list",
|
|
277
|
+
"/api/scan/account/reward_slash",
|
|
278
|
+
mapSubscanReward,
|
|
279
|
+
mapArgs,
|
|
280
|
+
startAt
|
|
281
|
+
),
|
|
282
|
+
]);
|
|
283
|
+
const incomingTransfers = transfersOp.filter((t) => t.type === "IN");
|
|
284
|
+
const operations = uniqBy<Operation>(
|
|
285
|
+
[...extrinsicsOp, ...incomingTransfers, ...rewardsOp],
|
|
286
|
+
(op) => op.id
|
|
287
|
+
);
|
|
288
|
+
operations.sort((a, b) => (b.date as any) - (a.date as any));
|
|
289
|
+
return operations;
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
const mapSubscanValidator = (validator, isElected): PolkadotValidator => {
|
|
293
|
+
return {
|
|
294
|
+
address: validator.stash_account_display.address,
|
|
295
|
+
identity: validator.stash_account_display.display,
|
|
296
|
+
nominatorsCount: validator.count_nominators,
|
|
297
|
+
rewardPoints: validator.reward_point,
|
|
298
|
+
commission: new BigNumber(validator.validator_prefs_value).dividedBy(
|
|
299
|
+
SUBSCAN_VALIDATOR_COMISSION_RATIO
|
|
300
|
+
),
|
|
301
|
+
totalBonded: new BigNumber(validator.bonded_nominators).plus(
|
|
302
|
+
validator.bonded_owner
|
|
303
|
+
),
|
|
304
|
+
selfBonded: new BigNumber(validator.bonded_owner),
|
|
305
|
+
isElected,
|
|
306
|
+
isOversubscribed:
|
|
307
|
+
validator.count_nominators >= SUBSCAN_VALIDATOR_OVERSUBSCRIBED,
|
|
308
|
+
};
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
const fetchSubscanValidators = async (isElected) => {
|
|
312
|
+
// Cannot fetch both at the same time through subscan
|
|
313
|
+
const url = isElected
|
|
314
|
+
? "/api/scan/staking/validators"
|
|
315
|
+
: "/api/scan/staking/waiting";
|
|
316
|
+
|
|
317
|
+
try {
|
|
318
|
+
const { data } = await network({
|
|
319
|
+
method: "POST",
|
|
320
|
+
url: `${getBaseApiUrl()}${url}`,
|
|
321
|
+
data: {},
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
if (data.code !== 0) {
|
|
325
|
+
throw new Error(`SUBSCAN: ${data.message} - code ${data.code}`);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const validators = data.data.list.map((v) =>
|
|
329
|
+
mapSubscanValidator(v, isElected)
|
|
330
|
+
);
|
|
331
|
+
return validators;
|
|
332
|
+
} catch (e) {
|
|
333
|
+
console.error(e);
|
|
334
|
+
throw e;
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* List all validators for the current era, and their exposure.
|
|
340
|
+
*/
|
|
341
|
+
export const getValidators = async (stashes: string | string[] = "elected") => {
|
|
342
|
+
if (stashes === "elected") {
|
|
343
|
+
return fetchSubscanValidators(true);
|
|
344
|
+
} else if (stashes === "waiting") {
|
|
345
|
+
return fetchSubscanValidators(false);
|
|
346
|
+
} else if (stashes === "all" || Array.isArray(stashes)) {
|
|
347
|
+
const [elected, waiting] = await Promise.all([
|
|
348
|
+
fetchSubscanValidators(true),
|
|
349
|
+
fetchSubscanValidators(false),
|
|
350
|
+
]);
|
|
351
|
+
|
|
352
|
+
if (Array.isArray(stashes)) {
|
|
353
|
+
return [...elected, ...waiting].filter((v) =>
|
|
354
|
+
stashes.includes(v.address)
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return [...elected, ...waiting];
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
return [];
|
|
362
|
+
};
|