@whetstone-research/doppler-sdk 1.0.8 → 1.0.10
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 +170 -29
- package/dist/{chunk-BXATWUGJ.cjs → chunk-I5JME35L.cjs} +39 -39
- package/dist/{chunk-BXATWUGJ.cjs.map → chunk-I5JME35L.cjs.map} +1 -1
- package/dist/{chunk-DPKVNI6Q.cjs → chunk-O6FR7TXY.cjs} +27 -3
- package/dist/chunk-O6FR7TXY.cjs.map +1 -0
- package/dist/{chunk-BSHIMMA4.js → chunk-RF4NM4ES.js} +3 -3
- package/dist/{chunk-BSHIMMA4.js.map → chunk-RF4NM4ES.js.map} +1 -1
- package/dist/{chunk-J57ROY36.js → chunk-YWZCHTXQ.js} +25 -4
- package/dist/chunk-YWZCHTXQ.js.map +1 -0
- package/dist/evm/index.cjs +6411 -3526
- package/dist/evm/index.cjs.map +1 -1
- package/dist/evm/index.d.cts +1512 -78
- package/dist/evm/index.d.ts +1512 -78
- package/dist/evm/index.js +6408 -3527
- package/dist/evm/index.js.map +1 -1
- package/dist/pda-NKKMVQ4N.js +4 -0
- package/dist/pda-NKKMVQ4N.js.map +1 -0
- package/dist/pda-UKFLYQGA.cjs +61 -0
- package/dist/pda-UKFLYQGA.cjs.map +1 -0
- package/dist/solana/index.cjs +428 -332
- package/dist/solana/index.cjs.map +1 -1
- package/dist/solana/index.d.cts +160 -118
- package/dist/solana/index.d.ts +160 -118
- package/dist/solana/index.js +208 -112
- package/dist/solana/index.js.map +1 -1
- package/dist/solana/react/index.cjs +45 -45
- package/dist/solana/react/index.js +3 -3
- package/package.json +2 -1
- package/dist/chunk-DPKVNI6Q.cjs.map +0 -1
- package/dist/chunk-J57ROY36.js.map +0 -1
- package/dist/pda-TXZDXZZ4.js +0 -4
- package/dist/pda-TXZDXZZ4.js.map +0 -1
- package/dist/pda-ZZMBZSFU.cjs +0 -53
- package/dist/pda-ZZMBZSFU.cjs.map +0 -1
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ The Doppler SDK consolidates functionality from the previous `doppler-v3-sdk` an
|
|
|
11
11
|
- **Static Auctions**: Fixed price range liquidity bootstrapping using Uniswap V3
|
|
12
12
|
- **Dynamic Auctions**: Gradual Dutch auctions using Uniswap V4 hooks
|
|
13
13
|
- **Multicurve Initializer**: Seed Uniswap V4 pools across multiple curves
|
|
14
|
-
- **Flexible Migration**: Support for
|
|
14
|
+
- **Flexible Migration**: Support for V2, V2 split, V4, V4 split, DopplerHook, and no-op migration paths
|
|
15
15
|
- **Token Management**: Built-in support for DERC20 tokens with vesting
|
|
16
16
|
- **Type Safety**: Full TypeScript support with discriminated unions
|
|
17
17
|
- **Chain Support**: Works with Base, Unichain, Ink, and other EVM chains
|
|
@@ -65,8 +65,9 @@ Static auctions use Uniswap V3 pools with concentrated liquidity in a fixed pric
|
|
|
65
65
|
|
|
66
66
|
```typescript
|
|
67
67
|
import { StaticAuctionBuilder } from '@whetstone-research/doppler-sdk/evm';
|
|
68
|
+
import { base } from 'viem/chains';
|
|
68
69
|
|
|
69
|
-
const params = new StaticAuctionBuilder()
|
|
70
|
+
const params = new StaticAuctionBuilder(base.id)
|
|
70
71
|
.tokenConfig({
|
|
71
72
|
name: 'My Token',
|
|
72
73
|
symbol: 'MTK',
|
|
@@ -186,8 +187,9 @@ import {
|
|
|
186
187
|
DynamicAuctionBuilder,
|
|
187
188
|
DAY_SECONDS,
|
|
188
189
|
} from '@whetstone-research/doppler-sdk/evm';
|
|
190
|
+
import { base } from 'viem/chains';
|
|
189
191
|
|
|
190
|
-
const params = new DynamicAuctionBuilder()
|
|
192
|
+
const params = new DynamicAuctionBuilder(base.id)
|
|
191
193
|
.tokenConfig({
|
|
192
194
|
name: 'My Token',
|
|
193
195
|
symbol: 'MTK',
|
|
@@ -232,7 +234,7 @@ const params = new DynamicAuctionBuilder()
|
|
|
232
234
|
.withDopplerDeployer('0xDeployer...')
|
|
233
235
|
.withTokenFactory('0xFactory...')
|
|
234
236
|
.withV4Initializer('0xInitializer...')
|
|
235
|
-
.withGovernanceFactory('0xGovFactory...') // used for
|
|
237
|
+
.withGovernanceFactory('0xGovFactory...') // used for standard, no-op, or launchpad governance overrides
|
|
236
238
|
// .withV2Migrator('0xV2Migrator...')
|
|
237
239
|
// .withV3Migrator('0xV3Migrator...')
|
|
238
240
|
// .withV4Migrator('0xV4Migrator...')
|
|
@@ -354,7 +356,7 @@ const params = new MulticurveBuilder(base.id)
|
|
|
354
356
|
],
|
|
355
357
|
})
|
|
356
358
|
.withGovernance({ type: 'default' })
|
|
357
|
-
// Choose a migration path (V2,
|
|
359
|
+
// Choose a migration path (V2, V2 split, V4, V4 split, DopplerHook, or noOp)
|
|
358
360
|
.withMigration({ type: 'uniswapV2' })
|
|
359
361
|
.withUserAddress('0x...')
|
|
360
362
|
.build();
|
|
@@ -598,9 +600,10 @@ import {
|
|
|
598
600
|
DynamicAuctionBuilder,
|
|
599
601
|
} from '@whetstone-research/doppler-sdk/evm';
|
|
600
602
|
import { parseEther } from 'viem';
|
|
603
|
+
import { base } from 'viem/chains';
|
|
601
604
|
|
|
602
605
|
// Dynamic auction via builder
|
|
603
|
-
const dynamicParams = new DynamicAuctionBuilder()
|
|
606
|
+
const dynamicParams = new DynamicAuctionBuilder(base.id)
|
|
604
607
|
.tokenConfig({
|
|
605
608
|
name: 'My Token',
|
|
606
609
|
symbol: 'MTK',
|
|
@@ -624,7 +627,7 @@ const dynamicParams = new DynamicAuctionBuilder()
|
|
|
624
627
|
const dyn = await sdk.factory.createDynamicAuction(dynamicParams);
|
|
625
628
|
|
|
626
629
|
// Static auction via builder
|
|
627
|
-
const staticParams = new StaticAuctionBuilder()
|
|
630
|
+
const staticParams = new StaticAuctionBuilder(base.id)
|
|
628
631
|
.tokenConfig({
|
|
629
632
|
name: 'My Token',
|
|
630
633
|
symbol: 'MTK',
|
|
@@ -652,7 +655,7 @@ The SDK intelligently applies defaults when parameters are omitted. Here are exa
|
|
|
652
655
|
|
|
653
656
|
```typescript
|
|
654
657
|
// Minimal static auction via builder
|
|
655
|
-
const staticMinimal = new StaticAuctionBuilder()
|
|
658
|
+
const staticMinimal = new StaticAuctionBuilder(base.id)
|
|
656
659
|
.tokenConfig({
|
|
657
660
|
name: 'My Token',
|
|
658
661
|
symbol: 'MTK',
|
|
@@ -671,7 +674,7 @@ const staticMinimal = new StaticAuctionBuilder()
|
|
|
671
674
|
const staticResult = await sdk.factory.createStaticAuction(staticMinimal);
|
|
672
675
|
|
|
673
676
|
// Minimal dynamic auction via builder
|
|
674
|
-
const dynamicMinimal = new DynamicAuctionBuilder()
|
|
677
|
+
const dynamicMinimal = new DynamicAuctionBuilder(base.id)
|
|
675
678
|
.tokenConfig({
|
|
676
679
|
name: 'My Token',
|
|
677
680
|
symbol: 'MTK',
|
|
@@ -832,6 +835,67 @@ import { Derc20 } from '@whetstone-research/doppler-sdk/evm';
|
|
|
832
835
|
const tokenDirect = new Derc20(publicClient, walletClient, tokenAddress);
|
|
833
836
|
```
|
|
834
837
|
|
|
838
|
+
### DopplerERC20V1 Tokens
|
|
839
|
+
|
|
840
|
+
Use the newer DopplerERC20V1 token template by either setting `type: 'dopplerERC20V1'` explicitly or by passing fields such as `maxBalanceLimit` with `balanceLimitEnd`, `controller`, or `excludedFromBalanceLimit`. When selected, the SDK uses the configured `dopplerERC20V1Factory` by default. `withTokenFactory(address)` is a generic factory override and takes precedence, but it must point to a factory compatible with the selected token path and token data ABI. `controller` is optional and defaults to the zero address, set it only if early balance-limit disable should be possible. Standard configs without the specific fields still use the legacy `standard` path, where cliff/allocation vesting routes to legacy DERC20 V2. Keep explicit `type: 'dopplerERC20V1'` when you want its behavior but have no specific fields to infer from.
|
|
841
|
+
|
|
842
|
+
When balance limiting is enabled on the default DopplerERC20V1 integration, the SDK encodes user exclusions plus determinable protocol recipients for the selected auction path into deployment-time `excludedFromBalanceLimit`, including initializers, hooks, PoolManager, migrators, known migration pools, no-op governance, and launchpad governance multisigs. Custom `withTokenFactory(address)` paths receive only the `excludedFromBalanceLimit` entries supplied in `tokenConfig`, so custom factory users must provide any required deployment-time exclusions themselves. Exclusions cannot be added later through the controller or governance. Default and custom governance timelocks are not precomputed before create, so account for them before deployment or disable strict limits early via the controller when needed.
|
|
843
|
+
|
|
844
|
+
DopplerERC20V1 supports vesting through `withVesting` while staying on the DopplerERC20V1 factory path: use `duration` with optional `cliffDuration` for a shared schedule, or `allocations` for per-beneficiary schedules.
|
|
845
|
+
|
|
846
|
+
```typescript
|
|
847
|
+
const params = new StaticAuctionBuilder(base.id)
|
|
848
|
+
.tokenConfig({
|
|
849
|
+
name: 'My Doppler Token',
|
|
850
|
+
symbol: 'MDT',
|
|
851
|
+
tokenURI: 'ipfs://doppler-token.json',
|
|
852
|
+
maxBalanceLimit: parseEther('10000'),
|
|
853
|
+
balanceLimitEnd: Math.floor(Date.now() / 1000) + 30 * DAY_SECONDS,
|
|
854
|
+
controller: userAddress, // optional; defaults to zero address when omitted
|
|
855
|
+
excludedFromBalanceLimit: [userAddress], // default DopplerERC20V1 path also adds protocol modules
|
|
856
|
+
})
|
|
857
|
+
.saleConfig({
|
|
858
|
+
initialSupply: parseEther('1000000'),
|
|
859
|
+
numTokensToSell: parseEther('900000'),
|
|
860
|
+
numeraire: wethAddress,
|
|
861
|
+
})
|
|
862
|
+
.poolByTicks({ startTick: -120000, endTick: -60000, fee: 3000 })
|
|
863
|
+
.withVesting({
|
|
864
|
+
duration: 365n * BigInt(DAY_SECONDS),
|
|
865
|
+
cliffDuration: 30 * DAY_SECONDS,
|
|
866
|
+
recipients: [userAddress],
|
|
867
|
+
amounts: [parseEther('100000')],
|
|
868
|
+
})
|
|
869
|
+
.withMigration({ type: 'uniswapV2' })
|
|
870
|
+
.withUserAddress(userAddress)
|
|
871
|
+
.build();
|
|
872
|
+
```
|
|
873
|
+
|
|
874
|
+
DopplerERC20V1 token data includes schedule vesting and balance-limit controls, but it intentionally omits `yearlyMintRate`; DopplerERC20V1 tokens do not expose `mintInflation` or mint-rate update helpers.
|
|
875
|
+
|
|
876
|
+
```typescript
|
|
877
|
+
const token = sdk.getDopplerERC20V1(tokenAddress);
|
|
878
|
+
const scheduleCount = await token.getVestingScheduleCount();
|
|
879
|
+
|
|
880
|
+
for (let scheduleId = 0n; scheduleId < scheduleCount; scheduleId++) {
|
|
881
|
+
const schedule = await token.getVestingSchedule(scheduleId);
|
|
882
|
+
const available = await token.getAvailableVestedAmountForSchedule(
|
|
883
|
+
userAddress,
|
|
884
|
+
scheduleId,
|
|
885
|
+
);
|
|
886
|
+
console.log(schedule, available);
|
|
887
|
+
|
|
888
|
+
// Release half of the available vested amount for one schedule.
|
|
889
|
+
if (available > 0n) await token.releaseSchedule(scheduleId, available / 2n);
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
console.log(await token.getMaxBalanceLimit());
|
|
893
|
+
console.log(await token.getBalanceLimitEnd());
|
|
894
|
+
console.log(await token.isBalanceLimitActive());
|
|
895
|
+
```
|
|
896
|
+
|
|
897
|
+
For a runnable example, see [examples/doppler-erc20-v1.ts](./examples/doppler-erc20-v1.ts).
|
|
898
|
+
|
|
835
899
|
### Governance Delegation (ERC20Votes)
|
|
836
900
|
|
|
837
901
|
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.
|
|
@@ -1031,32 +1095,100 @@ migration: {
|
|
|
1031
1095
|
}
|
|
1032
1096
|
```
|
|
1033
1097
|
|
|
1034
|
-
### Migrate to Uniswap
|
|
1098
|
+
### Migrate to Uniswap V4
|
|
1035
1099
|
|
|
1036
1100
|
```typescript
|
|
1037
1101
|
migration: {
|
|
1038
|
-
type: '
|
|
1039
|
-
fee: 3000,
|
|
1040
|
-
tickSpacing: 60,
|
|
1102
|
+
type: 'uniswapV4',
|
|
1103
|
+
fee: 3000,
|
|
1104
|
+
tickSpacing: 60,
|
|
1105
|
+
streamableFees: {
|
|
1106
|
+
lockDuration: 365 * 24 * 60 * 60, // 1 year
|
|
1107
|
+
beneficiaries: [
|
|
1108
|
+
{ beneficiary: '0x...', shares: parseEther('1') }, // 100%
|
|
1109
|
+
],
|
|
1110
|
+
},
|
|
1041
1111
|
}
|
|
1042
1112
|
```
|
|
1043
1113
|
|
|
1044
|
-
### Migrate to Uniswap
|
|
1114
|
+
### Migrate to Uniswap V2 with Proceeds Split + Top-ups
|
|
1045
1115
|
|
|
1046
1116
|
```typescript
|
|
1047
1117
|
migration: {
|
|
1048
|
-
type: '
|
|
1118
|
+
type: 'uniswapV2Split',
|
|
1119
|
+
proceedsSplit: {
|
|
1120
|
+
recipient: '0xRecipient...',
|
|
1121
|
+
share: parseEther('0.1'), // 10%, capped at 50%
|
|
1122
|
+
},
|
|
1123
|
+
}
|
|
1124
|
+
```
|
|
1125
|
+
|
|
1126
|
+
- The split recipient receives the configured share of numeraire proceeds during migration.
|
|
1127
|
+
- If the asset/numeraire pair was topped up in `TopUpDistributor` before migration, the split recipient also receives those top-ups automatically.
|
|
1128
|
+
|
|
1129
|
+
### Migrate to Uniswap V4 with Proceeds Split + Top-ups
|
|
1130
|
+
|
|
1131
|
+
```typescript
|
|
1132
|
+
migration: {
|
|
1133
|
+
type: 'uniswapV4Split',
|
|
1049
1134
|
fee: 3000,
|
|
1050
|
-
tickSpacing:
|
|
1135
|
+
tickSpacing: 8,
|
|
1051
1136
|
streamableFees: {
|
|
1052
|
-
lockDuration:
|
|
1137
|
+
lockDuration: 30 * 24 * 60 * 60,
|
|
1053
1138
|
beneficiaries: [
|
|
1054
|
-
{ beneficiary: '
|
|
1139
|
+
{ beneficiary: '0xAirlockOwner...', shares: parseEther('0.05') },
|
|
1140
|
+
{ beneficiary: '0xTeam...', shares: parseEther('0.95') },
|
|
1055
1141
|
],
|
|
1056
1142
|
},
|
|
1143
|
+
proceedsSplit: {
|
|
1144
|
+
recipient: '0xRecipient...',
|
|
1145
|
+
share: parseEther('0.1'),
|
|
1146
|
+
},
|
|
1057
1147
|
}
|
|
1058
1148
|
```
|
|
1059
1149
|
|
|
1150
|
+
- `streamableFees` is required for `uniswapV4Split`.
|
|
1151
|
+
- Beneficiaries must sum to `1e18`, and the Airlock owner must be included with at least 5% shares.
|
|
1152
|
+
- The split recipient also receives any `TopUpDistributor` funds pulled during migration.
|
|
1153
|
+
|
|
1154
|
+
### TopUpDistributor Top-ups
|
|
1155
|
+
|
|
1156
|
+
The SDK exposes `sdk.topUpDistributor` and `sdk.getTopUpDistributor(address?)`
|
|
1157
|
+
for building, simulating, and submitting `topUp({ asset, numeraire, amount })`
|
|
1158
|
+
transactions where `getAddresses(chainId).topUpDistributor` is configured. The helper methods
|
|
1159
|
+
accept the same object shape for `buildTopUpTransaction({ asset, numeraire, amount })` and
|
|
1160
|
+
`simulateTopUp({ asset, numeraire, amount })`. ETH top-ups use `numeraire = ZERO_ADDRESS` and
|
|
1161
|
+
send `value = amount`; ERC20 top-ups send no native value and require the user to approve the
|
|
1162
|
+
`TopUpDistributor` before calling `topUp`.
|
|
1163
|
+
|
|
1164
|
+
```typescript
|
|
1165
|
+
import { ZERO_ADDRESS } from '@whetstone-research/doppler-sdk/evm';
|
|
1166
|
+
import { parseEther } from 'viem';
|
|
1167
|
+
|
|
1168
|
+
const topUps = sdk.topUpDistributor;
|
|
1169
|
+
|
|
1170
|
+
const tx = topUps.buildTopUpTransaction({
|
|
1171
|
+
asset: tokenAddress,
|
|
1172
|
+
numeraire: ZERO_ADDRESS,
|
|
1173
|
+
amount: parseEther('1'),
|
|
1174
|
+
});
|
|
1175
|
+
|
|
1176
|
+
const simulation = await topUps.simulateTopUp({
|
|
1177
|
+
asset: tokenAddress,
|
|
1178
|
+
numeraire: ZERO_ADDRESS,
|
|
1179
|
+
amount: parseEther('1'),
|
|
1180
|
+
});
|
|
1181
|
+
|
|
1182
|
+
await topUps.topUp({
|
|
1183
|
+
asset: tokenAddress,
|
|
1184
|
+
numeraire: ZERO_ADDRESS,
|
|
1185
|
+
amount: parseEther('1'),
|
|
1186
|
+
});
|
|
1187
|
+
```
|
|
1188
|
+
|
|
1189
|
+
Split migrators pull any TopUpDistributor balance for the asset/numeraire pair during migration
|
|
1190
|
+
and pay it to the configured split recipient.
|
|
1191
|
+
|
|
1060
1192
|
### Migrate via DopplerHookMigrator (Dynamic Auctions)
|
|
1061
1193
|
|
|
1062
1194
|
Use this mode when you want rehypothecation / custom hook behavior on the
|
|
@@ -1266,7 +1398,7 @@ const builder = new StaticAuctionBuilder(base.id)
|
|
|
1266
1398
|
})
|
|
1267
1399
|
.poolByTicks({ startTick: -92100, endTick: -69060, fee: 3000 })
|
|
1268
1400
|
.withGovernance({ type: 'default' })
|
|
1269
|
-
.withMigration({ type: '
|
|
1401
|
+
.withMigration({ type: 'uniswapV4', fee: 3000, tickSpacing: 60 })
|
|
1270
1402
|
.withUserAddress('0x...');
|
|
1271
1403
|
|
|
1272
1404
|
const staticParams = builder.build();
|
|
@@ -1321,7 +1453,7 @@ import {
|
|
|
1321
1453
|
import { parseEther, keccak256, encodePacked, encodeAbiParameters } from 'viem';
|
|
1322
1454
|
import { base } from 'viem/chains';
|
|
1323
1455
|
|
|
1324
|
-
const builder = new DynamicAuctionBuilder()
|
|
1456
|
+
const builder = new DynamicAuctionBuilder(base.id)
|
|
1325
1457
|
.tokenConfig({
|
|
1326
1458
|
name: 'My Token',
|
|
1327
1459
|
symbol: 'MTK',
|
|
@@ -1499,7 +1631,7 @@ Note: Dual-prefix mining takes significantly longer than single-prefix mining. C
|
|
|
1499
1631
|
- **Prefix format**: Omit the `0x` prefix (e.g., use `'dead'` not `'0x dead'`)
|
|
1500
1632
|
- **Case insensitive**: `'DEAD'`, `'dead'`, and `'DeAd'` are equivalent
|
|
1501
1633
|
- **Iteration limit**: Longer prefixes require more iterations. A 4-character hex prefix takes ~65,000 attempts on average.
|
|
1502
|
-
- **Token variants**: Set `tokenVariant: 'doppler404'` for DN404-style tokens
|
|
1634
|
+
- **Token variants**: Set `tokenVariant: 'standard-v2'` or `tokenVariant: 'dopplerERC20V1'` with `v2Implementation` for clone templates, or `tokenVariant: 'doppler404'` for DN404-style tokens
|
|
1503
1635
|
- **Salt preservation**: High-level helpers like `createStaticAuction` and `createDynamicAuction` recompute salts internally to ensure proper token ordering. To use a mined salt, call `encodeCreate*Params` and submit the transaction manually via `publicClient.writeContract`
|
|
1504
1636
|
- **Hook flags**: The miner automatically ensures V4 hooks have the correct permission flags for Doppler operations
|
|
1505
1637
|
|
|
@@ -1558,7 +1690,7 @@ pnpm build
|
|
|
1558
1690
|
pnpm test
|
|
1559
1691
|
|
|
1560
1692
|
# Run specific test suite
|
|
1561
|
-
pnpm test
|
|
1693
|
+
pnpm test:whitelisting
|
|
1562
1694
|
|
|
1563
1695
|
# Run tests in watch mode
|
|
1564
1696
|
pnpm test:watch
|
|
@@ -1571,22 +1703,31 @@ pnpm dev
|
|
|
1571
1703
|
|
|
1572
1704
|
The SDK includes comprehensive tests covering:
|
|
1573
1705
|
|
|
1574
|
-
- **Airlock Whitelisting**: Verifies that all modules are properly whitelisted on
|
|
1706
|
+
- **Airlock Whitelisting**: Verifies that all modules are properly whitelisted on Ethereum Mainnet, Monad Mainnet, Base Mainnet, and Base Sepolia
|
|
1575
1707
|
- **Multicurve Functionality**: Tests multicurve auction creation and quoting
|
|
1576
1708
|
- **Token Address Mining**: Tests for generating optimized token addresses
|
|
1577
1709
|
|
|
1578
|
-
See [`test/README.md`](./test/README.md) for detailed testing documentation.
|
|
1579
|
-
|
|
1580
1710
|
To run whitelisting tests:
|
|
1581
1711
|
|
|
1582
1712
|
```bash
|
|
1583
|
-
#
|
|
1584
|
-
pnpm test
|
|
1713
|
+
# Canonical whitelist audit
|
|
1714
|
+
pnpm test:whitelisting
|
|
1585
1715
|
|
|
1586
|
-
#
|
|
1587
|
-
ALCHEMY_API_KEY=your_key_here pnpm test
|
|
1716
|
+
# With Alchemy fallback (faster and more reliable)
|
|
1717
|
+
ALCHEMY_API_KEY=your_key_here pnpm test:whitelisting
|
|
1718
|
+
|
|
1719
|
+
# Limit to specific whitelist-audit chains when needed
|
|
1720
|
+
TEST_CHAINS=mainnet,base,base-sepolia,monad-mainnet pnpm test:whitelisting
|
|
1588
1721
|
```
|
|
1589
1722
|
|
|
1723
|
+
The whitelisting suite is scoped to the release-audit chains: Ethereum Mainnet, Monad Mainnet, Base Mainnet, and Base Sepolia.
|
|
1724
|
+
|
|
1725
|
+
Whitelisting test RPC priority is:
|
|
1726
|
+
|
|
1727
|
+
1. Chain-specific RPC URL env var (`ETH_MAINNET_RPC_URL`, `BASE_RPC_URL`, `BASE_SEPOLIA_RPC_URL`, `MONAD_MAINNET_RPC_URL`)
|
|
1728
|
+
2. `ALCHEMY_API_KEY` fallback for supported Alchemy networks, including Monad Mainnet
|
|
1729
|
+
3. Public/default RPC URL
|
|
1730
|
+
|
|
1590
1731
|
To run fork tests (Anvil):
|
|
1591
1732
|
|
|
1592
1733
|
```bash
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkO6FR7TXY_cjs = require('./chunk-O6FR7TXY.cjs');
|
|
4
4
|
var kit = require('@solana/kit');
|
|
5
5
|
|
|
6
6
|
var addressCodec = kit.getAddressCodec();
|
|
@@ -52,7 +52,7 @@ var ammConfigDataCodec = kit.getStructCodec([
|
|
|
52
52
|
["sentinelAllowlistLen", u8Codec],
|
|
53
53
|
[
|
|
54
54
|
"sentinelAllowlist",
|
|
55
|
-
kit.getArrayCodec(addressCodec, { size:
|
|
55
|
+
kit.getArrayCodec(addressCodec, { size: chunkO6FR7TXY_cjs.MAX_SENTINEL_ALLOWLIST })
|
|
56
56
|
],
|
|
57
57
|
["maxSwapFeeBps", u16Codec],
|
|
58
58
|
["maxFeeSplitBps", u16Codec],
|
|
@@ -120,22 +120,22 @@ var oracleStateDataCodec = kit.getStructCodec([
|
|
|
120
120
|
["observationIndex", u16Codec],
|
|
121
121
|
[
|
|
122
122
|
"observations",
|
|
123
|
-
kit.getArrayCodec(observationCodec, { size:
|
|
123
|
+
kit.getArrayCodec(observationCodec, { size: chunkO6FR7TXY_cjs.MAX_ORACLE_OBSERVATIONS })
|
|
124
124
|
],
|
|
125
125
|
["version", u8Codec],
|
|
126
126
|
["reserved", reservedBytesCodec]
|
|
127
127
|
]);
|
|
128
128
|
var ammConfigDecoder = kit.getHiddenPrefixDecoder(ammConfigDataCodec, [
|
|
129
|
-
kit.getConstantDecoder(
|
|
129
|
+
kit.getConstantDecoder(chunkO6FR7TXY_cjs.ACCOUNT_DISCRIMINATORS.AmmConfig)
|
|
130
130
|
]);
|
|
131
131
|
var poolDecoder = kit.getHiddenPrefixDecoder(poolDataCodec, [
|
|
132
|
-
kit.getConstantDecoder(
|
|
132
|
+
kit.getConstantDecoder(chunkO6FR7TXY_cjs.ACCOUNT_DISCRIMINATORS.Pool)
|
|
133
133
|
]);
|
|
134
134
|
var positionDecoder = kit.getHiddenPrefixDecoder(positionDataCodec, [
|
|
135
|
-
kit.getConstantDecoder(
|
|
135
|
+
kit.getConstantDecoder(chunkO6FR7TXY_cjs.ACCOUNT_DISCRIMINATORS.Position)
|
|
136
136
|
]);
|
|
137
137
|
var oracleStateDecoder = kit.getHiddenPrefixDecoder(oracleStateDataCodec, [
|
|
138
|
-
kit.getConstantDecoder(
|
|
138
|
+
kit.getConstantDecoder(chunkO6FR7TXY_cjs.ACCOUNT_DISCRIMINATORS.OracleState)
|
|
139
139
|
]);
|
|
140
140
|
function decodeAmmConfig(data) {
|
|
141
141
|
return ammConfigDecoder.decode(data);
|
|
@@ -299,12 +299,12 @@ function encodeQuoteToNumeraireArgs(args) {
|
|
|
299
299
|
function q64ToNumber(q64) {
|
|
300
300
|
const intPart = q64 >> 64n;
|
|
301
301
|
const fracPart = q64 & (1n << 64n) - 1n;
|
|
302
|
-
return Number(intPart) + Number(fracPart) / Number(
|
|
302
|
+
return Number(intPart) + Number(fracPart) / Number(chunkO6FR7TXY_cjs.Q64_ONE);
|
|
303
303
|
}
|
|
304
304
|
function numberToQ64(n) {
|
|
305
305
|
const intPart = Math.floor(n);
|
|
306
306
|
const fracPart = n - intPart;
|
|
307
|
-
return (BigInt(intPart) << 64n) + BigInt(Math.round(fracPart * Number(
|
|
307
|
+
return (BigInt(intPart) << 64n) + BigInt(Math.round(fracPart * Number(chunkO6FR7TXY_cjs.Q64_ONE)));
|
|
308
308
|
}
|
|
309
309
|
function q64Mul(a, b) {
|
|
310
310
|
return a * b >> 64n;
|
|
@@ -360,8 +360,8 @@ function getSwapQuote(pool, amountIn, direction) {
|
|
|
360
360
|
if (reserveIn === 0n || reserveOut === 0n) {
|
|
361
361
|
throw new Error("Pool has zero liquidity");
|
|
362
362
|
}
|
|
363
|
-
const feeTotal = amountIn * BigInt(pool.swapFeeBps) /
|
|
364
|
-
const feeDist = feeTotal * BigInt(pool.feeSplitBps) /
|
|
363
|
+
const feeTotal = amountIn * BigInt(pool.swapFeeBps) / chunkO6FR7TXY_cjs.BPS_DENOM;
|
|
364
|
+
const feeDist = feeTotal * BigInt(pool.feeSplitBps) / chunkO6FR7TXY_cjs.BPS_DENOM;
|
|
365
365
|
const feeComp = feeTotal - feeDist;
|
|
366
366
|
const amountInEff = amountIn - feeTotal;
|
|
367
367
|
const amountOut = amountInEff * reserveOut / (reserveIn + amountInEff);
|
|
@@ -387,8 +387,8 @@ function getSwapQuoteExactOut(pool, amountOut, direction) {
|
|
|
387
387
|
}
|
|
388
388
|
const amountInEff = ceilDiv(amountOut * reserveIn, reserveOut - amountOut);
|
|
389
389
|
const amountIn = ceilDiv(
|
|
390
|
-
amountInEff *
|
|
391
|
-
|
|
390
|
+
amountInEff * chunkO6FR7TXY_cjs.BPS_DENOM,
|
|
391
|
+
chunkO6FR7TXY_cjs.BPS_DENOM - BigInt(pool.swapFeeBps)
|
|
392
392
|
);
|
|
393
393
|
const feeTotal = amountIn - amountInEff;
|
|
394
394
|
return { amountIn, feeTotal };
|
|
@@ -488,7 +488,7 @@ function calculateTwapNumber(cumulativeStart, cumulativeEnd, timestampStart, tim
|
|
|
488
488
|
);
|
|
489
489
|
return q64ToNumber(twapQ64);
|
|
490
490
|
}
|
|
491
|
-
function createCollectFeesInstruction(accounts, args, programId =
|
|
491
|
+
function createCollectFeesInstruction(accounts, args, programId = chunkO6FR7TXY_cjs.CPMM_PROGRAM_ID) {
|
|
492
492
|
const {
|
|
493
493
|
pool,
|
|
494
494
|
position,
|
|
@@ -500,7 +500,7 @@ function createCollectFeesInstruction(accounts, args, programId = chunkDPKVNI6Q_
|
|
|
500
500
|
token1Mint,
|
|
501
501
|
user0,
|
|
502
502
|
user1,
|
|
503
|
-
tokenProgram =
|
|
503
|
+
tokenProgram = chunkO6FR7TXY_cjs.TOKEN_PROGRAM_ADDRESS
|
|
504
504
|
} = accounts;
|
|
505
505
|
const keys = [
|
|
506
506
|
{ address: pool, role: kit.AccountRole.WRITABLE },
|
|
@@ -516,7 +516,7 @@ function createCollectFeesInstruction(accounts, args, programId = chunkDPKVNI6Q_
|
|
|
516
516
|
{ address: tokenProgram, role: kit.AccountRole.READONLY }
|
|
517
517
|
];
|
|
518
518
|
const data = encodeInstructionData(
|
|
519
|
-
|
|
519
|
+
chunkO6FR7TXY_cjs.INSTRUCTION_DISCRIMINATORS.collectFees,
|
|
520
520
|
collectFeesArgsCodec,
|
|
521
521
|
args
|
|
522
522
|
);
|
|
@@ -555,11 +555,11 @@ async function fetchPool(rpc, address, config) {
|
|
|
555
555
|
return decodePool(base64ToBytes(response.value.data[0]));
|
|
556
556
|
}
|
|
557
557
|
async function fetchAllPools(rpc, config) {
|
|
558
|
-
const programId = config?.programId ??
|
|
558
|
+
const programId = config?.programId ?? chunkO6FR7TXY_cjs.CPMM_PROGRAM_ID;
|
|
559
559
|
const discriminatorFilter = {
|
|
560
560
|
memcmp: {
|
|
561
561
|
offset: 0n,
|
|
562
|
-
bytes: bytesToBase64(
|
|
562
|
+
bytes: bytesToBase64(chunkO6FR7TXY_cjs.ACCOUNT_DISCRIMINATORS.Pool),
|
|
563
563
|
encoding: "base64"
|
|
564
564
|
}
|
|
565
565
|
};
|
|
@@ -584,8 +584,8 @@ async function fetchAllPools(rpc, config) {
|
|
|
584
584
|
return pools;
|
|
585
585
|
}
|
|
586
586
|
async function getPoolByMints(rpc, mint0, mint1, config) {
|
|
587
|
-
const programId = config?.programId ??
|
|
588
|
-
const [poolAddress] = await
|
|
587
|
+
const programId = config?.programId ?? chunkO6FR7TXY_cjs.CPMM_PROGRAM_ID;
|
|
588
|
+
const [poolAddress] = await chunkO6FR7TXY_cjs.getPoolAddress(mint0, mint1, programId);
|
|
589
589
|
const pool = await fetchPool(rpc, poolAddress, config);
|
|
590
590
|
if (!pool) {
|
|
591
591
|
return null;
|
|
@@ -612,9 +612,9 @@ async function poolExists(rpc, mint0, mint1, config) {
|
|
|
612
612
|
const result = await getPoolByMints(rpc, mint0, mint1, config);
|
|
613
613
|
return result !== null;
|
|
614
614
|
}
|
|
615
|
-
async function getPoolAddressFromMints(mint0, mint1, programId =
|
|
616
|
-
const [token0, token1] =
|
|
617
|
-
const [poolAddress] = await
|
|
615
|
+
async function getPoolAddressFromMints(mint0, mint1, programId = chunkO6FR7TXY_cjs.CPMM_PROGRAM_ID) {
|
|
616
|
+
const [token0, token1] = chunkO6FR7TXY_cjs.sortMints(mint0, mint1);
|
|
617
|
+
const [poolAddress] = await chunkO6FR7TXY_cjs.getPoolAddress(mint0, mint1, programId);
|
|
618
618
|
return {
|
|
619
619
|
poolAddress,
|
|
620
620
|
token0,
|
|
@@ -662,14 +662,14 @@ async function fetchPosition(rpc, address, config) {
|
|
|
662
662
|
return decodePosition(base64ToBytes2(response.value.data[0]));
|
|
663
663
|
}
|
|
664
664
|
async function fetchUserPositions(rpc, owner, pool, config) {
|
|
665
|
-
const programId = config?.programId ??
|
|
665
|
+
const programId = config?.programId ?? chunkO6FR7TXY_cjs.CPMM_PROGRAM_ID;
|
|
666
666
|
const filters = [
|
|
667
667
|
// Discriminator filter (first 8 bytes)
|
|
668
668
|
{
|
|
669
669
|
memcmp: {
|
|
670
670
|
offset: 0n,
|
|
671
671
|
bytes: bytesToBase642(
|
|
672
|
-
|
|
672
|
+
chunkO6FR7TXY_cjs.ACCOUNT_DISCRIMINATORS.Position
|
|
673
673
|
),
|
|
674
674
|
encoding: "base64"
|
|
675
675
|
}
|
|
@@ -713,14 +713,14 @@ async function fetchUserPositions(rpc, owner, pool, config) {
|
|
|
713
713
|
return positions;
|
|
714
714
|
}
|
|
715
715
|
async function fetchPoolPositions(rpc, pool, config) {
|
|
716
|
-
const programId = config?.programId ??
|
|
716
|
+
const programId = config?.programId ?? chunkO6FR7TXY_cjs.CPMM_PROGRAM_ID;
|
|
717
717
|
const filters = [
|
|
718
718
|
// Discriminator filter
|
|
719
719
|
{
|
|
720
720
|
memcmp: {
|
|
721
721
|
offset: 0n,
|
|
722
722
|
bytes: bytesToBase642(
|
|
723
|
-
|
|
723
|
+
chunkO6FR7TXY_cjs.ACCOUNT_DISCRIMINATORS.Position
|
|
724
724
|
),
|
|
725
725
|
encoding: "base64"
|
|
726
726
|
}
|
|
@@ -781,8 +781,8 @@ function getPositionValue(pool, position) {
|
|
|
781
781
|
};
|
|
782
782
|
}
|
|
783
783
|
async function fetchPositionByParams(rpc, pool, owner, positionId, config) {
|
|
784
|
-
const programId = config?.programId ??
|
|
785
|
-
const [address] = await
|
|
784
|
+
const programId = config?.programId ?? chunkO6FR7TXY_cjs.CPMM_PROGRAM_ID;
|
|
785
|
+
const [address] = await chunkO6FR7TXY_cjs.getPositionAddress(
|
|
786
786
|
pool,
|
|
787
787
|
owner,
|
|
788
788
|
positionId,
|
|
@@ -797,8 +797,8 @@ async function fetchPositionByParams(rpc, pool, owner, positionId, config) {
|
|
|
797
797
|
account: position
|
|
798
798
|
};
|
|
799
799
|
}
|
|
800
|
-
async function getPositionAddressFromParams(pool, owner, positionId, programId =
|
|
801
|
-
const [address] = await
|
|
800
|
+
async function getPositionAddressFromParams(pool, owner, positionId, programId = chunkO6FR7TXY_cjs.CPMM_PROGRAM_ID) {
|
|
801
|
+
const [address] = await chunkO6FR7TXY_cjs.getPositionAddress(
|
|
802
802
|
pool,
|
|
803
803
|
owner,
|
|
804
804
|
positionId,
|
|
@@ -849,8 +849,8 @@ async function fetchOracle(rpc, address, config) {
|
|
|
849
849
|
return decodeOracleState(base64ToBytes3(response.value.data[0]));
|
|
850
850
|
}
|
|
851
851
|
async function getOracleForPool(rpc, pool, config) {
|
|
852
|
-
const programId = config?.programId ??
|
|
853
|
-
const [oracleAddress] = await
|
|
852
|
+
const programId = config?.programId ?? chunkO6FR7TXY_cjs.CPMM_PROGRAM_ID;
|
|
853
|
+
const [oracleAddress] = await chunkO6FR7TXY_cjs.getOracleAddress(pool, programId);
|
|
854
854
|
const oracle = await fetchOracle(rpc, oracleAddress, config);
|
|
855
855
|
if (!oracle) {
|
|
856
856
|
return null;
|
|
@@ -860,8 +860,8 @@ async function getOracleForPool(rpc, pool, config) {
|
|
|
860
860
|
account: oracle
|
|
861
861
|
};
|
|
862
862
|
}
|
|
863
|
-
async function getOracleAddressFromPool(pool, programId =
|
|
864
|
-
const [address] = await
|
|
863
|
+
async function getOracleAddressFromPool(pool, programId = chunkO6FR7TXY_cjs.CPMM_PROGRAM_ID) {
|
|
864
|
+
const [address] = await chunkO6FR7TXY_cjs.getOracleAddress(pool, programId);
|
|
865
865
|
return address;
|
|
866
866
|
}
|
|
867
867
|
function consultTwap(oracle, windowSeconds, currentTimestamp) {
|
|
@@ -984,10 +984,10 @@ function getOracleBufferStats(oracle) {
|
|
|
984
984
|
};
|
|
985
985
|
}
|
|
986
986
|
async function fetchOraclesBatch(rpc, pools, config) {
|
|
987
|
-
const programId = config?.programId ??
|
|
987
|
+
const programId = config?.programId ?? chunkO6FR7TXY_cjs.CPMM_PROGRAM_ID;
|
|
988
988
|
const oracles = /* @__PURE__ */ new Map();
|
|
989
989
|
const oracleAddresses = await Promise.all(
|
|
990
|
-
pools.map((pool) =>
|
|
990
|
+
pools.map((pool) => chunkO6FR7TXY_cjs.getOracleAddress(pool, programId))
|
|
991
991
|
);
|
|
992
992
|
const results = await Promise.all(
|
|
993
993
|
oracleAddresses.map(([addr]) => fetchOracle(rpc, addr, config))
|
|
@@ -1107,5 +1107,5 @@ exports.sortPoolsByReserves = sortPoolsByReserves;
|
|
|
1107
1107
|
exports.sortPositionsByShares = sortPositionsByShares;
|
|
1108
1108
|
exports.swapExactInArgsCodec = swapExactInArgsCodec;
|
|
1109
1109
|
exports.transferAdminArgsCodec = transferAdminArgsCodec;
|
|
1110
|
-
//# sourceMappingURL=chunk-
|
|
1111
|
-
//# sourceMappingURL=chunk-
|
|
1110
|
+
//# sourceMappingURL=chunk-I5JME35L.cjs.map
|
|
1111
|
+
//# sourceMappingURL=chunk-I5JME35L.cjs.map
|