Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 41 additions & 1 deletion template/empty/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,50 @@

## How to use

- `pmRun build` – build `.ts` API for contract
- `pmRun build` – build contracts and the `.ts` wrappers
- `pmRun test` – build contracts and run jest tests
- `pmRun fmt` – fix source code formatting
- `pmRun lint` – run semantic checks with `misti` linter
- `pmRun verifier:testnet` – deploy contract to testnet
- `pmRun verifier:mainnet` – deploy contract to mainnet
- `pmRun fmt:check` – check source code formatting (for CI)

## Available CLIs

- `tact` – Tact compiler
- `tact-fmt` – Tact formatter
- `unboc` – Disassembler
- `@nowarp/misti` – Misti static analyzer
- `jest` – Jest testing framework

Use `npx` to run any of the CLIs available. For example, to invoke the Tact formatter, execute this:

```shell
npx tact-fmt
```

## Learn more about Tact

- [Website](https://tact-lang.org/)
- [Documentation](https://docs.tact-lang.org/)
- [Learn Tact in Y minutes](https://docs.tact-lang.org/book/learn-tact-in-y-minutes/)
- [Debugging and testing Tact contracts](https://docs.tact-lang.org/book/debug/)
- [Gas best practices](https://docs.tact-lang.org/book/gas-best-practices/)
- [Security best practices](https://docs.tact-lang.org/book/security-best-practices/)
- [Awesome Tact](https://github.com/tact-lang/awesome-tact)

For more interesting contract examples, see the [Tact's DeFi Cookbook](https://github.com/tact-lang/defi-cookbook).

## Community

If you can’t find the answer in the [docs](https://docs.tact-lang.org), or you’ve tried to do some local testing and it still didn’t help — don’t hesitate to reach out to Tact’s flourishing community:

- [`@tactlang` on Telegram](https://t.me/tactlang) - Main community chat and discussion group.
- [`@tactlang_ru` on Telegram](https://t.me/tactlang_ru) _(Russian)_
- [`@tact_kitchen` on Telegram](https://t.me/tact_kitchen) - Channel with updates from the team.
- [`@tact_language` on X/Twitter](https://x.com/tact_language)
- [`tact-lang` organization on GitHub](https://github.com/tact-lang)
- [`@ton_studio` on Telegram](https://t.me/ton_studio)
- [`@thetonstudio` on X/Twitter](https://x.com/thetonstudio)

Good luck on your coding adventure with ⚡ Tact!
34 changes: 25 additions & 9 deletions template/empty/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,31 @@ import { ContractName } from "./output/projectName_ContractName";
async function main() {
console.log("Deploying...");
const toProduction = process.argv.length === 3 && process.argv[2] === "mainnet";
const init = await ContractName.init();
const prepare = await prepareTactDeployment({
pkg: await readFile(resolve(__dirname, "output", "projectName_ContractName.pkg")),
data: init.data.toBoc(),
testnet: !toProduction,
});
const address = contractAddress(0, init).toString({ testOnly: !toProduction });
console.log(`Contract address: ${address}`);
console.log(`Please, follow deployment link: ${prepare}`);

// ContractName
{
// Default (initial) values of persistent state variables are supplied here
const init = await ContractName.init();

// Obtaining a convenient link to deploy a new contract in the mainnet or testnet,
// which could be used by your existing Toncoin wallet.
const prepare = await prepareTactDeployment({
// The .pkg file is a special JSON file containing the compiled contract,
// its dependencies, and all related metadata.
//
// See: https://docs.tact-lang.org/ref/evolution/otp-006/
pkg: await readFile(resolve(__dirname, "output", "projectName_ContractName.pkg")),
data: init.data.toBoc(),
testnet: !toProduction,
});

// Contract addresses on TON are obtained deterministically,
// from the initial code and data. The most used chain is basechain,
// which is the workchain with ID 0.
const address = contractAddress(0, init).toString({ testOnly: !toProduction });
console.log(`Contract address: ${address}`);
console.log(`Please, follow deployment link: ${prepare}`);
}
}

void main();
4 changes: 3 additions & 1 deletion template/empty/gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ output
.idea/
.DS_Store/
*.swp

.helix/
.vim/
.nvim/
49 changes: 37 additions & 12 deletions template/empty/src/main.spec.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,47 @@
import "@ton/test-utils";
import { toNano } from "@ton/core";
import { Blockchain } from "@ton/sandbox";
import { Blockchain, SandboxContract, TreasuryContract } from "@ton/sandbox";
import { ContractName } from "../output/projectName_ContractName";

it("should deploy correctly", async () => {
const blockchain = await Blockchain.create();
describe("ContractName", () => {
let blockchain: Blockchain;
let treasury: SandboxContract<TreasuryContract>;

const contract = blockchain.openContract(await ContractName.fromInit());
beforeEach(async () => {
blockchain = await Blockchain.create();
blockchain.verbosity.print = false;
treasury = await blockchain.treasury("deployer");
});

const deployer = await blockchain.treasury("deployer");
it("should be deployed correctly", async () => {
// Prepare a contract wrapper with initial data
const contract = blockchain.openContract(await ContractName.fromInit());

// call `receive()`
const result = await contract.send(deployer.getSender(), { value: toNano(1) }, null);
// Send a message that `receive()` would handle
const sendResult = await contract.send(treasury.getSender(), { value: toNano(1) }, null);

expect(result.transactions).toHaveTransaction({
from: deployer.address,
to: contract.address,
deploy: true,
success: true,
// Expect a successful deployment
expect(sendResult.transactions).toHaveTransaction({
from: treasury.address,
to: contract.address,
deploy: true,
success: true,
});
});

it("should do something else", async () => {
const contract = blockchain.openContract(await ContractName.fromInit());
let sendResult = await contract.send(treasury.getSender(), { value: toNano(1) }, null);
expect(sendResult.transactions).toHaveTransaction({
from: treasury.address,
to: contract.address,
deploy: true,
success: true,
});

// ...up to you!
});

// NOTE: To add your own tests, simply copy-paste any of the `it()` clauses
// within the `describe()`, and adjust the logic to match your expected outcome(s)
});
5 changes: 4 additions & 1 deletion template/empty/src/main.tact
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
contract ContractName() {
// empty receiver for deployment
// Empty receiver for the deployment,
// which expects the `null` message body
receive() {
// Forward the remaining value in the
// incoming message back to the sender
cashback(sender());
}
}
7 changes: 7 additions & 0 deletions template/empty/tact.config.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"$schema": "http://raw.githubusercontent.com/tact-lang/tact/main/src/config/configSchema.json",
"projects": [
{
"name": "projectName",
Expand All @@ -12,6 +13,12 @@
"interfacesGetter": false,
"experimental": {
"inline": false
},
"safety": {
"nullChecks": true
},
"optimizations": {
"internalExternalReceiversOutsideMethodsMap": false
}
}
}
Expand Down