0xa5::interchain_token_service_v0
InterchainTokenService_v0
new
unregistered_coin_type
registered_coin_type
channel_address
set_relayer_discovery_id
relayer_discovery_id
add_trusted_chain
remove_trusted_chain
add_trusted_chains
remove_trusted_chains
channel
version_control
register_coin
register_coin_from_info
register_coin_from_metadata
register_custom_coin
link_coin
register_coin_metadata
deploy_remote_interchain_token
send_interchain_transfer
receive_interchain_transfer
receive_interchain_transfer_with_data
receive_deploy_interchain_token
receive_link_coin
give_unregistered_coin
give_unlinked_coin
mint_as_distributor
mint_to_as_distributor
burn_as_distributor
set_flow_limit_as_token_operator
set_flow_limit
transfer_distributorship
transfer_operatorship
remove_treasury_cap
restore_treasury_cap
allow_function
disallow_function
coin_data
migrate_coin_metadata
is_trusted_chain
coin_management_mut
add_unregistered_coin
add_unlinked_coin
remove_unlinked_coin
remove_unregistered_coin
add_unregistered_coin_type
remove_unregistered_coin_type
add_registered_coin_type
add_registered_coin
prepare_hub_message
prepare_message
decode_approved_message
read_amount
coin_data_mut
use 0x1::ascii;
use 0x1::option;
use 0x1::string;
use 0x1::type_name;
use 0x1::vector;
use 0x2::address;
use 0x2::bag;
use 0x2::balance;
use 0x2::clock;
use 0x2::coin;
use 0x2::hash;
use 0x2::object;
use 0x2::table;
use 0x2::transfer;
use 0x2::tx_context;
use 0x2::url;
use 0xa0::abi;
use 0xa1::bytes32;
use 0xa1::channel;
use 0xa1::gateway;
use 0xa1::message_ticket;
use 0xa5::coin_data;
use 0xa5::coin_info;
use 0xa5::coin_management;
use 0xa5::events;
use 0xa5::interchain_transfer_ticket;
use 0xa5::token_id;
use 0xa5::token_manager_type;
use 0xa5::treasury_cap_reclaimer;
use 0xa5::trusted_chains;
use 0xa5::unregistered_coin_data;
use 0xa5::utils;
use 0xaa::discovery;
use 0xb0::version_control;
InterchainTokenService_v0
struct InterchainTokenService_v0 has store
channel: channel::Channel
trusted_chains: trusted_chains::TrustedChains
unregistered_coin_types: table::Table<token_id::UnregisteredTokenId, type_name::TypeName>
unregistered_coins: bag::Bag
registered_coin_types: table::Table<token_id::TokenId, type_name::TypeName>
registered_coins: bag::Bag
relayer_discovery_id: object::ID
its_hub_address: ascii::String
chain_name_hash: bytes32::Bytes32
version_control: version_control::VersionControl
#[error]
const EOverflow: vector<u8> = b"cannot receive more than 2^64-1 coins";
#[error]
const ECannotDeployInterchainTokenManager: vector<u8> = b"cannot deploy an interchain token token manager type remotely";
#[error]
const ECannotDeployRemotelyToSelf: vector<u8> = b"cannot deploy custom token to this chain remotely, use register_custom_coin instead";
#[error]
const EEmptyTokenAddress: vector<u8> = b"cannot deploy a remote custom token to an empty token address";
#[error]
const EInterchainTransferHasData: vector<u8> = b"interchain transfer with data trying to be processed as an interchain transfer";
#[error]
const EInterchainTransferHasNoData: vector<u8> = b"interchain transfer trying to be proccessed as an interchain transfer";
#[error]
const EInvalidMessageType: vector<u8> = b"the message type received is not supported";
#[error]
const EModuleNameDoesNotMatchSymbol: vector<u8> = b"the module name does not match the symbol";
#[error]
const ENewerTicket: vector<u8> = b"cannot proccess newer tickets";
#[error]
const ENonZeroTotalSupply: vector<u8> = b"trying to give a token that has had some supply already minted";
#[error]
const ENotCannonicalToken: vector<u8> = b"cannot deploy remote interchain token for a custom token";
#[error]
const ENotDistributor: vector<u8> = b"only the distributor can mint";
#[error]
const EUnregisteredCoin: vector<u8> = b"trying to find a coin that doesn't exist";
#[error]
const EUnregisteredCoinHasUrl: vector<u8> = b"the interchain token that is being registered has a URL";
#[error]
const EUntrustedAddress: vector<u8> = b"the sender that sent this message is not trusted";
#[error]
const EUntrustedChain: vector<u8> = b"the chain is not trusted";
#[error]
const EWrongDestination: vector<u8> = b"the channel trying to receive this call is not the destination";
const ITS_HUB_CHAIN_NAME: vector<u8> = [97, 120, 101, 108, 97, 114];
const MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN: u256 = 1;
const MESSAGE_TYPE_INTERCHAIN_TRANSFER: u256 = 0;
const MESSAGE_TYPE_LINK_TOKEN: u256 = 5;
const MESSAGE_TYPE_RECEIVE_FROM_HUB: u256 = 4;
const MESSAGE_TYPE_REGISTER_TOKEN_METADATA: u256 = 6;
const MESSAGE_TYPE_SEND_TO_HUB: u256 = 3;
new
public(friend) fun new(version_control: version_control::VersionControl, chain_name: ascii::String, its_hub_address: ascii::String, ctx: &mut tx_context::TxContext): interchain_token_service_v0::InterchainTokenService_v0
public(package) fun new(
version_control: VersionControl,
chain_name: String,
its_hub_address: String,
ctx: &mut TxContext,
): InterchainTokenService_v0 {
InterchainTokenService_v0 {
channel: axelar_gateway::channel::new(ctx),
trusted_chains: trusted_chains::new(
ctx,
),
registered_coins: bag::new(ctx),
registered_coin_types: table::new(ctx),
unregistered_coins: bag::new(ctx),
unregistered_coin_types: table::new(ctx),
its_hub_address,
chain_name_hash: bytes32::from_bytes(keccak256(&chain_name.into_bytes())),
relayer_discovery_id: object::id_from_address(@0x0),
version_control,
}
}
unregistered_coin_type
public(friend) fun unregistered_coin_type(self: &interchain_token_service_v0::InterchainTokenService_v0, symbol: &ascii::String, decimals: u8): &type_name::TypeName
public(package) fun unregistered_coin_type(self: &InterchainTokenService_v0, symbol: &String, decimals: u8): &TypeName {
let key = token_id::unregistered_token_id(symbol, decimals);
assert!(self.unregistered_coin_types.contains(key), EUnregisteredCoin);
&self.unregistered_coin_types[key]
}
registered_coin_type
public(friend) fun registered_coin_type(self: &interchain_token_service_v0::InterchainTokenService_v0, token_id: token_id::TokenId): &type_name::TypeName
public(package) fun registered_coin_type(self: &InterchainTokenService_v0, token_id: TokenId): &TypeName {
assert!(self.registered_coin_types.contains(token_id), EUnregisteredCoin);
&self.registered_coin_types[token_id]
}
channel_address
public(friend) fun channel_address(self: &interchain_token_service_v0::InterchainTokenService_v0): address
public(package) fun channel_address(self: &InterchainTokenService_v0): address {
self.channel.to_address()
}
set_relayer_discovery_id
public(friend) fun set_relayer_discovery_id(self: &mut interchain_token_service_v0::InterchainTokenService_v0, relayer_discovery: &discovery::RelayerDiscovery)
public(package) fun set_relayer_discovery_id(self: &mut InterchainTokenService_v0, relayer_discovery: &RelayerDiscovery) {
self.relayer_discovery_id = object::id(relayer_discovery);
}
relayer_discovery_id
public(friend) fun relayer_discovery_id(self: &interchain_token_service_v0::InterchainTokenService_v0): object::ID
public(package) fun relayer_discovery_id(self: &InterchainTokenService_v0): ID {
self.relayer_discovery_id
}
add_trusted_chain
public(friend) fun add_trusted_chain(self: &mut interchain_token_service_v0::InterchainTokenService_v0, chain_name: ascii::String)
public(package) fun add_trusted_chain(self: &mut InterchainTokenService_v0, chain_name: String) {
self.trusted_chains.add(chain_name);
}
remove_trusted_chain
public(friend) fun remove_trusted_chain(self: &mut interchain_token_service_v0::InterchainTokenService_v0, chain_name: ascii::String)
public(package) fun remove_trusted_chain(self: &mut InterchainTokenService_v0, chain_name: String) {
self.trusted_chains.remove(chain_name);
}
add_trusted_chains
public(friend) fun add_trusted_chains(self: &mut interchain_token_service_v0::InterchainTokenService_v0, chain_names: vector<ascii::String>)
public(package) fun add_trusted_chains(self: &mut InterchainTokenService_v0, chain_names: vector<String>) {
chain_names.do!(
|chain_name| self.add_trusted_chain(
chain_name,
),
);
}
remove_trusted_chains
public(friend) fun remove_trusted_chains(self: &mut interchain_token_service_v0::InterchainTokenService_v0, chain_names: vector<ascii::String>)
public(package) fun remove_trusted_chains(self: &mut InterchainTokenService_v0, chain_names: vector<String>) {
chain_names.do!(
|chain_name| self.remove_trusted_chain(
chain_name,
),
);
}
channel
public(friend) fun channel(self: &interchain_token_service_v0::InterchainTokenService_v0): &channel::Channel
public(package) fun channel(self: &InterchainTokenService_v0): &Channel {
&self.channel
}
version_control
public(friend) fun version_control(self: &interchain_token_service_v0::InterchainTokenService_v0): &version_control::VersionControl
public(package) fun version_control(self: &InterchainTokenService_v0): &VersionControl {
&self.version_control
}
register_coin
public(friend) fun register_coin<T>(self: &mut interchain_token_service_v0::InterchainTokenService_v0, coin_info: coin_info::CoinInfo<T>, coin_management: coin_management::CoinManagement<T>, has_metadata: bool): token_id::TokenId
public(package) fun register_coin<T>(
self: &mut InterchainTokenService_v0,
coin_info: CoinInfo<T>,
coin_management: CoinManagement<T>,
has_metadata: bool,
): TokenId {
let token_id = token_id::from_coin_data(
&self.chain_name_hash,
&coin_info,
&coin_management,
has_metadata,
);
self.add_registered_coin(token_id, coin_data::new(coin_management, coin_info));
token_id
}
register_coin_from_info
Register a coin using the coin’s name, symbol and decimals.
public(friend) fun register_coin_from_info<T>(self: &mut interchain_token_service_v0::InterchainTokenService_v0, name: string::String, symbol: ascii::String, decimals: u8, coin_management: coin_management::CoinManagement<T>): token_id::TokenId
public(package) fun register_coin_from_info<T>(
self: &mut InterchainTokenService_v0,
name: std::string::String,
symbol: ascii::String,
decimals: u8,
coin_management: CoinManagement<T>,
): TokenId {
let coin_info = coin_info::from_info<T>(name, symbol, decimals);
self.register_coin(coin_info, coin_management, false)
}
register_coin_from_metadata
Register a coin using the coin’s metadata. @see sui::coin::CoinMetadata
public(friend) fun register_coin_from_metadata<T>(self: &mut interchain_token_service_v0::InterchainTokenService_v0, metadata: &coin::CoinMetadata<T>, coin_management: coin_management::CoinManagement<T>): token_id::TokenId
public(package) fun register_coin_from_metadata<T>(
self: &mut InterchainTokenService_v0,
metadata: &CoinMetadata<T>,
coin_management: CoinManagement<T>,
): TokenId {
let coin_info = coin_info::from_metadata_ref<T>(metadata);
self.register_coin(coin_info, coin_management, true)
}
register_custom_coin
public(friend) fun register_custom_coin<T>(self: &mut interchain_token_service_v0::InterchainTokenService_v0, deployer: &channel::Channel, salt: bytes32::Bytes32, coin_metadata: &coin::CoinMetadata<T>, coin_management: coin_management::CoinManagement<T>, ctx: &mut tx_context::TxContext): (token_id::TokenId, option::Option<treasury_cap_reclaimer::TreasuryCapReclaimer<T>>)
public(package) fun register_custom_coin<T>(
self: &mut InterchainTokenService_v0,
deployer: &Channel,
salt: Bytes32,
coin_metadata: &CoinMetadata<T>,
coin_management: CoinManagement<T>,
ctx: &mut TxContext,
): (TokenId, Option<TreasuryCapReclaimer<T>>) {
let token_id = token_id::custom_token_id(&self.chain_name_hash, deployer, &salt);
let coin_info = coin_info::from_info(coin_metadata.get_name(), coin_metadata.get_symbol(), coin_metadata.get_decimals());
events::interchain_token_id_claimed<T>(token_id, deployer, salt);
let treasury_cap_reclaimer = if (coin_management.has_treasury_cap()) {
option::some(treasury_cap_reclaimer::create<T>(token_id, ctx))
} else {
option::none()
};
self.add_registered_coin(token_id, coin_data::new(coin_management, coin_info));
(token_id, treasury_cap_reclaimer)
}
link_coin
public(friend) fun link_coin(self: &interchain_token_service_v0::InterchainTokenService_v0, deployer: &channel::Channel, salt: bytes32::Bytes32, destination_chain: ascii::String, destination_token_address: vector<u8>, token_manager_type: token_manager_type::TokenManagerType, link_params: vector<u8>): message_ticket::MessageTicket
public(package) fun link_coin(
self: &InterchainTokenService_v0,
deployer: &Channel,
salt: Bytes32,
destination_chain: String,
destination_token_address: vector<u8>,
token_manager_type: TokenManagerType,
link_params: vector<u8>,
): MessageTicket {
assert!(destination_token_address.length() != 0, EEmptyTokenAddress);
// Custom token managers can't be deployed with native interchain token type, which is reserved for interchain tokens
assert!(token_manager_type != token_manager_type::native_interchain_token(), ECannotDeployInterchainTokenManager);
// Cannot link token to the origin chain
assert!(self.chain_name_hash != bytes32::from_bytes(keccak256(destination_chain.as_bytes())), ECannotDeployRemotelyToSelf);
let token_id = token_id::custom_token_id(&self.chain_name_hash, deployer, &salt);
// This ensures that the token is registered as a custom token specifically, since the token_id is derived as one
let source_token_address = (*self.registered_coin_type(token_id)).into_string().into_bytes();
let mut writer = abi::new_writer(6);
writer
.write_u256(MESSAGE_TYPE_LINK_TOKEN)
.write_u256(token_id.to_u256())
.write_u256(token_manager_type.to_u256())
.write_bytes(source_token_address)
.write_bytes(destination_token_address)
.write_bytes(link_params);
let payload = writer.into_bytes();
events::link_token_started(
token_id,
destination_chain,
source_token_address,
destination_token_address,
token_manager_type,
link_params,
);
self.prepare_hub_message(payload, destination_chain)
}
register_coin_metadata
public(friend) fun register_coin_metadata<T>(self: &interchain_token_service_v0::InterchainTokenService_v0, coin_metadata: &coin::CoinMetadata<T>): message_ticket::MessageTicket
public(package) fun register_coin_metadata<T>(self: &InterchainTokenService_v0, coin_metadata: &CoinMetadata<T>): MessageTicket {
let decimals = coin_metadata.get_decimals();
let mut writer = abi::new_writer(3);
writer
.write_u256(MESSAGE_TYPE_REGISTER_TOKEN_METADATA)
.write_bytes(type_name::get<T>().into_string().into_bytes())
.write_u8(decimals);
let payload = writer.into_bytes();
events::coin_metadata_registered<T>(decimals);
self.prepare_message(payload)
}
deploy_remote_interchain_token
public(friend) fun deploy_remote_interchain_token<T>(self: &interchain_token_service_v0::InterchainTokenService_v0, token_id: token_id::TokenId, destination_chain: ascii::String): message_ticket::MessageTicket
public(package) fun deploy_remote_interchain_token<T>(
self: &InterchainTokenService_v0,
token_id: TokenId,
destination_chain: String,
): MessageTicket {
let coin_data = self.coin_data<T>(token_id);
let coin_info = coin_data.coin_info();
let coin_management = coin_data.coin_management();
// TODO: fix needing to check both metadata (with / without)
let derived_token_id_without_metadata = token_id::from_coin_data(
&self.chain_name_hash,
coin_info,
coin_management,
false,
);
let derived_token_id_with_metadata = token_id::from_coin_data(
&self.chain_name_hash,
coin_info,
coin_management,
true,
);
assert!((token_id == derived_token_id_without_metadata) || (token_id == derived_token_id_with_metadata), ENotCannonicalToken);
let name = coin_info.name();
let symbol = coin_info.symbol();
let decimals = coin_info.decimals();
let mut writer = abi::new_writer(6);
writer
.write_u256(MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN)
.write_u256(token_id.to_u256())
.write_bytes(*name.as_bytes())
.write_bytes(*symbol.as_bytes())
.write_u256((decimals as u256))
.write_bytes(vector::empty());
events::interchain_token_deployment_started<T>(
token_id,
name,
symbol,
decimals,
destination_chain,
);
let payload = writer.into_bytes();
self.prepare_hub_message(payload, destination_chain)
}
send_interchain_transfer
public(friend) fun send_interchain_transfer<T>(self: &mut interchain_token_service_v0::InterchainTokenService_v0, ticket: interchain_transfer_ticket::InterchainTransferTicket<T>, current_version: u64, clock: &clock::Clock): message_ticket::MessageTicket
public(package) fun send_interchain_transfer<T>(
self: &mut InterchainTokenService_v0,
ticket: InterchainTransferTicket<T>,
current_version: u64,
clock: &Clock,
): MessageTicket {
let (token_id, balance, source_address, destination_chain, destination_address, metadata, version) = ticket.destroy();
assert!(version <= current_version, ENewerTicket);
let amount = self.coin_management_mut(token_id).take_balance(balance, clock);
let (_version, data) = its_utils::decode_metadata(metadata);
let mut writer = abi::new_writer(6);
writer
.write_u256(MESSAGE_TYPE_INTERCHAIN_TRANSFER)
.write_u256(token_id.to_u256())
.write_bytes(source_address.to_bytes())
.write_bytes(destination_address)
.write_u256((amount as u256))
.write_bytes(data);
events::interchain_transfer<T>(
token_id,
source_address,
destination_chain,
destination_address,
amount,
&data,
);
let payload = writer.into_bytes();
self.prepare_hub_message(payload, destination_chain)
}
receive_interchain_transfer
public(friend) fun receive_interchain_transfer<T>(self: &mut interchain_token_service_v0::InterchainTokenService_v0, approved_message: channel::ApprovedMessage, clock: &clock::Clock, ctx: &mut tx_context::TxContext)
public(package) fun receive_interchain_transfer<T>(
self: &mut InterchainTokenService_v0,
approved_message: ApprovedMessage,
clock: &Clock,
ctx: &mut TxContext,
) {
let (source_chain, payload, message_id) = self.decode_approved_message(
approved_message,
);
let mut reader = abi::new_reader(payload);
assert!(reader.read_u256() == MESSAGE_TYPE_INTERCHAIN_TRANSFER, EInvalidMessageType);
let token_id = token_id::from_u256(reader.read_u256());
let source_address = reader.read_bytes();
let destination_address = address::from_bytes(reader.read_bytes());
let amount = read_amount(&mut reader);
let data = reader.read_bytes();
assert!(data.is_empty(), EInterchainTransferHasData);
let coin = self.coin_management_mut(token_id).give_coin<T>(amount, clock, ctx);
transfer::public_transfer(coin, destination_address);
events::interchain_transfer_received<T>(
message_id,
token_id,
source_chain,
source_address,
destination_address,
amount,
&b"",
);
}
receive_interchain_transfer_with_data
public(friend) fun receive_interchain_transfer_with_data<T>(self: &mut interchain_token_service_v0::InterchainTokenService_v0, approved_message: channel::ApprovedMessage, channel: &channel::Channel, clock: &clock::Clock, ctx: &mut tx_context::TxContext): (ascii::String, vector<u8>, vector<u8>, coin::Coin<T>)
public(package) fun receive_interchain_transfer_with_data<T>(
self: &mut InterchainTokenService_v0,
approved_message: ApprovedMessage,
channel: &Channel,
clock: &Clock,
ctx: &mut TxContext,
): (String, vector<u8>, vector<u8>, Coin<T>) {
let (source_chain, payload, message_id) = self.decode_approved_message(
approved_message,
);
let mut reader = abi::new_reader(payload);
assert!(reader.read_u256() == MESSAGE_TYPE_INTERCHAIN_TRANSFER, EInvalidMessageType);
let token_id = token_id::from_u256(reader.read_u256());
let source_address = reader.read_bytes();
let destination_address = address::from_bytes(reader.read_bytes());
let amount = read_amount(&mut reader);
let data = reader.read_bytes();
assert!(destination_address == channel.to_address(), EWrongDestination);
assert!(!data.is_empty(), EInterchainTransferHasNoData);
let coin = self.coin_management_mut(token_id).give_coin(amount, clock, ctx);
events::interchain_transfer_received<T>(
message_id,
token_id,
source_chain,
source_address,
destination_address,
amount,
&data,
);
(source_chain, source_address, data, coin)
}
receive_deploy_interchain_token
public(friend) fun receive_deploy_interchain_token<T>(self: &mut interchain_token_service_v0::InterchainTokenService_v0, approved_message: channel::ApprovedMessage)
public(package) fun receive_deploy_interchain_token<T>(self: &mut InterchainTokenService_v0, approved_message: ApprovedMessage) {
let (_, payload, _) = self.decode_approved_message(approved_message);
let mut reader = abi::new_reader(payload);
assert!(reader.read_u256() == MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN, EInvalidMessageType);
let token_id = token_id::from_u256(reader.read_u256());
let name = string::utf8(reader.read_bytes());
let symbol = ascii::string(reader.read_bytes());
let decimals = (reader.read_u256() as u8);
let distributor_bytes = reader.read_bytes();
let (treasury_cap, mut coin_metadata) = self.remove_unregistered_coin<T>(
token_id::unregistered_token_id(&symbol, decimals),
);
treasury_cap.update_name(&mut coin_metadata, name);
let mut coin_management = coin_management::new_with_cap<T>(treasury_cap);
let coin_info = coin_info::from_metadata<T>(coin_metadata);
if (distributor_bytes.length() > 0) {
let distributor = address::from_bytes(distributor_bytes);
coin_management.add_distributor(distributor);
};
self.add_registered_coin<T>(token_id, coin_data::new(coin_management, coin_info));
}
receive_link_coin
public(friend) fun receive_link_coin<T>(self: &mut interchain_token_service_v0::InterchainTokenService_v0, approved_message: channel::ApprovedMessage)
public(package) fun receive_link_coin<T>(self: &mut InterchainTokenService_v0, approved_message: ApprovedMessage) {
let (source_chain, payload, _) = self.decode_approved_message(approved_message);
let mut reader = abi::new_reader(payload);
assert!(reader.read_u256() == MESSAGE_TYPE_LINK_TOKEN, EInvalidMessageType);
let token_id = token_id::from_u256(reader.read_u256());
let token_manager_type = reader.read_u256();
let source_token_address = reader.read_bytes();
let destination_token_address = reader.read_bytes();
let link_params = reader.read_bytes();
assert!(destination_token_address == type_name::get<T>().into_string().into_bytes());
let token_manager_type = token_manager_type::from_u256(token_manager_type);
// This implicitly validates token_manager_type because we only ever register lock_unlock and mint_burn unlinked coins
let mut coin_data = self.remove_unlinked_coin<T>(
token_id::unlinked_token_id<T>(token_id, token_manager_type),
);
if (link_params.length() > 0) {
let operator = address::from_bytes(link_params);
coin_data.coin_management_mut().add_operator(operator);
};
events::link_token_received<T>(token_id, source_chain, source_token_address, token_manager_type, link_params);
self.add_registered_coin<T>(token_id, coin_data);
}
give_unregistered_coin
public(friend) fun give_unregistered_coin<T>(self: &mut interchain_token_service_v0::InterchainTokenService_v0, treasury_cap: coin::TreasuryCap<T>, coin_metadata: coin::CoinMetadata<T>)
public(package) fun give_unregistered_coin<T>(
self: &mut InterchainTokenService_v0,
treasury_cap: TreasuryCap<T>,
mut coin_metadata: CoinMetadata<T>,
) {
assert!(treasury_cap.total_supply() == 0, ENonZeroTotalSupply);
assert!(coin::get_icon_url(&coin_metadata).is_none(), EUnregisteredCoinHasUrl);
treasury_cap.update_description(&mut coin_metadata, string::utf8(b""));
let decimals = coin_metadata.get_decimals();
let symbol = coin_metadata.get_symbol();
let module_name = type_name::get_module(&type_name::get<T>());
assert!(&module_name == &its_utils::module_from_symbol(&symbol), EModuleNameDoesNotMatchSymbol);
let token_id = token_id::unregistered_token_id(&symbol, decimals);
self.add_unregistered_coin<T>(token_id, treasury_cap, coin_metadata);
events::unregistered_coin_received<T>(
token_id,
symbol,
decimals,
);
}
give_unlinked_coin
public(friend) fun give_unlinked_coin<T>(self: &mut interchain_token_service_v0::InterchainTokenService_v0, token_id: token_id::TokenId, coin_metadata: &coin::CoinMetadata<T>, treasury_cap: option::Option<coin::TreasuryCap<T>>, ctx: &mut tx_context::TxContext): option::Option<treasury_cap_reclaimer::TreasuryCapReclaimer<T>>
public(package) fun give_unlinked_coin<T>(
self: &mut InterchainTokenService_v0,
token_id: TokenId,
coin_metadata: &CoinMetadata<T>,
treasury_cap: Option<TreasuryCap<T>>,
ctx: &mut TxContext,
): Option<TreasuryCapReclaimer<T>> {
let token_manager_type = if (treasury_cap.is_some()) {
token_manager_type::mint_burn()
} else {
token_manager_type::lock_unlock()
};
let unlinked_token_id = token_id::unlinked_token_id<T>(token_id, token_manager_type);
events::unlinked_coin_received<T>(unlinked_token_id, token_id, token_manager_type);
self.add_unlinked_coin(unlinked_token_id, coin_metadata, treasury_cap);
if (token_manager_type == token_manager_type::mint_burn()) {
option::some(treasury_cap_reclaimer::create<T>(token_id, ctx))
} else {
option::none()
}
}
mint_as_distributor
public(friend) fun mint_as_distributor<T>(self: &mut interchain_token_service_v0::InterchainTokenService_v0, channel: &channel::Channel, token_id: token_id::TokenId, amount: u64, ctx: &mut tx_context::TxContext): coin::Coin<T>
public(package) fun mint_as_distributor<T>(
self: &mut InterchainTokenService_v0,
channel: &Channel,
token_id: TokenId,
amount: u64,
ctx: &mut TxContext,
): Coin<T> {
let coin_management = self.coin_management_mut<T>(token_id);
let distributor = channel.to_address();
assert!(coin_management.is_distributor(distributor), ENotDistributor);
coin_management.mint(amount, ctx)
}
mint_to_as_distributor
public(friend) fun mint_to_as_distributor<T>(self: &mut interchain_token_service_v0::InterchainTokenService_v0, channel: &channel::Channel, token_id: token_id::TokenId, to: address, amount: u64, ctx: &mut tx_context::TxContext)
public(package) fun mint_to_as_distributor<T>(
self: &mut InterchainTokenService_v0,
channel: &Channel,
token_id: TokenId,
to: address,
amount: u64,
ctx: &mut TxContext,
) {
let coin_management = self.coin_management_mut<T>(token_id);
let distributor = channel.to_address();
assert!(coin_management.is_distributor(distributor), ENotDistributor);
let coin = coin_management.mint(amount, ctx);
transfer::public_transfer(coin, to);
}
burn_as_distributor
public(friend) fun burn_as_distributor<T>(self: &mut interchain_token_service_v0::InterchainTokenService_v0, channel: &channel::Channel, token_id: token_id::TokenId, coin: coin::Coin<T>)
public(package) fun burn_as_distributor<T>(self: &mut InterchainTokenService_v0, channel: &Channel, token_id: TokenId, coin: Coin<T>) {
let coin_management = self.coin_management_mut<T>(token_id);
let distributor = channel.to_address();
assert!(coin_management.is_distributor<T>(distributor), ENotDistributor);
coin_management.burn(coin.into_balance());
}
set_flow_limit_as_token_operator
public(friend) fun set_flow_limit_as_token_operator<T>(self: &mut interchain_token_service_v0::InterchainTokenService_v0, channel: &channel::Channel, token_id: token_id::TokenId, limit: option::Option<u64>)
public(package) fun set_flow_limit_as_token_operator<T>(
self: &mut InterchainTokenService_v0,
channel: &Channel,
token_id: TokenId,
limit: Option<u64>,
) {
self.coin_management_mut<T>(token_id).set_flow_limit(channel, limit);
events::flow_limit_set<T>(token_id, limit);
}
set_flow_limit
public(friend) fun set_flow_limit<T>(self: &mut interchain_token_service_v0::InterchainTokenService_v0, token_id: token_id::TokenId, limit: option::Option<u64>)
public(package) fun set_flow_limit<T>(self: &mut InterchainTokenService_v0, token_id: TokenId, limit: Option<u64>) {
self.coin_management_mut<T>(token_id).set_flow_limit_internal(limit);
events::flow_limit_set<T>(token_id, limit);
}
transfer_distributorship
public(friend) fun transfer_distributorship<T>(self: &mut interchain_token_service_v0::InterchainTokenService_v0, channel: &channel::Channel, token_id: token_id::TokenId, new_distributor: option::Option<address>)
public(package) fun transfer_distributorship<T>(
self: &mut InterchainTokenService_v0,
channel: &Channel,
token_id: TokenId,
new_distributor: Option<address>,
) {
let coin_management = self.coin_management_mut<T>(token_id);
let distributor = channel.to_address();
assert!(coin_management.is_distributor<T>(distributor), ENotDistributor);
coin_management.update_distributorship(new_distributor);
events::distributorship_transfered<T>(token_id, new_distributor);
}
transfer_operatorship
public(friend) fun transfer_operatorship<T>(self: &mut interchain_token_service_v0::InterchainTokenService_v0, channel: &channel::Channel, token_id: token_id::TokenId, new_operator: option::Option<address>)
public(package) fun transfer_operatorship<T>(
self: &mut InterchainTokenService_v0,
channel: &Channel,
token_id: TokenId,
new_operator: Option<address>,
) {
let coin_management = self.coin_management_mut<T>(token_id);
coin_management.update_operatorship<T>(channel, new_operator);
events::operatorship_transfered<T>(token_id, new_operator);
}
remove_treasury_cap
public(friend) fun remove_treasury_cap<T>(self: &mut interchain_token_service_v0::InterchainTokenService_v0, treasury_cap_reclaimer: treasury_cap_reclaimer::TreasuryCapReclaimer<T>): coin::TreasuryCap<T>
public(package) fun remove_treasury_cap<T>(
self: &mut InterchainTokenService_v0,
treasury_cap_reclaimer: TreasuryCapReclaimer<T>,
): TreasuryCap<T> {
let coin_management = self.coin_management_mut<T>(treasury_cap_reclaimer.token_id());
treasury_cap_reclaimer.destroy();
coin_management.remove_cap()
}
restore_treasury_cap
public(friend) fun restore_treasury_cap<T>(self: &mut interchain_token_service_v0::InterchainTokenService_v0, treasury_cap: coin::TreasuryCap<T>, token_id: token_id::TokenId, ctx: &mut tx_context::TxContext): treasury_cap_reclaimer::TreasuryCapReclaimer<T>
public(package) fun restore_treasury_cap<T>(
self: &mut InterchainTokenService_v0,
treasury_cap: TreasuryCap<T>,
token_id: TokenId,
ctx: &mut TxContext,
): TreasuryCapReclaimer<T> {
let coin_management = self.coin_management_mut<T>(token_id);
coin_management.restore_cap(treasury_cap);
treasury_cap_reclaimer::create<T>(token_id, ctx)
}
allow_function
public(friend) fun allow_function(self: &mut interchain_token_service_v0::InterchainTokenService_v0, version: u64, function_name: ascii::String)
public(package) fun allow_function(self: &mut InterchainTokenService_v0, version: u64, function_name: String) {
self.version_control.allow_function(version, function_name);
}
disallow_function
public(friend) fun disallow_function(self: &mut interchain_token_service_v0::InterchainTokenService_v0, version: u64, function_name: ascii::String)
public(package) fun disallow_function(self: &mut InterchainTokenService_v0, version: u64, function_name: String) {
self.version_control.disallow_function(version, function_name);
}
coin_data
public(friend) fun coin_data<T>(self: &interchain_token_service_v0::InterchainTokenService_v0, token_id: token_id::TokenId): &coin_data::CoinData<T>
public(package) fun coin_data<T>(self: &InterchainTokenService_v0, token_id: TokenId): &CoinData<T> {
assert!(self.registered_coins.contains(token_id), EUnregisteredCoin);
&self.registered_coins[token_id]
}
migrate_coin_metadata
public(friend) fun migrate_coin_metadata<T>(self: &mut interchain_token_service_v0::InterchainTokenService_v0, token_id: address)
public(package) fun migrate_coin_metadata<T>(self: &mut InterchainTokenService_v0, token_id: address) {
let token_id = token_id::from_address(token_id);
let coin_info = self.coin_data_mut<T>(token_id).coin_info_mut();
coin_info.release_metadata();
}
is_trusted_chain
fun is_trusted_chain(self: &interchain_token_service_v0::InterchainTokenService_v0, source_chain: ascii::String): bool
fun is_trusted_chain(self: &InterchainTokenService_v0, source_chain: String): bool {
self.trusted_chains.is_trusted(source_chain)
}
coin_management_mut
fun coin_management_mut<T>(self: &mut interchain_token_service_v0::InterchainTokenService_v0, token_id: token_id::TokenId): &mut coin_management::CoinManagement<T>
fun coin_management_mut<T>(self: &mut InterchainTokenService_v0, token_id: TokenId): &mut CoinManagement<T> {
let coin_data: &mut CoinData<T> = &mut self.registered_coins[token_id];
coin_data.coin_management_mut()
}
add_unregistered_coin
fun add_unregistered_coin<T>(self: &mut interchain_token_service_v0::InterchainTokenService_v0, token_id: token_id::UnregisteredTokenId, treasury_cap: coin::TreasuryCap<T>, coin_metadata: coin::CoinMetadata<T>)
fun add_unregistered_coin<T>(
self: &mut InterchainTokenService_v0,
token_id: UnregisteredTokenId,
treasury_cap: TreasuryCap<T>,
coin_metadata: CoinMetadata<T>,
) {
self
.unregistered_coins
.add(
token_id,
unregistered_coin_data::new(
treasury_cap,
coin_metadata,
),
);
let type_name = type_name::get<T>();
add_unregistered_coin_type(self, token_id, type_name);
}
add_unlinked_coin
fun add_unlinked_coin<T>(self: &mut interchain_token_service_v0::InterchainTokenService_v0, token_id: token_id::UnlinkedTokenId, coin_metadata: &coin::CoinMetadata<T>, treasury_cap: option::Option<coin::TreasuryCap<T>>)
fun add_unlinked_coin<T>(
self: &mut InterchainTokenService_v0,
token_id: UnlinkedTokenId,
coin_metadata: &CoinMetadata<T>,
treasury_cap: Option<TreasuryCap<T>>,
) {
let coin_info = coin_info::from_info<T>(coin_metadata.get_name(), coin_metadata.get_symbol(), coin_metadata.get_decimals());
let coin_management = if (treasury_cap.is_some()) {
coin_management::new_with_cap(treasury_cap.destroy_some())
} else {
treasury_cap.destroy_none();
coin_management::new_locked<T>()
};
let coin_data = coin_data::new(coin_management, coin_info);
// Use the same bag for this to not alter storage.
// Since there should not be any collisions to the token ids because different prefixes are used this will not be a problem.
// TODO: When doing a storage upgrade, move this to a separate Bag for clarity
self
.unregistered_coins
.add(
token_id,
coin_data,
);
}
remove_unlinked_coin
fun remove_unlinked_coin<T>(self: &mut interchain_token_service_v0::InterchainTokenService_v0, token_id: token_id::UnlinkedTokenId): coin_data::CoinData<T>
fun remove_unlinked_coin<T>(self: &mut InterchainTokenService_v0, token_id: UnlinkedTokenId): CoinData<T> {
self.unregistered_coins.remove(token_id)
}
remove_unregistered_coin
fun remove_unregistered_coin<T>(self: &mut interchain_token_service_v0::InterchainTokenService_v0, token_id: token_id::UnregisteredTokenId): (coin::TreasuryCap<T>, coin::CoinMetadata<T>)
fun remove_unregistered_coin<T>(
self: &mut InterchainTokenService_v0,
token_id: UnregisteredTokenId,
): (TreasuryCap<T>, CoinMetadata<T>) {
let unregistered_coins: UnregisteredCoinData<T> = self.unregistered_coins.remove(token_id);
let (treasury_cap, coin_metadata) = unregistered_coins.destroy();
remove_unregistered_coin_type(self, token_id);
(treasury_cap, coin_metadata)
}
add_unregistered_coin_type
fun add_unregistered_coin_type(self: &mut interchain_token_service_v0::InterchainTokenService_v0, token_id: token_id::UnregisteredTokenId, type_name: type_name::TypeName)
fun add_unregistered_coin_type(self: &mut InterchainTokenService_v0, token_id: UnregisteredTokenId, type_name: TypeName) {
self.unregistered_coin_types.add(token_id, type_name);
}
remove_unregistered_coin_type
fun remove_unregistered_coin_type(self: &mut interchain_token_service_v0::InterchainTokenService_v0, token_id: token_id::UnregisteredTokenId): type_name::TypeName
fun remove_unregistered_coin_type(self: &mut InterchainTokenService_v0, token_id: UnregisteredTokenId): TypeName {
self.unregistered_coin_types.remove(token_id)
}
add_registered_coin_type
fun add_registered_coin_type(self: &mut interchain_token_service_v0::InterchainTokenService_v0, token_id: token_id::TokenId, type_name: type_name::TypeName)
fun add_registered_coin_type(self: &mut InterchainTokenService_v0, token_id: TokenId, type_name: TypeName) {
self.registered_coin_types.add(token_id, type_name);
}
add_registered_coin
fun add_registered_coin<T>(self: &mut interchain_token_service_v0::InterchainTokenService_v0, token_id: token_id::TokenId, coin_data: coin_data::CoinData<T>)
fun add_registered_coin<T>(self: &mut InterchainTokenService_v0, token_id: TokenId, coin_data: CoinData<T>) {
self
.registered_coins
.add(
token_id,
coin_data,
);
let type_name = type_name::get<T>();
add_registered_coin_type(self, token_id, type_name);
events::coin_registered<T>(
token_id,
);
}
prepare_hub_message
fun prepare_hub_message(self: &interchain_token_service_v0::InterchainTokenService_v0, payload: vector<u8>, destination_chain: ascii::String): message_ticket::MessageTicket
fun prepare_hub_message(self: &InterchainTokenService_v0, mut payload: vector<u8>, destination_chain: String): MessageTicket {
assert!(self.is_trusted_chain(destination_chain), EUntrustedChain);
let mut writer = abi::new_writer(3);
writer.write_u256(MESSAGE_TYPE_SEND_TO_HUB);
writer.write_bytes(destination_chain.into_bytes());
writer.write_bytes(payload);
payload = writer.into_bytes();
self.prepare_message(payload)
}
prepare_message
Send a payload to a destination chain. The destination chain needs to have a trusted address.
fun prepare_message(self: &interchain_token_service_v0::InterchainTokenService_v0, payload: vector<u8>): message_ticket::MessageTicket
fun prepare_message(self: &InterchainTokenService_v0, payload: vector<u8>): MessageTicket {
gateway::prepare_message(
&self.channel,
ITS_HUB_CHAIN_NAME.to_ascii_string(),
self.its_hub_address,
payload,
)
}
decode_approved_message
Decode an approved call and check that the source chain is trusted.
fun decode_approved_message(self: &interchain_token_service_v0::InterchainTokenService_v0, approved_message: channel::ApprovedMessage): (ascii::String, vector<u8>, ascii::String)
fun decode_approved_message(self: &InterchainTokenService_v0, approved_message: ApprovedMessage): (String, vector<u8>, String) {
let (source_chain, message_id, source_address, payload) = self.channel.consume_approved_message(approved_message);
assert!(source_chain.into_bytes() == ITS_HUB_CHAIN_NAME, EUntrustedChain);
assert!(source_address == self.its_hub_address, EUntrustedAddress);
let mut reader = abi::new_reader(payload);
assert!(reader.read_u256() == MESSAGE_TYPE_RECEIVE_FROM_HUB, EInvalidMessageType);
let source_chain = ascii::string(reader.read_bytes());
let payload = reader.read_bytes();
assert!(self.is_trusted_chain(source_chain), EUntrustedChain);
(source_chain, payload, message_id)
}
read_amount
fun read_amount(reader: &mut abi::AbiReader): u64
fun read_amount(reader: &mut AbiReader): u64 {
let amount = std::macros::try_as_u64!(reader.read_u256());
assert!(amount.is_some(), EOverflow);
amount.destroy_some()
}
coin_data_mut
fun coin_data_mut<T>(self: &mut interchain_token_service_v0::InterchainTokenService_v0, token_id: token_id::TokenId): &mut coin_data::CoinData<T>
fun coin_data_mut<T>(self: &mut InterchainTokenService_v0, token_id: TokenId): &mut CoinData<T> {
assert!(self.registered_coins.contains(token_id), EUnregisteredCoin);
&mut self.registered_coins[token_id]
}