Skip to content

Commit 1931215

Browse files
committed
feat: repay debt with supply
1 parent 4475132 commit 1931215

File tree

6 files changed

+333
-1
lines changed

6 files changed

+333
-1
lines changed

.changeset/shaggy-flowers-sip.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@aave/graphql": patch
3+
"@aave/client": patch
4+
"@aave/react": patch
5+
---
6+
7+
**feat:** `repayWithSupplyQuote` action, `useRepayWithSupplyQuote` and `useRepayWithSupply` hooks.

packages/client/src/actions/swap.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import type {
77
PrepareBorrowSwapResult,
88
PreparePositionSwapRequest,
99
PreparePositionSwapResult,
10+
PrepareRepayWithSupplyRequest,
11+
PrepareRepayWithSupplyResult,
1012
PrepareSupplySwapRequest,
1113
PrepareSupplySwapResult,
1214
PrepareSwapCancelRequest,
@@ -33,6 +35,7 @@ import {
3335
PreparePositionSwapQuery,
3436
PrepareSwapCancelQuery,
3537
PrepareTokenSwapQuery,
38+
RepayWithSupplyQuoteQuery,
3639
SupplySwapQuoteQuery,
3740
SwapMutation,
3841
SwappableTokensQuery,
@@ -216,6 +219,38 @@ export function borrowSwapQuote(
216219
);
217220
}
218221

222+
/**
223+
* @experimental
224+
* Fetches a repay with supply quote for repaying debt using collateral.
225+
*
226+
* ```ts
227+
* const result = await repayWithSupplyQuote(client, {
228+
* market: {
229+
* sellPosition: userSupplyItemId('collateral_123'),
230+
* buyPosition: userBorrowItemId('debt_456'),
231+
* amount: bigDecimal('1000'),
232+
* user: evmAddress('0x742d35cc...'),
233+
* },
234+
* });
235+
* ```
236+
*
237+
* @param client - Aave client.
238+
* @param request - The repay with supply request parameters.
239+
* @param options - The query options.
240+
* @returns The repay with supply result with quote, approvals, and preview.
241+
*/
242+
export function repayWithSupplyQuote(
243+
client: AaveClient,
244+
request: PrepareRepayWithSupplyRequest,
245+
options: Required<CurrencyQueryOptions> = DEFAULT_QUERY_OPTIONS,
246+
): ResultAsync<PrepareRepayWithSupplyResult, UnexpectedError> {
247+
return client.query(
248+
RepayWithSupplyQuoteQuery,
249+
{ request, currency: options.currency },
250+
{ batch: false },
251+
);
252+
}
253+
219254
/**
220255
* @experimental
221256
* Prepares a position swap by obtaining the typed data for signing.

packages/graphql/src/fragments/swaps.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,22 @@ export const PrepareBorrowSwapResultFragment: FragmentDocumentFor<
466466
[PositionSwapByIntentApprovalsRequiredFragment],
467467
);
468468

469+
export type PrepareRepayWithSupplyResult =
470+
PositionSwapByIntentApprovalsRequired;
471+
472+
export const PrepareRepayWithSupplyResultFragment: FragmentDocumentFor<
473+
PrepareRepayWithSupplyResult,
474+
'PrepareRepayWithSupplyResult'
475+
> = graphql(
476+
`fragment PrepareRepayWithSupplyResult on PrepareRepayWithSupplyResult {
477+
__typename
478+
... on PositionSwapByIntentApprovalsRequired {
479+
...PositionSwapByIntentApprovalsRequired
480+
}
481+
}`,
482+
[PositionSwapByIntentApprovalsRequiredFragment],
483+
);
484+
469485
export type PreparePositionSwapResult = SwapByIntent;
470486

471487
export const PreparePositionSwapResultFragment: FragmentDocumentFor<

packages/graphql/src/swaps.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
PaginatedUserSwapsResultFragment,
44
PrepareBorrowSwapResultFragment,
55
PreparePositionSwapResultFragment,
6+
PrepareRepayWithSupplyResultFragment,
67
PrepareSupplySwapResultFragment,
78
PrepareSwapCancelResultFragment,
89
PrepareTokenSwapResultFragment,
@@ -143,6 +144,21 @@ export const BorrowSwapQuoteQuery = graphql(
143144
);
144145
export type PrepareBorrowSwapRequest = RequestOf<typeof BorrowSwapQuoteQuery>;
145146

147+
/**
148+
* @internal
149+
*/
150+
export const RepayWithSupplyQuoteQuery = graphql(
151+
`query RepayWithSupplyQuote($request: PrepareRepayWithSupplyRequest!, $currency: Currency!) {
152+
value: repayWithSupplyQuote(request: $request) {
153+
...PrepareRepayWithSupplyResult
154+
}
155+
}`,
156+
[PrepareRepayWithSupplyResultFragment],
157+
);
158+
export type PrepareRepayWithSupplyRequest = RequestOf<
159+
typeof RepayWithSupplyQuoteQuery
160+
>;
161+
146162
/**
147163
* @internal
148164
*/

packages/react/src/swap.test.ts

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ import {
99
BorrowSwapQuoteQuery,
1010
type PrepareBorrowSwapRequest,
1111
PreparePositionSwapQuery,
12+
type PrepareRepayWithSupplyRequest,
1213
type PrepareSupplySwapRequest,
14+
RepayWithSupplyQuoteQuery,
1315
SupplySwapQuoteQuery,
1416
SwapMutation,
1517
} from '@aave/graphql';
@@ -32,7 +34,7 @@ import {
3234
describe,
3335
it,
3436
} from 'vitest';
35-
import { useBorrowSwap, useSupplySwap } from './swap';
37+
import { useBorrowSwap, useRepayWithSupply, useSupplySwap } from './swap';
3638
import { renderHookWithinContext } from './test-utils';
3739
import { useSendTransaction } from './viem';
3840

@@ -229,4 +231,76 @@ describe('Given the swap hooks', () => {
229231
assertOk(result);
230232
});
231233
});
234+
235+
describe(`When using the '${useRepayWithSupply.name}' hook`, () => {
236+
beforeEach(() => {
237+
server.use(
238+
api.query(RepayWithSupplyQuoteQuery, () =>
239+
msw.HttpResponse.json({
240+
data: {
241+
value: {
242+
__typename: 'PositionSwapByIntentApprovalsRequired',
243+
quote: makeSwapQuote(),
244+
approvals: [
245+
makePositionSwapPositionManagerApproval({
246+
byTransaction: dummyTransactionRequest,
247+
}),
248+
makePositionSwapAdapterContractApproval({
249+
byTransaction: dummyTransactionRequest,
250+
}),
251+
],
252+
},
253+
},
254+
}),
255+
),
256+
);
257+
});
258+
259+
it('Then it should support position swap with position manager and adapter contract approvals via signatures', async () => {
260+
const {
261+
result: {
262+
current: [swap],
263+
},
264+
} = renderHookWithinContext(() =>
265+
useRepayWithSupply((plan) => {
266+
switch (plan.__typename) {
267+
case 'PositionSwapPositionManagerApproval':
268+
case 'PositionSwapAdapterContractApproval':
269+
return signSwapTypedDataWith(walletClient, plan.bySignature);
270+
271+
case 'SwapByIntent':
272+
return signSwapTypedDataWith(walletClient, plan.data);
273+
}
274+
}),
275+
);
276+
277+
const result = await swap({} as PrepareRepayWithSupplyRequest);
278+
279+
assertOk(result);
280+
});
281+
282+
it('Then it should support position swap with position manager and adapter contract approvals via transactions', async () => {
283+
const {
284+
result: {
285+
current: [swap],
286+
},
287+
} = renderHookWithinContext(() => {
288+
const [sendTransaction] = useSendTransaction(walletClient);
289+
return useRepayWithSupply((plan) => {
290+
switch (plan.__typename) {
291+
case 'PositionSwapPositionManagerApproval':
292+
case 'PositionSwapAdapterContractApproval':
293+
return sendTransaction(plan.byTransaction);
294+
295+
case 'SwapByIntent':
296+
return signSwapTypedDataWith(walletClient, plan.data);
297+
}
298+
});
299+
});
300+
301+
const result = await swap({} as PrepareRepayWithSupplyRequest);
302+
303+
assertOk(result);
304+
});
305+
});
232306
});

0 commit comments

Comments
 (0)