Skip to content

Commit 2942c8a

Browse files
committed
Initial commit
0 parents  commit 2942c8a

16 files changed

+502
-0
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
func/auto/*-code.fif
2+
python/__pycache__/
3+
data/

fift/create-contract.fif

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<b b{0011} s, code ref, storage ref, null dict, b> constant StateInit
2+
3+
StateInit hashu wc swap 2dup 2constant contract_addr
4+
2dup file-base +".addr" save-address-verbose
5+
2dup ."Raw address: " .addr cr
6+
2dup ."Bounceable address: " 6 .Addr cr
7+
."Non-bounceable address: " 7 .Addr cr
8+
9+
{ b{0} s, def? body { @' body s, } if } : body,
10+
11+
<b b{1000100} s, contract_addr addr, b{000011} s, StateInit ref, body, b>
12+
2 boc+>B
13+
file-base +"-create.boc" tuck B>file
14+
."(Saved contract creating query to file " type .")" cr

fift/new-game.fif

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
"TonUtil.fif" include
2+
"Asm.fif" include
3+
4+
{ parse-smc-addr drop
5+
<b -rot Addr, b> <s constant } : set-owner
6+
"setup.fif" include
7+
8+
."Creating distributor" cr
9+
"../data/distributor" =: file-base
10+
0 =: wc
11+
<{ SETCP0 ACCEPT
12+
"../func/auto/distributor-code.fif" include PUSHREF SETCODE
13+
}>c =: code
14+
<b b> =: storage
15+
"create-contract.fif" include
16+
<b contract_addr Addr, b> <s constant owner cr
17+
18+
."Creating game" cr
19+
"../data/game" =: file-base
20+
0 =: wc
21+
<{ SETCP0 ACCEPT
22+
"../func/auto/game-code.fif" include PUSHREF SETCODE
23+
}>c =: code
24+
<b 0xffffffff 32 u,
25+
jackpot Gram,
26+
owner s,
27+
0 40 u,
28+
b> =: storage
29+
"create-contract.fif" include

fift/new-test.fif

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
"TonUtil.fif" include
2+
"Asm.fif" include
3+
4+
<b "kQCx7imOA8QyndoDZcuGgmyEgPunWdO8WJ3kGziSgZ3Q3nht"
5+
parse-smc-addr drop Addr, b> <s constant game
6+
7+
."Creating test" cr
8+
"../data/test" =: file-base
9+
0 =: wc
10+
<{ SETCP0 ACCEPT
11+
"../func/auto/test-code.fif" include PUSHREF SETCODE
12+
}>c =: code
13+
<b b> =: storage
14+
"create-contract.fif" include

fift/setup.fif

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
"EQD_yI2IfYrb4OSGn67v_ZwPRxyw0BOZHr7GuhG2lUdgjjEF" set-owner owner1
2+
"EQDQzWHUBQJn4SWQiUQA-B5plpphzBJMiIcH0DMxfaCfjaGV" set-owner owner2
3+
10 Gram* constant jackpot

func/build.sh

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/bin/bash
2+
func -SP stdlib+.fc text.fc config.fc settings.fc storage.fc msgs.fc main.fc get-methods.fc -o auto/game-code.fif
3+
func -SP stdlib+.fc msgs.fc distributor.fc -o auto/distributor-code.fif

func/config.fc

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
;; utime_since, utime_until
2+
(int, int) current_round() inline_ref {
3+
var cs = config_param(34).begin_parse();
4+
int tag = cs~load_uint(8);
5+
if (tag != 0x11) & (tag != 0x12) {
6+
return (0, (1 << 32) - 1);
7+
}
8+
return (cs~load_uint(32), cs~load_uint(32));
9+
}

func/distributor.fc

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
slice owner1() asm "owner1 PUSHSLICE";
2+
slice owner2() asm "owner2 PUSHSLICE";
3+
4+
() recv_internal(int my_balance, int msg_value, cell, slice in_msg) impure {
5+
if (my_balance - msg_value < (1 << 30)) {
6+
msg_value -= (1 << 30);
7+
}
8+
msg_value /= 2;
9+
10+
var msg = begin_message(0x10, owner1(), msg_value);
11+
send_raw_message(msg.end_cell(), 3);
12+
var msg = begin_message(0x10, owner2(), msg_value);
13+
send_raw_message(msg.end_cell(), 3);
14+
}
15+
16+
((int, int), (int, int)) get_owners() method_id {
17+
return (parse_std_addr(owner1()), parse_std_addr(owner2()));
18+
}

func/get-methods.fc

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
int get_jackpot() method_id {
2+
var (_, jackpot, _, _) = load_data();
3+
return jackpot;
4+
}
5+
6+
int get_game_end() method_id {
7+
var (ends_at, _, _, _) = load_data();
8+
return ends_at;
9+
}
10+
11+
int get_seqno() method_id {
12+
var (_, _, _, seqno) = load_data();
13+
return seqno;
14+
}
15+
16+
(int, int) get_last_player() method_id {
17+
var (_, _, last_player, _) = load_data();
18+
return parse_std_addr(last_player);
19+
}
20+
21+
(int, int) get_owner() method_id {
22+
return parse_std_addr(settings::owner());
23+
}

func/main.fc

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
() recv_internal(int my_balance, int msg_value, cell in_msg_cell, slice in_msg) impure {
2+
var cs = in_msg_cell.begin_parse();
3+
var flags = cs~load_uint(4);
4+
5+
if (flags & 1) {
6+
;; ignore bounced messages
7+
return ();
8+
}
9+
10+
var sender = cs~load_msg_addr();
11+
(int wc, _) = parse_std_addr(sender);
12+
throw_if(31, wc); ;; we don't want waste too much on fwd_fee, ensure wc = 0
13+
14+
var (ends_at, jackpot, last_player, seqno) = load_data();
15+
if (ends_at < now()) {
16+
;; we have a WINNER
17+
var msg = begin_message(0x10, last_player, jackpot).store_comment(text::winner());
18+
send_raw_message(msg.end_cell(), 0);
19+
20+
var log = begin_log_msg()
21+
.store_uint(2, 8) ;; tag
22+
.store_uint(jackpot, 64);
23+
send_raw_message(log.end_cell(), 0);
24+
25+
;; return msg_value
26+
var msg = begin_message(0x10, sender, 0);
27+
send_raw_message(msg.end_cell(), 64 + 2);
28+
29+
;; withdraw the rest
30+
var msg = begin_message(0x10, settings::owner(), 0);
31+
send_raw_message(msg.end_cell(), 128 + 2);
32+
33+
;; restart the game
34+
return save_data(0xffffffff, 0, sender, 0);
35+
}
36+
37+
int bet = msg_value;
38+
throw_if(30, bet < settings::min_bet());
39+
40+
int fee = muldiv(bet, settings::owner_fee(), 100);
41+
int rest = bet - fee;
42+
jackpot += rest;
43+
last_player = sender;
44+
seqno += 1;
45+
46+
(int utime_since, int utime_until) = current_round();
47+
int time = now();
48+
int delay = settings::delay();
49+
if (time > utime_until - delay * 2) | (time < utime_since + settings::big_delay()) {
50+
delay = settings::big_delay();
51+
}
52+
ends_at = time + delay;
53+
54+
;; testnet only (delete me)
55+
;; throw_if(1000, utime_until - utime_since > 10000);
56+
57+
int reward = 0;
58+
ifnot (seqno % 10) {
59+
reward = settings::start_reward();
60+
;; unroll loop (lower gas fees)
61+
ifnot (seqno % 100) { reward *= 10;
62+
ifnot (seqno % 1000) { reward *= 10;
63+
ifnot (seqno % 10000) { reward *= 10;
64+
ifnot (seqno % 100000) { reward *= 10;
65+
ifnot (seqno % 1000000) { reward *= 10;
66+
ifnot (seqno % 10000000) { reward *= 10;
67+
} } } } } }
68+
}
69+
70+
if (reward > 0) {
71+
jackpot -= reward;
72+
73+
;; send reward
74+
slice txt = (reward > msg_value ? text::reward() : text::payback());
75+
ifnot (seqno % 1000000) {
76+
txt = text::big_reward();
77+
}
78+
var msg = begin_message(0x10, sender, reward).store_comment(txt);
79+
send_raw_message(msg.end_cell(), 1);
80+
}
81+
82+
var log = begin_log_msg()
83+
.store_uint(1, 8) ;; tag
84+
.store_uint(jackpot, 64)
85+
.store_uint(seqno, 40)
86+
.store_uint(reward, 64)
87+
.store_uint(ends_at, 32);
88+
send_raw_message(log.end_cell(), 0);
89+
90+
if (my_balance - reward - jackpot > settings::withdraw_at()) {
91+
;; auto-withdraw owner balance
92+
;; reserve some grams for gas fees
93+
raw_reserve(jackpot + (1 << 30), 0);
94+
var msg = begin_message(0x10, settings::owner(), 0).store_comment(text::withdrawal());
95+
send_raw_message(msg.end_cell(), 128);
96+
}
97+
98+
save_data(ends_at, jackpot, last_player, seqno);
99+
100+
;; we suppose that fee (0.2 ton) is always enough for paying blockchain fees
101+
;; we could check the config, but it seems to be overcomplication
102+
;; we ensure that sender wc is 0 to limit fwd_fee
103+
;; the max amount of gas used is a constant
104+
}

func/msgs.fc

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
builder begin_message(flags, addr, grams) inline_ref {
2+
var msg = begin_cell()
3+
.store_uint(flags, 6)
4+
.store_slice(addr)
5+
.store_grams(grams)
6+
.store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1);
7+
return msg;
8+
}
9+
10+
builder begin_log_msg() inline {
11+
var msg = begin_cell()
12+
.store_uint(0x30, 6) ;; ext_out_msg_info$11 addr_none$00 addr_none$00
13+
.store_uint(0, 32 + 64 + 2);
14+
return msg;
15+
}
16+
17+
builder store_comment(builder b, slice text) inline {
18+
return b.store_uint(0, 32).store_slice(text);
19+
}

func/settings.fc

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
int settings::owner_fee() asm "20 PUSHINT"; ;; 20%
2+
int settings::delay() asm "60 PUSHINT"; ;; 1 minute
3+
int settings::big_delay() asm "60 60 * PUSHINT"; ;; 60 minutes
4+
int settings::min_bet() asm "1.0 Gram*/ PUSHINT";
5+
int settings::withdraw_at() asm "100 Gram* PUSHINT";
6+
int settings::start_reward() asm "1.0 Gram*/ PUSHINT";
7+
slice settings::owner() asm "owner PUSHSLICE";

0 commit comments

Comments
 (0)