@logswap/sdk 0.5.35
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 +130 -0
- package/dist/actions.d.ts +136 -0
- package/dist/actions.js +140 -0
- package/dist/admin.d.ts +11 -0
- package/dist/admin.js +29 -0
- package/dist/claims.d.ts +53 -0
- package/dist/claims.js +98 -0
- package/dist/client.d.ts +68 -0
- package/dist/client.js +68 -0
- package/dist/fpool.d.ts +416 -0
- package/dist/fpool.js +653 -0
- package/dist/generated.d.ts +6522 -0
- package/dist/generated.js +3755 -0
- package/dist/ids.d.ts +42 -0
- package/dist/ids.js +72 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +23 -0
- package/dist/indexer.d.ts +91 -0
- package/dist/indexer.js +197 -0
- package/dist/keys.d.ts +40 -0
- package/dist/keys.js +50 -0
- package/dist/liquidity.d.ts +223 -0
- package/dist/liquidity.js +305 -0
- package/dist/onboard.d.ts +56 -0
- package/dist/onboard.js +188 -0
- package/dist/pools.d.ts +182 -0
- package/dist/pools.js +322 -0
- package/dist/positions.d.ts +164 -0
- package/dist/positions.js +197 -0
- package/dist/swap.d.ts +68 -0
- package/dist/swap.js +91 -0
- package/dist/tokencache.d.ts +76 -0
- package/dist/tokencache.js +150 -0
- package/dist/write.d.ts +86 -0
- package/dist/write.js +106 -0
- package/package.json +48 -0
- package/src/actions.ts +207 -0
- package/src/admin.ts +33 -0
- package/src/claims.ts +132 -0
- package/src/client.ts +104 -0
- package/src/fpool.ts +935 -0
- package/src/generated.ts +3762 -0
- package/src/ids.ts +78 -0
- package/src/index.ts +23 -0
- package/src/indexer.ts +252 -0
- package/src/keys.ts +73 -0
- package/src/liquidity.ts +430 -0
- package/src/onboard.ts +228 -0
- package/src/pools.ts +396 -0
- package/src/positions.ts +276 -0
- package/src/swap.ts +140 -0
- package/src/tokencache.ts +169 -0
- package/src/write.ts +134 -0
package/dist/onboard.js
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* onboard.ts — getting a wallet to the point where router writes actually work.
|
|
3
|
+
*
|
|
4
|
+
* There are **three separate approvals** with three separate failure modes, and a UI that surfaces
|
|
5
|
+
* them late produces failed transactions instead of prompts:
|
|
6
|
+
*
|
|
7
|
+
* 1. ERC-20 → Permit2 once per token, forever. Only when the router is Permit2-wired.
|
|
8
|
+
* 2. Permit2 → router a standing allowance, by transaction or by signature.
|
|
9
|
+
* 3. 6909 operator grant once per wallet, covers every market. Needed by burn/update/move.
|
|
10
|
+
*
|
|
11
|
+
* **The trap this module exists for:** when the router is deployed with Permit2, approving the
|
|
12
|
+
* ERC-20 to the *router* is not enough and not used — the pull goes through Permit2, and the
|
|
13
|
+
* failure is `NotAllowed()` from Permit2 rather than anything naming an allowance. Approving the
|
|
14
|
+
* router directly looks correct and does nothing.
|
|
15
|
+
*/
|
|
16
|
+
import { parseAbi, zeroAddress } from "viem";
|
|
17
|
+
import { requireWallet } from "./write.js";
|
|
18
|
+
export const MAX_UINT256 = (1n << 256n) - 1n;
|
|
19
|
+
export const MAX_UINT160 = (1n << 160n) - 1n;
|
|
20
|
+
export const MAX_UINT48 = (1n << 48n) - 1n;
|
|
21
|
+
const ERC20 = parseAbi([
|
|
22
|
+
"function approve(address spender, uint256 amount) returns (bool)",
|
|
23
|
+
"function allowance(address owner, address spender) view returns (uint256)",
|
|
24
|
+
]);
|
|
25
|
+
const PERMIT2 = parseAbi([
|
|
26
|
+
"function approve(address token, address spender, uint160 amount, uint48 expiration)",
|
|
27
|
+
"function allowance(address owner, address token, address spender) view returns (uint160 amount, uint48 expiration, uint48 nonce)",
|
|
28
|
+
"function transferFrom(address from, address to, uint160 amount, address token)",
|
|
29
|
+
]);
|
|
30
|
+
/** Is this deployment's router wired to Permit2? Decides which approval path applies. */
|
|
31
|
+
export function usesPermit2(c) {
|
|
32
|
+
return !!c.addresses.permit2 && c.addresses.permit2 !== zeroAddress;
|
|
33
|
+
}
|
|
34
|
+
/** The contract that will actually pull tokens: Permit2 when wired, otherwise the router. */
|
|
35
|
+
export function spenderFor(c) {
|
|
36
|
+
return usesPermit2(c) ? c.addresses.permit2 : c.addresses.router;
|
|
37
|
+
}
|
|
38
|
+
/** Step 1 — approve the *puller* on an ERC-20. Once per token. */
|
|
39
|
+
export async function approveToken(c, token, amount = MAX_UINT256) {
|
|
40
|
+
const { account } = requireWallet(c);
|
|
41
|
+
return c.wallet.writeContract({
|
|
42
|
+
address: token,
|
|
43
|
+
abi: ERC20,
|
|
44
|
+
functionName: "approve",
|
|
45
|
+
args: [spenderFor(c), amount],
|
|
46
|
+
account,
|
|
47
|
+
chain: c.wallet.chain,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Step 2 — the standing Permit2 allowance for the router.
|
|
52
|
+
*
|
|
53
|
+
* No-op when the deployment has no Permit2. Prefer the signature flow (`applyPermit2` on the
|
|
54
|
+
* router, bundled through `multicall`) in production; this transaction form is what a test or a
|
|
55
|
+
* simple UI wants.
|
|
56
|
+
*/
|
|
57
|
+
export async function approvePermit2ForRouter(c, token, amount = MAX_UINT160, expiration = MAX_UINT48) {
|
|
58
|
+
if (!usesPermit2(c))
|
|
59
|
+
return null;
|
|
60
|
+
const { account } = requireWallet(c);
|
|
61
|
+
return c.wallet.writeContract({
|
|
62
|
+
address: c.addresses.permit2,
|
|
63
|
+
abi: PERMIT2,
|
|
64
|
+
functionName: "approve",
|
|
65
|
+
args: [token, c.addresses.router, amount, Number(expiration)],
|
|
66
|
+
account,
|
|
67
|
+
chain: c.wallet.chain,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Both token-side steps in order, skipping any already satisfied.
|
|
72
|
+
*
|
|
73
|
+
* Returns the hashes actually sent, so a UI can report "2 approvals" honestly rather than always
|
|
74
|
+
* prompting twice.
|
|
75
|
+
*/
|
|
76
|
+
export async function onboardToken(c, token, need) {
|
|
77
|
+
// The address, not the account object: these two are READS. Signing paths take the object.
|
|
78
|
+
const { address } = requireWallet(c);
|
|
79
|
+
const sent = [];
|
|
80
|
+
const allowance = (await c.public.readContract({
|
|
81
|
+
address: token,
|
|
82
|
+
abi: ERC20,
|
|
83
|
+
functionName: "allowance",
|
|
84
|
+
args: [address, spenderFor(c)],
|
|
85
|
+
}));
|
|
86
|
+
if (allowance < need) {
|
|
87
|
+
const h = await approveToken(c, token);
|
|
88
|
+
await c.public.waitForTransactionReceipt({ hash: h });
|
|
89
|
+
sent.push(h);
|
|
90
|
+
}
|
|
91
|
+
if (usesPermit2(c)) {
|
|
92
|
+
const [amt] = (await c.public.readContract({
|
|
93
|
+
address: c.addresses.permit2,
|
|
94
|
+
abi: PERMIT2,
|
|
95
|
+
functionName: "allowance",
|
|
96
|
+
args: [address, token, c.addresses.router],
|
|
97
|
+
}));
|
|
98
|
+
if (amt < need) {
|
|
99
|
+
const h = await approvePermit2ForRouter(c, token);
|
|
100
|
+
if (h) {
|
|
101
|
+
await c.public.waitForTransactionReceipt({ hash: h });
|
|
102
|
+
sent.push(h);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return sent;
|
|
107
|
+
}
|
|
108
|
+
export async function checkTokenReadiness(c, token, owner, need) {
|
|
109
|
+
const allowance = (await c.public.readContract({
|
|
110
|
+
address: token,
|
|
111
|
+
abi: ERC20,
|
|
112
|
+
functionName: "allowance",
|
|
113
|
+
args: [owner, spenderFor(c)],
|
|
114
|
+
}));
|
|
115
|
+
let needsPermit2Approval = false;
|
|
116
|
+
if (usesPermit2(c)) {
|
|
117
|
+
const [amt] = (await c.public.readContract({
|
|
118
|
+
address: c.addresses.permit2,
|
|
119
|
+
abi: PERMIT2,
|
|
120
|
+
functionName: "allowance",
|
|
121
|
+
args: [owner, token, c.addresses.router],
|
|
122
|
+
}));
|
|
123
|
+
needsPermit2Approval = amt < need;
|
|
124
|
+
}
|
|
125
|
+
return { usesPermit2: usesPermit2(c), needsTokenApproval: allowance < need, needsPermit2Approval };
|
|
126
|
+
}
|
|
127
|
+
// ─── the signature path: allowances that ride inside the action's own transaction ─────────────
|
|
128
|
+
//
|
|
129
|
+
// The rationalized flow. A token's ONLY unavoidable transaction is its one-time ERC-20 approval
|
|
130
|
+
// to Permit2; the Permit2→router allowance is set by an EIP-712 SIGNATURE (free, instant, no
|
|
131
|
+
// gas) submitted as an `applyPermit2` call INSIDE the same multicall as the action. Minting on a
|
|
132
|
+
// fresh token is then one transaction, not three — the pattern the router's `applyPermit2` +
|
|
133
|
+
// `multicall` were built for, and the one canonical Permit2 UX uses.
|
|
134
|
+
const PERMIT2_TYPES = {
|
|
135
|
+
PermitDetails: [
|
|
136
|
+
{ name: "token", type: "address" },
|
|
137
|
+
{ name: "amount", type: "uint160" },
|
|
138
|
+
{ name: "expiration", type: "uint48" },
|
|
139
|
+
{ name: "nonce", type: "uint48" },
|
|
140
|
+
],
|
|
141
|
+
PermitSingle: [
|
|
142
|
+
{ name: "details", type: "PermitDetails" },
|
|
143
|
+
{ name: "spender", type: "address" },
|
|
144
|
+
{ name: "sigDeadline", type: "uint256" },
|
|
145
|
+
],
|
|
146
|
+
};
|
|
147
|
+
/**
|
|
148
|
+
* For each token whose Permit2→router allowance is missing: read the nonce, have the wallet SIGN
|
|
149
|
+
* a PermitSingle (a signature prompt, not a transaction), and return the encoded `applyPermit2`
|
|
150
|
+
* calls ready to ride in a router multicall. Tokens already allowed produce nothing.
|
|
151
|
+
*/
|
|
152
|
+
export async function permit2SigCalls(c, tokens) {
|
|
153
|
+
if (!usesPermit2(c))
|
|
154
|
+
return [];
|
|
155
|
+
const { account, address: owner } = requireWallet(c);
|
|
156
|
+
const chainId = await c.public.getChainId();
|
|
157
|
+
const calls = [];
|
|
158
|
+
for (const token of [...new Set(tokens.map((t) => t.toLowerCase()))]) {
|
|
159
|
+
const [amt, , nonce] = (await c.public.readContract({
|
|
160
|
+
address: c.addresses.permit2,
|
|
161
|
+
abi: PERMIT2,
|
|
162
|
+
functionName: "allowance",
|
|
163
|
+
args: [owner, token, c.addresses.router],
|
|
164
|
+
}));
|
|
165
|
+
if (amt >= 1n << 120n)
|
|
166
|
+
continue; // effectively infinite already
|
|
167
|
+
const message = {
|
|
168
|
+
details: { token, amount: MAX_UINT160, expiration: Number(MAX_UINT48), nonce },
|
|
169
|
+
spender: c.addresses.router,
|
|
170
|
+
sigDeadline: BigInt(Math.floor(Date.now() / 1000)) + 1800n,
|
|
171
|
+
};
|
|
172
|
+
const signature = await c.wallet.signTypedData({
|
|
173
|
+
account,
|
|
174
|
+
domain: { name: "Permit2", chainId, verifyingContract: c.addresses.permit2 },
|
|
175
|
+
types: PERMIT2_TYPES,
|
|
176
|
+
primaryType: "PermitSingle",
|
|
177
|
+
message,
|
|
178
|
+
});
|
|
179
|
+
const { encodeFunctionData } = await import("viem");
|
|
180
|
+
const { logswapRouterAbi } = await import("./generated.js");
|
|
181
|
+
calls.push(encodeFunctionData({
|
|
182
|
+
abi: logswapRouterAbi,
|
|
183
|
+
functionName: "applyPermit2",
|
|
184
|
+
args: [owner, message, signature],
|
|
185
|
+
}));
|
|
186
|
+
}
|
|
187
|
+
return calls;
|
|
188
|
+
}
|
package/dist/pools.d.ts
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pools.ts — market state and discovery.
|
|
3
|
+
*
|
|
4
|
+
* Two things worth knowing before reading further.
|
|
5
|
+
*
|
|
6
|
+
* **Markets are discovered from logs, not configuration.** `Initialize` carries the ENTIRE
|
|
7
|
+
* `PoolKey` in the clear, so a client can reconstruct any market's key — and therefore call any
|
|
8
|
+
* keyed function — having never been told the market exists. There is no registry to maintain.
|
|
9
|
+
*
|
|
10
|
+
* **`x` is the state, price is derived.** The contract stores $x = \log p$ and materialises the
|
|
11
|
+
* price only where unavoidable; `priceOf` below mirrors that, and is lossy in the way any float
|
|
12
|
+
* conversion is. Prefer comparing in log space when precision matters.
|
|
13
|
+
*/
|
|
14
|
+
import { type Address, type Hex } from "viem";
|
|
15
|
+
import type { LogswapClient } from "./client.js";
|
|
16
|
+
import { type PoolKey } from "./keys.js";
|
|
17
|
+
/** The manager's `getPool` view, decoded. Field-for-field with `PoolView` in the contract. */
|
|
18
|
+
export interface PoolState {
|
|
19
|
+
initialized: boolean;
|
|
20
|
+
backstopSeeded: boolean;
|
|
21
|
+
/** $x = \log p$, WAD — the stored state. */
|
|
22
|
+
x: bigint;
|
|
23
|
+
/** Exposure currently earning. Steps only when a floor or cap is crossed. */
|
|
24
|
+
lActive: bigint;
|
|
25
|
+
reserveBase: bigint;
|
|
26
|
+
reserveQuote: bigint;
|
|
27
|
+
/** Fee-per-unit-L accumulator: $\phi \cdot \mathrm{TV}(\log p)$. */
|
|
28
|
+
F: bigint;
|
|
29
|
+
/** Quadratic variation of log-price, $\Sigma = \int (dx)^2$. */
|
|
30
|
+
bigSigma: bigint;
|
|
31
|
+
sigma2Ema: bigint;
|
|
32
|
+
currentK: bigint;
|
|
33
|
+
protocolOwed: bigint;
|
|
34
|
+
minBackstopL: bigint;
|
|
35
|
+
backstopFloor: bigint;
|
|
36
|
+
}
|
|
37
|
+
/** Read a market's full state by key. */
|
|
38
|
+
export declare function getPool(c: LogswapClient, key: PoolKey): Promise<PoolState>;
|
|
39
|
+
/** The effective fee right now: $\max(\phi_{\min}, \kappa\sqrt{\sigma^2_{\text{ema}}})$, capped. */
|
|
40
|
+
export declare function phiEff(c: LogswapClient, key: PoolKey): Promise<bigint>;
|
|
41
|
+
/**
|
|
42
|
+
* Price from the stored log-price. **Lossy** — `x` is exact and this is a float, so use it for
|
|
43
|
+
* display and never for arithmetic you intend to send back on-chain.
|
|
44
|
+
*/
|
|
45
|
+
export declare function priceOf(state: Pick<PoolState, "x">, scale?: number): number;
|
|
46
|
+
/**
|
|
47
|
+
* The factor between the chain's price and the human one. The chain's log-price is of the WEI
|
|
48
|
+
* ratio, so with a 6-dec USDC quote and an 18-dec base the human price is `e^x · 10^12`. Pass
|
|
49
|
+
* this as `scale` to {@link priceOf}, {@link floorPrice} and `fPoolPriceOf` — with 18/18 tokens
|
|
50
|
+
* it is 1 and nothing changes.
|
|
51
|
+
*/
|
|
52
|
+
export declare function priceScale(baseDecimals: number, quoteDecimals: number): number;
|
|
53
|
+
/**
|
|
54
|
+
* The model-free LP edge, $F - \tfrac12\Sigma$ — the protocol's headline metric, in quote per unit
|
|
55
|
+
* of exposure.
|
|
56
|
+
*
|
|
57
|
+
* $F$ is fee income per unit active $L$; $\Sigma$ is the realised quadratic variation, whose half
|
|
58
|
+
* is the LVR a log pool pays. The difference is what an LP actually earns, with no model of the
|
|
59
|
+
* price process assumed. Both ride on every `Swap` event, so this is reconstructible from logs
|
|
60
|
+
* alone (docs/app.md) — no state read needed if you are already indexing.
|
|
61
|
+
*
|
|
62
|
+
* Signed: negative means variation has outrun fee income over the pool's life.
|
|
63
|
+
*/
|
|
64
|
+
export declare function lpEdge(state: Pick<PoolState, "F" | "bigSigma">): bigint;
|
|
65
|
+
/** A market discovered from an `Initialize` log — the full key, plus where it was created. */
|
|
66
|
+
export interface DiscoveredMarket {
|
|
67
|
+
key: PoolKey;
|
|
68
|
+
poolId: Hex;
|
|
69
|
+
/** The market's opening log-price. */
|
|
70
|
+
x0: bigint;
|
|
71
|
+
blockNumber: bigint;
|
|
72
|
+
transactionHash: Hex;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Enumerate markets from `Initialize` logs.
|
|
76
|
+
*
|
|
77
|
+
* This is the whole market registry: the event carries every key field rather than just the id,
|
|
78
|
+
* deliberately, so nothing downstream needs a configured list. Pass `fromBlock` as the manager's
|
|
79
|
+
* deployment block — scanning from genesis is slow and pointless.
|
|
80
|
+
*/
|
|
81
|
+
export declare function discoverMarkets(c: LogswapClient, opts?: {
|
|
82
|
+
fromBlock?: bigint;
|
|
83
|
+
toBlock?: bigint;
|
|
84
|
+
base?: Address;
|
|
85
|
+
quote?: Address;
|
|
86
|
+
}): Promise<DiscoveredMarket[]>;
|
|
87
|
+
/**
|
|
88
|
+
* Ladder shape: the live FLOORS, in log-price WAD — **not** tick indices.
|
|
89
|
+
*
|
|
90
|
+
* Named `liveFloors` deliberately. The lens function it wraps is called `liveTicks`, which reads as
|
|
91
|
+
* if it returns `k`; it returns `k * tickSpacing`. Multiplying by the spacing again yields an
|
|
92
|
+
* off-grid value and an `OffGrid` revert at the next call, which is a confusing place to discover
|
|
93
|
+
* the mistake.
|
|
94
|
+
*/
|
|
95
|
+
export declare function liveFloors(c: LogswapClient, key: PoolKey): Promise<readonly bigint[]>;
|
|
96
|
+
/** Is this floor on the market's grid, and inside `MAX_ABS_FLOOR`? Pure — no RPC on the manager. */
|
|
97
|
+
export declare function isValidFloor(c: LogswapClient, key: PoolKey, floor: bigint): Promise<boolean>;
|
|
98
|
+
/**
|
|
99
|
+
* A market's token decimals, read from the tokens themselves.
|
|
100
|
+
*
|
|
101
|
+
* **Never assume these.** A market's two tokens routinely differ (USDC 6 against WETH 18), the
|
|
102
|
+
* manager itself probes `decimals()` to scale `minBackstopL`, and a token that does not implement
|
|
103
|
+
* it falls back to 18. Hardcoding a guess makes every parse and every display wrong by orders of
|
|
104
|
+
* magnitude while the contract behaves perfectly — which reads as "the app is broken".
|
|
105
|
+
*/
|
|
106
|
+
export declare function marketDecimals(c: LogswapClient, key: PoolKey): Promise<{
|
|
107
|
+
base: number;
|
|
108
|
+
quote: number;
|
|
109
|
+
}>;
|
|
110
|
+
/** A token as a UI needs it: address, symbol and decimals, all read from the chain. */
|
|
111
|
+
export interface TokenInfo {
|
|
112
|
+
address: Address;
|
|
113
|
+
symbol: string;
|
|
114
|
+
decimals: number;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Both sides of a market, for labelling and scaling.
|
|
118
|
+
*
|
|
119
|
+
* **Decimals are read from the token and never guessed.** They used to fall back to 18 on any
|
|
120
|
+
* failure, which quietly reintroduced the worst bug this stack has had: an 18 assumed for a
|
|
121
|
+
* 6-decimal token is a 10^12 error in a number that goes on to `parseUnits` and becomes a transfer
|
|
122
|
+
* amount. A wrong scale is indistinguishable from a working app until somebody moves funds, so a
|
|
123
|
+
* read that will not resolve must fail loudly instead.
|
|
124
|
+
*
|
|
125
|
+
* `symbol` keeps a fallback because it is a label: a market shown as `0x5FbD…` is ugly, not wrong.
|
|
126
|
+
*
|
|
127
|
+
* Retries first, because a blip on the transport is not the same as a token that has no `decimals`,
|
|
128
|
+
* and killing a market over one dropped packet is its own kind of wrong.
|
|
129
|
+
*
|
|
130
|
+
* **Cached** per (chain, address) — see `tokencache.ts` for why only successes are stored and why
|
|
131
|
+
* the chain id is part of the key. Concurrent calls for the same token share one read, which
|
|
132
|
+
* matters because the quote asset is usually the same across every market in a deployment.
|
|
133
|
+
*/
|
|
134
|
+
export declare function marketTokens(c: LogswapClient, key: PoolKey): Promise<{
|
|
135
|
+
base: TokenInfo;
|
|
136
|
+
quote: TokenInfo;
|
|
137
|
+
}>;
|
|
138
|
+
/** Format a quote-denominated amount for display, given the quote's decimals. */
|
|
139
|
+
export declare function formatQuote(amount: bigint, quoteDecimals: number): string;
|
|
140
|
+
/** Fees the pool has accrued over its life, in QUOTE units: $F \cdot L$. */
|
|
141
|
+
export declare function feesQuote(state: Pick<PoolState, "F" | "lActive">): bigint;
|
|
142
|
+
/** The LP edge in QUOTE units: $(F - \tfrac12\Sigma) \cdot L$. Signed. */
|
|
143
|
+
export declare function edgeQuote(state: Pick<PoolState, "F" | "bigSigma" | "lActive">): bigint;
|
|
144
|
+
/** The pool floor as a price. **Lossy** — display only, like {@link priceOf}. */
|
|
145
|
+
export declare function floorPrice(state: Pick<PoolState, "backstopFloor">, scale?: number): number;
|
|
146
|
+
/** $\log(p / p_{\text{floor}}) = x - \xi$ — how far spot sits above the floor, in log units (WAD). */
|
|
147
|
+
export declare function floorDistance(state: Pick<PoolState, "x" | "backstopFloor">): bigint;
|
|
148
|
+
/**
|
|
149
|
+
* $-\log(p/p_{\text{floor}})$ as a fraction: the log-drawdown from spot down to the floor.
|
|
150
|
+
*
|
|
151
|
+
* **Negative** while price is above the floor — it is how far price has to fall, so a UI can print
|
|
152
|
+
* it with its sign and mean it. Zero at the floor.
|
|
153
|
+
*
|
|
154
|
+
* This is the LOG measure, not the arithmetic one: the actual price drawdown is
|
|
155
|
+
* $e^{-\Delta} - 1$, which differs materially once the distance is large (a log distance of 0.7
|
|
156
|
+
* is a 50% price fall, not 70%).
|
|
157
|
+
*/
|
|
158
|
+
export declare function floorDrawdown(state: Pick<PoolState, "x" | "backstopFloor">): number;
|
|
159
|
+
/** The arithmetic price drawdown to the floor, $p_{\text{floor}}/p - 1$. Negative above the floor. */
|
|
160
|
+
export declare function floorDrawdownPrice(state: Pick<PoolState, "x" | "backstopFloor">): number;
|
|
161
|
+
/**
|
|
162
|
+
* Annualise a per-unit-L WAD rate over the window it accrued in.
|
|
163
|
+
*
|
|
164
|
+
* `F` is cumulative fee income per unit of exposure since the pool opened, so dividing by the
|
|
165
|
+
* elapsed time and scaling to a year gives a rate directly — no price process assumed. Returns a
|
|
166
|
+
* fraction: 0.12 is 12%.
|
|
167
|
+
*
|
|
168
|
+
* Treat it as what it is: a *realised* rate over one short devnet window, not a forecast.
|
|
169
|
+
*/
|
|
170
|
+
export declare function annualise(perUnitL: bigint, elapsedSeconds: bigint): number;
|
|
171
|
+
/** When a market was created, as a unix timestamp — the denominator for {@link annualise}. */
|
|
172
|
+
export declare function marketOpenedAt(c: LogswapClient, m: DiscoveredMarket): Promise<bigint>;
|
|
173
|
+
/**
|
|
174
|
+
* Create a C market: `initialize(key, x0)` on the manager — a call, not a deployment. Manager-
|
|
175
|
+
* direct by design: creation moves no funds, so the router adds nothing. The pool id is
|
|
176
|
+
* `poolId(key)` (pure) and the market is tradeable immediately; the first mint funds it.
|
|
177
|
+
*/
|
|
178
|
+
export declare function initializeMarket(c: LogswapClient, a: {
|
|
179
|
+
key: PoolKey;
|
|
180
|
+
x0: bigint;
|
|
181
|
+
account: Address;
|
|
182
|
+
}): Promise<`0x${string}`>;
|