Skip to content

Instantly share code, notes, and snippets.

@EdsonAlcala
Last active November 22, 2019 10:56
Show Gist options
  • Save EdsonAlcala/97fa6a0e3aea84bb20226e61f2ff9730 to your computer and use it in GitHub Desktop.
Save EdsonAlcala/97fa6a0e3aea84bb20226e61f2ff9730 to your computer and use it in GitHub Desktop.
pragma solidity ^0.5.3;
contract FiniteStateMachine {
struct State {
bytes32[] allowedNextStates;
mapping(bytes32 => mapping(bytes4 => bool)) allowedFunctions;
}
bytes32 public currentStateId;
mapping(bytes32 => State) states;
mapping(bytes32 => address) public partyByRole; //party role => address
mapping(address => bytes32) public partyRoleByAddress;
modifier checkPartyCanCallFunction {
require(canCallFunction(currentStateId), "Function call not allowed in current state by this party");
_;
}
function addAllowedFunction(bytes32 _stateId, bytes32 _partyRole, bytes4 _functionSelector) internal {
states[_stateId].allowedFunctions[_partyRole][_functionSelector] = true;
}
function addAllowedState(bytes32 _stateId, bytes32 _nextState) internal {
states[_stateId].allowedNextStates.push(_nextState);
}
function setParty(bytes32 _role, address _party) internal {
if(_party != address(0)){
partyByRole[_role] = _party;
partyRoleByAddress[_party] = _role;
}
}
function setInitialState(bytes32 _stateId) internal {
currentStateId = _stateId;
}
function canCallFunction(bytes32 _stateId) public view returns (bool) {
State storage state = states[_stateId];
bytes32 partyRole = partyRoleByAddress[msg.sender];
if(state.allowedFunctions[partyRole][msg.sig])
return true;
return false;
}
function transitionToState(bytes32 _stateId) internal {
require(canTransition(_stateId), "Transition not allowed");
currentStateId = _stateId;
}
function canTransition(bytes32 _nextState) internal view returns (bool) {
bool allowed = false;
for (uint256 j = 0; j < states[currentStateId].allowedNextStates.length; j++) {
if (states[currentStateId].allowedNextStates[j] == _nextState) {
allowed = true;
break;
}
}
return allowed;
}
}
pragma solidity ^0.5.3;
contract LetterOfCredit is FiniteStateMachine {
// States
bytes32 constant REQUESTED = "requested";
bytes32 constant ISSUED = "issued";
bytes32 constant ADVISED = "advised";
bytes32 constant ACKNOWLEDGED = "acknowledged";
// Parties
bytes32 constant APPLICANT = "applicant";
bytes32 constant BENEFICIARY = "beneficiary";
bytes32 constant ISSUING_BANK = "issuingbank";
bytes32 constant ADVISING_BANK = "advisingbank";
constructor() public {
setupStates();
address _beneficiary = 0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c; // TO BE REPLACED
address _issuingBank = 0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c; // TO BE REPLACED
address _advisingBank = 0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c; // TO BE REPLACED
setParty(APPLICANT, msg.sender);
setParty(BENEFICIARY, _beneficiary);
setParty(ISSUING_BANK, _issuingBank);
setParty(ADVISING_BANK, _advisingBank);
setupAllowedFunctions();
setInitialState(REQUESTED);
}
function setupStates() internal {
// REQUESTED
addAllowedState(REQUESTED, ISSUED);
// ISSUED
addAllowedState(ISSUED, ADVISED);
addAllowedState(ISSUED, ACKNOWLEDGED);
// ADVISED
addAllowedState(ADVISED, ACKNOWLEDGED);
}
function setupAllowedFunctions() internal {
// functions
addAllowedFunction(REQUESTED, ISSUING_BANK, this.issue.selector);
addAllowedFunction(ISSUED, ADVISING_BANK, this.advise.selector);
addAllowedFunction(ADVISED, BENEFICIARY, this.acknowledge.selector);
}
function issue() public checkPartyCanCallFunction {
transitionToState(ADVISED);
}
function advise() public checkPartyCanCallFunction {
transitionToState(ADVISED);
}
function acknowledge() public checkPartyCanCallFunction {
transitionToState(ADVISED);
}
function getCurrentStateId() public view returns(bytes32) {
return currentStateId;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment