@layerzerolabs/layerzero-v2-ton 3.0.12-ton.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +67 -0
- package/README.md +15 -0
- package/build/AllStorages.boc +0 -0
- package/build/AllStorages.compiled.json +1 -0
- package/build/AllStorages.fif +4164 -0
- package/build/AllStorages.test.boc +0 -0
- package/build/AllStorages.test.compiled.json +1 -0
- package/build/AllStorages.test.fif +1831 -0
- package/build/BaseContract.test.boc +0 -0
- package/build/BaseContract.test.compiled.json +1 -0
- package/build/BaseContract.test.fif +3553 -0
- package/build/Channel.boc +0 -0
- package/build/Channel.compiled.json +1 -0
- package/build/Channel.fif +5001 -0
- package/build/Channel.permissions.test.boc +0 -0
- package/build/Channel.permissions.test.compiled.json +1 -0
- package/build/Channel.permissions.test.fif +7569 -0
- package/build/ChannelBurn.test.boc +0 -0
- package/build/ChannelBurn.test.compiled.json +1 -0
- package/build/ChannelBurn.test.fif +7454 -0
- package/build/ChannelCommitPacket.test.boc +0 -0
- package/build/ChannelCommitPacket.test.compiled.json +1 -0
- package/build/ChannelCommitPacket.test.fif +7981 -0
- package/build/ChannelConfig.test.boc +0 -0
- package/build/ChannelConfig.test.compiled.json +1 -0
- package/build/ChannelConfig.test.fif +7442 -0
- package/build/ChannelInitialize.test.boc +0 -0
- package/build/ChannelInitialize.test.compiled.json +1 -0
- package/build/ChannelInitialize.test.fif +7289 -0
- package/build/ChannelMsglibIntegration.test.boc +0 -0
- package/build/ChannelMsglibIntegration.test.compiled.json +1 -0
- package/build/ChannelMsglibIntegration.test.fif +7404 -0
- package/build/ChannelMsglibSendCallback.test.boc +0 -0
- package/build/ChannelMsglibSendCallback.test.compiled.json +1 -0
- package/build/ChannelMsglibSendCallback.test.fif +7711 -0
- package/build/ChannelNilify.test.boc +0 -0
- package/build/ChannelNilify.test.compiled.json +1 -0
- package/build/ChannelNilify.test.fif +7672 -0
- package/build/ChannelReceive.test.boc +0 -0
- package/build/ChannelReceive.test.compiled.json +1 -0
- package/build/ChannelReceive.test.fif +7702 -0
- package/build/ChannelReceiveCallback.test.boc +0 -0
- package/build/ChannelReceiveCallback.test.compiled.json +1 -0
- package/build/ChannelReceiveCallback.test.fif +7549 -0
- package/build/ChannelReceiveView.test.boc +0 -0
- package/build/ChannelReceiveView.test.compiled.json +1 -0
- package/build/ChannelReceiveView.test.fif +7352 -0
- package/build/ChannelSend.test.boc +0 -0
- package/build/ChannelSend.test.compiled.json +1 -0
- package/build/ChannelSend.test.fif +7658 -0
- package/build/Classlib.test.boc +0 -0
- package/build/Classlib.test.compiled.json +1 -0
- package/build/Classlib.test.fif +4728 -0
- package/build/Connection.boc +0 -0
- package/build/Connection.compiled.json +1 -0
- package/build/Connection.fif +3503 -0
- package/build/Connection.test.boc +0 -0
- package/build/Connection.test.compiled.json +1 -0
- package/build/Connection.test.fif +6575 -0
- package/build/Controller.assertions.test.boc +0 -0
- package/build/Controller.assertions.test.compiled.json +1 -0
- package/build/Controller.assertions.test.fif +6130 -0
- package/build/Controller.boc +0 -0
- package/build/Controller.compiled.json +1 -0
- package/build/Controller.fif +3195 -0
- package/build/Controller.permissions.test.boc +0 -0
- package/build/Controller.permissions.test.compiled.json +1 -0
- package/build/Controller.permissions.test.fif +6237 -0
- package/build/Controller.test.boc +0 -0
- package/build/Controller.test.compiled.json +1 -0
- package/build/Controller.test.fif +6400 -0
- package/build/Counter.boc +0 -0
- package/build/Counter.compiled.json +1 -0
- package/build/Counter.fif +4809 -0
- package/build/Counter.permissions.test.boc +0 -0
- package/build/Counter.permissions.test.compiled.json +1 -0
- package/build/Counter.permissions.test.fif +7106 -0
- package/build/Counter.setters.test.boc +0 -0
- package/build/Counter.setters.test.compiled.json +1 -0
- package/build/Counter.setters.test.fif +7083 -0
- package/build/Counter.test.boc +0 -0
- package/build/Counter.test.compiled.json +1 -0
- package/build/Counter.test.fif +7540 -0
- package/build/Dvn.boc +0 -0
- package/build/Dvn.compiled.json +1 -0
- package/build/Dvn.fif +2923 -0
- package/build/Dvn.test.boc +0 -0
- package/build/Dvn.test.compiled.json +1 -0
- package/build/Dvn.test.fif +5753 -0
- package/build/Endpoint.boc +0 -0
- package/build/Endpoint.compiled.json +1 -0
- package/build/Endpoint.fif +3694 -0
- package/build/Endpoint.permissions.test.boc +0 -0
- package/build/Endpoint.permissions.test.compiled.json +1 -0
- package/build/Endpoint.permissions.test.fif +6211 -0
- package/build/Endpoint.test.boc +0 -0
- package/build/Endpoint.test.compiled.json +1 -0
- package/build/Endpoint.test.fif +6899 -0
- package/build/EndpointSetEpConfigDefaults.test.boc +0 -0
- package/build/EndpointSetEpConfigDefaults.test.compiled.json +1 -0
- package/build/EndpointSetEpConfigDefaults.test.fif +6529 -0
- package/build/Executor.boc +0 -0
- package/build/Executor.compiled.json +1 -0
- package/build/Executor.fif +2731 -0
- package/build/Executor.test.boc +0 -0
- package/build/Executor.test.compiled.json +1 -0
- package/build/Executor.test.fif +5822 -0
- package/build/LzClasses.test.boc +0 -0
- package/build/LzClasses.test.compiled.json +1 -0
- package/build/LzClasses.test.fif +4457 -0
- package/build/LzUtil.test.boc +0 -0
- package/build/LzUtil.test.compiled.json +1 -0
- package/build/LzUtil.test.fif +1831 -0
- package/build/MsgData.test.boc +0 -0
- package/build/MsgData.test.compiled.json +1 -0
- package/build/MsgData.test.fif +4318 -0
- package/build/MsglibPacketCodec.test.boc +0 -0
- package/build/MsglibPacketCodec.test.compiled.json +1 -0
- package/build/MsglibPacketCodec.test.fif +4851 -0
- package/build/MultiSig.boc +0 -0
- package/build/MultiSig.compiled.json +1 -0
- package/build/MultiSig.fif +727 -0
- package/build/MultiSigOrder.boc +0 -0
- package/build/MultiSigOrder.compiled.json +1 -0
- package/build/MultiSigOrder.fif +650 -0
- package/build/PipelinedOutOfOrder.test.boc +0 -0
- package/build/PipelinedOutOfOrder.test.compiled.json +1 -0
- package/build/PipelinedOutOfOrder.test.fif +2188 -0
- package/build/SmlConnection.boc +0 -0
- package/build/SmlConnection.compiled.json +1 -0
- package/build/SmlConnection.fif +2517 -0
- package/build/SmlConnection.permissions.test.boc +0 -0
- package/build/SmlConnection.permissions.test.compiled.json +1 -0
- package/build/SmlConnection.permissions.test.fif +5497 -0
- package/build/SmlConnection.test.boc +0 -0
- package/build/SmlConnection.test.compiled.json +1 -0
- package/build/SmlConnection.test.fif +5494 -0
- package/build/SmlManager.boc +0 -0
- package/build/SmlManager.compiled.json +1 -0
- package/build/SmlManager.fif +3904 -0
- package/build/SmlManager.permissions.test.boc +0 -0
- package/build/SmlManager.permissions.test.compiled.json +1 -0
- package/build/SmlManager.permissions.test.fif +6018 -0
- package/build/SmlManager.test.boc +0 -0
- package/build/SmlManager.test.compiled.json +1 -0
- package/build/SmlManager.test.fif +6047 -0
- package/build/Uln.boc +0 -0
- package/build/Uln.compiled.json +1 -0
- package/build/Uln.fif +4841 -0
- package/build/Uln.test.boc +0 -0
- package/build/Uln.test.compiled.json +1 -0
- package/build/Uln.test.fif +7077 -0
- package/build/UlnManager.boc +0 -0
- package/build/UlnManager.compiled.json +1 -0
- package/build/UlnManager.fif +3851 -0
- package/build/UlnManager.test.boc +0 -0
- package/build/UlnManager.test.compiled.json +1 -0
- package/build/UlnManager.test.fif +6571 -0
- package/build/UlnReceiveConfig.test.boc +0 -0
- package/build/UlnReceiveConfig.test.compiled.json +1 -0
- package/build/UlnReceiveConfig.test.fif +4413 -0
- package/build/UlnSend.test.boc +0 -0
- package/build/UlnSend.test.compiled.json +1 -0
- package/build/UlnSend.test.fif +6576 -0
- package/build/UlnSendConfig.test.boc +0 -0
- package/build/UlnSendConfig.test.compiled.json +1 -0
- package/build/UlnSendConfig.test.fif +4431 -0
- package/build/UlnSendWorkerFactory.test.boc +0 -0
- package/build/UlnSendWorkerFactory.test.compiled.json +1 -0
- package/build/UlnSendWorkerFactory.test.fif +6683 -0
- package/build/UlnUtil.test.boc +0 -0
- package/build/UlnUtil.test.compiled.json +1 -0
- package/build/UlnUtil.test.fif +5873 -0
- package/build/WorkerCore.test.boc +0 -0
- package/build/WorkerCore.test.compiled.json +1 -0
- package/build/WorkerCore.test.fif +5630 -0
- package/build/ZroMinter.boc +0 -0
- package/build/ZroMinter.compiled.json +1 -0
- package/build/ZroMinter.fif +2300 -0
- package/build/ZroWallet.boc +0 -0
- package/build/ZroWallet.compiled.json +1 -0
- package/build/ZroWallet.fif +2471 -0
- package/package.json +64 -0
- package/src/classes/lz/Attestation.fc +23 -0
- package/src/classes/lz/Config.fc +23 -0
- package/src/classes/lz/EpConfig.fc +91 -0
- package/src/classes/lz/MsglibInfo.fc +31 -0
- package/src/classes/lz/Packet.fc +202 -0
- package/src/classes/lz/Path.fc +56 -0
- package/src/classes/lz/ReceiveEpConfig.fc +24 -0
- package/src/classes/lz/SendEpConfig.fc +18 -0
- package/src/classes/lz/SmlJobAssigned.fc +20 -0
- package/src/classes/lz/Worker.fc +32 -0
- package/src/classes/msgdata/AddMsglib.fc +18 -0
- package/src/classes/msgdata/Amount.fc +16 -0
- package/src/classes/msgdata/Bool.fc +16 -0
- package/src/classes/msgdata/ChannelNonceInfo.fc +18 -0
- package/src/classes/msgdata/ClaimUnaccountedPoolFunds.fc +0 -0
- package/src/classes/msgdata/CoinsAmount.fc +16 -0
- package/src/classes/msgdata/CounterIncrement.fc +24 -0
- package/src/classes/msgdata/Deploy.fc +20 -0
- package/src/classes/msgdata/ExtendedMd.fc +20 -0
- package/src/classes/msgdata/GetMsglibCallback.fc +18 -0
- package/src/classes/msgdata/InitEndpoint.fc +16 -0
- package/src/classes/msgdata/InitSmlConnection.fc +16 -0
- package/src/classes/msgdata/InitUlnConnection.fc +18 -0
- package/src/classes/msgdata/LzReceiveStatus.fc +58 -0
- package/src/classes/msgdata/LzSend.fc +58 -0
- package/src/classes/msgdata/MdAddress.fc +18 -0
- package/src/classes/msgdata/MdEid.fc +18 -0
- package/src/classes/msgdata/MdObj.fc +18 -0
- package/src/classes/msgdata/MessagingReceipt.fc +22 -0
- package/src/classes/msgdata/MsglibSendCallback.fc +113 -0
- package/src/classes/msgdata/Nonce.fc +16 -0
- package/src/classes/msgdata/OptionsExtended.fc +20 -0
- package/src/classes/msgdata/OptionsV1.fc +27 -0
- package/src/classes/msgdata/OptionsV2.fc +34 -0
- package/src/classes/msgdata/PacketId.fc +18 -0
- package/src/classes/msgdata/PacketSent.fc +39 -0
- package/src/classes/msgdata/SetAddress.fc +16 -0
- package/src/classes/msgdata/SetEpConfig.fc +33 -0
- package/src/classes/msgdata/SetPeer.fc +18 -0
- package/src/classes/msgdata/SetSmlManagerConfig.fc +18 -0
- package/src/funC++/abstract/contractMainAbstract.fc +3 -0
- package/src/funC++/abstract/handlerAbstract.fc +12 -0
- package/src/funC++/actions/call.fc +51 -0
- package/src/funC++/actions/deploy.fc +118 -0
- package/src/funC++/actions/destroy.fc +28 -0
- package/src/funC++/actions/dispatch.fc +57 -0
- package/src/funC++/actions/event.fc +69 -0
- package/src/funC++/actions/payment.fc +52 -0
- package/src/funC++/actions/sendJettons.fc +76 -0
- package/src/funC++/actions/utils.fc +49 -0
- package/src/funC++/baseInterface.fc +16 -0
- package/src/funC++/classlib.fc +819 -0
- package/src/funC++/constants.fc +64 -0
- package/src/funC++/contractMain.fc +84 -0
- package/src/funC++/dataStructures/DeterministicInsertionCircularQueue.fc +155 -0
- package/src/funC++/dataStructures/PipelinedOutOfOrder.fc +93 -0
- package/src/funC++/handlerCore.fc +30 -0
- package/src/funC++/stdlib.fc +625 -0
- package/src/funC++/stringlib.fc +75 -0
- package/src/funC++/txnContext.fc +126 -0
- package/src/funC++/utils.fc +119 -0
- package/src/jettons/zro/minter.fc +120 -0
- package/src/jettons/zro/op-codes.fc +10 -0
- package/src/jettons/zro/params.fc +18 -0
- package/src/jettons/zro/utils.fc +33 -0
- package/src/jettons/zro/wallet.fc +261 -0
- package/tests/baseContractTest.fc +192 -0
- package/tests/testMain.fc +135 -0
|
@@ -0,0 +1,819 @@
|
|
|
1
|
+
#include "utils.fc";
|
|
2
|
+
#include "constants.fc";
|
|
3
|
+
#include "stdlib.fc";
|
|
4
|
+
#include "stringlib.fc";
|
|
5
|
+
|
|
6
|
+
;; Types for storage abstraction
|
|
7
|
+
const int cl::t::bool = 0;
|
|
8
|
+
const int cl::t::uint8 = 3;
|
|
9
|
+
const int cl::t::uint16 = 4;
|
|
10
|
+
const int cl::t::uint32 = 5;
|
|
11
|
+
const int cl::t::uint64 = 6;
|
|
12
|
+
const int cl::t::coins = 7; ;; fixed-width uint128, because we are civilized people
|
|
13
|
+
const int cl::t::uint256 = 8;
|
|
14
|
+
const int cl::t::address = cl::t::uint256;
|
|
15
|
+
const int cl::t::cellRef = 9;
|
|
16
|
+
const int cl::t::dict256 = cl::t::cellRef;
|
|
17
|
+
const int cl::t::objRef = cl::t::cellRef;
|
|
18
|
+
const int INVALID_TYPE = 13;
|
|
19
|
+
|
|
20
|
+
const int DICT256_KEYLEN = 256;
|
|
21
|
+
|
|
22
|
+
const int cl::NULL_CLASS_NAME = "NULL"u;
|
|
23
|
+
|
|
24
|
+
const int cl::ERROR::INVALID_CLASS = "cl::ERROR::INVALID_CLASS"c & ERRORCODE_MASK;
|
|
25
|
+
|
|
26
|
+
const int DEBUG = 0;
|
|
27
|
+
|
|
28
|
+
const int MAX_NAME_LEN = 10; ;; each name can be up to 10 characters long
|
|
29
|
+
const int _NAME_WIDTH = 8 * MAX_NAME_LEN; ;; convert to bits
|
|
30
|
+
const int _BASIC_HEADER_WIDTH = _NAME_WIDTH;
|
|
31
|
+
const int MAX_NAME_INTLEN = (1 << (8 * MAX_NAME_LEN)) - 1;
|
|
32
|
+
|
|
33
|
+
const int _FIELD_TYPE_WIDTH+_CELL_ID_WIDTH = 6; ;; support up to 16 types
|
|
34
|
+
|
|
35
|
+
const int _FIELD_TYPE_WIDTH = 4; ;; support up to 16 types
|
|
36
|
+
const int _CELL_ID_WIDTH = 2; ;; the classlib backend supports up to 4 inner cells including root
|
|
37
|
+
const int _DATA_OFFSET_WIDTH = 10; ;; 1023 bits per cell = 2**10 - 1
|
|
38
|
+
const int _REF_OFFSET_WIDTH = 2; ;; each cell can have up to 4 refs
|
|
39
|
+
const int _FIELD_INFO_WIDTH = _FIELD_TYPE_WIDTH + _CELL_ID_WIDTH + _DATA_OFFSET_WIDTH + _REF_OFFSET_WIDTH;
|
|
40
|
+
const int _MAX_CLASS_FIELDS = 15; ;; reserve 0xff for the "invalid" object field name
|
|
41
|
+
const int INVALID_CLASS_MEMBER = 16;
|
|
42
|
+
const int _HEADER_WIDTH = _BASIC_HEADER_WIDTH + _MAX_CLASS_FIELDS * _FIELD_INFO_WIDTH;
|
|
43
|
+
|
|
44
|
+
;; declarations require a tuple of the form [[ name, type, val ], ...]
|
|
45
|
+
const int FIELD_TYPE_IDX = 0;
|
|
46
|
+
const int FIELD_VAL_IDX = 1;
|
|
47
|
+
|
|
48
|
+
;;; ====================== Address functions ======================
|
|
49
|
+
int basechainAddressStdToHashpart(slice full_address) inline {
|
|
50
|
+
(int wc, int hp) = parseStdAddress(full_address);
|
|
51
|
+
if (DEBUG) {
|
|
52
|
+
throw_unless(0, wc == BASECHAIN);
|
|
53
|
+
}
|
|
54
|
+
return hp;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
slice hashpartToBasechainAddressStd(int hashpart) inline {
|
|
58
|
+
return begin_cell()
|
|
59
|
+
.store_uint(4, 3) ;; 0b100
|
|
60
|
+
.store_int(BASECHAIN, 8)
|
|
61
|
+
.store_uint(hashpart, 256)
|
|
62
|
+
.as_slice();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
int getContractAddress() impure inline {
|
|
66
|
+
return my_address().preload_bits_offset(11, 256).preload_uint(256);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
slice cl::objToSlice(cell $obj) inline method_id {
|
|
70
|
+
return $obj.begin_parse();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
;;; ====================== Class functions ======================
|
|
74
|
+
;; returns type width in bits
|
|
75
|
+
int _getTypeWidth(int clType) inline {
|
|
76
|
+
if (clType <= cl::t::uint256) {
|
|
77
|
+
return 1 << clType; ;; type names are set up so this is true
|
|
78
|
+
}
|
|
79
|
+
;; all other types are ref types with 0 data bits
|
|
80
|
+
return 0;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
int cl::hash(cell $obj) impure inline {
|
|
84
|
+
return $obj.cell_hash();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
int cl::isNull(cell $obj) impure inline {
|
|
88
|
+
return $obj.cell_is_empty();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
;; checks if a class lib object is flat, and contains no 'refs'
|
|
92
|
+
;; null is considered 'flat'
|
|
93
|
+
int cl::noRefFields(cell $obj) {
|
|
94
|
+
slice headerSlice = $obj.begin_parse();
|
|
95
|
+
int numRefs = headerSlice.slice_refs();
|
|
96
|
+
|
|
97
|
+
if (numRefs == 0) {
|
|
98
|
+
return true;
|
|
99
|
+
} elseif (numRefs <= 2) {
|
|
100
|
+
;; if there are refs, the struct is not flat
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (numRefs >= 3) {
|
|
105
|
+
if (
|
|
106
|
+
(headerSlice.preload_ref_at(0).cell_is_empty() == false)
|
|
107
|
+
| (headerSlice.preload_ref_at(1).cell_is_empty() == false)
|
|
108
|
+
| (headerSlice.preload_ref_at(2).begin_parse().slice_refs() != 0)
|
|
109
|
+
) {
|
|
110
|
+
;; if there is 1 structural node, that structural node must have 0 refs
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (numRefs >= 4) {
|
|
116
|
+
if (headerSlice.preload_ref_at(3).begin_parse().slice_refs() != 0) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
int cl::equalObjTypeShallow(cell $a, cell $b) {
|
|
125
|
+
slice aSlice = $a.begin_parse();
|
|
126
|
+
slice bSlice = $b.begin_parse();
|
|
127
|
+
int aRefs = aSlice.slice_refs();
|
|
128
|
+
|
|
129
|
+
if (
|
|
130
|
+
(aRefs != bSlice.slice_refs())
|
|
131
|
+
| (aSlice.slice_bits() != bSlice.slice_bits())
|
|
132
|
+
) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
int refIndex = 2;
|
|
137
|
+
while (refIndex < aRefs) {
|
|
138
|
+
if (
|
|
139
|
+
(aSlice.preload_ref_at(refIndex).begin_parse().slice_refs() != bSlice.preload_ref_at(refIndex).begin_parse().slice_refs())
|
|
140
|
+
| (aSlice.preload_ref_at(refIndex).begin_parse().slice_bits() != bSlice.preload_ref_at(refIndex).begin_parse().slice_bits())
|
|
141
|
+
) {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
refIndex += 1;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
() setContractStorage(cell $obj) impure inline {
|
|
151
|
+
set_data($obj);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
cell getContractStorage() impure inline method_id {
|
|
155
|
+
return get_data();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
int computeContractAddress(cell $storage, cell code) impure inline {
|
|
159
|
+
return begin_cell()
|
|
160
|
+
.store_uint(6, 5)
|
|
161
|
+
.store_ref(code)
|
|
162
|
+
.store_ref($storage)
|
|
163
|
+
.end_cell()
|
|
164
|
+
.cell_hash();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
int cl::typeof(cell $obj) inline method_id {
|
|
168
|
+
if (cl::isNull($obj)) {
|
|
169
|
+
return cl::NULL_CLASS_NAME;
|
|
170
|
+
}
|
|
171
|
+
return $obj.begin_parse().preload_uint(_NAME_WIDTH);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
cell cl::declare(int name, tuple fields) inline method_id {
|
|
175
|
+
tuple classBuilder = unsafeTuple([null(), begin_cell()]);
|
|
176
|
+
|
|
177
|
+
if (DEBUG) {
|
|
178
|
+
if (name > MAX_NAME_INTLEN) {
|
|
179
|
+
~strdump("Class name too long! ".str::concat(str::asciiUint256ToStr(name)));
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
int num_fields = fields.tlen();
|
|
184
|
+
builder headerBuilder = begin_cell().store_uint(name, _NAME_WIDTH);
|
|
185
|
+
|
|
186
|
+
;; Loop indices
|
|
187
|
+
int curDataCell = 1;
|
|
188
|
+
int curRefCell = 1;
|
|
189
|
+
;; allow one direct ref in the root cell
|
|
190
|
+
int curCellMaxRefs = 2;
|
|
191
|
+
int curDataOffset = _HEADER_WIDTH;
|
|
192
|
+
int curRefOffset = 0;
|
|
193
|
+
|
|
194
|
+
int curField = 0;
|
|
195
|
+
while (curField < num_fields) {
|
|
196
|
+
;; ======================
|
|
197
|
+
;; loop management
|
|
198
|
+
tuple field = fields.tuple_at(curField);
|
|
199
|
+
int fieldType = field.int_at(FIELD_TYPE_IDX);
|
|
200
|
+
;; ===================================
|
|
201
|
+
int fieldBits = _getTypeWidth(fieldType);
|
|
202
|
+
if ((curDataOffset + fieldBits) > MAX_CELL_BITS) {
|
|
203
|
+
;; move to the next cell
|
|
204
|
+
curDataCell += 1;
|
|
205
|
+
curDataOffset = 0;
|
|
206
|
+
if (curDataCell >= classBuilder.tlen()) {
|
|
207
|
+
classBuilder = classBuilder.tpush(begin_cell());
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
if ((curRefOffset + 1) > curCellMaxRefs) {
|
|
211
|
+
;; move to the next cell
|
|
212
|
+
curRefCell += 1;
|
|
213
|
+
curRefOffset = 0;
|
|
214
|
+
curCellMaxRefs = MAX_CELL_REFS;
|
|
215
|
+
if (curRefCell >= classBuilder.tlen()) {
|
|
216
|
+
classBuilder = classBuilder.tpush(begin_cell());
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (fieldType <= cl::t::address) {
|
|
221
|
+
classBuilder = classBuilder.tset(
|
|
222
|
+
curDataCell,
|
|
223
|
+
cast_to_builder(classBuilder.at(curDataCell))
|
|
224
|
+
.store_uint(abs(field.int_at(FIELD_VAL_IDX)), fieldBits)
|
|
225
|
+
);
|
|
226
|
+
} elseif (fieldType == cl::t::objRef) {
|
|
227
|
+
classBuilder = classBuilder.tset(
|
|
228
|
+
curRefCell,
|
|
229
|
+
cast_to_builder(classBuilder.at(curRefCell))
|
|
230
|
+
.store_ref(field.cell_at(FIELD_VAL_IDX))
|
|
231
|
+
);
|
|
232
|
+
} else {
|
|
233
|
+
cell field_val = field.cell_at(FIELD_VAL_IDX);
|
|
234
|
+
classBuilder = classBuilder.tset(curRefCell,
|
|
235
|
+
cast_to_builder(classBuilder.at(curRefCell))
|
|
236
|
+
.store_ref(field_val)
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
headerBuilder = headerBuilder
|
|
241
|
+
.store_uint(fieldType, _FIELD_TYPE_WIDTH);
|
|
242
|
+
if (fieldBits > 0) {
|
|
243
|
+
headerBuilder = headerBuilder
|
|
244
|
+
.store_uint(curDataCell == 1 ? 0 : curDataCell, _CELL_ID_WIDTH)
|
|
245
|
+
.store_uint(curDataOffset, _DATA_OFFSET_WIDTH)
|
|
246
|
+
.store_uint(3, _REF_OFFSET_WIDTH);
|
|
247
|
+
curDataOffset += fieldBits;
|
|
248
|
+
} else {
|
|
249
|
+
headerBuilder = headerBuilder
|
|
250
|
+
.store_uint(curRefCell == 1 ? 0 : curRefCell, _CELL_ID_WIDTH)
|
|
251
|
+
.store_uint(MAX_CELL_BITS, _DATA_OFFSET_WIDTH)
|
|
252
|
+
.store_uint(curRefOffset, _REF_OFFSET_WIDTH);
|
|
253
|
+
curRefOffset += 1;
|
|
254
|
+
}
|
|
255
|
+
curField += 1;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
builder rootBuilder = classBuilder.at(1);
|
|
260
|
+
int numCells = classBuilder.tlen() - 1;
|
|
261
|
+
if (DEBUG) {
|
|
262
|
+
throw_if(cl::ERROR::INVALID_CLASS, numCells > 3);
|
|
263
|
+
}
|
|
264
|
+
if (numCells > 1) {
|
|
265
|
+
if (rootBuilder.builder_refs() == 0) {
|
|
266
|
+
rootBuilder = rootBuilder
|
|
267
|
+
.store_ref(empty_cell())
|
|
268
|
+
.store_ref(empty_cell());
|
|
269
|
+
} elseif (rootBuilder.builder_refs() == 1) {
|
|
270
|
+
rootBuilder = rootBuilder
|
|
271
|
+
.store_ref(empty_cell());
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
headerBuilder = headerBuilder
|
|
276
|
+
.store_ones(_HEADER_WIDTH - headerBuilder.builder_bits())
|
|
277
|
+
.store_builder(rootBuilder);
|
|
278
|
+
|
|
279
|
+
if (numCells == 1) {
|
|
280
|
+
return headerBuilder.end_cell();
|
|
281
|
+
}
|
|
282
|
+
if (numCells == 2) {
|
|
283
|
+
return headerBuilder
|
|
284
|
+
.store_ref(classBuilder.at(2).end_cell())
|
|
285
|
+
.end_cell();
|
|
286
|
+
}
|
|
287
|
+
return headerBuilder
|
|
288
|
+
.store_ref(classBuilder.at(2).end_cell())
|
|
289
|
+
.store_ref(classBuilder.at(3).end_cell())
|
|
290
|
+
.end_cell();
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
cell cl::nullObject() inline method_id {
|
|
294
|
+
return empty_cell();
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
;;; ====================== Class Setter ======================
|
|
298
|
+
int cl::getFieldType::asm(slice self, int fieldInfoOffset ) asm """
|
|
299
|
+
// STACK [fieldInfoOffset, headerSlice]
|
|
300
|
+
4 PUSHINT // STACK [_FIELD_TYPE_WIDTH, fieldInfoOffset, headerSlice]
|
|
301
|
+
SDSUBSTR // STACK [substring]
|
|
302
|
+
4 PLDU // STACK [2BitUnsignInt]
|
|
303
|
+
""";
|
|
304
|
+
|
|
305
|
+
int cl::getFieldCellIndex::asm(slice self, int fieldInfoOffset ) asm """
|
|
306
|
+
4 ADDCONST // STACK [fieldInfoOffset + _FIELD_TYPE_WIDTH, headerSlice]
|
|
307
|
+
2 PUSHINT // STACK [_CELL_ID_WIDTH, fieldInfoOffset + _FIELD_TYPE_WIDTH, headerSlice]
|
|
308
|
+
SDSUBSTR // STACK [substring]
|
|
309
|
+
2 PLDU // STACK [2BitUnsignInt]
|
|
310
|
+
""";
|
|
311
|
+
|
|
312
|
+
int cl::getFieldOffset::asm(slice self, int fieldInfoOffset ) asm """
|
|
313
|
+
6 ADDCONST // STACK [fieldInfoOffset + _FIELD_TYPE_WIDTH + _CELL_ID_WIDTH, headerSlice]
|
|
314
|
+
10 PUSHINT // STACK [_DATA_OFFSET_WIDTH, fieldInfoOffset +_FIELD_TYPE_WIDTH + _CELL_ID_WIDTH, headerSlice]
|
|
315
|
+
SDSUBSTR // STACK [substring]
|
|
316
|
+
10 PLDU // STACK [10BitUnsignInt]
|
|
317
|
+
""";
|
|
318
|
+
|
|
319
|
+
int cl::getFieldCellOffset::asm(slice self, int fieldInfoOffset ) asm """
|
|
320
|
+
16 ADDCONST // STACK [fieldInfoOffset + _FIELD_TYPE_WIDTH + _CELL_ID_WIDTH + _DATA_OFFSET_WIDTH, headerSlice]
|
|
321
|
+
2 PUSHINT // STACK [_REF_OFFSET_WIDTH, fieldInfoOffset + _FIELD_TYPE_WIDTH + _CELL_ID_WIDTH + _DATA_OFFSET_WIDTH headerSlice]
|
|
322
|
+
SDSUBSTR // STACK [substring]
|
|
323
|
+
2 PLDU // STACK [10BitUnsignInt]
|
|
324
|
+
""";
|
|
325
|
+
|
|
326
|
+
int cl::preload_bits_offset_3::asm(int width1, slice self, int fieldOffset, int width2 ) asm """
|
|
327
|
+
SDSUBSTR // STACK [substring]
|
|
328
|
+
s1 XCHG0
|
|
329
|
+
PLDUX // STACK [10BitUnsignInt] (CC +1 )
|
|
330
|
+
""";
|
|
331
|
+
|
|
332
|
+
forall X -> cell cl::set(cell $self, int fieldName, X val) inline method_id {
|
|
333
|
+
slice headerSlice = $self.begin_parse();
|
|
334
|
+
int fieldInfoOffset = _BASIC_HEADER_WIDTH + (fieldName * _FIELD_INFO_WIDTH);
|
|
335
|
+
int fieldCellIndex = headerSlice.cl::getFieldCellIndex::asm(fieldInfoOffset);
|
|
336
|
+
int fieldType = headerSlice.cl::getFieldType::asm(fieldInfoOffset);
|
|
337
|
+
int fieldOffset = headerSlice.cl::getFieldOffset::asm(fieldInfoOffset);
|
|
338
|
+
int fieldRefsOffset = headerSlice.cl::getFieldCellOffset::asm(fieldInfoOffset );
|
|
339
|
+
|
|
340
|
+
if (DEBUG) {
|
|
341
|
+
throwErrorUnless(fieldType < INVALID_TYPE, "Type does not exist");
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
int fieldWidth = _getTypeWidth(fieldType);
|
|
345
|
+
slice victim = fieldCellIndex == 0
|
|
346
|
+
? headerSlice
|
|
347
|
+
: headerSlice.preload_ref_at(fieldCellIndex).begin_parse();
|
|
348
|
+
if (fieldWidth != 0) {
|
|
349
|
+
fieldRefsOffset = MAX_CELL_REFS;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
builder replacement = begin_cell()
|
|
353
|
+
.store_slice(
|
|
354
|
+
victim.scutfirst(
|
|
355
|
+
min(victim.slice_bits(), fieldOffset),
|
|
356
|
+
min(fieldRefsOffset, victim.slice_refs())
|
|
357
|
+
)
|
|
358
|
+
);
|
|
359
|
+
|
|
360
|
+
if (fieldType == cl::t::cellRef) {
|
|
361
|
+
replacement = replacement
|
|
362
|
+
.store_ref(val.cast_to_cell())
|
|
363
|
+
.store_slice(victim.scutlast(0, victim.slice_refs() - fieldRefsOffset - 1));
|
|
364
|
+
} elseif (fieldType == cl::t::objRef) {
|
|
365
|
+
replacement = replacement
|
|
366
|
+
.store_ref(val.cast_to_cell())
|
|
367
|
+
.store_slice(victim.scutlast(0, victim.slice_refs() - fieldRefsOffset - 1));
|
|
368
|
+
} else { ;; numeric type
|
|
369
|
+
replacement = replacement
|
|
370
|
+
.store_uint(abs(val.cast_to_int()), fieldWidth)
|
|
371
|
+
.store_slice(victim.sskipfirst(fieldOffset + fieldWidth, victim.slice_refs()));
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
if (fieldCellIndex > 0) {
|
|
375
|
+
;; link the replacement into the root cell
|
|
376
|
+
return begin_cell()
|
|
377
|
+
.store_slice(headerSlice.scutfirst(headerSlice.slice_bits(), fieldCellIndex))
|
|
378
|
+
.store_ref(replacement.end_cell())
|
|
379
|
+
.store_slice(headerSlice.scutlast(0, headerSlice.slice_refs() - fieldCellIndex - 1))
|
|
380
|
+
.end_cell();
|
|
381
|
+
}
|
|
382
|
+
return replacement.end_cell();
|
|
383
|
+
}
|
|
384
|
+
;;; ====================== Class Getters ======================
|
|
385
|
+
|
|
386
|
+
const int _NAME_WIDTH = 8 * MAX_NAME_LEN; ;; convert to bits
|
|
387
|
+
const int _BASIC_HEADER_WIDTH = _NAME_WIDTH;
|
|
388
|
+
const int MAX_NAME_INTLEN = (1 << (8 * MAX_NAME_LEN)) - 1;
|
|
389
|
+
|
|
390
|
+
const int _FIELD_TYPE_WIDTH+_CELL_ID_WIDTH = 6; ;; support up to 16 types
|
|
391
|
+
|
|
392
|
+
const int _FIELD_TYPE_WIDTH = 4; ;; support up to 16 types
|
|
393
|
+
const int _CELL_ID_WIDTH = 2; ;; the classlib backend supports up to 4 inner cells including root
|
|
394
|
+
const int _DATA_OFFSET_WIDTH = 10; ;; 1023 bits per cell = 2**10 - 1
|
|
395
|
+
|
|
396
|
+
;; int cl::get<uint>::asm_t( int width, int fieldName, tuple self) asm """
|
|
397
|
+
;; // DUMPSTK // STACK [s, fieldName, width]
|
|
398
|
+
;; 0 INDEX // cell cell_at(tuple t, int index) => STACK [cellResult, fieldName, width]
|
|
399
|
+
;; CTOS // slice begin_parse(cell c) => STACK [sliceResult, fieldName, width]
|
|
400
|
+
;; s1 XCHG0 // STACK [fieldName, sliceResult, width]
|
|
401
|
+
;; 18 MULCONST // STACK [_FIELD_INFO_WIDTH*fieldName, sliceResult, width]
|
|
402
|
+
;; 84 ADDCONST // STACK [_BASIC_HEADER_WIDTH + _FIELD_TYPE_WIDTH + (_FIELD_INFO_WIDTH*fieldName) = fieldInfoOffset, mulRes, sliceResult, width]
|
|
403
|
+
;; s1 s1 s1 XCHG3 // STACK [width, fieldInfoOffset, sliceResult]
|
|
404
|
+
;; SDSUBSTR // STACK [preloadBitsOffsetResult]
|
|
405
|
+
;; 10 PLDU // STACK [fieldCellIndex]
|
|
406
|
+
;; """;
|
|
407
|
+
|
|
408
|
+
int cl::get<uint>(cell $self, int fieldName, int width) inline method_id {
|
|
409
|
+
slice headerSlice = $self.begin_parse();
|
|
410
|
+
|
|
411
|
+
int fieldInfoOffset = _BASIC_HEADER_WIDTH + (fieldName * _FIELD_INFO_WIDTH);
|
|
412
|
+
int fieldCellIndex = headerSlice.cl::getFieldCellIndex::asm(fieldInfoOffset);
|
|
413
|
+
int fieldOffset = headerSlice.cl::getFieldOffset::asm(fieldInfoOffset);
|
|
414
|
+
|
|
415
|
+
if (DEBUG) {
|
|
416
|
+
int fieldType = headerSlice
|
|
417
|
+
.preload_bits_offset(
|
|
418
|
+
fieldInfoOffset,
|
|
419
|
+
_FIELD_TYPE_WIDTH
|
|
420
|
+
)
|
|
421
|
+
.preload_uint(_FIELD_TYPE_WIDTH);
|
|
422
|
+
int expected_field_width = _getTypeWidth(fieldType);
|
|
423
|
+
throw_unless(0, expected_field_width == width);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
if (fieldCellIndex == 0) {
|
|
427
|
+
return cl::preload_bits_offset_3::asm(width, headerSlice, fieldOffset, width);
|
|
428
|
+
}
|
|
429
|
+
else {
|
|
430
|
+
return cl::preload_bits_offset_3::asm( width, headerSlice.preload_ref_at(fieldCellIndex).begin_parse(), fieldOffset, width);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
cell cl::get<cellRef>(cell $self, int fieldName) inline method_id {
|
|
435
|
+
slice headerSlice = $self.begin_parse();
|
|
436
|
+
int fieldInfoOffset = _BASIC_HEADER_WIDTH + (fieldName * _FIELD_INFO_WIDTH);
|
|
437
|
+
int fieldCellIndex = headerSlice.cl::getFieldCellIndex::asm(
|
|
438
|
+
fieldInfoOffset);
|
|
439
|
+
int fieldRefIdx = headerSlice
|
|
440
|
+
.cl::getFieldCellOffset::asm(
|
|
441
|
+
fieldInfoOffset);
|
|
442
|
+
|
|
443
|
+
if (DEBUG) {
|
|
444
|
+
int fieldType = headerSlice
|
|
445
|
+
.preload_bits_offset(
|
|
446
|
+
fieldInfoOffset,
|
|
447
|
+
_FIELD_TYPE_WIDTH
|
|
448
|
+
)
|
|
449
|
+
.preload_uint(_FIELD_TYPE_WIDTH);
|
|
450
|
+
int expected_field_width = _getTypeWidth(fieldType);
|
|
451
|
+
throw_unless(0, expected_field_width == 0);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
return fieldCellIndex == 0
|
|
455
|
+
? headerSlice.preload_ref_at(fieldRefIdx)
|
|
456
|
+
: (headerSlice
|
|
457
|
+
.preload_ref_at(fieldCellIndex)
|
|
458
|
+
.begin_parse()
|
|
459
|
+
.preload_ref_at(fieldRefIdx)
|
|
460
|
+
);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
cell cl::getWithCell<cellRef>(cell $self, int fieldName) inline method_id {
|
|
464
|
+
return $self.cl::get<cellRef>(fieldName);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
cell cl::get<objRef>(cell $self, int fieldName) inline method_id {
|
|
468
|
+
return cl::get<cellRef>($self, fieldName);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
int cl::get<uint8>(cell $self, int fieldName) inline method_id {
|
|
472
|
+
return $self.cl::get<uint>(fieldName, 8);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
int cl::get<uint16>(cell $self, int fieldName) inline method_id {
|
|
476
|
+
return $self.cl::get<uint>(fieldName, 16);
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
int cl::get<uint32>(cell $self, int fieldName) inline method_id {
|
|
480
|
+
return $self.cl::get<uint>(fieldName, 32);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
int cl::get<uint64>(cell $self, int fieldName) inline method_id {
|
|
484
|
+
return $self.cl::get<uint>(fieldName, 64);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
int cl::get<coins>(cell $self, int fieldName) inline method_id {
|
|
488
|
+
return $self.cl::get<uint>(fieldName, 128);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
int cl::get<uint256>(cell $self, int fieldName) inline method_id {
|
|
492
|
+
return $self.cl::get<uint>(fieldName, 256);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
slice cl::get<std_address>(cell $self, int fieldName) inline method_id {
|
|
496
|
+
return hashpartToBasechainAddressStd(
|
|
497
|
+
$self.cl::get<uint>(fieldName, 256)
|
|
498
|
+
);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
int cl::get<bool>(cell $self, int fieldName) inline method_id {
|
|
502
|
+
return $self.cl::get<uint>(fieldName, 1) != 0;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
cell cl::get<dict256>(cell $self, int fieldName) inline method_id {
|
|
506
|
+
return $self.cl::get<cellRef>(fieldName);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
int cl::get<address>(cell $self, int fieldName) inline method_id {
|
|
510
|
+
return $self.cl::get<uint>(fieldName, 256);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
;;; =============== DEBUG / CONVENIENCE FUNCTIONS =================
|
|
514
|
+
int typeofField(cell $self, int fieldName) inline {
|
|
515
|
+
slice headerSlice = $self.begin_parse();
|
|
516
|
+
int fieldInfoOffset = _BASIC_HEADER_WIDTH + (fieldName * _FIELD_INFO_WIDTH);
|
|
517
|
+
return headerSlice
|
|
518
|
+
.preload_bits_offset(
|
|
519
|
+
fieldInfoOffset,
|
|
520
|
+
_FIELD_TYPE_WIDTH
|
|
521
|
+
)
|
|
522
|
+
.preload_uint(_FIELD_TYPE_WIDTH);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
;; returns -1 (true) if equal, otherwise the index of the first field that differs
|
|
526
|
+
int compareObjectFields(cell $lhs, cell $rhs) impure inline {
|
|
527
|
+
int malformed = cl::typeof($lhs) != cl::typeof($rhs);
|
|
528
|
+
if (malformed) {
|
|
529
|
+
return INVALID_CLASS_MEMBER;
|
|
530
|
+
}
|
|
531
|
+
if (cl::typeof($lhs) == cl::NULL_CLASS_NAME) {
|
|
532
|
+
return -1;
|
|
533
|
+
}
|
|
534
|
+
int fieldIndex = 0;
|
|
535
|
+
while (fieldIndex < INVALID_CLASS_MEMBER) {
|
|
536
|
+
int curFieldType = $lhs.typeofField(fieldIndex);
|
|
537
|
+
if (curFieldType == cl::t::cellRef) {
|
|
538
|
+
malformed = $lhs.cl::get<objRef>(fieldIndex).cl::hash() != $rhs.cl::get<objRef>(fieldIndex).cl::hash();
|
|
539
|
+
if (malformed) {
|
|
540
|
+
~dump($lhs.cl::get<objRef>(fieldIndex).cell_hash());
|
|
541
|
+
~dump($rhs.cl::get<objRef>(fieldIndex).cell_hash());
|
|
542
|
+
}
|
|
543
|
+
} elseif (curFieldType <= cl::t::uint256) {
|
|
544
|
+
int cur_field_width = _getTypeWidth(curFieldType);
|
|
545
|
+
malformed = $lhs.cl::get<uint>(fieldIndex, cur_field_width) != $rhs.cl::get<uint>(fieldIndex, cur_field_width);
|
|
546
|
+
if (malformed) {
|
|
547
|
+
str::console::log<int>("lhs: ", $lhs.cl::get<uint>(fieldIndex, cur_field_width));
|
|
548
|
+
str::console::log<int>("rhs: ", $rhs.cl::get<uint>(fieldIndex, cur_field_width));
|
|
549
|
+
}
|
|
550
|
+
} else {
|
|
551
|
+
fieldIndex = INVALID_CLASS_MEMBER;
|
|
552
|
+
}
|
|
553
|
+
if (malformed) {
|
|
554
|
+
str::console::log<int>("Malformed field: ", fieldIndex);
|
|
555
|
+
return fieldIndex;
|
|
556
|
+
}
|
|
557
|
+
fieldIndex += 1;
|
|
558
|
+
}
|
|
559
|
+
return -1;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
int objectsAreEqual(cell $lhs, cell $rhs) impure inline {
|
|
563
|
+
return compareObjectFields($lhs, $rhs) == -1;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
slice _typeToStr(int fieldType) {
|
|
567
|
+
if (fieldType == cl::t::uint8) { return "uint8"; }
|
|
568
|
+
elseif (fieldType == cl::t::uint16) { return "uint16"; }
|
|
569
|
+
elseif (fieldType == cl::t::uint32) { return "uint32"; }
|
|
570
|
+
elseif (fieldType == cl::t::uint64) { return "uint64"; }
|
|
571
|
+
elseif (fieldType == cl::t::uint256) { return "uint256"; }
|
|
572
|
+
elseif (fieldType == cl::t::coins) { return "coins"; }
|
|
573
|
+
elseif (fieldType == cl::t::address) { return "address"; }
|
|
574
|
+
elseif (fieldType == cl::t::dict256) { return "dict256"; }
|
|
575
|
+
elseif (fieldType == cl::t::objRef) { return "objRef"; }
|
|
576
|
+
elseif (fieldType == cl::t::cellRef) { return "cellRef"; }
|
|
577
|
+
elseif (fieldType == cl::t::bool) { return "bool"; }
|
|
578
|
+
else { return "unknown"; }
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
() printField(cell $obj, int fieldName) impure inline {
|
|
582
|
+
slice headerSlice = $obj.begin_parse();
|
|
583
|
+
int fieldType = typeofField($obj, fieldName);
|
|
584
|
+
int fieldInfoOffset = _BASIC_HEADER_WIDTH + (fieldName * _FIELD_INFO_WIDTH);
|
|
585
|
+
int fieldCellIndex = headerSlice
|
|
586
|
+
.preload_bits_offset(
|
|
587
|
+
fieldInfoOffset + _FIELD_TYPE_WIDTH,
|
|
588
|
+
_CELL_ID_WIDTH
|
|
589
|
+
)
|
|
590
|
+
.preload_uint(_CELL_ID_WIDTH);
|
|
591
|
+
int fieldRefIdx = headerSlice
|
|
592
|
+
.preload_bits_offset(
|
|
593
|
+
fieldInfoOffset + _FIELD_TYPE_WIDTH + _CELL_ID_WIDTH + _DATA_OFFSET_WIDTH,
|
|
594
|
+
_REF_OFFSET_WIDTH
|
|
595
|
+
)
|
|
596
|
+
.preload_uint(_REF_OFFSET_WIDTH);
|
|
597
|
+
|
|
598
|
+
int fieldBits = _getTypeWidth(fieldType);
|
|
599
|
+
int fieldOffset = headerSlice
|
|
600
|
+
.preload_bits_offset(
|
|
601
|
+
fieldInfoOffset + _FIELD_TYPE_WIDTH + _CELL_ID_WIDTH,
|
|
602
|
+
_DATA_OFFSET_WIDTH
|
|
603
|
+
)
|
|
604
|
+
.preload_uint(_DATA_OFFSET_WIDTH);
|
|
605
|
+
|
|
606
|
+
slice toPrint = _typeToStr(fieldType)
|
|
607
|
+
.str::concat(" ")
|
|
608
|
+
.str::concatInt(fieldName)
|
|
609
|
+
.str::concat(" at c")
|
|
610
|
+
.str::concatInt(fieldCellIndex);
|
|
611
|
+
if (fieldBits > 0) {
|
|
612
|
+
toPrint = toPrint.str::concat(".b").str::concatInt(fieldOffset);
|
|
613
|
+
} else {
|
|
614
|
+
toPrint = toPrint.str::concat(".r").str::concatInt(fieldRefIdx);
|
|
615
|
+
}
|
|
616
|
+
if (fieldType <= cl::t::uint256) {
|
|
617
|
+
~strdump(
|
|
618
|
+
toPrint
|
|
619
|
+
.str::concat(" = ")
|
|
620
|
+
.str::concatInt($obj.cl::get<uint>(fieldName, fieldBits))
|
|
621
|
+
);
|
|
622
|
+
} elseif (fieldType == cl::t::objRef) {
|
|
623
|
+
~strdump(toPrint
|
|
624
|
+
.str::concat(" hash = ")
|
|
625
|
+
.str::concatInt($obj.cl::get<objRef>(fieldName).cl::hash())
|
|
626
|
+
);
|
|
627
|
+
} else {
|
|
628
|
+
~strdump(toPrint
|
|
629
|
+
.str::concat(" hash = ")
|
|
630
|
+
.str::concatInt($obj.cl::get<cellRef>(fieldName).cell_hash())
|
|
631
|
+
);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
;;; ====================== Dictionary functions ======================
|
|
636
|
+
|
|
637
|
+
slice uint256ToSlice(int val) inline method_id {
|
|
638
|
+
return begin_cell().store_uint256(val).as_slice();
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
int sliceToUint256(slice s) inline method_id {
|
|
642
|
+
return s.preload_uint(256);
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
;; override the insane behavior of TON to optimize out empty dictionaries
|
|
646
|
+
;; into a single bit
|
|
647
|
+
cell cl::dict256::New() inline method_id {
|
|
648
|
+
return empty_cell();
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
(slice, int) cl::dict256::get(cell dict, int key) inline method_id {
|
|
652
|
+
if (dict.cell_is_empty()) {
|
|
653
|
+
return new_dict().udict_get?(DICT256_KEYLEN, key);
|
|
654
|
+
}
|
|
655
|
+
return dict.udict_get?(DICT256_KEYLEN, key);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
(int, int) cl::dict256::get<uint256>(cell dict, int key) inline method_id {
|
|
659
|
+
(slice val, int exists) = cl::dict256::get(dict, key);
|
|
660
|
+
if (exists) {
|
|
661
|
+
return (sliceToUint256(val), true);
|
|
662
|
+
}
|
|
663
|
+
return (0, false);
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
(cell, int) cl::dict256::get<cellRef>(cell dict, int key) inline method_id {
|
|
667
|
+
if (dict.cell_is_empty()) {
|
|
668
|
+
return (empty_cell(), false);
|
|
669
|
+
}
|
|
670
|
+
return dict.udict_get_ref?(DICT256_KEYLEN, key);
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
cell cl::dict256::setRef(cell dict, int key, cell val) inline method_id {
|
|
674
|
+
if (dict.cell_is_empty()) {
|
|
675
|
+
return new_dict().udict_set_ref(
|
|
676
|
+
DICT256_KEYLEN,
|
|
677
|
+
key,
|
|
678
|
+
val.cast_to_cell()
|
|
679
|
+
);
|
|
680
|
+
}
|
|
681
|
+
return dict.udict_set_ref(DICT256_KEYLEN, key, val.cast_to_cell());
|
|
682
|
+
}
|
|
683
|
+
forall X -> cell cl::dict256::set(cell dict, int key, X val) inline {
|
|
684
|
+
slice _val = val.is_slice() ? val.cast_to_slice() : uint256ToSlice(val.cast_to_int());
|
|
685
|
+
if (dict.cell_is_empty()) {
|
|
686
|
+
return new_dict().udict_set(DICT256_KEYLEN, key, _val);
|
|
687
|
+
}
|
|
688
|
+
return dict.udict_set(DICT256_KEYLEN, key, _val);
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
cell cl::dict256::delete(cell dict, int key) {
|
|
692
|
+
if (dict.cell_is_empty()) {
|
|
693
|
+
return dict;
|
|
694
|
+
}
|
|
695
|
+
(cell modified_dict, _) = dict.udict_delete?(DICT256_KEYLEN, key);
|
|
696
|
+
return modified_dict.is_cell() ? modified_dict : cl::dict256::New();
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
;;; ====================== Dictionary Iterators ======================
|
|
700
|
+
;; returns key, val, and key == -1 if there is no next (or min) element
|
|
701
|
+
;; if the val exists, it is returned
|
|
702
|
+
;; if a val does not exist, null() is returned
|
|
703
|
+
|
|
704
|
+
(int, slice) cl::dict256::getMin<slice>(cell dict256) {
|
|
705
|
+
if (dict256.cell_is_empty()) {
|
|
706
|
+
return (-1, null());
|
|
707
|
+
}
|
|
708
|
+
(int key, slice val, int exists) = dict256.udict_get_min?(DICT256_KEYLEN);
|
|
709
|
+
if (exists) {
|
|
710
|
+
return (key, val);
|
|
711
|
+
}
|
|
712
|
+
return (-1, null());
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
(int, int) cl::dict256::getMin<uint256>(cell dict256) {
|
|
716
|
+
if (dict256.cell_is_empty()) {
|
|
717
|
+
return (-1, null());
|
|
718
|
+
}
|
|
719
|
+
(int key, slice val, int exists) = dict256.udict_get_min?(DICT256_KEYLEN);
|
|
720
|
+
if (exists) {
|
|
721
|
+
return (key, val.preload_uint(256));
|
|
722
|
+
}
|
|
723
|
+
return (-1, null());
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
(int, cell) cl::dict256::getMin<cellRef>(cell dict256) {
|
|
727
|
+
if (dict256.cell_is_empty()) {
|
|
728
|
+
return (-1, null());
|
|
729
|
+
}
|
|
730
|
+
(int key, cell val, int exists) = dict256.udict_get_min_ref?(DICT256_KEYLEN);
|
|
731
|
+
if (exists) {
|
|
732
|
+
return (key, val);
|
|
733
|
+
}
|
|
734
|
+
return (-1, null());
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
(int, slice) cl::dict256::getNext<slice>(cell dict256, int pivot) {
|
|
738
|
+
if (dict256.cell_is_empty()) {
|
|
739
|
+
return (-1, null());
|
|
740
|
+
}
|
|
741
|
+
(int key, slice val, int exists) = dict256.udict_get_next?(DICT256_KEYLEN, pivot);
|
|
742
|
+
if (exists) {
|
|
743
|
+
return (key, val);
|
|
744
|
+
}
|
|
745
|
+
return (-1, null());
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
(int, int) cl::dict256::getNext<uint256>(cell dict256, int pivot) {
|
|
749
|
+
if (dict256.cell_is_empty()) {
|
|
750
|
+
return (-1, null());
|
|
751
|
+
}
|
|
752
|
+
(int key, slice val, int exists) = dict256.udict_get_next?(DICT256_KEYLEN, pivot);
|
|
753
|
+
if (exists) {
|
|
754
|
+
return (key, val.preload_uint(256));
|
|
755
|
+
}
|
|
756
|
+
return (-1, null());
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
(int, cell) cl::dict256::getNext<cellRef>(cell dict256, int pivot) {
|
|
760
|
+
if (dict256.cell_is_empty()) {
|
|
761
|
+
return (-1, null());
|
|
762
|
+
}
|
|
763
|
+
(int key, slice val, int exists) = dict256.udict_get_next?(DICT256_KEYLEN, pivot);
|
|
764
|
+
if (exists) {
|
|
765
|
+
return (key, val.preload_first_ref());
|
|
766
|
+
}
|
|
767
|
+
return (-1, null());
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
int cl::dict256::size(cell dict) inline {
|
|
771
|
+
int count = 0;
|
|
772
|
+
(int pivot, _) = dict.cl::dict256::getMin<slice>();
|
|
773
|
+
while (pivot >= 0) {
|
|
774
|
+
(pivot, _) = dict.cl::dict256::getNext<slice>(pivot);
|
|
775
|
+
count = count + 1;
|
|
776
|
+
}
|
|
777
|
+
return count;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
;;; ====================== Nested Dict Helpers ======================
|
|
781
|
+
|
|
782
|
+
forall X -> cell cl::nestedDict256::set(cell $self, int fieldName, int key, X val) inline method_id {
|
|
783
|
+
return $self.cl::set(
|
|
784
|
+
fieldName,
|
|
785
|
+
$self
|
|
786
|
+
.cl::get<dict256>(fieldName)
|
|
787
|
+
.cl::dict256::set(key, val)
|
|
788
|
+
);
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
cell cl::nestedDict256::setRef(cell $self, int fieldName, int key, cell val) inline method_id {
|
|
792
|
+
return $self.cl::set(
|
|
793
|
+
fieldName,
|
|
794
|
+
$self.cl::get<dict256>(fieldName).cl::dict256::setRef(key, val)
|
|
795
|
+
);
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
cell cl::nestedDict256::delete(cell $self, int fieldName, int key) inline method_id {
|
|
799
|
+
return $self.cl::set(
|
|
800
|
+
fieldName,
|
|
801
|
+
$self.cl::get<dict256>(fieldName).cl::dict256::delete(key)
|
|
802
|
+
);
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
(int, int) cl::nestedDict256::get<uint256>(cell $self, int fieldName, int key) inline method_id {
|
|
806
|
+
return $self.cl::get<dict256>(fieldName).cl::dict256::get<uint256>(key);
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
(slice, int) cl::nestedDict256::get<slice>(cell $self, int fieldName, int key) inline method_id {
|
|
810
|
+
return $self.cl::get<dict256>(fieldName).cl::dict256::get(key);
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
(cell, int) cl::nestedDict256::get<cellRef>(cell $self, int fieldName, int key) inline method_id {
|
|
814
|
+
(slice s, int exists) = $self.cl::get<dict256>(fieldName).cl::dict256::get(key);
|
|
815
|
+
if (exists) {
|
|
816
|
+
return (s.preload_first_ref(), exists);
|
|
817
|
+
}
|
|
818
|
+
return (empty_cell(), exists);
|
|
819
|
+
}
|