Skip to content

Instantly share code, notes, and snippets.

@frangio
Last active February 2, 2023 19:06
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save frangio/e2438da9b8bdfa08198a9d57dd9c6611 to your computer and use it in GitHub Desktop.
Save frangio/e2438da9b8bdfa08198a9d57dd9c6611 to your computer and use it in GitHub Desktop.
Lightweight explicit state machines in Solidity.
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
import "./StateMachines.sol";
contract Pausable is StateMachines {
StateMachine m = initial("unpaused");
event Paused(bool paused);
function pause() external transition(m, "unpaused", "paused") {
emit Paused(true);
}
function unpause() external {
// More efficient than transition modifier for atomic transitions
move(m, "paused", "unpaused");
emit Paused(false);
}
function isPaused() external view returns (bool) {
return isState(m, "paused");
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
import "./ToString.sol";
struct StateMachine {
bytes31 _state;
bool _transitioning;
}
function initial(bytes31 state) pure returns (StateMachine memory) {
return StateMachine(state, false);
}
contract StateMachines {
modifier transition(StateMachine storage m, bytes31 from, bytes31 to) {
depart(m, from);
_;
arrive(m, to);
}
}
function depart(StateMachine storage m, bytes31 from) {
checkState(m, from);
m._transitioning = true;
}
function arrive(StateMachine storage m, bytes31 to) {
checkTransitioning(m, true);
m._transitioning = false;
m._state = to;
}
function move(StateMachine storage m, bytes31 from, bytes31 to) {
checkState(m, from);
m._state = to;
}
error StateViolation(string current, string expected);
error AtomicityViolation(string current);
function checkTransitioning(StateMachine storage m, bool transitioning) view {
if (m._transitioning != transitioning) {
revert AtomicityViolation(toString(m._state));
}
}
function checkState(StateMachine storage m, bytes31 expected) view {
if (m._state != expected) {
revert StateViolation(toString(m._state), toString(expected));
}
checkTransitioning(m, false);
}
function isState(StateMachine storage m, bytes31 expected) view returns (bool) {
return !m._transitioning && m._state == expected;
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
function toString(bytes32 s) pure returns (string memory) {
uint x = uint(s);
uint len = 0;
for (uint m = 0xff << 248; x & m != 0 && m != 0; m >>= 8) {
len += 1;
}
bytes memory b = new bytes(32);
assembly {
mstore(b, len)
mstore(add(b, 32), s)
}
return string(b);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment