0xa1::gateway_v0
Gateway_v0
CommandType
new
version_control
approve_messages
rotate_signers
is_message_approved
is_message_executed
take_approved_message
send_message
allow_function
disallow_function
borrow
borrow_mut
peel_messages
data_hash
approve_message
as_u8
use 0x1::ascii;
use 0x1::vector;
use 0x2::address;
use 0x2::bcs;
use 0x2::clock;
use 0x2::hash;
use 0x2::table;
use 0x2::tx_context;
use 0xa1::auth;
use 0xa1::bytes32;
use 0xa1::channel;
use 0xa1::events;
use 0xa1::message;
use 0xa1::message_status;
use 0xa1::message_ticket;
use 0xa1::proof;
use 0xa1::weighted_signers;
use 0xb0::version_control;
Gateway_v0
An object holding the state of the Axelar bridge. The central piece in managing call approval creation and signature verification.
struct Gateway_v0 has store
operator: address
messages: table::Table<bytes32::Bytes32, message_status::MessageStatus>
signers: auth::AxelarSigners
version_control: version_control::VersionControl
CommandType
public enum CommandType
ApproveMessages
RotateSigners
#[error]
const EMessageNotApproved: vector<u8> = b"trying to `take_approved_message` for a message that is not approved";
#[error]
const ENewerMessage: vector<u8> = b"message ticket created from newer versions cannot be sent here";
#[error]
const ENotLatestSigners: vector<u8> = b"not latest signers";
#[error]
const EZeroMessages: vector<u8> = b"no messages found";
new
Init the module by giving a OwnerCap to the sender to allow a full
setup
.
public(friend) fun new(operator: address, messages: table::Table<bytes32::Bytes32, message_status::MessageStatus>, signers: auth::AxelarSigners, version_control: version_control::VersionControl): gateway_v0::Gateway_v0
public(package) fun new(
operator: address,
messages: Table<Bytes32, MessageStatus>,
signers: AxelarSigners,
version_control: VersionControl,
): Gateway_v0 {
Gateway_v0 {
operator,
messages,
signers,
version_control,
}
}
version_control
public(friend) fun version_control(self: &gateway_v0::Gateway_v0): &version_control::VersionControl
public(package) fun version_control(self: &Gateway_v0): &VersionControl {
&self.version_control
}
approve_messages
public(friend) fun approve_messages(self: &mut gateway_v0::Gateway_v0, message_data: vector<u8>, proof_data: vector<u8>)
public(package) fun approve_messages(
self: &mut Gateway_v0,
message_data: vector<u8>,
proof_data: vector<u8>,
) {
let proof = utils::peel!(proof_data, |bcs| proof::peel(bcs));
let messages = peel_messages(message_data);
let _ = self
.signers
.validate_proof(
data_hash(CommandType::ApproveMessages, message_data),
proof,
);
messages.do!(|message| self.approve_message(message));
}
rotate_signers
public(friend) fun rotate_signers(self: &mut gateway_v0::Gateway_v0, clock: &clock::Clock, new_signers_data: vector<u8>, proof_data: vector<u8>, ctx: &tx_context::TxContext)
public(package) fun rotate_signers(
self: &mut Gateway_v0,
clock: &Clock,
new_signers_data: vector<u8>,
proof_data: vector<u8>,
ctx: &TxContext,
) {
let weighted_signers = utils::peel!(
new_signers_data,
|bcs| weighted_signers::peel(bcs),
);
let proof = utils::peel!(proof_data, |bcs| proof::peel(bcs));
let enforce_rotation_delay = ctx.sender() != self.operator;
let is_latest_signers = self
.signers
.validate_proof(
data_hash(CommandType::RotateSigners, new_signers_data),
proof,
);
assert!(!enforce_rotation_delay || is_latest_signers, ENotLatestSigners);
// This will fail if signers are duplicated
self
.signers
.rotate_signers(clock, weighted_signers, enforce_rotation_delay);
}
is_message_approved
public(friend) fun is_message_approved(self: &gateway_v0::Gateway_v0, source_chain: ascii::String, message_id: ascii::String, source_address: ascii::String, destination_id: address, payload_hash: bytes32::Bytes32): bool
public(package) fun is_message_approved(
self: &Gateway_v0,
source_chain: String,
message_id: String,
source_address: String,
destination_id: address,
payload_hash: Bytes32,
): bool {
let message = message::new(
source_chain,
message_id,
source_address,
destination_id,
payload_hash,
);
let command_id = message.command_id();
self[command_id] == message_status::approved(message.hash())
}
is_message_executed
public(friend) fun is_message_executed(self: &gateway_v0::Gateway_v0, source_chain: ascii::String, message_id: ascii::String): bool
public(package) fun is_message_executed(
self: &Gateway_v0,
source_chain: String,
message_id: String,
): bool {
let command_id = message::message_to_command_id(
source_chain,
message_id,
);
self[command_id] == message_status::executed()
}
take_approved_message
To execute a message, the relayer will call take_approved_message
to get the hot potato ApprovedMessage
object, and then trigger the app’s
package via discovery.
public(friend) fun take_approved_message(self: &mut gateway_v0::Gateway_v0, source_chain: ascii::String, message_id: ascii::String, source_address: ascii::String, destination_id: address, payload: vector<u8>): channel::ApprovedMessage
public(package) fun take_approved_message(
self: &mut Gateway_v0,
source_chain: String,
message_id: String,
source_address: String,
destination_id: address,
payload: vector<u8>,
): ApprovedMessage {
let command_id = message::message_to_command_id(source_chain, message_id);
let message = message::new(
source_chain,
message_id,
source_address,
destination_id,
bytes32::from_bytes(hash::keccak256(&payload)),
);
assert!(
self[command_id] == message_status::approved(message.hash()),
EMessageNotApproved,
);
let message_status_ref = &mut self[command_id];
*message_status_ref = message_status::executed();
events::message_executed(
message,
);
channel::create_approved_message(
source_chain,
message_id,
source_address,
destination_id,
payload,
)
}
send_message
public(friend) fun send_message(_self: &gateway_v0::Gateway_v0, message: message_ticket::MessageTicket, current_version: u64)
public(package) fun send_message(
_self: &Gateway_v0,
message: MessageTicket,
current_version: u64,
) {
let (
source_id,
destination_chain,
destination_address,
payload,
version,
) = message.destroy();
assert!(version <= current_version, ENewerMessage);
events::contract_call(
source_id,
destination_chain,
destination_address,
payload,
address::from_bytes(hash::keccak256(&payload)),
);
}
allow_function
public(friend) fun allow_function(self: &mut gateway_v0::Gateway_v0, version: u64, function_name: ascii::String)
public(package) fun allow_function(
self: &mut Gateway_v0,
version: u64,
function_name: String,
) {
self.version_control.allow_function(version, function_name);
}
disallow_function
public(friend) fun disallow_function(self: &mut gateway_v0::Gateway_v0, version: u64, function_name: ascii::String)
public(package) fun disallow_function(
self: &mut Gateway_v0,
version: u64,
function_name: String,
) {
self.version_control.disallow_function(version, function_name);
}
borrow
fun borrow(self: &gateway_v0::Gateway_v0, command_id: bytes32::Bytes32): &message_status::MessageStatus
fun borrow(self: &Gateway_v0, command_id: Bytes32): &MessageStatus {
table::borrow(&self.messages, command_id)
}
borrow_mut
fun borrow_mut(self: &mut gateway_v0::Gateway_v0, command_id: bytes32::Bytes32): &mut message_status::MessageStatus
fun borrow_mut(self: &mut Gateway_v0, command_id: Bytes32): &mut MessageStatus {
table::borrow_mut(&mut self.messages, command_id)
}
peel_messages
fun peel_messages(message_data: vector<u8>): vector<message::Message>
fun peel_messages(message_data: vector<u8>): vector<Message> {
utils::peel!(message_data, |bcs| {
let messages = vector::tabulate!(
bcs.peel_vec_length(),
|_| message::peel(bcs),
);
assert!(messages.length() > 0, EZeroMessages);
messages
})
}
data_hash
fun data_hash(command_type: gateway_v0::CommandType, data: vector<u8>): bytes32::Bytes32
fun data_hash(command_type: CommandType, data: vector<u8>): Bytes32 {
let mut typed_data = vector::singleton(command_type.as_u8());
typed_data.append(data);
bytes32::from_bytes(hash::keccak256(&typed_data))
}
approve_message
fun approve_message(self: &mut gateway_v0::Gateway_v0, message: message::Message)
fun approve_message(self: &mut Gateway_v0, message: message::Message) {
let command_id = message.command_id();
// If the message was already approved, ignore it.
if (self.messages.contains(command_id)) {
return
};
self
.messages
.add(
command_id,
message_status::approved(message.hash()),
);
events::message_approved(
message,
);
}
as_u8
fun as_u8(self: gateway_v0::CommandType): u8
fun as_u8(self: CommandType): u8 {
match (self) {
CommandType::ApproveMessages => 0,
CommandType::RotateSigners => 1,
}
}