1

Please explain why the following occurs

When this method is called, the tokens are equally divided and distributed to the user. (as expected)

All user balances get updated with the new amounts.

#[ink(message, payable)]
pub fn distribute_tokens(&mut self, to: Vec<AccountId>) -> Result<(), PSP22Error> {
    let total_transfer_amount = self.env().transferred_balance();

    // Calculate the amount to be sent to each recipient.
    let individual_amount = total_transfer_amount / to.len() as Balance;

    // Transfer tokens to each recipient.
    for recipient in to {
        // This will panic if the transfer fails.
        self.env().transfer(recipient, individual_amount).unwrap_or_default();
    }

    Ok(())
}

When I try to do something like this where the user has the option to specify the amount for each recipient, The transaction also succeeds. The balance of the caller (the one distributing the tokens) gets updated with the amount sent as deducted.

The problem occurs here : The receivers balances remain unchanged. I'm assuming the amount sent from the distributor gets to the contract and stays there without it distributing any of the tokens. Any insight would be appreciated!

#[ink(message, payable)]
pub fn distribute_tokens(&mut self, recipients: StorageVec<AccountId>, amounts: StorageVec<Balance>) {
    assert!(recipients.len() == amounts.len(), "Recipients and amounts vectors must be of the same length.");

    let transferred_amount: Balance = self.env().transferred_value();

    // Ensure the transferred amount matches the total of the amounts vector.
    let total_amounts: Balance = amounts.iter().sum();
    assert!(transferred_amount >= total_amounts, "Transferred amount does not match total of amounts vector.");

    for (recipient, amount) in recipients.iter().zip(amounts.iter()) {
    self.env().transfer(*recipient, *amount).unwrap_or_else(|err: InkEnvError| panic!("transfer failed: {:?}", err));
}


}

The transfer fail exception does not get thrown.

Note: StorageVec is an alias for Vec

2 Answers 2

1

The reason why the receivers' balances remain unchanged in the second function is because the env().transfer() function does not actually transfer the tokens. Instead, it simply checks if the transfer would be successful and returns an error if it would not be.

In the second function, the assert! statement ensures that the transferred amount is at least as much as the total of the amounts vector. However, this does not guarantee that the transfer will actually be successful. For example, if one of the recipients' accounts is not yet initialized, the transfer will fail.

The unwrap_or_else statement in the second function will only panic if the env().transfer() function returns an error. However, if the transfer fails because one of the recipients' accounts is not yet initialized, the env().transfer() function will not return an error. Instead, it will simply return None.

To fix this, you need to check the return value of the env().transfer() function and panic if it is None. You can do this by using the following code:

for (recipient, amount) in recipients.iter().zip(amounts.iter()) {
    let result = self.env().transfer(*recipient, *amount);
    if result.is_none() {
        panic!("Transfer to {} failed", recipient);
    }
}

This code will panic if any of the transfers fail. This will ensure that the receivers' balances are always updated correctly.

Here is a complete example of the second function with the fix:

#[ink(message, payable)]
pub fn distribute_tokens(&mut self, recipients: StorageVec<AccountId>, amounts: StorageVec<Balance>) {
    assert!(recipients.len() == amounts.len(), "Recipients and amounts vectors must be of the same length.");

    let transferred_amount: Balance = self.env().transferred_value();

    // Ensure the transferred amount matches the total of the amounts vector.
    let total_amounts: Balance = amounts.iter().sum();
    assert!(transferred_amount >= total_amounts, "Transferred amount does not match total of amounts vector.");

    for (recipient, amount) in recipients.iter().zip(amounts.iter()) {
        let result = self.env().transfer(*recipient, *amount);
        if result.is_none() {
            panic!("Transfer to {} failed", recipient);
        }
    }
}

I hope this helps!

0
0

Resolved the issue by specifying larger amounts to send. I was not factoring in the 12 decimals of the token. So technically everything was working fine. The issue was that I was sending amounts so small that it would not even reflect in the recievers balance.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.