@lifi/composer-sdk 0.4.0 → 0.4.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 +95 -5
- package/dist/authoring/raw.cjs +3 -1
- package/dist/authoring/raw.cjs.map +1 -1
- package/dist/authoring/raw.js +3 -1
- package/dist/authoring/raw.js.map +1 -1
- package/dist/client.cjs +26 -24
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +31 -1
- package/dist/client.d.ts +31 -1
- package/dist/client.js +26 -24
- package/dist/client.js.map +1 -1
- package/dist/discovery.cjs.map +1 -1
- package/dist/discovery.d.cts +13 -0
- package/dist/discovery.d.ts +13 -0
- package/dist/generated/config.generated.cjs.map +1 -1
- package/dist/generated/config.generated.d.cts +15 -3
- package/dist/generated/config.generated.d.ts +15 -3
- package/dist/generated/operations.generated.cjs +3 -0
- package/dist/generated/operations.generated.cjs.map +1 -1
- package/dist/generated/operations.generated.d.cts +17 -2
- package/dist/generated/operations.generated.d.ts +17 -2
- package/dist/generated/operations.generated.js +3 -0
- package/dist/generated/operations.generated.js.map +1 -1
- package/dist/index.cjs +5 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +22 -3
- package/dist/index.d.ts +22 -3
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/routeAmount-DdbJYJyM.d.cts +55 -0
- package/dist/routeAmount-DdbJYJyM.d.ts +55 -0
- package/dist/routeAmount.cjs +38 -0
- package/dist/routeAmount.cjs.map +1 -0
- package/dist/routeAmount.d.cts +2 -0
- package/dist/routeAmount.d.ts +2 -0
- package/dist/routeAmount.js +13 -0
- package/dist/routeAmount.js.map +1 -0
- package/dist/sdk.cjs +1 -0
- package/dist/sdk.cjs.map +1 -1
- package/dist/sdk.d.cts +14 -1
- package/dist/sdk.d.ts +14 -1
- package/dist/sdk.js +1 -0
- package/dist/sdk.js.map +1 -1
- package/package.json +5 -5
- package/src/authoring/raw.ts +3 -2
- package/src/client.ts +75 -23
- package/src/discovery.ts +13 -0
- package/src/examples/lifiZap.ts +4 -0
- package/src/examples/lifiZapAsync.ts +88 -0
- package/src/examples/routeTokenPair.ts +58 -0
- package/src/examples/run.ts +30 -5
- package/src/generated/config.generated.ts +21 -3
- package/src/generated/operations.generated.ts +30 -8
- package/src/index.ts +23 -0
- package/src/routeAmount.ts +61 -0
- package/src/sdk.ts +17 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { ComposeCompileRequest, Flow } from '@lifi/compose-spec';
|
|
2
|
+
|
|
3
|
+
import { createComposeSdk, materialisers, resources } from '../index.js';
|
|
4
|
+
import type { Address } from '../types.js';
|
|
5
|
+
|
|
6
|
+
import { API_KEY, BASE_URL } from './config.js';
|
|
7
|
+
|
|
8
|
+
const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';
|
|
9
|
+
// Aave aEthUSDC receipt token on Ethereum mainnet
|
|
10
|
+
const A_ETH_USDC = '0x98C23E9d8f34FEFb1B7BD6a91B7FF122F4e16F5c';
|
|
11
|
+
|
|
12
|
+
export interface LifiZapAsyncInput {
|
|
13
|
+
readonly owner: Address;
|
|
14
|
+
readonly recipient: Address;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Zap USDC into a DeFi position whose output settles asynchronously via LI.FI.
|
|
19
|
+
*
|
|
20
|
+
* Demonstrates:
|
|
21
|
+
* - `lifi.zapAsync`, the future-availability sibling of `lifi.zap`
|
|
22
|
+
* - Binding the required `recipient` input (the async op has no optional
|
|
23
|
+
* recipient — the decl is non-optional, so `bind.recipient` is mandatory)
|
|
24
|
+
* - Omitting `sweepTo`: `availability: 'future'` governs custody, so the
|
|
25
|
+
* output is delivered externally and never enters the execution VM — a
|
|
26
|
+
* sweep would find nothing to move (custody, not amount reporting)
|
|
27
|
+
* - Amount reporting is unaffected by availability: when the async lowering
|
|
28
|
+
* binds a terminal handle the output still reports `simulated.amountOut`,
|
|
29
|
+
* the protocol's in-transaction expected value (an estimate; the delivered
|
|
30
|
+
* amount arrives after settlement). `simulated.amountOutMin` appears only
|
|
31
|
+
* when a minimum source exists — for a future output that means a floor the
|
|
32
|
+
* edge lowering itself reported, never a user guard
|
|
33
|
+
* - No output guards: the reported value is the initiating-transaction
|
|
34
|
+
* estimate, not the asynchronously delivered amount a guard could enforce,
|
|
35
|
+
* so `amountOut` is excluded from the generated `TypedGuard` union
|
|
36
|
+
* (`guards` typechecks as `TypedGuard<never>[]`) and the compiler rejects
|
|
37
|
+
* any guard on it
|
|
38
|
+
*/
|
|
39
|
+
export const buildLifiZapAsyncExample = ({
|
|
40
|
+
owner,
|
|
41
|
+
recipient,
|
|
42
|
+
}: LifiZapAsyncInput): {
|
|
43
|
+
flow: Flow;
|
|
44
|
+
request: ComposeCompileRequest;
|
|
45
|
+
} => {
|
|
46
|
+
const sdk = createComposeSdk({ baseUrl: BASE_URL, apiKey: API_KEY });
|
|
47
|
+
|
|
48
|
+
// Declare the flow with a single USDC input and the recipient address input.
|
|
49
|
+
const builder = sdk.flow(1, {
|
|
50
|
+
name: 'zap-async-usdc-to-aave',
|
|
51
|
+
inputs: {
|
|
52
|
+
amountIn: resources.erc20(USDC, 1),
|
|
53
|
+
recipient: 'address',
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Zap USDC into an async Aave position via LI.FI.
|
|
58
|
+
// The future output is delivered to `recipient` once the initiating
|
|
59
|
+
// transaction settles; the recipient binding is required by the op.
|
|
60
|
+
builder.lifi.zapAsync('zap', {
|
|
61
|
+
bind: {
|
|
62
|
+
amountIn: builder.inputs.amountIn,
|
|
63
|
+
recipient: builder.inputs.recipient,
|
|
64
|
+
},
|
|
65
|
+
config: {
|
|
66
|
+
resourceOut: resources.erc20(A_ETH_USDC, 1),
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const flow = builder.build();
|
|
71
|
+
|
|
72
|
+
// Build the compile request.
|
|
73
|
+
// directDeposit transfers a fixed amount of USDC into the VM; the recipient
|
|
74
|
+
// handle passes the delivery address as a plain string.
|
|
75
|
+
// No `sweepTo`: the async output is delivered externally to the recipient,
|
|
76
|
+
// never landing in the VM for a sweep to reach.
|
|
77
|
+
// NOTE: no production edge sets `availability: 'future'` yet, so this request
|
|
78
|
+
// resolves to a typed no_route today; it documents the intended shape.
|
|
79
|
+
const request = sdk.request(flow, {
|
|
80
|
+
signer: owner,
|
|
81
|
+
inputs: {
|
|
82
|
+
amountIn: materialisers.directDeposit({ amount: '1000000000' }),
|
|
83
|
+
recipient,
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
return { flow, request };
|
|
88
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { ComposeRouteRequest } from '@lifi/compose-spec';
|
|
2
|
+
|
|
3
|
+
import { routeAmount } from '../index.js';
|
|
4
|
+
|
|
5
|
+
import { OWNER } from './config.js';
|
|
6
|
+
|
|
7
|
+
const NATIVE_ETH = '0x0000000000000000000000000000000000000000';
|
|
8
|
+
const WETH = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Wrap 0.1 native ETH into WETH on Ethereum mainnet through
|
|
12
|
+
* `POST /compose/route`.
|
|
13
|
+
*
|
|
14
|
+
* Demonstrates:
|
|
15
|
+
* - The convenience path: a from/to token pair instead of an authored flow.
|
|
16
|
+
* The pair resolves to the catalog's `wrap` edge, and the server authors the
|
|
17
|
+
* zap step for it
|
|
18
|
+
* - `routeAmount.exact` for a fixed input amount (`bigint`, serialised on send)
|
|
19
|
+
* - The native sentinel address as `fromToken`
|
|
20
|
+
*
|
|
21
|
+
* Pure: returns a plain {@link ComposeRouteRequest}, performs no network I/O.
|
|
22
|
+
* Pass it to `sdk.route(...)` / `sdk.client.route(...)` to compile it.
|
|
23
|
+
*/
|
|
24
|
+
export const buildRouteExactExample = (): ComposeRouteRequest => ({
|
|
25
|
+
chainId: 1,
|
|
26
|
+
fromToken: NATIVE_ETH,
|
|
27
|
+
toToken: WETH,
|
|
28
|
+
amount: routeAmount.exact(100_000_000_000_000_000n), // 0.1 ETH
|
|
29
|
+
signer: OWNER,
|
|
30
|
+
slippageBps: 100,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Unwrap the signer's entire WETH balance back into native ETH on Ethereum
|
|
35
|
+
* mainnet — the catalog's `unwrap` edge.
|
|
36
|
+
*
|
|
37
|
+
* Demonstrates:
|
|
38
|
+
* - `routeAmount.all` for a balance resolved on-chain at execution time, where
|
|
39
|
+
* the passed value is only the quoting stand-in
|
|
40
|
+
* - `sweepTo` naming the address that receives the output
|
|
41
|
+
* - `checkOnChainAllowances` so already-sufficient approvals are omitted from
|
|
42
|
+
* the response
|
|
43
|
+
*
|
|
44
|
+
* Pure: returns a plain {@link ComposeRouteRequest}, performs no network I/O.
|
|
45
|
+
*/
|
|
46
|
+
export const buildRouteAllExample = (): ComposeRouteRequest => ({
|
|
47
|
+
chainId: 1,
|
|
48
|
+
fromToken: WETH,
|
|
49
|
+
toToken: NATIVE_ETH,
|
|
50
|
+
// Estimate of the balance on hand — the quote and the derived preconditions
|
|
51
|
+
// are computed against this, but the amount actually moved is the real
|
|
52
|
+
// balance at execution time.
|
|
53
|
+
amount: routeAmount.all(10n ** 18n), // ~1 WETH
|
|
54
|
+
signer: OWNER,
|
|
55
|
+
sweepTo: OWNER,
|
|
56
|
+
slippageBps: 50,
|
|
57
|
+
checkOnChainAllowances: true,
|
|
58
|
+
});
|
package/src/examples/run.ts
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
* split-zap — split USDC 60/40 and zap into Aave + Morpho vaults
|
|
21
21
|
* split-arithmetic — split USDC 70/30 with arithmetic assertions
|
|
22
22
|
* zap — zap USDC into Aave lending position
|
|
23
|
+
* zap-async — zap USDC into an async Aave position (future output)
|
|
23
24
|
* swap-zap — swap WETH to USDC then zap into Aave
|
|
24
25
|
* swap-check — swap WETH to USDC with balance check
|
|
25
26
|
* swap-recipient — swap WETH + DAI to USDC and send to recipient
|
|
@@ -32,8 +33,13 @@
|
|
|
32
33
|
* transfer — transfer full token balance to a recipient
|
|
33
34
|
* partial-transfer — transfer a specific amount, keeping the remainder
|
|
34
35
|
* untyped-ref — mix untypedOp with typed handles via raw.ref
|
|
36
|
+
* route-exact — wrap 0.1 native ETH into WETH via /compose/route
|
|
37
|
+
* route-all — unwrap the whole WETH balance to ETH via /compose/route
|
|
35
38
|
*/
|
|
36
|
-
import type {
|
|
39
|
+
import type {
|
|
40
|
+
ComposeCompileRequest,
|
|
41
|
+
ComposeRouteRequest,
|
|
42
|
+
} from '@lifi/compose-spec';
|
|
37
43
|
|
|
38
44
|
import { createComposeSdk } from '../sdk.js';
|
|
39
45
|
|
|
@@ -49,8 +55,13 @@ import { buildDepositFromProxy } from './depositFromProxy.js';
|
|
|
49
55
|
import { buildDustSweepExample } from './dustSweep.js';
|
|
50
56
|
import { buildLifiSwapExample } from './lifiSwap.js';
|
|
51
57
|
import { buildLifiZapExample } from './lifiZap.js';
|
|
58
|
+
import { buildLifiZapAsyncExample } from './lifiZapAsync.js';
|
|
52
59
|
import { buildRawCallWithArithmetic } from './rawCallWithArithmetic.js';
|
|
53
60
|
import { buildReadContractState } from './readContractState.js';
|
|
61
|
+
import {
|
|
62
|
+
buildRouteAllExample,
|
|
63
|
+
buildRouteExactExample,
|
|
64
|
+
} from './routeTokenPair.js';
|
|
54
65
|
import { buildSplitAndZapExample } from './splitAndZap.js';
|
|
55
66
|
import { buildSplitWithArithmetic } from './splitWithArithmetic.js';
|
|
56
67
|
import { buildSwapAndZapExample } from './swapAndZap.js';
|
|
@@ -106,6 +117,8 @@ const EXAMPLES: Record<string, () => ComposeCompileRequest> = {
|
|
|
106
117
|
'split-arithmetic': () =>
|
|
107
118
|
buildSplitWithArithmetic({ owner: OWNER, amount: '1000000000' }).request,
|
|
108
119
|
zap: () => buildLifiZapExample().request,
|
|
120
|
+
'zap-async': () =>
|
|
121
|
+
buildLifiZapAsyncExample({ owner: OWNER, recipient: RECIPIENT }).request,
|
|
109
122
|
'swap-zap': () => buildSwapAndZapExample().request,
|
|
110
123
|
'swap-check': () =>
|
|
111
124
|
buildSwapWithBalanceCheck({ owner: OWNER, amount: '1000000000000000000' })
|
|
@@ -146,6 +159,13 @@ const EXAMPLES: Record<string, () => ComposeCompileRequest> = {
|
|
|
146
159
|
'untyped-ref': () => buildUntypedOpWithTypedRef({ owner: OWNER }).request,
|
|
147
160
|
};
|
|
148
161
|
|
|
162
|
+
// `/compose/route` examples build a `ComposeRouteRequest` and go to
|
|
163
|
+
// `sdk.route`, not `sdk.client.compile`, so they live in their own registry.
|
|
164
|
+
const ROUTE_EXAMPLES: Record<string, () => ComposeRouteRequest> = {
|
|
165
|
+
'route-exact': buildRouteExactExample,
|
|
166
|
+
'route-all': buildRouteAllExample,
|
|
167
|
+
};
|
|
168
|
+
|
|
149
169
|
const run = async () => {
|
|
150
170
|
const args = process.argv.slice(2);
|
|
151
171
|
const useStaged = args.includes('--staged');
|
|
@@ -166,10 +186,13 @@ const run = async () => {
|
|
|
166
186
|
examples = { ...EXAMPLES, ...stagedModule.STAGED_EXAMPLES };
|
|
167
187
|
}
|
|
168
188
|
|
|
189
|
+
const routeBuilder = name ? ROUTE_EXAMPLES[name] : undefined;
|
|
169
190
|
const builder = name ? examples[name] : undefined;
|
|
170
191
|
|
|
171
|
-
if (!builder) {
|
|
172
|
-
const valid = Object.keys(examples).
|
|
192
|
+
if (!builder && !routeBuilder) {
|
|
193
|
+
const valid = [...Object.keys(examples), ...Object.keys(ROUTE_EXAMPLES)]
|
|
194
|
+
.sort()
|
|
195
|
+
.join(', ');
|
|
173
196
|
console.error(
|
|
174
197
|
`Error: ${
|
|
175
198
|
name ? `unknown example "${name}"` : 'no example specified'
|
|
@@ -181,7 +204,7 @@ const run = async () => {
|
|
|
181
204
|
}
|
|
182
205
|
console.log(`Running example: ${name}`);
|
|
183
206
|
|
|
184
|
-
const request = builder();
|
|
207
|
+
const request = routeBuilder ? routeBuilder() : builder!();
|
|
185
208
|
const sdk = createComposeSdk({ baseUrl: BASE_URL, apiKey: API_KEY });
|
|
186
209
|
|
|
187
210
|
console.log('--- Request ---');
|
|
@@ -195,7 +218,9 @@ const run = async () => {
|
|
|
195
218
|
);
|
|
196
219
|
|
|
197
220
|
console.log(`\n--- Compiling against ${BASE_URL} ---`);
|
|
198
|
-
const result =
|
|
221
|
+
const result = routeBuilder
|
|
222
|
+
? await sdk.route(request as ComposeRouteRequest)
|
|
223
|
+
: await sdk.client.compile(request as ComposeCompileRequest);
|
|
199
224
|
|
|
200
225
|
console.log('\n--- Result ---');
|
|
201
226
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -203,9 +203,14 @@ export interface CoreCallConfig {
|
|
|
203
203
|
)[]
|
|
204
204
|
)[]
|
|
205
205
|
)[];
|
|
206
|
-
approvals?:
|
|
207
|
-
|
|
208
|
-
|
|
206
|
+
approvals?: (
|
|
207
|
+
| {
|
|
208
|
+
spender: Address;
|
|
209
|
+
}
|
|
210
|
+
| {
|
|
211
|
+
from: 'sender';
|
|
212
|
+
}
|
|
213
|
+
)[];
|
|
209
214
|
}
|
|
210
215
|
|
|
211
216
|
export interface CoreStaticCallConfig {
|
|
@@ -684,6 +689,19 @@ export interface LifiZapConfig {
|
|
|
684
689
|
};
|
|
685
690
|
}
|
|
686
691
|
|
|
692
|
+
export interface LifiZapAsyncConfig {
|
|
693
|
+
resourceOut:
|
|
694
|
+
| {
|
|
695
|
+
kind: 'native';
|
|
696
|
+
chainId: Positive;
|
|
697
|
+
}
|
|
698
|
+
| {
|
|
699
|
+
kind: 'erc20';
|
|
700
|
+
token: Address;
|
|
701
|
+
chainId: Positive;
|
|
702
|
+
};
|
|
703
|
+
}
|
|
704
|
+
|
|
687
705
|
export interface ParaswapBuyConfig {
|
|
688
706
|
resourceOut:
|
|
689
707
|
| {
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
// AUTO-GENERATED from manifest.json — do not edit by hand.
|
|
2
2
|
// Regenerate with: yarn workspace @lifi/composer-sdk generate
|
|
3
3
|
|
|
4
|
-
import type {
|
|
5
|
-
AnyBindable,
|
|
6
|
-
FlowBuilderInternal,
|
|
7
|
-
} from '../authoring/FlowBuilderCore.js';
|
|
4
|
+
import type { FlowBuilderInternal } from '../authoring/FlowBuilderCore.js';
|
|
8
5
|
import type { Bindable, OutputHandle } from '../authoring/handles.js';
|
|
9
6
|
import type {
|
|
10
7
|
CoreCallResult,
|
|
@@ -47,6 +44,7 @@ import type {
|
|
|
47
44
|
InvariantNumericConfig,
|
|
48
45
|
InvariantNumericInRangeConfig,
|
|
49
46
|
LifiSwapConfig,
|
|
47
|
+
LifiZapAsyncConfig,
|
|
50
48
|
LifiZapConfig,
|
|
51
49
|
MorphoBlueSupplyCollateralConfig,
|
|
52
50
|
MorphoBlueWithdrawCollateralConfig,
|
|
@@ -520,11 +518,22 @@ export interface MorphoBlueWithdrawCollateralArgs {
|
|
|
520
518
|
export interface LifiZapArgs {
|
|
521
519
|
readonly bind: {
|
|
522
520
|
readonly amountIn: Bindable<'resource'>;
|
|
521
|
+
readonly recipient?: Bindable<'address'>;
|
|
523
522
|
};
|
|
524
523
|
readonly config: LifiZapConfig;
|
|
525
524
|
readonly guards?: readonly TypedGuard<'amountOut'>[];
|
|
526
525
|
}
|
|
527
526
|
|
|
527
|
+
/** Route tokens into a DeFi protocol position whose output becomes available after the initiating transaction settles */
|
|
528
|
+
export interface LifiZapAsyncArgs {
|
|
529
|
+
readonly bind: {
|
|
530
|
+
readonly amountIn: Bindable<'resource'>;
|
|
531
|
+
readonly recipient: Bindable<'address'>;
|
|
532
|
+
};
|
|
533
|
+
readonly config: LifiZapAsyncConfig;
|
|
534
|
+
readonly guards?: readonly TypedGuard<never>[];
|
|
535
|
+
}
|
|
536
|
+
|
|
528
537
|
/** Exact-output (BUY) swap via the Paraswap/Velora Market API: produce exactly `exactAmountOut` of the destination token, pulling only the source needed and exposing the genuinely-unspent source as `unspentIn`. */
|
|
529
538
|
export interface ParaswapBuyArgs {
|
|
530
539
|
readonly bind: {
|
|
@@ -629,6 +638,10 @@ export interface LifiZapOutputs {
|
|
|
629
638
|
readonly amountOut: OutputHandle<'resource'>;
|
|
630
639
|
}
|
|
631
640
|
|
|
641
|
+
export interface LifiZapAsyncOutputs {
|
|
642
|
+
readonly amountOut: OutputHandle<'resource'>;
|
|
643
|
+
}
|
|
644
|
+
|
|
632
645
|
export interface ParaswapBuyOutputs {
|
|
633
646
|
readonly amountOut: OutputHandle<'resource'>;
|
|
634
647
|
readonly unspentIn: OutputHandle<'resource'>;
|
|
@@ -741,6 +754,11 @@ export type GeneratedOps = {
|
|
|
741
754
|
readonly swap: (nodeId: string, args: LifiSwapArgs) => LifiSwapOutputs;
|
|
742
755
|
/** Route tokens into a DeFi protocol position via the edge catalog — original id: "lifi.zap" */
|
|
743
756
|
readonly zap: (nodeId: string, args: LifiZapArgs) => LifiZapOutputs;
|
|
757
|
+
/** Route tokens into a DeFi protocol position whose output becomes available after the initiating transaction settles — original id: "lifi.zapAsync" */
|
|
758
|
+
readonly zapAsync: (
|
|
759
|
+
nodeId: string,
|
|
760
|
+
args: LifiZapAsyncArgs,
|
|
761
|
+
) => LifiZapAsyncOutputs;
|
|
744
762
|
};
|
|
745
763
|
readonly invariant: {
|
|
746
764
|
/** Assert that an account holds at least a minimum token balance — original id: "invariant.balanceAtLeast" */
|
|
@@ -917,8 +935,8 @@ export const bindGeneratedOps = (
|
|
|
917
935
|
call: <TSig extends string>(nodeId: string, args: CoreCallArgs<TSig>) => {
|
|
918
936
|
const wire = buildCallWireFormat({
|
|
919
937
|
resource: args.resource,
|
|
920
|
-
bind: args.bind
|
|
921
|
-
config: args.config
|
|
938
|
+
bind: args.bind,
|
|
939
|
+
config: args.config,
|
|
922
940
|
guards: args.guards,
|
|
923
941
|
});
|
|
924
942
|
return builder.call(nodeId, wire.op, wire, {
|
|
@@ -933,8 +951,8 @@ export const bindGeneratedOps = (
|
|
|
933
951
|
nodeId,
|
|
934
952
|
'core.staticCall',
|
|
935
953
|
buildStaticCallWireFormat({
|
|
936
|
-
bind: args.bind
|
|
937
|
-
config: args.config
|
|
954
|
+
bind: args.bind,
|
|
955
|
+
config: args.config,
|
|
938
956
|
guards: args.guards,
|
|
939
957
|
}),
|
|
940
958
|
{ result: 'uint256' } as const,
|
|
@@ -960,6 +978,10 @@ export const bindGeneratedOps = (
|
|
|
960
978
|
builder.call(nodeId, 'lifi.zap', args, {
|
|
961
979
|
amountOut: 'resource',
|
|
962
980
|
} as const),
|
|
981
|
+
zapAsync: (nodeId: string, args: LifiZapAsyncArgs) =>
|
|
982
|
+
builder.call(nodeId, 'lifi.zapAsync', args, {
|
|
983
|
+
amountOut: 'resource',
|
|
984
|
+
} as const),
|
|
963
985
|
},
|
|
964
986
|
invariant: {
|
|
965
987
|
balanceAtLeast: (nodeId: string, args: InvariantBalanceAtLeastArgs) =>
|
package/src/index.ts
CHANGED
|
@@ -41,6 +41,7 @@ export type {
|
|
|
41
41
|
ComposeCompileSuccessData,
|
|
42
42
|
ComposeContinuation,
|
|
43
43
|
ComposeErrorKind,
|
|
44
|
+
ComposeRouteRequest,
|
|
44
45
|
ComposeTransactionRequest,
|
|
45
46
|
FailedPreparedOp,
|
|
46
47
|
Flow,
|
|
@@ -52,6 +53,9 @@ export type {
|
|
|
52
53
|
PriceImpact,
|
|
53
54
|
Ref,
|
|
54
55
|
Resource,
|
|
56
|
+
RouteAmount,
|
|
57
|
+
RouteAmountAll,
|
|
58
|
+
RouteAmountExact,
|
|
55
59
|
SimulationPolicy,
|
|
56
60
|
SimulationRevert,
|
|
57
61
|
SolType,
|
|
@@ -108,6 +112,7 @@ import * as materialisersMod from './generated/materialisers.generated.js';
|
|
|
108
112
|
import * as preconditionsMod from './generated/preconditions.generated.js';
|
|
109
113
|
import * as rawMod from './raw.js';
|
|
110
114
|
import * as resourcesMod from './resources.js';
|
|
115
|
+
import * as routeAmountMod from './routeAmount.js';
|
|
111
116
|
|
|
112
117
|
/**
|
|
113
118
|
* Guard factories for protecting operation outputs (e.g. slippage tolerance).
|
|
@@ -168,6 +173,24 @@ export const preconditions: typeof preconditionsMod = preconditionsMod;
|
|
|
168
173
|
* ```
|
|
169
174
|
*/
|
|
170
175
|
export const resources: typeof resourcesMod = resourcesMod;
|
|
176
|
+
/**
|
|
177
|
+
* Amount constructors for {@link ComposeSdk.route}. Use
|
|
178
|
+
* {@link routeAmount.exact} to spend a fixed amount of the `fromToken`, and
|
|
179
|
+
* {@link routeAmount.all} to spend the signer's whole balance.
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* ```ts
|
|
183
|
+
* // USDC into the Aave v3 aEthUSDC position — one routing-catalog edge.
|
|
184
|
+
* const result = await sdk.route({
|
|
185
|
+
* chainId: 1,
|
|
186
|
+
* fromToken: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
|
|
187
|
+
* toToken: '0x98C23E9d8f34FEFb1B7BD6a91B7FF122F4e16F5c',
|
|
188
|
+
* amount: routeAmount.exact(1_000_000n),
|
|
189
|
+
* signer: '0xYourAddress...',
|
|
190
|
+
* });
|
|
191
|
+
* ```
|
|
192
|
+
*/
|
|
193
|
+
export const routeAmount: typeof routeAmountMod = routeAmountMod;
|
|
171
194
|
export * from './generated/config.generated.js';
|
|
172
195
|
|
|
173
196
|
/**
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { RouteAmountAll, RouteAmountExact } from '@lifi/compose-spec';
|
|
2
|
+
|
|
3
|
+
// Constructors for the `amount` member of a `ComposeRouteRequest`. The wire
|
|
4
|
+
// union is discriminated by `type` and — deliberately, because the two variants
|
|
5
|
+
// mean different things — names its payload field differently in each variant:
|
|
6
|
+
// `amount` is the sum actually moved, `simAmount` is only a quoting stand-in for
|
|
7
|
+
// a balance resolved on-chain. These helpers keep call sites from having to
|
|
8
|
+
// remember which name goes with which discriminant.
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Spend an exact amount of the route's `fromToken`.
|
|
12
|
+
*
|
|
13
|
+
* @param amount - Amount in the token's smallest unit. `bigint` is serialised
|
|
14
|
+
* to a decimal string when the request is sent.
|
|
15
|
+
* @returns The `EXACT` member of the route amount union.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* const result = await sdk.route({
|
|
20
|
+
* chainId: 1,
|
|
21
|
+
* fromToken: NATIVE_ETH,
|
|
22
|
+
* toToken: WETH,
|
|
23
|
+
* amount: routeAmount.exact(10n ** 17n), // 0.1 ETH, wrapped
|
|
24
|
+
* signer: OWNER,
|
|
25
|
+
* });
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export const exact = (amount: bigint | string): RouteAmountExact => ({
|
|
29
|
+
type: 'EXACT',
|
|
30
|
+
amount,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Spend the signer's entire `fromToken` balance, resolved on-chain at execution
|
|
35
|
+
* time.
|
|
36
|
+
*
|
|
37
|
+
* Not supported when `fromToken` is the chain's native sentinel — the server
|
|
38
|
+
* rejects it. A gas coin is sent via `msg.value`, so there is no on-chain
|
|
39
|
+
* balance to sweep; use {@link exact} for native inputs.
|
|
40
|
+
*
|
|
41
|
+
* @param simAmount - A realistic estimate of that balance, in the token's
|
|
42
|
+
* smallest unit. The server quotes and simulates against this value, so it
|
|
43
|
+
* shapes the returned quote and preconditions — but the amount actually moved
|
|
44
|
+
* is whatever the balance turns out to be.
|
|
45
|
+
* @returns The `ALL` member of the route amount union.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```ts
|
|
49
|
+
* const result = await sdk.route({
|
|
50
|
+
* chainId: 1,
|
|
51
|
+
* fromToken: USDC,
|
|
52
|
+
* toToken: A_ETH_USDC,
|
|
53
|
+
* amount: routeAmount.all(1_000_000n), // estimate: ~1 USDC on hand
|
|
54
|
+
* signer: OWNER,
|
|
55
|
+
* });
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export const all = (simAmount: bigint | string): RouteAmountAll => ({
|
|
59
|
+
type: 'ALL',
|
|
60
|
+
simAmount,
|
|
61
|
+
});
|
package/src/sdk.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
ComposeCompileRequest,
|
|
3
3
|
ComposeCompileResult,
|
|
4
|
+
ComposeRouteRequest,
|
|
4
5
|
InputSpec,
|
|
5
6
|
SimulateRequest,
|
|
6
7
|
SimulateResult,
|
|
@@ -119,6 +120,21 @@ export interface ComposeSdk {
|
|
|
119
120
|
flow: TypedFlow<T>,
|
|
120
121
|
run: ComposeRunInput<T>,
|
|
121
122
|
) => ComposeCompileRequest;
|
|
123
|
+
/**
|
|
124
|
+
* Compiles a token pair on one chain — as of today a single zap step over
|
|
125
|
+
* one routing-catalog edge. Thin pass-through to
|
|
126
|
+
* {@link ComposeClient.route}; see it for the current single-step limit,
|
|
127
|
+
* when to prefer `flow(...).compile(...)`, the `success` / `partial`
|
|
128
|
+
* discrimination, and error behaviour. Build the `amount` with
|
|
129
|
+
* `routeAmount.exact(...)` / `routeAmount.all(...)`.
|
|
130
|
+
*
|
|
131
|
+
* @param request - The from/to token pair, amount, signer, and route options.
|
|
132
|
+
* @returns A discriminated result: `status: 'success'` or `status: 'partial'`.
|
|
133
|
+
* @throws {@link ComposeError} on network, validation, or server errors.
|
|
134
|
+
*/
|
|
135
|
+
readonly route: (
|
|
136
|
+
request: ComposeRouteRequest,
|
|
137
|
+
) => Promise<ComposeCompileResult>;
|
|
122
138
|
/**
|
|
123
139
|
* Simulates a raw, pre-encoded transaction. Thin pass-through to
|
|
124
140
|
* {@link ComposeClient.simulate}; see it for the `ok` / `revert` / `error`
|
|
@@ -188,6 +204,7 @@ export const createComposeSdk = (options: ComposeSdkOptions): ComposeSdk => {
|
|
|
188
204
|
client: composeClient,
|
|
189
205
|
flow,
|
|
190
206
|
request,
|
|
207
|
+
route: composeClient.route,
|
|
191
208
|
simulate: composeClient.simulate,
|
|
192
209
|
};
|
|
193
210
|
};
|