Skip to main content

Module bridge::message

use bridge::chain_ids;
use bridge::message_types;
use std::ascii;
use std::bcs;
use std::option;
use std::string;
use std::vector;
use sui::address;
use sui::bcs;
use sui::hex;

Struct BridgeMessage

public struct BridgeMessage has copy, drop, store
Click to open
Fields

Struct BridgeMessageKey

public struct BridgeMessageKey has copy, drop, store
Click to open
Fields
source_chain: u8
message_type: u8
bridge_seq_num: u64

Struct TokenTransferPayload

public struct TokenTransferPayload has drop
Click to open
Fields
sender_address: vector<u8>
target_chain: u8
target_address: vector<u8>
token_type: u8
amount: u64

Struct EmergencyOp

public struct EmergencyOp has drop
Click to open
Fields
op_type: u8

Struct Blocklist

public struct Blocklist has drop
Click to open
Fields
blocklist_type: u8
validator_eth_addresses: vector<vector<u8>>

Struct UpdateBridgeLimit

public struct UpdateBridgeLimit has drop
Click to open
Fields
receiving_chain: u8
sending_chain: u8
limit: u64

Struct UpdateAssetPrice

public struct UpdateAssetPrice has drop
Click to open
Fields
token_id: u8
new_price: u64

Struct AddTokenOnSui

public struct AddTokenOnSui has drop
Click to open
Fields
native_token: bool
token_ids: vector<u8>
token_type_names: vector<std::ascii::String>
token_prices: vector<u64>

Struct ParsedTokenTransferMessage

public struct ParsedTokenTransferMessage has drop
Click to open
Fields

Constants

const CURRENT_MESSAGE_VERSION: u8 = 1;

const ECDSA_ADDRESS_LENGTH: u64 = 20;

const EEmptyList: u64 = 2;

const EInvalidAddressLength: u64 = 1;

const EInvalidEmergencyOpType: u64 = 4;

const EInvalidMessageType: u64 = 3;

const EInvalidPayloadLength: u64 = 5;

const EMustBeTokenMessage: u64 = 6;

const ETrailingBytes: u64 = 0;

const PAUSE: u8 = 0;

const UNPAUSE: u8 = 1;

Function extract_token_bridge_payload

public fun extract_token_bridge_payload(message: &bridge::message::BridgeMessage): bridge::message::TokenTransferPayload
Click to open
Implementation
public fun extract_token_bridge_payload(message: &BridgeMessage): TokenTransferPayload {
    let mut bcs = bcs::new(message.payload);
    let sender_address = bcs.peel_vec_u8();
    let target_chain = bcs.peel_u8();
    let target_address = bcs.peel_vec_u8();
    let token_type = bcs.peel_u8();
    let amount = peel_u64_be(&mut bcs);
    chain_ids::assert_valid_chain_id(target_chain);
    assert!(bcs.into_remainder_bytes().is_empty(), ETrailingBytes);
    TokenTransferPayload {
        sender_address,
        target_chain,
        target_address,
        token_type,
        amount
    }
}

Function extract_emergency_op_payload

Emergency op payload is just a single byte

public fun extract_emergency_op_payload(message: &bridge::message::BridgeMessage): bridge::message::EmergencyOp
Click to open
Implementation

Function extract_blocklist_payload

public fun extract_blocklist_payload(message: &bridge::message::BridgeMessage): bridge::message::Blocklist
Click to open
Implementation
public fun extract_blocklist_payload(message: &BridgeMessage): Blocklist {
    // blocklist payload should consist of one byte blocklist type, and list of 20 bytes evm addresses
    // derived from ECDSA public keys
    let mut bcs = bcs::new(message.payload);
    let blocklist_type = bcs.peel_u8();
    let mut address_count = bcs.peel_u8();
    assert!(address_count != 0, EEmptyList);
    let mut validator_eth_addresses = vector[];
    while (address_count > 0) {
        let (mut address, mut i) = (vector[], 0);
        while (i < ECDSA_ADDRESS_LENGTH) {
            address.push_back(bcs.peel_u8());
            i = i + 1;
        };
        validator_eth_addresses.push_back(address);
        address_count = address_count - 1;
    };
    assert!(bcs.into_remainder_bytes().is_empty(), ETrailingBytes);
    Blocklist {
        blocklist_type,
        validator_eth_addresses
    }
}

Function extract_update_bridge_limit

public fun extract_update_bridge_limit(message: &bridge::message::BridgeMessage): bridge::message::UpdateBridgeLimit
Click to open
Implementation
public fun extract_update_bridge_limit(message: &BridgeMessage): UpdateBridgeLimit {
    let mut bcs = bcs::new(message.payload);
    let sending_chain = bcs.peel_u8();
    let limit = peel_u64_be(&mut bcs);
    chain_ids::assert_valid_chain_id(sending_chain);
    assert!(bcs.into_remainder_bytes().is_empty(), ETrailingBytes);
    UpdateBridgeLimit {
        receiving_chain: message.source_chain,
        sending_chain,
        limit
    }
}

Function extract_update_asset_price

public fun extract_update_asset_price(message: &bridge::message::BridgeMessage): bridge::message::UpdateAssetPrice
Click to open
Implementation
public fun extract_update_asset_price(message: &BridgeMessage): UpdateAssetPrice {
    let mut bcs = bcs::new(message.payload);
    let token_id = bcs.peel_u8();
    let new_price = peel_u64_be(&mut bcs);
    assert!(bcs.into_remainder_bytes().is_empty(), ETrailingBytes);
    UpdateAssetPrice {
        token_id,
        new_price
    }
}

Function extract_add_tokens_on_sui

public fun extract_add_tokens_on_sui(message: &bridge::message::BridgeMessage): bridge::message::AddTokenOnSui
Click to open
Implementation
public fun extract_add_tokens_on_sui(message: &BridgeMessage): AddTokenOnSui {
    let mut bcs = bcs::new(message.payload);
    let native_token = bcs.peel_bool();
    let token_ids = bcs.peel_vec_u8();
    let token_type_names_bytes = bcs.peel_vec_vec_u8();
    let token_prices = bcs.peel_vec_u64();
    let mut n = 0;
    let mut token_type_names = vector[];
    while (n < token_type_names_bytes.length()){
        token_type_names.push_back(ascii::string(*token_type_names_bytes.borrow(n)));
        n = n + 1;
    };
    assert!(bcs.into_remainder_bytes().is_empty(), ETrailingBytes);
    AddTokenOnSui {
        native_token,
        token_ids,
        token_type_names,
        token_prices
    }
}

Function serialize_message

public fun serialize_message(message: bridge::message::BridgeMessage): vector<u8>
Click to open
Implementation
public fun serialize_message(message: BridgeMessage): vector<u8> {
    let BridgeMessage {
        message_type,
        message_version,
        seq_num,
        source_chain,
        payload
    } = message;
    let mut message = vector[
        message_type,
        message_version,
    ];
    // bcs serializes u64 as 8 bytes
    message.append(reverse_bytes(bcs::to_bytes(&seq_num)));
    message.push_back(source_chain);
    message.append(payload);
    message
}

Function create_token_bridge_message

Token Transfer Message Format: [message_type: u8] [version:u8] [nonce:u64] [source_chain: u8] [sender_address_length:u8] [sender_address: byte[]] [target_chain:u8] [target_address_length:u8] [target_address: byte[]] [token_type:u8] [amount:u64]

public fun create_token_bridge_message(source_chain: u8, seq_num: u64, sender_address: vector<u8>, target_chain: u8, target_address: vector<u8>, token_type: u8, amount: u64): bridge::message::BridgeMessage
Click to open
Implementation
public fun create_token_bridge_message(
    source_chain: u8,
    seq_num: u64,
    sender_address: vector<u8>,
    target_chain: u8,
    target_address: vector<u8>,
    token_type: u8,
    amount: u64
): BridgeMessage {
    chain_ids::assert_valid_chain_id(source_chain);
    chain_ids::assert_valid_chain_id(target_chain);
    let mut payload = vector[];
    // sender address should be less than 255 bytes so can fit into u8
    payload.push_back((vector::length(&sender_address) as u8));
    payload.append(sender_address);
    payload.push_back(target_chain);
    // target address should be less than 255 bytes so can fit into u8
    payload.push_back((vector::length(&target_address) as u8));
    payload.append(target_address);
    payload.push_back(token_type);
    // bcs serialzies u64 as 8 bytes
    payload.append(reverse_bytes(bcs::to_bytes(&amount)));
    assert!(vector::length(&payload) == 64, EInvalidPayloadLength);
    BridgeMessage {
        message_type: message_types::token(),
        message_version: CURRENT_MESSAGE_VERSION,
        seq_num,
        source_chain,
        payload,
    }
}

Function create_emergency_op_message

Emergency Op Message Format: [message_type: u8] [version:u8] [nonce:u64] [chain_id: u8] [op_type: u8]

public fun create_emergency_op_message(source_chain: u8, seq_num: u64, op_type: u8): bridge::message::BridgeMessage

Function create_blocklist_message

Blocklist Message Format: [message_type: u8] [version:u8] [nonce:u64] [chain_id: u8] [blocklist_type: u8] [validator_length: u8] [validator_ecdsa_addresses: byte[][]]

public fun create_blocklist_message(source_chain: u8, seq_num: u64, blocklist_type: u8, validator_ecdsa_addresses: vector<vector<u8>>): bridge::message::BridgeMessage
Click to open
Implementation
public fun create_blocklist_message(
    source_chain: u8,
    seq_num: u64,
    // 0: block, 1: unblock
    blocklist_type: u8,
    validator_ecdsa_addresses: vector<vector<u8>>,
): BridgeMessage {
    chain_ids::assert_valid_chain_id(source_chain);
    let address_length = validator_ecdsa_addresses.length();
    let mut payload = vector[blocklist_type, (address_length as u8)];
    let mut i = 0;
    while (i < address_length) {
        let address = validator_ecdsa_addresses[i];
        assert!(address.length() == ECDSA_ADDRESS_LENGTH, EInvalidAddressLength);
        payload.append(address);
        i = i + 1;
    };
    BridgeMessage {
        message_type: message_types::committee_blocklist(),
        message_version: CURRENT_MESSAGE_VERSION,
        seq_num,
        source_chain,
        payload,
    }
}

Function create_update_bridge_limit_message

Update bridge limit Message Format: [message_type: u8] [version:u8] [nonce:u64] [receiving_chain_id: u8] [sending_chain_id: u8] [new_limit: u64]

public fun create_update_bridge_limit_message(receiving_chain: u8, seq_num: u64, sending_chain: u8, new_limit: u64): bridge::message::BridgeMessage
Click to open
Implementation
public fun create_update_bridge_limit_message(
    receiving_chain: u8,
    seq_num: u64,
    sending_chain: u8,
    new_limit: u64,
): BridgeMessage {
    chain_ids::assert_valid_chain_id(receiving_chain);
    chain_ids::assert_valid_chain_id(sending_chain);
    let mut payload = vector[sending_chain];
    payload.append(reverse_bytes(bcs::to_bytes(&new_limit)));
    BridgeMessage {
        message_type: message_types::update_bridge_limit(),
        message_version: CURRENT_MESSAGE_VERSION,
        seq_num,
        source_chain: receiving_chain,
        payload,
    }
}

Function create_update_asset_price_message

Update asset price message [message_type: u8] [version:u8] [nonce:u64] [chain_id: u8] [token_id: u8] [new_price:u64]

public fun create_update_asset_price_message(token_id: u8, source_chain: u8, seq_num: u64, new_price: u64): bridge::message::BridgeMessage
Click to open
Implementation

Function create_add_tokens_on_sui_message

Update Sui token message [message_type:u8] [version:u8] [nonce:u64] [chain_id: u8] [native_token:bool] [token_ids:vector] [token_type_name:vector] [token_prices:vector]

public fun create_add_tokens_on_sui_message(source_chain: u8, seq_num: u64, native_token: bool, token_ids: vector<u8>, type_names: vector<std::ascii::String>, token_prices: vector<u64>): bridge::message::BridgeMessage
Click to open
Implementation
public fun create_add_tokens_on_sui_message(
    source_chain: u8,
    seq_num: u64,
    native_token: bool,
    token_ids: vector<u8>,
    type_names: vector<String>,
    token_prices: vector<u64>,
): BridgeMessage {
    chain_ids::assert_valid_chain_id(source_chain);
    let mut payload = bcs::to_bytes(&native_token);
    payload.append(bcs::to_bytes(&token_ids));
    payload.append(bcs::to_bytes(&type_names));
    payload.append(bcs::to_bytes(&token_prices));
    BridgeMessage {
        message_type: message_types::add_tokens_on_sui(),
        message_version: CURRENT_MESSAGE_VERSION,
        seq_num,
        source_chain,
        payload,
    }
}

Function create_key

public fun create_key(source_chain: u8, message_type: u8, bridge_seq_num: u64): bridge::message::BridgeMessageKey
Click to open
Implementation
public fun create_key(source_chain: u8, message_type: u8, bridge_seq_num: u64): BridgeMessageKey {
    BridgeMessageKey { source_chain, message_type, bridge_seq_num }
}

Function key

public fun key(self: &bridge::message::BridgeMessage): bridge::message::BridgeMessageKey
Click to open
Implementation
public fun key(self: &BridgeMessage): BridgeMessageKey {
    create_key(self.source_chain, self.message_type, self.seq_num)
}

Function message_version

public fun message_version(self: &bridge::message::BridgeMessage): u8
Click to open
Implementation
public fun message_version(self: &BridgeMessage): u8 {
    self.message_version
}

Function message_type

public fun message_type(self: &bridge::message::BridgeMessage): u8
Click to open
Implementation
public fun message_type(self: &BridgeMessage): u8 {
    self.message_type
}

Function seq_num

public fun seq_num(self: &bridge::message::BridgeMessage): u64
Click to open
Implementation
public fun seq_num(self: &BridgeMessage): u64 {
    self.seq_num
}

Function source_chain

public fun source_chain(self: &bridge::message::BridgeMessage): u8
Click to open
Implementation
public fun source_chain(self: &BridgeMessage): u8 {
    self.source_chain
}

Function payload

public fun payload(self: &bridge::message::BridgeMessage): vector<u8>
Click to open
Implementation
public fun payload(self: &BridgeMessage): vector<u8> {
    self.payload
}

Function token_target_chain

public fun token_target_chain(self: &bridge::message::TokenTransferPayload): u8
Click to open
Implementation
public fun token_target_chain(self: &TokenTransferPayload): u8 {
    self.target_chain
}

Function token_target_address

public fun token_target_address(self: &bridge::message::TokenTransferPayload): vector<u8>
Click to open
Implementation
public fun token_target_address(self: &TokenTransferPayload): vector<u8> {
    self.target_address
}

Function token_type

public fun token_type(self: &bridge::message::TokenTransferPayload): u8
Click to open
Implementation
public fun token_type(self: &TokenTransferPayload): u8 {
    self.token_type
}

Function token_amount

public fun token_amount(self: &bridge::message::TokenTransferPayload): u64
Click to open
Implementation
public fun token_amount(self: &TokenTransferPayload): u64 {
    self.amount
}

Function emergency_op_type

public fun emergency_op_type(self: &bridge::message::EmergencyOp): u8
Click to open
Implementation
public fun emergency_op_type(self: &EmergencyOp): u8 {
    self.op_type
}

Function blocklist_type

public fun blocklist_type(self: &bridge::message::Blocklist): u8
Click to open
Implementation
public fun blocklist_type(self: &Blocklist): u8 {
    self.blocklist_type
}

Function blocklist_validator_addresses

public fun blocklist_validator_addresses(self: &bridge::message::Blocklist): &vector<vector<u8>>
Click to open
Implementation
public fun blocklist_validator_addresses(self: &Blocklist): &vector<vector<u8>> {
    &self.validator_eth_addresses
}

Function update_bridge_limit_payload_sending_chain

public fun update_bridge_limit_payload_sending_chain(self: &bridge::message::UpdateBridgeLimit): u8
Click to open
Implementation
public fun update_bridge_limit_payload_sending_chain(self: &UpdateBridgeLimit): u8 {
    self.sending_chain
}

Function update_bridge_limit_payload_receiving_chain

public fun update_bridge_limit_payload_receiving_chain(self: &bridge::message::UpdateBridgeLimit): u8
Click to open
Implementation
public fun update_bridge_limit_payload_receiving_chain(self: &UpdateBridgeLimit): u8 {
    self.receiving_chain
}

Function update_bridge_limit_payload_limit

public fun update_bridge_limit_payload_limit(self: &bridge::message::UpdateBridgeLimit): u64
Click to open
Implementation
public fun update_bridge_limit_payload_limit(self: &UpdateBridgeLimit): u64 {
    self.limit
}

Function update_asset_price_payload_token_id

public fun update_asset_price_payload_token_id(self: &bridge::message::UpdateAssetPrice): u8
Click to open
Implementation
public fun update_asset_price_payload_token_id(self: &UpdateAssetPrice): u8 {
    self.token_id
}

Function update_asset_price_payload_new_price

public fun update_asset_price_payload_new_price(self: &bridge::message::UpdateAssetPrice): u64
Click to open
Implementation
public fun update_asset_price_payload_new_price(self: &UpdateAssetPrice): u64 {
    self.new_price
}

Function is_native

public fun is_native(self: &bridge::message::AddTokenOnSui): bool
Click to open
Implementation
public fun is_native(self: &AddTokenOnSui): bool {
    self.native_token
}

Function token_ids

public fun token_ids(self: &bridge::message::AddTokenOnSui): vector<u8>
Click to open
Implementation
public fun token_ids(self: &AddTokenOnSui): vector<u8> {
    self.token_ids
}

Function token_type_names

public fun token_type_names(self: &bridge::message::AddTokenOnSui): vector<std::ascii::String>
Click to open
Implementation
public fun token_type_names(self: &AddTokenOnSui): vector<String> {
    self.token_type_names
}

Function token_prices

public fun token_prices(self: &bridge::message::AddTokenOnSui): vector<u64>
Click to open
Implementation
public fun token_prices(self: &AddTokenOnSui): vector<u64> {
    self.token_prices
}

Function emergency_op_pause

public fun emergency_op_pause(): u8
Click to open
Implementation
public fun emergency_op_pause(): u8 {
    PAUSE
}

Function emergency_op_unpause

public fun emergency_op_unpause(): u8
Click to open
Implementation
public fun emergency_op_unpause(): u8 {
    UNPAUSE
}

Function required_voting_power

Return the required signature threshold for the message, values are voting power in the scale of 10000

public fun required_voting_power(self: &bridge::message::BridgeMessage): u64
Click to open
Implementation
public fun required_voting_power(self: &BridgeMessage): u64 {
    let message_type = message_type(self);
    if (message_type == message_types::token()) {
        3334
    } else if (message_type == message_types::emergency_op()) {
        let payload = extract_emergency_op_payload(self);
        if (payload.op_type == PAUSE) {
            450
        } else if (payload.op_type == UNPAUSE) {
            5001
        } else {
            abort EInvalidEmergencyOpType
        }
    } else if (message_type == message_types::committee_blocklist()) {
        5001
    } else if (message_type == message_types::update_asset_price()) {
        5001
    } else if (message_type == message_types::update_bridge_limit()) {
        5001
    } else if (message_type == message_types::add_tokens_on_sui()) {
        5001
    } else {
        abort EInvalidMessageType
    }
}

Function to_parsed_token_transfer_message

public fun to_parsed_token_transfer_message(message: &bridge::message::BridgeMessage): bridge::message::ParsedTokenTransferMessage

Function reverse_bytes

fun reverse_bytes(bytes: vector<u8>): vector<u8>
Click to open
Implementation
fun reverse_bytes(mut bytes: vector<u8>): vector<u8> {
    vector::reverse(&mut bytes);
    bytes
}

Function peel_u64_be

fun peel_u64_be(bcs: &mut sui::bcs::BCS): u64
Click to open
Implementation
fun peel_u64_be(bcs: &mut BCS): u64 {
    let (mut value, mut i) = (0u64, 64u8);
    while (i > 0) {
        i = i - 8;
        let byte = (bcs::peel_u8(bcs) as u64);
        value = value + (byte << i);
    };
    value
}