There are no Michelson ops for formatting values as strings.
Unless a protocol change adds such operations, it seems that the best way to convert mutez (or int, nat) to string will be to write the algorithm manually:
- First, we can convert mutez to nat by dividing by 1 mutez, using EDIV.
- Now we can do a loop, iteratively dividing the nat value by 10, again using EDIV. The remainders give us each successive digit of the decimal representation. We must map each digit 0-9 to the corresponding string "0"-"9", perhaps using a literal
map nat string
. Of course, once we get to zero, we are done.
- If we want to format mutez as a tez string, we need to add a decimal place and might drop trailing zeros after the decimal.
- To concatenate the string bits together we will use CONCAT. There are two forms of CONCAT. I think it is generally more gas-efficient to build up a
list string
and CONCAT it all at once, rather than doing a bunch of binary string/string CONCATs.
It seems like this is going to require a decent chunk of code. This will cost you some origination burn. You will probably consume gas for this code on every transaction to your contract, whether the code is executed or not.
You can mitigate this gas cost by putting the conversion code once in a lambda. You will still pay the cost once per transaction.
You could mitigate the gas cost even more by doing some big_map gymnastics, loading the lambda from the big_map only when it is needed.
Perhaps, in your case, the gas costs are not a concern. I don't know.
Current.failwith(("Not enough money", storage.addCost))
to at least communicate the amount in the fail message. However, still think there has to be a way to do this...?