Đây là bản thử nghiệm.

MainnetJetton thử nghiệm
TON Blockchain

Escrow Smart Contract

Khách hàng và nhà cung cấp gửi tiền vào hợp đồng thông minh. Nhà cung cấp được thanh toán khi công việc hoàn thành và hai bên đồng ý.

Cách hoạt động

Năm bước đến hợp đồng

Tạo hợp đồng thông minh bằng trình hướng dẫn đơn giản.

  1. Bước 1Vai trò trong hợp đồngChọn vai trò của bạn trong hợp đồng. Hợp đồng chỉ có hai vai trò: khách hàng và nhà cung cấp. Không có trọng tài bên thứ ba.
    9:41LTE

    Vai trò trong hợp đồng

    Vai trò trong hợp đồng

    Khách hàng là bên đặt dịch vụ hoặc hàng hóa. Thanh toán trước 100%, cộng thêm khoản đặt cọc hoàn lại tối đa 30% nếu muốn.

    Nhà cung cấp là bên cung cấp dịch vụ hoặc hàng hóa. Nộp khoản đặt cọc hoàn lại (mặc định 30%) trên giá trị hợp đồng.

  2. Bước 2Chọn loại tiềnChọn loại tiền cho hợp đồng. GRAM, tiền gốc của TON, phù hợp với giao dịch nhanh và nhỏ vì khá biến động. USDT là loại tiền ổn định hơn cho giao dịch lớn và dài hạn.
    9:41LTE

    Chọn loại tiền

    Loại tiền của hợp đồng

    GRAM: tạo nhanh hơn. Bạn có thể tạo hợp đồng và nạp tiền ngay trong một giao dịch.

    USDT: tạo theo hai bước. Đầu tiên tạo hợp đồng (ví của bạn cần có tiền gốc GRAM hoặc hỗ trợ giao dịch không cần gas; nên dùng GRAM), sau đó nạp USDT.USDT ít biến động hơn GRAM.

  3. Bước 3Giá trị hợp đồngNhập giá trị hợp đồng bằng loại tiền đã chọn. Số tiền này sẽ được chuyển cho nhà cung cấp sau khi hoàn thành công việc.
    9:41LTE

    Giá trị hợp đồng

    GRAM

    Giá trị hợp đồng là giá của công việc. Do khách hàng nạp.

    30%

    Từ 10% đến 90%. Mặc định: 30%.

    0,4%

    0,4% giá trị, nhưng không quá 15 GRAM.

  4. Bước 4Địa chỉ víDán địa chỉ ví. Về sau, việc nạp và rút tiền sẽ được thực hiện qua các ví này.
    9:41LTE

    Địa chỉ ví

  5. Bước 5Kiểm tra hợp đồngKiểm tra dữ liệu hợp đồng đã nhập trước khi triển khai.
    9:41LTE

    Kiểm tra hợp đồng

    Điều khoản hợp đồng
    Loại tiền
    GRAM
    Giá trị hợp đồng
    1 000 GRAM
    Tiền cọc của nhà cung cấp
    300 GRAM · 30%
    Phí dịch vụ
    4 GRAM · 0,4%

Sau khi tạo

Thẻ hợp đồng

Bạn là khách hàng, loại tiền là USDT. Sáu ảnh chụp của cùng một thẻ như trong trang quản lý thật, với mọi thao tác có thể ở từng bước.

  1. Chờ nạp tiền
    1 000 USDT
    Hợp đồng ngày 21.09.2026 - EQDe…0001
    Khách hàng (bạn)
    0 / 1 000
    Nhà cung cấp
    0 / 300

    *Cộng tối đa 30% tiền cọc hoàn lại

    USDT

    Vừa tạo

    Số dư bằng không. Bạn có thể nạp giá trị giao dịch, nạp luôn kèm phần cọc thêm tối đa 30%, hoặc xóa hợp đồng khi chưa ai nạp gì.

  2. Chờ nạp tiền
    1 000 USDT
    Hợp đồng ngày 21.09.2026 - EQDe…0001
    Khách hàng (bạn)
    1 000 / 1 000
    Nhà cung cấp
    0 / 300

    *Cộng tối đa 30% tiền cọc hoàn lại

    USDT

    Đã nạp, đang chờ

    Giá trị giao dịch đã có trong hợp đồng, nhưng chưa có tiền cọc của nhà cung cấp. Khi trạng thái chưa là “Đang hiệu lực”, bạn có thể rút tiền của mình. Vẫn có thể nạp thêm phần cọc tối đa 30%.

  3. Đang hiệu lực
    1 000 USDT
    Hợp đồng ngày 21.09.2026 - EQDe…0001
    Khách hàng (bạn)
    1 000 / 1 000
    Nhà cung cấp
    300 / 300
    USDT

    Nhà cung cấp phải đồng ý. Số tiền sẽ được làm tròn đến phần trăm nguyên của giá trị giao dịch.

    *Cộng tối đa 30% tiền cọc hoàn lại

    USDT

    Nhà cung cấp đã nạp

    Cả hai khoản đã thỏa thuận đều đã có, hợp đồng đang hiệu lực. Tiền bị đóng băng, không thể rút USDT. Bạn có thể chấp nhận công việc, đề xuất tỷ lệ khác hoặc nạp thêm khoản cọc (bảo đảm bổ sung của khách hàng).

  4. Đang hiệu lực
    1 000 USDT
    Hợp đồng ngày 21.09.2026 - EQDe…0001
    Khách hàng (bạn)
    1 200 / 1 000 + 200 · 20%
    Nhà cung cấp
    300 / 300
    USDT

    Nhà cung cấp phải đồng ý. Số tiền sẽ được làm tròn đến phần trăm nguyên của giá trị giao dịch.

    *Cộng tối đa 30% tiền cọc hoàn lại

    USDT

    Đã thêm 20% tiền cọc

    Có thêm +200 USDT ngoài giá trị giao dịch. Còn 100 USDT nữa mới đến mức trần 30%. Vẫn chưa thể rút: hợp đồng đang hiệu lực giữ giá trị hợp đồng cộng khoản cọc thêm.

  5. Đã đề xuất thanh toán 800 USDT
    1 000 USDT
    Hợp đồng ngày 21.09.2026 - EQDe…0001
    Khách hàng (bạn)
    1 200 / 1 000 + 200 · 20%
    Nhà cung cấp
    300 / 300
    USDT

    Hiện đang đề xuất 800 USDT · 80%. Có thể thay đổi.

    *Cộng tối đa 30% tiền cọc hoàn lại

    USDT

    Đã đề xuất 80% cho nhà cung cấp.

    Nhà cung cấp sẽ nhận 800 USDT nếu đồng ý. Nút “Chấp nhận công việc” đã biến mất; nó chỉ xuất hiện lại nếu bạn đặt 100%. Có thể thay đổi đề xuất và nạp thêm khoản cọc.

  6. Hoàn tất 800 USDT
    1 000 USDT
    Hợp đồng ngày 21.09.2026 - EQDe…0001
    Khách hàng (bạn)
    400
    Nhà cung cấp
    1 096

    Nhà cung cấp đã đồng ý

    Hợp đồng hoàn tất: 800 USDT đã chuyển cho nhà cung cấp, 4 USDT là phí bản quyền của dịch vụ. Bạn còn 400 USDT, có thể rút về.

Q&A

Câu hỏi thường gặp

Bên thứ ba ở đâu?

Không có. Nhà cung cấp mạo hiểm tiền cọc của mình, nên họ có lợi khi làm xong công việc.

Mặc định, tiền cọc của nhà cung cấp bằng 30% giá trị giao dịch. Có vẻ như họ có lợi thế: họ chỉ mạo hiểm 30%, còn bạn 100%. Nhưng điều quan trọng không phải là phần trăm, mà là tiền. 30% đó là tiền của chính họ, và mất nó có thể khiến họ đau không kém gì bạn mất 100% của mình. Không ai tự dưng hy sinh tiền của mình.

Rủi ro khác: khách hàng đã nhận công việc và có thể không trả tiền. Khi đó có hai cách. Cách thứ nhất: khi công việc gần xong, đề nghị thanh toán trước. Cách thứ hai: yêu cầu khách hàng nạp thêm tối đa 30% ngoài giá trị (tiền cọc). Sau khi hợp đồng kết thúc, khách hàng sẽ nhận lại tiền cọc, nên họ có lý do để đóng giao dịch (hợp đồng).

Vì sao tôi nên tin bạn?

Không cần tin. Hợp đồng thông minh là công khai. Địa chỉ hợp đồng của bạn là hash của dữ liệu ban đầu và mã. Nếu mã bị tráo, địa chỉ sẽ khác.

Bạn có thể mở và xem nó (ví dụ trên Tonviewer). Điều duy nhất là cần hiểu mã — đó là vấn đề chính. Nhưng đổi lại, đây là bằng chứng 100%. Bạn cũng có thể đưa mã cho mô hình AI. Dưới đây là mã hợp đồng kèm giải thích đơn giản nhất có thể.

ContractUSDT

Đây là danh sách import: các hằng số và hàm hỗ trợ.

contract_usdt.tolk
1import "@contracts/common-messages"
2import "@contracts/errors"
3import "@contracts/contract_USDT/usdt-utils"
4import "fees-management"
5import "messages"
6import "storage"

Mô tả ngắn gọn về hợp đồng.

8contract ContractUSDT {
9 author: "Alexandr_K"
10 version: "0.0.4"
11 description: "Escrow contract USDT"
12 storage: StorageUsdt
13 incomingMessages: AllowedMessage
14}

Danh sách các thao tác có thể thực hiện với hợp đồng.

16type AllowedMessage =
17 | TransferNotificationForRecipient
18 | ChangePercent
19 | AcceptPercent
20 | RefundUsdt
21 | ErrRefund
22 | ErrMode
23 | BurnContract

Hàm hỗ trợ: hợp đồng có đang hiệu lực hay không. Khi mọi người đã nạp đủ phần của mình, hợp đồng có hiệu lực và không thể rút tiền tùy ý nữa.

28fun StorageUsdt.isActive(self, extra: ExtraFieldsUsdt): bool {
29 if (extra.completed) {
30 return false;
31 }
32 return self.clientAmount >= extra.clientAmountInit &&
33 self.providerDeposit >= extra.providerDepositInit;
34}

Hàm xử lý tiền thừa. Mỗi tin nhắn kèm một ít GRAM để xử lý giao dịch. Phần dư được hàm này trả lại.

67fun sendExcessesTon(to: address, amount: coins) {
68 if (amount > MIN_MESSAGE_VALUE_BOUND) {
69 val excessesMsg = createMessage({
70 bounce: BounceMode.NoBounce,
71 dest: to,
72 value: amount,
73 });
74 excessesMsg.send(SEND_MODE_IGNORE_ERRORS);
75 }
76}

Tính địa chỉ ví jetton. Địa chỉ này phụ thuộc vào địa chỉ hợp đồng.

78fun contractUsdtWallet(): address {
79 return calcAddressOfJettonWallet(contract.getAddress());
80}

Nếu chuyển khoản thất bại, tiền sẽ quay lại và hợp đồng sửa lại sổ sách: ai có bao nhiêu.

105fun onBouncedMessage(in: InMessageBounced) {
106 in.bouncedBody.skipBouncedPrefix();
107 val msg = lazy BounceOpToHandle.fromSlice(in.bouncedBody);
108 var storage = lazy StorageUsdt.load();
109 match (msg) {
110 TransferBounce => {
111 if (msg.queryId == QueryRole.Client as uint64) {
112 storage.clientAmount += msg.jettonAmount;
113 } else if (msg.queryId == QueryRole.Provider as uint64) {
114 storage.providerDeposit += msg.jettonAmount;
115 } else if (msg.queryId == QueryRole.Admin as uint64) {
116 var extra: ExtraFieldsUsdt = lazy storage.extra.load();
117 extra.royaltyInit += msg.jettonAmount;
118 storage.extra = extra.toCell();
119 } else {
120 // ErrRefund (QueryRole.None) и неизвестные id: учёт не уменьшали
121 return;
122 }
123 }
124 }
125 storage.save();
126}

Nếu nội dung tin nhắn trống thì không làm gì.

131fun onInternalMessage(in: InMessage) {
132 if (in.body.isEmpty()) {
133 return;
134 }

Tiếp theo là phần khai báo biến.

137val msg = lazy AllowedMessage.fromSlice(in.body);
138var storage: StorageUsdt = lazy StorageUsdt.load();
139val tonBalanceBeforeMsg = contract.getOriginalBalance() - in.valueCoins;
140val storageFee = MIN_TONS_FOR_STORAGE_THIS_CONTRACT -
141min(tonBalanceBeforeMsg, MIN_TONS_FOR_STORAGE_THIS_CONTRACT);
142var msgValue = in.valueCoins - storageFee - CONTRACT_GAS_CONSUMPTION;

Nạp USDT: nhận chuyển khoản và ghi lại mỗi bên có bao nhiêu USDT.

145TransferNotificationForRecipient => {
146 assert (in.senderAddress == contractUsdtWallet()) throw Errors.InvalidWallet;
147 assert (msg.transferInitiator != null) throw Errors.InvalidData;
148 if (msg.transferInitiator == storage.clientAddress) {
149 storage.clientAmount += msg.jettonAmount;
150 storage.save();
151 } else if (msg.transferInitiator == storage.providerAddress) {
152 storage.providerDeposit += msg.jettonAmount;
153 storage.save();
154 }
155 sendExcessesTon(msg.transferInitiator, msgValue);
156}

Thay đổi tỷ lệ thanh toán. Nếu công việc mới xong một nửa, bạn có thể đề xuất 50%. Nhà cung cấp đồng ý thì hợp đồng hoàn tất. Nếu không thì tiếp tục thương lượng.

162ChangePercent => {
163 assert (msgValue > 0) throw Errors.NotEnoughGas;
164 assert (in.senderAddress == storage.clientAddress) throw Errors.UnauthorizedSender;
165 assert (msg.percent >= 0 && msg.percent <= 100) throw Errors.WrongPercent;
166 var extra: ExtraFieldsUsdt = lazy storage.extra.load();
167 assert (extra.completed == false) throw Errors.ContractIsCompleted;
168 assert (storage.isActive(extra)) throw Errors.ContractIsNotActive;
169 extra.percent = msg.percent;
170 if (msg.percent == 100) {
171 extra.completed = true;
172 storage.providerDeposit += extra.clientAmountInit - extra.royaltyInit;
173 storage.clientAmount -= extra.clientAmountInit;
174 }
175 storage.extra = extra.toCell();
176 storage.save();
177 sendExcessesTon(in.senderAddress, msgValue);
178}

Nếu nhà cung cấp đồng ý, hợp đồng trả cho họ phần của họ cộng tiền cọc, phần còn lại về bạn. Với 0%, toàn bộ giao dịch bị hủy, mọi người nhận lại tiền của mình. Khi đó không phải trả phí 0,4% cho hợp đồng.

183AcceptPercent => {
184 assert (msgValue > 0) throw Errors.NotEnoughGas;
185 assert (in.senderAddress == storage.providerAddress) throw Errors.UnauthorizedSender;
186 var extra: ExtraFieldsUsdt = lazy storage.extra.load();
187 assert (extra.completed == false) throw Errors.ContractIsCompleted;
188 assert (extra.percent != 100) throw Errors.WrongPercent;
189 assert (msg.percent == extra.percent) throw Errors.WrongPercent;
190 extra.completed = true;
191 val percentValue = extra.clientAmountInit / 100 * msg.percent;
192 if (msg.percent == 0) {
193 extra.royaltyInit = 0;
194 }
195 storage.providerDeposit += percentValue - extra.royaltyInit;
196 storage.clientAmount -= percentValue;
197 storage.extra = extra.toCell();
198 storage.save();
199 sendExcessesTon(in.senderAddress, msgValue);
200}

Khối lớn nhất: quản lý việc hoàn tiền.

208RefundUsdt => {
209 msgValue -= (MIN_MESSAGE_VALUE_BOUND + MIN_FORWARD_TON_AMOUNT);
210 assert (msgValue > 0) throw Errors.NotEnoughGas;
211 assert (msg.jettonAmount > 0) throw Errors.InvalidData;
212 var extra: ExtraFieldsUsdt = lazy storage.extra.load();
213 val transferRecipient: address = msg.addressRefund != null
214 ? msg.addressRefund
215 : in.senderAddress;
216 val isActive = storage.isActive(extra);
217 var queryId: uint64;
218 var jettonAmount: coins;
219 if (in.senderAddress == storage.clientAddress) {
220 queryId = QueryRole.Client;
221 if (isActive) {
222 val deposit: uint72 = (extra.clientAmountInit / 100) * 30;
223 val locked = extra.clientAmountInit + deposit;
224 assert (storage.clientAmount > locked) throw Errors.NotEnoughJettons;
225 jettonAmount = min(storage.clientAmount - locked, msg.jettonAmount);
226 } else {
227 jettonAmount = min(storage.clientAmount, msg.jettonAmount);
228 }
229 storage.clientAmount -= jettonAmount;
230 } else if (in.senderAddress == storage.providerAddress) {
231 queryId = QueryRole.Provider;
232 if (isActive) {
233 assert (
234 storage.providerDeposit > extra.providerDepositInit
235 ) throw Errors.NotEnoughJettons;
236 jettonAmount = min(
237 storage.providerDeposit - extra.providerDepositInit,
238 msg.jettonAmount,
239 );
240 } else {
241 jettonAmount = min(storage.providerDeposit, msg.jettonAmount);
242 }
243 storage.providerDeposit -= jettonAmount;
244 } else if (in.senderAddress == extra.adminAddress) {
245 queryId = QueryRole.Admin;
246 val maxRefundUsdt: uint72 = extra.completed ? extra.royaltyInit : 0;
247 jettonAmount = min(maxRefundUsdt, msg.jettonAmount);
248 extra.royaltyInit -= jettonAmount;
249 storage.extra = extra.toCell();
250 } else {
251 throw Errors.UnauthorizedSender;
252 }
253 assert (jettonAmount > 0) throw Errors.NotEnoughJettons;
254 storage.save();
255 sendAskToTransferUsdt(
256 queryId,
257 jettonAmount,
258 transferRecipient,
259 msgValue + MIN_MESSAGE_VALUE_BOUND + MIN_FORWARD_TON_AMOUNT,
260 );
261}

Chế độ lỗi. Nếu mất ví hoặc tiền đi ngoài sổ sách, một bên có thể chuyển quyền kiểm soát cho bên kia. Tình huống “ngoài sổ sách” nói đúng ra là không thể xảy ra, trừ khi cố ý. Nhưng cứ để đó. Còn quên hoặc mất ví thì hoàn toàn có thể.

271ErrMode => {
272 assert (msgValue > 0) throw Errors.NotEnoughGas;
273 var extra: ExtraFieldsUsdt = lazy storage.extra.load();
274 var noticeTo: address? = null;
275 var noticeAboutClient: bool = false;
276 if (in.senderAddress == storage.clientAddress) {
277 if (msg.value == ErrModeVal.ProviderFullRights as int8) {
278 extra.errMode = ErrModeVal.ProviderFullRights;
279 } else if (msg.value == ErrModeVal.BlockErrorMode as int8) {
280 extra.errMode = ErrModeVal.BlockErrorMode;
281 } else if (
282 msg.value == ErrModeVal.ClientFullRightsAfterHalfYear as int8 &&
283 extra.errMode != ErrModeVal.BlockErrorMode as int8
284 ) {
285 extra.errMode = ErrModeVal.ClientFullRightsAfterHalfYear;
286 extra.errModeAt = blockchain.now() as uint64;
287 noticeTo = storage.providerAddress;
288 noticeAboutClient = true;
289 }
290 } else if (in.senderAddress == storage.providerAddress) {
291 if (msg.value == ErrModeVal.ClientFullRights as int8) {
292 extra.errMode = ErrModeVal.ClientFullRights;
293 } else if (msg.value == ErrModeVal.BlockErrorMode as int8) {
294 extra.errMode = ErrModeVal.BlockErrorMode;
295 } else if (
296 msg.value == ErrModeVal.ProviderFullRightsAfterHalfYear as int8 &&
297 extra.errMode != ErrModeVal.BlockErrorMode as int8
298 ) {
299 extra.errMode = ErrModeVal.ProviderFullRightsAfterHalfYear;
300 extra.errModeAt = blockchain.now() as uint64;
301 noticeTo = storage.clientAddress;
302 noticeAboutClient = false;
303 }
304 } else {
305 throw Errors.UnauthorizedSender;
306 }
307 if (noticeTo != null) {
308 assert (msgValue > HALF_YEAR_NOTICE_VALUE) throw Errors.NotEnoughGas;
309 msgValue -= HALF_YEAR_NOTICE_VALUE;
310 }
311 storage.extra = extra.toCell();
312 storage.save();
313 if (noticeTo != null) {
314 sendHalfYearControlNotice(noticeTo, noticeAboutClient);
315 }
316 sendExcessesTon(in.senderAddress, msgValue);
317}
10enum ErrModeVal {
11 ClientFullRights = 1
12 ProviderFullRights = 2
13 ClientFullRightsAfterHalfYear = 16 // клиент получает полные права через полгода
14 ProviderFullRightsAfterHalfYear = 26 // исполнитель — через полгода
15 BlockErrorMode = 99
16}

ErrRefund: rút khẩn cấp các jetton đến mà không có thông báo và không được ghi sổ. Hoặc khi mất ví (nói đúng hơn là mất mật khẩu của ví).

321ErrRefund => {
322 msgValue -= (MIN_MESSAGE_VALUE_BOUND + MIN_FORWARD_TON_AMOUNT);
323 assert (msgValue > 0) throw Errors.NotEnoughGas;
324 assert (msg.jettonAmount > 0) throw Errors.InvalidData;
325 val extra: ExtraFieldsUsdt = lazy storage.extra.load();
326 if (
327 !extra.allowsErrRefund(
328 in.senderAddress,
329 storage.clientAddress,
330 storage.providerAddress,
331 )
332 ) {
333 throw Errors.UnauthorizedSender;
334 }
335 val transferRecipient: address = msg.addressRefund != null
336 ? msg.addressRefund
337 : in.senderAddress;
338 sendAskToTransferUsdt(
339 QueryRole.None,
340 msg.jettonAmount as coins,
341 transferRecipient,
342 msgValue + MIN_MESSAGE_VALUE_BOUND + MIN_FORWARD_TON_AMOUNT,
343 );
344}
36fun ExtraFieldsUsdt.allowsErrRefund(
37 self,
38 sender: address,
39 client: address,
40 provider: address,
41): bool {
42 if (sender == client) {
43 if (self.errMode == ErrModeVal.ClientFullRights as int8) {
44 return true;
45 }
46 return self.errMode == ErrModeVal.ClientFullRightsAfterHalfYear as int8 &&
47 (blockchain.now() as uint64) >= self.errModeAt + HALF_YEAR;
48 }
49 if (sender == provider) {
50 if (self.errMode == ErrModeVal.ProviderFullRights as int8) {
51 return true;
52 }
53 return self.errMode == ErrModeVal.ProviderFullRightsAfterHalfYear as int8 &&
54 (blockchain.now() as uint64) >= self.errModeAt + HALF_YEAR;
55 }
56 return false;
57}

Burn: hủy hợp đồng để vỏ trống không còn lơ lửng trên mạng. Người có thể đốt là người tạo ra nó (khách hàng hoặc nhà cung cấp) hoặc quản trị viên, và chỉ khi số dư của khách hàng và nhà cung cấp đều bằng không.

351BurnContract => {
352 assert (msgValue > 0) throw Errors.NotEnoughGas;
353 val extra: ExtraFieldsUsdt = lazy storage.extra.load();
354 val deployer = extra.deployerAddress(storage.clientAddress, storage.providerAddress);
355 assert (
356 in.senderAddress == deployer || in.senderAddress == extra.adminAddress
357 ) throw Errors.UnauthorizedSender;
358 assert (
359 storage.clientAmount == 0 && storage.providerDeposit == 0
360 ) throw Errors.BalancesNotEmpty;
361 if (extra.completed && extra.royaltyInit > 0) {
362 val jettonTon = MIN_MESSAGE_VALUE_BOUND + MIN_FORWARD_TON_AMOUNT;
363 msgValue -= jettonTon;
364 assert (msgValue > 0) throw Errors.NotEnoughGas;
365 sendAskToTransferUsdt(
366 QueryRole.Admin,
367 extra.royaltyInit as coins,
368 extra.adminAddress,
369 msgValue + jettonTon,
370 );
371 }
372 val burn = createMessage({
373 bounce: BounceMode.NoBounce,
374 dest: in.senderAddress,
375 value: 0,
376 });
377 burn.send(SEND_MODE_CARRY_ALL_BALANCE | SEND_MODE_DESTROY);
378}
59fun ExtraFieldsUsdt.deployerAddress(self, client: address, provider: address): address {
60 if (self.mode == QueryRole.Client as int8) {
61 return client;
62 }
63 assert (self.mode == QueryRole.Provider as int8) throw Errors.UnauthorizedSender;
64 return provider;
65}

Mã nguồn đã xác minh của ba hợp đồng. Hash mã khớp với mã trên mạng. Mỗi liên kết mở mã trên TON Verifier.

ContractMinterContractUSDTContractTON