Skip to content

Commit 46d5bf4

Browse files
authored
Merge pull request #4187 from ava-labs/refactor/use-avalanche-sdk
refactor(console): migrate warp helpers to @avalanche-sdk/interchain
2 parents b951b7f + 20167e9 commit 46d5bf4

63 files changed

Lines changed: 658 additions & 1107 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

app/console/layout.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { baseOptions } from "@/app/layout.config";
2121
import { NavbarDropdownInjector } from "@/components/navigation/navbar-dropdown-injector";
2222
import { StepErrorBoundary } from "@/components/toolbox/components/StepErrorBoundary";
2323
import { CommandPalette } from "@/components/console/command-palette";
24+
import { ConsoleFooter } from "@/components/console/console-footer";
2425

2526
function ConsolePageTransition({ children }: { children: ReactNode }) {
2627
const pathname = usePathname();
@@ -74,6 +75,7 @@ function ConsoleContent({ children }: { children: ReactNode }) {
7475
<StepErrorBoundary fallbackMessage="Something went wrong rendering this page. The console sidebar is still available — try navigating to a different tool.">
7576
<ConsolePageTransition>{children}</ConsolePageTransition>
7677
</StepErrorBoundary>
78+
<ConsoleFooter />
7779
</div>
7880
</SidebarInset>
7981
<CommandPalette />
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { Github } from "lucide-react";
2+
3+
export function ConsoleFooter() {
4+
return (
5+
<footer className="mt-auto pt-6 pb-2 px-1 border-t border-zinc-200 dark:border-zinc-800">
6+
<div className="flex flex-col gap-2 text-xs text-zinc-500 dark:text-zinc-400 sm:flex-row sm:items-center sm:justify-between">
7+
<div className="flex-1 text-left">
8+
Crafted with <span aria-hidden>❤️</span> by Ava Labs DevRel team.
9+
</div>
10+
<div className="flex-1 flex justify-center">
11+
<a
12+
href="https://github.com/ava-labs/avalanche-sdk-typescript"
13+
target="_blank"
14+
rel="noopener noreferrer"
15+
className="inline-flex items-center gap-1.5 hover:text-zinc-900 dark:hover:text-zinc-100 transition-colors"
16+
>
17+
<span>powered by</span>
18+
<span className="font-mono">avalanche-sdk-typescript</span>
19+
<Github className="size-3.5" />
20+
</a>
21+
</div>
22+
<div className="flex-1 text-right">© 2026 Ava Labs, Inc.</div>
23+
</div>
24+
</footer>
25+
);
26+
}

components/explorer/utils/chainConverter.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { L1Chain } from "@/types/stats";
22
import { L1ListItem } from "@/components/toolbox/stores/l1ListStore";
3-
import { cb58ToHex } from "@/components/tools/common/utils/cb58";
3+
import { CB58ToHex } from "@avalanche-sdk/client/utils";
44

55
/**
66
* Converts an L1ListItem (from localStorage/console) to L1Chain format (for explorer)
@@ -16,7 +16,7 @@ export function convertL1ListItemToL1Chain(item: L1ListItem): L1Chain {
1616
chainId: String(item.evmChainId),
1717
chainName: item.name,
1818
chainLogoURI: item.logoUrl || "",
19-
blockchainId: cb58ToHex(item.id), // The L1ListItem.id IS the blockchain ID (cb58 format)
19+
blockchainId: CB58ToHex(item.id), // The L1ListItem.id IS the blockchain ID (cb58 format)
2020
subnetId: item.subnetId,
2121
slug,
2222
color: "#3B82F6", // Default blue color for console chains

components/toolbox/components/HostInput.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,12 @@ const validateDomainOrIP = (value: string): string | null => {
2727

2828
export const nipify = (domain: string): string => {
2929
if (isValidIPv4(domain)) {
30-
return `${domain}.sslip.io`;
30+
// nip.io instead of sslip.io: as of 2026-05-21 sslip.io's shared
31+
// Let's Encrypt zone is rate-limited (HTTP 429 "too many certificates"
32+
// — 250k cert cap per registered domain over 168h), so Caddy retries
33+
// forever on the docker-generated reverse proxy. nip.io resolves the
34+
// same `<ip>.<domain>` → ip but lives under a non-rate-limited zone.
35+
return `${domain}.nip.io`;
3136
}
3237
return domain;
3338
};

components/toolbox/components/SelectValidationID.tsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Input, type Suggestion } from './Input';
22
import { useMemo, useState, useEffect } from 'react';
3-
import { cb58ToHex, hexToCB58 } from '../console/utilities/format-converter/FormatConverter';
3+
import { CB58ToHex, hexToCB58 } from '@avalanche-sdk/client/utils';
44
import { L1ValidatorDetailsFull } from '@avalabs/avacloud-sdk/models/components';
55
import { formatAvaxBalance } from '../coreViem/utils/format';
66
import { useAvalancheSDKChainkit } from '../stores/useAvalancheSDKChainkit';
@@ -108,7 +108,7 @@ export default function SelectValidationID({
108108
mapping[v.validationId] = v.nodeId;
109109
// Also add hex format for easy lookup
110110
try {
111-
const hexId = '0x' + cb58ToHex(v.validationId);
111+
const hexId = CB58ToHex(v.validationId);
112112
mapping[hexId] = v.nodeId;
113113
} catch {
114114
// Skip if conversion fails
@@ -136,7 +136,7 @@ export default function SelectValidationID({
136136

137137
// Build multicall contracts array
138138
const contracts = validatorsWithId.map((v) => {
139-
const hexId = '0x' + cb58ToHex(v.validationId);
139+
const hexId = CB58ToHex(v.validationId);
140140
return {
141141
address: vmcAddr,
142142
abi: ValidatorManagerAbi.abi,
@@ -166,7 +166,7 @@ export default function SelectValidationID({
166166
// Store by both cb58 and hex IDs for easy lookup
167167
statusMap[v.validationId] = data.status;
168168
try {
169-
const hexId = '0x' + cb58ToHex(v.validationId);
169+
const hexId = CB58ToHex(v.validationId);
170170
statusMap[hexId] = data.status;
171171
} catch {
172172
// skip
@@ -187,7 +187,7 @@ export default function SelectValidationID({
187187
return (
188188
validationIdToNodeId[value] ||
189189
(value && value.startsWith('0x') && validationIdToNodeId[value]) ||
190-
(value && !value.startsWith('0x') && validationIdToNodeId['0x' + cb58ToHex(value)]) ||
190+
(value && !value.startsWith('0x') && validationIdToNodeId[CB58ToHex(value)]) ||
191191
''
192192
);
193193
}, [value, validationIdToNodeId]);
@@ -214,7 +214,7 @@ export default function SelectValidationID({
214214
// Add just one version based on the format prop
215215
if (format === 'hex') {
216216
try {
217-
const hexId = '0x' + cb58ToHex(validator.validationId);
217+
const hexId = CB58ToHex(validator.validationId);
218218
result.push({
219219
title: `${nodeId}${isSelected ? ' ✓' : ''}`,
220220
value: hexId,
@@ -245,10 +245,10 @@ export default function SelectValidationID({
245245
try {
246246
if (format === 'hex' && !newValue.startsWith('0x')) {
247247
// Convert CB58 to hex
248-
formattedValue = '0x' + cb58ToHex(newValue);
248+
formattedValue = CB58ToHex(newValue);
249249
} else if (format === 'cb58' && newValue.startsWith('0x')) {
250250
// Convert hex to CB58
251-
formattedValue = hexToCB58(newValue.slice(2));
251+
formattedValue = hexToCB58(newValue as `0x${string}`);
252252
}
253253
} catch {
254254
// If conversion fails, use the original value
@@ -260,7 +260,7 @@ export default function SelectValidationID({
260260

261261
// If not found directly, try the alternate format
262262
if (!nodeId) {
263-
const alternateFormat = format === 'hex' ? hexToCB58(formattedValue.slice(2)) : '0x' + cb58ToHex(formattedValue);
263+
const alternateFormat = format === 'hex' ? hexToCB58(formattedValue as `0x${string}`) : CB58ToHex(formattedValue);
264264
nodeId = validationIdToNodeId[alternateFormat] || '';
265265
}
266266

components/toolbox/components/ValidatorManagerDetails.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { useState, useEffect, useCallback } from 'react';
22
import { Copy, Check } from 'lucide-react';
33
import { formatEther } from 'viem';
44
import { getBlockchainInfo } from '../coreViem/utils/glacier';
5-
import { hexToCB58 } from '@/components/tools/common/utils/cb58';
5+
import { hexToCB58 } from '@avalanche-sdk/client/utils';
66
import type { StakingDetails } from '@/components/toolbox/contexts/ValidatorManagerContext';
77

88
interface ValidatorManagerDetailsProps {
@@ -86,7 +86,7 @@ export function ValidatorManagerDetails({
8686
setIsLoadingUptimeChainName(true);
8787
(async () => {
8888
try {
89-
const cb58Id = hexToCB58(uptimeBlockchainID);
89+
const cb58Id = hexToCB58(uptimeBlockchainID as `0x${string}`);
9090
const info = await getBlockchainInfo(cb58Id);
9191
if (!cancelled) setUptimeChainName(info.blockchainName);
9292
} catch {
@@ -187,7 +187,7 @@ export function ValidatorManagerDetails({
187187
badge={uptimeChainName || (isLoadingUptimeChainName ? 'loading...' : null)}
188188
value={(() => {
189189
try {
190-
return hexToCB58(staking.settings.uptimeBlockchainID);
190+
return hexToCB58(staking.settings.uptimeBlockchainID as `0x${string}`);
191191
} catch {
192192
return staking.settings.uptimeBlockchainID;
193193
}

components/toolbox/console/create-l1/generateSteps.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,18 @@ function createChainWithAnswers(answers: QuestionnaireAnswers): React.ComponentT
5858
}
5959

6060
/**
61-
* Wraps AvalancheGoDockerL1 with Create L1 flow defaults: force validator
62-
* node type (the user just created a validator set) and hide the node-type
63-
* selector so RPC/archival options don't clutter the flow.
61+
* Wraps AvalancheGoDockerL1 with Create L1 flow defaults. Previously this
62+
* pinned `forceNodeType: 'validator'`, which hid the node-type selector
63+
* AND the reverse-proxy step (gated on isRPC). For Fuji L1s especially,
64+
* users want the combined validator+RPC setup ("Both") so they get both
65+
* consensus and an HTTPS RPC endpoint out of the same node.
66+
*
67+
* Leaving forceNodeType unset lets the component pick its default:
68+
* - testnet → 'archival' = Validator + RPC (proxy step visible)
69+
* - mainnet → 'validator' (proxy hidden; user can flip via the selector)
6470
*/
6571
function dockerForL1Flow(): React.ComponentType {
6672
const props: AvalancheGoDockerL1Props = {
67-
forceNodeType: 'validator',
6873
showPrerequisites: true,
6974
};
7075
const Target = AvalancheGoDockerL1 as React.ComponentType<AvalancheGoDockerL1Props>;

components/toolbox/console/icm/test-connection/SendICMMessage.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { useToolboxStore, useViemChainStore, getToolboxStore } from '@/component
44
import { useState, useMemo } from 'react';
55
import { makePublicClientForChain } from '@/components/toolbox/hooks/usePublicClientForChain';
66
import ICMDemoABI from '@/contracts/example-contracts/compiled/ICMDemo.json';
7-
import { cb58ToHex } from '@/components/tools/common/utils/cb58';
7+
import { CB58ToHex } from '@avalanche-sdk/client/utils';
88
import SelectBlockchainId from '@/components/toolbox/components/SelectBlockchainId';
99
import { useL1ByChainId, useSelectedL1 } from '@/components/toolbox/stores/l1ListStore';
1010
import { useEffect } from 'react';
@@ -212,7 +212,7 @@ function SendICMMessage({ onSuccess }: BaseConsoleToolProps) {
212212
const destinationBlockchainIDHex = useMemo(() => {
213213
if (!targetL1?.id) return undefined;
214214
try {
215-
return cb58ToHex(targetL1.id);
215+
return CB58ToHex(targetL1.id);
216216
} catch (e) {
217217
console.error('Error decoding destination chain ID:', e);
218218
return undefined;

components/toolbox/console/ictt/bridge/hooks/useAddCollateral.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { useContractActions } from '@/components/toolbox/hooks/contracts';
66
import { makePublicClientForChain } from '@/components/toolbox/hooks/usePublicClientForChain';
77
import ExampleERC20 from '@/contracts/icm-contracts/compiled/ExampleERC20.json';
88
import ERC20TokenHomeAbi from '@/contracts/icm-contracts/compiled/ERC20TokenHome.json';
9-
import { cb58ToHex } from '@/components/tools/common/utils/cb58';
9+
import { CB58ToHex } from '@avalanche-sdk/client/utils';
1010
import { useIcttBridgeStore } from '@/components/toolbox/stores/iccttBridgeStore';
1111
import { useWalletStore } from '@/components/toolbox/stores/walletStore';
1212
import { useL1ByChainId } from '@/components/toolbox/stores/l1ListStore';
@@ -117,7 +117,7 @@ export function useAddCollateral({ bridge, remote }: UseAddCollateralOptions) {
117117
setPollAttempts(0);
118118
setLastError(null);
119119

120-
const blockchainIDHex = cb58ToHex(remote.l1Id) as Address;
120+
const blockchainIDHex = CB58ToHex(remote.l1Id) as Address;
121121
let attempt = 0;
122122
let timeoutHandle: ReturnType<typeof setTimeout> | null = null;
123123
let sawError = false;
@@ -245,7 +245,7 @@ export function useAddCollateral({ bridge, remote }: UseAddCollateralOptions) {
245245
status: 'pending',
246246
});
247247
try {
248-
const blockchainIDHex = cb58ToHex(remote.l1Id) as Address;
248+
const blockchainIDHex = CB58ToHex(remote.l1Id) as Address;
249249
const depositTx = (await tokenHome.addCollateral(blockchainIDHex, remote.address, amount)) as Address;
250250
updateActivity(activityId, { status: 'confirmed', txHash: depositTx, sublabel: 'Collateral added' });
251251
upsertRemote(bridge.id, { ...remote, collateralizedAt: Date.now() });

components/toolbox/console/ictt/bridge/hooks/useDeployTokenRemote.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import { useState } from 'react';
44
import ERC20TokenRemote from '@/contracts/icm-contracts/compiled/ERC20TokenRemote.json';
55
import NativeTokenRemote from '@/contracts/icm-contracts/compiled/NativeTokenRemote.json';
6-
import { cb58ToHex } from '@/components/tools/common/utils/cb58';
6+
import { CB58ToHex } from '@avalanche-sdk/client/utils';
77
import { useContractDeployer } from '@/components/toolbox/hooks/contracts';
88
import { useWalletStore } from '@/components/toolbox/stores/walletStore';
99
import { useL1ByChainId, useSelectedL1 } from '@/components/toolbox/stores/l1ListStore';
@@ -63,7 +63,7 @@ export function useDeployTokenRemote(remoteL1Id: string | null) {
6363
return null;
6464
}
6565
try {
66-
const tokenHomeBlockchainID = cb58ToHex(params.homeL1Id) as Address;
66+
const tokenHomeBlockchainID = CB58ToHex(params.homeL1Id) as Address;
6767
const decimals = params.decimals ?? params.homeDecimals;
6868

6969
const settings = {

0 commit comments

Comments
 (0)