Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ICP Examples (Motoko + Rust)",
"image": "ghcr.io/dfinity/icp-dev-env-all:v1.2.0",
"image": "ghcr.io/dfinity/icp-dev-env-all:v2.0.0",
"forwardPorts": [8000, 5173],
"portsAttributes": {
"8000": {
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/_run-example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ on:
jobs:
run:
runs-on: ubuntu-24.04
container: ghcr.io/dfinity/icp-dev-env-${{ inputs.language }}:v1.2.0
container: ghcr.io/dfinity/icp-dev-env-${{ inputs.language }}:v2.0.0
env:
ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ mops check # type-check all canister entry points
mops check --fix # auto-fix style warnings (M0236, M0237, M0223)
```

`--default-persistent-actors` makes the **main actor** persistent by default, so the `persistent` keyword is omitted on the top-level `actor` declaration. `persistent actor class` declarations holding mutable state must still carry the keyword explicitly — the flag does not propagate into actor class sub-WASMs.
`--default-persistent-actors` makes every actor persistent by default, including spawned `actor class` sub-WASMs — so the `persistent` keyword is omitted everywhere: on the top-level `actor` declaration and on `actor class` declarations alike (verified with `moc` 1.14.1: an `actor class` holding mutable `var` fields compiles and preserves state across `#upgrade` without the keyword, under this flag). If `moc` warns `M0217` ("the `persistent` keyword is redundant") on an `actor class`, remove it rather than keeping it "to be safe" — it is genuinely redundant.

### Naming

Expand Down
9 changes: 3 additions & 6 deletions motoko/backend_only/mops.toml
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
[toolchain]
moc = "1.9.0"
moc = "1.14.1"

[dependencies]
core = "2.5.0"
core = "2.6.1"

[moc]
# M0236: use context dot notation
# M0237: redundant explicit implicit arguments
# M0223: redundant type instantiation
args = ["--default-persistent-actors", "-W=M0236,M0237,M0223"]
args = [ "--default-persistent-actors", "-W=M0236,M0237,M0223" ]

[canisters.backend]
main = "backend/main.mo"
4 changes: 2 additions & 2 deletions motoko/basic_bitcoin/backend/BitcoinApi.mo
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Array "mo:core/Array";
import Types "Types";
import Blob "mo:core/Blob";

module {
type Network = Types.Network;
Expand Down Expand Up @@ -116,7 +116,7 @@ module {
let cost = 5_000_000_000 + transaction.size() * 20_000_000;
await (with cycles = cost) bitcoinCanister(network).bitcoin_send_transaction({
network;
transaction = Blob.fromArray(transaction);
transaction = transaction.toBlob();
});
};
}
18 changes: 9 additions & 9 deletions motoko/basic_bitcoin/backend/P2pkh.mo
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import Debug "mo:core/Debug";
import Runtime "mo:core/Runtime";
import Array "mo:core/Array";
import Nat8 "mo:core/Nat8";
import Nat "mo:core/Nat";
import Nat32 "mo:core/Nat32";
import Nat64 "mo:core/Nat64";
import Blob "mo:core/Blob";
Expand Down Expand Up @@ -48,7 +48,7 @@ module {
/// Returns the P2PKH address of this canister at the given derivation path.
public func get_address(network : Network, key_name : Text, derivation_path : [[Nat8]]) : async BitcoinAddress {
// Fetch the public key of the given derivation path.
let public_key = await EcdsaApi.ecdsa_public_key(key_name, derivation_path.map(Blob.fromArray));
let public_key = await EcdsaApi.ecdsa_public_key(key_name, derivation_path.map(Array.toBlob));

// Compute the address.
public_key_to_p2pkh_address(network, public_key.toArray());
Expand All @@ -72,7 +72,7 @@ module {
};

// Fetch our public key, P2PKH address, and UTXOs.
let own_public_key = (await EcdsaApi.ecdsa_public_key(key_name, derivation_path.map(Blob.fromArray))).toArray();
let own_public_key = (await EcdsaApi.ecdsa_public_key(key_name, derivation_path.map(Array.toBlob))).toArray();
let own_address = public_key_to_p2pkh_address(network, own_public_key);

// Note that pagination may have to be used to get all UTXOs for the given address.
Expand All @@ -82,11 +82,11 @@ module {

// Build the transaction that sends `amount` to the destination address.
let tx_bytes = await build_transaction(own_public_key, own_address, own_utxos, dst_address, amount, fee_per_vbyte);
let transaction = Utils.get_ok(Transaction.fromBytes(tx_bytes.vals()));
let transaction = Utils.get_ok(Transaction.fromBytes(tx_bytes.values()));

// Sign the transaction.
let signed_transaction_bytes = await sign_transaction(own_public_key, own_address, transaction, key_name, derivation_path.map(Blob.fromArray), EcdsaApi.sign_with_ecdsa);
let signed_transaction = Utils.get_ok(Transaction.fromBytes(signed_transaction_bytes.vals()));
let signed_transaction_bytes = await sign_transaction(own_public_key, own_address, transaction, key_name, derivation_path.map(Array.toBlob), EcdsaApi.sign_with_ecdsa);
let signed_transaction = Utils.get_ok(Transaction.fromBytes(signed_transaction_bytes.values()));

Debug.print("Sending transaction");
await BitcoinApi.send_transaction(network, signed_transaction_bytes);
Expand Down Expand Up @@ -118,7 +118,7 @@ module {
Debug.print("Building transaction...");
var total_fee : Nat = 0;
loop {
let transaction = Utils.get_ok_expect(Bitcoin.buildTransaction(2, own_utxos, [(dst_address_typed, amount)], #p2pkh own_address, Nat64.fromNat(total_fee)), "Error building transaction.");
let transaction = Utils.get_ok_expect(Bitcoin.buildTransaction(2, own_utxos, [(dst_address_typed, amount)], #p2pkh own_address, total_fee.toNat64()), "Error building transaction.");

// Sign the transaction. We only care about the size of the signed
// transaction for fee estimation, so we use a mock signer here for efficiency.
Expand Down Expand Up @@ -171,7 +171,7 @@ module {
SIGHASH_ALL,
);

let signature_sec = await signer(key_name, derivation_path, Blob.fromArray(sighash));
let signature_sec = await signer(key_name, derivation_path, sighash.toBlob());
let signature_der = Der.encodeSignature(signature_sec).toArray();

// Append the sighash type.
Expand All @@ -181,7 +181,7 @@ module {
if (n < signature_der.size()) {
signature_der[n];
} else {
Nat8.fromNat(SIGHASH_ALL.toNat());
SIGHASH_ALL.toNat().toNat8();
};
},
);
Expand Down
16 changes: 8 additions & 8 deletions motoko/basic_bitcoin/backend/P2tr.mo
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import Debug "mo:core/Debug";
import Runtime "mo:core/Runtime";
import Array "mo:core/Array";
import Nat8 "mo:core/Nat8";
import Nat "mo:core/Nat";
import Nat32 "mo:core/Nat32";
import Nat64 "mo:core/Nat64";
import Blob "mo:core/Blob";
Expand Down Expand Up @@ -103,7 +103,7 @@ module {
var total_fee : Nat = 0;

loop {
let transaction = Utils.get_ok_expect(Bitcoin.buildTransaction(2, own_utxos, [(dst_address_typed, amount)], #p2tr_key own_address, Nat64.fromNat(total_fee)), "Error building transaction.");
let transaction = Utils.get_ok_expect(Bitcoin.buildTransaction(2, own_utxos, [(dst_address_typed, amount)], #p2tr_key own_address, total_fee.toNat64()), "Error building transaction.");
let tx_in_outpoints = transaction.txInputs.map(func(txin : TxInput.TxInput) : Types.OutPoint { txin.prevOutput });

let amounts = own_utxos.filterMap(
Expand Down Expand Up @@ -169,7 +169,7 @@ module {
Nat32.fromIntWrap(i),
);

let signature = (await signer(key_name, derivation_path, Blob.fromArray(sighash), aux)).toArray();
let signature = (await signer(key_name, derivation_path, sighash.toBlob(), aux)).toArray();
transaction.witnesses[i] := [signature];
};
};
Expand Down Expand Up @@ -226,7 +226,7 @@ module {

Debug.print("Signing sighash: " # debug_show (sighash));

let signature = (await signer(key_name, derivation_path, Blob.fromArray(sighash), null)).toArray();
let signature = (await signer(key_name, derivation_path, sighash.toBlob(), null)).toArray();
transaction.witnesses[i] := [signature, script_bytes, control_block_bytes];
};
};
Expand All @@ -248,7 +248,7 @@ module {
let leaf_script = Utils.get_ok(leafScript(script_bip340_public_key));
let aux =
#bip341({
merkle_root_hash = Blob.fromArray(leafHash(leaf_script));
merkle_root_hash = leafHash(leaf_script).toBlob();
});

await send_key_path_generic(own_tweaked_address, network, derivation_paths.key_path_derivation_path, key_name, ?aux, dst_address, amount);
Expand Down Expand Up @@ -293,7 +293,7 @@ module {
},
);

let signed_transaction_bytes = await sign_key_spend_transaction(own_address, transaction, amounts, key_name, signer_derivation_path.map(Blob.fromArray), aux, SchnorrApi.sign_with_schnorr);
let signed_transaction_bytes = await sign_key_spend_transaction(own_address, transaction, amounts, key_name, signer_derivation_path.map(Array.toBlob), aux, SchnorrApi.sign_with_schnorr);

Debug.print("Sending transaction : " # debug_show (signed_transaction_bytes));
let signed_transaction = Utils.get_ok(Transaction.fromBytes(signed_transaction_bytes.vals()));
Expand Down Expand Up @@ -359,7 +359,7 @@ module {
transaction,
amounts,
key_name,
derivation_paths.script_path_derivation_path.map(Blob.fromArray),
derivation_paths.script_path_derivation_path.map(Array.toBlob),
SchnorrApi.sign_with_schnorr,
);

Expand Down Expand Up @@ -413,7 +413,7 @@ module {
};

public func fetch_bip340_public_key(key_name : Text, derivation_path : [[Nat8]]) : async [Nat8] {
let sec1_public_key = (await SchnorrApi.schnorr_public_key(key_name, derivation_path.map(Blob.fromArray))).toArray();
let sec1_public_key = (await SchnorrApi.schnorr_public_key(key_name, derivation_path.map(Array.toBlob))).toArray();
sec1_public_key.sliceToArray(1, 33);
};
};
5 changes: 2 additions & 3 deletions motoko/basic_bitcoin/backend/P2trKeyOnly.mo
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@
//! * Caching spent UTXOs so that they are not reused in future transactions.
//! * Option to set the fee.

import Nat8 "mo:core/Nat8";
import Blob "mo:core/Blob";
import Array "mo:core/Array";

import Script "mo:bitcoin/bitcoin/Script";
import Transaction "mo:bitcoin/bitcoin/Transaction";
Expand All @@ -38,7 +37,7 @@ module {
let untweaked_bip340_public_key_bytes = await P2tr.fetch_bip340_public_key(key_name, derivation_path);
let aux =
#bip341({
merkle_root_hash = Blob.fromArray(P2tr.unspendableMerkleRoot(untweaked_bip340_public_key_bytes));
merkle_root_hash = P2tr.unspendableMerkleRoot(untweaked_bip340_public_key_bytes).toBlob();
});
await P2tr.send_key_path_generic(own_address, network, derivation_path, key_name, ?aux, dst_address, amount);
};
Expand Down
12 changes: 6 additions & 6 deletions motoko/basic_bitcoin/backend/Utils.mo
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import Result "mo:core/Result";
import Nat8 "mo:core/Nat8";
import Runtime "mo:core/Runtime";
import Char "mo:core/Char";
import Text "mo:core/Text";
import Iter "mo:core/Iter";
import Blob "mo:core/Blob";
import Array "mo:core/Array";
import IC "mo:ic/Types";

Expand Down Expand Up @@ -39,7 +39,7 @@ module {

// Returns the hexadecimal representation of a `Nat8` considered as a `Nat4`.
func nat4ToText(nat4 : Nat8) : Text {
Text.fromChar(
(
switch nat4 {
case 0 '0';
case 1 '1';
Expand All @@ -59,7 +59,7 @@ module {
case 15 'f';
case _ Runtime.unreachable();
}
);
).toText();
};

/// Returns the hexadecimal representation of a `Nat8`.
Expand All @@ -71,20 +71,20 @@ module {

/// Returns the hexadecimal representation of a byte array.
public func bytesToText(bytes : [Nat8]) : Text {
bytes.vals().map(func(n : Nat8) : Text { nat8ToText(n) }).join("");
bytes.values().map(func(n : Nat8) : Text { nat8ToText(n) }).join("");
};

/// Mock ECDSA signer that returns a 64-byte placeholder signature.
/// Used only during fee estimation to get the correct transaction size
/// before invoking the real (expensive) threshold signing operation.
public func mock_sign_with_ecdsa(_key_name : Text, _derivation_path : [Blob], _message_hash : Blob) : async Blob {
Blob.fromArray(Array.repeat(255 : Nat8, 64));
Array.repeat(255 : Nat8, 64).toBlob();
};

/// Mock Schnorr signer that returns a 64-byte placeholder signature.
/// Used only during fee estimation to get the correct transaction size
/// before invoking the real (expensive) threshold signing operation.
public func mock_sign_with_schnorr(_key_name : Text, _derivation_path : [Blob], _message_hash : Blob, _aux : ?SchnorrAux) : async Blob {
Blob.fromArray(Array.repeat(255 : Nat8, 64));
Array.repeat(255 : Nat8, 64).toBlob();
};
};
4 changes: 2 additions & 2 deletions motoko/basic_bitcoin/mops.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
[toolchain]
moc = "1.9.0"
moc = "1.14.1"

[dependencies]
core = "2.5.0"
core = "2.6.1"
bitcoin = "0.2.0"
ic = "4.0.0"

Expand Down
2 changes: 1 addition & 1 deletion motoko/canister_factory/backend/Counter.mo
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// Simple counter actor class with mutable state for demonstrating upgrade vs reinstall behavior.
/// State is preserved during #upgrade but reset to 42 during #reinstall.
persistent actor class Counter() {
actor class Counter() {
var value : Nat = 42;
public func getValue() : async Nat { value };
public func addToValue(x : Nat) : async Nat {
Expand Down
2 changes: 1 addition & 1 deletion motoko/canister_factory/backend/CounterV2.mo
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/// Extended counter actor class used for upgrade/reinstall demonstrations.
/// Adds `substractFromValue` to show new functionality introduced after an upgrade.
/// State is preserved during #upgrade but reset to 42 during #reinstall.
persistent actor class CounterV2() {
actor class CounterV2() {
var value : Nat = 42;
public func getValue() : async Nat { value };
public func addToValue(x : Nat) : async Nat {
Expand Down
9 changes: 3 additions & 6 deletions motoko/canister_factory/mops.toml
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
[toolchain]
moc = "1.9.0"
moc = "1.14.1"

[dependencies]
core = "2.5.0"
core = "2.6.1"
ic = "4.0.0"

[moc]
# M0236: use context dot notation (e.g. x.toText() instead of Nat.toText(x))
# M0237: redundant explicit implicit arguments (e.g. Nat.compare is inferred automatically)
# M0223: redundant type instantiation (e.g. Array.tabulate instead of Array.tabulate<T>)
args = ["--default-persistent-actors", "-W=M0236,M0237,M0223"]
args = [ "--default-persistent-actors", "-W=M0236,M0237,M0223" ]

[canisters.backend]
main = "backend/main.mo"
2 changes: 1 addition & 1 deletion motoko/canister_logs/backend/main.mo
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { now } = "mo:core/Time";
import { setTimer; recurringTimer } = "mo:core/Timer";
import { ic } "mo:ic";

persistent actor CanisterLogs {
actor CanisterLogs {

transient let timerDelaySeconds = 5;
transient let second = 1_000_000_000;
Expand Down
9 changes: 3 additions & 6 deletions motoko/canister_logs/mops.toml
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
[toolchain]
moc = "1.9.0"
moc = "1.14.1"

[dependencies]
core = "2.5.0"
core = "2.6.1"
ic = "4.0.0"

[moc]
# M0236: use context dot notation
# M0237: redundant explicit implicit arguments
# M0223: redundant type instantiation
args = ["--default-persistent-actors", "-W=M0236,M0237,M0223"]
args = [ "--default-persistent-actors", "-W=M0236,M0237,M0223" ]

[canisters.backend]
main = "backend/main.mo"
6 changes: 3 additions & 3 deletions motoko/cert-var/backend/main.mo
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
/// system-level certified-data hash so that query callers can cryptographically
/// verify the returned value without waiting for a full consensus round.
import CD "mo:core/CertifiedData";
import Blob "mo:core/Blob";
import Array "mo:core/Array";
import Nat32 "mo:core/Nat32";

actor CertVar {
Expand All @@ -17,12 +17,12 @@ actor CertVar {
func blobOfNat32(n : Nat32) : Blob {
let byteMask : Nat32 = 0xff;
func byte(x : Nat32) : Nat8 = x.toNat8();
Blob.fromArray([
[
byte(((byteMask << 0) & n) >> 0),
byte(((byteMask << 8) & n) >> 8),
byte(((byteMask << 16) & n) >> 16),
byte(((byteMask << 24) & n) >> 24),
]);
].toBlob();
};

/// Increment the counter by one, update the certificate, and return the new value.
Expand Down
9 changes: 3 additions & 6 deletions motoko/cert-var/mops.toml
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
[toolchain]
moc = "1.9.0"
moc = "1.14.1"

[dependencies]
core = "2.5.0"
core = "2.6.1"

[moc]
# M0236: use context dot notation
# M0237: redundant explicit implicit arguments
# M0223: redundant type instantiation
args = ["--default-persistent-actors", "-W=M0236,M0237,M0223"]
args = [ "--default-persistent-actors", "-W=M0236,M0237,M0223" ]

[canisters.backend]
main = "backend/main.mo"
Expand Down
2 changes: 1 addition & 1 deletion motoko/composite_query/backend/Buckets.mo
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Map "mo:core/Map";
import Nat "mo:core/Nat";

persistent actor class Bucket(n : Nat, i : Nat) {
actor class Bucket(n : Nat, i : Nat) {

type Key = Nat;
type Value = Text;
Expand Down
Loading
Loading