Browse Source

Added contracts

master
Lev 2 years ago
parent
commit
0c66fd8983
  1. 31
      build/jetton-wallet.deploy.ts
  2. 31
      build/minter.deploy.ts
  3. 10
      contracts/imports/discovery-params.fc
  4. 23
      contracts/imports/forward-fee-calc.fc
  5. 16
      contracts/imports/op-codes.fc
  6. 42
      contracts/imports/utils.fc
  7. 243
      contracts/jetton-wallet.fc
  8. 19
      contracts/jetton-wallet.tlb
  9. 239
      contracts/minter.fc
  10. 21
      contracts/minter.tlb
  11. 2
      package.json

31
build/jetton-wallet.deploy.ts

@ -0,0 +1,31 @@
import * as main from "../contracts/main";
import { Address, toNano, TupleSlice, WalletContract } from "ton";
import { sendInternalMessageWithWallet } from "../test/helpers";
// return the init Cell of the contract storage (according to load_data() contract method)
export function initData() {
return main.data({
ownerAddress: Address.parseFriendly("EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N").address,
counter: 10,
});
}
// return the op that should be sent to the contract on deployment, can be "null" to send an empty message
export function initMessage() {
return main.increment();
}
// optional end-to-end sanity test for the actual on-chain contract to see it is actually working on-chain
export async function postDeployTest(walletContract: WalletContract, secretKey: Buffer, contractAddress: Address) {
const call = await walletContract.client.callGetMethod(contractAddress, "counter");
const counter = new TupleSlice(call.stack).readBigNumber();
console.log(` # Getter 'counter' = ${counter.toString()}`);
const message = main.increment();
await sendInternalMessageWithWallet({ walletContract, secretKey, to: contractAddress, value: toNano(0.02), body: message });
console.log(` # Sent 'increment' op message`);
const call2 = await walletContract.client.callGetMethod(contractAddress, "counter");
const counter2 = new TupleSlice(call2.stack).readBigNumber();
console.log(` # Getter 'counter' = ${counter2.toString()}`);
}

31
build/minter.deploy.ts

@ -0,0 +1,31 @@
import * as main from "../contracts/main";
import { Address, toNano, TupleSlice, WalletContract } from "ton";
import { sendInternalMessageWithWallet } from "../test/helpers";
// return the init Cell of the contract storage (according to load_data() contract method)
export function initData() {
return main.data({
ownerAddress: Address.parseFriendly("EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N").address,
counter: 10,
});
}
// return the op that should be sent to the contract on deployment, can be "null" to send an empty message
export function initMessage() {
return main.increment();
}
// optional end-to-end sanity test for the actual on-chain contract to see it is actually working on-chain
export async function postDeployTest(walletContract: WalletContract, secretKey: Buffer, contractAddress: Address) {
const call = await walletContract.client.callGetMethod(contractAddress, "counter");
const counter = new TupleSlice(call.stack).readBigNumber();
console.log(` # Getter 'counter' = ${counter.toString()}`);
const message = main.increment();
await sendInternalMessageWithWallet({ walletContract, secretKey, to: contractAddress, value: toNano(0.02), body: message });
console.log(` # Sent 'increment' op message`);
const call2 = await walletContract.client.callGetMethod(contractAddress, "counter");
const counter2 = new TupleSlice(call2.stack).readBigNumber();
console.log(` # Getter 'counter' = ${counter2.toString()}`);
}

10
contracts/imports/discovery-params.fc

@ -0,0 +1,10 @@
;; moved to the separate file to keep hex of the previous codes unchanged
const op::provide_wallet_address = 0x2c76b973;
const op::take_wallet_address = 0xd1735400;
int is_resolvable?(slice addr) inline {
(int wc, _) = parse_std_addr(addr);
return wc == workchain();
}

23
contracts/imports/forward-fee-calc.fc

@ -0,0 +1,23 @@
{-
Forward fee calculation supporting different workchains
-}
;; See crypto/block/transaction.cpp:L1499
int msg_fwd_fee(slice destination, cell message_body, cell init_state, int max_viewed_cells) inline {
(int wc, _) = parse_std_addr(destination);
throw_unless(107, (workchain == -1) | (workchain == 0) );
int config_index = 25 + workchain;
slice cfg = config_param(config_index).begin_parse().skip_bits(8);
int lump_price = cfg~load_uint(64);
int bit_price = cfg~load_uint(64);
int cell_price = cfg~load_uint(64);
(int cells, int bits, _) = compute_data_size(message_body, max_viewed_cells);
cells -= 1;
bits -= message_body.slice_bits();
(int is_cells, int is_bits, _) = compute_data_size(init_state, max_viewed_cells);
is_cells -= 1;
is_bits -= init_state.slice_bits();
return lump_price + (((bits + is_bits) * bit_price + (cells + is_cells) * cell_price + 65535) >> 16 );
}

16
contracts/imports/op-codes.fc

@ -0,0 +1,16 @@
;; operations (constant values taken from crc32 on op message in the companion .tlb files and appear during build)
;; Wton
const op::deposit = 0x77a33521;
const op::withdraw = 0x47d1895f;
const op::change_next_admin = 0x62dd86f1;
const op::change_admin = 0x66447dad;
const op::change_content = 0x743f8e58;
;; Wallet
const op::transfer = 0xf8a7ea5;
const op::transfer_notification = 0x7362d09c;
const op::excesses = 0xd53276db;
const op::burn = 0x595f07bc;
const op::internal_transfer = 0x178d4519;
const op::burn_notification = 0x7bdd97de;

42
contracts/imports/utils.fc

@ -1,3 +1,7 @@
#pragma version >=0.2.0;
#include "stdlib.fc";
() send_grams(slice address, int amount) impure { () send_grams(slice address, int amount) impure {
cell msg = begin_cell() cell msg = begin_cell()
.store_uint (0x18, 6) ;; bounce .store_uint (0x18, 6) ;; bounce
@ -7,3 +11,41 @@
.end_cell(); .end_cell();
send_raw_message(msg, 3); ;; mode, 2 for ignoring errors, 1 for sender pays fees, 64 for returning inbound message value send_raw_message(msg, 3); ;; mode, 2 for ignoring errors, 1 for sender pays fees, 64 for returning inbound message value
} }
int workchain() asm "0 PUSHINT";
() force_chain(slice addr) impure {
(int wc, _) = parse_std_addr(addr);
throw_unless(333, wc == workchain());
}
cell pack_jetton_wallet_data(int balance, slice owner_address, slice jetton_master_address, cell jetton_wallet_code) inline {
return begin_cell()
.store_coins(balance)
.store_slice(owner_address)
.store_slice(jetton_master_address)
.store_ref(jetton_wallet_code)
.end_cell();
}
cell calculate_jetton_wallet_state_init(slice owner_address, slice jetton_master_address, cell jetton_wallet_code) inline {
return begin_cell()
.store_uint(0, 2)
.store_dict(jetton_wallet_code)
.store_dict(pack_jetton_wallet_data(0, owner_address, jetton_master_address, jetton_wallet_code))
.store_uint(0, 1)
.end_cell();
}
slice calculate_jetton_wallet_address(cell state_init) inline {
return begin_cell()
.store_uint(4, 3)
.store_int(workchain(), 8)
.store_uint(cell_hash(state_init), 256)
.end_cell()
.begin_parse();
}
slice calculate_user_jetton_wallet_address(slice owner_address, slice jetton_master_address, cell jetton_wallet_code) inline {
return calculate_jetton_wallet_address(calculate_jetton_wallet_state_init(owner_address, jetton_master_address, jetton_wallet_code));
}

243
contracts/jetton-wallet.fc

@ -0,0 +1,243 @@
;; Jetton Wallet Smart Contract
{-
NOTE that this tokens can be transferred within the same workchain.
This is suitable for most tokens, if you need tokens transferable between workchains there are two solutions:
1) use more expensive but universal function to calculate message forward fee for arbitrary destination (see `misc/forward-fee-calc.cs`)
2) use token holder proxies in target workchain (that way even 'non-universal' token can be used from any workchain)
-}
#pragma version >=0.2.0;
#include "imports/stdlib.fc";
#include "imports/utils.fc";
#include "imports/op-codes.fc";
int min_tons_for_storage() asm "10000000 PUSHINT"; ;; 0.01 TON
int gas_consumption() asm "10000000 PUSHINT"; ;; 0.01 TON
{-
Storage
storage#_ balance:(VarUInteger 16) owner_address:MsgAddressInt jetton_master_address:MsgAddressInt jetton_wallet_code:^Cell = Storage;
-}
(int, slice, slice, cell) load_data() inline {
slice ds = get_data().begin_parse();
return (ds~load_coins(), ds~load_msg_addr(), ds~load_msg_addr(), ds~load_ref());
}
() save_data (int balance, slice owner_address, slice jetton_master_address, cell jetton_wallet_code) impure inline {
set_data(pack_jetton_wallet_data(balance, owner_address, jetton_master_address, jetton_wallet_code));
}
{-
transfer query_id:uint64 amount:(VarUInteger 16) destination:MsgAddress
response_destination:MsgAddress custom_payload:(Maybe ^Cell)
forward_ton_amount:(VarUInteger 16) forward_payload:(Either Cell ^Cell)
= InternalMsgBody;
-}
() send_tokens (slice in_msg_body, slice sender_address, int msg_value, int fwd_fee) impure {
int query_id = in_msg_body~load_uint(64);
int jetton_amount = in_msg_body~load_coins();
slice to_owner_address = in_msg_body~load_msg_addr();
force_chain(to_owner_address);
(int balance, slice owner_address, slice jetton_master_address, cell jetton_wallet_code) = load_data();
balance -= jetton_amount;
throw_unless(705, equal_slices(owner_address, sender_address));
throw_unless(706, balance >= 0);
cell state_init = calculate_jetton_wallet_state_init(to_owner_address, jetton_master_address, jetton_wallet_code);
slice to_wallet_address = calculate_jetton_wallet_address(state_init);
slice response_address = in_msg_body~load_msg_addr();
cell custom_payload = in_msg_body~load_dict();
int forward_ton_amount = in_msg_body~load_coins();
throw_unless(708, slice_bits(in_msg_body) >= 1);
slice either_forward_payload = in_msg_body;
var msg = begin_cell()
.store_uint(0x18, 6)
.store_slice(to_wallet_address)
.store_coins(0)
.store_uint(4 + 2 + 1, 1 + 4 + 4 + 64 + 32 + 1 + 1 + 1)
.store_ref(state_init);
var msg_body = begin_cell()
.store_uint(op::internal_transfer, 32)
.store_uint(query_id, 64)
.store_coins(jetton_amount)
.store_slice(owner_address)
.store_slice(response_address)
.store_coins(forward_ton_amount)
.store_slice(either_forward_payload)
.end_cell();
msg = msg.store_ref(msg_body);
int fwd_count = forward_ton_amount ? 2 : 1;
throw_unless(709, msg_value >
forward_ton_amount +
;; 3 messages: wal1->wal2, wal2->owner, wal2->response
;; but last one is optional (it is ok if it fails)
fwd_count * fwd_fee +
(2 * gas_consumption() + min_tons_for_storage()));
;; universal message send fee calculation may be activated here
;; by using this instead of fwd_fee
;; msg_fwd_fee(to_wallet, msg_body, state_init, 15)
send_raw_message(msg.end_cell(), 64); ;; revert on errors
save_data(balance, owner_address, jetton_master_address, jetton_wallet_code);
}
{-
internal_transfer query_id:uint64 amount:(VarUInteger 16) from:MsgAddress
response_address:MsgAddress
forward_ton_amount:(VarUInteger 16)
forward_payload:(Either Cell ^Cell)
= InternalMsgBody;
-}
() receive_tokens (slice in_msg_body, slice sender_address, int my_ton_balance, int fwd_fee, int msg_value) impure {
;; NOTE we can not allow fails in action phase since in that case there will be
;; no bounce. Thus check and throw in computation phase.
(int balance, slice owner_address, slice jetton_master_address, cell jetton_wallet_code) = load_data();
int query_id = in_msg_body~load_uint(64);
int jetton_amount = in_msg_body~load_coins();
balance += jetton_amount;
slice from_address = in_msg_body~load_msg_addr();
slice response_address = in_msg_body~load_msg_addr();
throw_unless(707,
equal_slices(jetton_master_address, sender_address)
|
equal_slices(calculate_user_jetton_wallet_address(from_address, jetton_master_address, jetton_wallet_code), sender_address)
);
int forward_ton_amount = in_msg_body~load_coins();
int ton_balance_before_msg = my_ton_balance - msg_value;
int storage_fee = min_tons_for_storage() - min(ton_balance_before_msg, min_tons_for_storage());
msg_value -= (storage_fee + gas_consumption());
if(forward_ton_amount) {
msg_value -= (forward_ton_amount + fwd_fee);
slice either_forward_payload = in_msg_body;
var msg_body = begin_cell()
.store_uint(op::transfer_notification, 32)
.store_uint(query_id, 64)
.store_coins(jetton_amount)
.store_slice(from_address)
.store_slice(either_forward_payload)
.end_cell();
var msg = begin_cell()
.store_uint(0x10, 6) ;; we should not bounce here cause receiver can have uninitialized contract
.store_slice(owner_address)
.store_coins(forward_ton_amount)
.store_uint(1, 1 + 4 + 4 + 64 + 32 + 1 + 1)
.store_ref(msg_body);
send_raw_message(msg.end_cell(), 1);
}
if ((response_address.preload_uint(2) != 0) & (msg_value > 0)) {
var msg = begin_cell()
.store_uint(0x10, 6) ;; nobounce - int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool src:MsgAddress -> 010000
.store_slice(response_address)
.store_coins(msg_value)
.store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1)
.store_uint(op::excesses, 32)
.store_uint(query_id, 64);
send_raw_message(msg.end_cell(), 2);
}
save_data(balance, owner_address, jetton_master_address, jetton_wallet_code);
}
() burn_tokens (slice in_msg_body, slice sender_address, int msg_value, int fwd_fee) impure {
;; NOTE we can not allow fails in action phase since in that case there will be
;; no bounce. Thus check and throw in computation phase.
(int balance, slice owner_address, slice jetton_master_address, cell jetton_wallet_code) = load_data();
int query_id = in_msg_body~load_uint(64);
int jetton_amount = in_msg_body~load_coins();
slice response_address = in_msg_body~load_msg_addr();
cell custom_payload = in_msg_body~load_dict();
balance -= jetton_amount;
throw_unless(705, equal_slices(jetton_master_address, sender_address));
throw_unless(706, balance >= 0);
throw_unless(707, msg_value > fwd_fee + 2 * gas_consumption());
var msg_body = begin_cell()
.store_uint(op::burn_notification, 32)
.store_uint(query_id, 64)
.store_coins(jetton_amount)
.store_slice(owner_address)
.store_slice(response_address)
.store_dict(custom_payload)
.end_cell();
var msg = begin_cell()
.store_uint(0x18, 6)
.store_slice(jetton_master_address)
.store_coins(0)
.store_uint(1, 1 + 4 + 4 + 64 + 32 + 1 + 1)
.store_ref(msg_body);
send_raw_message(msg.end_cell(), 64);
save_data(balance, owner_address, jetton_master_address, jetton_wallet_code);
}
() on_bounce (slice in_msg_body) impure {
in_msg_body~skip_bits(32); ;; 0xFFFFFFFF
(int balance, slice owner_address, slice jetton_master_address, cell jetton_wallet_code) = load_data();
int op = in_msg_body~load_uint(32);
throw_unless(709, (op == op::internal_transfer) | (op == op::burn_notification));
int query_id = in_msg_body~load_uint(64);
int jetton_amount = in_msg_body~load_coins();
balance += jetton_amount;
save_data(balance, owner_address, jetton_master_address, jetton_wallet_code);
}
() recv_internal(int my_balance, int msg_value, cell in_msg_full, slice in_msg_body) impure {
if (in_msg_body.slice_empty?()) { ;; ignore empty messages
return ();
}
slice cs = in_msg_full.begin_parse();
int flags = cs~load_uint(4);
if (flags & 1) {
on_bounce(in_msg_body);
return ();
}
slice sender_address = cs~load_msg_addr();
cs~load_msg_addr(); ;; skip dst
cs~load_coins(); ;; skip value
cs~skip_bits(1); ;; skip extracurrency collection
cs~load_coins(); ;; skip ihr_fee
int fwd_fee = cs~load_coins(); ;; we use message fwd_fee for estimation of forward_payload costs
int op = in_msg_body~load_uint(32);
if (op == op::transfer) { ;; outgoing transfer
send_tokens(in_msg_body, sender_address, msg_value, fwd_fee);
return ();
}
if (op == op::internal_transfer) { ;; incoming transfer
receive_tokens(in_msg_body, sender_address, my_balance, fwd_fee, msg_value);
return ();
}
if (op == op::burn) { ;; burn
burn_tokens(in_msg_body, sender_address, msg_value, fwd_fee);
return ();
}
throw(0xffff);
}
(int, slice, slice, cell) get_wallet_data() method_id {
return load_data();
}

19
contracts/jetton-wallet.tlb

@ -0,0 +1,19 @@
// base types defined in https://github.com/newton-blockchain/ton/blob/master/crypto/block/block.tlb
// storage (according to save_data() contract method)
storage#_ balance:(VarUInteger 16) owner_address:MsgAddress jetton_master_address:MsgAddress jetton_wallet_code:^Cell = Storage
// ops
transfer query_id:uint64 amount:VarUInteger 16 destination:MsgAddress response_destination:MsgAddress custom_payload:Maybe ^Cell forward_ton_amount:VarUInteger 16 forward_payload:Either Cell ^Cell = InternalMsgBody
transfer_notification query_id:uint64 amount:VarUInteger 16 sender:MsgAddress forward_payload:Either Cell ^Cell = InternalMsgBody
excesses query_id:uint64 = InternalMsgBody
burn query_id:uint64 amount:VarUInteger 16 response_destination:MsgAddress custom_payload:Maybe ^Cell = InternalMsgBody
internal_transfer query_id:uint64 amount:VarUInteger 16 from:MsgAddress response_address:MsgAddress forward_ton_amount:VarUInteger 16 forward_payload:Either Cell ^Cell = InternalMsgBody
burn_notification#0x7bdd97de query_id:uint64 amount:VarUInteger 16 sender:MsgAddress response_destination:MsgAddress custom_payload:Maybe ^Cell = InternalMsgBody

239
contracts/minter.fc

@ -0,0 +1,239 @@
;; Wrapped TON minter smart contract
;; storage scheme
;; storage#_ total_supply:Coins admin_address:MsgAddress next_admin_address:MsgAddress content:^Cell jetton_wallet_code:^Cell = Storage;
#pragma version >=0.2.0;
#include "imports/stdlib.fc";
#include "imports/op-codes.fc";
#include "imports/utils.fc";
#include "imports/discovery-params.fc";
int gas_consumption() asm "10000000 PUSHINT"; ;; 0.01 TON
int withdraw_gas_consumption() asm "10000000 PUSHINT"; ;; 0.01 TON
int deposit_gas_consumption() asm "35000000 PUSHINT"; ;; 0.035 TON
(int, slice, slice, cell, cell) load_data() inline {
slice ds = get_data().begin_parse();
return (
ds~load_coins(), ;; total_supply
ds~load_msg_addr(), ;; admin_address
ds~load_msg_addr(), ;; next_admin_address
ds~load_ref(), ;; content
ds~load_ref() ;; jetton_wallet_code
);
}
() save_data(int total_supply, slice admin_address, slice next_admin_address, cell content, cell jetton_wallet_code) impure inline {
set_data(begin_cell()
.store_coins(total_supply)
.store_slice(admin_address)
.store_slice(next_admin_address)
.store_ref(content)
.store_ref(jetton_wallet_code)
.end_cell()
);
}
() mint_tokens(slice to_address, cell jetton_wallet_code, int amount) impure {
cell state_init = calculate_jetton_wallet_state_init(to_address, my_address(), jetton_wallet_code);
slice to_wallet_address = calculate_jetton_wallet_address(state_init);
var master_msg = begin_cell()
.store_uint(op::internal_transfer, 32)
;; query_id
.store_uint(0, 64)
;; jetton_amount
.store_coins(amount)
;; from_address == to_address
.store_slice(to_address)
;; response_address
.store_slice(my_address())
;; forward ton amount
.store_coins(0)
.end_cell();
var msg = begin_cell()
.store_uint(0x18, 6)
.store_slice(to_wallet_address)
.store_coins(gas_consumption())
.store_uint(4 + 2 + 1, 1 + 4 + 4 + 64 + 32 + 1 + 1 + 1)
.store_ref(state_init)
.store_ref(master_msg);
send_raw_message(msg.end_cell(), 1); ;; pay transfer fees separately, revert on errors
}
() burn_tokens(slice to_address, cell jetton_wallet_code, int amount) impure {
cell state_init = calculate_jetton_wallet_state_init(to_address, my_address(), jetton_wallet_code);
slice to_wallet_address = calculate_jetton_wallet_address(state_init);
var master_msg = begin_cell()
.store_uint(op::burn, 32)
;; query_id
.store_uint(0, 64)
;; jetton_amount
.store_coins(amount)
;; response_address
.store_slice(my_address())
;; custom_payload (currently not used)
.store_dict(new_dict())
.end_cell();
var msg = begin_cell()
.store_uint(0x18, 6)
.store_slice(to_wallet_address)
.store_coins(gas_consumption() * 3)
.store_uint(4 + 2 + 1, 1 + 4 + 4 + 64 + 32 + 1 + 1 + 1)
.store_ref(state_init)
.store_ref(master_msg);
send_raw_message(msg.end_cell(), 1); ;; pay transfer fees separately, revert on errors
}
() recv_internal(int my_balance, int msg_value, cell in_msg_full, slice in_msg_body) impure {
if (in_msg_body.slice_empty?()) { ;; ignore empty messages
return ();
}
slice cs = in_msg_full.begin_parse();
int flags = cs~load_uint(4);
if (flags & 1) { ;; ignore all bounced messages
return ();
}
slice sender_address = cs~load_msg_addr();
cs~load_msg_addr(); ;; skip dst
cs~load_coins(); ;; skip value
cs~skip_bits(1); ;; skip extracurrency collection
cs~load_coins(); ;; skip ihr_fee
int fwd_fee = cs~load_coins(); ;; we use message fwd_fee for estimation of provide_wallet_address cost
int op = in_msg_body~load_uint(32);
int query_id = in_msg_body~load_uint(64);
(int total_supply, slice admin_address, slice next_admin_address, cell content, cell jetton_wallet_code) = load_data();
if (op == op::deposit) {
msg_value -= deposit_gas_consumption();
throw_if(74, msg_value < 0);
int ton_amount = msg_value;
int jetton_amount = in_msg_body~load_coins();
throw_if(75, ton_amount < jetton_amount);
mint_tokens(sender_address, jetton_wallet_code, jetton_amount);
save_data(total_supply + jetton_amount, admin_address, next_admin_address, content, jetton_wallet_code);
msg_value -= jetton_amount + gas_consumption();
if (msg_value > 0) {
var msg = begin_cell()
.store_uint(0x10, 6) ;; nobounce - int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool src:MsgAddress -> 010000
.store_slice(sender_address)
.store_coins(msg_value)
.store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1)
.store_uint(op::excesses, 32)
.store_uint(query_id, 64);
send_raw_message(msg.end_cell(), 2); ;; pay transfer fees together, ignore errors
}
return ();
}
if (op == op::withdraw) {
msg_value -= withdraw_gas_consumption();
throw_if(74, msg_value < 0);
int jetton_amount = in_msg_body~load_coins();
throw_if(75, total_supply < jetton_amount);
burn_tokens(sender_address, jetton_wallet_code, jetton_amount);
save_data(total_supply, admin_address, next_admin_address, content, jetton_wallet_code);
return ();
}
if (op == op::burn_notification) {
int jetton_amount = in_msg_body~load_coins();
slice from_address = in_msg_body~load_msg_addr();
throw_unless(74,
equal_slices(calculate_user_jetton_wallet_address(from_address, my_address(), jetton_wallet_code), sender_address)
);
if (jetton_amount > 0) {
var msg = begin_cell()
.store_uint(0x10, 6) ;; nobounce - int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool src:MsgAddress -> 010000
.store_slice(from_address)
.store_coins(jetton_amount)
.store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1)
;; op code = 0
.store_uint(0, 32)
.store_uint(query_id, 64);
send_raw_message(msg.end_cell(), 1); ;; pay transfer fees seperatly, revert on errors
}
save_data(total_supply - jetton_amount, admin_address, next_admin_address, content, jetton_wallet_code);
return ();
}
if (op == op::provide_wallet_address) {
throw_unless(75, msg_value > fwd_fee + const::provide_address_gas_consumption);
slice owner_address = in_msg_body~load_msg_addr();
int include_address? = in_msg_body~load_uint(1);
cell included_address = include_address?
? begin_cell().store_slice(owner_address).end_cell()
: null();
var msg = begin_cell()
.store_uint(0x18, 6)
.store_slice(sender_address)
.store_coins(0)
.store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1)
.store_uint(op::take_wallet_address, 32)
.store_uint(query_id, 64);
if (is_resolvable?(owner_address)) {
msg = msg.store_slice(calculate_user_jetton_wallet_address(owner_address, my_address(), jetton_wallet_code));
} else {
msg = msg.store_uint(0, 2); ;; addr_none
}
send_raw_message(msg.store_maybe_ref(included_address).end_cell(), 64);
return ();
}
if (op == op::change_next_admin) { ;; change next admin
throw_unless(73, equal_slices(sender_address, admin_address));
slice new_next_admin_address = in_msg_body~load_msg_addr();
save_data(total_supply, admin_address, new_next_admin_address, content, jetton_wallet_code);
return ();
}
if (op == op::change_admin) { ;; change admin (only next admin can get an admin permission)
throw_unless(73, equal_slices(sender_address, next_admin_address));
slice addr_none = begin_cell().store_uint(0, 2).end_cell().begin_parse();
save_data(total_supply, next_admin_address, addr_none, content, jetton_wallet_code);
return ();
}
if (op == op::change_content) { ;; change content, delete this for immutable tokens
throw_unless(73, equal_slices(sender_address, admin_address));
save_data(total_supply, admin_address, next_admin_address, in_msg_body~load_ref(), jetton_wallet_code);
return ();
}
if (op == op::excesses) {
return ();
}
throw(0xffff);
}
(int, int, slice, cell, cell) get_jetton_data() method_id {
(int total_supply, slice admin_address, _, cell content, cell jetton_wallet_code) = load_data();
return (total_supply, -1, admin_address, content, jetton_wallet_code);
}
(slice) get_jetton_extra_data() method_id {
(_, _, slice next_admin_address, _, _) = load_data();
return (next_admin_address);
}
slice get_wallet_address(slice owner_address) method_id {
(_, _, _, _, cell jetton_wallet_code) = load_data();
return calculate_user_jetton_wallet_address(owner_address, my_address(), jetton_wallet_code);
}

21
contracts/minter.tlb

@ -0,0 +1,21 @@
// base types defined in https://github.com/newton-blockchain/ton/blob/master/crypto/block/block.tlb
// storage (according to save_data() contract method)
storage#_ total_supply:Coins admin_address:MsgAddress next_admin_address:MsgAddress content:^Cell jetton_wallet_code:^Cell = Storage
// ops
deposit query_id:uint64 amount:VarUInteger 16 = InternalMsgBody
withdraw query_id:uint64 amount:VarUInteger 16 = InternalMsgBody
change_next_admin query_id:uint64 new_next_admin_address:MsgAddress = InternalMsgBody
change_admin query_id:uint64 = InternalMsgBody
change_content query_id:uint64 new_content:^Cell = InternalMsgBody
provide_wallet_address query_id:uint64 owner_address:MsgAddress include_owner_address:Bool = InternalMsgBody
excesses query_id:uint64 = InternalMsgBody

2
package.json

@ -1,5 +1,5 @@
{ {
"name": "tonstarter-contracts", "name": "tonb",
"description": "", "description": "",
"version": "0.0.0", "version": "0.0.0",
"license": "MIT", "license": "MIT",

Loading…
Cancel
Save