@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
package/package.json
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ledgerhq/coin-polkadot",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "Ledger Polkadot Coin integration",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"Ledger",
|
|
7
|
+
"LedgerWallet",
|
|
8
|
+
"dot",
|
|
9
|
+
"Polkadot",
|
|
10
|
+
"Hardware Wallet"
|
|
11
|
+
],
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/LedgerHQ/ledger-live.git"
|
|
15
|
+
},
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/LedgerHQ/ledger-live/issues"
|
|
18
|
+
},
|
|
19
|
+
"homepage": "https://github.com/LedgerHQ/ledger-live/tree/develop/libs/coin-polkadot",
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"main": "lib/index.js",
|
|
24
|
+
"module": "lib-es/index.js",
|
|
25
|
+
"types": "lib/index.d.ts",
|
|
26
|
+
"typesVersions": {
|
|
27
|
+
"*": {
|
|
28
|
+
"lib/*": [
|
|
29
|
+
"lib/*"
|
|
30
|
+
],
|
|
31
|
+
"lib-es/*": [
|
|
32
|
+
"lib-es/*"
|
|
33
|
+
],
|
|
34
|
+
"*": [
|
|
35
|
+
"lib/*"
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"exports": {
|
|
40
|
+
"./lib/*": "./lib/*.js",
|
|
41
|
+
"./lib-es/*": "./lib-es/*.js",
|
|
42
|
+
"./*": {
|
|
43
|
+
"require": "./lib/*.js",
|
|
44
|
+
"default": "./lib-es/*.js"
|
|
45
|
+
},
|
|
46
|
+
"./package.json": "./package.json"
|
|
47
|
+
},
|
|
48
|
+
"license": "Apache-2.0",
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"@ledgerhq/live-app-sdk": "^0.8.1",
|
|
51
|
+
"@polkadot/types": "9.8.1",
|
|
52
|
+
"@polkadot/types-known": "9.8.1",
|
|
53
|
+
"@polkadot/util": "10.3.1",
|
|
54
|
+
"@polkadot/util-crypto": "10.3.1",
|
|
55
|
+
"bignumber.js": "^9.1.0",
|
|
56
|
+
"expect": "^27.4.6",
|
|
57
|
+
"invariant": "^2.2.2",
|
|
58
|
+
"lodash": "^4.17.21",
|
|
59
|
+
"rxjs": "^6.6.7",
|
|
60
|
+
"@ledgerhq/coin-framework": "^0.0.2",
|
|
61
|
+
"@ledgerhq/cryptoassets": "^9.0.0",
|
|
62
|
+
"@ledgerhq/devices": "^8.0.0",
|
|
63
|
+
"@ledgerhq/errors": "^6.12.3",
|
|
64
|
+
"@ledgerhq/hw-app-polkadot": "^6.27.12",
|
|
65
|
+
"@ledgerhq/logs": "^6.10.1",
|
|
66
|
+
"@ledgerhq/types-cryptoassets": "^7.0.0",
|
|
67
|
+
"@ledgerhq/types-live": "^6.31.0"
|
|
68
|
+
},
|
|
69
|
+
"devDependencies": {
|
|
70
|
+
"@types/jest": "^29.2.4",
|
|
71
|
+
"@typescript-eslint/eslint-plugin": "^5.46.1",
|
|
72
|
+
"@typescript-eslint/parser": "^5.46.1",
|
|
73
|
+
"eslint": "^7.32.0",
|
|
74
|
+
"eslint-config-prettier": "^8.3.0",
|
|
75
|
+
"eslint-config-typescript": "^3.0.0",
|
|
76
|
+
"eslint-formatter-pretty": "^3.0.1",
|
|
77
|
+
"eslint-plugin-prettier": "^3.4.0",
|
|
78
|
+
"eslint-plugin-typescript": "^0.14.0",
|
|
79
|
+
"jest": "^28.1.1",
|
|
80
|
+
"prettier": "^2.8.1",
|
|
81
|
+
"ts-jest": "^28.0.5",
|
|
82
|
+
"typescript": "^4.9.4"
|
|
83
|
+
},
|
|
84
|
+
"gitHead": "dd0dea64b58e5a9125c8a422dcffd29e5ef6abec",
|
|
85
|
+
"scripts": {
|
|
86
|
+
"clean": "rimraf lib lib-es",
|
|
87
|
+
"build": "tsc && tsc -m ES6 --outDir lib-es",
|
|
88
|
+
"prewatch": "pnpm build",
|
|
89
|
+
"watch": "tsc --watch",
|
|
90
|
+
"doc": "documentation readme src/** --section=API --pe ts --re ts --re d.ts",
|
|
91
|
+
"lint": "eslint ./src --no-error-on-unmatched-pattern --ext .ts,.tsx",
|
|
92
|
+
"lint:fix": "pnpm lint --fix",
|
|
93
|
+
"test": "jest"
|
|
94
|
+
}
|
|
95
|
+
}
|
package/src/account.ts
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import invariant from "invariant";
|
|
2
|
+
import { BigNumber } from "bignumber.js";
|
|
3
|
+
import type { Operation } from "@ledgerhq/types-live";
|
|
4
|
+
import { getAccountUnit } from "@ledgerhq/coin-framework/account/index";
|
|
5
|
+
import { formatCurrencyUnit } from "@ledgerhq/coin-framework/currencies/index";
|
|
6
|
+
import { PolkadotAccount, PolkadotResources } from "./types";
|
|
7
|
+
import type { Unit } from "@ledgerhq/types-cryptoassets";
|
|
8
|
+
|
|
9
|
+
function formatOperationSpecifics(
|
|
10
|
+
op: Operation,
|
|
11
|
+
unit: Unit | null | undefined
|
|
12
|
+
): string {
|
|
13
|
+
const {
|
|
14
|
+
validators,
|
|
15
|
+
bondedAmount,
|
|
16
|
+
unbondedAmount,
|
|
17
|
+
withdrawUnbondedAmount,
|
|
18
|
+
validatorStash,
|
|
19
|
+
amount,
|
|
20
|
+
} = op.extra;
|
|
21
|
+
let str = (validators || []).map((v) => `\n ${v}`).join("");
|
|
22
|
+
const formatConfig = {
|
|
23
|
+
disableRounding: true,
|
|
24
|
+
alwaysShowSign: false,
|
|
25
|
+
showCode: true,
|
|
26
|
+
};
|
|
27
|
+
str +=
|
|
28
|
+
bondedAmount && !bondedAmount.isNaN()
|
|
29
|
+
? `\n bondedAmount: ${
|
|
30
|
+
unit
|
|
31
|
+
? formatCurrencyUnit(unit, bondedAmount, formatConfig)
|
|
32
|
+
: bondedAmount
|
|
33
|
+
}`
|
|
34
|
+
: unbondedAmount && !unbondedAmount.isNaN()
|
|
35
|
+
? `\n unbondedAmount: ${
|
|
36
|
+
unit
|
|
37
|
+
? formatCurrencyUnit(unit, unbondedAmount, formatConfig)
|
|
38
|
+
: unbondedAmount
|
|
39
|
+
}`
|
|
40
|
+
: withdrawUnbondedAmount && !withdrawUnbondedAmount.isNaN()
|
|
41
|
+
? `\n withdrawUnbondedAmount: ${
|
|
42
|
+
unit
|
|
43
|
+
? formatCurrencyUnit(unit, withdrawUnbondedAmount, formatConfig)
|
|
44
|
+
: withdrawUnbondedAmount
|
|
45
|
+
}`
|
|
46
|
+
: "";
|
|
47
|
+
str += validatorStash ? `\n validatorStash: ${validatorStash}` : "";
|
|
48
|
+
str += amount
|
|
49
|
+
? `\n amount: ${
|
|
50
|
+
unit ? formatCurrencyUnit(unit, amount, formatConfig) : amount
|
|
51
|
+
}`
|
|
52
|
+
: "";
|
|
53
|
+
return str;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function formatAccountSpecifics(account: PolkadotAccount): string {
|
|
57
|
+
const { polkadotResources } = account;
|
|
58
|
+
invariant(polkadotResources, "polkadot account expected");
|
|
59
|
+
const unit = getAccountUnit(account);
|
|
60
|
+
const formatConfig = {
|
|
61
|
+
disableRounding: true,
|
|
62
|
+
alwaysShowSign: false,
|
|
63
|
+
showCode: true,
|
|
64
|
+
};
|
|
65
|
+
let str = " ";
|
|
66
|
+
str +=
|
|
67
|
+
formatCurrencyUnit(unit, account.spendableBalance, formatConfig) +
|
|
68
|
+
" spendable. ";
|
|
69
|
+
|
|
70
|
+
if ((polkadotResources as PolkadotResources).lockedBalance.gt(0)) {
|
|
71
|
+
str +=
|
|
72
|
+
formatCurrencyUnit(
|
|
73
|
+
unit,
|
|
74
|
+
(polkadotResources as PolkadotResources).lockedBalance,
|
|
75
|
+
formatConfig
|
|
76
|
+
) + " locked. ";
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if ((polkadotResources as PolkadotResources).unlockedBalance.gt(0)) {
|
|
80
|
+
str +=
|
|
81
|
+
formatCurrencyUnit(
|
|
82
|
+
unit,
|
|
83
|
+
(polkadotResources as PolkadotResources).unlockedBalance,
|
|
84
|
+
formatConfig
|
|
85
|
+
) + " unlocked. ";
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if ((polkadotResources as PolkadotResources).stash) {
|
|
89
|
+
str += "\nstash : " + (polkadotResources as PolkadotResources).stash;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if ((polkadotResources as PolkadotResources).controller) {
|
|
93
|
+
str +=
|
|
94
|
+
"\ncontroller : " + (polkadotResources as PolkadotResources).controller;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if ((polkadotResources as PolkadotResources).nominations?.length) {
|
|
98
|
+
str += "\nNominations\n";
|
|
99
|
+
str += ((polkadotResources as PolkadotResources).nominations as any[])
|
|
100
|
+
.map((v) => ` to ${v.address}`)
|
|
101
|
+
.join("\n");
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return str;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function fromOperationExtraRaw(
|
|
108
|
+
extra: Record<string, any> | null | undefined
|
|
109
|
+
) {
|
|
110
|
+
if (extra && extra.transferAmount) {
|
|
111
|
+
extra = { ...extra, transferAmount: extra.transferAmount.toString() };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (extra && extra.bondedAmount) {
|
|
115
|
+
return { ...extra, bondedAmount: new BigNumber(extra.bondedAmount) };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (extra && extra.unbondedAmount) {
|
|
119
|
+
return { ...extra, unbondedAmount: new BigNumber(extra.unbondedAmount) };
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (extra && extra.withdrawUnbondedAmount) {
|
|
123
|
+
return {
|
|
124
|
+
...extra,
|
|
125
|
+
withdrawUnbondedAmount: new BigNumber(extra.withdrawUnbondedAmount),
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// for subscan reward & slash
|
|
130
|
+
if (extra && extra.amount) {
|
|
131
|
+
return { ...extra, amount: new BigNumber(extra.amount) };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return extra;
|
|
135
|
+
}
|
|
136
|
+
export function toOperationExtraRaw(
|
|
137
|
+
extra: Record<string, any> | null | undefined
|
|
138
|
+
) {
|
|
139
|
+
if (extra && extra.transferAmount) {
|
|
140
|
+
extra = { ...extra, transferAmount: extra.transferAmount.toString() };
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (extra && extra.bondedAmount) {
|
|
144
|
+
return { ...extra, bondedAmount: extra.bondedAmount.toString() };
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (extra && extra.unbondedAmount) {
|
|
148
|
+
return { ...extra, unbondedAmount: extra.unbondedAmount.toString() };
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (extra && extra.withdrawUnbondedAmount) {
|
|
152
|
+
return {
|
|
153
|
+
...extra,
|
|
154
|
+
withdrawUnbondedAmount: extra.withdrawUnbondedAmount.toString(),
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// for subscan reward & slash
|
|
159
|
+
if (extra && extra.amount) {
|
|
160
|
+
return { ...extra, amount: extra.amount.toString() };
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return extra;
|
|
164
|
+
}
|
|
165
|
+
export default {
|
|
166
|
+
formatAccountSpecifics,
|
|
167
|
+
formatOperationSpecifics,
|
|
168
|
+
fromOperationExtraRaw,
|
|
169
|
+
toOperationExtraRaw,
|
|
170
|
+
};
|
package/src/address.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { encodeAddress, decodeAddress } from "@polkadot/util-crypto";
|
|
2
|
+
import { hexToU8a, isHex } from "@polkadot/util";
|
|
3
|
+
|
|
4
|
+
const POLKADOT_SS58_PREFIX = 0;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Returns true if address is valid, false if it's invalid (can't parse or wrong checksum)
|
|
8
|
+
*
|
|
9
|
+
* @param {*} address
|
|
10
|
+
*/
|
|
11
|
+
// TODO Cache this to improve perf
|
|
12
|
+
export const isValidAddress = (
|
|
13
|
+
address: string,
|
|
14
|
+
ss58Format: number = POLKADOT_SS58_PREFIX
|
|
15
|
+
): boolean => {
|
|
16
|
+
if (!address) return false;
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
encodeAddress(
|
|
20
|
+
isHex(address)
|
|
21
|
+
? hexToU8a(address)
|
|
22
|
+
: decodeAddress(address, false, ss58Format)
|
|
23
|
+
);
|
|
24
|
+
return true;
|
|
25
|
+
} catch (err) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
import network from "@ledgerhq/coin-framework/network";
|
|
2
|
+
import querystring from "querystring";
|
|
3
|
+
import { BigNumber } from "bignumber.js";
|
|
4
|
+
import { encodeOperationId } from "@ledgerhq/coin-framework/operation";
|
|
5
|
+
import { getEnv } from "@ledgerhq/coin-framework/env";
|
|
6
|
+
import { getOperationType } from "./common";
|
|
7
|
+
import type { OperationType, Operation } from "@ledgerhq/types-live";
|
|
8
|
+
import { isValidAddress } from "../address";
|
|
9
|
+
|
|
10
|
+
const LIMIT = 200;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Return the url of the indexer
|
|
14
|
+
*
|
|
15
|
+
* @returns {string}
|
|
16
|
+
*/
|
|
17
|
+
const getBaseApiUrl = (): string => getEnv("API_POLKADOT_INDEXER");
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Fetch operation lists from indexer
|
|
21
|
+
*
|
|
22
|
+
* @param {string} addr
|
|
23
|
+
* @param {number} offset
|
|
24
|
+
* @param {number} startAt
|
|
25
|
+
* @param {number} limit
|
|
26
|
+
*
|
|
27
|
+
* @returns {string}
|
|
28
|
+
*/
|
|
29
|
+
const getAccountOperationUrl = (
|
|
30
|
+
addr: string,
|
|
31
|
+
offset: number,
|
|
32
|
+
startAt: number,
|
|
33
|
+
limit: number = LIMIT
|
|
34
|
+
): string =>
|
|
35
|
+
`${getBaseApiUrl()}/accounts/${addr}/operations?${querystring.stringify({
|
|
36
|
+
limit,
|
|
37
|
+
offset,
|
|
38
|
+
startAt,
|
|
39
|
+
})}`;
|
|
40
|
+
|
|
41
|
+
const getWithdrawUnbondedAmount = (extrinsic) => {
|
|
42
|
+
return (
|
|
43
|
+
extrinsic?.staking?.eventStaking.reduce((acc, curr) => {
|
|
44
|
+
return curr.method === "Withdrawn"
|
|
45
|
+
? new BigNumber(acc).plus(curr.value)
|
|
46
|
+
: new BigNumber(0);
|
|
47
|
+
}, new BigNumber(0)) || new BigNumber(0)
|
|
48
|
+
);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const getController = (_extrinsic) => {
|
|
52
|
+
// TODO: ask BisonTrails to provide the info
|
|
53
|
+
return "";
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* add Extra info for operation details
|
|
58
|
+
*
|
|
59
|
+
* @param {OperationType} type
|
|
60
|
+
* @param {*} extrinsic
|
|
61
|
+
*
|
|
62
|
+
* @returns {Object}
|
|
63
|
+
*/
|
|
64
|
+
const getExtra = (type: OperationType, extrinsic: any): Record<string, any> => {
|
|
65
|
+
let extra: {
|
|
66
|
+
transferAmount?: BigNumber;
|
|
67
|
+
palletMethod: string;
|
|
68
|
+
bondedAmount?: BigNumber;
|
|
69
|
+
unbondedAmount?: BigNumber;
|
|
70
|
+
amount?: BigNumber;
|
|
71
|
+
withdrawUnbondedAmount?: any;
|
|
72
|
+
validatorStash?: any;
|
|
73
|
+
validators?: any;
|
|
74
|
+
controller?: any;
|
|
75
|
+
} = {
|
|
76
|
+
palletMethod: `${extrinsic.section}.${extrinsic.method}`,
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
switch (type) {
|
|
80
|
+
case "IN":
|
|
81
|
+
case "OUT":
|
|
82
|
+
if (extrinsic.amount || extrinsic.amount === 0) {
|
|
83
|
+
extra = { ...extra, transferAmount: new BigNumber(extrinsic.amount) };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
break;
|
|
87
|
+
|
|
88
|
+
case "BOND":
|
|
89
|
+
if (extrinsic.amount || extrinsic.amount === 0) {
|
|
90
|
+
extra = { ...extra, bondedAmount: new BigNumber(extrinsic.amount) };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
break;
|
|
94
|
+
|
|
95
|
+
case "UNBOND":
|
|
96
|
+
if (extrinsic.amount || extrinsic.amount === 0) {
|
|
97
|
+
extra = { ...extra, unbondedAmount: new BigNumber(extrinsic.amount) };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
break;
|
|
101
|
+
|
|
102
|
+
case "WITHDRAW_UNBONDED":
|
|
103
|
+
extra = {
|
|
104
|
+
...extra,
|
|
105
|
+
withdrawUnbondedAmount: getWithdrawUnbondedAmount(extrinsic),
|
|
106
|
+
};
|
|
107
|
+
break;
|
|
108
|
+
|
|
109
|
+
case "SET_CONTROLLER":
|
|
110
|
+
extra = {
|
|
111
|
+
...extra,
|
|
112
|
+
controller: getController(extrinsic),
|
|
113
|
+
};
|
|
114
|
+
break;
|
|
115
|
+
|
|
116
|
+
case "REWARD_PAYOUT":
|
|
117
|
+
case "SLASH":
|
|
118
|
+
extra = {
|
|
119
|
+
...extra,
|
|
120
|
+
validatorStash: extrinsic.validatorStash,
|
|
121
|
+
amount: new BigNumber(extrinsic.value),
|
|
122
|
+
};
|
|
123
|
+
break;
|
|
124
|
+
|
|
125
|
+
case "NOMINATE":
|
|
126
|
+
extra = {
|
|
127
|
+
...extra,
|
|
128
|
+
validators:
|
|
129
|
+
extrinsic.staking?.validators?.reduce((acc, current) => {
|
|
130
|
+
return [...acc, current.address];
|
|
131
|
+
}, []) ?? [],
|
|
132
|
+
};
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return extra;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Returns the operation value (amount if relevant + fees) depending on type
|
|
141
|
+
*
|
|
142
|
+
* @param {*} extrinsic
|
|
143
|
+
* @param {OperationType} type
|
|
144
|
+
*
|
|
145
|
+
* @returns {BigNumber}
|
|
146
|
+
*/
|
|
147
|
+
const getValue = (extrinsic, type: OperationType): BigNumber => {
|
|
148
|
+
if (!extrinsic.isSuccess) {
|
|
149
|
+
return type === "IN"
|
|
150
|
+
? new BigNumber(0)
|
|
151
|
+
: new BigNumber(extrinsic.partialFee || 0);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
switch (type) {
|
|
155
|
+
case "OUT":
|
|
156
|
+
return extrinsic.signer !== extrinsic.affectedAddress1
|
|
157
|
+
? new BigNumber(extrinsic.amount).plus(extrinsic.partialFee)
|
|
158
|
+
: new BigNumber(extrinsic.partialFee);
|
|
159
|
+
|
|
160
|
+
case "IN":
|
|
161
|
+
case "SLASH":
|
|
162
|
+
return new BigNumber(extrinsic.amount);
|
|
163
|
+
|
|
164
|
+
default:
|
|
165
|
+
return new BigNumber(extrinsic.partialFee);
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Map extrinsic into the live operation type
|
|
171
|
+
*
|
|
172
|
+
* @param {string} addr
|
|
173
|
+
* @param {string} accountId
|
|
174
|
+
* @param {*} extrinsic
|
|
175
|
+
*
|
|
176
|
+
* @returns {Operation | null}
|
|
177
|
+
*/
|
|
178
|
+
const extrinsicToOperation = (
|
|
179
|
+
addr: string,
|
|
180
|
+
accountId: string,
|
|
181
|
+
extrinsic
|
|
182
|
+
): Partial<Operation> | null => {
|
|
183
|
+
let type = getOperationType(extrinsic.section, extrinsic.method);
|
|
184
|
+
|
|
185
|
+
if (
|
|
186
|
+
type === "OUT" &&
|
|
187
|
+
extrinsic.affectedAddress1 === addr &&
|
|
188
|
+
extrinsic.signer !== addr
|
|
189
|
+
) {
|
|
190
|
+
type = "IN";
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (type !== "IN" && extrinsic.signer !== addr) {
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return {
|
|
198
|
+
id: encodeOperationId(accountId, extrinsic.hash, type),
|
|
199
|
+
accountId,
|
|
200
|
+
fee: new BigNumber(extrinsic.partialFee || 0),
|
|
201
|
+
value: getValue(extrinsic, type),
|
|
202
|
+
type,
|
|
203
|
+
hash: extrinsic.hash,
|
|
204
|
+
blockHeight: extrinsic.blockNumber,
|
|
205
|
+
date: new Date(extrinsic.timestamp),
|
|
206
|
+
extra: getExtra(type, extrinsic),
|
|
207
|
+
senders: [extrinsic.signer],
|
|
208
|
+
recipients: [extrinsic.affectedAddress1, extrinsic.affectedAddress2]
|
|
209
|
+
.filter(Boolean)
|
|
210
|
+
.filter(isValidAddress),
|
|
211
|
+
transactionSequenceNumber:
|
|
212
|
+
extrinsic.signer === addr ? extrinsic.nonce : undefined,
|
|
213
|
+
hasFailed: !extrinsic.isSuccess,
|
|
214
|
+
};
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Map reward to live operation type
|
|
219
|
+
*
|
|
220
|
+
* @param {string} addr
|
|
221
|
+
* @param {string} accountId
|
|
222
|
+
* @param {*} reward
|
|
223
|
+
*
|
|
224
|
+
* @returns {Operation | null}
|
|
225
|
+
*/
|
|
226
|
+
const rewardToOperation = (
|
|
227
|
+
addr: string,
|
|
228
|
+
accountId: string,
|
|
229
|
+
reward
|
|
230
|
+
): Partial<Operation> => {
|
|
231
|
+
const hash = reward.extrinsicHash;
|
|
232
|
+
const type = "REWARD_PAYOUT";
|
|
233
|
+
return {
|
|
234
|
+
id: encodeOperationId(accountId, `${hash}+${reward.index}`, type),
|
|
235
|
+
accountId,
|
|
236
|
+
fee: new BigNumber(0),
|
|
237
|
+
value: new BigNumber(reward.value),
|
|
238
|
+
type: type,
|
|
239
|
+
hash,
|
|
240
|
+
blockHeight: reward.blockNumber,
|
|
241
|
+
date: new Date(reward.timestamp),
|
|
242
|
+
extra: getExtra(type, reward),
|
|
243
|
+
senders: [reward.validatorStash].filter(Boolean),
|
|
244
|
+
recipients: [reward.accountId].filter(Boolean),
|
|
245
|
+
};
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Map slash to live operation type
|
|
250
|
+
*
|
|
251
|
+
* @param {string} addr
|
|
252
|
+
* @param {string} accountId
|
|
253
|
+
* @param {*} slash
|
|
254
|
+
*
|
|
255
|
+
* @returns {Operation | null}
|
|
256
|
+
*/
|
|
257
|
+
const slashToOperation = (
|
|
258
|
+
addr: string,
|
|
259
|
+
accountId: string,
|
|
260
|
+
slash
|
|
261
|
+
): Partial<Operation> => {
|
|
262
|
+
const hash = `${slash.blockNumber}`;
|
|
263
|
+
const type = "SLASH";
|
|
264
|
+
return {
|
|
265
|
+
id: encodeOperationId(accountId, `${hash}+${slash.index}`, type),
|
|
266
|
+
accountId,
|
|
267
|
+
fee: new BigNumber(0),
|
|
268
|
+
value: new BigNumber(slash.value),
|
|
269
|
+
type: type,
|
|
270
|
+
hash: hash,
|
|
271
|
+
blockHeight: slash.blockNumber,
|
|
272
|
+
senders: [slash.validatorStash].filter(Boolean),
|
|
273
|
+
recipients: [slash.accountId].filter(Boolean),
|
|
274
|
+
date: new Date(slash.timestamp),
|
|
275
|
+
extra: getExtra(type, slash),
|
|
276
|
+
};
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Fetch loop with multiple operations per page / offsite / start
|
|
281
|
+
*
|
|
282
|
+
* @param {string} accountId
|
|
283
|
+
* @param {string} addr
|
|
284
|
+
* @param {number} startAt
|
|
285
|
+
* @param {number} offset
|
|
286
|
+
*
|
|
287
|
+
* @param {Operation[]} prevOperations
|
|
288
|
+
*/
|
|
289
|
+
const fetchOperationList = async (
|
|
290
|
+
accountId: string,
|
|
291
|
+
addr: string,
|
|
292
|
+
startAt: number,
|
|
293
|
+
offset = 0,
|
|
294
|
+
prevOperations: Operation[] = []
|
|
295
|
+
) => {
|
|
296
|
+
const { data } = await network({
|
|
297
|
+
method: "GET",
|
|
298
|
+
url: getAccountOperationUrl(addr, offset, startAt),
|
|
299
|
+
});
|
|
300
|
+
const operations = data.extrinsics.map((extrinsic) =>
|
|
301
|
+
extrinsicToOperation(addr, accountId, extrinsic)
|
|
302
|
+
);
|
|
303
|
+
const rewards = data.rewards.map((reward) =>
|
|
304
|
+
rewardToOperation(addr, accountId, reward)
|
|
305
|
+
);
|
|
306
|
+
const slashes = data.slashes.map((slash) =>
|
|
307
|
+
slashToOperation(addr, accountId, slash)
|
|
308
|
+
);
|
|
309
|
+
const mergedOp = [...prevOperations, ...operations, ...rewards, ...slashes];
|
|
310
|
+
|
|
311
|
+
if (
|
|
312
|
+
operations.length < LIMIT &&
|
|
313
|
+
rewards.length < LIMIT &&
|
|
314
|
+
slashes.length < LIMIT
|
|
315
|
+
) {
|
|
316
|
+
return mergedOp.filter(Boolean).sort((a, b) => b.date - a.date);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
return await fetchOperationList(
|
|
320
|
+
accountId,
|
|
321
|
+
addr,
|
|
322
|
+
startAt,
|
|
323
|
+
offset + LIMIT,
|
|
324
|
+
mergedOp
|
|
325
|
+
);
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Fetch all operations for a single account from indexer
|
|
330
|
+
*
|
|
331
|
+
* @param {string} accountId
|
|
332
|
+
* @param {string} addr
|
|
333
|
+
* @param {number} startAt - blockHeight after which you fetch this op (included)
|
|
334
|
+
*
|
|
335
|
+
* @return {Operation[]}
|
|
336
|
+
*/
|
|
337
|
+
export const getOperations = async (
|
|
338
|
+
accountId: string,
|
|
339
|
+
addr: string,
|
|
340
|
+
startAt = 0
|
|
341
|
+
) => {
|
|
342
|
+
return await fetchOperationList(accountId, addr, startAt);
|
|
343
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { log } from "@ledgerhq/logs";
|
|
2
|
+
import type { OperationType } from "@ledgerhq/types-live";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Returns the operation type by using his palletMethod
|
|
6
|
+
* the method case depends from which indexer you are using
|
|
7
|
+
*
|
|
8
|
+
* @param {*} pallet
|
|
9
|
+
* @param {*} palletMethod
|
|
10
|
+
*
|
|
11
|
+
* @returns {string} - OperationType
|
|
12
|
+
*/
|
|
13
|
+
export const getOperationType = (
|
|
14
|
+
pallet: string,
|
|
15
|
+
palletMethod: string
|
|
16
|
+
): OperationType => {
|
|
17
|
+
switch (palletMethod) {
|
|
18
|
+
case "transfer":
|
|
19
|
+
case "transferKeepAlive":
|
|
20
|
+
return "OUT";
|
|
21
|
+
|
|
22
|
+
case "bond":
|
|
23
|
+
case "bondExtra":
|
|
24
|
+
case "rebond":
|
|
25
|
+
return "BOND";
|
|
26
|
+
|
|
27
|
+
case "unbond":
|
|
28
|
+
return "UNBOND";
|
|
29
|
+
|
|
30
|
+
case "nominate":
|
|
31
|
+
return "NOMINATE";
|
|
32
|
+
|
|
33
|
+
case "chill":
|
|
34
|
+
return "CHILL";
|
|
35
|
+
|
|
36
|
+
case "withdrawUnbonded":
|
|
37
|
+
return "WITHDRAW_UNBONDED";
|
|
38
|
+
|
|
39
|
+
case "setController":
|
|
40
|
+
return "SET_CONTROLLER";
|
|
41
|
+
|
|
42
|
+
case "payoutStakers":
|
|
43
|
+
return "FEES";
|
|
44
|
+
|
|
45
|
+
default:
|
|
46
|
+
log(
|
|
47
|
+
"polkadot/api",
|
|
48
|
+
`Unknown operation type ${pallet}.${palletMethod} - fallback to FEES`
|
|
49
|
+
);
|
|
50
|
+
return "FEES";
|
|
51
|
+
}
|
|
52
|
+
};
|