@whetstone-research/doppler-sdk 0.0.23 → 0.0.24

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 (188) hide show
  1. package/README.md +488 -230
  2. package/dist/DopplerSDK.d.mts +12 -0
  3. package/dist/DopplerSDK.d.ts +12 -0
  4. package/dist/DopplerSDK.js +21 -19
  5. package/dist/DopplerSDK.mjs +20 -18
  6. package/dist/abis/index.d.mts +421 -10
  7. package/dist/abis/index.d.ts +421 -10
  8. package/dist/abis/index.js +31 -23
  9. package/dist/abis/index.mjs +1 -1
  10. package/dist/addresses.d.mts +4 -0
  11. package/dist/addresses.d.ts +4 -0
  12. package/dist/addresses.js +7 -7
  13. package/dist/addresses.mjs +2 -2
  14. package/dist/builders/DynamicAuctionBuilder.js +8 -8
  15. package/dist/builders/DynamicAuctionBuilder.mjs +7 -7
  16. package/dist/builders/MulticurveBuilder.d.mts +18 -5
  17. package/dist/builders/MulticurveBuilder.d.ts +18 -5
  18. package/dist/builders/MulticurveBuilder.js +8 -8
  19. package/dist/builders/MulticurveBuilder.mjs +7 -7
  20. package/dist/builders/StaticAuctionBuilder.js +8 -8
  21. package/dist/builders/StaticAuctionBuilder.mjs +7 -7
  22. package/dist/builders/index.js +12 -12
  23. package/dist/builders/index.mjs +9 -9
  24. package/dist/builders/shared.js +6 -5
  25. package/dist/builders/shared.mjs +6 -5
  26. package/dist/{chunk-EH3V2BJF.js → chunk-2A3B3NVB.js} +163 -18
  27. package/dist/chunk-2A3B3NVB.js.map +1 -0
  28. package/dist/{chunk-JB5XXPLL.js → chunk-44CYUEPG.js} +5 -5
  29. package/dist/{chunk-JB5XXPLL.js.map → chunk-44CYUEPG.js.map} +1 -1
  30. package/dist/{chunk-GSTY3GO7.mjs → chunk-5GQJRNFL.mjs} +3 -3
  31. package/dist/{chunk-GSTY3GO7.mjs.map → chunk-5GQJRNFL.mjs.map} +1 -1
  32. package/dist/{chunk-YFEPTSI2.js → chunk-5JHXBDZD.js} +20 -20
  33. package/dist/{chunk-YFEPTSI2.js.map → chunk-5JHXBDZD.js.map} +1 -1
  34. package/dist/{chunk-OX5CESVM.js → chunk-65CESA3J.js} +19 -13
  35. package/dist/chunk-65CESA3J.js.map +1 -0
  36. package/dist/{chunk-7CAAI5DL.js → chunk-7A4DBBXA.js} +141 -103
  37. package/dist/chunk-7A4DBBXA.js.map +1 -0
  38. package/dist/{chunk-RXUJ4DUB.js → chunk-A2CJYRRQ.js} +28 -28
  39. package/dist/{chunk-RXUJ4DUB.js.map → chunk-A2CJYRRQ.js.map} +1 -1
  40. package/dist/{chunk-6UHDSD42.js → chunk-BK3S6SVR.js} +209 -87
  41. package/dist/chunk-BK3S6SVR.js.map +1 -0
  42. package/dist/{chunk-XT3BAM4H.js → chunk-BQZTELUX.js} +5 -5
  43. package/dist/{chunk-XT3BAM4H.js.map → chunk-BQZTELUX.js.map} +1 -1
  44. package/dist/{chunk-FZ4FIWCR.js → chunk-CFXXUZJY.js} +57 -22
  45. package/dist/chunk-CFXXUZJY.js.map +1 -0
  46. package/dist/chunk-DCWF3EMP.js +171 -0
  47. package/dist/chunk-DCWF3EMP.js.map +1 -0
  48. package/dist/{chunk-VCX6FG3E.mjs → chunk-DQJXCZU2.mjs} +3 -3
  49. package/dist/{chunk-VCX6FG3E.mjs.map → chunk-DQJXCZU2.mjs.map} +1 -1
  50. package/dist/chunk-F2BYG63D.mjs +145 -0
  51. package/dist/chunk-F2BYG63D.mjs.map +1 -0
  52. package/dist/chunk-FXTGIKQG.mjs +3 -0
  53. package/dist/{chunk-SD7BHT2F.mjs.map → chunk-FXTGIKQG.mjs.map} +1 -1
  54. package/dist/chunk-IIM2CSDQ.js +147 -0
  55. package/dist/chunk-IIM2CSDQ.js.map +1 -0
  56. package/dist/{chunk-RI6SDMER.mjs → chunk-IUTIHSLH.mjs} +4 -4
  57. package/dist/{chunk-RI6SDMER.mjs.map → chunk-IUTIHSLH.mjs.map} +1 -1
  58. package/dist/chunk-IUZ3BBQP.mjs +117 -0
  59. package/dist/chunk-IUZ3BBQP.mjs.map +1 -0
  60. package/dist/{chunk-CATH4QRQ.mjs → chunk-IX4V4UGW.mjs} +4 -4
  61. package/dist/{chunk-CATH4QRQ.mjs.map → chunk-IX4V4UGW.mjs.map} +1 -1
  62. package/dist/{chunk-E2NF4AQB.mjs → chunk-JLUOFAE4.mjs} +272 -12
  63. package/dist/chunk-JLUOFAE4.mjs.map +1 -0
  64. package/dist/{chunk-7P2SPZC7.mjs → chunk-LW3CYA27.mjs} +178 -56
  65. package/dist/chunk-LW3CYA27.mjs.map +1 -0
  66. package/dist/{chunk-TIGHBA37.js → chunk-MEA2C5YX.js} +16 -16
  67. package/dist/{chunk-TIGHBA37.js.map → chunk-MEA2C5YX.js.map} +1 -1
  68. package/dist/{chunk-3MVW6UIW.js → chunk-MU56HCUI.js} +273 -11
  69. package/dist/chunk-MU56HCUI.js.map +1 -0
  70. package/dist/chunk-OCIY7QEJ.mjs +169 -0
  71. package/dist/chunk-OCIY7QEJ.mjs.map +1 -0
  72. package/dist/{chunk-CMNJZKTM.js → chunk-P563HTVU.js} +50 -26
  73. package/dist/chunk-P563HTVU.js.map +1 -0
  74. package/dist/chunk-PGYTMRP3.js +277 -0
  75. package/dist/chunk-PGYTMRP3.js.map +1 -0
  76. package/dist/{chunk-QOGBOT2M.mjs → chunk-QHBKRUBY.mjs} +3 -3
  77. package/dist/{chunk-QOGBOT2M.mjs.map → chunk-QHBKRUBY.mjs.map} +1 -1
  78. package/dist/chunk-QOYI7WCH.js +120 -0
  79. package/dist/chunk-QOYI7WCH.js.map +1 -0
  80. package/dist/{chunk-EIXUJANI.mjs → chunk-QUBD6HUZ.mjs} +161 -16
  81. package/dist/chunk-QUBD6HUZ.mjs.map +1 -0
  82. package/dist/{chunk-FFV6DMPA.mjs → chunk-RDTIXP6S.mjs} +4 -4
  83. package/dist/{chunk-FFV6DMPA.mjs.map → chunk-RDTIXP6S.mjs.map} +1 -1
  84. package/dist/{chunk-FTRCBE3J.js → chunk-RLOZWHRR.js} +5 -5
  85. package/dist/{chunk-FTRCBE3J.js.map → chunk-RLOZWHRR.js.map} +1 -1
  86. package/dist/chunk-T3UA4MJL.js +4 -0
  87. package/dist/{chunk-3PNCB4W5.js.map → chunk-T3UA4MJL.js.map} +1 -1
  88. package/dist/{chunk-C6MH7HYT.mjs → chunk-TEWAXP5C.mjs} +36 -12
  89. package/dist/chunk-TEWAXP5C.mjs.map +1 -0
  90. package/dist/{chunk-FLFYAWSS.mjs → chunk-THEIRDGE.mjs} +50 -15
  91. package/dist/chunk-THEIRDGE.mjs.map +1 -0
  92. package/dist/chunk-VKSD3KXF.mjs +275 -0
  93. package/dist/chunk-VKSD3KXF.mjs.map +1 -0
  94. package/dist/{chunk-RIIVW6TQ.mjs → chunk-WDC53TM7.mjs} +47 -9
  95. package/dist/chunk-WDC53TM7.mjs.map +1 -0
  96. package/dist/{chunk-TLEVIIUE.mjs → chunk-WKWP42TD.mjs} +9 -4
  97. package/dist/chunk-WKWP42TD.mjs.map +1 -0
  98. package/dist/{chunk-HL7ZAAD4.mjs → chunk-WNWK2QMU.mjs} +3 -3
  99. package/dist/{chunk-HL7ZAAD4.mjs.map → chunk-WNWK2QMU.mjs.map} +1 -1
  100. package/dist/{chunk-H7WPK5CR.js → chunk-WZF5XNBC.js} +26 -26
  101. package/dist/{chunk-H7WPK5CR.js.map → chunk-WZF5XNBC.js.map} +1 -1
  102. package/dist/deployments.generated.d.mts +46 -38
  103. package/dist/deployments.generated.d.ts +46 -38
  104. package/dist/deployments.generated.js +2 -2
  105. package/dist/deployments.generated.mjs +1 -1
  106. package/dist/entities/DopplerFactory.d.mts +7 -1
  107. package/dist/entities/DopplerFactory.d.ts +7 -1
  108. package/dist/entities/DopplerFactory.js +8 -7
  109. package/dist/entities/DopplerFactory.mjs +7 -6
  110. package/dist/entities/auction/DynamicAuction.js +5 -5
  111. package/dist/entities/auction/DynamicAuction.mjs +4 -4
  112. package/dist/entities/auction/MulticurvePool.d.mts +6 -2
  113. package/dist/entities/auction/MulticurvePool.d.ts +6 -2
  114. package/dist/entities/auction/MulticurvePool.js +6 -6
  115. package/dist/entities/auction/MulticurvePool.mjs +5 -5
  116. package/dist/entities/auction/RehypeDopplerHook.d.mts +57 -0
  117. package/dist/entities/auction/RehypeDopplerHook.d.ts +57 -0
  118. package/dist/entities/auction/RehypeDopplerHook.js +34 -0
  119. package/dist/entities/auction/RehypeDopplerHook.js.map +1 -0
  120. package/dist/entities/auction/RehypeDopplerHook.mjs +25 -0
  121. package/dist/entities/auction/RehypeDopplerHook.mjs.map +1 -0
  122. package/dist/entities/auction/RehypeDopplerHookMigrator.d.mts +48 -0
  123. package/dist/entities/auction/RehypeDopplerHookMigrator.d.ts +48 -0
  124. package/dist/entities/auction/RehypeDopplerHookMigrator.js +34 -0
  125. package/dist/entities/auction/RehypeDopplerHookMigrator.js.map +1 -0
  126. package/dist/entities/auction/RehypeDopplerHookMigrator.mjs +25 -0
  127. package/dist/entities/auction/RehypeDopplerHookMigrator.mjs.map +1 -0
  128. package/dist/entities/auction/StaticAuction.js +5 -5
  129. package/dist/entities/auction/StaticAuction.mjs +4 -4
  130. package/dist/entities/auction/index.d.mts +2 -0
  131. package/dist/entities/auction/index.d.ts +2 -0
  132. package/dist/entities/auction/index.js +31 -11
  133. package/dist/entities/auction/index.mjs +20 -8
  134. package/dist/entities/quoter/Quoter.js +5 -5
  135. package/dist/entities/quoter/Quoter.mjs +4 -4
  136. package/dist/entities/quoter/index.js +5 -5
  137. package/dist/entities/quoter/index.mjs +4 -4
  138. package/dist/entities/token/derc20/Derc20.js +3 -3
  139. package/dist/entities/token/derc20/Derc20.mjs +2 -2
  140. package/dist/entities/token/derc20/index.js +3 -3
  141. package/dist/entities/token/derc20/index.mjs +2 -2
  142. package/dist/entities/token/index.js +7 -7
  143. package/dist/entities/token/index.mjs +3 -3
  144. package/dist/index.d.mts +4 -2
  145. package/dist/index.d.ts +4 -2
  146. package/dist/index.js +86 -64
  147. package/dist/index.js.map +1 -1
  148. package/dist/index.mjs +20 -18
  149. package/dist/index.mjs.map +1 -1
  150. package/dist/types.d.mts +65 -10
  151. package/dist/types.d.ts +65 -10
  152. package/dist/types.js +12 -8
  153. package/dist/types.mjs +3 -3
  154. package/dist/utils/airlock.js +7 -7
  155. package/dist/utils/airlock.mjs +3 -3
  156. package/dist/utils/dopplerHookMigrator.d.mts +9 -2
  157. package/dist/utils/dopplerHookMigrator.d.ts +9 -2
  158. package/dist/utils/dopplerHookMigrator.js +10 -2
  159. package/dist/utils/dopplerHookMigrator.mjs +5 -1
  160. package/dist/utils/index.js +12 -10
  161. package/dist/utils/index.mjs +7 -5
  162. package/dist/utils/tokenAddressMiner.js +1 -1
  163. package/dist/utils/tokenAddressMiner.mjs +1 -1
  164. package/package.json +2 -2
  165. package/dist/chunk-3MVW6UIW.js.map +0 -1
  166. package/dist/chunk-3PNCB4W5.js +0 -4
  167. package/dist/chunk-6UHDSD42.js.map +0 -1
  168. package/dist/chunk-7CAAI5DL.js.map +0 -1
  169. package/dist/chunk-7P2SPZC7.mjs.map +0 -1
  170. package/dist/chunk-C6MH7HYT.mjs.map +0 -1
  171. package/dist/chunk-CMNJZKTM.js.map +0 -1
  172. package/dist/chunk-DNB3T5P2.js +0 -269
  173. package/dist/chunk-DNB3T5P2.js.map +0 -1
  174. package/dist/chunk-E2NF4AQB.mjs.map +0 -1
  175. package/dist/chunk-EH3V2BJF.js.map +0 -1
  176. package/dist/chunk-EIXUJANI.mjs.map +0 -1
  177. package/dist/chunk-FLFYAWSS.mjs.map +0 -1
  178. package/dist/chunk-FZ4FIWCR.js.map +0 -1
  179. package/dist/chunk-GDODJJ7D.mjs +0 -36
  180. package/dist/chunk-GDODJJ7D.mjs.map +0 -1
  181. package/dist/chunk-OX5CESVM.js.map +0 -1
  182. package/dist/chunk-RIIVW6TQ.mjs.map +0 -1
  183. package/dist/chunk-SD7BHT2F.mjs +0 -3
  184. package/dist/chunk-TLEVIIUE.mjs.map +0 -1
  185. package/dist/chunk-WJBJARLJ.js +0 -38
  186. package/dist/chunk-WJBJARLJ.js.map +0 -1
  187. package/dist/chunk-XRYLHTVV.mjs +0 -267
  188. package/dist/chunk-XRYLHTVV.mjs.map +0 -1
package/README.md CHANGED
@@ -60,12 +60,25 @@ const sdk = new DopplerSDK({
60
60
  Static auctions use Uniswap V3 pools with concentrated liquidity in a fixed price range. They're ideal for simple, predictable price discovery.
61
61
 
62
62
  ```typescript
63
- import { StaticAuctionBuilder } from '@whetstone-research/doppler-sdk'
63
+ import { StaticAuctionBuilder } from '@whetstone-research/doppler-sdk';
64
64
 
65
65
  const params = new StaticAuctionBuilder()
66
- .tokenConfig({ name: 'My Token', symbol: 'MTK', tokenURI: 'https://example.com/metadata.json' })
67
- .saleConfig({ initialSupply: parseEther('1000000000'), numTokensToSell: parseEther('900000000'), numeraire: '0x...' })
68
- .poolByTicks({ startTick: -92200, endTick: -69000, fee: 10000, numPositions: 15 })
66
+ .tokenConfig({
67
+ name: 'My Token',
68
+ symbol: 'MTK',
69
+ tokenURI: 'https://example.com/metadata.json',
70
+ })
71
+ .saleConfig({
72
+ initialSupply: parseEther('1000000000'),
73
+ numTokensToSell: parseEther('900000000'),
74
+ numeraire: '0x...',
75
+ })
76
+ .poolByTicks({
77
+ startTick: -92200,
78
+ endTick: -69000,
79
+ fee: 10000,
80
+ numPositions: 15,
81
+ })
69
82
  .withVesting({
70
83
  duration: BigInt(365 * 24 * 60 * 60),
71
84
  // Optional: specify multiple recipients and amounts
@@ -74,11 +87,11 @@ const params = new StaticAuctionBuilder()
74
87
  })
75
88
  .withMigration({ type: 'uniswapV2' })
76
89
  .withUserAddress('0x...')
77
- .build()
90
+ .build();
78
91
 
79
- const result = await sdk.factory.createStaticAuction(params)
80
- console.log('Pool address:', result.poolAddress)
81
- console.log('Token address:', result.tokenAddress)
92
+ const result = await sdk.factory.createStaticAuction(params);
93
+ console.log('Pool address:', result.poolAddress);
94
+ console.log('Token address:', result.tokenAddress);
82
95
  ```
83
96
 
84
97
  > **Tick spacing reminder:** When you provide ticks manually via `poolByTicks`, make sure both `startTick` and `endTick` are exact multiples of the fee tier's tick spacing (100→1, 500→10, 3000→60, 10000→200). The SDK now validates this locally and will fail fast if the ticks are misaligned.
@@ -88,38 +101,51 @@ console.log('Token address:', result.tokenAddress)
88
101
  When you want fee revenue to flow to specific addresses without migrating liquidity, use lockable beneficiaries. The pool enters a "Locked" state where trading fees are collected and distributed to beneficiaries:
89
102
 
90
103
  ```typescript
91
- import { StaticAuctionBuilder, WAD, getAirlockOwner } from '@whetstone-research/doppler-sdk'
92
- import { parseEther } from 'viem'
104
+ import {
105
+ StaticAuctionBuilder,
106
+ WAD,
107
+ getAirlockOwner,
108
+ } from '@whetstone-research/doppler-sdk';
109
+ import { parseEther } from 'viem';
93
110
 
94
111
  // Get the protocol owner (required beneficiary with min 5%)
95
- const protocolOwner = await getAirlockOwner(publicClient)
112
+ const protocolOwner = await getAirlockOwner(publicClient);
96
113
 
97
114
  // Define beneficiaries - shares must sum to WAD (1e18 = 100%)
98
115
  const beneficiaries = [
99
- { beneficiary: protocolOwner, shares: parseEther('0.05') }, // 5% (minimum required)
100
- { beneficiary: '0xTeamWallet...', shares: parseEther('0.45') }, // 45%
116
+ { beneficiary: protocolOwner, shares: parseEther('0.05') }, // 5% (minimum required)
117
+ { beneficiary: '0xTeamWallet...', shares: parseEther('0.45') }, // 45%
101
118
  { beneficiary: '0xDAOTreasury...', shares: parseEther('0.50') }, // 50%
102
- ]
119
+ ];
103
120
 
104
121
  const params = new StaticAuctionBuilder(chainId)
105
- .tokenConfig({ name: 'My Token', symbol: 'MTK', tokenURI: 'https://example.com/metadata.json' })
106
- .saleConfig({ initialSupply: parseEther('1000000000'), numTokensToSell: parseEther('900000000'), numeraire: wethAddress })
122
+ .tokenConfig({
123
+ name: 'My Token',
124
+ symbol: 'MTK',
125
+ tokenURI: 'https://example.com/metadata.json',
126
+ })
127
+ .saleConfig({
128
+ initialSupply: parseEther('1000000000'),
129
+ numTokensToSell: parseEther('900000000'),
130
+ numeraire: wethAddress,
131
+ })
107
132
  .poolByTicks({
108
- startTick: 174960, // Must be multiple of 60 for fee 3000
133
+ startTick: 174960, // Must be multiple of 60 for fee 3000
109
134
  endTick: 225000,
110
- fee: 3000, // Set > 0 to accumulate fees for beneficiaries
135
+ fee: 3000, // Set > 0 to accumulate fees for beneficiaries
111
136
  })
112
- .withBeneficiaries(beneficiaries) // Lock pool and enable fee streaming
113
- .withMigration({ type: 'noOp' }) // Use NoOp since pool is locked
137
+ .withBeneficiaries(beneficiaries) // Lock pool and enable fee streaming
138
+ .withMigration({ type: 'noOp' }) // Use NoOp since pool is locked
114
139
  .withGovernance({ type: 'default' })
115
140
  .withUserAddress('0x...')
116
- .build()
141
+ .build();
117
142
 
118
- const result = await sdk.factory.createStaticAuction(params)
119
- console.log('Pool address:', result.poolAddress) // SAVE THIS - needed to collect fees!
143
+ const result = await sdk.factory.createStaticAuction(params);
144
+ console.log('Pool address:', result.poolAddress); // SAVE THIS - needed to collect fees!
120
145
  ```
121
146
 
122
147
  **Important Notes:**
148
+
123
149
  - **Shares must sum to exactly WAD (1e18 = 100%)**
124
150
  - **Protocol owner must receive at least 5%** of fees
125
151
  - **SDK automatically sorts beneficiaries** by address (ascending)
@@ -135,11 +161,22 @@ See [examples/static-auction-lockable-beneficiaries.ts](./examples/static-auctio
135
161
  Dynamic auctions use Uniswap V4 hooks to implement gradual Dutch auctions where the price moves over time.
136
162
 
137
163
  ```typescript
138
- import { DynamicAuctionBuilder, DAY_SECONDS } from '@whetstone-research/doppler-sdk'
164
+ import {
165
+ DynamicAuctionBuilder,
166
+ DAY_SECONDS,
167
+ } from '@whetstone-research/doppler-sdk';
139
168
 
140
169
  const params = new DynamicAuctionBuilder()
141
- .tokenConfig({ name: 'My Token', symbol: 'MTK', tokenURI: 'https://example.com/metadata.json' })
142
- .saleConfig({ initialSupply: parseEther('1000000'), numTokensToSell: parseEther('900000'), numeraire: '0x...' })
170
+ .tokenConfig({
171
+ name: 'My Token',
172
+ symbol: 'MTK',
173
+ tokenURI: 'https://example.com/metadata.json',
174
+ })
175
+ .saleConfig({
176
+ initialSupply: parseEther('1000000'),
177
+ numTokensToSell: parseEther('900000'),
178
+ numeraire: '0x...',
179
+ })
143
180
  .poolConfig({ fee: 3000, tickSpacing: 60 })
144
181
  .auctionByTicks({
145
182
  duration: 7 * DAY_SECONDS,
@@ -179,11 +216,11 @@ const params = new DynamicAuctionBuilder()
179
216
  // .withV3Migrator('0xV3Migrator...')
180
217
  // .withV4Migrator('0xV4Migrator...')
181
218
  .withUserAddress('0x...')
182
- .build()
219
+ .build();
183
220
 
184
- const result = await sdk.factory.createDynamicAuction(params)
185
- console.log('Hook address:', result.hookAddress)
186
- console.log('Token address:', result.tokenAddress)
221
+ const result = await sdk.factory.createDynamicAuction(params);
222
+ console.log('Hook address:', result.hookAddress);
223
+ console.log('Token address:', result.tokenAddress);
187
224
  ```
188
225
 
189
226
  ### Multicurve Auction (V4 Multicurve Initializer)
@@ -191,42 +228,70 @@ console.log('Token address:', result.tokenAddress)
191
228
  Multicurve auctions use a Uniswap V4-style initializer that seeds liquidity across multiple curves in a single pool. This enables richer distributions and can be combined with any supported migration path (V2, V3, V4, or NoOp). Multicurve initializer modes are modeled as a typed variant (`standard`, `scheduled`, `decay`, `rehype`) so new hook/initializer variations can be added without breaking existing integrations.
192
229
 
193
230
  **Standard Multicurve with Migration:**
231
+
194
232
  ```typescript
195
- import { MulticurveBuilder } from '@whetstone-research/doppler-sdk'
196
- import { parseEther } from 'viem'
197
- import { base } from 'viem/chains'
233
+ import { MulticurveBuilder } from '@whetstone-research/doppler-sdk';
234
+ import { parseEther } from 'viem';
235
+ import { base } from 'viem/chains';
198
236
 
199
237
  const params = new MulticurveBuilder(base.id)
200
- .tokenConfig({ name: 'My Token', symbol: 'MTK', tokenURI: 'https://example.com/metadata.json' })
201
- .saleConfig({ initialSupply: parseEther('1000000'), numTokensToSell: parseEther('900000'), numeraire: '0x...' })
238
+ .tokenConfig({
239
+ name: 'My Token',
240
+ symbol: 'MTK',
241
+ tokenURI: 'https://example.com/metadata.json',
242
+ })
243
+ .saleConfig({
244
+ initialSupply: parseEther('1000000'),
245
+ numTokensToSell: parseEther('900000'),
246
+ numeraire: '0x...',
247
+ })
202
248
  .poolConfig({
203
249
  fee: 0,
204
250
  tickSpacing: 8,
205
251
  curves: [
206
- { tickLower: 0, tickUpper: 240000, numPositions: 10, shares: parseEther('0.5') },
207
- { tickLower: 16000, tickUpper: 240000, numPositions: 10, shares: parseEther('0.5') },
252
+ {
253
+ tickLower: 0,
254
+ tickUpper: 240000,
255
+ numPositions: 10,
256
+ shares: parseEther('0.5'),
257
+ },
258
+ {
259
+ tickLower: 16000,
260
+ tickUpper: 240000,
261
+ numPositions: 10,
262
+ shares: parseEther('0.5'),
263
+ },
208
264
  ],
209
265
  })
210
266
  .withGovernance({ type: 'default' })
211
267
  // Choose a migration path (V2, V3, or V4)
212
268
  .withMigration({ type: 'uniswapV2' })
213
269
  .withUserAddress('0x...')
214
- .build()
270
+ .build();
215
271
 
216
- const result = await sdk.factory.createMulticurve(params)
217
- console.log('Pool address:', result.poolAddress)
218
- console.log('Token address:', result.tokenAddress)
272
+ const result = await sdk.factory.createMulticurve(params);
273
+ console.log('Pool address:', result.poolAddress);
274
+ console.log('Token address:', result.tokenAddress);
219
275
  ```
220
276
 
221
277
  **Market Cap Presets (Low / Medium / High):**
278
+
222
279
  ```typescript
223
- import { MulticurveBuilder, FEE_TIERS } from '@whetstone-research/doppler-sdk'
224
- import { parseEther } from 'viem'
225
- import { base } from 'viem/chains'
280
+ import { MulticurveBuilder, FEE_TIERS } from '@whetstone-research/doppler-sdk';
281
+ import { parseEther } from 'viem';
282
+ import { base } from 'viem/chains';
226
283
 
227
284
  const presetParams = new MulticurveBuilder(base.id)
228
- .tokenConfig({ name: 'Preset Launch', symbol: 'PRST', tokenURI: 'ipfs://preset.json' })
229
- .saleConfig({ initialSupply: parseEther('1000000'), numTokensToSell: parseEther('900000'), numeraire: '0x...' })
285
+ .tokenConfig({
286
+ name: 'Preset Launch',
287
+ symbol: 'PRST',
288
+ tokenURI: 'ipfs://preset.json',
289
+ })
290
+ .saleConfig({
291
+ initialSupply: parseEther('1000000'),
292
+ numTokensToSell: parseEther('900000'),
293
+ numeraire: '0x...',
294
+ })
230
295
  .withMarketCapPresets({
231
296
  fee: FEE_TIERS.LOW, // defaults to 0.05% fee tier (tick spacing 10)
232
297
  presets: ['low', 'medium', 'high'], // defaults to all tiers
@@ -235,14 +300,15 @@ const presetParams = new MulticurveBuilder(base.id)
235
300
  .withGovernance({ type: 'default' })
236
301
  .withMigration({ type: 'uniswapV2' })
237
302
  .withUserAddress('0x...')
238
- .build()
303
+ .build();
239
304
 
240
- const presetResult = await sdk.factory.createMulticurve(presetParams)
241
- console.log('Pool address:', presetResult.poolAddress)
242
- console.log('Token address:', presetResult.tokenAddress)
305
+ const presetResult = await sdk.factory.createMulticurve(presetParams);
306
+ console.log('Pool address:', presetResult.poolAddress);
307
+ console.log('Token address:', presetResult.tokenAddress);
243
308
  ```
244
309
 
245
310
  The preset helper seeds three curated curve buckets sized for ~1B token supply targets:
311
+
246
312
  - `low`: ~5% of the sale allocated to a $7.5k-$30k market cap window.
247
313
  - `medium`: ~12.5% targeting roughly $50k-$150k market caps.
248
314
  - `high`: ~20% aimed at $250k-$750k market caps.
@@ -250,69 +316,107 @@ The preset helper seeds three curated curve buckets sized for ~1B token supply t
250
316
  Pass `presets` to pick a subset (e.g. `['medium', 'high']`) or provide `overrides` to adjust ticks, positions, or shares for a specific tier. When the selected presets sum to less than 100%, the builder automatically appends a filler curve (using the highest selected tier's shape) so liquidity always covers the full sale. Shares must stay within 0-1e18 and the helper will throw if the total ever exceeds 100%.
251
317
 
252
318
  **Scheduled Multicurve Launch:**
319
+
253
320
  ```typescript
254
- import { MulticurveBuilder } from '@whetstone-research/doppler-sdk'
255
- import { parseEther } from 'viem'
256
- import { base } from 'viem/chains'
321
+ import { MulticurveBuilder } from '@whetstone-research/doppler-sdk';
322
+ import { parseEther } from 'viem';
323
+ import { base } from 'viem/chains';
257
324
 
258
- const startTime = Math.floor(Date.now() / 1000) + 3600 // one hour from now
325
+ const startTime = Math.floor(Date.now() / 1000) + 3600; // one hour from now
259
326
 
260
327
  const scheduled = new MulticurveBuilder(base.id)
261
- .tokenConfig({ name: 'My Token', symbol: 'MTK', tokenURI: 'ipfs://scheduled.json' })
262
- .saleConfig({ initialSupply: parseEther('1000000'), numTokensToSell: parseEther('900000'), numeraire: '0x4200000000000000000000000000000000000006' })
328
+ .tokenConfig({
329
+ name: 'My Token',
330
+ symbol: 'MTK',
331
+ tokenURI: 'ipfs://scheduled.json',
332
+ })
333
+ .saleConfig({
334
+ initialSupply: parseEther('1000000'),
335
+ numTokensToSell: parseEther('900000'),
336
+ numeraire: '0x4200000000000000000000000000000000000006',
337
+ })
263
338
  .poolConfig({
264
339
  fee: 0,
265
340
  tickSpacing: 8,
266
341
  curves: [
267
- { tickLower: 0, tickUpper: 240000, numPositions: 12, shares: parseEther('0.5') },
268
- { tickLower: 16000, tickUpper: 240000, numPositions: 12, shares: parseEther('0.5') },
342
+ {
343
+ tickLower: 0,
344
+ tickUpper: 240000,
345
+ numPositions: 12,
346
+ shares: parseEther('0.5'),
347
+ },
348
+ {
349
+ tickLower: 16000,
350
+ tickUpper: 240000,
351
+ numPositions: 12,
352
+ shares: parseEther('0.5'),
353
+ },
269
354
  ],
270
355
  })
271
356
  .withSchedule({ startTime })
272
357
  .withGovernance({ type: 'default' })
273
358
  .withMigration({ type: 'uniswapV2' })
274
359
  .withUserAddress('0x...')
275
- .build()
360
+ .build();
276
361
 
277
- const scheduledResult = await sdk.factory.createMulticurve(scheduled)
278
- console.log('Pool address:', scheduledResult.poolAddress)
279
- console.log('Token address:', scheduledResult.tokenAddress)
362
+ const scheduledResult = await sdk.factory.createMulticurve(scheduled);
363
+ console.log('Pool address:', scheduledResult.poolAddress);
364
+ console.log('Token address:', scheduledResult.tokenAddress);
280
365
  ```
281
366
 
282
367
  Ensure the target chain has the scheduled multicurve initializer whitelisted. If you are targeting a custom deployment, override it via `.withV4ScheduledMulticurveInitializer('0x...')`.
283
368
 
284
369
  **Decay Multicurve Launch (Dynamic Fee):**
370
+
285
371
  ```typescript
286
- import { MulticurveBuilder } from '@whetstone-research/doppler-sdk'
287
- import { parseEther } from 'viem'
288
- import { baseSepolia } from 'viem/chains'
372
+ import { MulticurveBuilder } from '@whetstone-research/doppler-sdk';
373
+ import { parseEther } from 'viem';
374
+ import { baseSepolia } from 'viem/chains';
289
375
 
290
- const startTime = Math.floor(Date.now() / 1000) + 300
376
+ const startTime = Math.floor(Date.now() / 1000) + 300;
291
377
 
292
378
  const decay = new MulticurveBuilder(baseSepolia.id)
293
- .tokenConfig({ name: 'Decay Token', symbol: 'DMC', tokenURI: 'ipfs://decay.json' })
294
- .saleConfig({ initialSupply: parseEther('1000000'), numTokensToSell: parseEther('900000'), numeraire: '0x4200000000000000000000000000000000000006' })
379
+ .tokenConfig({
380
+ name: 'Decay Token',
381
+ symbol: 'DMC',
382
+ tokenURI: 'ipfs://decay.json',
383
+ })
384
+ .saleConfig({
385
+ initialSupply: parseEther('1000000'),
386
+ numTokensToSell: parseEther('900000'),
387
+ numeraire: '0x4200000000000000000000000000000000000006',
388
+ })
295
389
  .poolConfig({
296
390
  fee: 500, // terminal fee (0.05%)
297
391
  tickSpacing: 10,
298
392
  curves: [
299
- { tickLower: 0, tickUpper: 220000, numPositions: 12, shares: parseEther('0.5') },
300
- { tickLower: 20000, tickUpper: 220000, numPositions: 12, shares: parseEther('0.5') },
393
+ {
394
+ tickLower: 0,
395
+ tickUpper: 220000,
396
+ numPositions: 12,
397
+ shares: parseEther('0.5'),
398
+ },
399
+ {
400
+ tickLower: 20000,
401
+ tickUpper: 220000,
402
+ numPositions: 12,
403
+ shares: parseEther('0.5'),
404
+ },
301
405
  ],
302
406
  })
303
407
  .withDecay({
304
408
  startTime,
305
- startFee: 3000, // starts at 0.3%
409
+ startFee: 3000, // starts at 0.3%
306
410
  durationSeconds: 3600, // decays to pool.fee over 1 hour
307
411
  })
308
412
  .withGovernance({ type: 'default' })
309
413
  .withMigration({ type: 'uniswapV2' })
310
414
  .withUserAddress('0x...')
311
- .build()
415
+ .build();
312
416
 
313
- const decayResult = await sdk.factory.createMulticurve(decay)
314
- console.log('Pool address:', decayResult.poolAddress)
315
- console.log('Token address:', decayResult.tokenAddress)
417
+ const decayResult = await sdk.factory.createMulticurve(decay);
418
+ console.log('Pool address:', decayResult.poolAddress);
419
+ console.log('Token address:', decayResult.tokenAddress);
316
420
  ```
317
421
 
318
422
  For decay pools, `pool.fee` is always the terminal fee (`endFee`) of the schedule. `withDecay({ startTime })` is optional; if omitted, `startTime` defaults to `0`. The SDK supports `startFee` values up to `800_000` (80%) for anti-sniping configurations. Ensure your deployed decay initializer/hook also supports the same max start fee. Override the decay initializer module with `.withV4DecayMulticurveInitializer('0x...')` when targeting custom deployments.
@@ -322,36 +426,54 @@ For decay pools, `pool.fee` is always the terminal fee (`endFee`) of the schedul
322
426
  When you want fee revenue to flow to specific addresses without migrating liquidity after the auction, use lockable beneficiaries with NoOp migration:
323
427
 
324
428
  ```typescript
325
- import { WAD } from '@whetstone-research/doppler-sdk'
429
+ import { WAD } from '@whetstone-research/doppler-sdk';
326
430
 
327
431
  // Define beneficiaries with shares that sum to WAD (1e18 = 100%)
328
432
  // IMPORTANT: Protocol owner must be included with at least 5% shares
329
433
  const lockableBeneficiaries = [
330
- { beneficiary: '0xProtocolOwner...', shares: WAD / 10n }, // 10% to protocol (>= 5% required)
434
+ { beneficiary: '0xProtocolOwner...', shares: WAD / 10n }, // 10% to protocol (>= 5% required)
331
435
  { beneficiary: '0xYourAddress...', shares: (WAD * 4n) / 10n }, // 40%
332
- { beneficiary: '0xOtherAddress...', shares: WAD / 2n }, // 50%
333
- ]
436
+ { beneficiary: '0xOtherAddress...', shares: WAD / 2n }, // 50%
437
+ ];
334
438
 
335
439
  const params = new MulticurveBuilder(base.id)
336
- .tokenConfig({ name: 'My Token', symbol: 'MTK', tokenURI: 'https://example.com/metadata.json' })
337
- .saleConfig({ initialSupply: parseEther('1000000'), numTokensToSell: parseEther('900000'), numeraire: '0x...' })
440
+ .tokenConfig({
441
+ name: 'My Token',
442
+ symbol: 'MTK',
443
+ tokenURI: 'https://example.com/metadata.json',
444
+ })
445
+ .saleConfig({
446
+ initialSupply: parseEther('1000000'),
447
+ numTokensToSell: parseEther('900000'),
448
+ numeraire: '0x...',
449
+ })
338
450
  .poolConfig({
339
451
  fee: 3000, // 0.3% fee tier - set > 0 to accumulate fees for beneficiaries
340
452
  tickSpacing: 8,
341
453
  curves: [
342
- { tickLower: 0, tickUpper: 240000, numPositions: 10, shares: parseEther('0.5') },
343
- { tickLower: 16000, tickUpper: 240000, numPositions: 10, shares: parseEther('0.5') },
454
+ {
455
+ tickLower: 0,
456
+ tickUpper: 240000,
457
+ numPositions: 10,
458
+ shares: parseEther('0.5'),
459
+ },
460
+ {
461
+ tickLower: 16000,
462
+ tickUpper: 240000,
463
+ numPositions: 10,
464
+ shares: parseEther('0.5'),
465
+ },
344
466
  ],
345
467
  beneficiaries: lockableBeneficiaries, // Add beneficiaries for fee streaming
346
468
  })
347
469
  .withGovernance({ type: 'default' })
348
470
  .withMigration({ type: 'noOp' }) // Use NoOp migration with lockable beneficiaries
349
471
  .withUserAddress('0x...')
350
- .build()
472
+ .build();
351
473
 
352
- const result = await sdk.factory.createMulticurve(params)
353
- const assetAddress = result.tokenAddress // SAVE THIS - you'll need it to collect fees!
354
- console.log('Asset address:', assetAddress)
474
+ const result = await sdk.factory.createMulticurve(params);
475
+ const assetAddress = result.tokenAddress; // SAVE THIS - you'll need it to collect fees!
476
+ console.log('Asset address:', assetAddress);
355
477
 
356
478
  // Later, to collect fees (works before and after migration):
357
479
  // const pool = await sdk.getMulticurvePool(assetAddress)
@@ -359,6 +481,7 @@ console.log('Asset address:', assetAddress)
359
481
  ```
360
482
 
361
483
  **Important Notes:**
484
+
362
485
  - Set `fee` > 0 (e.g., 3000 for 0.3%) to accumulate trading fees for beneficiaries
363
486
  - **Save the asset address** (token address) returned from creation - you need it to collect fees later
364
487
  - Beneficiaries receive fees proportional to their shares when `collectFees()` is called
@@ -369,25 +492,35 @@ console.log('Asset address:', assetAddress)
369
492
  See [examples/multicurve-lockable-beneficiaries.ts](./examples/multicurve-lockable-beneficiaries.ts) for a complete example.
370
493
 
371
494
  #### Transaction gas override
495
+
372
496
  - You can pass a gas limit to factory create calls via the `gas` field on `CreateStaticAuctionParams` / `CreateDynamicAuctionParams` / `CreateMulticurveParams`.
373
497
  - If omitted, the SDK uses the simulation's gas estimate when available, falling back to 13,500,000 gas for the `create()` transaction.
374
498
  - `simulateCreate*` helpers now return `gasEstimate` so you can tune overrides before sending.
375
499
  - Builders expose `.withGasLimit(gas: bigint)` so you can set overrides fluently.
376
500
 
377
-
378
-
379
501
  ### Builder Pattern (Recommended)
380
502
 
381
503
  Prefer using the builders to construct `CreateStaticAuctionParams` and `CreateDynamicAuctionParams` fluently and safely. Builders apply sensible defaults and can compute ticks and gamma for you.
382
504
 
383
505
  ```typescript
384
- import { StaticAuctionBuilder, DynamicAuctionBuilder } from '@whetstone-research/doppler-sdk'
385
- import { parseEther } from 'viem'
506
+ import {
507
+ StaticAuctionBuilder,
508
+ DynamicAuctionBuilder,
509
+ } from '@whetstone-research/doppler-sdk';
510
+ import { parseEther } from 'viem';
386
511
 
387
512
  // Dynamic auction via builder
388
513
  const dynamicParams = new DynamicAuctionBuilder()
389
- .tokenConfig({ name: 'My Token', symbol: 'MTK', tokenURI: 'https://example.com/metadata.json' })
390
- .saleConfig({ initialSupply: parseEther('1000000'), numTokensToSell: parseEther('500000'), numeraire: wethAddress })
514
+ .tokenConfig({
515
+ name: 'My Token',
516
+ symbol: 'MTK',
517
+ tokenURI: 'https://example.com/metadata.json',
518
+ })
519
+ .saleConfig({
520
+ initialSupply: parseEther('1000000'),
521
+ numTokensToSell: parseEther('500000'),
522
+ numeraire: wethAddress,
523
+ })
391
524
  .poolConfig({ fee: 3000, tickSpacing: 60 })
392
525
  .auctionByPriceRange({
393
526
  priceRange: { startPrice: 0.0001, endPrice: 0.001 },
@@ -396,20 +529,31 @@ const dynamicParams = new DynamicAuctionBuilder()
396
529
  })
397
530
  .withMigration({ type: 'uniswapV2' })
398
531
  .withUserAddress('0x...')
399
- .build()
532
+ .build();
400
533
 
401
- const dyn = await sdk.factory.createDynamicAuction(dynamicParams)
534
+ const dyn = await sdk.factory.createDynamicAuction(dynamicParams);
402
535
 
403
536
  // Static auction via builder
404
537
  const staticParams = new StaticAuctionBuilder()
405
- .tokenConfig({ name: 'My Token', symbol: 'MTK', tokenURI: 'https://example.com/metadata.json' })
406
- .saleConfig({ initialSupply: parseEther('1000000000'), numTokensToSell: parseEther('900000000'), numeraire: wethAddress })
407
- .poolByPriceRange({ priceRange: { startPrice: 0.0001, endPrice: 0.001 }, fee: 3000 })
538
+ .tokenConfig({
539
+ name: 'My Token',
540
+ symbol: 'MTK',
541
+ tokenURI: 'https://example.com/metadata.json',
542
+ })
543
+ .saleConfig({
544
+ initialSupply: parseEther('1000000000'),
545
+ numTokensToSell: parseEther('900000000'),
546
+ numeraire: wethAddress,
547
+ })
548
+ .poolByPriceRange({
549
+ priceRange: { startPrice: 0.0001, endPrice: 0.001 },
550
+ fee: 3000,
551
+ })
408
552
  .withMigration({ type: 'uniswapV2' })
409
553
  .withUserAddress('0x...')
410
- .build()
554
+ .build();
411
555
 
412
- const stat = await sdk.factory.createStaticAuction(staticParams)
556
+ const stat = await sdk.factory.createStaticAuction(staticParams);
413
557
  ```
414
558
 
415
559
  ### Simplified Creation with Defaults
@@ -419,19 +563,35 @@ The SDK intelligently applies defaults when parameters are omitted. Here are exa
419
563
  ```typescript
420
564
  // Minimal static auction via builder
421
565
  const staticMinimal = new StaticAuctionBuilder()
422
- .tokenConfig({ name: 'My Token', symbol: 'MTK', tokenURI: 'https://example.com/metadata.json' })
423
- .saleConfig({ initialSupply: parseEther('1000000000'), numTokensToSell: parseEther('900000000'), numeraire: '0x...' })
566
+ .tokenConfig({
567
+ name: 'My Token',
568
+ symbol: 'MTK',
569
+ tokenURI: 'https://example.com/metadata.json',
570
+ })
571
+ .saleConfig({
572
+ initialSupply: parseEther('1000000000'),
573
+ numTokensToSell: parseEther('900000000'),
574
+ numeraire: '0x...',
575
+ })
424
576
  .poolByTicks({ fee: 10000 }) // uses default tick range and numPositions
425
577
  .withMigration({ type: 'uniswapV2' })
426
578
  .withUserAddress('0x...')
427
- .build()
579
+ .build();
428
580
 
429
- const staticResult = await sdk.factory.createStaticAuction(staticMinimal)
581
+ const staticResult = await sdk.factory.createStaticAuction(staticMinimal);
430
582
 
431
583
  // Minimal dynamic auction via builder
432
584
  const dynamicMinimal = new DynamicAuctionBuilder()
433
- .tokenConfig({ name: 'My Token', symbol: 'MTK', tokenURI: 'https://example.com/metadata.json' })
434
- .saleConfig({ initialSupply: parseEther('1000000'), numTokensToSell: parseEther('900000'), numeraire: '0x...' })
585
+ .tokenConfig({
586
+ name: 'My Token',
587
+ symbol: 'MTK',
588
+ tokenURI: 'https://example.com/metadata.json',
589
+ })
590
+ .saleConfig({
591
+ initialSupply: parseEther('1000000'),
592
+ numTokensToSell: parseEther('900000'),
593
+ numeraire: '0x...',
594
+ })
435
595
  .poolConfig({ fee: 3000, tickSpacing: 60 })
436
596
  .auctionByTicks({
437
597
  startTick: -92103,
@@ -441,9 +601,9 @@ const dynamicMinimal = new DynamicAuctionBuilder()
441
601
  }) // duration/epoch defaults applied; gamma computed automatically
442
602
  .withMigration({ type: 'uniswapV4' })
443
603
  .withUserAddress('0x...')
444
- .build()
604
+ .build();
445
605
 
446
- const dynamicResult = await sdk.factory.createDynamicAuction(dynamicMinimal)
606
+ const dynamicResult = await sdk.factory.createDynamicAuction(dynamicMinimal);
447
607
  ```
448
608
 
449
609
  ## Interacting with Auctions
@@ -521,6 +681,7 @@ const numeraireAddress = await pool.getNumeraireAddress();
521
681
  **Fee Collection Technical Details:**
522
682
 
523
683
  The SDK handles the complexity of fee collection by:
684
+
524
685
  1. **Retrieving pool configuration** from the multicurve initializer contract
525
686
  2. **Detecting migration status** and, if the pool has migrated, resolving the shared `StreamableFeesLockerV2`
526
687
  address via the multicurve migrator (no manual lookup required)
@@ -529,6 +690,7 @@ The SDK handles the complexity of fee collection by:
529
690
  5. **Distributing fees** proportionally to all configured beneficiaries
530
691
 
531
692
  **Important Notes:**
693
+
532
694
  - Fees accumulate from swap activity on the pool (only if fee tier > 0)
533
695
  - Anyone can call `collectFees()`, but fees are distributed to beneficiaries only
534
696
  - Fees are automatically split according to configured beneficiary shares
@@ -541,6 +703,7 @@ The SDK handles the complexity of fee collection by:
541
703
  - Beneficiaries must be configured at pool creation time and cannot be changed
542
704
 
543
705
  **Common Use Cases:**
706
+
544
707
  - Set up periodic fee collection (e.g., daily or weekly)
545
708
  - Integrate with a bot that automatically collects fees when threshold is reached
546
709
  - Allow any beneficiary to trigger collection after significant trading activity
@@ -573,9 +736,10 @@ await token.release();
573
736
  ```
574
737
 
575
738
  Alternatively, you can instantiate directly if needed:
739
+
576
740
  ```typescript
577
- import { Derc20 } from '@whetstone-research/doppler-sdk'
578
- const tokenDirect = new Derc20(publicClient, walletClient, tokenAddress)
741
+ import { Derc20 } from '@whetstone-research/doppler-sdk';
742
+ const tokenDirect = new Derc20(publicClient, walletClient, tokenAddress);
579
743
  ```
580
744
 
581
745
  ### Governance Delegation (ERC20Votes)
@@ -583,81 +747,105 @@ const tokenDirect = new Derc20(publicClient, walletClient, tokenAddress)
583
747
  DERC20 extends OpenZeppelin's ERC20Votes. Voting power is tracked via checkpoints and only updates once an address delegates voting power (typically to itself). The SDK exposes simple read/write helpers for delegation.
584
748
 
585
749
  Basics:
750
+
586
751
  ```ts
587
- import { Derc20 } from '@whetstone-research/doppler-sdk'
752
+ import { Derc20 } from '@whetstone-research/doppler-sdk';
588
753
 
589
- const token = sdk.getDerc20(tokenAddress)
754
+ const token = sdk.getDerc20(tokenAddress);
590
755
 
591
756
  // Read: who an account delegates to, and current voting power
592
- const currentDelegate = await token.getDelegates(userAddress)
593
- const votes = await token.getVotes(userAddress)
757
+ const currentDelegate = await token.getDelegates(userAddress);
758
+ const votes = await token.getVotes(userAddress);
594
759
 
595
760
  // Self‑delegate to activate vote tracking
596
- await token.delegate(userAddress)
761
+ await token.delegate(userAddress);
597
762
 
598
763
  // Or delegate to another address
599
- await token.delegate('0xDelegatee...')
764
+ await token.delegate('0xDelegatee...');
600
765
  ```
601
766
 
602
767
  Historical votes:
768
+
603
769
  ```ts
604
770
  // OZ v5 uses timepoints (block numbers for block‑based clocks)
605
- const blockNumber = await publicClient.getBlockNumber()
606
- const pastVotes = await token.getPastVotes(userAddress, blockNumber - 1n)
771
+ const blockNumber = await publicClient.getBlockNumber();
772
+ const pastVotes = await token.getPastVotes(userAddress, blockNumber - 1n);
607
773
  ```
608
774
 
609
775
  Signature‑based delegation (delegateBySig):
776
+
610
777
  ```ts
611
778
  // Signs an EIP‑712 message and submits a transaction calling delegateBySig
612
779
  // Note: This still submits a transaction from the connected wallet.
613
- const expiry = BigInt(Math.floor(Date.now() / 1000) + 3600) // 1h
614
- await token.delegateBySig('0xDelegatee...', expiry)
780
+ const expiry = BigInt(Math.floor(Date.now() / 1000) + 3600); // 1h
781
+ await token.delegateBySig('0xDelegatee...', expiry);
615
782
  ```
616
783
 
617
784
  Advanced: gasless delegation via relayer
785
+
618
786
  - The token supports `delegateBySig(delegatee, nonce, expiry, v, r, s)`. A relayer can submit this on behalf of the user if it holds ETH for gas.
619
787
  - To do this, have the user sign typed data, then send the signature to your backend that calls the contract.
620
788
 
621
789
  Client (sign only):
790
+
622
791
  ```ts
623
792
  const [nonce, name] = await Promise.all([
624
- publicClient.readContract({ address: tokenAddress, abi: derc20Abi, functionName: 'nonces', args: [userAddress] }),
793
+ publicClient.readContract({
794
+ address: tokenAddress,
795
+ abi: derc20Abi,
796
+ functionName: 'nonces',
797
+ args: [userAddress],
798
+ }),
625
799
  token.getName(),
626
- ])
627
- const chainId = await publicClient.getChainId()
628
- const domain = { name, version: '1', chainId, verifyingContract: tokenAddress } as const
629
- const types = { Delegation: [
630
- { name: 'delegatee', type: 'address' },
631
- { name: 'nonce', type: 'uint256' },
632
- { name: 'expiry', type: 'uint256' },
633
- ] } as const
634
- const message = { delegatee: '0xDelegatee...', nonce, expiry } as const
800
+ ]);
801
+ const chainId = await publicClient.getChainId();
802
+ const domain = {
803
+ name,
804
+ version: '1',
805
+ chainId,
806
+ verifyingContract: tokenAddress,
807
+ } as const;
808
+ const types = {
809
+ Delegation: [
810
+ { name: 'delegatee', type: 'address' },
811
+ { name: 'nonce', type: 'uint256' },
812
+ { name: 'expiry', type: 'uint256' },
813
+ ],
814
+ } as const;
815
+ const message = { delegatee: '0xDelegatee...', nonce, expiry } as const;
635
816
 
636
817
  const signature = await walletClient.signTypedData({
637
- domain, types, primaryType: 'Delegation', message, account: userAddress,
638
- })
818
+ domain,
819
+ types,
820
+ primaryType: 'Delegation',
821
+ message,
822
+ account: userAddress,
823
+ });
639
824
  // POST { signature, delegatee, nonce, expiry } to your relayer
640
825
  ```
641
826
 
642
827
  Relayer (submit tx):
828
+
643
829
  ```ts
644
830
  function splitSig(sig: `0x${string}`) {
645
- const r = `0x${sig.slice(2, 66)}` as `0x${string}`
646
- const s = `0x${sig.slice(66, 130)}` as `0x${string}`
647
- let v = parseInt(sig.slice(130, 132), 16); if (v < 27) v += 27
648
- return { v, r, s }
831
+ const r = `0x${sig.slice(2, 66)}` as `0x${string}`;
832
+ const s = `0x${sig.slice(66, 130)}` as `0x${string}`;
833
+ let v = parseInt(sig.slice(130, 132), 16);
834
+ if (v < 27) v += 27;
835
+ return { v, r, s };
649
836
  }
650
837
 
651
- const { v, r, s } = splitSig(signature)
838
+ const { v, r, s } = splitSig(signature);
652
839
  await relayerWallet.writeContract({
653
840
  address: tokenAddress,
654
841
  abi: derc20Abi,
655
842
  functionName: 'delegateBySig',
656
843
  args: ['0xDelegatee...', nonce, expiry, v, r, s],
657
- })
844
+ });
658
845
  ```
659
846
 
660
847
  Notes
848
+
661
849
  - Users must delegate (even to themselves) before votes appear in `getVotes`.
662
850
  - `getPastVotes`/`getPastTotalSupply` expect a timepoint; for block‑based clocks, pass a block number that has already been mined.
663
851
  - Events you may track: `DelegateChanged` and `DelegateVotesChanged` for live updates.
@@ -698,6 +886,7 @@ console.log('Price after swap:', quote.sqrtPriceX96After);
698
886
  For static auctions, you can create the pool and execute a pre‑buy in a single transaction via the Bundler.
699
887
 
700
888
  High‑level flow:
889
+
701
890
  - Simulate create to get `CreateParams` and the predicted token address
702
891
  - Decide `amountOut` to buy, simulate `amountIn` with `simulateBundleExactOutput(...)`
703
892
  - Build Universal Router commands (e.g., via `doppler-router`)
@@ -714,21 +903,27 @@ before attempting these flows; if you see
714
903
 
715
904
  ```ts
716
905
  // Prepare multicurve CreateParams up front
717
- const createParams = sdk.factory.encodeCreateMulticurveParams(multicurveConfig)
906
+ const createParams = sdk.factory.encodeCreateMulticurveParams(multicurveConfig);
718
907
 
719
908
  // Quote an exact-out bundle
720
- const exactOutQuote = await sdk.factory.simulateMulticurveBundleExactOut(createParams, {
721
- exactAmountOut: parseEther('100'),
722
- })
909
+ const exactOutQuote = await sdk.factory.simulateMulticurveBundleExactOut(
910
+ createParams,
911
+ {
912
+ exactAmountOut: parseEther('100'),
913
+ },
914
+ );
723
915
 
724
916
  // Quote an exact-in bundle
725
- const exactInQuote = await sdk.factory.simulateMulticurveBundleExactIn(createParams, {
726
- exactAmountIn: parseEther('25'),
727
- })
917
+ const exactInQuote = await sdk.factory.simulateMulticurveBundleExactIn(
918
+ createParams,
919
+ {
920
+ exactAmountIn: parseEther('25'),
921
+ },
922
+ );
728
923
 
729
- console.log('Predicted asset:', exactOutQuote.asset)
730
- console.log('PoolKey:', exactOutQuote.poolKey)
731
- console.log('Input required:', exactOutQuote.amountIn)
924
+ console.log('Predicted asset:', exactOutQuote.asset);
925
+ console.log('PoolKey:', exactOutQuote.poolKey);
926
+ console.log('Input required:', exactOutQuote.amountIn);
732
927
  ```
733
928
 
734
929
  The multicurve helpers automatically normalise the returned PoolKey to maintain canonical token ordering and
@@ -739,6 +934,7 @@ hash the result when collecting fees, so consumers no longer need to manually as
739
934
  The SDK supports flexible migration paths after auction completion:
740
935
 
741
936
  ### Migrate to Uniswap V2
937
+
742
938
  ```typescript
743
939
  migration: {
744
940
  type: 'uniswapV2',
@@ -746,6 +942,7 @@ migration: {
746
942
  ```
747
943
 
748
944
  ### Migrate to Uniswap V3
945
+
749
946
  ```typescript
750
947
  migration: {
751
948
  type: 'uniswapV3',
@@ -755,6 +952,7 @@ migration: {
755
952
  ```
756
953
 
757
954
  ### Migrate to Uniswap V4
955
+
758
956
  ```typescript
759
957
  migration: {
760
958
  type: 'uniswapV4',
@@ -777,7 +975,11 @@ migrated V4 pool. This migration type is only supported for dynamic auctions.
777
975
  ```typescript
778
976
  const params = sdk
779
977
  .buildDynamicAuction()
780
- .tokenConfig({ name: 'Example', symbol: 'EX', tokenURI: 'https://example.com/token.json' })
978
+ .tokenConfig({
979
+ name: 'Example',
980
+ symbol: 'EX',
981
+ tokenURI: 'https://example.com/token.json',
982
+ })
781
983
  .saleConfig({
782
984
  initialSupply: parseEther('1000000'),
783
985
  numTokensToSell: parseEther('500000'),
@@ -803,10 +1005,17 @@ const params = sdk
803
1005
  rehype: {
804
1006
  buybackDestination: '0xYourBuybackDestination...',
805
1007
  customFee: 3000,
806
- assetBuybackPercentWad: parseEther('0.25'),
807
- numeraireBuybackPercentWad: parseEther('0.25'),
808
- beneficiaryPercentWad: parseEther('0.25'),
809
- lpPercentWad: parseEther('0.25'),
1008
+ feeRoutingMode: 'directBuyback',
1009
+ feeDistributionInfo: {
1010
+ assetFeesToAssetBuybackWad: parseEther('0.25'),
1011
+ assetFeesToNumeraireBuybackWad: parseEther('0.25'),
1012
+ assetFeesToBeneficiaryWad: parseEther('0.25'),
1013
+ assetFeesToLpWad: parseEther('0.25'),
1014
+ numeraireFeesToAssetBuybackWad: parseEther('0.25'),
1015
+ numeraireFeesToNumeraireBuybackWad: parseEther('0.25'),
1016
+ numeraireFeesToBeneficiaryWad: parseEther('0.25'),
1017
+ numeraireFeesToLpWad: parseEther('0.25'),
1018
+ },
810
1019
  },
811
1020
  })
812
1021
  .withUserAddress('0xYourAddress...')
@@ -815,6 +1024,8 @@ const params = sdk
815
1024
 
816
1025
  Note: `dopplerHook` migrator beneficiaries must include the current Airlock owner
817
1026
  with at least 5% shares, and total shares must sum to `1e18`.
1027
+ Unlike initializer-side Rehype pools, migrator-side Rehype uses a static
1028
+ `customFee`; there is no fee decay schedule in this mode.
818
1029
 
819
1030
  ```typescript
820
1031
  migration: {
@@ -831,10 +1042,17 @@ migration: {
831
1042
  // hookAddress: '0xRehypeMigratorHook...',
832
1043
  buybackDestination: '0xYourBuybackDestination...',
833
1044
  customFee: 3000,
834
- assetBuybackPercentWad: parseEther('0.25'),
835
- numeraireBuybackPercentWad: parseEther('0.25'),
836
- beneficiaryPercentWad: parseEther('0.25'),
837
- lpPercentWad: parseEther('0.25'),
1045
+ feeRoutingMode: 'directBuyback',
1046
+ feeDistributionInfo: {
1047
+ assetFeesToAssetBuybackWad: parseEther('0.25'),
1048
+ assetFeesToNumeraireBuybackWad: parseEther('0.25'),
1049
+ assetFeesToBeneficiaryWad: parseEther('0.25'),
1050
+ assetFeesToLpWad: parseEther('0.25'),
1051
+ numeraireFeesToAssetBuybackWad: parseEther('0.25'),
1052
+ numeraireFeesToNumeraireBuybackWad: parseEther('0.25'),
1053
+ numeraireFeesToBeneficiaryWad: parseEther('0.25'),
1054
+ numeraireFeesToLpWad: parseEther('0.25'),
1055
+ },
838
1056
  },
839
1057
  proceedsSplit: {
840
1058
  recipient: '0xProceedsRecipient...',
@@ -847,18 +1065,22 @@ To make configuring the first beneficiary simpler, the SDK now exposes helpers f
847
1065
  airlock owner and creating the default 5% entry:
848
1066
 
849
1067
  ```ts
850
- import { DopplerSDK, createAirlockBeneficiary, getAirlockOwner } from '@whetstone-research/doppler-sdk'
851
- import { parseEther } from 'viem'
1068
+ import {
1069
+ DopplerSDK,
1070
+ createAirlockBeneficiary,
1071
+ getAirlockOwner,
1072
+ } from '@whetstone-research/doppler-sdk';
1073
+ import { parseEther } from 'viem';
852
1074
 
853
- const sdk = new DopplerSDK({ publicClient, chainId })
1075
+ const sdk = new DopplerSDK({ publicClient, chainId });
854
1076
 
855
1077
  // Get the owner and construct the beneficiary entry (5% by default)
856
- const airlockBeneficiary = await sdk.getAirlockBeneficiary()
1078
+ const airlockBeneficiary = await sdk.getAirlockBeneficiary();
857
1079
 
858
1080
  // Or build the entry manually if you do not have an SDK instance handy
859
1081
  // (airlockEntry will be equivalent to airlockBeneficiary above)
860
- const owner = await getAirlockOwner(publicClient)
861
- const airlockEntry = createAirlockBeneficiary(owner) // defaults to 5% shares
1082
+ const owner = await getAirlockOwner(publicClient);
1083
+ const airlockEntry = createAirlockBeneficiary(owner); // defaults to 5% shares
862
1084
 
863
1085
  const migration = {
864
1086
  type: 'uniswapV4' as const,
@@ -871,11 +1093,9 @@ const migration = {
871
1093
  { beneficiary: '0xYourDAO...', shares: parseEther('0.95') }, // 95%
872
1094
  ],
873
1095
  },
874
- }
1096
+ };
875
1097
  ```
876
1098
 
877
-
878
-
879
1099
  ## Supported Chains
880
1100
 
881
1101
  The SDK exposes runtime constants and TypeScript types for supported chains:
@@ -888,21 +1108,21 @@ import {
888
1108
  isSupportedChainId,
889
1109
  type SupportedChainId,
890
1110
  type ChainAddresses,
891
- } from '@whetstone-research/doppler-sdk'
1111
+ } from '@whetstone-research/doppler-sdk';
892
1112
 
893
1113
  // Validate and narrow a chain ID
894
1114
  function ensureSupported(id: number): SupportedChainId {
895
- if (!isSupportedChainId(id)) throw new Error('Unsupported chain')
896
- return id
1115
+ if (!isSupportedChainId(id)) throw new Error('Unsupported chain');
1116
+ return id;
897
1117
  }
898
1118
 
899
- const chainId = ensureSupported(CHAIN_IDS.BASE)
900
- const addresses: ChainAddresses = getAddresses(chainId)
901
- console.log('Airlock for Base:', addresses.airlock)
1119
+ const chainId = ensureSupported(CHAIN_IDS.BASE);
1120
+ const addresses: ChainAddresses = getAddresses(chainId);
1121
+ console.log('Airlock for Base:', addresses.airlock);
902
1122
 
903
1123
  // Iterate supported chains
904
1124
  for (const id of SUPPORTED_CHAIN_IDS) {
905
- console.log('Supported chain id:', id)
1125
+ console.log('Supported chain id:', id);
906
1126
  }
907
1127
  ```
908
1128
 
@@ -925,6 +1145,7 @@ vesting: {
925
1145
  The Doppler protocol uses CREATE2 for deterministic deployments, enabling you to find vanity addresses for both tokens and hooks before submitting transactions. The SDK provides a `mineTokenAddress` utility that mirrors on-chain calculations.
926
1146
 
927
1147
  `mineTokenAddress` supports matching:
1148
+
928
1149
  - A **prefix** (address starts with hex characters)
929
1150
  - A **suffix** (address ends with hex characters, useful as an identifier)
930
1151
  - Both prefix + suffix simultaneously (logical AND)
@@ -938,12 +1159,16 @@ import {
938
1159
  StaticAuctionBuilder,
939
1160
  mineTokenAddress,
940
1161
  getAddresses,
941
- } from '@whetstone-research/doppler-sdk'
942
- import { parseEther } from 'viem'
943
- import { base } from 'viem/chains'
1162
+ } from '@whetstone-research/doppler-sdk';
1163
+ import { parseEther } from 'viem';
1164
+ import { base } from 'viem/chains';
944
1165
 
945
1166
  const builder = new StaticAuctionBuilder(base.id)
946
- .tokenConfig({ name: 'Vanity Token', symbol: 'VNY', tokenURI: 'https://example.com/token.json' })
1167
+ .tokenConfig({
1168
+ name: 'Vanity Token',
1169
+ symbol: 'VNY',
1170
+ tokenURI: 'https://example.com/token.json',
1171
+ })
947
1172
  .saleConfig({
948
1173
  initialSupply: parseEther('1000000'),
949
1174
  numTokensToSell: parseEther('750000'),
@@ -952,12 +1177,13 @@ const builder = new StaticAuctionBuilder(base.id)
952
1177
  .poolByTicks({ startTick: -92100, endTick: -69060, fee: 3000 })
953
1178
  .withGovernance({ type: 'default' })
954
1179
  .withMigration({ type: 'uniswapV3', fee: 3000, tickSpacing: 60 })
955
- .withUserAddress('0x...')
1180
+ .withUserAddress('0x...');
956
1181
 
957
- const staticParams = builder.build()
1182
+ const staticParams = builder.build();
958
1183
  // Fetch the encoded create() payload without sending the transaction
959
- const createParams = await sdk.factory.encodeCreateStaticAuctionParams(staticParams)
960
- const addresses = getAddresses(base.id)
1184
+ const createParams =
1185
+ await sdk.factory.encodeCreateStaticAuctionParams(staticParams);
1186
+ const addresses = getAddresses(base.id);
961
1187
 
962
1188
  const { salt, tokenAddress, iterations } = mineTokenAddress({
963
1189
  prefix: 'dead', // omit 0x prefix
@@ -967,9 +1193,11 @@ const { salt, tokenAddress, iterations } = mineTokenAddress({
967
1193
  owner: addresses.airlock,
968
1194
  tokenData: createParams.tokenFactoryData,
969
1195
  maxIterations: 1_000_000, // optional safety cap
970
- })
1196
+ });
971
1197
 
972
- console.log(`Vanity token ${tokenAddress} found after ${iterations} iterations`)
1198
+ console.log(
1199
+ `Vanity token ${tokenAddress} found after ${iterations} iterations`,
1200
+ );
973
1201
  // Now submit airlock.create({ ...createParams, salt }) when ready to deploy
974
1202
  ```
975
1203
 
@@ -985,7 +1213,7 @@ const { salt, tokenAddress, iterations } = mineTokenAddress({
985
1213
  owner: addresses.airlock,
986
1214
  tokenData: createParams.tokenFactoryData,
987
1215
  maxIterations: 1_000_000,
988
- })
1216
+ });
989
1217
  ```
990
1218
 
991
1219
  #### Mining Hook and Token Addresses (Dynamic Auctions)
@@ -999,12 +1227,16 @@ import {
999
1227
  getAddresses,
1000
1228
  DopplerBytecode,
1001
1229
  DAY_SECONDS,
1002
- } from '@whetstone-research/doppler-sdk'
1003
- import { parseEther, keccak256, encodePacked, encodeAbiParameters } from 'viem'
1004
- import { base } from 'viem/chains'
1230
+ } from '@whetstone-research/doppler-sdk';
1231
+ import { parseEther, keccak256, encodePacked, encodeAbiParameters } from 'viem';
1232
+ import { base } from 'viem/chains';
1005
1233
 
1006
1234
  const builder = new DynamicAuctionBuilder()
1007
- .tokenConfig({ name: 'My Token', symbol: 'MTK', tokenURI: 'https://example.com/token.json' })
1235
+ .tokenConfig({
1236
+ name: 'My Token',
1237
+ symbol: 'MTK',
1238
+ tokenURI: 'https://example.com/token.json',
1239
+ })
1008
1240
  .saleConfig({
1009
1241
  initialSupply: parseEther('1000000'),
1010
1242
  numTokensToSell: parseEther('900000'),
@@ -1020,20 +1252,30 @@ const builder = new DynamicAuctionBuilder()
1020
1252
  maxProceeds: parseEther('1000'),
1021
1253
  })
1022
1254
  .withMigration({ type: 'uniswapV4', fee: 3000, tickSpacing: 60 })
1023
- .withUserAddress('0x...')
1255
+ .withUserAddress('0x...');
1024
1256
 
1025
- const dynamicParams = builder.build()
1026
- const { createParams } = await sdk.factory.encodeCreateDynamicAuctionParams(dynamicParams)
1027
- const addresses = getAddresses(base.id)
1257
+ const dynamicParams = builder.build();
1258
+ const { createParams } =
1259
+ await sdk.factory.encodeCreateDynamicAuctionParams(dynamicParams);
1260
+ const addresses = getAddresses(base.id);
1028
1261
 
1029
1262
  // Compute hook init code hash (required for hook mining)
1030
1263
  const hookInitHashData = encodeAbiParameters(
1031
1264
  [
1032
- { type: 'address' }, { type: 'uint256' }, { type: 'uint256' },
1033
- { type: 'uint256' }, { type: 'uint256' }, { type: 'uint256' },
1034
- { type: 'int24' }, { type: 'int24' }, { type: 'uint256' },
1035
- { type: 'int24' }, { type: 'bool' }, { type: 'uint256' },
1036
- { type: 'address' }, { type: 'uint24' },
1265
+ { type: 'address' },
1266
+ { type: 'uint256' },
1267
+ { type: 'uint256' },
1268
+ { type: 'uint256' },
1269
+ { type: 'uint256' },
1270
+ { type: 'uint256' },
1271
+ { type: 'int24' },
1272
+ { type: 'int24' },
1273
+ { type: 'uint256' },
1274
+ { type: 'int24' },
1275
+ { type: 'bool' },
1276
+ { type: 'uint256' },
1277
+ { type: 'address' },
1278
+ { type: 'uint24' },
1037
1279
  ],
1038
1280
  [
1039
1281
  addresses.poolManager,
@@ -1042,15 +1284,15 @@ const hookInitHashData = encodeAbiParameters(
1042
1284
  dynamicParams.auction.maxProceeds,
1043
1285
  /* startingTime, endingTime, startTick, endTick, epochLength, gamma, isToken0, numPDSlugs */
1044
1286
  /* poolInitializer, fee - extract from createParams */
1045
- ]
1046
- )
1287
+ ],
1288
+ );
1047
1289
 
1048
1290
  const hookInitHash = keccak256(
1049
- encodePacked(['bytes', 'bytes'], [DopplerBytecode, hookInitHashData])
1050
- )
1291
+ encodePacked(['bytes', 'bytes'], [DopplerBytecode, hookInitHashData]),
1292
+ );
1051
1293
 
1052
1294
  const result = mineTokenAddress({
1053
- prefix: 'cafe', // Token prefix
1295
+ prefix: 'cafe', // Token prefix
1054
1296
  tokenFactory: createParams.tokenFactory,
1055
1297
  initialSupply: createParams.initialSupply,
1056
1298
  recipient: addresses.airlock,
@@ -1064,11 +1306,11 @@ const result = mineTokenAddress({
1064
1306
  initCodeHash: hookInitHash,
1065
1307
  prefix: '00', // Hook prefix for gas optimization
1066
1308
  },
1067
- })
1309
+ });
1068
1310
 
1069
- console.log('Token address:', result.tokenAddress)
1070
- console.log('Hook address:', result.hookAddress) // only if hook config provided
1071
- console.log(`Found after ${result.iterations} iterations`)
1311
+ console.log('Token address:', result.tokenAddress);
1312
+ console.log('Hook address:', result.hookAddress); // only if hook config provided
1313
+ console.log(`Found after ${result.iterations} iterations`);
1072
1314
  ```
1073
1315
 
1074
1316
  #### Mining Token Addresses (Multicurve Auctions)
@@ -1080,12 +1322,16 @@ import {
1080
1322
  MulticurveBuilder,
1081
1323
  mineTokenAddress,
1082
1324
  getAddresses,
1083
- } from '@whetstone-research/doppler-sdk'
1084
- import { parseEther } from 'viem'
1085
- import { base } from 'viem/chains'
1325
+ } from '@whetstone-research/doppler-sdk';
1326
+ import { parseEther } from 'viem';
1327
+ import { base } from 'viem/chains';
1086
1328
 
1087
1329
  const builder = new MulticurveBuilder(base.id)
1088
- .tokenConfig({ name: 'Vanity Multicurve', symbol: 'VMC', tokenURI: 'https://example.com/token.json' })
1330
+ .tokenConfig({
1331
+ name: 'Vanity Multicurve',
1332
+ symbol: 'VMC',
1333
+ tokenURI: 'https://example.com/token.json',
1334
+ })
1089
1335
  .saleConfig({
1090
1336
  initialSupply: parseEther('1000000'),
1091
1337
  numTokensToSell: parseEther('900000'),
@@ -1095,19 +1341,29 @@ const builder = new MulticurveBuilder(base.id)
1095
1341
  fee: 3000,
1096
1342
  tickSpacing: 60,
1097
1343
  curves: [
1098
- { tickLower: 0, tickUpper: 240000, numPositions: 10, shares: parseEther('0.5') },
1099
- { tickLower: 16000, tickUpper: 240000, numPositions: 10, shares: parseEther('0.5') },
1344
+ {
1345
+ tickLower: 0,
1346
+ tickUpper: 240000,
1347
+ numPositions: 10,
1348
+ shares: parseEther('0.5'),
1349
+ },
1350
+ {
1351
+ tickLower: 16000,
1352
+ tickUpper: 240000,
1353
+ numPositions: 10,
1354
+ shares: parseEther('0.5'),
1355
+ },
1100
1356
  ],
1101
1357
  })
1102
1358
  .withGovernance({ type: 'default' })
1103
1359
  .withMigration({ type: 'uniswapV2' })
1104
- .withUserAddress('0x...')
1360
+ .withUserAddress('0x...');
1105
1361
 
1106
- const multicurveParams = builder.build()
1107
- const addresses = getAddresses(base.id)
1362
+ const multicurveParams = builder.build();
1363
+ const addresses = getAddresses(base.id);
1108
1364
 
1109
1365
  // Get CreateParams without calling create
1110
- const createParams = sdk.factory.encodeCreateMulticurveParams(multicurveParams)
1366
+ const createParams = sdk.factory.encodeCreateMulticurveParams(multicurveParams);
1111
1367
 
1112
1368
  // Mine a vanity token address
1113
1369
  const { salt, tokenAddress, iterations } = mineTokenAddress({
@@ -1118,12 +1374,14 @@ const { salt, tokenAddress, iterations } = mineTokenAddress({
1118
1374
  owner: addresses.airlock,
1119
1375
  tokenData: createParams.tokenFactoryData,
1120
1376
  maxIterations: 500_000,
1121
- })
1377
+ });
1122
1378
 
1123
- console.log(`Vanity token ${tokenAddress} found after ${iterations} iterations`)
1379
+ console.log(
1380
+ `Vanity token ${tokenAddress} found after ${iterations} iterations`,
1381
+ );
1124
1382
 
1125
1383
  // Use the mined salt in createParams
1126
- const vanityCreateParams = { ...createParams, salt }
1384
+ const vanityCreateParams = { ...createParams, salt };
1127
1385
 
1128
1386
  // Now submit the transaction manually with the vanity salt
1129
1387
  await publicClient.writeContract({
@@ -1132,7 +1390,7 @@ await publicClient.writeContract({
1132
1390
  functionName: 'create',
1133
1391
  args: [vanityCreateParams],
1134
1392
  account: walletClient.account,
1135
- })
1393
+ });
1136
1394
  ```
1137
1395
 
1138
1396
  **Important**: Since `encodeCreateMulticurveParams` generates a random salt internally, you must construct the final `CreateParams` manually with your mined salt. The high-level `createMulticurve` method will replace any provided salt.
@@ -1163,19 +1421,19 @@ The main SDK class providing access to all functionality.
1163
1421
 
1164
1422
  ```typescript
1165
1423
  class DopplerSDK {
1166
- constructor(config: DopplerSDKConfig)
1167
-
1424
+ constructor(config: DopplerSDKConfig);
1425
+
1168
1426
  // Properties
1169
- factory: DopplerFactory
1170
- quoter: Quoter
1171
-
1427
+ factory: DopplerFactory;
1428
+ quoter: Quoter;
1429
+
1172
1430
  // Methods
1173
- getStaticAuction(poolAddress: Address): Promise<StaticAuction>
1174
- getDynamicAuction(hookAddress: Address): Promise<DynamicAuction>
1431
+ getStaticAuction(poolAddress: Address): Promise<StaticAuction>;
1432
+ getDynamicAuction(hookAddress: Address): Promise<DynamicAuction>;
1175
1433
  // Multicurve helper
1176
- buildMulticurveAuction(): MulticurveBuilder
1177
- getPoolInfo(poolAddress: Address): Promise<PoolInfo>
1178
- getHookInfo(hookAddress: Address): Promise<HookInfo>
1434
+ buildMulticurveAuction(): MulticurveBuilder;
1435
+ getPoolInfo(poolAddress: Address): Promise<PoolInfo>;
1436
+ getHookInfo(hookAddress: Address): Promise<HookInfo>;
1179
1437
  }
1180
1438
  ```
1181
1439