@morpho-org/bundler-sdk-viem 4.1.4 → 4.3.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 (48) hide show
  1. package/lib/{actions.js → cjs/actions.js} +3 -0
  2. package/lib/cjs/package.json +1 -0
  3. package/lib/esm/ActionBundle.d.ts +37 -0
  4. package/lib/esm/ActionBundle.js +35 -0
  5. package/lib/esm/BundlerAction.d.ts +470 -0
  6. package/lib/esm/BundlerAction.js +1657 -0
  7. package/lib/esm/abis.d.ts +3014 -0
  8. package/lib/esm/abis.js +2047 -0
  9. package/lib/esm/actions.d.ts +10 -0
  10. package/lib/esm/actions.js +793 -0
  11. package/lib/esm/bundle.d.ts +12 -0
  12. package/lib/esm/bundle.js +11 -0
  13. package/lib/esm/errors.d.ts +30 -0
  14. package/lib/esm/errors.js +54 -0
  15. package/lib/esm/index.d.ts +8 -0
  16. package/lib/esm/index.js +8 -0
  17. package/lib/esm/operations.d.ts +78 -0
  18. package/lib/esm/operations.js +800 -0
  19. package/lib/esm/package.json +1 -0
  20. package/lib/esm/types/actions.d.ts +355 -0
  21. package/lib/esm/types/actions.js +1 -0
  22. package/lib/esm/types/index.d.ts +2 -0
  23. package/lib/esm/types/index.js +2 -0
  24. package/lib/esm/types/operations.d.ts +86 -0
  25. package/lib/esm/types/operations.js +55 -0
  26. package/package.json +25 -16
  27. package/src/index.ts +8 -0
  28. /package/lib/{ActionBundle.d.ts → cjs/ActionBundle.d.ts} +0 -0
  29. /package/lib/{ActionBundle.js → cjs/ActionBundle.js} +0 -0
  30. /package/lib/{BundlerAction.d.ts → cjs/BundlerAction.d.ts} +0 -0
  31. /package/lib/{BundlerAction.js → cjs/BundlerAction.js} +0 -0
  32. /package/lib/{abis.d.ts → cjs/abis.d.ts} +0 -0
  33. /package/lib/{abis.js → cjs/abis.js} +0 -0
  34. /package/lib/{actions.d.ts → cjs/actions.d.ts} +0 -0
  35. /package/lib/{bundle.d.ts → cjs/bundle.d.ts} +0 -0
  36. /package/lib/{bundle.js → cjs/bundle.js} +0 -0
  37. /package/lib/{errors.d.ts → cjs/errors.d.ts} +0 -0
  38. /package/lib/{errors.js → cjs/errors.js} +0 -0
  39. /package/lib/{index.d.ts → cjs/index.d.ts} +0 -0
  40. /package/lib/{index.js → cjs/index.js} +0 -0
  41. /package/lib/{operations.d.ts → cjs/operations.d.ts} +0 -0
  42. /package/lib/{operations.js → cjs/operations.js} +0 -0
  43. /package/lib/{types → cjs/types}/actions.d.ts +0 -0
  44. /package/lib/{types → cjs/types}/actions.js +0 -0
  45. /package/lib/{types → cjs/types}/index.d.ts +0 -0
  46. /package/lib/{types → cjs/types}/index.js +0 -0
  47. /package/lib/{types → cjs/types}/operations.d.ts +0 -0
  48. /package/lib/{types → cjs/types}/operations.js +0 -0
@@ -0,0 +1,793 @@
1
+ import { encodeFunctionData, erc20Abi, hexToBigInt, maxUint256, slice, verifyTypedData, zeroAddress, } from "viem";
2
+ import { DEFAULT_SLIPPAGE_TOLERANCE, MathLib, NATIVE_ADDRESS, convexWrapperTokens, erc20WrapperTokens, getChainAddresses, getUnwrappedToken, } from "@morpho-org/blue-sdk";
3
+ import { Time, getValue } from "@morpho-org/morpho-ts";
4
+ import { APPROVE_ONLY_ONCE_TOKENS, MAX_TOKEN_APPROVALS, getCurrent, simulateOperation, } from "@morpho-org/simulation-sdk";
5
+ import { blueAbi, getAuthorizationTypedData, getDaiPermitTypedData, getPermit2PermitTypedData, getPermitTypedData, } from "@morpho-org/blue-sdk-viem";
6
+ import { signTypedData } from "viem/actions";
7
+ import { ActionBundle, ActionBundleRequirements } from "./ActionBundle.js";
8
+ import { BundlerErrors } from "./errors.js";
9
+ export const MAX_ABSOLUTE_SHARE_PRICE = 100n * MathLib.RAY;
10
+ const encodeErc20Approval = (token, spender, amount, data) => {
11
+ const { chainId } = data;
12
+ amount = MathLib.min(amount, MAX_TOKEN_APPROVALS[chainId]?.[token] ?? maxUint256);
13
+ const txRequirements = [];
14
+ txRequirements.push({
15
+ type: "erc20Approve",
16
+ args: [token, spender, amount],
17
+ tx: {
18
+ to: token,
19
+ data: encodeFunctionData({
20
+ abi: erc20Abi,
21
+ functionName: "approve",
22
+ args: [spender, amount],
23
+ }),
24
+ },
25
+ });
26
+ return txRequirements;
27
+ };
28
+ export const encodeOperation = (operation, dataBefore, supportsSignature = true, index = 0) => {
29
+ const { chainId } = dataBefore;
30
+ const { morpho, bundler3: { bundler3, generalAdapter1, paraswapAdapter }, permit2, wNative, dai, wstEth, stEth, } = getChainAddresses(chainId);
31
+ const actions = [];
32
+ const requirements = new ActionBundleRequirements();
33
+ let callbackBundle;
34
+ const callback = getValue(operation.args, "callback");
35
+ const simulatedOperation = {
36
+ ...operation,
37
+ args: {
38
+ ...operation.args,
39
+ ...(callback && {
40
+ callback: (dataBefore) => {
41
+ callbackBundle = encodeBundle(callback.map((callbackOperation) => ({
42
+ ...callbackOperation,
43
+ // Inside a callback, the sender is forced to be the generalAdapter1.
44
+ sender: generalAdapter1,
45
+ })), getCurrent(dataBefore), supportsSignature);
46
+ return callback;
47
+ },
48
+ }),
49
+ },
50
+ };
51
+ // Operations with callbacks are encoded recursively as a side-effect of the simulation, within the callback itself.
52
+ const dataAfter = simulateOperation(simulatedOperation, dataBefore, index);
53
+ if (callbackBundle) {
54
+ requirements.txs.push(...callbackBundle.requirements.txs);
55
+ requirements.signatures.push(...callbackBundle.requirements.signatures);
56
+ }
57
+ const { sender } = operation;
58
+ switch (operation.type) {
59
+ case "Blue_SetAuthorization": {
60
+ const { owner, isAuthorized, authorized, deadline = dataBefore.block.timestamp + Time.s.from.h(2n), } = operation.args;
61
+ // Never authorize bundler3 otherwise the signature can be used independently.
62
+ if (authorized === bundler3)
63
+ throw new BundlerErrors.UnexpectedSignature(authorized);
64
+ if (supportsSignature) {
65
+ const ownerData = dataBefore.getUser(owner);
66
+ const authorization = {
67
+ authorizer: owner,
68
+ authorized,
69
+ isAuthorized,
70
+ deadline,
71
+ nonce: ownerData.morphoNonce,
72
+ };
73
+ const action = {
74
+ type: "morphoSetAuthorizationWithSig",
75
+ args: [authorization, null, operation.skipRevert],
76
+ };
77
+ actions.push(action);
78
+ requirements.signatures.push({
79
+ action,
80
+ async sign(client, account = client.account) {
81
+ let signature = action.args[1];
82
+ if (signature != null)
83
+ return signature;
84
+ const typedData = getAuthorizationTypedData(authorization, chainId);
85
+ signature = await signTypedData(client, {
86
+ ...typedData,
87
+ account,
88
+ });
89
+ await verifyTypedData({
90
+ ...typedData,
91
+ address: owner, // Verify against the authorization's owner.
92
+ signature,
93
+ });
94
+ return (action.args[1] = signature);
95
+ },
96
+ });
97
+ break;
98
+ }
99
+ // Signatures are not supported, fallback to standard approval.
100
+ requirements.txs.push({
101
+ type: "morphoSetAuthorization",
102
+ args: [authorized, isAuthorized],
103
+ tx: {
104
+ to: morpho,
105
+ data: encodeFunctionData({
106
+ abi: blueAbi,
107
+ functionName: "setAuthorization",
108
+ args: [authorized, isAuthorized],
109
+ }),
110
+ },
111
+ });
112
+ break;
113
+ }
114
+ case "Erc20_Approve": {
115
+ // Native token cannot be approved.
116
+ if (operation.address === NATIVE_ADDRESS)
117
+ break;
118
+ const { amount, spender } = operation.args;
119
+ // Signatures are not supported, skip Permit2 approval.
120
+ if (!supportsSignature && spender === permit2)
121
+ break;
122
+ requirements.txs.push(...encodeErc20Approval(operation.address, spender, amount, dataBefore));
123
+ break;
124
+ }
125
+ case "Erc20_Permit": {
126
+ // Native token cannot be permitted.
127
+ if (operation.address === NATIVE_ADDRESS)
128
+ break;
129
+ const { amount, spender, nonce, deadline = dataBefore.block.timestamp + Time.s.from.h(2n), } = operation.args;
130
+ // Never permit any other address than the GeneralAdapter1 otherwise
131
+ // the signature can be used independently.
132
+ if (spender !== generalAdapter1)
133
+ throw new BundlerErrors.UnexpectedSignature(spender);
134
+ const isDai = dai != null && operation.address === dai;
135
+ if (supportsSignature) {
136
+ const action = isDai
137
+ ? {
138
+ type: "permitDai",
139
+ args: [
140
+ sender,
141
+ nonce,
142
+ deadline,
143
+ amount > 0n,
144
+ null,
145
+ operation.skipRevert,
146
+ ],
147
+ }
148
+ : {
149
+ type: "permit",
150
+ args: [
151
+ sender,
152
+ operation.address,
153
+ amount,
154
+ deadline,
155
+ null,
156
+ operation.skipRevert,
157
+ ],
158
+ };
159
+ actions.push(action);
160
+ const tokenData = dataBefore.getToken(operation.address);
161
+ requirements.signatures.push({
162
+ action,
163
+ async sign(client, account = client.account) {
164
+ let signature = action.args[4];
165
+ if (signature != null)
166
+ return signature; // action is already signed
167
+ if (isDai) {
168
+ const typedData = getDaiPermitTypedData({
169
+ owner: sender,
170
+ spender,
171
+ allowance: amount,
172
+ nonce,
173
+ deadline,
174
+ }, chainId);
175
+ signature = await signTypedData(client, {
176
+ ...typedData,
177
+ account,
178
+ });
179
+ await verifyTypedData({
180
+ ...typedData,
181
+ address: account.address,
182
+ signature,
183
+ });
184
+ }
185
+ else {
186
+ const typedData = getPermitTypedData({
187
+ erc20: tokenData,
188
+ owner: sender,
189
+ spender,
190
+ allowance: amount,
191
+ nonce,
192
+ deadline,
193
+ }, chainId);
194
+ signature = await signTypedData(client, {
195
+ ...typedData,
196
+ account,
197
+ });
198
+ await verifyTypedData({
199
+ ...typedData,
200
+ address: sender, // Verify against the permit's owner.
201
+ signature,
202
+ });
203
+ }
204
+ return (action.args[4] = signature);
205
+ },
206
+ });
207
+ break;
208
+ }
209
+ // Simple permit is not supported, fallback to standard approval.
210
+ // Ignore DAI-specific zero permits used to reset allowances at the end of a bundle
211
+ // when the signer does not support signatures, as they cannot be bundled.
212
+ if (amount > 0n || !isDai)
213
+ requirements.txs.push(...encodeErc20Approval(operation.address, spender, amount, dataBefore));
214
+ break;
215
+ }
216
+ case "Erc20_Permit2": {
217
+ // Native token cannot be permitted.
218
+ if (operation.address === NATIVE_ADDRESS)
219
+ break;
220
+ const { amount, expiration, nonce, deadline = dataBefore.block.timestamp + Time.s.from.h(2n), } = operation.args;
221
+ if (supportsSignature) {
222
+ const action = {
223
+ type: "approve2",
224
+ args: [
225
+ sender,
226
+ {
227
+ details: {
228
+ token: operation.address,
229
+ amount,
230
+ nonce: Number(nonce),
231
+ expiration: Number(expiration),
232
+ },
233
+ sigDeadline: deadline,
234
+ },
235
+ null,
236
+ operation.skipRevert,
237
+ ],
238
+ };
239
+ actions.push(action);
240
+ requirements.signatures.push({
241
+ action,
242
+ async sign(client, account = client.account) {
243
+ const { details, sigDeadline } = action.args[1];
244
+ let signature = action.args[2];
245
+ if (signature != null)
246
+ return signature; // action is already signed
247
+ const typedData = getPermit2PermitTypedData({
248
+ // Never permit any other address than the GeneralAdapter1 otherwise
249
+ // the signature can be used independently.
250
+ spender: generalAdapter1,
251
+ allowance: details.amount,
252
+ erc20: details.token,
253
+ nonce: details.nonce,
254
+ deadline: sigDeadline,
255
+ expiration: details.expiration,
256
+ }, chainId);
257
+ signature = await signTypedData(client, {
258
+ ...typedData,
259
+ account,
260
+ });
261
+ await verifyTypedData({
262
+ ...typedData,
263
+ address: sender, // Verify against the permit's owner.
264
+ signature,
265
+ });
266
+ return (action.args[2] = signature);
267
+ },
268
+ });
269
+ break;
270
+ }
271
+ // Signatures are not supported, fallback to standard approval.
272
+ if (APPROVE_ONLY_ONCE_TOKENS[dataBefore.chainId]?.includes(operation.address) &&
273
+ dataBefore.getHolding(sender, operation.address).erc20Allowances["bundler3.generalAdapter1"] > 0n)
274
+ requirements.txs.push(...encodeErc20Approval(operation.address, generalAdapter1, 0n, dataBefore));
275
+ requirements.txs.push(...encodeErc20Approval(operation.address, generalAdapter1, amount, dataBefore));
276
+ break;
277
+ }
278
+ case "Erc20_Transfer": {
279
+ const { amount, from, to } = operation.args;
280
+ if (operation.address === NATIVE_ADDRESS) {
281
+ actions.push({
282
+ type: "nativeTransfer",
283
+ args: [from, to, amount, operation.skipRevert],
284
+ });
285
+ break;
286
+ }
287
+ // Output transfer from the bundler.
288
+ if (from === generalAdapter1) {
289
+ actions.push({
290
+ type: "erc20Transfer",
291
+ args: [
292
+ operation.address,
293
+ to,
294
+ amount,
295
+ generalAdapter1,
296
+ operation.skipRevert,
297
+ ],
298
+ });
299
+ break;
300
+ }
301
+ actions.push({
302
+ type: "erc20TransferFrom",
303
+ args: [operation.address, amount, to, operation.skipRevert],
304
+ });
305
+ break;
306
+ }
307
+ case "Erc20_Transfer2": {
308
+ const { amount, to } = operation.args;
309
+ if (supportsSignature) {
310
+ actions.push({
311
+ type: "transferFrom2",
312
+ args: [operation.address, amount, to, operation.skipRevert],
313
+ });
314
+ break;
315
+ }
316
+ // Signatures are not supported, fallback to standard transfer.
317
+ actions.push({
318
+ type: "erc20TransferFrom",
319
+ args: [operation.address, amount, to, operation.skipRevert],
320
+ });
321
+ break;
322
+ }
323
+ case "Erc20_Wrap": {
324
+ const { amount, owner } = operation.args;
325
+ switch (operation.address) {
326
+ case wNative: {
327
+ actions.push({
328
+ type: "wrapNative",
329
+ args: [amount, owner, operation.skipRevert],
330
+ });
331
+ break;
332
+ }
333
+ case wstEth: {
334
+ actions.push({
335
+ type: "wrapStEth",
336
+ args: [amount, owner, operation.skipRevert],
337
+ });
338
+ break;
339
+ }
340
+ case stEth: {
341
+ actions.push({
342
+ type: "stakeEth",
343
+ args: [
344
+ amount,
345
+ MathLib.MAX_UINT_256,
346
+ zeroAddress,
347
+ owner,
348
+ operation.skipRevert,
349
+ ],
350
+ });
351
+ break;
352
+ }
353
+ default: {
354
+ if (erc20WrapperTokens[chainId]?.has(operation.address)) {
355
+ const underlying = getUnwrappedToken(operation.address, chainId);
356
+ if (underlying == null)
357
+ throw Error(`unknown wrapped token: ${operation.address}`);
358
+ actions.push({
359
+ type: "erc20WrapperDepositFor",
360
+ args: [
361
+ operation.address,
362
+ underlying,
363
+ amount,
364
+ operation.skipRevert,
365
+ ],
366
+ });
367
+ break;
368
+ }
369
+ // Convex token wrapping is executed onchain along with supplyCollateral, via depositFor.
370
+ if (!convexWrapperTokens[chainId]?.has(operation.address))
371
+ throw Error(`unexpected token wrap: ${operation.address}`);
372
+ }
373
+ }
374
+ break;
375
+ }
376
+ case "Erc20_Unwrap": {
377
+ const { amount, receiver } = operation.args;
378
+ switch (operation.address) {
379
+ case wNative: {
380
+ actions.push({
381
+ type: "unwrapNative",
382
+ args: [amount, receiver, operation.skipRevert],
383
+ });
384
+ break;
385
+ }
386
+ case wstEth: {
387
+ actions.push({
388
+ type: "unwrapStEth",
389
+ args: [amount, receiver, operation.skipRevert],
390
+ });
391
+ break;
392
+ }
393
+ default: {
394
+ if (!erc20WrapperTokens[chainId]?.has(operation.address))
395
+ throw Error(`unexpected token unwrap: ${operation.address}`);
396
+ actions.push({
397
+ type: "erc20WrapperWithdrawTo",
398
+ args: [operation.address, receiver, amount, operation.skipRevert],
399
+ });
400
+ }
401
+ }
402
+ break;
403
+ }
404
+ case "Blue_Supply": {
405
+ const { id, assets = 0n, shares = 0n, onBehalf, slippage = DEFAULT_SLIPPAGE_TOLERANCE, } = operation.args;
406
+ // Accrue interest to calculate the expected share price.
407
+ const market = dataBefore
408
+ .getMarket(id)
409
+ .accrueInterest(dataBefore.block.timestamp);
410
+ const { assets: suppliedAssets, shares: suppliedShares } = market.supply(assets, shares);
411
+ const maxSharePrice = MathLib.min(MathLib.mulDivUp(suppliedAssets, MathLib.wToRay(MathLib.WAD + slippage), suppliedShares), MAX_ABSOLUTE_SHARE_PRICE);
412
+ actions.push({
413
+ type: "morphoSupply",
414
+ args: [
415
+ // Avoid passing the reference of a revokable proxy that would fail
416
+ // accessing its underlying value after revocation.
417
+ getCurrent(market.params),
418
+ assets,
419
+ shares,
420
+ maxSharePrice,
421
+ onBehalf,
422
+ callbackBundle?.actions ?? [],
423
+ operation.skipRevert,
424
+ ],
425
+ });
426
+ break;
427
+ }
428
+ case "Blue_Withdraw": {
429
+ const { id, assets = 0n, shares = 0n, receiver, slippage = DEFAULT_SLIPPAGE_TOLERANCE, } = operation.args;
430
+ // Accrue interest to calculate the expected share price.
431
+ const market = dataBefore
432
+ .getMarket(id)
433
+ .accrueInterest(dataBefore.block.timestamp);
434
+ const { assets: withdrawnAssets, shares: withdrawnShares } = market.withdraw(assets, shares);
435
+ const minSharePrice = MathLib.mulDivDown(withdrawnAssets, MathLib.wToRay(MathLib.WAD - slippage), withdrawnShares);
436
+ actions.push({
437
+ type: "morphoWithdraw",
438
+ args: [
439
+ // Avoid passing the reference of a revokable proxy that would fail
440
+ // accessing its underlying value after revocation.
441
+ getCurrent(market.params),
442
+ assets,
443
+ shares,
444
+ minSharePrice,
445
+ receiver,
446
+ operation.skipRevert,
447
+ ],
448
+ });
449
+ break;
450
+ }
451
+ case "Blue_Borrow": {
452
+ const { id, assets = 0n, shares = 0n, receiver, slippage = DEFAULT_SLIPPAGE_TOLERANCE, } = operation.args;
453
+ // Accrue interest to calculate the expected share price.
454
+ const market = dataBefore
455
+ .getMarket(id)
456
+ .accrueInterest(dataBefore.block.timestamp);
457
+ const { assets: borrowedAssets, shares: borrowedShares } = market.borrow(assets, shares);
458
+ const minSharePrice = MathLib.mulDivDown(borrowedAssets, MathLib.wToRay(MathLib.WAD - slippage), borrowedShares);
459
+ actions.push({
460
+ type: "morphoBorrow",
461
+ args: [
462
+ // Avoid passing the reference of a revokable proxy that would fail
463
+ // accessing its underlying value after revocation.
464
+ getCurrent(market.params),
465
+ assets,
466
+ shares,
467
+ minSharePrice,
468
+ receiver,
469
+ operation.skipRevert,
470
+ ],
471
+ });
472
+ break;
473
+ }
474
+ case "Blue_Repay": {
475
+ const { id, assets = 0n, shares = 0n, onBehalf, slippage = DEFAULT_SLIPPAGE_TOLERANCE, } = operation.args;
476
+ // Accrue interest to calculate the expected share price.
477
+ const market = dataBefore
478
+ .getMarket(id)
479
+ .accrueInterest(dataBefore.block.timestamp);
480
+ const { assets: repaidAssets, shares: repaidShares } = market.repay(assets, shares);
481
+ const maxSharePrice = MathLib.min(MathLib.mulDivUp(repaidAssets, MathLib.wToRay(MathLib.WAD + slippage), repaidShares), MAX_ABSOLUTE_SHARE_PRICE);
482
+ actions.push({
483
+ type: "morphoRepay",
484
+ args: [
485
+ // Avoid passing the reference of a revokable proxy that would fail
486
+ // accessing its underlying value after revocation.
487
+ getCurrent(market.params),
488
+ assets,
489
+ shares,
490
+ maxSharePrice,
491
+ onBehalf,
492
+ callbackBundle?.actions ?? [],
493
+ operation.skipRevert,
494
+ ],
495
+ });
496
+ break;
497
+ }
498
+ case "Blue_SupplyCollateral": {
499
+ const { id, assets, onBehalf } = operation.args;
500
+ const { params } = dataBefore.getMarket(id);
501
+ if (convexWrapperTokens[chainId]?.has(params.collateralToken)) {
502
+ const underlying = getUnwrappedToken(params.collateralToken, chainId);
503
+ if (underlying == null)
504
+ throw Error(`unknown wrapped token: ${params.collateralToken}`);
505
+ actions.push({
506
+ type: "erc20WrapperDepositFor",
507
+ args: [
508
+ params.collateralToken,
509
+ underlying,
510
+ assets,
511
+ operation.skipRevert,
512
+ ],
513
+ });
514
+ break;
515
+ }
516
+ actions.push({
517
+ type: "morphoSupplyCollateral",
518
+ args: [
519
+ // Avoid passing the reference of a revokable proxy that would fail
520
+ // accessing its underlying value after revocation.
521
+ getCurrent(params),
522
+ assets,
523
+ onBehalf,
524
+ callbackBundle?.actions ?? [],
525
+ operation.skipRevert,
526
+ ],
527
+ });
528
+ break;
529
+ }
530
+ case "Blue_WithdrawCollateral": {
531
+ const { id, assets, receiver } = operation.args;
532
+ const { params } = dataBefore.getMarket(id);
533
+ actions.push({
534
+ type: "morphoWithdrawCollateral",
535
+ args: [
536
+ // Avoid passing the reference of a revokable proxy that would fail
537
+ // accessing its underlying value after revocation.
538
+ getCurrent(params),
539
+ assets,
540
+ receiver,
541
+ operation.skipRevert,
542
+ ],
543
+ });
544
+ break;
545
+ }
546
+ case "MetaMorpho_Deposit": {
547
+ const { assets = 0n, shares = 0n, owner, slippage = DEFAULT_SLIPPAGE_TOLERANCE, } = operation.args;
548
+ // Accrue interest to calculate the expected share price.
549
+ const vault = dataBefore
550
+ .getAccrualVault(operation.address)
551
+ .accrueInterest(dataBefore.block.timestamp);
552
+ if (shares === 0n) {
553
+ const maxSharePrice = MathLib.min(MathLib.mulDivUp(assets, MathLib.wToRay(MathLib.WAD + slippage), vault.toShares(assets, "Down")), MAX_ABSOLUTE_SHARE_PRICE);
554
+ actions.push({
555
+ type: "erc4626Deposit",
556
+ args: [
557
+ operation.address,
558
+ assets,
559
+ maxSharePrice,
560
+ owner,
561
+ operation.skipRevert,
562
+ ],
563
+ });
564
+ }
565
+ else {
566
+ const maxSharePrice = MathLib.min(MathLib.mulDivUp(vault.toAssets(shares, "Up"), MathLib.wToRay(MathLib.WAD + slippage), shares), MAX_ABSOLUTE_SHARE_PRICE);
567
+ actions.push({
568
+ type: "erc4626Mint",
569
+ args: [
570
+ operation.address,
571
+ shares,
572
+ maxSharePrice,
573
+ owner,
574
+ operation.skipRevert,
575
+ ],
576
+ });
577
+ }
578
+ break;
579
+ }
580
+ case "MetaMorpho_Withdraw": {
581
+ const { assets = 0n, shares = 0n, owner, receiver, slippage = DEFAULT_SLIPPAGE_TOLERANCE, } = operation.args;
582
+ // Accrue interest to calculate the expected share price.
583
+ const vault = dataBefore
584
+ .getAccrualVault(operation.address)
585
+ .accrueInterest(dataBefore.block.timestamp);
586
+ if (shares === 0n) {
587
+ const minSharePrice = MathLib.mulDivDown(assets, MathLib.wToRay(MathLib.WAD - slippage), vault.toShares(assets, "Up"));
588
+ actions.push({
589
+ type: "erc4626Withdraw",
590
+ args: [
591
+ operation.address,
592
+ assets,
593
+ minSharePrice,
594
+ receiver,
595
+ owner,
596
+ operation.skipRevert,
597
+ ],
598
+ });
599
+ }
600
+ else {
601
+ const minSharePrice = MathLib.mulDivDown(vault.toAssets(shares, "Down"), MathLib.wToRay(MathLib.WAD - slippage), shares);
602
+ actions.push({
603
+ type: "erc4626Redeem",
604
+ args: [
605
+ operation.address,
606
+ shares,
607
+ minSharePrice,
608
+ receiver,
609
+ owner,
610
+ operation.skipRevert,
611
+ ],
612
+ });
613
+ }
614
+ break;
615
+ }
616
+ case "MetaMorpho_PublicReallocate": {
617
+ const { withdrawals, supplyMarketId } = operation.args;
618
+ const { fee } = dataBefore.getVault(operation.address)
619
+ .publicAllocatorConfig;
620
+ // Value is already accrued via another native input transfer.
621
+ actions.push({
622
+ type: "reallocateTo",
623
+ args: [
624
+ operation.address,
625
+ fee,
626
+ withdrawals.map(({ id, assets }) => ({
627
+ // Avoid passing the reference of a revokable proxy that would fail
628
+ // accessing its underlying value after revocation.
629
+ marketParams: getCurrent(dataBefore.getMarket(id).params),
630
+ amount: assets,
631
+ })),
632
+ // Avoid passing the reference of a revokable proxy that would fail
633
+ // accessing its underlying value after revocation.
634
+ getCurrent(dataBefore.getMarket(supplyMarketId).params),
635
+ operation.skipRevert,
636
+ ],
637
+ });
638
+ break;
639
+ }
640
+ case "Blue_FlashLoan": {
641
+ const { token, assets } = operation.args;
642
+ actions.push({
643
+ type: "morphoFlashLoan",
644
+ args: [
645
+ token,
646
+ assets,
647
+ callbackBundle?.actions ?? [],
648
+ operation.skipRevert,
649
+ ],
650
+ });
651
+ break;
652
+ }
653
+ case "Paraswap_Buy": {
654
+ if (!("swap" in operation.args))
655
+ throw new BundlerErrors.MissingSwapData();
656
+ if (paraswapAdapter == null)
657
+ throw new BundlerErrors.UnexpectedAction("paraswapBuy", chainId);
658
+ const { srcToken, swap, receiver } = operation.args;
659
+ const limitAmountOffset = Number(swap.offsets.limitAmount);
660
+ const limitAmount = hexToBigInt(slice(swap.data, limitAmountOffset, limitAmountOffset + 32));
661
+ actions.push({
662
+ type: "erc20Transfer",
663
+ args: [
664
+ srcToken,
665
+ paraswapAdapter,
666
+ limitAmount,
667
+ generalAdapter1,
668
+ operation.skipRevert,
669
+ ],
670
+ }, {
671
+ type: "paraswapBuy",
672
+ args: [
673
+ swap.to,
674
+ swap.data,
675
+ srcToken,
676
+ operation.address,
677
+ swap.offsets,
678
+ receiver === paraswapAdapter ? generalAdapter1 : receiver,
679
+ operation.skipRevert,
680
+ ],
681
+ }, {
682
+ type: "erc20Transfer",
683
+ args: [
684
+ srcToken,
685
+ generalAdapter1,
686
+ maxUint256,
687
+ paraswapAdapter,
688
+ operation.skipRevert,
689
+ ],
690
+ });
691
+ break;
692
+ }
693
+ case "Paraswap_Sell": {
694
+ if (!("swap" in operation.args))
695
+ throw new BundlerErrors.MissingSwapData();
696
+ if (paraswapAdapter == null)
697
+ throw new BundlerErrors.UnexpectedAction("paraswapBuy", chainId);
698
+ const { dstToken, swap, sellEntireBalance = false, receiver, } = operation.args;
699
+ const exactAmountOffset = Number(swap.offsets.exactAmount);
700
+ const exactAmount = hexToBigInt(slice(swap.data, exactAmountOffset, exactAmountOffset + 32));
701
+ actions.push({
702
+ type: "erc20Transfer",
703
+ args: [
704
+ operation.address,
705
+ paraswapAdapter,
706
+ sellEntireBalance ? maxUint256 : exactAmount,
707
+ generalAdapter1,
708
+ operation.skipRevert,
709
+ ],
710
+ }, {
711
+ type: "paraswapSell",
712
+ args: [
713
+ swap.to,
714
+ swap.data,
715
+ operation.address,
716
+ dstToken,
717
+ sellEntireBalance,
718
+ swap.offsets,
719
+ receiver === paraswapAdapter ? generalAdapter1 : receiver,
720
+ operation.skipRevert,
721
+ ],
722
+ });
723
+ if (!sellEntireBalance)
724
+ actions.push({
725
+ type: "erc20Transfer",
726
+ args: [
727
+ operation.address,
728
+ generalAdapter1,
729
+ maxUint256,
730
+ paraswapAdapter,
731
+ operation.skipRevert,
732
+ ],
733
+ });
734
+ break;
735
+ }
736
+ case "Blue_Paraswap_BuyDebt": {
737
+ if (!("swap" in operation.args))
738
+ throw new BundlerErrors.MissingSwapData();
739
+ if (paraswapAdapter == null)
740
+ throw new BundlerErrors.UnexpectedAction("paraswapBuy", chainId);
741
+ const { srcToken, id, swap, onBehalf, receiver } = operation.args;
742
+ const { params } = dataBefore.getMarket(id);
743
+ actions.push({
744
+ type: "erc20Transfer",
745
+ args: [
746
+ srcToken,
747
+ paraswapAdapter,
748
+ maxUint256,
749
+ generalAdapter1,
750
+ operation.skipRevert,
751
+ ],
752
+ }, {
753
+ type: "paraswapBuyMorphoDebt",
754
+ args: [
755
+ swap.to,
756
+ swap.data,
757
+ srcToken,
758
+ params,
759
+ swap.offsets,
760
+ onBehalf,
761
+ receiver === paraswapAdapter ? generalAdapter1 : receiver,
762
+ operation.skipRevert,
763
+ ],
764
+ }, {
765
+ type: "erc20Transfer",
766
+ args: [
767
+ srcToken,
768
+ generalAdapter1,
769
+ maxUint256,
770
+ paraswapAdapter,
771
+ operation.skipRevert,
772
+ ],
773
+ });
774
+ break;
775
+ }
776
+ }
777
+ return {
778
+ dataAfter,
779
+ actions,
780
+ requirements,
781
+ };
782
+ };
783
+ export function encodeBundle(operations, startData, supportsSignature = true) {
784
+ const bundle = new ActionBundle([startData]);
785
+ for (let index = 0; index < operations.length; ++index) {
786
+ const { dataAfter, actions, requirements } = encodeOperation(operations[index], bundle.steps[index], supportsSignature, index);
787
+ bundle.steps.push(dataAfter);
788
+ bundle.actions.push(...actions);
789
+ bundle.requirements.signatures.push(...requirements.signatures);
790
+ bundle.requirements.txs.push(...requirements.txs);
791
+ }
792
+ return bundle;
793
+ }