/// This is the only operation that changes the state of the canister blocks and
/// balances after init. This creates a payment from the caller's account. It
/// returns the index of the resulting transaction
///
/// # Arguments
///
/// * `memo` -  A 8 byte "message" you can attach to transactions to help the
///   receiver disambiguate transactions.
/// * `amount` - The number of Tokens the recipient gets. The number of Tokens
///   withdrawn is equal to the amount + the fee.
/// * `fee` - The maximum fee that the sender is willing to pay. If the required
///   fee is greater than this the transaction will be rejected otherwise the
///   required fee will be paid. TODO(ROSETTA1-45): automatically pay a lower
///   fee if possible.
/// * `from_subaccount` - The subaccount you want to draw funds from.
/// * `to` - The account you want to send the funds to.
/// * `created_at_time`: When the transaction has been created. If not set then
///   now is used.
This is the only operation that changes the state of the canister blocks and
balances after init. This creates a payment from the caller's account. It
returns the index of the resulting transaction
This is the only operation that changes the state of the canister blocks and balances after init . This creates a payment from the caller ' s account . It returns the index of the resulting transaction
async fn send(
    memo: Memo,
    amount: Tokens,
    fee: Tokens,
    from_subaccount: Option<Subaccount>,
    to: AccountIdentifier,
    created_at_time: Option<TimeStamp>,
) -> Result<BlockHeight, TransferError> {
    let caller_principal_id = caller();
    if !LEDGER.read().unwrap().can_send(&caller_principal_id) {
        panic!("Sending from {} is not allowed", caller_principal_id);
    }
    let from = AccountIdentifier::new(caller_principal_id, from_subaccount);
    let minting_acc = LEDGER
        .read()
        .unwrap()
        .minting_account_id
        .expect("Minting canister id not initialized");
    let transfer = if from == minting_acc {
        assert_eq!(fee, Tokens::ZERO, "Fee for minting should be zero");
        assert_ne!(
            to, minting_acc,
            "It is illegal to mint to a minting_account"
        );
        Operation::Mint { to, amount }
    } else if to == minting_acc {
        assert_eq!(fee, Tokens::ZERO, "Fee for burning should be zero");
        if amount < MIN_BURN_AMOUNT {
            panic!("Burns lower than {} are not allowed", MIN_BURN_AMOUNT);
        }
        Operation::Burn { from, amount }
    } else {
        if fee != TRANSACTION_FEE {
            return Err(TransferError::BadFee {
                expected_fee: TRANSACTION_FEE,
            });
        }
        Operation::Transfer {
            from,
            to,
            amount,
            fee,
        }
    };
    let (height, hash) = match LEDGER
        .write()
        .unwrap()
        .add_payment(memo, transfer, created_at_time)
    {
        Ok((height, hash)) => (height, hash),
        Err(PaymentError::TransferError(transfer_error)) => return Err(transfer_error),
        Err(PaymentError::Reject(msg)) => panic!("{}", msg),
    };
    set_certified_data(&hash.into_bytes());
    // Don't put anything that could ever trap after this call or people using this
    // endpoint. If something did panic the payment would appear to fail, but would
    // actually succeed on chain.
    archive_blocks().await;
    Ok(height)
}
async fn send ( memo : Memo , amount : Tokens , fee : Tokens , from_subaccount : Option < Subaccount > , to : AccountIdentifier , created_at_time : Option < TimeStamp > , ) -> Result < BlockHeight , TransferError > { let caller_principal_id = caller ( ) ; if ! LEDGER . read ( ) . unwrap ( ) . can_send ( & caller_principal_id ) { panic ! ( " " caller_principal_id ) ; } let from = AccountIdentifier :: new ( caller_principal_id , from_subaccount ) ; let minting_acc = LEDGER . read ( ) . unwrap ( ) . minting_account_id . expect ( " " ) ; let transfer = if from == minting_acc { assert_eq ! ( fee Tokens ZERO " " ) ; assert_ne ! ( to minting_acc " " ) ; Operation :: Mint { to , amount } } else if to == minting_acc { assert_eq ! ( fee Tokens ZERO " " ) ; if amount < MIN_BURN_AMOUNT { panic ! ( " " MIN_BURN_AMOUNT ) ; } Operation :: Burn { from , amount } } else { if fee != TRANSACTION_FEE { return Err ( TransferError :: BadFee { expected_fee : TRANSACTION_FEE , } ) ; } Operation :: Transfer { from , to , amount , fee , } } ; let ( height , hash ) = match LEDGER . write ( ) . unwrap ( ) . add_payment ( memo , transfer , created_at_time ) { Ok ( ( height , hash ) ) => ( height , hash ) , Err ( PaymentError :: TransferError ( transfer_error ) ) => return Err ( transfer_error ) , Err ( PaymentError :: Reject ( msg ) ) => panic ! ( " " msg ) , } ; set_certified_data ( & hash . into_bytes ( ) ) ; // Don't put anything that could ever trap after this call or people using this // endpoint. If something did panic the payment would appear to fail, but would // actually succeed on chain. archive_blocks ( ) . await ; Ok ( height ) }
This is the only operation that changes the state of the canister blocks and
balances after init.
This is the only operation that changes the state of the canister blocks and balances after init .
memo
Memo
amount
Tokens
fee
Tokens
from_subaccount
Option<Subaccount>
to
AccountIdentifier
created_at_time
Option<TimeStamp>