@otoplo/wallet-common 0.1.15 → 0.2.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.
Files changed (56) hide show
  1. package/dist/index.js +555 -579
  2. package/dist/index.js.map +1 -1
  3. package/dist/types/persistence/datastore/db.d.ts +5 -3
  4. package/dist/types/persistence/datastore/db.d.ts.map +1 -1
  5. package/dist/types/persistence/wallet-db.d.ts +10 -18
  6. package/dist/types/persistence/wallet-db.d.ts.map +1 -1
  7. package/dist/types/services/asset.d.ts +5 -9
  8. package/dist/types/services/asset.d.ts.map +1 -1
  9. package/dist/types/services/cache.d.ts +4 -2
  10. package/dist/types/services/cache.d.ts.map +1 -1
  11. package/dist/types/services/wallet.d.ts +2 -1
  12. package/dist/types/services/wallet.d.ts.map +1 -1
  13. package/dist/types/state/hooks.d.ts +2 -1
  14. package/dist/types/state/hooks.d.ts.map +1 -1
  15. package/dist/types/state/slices/market.d.ts +54 -0
  16. package/dist/types/state/slices/market.d.ts.map +1 -0
  17. package/dist/types/state/slices/status.d.ts +0 -27
  18. package/dist/types/state/slices/status.d.ts.map +1 -1
  19. package/dist/types/state/slices/wallet.d.ts +21 -220
  20. package/dist/types/state/slices/wallet.d.ts.map +1 -1
  21. package/dist/types/state/store.d.ts +3 -0
  22. package/dist/types/state/store.d.ts.map +1 -1
  23. package/dist/types/types/db.types.d.ts +16 -11
  24. package/dist/types/types/db.types.d.ts.map +1 -1
  25. package/dist/types/types/wallet.types.d.ts +39 -14
  26. package/dist/types/types/wallet.types.d.ts.map +1 -1
  27. package/dist/types/utils/asset.d.ts +3 -6
  28. package/dist/types/utils/asset.d.ts.map +1 -1
  29. package/dist/types/utils/common.d.ts +0 -1
  30. package/dist/types/utils/common.d.ts.map +1 -1
  31. package/dist/types/utils/enums.d.ts +0 -4
  32. package/dist/types/utils/enums.d.ts.map +1 -1
  33. package/dist/types/utils/index.d.ts +1 -1
  34. package/dist/types/utils/index.d.ts.map +1 -1
  35. package/dist/types/utils/{price.d.ts → market.d.ts} +19 -13
  36. package/dist/types/utils/market.d.ts.map +1 -0
  37. package/package.json +4 -5
  38. package/src/persistence/datastore/db.ts +5 -3
  39. package/src/persistence/wallet-db.ts +28 -28
  40. package/src/services/asset.ts +69 -162
  41. package/src/services/cache.ts +12 -2
  42. package/src/services/wallet.ts +23 -21
  43. package/src/state/hooks.ts +3 -1
  44. package/src/state/slices/market.ts +47 -0
  45. package/src/state/slices/status.ts +2 -31
  46. package/src/state/slices/wallet.ts +8 -13
  47. package/src/state/store.ts +3 -0
  48. package/src/types/db.types.ts +17 -12
  49. package/src/types/wallet.types.ts +40 -16
  50. package/src/utils/asset.ts +12 -52
  51. package/src/utils/common.ts +0 -6
  52. package/src/utils/enums.ts +0 -5
  53. package/src/utils/index.ts +1 -1
  54. package/src/utils/market.ts +97 -0
  55. package/dist/types/utils/price.d.ts.map +0 -1
  56. package/src/utils/price.ts +0 -46
@@ -1,9 +1,6 @@
1
- import { TokenEntity } from '../types/db.types';
2
- export declare function getNiftyToken(): TokenEntity;
3
- export declare function fetchNiftyNFT(id: string): Promise<Uint8Array>;
4
- export declare function isNiftySubgroup(group: string): boolean;
5
- export declare function fetchAssetDoc(url: string): Promise<any>;
6
- export declare function fetchAssetBlob(url: string): Promise<Uint8Array>;
1
+ import { AssetInfo } from '../types';
7
2
  export declare function transformTokenIconUrl(icon: string, documentUrl: string): string;
8
3
  export declare function parseTokenDataUrl(data?: string): string | null;
4
+ export declare function getAssetMetadata(token: string): Promise<AssetInfo>;
5
+ export declare function getAssetFileUrl(token: string, asset: string): string;
9
6
  //# sourceMappingURL=asset.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"asset.d.ts","sourceRoot":"","sources":["../../../src/utils/asset.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,wBAAgB,aAAa,IAAI,WAAW,CAc3C;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAE7D;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAWtD;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAKvD;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAK/D;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAY/E;AAED,wBAAgB,iBAAiB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAK9D"}
1
+ {"version":3,"file":"asset.d.ts","sourceRoot":"","sources":["../../../src/utils/asset.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE1C,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAY/E;AAED,wBAAgB,iBAAiB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAK9D;AAYD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAElE;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAC,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEnE"}
@@ -23,5 +23,4 @@ export declare function getFileMediaType(filename: string): 'video' | 'audio' |
23
23
  export declare function getFileMimeType(filename: string): string;
24
24
  export declare function sleep(ms: number): Promise<void>;
25
25
  export declare function prettifyAmount(amount: string | number): string;
26
- export declare function calcAmountValue(amount: string | number, price: number, prettify?: boolean): string;
27
26
  //# sourceMappingURL=common.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../../src/utils/common.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,WAAW,EAAsC,MAAM,YAAY,CAAC;AACtF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAGrD,eAAO,MAAM,cAAc,KAAK,CAAC;AACjC,eAAO,MAAM,SAAS,uBAAuB,CAAC;AAC9C,eAAO,MAAM,iBAAiB,SAAS,CAAC;AACxC,eAAO,MAAM,mBAAmB,iDAAkD,CAAC;AAEnF,wBAAgB,SAAS,IAAI,OAAO,CAEnC;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAKxD;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,cAAkC,GAAG,OAAO,CAEnG;AAED,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAKjF;AAED,wBAAgB,aAAa,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,GAAG,EAAE,GAAG,IAAI,GAAG,GAAG,IAAI,SAAS,GAAG,EAAE,GAAG,IAAI,GAAG,EAAE,CAE5F;AAED,wBAAgB,oBAAoB,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,SAAS,SAAI,GAAG,MAAM,CAWxE;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKzD;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAK5D;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKlD;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKpD;AAED,wBAAgB,wBAAwB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAQlF;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAOvD;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAc7F;AA4BD,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,CAM1F;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMxD;AAED,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/C;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAM9D;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,UAAQ,GAAG,MAAM,CAIhG"}
1
+ {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../../src/utils/common.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,WAAW,EAAsC,MAAM,YAAY,CAAC;AACtF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAGrD,eAAO,MAAM,cAAc,KAAK,CAAC;AACjC,eAAO,MAAM,SAAS,uBAAuB,CAAC;AAC9C,eAAO,MAAM,iBAAiB,SAAS,CAAC;AACxC,eAAO,MAAM,mBAAmB,iDAAkD,CAAC;AAEnF,wBAAgB,SAAS,IAAI,OAAO,CAEnC;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAKxD;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,cAAkC,GAAG,OAAO,CAEnG;AAED,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAKjF;AAED,wBAAgB,aAAa,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,GAAG,EAAE,GAAG,IAAI,GAAG,GAAG,IAAI,SAAS,GAAG,EAAE,GAAG,IAAI,GAAG,EAAE,CAE5F;AAED,wBAAgB,oBAAoB,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,SAAS,SAAI,GAAG,MAAM,CAWxE;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKzD;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAK5D;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKlD;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKpD;AAED,wBAAgB,wBAAwB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAQlF;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAOvD;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAc7F;AA4BD,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,CAM1F;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMxD;AAED,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/C;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAM9D"}
@@ -13,8 +13,4 @@ export declare enum SessionRequestType {
13
13
  SignTransaction = "signTransaction",
14
14
  SendTransaction = "sendTransaction"
15
15
  }
16
- export declare enum AssetType {
17
- TOKEN = "token",
18
- NFT = "nft"
19
- }
20
16
  //# sourceMappingURL=enums.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"enums.d.ts","sourceRoot":"","sources":["../../../src/utils/enums.ts"],"names":[],"mappings":"AAAA,oBAAY,WAAW;IACrB,IAAI,IAAI;IACR,KAAK,IAAI;IACT,IAAI,IAAI;CACT;AAED,oBAAY,QAAQ;IAClB,OAAO,IAAI;IACX,MAAM,IAAI;CACX;AAED,oBAAY,kBAAkB;IAC5B,WAAW,gBAAgB;IAC3B,QAAQ,aAAa;IACrB,eAAe,oBAAoB;IACnC,eAAe,oBAAoB;CACpC;AAED,oBAAY,SAAS;IACnB,KAAK,UAAU;IACf,GAAG,QAAQ;CACZ"}
1
+ {"version":3,"file":"enums.d.ts","sourceRoot":"","sources":["../../../src/utils/enums.ts"],"names":[],"mappings":"AAAA,oBAAY,WAAW;IACrB,IAAI,IAAI;IACR,KAAK,IAAI;IACT,IAAI,IAAI;CACT;AAED,oBAAY,QAAQ;IAClB,OAAO,IAAI;IACX,MAAM,IAAI;CACX;AAED,oBAAY,kBAAkB;IAC5B,WAAW,gBAAgB;IAC3B,QAAQ,aAAa;IACrB,eAAe,oBAAoB;IACnC,eAAe,oBAAoB;CACpC"}
@@ -2,7 +2,7 @@ export * from './asset';
2
2
  export * from './common';
3
3
  export * from './enums';
4
4
  export * from './seed';
5
- export * from './price';
5
+ export * from './market';
6
6
  export * from './vault';
7
7
  export * from './keypath';
8
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC"}
@@ -1,4 +1,4 @@
1
- import { Price } from '../types/wallet.types';
1
+ import { MarketData } from '../types/wallet.types';
2
2
  export declare const CURRENCIES: readonly [{
3
3
  readonly code: "usd";
4
4
  readonly symbol: "$";
@@ -11,14 +11,6 @@ export declare const CURRENCIES: readonly [{
11
11
  readonly code: "gbp";
12
12
  readonly symbol: "£";
13
13
  readonly name: "British Pound";
14
- }, {
15
- readonly code: "cny";
16
- readonly symbol: "¥";
17
- readonly name: "Chinese Yuan";
18
- }, {
19
- readonly code: "jpy";
20
- readonly symbol: "¥";
21
- readonly name: "Japanese Yen";
22
14
  }, {
23
15
  readonly code: "aud";
24
16
  readonly symbol: "A$";
@@ -31,12 +23,26 @@ export declare const CURRENCIES: readonly [{
31
23
  readonly code: "chf";
32
24
  readonly symbol: "Fr";
33
25
  readonly name: "Swiss Franc";
26
+ }, {
27
+ readonly code: "inr";
28
+ readonly symbol: "₹";
29
+ readonly name: "Indian Rupee";
30
+ }, {
31
+ readonly code: "cny";
32
+ readonly symbol: "¥";
33
+ readonly name: "Chinese Yuan";
34
+ }, {
35
+ readonly code: "jpy";
36
+ readonly symbol: "¥";
37
+ readonly name: "Japanese Yen";
34
38
  }];
35
39
  export type CurrencyCode = typeof CURRENCIES[number]['code'];
36
40
  export type CurrencySymbol = typeof CURRENCIES[number]['symbol'];
37
41
  export declare const currencySymbols: Record<CurrencyCode, CurrencySymbol>;
38
- export declare const currencyCodes: ("usd" | "eur" | "gbp" | "cny" | "jpy" | "aud" | "cad" | "chf")[];
39
- export declare function getNexaPrices(): Promise<Record<string, number>>;
42
+ export declare const currencyCodes: ("usd" | "eur" | "gbp" | "aud" | "cad" | "chf" | "inr" | "cny" | "jpy")[];
43
+ export declare const SUPPORTED_TOKENS: Record<string, string>;
44
+ export declare function getMarketData(currency: CurrencyCode): Promise<Record<string, MarketData>>;
40
45
  export declare function getCurrencySymbol(currency: CurrencyCode): string;
41
- export declare function initializePrices(): Record<string, Price>;
42
- //# sourceMappingURL=price.d.ts.map
46
+ export declare function calculateFiatValue(amount: string | number, price: number, currency?: CurrencyCode): string;
47
+ export declare function formatMoney(value: string | number, currency: CurrencyCode, locale?: string): string;
48
+ //# sourceMappingURL=market.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"market.d.ts","sourceRoot":"","sources":["../../../src/utils/market.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAqBxD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAUb,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;AAE7D,MAAM,MAAM,cAAc,GAAG,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC;AAEjE,eAAO,MAAM,eAAe,EAEvB,MAAM,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;AAE1C,eAAO,MAAM,aAAa,2EAA8B,CAAC;AAEzD,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAEnD,CAAC;AAEF,wBAAsB,aAAa,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CA4B/F;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,YAAY,GAAG,MAAM,CAEhE;AAGD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,YAAY,GAAG,MAAM,CAI1G;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAU,GAAG,MAAM,CAOpG"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@otoplo/wallet-common",
3
- "version": "0.1.15",
3
+ "version": "0.2.0",
4
4
  "description": "Shared common library for internal use in Otoplo wallet",
5
5
  "license": "MIT",
6
6
  "author": "vgrunner",
@@ -31,14 +31,13 @@
31
31
  "url": "git+https://gitlab.com/nexa/otoplo/otoplo-wallet-common.git"
32
32
  },
33
33
  "dependencies": {
34
- "@scure/bip39": "^2.0.1",
35
- "jszip": "^3.10.1"
34
+ "@scure/bip39": "^2.0.1"
36
35
  },
37
36
  "devDependencies": {
38
37
  "del-cli": "^7.0.0",
39
38
  "eslint": "^9.39.2",
40
39
  "typescript": "^5.9.3",
41
- "typescript-eslint": "^8.53.0",
40
+ "typescript-eslint": "^8.54.0",
42
41
  "vite": "^7.3.1",
43
42
  "vite-plugin-dts": "^4.5.4"
44
43
  },
@@ -46,7 +45,7 @@
46
45
  "@otoplo/electrum-client": "^0.2.1",
47
46
  "@reduxjs/toolkit": "^2.11.2",
48
47
  "js-big-decimal": "^2.2.0",
49
- "libnexa-ts": "^3.0.0",
48
+ "libnexa-ts": "^3.0.1",
50
49
  "react": ">=19.1.0",
51
50
  "react-redux": "^9.2.0",
52
51
  "wallet-comms-sdk": "^0.9.1"
@@ -1,4 +1,5 @@
1
1
  import type { AccountEntity, AssetEntity, AssetTransactionEntity, NftEntity, SessionEntity, TokenEntity, TransactionEntity, AddressEntity, VaultEntity } from "../../types/db.types";
2
+ import type { AssetType } from "../../types/wallet.types";
2
3
 
3
4
  export interface DBStore {
4
5
  clearData(): Promise<void>;
@@ -11,22 +12,23 @@ export interface DBStore {
11
12
  countTransactions(account: number, tokenId?: string): Promise<number>;
12
13
  clearTransactions(account: number): Promise<void>;
13
14
 
15
+ countTokens(account: number): Promise<number>;
14
16
  upsertToken(token: TokenEntity): Promise<void>;
15
- getTokens(account: number): Promise<AssetEntity[]>;
17
+ getTokens(account: number, pageNum: number, pageSize: number): Promise<TokenEntity[]>;
16
18
  getToken(id: string): Promise<TokenEntity | undefined>;
17
19
  deleteToken(id: string): Promise<void>;
18
20
 
19
21
  countNfts(account: number): Promise<number>;
20
22
  upsertNft(nft: NftEntity): Promise<void>;
21
- getNfts(account: number, pageNum: number, pageSize: number): Promise<AssetEntity[]>;
23
+ getNfts(account: number, pageNum: number, pageSize: number): Promise<NftEntity[]>;
22
24
  getNft(id: string): Promise<NftEntity | undefined>;
23
25
  deleteNft(id: string): Promise<void>;
24
26
  isNftExist(id: string): Promise<boolean>;
25
27
 
26
28
  upsertAsset(asset: AssetEntity): Promise<void>;
29
+ getAssets(account: number, type: AssetType): Promise<AssetEntity[]>;
27
30
  deleteAsset(account: number, id: string): Promise<void>;
28
31
  countAssetsById(id: string): Promise<number>;
29
- isAssetExistForAccount(account: number, id: string): Promise<boolean>
30
32
 
31
33
  upsertAccount(account: AccountEntity): Promise<void>;
32
34
  getAccounts(): Promise<AccountEntity[]>;
@@ -1,14 +1,13 @@
1
1
  import type { DBStore } from "./datastore/db";
2
- import { AccountType, AssetType } from "../utils/enums";
2
+ import { AccountType } from "../utils/enums";
3
3
  import type { AccountDTO, AccountEntity, AddressDTO, AddressEntity, AssetEntity, AssetTransactionEntity, NftEntity, SessionEntity, TokenEntity, TransactionEntity, VaultDTO, VaultEntity } from "../types/db.types";
4
+ import type { AssetType } from "../types/wallet.types";
4
5
  import { currentTimestamp } from "../utils/common";
5
6
 
6
7
  export type DBEvent =
7
8
  | { type: 'tx_refresh'; }
8
9
  | { type: 'nft_refresh'; }
9
- | { type: 'token_added'; accountId: number; token: AssetEntity; }
10
- | { type: 'token_removed'; accountId: number; tokenId: string; }
11
- | { type: 'nft_deleted'; id: string; }
10
+ | { type: 'token_refresh'; }
12
11
 
13
12
  export type DBUpdateCallback = (event: DBEvent) => void;
14
13
 
@@ -50,11 +49,11 @@ export class WalletDB {
50
49
  return this.store.upsertAssetTransaction(assetTx);
51
50
  }
52
51
 
53
- public async getLocalTransactions(account: number, tokenId?: string): Promise<TransactionEntity[] | undefined> {
52
+ public async getLocalTransactions(account: number, tokenId?: string): Promise<TransactionEntity[]> {
54
53
  return this.store.getTransactions(account, tokenId);
55
54
  }
56
55
 
57
- public async getPageLocalTransactions(account: number, pageNum: number, pageSize: number, tokenId?: string): Promise<TransactionEntity[] | undefined> {
56
+ public async getPageLocalTransactions(account: number, pageNum: number, pageSize: number, tokenId?: string): Promise<TransactionEntity[]> {
58
57
  return this.store.getPageTransactions(account, pageNum, pageSize, tokenId);
59
58
  }
60
59
 
@@ -71,16 +70,16 @@ export class WalletDB {
71
70
  const asset: AssetEntity = {
72
71
  accountId: account,
73
72
  tokenIdHex: token.tokenIdHex,
74
- type: AssetType.TOKEN,
73
+ type: "token",
75
74
  addedTime: currentTimestamp()
76
75
  }
77
- await this.store.upsertAsset(asset);
78
76
  await this.store.upsertToken(token);
79
- this.notify({ type: 'token_added', accountId: account, token: asset });
77
+ await this.saveAsset(asset);
78
+ this.notify({ type: 'token_refresh' });
80
79
  }
81
80
 
82
- public async getLocalTokens(account: number): Promise<AssetEntity[] | undefined> {
83
- return this.store.getTokens(account);
81
+ public async getLocalTokens(account: number, pageNum: number, pageSize: number): Promise<TokenEntity[]> {
82
+ return this.store.getTokens(account, pageNum, pageSize);
84
83
  }
85
84
 
86
85
  public async getToken(id: string): Promise<TokenEntity | undefined> {
@@ -93,15 +92,22 @@ export class WalletDB {
93
92
  if (count == 0) {
94
93
  await this.store.deleteToken(tokenId);
95
94
  }
96
- this.notify({ type: 'token_removed', accountId: account, tokenId: tokenId });
95
+ this.notify({ type: 'token_refresh' });
97
96
  }
98
97
 
99
- public async saveNft(asset: AssetEntity, nft: NftEntity): Promise<void> {
98
+ public async saveNft(account: number, nft: NftEntity, time: number): Promise<void> {
99
+ const asset: AssetEntity = {
100
+ accountId: account,
101
+ tokenIdHex: nft.tokenIdHex,
102
+ type: "nft",
103
+ addedTime: time
104
+ }
100
105
  await this.store.upsertNft(nft);
101
- await this.saveAsset(asset, true);
106
+ await this.saveAsset(asset);
107
+ this.notify({ type: 'nft_refresh' });
102
108
  }
103
109
 
104
- public async getLocalNfts(account: number, pageNum: number, pageSize: number): Promise<AssetEntity[] | undefined> {
110
+ public async getLocalNfts(account: number, pageNum: number, pageSize: number): Promise<NftEntity[]> {
105
111
  return this.store.getNfts(account, pageNum, pageSize);
106
112
  }
107
113
 
@@ -109,16 +115,13 @@ export class WalletDB {
109
115
  return this.store.getNft(id);
110
116
  }
111
117
 
112
- public async deleteNft(account: number, tokenId: string, notify = false): Promise<void> {
118
+ public async deleteNft(account: number, tokenId: string): Promise<void> {
113
119
  await this.removeAsset(account, tokenId);
114
120
  const count = await this.store.countAssetsById(tokenId);
115
121
  if (count == 0) {
116
122
  await this.store.deleteNft(tokenId);
117
- this.notify({ type: 'nft_deleted', id: tokenId });
118
- }
119
- if (notify) {
120
- this.notify({ type: 'nft_refresh' });
121
123
  }
124
+ this.notify({ type: 'nft_refresh' });
122
125
  }
123
126
 
124
127
  public async countLocalNfts(account: number): Promise<number> {
@@ -129,21 +132,18 @@ export class WalletDB {
129
132
  return this.store.isNftExist(id);
130
133
  }
131
134
 
132
- public async saveAsset(asset: AssetEntity, notifyNft = false): Promise<void> {
135
+ public async getAssets(account: number, type: AssetType): Promise<AssetEntity[]> {
136
+ return this.store.getAssets(account, type);
137
+ }
138
+
139
+ public async saveAsset(asset: AssetEntity): Promise<void> {
133
140
  await this.store.upsertAsset(asset);
134
- if (notifyNft) {
135
- this.notify({ type: 'nft_refresh' });
136
- }
137
141
  }
138
142
 
139
143
  public async removeAsset(account: number, id: string): Promise<void> {
140
144
  return this.store.deleteAsset(account, id);
141
145
  }
142
146
 
143
- public async isAssetExistForAccount(account: number, id: string): Promise<boolean> {
144
- return this.store.isAssetExistForAccount(account, id);
145
- }
146
-
147
147
  public async saveAccount(account: AccountDTO): Promise<void> {
148
148
  const accountEntity: AccountEntity = {
149
149
  id: account.id,
@@ -1,200 +1,102 @@
1
- import { Address, AddressType, BufferUtils, GroupIdType, GroupToken, Networks } from "libnexa-ts";
2
- import type { AssetEntity, NftEntity, TokenEntity } from "../types/db.types";
3
- import { fetchAssetBlob, fetchAssetDoc, getNiftyToken, isNiftySubgroup, transformTokenIconUrl } from "../utils/asset";
4
- import { currentTimestamp, getAddressBuffer, tokenHexToAddr, tokenIdToHex } from "../utils/common";
5
- import { AssetType } from "../utils/enums";
1
+ import type { NftEntity, TokenEntity } from "../types/db.types";
2
+ import { getAssetMetadata } from "../utils/asset";
3
+ import { currentTimestamp, tokenIdToHex } from "../utils/common";
6
4
  import type { WalletDB } from "../persistence/wallet-db";
7
- import type { RostrumService } from "./rostrum";
8
5
  import type { WalletCache } from "./cache";
9
- import JSZip from "jszip";
10
6
  import type { AssetInfo, Balance } from "../types/wallet.types";
11
7
 
12
8
  export class AssetService {
13
9
 
14
10
  private readonly walletDb: WalletDB;
15
- private readonly rostrumService: RostrumService;
16
11
  private readonly walletCache: WalletCache;
17
12
 
18
- constructor(walletDb: WalletDB, rostrumService: RostrumService, walletCache: WalletCache) {
13
+ constructor(walletDb: WalletDB, walletCache: WalletCache) {
19
14
  this.walletDb = walletDb;
20
- this.rostrumService = rostrumService;
21
15
  this.walletCache = walletCache;
22
16
  }
23
17
 
24
- public async getTokenInfo(token: string, checkCache = true): Promise<TokenEntity | undefined> {
18
+ public async getAssetInfo(assetId: string): Promise<AssetInfo | undefined> {
25
19
  try {
26
- if (checkCache) {
27
- const cachedToken = await this.walletCache.getTokenById(token);
28
- if (cachedToken) {
29
- return cachedToken;
20
+ if (this.walletCache.hasToken(assetId)) {
21
+ const token = await this.walletCache.getToken(assetId);
22
+ return {
23
+ type: "token",
24
+ parent: token!.parent,
25
+ token: token!.token,
26
+ tokenIdHex: token!.tokenIdHex,
27
+ data: {
28
+ name: token!.name,
29
+ ticker: token!.ticker,
30
+ decimals: token!.decimals,
31
+ iconUrl: token!.iconUrl
32
+ }
30
33
  }
31
34
  }
32
35
 
33
- const genesis = await this.rostrumService.getTokenGenesis(token);
34
- const groupId = BufferUtils.hexToBuffer(genesis.token_id_hex);
35
- let parent = "";
36
- let iconUrl = "";
37
-
38
- if (genesis.op_return_id == GroupIdType.NRC2 || genesis.op_return_id == GroupIdType.NRC3 || isNiftySubgroup(token)) {
39
- return undefined;
40
- }
41
-
42
- if (GroupToken.isSubgroup(groupId)) {
43
- parent = new Address(GroupToken.getParentGroupId(groupId), Networks.defaultNetwork, AddressType.GroupIdAddress).toString();
44
- }
45
-
46
- if (genesis.document_url) {
47
- try {
48
- if (genesis.op_return_id == GroupIdType.NRC1) {
49
- const token_zip = await fetchAssetBlob(genesis.document_url);
50
- const zip = await JSZip.loadAsync(token_zip);
51
- const info = zip.file('info.json');
52
- if (info) {
53
- const infoData = await info.async('string');
54
- const infoJson = JSON.parse(infoData);
55
- iconUrl = transformTokenIconUrl(infoJson[0]?.icon, genesis.document_url);
56
- }
57
- } else {
58
- const infoJson = await fetchAssetDoc(genesis.document_url);
59
- iconUrl = transformTokenIconUrl(infoJson[0]?.icon, genesis.document_url);
36
+ if (this.walletCache.hasNft(assetId)) {
37
+ const nft = await this.walletCache.getNft(assetId);
38
+ return {
39
+ type: "nft",
40
+ parent: nft!.parent,
41
+ token: nft!.token,
42
+ tokenIdHex: nft!.tokenIdHex,
43
+ data: {
44
+ name: nft!.name,
45
+ series: nft!.series,
46
+ collection: nft!.collection,
47
+ author: nft!.author,
48
+ public: nft!.public,
49
+ front: nft!.front,
50
+ back: nft!.back
60
51
  }
61
- } catch (e) {
62
- console.error("Failed to load metadata", e)
63
52
  }
64
53
  }
65
-
66
- const tokenEntity: TokenEntity = {
67
- token: genesis.group,
68
- tokenIdHex: genesis.token_id_hex,
69
- decimals: genesis.decimal_places ?? 0,
70
- parentGroup: parent,
71
- name: genesis.name ?? "",
72
- ticker: genesis.ticker ?? "",
73
- iconUrl: iconUrl
74
- };
75
-
76
- return tokenEntity;
77
- } catch (e) {
78
- console.error(e)
79
- return undefined;
80
- }
81
- }
82
-
83
- public async isNftToken(token: string): Promise<boolean> {
84
- try {
85
- if (isNiftySubgroup(token)) {
86
- return true;
87
- }
88
54
 
89
- const cachedToken = await this.walletCache.getNftById(token);
90
- if (cachedToken) {
91
- return true;
92
- }
93
-
94
- const genesis = await this.rostrumService.getTokenGenesis(token);
95
- if (genesis.op_return_id == GroupIdType.NRC3) {
96
- return true;
97
- }
55
+ return await getAssetMetadata(assetId);
98
56
  } catch (e) {
99
- console.error(e)
100
- }
101
-
102
- return false;
103
- }
104
-
105
- public async getAssetInfo(token: string): Promise<AssetInfo | undefined> {
106
- let asset: AssetInfo | undefined = await this.getTokenInfo(token);
107
- if (!asset) {
108
- const isNft = await this.isNftToken(token);
109
- if (isNft) {
110
- asset = {
111
- token: tokenHexToAddr(token),
112
- tokenIdHex: tokenIdToHex(token),
113
- decimals: 0,
114
- };
115
- }
57
+ console.error(e);
58
+ return undefined;
116
59
  }
117
- return asset;
118
60
  }
119
61
 
120
62
  public async handleNftReceive(accountId: number, tokenIdHex: string, time: number): Promise<void> {
121
- const exist = await this.walletDb.isNftExist(tokenIdHex);
122
- if (exist) {
123
- const asset: AssetEntity = {
124
- accountId: accountId,
125
- tokenIdHex: tokenIdHex,
126
- type: AssetType.NFT,
127
- addedTime: time
128
- }
129
- await this.walletDb.saveAsset(asset, true);
130
- return;
131
- }
132
-
133
- const genesis = await this.rostrumService.getTokenGenesis(tokenIdHex);
134
- if (genesis.op_return_id == GroupIdType.NRC3) {
135
- const groupId = getAddressBuffer(tokenIdHex);
136
- if (GroupToken.isSubgroup(groupId)) {
137
- const parentGroupId = new Address(groupId.subarray(0, 32), Networks.defaultNetwork, AddressType.GroupIdAddress).toString();
138
- const parentGenesis = await this.rostrumService.getTokenGenesis(parentGroupId);
139
- if (parentGenesis?.op_return_id == GroupIdType.NRC2) {
140
- // parent is an NRC-2 collection, this is an NRC-3 NFT. The name of the collection and NRC-3 NFT belongs
141
- // to is the name of the NRC-2 collection.
142
- await this.saveNft(accountId, tokenIdHex, genesis.document_url ?? '', parentGroupId, time, parentGenesis?.name ?? "");
143
- }
144
- }
145
- } else if (isNiftySubgroup(tokenIdHex)) {
146
- // NiftyArt does not have collections, pass "" for the collection
147
- await this.saveNft(accountId, tokenIdHex, 'nifty', getNiftyToken().token, time, "");
148
- }
149
- }
150
-
151
- private async saveNft(account: number, hexId: string, source: string, parent: string, time: number, collection: string): Promise<void> {
152
- if (!source) {
153
- return;
154
- }
155
-
156
- try {
157
- const asset: AssetEntity = {
158
- accountId: account,
159
- tokenIdHex: hexId,
160
- type: AssetType.NFT,
161
- addedTime: time
162
- }
63
+ const nft = await this.getAssetInfo(tokenIdHex);
64
+ if (nft && nft.type == 'nft') {
163
65
  const nftEntity: NftEntity = {
164
- parentGroup: parent,
165
- token: tokenHexToAddr(hexId),
166
- tokenIdHex: hexId,
167
- source: source,
168
- collection: collection
66
+ token: nft.token,
67
+ tokenIdHex: nft.tokenIdHex,
68
+ parent: nft.parent,
69
+ ...nft.data
169
70
  }
170
-
171
- await this.walletDb.saveNft(asset, nftEntity);
172
- } catch (e) {
173
- console.error('failed to save NFT', e);
71
+ await this.walletDb.saveNft(accountId, nftEntity, time);
174
72
  }
175
73
  }
176
74
 
177
- public async fetchAndSaveTokens(accountId: number, tokenBalances: Record<string, Balance>): Promise<void> {
75
+ public async syncTokens(accountId: number, tokenBalances: Record<string, Balance>): Promise<void> {
178
76
  for (const tokenId in tokenBalances) {
179
- const token = await this.getTokenInfo(tokenId);
180
- if (token) {
181
- await this.walletDb.saveToken(accountId, token);
77
+ const balance = tokenBalances[tokenId];
78
+ if (balance && BigInt(balance.confirmed) + BigInt(balance.unconfirmed) > 0n) {
79
+ const token = await this.getAssetInfo(tokenId);
80
+ if (token && token.type == 'token') {
81
+ const tokenEntity: TokenEntity = {
82
+ token: token.token,
83
+ tokenIdHex: token.tokenIdHex,
84
+ parent: token.parent,
85
+ ...token.data
86
+ };
87
+ await this.walletDb.saveToken(accountId, tokenEntity);
88
+ }
182
89
  }
183
90
  }
184
91
  }
185
92
 
186
93
  public async syncNfts(accountId: number, tokensBalance: Record<string, Balance>): Promise<void> {
187
94
  const currentAssets = Object.keys(tokensBalance);
188
- const internalAssets = await this.walletDb.getLocalNfts(accountId, 1, 1000);
189
-
190
- const handleNftDelete = async (tokenId: string): Promise<void> => {
191
- await this.walletDb.deleteNft(accountId, tokenId, true);
192
- this.walletCache.removeNft(tokenId);
193
- }
95
+ const internalAssets = await this.walletDb.getAssets(accountId, "nft");
194
96
 
195
97
  const staleAssets = internalAssets?.filter(a => !currentAssets.includes(a.tokenIdHex)) ?? [];
196
98
  for (const asset of staleAssets) {
197
- await handleNftDelete(asset.tokenIdHex);
99
+ await this.deleteNft(accountId, asset.tokenIdHex);
198
100
  }
199
101
 
200
102
  for (const [token, balance] of Object.entries(tokensBalance)) {
@@ -204,17 +106,22 @@ export class AssetService {
204
106
  if ((!hasBalance && !isAssetExist) || (hasBalance && isAssetExist)) {
205
107
  continue;
206
108
  }
207
-
208
- const isNft = await this.isNftToken(tokenId);
209
- if (!isNft) {
210
- continue;
211
- }
212
109
 
213
110
  if (!hasBalance && isAssetExist) {
214
- await handleNftDelete(tokenId);
111
+ await this.deleteNft(accountId, tokenId);
215
112
  } else {
216
113
  await this.handleNftReceive(accountId, tokenId, currentTimestamp());
217
114
  }
218
115
  }
219
116
  }
117
+
118
+ public async deleteToken(accountId: number, tokenId: string): Promise<void> {
119
+ await this.walletDb.deleteToken(accountId, tokenId);
120
+ this.walletCache.removeToken(tokenId);
121
+ }
122
+
123
+ public async deleteNft(accountId: number, tokenId: string): Promise<void> {
124
+ await this.walletDb.deleteNft(accountId, tokenId);
125
+ this.walletCache.removeNft(tokenId);
126
+ }
220
127
  }
@@ -18,7 +18,17 @@ export class WalletCache {
18
18
  this.nfts.clear();
19
19
  }
20
20
 
21
- public async getTokenById(id: string): Promise<TokenEntity | undefined> {
21
+ public hasToken(id: string): boolean {
22
+ id = tokenIdToHex(id);
23
+ return this.tokens.has(id);
24
+ }
25
+
26
+ public hasNft(id: string): boolean {
27
+ id = tokenIdToHex(id);
28
+ return this.nfts.has(id);
29
+ }
30
+
31
+ public async getToken(id: string): Promise<TokenEntity | undefined> {
22
32
  id = tokenIdToHex(id);
23
33
  if (this.tokens.has(id)) {
24
34
  return this.tokens.get(id)!;
@@ -31,7 +41,7 @@ export class WalletCache {
31
41
  return token;
32
42
  }
33
43
 
34
- public async getNftById(id: string): Promise<NftEntity | undefined> {
44
+ public async getNft(id: string): Promise<NftEntity | undefined> {
35
45
  id = tokenIdToHex(id);
36
46
  if (this.nfts.has(id)) {
37
47
  return this.nfts.get(id)!;