@portal-hq/web 3.13.2 → 3.14.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 (96) hide show
  1. package/lib/commonjs/index.js +127 -9
  2. package/lib/commonjs/index.test.js +13 -0
  3. package/lib/commonjs/integrations/delegations/index.js +109 -2
  4. package/lib/commonjs/integrations/delegations/index.test.js +171 -0
  5. package/lib/commonjs/integrations/ramps/noah/index.test.js +18 -5
  6. package/lib/commonjs/integrations/trading/index.js +16 -5
  7. package/lib/commonjs/integrations/trading/lifi/index.js +318 -25
  8. package/lib/commonjs/integrations/trading/lifi/lifi.tradeAsset.test.js +360 -0
  9. package/lib/commonjs/integrations/trading/lifi/lifiStatusPoll.js +118 -0
  10. package/lib/commonjs/integrations/trading/lifi/lifiStatusPoll.test.js +66 -0
  11. package/lib/commonjs/integrations/trading/zero-x/index.js +129 -26
  12. package/lib/commonjs/integrations/trading/zero-x/index.test.js +163 -1
  13. package/lib/commonjs/integrations/yield/index.js +18 -4
  14. package/lib/commonjs/integrations/yield/yieldxyz.getValidators.test.js +71 -0
  15. package/lib/commonjs/integrations/yield/yieldxyz.highLevel.test.js +438 -0
  16. package/lib/commonjs/integrations/yield/yieldxyz.js +541 -1
  17. package/lib/commonjs/internal/pollLoop.js +64 -0
  18. package/lib/commonjs/internal/pollLoop.test.js +100 -0
  19. package/lib/commonjs/internal/stripStalePlanningNonce.js +65 -0
  20. package/lib/commonjs/internal/stripStalePlanningNonce.test.js +35 -0
  21. package/lib/commonjs/internal/waitForEvmOrUserOpConfirmation.js +155 -0
  22. package/lib/commonjs/internal/waitForEvmOrUserOpConfirmation.test.js +33 -0
  23. package/lib/commonjs/internal/waitForEvmTxConfirmation.js +104 -0
  24. package/lib/commonjs/internal/waitForSolanaTxConfirmation.js +106 -0
  25. package/lib/commonjs/internal/yieldEvmNetwork.js +60 -0
  26. package/lib/commonjs/mpc/index.js +117 -1
  27. package/lib/commonjs/provider/index.js +17 -0
  28. package/lib/commonjs/shared/trace/index.js +0 -1
  29. package/lib/esm/index.js +127 -9
  30. package/lib/esm/index.test.js +13 -0
  31. package/lib/esm/integrations/delegations/index.js +109 -2
  32. package/lib/esm/integrations/delegations/index.test.js +171 -0
  33. package/lib/esm/integrations/ramps/noah/index.test.js +18 -5
  34. package/lib/esm/integrations/trading/index.js +16 -5
  35. package/lib/esm/integrations/trading/lifi/index.js +313 -25
  36. package/lib/esm/integrations/trading/lifi/lifi.tradeAsset.test.js +332 -0
  37. package/lib/esm/integrations/trading/lifi/lifiStatusPoll.js +113 -0
  38. package/lib/esm/integrations/trading/lifi/lifiStatusPoll.test.js +64 -0
  39. package/lib/esm/integrations/trading/zero-x/index.js +129 -26
  40. package/lib/esm/integrations/trading/zero-x/index.test.js +141 -2
  41. package/lib/esm/integrations/yield/index.js +18 -4
  42. package/lib/esm/integrations/yield/yieldxyz.getValidators.test.js +66 -0
  43. package/lib/esm/integrations/yield/yieldxyz.highLevel.test.js +433 -0
  44. package/lib/esm/integrations/yield/yieldxyz.js +541 -1
  45. package/lib/esm/internal/pollLoop.js +59 -0
  46. package/lib/esm/internal/pollLoop.test.js +98 -0
  47. package/lib/esm/internal/stripStalePlanningNonce.js +61 -0
  48. package/lib/esm/internal/stripStalePlanningNonce.test.js +33 -0
  49. package/lib/esm/internal/waitForEvmOrUserOpConfirmation.js +151 -0
  50. package/lib/esm/internal/waitForEvmOrUserOpConfirmation.test.js +31 -0
  51. package/lib/esm/internal/waitForEvmTxConfirmation.js +100 -0
  52. package/lib/esm/internal/waitForSolanaTxConfirmation.js +102 -0
  53. package/lib/esm/internal/yieldEvmNetwork.js +55 -0
  54. package/lib/esm/mpc/index.js +117 -1
  55. package/lib/esm/provider/index.js +17 -0
  56. package/lib/esm/shared/trace/index.js +0 -1
  57. package/noah-types.d.ts +16 -2
  58. package/package.json +1 -1
  59. package/src/index.test.ts +15 -0
  60. package/src/index.ts +203 -14
  61. package/src/integrations/delegations/index.test.ts +251 -0
  62. package/src/integrations/delegations/index.ts +202 -4
  63. package/src/integrations/ramps/noah/index.test.ts +18 -5
  64. package/src/integrations/trading/index.ts +10 -7
  65. package/src/integrations/trading/lifi/index.ts +421 -28
  66. package/src/integrations/trading/lifi/lifi.tradeAsset.test.ts +436 -0
  67. package/src/integrations/trading/lifi/lifiStatusPoll.test.ts +74 -0
  68. package/src/integrations/trading/lifi/lifiStatusPoll.ts +158 -0
  69. package/src/integrations/trading/zero-x/index.test.ts +297 -1
  70. package/src/integrations/trading/zero-x/index.ts +181 -27
  71. package/src/integrations/yield/index.ts +24 -4
  72. package/src/integrations/yield/yieldxyz.getValidators.test.ts +70 -0
  73. package/src/integrations/yield/yieldxyz.highLevel.test.ts +536 -0
  74. package/src/integrations/yield/yieldxyz.ts +762 -8
  75. package/src/internal/pollLoop.test.ts +109 -0
  76. package/src/internal/pollLoop.ts +87 -0
  77. package/src/internal/stripStalePlanningNonce.test.ts +38 -0
  78. package/src/internal/stripStalePlanningNonce.ts +66 -0
  79. package/src/internal/waitForEvmOrUserOpConfirmation.test.ts +31 -0
  80. package/src/internal/waitForEvmOrUserOpConfirmation.ts +194 -0
  81. package/src/internal/waitForEvmTxConfirmation.ts +155 -0
  82. package/src/internal/waitForSolanaTxConfirmation.ts +135 -0
  83. package/src/internal/yieldEvmNetwork.ts +57 -0
  84. package/src/mpc/index.ts +144 -1
  85. package/src/provider/index.ts +25 -0
  86. package/src/shared/trace/index.ts +0 -1
  87. package/src/shared/types/README.md +6 -0
  88. package/src/shared/types/api.ts +12 -1
  89. package/src/shared/types/common.ts +332 -20
  90. package/src/shared/types/delegations.ts +10 -0
  91. package/src/shared/types/index.ts +1 -0
  92. package/src/shared/types/lifi.ts +82 -0
  93. package/src/shared/types/noah.ts +124 -33
  94. package/src/shared/types/yieldxyz.ts +193 -0
  95. package/src/shared/types/zero-x.ts +83 -1
  96. package/types.d.ts +6 -0
@@ -7,48 +7,151 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
+ var __rest = (this && this.__rest) || function (s, e) {
11
+ var t = {};
12
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
13
+ t[p] = s[p];
14
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
15
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
16
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
17
+ t[p[i]] = s[p[i]];
18
+ }
19
+ return t;
20
+ };
21
+ import { waitForEvmTxConfirmation } from '../../../internal/waitForEvmTxConfirmation';
22
+ import { normalizeChainToNetwork } from '../lifi';
23
+ const LOG_PREFIX = '[ZeroX]';
24
+ function mergeZeroXOptions(instance, perCall) {
25
+ return Object.assign(Object.assign({}, instance), perCall);
26
+ }
10
27
  export default class ZeroX {
11
- constructor({ mpc }) {
28
+ constructor(_a) {
29
+ var { mpc } = _a, defaults = __rest(_a, ["mpc"]);
12
30
  this.mpc = mpc;
31
+ this.defaults = defaults;
13
32
  }
14
- /**
15
- * Get a quote from the Swaps API.
16
- *
17
- * @param apiKey - The API key for the Swaps API.
18
- * @param args - The arguments for the quote.
19
- * @param chainId - The chain ID for the quote.
20
- * @returns The quote response.
21
- */
22
33
  getQuote(args, options) {
23
34
  var _a;
24
35
  return __awaiter(this, void 0, void 0, function* () {
25
- return (_a = this.mpc) === null || _a === void 0 ? void 0 : _a.getSwapsQuoteV2(args, options);
36
+ const merged = Object.assign(Object.assign({}, this.defaults), options);
37
+ const key = merged.zeroXApiKey;
38
+ return (_a = this.mpc) === null || _a === void 0 ? void 0 : _a.getSwapsQuoteV2(args, key != null && key !== '' ? { zeroXApiKey: key } : undefined);
26
39
  });
27
40
  }
28
- /**
29
- * Get the valid, swappable token sources that can be used with your Portal MPC Wallet.
30
- *
31
- * @param apiKey - The API key for the Swaps API.
32
- * @param chainId - The chain ID for the sources.
33
- * @returns The sources response.
34
- */
35
41
  getSources(chainId, options) {
36
42
  var _a;
37
43
  return __awaiter(this, void 0, void 0, function* () {
38
- return (_a = this.mpc) === null || _a === void 0 ? void 0 : _a.getSwapsSourcesV2({ chainId }, options);
44
+ const merged = Object.assign(Object.assign({}, this.defaults), options);
45
+ const key = merged.zeroXApiKey;
46
+ return (_a = this.mpc) === null || _a === void 0 ? void 0 : _a.getSwapsSourcesV2({ chainId }, key != null && key !== '' ? { zeroXApiKey: key } : undefined);
39
47
  });
40
48
  }
41
- /**
42
- * Get the price of a token from the Swaps API.
43
- *
44
- * @param args - The arguments for the price.
45
- * @param options - The options for the price.
46
- * @returns The price response.
47
- */
48
49
  getPrice(args, options) {
49
50
  var _a;
50
51
  return __awaiter(this, void 0, void 0, function* () {
51
- return (_a = this.mpc) === null || _a === void 0 ? void 0 : _a.getSwapsPrice(args, options);
52
+ const merged = Object.assign(Object.assign({}, this.defaults), options);
53
+ const key = merged.zeroXApiKey;
54
+ return (_a = this.mpc) === null || _a === void 0 ? void 0 : _a.getSwapsPrice(args, key != null && key !== '' ? { zeroXApiKey: key } : undefined);
55
+ });
56
+ }
57
+ tradeAsset(params, options) {
58
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w;
59
+ return __awaiter(this, void 0, void 0, function* () {
60
+ const o = mergeZeroXOptions(this.defaults, options);
61
+ const signAndSend = o.signAndSendTransaction;
62
+ if (!signAndSend) {
63
+ throw new Error(`${LOG_PREFIX} tradeAsset requires signAndSendTransaction`);
64
+ }
65
+ if (!o.waitForConfirmation && !o.evmRequestFn) {
66
+ throw new Error(`${LOG_PREFIX} tradeAsset requires waitForConfirmation (instance default or per-call option), or evmRequestFn fallback.`);
67
+ }
68
+ const apiOpts = { zeroXApiKey: (_a = o.zeroXApiKey) !== null && _a !== void 0 ? _a : params.zeroXApiKey };
69
+ (_b = params.onProgress) === null || _b === void 0 ? void 0 : _b.call(params, 'fetching_quote');
70
+ const quoteReq = {
71
+ chainId: params.chainId,
72
+ buyToken: params.buyToken,
73
+ sellToken: params.sellToken,
74
+ sellAmount: params.sellAmount,
75
+ txOrigin: params.fromAddress,
76
+ swapFeeRecipient: params.swapFeeRecipient,
77
+ swapFeeBps: params.swapFeeBps,
78
+ swapFeeToken: params.swapFeeToken,
79
+ tradeSurplusRecipient: params.tradeSurplusRecipient,
80
+ gasPrice: params.gasPrice,
81
+ slippageBps: params.slippageBps,
82
+ excludedSources: params.excludedSources,
83
+ sellEntireBalance: params.sellEntireBalance,
84
+ };
85
+ const quote = yield this.mpc.getSwapsQuoteV2(quoteReq, apiOpts);
86
+ const err = (_c = quote.error) === null || _c === void 0 ? void 0 : _c.trim();
87
+ if (err) {
88
+ throw new Error(`${LOG_PREFIX} Quote error: ${err}`);
89
+ }
90
+ const raw = (_d = quote.data) === null || _d === void 0 ? void 0 : _d.rawResponse;
91
+ if (!raw) {
92
+ const msg = 'Quote response missing data.rawResponse';
93
+ (_e = params.onProgress) === null || _e === void 0 ? void 0 : _e.call(params, 'failed', { errorMessage: msg });
94
+ throw new Error(`${LOG_PREFIX} ${msg}`);
95
+ }
96
+ const transaction = raw.transaction;
97
+ const to = transaction !== null &&
98
+ transaction !== undefined &&
99
+ typeof transaction === 'object' &&
100
+ 'to' in transaction
101
+ ? transaction.to
102
+ : undefined;
103
+ if (typeof to !== 'string' ||
104
+ to.trim() === '' ||
105
+ transaction === null ||
106
+ transaction === undefined ||
107
+ typeof transaction !== 'object') {
108
+ const msg = 'Quote response missing valid transaction (expected object with non-empty string "to")';
109
+ (_f = params.onProgress) === null || _f === void 0 ? void 0 : _f.call(params, 'failed', { errorMessage: msg });
110
+ throw new Error(`${LOG_PREFIX} ${msg}`);
111
+ }
112
+ const tx = transaction;
113
+ const network = normalizeChainToNetwork(params.chainId);
114
+ (_g = params.onProgress) === null || _g === void 0 ? void 0 : _g.call(params, 'signing', {
115
+ buyAmount: (_j = (_h = quote.data) === null || _h === void 0 ? void 0 : _h.rawResponse) === null || _j === void 0 ? void 0 : _j.buyAmount,
116
+ sellAmount: (_l = (_k = quote.data) === null || _k === void 0 ? void 0 : _k.rawResponse) === null || _l === void 0 ? void 0 : _l.sellAmount,
117
+ transaction: tx,
118
+ });
119
+ let txHash;
120
+ try {
121
+ txHash = yield signAndSend(tx, network);
122
+ }
123
+ catch (e) {
124
+ const msg = e instanceof Error ? e.message : String(e);
125
+ (_m = params.onProgress) === null || _m === void 0 ? void 0 : _m.call(params, 'failed', { errorMessage: msg });
126
+ throw e;
127
+ }
128
+ if (typeof txHash !== 'string' || txHash.trim() === '') {
129
+ const msg = 'signAndSendTransaction returned empty or invalid transaction hash';
130
+ (_o = params.onProgress) === null || _o === void 0 ? void 0 : _o.call(params, 'failed', { errorMessage: msg });
131
+ throw new Error(`${LOG_PREFIX} ${msg}`);
132
+ }
133
+ (_p = params.onProgress) === null || _p === void 0 ? void 0 : _p.call(params, 'submitted', { txHash });
134
+ if (o.waitForConfirmation) {
135
+ (_q = params.onProgress) === null || _q === void 0 ? void 0 : _q.call(params, 'confirming', { txHash });
136
+ const waiterResult = yield o.waitForConfirmation(txHash, network);
137
+ const ok = waiterResult === true;
138
+ if (!ok) {
139
+ const msg = `${LOG_PREFIX} on-chain confirmation did not complete (waitForConfirmation did not return true) for ${txHash} on ${network}`;
140
+ (_r = params.onProgress) === null || _r === void 0 ? void 0 : _r.call(params, 'failed', { errorMessage: msg, txHash });
141
+ throw new Error(msg);
142
+ }
143
+ (_s = params.onProgress) === null || _s === void 0 ? void 0 : _s.call(params, 'confirmed', { txHash });
144
+ }
145
+ else if (o.evmRequestFn) {
146
+ (_t = params.onProgress) === null || _t === void 0 ? void 0 : _t.call(params, 'confirming', { txHash });
147
+ yield waitForEvmTxConfirmation(txHash, network, o.evmRequestFn, {
148
+ pollIntervalMs: (_u = o.evmPollerOptions) === null || _u === void 0 ? void 0 : _u.pollIntervalMs,
149
+ timeoutMs: (_v = o.evmPollerOptions) === null || _v === void 0 ? void 0 : _v.timeoutMs,
150
+ onTimeout: 'throw',
151
+ });
152
+ (_w = params.onProgress) === null || _w === void 0 ? void 0 : _w.call(params, 'confirmed', { txHash });
153
+ }
154
+ return { hashes: [txHash] };
52
155
  });
53
156
  }
54
157
  }
@@ -13,7 +13,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
13
13
  import ZeroX from '.';
14
14
  import Mpc from '../../../mpc';
15
15
  import portalMock from '../../../__mocks/portal/portal';
16
- import { mockHost, mockSourcesRes, mockZeroExQuoteV2Request, mockZeroExQuoteV2Response, mockZeroExOptions, mockZeroExPriceRequest, mockZeroExPriceResponse, } from '../../../__mocks/constants';
16
+ import * as waitEvm from '../../../internal/waitForEvmTxConfirmation';
17
+ import { mockEip155Address, mockHost, mockSourcesRes, mockZeroExQuoteV2Request, mockZeroExQuoteV2Response, mockZeroExOptions, mockZeroExPriceRequest, mockZeroExPriceResponse, } from '../../../__mocks/constants';
17
18
  describe('ZeroX', () => {
18
19
  let zeroX;
19
20
  let mpc;
@@ -58,7 +59,6 @@ describe('ZeroX', () => {
58
59
  const result = yield zeroX.getSources('eip155:1', {
59
60
  zeroXApiKey: 'test-api-key',
60
61
  });
61
- console.log(`Result:`, result);
62
62
  expect(spy).toHaveBeenCalledTimes(1);
63
63
  expect(spy).toHaveBeenCalledWith({ chainId: 'eip155:1' }, { zeroXApiKey: 'test-api-key' });
64
64
  expect(result).toEqual(mockSourcesRes);
@@ -103,4 +103,143 @@ describe('ZeroX', () => {
103
103
  yield expect(zeroX.getPrice(mockZeroExPriceRequest)).rejects.toThrow('Test error');
104
104
  }));
105
105
  });
106
+ describe('tradeAsset', () => {
107
+ it('throws when waitForConfirmation returns false and emits failed, not confirmed', () => __awaiter(void 0, void 0, void 0, function* () {
108
+ const onProgress = jest.fn();
109
+ jest
110
+ .spyOn(mpc, 'getSwapsQuoteV2')
111
+ .mockResolvedValue(mockZeroExQuoteV2Response);
112
+ yield expect(zeroX.tradeAsset(Object.assign(Object.assign({}, mockZeroExQuoteV2Request), { fromAddress: mockEip155Address, onProgress }), {
113
+ signAndSendTransaction: () => __awaiter(void 0, void 0, void 0, function* () { return '0xabc'; }),
114
+ waitForConfirmation: () => __awaiter(void 0, void 0, void 0, function* () { return false; }),
115
+ })).rejects.toThrow(/on-chain confirmation/);
116
+ const statuses = onProgress.mock.calls.map((c) => c[0]);
117
+ expect(statuses).toContain('failed');
118
+ expect(statuses).not.toContain('confirmed');
119
+ }));
120
+ it('emits confirmed after waitForConfirmation succeeds', () => __awaiter(void 0, void 0, void 0, function* () {
121
+ const onProgress = jest.fn();
122
+ jest
123
+ .spyOn(mpc, 'getSwapsQuoteV2')
124
+ .mockResolvedValue(mockZeroExQuoteV2Response);
125
+ yield zeroX.tradeAsset(Object.assign(Object.assign({}, mockZeroExQuoteV2Request), { fromAddress: mockEip155Address, onProgress }), {
126
+ signAndSendTransaction: () => __awaiter(void 0, void 0, void 0, function* () { return '0xabc'; }),
127
+ waitForConfirmation: () => __awaiter(void 0, void 0, void 0, function* () { return true; }),
128
+ });
129
+ expect(onProgress).toHaveBeenCalledWith('confirmed', { txHash: '0xabc' });
130
+ }));
131
+ it('throws before signing when quote has error string', () => __awaiter(void 0, void 0, void 0, function* () {
132
+ jest.spyOn(mpc, 'getSwapsQuoteV2').mockResolvedValue({
133
+ error: 'insufficient liquidity',
134
+ });
135
+ yield expect(zeroX.tradeAsset(Object.assign(Object.assign({}, mockZeroExQuoteV2Request), { fromAddress: mockEip155Address }), {
136
+ signAndSendTransaction: () => __awaiter(void 0, void 0, void 0, function* () { return '0x'; }),
137
+ waitForConfirmation: () => __awaiter(void 0, void 0, void 0, function* () { return true; }),
138
+ })).rejects.toThrow(/Quote error: insufficient liquidity/);
139
+ }));
140
+ it('throws before signing when neither waitForConfirmation nor evmRequestFn', () => __awaiter(void 0, void 0, void 0, function* () {
141
+ const quoteSpy = jest
142
+ .spyOn(mpc, 'getSwapsQuoteV2')
143
+ .mockResolvedValue(mockZeroExQuoteV2Response);
144
+ yield expect(zeroX.tradeAsset(Object.assign(Object.assign({}, mockZeroExQuoteV2Request), { fromAddress: mockEip155Address }), {
145
+ signAndSendTransaction: () => __awaiter(void 0, void 0, void 0, function* () { return '0xshouldnotrun'; }),
146
+ })).rejects.toThrow(/requires waitForConfirmation.*or evmRequestFn/);
147
+ expect(quoteSpy).not.toHaveBeenCalled();
148
+ }));
149
+ it('throws before signing when rawResponse is missing', () => __awaiter(void 0, void 0, void 0, function* () {
150
+ jest.spyOn(mpc, 'getSwapsQuoteV2').mockResolvedValue({
151
+ data: {},
152
+ });
153
+ yield expect(zeroX.tradeAsset(Object.assign(Object.assign({}, mockZeroExQuoteV2Request), { fromAddress: mockEip155Address }), {
154
+ signAndSendTransaction: () => __awaiter(void 0, void 0, void 0, function* () { return '0x'; }),
155
+ waitForConfirmation: () => __awaiter(void 0, void 0, void 0, function* () { return true; }),
156
+ })).rejects.toThrow(/missing data.rawResponse/);
157
+ }));
158
+ it('throws before signing when transaction.to is invalid', () => __awaiter(void 0, void 0, void 0, function* () {
159
+ jest.spyOn(mpc, 'getSwapsQuoteV2').mockResolvedValue({
160
+ data: {
161
+ rawResponse: Object.assign(Object.assign({}, mockZeroExQuoteV2Response.data.rawResponse), { transaction: { to: '' } }),
162
+ },
163
+ });
164
+ const onProgress = jest.fn();
165
+ yield expect(zeroX.tradeAsset(Object.assign(Object.assign({}, mockZeroExQuoteV2Request), { fromAddress: mockEip155Address, onProgress }), {
166
+ signAndSendTransaction: () => __awaiter(void 0, void 0, void 0, function* () { return '0x'; }),
167
+ waitForConfirmation: () => __awaiter(void 0, void 0, void 0, function* () { return true; }),
168
+ })).rejects.toThrow(/missing valid transaction/);
169
+ expect(onProgress).toHaveBeenCalledWith('failed', expect.objectContaining({
170
+ errorMessage: expect.stringContaining('valid transaction'),
171
+ }));
172
+ }));
173
+ it('signer throws: rethrows and emits failed', () => __awaiter(void 0, void 0, void 0, function* () {
174
+ const onProgress = jest.fn();
175
+ jest
176
+ .spyOn(mpc, 'getSwapsQuoteV2')
177
+ .mockResolvedValue(mockZeroExQuoteV2Response);
178
+ yield expect(zeroX.tradeAsset(Object.assign(Object.assign({}, mockZeroExQuoteV2Request), { fromAddress: mockEip155Address, onProgress }), {
179
+ signAndSendTransaction: () => __awaiter(void 0, void 0, void 0, function* () {
180
+ throw new Error('user rejected');
181
+ }),
182
+ waitForConfirmation: () => __awaiter(void 0, void 0, void 0, function* () { return true; }),
183
+ })).rejects.toThrow('user rejected');
184
+ expect(onProgress).toHaveBeenCalledWith('failed', expect.objectContaining({ errorMessage: 'user rejected' }));
185
+ }));
186
+ it('empty hash after sign: throws and emits failed', () => __awaiter(void 0, void 0, void 0, function* () {
187
+ const onProgress = jest.fn();
188
+ jest
189
+ .spyOn(mpc, 'getSwapsQuoteV2')
190
+ .mockResolvedValue(mockZeroExQuoteV2Response);
191
+ yield expect(zeroX.tradeAsset(Object.assign(Object.assign({}, mockZeroExQuoteV2Request), { fromAddress: mockEip155Address, onProgress }), {
192
+ signAndSendTransaction: () => __awaiter(void 0, void 0, void 0, function* () { return ' '; }),
193
+ waitForConfirmation: () => __awaiter(void 0, void 0, void 0, function* () { return true; }),
194
+ })).rejects.toThrow(/empty or invalid transaction hash/);
195
+ expect(onProgress).toHaveBeenCalledWith('failed', expect.objectContaining({ errorMessage: expect.any(String) }));
196
+ }));
197
+ it('evmRequestFn path: waits for receipt with onTimeout throw', () => __awaiter(void 0, void 0, void 0, function* () {
198
+ const waitSpy = jest
199
+ .spyOn(waitEvm, 'waitForEvmTxConfirmation')
200
+ .mockResolvedValue(true);
201
+ jest
202
+ .spyOn(mpc, 'getSwapsQuoteV2')
203
+ .mockResolvedValue(mockZeroExQuoteV2Response);
204
+ yield zeroX.tradeAsset(Object.assign(Object.assign({}, mockZeroExQuoteV2Request), { fromAddress: mockEip155Address }), {
205
+ signAndSendTransaction: () => __awaiter(void 0, void 0, void 0, function* () { return '0xhash'; }),
206
+ evmRequestFn: () => __awaiter(void 0, void 0, void 0, function* () { return ({}); }),
207
+ });
208
+ expect(waitSpy).toHaveBeenCalledWith('0xhash', 'eip155:1', expect.any(Function), expect.objectContaining({ onTimeout: 'throw' }));
209
+ waitSpy.mockRestore();
210
+ }));
211
+ it('instance zeroXApiKey wins over params.zeroXApiKey when both set', () => __awaiter(void 0, void 0, void 0, function* () {
212
+ const spy = jest
213
+ .spyOn(mpc, 'getSwapsQuoteV2')
214
+ .mockResolvedValue(mockZeroExQuoteV2Response);
215
+ const z = new ZeroX({
216
+ mpc,
217
+ zeroXApiKey: 'from-instance',
218
+ });
219
+ yield z.tradeAsset(Object.assign(Object.assign({}, mockZeroExQuoteV2Request), { fromAddress: mockEip155Address, zeroXApiKey: 'from-params' }), {
220
+ signAndSendTransaction: () => __awaiter(void 0, void 0, void 0, function* () { return '0xh'; }),
221
+ waitForConfirmation: () => __awaiter(void 0, void 0, void 0, function* () { return true; }),
222
+ });
223
+ expect(spy).toHaveBeenCalledWith(expect.any(Object), expect.objectContaining({ zeroXApiKey: 'from-instance' }));
224
+ }));
225
+ it('uses params.zeroXApiKey when instance has no key', () => __awaiter(void 0, void 0, void 0, function* () {
226
+ const spy = jest
227
+ .spyOn(mpc, 'getSwapsQuoteV2')
228
+ .mockResolvedValue(mockZeroExQuoteV2Response);
229
+ yield zeroX.tradeAsset(Object.assign(Object.assign({}, mockZeroExQuoteV2Request), { fromAddress: mockEip155Address, zeroXApiKey: 'params-only' }), {
230
+ signAndSendTransaction: () => __awaiter(void 0, void 0, void 0, function* () { return '0xh'; }),
231
+ waitForConfirmation: () => __awaiter(void 0, void 0, void 0, function* () { return true; }),
232
+ });
233
+ expect(spy).toHaveBeenCalledWith(expect.any(Object), expect.objectContaining({ zeroXApiKey: 'params-only' }));
234
+ }));
235
+ it('normalizes numeric chainId to eip155 for signer', () => __awaiter(void 0, void 0, void 0, function* () {
236
+ const sign = jest.fn().mockResolvedValue('0xh');
237
+ jest.spyOn(mpc, 'getSwapsQuoteV2').mockResolvedValue(Object.assign({}, mockZeroExQuoteV2Response));
238
+ yield zeroX.tradeAsset(Object.assign(Object.assign({}, mockZeroExQuoteV2Request), { chainId: '1', fromAddress: mockEip155Address }), {
239
+ signAndSendTransaction: sign,
240
+ waitForConfirmation: () => __awaiter(void 0, void 0, void 0, function* () { return true; }),
241
+ });
242
+ expect(sign).toHaveBeenCalledWith(expect.anything(), 'eip155:1');
243
+ }));
244
+ });
106
245
  });
@@ -1,10 +1,24 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
1
12
  import YieldXyz from './yieldxyz';
2
13
  /**
3
- * This class is a container for the YieldXyz class.
4
- * In the future, Yield domain logic should be here.
14
+ * Yield integrations (Yield.xyz, etc.).
5
15
  */
6
16
  export default class Yield {
7
- constructor({ mpc }) {
8
- this.yieldXyz = new YieldXyz({ mpc });
17
+ constructor(_a) {
18
+ var { mpc } = _a, rest = __rest(_a, ["mpc"]);
19
+ this.yieldXyz = new YieldXyz(Object.assign({ mpc }, rest));
20
+ }
21
+ getValidators(yieldId) {
22
+ return this.yieldXyz.getValidators(yieldId);
9
23
  }
10
24
  }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * @jest-environment jsdom
3
+ */
4
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
5
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
6
+ return new (P || (P = Promise))(function (resolve, reject) {
7
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
8
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
9
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
10
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
11
+ });
12
+ };
13
+ import YieldXyz from './yieldxyz';
14
+ import Mpc from '../../mpc';
15
+ import portalMock from '../../__mocks/portal/portal';
16
+ import { mockHost } from '../../__mocks/constants';
17
+ describe('YieldXyz getValidators', () => {
18
+ let mpc;
19
+ let yieldXyz;
20
+ beforeEach(() => {
21
+ jest.clearAllMocks();
22
+ portalMock.host = mockHost;
23
+ mpc = new Mpc({ portal: portalMock });
24
+ yieldXyz = new YieldXyz({ mpc });
25
+ });
26
+ it('returns validators from data.validators', () => __awaiter(void 0, void 0, void 0, function* () {
27
+ const v = [{ address: '0x1', name: 'v1' }];
28
+ jest.spyOn(mpc, 'getYieldXyzValidators').mockResolvedValue({
29
+ data: { validators: v },
30
+ });
31
+ yield expect(yieldXyz.getValidators('y1')).resolves.toEqual(v);
32
+ }));
33
+ it('falls back to data.rawResponse.validators', () => __awaiter(void 0, void 0, void 0, function* () {
34
+ const v = [{ address: '0x2' }];
35
+ jest.spyOn(mpc, 'getYieldXyzValidators').mockResolvedValue({
36
+ data: { rawResponse: { validators: v } },
37
+ });
38
+ yield expect(yieldXyz.getValidators('y1')).resolves.toEqual(v);
39
+ }));
40
+ it('falls back to data.rawResponse.items', () => __awaiter(void 0, void 0, void 0, function* () {
41
+ const v = [{ address: '0x3' }];
42
+ jest.spyOn(mpc, 'getYieldXyzValidators').mockResolvedValue({
43
+ data: { rawResponse: { items: v, total: 1 } },
44
+ });
45
+ yield expect(yieldXyz.getValidators('y1')).resolves.toEqual(v);
46
+ }));
47
+ it('returns empty array when validators is empty (valid)', () => __awaiter(void 0, void 0, void 0, function* () {
48
+ jest.spyOn(mpc, 'getYieldXyzValidators').mockResolvedValue({
49
+ data: { validators: [] },
50
+ });
51
+ yield expect(yieldXyz.getValidators('y1')).resolves.toEqual([]);
52
+ }));
53
+ it('throws on res.error', () => __awaiter(void 0, void 0, void 0, function* () {
54
+ jest.spyOn(mpc, 'getYieldXyzValidators').mockResolvedValue({
55
+ error: 'not found',
56
+ data: { validators: [{ address: 'x' }] },
57
+ });
58
+ yield expect(yieldXyz.getValidators('y1')).rejects.toThrow('[YieldXyz] getValidators failed: not found');
59
+ }));
60
+ it('throws when no validators array in response', () => __awaiter(void 0, void 0, void 0, function* () {
61
+ jest.spyOn(mpc, 'getYieldXyzValidators').mockResolvedValue({
62
+ data: { rawResponse: {} },
63
+ });
64
+ yield expect(yieldXyz.getValidators('y1')).rejects.toThrow('No validators in response');
65
+ }));
66
+ });