@lifi/composer-sdk 0.11.3 → 0.13.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/README.md +3 -3
- package/dist/authoring/raw.cjs +10 -2
- package/dist/authoring/raw.cjs.map +1 -1
- package/dist/authoring/raw.d.cts +10 -2
- package/dist/authoring/raw.d.ts +10 -2
- package/dist/authoring/raw.js +10 -2
- package/dist/authoring/raw.js.map +1 -1
- package/dist/authoring/signatureArgs.cjs +10 -3
- package/dist/authoring/signatureArgs.cjs.map +1 -1
- package/dist/authoring/signatureArgs.d.cts +23 -16
- package/dist/authoring/signatureArgs.d.ts +23 -16
- package/dist/authoring/signatureArgs.js +10 -3
- package/dist/authoring/signatureArgs.js.map +1 -1
- package/dist/client.cjs +1 -1
- package/dist/client.js +1 -1
- package/dist/generated/config.generated.d.cts +6 -18
- package/dist/generated/config.generated.d.ts +6 -18
- package/dist/generated/operations.generated.cjs.map +1 -1
- package/dist/generated/operations.generated.d.cts +1 -1
- package/dist/generated/operations.generated.d.ts +1 -1
- package/dist/generated/operations.generated.js.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js.map +1 -1
- package/dist/run/inputs.cjs +0 -1
- package/dist/run/inputs.cjs.map +1 -1
- package/dist/run/inputs.d.cts +0 -8
- package/dist/run/inputs.d.ts +0 -8
- package/dist/run/inputs.js +0 -1
- package/dist/run/inputs.js.map +1 -1
- package/dist/sdk.cjs +0 -1
- package/dist/sdk.cjs.map +1 -1
- package/dist/sdk.js +0 -1
- package/dist/sdk.js.map +1 -1
- package/package.json +2 -2
- package/src/authoring/raw.ts +10 -2
- package/src/authoring/signatureArgs.ts +53 -23
- package/src/examples/continuationBridgeSettle.ts +1 -2
- package/src/examples/continuationExactInvoice.ts +341 -0
- package/src/examples/continuationSettle.ts +1 -1
- package/src/examples/run.ts +27 -0
- package/src/generated/config.generated.ts +16 -31
- package/src/generated/operations.generated.ts +1 -1
- package/src/index.ts +2 -1
- package/src/run/inputs.ts +0 -9
- package/src/sdk.ts +0 -1
- package/src/examples/swapWithFee.ts +0 -59
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
import type { ComposeCompileRequest, Flow } from '@lifi/compose-spec';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
type ComposeSdk,
|
|
5
|
+
type ContinuationSettleConfig,
|
|
6
|
+
createComposeSdk,
|
|
7
|
+
materialisers,
|
|
8
|
+
raw,
|
|
9
|
+
resources,
|
|
10
|
+
} from '../index.js';
|
|
11
|
+
import type { Address } from '../types.js';
|
|
12
|
+
|
|
13
|
+
import { API_KEY, BASE_URL, RECIPIENT } from './config.js';
|
|
14
|
+
|
|
15
|
+
const ARBITRUM = 42161;
|
|
16
|
+
const BASE = 8453;
|
|
17
|
+
const ARB_USDC = '0xaf88d065e77c8cC2239327C5EDb3A432268e5831';
|
|
18
|
+
const USDC = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';
|
|
19
|
+
const WETH = '0x4200000000000000000000000000000000000006';
|
|
20
|
+
// Request Network's ERC20FeeProxy on Base. It moves `amount` to `to` and
|
|
21
|
+
// `feeAmount` to `feeAddress` from the caller with `transferFrom`, and emits
|
|
22
|
+
// `TransferWithReferenceAndFee` with the payment reference: the event that
|
|
23
|
+
// marks the invoice paid.
|
|
24
|
+
const ERC20_FEE_PROXY = '0x1892196E80C4c17ea5100Da765Ab48c1fE2Fb814';
|
|
25
|
+
const VALIDITY_WINDOW_MS = 3_600_000;
|
|
26
|
+
|
|
27
|
+
/** A Request Network invoice payable in USDC on Base. */
|
|
28
|
+
export interface UsdcInvoice {
|
|
29
|
+
readonly payee: Address;
|
|
30
|
+
// USDC base units (6 decimals) paid to `payee`.
|
|
31
|
+
readonly amount: bigint;
|
|
32
|
+
// USDC base units paid to `feeAddress`; may be 0.
|
|
33
|
+
readonly fee: bigint;
|
|
34
|
+
readonly feeAddress: Address;
|
|
35
|
+
// The invoice's payment reference (8 bytes for Request Network).
|
|
36
|
+
readonly paymentReference: `0x${string}`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// A sample invoice for the examples: 990 USDC to the payee plus a 10 USDC fee.
|
|
40
|
+
export const SAMPLE_INVOICE: UsdcInvoice = {
|
|
41
|
+
payee: RECIPIENT,
|
|
42
|
+
amount: 990_000_000n,
|
|
43
|
+
fee: 10_000_000n,
|
|
44
|
+
feeAddress: '0x2222222222222222222222222222222222222222',
|
|
45
|
+
paymentReference: '0x8c6f1d3b4a5e7c21',
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export interface ContinuationExactInvoiceInput {
|
|
49
|
+
readonly owner: Address;
|
|
50
|
+
readonly invoice: UsdcInvoice;
|
|
51
|
+
// USDC base units the escrow is funded with. Must exceed
|
|
52
|
+
// `invoice.amount + invoice.fee`: the surplus, the settle's only outcome,
|
|
53
|
+
// returns to `owner`, and an outcome must commit a positive floor.
|
|
54
|
+
readonly usdcAmount: `${bigint}`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface ContinuationExactSwapInvoiceInput {
|
|
58
|
+
readonly owner: Address;
|
|
59
|
+
readonly invoice: UsdcInvoice;
|
|
60
|
+
// WETH base units (18 decimals) swapped to USDC. The swap's guaranteed
|
|
61
|
+
// minimum output must exceed `invoice.amount + invoice.fee`, for the same
|
|
62
|
+
// reason as `usdcAmount` above.
|
|
63
|
+
readonly wethAmount: `${bigint}`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface ContinuationExactIntentInvoiceInput {
|
|
67
|
+
readonly owner: Address;
|
|
68
|
+
readonly invoice: UsdcInvoice;
|
|
69
|
+
// Native ETH base units (18 decimals) on Arbitrum, swapped to Arbitrum
|
|
70
|
+
// USDC. The swap's guaranteed minimum output must cover the input the
|
|
71
|
+
// solver asks for the invoice total plus one unit; the rest returns to
|
|
72
|
+
// `owner`.
|
|
73
|
+
readonly ethAmount: `${bigint}`;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* The leg every example settles: split the invoice total off the escrowed
|
|
78
|
+
* USDC, pay it through `ERC20FeeProxy`, and leave the surplus in the leg's
|
|
79
|
+
* proxy as the settle's outcome, if the settle commits one.
|
|
80
|
+
*
|
|
81
|
+
* `core.call` declares no settlement verification, so only an exact settle
|
|
82
|
+
* may run it. The invoice terms are constants of the leg document, so each
|
|
83
|
+
* argument is a `raw.literal` of the parameter's Solidity type. The leg names
|
|
84
|
+
* no funding amount: at fill the executor's proxy sweeps the escrowed USDC
|
|
85
|
+
* into `input.funding`.
|
|
86
|
+
*/
|
|
87
|
+
const buildInvoiceLeg = (sdk: ComposeSdk, invoice: UsdcInvoice): Flow => {
|
|
88
|
+
const leg = sdk.flow(BASE, {
|
|
89
|
+
name: 'pay-invoice-leg',
|
|
90
|
+
inputs: { funding: resources.erc20(USDC, BASE) },
|
|
91
|
+
});
|
|
92
|
+
// `head` is the invoice total; `tail`, the surplus, stays in the proxy.
|
|
93
|
+
const { head } = leg.core.splitAt('invoice', {
|
|
94
|
+
bind: { source: leg.inputs.funding },
|
|
95
|
+
config: { amount: `${invoice.amount + invoice.fee}` },
|
|
96
|
+
});
|
|
97
|
+
leg.core.call('pay', {
|
|
98
|
+
resource: head,
|
|
99
|
+
bind: {
|
|
100
|
+
tokenAddress: raw.literal('address', USDC),
|
|
101
|
+
to: raw.literal('address', invoice.payee),
|
|
102
|
+
amount: raw.literal('uint256', `${invoice.amount}`),
|
|
103
|
+
paymentReference: raw.literal('bytes', invoice.paymentReference),
|
|
104
|
+
feeAmount: raw.literal('uint256', `${invoice.fee}`),
|
|
105
|
+
feeAddress: raw.literal('address', invoice.feeAddress),
|
|
106
|
+
},
|
|
107
|
+
config: {
|
|
108
|
+
target: ERC20_FEE_PROXY,
|
|
109
|
+
functionSignature:
|
|
110
|
+
'function transferFromWithReferenceAndFee(address tokenAddress, address to, uint256 amount, bytes paymentReference, uint256 feeAmount, address feeAddress)',
|
|
111
|
+
// The fee proxy pulls the USDC with `transferFrom`.
|
|
112
|
+
approvals: [{ spender: ERC20_FEE_PROXY }],
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
return leg.build();
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* The exact settle config every example shares: the leg's leftover USDC
|
|
120
|
+
* returns to `owner` on Base, and so does the escrow if it expires unfilled.
|
|
121
|
+
*/
|
|
122
|
+
const invoiceSettleConfig = (
|
|
123
|
+
sdk: ComposeSdk,
|
|
124
|
+
owner: Address,
|
|
125
|
+
invoice: UsdcInvoice,
|
|
126
|
+
): ContinuationSettleConfig => ({
|
|
127
|
+
exact: true,
|
|
128
|
+
outcomes: [{ token: USDC, destination: owner, chainId: BASE }],
|
|
129
|
+
validity: { expiresAtMs: Date.now() + VALIDITY_WINDOW_MS },
|
|
130
|
+
provider: 'intent-factory',
|
|
131
|
+
refund: owner,
|
|
132
|
+
continuationFlow: buildInvoiceLeg(sdk, invoice),
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Escrow USDC on Base for an exact continuation leg that pays a Request
|
|
137
|
+
* Network invoice, and return the surplus to the owner.
|
|
138
|
+
*
|
|
139
|
+
* Demonstrates:
|
|
140
|
+
* - `exact: true` on `continuation.settle`: the escrow is bound to the leg's
|
|
141
|
+
* compiled calldata, so the solver runs exactly those bytes and chooses
|
|
142
|
+
* nothing. A committed (non-exact) leg rejects `core.call`, because a
|
|
143
|
+
* balance cannot prove that an invoice was paid; an exact leg admits it.
|
|
144
|
+
* - A leg that pays a third party (`invoice.payee`), which only an exact leg
|
|
145
|
+
* may do: its bytes are fixed at compile time.
|
|
146
|
+
* - The surplus (`usdcAmount` minus the invoice total) as the outcome. The
|
|
147
|
+
* compile proves its floor at the escrow's funding floor, so `minAmount` is
|
|
148
|
+
* omitted. A surplus of 0 proves no floor, and the compile rejects it.
|
|
149
|
+
* - Funding from a declared input, transferred into the escrow inline by the
|
|
150
|
+
* user's transaction.
|
|
151
|
+
*
|
|
152
|
+
* Reading the response:
|
|
153
|
+
* - `settlements.settle.escrow` holds the registered escrow. `binding` holds
|
|
154
|
+
* what the escrow is bound to: the solver's executor (`executionTarget`),
|
|
155
|
+
* the compiled leg (`calldata`), its `approvals`, and the `payload` the
|
|
156
|
+
* settlement service hashes into `payloadHash`.
|
|
157
|
+
* - Inline funding means the user's `execute` transaction funds the escrow.
|
|
158
|
+
* Before submitting it, check that `payloadHash` is the hash of `payload`,
|
|
159
|
+
* for example with viem:
|
|
160
|
+
* `keccak256(binding.payload) === binding.payloadHash.toLowerCase()`.
|
|
161
|
+
* On a mismatch, do not submit.
|
|
162
|
+
*
|
|
163
|
+
* The exact-leg rules:
|
|
164
|
+
* - No leg node may quote off-chain or declare an expiring route:
|
|
165
|
+
* `lifi.swap`, `paraswap.buy`, `core.peek` and any prepared op fail
|
|
166
|
+
* `validation_error` at the leg node, because the bound bytes cannot be
|
|
167
|
+
* re-quoted at fill.
|
|
168
|
+
* - The settle's funding must be an ERC-20 from a declared input, an upstream
|
|
169
|
+
* output, or a `lifi.bridge` or `lifiIntents.order` delivery into the
|
|
170
|
+
* escrow: native funding fails `validation_error`.
|
|
171
|
+
* - The deployment must serve exact legs (an intent-factory provider
|
|
172
|
+
* configured with the solver's executor); elsewhere the settle fails
|
|
173
|
+
* `validation_error` before any registration.
|
|
174
|
+
*/
|
|
175
|
+
export const buildContinuationExactInvoiceExample = ({
|
|
176
|
+
owner,
|
|
177
|
+
invoice,
|
|
178
|
+
usdcAmount,
|
|
179
|
+
}: ContinuationExactInvoiceInput): {
|
|
180
|
+
flow: Flow;
|
|
181
|
+
request: ComposeCompileRequest;
|
|
182
|
+
} => {
|
|
183
|
+
const sdk = createComposeSdk({ baseUrl: BASE_URL, apiKey: API_KEY });
|
|
184
|
+
|
|
185
|
+
const builder = sdk.flow(BASE, {
|
|
186
|
+
name: 'pay-invoice',
|
|
187
|
+
inputs: { usdc: resources.erc20(USDC, BASE) },
|
|
188
|
+
});
|
|
189
|
+
builder.continuation.settle('settle', {
|
|
190
|
+
bind: { input: builder.inputs.usdc },
|
|
191
|
+
config: invoiceSettleConfig(sdk, owner, invoice),
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
const flow = builder.build();
|
|
195
|
+
|
|
196
|
+
// No `sweepTo`: the funding moves into the escrow, and the surplus reaches
|
|
197
|
+
// the owner through the settlement, never through the user's proxy.
|
|
198
|
+
const request = sdk.request(flow, {
|
|
199
|
+
signer: owner,
|
|
200
|
+
inputs: {
|
|
201
|
+
usdc: materialisers.directDeposit({ amount: usdcAmount }),
|
|
202
|
+
},
|
|
203
|
+
// The price-impact check compares the flow's input value with its output
|
|
204
|
+
// value. The invoice payment leaves the flow, so the check would count it
|
|
205
|
+
// as lost value (1,050 USDC in, a 50 USDC surplus out: 95% impact) and
|
|
206
|
+
// reject the compile. `0` disables the check.
|
|
207
|
+
maxPriceImpactBps: 0,
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
return { flow, request };
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Pay the same USDC invoice from WETH: the user's transaction swaps WETH to
|
|
215
|
+
* USDC and escrows the swap output for the exact leg.
|
|
216
|
+
*
|
|
217
|
+
* Demonstrates:
|
|
218
|
+
* - An exact settle funded by an upstream output (`swap.amountOut`). The
|
|
219
|
+
* escrow's funding floor is the swap's guaranteed minimum output, and the
|
|
220
|
+
* leg is proven at that floor, so the minimum must exceed the invoice total.
|
|
221
|
+
* - The quote rule applies to the leg only. The main flow runs inside the
|
|
222
|
+
* user's transaction, so its `lifi.swap` may quote; the leg, bound to fixed
|
|
223
|
+
* bytes until the fill, may not.
|
|
224
|
+
*/
|
|
225
|
+
export const buildContinuationExactSwapInvoiceExample = ({
|
|
226
|
+
owner,
|
|
227
|
+
invoice,
|
|
228
|
+
wethAmount,
|
|
229
|
+
}: ContinuationExactSwapInvoiceInput): {
|
|
230
|
+
flow: Flow;
|
|
231
|
+
request: ComposeCompileRequest;
|
|
232
|
+
} => {
|
|
233
|
+
const sdk = createComposeSdk({ baseUrl: BASE_URL, apiKey: API_KEY });
|
|
234
|
+
|
|
235
|
+
const builder = sdk.flow(BASE, {
|
|
236
|
+
name: 'swap-and-pay-invoice',
|
|
237
|
+
inputs: { weth: resources.erc20(WETH, BASE) },
|
|
238
|
+
});
|
|
239
|
+
const swap = builder.lifi.swap('swap', {
|
|
240
|
+
bind: { amountIn: builder.inputs.weth },
|
|
241
|
+
config: { resourceOut: resources.erc20(USDC, BASE) },
|
|
242
|
+
});
|
|
243
|
+
builder.continuation.settle('settle', {
|
|
244
|
+
bind: { input: swap.amountOut },
|
|
245
|
+
config: invoiceSettleConfig(sdk, owner, invoice),
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
const flow = builder.build();
|
|
249
|
+
|
|
250
|
+
const request = sdk.request(flow, {
|
|
251
|
+
signer: owner,
|
|
252
|
+
inputs: {
|
|
253
|
+
weth: materialisers.directDeposit({ amount: wethAmount }),
|
|
254
|
+
},
|
|
255
|
+
// The invoice payment leaves the flow, so the price-impact check would
|
|
256
|
+
// count it as lost value. `0` disables the check, and with it the only
|
|
257
|
+
// bound on the swap's price against the market. The swap's minimum output
|
|
258
|
+
// bounds only slippage against its own quote. Before signing, compare
|
|
259
|
+
// that minimum (`settlements.settle.escrow.floor` in the response) with
|
|
260
|
+
// an independent WETH price.
|
|
261
|
+
maxPriceImpactBps: 0,
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
return { flow, request };
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Pay the same USDC invoice on Base from ETH on Arbitrum: the user's
|
|
269
|
+
* transaction swaps ETH to Arbitrum USDC and opens an exact-output LI.FI
|
|
270
|
+
* Intents order whose solver delivers Base USDC into the escrow.
|
|
271
|
+
*
|
|
272
|
+
* Demonstrates:
|
|
273
|
+
* - An exact settle funded by a `lifiIntents.order` delivery: the order omits
|
|
274
|
+
* `destination`, the solver delivers into the escrow on Base, and the user
|
|
275
|
+
* signs one transaction on Arbitrum.
|
|
276
|
+
* - `exactAmountOut` `T`, the invoice total, and `outcomes: []`. The leg pays
|
|
277
|
+
* all of `T`, so nothing is left on Base and the settle commits no outcome.
|
|
278
|
+
* An outcome would need a positive floor, so it would cost an extra unit of
|
|
279
|
+
* funding that only lands on Base as dust.
|
|
280
|
+
* - The escrow registers at `T` itself, with no drift margin: an exact-output
|
|
281
|
+
* order delivers exactly `T` on both of the compile's quotes, so the leg
|
|
282
|
+
* compiles at `T`.
|
|
283
|
+
*
|
|
284
|
+
* Sizing the deposit:
|
|
285
|
+
* - The solver quotes the Arbitrum USDC input `X` it needs for exactly `T`,
|
|
286
|
+
* and the order pulls exactly `X`. The swap's minimum output must cover
|
|
287
|
+
* `X`, or the compile fails with a 422 `preparation_error` whose failed op
|
|
288
|
+
* is a `validation_error` naming both amounts. Deposit enough ETH for the
|
|
289
|
+
* swap's minimum to clear `X` with room to spare.
|
|
290
|
+
* - The rest of the swap output (`order.unspentIn`) returns to `owner` as
|
|
291
|
+
* Arbitrum USDC through `sweepTo`, in the same transaction. All slack
|
|
292
|
+
* (swap slippage, the solver's price, the sizing buffer) lands there, not
|
|
293
|
+
* on Base.
|
|
294
|
+
*/
|
|
295
|
+
export const buildContinuationExactIntentInvoiceExample = ({
|
|
296
|
+
owner,
|
|
297
|
+
invoice,
|
|
298
|
+
ethAmount,
|
|
299
|
+
}: ContinuationExactIntentInvoiceInput): {
|
|
300
|
+
flow: Flow;
|
|
301
|
+
request: ComposeCompileRequest;
|
|
302
|
+
} => {
|
|
303
|
+
const sdk = createComposeSdk({ baseUrl: BASE_URL, apiKey: API_KEY });
|
|
304
|
+
|
|
305
|
+
const builder = sdk.flow(ARBITRUM, {
|
|
306
|
+
name: 'intent-and-pay-invoice',
|
|
307
|
+
inputs: { eth: resources.native(ARBITRUM) },
|
|
308
|
+
});
|
|
309
|
+
const swap = builder.lifi.swap('swap', {
|
|
310
|
+
bind: { amountIn: builder.inputs.eth },
|
|
311
|
+
config: { resourceOut: resources.erc20(ARB_USDC, ARBITRUM) },
|
|
312
|
+
});
|
|
313
|
+
const order = builder.lifiIntents.order('order', {
|
|
314
|
+
bind: { amountIn: swap.amountOut },
|
|
315
|
+
config: {
|
|
316
|
+
resourceOut: resources.erc20(USDC, BASE),
|
|
317
|
+
exactAmountOut: `${invoice.amount + invoice.fee}`,
|
|
318
|
+
},
|
|
319
|
+
});
|
|
320
|
+
builder.continuation.settle('settle', {
|
|
321
|
+
bind: { input: order.amountOut },
|
|
322
|
+
config: { ...invoiceSettleConfig(sdk, owner, invoice), outcomes: [] },
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
const flow = builder.build();
|
|
326
|
+
|
|
327
|
+
const request = sdk.request(flow, {
|
|
328
|
+
signer: owner,
|
|
329
|
+
inputs: {
|
|
330
|
+
eth: materialisers.directDeposit({ amount: ethAmount }),
|
|
331
|
+
},
|
|
332
|
+
// Returns the order's unspent Arbitrum USDC to the owner.
|
|
333
|
+
sweepTo: owner,
|
|
334
|
+
// The invoice payment leaves the flow, so the price-impact check would
|
|
335
|
+
// count it as lost value. `0` disables the check; the swap is then bounded
|
|
336
|
+
// only by its slippage against its own quote.
|
|
337
|
+
maxPriceImpactBps: 0,
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
return { flow, request };
|
|
341
|
+
};
|
|
@@ -50,7 +50,7 @@ export interface ContinuationSettleInput {
|
|
|
50
50
|
* settlement account, not the user). Never set the leg's own epilogue. At
|
|
51
51
|
* commit the composer appends the settlement epilogue, which forwards each
|
|
52
52
|
* outcome to the provider's recipient and the residual to `refund`.
|
|
53
|
-
* - Omit `funding`
|
|
53
|
+
* - Omit `funding` when the settle input is a bridge's
|
|
54
54
|
* `amountOut` (see `continuationBridgeSettle.ts`).
|
|
55
55
|
* - `minAmount` is optional: a guard or an op floor on the outcome token
|
|
56
56
|
* proves it, and an unconsumed funding input proves the full funding floor.
|
package/src/examples/run.ts
CHANGED
|
@@ -18,6 +18,9 @@
|
|
|
18
18
|
* consolidate-eth — consolidate ERC-20 balances to native ETH
|
|
19
19
|
* continuation-settle — swap USDC to WETH on Base, escrow it for a deferred settlement
|
|
20
20
|
* continuation-bridge-settle — bridge Arbitrum USDC into a Base settlement escrow
|
|
21
|
+
* continuation-exact-invoice — escrow USDC on Base for an exact leg that pays a Request Network invoice
|
|
22
|
+
* continuation-exact-swap-invoice — swap WETH to USDC on Base, escrow it for the same exact invoice leg
|
|
23
|
+
* continuation-exact-intent-invoice — swap Arbitrum ETH to USDC, order exactly the invoice total on Base for the same exact leg, with no outcome
|
|
21
24
|
* deposit-proxy — deposit tokens already on the proxy into Aave
|
|
22
25
|
* dust-sweep — split USDC 80/20 and sweep leftover dust
|
|
23
26
|
* swap — swap WETH to USDC via LI.FI
|
|
@@ -65,6 +68,12 @@ import { API_KEY, BASE_URL, OWNER, PROXY, RECIPIENT } from './config.js';
|
|
|
65
68
|
import { buildConsolidateToEth } from './consolidateToEth.js';
|
|
66
69
|
import { buildConsolidateStablesToUsdc } from './consolidateToUsdc.js';
|
|
67
70
|
import { buildContinuationBridgeSettleExample } from './continuationBridgeSettle.js';
|
|
71
|
+
import {
|
|
72
|
+
buildContinuationExactIntentInvoiceExample,
|
|
73
|
+
buildContinuationExactInvoiceExample,
|
|
74
|
+
buildContinuationExactSwapInvoiceExample,
|
|
75
|
+
SAMPLE_INVOICE,
|
|
76
|
+
} from './continuationExactInvoice.js';
|
|
68
77
|
import { buildContinuationSettleExample } from './continuationSettle.js';
|
|
69
78
|
import { buildDepositFromProxy } from './depositFromProxy.js';
|
|
70
79
|
import { buildDustSweepExample } from './dustSweep.js';
|
|
@@ -142,6 +151,24 @@ const EXAMPLES: Record<string, () => ComposeCompileRequest> = {
|
|
|
142
151
|
buildContinuationSettleExample({ owner: OWNER }).request,
|
|
143
152
|
'continuation-bridge-settle': () =>
|
|
144
153
|
buildContinuationBridgeSettleExample({ owner: OWNER }).request,
|
|
154
|
+
'continuation-exact-invoice': () =>
|
|
155
|
+
buildContinuationExactInvoiceExample({
|
|
156
|
+
owner: OWNER,
|
|
157
|
+
invoice: SAMPLE_INVOICE,
|
|
158
|
+
usdcAmount: '1050000000',
|
|
159
|
+
}).request,
|
|
160
|
+
'continuation-exact-swap-invoice': () =>
|
|
161
|
+
buildContinuationExactSwapInvoiceExample({
|
|
162
|
+
owner: OWNER,
|
|
163
|
+
invoice: SAMPLE_INVOICE,
|
|
164
|
+
wethAmount: '1000000000000000000',
|
|
165
|
+
}).request,
|
|
166
|
+
'continuation-exact-intent-invoice': () =>
|
|
167
|
+
buildContinuationExactIntentInvoiceExample({
|
|
168
|
+
owner: OWNER,
|
|
169
|
+
invoice: SAMPLE_INVOICE,
|
|
170
|
+
ethAmount: '500000000000000000',
|
|
171
|
+
}).request,
|
|
145
172
|
'deposit-proxy': () =>
|
|
146
173
|
buildDepositFromProxy({
|
|
147
174
|
owner: OWNER,
|
|
@@ -1230,7 +1230,7 @@ export interface ParaswapBuyConfig {
|
|
|
1230
1230
|
*/
|
|
1231
1231
|
partnerAddress?: string;
|
|
1232
1232
|
/**
|
|
1233
|
-
*
|
|
1233
|
+
* Paraswap partner fee in basis points; non-negative integer string capped at 9000.
|
|
1234
1234
|
*/
|
|
1235
1235
|
partnerFeeBps?: string;
|
|
1236
1236
|
}
|
|
@@ -1286,46 +1286,29 @@ export interface FlySwapConfig {
|
|
|
1286
1286
|
export type Between86400000000000008640000000000000 = number;
|
|
1287
1287
|
|
|
1288
1288
|
export interface ContinuationSettleConfig {
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
*/
|
|
1302
|
-
destination: Address;
|
|
1303
|
-
chainId: Positive;
|
|
1304
|
-
},
|
|
1305
|
-
...{
|
|
1306
|
-
/**
|
|
1307
|
-
* EVM address: 0x followed by 40 hex characters
|
|
1308
|
-
*/
|
|
1309
|
-
token: Address;
|
|
1310
|
-
minAmount?: IntegerStringInput;
|
|
1311
|
-
/**
|
|
1312
|
-
* EVM address: 0x followed by 40 hex characters
|
|
1313
|
-
*/
|
|
1314
|
-
destination: Address;
|
|
1315
|
-
chainId: Positive;
|
|
1316
|
-
}[],
|
|
1317
|
-
];
|
|
1289
|
+
outcomes: {
|
|
1290
|
+
/**
|
|
1291
|
+
* EVM address: 0x followed by 40 hex characters
|
|
1292
|
+
*/
|
|
1293
|
+
token: Address;
|
|
1294
|
+
minAmount?: IntegerStringInput;
|
|
1295
|
+
/**
|
|
1296
|
+
* EVM address: 0x followed by 40 hex characters
|
|
1297
|
+
*/
|
|
1298
|
+
destination: Address;
|
|
1299
|
+
chainId: Positive;
|
|
1300
|
+
}[];
|
|
1318
1301
|
continuationFlow?: Flow;
|
|
1319
1302
|
validity: {
|
|
1320
1303
|
expiresAtMs: Between86400000000000008640000000000000;
|
|
1321
1304
|
};
|
|
1322
|
-
perpetual?: boolean;
|
|
1323
1305
|
provider?: string;
|
|
1324
1306
|
funding?: 'inline' | 'external';
|
|
1325
1307
|
/**
|
|
1326
1308
|
* EVM address: 0x followed by 40 hex characters
|
|
1327
1309
|
*/
|
|
1328
1310
|
refund?: Address;
|
|
1311
|
+
exact?: boolean;
|
|
1329
1312
|
}
|
|
1330
1313
|
|
|
1331
1314
|
export interface UniswapV2AddLiquidityConfig {
|
|
@@ -1436,6 +1419,7 @@ export interface LifiIntentsOrderConfig {
|
|
|
1436
1419
|
slippage?: LessThan1;
|
|
1437
1420
|
validitySeconds?: Between1300;
|
|
1438
1421
|
exclusiveSeconds?: Between0120;
|
|
1422
|
+
exactAmountOut?: string;
|
|
1439
1423
|
}
|
|
1440
1424
|
|
|
1441
1425
|
export interface LifiIntentsRefundConfig {
|
|
@@ -1498,6 +1482,7 @@ export type DirectDepositMaterialiserConfig =
|
|
|
1498
1482
|
| {
|
|
1499
1483
|
allowNonExact: true;
|
|
1500
1484
|
simAmount?: string;
|
|
1485
|
+
minAmount?: IntegerStringInput;
|
|
1501
1486
|
};
|
|
1502
1487
|
|
|
1503
1488
|
export interface CallMaterialiserConfig {
|
|
@@ -436,7 +436,7 @@ export interface CoreTransferArgs {
|
|
|
436
436
|
readonly amount: Bindable<'resource'>;
|
|
437
437
|
readonly recipient: Bindable<'address'>;
|
|
438
438
|
};
|
|
439
|
-
readonly config
|
|
439
|
+
readonly config?: CoreTransferConfig;
|
|
440
440
|
readonly guards?: readonly TypedGuard<'transferred'>[];
|
|
441
441
|
}
|
|
442
442
|
|
package/src/index.ts
CHANGED
|
@@ -49,7 +49,6 @@ export type {
|
|
|
49
49
|
ComposeCompilePartialData,
|
|
50
50
|
ComposeAction,
|
|
51
51
|
ComposeFill,
|
|
52
|
-
ComposeFee,
|
|
53
52
|
ComposeUserProgramSimulation,
|
|
54
53
|
ComposeWarning,
|
|
55
54
|
ComposeCompileRequest,
|
|
@@ -100,10 +99,12 @@ export type {
|
|
|
100
99
|
Erc20BalanceRequirement,
|
|
101
100
|
NativeBalanceRequirement,
|
|
102
101
|
Erc20AllowanceRequirement,
|
|
102
|
+
Permit2AllowanceRequirement,
|
|
103
103
|
ContinuationIntent,
|
|
104
104
|
ContinuationOutcome,
|
|
105
105
|
SettlementWire,
|
|
106
106
|
SettlementEscrowWire,
|
|
107
|
+
SettlementBindingWire,
|
|
107
108
|
} from '@lifi/compose-spec';
|
|
108
109
|
export {
|
|
109
110
|
SIMULATE_MAX_TRACKED_BALANCES,
|
package/src/run/inputs.ts
CHANGED
|
@@ -33,13 +33,6 @@ export interface ComposeRunInput<T extends InputSchema = InputSchema> {
|
|
|
33
33
|
readonly assumptions?: { readonly [K in keyof T]?: bigint };
|
|
34
34
|
/** Optional integrator referrer identifier. */
|
|
35
35
|
readonly referrer?: string;
|
|
36
|
-
/**
|
|
37
|
-
* Optional integrator fee in basis points (1bp = 0.01%, max `9000` = 90%).
|
|
38
|
-
* A non-zero value requires the request to be authenticated with an
|
|
39
|
-
* integration-scoped API key — the integration is derived from the key, not
|
|
40
|
-
* this field. Defaults to `0` (no fee) when omitted.
|
|
41
|
-
*/
|
|
42
|
-
readonly integratorFeeBps?: number;
|
|
43
36
|
/** Maximum acceptable price impact in basis points (e.g. `300` = 3%). */
|
|
44
37
|
readonly maxPriceImpactBps?: number;
|
|
45
38
|
/**
|
|
@@ -123,7 +116,6 @@ export const buildRun = (run: {
|
|
|
123
116
|
signer: string;
|
|
124
117
|
assumptions?: Record<string, bigint>;
|
|
125
118
|
referrer?: string;
|
|
126
|
-
integratorFeeBps?: number;
|
|
127
119
|
maxPriceImpactBps?: number;
|
|
128
120
|
sweepTo?: ForwardTo;
|
|
129
121
|
simulationPolicy?: SimulationPolicy;
|
|
@@ -137,7 +129,6 @@ export const buildRun = (run: {
|
|
|
137
129
|
preconditions: run.preconditions?.length ? run.preconditions : undefined,
|
|
138
130
|
assumptions: run.assumptions,
|
|
139
131
|
referrer: run.referrer,
|
|
140
|
-
integratorFeeBps: run.integratorFeeBps,
|
|
141
132
|
maxPriceImpactBps: run.maxPriceImpactBps,
|
|
142
133
|
sweepTo: run.sweepTo,
|
|
143
134
|
simulationPolicy: run.simulationPolicy,
|
package/src/sdk.ts
CHANGED
|
@@ -201,7 +201,6 @@ export const createComposeSdk = (options: ComposeSdkOptions): ComposeSdk => {
|
|
|
201
201
|
signer: run.signer,
|
|
202
202
|
assumptions: run.assumptions as Record<string, bigint> | undefined,
|
|
203
203
|
referrer: run.referrer,
|
|
204
|
-
integratorFeeBps: run.integratorFeeBps,
|
|
205
204
|
maxPriceImpactBps: run.maxPriceImpactBps,
|
|
206
205
|
sweepTo: run.sweepTo,
|
|
207
206
|
simulationPolicy: run.simulationPolicy,
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import type { ComposeCompileRequest, Flow } from '@lifi/compose-spec';
|
|
2
|
-
|
|
3
|
-
import { createComposeSdk, materialisers, resources } from '../index.js';
|
|
4
|
-
|
|
5
|
-
import { API_KEY, BASE_URL, OWNER } from './config.js';
|
|
6
|
-
|
|
7
|
-
const WETH = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2';
|
|
8
|
-
const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Swap WETH to USDC via LI.FI while collecting an integrator fee.
|
|
12
|
-
*
|
|
13
|
-
* Demonstrates:
|
|
14
|
-
* - Setting `integratorFeeBps` on the compile request (50 bps = 0.5%)
|
|
15
|
-
* - The fee is taken on the input token; the backend injects the fee transfer
|
|
16
|
-
*
|
|
17
|
-
* A non-zero `integratorFeeBps` requires the SDK to be configured with an
|
|
18
|
-
* integration-scoped API key (`apiKey`); the integration is derived from the
|
|
19
|
-
* key, not the request body.
|
|
20
|
-
*/
|
|
21
|
-
export const buildSwapWithFeeExample = (): {
|
|
22
|
-
flow: Flow;
|
|
23
|
-
request: ComposeCompileRequest;
|
|
24
|
-
} => {
|
|
25
|
-
const sdk = createComposeSdk({ baseUrl: BASE_URL, apiKey: API_KEY });
|
|
26
|
-
|
|
27
|
-
// Declare the flow with a single WETH input on Ethereum mainnet.
|
|
28
|
-
const builder = sdk.flow(1, {
|
|
29
|
-
name: 'swap-with-fee',
|
|
30
|
-
inputs: {
|
|
31
|
-
amountIn: resources.erc20(WETH, 1),
|
|
32
|
-
},
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
// Swap WETH → USDC via LI.FI.
|
|
36
|
-
builder.lifi.swap('swap', {
|
|
37
|
-
bind: { amountIn: builder.inputs.amountIn },
|
|
38
|
-
config: {
|
|
39
|
-
resourceOut: resources.erc20(USDC, 1),
|
|
40
|
-
slippage: 0.03,
|
|
41
|
-
},
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
const flow = builder.build();
|
|
45
|
-
|
|
46
|
-
// Build the compile request with a 50 bps (0.5%) integrator fee.
|
|
47
|
-
const request = sdk.request(flow, {
|
|
48
|
-
signer: OWNER,
|
|
49
|
-
inputs: {
|
|
50
|
-
amountIn: materialisers.directDeposit({
|
|
51
|
-
amount: '1000000000000000000',
|
|
52
|
-
}),
|
|
53
|
-
},
|
|
54
|
-
integratorFeeBps: 50,
|
|
55
|
-
sweepTo: builder.context.sender,
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
return { flow, request };
|
|
59
|
-
};
|