@zcomb/programs-sdk 1.7.0 → 1.8.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/dist/futarchy/client.d.ts +113 -1
- package/dist/futarchy/client.js +13 -3
- package/dist/futarchy/instructions.d.ts +109 -1
- package/dist/futarchy/instructions.js +17 -3
- package/dist/generated/idls/futarchy.json +112 -0
- package/dist/generated/types/futarchy.d.ts +112 -0
- package/dist/generated/types/futarchy.js +1 -1
- package/package.json +1 -2
- package/src/amm/client.ts +0 -485
- package/src/amm/constants.ts +0 -31
- package/src/amm/index.ts +0 -5
- package/src/amm/instructions.ts +0 -139
- package/src/amm/types.ts +0 -62
- package/src/amm/utils.ts +0 -263
- package/src/futarchy/client.ts +0 -1100
- package/src/futarchy/constants.ts +0 -28
- package/src/futarchy/index.ts +0 -5
- package/src/futarchy/instructions.ts +0 -235
- package/src/futarchy/types.ts +0 -54
- package/src/futarchy/utils.ts +0 -108
- package/src/generated/idls/amm.json +0 -1252
- package/src/generated/idls/futarchy.json +0 -1763
- package/src/generated/idls/index.ts +0 -4
- package/src/generated/idls/svault.json +0 -2228
- package/src/generated/idls/vault.json +0 -1501
- package/src/generated/types/amm.ts +0 -1258
- package/src/generated/types/futarchy.ts +0 -1769
- package/src/generated/types/index.ts +0 -4
- package/src/generated/types/svault.ts +0 -2234
- package/src/generated/types/vault.ts +0 -1507
- package/src/index.ts +0 -163
- package/src/svault/client.ts +0 -401
- package/src/svault/constants.ts +0 -23
- package/src/svault/index.ts +0 -5
- package/src/svault/instructions.ts +0 -258
- package/src/svault/types.ts +0 -45
- package/src/svault/utils.ts +0 -145
- package/src/utils.ts +0 -41
- package/src/vault/client.ts +0 -333
- package/src/vault/constants.ts +0 -23
- package/src/vault/index.ts +0 -5
- package/src/vault/instructions.ts +0 -170
- package/src/vault/types.ts +0 -54
- package/src/vault/utils.ts +0 -70
package/src/amm/types.ts
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Type definitions for the AMM program.
|
|
3
|
-
* Exports IDL-derived types and SDK-friendly enums.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { BN, IdlAccounts, IdlEvents, IdlTypes } from "@coral-xyz/anchor";
|
|
7
|
-
import { TxOptions } from "../utils";
|
|
8
|
-
|
|
9
|
-
/* IDL Type Re-export */
|
|
10
|
-
|
|
11
|
-
export { Amm } from "../generated/types";
|
|
12
|
-
import type { Amm } from "../generated/types";
|
|
13
|
-
|
|
14
|
-
/* IDL-derived Types */
|
|
15
|
-
|
|
16
|
-
export type PoolAccount = IdlAccounts<Amm>["poolAccount"];
|
|
17
|
-
export type PoolStateRaw = IdlTypes<Amm>["poolState"];
|
|
18
|
-
export type TwapOracle = IdlTypes<Amm>["twapOracle"];
|
|
19
|
-
export type PoolBumps = IdlTypes<Amm>["poolBumps"];
|
|
20
|
-
|
|
21
|
-
/* Event Types */
|
|
22
|
-
|
|
23
|
-
export type PoolCreatedEvent = IdlEvents<Amm>["poolCreated"];
|
|
24
|
-
export type LiquidityAddedEvent = IdlEvents<Amm>["liquidityAdded"];
|
|
25
|
-
export type LiquidityRemovedEvent = IdlEvents<Amm>["liquidityRemoved"];
|
|
26
|
-
export type CondSwapEvent = IdlEvents<Amm>["condSwap"];
|
|
27
|
-
export type TWAPUpdateEvent = IdlEvents<Amm>["twapUpdate"];
|
|
28
|
-
|
|
29
|
-
/* Enums */
|
|
30
|
-
|
|
31
|
-
export enum PoolState {
|
|
32
|
-
Trading = "trading",
|
|
33
|
-
Finalized = "finalized",
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/* Quote Types */
|
|
37
|
-
|
|
38
|
-
export interface SwapQuote {
|
|
39
|
-
inputAmount: BN;
|
|
40
|
-
outputAmount: BN;
|
|
41
|
-
minOutputAmount: BN;
|
|
42
|
-
feeAmount: BN;
|
|
43
|
-
priceImpact: number;
|
|
44
|
-
spotPriceBefore: BN;
|
|
45
|
-
spotPriceAfter: BN;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/* Event Union Type */
|
|
49
|
-
|
|
50
|
-
export type AMMEvent =
|
|
51
|
-
| { name: "PoolCreated"; data: PoolCreatedEvent }
|
|
52
|
-
| { name: "LiquidityAdded"; data: LiquidityAddedEvent }
|
|
53
|
-
| { name: "LiquidityRemoved"; data: LiquidityRemovedEvent }
|
|
54
|
-
| { name: "CondSwap"; data: CondSwapEvent }
|
|
55
|
-
| { name: "TWAPUpdate"; data: TWAPUpdateEvent };
|
|
56
|
-
|
|
57
|
-
/* Options */
|
|
58
|
-
|
|
59
|
-
export interface AmmActionOptions extends TxOptions {
|
|
60
|
-
autoWrapUnwrap?: boolean; // Auto wrap/unwrap native SOL (default: true) - for liquidity operations
|
|
61
|
-
autoCreateTokenAccounts?: boolean; // Auto create token accounts (default: true) - for swaps
|
|
62
|
-
}
|
package/src/amm/utils.ts
DELETED
|
@@ -1,263 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Utility functions for the AMM program.
|
|
3
|
-
* PDA derivation, state parsing, price calculations, and account fetching.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { Program, BN } from "@coral-xyz/anchor";
|
|
7
|
-
import { PublicKey } from "@solana/web3.js";
|
|
8
|
-
import { POOL_SEED, RESERVE_SEED, FEE_VAULT_SEED, PROGRAM_ID, PRICE_SCALE } from "./constants";
|
|
9
|
-
import { Amm, PoolState, PoolAccount, TwapOracle, SwapQuote } from "./types";
|
|
10
|
-
|
|
11
|
-
/* PDA Derivation */
|
|
12
|
-
|
|
13
|
-
export function derivePoolPDA(
|
|
14
|
-
admin: PublicKey,
|
|
15
|
-
mintA: PublicKey,
|
|
16
|
-
mintB: PublicKey,
|
|
17
|
-
programId: PublicKey = PROGRAM_ID
|
|
18
|
-
): [PublicKey, number] {
|
|
19
|
-
return PublicKey.findProgramAddressSync(
|
|
20
|
-
[POOL_SEED, admin.toBuffer(), mintA.toBuffer(), mintB.toBuffer()],
|
|
21
|
-
programId
|
|
22
|
-
);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function deriveReservePDA(
|
|
26
|
-
pool: PublicKey,
|
|
27
|
-
mint: PublicKey,
|
|
28
|
-
programId: PublicKey = PROGRAM_ID
|
|
29
|
-
): [PublicKey, number] {
|
|
30
|
-
return PublicKey.findProgramAddressSync(
|
|
31
|
-
[RESERVE_SEED, pool.toBuffer(), mint.toBuffer()],
|
|
32
|
-
programId
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function deriveFeeVaultPDA(
|
|
37
|
-
pool: PublicKey,
|
|
38
|
-
programId: PublicKey = PROGRAM_ID
|
|
39
|
-
): [PublicKey, number] {
|
|
40
|
-
return PublicKey.findProgramAddressSync(
|
|
41
|
-
[FEE_VAULT_SEED, pool.toBuffer()],
|
|
42
|
-
programId
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/* Parsers */
|
|
47
|
-
|
|
48
|
-
export function parsePoolState(state: any): PoolState {
|
|
49
|
-
if ("trading" in state) return PoolState.Trading;
|
|
50
|
-
if ("finalized" in state) return PoolState.Finalized;
|
|
51
|
-
throw new Error("Unknown pool state");
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/* Fetch */
|
|
55
|
-
|
|
56
|
-
export async function fetchPoolAccount(
|
|
57
|
-
program: Program<Amm>,
|
|
58
|
-
poolPda: PublicKey
|
|
59
|
-
): Promise<PoolAccount> {
|
|
60
|
-
return program.account.poolAccount.fetch(poolPda);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/* Math Utilities */
|
|
64
|
-
|
|
65
|
-
const PRICE_SCALE_BN = new BN(PRICE_SCALE.toString());
|
|
66
|
-
|
|
67
|
-
export function calculateSpotPrice(
|
|
68
|
-
reserveA: BN,
|
|
69
|
-
reserveB: BN,
|
|
70
|
-
decimalsA: number,
|
|
71
|
-
decimalsB: number,
|
|
72
|
-
): BN {
|
|
73
|
-
if (reserveB.isZero()) return new BN(0);
|
|
74
|
-
|
|
75
|
-
const decimalDiff = decimalsB - decimalsA;
|
|
76
|
-
|
|
77
|
-
if (decimalDiff >= 0) {
|
|
78
|
-
const multiplier = new BN(10).pow(new BN(decimalDiff));
|
|
79
|
-
return reserveA.mul(multiplier).mul(PRICE_SCALE_BN).div(reserveB);
|
|
80
|
-
} else {
|
|
81
|
-
const divisor = new BN(10).pow(new BN(-decimalDiff));
|
|
82
|
-
return reserveA.mul(PRICE_SCALE_BN).div(reserveB).div(divisor);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Compute swap output using constant product formula.
|
|
88
|
-
* Fee is ALWAYS collected in token A:
|
|
89
|
-
* - A -> B: fee on input (before swap)
|
|
90
|
-
* - B -> A: fee on output (after swap)
|
|
91
|
-
*/
|
|
92
|
-
export function computeSwapOutput(
|
|
93
|
-
inputAmount: BN | number,
|
|
94
|
-
reserveIn: BN,
|
|
95
|
-
reserveOut: BN,
|
|
96
|
-
feeBps: number,
|
|
97
|
-
swapAToB: boolean
|
|
98
|
-
): { outputAmount: BN; feeAmount: BN } {
|
|
99
|
-
const input = typeof inputAmount === "number" ? new BN(inputAmount) : inputAmount;
|
|
100
|
-
|
|
101
|
-
if (reserveIn.isZero() || reserveOut.isZero()) {
|
|
102
|
-
return { outputAmount: new BN(0), feeAmount: new BN(0) };
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
if (swapAToB) {
|
|
106
|
-
// A -> B: fee on input (token A)
|
|
107
|
-
const feeAmount = input.mul(new BN(feeBps)).div(new BN(10000));
|
|
108
|
-
const inputAfterFee = input.sub(feeAmount);
|
|
109
|
-
|
|
110
|
-
// Constant product: output = reserveOut * inputAfterFee / (reserveIn + inputAfterFee)
|
|
111
|
-
const numerator = reserveOut.mul(inputAfterFee);
|
|
112
|
-
const denominator = reserveIn.add(inputAfterFee);
|
|
113
|
-
const outputAmount = numerator.div(denominator);
|
|
114
|
-
|
|
115
|
-
return { outputAmount, feeAmount };
|
|
116
|
-
} else {
|
|
117
|
-
// B -> A: fee on output (token A)
|
|
118
|
-
// First compute gross output without fee
|
|
119
|
-
const numerator = reserveOut.mul(input);
|
|
120
|
-
const denominator = reserveIn.add(input);
|
|
121
|
-
const grossOutput = numerator.div(denominator);
|
|
122
|
-
|
|
123
|
-
// Then deduct fee from output
|
|
124
|
-
const feeAmount = grossOutput.mul(new BN(feeBps)).div(new BN(10000));
|
|
125
|
-
const outputAmount = grossOutput.sub(feeAmount);
|
|
126
|
-
|
|
127
|
-
return { outputAmount, feeAmount };
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Compute swap input needed to get a specific output.
|
|
133
|
-
* Fee is ALWAYS collected in token A:
|
|
134
|
-
* - A -> B: fee on input
|
|
135
|
-
* - B -> A: fee on output
|
|
136
|
-
*/
|
|
137
|
-
export function computeSwapInput(
|
|
138
|
-
outputAmount: BN | number,
|
|
139
|
-
reserveIn: BN,
|
|
140
|
-
reserveOut: BN,
|
|
141
|
-
feeBps: number,
|
|
142
|
-
swapAToB: boolean
|
|
143
|
-
): { inputAmount: BN; feeAmount: BN } {
|
|
144
|
-
const output = typeof outputAmount === "number" ? new BN(outputAmount) : outputAmount;
|
|
145
|
-
|
|
146
|
-
if (reserveIn.isZero() || reserveOut.isZero() || output.gte(reserveOut)) {
|
|
147
|
-
return { inputAmount: new BN(0), feeAmount: new BN(0) };
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
if (swapAToB) {
|
|
151
|
-
// A -> B: fee on input
|
|
152
|
-
// We need: output = (reserveOut * inputAfterFee) / (reserveIn + inputAfterFee)
|
|
153
|
-
// Solve for inputAfterFee: inputAfterFee = (reserveIn * output) / (reserveOut - output)
|
|
154
|
-
const numerator = reserveIn.mul(output);
|
|
155
|
-
const denominator = reserveOut.sub(output);
|
|
156
|
-
const inputAfterFee = numerator.div(denominator).add(new BN(1)); // Round up
|
|
157
|
-
|
|
158
|
-
// inputAmount = inputAfterFee * 10000 / (10000 - feeBps)
|
|
159
|
-
const inputAmount = inputAfterFee.mul(new BN(10000)).div(new BN(10000 - feeBps)).add(new BN(1));
|
|
160
|
-
const feeAmount = inputAmount.sub(inputAfterFee);
|
|
161
|
-
|
|
162
|
-
return { inputAmount, feeAmount };
|
|
163
|
-
} else {
|
|
164
|
-
// B -> A: fee on output
|
|
165
|
-
// User wants `output` after fee, so grossOutput = output * 10000 / (10000 - feeBps)
|
|
166
|
-
const grossOutput = output.mul(new BN(10000)).div(new BN(10000 - feeBps)).add(new BN(1));
|
|
167
|
-
const feeAmount = grossOutput.sub(output);
|
|
168
|
-
|
|
169
|
-
// Now compute input needed for grossOutput
|
|
170
|
-
// grossOutput = (reserveOut * input) / (reserveIn + input)
|
|
171
|
-
// input = (reserveIn * grossOutput) / (reserveOut - grossOutput)
|
|
172
|
-
const numerator = reserveIn.mul(grossOutput);
|
|
173
|
-
const denominator = reserveOut.sub(grossOutput);
|
|
174
|
-
|
|
175
|
-
if (denominator.lte(new BN(0))) {
|
|
176
|
-
return { inputAmount: new BN(0), feeAmount: new BN(0) };
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
const inputAmount = numerator.div(denominator).add(new BN(1)); // Round up
|
|
180
|
-
|
|
181
|
-
return { inputAmount, feeAmount };
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
export function calculatePriceImpact(
|
|
186
|
-
inputAmount: BN,
|
|
187
|
-
outputAmount: BN,
|
|
188
|
-
reserveIn: BN,
|
|
189
|
-
reserveOut: BN,
|
|
190
|
-
decimalsIn: number,
|
|
191
|
-
decimalsOut: number,
|
|
192
|
-
): number {
|
|
193
|
-
if (reserveIn.isZero() || reserveOut.isZero() || inputAmount.isZero()) {
|
|
194
|
-
return 0;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
const spotPrice = calculateSpotPrice(reserveIn, reserveOut, decimalsIn, decimalsOut);
|
|
198
|
-
const executionPrice = calculateSpotPrice(inputAmount, outputAmount, decimalsIn, decimalsOut);
|
|
199
|
-
|
|
200
|
-
if (spotPrice.isZero()) return 0;
|
|
201
|
-
|
|
202
|
-
const impact = executionPrice.sub(spotPrice).mul(new BN(10000)).div(spotPrice);
|
|
203
|
-
return Math.abs(impact.toNumber()) / 100;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
export function createSwapQuote(
|
|
207
|
-
inputAmount: BN | number,
|
|
208
|
-
reserveIn: BN,
|
|
209
|
-
reserveOut: BN,
|
|
210
|
-
feeBps: number,
|
|
211
|
-
decimalsIn: number,
|
|
212
|
-
decimalsOut: number,
|
|
213
|
-
swapAToB: boolean,
|
|
214
|
-
slippagePercent: number = 0.5,
|
|
215
|
-
): SwapQuote {
|
|
216
|
-
const input = typeof inputAmount === "number" ? new BN(inputAmount) : inputAmount;
|
|
217
|
-
|
|
218
|
-
const { outputAmount, feeAmount } = computeSwapOutput(input, reserveIn, reserveOut, feeBps, swapAToB);
|
|
219
|
-
|
|
220
|
-
const slippageBps = Math.floor(slippagePercent * 100);
|
|
221
|
-
const minOutputAmount = outputAmount.mul(new BN(10000 - slippageBps)).div(new BN(10000));
|
|
222
|
-
|
|
223
|
-
const spotPriceBefore = calculateSpotPrice(reserveIn, reserveOut, decimalsIn, decimalsOut);
|
|
224
|
-
const newReserveIn = reserveIn.add(input);
|
|
225
|
-
const newReserveOut = reserveOut.sub(outputAmount);
|
|
226
|
-
const spotPriceAfter = calculateSpotPrice(newReserveIn, newReserveOut, decimalsIn, decimalsOut);
|
|
227
|
-
|
|
228
|
-
const priceImpact = calculatePriceImpact(input, outputAmount, reserveIn, reserveOut, decimalsIn, decimalsOut);
|
|
229
|
-
|
|
230
|
-
return {
|
|
231
|
-
inputAmount: input,
|
|
232
|
-
outputAmount,
|
|
233
|
-
minOutputAmount,
|
|
234
|
-
feeAmount,
|
|
235
|
-
priceImpact,
|
|
236
|
-
spotPriceBefore,
|
|
237
|
-
spotPriceAfter,
|
|
238
|
-
};
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
/* TWAP Utilities */
|
|
242
|
-
|
|
243
|
-
export function calculateTwap(oracle: TwapOracle): BN | null {
|
|
244
|
-
const warmupEnd = oracle.createdAtUnixTime.add(new BN(oracle.warmupDuration));
|
|
245
|
-
|
|
246
|
-
if (oracle.lastUpdateUnixTime.lte(warmupEnd)) {
|
|
247
|
-
return oracle.startingObservation;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
const elapsed = oracle.lastUpdateUnixTime.sub(warmupEnd);
|
|
251
|
-
|
|
252
|
-
if (elapsed.isZero() || oracle.cumulativeObservations.isZero()) {
|
|
253
|
-
return null;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
return oracle.cumulativeObservations.div(elapsed);
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
export function isOracleInWarmup(oracle: TwapOracle, currentTime?: BN): boolean {
|
|
260
|
-
const now = currentTime ?? new BN(Math.floor(Date.now() / 1000));
|
|
261
|
-
const warmupEnd = oracle.createdAtUnixTime.add(new BN(oracle.warmupDuration));
|
|
262
|
-
return now.lt(warmupEnd);
|
|
263
|
-
}
|