Skip to content

Commit 01edb5d

Browse files
marc0oloclaude
andauthored
chore(motoko): bump dev-env to v2.0.0, moc to 1.14.1, mo:core to 2.6.1 (#1476)
dfinity/icp-dev-env v2.0.0 bundles mops-cli 3.1.0, which the mops-cli and writing-motoko skills now assume as a floor (moc >= 1.11.2, core >= 2.5.0). Every motoko example was below that floor (mostly moc 1.8.2-1.13.0). - Bump the dev-env container image pin (v1.2.0 -> v2.0.0) in both guarded locations: .devcontainer/devcontainer.json and _run-example.yml. - Bump moc to 1.14.1 and mo:core to 2.6.1 across all ~30 motoko mops.toml files via `mops toolchain use`/`mops add` (never hand-edited). - Fix the new compiler warnings the bump surfaced, per the writing-motoko skill: deprecated Blob/Array/Nat conversions replaced with dot-notation equivalents (.toBlob(), .toArray(), .toNat64()/.toNat8(), .toText()), redundant `persistent` on actor classes removed (verified empirically on canister_factory and composite_query that --default-persistent-actors now covers spawned actor-class sub-WASMs too, under moc 1.14.1 - state survives upgrade without the keyword), unused HTTP-outcall `context` params underscore-prefixed, `var` map bindings that are never reassigned changed to `let`, and redundant `ignore` removed from Map.remove calls (which return unit, unlike Map.insert). - Correct the AGENTS.md actor-class persistence caveat to match the verified moc 1.14.1 behavior. Left as-is (not fixed): a few `operator may trap for Nat` warnings on subtractions that are already correctly guarded by a preceding bounds check (icrc2-swap, random_maze, threshold-ecdsa/SHA256.mo) - the compiler's flow analysis can't see across the branch, but the code is safe; and an "importing Candid service constructor as instantiated service" warning on three vendored third-party .did files (icp_ledger, icrc1_ledger, evm_rpc) used via --actor-id-alias/--actor-env-alias - editing a vendored interface file to silence a new moc parsing nuance was judged out of scope here. Verified: `mops check` and `mops build` pass clean (bar the above) across all 34 motoko canisters, and full local test.sh runs pass for canister_factory and composite_query (the two actor-class-persistence examples) confirming no upgrade-state regression. Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
1 parent c73823d commit 01edb5d

63 files changed

Lines changed: 256 additions & 405 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.devcontainer/devcontainer.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ICP Examples (Motoko + Rust)",
3-
"image": "ghcr.io/dfinity/icp-dev-env-all:v1.2.0",
3+
"image": "ghcr.io/dfinity/icp-dev-env-all:v2.0.0",
44
"forwardPorts": [8000, 5173],
55
"portsAttributes": {
66
"8000": {

‎.github/workflows/_run-example.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ on:
5050
jobs:
5151
run:
5252
runs-on: ubuntu-24.04
53-
container: ghcr.io/dfinity/icp-dev-env-${{ inputs.language }}:v1.2.0
53+
container: ghcr.io/dfinity/icp-dev-env-${{ inputs.language }}:v2.0.0
5454
env:
5555
ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
5656
steps:

‎AGENTS.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ mops check # type-check all canister entry points
257257
mops check --fix # auto-fix style warnings (M0236, M0237, M0223)
258258
```
259259

260-
`--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.
260+
`--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.
261261

262262
### Naming
263263

‎motoko/backend_only/mops.toml‎

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
[toolchain]
2-
moc = "1.9.0"
2+
moc = "1.14.1"
33

44
[dependencies]
5-
core = "2.5.0"
5+
core = "2.6.1"
66

77
[moc]
8-
# M0236: use context dot notation
9-
# M0237: redundant explicit implicit arguments
10-
# M0223: redundant type instantiation
11-
args = ["--default-persistent-actors", "-W=M0236,M0237,M0223"]
8+
args = [ "--default-persistent-actors", "-W=M0236,M0237,M0223" ]
129

1310
[canisters.backend]
1411
main = "backend/main.mo"

‎motoko/basic_bitcoin/backend/BitcoinApi.mo‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1+
import Array "mo:core/Array";
12
import Types "Types";
2-
import Blob "mo:core/Blob";
33

44
module {
55
type Network = Types.Network;
@@ -116,7 +116,7 @@ module {
116116
let cost = 5_000_000_000 + transaction.size() * 20_000_000;
117117
await (with cycles = cost) bitcoinCanister(network).bitcoin_send_transaction({
118118
network;
119-
transaction = Blob.fromArray(transaction);
119+
transaction = transaction.toBlob();
120120
});
121121
};
122122
}

‎motoko/basic_bitcoin/backend/P2pkh.mo‎

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import Debug "mo:core/Debug";
1212
import Runtime "mo:core/Runtime";
1313
import Array "mo:core/Array";
14-
import Nat8 "mo:core/Nat8";
14+
import Nat "mo:core/Nat";
1515
import Nat32 "mo:core/Nat32";
1616
import Nat64 "mo:core/Nat64";
1717
import Blob "mo:core/Blob";
@@ -48,7 +48,7 @@ module {
4848
/// Returns the P2PKH address of this canister at the given derivation path.
4949
public func get_address(network : Network, key_name : Text, derivation_path : [[Nat8]]) : async BitcoinAddress {
5050
// Fetch the public key of the given derivation path.
51-
let public_key = await EcdsaApi.ecdsa_public_key(key_name, derivation_path.map(Blob.fromArray));
51+
let public_key = await EcdsaApi.ecdsa_public_key(key_name, derivation_path.map(Array.toBlob));
5252

5353
// Compute the address.
5454
public_key_to_p2pkh_address(network, public_key.toArray());
@@ -72,7 +72,7 @@ module {
7272
};
7373

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

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

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

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

9191
Debug.print("Sending transaction");
9292
await BitcoinApi.send_transaction(network, signed_transaction_bytes);
@@ -118,7 +118,7 @@ module {
118118
Debug.print("Building transaction...");
119119
var total_fee : Nat = 0;
120120
loop {
121-
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.");
121+
let transaction = Utils.get_ok_expect(Bitcoin.buildTransaction(2, own_utxos, [(dst_address_typed, amount)], #p2pkh own_address, total_fee.toNat64()), "Error building transaction.");
122122

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

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

177177
// Append the sighash type.
@@ -181,7 +181,7 @@ module {
181181
if (n < signature_der.size()) {
182182
signature_der[n];
183183
} else {
184-
Nat8.fromNat(SIGHASH_ALL.toNat());
184+
SIGHASH_ALL.toNat().toNat8();
185185
};
186186
},
187187
);

‎motoko/basic_bitcoin/backend/P2tr.mo‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import Debug "mo:core/Debug";
1717
import Runtime "mo:core/Runtime";
1818
import Array "mo:core/Array";
19-
import Nat8 "mo:core/Nat8";
19+
import Nat "mo:core/Nat";
2020
import Nat32 "mo:core/Nat32";
2121
import Nat64 "mo:core/Nat64";
2222
import Blob "mo:core/Blob";
@@ -103,7 +103,7 @@ module {
103103
var total_fee : Nat = 0;
104104

105105
loop {
106-
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.");
106+
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.");
107107
let tx_in_outpoints = transaction.txInputs.map(func(txin : TxInput.TxInput) : Types.OutPoint { txin.prevOutput });
108108

109109
let amounts = own_utxos.filterMap(
@@ -169,7 +169,7 @@ module {
169169
Nat32.fromIntWrap(i),
170170
);
171171

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

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

229-
let signature = (await signer(key_name, derivation_path, Blob.fromArray(sighash), null)).toArray();
229+
let signature = (await signer(key_name, derivation_path, sighash.toBlob(), null)).toArray();
230230
transaction.witnesses[i] := [signature, script_bytes, control_block_bytes];
231231
};
232232
};
@@ -248,7 +248,7 @@ module {
248248
let leaf_script = Utils.get_ok(leafScript(script_bip340_public_key));
249249
let aux =
250250
#bip341({
251-
merkle_root_hash = Blob.fromArray(leafHash(leaf_script));
251+
merkle_root_hash = leafHash(leaf_script).toBlob();
252252
});
253253

254254
await send_key_path_generic(own_tweaked_address, network, derivation_paths.key_path_derivation_path, key_name, ?aux, dst_address, amount);
@@ -293,7 +293,7 @@ module {
293293
},
294294
);
295295

296-
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);
296+
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);
297297

298298
Debug.print("Sending transaction : " # debug_show (signed_transaction_bytes));
299299
let signed_transaction = Utils.get_ok(Transaction.fromBytes(signed_transaction_bytes.vals()));
@@ -359,7 +359,7 @@ module {
359359
transaction,
360360
amounts,
361361
key_name,
362-
derivation_paths.script_path_derivation_path.map(Blob.fromArray),
362+
derivation_paths.script_path_derivation_path.map(Array.toBlob),
363363
SchnorrApi.sign_with_schnorr,
364364
);
365365

@@ -413,7 +413,7 @@ module {
413413
};
414414

415415
public func fetch_bip340_public_key(key_name : Text, derivation_path : [[Nat8]]) : async [Nat8] {
416-
let sec1_public_key = (await SchnorrApi.schnorr_public_key(key_name, derivation_path.map(Blob.fromArray))).toArray();
416+
let sec1_public_key = (await SchnorrApi.schnorr_public_key(key_name, derivation_path.map(Array.toBlob))).toArray();
417417
sec1_public_key.sliceToArray(1, 33);
418418
};
419419
};

‎motoko/basic_bitcoin/backend/P2trKeyOnly.mo‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@
1010
//! * Caching spent UTXOs so that they are not reused in future transactions.
1111
//! * Option to set the fee.
1212

13-
import Nat8 "mo:core/Nat8";
14-
import Blob "mo:core/Blob";
13+
import Array "mo:core/Array";
1514

1615
import Script "mo:bitcoin/bitcoin/Script";
1716
import Transaction "mo:bitcoin/bitcoin/Transaction";
@@ -38,7 +37,7 @@ module {
3837
let untweaked_bip340_public_key_bytes = await P2tr.fetch_bip340_public_key(key_name, derivation_path);
3938
let aux =
4039
#bip341({
41-
merkle_root_hash = Blob.fromArray(P2tr.unspendableMerkleRoot(untweaked_bip340_public_key_bytes));
40+
merkle_root_hash = P2tr.unspendableMerkleRoot(untweaked_bip340_public_key_bytes).toBlob();
4241
});
4342
await P2tr.send_key_path_generic(own_address, network, derivation_path, key_name, ?aux, dst_address, amount);
4443
};

‎motoko/basic_bitcoin/backend/Utils.mo‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import Result "mo:core/Result";
22
import Nat8 "mo:core/Nat8";
33
import Runtime "mo:core/Runtime";
4+
import Char "mo:core/Char";
45
import Text "mo:core/Text";
56
import Iter "mo:core/Iter";
6-
import Blob "mo:core/Blob";
77
import Array "mo:core/Array";
88
import IC "mo:ic/Types";
99

@@ -39,7 +39,7 @@ module {
3939

4040
// Returns the hexadecimal representation of a `Nat8` considered as a `Nat4`.
4141
func nat4ToText(nat4 : Nat8) : Text {
42-
Text.fromChar(
42+
(
4343
switch nat4 {
4444
case 0 '0';
4545
case 1 '1';
@@ -59,7 +59,7 @@ module {
5959
case 15 'f';
6060
case _ Runtime.unreachable();
6161
}
62-
);
62+
).toText();
6363
};
6464

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

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

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

8484
/// Mock Schnorr signer that returns a 64-byte placeholder signature.
8585
/// Used only during fee estimation to get the correct transaction size
8686
/// before invoking the real (expensive) threshold signing operation.
8787
public func mock_sign_with_schnorr(_key_name : Text, _derivation_path : [Blob], _message_hash : Blob, _aux : ?SchnorrAux) : async Blob {
88-
Blob.fromArray(Array.repeat(255 : Nat8, 64));
88+
Array.repeat(255 : Nat8, 64).toBlob();
8989
};
9090
};

‎motoko/basic_bitcoin/mops.toml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
[toolchain]
2-
moc = "1.9.0"
2+
moc = "1.14.1"
33

44
[dependencies]
5-
core = "2.5.0"
5+
core = "2.6.1"
66
bitcoin = "0.2.0"
77
ic = "4.0.0"
88

0 commit comments

Comments
 (0)