@picon-finance/dlmm-sdk 1.16.0 → 1.16.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/entities/pool.d.ts.map +1 -1
- package/dist/entities/pool.js +37 -62
- package/dist/picon_dlmm.json +1 -1
- package/dist/quote/wasm-node/picon_dlmm_quote_bg.wasm +0 -0
- package/dist/quote/wasm-web/picon_dlmm_quote_bg.wasm +0 -0
- package/dist/utils/price.d.ts +1 -0
- package/dist/utils/price.d.ts.map +1 -1
- package/dist/utils/price.js +64 -2
- package/package.json +6 -4
- package/src/entities/pool.ts +75 -86
- package/src/entities/position.ts +2 -2
- package/src/picon_dlmm.json +1 -1
- package/src/quote/wasm-node/picon_dlmm_quote_bg.wasm +0 -0
- package/src/quote/wasm-web/picon_dlmm_quote_bg.wasm +0 -0
- package/src/utils/price.ts +71 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../../src/entities/pool.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EAEf,KAAK,OAAO,EACZ,KAAK,OAAO,EACZ,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACzB,MAAM,aAAa,CAAC;AAMrB,OAAO,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAC/B,OAAO,EAIL,KAAK,QAAQ,EACb,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,WAAW,EACjB,MAAM,UAAU,CAAC;AAUlB,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,gBAAgB,IAAI,oBAAoB,EAC9C,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,QAAQ,EAKT,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C,qBAAa,IAAI;;IAQf,OAAO,eAYN;IAED,IAAW,GAAG,+5nBAAwB;IAEtC,IAAW,cAAc,YAAmC;IAC5D,IAAW,OAAO,oBAAoC;IACtD,IAAW,IAAI,mBAAiC;IAChD,IAAW,WAAW,WAAoC;IAE1D,IAAW,UAAU,YAAmC;IACxD,IAAW,UAAU,YAAmC;IAExD,IAAW,cAAc,WAAwC;IACjE,IAAW,cAAc,WAAwC;IAEjE,IAAW,WAAW,YAAoC;IAC1D,IAAW,WAAW,YAAoC;IAE1D,IAAW,aAAa,YAAyC;IACjE,IAAW,aAAa,YAAyC;IAEpD,eAAe,IAAI,OAAO,CAAC;QAAE,YAAY,CAAC,EAAE,WAAW,CAAC;QAAC,YAAY,CAAC,EAAE,WAAW,CAAA;KAAE,CAAC,CAMlG;IAEY,WAAW,CAAC,GAAG,GAAE,MAA8C,GAAG,OAAO,CAAC,QAAQ,CAAC,CAE/F;IAEY,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtD,OAAO,CAAC,MAAM,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAQpD,WAAW,CACtB,OAAO,EAAE,OAAO,EAChB,MAAM,CAAC,EAAE,mBAAmB,GAC3B,OAAO,CAAC,QAAQ,CAAC,CAEnB;IAEY,yBAAyB,CACpC,YAAY,EAAE,OAAO,EACrB,MAAM,CAAC,EAAE,mBAAmB,GAC3B,OAAO,CAAC,QAAQ,CAAC,CAMnB;IAEY,8BAA8B,CACzC,aAAa,EAAE,OAAO,EAAE,EACxB,MAAM,CAAC,EAAE,mBAAmB,GAC3B,OAAO,CAAC,QAAQ,EAAE,CAAC,CAMrB;IAEY,YAAY,CACvB,KAAK,EAAE,iBAAiB,EACxB,YAAY,EAAE,iBAAiB,EAC/B,EAAE,UAAU,EAAE,UAAU,EAAE,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GACrE,OAAO,CAAC,WAAW,EAAE,CAAC,CAMxB;IAEY,aAAa,CACxB,KAAK,EAAE,iBAAiB,EACxB,YAAY,EAAE,OAAO,GACpB,OAAO,CAAC,WAAW,CAAC,CAKtB;IAEY,WAAW,CACtB,IAAI,EAAE,iBAAiB,EACvB,EACE,IAAI,EACJ,QAAQ,EACR,oBAAoB,GACrB,EAAE;QACD,IAAI,EAAE,OAAO,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,oBAAoB,EAAE,MAAM,CAAC;KAC9B,GACA,OAAO,CAAC;QAAE,WAAW,EAAE,kBAAkB,CAAC;QAAC,YAAY,EAAE,WAAW,EAAE,CAAA;KAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../../src/entities/pool.ts"],"names":[],"mappings":"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"}
|
package/dist/entities/pool.js
CHANGED
|
@@ -72,41 +72,8 @@ export class Pool {
|
|
|
72
72
|
}
|
|
73
73
|
async swapExactIn(user, { xToY, amountIn, slippageToleranceBps, }) {
|
|
74
74
|
const { quoteOutput, binArrayAddresses } = await this.#quoteExactIn({ xToY, amountIn, slippageToleranceBps });
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
tokenMintX: this.tokenMintX,
|
|
78
|
-
tokenMintY: this.tokenMintY,
|
|
79
|
-
tokenProgramX: this.tokenProgramX,
|
|
80
|
-
tokenProgramY: this.tokenProgramY,
|
|
81
|
-
amountX: xToY ? amountIn : undefined,
|
|
82
|
-
amountY: xToY ? undefined : amountIn,
|
|
83
|
-
});
|
|
84
|
-
// Each mint's hook accounts are resolved against whichever role it plays in this swap —
|
|
85
|
-
// input (user -> vault, owner = user) or output (vault -> user, owner = pool PDA).
|
|
86
|
-
const xTransferAccounts = xToY
|
|
87
|
-
? { source: tokenUserAccountX, mint: this.tokenMintX, destination: this.tokenVaultX, owner: user.address }
|
|
88
|
-
: { source: this.tokenVaultX, mint: this.tokenMintX, destination: tokenUserAccountX, owner: this.address };
|
|
89
|
-
const yTransferAccounts = xToY
|
|
90
|
-
? { source: this.tokenVaultY, mint: this.tokenMintY, destination: tokenUserAccountY, owner: this.address }
|
|
91
|
-
: { source: tokenUserAccountY, mint: this.tokenMintY, destination: this.tokenVaultY, owner: user.address };
|
|
92
|
-
const [transferHookXAccounts, transferHookYAccounts] = await Promise.all([
|
|
93
|
-
this.resolveTransferHookAccountsX(xTransferAccounts),
|
|
94
|
-
this.resolveTransferHookAccountsY(yTransferAccounts),
|
|
95
|
-
]);
|
|
96
|
-
const groups = [
|
|
97
|
-
{ kind: generated.AccountKind.BinArray, count: binArrayAddresses.length },
|
|
98
|
-
];
|
|
99
|
-
const remainingAccounts = binArrayAddresses.map(address => ({ address, role: AccountRole.WRITABLE }));
|
|
100
|
-
if (transferHookXAccounts.length > 0) {
|
|
101
|
-
groups.push({ kind: generated.AccountKind.TransferHookX, count: transferHookXAccounts.length });
|
|
102
|
-
remainingAccounts.push(...transferHookXAccounts.map(toRemainingAccountMeta));
|
|
103
|
-
}
|
|
104
|
-
if (transferHookYAccounts.length > 0) {
|
|
105
|
-
groups.push({ kind: generated.AccountKind.TransferHookY, count: transferHookYAccounts.length });
|
|
106
|
-
remainingAccounts.push(...transferHookYAccounts.map(toRemainingAccountMeta));
|
|
107
|
-
}
|
|
108
|
-
const remainingAccountsScheme = { groups };
|
|
109
|
-
const swapIx = generated.getSwapExactInInstruction({
|
|
75
|
+
// The input leg is fixed, so it funds the wSOL leg (if any) directly.
|
|
76
|
+
const instructions = await this.#assembleSwapInstructions(user, xToY, amountIn, binArrayAddresses, ({ tokenUserAccountX, tokenUserAccountY, remainingAccountsScheme }) => generated.getSwapExactInInstruction({
|
|
110
77
|
user,
|
|
111
78
|
pool: this.address,
|
|
112
79
|
tokenMintX: this.tokenMintX,
|
|
@@ -121,26 +88,47 @@ export class Pool {
|
|
|
121
88
|
minAmountOut: quoteOutput.minAmountOut,
|
|
122
89
|
xToY,
|
|
123
90
|
remainingAccountsScheme,
|
|
124
|
-
}, { programAddress: this.#programAddress });
|
|
125
|
-
const swapIxWithBinArrays = { ...swapIx, accounts: [...swapIx.accounts, ...remainingAccounts] };
|
|
126
|
-
const instructions = [...preInstructions, swapIxWithBinArrays, ...postInstructions];
|
|
91
|
+
}, { programAddress: this.#programAddress }));
|
|
127
92
|
return { quoteOutput, instructions };
|
|
128
93
|
}
|
|
129
94
|
async swapExactOut(user, { xToY, amountOut, slippageToleranceBps, }) {
|
|
130
95
|
const { quoteOutput, binArrayAddresses } = await this.#quoteExactOut({ xToY, amountOut, slippageToleranceBps });
|
|
96
|
+
// The real input isn't known until the swap executes, so the wSOL leg (if any) is funded with
|
|
97
|
+
// the worst-case maxAmountIn — any excess is unwrapped back to the owner in postInstructions.
|
|
98
|
+
const instructions = await this.#assembleSwapInstructions(user, xToY, quoteOutput.maxAmountIn, binArrayAddresses, ({ tokenUserAccountX, tokenUserAccountY, remainingAccountsScheme }) => generated.getSwapExactOutInstruction({
|
|
99
|
+
user,
|
|
100
|
+
pool: this.address,
|
|
101
|
+
tokenMintX: this.tokenMintX,
|
|
102
|
+
tokenMintY: this.tokenMintY,
|
|
103
|
+
tokenUserAccountX,
|
|
104
|
+
tokenUserAccountY,
|
|
105
|
+
tokenVaultX: this.tokenVaultX,
|
|
106
|
+
tokenVaultY: this.tokenVaultY,
|
|
107
|
+
tokenProgramX: this.tokenProgramX,
|
|
108
|
+
tokenProgramY: this.tokenProgramY,
|
|
109
|
+
amountOut,
|
|
110
|
+
maxAmountIn: quoteOutput.maxAmountIn,
|
|
111
|
+
xToY,
|
|
112
|
+
remainingAccountsScheme,
|
|
113
|
+
}, { programAddress: this.#programAddress }));
|
|
114
|
+
return { quoteOutput, instructions };
|
|
115
|
+
}
|
|
116
|
+
// Shared tail of both swap directions: sets up the user's X/Y ATAs (funding the wSOL leg, if
|
|
117
|
+
// any, with `fundingAmount`), resolves each mint's transfer-hook accounts against the role it
|
|
118
|
+
// plays in this swap — input (user -> vault, owner = user) or output (vault -> user, owner =
|
|
119
|
+
// pool PDA) — builds the remaining-accounts scheme, and splices the bin arrays + resolved hook
|
|
120
|
+
// accounts onto the instruction `buildSwapIx` produces. Only the funding amount and the
|
|
121
|
+
// instruction itself differ between exact-in and exact-out.
|
|
122
|
+
async #assembleSwapInstructions(user, xToY, fundingAmount, binArrayAddresses, buildSwapIx) {
|
|
131
123
|
const { ataX: tokenUserAccountX, ataY: tokenUserAccountY, preInstructions, postInstructions, } = await processAssociatedTokenAccountPair({
|
|
132
124
|
owner: user,
|
|
133
125
|
tokenMintX: this.tokenMintX,
|
|
134
126
|
tokenMintY: this.tokenMintY,
|
|
135
127
|
tokenProgramX: this.tokenProgramX,
|
|
136
128
|
tokenProgramY: this.tokenProgramY,
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
amountX: xToY ? quoteOutput.maxAmountIn : undefined,
|
|
140
|
-
amountY: xToY ? undefined : quoteOutput.maxAmountIn,
|
|
129
|
+
amountX: xToY ? fundingAmount : undefined,
|
|
130
|
+
amountY: xToY ? undefined : fundingAmount,
|
|
141
131
|
});
|
|
142
|
-
// Each mint's hook accounts are resolved against whichever role it plays in this swap —
|
|
143
|
-
// input (user -> vault, owner = user) or output (vault -> user, owner = pool PDA).
|
|
144
132
|
const xTransferAccounts = xToY
|
|
145
133
|
? { source: tokenUserAccountX, mint: this.tokenMintX, destination: this.tokenVaultX, owner: user.address }
|
|
146
134
|
: { source: this.tokenVaultX, mint: this.tokenMintX, destination: tokenUserAccountX, owner: this.address };
|
|
@@ -163,26 +151,13 @@ export class Pool {
|
|
|
163
151
|
groups.push({ kind: generated.AccountKind.TransferHookY, count: transferHookYAccounts.length });
|
|
164
152
|
remainingAccounts.push(...transferHookYAccounts.map(toRemainingAccountMeta));
|
|
165
153
|
}
|
|
166
|
-
const
|
|
167
|
-
const swapIx = generated.getSwapExactOutInstruction({
|
|
168
|
-
user,
|
|
169
|
-
pool: this.address,
|
|
170
|
-
tokenMintX: this.tokenMintX,
|
|
171
|
-
tokenMintY: this.tokenMintY,
|
|
154
|
+
const swapIx = buildSwapIx({
|
|
172
155
|
tokenUserAccountX,
|
|
173
156
|
tokenUserAccountY,
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
amountOut,
|
|
179
|
-
maxAmountIn: quoteOutput.maxAmountIn,
|
|
180
|
-
xToY,
|
|
181
|
-
remainingAccountsScheme,
|
|
182
|
-
}, { programAddress: this.#programAddress });
|
|
183
|
-
const swapIxWithBinArrays = { ...swapIx, accounts: [...swapIx.accounts, ...remainingAccounts] };
|
|
184
|
-
const instructions = [...preInstructions, swapIxWithBinArrays, ...postInstructions];
|
|
185
|
-
return { quoteOutput, instructions };
|
|
157
|
+
remainingAccountsScheme: { groups },
|
|
158
|
+
});
|
|
159
|
+
const swapIxWithBinArrays = { ...swapIx, accounts: [...(swapIx.accounts ?? []), ...remainingAccounts] };
|
|
160
|
+
return [...preInstructions, swapIxWithBinArrays, ...postInstructions];
|
|
186
161
|
}
|
|
187
162
|
// Public so Position (which only holds a reference to this Pool, not its private mint data)
|
|
188
163
|
// can resolve hook accounts for its own deposit/withdraw/claimFee instructions without ever
|
package/dist/picon_dlmm.json
CHANGED
|
Binary file
|
|
Binary file
|
package/dist/utils/price.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export declare function getBaseBinPrice(binStep: number): bigint;
|
|
2
2
|
export declare function getBinPrice(baseBinPrice: bigint, binId: number): bigint | undefined;
|
|
3
3
|
export declare function getBinPriceFromStep(binStep: number, binId: number): bigint | undefined;
|
|
4
|
+
export declare function getBinIdFromPrice(binStep: number, price: bigint): number | undefined;
|
|
4
5
|
//# sourceMappingURL=price.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"price.d.ts","sourceRoot":"","sources":["../../src/utils/price.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"price.d.ts","sourceRoot":"","sources":["../../src/utils/price.ts"],"names":[],"mappings":"AAIA,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGvD;AAED,wBAAgB,WAAW,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAmBnF;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEtF;AA8BD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAsCpF"}
|
package/dist/utils/price.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { MAX_BASIS_POINTS } from "./constants";
|
|
2
|
+
import { isUndefined } from "./type_guards";
|
|
2
3
|
import { expBySquaring, MAX, MAX_EXPONENTIAL, ONE, SCALE_OFFSET } from "./u64x64";
|
|
3
4
|
export function getBaseBinPrice(binStep) {
|
|
4
5
|
const priceStep = (BigInt(binStep) << SCALE_OFFSET) / BigInt(MAX_BASIS_POINTS);
|
|
@@ -16,8 +17,8 @@ export function getBinPrice(baseBinPrice, binId) {
|
|
|
16
17
|
const absBinId = Math.abs(binId);
|
|
17
18
|
if (absBinId >= MAX_EXPONENTIAL)
|
|
18
19
|
return;
|
|
19
|
-
const
|
|
20
|
-
const price = expBySquaring(
|
|
20
|
+
const invertedBaseBinPrice = MAX / baseBinPrice;
|
|
21
|
+
const price = expBySquaring(invertedBaseBinPrice, absBinId);
|
|
21
22
|
if (price === 0n)
|
|
22
23
|
return;
|
|
23
24
|
return invert ? MAX / price : price;
|
|
@@ -25,3 +26,64 @@ export function getBinPrice(baseBinPrice, binId) {
|
|
|
25
26
|
export function getBinPriceFromStep(binStep, binId) {
|
|
26
27
|
return getBinPrice(getBaseBinPrice(binStep), binId);
|
|
27
28
|
}
|
|
29
|
+
const MAX_BIN_ID_BY_BIN_STEP = new Map([
|
|
30
|
+
[1, 443636],
|
|
31
|
+
[2, 221829],
|
|
32
|
+
[4, 110925],
|
|
33
|
+
[5, 88745],
|
|
34
|
+
[8, 55473],
|
|
35
|
+
[10, 44383],
|
|
36
|
+
[15, 29596],
|
|
37
|
+
[16, 27748],
|
|
38
|
+
[20, 22202],
|
|
39
|
+
[25, 17759],
|
|
40
|
+
[30, 14809],
|
|
41
|
+
[50, 8893],
|
|
42
|
+
[75, 5937],
|
|
43
|
+
[80, 5567],
|
|
44
|
+
[100, 4456],
|
|
45
|
+
[125, 3571],
|
|
46
|
+
[150, 2979],
|
|
47
|
+
[160, 2794],
|
|
48
|
+
[200, 2239],
|
|
49
|
+
[250, 1796],
|
|
50
|
+
[300, 1500],
|
|
51
|
+
[400, 1130],
|
|
52
|
+
]);
|
|
53
|
+
const MIN_PRICE = 1n;
|
|
54
|
+
const MAX_PRICE = MAX;
|
|
55
|
+
export function getBinIdFromPrice(binStep, price) {
|
|
56
|
+
if (price <= 0n)
|
|
57
|
+
return;
|
|
58
|
+
const maxBinId = MAX_BIN_ID_BY_BIN_STEP.get(binStep);
|
|
59
|
+
if (isUndefined(maxBinId)) {
|
|
60
|
+
throw new Error(`getBinIdFromPrice: unsupported binStep (${binStep})`);
|
|
61
|
+
}
|
|
62
|
+
if (price <= MIN_PRICE)
|
|
63
|
+
return -maxBinId;
|
|
64
|
+
if (price >= MAX_PRICE)
|
|
65
|
+
return maxBinId;
|
|
66
|
+
const baseBinPrice = getBaseBinPrice(binStep);
|
|
67
|
+
let lowerBinId = -maxBinId;
|
|
68
|
+
let upperBinId = maxBinId;
|
|
69
|
+
let currentPrice = MAX_PRICE;
|
|
70
|
+
let previousPrice;
|
|
71
|
+
while (lowerBinId < upperBinId) {
|
|
72
|
+
const middleBinId = lowerBinId + Math.floor((upperBinId - lowerBinId) / 2);
|
|
73
|
+
const middlePrice = getBinPrice(baseBinPrice, middleBinId);
|
|
74
|
+
if (middlePrice < price) {
|
|
75
|
+
lowerBinId = middleBinId + 1;
|
|
76
|
+
previousPrice = middlePrice;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
upperBinId = middleBinId;
|
|
80
|
+
currentPrice = middlePrice;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (isUndefined(previousPrice))
|
|
84
|
+
return lowerBinId;
|
|
85
|
+
// previousPrice < price <= currentPrice always holds here, so both distances are non-negative.
|
|
86
|
+
const previousPriceDistance = price - previousPrice;
|
|
87
|
+
const currentPriceDistance = currentPrice - price;
|
|
88
|
+
return previousPriceDistance < currentPriceDistance ? lowerBinId - 1 : lowerBinId;
|
|
89
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@picon-finance/dlmm-sdk",
|
|
3
|
-
"version": "1.16.
|
|
3
|
+
"version": "1.16.2",
|
|
4
4
|
"description": "Typescript SDK for interacting with the Picon DLMM protocol",
|
|
5
5
|
"author": "Picon Finance",
|
|
6
6
|
"license": "MIT",
|
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
},
|
|
24
24
|
"files": [
|
|
25
25
|
"./dist/",
|
|
26
|
-
"./src/"
|
|
26
|
+
"./src/",
|
|
27
|
+
"!**/*.test.ts"
|
|
27
28
|
],
|
|
28
29
|
"scripts": {
|
|
29
30
|
"clean": "rm -rf ./dist/",
|
|
@@ -36,9 +37,10 @@
|
|
|
36
37
|
"build-wasm-bindings-web": "wasm-bindgen ../target/wasm32-unknown-unknown/release/picon_dlmm_quote.wasm --out-dir ./src/quote/wasm-web --target web --typescript",
|
|
37
38
|
"build-wasm": "bun run build-wasm-crate && bun run clean-wasm && bun run build-wasm-bindings-node && bun run build-wasm-bindings-web",
|
|
38
39
|
"copy-wasm-binaries": "mkdir -p ./dist/quote/wasm-node ./dist/quote/wasm-web && cp ./src/quote/wasm-node/*.wasm ./src/quote/wasm-node/*.js ./src/quote/wasm-node/*.d.ts ./dist/quote/wasm-node/ && cp ./src/quote/wasm-web/*.wasm ./src/quote/wasm-web/*.js ./src/quote/wasm-web/*.d.ts ./dist/quote/wasm-web/",
|
|
39
|
-
"compile": "bun run clean && npx tsc && bun run copy-wasm-binaries",
|
|
40
|
+
"compile": "bun run clean && npx tsc -p tsconfig.build.json && bun run copy-wasm-binaries",
|
|
40
41
|
"build": "bun run codama-generate-js && bun run build-wasm && bun run compile",
|
|
41
|
-
"prepublishOnly": "bun run build"
|
|
42
|
+
"prepublishOnly": "bun run build",
|
|
43
|
+
"test": "bun test"
|
|
42
44
|
},
|
|
43
45
|
"dependencies": {
|
|
44
46
|
"@solana-program/system": "^0.13.0",
|
package/src/entities/pool.ts
CHANGED
|
@@ -178,70 +178,31 @@ export class Pool {
|
|
|
178
178
|
const { quoteOutput, binArrayAddresses } =
|
|
179
179
|
await this.#quoteExactIn({ xToY, amountIn, slippageToleranceBps });
|
|
180
180
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
ataY: tokenUserAccountY,
|
|
184
|
-
preInstructions,
|
|
185
|
-
postInstructions,
|
|
186
|
-
} = await processAssociatedTokenAccountPair({
|
|
187
|
-
owner: user,
|
|
188
|
-
tokenMintX: this.tokenMintX,
|
|
189
|
-
tokenMintY: this.tokenMintY,
|
|
190
|
-
tokenProgramX: this.tokenProgramX,
|
|
191
|
-
tokenProgramY: this.tokenProgramY,
|
|
192
|
-
amountX: xToY ? amountIn : undefined,
|
|
193
|
-
amountY: xToY ? undefined : amountIn,
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
// Each mint's hook accounts are resolved against whichever role it plays in this swap —
|
|
197
|
-
// input (user -> vault, owner = user) or output (vault -> user, owner = pool PDA).
|
|
198
|
-
const xTransferAccounts: TransferHookAccounts = xToY
|
|
199
|
-
? { source: tokenUserAccountX, mint: this.tokenMintX, destination: this.tokenVaultX, owner: user.address }
|
|
200
|
-
: { source: this.tokenVaultX, mint: this.tokenMintX, destination: tokenUserAccountX, owner: this.address };
|
|
201
|
-
const yTransferAccounts: TransferHookAccounts = xToY
|
|
202
|
-
? { source: this.tokenVaultY, mint: this.tokenMintY, destination: tokenUserAccountY, owner: this.address }
|
|
203
|
-
: { source: tokenUserAccountY, mint: this.tokenMintY, destination: this.tokenVaultY, owner: user.address };
|
|
204
|
-
|
|
205
|
-
const [transferHookXAccounts, transferHookYAccounts] = await Promise.all([
|
|
206
|
-
this.resolveTransferHookAccountsX(xTransferAccounts),
|
|
207
|
-
this.resolveTransferHookAccountsY(yTransferAccounts),
|
|
208
|
-
]);
|
|
209
|
-
|
|
210
|
-
const groups: generated.AccountGroup[] = [
|
|
211
|
-
{ kind: generated.AccountKind.BinArray, count: binArrayAddresses.length },
|
|
212
|
-
];
|
|
213
|
-
const remainingAccounts = binArrayAddresses.map(address => ({ address, role: AccountRole.WRITABLE }));
|
|
214
|
-
|
|
215
|
-
if (transferHookXAccounts.length > 0) {
|
|
216
|
-
groups.push({ kind: generated.AccountKind.TransferHookX, count: transferHookXAccounts.length });
|
|
217
|
-
remainingAccounts.push(...transferHookXAccounts.map(toRemainingAccountMeta));
|
|
218
|
-
}
|
|
219
|
-
if (transferHookYAccounts.length > 0) {
|
|
220
|
-
groups.push({ kind: generated.AccountKind.TransferHookY, count: transferHookYAccounts.length });
|
|
221
|
-
remainingAccounts.push(...transferHookYAccounts.map(toRemainingAccountMeta));
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
const remainingAccountsScheme: generated.RemainingAccountsScheme = { groups };
|
|
225
|
-
const swapIx = generated.getSwapExactInInstruction({
|
|
181
|
+
// The input leg is fixed, so it funds the wSOL leg (if any) directly.
|
|
182
|
+
const instructions = await this.#assembleSwapInstructions(
|
|
226
183
|
user,
|
|
227
|
-
pool: this.address,
|
|
228
|
-
tokenMintX: this.tokenMintX,
|
|
229
|
-
tokenMintY: this.tokenMintY,
|
|
230
|
-
tokenUserAccountX,
|
|
231
|
-
tokenUserAccountY,
|
|
232
|
-
tokenVaultX: this.tokenVaultX,
|
|
233
|
-
tokenVaultY: this.tokenVaultY,
|
|
234
|
-
tokenProgramX: this.tokenProgramX,
|
|
235
|
-
tokenProgramY: this.tokenProgramY,
|
|
236
|
-
amountIn,
|
|
237
|
-
minAmountOut: quoteOutput.minAmountOut,
|
|
238
184
|
xToY,
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
185
|
+
amountIn,
|
|
186
|
+
binArrayAddresses,
|
|
187
|
+
({ tokenUserAccountX, tokenUserAccountY, remainingAccountsScheme }) =>
|
|
188
|
+
generated.getSwapExactInInstruction({
|
|
189
|
+
user,
|
|
190
|
+
pool: this.address,
|
|
191
|
+
tokenMintX: this.tokenMintX,
|
|
192
|
+
tokenMintY: this.tokenMintY,
|
|
193
|
+
tokenUserAccountX,
|
|
194
|
+
tokenUserAccountY,
|
|
195
|
+
tokenVaultX: this.tokenVaultX,
|
|
196
|
+
tokenVaultY: this.tokenVaultY,
|
|
197
|
+
tokenProgramX: this.tokenProgramX,
|
|
198
|
+
tokenProgramY: this.tokenProgramY,
|
|
199
|
+
amountIn,
|
|
200
|
+
minAmountOut: quoteOutput.minAmountOut,
|
|
201
|
+
xToY,
|
|
202
|
+
remainingAccountsScheme,
|
|
203
|
+
}, { programAddress: this.#programAddress }),
|
|
204
|
+
);
|
|
243
205
|
|
|
244
|
-
const instructions = [...preInstructions, swapIxWithBinArrays, ...postInstructions];
|
|
245
206
|
return { quoteOutput, instructions };
|
|
246
207
|
}
|
|
247
208
|
|
|
@@ -260,6 +221,52 @@ export class Pool {
|
|
|
260
221
|
const { quoteOutput, binArrayAddresses } =
|
|
261
222
|
await this.#quoteExactOut({ xToY, amountOut, slippageToleranceBps });
|
|
262
223
|
|
|
224
|
+
// The real input isn't known until the swap executes, so the wSOL leg (if any) is funded with
|
|
225
|
+
// the worst-case maxAmountIn — any excess is unwrapped back to the owner in postInstructions.
|
|
226
|
+
const instructions = await this.#assembleSwapInstructions(
|
|
227
|
+
user,
|
|
228
|
+
xToY,
|
|
229
|
+
quoteOutput.maxAmountIn,
|
|
230
|
+
binArrayAddresses,
|
|
231
|
+
({ tokenUserAccountX, tokenUserAccountY, remainingAccountsScheme }) =>
|
|
232
|
+
generated.getSwapExactOutInstruction({
|
|
233
|
+
user,
|
|
234
|
+
pool: this.address,
|
|
235
|
+
tokenMintX: this.tokenMintX,
|
|
236
|
+
tokenMintY: this.tokenMintY,
|
|
237
|
+
tokenUserAccountX,
|
|
238
|
+
tokenUserAccountY,
|
|
239
|
+
tokenVaultX: this.tokenVaultX,
|
|
240
|
+
tokenVaultY: this.tokenVaultY,
|
|
241
|
+
tokenProgramX: this.tokenProgramX,
|
|
242
|
+
tokenProgramY: this.tokenProgramY,
|
|
243
|
+
amountOut,
|
|
244
|
+
maxAmountIn: quoteOutput.maxAmountIn,
|
|
245
|
+
xToY,
|
|
246
|
+
remainingAccountsScheme,
|
|
247
|
+
}, { programAddress: this.#programAddress }),
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
return { quoteOutput, instructions };
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Shared tail of both swap directions: sets up the user's X/Y ATAs (funding the wSOL leg, if
|
|
254
|
+
// any, with `fundingAmount`), resolves each mint's transfer-hook accounts against the role it
|
|
255
|
+
// plays in this swap — input (user -> vault, owner = user) or output (vault -> user, owner =
|
|
256
|
+
// pool PDA) — builds the remaining-accounts scheme, and splices the bin arrays + resolved hook
|
|
257
|
+
// accounts onto the instruction `buildSwapIx` produces. Only the funding amount and the
|
|
258
|
+
// instruction itself differ between exact-in and exact-out.
|
|
259
|
+
async #assembleSwapInstructions(
|
|
260
|
+
user: TransactionSigner,
|
|
261
|
+
xToY: boolean,
|
|
262
|
+
fundingAmount: bigint,
|
|
263
|
+
binArrayAddresses: Address[],
|
|
264
|
+
buildSwapIx: (accounts: {
|
|
265
|
+
tokenUserAccountX: Address,
|
|
266
|
+
tokenUserAccountY: Address,
|
|
267
|
+
remainingAccountsScheme: generated.RemainingAccountsScheme,
|
|
268
|
+
}) => Instruction,
|
|
269
|
+
): Promise<Instruction[]> {
|
|
263
270
|
const {
|
|
264
271
|
ataX: tokenUserAccountX,
|
|
265
272
|
ataY: tokenUserAccountY,
|
|
@@ -271,14 +278,10 @@ export class Pool {
|
|
|
271
278
|
tokenMintY: this.tokenMintY,
|
|
272
279
|
tokenProgramX: this.tokenProgramX,
|
|
273
280
|
tokenProgramY: this.tokenProgramY,
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
amountX: xToY ? quoteOutput.maxAmountIn : undefined,
|
|
277
|
-
amountY: xToY ? undefined : quoteOutput.maxAmountIn,
|
|
281
|
+
amountX: xToY ? fundingAmount : undefined,
|
|
282
|
+
amountY: xToY ? undefined : fundingAmount,
|
|
278
283
|
});
|
|
279
284
|
|
|
280
|
-
// Each mint's hook accounts are resolved against whichever role it plays in this swap —
|
|
281
|
-
// input (user -> vault, owner = user) or output (vault -> user, owner = pool PDA).
|
|
282
285
|
const xTransferAccounts: TransferHookAccounts = xToY
|
|
283
286
|
? { source: tokenUserAccountX, mint: this.tokenMintX, destination: this.tokenVaultX, owner: user.address }
|
|
284
287
|
: { source: this.tokenVaultX, mint: this.tokenMintX, destination: tokenUserAccountX, owner: this.address };
|
|
@@ -305,28 +308,14 @@ export class Pool {
|
|
|
305
308
|
remainingAccounts.push(...transferHookYAccounts.map(toRemainingAccountMeta));
|
|
306
309
|
}
|
|
307
310
|
|
|
308
|
-
const
|
|
309
|
-
const swapIx = generated.getSwapExactOutInstruction({
|
|
310
|
-
user,
|
|
311
|
-
pool: this.address,
|
|
312
|
-
tokenMintX: this.tokenMintX,
|
|
313
|
-
tokenMintY: this.tokenMintY,
|
|
311
|
+
const swapIx = buildSwapIx({
|
|
314
312
|
tokenUserAccountX,
|
|
315
313
|
tokenUserAccountY,
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
tokenProgramY: this.tokenProgramY,
|
|
320
|
-
amountOut,
|
|
321
|
-
maxAmountIn: quoteOutput.maxAmountIn,
|
|
322
|
-
xToY,
|
|
323
|
-
remainingAccountsScheme,
|
|
324
|
-
}, { programAddress: this.#programAddress });
|
|
325
|
-
|
|
326
|
-
const swapIxWithBinArrays = { ...swapIx, accounts: [...swapIx.accounts, ...remainingAccounts] };
|
|
314
|
+
remainingAccountsScheme: { groups },
|
|
315
|
+
});
|
|
316
|
+
const swapIxWithBinArrays = { ...swapIx, accounts: [...(swapIx.accounts ?? []), ...remainingAccounts] };
|
|
327
317
|
|
|
328
|
-
|
|
329
|
-
return { quoteOutput, instructions };
|
|
318
|
+
return [...preInstructions, swapIxWithBinArrays, ...postInstructions];
|
|
330
319
|
}
|
|
331
320
|
|
|
332
321
|
// Public so Position (which only holds a reference to this Pool, not its private mint data)
|
package/src/entities/position.ts
CHANGED
|
@@ -30,12 +30,12 @@ import {
|
|
|
30
30
|
assertPositionBelongsToPool,
|
|
31
31
|
} from "../utils/assert";
|
|
32
32
|
import { isUndefined } from "../utils/type_guards";
|
|
33
|
-
import {
|
|
33
|
+
import {
|
|
34
34
|
chunk,
|
|
35
35
|
fetchInChunks,
|
|
36
36
|
} from "../utils/chunk";
|
|
37
37
|
import { resolveAdminConfigAddress } from "./admin_config";
|
|
38
|
-
import {
|
|
38
|
+
import {
|
|
39
39
|
DEFAULT_POSITIONS_PER_CLAIM,
|
|
40
40
|
MAX_ACCOUNTS_PER_RPC_BATCH,
|
|
41
41
|
} from "../utils/constants";
|
package/src/picon_dlmm.json
CHANGED
|
Binary file
|
|
Binary file
|
package/src/utils/price.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { MAX_BASIS_POINTS } from "./constants";
|
|
2
|
+
import { isUndefined } from "./type_guards";
|
|
2
3
|
import { expBySquaring, MAX, MAX_EXPONENTIAL, ONE, SCALE_OFFSET } from "./u64x64";
|
|
3
4
|
|
|
4
5
|
export function getBaseBinPrice(binStep: number): bigint {
|
|
@@ -19,8 +20,8 @@ export function getBinPrice(baseBinPrice: bigint, binId: number): bigint | undef
|
|
|
19
20
|
|
|
20
21
|
if (absBinId >= MAX_EXPONENTIAL) return;
|
|
21
22
|
|
|
22
|
-
const
|
|
23
|
-
const price = expBySquaring(
|
|
23
|
+
const invertedBaseBinPrice = MAX / baseBinPrice;
|
|
24
|
+
const price = expBySquaring(invertedBaseBinPrice, absBinId);
|
|
24
25
|
|
|
25
26
|
if (price === 0n) return;
|
|
26
27
|
|
|
@@ -30,3 +31,71 @@ export function getBinPrice(baseBinPrice: bigint, binId: number): bigint | undef
|
|
|
30
31
|
export function getBinPriceFromStep(binStep: number, binId: number): bigint | undefined {
|
|
31
32
|
return getBinPrice(getBaseBinPrice(binStep), binId);
|
|
32
33
|
}
|
|
34
|
+
|
|
35
|
+
const MAX_BIN_ID_BY_BIN_STEP = new Map<number, number>([
|
|
36
|
+
[1, 443636],
|
|
37
|
+
[2, 221829],
|
|
38
|
+
[4, 110925],
|
|
39
|
+
[5, 88745],
|
|
40
|
+
[8, 55473],
|
|
41
|
+
[10, 44383],
|
|
42
|
+
[15, 29596],
|
|
43
|
+
[16, 27748],
|
|
44
|
+
[20, 22202],
|
|
45
|
+
[25, 17759],
|
|
46
|
+
[30, 14809],
|
|
47
|
+
[50, 8893],
|
|
48
|
+
[75, 5937],
|
|
49
|
+
[80, 5567],
|
|
50
|
+
[100, 4456],
|
|
51
|
+
[125, 3571],
|
|
52
|
+
[150, 2979],
|
|
53
|
+
[160, 2794],
|
|
54
|
+
[200, 2239],
|
|
55
|
+
[250, 1796],
|
|
56
|
+
[300, 1500],
|
|
57
|
+
[400, 1130],
|
|
58
|
+
]);
|
|
59
|
+
|
|
60
|
+
const MIN_PRICE = 1n;
|
|
61
|
+
const MAX_PRICE = MAX;
|
|
62
|
+
|
|
63
|
+
export function getBinIdFromPrice(binStep: number, price: bigint): number | undefined {
|
|
64
|
+
if (price <= 0n) return;
|
|
65
|
+
|
|
66
|
+
const maxBinId = MAX_BIN_ID_BY_BIN_STEP.get(binStep);
|
|
67
|
+
if (isUndefined(maxBinId)) {
|
|
68
|
+
throw new Error(`getBinIdFromPrice: unsupported binStep (${binStep})`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (price <= MIN_PRICE) return -maxBinId;
|
|
72
|
+
if (price >= MAX_PRICE) return maxBinId;
|
|
73
|
+
|
|
74
|
+
const baseBinPrice = getBaseBinPrice(binStep);
|
|
75
|
+
|
|
76
|
+
let lowerBinId = -maxBinId;
|
|
77
|
+
let upperBinId = maxBinId;
|
|
78
|
+
|
|
79
|
+
let currentPrice = MAX_PRICE;
|
|
80
|
+
let previousPrice: bigint | undefined;
|
|
81
|
+
|
|
82
|
+
while (lowerBinId < upperBinId) {
|
|
83
|
+
const middleBinId = lowerBinId + Math.floor((upperBinId - lowerBinId) / 2);
|
|
84
|
+
const middlePrice = getBinPrice(baseBinPrice, middleBinId)!;
|
|
85
|
+
|
|
86
|
+
if (middlePrice < price) {
|
|
87
|
+
lowerBinId = middleBinId + 1;
|
|
88
|
+
previousPrice = middlePrice;
|
|
89
|
+
} else {
|
|
90
|
+
upperBinId = middleBinId;
|
|
91
|
+
currentPrice = middlePrice;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (isUndefined(previousPrice)) return lowerBinId;
|
|
96
|
+
|
|
97
|
+
// previousPrice < price <= currentPrice always holds here, so both distances are non-negative.
|
|
98
|
+
const previousPriceDistance = price - previousPrice;
|
|
99
|
+
const currentPriceDistance = currentPrice - price;
|
|
100
|
+
return previousPriceDistance < currentPriceDistance ? lowerBinId - 1 : lowerBinId;
|
|
101
|
+
}
|