How are messages encoded with call frames?

We know how solidity receives data and process them. But there isn’t much docs on how data received is treated from L1 to L2 and L2 to L2. It seems to be designed with some differentiation in encoding and offsets. Hence can someone explain how data received and sent treated? @Nazeeh21 @david

In essence, how data is formatted and transmitted between contracts and from L1 to L2?
In FuelERC20Gatewayv4.sol

        bytes memory depositMessage = abi.encodePacked(
            assetIssuerId,
            uint256(data.length == 0 ? MessageType.DEPOSIT_TO_CONTRACT : MessageType.DEPOSIT_WITH_DATA),
            bytes32(uint256(uint160(tokenAddress))),
            uint256(0), // token_id = 0 for all erc20 deposits
            bytes32(uint256(uint160(msg.sender))),
            to,
            l2MintedAmount,
            uint256(decimals),
            data
        );

Constants.sw for offsets

library;

// A message is encoded as
// 0x00 => CONTRACT_ID
// 0x20 => MESSAGE_TYPE
// 0x40 => TOKEN_ADDRESS
// 0x60 => TOKEN_ID
pub const OFFSET_MESSAGE_TYPE: u64 = 32; //0x20
pub const OFFSET_TOKEN_ADDRESS: u64 = OFFSET_MESSAGE_TYPE + 32; //0x40
pub const OFFSET_TOKEN_ID: u64 = OFFSET_TOKEN_ADDRESS + 32; //0x60

// 0x80 and onwards: payload, with offsets defined as below

// Offsets for a deposit message
pub const OFFSET_FROM: u64 = OFFSET_TOKEN_ID + 32;
pub const OFFSET_TO: u64 = OFFSET_FROM + 32;
pub const OFFSET_AMOUNT: u64 = OFFSET_TO + 32; //0xC0
pub const OFFSET_DECIMALS: u64 = OFFSET_AMOUNT + 32;

// Offsets for a metadata message
pub const OFFSET_NAME_PTR: u64 = OFFSET_TOKEN_ID + 32;
pub const OFFSET_SYMBOL_PTR: u64 = OFFSET_NAME_PTR + 32;

// Type of messages that can be received
pub const DEPOSIT: u8 = 0;
pub const CONTRACT_DEPOSIT: u8 = 1;
pub const CONTRACT_DEPOSIT_WITH_DATA: u8 = 2;
pub const METADATA: u8 = 3;

In deposit_message.sw

//     pub struct DepositMessage {
//     pub amount: b256,
//     pub from: b256,
//     pub to: Identity,
//     pub token_address: b256,
//     pub token_id: b256,
//     pub decimals: u8,
//     pub deposit_type: DepositType,
// }
    /// Read the bytes passed as message data into an in-memory representation using the DepositMessage type
    pub fn parse_deposit_to_contract_with_data(msg_idx: u64) -> Self {
        Self {
            amount: input_message_data(msg_idx, OFFSET_AMOUNT).into(),
            from: input_message_data(msg_idx, OFFSET_FROM).into(),
            token_address: input_message_data(msg_idx, OFFSET_TOKEN_ADDRESS).into(),
            to: Identity::ContractId(ContractId::from(b256::from(input_message_data(msg_idx, OFFSET_TO)))),
            token_id: input_message_data(msg_idx, OFFSET_TOKEN_ID).into(),
            decimals: input_message_data(msg_idx, OFFSET_DECIMALS).get(31).unwrap(),
            deposit_type: DepositType::ContractWithData,
        }
    }

I really need help: Fuel Specifications | Fuel Docs stated that 8*64 byte[8][64] regs Saved registers from previous context.

Does this means that the bytes are fitted here?: The weird thing I found is that there is one more bytes that is not used though

library;

// A message is encoded as
// 0x00 => CONTRACT_ID
// 0x20 => MESSAGE_TYPE
// 0x40 => TOKEN_ADDRESS
// 0x60 => TOKEN_ID
pub const OFFSET_MESSAGE_TYPE: u64 = 32; //0x20
pub const OFFSET_TOKEN_ADDRESS: u64 = OFFSET_MESSAGE_TYPE + 32; //0x40
pub const OFFSET_TOKEN_ID: u64 = OFFSET_TOKEN_ADDRESS + 32; //0x60

// 0x80 and onwards: payload, with offsets defined as below

// Offsets for a deposit message
pub const OFFSET_FROM: u64 = OFFSET_TOKEN_ID + 32;
pub const OFFSET_TO: u64 = OFFSET_FROM + 32;
pub const OFFSET_AMOUNT: u64 = OFFSET_TO + 32; //0xC0
pub const OFFSET_DECIMALS: u64 = OFFSET_AMOUNT + 32;

// Offsets for a metadata message
pub const OFFSET_NAME_PTR: u64 = OFFSET_TOKEN_ID + 32;
pub const OFFSET_SYMBOL_PTR: u64 = OFFSET_NAME_PTR + 32;

Hi @eesheng ,

The bridge team should respond shortly with a more in-depth answer, but somethings that may be of help to you below.

When data is being communicated from the L1 bridge, you can access it via a MessageInput:

This input will specify the actual data from the L1 in memory, and thus make it accessible to the transaction execution script/contracts/predicates contained in the transaction spending this input.