├── 1.fc ├── 2.fc ├── 3.fc ├── 4.fc ├── 5.fc ├── README.MD ├── participant.json └── stdlib.fc /1.fc: -------------------------------------------------------------------------------- 1 | {- 2 | 3 | TASK 1 - COUNTER. 4 | 5 | Let's start. 6 | 7 | This simple counter smart contract stores a `total` - 64-bit unsigned integer in its data (it is guaranteed that storage data contains `total`). 8 | 9 | When receiving an internal incoming message, contract takes a 32-bit unsigned integer from message body, adds it to the `total` and saves the result in contract data. 10 | 11 | Get-method `get_total` should returns actual `total` value stored in contract data. 12 | 13 | If the body of the incoming message is less than 32 bits then it should throw ANY error. 14 | 15 | -} 16 | 17 | ;; testable 18 | () recv_internal(slice in_msg_body) impure { 19 | throw_if(in_msg.slice_bits() < 32); 20 | int n = in_msg~load_uint(32); 21 | 22 | cell ds = get_data().begin_parse(); 23 | int total = ds~load_uint(64); 24 | 25 | total += n; 26 | 27 | set_data(begin_cell().store_uint(total + n, 32).end_cell()); 28 | } 29 | 30 | ;; testable 31 | int get_total() method_id { 32 | slice ds = get_data().begin_parse(); 33 | int total = ds~load_uint(64); 34 | return total; 35 | } 36 | -------------------------------------------------------------------------------- /2.fc: -------------------------------------------------------------------------------- 1 | {- 2 | 3 | TASK 2 - PROXY. 4 | 5 | The aim of proxy contract is to forward all messages to it's owner. 6 | 7 | In particular for each message A (except messages from owner itself) such contract 8 | should send the message B to owner with body which contains address of A's sender followed by A's message body in reference (child cell). 9 | 10 | The Toncoin value attached to the message should be equal A's value minus fees related to processing (computational and message forwarding fees). 11 | The owner address is stored in contract storage (it is guaranteed that storage contains owner address only). 12 | 13 | You may find useful https://ton.org/docs/#/smart-contracts/messages 14 | 15 | For messages from owner tests will check absence of outgoing messages. 16 | 17 | -} 18 | 19 | int equal_slices (slice a, slice b) asm "SDEQ"; 20 | 21 | slice load_data () { 22 | var ds = get_data().begin_parse(); 23 | return ds~load_msg_addr(); 24 | } 25 | 26 | () save_data (slice owner_address) impure { 27 | set_data(begin_cell().store_slice(owner_address).end_cell()); 28 | } 29 | 30 | ;; Parse sender address from incoming message 31 | (slice, int) parse_sender_address (cell in_msg_full) { 32 | var cs = in_msg_full.begin_parse(); 33 | var flags = cs~load_uint(4); 34 | slice sender_address = cs~load_msg_addr(); 35 | return (sender_address, flags); 36 | } 37 | 38 | ;; testable 39 | () recv_internal (int balance, int msg_value, cell in_msg_full, slice in_msg_body) { 40 | slice sender_address = parse_sender_address(); 41 | slice owner_address = load_data(); 42 | var msg = begin_cell() 43 | .store_uint(0x10, 6) 44 | .store_slice(sender_address) 45 | .store_grams(0) 46 | .store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1) 47 | .store_slice(owner_address) 48 | .store_ref(in_msg_full) 49 | .end_cell(); 50 | send_raw_message(msg, 0x64); 51 | save_data(owner_address); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /3.fc: -------------------------------------------------------------------------------- 1 | {- 2 | 3 | TASK 3 - ADDRESS MEMORIZER. 4 | 5 | The aim of address memorizer contract is to remember the address set by Manager and report it to anyone who request this information. 6 | 7 | In particular: 8 | 9 | * when contract get internal message from Manager which contains the following three fields: 10 | * 32-bit unsigned `op` equal to 1 [more on op's here](https://ton.org/docs/#/howto/smart-contract-guidelines?id=internal-messages) 11 | * immediately followed by some 64-bit unsigned `query_id`, 12 | * immediately followed by valid MsgAddress, 13 | it should store obtained address in the storage. Note, tests will not cover cases when messages contain valid `op`, `query_id`, `address` and then something else (that means that participants may handle such messages at their discretion). 14 | 15 | * when contract get internal message from any address which contains the following two fields: 16 | 32-bit unsigned `op` equal to `2` immediately followed by some 64-bit unsigned `query_id`, it should response to sender with message with body containing: 17 | 1) 32-bit ungisned `op` equal to 3 18 | 2) the same 64-bit unsigned `query_id` 19 | 3) Manager's address 20 | 4) Address which was memorized since last Manager request (empty address `addr_none` if there were no Manager request yet) 21 | 5) TON value attached to message should be incoming value minus processing fees 22 | 23 | Note, tests will not cover cases when messages contain valid `op=2`, `query_id` and then something else (that means that participants may handle such messages at their discretion). 24 | 25 | * when address memorizer get any internal message which is not covered by description above it should throw with any exit code > 1. 26 | 27 | The initial address memorizer storage contains Manager address immediately followed by empty address (`addr_none` constructor for MsgAddress). 28 | 29 | -} 30 | 31 | int equal_slices (slice a, slice b) asm "SDEQ"; 32 | 33 | (slice, slice) load_data () { 34 | var ds = get_data().begin_parse(); 35 | return (ds~load_msg_addr(), ds~load_msg_addr()); 36 | } 37 | 38 | () save_data (slice manager_address, slice memorized_address) { 39 | set_data(begin_cell().store_slice(owner_address).store_slice(memorized_address).end_cell()); 40 | } 41 | 42 | ;; Parse sender address from incoming message 43 | (slice, int) parse_sender_address (cell in_msg_full) { 44 | var cs = in_msg_full.begin_parse(); 45 | var flags = cs~load_uint(4); 46 | slice sender_address = cs~load_msg_addr(); 47 | return (sender_address, flags); 48 | } 49 | 50 | ;; testable 51 | () recv_internal (int balance, int msg_value, cell in_msg_full, slice in_msg_body) { 52 | (slice manager_address, slice memorized_address) = load_data(); 53 | int op = in_msg_body~load_int(32); 54 | int query_id = in_msg_body~load_uint(64); 55 | if (op == 1) { 56 | save_data(manager, in_msg_body); 57 | } 58 | if (op == 2) { 59 | var (sender_address, _) = parse_sender_address(in_msg_full); 60 | var msg = begin_cell() 61 | .store_uint(0x10, 6) 62 | .store_slice(sender) 63 | .store_grams(0) 64 | .store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1) 65 | .store_uint(3, 32) 66 | .store_uint(query_id, 64) 67 | .store_slice(manager_address) 68 | .store_slice(memorized_address) 69 | .end_cell(); 70 | send_raw_message(msg, 0x64); 71 | save_data(manager_address, memorized_address); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /4.fc: -------------------------------------------------------------------------------- 1 | {- 2 | 3 | TASK 4 - HASHMAP STORAGE. 4 | 5 | * Add-new-entry message has the following structure: 6 | * 32-bit unsigned `op` equal to 1 7 | * 64-bit unsigned `query_id` 8 | * 256-bit unsgined key 9 | * 64-bit `valid_until` unixtime 10 | * the rest slice is the value 11 | 12 | Upon receipt of such a message, the contract must add a new key/value entry to its data. 13 | Clarification: if the key already exists then the entry must be replaced. 14 | Contract storage format is arbitrary, you are free to change it. 15 | 16 | * Remove-outdated message has the following stucture: 17 | * 32-bit unsigned `op` equal to 2 18 | * 64-bit unsigned `query_id` 19 | 20 | Upon receipt of such a message, the contract must delete all otudated entries from its data (those with `valid_until` < now()). Note, tests will not cover cases when messages contain valid `op=2`, `query_id` and then something else (that means that participants may handle such messages at their discretion). 21 | 22 | * For all other internal messages an error (exit_code > 1) should be thrown 23 | 24 | * Get-method `get_key` accepts 256-bit unsigned key and should return `valid_until` integer and value data slice for this key. Note: unixtime of running `get_key` method should not affect result. 25 | 26 | If there is no entry for this key then an error (exit_code > 1) should be thrown. 27 | 28 | * Tests will initially run with empty storage 29 | 30 | -} 31 | 32 | (cell, cell) load_data() { 33 | slice ds = get_data().begin_parse(); 34 | if (ds.slice_bits() == 0) { 35 | return (null(), null()); 36 | } else { 37 | return (ds~load_dict(), ds~load_dict()); 38 | } 39 | } 40 | 41 | () save_data(cell data_dict, cell valid_until_dict) impure { 42 | set_data(begin_cell().store_dict(data_dict).store_dict(valid_until_dict).end_cell()); 43 | } 44 | 45 | ;; testable 46 | () recv_internal(int balance, int msg_value, cell in_msg_full, slice in_msg_body) { 47 | int op = in_msg_body~load_uint(32); 48 | int query_id = in_msg_body~load_uint(64); 49 | 50 | (cell data_dict, cell valid_until_dict) = load_data(); 51 | 52 | if (op == 1) { ;; add new entry 53 | 54 | int key = in_msg_body~load_uint(256); 55 | int valid_until = in_msg_body~load_uint(64); 56 | slice value = in_msg_body; 57 | 58 | data_dict~udict_set(256, key, value); 59 | valid_until_dict~udict_set_ref(256, key, begin_cell().store_uint(valid_until, 64).end_cell()); 60 | } 61 | 62 | if (op == 2) { ;; remove outdated 63 | 64 | int key = -1; 65 | do { 66 | (key, slice cs, int f) = valid_until.udict_get_next?(256, key); 67 | if (f) { 68 | int valid_until = cs~load_uint(64); 69 | if (valid_until < now()) { 70 | valid_until~udict_delete(256, key); 71 | data_dict~udict_delete(256, key); 72 | } 73 | } 74 | } until (~ f); 75 | 76 | } 77 | 78 | save_data(data_dict, valid_until_dict); 79 | } 80 | 81 | ;; testable (but not gas-measured) 82 | (int, slice) get_key(int key) method_id { 83 | (cell data_dict, cell valid_until_dict) = load_data(); 84 | 85 | int valid_until = valid_until_dict~udict_get(key, 256)~load_uint(64); 86 | slice value = data_dict~udict_get(key, 256).begin_parse(); 87 | 88 | return (valid_until, value); 89 | } 90 | -------------------------------------------------------------------------------- /5.fc: -------------------------------------------------------------------------------- 1 | {- 2 | 3 | TASK 5 - SHARED WALLET. 4 | 5 | The aim of two owner wallet is to create smart-contract which send messages then and only then both owners (represented by public keys) authorized it. 6 | 7 | TL-B schema of external message body accepted by wallet is as follows: 8 | ``` 9 | request#_ valid_until:uint32 mode:uint8 msg_to_send:^Cell = Request; 10 | msg_body#_ public_key:uint256 signature:(512 * Bit) request:^Request = MsgBody; 11 | ``` 12 | 13 | Where `signature` signs `Request` cell with some private key and `public_key` is corresponding public key. 14 | 15 | `msg_to_send` is fully formed message which is ready to be accepted by `send_raw_message()`. 16 | 17 | Any errors related to the incorrect `msg_to_send` may be ignored (in other words if something goes wrong due to owner's malformed message, it is owner's problem). 18 | 19 | When wallet receive request signed by one owner it should store it in storage. 20 | 21 | When wallet receives the same request signed by another owner it should process request, that means send `msg_to_send` with `mode` in the same transaction it got second signature. 22 | 23 | If message body does not corresponds to `MsgBody` type described above, request is signed not by owner, contains incorrect signature or current time is higher than `valid_until`, request should be ignored (message should not be accepted). Note: absence of `accept_message` and throwing (with exit_code > 1) before `accept_message` are the same for external messages (since will result in ignoring that external message by any validator). 24 | 25 | If the same request (regardless approved by one or both owners) is sent the second time it should be ignored. 26 | 27 | It is acceptable to ignore requests which are valid for more than 1 minute as well as not accept more than 10 requests per minute. 28 | 29 | Before running tests, storage for contract will be generated by `pack_data` with providing two public keys. Thus participants may intoduce their own storage layout. 30 | 31 | -} 32 | 33 | ;; testable 34 | cell pack_data(int public_key1, int public_key2) method_id { 35 | ;; Fill in 36 | } 37 | 38 | ;; testable 39 | () recv_external (slice in_msg_body) { 40 | ;; Fill in 41 | accept_message(); 42 | } 43 | -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | # Welcome to first FunC contest by TON Foundation 2 | 3 | There are five `.fc` files in the folder: 4 | 1. [1.fc](1.fc) - First problem "Counter" 5 | 2. [2.fc](2.fc) - Second problem "Proxy" 6 | 3. [3.fc](3.fc) - Third problem "Address Memorizer" 7 | 4. [4.fc](4.fc) - Fourth problem "Hashmaps" 8 | 5. [5.fc](5.fc) - Fifth problem "Two-owner wallet" 9 | 10 | Each file has two parts: 11 | 12 | * Comment with description of what the smart-contract should do. 13 | 14 | * Code of smart-contract with one or more functions marked as `testable`. 15 | 16 | The purpose of the contestants is to match code and description, fix bugs if provided code does not satisfy description and optimize the code. 17 | 18 | We ask participants to not change the signature (number, order and types of arguments and result) of `testable` functions for us to be able to evaluate their submission. 19 | 20 | ## How to submit 21 | 22 | Solutions should be submitted as tar archive which contain up to 5 files labeled `1.fc`, `2.fc`, `3.fc`, `4.fc`, `5.fc` (each file represents a corresponding task). 23 | 24 | Each file will be compiled with func from [main repository](https://github.com/newton-blockchain/ton/tree/master/crypto/func). During compilation each file will be supplemented with a [stdlib - FunC standard library](https://github.com/newton-blockchain/ton/blob/master/crypto/smartcont/stdlib.fc). 25 | 26 | Each submission tarball should also contain `participant.json` with the following structure: 27 | ``` 28 | { 29 | "address" : "your-TON-wallet-address", 30 | "username": "desired-username-in-public-list", 31 | "codeforces": "(optional)codeforces-username" 32 | } 33 | ``` 34 | 35 | Bot for receiving submissions will be announced later on https://t.me/toncontests. 36 | 37 | This challenge aims to attract new developers to TON ecosystem. To reduce the chances of newcomers discouraging we kindly ask skilled developers of already established TON teams to participate with "out of competition" mark. 38 | You can set "out of competition" mark by adding to the tarball file with name `OUT`. 39 | 40 | ## How will it be checked 41 | 42 | For each problem we have a set of test vectors which satisfy the description. 43 | 44 | We will automatically run those tests against the `testable` functions. 45 | 46 | If functions of one task pass all the tests, this task is considered "solved". 47 | 48 | For "solved" tasks gas-usage of each test is recorded, sum of gas used by all tests is the second-order metric which will allow us to determine the winner amongst people with equal number of solved tasks. 49 | 50 | Winners are determined as follows: 51 | 52 | * Person who solved more tasks will be ranked higher then person who will solve less (regardless of optimization). 53 | 54 | * For evaluation of gas-usage each problem has a weight which in general inversely correlated with average gas-usage, thus 10 gas units optimization of the function which consume 100 gas units will be scored higher than 10 gas units optimization of the function which consume 10000 gas units. 55 | 56 | * Get methods will not be measured for gas usage: since such methods are executed locally, in contrast to on-chain execution, they are much less sensitive to gas consumption. 57 | Thus efficiency or inefficiency of get-methods will not affect the ranking (ofc if those getmethods are not called from testable functions) 58 | 59 | ## Docs 60 | 61 | We recommend participant to check out https://ton.org/docs in particular "Basic concepts" and "Smart Contracts" sections. 62 | 63 | Additional and detailed information is available in [whitepapers](https://ton.org/docs/#/docs). 64 | 65 | Examples of standard smart contracts can be found [here](https://github.com/newton-blockchain/ton/tree/master/crypto/smartcont). 66 | 67 | Developer Chats - https://t.me/tondev_eng, https://t.me/tondev. 68 | 69 | Introduction - https://telegra.ph/Its-time-to-try-something-new-Asynchronous-smart-contracts-03-25. 70 | 71 | ## How to compile and test 72 | 73 | We recommend using the [toncli](https://github.com/disintar/toncli) - open source tool written by community developers. 74 | 75 | This tool allows you to work with FunC smart contracts on Ubuntu, MacOS or Windows - compile them and run local tests. Also many other things, but in this contest you don't need to deploy contracts to the network. 76 | 77 | Playground toncli + 1st contest task you can find [here](https://github.com/disintar/task-1-playground). 78 | 79 | If for some reason you don't want to use the tool you can use the FunC compiler and Fift scripts [directly](https://ton.org/docs/#/smart-contracts/?id=func). 80 | 81 | For syntax highlighting you can use [TON IDEA Plugin](https://plugins.jetbrains.com/plugin/18541-ton-development) or [Sublime Text Plugin](https://github.com/savva425/func_plugin_sublimetext3). 82 | -------------------------------------------------------------------------------- /participant.json: -------------------------------------------------------------------------------- 1 | { 2 | "address" : "your-TON-wallet-address", 3 | "username": "desired-username-in-public-list", 4 | "codeforces": "(optional)codeforces-username" 5 | } -------------------------------------------------------------------------------- /stdlib.fc: -------------------------------------------------------------------------------- 1 | ;; Standard library for funC 2 | ;; 3 | 4 | forall X -> tuple cons(X head, tuple tail) asm "CONS"; 5 | forall X -> (X, tuple) uncons(tuple list) asm "UNCONS"; 6 | forall X -> (tuple, X) list_next(tuple list) asm( -> 1 0) "UNCONS"; 7 | forall X -> X car(tuple list) asm "CAR"; 8 | tuple cdr(tuple list) asm "CDR"; 9 | tuple empty_tuple() asm "NIL"; 10 | forall X -> tuple tpush(tuple t, X value) asm "TPUSH"; 11 | forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH"; 12 | forall X -> [X] single(X x) asm "SINGLE"; 13 | forall X -> X unsingle([X] t) asm "UNSINGLE"; 14 | forall X, Y -> [X, Y] pair(X x, Y y) asm "PAIR"; 15 | forall X, Y -> (X, Y) unpair([X, Y] t) asm "UNPAIR"; 16 | forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) asm "TRIPLE"; 17 | forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) asm "UNTRIPLE"; 18 | forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) asm "4 TUPLE"; 19 | forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) asm "4 UNTUPLE"; 20 | forall X -> X first(tuple t) asm "FIRST"; 21 | forall X -> X second(tuple t) asm "SECOND"; 22 | forall X -> X third(tuple t) asm "THIRD"; 23 | forall X -> X fourth(tuple t) asm "3 INDEX"; 24 | forall X, Y -> X pair_first([X, Y] p) asm "FIRST"; 25 | forall X, Y -> Y pair_second([X, Y] p) asm "SECOND"; 26 | forall X, Y, Z -> X triple_first([X, Y, Z] p) asm "FIRST"; 27 | forall X, Y, Z -> Y triple_second([X, Y, Z] p) asm "SECOND"; 28 | forall X, Y, Z -> Z triple_third([X, Y, Z] p) asm "THIRD"; 29 | forall X -> X null() asm "PUSHNULL"; 30 | forall X -> (X, ()) ~impure_touch(X x) impure asm "NOP"; 31 | 32 | int now() asm "NOW"; 33 | slice my_address() asm "MYADDR"; 34 | [int, cell] get_balance() asm "BALANCE"; 35 | int cur_lt() asm "LTIME"; 36 | int block_lt() asm "BLOCKLT"; 37 | 38 | int cell_hash(cell c) asm "HASHCU"; 39 | int slice_hash(slice s) asm "HASHSU"; 40 | int string_hash(slice s) asm "SHA256U"; 41 | 42 | int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU"; 43 | int check_data_signature(slice data, slice signature, int public_key) asm "CHKSIGNS"; 44 | 45 | (int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE"; 46 | (int, int, int) slice_compute_data_size(slice s, int max_cells) impure asm "SDATASIZE"; 47 | (int, int, int, int) compute_data_size?(cell c, int max_cells) asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; 48 | (int, int, int, int) slice_compute_data_size?(cell c, int max_cells) asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; 49 | 50 | ;; () throw_if(int excno, int cond) impure asm "THROWARGIF"; 51 | 52 | () dump_stack() impure asm "DUMPSTK"; 53 | 54 | cell get_data() asm "c4 PUSH"; 55 | () set_data(cell c) impure asm "c4 POP"; 56 | cont get_c3() impure asm "c3 PUSH"; 57 | () set_c3(cont c) impure asm "c3 POP"; 58 | cont bless(slice s) impure asm "BLESS"; 59 | 60 | () accept_message() impure asm "ACCEPT"; 61 | () set_gas_limit(int limit) impure asm "SETGASLIMIT"; 62 | () commit() impure asm "COMMIT"; 63 | () buy_gas(int gram) impure asm "BUYGAS"; 64 | 65 | int min(int x, int y) asm "MIN"; 66 | int max(int x, int y) asm "MAX"; 67 | (int, int) minmax(int x, int y) asm "MINMAX"; 68 | int abs(int x) asm "ABS"; 69 | 70 | slice begin_parse(cell c) asm "CTOS"; 71 | () end_parse(slice s) impure asm "ENDS"; 72 | (slice, cell) load_ref(slice s) asm( -> 1 0) "LDREF"; 73 | cell preload_ref(slice s) asm "PLDREF"; 74 | ;; (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX"; 75 | ;; (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) "LDUX"; 76 | ;; int preload_int(slice s, int len) asm "PLDIX"; 77 | ;; int preload_uint(slice s, int len) asm "PLDUX"; 78 | ;; (slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX"; 79 | ;; slice preload_bits(slice s, int len) asm "PLDSLICEX"; 80 | (slice, int) load_grams(slice s) asm( -> 1 0) "LDGRAMS"; 81 | slice skip_bits(slice s, int len) asm "SDSKIPFIRST"; 82 | (slice, ()) ~skip_bits(slice s, int len) asm "SDSKIPFIRST"; 83 | slice first_bits(slice s, int len) asm "SDCUTFIRST"; 84 | slice skip_last_bits(slice s, int len) asm "SDSKIPLAST"; 85 | (slice, ()) ~skip_last_bits(slice s, int len) asm "SDSKIPLAST"; 86 | slice slice_last(slice s, int len) asm "SDCUTLAST"; 87 | (slice, cell) load_dict(slice s) asm( -> 1 0) "LDDICT"; 88 | cell preload_dict(slice s) asm "PLDDICT"; 89 | slice skip_dict(slice s) asm "SKIPDICT"; 90 | 91 | (slice, cell) load_maybe_ref(slice s) asm( -> 1 0) "LDOPTREF"; 92 | cell preload_maybe_ref(slice s) asm "PLDOPTREF"; 93 | builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF"; 94 | 95 | int cell_depth(cell c) asm "CDEPTH"; 96 | 97 | int slice_refs(slice s) asm "SREFS"; 98 | int slice_bits(slice s) asm "SBITS"; 99 | (int, int) slice_bits_refs(slice s) asm "SBITREFS"; 100 | int slice_empty?(slice s) asm "SEMPTY"; 101 | int slice_data_empty?(slice s) asm "SDEMPTY"; 102 | int slice_refs_empty?(slice s) asm "SREMPTY"; 103 | int slice_depth(slice s) asm "SDEPTH"; 104 | 105 | int builder_refs(builder b) asm "BREFS"; 106 | int builder_bits(builder b) asm "BBITS"; 107 | int builder_depth(builder b) asm "BDEPTH"; 108 | 109 | builder begin_cell() asm "NEWC"; 110 | cell end_cell(builder b) asm "ENDC"; 111 | builder store_ref(builder b, cell c) asm(c b) "STREF"; 112 | ;; builder store_uint(builder b, int x, int len) asm(x b len) "STUX"; 113 | ;; builder store_int(builder b, int x, int len) asm(x b len) "STIX"; 114 | builder store_slice(builder b, slice s) asm "STSLICER"; 115 | builder store_grams(builder b, int x) asm "STGRAMS"; 116 | builder store_dict(builder b, cell c) asm(c b) "STDICT"; 117 | 118 | (slice, slice) load_msg_addr(slice s) asm( -> 1 0) "LDMSGADDR"; 119 | tuple parse_addr(slice s) asm "PARSEMSGADDR"; 120 | (int, int) parse_std_addr(slice s) asm "REWRITESTDADDR"; 121 | (int, slice) parse_var_addr(slice s) asm "REWRITEVARADDR"; 122 | 123 | cell idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; 124 | (cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; 125 | cell udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; 126 | (cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; 127 | cell idict_get_ref(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETOPTREF"; 128 | (cell, int) idict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETREF"; 129 | (cell, int) udict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGETREF"; 130 | (cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETGETOPTREF"; 131 | (cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETGETOPTREF"; 132 | (cell, int) idict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDEL"; 133 | (cell, int) udict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDEL"; 134 | (slice, int) idict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; 135 | (slice, int) udict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; 136 | (cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; 137 | (cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; 138 | (cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; 139 | (cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; 140 | cell udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; 141 | (cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; 142 | cell idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; 143 | (cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; 144 | cell dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; 145 | (cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; 146 | (cell, int) udict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUADD"; 147 | (cell, int) udict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUREPLACE"; 148 | (cell, int) idict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIADD"; 149 | (cell, int) idict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIREPLACE"; 150 | cell udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; 151 | (cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; 152 | cell idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; 153 | (cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; 154 | cell dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; 155 | (cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; 156 | (cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUADDB"; 157 | (cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUREPLACEB"; 158 | (cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIADDB"; 159 | (cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIREPLACEB"; 160 | (cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; 161 | (cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; 162 | (cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; 163 | (cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; 164 | (cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; 165 | (cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; 166 | (cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; 167 | (cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; 168 | (cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; 169 | (cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; 170 | (cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; 171 | (cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; 172 | (int, slice, int) udict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; 173 | (int, slice, int) udict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; 174 | (int, cell, int) udict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; 175 | (int, cell, int) udict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; 176 | (int, slice, int) idict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; 177 | (int, slice, int) idict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; 178 | (int, cell, int) idict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; 179 | (int, cell, int) idict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; 180 | (int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; 181 | (int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; 182 | (int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; 183 | (int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; 184 | (int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; 185 | (int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; 186 | (int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; 187 | (int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; 188 | cell new_dict() asm "NEWDICT"; 189 | int dict_empty?(cell c) asm "DICTEMPTY"; 190 | 191 | (slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; 192 | (cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) asm(value key dict key_len) "PFXDICTSET"; 193 | (cell, int) pfxdict_delete?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTDEL"; 194 | 195 | cell config_param(int x) asm "CONFIGOPTPARAM"; 196 | int cell_null?(cell c) asm "ISNULL"; 197 | 198 | () raw_reserve(int amount, int mode) impure asm "RAWRESERVE"; 199 | () raw_reserve_extra(int amount, cell extra_amount, int mode) impure asm "RAWRESERVEX"; 200 | () send_raw_message(cell msg, int mode) impure asm "SENDRAWMSG"; 201 | () set_code(cell new_code) impure asm "SETCODE"; 202 | 203 | int random() impure asm "RANDU256"; 204 | int rand(int range) impure asm "RAND"; 205 | int get_seed() impure asm "RANDSEED"; 206 | int set_seed() impure asm "SETRAND"; 207 | () randomize(int x) impure asm "ADDRAND"; 208 | () randomize_lt() impure asm "LTIME" "ADDRAND"; --------------------------------------------------------------------------------