Make a simple multisig contract with fift
This information is very low-level. It could be hard for newcomers and designed for advanced people who want to understand fift. The use of fift is not required in everyday tasks.
đĄ Overviewâ
This tutorial helps you learn how to deploy your multisig contract.
Recall that an (n, k)-multisig contract is a multisignature wallet with n private key holders, which accepts requests to send messages if the request (aka order, query) collects at least k holders' signatures.
Based on the original multisig contract code and updates by akifoq:
- Original TON Blockchain multisig-code.fc
- akifoq/multisig with fift libraries to work with multisig.
For anyone new to multisig: What is Multisig Technology? (video)
đ What you'll learnâ
- How to create and customize a simple multisig wallet.
- How to deploy a multisig wallet using lite-client.
- How to sign a request and send it in a message to the blockchain.
â Set your environmentâ
Before we begin our journey, check and prepare your environment.
- Install
func
,fift
,lite-client
binaries, andfiftlib
from the Installation section. - Clone the repository and open its directory in CLI.
git clone https://github.com/akifoq/multisig.git
cd ~/multisig
đ Let's get started!â
- Compile the code to fift.
- Prepare multisig owners' keys.
- Deploy your contract.
- Interact with the deployed multisig wallet in the blockchain.
Compile the contractâ
Compile the contract to Fift with:
func -o multisig-code.fif -SPA stdlib.fc multisig-code.fc
Prepare multisig owners' keysâ
Create participants' keysâ
To create a key, you need to run:
fift -s new-key.fif $KEY_NAME$
- Where
KEY_NAME
is the file name where the private key will be written.
For example:
fift -s new-key.fif multisig_key
We'll receive a multisig_key.pk
file with the private key inside.
Collect public keysâ
Also, the script will issue a public key in the format:
Public key = Pub5XqPLwPgP8rtryoUDg2sadfuGjkT4DLRaVeIr08lb8CB5HW
Anything after "Public key = "
needs to be saved somewhere!
Let's store it in a file called keys.txt
. It's important to have one public key per line.
Deploy your contractâ
Deploy via lite-clientâ
After creating all the keys, you need to collect the public keys into a text file, keys.txt
.
For example:
PubExXl3MdwPVuffxRXkhKN1avcGYrm6QgJfsqdf4dUc0an7/IA
PubH821csswh8R1uO9rLYyP1laCpYWxhNkx+epOkqwdWXgzY4
After that, you need to run:
fift -s new-multisig.fif 0 $WALLET_ID$ wallet $KEYS_COUNT$ ./keys.txt
$WALLET_ID$
- the wallet number assigned for the current key. It is recommended that each new wallet with the same key use a unique$WALLET_ID$
.$KEYS_COUNT$
- the number of keys needed for confirmation, usually equal to the number of public keys.
It is possible to create many wallets with the same keys (Alice key, Bob key). What should we do if Alice and Bob already have a treasure? That's why $WALLET_ID$
is crucial here.
The script will output something like:
new wallet address = 0:4bbb2660097db5c72dd5e9086115010f0f8c8501e0b8fef1fe318d9de5d0e501
(Saving address to file wallet.addr)
Non-bounceable address (for init): 0QBLuyZgCX21xy3V6QhhFQEPD4yFAeC4_vH-MY2d5dDlAbel
Bounceable address (for later access): kQBLuyZgCX21xy3V6QhhFQEPD4yFAeC4_vH-MY2d5dDlAepg
(Saved wallet creating query to file wallet-create.boc)
If you have a "public key must be 48 characters long" error, please make sure your keys.txt
has a Unix-type word wrap - LF. For example, word wrap can be changed via the Sublime text editor.
A bounceable address is better to keep - this is the wallet's address.
Activate your contractâ
You need to send some TON to our newly generated treasure. For example, 0.5 TON. You can send testnet coins via @testgiver_ton_bot.
After that, you need to run lite-client:
lite-client -C global.config.json
global.config.json
?After starting lite-client, it's best to run the time
command in the lite-client console to make sure the connection was successful:
time
Okay, lite-client works!
After that, you need to deploy the wallet. Run the command:
sendfile ./wallet-create.boc
After that, the wallet will be ready to work within a minute.
Interact with a multisig walletâ
Create a requestâ
First, you need to create a message request:
fift -s create-msg.fif $ADDRESS$ $AMOUNT$ $MESSAGE$
$ADDRESS$
- address where to send coins.$AMOUNT$
- number of coins.$MESSAGE$
- the file name for the compiled message.
For example:
fift -s create-msg.fif EQApAj3rEnJJSxEjEHVKrH3QZgto_MQMOmk8l72azaXlY1zB 0.1 message
Use the -C comment
attribute to add a comment for your transaction. To get more information, run the create-msg.fif file without parameters.
Choose a walletâ
Next, you need to choose a wallet to send coins from:
fift -s create-order.fif $WALLET_ID$ $MESSAGE$ -t $AWAIT_TIME$
Where
$WALLET_ID$
â is an ID of the wallet backed by this multisig contract.$AWAIT_TIME$
â Time in seconds that the smart contract will await signs from multisig wallet's owners for the request.$MESSAGE$
â here is the name of the message boc-file created in the previous step.
The request expires if the time equals $AWAIT_TIME$
passed before the request signs. As usual, $AWAIT_TIME$
equals a couple of hours (7200 seconds).
For example:
fift -s create-order.fif 0 message -t 7200
The ready file will be saved in order.boc
.
order.boc
must be shared with key holders; they must sign it.
Sign your partâ
To sign, you need to do:
fift -s add-signature.fif $KEY$ $KEY_INDEX$
$KEY$
- file name containing the private key to sign, without extension.$KEY_INDEX$
- index of the given key inkeys.txt
(zero-based).
For example, for our multisig_key.pk
file:
fift -s add-signature.fif multisig_key 0
Create a messageâ
After everyone has signed the order, it needs to be turned into a message for the wallet and signed again with the following command:
fift -s create-external-message.fif wallet $KEY$ $KEY_INDEX$
In this case, only one sign of the wallet's owner will be enough. The idea is that you can't attack a contract with invalid signatures.
For example:
fift -s create-external-message.fif wallet multisig_key 0
Send sign to TON blockchainâ
After that, you need to start the light client again:
lite-client -C global.config.json
And finally, we want to send our sign! Just run:
sendfile wallet-query.boc
If everyone else signed the request, it will be completed!
You did it, ha-ha! đđđ