The root cause of this problem is dfx nns install
being buggy.
-
When using dfx extension install nns --version 0.4.1
, the Icrc Index canister uploaded in the deployed SNS-W canister is an outdated WASM - i.e., not the “ng” canister - which does not match the init parameters used when the SNS proposal is executed to spin the Index canister of the SNS project.
-
dfx extension install nns --version 0.4.2
is better in the sense that it uploads an Index “ng” canister WASM, but that stuff is still buggy and ultimately leads to the same problem. I don’t know exactly what the issue is, but everything seems to point out that the WASM contained in the extension is too old or the Candid files used to spin the Index canister are too recent. One or the other, it’s buggy and inconsistent.
For local testing purposes, the SNS-W is actually deployed locally without many guards on who can execute its functions. Therefore, the solution to the issue is to manually upload a valid WASM version of the Index canister.
At this point, you might ask yourself: “Yeah, that’s cool, but how do you know which version?”
So, here’s the thing: after 5 hours of debugging yesterday, writing hacks, and being totally upset by the developer experience, I finally had luck. I just reused the same commit hash that I am using in Oisy and Juno to deploy the Index canister, and it worked out. I could have cried.
Anyway, so here’s my download script:
#!/bin/bash
DIR=.
IC_COMMIT="43f31c0a1b0d9f9ecbc4e2e5f142c56c7d9b0c7b"
curl -sSL https://download.dfinity.systems/ic/$IC_COMMIT/canisters/ic-icrc1-index-ng.wasm.gz -o "$DIR"/ic-icrc1-index-ng.wasm.gz
curl -sSL https://raw.githubusercontent.com/dfinity/ic/$IC_COMMIT/rs/rosetta-api/icrc1/index-ng/index-ng.did -o "$DIR"/ic-icrc1-index-ng.did
And that’s the script I use to manually upload the WASM to SNS-W:
#!/usr/bin/env node
import { hexStringToUint8Array } from '@dfinity/utils';
import { createHash } from 'crypto';
import { copyFileSync } from 'node:fs';
import { readFile } from 'node:fs/promises';
import { join } from 'node:path';
import { getSnsWasmActor } from './actor.utils.mjs';
const snsWasmCanisterId = 'qaa6y-5yaaa-aaaaa-aaafa-cai';
copyFileSync(
join(process.cwd(), 'node_modules/@dfinity/nns/dist/candid/sns_wasm.idl.js'),
join(process.cwd(), 'node_modules/@dfinity/nns/dist/candid/sns_wasm.idl.mjs')
);
const loadGWasm = async () => {
const buffer = await readFile(`${process.cwd()}/ic-icrc1-index-ng.wasm.gz`);
return {
wasm: [...new Uint8Array(buffer)],
hash: createHash('sha256').update(buffer).digest('hex')
};
};
const deployIndexCanister = async () => {
// The canister of that SNS-Wasm on mainnet is qaa6y-5yaaa-aaaaa-aaafa-cai
const actor = await getSnsWasmActor(snsWasmCanisterId);
const { wasm, hash } = await loadGWasm();
console.log(`Upload ${hash}`);
await actor.add_wasm({
hash: hexStringToUint8Array(hash),
wasm: [
{
wasm,
proposal_id: [],
canister_type: 6 // #!/usr/bin/env node
import { hexStringToUint8Array } from '@dfinity/utils';
import { createHash } from 'crypto';
import { copyFileSync } from 'node:fs';
import { readFile } from 'node:fs/promises';
import { join } from 'node:path';
import { getSnsWasmActor } from './actor.utils.mjs';
const snsWasmCanisterId = 'qaa6y-5yaaa-aaaaa-aaafa-cai';
copyFileSync(
join(process.cwd(), 'node_modules/@dfinity/nns/dist/candid/sns_wasm.idl.js'),
join(process.cwd(), 'node_modules/@dfinity/nns/dist/candid/sns_wasm.idl.mjs')
);
const loadGWasm = async () => {
const buffer = await readFile(`${process.cwd()}/ic-icrc1-index-ng.wasm.gz`);
return {
wasm: [...new Uint8Array(buffer)],
hash: createHash('sha256').update(buffer).digest('hex')
};
};
const deployIndexCanister = async () => {
// The canister of that SNS-Wasm on mainnet is qaa6y-5yaaa-aaaaa-aaafa-cai
const actor = await getSnsWasmActor(snsWasmCanisterId);
const { wasm, hash } = await loadGWasm();
console.log(`Upload ${hash}`);
await actor.add_wasm({
hash: hexStringToUint8Array(hash),
wasm: [
{
wasm,
proposal_id: [],
canister_type: 6 // Yolo it's 6 for Index
}
]
});
// dfx canister call qaa6y-5yaaa-aaaaa-aaafa-cai get_latest_sns_version_pretty
console.log(await actor.get_latest_sns_version_pretty(null));
};
await deployIndexCanister();
}
]
});
// dfx canister call qaa6y-5yaaa-aaaaa-aaafa-cai get_latest_sns_version_pretty
console.log(await actor.get_latest_sns_version_pretty(null));
};
await deployIndexCanister();
Just copying the above code won’t probably work. Check out the repo for everything: https://github.com/peterpeterparker/proposals.network