ICRC-104 - Rule-Based Membership Manager Standard

This Topic is to discuss ICRC-104.

The Issue: ICRC-104 - Rule-Based Membership Manager - ICRC-75 Expansion · Issue #104 · dfinity/ICRC · GitHub

The Draft: https://github.com/icdevsorg/icrc04.mo/blob/main/icrc104-standard.md

Reference Motoko Module: GitHub - icdevsorg/icrc104.mo: ICRC-104 for motoko. Rule-Based Membership Manager Standard

Mops: Mops • Motoko Package Manager

Sample Dapp: https://iedms-tqaaa-aaaal-amieq-cai.icp0.io/ (A ICRC-104 Rule manages the org.icdevs.lists.king_of_the_hill list, note the canister as admin)

Tips:

  • Easily add handling multiple rules to manage your ICRC-75 lists through a single governance endpoint.
  • You can write simulators and validators(for SNS integration) as well
  • Code to add a new rule is straightforward:
    public func run_validator<system>(request: ICRC104.HandleRuleEvent) : async* ICRC104.SNSValidationResponse {

      if(not Set.has(init.icrc104.get_state().admins, Set.phash, request.caller)){
        return #Err("caller not authorized");
      };

      switch(init.validator){
        case(?validator){
          switch(await* validator(request)){
            case(#Err(response)) return #Err(response);
            case(#Ok(response)) return #Ok(response);
          };
        };
        case(null) {
          return #Ok(defaultValidationMessage(request));
        };
      };
    };

    public func rule_action<system>(request: ICRC104.HandleRuleEvent, bSimulate : Bool) : async* Star.Star<ICRC104.RuleHandlerResponse,()> {

      if(request.rule_namespace != init.ruleNamespace){
        return #trappable(#apply(#Err(#ExecutionFailed("rule namespace mismatch"))));
      };
      ///add rule execution code here

      if(not Set.has(init.icrc104.get_state().admins, Set.phash, request.caller)){
        return #trappable(#apply(#Err(#ExecutionFailed("caller not authorized"))));
      };

      if(bSimulate){
        //handle simulation
      };

      var bAwaited = false;

      //qualify the request

      //handle the return
      return if(bAwaited){
        #awaited(#apply(#Ok(#LocalTrx({
        metadata = if(metadata.size() > 0){
            [("errors", #Text(metadata))];
          }else {
            []
          };
        transactions = Buffer.toArray(trx);
      }))))} else {
        #trappable(#apply(#Ok(#LocalTrx({
          metadata = if(metadata.size() > 0){
              [("errors", #Text(metadata))];
            }else {
              []
            };
          transactions = Buffer.toArray(trx);
        }))));
      };
    };

    ignore init.icrc104.add_rule_handler_listener("my_rule_namespace", replace_role, ?run_validator);

The candid function list interface:

  icrc104_apply_rule : (ApplyRuleRequest) -> (ApplyRuleResult);
  icrc104_simulate_rule : (ApplyRuleRequest) -> (ApplyRuleResult);
  validateApplyRule : (ApplyRuleRequest) -> (SNSValidationResponse);