Skip to content

Commit e17791c

Browse files
committed
test: repay scenarios and missing borrow with native token
1 parent f190e71 commit e17791c

File tree

4 files changed

+260
-71
lines changed

4 files changed

+260
-71
lines changed

packages/client/src/actions/borrow.test.ts

Lines changed: 87 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@ import {
1313
ETHEREUM_MARKET_ADDRESS,
1414
fetchReserve,
1515
fundErc20Address,
16+
fundNativeAddress,
1617
WETH_ADDRESS,
1718
wait,
1819
} from '../test-utils';
1920
import { sendWith } from '../viem';
2021
import { market } from './markets';
21-
import { borrow, collateralToggle, supply } from './transactions';
22+
import { borrow, supply } from './transactions';
2223
import { userBorrows, userSupplies } from './user';
2324

2425
async function supplyAndCheck(
@@ -55,30 +56,31 @@ async function supplyAndCheck(
5556
}
5657

5758
describe('Given an Aave Market', () => {
58-
let marketInfo: Market;
59-
const wallet: WalletClient = createNewWallet();
59+
describe('And a user with a supply position', () => {
60+
describe('When user set the supply as collateral', async () => {
61+
let marketInfo: Market;
62+
const wallet: WalletClient = createNewWallet();
6063

61-
beforeAll(async () => {
62-
// Set up market info first
63-
const result = await market(client, {
64-
address: ETHEREUM_MARKET_ADDRESS,
65-
chainId: ETHEREUM_FORK_ID,
66-
});
67-
assertOk(result);
68-
marketInfo = result.value!;
64+
beforeAll(async () => {
65+
// Set up market info first
66+
const result = await market(client, {
67+
address: ETHEREUM_MARKET_ADDRESS,
68+
chainId: ETHEREUM_FORK_ID,
69+
});
70+
assertOk(result);
71+
marketInfo = result.value!;
6972

70-
// Set up wallet and supply position
71-
await fundErc20Address(
72-
WETH_ADDRESS,
73-
evmAddress(wallet.account!.address),
74-
bigDecimal('0.011'),
75-
);
76-
});
73+
// Set up wallet and supply position
74+
await fundErc20Address(
75+
WETH_ADDRESS,
76+
evmAddress(wallet.account!.address),
77+
bigDecimal('0.011'),
78+
);
79+
});
7780

78-
describe('And a user with a supply position', () => {
79-
describe('When user set the supply as collateral', async () => {
80-
it('Then it should be possible to borrow from the reserve', async () => {
81-
const supplyResult = await supplyAndCheck(wallet, {
81+
it('Then it should be possible to borrow ERC20 from the reserve', async () => {
82+
// NOTE: first time supply is set as collateral automatically
83+
await supplyAndCheck(wallet, {
8284
market: marketInfo.address,
8385
chainId: marketInfo.chain.chainId,
8486
supplier: evmAddress(wallet.account!.address),
@@ -90,35 +92,6 @@ describe('Given an Aave Market', () => {
9092
},
9193
});
9294

93-
if (!supplyResult[0]!.isCollateral) {
94-
// Enable collateral
95-
const result = await collateralToggle(client, {
96-
market: marketInfo.address,
97-
underlyingToken: WETH_ADDRESS,
98-
chainId: marketInfo.chain.chainId,
99-
user: evmAddress(wallet.account!.address),
100-
})
101-
.andThen(sendWith(wallet))
102-
.andTee((tx) => console.log(`tx to enable collateral: ${tx}`))
103-
.andThen(() => {
104-
return userSupplies(client, {
105-
markets: [
106-
{
107-
address: marketInfo.address,
108-
chainId: marketInfo.chain.chainId,
109-
},
110-
],
111-
user: evmAddress(wallet.account!.address),
112-
});
113-
});
114-
assertOk(result);
115-
expect(result.value).toEqual([
116-
expect.objectContaining({
117-
isCollateral: true,
118-
}),
119-
]);
120-
}
121-
12295
// Borrow from the reserve
12396
const borrowReserve = await fetchReserve(
12497
WETH_ADDRESS,
@@ -153,5 +126,68 @@ describe('Given an Aave Market', () => {
153126
expect(borrowResult.value.length).toBe(1);
154127
}, 25_000);
155128
});
129+
130+
describe('When user set the supply as collateral', async () => {
131+
let marketInfo: Market;
132+
const wallet: WalletClient = createNewWallet();
133+
134+
beforeAll(async () => {
135+
// Set up market info first
136+
const result = await market(client, {
137+
address: ETHEREUM_MARKET_ADDRESS,
138+
chainId: ETHEREUM_FORK_ID,
139+
});
140+
assertOk(result);
141+
marketInfo = result.value!;
142+
143+
// Set up wallet and supply position
144+
await fundNativeAddress(
145+
evmAddress(wallet.account!.address),
146+
bigDecimal('0.2'),
147+
);
148+
});
149+
150+
it('Then it should be possible to borrow native from the reserve', async () => {
151+
// NOTE: first time supply is set as collateral automatically
152+
await supplyAndCheck(wallet, {
153+
market: marketInfo.address,
154+
chainId: marketInfo.chain.chainId,
155+
supplier: evmAddress(wallet.account!.address),
156+
amount: {
157+
native: '0.1',
158+
},
159+
});
160+
161+
// Borrow from the reserve
162+
const borrowReserve = await fetchReserve(
163+
WETH_ADDRESS,
164+
evmAddress(wallet.account!.address),
165+
);
166+
const borrowResult = await borrow(client, {
167+
market: marketInfo.address,
168+
chainId: marketInfo.chain.chainId,
169+
borrower: evmAddress(wallet.account!.address),
170+
amount: {
171+
native: borrowReserve.userState!.borrowable.amount.value,
172+
},
173+
})
174+
.andThen(sendWith(wallet))
175+
.andTee((tx) => console.log(`tx to borrow: ${tx}`))
176+
.andTee(() => wait(5000))
177+
.andThen(() =>
178+
userBorrows(client, {
179+
markets: [
180+
{
181+
address: marketInfo.address,
182+
chainId: marketInfo.chain.chainId,
183+
},
184+
],
185+
user: evmAddress(wallet.account!.address),
186+
}),
187+
);
188+
assertOk(borrowResult);
189+
expect(borrowResult.value.length).toBe(1);
190+
}, 25_000);
191+
});
156192
});
157193
});
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
import type { Market, SupplyRequest } from '@aave/graphql';
2+
import { assertOk, bigDecimal, evmAddress } from '@aave/types';
3+
import type { WalletClient } from 'viem';
4+
import { beforeAll, describe, expect, it } from 'vitest';
5+
import {
6+
client,
7+
createNewWallet,
8+
ETHEREUM_FORK_ID,
9+
ETHEREUM_MARKET_ADDRESS,
10+
fundErc20Address,
11+
fundNativeAddress,
12+
WETH_ADDRESS,
13+
wait,
14+
} from '../test-utils';
15+
import { sendWith } from '../viem';
16+
import { market } from './markets';
17+
import { reserve } from './reserve';
18+
import { borrow, repay, supply } from './transactions';
19+
import { userBorrows } from './user';
20+
21+
async function supplyAndBorrow(wallet: WalletClient, request: SupplyRequest) {
22+
const userAddress = evmAddress(wallet.account!.address);
23+
const result = await supply(client, request)
24+
.andThen(sendWith(wallet))
25+
.andTee((tx) => console.log(`Supplied tx: ${tx}`))
26+
.andThen(() =>
27+
reserve(client, {
28+
market: request.market,
29+
user: userAddress,
30+
chainId: request.chainId,
31+
underlyingToken:
32+
'erc20' in request.amount ? request.amount.erc20.currency : undefined,
33+
}),
34+
)
35+
.andThen((reserveInfo) =>
36+
borrow(client, {
37+
market: reserveInfo?.market.address,
38+
amount: {
39+
erc20: {
40+
currency: reserveInfo?.underlyingToken.address,
41+
value: reserveInfo?.userState?.borrowable.amount.value,
42+
},
43+
},
44+
borrower: userAddress,
45+
chainId: request.chainId,
46+
}),
47+
)
48+
.andThen(sendWith(wallet))
49+
.andTee((tx) => console.log(`Borrowed tx: ${tx}`));
50+
assertOk(result);
51+
}
52+
53+
describe('Given an Aave Market', () => {
54+
describe('And a user with a borrow position', () => {
55+
describe('When the user repays their loan', () => {
56+
let marketInfo: Market;
57+
const wallet = createNewWallet();
58+
59+
beforeAll(async () => {
60+
// Set up market info first
61+
const result = await market(client, {
62+
address: ETHEREUM_MARKET_ADDRESS,
63+
chainId: ETHEREUM_FORK_ID,
64+
});
65+
assertOk(result);
66+
marketInfo = result.value!;
67+
68+
// Set up wallet and supply position
69+
await fundErc20Address(
70+
WETH_ADDRESS,
71+
evmAddress(wallet.account!.address),
72+
bigDecimal('0.02'),
73+
);
74+
75+
// supply and borrow
76+
await supplyAndBorrow(wallet, {
77+
market: marketInfo.address,
78+
chainId: marketInfo.chain.chainId,
79+
supplier: evmAddress(wallet.account!.address),
80+
amount: { erc20: { currency: WETH_ADDRESS, value: '0.01' } },
81+
});
82+
});
83+
84+
it('Then it should be reflected in the user borrow positions', async () => {
85+
const result = await repay(client, {
86+
amount: { erc20: { currency: WETH_ADDRESS, value: '0.01' } },
87+
borrower: evmAddress(wallet.account!.address),
88+
chainId: marketInfo.chain.chainId,
89+
market: marketInfo.address,
90+
})
91+
.andThen(sendWith(wallet))
92+
.andTee((tx) => console.log(`Repaid tx: ${tx}`))
93+
.andTee(() => wait(5000))
94+
.andThen(() =>
95+
userBorrows(client, {
96+
markets: [
97+
{
98+
address: marketInfo.address,
99+
chainId: marketInfo.chain.chainId,
100+
},
101+
],
102+
user: evmAddress(wallet.account!.address),
103+
}),
104+
);
105+
assertOk(result);
106+
expect(result.value.length).toBe(0);
107+
}, 25_000);
108+
});
109+
110+
describe('And the reserve allows repaying in native tokens', () => {
111+
describe('When the user repays their loan in native tokens', () => {
112+
let marketInfo: Market;
113+
const wallet = createNewWallet();
114+
115+
beforeAll(async () => {
116+
// Set up market info first
117+
const result = await market(client, {
118+
address: ETHEREUM_MARKET_ADDRESS,
119+
chainId: ETHEREUM_FORK_ID,
120+
});
121+
assertOk(result);
122+
marketInfo = result.value!;
123+
124+
// Set up wallet and supply position
125+
await fundNativeAddress(
126+
evmAddress(wallet.account!.address),
127+
bigDecimal('0.02'),
128+
);
129+
130+
await fundErc20Address(
131+
WETH_ADDRESS,
132+
evmAddress(wallet.account!.address),
133+
bigDecimal('0.02'),
134+
);
135+
136+
// supply and borrow
137+
await supplyAndBorrow(wallet, {
138+
market: marketInfo.address,
139+
chainId: marketInfo.chain.chainId,
140+
supplier: evmAddress(wallet.account!.address),
141+
amount: { erc20: { currency: WETH_ADDRESS, value: '0.01' } },
142+
});
143+
});
144+
145+
it('Then it should be reflected in the user borrow positions', async () => {
146+
const result = await repay(client, {
147+
amount: { native: '0.01' },
148+
borrower: evmAddress(wallet.account!.address),
149+
chainId: marketInfo.chain.chainId,
150+
market: marketInfo.address,
151+
})
152+
.andThen(sendWith(wallet))
153+
.andTee((tx) => console.log(`Repaid tx: ${tx}`))
154+
.andTee(() => wait(5000))
155+
.andThen(() =>
156+
userBorrows(client, {
157+
markets: [
158+
{
159+
address: marketInfo.address,
160+
chainId: marketInfo.chain.chainId,
161+
},
162+
],
163+
user: evmAddress(wallet.account!.address),
164+
}),
165+
);
166+
assertOk(result);
167+
expect(result.value.length).toBe(0);
168+
}, 25_000);
169+
});
170+
});
171+
});
172+
});

packages/client/src/actions/repay.todo.ts

Lines changed: 0 additions & 19 deletions
This file was deleted.

packages/client/src/actions/withdraw.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ describe('Given an Aave Market', () => {
7777
});
7878
});
7979

80-
describe('When the user withdraws their supply ', () => {
80+
describe('When the user withdraws their supply', () => {
8181
it('Then it should be reflected in the user supply positions', async () => {
8282
const result = await withdraw(client, {
8383
market: reserveInfo.market.address,

0 commit comments

Comments
 (0)