@portal-hq/web 3.17.0 → 3.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/lib/commonjs/index.js +62 -20
  2. package/lib/commonjs/index.test.js +51 -10
  3. package/lib/commonjs/integrations/ramps/index.js +2 -0
  4. package/lib/commonjs/integrations/ramps/meld/index.js +121 -0
  5. package/lib/commonjs/integrations/ramps/meld/index.test.js +162 -0
  6. package/lib/commonjs/integrations/ramps/noah/index.js +2 -2
  7. package/lib/commonjs/integrations/ramps/noah/index.test.js +11 -2
  8. package/lib/commonjs/mpc/index.js +199 -3
  9. package/lib/commonjs/mpc/index.test.js +634 -0
  10. package/lib/commonjs/provider/index.js +44 -2
  11. package/lib/commonjs/provider/index.test.js +186 -0
  12. package/lib/commonjs/rpc.test.js +162 -0
  13. package/lib/commonjs/shared/rpc/auth.js +29 -0
  14. package/lib/commonjs/shared/rpc/defaults.js +40 -0
  15. package/lib/commonjs/shared/types/index.js +1 -0
  16. package/lib/commonjs/shared/types/meld.js +2 -0
  17. package/lib/esm/index.js +59 -19
  18. package/lib/esm/index.test.js +51 -10
  19. package/lib/esm/integrations/ramps/index.js +2 -0
  20. package/lib/esm/integrations/ramps/meld/index.js +118 -0
  21. package/lib/esm/integrations/ramps/meld/index.test.js +157 -0
  22. package/lib/esm/integrations/ramps/noah/index.js +2 -2
  23. package/lib/esm/integrations/ramps/noah/index.test.js +11 -2
  24. package/lib/esm/mpc/index.js +199 -3
  25. package/lib/esm/mpc/index.test.js +635 -1
  26. package/lib/esm/provider/index.js +44 -2
  27. package/lib/esm/provider/index.test.js +186 -0
  28. package/lib/esm/rpc.test.js +157 -0
  29. package/lib/esm/shared/rpc/auth.js +25 -0
  30. package/lib/esm/shared/rpc/defaults.js +36 -0
  31. package/lib/esm/shared/types/index.js +1 -0
  32. package/lib/esm/shared/types/meld.js +1 -0
  33. package/noah-types.d.ts +17 -1
  34. package/package.json +1 -1
  35. package/src/__mocks/constants.ts +68 -0
  36. package/src/__mocks/portal/portal.ts +0 -1
  37. package/src/index.test.ts +90 -0
  38. package/src/index.ts +159 -7
  39. package/src/integrations/ramps/index.ts +3 -0
  40. package/src/integrations/ramps/meld/index.test.ts +189 -0
  41. package/src/integrations/ramps/meld/index.ts +149 -0
  42. package/src/integrations/ramps/noah/index.test.ts +11 -2
  43. package/src/integrations/ramps/noah/index.ts +5 -2
  44. package/src/mpc/index.test.ts +804 -7
  45. package/src/mpc/index.ts +247 -3
  46. package/src/provider/index.test.ts +233 -0
  47. package/src/provider/index.ts +64 -1
  48. package/src/rpc.test.ts +190 -0
  49. package/src/shared/rpc/auth.ts +27 -0
  50. package/src/shared/rpc/defaults.ts +41 -0
  51. package/src/shared/types/common.ts +24 -0
  52. package/src/shared/types/index.ts +1 -0
  53. package/src/shared/types/meld.ts +302 -0
  54. package/src/shared/types/noah.ts +191 -29
  55. package/types.d.ts +65 -3
@@ -12,7 +12,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
12
12
  };
13
13
  import { BackupMethods, MpcStatuses, PortalCurve } from '../index';
14
14
  import Mpc from '.';
15
- import { mockAddress, mockApikey, mockAssets, mockBackupConfig, mockBackupIds, mockBalances, mockBuiltTransaction, mockCipherText, mockClientResponse, mockEjectResult, mockEjectPrivateKeysResult, mockEvaluationResult, mockHost, mockNFTs, mockOrgBackupShares, mockQuoteArgs, mockRpcUrl, mockSharesOnDevice, mockSimulationResult, mockTransactionToEvaluate, mockTransactionToSimulate, mockYieldXyzGetYieldsRequest, mockYieldXyzGetYieldsResponse, mockYieldXyzEnterRequest, mockYieldXyzEnterResponse, mockYieldXyzExitRequest, mockYieldXyzExitResponse, mockYieldXyzGetBalancesRequest, mockYieldXyzGetBalancesResponse, mockYieldXyzGetHistoricalActionsRequest, mockYieldXyzGetHistoricalActionsResponse, mockYieldXyzManageYieldRequest, mockYieldXyzManageYieldResponse, mockYieldXyzTrackTransactionRequest, mockYieldXyzTrackTransactionResponse, mockYieldXyzGetTransactionResponse, mockLifiGetRoutesRequest, mockLifiGetRoutesResponse, mockLifiGetQuoteRequest, mockLifiGetQuoteResponse, mockLifiGetStatusRequest, mockLifiGetStatusResponse, mockLifiGetRouteStepRequest, mockLifiGetRouteStepResponse, mockZeroExQuoteV2Request, mockZeroExQuoteV2Response, mockZeroExSourcesV2Request, mockZeroExSourcesV2Response, mockZeroExPriceRequest, mockZeroExPriceResponse, mockZeroExOptions, mockScanAddressesRequest, mockScanAddressesResponse, mockScanEVMTxRequest, mockScanEVMTxResponse, mockScanEip712TxRequest, mockScanEip712TxResponse, mockScanSolanaTxRequest, mockScanSolanaTxResponse, mockScanNftRequest, mockScanNftResponse, mockScanTokenRequest, mockScanTokenResponse, mockScanUrlRequest, mockScanUrlResponse, mockBlockaidScanEvmTxRequest, mockBlockaidScanEvmTxResponse, mockBlockaidScanSolanaTxRequest, mockBlockaidScanSolanaTxResponse, mockBlockaidScanAddressRequest, mockBlockaidScanAddressResponse, mockBlockaidScanTokensRequest, mockBlockaidScanTokensResponse, mockBlockaidScanUrlRequest, mockBlockaidScanUrlResponse, mockBuildBatchedUserOpRequest, mockBuildBatchedUserOpResponse, mockBroadcastBatchedUserOpRequest, mockBroadcastBatchedUserOpResponse, } from '../__mocks/constants';
15
+ import { mockAddress, mockApikey, mockAssets, mockBackupConfig, mockBackupIds, mockBalances, mockBuiltTransaction, mockCipherText, mockClientResponse, mockEjectResult, mockEjectPrivateKeysResult, mockEvaluationResult, mockHost, mockNFTs, mockOrgBackupShares, mockQuoteArgs, mockRpcUrl, mockSharesOnDevice, mockSimulationResult, mockTransactionToEvaluate, mockTransactionToSimulate, mockYieldXyzGetYieldsRequest, mockYieldXyzGetYieldsResponse, mockYieldXyzEnterRequest, mockYieldXyzEnterResponse, mockYieldXyzExitRequest, mockYieldXyzExitResponse, mockYieldXyzGetBalancesRequest, mockYieldXyzGetBalancesResponse, mockYieldXyzGetHistoricalActionsRequest, mockYieldXyzGetHistoricalActionsResponse, mockYieldXyzManageYieldRequest, mockYieldXyzManageYieldResponse, mockYieldXyzTrackTransactionRequest, mockYieldXyzTrackTransactionResponse, mockYieldXyzGetTransactionResponse, mockLifiGetRoutesRequest, mockLifiGetRoutesResponse, mockLifiGetQuoteRequest, mockLifiGetQuoteResponse, mockLifiGetStatusRequest, mockLifiGetStatusResponse, mockLifiGetRouteStepRequest, mockLifiGetRouteStepResponse, mockZeroExQuoteV2Request, mockZeroExQuoteV2Response, mockZeroExSourcesV2Request, mockZeroExSourcesV2Response, mockZeroExPriceRequest, mockZeroExPriceResponse, mockZeroExOptions, mockScanAddressesRequest, mockScanAddressesResponse, mockScanEVMTxRequest, mockScanEVMTxResponse, mockScanEip712TxRequest, mockScanEip712TxResponse, mockScanSolanaTxRequest, mockScanSolanaTxResponse, mockScanNftRequest, mockScanNftResponse, mockScanTokenRequest, mockScanTokenResponse, mockScanUrlRequest, mockScanUrlResponse, mockBlockaidScanEvmTxRequest, mockBlockaidScanEvmTxResponse, mockBlockaidScanSolanaTxRequest, mockBlockaidScanSolanaTxResponse, mockBlockaidScanAddressRequest, mockBlockaidScanAddressResponse, mockBlockaidScanTokensRequest, mockBlockaidScanTokensResponse, mockBlockaidScanUrlRequest, mockBlockaidScanUrlResponse, mockMeldCreateCustomerRequest, mockMeldCreateCustomerResponse, mockMeldSearchCustomerResponse, mockMeldGetRetailQuoteRequest, mockMeldGetRetailQuoteResponse, mockMeldCreateRetailWidgetRequest, mockMeldCreateRetailWidgetResponse, mockMeldSearchRetailTransactionsResponse, mockMeldGetRetailTransactionResponse, mockMeldDiscoveryResponse, mockMeldDiscoveryParams, mockBuildBatchedUserOpRequest, mockBuildBatchedUserOpResponse, mockBroadcastBatchedUserOpRequest, mockBroadcastBatchedUserOpResponse, } from '../__mocks/constants';
16
16
  import portalMock from '../__mocks/portal/portal';
17
17
  import { PortalMpcError } from './errors';
18
18
  describe('Mpc', () => {
@@ -3759,6 +3759,513 @@ describe('Mpc', () => {
3759
3759
  });
3760
3760
  });
3761
3761
  });
3762
+ describe('meldCreateCustomer', () => {
3763
+ const args = mockMeldCreateCustomerRequest;
3764
+ const res = mockMeldCreateCustomerResponse;
3765
+ it('should successfully return the created customer', (done) => {
3766
+ var _a;
3767
+ jest
3768
+ .spyOn((_a = mpc.iframe) === null || _a === void 0 ? void 0 : _a.contentWindow, 'postMessage')
3769
+ .mockImplementation((message, origin) => {
3770
+ const { type, data } = message;
3771
+ expect(type).toEqual('portal:meld:createCustomer');
3772
+ expect(data).toMatchObject(args);
3773
+ expect(typeof message.traceId).toBe('string');
3774
+ expect(origin).toEqual(mockHostOrigin);
3775
+ window.dispatchEvent(new MessageEvent('message', {
3776
+ origin: mockHostOrigin,
3777
+ data: {
3778
+ type: 'portal:meld:createCustomerResult',
3779
+ data: res,
3780
+ },
3781
+ }));
3782
+ });
3783
+ mpc
3784
+ .meldCreateCustomer(args)
3785
+ .then((data) => {
3786
+ expect(data).toEqual(res);
3787
+ done();
3788
+ })
3789
+ .catch((_) => {
3790
+ expect(0).toEqual(1);
3791
+ done();
3792
+ });
3793
+ });
3794
+ it('should error out if the iframe sends an error message', (done) => {
3795
+ var _a;
3796
+ jest
3797
+ .spyOn((_a = mpc.iframe) === null || _a === void 0 ? void 0 : _a.contentWindow, 'postMessage')
3798
+ .mockImplementationOnce((message, origin) => {
3799
+ const { type } = message;
3800
+ expect(type).toEqual('portal:meld:createCustomer');
3801
+ expect(origin).toEqual(mockHostOrigin);
3802
+ window.dispatchEvent(new MessageEvent('message', {
3803
+ origin: mockHostOrigin,
3804
+ data: {
3805
+ type: 'portal:meld:createCustomerError',
3806
+ data: { code: 1, message: 'test' },
3807
+ },
3808
+ }));
3809
+ });
3810
+ mpc
3811
+ .meldCreateCustomer(args)
3812
+ .then(() => {
3813
+ expect(0).toEqual(1);
3814
+ done();
3815
+ })
3816
+ .catch((e) => {
3817
+ expect(e).toBeInstanceOf(PortalMpcError);
3818
+ expect(e.message).toEqual('test');
3819
+ expect(e.code).toEqual(1);
3820
+ done();
3821
+ });
3822
+ });
3823
+ });
3824
+ describe('meldSearchCustomer', () => {
3825
+ const res = mockMeldSearchCustomerResponse;
3826
+ it('should successfully return the customer data', (done) => {
3827
+ var _a;
3828
+ jest
3829
+ .spyOn((_a = mpc.iframe) === null || _a === void 0 ? void 0 : _a.contentWindow, 'postMessage')
3830
+ .mockImplementation((message, origin) => {
3831
+ const { type } = message;
3832
+ expect(type).toEqual('portal:meld:searchCustomer');
3833
+ expect(origin).toEqual(mockHostOrigin);
3834
+ window.dispatchEvent(new MessageEvent('message', {
3835
+ origin: mockHostOrigin,
3836
+ data: {
3837
+ type: 'portal:meld:searchCustomerResult',
3838
+ data: res,
3839
+ },
3840
+ }));
3841
+ });
3842
+ mpc
3843
+ .meldSearchCustomer()
3844
+ .then((data) => {
3845
+ expect(data).toEqual(res);
3846
+ done();
3847
+ })
3848
+ .catch((_) => {
3849
+ expect(0).toEqual(1);
3850
+ done();
3851
+ });
3852
+ });
3853
+ it('should error out if the iframe sends an error message', (done) => {
3854
+ var _a;
3855
+ jest
3856
+ .spyOn((_a = mpc.iframe) === null || _a === void 0 ? void 0 : _a.contentWindow, 'postMessage')
3857
+ .mockImplementationOnce((_message, _origin) => {
3858
+ window.dispatchEvent(new MessageEvent('message', {
3859
+ origin: mockHostOrigin,
3860
+ data: {
3861
+ type: 'portal:meld:searchCustomerError',
3862
+ data: { code: 2, message: 'not found' },
3863
+ },
3864
+ }));
3865
+ });
3866
+ mpc
3867
+ .meldSearchCustomer()
3868
+ .then(() => {
3869
+ expect(0).toEqual(1);
3870
+ done();
3871
+ })
3872
+ .catch((e) => {
3873
+ expect(e).toBeInstanceOf(PortalMpcError);
3874
+ expect(e.code).toEqual(2);
3875
+ done();
3876
+ });
3877
+ });
3878
+ });
3879
+ describe('meldGetRetailQuote', () => {
3880
+ const args = mockMeldGetRetailQuoteRequest;
3881
+ const res = mockMeldGetRetailQuoteResponse;
3882
+ it('should successfully return the retail quote', (done) => {
3883
+ var _a;
3884
+ jest
3885
+ .spyOn((_a = mpc.iframe) === null || _a === void 0 ? void 0 : _a.contentWindow, 'postMessage')
3886
+ .mockImplementation((message, origin) => {
3887
+ const { type, data } = message;
3888
+ expect(type).toEqual('portal:meld:getRetailQuote');
3889
+ expect(data).toMatchObject(args);
3890
+ expect(typeof message.traceId).toBe('string');
3891
+ expect(origin).toEqual(mockHostOrigin);
3892
+ window.dispatchEvent(new MessageEvent('message', {
3893
+ origin: mockHostOrigin,
3894
+ data: {
3895
+ type: 'portal:meld:getRetailQuoteResult',
3896
+ data: res,
3897
+ },
3898
+ }));
3899
+ });
3900
+ mpc
3901
+ .meldGetRetailQuote(args)
3902
+ .then((data) => {
3903
+ expect(data).toEqual(res);
3904
+ done();
3905
+ })
3906
+ .catch((_) => {
3907
+ expect(0).toEqual(1);
3908
+ done();
3909
+ });
3910
+ });
3911
+ it('should error out if the iframe sends an error message', (done) => {
3912
+ var _a;
3913
+ jest
3914
+ .spyOn((_a = mpc.iframe) === null || _a === void 0 ? void 0 : _a.contentWindow, 'postMessage')
3915
+ .mockImplementationOnce((_message, _origin) => {
3916
+ window.dispatchEvent(new MessageEvent('message', {
3917
+ origin: mockHostOrigin,
3918
+ data: {
3919
+ type: 'portal:meld:getRetailQuoteError',
3920
+ data: { code: 1, message: 'test' },
3921
+ },
3922
+ }));
3923
+ });
3924
+ mpc
3925
+ .meldGetRetailQuote(args)
3926
+ .then(() => {
3927
+ expect(0).toEqual(1);
3928
+ done();
3929
+ })
3930
+ .catch((e) => {
3931
+ expect(e).toBeInstanceOf(PortalMpcError);
3932
+ expect(e.message).toEqual('test');
3933
+ expect(e.code).toEqual(1);
3934
+ done();
3935
+ });
3936
+ });
3937
+ });
3938
+ describe('meldCreateRetailWidget', () => {
3939
+ const args = mockMeldCreateRetailWidgetRequest;
3940
+ const res = mockMeldCreateRetailWidgetResponse;
3941
+ it('should successfully return the retail widget', (done) => {
3942
+ var _a;
3943
+ jest
3944
+ .spyOn((_a = mpc.iframe) === null || _a === void 0 ? void 0 : _a.contentWindow, 'postMessage')
3945
+ .mockImplementation((message, origin) => {
3946
+ expect(message.type).toEqual('portal:meld:createRetailWidget');
3947
+ expect(message.data).toMatchObject(args);
3948
+ expect(origin).toEqual(mockHostOrigin);
3949
+ window.dispatchEvent(new MessageEvent('message', {
3950
+ origin: mockHostOrigin,
3951
+ data: { type: 'portal:meld:createRetailWidgetResult', data: res },
3952
+ }));
3953
+ });
3954
+ mpc
3955
+ .meldCreateRetailWidget(args)
3956
+ .then((data) => {
3957
+ expect(data).toEqual(res);
3958
+ done();
3959
+ })
3960
+ .catch((_) => {
3961
+ expect(0).toEqual(1);
3962
+ done();
3963
+ });
3964
+ });
3965
+ });
3966
+ describe('meldSearchRetailTransactions', () => {
3967
+ const res = mockMeldSearchRetailTransactionsResponse;
3968
+ it('should successfully return transactions without params', (done) => {
3969
+ var _a;
3970
+ jest
3971
+ .spyOn((_a = mpc.iframe) === null || _a === void 0 ? void 0 : _a.contentWindow, 'postMessage')
3972
+ .mockImplementation((message, origin) => {
3973
+ expect(message.type).toEqual('portal:meld:searchRetailTransactions');
3974
+ expect(origin).toEqual(mockHostOrigin);
3975
+ window.dispatchEvent(new MessageEvent('message', {
3976
+ origin: mockHostOrigin,
3977
+ data: { type: 'portal:meld:searchRetailTransactionsResult', data: res },
3978
+ }));
3979
+ });
3980
+ mpc
3981
+ .meldSearchRetailTransactions()
3982
+ .then((data) => {
3983
+ expect(data).toEqual(res);
3984
+ done();
3985
+ })
3986
+ .catch((_) => {
3987
+ expect(0).toEqual(1);
3988
+ done();
3989
+ });
3990
+ });
3991
+ });
3992
+ describe('meldGetRetailTransactionBySession', () => {
3993
+ const res = mockMeldGetRetailTransactionResponse;
3994
+ it('should successfully return a transaction by session ID', (done) => {
3995
+ var _a;
3996
+ jest
3997
+ .spyOn((_a = mpc.iframe) === null || _a === void 0 ? void 0 : _a.contentWindow, 'postMessage')
3998
+ .mockImplementation((message, origin) => {
3999
+ expect(message.type).toEqual('portal:meld:getRetailTransactionBySession');
4000
+ expect(message.data).toEqual('ses-123');
4001
+ expect(origin).toEqual(mockHostOrigin);
4002
+ window.dispatchEvent(new MessageEvent('message', {
4003
+ origin: mockHostOrigin,
4004
+ data: { type: 'portal:meld:getRetailTransactionBySessionResult', data: res },
4005
+ }));
4006
+ });
4007
+ mpc
4008
+ .meldGetRetailTransactionBySession('ses-123')
4009
+ .then((data) => {
4010
+ expect(data).toEqual(res);
4011
+ done();
4012
+ })
4013
+ .catch((_) => {
4014
+ expect(0).toEqual(1);
4015
+ done();
4016
+ });
4017
+ });
4018
+ });
4019
+ describe('meldGetRetailTransaction', () => {
4020
+ const res = mockMeldGetRetailTransactionResponse;
4021
+ it('should successfully return a transaction by ID', (done) => {
4022
+ var _a;
4023
+ jest
4024
+ .spyOn((_a = mpc.iframe) === null || _a === void 0 ? void 0 : _a.contentWindow, 'postMessage')
4025
+ .mockImplementation((message, origin) => {
4026
+ expect(message.type).toEqual('portal:meld:getRetailTransaction');
4027
+ expect(message.data).toEqual('tx-123');
4028
+ expect(origin).toEqual(mockHostOrigin);
4029
+ window.dispatchEvent(new MessageEvent('message', {
4030
+ origin: mockHostOrigin,
4031
+ data: { type: 'portal:meld:getRetailTransactionResult', data: res },
4032
+ }));
4033
+ });
4034
+ mpc
4035
+ .meldGetRetailTransaction('tx-123')
4036
+ .then((data) => {
4037
+ expect(data).toEqual(res);
4038
+ done();
4039
+ })
4040
+ .catch((_) => {
4041
+ expect(0).toEqual(1);
4042
+ done();
4043
+ });
4044
+ });
4045
+ });
4046
+ describe('meldGetServiceProviders', () => {
4047
+ const res = mockMeldDiscoveryResponse;
4048
+ it('should successfully return service providers without params', (done) => {
4049
+ var _a;
4050
+ jest
4051
+ .spyOn((_a = mpc.iframe) === null || _a === void 0 ? void 0 : _a.contentWindow, 'postMessage')
4052
+ .mockImplementation((message, origin) => {
4053
+ expect(message.type).toEqual('portal:meld:getServiceProviders');
4054
+ expect(origin).toEqual(mockHostOrigin);
4055
+ window.dispatchEvent(new MessageEvent('message', {
4056
+ origin: mockHostOrigin,
4057
+ data: { type: 'portal:meld:getServiceProvidersResult', data: res },
4058
+ }));
4059
+ });
4060
+ mpc
4061
+ .meldGetServiceProviders()
4062
+ .then((data) => {
4063
+ expect(data).toEqual(res);
4064
+ done();
4065
+ })
4066
+ .catch((_) => {
4067
+ expect(0).toEqual(1);
4068
+ done();
4069
+ });
4070
+ });
4071
+ it('should pass params to the iframe when provided', (done) => {
4072
+ var _a;
4073
+ const params = mockMeldDiscoveryParams;
4074
+ jest
4075
+ .spyOn((_a = mpc.iframe) === null || _a === void 0 ? void 0 : _a.contentWindow, 'postMessage')
4076
+ .mockImplementation((message, origin) => {
4077
+ expect(message.type).toEqual('portal:meld:getServiceProviders');
4078
+ expect(message.data).toMatchObject(params);
4079
+ expect(origin).toEqual(mockHostOrigin);
4080
+ window.dispatchEvent(new MessageEvent('message', {
4081
+ origin: mockHostOrigin,
4082
+ data: { type: 'portal:meld:getServiceProvidersResult', data: res },
4083
+ }));
4084
+ });
4085
+ mpc
4086
+ .meldGetServiceProviders(params)
4087
+ .then(() => done())
4088
+ .catch((_) => {
4089
+ expect(0).toEqual(1);
4090
+ done();
4091
+ });
4092
+ });
4093
+ });
4094
+ describe('meldGetCountries', () => {
4095
+ it('should successfully return countries', (done) => {
4096
+ var _a;
4097
+ const res = mockMeldDiscoveryResponse;
4098
+ jest
4099
+ .spyOn((_a = mpc.iframe) === null || _a === void 0 ? void 0 : _a.contentWindow, 'postMessage')
4100
+ .mockImplementation((message, origin) => {
4101
+ expect(message.type).toEqual('portal:meld:getCountries');
4102
+ expect(origin).toEqual(mockHostOrigin);
4103
+ window.dispatchEvent(new MessageEvent('message', {
4104
+ origin: mockHostOrigin,
4105
+ data: { type: 'portal:meld:getCountriesResult', data: res },
4106
+ }));
4107
+ });
4108
+ mpc
4109
+ .meldGetCountries()
4110
+ .then((data) => {
4111
+ expect(data).toEqual(res);
4112
+ done();
4113
+ })
4114
+ .catch((_) => {
4115
+ expect(0).toEqual(1);
4116
+ done();
4117
+ });
4118
+ });
4119
+ it('should error out if the iframe sends an error message', (done) => {
4120
+ var _a;
4121
+ jest
4122
+ .spyOn((_a = mpc.iframe) === null || _a === void 0 ? void 0 : _a.contentWindow, 'postMessage')
4123
+ .mockImplementationOnce((_message, _origin) => {
4124
+ window.dispatchEvent(new MessageEvent('message', {
4125
+ origin: mockHostOrigin,
4126
+ data: { type: 'portal:meld:getCountriesError', data: { code: 1, message: 'test' } },
4127
+ }));
4128
+ });
4129
+ mpc
4130
+ .meldGetCountries()
4131
+ .then(() => {
4132
+ expect(0).toEqual(1);
4133
+ done();
4134
+ })
4135
+ .catch((e) => {
4136
+ expect(e).toBeInstanceOf(PortalMpcError);
4137
+ done();
4138
+ });
4139
+ });
4140
+ });
4141
+ describe('meldGetFiatCurrencies', () => {
4142
+ it('should successfully return fiat currencies', (done) => {
4143
+ var _a;
4144
+ const res = mockMeldDiscoveryResponse;
4145
+ jest
4146
+ .spyOn((_a = mpc.iframe) === null || _a === void 0 ? void 0 : _a.contentWindow, 'postMessage')
4147
+ .mockImplementation((message, origin) => {
4148
+ expect(message.type).toEqual('portal:meld:getFiatCurrencies');
4149
+ expect(origin).toEqual(mockHostOrigin);
4150
+ window.dispatchEvent(new MessageEvent('message', {
4151
+ origin: mockHostOrigin,
4152
+ data: { type: 'portal:meld:getFiatCurrenciesResult', data: res },
4153
+ }));
4154
+ });
4155
+ mpc
4156
+ .meldGetFiatCurrencies()
4157
+ .then((data) => {
4158
+ expect(data).toEqual(res);
4159
+ done();
4160
+ })
4161
+ .catch((_) => {
4162
+ expect(0).toEqual(1);
4163
+ done();
4164
+ });
4165
+ });
4166
+ });
4167
+ describe('meldGetCryptoCurrencies', () => {
4168
+ it('should successfully return crypto currencies', (done) => {
4169
+ var _a;
4170
+ const res = mockMeldDiscoveryResponse;
4171
+ jest
4172
+ .spyOn((_a = mpc.iframe) === null || _a === void 0 ? void 0 : _a.contentWindow, 'postMessage')
4173
+ .mockImplementation((message, origin) => {
4174
+ expect(message.type).toEqual('portal:meld:getCryptoCurrencies');
4175
+ expect(origin).toEqual(mockHostOrigin);
4176
+ window.dispatchEvent(new MessageEvent('message', {
4177
+ origin: mockHostOrigin,
4178
+ data: { type: 'portal:meld:getCryptoCurrenciesResult', data: res },
4179
+ }));
4180
+ });
4181
+ mpc.meldGetCryptoCurrencies().then((data) => { expect(data).toEqual(res); done(); }).catch((_) => { expect(0).toEqual(1); done(); });
4182
+ });
4183
+ });
4184
+ describe('meldGetPaymentMethods', () => {
4185
+ it('should successfully return payment methods', (done) => {
4186
+ var _a;
4187
+ const res = mockMeldDiscoveryResponse;
4188
+ jest
4189
+ .spyOn((_a = mpc.iframe) === null || _a === void 0 ? void 0 : _a.contentWindow, 'postMessage')
4190
+ .mockImplementation((message, origin) => {
4191
+ expect(message.type).toEqual('portal:meld:getPaymentMethods');
4192
+ expect(origin).toEqual(mockHostOrigin);
4193
+ window.dispatchEvent(new MessageEvent('message', {
4194
+ origin: mockHostOrigin,
4195
+ data: { type: 'portal:meld:getPaymentMethodsResult', data: res },
4196
+ }));
4197
+ });
4198
+ mpc.meldGetPaymentMethods().then((data) => { expect(data).toEqual(res); done(); }).catch((_) => { expect(0).toEqual(1); done(); });
4199
+ });
4200
+ });
4201
+ describe('meldGetDefaults', () => {
4202
+ it('should successfully return defaults', (done) => {
4203
+ var _a;
4204
+ const res = mockMeldDiscoveryResponse;
4205
+ jest
4206
+ .spyOn((_a = mpc.iframe) === null || _a === void 0 ? void 0 : _a.contentWindow, 'postMessage')
4207
+ .mockImplementation((message, origin) => {
4208
+ expect(message.type).toEqual('portal:meld:getDefaults');
4209
+ expect(origin).toEqual(mockHostOrigin);
4210
+ window.dispatchEvent(new MessageEvent('message', {
4211
+ origin: mockHostOrigin,
4212
+ data: { type: 'portal:meld:getDefaultsResult', data: res },
4213
+ }));
4214
+ });
4215
+ mpc.meldGetDefaults().then((data) => { expect(data).toEqual(res); done(); }).catch((_) => { expect(0).toEqual(1); done(); });
4216
+ });
4217
+ });
4218
+ describe('meldGetBuyLimits', () => {
4219
+ it('should successfully return buy limits', (done) => {
4220
+ var _a;
4221
+ const res = mockMeldDiscoveryResponse;
4222
+ jest
4223
+ .spyOn((_a = mpc.iframe) === null || _a === void 0 ? void 0 : _a.contentWindow, 'postMessage')
4224
+ .mockImplementation((message, origin) => {
4225
+ expect(message.type).toEqual('portal:meld:getBuyLimits');
4226
+ expect(origin).toEqual(mockHostOrigin);
4227
+ window.dispatchEvent(new MessageEvent('message', {
4228
+ origin: mockHostOrigin,
4229
+ data: { type: 'portal:meld:getBuyLimitsResult', data: res },
4230
+ }));
4231
+ });
4232
+ mpc.meldGetBuyLimits().then((data) => { expect(data).toEqual(res); done(); }).catch((_) => { expect(0).toEqual(1); done(); });
4233
+ });
4234
+ });
4235
+ describe('meldGetSellLimits', () => {
4236
+ it('should successfully return sell limits', (done) => {
4237
+ var _a;
4238
+ const res = mockMeldDiscoveryResponse;
4239
+ jest
4240
+ .spyOn((_a = mpc.iframe) === null || _a === void 0 ? void 0 : _a.contentWindow, 'postMessage')
4241
+ .mockImplementation((message, origin) => {
4242
+ expect(message.type).toEqual('portal:meld:getSellLimits');
4243
+ expect(origin).toEqual(mockHostOrigin);
4244
+ window.dispatchEvent(new MessageEvent('message', {
4245
+ origin: mockHostOrigin,
4246
+ data: { type: 'portal:meld:getSellLimitsResult', data: res },
4247
+ }));
4248
+ });
4249
+ mpc.meldGetSellLimits().then((data) => { expect(data).toEqual(res); done(); }).catch((_) => { expect(0).toEqual(1); done(); });
4250
+ });
4251
+ });
4252
+ describe('meldGetKycLimits', () => {
4253
+ it('should successfully return KYC limits', (done) => {
4254
+ var _a;
4255
+ const res = mockMeldDiscoveryResponse;
4256
+ jest
4257
+ .spyOn((_a = mpc.iframe) === null || _a === void 0 ? void 0 : _a.contentWindow, 'postMessage')
4258
+ .mockImplementation((message, origin) => {
4259
+ expect(message.type).toEqual('portal:meld:getKycLimits');
4260
+ expect(origin).toEqual(mockHostOrigin);
4261
+ window.dispatchEvent(new MessageEvent('message', {
4262
+ origin: mockHostOrigin,
4263
+ data: { type: 'portal:meld:getKycLimitsResult', data: res },
4264
+ }));
4265
+ });
4266
+ mpc.meldGetKycLimits().then((data) => { expect(data).toEqual(res); done(); }).catch((_) => { expect(0).toEqual(1); done(); });
4267
+ });
4268
+ });
3762
4269
  describe('accountAbstractionBuildBatchedUserOp', () => {
3763
4270
  const args = mockBuildBatchedUserOpRequest;
3764
4271
  const res = mockBuildBatchedUserOpResponse;
@@ -3893,4 +4400,131 @@ describe('Mpc', () => {
3893
4400
  });
3894
4401
  });
3895
4402
  });
4403
+ describe('walletNotOnDevice detection', () => {
4404
+ const makeClient = (overrides = {}) => (Object.assign({ id: 'client-test', address: mockAddress, ejectedAt: null, custodian: { id: 'c', name: 'c' }, environment: { id: 'e', name: 'e', backupWithPortalEnabled: false, isMultiBackupEnabled: false }, isAccountAbstracted: false, metadata: { namespaces: {} }, wallets: [] }, overrides));
4405
+ const makeWallet = (curve, signingStatus, backupStatus) => ({
4406
+ id: `wallet-${curve}`,
4407
+ createdAt: '2024-01-01T00:00:00.000Z',
4408
+ curve,
4409
+ publicKey: 'pk',
4410
+ signingSharePairs: [{ id: 'sp1', createdAt: '2024-01-01T00:00:00.000Z', status: signingStatus }],
4411
+ backupSharePairs: [
4412
+ {
4413
+ id: 'bp1',
4414
+ createdAt: '2024-01-01T00:00:00.000Z',
4415
+ backupMethod: BackupMethods.password,
4416
+ status: backupStatus,
4417
+ },
4418
+ ],
4419
+ });
4420
+ const dispatchReady = () => {
4421
+ window.dispatchEvent(new MessageEvent('message', {
4422
+ origin: `https://${mockHost}`,
4423
+ data: { type: 'portal:ready', data: true },
4424
+ }));
4425
+ };
4426
+ const flushPromises = () => new Promise((resolve) => setTimeout(resolve, 0));
4427
+ beforeEach(() => {
4428
+ jest.spyOn(mpc, 'getAddress').mockResolvedValue(mockAddress);
4429
+ mpc.waitForReadyMessage();
4430
+ });
4431
+ it('does not emit when client has no wallets (new user / initial setup)', () => __awaiter(void 0, void 0, void 0, function* () {
4432
+ jest.spyOn(mpc, 'getClient').mockResolvedValue(makeClient({ wallets: [] }));
4433
+ jest.spyOn(mpc, 'checkSharesOnDevice').mockResolvedValue({ SECP256K1: false, ED25519: false });
4434
+ dispatchReady();
4435
+ yield flushPromises();
4436
+ expect(portalMock.triggerWalletNotOnDevice).not.toHaveBeenCalled();
4437
+ expect(portalMock.triggerReady).toHaveBeenCalled();
4438
+ }));
4439
+ it('does not emit when wallets exist but all signing share pairs are incomplete (setup in progress)', () => __awaiter(void 0, void 0, void 0, function* () {
4440
+ jest.spyOn(mpc, 'getClient').mockResolvedValue(makeClient({
4441
+ wallets: [
4442
+ makeWallet(PortalCurve.SECP256K1, 'incomplete', 'incomplete'),
4443
+ makeWallet(PortalCurve.ED25519, 'incomplete', 'incomplete'),
4444
+ ],
4445
+ }));
4446
+ jest.spyOn(mpc, 'checkSharesOnDevice').mockResolvedValue({ SECP256K1: false, ED25519: false });
4447
+ dispatchReady();
4448
+ yield flushPromises();
4449
+ expect(portalMock.triggerWalletNotOnDevice).not.toHaveBeenCalled();
4450
+ expect(portalMock.triggerReady).toHaveBeenCalled();
4451
+ }));
4452
+ it('does not emit when wallet is present on device', () => __awaiter(void 0, void 0, void 0, function* () {
4453
+ jest.spyOn(mpc, 'getClient').mockResolvedValue(makeClient({
4454
+ wallets: [
4455
+ makeWallet(PortalCurve.SECP256K1, 'completed', 'completed'),
4456
+ makeWallet(PortalCurve.ED25519, 'completed', 'completed'),
4457
+ ],
4458
+ }));
4459
+ jest.spyOn(mpc, 'checkSharesOnDevice').mockResolvedValue({ SECP256K1: true, ED25519: true });
4460
+ dispatchReady();
4461
+ yield flushPromises();
4462
+ expect(portalMock.triggerWalletNotOnDevice).not.toHaveBeenCalled();
4463
+ }));
4464
+ it('emits walletNotOnDevice with isBackedUp=false when wallet is not on device and not backed up', () => __awaiter(void 0, void 0, void 0, function* () {
4465
+ jest.spyOn(mpc, 'getClient').mockResolvedValue(makeClient({
4466
+ wallets: [
4467
+ makeWallet(PortalCurve.SECP256K1, 'completed', 'incomplete'),
4468
+ makeWallet(PortalCurve.ED25519, 'completed', 'incomplete'),
4469
+ ],
4470
+ }));
4471
+ jest.spyOn(mpc, 'checkSharesOnDevice').mockResolvedValue({ SECP256K1: false, ED25519: false });
4472
+ dispatchReady();
4473
+ yield flushPromises();
4474
+ expect(portalMock.triggerWalletNotOnDevice).toHaveBeenCalledWith({
4475
+ clientId: 'client-test',
4476
+ isBackedUp: false,
4477
+ reason: 'storage_cleared',
4478
+ });
4479
+ }));
4480
+ it('emits walletNotOnDevice with isBackedUp=true when at least one backup is complete', () => __awaiter(void 0, void 0, void 0, function* () {
4481
+ jest.spyOn(mpc, 'getClient').mockResolvedValue(makeClient({
4482
+ wallets: [makeWallet(PortalCurve.SECP256K1, 'completed', 'completed')],
4483
+ }));
4484
+ jest.spyOn(mpc, 'checkSharesOnDevice').mockResolvedValue({ SECP256K1: false, ED25519: false });
4485
+ dispatchReady();
4486
+ yield flushPromises();
4487
+ expect(portalMock.triggerWalletNotOnDevice).toHaveBeenCalledWith({
4488
+ clientId: 'client-test',
4489
+ isBackedUp: true,
4490
+ reason: 'storage_cleared',
4491
+ });
4492
+ }));
4493
+ it('does not emit for EVM-only client when SECP256K1 share is present (ED25519 absence is irrelevant)', () => __awaiter(void 0, void 0, void 0, function* () {
4494
+ jest.spyOn(mpc, 'getClient').mockResolvedValue(makeClient({
4495
+ wallets: [makeWallet(PortalCurve.SECP256K1, 'completed', 'incomplete')],
4496
+ }));
4497
+ jest.spyOn(mpc, 'checkSharesOnDevice').mockResolvedValue({ SECP256K1: true, ED25519: false });
4498
+ dispatchReady();
4499
+ yield flushPromises();
4500
+ expect(portalMock.triggerWalletNotOnDevice).not.toHaveBeenCalled();
4501
+ }));
4502
+ it('emits for EVM-only client when SECP256K1 share is missing', () => __awaiter(void 0, void 0, void 0, function* () {
4503
+ jest.spyOn(mpc, 'getClient').mockResolvedValue(makeClient({
4504
+ wallets: [makeWallet(PortalCurve.SECP256K1, 'completed', 'incomplete')],
4505
+ }));
4506
+ jest.spyOn(mpc, 'checkSharesOnDevice').mockResolvedValue({ SECP256K1: false, ED25519: false });
4507
+ dispatchReady();
4508
+ yield flushPromises();
4509
+ expect(portalMock.triggerWalletNotOnDevice).toHaveBeenCalled();
4510
+ }));
4511
+ it('does not emit when wallet is ejected (recovery is impossible)', () => __awaiter(void 0, void 0, void 0, function* () {
4512
+ jest.spyOn(mpc, 'getClient').mockResolvedValue(makeClient({
4513
+ ejectedAt: '2024-06-01T00:00:00.000Z',
4514
+ wallets: [makeWallet(PortalCurve.SECP256K1, 'completed', 'incomplete')],
4515
+ }));
4516
+ jest.spyOn(mpc, 'checkSharesOnDevice').mockResolvedValue({ SECP256K1: false, ED25519: false });
4517
+ dispatchReady();
4518
+ yield flushPromises();
4519
+ expect(portalMock.triggerWalletNotOnDevice).not.toHaveBeenCalled();
4520
+ }));
4521
+ it('still calls triggerReady when detection throws (detection must not block initialization)', () => __awaiter(void 0, void 0, void 0, function* () {
4522
+ jest.spyOn(mpc, 'getClient').mockRejectedValue(new Error('network error'));
4523
+ jest.spyOn(mpc, 'checkSharesOnDevice').mockRejectedValue(new Error('network error'));
4524
+ dispatchReady();
4525
+ yield flushPromises();
4526
+ expect(portalMock.triggerWalletNotOnDevice).not.toHaveBeenCalled();
4527
+ expect(portalMock.triggerReady).toHaveBeenCalled();
4528
+ }));
4529
+ });
3896
4530
  });