示例:

直接进入正题,现在,我举个使用Ledger Actor动态创建canister的例子。

假如我们想在A.mo的actor中动态创建B.mo中的actor类,则:

一、先创建Types.mo模块,在其中写入以下代码:

module IC{
    public type canister_settings = {
        freezing_threshold : ?Nat;
        controllers : ?[Principal];
        memory_allocation : ?Nat;
        compute_allocation : ?Nat;
    };

    public type definite_canister_settings = {
        freezing_threshold : Nat;
        controllers : [Principal];
        memory_allocation : Nat;
        compute_allocation : Nat;
    };
    public type user_id = Principal;
    
    public type wasm_module = [Nat8];
    public type canister_id = Principal;
    public type ICActor = actor {
        canister_status : shared { canister_id : canister_id } -> async {
            status : { #stopped; #stopping; #running };
            memory_size : Nat;
            cycles : Nat;
            settings : definite_canister_settings;
            module_hash : ?[Nat8];
        };

        create_canister : shared { settings : ?canister_settings } -> async {
            canister_id : canister_id;
        };
        
        delete_canister : shared { canister_id : canister_id } -> async ();
        
        deposit_cycles : shared { canister_id : canister_id } -> async ();
        
        install_code : shared {
            arg : [Nat8];
            wasm_module : wasm_module;
            mode : { #reinstall; #upgrade; #install };
            canister_id : canister_id;
            } -> async ();
        
        provisional_create_canister_with_cycles : shared {
            settings : ?canister_settings;
            amount : ?Nat;
            } -> async { canister_id : canister_id };
        
        provisional_top_up_canister : shared {
            canister_id : canister_id;
            amount : Nat;
            } -> async ();
        
        raw_rand : shared () -> async [Nat8];
        start_canister : shared { canister_id : canister_id } -> async ();
        stop_canister : shared { canister_id : canister_id } -> async ();
        uninstall_code : shared { canister_id : canister_id } -> async ();
        
        update_settings : shared {
            canister_id : Principal;
            settings : canister_settings;
            } -> async ();
    };
}

然后在A.mo中引入Types:

import Types "./Types";

二、在A.mo和B.mo中都引入以下base库文件:

import Cycles "mo:base/ExperimentalCycles"; //目前为实验版,后续会更新

并添加以下代码:

public query({caller}) func cycleBalance() : async Nat{
    Cycles.balance()
};

public shared({caller}) func wallet_receive() : async Nat {
    Cycles.accept(Cycles.available())
};

三、对ledger actor进行调用,以创建B canister:

假设B.mo大致为以下样式:

//import ...

shared({caller}) actor class B(installer : Principal) = this{
    //...
};

在A.mo中添加以下代码:(仅摘取部分代码)

import RBT "mo:base/RBTree"; //RB树的库文件
import Nat "mo:base/Nat";
import Principal "mo:base/Principal";
import B "./B.mo";

private stable var b_index : Nat = 0;
private let Bs = RBT.RBTree<Nat, Principal>(Nat.compare); //存储创建的B canister

private let IC : Types.IC.ICActor = actor "aaaaa-aa"; //ledger actor的ID
private let CYCLE_LIMIT = 1_000_000_000_000; //根据需要进行分配

//动态创建canister的函数
public shared({caller}) func createB() : async Result.Result<Principal, Text>{
        Cycles.add(CYCLE_LIMIT);
        let b = await B.B(caller);
        let principal = Principal.fromActor(b);
        await IC.update_settings({
            canister_id = principal;
            settings = {
                freezing_threshold = ?2592000;
                controllers = ?[caller]; //A不作为B的控制者的写法
                memory_allocation = ?0;
                compute_allocation = ?0;
            }
        });
        Bs.put(b_index, principal);
        b_index += 1;
        #ok(principal)
    };

完毕。

Unknown-51

A Student on the way to full stack of Web3.