Hooks and Events
The Nexus SDK comes baked in with some helpful hooks and error codes to make your development experience easier.
Hooks
onEvent
Supported by all main SDK functions, this hook allows you to subscribe to progress events for submitted transactions.
Signature
/**
* EventUnion is a union type of all possible event types.
*/
type EventUnion =
| { name: 'STEPS_LIST'; args: BridgeStepType[] }
| { name: 'STEP_COMPLETE'; args: BridgeStepType }
| { name: 'SWAP_STEP_COMPLETE'; args: SwapStepType };
type OnEventParam = {
onEvent?: (event: EventUnion) => void;
};Example
Use onEvent to log the progress of a transaction to the console:
const bridgeResult = await sdk.bridge(
{
token: 'USDC',
amount: 1_500_000n,
recipient: '0x...' // Optional
toChainId: 137, // Polygon
},
{
onEvent: (event) => {
if (event.name === NEXUS_EVENTS.STEPS_LIST) console.log('Bridge steps:', event.args);
if (event.name === NEXUS_EVENTS.STEP_COMPLETE) console.log('Step completed:', event.args);
},
},
);STEPS_LIST is emitted with bridge(), bridgeAndTransfer() and bridgeAndExecute().
swapWithExactIn() and swapWithExactOut() however do emit SWAP_STEP_COMPLETE instead.
const swapResult = await sdk.swapWithExactIn(
{
from: [{ chainId: 10, amount: 1_000_000n, tokenAddress: '0x...' }],
toChainId: 8453,
toTokenAddress: '0x...',
},
{
onEvent: (event) => {
if (event.name === NEXUS_EVENTS.SWAP_STEP_COMPLETE) {
console.log('Swap step:', event.args);
}
},
},
);
onIntentHook
This hook allows you to give your user a way to approve or deny the intent.
Signature
type OnIntentHookData = {
allow: () => void;
deny: () => void;
intent: ReadableIntent; // human-readable breakdown of sources, destination, fees
refresh: (selectedSources?: number[]) => Promise<ReadableIntent>; // recompute plan
};- Call
allow()to continue ordeny()to abort. Model this behaviour behindallowanddenybuttons in your UI. - If you need to re-plan (e.g., change source chains), call
refresh(...)and re-render. - On allow, the SDK marks
INTENT_ACCEPTEDand proceeds to the allowance phase (if required).
Example
sdk.setOnIntentHook(({ intent, allow, deny, refresh }) => {
// Render the plan and fees to the user using `intent`
// Optionally let the user change source chains
if (userApproves) allow();
else deny();
});- If you don’t set this hook, the SDK defaults to allowing the intent automatically.
- After acceptance, allowance approvals (if any) are handled via
onAllowance.
onSwapIntentHook
Use this hook to prompt the user to approve or deny the swap plan before execution begins.
Signature
type OnSwapIntentHookData = {
allow: () => void;
deny: () => void;
intent: SwapIntent;
refresh: () => Promise<SwapIntent>;
};Lifecycle:
- Called during
swapWithExactIn()/swapWithExactOut()after a route is computed and before the actual swap is executed. refresh()recomputes the route (e.g., after user changes inputs); callallow()to proceed ordeny()to abort.- If you don’t set this hook, the SDK defaults to allowing the swap automatically.
Example
sdk.setOnSwapIntentHook(({ intent, allow, deny, refresh }) => {
// Render swap route and destination details from `intent`
// Optionally call `refresh()` if the user tweaks inputs
if (userApproves) allow();
else deny();
});onAllowanceHook
Use this hook to allow your users to approve or deny any additional allowances that are required for an intent to go through.
Signature
type OnAllowanceHookData = {
allow: (values: Array<'max' | 'min' | bigint | string>) => void;
deny: () => void;
sources: {
allowance: { current: string; minimum: string };
chain: { id: number; logo: string; name: string };
token: { contractAddress: `0x${string}`; decimals: number; logo: string; name: string; symbol: string };
}[];
};- Call
allow(values)to approve the allowances.valuesis an array of strings, numbers, or bigints that represent the amount of the allowance. - Call
deny()to abort if the user does not want to approve the allowances. sourcesis an array of objects that represent the sources of the allowances.
Example
sdk.setOnAllowanceHook(({ allow, deny, sources }) => {
// `sources` is an array of objects with minAllowance, chainID, token symbol, etc.
// allow(values): continues the transaction flow with the specified allowances;
// `values` is an array with the chosen allowance for each of the requirements (values.length === sources.length), either 'min', 'max', a bigint or a string
// deny(): stops the flow
if (userApproves) allow(['min']); // or ['max'] or custom per source
else deny();
});- Values:
- ‘min’: set minimum required allowance for that source
- ‘max’: set unlimited (maxUint256) for that source`
Behavior:
- Fires after the intent is accepted via
setOnIntentHook. - If not set, the SDK defaults to
minfor each source. - Progress events for approvals appear via
onEventas allowance steps complete.
Error Codes
Recommended Error Handling Pattern
The Nexus SDK uses the NexusError class to throw errors.
It extends the built-in Error class and adds a code property to the error object.
function handleNexusError(err: unknown) {
if (err instanceof NexusError) {
console.error(`[${err.code}] ${err.message}`);
if (err.data?.context) {
console.error(`Context: ${err.data.context}`);
}
if (err.data?.details) {
console.error('Details:', err.data.details);
}
switch (err.code) {
case ERROR_CODES.USER_DENIED_INTENT:
case ERROR_CODES.USER_DENIED_ALLOWANCE:
alert('You rejected the transaction. Please try again.');
break;
case ERROR_CODES.INSUFFICIENT_BALANCE:
alert('Your wallet does not have enough funds.');
break;
case ERROR_CODES.TRON_DEPOSIT_FAIL:
case ERROR_CODES.FUEL_DEPOSIT_FAIL:
console.warn('Deposit failed');
// Possibly ask user to retry
break;
default:
// Unknown but typed error
console.error('Unexpected NexusError:', err.toJSON());
}
// Optional:
logErrorToService(err.toJSON());
} else {
// Non-Nexus errors (network, library, etc.)
console.error('Unexpected error:', err);
}
}Complete List of ERROR_CODES
The Nexus SDK also provides a list of error codes that can be used to identify the type of error that occurred, and handle them accordingly.
You can view the list of error codes and their signatures respectively in the Nexus SDK Github repo:
import { ERROR_CODES } from '@avail-project/nexus-core';
export const ERROR_CODES = {
INVALID_VALUES_ALLOWANCE_HOOK: 'INVALID_VALUES_ALLOWANCE_HOOK',
SDK_NOT_INITIALIZED: 'SDK_NOT_INITIALIZED',
CHAIN_NOT_FOUND: 'CHAIN_NOT_FOUND',
INTERNAL_ERROR: 'INTERNAL_ERROR',
TOKEN_NOT_SUPPORTED: 'TOKEN_NOT_SUPPORTED',
TRON_DEPOSIT_FAIL: 'TRON_DEPOSIT_FAIL',
TRON_APPROVAL_FAIL: 'TRON_APPROVAL_FAIL',
FUEL_DEPOSIT_FAIL: 'FUEL_DEPOSIT_FAIL',
LIQUIDITY_TIMEOUT: 'LIQUIDITY_TIMEOUT',
USER_DENIED_INTENT: 'USER_DENIED_INTENT',
USER_DENIED_ALLOWANCE: 'USER_DENIED_ALLOWANCE',
USER_DENIED_INTENT_SIGNATURE: 'USER_DENIED_INTENT_SIGNATURE',
INSUFFICIENT_BALANCE: 'INSUFFICIENT_BALANCE',
WALLET_NOT_CONNECTED: 'WALLET_NOT_CONNECTED',
USER_DENIED_SIWE_SIGNATURE: 'USER_DENIED_SIWE_SIGNATURE',
FETCH_GAS_PRICE_FAILED: 'FETCH_GAS_PRICE_FAILED',
SIMULATION_FAILED: 'SIMULATION_FAILED',
CONNECT_ACCOUNT_FAILED: 'CONNECT_ACCOUNT_FAILED',
VAULT_CONTRACT_NOT_FOUND: 'VAULT_CONTRACT_NOT_FOUND',
SLIPPAGE_EXCEEDED_ALLOWANCE: 'SLIPPAGE_EXCEEDED_ALLOWANCE',
RFF_FEE_EXPIRED: 'RFF_FEE_EXPIRED',
} as const;