Skip to content

Commit e4f0f23

Browse files
authored
Fix verified issues across 8 skills from multi-agent audit (#4)
- certified-variables: Add missing Cargo.toml headers, HTTP cert API warning - https-outcalls: Fix Motoko Blob API (fromArray/toArray/empty), Rust import path - icrc-ledger: Add transient keyword, pin wasm/candid URLs - internet-identity: Remove invalid .unwrap() on StableCell::set() - multi-canister: Fix nested RefCell panic, ic-cdk 0.18 type names - sns-launch: Fix quill→dfx CLI commands, token math - vetkd: Fix git URL, version 0.6.0, determinism test claim - wallet: Fix ic-cdk 0.18 type names and call signatures
1 parent cfa90f8 commit e4f0f23

9 files changed

Lines changed: 124 additions & 90 deletions

File tree

public/llms-full.txt

Lines changed: 62 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,14 @@ CLIENT VERIFICATION:
377377
**Cargo.toml:**
378378

379379
```toml
380+
[package]
381+
name = "certified_vars_backend"
382+
version = "0.1.0"
383+
edition = "2021"
384+
385+
[lib]
386+
crate-type = ["cdylib"]
387+
380388
[dependencies]
381389
candid = "0.10"
382390
ic-cdk = "0.18"
@@ -496,12 +504,22 @@ For canisters serving HTTP responses directly (not through the asset canister),
496504
**Additional Cargo.toml dependency:**
497505

498506
```toml
507+
[package]
508+
name = "http_certified_backend"
509+
version = "0.1.0"
510+
edition = "2021"
511+
512+
[lib]
513+
crate-type = ["cdylib"]
514+
499515
[dependencies]
500516
ic-http-certification = "2.6"
501517
```
502518

503519
**Certifying HTTP responses:**
504520

521+
> **Note:** The HTTP certification API is evolving rapidly. Verify these examples against the latest [ic-http-certification docs](https://docs.rs/ic-http-certification) before use.
522+
505523
```rust
506524
use ic_http_certification::{
507525
HttpCertification, HttpCertificationTree, HttpCertificationTreeEntry,
@@ -2431,7 +2449,6 @@ import Blob "mo:core/Blob";
24312449
import Nat64 "mo:core/Nat64";
24322450
import Text "mo:core/Text";
24332451
import Runtime "mo:core/Runtime";
2434-
import Iter "mo:core/Iter";
24352452

24362453
persistent actor {
24372454

@@ -2502,7 +2519,7 @@ persistent actor {
25022519
method = #get;
25032520
transform = ?{
25042521
function = transform;
2505-
context = Blob.fromIter(Iter.empty());
2522+
context = Blob.empty();
25062523
};
25072524
};
25082525

@@ -2511,7 +2528,7 @@ persistent actor {
25112528
let response = await (with cycles = 200_000_000) ic.http_request(request);
25122529

25132530
// Decode the response body
2514-
let bodyBlob = Blob.fromIter(Iter.fromArray(response.body));
2531+
let bodyBlob = Blob.fromArray(response.body);
25152532
let body = Text.decodeUtf8(bodyBlob);
25162533
switch (body) {
25172534
case (?text) { text };
@@ -2523,7 +2540,7 @@ persistent actor {
25232540
public func postData(jsonPayload : Text) : async Text {
25242541
let url = "https://httpbin.org/post";
25252542

2526-
let bodyBytes = Iter.toArray(Blob.values(Text.encodeUtf8(jsonPayload)));
2543+
let bodyBytes = Blob.toArray(Text.encodeUtf8(jsonPayload));
25272544

25282545
let request : HttpRequestArgs = {
25292546
url = url;
@@ -2538,14 +2555,14 @@ persistent actor {
25382555
method = #post;
25392556
transform = ?{
25402557
function = transform;
2541-
context = Blob.fromIter(Iter.empty());
2558+
context = Blob.empty();
25422559
};
25432560
};
25442561

25452562
// POST may cost more due to request body size
25462563
let response = await (with cycles = 300_000_000) ic.http_request(request);
25472564

2548-
let bodyBlob = Blob.fromIter(Iter.fromArray(response.body));
2565+
let bodyBlob = Blob.fromArray(response.body);
25492566
let body = Text.decodeUtf8(bodyBlob);
25502567
switch (body) {
25512568
case (?text) { text };
@@ -2575,7 +2592,7 @@ serde_json = "1"
25752592
```
25762593

25772594
```rust
2578-
use ic_cdk::management_canister::http_request::{
2595+
use ic_cdk::api::management_canister::http_request::{
25792596
http_request, CanisterHttpRequestArgument, HttpHeader, HttpMethod, HttpResponse,
25802597
TransformArgs, TransformContext, TransformFunc,
25812598
};
@@ -2973,7 +2990,7 @@ persistent actor {
29732990
};
29742991

29752992
// Remote ledger actor reference (ICP ledger shown; swap canister ID for other tokens)
2976-
let icpLedger = actor ("ryjl3-tyaaa-aaaaa-aaaba-cai") : actor {
2993+
transient let icpLedger = actor ("ryjl3-tyaaa-aaaaa-aaaba-cai") : actor {
29772994
icrc1_balance_of : shared query (Account) -> async Nat;
29782995
icrc1_transfer : shared (TransferArg) -> async { #Ok : Nat; #Err : TransferError };
29792996
icrc2_approve : shared (ApproveArg) -> async { #Ok : Nat; #Err : ApproveError };
@@ -3214,13 +3231,15 @@ async fn transfer_from(from: Principal, to: Principal, amount: Nat) -> Result<Na
32143231

32153232
Add to `icp.json`:
32163233

3234+
Pin the release hash before deploying: get the latest hash from https://dashboard.internetcomputer.org/releases, then substitute it for `<RELEASE_HASH>` in both URLs below.
3235+
32173236
```json
32183237
{
32193238
"canisters": {
32203239
"icrc1_ledger": {
32213240
"type": "custom",
3222-
"candid": "https://raw.githubusercontent.com/dfinity/ic/master/rs/ledger_suite/icrc1/ledger/ledger.did",
3223-
"wasm": "https://download.dfinity.systems/ic/master/canisters/ic-icrc1-ledger.wasm.gz",
3241+
"candid": "https://raw.githubusercontent.com/dfinity/ic/<RELEASE_HASH>/rs/ledger_suite/icrc1/ledger/ledger.did",
3242+
"wasm": "https://download.dfinity.systems/ic/<RELEASE_HASH>/canisters/ic-icrc1-ledger.wasm.gz",
32243243
"init_arg_file": "icrc1_ledger_init.args"
32253244
}
32263245
}
@@ -3628,7 +3647,7 @@ fn init_owner() -> String {
36283647
let mut cell = owner.borrow_mut();
36293648
match cell.get() {
36303649
None => {
3631-
cell.set(Some(caller)).unwrap();
3650+
cell.set(Some(caller));
36323651
format!("Owner set to {}", caller)
36333652
}
36343653
Some(_) => "Owner already initialized".to_string(),
@@ -4177,19 +4196,17 @@ fn register(username: String) -> Result<UserProfile, String> {
41774196

41784197
let key = principal_to_key(&caller);
41794198
USERS.with(|users| {
4180-
let users = users.borrow();
4181-
if users.contains_key(&key) {
4199+
if users.borrow().contains_key(&key) {
41824200
return Err("Already exists".to_string());
41834201
}
4184-
drop(users);
41854202

41864203
let profile = UserProfile {
41874204
id: caller,
41884205
username,
41894206
created: ic_cdk::api::time() as i64,
41904207
};
41914208
let bytes = serialize_profile(&profile);
4192-
USERS.with(|u| u.borrow_mut().insert(key, bytes));
4209+
users.borrow_mut().insert(key, bytes);
41934210
Ok(profile)
41944211
})
41954212
}
@@ -4493,9 +4510,9 @@ persistent actor Self {
44934510

44944511
```rust
44954512
use candid::{CandidType, Deserialize, Principal, encode_one};
4496-
use ic_cdk::management_canister::main::{
4513+
use ic_cdk::management_canister::{
44974514
create_canister, install_code,
4498-
CreateCanisterArgument, InstallCodeArgument, CanisterInstallMode, CanisterSettings,
4515+
CreateCanisterArgs, InstallCodeArgs, CanisterInstallMode, CanisterSettings,
44994516
};
45004517
use ic_cdk::update;
45014518
use ic_stable_structures::memory_manager::{MemoryId, MemoryManager, VirtualMemory};
@@ -4522,7 +4539,7 @@ async fn create_child_canister(wasm_module: Vec<u8>) -> Principal {
45224539
assert_ne!(caller, Principal::anonymous(), "Auth required");
45234540

45244541
// Create canister
4525-
let create_args = CreateCanisterArgument {
4542+
let create_args = CreateCanisterArgs {
45264543
settings: Some(CanisterSettings {
45274544
controllers: Some(vec![ic_cdk::id(), caller]),
45284545
compute_allocation: None,
@@ -4535,21 +4552,21 @@ async fn create_child_canister(wasm_module: Vec<u8>) -> Principal {
45354552
};
45364553

45374554
// Attach 1T cycles for the new canister
4538-
let (create_result,) = create_canister(create_args, 1_000_000_000_000u128)
4555+
let create_result = create_canister(&create_args, 1_000_000_000_000u128)
45394556
.await
45404557
.expect("Failed to create canister");
45414558

45424559
let canister_id = create_result.canister_id;
45434560

45444561
// Install code
4545-
let install_args = InstallCodeArgument {
4562+
let install_args = InstallCodeArgs {
45464563
mode: CanisterInstallMode::Install,
45474564
canister_id,
45484565
wasm_module,
45494566
arg: encode_one(&caller).unwrap(), // Pass owner as init arg
45504567
};
45514568

4552-
install_code(install_args)
4569+
install_code(&install_args)
45534570
.await
45544571
.expect("Failed to install code");
45554572

@@ -4725,7 +4742,7 @@ dependencies: [icrc-ledger, multi-canister]
47254742
---
47264743

47274744
# SNS DAO Launch
4728-
> version: 1.8.0 | requires: [icp-cli >= 0.1.0, quill CLI, NNS neuron with stake]
4745+
> version: 1.8.0 | requires: [icp-cli >= 0.1.0, dfx sns extension, NNS neuron with stake]
47294746

47304747
## What This Is
47314748

@@ -4734,7 +4751,7 @@ Service Nervous System (SNS) is the DAO framework for decentralizing individual
47344751
## Prerequisites
47354752

47364753
- `icp-cli` >= 0.1.0 (`brew install dfinity/tap/icp-cli`)
4737-
- `quill` CLI for proposal submission (`quill sns make-proposal` is the recommended approach)
4754+
- `dfx` with the sns extension (`dfx extension install sns`) for prepare-canisters, validate, and propose
47384755
- An NNS neuron with sufficient stake to submit proposals (mainnet)
47394756
- Dapp canisters already deployed and working on mainnet
47404757
- `sns_init.yaml` configuration file with all parameters defined
@@ -4891,7 +4908,7 @@ Swap:
48914908
```
48924909
Stage 1: Developer defines parameters in sns_init.yaml
48934910
Stage 2: Developer adds NNS Root as co-controller of dapp canisters
4894-
Stage 3: Developer submits NNS proposal using `quill sns make-proposal`
4911+
Stage 3: Developer submits NNS proposal using `dfx sns propose`
48954912
Stage 4: NNS community votes on the proposal
48964913
Stage 5: (If adopted) SNS-W deploys uninitialized SNS canisters
48974914
Stage 6: SNS Root becomes sole controller of dapp canisters
@@ -5058,17 +5075,17 @@ icp deploy my_frontend
50585075

50595076
```bash
50605077
# Step 1: Add NNS Root as co-controller of each dapp canister
5061-
# Use quill to add NNS Root as co-controller:
5062-
quill sns prepare-canisters add-nns-root BACKEND_CANISTER_ID --network ic
5063-
quill sns prepare-canisters add-nns-root FRONTEND_CANISTER_ID --network ic
5078+
# Requires dfx sns extension: `dfx extension install sns`
5079+
dfx sns prepare-canisters add-nns-root BACKEND_CANISTER_ID --network ic
5080+
dfx sns prepare-canisters add-nns-root FRONTEND_CANISTER_ID --network ic
50645081

50655082
# Step 2: Validate your config locally before submitting
5066-
sns-cli validate --init-config-file sns_init.yaml
5083+
dfx sns init-config-file validate
50675084
# Or review the rendered proposal by inspecting the yaml output carefully.
50685085
# You can also test the full flow on a local replica first (see Local Testing above).
50695086

50705087
# Step 3: Submit the proposal (THIS IS IRREVERSIBLE — double-check your config)
5071-
quill sns make-proposal --network ic --neuron-id NEURON_ID sns_init.yaml
5088+
dfx sns propose --network ic --neuron $NEURON_ID sns_init.yaml
50725089
```
50735090

50745091
## Verify It Works
@@ -5622,9 +5639,9 @@ serde_bytes = "0.11"
56225639

56235640
# Option A: Use the high-level ic-vetkeys library (if available on crates.io)
56245641
# ⚠ Verify this crate exists before adding. If not published, use a git dependency:
5625-
# ic-vetkeys = { git = "https://github.com/dfinity/examples", branch = "master" }
5642+
# ic-vetkeys = { git = "https://github.com/dfinity/ic-vetkeys" }
56265643
# Or use Option B (raw canister calls) which has no extra dependency.
5627-
ic-vetkeys = "0.1"
5644+
ic-vetkeys = "0.6.0"
56285645

56295646
# Option B: Call management canister directly (lower level, always works)
56305647
# No extra dependency -- use ic_cdk::api::call::call_with_payment128
@@ -5918,9 +5935,10 @@ icp canister call backend getPublicKey '()'
59185935
icp canister call backend deriveKey '(blob "\00\01...")'
59195936
# Expected: (blob "\12\34\56...") -- encrypted key material
59205937

5921-
# 3. Verify determinism: same inputs produce same output
5922-
# Call deriveKey twice with identical transport key
5923-
# Expected: identical encrypted_key blobs both times
5938+
# 3. Note: vetkd_derive_key uses randomized encryption — the encrypted blobs DIFFER each call.
5939+
# The underlying derived key is deterministic (same canister/context/input always produces the same key),
5940+
# but the encrypted_key blob varies because a fresh random nonce is used each time.
5941+
# To verify the underlying key is correct, decrypt both blobs with the transport secret and confirm they match.
59245942

59255943
# 4. Verify isolation: different callers get different keys
59265944
icp identity new test-user-1 --storage-mode=plaintext
@@ -6139,8 +6157,8 @@ use candid::{CandidType, Deserialize, Nat, Principal};
61396157
use ic_cdk::update;
61406158
use ic_cdk::management_canister::{
61416159
create_canister, canister_status, deposit_cycles, stop_canister, delete_canister,
6142-
CreateCanisterArgument, CanisterIdRecord,
6143-
CanisterSettings, CanisterStatusResponse,
6160+
CreateCanisterArgs, CanisterStatusArgs, DepositCyclesArgs, StopCanisterArgs, DeleteCanisterArgs,
6161+
CanisterSettings, CanisterStatusResult,
61446162
};
61456163

61466164
#[update]
@@ -6157,40 +6175,39 @@ async fn create_new_canister() -> Principal {
61576175
wasm_memory_limit: None,
61586176
};
61596177

6160-
let arg = CreateCanisterArgument {
6178+
let arg = CreateCanisterArgs {
61616179
settings: Some(settings),
61626180
};
61636181

61646182
// Send 1T cycles with the create call
6165-
let (result,) = create_canister(arg, 1_000_000_000_000u128)
6183+
let result = create_canister(&arg, 1_000_000_000_000u128)
61666184
.await
61676185
.expect("Failed to create canister");
61686186

61696187
result.canister_id
61706188
}
61716189

61726190
#[update]
6173-
async fn check_status(canister_id: Principal) -> CanisterStatusResponse {
6174-
let (status,) = canister_status(CanisterIdRecord { canister_id })
6191+
async fn check_status(canister_id: Principal) -> CanisterStatusResult {
6192+
canister_status(&CanisterStatusArgs { canister_id })
61756193
.await
6176-
.expect("Failed to get canister status");
6177-
status
6194+
.expect("Failed to get canister status")
61786195
}
61796196

61806197
#[update]
61816198
async fn top_up(canister_id: Principal, amount: u128) {
6182-
deposit_cycles(CanisterIdRecord { canister_id }, amount)
6199+
deposit_cycles(&DepositCyclesArgs { canister_id }, amount)
61836200
.await
61846201
.expect("Failed to deposit cycles");
61856202
}
61866203

61876204
#[update]
61886205
async fn stop_and_delete(canister_id: Principal) {
6189-
stop_canister(CanisterIdRecord { canister_id })
6206+
stop_canister(&StopCanisterArgs { canister_id })
61906207
.await
61916208
.expect("Failed to stop canister");
61926209

6193-
delete_canister(CanisterIdRecord { canister_id })
6210+
delete_canister(&DeleteCanisterArgs { canister_id })
61946211
.await
61956212
.expect("Failed to delete canister");
61966213
}

skills/certified-variables/SKILL.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,14 @@ CLIENT VERIFICATION:
7878
**Cargo.toml:**
7979

8080
```toml
81+
[package]
82+
name = "certified_vars_backend"
83+
version = "0.1.0"
84+
edition = "2021"
85+
86+
[lib]
87+
crate-type = ["cdylib"]
88+
8189
[dependencies]
8290
candid = "0.10"
8391
ic-cdk = "0.18"
@@ -197,12 +205,22 @@ For canisters serving HTTP responses directly (not through the asset canister),
197205
**Additional Cargo.toml dependency:**
198206

199207
```toml
208+
[package]
209+
name = "http_certified_backend"
210+
version = "0.1.0"
211+
edition = "2021"
212+
213+
[lib]
214+
crate-type = ["cdylib"]
215+
200216
[dependencies]
201217
ic-http-certification = "2.6"
202218
```
203219

204220
**Certifying HTTP responses:**
205221

222+
> **Note:** The HTTP certification API is evolving rapidly. Verify these examples against the latest [ic-http-certification docs](https://docs.rs/ic-http-certification) before use.
223+
206224
```rust
207225
use ic_http_certification::{
208226
HttpCertification, HttpCertificationTree, HttpCertificationTreeEntry,

0 commit comments

Comments
 (0)