4

Example of an address with the wrong checksum:

0xa54D3c09E34aC96807c1CC397404bF2B98DC4eFb

Example of an address with the right checksum:

0xa54d3c09E34aC96807c1CC397404bF2B98DC4eFb

-Difference is the first letter "D".

Which function call should I make in Solidity to convert the wrong checksum address to a right checksum address ?

3
  • 1
    I think I don't understand your use case, Solidity doesn't have a function with that functionality, perhaps you want to use web3.utils.toChecksumAddress from web3.js.
    – Ismael
    Commented Sep 8, 2019 at 15:08
  • I want to do it with Solidity and not Javascript. The only way I know is to convert to a string and then correct the checksum of a string and then back to address... which costs a lot of eth to process. Commented Sep 8, 2019 at 15:20
  • 1
    As stated by Lauri Peltonen EVM/Solidity deal with addresses as raw bytes and they do not include the checksum. It is responsibility of framework/libraries to calculate the checksum at user presentation.
    – Ismael
    Commented Sep 8, 2019 at 18:32

7 Answers 7

3

The simple answer is that in solidity:

address(0xa54D3c09E34aC96807c1CC397404bF2B98DC4eFb);

It is true that the compiler warns you of incorrect checksum when it sees one, but that warning is probably there just to tell you that you might have gotten the wrong address altogether (because typically, constant addresses are copy-pasted from one place to another, and copy-pasting would not "accidentally" change some upper-case letter to lower-case or vice versa).

The Solidity compiler tells you exactly how you can fix it (manually):

SyntaxError: This looks like an address but has an invalid checksum. Correct checksummed address: "0xa54d3c09E34aC96807c1CC397404bF2B98DC4eFb". If this is not used as an address, please prepend '00'. For more information please see solidity.readthedocs.io/en/develop/types.html#address-literals address(0xa54D3c09E34aC96807c1CC397404bF2B98DC4eFb);

The solution then becomes:

Hexadecimal literals that pass the address checksum test, for example 0xdCad3a6d3569DF655070DEd06cb7A1b2Ccd1D3AF are of address payable type. Hexadecimal literals that are between 39 and 41 digits long and do not pass the checksum test produce an error. You can prepend (for integer types) or append (for bytesNN types) zeros to remove the error.

But again, these two constants are identical, and they will yield the exact same runtime-behavior.

1
  • I will accept this as an answer because it is pointing to the right link which contains the solution I have written here. I just didn't want to accept my own answer. For anyone interested, follow the link (or see my answer). You can continue using the address and convert it to a String with a correct checksum if necessary. Commented Oct 1, 2019 at 11:41
3

As mentioned in comments Solidity doesn't have such functionality. Solidity (and also EVM) doesn't understand anything about address checksums, it's only a construct added on top of the toolkits.

If you really really want to you can calculate it yourself in Solidity. Here's the original EIP: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md with some example code. But I fail to see why you'd want to do that.

1
  • In that case it has to be coded, and I am sure there is a simple solution for it. Sorry, but can't accept the answer... Commented Sep 8, 2019 at 17:58
3

We can get help from the solidity compiler since it's showing the fixed checksummed address in below compiler error

SyntaxError: This looks like an address but has an invalid checksum. Correct checksummed address: "0xa54d3c09E34aC96807c1CC397404bF2B98DC4eFb". If this is not used as an address, etc..

2

Other colleagues did underline very well the point: in Solidity does not exist something called “address with correct checksum”. There exist addresses. Full stop.

The request for a proper checksum comes from the user interface of the IDE, like remix or similar, just to ask you to double check your address. But just for this.

You can obtain your correct checksum address treating it as a string, then applying the EIP 55 rules, then converting it back to address.

But this do not make sense in a smart contract: never. And it does not make sense to record that on blockchain. It is something like using EVM and paying ethers at running time to indent properly the source code. It, if required, is to be done offline, by means of some JavaScript or C.

In other word: the CRC is a “cosmetic” element useful for the interface to the IDE, like comments in green and between /* and */.

You are asking something like “I want to format comments in solidity”.

This does not make sense. At run time do not exist anymore both indenting and comments and CRC for addresses.

I hope this can help.

5
  • If incorrect checksum didn't exist, there shouldn't be a compiler error stating that the address contains the incorrect checksum. It should exist as a warning instead. On the other hand, the older versions of solidity do accept the incorrect checksum, so perhaps your answer is valid, however, outdated. Commented Oct 1, 2019 at 10:52
  • It is a safe check made in order to give you the habit to copy and paste addresses in the code, not to write them from the scratch. Nothing more. Try this way: may be (may be!) that in a future the CRC of addresses be possibly used for something not clear at the moment. At the moment it is not. In no way. Sorry for it, this is the cruel truth.
    – Rick Park
    Commented Oct 1, 2019 at 11:23
  • I am sorry, but you are telling me that a Syntax Error is just a warning and not a compile-time error... However, I don't want this to become an argument or a chat, given the board rules. The link says how to fix it... SyntaxError: This looks like an address but has an invalid checksum. Correct checksummed address: "0xa54d3c09E34aC96807c1CC397404bF2B98DC4eFb". If this is not used as an address, please prepend '00'. For more information please see solidity.readthedocs.io/en/develop/types.html#address-literals address(0xa54D3c09E34aC96807c1CC397404bF2B98DC4eFb); Commented Oct 1, 2019 at 11:32
  • The compiler requires that you insert checksum corrected address in the .sol. This is a fact. This does not mean that it is useful vs the generated code (it is not), nor that you should write solidity routines in order to have that a checksum (that are not required). Address(this) do not return a checksummed address, but an address. You do not have to work on it in order to have the proper checksum. Nobody is worried about the checksum in the EVM. And this is definitive. You do not understand properly the situation and are searching for something existing in the UI side of the compiler only.
    – Rick Park
    Commented Oct 1, 2019 at 12:11
  • All I am saying is that Syntax Error is not to be used as an UI-side warning but a compiler error, regardless the language and IDE. Commented Oct 1, 2019 at 13:20
2

The solution is simple...

https://solidity.readthedocs.io/en/develop/types.html#address-literals

Hexadecimal literals that pass the address checksum test, for example 0xdCad3a6d3569DF655070DEd06cb7A1b2Ccd1D3AF are of address payable type. Hexadecimal literals that are between 39 and 41 digits long and do not pass the checksum test produce an error. You can prepend (for integer types) or append (for bytesNN types) zeros to remove the error.

Furthermore, I can use the address however I want and convert it to a String with the proper checksum if I need it.

1

I found a solution just copy the address to Etherscan.io and paste it to see the tokens and transactions in the wallet, then check at the top the address that etherscan shows its the address with the right checksum. this worked for me

0

I had a use-case where hash of the checksummed address (as string) was already committed, and I needed to check if the address provided later matched it on chain. Thus, I needed to compute the checksummed hex string of the address. Here is my implementation of EIP-55 in solidity:

bytes16 private constant HEX_DIGITS = "0123456789abcdef";
bytes16 private constant HEX_CAPITAL = "0123456789ABCDEF";

function toChecksumHexString(address addr) public pure returns (string memory) {
    bytes memory lowercase = new bytes(40);
    uint160 currentAddressValue = uint160(addr);
    for (uint i = 40; i > 0; --i) {
        lowercase[i-1] = HEX_DIGITS[currentAddressValue & 0xf];
        currentAddressValue >>= 4;
    }
    bytes32 hashed_addr = keccak256(abi.encodePacked(lowercase));

    bytes memory buffer = new bytes(42);
    buffer[0] = '0';
    buffer[1] = 'x';

    uint160 addrValue = uint160(addr);
    uint160 hashValue = uint160(bytes20(hashed_addr));
    for (uint i = 41; i>1; --i) {
        uint hashIndex = hashValue & 0xf;
        if (hashIndex > 7) {
            buffer[i] = HEX_CAPITAL[addrValue & 0xf];
        }
        else {
            buffer[i] = HEX_DIGITS[addrValue & 0xf];
        }
        addrValue >>= 4;
        hashValue >>= 4;
    }
    return string(abi.encodePacked(buffer));
}

I have raised an issue on openzeppelin to add it to their string utils, hopefully an implementation will be added soon.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.