Let's say I have an enum
and set the default:
enum Status {
INACTIVE,
FAIL,
SUCCESS,
PENDING
}
Status public myStatus = Status.INACTIVE;
I'm wondering if one approach to updating myStatus
is "better" than the other in terms of gas and just best practice:
Approach A
Have one generic setter function that accepts a value:
function setStatus(uint256 _status) external onlyOwner {
require(_status <= uint256(Status.PENDING), "Status out of bounds");
myStatus = Status(_status);
}
Approach B
Have individual setter functions:
function setStatusToInactive() external onlyOwner {
myStatus = Status.INACTIVE;
}
function setStatusToFail() external onlyOwner {
myStatus = Status.FAIL;
}
function setStatusToSuccess() external onlyOwner {
myStatus = Status.SUCCESS;
}
function setStatusToPending() external onlyOwner {
myStatus = Status.PENDING;
}
With B, you can strictly control the setters and have no need for require
statements. Any front-end interacting with the contract will not need to be aware of the enum and instead just call the appropriate function.
With A, does it cost less gas to deploy? Does it have any effect? Should you not add "unnecessary" functions like in B? In a scenario where there are many values in the enum, B becomes unmanageable if you need a setter for every one.
Best Answer
You can do it with A and an
enum
.By casting the input as an
enum
you get a similar effect as yourrequire
and you avoid the convoluted type conversions. The internalenum
creates an externaluint8
because the list "fits" in auint8
. From a client-side perspective, they pass 0, 1, 2, etc. as auint8
as you would expect.While there are arguments for B around user-friendliness in some cases (enable/disable?), that's a subjective call. It will increase deployment cost to increase the contract size so I would avoid using it for long lists. General heuristic - always aim for simplicity.
Hope it helps.