@whetstone-research/doppler-sdk 0.0.22 → 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 +553 -221
- package/dist/DopplerSDK.d.mts +12 -0
- package/dist/DopplerSDK.d.ts +12 -0
- package/dist/DopplerSDK.js +29 -26
- package/dist/DopplerSDK.mjs +28 -25
- package/dist/abis/bytecodes/derc20.js +2 -2
- package/dist/abis/bytecodes/derc20.mjs +1 -1
- package/dist/abis/bytecodes/derc2080.js +2 -2
- package/dist/abis/bytecodes/derc2080.mjs +1 -1
- package/dist/abis/bytecodes/doppler.js +2 -2
- package/dist/abis/bytecodes/doppler.mjs +1 -1
- package/dist/abis/bytecodes/dopplerDN404.js +2 -2
- package/dist/abis/bytecodes/dopplerDN404.mjs +1 -1
- package/dist/abis/bytecodes/stateView.js +2 -2
- package/dist/abis/bytecodes/stateView.mjs +1 -1
- package/dist/abis/bytecodes.js +10 -10
- package/dist/abis/bytecodes.mjs +5 -5
- package/dist/abis/index.d.mts +421 -10
- package/dist/abis/index.d.ts +421 -10
- package/dist/abis/index.js +41 -33
- package/dist/abis/index.mjs +6 -6
- package/dist/addresses.d.mts +6 -0
- package/dist/addresses.d.ts +6 -0
- package/dist/addresses.js +7 -7
- package/dist/addresses.mjs +2 -2
- package/dist/builders/DynamicAuctionBuilder.d.mts +2 -0
- package/dist/builders/DynamicAuctionBuilder.d.ts +2 -0
- package/dist/builders/DynamicAuctionBuilder.js +17 -16
- package/dist/builders/DynamicAuctionBuilder.mjs +16 -15
- package/dist/builders/MulticurveBuilder.d.mts +18 -5
- package/dist/builders/MulticurveBuilder.d.ts +18 -5
- package/dist/builders/MulticurveBuilder.js +17 -16
- package/dist/builders/MulticurveBuilder.mjs +16 -15
- package/dist/builders/StaticAuctionBuilder.js +17 -16
- package/dist/builders/StaticAuctionBuilder.mjs +16 -15
- package/dist/builders/index.js +25 -24
- package/dist/builders/index.mjs +18 -17
- package/dist/builders/shared.d.mts +1 -1
- package/dist/builders/shared.d.ts +1 -1
- package/dist/builders/shared.js +19 -17
- package/dist/builders/shared.mjs +15 -13
- package/dist/{chunk-3XYDN2XB.js → chunk-2A3B3NVB.js} +170 -25
- package/dist/chunk-2A3B3NVB.js.map +1 -0
- package/dist/{chunk-AZOBEWP3.mjs → chunk-3NMGCQJ4.mjs} +2 -2
- package/dist/chunk-3NMGCQJ4.mjs.map +1 -0
- package/dist/{chunk-CUB4F546.js → chunk-44CYUEPG.js} +25 -13
- package/dist/chunk-44CYUEPG.js.map +1 -0
- package/dist/{chunk-AZH2P4JK.mjs → chunk-5GQJRNFL.mjs} +3 -3
- package/dist/{chunk-AZH2P4JK.mjs.map → chunk-5GQJRNFL.mjs.map} +1 -1
- package/dist/{chunk-ZDTJ3BPS.js → chunk-5JHXBDZD.js} +20 -20
- package/dist/{chunk-ZDTJ3BPS.js.map → chunk-5JHXBDZD.js.map} +1 -1
- package/dist/{chunk-OGYWNJGI.js → chunk-5TQOT6CW.js} +2 -2
- package/dist/chunk-5TQOT6CW.js.map +1 -0
- package/dist/{chunk-COOVGAOE.js → chunk-65CESA3J.js} +19 -13
- package/dist/chunk-65CESA3J.js.map +1 -0
- package/dist/{chunk-5VV7STYK.js → chunk-7A4DBBXA.js} +141 -101
- package/dist/chunk-7A4DBBXA.js.map +1 -0
- package/dist/chunk-7ZUV6WPX.mjs +3 -0
- package/dist/{chunk-5TL5V6UX.mjs.map → chunk-7ZUV6WPX.mjs.map} +1 -1
- 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-QQEOKYEX.js → chunk-BK3S6SVR.js} +383 -83
- package/dist/chunk-BK3S6SVR.js.map +1 -0
- package/dist/{chunk-S4IZ5ATO.js → chunk-BQZTELUX.js} +5 -5
- package/dist/{chunk-S4IZ5ATO.js.map → chunk-BQZTELUX.js.map} +1 -1
- package/dist/{chunk-WKKOBMXR.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-YWK6YH6M.mjs → chunk-DQJXCZU2.mjs} +5 -5
- package/dist/{chunk-YWK6YH6M.mjs.map → chunk-DQJXCZU2.mjs.map} +1 -1
- package/dist/chunk-DSYPZETD.js +4 -0
- package/dist/{chunk-3PNCB4W5.js.map → chunk-DSYPZETD.js.map} +1 -1
- package/dist/chunk-F2BYG63D.mjs +145 -0
- package/dist/chunk-F2BYG63D.mjs.map +1 -0
- package/dist/{chunk-N33R22A2.js → chunk-FNUBKONK.js} +2 -2
- package/dist/{chunk-N33R22A2.js.map → chunk-FNUBKONK.js.map} +1 -1
- package/dist/chunk-FXTGIKQG.mjs +3 -0
- package/dist/{chunk-SD7BHT2F.mjs.map → chunk-FXTGIKQG.mjs.map} +1 -1
- package/dist/{chunk-MQNSJCAW.mjs → chunk-GSBQIVME.mjs} +2 -2
- package/dist/{chunk-MQNSJCAW.mjs.map → chunk-GSBQIVME.mjs.map} +1 -1
- package/dist/{chunk-SAX7P3MH.js → chunk-HJFVRV47.js} +2 -2
- package/dist/{chunk-SAX7P3MH.js.map → chunk-HJFVRV47.js.map} +1 -1
- package/dist/chunk-IIM2CSDQ.js +147 -0
- package/dist/chunk-IIM2CSDQ.js.map +1 -0
- package/dist/{chunk-O3RH43H3.mjs → chunk-IUTIHSLH.mjs} +4 -4
- package/dist/{chunk-O3RH43H3.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-D7PCIMWU.mjs → chunk-IX4V4UGW.mjs} +4 -4
- package/dist/{chunk-D7PCIMWU.mjs.map → chunk-IX4V4UGW.mjs.map} +1 -1
- package/dist/{chunk-2ZM4JVFC.js → chunk-J62YDWIK.js} +2 -2
- package/dist/chunk-J62YDWIK.js.map +1 -0
- package/dist/{chunk-E2NF4AQB.mjs → chunk-JLUOFAE4.mjs} +272 -12
- package/dist/chunk-JLUOFAE4.mjs.map +1 -0
- package/dist/{chunk-KITPRKQ4.mjs → chunk-LW3CYA27.mjs} +351 -51
- package/dist/chunk-LW3CYA27.mjs.map +1 -0
- package/dist/{chunk-3L4DLMOK.js → chunk-MEA2C5YX.js} +16 -16
- package/dist/{chunk-3L4DLMOK.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-WDSV4O6T.mjs → chunk-OHA5KJ2M.mjs} +2 -2
- package/dist/chunk-OHA5KJ2M.mjs.map +1 -0
- package/dist/{chunk-MT34O3YL.js → chunk-P563HTVU.js} +50 -26
- package/dist/chunk-P563HTVU.js.map +1 -0
- package/dist/{chunk-RLUMYHPI.js → chunk-PGYTMRP3.js} +46 -18
- package/dist/chunk-PGYTMRP3.js.map +1 -0
- package/dist/{chunk-VGOEXLQ2.js → chunk-QAPQGDWK.js} +2 -2
- package/dist/chunk-QAPQGDWK.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-OF7BIKXV.js → chunk-QRTABC4Z.js} +2 -2
- package/dist/chunk-QRTABC4Z.js.map +1 -0
- package/dist/{chunk-CS6FVODR.mjs → chunk-QUBD6HUZ.mjs} +163 -18
- package/dist/chunk-QUBD6HUZ.mjs.map +1 -0
- package/dist/{chunk-RWVNXU7Z.mjs → chunk-RDTIXP6S.mjs} +4 -4
- package/dist/{chunk-RWVNXU7Z.mjs.map → chunk-RDTIXP6S.mjs.map} +1 -1
- package/dist/{chunk-5WYXNWNH.js → chunk-RLOZWHRR.js} +11 -11
- package/dist/{chunk-5WYXNWNH.js.map → chunk-RLOZWHRR.js.map} +1 -1
- package/dist/{chunk-VK5HAWX6.mjs → chunk-SWWLOD7Q.mjs} +2 -2
- package/dist/chunk-SWWLOD7Q.mjs.map +1 -0
- package/dist/chunk-T3UA4MJL.js +4 -0
- package/dist/{chunk-WTS75RUC.js.map → chunk-T3UA4MJL.js.map} +1 -1
- package/dist/{chunk-HJ4AS5DZ.mjs → chunk-TEWAXP5C.mjs} +36 -12
- package/dist/chunk-TEWAXP5C.mjs.map +1 -0
- package/dist/{chunk-ZRNPHFP3.mjs → chunk-THEIRDGE.mjs} +50 -15
- package/dist/chunk-THEIRDGE.mjs.map +1 -0
- package/dist/{chunk-LPA32BIK.mjs → chunk-U3GOWK6J.mjs} +2 -2
- package/dist/chunk-U3GOWK6J.mjs.map +1 -0
- package/dist/{chunk-QFQXHDC7.mjs → chunk-VKSD3KXF.mjs} +46 -18
- package/dist/chunk-VKSD3KXF.mjs.map +1 -0
- package/dist/{chunk-64ZQRKG3.mjs → chunk-VYSOAGRU.mjs} +2 -2
- package/dist/chunk-VYSOAGRU.mjs.map +1 -0
- package/dist/{chunk-ADAAU4F5.mjs → chunk-WDC53TM7.mjs} +49 -9
- package/dist/chunk-WDC53TM7.mjs.map +1 -0
- package/dist/{chunk-M2EMKIP5.mjs → chunk-WKWP42TD.mjs} +9 -4
- package/dist/chunk-WKWP42TD.mjs.map +1 -0
- package/dist/{chunk-OROTK4OT.js → chunk-WNUB3UTT.js} +12 -12
- package/dist/chunk-WNUB3UTT.js.map +1 -0
- package/dist/{chunk-FVTTG72Z.mjs → chunk-WNWK2QMU.mjs} +19 -7
- package/dist/chunk-WNWK2QMU.mjs.map +1 -0
- package/dist/{chunk-INLXNN7P.js → chunk-WZF5XNBC.js} +26 -26
- package/dist/{chunk-INLXNN7P.js.map → chunk-WZF5XNBC.js.map} +1 -1
- package/dist/{chunk-SMTHFPBA.js → chunk-XMFOZYNI.js} +2 -2
- package/dist/chunk-XMFOZYNI.js.map +1 -0
- package/dist/{chunk-VGCXJRUV.mjs → chunk-YBK6EBA5.mjs} +10 -10
- package/dist/chunk-YBK6EBA5.mjs.map +1 -0
- package/dist/{chunk-HH7HQ4HC.mjs → chunk-ZEDJUNC6.mjs} +2 -2
- package/dist/{chunk-HH7HQ4HC.mjs.map → chunk-ZEDJUNC6.mjs.map} +1 -1
- package/dist/deployments.generated.d.mts +44 -16
- package/dist/deployments.generated.d.ts +44 -16
- 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 +16 -14
- package/dist/entities/DopplerFactory.mjs +15 -13
- package/dist/entities/auction/DynamicAuction.js +10 -10
- package/dist/entities/auction/DynamicAuction.mjs +9 -9
- package/dist/entities/auction/MulticurvePool.d.mts +6 -2
- package/dist/entities/auction/MulticurvePool.d.ts +6 -2
- package/dist/entities/auction/MulticurvePool.js +11 -11
- package/dist/entities/auction/MulticurvePool.mjs +10 -10
- 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 +10 -10
- package/dist/entities/auction/StaticAuction.mjs +9 -9
- package/dist/entities/auction/index.d.mts +2 -0
- package/dist/entities/auction/index.d.ts +2 -0
- package/dist/entities/auction/index.js +38 -18
- package/dist/entities/auction/index.mjs +25 -13
- package/dist/entities/quoter/Quoter.js +10 -10
- package/dist/entities/quoter/Quoter.mjs +9 -9
- package/dist/entities/quoter/index.js +10 -10
- package/dist/entities/quoter/index.mjs +9 -9
- package/dist/entities/token/derc20/Derc20.js +8 -8
- package/dist/entities/token/derc20/Derc20.mjs +7 -7
- package/dist/entities/token/derc20/index.js +8 -8
- package/dist/entities/token/derc20/index.mjs +7 -7
- package/dist/entities/token/index.js +11 -11
- package/dist/entities/token/index.mjs +7 -7
- package/dist/index.d.mts +5 -2
- package/dist/index.d.ts +5 -2
- package/dist/index.js +120 -93
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +28 -25
- package/dist/index.mjs.map +1 -1
- package/dist/types.d.mts +90 -7
- package/dist/types.d.ts +90 -7
- 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 +18 -0
- package/dist/utils/dopplerHookMigrator.d.ts +18 -0
- package/dist/utils/dopplerHookMigrator.js +20 -0
- package/dist/utils/dopplerHookMigrator.js.map +1 -0
- package/dist/utils/dopplerHookMigrator.mjs +7 -0
- package/dist/utils/dopplerHookMigrator.mjs.map +1 -0
- package/dist/utils/index.d.mts +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +39 -32
- package/dist/utils/index.mjs +15 -12
- package/dist/utils/marketCapHelpers.js +13 -13
- package/dist/utils/marketCapHelpers.mjs +1 -1
- package/dist/utils/tokenAddressMiner.js +8 -8
- package/dist/utils/tokenAddressMiner.mjs +7 -7
- package/package.json +2 -2
- package/dist/chunk-2ZM4JVFC.js.map +0 -1
- package/dist/chunk-3MVW6UIW.js.map +0 -1
- package/dist/chunk-3PNCB4W5.js +0 -4
- package/dist/chunk-3XYDN2XB.js.map +0 -1
- package/dist/chunk-5TL5V6UX.mjs +0 -3
- package/dist/chunk-5VV7STYK.js.map +0 -1
- package/dist/chunk-64ZQRKG3.mjs.map +0 -1
- package/dist/chunk-ADAAU4F5.mjs.map +0 -1
- package/dist/chunk-AZOBEWP3.mjs.map +0 -1
- package/dist/chunk-COOVGAOE.js.map +0 -1
- package/dist/chunk-CS6FVODR.mjs.map +0 -1
- package/dist/chunk-CUB4F546.js.map +0 -1
- package/dist/chunk-E2NF4AQB.mjs.map +0 -1
- package/dist/chunk-FVTTG72Z.mjs.map +0 -1
- package/dist/chunk-HJ4AS5DZ.mjs.map +0 -1
- package/dist/chunk-KITPRKQ4.mjs.map +0 -1
- package/dist/chunk-LPA32BIK.mjs.map +0 -1
- package/dist/chunk-M2EMKIP5.mjs.map +0 -1
- package/dist/chunk-MT34O3YL.js.map +0 -1
- package/dist/chunk-OF7BIKXV.js.map +0 -1
- package/dist/chunk-OGYWNJGI.js.map +0 -1
- package/dist/chunk-OROTK4OT.js.map +0 -1
- package/dist/chunk-QFQXHDC7.mjs.map +0 -1
- package/dist/chunk-QQEOKYEX.js.map +0 -1
- package/dist/chunk-RLUMYHPI.js.map +0 -1
- package/dist/chunk-SD7BHT2F.mjs +0 -3
- package/dist/chunk-SMTHFPBA.js.map +0 -1
- package/dist/chunk-VGCXJRUV.mjs.map +0 -1
- package/dist/chunk-VGOEXLQ2.js.map +0 -1
- package/dist/chunk-VK5HAWX6.mjs.map +0 -1
- package/dist/chunk-WDSV4O6T.mjs.map +0 -1
- package/dist/chunk-WKKOBMXR.js.map +0 -1
- package/dist/chunk-WTS75RUC.js +0 -4
- package/dist/chunk-ZRNPHFP3.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',
|
|
@@ -769,22 +967,120 @@ migration: {
|
|
|
769
967
|
}
|
|
770
968
|
```
|
|
771
969
|
|
|
970
|
+
### Migrate via DopplerHookMigrator (Dynamic Auctions)
|
|
971
|
+
|
|
972
|
+
Use this mode when you want rehypothecation / custom hook behavior on the
|
|
973
|
+
migrated V4 pool. This migration type is only supported for dynamic auctions.
|
|
974
|
+
|
|
975
|
+
```typescript
|
|
976
|
+
const params = sdk
|
|
977
|
+
.buildDynamicAuction()
|
|
978
|
+
.tokenConfig({
|
|
979
|
+
name: 'Example',
|
|
980
|
+
symbol: 'EX',
|
|
981
|
+
tokenURI: 'https://example.com/token.json',
|
|
982
|
+
})
|
|
983
|
+
.saleConfig({
|
|
984
|
+
initialSupply: parseEther('1000000'),
|
|
985
|
+
numTokensToSell: parseEther('500000'),
|
|
986
|
+
numeraire: addresses.weth,
|
|
987
|
+
})
|
|
988
|
+
.withMarketCapRange({
|
|
989
|
+
marketCap: { start: 500_000, min: 50_000 },
|
|
990
|
+
numerairePrice: 3000,
|
|
991
|
+
minProceeds: parseEther('10'),
|
|
992
|
+
maxProceeds: parseEther('1000'),
|
|
993
|
+
fee: 3000,
|
|
994
|
+
tickSpacing: 10,
|
|
995
|
+
})
|
|
996
|
+
.withMigration({
|
|
997
|
+
type: 'dopplerHook',
|
|
998
|
+
fee: 3000,
|
|
999
|
+
tickSpacing: 10,
|
|
1000
|
+
lockDuration: 30 * 24 * 60 * 60,
|
|
1001
|
+
beneficiaries: [
|
|
1002
|
+
{ beneficiary: '0xYourBeneficiary...', shares: parseEther('0.95') },
|
|
1003
|
+
await sdk.getAirlockBeneficiary(), // required protocol owner entry (>=5%)
|
|
1004
|
+
],
|
|
1005
|
+
rehype: {
|
|
1006
|
+
buybackDestination: '0xYourBuybackDestination...',
|
|
1007
|
+
customFee: 3000,
|
|
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
|
+
},
|
|
1019
|
+
},
|
|
1020
|
+
})
|
|
1021
|
+
.withUserAddress('0xYourAddress...')
|
|
1022
|
+
.build();
|
|
1023
|
+
```
|
|
1024
|
+
|
|
1025
|
+
Note: `dopplerHook` migrator beneficiaries must include the current Airlock owner
|
|
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.
|
|
1029
|
+
|
|
1030
|
+
```typescript
|
|
1031
|
+
migration: {
|
|
1032
|
+
type: 'dopplerHook',
|
|
1033
|
+
fee: 3000,
|
|
1034
|
+
useDynamicFee: false,
|
|
1035
|
+
tickSpacing: 10,
|
|
1036
|
+
lockDuration: 30 * 24 * 60 * 60,
|
|
1037
|
+
beneficiaries: [
|
|
1038
|
+
{ beneficiary: '0xYourBeneficiary...', shares: parseEther('1') },
|
|
1039
|
+
],
|
|
1040
|
+
rehype: {
|
|
1041
|
+
// optional; defaults to chain rehypeDopplerHookMigrator address
|
|
1042
|
+
// hookAddress: '0xRehypeMigratorHook...',
|
|
1043
|
+
buybackDestination: '0xYourBuybackDestination...',
|
|
1044
|
+
customFee: 3000,
|
|
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
|
+
},
|
|
1056
|
+
},
|
|
1057
|
+
proceedsSplit: {
|
|
1058
|
+
recipient: '0xProceedsRecipient...',
|
|
1059
|
+
share: parseEther('0.1'),
|
|
1060
|
+
},
|
|
1061
|
+
}
|
|
1062
|
+
```
|
|
1063
|
+
|
|
772
1064
|
To make configuring the first beneficiary simpler, the SDK now exposes helpers for resolving the
|
|
773
1065
|
airlock owner and creating the default 5% entry:
|
|
774
1066
|
|
|
775
1067
|
```ts
|
|
776
|
-
import {
|
|
777
|
-
|
|
1068
|
+
import {
|
|
1069
|
+
DopplerSDK,
|
|
1070
|
+
createAirlockBeneficiary,
|
|
1071
|
+
getAirlockOwner,
|
|
1072
|
+
} from '@whetstone-research/doppler-sdk';
|
|
1073
|
+
import { parseEther } from 'viem';
|
|
778
1074
|
|
|
779
|
-
const sdk = new DopplerSDK({ publicClient, chainId })
|
|
1075
|
+
const sdk = new DopplerSDK({ publicClient, chainId });
|
|
780
1076
|
|
|
781
1077
|
// Get the owner and construct the beneficiary entry (5% by default)
|
|
782
|
-
const airlockBeneficiary = await sdk.getAirlockBeneficiary()
|
|
1078
|
+
const airlockBeneficiary = await sdk.getAirlockBeneficiary();
|
|
783
1079
|
|
|
784
1080
|
// Or build the entry manually if you do not have an SDK instance handy
|
|
785
1081
|
// (airlockEntry will be equivalent to airlockBeneficiary above)
|
|
786
|
-
const owner = await getAirlockOwner(publicClient)
|
|
787
|
-
const airlockEntry = createAirlockBeneficiary(owner) // defaults to 5% shares
|
|
1082
|
+
const owner = await getAirlockOwner(publicClient);
|
|
1083
|
+
const airlockEntry = createAirlockBeneficiary(owner); // defaults to 5% shares
|
|
788
1084
|
|
|
789
1085
|
const migration = {
|
|
790
1086
|
type: 'uniswapV4' as const,
|
|
@@ -797,11 +1093,9 @@ const migration = {
|
|
|
797
1093
|
{ beneficiary: '0xYourDAO...', shares: parseEther('0.95') }, // 95%
|
|
798
1094
|
],
|
|
799
1095
|
},
|
|
800
|
-
}
|
|
1096
|
+
};
|
|
801
1097
|
```
|
|
802
1098
|
|
|
803
|
-
|
|
804
|
-
|
|
805
1099
|
## Supported Chains
|
|
806
1100
|
|
|
807
1101
|
The SDK exposes runtime constants and TypeScript types for supported chains:
|
|
@@ -814,21 +1108,21 @@ import {
|
|
|
814
1108
|
isSupportedChainId,
|
|
815
1109
|
type SupportedChainId,
|
|
816
1110
|
type ChainAddresses,
|
|
817
|
-
} from '@whetstone-research/doppler-sdk'
|
|
1111
|
+
} from '@whetstone-research/doppler-sdk';
|
|
818
1112
|
|
|
819
1113
|
// Validate and narrow a chain ID
|
|
820
1114
|
function ensureSupported(id: number): SupportedChainId {
|
|
821
|
-
if (!isSupportedChainId(id)) throw new Error('Unsupported chain')
|
|
822
|
-
return id
|
|
1115
|
+
if (!isSupportedChainId(id)) throw new Error('Unsupported chain');
|
|
1116
|
+
return id;
|
|
823
1117
|
}
|
|
824
1118
|
|
|
825
|
-
const chainId = ensureSupported(CHAIN_IDS.BASE)
|
|
826
|
-
const addresses: ChainAddresses = getAddresses(chainId)
|
|
827
|
-
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);
|
|
828
1122
|
|
|
829
1123
|
// Iterate supported chains
|
|
830
1124
|
for (const id of SUPPORTED_CHAIN_IDS) {
|
|
831
|
-
console.log('Supported chain id:', id)
|
|
1125
|
+
console.log('Supported chain id:', id);
|
|
832
1126
|
}
|
|
833
1127
|
```
|
|
834
1128
|
|
|
@@ -851,6 +1145,7 @@ vesting: {
|
|
|
851
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.
|
|
852
1146
|
|
|
853
1147
|
`mineTokenAddress` supports matching:
|
|
1148
|
+
|
|
854
1149
|
- A **prefix** (address starts with hex characters)
|
|
855
1150
|
- A **suffix** (address ends with hex characters, useful as an identifier)
|
|
856
1151
|
- Both prefix + suffix simultaneously (logical AND)
|
|
@@ -864,12 +1159,16 @@ import {
|
|
|
864
1159
|
StaticAuctionBuilder,
|
|
865
1160
|
mineTokenAddress,
|
|
866
1161
|
getAddresses,
|
|
867
|
-
} from '@whetstone-research/doppler-sdk'
|
|
868
|
-
import { parseEther } from 'viem'
|
|
869
|
-
import { base } from 'viem/chains'
|
|
1162
|
+
} from '@whetstone-research/doppler-sdk';
|
|
1163
|
+
import { parseEther } from 'viem';
|
|
1164
|
+
import { base } from 'viem/chains';
|
|
870
1165
|
|
|
871
1166
|
const builder = new StaticAuctionBuilder(base.id)
|
|
872
|
-
.tokenConfig({
|
|
1167
|
+
.tokenConfig({
|
|
1168
|
+
name: 'Vanity Token',
|
|
1169
|
+
symbol: 'VNY',
|
|
1170
|
+
tokenURI: 'https://example.com/token.json',
|
|
1171
|
+
})
|
|
873
1172
|
.saleConfig({
|
|
874
1173
|
initialSupply: parseEther('1000000'),
|
|
875
1174
|
numTokensToSell: parseEther('750000'),
|
|
@@ -878,12 +1177,13 @@ const builder = new StaticAuctionBuilder(base.id)
|
|
|
878
1177
|
.poolByTicks({ startTick: -92100, endTick: -69060, fee: 3000 })
|
|
879
1178
|
.withGovernance({ type: 'default' })
|
|
880
1179
|
.withMigration({ type: 'uniswapV3', fee: 3000, tickSpacing: 60 })
|
|
881
|
-
.withUserAddress('0x...')
|
|
1180
|
+
.withUserAddress('0x...');
|
|
882
1181
|
|
|
883
|
-
const staticParams = builder.build()
|
|
1182
|
+
const staticParams = builder.build();
|
|
884
1183
|
// Fetch the encoded create() payload without sending the transaction
|
|
885
|
-
const createParams =
|
|
886
|
-
|
|
1184
|
+
const createParams =
|
|
1185
|
+
await sdk.factory.encodeCreateStaticAuctionParams(staticParams);
|
|
1186
|
+
const addresses = getAddresses(base.id);
|
|
887
1187
|
|
|
888
1188
|
const { salt, tokenAddress, iterations } = mineTokenAddress({
|
|
889
1189
|
prefix: 'dead', // omit 0x prefix
|
|
@@ -893,9 +1193,11 @@ const { salt, tokenAddress, iterations } = mineTokenAddress({
|
|
|
893
1193
|
owner: addresses.airlock,
|
|
894
1194
|
tokenData: createParams.tokenFactoryData,
|
|
895
1195
|
maxIterations: 1_000_000, // optional safety cap
|
|
896
|
-
})
|
|
1196
|
+
});
|
|
897
1197
|
|
|
898
|
-
console.log(
|
|
1198
|
+
console.log(
|
|
1199
|
+
`Vanity token ${tokenAddress} found after ${iterations} iterations`,
|
|
1200
|
+
);
|
|
899
1201
|
// Now submit airlock.create({ ...createParams, salt }) when ready to deploy
|
|
900
1202
|
```
|
|
901
1203
|
|
|
@@ -911,7 +1213,7 @@ const { salt, tokenAddress, iterations } = mineTokenAddress({
|
|
|
911
1213
|
owner: addresses.airlock,
|
|
912
1214
|
tokenData: createParams.tokenFactoryData,
|
|
913
1215
|
maxIterations: 1_000_000,
|
|
914
|
-
})
|
|
1216
|
+
});
|
|
915
1217
|
```
|
|
916
1218
|
|
|
917
1219
|
#### Mining Hook and Token Addresses (Dynamic Auctions)
|
|
@@ -925,12 +1227,16 @@ import {
|
|
|
925
1227
|
getAddresses,
|
|
926
1228
|
DopplerBytecode,
|
|
927
1229
|
DAY_SECONDS,
|
|
928
|
-
} from '@whetstone-research/doppler-sdk'
|
|
929
|
-
import { parseEther, keccak256, encodePacked, encodeAbiParameters } from 'viem'
|
|
930
|
-
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';
|
|
931
1233
|
|
|
932
1234
|
const builder = new DynamicAuctionBuilder()
|
|
933
|
-
.tokenConfig({
|
|
1235
|
+
.tokenConfig({
|
|
1236
|
+
name: 'My Token',
|
|
1237
|
+
symbol: 'MTK',
|
|
1238
|
+
tokenURI: 'https://example.com/token.json',
|
|
1239
|
+
})
|
|
934
1240
|
.saleConfig({
|
|
935
1241
|
initialSupply: parseEther('1000000'),
|
|
936
1242
|
numTokensToSell: parseEther('900000'),
|
|
@@ -946,20 +1252,30 @@ const builder = new DynamicAuctionBuilder()
|
|
|
946
1252
|
maxProceeds: parseEther('1000'),
|
|
947
1253
|
})
|
|
948
1254
|
.withMigration({ type: 'uniswapV4', fee: 3000, tickSpacing: 60 })
|
|
949
|
-
.withUserAddress('0x...')
|
|
1255
|
+
.withUserAddress('0x...');
|
|
950
1256
|
|
|
951
|
-
const dynamicParams = builder.build()
|
|
952
|
-
const { createParams } =
|
|
953
|
-
|
|
1257
|
+
const dynamicParams = builder.build();
|
|
1258
|
+
const { createParams } =
|
|
1259
|
+
await sdk.factory.encodeCreateDynamicAuctionParams(dynamicParams);
|
|
1260
|
+
const addresses = getAddresses(base.id);
|
|
954
1261
|
|
|
955
1262
|
// Compute hook init code hash (required for hook mining)
|
|
956
1263
|
const hookInitHashData = encodeAbiParameters(
|
|
957
1264
|
[
|
|
958
|
-
{ type: 'address' },
|
|
959
|
-
{ type: 'uint256' },
|
|
960
|
-
{ type: '
|
|
961
|
-
{ type: '
|
|
962
|
-
{ 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' },
|
|
963
1279
|
],
|
|
964
1280
|
[
|
|
965
1281
|
addresses.poolManager,
|
|
@@ -968,15 +1284,15 @@ const hookInitHashData = encodeAbiParameters(
|
|
|
968
1284
|
dynamicParams.auction.maxProceeds,
|
|
969
1285
|
/* startingTime, endingTime, startTick, endTick, epochLength, gamma, isToken0, numPDSlugs */
|
|
970
1286
|
/* poolInitializer, fee - extract from createParams */
|
|
971
|
-
]
|
|
972
|
-
)
|
|
1287
|
+
],
|
|
1288
|
+
);
|
|
973
1289
|
|
|
974
1290
|
const hookInitHash = keccak256(
|
|
975
|
-
encodePacked(['bytes', 'bytes'], [DopplerBytecode, hookInitHashData])
|
|
976
|
-
)
|
|
1291
|
+
encodePacked(['bytes', 'bytes'], [DopplerBytecode, hookInitHashData]),
|
|
1292
|
+
);
|
|
977
1293
|
|
|
978
1294
|
const result = mineTokenAddress({
|
|
979
|
-
prefix: 'cafe',
|
|
1295
|
+
prefix: 'cafe', // Token prefix
|
|
980
1296
|
tokenFactory: createParams.tokenFactory,
|
|
981
1297
|
initialSupply: createParams.initialSupply,
|
|
982
1298
|
recipient: addresses.airlock,
|
|
@@ -990,11 +1306,11 @@ const result = mineTokenAddress({
|
|
|
990
1306
|
initCodeHash: hookInitHash,
|
|
991
1307
|
prefix: '00', // Hook prefix for gas optimization
|
|
992
1308
|
},
|
|
993
|
-
})
|
|
1309
|
+
});
|
|
994
1310
|
|
|
995
|
-
console.log('Token address:', result.tokenAddress)
|
|
996
|
-
console.log('Hook address:', result.hookAddress) // only if hook config provided
|
|
997
|
-
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`);
|
|
998
1314
|
```
|
|
999
1315
|
|
|
1000
1316
|
#### Mining Token Addresses (Multicurve Auctions)
|
|
@@ -1006,12 +1322,16 @@ import {
|
|
|
1006
1322
|
MulticurveBuilder,
|
|
1007
1323
|
mineTokenAddress,
|
|
1008
1324
|
getAddresses,
|
|
1009
|
-
} from '@whetstone-research/doppler-sdk'
|
|
1010
|
-
import { parseEther } from 'viem'
|
|
1011
|
-
import { base } from 'viem/chains'
|
|
1325
|
+
} from '@whetstone-research/doppler-sdk';
|
|
1326
|
+
import { parseEther } from 'viem';
|
|
1327
|
+
import { base } from 'viem/chains';
|
|
1012
1328
|
|
|
1013
1329
|
const builder = new MulticurveBuilder(base.id)
|
|
1014
|
-
.tokenConfig({
|
|
1330
|
+
.tokenConfig({
|
|
1331
|
+
name: 'Vanity Multicurve',
|
|
1332
|
+
symbol: 'VMC',
|
|
1333
|
+
tokenURI: 'https://example.com/token.json',
|
|
1334
|
+
})
|
|
1015
1335
|
.saleConfig({
|
|
1016
1336
|
initialSupply: parseEther('1000000'),
|
|
1017
1337
|
numTokensToSell: parseEther('900000'),
|
|
@@ -1021,19 +1341,29 @@ const builder = new MulticurveBuilder(base.id)
|
|
|
1021
1341
|
fee: 3000,
|
|
1022
1342
|
tickSpacing: 60,
|
|
1023
1343
|
curves: [
|
|
1024
|
-
{
|
|
1025
|
-
|
|
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
|
+
},
|
|
1026
1356
|
],
|
|
1027
1357
|
})
|
|
1028
1358
|
.withGovernance({ type: 'default' })
|
|
1029
1359
|
.withMigration({ type: 'uniswapV2' })
|
|
1030
|
-
.withUserAddress('0x...')
|
|
1360
|
+
.withUserAddress('0x...');
|
|
1031
1361
|
|
|
1032
|
-
const multicurveParams = builder.build()
|
|
1033
|
-
const addresses = getAddresses(base.id)
|
|
1362
|
+
const multicurveParams = builder.build();
|
|
1363
|
+
const addresses = getAddresses(base.id);
|
|
1034
1364
|
|
|
1035
1365
|
// Get CreateParams without calling create
|
|
1036
|
-
const createParams = sdk.factory.encodeCreateMulticurveParams(multicurveParams)
|
|
1366
|
+
const createParams = sdk.factory.encodeCreateMulticurveParams(multicurveParams);
|
|
1037
1367
|
|
|
1038
1368
|
// Mine a vanity token address
|
|
1039
1369
|
const { salt, tokenAddress, iterations } = mineTokenAddress({
|
|
@@ -1044,12 +1374,14 @@ const { salt, tokenAddress, iterations } = mineTokenAddress({
|
|
|
1044
1374
|
owner: addresses.airlock,
|
|
1045
1375
|
tokenData: createParams.tokenFactoryData,
|
|
1046
1376
|
maxIterations: 500_000,
|
|
1047
|
-
})
|
|
1377
|
+
});
|
|
1048
1378
|
|
|
1049
|
-
console.log(
|
|
1379
|
+
console.log(
|
|
1380
|
+
`Vanity token ${tokenAddress} found after ${iterations} iterations`,
|
|
1381
|
+
);
|
|
1050
1382
|
|
|
1051
1383
|
// Use the mined salt in createParams
|
|
1052
|
-
const vanityCreateParams = { ...createParams, salt }
|
|
1384
|
+
const vanityCreateParams = { ...createParams, salt };
|
|
1053
1385
|
|
|
1054
1386
|
// Now submit the transaction manually with the vanity salt
|
|
1055
1387
|
await publicClient.writeContract({
|
|
@@ -1058,7 +1390,7 @@ await publicClient.writeContract({
|
|
|
1058
1390
|
functionName: 'create',
|
|
1059
1391
|
args: [vanityCreateParams],
|
|
1060
1392
|
account: walletClient.account,
|
|
1061
|
-
})
|
|
1393
|
+
});
|
|
1062
1394
|
```
|
|
1063
1395
|
|
|
1064
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.
|
|
@@ -1089,19 +1421,19 @@ The main SDK class providing access to all functionality.
|
|
|
1089
1421
|
|
|
1090
1422
|
```typescript
|
|
1091
1423
|
class DopplerSDK {
|
|
1092
|
-
constructor(config: DopplerSDKConfig)
|
|
1093
|
-
|
|
1424
|
+
constructor(config: DopplerSDKConfig);
|
|
1425
|
+
|
|
1094
1426
|
// Properties
|
|
1095
|
-
factory: DopplerFactory
|
|
1096
|
-
quoter: Quoter
|
|
1097
|
-
|
|
1427
|
+
factory: DopplerFactory;
|
|
1428
|
+
quoter: Quoter;
|
|
1429
|
+
|
|
1098
1430
|
// Methods
|
|
1099
|
-
getStaticAuction(poolAddress: Address): Promise<StaticAuction
|
|
1100
|
-
getDynamicAuction(hookAddress: Address): Promise<DynamicAuction
|
|
1431
|
+
getStaticAuction(poolAddress: Address): Promise<StaticAuction>;
|
|
1432
|
+
getDynamicAuction(hookAddress: Address): Promise<DynamicAuction>;
|
|
1101
1433
|
// Multicurve helper
|
|
1102
|
-
buildMulticurveAuction(): MulticurveBuilder
|
|
1103
|
-
getPoolInfo(poolAddress: Address): Promise<PoolInfo
|
|
1104
|
-
getHookInfo(hookAddress: Address): Promise<HookInfo
|
|
1434
|
+
buildMulticurveAuction(): MulticurveBuilder;
|
|
1435
|
+
getPoolInfo(poolAddress: Address): Promise<PoolInfo>;
|
|
1436
|
+
getHookInfo(hookAddress: Address): Promise<HookInfo>;
|
|
1105
1437
|
}
|
|
1106
1438
|
```
|
|
1107
1439
|
|