@nradko/metric-omm-sdk-v1 0.3.0 → 0.4.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/README.md +98 -111
- package/dist/abis/MetricOmmPool.d.ts +14 -0
- package/dist/abis/MetricOmmPool.d.ts.map +1 -1
- package/dist/abis/MetricOmmPool.js +18 -0
- package/dist/abis/MetricOmmPool.js.map +1 -1
- package/dist/abis/MetricOmmPoolDataProvider.d.ts +0 -136
- package/dist/abis/MetricOmmPoolDataProvider.d.ts.map +1 -1
- package/dist/abis/MetricOmmPoolDataProvider.js +0 -177
- package/dist/abis/MetricOmmPoolDataProvider.js.map +1 -1
- package/dist/abis/MetricOmmPoolStateView.d.ts +238 -0
- package/dist/abis/MetricOmmPoolStateView.d.ts.map +1 -0
- package/dist/abis/MetricOmmPoolStateView.js +315 -0
- package/dist/abis/MetricOmmPoolStateView.js.map +1 -0
- package/dist/abis/MetricOmmSimpleRouter.d.ts +619 -0
- package/dist/abis/{MetricOmmPoolSwapper.d.ts.map → MetricOmmSimpleRouter.d.ts.map} +1 -1
- package/dist/abis/MetricOmmSimpleRouter.js +805 -0
- package/dist/abis/MetricOmmSimpleRouter.js.map +1 -0
- package/dist/abis/MetricOmmSwapQuoter.d.ts +576 -0
- package/dist/abis/{PriceProviderUi.d.ts.map → MetricOmmSwapQuoter.d.ts.map} +1 -1
- package/dist/abis/MetricOmmSwapQuoter.js +748 -0
- package/dist/abis/MetricOmmSwapQuoter.js.map +1 -0
- package/dist/abis/OracleProvider.d.ts +106 -0
- package/dist/abis/OracleProvider.d.ts.map +1 -0
- package/dist/abis/OracleProvider.js +62 -0
- package/dist/abis/OracleProvider.js.map +1 -0
- package/dist/abis/PriceProvider.d.ts +8 -2
- package/dist/abis/PriceProvider.d.ts.map +1 -1
- package/dist/abis/PriceProvider.js +9 -1
- package/dist/abis/PriceProvider.js.map +1 -1
- package/dist/abis/index.d.ts +4 -2
- package/dist/abis/index.d.ts.map +1 -1
- package/dist/abis/index.js +4 -2
- package/dist/abis/index.js.map +1 -1
- package/dist/addresses.d.ts +3 -3
- package/dist/addresses.d.ts.map +1 -1
- package/dist/addresses.js +10 -10
- package/dist/addresses.js.map +1 -1
- package/dist/constants.d.ts +4 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +7 -2
- package/dist/constants.js.map +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -4
- package/dist/index.js.map +1 -1
- package/dist/oracle/index.d.ts +5 -0
- package/dist/oracle/index.d.ts.map +1 -0
- package/dist/oracle/index.js +5 -0
- package/dist/oracle/index.js.map +1 -0
- package/dist/oracle/registry.d.ts +53 -0
- package/dist/oracle/registry.d.ts.map +1 -0
- package/dist/oracle/registry.js +70 -0
- package/dist/oracle/registry.js.map +1 -0
- package/dist/quoter/index.d.ts +6 -0
- package/dist/quoter/index.d.ts.map +1 -0
- package/dist/quoter/index.js +6 -0
- package/dist/quoter/index.js.map +1 -0
- package/dist/quoter/quote.d.ts +58 -0
- package/dist/quoter/quote.d.ts.map +1 -0
- package/dist/quoter/quote.js +74 -0
- package/dist/quoter/quote.js.map +1 -0
- package/dist/quoter/quotePath.d.ts +65 -0
- package/dist/quoter/quotePath.d.ts.map +1 -0
- package/dist/quoter/quotePath.js +108 -0
- package/dist/quoter/quotePath.js.map +1 -0
- package/dist/router/index.d.ts +2 -1
- package/dist/router/index.d.ts.map +1 -1
- package/dist/router/index.js +2 -1
- package/dist/router/index.js.map +1 -1
- package/dist/router/swap.d.ts +37 -92
- package/dist/router/swap.d.ts.map +1 -1
- package/dist/router/swap.js +96 -298
- package/dist/router/swap.js.map +1 -1
- package/dist/router/swapPath.d.ts +56 -0
- package/dist/router/swapPath.d.ts.map +1 -0
- package/dist/router/swapPath.js +98 -0
- package/dist/router/swapPath.js.map +1 -0
- package/dist/swap/path.d.ts +13 -0
- package/dist/swap/path.d.ts.map +1 -0
- package/dist/swap/path.js +74 -0
- package/dist/swap/path.js.map +1 -0
- package/package.json +4 -5
- package/src/abis/MetricOmmPool.ts +18 -0
- package/src/abis/MetricOmmPoolDataProvider.ts +0 -177
- package/src/abis/MetricOmmPoolStateView.ts +314 -0
- package/src/abis/MetricOmmSimpleRouter.ts +804 -0
- package/src/abis/MetricOmmSwapQuoter.ts +747 -0
- package/src/abis/OracleProvider.ts +61 -0
- package/src/abis/PriceProvider.ts +9 -1
- package/src/abis/index.ts +4 -2
- package/src/addresses.ts +13 -13
- package/src/constants.ts +7 -2
- package/src/index.ts +62 -23
- package/src/oracle/index.ts +14 -0
- package/src/oracle/registry.ts +146 -0
- package/src/quoter/index.ts +28 -0
- package/src/quoter/quote.ts +193 -0
- package/src/quoter/quotePath.ts +240 -0
- package/src/router/index.ts +24 -25
- package/src/router/swap.ts +142 -480
- package/src/router/swapPath.ts +181 -0
- package/src/swap/path.ts +107 -0
- package/dist/abis/MetricOmmPoolSwapper.d.ts +0 -917
- package/dist/abis/MetricOmmPoolSwapper.js +0 -1185
- package/dist/abis/MetricOmmPoolSwapper.js.map +0 -1
- package/dist/abis/PriceProviderUi.d.ts +0 -433
- package/dist/abis/PriceProviderUi.js +0 -318
- package/dist/abis/PriceProviderUi.js.map +0 -1
- package/src/abis/MetricOmmPoolSwapper.ts +0 -1184
- package/src/abis/PriceProviderUi.ts +0 -317
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MetricAMM SDK - SimpleRouter multihop swap helpers.
|
|
3
|
+
*/
|
|
4
|
+
import type { Address, Hex, PublicClient } from "viem";
|
|
5
|
+
import { encodeFunctionData } from "viem";
|
|
6
|
+
import { quoteLiveExactIn, quoteLiveExactOut } from "../quoter/quotePath.js";
|
|
7
|
+
import { resolveSwapPath } from "../swap/path.js";
|
|
8
|
+
import { SIMPLE_ROUTER_ABI } from "../constants.js";
|
|
9
|
+
import { ceilDiv, toSlippageBps } from "./swap.js";
|
|
10
|
+
|
|
11
|
+
const BPS_BASE = 10_000n;
|
|
12
|
+
|
|
13
|
+
export type ExactInputParams = {
|
|
14
|
+
tokens: Address[];
|
|
15
|
+
pools: Address[];
|
|
16
|
+
extensionDatas: Hex[];
|
|
17
|
+
zeroForOneBitMap: bigint;
|
|
18
|
+
amountIn: bigint;
|
|
19
|
+
amountOutMinimum: bigint;
|
|
20
|
+
recipient: Address;
|
|
21
|
+
deadline: bigint;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export type ExactOutputParams = {
|
|
25
|
+
tokens: Address[];
|
|
26
|
+
pools: Address[];
|
|
27
|
+
extensionDatas: Hex[];
|
|
28
|
+
zeroForOneBitMap: bigint;
|
|
29
|
+
amountOut: bigint;
|
|
30
|
+
amountInMaximum: bigint;
|
|
31
|
+
recipient: Address;
|
|
32
|
+
deadline: bigint;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export interface BuildExactInputParams {
|
|
36
|
+
publicClient: PublicClient;
|
|
37
|
+
tokenIn: Address;
|
|
38
|
+
tokenOut: Address;
|
|
39
|
+
pools: readonly Address[];
|
|
40
|
+
extensionDatas?: readonly Hex[];
|
|
41
|
+
recipient: Address;
|
|
42
|
+
amountIn: bigint;
|
|
43
|
+
slippagePercent: number;
|
|
44
|
+
deadline: bigint;
|
|
45
|
+
quoterAddress?: Address;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface BuildExactOutputParams {
|
|
49
|
+
publicClient: PublicClient;
|
|
50
|
+
tokenIn: Address;
|
|
51
|
+
tokenOut: Address;
|
|
52
|
+
pools: readonly Address[];
|
|
53
|
+
extensionDatas?: readonly Hex[];
|
|
54
|
+
recipient: Address;
|
|
55
|
+
amountOut: bigint;
|
|
56
|
+
slippagePercent: number;
|
|
57
|
+
deadline: bigint;
|
|
58
|
+
quoterAddress?: Address;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function toExactInputStruct(params: ExactInputParams) {
|
|
62
|
+
return {
|
|
63
|
+
tokens: params.tokens,
|
|
64
|
+
pools: params.pools,
|
|
65
|
+
extensionDatas: params.extensionDatas,
|
|
66
|
+
zeroForOneBitMap: params.zeroForOneBitMap,
|
|
67
|
+
amountIn: params.amountIn,
|
|
68
|
+
amountOutMinimum: params.amountOutMinimum,
|
|
69
|
+
recipient: params.recipient,
|
|
70
|
+
deadline: params.deadline,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function toExactOutputStruct(params: ExactOutputParams) {
|
|
75
|
+
return {
|
|
76
|
+
tokens: params.tokens,
|
|
77
|
+
pools: params.pools,
|
|
78
|
+
extensionDatas: params.extensionDatas,
|
|
79
|
+
zeroForOneBitMap: params.zeroForOneBitMap,
|
|
80
|
+
amountOut: params.amountOut,
|
|
81
|
+
amountInMaximum: params.amountInMaximum,
|
|
82
|
+
recipient: params.recipient,
|
|
83
|
+
deadline: params.deadline,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export async function buildExactInputParams(
|
|
88
|
+
params: BuildExactInputParams,
|
|
89
|
+
): Promise<ExactInputParams> {
|
|
90
|
+
const slippageBps = toSlippageBps(params.slippagePercent);
|
|
91
|
+
const { tokens, extensionDatas, zeroForOneBitMap } = await resolveSwapPath(
|
|
92
|
+
params.publicClient,
|
|
93
|
+
params.tokenIn,
|
|
94
|
+
params.tokenOut,
|
|
95
|
+
params.pools,
|
|
96
|
+
params.extensionDatas,
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
const { amountOut } = await quoteLiveExactIn({
|
|
100
|
+
publicClient: params.publicClient,
|
|
101
|
+
tokenIn: params.tokenIn,
|
|
102
|
+
tokenOut: params.tokenOut,
|
|
103
|
+
pools: params.pools,
|
|
104
|
+
extensionDatas: params.extensionDatas,
|
|
105
|
+
recipient: params.recipient,
|
|
106
|
+
amountIn: params.amountIn,
|
|
107
|
+
quoterAddress: params.quoterAddress,
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const amountOutMinimum = (amountOut * (BPS_BASE - slippageBps)) / BPS_BASE;
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
tokens,
|
|
114
|
+
pools: [...params.pools],
|
|
115
|
+
extensionDatas,
|
|
116
|
+
zeroForOneBitMap,
|
|
117
|
+
amountIn: params.amountIn,
|
|
118
|
+
amountOutMinimum,
|
|
119
|
+
recipient: params.recipient,
|
|
120
|
+
deadline: params.deadline,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export async function buildExactOutputParams(
|
|
125
|
+
params: BuildExactOutputParams,
|
|
126
|
+
): Promise<ExactOutputParams> {
|
|
127
|
+
const slippageBps = toSlippageBps(params.slippagePercent);
|
|
128
|
+
const { tokens, extensionDatas, zeroForOneBitMap } = await resolveSwapPath(
|
|
129
|
+
params.publicClient,
|
|
130
|
+
params.tokenIn,
|
|
131
|
+
params.tokenOut,
|
|
132
|
+
params.pools,
|
|
133
|
+
params.extensionDatas,
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
const { amountIn } = await quoteLiveExactOut({
|
|
137
|
+
publicClient: params.publicClient,
|
|
138
|
+
tokenIn: params.tokenIn,
|
|
139
|
+
tokenOut: params.tokenOut,
|
|
140
|
+
pools: params.pools,
|
|
141
|
+
extensionDatas: params.extensionDatas,
|
|
142
|
+
recipient: params.recipient,
|
|
143
|
+
amountOut: params.amountOut,
|
|
144
|
+
quoterAddress: params.quoterAddress,
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
const amountInMaximum = ceilDiv(amountIn * (BPS_BASE + slippageBps), BPS_BASE);
|
|
148
|
+
|
|
149
|
+
return {
|
|
150
|
+
tokens,
|
|
151
|
+
pools: [...params.pools],
|
|
152
|
+
extensionDatas,
|
|
153
|
+
zeroForOneBitMap,
|
|
154
|
+
amountOut: params.amountOut,
|
|
155
|
+
amountInMaximum,
|
|
156
|
+
recipient: params.recipient,
|
|
157
|
+
deadline: params.deadline,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function encodeExactInputCalldata(params: ExactInputParams): Hex {
|
|
162
|
+
return encodeFunctionData({
|
|
163
|
+
abi: SIMPLE_ROUTER_ABI,
|
|
164
|
+
functionName: "exactInput",
|
|
165
|
+
args: [toExactInputStruct(params)],
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export const prepareExactInputCalldata = encodeExactInputCalldata;
|
|
170
|
+
|
|
171
|
+
export function encodeExactOutputCalldata(params: ExactOutputParams): Hex {
|
|
172
|
+
return encodeFunctionData({
|
|
173
|
+
abi: SIMPLE_ROUTER_ABI,
|
|
174
|
+
functionName: "exactOutput",
|
|
175
|
+
args: [toExactOutputStruct(params)],
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export const prepareExactOutputCalldata = encodeExactOutputCalldata;
|
|
180
|
+
|
|
181
|
+
export { encodeZeroForOneBitMap } from "../swap/path.js";
|
package/src/swap/path.ts
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MetricAMM SDK - swap path helpers shared by router and quoter.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { Address, Hex, PublicClient } from "viem";
|
|
6
|
+
import { getAddress } from "viem";
|
|
7
|
+
import { POOL_ABI } from "../constants.js";
|
|
8
|
+
import { EMPTY_EXTENSION_DATA } from "../extensions/types.js";
|
|
9
|
+
|
|
10
|
+
function withExtensionData(extensionData?: Hex): Hex {
|
|
11
|
+
return extensionData ?? EMPTY_EXTENSION_DATA;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function encodeZeroForOneBitMap(zeroForOneDirections: readonly boolean[]): bigint {
|
|
15
|
+
let bitmap = 0n;
|
|
16
|
+
for (let i = 0; i < zeroForOneDirections.length; i++) {
|
|
17
|
+
if (zeroForOneDirections[i]) {
|
|
18
|
+
bitmap |= 1n << BigInt(i);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return bitmap;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function readPoolTokens(
|
|
25
|
+
publicClient: PublicClient,
|
|
26
|
+
pool: Address,
|
|
27
|
+
): Promise<{ token0: Address; token1: Address }> {
|
|
28
|
+
const imm = (await publicClient.readContract({
|
|
29
|
+
address: pool,
|
|
30
|
+
abi: POOL_ABI,
|
|
31
|
+
functionName: "getImmutables",
|
|
32
|
+
})) as { token0: Address; token1: Address };
|
|
33
|
+
|
|
34
|
+
return { token0: imm.token0, token1: imm.token1 };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function zeroForOneFromTokenIn(tokenIn: Address, token0: Address, token1: Address): boolean {
|
|
38
|
+
const normalized = getAddress(tokenIn);
|
|
39
|
+
if (normalized === getAddress(token0)) return true;
|
|
40
|
+
if (normalized === getAddress(token1)) return false;
|
|
41
|
+
throw new Error(`tokenIn ${tokenIn} is not a token in pool (${token0}, ${token1})`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function normalizeExtensionDatas(
|
|
45
|
+
pools: readonly Address[],
|
|
46
|
+
extensionDatas?: readonly Hex[],
|
|
47
|
+
): Hex[] {
|
|
48
|
+
if (!extensionDatas) {
|
|
49
|
+
return pools.map(() => EMPTY_EXTENSION_DATA);
|
|
50
|
+
}
|
|
51
|
+
if (extensionDatas.length !== pools.length) {
|
|
52
|
+
throw new Error("extensionDatas length must match pools length");
|
|
53
|
+
}
|
|
54
|
+
return extensionDatas.map((extensionData) => withExtensionData(extensionData));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export async function resolveSwapPath(
|
|
58
|
+
publicClient: PublicClient,
|
|
59
|
+
tokenIn: Address,
|
|
60
|
+
tokenOut: Address,
|
|
61
|
+
pools: readonly Address[],
|
|
62
|
+
extensionDatas?: readonly Hex[],
|
|
63
|
+
): Promise<{
|
|
64
|
+
tokens: Address[];
|
|
65
|
+
zeroForOnes: boolean[];
|
|
66
|
+
extensionDatas: Hex[];
|
|
67
|
+
zeroForOneBitMap: bigint;
|
|
68
|
+
}> {
|
|
69
|
+
if (pools.length === 0) {
|
|
70
|
+
throw new Error("pools must not be empty");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const normalizedExtensionDatas = normalizeExtensionDatas(pools, extensionDatas);
|
|
74
|
+
const tokens: Address[] = [getAddress(tokenIn)];
|
|
75
|
+
const zeroForOnes: boolean[] = [];
|
|
76
|
+
let currentToken = getAddress(tokenIn);
|
|
77
|
+
|
|
78
|
+
for (const pool of pools) {
|
|
79
|
+
const { token0, token1 } = await readPoolTokens(publicClient, pool);
|
|
80
|
+
const zeroForOne = zeroForOneFromTokenIn(currentToken, token0, token1);
|
|
81
|
+
const nextToken = getAddress(zeroForOne ? token1 : token0);
|
|
82
|
+
zeroForOnes.push(zeroForOne);
|
|
83
|
+
tokens.push(nextToken);
|
|
84
|
+
currentToken = nextToken;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (currentToken !== getAddress(tokenOut)) {
|
|
88
|
+
throw new Error(`path ends at ${currentToken}, expected ${getAddress(tokenOut)}`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
tokens,
|
|
93
|
+
zeroForOnes,
|
|
94
|
+
extensionDatas: normalizedExtensionDatas,
|
|
95
|
+
zeroForOneBitMap: encodeZeroForOneBitMap(zeroForOnes),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export async function resolveZeroForOne(
|
|
100
|
+
publicClient: PublicClient,
|
|
101
|
+
pool: Address,
|
|
102
|
+
tokenIn: Address,
|
|
103
|
+
tokenOut: Address,
|
|
104
|
+
): Promise<boolean> {
|
|
105
|
+
const { zeroForOnes } = await resolveSwapPath(publicClient, tokenIn, tokenOut, [pool]);
|
|
106
|
+
return zeroForOnes[0]!;
|
|
107
|
+
}
|