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
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ CI (`.github/workflows/mops-test.yml`) runs `mops install` then `mops test` on p

- **`src/Types.mo` is generated — never hand-edit it.** It carries a `// This is a generated Motoko binding.` header. Add helpers to `src/lib.mo` or a new sibling module instead. See `REGENERATING.md` for the full regeneration flow.
- Regeneration produces `PascalCase` type names (field and method names stay `snake_case`) via `scripts/pascal_types.py`. Regenerating requires `didc` ≥ 0.6.x.
- Tool versions are pinned in `mops.toml`: toolchain `moc = 1.7.0`, minimum requirement `moc = 1.4.0`.
- `[moc].args` in `mops.toml` sets compiler flags (e.g. `--default-persistent-actors`); keep them when running `moc` manually.
- Tool versions are pinned in `mops.toml`: toolchain `moc = 2.1.0`, minimum requirement `moc = 1.4.0`.
- `[moc].args` in `mops.toml` sets compiler flags (e.g. `-W=M0223,M0236,M0237`); keep them when running `moc` manually. `moc` 2.0 rejects `--default-persistent-actors` (actors are persistent by default).
- The public consumer pattern is `import { ic } "mo:ic";` and `import IC "mo:ic/Types";` — stable across regenerations, don't change casually.
- `.mops/` and `mops.lock` are gitignored (generated by `mops install`).
- Publishing is automatic: bumping `[package].version` in `mops.toml` on `master` triggers `mops-publish.yml`, which publishes and tags the release. Don't run `mops publish` by hand.
Expand Down
41 changes: 41 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,44 @@
## 5.0.0

Regenerated from the upstream Candid spec through interface spec 0.70.0 (dfinity/developer-docs#394, #333, #254, #252, #346, #315, #302). Motoko record literals must name every field, so the new input/status fields below are breaking even though they are optional in Candid.

### Migration

Hand-built `IC.HttpRequestArgs`, `IC.CanisterSettings`, `IC.FetchCanisterLogsArgs`, and `CanisterStatusResult.memory_metrics` literals need the new fields (use `null` for optional ones):

```motoko
// before
let request : IC.HttpRequestArgs = { url; method; headers; body; max_response_bytes; transform; is_replicated };

// after
let request : IC.HttpRequestArgs = { url; method; headers; body; max_response_bytes; transform; is_replicated; pricing_version = null };
```

`Call.httpRequest` is unchanged: it still takes `IC.HttpRequestArgs` and still attaches the version-1 (`ic0.cost_http_request`) cost. Pass `pricing_version = ?2` only after computing and attaching a version-2 reservation yourself. `moc` 2.1.0 exposes `Prim.costHttpRequestV2` (`ic0.cost_http_request_v2`); this package does not call it.

`IC.StatusVisibility` spells the Candid `public` case as `#public_` (Motoko reserved word).

### Breaking changes

- `CanisterSettings` / `DefiniteCanisterSettings`: added `minimum_incoming_canister_call_cycles` (spec 0.64.0, dfinity/developer-docs#302), `log_memory_limit` (spec 0.67.0, dfinity/developer-docs#252), `status_visibility` (spec 0.65.0, dfinity/developer-docs#315).
- `HttpRequestArgs`: added `pricing_version : ?Nat32` — `1` (legacy, default, deprecated) or `2` (pay-as-you-go). Spec 0.68.0, dfinity/developer-docs#254.
- `FetchCanisterLogsArgs`: added `filter : ?{ #by_idx; #by_timestamp_nanos }` (spec 0.67.0, dfinity/developer-docs#252).
- `CanisterStatusResult.memory_metrics`: added `log_memory_store_size : Nat` (spec 0.67.0).

### Additive changes

- New types: `StatusVisibility`, `FlexibleHttpRequestArgs`, `FlexibleHttpRequestErr`, `FlexibleHttpRequestResult`, `HttpRequestResourceReport`, `SubnetMetricsArgs`, `SubnetMetricsResult`.
- New method: `ic.flexible_http_request` — committee of nodes return individual HTTP responses instead of subnet consensus (spec 0.68.0, dfinity/developer-docs#254).
- New method: `ic.subnet_metrics` (update) — subnet-wide metrics for a subnet: `block_height`, `num_canisters`, `canister_state_bytes`, `consumed_cycles_total`, `update_transactions_total`, and `million_round_instructions_total` (instructions in units of one million, rounded up). Experimental. Spec 0.69.0, dfinity/developer-docs#333.
- `EcdsaCurve` gains `#secp256r1` (threshold ECDSA on NIST P-256; signatures and SLIP-10 derivation match `secp256k1`). `Call.Cost.signWithEcdsa` maps it to `1`, the `ic0.cost_sign_with_ecdsa` curve argument. Spec 0.70.0, dfinity/developer-docs#394. Exhaustive `switch`es on `EcdsaCurve` must handle the new case; constructing `#secp256k1` is unchanged.
- `canister_info` is now a query method on `Types.Self` (spec 0.67.0, dfinity/developer-docs#346); inter-canister update calls still work.

### Housekeeping

- Refreshed `did/ic.did` from `dfinity/developer-docs` main (spec 0.64.0–0.70.0).
- `REGENERATING.md`: install `didc` 0.6.2 from the GitHub release instead of building from source.
- `[toolchain] moc` raised to `2.1.0`. `[requirements] moc` stays `1.4.0` (`Float32`). Dropped `--default-persistent-actors` from `[moc].args` (`moc` 2.0 removes the flag; actors are persistent by default). `Call.Cost.httpRequest` uses `Array.values()` instead of the `.vals()` that `moc` 1.16 deprecates (`M0269`).

## 4.2.0

### Additive changes
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,13 @@ let settings : IC.CanisterSettings = {
freezing_threshold = null;
reserved_cycles_limit = null;
log_visibility = null;
log_memory_limit = null;
snapshot_visibility = null;
wasm_memory_limit = null;
wasm_memory_threshold = null;
environment_variables = null;
minimum_incoming_canister_call_cycles = null;
status_visibility = null;
};
await ic.update_settings({
canister_id = canisterId;
Expand Down
13 changes: 9 additions & 4 deletions REGENERATING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@

How to update `src/Types.mo` when `did/ic.did` changes upstream.

Requires `didc` ≥ 0.6.x for `Float32` support. As of 2026-06-11 the released binary is 0.5.4 (lacks `Float32`); build from source:
Requires `didc` ≥ 0.6.x for `Float32` support. The current release is [didc 0.6.2](https://github.com/dfinity/candid/releases/tag/didc-v0.6.2) (2026-06-25); install a GitHub-release binary rather than building from source:

```bash
git clone --depth 1 https://github.com/dfinity/candid.git /tmp/candid-src
cargo build --release --manifest-path /tmp/candid-src/Cargo.toml -p didc
# binary at /tmp/candid-src/target/release/didc
# Linux x86_64
curl -fsSL -o /tmp/didc.tar.xz \
https://github.com/dfinity/candid/releases/download/didc-v0.6.2/didc-x86_64-unknown-linux-gnu.tar.xz
tar -xJf /tmp/didc.tar.xz -C /tmp
# binary at /tmp/didc-x86_64-unknown-linux-gnu/didc

# macOS Apple Silicon
# https://github.com/dfinity/candid/releases/download/didc-v0.6.2/didc-aarch64-apple-darwin.tar.xz
```

**Note on naming:** `didc bind --target mo` outputs `snake_case` type names. The canonical `src/Types.mo` uses `PascalCase` for type names (field names and method names stay `snake_case`). The TL;DR and steps below include the conversion.
Expand Down
118 changes: 116 additions & 2 deletions did/ic.did
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@ type snapshot_visibility = variant {
allowed_viewers : vec principal;
};

type environment_variable = record {
type status_visibility = variant {
controllers;
public;
allowed_viewers : vec principal;
};

type environment_variable = record {
name: text;
value: text;
};
Expand All @@ -25,8 +31,11 @@ type canister_settings = record {
memory_allocation : opt nat;
freezing_threshold : opt nat;
reserved_cycles_limit : opt nat;
minimum_incoming_canister_call_cycles : opt nat;
log_visibility : opt log_visibility;
log_memory_limit : opt nat;
snapshot_visibility : opt snapshot_visibility;
status_visibility : opt status_visibility;
wasm_memory_limit : opt nat;
wasm_memory_threshold : opt nat;
environment_variables : opt vec environment_variable;
Expand All @@ -38,8 +47,11 @@ type definite_canister_settings = record {
memory_allocation : nat;
freezing_threshold : nat;
reserved_cycles_limit : nat;
minimum_incoming_canister_call_cycles : nat;
log_visibility : log_visibility;
log_memory_limit : nat;
snapshot_visibility : snapshot_visibility;
status_visibility : status_visibility;
wasm_memory_limit : nat;
wasm_memory_threshold : nat;
environment_variables : vec environment_variable;
Expand Down Expand Up @@ -112,8 +124,37 @@ type http_request_result = record {
body : blob;
};

type http_request_resource_report = record {
raw_response_bytes : opt variant { used : nat64; exceeded : reserved };
http_roundtrip_time_ms : opt variant { used : nat64; exceeded : reserved };
transform_instructions : opt variant { used : nat64; exceeded : reserved };
transformed_response_bytes : opt variant { used : nat64; exceeded : reserved };
cycles : opt variant { used : nat; exceeded : reserved };
};

type flexible_http_request_err = record {
global_error : opt variant {
timeout : reserved;
out_of_cycles : reserved;
responses_too_large : reserved;
too_many_rejects : reserved;
};
node_details : vec record {
node_id : principal;
report : http_request_resource_report;
error : opt record { code : text; message : text };
};
message : text;
};

type flexible_http_request_result = variant {
ok : vec http_request_result;
err : flexible_http_request_err;
};

type ecdsa_curve = variant {
secp256k1;
secp256r1;
};

type vetkd_curve = variant {
Expand Down Expand Up @@ -300,6 +341,7 @@ type canister_status_result = record {
canister_history_size : nat;
wasm_chunk_store_size : nat;
snapshots_size : nat;
log_memory_store_size : nat;
};
cycles : nat;
reserved_cycles : nat;
Expand Down Expand Up @@ -352,6 +394,24 @@ type http_request_args = record {
context : blob;
};
is_replicated : opt bool;
pricing_version : opt nat32;
};

type flexible_http_request_args = record {
url : text;
max_response_bytes : opt nat64;
method : variant { get; head; post; put; delete; patch };
headers : vec http_header;
body : opt blob;
transform : opt record {
function : func(record { response : http_request_result; context : blob }) -> (http_request_result) query;
context : blob;
};
replication : opt record {
min_responses : nat32;
max_responses : nat32;
total_requests : nat32;
};
};

type ecdsa_public_key_args = record {
Expand Down Expand Up @@ -434,6 +494,54 @@ type node_metrics_history_result = vec record {
node_metrics : vec node_metrics;
};

type subnet_metrics_args = record {
subnet_id : principal;
};

// Only `block_height` describes the block in whose execution the call is
// processed. The other five fields are aggregates refreshed at block
// boundaries, so they describe the subnet as of an earlier block, and they are
// not all refreshed at the same rate; see the individual fields.
type subnet_metrics_result = record {
// Current block height of the subnet, i.e. the height of the block in
// whose execution this call is processed. Monotonically non-decreasing for
// a given subnet; the heights of different subnets are unrelated.
block_height : nat;
// Number of canisters on the subnet. A current value, not a counter.
num_canisters : nat;
// Total size in bytes of the state taken by canisters on the subnet. A
// current value, not a counter. Recomputing it is expensive, so it is
// refreshed only every 10 blocks, at heights that are multiples of 10. It
// can be up to 10 blocks behind block_height and up to 9 blocks behind the
// other aggregates. Reads 0 until the first refresh after subnet creation.
canister_state_bytes : nat;
// Total nominal cycles accounted for by the subnet: the historical
// consumption of current and deleted canisters (plus the remaining balances
// of deleted canisters), the cycles charged for HTTPS outcalls, threshold
// signature requests, and vetKD requests (accounted for at the subnet level
// rather than per canister), and the cycles lost when messages or refunds
// are dropped (e.g. because their recipient no longer exists). Resource use
// is recorded at normal cost-schedule rates even where it is free, so this
// is not a count of cycles burned. Refunds of prepaid charges reduce the
// total. Subnet splitting redistributes canisters' histories, so the total
// can decrease and can include consumption from before the receiving subnet
// was created.
consumed_cycles_total : nat;
// Total number of transactions processed on the subnet, i.e. the total
// number of messages executed in the replicated mode. Monotonically
// non-decreasing.
update_transactions_total : nat;
// Total instructions the subnet accounted for when executing its blocks,
// in units of one million and rounded up: a value of 42 represents
// 41,000,001 through 42,000,000 instructions. Besides the executed Wasm
// instructions, it covers the fixed per-execution and per-canister
// overheads charged by the scheduler and the charges for work performed
// outside of Wasm execution, so it is not a Wasm instruction meter.
// Monotonically non-decreasing. Like `block_height`, it has no counterpart
// under `/subnet/<subnet_id>/metrics` in the certified state tree.
million_round_instructions_total : nat;
};

type subnet_info_args = record {
subnet_id : principal;
};
Expand Down Expand Up @@ -499,6 +607,10 @@ type delete_canister_snapshot_args = record {

type fetch_canister_logs_args = record {
canister_id : canister_id;
filter : opt variant {
by_idx : record { start : nat64; end : nat64 };
by_timestamp_nanos : record { start : nat64; end : nat64 };
};
};

type canister_log_record = record {
Expand Down Expand Up @@ -672,9 +784,10 @@ service ic : {
deposit_cycles : (deposit_cycles_args) -> ();
raw_rand : () -> (raw_rand_result);
http_request : (http_request_args) -> (http_request_result);
flexible_http_request : (flexible_http_request_args) -> (flexible_http_request_result);

// Public canister data
canister_info : (canister_info_args) -> (canister_info_result);
canister_info : (canister_info_args) -> (canister_info_result) query;
canister_metadata : (canister_metadata_args) -> (canister_metadata_result);

// Threshold ECDSA signature
Expand All @@ -698,6 +811,7 @@ service ic : {

// metrics interface
node_metrics_history : (node_metrics_history_args) -> (node_metrics_history_result);
subnet_metrics : (subnet_metrics_args) -> (subnet_metrics_result);

// subnet info
subnet_info : (subnet_info_args) -> (subnet_info_result);
Expand Down
6 changes: 3 additions & 3 deletions mops.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ic"
version = "4.2.0"
version = "5.0.0"
description = "IC management canister interface (aaaaa-aa)"
repository = "https://github.com/caffeinelabs/mops-ic"
keywords = ["ic", "types", "interface", "http"]
Expand All @@ -13,10 +13,10 @@ core = "2.5.0"
moc = "1.4.0"

[toolchain]
moc = "1.7.0"
moc = "2.1.0"

[dev-dependencies]
test = "2.1.2"

[moc]
args = ["--default-persistent-actors", "-W=M0223,M0236,M0237"]
args = ["-W=M0223,M0236,M0237"]
3 changes: 2 additions & 1 deletion src/Call.mo
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ module {
public func signWithEcdsa(keyName : Text, curve : IC.EcdsaCurve) : Result<Nat, SignError> {
let curveEncoding : Nat32 = switch (curve) {
case (#secp256k1) 0;
case (#secp256r1) 1;
};
let (code, cyclesOrArbitrary) = Prim.costSignWithEcdsa(keyName, curveEncoding);
switch (code) {
Expand Down Expand Up @@ -118,7 +119,7 @@ module {
size += Prim.natToNat64(request.url.size());

// Add headers byte length (sum of all names and values)
for (header in request.headers.vals()) {
for (header in request.headers.values()) {
size += Prim.natToNat64(header.name.size());
size += Prim.natToNat64(header.value.size());
};
Expand Down
Loading
Loading