Repository navigation
feat!: sync ic.did to spec 0.70.0 with pay-as-you-go pricing_version (5.0.0) - #17
Merged
Merged
Conversation
Regenerate Types.mo from the upstream management canister interface through spec 0.68.0. New record fields are breaking in Motoko because literals must name every field. Call.httpRequest is unchanged and still attaches the version-1 cost. Co-authored-by: Kamil Listopad <listopadkamil@gmail.com>
The 0.6.2 binary has Float32 support; stop telling people to build from source. Also record the moc 1.16.1 toolchain pin in AGENTS.md. Co-authored-by: Kamil Listopad <listopadkamil@gmail.com>
moc 1.16 warns M0269 on .vals(); the headers walk in Cost.httpRequest now uses .values(). Co-authored-by: Kamil Listopad <listopadkamil@gmail.com>
Kamirus
added a commit
that referenced
this pull request
Oct 9, 2026
The next version bump will fail to publish. `mops publish` runs the test suite, and `mops-publish.yml` still installs the latest mops (3.x), which dropped the dfx replica these tests need: ``` Tool 'pocket-ic' is not defined in [toolchain] section in mops.toml Run mops toolchain use pocket-ic 15.0.0 to install it ``` [#18](#18) pinned mops 2.24.0 in `mops-test.yml` only, so PR checks pass while the publish job is still exposed. That job hasn't run with mops 3 yet because no version bump has landed since; [#16](#16) and [#17](#17) (both 5.0.0) would be the first to hit it. Moving these tests to mops 3 needs mops-side changes: configurable test-canister cycles, auto-progress for HTTP outcalls, and a `TestThresholdKeys` subnet. Out of scope here. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
subnet_metrics and EcdsaCurve.#secp256r1 are additive on the unpublished 5.0.0. Call.Cost.signWithEcdsa encodes the new curve as 1. Pin moc 2.0.0 and drop --default-persistent-actors, which that compiler rejects. mops test passes with the dfx replica. Co-authored-by: Kamil Listopad <listopadkamil@gmail.com>
moc 2.1.0 is a minor ahead of the 2.0.0 toolchain pin and adds Prim.costHttpRequestV2. mops test passes. No package version bump; Call.httpRequest still attaches the version-1 cost. Co-authored-by: Kamil Listopad <listopadkamil@gmail.com>
Kamirus
marked this pull request as ready for review
October 28, 2026 12:07
This was referenced Oct 28, 2026
Kamirus
added a commit
that referenced
this pull request
Nov 2, 2026
`Call.httpRequest` now attaches a pricing version 2 ("pay-as-you-go")
reservation instead of the version 1 cost. Version 1 charges for
`max_response_bytes`, which is 2 MB when unset. Version 2 charges for
the bytes and round-trip time a call actually uses and refunds the rest.
Costs come from `Prim.costHttpRequestV2`, which `moc` 2.1.0 exposes.
Supersedes [#16](#16),
rebuilt on the 5.0.0 types from
[#17](#17). The builder
design is from #16.
## Before / After
```motoko
// Before (5.0.0): version 1 pricing
let response = await Call.httpRequest(args);
// After: same arguments, version 2 pricing
let response = await Call.httpRequestFromArgs(args).send();
// Or build in place, and narrow the reservation
let response = await Call.httpRequest("https://example.com/api")
.withMaxResponseBytes(4_000)
.withExpectedRoundtripTimeMs(300)
.send();
// New: flexible outcalls
let result = await Call.flexibleHttpRequest("https://example.com/api")
.withReplication({ min_responses = 2; max_responses = 3; total_requests = 3 })
.send();
```
The signature change is deliberate. Every call site fails to compile
until it migrates, rather than switching pricing silently.
`Call.Cost.httpRequest(args, expected)` now prices version 2. The
version 1 `Call.Cost.httpRequest(args)` is gone, but
`Prim.costHttpRequest` still exposes it.
`[requirements] moc` goes to 2.1.0. Merging publishes `ic` 6.0.0, so
this is a draft.
## Differences from #16
- **No `Prim.subnetSelfNodeCount`.** `moc` imports every system API it
references into each canister that imports `mo:ic/Call`, even a canister
that only calls `createCanister`. Replicas without
`ic0.subnet_self_node_count`, such as the ones in `dfx` 0.30.1 and
0.31.0, refuse to install those canisters. #16 used the node count only
to cap the default reservation when `replication` is unset. Without it,
such a flexible outcall reserves for full-size responses, and the
surplus is refunded. Setting `replication` restores the cap.
- **`#flexible_` instead of `#_351978059_`.** `moc` drops the trailing
underscore when it maps to Candid, the same escape `didc` uses for
`#public_`.
- **`replication` is passed through as given.** When it's unset, the
system applies its own defaults, the same as
`ic-cdk-management-canister`.
- **`Cost.httpRequestV2` is named `Cost.httpRequest`.** It takes a
second argument, so old call sites fail to compile.
## Why CI changed
The `dfx` 0.30.1 replica that CI uses implements an earlier draft of
`ic0.cost_http_request_v2`, with five parameters and no `outcall_type`.
It rejects the specified encoding:
```
Canister violated contract: Failed to decode HttpRequestV2CostParams from Candid
```
PocketIC 16.1.0 implements the spec. However, under `mops test` PocketIC
has no signing keys and makes no outcalls. The suite is now split:
- **`test` job:** runs `test/Call.test.mo` on `dfx` 0.30.1 for
`create_canister`, ECDSA, and Schnorr. The suite is unchanged except
that the HTTP tests moved out.
- **`test-pocket-ic` job:** runs `test/HttpRequest.test.mo` on PocketIC
16.1.0. It pins each builder's cost to `ic0.cost_http_request_v2` on the
parameters the spec defines, and checks that each setter moves the price
the right way.
Both jobs use `mops` 2.24.0. `mops publish` would run every test file on
a single replica, and neither replica passes both. So `mops-publish.yml`
now runs the same two commands, then `mops publish --no-test`. As a side
effect, mops.one won't show test results for 6.0.0.
No CI replica can both price version 2 and make an outcall, so nothing
here sends a request end to end. `send()` is `getCost()` plus the
management canister call.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Leo Eichhorn <leo.eichhorn@dfinity.org>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Exposes the IC's pay-as-you-go HTTPS outcall pricing to Motoko callers.
IC.HttpRequestArgsnow carriespricing_version, so a canister can opt into version 2. Version 2 charges for the bytes and round-trip time a call actually uses and refunds the rest. Version 1 charges formax_response_bytes, which is 2 MB when unset.Types.mois regenerated from the upstreamic.didthrough interface spec 0.70.0.Breaking: record literals need the new fields
Motoko record literals must name every field, so new fields on records that callers build break compilation even when they're optional in Candid.
The same applies to the following:
IC.CanisterSettingsandIC.DefiniteCanisterSettings:minimum_incoming_canister_call_cycles,log_memory_limit, andstatus_visibility.IC.FetchCanisterLogsArgs:filter.CanisterStatusResult.memory_metrics:log_memory_store_size.IC.StatusVisibilityspells the Candidpubliccase as#public_, becausepublicis a reserved word.EcdsaCurvegains#secp256r1, so an exhaustiveswitchon it must handle the new case.Additive
ic.flexible_http_request, plusIC.FlexibleHttpRequestArgs,FlexibleHttpRequestErr,FlexibleHttpRequestResult, andHttpRequestResourceReport. Itsmethodvariant covers#get,#head,#post,#put,#delete, and#patch.ic.subnet_metricswithSubnetMetricsArgsandSubnetMetricsResult.canister_infois a query onTypes.Self.What is unchanged
Call.httpRequeststill takesIC.HttpRequestArgsand still attaches the version 1 (ic0.cost_http_request) cost. Setpricing_version = ?2only after you compute and attach a version 2 reservation yourself.moc2.1.0 exposesPrim.costHttpRequestV2, but this package doesn't call it. #16 rewritesCall.httpRequestaround that primitive and can build on this types bump.Toolchain
[toolchain] mocgoes to 2.1.0.[requirements] mocstays at 1.4.0.[moc].argsdrops--default-persistent-actors, becausemoc2 removed the flag.REGENERATING.mdinstallsdidc0.6.2 from the GitHub release.Merging this publishes
ic5.0.0 to mops automatically.🤖 Generated with Claude Code