create_canister function

Future<Principal> create_canister(
  1. Caller caller,
  2. IcpTokens icp_tokens, {
  3. Uint8List? from_subaccount_bytes,
  4. Nat64? block_height,
  5. String? subnet_type,
})

Creates a canister using the NNS ledger and the cycles-minting-canister.

Returns the new canister's Principal.

Transforms the icp_tokens into cycles for the canister.

Use an optional from_subaccount_bytes to use ICP in a subaccount of the caller.

This function makes two calls. One for the ICP ledger to transfer ICP-tokens to the cycles-minter-canister's account, and one for the cycles-minter-canister to trigger it to use that ICP to create a canister with cycles. A scenario can occur where the first call to transfer ICP-tokens can succeed but the second call to notify the cycles-minter-canister can fail (due to network load or similar).
In this scenario, this function will print the Nat64(block_height) of the first ICP-transfer call. Use the block_height of the first call to complete this canister-creation by calling this function again with the same caller and from_subaccount_bytes and with the block_height parameter.

When the block_height is not given, this function will make a new icp-transfer. When the block_height is given, this function will skip the first icp-transfer call, and will call the cycles-minter-canister with the given block_height.

Implementation

Future<Principal> create_canister(Caller caller, IcpTokens icp_tokens, {Uint8List? from_subaccount_bytes, Nat64? block_height, String? subnet_type}) async {
    Uint8List to_subaccount_bytes = principal_as_an_icpsubaccountbytes(caller.principal);

    if (block_height == null) {
        block_height = match_variant<Nat64>(await transfer_icp(
            caller,
            icp_id(SYSTEM_CANISTERS.cycles_mint.principal, subaccount_bytes: to_subaccount_bytes),
            icp_tokens,
            subaccount_bytes: from_subaccount_bytes,
            memo: MEMO_CREATE_CANISTER_nat64,
        ), {
            'Ok': (block_height) {
                return block_height as Nat64;
            },
            'Err': (transfer_error) {
                return match_variant<Never>(transfer_error as Variant, transfer_error_match_map);
            }
        });
        print('block_height: ${block_height.value}');
    } else {
        print('using given block_height: ${block_height.value}');
    }

    Record notifycanisterarg = Record.of_the_map({
        'controller' : caller.principal,
        'block_index' : block_height,
        'subnet_type': Option<Text>(value: subnet_type.nullmap((st)=>Text(st)), value_type: Text())
    });

    Variant notify_create_canister_result = c_backwards(await SYSTEM_CANISTERS.cycles_mint.call(
        calltype: CallType.call,
        method_name: 'notify_create_canister',
        put_bytes: c_forwards([notifycanisterarg]),
        caller: caller
    ))[0] as Variant;

    return match_variant<Principal>(notify_create_canister_result, {
        'Ok': (p) {
            return p as Principal;
        },
        'Err': (notify_error) {
            return match_variant<Never>(notify_error as Variant, cmc_notify_error_match_map);
        }
    });
}