@metamask/assets-controller 7.1.2 → 8.0.1

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 (36) hide show
  1. package/CHANGELOG.md +28 -2
  2. package/dist/AssetsController.cjs +10 -1
  3. package/dist/AssetsController.cjs.map +1 -1
  4. package/dist/AssetsController.d.cts +2 -2
  5. package/dist/AssetsController.d.cts.map +1 -1
  6. package/dist/AssetsController.d.mts +2 -2
  7. package/dist/AssetsController.d.mts.map +1 -1
  8. package/dist/AssetsController.mjs +12 -3
  9. package/dist/AssetsController.mjs.map +1 -1
  10. package/dist/data-sources/AccountsApiDataSource.cjs +4 -1
  11. package/dist/data-sources/AccountsApiDataSource.cjs.map +1 -1
  12. package/dist/data-sources/AccountsApiDataSource.d.cts.map +1 -1
  13. package/dist/data-sources/AccountsApiDataSource.d.mts.map +1 -1
  14. package/dist/data-sources/AccountsApiDataSource.mjs +4 -1
  15. package/dist/data-sources/AccountsApiDataSource.mjs.map +1 -1
  16. package/dist/data-sources/SnapDataSource.cjs +4 -0
  17. package/dist/data-sources/SnapDataSource.cjs.map +1 -1
  18. package/dist/data-sources/SnapDataSource.d.cts +2 -2
  19. package/dist/data-sources/SnapDataSource.d.cts.map +1 -1
  20. package/dist/data-sources/SnapDataSource.d.mts +2 -2
  21. package/dist/data-sources/SnapDataSource.d.mts.map +1 -1
  22. package/dist/data-sources/SnapDataSource.mjs +4 -0
  23. package/dist/data-sources/SnapDataSource.mjs.map +1 -1
  24. package/dist/data-sources/TokenDataSource.cjs +7 -4
  25. package/dist/data-sources/TokenDataSource.cjs.map +1 -1
  26. package/dist/data-sources/TokenDataSource.d.cts +6 -0
  27. package/dist/data-sources/TokenDataSource.d.cts.map +1 -1
  28. package/dist/data-sources/TokenDataSource.d.mts +6 -0
  29. package/dist/data-sources/TokenDataSource.d.mts.map +1 -1
  30. package/dist/data-sources/TokenDataSource.mjs +6 -3
  31. package/dist/data-sources/TokenDataSource.mjs.map +1 -1
  32. package/dist/types.cjs.map +1 -1
  33. package/dist/types.d.cts +1 -1
  34. package/dist/types.d.mts +1 -1
  35. package/dist/types.mjs.map +1 -1
  36. package/package.json +6 -6
@@ -1 +1 @@
1
- {"version":3,"file":"SnapDataSource.d.cts","sourceRoot":"","sources":["../../src/data-sources/SnapDataSource.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEV,cAAc,EACd,oBAAoB,EACpB,+BAA+B,EAEhC,wCAAwC;AACzC,OAAO,KAAK,EACV,oCAAoC,EACpC,iCAAiC,EAClC,oCAAoC;AAMrC,OAAO,KAAK,EAAE,yBAAyB,EAAE,gCAA4B;AAErE,OAAO,KAAK,EAEV,OAAO,EAEP,WAAW,EACX,YAAY,EACZ,UAAU,EACX,qBAAiB;AAClB,OAAO,EAAE,kBAAkB,EAAE,iCAA6B;AAC1D,OAAO,KAAK,EACV,eAAe,EACf,mBAAmB,EACpB,iCAA6B;AAM9B;;;GAGG;AACH,MAAM,MAAM,kCAAkC,GAAG;IAC/C,QAAQ,EAAE;QACR,CAAC,SAAS,EAAE,MAAM,GAAG;YACnB,CAAC,OAAO,EAAE,MAAM,GAAG;gBACjB,MAAM,EAAE,MAAM,CAAC;gBACf,IAAI,EAAE,MAAM,CAAC;aACd,CAAC;SACH,CAAC;KACH,CAAC;CACH,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,6CAA6C,GAAG;IAC1D,IAAI,EAAE,2CAA2C,CAAC;IAClD,OAAO,EAAE,CAAC,kCAAkC,CAAC,CAAC;CAC/C,CAAC;AAQF,eAAO,MAAM,qBAAqB,mBAAmB,CAAC;AAEtD,qDAAqD;AACrD,eAAO,MAAM,kBAAkB,sBAAsB,CAAC;AAEtD,wEAAwE;AACxE,eAAO,MAAM,iBAAiB,qBAAqB,CAAC;AAMpD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,CAAC,EAAE,oBAAoB,GAChC,OAAO,EAAE,GAAG,IAAI,CAUlB;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAGhE;AAMD;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;CACtC,GAAG,eAAe,CAAC;AAWpB;;GAEG;AACH,MAAM,MAAM,2BAA2B,GACnC,6CAA6C,GAC7C,+BAA+B,CAAC;AAEpC,MAAM,MAAM,4BAA4B,GACpC,oCAAoC,GACpC,iCAAiC,GACjC,cAAc,CAAC;AAMnB,MAAM,MAAM,qBAAqB,GAAG;IAClC,mEAAmE;IACnE,SAAS,EAAE,yBAAyB,CAAC;IACrC,mHAAmH;IACnH,qBAAqB,EAAE,CACrB,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,OAAO,EAAE,EACjB,cAAc,EAAE,OAAO,EAAE,KACtB,IAAI,CAAC;IACV,qEAAqE;IACrE,kBAAkB,CAAC,EAAE,OAAO,EAAE,CAAC;IAC/B,uDAAuD;IACvD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oBAAoB;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAC;CACtC,CAAC;AAMF;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,cAAe,SAAQ,kBAAkB,CACpD,OAAO,qBAAqB,EAC5B,mBAAmB,CACpB;;gBAmBa,OAAO,EAAE,qBAAqB;IAwNpC,KAAK,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IA2ExD;;;;;;;;;;OAUG;IACH,IAAI,gBAAgB,IAAI,UAAU,CA4EjC;IAMK,SAAS,CAAC,mBAAmB,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IA+GxE,OAAO,IAAI,IAAI;CAkChB;AAMD,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,qBAAqB,GAC7B,cAAc,CAEhB"}
1
+ {"version":3,"file":"SnapDataSource.d.cts","sourceRoot":"","sources":["../../src/data-sources/SnapDataSource.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEV,cAAc,EACd,oBAAoB,EACpB,+BAA+B,EAEhC,wCAAwC;AACzC,OAAO,KAAK,EACV,oCAAoC,EACpC,iCAAiC,EACjC,gCAAgC,EACjC,oCAAoC;AAMrC,OAAO,KAAK,EAAE,yBAAyB,EAAE,gCAA4B;AAErE,OAAO,KAAK,EAEV,OAAO,EAEP,WAAW,EACX,YAAY,EACZ,UAAU,EACX,qBAAiB;AAClB,OAAO,EAAE,kBAAkB,EAAE,iCAA6B;AAC1D,OAAO,KAAK,EACV,eAAe,EACf,mBAAmB,EACpB,iCAA6B;AAM9B;;;GAGG;AACH,MAAM,MAAM,kCAAkC,GAAG;IAC/C,QAAQ,EAAE;QACR,CAAC,SAAS,EAAE,MAAM,GAAG;YACnB,CAAC,OAAO,EAAE,MAAM,GAAG;gBACjB,MAAM,EAAE,MAAM,CAAC;gBACf,IAAI,EAAE,MAAM,CAAC;aACd,CAAC;SACH,CAAC;KACH,CAAC;CACH,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,6CAA6C,GAAG;IAC1D,IAAI,EAAE,2CAA2C,CAAC;IAClD,OAAO,EAAE,CAAC,kCAAkC,CAAC,CAAC;CAC/C,CAAC;AAQF,eAAO,MAAM,qBAAqB,mBAAmB,CAAC;AAEtD,qDAAqD;AACrD,eAAO,MAAM,kBAAkB,sBAAsB,CAAC;AAEtD,wEAAwE;AACxE,eAAO,MAAM,iBAAiB,qBAAqB,CAAC;AAMpD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,CAAC,EAAE,oBAAoB,GAChC,OAAO,EAAE,GAAG,IAAI,CAUlB;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAGhE;AAMD;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;CACtC,GAAG,eAAe,CAAC;AAWpB;;GAEG;AACH,MAAM,MAAM,2BAA2B,GACnC,6CAA6C,GAC7C,+BAA+B,GAC/B,gCAAgC,CAAC;AAErC,MAAM,MAAM,4BAA4B,GACpC,oCAAoC,GACpC,iCAAiC,GACjC,cAAc,CAAC;AAMnB,MAAM,MAAM,qBAAqB,GAAG;IAClC,mEAAmE;IACnE,SAAS,EAAE,yBAAyB,CAAC;IACrC,mHAAmH;IACnH,qBAAqB,EAAE,CACrB,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,OAAO,EAAE,EACjB,cAAc,EAAE,OAAO,EAAE,KACtB,IAAI,CAAC;IACV,qEAAqE;IACrE,kBAAkB,CAAC,EAAE,OAAO,EAAE,CAAC;IAC/B,uDAAuD;IACvD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oBAAoB;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAC;CACtC,CAAC;AAMF;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,cAAe,SAAQ,kBAAkB,CACpD,OAAO,qBAAqB,EAC5B,mBAAmB,CACpB;;gBAmBa,OAAO,EAAE,qBAAqB;IA4NpC,KAAK,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IA2ExD;;;;;;;;;;OAUG;IACH,IAAI,gBAAgB,IAAI,UAAU,CA4EjC;IAMK,SAAS,CAAC,mBAAmB,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IA+GxE,OAAO,IAAI,IAAI;CAkChB;AAMD,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,qBAAqB,GAC7B,cAAc,CAEhB"}
@@ -1,5 +1,5 @@
1
1
  import type { GetPermissions, PermissionConstraint, PermissionControllerStateChange } from "@metamask/permission-controller";
2
- import type { SnapControllerGetRunnableSnapsAction, SnapControllerHandleRequestAction } from "@metamask/snaps-controllers";
2
+ import type { SnapControllerGetRunnableSnapsAction, SnapControllerHandleRequestAction, SnapControllerSnapInstalledEvent } from "@metamask/snaps-controllers";
3
3
  import type { AssetsControllerMessenger } from "../AssetsController.mjs";
4
4
  import type { ChainId, DataRequest, DataResponse, Middleware } from "../types.mjs";
5
5
  import { AbstractDataSource } from "./AbstractDataSource.mjs";
@@ -64,7 +64,7 @@ export type SnapDataSourceState = {
64
64
  /**
65
65
  * Allowed events that SnapDataSource can subscribe to.
66
66
  */
67
- export type SnapDataSourceAllowedEvents = AccountsControllerAccountBalancesUpdatedEvent | PermissionControllerStateChange;
67
+ export type SnapDataSourceAllowedEvents = AccountsControllerAccountBalancesUpdatedEvent | PermissionControllerStateChange | SnapControllerSnapInstalledEvent;
68
68
  export type SnapDataSourceAllowedActions = SnapControllerGetRunnableSnapsAction | SnapControllerHandleRequestAction | GetPermissions;
69
69
  export type SnapDataSourceOptions = {
70
70
  /** The AssetsController messenger (shared by all data sources). */
@@ -1 +1 @@
1
- {"version":3,"file":"SnapDataSource.d.mts","sourceRoot":"","sources":["../../src/data-sources/SnapDataSource.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEV,cAAc,EACd,oBAAoB,EACpB,+BAA+B,EAEhC,wCAAwC;AACzC,OAAO,KAAK,EACV,oCAAoC,EACpC,iCAAiC,EAClC,oCAAoC;AAMrC,OAAO,KAAK,EAAE,yBAAyB,EAAE,gCAA4B;AAErE,OAAO,KAAK,EAEV,OAAO,EAEP,WAAW,EACX,YAAY,EACZ,UAAU,EACX,qBAAiB;AAClB,OAAO,EAAE,kBAAkB,EAAE,iCAA6B;AAC1D,OAAO,KAAK,EACV,eAAe,EACf,mBAAmB,EACpB,iCAA6B;AAM9B;;;GAGG;AACH,MAAM,MAAM,kCAAkC,GAAG;IAC/C,QAAQ,EAAE;QACR,CAAC,SAAS,EAAE,MAAM,GAAG;YACnB,CAAC,OAAO,EAAE,MAAM,GAAG;gBACjB,MAAM,EAAE,MAAM,CAAC;gBACf,IAAI,EAAE,MAAM,CAAC;aACd,CAAC;SACH,CAAC;KACH,CAAC;CACH,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,6CAA6C,GAAG;IAC1D,IAAI,EAAE,2CAA2C,CAAC;IAClD,OAAO,EAAE,CAAC,kCAAkC,CAAC,CAAC;CAC/C,CAAC;AAQF,eAAO,MAAM,qBAAqB,mBAAmB,CAAC;AAEtD,qDAAqD;AACrD,eAAO,MAAM,kBAAkB,sBAAsB,CAAC;AAEtD,wEAAwE;AACxE,eAAO,MAAM,iBAAiB,qBAAqB,CAAC;AAMpD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,CAAC,EAAE,oBAAoB,GAChC,OAAO,EAAE,GAAG,IAAI,CAUlB;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAGhE;AAMD;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;CACtC,GAAG,eAAe,CAAC;AAWpB;;GAEG;AACH,MAAM,MAAM,2BAA2B,GACnC,6CAA6C,GAC7C,+BAA+B,CAAC;AAEpC,MAAM,MAAM,4BAA4B,GACpC,oCAAoC,GACpC,iCAAiC,GACjC,cAAc,CAAC;AAMnB,MAAM,MAAM,qBAAqB,GAAG;IAClC,mEAAmE;IACnE,SAAS,EAAE,yBAAyB,CAAC;IACrC,mHAAmH;IACnH,qBAAqB,EAAE,CACrB,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,OAAO,EAAE,EACjB,cAAc,EAAE,OAAO,EAAE,KACtB,IAAI,CAAC;IACV,qEAAqE;IACrE,kBAAkB,CAAC,EAAE,OAAO,EAAE,CAAC;IAC/B,uDAAuD;IACvD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oBAAoB;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAC;CACtC,CAAC;AAMF;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,cAAe,SAAQ,kBAAkB,CACpD,OAAO,qBAAqB,EAC5B,mBAAmB,CACpB;;gBAmBa,OAAO,EAAE,qBAAqB;IAwNpC,KAAK,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IA2ExD;;;;;;;;;;OAUG;IACH,IAAI,gBAAgB,IAAI,UAAU,CA4EjC;IAMK,SAAS,CAAC,mBAAmB,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IA+GxE,OAAO,IAAI,IAAI;CAkChB;AAMD,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,qBAAqB,GAC7B,cAAc,CAEhB"}
1
+ {"version":3,"file":"SnapDataSource.d.mts","sourceRoot":"","sources":["../../src/data-sources/SnapDataSource.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEV,cAAc,EACd,oBAAoB,EACpB,+BAA+B,EAEhC,wCAAwC;AACzC,OAAO,KAAK,EACV,oCAAoC,EACpC,iCAAiC,EACjC,gCAAgC,EACjC,oCAAoC;AAMrC,OAAO,KAAK,EAAE,yBAAyB,EAAE,gCAA4B;AAErE,OAAO,KAAK,EAEV,OAAO,EAEP,WAAW,EACX,YAAY,EACZ,UAAU,EACX,qBAAiB;AAClB,OAAO,EAAE,kBAAkB,EAAE,iCAA6B;AAC1D,OAAO,KAAK,EACV,eAAe,EACf,mBAAmB,EACpB,iCAA6B;AAM9B;;;GAGG;AACH,MAAM,MAAM,kCAAkC,GAAG;IAC/C,QAAQ,EAAE;QACR,CAAC,SAAS,EAAE,MAAM,GAAG;YACnB,CAAC,OAAO,EAAE,MAAM,GAAG;gBACjB,MAAM,EAAE,MAAM,CAAC;gBACf,IAAI,EAAE,MAAM,CAAC;aACd,CAAC;SACH,CAAC;KACH,CAAC;CACH,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,6CAA6C,GAAG;IAC1D,IAAI,EAAE,2CAA2C,CAAC;IAClD,OAAO,EAAE,CAAC,kCAAkC,CAAC,CAAC;CAC/C,CAAC;AAQF,eAAO,MAAM,qBAAqB,mBAAmB,CAAC;AAEtD,qDAAqD;AACrD,eAAO,MAAM,kBAAkB,sBAAsB,CAAC;AAEtD,wEAAwE;AACxE,eAAO,MAAM,iBAAiB,qBAAqB,CAAC;AAMpD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,CAAC,EAAE,oBAAoB,GAChC,OAAO,EAAE,GAAG,IAAI,CAUlB;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAGhE;AAMD;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;CACtC,GAAG,eAAe,CAAC;AAWpB;;GAEG;AACH,MAAM,MAAM,2BAA2B,GACnC,6CAA6C,GAC7C,+BAA+B,GAC/B,gCAAgC,CAAC;AAErC,MAAM,MAAM,4BAA4B,GACpC,oCAAoC,GACpC,iCAAiC,GACjC,cAAc,CAAC;AAMnB,MAAM,MAAM,qBAAqB,GAAG;IAClC,mEAAmE;IACnE,SAAS,EAAE,yBAAyB,CAAC;IACrC,mHAAmH;IACnH,qBAAqB,EAAE,CACrB,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,OAAO,EAAE,EACjB,cAAc,EAAE,OAAO,EAAE,KACtB,IAAI,CAAC;IACV,qEAAqE;IACrE,kBAAkB,CAAC,EAAE,OAAO,EAAE,CAAC;IAC/B,uDAAuD;IACvD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oBAAoB;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAC;CACtC,CAAC;AAMF;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,cAAe,SAAQ,kBAAkB,CACpD,OAAO,qBAAqB,EAC5B,mBAAmB,CACpB;;gBAmBa,OAAO,EAAE,qBAAqB;IA4NpC,KAAK,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IA2ExD;;;;;;;;;;OAUG;IACH,IAAI,gBAAgB,IAAI,UAAU,CA4EjC;IAMK,SAAS,CAAC,mBAAmB,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IA+GxE,OAAO,IAAI,IAAI;CAkChB;AAMD,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,qBAAqB,GAC7B,cAAc,CAEhB"}
@@ -339,6 +339,10 @@ _SnapDataSource_messenger = new WeakMap(), _SnapDataSource_onActiveChainsUpdated
339
339
  const messenger = __classPrivateFieldGet(this, _SnapDataSource_messenger, "f");
340
340
  messenger.subscribe('AccountsController:accountBalancesUpdated', __classPrivateFieldGet(this, _SnapDataSource_handleSnapBalancesUpdatedBound, "f"));
341
341
  messenger.subscribe('PermissionController:stateChange', __classPrivateFieldGet(this, _SnapDataSource_handlePermissionStateChangeBound, "f"));
342
+ // Rediscover keyring snaps when any snap gets installed
343
+ messenger.subscribe('SnapController:snapInstalled', () => {
344
+ __classPrivateFieldGet(this, _SnapDataSource_instances, "m", _SnapDataSource_discoverKeyringSnaps).call(this);
345
+ });
342
346
  }, _SnapDataSource_handleSnapBalancesUpdated = function _SnapDataSource_handleSnapBalancesUpdated(payload) {
343
347
  // Transform the snap keyring payload to DataResponse format
344
348
  let assetsBalance;
@@ -1 +1 @@
1
- {"version":3,"file":"SnapDataSource.mjs","sourceRoot":"","sources":["../../src/data-sources/SnapDataSource.ts"],"names":[],"mappings":";;;;;;;;;;;;AACA,OAAO,EAAE,aAAa,EAAE,sCAAsC;AAa9D,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,8BAA8B;AACpE,OAAO,EAAE,kBAAkB,EAAE,wBAAwB;AAIrD,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,sBAAkB;AAS9D,OAAO,EAAE,kBAAkB,EAAE,iCAA6B;AAiC1D,MAAM,GAAG,GAAG,kBAAkB,CAAC,aAAa,EAAE,gBAAgB,CAAC,CAAC;AAEhE,+EAA+E;AAC/E,YAAY;AACZ,+EAA+E;AAE/E,MAAM,CAAC,MAAM,qBAAqB,GAAG,gBAAgB,CAAC;AAEtD,qDAAqD;AACrD,MAAM,CAAC,MAAM,kBAAkB,GAAG,mBAAmB,CAAC;AAEtD,wEAAwE;AACxE,MAAM,CAAC,MAAM,iBAAiB,GAAG,kBAAkB,CAAC;AAEpD,+EAA+E;AAC/E,uBAAuB;AACvB,+EAA+E;AAE/E;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAC/B,UAAiC;IAEjC,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,IAAI,CACpC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,KAAK,cAAc,CAAC,QAAQ,CACpB,CAAC;IAE1C,OAAO,MAAM,CAAC,CAAC,CAAE,MAAM,CAAC,KAAmB,CAAC,CAAC,CAAC,IAAI,CAAC;AACrD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,uBAAuB,CAAC,OAAe;IACrD,MAAM,MAAM,GAAG,kBAAkB,CAAC,OAAwB,CAAC,CAAC;IAC5D,OAAO,MAAM,CAAC,OAAO,CAAC;AACxB,CAAC;AAkBD,MAAM,gBAAgB,GAAwB;IAC5C,YAAY,EAAE,EAAE;IAChB,WAAW,EAAE,EAAE;CAChB,CAAC;AAuCF,+EAA+E;AAC/E,mBAAmB;AACnB,+EAA+E;AAE/E;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,OAAO,cAAe,SAAQ,kBAGnC;IAmBC,YAAY,OAA8B;QACxC,KAAK,CAAC,qBAAqB,EAAE;YAC3B,GAAG,gBAAgB;YACnB,GAAG,OAAO,CAAC,KAAK;SACjB,CAAC,CAAC;;QAtBI,4CAAsC;QAEtC,wDAIC;QAEV,yEAAyE;QAChE,iEAEC;QAED,mEAA8C;QAEvD,6EAA6E;QACpE,6CAAkD,IAAI,GAAG,EAAE,EAAC;QAQnE,uBAAA,IAAI,6BAAc,OAAO,CAAC,SAAS,MAAA,CAAC;QACpC,uBAAA,IAAI,yCAA0B,OAAO,CAAC,qBAAqB,MAAA,CAAC;QAE5D,yCAAyC;QACzC,uBAAA,IAAI,kDAAmC,uBAAA,IAAI,4EAA2B,CAAC,IAAI,CACzE,IAAI,CACoD,MAAA,CAAC;QAC3D,uBAAA,IAAI,oDACF,uBAAA,IAAI,uEAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,MAAA,CAAC;QAExC,uBAAA,IAAI,oEAAmB,MAAvB,IAAI,CAAqB,CAAC;QAE1B,uEAAuE;QACvE,uBAAA,IAAI,uEAAsB,MAA1B,IAAI,CAAwB,CAAC;IAC/B,CAAC;IAgMD,+EAA+E;IAC/E,QAAQ;IACR,+EAA+E;IAE/E,KAAK,CAAC,KAAK,CAAC,OAAoB;;QAC9B,kCAAkC;QAClC,gFAAgF;QAChF,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;YAC/B,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,IAAI,CAAC,OAAO,EAAE,2BAA2B,EAAE,MAAM,EAAE,CAAC;YAClD,OAAO,EAAE,aAAa,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC;QACnE,CAAC;QAED,MAAM,OAAO,GAAiB;YAC5B,aAAa,EAAE,EAAE;YACjB,UAAU,EAAE,EAAE;YACd,UAAU,EAAE,MAAM;SACnB,CAAC;QAEF,kEAAkE;QAClE,KAAK,MAAM,EAAE,OAAO,EAAE,IAAI,OAAO,CAAC,2BAA2B,EAAE,CAAC;YAC9D,0DAA0D;YAC1D,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;YACzC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,SAAS;YACX,CAAC;YAED,uEAAuE;YACvE,MAAM,2BAA2B,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,CACvD,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,KAAK,MAAM,CACxD,CAAC;YACF,IAAI,CAAC,2BAA2B,EAAE,CAAC;gBACjC,SAAS;YACX,CAAC;YAED,MAAM,SAAS,GAAG,OAAO,CAAC,EAAE,CAAC;YAC7B,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,uBAAA,IAAI,mEAAkB,MAAtB,IAAI,EAAmB,MAAM,CAAC,CAAC;gBAE9C,kDAAkD;gBAClD,MAAM,aAAa,GAAG,MAAM,MAAM,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC;gBAEhE,qCAAqC;gBACrC,IAAI,CAAC,aAAa,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBACjD,SAAS;gBACX,CAAC;gBAED,iDAAiD;gBACjD,MAAM,QAAQ,GACZ,MAAM,MAAM,CAAC,kBAAkB,CAC7B,SAAS,EACT,aAAgC,CACjC,CAAC;gBAEJ,oDAAoD;gBACpD,IAAI,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;oBACtE,KAAK,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;wBAC1D,MAAA,OAAO,CAAC,aAAa,EAAC,SAAS,SAAT,SAAS,IAAM,EAAE,EAAC;wBACxC,MAAM,eAAe,GAAG,OAAO,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;wBACzD,IAAI,eAAe,EAAE,CAAC;4BACnB,eAA2C,CAAC,OAAO,CAAC,GAAG;gCACtD,MAAM,EAAE,OAAO,CAAC,MAAM;6BACvB,CAAC;wBACJ,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,oDAAoD;YACtD,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,+EAA+E;IAC/E,aAAa;IACb,+EAA+E;IAE/E;;;;;;;;;;OAUG;IACH,IAAI,gBAAgB;QAClB,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;;YAC7B,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;YAE5B,6CAA6C;YAC7C,MAAM,eAAe,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAC1D,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,CAC1C,CAAC;YAEF,2DAA2D;YAC3D,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACjC,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC;YACvB,CAAC;YAED,IAAI,yBAAyB,GAAc,EAAE,CAAC;YAE9C,IAAI,CAAC;gBACH,6BAA6B;gBAC7B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC;oBAChC,GAAG,OAAO;oBACV,QAAQ,EAAE,eAAe;iBAC1B,CAAC,CAAC;gBAEH,8BAA8B;gBAC9B,IAAI,QAAQ,CAAC,aAAa,EAAE,CAAC;oBAC3B,MAAA,OAAO,CAAC,QAAQ,EAAC,aAAa,QAAb,aAAa,GAAK,EAAE,EAAC;oBACtC,KAAK,MAAM,CAAC,SAAS,EAAE,eAAe,CAAC,IAAI,MAAM,CAAC,OAAO,CACvD,QAAQ,CAAC,aAAa,CACvB,EAAE,CAAC;wBACF,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,SAAS,CAAC,GAAG;4BAC1C,GAAG,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,SAAS,CAAC;4BAC5C,GAAG,eAAe;yBACnB,CAAC;oBACJ,CAAC;gBACH,CAAC;gBACD,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC;oBACxB,OAAO,CAAC,QAAQ,CAAC,UAAU,GAAG;wBAC5B,GAAG,OAAO,CAAC,QAAQ,CAAC,UAAU;wBAC9B,GAAG,QAAQ,CAAC,UAAU;qBACvB,CAAC;gBACJ,CAAC;gBACD,IAAI,QAAQ,CAAC,WAAW,EAAE,CAAC;oBACzB,OAAO,CAAC,QAAQ,CAAC,WAAW,GAAG;wBAC7B,GAAG,OAAO,CAAC,QAAQ,CAAC,WAAW;wBAC/B,GAAG,QAAQ,CAAC,WAAW;qBACxB,CAAC;gBACJ,CAAC;gBAED,yDAAyD;gBACzD,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC;gBACjE,yBAAyB,GAAG,eAAe,CAAC,MAAM,CAChD,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CACxC,CAAC;YACJ,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,GAAG,CAAC,yBAAyB,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;gBAC1C,yBAAyB,GAAG,EAAE,CAAC;YACjC,CAAC;YAED,sCAAsC;YACtC,IAAI,WAAW,GAAG,OAAO,CAAC;YAC1B,IAAI,yBAAyB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACzC,MAAM,eAAe,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAC7C,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,yBAAyB,CAAC,QAAQ,CAAC,OAAO,CAAC,CAC1D,CAAC;gBACF,WAAW,GAAG;oBACZ,GAAG,OAAO;oBACV,OAAO,EAAE;wBACP,GAAG,OAAO;wBACV,QAAQ,EAAE,eAAe;qBAC1B;iBACF,CAAC;YACJ,CAAC;YAED,uBAAuB;YACvB,OAAO,IAAI,CAAC,WAAW,CAAC,CAAC;QAC3B,CAAC,CAAC;IACJ,CAAC;IAED,+EAA+E;IAC/E,4CAA4C;IAC5C,+EAA+E;IAE/E,KAAK,CAAC,SAAS,CAAC,mBAAwC;QACtD,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,GAAG,mBAAmB,CAAC;QAElE,8CAA8C;QAC9C,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,CAAC;YACvB,OAAO;QACT,CAAC;QAED,sCAAsC;QACtC,MAAM,eAAe,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAC1D,uBAAA,IAAI,yEAAwB,MAA5B,IAAI,EAAyB,OAAO,CAAC,CACtC,CAAC;QAEF,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACjC,OAAO;QACT,CAAC;QAED,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,QAAQ,GAAG,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;YAC9D,IAAI,QAAQ,EAAE,CAAC;gBACb,QAAQ,CAAC,MAAM,GAAG,eAAe,CAAC;gBAClC,uDAAuD;gBACvD,IAAI,CAAC,KAAK,CAAC;oBACT,GAAG,OAAO;oBACV,QAAQ,EAAE,eAAe;iBAC1B,CAAC;qBACC,IAAI,CAAC,KAAK,EAAE,aAAa,EAAE,EAAE;oBAC5B,IAAI,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBAC9D,MAAM,QAAQ,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC;oBAC/C,CAAC;oBACD,OAAO,aAAa,CAAC;gBACvB,CAAC,CAAC;qBACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;oBACf,GAAG,CAAC,kCAAkC,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC,CAAC;gBACrE,CAAC,CAAC,CAAC;gBACL,OAAO;YACT,CAAC;QACH,CAAC;QAED,MAAM,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;QAEvC,gFAAgF;QAChF,iEAAiE;QACjE,sEAAsE;QAEtE,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,cAAc,EAAE;YAC3C,OAAO,EAAE,GAAG,EAAE;gBACZ,iDAAiD;YACnD,CAAC;YACD,MAAM,EAAE,eAAe;YACvB,cAAc,EAAE,mBAAmB,CAAC,cAAc;SACnD,CAAC,CAAC;QAEH,wCAAwC;QACxC,IAAI,CAAC;YACH,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC;gBACrC,GAAG,OAAO;gBACV,QAAQ,EAAE,eAAe;aAC1B,CAAC,CAAC;YAEH,MAAM,YAAY,GAAG,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;YAClE,IACE,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC;gBACzD,YAAY,EACZ,CAAC;gBACD,MAAM,YAAY,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC;YACnD,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,GAAG,CAAC,sBAAsB,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC,CAAC;QACzD,CAAC;IACH,CAAC;IAqCD,+EAA+E;IAC/E,UAAU;IACV,+EAA+E;IAE/E,OAAO;QACL,8DAA8D;QAC9D,MAAM,SAAS,GAAG,uBAAA,IAAI,iCAAkB,CAAC;QAEzC,uCAAuC;QACvC,IAAI,CAAC;YACH,SAAS,CAAC,WAAW,CACnB,2CAA2C,EAC3C,uBAAA,IAAI,sDAAgC,CACrC,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,GAAG,CAAC,gDAAgD,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QACnE,CAAC;QAED,sCAAsC;QACtC,IAAI,CAAC;YACH,SAAS,CAAC,WAAW,CACnB,kCAAkC,EAClC,uBAAA,IAAI,wDAAkC,CACvC,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,GAAG,CAAC,+CAA+C,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QAClE,CAAC;QAED,gCAAgC;QAChC,KAAK,MAAM,CAAC,cAAc,CAAC,IAAI,IAAI,CAAC,mBAAmB,EAAE,CAAC;YACxD,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;gBAC1C,wBAAwB;YAC1B,CAAC,CAAC,CAAC;QACL,CAAC;QAED,6BAA6B;QAC7B,uBAAA,IAAI,0CAAoB,CAAC,KAAK,EAAE,CAAC;IACnC,CAAC;CACF;;IAtfG,2FAA2F;IAC3F,8DAA8D;IAC9D,MAAM,SAAS,GAAG,uBAAA,IAAI,iCAAkB,CAAC;IACzC,SAAS,CAAC,SAAS,CACjB,2CAA2C,EAC3C,uBAAA,IAAI,sDAAgC,CACrC,CAAC;IACF,SAAS,CAAC,SAAS,CACjB,kCAAkC,EAClC,uBAAA,IAAI,wDAAkC,CACvC,CAAC;AACJ,CAAC,iGASC,OAA2C;IAE3C,4DAA4D;IAC5D,IAAI,aAAqE,CAAC;IAE1E,KAAK,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QACnE,IAAI,aAA8D,CAAC;QAEnE,KAAK,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACxD,IAAI,OAAgB,CAAC;YACrB,IAAI,CAAC;gBACH,OAAO,GAAG,uBAAuB,CAAC,OAAO,CAAC,CAAC;YAC7C,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,GAAG,CAAC,8CAA8C,EAAE;oBAClD,OAAO;oBACP,KAAK;iBACN,CAAC,CAAC;gBACH,SAAS;YACX,CAAC;YACD,IAAI,uBAAA,IAAI,yEAAwB,MAA5B,IAAI,EAAyB,OAAO,CAAC,EAAE,CAAC;gBAC1C,aAAa,KAAb,aAAa,GAAK,EAAE,EAAC;gBACrB,aAAa,CAAC,OAAwB,CAAC,GAAG;oBACxC,MAAM,EAAE,OAAO,CAAC,MAAM;iBACvB,CAAC;YACJ,CAAC;QACH,CAAC;QAED,IAAI,aAAa,EAAE,CAAC;YAClB,aAAa,KAAb,aAAa,GAAK,EAAE,EAAC;YACrB,aAAa,CAAC,SAAS,CAAC,GAAG,aAAa,CAAC;QAC3C,CAAC;IACH,CAAC;IAED,8CAA8C;IAC9C,IAAI,aAAa,EAAE,CAAC;QAClB,MAAM,QAAQ,GAAiB,EAAE,aAAa,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC;QACtE,KAAK,MAAM,YAAY,IAAI,IAAI,CAAC,mBAAmB,CAAC,MAAM,EAAE,EAAE,CAAC;YAC7D,YAAY,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;AACH,CAAC,2FAQuB,OAAgB;IACtC,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AACnD,CAAC;IAaC,IAAI,CAAC;QACH,8DAA8D;QAC9D,OAAQ,uBAAA,IAAI,iCAAmB,CAAC,IAAI,CAClC,iCAAiC,CACxB,CAAC;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,8BAA8B,EAAE,KAAK,CAAC,CAAC;QAC3C,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC,mFASC,MAAc;IAEd,IAAI,CAAC;QACH,8DAA8D;QAC9D,OAAQ,uBAAA,IAAI,iCAAmB,CAAC,IAAI,CAClC,qCAAqC,EACrC,MAAM,CACqC,CAAC;IAChD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,oCAAoC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QAC7D,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;IAkBC,IAAI,CAAC;QACH,MAAM,aAAa,GAAG,uBAAA,IAAI,mEAAkB,MAAtB,IAAI,CAAoB,CAAC;QAC/C,MAAM,WAAW,GAA4B,EAAE,CAAC;QAChD,MAAM,eAAe,GAAc,EAAE,CAAC;QAEtC,KAAK,MAAM,IAAI,IAAI,aAAa,EAAE,CAAC;YACjC,MAAM,WAAW,GAAG,uBAAA,IAAI,qEAAoB,MAAxB,IAAI,EAAqB,IAAI,CAAC,EAAE,CAAC,CAAC;YACtD,8DAA8D;YAC9D,IAAI,CAAC,WAAW,EAAE,CAAC,kBAAkB,CAAC,EAAE,CAAC;gBACvC,SAAS;YACX,CAAC;YAED,0EAA0E;YAC1E,8CAA8C;YAC9C,MAAM,gBAAgB,GAAG,WAAW,CAAC,iBAAiB,CAAC,CAAC;YACxD,MAAM,QAAQ,GAAG,iBAAiB,CAAC,gBAAgB,CAAC,CAAC;YAErD,+EAA+E;YAC/E,IAAI,QAAQ,EAAE,CAAC;gBACb,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;oBAC/B,IAAI,CAAC,CAAC,OAAO,IAAI,WAAW,CAAC,EAAE,CAAC;wBAC9B,WAAW,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC;wBAC/B,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;oBAChC,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,6BAA6B;QAC7B,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,WAAW,CAAC;QAErC,2BAA2B;QAC3B,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;YAC9C,IAAI,CAAC,kBAAkB,CAAC,eAAe,EAAE,CAAC,aAAa,EAAE,EAAE;gBACzD,uBAAA,IAAI,6CAAuB,MAA3B,IAAI,EAAwB,IAAI,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,QAAQ,CAAC,CAAC;YACvE,CAAC,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,kEAAkE;QACpE,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,+BAA+B,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QAChD,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,EAAE,CAAC;QAC5B,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;YAC9C,IAAI,CAAC,kBAAkB,CAAC,EAAE,EAAE,CAAC,aAAa,EAAE,EAAE;gBAC5C,uBAAA,IAAI,6CAAuB,MAA3B,IAAI,EAAwB,IAAI,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,QAAQ,CAAC,CAAC;YACvE,CAAC,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,kEAAkE;QACpE,CAAC;IACH,CAAC;AACH,CAAC,+EAiQiB,MAAc;IAC9B,MAAM,YAAY,GAAG,uBAAA,IAAI,0CAAoB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC1D,IAAI,YAAY,EAAE,CAAC;QACjB,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC;QAC/B,IAAI,EAAE,KAAK,EAAE,OAAuB,EAAiB,EAAE,CACrD,MACE,uBAAA,IAAI,iCAGL,CAAC,IAAI,CAAC,8BAA8B,EAAE;YACrC,MAAM,EAAE,MAAgB;YACxB,MAAM,EAAE,UAAU;YAClB,OAAO,EAAE,WAAW,CAAC,gBAAgB;YACrC,OAAO;SACR,CAAC;KACL,CAAC,CAAC;IAEH,uBAAA,IAAI,0CAAoB,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7C,OAAO,MAAM,CAAC;AAChB,CAAC;AA0CH,+EAA+E;AAC/E,UAAU;AACV,+EAA+E;AAE/E,MAAM,UAAU,oBAAoB,CAClC,OAA8B;IAE9B,OAAO,IAAI,cAAc,CAAC,OAAO,CAAC,CAAC;AACrC,CAAC","sourcesContent":["import type { Balance, CaipAssetType } from '@metamask/keyring-api';\nimport { KeyringClient } from '@metamask/keyring-snap-client';\nimport type {\n Caveat,\n GetPermissions,\n PermissionConstraint,\n PermissionControllerStateChange,\n SubjectPermissions,\n} from '@metamask/permission-controller';\nimport type {\n SnapControllerGetRunnableSnapsAction,\n SnapControllerHandleRequestAction,\n} from '@metamask/snaps-controllers';\nimport type { Snap, SnapId } from '@metamask/snaps-sdk';\nimport { HandlerType, SnapCaveatType } from '@metamask/snaps-utils';\nimport { parseCaipAssetType } from '@metamask/utils';\nimport type { Json, JsonRpcRequest } from '@metamask/utils';\n\nimport type { AssetsControllerMessenger } from '../AssetsController';\nimport { projectLogger, createModuleLogger } from '../logger';\nimport type {\n AssetBalance,\n ChainId,\n Caip19AssetId,\n DataRequest,\n DataResponse,\n Middleware,\n} from '../types';\nimport { AbstractDataSource } from './AbstractDataSource';\nimport type {\n DataSourceState,\n SubscriptionRequest,\n} from './AbstractDataSource';\n\n// ============================================================================\n// SNAP KEYRING EVENT TYPES\n// ============================================================================\n\n/**\n * Payload for AccountsController:accountBalancesUpdated event.\n * Re-published from SnapKeyring:accountBalancesUpdated.\n */\nexport type AccountBalancesUpdatedEventPayload = {\n balances: {\n [accountId: string]: {\n [assetId: string]: {\n amount: string;\n unit: string;\n };\n };\n };\n};\n\n/**\n * Event from AccountsController when snap balances are updated.\n */\nexport type AccountsControllerAccountBalancesUpdatedEvent = {\n type: 'AccountsController:accountBalancesUpdated';\n payload: [AccountBalancesUpdatedEventPayload];\n};\n\nconst log = createModuleLogger(projectLogger, 'SnapDataSource');\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nexport const SNAP_DATA_SOURCE_NAME = 'SnapDataSource';\n\n/** The permission name for snap keyring endowment */\nexport const KEYRING_PERMISSION = 'endowment:keyring';\n\n/** The permission name for snap assets endowment (contains chainIds) */\nexport const ASSETS_PERMISSION = 'endowment:assets';\n\n// ============================================================================\n// PERMISSION UTILITIES\n// ============================================================================\n\n/**\n * Getter function to get the chainIds caveat from a permission.\n *\n * This does basic validation of the caveat, but does not validate the type or\n * value of the namespaces object itself, as this is handled by the\n * `PermissionsController` when the permission is requested.\n *\n * @param permission - The permission to get the `chainIds` caveat from.\n * @returns An array of `chainIds` that the snap supports, or null if none.\n */\nexport function getChainIdsCaveat(\n permission?: PermissionConstraint,\n): ChainId[] | null {\n if (!permission?.caveats) {\n return null;\n }\n\n const caveat = permission.caveats.find(\n (permCaveat) => permCaveat.type === SnapCaveatType.ChainIds,\n ) as Caveat<string, string[]> | undefined;\n\n return caveat ? (caveat.value as ChainId[]) : null;\n}\n\n/**\n * Extracts the CAIP-2 chain ID from a CAIP-19 asset ID.\n * e.g., \"solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501\" -> \"solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp\"\n * Uses @metamask/utils parseCaipAssetType for CAIP parsing.\n *\n * @param assetId - The CAIP-19 asset ID to extract chain from.\n * @returns The CAIP-2 chain ID portion of the asset ID.\n */\nexport function extractChainFromAssetId(assetId: string): ChainId {\n const parsed = parseCaipAssetType(assetId as CaipAssetType);\n return parsed.chainId;\n}\n\n// ============================================================================\n// STATE\n// ============================================================================\n\n/**\n * State for the SnapDataSource.\n * Uses dynamic snap discovery - chains are populated from PermissionController.\n */\nexport type SnapDataSourceState = {\n /**\n * Mapping of chain IDs to snap IDs that support them.\n * Used to filter which accounts to process for a given chain request.\n */\n chainToSnap: Record<ChainId, string>;\n} & DataSourceState;\n\nconst defaultSnapState: SnapDataSourceState = {\n activeChains: [],\n chainToSnap: {},\n};\n\n// ============================================================================\n// MESSENGER TYPES\n// ============================================================================\n\n/**\n * Allowed events that SnapDataSource can subscribe to.\n */\nexport type SnapDataSourceAllowedEvents =\n | AccountsControllerAccountBalancesUpdatedEvent\n | PermissionControllerStateChange;\n\nexport type SnapDataSourceAllowedActions =\n | SnapControllerGetRunnableSnapsAction\n | SnapControllerHandleRequestAction\n | GetPermissions;\n\n// ============================================================================\n// OPTIONS\n// ============================================================================\n\nexport type SnapDataSourceOptions = {\n /** The AssetsController messenger (shared by all data sources). */\n messenger: AssetsControllerMessenger;\n /** Called when this data source's active chains change. Pass dataSourceName so the controller knows the source. */\n onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n /** Configured networks to support (defaults to all snap networks) */\n configuredNetworks?: ChainId[];\n /** Default polling interval in ms for subscriptions */\n pollInterval?: number;\n /** Initial state */\n state?: Partial<SnapDataSourceState>;\n};\n\n// ============================================================================\n// SNAP DATA SOURCE\n// ============================================================================\n\n/**\n * Unified Snap data source that routes requests to the appropriate wallet snap\n * based on the chain ID prefix.\n *\n * @example\n * ```typescript\n * const snapDataSource = new SnapDataSource({\n * messenger,\n * onActiveChainsUpdated: (chains) => { /* ... *\\/ },\n * });\n *\n * // Fetch will automatically route to the correct snap\n * await snapDataSource.fetch({\n * chainIds: ['solana:mainnet', 'bip122:000000000019d6689c085ae165831e93'],\n * accountIds: ['account1'],\n * });\n * ```\n */\nexport class SnapDataSource extends AbstractDataSource<\n typeof SNAP_DATA_SOURCE_NAME,\n SnapDataSourceState\n> {\n readonly #messenger: AssetsControllerMessenger;\n\n readonly #onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n\n /** Bound handler for snap keyring balance updates, stored for cleanup */\n readonly #handleSnapBalancesUpdatedBound: (\n payload: AccountBalancesUpdatedEventPayload,\n ) => void;\n\n readonly #handlePermissionStateChangeBound: () => void;\n\n /** Cache of KeyringClient instances per snap ID to avoid re-instantiation */\n readonly #keyringClientCache: Map<string, KeyringClient> = new Map();\n\n constructor(options: SnapDataSourceOptions) {\n super(SNAP_DATA_SOURCE_NAME, {\n ...defaultSnapState,\n ...options.state,\n });\n\n this.#messenger = options.messenger;\n this.#onActiveChainsUpdated = options.onActiveChainsUpdated;\n\n // Bind handlers for cleanup in destroy()\n this.#handleSnapBalancesUpdatedBound = this.#handleSnapBalancesUpdated.bind(\n this,\n ) as (payload: AccountBalancesUpdatedEventPayload) => void;\n this.#handlePermissionStateChangeBound =\n this.#discoverKeyringSnaps.bind(this);\n\n this.#subscribeToEvents();\n\n // Discover keyring-capable snaps and populate activeChains dynamically\n this.#discoverKeyringSnaps();\n }\n\n /**\n * Subscribe to all events needed by SnapDataSource.\n * Groups snap keyring events and permission change events.\n */\n #subscribeToEvents(): void {\n // Subscribe to snap keyring events and permission changes (not in AssetsControllerEvents).\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const messenger = this.#messenger as any;\n messenger.subscribe(\n 'AccountsController:accountBalancesUpdated',\n this.#handleSnapBalancesUpdatedBound,\n );\n messenger.subscribe(\n 'PermissionController:stateChange',\n this.#handlePermissionStateChangeBound,\n );\n }\n\n /**\n * Handle snap balance updates from the keyring.\n * Transforms the payload and publishes to AssetsController.\n *\n * @param payload - The balance update payload from AccountsController.\n */\n #handleSnapBalancesUpdated(\n payload: AccountBalancesUpdatedEventPayload,\n ): void {\n // Transform the snap keyring payload to DataResponse format\n let assetsBalance: NonNullable<DataResponse['assetsBalance']> | undefined;\n\n for (const [accountId, assets] of Object.entries(payload.balances)) {\n let accountAssets: Record<Caip19AssetId, AssetBalance> | undefined;\n\n for (const [assetId, balance] of Object.entries(assets)) {\n let chainId: ChainId;\n try {\n chainId = extractChainFromAssetId(assetId);\n } catch (error) {\n log('Skipping snap balance for malformed asset ID', {\n assetId,\n error,\n });\n continue;\n }\n if (this.#isChainSupportedBySnap(chainId)) {\n accountAssets ??= {};\n accountAssets[assetId as Caip19AssetId] = {\n amount: balance.amount,\n };\n }\n }\n\n if (accountAssets) {\n assetsBalance ??= {};\n assetsBalance[accountId] = accountAssets;\n }\n }\n\n // Only report if we have snap-related updates\n if (assetsBalance) {\n const response: DataResponse = { assetsBalance, updateMode: 'merge' };\n for (const subscription of this.activeSubscriptions.values()) {\n subscription.onAssetsUpdate(response)?.catch(console.error);\n }\n }\n }\n\n /**\n * Check if a chain ID is supported by any discovered snap.\n *\n * @param chainId - The CAIP-2 chain ID to check.\n * @returns True if we have a snap that supports this chain.\n */\n #isChainSupportedBySnap(chainId: ChainId): boolean {\n return this.state.activeChains.includes(chainId);\n }\n\n // ============================================================================\n // SNAP DISCOVERY (Dynamic via PermissionController)\n // ============================================================================\n\n /**\n * Get all runnable snaps from SnapController.\n * Runnable snaps are enabled and not blocked.\n *\n * @returns Array of runnable snaps.\n */\n #getRunnableSnaps(): Snap[] {\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (this.#messenger as any).call(\n 'SnapController:getRunnableSnaps',\n ) as Snap[];\n } catch (error) {\n log('Failed to get runnable snaps', error);\n return [];\n }\n }\n\n /**\n * Get permissions for a snap from PermissionController.\n *\n * @param snapId - The snap ID to get permissions for.\n * @returns The snap's permissions, or undefined if none.\n */\n #getSnapPermissions(\n snapId: string,\n ): SubjectPermissions<PermissionConstraint> | undefined {\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (this.#messenger as any).call(\n 'PermissionController:getPermissions',\n snapId,\n ) as SubjectPermissions<PermissionConstraint>;\n } catch (error) {\n log('Failed to get permissions for snap', { snapId, error });\n return undefined;\n }\n }\n\n /**\n * Discover all snaps with keyring capabilities and their supported chains.\n * Uses PermissionController to find snaps with endowment:keyring permission.\n * Updates chainToSnap mapping and activeChains.\n *\n * Called on initialization and whenever PermissionController state changes\n * (e.g., new snaps installed, permissions granted/revoked).\n *\n * @remarks\n * **Known limitation:** If discovery fails (e.g., SnapController not ready),\n * the data source continues with empty chainToSnap. This means no snap\n * chains will be supported until a re-discovery is triggered by a permission\n * change. Callers should be aware that initialization may complete with no\n * active chains.\n */\n #discoverKeyringSnaps(): void {\n try {\n const runnableSnaps = this.#getRunnableSnaps();\n const chainToSnap: Record<ChainId, string> = {};\n const supportedChains: ChainId[] = [];\n\n for (const snap of runnableSnaps) {\n const permissions = this.#getSnapPermissions(snap.id);\n // Must have endowment:keyring permission to be a keyring snap\n if (!permissions?.[KEYRING_PERMISSION]) {\n continue;\n }\n\n // Get chainIds caveat from the assets permission (not keyring permission)\n // The chainIds are stored in endowment:assets\n const assetsPermission = permissions[ASSETS_PERMISSION];\n const chainIds = getChainIdsCaveat(assetsPermission);\n\n // Map each chain to this snap (first snap wins if multiple support same chain)\n if (chainIds) {\n for (const chainId of chainIds) {\n if (!(chainId in chainToSnap)) {\n chainToSnap[chainId] = snap.id;\n supportedChains.push(chainId);\n }\n }\n }\n }\n\n // Update chainToSnap mapping\n this.state.chainToSnap = chainToSnap;\n\n // Notify if chains changed\n try {\n const previous = [...this.state.activeChains];\n this.updateActiveChains(supportedChains, (updatedChains) => {\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous);\n });\n } catch {\n // AssetsController not ready yet - expected during initialization\n }\n } catch (error) {\n log('Keyring snap discovery failed', { error });\n this.state.chainToSnap = {};\n try {\n const previous = [...this.state.activeChains];\n this.updateActiveChains([], (updatedChains) => {\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous);\n });\n } catch {\n // AssetsController not ready yet - expected during initialization\n }\n }\n }\n\n // ============================================================================\n // FETCH\n // ============================================================================\n\n async fetch(request: DataRequest): Promise<DataResponse> {\n // Guard against undefined request\n // Note: chainIds filtering is done by middleware/subscribe before calling fetch\n if (!request?.chainIds?.length) {\n return {};\n }\n if (!request?.accountsWithSupportedChains?.length) {\n return { assetsBalance: {}, assetsInfo: {}, updateMode: 'full' };\n }\n\n const results: DataResponse = {\n assetsBalance: {},\n assetsInfo: {},\n updateMode: 'full',\n };\n\n // Fetch balances for each account using its snap ID from metadata\n for (const { account } of request.accountsWithSupportedChains) {\n // Skip accounts without snap metadata (non-snap accounts)\n const snapId = account.metadata.snap?.id;\n if (!snapId) {\n continue;\n }\n\n // Skip accounts whose snap doesn't support any of the requested chains\n const snapSupportsRequestedChains = request.chainIds.some(\n (chainId) => this.state.chainToSnap[chainId] === snapId,\n );\n if (!snapSupportsRequestedChains) {\n continue;\n }\n\n const accountId = account.id;\n try {\n const client = this.#getKeyringClient(snapId);\n\n // Step 1: Get the list of assets for this account\n const accountAssets = await client.listAccountAssets(accountId);\n\n // If no assets, skip to next account\n if (!accountAssets || accountAssets.length === 0) {\n continue;\n }\n\n // Step 2: Get balances for those specific assets\n const balances: Record<CaipAssetType, Balance> =\n await client.getAccountBalances(\n accountId,\n accountAssets as CaipAssetType[],\n );\n\n // Transform keyring response to DataResponse format\n if (balances && typeof balances === 'object' && results.assetsBalance) {\n for (const [assetId, balance] of Object.entries(balances)) {\n results.assetsBalance[accountId] ??= {};\n const accountBalances = results.assetsBalance[accountId];\n if (accountBalances) {\n (accountBalances as Record<string, unknown>)[assetId] = {\n amount: balance.amount,\n };\n }\n }\n }\n } catch {\n // Expected when account doesn't belong to this snap\n }\n }\n\n return results;\n }\n\n // ============================================================================\n // MIDDLEWARE\n // ============================================================================\n\n /**\n * Get the middleware for fetching balances via Snaps.\n * This middleware:\n * - Supports multiple accounts in a single request\n * - Filters request to only chains this data source supports\n * - Fetches balances for those chains for all accounts\n * - Merges response into context\n * - Removes handled chains from request for next middleware\n *\n * @returns The middleware function for the assets pipeline.\n */\n get assetsMiddleware(): Middleware {\n return async (context, next) => {\n const { request } = context;\n\n // Filter to chains this data source supports\n const supportedChains = request.chainIds.filter((chainId) =>\n this.state.activeChains.includes(chainId),\n );\n\n // If no supported chains, skip and pass to next middleware\n if (supportedChains.length === 0) {\n return next(context);\n }\n\n let successfullyHandledChains: ChainId[] = [];\n\n try {\n // Fetch for supported chains\n const response = await this.fetch({\n ...request,\n chainIds: supportedChains,\n });\n\n // Merge response into context\n if (response.assetsBalance) {\n context.response.assetsBalance ??= {};\n for (const [accountId, accountBalances] of Object.entries(\n response.assetsBalance,\n )) {\n context.response.assetsBalance[accountId] = {\n ...context.response.assetsBalance[accountId],\n ...accountBalances,\n };\n }\n }\n if (response.assetsInfo) {\n context.response.assetsInfo = {\n ...context.response.assetsInfo,\n ...response.assetsInfo,\n };\n }\n if (response.assetsPrice) {\n context.response.assetsPrice = {\n ...context.response.assetsPrice,\n ...response.assetsPrice,\n };\n }\n\n // Determine successfully handled chains (exclude errors)\n const failedChains = new Set(Object.keys(response.errors ?? {}));\n successfullyHandledChains = supportedChains.filter(\n (chainId) => !failedChains.has(chainId),\n );\n } catch (error) {\n log('Middleware fetch failed', { error });\n successfullyHandledChains = [];\n }\n\n // Prepare context for next middleware\n let nextContext = context;\n if (successfullyHandledChains.length > 0) {\n const remainingChains = request.chainIds.filter(\n (chainId) => !successfullyHandledChains.includes(chainId),\n );\n nextContext = {\n ...context,\n request: {\n ...request,\n chainIds: remainingChains,\n },\n };\n }\n\n // Call next middleware\n return next(nextContext);\n };\n }\n\n // ============================================================================\n // SUBSCRIBE - Routes to appropriate snap(s)\n // ============================================================================\n\n async subscribe(subscriptionRequest: SubscriptionRequest): Promise<void> {\n const { request, subscriptionId, isUpdate } = subscriptionRequest;\n\n // Guard against undefined request or chainIds\n if (!request?.chainIds) {\n return;\n }\n\n // Filter to chains we have a snap for\n const supportedChains = request.chainIds.filter((chainId) =>\n this.#isChainSupportedBySnap(chainId),\n );\n\n if (supportedChains.length === 0) {\n return;\n }\n\n if (isUpdate) {\n const existing = this.activeSubscriptions.get(subscriptionId);\n if (existing) {\n existing.chains = supportedChains;\n // Do a fetch to get latest data on subscription update\n this.fetch({\n ...request,\n chainIds: supportedChains,\n })\n .then(async (fetchResponse) => {\n if (Object.keys(fetchResponse.assetsBalance ?? {}).length > 0) {\n await existing.onAssetsUpdate(fetchResponse);\n }\n return fetchResponse;\n })\n .catch((error) => {\n log('Subscription update fetch failed', { subscriptionId, error });\n });\n return;\n }\n }\n\n await this.unsubscribe(subscriptionId);\n\n // Snaps provide real-time updates via AccountsController:accountBalancesUpdated\n // We only need to track the subscription and do an initial fetch\n // No polling needed - updates come through #handleSnapBalancesUpdated\n\n this.activeSubscriptions.set(subscriptionId, {\n cleanup: () => {\n // No timer to clear - we use event-based updates\n },\n chains: supportedChains,\n onAssetsUpdate: subscriptionRequest.onAssetsUpdate,\n });\n\n // Initial fetch to get current balances\n try {\n const fetchResponse = await this.fetch({\n ...request,\n chainIds: supportedChains,\n });\n\n const subscription = this.activeSubscriptions.get(subscriptionId);\n if (\n Object.keys(fetchResponse.assetsBalance ?? {}).length > 0 &&\n subscription\n ) {\n await subscription.onAssetsUpdate(fetchResponse);\n }\n } catch (error) {\n log('Initial fetch failed', { subscriptionId, error });\n }\n }\n\n // ============================================================================\n // KEYRING CLIENT\n // ============================================================================\n\n /**\n * Gets a `KeyringClient` for a Snap.\n * Caches clients per snap ID to avoid re-instantiation across multiple calls.\n *\n * @param snapId - ID of the Snap to get the client for.\n * @returns A `KeyringClient` for the Snap.\n */\n #getKeyringClient(snapId: string): KeyringClient {\n const cachedClient = this.#keyringClientCache.get(snapId);\n if (cachedClient) {\n return cachedClient;\n }\n\n const client = new KeyringClient({\n send: async (request: JsonRpcRequest): Promise<Json> =>\n await (\n this.#messenger as unknown as {\n call: (action: string, ...args: unknown[]) => Promise<Json> | Json;\n }\n ).call('SnapController:handleRequest', {\n snapId: snapId as SnapId,\n origin: 'metamask',\n handler: HandlerType.OnKeyringRequest,\n request,\n }),\n });\n\n this.#keyringClientCache.set(snapId, client);\n return client;\n }\n\n // ============================================================================\n // CLEANUP\n // ============================================================================\n\n destroy(): void {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const messenger = this.#messenger as any;\n\n // Unsubscribe from snap keyring events\n try {\n messenger.unsubscribe(\n 'AccountsController:accountBalancesUpdated',\n this.#handleSnapBalancesUpdatedBound,\n );\n } catch (error) {\n log('Failed to unsubscribe from snap keyring events', { error });\n }\n\n // Unsubscribe from permission changes\n try {\n messenger.unsubscribe(\n 'PermissionController:stateChange',\n this.#handlePermissionStateChangeBound,\n );\n } catch (error) {\n log('Failed to unsubscribe from permission changes', { error });\n }\n\n // Clean up active subscriptions\n for (const [subscriptionId] of this.activeSubscriptions) {\n this.unsubscribe(subscriptionId).catch(() => {\n // Ignore cleanup errors\n });\n }\n\n // Clear keyring client cache\n this.#keyringClientCache.clear();\n }\n}\n\n// ============================================================================\n// FACTORY\n// ============================================================================\n\nexport function createSnapDataSource(\n options: SnapDataSourceOptions,\n): SnapDataSource {\n return new SnapDataSource(options);\n}\n"]}
1
+ {"version":3,"file":"SnapDataSource.mjs","sourceRoot":"","sources":["../../src/data-sources/SnapDataSource.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Balance, CaipAssetType } from '@metamask/keyring-api';\nimport { KeyringClient } from '@metamask/keyring-snap-client';\nimport type {\n Caveat,\n GetPermissions,\n PermissionConstraint,\n PermissionControllerStateChange,\n SubjectPermissions,\n} from '@metamask/permission-controller';\nimport type {\n SnapControllerGetRunnableSnapsAction,\n SnapControllerHandleRequestAction,\n SnapControllerSnapInstalledEvent,\n} from '@metamask/snaps-controllers';\nimport type { Snap, SnapId } from '@metamask/snaps-sdk';\nimport { HandlerType, SnapCaveatType } from '@metamask/snaps-utils';\nimport { parseCaipAssetType } from '@metamask/utils';\nimport type { Json, JsonRpcRequest } from '@metamask/utils';\n\nimport type { AssetsControllerMessenger } from '../AssetsController';\nimport { projectLogger, createModuleLogger } from '../logger';\nimport type {\n AssetBalance,\n ChainId,\n Caip19AssetId,\n DataRequest,\n DataResponse,\n Middleware,\n} from '../types';\nimport { AbstractDataSource } from './AbstractDataSource';\nimport type {\n DataSourceState,\n SubscriptionRequest,\n} from './AbstractDataSource';\n\n// ============================================================================\n// SNAP KEYRING EVENT TYPES\n// ============================================================================\n\n/**\n * Payload for AccountsController:accountBalancesUpdated event.\n * Re-published from SnapKeyring:accountBalancesUpdated.\n */\nexport type AccountBalancesUpdatedEventPayload = {\n balances: {\n [accountId: string]: {\n [assetId: string]: {\n amount: string;\n unit: string;\n };\n };\n };\n};\n\n/**\n * Event from AccountsController when snap balances are updated.\n */\nexport type AccountsControllerAccountBalancesUpdatedEvent = {\n type: 'AccountsController:accountBalancesUpdated';\n payload: [AccountBalancesUpdatedEventPayload];\n};\n\nconst log = createModuleLogger(projectLogger, 'SnapDataSource');\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nexport const SNAP_DATA_SOURCE_NAME = 'SnapDataSource';\n\n/** The permission name for snap keyring endowment */\nexport const KEYRING_PERMISSION = 'endowment:keyring';\n\n/** The permission name for snap assets endowment (contains chainIds) */\nexport const ASSETS_PERMISSION = 'endowment:assets';\n\n// ============================================================================\n// PERMISSION UTILITIES\n// ============================================================================\n\n/**\n * Getter function to get the chainIds caveat from a permission.\n *\n * This does basic validation of the caveat, but does not validate the type or\n * value of the namespaces object itself, as this is handled by the\n * `PermissionsController` when the permission is requested.\n *\n * @param permission - The permission to get the `chainIds` caveat from.\n * @returns An array of `chainIds` that the snap supports, or null if none.\n */\nexport function getChainIdsCaveat(\n permission?: PermissionConstraint,\n): ChainId[] | null {\n if (!permission?.caveats) {\n return null;\n }\n\n const caveat = permission.caveats.find(\n (permCaveat) => permCaveat.type === SnapCaveatType.ChainIds,\n ) as Caveat<string, string[]> | undefined;\n\n return caveat ? (caveat.value as ChainId[]) : null;\n}\n\n/**\n * Extracts the CAIP-2 chain ID from a CAIP-19 asset ID.\n * e.g., \"solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501\" -> \"solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp\"\n * Uses @metamask/utils parseCaipAssetType for CAIP parsing.\n *\n * @param assetId - The CAIP-19 asset ID to extract chain from.\n * @returns The CAIP-2 chain ID portion of the asset ID.\n */\nexport function extractChainFromAssetId(assetId: string): ChainId {\n const parsed = parseCaipAssetType(assetId as CaipAssetType);\n return parsed.chainId;\n}\n\n// ============================================================================\n// STATE\n// ============================================================================\n\n/**\n * State for the SnapDataSource.\n * Uses dynamic snap discovery - chains are populated from PermissionController.\n */\nexport type SnapDataSourceState = {\n /**\n * Mapping of chain IDs to snap IDs that support them.\n * Used to filter which accounts to process for a given chain request.\n */\n chainToSnap: Record<ChainId, string>;\n} & DataSourceState;\n\nconst defaultSnapState: SnapDataSourceState = {\n activeChains: [],\n chainToSnap: {},\n};\n\n// ============================================================================\n// MESSENGER TYPES\n// ============================================================================\n\n/**\n * Allowed events that SnapDataSource can subscribe to.\n */\nexport type SnapDataSourceAllowedEvents =\n | AccountsControllerAccountBalancesUpdatedEvent\n | PermissionControllerStateChange\n | SnapControllerSnapInstalledEvent;\n\nexport type SnapDataSourceAllowedActions =\n | SnapControllerGetRunnableSnapsAction\n | SnapControllerHandleRequestAction\n | GetPermissions;\n\n// ============================================================================\n// OPTIONS\n// ============================================================================\n\nexport type SnapDataSourceOptions = {\n /** The AssetsController messenger (shared by all data sources). */\n messenger: AssetsControllerMessenger;\n /** Called when this data source's active chains change. Pass dataSourceName so the controller knows the source. */\n onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n /** Configured networks to support (defaults to all snap networks) */\n configuredNetworks?: ChainId[];\n /** Default polling interval in ms for subscriptions */\n pollInterval?: number;\n /** Initial state */\n state?: Partial<SnapDataSourceState>;\n};\n\n// ============================================================================\n// SNAP DATA SOURCE\n// ============================================================================\n\n/**\n * Unified Snap data source that routes requests to the appropriate wallet snap\n * based on the chain ID prefix.\n *\n * @example\n * ```typescript\n * const snapDataSource = new SnapDataSource({\n * messenger,\n * onActiveChainsUpdated: (chains) => { /* ... *\\/ },\n * });\n *\n * // Fetch will automatically route to the correct snap\n * await snapDataSource.fetch({\n * chainIds: ['solana:mainnet', 'bip122:000000000019d6689c085ae165831e93'],\n * accountIds: ['account1'],\n * });\n * ```\n */\nexport class SnapDataSource extends AbstractDataSource<\n typeof SNAP_DATA_SOURCE_NAME,\n SnapDataSourceState\n> {\n readonly #messenger: AssetsControllerMessenger;\n\n readonly #onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n\n /** Bound handler for snap keyring balance updates, stored for cleanup */\n readonly #handleSnapBalancesUpdatedBound: (\n payload: AccountBalancesUpdatedEventPayload,\n ) => void;\n\n readonly #handlePermissionStateChangeBound: () => void;\n\n /** Cache of KeyringClient instances per snap ID to avoid re-instantiation */\n readonly #keyringClientCache: Map<string, KeyringClient> = new Map();\n\n constructor(options: SnapDataSourceOptions) {\n super(SNAP_DATA_SOURCE_NAME, {\n ...defaultSnapState,\n ...options.state,\n });\n\n this.#messenger = options.messenger;\n this.#onActiveChainsUpdated = options.onActiveChainsUpdated;\n\n // Bind handlers for cleanup in destroy()\n this.#handleSnapBalancesUpdatedBound = this.#handleSnapBalancesUpdated.bind(\n this,\n ) as (payload: AccountBalancesUpdatedEventPayload) => void;\n this.#handlePermissionStateChangeBound =\n this.#discoverKeyringSnaps.bind(this);\n\n this.#subscribeToEvents();\n\n // Discover keyring-capable snaps and populate activeChains dynamically\n this.#discoverKeyringSnaps();\n }\n\n /**\n * Subscribe to all events needed by SnapDataSource.\n * Groups snap keyring events and permission change events.\n */\n #subscribeToEvents(): void {\n // Subscribe to snap keyring events and permission changes (not in AssetsControllerEvents).\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const messenger = this.#messenger as any;\n messenger.subscribe(\n 'AccountsController:accountBalancesUpdated',\n this.#handleSnapBalancesUpdatedBound,\n );\n messenger.subscribe(\n 'PermissionController:stateChange',\n this.#handlePermissionStateChangeBound,\n );\n // Rediscover keyring snaps when any snap gets installed\n messenger.subscribe('SnapController:snapInstalled', () => {\n this.#discoverKeyringSnaps();\n });\n }\n\n /**\n * Handle snap balance updates from the keyring.\n * Transforms the payload and publishes to AssetsController.\n *\n * @param payload - The balance update payload from AccountsController.\n */\n #handleSnapBalancesUpdated(\n payload: AccountBalancesUpdatedEventPayload,\n ): void {\n // Transform the snap keyring payload to DataResponse format\n let assetsBalance: NonNullable<DataResponse['assetsBalance']> | undefined;\n\n for (const [accountId, assets] of Object.entries(payload.balances)) {\n let accountAssets: Record<Caip19AssetId, AssetBalance> | undefined;\n\n for (const [assetId, balance] of Object.entries(assets)) {\n let chainId: ChainId;\n try {\n chainId = extractChainFromAssetId(assetId);\n } catch (error) {\n log('Skipping snap balance for malformed asset ID', {\n assetId,\n error,\n });\n continue;\n }\n if (this.#isChainSupportedBySnap(chainId)) {\n accountAssets ??= {};\n accountAssets[assetId as Caip19AssetId] = {\n amount: balance.amount,\n };\n }\n }\n\n if (accountAssets) {\n assetsBalance ??= {};\n assetsBalance[accountId] = accountAssets;\n }\n }\n\n // Only report if we have snap-related updates\n if (assetsBalance) {\n const response: DataResponse = { assetsBalance, updateMode: 'merge' };\n for (const subscription of this.activeSubscriptions.values()) {\n subscription.onAssetsUpdate(response)?.catch(console.error);\n }\n }\n }\n\n /**\n * Check if a chain ID is supported by any discovered snap.\n *\n * @param chainId - The CAIP-2 chain ID to check.\n * @returns True if we have a snap that supports this chain.\n */\n #isChainSupportedBySnap(chainId: ChainId): boolean {\n return this.state.activeChains.includes(chainId);\n }\n\n // ============================================================================\n // SNAP DISCOVERY (Dynamic via PermissionController)\n // ============================================================================\n\n /**\n * Get all runnable snaps from SnapController.\n * Runnable snaps are enabled and not blocked.\n *\n * @returns Array of runnable snaps.\n */\n #getRunnableSnaps(): Snap[] {\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (this.#messenger as any).call(\n 'SnapController:getRunnableSnaps',\n ) as Snap[];\n } catch (error) {\n log('Failed to get runnable snaps', error);\n return [];\n }\n }\n\n /**\n * Get permissions for a snap from PermissionController.\n *\n * @param snapId - The snap ID to get permissions for.\n * @returns The snap's permissions, or undefined if none.\n */\n #getSnapPermissions(\n snapId: string,\n ): SubjectPermissions<PermissionConstraint> | undefined {\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (this.#messenger as any).call(\n 'PermissionController:getPermissions',\n snapId,\n ) as SubjectPermissions<PermissionConstraint>;\n } catch (error) {\n log('Failed to get permissions for snap', { snapId, error });\n return undefined;\n }\n }\n\n /**\n * Discover all snaps with keyring capabilities and their supported chains.\n * Uses PermissionController to find snaps with endowment:keyring permission.\n * Updates chainToSnap mapping and activeChains.\n *\n * Called on initialization and whenever PermissionController state changes\n * (e.g., new snaps installed, permissions granted/revoked).\n *\n * @remarks\n * **Known limitation:** If discovery fails (e.g., SnapController not ready),\n * the data source continues with empty chainToSnap. This means no snap\n * chains will be supported until a re-discovery is triggered by a permission\n * change. Callers should be aware that initialization may complete with no\n * active chains.\n */\n #discoverKeyringSnaps(): void {\n try {\n const runnableSnaps = this.#getRunnableSnaps();\n const chainToSnap: Record<ChainId, string> = {};\n const supportedChains: ChainId[] = [];\n\n for (const snap of runnableSnaps) {\n const permissions = this.#getSnapPermissions(snap.id);\n // Must have endowment:keyring permission to be a keyring snap\n if (!permissions?.[KEYRING_PERMISSION]) {\n continue;\n }\n\n // Get chainIds caveat from the assets permission (not keyring permission)\n // The chainIds are stored in endowment:assets\n const assetsPermission = permissions[ASSETS_PERMISSION];\n const chainIds = getChainIdsCaveat(assetsPermission);\n\n // Map each chain to this snap (first snap wins if multiple support same chain)\n if (chainIds) {\n for (const chainId of chainIds) {\n if (!(chainId in chainToSnap)) {\n chainToSnap[chainId] = snap.id;\n supportedChains.push(chainId);\n }\n }\n }\n }\n\n // Update chainToSnap mapping\n this.state.chainToSnap = chainToSnap;\n\n // Notify if chains changed\n try {\n const previous = [...this.state.activeChains];\n this.updateActiveChains(supportedChains, (updatedChains) => {\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous);\n });\n } catch {\n // AssetsController not ready yet - expected during initialization\n }\n } catch (error) {\n log('Keyring snap discovery failed', { error });\n this.state.chainToSnap = {};\n try {\n const previous = [...this.state.activeChains];\n this.updateActiveChains([], (updatedChains) => {\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous);\n });\n } catch {\n // AssetsController not ready yet - expected during initialization\n }\n }\n }\n\n // ============================================================================\n // FETCH\n // ============================================================================\n\n async fetch(request: DataRequest): Promise<DataResponse> {\n // Guard against undefined request\n // Note: chainIds filtering is done by middleware/subscribe before calling fetch\n if (!request?.chainIds?.length) {\n return {};\n }\n if (!request?.accountsWithSupportedChains?.length) {\n return { assetsBalance: {}, assetsInfo: {}, updateMode: 'full' };\n }\n\n const results: DataResponse = {\n assetsBalance: {},\n assetsInfo: {},\n updateMode: 'full',\n };\n\n // Fetch balances for each account using its snap ID from metadata\n for (const { account } of request.accountsWithSupportedChains) {\n // Skip accounts without snap metadata (non-snap accounts)\n const snapId = account.metadata.snap?.id;\n if (!snapId) {\n continue;\n }\n\n // Skip accounts whose snap doesn't support any of the requested chains\n const snapSupportsRequestedChains = request.chainIds.some(\n (chainId) => this.state.chainToSnap[chainId] === snapId,\n );\n if (!snapSupportsRequestedChains) {\n continue;\n }\n\n const accountId = account.id;\n try {\n const client = this.#getKeyringClient(snapId);\n\n // Step 1: Get the list of assets for this account\n const accountAssets = await client.listAccountAssets(accountId);\n\n // If no assets, skip to next account\n if (!accountAssets || accountAssets.length === 0) {\n continue;\n }\n\n // Step 2: Get balances for those specific assets\n const balances: Record<CaipAssetType, Balance> =\n await client.getAccountBalances(\n accountId,\n accountAssets as CaipAssetType[],\n );\n\n // Transform keyring response to DataResponse format\n if (balances && typeof balances === 'object' && results.assetsBalance) {\n for (const [assetId, balance] of Object.entries(balances)) {\n results.assetsBalance[accountId] ??= {};\n const accountBalances = results.assetsBalance[accountId];\n if (accountBalances) {\n (accountBalances as Record<string, unknown>)[assetId] = {\n amount: balance.amount,\n };\n }\n }\n }\n } catch {\n // Expected when account doesn't belong to this snap\n }\n }\n\n return results;\n }\n\n // ============================================================================\n // MIDDLEWARE\n // ============================================================================\n\n /**\n * Get the middleware for fetching balances via Snaps.\n * This middleware:\n * - Supports multiple accounts in a single request\n * - Filters request to only chains this data source supports\n * - Fetches balances for those chains for all accounts\n * - Merges response into context\n * - Removes handled chains from request for next middleware\n *\n * @returns The middleware function for the assets pipeline.\n */\n get assetsMiddleware(): Middleware {\n return async (context, next) => {\n const { request } = context;\n\n // Filter to chains this data source supports\n const supportedChains = request.chainIds.filter((chainId) =>\n this.state.activeChains.includes(chainId),\n );\n\n // If no supported chains, skip and pass to next middleware\n if (supportedChains.length === 0) {\n return next(context);\n }\n\n let successfullyHandledChains: ChainId[] = [];\n\n try {\n // Fetch for supported chains\n const response = await this.fetch({\n ...request,\n chainIds: supportedChains,\n });\n\n // Merge response into context\n if (response.assetsBalance) {\n context.response.assetsBalance ??= {};\n for (const [accountId, accountBalances] of Object.entries(\n response.assetsBalance,\n )) {\n context.response.assetsBalance[accountId] = {\n ...context.response.assetsBalance[accountId],\n ...accountBalances,\n };\n }\n }\n if (response.assetsInfo) {\n context.response.assetsInfo = {\n ...context.response.assetsInfo,\n ...response.assetsInfo,\n };\n }\n if (response.assetsPrice) {\n context.response.assetsPrice = {\n ...context.response.assetsPrice,\n ...response.assetsPrice,\n };\n }\n\n // Determine successfully handled chains (exclude errors)\n const failedChains = new Set(Object.keys(response.errors ?? {}));\n successfullyHandledChains = supportedChains.filter(\n (chainId) => !failedChains.has(chainId),\n );\n } catch (error) {\n log('Middleware fetch failed', { error });\n successfullyHandledChains = [];\n }\n\n // Prepare context for next middleware\n let nextContext = context;\n if (successfullyHandledChains.length > 0) {\n const remainingChains = request.chainIds.filter(\n (chainId) => !successfullyHandledChains.includes(chainId),\n );\n nextContext = {\n ...context,\n request: {\n ...request,\n chainIds: remainingChains,\n },\n };\n }\n\n // Call next middleware\n return next(nextContext);\n };\n }\n\n // ============================================================================\n // SUBSCRIBE - Routes to appropriate snap(s)\n // ============================================================================\n\n async subscribe(subscriptionRequest: SubscriptionRequest): Promise<void> {\n const { request, subscriptionId, isUpdate } = subscriptionRequest;\n\n // Guard against undefined request or chainIds\n if (!request?.chainIds) {\n return;\n }\n\n // Filter to chains we have a snap for\n const supportedChains = request.chainIds.filter((chainId) =>\n this.#isChainSupportedBySnap(chainId),\n );\n\n if (supportedChains.length === 0) {\n return;\n }\n\n if (isUpdate) {\n const existing = this.activeSubscriptions.get(subscriptionId);\n if (existing) {\n existing.chains = supportedChains;\n // Do a fetch to get latest data on subscription update\n this.fetch({\n ...request,\n chainIds: supportedChains,\n })\n .then(async (fetchResponse) => {\n if (Object.keys(fetchResponse.assetsBalance ?? {}).length > 0) {\n await existing.onAssetsUpdate(fetchResponse);\n }\n return fetchResponse;\n })\n .catch((error) => {\n log('Subscription update fetch failed', { subscriptionId, error });\n });\n return;\n }\n }\n\n await this.unsubscribe(subscriptionId);\n\n // Snaps provide real-time updates via AccountsController:accountBalancesUpdated\n // We only need to track the subscription and do an initial fetch\n // No polling needed - updates come through #handleSnapBalancesUpdated\n\n this.activeSubscriptions.set(subscriptionId, {\n cleanup: () => {\n // No timer to clear - we use event-based updates\n },\n chains: supportedChains,\n onAssetsUpdate: subscriptionRequest.onAssetsUpdate,\n });\n\n // Initial fetch to get current balances\n try {\n const fetchResponse = await this.fetch({\n ...request,\n chainIds: supportedChains,\n });\n\n const subscription = this.activeSubscriptions.get(subscriptionId);\n if (\n Object.keys(fetchResponse.assetsBalance ?? {}).length > 0 &&\n subscription\n ) {\n await subscription.onAssetsUpdate(fetchResponse);\n }\n } catch (error) {\n log('Initial fetch failed', { subscriptionId, error });\n }\n }\n\n // ============================================================================\n // KEYRING CLIENT\n // ============================================================================\n\n /**\n * Gets a `KeyringClient` for a Snap.\n * Caches clients per snap ID to avoid re-instantiation across multiple calls.\n *\n * @param snapId - ID of the Snap to get the client for.\n * @returns A `KeyringClient` for the Snap.\n */\n #getKeyringClient(snapId: string): KeyringClient {\n const cachedClient = this.#keyringClientCache.get(snapId);\n if (cachedClient) {\n return cachedClient;\n }\n\n const client = new KeyringClient({\n send: async (request: JsonRpcRequest): Promise<Json> =>\n await (\n this.#messenger as unknown as {\n call: (action: string, ...args: unknown[]) => Promise<Json> | Json;\n }\n ).call('SnapController:handleRequest', {\n snapId: snapId as SnapId,\n origin: 'metamask',\n handler: HandlerType.OnKeyringRequest,\n request,\n }),\n });\n\n this.#keyringClientCache.set(snapId, client);\n return client;\n }\n\n // ============================================================================\n // CLEANUP\n // ============================================================================\n\n destroy(): void {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const messenger = this.#messenger as any;\n\n // Unsubscribe from snap keyring events\n try {\n messenger.unsubscribe(\n 'AccountsController:accountBalancesUpdated',\n this.#handleSnapBalancesUpdatedBound,\n );\n } catch (error) {\n log('Failed to unsubscribe from snap keyring events', { error });\n }\n\n // Unsubscribe from permission changes\n try {\n messenger.unsubscribe(\n 'PermissionController:stateChange',\n this.#handlePermissionStateChangeBound,\n );\n } catch (error) {\n log('Failed to unsubscribe from permission changes', { error });\n }\n\n // Clean up active subscriptions\n for (const [subscriptionId] of this.activeSubscriptions) {\n this.unsubscribe(subscriptionId).catch(() => {\n // Ignore cleanup errors\n });\n }\n\n // Clear keyring client cache\n this.#keyringClientCache.clear();\n }\n}\n\n// ============================================================================\n// FACTORY\n// ============================================================================\n\nexport function createSnapDataSource(\n options: SnapDataSourceOptions,\n): SnapDataSource {\n return new SnapDataSource(options);\n}\n"]}
@@ -12,7 +12,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
12
12
  };
13
13
  var _TokenDataSource_instances, _TokenDataSource_apiClient, _TokenDataSource_getNativeAssetIds, _TokenDataSource_messenger, _TokenDataSource_fetchTimeoutMs, _TokenDataSource_getSupportedNetworks, _TokenDataSource_filterAssetsByNetwork, _TokenDataSource_filterBlockaidSpamTokens;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.TokenDataSource = void 0;
15
+ exports.TokenDataSource = exports.CaipAssetNamespace = void 0;
16
16
  const core_backend_1 = require("@metamask/core-backend");
17
17
  const phishing_controller_1 = require("@metamask/phishing-controller");
18
18
  const utils_1 = require("@metamask/utils");
@@ -41,7 +41,7 @@ var CaipAssetNamespace;
41
41
  CaipAssetNamespace["Slip44"] = "slip44";
42
42
  CaipAssetNamespace["Erc20"] = "erc20";
43
43
  CaipAssetNamespace["Token"] = "token";
44
- })(CaipAssetNamespace || (CaipAssetNamespace = {}));
44
+ })(CaipAssetNamespace || (exports.CaipAssetNamespace = CaipAssetNamespace = {}));
45
45
  const MUSD_ADDRESS_LOWERCASE = '0xaca92e438df0b2401ff60da7e4337b687a2435da';
46
46
  // ============================================================================
47
47
  // HELPER FUNCTIONS
@@ -62,12 +62,15 @@ const MUSD_ADDRESS_LOWERCASE = '0xaca92e438df0b2401ff60da7e4337b687a2435da';
62
62
  function transformV3AssetResponseToMetadata(assetId, assetData, nativeAssetIds) {
63
63
  const parsed = (0, utils_1.parseCaipAssetType)(assetId);
64
64
  let tokenType = 'erc20';
65
- if (nativeAssetIds.has(assetId.toLowerCase())) {
65
+ if (nativeAssetIds.has(assetId.toLowerCase()) ||
66
+ parsed.assetNamespace === CaipAssetNamespace.Slip44) {
66
67
  tokenType = 'native';
67
68
  }
68
- else if (parsed.assetNamespace === 'spl') {
69
+ else if (parsed.chain.namespace === utils_1.KnownCaipNamespace.Solana &&
70
+ parsed.assetNamespace === CaipAssetNamespace.Token) {
69
71
  tokenType = 'spl';
70
72
  }
73
+ // TODO: Add support for Tron trc20 standard
71
74
  const metadata = {
72
75
  // Type derived from assetId
73
76
  type: tokenType,
@@ -1 +1 @@
1
- {"version":3,"file":"TokenDataSource.cjs","sourceRoot":"","sources":["../../src/data-sources/TokenDataSource.ts"],"names":[],"mappings":"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","sourcesContent":["import type { V3AssetResponse } from '@metamask/core-backend';\nimport { ApiPlatformClient } from '@metamask/core-backend';\nimport type {\n BulkTokenScanResponse,\n PhishingControllerBulkScanTokensAction,\n} from '@metamask/phishing-controller';\nimport { TokenScanResultType } from '@metamask/phishing-controller';\nimport { KnownCaipNamespace, parseCaipAssetType } from '@metamask/utils';\nimport type { CaipAssetType } from '@metamask/utils';\n\nimport type { AssetsControllerMessenger } from '../AssetsController';\nimport { projectLogger, createModuleLogger } from '../logger';\nimport { forDataTypes } from '../types';\nimport type {\n Caip19AssetId,\n AssetMetadata,\n Middleware,\n FungibleAssetMetadata,\n} from '../types';\nimport { fetchWithTimeout } from '../utils';\nimport {\n isStakingContractAssetId,\n reduceInBatchesSerially,\n} from './evm-rpc-services';\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nconst CONTROLLER_NAME = 'TokenDataSource';\nconst DEFAULT_FETCH_TIMEOUT_MS = 15_000;\n\nconst log = createModuleLogger(projectLogger, CONTROLLER_NAME);\n\n/** Max asset IDs per tokens API request. */\nconst TOKENS_API_BATCH_SIZE = 50;\n\n/** Max tokens per PhishingController:bulkScanTokens request (see PhishingController). */\nconst BULK_SCAN_BATCH_SIZE = 100;\n\n/**\n * Minimum number of aggregator occurrences required for an EVM ERC-20 token to\n * pass the spam filter. Non-EVM tokens are filtered via Blockaid bulk scan instead.\n */\nconst MIN_TOKEN_OCCURRENCES = 3;\n\n/** CAIP-19 `assetNamespace` segments used across filtering logic. */\nenum CaipAssetNamespace {\n Slip44 = 'slip44',\n Erc20 = 'erc20',\n Token = 'token',\n}\n\nconst MUSD_ADDRESS_LOWERCASE = '0xaca92e438df0b2401ff60da7e4337b687a2435da';\n\n// ============================================================================\n// OPTIONS\n// ============================================================================\n\nexport type TokenDataSourceOptions = {\n /** ApiPlatformClient for API calls with caching */\n queryApiClient: ApiPlatformClient;\n /** Returns CAIP-19 native asset IDs from NetworkEnablementController state */\n getNativeAssetIds: () => string[];\n /**\n * Timeout in ms for a single Tokens API call (default: 15000). When it\n * fires, the batch rejects so metadata enrichment proceeds without it.\n */\n fetchTimeoutMs?: number;\n};\n\n/**\n * Messenger actions `TokenDataSource` may invoke (via {@link AssetsControllerMessenger}).\n * Not re-exported from the package public `index` (repo ESLint); import from this module when\n * typing a messenger in the same package or tests.\n */\nexport type TokenDataSourceAllowedActions =\n PhishingControllerBulkScanTokensAction;\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Transform V3 API response to FungibleAssetMetadata for state storage.\n *\n * Mapping:\n * - assetId → used to derive `type` (native/erc20/spl)\n * - iconUrl → image\n * - All other fields map directly\n *\n * @param assetId - CAIP-19 asset ID used to derive token type.\n * @param assetData - V3 API response data.\n * @param nativeAssetIds - Set of known native asset IDs (lowercased) for membership checks.\n * @returns FungibleAssetMetadata for state storage.\n */\nfunction transformV3AssetResponseToMetadata(\n assetId: Caip19AssetId,\n assetData: V3AssetResponse,\n nativeAssetIds: ReadonlySet<string>,\n): AssetMetadata {\n const parsed = parseCaipAssetType(assetId);\n let tokenType: 'native' | 'erc20' | 'spl' = 'erc20';\n\n if (nativeAssetIds.has(assetId.toLowerCase())) {\n tokenType = 'native';\n } else if (parsed.assetNamespace === 'spl') {\n tokenType = 'spl';\n }\n\n const metadata: FungibleAssetMetadata = {\n // Type derived from assetId\n type: tokenType,\n // BaseAssetMetadata fields\n name: assetData.name,\n symbol: assetData.symbol,\n decimals: assetData.decimals,\n image: assetData.iconUrl,\n // Direct mapping fields\n coingeckoId: assetData.coingeckoId,\n occurrences: assetData.occurrences,\n aggregators: assetData.aggregators,\n labels: assetData.labels,\n erc20Permit: assetData.erc20Permit,\n fees: assetData.fees,\n honeypotStatus: assetData.honeypotStatus,\n storage: assetData.storage,\n isContractVerified: assetData.isContractVerified,\n description: assetData.description,\n };\n\n return metadata;\n}\n\n// ============================================================================\n// TOKEN DATA SOURCE\n// ============================================================================\n\n/**\n * TokenDataSource enriches responses with token metadata from the Tokens API.\n *\n * This middleware-based data source:\n * - Checks detected assets for missing metadata/images\n * - Fetches metadata from Tokens API v3 for assets needing enrichment\n * - Merges fetched metadata into the response\n *\n * Pass the same {@link AssetsControllerMessenger} as other data sources for Blockaid\n * token scans.\n */\nexport class TokenDataSource {\n readonly name = CONTROLLER_NAME;\n\n getName(): string {\n return this.name;\n }\n\n /** ApiPlatformClient for cached API calls */\n readonly #apiClient: ApiPlatformClient;\n\n /** Returns CAIP-19 native asset IDs from NetworkEnablementController state */\n readonly #getNativeAssetIds: () => string[];\n\n /** Shared controller messenger — used for `PhishingController:bulkScanTokens`. */\n readonly #messenger: AssetsControllerMessenger;\n\n readonly #fetchTimeoutMs: number;\n\n constructor(\n messenger: AssetsControllerMessenger,\n options: TokenDataSourceOptions,\n ) {\n this.#messenger = messenger;\n this.#apiClient = options.queryApiClient;\n this.#getNativeAssetIds = options.getNativeAssetIds;\n this.#fetchTimeoutMs = options.fetchTimeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS;\n }\n\n /**\n * Gets the supported networks from the API.\n * Caching is handled by ApiPlatformClient.\n *\n * @returns Set of supported chain IDs in CAIP format\n */\n async #getSupportedNetworks(): Promise<Set<string>> {\n try {\n // Use v2/supportedNetworks which returns CAIP chain IDs\n // ApiPlatformClient handles caching\n const response = await fetchWithTimeout(\n () => this.#apiClient.tokens.fetchTokenV2SupportedNetworks(),\n this.#fetchTimeoutMs,\n );\n\n // Combine full and partial support networks\n const allNetworks = [...response.fullSupport, ...response.partialSupport];\n\n return new Set(allNetworks);\n } catch (error) {\n log('Failed to fetch supported networks', { error });\n return new Set();\n }\n }\n\n /**\n * Filters asset IDs to only include those from supported networks.\n *\n * @param assetIds - Array of CAIP-19 asset IDs\n * @param supportedNetworks - Set of supported chain IDs\n * @returns Array of asset IDs from supported networks\n */\n #filterAssetsByNetwork(\n assetIds: string[],\n supportedNetworks: Set<string>,\n ): string[] {\n return assetIds.filter((assetId) => {\n try {\n const parsed = parseCaipAssetType(assetId as CaipAssetType);\n // chainId is in format \"eip155:1\" or \"tron:728126428\"\n // parsed.chain has namespace and reference properties\n const chainId = `${parsed.chain.namespace}:${parsed.chain.reference}`;\n return supportedNetworks.has(chainId);\n } catch {\n // If we can't parse the asset ID, filter it out\n return false;\n }\n });\n }\n\n /**\n * Filters non-EVM fungible `token` assets flagged as malicious by Blockaid\n * via `PhishingController:bulkScanTokens`. Only the `token` namespace (e.g.\n * Solana mints) is scanned; native (`slip44`) and EVM assets are not handled\n * here (EVM uses occurrence-count filtering instead). Fails open on error.\n *\n * @param assets - CAIP-19 asset IDs to filter (non-EVM only).\n * @returns Asset IDs with malicious tokens removed.\n */\n async #filterBlockaidSpamTokens(assets: string[]): Promise<string[]> {\n if (assets.length === 0) {\n return assets;\n }\n\n const tokensByChain: Record<string, { asset: string; address: string }[]> =\n {};\n\n for (const asset of assets) {\n try {\n const { assetNamespace, assetReference, chain } = parseCaipAssetType(\n asset as CaipAssetType,\n );\n\n if (assetNamespace === CaipAssetNamespace.Token) {\n const chainName = chain.namespace;\n if (!tokensByChain[chainName]) {\n tokensByChain[chainName] = [];\n }\n tokensByChain[chainName].push({ asset, address: assetReference });\n }\n } catch {\n // Malformed or unsupported for bulk scan — keep asset (fail open)\n }\n }\n\n if (Object.keys(tokensByChain).length === 0) {\n return assets;\n }\n\n const rejectedAssets = new Set<string>();\n\n try {\n for (const [chainId, tokenEntries] of Object.entries(tokensByChain)) {\n const addresses = tokenEntries.map((entry) => entry.address);\n const batches: string[][] = [];\n for (let i = 0; i < addresses.length; i += BULK_SCAN_BATCH_SIZE) {\n batches.push(addresses.slice(i, i + BULK_SCAN_BATCH_SIZE));\n }\n\n const batchResults = await Promise.allSettled(\n batches.map((batch) =>\n this.#messenger.call('PhishingController:bulkScanTokens', {\n chainId,\n tokens: batch,\n }),\n ),\n );\n\n const scanResponse: BulkTokenScanResponse = {};\n for (const result of batchResults) {\n if (result.status === 'fulfilled') {\n Object.assign(scanResponse, result.value);\n }\n }\n\n for (const entry of tokenEntries) {\n const result = scanResponse[entry.address];\n if (result?.result_type === TokenScanResultType.Malicious) {\n rejectedAssets.add(entry.asset);\n }\n }\n }\n } catch (error) {\n log('Blockaid bulk token scan failed; keeping all tokens', { error });\n return assets;\n }\n\n return assets.filter((asset) => !rejectedAssets.has(asset));\n }\n\n /**\n * Get the middleware for enriching responses with token metadata.\n *\n * This middleware:\n * 1. Extracts the response from context\n * 2. Fetches metadata for detected assets (assets without metadata)\n * 3. Enriches the response with fetched metadata\n * 4. Calls next() at the end to continue the middleware chain\n *\n * @returns The middleware function for the assets pipeline.\n */\n get assetsMiddleware(): Middleware {\n return forDataTypes(['metadata'], async (ctx, next) => {\n // Extract response from context\n const { response } = ctx;\n\n const { assetsInfo: stateMetadata, customAssets } = ctx.getAssetsState();\n const assetIdsNeedingMetadata = new Set<string>();\n\n // Custom assets are user-imported — exempt from spam filtering.\n // State stores asset IDs in their normalized (checksummed) form, but the\n // V3 Tokens API can return them lower-cased. Lowercase both sides so the\n // bypass is robust to address-case differences across data sources.\n const customAssetIds = new Set<string>(\n Object.values(customAssets ?? {})\n .flat()\n .map((id) => id.toLowerCase()),\n );\n\n // Always include native asset IDs from NetworkEnablementController\n const nativeAssetIdsList = this.#getNativeAssetIds();\n const nativeAssetIds = new Set(\n nativeAssetIdsList.map((id) => id.toLowerCase()),\n );\n for (const nativeAssetId of nativeAssetIdsList) {\n assetIdsNeedingMetadata.add(nativeAssetId);\n }\n\n // Also fetch metadata for detected assets that are missing it\n if (response.detectedAssets) {\n for (const detectedIds of Object.values(response.detectedAssets)) {\n for (const assetId of detectedIds) {\n // Skip if response already has metadata with image\n const responseMetadata = response.assetsInfo?.[assetId];\n if (responseMetadata?.image) {\n continue;\n }\n\n // Skip if state already has metadata with image\n const existingMetadata = stateMetadata[assetId];\n if (existingMetadata?.image) {\n continue;\n }\n\n // Skip staking contracts; we use built-in metadata and do not fetch from the tokens API\n if (isStakingContractAssetId(assetId)) {\n continue;\n }\n\n assetIdsNeedingMetadata.add(assetId);\n }\n }\n }\n\n if (assetIdsNeedingMetadata.size === 0) {\n return next(ctx);\n }\n\n // Filter asset IDs to only include supported networks\n const supportedNetworks = await this.#getSupportedNetworks();\n const supportedAssetIds = this.#filterAssetsByNetwork(\n [...assetIdsNeedingMetadata],\n supportedNetworks,\n );\n\n if (supportedAssetIds.length === 0) {\n return next(ctx);\n }\n\n try {\n const fetchOptions = {\n includeIconUrl: true,\n includeMarketData: true,\n includeMetadata: true,\n includeLabels: true,\n includeRwaData: true,\n includeAggregators: true,\n includeOccurrences: true,\n };\n\n const metadataResponse = await reduceInBatchesSerially<\n string,\n V3AssetResponse[]\n >({\n values: supportedAssetIds,\n batchSize: TOKENS_API_BATCH_SIZE,\n eachBatch: async (workingResult, batch) => {\n const batchResponse = await fetchWithTimeout(\n () => this.#apiClient.tokens.fetchV3Assets(batch, fetchOptions),\n this.#fetchTimeoutMs,\n );\n return [...(workingResult as V3AssetResponse[]), ...batchResponse];\n },\n initialResult: [],\n });\n\n // Split assets by chain type: EVM uses occurrence-count filtering;\n // non-EVM non-native uses Blockaid; native assets are always allowed.\n const occurrencesByAssetId = new Map(\n metadataResponse.map((a) => [a.assetId, a.occurrences]),\n );\n\n const evmErc20Ids: string[] = [];\n const nonEvmTokenIds: string[] = [];\n\n for (const assetData of metadataResponse) {\n const assetId = assetData.assetId as Caip19AssetId;\n const { assetNamespace, chain } = parseCaipAssetType(assetId);\n if (nativeAssetIds.has(assetId.toLowerCase())) {\n // Native assets are always kept — no filtering.\n } else if (\n assetNamespace === CaipAssetNamespace.Erc20 &&\n chain.namespace === KnownCaipNamespace.Eip155\n ) {\n evmErc20Ids.push(assetId);\n } else if (assetNamespace === CaipAssetNamespace.Token) {\n nonEvmTokenIds.push(assetId);\n }\n }\n\n // EVM: require minimum occurrence count to suppress low-signal tokens.\n // Tokens with no occurrence data (undefined) are treated the same as\n // zero occurrences and filtered out.\n // Custom assets (user-imported) bypass the occurrence filter — users\n // can import whatever they want and we must keep their metadata even\n // if the API has fewer than `MIN_TOKEN_OCCURRENCES` aggregator hits.\n const allowedEvmIds = new Set(\n evmErc20Ids.filter(\n (id) =>\n customAssetIds.has(id.toLowerCase()) ||\n (occurrencesByAssetId.get(id) ?? 0) >= MIN_TOKEN_OCCURRENCES ||\n id.includes(`/erc20:${MUSD_ADDRESS_LOWERCASE}`),\n ),\n );\n\n // Non-EVM: Blockaid bulk scan.\n // Custom assets (user-imported) bypass Blockaid filtering.\n const nonEvmToScan = nonEvmTokenIds.filter(\n (id) => !customAssetIds.has(id.toLowerCase()),\n );\n const allowedNonEvmIds = new Set([\n ...nonEvmTokenIds.filter((id) =>\n customAssetIds.has(id.toLowerCase()),\n ),\n ...(await this.#filterBlockaidSpamTokens(nonEvmToScan)),\n ]);\n\n // Start with every asset the API returned; only remove those that\n // fail their respective filter (EVM occurrences / non-EVM Blockaid).\n // Native (slip44) and unrecognised namespaces are kept (fail open).\n const allowedAssetIds = new Set(metadataResponse.map((a) => a.assetId));\n\n for (const id of evmErc20Ids) {\n if (!allowedEvmIds.has(id)) {\n allowedAssetIds.delete(id);\n }\n }\n for (const id of nonEvmTokenIds) {\n if (!allowedNonEvmIds.has(id)) {\n allowedAssetIds.delete(id);\n }\n }\n\n response.assetsInfo ??= {};\n\n const filteredOutAssets = new Set<string>();\n\n for (const assetData of metadataResponse) {\n if (!allowedAssetIds.has(assetData.assetId)) {\n filteredOutAssets.add(assetData.assetId);\n continue;\n }\n\n const caipAssetId = assetData.assetId as Caip19AssetId;\n response.assetsInfo[caipAssetId] = transformV3AssetResponseToMetadata(\n caipAssetId,\n assetData,\n nativeAssetIds,\n );\n }\n\n if (filteredOutAssets.size > 0) {\n if (response.assetsBalance) {\n for (const accountBalances of Object.values(\n response.assetsBalance,\n )) {\n for (const assetId of filteredOutAssets) {\n delete (accountBalances as Record<string, unknown>)[assetId];\n }\n }\n }\n\n if (response.detectedAssets) {\n for (const [accountId, assetIds] of Object.entries(\n response.detectedAssets,\n )) {\n response.detectedAssets[accountId] = assetIds.filter(\n (id) => !filteredOutAssets.has(id),\n );\n }\n }\n }\n } catch (error) {\n log('Failed to fetch metadata', { error });\n }\n\n // Call next() at the end to continue the middleware chain\n return next(ctx);\n });\n }\n}\n"]}
1
+ {"version":3,"file":"TokenDataSource.cjs","sourceRoot":"","sources":["../../src/data-sources/TokenDataSource.ts"],"names":[],"mappings":"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","sourcesContent":["import type { V3AssetResponse } from '@metamask/core-backend';\nimport { ApiPlatformClient } from '@metamask/core-backend';\nimport type {\n BulkTokenScanResponse,\n PhishingControllerBulkScanTokensAction,\n} from '@metamask/phishing-controller';\nimport { TokenScanResultType } from '@metamask/phishing-controller';\nimport { KnownCaipNamespace, parseCaipAssetType } from '@metamask/utils';\nimport type { CaipAssetType } from '@metamask/utils';\n\nimport type { AssetsControllerMessenger } from '../AssetsController';\nimport { projectLogger, createModuleLogger } from '../logger';\nimport { forDataTypes } from '../types';\nimport type {\n Caip19AssetId,\n AssetMetadata,\n Middleware,\n FungibleAssetMetadata,\n} from '../types';\nimport { fetchWithTimeout } from '../utils';\nimport {\n isStakingContractAssetId,\n reduceInBatchesSerially,\n} from './evm-rpc-services';\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nconst CONTROLLER_NAME = 'TokenDataSource';\nconst DEFAULT_FETCH_TIMEOUT_MS = 15_000;\n\nconst log = createModuleLogger(projectLogger, CONTROLLER_NAME);\n\n/** Max asset IDs per tokens API request. */\nconst TOKENS_API_BATCH_SIZE = 50;\n\n/** Max tokens per PhishingController:bulkScanTokens request (see PhishingController). */\nconst BULK_SCAN_BATCH_SIZE = 100;\n\n/**\n * Minimum number of aggregator occurrences required for an EVM ERC-20 token to\n * pass the spam filter. Non-EVM tokens are filtered via Blockaid bulk scan instead.\n */\nconst MIN_TOKEN_OCCURRENCES = 3;\n\n/** CAIP-19 `assetNamespace` segments used across filtering logic. */\nexport enum CaipAssetNamespace {\n Slip44 = 'slip44',\n Erc20 = 'erc20',\n Token = 'token',\n}\n\nconst MUSD_ADDRESS_LOWERCASE = '0xaca92e438df0b2401ff60da7e4337b687a2435da';\n\n// ============================================================================\n// OPTIONS\n// ============================================================================\n\nexport type TokenDataSourceOptions = {\n /** ApiPlatformClient for API calls with caching */\n queryApiClient: ApiPlatformClient;\n /** Returns CAIP-19 native asset IDs from NetworkEnablementController state */\n getNativeAssetIds: () => string[];\n /**\n * Timeout in ms for a single Tokens API call (default: 15000). When it\n * fires, the batch rejects so metadata enrichment proceeds without it.\n */\n fetchTimeoutMs?: number;\n};\n\n/**\n * Messenger actions `TokenDataSource` may invoke (via {@link AssetsControllerMessenger}).\n * Not re-exported from the package public `index` (repo ESLint); import from this module when\n * typing a messenger in the same package or tests.\n */\nexport type TokenDataSourceAllowedActions =\n PhishingControllerBulkScanTokensAction;\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Transform V3 API response to FungibleAssetMetadata for state storage.\n *\n * Mapping:\n * - assetId → used to derive `type` (native/erc20/spl)\n * - iconUrl → image\n * - All other fields map directly\n *\n * @param assetId - CAIP-19 asset ID used to derive token type.\n * @param assetData - V3 API response data.\n * @param nativeAssetIds - Set of known native asset IDs (lowercased) for membership checks.\n * @returns FungibleAssetMetadata for state storage.\n */\nfunction transformV3AssetResponseToMetadata(\n assetId: Caip19AssetId,\n assetData: V3AssetResponse,\n nativeAssetIds: ReadonlySet<string>,\n): AssetMetadata {\n const parsed = parseCaipAssetType(assetId);\n let tokenType: 'native' | 'erc20' | 'spl' = 'erc20';\n\n if (\n nativeAssetIds.has(assetId.toLowerCase()) ||\n parsed.assetNamespace === CaipAssetNamespace.Slip44\n ) {\n tokenType = 'native';\n } else if (\n parsed.chain.namespace === KnownCaipNamespace.Solana &&\n parsed.assetNamespace === CaipAssetNamespace.Token\n ) {\n tokenType = 'spl';\n }\n // TODO: Add support for Tron trc20 standard\n\n const metadata: FungibleAssetMetadata = {\n // Type derived from assetId\n type: tokenType,\n // BaseAssetMetadata fields\n name: assetData.name,\n symbol: assetData.symbol,\n decimals: assetData.decimals,\n image: assetData.iconUrl,\n // Direct mapping fields\n coingeckoId: assetData.coingeckoId,\n occurrences: assetData.occurrences,\n aggregators: assetData.aggregators,\n labels: assetData.labels,\n erc20Permit: assetData.erc20Permit,\n fees: assetData.fees,\n honeypotStatus: assetData.honeypotStatus,\n storage: assetData.storage,\n isContractVerified: assetData.isContractVerified,\n description: assetData.description,\n };\n\n return metadata;\n}\n\n// ============================================================================\n// TOKEN DATA SOURCE\n// ============================================================================\n\n/**\n * TokenDataSource enriches responses with token metadata from the Tokens API.\n *\n * This middleware-based data source:\n * - Checks detected assets for missing metadata/images\n * - Fetches metadata from Tokens API v3 for assets needing enrichment\n * - Merges fetched metadata into the response\n *\n * Pass the same {@link AssetsControllerMessenger} as other data sources for Blockaid\n * token scans.\n */\nexport class TokenDataSource {\n readonly name = CONTROLLER_NAME;\n\n getName(): string {\n return this.name;\n }\n\n /** ApiPlatformClient for cached API calls */\n readonly #apiClient: ApiPlatformClient;\n\n /** Returns CAIP-19 native asset IDs from NetworkEnablementController state */\n readonly #getNativeAssetIds: () => string[];\n\n /** Shared controller messenger — used for `PhishingController:bulkScanTokens`. */\n readonly #messenger: AssetsControllerMessenger;\n\n readonly #fetchTimeoutMs: number;\n\n constructor(\n messenger: AssetsControllerMessenger,\n options: TokenDataSourceOptions,\n ) {\n this.#messenger = messenger;\n this.#apiClient = options.queryApiClient;\n this.#getNativeAssetIds = options.getNativeAssetIds;\n this.#fetchTimeoutMs = options.fetchTimeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS;\n }\n\n /**\n * Gets the supported networks from the API.\n * Caching is handled by ApiPlatformClient.\n *\n * @returns Set of supported chain IDs in CAIP format\n */\n async #getSupportedNetworks(): Promise<Set<string>> {\n try {\n // Use v2/supportedNetworks which returns CAIP chain IDs\n // ApiPlatformClient handles caching\n const response = await fetchWithTimeout(\n () => this.#apiClient.tokens.fetchTokenV2SupportedNetworks(),\n this.#fetchTimeoutMs,\n );\n\n // Combine full and partial support networks\n const allNetworks = [...response.fullSupport, ...response.partialSupport];\n\n return new Set(allNetworks);\n } catch (error) {\n log('Failed to fetch supported networks', { error });\n return new Set();\n }\n }\n\n /**\n * Filters asset IDs to only include those from supported networks.\n *\n * @param assetIds - Array of CAIP-19 asset IDs\n * @param supportedNetworks - Set of supported chain IDs\n * @returns Array of asset IDs from supported networks\n */\n #filterAssetsByNetwork(\n assetIds: string[],\n supportedNetworks: Set<string>,\n ): string[] {\n return assetIds.filter((assetId) => {\n try {\n const parsed = parseCaipAssetType(assetId as CaipAssetType);\n // chainId is in format \"eip155:1\" or \"tron:728126428\"\n // parsed.chain has namespace and reference properties\n const chainId = `${parsed.chain.namespace}:${parsed.chain.reference}`;\n return supportedNetworks.has(chainId);\n } catch {\n // If we can't parse the asset ID, filter it out\n return false;\n }\n });\n }\n\n /**\n * Filters non-EVM fungible `token` assets flagged as malicious by Blockaid\n * via `PhishingController:bulkScanTokens`. Only the `token` namespace (e.g.\n * Solana mints) is scanned; native (`slip44`) and EVM assets are not handled\n * here (EVM uses occurrence-count filtering instead). Fails open on error.\n *\n * @param assets - CAIP-19 asset IDs to filter (non-EVM only).\n * @returns Asset IDs with malicious tokens removed.\n */\n async #filterBlockaidSpamTokens(assets: string[]): Promise<string[]> {\n if (assets.length === 0) {\n return assets;\n }\n\n const tokensByChain: Record<string, { asset: string; address: string }[]> =\n {};\n\n for (const asset of assets) {\n try {\n const { assetNamespace, assetReference, chain } = parseCaipAssetType(\n asset as CaipAssetType,\n );\n\n if (assetNamespace === CaipAssetNamespace.Token) {\n const chainName = chain.namespace;\n if (!tokensByChain[chainName]) {\n tokensByChain[chainName] = [];\n }\n tokensByChain[chainName].push({ asset, address: assetReference });\n }\n } catch {\n // Malformed or unsupported for bulk scan — keep asset (fail open)\n }\n }\n\n if (Object.keys(tokensByChain).length === 0) {\n return assets;\n }\n\n const rejectedAssets = new Set<string>();\n\n try {\n for (const [chainId, tokenEntries] of Object.entries(tokensByChain)) {\n const addresses = tokenEntries.map((entry) => entry.address);\n const batches: string[][] = [];\n for (let i = 0; i < addresses.length; i += BULK_SCAN_BATCH_SIZE) {\n batches.push(addresses.slice(i, i + BULK_SCAN_BATCH_SIZE));\n }\n\n const batchResults = await Promise.allSettled(\n batches.map((batch) =>\n this.#messenger.call('PhishingController:bulkScanTokens', {\n chainId,\n tokens: batch,\n }),\n ),\n );\n\n const scanResponse: BulkTokenScanResponse = {};\n for (const result of batchResults) {\n if (result.status === 'fulfilled') {\n Object.assign(scanResponse, result.value);\n }\n }\n\n for (const entry of tokenEntries) {\n const result = scanResponse[entry.address];\n if (result?.result_type === TokenScanResultType.Malicious) {\n rejectedAssets.add(entry.asset);\n }\n }\n }\n } catch (error) {\n log('Blockaid bulk token scan failed; keeping all tokens', { error });\n return assets;\n }\n\n return assets.filter((asset) => !rejectedAssets.has(asset));\n }\n\n /**\n * Get the middleware for enriching responses with token metadata.\n *\n * This middleware:\n * 1. Extracts the response from context\n * 2. Fetches metadata for detected assets (assets without metadata)\n * 3. Enriches the response with fetched metadata\n * 4. Calls next() at the end to continue the middleware chain\n *\n * @returns The middleware function for the assets pipeline.\n */\n get assetsMiddleware(): Middleware {\n return forDataTypes(['metadata'], async (ctx, next) => {\n // Extract response from context\n const { response } = ctx;\n\n const { assetsInfo: stateMetadata, customAssets } = ctx.getAssetsState();\n const assetIdsNeedingMetadata = new Set<string>();\n\n // Custom assets are user-imported — exempt from spam filtering.\n // State stores asset IDs in their normalized (checksummed) form, but the\n // V3 Tokens API can return them lower-cased. Lowercase both sides so the\n // bypass is robust to address-case differences across data sources.\n const customAssetIds = new Set<string>(\n Object.values(customAssets ?? {})\n .flat()\n .map((id) => id.toLowerCase()),\n );\n\n // Always include native asset IDs from NetworkEnablementController\n const nativeAssetIdsList = this.#getNativeAssetIds();\n const nativeAssetIds = new Set(\n nativeAssetIdsList.map((id) => id.toLowerCase()),\n );\n for (const nativeAssetId of nativeAssetIdsList) {\n assetIdsNeedingMetadata.add(nativeAssetId);\n }\n\n // Also fetch metadata for detected assets that are missing it\n if (response.detectedAssets) {\n for (const detectedIds of Object.values(response.detectedAssets)) {\n for (const assetId of detectedIds) {\n // Skip if response already has metadata with image\n const responseMetadata = response.assetsInfo?.[assetId];\n if (responseMetadata?.image) {\n continue;\n }\n\n // Skip if state already has metadata with image\n const existingMetadata = stateMetadata[assetId];\n if (existingMetadata?.image) {\n continue;\n }\n\n // Skip staking contracts; we use built-in metadata and do not fetch from the tokens API\n if (isStakingContractAssetId(assetId)) {\n continue;\n }\n\n assetIdsNeedingMetadata.add(assetId);\n }\n }\n }\n\n if (assetIdsNeedingMetadata.size === 0) {\n return next(ctx);\n }\n\n // Filter asset IDs to only include supported networks\n const supportedNetworks = await this.#getSupportedNetworks();\n const supportedAssetIds = this.#filterAssetsByNetwork(\n [...assetIdsNeedingMetadata],\n supportedNetworks,\n );\n\n if (supportedAssetIds.length === 0) {\n return next(ctx);\n }\n\n try {\n const fetchOptions = {\n includeIconUrl: true,\n includeMarketData: true,\n includeMetadata: true,\n includeLabels: true,\n includeRwaData: true,\n includeAggregators: true,\n includeOccurrences: true,\n };\n\n const metadataResponse = await reduceInBatchesSerially<\n string,\n V3AssetResponse[]\n >({\n values: supportedAssetIds,\n batchSize: TOKENS_API_BATCH_SIZE,\n eachBatch: async (workingResult, batch) => {\n const batchResponse = await fetchWithTimeout(\n () => this.#apiClient.tokens.fetchV3Assets(batch, fetchOptions),\n this.#fetchTimeoutMs,\n );\n return [...(workingResult as V3AssetResponse[]), ...batchResponse];\n },\n initialResult: [],\n });\n\n // Split assets by chain type: EVM uses occurrence-count filtering;\n // non-EVM non-native uses Blockaid; native assets are always allowed.\n const occurrencesByAssetId = new Map(\n metadataResponse.map((a) => [a.assetId, a.occurrences]),\n );\n\n const evmErc20Ids: string[] = [];\n const nonEvmTokenIds: string[] = [];\n\n for (const assetData of metadataResponse) {\n const assetId = assetData.assetId as Caip19AssetId;\n const { assetNamespace, chain } = parseCaipAssetType(assetId);\n if (nativeAssetIds.has(assetId.toLowerCase())) {\n // Native assets are always kept — no filtering.\n } else if (\n assetNamespace === CaipAssetNamespace.Erc20 &&\n chain.namespace === KnownCaipNamespace.Eip155\n ) {\n evmErc20Ids.push(assetId);\n } else if (assetNamespace === CaipAssetNamespace.Token) {\n nonEvmTokenIds.push(assetId);\n }\n }\n\n // EVM: require minimum occurrence count to suppress low-signal tokens.\n // Tokens with no occurrence data (undefined) are treated the same as\n // zero occurrences and filtered out.\n // Custom assets (user-imported) bypass the occurrence filter — users\n // can import whatever they want and we must keep their metadata even\n // if the API has fewer than `MIN_TOKEN_OCCURRENCES` aggregator hits.\n const allowedEvmIds = new Set(\n evmErc20Ids.filter(\n (id) =>\n customAssetIds.has(id.toLowerCase()) ||\n (occurrencesByAssetId.get(id) ?? 0) >= MIN_TOKEN_OCCURRENCES ||\n id.includes(`/erc20:${MUSD_ADDRESS_LOWERCASE}`),\n ),\n );\n\n // Non-EVM: Blockaid bulk scan.\n // Custom assets (user-imported) bypass Blockaid filtering.\n const nonEvmToScan = nonEvmTokenIds.filter(\n (id) => !customAssetIds.has(id.toLowerCase()),\n );\n const allowedNonEvmIds = new Set([\n ...nonEvmTokenIds.filter((id) =>\n customAssetIds.has(id.toLowerCase()),\n ),\n ...(await this.#filterBlockaidSpamTokens(nonEvmToScan)),\n ]);\n\n // Start with every asset the API returned; only remove those that\n // fail their respective filter (EVM occurrences / non-EVM Blockaid).\n // Native (slip44) and unrecognised namespaces are kept (fail open).\n const allowedAssetIds = new Set(metadataResponse.map((a) => a.assetId));\n\n for (const id of evmErc20Ids) {\n if (!allowedEvmIds.has(id)) {\n allowedAssetIds.delete(id);\n }\n }\n for (const id of nonEvmTokenIds) {\n if (!allowedNonEvmIds.has(id)) {\n allowedAssetIds.delete(id);\n }\n }\n\n response.assetsInfo ??= {};\n\n const filteredOutAssets = new Set<string>();\n\n for (const assetData of metadataResponse) {\n if (!allowedAssetIds.has(assetData.assetId)) {\n filteredOutAssets.add(assetData.assetId);\n continue;\n }\n\n const caipAssetId = assetData.assetId as Caip19AssetId;\n response.assetsInfo[caipAssetId] = transformV3AssetResponseToMetadata(\n caipAssetId,\n assetData,\n nativeAssetIds,\n );\n }\n\n if (filteredOutAssets.size > 0) {\n if (response.assetsBalance) {\n for (const accountBalances of Object.values(\n response.assetsBalance,\n )) {\n for (const assetId of filteredOutAssets) {\n delete (accountBalances as Record<string, unknown>)[assetId];\n }\n }\n }\n\n if (response.detectedAssets) {\n for (const [accountId, assetIds] of Object.entries(\n response.detectedAssets,\n )) {\n response.detectedAssets[accountId] = assetIds.filter(\n (id) => !filteredOutAssets.has(id),\n );\n }\n }\n }\n } catch (error) {\n log('Failed to fetch metadata', { error });\n }\n\n // Call next() at the end to continue the middleware chain\n return next(ctx);\n });\n }\n}\n"]}
@@ -2,6 +2,12 @@ import { ApiPlatformClient } from "@metamask/core-backend";
2
2
  import type { PhishingControllerBulkScanTokensAction } from "@metamask/phishing-controller";
3
3
  import type { AssetsControllerMessenger } from "../AssetsController.cjs";
4
4
  import type { Middleware } from "../types.cjs";
5
+ /** CAIP-19 `assetNamespace` segments used across filtering logic. */
6
+ export declare enum CaipAssetNamespace {
7
+ Slip44 = "slip44",
8
+ Erc20 = "erc20",
9
+ Token = "token"
10
+ }
5
11
  export type TokenDataSourceOptions = {
6
12
  /** ApiPlatformClient for API calls with caching */
7
13
  queryApiClient: ApiPlatformClient;
@@ -1 +1 @@
1
- {"version":3,"file":"TokenDataSource.d.cts","sourceRoot":"","sources":["../../src/data-sources/TokenDataSource.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,+BAA+B;AAC3D,OAAO,KAAK,EAEV,sCAAsC,EACvC,sCAAsC;AAKvC,OAAO,KAAK,EAAE,yBAAyB,EAAE,gCAA4B;AAGrE,OAAO,KAAK,EAGV,UAAU,EAEX,qBAAiB;AAyClB,MAAM,MAAM,sBAAsB,GAAG;IACnC,mDAAmD;IACnD,cAAc,EAAE,iBAAiB,CAAC;IAClC,8EAA8E;IAC9E,iBAAiB,EAAE,MAAM,MAAM,EAAE,CAAC;IAClC;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,6BAA6B,GACvC,sCAAsC,CAAC;AA6DzC;;;;;;;;;;GAUG;AACH,qBAAa,eAAe;;IAC1B,QAAQ,CAAC,IAAI,qBAAmB;IAEhC,OAAO,IAAI,MAAM;gBAgBf,SAAS,EAAE,yBAAyB,EACpC,OAAO,EAAE,sBAAsB;IA0IjC;;;;;;;;;;OAUG;IACH,IAAI,gBAAgB,IAAI,UAAU,CAgNjC;CACF"}
1
+ {"version":3,"file":"TokenDataSource.d.cts","sourceRoot":"","sources":["../../src/data-sources/TokenDataSource.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,+BAA+B;AAC3D,OAAO,KAAK,EAEV,sCAAsC,EACvC,sCAAsC;AAKvC,OAAO,KAAK,EAAE,yBAAyB,EAAE,gCAA4B;AAGrE,OAAO,KAAK,EAGV,UAAU,EAEX,qBAAiB;AA4BlB,qEAAqE;AACrE,oBAAY,kBAAkB;IAC5B,MAAM,WAAW;IACjB,KAAK,UAAU;IACf,KAAK,UAAU;CAChB;AAQD,MAAM,MAAM,sBAAsB,GAAG;IACnC,mDAAmD;IACnD,cAAc,EAAE,iBAAiB,CAAC;IAClC,8EAA8E;IAC9E,iBAAiB,EAAE,MAAM,MAAM,EAAE,CAAC;IAClC;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,6BAA6B,GACvC,sCAAsC,CAAC;AAoEzC;;;;;;;;;;GAUG;AACH,qBAAa,eAAe;;IAC1B,QAAQ,CAAC,IAAI,qBAAmB;IAEhC,OAAO,IAAI,MAAM;gBAgBf,SAAS,EAAE,yBAAyB,EACpC,OAAO,EAAE,sBAAsB;IA0IjC;;;;;;;;;;OAUG;IACH,IAAI,gBAAgB,IAAI,UAAU,CAgNjC;CACF"}
@@ -2,6 +2,12 @@ import { ApiPlatformClient } from "@metamask/core-backend";
2
2
  import type { PhishingControllerBulkScanTokensAction } from "@metamask/phishing-controller";
3
3
  import type { AssetsControllerMessenger } from "../AssetsController.mjs";
4
4
  import type { Middleware } from "../types.mjs";
5
+ /** CAIP-19 `assetNamespace` segments used across filtering logic. */
6
+ export declare enum CaipAssetNamespace {
7
+ Slip44 = "slip44",
8
+ Erc20 = "erc20",
9
+ Token = "token"
10
+ }
5
11
  export type TokenDataSourceOptions = {
6
12
  /** ApiPlatformClient for API calls with caching */
7
13
  queryApiClient: ApiPlatformClient;
@@ -1 +1 @@
1
- {"version":3,"file":"TokenDataSource.d.mts","sourceRoot":"","sources":["../../src/data-sources/TokenDataSource.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,+BAA+B;AAC3D,OAAO,KAAK,EAEV,sCAAsC,EACvC,sCAAsC;AAKvC,OAAO,KAAK,EAAE,yBAAyB,EAAE,gCAA4B;AAGrE,OAAO,KAAK,EAGV,UAAU,EAEX,qBAAiB;AAyClB,MAAM,MAAM,sBAAsB,GAAG;IACnC,mDAAmD;IACnD,cAAc,EAAE,iBAAiB,CAAC;IAClC,8EAA8E;IAC9E,iBAAiB,EAAE,MAAM,MAAM,EAAE,CAAC;IAClC;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,6BAA6B,GACvC,sCAAsC,CAAC;AA6DzC;;;;;;;;;;GAUG;AACH,qBAAa,eAAe;;IAC1B,QAAQ,CAAC,IAAI,qBAAmB;IAEhC,OAAO,IAAI,MAAM;gBAgBf,SAAS,EAAE,yBAAyB,EACpC,OAAO,EAAE,sBAAsB;IA0IjC;;;;;;;;;;OAUG;IACH,IAAI,gBAAgB,IAAI,UAAU,CAgNjC;CACF"}
1
+ {"version":3,"file":"TokenDataSource.d.mts","sourceRoot":"","sources":["../../src/data-sources/TokenDataSource.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,+BAA+B;AAC3D,OAAO,KAAK,EAEV,sCAAsC,EACvC,sCAAsC;AAKvC,OAAO,KAAK,EAAE,yBAAyB,EAAE,gCAA4B;AAGrE,OAAO,KAAK,EAGV,UAAU,EAEX,qBAAiB;AA4BlB,qEAAqE;AACrE,oBAAY,kBAAkB;IAC5B,MAAM,WAAW;IACjB,KAAK,UAAU;IACf,KAAK,UAAU;CAChB;AAQD,MAAM,MAAM,sBAAsB,GAAG;IACnC,mDAAmD;IACnD,cAAc,EAAE,iBAAiB,CAAC;IAClC,8EAA8E;IAC9E,iBAAiB,EAAE,MAAM,MAAM,EAAE,CAAC;IAClC;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,6BAA6B,GACvC,sCAAsC,CAAC;AAoEzC;;;;;;;;;;GAUG;AACH,qBAAa,eAAe;;IAC1B,QAAQ,CAAC,IAAI,qBAAmB;IAEhC,OAAO,IAAI,MAAM;gBAgBf,SAAS,EAAE,yBAAyB,EACpC,OAAO,EAAE,sBAAsB;IA0IjC;;;;;;;;;;OAUG;IACH,IAAI,gBAAgB,IAAI,UAAU,CAgNjC;CACF"}
@@ -33,7 +33,7 @@ const BULK_SCAN_BATCH_SIZE = 100;
33
33
  */
34
34
  const MIN_TOKEN_OCCURRENCES = 3;
35
35
  /** CAIP-19 `assetNamespace` segments used across filtering logic. */
36
- var CaipAssetNamespace;
36
+ export var CaipAssetNamespace;
37
37
  (function (CaipAssetNamespace) {
38
38
  CaipAssetNamespace["Slip44"] = "slip44";
39
39
  CaipAssetNamespace["Erc20"] = "erc20";
@@ -59,12 +59,15 @@ const MUSD_ADDRESS_LOWERCASE = '0xaca92e438df0b2401ff60da7e4337b687a2435da';
59
59
  function transformV3AssetResponseToMetadata(assetId, assetData, nativeAssetIds) {
60
60
  const parsed = parseCaipAssetType(assetId);
61
61
  let tokenType = 'erc20';
62
- if (nativeAssetIds.has(assetId.toLowerCase())) {
62
+ if (nativeAssetIds.has(assetId.toLowerCase()) ||
63
+ parsed.assetNamespace === CaipAssetNamespace.Slip44) {
63
64
  tokenType = 'native';
64
65
  }
65
- else if (parsed.assetNamespace === 'spl') {
66
+ else if (parsed.chain.namespace === KnownCaipNamespace.Solana &&
67
+ parsed.assetNamespace === CaipAssetNamespace.Token) {
66
68
  tokenType = 'spl';
67
69
  }
70
+ // TODO: Add support for Tron trc20 standard
68
71
  const metadata = {
69
72
  // Type derived from assetId
70
73
  type: tokenType,