npm install
npm run build
npm run test
Note: if you experience issues with running the test try to test using node.js 14
Current jetton contracts extend and modify some behavior of original contracts https://github.com/ton-blockchain/minter-contract. But it is fully compatible with contracts that use ordinary jettons.
jetton-platform.fc
contract which allows the upgrade of wallet contracts- on-chain jetton content encoding
on_accept_tokens_burn
callback for integration with other contractsupgrade_wallet
andupgrade_minter
opcodes for minter and wallet contracts upgrade- additional admin opcodes in root
set_wallet_code
anddeploy_wallet
provide_info
andtake_info
to get the minter's decimals, name, and symbol for another contract
The platform allows for upgradable and secure contracts without breaking compatibility between wallets of different versions.
Each contract in TVM receives a deterministic address from its code and init data: address = hash(code + init_data)
.
To make upgradable jetton wallets we use jetton-platform.fc as code and address of its owner and minter as init data.
To check that the sender is a valid Jetton wallet we also use platform code with the owner's and minter's addresses to derive a valid address
cell calculate_jetton_wallet_state_init(
slice owner_address,
slice jetton_master_address,
cell jetton_platform_code
) inline {
cell data = pack_jetton_wallet_data(
0,
owner_address,
jetton_master_address,
begin_cell().end_cell(),
jetton_platform_code,
0
);
return begin_cell()
.store_uint(0, 2)
.store_dict(jetton_platform_code) ;; code
.store_dict(data) ;; init data
.store_uint(0, 1)
.end_cell();
}
To upgrade wallet from platform and perform receive_tokens
:
;; update contract's code for future txs
set_code(wallet_code);
;; update contract's code for current receive_tokens() call. God bless us!!!
set_c3(wallet_code.begin_parse().bless());
;; for newly deployed jetton wallet only receive_tokens() call is possible
receive_tokens(
ms,
sender_address,
my_balance,
fwd_fee,
msg_value
);
Jetton's metadata builds on-chain.
Note: replace Jetton's icon URL with yours
slice image_slice = begin_cell()
.store_slice("https://ton-tokens-api.bf.works/image/")
.store_slice(my_workchain)
.store_slice(":")
.store_slice(my_hash)
.store_slice(".svg")
.end_cell()
.begin_parse();
cell content_dict = new_dict();
content_dict~udict_set_ref(256, "image"H, pack_metadata_value(image_slice));
content_dict~udict_set_ref(256, "decimals"H, pack_metadata_value(decimals_slice));
content_dict~udict_set_ref(256, "name"H, pack_metadata_value(name.begin_parse()));
content_dict~udict_set_ref(256, "symbol"H, pack_metadata_value(symbol_slice));
cell onchain_content = begin_cell()
.store_uint(0, 8)
.store_dict(content_dict)
.end_cell();
When the wallet's owner burns his jettons he will receive a notification callback from the minter. It needs for integration with other contracts or protocols e.a.: DEXes, lendings, bridges, etc.
It's also possible to upgrade wallet and minter contracts anytime if you find vulnerabilities in contracts or decided to extend their interface
These opcodes will provide you info about Jetton from the minter contract: decimals, name, symbol, etc. It's useful if you need to identify your contracts by tokens' names or need to make price oracle, curve-like DEX pools or some other useful stuff that needs Jetton's decimals, symbol, name, or your custom metadata (chain ID and base token address for a bridge for example)
When the wallet receives a transfer it will try to keep its balance before the tx or at least take some message's gas to pay for its storage. Wallet's balance can be: [min_tons_for_storage, ∞)
raw_reserve(max(ton_balance_before_msg, min_tons_for_storage), 2);
Also, you don't need to split your gas for op::transfer_notification()
and op::excesses()
.
In most cases, contracts want to send whole gas to notification or excesses callback.
Use a non-zero forward amount to send the whole gas to op::transfer_notification()
.
Otherwise, the whole gas will be sent to op::excesses()
op::drain()
in minter and wallet contracts to drain excesses from the contract's balancejetton-wallet.fc#get_wallet_platform_data()
getter to receive platform code and current wallet's versionjetton-minter.fc#get_jetton_meta()
getter to receive raw metadata without dictionaryjetton-minter.fc#get_jetton_platform_data()
getter to receive platform code and current wallet's code version