Skip to content

Instantly share code, notes, and snippets.

@tvorogme
Last active September 9, 2022 13:23
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save tvorogme/fdb174ac0740b6a52d1dbdf85f4ddc63 to your computer and use it in GitHub Desktop.
Save tvorogme/fdb174ac0740b6a52d1dbdf85f4ddc63 to your computer and use it in GitHub Desktop.
TON deploy smart contract
#!/usr/bin/fift -s
"TonUtil.fif" include
"Asm.fif" include
// If you dont know about stack-base languages
// Please read something before read comments and trying to understand what is going on here :)
5 :$1..n // parse arguments
$1 parse-workchain-id =: wc // set workchain id from command line argument
$2 parse-int =: subwallet-id // set subwallet id
$3 =: file-base // set file path, we will save public key, boc, addr with this base
$4 =: fif-code // set fif code path
// Include fif-code compiled from func
// It will create cell for our code
// We will save it to stack
fif-code include
// Create data cell builder for wallet
// Data will be loaded on line 13 in func file of our smart contract
<b // Builder will now in top of stack
// https://newton-blockchain.github.io/docs/fiftbase.pdf - 5.2 Builder primitives, page 44
// seqno, https://newton-blockchain.github.io/docs/tblkch.pdf - 1.3. Consistency conditions, page 12
0 32 u,
// subwallet-id
subwallet-id 32 u,
// generate public / private key, save private key to file (in stack private and pub)
file-base +".pk" load-generate-keypair
constant wallet_pk // save wallet private key to constant
B, // add bin public key to cell
b> // Transform cell builder to cell
null // lib cell
// in stack now: (code, data, lib) cells
// Generate initialize message (StateInit), it's very hard to understand, but:
// https://newton-blockchain.github.io/docs/tblkch.pdf
// 1.7.3. Initializing smart contracts by constructor messages, page 27
// 3.1.7. Message layout, page 56
// TL-B schema of init message - https://github.com/ton-blockchain/ton/blob/24dc184a2ea67f9c47042b4104bbb4d82289fac1/crypto/block/block.tlb#L141
// To understand TL-B - 3.3.4. Brief explanation of TL-B schemes., page 38
<b
// _ split_depth:(Maybe (## 5)) special:(Maybe TickTock)
// code:(Maybe ^Cell) data:(Maybe ^Cell)
// library:(HashmapE 256 SimpleLib) = StateInit;
// split_depth - because of Maybe - 0 (more info about split_depth in 4.1. Accounts and their states, page 72: https://newton-blockchain.github.io/docs/tblkch.pdf
// special - because of Maybe - 0 (more info about 4.2. Transactions, page 77)
// code cell ref - 1
// data cell ref - 1
// library has HashmapE type it will defined after data in the end of builder
b{0011} s,
// code cell reference
3 roll ref,
// data cell reference
rot ref,
// library - by default its null dict (HashmapE type) examples of lib usage can be founded in:
// https://github.com/akifoq/ton-samples/blob/742dcaf3167a15b2f8c57c1699fbee28640523da/libs/new-lib.fif#L15
swap dict,
b>
// The hash of the code and of the data
// contained in the constructor message must coincide with the address η of the
// smart contract; otherwise, it is rejected.
dup hashu // get sha256 hash of init message cell
wc // get workchain id (parsed in top of file)
swap // swap, because valid address scheme workchain id : sha256
2dup 2constant wallet_addr // save address to wallet_addr and duplicate to stack
."new wallet address = " // print message to console
2dup // duplicate wallet address
.addr // print wallet address <workchain>:<account> (TonUtil.fif:40)
cr // endline print
2dup // duplicate wallet address again
file-base +".addr" // generate path for saving file
save-address-verbose // save address to file
// print addreses to console
."Non-bounceable address (for init): " 2dup 7 .Addr cr
."Bounceable address (for later access): " 6 .Addr cr
// Now in stack we have StateInit message
// Generate fist init message
<b // Will be loaded on line 10 in func file of our smart contract
subwallet-id 32 u, // subwallet id
-1 32 i, // valid_until
0 32 u, // msg_seqno
b>
// Console.log external message
dup ."signing message: " <s csr. cr
// In stack: StateInit, external message
// We need sign first message:
// https://newton-blockchain.github.io/docs/tblkch.pdf 1.2. Principal components of a block and the blockchain state, page 7
dup hashu // get sha256 hash of external message
wallet_pk ed25519_sign_uint // sign sha256 with our private key
rot // get StateInit message back to top
// now in stack: "first external message, signed message, StateInit"
// Generate final external message
// External message scheme can be found:
// https://github.com/newton-blockchain/ton/blob/master/crypto/block/block.tlb#L147
// message$_ {X:Type} info:CommonMsgInfo
// init:(Maybe (Either StateInit ^StateInit))
// body:(Either X ^X) = Message X;
//
<b
// First we need to define info which is CommonMsgInfo
// You can Cntrl+F `CommonMsgInfo` in block.tlb, but:
// it can be: (int_msg_info$0 / ext_in_msg_info$10 / ext_out_msg_info$11)
// We need to take ext_in_msg_info$10 so our first bits will be => `10`
// You can find more information about it in 3.1.7. Message layout, page 56
// When we chose CommonMsgInfo as ext_in_msg_info$10
//
// https://github.com/newton-blockchain/ton/blob/master/crypto/block/block.tlb#L127
// ext_in_msg_info$10 src:MsgAddressExt dest:MsgAddressInt
// import_fee:Grams = CommonMsgInfo;
//
// We need to define: src address, dest address, import fee
// So you can find in block.tlb MsgAddressExt:
// addr_none$00 = MsgAddressExt;
// addr_extern$01 len:(## 9) external_address:(bits len)
// = MsgAddressExt;
// https://newton-blockchain.github.io/docs/tblkch.pdf, 3.1.3. External addresses., page 54
// We need to take none - so => `00`
//
// Next - dest address now it will be MsgAddressInt, we need addr_std$10 so - `10`
// Finally import_fee - set it to nothing => `0`
// Concat all bits - 1000100
b{1000100} s, // write constructor
wallet_addr addr, // Define external address as wallet (contract) address (it is addr_std$10)
b{000010} s, // ???
swap <s s, // StateInit
b{0} s, // ???
swap B, // Append signed sha256 of our init message
swap <s s, // Append our init message
b>
// Generate boc
// 2 - it's a mode, checkout explanation:
// https://newton-blockchain.github.io/docs/fiftbase.pdf 5.6. Binary file I/O and Bytes manipulation, page 50
2 boc+>B
// Console.log boc
."BOC: " dup Bx. cr
// Save boc to file!
file-base +".boc" tuck B>file
."(Saved wallet creating query to file " type .")" cr
;; Simple wallet smart contract
() recv_internal(slice in_msg) impure {
;; do nothing for internal messages
}
() recv_external(slice in_msg) impure {
var signature = in_msg~load_bits(512);
var cs = in_msg;
var (subwallet_id, valid_until, msg_seqno) = (cs~load_uint(32), cs~load_uint(32), cs~load_uint(32));
throw_if(35, valid_until <= now());
var ds = get_data().begin_parse();
var (stored_seqno, stored_subwallet, public_key) = (ds~load_uint(32), ds~load_uint(32), ds~load_uint(256));
ds.end_parse();
throw_unless(33, msg_seqno == stored_seqno);
throw_unless(34, subwallet_id == stored_subwallet);
throw_unless(35, check_signature(slice_hash(in_msg), signature, public_key));
accept_message();
cs~touch();
while (cs.slice_refs()) {
var mode = cs~load_uint(8);
send_raw_message(cs~load_ref(), mode);
}
set_data(begin_cell()
.store_uint(stored_seqno + 1, 32)
.store_uint(stored_subwallet, 32)
.store_uint(public_key, 256)
.end_cell());
}
;; Get methods
int seqno() method_id {
return get_data().begin_parse().preload_uint(32);
}
int get_public_key() method_id {
var cs = get_data().begin_parse();
cs~load_uint(64);
return cs.preload_uint(256);
}
int hello_world() method_id {
return 1234567890;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment