@ledgerhq/live-common 21.19.7 → 21.20.0
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/lib/__tests__/svg.d.ts +9 -0
- package/lib/__tests__/svg.d.ts.map +1 -0
- package/lib/__tests__/svg.js +105 -0
- package/lib/__tests__/svg.js.map +1 -0
- package/lib/bridge/jsHelpers.d.ts +1 -1
- package/lib/bridge/jsHelpers.d.ts.map +1 -1
- package/lib/bridge/jsHelpers.js +7 -8
- package/lib/bridge/jsHelpers.js.map +1 -1
- package/lib/data/icons/react/index.d.ts +0 -2
- package/lib/data/icons/react/index.d.ts.map +1 -1
- package/lib/data/icons/react/index.js +8 -12
- package/lib/data/icons/react/index.js.map +1 -1
- package/lib/data/icons/react/matic.js +2 -2
- package/lib/data/icons/react/matic.js.map +1 -1
- package/lib/data/icons/reactNative/index.d.ts +0 -2
- package/lib/data/icons/reactNative/index.d.ts.map +1 -1
- package/lib/data/icons/reactNative/index.js +8 -12
- package/lib/data/icons/reactNative/index.js.map +1 -1
- package/lib/data/icons/reactNative/matic.js +2 -2
- package/lib/data/icons/reactNative/matic.js.map +1 -1
- package/lib/families/ethereum/modules/compound.resilience.test.js +2 -18
- package/lib/families/ethereum/modules/compound.resilience.test.js.map +1 -1
- package/lib/families/ethereum/modules/erc20.d.ts.map +1 -1
- package/lib/families/ethereum/modules/erc20.js +0 -12
- package/lib/families/ethereum/modules/erc20.js.map +1 -1
- package/lib/families/ethereum/modules/erc721.d.ts.map +1 -1
- package/lib/families/ethereum/modules/erc721.js +0 -1
- package/lib/families/ethereum/modules/erc721.js.map +1 -1
- package/lib/families/ethereum/nft.integration.test.d.ts +2 -0
- package/lib/families/ethereum/nft.integration.test.d.ts.map +1 -0
- package/lib/families/ethereum/nft.integration.test.js +264 -0
- package/lib/families/ethereum/nft.integration.test.js.map +1 -0
- package/lib/families/ethereum/nft.merging.unit.test.d.ts +2 -0
- package/lib/families/ethereum/nft.merging.unit.test.d.ts.map +1 -0
- package/lib/families/ethereum/nft.merging.unit.test.js +72 -0
- package/lib/families/ethereum/nft.merging.unit.test.js.map +1 -0
- package/lib/families/ethereum/synchronisation.js +5 -5
- package/lib/families/ethereum/synchronisation.js.map +1 -1
- package/lib/nft/NftMetadataProvider/index.d.ts +3 -2
- package/lib/nft/NftMetadataProvider/index.d.ts.map +1 -1
- package/lib/nft/NftMetadataProvider/index.js +9 -2
- package/lib/nft/NftMetadataProvider/index.js.map +1 -1
- package/lib/operation.d.ts.map +1 -1
- package/lib/operation.js +0 -2
- package/lib/operation.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/svg.ts +78 -0
- package/src/bridge/jsHelpers.ts +9 -15
- package/src/data/icons/react/index.tsx +0 -2
- package/src/data/icons/react/matic.tsx +1 -1
- package/src/data/icons/reactNative/index.tsx +0 -2
- package/src/data/icons/reactNative/matic.tsx +1 -1
- package/src/data/icons/svg/MATIC.svg +2 -2
- package/src/families/ethereum/modules/compound.resilience.test.ts +2 -18
- package/src/families/ethereum/modules/erc20.ts +0 -4
- package/src/families/ethereum/modules/erc721.ts +0 -4
- package/src/families/ethereum/nft.integration.test.ts +168 -0
- package/src/families/ethereum/nft.merging.unit.test.ts +78 -0
- package/src/families/ethereum/synchronisation.ts +5 -5
- package/src/nft/NftMetadataProvider/index.tsx +12 -3
- package/src/operation.ts +0 -2
- package/lib/data/icons/react/cro.d.ts +0 -8
- package/lib/data/icons/react/cro.d.ts.map +0 -1
- package/lib/data/icons/react/cro.js +0 -30
- package/lib/data/icons/react/cro.js.map +0 -1
- package/lib/data/icons/react/grs.d.ts +0 -8
- package/lib/data/icons/react/grs.d.ts.map +0 -1
- package/lib/data/icons/react/grs.js +0 -34
- package/lib/data/icons/react/grs.js.map +0 -1
- package/lib/data/icons/reactNative/cro.d.ts +0 -8
- package/lib/data/icons/reactNative/cro.d.ts.map +0 -1
- package/lib/data/icons/reactNative/cro.js +0 -31
- package/lib/data/icons/reactNative/cro.js.map +0 -1
- package/lib/data/icons/reactNative/grs.d.ts +0 -8
- package/lib/data/icons/reactNative/grs.d.ts.map +0 -1
- package/lib/data/icons/reactNative/grs.js +0 -35
- package/lib/data/icons/reactNative/grs.js.map +0 -1
- package/lib/families/ethereum/nft.test.d.ts +0 -2
- package/lib/families/ethereum/nft.test.d.ts.map +0 -1
- package/lib/families/ethereum/nft.test.js +0 -360
- package/lib/families/ethereum/nft.test.js.map +0 -1
- package/src/data/icons/react/cro.tsx +0 -12
- package/src/data/icons/react/grs.tsx +0 -12
- package/src/data/icons/reactNative/cro.tsx +0 -13
- package/src/data/icons/reactNative/grs.tsx +0 -13
- package/src/data/icons/svg/CRO.svg +0 -3
- package/src/data/icons/svg/GRS.svg +0 -10
- package/src/families/ethereum/modules/__snapshots__/compound.resilience.test.ts.snap +0 -15991
- package/src/families/ethereum/nft.test.ts +0 -263
package/package.json
CHANGED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import glob from "glob";
|
|
3
|
+
import path from "path";
|
|
4
|
+
|
|
5
|
+
const rootDir = path.join(__dirname, "../data");
|
|
6
|
+
|
|
7
|
+
declare global {
|
|
8
|
+
namespace jest {
|
|
9
|
+
interface Matchers<R> {
|
|
10
|
+
toBeValidSvg(a: string, b: string): R;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
expect.extend({
|
|
16
|
+
toBeValidSvg(received, fileName, errorMessage) {
|
|
17
|
+
if (received) {
|
|
18
|
+
return {
|
|
19
|
+
message: () => `Svg: ${fileName} valid`,
|
|
20
|
+
pass: true,
|
|
21
|
+
};
|
|
22
|
+
} else {
|
|
23
|
+
return {
|
|
24
|
+
message: () => `Svg: ${fileName} invalid
|
|
25
|
+
${errorMessage}
|
|
26
|
+
`,
|
|
27
|
+
pass: false,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("svg icons valid", async () => {
|
|
34
|
+
glob.sync(`${rootDir}/icons/svg/*.svg`).map((svgFileName) => {
|
|
35
|
+
const buffer = fs.readFileSync(svgFileName);
|
|
36
|
+
const fileContent = buffer.toString();
|
|
37
|
+
|
|
38
|
+
const tags = fileContent.match(/<[^>]*?>/g) || [];
|
|
39
|
+
|
|
40
|
+
expect(tags.length > 1).toBeTruthy();
|
|
41
|
+
|
|
42
|
+
tags.forEach((element, i) => {
|
|
43
|
+
if (i === 0) {
|
|
44
|
+
const m = /width="([^"]+)"/.exec(element);
|
|
45
|
+
if (!m) {
|
|
46
|
+
throw new Error("no width found in " + svgFileName);
|
|
47
|
+
}
|
|
48
|
+
const [, size] = m;
|
|
49
|
+
expect(element.includes('height="' + size + '"')).toBeValidSvg(
|
|
50
|
+
svgFileName,
|
|
51
|
+
"Must contain height of same width. " + element
|
|
52
|
+
);
|
|
53
|
+
expect(
|
|
54
|
+
element.includes('viewBox="0 0 ' + size + " " + size + '"')
|
|
55
|
+
).toBeValidSvg(svgFileName, "Must contain correct viewport");
|
|
56
|
+
expect(!/style=/.test(element)).toBeValidSvg(
|
|
57
|
+
svgFileName,
|
|
58
|
+
"Must not contain style attrs. " + element
|
|
59
|
+
);
|
|
60
|
+
} else {
|
|
61
|
+
expect(
|
|
62
|
+
/svg|path|line|rect|ellipse|polyline|polygon|circle|g/.test(element)
|
|
63
|
+
).toBeValidSvg(
|
|
64
|
+
svgFileName,
|
|
65
|
+
"must only contain svg|path|line|rect|ellipse|polyline|polygon|circle|g"
|
|
66
|
+
);
|
|
67
|
+
expect(
|
|
68
|
+
!/style=|clipPath|mask|id=|class=|url\(|clip-path|data|defs/.test(
|
|
69
|
+
element
|
|
70
|
+
)
|
|
71
|
+
).toBeValidSvg(
|
|
72
|
+
svgFileName,
|
|
73
|
+
"must not contain style=|clipPath|mask|id|class|url|clip-path|data|defs"
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
});
|
package/src/bridge/jsHelpers.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import isEqual from "lodash/isEqual";
|
|
2
|
-
import setWith from "lodash/setWith";
|
|
3
2
|
import { BigNumber } from "bignumber.js";
|
|
4
3
|
import { Observable, from } from "rxjs";
|
|
5
4
|
import { log } from "@ledgerhq/logs";
|
|
@@ -64,7 +63,7 @@ type AccountUpdater = (arg0: Account) => Account;
|
|
|
64
63
|
const sameDate = (a, b) => Math.abs(a - b) < 1000 * 60 * 30;
|
|
65
64
|
|
|
66
65
|
// an operation is relatively immutable, however we saw that sometimes it can temporarily change due to reorg,..
|
|
67
|
-
export const sameOp = (a: Operation, b: Operation) =>
|
|
66
|
+
export const sameOp = (a: Operation, b: Operation): boolean =>
|
|
68
67
|
a === b ||
|
|
69
68
|
(a.id === b.id && // hash, accountId, type are in id
|
|
70
69
|
(a.fee ? a.fee.isEqualTo(b.fee) : a.fee === b.fee) &&
|
|
@@ -119,20 +118,15 @@ Operation[] {
|
|
|
119
118
|
return all;
|
|
120
119
|
}
|
|
121
120
|
|
|
122
|
-
export const mergeNfts = (
|
|
123
|
-
oldNfts: NFT[] | undefined,
|
|
124
|
-
newNfts: NFT[] | undefined
|
|
125
|
-
): NFT[] => {
|
|
126
|
-
if (!newNfts?.length) return oldNfts ?? [];
|
|
127
|
-
|
|
121
|
+
export const mergeNfts = (oldNfts: NFT[], newNfts: NFT[]): NFT[] => {
|
|
128
122
|
// Getting a map of id => NFT
|
|
129
|
-
const newNftsPerId: Record<string, NFT> =
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
);
|
|
123
|
+
const newNftsPerId: Record<string, NFT> = {};
|
|
124
|
+
newNfts.forEach((n) => {
|
|
125
|
+
newNftsPerId[n.id] = n;
|
|
126
|
+
});
|
|
133
127
|
|
|
134
128
|
// copying the argument to avoid mutating it
|
|
135
|
-
const nfts = oldNfts
|
|
129
|
+
const nfts = oldNfts.slice();
|
|
136
130
|
for (let i = 0; i < nfts.length; i++) {
|
|
137
131
|
const nft = nfts[i];
|
|
138
132
|
|
|
@@ -141,8 +135,8 @@ export const mergeNfts = (
|
|
|
141
135
|
nfts.splice(i, 1);
|
|
142
136
|
i--;
|
|
143
137
|
} else if (!isEqual(nft, newNftsPerId[nft.id])) {
|
|
144
|
-
// Use the new NFT instead
|
|
145
|
-
nfts[i] =
|
|
138
|
+
// Use the new NFT instead
|
|
139
|
+
nfts[i] = newNftsPerId[nft.id];
|
|
146
140
|
}
|
|
147
141
|
|
|
148
142
|
// Delete it from the newNfts to keep only the un-added ones at the end
|
|
@@ -95,7 +95,6 @@ export { default as colx } from "./colx";
|
|
|
95
95
|
export { default as comp } from "./comp";
|
|
96
96
|
export { default as coqui } from "./coqui";
|
|
97
97
|
export { default as cred } from "./cred";
|
|
98
|
-
export { default as cro } from "./cro";
|
|
99
98
|
export { default as crpt } from "./crpt";
|
|
100
99
|
export { default as crw } from "./crw";
|
|
101
100
|
export { default as cs } from "./cs";
|
|
@@ -179,7 +178,6 @@ export { default as gnt } from "./gnt";
|
|
|
179
178
|
export { default as gold } from "./gold";
|
|
180
179
|
export { default as grc } from "./grc";
|
|
181
180
|
export { default as grin } from "./grin";
|
|
182
|
-
export { default as grs } from "./grs";
|
|
183
181
|
export { default as gsc } from "./gsc";
|
|
184
182
|
export { default as gto } from "./gto";
|
|
185
183
|
export { default as gup } from "./gup";
|
|
@@ -6,7 +6,7 @@ interface Props {
|
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
function matic({size, color = "currentColor"}: Props) {
|
|
9
|
-
return <svg width={size} height={size} viewBox="0 0 24 24" fill="none"
|
|
9
|
+
return <svg width={size} height={size} viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M17.0922 8.69345C16.7232 8.47781 16.2435 8.47781 15.8377 8.69345L12.9594 10.3467L11.0037 11.425L8.12546 13.0782C7.75645 13.2939 7.27675 13.2939 6.87085 13.0782L4.58303 11.7843C4.21402 11.5687 3.95572 11.1734 3.95572 10.7421V8.19028C3.95572 7.75899 4.17712 7.36364 4.58303 7.14799L6.83394 5.89007C7.20295 5.67442 7.68265 5.67442 8.08855 5.89007L10.3395 7.14799C10.7085 7.36364 10.9668 7.75899 10.9668 8.19028V9.84356L12.9225 8.72939V7.07612C12.9225 6.64482 12.7011 6.24947 12.2952 6.03383L8.12546 3.66173C7.75645 3.44609 7.27675 3.44609 6.87085 3.66173L2.62731 6.03383C2.2214 6.24947 2 6.64482 2 7.07612V11.8563C2 12.2875 2.2214 12.6829 2.62731 12.8986L6.87085 15.2706C7.23984 15.4863 7.71956 15.4863 8.12546 15.2706L11.0037 13.6533L12.9594 12.5391L15.8377 10.9218C16.2066 10.7061 16.6863 10.7061 17.0922 10.9218L19.3432 12.1797C19.7121 12.3954 19.9704 12.7907 19.9704 13.222V15.7738C19.9704 16.2051 19.7491 16.6004 19.3432 16.8161L17.0922 18.11C16.7232 18.3256 16.2435 18.3256 15.8377 18.11L13.5867 16.852C13.2177 16.6364 12.9594 16.241 12.9594 15.8097V14.1565L11.0037 15.2706V16.9239C11.0037 17.3552 11.2251 17.7505 11.631 17.9662L15.8745 20.3383C16.2435 20.5539 16.7232 20.5539 17.1291 20.3383L21.3727 17.9662C21.7417 17.7505 22 17.3552 22 16.9239V12.1437C22 11.7125 21.7786 11.3172 21.3727 11.1015L17.0922 8.69345Z" fill={color} /></svg>;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export default matic;
|
|
@@ -95,7 +95,6 @@ export { default as colx } from "./colx";
|
|
|
95
95
|
export { default as comp } from "./comp";
|
|
96
96
|
export { default as coqui } from "./coqui";
|
|
97
97
|
export { default as cred } from "./cred";
|
|
98
|
-
export { default as cro } from "./cro";
|
|
99
98
|
export { default as crpt } from "./crpt";
|
|
100
99
|
export { default as crw } from "./crw";
|
|
101
100
|
export { default as cs } from "./cs";
|
|
@@ -179,7 +178,6 @@ export { default as gnt } from "./gnt";
|
|
|
179
178
|
export { default as gold } from "./gold";
|
|
180
179
|
export { default as grc } from "./grc";
|
|
181
180
|
export { default as grin } from "./grin";
|
|
182
|
-
export { default as grs } from "./grs";
|
|
183
181
|
export { default as gsc } from "./gsc";
|
|
184
182
|
export { default as gto } from "./gto";
|
|
185
183
|
export { default as gup } from "./gup";
|
|
@@ -7,7 +7,7 @@ interface Props {
|
|
|
7
7
|
};
|
|
8
8
|
|
|
9
9
|
function matic({ size, color }: Props) {
|
|
10
|
-
return <Svg width={size} height={size} viewBox="0 0 24 24" fill="none"
|
|
10
|
+
return <Svg width={size} height={size} viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><Path d="M17.0922 8.69345C16.7232 8.47781 16.2435 8.47781 15.8377 8.69345L12.9594 10.3467L11.0037 11.425L8.12546 13.0782C7.75645 13.2939 7.27675 13.2939 6.87085 13.0782L4.58303 11.7843C4.21402 11.5687 3.95572 11.1734 3.95572 10.7421V8.19028C3.95572 7.75899 4.17712 7.36364 4.58303 7.14799L6.83394 5.89007C7.20295 5.67442 7.68265 5.67442 8.08855 5.89007L10.3395 7.14799C10.7085 7.36364 10.9668 7.75899 10.9668 8.19028V9.84356L12.9225 8.72939V7.07612C12.9225 6.64482 12.7011 6.24947 12.2952 6.03383L8.12546 3.66173C7.75645 3.44609 7.27675 3.44609 6.87085 3.66173L2.62731 6.03383C2.2214 6.24947 2 6.64482 2 7.07612V11.8563C2 12.2875 2.2214 12.6829 2.62731 12.8986L6.87085 15.2706C7.23984 15.4863 7.71956 15.4863 8.12546 15.2706L11.0037 13.6533L12.9594 12.5391L15.8377 10.9218C16.2066 10.7061 16.6863 10.7061 17.0922 10.9218L19.3432 12.1797C19.7121 12.3954 19.9704 12.7907 19.9704 13.222V15.7738C19.9704 16.2051 19.7491 16.6004 19.3432 16.8161L17.0922 18.11C16.7232 18.3256 16.2435 18.3256 15.8377 18.11L13.5867 16.852C13.2177 16.6364 12.9594 16.241 12.9594 15.8097V14.1565L11.0037 15.2706V16.9239C11.0037 17.3552 11.2251 17.7505 11.631 17.9662L15.8745 20.3383C16.2435 20.5539 16.7232 20.5539 17.1291 20.3383L21.3727 17.9662C21.7417 17.7505 22 17.3552 22 16.9239V12.1437C22 11.7125 21.7786 11.3172 21.3727 11.1015L17.0922 8.69345Z" fill={color} /></Svg>;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export default matic;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
|
|
2
|
-
<path
|
|
1
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M17.0922 8.69345C16.7232 8.47781 16.2435 8.47781 15.8377 8.69345L12.9594 10.3467L11.0037 11.425L8.12546 13.0782C7.75645 13.2939 7.27675 13.2939 6.87085 13.0782L4.58303 11.7843C4.21402 11.5687 3.95572 11.1734 3.95572 10.7421V8.19028C3.95572 7.75899 4.17712 7.36364 4.58303 7.14799L6.83394 5.89007C7.20295 5.67442 7.68265 5.67442 8.08855 5.89007L10.3395 7.14799C10.7085 7.36364 10.9668 7.75899 10.9668 8.19028V9.84356L12.9225 8.72939V7.07612C12.9225 6.64482 12.7011 6.24947 12.2952 6.03383L8.12546 3.66173C7.75645 3.44609 7.27675 3.44609 6.87085 3.66173L2.62731 6.03383C2.2214 6.24947 2 6.64482 2 7.07612V11.8563C2 12.2875 2.2214 12.6829 2.62731 12.8986L6.87085 15.2706C7.23984 15.4863 7.71956 15.4863 8.12546 15.2706L11.0037 13.6533L12.9594 12.5391L15.8377 10.9218C16.2066 10.7061 16.6863 10.7061 17.0922 10.9218L19.3432 12.1797C19.7121 12.3954 19.9704 12.7907 19.9704 13.222V15.7738C19.9704 16.2051 19.7491 16.6004 19.3432 16.8161L17.0922 18.11C16.7232 18.3256 16.2435 18.3256 15.8377 18.11L13.5867 16.852C13.2177 16.6364 12.9594 16.241 12.9594 15.8097V14.1565L11.0037 15.2706V16.9239C11.0037 17.3552 11.2251 17.7505 11.631 17.9662L15.8745 20.3383C16.2435 20.5539 16.7232 20.5539 17.1291 20.3383L21.3727 17.9662C21.7417 17.7505 22 17.3552 22 16.9239V12.1437C22 11.7125 21.7786 11.3172 21.3727 11.1015L17.0922 8.69345Z" fill="#8247E5"/>
|
|
3
3
|
</svg>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "../../../__tests__/test-helpers/setup";
|
|
2
2
|
import { reduce } from "rxjs/operators";
|
|
3
|
-
import { fromAccountRaw
|
|
3
|
+
import { fromAccountRaw } from "../../../account";
|
|
4
4
|
import type { Account } from "../../../types";
|
|
5
5
|
import { getAccountBridge } from "../../../bridge";
|
|
6
6
|
import { makeBridgeCacheSystem } from "../../../bridge/cache";
|
|
@@ -33,21 +33,5 @@ test("if API is down, an account still sync fine", async () => {
|
|
|
33
33
|
})
|
|
34
34
|
.pipe(reduce((a, f: (arg0: Account) => Account) => f(a), account))
|
|
35
35
|
.toPromise();
|
|
36
|
-
|
|
37
|
-
// empty unstable fields
|
|
38
|
-
raw.blockHeight = 0;
|
|
39
|
-
raw.lastSyncDate = "";
|
|
40
|
-
raw.creationDate = "";
|
|
41
|
-
delete raw.balanceHistoryCache;
|
|
42
|
-
delete raw.syncHash;
|
|
43
|
-
raw.subAccounts = (raw.subAccounts || []).map((a) => {
|
|
44
|
-
delete a.balanceHistoryCache;
|
|
45
|
-
return a;
|
|
46
|
-
});
|
|
47
|
-
raw.operations = raw.operations.map((op) => {
|
|
48
|
-
op.blockHeight = 0;
|
|
49
|
-
op.date = "";
|
|
50
|
-
return op;
|
|
51
|
-
});
|
|
52
|
-
expect(raw).toMatchSnapshot();
|
|
36
|
+
expect(synced).not.toBeFalsy();
|
|
53
37
|
});
|
|
@@ -137,10 +137,6 @@ const erc20approve: ModeModule = {
|
|
|
137
137
|
|
|
138
138
|
fillOptimisticOperation(_account, _transaction, operation) {
|
|
139
139
|
operation.type = "FEES";
|
|
140
|
-
operation.extra = {
|
|
141
|
-
...operation.extra,
|
|
142
|
-
approving: true, // workaround to track the status ENABLING
|
|
143
|
-
};
|
|
144
140
|
},
|
|
145
141
|
};
|
|
146
142
|
export const modes: Record<Modes, ModeModule> = {
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import "../../__tests__/test-helpers/setup";
|
|
2
|
+
import { reduce } from "rxjs/operators";
|
|
3
|
+
import { fromAccountRaw, toAccountRaw } from "../../account";
|
|
4
|
+
import type { Account, AccountRaw } from "../../types";
|
|
5
|
+
import { getAccountBridge } from "../../bridge";
|
|
6
|
+
import { makeBridgeCacheSystem } from "../../bridge/cache";
|
|
7
|
+
import { patchAccount } from "../../reconciliation";
|
|
8
|
+
import { setEnv } from "../../env";
|
|
9
|
+
|
|
10
|
+
jest.setTimeout(200000);
|
|
11
|
+
|
|
12
|
+
const ethTestingAccounts: AccountRaw[] = [
|
|
13
|
+
{
|
|
14
|
+
id: "js:1:ethereum:0xb98d10d9f6d07ba283bfd21b2dfec050f9ae282a:",
|
|
15
|
+
seedIdentifier: "0xb98d10d9f6d07ba283bfd21b2dfec050f9ae282a",
|
|
16
|
+
name: "G4sp4rd",
|
|
17
|
+
derivationMode: "",
|
|
18
|
+
index: 0,
|
|
19
|
+
freshAddress: "0xb98d10d9f6d07ba283bfd21b2dfec050f9ae282a",
|
|
20
|
+
freshAddressPath: "44'/60'/0'/0/0",
|
|
21
|
+
freshAddresses: [],
|
|
22
|
+
pendingOperations: [],
|
|
23
|
+
operations: [],
|
|
24
|
+
currencyId: "ethereum",
|
|
25
|
+
unitMagnitude: 18,
|
|
26
|
+
balance: "",
|
|
27
|
+
blockHeight: 0,
|
|
28
|
+
lastSyncDate: "",
|
|
29
|
+
xpub: "",
|
|
30
|
+
},
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
const gaspardPolygonAccount: AccountRaw = {
|
|
34
|
+
id: "js:1:polygon:0xb98d10d9f6d07ba283bfd21b2dfec050f9ae282a:",
|
|
35
|
+
seedIdentifier: "0xb98d10d9f6d07ba283bfd21b2dfec050f9ae282a",
|
|
36
|
+
name: "G4sp4rd",
|
|
37
|
+
derivationMode: "",
|
|
38
|
+
index: 0,
|
|
39
|
+
freshAddress: "0xb98d10d9f6d07ba283bfd21b2dfec050f9ae282a",
|
|
40
|
+
freshAddressPath: "44'/60'/0'/0/0",
|
|
41
|
+
freshAddresses: [],
|
|
42
|
+
pendingOperations: [],
|
|
43
|
+
operations: [],
|
|
44
|
+
currencyId: "polygon",
|
|
45
|
+
unitMagnitude: 18,
|
|
46
|
+
balance: "",
|
|
47
|
+
blockHeight: 0,
|
|
48
|
+
lastSyncDate: "",
|
|
49
|
+
xpub: "",
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const gaspardBscAccount: AccountRaw = {
|
|
53
|
+
id: "js:1:bsc:0xb98d10d9f6d07ba283bfd21b2dfec050f9ae282a:",
|
|
54
|
+
seedIdentifier: "0xb98d10d9f6d07ba283bfd21b2dfec050f9ae282a",
|
|
55
|
+
name: "G4sp4rd",
|
|
56
|
+
derivationMode: "",
|
|
57
|
+
index: 0,
|
|
58
|
+
freshAddress: "0xb98d10d9f6d07ba283bfd21b2dfec050f9ae282a",
|
|
59
|
+
freshAddressPath: "44'/60'/0'/0/0",
|
|
60
|
+
freshAddresses: [],
|
|
61
|
+
pendingOperations: [],
|
|
62
|
+
operations: [],
|
|
63
|
+
currencyId: "bsc",
|
|
64
|
+
unitMagnitude: 18,
|
|
65
|
+
balance: "",
|
|
66
|
+
blockHeight: 0,
|
|
67
|
+
lastSyncDate: "",
|
|
68
|
+
xpub: "",
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
async function sync(account, withNFT = true) {
|
|
72
|
+
const bridge = getAccountBridge(account);
|
|
73
|
+
const blacklistedTokenIds = [];
|
|
74
|
+
setEnv("NFT", withNFT);
|
|
75
|
+
const r = await bridge
|
|
76
|
+
.sync(account, {
|
|
77
|
+
paginationConfig: {},
|
|
78
|
+
blacklistedTokenIds,
|
|
79
|
+
})
|
|
80
|
+
.pipe(reduce((a, f: (arg0: Account) => Account) => f(a), account))
|
|
81
|
+
.toPromise();
|
|
82
|
+
setEnv("NFT", false);
|
|
83
|
+
return r;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const localCache = {};
|
|
87
|
+
const cache = makeBridgeCacheSystem({
|
|
88
|
+
saveData(c, d) {
|
|
89
|
+
localCache[c.id] = d;
|
|
90
|
+
return Promise.resolve();
|
|
91
|
+
},
|
|
92
|
+
getData(c) {
|
|
93
|
+
return Promise.resolve(localCache[c.id]);
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
ethTestingAccounts.forEach((a) => {
|
|
98
|
+
describe(a.name + " NFT on ethereum", () => {
|
|
99
|
+
let account = fromAccountRaw(a);
|
|
100
|
+
|
|
101
|
+
test("first sync & have nfts", async () => {
|
|
102
|
+
await cache.prepareCurrency(account.currency);
|
|
103
|
+
account = await sync(account);
|
|
104
|
+
expect(account.nfts?.length || 0).not.toBe(0);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test("no nft should be on quantity 0 or negative", () => {
|
|
108
|
+
expect(account.nfts?.find((n) => !n.amount.gt(0))).toEqual(undefined);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test("patchAccount restore new NFTs correctly", () => {
|
|
112
|
+
const copy = {
|
|
113
|
+
...account,
|
|
114
|
+
operations: [],
|
|
115
|
+
nfts: account.nfts?.slice(Math.ceil((account.nfts?.length || 0) / 2)),
|
|
116
|
+
};
|
|
117
|
+
const newAccount = patchAccount(copy, toAccountRaw(account));
|
|
118
|
+
expect(newAccount.nfts).toEqual(account.nfts);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test("remove half NFTs will restore them with half operations", async () => {
|
|
122
|
+
const halfOps = Math.ceil(account.operations.length / 2);
|
|
123
|
+
const copy = {
|
|
124
|
+
...account,
|
|
125
|
+
operations: account.operations.slice(halfOps),
|
|
126
|
+
nfts: account.nfts?.slice(Math.ceil((account.nfts?.length || 0) / 2)),
|
|
127
|
+
};
|
|
128
|
+
const resync = await sync(copy);
|
|
129
|
+
expect(resync.nfts).toEqual(account.nfts);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test("start account with .nfts and disable the NFT flag should make it disappear", async () => {
|
|
133
|
+
expect(account.nfts).not.toBeFalsy();
|
|
134
|
+
const resync = await sync(account, false);
|
|
135
|
+
expect(resync.nfts).toBeFalsy();
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test("start account without .nfts and enable the NFT flag should make it appear", async () => {
|
|
139
|
+
const first = await sync(account, false);
|
|
140
|
+
expect(first.nfts).toBeFalsy();
|
|
141
|
+
const second = await sync(first, true);
|
|
142
|
+
expect(second.nfts).not.toBeFalsy();
|
|
143
|
+
expect(second.nfts).toEqual(account.nfts);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
describe.skip("gaspard NFT on polygon", () => {
|
|
149
|
+
let account = fromAccountRaw(gaspardPolygonAccount);
|
|
150
|
+
test("first sync", async () => {
|
|
151
|
+
await cache.prepareCurrency(account.currency);
|
|
152
|
+
account = await sync(account);
|
|
153
|
+
});
|
|
154
|
+
test(".nfts shouldn't be visible", () => {
|
|
155
|
+
expect(account.nfts).toBeFalsy();
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
describe("gaspard NFT on bsc", () => {
|
|
160
|
+
let account = fromAccountRaw(gaspardBscAccount);
|
|
161
|
+
test("first sync", async () => {
|
|
162
|
+
await cache.prepareCurrency(account.currency);
|
|
163
|
+
account = await sync(account);
|
|
164
|
+
});
|
|
165
|
+
test(".nfts shouldn't be visible", () => {
|
|
166
|
+
expect(account.nfts).toBeFalsy();
|
|
167
|
+
});
|
|
168
|
+
});
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import "../../__tests__/test-helpers/setup";
|
|
2
|
+
import BigNumber from "bignumber.js";
|
|
3
|
+
import { toNFTRaw } from "../../account";
|
|
4
|
+
import type { NFT } from "../../types";
|
|
5
|
+
import { mergeNfts } from "../../bridge/jsHelpers";
|
|
6
|
+
import { encodeNftId } from "../../nft";
|
|
7
|
+
|
|
8
|
+
describe("nft merging", () => {
|
|
9
|
+
const makeNFT = (tokenId: string, contract: string, amount: number): NFT => ({
|
|
10
|
+
id: encodeNftId("test", contract, tokenId),
|
|
11
|
+
tokenId,
|
|
12
|
+
amount: new BigNumber(amount),
|
|
13
|
+
collection: {
|
|
14
|
+
contract,
|
|
15
|
+
standard: "erc721",
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
const oldNfts = [
|
|
19
|
+
makeNFT("1", "contract1", 10),
|
|
20
|
+
makeNFT("2", "contract1", 1),
|
|
21
|
+
makeNFT("3", "contract2", 6),
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
test("should remove first NFT and return new array with same refs", () => {
|
|
25
|
+
const nfts = [makeNFT("2", "contract1", 1), makeNFT("3", "contract2", 6)];
|
|
26
|
+
const newNfts = mergeNfts(oldNfts, nfts);
|
|
27
|
+
|
|
28
|
+
expect(newNfts.map(toNFTRaw)).toEqual(nfts.map(toNFTRaw));
|
|
29
|
+
expect(oldNfts[1]).toBe(newNfts[0]);
|
|
30
|
+
expect(oldNfts[2]).toBe(newNfts[1]);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("should remove any NFT and return new array with same refs", () => {
|
|
34
|
+
const nfts = [makeNFT("1", "contract1", 10), makeNFT("3", "contract2", 6)];
|
|
35
|
+
const newNfts = mergeNfts(oldNfts, nfts);
|
|
36
|
+
|
|
37
|
+
expect(newNfts.map(toNFTRaw)).toEqual(nfts.map(toNFTRaw));
|
|
38
|
+
expect(oldNfts[0]).toBe(newNfts[0]);
|
|
39
|
+
expect(oldNfts[2]).toBe(newNfts[1]);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("should change NFT amount and return new array with new ref", () => {
|
|
43
|
+
const nfts = [
|
|
44
|
+
makeNFT("1", "contract1", 10),
|
|
45
|
+
makeNFT("2", "contract1", 5),
|
|
46
|
+
makeNFT("3", "contract2", 6),
|
|
47
|
+
];
|
|
48
|
+
const addToNft1 = mergeNfts(oldNfts, nfts);
|
|
49
|
+
|
|
50
|
+
expect(addToNft1.map(toNFTRaw)).toEqual(nfts.map(toNFTRaw));
|
|
51
|
+
expect(oldNfts[0]).toBe(addToNft1[0]);
|
|
52
|
+
expect(oldNfts[1]).not.toBe(addToNft1[1]);
|
|
53
|
+
expect(oldNfts[2]).toBe(addToNft1[2]);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("should add NFT and return new array with new ref", () => {
|
|
57
|
+
const nfts = [
|
|
58
|
+
makeNFT("1", "contract1", 10),
|
|
59
|
+
makeNFT("2", "contract1", 1),
|
|
60
|
+
makeNFT("3", "contract2", 6),
|
|
61
|
+
makeNFT("4", "contract2", 4),
|
|
62
|
+
];
|
|
63
|
+
const addToNft1 = mergeNfts(oldNfts, nfts);
|
|
64
|
+
|
|
65
|
+
expect(addToNft1.map(toNFTRaw)).toEqual(
|
|
66
|
+
[
|
|
67
|
+
makeNFT("4", "contract2", 4),
|
|
68
|
+
makeNFT("1", "contract1", 10),
|
|
69
|
+
makeNFT("2", "contract1", 1),
|
|
70
|
+
makeNFT("3", "contract2", 6),
|
|
71
|
+
].map(toNFTRaw)
|
|
72
|
+
);
|
|
73
|
+
expect(oldNfts[0]).toBe(addToNft1[1]);
|
|
74
|
+
expect(oldNfts[1]).toBe(addToNft1[2]);
|
|
75
|
+
expect(oldNfts[2]).toBe(addToNft1[3]);
|
|
76
|
+
expect(addToNft1[0]).toBe(nfts[3]);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
@@ -167,7 +167,7 @@ export const getAccountShape: GetAccountShape = async (
|
|
|
167
167
|
const operations = mergeOps(initialStableOperations, newOps);
|
|
168
168
|
|
|
169
169
|
const nfts = isNFTActive(currency)
|
|
170
|
-
? mergeNfts(initialAccount?.nfts, nftsFromOperations(operations))
|
|
170
|
+
? mergeNfts(initialAccount?.nfts || [], nftsFromOperations(operations))
|
|
171
171
|
: undefined;
|
|
172
172
|
|
|
173
173
|
const accountShape: Partial<Account> = {
|
|
@@ -396,7 +396,7 @@ const txToOps =
|
|
|
396
396
|
const erc1155Operations =
|
|
397
397
|
!erc1155_transfer_events || !isNFTActive(currency)
|
|
398
398
|
? []
|
|
399
|
-
: flatMap(erc1155_transfer_events, (event) => {
|
|
399
|
+
: flatMap(erc1155_transfer_events, (event, i) => {
|
|
400
400
|
const sender = safeEncodeEIP55(event.sender);
|
|
401
401
|
const receiver = safeEncodeEIP55(event.receiver);
|
|
402
402
|
const contract = safeEncodeEIP55(event.contract);
|
|
@@ -410,7 +410,7 @@ const txToOps =
|
|
|
410
410
|
|
|
411
411
|
const all: Operation[] = [];
|
|
412
412
|
|
|
413
|
-
event.transfers.forEach((transfer) => {
|
|
413
|
+
event.transfers.forEach((transfer, j) => {
|
|
414
414
|
const tokenId = transfer.id;
|
|
415
415
|
const value = new BigNumber(transfer.value);
|
|
416
416
|
const nftId = encodeNftId(id, event.contract, tokenId);
|
|
@@ -418,7 +418,7 @@ const txToOps =
|
|
|
418
418
|
if (sending) {
|
|
419
419
|
const type = "NFT_OUT";
|
|
420
420
|
all.push({
|
|
421
|
-
id: `${nftId}-${hash}-${type}`,
|
|
421
|
+
id: `${nftId}-${hash}-${type}-i${i}_${j}`,
|
|
422
422
|
senders: [sender],
|
|
423
423
|
recipients: [receiver],
|
|
424
424
|
contract,
|
|
@@ -441,7 +441,7 @@ const txToOps =
|
|
|
441
441
|
if (receiving) {
|
|
442
442
|
const type = "NFT_IN";
|
|
443
443
|
all.push({
|
|
444
|
-
id: `${nftId}-${hash}-${type}`,
|
|
444
|
+
id: `${nftId}-${hash}-${type}-i${i}`,
|
|
445
445
|
senders: [sender],
|
|
446
446
|
recipients: [receiver],
|
|
447
447
|
contract,
|
|
@@ -7,7 +7,7 @@ import React, {
|
|
|
7
7
|
} from "react";
|
|
8
8
|
import { Currency, findCryptoCurrencyById } from "@ledgerhq/cryptoassets";
|
|
9
9
|
import { API, apiForCurrency } from "../../api/Ethereum";
|
|
10
|
-
import { NFTMetadataResponse } from "../../types";
|
|
10
|
+
import { NFT, NFTMetadataResponse } from "../../types";
|
|
11
11
|
import { getNftKey } from "../helpers";
|
|
12
12
|
import {
|
|
13
13
|
Batch,
|
|
@@ -77,14 +77,19 @@ export const metadataCallBatcher = (() => {
|
|
|
77
77
|
};
|
|
78
78
|
})();
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
// DEPRECATED, use useNftResource
|
|
81
|
+
export function useNftMetadata(
|
|
82
|
+
contract: string | undefined,
|
|
83
|
+
tokenId: string | undefined
|
|
84
|
+
): NFTResource {
|
|
81
85
|
const { cache, loadNFTMetadata } = useContext(NftMetadataContext);
|
|
82
86
|
|
|
83
|
-
const key = getNftKey(contract, tokenId);
|
|
87
|
+
const key = contract && tokenId ? getNftKey(contract, tokenId) : "";
|
|
84
88
|
|
|
85
89
|
const cachedData = cache[key];
|
|
86
90
|
|
|
87
91
|
useEffect(() => {
|
|
92
|
+
if (!contract || !tokenId) return;
|
|
88
93
|
if (!cachedData || isOutdated(cachedData)) {
|
|
89
94
|
loadNFTMetadata(contract, tokenId);
|
|
90
95
|
}
|
|
@@ -99,6 +104,10 @@ export function useNftMetadata(contract: string, tokenId: string): NFTResource {
|
|
|
99
104
|
}
|
|
100
105
|
}
|
|
101
106
|
|
|
107
|
+
export function useNftResource(nft: NFT | undefined): NFTResource {
|
|
108
|
+
return useNftMetadata(nft?.collection.contract, nft?.tokenId);
|
|
109
|
+
}
|
|
110
|
+
|
|
102
111
|
export function useNftAPI(): NFTMetadataContextAPI {
|
|
103
112
|
const { clearCache, loadNFTMetadata } = useContext(NftMetadataContext);
|
|
104
113
|
|
package/src/operation.ts
CHANGED
|
@@ -105,7 +105,6 @@ export function getOperationAmountNumber(op: Operation): BigNumber {
|
|
|
105
105
|
case "REWARD":
|
|
106
106
|
case "REWARD_PAYOUT":
|
|
107
107
|
case "SUPPLY":
|
|
108
|
-
case "NFT_IN":
|
|
109
108
|
return op.value;
|
|
110
109
|
|
|
111
110
|
case "OUT":
|
|
@@ -119,7 +118,6 @@ export function getOperationAmountNumber(op: Operation): BigNumber {
|
|
|
119
118
|
case "OPT_OUT":
|
|
120
119
|
case "REDEEM":
|
|
121
120
|
case "SLASH":
|
|
122
|
-
case "NFT_OUT":
|
|
123
121
|
return op.value.negated();
|
|
124
122
|
|
|
125
123
|
case "FREEZE":
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cro.d.ts","sourceRoot":"","sources":["../../../../src/data/icons/react/cro.tsx"],"names":[],"mappings":";AAEA,UAAU,KAAK;IACH,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAEX,iBAAS,GAAG,CAAC,EAAC,IAAI,EAAE,KAAsB,EAAC,EAAE,KAAK,eAEjD;AAED,eAAe,GAAG,CAAC"}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
-
}) : (function(o, m, k, k2) {
|
|
6
|
-
if (k2 === undefined) k2 = k;
|
|
7
|
-
o[k2] = m[k];
|
|
8
|
-
}));
|
|
9
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
10
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
11
|
-
}) : function(o, v) {
|
|
12
|
-
o["default"] = v;
|
|
13
|
-
});
|
|
14
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
15
|
-
if (mod && mod.__esModule) return mod;
|
|
16
|
-
var result = {};
|
|
17
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
18
|
-
__setModuleDefault(result, mod);
|
|
19
|
-
return result;
|
|
20
|
-
};
|
|
21
|
-
exports.__esModule = true;
|
|
22
|
-
var React = __importStar(require("react"));
|
|
23
|
-
;
|
|
24
|
-
function cro(_a) {
|
|
25
|
-
var size = _a.size, _b = _a.color, color = _b === void 0 ? "currentColor" : _b;
|
|
26
|
-
return React.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg" },
|
|
27
|
-
React.createElement("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M0 5.99919L10.3937 0L20.7808 5.99919V18.0008L10.3937 24L0 18.0008V5.99919ZM10.3937 20.4289L17.7038 16.2314V7.77829L10.3937 3.55819L3.08032 7.77829V16.2314L10.3937 20.4289ZM10.3906 17.6037L15.2436 14.801V9.19898L10.3906 6.39634L5.53767 9.19898V14.801L10.3906 17.6037Z", fill: color }));
|
|
28
|
-
}
|
|
29
|
-
exports["default"] = cro;
|
|
30
|
-
//# sourceMappingURL=cro.js.map
|