English 简体中文 繁體中文 한국 사람 日本語 Deutsch русский بالعربية TÜRKÇE português คนไทย french

简体中文 繁體中文 English 日本語 Deutsch 한국 사람 بالعربية TÜRKÇE คนไทย Français русский

回答

收藏

7.5 NFT 项目/SBT 项目智能合约

开源社区 开源社区 7002 人阅读 | 0 人回复 | 2025-03-15

在本课中,我们将回顾经典的 NFT 项目的代码。此外,我们还将学习 SoulBound (SBT) Item。

8 u9 z- I( Z7 y" VNFT Item合约
让我们打开并查看 contract.
  1. int min_tons_for_storage() asm "50000000 PUSHINT"; ;; 0.05 TON2 H3 J# G" B3 H
复制代码
就像在前面的课程中一样,我们看到有一些常量显示了我们应该在合约上存储的最低代币数量,以便能够支付租金。

  p* @" U2 u! ?3 ?" U# L
  1. (int, int, slice, slice, cell) load_data() {
      V, K* K$ [& ~) o- |
  2.     slice ds = get_data().begin_parse();! p1 J. d# S7 n: I9 {0 h2 z& V
  3.     var (index, collection_address) = (ds~load_uint(64), ds~load_msg_addr());
    8 }# Q/ a# h# b0 g" U6 ~
  4.     if (ds.slice_bits() > 0) {% W6 I0 H# A- H5 j* K
  5.       return (-1, index, collection_address, ds~load_msg_addr(), ds~load_ref());& C, X) [% z; `+ C/ a7 ?
  6.     } else {  * |; |) A! L" t( S, y
  7.       return (0, index, collection_address, null(), null()); ;; nft not initialized yet2 N, v$ W6 u6 f
  8.     }$ m$ k  W, F7 P
  9. }
复制代码
然后我们看到 load_data. 这个 load_data 与我们以前看到的有些不同。通常,我们只是从本地存储区读取数据,但在这里,我们有一些更复杂的逻辑。因此,我们打开本地存储的Cell进行读取,然后读出 index 和 collection_address. 我们知道什么是索引和 Collections 地址。  
然后,我们尝试读取 NFT Item的元数据。首先,我们检查它是否存在。如果是,我们返回 –1, 以及Collections地址、所有者地址和元数据。或者我们只返回 0, 索引和Collections地址时,没有所有者和元数据。这意味着 NFT 尚未初始化。基于这一点,我们将在后面的代码中做出一些决定。
  1. () store_data(int index, slice collection_address, slice owner_address, cell content) impure {
    - ?' G; L8 D$ J7 T0 f3 M
  2.     set_data(: W% i% W4 i. a6 {
  3.         begin_cell()4 K# J. v/ h0 x& N. [, s6 \
  4.             .store_uint(index, 64)
    2 i% l/ v" [2 O+ Q1 O
  5.             .store_slice(collection_address)$ m* X- j4 s2 T7 x; v2 e9 E
  6.             .store_slice(owner_address)
    5 |& a+ ?* e5 @
  7.             .store_ref(content)
    % s5 [4 Q, h3 k+ N: o
  8.             .end_cell()) R& i! W& T2 f. t9 B3 J3 ^) J
  9.     );1 L2 w7 k; [6 _
  10. }
复制代码
我们还看到 store_data 就像我们调查的其他合约一样,这只是正常情况。
! @9 B+ |( G" W
  1. () send_msg(slice to_address, int amount, int op, int query_id, builder payload, int send_mode) impure inline {
    : M" v2 l1 Z& S; H
  2.   var msg = begin_cell()) Q. `1 u* Z* h
  3.     .store_uint(0x10, 6) ;; nobounce - int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool src:MsgAddress -> 010000
    ! T- h1 a# O7 w& f# I8 M
  4.     .store_slice(to_address)' ~' T5 N; c( H1 _* _" U
  5.     .store_coins(amount)# x! a# R. P3 Y2 ]8 D
  6.     .store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1)  Y- d: N+ O7 u2 D& O
  7.     .store_uint(op, 32)
    6 B8 @2 r) `) s8 J
  8.     .store_uint(query_id, 64);
    & \. Z; f) j4 G! X' [3 \: e4 ~+ g

  9. ) d! r0 Y- o2 L. z4 S. m! ]/ C
  10.   if (~ builder_null?(payload)) {) p& j, q; s* E
  11.     msg = msg.store_builder(payload);
    : f5 ~1 F  S5 I( e# y2 U+ m" E
  12.   }
复制代码
在这里,我们封装了发送消息的逻辑,因此我们可以在合约的其他逻辑中使用这个函数。因此,只要我们想发送信息,就可以使用这个函数。它接受目标地址、我们应附加的金额、操作代码、查询 ID、可能的有效载荷(这次是以生成器格式)以及消息的发送模式。这就是我们发送信息的逻辑。
我们的另一个函数是 transfer_ownership. 让我们稍后再研究,一旦我们在 recv_internal 逻辑,因为它是这里最重要的功能。
  1. () recv_internal(int my_balance, int msg_value, cell in_msg_full, slice in_msg_body) impure {
    & Z2 r2 Y; j! G3 l! U9 v
  2.     if (in_msg_body.slice_empty?()) { ;; ignore empty messages: k; l7 e; Q" l. E& \; S
  3.         return ();1 L+ H; W: o' R# {8 p
  4.     }& H2 r1 l  z" B, i
  5. 6 v, I3 c3 ]# g8 E7 f6 R& [
  6.     slice cs = in_msg_full.begin_parse();; L  p- i7 ?& U" D% V
  7.     int flags = cs~load_uint(4);
      G( ]- N" e: ~4 n
  8. 1 |; Z5 L- Z/ L1 k0 Y8 K
  9.     if (flags & 1) { ;; ignore all bounced messages5 X! F4 z0 _1 W- m7 u8 F
  10.         return ();1 p! \0 d: Z+ ^3 U' w7 X
  11.     }* h, F  K7 w4 s, ?
  12.     slice sender_address = cs~load_msg_addr();
    ) ?1 `+ g8 J5 ]% A1 N/ I, K

  13. 5 I4 M8 H  e" ^# g- Q6 T2 Z- Y
  14.     cs~load_msg_addr(); ;; skip dst
    + D0 G2 v0 x* s6 W( \7 `8 s& Y
  15.     cs~load_coins(); ;; skip value
    3 V9 G  S7 k5 h  i- ^
  16.     cs~skip_bits(1); ;; skip extracurrency collection1 z0 Z# f  [; W: x2 J
  17.     cs~load_coins(); ;; skip ihr_fee2 \7 C$ y6 r1 [+ Y5 m8 |
  18.     int fwd_fee = muldiv(cs~load_coins(), 3, 2); ;; we use message fwd_fee for estimation of forward_payload costs- x) Z. v: q0 c% h: H
  19. / _" s8 p5 R# ^/ a- x
  20.     (int init?, int index, slice collection_address, slice owner_address, cell content) = load_data();: |! f' K& V2 Q" }" l
  21.     if (~ init?) {
    2 p/ ^0 x% r0 N' _2 Y' A5 \2 o6 p
  22.       throw_unless(405, equal_slices(collection_address, sender_address));
    6 N) h  V6 W7 A. ]
  23.       store_data(index, collection_address, in_msg_body~load_msg_addr(), in_msg_body~load_ref());
    ) K+ Y$ _2 {, g0 B1 d3 @; y: s
  24.       return ();
    ; u) e& l: U% x' d* q1 x
  25.     }
复制代码
我们来看看它是怎么做的。我们再次忽略空的 in_msg_body 消息,读取标志,忽略退回的信息,并检查发件人是谁。现在我们跳过一些内容,比如信息的目标地址之类的,因为你已经知道这个Cell的内容是什么了。接下来是 fwd_fee 再次根据上一笔交易估算发送下一笔交易的成本。
然后加载数据。正如你所记得的,我们加载数据的方式与这里的实现方式相同。因此,我们要检查它是否未初始化,然后我们期待实际获得这些数据,期待 in_msg_body 以获得所有者的地址和带有元数据的Cell。但这只能通过 collection_address, 因此我们要检查它是否等于发件人地址。然后我们就可以初始化 NFT Item了。
  1. int op = in_msg_body~load_uint(32);7 M" s; e! n0 G4 k0 P' U8 x( \/ d) s* K
  2.   int query_id = in_msg_body~load_uint(64);# [" \7 Q% g, J, ^/ \
  3. 2 ?: C  Q. s3 `# V
  4.   if (op == op::transfer()) {
    4 V- f' J' M; k0 P) N" Q" t: d6 F1 V
  5.     transfer_ownership(my_balance, index, collection_address, owner_address, content, sender_address, query_id, in_msg_body, fwd_fee);
    ( L% G/ [5 {1 D9 K. G
  6.     return ();
    / [! G3 y4 E9 a6 O; p6 A- \
  7.   }7 ]. U+ d# }6 R$ K, q2 u5 Q
  8.   if (op == op::get_static_data()) {
    / L$ {' R  T+ o/ i; @! t
  9.     send_msg(sender_address, 0, op::report_static_data(), query_id, begin_cell().store_uint(index, 256).store_slice(collection_address), 64);  ;; carry all the remaining value of the inbound message
    7 x5 c% ^" P4 K$ a/ {; U
  10.     return ();
    - i" ^: k+ H$ Y, }
  11.   }
复制代码
接下来是操作代码,可以是 op::transfer 或 op::get_static_data. 这是我们要处理的两个可能值。当我们说 get_static_data, 我们会立即向发送静态数据请求的用户发送一条信息。我们只是报告数据,所以我们会向他发送 index 和 collection_address. 这是 get_static_data 函数。正如你所看到的,这是我们的第一个 send_ msg 用例
0 J9 D$ b4 r9 }
  1. () transfer_ownership(int my_balance, int index, slice collection_address, slice owner_address, cell content, slice sender_address, int query_id, slice in_msg_body, int fwd_fees) impure inline {- b0 o% N: q; |. u3 `" q6 D! W
  2.     throw_unless(401, equal_slices(sender_address, owner_address));
    8 D6 K" \5 H6 Q

  3. $ s- K, ?+ I  \" ]
  4.     slice new_owner_address = in_msg_body~load_msg_addr();4 A' X2 K, q" l- L5 F$ f
  5.     force_chain(new_owner_address);8 U, u, V8 Z5 b7 \, I8 z3 X( N
  6.     slice response_destination = in_msg_body~load_msg_addr();% X( R; u" @& @8 M
  7.     in_msg_body~load_int(1); ;; this nft don't use custom_payload3 d" q& G- _* }
  8.     int forward_amount = in_msg_body~load_coins();
    ( r: h0 [, ?1 {5 B" s& O
  9.     throw_unless(708, slice_bits(in_msg_body) >= 1);
      R' t" T, k8 d/ V

  10. # q' E3 b% Q( s) @( G$ u  l3 V4 r
  11.     int rest_amount = my_balance - min_tons_for_storage();' h) o; N! ~1 L$ J
  12.     if (forward_amount) {8 G6 M# G& x0 `: E- e
  13.       rest_amount -= (forward_amount + fwd_fees);
    5 u0 |: T, x; D7 H- \  I
  14.     }
    ' d1 f+ |* n! m8 T+ C" K* v" {
  15.     int need_response = response_destination.preload_uint(2) != 0; ;; if NOT addr_none: 00
    8 a" I' M3 W0 P* u/ S5 X
  16.     if (need_response) {
    ; |: D5 l- O2 g8 h$ B
  17.       rest_amount -= fwd_fees;
    , |/ O; O# Y, ?" K
  18.     }$ ?% v$ L; I/ e

  19. 9 Z! Q2 p4 D. P6 Z1 E
  20.     throw_unless(402, rest_amount >= 0); ;; base nft spends fixed amount of gas, will not check for response
    7 Q! ]2 D9 Q* V: e" U! I7 W& a
  21. % Q; d5 B5 I5 {5 O, ^
  22.     if (forward_amount) {; H0 Y+ Q3 T6 Z. S2 l* z
  23.       send_msg(new_owner_address, forward_amount, op::ownership_assigned(), query_id, begin_cell().store_slice(owner_address).store_slice(in_msg_body), 1);  ;; paying fees, revert on errors
    ) }/ F8 f( h2 a6 o7 ^5 J; b
  24.     }% T5 s- v6 R5 |7 Y
  25.     if (need_response) {
    5 A' q2 p5 @- y
  26.       force_chain(response_destination);
    % u8 V, c, G; g1 v. u5 I
  27.       send_msg(response_destination, rest_amount, op::excesses(), query_id, null(), 1); ;; paying fees, revert on errors
    7 ?: ?6 g# q" Q& z! ~+ p
  28.     }0 s3 P2 u2 `: o9 B7 n: Q2 ^

  29. ( W5 L2 Y( o9 o3 \. w" R) J
  30.     store_data(index, collection_address, new_owner_address, content);
    9 g9 c! K8 q* T' u
  31. }
复制代码
这里有一个转移所有权的功能。首先,我们要检查物品的所有者地址是否就是发送信息的人,因为只有他才能转移所有权。然后,我们读出新所有者的地址。我们 force_chain 以确保他在同一条链上。然后我们检查是否有 response_destination, 因此,一旦我们转移了这个所有权,我们是否应该告诉某人向另一个人发送信息。我们检查 forward_amount 是多少,如果有人要求的话。然后,我们就可以计算出,在发出信息之后,我们就会有足够的钱 forward_amount 到目的地。然后,我们要弄清楚是否需要回应,如果存在 response_destination 。如果存在,其剩余金额必须大于 0。
下面我就向大家简单介绍一下它的工作原理。如果存在 forward_amount ,我们将发送一条信息,通知用户所有权已由该 forward_amount 分配。如果我们需要回应,我们将 force_chain 以确保响应目的地在同一链上。我们发送的回复通常包括超额费用部分和所有额外资金;它们只是被转发到 response_destination. 然后,我们只需使用 new_owner_address 保存数据。基本上,这是唯一会发生变化的地方、 transfer_ownership 是这里的核心函数之一。您拥有一件物品,有时您会将其所有权转让给其他人或出售,这取决于交易的类型。
: ?! Q6 y% f) _& D
SBT item合约
NFT 可以在另一个层面运作。查看 Getgems (https://getgems.io/) 市场。它们有自己的合约,可以出售这类资产。我们现在不研究这些市场合约。不过,我还是要告诉你一个地方,在那里你可以学到很多关于 NFT 的知识 — GetGems github — 在这里,我还想为大家介绍一种 NFT。
GetGems repository 正在主办一些不同的 NFT 合约、藏品、销售和市场以及一些拍卖活动。这里是了解更多与 NFT 藏品、物品及其相关的合约的好地方。但我想向您展示一份确切的合约,我们可以对其进行深入研究。
sbt-item 是一种灵魂绑定代币(SBT)。灵魂绑定与 NFT 非常相似,但不同之处在于灵魂绑定代币不能擅自转让给其他人。我们仔细看看它的代码。
  1. global int storage::index;
    6 t6 T- h  b* k2 D3 P" l
  2. global int init?;
    - J; H1 }2 B0 A" n/ A1 M
  3. global slice storage::collection_address;
    $ B8 {2 X! c9 {# _1 C
  4. global slice storage::owner_address;! O+ O2 j3 W% a% y1 X
  5. global slice storage::authority_address;
    5 J" W! a0 t, M2 l5 E
  6. global cell storage::content;9 z$ \! I+ K* A- }2 a, S
  7. global int storage::revoked_at;3 w( Q$ Y  y1 R" L9 f
  8. () load_data() impure {3 P6 F5 `5 C2 j3 ^/ ~
  9.     slice ds = get_data().begin_parse();, a$ Q4 }/ \) @4 {" k( [( q

  10. ( B/ m' r# j% T9 T0 D: _
  11.     storage::index              = ds~load_uint(64);+ ~" b' o1 n! [% ?
  12.     storage::collection_address = ds~load_msg_addr();
    . G% e7 i: L" V; P
  13.     init?                       = false;
      I( X( x" U) e4 F0 h! X/ v' u6 W
  14.   f% P  k% ~4 d" T
  15.     if (ds.slice_bits() > 0) {
    ! f! n: b& q, P/ b3 {: X' }
  16.         init?                      = true;
    & R: d6 F6 K* C1 q8 Z  L, r
  17.         storage::owner_address     = ds~load_msg_addr();
    ) O/ Q* |7 F$ S9 }& L0 u" h# p
  18.         storage::content           = ds~load_ref();! J1 W% u2 N3 M2 p
  19.         storage::authority_address = ds~load_msg_addr();
    0 {7 J: b/ p& h' s8 c
  20.         storage::revoked_at        = ds~load_uint(64);
      ~! G/ Z" k; E* Q' C9 B
  21.     }+ E  l) i& D7 N& U: Z
  22. }
复制代码
这里有一些变量: storage::index, storage::collection_address. 我们还定义了其他全局变量,这只是 GetGems 实现的一个例子。你不必用同样的方法。我想在这里重点谈谈其他部分:

+ i# x1 w+ l4 c# c7 t, E3 m
  1. if (op == op::request_owner()) {
    " [4 L$ t) ]' D0 T' w* l
  2.     slice dest = in_msg_body~load_msg_addr();
    8 s' o! M7 Y6 B2 W0 F2 T
  3.     cell body = in_msg_body~load_ref();
      X7 j& I, h9 Q7 Y6 s) w
  4.     int with_content = in_msg_body~load_uint(1);
    * r4 i% Y- S. g: \7 A

  5. * c: X0 z+ l2 `/ W: W6 [
  6.     var msg = begin_cell()% P# w& a3 L1 D& f
  7.             .store_uint(storage::index, 256)
    $ g' V  z4 v, Q6 g' ]- \
  8.             .store_slice(sender_address)2 [1 Y% T2 ^5 d
  9.             .store_slice(storage::owner_address)
    : l9 K/ D8 `, v8 X6 d6 \! U
  10.             .store_ref(body)$ v1 c, s0 P$ H  O- Q0 a
  11.             .store_uint(storage::revoked_at, 64)
    5 ^2 M- a4 P8 H
  12.             .store_uint(with_content, 1);: Z' M  M5 Z8 G; n# b

  13. ; ?: {# A, P4 w( U7 l! g6 A
  14.     if (with_content != 0) {9 N# H4 ~$ m8 ]/ k0 n1 ?2 l
  15.         msg = msg.store_ref(storage::content);% v* G! H: a5 Q
  16.     }
    / {+ M& h0 o/ _' _
  17. 7 Q# v# L' [3 h! G  s; C1 K9 c
  18.     ;; mode 64 = carry all the remaining value of the inbound message
    * q3 {: `8 F$ p8 ?% ^* D
  19.     send_msg(flag::regular() | flag::bounce(), dest, 0, op::owner_info(), query_id, msg, 64);
    $ ]# U. h' x: ^  I  u
  20.     return ();0 J( Q0 D" o6 P+ y
  21. }. C4 d8 u! O% [; n5 [' l* r
  22. if (op == op::prove_ownership()) {7 G0 S. {- j+ H  z8 m# R
  23.     throw_unless(401, equal_slices(storage::owner_address, sender_address));. G, a: K6 z- _4 d$ d, d
  24. 3 l" w# J/ d! z% s" G% S9 ^/ f
  25.     slice dest = in_msg_body~load_msg_addr();. k2 I% {8 n# i# u& I4 [$ K# k# n. y
  26.     cell body = in_msg_body~load_ref();0 _" x" w! Y6 k$ V1 a& A0 C) [
  27.     int with_content = in_msg_body~load_uint(1);
    8 u. @* s# J& m- h/ G8 b/ O0 }& i9 J( e

  28. # j  {) |2 N& R: @- }
  29.     var msg = begin_cell()
    " m! k; K/ m5 H; z0 [- C/ V) K) Z
  30.             .store_uint(storage::index, 256)
    / l( G7 K+ [3 K" m0 M: W9 _
  31.             .store_slice(storage::owner_address)
    5 u7 [0 i# ~4 C7 M: s2 Y
  32.             .store_ref(body)
    8 X; z  I# A& C6 `, _3 [7 p
  33.             .store_uint(storage::revoked_at, 64)
    7 q+ X7 g4 w5 O0 z( Y
  34.             .store_uint(with_content, 1);# |! B9 _5 i5 c; G, t; B
  35. 1 ?3 T- X& P: p4 W
  36.     if (with_content != 0) {
    " O9 w- Z1 r  ~: n8 Y" m& z2 |; K
  37.         msg = msg.store_ref(storage::content);1 F* n4 v1 R4 {, e, j
  38.     }
    . f  o& v& O$ D$ p
  39. 8 x3 }- u0 ~( p1 i# ^
  40.     ;; mode 64 = carry all the remaining value of the inbound message
    ' n: F' c8 X. ?$ y
  41.     send_msg(flag::regular() | flag::bounce(), dest, 0, op::ownership_proof(), query_id, msg, 64);
    : K; u& v) I" C2 t- @) S
  42.     return ();4 c+ O; O: ^, k+ J
  43. }
    + o, a6 X8 k- g, a( p
  44. if (op == op::get_static_data()) {
    ) i9 l1 a1 D' R# {  _
  45.     var msg = begin_cell().store_uint(storage::index, 256).store_slice(storage::collection_address);
    / h* }7 w5 E: x8 J. `* {4 P

  46. , Z: M6 r: H9 B6 P$ _) W
  47.     ;; mode 64 = carry all the remaining value of the inbound message4 {( J, ^, S- a) w; _1 r
  48.     send_msg(flag::regular(), sender_address, 0, op::report_static_data(), query_id, msg, 64);
    ' e( x0 f8 C. H9 F! g7 C
  49.     return ();3 ^% `* g8 j/ o# C) ]
  50. }
    ! r5 V2 i8 O# `! Y1 ~
  51. if (op == op::destroy()) {
    9 a8 N+ P7 y. w! ~
  52.     throw_unless(401, equal_slices(storage::owner_address, sender_address));
    ; ~. Z4 |! [  l5 ^% L, \. ~5 y
  53. - v, |- w3 D$ i. |
  54.     send_msg(flag::regular(), sender_address, 0, op::excesses(), query_id, null(), 128);& g0 |; }" a6 a" Y" N" _
  55. + D% j9 @9 _5 ?4 @3 a
  56.     storage::owner_address = null_addr();  f/ S1 j7 {9 u3 b, R6 o
  57.     storage::authority_address = null_addr();
    $ P7 L+ V* a$ Q* w* o' |- P1 _+ t
  58.     store_data();, U. `! V1 ?, z% q: Y
  59.     return ();
    ' p' j" M- D! @( ]
  60. }
    , R- |# a( h( F; p  `3 c
  61. if (op == op::revoke()) {4 \8 l# U$ T3 L. e5 V: e3 V
  62.     throw_unless(401, equal_slices(storage::authority_address, sender_address));/ e, m+ J) `4 m. v9 \/ s' K5 q
  63.     throw_unless(403, storage::revoked_at == 0);1 c2 ~7 _+ B1 O, T
  64. & h# T% n: X& z3 s0 f
  65.     storage::revoked_at = now();
    ; {" q" K+ E: n0 B/ G# _( }$ p
  66.     store_data();# d4 W$ ^( K, Y, I' M+ E
  67.     return ();
    3 E2 ?6 _: \0 ^  p: w0 h
  68. }
    * X% U5 d" d4 n: b2 J
  69. if (op == op::take_excess()) {6 o+ `. L" Q# E* v3 z! c0 N
  70.     throw_unless(401, equal_slices(storage::owner_address, sender_address));
    3 T, F8 O, Y; e6 q
  71. 8 t- f$ ]4 q! N) C) V" S
  72.     ;; reserve amount for storage
    0 N% J$ b) x( L: j  \. S+ h
  73.     raw_reserve(min_tons_for_storage(), 0);. n$ e/ i' T  E9 ?; c

  74. ) U4 j7 ?6 ~8 {$ x% |0 Y
  75.     send_msg(flag::regular(), sender_address, 0, op::excesses(), query_id, null(), 128);* O2 e( R# r  E3 |6 m' @& q
  76.     return ();0 @( z( C- {7 q8 A+ W" Q; O
  77. }
    7 v1 [" m" ?7 m
  78. if (op == op::transfer()) {0 L- d! I, n( K4 T5 w0 u  ~  U' {9 F
  79.     throw(413);: d% k" ]1 N* o3 J% h6 [1 ^& \
  80. }
复制代码
如你所见,这里有许多注释,但我们不会逐行深入研究。你可以看到,这个通证将被用于多种不同的用途,但与普通的 NFT 不同。这里是合约,你可以申请这个合约的所有者。一些操作代码可以请求所有权证明。您可以获取静态数据。你还可以销毁或撤销这个标记。你可以拿走多余的东西,比如,存放在这里的一些钱。如果你是这个合约的所有者,你就可以申请。但你显然不能转让它,就像你在这里看到的一样。这是一种完全不同类型的代币,如果你对 NFT 感兴趣,就应该在 GetGems 存储库里多花点时间。
我想向你展示的是,NFT collections 的所有代码可以保持不变,但collections合约部署的 item 可以不同。例如,你可以用 SBT item 替换 NFT item。这样您就会有一个 SBT item collection,然后您只需更改  code 来初始化你的 collection:
  1. (slice, int, cell, cell, cell) load_data() inline {- Q8 L+ E% x" M& b# l
  2.   var ds = get_data().begin_parse();- L7 G7 V, I; r$ N3 s% x
  3.   return 4 s0 }" L6 p" E' C+ o% r
  4.     (ds~load_msg_addr(), ;; owner_address
      g: _. q) `, p+ W, x4 B  W$ S
  5.      ds~load_uint(64), ;; next_item_index
    0 C  T+ J6 m" G( X) [7 `% ]
  6.      ds~load_ref(), ;; content5 O$ E1 Y/ n/ _; Y" s. w9 x
  7.      ds~load_ref(), ;; nft_item_code8 m: F2 M8 t/ T" q/ F7 B. |& q
  8.      ds~load_ref()  ;; royalty_params
    4 }, @  {4 u+ y: m& ^
  9.      );
    / L( t) ~9 C  o1 D; W5 d( k
  10. }
复制代码
这样,您就可以实际部署 SBT item collection。此外,您还可以创建一个独立的没有collection SBT item。我们不会掌握这些item的编程,我只是想向大家展示它在更大范围内的工作原理。

" a! x1 ]9 m6 O4 I  T  N
结论/ O2 S  {! X- f0 s% Y( Q
从第 3 章中非常简单的逻辑开始,我们已经了解了 NFT 或 Jettons 等复杂合约中的许多内容。这就是一个很好的例子,你可以一步一步地学习某些语法和概念,然后就可以学习更复杂的逻辑。希望这几节课能帮助你理解 Jettons 和 NFTs 的真正含义,以及如何处理它们的代码库--弄清楚它们是如何工作的,并在使用 TON 构建时学习更多可用的语法和架构。
非常感谢您的关注。对你们来说,这可能是最难的一章,虽然我们没有编写任何代码;我们只是在阅读一些你们从未见过的东西,而且非常复杂。你们能坚持到最后一课,我真的很骄傲,我期待着在接下来的章节中看到你们。希望你们喜欢目前的课程。
8 L; w, I, ?3 D, c4 q  {2 a

  b' i1 t* N/ m4 V$ j4 u0 c7 l: y# Y; I$ l
# [- N  B. G* }

& y* u' V5 _4 [# I. p, q' g8 K! t- ^* X2 d$ P' ]- R5 C

2 R6 Y' B' X* s$ K  r
- P% \! j6 x  m* M' E9 T
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则