diff --git a/examples/user-positions/README.md b/examples/user-positions/README.md new file mode 100644 index 0000000..5a7b261 --- /dev/null +++ b/examples/user-positions/README.md @@ -0,0 +1,3 @@ +# query for user positions on aave v3 + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/aave/aave-sdk/tree/main/examples/user-positions) diff --git a/examples/user-positions/index.html b/examples/user-positions/index.html new file mode 100644 index 0000000..f914789 --- /dev/null +++ b/examples/user-positions/index.html @@ -0,0 +1,14 @@ + + + + + + + + query for user positions on aave v3 + + +
+ + + diff --git a/examples/user-positions/package.json b/examples/user-positions/package.json new file mode 100644 index 0000000..f591fae --- /dev/null +++ b/examples/user-positions/package.json @@ -0,0 +1,22 @@ +{ + "name": "user-positions", + "description": "query for user positions on aave v3", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite" + }, + "dependencies": { + "@aave/react": "workspace:*", + "react": "^19.1.0", + "react-dom": "^19.1.0" + }, + "devDependencies": { + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react-swc": "^3.7.2", + "typescript": "^5.6.3", + "vite": "^5.4.9" + } +} diff --git a/examples/user-positions/public/aave.svg b/examples/user-positions/public/aave.svg new file mode 100644 index 0000000..f6f9113 --- /dev/null +++ b/examples/user-positions/public/aave.svg @@ -0,0 +1 @@ + diff --git a/examples/user-positions/src/App.tsx b/examples/user-positions/src/App.tsx new file mode 100644 index 0000000..fcdcb12 --- /dev/null +++ b/examples/user-positions/src/App.tsx @@ -0,0 +1,238 @@ +import { AaveProvider, useUserSupplies, useUserBorrows, evmAddress, chainId, useAaveMarkets, ZERO_ADDRESS } from '@aave/react'; +import { client } from './client'; + +// TODO: change to your address or any address you want to query +const user = evmAddress(ZERO_ADDRESS); + +function UserPositions() { + const { data: markets, loading: marketsLoading } = useAaveMarkets({ + chainIds: [chainId(1), chainId(8453)], + }); + + const marketAddresses = markets?.map(market => ({ + address: market.address, + chainId: market.chain.chainId, + })) || []; + + const { data: userSupplies, loading: userSuppliesLoading } = useUserSupplies({ + markets: marketAddresses, + user, + }); + + const { data: userBorrows, loading: userBorrowsLoading } = useUserBorrows({ + markets: marketAddresses, + user, + }); + + if (userSuppliesLoading || userBorrowsLoading || marketsLoading) { + return

Loading positions...

; + } + + return ( + <> +
+

👻 Aave V3 User Positions

+

Address: {user}

+
+ +
+

Supply Positions ({userSupplies?.length || 0})

+ + {userSupplies?.map((position, index) => ( +
+
+ {position.currency.symbol} +
+

+ {position.currency.name} ({position.currency.symbol}) +

+

+ {position.market.name} +

+
+
+ {position.market.chain.name} +
+

+ {position.market.chain.name} +

+

+ Chain ID: {position.market.chain.chainId} +

+
+
+
+ +
+
+

Balance

+

+ {parseFloat(position.balance.amount.value).toFixed(6)} {position.currency.symbol} +

+

+ ${parseFloat(position.balance.usd).toFixed(2)} USD +

+
+ +
+

Supply APY

+

+ {(parseFloat(position.apy.value) * 100).toFixed(2)}% +

+
+ +
+

Token Price

+

+ ${parseFloat(position.balance.usdPerToken).toLocaleString()} +

+
+ +
+

Collateral Status

+
+ + {position.canBeCollateral ? '✅ Can Collateralize' : '❌ Cannot Collateralize'} + + {position.isCollateral && ( + + 🔒 Used as Collateral + + )} +
+
+
+
+ ))} + + {userSupplies?.length === 0 && ( +

+ No supply positions found for this address. +

+ )} + +

Borrow Positions ({userBorrows?.length || 0})

+ + {userBorrows?.map((position, index) => ( +
+
+ {position.currency.symbol} +
+

+ {position.currency.name} ({position.currency.symbol}) +

+

+ {position.market.name} +

+
+
+ {position.market.chain.name} +
+

+ {position.market.chain.name} +

+

+ Chain ID: {position.market.chain.chainId} +

+
+
+
+ +
+
+

Debt Amount

+

+ {parseFloat(position.debt.amount.value).toFixed(6)} {position.currency.symbol} +

+

+ ${parseFloat(position.debt.usd).toFixed(2)} USD +

+
+ +
+

Borrow APY

+

+ {(parseFloat(position.apy.value) * 100).toFixed(2)}% +

+
+ +
+

Token Price

+

+ ${parseFloat(position.debt.usdPerToken).toLocaleString()} +

+
+ +
+

Borrow Type

+ + 📉 Borrowed Debt + +
+
+
+ ))} + + {userBorrows?.length === 0 && ( +

+ No borrow positions found for this address. +

+ )} +
+ + ); +} + +export function App() { + return ( + + + + ); +} diff --git a/examples/user-positions/src/client.ts b/examples/user-positions/src/client.ts new file mode 100644 index 0000000..3653cce --- /dev/null +++ b/examples/user-positions/src/client.ts @@ -0,0 +1,5 @@ +import { AaveClient, staging } from '@aave/react'; + +export const client = AaveClient.create({ + environment: staging, +}); diff --git a/examples/user-positions/src/main.tsx b/examples/user-positions/src/main.tsx new file mode 100644 index 0000000..216848b --- /dev/null +++ b/examples/user-positions/src/main.tsx @@ -0,0 +1,10 @@ +import { StrictMode } from 'react'; +import { createRoot } from 'react-dom/client'; + +import { App } from './App'; + +createRoot(document.getElementById('root')!).render( + + + , +); diff --git a/examples/user-positions/src/vite-env.d.ts b/examples/user-positions/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/examples/user-positions/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/user-positions/tsconfig.json b/examples/user-positions/tsconfig.json new file mode 100644 index 0000000..3ca84ac --- /dev/null +++ b/examples/user-positions/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "jsx": "react-jsx", + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "resolveJsonModule": true, + "isolatedModules": true, + "esModuleInterop": true, + "noEmit": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "skipLibCheck": true + }, + "include": ["src", "vite.config.ts"] +} diff --git a/examples/user-positions/vite.config.ts b/examples/user-positions/vite.config.ts new file mode 100644 index 0000000..0225812 --- /dev/null +++ b/examples/user-positions/vite.config.ts @@ -0,0 +1,6 @@ +import react from '@vitejs/plugin-react-swc'; +import { defineConfig } from 'vite'; + +export default defineConfig({ + plugins: [react()], +});