@gearbox-protocol/sdk 14.12.0-next.23 → 14.12.0-next.25

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 (100) hide show
  1. package/dist/cjs/dev/withdrawalUtils.js +35 -28
  2. package/dist/cjs/plugins/adapters/contracts/AbstractAdapter.js +31 -9
  3. package/dist/cjs/plugins/adapters/contracts/AbstractCurveAdapter.js +8 -5
  4. package/dist/cjs/plugins/adapters/contracts/BalancerV3RouterAdapterContract.js +6 -4
  5. package/dist/cjs/plugins/adapters/contracts/BalancerV3WrapperAdapterContract.js +6 -4
  6. package/dist/cjs/plugins/adapters/contracts/CamelotV3AdapterContract.js +6 -9
  7. package/dist/cjs/plugins/adapters/contracts/ConvexV1BaseRewardPoolAdapterContract.js +7 -5
  8. package/dist/cjs/plugins/adapters/contracts/ConvexV1BoosterAdapterContract.js +6 -4
  9. package/dist/cjs/plugins/adapters/contracts/DaiUsdsAdapterContract.js +6 -4
  10. package/dist/cjs/plugins/adapters/contracts/ERC4626AdapterContract.js +13 -4
  11. package/dist/cjs/plugins/adapters/contracts/ERC4626ReferralAdapterContract.js +6 -4
  12. package/dist/cjs/plugins/adapters/contracts/FluidDexAdapterContract.js +8 -8
  13. package/dist/cjs/plugins/adapters/contracts/InfinifiGatewayAdapterContract.js +8 -5
  14. package/dist/cjs/plugins/adapters/contracts/KelpLRTDepositPoolAdapterContract.js +4 -3
  15. package/dist/cjs/plugins/adapters/contracts/LidoV1AdapterContract.js +4 -3
  16. package/dist/cjs/plugins/adapters/contracts/MellowClaimerAdapterContract.js +29 -0
  17. package/dist/cjs/plugins/adapters/contracts/MellowDVVAdapterContract.js +6 -4
  18. package/dist/cjs/plugins/adapters/contracts/MellowERC4626VaultAdapterContract.js +11 -4
  19. package/dist/cjs/plugins/adapters/contracts/MellowWrapperAdapterContract.js +4 -3
  20. package/dist/cjs/plugins/adapters/contracts/MidasGatewayAdapterContract.js +31 -4
  21. package/dist/cjs/plugins/adapters/contracts/MidasIssuanceVaultAdapterContract.js +4 -3
  22. package/dist/cjs/plugins/adapters/contracts/MidasRedemptionVaultAdapterContract.js +4 -3
  23. package/dist/cjs/plugins/adapters/contracts/PendleRouterAdapterContract.js +14 -16
  24. package/dist/cjs/plugins/adapters/contracts/SecuritizeOnRampAdapterContract.js +4 -3
  25. package/dist/cjs/plugins/adapters/contracts/SecuritizeRedemptionGatewayAdapterContract.js +14 -13
  26. package/dist/cjs/plugins/adapters/contracts/StakingRewardsAdapterContract.js +7 -5
  27. package/dist/cjs/plugins/adapters/contracts/TraderJoeRouterAdapterContract.js +4 -3
  28. package/dist/cjs/plugins/adapters/contracts/UniswapV2AdapterContract.js +4 -3
  29. package/dist/cjs/plugins/adapters/contracts/UniswapV3AdapterContract.js +6 -9
  30. package/dist/cjs/plugins/adapters/contracts/UniswapV4AdapterContract.js +8 -8
  31. package/dist/cjs/plugins/adapters/contracts/UpshiftVaultAdapterContract.js +6 -4
  32. package/dist/cjs/plugins/adapters/contracts/VelodromeV2AdapterContract.js +4 -3
  33. package/dist/cjs/plugins/adapters/contracts/WstETHV1AdapterContract.js +6 -4
  34. package/dist/esm/dev/withdrawalUtils.js +35 -28
  35. package/dist/esm/plugins/adapters/contracts/AbstractAdapter.js +31 -9
  36. package/dist/esm/plugins/adapters/contracts/AbstractCurveAdapter.js +8 -5
  37. package/dist/esm/plugins/adapters/contracts/BalancerV3RouterAdapterContract.js +6 -4
  38. package/dist/esm/plugins/adapters/contracts/BalancerV3WrapperAdapterContract.js +6 -4
  39. package/dist/esm/plugins/adapters/contracts/CamelotV3AdapterContract.js +6 -9
  40. package/dist/esm/plugins/adapters/contracts/ConvexV1BaseRewardPoolAdapterContract.js +7 -5
  41. package/dist/esm/plugins/adapters/contracts/ConvexV1BoosterAdapterContract.js +6 -4
  42. package/dist/esm/plugins/adapters/contracts/DaiUsdsAdapterContract.js +6 -4
  43. package/dist/esm/plugins/adapters/contracts/ERC4626AdapterContract.js +13 -4
  44. package/dist/esm/plugins/adapters/contracts/ERC4626ReferralAdapterContract.js +6 -4
  45. package/dist/esm/plugins/adapters/contracts/FluidDexAdapterContract.js +8 -8
  46. package/dist/esm/plugins/adapters/contracts/InfinifiGatewayAdapterContract.js +8 -5
  47. package/dist/esm/plugins/adapters/contracts/KelpLRTDepositPoolAdapterContract.js +4 -3
  48. package/dist/esm/plugins/adapters/contracts/LidoV1AdapterContract.js +4 -3
  49. package/dist/esm/plugins/adapters/contracts/MellowClaimerAdapterContract.js +32 -1
  50. package/dist/esm/plugins/adapters/contracts/MellowDVVAdapterContract.js +6 -4
  51. package/dist/esm/plugins/adapters/contracts/MellowERC4626VaultAdapterContract.js +11 -4
  52. package/dist/esm/plugins/adapters/contracts/MellowWrapperAdapterContract.js +4 -3
  53. package/dist/esm/plugins/adapters/contracts/MidasGatewayAdapterContract.js +33 -5
  54. package/dist/esm/plugins/adapters/contracts/MidasIssuanceVaultAdapterContract.js +4 -3
  55. package/dist/esm/plugins/adapters/contracts/MidasRedemptionVaultAdapterContract.js +4 -3
  56. package/dist/esm/plugins/adapters/contracts/PendleRouterAdapterContract.js +14 -16
  57. package/dist/esm/plugins/adapters/contracts/SecuritizeOnRampAdapterContract.js +4 -3
  58. package/dist/esm/plugins/adapters/contracts/SecuritizeRedemptionGatewayAdapterContract.js +14 -13
  59. package/dist/esm/plugins/adapters/contracts/StakingRewardsAdapterContract.js +7 -5
  60. package/dist/esm/plugins/adapters/contracts/TraderJoeRouterAdapterContract.js +4 -3
  61. package/dist/esm/plugins/adapters/contracts/UniswapV2AdapterContract.js +4 -3
  62. package/dist/esm/plugins/adapters/contracts/UniswapV3AdapterContract.js +6 -9
  63. package/dist/esm/plugins/adapters/contracts/UniswapV4AdapterContract.js +8 -8
  64. package/dist/esm/plugins/adapters/contracts/UpshiftVaultAdapterContract.js +6 -4
  65. package/dist/esm/plugins/adapters/contracts/VelodromeV2AdapterContract.js +4 -3
  66. package/dist/esm/plugins/adapters/contracts/WstETHV1AdapterContract.js +6 -4
  67. package/dist/types/plugins/adapters/contracts/AbstractAdapter.d.ts +27 -7
  68. package/dist/types/plugins/adapters/contracts/AbstractCurveAdapter.d.ts +2 -3
  69. package/dist/types/plugins/adapters/contracts/BalancerV3RouterAdapterContract.d.ts +2 -3
  70. package/dist/types/plugins/adapters/contracts/BalancerV3WrapperAdapterContract.d.ts +2 -3
  71. package/dist/types/plugins/adapters/contracts/CamelotV3AdapterContract.d.ts +2 -3
  72. package/dist/types/plugins/adapters/contracts/ConvexV1BaseRewardPoolAdapterContract.d.ts +2 -3
  73. package/dist/types/plugins/adapters/contracts/ConvexV1BoosterAdapterContract.d.ts +2 -3
  74. package/dist/types/plugins/adapters/contracts/DaiUsdsAdapterContract.d.ts +2 -3
  75. package/dist/types/plugins/adapters/contracts/ERC4626AdapterContract.d.ts +2 -3
  76. package/dist/types/plugins/adapters/contracts/ERC4626ReferralAdapterContract.d.ts +2 -3
  77. package/dist/types/plugins/adapters/contracts/FluidDexAdapterContract.d.ts +2 -3
  78. package/dist/types/plugins/adapters/contracts/InfinifiGatewayAdapterContract.d.ts +2 -3
  79. package/dist/types/plugins/adapters/contracts/KelpLRTDepositPoolAdapterContract.d.ts +2 -3
  80. package/dist/types/plugins/adapters/contracts/LidoV1AdapterContract.d.ts +2 -3
  81. package/dist/types/plugins/adapters/contracts/MellowClaimerAdapterContract.d.ts +3 -2
  82. package/dist/types/plugins/adapters/contracts/MellowDVVAdapterContract.d.ts +2 -3
  83. package/dist/types/plugins/adapters/contracts/MellowERC4626VaultAdapterContract.d.ts +2 -3
  84. package/dist/types/plugins/adapters/contracts/MellowWrapperAdapterContract.d.ts +2 -3
  85. package/dist/types/plugins/adapters/contracts/MidasGatewayAdapterContract.d.ts +2 -3
  86. package/dist/types/plugins/adapters/contracts/MidasIssuanceVaultAdapterContract.d.ts +2 -3
  87. package/dist/types/plugins/adapters/contracts/MidasRedemptionVaultAdapterContract.d.ts +2 -3
  88. package/dist/types/plugins/adapters/contracts/PendleRouterAdapterContract.d.ts +2 -3
  89. package/dist/types/plugins/adapters/contracts/SecuritizeOnRampAdapterContract.d.ts +2 -3
  90. package/dist/types/plugins/adapters/contracts/SecuritizeRedemptionGatewayAdapterContract.d.ts +2 -3
  91. package/dist/types/plugins/adapters/contracts/StakingRewardsAdapterContract.d.ts +2 -3
  92. package/dist/types/plugins/adapters/contracts/TraderJoeRouterAdapterContract.d.ts +2 -3
  93. package/dist/types/plugins/adapters/contracts/UniswapV2AdapterContract.d.ts +2 -3
  94. package/dist/types/plugins/adapters/contracts/UniswapV3AdapterContract.d.ts +2 -3
  95. package/dist/types/plugins/adapters/contracts/UniswapV4AdapterContract.d.ts +2 -3
  96. package/dist/types/plugins/adapters/contracts/UpshiftVaultAdapterContract.d.ts +2 -3
  97. package/dist/types/plugins/adapters/contracts/VelodromeV2AdapterContract.d.ts +2 -3
  98. package/dist/types/plugins/adapters/contracts/WstETHV1AdapterContract.d.ts +2 -3
  99. package/dist/types/plugins/adapters/types.d.ts +0 -10
  100. package/package.json +1 -1
@@ -97,21 +97,48 @@ class MidasGatewayAdapterContract extends import_AbstractAdapter.AbstractAdapter
97
97
  }))
98
98
  };
99
99
  }
100
- decodeDiffLeftovers(decoded, balances) {
100
+ applyBalanceChanges(balances, decoded) {
101
101
  switch (decoded.functionName) {
102
102
  case "depositInstantDiff": {
103
103
  const [tokenIn, leftoverAmount] = decoded.args;
104
- return [{ tokenIn, leftoverAmount }];
104
+ this.setLeftover(balances, tokenIn, leftoverAmount);
105
+ break;
105
106
  }
106
107
  // redemptions spend the mToken down to the leftover, tokenOut arg is
107
108
  // the received token
108
109
  case "redeemInstantDiff":
109
110
  case "redeemRequestDiff": {
110
111
  const [, leftoverAmount] = decoded.args;
111
- return [{ tokenIn: this.mToken, leftoverAmount }];
112
+ this.setLeftover(balances, this.mToken, leftoverAmount);
113
+ break;
114
+ }
115
+ // exact-input redemption request emitted in-bracket by the withdrawal
116
+ // compressor
117
+ case "redeemRequest": {
118
+ const [, amountMTokenIn] = decoded.args;
119
+ this.spendExact(balances, this.mToken, amountMTokenIn);
120
+ break;
121
+ }
122
+ // claim call emitted by the withdrawal compressor
123
+ case "withdrawFromRedeemer": {
124
+ const [, tokenOut, amount] = decoded.args;
125
+ const phantomToken = this.allowedOutputTokens.find(
126
+ (t) => (0, import_viem.isAddressEqual)(t.token, tokenOut)
127
+ )?.phantomToken;
128
+ if (!phantomToken) {
129
+ super.applyBalanceChanges(balances, decoded);
130
+ break;
131
+ }
132
+ this.spendExact(balances, phantomToken, amount);
133
+ break;
134
+ }
135
+ case "withdrawPhantomToken": {
136
+ const [token, amount] = decoded.args;
137
+ this.spendExact(balances, token, amount);
138
+ break;
112
139
  }
113
140
  default:
114
- return super.decodeDiffLeftovers(decoded, balances);
141
+ super.applyBalanceChanges(balances, decoded);
115
142
  }
116
143
  }
117
144
  }
@@ -72,14 +72,15 @@ class MidasIssuanceVaultAdapterContract extends import_AbstractAdapter.AbstractA
72
72
  allowedTokens: this.#allowedTokens?.map((t) => this.labelAddress(t))
73
73
  };
74
74
  }
75
- decodeDiffLeftovers(decoded, balances) {
75
+ applyBalanceChanges(balances, decoded) {
76
76
  switch (decoded.functionName) {
77
77
  case "depositInstantDiff": {
78
78
  const [tokenIn, leftoverAmount] = decoded.args;
79
- return [{ tokenIn, leftoverAmount }];
79
+ this.setLeftover(balances, tokenIn, leftoverAmount);
80
+ break;
80
81
  }
81
82
  default:
82
- return super.decodeDiffLeftovers(decoded, balances);
83
+ super.applyBalanceChanges(balances, decoded);
83
84
  }
84
85
  }
85
86
  }
@@ -77,16 +77,17 @@ class MidasRedemptionVaultAdapterContract extends import_AbstractAdapter.Abstrac
77
77
  }))
78
78
  };
79
79
  }
80
- decodeDiffLeftovers(decoded, balances) {
80
+ applyBalanceChanges(balances, decoded) {
81
81
  switch (decoded.functionName) {
82
82
  // redemption spends the mToken down to the leftover, tokenOut arg is
83
83
  // the received token
84
84
  case "redeemInstantDiff": {
85
85
  const [, leftoverAmount] = decoded.args;
86
- return [{ tokenIn: this.mToken, leftoverAmount }];
86
+ this.setLeftover(balances, this.mToken, leftoverAmount);
87
+ break;
87
88
  }
88
89
  default:
89
- return super.decodeDiffLeftovers(decoded, balances);
90
+ super.applyBalanceChanges(balances, decoded);
90
91
  }
91
92
  }
92
93
  }
@@ -117,27 +117,29 @@ class PendleRouterAdapterContract extends import_AbstractAdapter.AbstractAdapter
117
117
  }))
118
118
  };
119
119
  }
120
- decodeDiffLeftovers(decoded, balances) {
120
+ applyBalanceChanges(balances, decoded) {
121
121
  switch (decoded.functionName) {
122
122
  case "swapDiffTokenForPt":
123
123
  case "addLiquiditySingleTokenDiff": {
124
124
  const [, , , diffInput] = decoded.args;
125
- return [
126
- {
127
- tokenIn: diffInput.tokenIn,
128
- leftoverAmount: diffInput.leftoverTokenIn
129
- }
130
- ];
125
+ this.setLeftover(
126
+ balances,
127
+ diffInput.tokenIn,
128
+ diffInput.leftoverTokenIn
129
+ );
130
+ break;
131
131
  }
132
132
  case "swapDiffPtForToken": {
133
133
  const [market, leftoverPt] = decoded.args;
134
134
  const pt = this.#mustFindPendleToken(market, 0 /* PT */);
135
- return [{ tokenIn: pt, leftoverAmount: leftoverPt }];
135
+ this.setLeftover(balances, pt, leftoverPt);
136
+ break;
136
137
  }
137
138
  case "removeLiquiditySingleTokenDiff": {
138
139
  const [market, leftoverLp] = decoded.args;
139
140
  const lp = this.#mustFindPendleToken(market, 1 /* LP */);
140
- return [{ tokenIn: lp, leftoverAmount: leftoverLp }];
141
+ this.setLeftover(balances, lp, leftoverLp);
142
+ break;
141
143
  }
142
144
  case "redeemDiffPyToToken": {
143
145
  const candidates = this.allowedPairs.filter(
@@ -152,15 +154,11 @@ class PendleRouterAdapterContract extends import_AbstractAdapter.AbstractAdapter
152
154
  );
153
155
  }
154
156
  const [, leftoverPt] = decoded.args;
155
- return [
156
- {
157
- tokenIn: candidates[0].pendleToken,
158
- leftoverAmount: leftoverPt
159
- }
160
- ];
157
+ this.setLeftover(balances, candidates[0].pendleToken, leftoverPt);
158
+ break;
161
159
  }
162
160
  default:
163
- return super.decodeDiffLeftovers(decoded, balances);
161
+ super.applyBalanceChanges(balances, decoded);
164
162
  }
165
163
  }
166
164
  #mustFindPendleToken(market, type) {
@@ -64,15 +64,16 @@ class SecuritizeOnRampAdapterContract extends import_AbstractAdapter.AbstractAda
64
64
  liquidityToken: this.#liquidityToken ? this.labelAddress(this.#liquidityToken) : void 0
65
65
  };
66
66
  }
67
- decodeDiffLeftovers(decoded, balances) {
67
+ applyBalanceChanges(balances, decoded) {
68
68
  switch (decoded.functionName) {
69
69
  // swaps the liquidity token into dsToken
70
70
  case "swapDiff": {
71
71
  const [leftoverAmount] = decoded.args;
72
- return [{ tokenIn: this.liquidityToken, leftoverAmount }];
72
+ this.setLeftover(balances, this.liquidityToken, leftoverAmount);
73
+ break;
73
74
  }
74
75
  default:
75
- return super.decodeDiffLeftovers(decoded, balances);
76
+ super.applyBalanceChanges(balances, decoded);
76
77
  }
77
78
  }
78
79
  }
@@ -72,28 +72,29 @@ class SecuritizeRedemptionGatewayAdapterContract extends import_AbstractAdapter.
72
72
  redemptionPhantomToken: this.#redemptionPhantomToken ? this.labelAddress(this.#redemptionPhantomToken) : void 0
73
73
  };
74
74
  }
75
- decodeDiffLeftovers(decoded, balances) {
75
+ applyBalanceChanges(balances, decoded) {
76
76
  switch (decoded.functionName) {
77
- // exact-input redemption: burns dsTokenAmount of the DS token in
78
- // exchange for the redemption phantom token (which is credited by the
79
- // storeExpectedBalances bracket delta, not here)
80
77
  case "redeem": {
81
78
  const [dsTokenAmount] = decoded.args;
82
- const balance = balances.get(this.dsToken) ?? 0n;
83
- return [
84
- {
85
- tokenIn: this.dsToken,
86
- leftoverAmount: balance > dsTokenAmount ? balance - dsTokenAmount : 0n
87
- }
88
- ];
79
+ this.spendExact(balances, this.dsToken, dsTokenAmount);
80
+ break;
89
81
  }
90
82
  // diff-style redemption: spends the DS token down to the leftover
91
83
  case "redeemDiff": {
92
84
  const [leftoverAmount] = decoded.args;
93
- return [{ tokenIn: this.dsToken, leftoverAmount }];
85
+ this.setLeftover(balances, this.dsToken, leftoverAmount);
86
+ break;
94
87
  }
88
+ // TODO:
89
+ // `claim(address[] redeemers)` (the claim call emitted by the
90
+ // withdrawal compressor) cannot be previewed offline: the redemption
91
+ // phantom token burn (the compressor's `withdrawalTokenSpent`, i.e.
92
+ // each redeemer's `getRedemptionAmount()`) lives in per-redeemer clone
93
+ // contracts and is not recoverable from calldata. For claimable
94
+ // redeemers it equals the stablecoin credit, but that value is not in
95
+ // calldata either.
95
96
  default:
96
- return super.decodeDiffLeftovers(decoded, balances);
97
+ super.applyBalanceChanges(balances, decoded);
97
98
  }
98
99
  }
99
100
  }
@@ -100,21 +100,23 @@ class StakingRewardsAdapterContract extends import_AbstractAdapter.AbstractAdapt
100
100
  referral: this.#referral
101
101
  };
102
102
  }
103
- decodeDiffLeftovers(decoded, balances) {
103
+ applyBalanceChanges(balances, decoded) {
104
104
  switch (decoded.functionName) {
105
105
  case "stakeDiff": {
106
106
  const [leftoverAmount] = decoded.args;
107
- return [{ tokenIn: this.stakingToken, leftoverAmount }];
107
+ this.setLeftover(balances, this.stakingToken, leftoverAmount);
108
+ break;
108
109
  }
109
110
  case "withdrawDiff": {
110
111
  const [leftoverAmount] = decoded.args;
111
- return [{ tokenIn: this.stakedPhantomToken, leftoverAmount }];
112
+ this.setLeftover(balances, this.stakedPhantomToken, leftoverAmount);
113
+ break;
112
114
  }
113
115
  // no accrued rewards on a freshly opened account
114
116
  case "getReward":
115
- return [];
117
+ break;
116
118
  default:
117
- return super.decodeDiffLeftovers(decoded, balances);
119
+ super.applyBalanceChanges(balances, decoded);
118
120
  }
119
121
  }
120
122
  }
@@ -82,14 +82,15 @@ class TraderJoeRouterAdapterContract extends import_AbstractAdapter.AbstractAdap
82
82
  }))
83
83
  };
84
84
  }
85
- decodeDiffLeftovers(decoded, balances) {
85
+ applyBalanceChanges(balances, decoded) {
86
86
  switch (decoded.functionName) {
87
87
  case "swapDiffTokensForTokens": {
88
88
  const [leftoverAmount, , path] = decoded.args;
89
- return [{ tokenIn: path.tokenPath[0], leftoverAmount }];
89
+ this.setLeftover(balances, path.tokenPath[0], leftoverAmount);
90
+ break;
90
91
  }
91
92
  default:
92
- return super.decodeDiffLeftovers(decoded, balances);
93
+ super.applyBalanceChanges(balances, decoded);
93
94
  }
94
95
  }
95
96
  }
@@ -93,14 +93,15 @@ class UniswapV2AdapterContract extends import_AbstractAdapter.AbstractAdapterCon
93
93
  classifyLegacyOperation(_parsed, transfers) {
94
94
  return { operation: "UniswapSwap", ...(0, import_transferHelpers.swapFromTransfers)(transfers) };
95
95
  }
96
- decodeDiffLeftovers(decoded, balances) {
96
+ applyBalanceChanges(balances, decoded) {
97
97
  switch (decoded.functionName) {
98
98
  case "swapDiffTokensForTokens": {
99
99
  const [leftoverAmount, , path] = decoded.args;
100
- return [{ tokenIn: path[0], leftoverAmount }];
100
+ this.setLeftover(balances, path[0], leftoverAmount);
101
+ break;
101
102
  }
102
103
  default:
103
- return super.decodeDiffLeftovers(decoded, balances);
104
+ super.applyBalanceChanges(balances, decoded);
104
105
  }
105
106
  }
106
107
  }
@@ -71,24 +71,21 @@ class UniswapV3AdapterContract extends import_AbstractAdapter.AbstractAdapterCon
71
71
  }))
72
72
  };
73
73
  }
74
- decodeDiffLeftovers(decoded, balances) {
74
+ applyBalanceChanges(balances, decoded) {
75
75
  switch (decoded.functionName) {
76
76
  case "exactDiffInputSingle": {
77
77
  const [params] = decoded.args;
78
- return [
79
- {
80
- tokenIn: params.tokenIn,
81
- leftoverAmount: params.leftoverAmount
82
- }
83
- ];
78
+ this.setLeftover(balances, params.tokenIn, params.leftoverAmount);
79
+ break;
84
80
  }
85
81
  case "exactDiffInput": {
86
82
  const [params] = decoded.args;
87
83
  const tokenIn = `0x${params.path.replace("0x", "").slice(0, 40)}`;
88
- return [{ tokenIn, leftoverAmount: params.leftoverAmount }];
84
+ this.setLeftover(balances, tokenIn, params.leftoverAmount);
85
+ break;
89
86
  }
90
87
  default:
91
- return super.decodeDiffLeftovers(decoded, balances);
88
+ super.applyBalanceChanges(balances, decoded);
92
89
  }
93
90
  }
94
91
  stringifyFunctionParams(params) {
@@ -81,19 +81,19 @@ class UniswapV4AdapterContract extends import_AbstractAdapter.AbstractAdapterCon
81
81
  classifyLegacyOperation(_parsed, transfers) {
82
82
  return { operation: "UniswapSwap", ...(0, import_transferHelpers.swapFromTransfers)(transfers) };
83
83
  }
84
- decodeDiffLeftovers(decoded, balances) {
84
+ applyBalanceChanges(balances, decoded) {
85
85
  switch (decoded.functionName) {
86
86
  case "swapExactInputSingleDiff": {
87
87
  const [poolKey, zeroForOne, leftoverAmount] = decoded.args;
88
- return [
89
- {
90
- tokenIn: zeroForOne ? poolKey.token0 : poolKey.token1,
91
- leftoverAmount
92
- }
93
- ];
88
+ this.setLeftover(
89
+ balances,
90
+ zeroForOne ? poolKey.token0 : poolKey.token1,
91
+ leftoverAmount
92
+ );
93
+ break;
94
94
  }
95
95
  default:
96
- return super.decodeDiffLeftovers(decoded, balances);
96
+ super.applyBalanceChanges(balances, decoded);
97
97
  }
98
98
  }
99
99
  }
@@ -70,18 +70,20 @@ class UpshiftVaultAdapterContract extends import_AbstractAdapter.AbstractAdapter
70
70
  stakedPhantomToken: this.#stakedPhantomToken ? this.labelAddress(this.#stakedPhantomToken) : void 0
71
71
  };
72
72
  }
73
- decodeDiffLeftovers(decoded, balances) {
73
+ applyBalanceChanges(balances, decoded) {
74
74
  switch (decoded.functionName) {
75
75
  case "depositDiff": {
76
76
  const [leftoverAmount] = decoded.args;
77
- return [{ tokenIn: this.asset, leftoverAmount }];
77
+ this.setLeftover(balances, this.asset, leftoverAmount);
78
+ break;
78
79
  }
79
80
  case "redeemDiff": {
80
81
  const [leftoverAmount] = decoded.args;
81
- return [{ tokenIn: this.vault, leftoverAmount }];
82
+ this.setLeftover(balances, this.vault, leftoverAmount);
83
+ break;
82
84
  }
83
85
  default:
84
- return super.decodeDiffLeftovers(decoded, balances);
86
+ super.applyBalanceChanges(balances, decoded);
85
87
  }
86
88
  }
87
89
  }
@@ -74,14 +74,15 @@ class VelodromeV2RouterAdapterContract extends import_AbstractAdapter.AbstractAd
74
74
  }))
75
75
  };
76
76
  }
77
- decodeDiffLeftovers(decoded, balances) {
77
+ applyBalanceChanges(balances, decoded) {
78
78
  switch (decoded.functionName) {
79
79
  case "swapDiffTokensForTokens": {
80
80
  const [leftoverAmount, , routes] = decoded.args;
81
- return [{ tokenIn: routes[0].from, leftoverAmount }];
81
+ this.setLeftover(balances, routes[0].from, leftoverAmount);
82
+ break;
82
83
  }
83
84
  default:
84
- return super.decodeDiffLeftovers(decoded, balances);
85
+ super.applyBalanceChanges(balances, decoded);
85
86
  }
86
87
  }
87
88
  }
@@ -65,19 +65,21 @@ class WstETHV1AdapterContract extends import_AbstractAdapter.AbstractAdapterCont
65
65
  }
66
66
  return super.classifyLegacyOperation(parsed, transfers);
67
67
  }
68
- decodeDiffLeftovers(decoded, balances) {
68
+ applyBalanceChanges(balances, decoded) {
69
69
  switch (decoded.functionName) {
70
70
  case "wrapDiff": {
71
71
  const [leftoverAmount] = decoded.args;
72
- return [{ tokenIn: this.stETH, leftoverAmount }];
72
+ this.setLeftover(balances, this.stETH, leftoverAmount);
73
+ break;
73
74
  }
74
75
  // wstETH is the adapter's target contract
75
76
  case "unwrapDiff": {
76
77
  const [leftoverAmount] = decoded.args;
77
- return [{ tokenIn: this.targetContract, leftoverAmount }];
78
+ this.setLeftover(balances, this.targetContract, leftoverAmount);
79
+ break;
78
80
  }
79
81
  default:
80
- return super.decodeDiffLeftovers(decoded, balances);
82
+ super.applyBalanceChanges(balances, decoded);
81
83
  }
82
84
  }
83
85
  }
@@ -216,43 +216,50 @@ async function fulfillSecuritizeWithdrawal(anvil, creditAccount, withdrawalPhant
216
216
  const redeemers = await anvil.readContract({
217
217
  address: redemptionGateway,
218
218
  abi: securitizeRedemptionGatewayAbi,
219
- functionName: "getRedeemers",
219
+ functionName: "getUnclaimedRedeemers",
220
220
  args: [creditAccount]
221
221
  });
222
222
  logger?.debug(
223
- `securitize: gateway ${redemptionGateway}, stablecoin ${stableCoinToken}, ${redeemers.length} redeemers`
223
+ `securitize: gateway ${redemptionGateway}, stablecoin ${stableCoinToken}, ${redeemers.length} unclaimed redeemers`
224
224
  );
225
225
  if (redeemers.length === 0) {
226
226
  logger?.warn(
227
- `securitize: no redeemers found for credit account ${creditAccount}`
227
+ `securitize: no unclaimed redeemers found for credit account ${creditAccount}`
228
228
  );
229
229
  return;
230
230
  }
231
- const redeemer = redeemers[0];
232
- const [redemptionValue, redeemerBalance] = await anvil.multicall({
233
- allowFailure: false,
234
- contracts: [
235
- {
236
- address: redeemer,
237
- abi: securitizeRedeemerAbi,
238
- functionName: "getCurrentRedemptionValue"
239
- },
240
- {
241
- address: stableCoinToken,
242
- abi: erc20Abi,
243
- functionName: "balanceOf",
244
- args: [redeemer]
245
- }
246
- ]
247
- });
248
- logger?.debug(
249
- `securitize: dealing ${redemptionValue} of stablecoin ${stableCoinToken} to redeemer ${redeemer}`
250
- );
251
- await anvil.deal({
252
- erc20: stableCoinToken,
253
- account: redeemer,
254
- amount: redeemerBalance + redemptionValue
255
- });
231
+ for (const redeemer of redeemers) {
232
+ const [redemptionValue, redeemerBalance] = await anvil.multicall({
233
+ allowFailure: false,
234
+ contracts: [
235
+ {
236
+ address: redeemer,
237
+ abi: securitizeRedeemerAbi,
238
+ functionName: "getCurrentRedemptionValue"
239
+ },
240
+ {
241
+ address: stableCoinToken,
242
+ abi: erc20Abi,
243
+ functionName: "balanceOf",
244
+ args: [redeemer]
245
+ }
246
+ ]
247
+ });
248
+ if (redemptionValue === 0n) {
249
+ logger?.debug(
250
+ `securitize: skipping redeemer ${redeemer} with zero redemption value`
251
+ );
252
+ continue;
253
+ }
254
+ logger?.debug(
255
+ `securitize: dealing ${redemptionValue} of stablecoin ${stableCoinToken} to redeemer ${redeemer}`
256
+ );
257
+ await anvil.deal({
258
+ erc20: stableCoinToken,
259
+ account: redeemer,
260
+ amount: redeemerBalance + redemptionValue
261
+ });
262
+ }
256
263
  }
257
264
  export {
258
265
  makePendingWithdrawalsClaimable
@@ -104,8 +104,10 @@ class AbstractAdapterContract extends BaseContract {
104
104
  }
105
105
  }
106
106
  /**
107
- * Applies the balance changes implied by a router-generated diff-style
108
- * adapter call to a map of credit-account token balances.
107
+ * Applies the balance changes implied by an adapter call to a map of
108
+ * credit-account token balances. Handles both router-generated diff-style
109
+ * calls and exact-input calls (e.g. those emitted by the withdrawal
110
+ * compressor).
109
111
  *
110
112
  * @param balances - Token balances before the call. Mutated in place.
111
113
  * @param calldata - Raw ABI-encoded adapter calldata.
@@ -122,23 +124,43 @@ class AbstractAdapterContract extends BaseContract {
122
124
  { cause: e }
123
125
  );
124
126
  }
125
- const leftovers = this.decodeDiffLeftovers(decoded, balances);
126
- for (const { tokenIn, leftoverAmount } of leftovers) {
127
- balances.upsert(tokenIn, leftoverAmount);
128
- }
127
+ this.applyBalanceChanges(balances, decoded);
129
128
  }
130
129
  /**
131
- * Resolves which tokens the diff-style call spends down to which leftovers.
130
+ * Applies the balance changes of a decoded adapter call to the running
131
+ * balances, mutating them in place. Overrides should express changes via
132
+ * {@link setLeftover} (diff-style calls) and {@link spendExact}
133
+ * (exact-input calls), and should resolve all tokens/amounts before the
134
+ * first write so a throw never leaves balances partially mutated.
132
135
  *
136
+ * @param _balances - Token balances before the call. Mutated in place.
133
137
  * @param decoded - The viem-decoded adapter call
134
- * @param _balances - Token balances before the call
135
138
  * @throws When the adapter (or the specific function) has no balance-changes support
136
139
  */
137
- decodeDiffLeftovers(decoded, _balances) {
140
+ applyBalanceChanges(_balances, decoded) {
138
141
  throw new Error(
139
142
  `previewBalanceChanges is not supported for ${decoded.functionName} on ${this.contractType} adapter at ${this.address}`
140
143
  );
141
144
  }
145
+ /**
146
+ * Diff-call semantics of a diff-style adapter call: the call spends the
147
+ * consumed token down to the exact `leftoverAmount` encoded in its
148
+ * calldata, so the post-call balance of `tokenIn` is `leftoverAmount`
149
+ * regardless of the actual amount spent.
150
+ */
151
+ setLeftover(balances, tokenIn, leftoverAmount) {
152
+ balances.upsert(tokenIn, leftoverAmount);
153
+ }
154
+ /**
155
+ * Exact-input call semantics: spends exactly `amount` of `tokenIn` from
156
+ * the running balance, clamping at zero. Used for non-diff adapter calls
157
+ * (e.g. those generated by the withdrawal compressor) whose spent amount
158
+ * is present in calldata.
159
+ */
160
+ spendExact(balances, tokenIn, amount) {
161
+ const balance = balances.getOrZero(tokenIn);
162
+ balances.upsert(tokenIn, balance > amount ? balance - amount : 0n);
163
+ }
142
164
  /**
143
165
  * Classifies an adapter call into a {@link LegacyAdapterOperation} using the
144
166
  * parsed call and credit-account transfer deltas.
@@ -5,23 +5,26 @@ class AbstractCurveAdapterContract extends AbstractAdapterContract {
5
5
  classifyLegacyOperation(parsed, transfers) {
6
6
  return classifyCurveOperation(parsed.functionName, transfers) ?? super.classifyLegacyOperation(parsed, transfers);
7
7
  }
8
- decodeDiffLeftovers(decoded, balances) {
8
+ applyBalanceChanges(balances, decoded) {
9
9
  const { functionName, args } = decoded;
10
10
  switch (functionName) {
11
11
  case "exchange_diff": {
12
12
  const [i, , leftoverAmount] = args;
13
- return [{ tokenIn: this.curveCoin(i), leftoverAmount }];
13
+ this.setLeftover(balances, this.curveCoin(i), leftoverAmount);
14
+ break;
14
15
  }
15
16
  case "add_diff_liquidity_one_coin": {
16
17
  const [leftoverAmount, i] = args;
17
- return [{ tokenIn: this.curveCoin(i), leftoverAmount }];
18
+ this.setLeftover(balances, this.curveCoin(i), leftoverAmount);
19
+ break;
18
20
  }
19
21
  case "remove_diff_liquidity_one_coin": {
20
22
  const [leftoverAmount] = args;
21
- return [{ tokenIn: this.lpToken, leftoverAmount }];
23
+ this.setLeftover(balances, this.lpToken, leftoverAmount);
24
+ break;
22
25
  }
23
26
  default:
24
- return super.decodeDiffLeftovers(decoded, balances);
27
+ super.applyBalanceChanges(balances, decoded);
25
28
  }
26
29
  }
27
30
  /**
@@ -71,23 +71,25 @@ class BalancerV3RouterAdapterContract extends AbstractAdapterContract {
71
71
  }))
72
72
  };
73
73
  }
74
- decodeDiffLeftovers(decoded, balances) {
74
+ applyBalanceChanges(balances, decoded) {
75
75
  switch (decoded.functionName) {
76
76
  case "swapSingleTokenDiffIn": {
77
77
  const [, tokenIn, , leftoverAmount] = decoded.args;
78
- return [{ tokenIn, leftoverAmount }];
78
+ this.setLeftover(balances, tokenIn, leftoverAmount);
79
+ break;
79
80
  }
80
81
  // BPT (pool token) is spent down to the leftover
81
82
  case "removeLiquiditySingleTokenDiff": {
82
83
  const [pool, leftoverAmount] = decoded.args;
83
- return [{ tokenIn: pool, leftoverAmount }];
84
+ this.setLeftover(balances, pool, leftoverAmount);
85
+ break;
84
86
  }
85
87
  case "addLiquidityUnbalancedDiff":
86
88
  throw new Error(
87
89
  `previewBalanceChanges cannot resolve pool tokens for addLiquidityUnbalancedDiff on ${this.contractType} adapter at ${this.address}`
88
90
  );
89
91
  default:
90
- return super.decodeDiffLeftovers(decoded, balances);
92
+ super.applyBalanceChanges(balances, decoded);
91
93
  }
92
94
  }
93
95
  }