Self-sponsoring Shimmer Assets Claiming
In the case in which an address owns some assets but no IOTA coins, the self-sponsorship can be of help for claiming those coins. Sponsoring a transaction means having an IOTA address (i.e., the sponsor) to pay the transaction gas fees for another address (i.e., the user). In the case of a claim a sponsor can pay for the claiming transaction gas.
This is useful for Shimmer assets, because none of the Move objects obtained from migrating the Shimmer Stardust Outputs contain any IOTA coin. It means that addresses owning these Objects have no IOTA coins to pay for gas.
Claim of a Shimmer Basic Output with self-sponsorship
- A Shimmer derivation path uses a
coin_type
(4219) which is different from the IOTA's one (4218). A user's self-sponsoring address could be then found using the IOTAcoin_type
.
- Rust
- TypeScript
// For this example we need to derive addresses that are not at different
// indexes and coin_types, one for sponsoring with IOTA coin type and one for
// claiming the Basic Output with Shimmer coin type.
let sponsor_derivation_path =
DerivationPath::from_str(format!("m/44'/{IOTA_COIN_TYPE}'/0'/0'/5'").as_str())?;
let sender_derivation_path =
DerivationPath::from_str(format!("m/44'/{SHIMMER_COIN_TYPE}'/0'/0'/50'").as_str())?;
TODO
- A PTB for claiming a
BasicOutput
owned by the derived Shimmer address can be created similarly to what is shown in Basic Output.
- Rust
- TypeScript
let basic_output_object_ref = basic_output_object.object_ref();
// Create a PTB to for claiming the assets of a basic output for the sender
let pt = {
// Init the builder
let mut builder = ProgrammableTransactionBuilder::new();
////// Command #1: extract the base token and native tokens bag.
// Type argument for a Basic Output coming from the Shimmer network, i.e., the
// SMR coin
let type_arguments = vec![SMR::type_tag()];
// Then pass the basic output object as input
let arguments = vec![builder.obj(ObjectArg::ImmOrOwnedObject(basic_output_object_ref))?];
// Finally call the basic_output::extract_assets function
if let Argument::Result(extracted_assets) = builder.programmable_move_call(
STARDUST_ADDRESS.into(),
ident_str!("basic_output").to_owned(),
ident_str!("extract_assets").to_owned(),
type_arguments,
arguments,
) {
// If the basic output can be unlocked, the command will be succesful and will
// return a `base_token` (i.e., SMR) balance and a `Bag` of native tokens
let extracted_base_token = Argument::NestedResult(extracted_assets, 0);
let extracted_native_tokens_bag = Argument::NestedResult(extracted_assets, 1);
////// Command #2: delete the empty native tokens bag
let arguments = vec![extracted_native_tokens_bag];
builder.programmable_move_call(
IOTA_FRAMEWORK_ADDRESS.into(),
ident_str!("bag").to_owned(),
ident_str!("destroy_empty").to_owned(),
vec![],
arguments,
);
////// Command #3: create a coin from the extracted SMR balance
// Type argument for the SMR coin
let type_arguments = vec![SMR::type_tag()];
let arguments = vec![extracted_base_token];
let new_iota_coin = builder.programmable_move_call(
IOTA_FRAMEWORK_ADDRESS.into(),
ident_str!("coin").to_owned(),
ident_str!("from_balance").to_owned(),
type_arguments,
arguments,
);
////// Command #5: send back the base token coin to the user.
builder.transfer_arg(sender, new_iota_coin)
}
TODO
- In this case, the transaction must be signed by both the sender address (i.e., the objects' owner) and the sponsor address.
- Rust
- TypeScript
.ok_or(anyhow!("No coins found for sponsor"))?;
// Create the transaction data that will be sent to the network and allow
// sponsoring
let tx_data = TransactionData::new_programmable_allow_sponsor(
sender,
vec![gas_coin.object_ref()],
pt,
gas_budget,
gas_price,
sponsor,
);
// Sender signs the transaction
let sender_signature = keystore.sign_secure(&sender, &tx_data, Intent::iota_transaction())?;
// Sponsor signs the transaction
let sponsor_signature = keystore.sign_secure(&sponsor, &tx_data, Intent::iota_transaction())?;
// Execute transaction; the transaction data is created using the signature of
// the sender and of the sponsor.
let transaction_response = iota_client
.quorum_driver_api()
.execute_transaction_block(
Transaction::from_data(tx_data, vec![sender_signature, sponsor_signature]),
IotaTransactionBlockResponseOptions::full_content(),
Some(ExecuteTransactionRequestType::WaitForLocalExecution),
TODO