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
- Motoko (a special programming language for ICP blockchain). Don’t afraid of a new language Motoko is a easy as Python to learn, meanwhile having features of a strict type system, helping you to eliminate stupid errors due to messed types and increasing code execution speed (and reducing costs).
- Rust (A bit of advice: because we hold all data in VM memory, not on disk files or an external database, memory corruption would be especially bad, so I recommend to never use
unsafe
Rust feature. To create circular data structures Better useRc
orArc
reference counting pointers than to resort tounsafe
.) - TypeScript or JavaScript (Azle);
- Python (Kybra);
- C++ (icpp-pro).
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.