@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.
- package/README.md +488 -230
- package/dist/DopplerSDK.d.mts +12 -0
- package/dist/DopplerSDK.d.ts +12 -0
- package/dist/DopplerSDK.js +21 -19
- package/dist/DopplerSDK.mjs +20 -18
- package/dist/abis/index.d.mts +421 -10
- package/dist/abis/index.d.ts +421 -10
- package/dist/abis/index.js +31 -23
- package/dist/abis/index.mjs +1 -1
- package/dist/addresses.d.mts +4 -0
- package/dist/addresses.d.ts +4 -0
- package/dist/addresses.js +7 -7
- package/dist/addresses.mjs +2 -2
- package/dist/builders/DynamicAuctionBuilder.js +8 -8
- package/dist/builders/DynamicAuctionBuilder.mjs +7 -7
- package/dist/builders/MulticurveBuilder.d.mts +18 -5
- package/dist/builders/MulticurveBuilder.d.ts +18 -5
- package/dist/builders/MulticurveBuilder.js +8 -8
- package/dist/builders/MulticurveBuilder.mjs +7 -7
- package/dist/builders/StaticAuctionBuilder.js +8 -8
- package/dist/builders/StaticAuctionBuilder.mjs +7 -7
- package/dist/builders/index.js +12 -12
- package/dist/builders/index.mjs +9 -9
- package/dist/builders/shared.js +6 -5
- package/dist/builders/shared.mjs +6 -5
- package/dist/{chunk-EH3V2BJF.js → chunk-2A3B3NVB.js} +163 -18
- package/dist/chunk-2A3B3NVB.js.map +1 -0
- package/dist/{chunk-JB5XXPLL.js → chunk-44CYUEPG.js} +5 -5
- package/dist/{chunk-JB5XXPLL.js.map → chunk-44CYUEPG.js.map} +1 -1
- package/dist/{chunk-GSTY3GO7.mjs → chunk-5GQJRNFL.mjs} +3 -3
- package/dist/{chunk-GSTY3GO7.mjs.map → chunk-5GQJRNFL.mjs.map} +1 -1
- package/dist/{chunk-YFEPTSI2.js → chunk-5JHXBDZD.js} +20 -20
- package/dist/{chunk-YFEPTSI2.js.map → chunk-5JHXBDZD.js.map} +1 -1
- package/dist/{chunk-OX5CESVM.js → chunk-65CESA3J.js} +19 -13
- package/dist/chunk-65CESA3J.js.map +1 -0
- package/dist/{chunk-7CAAI5DL.js → chunk-7A4DBBXA.js} +141 -103
- package/dist/chunk-7A4DBBXA.js.map +1 -0
- package/dist/{chunk-RXUJ4DUB.js → chunk-A2CJYRRQ.js} +28 -28
- package/dist/{chunk-RXUJ4DUB.js.map → chunk-A2CJYRRQ.js.map} +1 -1
- package/dist/{chunk-6UHDSD42.js → chunk-BK3S6SVR.js} +209 -87
- package/dist/chunk-BK3S6SVR.js.map +1 -0
- package/dist/{chunk-XT3BAM4H.js → chunk-BQZTELUX.js} +5 -5
- package/dist/{chunk-XT3BAM4H.js.map → chunk-BQZTELUX.js.map} +1 -1
- package/dist/{chunk-FZ4FIWCR.js → chunk-CFXXUZJY.js} +57 -22
- package/dist/chunk-CFXXUZJY.js.map +1 -0
- package/dist/chunk-DCWF3EMP.js +171 -0
- package/dist/chunk-DCWF3EMP.js.map +1 -0
- package/dist/{chunk-VCX6FG3E.mjs → chunk-DQJXCZU2.mjs} +3 -3
- package/dist/{chunk-VCX6FG3E.mjs.map → chunk-DQJXCZU2.mjs.map} +1 -1
- package/dist/chunk-F2BYG63D.mjs +145 -0
- package/dist/chunk-F2BYG63D.mjs.map +1 -0
- package/dist/chunk-FXTGIKQG.mjs +3 -0
- package/dist/{chunk-SD7BHT2F.mjs.map → chunk-FXTGIKQG.mjs.map} +1 -1
- package/dist/chunk-IIM2CSDQ.js +147 -0
- package/dist/chunk-IIM2CSDQ.js.map +1 -0
- package/dist/{chunk-RI6SDMER.mjs → chunk-IUTIHSLH.mjs} +4 -4
- package/dist/{chunk-RI6SDMER.mjs.map → chunk-IUTIHSLH.mjs.map} +1 -1
- package/dist/chunk-IUZ3BBQP.mjs +117 -0
- package/dist/chunk-IUZ3BBQP.mjs.map +1 -0
- package/dist/{chunk-CATH4QRQ.mjs → chunk-IX4V4UGW.mjs} +4 -4
- package/dist/{chunk-CATH4QRQ.mjs.map → chunk-IX4V4UGW.mjs.map} +1 -1
- package/dist/{chunk-E2NF4AQB.mjs → chunk-JLUOFAE4.mjs} +272 -12
- package/dist/chunk-JLUOFAE4.mjs.map +1 -0
- package/dist/{chunk-7P2SPZC7.mjs → chunk-LW3CYA27.mjs} +178 -56
- package/dist/chunk-LW3CYA27.mjs.map +1 -0
- package/dist/{chunk-TIGHBA37.js → chunk-MEA2C5YX.js} +16 -16
- package/dist/{chunk-TIGHBA37.js.map → chunk-MEA2C5YX.js.map} +1 -1
- package/dist/{chunk-3MVW6UIW.js → chunk-MU56HCUI.js} +273 -11
- package/dist/chunk-MU56HCUI.js.map +1 -0
- package/dist/chunk-OCIY7QEJ.mjs +169 -0
- package/dist/chunk-OCIY7QEJ.mjs.map +1 -0
- package/dist/{chunk-CMNJZKTM.js → chunk-P563HTVU.js} +50 -26
- package/dist/chunk-P563HTVU.js.map +1 -0
- package/dist/chunk-PGYTMRP3.js +277 -0
- package/dist/chunk-PGYTMRP3.js.map +1 -0
- package/dist/{chunk-QOGBOT2M.mjs → chunk-QHBKRUBY.mjs} +3 -3
- package/dist/{chunk-QOGBOT2M.mjs.map → chunk-QHBKRUBY.mjs.map} +1 -1
- package/dist/chunk-QOYI7WCH.js +120 -0
- package/dist/chunk-QOYI7WCH.js.map +1 -0
- package/dist/{chunk-EIXUJANI.mjs → chunk-QUBD6HUZ.mjs} +161 -16
- package/dist/chunk-QUBD6HUZ.mjs.map +1 -0
- package/dist/{chunk-FFV6DMPA.mjs → chunk-RDTIXP6S.mjs} +4 -4
- package/dist/{chunk-FFV6DMPA.mjs.map → chunk-RDTIXP6S.mjs.map} +1 -1
- package/dist/{chunk-FTRCBE3J.js → chunk-RLOZWHRR.js} +5 -5
- package/dist/{chunk-FTRCBE3J.js.map → chunk-RLOZWHRR.js.map} +1 -1
- package/dist/chunk-T3UA4MJL.js +4 -0
- package/dist/{chunk-3PNCB4W5.js.map → chunk-T3UA4MJL.js.map} +1 -1
- package/dist/{chunk-C6MH7HYT.mjs → chunk-TEWAXP5C.mjs} +36 -12
- package/dist/chunk-TEWAXP5C.mjs.map +1 -0
- package/dist/{chunk-FLFYAWSS.mjs → chunk-THEIRDGE.mjs} +50 -15
- package/dist/chunk-THEIRDGE.mjs.map +1 -0
- package/dist/chunk-VKSD3KXF.mjs +275 -0
- package/dist/chunk-VKSD3KXF.mjs.map +1 -0
- package/dist/{chunk-RIIVW6TQ.mjs → chunk-WDC53TM7.mjs} +47 -9
- package/dist/chunk-WDC53TM7.mjs.map +1 -0
- package/dist/{chunk-TLEVIIUE.mjs → chunk-WKWP42TD.mjs} +9 -4
- package/dist/chunk-WKWP42TD.mjs.map +1 -0
- package/dist/{chunk-HL7ZAAD4.mjs → chunk-WNWK2QMU.mjs} +3 -3
- package/dist/{chunk-HL7ZAAD4.mjs.map → chunk-WNWK2QMU.mjs.map} +1 -1
- package/dist/{chunk-H7WPK5CR.js → chunk-WZF5XNBC.js} +26 -26
- package/dist/{chunk-H7WPK5CR.js.map → chunk-WZF5XNBC.js.map} +1 -1
- package/dist/deployments.generated.d.mts +46 -38
- package/dist/deployments.generated.d.ts +46 -38
- package/dist/deployments.generated.js +2 -2
- package/dist/deployments.generated.mjs +1 -1
- package/dist/entities/DopplerFactory.d.mts +7 -1
- package/dist/entities/DopplerFactory.d.ts +7 -1
- package/dist/entities/DopplerFactory.js +8 -7
- package/dist/entities/DopplerFactory.mjs +7 -6
- package/dist/entities/auction/DynamicAuction.js +5 -5
- package/dist/entities/auction/DynamicAuction.mjs +4 -4
- package/dist/entities/auction/MulticurvePool.d.mts +6 -2
- package/dist/entities/auction/MulticurvePool.d.ts +6 -2
- package/dist/entities/auction/MulticurvePool.js +6 -6
- package/dist/entities/auction/MulticurvePool.mjs +5 -5
- package/dist/entities/auction/RehypeDopplerHook.d.mts +57 -0
- package/dist/entities/auction/RehypeDopplerHook.d.ts +57 -0
- package/dist/entities/auction/RehypeDopplerHook.js +34 -0
- package/dist/entities/auction/RehypeDopplerHook.js.map +1 -0
- package/dist/entities/auction/RehypeDopplerHook.mjs +25 -0
- package/dist/entities/auction/RehypeDopplerHook.mjs.map +1 -0
- package/dist/entities/auction/RehypeDopplerHookMigrator.d.mts +48 -0
- package/dist/entities/auction/RehypeDopplerHookMigrator.d.ts +48 -0
- package/dist/entities/auction/RehypeDopplerHookMigrator.js +34 -0
- package/dist/entities/auction/RehypeDopplerHookMigrator.js.map +1 -0
- package/dist/entities/auction/RehypeDopplerHookMigrator.mjs +25 -0
- package/dist/entities/auction/RehypeDopplerHookMigrator.mjs.map +1 -0
- package/dist/entities/auction/StaticAuction.js +5 -5
- package/dist/entities/auction/StaticAuction.mjs +4 -4
- package/dist/entities/auction/index.d.mts +2 -0
- package/dist/entities/auction/index.d.ts +2 -0
- package/dist/entities/auction/index.js +31 -11
- package/dist/entities/auction/index.mjs +20 -8
- package/dist/entities/quoter/Quoter.js +5 -5
- package/dist/entities/quoter/Quoter.mjs +4 -4
- package/dist/entities/quoter/index.js +5 -5
- package/dist/entities/quoter/index.mjs +4 -4
- package/dist/entities/token/derc20/Derc20.js +3 -3
- package/dist/entities/token/derc20/Derc20.mjs +2 -2
- package/dist/entities/token/derc20/index.js +3 -3
- package/dist/entities/token/derc20/index.mjs +2 -2
- package/dist/entities/token/index.js +7 -7
- package/dist/entities/token/index.mjs +3 -3
- package/dist/index.d.mts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +86 -64
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +20 -18
- package/dist/index.mjs.map +1 -1
- package/dist/types.d.mts +65 -10
- package/dist/types.d.ts +65 -10
- package/dist/types.js +12 -8
- package/dist/types.mjs +3 -3
- package/dist/utils/airlock.js +7 -7
- package/dist/utils/airlock.mjs +3 -3
- package/dist/utils/dopplerHookMigrator.d.mts +9 -2
- package/dist/utils/dopplerHookMigrator.d.ts +9 -2
- package/dist/utils/dopplerHookMigrator.js +10 -2
- package/dist/utils/dopplerHookMigrator.mjs +5 -1
- package/dist/utils/index.js +12 -10
- package/dist/utils/index.mjs +7 -5
- package/dist/utils/tokenAddressMiner.js +1 -1
- package/dist/utils/tokenAddressMiner.mjs +1 -1
- package/package.json +2 -2
- package/dist/chunk-3MVW6UIW.js.map +0 -1
- package/dist/chunk-3PNCB4W5.js +0 -4
- package/dist/chunk-6UHDSD42.js.map +0 -1
- package/dist/chunk-7CAAI5DL.js.map +0 -1
- package/dist/chunk-7P2SPZC7.mjs.map +0 -1
- package/dist/chunk-C6MH7HYT.mjs.map +0 -1
- package/dist/chunk-CMNJZKTM.js.map +0 -1
- package/dist/chunk-DNB3T5P2.js +0 -269
- package/dist/chunk-DNB3T5P2.js.map +0 -1
- package/dist/chunk-E2NF4AQB.mjs.map +0 -1
- package/dist/chunk-EH3V2BJF.js.map +0 -1
- package/dist/chunk-EIXUJANI.mjs.map +0 -1
- package/dist/chunk-FLFYAWSS.mjs.map +0 -1
- package/dist/chunk-FZ4FIWCR.js.map +0 -1
- package/dist/chunk-GDODJJ7D.mjs +0 -36
- package/dist/chunk-GDODJJ7D.mjs.map +0 -1
- package/dist/chunk-OX5CESVM.js.map +0 -1
- package/dist/chunk-RIIVW6TQ.mjs.map +0 -1
- package/dist/chunk-SD7BHT2F.mjs +0 -3
- package/dist/chunk-TLEVIIUE.mjs.map +0 -1
- package/dist/chunk-WJBJARLJ.js +0 -38
- package/dist/chunk-WJBJARLJ.js.map +0 -1
- package/dist/chunk-XRYLHTVV.mjs +0 -267
- 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({
|
|
67
|
-
|
|
68
|
-
|
|
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 {
|
|
92
|
-
|
|
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') },
|
|
100
|
-
{ beneficiary: '0xTeamWallet...', shares: parseEther('0.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({
|
|
106
|
-
|
|
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,
|
|
133
|
+
startTick: 174960, // Must be multiple of 60 for fee 3000
|
|
109
134
|
endTick: 225000,
|
|
110
|
-
fee: 3000,
|
|
135
|
+
fee: 3000, // Set > 0 to accumulate fees for beneficiaries
|
|
111
136
|
})
|
|
112
|
-
.withBeneficiaries(beneficiaries)
|
|
113
|
-
.withMigration({ type: 'noOp' })
|
|
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)
|
|
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 {
|
|
164
|
+
import {
|
|
165
|
+
DynamicAuctionBuilder,
|
|
166
|
+
DAY_SECONDS,
|
|
167
|
+
} from '@whetstone-research/doppler-sdk';
|
|
139
168
|
|
|
140
169
|
const params = new DynamicAuctionBuilder()
|
|
141
|
-
.tokenConfig({
|
|
142
|
-
|
|
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({
|
|
201
|
-
|
|
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
|
-
{
|
|
207
|
-
|
|
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({
|
|
229
|
-
|
|
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({
|
|
262
|
-
|
|
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
|
-
{
|
|
268
|
-
|
|
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({
|
|
294
|
-
|
|
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
|
-
{
|
|
300
|
-
|
|
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,
|
|
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 },
|
|
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 },
|
|
333
|
-
]
|
|
436
|
+
{ beneficiary: '0xOtherAddress...', shares: WAD / 2n }, // 50%
|
|
437
|
+
];
|
|
334
438
|
|
|
335
439
|
const params = new MulticurveBuilder(base.id)
|
|
336
|
-
.tokenConfig({
|
|
337
|
-
|
|
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
|
-
{
|
|
343
|
-
|
|
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 {
|
|
385
|
-
|
|
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({
|
|
390
|
-
|
|
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({
|
|
406
|
-
|
|
407
|
-
|
|
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({
|
|
423
|
-
|
|
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({
|
|
434
|
-
|
|
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({
|
|
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 = {
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
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,
|
|
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);
|
|
648
|
-
|
|
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(
|
|
721
|
-
|
|
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(
|
|
726
|
-
|
|
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({
|
|
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
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
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
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
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 {
|
|
851
|
-
|
|
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({
|
|
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 =
|
|
960
|
-
|
|
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(
|
|
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({
|
|
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 } =
|
|
1027
|
-
|
|
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' },
|
|
1033
|
-
{ type: 'uint256' },
|
|
1034
|
-
{ type: '
|
|
1035
|
-
{ type: '
|
|
1036
|
-
{ type: '
|
|
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',
|
|
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({
|
|
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
|
-
{
|
|
1099
|
-
|
|
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(
|
|
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
|
|