# Sidekick Sidekick is a simple JavaScript library for talking to an Aeternity browser wallet extension such as Superhero from the document context of a webpage. | **Thing** | **URL** | | --- | --- | | Bug Tracker | https://gitlab.com/DoctorAjayKumar/sidekick/-/issues | | Documentation | http://orangepill.healthcare/projects/sidekick/current/docs | | Examples | https://gitlab.com/DoctorAjayKumar/sidekick/-/tree/master/examples | | Git repository | https://gitlab.com/DoctorAjayKumar/sidekick | | Homepage | http://orangepill.healthcare/projects/sidekick | | License | ./LICENSE.txt | | Maintainer | Dr. Ajay Kumar PHD | | Releases | http://orangepill.healthcare/projects/sidekick/releases | > One of the most important things for designing a computer, which I > think most designers don't do, is you study the problem you want to > solve. And then use what you learn from studying the problem you > want to solve to put in the mechanisms needed to solve it in the > computer you're building. No more, no less. — Gerald Jay Sussman ### What sidekick is NOT Sidekick is **not** ideal if you operate in the Node/NPM ecosystem. If you are working in the Node/NPM ecosystem, you probably want the [Aeternity JavaScript SDK](https://github.com/aeternity/aepp-sdk-js/). Every single Aeternity-related thing you could ever possibly want to do is possible to accomplish with the SDK. All that Sidekick knows how to do is talk to a browser wallet extension. In an application, there is a great deal of necessary functionality (e.g. forming transactions for the wallet to sign) which sidekick assumes your server-side code has already handled. In all software there is a tradeoff between simplicity and number of features. Sidekick is very simple: 2300 lines of TypeScript, including comments, with no dependencies. Therefore Sidekick intentionally only has a very limited set of features. # How to use this library To obtain this library, download and unpack a release tarball wget http://zxq9.com/projects/vanillae/sidekick/releases/sidekick_dist_X-Y-Z.tar.gz tar xzvf sidekick_dist_X-Y-Z.tar.gz You *should* be able to get all of the functionality you need just from the exposed functions in the `sidekick` module. (If this is not the case, please report this as a bug.) You probably want to read the documentation of: sidekick.js : top-level function calls awcp/awcp.js : explains the return types of top-level sidekick functions, explains what sidekick actually does for you, and explains how all the various modules fit together skylight.js : main data structure in sidekick helpers.js : what it sounds like There are examples explained in this document. Their source can be found in full in the GitLab repository, link above. The examples exhibit how to interact with the standard release tarball using TypeScript. ## General flow of Sidekick usage 1. Import the sidekick.js file: ```typescript import * as sk from '/path/to/sidekick_dist_X-Y-Z/dist_js/sidekick.js' ``` 2. Create a `Skylight`. This is the main data structure of Sidekick. There are two ways to do this 1. `start_dwim() : Promise` This is probably the one you want. It starts up the Skylight and does the handshake with the wallet (will pop up the little window for your user). The effect of this is to populate all the variables like the user's public key. Note that this is an async function. It doesn't return until the handshake is complete. ```typescript // Needs to be wrapped in an async function in order to use // await keyword async function main() : Promise { let my_skylight = await sk.start_dwim(); ... } main(); ``` 2. `start : Skylight` This is the vanilla option. All it does is create the Skylight object. Beware that this does start up a message queue that passively listens for messages from the wallet. 3. Pass the skylight in to various functions along with additional calldata generated by your server-side backend code. ## Example 1: Hello World The effect of this example is to print "hello world" to the JS console (Ctrl+Shift+C in most browsers). This example is included for debugging/mental-quicksand-escape purposes. ```html Hello world: Sidekick

Sidekick Example: Hello World

Check the console

``` The important lines are ```html ``` This shows - you need to use `type="module"` in order for imports to work - how to do an import - how to call functions from an imported module ## Example 2: get the user to sign a transaction Anything you will want the user to do (e.g. sign smart contracts) is contained in "get the user to sign a transaction". This example illustrates the basic things you need to do in order to accomplish that. Sidekick does not provide functionality for forming the transaction string you want the user to sign. Your backend should be doing that. The example here uses a shim library called `parasite`, which you can find in the GitLab repository in the `examples` directory. Parasite is just a rewrite layer in front of the `testnet.aeternity.io` JSON interface. It is not suitable for usage in production. This is adapted from [`examples/examples_src_ts/do_a_transfer.ts`][dat_ts]. The difference is that `do_a_transfer.ts` is written against [`examples/examples_html/do_a_transfer.html`][dat_html]. It contains a lot of unnecessary detail, like doing things in response to buttons being clicked, and filling in DOM textboxes with the results of things. The full example has logic that resembles a register machine, rather than a functional program. This example is closer to a functional program. [dat_html]: https://gitlab.com/DoctorAjayKumar/sidekick/-/blob/master/examples/examples_html/do_a_transfer.html [dat_ts]: https://gitlab.com/DoctorAjayKumar/sidekick/-/blob/master/examples/examples_src_ts/do_a_transfer.ts ```typescript import * as ae_node from './parasite/ae_node.js'; import * as sk from '../sidekick_dist/dist_js/sidekick.js'; async function main() : Promise { //--------------------------------------------------------------- // STEP 1: MAKE A SKYLIGHT //--------------------------------------------------------------- let skl : sk.Skylight = await sk.start_dwim(sk.TIMEOUT_DEF_DETECT, sk.TIMEOUT_DEF_CONNECT, sk.TIMEOUT_DEF_ADDRESS); //--------------------------------------------------------------- // STEP 2: GET THE USER'S ADDRESS //--------------------------------------------------------------- let user_addr : string = await sk.address(skl, sk.TIMEOUT_DEF_ADDRESS); // faster/non-async: // // let user_addr = skl.waellet_address // // the non-commented code // // - will crash if the wallet isn't connected // - will query the wallet for the address if the wallet *is* // connected but the skl.waellet_address field *is not* // populated // - will crash if that times out after the second argument // number of milliseconds // // if you know with 100% certainty that the address field will be // populated (which we do here, because we used connect_dwim), // then it's safe to just grab the field from the skylight // // The problem is that if the address field isn't populated, the // commented code defaults to `undefined`, rather than crashing // with an error message and callstack trace //--------------------------------------------------------------- // STEP 3: FORM THE TRANSACTION // // This will be different for your application, because you're // not using parasite (right?) // // You need to figure out how to make something like `tx_obj` on // your own. // // `tx_obj` is just `{tx: "some_base58_garbage"}`. //--------------------------------------------------------------- let target_addr : string = 'ak_dvNHMgVvdSgDchLsmcUpuFTbMBGfG3E5V9KZnNjLYPyEhcqnL'; // amount is in aettos let amount : number = 1; let endpoint : string = ae_node.URL_TESTNET; let spendtx = {'recipient_id' : target_addr, 'amount' : amount, 'fee' : ae_node.MIN_FEE, 'sender_id' : user_addr, 'payload' : ""}; let tx_obj = await ae_node.PostSpend(endpoint, spendtx); //--------------------------------------------------------------- // STEP 4: HAVE THE USER SIGN THE TRANSACTION // // There are two options: // // 1. `tx_sign_no_propagate` simply has the wallet sign the // transaction, and return the signed transaction back to you // // 2. `tx_sign_yes_propagate` has the wallet sign the transaction // and also propagates it into the network. It returns a more // elaborate data structure, which is documented in somewhere // the AWCP module documentation. //--------------------------------------------------------------- let result = await sk.tx_sign_no_propagate(skl, tx_obj, sk.NETWORK_ID_TESTNET, sk.TIMEOUT_DEF_SIGN); console.log(result); } main(); ``` # Known pitfalls - See notes in sidekick module about potential state crossups if your document logic is multi-threaded. - Has only been tested against Firefox-on-Linux - Have not worked out good user idioms for handling errors # How the release is structured and why The idea of the release is that it contains exactly what is needed in order to drop Sidekick into your project and start using it. No more, no less. A release has the following structure: ``` sidekick_dist_X-Y-Z/ dist_js/............tsc-generated human-readable JS tree foo.js..............the actual code that is run foo.d.ts............included so that your TypeScript code can typecheck against sidekick foo.js.map..........debug symbols that map foo.js to locations in the TypeScript source src_ts/.............included so that the browser's debugger works foo.ts README.txt LICENSE.txt ``` We use semantic versioning: `X.Y.Z` - A change in `X` means an API-breaking change - A change in `Y` means an non-breaking API change - A change in `Z` means no change to the API There is no documentation included in the release. There is autogenerated API documentation linked above, which is generated from this file and the sources that are included in the release. ## What each file does ``` src_ts/.....................TypeScript source for sidekick library awcp/.......................Aepp-Waellet Communication Protocol awcp.ts.....................Protocol definition msgq.ts.....................Block-on-raseev implementation msgr.ts.....................Protocol implementation helpers.ts..................what it sounds like sidekick.ts.................top-level module skylight.ts.................primary data structure ``` ## Where is the NPM package or the webpack bundle? There isn't one. ### Why? Sidekick is a library that deals with cryptocurrency. The security model is based on transparency and trust. A user must be able to inspect code that is running on his hardware handling his money. We don't support NPM because of the security issues that NPM introduces. Briefly, the code can change at any time under the developer's nose without the developer knowing. The [leftpad debacle][lpad] and the [RIAEvangelist debacle][ria] are good examples of the types of vulnerabilities that package managers like NPM enable. [lpad]: https://archive.ph/Qsh7j [ria]: https://archive.ph/OF5I9 We don't use something like webpack because that introduces an opaque rewrite using an untrusted tool. Webpack could plausibly alter the runtime behavior of the program, and we would have no way to detect that. Even if we trusted webpack, how do we obtain webpack? NPM. So. It is debatable whether or not we should trust the TypeScript compiler (TSC). On the whole, TSC probably makes Sidekick more secure, simply by virtue of increasing overall code quality and eliminating the largest categories of potential bugs. Moreover, the output that TSC produces is human-readable, and has a very straightforward mapping to the original source code. A human can easily read the TSC-generated JavaScript tree, even without the aid of the source map, and have a high degree of faith that the code is trustworthy and that TSC is behaving as promised. # How to obtain the source tree The source tree is included in your release. You can clone the git repository with ``` git clone https://gitlab.com/DoctorAjayKumar/sidekick.git ``` # Repo file tree (non-exhaustive) ``` examples/...................Examples contract-examples/..........Example Sophia smart contracts examples_html/..............Low-budget example interfaces do_a_transfer.html......Send money to an arbitrary address hello.html..............Hello world ide.html................Play around with smart contracts examples_src_ts/............TypeScript source for each example parasite/...................JavaScript shim that does what your backend code ordinarily would do ae_compiler.ts..............Talk to a remote Sophia compiler JSON HTTP interface ae_node.ts..................Talk to a node (for forming transactions, querying chain, etc) net.ts......................Network helper functions do_a_transfer.ts........Send money to an arbitrary address ide.ts..................Play around with smart contracts tsconfig.json...............Examples-specific tsc configuration src_ts/.....................TypeScript source for sidekick library awcp/.......................Aepp-Waellet Communication Protocol awcp.ts.....................Protocol definition msgq.ts.....................Block-on-raseev implementation msgr.ts.....................Protocol implementation helpers.ts..................what it sounds like sidekick.ts.................top-level module skylight.ts.................primary data structure LICENSE.txt.................MIT License Makefile....................Makefile make........................Equivalent to `make build` make build..................Run tsc make clean..................rm -r dist_js sidekick_dist docs \ examples/examples_dist_js make dist...................Build a release tarball directory make jsdoc..................Build the HTML documentation make build_examples.........cd examples && tsc make serve_examples.........cd examples && python3 -m \ http.server 8001 README.txt..................This file STYLE_GUIDE.md..............Explains why the code looks so weird TODO.md.....................what it sounds like tsconfig.json...............Configuration file for tsc ``` # How to build a release You will need the TypeScript compiler installed. See prereqs section. make dist ## Prereqs for building source files If you want to edit and rebuild the source files, you need TypeScript installed, and you should update npm. npm install -g typescript npm install -g npm ## Protip: avoid using `sudo npm install -g` If you want to avoid using sudo ``` mkdir ~/.npm-packages npm config set prefix "${HOME}/.npm-packages" ``` Edit `~/.bashrc` or `~/.zshrc` with ``` NPM_PACKAGES="${HOME}/.npm-packages" export PATH=$NPM_PACKAGES/bin:$PATH ``` Source: https://github.com/sindresorhus/guides/blob/main/npm-global-without-sudo.md # How to build and view documentation ``` make build_docs make serve_docs ```