Skip to content

Add Wrapped TON (wTON)#746

Open
krebernisak wants to merge 12 commits into
mainfrom
feat/wton
Open

Add Wrapped TON (wTON)#746
krebernisak wants to merge 12 commits into
mainfrom
feat/wton

Conversation

@krebernisak
Copy link
Copy Markdown
Collaborator

No description provided.

@krebernisak krebernisak requested a review from a team as a code owner May 20, 2026 13:22
Copilot AI review requested due to automatic review settings May 20, 2026 13:22
@krebernisak krebernisak marked this pull request as draft May 20, 2026 13:22
@github-actions
Copy link
Copy Markdown

👋 krebernisak, thanks for creating this pull request!

To help reviewers, please consider creating future PRs as drafts first. This allows you to self-review and make any final changes before notifying the team.

Once you're ready, you can mark it as "Ready for review" to request feedback. Thanks!

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds initial Wrapped TON (wTON) Jetton-style contracts plus supporting Jetton library utilities/types.

Changes:

  • Introduces wTON JettonMinter and JettonWallet contracts and a short README.
  • Refactors/extends Jetton shared code (errors, fees management, wallet address derivation) and updates message/storage types.
  • Updates the Jetton onramp mock example to import the new jetton-utils module.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 15 comments.

Show a summary per file
File Description
contracts/contracts/wton/README.md Adds brief documentation for the new wTON module.
contracts/contracts/wton/JettonWallet.tolk Implements the wTON Jetton wallet contract (transfers, burns, bounce handling, getters).
contracts/contracts/wton/JettonMinter.tolk Implements the wTON Jetton minter contract (mint/burn handling, wallet address queries, metadata getter).
contracts/contracts/lib/jetton/utils.tolk Removes the previous Jetton utility module.
contracts/contracts/lib/jetton/storage.tolk Updates Jetton storage types (admin fields optional, metadataUri now string).
contracts/contracts/lib/jetton/messages.tolk Updates Jetton message schemas (several fields now optional; metadata update payload type adjusted).
contracts/contracts/lib/jetton/jetton-utils.tolk Adds new wallet address/state-init derivation helpers.
contracts/contracts/lib/jetton/fees-management.tolk Adds shared fee/gas/storage calculations and “enough gas” checks.
contracts/contracts/lib/jetton/errors.tolk Adds shared Jetton error constants.
contracts/contracts/examples/jetton/onramp_mock.tolk Updates imports and local constants to align with the Jetton refactor.
Comments suppressed due to low confidence (1)

contracts/contracts/lib/jetton/fees-management.tolk:58

  • Spelling typo in comment: "iternal_transfer" should be "internal_transfer".
        // but last one is optional (it is ok if it fails)
        fwdCount * fwdFee +
        forwardInitStateOverhead() + // additional fwd fees related to initstate in iternal_transfer
        calculateGasFee(MY_WORKCHAIN, sendTransferGasConsumption) +

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +23 to +25
in.bouncedBody.skipBouncedPrefix();

val msg = lazy BounceOpToHandle.fromSlice(in.bouncedBody);
Comment thread contracts/contracts/wton/JettonWallet.tolk
Comment on lines +25 to +32
fun onBouncedMessage(in: InMessageBounced) {
in.bouncedBody.skipBouncedPrefix();
// process only mint bounces; on other messages, an exception will be thrown, it's okay
val msg = lazy InternalTransferStep.fromSlice(in.bouncedBody);

var storage = lazy MinterStorage.load();
storage.totalSupply -= msg.jettonAmount;
storage.save();
Comment thread contracts/contracts/wton/JettonMinter.tolk
Comment thread contracts/contracts/wton/JettonMinter.tolk Outdated
Comment thread contracts/contracts/lib/jetton/errors.tolk
Comment thread contracts/contracts/lib/jetton/jetton-utils.tolk Outdated
@@ -0,0 +1,73 @@
// SPDX-License-Identifier: MIT
// Imported from https://github.com/ton-blockchain/tolk-bench/blob/0f416ca611fbfa25e736973d01e5fb70af485468/contracts_Tolk/03_notcoin/messages.tolk
}

fun checkAmountIsEnoughToTransfer(msgValue: int, forwardTonAmount: int, fwdFee: int) {
var fwdCount = forwardTonAmount != 0 ? 2 : 1; // second sending (forward) will be cheaper that first
Comment thread contracts/contracts/wton/JettonMinter.tolk
return {
workchain: MY_WORKCHAIN,
stateInit: {
code: jettonWalletCode,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if there's a way to use the hash of the code instead to save on storage and compute fees. IIUC the hash is computed from leaves to root, so the hash of the code should always result in the same.

// SPDX-License-Identifier: MIT

const ERROR_INVALID_OP = 72
const ERROR_WRONG_OP = 0xffff
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused

const ERROR_WRONG_WORKCHAIN = 333
const ERROR_BALANCE_ERROR = 47
const ERROR_NOT_ENOUGH_GAS = 48
const ERROR_INVALID_MESSAGE = 49
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused

val excessesMsg = createMessage({
bounce: BounceMode.NoBounce,
dest: msg.sendExcessesTo,
value: 0,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But we should be sending that amount of TON, right?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're sending whatever bounced after a failed mint with SEND_MODE_CARRY_ALL_REMAINING_MESSAGE_VALUE

bounce: BounceMode.Only256BitsOfBody,
dest: calcDeployedJettonWallet(msg.mintRecipient, contract.getAddress(), storage.jettonWalletCode),
value: msg.tonAmount,
body: msg.internalTransferMsg,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we have owner checks here? I think this should be permissionless. We are missing:

  • checking that incomming value is greater than msg.tonAmount
  • There is redundancy between MintNewJettons.tonAmount and internalTransferMsg.jettonAmount. Maybe we can drop MintNewJettons.tonAmount. Otherwise, we should be asserting both match
  • we need to reserve jettonAmount of TON

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check the updated code.

There is redundancy between MintNewJettons.tonAmount and internalTransferMsg.jettonAmount. Maybe we can drop MintNewJettons.tonAmount. Otherwise, we should be asserting both match

Not redundant, they are used differently; MintNewJettons.tonAmount is the TON sent with internalTransferMsg and nternalTransferMsg.jettonAmount is the Jetton amount. Now Jetton amount should equal TON amount so we update the sent value with value: jettonAmount + msg.tonAmount,

@krebernisak krebernisak marked this pull request as ready for review May 22, 2026 14:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants