Purpose: User wants to move [(s)frxUSD, (s)frxETH, FXS, FPI] from chain A to chain B via LZ.
- User sends OFT to RemoteHop on Chain A
- If
Chain B == Fraxtal- Chain A RemoteHop sends OFT to recipient on Fraxtal
- If
Chain B != Fraxtal- Chain A RemoteHop sends OFT to Fraxtal Remotehop
- Fraxtal Remotehop sends OFT to recipient on chain B.
- If
interface IERC20 {
function approve(address spender, uint256 amount) external;
}
interface IOFT {
function token() external view returns (address);
}
interface IRemoteHop {
function quote(
address _oft,
uint32 _dstEid,
bytes32 _recipient,
uint256 _amountLD,
uint128 _dstGas,
bytes memory _data
) external view returns (uint256 fee);
function sendOFT(
address _oft,
uint32 _dstEid,
bytes32 _recipient,
uint256 _amountLD,
uint128 _dstGas,
bytes memory _data
) external payable;
}// Ethereum WFRAX => (Fraxtal) => Arbitrum WFRAX
// OFT address found @ https://docs.frax.com/protocol/crosschain/addresses
address remoteHop = 0xFd3B410b82a00B2651b42A13837204c5e3D92e27; // See deployed contracts below
address oft = 0x04ACaF8D2865c0714F79da09645C13FD2888977f; // WFRAX OFT
uint32 dstEid = 30110; // Arbitrum
bytes32 recipient = bytes32(uint256(uint160(0xb0E1650A9760e0f383174af042091fc544b8356f))); // example
uint256 amountLD = 1e18;
uint128 dstGas = 0;
bytes memory data = "";
// 1. Quote cost of send
uint256 fee = IRemoteHop(remoteHop).quote(oft, dstEid, recipient, amountLD, dstGas, data);
// 2. Approve OFT underlying token to be transferred to the remoteHop
IERC20(IOFT(oft).token()).approve(remoteHop, amountLD);
// 3. Send the OFT to destination
IRemoteHop(remoteHop).sendOFT{value: fee}(oft, dstEid, recipient, amountLD, dstGas, data);When sending _data, the _recipient on _dstEid must support the interface to receive the tokens via lzCompose():
function hopCompose(
uint32 _srcEid,
bytes32 _sender,
address _oft,
uint256 _amount,
bytes memory _data
)The RemoteVaultHop system enables users to deposit into and redeem from ERC-4626 vaults on remote chains using cross-chain token hops.
1. RemoteVaultHop Contract
- Core orchestrator implementing
IHopComposerto handle vault operations across chains - Manages both local vaults (on the same chain) and remote vaults (on other chains)
- Tracks user deposits via synthetic
RemoteVaultDepositERC20 tokens
2. RemoteVaultDeposit Contract
- ERC20 receipt token representing user deposits in remote vaults
- Tracks price-per-share with linear interpolation over 100 blocks for smooth price updates
- Provides convenience methods:
deposit()andredeem()forward calls to RemoteVaultHop - Users interact with this token to manage their remote vault positions
Deposit Flow (Chain A → Vault on Chain B):
- User calls
RemoteVaultDeposit.deposit(_amount)on Chain A - Transfers tokens to RemoteVaultHop and calls
HOP.sendOFT()withAction.Depositmessage - RemoteVaultHop on Chain B receives via
hopCompose(), callsvault.deposit() - Chain B sends
Action.DepositReturnmessage back with shares received + vault price-per-share - Chain A receives return message, mints RemoteVaultDeposit tokens to user, updates price
Redeem Flow (Chain A ← Vault on Chain B):
- User calls
RemoteVaultDeposit.redeem(_amount)on Chain A (burns deposit tokens) - Sends
Action.Redeemmessage to Chain B - Chain B calls
vault.redeem(), sends tokens back withAction.RedeemReturnmessage - Chain A receives underlying tokens, transfers to user
Security:
- Only RemoteVaultHop can mint/burn RemoteVaultDeposit tokens
- Validates incoming messages are from registered RemoteVaultHops