Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
5f03ecb
loading spinner faster
shrinathprabhu Jul 16, 2026
e935d4b
Add onramp
shrinathprabhu Jul 22, 2026
7e0fb0d
Merge branch 'main' into feat/onramp-meld
shrinathprabhu Jul 29, 2026
1039cd3
Update api to original ramp api
shrinathprabhu Jul 30, 2026
6be0bcf
Send ack once message is received
shrinathprabhu Jul 30, 2026
370951a
Add bug fixes
shrinathprabhu Jul 30, 2026
ece9114
Finally done
shrinathprabhu Jul 30, 2026
035067c
Update opportunities
shrinathprabhu Jul 31, 2026
98be467
Fix the offline quoting thing
shrinathprabhu Jul 31, 2026
072e791
handle server errors
shrinathprabhu Jul 31, 2026
5b8800c
log return url
shrinathprabhu Aug 14, 2026
4759577
Swap the gas
shrinathprabhu Aug 25, 2026
2842909
Add country to currency
shrinathprabhu Aug 25, 2026
621c199
Add france logo to EU
shrinathprabhu Aug 25, 2026
3b7fa23
Add slippage and min received
shrinathprabhu Aug 26, 2026
eafaf70
Fix the issues
shrinathprabhu Aug 26, 2026
c77df55
Create an rc release
shrinathprabhu Sep 1, 2026
f070b5e
Add option for onramp
shrinathprabhu Sep 8, 2026
c5742a7
Fix onramp issues
shrinathprabhu Sep 8, 2026
488f355
Update onramp and add history support for onramp
shrinathprabhu Sep 10, 2026
7a73c14
get flag from meld api
shrinathprabhu Sep 16, 2026
2734ab4
add metadata from data
shrinathprabhu Sep 17, 2026
ae50e38
add normalized payment methods and logos
shrinathprabhu Sep 17, 2026
36d88fa
Update google pay logo
shrinathprabhu Sep 17, 2026
a4c2afc
Update rc2
shrinathprabhu Sep 18, 2026
89f2810
Merge branch 'main' into feat/onramp-meld
shrinathprabhu Sep 18, 2026
0733972
Update registry
shrinathprabhu Sep 18, 2026
f050e58
bump up rc3
shrinathprabhu Sep 18, 2026
e91671b
Update the styles
shrinathprabhu Sep 23, 2026
9fe638b
bump up a release version
shrinathprabhu Sep 25, 2026
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
12 changes: 11 additions & 1 deletion .github/workflows/publish-widgets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,16 @@ jobs:
working-directory: ${{ env.PACKAGE_DIR }}
run: npm pack --dry-run

- name: Determine npm dist-tag
id: dist-tag
run: |
VERSION="${{ steps.package.outputs.version }}"
if [[ "$VERSION" == *-rc.* ]] || [[ "$VERSION" == *-beta.* ]] || [[ "$VERSION" == *-alpha.* ]]; then
echo "tag=rc" >> "$GITHUB_OUTPUT"
else
echo "tag=latest" >> "$GITHUB_OUTPUT"
fi

- name: Publish package with trusted publishing
working-directory: ${{ env.PACKAGE_DIR }}
run: npm publish --access public
run: npm publish --access public --tag ${{ steps.dist-tag.outputs.tag }}
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ function buildDepositExecuteConfig(
<NexusWidget
config={{
mode: "deposit",
enableOnRamp: true, // Optional; defaults to false (wallet funding only).
destination: {
chain: 42161,
tokens: [
Expand Down
63 changes: 63 additions & 0 deletions app/onramp/complete/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"use client";

import React from "react";
import { logOnramp } from "@/registry/avail-widgets/nexus-widget/utils/onramp-session";

const ONRAMP_SUCCESS_MESSAGE = "nexus-onramp-success";
const ONRAMP_SUCCESS_ACK_MESSAGE = "nexus-onramp-success-received";

export default function OnrampCompletePage() {
React.useEffect(() => {
let closed = false;
logOnramp("provider.return_page", { hasOpener: Boolean(window.opener) });

const closePage = () => {
if (closed) return;
closed = true;
logOnramp("provider.return_page.close");
window.close();
};

const handleMessage = (event: MessageEvent) => {
if (
event.source !== window.opener ||
event.data !== ONRAMP_SUCCESS_ACK_MESSAGE
)
return;
logOnramp("provider.return_page.acknowledged");
closePage();
};

window.addEventListener("message", handleMessage);
const closeTimeout = window.setTimeout(closePage, 3000);

try {
window.opener?.postMessage(ONRAMP_SUCCESS_MESSAGE, "*");
} catch {
// The provider can return without an opener in some browser flows.
}

return () => {
window.removeEventListener("message", handleMessage);
window.clearTimeout(closeTimeout);
};
}, []);

return (
<main
style={{
alignItems: "center",
color: "#161615",
display: "grid",
fontFamily:
'ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
minHeight: "100vh",
padding: "24px",
textAlign: "center",
}}
>
Returning to payment status. Keep the original page open to finish your
deposit.
</main>
);
}
137 changes: 65 additions & 72 deletions components/showcase/nexus-widget-deposit-showcase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
} from "viem";
import { useAccount } from "wagmi";
import { useConnectWalletClick } from "../helpers/use-connect-wallet-click";
import { cn } from "@/lib/utils";
import {
NexusWidgetRenderModeToggle,
type NexusWidgetRenderMode,
Expand Down Expand Up @@ -223,29 +224,15 @@ const resolveDepositAddress = (opportunity: DepositShowcaseOpportunity) => {
const OPPORTUNITIES = {
// 1. Aave on Arbitrum
"aave-arbitrum": {
label: "Aave - Arbitrum",
label: "Aave - Optimism",
protocol: "Aave",
depositTargetLogo:
"https://files.availproject.org/uploads/2026-04-16/aave.svg",
chainId: 42161,
tokenSymbol: "USD₮0",
tokenAddress: "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9" as const,
chainId: 10,
tokenSymbol: "USDC",
tokenAddress: "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85" as const,
tokenDecimals: 6,
tokenLogo: "https://arbiscan.io/token/images/centre-usdc_28.png",
tokens: [
{
address: "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9",
decimals: 6,
logo: "https://arbiscan.io/token/images/usdt0_64.png",
symbol: "USD₮0",
},
{
address: "0xba5DdD1f9d7F570dc94a51479a000E3BCE967196",
decimals: 18,
logo: "https://arbiscan.io/token/images/aave_32.svg",
symbol: "AAVE",
},
],
tokenLogo: "https://optimistic.etherscan.io/token/images/usdc_32.png",
executeDeposit: (
symbol: string,
tokenAddress: `0x${string}`,
Expand All @@ -269,46 +256,28 @@ const OPPORTUNITIES = {
},

// 2. Aave on Ethereum
"aave-ethereum": {
label: "Aave - Ethereum",
"aave-bsc": {
label: "Aave - BSC",
protocol: "Aave",
depositTargetLogo:
"https://files.availproject.org/uploads/2026-04-16/aave.svg",
chainId: 1,
chainId: 56,
tokenSymbol: "USDC",
tokenAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" as const,
tokenDecimals: 6,
tokenLogo: "https://etherscan.io/token/images/usdc_ofc_32.svg",
tokenAddress: "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d" as const,
tokenDecimals: 18,
tokenLogo: "https://bscscan.com/token/images/centre-usdc_28.png",
tokens: [
{
address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
decimals: 6,
logo: "https://etherscan.io/token/images/usdc_ofc_32.svg",
symbol: "USDC",
},
{
address: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
decimals: 6,
logo: "https://etherscan.io/token/images/tethernew_32.svg",
symbol: "USDT",
},
{
address: "0x40D16FC0246aD3160Ccc09B8D0D3A2cD28aE6C2f",
decimals: 18,
logo: "https://etherscan.io/token/images/aavegho_new_32.png",
symbol: "GHO",
},
{
address: "0x6B175474E89094C44Da98b954EedeAC495271d0F",
address: "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d",
decimals: 18,
logo: "https://etherscan.io/token/images/dairplce_32.svg",
symbol: "DAI",
logo: "https://bscscan.com/token/images/centre-usdc_28.png",
symbol: "USDC",
},
{
address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
address: "0x55d398326f99059fF775485246999027B3197955",
decimals: 18,
logo: "https://etherscan.io/token/images/weth_28.png",
symbol: "WETH",
logo: "https://bscscan.com/token/images/busdt_32.png",
symbol: "USDT",
},
],
executeDeposit: (
Expand All @@ -318,7 +287,7 @@ const OPPORTUNITIES = {
chainId: number,
user: `0x${string}`,
) => ({
to: "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2" as const,
to: "0x6807dc923806fE8Fd134338EABCA509979a7e0cB" as const,
gas: BigInt(400_000),
data: encodeFunctionData({
abi: AAVE_ABI,
Expand All @@ -328,30 +297,29 @@ const OPPORTUNITIES = {
tokenApproval: {
toTokenAddress: tokenAddress,
amount,
spender: "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2" as const,
spender: "0x6807dc923806fE8Fd134338EABCA509979a7e0cB" as const,
},
}),
},

// 3. Compound on Polygon (USDT)
"compound-pol-usdt": {
"compound-eth-usdt": {
protocol: "Compound",
depositTargetLogo:
"https://files.availproject.org/uploads/2026-04-16/compound.svg",
chainId: 137,
chainId: 1,
tokenSymbol: "USDT",
tokenAddress: "0xc2132D05D31c914a87C6611C10748AEb04B58e8F" as const,
tokenAddress: "0xdAC17F958D2ee523a2206206994597C13D831ec7" as const,
tokenDecimals: 6,
tokenLogo:
"https://raw.githubusercontent.com/availproject/nexus-assets/refs/heads/main/tokens/usdt/logo.png",
tokenLogo: "https://etherscan.io/token/images/tethernew_32.svg",
executeDeposit: (
symbol: string,
tokenAddress: `0x${string}`,
amount: bigint,
chainId: number,
user: `0x${string}`,
) => ({
to: "0xaeB318360f27748Acb200CE616E389A6C9409a07" as const,
to: "0x3Afdc9BCA9213A35503b077a6072F3D0d5AB0840" as const,
gas: BigInt(400_000),
data: encodeFunctionData({
abi: COMPOUND_ABI,
Expand All @@ -361,29 +329,28 @@ const OPPORTUNITIES = {
tokenApproval: {
toTokenAddress: tokenAddress,
amount,
spender: "0xaeB318360f27748Acb200CE616E389A6C9409a07" as const,
spender: "0x3Afdc9BCA9213A35503b077a6072F3D0d5AB0840" as const,
},
}),
},

// 4. Fluid on Base (USDC)
"fluid-base-usdc": {
"fluid-arb-usdc": {
protocol: "Fluid",
depositTargetLogo: "https://fluid.instad.app/images/logo.png",
chainId: 8453,
chainId: 42161,
tokenSymbol: "USDC",
tokenAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" as const,
tokenAddress: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831" as const,
tokenDecimals: 6,
tokenLogo:
"https://raw.githubusercontent.com/availproject/nexus-assets/refs/heads/main/tokens/usdc/logo.png",
tokenLogo: "https://arbiscan.io/token/images/centre-usdc_28.png",
executeDeposit: (
symbol: string,
tokenAddress: `0x${string}`,
amount: bigint,
chainId: number,
user: `0x${string}`,
) => ({
to: "0xf42f5795D9ac7e9D757dB633D693cD548Cfd9169" as const,
to: "0x1A996cb54bb95462040408C06122D45D6Cdb6096" as const,
gas: BigInt(400_000),
data: encodeFunctionData({
abi: FLUID_ABI,
Expand All @@ -393,13 +360,14 @@ const OPPORTUNITIES = {
tokenApproval: {
toTokenAddress: tokenAddress,
amount,
spender: "0xf42f5795D9ac7e9D757dB633D693cD548Cfd9169" as const,
spender: "0x1A996cb54bb95462040408C06122D45D6Cdb6096" as const,
},
}),
},

// 5. Mystic on Citrea (ctUSD)
"mystic-citrea-ctusd": {
label: "Mystic ctUSD (onramp not supported)",
protocol: "Mystic",
depositTargetLogo:
"https://files.availproject.org/nexus-elements/mystic.png",
Expand Down Expand Up @@ -432,6 +400,7 @@ const OPPORTUNITIES = {

// 6. Zentra on Citrea (wcBTC)
"zentra-citrea-wcbtc": {
label: "Zentra wcBTC (onramp not supported)",
protocol: "Zentra",
depositTargetLogo:
"https://zentrafinance.gitbook.io/zentra/~gitbook/image?url=https%3A%2F%2F2899070418-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Forganizations%252F1jzW9aBSq190MuRJKgIj%252Fsites%252Fsite_2l6Ro%252Ficon%252Fb8adwB6RA7Y6VJH3vGjh%252FZentra%2520%284%29.png%3Falt%3Dmedia%26token%3D8aa44578-e817-4c2f-b20e-abd25827d4fe&width=32&dpr=3&quality=100&sign=d18163fe&sv=2",
Expand Down Expand Up @@ -473,9 +442,9 @@ const NexusWidgetDepositShowcase = () => {
>("aave-arbitrum");
const [isOpen, setIsOpen] = useState(false);
const [isSandboxModalOpen, setIsSandboxModalOpen] = useState(false);
const [renderMode, setRenderMode] =
useState<NexusWidgetRenderMode>("inline");
const [renderMode, setRenderMode] = useState<NexusWidgetRenderMode>("inline");
const isPopupMode = renderMode === "popup";
const [enableOnRamp, setEnableOnRamp] = useState(true);

// Default sandbox configuration state
const [sandboxConfig, setSandboxConfig] = useState<{
Expand Down Expand Up @@ -746,10 +715,33 @@ const NexusWidgetDepositShowcase = () => {
type="nexus-widget"
connectLabel="Connect wallet to use Deposit"
controls={
<NexusWidgetRenderModeToggle
value={renderMode}
onValueChange={setRenderMode}
/>
<div className="flex flex-wrap items-center gap-2">
<button
type="button"
aria-pressed={enableOnRamp}
onClick={() => setEnableOnRamp((prev) => !prev)}
className={cn(
"inline-flex items-center gap-1.5 h-9 rounded-md border px-3 text-xs font-medium transition-colors shadow-sm cursor-pointer",
enableOnRamp
? "border-zinc-900 bg-zinc-900 text-white dark:border-zinc-100 dark:bg-zinc-100 dark:text-zinc-950"
: "border-zinc-200 bg-white text-zinc-600 hover:bg-zinc-50 hover:text-zinc-900 dark:border-zinc-800 dark:bg-zinc-950 dark:text-zinc-400 dark:hover:bg-zinc-900 dark:hover:text-zinc-100",
)}
>
<span
className={cn(
"w-2 h-2 rounded-full transition-colors",
enableOnRamp
? "bg-emerald-400 dark:bg-emerald-500"
: "bg-zinc-300 dark:bg-zinc-600",
)}
/>
Onramp
</button>
<NexusWidgetRenderModeToggle
value={renderMode}
onValueChange={setRenderMode}
/>
</div>
}
>
<div className="flex flex-col gap-6 w-full items-center">
Expand Down Expand Up @@ -936,7 +928,7 @@ const NexusWidgetDepositShowcase = () => {
}}
>
<NexusWidget
key={`${selectedOpt}-${renderMode}`}
key={`${selectedOpt}-${renderMode}-${enableOnRamp}`}
embed={!isPopupMode}
defaultOpen={isPopupMode}
config={{
Expand All @@ -948,6 +940,7 @@ const NexusWidgetDepositShowcase = () => {
},
depositAddress: resolveDepositAddress(currentOpportunity),
executeDeposit: currentOpportunity.executeDeposit,
enableOnRamp,
appearance: {
appLogoURL: currentOpportunity.depositTargetLogo,
appName: currentOpportunity.protocol,
Expand Down
5 changes: 5 additions & 0 deletions content/docs/components/deposit.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ const APP_DEPOSIT_ABI = [

const depositConfig = {
mode: "deposit",
enableOnRamp: true, // Optional; defaults to false (wallet funding only).
destination: {
chain: DESTINATION_CHAIN_ID,
tokens: [
Expand Down Expand Up @@ -206,6 +207,7 @@ Deposit uses only `mode: "deposit"`. This mode is exact-out: users enter the des
| `config.destination.tokens` | Yes | One or more accepted destination tokens. The token dropdown is limited to this list and is editable only when multiple tokens are supplied. |
| `config.depositAddress` | Yes | Smart contract address for the deposit target. |
| `config.executeDeposit` | Yes | Callback builder returning `{ to, gas, data?, value?, tokenApproval? }` for the final app transaction. `gas` must be a positive `bigint`. |
| `config.enableOnRamp` | Optional | Defaults to `false`. Set `true` to display "Deposit with Cash" alongside wallet funding. |
| `config.prefill.amount` | Optional | Prefills the exact output deposit amount. Must be greater than `0`. |
| `config.validation.minAmount` | Optional | Minimum deposit amount. Must be `0` or greater. |
| `config.validation.maxAmount` | Optional | Maximum deposit amount. Must be greater than `0`. |
Expand All @@ -216,6 +218,8 @@ Deposit uses only `mode: "deposit"`. This mode is exact-out: users enter the des
| `open`, `onOpenChange`, `defaultOpen` | Optional | Control the modal when `embed={false}`. |
| `onStart`, `onComplete`, `onError`, `onClose`, `onConnectClick`, `onConnectWallet` | Optional | Host app callbacks. Use `onConnectClick` to open your app/header wallet modal from the element CTA. |

Set `enableOnRamp: true` to offer wallet and local currency funding. Set it to `false` or omit it to open directly in the wallet deposit flow. The showcase Onramp toggle demonstrates both settings.

### `executeDeposit`

```ts
Expand Down Expand Up @@ -348,6 +352,7 @@ export function MultiDepositShowcase({ address }) {
<NexusWidget
config={{
mode: "deposit",
enableOnRamp: true, // Optional; defaults to false (wallet funding only).
destination: {
chain: OPPORTUNITIES[selectedOpt].chain,
tokens: [OPPORTUNITIES[selectedOpt].token],
Expand Down
Loading