Learn
Wallet contract

Tact wallet contract

This article explains how wallet contract works in Tact, how to deploy and test this.

Did you notice something unclear, incorrect or get stuck with some issue in guide? Please ask a question in the Telegram chat (opens in a new tab) or text me directly @iftryalexg (opens in a new tab). Guide will be updated ASAP and all unclear points will be clarified 🚒💦🔥.

Set up your environment

For this project you should install

Tact wallet demo project

Get tact-wallet project from git:

git clone https://github.com/Reveloper/tact-wallet.git
cd tact-wallet

This project has ready to use TACT compiler, typescript + jest with ton-emulator (opens in a new tab), example how to test and deploy. You have ready-to-use commands configured for contract. Try to input them in terminal and look how it works:

yarn test # To test contract
yarn build # To build contract
yarn deploy # To deploy contract via deployment link
yarn deploy-api # To deploy through API(need to input deployment wallet in wallet.deploy-api.ts before using)

Briefing for Tact project structure

In the tact-wallet/sources/ directory placed core project files, that defines what yarn commands will do:

  1. File wallet.tact contract on Tact language, that will be compiled with Tact compiler in yarn build
  2. File wallet.spec.ts contents unit tests for yarn tests command. This command allow to launch local tests on your local IDE. Not necessary for deployment.
  3. File wallet.deploy.ts is a helper, that allow to deploy your wallet.tact compiled file(src/output) with deployment link. From the beginning you can deploy your smart contract via Sandbox (opens in a new tab)/Tonkeeper (opens in a new tab) application.
  4. Describes alternative deployment script wallet.deploy-api.ts for yarn deploy-api according to your contract.tact to send deployment message from deployment wallet. You need to input your deployment wallet 24 words here.

What is wallet contract general idea?

Wallet similar to usual smart contract serve as a platform for managing and transferring funds in a decentralized and secure manner. However, it is important to note that while a smart contract may have built-in features for handling funds, additional steps may be necessary to make the user experience more convenient and secure. This may involve handling additional user stories and implementing additional features to meet real-life requirements.

Let's describe small list of feature for wallet contract:

  • Deployment of smart contract where placed information of its owner with public key.
  • Requests for action with funds by owner.
  • Get and handle messages from other smart-contracts, including incoming transfer of funds.

Explorers recognize contract's type by hash of the smart contract's code or by interfaces founded in smart contract. If you check your common wallet contract with explorer (opens in a new tab), you will see that it recognized with type "wallet". From this side, tact-wallet contract is a new version, and it will have different hash(because of original FunC contract and FunC compiled from Tact will be absolutely different). On the same reason current wallet application will not support Tact contract until they add its tact version to their applications.

Contract structure

Tact language allows to define behaviour of contracts with convenient tools as Contract, Trait, Receiver, Message. Generally simple contract has such structure:

  • Includes
  • Custom Messages and Structs declaration
  • Contract's body
    • Fields

    • Init function

    • Functions

    • Receivers

    • Getters

Wallet contract overview

As we mentioned earlier, contract consists of

  1. Includes and struct definition
  2. Contract's body

For contract wallet we will define struct Transfer as base struct for messages:

tact-wallet/sources/wallet.tact

Next will be wallet contract body with all included sections:

tact-wallet/sources/wallet.tact

Wallet fields

Now, let's take a look one by one these section and find out their functions. First - contract fields. In these section we describe data, that will be store in Blockchain inside contract's storage. Shortly, it calls on-chain. For features of wallet contract we declare following:

  • seqno - is field that store last executed transaction id. Used for deduplication of transactions.
  • key - key of owner. Used for checks if transaction asked from wallet owner.
  • walletId - wallet id, serves for supporting different(up to uint64) instance of wallets based on one key. For each walledId we deploy unique smart contract with access by same key.
tact-wallet/sources/wallet.tact

Wallet init

The init() function define first state of our smart contract for deploying process. To deploy our wallet contract we will keep public key and id in its store. Usually, public keypair - public and secret keys computes locally on device which initiate deployment. Secret key stores locally for future signing transaction of owner, and public key sent as argument in init() function. Wallet ID, according to definition of field allows to create several(up to uin64) wallets based on same keypair.

tact-wallet/sources/wallet.tact

Wallet receivers

Contract receivers define how contract acts depending on what it was received in incoming message. Notice, that when contract sends outgoing message or do computation it pays network fees from its contract balance. Read more about fees in TON here. For wallet contract we describe the following:

  • msg: TransferMessage - receiver that handles incoming message and performs outcoming message from our wallet. It will check op_code and seqno to be sure, that transaction valid. If requires successes, we will increment seqno counter and send outgoing message.
  • msg: Slice - if msg_body is Slice we check that incoming message was not bounced before, and if this requirements successes increment our seqno counter.
  • "notify" - receiver declares actions when incoming message contents string comment "notify". Here it will increment seqno field.
  • "duplicate" - receiver declares actions when incoming message contents string comment "duplicate". Here it will increment seqno field.
  • bounced() - special receiver for handling bounced messages.
tact-wallet/sources/wallet.tact

Wallet getters

Get functions allows to get information about contract's data for free. It's helpfully for us, as we want get seqno before every transaction we want made.

  • get publicKey() - returns Integer number of public key for smart contract;
  • get walletId() - returns walletId that was used to initiate this wallet;
  • get seqno() - returns current seqno of wallet
tact-wallet/sources/wallet.tact

Wallet tests overview

From the beginning example of unit tests distributed with contract in wallet.spec.contract. You can launch test via yarn test or specify your own with help of jest and ton-emulator library.

Wallet deployment

For deployment wallet we have two demo options to run:

yarn deploy
yarn deploy-api

Deployment with user wallet application

As simple way offered to deploy smart contract with usual wallet application. The trick is that we just need specify our outgoing message with data we need(we've already done this) and input this data in message. Wallet applications supports transfer links and QR, so we can use it for our deployment message. The following scheme shows how deployment process via wallet applications works.

Tact wallet deploy

Step list here:

  1. Install wallet application on device from which we will do deployment.
  2. Get test Toncoins on our wallet application with bot.
  3. Run deployment script for deployment:
yarn deploy
  1. Use deployment link or QR with wallet application and confirm the sending of outgoing message.
  2. Notice our new smart contract deployed on the address we sent the message.

Deployment with TON public API

The way, some applications in production uses is public API. It is acceptable solution for services that not requires operative updating data and just need sometimes send messages. Demo script for this process needs to fill with your wallet 24 words of wallet in testnet, you also can use your wallet from previous step. So, this wallet will call deployment wallet and will be use in similar to wallet application way.

Tact API deploy

Step list here:

  1. Install wallet application on device from which we will do deployment and get toncoins.(Using same wallet from previous step)
  2. Input your test wallet 24 words in deployment script soucre/wallet.deploy-api.ts.
  3. Run yarn deploy-api in terminal command line.
  4. Notice in blockchain explorer our new smart contract deployed according address in console log where we sent the deployment message.

Summary about Tact wallet

TON dApps uses code hash as identifier of contract type, and wallet contract will absolutely different hash for its, so it will not work from the box. This contract is generic, so in production all application already set up for using original FunC contract, but still it is most used contract so it was used for learning and explanation purposes of how it works. You can learn more about launching and testing your own tact contract from Jetton Tact article.