Upgradable multisignature wallet, with custom scripts to deserialize and inspect the contents of BOC files containing TL-B Message constructors, create, sign and verify wallet requests and wallet code upgrades.
All custom data structures used in the wallet can be viewed as a custom TL-B scheme in proto/scheme.tlb (some basic TON constructors are also included for reference).
*`lib.fif` - Library with functions to deserialize and inspect contents of TON messages
The external TL-B Message X object is deserialized, with info printed to stdout.
Then, the custom `multiSigWrapper`, `wrappedMessage`, `modeMessage` and `codeMessage` TL-B objects are deserialized, with info printed to stdout.
In the case of `modeMessage` (simple message to be sent by wallet once enough signatures are gathered), a the internal Message X object is also unpacked, with info printed to stdout.
In the case of `codeMessage`, the new public key dictionary is unpacked an printed to stdout, along with a csr dump of the code slice and other info.
The first of the keys must be a private key (with ID `<key-id>`), used to sign the wallet update request saved to `<wallet-update>.boc`; the rest MUST be public keys.
Create or generate public key files from private keys using gen-pub.fif privkey
Min `<k>` (1-10) signatures required to send an order; load `<n>` pre-existing public keys from files `<key1...n>`.
Creates a request to shared wallet created by wallet-create.fif, with private key `<key-id>` loaded from file `<key>.pk` and address from `<filename-base>.addr`, and saves it into `<savefile>.boc` ('wallet-query.boc' by default)
The `test.sh` script contains a full set of commands to test every fift script.
You might want to run each command inside `test.sh` separately (there are also multiple comments explaining what each line does in detail), or run `./test.sh | less` to be able to better review the output of each command.
The script starts by creating ten public/private keypairs using `gen-pub.fif`:
After extracting the computed wallet address from `log`, the scripts generates an initial wallet request, requesting to send 10 grams to itself (just as a test, saving to `a.boc`).
Here, note the `a 0`: to save space, I have chosen to not use the entire ecdh key as key in the signature dictionary.
Instead, a **key ID** is used to distinguish signatures made by certain keys: this is a simple 4-bit value (instead of 256 bits!), equal to the position of the key in the `wallet-create` argument list.
In this case, the `a` key was the first key (`{a..j}` in Bash is shorthand for `a b c .. j`), so the ID is `0`.
What follows is the address, the seqno, the amount of grams and the savefile (`a`) for the query.
`test-update.sh` should be run after `test.sh`, it executes a similar set of operations:
* The wallet is initialized as before (10 signatures required to send message)
* A simple message is created with only 1 signature (`a`), sending 10 grams to the wallet itself
* This message is sent to the wallet and stored, waiting for further (9 more) signatures
* A **code upgrade** message is created with only 1 signature (`a`): the upgrade sets to 3 the minimum number of required signatures
* This message is sent to the wallet and stored, waiting for further (9 more) signatures
* 9 more signatures (`b-j`) are appended to the **code upgrade** message
* The full **code upgrade** message is sent to the wallet, setting to **3** the minimum number of signatures required to send the message, also modifying the code by adding a new method.
This code upgrade message, however, was signed by all **10** users, so it's really just a simpler way to upgrade a wallet: instead of creating new wallet => moving all funds to new upgraded wallet, a simple code upgrade message is signed.
* 2 more signatures (`b`, `c`) are appended to the **simple** message
* The simple message with additional signatures (`b`, `c`) is sent to the wallet, sending out wallet funds since all **3 required signatures** are gathered.
If we were running on the blockchain, at this point the smart contract code root would be updated to point to the new code, allowing us to use the new `getMagic` (77784) method that returns (420, 69) when called.
Since we're running in a local TVM instance, and fift's `runvm` primitives have no way of returning the output action list (including changes to the code), the code isn't actually updated, but the signature list and minSig data structures in the persistent contract storage are indeed returned to the fift stack and re-used for the next TVM method call, allowing us to test the feature.