Skip to content
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
4b6cb78
feat: add multicollateral sdk and cli support
nambrot Feb 28, 2026
7c749f8
feat: port multicollateral fee and transfer flows to sdk and cli
nambrot Feb 28, 2026
da848b0
feat: add pending-transfer and inventory metrics to warp monitor
nambrot Feb 28, 2026
53d9a5c
fix: align sdk multicollateral imports and defer routing-fee mutations
nambrot Feb 28, 2026
2a12030
refactor(cli): dedupe multicollateral prompt switch case
nambrot Feb 28, 2026
82b8dde
feat(cli): validate warp combine inputs and warn on unenroll
nambrot Feb 28, 2026
afc9533
feat(warp-monitor): scope projected deficit to collateralized routes
nambrot Feb 28, 2026
b934636
fix(ci): include multicollateral deps in node-service image
nambrot Feb 28, 2026
337949d
fix(ci): ignore multicollateral in core eslint
nambrot Mar 1, 2026
7bb08df
style: format warp monitor explorer
nambrot Mar 1, 2026
a1b349e
Apply CodeRabbit fixes for multicollateral + monitor
nambrot Mar 1, 2026
66b2a6e
Address CodeRabbit transfer and quote robustness feedback
nambrot Mar 2, 2026
f918524
fix(lockfile): restore multicollateral devDependencies section
nambrot Mar 2, 2026
5b2a9cd
Fix multicollateral routing + fee quoting edge cases
nambrot Mar 2, 2026
f3ee80e
fix: address multicollateral PR-B review issues
nambrot Mar 2, 2026
37ca736
fix: unblock CI by tightening monitor test token mocks
nambrot Mar 2, 2026
70ec299
test: always restore multicollateral reader stubs
nambrot Mar 2, 2026
f0be3b5
fix(cli): format ratio scales in combine incompatibility logs
nambrot Mar 2, 2026
23ddc77
fix multicollateral adapter wiring and monitor amount conversion
nambrot Mar 3, 2026
0edf9dd
chore(multicollateral): align tsconfig with main
nambrot Mar 3, 2026
4ee1934
fix: address PR review feedback from paulbalaji
nambrot Mar 3, 2026
406c680
rebalancer-sim: package scenarios and support SCENARIOS_DIR override
nambrot Mar 3, 2026
03e2cac
rebalancer-sim: add shared result exporter API
nambrot Mar 3, 2026
6532996
fix: add path traversal guards and temp dir cleanup in rebalancer-sim
nambrot Mar 3, 2026
70e12c8
fix: lowercase router before isAddressEvm check in toCanonicalRouterId
nambrot Mar 3, 2026
a7ff614
chore: add changesets for multicollateral SDK/CLI/monitor and rebalan…
nambrot Mar 4, 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
7 changes: 5 additions & 2 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion solidity/eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ export default [
'**/dist/**/*',
'**/lib/**/*',
'**/typechain/**/*',
'**/dependencies/**/*',
'**/multicollateral/**/*',
'**/dependencies/**/*',
'.solcover.js',
'generate-artifact-exports.mjs',
],
Expand Down
3 changes: 2 additions & 1 deletion typescript/Dockerfile.node-service
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ COPY typescript/tron-sdk/package.json ./typescript/tron-sdk/
COPY typescript/tsconfig/package.json ./typescript/tsconfig/
COPY typescript/eslint-config/package.json ./typescript/eslint-config/
COPY solidity/package.json ./solidity/
COPY solidity/multicollateral/package.json ./solidity/multicollateral/
COPY solhint-plugin/package.json ./solhint-plugin/
COPY starknet/package.json ./starknet/

Expand Down Expand Up @@ -138,4 +139,4 @@ ENV SERVER_PORT=${SERVICE_PORT}
EXPOSE 9090

# Run the service from the bundle
CMD ["node", "bundle/index.js"]
CMD ["node", "bundle/index.js"]
78 changes: 73 additions & 5 deletions typescript/cli/src/commands/warp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ import {
type CommandModuleWithWarpDeployContext,
type CommandModuleWithWriteContext,
} from '../context/types.js';
import { runWarpRouteApply, runWarpRouteDeploy } from '../deploy/warp.js';
import {
runWarpRouteApply,
runWarpRouteCombine,
runWarpRouteDeploy,
} from '../deploy/warp.js';
import { runWarpRouteFees } from '../fees/warp.js';
import { runForkCommand } from '../fork/fork.js';
import {
Expand Down Expand Up @@ -77,6 +81,7 @@ export const warpCommand: CommandModule = {
yargs
.command(apply)
.command(check)
.command(combine)
.command(deploy)
.command(fork)
.command(getFees)
Expand Down Expand Up @@ -182,6 +187,47 @@ export const deploy: CommandModuleWithWarpDeployContext<SelectWarpRouteBuilder>
},
};

const combine: CommandModuleWithWriteContext<{
routes: string;
'output-warp-route-id': string;
}> = {
command: 'combine',
describe:
'Combine multiple MultiCollateral warp routes, updating deploy configs with cross-route enrolledRouters',
builder: {
routes: {
type: 'string',
description:
'Comma-separated warp route IDs to combine (e.g., "USDC/eth-arb,USDT/eth-arb")',
demandOption: true,
},
'output-warp-route-id': {
type: 'string',
description:
'Warp route ID for the merged WarpCoreConfig (e.g., MULTI/stableswap)',
demandOption: true,
},
},
handler: async ({ context, routes, 'output-warp-route-id': outputId }) => {
logCommandHeader('Hyperlane Warp Combine');

const routeIds = routes
.split(',')
.map((r) => r.trim())
.filter((r) => r.length > 0);
assert(
routeIds.length >= 2,
'At least 2 route IDs are required to combine',
);
await runWarpRouteCombine({
context,
routeIds,
outputWarpRouteId: outputId,
});
process.exit(0);
},
};

export const init: CommandModuleWithContext<{
advanced: boolean;
out: string;
Expand Down Expand Up @@ -296,6 +342,8 @@ const send: CommandModuleWithWriteContext<
recipient?: string;
chains?: string[];
skipValidation?: boolean;
sourceToken?: string;
destinationToken?: string;
}
> = {
command: 'send',
Expand All @@ -322,6 +370,15 @@ const send: CommandModuleWithWriteContext<
description: 'Skip transfer validation (e.g., collateral checks)',
default: false,
},
'source-token': {
type: 'string',
description: 'Source token router address (for MultiCollateral routes)',
},
'destination-token': {
type: 'string',
description:
'Destination token router address (for MultiCollateral cross-stablecoin transfers)',
},
},
handler: async ({
context,
Expand All @@ -337,6 +394,8 @@ const send: CommandModuleWithWriteContext<
roundTrip,
chains: chainsArg,
skipValidation,
sourceToken,
destinationToken,
}) => {
const warpCoreConfig = await getWarpCoreConfigOrExit({
symbol,
Expand Down Expand Up @@ -366,10 +425,17 @@ const send: CommandModuleWithWriteContext<
`Chain(s) ${[...unsupportedChains].join(', ')} are not part of the warp route.`,
);

chains =
chains.length === 0
? [...supportedChains]
: [...intersection(new Set(chains), supportedChains)];
// When origin & destination are explicitly provided, preserve duplicates
// for same-chain transfers (e.g., origin=anvil2, destination=anvil2).
// Only deduplicate when using --chains or auto-selecting from config.
if (origin && destination) {
chains = [origin, destination];
} else {
chains =
chains.length === 0
? [...supportedChains]
: [...intersection(new Set(chains), supportedChains)];
}

if (roundTrip) {
// Appends the reverse of the array, excluding the 1st (e.g. [1,2,3] becomes [1,2,3,2,1])
Expand All @@ -388,6 +454,8 @@ const send: CommandModuleWithWriteContext<
skipWaitForDelivery: quick,
selfRelay: relay,
skipValidation,
sourceToken,
destinationToken,
});
logGreen(
`✅ Successfully sent messages for chains: ${chains.join(' ➡️ ')}`,
Expand Down
3 changes: 3 additions & 0 deletions typescript/cli/src/config/warp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ const TYPE_DESCRIPTIONS: Record<DeployableTokenType, string> = {
[TokenType.syntheticUri]: '',
[TokenType.collateralUri]: '',
[TokenType.nativeScaled]: '',
[TokenType.multiCollateral]:
'A collateral token that can route to multiple routers across chains',
};

const TYPE_CHOICES = Object.values(TokenType)
Expand Down Expand Up @@ -248,6 +250,7 @@ export async function createWarpRouteDeployConfig({
case TokenType.XERC20:
case TokenType.XERC20Lockbox:
case TokenType.collateralFiat:
case TokenType.multiCollateral:
result[chain] = {
type,
owner,
Expand Down
Loading
Loading