@gearbox-protocol/sdk 14.12.0-next.1 → 14.12.0-next.2

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 (80) hide show
  1. package/dist/cjs/abi/iZapper.js +62 -24
  2. package/dist/cjs/preview/parse/errors.js +5 -2
  3. package/dist/cjs/preview/parse/parseOperationCalldata.js +30 -1
  4. package/dist/cjs/preview/parse/parsePoolOperationCalldata.js +10 -2
  5. package/dist/cjs/preview/prerequisites/buildPrerequisites.js +34 -0
  6. package/dist/cjs/preview/simulate/errors.js +0 -7
  7. package/dist/cjs/preview/simulate/index.js +0 -3
  8. package/dist/cjs/preview/simulate/simulatePoolOperation.js +154 -29
  9. package/dist/cjs/sdk/MultichainSDK.js +1 -0
  10. package/dist/cjs/sdk/OnchainSDK.js +7 -3
  11. package/dist/cjs/sdk/market/MarketRegister.js +10 -5
  12. package/dist/cjs/sdk/market/ZapperRegister.js +54 -0
  13. package/dist/cjs/sdk/market/zapper/IERC20ZapperContract.js +3 -38
  14. package/dist/cjs/sdk/market/zapper/IETHZapperContract.js +3 -38
  15. package/dist/cjs/sdk/market/zapper/ZapperContract.js +109 -0
  16. package/dist/cjs/sdk/market/zapper/createZapper.js +12 -4
  17. package/dist/cjs/{preview/simulate/constants.js → sdk/market/zapper/errors.js} +15 -6
  18. package/dist/cjs/sdk/market/zapper/index.js +6 -2
  19. package/dist/cjs/sdk/market/zapper/types.js +16 -0
  20. package/dist/cjs/sdk/options.js +41 -17
  21. package/dist/esm/abi/iZapper.js +62 -24
  22. package/dist/esm/preview/parse/errors.js +3 -1
  23. package/dist/esm/preview/parse/parseOperationCalldata.js +32 -2
  24. package/dist/esm/preview/parse/parsePoolOperationCalldata.js +10 -2
  25. package/dist/esm/preview/prerequisites/buildPrerequisites.js +34 -0
  26. package/dist/esm/preview/simulate/errors.js +0 -6
  27. package/dist/esm/preview/simulate/index.js +0 -2
  28. package/dist/esm/preview/simulate/simulatePoolOperation.js +155 -30
  29. package/dist/esm/sdk/MultichainSDK.js +1 -0
  30. package/dist/esm/sdk/OnchainSDK.js +7 -3
  31. package/dist/esm/sdk/market/MarketRegister.js +10 -5
  32. package/dist/esm/sdk/market/ZapperRegister.js +54 -0
  33. package/dist/esm/sdk/market/zapper/IERC20ZapperContract.js +3 -38
  34. package/dist/esm/sdk/market/zapper/IETHZapperContract.js +3 -38
  35. package/dist/esm/sdk/market/zapper/ZapperContract.js +85 -0
  36. package/dist/esm/sdk/market/zapper/createZapper.js +12 -4
  37. package/dist/esm/sdk/market/zapper/errors.js +13 -0
  38. package/dist/esm/sdk/market/zapper/index.js +3 -1
  39. package/dist/esm/sdk/market/zapper/types.js +0 -0
  40. package/dist/esm/sdk/options.js +39 -15
  41. package/dist/types/abi/iERC20Zapper.d.ts +91 -23
  42. package/dist/types/abi/iETHZapper.d.ts +91 -23
  43. package/dist/types/abi/iZapper.d.ts +91 -23
  44. package/dist/types/preview/parse/errors.d.ts +1 -0
  45. package/dist/types/preview/parse/parseOperationCalldata.d.ts +3 -3
  46. package/dist/types/preview/parse/types-pools.d.ts +61 -1
  47. package/dist/types/preview/simulate/errors.d.ts +6 -12
  48. package/dist/types/preview/simulate/index.d.ts +0 -1
  49. package/dist/types/preview/simulate/simulatePoolOperation.d.ts +22 -4
  50. package/dist/types/preview/simulate/types.d.ts +3 -16
  51. package/dist/types/sdk/MultichainSDK.d.ts +5 -0
  52. package/dist/types/sdk/OnchainSDK.d.ts +4 -0
  53. package/dist/types/sdk/market/MarketRegister.d.ts +15 -6
  54. package/dist/types/sdk/market/ZapperRegister.d.ts +25 -4
  55. package/dist/types/sdk/market/zapper/IERC20ZapperContract.d.ts +93 -39
  56. package/dist/types/sdk/market/zapper/IETHZapperContract.d.ts +93 -39
  57. package/dist/types/sdk/market/zapper/ZapperContract.d.ts +35 -0
  58. package/dist/types/sdk/market/zapper/createZapper.d.ts +2 -4
  59. package/dist/types/sdk/market/zapper/errors.d.ts +10 -0
  60. package/dist/types/sdk/market/zapper/index.d.ts +3 -1
  61. package/dist/types/sdk/market/zapper/types.d.ts +64 -0
  62. package/dist/types/sdk/options.d.ts +10 -5
  63. package/dist/types/sdk/pools/types.d.ts +3 -3
  64. package/dist/types/sdk/types/state-human.d.ts +9 -0
  65. package/dist/types/sdk/types/state.d.ts +7 -0
  66. package/package.json +3 -3
  67. package/dist/cjs/preview/simulate/extractERC20Transfers.js +0 -47
  68. package/dist/cjs/preview/simulate/simulatePoolOpMulticall.js +0 -155
  69. package/dist/cjs/preview/simulate/simulatePoolOpV1.js +0 -106
  70. package/dist/cjs/sdk/market/zapper/Zapper.js +0 -47
  71. package/dist/esm/preview/simulate/constants.js +0 -4
  72. package/dist/esm/preview/simulate/extractERC20Transfers.js +0 -23
  73. package/dist/esm/preview/simulate/simulatePoolOpMulticall.js +0 -130
  74. package/dist/esm/preview/simulate/simulatePoolOpV1.js +0 -82
  75. package/dist/esm/sdk/market/zapper/Zapper.js +0 -23
  76. package/dist/types/preview/simulate/constants.d.ts +0 -6
  77. package/dist/types/preview/simulate/extractERC20Transfers.d.ts +0 -11
  78. package/dist/types/preview/simulate/simulatePoolOpMulticall.d.ts +0 -28
  79. package/dist/types/preview/simulate/simulatePoolOpV1.d.ts +0 -14
  80. package/dist/types/sdk/market/zapper/Zapper.d.ts +0 -13
@@ -1,16 +1,46 @@
1
1
  import {
2
2
  CreditFacadeV310Contract,
3
- PoolV310Contract
3
+ PoolV310Contract,
4
+ ZapperContract
4
5
  } from "../../sdk/index.js";
5
6
  import { UnsupportedTargetError } from "./errors.js";
6
7
  import { parseFacadeOperationCalldata } from "./parseFacadeOperationCalldata.js";
7
8
  import { parsePoolOperationCalldata } from "./parsePoolOperationCalldata.js";
8
9
  function parseOperationCalldata(input) {
9
- const { sdk, to, calldata } = input;
10
+ const { sdk, to, calldata, value, sender } = input;
10
11
  const contract = sdk.getContract(to);
11
12
  if (contract instanceof PoolV310Contract) {
12
13
  return parsePoolOperationCalldata({ sdk, pool: contract, calldata });
13
14
  }
15
+ if (contract instanceof ZapperContract) {
16
+ const parsed = contract.parseOperation(calldata, value);
17
+ if (parsed.operation === "Deposit") {
18
+ const op2 = {
19
+ operation: "Deposit",
20
+ pool: parsed.pool,
21
+ receiver: parsed.receiver,
22
+ assets: parsed.assets,
23
+ underlying: parsed.underlying,
24
+ tokenIn: parsed.token,
25
+ zapper: parsed.zapper,
26
+ referralCode: parsed.referralCode
27
+ };
28
+ return op2;
29
+ }
30
+ const op = {
31
+ operation: "Redeem",
32
+ pool: parsed.pool,
33
+ receiver: parsed.receiver,
34
+ // The zapper burns the caller's pool shares, so the share owner is the
35
+ // transaction sender.
36
+ owner: sender,
37
+ shares: parsed.shares,
38
+ underlying: parsed.underlying,
39
+ tokenOut: parsed.token,
40
+ zapper: parsed.zapper
41
+ };
42
+ return op;
43
+ }
14
44
  if (contract instanceof CreditFacadeV310Contract) {
15
45
  return parseFacadeOperationCalldata({
16
46
  sdk,
@@ -14,6 +14,8 @@ function parsePoolOperationCalldata(props) {
14
14
  receiver: rawArgs.receiver,
15
15
  assets: rawArgs.assets,
16
16
  underlying,
17
+ tokenIn: underlying,
18
+ zapper: void 0,
17
19
  referralCode: functionName === "depositWithReferral" ? rawArgs.referralCode : void 0
18
20
  };
19
21
  case "mint":
@@ -24,6 +26,8 @@ function parsePoolOperationCalldata(props) {
24
26
  receiver: rawArgs.receiver,
25
27
  shares: rawArgs.shares,
26
28
  underlying,
29
+ tokenIn: underlying,
30
+ zapper: void 0,
27
31
  referralCode: functionName === "mintWithReferral" ? rawArgs.referralCode : void 0
28
32
  };
29
33
  case "withdraw":
@@ -33,7 +37,9 @@ function parsePoolOperationCalldata(props) {
33
37
  receiver: rawArgs.receiver,
34
38
  owner: rawArgs.owner,
35
39
  assets: rawArgs.assets,
36
- underlying
40
+ underlying,
41
+ tokenOut: underlying,
42
+ zapper: void 0
37
43
  };
38
44
  case "redeem":
39
45
  return {
@@ -42,7 +48,9 @@ function parsePoolOperationCalldata(props) {
42
48
  receiver: rawArgs.receiver,
43
49
  owner: rawArgs.owner,
44
50
  shares: rawArgs.shares,
45
- underlying
51
+ underlying,
52
+ tokenOut: underlying,
53
+ zapper: void 0
46
54
  };
47
55
  default:
48
56
  throw new UnsupportedPoolFunctionError(pool.address, parsed.functionName);
@@ -11,6 +11,23 @@ function buildPrerequisites(tx, ctx) {
11
11
  // here we approximate Mint by its shares amount (a lower bound on assets is
12
12
  // not knowable from calldata alone).
13
13
  case "Deposit":
14
+ if (tx.zapper) {
15
+ return [
16
+ new AllowancePrerequisite({
17
+ token: tx.tokenIn,
18
+ owner: wallet,
19
+ spender: tx.zapper,
20
+ required: tx.assets,
21
+ title: "Token approved to zapper"
22
+ }),
23
+ new BalancePrerequisite({
24
+ token: tx.tokenIn,
25
+ owner: wallet,
26
+ required: tx.assets,
27
+ title: "Sufficient token balance"
28
+ })
29
+ ];
30
+ }
14
31
  return [
15
32
  new AllowancePrerequisite({
16
33
  token: tx.underlying,
@@ -45,6 +62,23 @@ function buildPrerequisites(tx, ctx) {
45
62
  // Redeem and Withdraw both burn LP shares from `owner`; they only differ in
46
63
  // which side (shares vs assets) the caller specifies.
47
64
  case "Redeem": {
65
+ if (tx.zapper) {
66
+ return [
67
+ new BalancePrerequisite({
68
+ token: tx.pool,
69
+ owner: wallet,
70
+ required: tx.shares,
71
+ title: "Sufficient LP token balance"
72
+ }),
73
+ new AllowancePrerequisite({
74
+ token: tx.pool,
75
+ owner: wallet,
76
+ spender: tx.zapper,
77
+ required: tx.shares,
78
+ title: "LP token approved to zapper"
79
+ })
80
+ ];
81
+ }
48
82
  const prereqs = [
49
83
  new BalancePrerequisite({
50
84
  token: tx.pool,
@@ -27,11 +27,6 @@ function asPreviewSimulationError(reason, source) {
27
27
  { source, detail: decodeSimulationError({ error }) }
28
28
  ]);
29
29
  }
30
- function combinePreviewSimulationErrors(...errors) {
31
- return new PreviewSimulationError(
32
- errors.filter((e) => e).flatMap((e) => e?.failures ?? [])
33
- );
34
- }
35
30
  function decodeSimulationError(revert) {
36
31
  const { error, data } = revert;
37
32
  if (data && data !== "0x") {
@@ -70,6 +65,5 @@ function formatDecodedError(errorName, args) {
70
65
  export {
71
66
  PreviewSimulationError,
72
67
  asPreviewSimulationError,
73
- combinePreviewSimulationErrors,
74
68
  decodeSimulationError
75
69
  };
@@ -1,10 +1,8 @@
1
- import { ETH_SIMULATE_V1_NETWORKS } from "./constants.js";
2
1
  import { PreviewSimulationError } from "./errors.js";
3
2
  import { simulateFacadeOperation } from "./simulateFacadeOperation.js";
4
3
  import { simulateOperation } from "./simulateOperation.js";
5
4
  import { simulatePoolOperation } from "./simulatePoolOperation.js";
6
5
  export {
7
- ETH_SIMULATE_V1_NETWORKS,
8
6
  PreviewSimulationError,
9
7
  simulateFacadeOperation,
10
8
  simulateOperation,
@@ -1,41 +1,166 @@
1
- import { ETH_SIMULATE_V1_NETWORKS } from "./constants.js";
1
+ import { iPoolV310Abi } from "../../abi/310/generated.js";
2
+ import { ierc20Abi } from "../../abi/iERC20.js";
3
+ import { iZapperAbi } from "../../abi/iZapper.js";
4
+ import { AddressMap } from "../../sdk/index.js";
2
5
  import {
3
6
  asPreviewSimulationError,
4
- combinePreviewSimulationErrors
7
+ decodeSimulationError,
8
+ PreviewSimulationError
5
9
  } from "./errors.js";
6
- import { simulatePoolOpMulticall } from "./simulatePoolOpMulticall.js";
7
- import { simulatePoolOpV1 } from "./simulatePoolOpV1.js";
10
+ import { watchedHolders } from "./holders.js";
11
+ function previewRead(operation) {
12
+ switch (operation.operation) {
13
+ case "Deposit":
14
+ return { functionName: "previewDeposit", amount: operation.assets };
15
+ case "Mint":
16
+ return { functionName: "previewMint", amount: operation.shares };
17
+ case "Withdraw":
18
+ return { functionName: "previewWithdraw", amount: operation.assets };
19
+ case "Redeem":
20
+ return { functionName: "previewRedeem", amount: operation.shares };
21
+ }
22
+ }
23
+ function outsideToken(operation) {
24
+ switch (operation.operation) {
25
+ case "Deposit":
26
+ case "Mint":
27
+ return operation.tokenIn;
28
+ case "Withdraw":
29
+ case "Redeem":
30
+ return operation.tokenOut;
31
+ }
32
+ }
33
+ function previewContract(operation) {
34
+ const { functionName, amount } = previewRead(operation);
35
+ if (operation.zapper) {
36
+ return {
37
+ address: operation.zapper,
38
+ abi: iZapperAbi,
39
+ functionName,
40
+ args: [amount]
41
+ };
42
+ }
43
+ return {
44
+ address: operation.pool,
45
+ abi: iPoolV310Abi,
46
+ functionName,
47
+ args: [amount]
48
+ };
49
+ }
8
50
  async function simulatePoolOperation(input, options = {}) {
9
- const { sdk } = input;
10
- const { logger } = options;
11
- const useSimulateV1 = options.useSimulateV1 ?? ETH_SIMULATE_V1_NETWORKS.has(sdk.networkType);
12
- logger?.debug(
13
- { wallet: input.wallet, to: input.to },
14
- "simulating pool operation"
15
- );
16
- const [v1, multicall] = await Promise.allSettled([
17
- useSimulateV1 ? simulatePoolOpV1(input, options) : void 0,
18
- simulatePoolOpMulticall(input, options)
19
- ]);
20
- if (v1.status === "fulfilled" && v1.value) {
21
- return { status: "success", ...v1.value };
51
+ const { sdk, operation, wallet } = input;
52
+ const { blockNumber, logger } = options;
53
+ const { pool } = operation;
54
+ try {
55
+ const holders = watchedHolders(operation, wallet);
56
+ const tokens = [outsideToken(operation), pool];
57
+ const balanceCalls = holders.flatMap(
58
+ (holder) => tokens.map((token) => ({ holder, token }))
59
+ );
60
+ const balanceContracts = balanceCalls.map(
61
+ ({ holder, token }) => ({
62
+ address: token,
63
+ abi: ierc20Abi,
64
+ functionName: "balanceOf",
65
+ args: [holder]
66
+ })
67
+ );
68
+ const preview = previewContract(operation);
69
+ let results;
70
+ try {
71
+ results = await sdk.client.multicall({
72
+ allowFailure: false,
73
+ // `undefined` lets viem read at `latest`; `blockNumber` is only set for
74
+ // testnet forks pinned to a specific block.
75
+ blockNumber,
76
+ contracts: [...balanceContracts, preview]
77
+ });
78
+ } catch (cause) {
79
+ throw new PreviewSimulationError([
80
+ {
81
+ source: "multicall",
82
+ detail: decodeSimulationError({
83
+ error: cause instanceof Error ? cause : new Error(String(cause))
84
+ })
85
+ }
86
+ ]);
87
+ }
88
+ const previewAmount = results[balanceContracts.length];
89
+ const balances = new AddressMap();
90
+ for (const [i, { holder, token }] of balanceCalls.entries()) {
91
+ const tokenBalances = balances.get(holder) ?? new AddressMap();
92
+ tokenBalances.upsert(token, results[i]);
93
+ balances.upsert(holder, tokenBalances);
94
+ }
95
+ const before = (token, holder) => balances.get(holder)?.get(token) ?? 0n;
96
+ return {
97
+ status: "success",
98
+ balanceChanges: computePoolOpBalanceChanges(
99
+ operation,
100
+ wallet,
101
+ previewAmount,
102
+ before
103
+ )
104
+ };
105
+ } catch (cause) {
106
+ const error = asPreviewSimulationError(cause, "multicall");
107
+ logger?.error(error, "pool operation simulation failed");
108
+ return { status: "failure", error };
22
109
  }
23
- if (multicall.status === "fulfilled") {
24
- if (v1.status === "rejected") {
25
- logger?.debug(
26
- asPreviewSimulationError(v1.reason, "eth_simulateV1"),
27
- "eth_simulateV1 flow failed; falling back to multicall result"
28
- );
110
+ }
111
+ function balanceLegs(operation, wallet, previewAmount) {
112
+ const { pool, receiver } = operation;
113
+ switch (operation.operation) {
114
+ case "Deposit":
115
+ return [
116
+ { address: wallet, token: operation.tokenIn, delta: -operation.assets },
117
+ { address: receiver, token: pool, delta: previewAmount }
118
+ ];
119
+ case "Mint":
120
+ return [
121
+ { address: wallet, token: operation.tokenIn, delta: -previewAmount },
122
+ { address: receiver, token: pool, delta: operation.shares }
123
+ ];
124
+ case "Withdraw":
125
+ return [
126
+ { address: operation.owner, token: pool, delta: -previewAmount },
127
+ {
128
+ address: receiver,
129
+ token: operation.tokenOut,
130
+ delta: operation.assets
131
+ }
132
+ ];
133
+ case "Redeem":
134
+ return [
135
+ { address: operation.owner, token: pool, delta: -operation.shares },
136
+ { address: receiver, token: operation.tokenOut, delta: previewAmount }
137
+ ];
138
+ }
139
+ }
140
+ function computePoolOpBalanceChanges(operation, wallet, previewAmount, before) {
141
+ const byAddress = new AddressMap();
142
+ for (const { address, token, delta } of balanceLegs(
143
+ operation,
144
+ wallet,
145
+ previewAmount
146
+ )) {
147
+ const beforeBalance = before(token, address);
148
+ const change = {
149
+ token,
150
+ before: beforeBalance,
151
+ after: beforeBalance + delta,
152
+ delta
153
+ };
154
+ const existing = byAddress.get(address);
155
+ if (existing) {
156
+ existing.changes.push(change);
157
+ } else {
158
+ byAddress.upsert(address, { address, changes: [change] });
29
159
  }
30
- return { status: "success", ...multicall.value };
31
160
  }
32
- const error = combinePreviewSimulationErrors(
33
- v1.status === "rejected" ? asPreviewSimulationError(v1.reason, "eth_simulateV1") : void 0,
34
- asPreviewSimulationError(multicall.reason, "multicall")
35
- );
36
- logger?.error(error, "pool operation simulation failed");
37
- return { status: "failure", error };
161
+ return byAddress.values();
38
162
  }
39
163
  export {
164
+ computePoolOpBalanceChanges,
40
165
  simulatePoolOperation
41
166
  };
@@ -67,6 +67,7 @@ class MultichainSDK {
67
67
  const perChainOpts = options?.perChain?.[network] ?? {};
68
68
  return sdk.attach({
69
69
  ...perChainOpts,
70
+ loadZappers: perChainOpts.loadZappers ?? options?.loadZappers,
70
71
  redstone: {
71
72
  ...options?.redstone,
72
73
  cache: this.#redstoneCache,
@@ -126,7 +126,8 @@ class OnchainSDK extends ChainContractsRegister {
126
126
  ignoreMarkets,
127
127
  marketConfigurators: mcs,
128
128
  redstone,
129
- pyth
129
+ pyth,
130
+ loadZappers
130
131
  } = options ?? {};
131
132
  const marketConfigurators = mcs ?? TypedObjectUtils.keys(
132
133
  this.client.chain.defaultMarketConfigurators
@@ -195,6 +196,9 @@ class OnchainSDK extends ChainContractsRegister {
195
196
  blockNumber: this.currentBlock,
196
197
  gas: this.gasLimit
197
198
  });
199
+ if (loadZappers) {
200
+ await this.#marketRegister.loadZappers();
201
+ }
198
202
  }
199
203
  const pluginsList = TypedObjectUtils.entries(this.plugins);
200
204
  const pluginResponse = await Promise.allSettled(
@@ -247,7 +251,7 @@ class OnchainSDK extends ChainContractsRegister {
247
251
  `address provider version: ${this.#addressProvider.version}`
248
252
  );
249
253
  this.#marketRegister = new MarketRegister(this, ignoreMarkets);
250
- this.#marketRegister.hydrate(state.markets);
254
+ this.#marketRegister.hydrate(state);
251
255
  this.#rwa = new RWARegistry(this);
252
256
  this.#rwa.setState(state.rwa);
253
257
  for (const [name, plugin] of TypedObjectUtils.entries(this.plugins)) {
@@ -312,7 +316,7 @@ class OnchainSDK extends ChainContractsRegister {
312
316
  currentBlock: this.currentBlock,
313
317
  timestamp: this.timestamp,
314
318
  addressProvider: this.addressProvider.state,
315
- markets: this.marketRegister.state,
319
+ ...this.marketRegister.state,
316
320
  rwa: this.#rwa.state,
317
321
  plugins: Object.fromEntries(
318
322
  TypedObjectUtils.entries(this.plugins).map(([name, plugin]) => [
@@ -35,10 +35,11 @@ class MarketRegister extends ZapperRegister {
35
35
  * bypassing on-chain reads.
36
36
  * @param state - Array of market data snapshots.
37
37
  **/
38
- hydrate(state) {
39
- const configurators = new Set(state.map((m) => m.configurator));
38
+ hydrate({ markets, zappers }) {
39
+ const configurators = new Set(markets.map((m) => m.configurator));
40
40
  this.#setMarketFilter([...configurators]);
41
- this.#setMarkets(state);
41
+ this.#setMarkets(markets);
42
+ this.hydrateZappers(zappers);
42
43
  }
43
44
  /**
44
45
  * @internal
@@ -157,7 +158,10 @@ class MarketRegister extends ZapperRegister {
157
158
  * Serializable snapshot of all loaded markets, suitable for hydration.
158
159
  **/
159
160
  get state() {
160
- return this.markets.map((market) => market.state);
161
+ return {
162
+ markets: this.markets.map((market) => market.state),
163
+ zappers: this.zappersState
164
+ };
161
165
  }
162
166
  /**
163
167
  * Returns a human-readable snapshot of all markets.
@@ -165,7 +169,8 @@ class MarketRegister extends ZapperRegister {
165
169
  **/
166
170
  stateHuman(raw = true) {
167
171
  return {
168
- markets: this.markets.map((market) => market.stateHuman(raw))
172
+ markets: this.markets.map((market) => market.stateHuman(raw)),
173
+ zappers: this.zappersStateHuman(raw)
169
174
  };
170
175
  }
171
176
  /**
@@ -55,6 +55,60 @@ class ZapperRegister extends SDKConstruct {
55
55
  }
56
56
  }
57
57
  }
58
+ /**
59
+ * Serializable snapshot of all loaded zappers, suitable for hydration.
60
+ * Returns `undefined` when zappers were never loaded (i.e. `loadZappers` was
61
+ * not called), so the not-loaded state round-trips cleanly.
62
+ **/
63
+ get zappersState() {
64
+ if (!this.#zappers) {
65
+ return void 0;
66
+ }
67
+ return this.#zappers.values().flatMap(
68
+ (zappers) => zappers.map((z) => ({
69
+ pool: z.pool,
70
+ type: z.type,
71
+ baseParams: z.baseParams,
72
+ tokenIn: z.tokenIn,
73
+ tokenOut: z.tokenOut
74
+ }))
75
+ );
76
+ }
77
+ /**
78
+ * Restores zapper state from a previously serialized snapshot,
79
+ * bypassing on-chain reads.
80
+ * @param state - Array of zapper data snapshots, or `undefined` when zappers
81
+ * were not loaded in the snapshot (leaves the registry in the not-loaded state).
82
+ **/
83
+ hydrateZappers(state) {
84
+ if (!state) {
85
+ return;
86
+ }
87
+ this.#zappers = new AddressMap(void 0, "zappers");
88
+ for (const z of state) {
89
+ this.#addZapper(z);
90
+ }
91
+ }
92
+ /**
93
+ * Returns a human-readable snapshot of all loaded zappers.
94
+ * Returns `undefined` when zappers were never loaded.
95
+ * @param raw - When `true`, includes raw/unformatted values.
96
+ **/
97
+ zappersStateHuman(_ = true) {
98
+ if (!this.#zappers) {
99
+ return void 0;
100
+ }
101
+ return this.#zappers.values().flatMap(
102
+ (zappers) => zappers.map((z) => ({
103
+ address: this.labelAddress(z.baseParams.addr),
104
+ contractType: z.contractType,
105
+ type: z.type,
106
+ pool: this.labelAddress(z.pool),
107
+ tokenIn: this.sdk.labelAddress(z.tokenIn.addr),
108
+ tokenOut: this.sdk.labelAddress(z.tokenOut.addr)
109
+ }))
110
+ );
111
+ }
58
112
  #addZapper(z) {
59
113
  const zapper = createZapper(this.sdk, z);
60
114
  const existing = this.zappers.get(z.pool);
@@ -1,25 +1,9 @@
1
1
  import { ierc20ZapperAbi } from "../../../abi/iERC20Zapper.js";
2
- import { BaseContract } from "../../base/index.js";
2
+ import { ZapperContract } from "./ZapperContract.js";
3
3
  const abi = ierc20ZapperAbi;
4
- class IERC20ZapperContract extends BaseContract {
5
- pool;
6
- type;
7
- baseParams;
8
- tokenIn;
9
- tokenOut;
4
+ class IERC20ZapperContract extends ZapperContract {
10
5
  constructor(sdk, data) {
11
- super(sdk, {
12
- addr: data.baseParams.addr,
13
- abi,
14
- name: `ERC20Zapper(${sdk.labelAddress(data.baseParams.addr)})`,
15
- version: data.baseParams.version,
16
- contractType: data.baseParams.contractType
17
- });
18
- this.pool = data.pool;
19
- this.type = data.type;
20
- this.baseParams = data.baseParams;
21
- this.tokenIn = data.tokenIn;
22
- this.tokenOut = data.tokenOut;
6
+ super(sdk, data, abi, "ERC20Zapper");
23
7
  }
24
8
  /**
25
9
  * Deposits ERC20 tokens into the pool via this zapper.
@@ -49,25 +33,6 @@ class IERC20ZapperContract extends BaseContract {
49
33
  args: [tokenInAmount, receiver, referralCode, deadline, v, r, s]
50
34
  });
51
35
  }
52
- /**
53
- * Redeems pool shares (diesel tokens) for the underlying asset via this zapper.
54
- */
55
- redeem(tokenInAmount, receiver) {
56
- return this.createRawTx({
57
- functionName: "redeem",
58
- args: [tokenInAmount, receiver]
59
- });
60
- }
61
- /**
62
- * Redeems pool shares via this zapper with an EIP-2612 permit signature,
63
- * skipping a separate approve transaction.
64
- */
65
- redeemWithPermit(tokenInAmount, receiver, deadline, v, r, s) {
66
- return this.createRawTx({
67
- functionName: "redeemWithPermit",
68
- args: [tokenInAmount, receiver, deadline, v, r, s]
69
- });
70
- }
71
36
  }
72
37
  export {
73
38
  IERC20ZapperContract
@@ -1,25 +1,9 @@
1
1
  import { iethZapperAbi } from "../../../abi/iETHZapper.js";
2
- import { BaseContract } from "../../base/index.js";
2
+ import { ZapperContract } from "./ZapperContract.js";
3
3
  const abi = iethZapperAbi;
4
- class IETHZapperContract extends BaseContract {
5
- pool;
6
- type;
7
- baseParams;
8
- tokenIn;
9
- tokenOut;
4
+ class IETHZapperContract extends ZapperContract {
10
5
  constructor(sdk, data) {
11
- super(sdk, {
12
- addr: data.baseParams.addr,
13
- abi,
14
- name: `ETHZapper(${sdk.labelAddress(data.baseParams.addr)})`,
15
- version: data.baseParams.version,
16
- contractType: data.baseParams.contractType
17
- });
18
- this.pool = data.pool;
19
- this.type = data.type;
20
- this.baseParams = data.baseParams;
21
- this.tokenIn = data.tokenIn;
22
- this.tokenOut = data.tokenOut;
6
+ super(sdk, data, abi, "ETHZapper");
23
7
  }
24
8
  /**
25
9
  * Deposits native ETH into the pool via this zapper.
@@ -40,25 +24,6 @@ class IETHZapperContract extends BaseContract {
40
24
  args: [receiver, referralCode]
41
25
  });
42
26
  }
43
- /**
44
- * Redeems pool shares (diesel tokens) for the underlying asset via this zapper.
45
- */
46
- redeem(tokenInAmount, receiver) {
47
- return this.createRawTx({
48
- functionName: "redeem",
49
- args: [tokenInAmount, receiver]
50
- });
51
- }
52
- /**
53
- * Redeems pool shares via this zapper with an EIP-2612 permit signature,
54
- * skipping a separate approve transaction.
55
- */
56
- redeemWithPermit(tokenInAmount, receiver, deadline, v, r, s) {
57
- return this.createRawTx({
58
- functionName: "redeemWithPermit",
59
- args: [tokenInAmount, receiver, deadline, v, r, s]
60
- });
61
- }
62
27
  }
63
28
  export {
64
29
  IETHZapperContract