2

I saw this question already, and several others going the other direction, from int to string, but how do I go specifically from string to a uint256?

I saw this answer has code for uint only, and it makes sense, but what needs to change for uint256?

I am also interested in how error-handling works in this---suppose the string does not contain integers, what is the right way to return an error, and to handle this in the calling function?

Update

Answers below were helpful. So would something like the below give me uint==uint256 and error handling efficiently and idiomatically?

function stringToUint(string s) constant returns ((bool success,uint result)) {
    bytes memory b = bytes(s);
    uint result = 0;
    success = false;
    for (uint i = 0; i < b.length; i++) { 
        if (b[i] >= 48 && b[i] <= 57) {
            result = result * 10 + (uint(b[i]) - 48); 
            success = true;
        } else {
            result = 0
            success = false;
            break;
    }
    } 
    return (success,result);
}

Update 2

Sorry, one more part of error handling: I understand the max value of uint256 to be:

2^256-1 = 115792089237316195423570985008687907853269984665640564039457584007913129639935

How would I handle correctly rejecting a string that would cause rollover?

eg, would this:

stringToUint("115792089237316195423570985008687907853269984665640564039457584007913129639937")

(which is 2^256+1) rollover to 1?

3 Answers 3

2

Uint is actually an alias for uint256, the "stringToUint" method you're pointing at in the other question actually supports the conversion of shorter uints ( uint 8 / uint 16 / etc ) as well depending on the "string length you provide".

The only thing you should keep in mind is if you want to store said uints in a contract's storage, it's better to cast them as the actual uint size you need ( uint8 for a number lower than 255 / uint16 for lower than 65537 / etc )

ie:  uint16 myUint16Val = uint16( stringToUint("500") );

Try it out and you'll see it works.

The method itself only reads numeric characters and ignores everything else. If you actually want to only resolve strings that contain only numbers, you can add an "else check that returns a boolean value like @flygoing suggested"

// Code example:
function stringToUint(string s) constant returns (uint, bool) {
    bool hasError = false;
    bytes memory b = bytes(s);
    uint result = 0;
    uint oldResult = 0;
    for (uint i = 0; i < b.length; i++) { // c = b[i] was not needed
        if (b[i] >= 48 && b[i] <= 57) {
            // store old value so we can check for overflows
            oldResult = result;
            result = result * 10 + (uint(b[i]) - 48); // bytes and int are not compatible with the operator -.
            // prevent overflows
            if(oldResult > result ) {
                // we can only get here if the result overflowed and is smaller than last stored value
                hasError = true;
            }
        } else {
            hasError = true;
        }
    }
    return (result, hasError); 
}

in which case, you call the method and check the return values to make sure that the "hasNonNumericBytes" is false before using said uint value.

var( myuint, hasBadBytes ) = stringToUint("5a0");
if( hasBadBytes == false ) {
    // revert transaction 
}

Hope that helps.

3
  • Super helpful. To press my luck, any chance you have a suggestion on the rollover too? :) Commented Nov 14, 2018 at 21:36
  • 1
    To prevent overflows, you could check that the "new result is actually higher than the old one, after multiplying" and if not, trigger the error Commented Nov 14, 2018 at 22:15
  • 1
    I've added the overflow check to the answer :) feel free to accept it if it works for you. Commented Nov 14, 2018 at 22:19
2

Here is a function that allows to convert a string to a uint256. The error has been handled by returning false as second output.

function strToUint(string memory _str) public pure returns(uint256 res, bool err) {
    
    for (uint256 i = 0; i < bytes(_str).length; i++) {
        if ((uint8(bytes(_str)[i]) - 48) < 0 || (uint8(bytes(_str)[i]) - 48) > 9) {
            return (0, false);
        }
        res += (uint8(bytes(_str)[i]) - 48) * 10**(bytes(_str).length - i - 1);
    }
    
    return (res, true);
}
1

uint is just an alias for uint256. The linked answer with code will work for uint256.

As for error handling, that is completely up to. I'd say you should return a tuple like (bool success, uint256 value).

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.