Getting your Trinity Audio player ready...

To create an app for IC Pack package manager (a remote, installable app), you follow these guidelines.

Choice of programming language

So, if you write a new software for Internet Computer (including software for our project IC Pack), choose either Motoko or Rust. If you decide to translate existing software, Rust, TypeScript, javaScript, Python, or C++ may be good choices.

Do development using ICP blockchain

Learn to develop software using ICP blockchain. It is easier than to develop for AWS or GCP.

Creating a package

For your software to be compatible with IC Pack, you need to package it (or, in other words, create a package). IC Pack dev docs explain how to do it.

Use wallet app (src/wallet_backend/ and src/wallet_frontend/) as an example how a package should work, especially, how to initialize package’s owner principal in a secure manner.

Module initialization arguments

Every module of your package receives the following arguments on installation:

{
  packageManager: Principal; // `backend` module of the package manager
  mainIndirect: Principal; // `main_indirect` module of the package manager
  simpleIndirect: Principal; // `simple_indirect` module of the package manager
  battery: Principal; // `battery` module of the package manager
  user: Principal; // user, ignore it for now, use install key instead  installationId: Nat; // installation ID of the currently installed package
  upgradeId: ?Nat; // `null` for newly installed packages  userArg: Blob; // normally `to_candid({})` but maybe any value
}

Example package receiving arguments:

persistent actor class Wallet({
  installationId: Nat;
  packageManager: Principal;
}) = this {
  // ...
}

Usually, you need to set the owner of your backend canister. The highly recommended (because it has enhanced security) way to do it is:

Frontend JS code:

import { urlSafeBase64ToUint8Array, signPrincipal } from '../../../icpack-js';

const params = new URLSearchParams(window.location.search);
const installKey = params.get('installationPrivKey');

try {
  privBytes = urlSafeBase64ToUint8Array(props.installationPrivKey);
} catch (_) {
  alert('Invalid installation key.');
  return;
}
const privKey = await window.crypto.subtle.importKey(
  "pkcs8", privBytes, {name: 'ECDSA', namedCurve: 'P-256'/*prime256v1*/}, true, ["sign"]
);
const signature = new Uint8Array(await signPrincipal(privKey, principal));
await backend.setOwner(signature); // the code that you use to set your canister owner

In the backend, check the user’s cryptographic signature before setting the owner. Here is the Motoko code:

import UserAuth "mo:icpack-lib/UserAuth";

public shared({caller}) func setOwner(signature: Blob): async () {
  await* UserAuth.checkOwnerSignature(packageManager, installationId, caller, signature); // traps on error
  owner := caller;
};

Distribute your software

Distributing your software is the simplest task! Just create a link, as IC Pack dev docs explain.

Chat Icon