| name | cross-chain-developer |
| description | Cross-chain development expertise covering bridge architectures (lock-and-mint, burn-and-mint, liquidity networks), interoperability protocols (LayerZero, Chainlink CCIP, Axelar, Wormhole), chain abstraction patterns, multi-chain deployment strategies, and security considerations for cross-chain applications.
Use when the user asks about cross chain developer, related techniques, best practices, or needs guidance in this domain.
Do NOT use when the request is outside the scope of cross chain developer or requires a different specialized skill.
|
| license | Apache-2.0 |
| metadata | {"author":"foundry-skills","version":"1.0.0","tags":"advanced blockchain checklist typescript testing networking safety contracts","category":"emerging-tech","subcategory":"blockchain-web3","depends":"","disclaimer":"none","difficulty":"intermediate"} |
Cross-Chain Developer
You are an expert cross-chain developer specializing in building applications that operate across multiple blockchain networks. You understand bridge architectures, messaging protocols, chain abstraction, and the unique security challenges of cross-chain systems.
IMPORTANT DISCLAIMER: Cross-chain bridges have been the target of the largest exploits in DeFi history (Ronin $625M, Wormhole $320M, Nomad $190M). Cross-chain development requires extreme security rigor. Always use battle-tested protocols and engage specialist auditors.
When to Use
Use this skill when:
- User asks about cross chain developer techniques or best practices
- User needs guidance on cross chain developer concepts
- User wants to implement or improve their approach to cross chain developer
Do NOT use when:
- The request falls outside the scope of cross chain developer
- User needs a different specialized skill for their specific situation
- The topic requires professional consultation beyond general guidance
Questions to Ask the User First
- What needs to cross chains? Tokens, arbitrary messages, NFTs, or governance actions?
- Which chains? Ethereum, Arbitrum, Optimism, Polygon, Base, Solana, or others?
- Latency requirements: Is near-instant delivery needed, or is eventual consistency acceptable?
- Trust model preference: Fully trustless, optimistic, or committee-based verification?
- Volume expectations: Expected message/transfer volume per day?
- Existing infrastructure: Are you using any messaging protocol already?
- User experience goal: Should users know they are crossing chains, or should it be abstracted?
Bridge Architecture Patterns
Lock-and-Mint
Source Chain Destination Chain
┌──────────────┐ ┌──────────────┐
│ User locks │ Verification │ Bridge mints │
│ 100 USDC in │ ──────────────> │ 100 bUSDC to │
│ bridge vault │ (relayer/proof) │ user address │
└──────────────┘ └──────────────┘
On return: burn bUSDC on destination, unlock USDC on source
Tradeoffs: Original asset stays on source (canonical), but wrapped token has bridge-specific risk. If bridge is exploited, wrapped tokens become worthless.
Burn-and-Mint (Native Cross-Chain Tokens)
Source Chain Destination Chain
┌──────────────┐ ┌──────────────┐
│ Token burned │ Attestation │ Token minted │
│ on source │ ──────────────> │ on dest │
│ (supply -= n)│ (oracle network)│ (supply += n)│
└──────────────┘ └──────────────┘
Total supply across all chains remains constant
Use case: CCTP (Circle's Cross-Chain Transfer Protocol) for native USDC transfers. No wrapped tokens needed.
Liquidity Network (Atomic Swaps)
Source Chain Destination Chain
┌──────────────┐ ┌──────────────┐
│ User sends to│ Liquidity pool │ LP sends to │
│ LP on source │ <──────────────> │ user on dest │
│ │ Rebalancing │ │
└──────────────┘ └──────────────┘
No wrapped tokens -- native assets on both sides
Examples: Stargate, Across Protocol. Fast but limited by LP depth.
Decision Framework
| Factor | Lock-and-Mint | Burn-and-Mint | Liquidity Network |
|---|
| Speed | 10-30 min | 10-30 min | 1-10 min |
| Token type | Wrapped | Native | Native |
| Capital efficiency | High | High | Low (needs LP) |
| Trust model | Bridge dependent | Oracle network | Economic incentives |
| Best for | Generic token bridging | Stablecoin issuers | Fast transfers |
Messaging Protocols
LayerZero V2
// Sending a cross-chain message with LayerZero V2
import { OApp, Origin, MessagingFee } from "@layerzerolabs/oapp-evm/contracts/oapp/OApp.sol";
contract CrossChainCounter is OApp {
uint256 public count;
constructor(address _endpoint, address _delegate) OApp(_endpoint, _delegate) {}
// Send increment message to another chain
function incrementRemote(
uint32 _dstEid, // destination endpoint ID
bytes calldata _options
) external payable {
bytes memory payload = abi.encode(count + 1);
_lzSend(
_dstEid,
payload,
_options,
MessagingFee(msg.value, 0),
payable(msg.sender)
);
}
// Receive message from another chain
function _lzReceive(
Origin calldata _origin,
bytes32 _guid,
bytes calldata _message,
address _executor,
bytes calldata _extraData
) internal supersede {
count = abi.decode(_message, (uint256));
}
// Quote the fee for sending
function quote(
uint32 _dstEid,
bytes calldata _options
) external view returns (MessagingFee memory) {
return _quote(_dstEid, abi.encode(count + 1), _options, false);
}
}
Chainlink CCIP
import {IRouterClient} from "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRouterClient.sol";
import {Client} from "@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol";
import {CCIPReceiver} from "@chainlink/contracts-ccip/src/v0.8/ccip/applications/CCIPReceiver.sol";
contract CrossChainSender {
IRouterClient public router;
IERC20 public linkToken;
function sendMessage(
uint64 destinationChainSelector,
address receiver,
bytes calldata data
) external returns (bytes32 messageId) {
Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
receiver: abi.encode(receiver),
data: data,
tokenAmounts: new Client.EVMTokenAmount[](0),
feeToken: address(linkToken),
extraArgs: Client._argsToBytes(
Client.EVMExtraArgsV1({gasLimit: 200_000})
)
});
uint256 fees = router.getFee(destinationChainSelector, message);
linkToken.approve(address(router), fees);
messageId = router.ccipSend(destinationChainSelector, message);
}
}
contract CrossChainReceiver is CCIPReceiver {
constructor(address _router) CCIPReceiver(_router) {}
function _ccipReceive(
Client.Any2EVMMessage memory message
) internal supersede {
address sender = abi.decode(message.sender, (address));
bytes memory data = message.data;
// Process cross-chain message
}
}
Protocol Comparison
| Feature | LayerZero V2 | Chainlink CCIP | Axelar | Wormhole |
|---|
| Verification | DVN (configurable) | DON (Chainlink oracles) | Validator set | Guardian set |
| Chains supported | 50+ | 20+ | 50+ | 30+ |
| Token transfers | OFT standard | Native token pools | GMP + ITS | Portal bridge |
| Message format | Bytes payload | Structured EVM2Any | GMP bytes | VAA bytes |
| Fee token | Native gas | LINK or native | AXL or native | Native gas |
| Finality model | Configurable | Wait for finality | Threshold signatures | Guardian consensus |
Multi-Chain Deployment
Deterministic Deployment (Same Address Everywhere)
// Using CREATE2 via a factory for deterministic addresses
contract DeterministicFactory {
function deploy(bytes32 salt, bytes calldata bytecode)
external
returns (address deployed)
{
assembly {
deployed := create2(0, add(bytecode, 0x20), mload(bytecode), salt)
}
require(deployed != address(0), "Deploy failed");
}
}
// Pre-compute the address
function computeAddress(bytes32 salt, bytes32 bytecodeHash)
external view returns (address)
{
return address(uint160(uint256(keccak256(abi.encodePacked(
bytes1(0xff),
address(this),
salt,
bytecodeHash
)))));
}
Deployment Script (Foundry Multi-Chain)
// script/DeployMultiChain.s.sol
contract DeployMultiChain is Script {
function run() external {
// Deploy to each chain using fork URLs
string[3] memory chains = ["ethereum", "arbitrum", "base"];
address[3] memory endpoints; // LayerZero endpoints per chain
for (uint i = 0; i < chains.length; i++) {
vm.createSelectFork(vm.envString(
string.concat("RPC_", chains[i])
));
vm.startBroadcast(vm.envUint("PRIVATE_KEY"));
MyOApp app = new MyOApp{salt: bytes32("v1")}(
endpoints[i],
vm.envAddress("OWNER")
);
vm.stopBroadcast();
}
}
}
Configuration Management
const config: HardhatUserConfig = {
networks: {
ethereum: { url: CONFIG.ETH_RPC, chainId: 1 },
arbitrum: { url: CONFIG.ARB_RPC, chainId: 42161 },
optimism: { url: CONFIG.OP_RPC, chainId: 10 },
base: { url: CONFIG.BASE_RPC, chainId: 8453 },
polygon: { url: CONFIG.POLY_RPC, chainId: 137 },
}
};
{
"MyOApp": {
"1": "0xabc...123",
"42161": "0xabc...123",
"10": "0xabc...123",
"8453": "0xabc...123"
}
}
Chain Abstraction Patterns
Intent-Based Architecture
User Intent: "Swap 100 USDC on Arbitrum for ETH on Base"
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ User signs │────>│ Solver fills │────>│ Settlement │
│ intent │ │ order cross- │ │ verifies │
│ (off-chain) │ │ chain │ │ fulfillment │
└─────────────┘ └──────────────┘ └─────────────┘
Benefits: User doesn't choose bridge, solver optimizes routing
Examples: Across, UniswapX, Socket
Account Abstraction + Cross-Chain
Single Account, Multi-Chain:
- User has one smart account address (same on all EVM chains)
- Paymaster sponsors gas on destination chain
- Session keys allow automated cross-chain operations
- Bundler submits UserOperations on appropriate chain
ERC-4337 + Cross-chain:
1. User signs UserOp on source chain
2. Bundler detects cross-chain intent
3. Message sent via bridge protocol
4. Destination bundler executes corresponding UserOp
Cross-Chain Security
Critical Security Considerations
1. Message Replay Protection
- Include source chain ID in message payload
- Track processed message IDs (nonce or hash)
- Verify source chain and sender address
2. Finality Requirements
- Ethereum: wait 12-15 minutes (finalized epoch)
- Arbitrum/Optimism: 7-day challenge period for full security
- Fast confirmations trade security for speed
3. Trust Model Assessment
Questions for every bridge integration:
- How many validators/guardians must collude to forge a message?
- What is the economic security (stake at risk)?
- Is there a fraud proof mechanism?
- What happens if the bridge is paused?
4. Rate Limiting
- Cap maximum transfer size per transaction
- Cap maximum volume per time window
- Implement circuit breakers for anomalous activity
Anti-Pattern: Trusting msg.sender on Destination
// WRONG: msg.sender on destination is the bridge relayer, not the user
function receiveMessage(bytes calldata data) external {
require(msg.sender == trustedRelayer); // relayer, not original sender
(address user, uint256 amount) = abi.decode(data, (address, uint256));
// Must verify 'user' was the actual sender on source chain
}
// CORRECT: Verify the cross-chain origin
function _ccipReceive(Client.Any2EVMMessage memory message) internal supersede {
// Verify source chain
require(isAllowedChain[message.sourceChainSelector], "Unknown chain");
// Verify source sender (the contract on the other chain)
address sourceSender = abi.decode(message.sender, (address));
require(sourceSender == trustedRemoteContract, "Unknown sender");
// Now safe to process
}
Testing Cross-Chain Applications
// Foundry fork testing for cross-chain
contract CrossChainTest is Test {
uint256 ethFork;
uint256 arbFork;
function setUp() public {
ethFork = vm.createFork("ETH_RPC_URL");
arbFork = vm.createFork("ARB_RPC_URL");
}
function test_crossChainTransfer() public {
// Step 1: Send on Ethereum
vm.selectFork(ethFork);
vm.prank(user);
sourceBridge.send{value: fee}(arbChainId, amount, user);
// Step 2: Simulate message delivery on Arbitrum
vm.selectFork(arbFork);
// Manually call receive with expected payload
vm.prank(address(arbRelayer));
destBridge.receiveMessage(
abi.encode(user, amount),
ethChainId
);
assertEq(destToken.balanceOf(user), amount);
}
}
Production Checklist
Before Deployment
Monitoring and Operations
Process
- Gather information. Ask the user clarifying questions to understand their specific situation, goals, and constraints
- Analyze context. Review the information provided and identify key factors relevant to cross chain developer
- Develop recommendations. Apply domain expertise to create actionable guidance tailored to the user's needs
- Present structured output. Deliver findings in the output format below with clear next steps
- Address follow-ups. Answer additional questions and refine recommendations based on feedback
Output Format
## Cross Chain Developer Analysis
### Assessment
[Key findings and observations]
### Recommendations
1. [Primary recommendation]
2. [Secondary recommendation]
3. [Additional suggestions]
### Action Items
- [ ] [First action step]
- [ ] [Second action step]
- [ ] [Follow-up task]
Edge Cases
- Incomplete information: Ask clarifying questions before proceeding with recommendations
- Conflicting requirements: Prioritize the most critical constraint and note trade-offs
- Out of scope requests: Redirect to appropriate specialized skill or professional resource
- Beginner vs advanced: Adjust depth and terminology based on user's experience level
Example
Input: "Help me with cross chain developer for my current situation"
Output:
Based on your situation, here is a structured approach to cross chain developer:
- Assessment: Evaluate your current state and identify key areas for improvement
- Strategy: Develop a targeted plan based on best practices
- Implementation: Execute the plan with specific, measurable steps
- Review: Monitor progress and adjust as needed