@aegis-engine/core 0.1.0 → 0.1.1
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 +284 -17
- package/dist/actions/directPoolSwap.d.ts +13 -2
- package/dist/aegis-core.js +520 -568
- package/dist/config.d.ts +0 -4
- package/dist/index.d.ts +4 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,41 +2,308 @@
|
|
|
2
2
|
|
|
3
3
|
React-free swap operations for Aegis integrations.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
`@aegis-engine/core` is the operations layer behind the Aegis swap experience.
|
|
6
|
+
Use it when you want Aegis direct-pool swaps or KyberSwap aggregated routes
|
|
7
|
+
inside your own UI instead of using a prebuilt widget.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npm install @aegis-engine/core viem
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`viem` is a peer dependency because hosts usually already own their wallet and
|
|
16
|
+
RPC setup.
|
|
17
|
+
|
|
18
|
+
## What It Supports
|
|
19
|
+
|
|
20
|
+
- Direct Aegis pool quotes and execution against host-supplied Uniswap v4 pool
|
|
21
|
+
configs.
|
|
22
|
+
- KyberSwap aggregated quotes and execution through the Kyber aggregator API.
|
|
23
|
+
- ERC-20 approvals, Permit2 signing, Permit2 on-chain fallback, wallet chain
|
|
24
|
+
switching, transaction submission, replacement tracking, and receipt summaries.
|
|
25
|
+
- Token, market, chain, metadata, polling, and progress helpers for custom UIs.
|
|
26
|
+
|
|
27
|
+
Direct pool swaps support `exactIn` and `exactOut`. KyberSwap routes currently
|
|
28
|
+
support `exactIn` only because Kyber's route/build flow is exact-input.
|
|
29
|
+
|
|
30
|
+
Core does not ship a hardcoded pool list. The widget or host app should own pool
|
|
31
|
+
selection and pass the selected market into the operation functions.
|
|
32
|
+
|
|
33
|
+
## Wallet Sessions
|
|
34
|
+
|
|
35
|
+
Execution functions take a `WalletSession`:
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
type WalletSession = {
|
|
39
|
+
provider: Eip1193Provider
|
|
40
|
+
account: Address
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
If your app already uses wagmi, RainbowKit, Privy, Dynamic, or another wallet
|
|
45
|
+
manager, you can build this object yourself and skip `resolveWalletSession`.
|
|
46
|
+
|
|
47
|
+
`resolveWalletSession` is a convenience for simple browser integrations. It:
|
|
48
|
+
|
|
49
|
+
- uses a supplied `provider` and `account` when provided,
|
|
50
|
+
- otherwise calls `getProvider`,
|
|
51
|
+
- otherwise falls back to `window.ethereum`,
|
|
52
|
+
- optionally calls your `connectWallet` callback,
|
|
53
|
+
- requests an account by default when one is missing.
|
|
54
|
+
|
|
55
|
+
Call it from a user action, not during render, because it may open the wallet
|
|
56
|
+
connection prompt.
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
import { resolveWalletSession } from '@aegis-engine/core'
|
|
60
|
+
|
|
61
|
+
const wallet = await resolveWalletSession()
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
With a host wallet manager:
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
const wallet = await resolveWalletSession({
|
|
68
|
+
account: address,
|
|
69
|
+
getProvider: () => connector.getProvider()
|
|
70
|
+
})
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
To only read an already connected account without prompting:
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
const wallet = await resolveWalletSession({
|
|
77
|
+
provider,
|
|
78
|
+
requestAccount: false
|
|
79
|
+
})
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Public Client
|
|
83
|
+
|
|
84
|
+
Create a read-side viem client from an Aegis chain config:
|
|
9
85
|
|
|
10
86
|
```ts
|
|
11
87
|
import {
|
|
12
88
|
AEGIS_SWAP_MAINNET_CHAIN,
|
|
13
|
-
|
|
14
|
-
AEGIS_SWAP_TOKENS,
|
|
15
|
-
createSwapPublicClient,
|
|
16
|
-
executeDirectPoolSwap,
|
|
17
|
-
resolveWalletSession
|
|
89
|
+
createSwapPublicClient
|
|
18
90
|
} from '@aegis-engine/core'
|
|
19
91
|
|
|
20
92
|
const publicClient = createSwapPublicClient(
|
|
21
93
|
AEGIS_SWAP_MAINNET_CHAIN.chain,
|
|
22
94
|
AEGIS_SWAP_MAINNET_CHAIN.rpcUrls
|
|
23
95
|
)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
For production integrations, prefer passing your own viem `PublicClient` backed
|
|
99
|
+
by your RPC provider. `createSwapPublicClient` is a convenience fallback for
|
|
100
|
+
simple integrations and demos.
|
|
101
|
+
|
|
102
|
+
## Direct Pool Market Config
|
|
103
|
+
|
|
104
|
+
The direct pool operations take an `AegisSwapMarket`. Hosts can build one from
|
|
105
|
+
their own pool config:
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
import { createAegisSwapPoolMarket } from '@aegis-engine/core'
|
|
109
|
+
|
|
110
|
+
const market = createAegisSwapPoolMarket({
|
|
111
|
+
id: 'HOST_POOL_ID',
|
|
112
|
+
token: targetToken,
|
|
113
|
+
counterToken,
|
|
114
|
+
poolKey: {
|
|
115
|
+
currency0,
|
|
116
|
+
currency1,
|
|
117
|
+
fee,
|
|
118
|
+
tickSpacing,
|
|
119
|
+
hooks
|
|
120
|
+
},
|
|
121
|
+
poolId
|
|
122
|
+
})
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
The pool key must use Uniswap v4 canonical currency ordering. If `poolId` is
|
|
126
|
+
provided, core verifies it matches the key.
|
|
127
|
+
|
|
128
|
+
## Direct Pool Quote
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
import {
|
|
132
|
+
AEGIS_SWAP_MAINNET_CHAIN,
|
|
133
|
+
fetchDirectPoolSwapQuote
|
|
134
|
+
} from '@aegis-engine/core'
|
|
135
|
+
|
|
136
|
+
const quote = await fetchDirectPoolSwapQuote({
|
|
137
|
+
publicClient,
|
|
138
|
+
account,
|
|
139
|
+
activeChain: AEGIS_SWAP_MAINNET_CHAIN,
|
|
140
|
+
market,
|
|
141
|
+
inputToken,
|
|
142
|
+
outputToken,
|
|
143
|
+
mode: 'exactIn',
|
|
144
|
+
amount: 1_000_000n,
|
|
145
|
+
slippageBps: 100
|
|
146
|
+
})
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Amounts are raw token base units. `slippageBps: 100` means 1%.
|
|
150
|
+
The Aegis 0.5% output fee is applied by the high-level quote and execution
|
|
151
|
+
helpers.
|
|
152
|
+
|
|
153
|
+
## Direct Pool Execution
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
import {
|
|
157
|
+
AEGIS_SWAP_MAINNET_CHAIN,
|
|
158
|
+
executeDirectPoolSwap,
|
|
159
|
+
resolveWalletSession
|
|
160
|
+
} from '@aegis-engine/core'
|
|
161
|
+
|
|
24
162
|
const wallet = await resolveWalletSession()
|
|
25
163
|
|
|
26
164
|
const result = await executeDirectPoolSwap({
|
|
27
165
|
wallet,
|
|
28
166
|
publicClient,
|
|
29
167
|
activeChain: AEGIS_SWAP_MAINNET_CHAIN,
|
|
30
|
-
market
|
|
31
|
-
inputToken
|
|
32
|
-
outputToken
|
|
168
|
+
market,
|
|
169
|
+
inputToken,
|
|
170
|
+
outputToken,
|
|
33
171
|
mode: 'exactIn',
|
|
34
172
|
amount: 1_000_000n,
|
|
35
|
-
slippageBps: 100
|
|
173
|
+
slippageBps: 100,
|
|
174
|
+
displayedQuote: quote,
|
|
175
|
+
approvalMode: 'exact',
|
|
176
|
+
onStatus: (status) => setStatus(status),
|
|
177
|
+
onTxHash: (hash) => setTxHash(hash),
|
|
178
|
+
onSubmitted: (hash, swap) => trackSwapSubmitted(hash, swap)
|
|
179
|
+
})
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Passing `displayedQuote` is recommended. Core requotes immediately before
|
|
183
|
+
submission and refuses to submit if the fresh quote no longer satisfies the
|
|
184
|
+
protection the user saw.
|
|
185
|
+
|
|
186
|
+
## KyberSwap Quote
|
|
187
|
+
|
|
188
|
+
```ts
|
|
189
|
+
import {
|
|
190
|
+
AGGREGATED_SWAP_DEFAULT_TOKENS,
|
|
191
|
+
fetchAggregatedSwapQuote
|
|
192
|
+
} from '@aegis-engine/core'
|
|
193
|
+
|
|
194
|
+
const quote = await fetchAggregatedSwapQuote(
|
|
195
|
+
AGGREGATED_SWAP_DEFAULT_TOKENS.USDC,
|
|
196
|
+
AGGREGATED_SWAP_DEFAULT_TOKENS.USDT,
|
|
197
|
+
1_000_000n,
|
|
198
|
+
100,
|
|
199
|
+
'exactIn'
|
|
200
|
+
)
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
For a display-only quote, omit the account. For executable calldata, pass the
|
|
204
|
+
user account:
|
|
205
|
+
|
|
206
|
+
```ts
|
|
207
|
+
const executableQuote = await fetchAggregatedSwapQuote(
|
|
208
|
+
inputToken,
|
|
209
|
+
outputToken,
|
|
210
|
+
amount,
|
|
211
|
+
slippageBps,
|
|
212
|
+
'exactIn',
|
|
213
|
+
wallet.account
|
|
214
|
+
)
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## KyberSwap Execution
|
|
218
|
+
|
|
219
|
+
```ts
|
|
220
|
+
import {
|
|
221
|
+
AEGIS_SWAP_MAINNET_CHAIN,
|
|
222
|
+
AGGREGATED_SWAP_DEFAULT_TOKENS,
|
|
223
|
+
executeKyberSwap,
|
|
224
|
+
resolveWalletSession
|
|
225
|
+
} from '@aegis-engine/core'
|
|
226
|
+
|
|
227
|
+
const wallet = await resolveWalletSession()
|
|
228
|
+
|
|
229
|
+
const result = await executeKyberSwap({
|
|
230
|
+
wallet,
|
|
231
|
+
publicClient,
|
|
232
|
+
activeChain: AEGIS_SWAP_MAINNET_CHAIN,
|
|
233
|
+
inputToken: AGGREGATED_SWAP_DEFAULT_TOKENS.USDC,
|
|
234
|
+
outputToken: AGGREGATED_SWAP_DEFAULT_TOKENS.USDT,
|
|
235
|
+
amount: 1_000_000n,
|
|
236
|
+
slippageBps: 100,
|
|
237
|
+
displayedQuote: quote,
|
|
238
|
+
approvalMode: 'exact',
|
|
239
|
+
onStatus: (status) => setStatus(status),
|
|
240
|
+
onTxHash: (hash) => setTxHash(hash)
|
|
36
241
|
})
|
|
37
242
|
```
|
|
38
243
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
244
|
+
Kyber execution will:
|
|
245
|
+
|
|
246
|
+
- switch the wallet to the active chain when needed,
|
|
247
|
+
- approve the Kyber router for ERC-20 input tokens,
|
|
248
|
+
- skip approval for native ETH-style input tokens,
|
|
249
|
+
- rebuild the route with executable calldata for the connected account,
|
|
250
|
+
- reject submission if the route moved below the displayed minimum,
|
|
251
|
+
- send the transaction and wait for a receipt.
|
|
252
|
+
|
|
253
|
+
## Approval Modes
|
|
254
|
+
|
|
255
|
+
`approvalMode` controls ERC-20 approval sizing.
|
|
256
|
+
|
|
257
|
+
- `exact`: approve only the current quote spend.
|
|
258
|
+
- `max`: approve the maximum spender allowance to reduce future approval prompts.
|
|
259
|
+
|
|
260
|
+
Direct pool swaps also use Permit2. Core first attempts an off-chain Permit2
|
|
261
|
+
signature and falls back to an on-chain Permit2 approval if the wallet cannot
|
|
262
|
+
produce a compatible typed-data signature.
|
|
263
|
+
|
|
264
|
+
## Result Shape
|
|
265
|
+
|
|
266
|
+
Execution returns:
|
|
267
|
+
|
|
268
|
+
```ts
|
|
269
|
+
{
|
|
270
|
+
hash: Hex
|
|
271
|
+
explorerUrl: string
|
|
272
|
+
quote: DirectSwapQuote | AggregatedSwapQuote
|
|
273
|
+
receiptSummary: {
|
|
274
|
+
transactionHash: Hex
|
|
275
|
+
blockNumber: bigint
|
|
276
|
+
gasUsed: bigint
|
|
277
|
+
effectiveGasPrice: bigint
|
|
278
|
+
feeWei: bigint
|
|
279
|
+
}
|
|
280
|
+
swap: {
|
|
281
|
+
mode: 'exactIn' | 'exactOut'
|
|
282
|
+
inputSymbol: string
|
|
283
|
+
outputSymbol: string
|
|
284
|
+
amountIn: bigint
|
|
285
|
+
amountOut: bigint
|
|
286
|
+
feeAmount: bigint
|
|
287
|
+
feeBps: number
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
## Errors To Handle
|
|
293
|
+
|
|
294
|
+
- `DirectPoolSwapPriceMovedError`: direct pool submit-time quote moved beyond
|
|
295
|
+
the displayed tolerance. The error includes the fresh `quote`.
|
|
296
|
+
- `KyberSwapPriceMovedError`: Kyber executable route moved below the displayed
|
|
297
|
+
minimum. The error includes the fresh `quote`.
|
|
298
|
+
- User rejection errors normalize through `errorMessage(error, fallback)`.
|
|
299
|
+
- Kyber temporary failures can be mapped with
|
|
300
|
+
`aggregatedSwapErrorMessage(error, fallback)`.
|
|
301
|
+
|
|
302
|
+
## Publishing
|
|
303
|
+
|
|
304
|
+
This package is configured with `prepack`, so `npm publish` builds `dist` before
|
|
305
|
+
creating the tarball.
|
|
306
|
+
|
|
307
|
+
```sh
|
|
308
|
+
npm publish --access public
|
|
309
|
+
```
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Hex, type PublicClient } from 'viem';
|
|
2
|
-
import type { AegisSwapChainConfig,
|
|
2
|
+
import type { AegisSwapChainConfig, AegisSwapMarket, AegisSwapToken } from '../config';
|
|
3
3
|
import { type DirectSwapQuote, type SwapQuoteMode } from '../quote';
|
|
4
4
|
import type { AegisSwapApprovalMode, WalletSession } from '../swap/types';
|
|
5
5
|
import type { AegisSwapActionCallbacks, AegisSwapActionResult } from './types';
|
|
@@ -11,6 +11,18 @@ export type DirectPoolSwapApprovalResult = {
|
|
|
11
11
|
approvalHash: Hex | null;
|
|
12
12
|
allowance: bigint;
|
|
13
13
|
};
|
|
14
|
+
export declare function fetchDirectPoolSwapQuote(args: {
|
|
15
|
+
publicClient: PublicClient;
|
|
16
|
+
account: WalletSession['account'];
|
|
17
|
+
activeChain: AegisSwapChainConfig;
|
|
18
|
+
market: AegisSwapMarket;
|
|
19
|
+
inputToken: AegisSwapToken;
|
|
20
|
+
outputToken: AegisSwapToken;
|
|
21
|
+
mode: SwapQuoteMode;
|
|
22
|
+
amount: bigint;
|
|
23
|
+
slippageBps: number;
|
|
24
|
+
signal?: AbortSignal;
|
|
25
|
+
}): Promise<DirectSwapQuote>;
|
|
14
26
|
export declare function approveDirectPoolSwapInput(args: {
|
|
15
27
|
wallet: WalletSession;
|
|
16
28
|
publicClient: PublicClient;
|
|
@@ -31,7 +43,6 @@ export declare function executeDirectPoolSwap(args: {
|
|
|
31
43
|
mode: SwapQuoteMode;
|
|
32
44
|
amount: bigint;
|
|
33
45
|
slippageBps: number;
|
|
34
|
-
fee?: AegisSwapFeeConfig | null;
|
|
35
46
|
displayedQuote?: DirectSwapQuote | null;
|
|
36
47
|
approvalMode?: AegisSwapApprovalMode;
|
|
37
48
|
signal?: AbortSignal;
|