Awarded: ICDevs.org Bounty #39 - Async Flow - One Shot - Motoko - $6,000

Note: com_asyncFlow_ackack has been renamed
You may want to coordinate with @GLdev on some of this as he is doing the rust counterpart.

The point of the library is that the canisters are not connected and are likely developed by different (potentially malicious) people.

mscgenjs_chart (8)

my_args could be something like:

type MyArgs = {
     #transfer: TransferArgs;
     #mint: MintArgs;
     #burn: BurnArgs;
}

The sender would instantiate the class:


actor {

func handle_return(canister_id: principal, sent_payload : blob, received_payload : blob, msg_id: nat, hash: ?nat32){
    let my_args = to_candid(sent_payload)  : MyArgs;
    //check hash if desired;
     switch(my_args){
         case(#transfer(val){
           let my_response = to_candid(recieved_payload) : TransferResponse;
           //handle transfer
         };
         ///......etc
     };

     one_shot_hadler.finish(msg_id);
};

//instantiate the oneshot handler
let one_shot_handler = OneShot.Handler(
   return_async = ?handle_response;
   request_async = null; // you'd set this if you were a receiver and a sender
);

public shared func com_asyncFlow_ack(id: Nat, hash: ?Hash, return_args: Blob){
     one_shot_hadler.handle_response(id, hash, return_args);
};

public shared func transfer_proxy_async(request: TransferArgs) : async (){
     let request_id = one_shot_handler.call_async(target_canister, from_candid(transfer_args);
};

//handle timers upon upgrade
public system pre_upgragde{
    stable_one_shot_timers := one_shot_handler.backup_timers()
}

public system post_upgragde{
    one_shot_hadler.hydrate_timers(stable_one_shot_timers);
}


}

The receiver:


actor {

func handle_request(canister_id: principal, sent_payload : blob, msg_id: nat, hash: ?nat32){
    let my_args = to_candid(sent_payload)  : MyArgs;
    //check hash if desired; <-maybe the library should handle this and this is only for info
     switch(my_args){
         case(#transfer(val){
           //do request transfer
          let response = #transfer(#ok(block));
           one_shot_hadler.return(msg_id, from_candid(response));
         };
         ///......etc
     };

     
};

//instantiate the oneshot handler
let one_shot_handler = OneShot.Handler(
   return_async = null; // you'd set this if you were a receiver and a sender
   request_async = ?handle_request;
);

public shared({caller}) func com_asyncFlow_newMessage(id: Nat, payload: Blob){
     one_shot_hadler.handle_request(caller, id, payload);
};

public shared({caller}) func com_asyncFlow_finish(id: Nat, hash: ?Blob){
     one_shot_hadler.handle_finish(id, hash);
};

public shared func transfer_proxy_async(request: TransferArgs) : async (){
     let request_id = one_shot_handler.call_async(target_canister, from_candid(transfer_args);
};

//handle timers upon upgrade
public system pre_upgragde{
    stable_one_shot_timers := one_shot_handler.backup_timers()
}

public system post_upgragde{
    one_shot_hadler.hydrate_timers(stable_one_shot_timers);
}

}

You will likely run across some other maintenance functions that you may need.

1 Like