Yes, they store the same data, that is a valid ethereum address.
The difference is that the compiler (at compile time) when encounter an “address payable” is ready to allow (if required in the following code) that address to access primitives useful to manage ethers (namely call, transfer, send).
In that sense, after a declaration like:
address payable spender;
the compiler shall accept any
spender.send();
spender.transfer(); (1)
spender.call();
and generates the bytecode required to implement them.
On the other hand if the declaration is:
address spender;
the compiler shall generate error if any of the (1) is encountered.
After the compile time there is not difference between payable or not address. In particular they have the same size in memory and are not distinguishable.
In short it is a congruency tag, nothing more.
Understanding this, it is very simple to convert any address payable to address and viceversa using cast:
address payable spender = msg.sender;
address owner;
address payable newspender;
owner = address(spender); // this is no more payable
newspender = address( uint160(owner) ); // this is again payable
As you can see to do the opposite (not payable to payable) it is required explicitly to use uint160 as intermediate casting
Added after 0.6.0 solidity update:
now you have the possibility to directly cast any address to a payable address using the “payable” keyword:
address payable spender = msg.sender;
address owner;
address payable newspender;
owner = address(spender); // this is no more payable
newspender = payable(owner); // this is again payable
address payablewas added in Solidity 0.5.0, and prior to this release,addresstype worked asaddress payable. – Mikhail Vladimirov Apr 27 '19 at 17:38address payablelike this:payable(...)– Jesbus Dec 27 '19 at 20:21address(0x8aB27....)have the typeaddressinstead ofaddress payable– Jesbus Dec 22 '20 at 13:55msg.sender.transfer(x)topayable(msg.sender).transfer(x). Source: https://docs.soliditylang.org/en/v0.8.2/080-breaking-changes.html#how-to-update-your-code – peizhao Oct 02 '21 at 23:43address payable addr4 = payable(addr1);. why should i state payable on the variable and also cast the address itself to a payable address. what is the purpose of setting the variable as payble if the second one is what adds the functionality of transfer and send. thanks – fedesc Feb 02 '22 at 15:26.transfer()and.send()are basically deprecated now, with.call{value: X}()being the new recommended way to send X ETH wei to a recipient. Therefore, since.callworks with bothaddressandaddress payable, I assume this means thataddress payableis more or less useless at this point? – Luke Hutchison Jun 13 '22 at 21:06