Skip to content

Commit b4814b2

Browse files
committed
fix: rewirte test scenarios
1 parent a1f8f45 commit b4814b2

File tree

1 file changed

+186
-0
lines changed

1 file changed

+186
-0
lines changed

packages/spec/swap/erc20.spec.ts

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
import {
2+
assertOk,
3+
bigDecimal,
4+
evmAddress,
5+
invariant,
6+
SwapKind,
7+
} from '@aave/client';
8+
import {
9+
prepareTokenSwap,
10+
swap,
11+
swapStatus,
12+
userSwaps,
13+
} from '@aave/client/actions';
14+
import {
15+
client,
16+
createNewWallet,
17+
ETHEREUM_FORK_ID,
18+
ETHEREUM_USDC_ADDRESS,
19+
ETHEREUM_WETH_ADDRESS,
20+
fundErc20Address,
21+
} from '@aave/client/testing';
22+
import { sendTransaction, signSwapTypedDataWith } from '@aave/client/viem';
23+
import type { Account, Chain, Transport, WalletClient } from 'viem';
24+
import { beforeAll, describe, expect, it } from 'vitest';
25+
26+
describe('Token swapping on Aave V4', () => {
27+
describe('Given a user who has previously swapped the current token', () => {
28+
let userDidSwap: WalletClient<Transport, Chain, Account>;
29+
30+
beforeAll(async () => {
31+
userDidSwap = await createNewWallet(
32+
'0x7e97068be691cce1b5c1216b8bc4600fa9c605fcef07c8ef5af05f86e838d69b',
33+
);
34+
35+
const setup = await fundErc20Address(
36+
evmAddress(userDidSwap.account.address),
37+
{
38+
address: ETHEREUM_USDC_ADDRESS,
39+
amount: bigDecimal('20'),
40+
decimals: 6,
41+
},
42+
);
43+
assertOk(setup);
44+
});
45+
46+
describe('When the user swaps the token again', () => {
47+
it('Then the swap executes without requiring approval', async ({
48+
annotate,
49+
}) => {
50+
const swapResult = await prepareTokenSwap(client, {
51+
market: {
52+
amount: bigDecimal('20'),
53+
sell: { erc20: ETHEREUM_USDC_ADDRESS },
54+
buy: { erc20: ETHEREUM_WETH_ADDRESS },
55+
chainId: ETHEREUM_FORK_ID,
56+
kind: SwapKind.Sell,
57+
receiver: evmAddress(userDidSwap.account.address),
58+
user: evmAddress(userDidSwap.account.address),
59+
},
60+
}).andThen((swapPlan) => {
61+
invariant(
62+
swapPlan.__typename === 'SwapByIntent',
63+
`Swap plan is not a swap by intent: ${swapPlan.__typename}`,
64+
);
65+
return signSwapTypedDataWith(userDidSwap, swapPlan.data).andThen(
66+
(signature) => {
67+
return swap(client, {
68+
intent: {
69+
quoteId: swapPlan.quote.quoteId,
70+
signature: signature,
71+
},
72+
});
73+
},
74+
);
75+
});
76+
77+
assertOk(swapResult);
78+
invariant(
79+
swapResult.value.__typename === 'SwapReceipt',
80+
`Swap result is not a swap receipt: ${swapResult.value.__typename}`,
81+
);
82+
annotate(`Swap id: ${swapResult.value.id}`);
83+
const status = await swapStatus(client, { id: swapResult.value.id });
84+
assertOk(status);
85+
// Check swap was opened successfully
86+
expect(status.value.__typename).toBe('SwapOpen');
87+
88+
const swapPositions = await userSwaps(client, {
89+
chainId: ETHEREUM_FORK_ID,
90+
user: evmAddress(userDidSwap.account.address),
91+
});
92+
assertOk(swapPositions);
93+
expect(
94+
swapPositions.value.items.find(
95+
(swap) =>
96+
swap.__typename === 'SwapOpen' &&
97+
swapResult.value.__typename === 'SwapReceipt' &&
98+
swap.swapId === swapResult.value.id,
99+
),
100+
).toBeDefined();
101+
});
102+
});
103+
});
104+
105+
describe('Given a user swapping a token for the first time', () => {
106+
let newUser: WalletClient<Transport, Chain, Account>;
107+
108+
beforeAll(async () => {
109+
newUser = await createNewWallet();
110+
111+
const setup = await fundErc20Address(
112+
evmAddress(newUser.account.address),
113+
{
114+
address: ETHEREUM_USDC_ADDRESS,
115+
amount: bigDecimal('20'),
116+
decimals: 6,
117+
},
118+
);
119+
assertOk(setup);
120+
});
121+
122+
describe('When the user initiates the swap', () => {
123+
it('Then the user must approve before swapping', async ({ annotate }) => {
124+
const swapResult = await prepareTokenSwap(client, {
125+
market: {
126+
amount: bigDecimal('20'),
127+
sell: { erc20: ETHEREUM_USDC_ADDRESS },
128+
buy: { erc20: ETHEREUM_WETH_ADDRESS },
129+
chainId: ETHEREUM_FORK_ID,
130+
kind: SwapKind.Sell,
131+
receiver: evmAddress(newUser.account.address),
132+
user: evmAddress(newUser.account.address),
133+
},
134+
}).andThen((swapPlan) => {
135+
invariant(
136+
swapPlan.__typename === 'SwapByIntentWithApprovalRequired',
137+
`Swap plan is not a swap by intent: ${swapPlan.__typename}`,
138+
);
139+
return sendTransaction(newUser, swapPlan.approval).andThen(() =>
140+
signSwapTypedDataWith(newUser, swapPlan.data).andThen(
141+
(signature) => {
142+
return swap(client, {
143+
intent: {
144+
quoteId: swapPlan.quote.quoteId,
145+
signature: signature,
146+
},
147+
});
148+
},
149+
),
150+
);
151+
});
152+
153+
assertOk(swapResult);
154+
invariant(
155+
swapResult.value.__typename === 'SwapReceipt',
156+
`Swap result is not a swap receipt: ${swapResult.value.__typename}`,
157+
);
158+
annotate(`Swap id: ${swapResult.value.id}`);
159+
const status = await swapStatus(client, { id: swapResult.value.id });
160+
assertOk(status);
161+
// Check swap was opened successfully
162+
expect(status.value.__typename).toBe('SwapOpen');
163+
164+
const swapPositions = await userSwaps(client, {
165+
chainId: ETHEREUM_FORK_ID,
166+
user: evmAddress(newUser.account.address),
167+
});
168+
assertOk(swapPositions);
169+
expect(
170+
swapPositions.value.items.find(
171+
(swap) =>
172+
swap.__typename === 'SwapOpen' &&
173+
swapResult.value.__typename === 'SwapReceipt' &&
174+
swap.swapId === swapResult.value.id,
175+
),
176+
).toBeDefined();
177+
});
178+
});
179+
});
180+
181+
describe('Given a user with a native token', () => {
182+
describe('When the user swaps it for a wrapped native token', () => {
183+
it.todo('Then the swap executes via a single transaction');
184+
});
185+
});
186+
});

0 commit comments

Comments
 (0)