axelar-cgp-sui

Module 0xa9::its

use 0x1::ascii;
use 0x1::string;
use 0x1::type_name;
use 0x2::address;
use 0x2::clock;
use 0x2::coin;
use 0x2::event;
use 0x2::hex;
use 0x2::object;
use 0x2::sui;
use 0x2::transfer;
use 0x2::tx_context;
use 0xa1::channel;
use 0xa1::gateway;
use 0xa1::message_ticket;
use 0xa2::gas_service;
use 0xa5::coin_info;
use 0xa5::coin_management;
use 0xa5::discovery;
use 0xa5::interchain_token_service;
use 0xa5::interchain_transfer_ticket;
use 0xa5::token_id;
use 0xa9::utils;
use 0xaa::discovery;
use 0xaa::transaction;

Resource Singleton

struct Singleton has key
Fields
id: object::UID
channel: channel::Channel

Struct ExecutedWithToken

struct ExecutedWithToken has copy, drop
Fields
source_chain: ascii::String
source_address: vector<u8>
data: vector<u8>
amount: u64

Function init


Setup —–

fun init(ctx: &mut tx_context::TxContext)
Implementation
fun init(ctx: &mut TxContext) {
    let singletonId = object::new(ctx);
    let channel = channel::new(ctx);
    transfer::share_object(Singleton {
        id: singletonId,
        channel,
    });
}

Function register_transaction

This needs to be called to register the transaction so that the relayer knows to call this to fulfill calls.

public fun register_transaction(discovery: &mut discovery::RelayerDiscovery, singleton: &its::Singleton, its: &interchain_token_service::InterchainTokenService, clock: &clock::Clock)
Implementation
public fun register_transaction(discovery: &mut RelayerDiscovery, singleton: &Singleton, its: &InterchainTokenService, clock: &Clock) {
    let arguments = vector[
        concat(vector[0u8], object::id_address(singleton).to_bytes()),
        concat(vector[0u8], object::id_address(its).to_bytes()),
        vector[3u8],
        concat(vector[0u8], object::id_address(clock).to_bytes()),
    ];

    let transaction = transaction::new_transaction(
        false,
        vector[
            transaction::new_move_call(
                transaction::new_function(
                    address::from_bytes(
                        hex::decode(
                            *ascii::as_bytes(
                                &type_name::get_address(
                                    &type_name::get<Singleton>(),
                                ),
                            ),
                        ),
                    ),
                    ascii::string(b"its"),
                    ascii::string(b"get_final_transaction"),
                ),
                arguments,
                vector[],
            ),
        ],
    );

    discovery.register_transaction(&singleton.channel, transaction);
}

Function get_final_transaction

public fun get_final_transaction(singleton: &its::Singleton, its: &interchain_token_service::InterchainTokenService, payload: vector<u8>, clock: &clock::Clock): transaction::Transaction
Implementation
public fun get_final_transaction(singleton: &Singleton, its: &InterchainTokenService, payload: vector<u8>, clock: &Clock): Transaction {
    let arguments = vector[
        vector[2u8],
        concat(vector[0u8], object::id_address(singleton).to_bytes()),
        concat(vector[0u8], object::id_address(its).to_bytes()),
        concat(vector[0u8], object::id_address(clock).to_bytes()),
    ];

    // Get the coin type from its
    let (token_id, _, _, _) = its_discovery::interchain_transfer_info(
        payload,
    );
    let coin_type = (*its.registered_coin_type(token_id)).into_string();

    let transaction = transaction::new_transaction(
        true,
        vector[
            transaction::new_move_call(
                transaction::new_function(
                    address::from_bytes(
                        hex::decode(
                            *ascii::as_bytes(
                                &type_name::get_address(
                                    &type_name::get<Singleton>(),
                                ),
                            ),
                        ),
                    ),
                    ascii::string(b"its"),
                    ascii::string(b"receive_interchain_transfer"),
                ),
                arguments,
                vector[coin_type],
            ),
        ],
    );

    transaction
}

Function register_coin

This function needs to be called first to register the coin for either of the other two functions to work.

public fun register_coin<TOKEN>(its: &mut interchain_token_service::InterchainTokenService, coin_metadata: &coin::CoinMetadata<TOKEN>): token_id::TokenId
Implementation
public fun register_coin<TOKEN>(its: &mut InterchainTokenService, coin_metadata: &CoinMetadata<TOKEN>): TokenId {
    let coin_info = coin_info::from_info<TOKEN>(
        coin_metadata.get_name(),
        coin_metadata.get_symbol(),
        coin_metadata.get_decimals(),
    );
    let coin_management = coin_management::new_locked();

    its.register_coin(
        coin_info,
        coin_management,
    )
}

Function register_coin_with_cap

Registers a coin with the Interchain Token Service (ITS), using the provided TreasuryCap to manage the coin. The TreasuryCap gives the ITS control over minting and burning of this coin.

public fun register_coin_with_cap<TOKEN>(its: &mut interchain_token_service::InterchainTokenService, coin_metadata: &coin::CoinMetadata<TOKEN>, treasury_cap: coin::TreasuryCap<TOKEN>): token_id::TokenId
Implementation
public fun register_coin_with_cap<TOKEN>(
    its: &mut InterchainTokenService,
    coin_metadata: &CoinMetadata<TOKEN>,
    treasury_cap: TreasuryCap<TOKEN>,
): TokenId {
    let coin_info = coin_info::from_info<TOKEN>(
        coin_metadata.get_name(),
        coin_metadata.get_symbol(),
        coin_metadata.get_decimals(),
    );
    let coin_management = coin_management::new_with_cap(treasury_cap);

    its.register_coin(
        coin_info,
        coin_management,
    )
}

Function deploy_remote_interchain_token

public fun deploy_remote_interchain_token<TOKEN>(its: &mut interchain_token_service::InterchainTokenService, gateway: &mut gateway::Gateway, gas_service: &mut gas_service::GasService, destination_chain: ascii::String, token_id: token_id::TokenId, gas: coin::Coin<sui::SUI>, gas_params: vector<u8>, refund_address: address)
Implementation
public fun deploy_remote_interchain_token<TOKEN>(
    its: &mut InterchainTokenService,
    gateway: &mut Gateway,
    gas_service: &mut GasService,
    destination_chain: String,
    token_id: TokenId,
    gas: Coin<SUI>,
    gas_params: vector<u8>,
    refund_address: address,
) {
    let message_ticket = its.deploy_remote_interchain_token<TOKEN>(
        token_id,
        destination_chain,
    );

    pay_gas_and_send_message(
        gateway,
        gas_service,
        gas,
        message_ticket,
        refund_address,
        gas_params,
    );
}

Function send_interchain_transfer_call

This should trigger an interchain trasnfer.

public fun send_interchain_transfer_call<TOKEN>(singleton: &its::Singleton, its: &mut interchain_token_service::InterchainTokenService, gateway: &mut gateway::Gateway, gas_service: &mut gas_service::GasService, token_id: token_id::TokenId, coin: coin::Coin<TOKEN>, destination_chain: ascii::String, destination_address: vector<u8>, metadata: vector<u8>, refund_address: address, gas: coin::Coin<sui::SUI>, gas_params: vector<u8>, clock: &clock::Clock)
Implementation
public fun send_interchain_transfer_call<TOKEN>(
    singleton: &Singleton,
    its: &mut InterchainTokenService,
    gateway: &mut Gateway,
    gas_service: &mut GasService,
    token_id: TokenId,
    coin: Coin<TOKEN>,
    destination_chain: String,
    destination_address: vector<u8>,
    metadata: vector<u8>,
    refund_address: address,
    gas: Coin<SUI>,
    gas_params: vector<u8>,
    clock: &Clock,
) {
    let interchain_transfer_ticket = interchain_token_service::prepare_interchain_transfer<TOKEN>(
        token_id,
        coin,
        destination_chain,
        destination_address,
        metadata,
        &singleton.channel,
    );

    let message_ticket = its.send_interchain_transfer<TOKEN>(
        interchain_transfer_ticket,
        clock,
    );

    pay_gas_and_send_message(
        gateway,
        gas_service,
        gas,
        message_ticket,
        refund_address,
        gas_params,
    );
}

Function receive_interchain_transfer

This should receive some coins, give them to the executor, and emit and event with all the relevant info.

public fun receive_interchain_transfer<TOKEN>(approved_message: channel::ApprovedMessage, singleton: &its::Singleton, its: &mut interchain_token_service::InterchainTokenService, clock: &clock::Clock, ctx: &mut tx_context::TxContext)
Implementation
public fun receive_interchain_transfer<TOKEN>(
    approved_message: ApprovedMessage,
    singleton: &Singleton,
    its: &mut InterchainTokenService,
    clock: &Clock,
    ctx: &mut TxContext,
) {
    let (source_chain, source_address, data, coin) = its.receive_interchain_transfer_with_data<TOKEN>(
        approved_message,
        &singleton.channel,
        clock,
        ctx,
    );

    event::emit(ExecutedWithToken {
        source_chain,
        source_address,
        data,
        amount: coin.value(),
    });

    // give the coin to the caller
    transfer::public_transfer(coin, ctx.sender());
}

Function pay_gas_and_send_message

fun pay_gas_and_send_message(gateway: &gateway::Gateway, gas_service: &mut gas_service::GasService, gas: coin::Coin<sui::SUI>, message_ticket: message_ticket::MessageTicket, refund_address: address, gas_params: vector<u8>)
Implementation
fun pay_gas_and_send_message(
    gateway: &Gateway,
    gas_service: &mut GasService,
    gas: Coin<SUI>,
    message_ticket: MessageTicket,
    refund_address: address,
    gas_params: vector<u8>,
) {
    gas_service.pay_gas(
        &message_ticket,
        gas,
        refund_address,
        gas_params,
    );

    gateway::send_message(gateway, message_ticket);
}