@picon-finance/dlmm-sdk 1.6.0 → 1.7.0
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 +22 -6
- package/dist/entities/pool.d.ts +5 -1
- package/dist/entities/pool.d.ts.map +1 -1
- package/dist/entities/pool.js +10 -5
- package/dist/entities/position.d.ts +3 -5
- package/dist/entities/position.d.ts.map +1 -1
- package/dist/entities/position.js +58 -14
- package/dist/entities/types.d.ts +26 -0
- package/dist/entities/types.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/quote/index.d.ts +1 -0
- package/dist/quote/index.d.ts.map +1 -1
- package/dist/quote/index.js +4 -0
- package/dist/quote/wasm-node/picon_dlmm_quote.d.ts +6 -0
- package/dist/quote/wasm-node/picon_dlmm_quote.js +15 -0
- package/dist/quote/wasm-node/picon_dlmm_quote_bg.wasm +0 -0
- package/dist/quote/wasm-node/picon_dlmm_quote_bg.wasm.d.ts +1 -0
- package/dist/quote/wasm-web/picon_dlmm_quote.d.ts +7 -0
- package/dist/quote/wasm-web/picon_dlmm_quote.js +15 -0
- package/dist/quote/wasm-web/picon_dlmm_quote_bg.wasm +0 -0
- package/dist/quote/wasm-web/picon_dlmm_quote_bg.wasm.d.ts +1 -0
- package/package.json +1 -1
- package/src/entities/pool.ts +15 -6
- package/src/entities/position.ts +68 -17
- package/src/entities/types.ts +37 -1
- package/src/index.ts +1 -1
- package/src/quote/index.ts +5 -0
- package/src/quote/wasm-node/picon_dlmm_quote.d.ts +6 -0
- package/src/quote/wasm-node/picon_dlmm_quote.js +15 -0
- package/src/quote/wasm-node/picon_dlmm_quote_bg.wasm +0 -0
- package/src/quote/wasm-node/picon_dlmm_quote_bg.wasm.d.ts +1 -0
- package/src/quote/wasm-web/picon_dlmm_quote.d.ts +7 -0
- package/src/quote/wasm-web/picon_dlmm_quote.js +15 -0
- package/src/quote/wasm-web/picon_dlmm_quote_bg.wasm +0 -0
- package/src/quote/wasm-web/picon_dlmm_quote_bg.wasm.d.ts +1 -0
package/README.md
CHANGED
|
@@ -67,8 +67,8 @@ const openPositionIxs = await pool.openPosition(ownerSigner, positionMintSigner,
|
|
|
67
67
|
|
|
68
68
|
const position = await pool.getPositionByPositionMint(positionMintSigner.address);
|
|
69
69
|
|
|
70
|
-
// depositByWeight checks the deposit against the pool's cached activeBinId — if
|
|
71
|
-
//
|
|
70
|
+
// depositByWeight checks the deposit against the pool's cached activeBinId — if time has
|
|
71
|
+
// passed since pool was fetched (other activity could've moved the price since), refresh it
|
|
72
72
|
// first so the deposit isn't built/checked against a stale active bin.
|
|
73
73
|
await pool.refresh();
|
|
74
74
|
|
|
@@ -93,12 +93,28 @@ const closeIx = await position.close(ownerSigner);
|
|
|
93
93
|
console.log(position.data.lowerBinId, position.data.upperBinId);
|
|
94
94
|
```
|
|
95
95
|
|
|
96
|
-
`position.
|
|
96
|
+
`position.getInfo()` returns a full summary: deposited amounts and the total fee a `claimFee` call would sweep right now, each in both `gross*` (before any Token-2022 transfer fee) and `net*` (what you'd actually receive) forms, plus the per-bin data they're summed from:
|
|
97
97
|
|
|
98
98
|
```ts
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
99
|
+
const info = await position.getInfo();
|
|
100
|
+
console.log(`Deposited: ${info.netAmountX} X / ${info.netAmountY} Y`);
|
|
101
|
+
console.log(`Claimable fee: ${info.netFeeX} X / ${info.netFeeY} Y`);
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
`info.bins` (same as calling `position.getBinInfos()` directly) is the per-bin breakdown `getInfo()` sums to produce those totals — always raw, since `gross*`/`net*` only apply once, to the aggregate:
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
for (const { bin, amountX, amountY, feeX, feeY } of position.getBinInfos()) {
|
|
108
|
+
console.log(`bin ${bin.id}: deposited ${amountX} X / ${amountY} Y, fee ${feeX} X / ${feeY} Y`);
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Both are computed entirely from cached position + bin array data — `getBinInfos()` makes no RPC calls at all; `getInfo()` makes one round trip (via `Pool.getTransferFees()`) to resolve each mint's live transfer-fee rate.
|
|
113
|
+
|
|
114
|
+
`Pool.getTransferFees()` resolves each mint's active [Token-2022 transfer-fee](https://spl.solana.com/token-2022/extensions#transfer-fees) config from cached mint data — `undefined` per side means that mint has no `TransferFeeConfig` extension, not that the fee is zero:
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
const { transferFeeX, transferFeeY } = await pool.getTransferFees();
|
|
102
118
|
```
|
|
103
119
|
|
|
104
120
|
Refresh a position's cached state after it changes on-chain (e.g. after a deposit lands):
|
package/dist/entities/pool.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createSolanaRpc, type Address, type Account, type Instruction, type TransactionSigner, type FetchAccountConfig, type FetchAccountsConfig } from "@solana/kit";
|
|
2
2
|
import { generated } from "..";
|
|
3
|
-
import { type QuoteOutput } from "../quote";
|
|
3
|
+
import { type QuoteOutput, type TransferFee } from "../quote";
|
|
4
4
|
import { Position } from "./position";
|
|
5
5
|
import { type ProgramConfig } from "./types";
|
|
6
6
|
export declare class Pool {
|
|
@@ -19,6 +19,10 @@ export declare class Pool {
|
|
|
19
19
|
get tokenVaultY(): Address;
|
|
20
20
|
get tokenProgramX(): Address;
|
|
21
21
|
get tokenProgramY(): Address;
|
|
22
|
+
getTransferFees(): Promise<{
|
|
23
|
+
transferFeeX?: TransferFee;
|
|
24
|
+
transferFeeY?: TransferFee;
|
|
25
|
+
}>;
|
|
22
26
|
refresh(data: Account<generated.Pool>): Promise<void>;
|
|
23
27
|
refresh(config?: FetchAccountConfig): Promise<void>;
|
|
24
28
|
getPosition(address: Address, config?: FetchAccountsConfig): Promise<Position>;
|
|
@@ -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,
|
|
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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AccountRole, } from "@solana/kit";
|
|
2
2
|
import { fetchAllMint, } from "@solana-program/token-2022";
|
|
3
3
|
import { generated } from "..";
|
|
4
|
-
import { quote } from "../quote";
|
|
4
|
+
import { quote, } from "../quote";
|
|
5
5
|
import { isAccount } from "../utils/type_guards";
|
|
6
6
|
import { resolveAdminConfigAddress } from "./admin_config";
|
|
7
7
|
import { processAssociatedTokenAccountPair } from "../utils/ata";
|
|
@@ -36,6 +36,13 @@ export class Pool {
|
|
|
36
36
|
get tokenVaultY() { return this.data.tokenVaultY; }
|
|
37
37
|
get tokenProgramX() { return this.#mintX.programAddress; }
|
|
38
38
|
get tokenProgramY() { return this.#mintY.programAddress; }
|
|
39
|
+
async getTransferFees() {
|
|
40
|
+
const { epoch } = await this.#rpc.getEpochInfo().send();
|
|
41
|
+
return {
|
|
42
|
+
transferFeeX: resolveTransferFee(this.#mintX.data, epoch),
|
|
43
|
+
transferFeeY: resolveTransferFee(this.#mintY.data, epoch),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
39
46
|
async refresh(arg) {
|
|
40
47
|
if (!isAccount(arg)) {
|
|
41
48
|
arg = await generated.fetchPool(this.#rpc, this.address, arg);
|
|
@@ -95,13 +102,11 @@ export class Pool {
|
|
|
95
102
|
async quote({ xToY, amountIn, slippageToleranceBps, }) {
|
|
96
103
|
const indices = generateBinArrayIndicesForSwap(this.activeBinId, xToY, MAX_BIN_ARRAYS_PER_SWAP);
|
|
97
104
|
const binArrayAddresses = await findAllBinArrayAddresses({ pool: this.address, indices }, { programAddress: this.#programAddress });
|
|
98
|
-
const [maybeBinArrays, {
|
|
105
|
+
const [maybeBinArrays, { transferFeeX, transferFeeY }] = await Promise.all([
|
|
99
106
|
generated.fetchAllMaybeBinArray(this.#rpc, binArrayAddresses),
|
|
100
|
-
this
|
|
107
|
+
this.getTransferFees(),
|
|
101
108
|
]);
|
|
102
109
|
const binArrays = maybeBinArrays.map(maybeBinArray => maybeBinArray.exists ? maybeBinArray.data : undefined);
|
|
103
|
-
const transferFeeX = resolveTransferFee(this.#mintX.data, epoch);
|
|
104
|
-
const transferFeeY = resolveTransferFee(this.#mintY.data, epoch);
|
|
105
110
|
return await quote({
|
|
106
111
|
amountIn,
|
|
107
112
|
xToY,
|
|
@@ -3,7 +3,7 @@ import { generated } from "..";
|
|
|
3
3
|
import { type BinIdRange } from "../utils/bin_location";
|
|
4
4
|
import { Pool } from "./pool";
|
|
5
5
|
import { BinArray } from "./bin_array";
|
|
6
|
-
import { type ProgramConfig } from "./types";
|
|
6
|
+
import { type PositionInfo, type ProgramConfig, type PositionBinInfo } from "./types";
|
|
7
7
|
export declare class Position {
|
|
8
8
|
#private;
|
|
9
9
|
private constructor();
|
|
@@ -15,10 +15,8 @@ export declare class Position {
|
|
|
15
15
|
lowerBinArray: Address;
|
|
16
16
|
upperBinArray?: Address | undefined;
|
|
17
17
|
};
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
amountY: bigint;
|
|
21
|
-
};
|
|
18
|
+
getBinInfos(): PositionBinInfo[];
|
|
19
|
+
getInfo(): Promise<PositionInfo>;
|
|
22
20
|
refresh(data: [Account<generated.Position>, Account<generated.BinArray>[]]): Promise<void>;
|
|
23
21
|
refresh(config?: FetchAccountsConfig): Promise<void>;
|
|
24
22
|
depositByWeight(owner: TransactionSigner, { amountX, amountY, lowerBinId, binWeights, maxActiveBinSlippage, distributionMode, }: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"position.d.ts","sourceRoot":"","sources":["../../src/entities/position.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,eAAe,EAGf,KAAK,OAAO,EACZ,KAAK,OAAO,EACZ,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EAEzB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"position.d.ts","sourceRoot":"","sources":["../../src/entities/position.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { decodeAccount, assertAccountExists, fetchEncodedAccounts, } from "@solana/kit";
|
|
2
2
|
import { generated } from "..";
|
|
3
|
+
import { applyTransferFee } from "../quote";
|
|
3
4
|
import { findPositionTokenAccount, processAssociatedTokenAccountPair, } from "../utils/ata";
|
|
4
5
|
import { getBinIndex, getBinArrayIndex, getPositionBinArrayIndices, } from "../utils/bin_location";
|
|
5
6
|
import { assertRangeWithinRange, assertPositionBelongsToPool, } from "../utils/assert";
|
|
@@ -26,25 +27,68 @@ export class Position {
|
|
|
26
27
|
const upperBinArray = this.#binArrays.length > 1 ? this.#binArrays[1].address : undefined;
|
|
27
28
|
return { lowerBinArray, upperBinArray };
|
|
28
29
|
}
|
|
29
|
-
|
|
30
|
+
getBinInfos() {
|
|
30
31
|
const { lowerBinId, upperBinId, feeStates } = this.data;
|
|
31
32
|
const lowerBinArrayIndex = getBinArrayIndex(lowerBinId);
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
return [];
|
|
33
|
+
const binCount = upperBinId - lowerBinId + 1;
|
|
34
|
+
return feeStates
|
|
35
|
+
.slice(0, binCount)
|
|
36
|
+
.map((feeState, i) => {
|
|
37
37
|
const binId = lowerBinId + i;
|
|
38
38
|
const binIndex = getBinIndex(binId);
|
|
39
|
-
const
|
|
40
|
-
const binArray = this.#binArrays[
|
|
39
|
+
const localBinArrayIndex = getBinArrayIndex(binId) - lowerBinArrayIndex;
|
|
40
|
+
const binArray = this.#binArrays[localBinArrayIndex];
|
|
41
41
|
const bin = binArray.bins[binIndex];
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
42
|
+
const amountX = bin.totalShares > 0n ? (feeState.shares * bin.amountX) / bin.totalShares : 0n;
|
|
43
|
+
const amountY = bin.totalShares > 0n ? (feeState.shares * bin.amountY) / bin.totalShares : 0n;
|
|
44
|
+
let feeX = feeState.feeOwedX;
|
|
45
|
+
let feeY = feeState.feeOwedY;
|
|
46
|
+
if (feeState.shares > 0n && bin.totalShares > 0n) {
|
|
47
|
+
feeX += earnedAmount(bin.feePerShareX, feeState.feePerShareCheckpointX, feeState.shares);
|
|
48
|
+
feeY += earnedAmount(bin.feePerShareY, feeState.feePerShareCheckpointY, feeState.shares);
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
bin: {
|
|
52
|
+
id: binId,
|
|
53
|
+
price: bin.price,
|
|
54
|
+
amountX: bin.amountX,
|
|
55
|
+
amountY: bin.amountY,
|
|
56
|
+
shares: bin.totalShares
|
|
57
|
+
},
|
|
58
|
+
amountX,
|
|
59
|
+
amountY,
|
|
60
|
+
shares: feeState.shares,
|
|
61
|
+
feeX,
|
|
62
|
+
feeY,
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
async getInfo() {
|
|
67
|
+
const bins = this.getBinInfos();
|
|
68
|
+
const gross = bins.reduce((acc, { amountX, amountY, feeX, feeY }) => ({
|
|
69
|
+
amountX: acc.amountX + amountX,
|
|
70
|
+
amountY: acc.amountY + amountY,
|
|
71
|
+
feeX: acc.feeX + feeX,
|
|
72
|
+
feeY: acc.feeY + feeY,
|
|
73
|
+
}), { amountX: 0n, amountY: 0n, feeX: 0n, feeY: 0n });
|
|
74
|
+
const { transferFeeX, transferFeeY } = await this.#pool.getTransferFees();
|
|
75
|
+
const [netAmountX, netAmountY, netFeeX, netFeeY] = await Promise.all([
|
|
76
|
+
applyTransferFee(gross.amountX, transferFeeX),
|
|
77
|
+
applyTransferFee(gross.amountY, transferFeeY),
|
|
78
|
+
applyTransferFee(gross.feeX, transferFeeX),
|
|
79
|
+
applyTransferFee(gross.feeY, transferFeeY),
|
|
80
|
+
]);
|
|
81
|
+
return {
|
|
82
|
+
bins,
|
|
83
|
+
grossAmountX: gross.amountX,
|
|
84
|
+
grossAmountY: gross.amountY,
|
|
85
|
+
netAmountX,
|
|
86
|
+
netAmountY,
|
|
87
|
+
grossFeeX: gross.feeX,
|
|
88
|
+
grossFeeY: gross.feeY,
|
|
89
|
+
netFeeX,
|
|
90
|
+
netFeeY,
|
|
91
|
+
};
|
|
48
92
|
}
|
|
49
93
|
async refresh(arg) {
|
|
50
94
|
if (!Array.isArray(arg)) {
|
package/dist/entities/types.d.ts
CHANGED
|
@@ -2,4 +2,30 @@ import { type Address } from "@solana/kit";
|
|
|
2
2
|
export type ProgramConfig = {
|
|
3
3
|
programAddress: Address;
|
|
4
4
|
};
|
|
5
|
+
export type BinInfo = {
|
|
6
|
+
id: number;
|
|
7
|
+
price: bigint;
|
|
8
|
+
amountX: bigint;
|
|
9
|
+
amountY: bigint;
|
|
10
|
+
shares: bigint;
|
|
11
|
+
};
|
|
12
|
+
export type PositionBinInfo = {
|
|
13
|
+
bin: BinInfo;
|
|
14
|
+
amountX: bigint;
|
|
15
|
+
amountY: bigint;
|
|
16
|
+
shares: bigint;
|
|
17
|
+
feeX: bigint;
|
|
18
|
+
feeY: bigint;
|
|
19
|
+
};
|
|
20
|
+
export type PositionInfo = {
|
|
21
|
+
bins: PositionBinInfo[];
|
|
22
|
+
grossAmountX: bigint;
|
|
23
|
+
grossAmountY: bigint;
|
|
24
|
+
netAmountX: bigint;
|
|
25
|
+
netAmountY: bigint;
|
|
26
|
+
grossFeeX: bigint;
|
|
27
|
+
grossFeeY: bigint;
|
|
28
|
+
netFeeX: bigint;
|
|
29
|
+
netFeeY: bigint;
|
|
30
|
+
};
|
|
5
31
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/entities/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,MAAM,aAAa,GAAG;IAAE,cAAc,EAAE,OAAO,CAAA;CAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/entities/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,MAAM,aAAa,GAAG;IAAE,cAAc,EAAE,OAAO,CAAA;CAAE,CAAC;AAExD,MAAM,MAAM,OAAO,GAAG;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IAEd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,EAAE,OAAO,CAAC;IAEb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IAEf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,eAAe,EAAE,CAAC;IAExB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IAErB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IAEnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAElB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,6 @@ export * as events from "./events";
|
|
|
4
4
|
export * from "./entities";
|
|
5
5
|
export * from "./utils/constants";
|
|
6
6
|
export { NATIVE_MINT_ADDRESS } from "./utils/ata";
|
|
7
|
-
export type {
|
|
7
|
+
export type { QuoteOutput, TransferFee } from "./quote";
|
|
8
8
|
export * from "./program_addresses";
|
|
9
9
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AACtE,OAAO,KAAK,MAAM,MAAM,UAAU,CAAC;AACnC,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AACtE,OAAO,KAAK,MAAM,MAAM,UAAU,CAAC;AACnC,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACxD,cAAc,qBAAqB,CAAC"}
|
package/dist/quote/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type QuoteInput, type QuoteOutput, type PoolState, type TransferFee } from "#wasm";
|
|
2
2
|
export type { QuoteInput, QuoteOutput, PoolState, TransferFee };
|
|
3
3
|
export declare function quote(input: QuoteInput): Promise<QuoteOutput>;
|
|
4
|
+
export declare function applyTransferFee(amount: bigint, fee?: TransferFee): Promise<bigint>;
|
|
4
5
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/quote/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,WAAW,EACjB,MAAM,OAAO,CAAC;AAEf,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC;AAEhE,wBAAsB,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CAGnE"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/quote/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,WAAW,EACjB,MAAM,OAAO,CAAC;AAEf,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC;AAEhE,wBAAsB,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CAGnE;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAGzF"}
|
package/dist/quote/index.js
CHANGED
|
@@ -61,4 +61,10 @@ export interface TransferFee {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Applies `fee` to a gross `amount`, returning the net amount — or `amount` unchanged when
|
|
66
|
+
* `fee` is `None` (the mint has no `TransferFeeConfig` extension).
|
|
67
|
+
*/
|
|
68
|
+
export function applyTransferFee(amount: bigint, fee?: TransferFee | null): bigint;
|
|
69
|
+
|
|
64
70
|
export function quote(input: QuoteInput): QuoteOutput;
|
|
@@ -2,6 +2,21 @@
|
|
|
2
2
|
import { readFileSync } from 'node:fs';
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Applies `fee` to a gross `amount`, returning the net amount — or `amount` unchanged when
|
|
7
|
+
* `fee` is `None` (the mint has no `TransferFeeConfig` extension).
|
|
8
|
+
* @param {bigint} amount
|
|
9
|
+
* @param {TransferFee | null} [fee]
|
|
10
|
+
* @returns {bigint}
|
|
11
|
+
*/
|
|
12
|
+
export function applyTransferFee(amount, fee) {
|
|
13
|
+
const ret = wasm.applyTransferFee(amount, isLikeNone(fee) ? 0 : addToExternrefTable0(fee));
|
|
14
|
+
if (ret[2]) {
|
|
15
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
16
|
+
}
|
|
17
|
+
return BigInt.asUintN(64, ret[0]);
|
|
18
|
+
}
|
|
19
|
+
|
|
5
20
|
/**
|
|
6
21
|
* @param {QuoteInput} input
|
|
7
22
|
* @returns {QuoteOutput}
|
|
Binary file
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* tslint:disable */
|
|
2
2
|
/* eslint-disable */
|
|
3
3
|
export const memory: WebAssembly.Memory;
|
|
4
|
+
export const applyTransferFee: (a: bigint, b: number) => [bigint, number, number];
|
|
4
5
|
export const quote: (a: any) => [number, number, number];
|
|
5
6
|
export const __wbindgen_malloc: (a: number, b: number) => number;
|
|
6
7
|
export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
|
@@ -61,12 +61,19 @@ export interface TransferFee {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Applies `fee` to a gross `amount`, returning the net amount — or `amount` unchanged when
|
|
66
|
+
* `fee` is `None` (the mint has no `TransferFeeConfig` extension).
|
|
67
|
+
*/
|
|
68
|
+
export function applyTransferFee(amount: bigint, fee?: TransferFee | null): bigint;
|
|
69
|
+
|
|
64
70
|
export function quote(input: QuoteInput): QuoteOutput;
|
|
65
71
|
|
|
66
72
|
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
|
|
67
73
|
|
|
68
74
|
export interface InitOutput {
|
|
69
75
|
readonly memory: WebAssembly.Memory;
|
|
76
|
+
readonly applyTransferFee: (a: bigint, b: number) => [bigint, number, number];
|
|
70
77
|
readonly quote: (a: any) => [number, number, number];
|
|
71
78
|
readonly __wbindgen_malloc: (a: number, b: number) => number;
|
|
72
79
|
readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
/* @ts-self-types="./picon_dlmm_quote.d.ts" */
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Applies `fee` to a gross `amount`, returning the net amount — or `amount` unchanged when
|
|
5
|
+
* `fee` is `None` (the mint has no `TransferFeeConfig` extension).
|
|
6
|
+
* @param {bigint} amount
|
|
7
|
+
* @param {TransferFee | null} [fee]
|
|
8
|
+
* @returns {bigint}
|
|
9
|
+
*/
|
|
10
|
+
export function applyTransferFee(amount, fee) {
|
|
11
|
+
const ret = wasm.applyTransferFee(amount, isLikeNone(fee) ? 0 : addToExternrefTable0(fee));
|
|
12
|
+
if (ret[2]) {
|
|
13
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
14
|
+
}
|
|
15
|
+
return BigInt.asUintN(64, ret[0]);
|
|
16
|
+
}
|
|
17
|
+
|
|
3
18
|
/**
|
|
4
19
|
* @param {QuoteInput} input
|
|
5
20
|
* @returns {QuoteOutput}
|
|
Binary file
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* tslint:disable */
|
|
2
2
|
/* eslint-disable */
|
|
3
3
|
export const memory: WebAssembly.Memory;
|
|
4
|
+
export const applyTransferFee: (a: bigint, b: number) => [bigint, number, number];
|
|
4
5
|
export const quote: (a: any) => [number, number, number];
|
|
5
6
|
export const __wbindgen_malloc: (a: number, b: number) => number;
|
|
6
7
|
export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
package/package.json
CHANGED
package/src/entities/pool.ts
CHANGED
|
@@ -14,7 +14,11 @@ import {
|
|
|
14
14
|
} from "@solana-program/token-2022";
|
|
15
15
|
|
|
16
16
|
import { generated } from "..";
|
|
17
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
quote,
|
|
19
|
+
type QuoteOutput,
|
|
20
|
+
type TransferFee,
|
|
21
|
+
} from "../quote";
|
|
18
22
|
import { isAccount } from "../utils/type_guards";
|
|
19
23
|
import { resolveAdminConfigAddress } from "./admin_config";
|
|
20
24
|
import { processAssociatedTokenAccountPair } from "../utils/ata";
|
|
@@ -78,6 +82,14 @@ export class Pool {
|
|
|
78
82
|
public get tokenProgramX() { return this.#mintX.programAddress; }
|
|
79
83
|
public get tokenProgramY() { return this.#mintY.programAddress; }
|
|
80
84
|
|
|
85
|
+
public async getTransferFees(): Promise<{ transferFeeX?: TransferFee, transferFeeY?: TransferFee }> {
|
|
86
|
+
const { epoch } = await this.#rpc.getEpochInfo().send();
|
|
87
|
+
return {
|
|
88
|
+
transferFeeX: resolveTransferFee(this.#mintX.data, epoch),
|
|
89
|
+
transferFeeY: resolveTransferFee(this.#mintY.data, epoch),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
81
93
|
public async refresh(data: Account<generated.Pool>): Promise<void>;
|
|
82
94
|
public async refresh(config?: FetchAccountConfig): Promise<void>;
|
|
83
95
|
public async refresh(arg?: Account<generated.Pool> | FetchAccountConfig) {
|
|
@@ -211,15 +223,12 @@ export class Pool {
|
|
|
211
223
|
{ programAddress: this.#programAddress },
|
|
212
224
|
);
|
|
213
225
|
|
|
214
|
-
const [maybeBinArrays, {
|
|
226
|
+
const [maybeBinArrays, { transferFeeX, transferFeeY }] = await Promise.all([
|
|
215
227
|
generated.fetchAllMaybeBinArray(this.#rpc, binArrayAddresses),
|
|
216
|
-
this
|
|
228
|
+
this.getTransferFees(),
|
|
217
229
|
]);
|
|
218
230
|
const binArrays = maybeBinArrays.map(maybeBinArray => maybeBinArray.exists ? maybeBinArray.data : undefined);
|
|
219
231
|
|
|
220
|
-
const transferFeeX = resolveTransferFee(this.#mintX.data, epoch);
|
|
221
|
-
const transferFeeY = resolveTransferFee(this.#mintY.data, epoch);
|
|
222
|
-
|
|
223
232
|
return await quote({
|
|
224
233
|
amountIn,
|
|
225
234
|
xToY,
|
package/src/entities/position.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
} from "@solana/kit";
|
|
13
13
|
|
|
14
14
|
import { generated } from "..";
|
|
15
|
+
import { applyTransferFee } from "../quote";
|
|
15
16
|
import {
|
|
16
17
|
findPositionTokenAccount,
|
|
17
18
|
processAssociatedTokenAccountPair,
|
|
@@ -38,7 +39,11 @@ import {
|
|
|
38
39
|
createAllBinArrays,
|
|
39
40
|
fetchAllBinArraysChunked,
|
|
40
41
|
} from "./bin_array";
|
|
41
|
-
import {
|
|
42
|
+
import {
|
|
43
|
+
type PositionInfo,
|
|
44
|
+
type ProgramConfig,
|
|
45
|
+
type PositionBinInfo,
|
|
46
|
+
} from "./types";
|
|
42
47
|
|
|
43
48
|
export class Position {
|
|
44
49
|
#pool: Pool;
|
|
@@ -66,29 +71,75 @@ export class Position {
|
|
|
66
71
|
return { lowerBinArray, upperBinArray };
|
|
67
72
|
}
|
|
68
73
|
|
|
69
|
-
public
|
|
74
|
+
public getBinInfos(): PositionBinInfo[] {
|
|
70
75
|
const { lowerBinId, upperBinId, feeStates } = this.data;
|
|
71
76
|
const lowerBinArrayIndex = getBinArrayIndex(lowerBinId);
|
|
77
|
+
const binCount = upperBinId - lowerBinId + 1;
|
|
72
78
|
|
|
73
|
-
return
|
|
74
|
-
.
|
|
75
|
-
|
|
76
|
-
if (feeState.shares === 0n) return [];
|
|
77
|
-
|
|
79
|
+
return feeStates
|
|
80
|
+
.slice(0, binCount)
|
|
81
|
+
.map((feeState, i) => {
|
|
78
82
|
const binId = lowerBinId + i;
|
|
79
|
-
|
|
80
83
|
const binIndex = getBinIndex(binId);
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
const binArray = this.#binArrays[binArrayIndex];
|
|
84
|
+
const localBinArrayIndex = getBinArrayIndex(binId) - lowerBinArrayIndex;
|
|
85
|
+
const binArray = this.#binArrays[localBinArrayIndex];
|
|
84
86
|
const bin = binArray.bins[binIndex];
|
|
85
87
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
88
|
+
const amountX = bin.totalShares > 0n ? (feeState.shares * bin.amountX) / bin.totalShares : 0n;
|
|
89
|
+
const amountY = bin.totalShares > 0n ? (feeState.shares * bin.amountY) / bin.totalShares : 0n;
|
|
90
|
+
|
|
91
|
+
let feeX = feeState.feeOwedX;
|
|
92
|
+
let feeY = feeState.feeOwedY;
|
|
93
|
+
if (feeState.shares > 0n && bin.totalShares > 0n) {
|
|
94
|
+
feeX += earnedAmount(bin.feePerShareX, feeState.feePerShareCheckpointX, feeState.shares);
|
|
95
|
+
feeY += earnedAmount(bin.feePerShareY, feeState.feePerShareCheckpointY, feeState.shares);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
bin: {
|
|
100
|
+
id: binId,
|
|
101
|
+
price: bin.price,
|
|
102
|
+
amountX: bin.amountX,
|
|
103
|
+
amountY: bin.amountY,
|
|
104
|
+
shares: bin.totalShares
|
|
105
|
+
},
|
|
106
|
+
amountX,
|
|
107
|
+
amountY,
|
|
108
|
+
shares: feeState.shares,
|
|
109
|
+
feeX,
|
|
110
|
+
feeY,
|
|
111
|
+
};
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
public async getInfo(): Promise<PositionInfo> {
|
|
116
|
+
const bins = this.getBinInfos();
|
|
117
|
+
const gross = bins.reduce((acc, { amountX, amountY, feeX, feeY }) => ({
|
|
118
|
+
amountX: acc.amountX + amountX,
|
|
119
|
+
amountY: acc.amountY + amountY,
|
|
120
|
+
feeX: acc.feeX + feeX,
|
|
121
|
+
feeY: acc.feeY + feeY,
|
|
122
|
+
}), { amountX: 0n, amountY: 0n, feeX: 0n, feeY: 0n });
|
|
123
|
+
|
|
124
|
+
const { transferFeeX, transferFeeY } = await this.#pool.getTransferFees();
|
|
125
|
+
const [netAmountX, netAmountY, netFeeX, netFeeY] = await Promise.all([
|
|
126
|
+
applyTransferFee(gross.amountX, transferFeeX),
|
|
127
|
+
applyTransferFee(gross.amountY, transferFeeY),
|
|
128
|
+
applyTransferFee(gross.feeX, transferFeeX),
|
|
129
|
+
applyTransferFee(gross.feeY, transferFeeY),
|
|
130
|
+
]);
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
bins,
|
|
134
|
+
grossAmountX: gross.amountX,
|
|
135
|
+
grossAmountY: gross.amountY,
|
|
136
|
+
netAmountX,
|
|
137
|
+
netAmountY,
|
|
138
|
+
grossFeeX: gross.feeX,
|
|
139
|
+
grossFeeY: gross.feeY,
|
|
140
|
+
netFeeX,
|
|
141
|
+
netFeeY,
|
|
142
|
+
};
|
|
92
143
|
}
|
|
93
144
|
|
|
94
145
|
public async refresh(data: [Account<generated.Position>, Account<generated.BinArray>[]]): Promise<void>;
|
package/src/entities/types.ts
CHANGED
|
@@ -1,3 +1,39 @@
|
|
|
1
1
|
import { type Address } from "@solana/kit";
|
|
2
2
|
|
|
3
|
-
export type ProgramConfig = { programAddress: Address };
|
|
3
|
+
export type ProgramConfig = { programAddress: Address };
|
|
4
|
+
|
|
5
|
+
export type BinInfo = {
|
|
6
|
+
id: number;
|
|
7
|
+
price: bigint;
|
|
8
|
+
|
|
9
|
+
amountX: bigint;
|
|
10
|
+
amountY: bigint;
|
|
11
|
+
shares: bigint;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type PositionBinInfo = {
|
|
15
|
+
bin: BinInfo;
|
|
16
|
+
|
|
17
|
+
amountX: bigint;
|
|
18
|
+
amountY: bigint;
|
|
19
|
+
shares: bigint;
|
|
20
|
+
|
|
21
|
+
feeX: bigint;
|
|
22
|
+
feeY: bigint;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type PositionInfo = {
|
|
26
|
+
bins: PositionBinInfo[];
|
|
27
|
+
|
|
28
|
+
grossAmountX: bigint;
|
|
29
|
+
grossAmountY: bigint;
|
|
30
|
+
|
|
31
|
+
netAmountX: bigint;
|
|
32
|
+
netAmountY: bigint;
|
|
33
|
+
|
|
34
|
+
grossFeeX: bigint;
|
|
35
|
+
grossFeeY: bigint;
|
|
36
|
+
|
|
37
|
+
netFeeX: bigint;
|
|
38
|
+
netFeeY: bigint;
|
|
39
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -4,5 +4,5 @@ export * as events from "./events";
|
|
|
4
4
|
export * from "./entities";
|
|
5
5
|
export * from "./utils/constants";
|
|
6
6
|
export { NATIVE_MINT_ADDRESS } from "./utils/ata";
|
|
7
|
-
export type {
|
|
7
|
+
export type { QuoteOutput, TransferFee } from "./quote";
|
|
8
8
|
export * from "./program_addresses";
|
package/src/quote/index.ts
CHANGED
|
@@ -12,3 +12,8 @@ export async function quote(input: QuoteInput): Promise<QuoteOutput> {
|
|
|
12
12
|
const wasm = await loadWasm();
|
|
13
13
|
return wasm.quote(input);
|
|
14
14
|
}
|
|
15
|
+
|
|
16
|
+
export async function applyTransferFee(amount: bigint, fee?: TransferFee): Promise<bigint> {
|
|
17
|
+
const wasm = await loadWasm();
|
|
18
|
+
return wasm.applyTransferFee(amount, fee);
|
|
19
|
+
}
|
|
@@ -61,4 +61,10 @@ export interface TransferFee {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Applies `fee` to a gross `amount`, returning the net amount — or `amount` unchanged when
|
|
66
|
+
* `fee` is `None` (the mint has no `TransferFeeConfig` extension).
|
|
67
|
+
*/
|
|
68
|
+
export function applyTransferFee(amount: bigint, fee?: TransferFee | null): bigint;
|
|
69
|
+
|
|
64
70
|
export function quote(input: QuoteInput): QuoteOutput;
|
|
@@ -2,6 +2,21 @@
|
|
|
2
2
|
import { readFileSync } from 'node:fs';
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Applies `fee` to a gross `amount`, returning the net amount — or `amount` unchanged when
|
|
7
|
+
* `fee` is `None` (the mint has no `TransferFeeConfig` extension).
|
|
8
|
+
* @param {bigint} amount
|
|
9
|
+
* @param {TransferFee | null} [fee]
|
|
10
|
+
* @returns {bigint}
|
|
11
|
+
*/
|
|
12
|
+
export function applyTransferFee(amount, fee) {
|
|
13
|
+
const ret = wasm.applyTransferFee(amount, isLikeNone(fee) ? 0 : addToExternrefTable0(fee));
|
|
14
|
+
if (ret[2]) {
|
|
15
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
16
|
+
}
|
|
17
|
+
return BigInt.asUintN(64, ret[0]);
|
|
18
|
+
}
|
|
19
|
+
|
|
5
20
|
/**
|
|
6
21
|
* @param {QuoteInput} input
|
|
7
22
|
* @returns {QuoteOutput}
|
|
Binary file
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* tslint:disable */
|
|
2
2
|
/* eslint-disable */
|
|
3
3
|
export const memory: WebAssembly.Memory;
|
|
4
|
+
export const applyTransferFee: (a: bigint, b: number) => [bigint, number, number];
|
|
4
5
|
export const quote: (a: any) => [number, number, number];
|
|
5
6
|
export const __wbindgen_malloc: (a: number, b: number) => number;
|
|
6
7
|
export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
|
@@ -61,12 +61,19 @@ export interface TransferFee {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Applies `fee` to a gross `amount`, returning the net amount — or `amount` unchanged when
|
|
66
|
+
* `fee` is `None` (the mint has no `TransferFeeConfig` extension).
|
|
67
|
+
*/
|
|
68
|
+
export function applyTransferFee(amount: bigint, fee?: TransferFee | null): bigint;
|
|
69
|
+
|
|
64
70
|
export function quote(input: QuoteInput): QuoteOutput;
|
|
65
71
|
|
|
66
72
|
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
|
|
67
73
|
|
|
68
74
|
export interface InitOutput {
|
|
69
75
|
readonly memory: WebAssembly.Memory;
|
|
76
|
+
readonly applyTransferFee: (a: bigint, b: number) => [bigint, number, number];
|
|
70
77
|
readonly quote: (a: any) => [number, number, number];
|
|
71
78
|
readonly __wbindgen_malloc: (a: number, b: number) => number;
|
|
72
79
|
readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
/* @ts-self-types="./picon_dlmm_quote.d.ts" */
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Applies `fee` to a gross `amount`, returning the net amount — or `amount` unchanged when
|
|
5
|
+
* `fee` is `None` (the mint has no `TransferFeeConfig` extension).
|
|
6
|
+
* @param {bigint} amount
|
|
7
|
+
* @param {TransferFee | null} [fee]
|
|
8
|
+
* @returns {bigint}
|
|
9
|
+
*/
|
|
10
|
+
export function applyTransferFee(amount, fee) {
|
|
11
|
+
const ret = wasm.applyTransferFee(amount, isLikeNone(fee) ? 0 : addToExternrefTable0(fee));
|
|
12
|
+
if (ret[2]) {
|
|
13
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
14
|
+
}
|
|
15
|
+
return BigInt.asUintN(64, ret[0]);
|
|
16
|
+
}
|
|
17
|
+
|
|
3
18
|
/**
|
|
4
19
|
* @param {QuoteInput} input
|
|
5
20
|
* @returns {QuoteOutput}
|
|
Binary file
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* tslint:disable */
|
|
2
2
|
/* eslint-disable */
|
|
3
3
|
export const memory: WebAssembly.Memory;
|
|
4
|
+
export const applyTransferFee: (a: bigint, b: number) => [bigint, number, number];
|
|
4
5
|
export const quote: (a: any) => [number, number, number];
|
|
5
6
|
export const __wbindgen_malloc: (a: number, b: number) => number;
|
|
6
7
|
export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|