Skip to main content

Make a simple multisig contract with fift

advanced level

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:

starter tip

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, and fiftlib 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!​

  1. Compile the code to fift.
  2. Prepare multisig owners' keys.
  3. Deploy your contract.
  4. 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.
wallet_id explained

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)
info

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.

tip

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
Where to get global.config.json?

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

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
tip

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.
info

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.

info

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 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, 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! 🚀🚀🚀

See also​