withdraw
Function Type: external payable
Function Signature: withdraw(address,address,uint256,bytes1)
Returns: void
Withdraws tokens from EVVM balance and sends them to external chain via selected cross-chain protocol. This function validates balance, deducts from EVVM, and bridges via Hyperlane, LayerZero, or Axelar protocols.
Parameters
| Parameter | Type | Description |
|---|---|---|
toAddress | address | Recipient address on the external chain |
token | address | Token contract address or address(0) for native coin |
amount | uint256 | Amount to withdraw |
protocolToExecute | bytes1 | Cross-chain protocol identifier (0x01, 0x02, or 0x03) |
Protocol Identifiers
| Value | Protocol | Description |
|---|---|---|
0x01 | Hyperlane | Uses Hyperlane mailbox for cross-chain messaging |
0x02 | LayerZero | Uses LayerZero endpoint for omnichain transfers |
0x03 | Axelar | Uses Axelar gateway for decentralized cross-chain communication |
Workflow
Initial Validations
- Principal Token Protection: Validates token is not the Principal Token (MATE) using
Evvm(evvmAddress).getEvvmMetadata().principalTokenAddress. Reverts withErrorsLib.PrincipalTokenIsNotWithdrawable()if attempted. - Balance Verification: Confirms user has sufficient EVVM balance using
Evvm(evvmAddress).getBalance(msg.sender, token). Reverts withErrorsLib.InsufficientBalance()if insufficient. - EVVM Balance Deduction: Calls
Evvm(evvmAddress).removeAmountFromUser(msg.sender, token, amount)to deduct from user's virtual balance.
Protocol-Specific Execution
Hyperlane (0x01)
bytes memory payload = PayloadUtils.encodePayload(token, toAddress, amount);
uint256 quote = IMailbox(hyperlane.mailboxAddress).quoteDispatch(
hyperlane.externalChainStationDomainId,
hyperlane.externalChainStationAddress,
payload
);
IMailbox(hyperlane.mailboxAddress).dispatch{value: quote}(
hyperlane.externalChainStationDomainId,
hyperlane.externalChainStationAddress,
payload
);
- Payload Encoding: Uses
PayloadUtils.encodePayload()for standardized message format - Quote Calculation: Gets exact dispatch cost via
IMailbox.quoteDispatch() - Message Dispatch: Sends to external station via Hyperlane mailbox with proper gas payment
LayerZero (0x02)
bytes memory payload = PayloadUtils.encodePayload(token, toAddress, amount);
MessagingFee memory fee = _quote(
layerZero.externalChainStationEid,
payload,
options,
false
);
_lzSend(
layerZero.externalChainStationEid,
payload,
options,
MessagingFee(fee.nativeFee, 0),
msg.sender
);
- Payload Encoding: Uses
PayloadUtils.encodePayload()for consistent data structure - Fee Quotation: Calculates exact messaging fee via
_quote()function - Omnichain Send: Dispatches via LayerZero V2 endpoint with proper fee handling
Axelar (0x03)
bytes memory payload = PayloadUtils.encodePayload(token, toAddress, amount);
IAxelarGasService(axelar.gasServiceAddress).payNativeGasForContractCall{
value: msg.value
}(
address(this),
axelar.externalChainStationChainName,
axelar.externalChainStationAddress,
payload,
msg.sender
);
gateway().callContract(
axelar.externalChainStationChainName,
axelar.externalChainStationAddress,
payload
);
- Payload Encoding: Uses
PayloadUtils.encodePayload()for cross-chain compatibility - Gas Service Payment: Prepays execution gas to Axelar gas service contract
- Gateway Dispatch: Routes message through Axelar gateway with refund to sender
Payload Encoding
The function uses standardized payload encoding via PayloadUtils library:
bytes memory payload = PayloadUtils.encodePayload(token, toAddress, amount);
This creates a consistent format decoded on external chain station using:
(address token, address toAddress, uint256 amount) = PayloadUtils.decodePayload(payload);
The payload structure ensures:
- Token identification: ERC20 contract address or
address(0)for native coins - Recipient specification: Exact recipient address on external chain
- Amount precision: Token amount in native decimals
Gas Requirements
Users must send sufficient native tokens with the transaction to cover:
- Hyperlane: Mailbox dispatch fees
- LayerZero: Endpoint messaging fees
- Axelar: Gas service payments
The transaction will revert if insufficient native tokens are provided to cover cross-chain messaging costs. Use the respective quote functions to estimate required amounts.
Security Features
- User Authorization: Only holders can withdraw from their own EVVM balances
- Principal Token Protection:
ErrorsLib.PrincipalTokenIsNotWithdrawable()prevents MATE token withdrawal - Balance Verification:
ErrorsLib.InsufficientBalance()protection with EVVM balance checks - Protocol Validation: Reverts for invalid protocol identifiers
- Cross-Chain Security: Each protocol validates sender authorization on message receipt
External Chain Processing
Upon successful cross-chain message delivery, the External Chain Station:
- Message Validation: Verifies sender authorization and chain ID
- Payload Decoding: Uses
PayloadUtils.decodePayload()to extract transfer details - Asset Transfer: Transfers ERC20 tokens or native coins to recipient
- Event Emission: Logs successful cross-chain transfer for tracking