Smart Contract Security Class (№009)

TRON Foundation
Jul 12 · 3 min read

This small class will discuss the disappearing internal transfer transactions, giving an example of using this phenomenon for honeypot attacks. At the same time, everyone is welcome to pay attention to @tron official twitter, and actively submit the contract code.
This is the contract revealed at https://troneye.com (hereafter referred to as TRON-Eye). TRON-Eye is a wave-based verification platform from the community. The previous small class has introduced the TRON-Eye verification platform in detail. This contract is DisappearedTransfer (https://troneye.com/reveal?address=TFVE66w23Azoa31YEXP5z6XPszUkNLDWTv).

Figure 1 DisappearedTransfer contract source code
As the contract shows, this is an very simple contract with only two withdraw functions. All we need to do is call these two methods to take the TRX out of the contract. Of course, the facts are not as simple as we think.
1. contract DisappearedTransaction
2. {
3. function withdraw()
4. public
5. payable
6. {
7. if (msg.value >= address(this).balance)
8. {
9. msg.sender.transfer(address(this).balance + msg.value);
10. }
11. }
12.
13. function withdraw2()
14. public
15. payable
16. {
17. if (msg.value >= 100)
18. {
19. msg.sender.call.value(address(this).balance);
20. }
21. }
22. }
With the Withdraw1 method, this code makes you think that when the incoming TRX is greater than the contract’s balance, we will get both the incoming TRX and the contract’s balance.
In fact, when we call Withdraw1 with TRX that is more than the contract’s balance, we will find that the contract’s TRX is never transferred out, and the TRX we transferred into is locked.
Let’s take a closer look at the 7th line of code:
if (msg.value >= address(this).balance)
This line of code looks like, when the incoming TRX is greater than the balance in the contract, you can enter the logic in this judgment. In fact, since the TRX attached to the contract was transferred to the contract before the contract was executed, the this.balance taken in the contract already contains the incoming msg.value. In other words, balance can never be smaller than mag.value.
And the code on line 9:
Msg.sender.transfer(address(this).balance+msg.value);
The problem with this line of code is also obvious. Even when the previous balance is 0, the following transfer method is entered, and this will fail due to insufficient balance.
There is another withdraw2 method, the 19th line of code in withdraw2:
Msg.sender.call.value(address(this).balance);
This line of code only transfers balance, there is no problem mentioned earlier. But, when you are looking forward to calling this method, you still cannot find any records that the contract’s TRX is transferred out.
This is another problem. When we call the contract with the call method, we allow the value to be passed in the form of “.value()”. Of course, we can also use this method to transfer the ordinary non-contracted address.
But even if you don’t need to explicitly pass in the method name and any parameters, you still need to use the “()” empty parenthesis to make the call method execute. The correct line 19 should be:
Msg.sender.call.value(address(this).balance)();
These are just a few of the many things you need to pay attention to in this.balance. Welcome to twitter. Tell me about the magical things you have encountered.
This small class will be mentioned here first. Thanks to TRON-Eye for providing contract verification tools. More information about them can be found directly on their website https://troneye.com.
We continue to collect sample source code for follow-up classes, and we welcome your official twitter submissions.

TRON Foundation

Written by

The official medium of Tron Foundation