This specification defines the SecurityBridge contract and cross-chain protocol for moving security tokens between Lux chains. Security tokens can be bridged between the C-Chain, a tenant L2, Zoo EVM, and any Lux L1 / L2 (per LP-018). The bridge enforces compliance on both source and destination chains. Cross-listing with tZero uses the same bridge architecture for off-chain ATS settlement.
Security tokens issued on one Lux chain need to trade on others:
Without a bridge, each chain would need its own token with its own compliance registry, and balances would diverge. The bridge maintains a single logical token supply across all chains.
Used when moving tokens from the chain where the token was originally deployed (the "home chain") to a remote chain.
Home Chain (C-Chain) Remote Chain (Tenant L2)
-------------------- -------------------------
1. User calls lock()
-> tokens transferred
to SecurityBridge contract
-> BridgeLock event emitted
2. Relayer verifies the lock
via Warp message
3. Relayer calls bridgeMint()
-> new tokens minted
to user on remote chain
-> BridgeMint event emitted
Used when moving tokens back to the home chain.
Remote Chain (Tenant L2) Home Chain (C-Chain)
--------------------------- --------------------
1. User calls burn()
-> tokens burned on
remote chain
-> BridgeBurn event emitted
2. Relayer verifies the burn
via Warp message
3. Relayer calls bridgeRelease()
-> locked tokens released
to user on home chain
-> BridgeRelease event emitted
At all times:
HomeChain.SecurityBridge.lockedBalance + sum(RemoteChain[i].SecurityToken.totalSupply)
== HomeChain.SecurityToken.totalSupply (at time of lock)
The bridge never creates or destroys net supply. Tokens are either locked on the home chain or minted on a remote chain. Never both.
The SecurityBridge contract (deployed per-token, per-chain):
contract SecurityBridge is AccessControl {
bytes32 public constant BRIDGE_ROLE = keccak256("BRIDGE_ROLE");
SecurityToken public immutable TOKEN;
mapping(bytes32 => bool) public processedNonces;
// Source chain operations (user-callable)
function lock(uint256 amount, uint256 destinationChainId, address destinationAddress) external;
function burn(uint256 amount, uint256 destinationChainId) external;
// Destination chain operations (bridge operator only)
function bridgeMint(address recipient, uint256 amount, uint256 sourceChainId, bytes32 nonce) external;
function bridgeRelease(address recipient, uint256 amount, uint256 sourceChainId, bytes32 nonce) external;
}
Every bridge operation generates a nonce:
bytes32 nonce = keccak256(abi.encodePacked(sender, amount, destinationChainId, block.timestamp, block.number));
The destination chain tracks processedNonces[nonce]. A nonce can only be processed once. This prevents replay attacks.
The BRIDGE_ROLE authorizes bridgeMint() and bridgeRelease(). This role must be held by:
A single EOA must never hold BRIDGE_ROLE in production.
Lux Warp Messaging (LP-6022) provides native cross-chain (L1 / L2) communication. The bridge uses Warp for lock/mint and burn/release verification.
Source Chain Lux P-Chain Destination Chain
------------ ----------- -----------------
1. SecurityBridge.lock()
emits BridgeLock event
2. L1 / L2 validators sign
Warp message containing:
- sourceChainId
- destinationChainId
- sender
- recipient
- amount
- nonce
3. Warp message aggregated
(BLS signature threshold)
4. Relayer submits
Warp message to
destination chain
5. WarpMessenger precompile
verifies BLS signature
6. SecurityBridge.bridgeMint()
called with verified params
struct SecurityBridgeMessage {
bytes32 messageType; // keccak256("BRIDGE_LOCK") or keccak256("BRIDGE_BURN")
uint256 sourceChainId;
uint256 destinationChainId;
address sender;
address recipient;
uint256 amount;
bytes32 nonce;
address tokenAddress; // SecurityToken on source chain
}
Warp messages require a configurable BLS signature threshold from the source chain's validators. For security tokens:
Lux C-Chain (Home)
SecurityToken deployed here
SecurityBridge (lock/release)
|
Warp Messaging
|
+----------+----------+
| |
Tenant L2 Zoo EVM
SecurityToken SecurityToken
(bridge-minted) (bridge-minted)
SecurityBridge SecurityBridge
(burn/mint) (burn/mint)
ComplianceHook ComplianceHook
(DEX trading) (marketplace)
C-Chain -> Tenant L2:
1. User locks 1000 ACME on C-Chain SecurityBridge
2. Warp message signed by C-Chain validators
3. Tenant L2 relayer verifies and calls bridgeMint(user, 1000, cChainId, nonce)
4. User now has 1000 ACME on Tenant L2, tradeable on DEX with ComplianceHook
Tenant L2 -> Zoo EVM:
1. User burns 500 ACME on Tenant L2 SecurityBridge (destination: Zoo EVM)
2. NOT a release back to C-Chain -- this is a hop. Implementation:
3. This two-hop pattern ensures the C-Chain invariant holds
Direct chain-to-chain bridging (L1 ↔ L2 without C-Chain hop) is possible when both chains trust each other's validator set directly. This requires explicit opt-in via bridge configuration.
Compliance is enforced at both ends:
Source chain (lock/burn):
lock() calls TOKEN.safeTransferFrom(), which triggers SecurityToken._update(), which calls ComplianceRegistry.canTransfer(). If the sender is not compliant, the lock reverts.Destination chain (mint/release):
bridgeMint() calls TOKEN.mint(), which bypasses compliance (minting is issuer-controlled). However, the recipient must be whitelisted on the destination chain's ComplianceRegistry to subsequently trade.Compliance registry synchronization:
ComplianceRegistrylux/compliance) synchronizes whitelist status across chainstZero is an off-chain ATS. The "bridge" to tZero is not a blockchain bridge -- it is an API integration that uses the same lock/mint mental model.
Lux C-Chain tZero ATS
----------- ---------
SecurityToken tZero Security (off-chain)
SecurityBridge.lock() tZero credits investor account
| |
+--- REST/Webhook API ----------+
| |
SecurityBridge.bridgeRelease() tZero debits investor account
Lux -> tZero (investor wants to sell on tZero):
1. Investor locks tokens on Lux SecurityBridge (destination: tZero, identified by a reserved chainId)
2. Bridge event triggers webhook to tZero settlement API
3. tZero credits the investor's account with the corresponding security position
4. Investor can now sell on tZero ATS
tZero -> Lux (investor wants tokens on-chain):
1. Investor initiates withdrawal on tZero
2. tZero settlement API sends webhook to Lux bridge service
3. Bridge service (authorized with BRIDGE_ROLE via MPC) calls SecurityBridge.bridgeRelease()
4. Tokens released to investor's on-chain address
tZero uses a reserved chain ID for bridge addressing:
tZero Chain ID: 0xTZERO (placeholder -- actual value assigned at integration time)
This is not a blockchain chain ID. It is a routing identifier that the bridge service uses to determine that the destination is tZero rather than another Lux chain.
All tZero webhooks use:
X-Signature: HMAC-SHA256(secret, timestamp + "." + body)
X-Timestamp: 1711100400
X-Idempotency-Key: uuid-v4
The bridge operator for production deployments is an M-Chain MPC multisig (per LP-134; supersedes LP-5013) hosting MPC ceremonies for bridge custody of external wallets (BTC, ETH, SOL, etc.):
Warp Message (BLS signed)
|
v
+-------------------+
| Bridge Relayer |
| (Go service) |
| |
| 1. Verify Warp msg|
| 2. Decode params |
| 3. Check compliance|
| 4. Submit to MPC |
+-------------------+
|
v
+-------------------+
| M-Chain MPC |
| (threshold sign) |
| |
| 5. Sign bridgeMint |
| transaction |
+-------------------+
|
v
+-------------------+
| Destination Chain |
| SecurityBridge |
| |
| 6. bridgeMint() |
+-------------------+
The relayer is a stateless Go service that:
1. Watches for Warp messages on source chains
2. Verifies BLS signature threshold
3. Checks compliance on destination chain (pre-flight)
4. Submits the mint/release request to the MPC signing cluster
5. Broadcasts the signed transaction to the destination chain
Both the SecurityToken and SecurityBridge can be paused independently:
SecurityToken.pause() halts all transfers including bridge operationsBRIDGE_ROLE from the operatorIf tokens are locked on the home chain but the destination chain fails to mint:
1. The lock event and nonce are recorded on-chain
2. After a timeout (configurable, default 24 hours), admin can call a recovery function to release locked tokens back to the sender
3. Recovery requires DEFAULT_ADMIN_ROLE (multisig)
If a destination chain halts:
1. Lock operations on the home chain continue to work (tokens accumulate in the bridge)
2. No mints occur on the halted chain
3. When the chain resumes, the relayer processes the backlog in order
4. Nonce deduplication prevents double-minting
lock() | Home chain | ~65,000 (transfer + event) |burn() | Remote chain | ~45,000 (burn + event) |bridgeMint() | Remote chain | ~55,000 (mint + nonce check + event) |bridgeRelease() | Home chain | ~50,000 (transfer + nonce check + event) |Compliance checks in lock() add ~8,000-15,000 gas (via SecurityToken._update).
1. Nonce replay: Each nonce can only be processed once. The nonce includes block.timestamp and block.number, making it unique per-block. Two locks in the same block from the same sender for the same amount produce different nonces due to different call positions.
2. Warp signature verification: The destination chain verifies the BLS aggregate signature against the source chain's registered validator set on the P-Chain. A compromised minority of validators cannot produce a valid Warp message (67% threshold minimum).
3. MPC key compromise: If the MPC signing threshold is compromised, the attacker can mint tokens on destination chains. Mitigation: per-asset key groups, HSM backing, quarterly rotation, real-time monitoring of bridge events.
4. Compliance desynchronization: If chain A whitelists a user and chain B has not synced yet, the user can lock on A but cannot trade on B. This is a liveness issue, not a safety issue -- compliance sync latency is the bottleneck. The compliance service targets < 30 second sync across chains.
5. Double-spend via reorg: If the source chain reorgs after a lock is processed, the destination chain has already minted. Mitigation: wait for finality before processing (Lux finality is 1ms, so reorgs are practically impossible under normal conditions).
6. Token supply audit: The bridge invariant (locked + remote supply = home supply) must be auditable. Both the home chain bridge balance and remote chain total supply are public on-chain state. An automated monitor verifies the invariant every block.
github.com/luxfi/standard/contracts/securities/bridge/SecurityBridge.sol |lp-6022-warp-messaging-20-native-interchain-transfers.md |LP-134-lux-chain-topology.md |lp-6332-teleport-bridge-architecture-unified-cross-chain-protocol.md |LP-001-digital-securities.md |Copyright (c) 2026 Lux Partners Limited. All rights reserved.
Licensed under the MIT License.