diff --git a/app/nexus/avail-nexus-sdk/nexus-core/bridge-and-execute/bridge-and-execute-aave-tutorial.md b/app/nexus/avail-nexus-sdk/nexus-core/bridge-and-execute/bridge-and-execute-aave-tutorial.md new file mode 100644 index 000000000..b214aac41 --- /dev/null +++ b/app/nexus/avail-nexus-sdk/nexus-core/bridge-and-execute/bridge-and-execute-aave-tutorial.md @@ -0,0 +1,155 @@ +### Tutorial: Bridge from Base to Ethereum and Stake USDC in Aave + +The following example shows how to wire up a complete bridge → stake experience that: + +1. Bridges 5,000,000 USDC (5,000 USDC with 6 decimals) from **Base (chainId 8453)**. +2. Stakes the bridged USDC inside **Aave v3 on Ethereum mainnet (chainId 1)** by calling `Pool.supply` at `0x87870Bca3F3fD6335C3F4ce8392D69350B4FA4E2`. +3. Requires a token approval on Ethereum because Aave pulls USDC via `transferFrom` (non-native deposit). +4. Streams progress, handles transaction responses, and surfaces explorer links in your UI. + +#### 1. Subscribe to bridge-and-execute progress for UI updates + +```tsx +import { useEffect, useState } from 'react'; +import { + NexusSDK, + NEXUS_EVENTS, + type BridgeAndExecuteResult, + type ProgressStep, +} from '@avail-project/nexus-core'; + +const sdk = new NexusSDK({ network: 'mainnet' }); + +export function useBridgeAndStakeProgress() { + const [expectedSteps, setExpectedSteps] = useState([]); + const [completedStep, setCompletedStep] = useState(null); + + useEffect(() => { + const unsubExpected = sdk.nexusEvents.on( + NEXUS_EVENTS.BRIDGE_EXECUTE_EXPECTED_STEPS, + (steps) => setExpectedSteps(steps), + ); + const unsubCompleted = sdk.nexusEvents.on( + NEXUS_EVENTS.BRIDGE_EXECUTE_COMPLETED_STEPS, + (step) => setCompletedStep(step), + ); + return () => { + unsubExpected(); + unsubCompleted(); + }; + }, []); + + return { expectedSteps, completedStep }; +} +``` + +Render `expectedSteps` to show the checklist (intent signed → bridge submitted → execute submitted) and `completedStep` to highlight the active stage or link out to the explorer when a step exposes `step.data.explorerURL`. + +#### 2. Simulate the flow and prompt for approvals + +```typescript +import { + type BridgeAndExecuteParams, + type BridgeAndExecuteSimulationResult, + TOKEN_CONTRACT_ADDRESSES, + TOKEN_METADATA, +} from '@avail-project/nexus-core'; +import { parseUnits } from 'viem'; + +const params: BridgeAndExecuteParams = { + token: 'USDC', + amount: '5000000', // 5,000 USDC with 6 decimals + toChainId: 1, + sourceChains: [8453], + enableTransactionPolling: true, // auto-poll if the provider does not emit receipts + transactionTimeout: 180_000, // 3 minutes + waitForReceipt: true, + requiredConfirmations: 2, + execute: { + contractAddress: '0x87870Bca3F3fD6335C3F4ce8392D69350B4FA4E2', // Aave v3 Pool + contractAbi: [ + { + inputs: [ + { internalType: 'address', name: 'asset', type: 'address' }, + { internalType: 'uint256', name: 'amount', type: 'uint256' }, + { internalType: 'address', name: 'onBehalfOf', type: 'address' }, + { internalType: 'uint16', name: 'referralCode', type: 'uint16' }, + ], + name: 'supply', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + ], + functionName: 'supply', + buildFunctionParams: (token, amount, chainId, userAddress) => { + const decimals = TOKEN_METADATA[token].decimals; + const amountWei = parseUnits(amount, decimals); + const tokenAddress = TOKEN_CONTRACT_ADDRESSES[token][chainId]; + return { + functionParams: [tokenAddress, amountWei, userAddress, 0], + }; + }, + tokenApproval: { + token: 'USDC', + amount: '5000000', + }, + }, +}; + +const preview: BridgeAndExecuteSimulationResult = await sdk.simulateBridgeAndExecute(params); + +if (!preview.success) { + throw new Error(preview.error || 'Simulation failed'); +} + +if (preview.metadata?.approvalRequired) { + // Trigger your allowance modal – show preview.metadata.minApproval to the user. +} +``` + +Simulations also return the full `steps` array so you can pre-render the UI timeline while the user decides whether to proceed. + +#### 3. Submit the bridge and staking call + +```typescript +const result: BridgeAndExecuteResult = await sdk.bridgeAndExecute(params); + +if (!result.success) { + console.error('Bridge + stake failed:', result.error); + return; +} + +// Update the UI immediately after each phase +if (result.approvalTransactionHash) { + setApprovalLink(result.approvalTransactionHash); +} + +if (result.bridgeTransactionHash) { + setBridgeLink(result.bridgeExplorerUrl ?? result.bridgeTransactionHash); +} + +if (result.executeTransactionHash) { + setStakeLink(result.executeExplorerUrl ?? result.executeTransactionHash); +} +``` + +- With `waitForReceipt: true`, the promise resolves only after the execute transaction reaches 2 confirmations (configurable via `requiredConfirmations`). Surface `result.executeExplorerUrl` as “Funds staked” in the UI. +- Without waiting for receipts you can still poll your own subgraph or rely on `enableTransactionPolling` so the SDK polls for hashes on RPCs that delay responses. + +#### 4. Keep the UI in sync post-submission + +Even after the promise resolves, you may want to periodically refresh balances or intent status: + +```typescript +// Example poller to refresh balances + confirmations every 15 seconds +const interval = window.setInterval(async () => { + const balances = await sdk.getUnifiedBalances(); + updatePortfolio(balances); +}, 15_000); + +// When you no longer need updates +window.clearInterval(interval); +``` + +Pairing periodic refreshes with the progress events from Step 1 guarantees that users always see the latest state: intent accepted, bridge mined, Aave supply confirmed, and the resulting aUSDC balance increase. diff --git a/app/nexus/avail-nexus-sdk/nexus-core/bridge-and-execute/bridge-and-execute-tutorial.md b/app/nexus/avail-nexus-sdk/nexus-core/bridge-and-execute/bridge-and-execute-tutorial.md new file mode 100644 index 000000000..e807483ba --- /dev/null +++ b/app/nexus/avail-nexus-sdk/nexus-core/bridge-and-execute/bridge-and-execute-tutorial.md @@ -0,0 +1,210 @@ +# End-to-End `bridgeAndExecute` Tutorial + +A guided walkthrough for full-stack developers who want to move tokens **and** call a contract in one flow using `bridgeAndExecute`. If you already read the `getUnifiedBalances` tutorial, this picks up where it left off and focuses on the full bridge + execution journey with clear explanations, configuration tips, and response-handling best practices. + +## What you will build + +A minimal Node/TypeScript script that: + +1. Initializes the Nexus SDK with your wallet provider +2. Simulates a bridge + execute flow to preview costs and approvals +3. Bridges USDC from Base to Ethereum **and** deposits it into a Yearn USDC vault +4. Streams progress updates (bridge + execution stages) +5. Waits for receipts and confirmations following production-ready practices + +> Feel free to swap the contract, ABI, or destination chain—this tutorial highlights the pieces you need to change later on. + +## Prerequisites + +- Node 18+ and pnpm/npm/yarn +- An EIP-1193 provider (e.g., injected wallet like MetaMask, or a viem `walletClient` wrapped as a provider) +- USDC on Base for the example flow (or adjust `token`/`sourceChains` as needed) +- Basic TypeScript familiarity (no web3 expertise required) + +## Install dependencies + +```bash +npm install @avail-project/nexus-core viem dotenv +``` + +- `@avail-project/nexus-core` – headless SDK +- `viem` – ergonomic provider utilities (works great with Nexus) +- `dotenv` – keep keys out of source control + +## Configure an EIP-1193 provider + +Nexus only needs a standard EIP-1193 provider. The snippet below shows how to adapt a viem wallet client into that shape for Node scripts. In a browser app you can simply pass `window.ethereum`. + +Note that the below example shows a simplified way of handling the private key (and secrets in general). For production, a better validation flow and secret handling is adviseable. + +```ts +// src/provider.ts +import { createWalletClient, http } from 'viem'; +import { base, mainnet } from 'viem/chains'; +import { privateKeyToAccount } from 'viem/accounts'; + +const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`); + +// Use Base as the default chain; Nexus will route bridge legs for you +const walletClient = createWalletClient({ + account, + chain: base, + transport: http(process.env.RPC_URL || 'https://mainnet.base.org'), +}); + +// viem exposes an EIP-1193-compatible provider on the client +export const provider = walletClient.transport as unknown as any; // satisfies EthereumProvider +``` + +> **Security tip:** keep `PRIVATE_KEY` and `RPC_URL` in `.env` and never commit them. + +## Understand the `bridgeAndExecute` inputs + +`bridgeAndExecute` combines a bridge with a contract call on the destination chain. Key properties: + +- **token** – symbol from `SUPPORTED_TOKENS` (e.g., `"USDC"`). +- **amount** – string amount in token units (e.g., `"100"` for 100 USDC). The SDK normalizes to wei internally. +- **toChainId** – numeric chain ID where the contract call runs (Ethereum in the example). +- **sourceChains** – optional array restricting which chains to pull liquidity from. Use it to avoid slow/expensive sources. +- **execute** – describes the destination contract call: + - `contractAddress`, `contractAbi`, `functionName` – standard ABI call details. + - `buildFunctionParams(token, amount, chainId, userAddress)` – returns `{ functionParams, value? }` with properly formatted arguments. Use this to convert amounts to wei and insert token addresses for the target chain. + - `tokenApproval` – optional approval to request before execution (token + amount in wei). Omit if not needed. + - `value` – optional native value to forward (e.g., when calling a payable function). +- **waitForReceipt** – when `true`, SDK waits for the destination execution receipt. +- **requiredConfirmations** – number of block confirmations to wait for after the receipt (useful for production safety). + +### Best practices before calling + +1. **Always simulate** with `simulateBridgeAndExecute` to get gas/fee estimates, approval requirements, and the planned route. +2. **Validate balances** with `getUnifiedBalances` if you want to short-circuit when the user already has funds on the target chain. +3. **Cap approvals** – set `tokenApproval.amount` to the exact amount you need instead of `MAX_UINT`. +4. **Timeouts and polling** – keep `waitForReceipt` + `requiredConfirmations` for production, but surface a loading UI that respects the bridge duration. +5. **Log hashes** – persist `bridgeTransactionHash`, `approvalTransactionHash`, and `executeTransactionHash` so you can rehydrate UI state after a refresh. + +## Full example + +```ts +// src/bridge-and-execute.ts +import 'dotenv/config'; +import { parseUnits } from 'viem'; +import { + NexusSDK, + TOKEN_METADATA, + type SUPPORTED_TOKENS, + type SUPPORTED_CHAINS_IDS, + NEXUS_EVENTS, +} from '@avail-project/nexus-core'; +import { provider } from './provider'; + +async function main() { + const sdk = new NexusSDK({ network: 'mainnet' }); + await sdk.initialize(provider); + + // Optional: listen for granular bridge + execute step updates + sdk.nexusEvents.on(NEXUS_EVENTS.BRIDGE_EXECUTE_COMPLETED_STEPS, (step) => { + console.log(`[step] ${step.type}:`, step.data); + }); + + const params = { + token: 'USDC', + amount: '100', // in token units + toChainId: 1, // Ethereum + sourceChains: [8453], // Prefer pulling USDC from Base + execute: { + contractAddress: '0xa354F35829Ae975e850e23e9615b11Da1B3dC4DE', // Yearn USDC vault + contractAbi: [ + { + inputs: [ + { internalType: 'uint256', name: 'assets', type: 'uint256' }, + { internalType: 'address', name: 'receiver', type: 'address' }, + ], + name: 'deposit', + outputs: [{ internalType: 'uint256', name: 'shares', type: 'uint256' }], + stateMutability: 'nonpayable', + type: 'function', + }, + ], + functionName: 'deposit', + buildFunctionParams: + (token: SUPPORTED_TOKENS, amount: string, chainId: SUPPORTED_CHAINS_IDS, user: `0x${string}`) => { + const decimals = TOKEN_METADATA[token].decimals; + const amountWei = parseUnits(amount, decimals); + return { + functionParams: [amountWei, user], + }; + }, + tokenApproval: { + token: 'USDC', + amount: parseUnits('100', TOKEN_METADATA.USDC.decimals).toString(), + }, + }, + waitForReceipt: true, + requiredConfirmations: 3, + } as const; + + // 1) Simulate to surface costs, approvals, and routing + const simulation = await sdk.simulateBridgeAndExecute(params); + if (!simulation.success) { + console.error('Simulation failed:', simulation.error); + return; + } + + console.log('Route overview:', simulation.steps); + console.log('Estimated total cost:', simulation.totalEstimatedCost); + if (simulation.metadata?.approvalRequired) { + console.log('Approval required:', simulation.metadata.approvalRequired); + } + + // 2) Run the real transaction + const result = await sdk.bridgeAndExecute(params); + + if (!result.success) { + console.error('Bridge + execute failed:', result.error); + return; + } + + // 3) Production-friendly response handling + console.log('Bridge tx hash:', result.bridgeTransactionHash); + console.log('Execute tx hash:', result.executeTransactionHash); + console.log('Explorer links:', { + bridge: result.bridgeExplorerUrl, + execute: result.executeExplorerUrl, + }); + + if (result.bridgeSkipped) { + console.log('Bridge skipped: funds already available on destination chain.'); + } + + // Clean up your listener when done + sdk.nexusEvents.removeAllListeners(NEXUS_EVENTS.BRIDGE_EXECUTE_COMPLETED_STEPS); +} + +main().catch((err) => { + console.error(err); + process.exit(1); +}); +``` + +### Notes on the example +Some of the practices used in the example for better usage in production user interface: + +- **Simulation first** catches allowance issues and previews the exact steps (including chain abstraction routes). +- **`waitForReceipt` + confirmations** ensure the contract call is finalized, which is critical for downstream business logic. +- **Step events** let you stream progress to your UI (or logs) during longer bridge legs. +- **Explicit approvals** scope token allowances to the amount you actually need. +- **Route constraints** via `sourceChains` help you avoid illiquid or slow chains. + +## Handling responses safely + +- **Persist hashes**: store the transaction hashes and explorer URLs so you can rebuild UI state after refresh or process restarts. +- **Map stages to UX**: use `simulation.steps` and runtime step events to display stages like "bridging", "waiting for settlement", "executing", and "confirming". +- **Timeout strategy**: if you set client-side timers, keep them generous—bridges may take minutes. Prefer showing the live step stream over hard timeouts. +- **Error surfaces**: the SDK returns structured errors (`result.error`) and also emits a final `operation.failed` step; display both in UI for clarity. +- **Reconciliation**: after success, call `getUnifiedBalances` again to refresh balances on the destination chain and verify the vault receipt/shares. + +## Next steps + +- Swap in your own ABI + params builder to target different protocols (staking, lending, DEX interactions, etc.). +- Gate flows with `simulateBridgeAndExecute` + `getUnifiedBalances` checks to avoid redundant bridges when funds already exist on the destination chain. +- Combine with the widgets package if you want pre-built UI components once the headless flow is working. \ No newline at end of file diff --git a/app/nexus/avail-nexus-sdk/nexus-core/bridge-and-execute/page.mdx b/app/nexus/avail-nexus-sdk/nexus-core/bridge-and-execute/page.mdx index 2546b2a68..abdfe77e1 100644 --- a/app/nexus/avail-nexus-sdk/nexus-core/bridge-and-execute/page.mdx +++ b/app/nexus/avail-nexus-sdk/nexus-core/bridge-and-execute/page.mdx @@ -13,7 +13,46 @@ import { Callout, Steps, Tabs } from 'nextra/components' 2. We also [created a tutorial](/nexus/nexus-examples/nexus-initialization-basic) to make it easier to understand how devs need to initialize the Nexus SDK in their project. -Use the `bridgeAndExecute()` function to bridge a token and execute a contract function on the recipient chain in a single flow. +The `bridgeAndExecute` method enables **atomic cross-chain operations** - allowing you to bridge assets from one chain to another and immediately execute a smart contract call in a single transaction. This eliminates the need for multiple steps and reduces the risk of MEV attacks, failed transactions, or price slippage that can occur when bridging and executing separately. + +### Key Benefits + +- **Atomic Execution**: Both the bridge and subsequent operation succeed or fail together +- **Reduced Complexity**: Single transaction instead of multiple steps +- **Improved User Experience**: Users get their desired outcome in one interaction +- **Cost Efficiency**: Potentially lower overall gas costs +- **MEV Protection**: Minimizes front-running opportunities + +### Common Use Cases + +- Bridging tokens and immediately swapping to another token +- Cross-chain yield farming deposits +- Bridging NFTs and listing them on a marketplace +- Cross-chain liquidity provision +- Bridging and staking in one transaction + +## How It Works + +The `bridgeAndExecute` process follows this sequence: + +### Step 1: Initiation +Your dApp calls the `bridgeAndExecute` method with both the bridging parameters and the execution payload for the destination chain. + +### Step 2: Source Chain Processing +- Tokens are locked or burned on the source chain +- Bridge message is emitted with both the asset transfer details and execution instructions + +### Step 3: Cross-Chain Messaging +The bridge protocol relays the message to the destination chain, ensuring the execution payload is included. + +### Step 4: Atomic Execution on Destination +On the destination chain: +1. Tokens are minted or released to the user +2. The specified contract is immediately called with the provided calldata +3. Both operations are atomic - if either fails, the entire transaction reverts + +### Step 5: Confirmation +Your application receives a response with transaction details to track the operation. ## Method signature @@ -28,6 +67,7 @@ async simulateBridgeAndExecute(params: BridgeAndExecuteParams): Promise { + const amountWei = parseUnits(amount, 18); + return { + // Stake without referral and send the bridged ETH as msg.value + functionParams: ['0x0000000000000000000000000000000000000000'], + value: amountWei.toString(), + }; + }, + }, + waitForReceipt: true, +} as BridgeAndExecuteParams); +... + +``` + ## Return Value The return value is a `BridgeAndExecuteResult` object. diff --git a/app/nexus/avail-nexus-sdk/nexus-core/fetch-unified-balances/fetch-unified-balances-tutorial.md b/app/nexus/avail-nexus-sdk/nexus-core/fetch-unified-balances/fetch-unified-balances-tutorial.md new file mode 100644 index 000000000..e9745aaad --- /dev/null +++ b/app/nexus/avail-nexus-sdk/nexus-core/fetch-unified-balances/fetch-unified-balances-tutorial.md @@ -0,0 +1,191 @@ +# `getUnifiedBalances` End-to-End Guide + +The `getUnifiedBalances` method collects a user's on-chain portfolio across every chain that Nexus knows about. The call is a great way to have a single source of truth for every balance-aware widget in your application, from asset pickers to transaction reviews and more. Handling and setting up the the experience well in your front-end requires a bit more work as you depend on a larger number of concurrent calls with different properties and guarantees. This document provides some best practices for working with the call in your UI to achieve the best results. + +This document walks through: + +1. Preparing the SDK +2. Calling `getUnifiedBalances` +3. Understanding the response shape +4. Rendering balances in a production-ready UI with resilient UX patterns + +--- + +## 1. Prerequisites + +- Install the core SDK and peers: `npm install @avail-project/nexus-core viem` +- Make sure you have a connected wallet provider (e.g., `window.ethereum`) +- Initialize the SDK once during app bootstrap, then reuse the instance everywhere + +```ts +import { NexusSDK } from '@avail-project/nexus-core'; + +const sdk = new NexusSDK({ network: 'mainnet' }); +await sdk.initialize(window.ethereum); +``` + +> **Tip:** Run `initialize` after the wallet is connected. This lets Nexus read the current account and chain before any balance calls go out. + +--- + +## 2. Fetching unified balances + +```ts +const balances = await sdk.getUnifiedBalances(); +``` + +Calling `getUnifiedBalances` automatically: + +- Fetches balances for every supported chain +- Normalizes token decimals +- Calculates fiat equivalents (USD) for each entry +- Groups the raw sources in a `breakdown` array so UIs can explain where funds sit + +Because `getUnifiedBalances` makes multiple RPC/intent requests under the hood, prefer memoized calls (React Query, SWR, Zustand store) instead of calling it inside render loops. + +--- + +## 3. Response shape + +Each entry in the returned array is a `UserAsset`: + +```ts +export type UserAsset = { + symbol: string; // e.g., 'USDC' + decimals: number; // 6 for USDC, 18 for ETH, etc. + balance: string; // human-readable balance (already decimal adjusted) + balanceInFiat: number; // USD value of the total balance + icon?: string; // CDN URL for token icon (optional) + abstracted?: boolean; // True if the asset is available via chain abstraction + breakdown: Array<{ + balance: string; // chain-specific portion of the balance + balanceInFiat: number; // USD value for that portion + chain: { + id: number; // EVM chain ID + name: string; // Human label, e.g., 'Base' + logo: string; // Logo URL for the chain + }; + decimals: number; + contractAddress: `0x${string}`; + isNative?: boolean; // Native ETH/MATIC/etc. + universe: 'evm' | 'fuel' | 'cosmos'; + }>; +}; +``` + +### Common UI operations + +- Convert `balance` to `number` or `bigint` for calculations via `parseFloat` / `parseUnits` +- Aggregate totals per chain by summing `breakdown` +- Flag abstracted balances (e.g., "Available through Chain Abstraction") + +--- + +## 4. UI integration best practices + +### 4.1 React hook using TanStack Query (recommended) + +```tsx +import { useQuery } from '@tanstack/react-query'; +import { sdk } from './nexus-sdk-instance'; + +export function useUnifiedBalances() { + return useQuery({ + queryKey: ['nexus', 'unified-balances'], + queryFn: () => sdk.getUnifiedBalances(), + staleTime: 30_000, // cache for 30s to avoid spam + refetchInterval: 60_000, // background refresh + retry: 2, // auto-retry transient RPC issues + }); +} +``` + +Why TanStack Query? + +- Deduplicates concurrent requests when multiple components need balances +- Survives re-renders and route changes +- Gives you `isLoading`, `isError`, and `refetch` helpers for UI states + +### 4.2 Rendering component with skeleton, error, empty states + +```tsx +import { formatUSD } from './currency'; +import { useUnifiedBalances } from './useUnifiedBalances'; + +export function PortfolioPanel() { + const { data, isLoading, isError, refetch } = useUnifiedBalances(); + + if (isLoading) return ; + if (isError) + return ( + + ); + + if (!data?.length) return ; + + return ( +
+ {data.map((asset) => ( +
+
+ +
+ {asset.symbol} + {asset.balance} +
+
+
{formatUSD(asset.balanceInFiat)}
+ +
+ ))} +
+ ); +} +``` + +### 4.3 Showing the chain breakdown (modal or drawer) + +```tsx +function openBreakdown(asset: UserAsset) { + showModal({ + title: `${asset.symbol} sources`, + body: ( +
    + {asset.breakdown.map((entry) => ( +
  • + + {entry.balance} + {formatUSD(entry.balanceInFiat)} + {entry.isNative && Native} + {asset.abstracted && Abstracted} +
  • + ))} +
+ ), + }); +} +``` + +### 4.4 Additional UX recommendations + +- **Keep totals consistent**: Derive UI totals from `balanceInFiat` rather than recalculating on the client, to avoid rounding drift with large decimal tokens. +- **Sort deterministically**: Sort by `balanceInFiat` (desc) or alphabetically so that rows do not jump between renders. +- **Respect chain context**: When a user switches wallet chains, call `sdk.initialize` again or trigger a refetch so balances stay accurate. +- **Highlight actionable entries**: Show "Bridge" or "Send" buttons inline when `asset.balanceInFiat` exceeds a threshold. +- **Avoid blocking UI**: Never gate the page behind the balance call; render skeletons or cached data immediately and refresh in the background. +- **Accessibility**: Use semantic lists/tables and ensure fiat + token amounts have `aria-label`s (e.g., "15.23 USDC on Base"). + +--- + +## 5. Testing strategies + +- **Unit test parsing**: Mock `sdk.getUnifiedBalances` to return fixture data and ensure your selectors (totals, breakdown) behave as expected. +- **Integration test flows**: In Playwright/Cypress, stub the SDK call to simulate loading, error, and success states. +- **Performance checks**: Measure render time with 20+ assets to ensure the UI remains responsive; memoize derived data if necessary. + +With these patterns, `getUnifiedBalances` becomes a single source of truth for every balance-aware widget in your application, from asset pickers to transaction reviews.