Confused about a withdraw function in a contract I am studying - solidity

I am fairly new to Solidity and at this point, reviewing contracts that are active and on chain. I am trying to understand every detail. This withdraw function has got me stumped.
function withdraw(address token, uint256 amount) external onlyOwner {
if(token == address(0)) {
payable(_msgSender()).transfer(amount);
} else {
IERC20(token).transfer(_msgSender(), amount);
}
}
Particularly the two parts that are "if(token == address(0))" and "payable(_msgSender()).transfer(amount);".
The best explanation for address(0) is here What is address(0) in Solidity but I have to admit, both answers have me bewildered.
I have read that payable() is casting the address to be payable and that this has been deprecated. Just looking for a short explanation as if to a child.
A decent amount of time searching to no avail.

This code seems to aim to be an universal function for two separate features:
withdraw native token
withdraw ERC-20 token
If you pass 0x0000000000000000000000000000000000000000 as the value of address token, the code transfers amount of native token from the contract balance to the _msgSender() address. Each network has usually different native token - ETH on Ethereum, BNB on Binance Smart Chain, MATIC on Polygon, ...
If you pass any other value as address token, the contract assumes that there's an ERC-20 contract on that address, and tries to transfer out amount of the ERC-20 token from the contract balance to the _msgSender() address.
payable extension of address is not deprecated. Since Solidity v0.8.0, all native transfers need to be performed to an address payable type - while older versions also allowed transfers to the regular address type.
The use of transfer() function might be a bit confusing, though. When it's called on an address payable type, it's the native transfer. And when it's called on an interface or contract type (in your case IERC20), it invokes a function on the specified contract - in this case the external contract function is also called transfer().

Related

Is it ever more gas efficient to store address(0) as a variable constant?

I see that in many smart contracts address(0) is being used as shorthand for 0x0000000000....
However since it appears very often in almost all smart contracts, I am wondering if it is, or ever becomes gas efficient to simply create the variable as constant in the blockchain instead, and just reference it when necessary, or if it really is just cheaper to constantly write address(0) inline every time.
address public constant NULLADDRESS = address(0); vs using address(0) inline 50 times.
So i just tested this out with this code
pragma solidity >=0.4.22 <0.9.0;
contract NullContract{
address public constant NULLADDRESS = address(0);
function retrieve() public pure returns(address){
return (address(0));
}
}
constant NULLADDRESS needed 21442 gas
and retrieve function which returns value doesn't change anything in the blockchain needed 21420 gas. so its basically the same

Transferring msv.value within the body of a function in solidity

If I have a payable function in Solidity, can I transfer msg.value directly to another address without having funds in the contract. For example:
function foo() payable {
myaddr.transfer(msg.value);
}
If the contract has not received any funds yet, will this work? Or will it only work if there are at least msg.value worth of funds from a previous transaction? Thanks!
If the contract has not received any funds yet, will this work?
Yes. This snippet works as a "transaction proxy", transferring the currently received value to myaddr without having to have the balance before the transaction.
Example:
Your contract has 0 ETH balance.
Execute foo() sending along 10 ETH
myaddr receives the 10 ETH, while your contract keeps the 0 balance
User executing the foo() function pays gas fees for both the main transaction (to your contract implementing foo()) and the internal transaction (from your contract to the myaddr).

Should I check whether there is a eth in contract

I cannot understand when the revert is running. I have this code:
function test() public payable returns(uint){
require(getContractBalance() >= msg.value.add(msg.value).add(_foo), "Not enough eth in contract");
_foo= _foo.add(msg.value.mul(5).div(1000));
return _foo;
}
In contract I have 2 ETH, and _foo var have 1e18 wei;
When I call the test() function and send 1 ETH, I don't have revert, and the function is run in the same way. But while 1ETH+1ETH+1ETH = 3ETH, in the contract I have only 2 ETH.
Why does revert not work? Is this because the require() is running after the changes in the contract? How can I do this: revert when the contract does not have enough eth!
Should I check whether there is a eth in the contract? If I call some function that sends ETH to an account, but I don't have eth in the contract I get revert? Should I check contract balance?
Should I set require(addres(this).balance > 0) or not?
Your require does not fail, because when you are starting with a contract with balance 2 ETH and you send 1 ETH along with the call of test, then the contract balance becomes 3 ETH and the condition for the require is satisfied.
So, you have to revisit your logic, e.g. by checking if getContractBalance() - msg.value >= <desired-start-value-before-the-call>

Solidity contract not working

I'm having trouble running my first solidity contract in remix ethereum and through web3 so I'm guessing something is wrong with my contract code:
pragma solidity ^0.4.0;
contract cntrct
{
uint public aaa;
function() payable public
{
create(msg.value);
}
function create(uint _value) internal
{
require(_value>0);
aaa = _value;
}
function reader() view public returns(uint)
{
return aaa;
}
}
I succesfully deployed the contract in both remix and web3. However, after sending a transaction to the contract, the aaa variable is still 0. What I want this code to do is update the aaa variable to the last deposited amount so I can read it later by calling the reader function. In remix it does not show any input field for the aaa variable. Also, in MetaMask transactions sent to the contract stay in a pending status even if they're already completed (balances updated in remix and tx in testRPC.)
In node I'm using the following line to try to execute the reader function but I'm unsure if this will work.
contract.methods.reader().call(0, (error, result) => { if(!error){console.log(result);}});
There’s no reason to store the ether sent in a state variable unless you need to maintain a mapping of balances spread across multiple addresses. The total balance is held in the contract and is accessible with this.balance.
In addition, fallback functions are limited to 2300 gas. You can’t write to storage (ie, update a state variable) within that limit. Your variable isn’t updated because it’s failing. See the second bullet point here for more info.
In solidity contract, you can read the value of public filed by calling field as a method. here, aaa()
I have deployed with mist browser under private network and send 10 ether to this contract successfully.

web3.js - how to check if a Token Contract implements ERC223 standard?

I would like to receive payments in any given ERC20 Token.
For that, the user must fisrt approve the transaction calling...
function approve(address, uint)
... on the Token's contract and then call to a specific function on MyContract that will triggers the actual transfer, calling...
function transferFrom(address from, address to, uint tokens)
... again on the Tokens's contract
That works fine but is very tedius and has double gas spending.
Now I found out the ERC223 standard that solves this (and other issues) but is not implemented by the mayority of the current popular tokens. It would be great to give the user the opportunity to pay just making a single transaccion when posible.
So, how can I dynamicaly check if a given token address implements ERC223 standar using web3 v0.x (im using v0.20.4) ?