Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
9e9cdef
fix: update snapshots
juangm Jul 17, 2025
b1b2b4e
test: add supply test in stage
juangm Jul 17, 2025
3a04e15
fix: lint
juangm Jul 17, 2025
af5890f
fix: remove examples from packages
juangm Jul 17, 2025
a9f1706
fix: update lockfile
juangm Jul 17, 2025
20d9af0
fix: refactor
juangm Jul 17, 2025
716eb05
Merge branch 'main' into juan/supply-tests
juangm Jul 17, 2025
a4117d4
fix: problem with lock file
juangm Jul 17, 2025
79149f6
fix: set bigger timeout
juangm Jul 17, 2025
0d52fea
Merge branch 'main' into juan/supply-tests
juangm Jul 17, 2025
e84b55f
fix: refactor scenario
juangm Jul 18, 2025
108379f
temp: possible to run tests locally
juangm Jul 18, 2025
4286072
fix: use expect instead of error
juangm Jul 18, 2025
b874ec7
fix: not run tests if lint fail
juangm Jul 18, 2025
d5f5ea6
fix: refactor scenario
juangm Jul 18, 2025
e4fe694
fix: add custom matcher and refactor
juangm Jul 21, 2025
b28aaa8
test: fetch specific market data
juangm Jul 21, 2025
47eefd6
Merge branch 'main' into juan/supply-tests
juangm Jul 21, 2025
c137bf0
core: update schema and fixes
juangm Jul 21, 2025
67c2c1f
test: add fetch vaults and market state
juangm Jul 21, 2025
e32d741
fix: rename file
juangm Jul 21, 2025
69ee083
chore: scaffold aave market test scenarios
cesarenaldi Jul 21, 2025
e1b0441
chore: temp tweak to CI workflows
cesarenaldi Jul 21, 2025
43c2fe2
Merge branch 'main' into juan/supply-tests
juangm Jul 21, 2025
16d7556
test: separate tests in supply and withdraw
juangm Jul 21, 2025
ce91256
Merge branch 'main' into juan/supply-tests
juangm Jul 21, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 14 additions & 10 deletions .github/workflows/verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,19 @@ jobs:
- name: Run Biome
run: biome ci .

test:
name: Test
runs-on: ubuntu-latest
- name: Build
uses: ./.github/actions/setup

steps:
- uses: actions/checkout@v4
# test:
# name: Test
# needs: lint
# runs-on: ubuntu-latest

- name: Run Tests
uses: ./.github/actions/tests
with:
environment: 'staging'
private_key: ${{ secrets.PRIVATE_KEY }}
# steps:
# - uses: actions/checkout@v4

# - name: Run Tests
# uses: ./.github/actions/tests
# with:
# environment: 'staging'
# private_key: ${{ secrets.PRIVATE_KEY }}
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,10 @@ The project uses [Biome](https://biomejs.dev/) to format and lint the code. You

9. Merge the pull request to the `main` branch.


## Contributing

We welcome contributions to the Aave SDK! If you're interested in contributing, please follow these steps:

1. Fork the repository.
2. Create a new branch for your feature or bug fix.
3. Make your changes and commit them with clear messages.
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"new:package": "NODE_OPTIONS='--import tsx' plop --plopfile=plopfile.ts",
"prepublish": "pnpm run build",
"test:client": "vitest --project client",
"test:client:local": "ENVIRONMENT=local vitest --project client",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is doable with a simple ENVIRONMENT=local in front of any of the commands. I am not sure if we should have these scripts proliferating.

"test:react": "vitest --project react",
"test": "vitest"
},
Expand Down
38 changes: 38 additions & 0 deletions packages/client/src/actions/__snapshots__/markets.test.ts.snap
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`Given the Aave Protocol v3 > When fetching a market data for a given address > Then it should be possible to fetch market data for a given address 1`] = `
{
"__typename": "Market",
"address": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
"borrowReserves": Any<Array>,
"chain": {
"__typename": "Chain",
"chainId": 99999999,
"explorerUrl": "https://dashboard.tenderly.co/explorer/vnet/27ff3c60-0e2c-4d46-8190-f5170dc7da8c",
"icon": "https://statics.aave.com/ethereum.svg",
"name": "Forked Ethereum",
},
"eModeCategories": Any<Array>,
"icon": "https://statics.aave.com/ethereum.svg",
"name": "AaveV3ForkedEthereum",
"supplyReserves": Any<Array>,
"totalAvailableLiquidity": Any<String>,
"totalMarketSize": Any<String>,
"userState": null,
}
`;

exports[`Given the Aave Protocol v3 > When fetching markets data > Then it should be possible to fetch markets for a given chain ID 1`] = `
{
"__typename": "Market",
Expand Down Expand Up @@ -65,3 +87,19 @@ exports[`Given the Aave Protocol v3 > When fetching markets data > Then it shoul
"userState": null,
}
`;

exports[`Given the Aave Protocol v3 > When fetching user market state > Then it should be possible to fetch user market state for a given user, market address and chain ID 1`] = `
{
"__typename": "MarketUserState",
"availableBorrowsBase": Any<String>,
"currentLiquidationThreshold": Any<String>,
"eModeEnabled": Any<Boolean>,
"healthFactor": Any<String>,
"isInIsolationMode": Any<Boolean>,
"ltv": Any<String>,
"netAPY": Any<String>,
"netWorth": Any<String>,
"totalCollateralBase": Any<String>,
"totalDebtBase": Any<String>,
}
`;
13 changes: 13 additions & 0 deletions packages/client/src/actions/borrow.todo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { describe, expect, it } from 'vitest';

// THIS IS A VERY WIP

describe('Given an Aave Market', () => {
describe('And a user with a supply position', () => {
describe('When the user enables e-mode for that market', () => {
it('Then it should be possible to borrow from the reserve', () => {
expect(true).toBe(true);
});
});
});
});
Empty file.
54 changes: 51 additions & 3 deletions packages/client/src/actions/markets.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { assertOk, chainId } from '@aave/types';
import { assertOk, chainId, evmAddress } from '@aave/types';
import { describe, expect, it } from 'vitest';
import { client } from '../test-utils';
import { markets } from './markets';
import {
client,
DEFAULT_MARKET_ADDRESS,
ETHEREUM_FORK_ID,
wallet,
} from '../test-utils';
import { market, markets, userMarketState } from './markets';

describe('Given the Aave Protocol v3', () => {
describe('When fetching markets data', () => {
Expand All @@ -23,4 +28,47 @@ describe('Given the Aave Protocol v3', () => {
});
});
});

describe('When fetching a market data for a given address', () => {
it('Then it should be possible to fetch market data for a given market address and chain ID', async () => {
const result = await market(client, {
address: DEFAULT_MARKET_ADDRESS,
chainId: ETHEREUM_FORK_ID,
});

assertOk(result);

expect(result.value).toMatchSnapshot({
totalAvailableLiquidity: expect.any(String),
totalMarketSize: expect.any(String),
borrowReserves: expect.any(Array),
supplyReserves: expect.any(Array),
eModeCategories: expect.any(Array),
});
});
});

describe('When fetching user market state', () => {
it('Then it should be possible to fetch user market state for a given user, market address and chain ID', async () => {
const result = await userMarketState(client, {
market: DEFAULT_MARKET_ADDRESS,
chainId: ETHEREUM_FORK_ID,
user: evmAddress(wallet.account!.address),
});

assertOk(result);
expect(result.value).toMatchSnapshot({
availableBorrowsBase: expect.any(String),
currentLiquidationThreshold: expect.any(String),
eModeEnabled: expect.any(Boolean),
healthFactor: expect.any(String),
isInIsolationMode: expect.any(Boolean),
ltv: expect.any(String),
netAPY: expect.any(String),
netWorth: expect.any(String),
totalCollateralBase: expect.any(String),
totalDebtBase: expect.any(String),
});
});
});
});
19 changes: 19 additions & 0 deletions packages/client/src/actions/repay.todo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { describe, expect, it } from 'vitest';

describe('Given an Aave Market', () => {
describe('And a user with a borrow position', () => {
describe('When the user repays their loan', () => {
it('Then it should be reflected in the user borrow positions', () => {
expect(true).toBe(true);
});
});

describe('And the reserve allows repaying in native tokens', () => {
describe('When the user repays their loan in native tokens', () => {
it('Then it should be reflected in the user borrow positions', () => {
expect(true).toBe(true);
});
});
});
});
});
129 changes: 129 additions & 0 deletions packages/client/src/actions/supply.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import type { Reserve } from '@aave/graphql';
import { assertOk, bigDecimal, evmAddress } from '@aave/types';
import { beforeAll, describe, expect, it } from 'vitest';
import {
client,
createNewWallet,
fetchReserve,
fundErc20Address,
fundNativeAddress,
WETH_ADDRESS,
} from '../test-utils';
import { sendWith } from '../viem';
import { supply } from './transactions';
import { userSupplies } from './user';

describe('Given an Aave Market', () => {
describe('When the user supplies tokens to a Reserve', () => {
const wallet = createNewWallet();
const amountToSupply = '0.01';
let reserveInfo: Reserve;

beforeAll(async () => {
await fundErc20Address(
WETH_ADDRESS,
evmAddress(wallet.account!.address),
bigDecimal('0.02'),
);

reserveInfo = await fetchReserve(WETH_ADDRESS);
// Check if the reserve is not frozen or paused
expect(reserveInfo.isFrozen).toBe(false);
expect(reserveInfo.isPaused).toBe(false);
});

it(`Then it should be available in the user's supply positions`, async () => {
const result = await supply(client, {
market: reserveInfo.market.address,
supplier: evmAddress(wallet.account!.address),
amount: {
erc20: {
value: amountToSupply,
currency: WETH_ADDRESS,
},
},
chainId: reserveInfo.market.chain.chainId,
})
.andThen(sendWith(wallet))
.andThen(() =>
userSupplies(client, {
markets: [
{
address: reserveInfo.market.address,
chainId: reserveInfo.market.chain.chainId,
},
],
user: evmAddress(wallet.account!.address),
}),
);
assertOk(result);
expect(result.value).toEqual([
expect.objectContaining({
balance: expect.objectContaining({
amount: expect.objectContaining({
value: expect.toBeBigDecimalCloseTo(amountToSupply),
}),
}),
}),
]);
}, 25_000);
});

describe('And the Reserve allows to supply in native tokens', () => {
let reserveInfo: Reserve;

beforeAll(async () => {
reserveInfo = await fetchReserve(WETH_ADDRESS);
// Check if the reserve is not frozen or paused
expect(reserveInfo.isFrozen).toBe(false);
expect(reserveInfo.isPaused).toBe(false);
// And accepts native tokens
expect(reserveInfo.acceptsNative?.symbol).toEqual('ETH');
});

describe('When the user supplies to the reserve in native tokens', () => {
const wallet = createNewWallet();
const amountToSupply = '0.01';

beforeAll(async () => {
await fundNativeAddress(
evmAddress(wallet.account!.address),
bigDecimal('0.02'),
);
});

it(`Then it should be available in the user's supply positions`, async () => {
const result = await supply(client, {
market: reserveInfo.market.address,
supplier: evmAddress(wallet.account!.address),
amount: {
native: amountToSupply,
},
chainId: reserveInfo.market.chain.chainId,
})
.andThen(sendWith(wallet))
.andThen(() =>
userSupplies(client, {
markets: [
{
address: reserveInfo.market.address,
chainId: reserveInfo.market.chain.chainId,
},
],
user: evmAddress(wallet.account!.address),
}),
);
assertOk(result);
expect(result.value).toEqual([
expect.objectContaining({
balance: expect.objectContaining({
amount: expect.objectContaining({
value: expect.toBeBigDecimalCloseTo(amountToSupply),
}),
}),
}),
]);
}, 25_000);
});
});
});
9 changes: 7 additions & 2 deletions packages/client/src/actions/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,18 @@ export function userBorrows(
}

/**
* Fetches the user's transaction history.
* Fetches the user's transaction history for a given market.
*
* ```ts
* const result = await userTransactionHistory(client);
* const result = await userTransactionHistory(client, {
* chainId: chainId(1),
* market: evmAddress('0x87870bca…'),
* user: evmAddress('0x742d35cc…'),
* });
* ```
*
* @param client - Aave client.
* @param request - The user transaction history request parameters.
* @returns The user's paginated transaction history.
*/
export function userTransactionHistory(
Expand Down
22 changes: 22 additions & 0 deletions packages/client/src/actions/vaults.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { assertOk, evmAddress } from '@aave/types';
import { describe, expect, it } from 'vitest';
import { client, wallet } from '../test-utils';
import { vaults } from './vaults';

describe('Given the Aave Protocol v3', () => {
describe('When fetching vaults data', () => {
it('Then it should be possible to fetch vaults owned by a given user', async () => {
const result = await vaults(client, {
criteria: {
ownedBy: [evmAddress(wallet.account!.address)],
},
});

assertOk(result);

result.value.items.forEach((vault) => {
expect(vault).toMatchSnapshot();
});
});
});
});
Loading