Logic eval error: underflow on subtracting 1 from sender amount 0

Hi everybody.
I’m facing an issue that i try to explain, hope for some help!
I’ve written an ABI-compiant smart contract that i registered as the clawback of a nft, and which exposes a method to transfer the nft from the sender of the app call to a receiver (both included in the addressArray of the app call): after some check, in the TEAL i build an inner transaction of type ‘axfer’ from the sender (i’m sure they have the nft in its asa balance) to a receiver (i’m sure also about the opting into the nft), and i’m also sure about the fact that the SC can do the transfer because of its clawback role. So, in this scenary, in some random cases the app call failes with the message in the title: “Logic eval error: underflow on subtracting 1 from sender amount 0” : it seems that the SC could not perform the axfer inner txn because it isn’t able to ‘see’ that the sender does own the nft! But, as i’ve said, if i try to execute the same app call after a few seconds, in some random cases it works well, the clawback transfers the nft as expected. So, what could be the problem? It seems there is a gap in the synchronization!
I’m working on Testnet, in a java-based Spring web application (with the last version of the algorand-java-sdk 2.3.0 in my pom dependencies), connection based on PureStake service.

Thanks for any suggestions and help!

Indeed, it could be the case that the transaction is not immediately added to a block after correctly sending it to the network.
I assume you have some setup / prelude to your SC call. Do you wait for confirmation on all transactions before the SC call?

Yes, actually i’m used to verify via AlgoExplorer who’s the actual owner of the nft before the app call to transfer it. And, in the SC itself i’ve written some subroutine called before the inner transaction to verify all conditions before transferring the nft (i.e. the app caller has to be the owner of at least 1 amount of the nft (obviously, as an nft, it has 0 decimals and 1 unit), the receiver has to have already opted into the nft…). And finally, the app call fails obviously if one of those conditions fails, so it returns 0 before starting building the inner trasfer.
So, the problem is: all the controls in the subroutines pass well, but the inner transaction doesn’t, giving the error “Logic eval error: underflow on subtracting 1 from sender amount 0”. If i try to submit the same app call after some minutes, it works well, the SC returns 1, the inner txn goes on and get submitted as expected.
Hope it’s all clear :slight_smile:

Would you be able to (privately) share your source code or debug live this issue? The problem seems to be dependent on the state of the chain rather than just the logic in your code.

If not, I have a general suggestion which may or may not help with your situation.

If your logic allows it, I often prefer to just go ahead with my transaction. If you check the sender’s balance and it doesn’t have sufficient NFT/funds then the logic has to reject the transaction. If you just submit your desired inner transaction and the ledger rejects it (insufficient balance, ecc…), then the app call fails anyway. If external conditions don’t influence when/how to run an inner transaction, just send it and let the ledger work for you.

Thanks @gcc for your suggestions, but i’m already doing it: as i said, in the SC itself i’ve written control subroutines which logics pass, so the sender does actually own the nft (as i am able to verify via AlgoExplorer). So, in a few words the situation is: before the inner txn, the app is able to see the owner of the nft, but in the inner txn it’s not able to transfer it. This is the reason why i think there’s a gap between ‘regular’ transactions and inner ones in the ability to ‘see’ the chain state.

I see. Do you have any inner app call or just inner asset transfers?

Just an inner txn of type axfer.

After a session of code debugging with @gcc, we found out the problem: the accounts’ array passed to app call didn’t always follow the order in which the elements were inserted into: even if the accounts’ array was initialised as a ArrayList (a ordered data structure), when the java sdk builds the txns to be submitted, it wraps the structure passing through an HashSet, changing randomly the order of the elements.
I want to thank @gcc for his support, the bug in the java sdk will be fixed as soon as possible. Till that moment, we’ll bypass it creating a custom class which extends MethodCallTransactionBuilder and overrides the methods that initialize the app call arrays.
Hope this would help anyone else who has to face the same problem as me!

1 Like