Upgrade Smart Contracts on the Internet Computer With JavaScript

How to install code in child canisters with NodeJS.

Photo by Milad Fakurian on Unsplash

Getting started

​Child canister

import Nat "mo:base/Nat";

actor class Bucket(user: Text) = this {

var version: Nat = 2; // <-- Bump v2

public query func say() : async Text {
return "Hello World - " # user # " - v" # Nat.toText(version);
};

}

​Backend

import IC "./ic.types";

actor Main {
private let ic : IC.Self = actor "aaaaa-aa";

public func installCode(canisterId: Principal, arg: Blob, wasmModule: Blob): async() {
await ic.install_code({
arg = arg;
wasm_module = wasmModule;
mode = #upgrade;
canister_id = canisterId;
});
};
};

NodeJS script

import {Principal} from "@dfinity/principal";
import {IDL} from '@dfinity/candid';

const installCode = async () => {
// Param 1.
const canisterId =
Principal.fromText('renrk-eyaaa-aaaaa-aaada-cai');

// Param 2.
const wasmModule = loadWasm();

// Param 3.
const arg = IDL.encode([IDL.Text], ['User1']);

// Agent-js actor
const actor = await managerActor();

// Execute
await upgradeBucket({actor, wasmModule, canisterId, arg})
}

try {
await installCode()
} catch (err) {
console.error(err);
}
import {readFileSync} from 'fs';

const loadWasm = () => {
const localPath =
`${process.cwd()}/.dfx/local/canisters/bucket/bucket.wasm`;
const buffer = readFileSync(localPath);
return [...new Uint8Array(buffer)];
};
actor class Bucket(user: Text) = this {
// commented
}
import {IDL} from '@dfinity/candid';

const arg = IDL.encode([IDL.Text], ['User1']);
import {IDL} from '@dfinity/candid';
import {Principal} from "@dfinity/principal";

const arg = IDL.encode([IDL.Principal],
[Principal.fromText('rrrrr-ccccc-user-principal')]);
import {idlFactory} from './.dfx/local/canisters/manager/manager.did.mjs';
import fetch from 'node-fetch';
import {HttpAgent, Actor} from '@dfinity/agent';

const managerActor = async () => {
const canisterId = managerPrincipalLocal();

// Replace host with https://ic0.app for mainnet
const agent =
new HttpAgent({fetch, host: 'http://localhost:8000/'});

// Only if local IC
await agent.fetchRootKey();

return Actor.createActor(idlFactory, {
agent,
canisterId
});
};
cp ./.dfx/local/canisters/manager/manager.did.js ./.dfx/local/canisters/manager/manager.did.mjs
const managerPrincipalLocal = () => {
const buffer =
readFileSync('./.dfx/local/canister_ids.json');
const {manager} = JSON.parse(buffer.toString('utf-8'));
return Principal.fromText(manager.local);
};
const managerPrincipalIC = () => {
const buffer = readFileSync('./canister_ids.json');
const {manager} = JSON.parse(buffer.toString('utf-8'));
return Principal.fromText(manager.ic);
};
const upgradeBucket = 
async ({actor, wasmModule, canisterId, arg}) => {
console.log(`Upgrading: ${canisterId.toText()}`);

await actor.installCode(canisterId, [...arg], wasmModule);

console.log(`Done: ${canisterId.toText()}`);
};

​Test

​Conclusion and sample repo

Start building at internetcomputer.org and join the developer community at forum.dfinity.org.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store