Skip to main content

How to make a simple multisig contract

💡 Overview​

This tutorial help you learn how to deploy your multisig contract.
Recall, that (n, k)-multisig contract is a multisignature wallet with n private keys holders, which accepts requests to send messages if the request (aka order, query) collects at least k signatures of the holders.

Based on original multisig contract code and updates by akifoq:

starter tip

For anyone new with multisig: What is Multisig Technology? (video)

📖 What you'll learn​

  • How to create and customize a simple multisig wallet.
  • How to deploy multisig wallet using lite-client.
  • How to sign request and send it in message to blockchain.

⚙ Set your environment​

Before we begin our journey, check and prepare your environment.

  • Install func, fift, lite-client binaries and fiftlib from the Installation section.
  • Clone repository and open its directory in CLI.
https://github.com/akifoq/multisig.git
cd ~/multisig

🚀 Let's get started!​

  1. Compile the code to fift.
  2. Prepare multisig owners keys.
  3. Deploy your contract.
  4. Interact with deployed multisig wallet in 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 name of the file where the private key will be written.

For example:

fift -s new-key.fif multisig_key

We'll receive a file multisig_key.pk with 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 in file keys.txt. One Public Key per line, it's important.

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 current key. It is recommended to use a unique $WALLET_ID$ for each new wallet with the same key.
  • $KEYS_COUNT$ - the number of keys needed for confirmation, usually equal to the number of public keys
wallet_id explained

It's possible to create many wallets with the same keys (Alice key, Bob key). What to do if Alice and Bob already have 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)
info

If you have "public key must be 48 characters long" error, please make sure your keys.txt has unix type word wrap - LF. For example, word wrap can be changed via Sublime text editor.

tip

Bounceable address is better to keep - this is the address of the wallet.

Activate your contract​

You need to send some TON to our newly generated treasure. For example 0.5 TON.

After that, you need to run lite-client:

lite-client -C global.config.json
Where get global.config.json?

You can get fresh config file global.config.json for mainnet or testnet.

After starting lite-client, it's best to run the time command in lite-client console to make sure the connection was successful:

time

Okay, lite-client is works!

After 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 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$ - name of file for compiled message.

For example:

fift -s create-msg.fif EQApAj3rEnJJSxEjEHVKrH3QZgto_MQMOmk8l72azaXlY1zB 0.1 message
tip

To add comment for your transaction, use -C comment attribute. To get more information, run create-msg.fif file without parameters.

Choose a wallet​

Next you need to choose a wallet to send a coins from:

fift -s create-order.fif $WALLET_ID$ $MESSAGE$ -t $AWAIT_TIME$

Where

  • $WALLET_ID$ — is an ID of wallet backed by this multisig contract.
  • $AWAIT_TIME$ — Time in seconds that smart contract will await signs from multisig wallet's owners for request.
  • $MESSAGE$ — here is a name of message boc-file created on the previous step.
info

If time equals $AWAIT_TIME$ passed before the request signs, the request becomes expired. As usual, $AWAIT_TIME$ equals a couple of hours (7200 seconds)

For example:

fift -s create-order.fif 0 message -t 7200

Ready file will be saved in order.boc

info

order.boc needs to be shared with key holders, they have to sign it.

Sign your part​

To sign, you need to do:

fift -s add-signature.fif $KEY$ $KEY_INDEX$
  • $KEY$ - name of the file containing the private key to sign, without extension.
  • $KEY_INDEX$ - index of the given key in keys.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, will be enough only one sign of wallet's owner. 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 after 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! 🚀🚀🚀

What's next?​