feat: OMNL Bank online production — 128 chains, Central Bank UI, settlement stack
Some checks failed
CI/CD Pipeline / Solidity Contracts (push) Failing after 1m22s
CI/CD Pipeline / Security Scanning (push) Successful in 2m30s
CI/CD Pipeline / Lint and Format (push) Failing after 44s
CI/CD Pipeline / Terraform Validation (push) Failing after 27s
CI/CD Pipeline / Kubernetes Validation (push) Successful in 31s
Deploy ChainID 138 / Deploy ChainID 138 (push) Failing after 56s
HYBX OMNL TypeScript & anchor / token-aggregation build + reconcile artifact (push) Failing after 29s
Validation / validate-genesis (push) Successful in 34s
Validation / validate-terraform (push) Failing after 39s
Validation / validate-kubernetes (push) Failing after 14s
Validation / validate-smart-contracts (push) Failing after 20s
Validation / validate-security (push) Failing after 1m19s
Validation / validate-documentation (push) Failing after 27s
Verify Deployment / Verify Deployment (push) Failing after 1m13s

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-28 08:44:42 -07:00
parent 2b1a3ba6af
commit 5dd67e2b1d
113 changed files with 13223 additions and 98 deletions

View File

@@ -25,7 +25,6 @@ import CopyButton from '../ui/CopyButton';
import ConfirmationModal from '../ui/ConfirmationModal';
import Tooltip from '../ui/Tooltip';
import LoadingSkeleton from '../ui/LoadingSkeleton';
import ChainIcon from '../ui/ChainIcon';
import TokenIcon from '../ui/TokenIcon';
interface BridgeButtonsProps {
@@ -384,38 +383,28 @@ function BridgeButtonsConnected({
/>
)}
<div className="relative">
<div className="mb-6">
<div className="flex items-center justify-between mb-2">
<h2 className="text-[20px] font-semibold text-white flex items-center gap-2">
Bridge to
{destination && (
<>
<ChainIcon chainId={destination.chainId} name={destination.name} size={24} />
<span>{destination.name}</span>
</>
)}
{!destination && <span>Ethereum Mainnet</span>}
</h2>
<Tooltip content="Refresh all balances and allowances">
<button
onClick={handleRefreshBalances}
disabled={!address}
className="p-2 text-teal-400 hover:text-teal-300 hover:bg-teal-500/20 rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed border border-white/20"
aria-label="Refresh balances"
>
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
</svg>
</button>
</Tooltip>
</div>
<p className="text-[#A0A0A0] text-sm mt-1">
Wrap ETH, approve tokens, and bridge WETH9 via CCIP
<div className="mb-6 flex items-center justify-between gap-3">
<p className="ui-muted text-sm">
Wrap ETH, approve tokens, and bridge WETH9 via CCIP to{' '}
{destination?.name ?? 'Ethereum Mainnet'}
</p>
<Tooltip content="Refresh all balances and allowances">
<button
type="button"
onClick={handleRefreshBalances}
disabled={!address}
className="ui-btn-icon disabled:opacity-50 disabled:cursor-not-allowed shrink-0"
aria-label="Refresh balances"
>
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
</svg>
</button>
</Tooltip>
</div>
<div className="mb-8">
<label className="flex items-center gap-2 text-[13px] font-medium mb-2 text-[#A0A0A0]">
<label className="ui-label">
<TokenIcon symbol="ETH" size={20} />
<span>Amount (ETH)</span>
<Tooltip content="Enter the amount of ETH you want to bridge. This will be wrapped to WETH9 first.">
@@ -429,10 +418,8 @@ function BridgeButtonsConnected({
min="0"
value={amount}
onChange={(e) => setAmount(e.target.value)}
className={`w-full min-h-[48px] pl-4 pr-24 py-3 border rounded-xl focus:outline-none focus:ring-2 focus:ring-teal-500 focus:ring-offset-2 focus:ring-offset-[#252830] transition-all text-lg bg-[#1a1d24] text-white placeholder:text-[#A0A0A0] hover:border-white/30 ${
amountError
? 'border-red-500 focus:border-red-500'
: 'border-white/20 focus:border-teal-500'
className={`ui-input pl-4 pr-24 text-lg ${
amountError ? '!border-red-500 focus:!border-red-500' : ''
}`}
placeholder="0.0"
aria-invalid={!!amountError}
@@ -444,7 +431,7 @@ function BridgeButtonsConnected({
setAmount(ethBalance.displayValue);
setAmountError('');
}}
className="absolute right-3 top-1/2 -translate-y-1/2 px-4 py-2 min-h-[36px] text-sm font-medium bg-teal-600 text-white rounded-lg hover:bg-teal-500 transition-colors"
className="ui-btn-primary absolute right-2 top-1/2 -translate-y-1/2 !py-2 !min-h-0 text-sm"
>
MAX
</button>
@@ -461,7 +448,7 @@ function BridgeButtonsConnected({
</div>
<div className="mb-8">
<label htmlFor="bridge-recipient-address" className="block text-[13px] font-medium mb-2 text-[#A0A0A0]">
<label htmlFor="bridge-recipient-address" className="ui-label">
Recipient Address
<Tooltip content="The Ethereum address that will receive the bridged tokens on the destination chain.">
<span className="ml-2 text-white/60 cursor-help text-xs"></span>
@@ -474,10 +461,8 @@ function BridgeButtonsConnected({
type="text"
value={recipient}
onChange={(e) => setRecipient(e.target.value)}
className={`w-full min-h-[48px] p-4 border rounded-xl focus:outline-none focus:ring-2 focus:ring-teal-500 focus:ring-offset-2 focus:ring-offset-[#252830] transition-all font-mono text-base bg-[#1a1d24] text-white placeholder:text-[#A0A0A0] hover:border-white/30 ${
recipientError
? 'border-red-500 focus:border-red-500'
: 'border-white/20 focus:border-teal-500'
className={`ui-input font-mono pr-36 ${
recipientError ? '!border-red-500 focus:!border-red-500' : ''
}`}
placeholder="0x..."
aria-invalid={!!recipientError}
@@ -490,7 +475,7 @@ function BridgeButtonsConnected({
setRecipient(address);
setRecipientError('');
}}
className="px-4 py-2 text-sm font-medium bg-[#252830] text-white rounded-lg hover:bg-white/10 transition-colors border border-white/20"
className="ui-btn-secondary !py-2 text-sm"
>
Use my address
</button>
@@ -510,9 +495,9 @@ function BridgeButtonsConnected({
)}
</div>
<div className="mb-8 p-6 bg-[#1a1d24] rounded-xl border border-white/10">
<div className="mb-8 p-6 ui-inset rounded-xl">
<div className="flex items-center justify-between mb-4">
<h3 className="text-[20px] font-semibold text-[#A0A0A0]">Balances & Fees</h3>
<h3 className="text-lg font-semibold ui-muted">Balances & Fees</h3>
{address && (
<CopyButton text={address} className="text-xs">
<span className="text-xs">Copy Address</span>
@@ -520,49 +505,49 @@ function BridgeButtonsConnected({
)}
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="flex justify-between items-center p-4 bg-[#252830] rounded-lg border border-white/10 font-mono text-sm">
<span className="font-medium text-[#A0A0A0] flex items-center gap-2">
<div className="ui-stat-row">
<span className="ui-muted font-medium flex items-center gap-2">
<TokenIcon symbol="ETH" size={20} />
ETH Balance:
</span>
<span className="text-white font-medium">
{ethBalance ? ethBalance.displayValue : <LoadingSkeleton />} <span className="text-[#A0A0A0]">ETH</span>
<span className="font-medium">
{ethBalance ? ethBalance.displayValue : <LoadingSkeleton />} <span className="ui-muted">ETH</span>
</span>
</div>
<div className="flex justify-between items-center p-4 bg-[#252830] rounded-lg border border-white/10 font-mono text-sm">
<span className="font-medium text-[#A0A0A0] flex items-center gap-2">
<div className="ui-stat-row">
<span className="ui-muted font-medium flex items-center gap-2">
<TokenIcon symbol="WETH9" size={20} />
WETH9 Balance:
</span>
<span className="text-white font-medium">
<span className="font-medium">
{address && weth9Balance !== undefined
? `${ethers.utils.formatEther(weth9Balance.toString())}`
: address
? <LoadingSkeleton />
: '0'} <span className="text-[#A0A0A0]">WETH9</span>
: '0'} <span className="ui-muted">WETH9</span>
</span>
</div>
<div className="flex justify-between items-center p-4 bg-[#252830] rounded-lg border border-white/10 font-mono text-sm">
<span className="font-medium text-[#A0A0A0] flex items-center gap-2">
<div className="ui-stat-row">
<span className="ui-muted font-medium flex items-center gap-2">
<TokenIcon symbol="LINK" size={20} />
LINK Balance:
</span>
<span className="text-white font-medium">
<span className="font-medium">
{address && linkBalance !== undefined
? `${ethers.utils.formatEther(linkBalance.toString())}`
: address
? <LoadingSkeleton />
: '0'} <span className="text-[#A0A0A0]">LINK</span>
: '0'} <span className="ui-muted">LINK</span>
</span>
</div>
{ccipFee != null && ccipFee.gt(0) && (
<div className="flex justify-between items-center p-4 bg-[#252830] rounded-lg border border-teal-500/30 font-mono text-sm">
<span className="font-medium text-[#A0A0A0] flex items-center gap-2">
<div className="ui-stat-row ui-stat-row--highlight">
<span className="ui-muted font-medium flex items-center gap-2">
<TokenIcon symbol="LINK" size={20} />
CCIP Fee:
</span>
<span className="text-white font-medium">
{ethers.utils.formatEther(ccipFee)} <span className="text-[#A0A0A0]">LINK</span>
<span className="font-medium">
{ethers.utils.formatEther(ccipFee)} <span className="ui-muted">LINK</span>
</span>
</div>
)}
@@ -573,7 +558,7 @@ function BridgeButtonsConnected({
<button
onClick={() => setShowWrapModal(true)}
disabled={!needsWrapping || !address || isWrapping}
className="px-6 py-4 bg-[#252830] text-white rounded-xl font-semibold hover:bg-white/10 disabled:bg-gray-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors border border-white/20"
className="ui-btn-secondary w-full"
aria-label="Wrap ETH to WETH9"
>
{isWrapping ? (
@@ -592,7 +577,7 @@ function BridgeButtonsConnected({
<button
onClick={() => setShowApproveModal(true)}
disabled={!needsApproval || !address || isApproving}
className="px-6 py-4 bg-[#252830] text-white rounded-xl font-semibold hover:bg-white/10 disabled:bg-gray-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors border border-white/20"
className="ui-btn-secondary w-full"
aria-label="Approve tokens for bridge"
>
{isApproving ? (
@@ -612,7 +597,7 @@ function BridgeButtonsConnected({
<button
onClick={() => setShowBridgeModal(true)}
disabled={!canBridge || !address || isBridging}
className="w-full min-h-[56px] py-4 text-lg font-semibold bg-teal-600 text-white rounded-xl hover:bg-teal-500 disabled:bg-[#252830] disabled:opacity-50 disabled:cursor-not-allowed transition-colors focus:outline-none focus:ring-2 focus:ring-teal-500 focus:ring-offset-2 focus:ring-offset-[#252830] shadow-lg"
className="ui-btn-primary w-full min-h-[56px] text-lg"
aria-label="Start bridge transfer"
>
{isBridging ? (
@@ -683,26 +668,11 @@ export default function BridgeButtons(props: BridgeButtonsProps) {
const destination = CCIP_DESTINATIONS.find((d) => d.selector === destinationChainSelector);
return (
<div className="w-full">
<div className="mb-6">
<h2 className="text-[20px] font-semibold text-white flex items-center gap-2">
Bridge to
{destination && (
<>
<ChainIcon chainId={destination.chainId} name={destination.name} size={24} />
<span>{destination.name}</span>
</>
)}
{!destination && <span>Ethereum Mainnet</span>}
</h2>
<p className="text-[#A0A0A0] text-sm mt-1">
Wrap ETH, approve tokens, and bridge WETH9 via CCIP
</p>
</div>
<div className="mt-8 p-5 bg-amber-500/10 border border-amber-500/30 rounded-xl text-sm text-white font-medium flex items-center gap-4">
<svg className="h-6 w-6 text-yellow-300 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<div className="ui-alert">
<svg className="h-5 w-5 shrink-0 ui-accent-text" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
</svg>
<span>Please connect your wallet to continue</span>
<span>Connect your wallet to bridge to {destination?.name ?? 'Ethereum Mainnet'}</span>
</div>
</div>
);

View File

@@ -0,0 +1,60 @@
import { Link, Outlet, useLocation } from 'react-router-dom';
import { useRef } from 'react';
import WalletConnect from '../wallet/WalletConnect';
import WalletDisconnectNotice from '../wallet/WalletDisconnectNotice';
const PRODUCTS = [
{ path: '/central-bank', label: 'Central Bank', short: 'CB' },
{ path: '/office-24', label: 'Office 24', short: 'O24' },
{ path: '/trade', label: 'DBIS Trade', short: 'Trade' },
] as const;
export default function OmnlProductLayout() {
const location = useLocation();
const userInitiatedDisconnectRef = useRef(false);
const isActive = (path: string) => location.pathname.startsWith(path);
return (
<div className="omnl-app min-h-screen flex flex-col bg-[#0b0e11]">
<WalletDisconnectNotice userInitiatedDisconnectRef={userInitiatedDisconnectRef} />
<header className="omnl-app-header sticky top-0 z-50 border-b border-[#2b3139] bg-[#181a20]">
<div className="max-w-[1600px] mx-auto px-4 h-14 flex items-center gap-4">
<Link to="/central-bank" className="flex items-center gap-2 shrink-0">
<span className="w-8 h-8 rounded bg-[#f0b90b] text-[#181a20] font-bold flex items-center justify-center text-sm">
O
</span>
<span className="font-semibold text-[#eaecef] hidden sm:inline">OMNL</span>
</Link>
<nav className="flex items-center gap-1 flex-1" aria-label="OMNL products">
{PRODUCTS.map(({ path, label }) => (
<Link
key={path}
to={path}
className={`px-4 py-2 rounded text-sm font-medium transition-colors ${
isActive(path)
? 'bg-[#2b3139] text-[#f0b90b]'
: 'text-[#848e9c] hover:text-[#eaecef] hover:bg-[#1e2329]'
}`}
>
{label}
</Link>
))}
</nav>
<Link
to="/"
className="text-xs text-[#848e9c] hover:text-[#f0b90b] hidden md:inline shrink-0"
>
Bridge
</Link>
<WalletConnect onBeforeDisconnect={() => { userInitiatedDisconnectRef.current = true; }} />
</div>
</header>
<main className="flex-1">
<Outlet />
</main>
</div>
);
}