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
- Git. Essential tool for every developer to work with repositories. Download it here (opens in a new tab).
- NodeJS. We will use JavaScript with TypeScript mode as the most popular choice for dApp development on TON. Download it here (opens in a new tab).
- JavaScript IDE. Your normal choice for development. VSCode (opens in a new tab), for example.
- Wallet app. You need one of TON noncustodial testnet wallet app (better with support Walletv4), for example Sandbox (opens in a new tab)/Tonkeeper (opens in a new tab). This is as part of simplify demonstration, you also can get access to your wallet from code, example added in demo.
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:
- File
wallet.tact
contract on Tact language, that will be compiled with Tact compiler inyarn build
- File
wallet.spec.ts
contents unit tests foryarn tests
command. This command allow to launch local tests on your local IDE. Not necessary for deployment. - File
wallet.deploy.ts
is a helper, that allow to deploy yourwallet.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. - Describes alternative deployment script
wallet.deploy-api.ts
foryarn deploy-api
according to yourcontract.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
- Includes and struct definition
- Contract's body
For contract wallet we will define struct Transfer as base struct for messages:
Next will be wallet contract body with all included sections:
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 samekey
.
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.
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.
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
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.
Step list here:
- Install wallet application on device from which we will do deployment.
- Get test Toncoins on our wallet application with bot.
- Run deployment script for deployment:
yarn deploy
- Use deployment link or QR with wallet application and confirm the sending of outgoing message.
- 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.
Step list here:
- Install wallet application on device from which we will do deployment and get toncoins.(Using same wallet from previous step)
- Input your test wallet 24 words in deployment script
soucre/wallet.deploy-api.ts
. - Run
yarn deploy-api
in terminal command line. - 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.