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

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

回答

收藏

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

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

在本课中,我们将回顾经典的 NFT 项目的代码。此外,我们还将学习 SoulBound (SBT) Item。
# ~) J7 S" u3 \( F
NFT Item合约
让我们打开并查看 contract.
  1. int min_tons_for_storage() asm "50000000 PUSHINT"; ;; 0.05 TON
    & F- q- ?; V: c$ j' \3 x8 a
复制代码
就像在前面的课程中一样,我们看到有一些常量显示了我们应该在合约上存储的最低代币数量,以便能够支付租金。
/ a; Y$ X* r' ]2 E
  1. (int, int, slice, slice, cell) load_data() {+ G; ~& O/ w1 p4 r7 j$ F! ?5 E; g
  2.     slice ds = get_data().begin_parse();1 S4 O3 Q/ g' _2 [
  3.     var (index, collection_address) = (ds~load_uint(64), ds~load_msg_addr());
    - ]) Q6 \& o; b) p. y
  4.     if (ds.slice_bits() > 0) {
    * S& H: }8 v& H) m2 v5 v/ x1 X
  5.       return (-1, index, collection_address, ds~load_msg_addr(), ds~load_ref());9 z6 Q! w/ H! n* c/ R
  6.     } else {  
    5 W! Y, G1 t% o5 c
  7.       return (0, index, collection_address, null(), null()); ;; nft not initialized yet; D  D9 B' V% h, D4 A. V
  8.     }, I) u$ }: j  S4 W% \
  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 {/ h4 H2 B, g1 N
  2.     set_data(
    # q5 H: O$ |6 v$ u: B$ C5 b6 ]% d
  3.         begin_cell(). B( W6 \3 {" \: O# x' \
  4.             .store_uint(index, 64)7 Y. A% b+ Y4 Y; |
  5.             .store_slice(collection_address)4 H& D) j$ N" s: A' H/ G
  6.             .store_slice(owner_address)
    7 s$ X- H2 I. O) O. x0 C
  7.             .store_ref(content)
    ! Q4 Q: W. l4 W* M& G; m
  8.             .end_cell()1 h7 h0 B$ z- l$ v
  9.     );1 l. b( c9 Q/ u0 I6 }
  10. }
复制代码
我们还看到 store_data 就像我们调查的其他合约一样,这只是正常情况。
) S* J: M5 L- [( Y! |' K
  1. () send_msg(slice to_address, int amount, int op, int query_id, builder payload, int send_mode) impure inline {- S' r) u9 S7 `$ f$ R4 a
  2.   var msg = begin_cell()
    ( c3 r! o& [2 C1 U# s
  3.     .store_uint(0x10, 6) ;; nobounce - int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool src:MsgAddress -> 010000( a  e1 B$ ^( z7 [% w% n: Z
  4.     .store_slice(to_address)' z+ L% E( I/ Y0 W
  5.     .store_coins(amount)! d% M. N( T7 B1 W* P+ n' N
  6.     .store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1)
    . c0 o- ]6 }0 c+ S, w( L) G
  7.     .store_uint(op, 32)
    ! e- ~% k+ S% _" y, n) H
  8.     .store_uint(query_id, 64);
    ( b5 `% Y) S0 \% C3 h) X2 y3 C/ j
  9. , X$ |8 v1 @7 R$ ]% v
  10.   if (~ builder_null?(payload)) {, F( S1 u, ?7 A4 N( }
  11.     msg = msg.store_builder(payload);. u8 ^- x9 I' v+ a
  12.   }
复制代码
在这里,我们封装了发送消息的逻辑,因此我们可以在合约的其他逻辑中使用这个函数。因此,只要我们想发送信息,就可以使用这个函数。它接受目标地址、我们应附加的金额、操作代码、查询 ID、可能的有效载荷(这次是以生成器格式)以及消息的发送模式。这就是我们发送信息的逻辑。
我们的另一个函数是 transfer_ownership. 让我们稍后再研究,一旦我们在 recv_internal 逻辑,因为它是这里最重要的功能。
  1. () recv_internal(int my_balance, int msg_value, cell in_msg_full, slice in_msg_body) impure {8 s. v& j% {5 J2 ]
  2.     if (in_msg_body.slice_empty?()) { ;; ignore empty messages
    # j. g( L8 s7 y+ O
  3.         return ();
    6 z) E  C1 ^- N" z
  4.     }7 X1 h( t8 ^- O$ j8 W3 ^2 s- S

  5. ) Q- f& w/ d) z% G
  6.     slice cs = in_msg_full.begin_parse();7 J% z6 g9 M" K' ?5 n) B6 D
  7.     int flags = cs~load_uint(4);$ c  i/ K8 d8 X5 v+ G9 X& T6 j
  8. 1 n& ~- e  r: G4 _" D
  9.     if (flags & 1) { ;; ignore all bounced messages
    ' f0 {+ n$ w; a
  10.         return ();
    ( s3 ?/ I7 Y1 X8 u
  11.     }. t% ~3 V; w) r6 S( G. f
  12.     slice sender_address = cs~load_msg_addr();
    5 A2 s) m  G% F3 l) D

  13. ' F  S* W3 `% Q- K0 X- Z, F, z. C8 ^
  14.     cs~load_msg_addr(); ;; skip dst! c% {* P& p. v( k6 `' r
  15.     cs~load_coins(); ;; skip value1 ^- T$ V# |. O( j# }( u/ m
  16.     cs~skip_bits(1); ;; skip extracurrency collection) c( D5 E6 B1 R: S7 j& g4 o
  17.     cs~load_coins(); ;; skip ihr_fee
    6 R& d; K! K; F: l' s/ v
  18.     int fwd_fee = muldiv(cs~load_coins(), 3, 2); ;; we use message fwd_fee for estimation of forward_payload costs7 l9 E/ a" z0 a" R

  19. 2 `* B4 q1 K% N+ _
  20.     (int init?, int index, slice collection_address, slice owner_address, cell content) = load_data();
    2 {2 [% v, N8 C$ z) O" ^. X
  21.     if (~ init?) {- U! V- N: q9 b$ P# p) p% d
  22.       throw_unless(405, equal_slices(collection_address, sender_address));8 b! k# H, V" B( [  O/ Z
  23.       store_data(index, collection_address, in_msg_body~load_msg_addr(), in_msg_body~load_ref());. ^* `% K1 b7 C$ C; `# ]  K
  24.       return ();6 R1 O8 X( C7 g3 Q% y
  25.     }
复制代码
我们来看看它是怎么做的。我们再次忽略空的 in_msg_body 消息,读取标志,忽略退回的信息,并检查发件人是谁。现在我们跳过一些内容,比如信息的目标地址之类的,因为你已经知道这个Cell的内容是什么了。接下来是 fwd_fee 再次根据上一笔交易估算发送下一笔交易的成本。
然后加载数据。正如你所记得的,我们加载数据的方式与这里的实现方式相同。因此,我们要检查它是否未初始化,然后我们期待实际获得这些数据,期待 in_msg_body 以获得所有者的地址和带有元数据的Cell。但这只能通过 collection_address, 因此我们要检查它是否等于发件人地址。然后我们就可以初始化 NFT Item了。
  1. int op = in_msg_body~load_uint(32);
    $ i# ]. C2 y# r$ S  j
  2.   int query_id = in_msg_body~load_uint(64);/ ~! t4 R+ a" D3 W  Y6 y

  3. 9 d4 Y3 M2 N5 q( W$ w
  4.   if (op == op::transfer()) {7 N0 g' }; a7 ^5 b, P0 |, S8 F
  5.     transfer_ownership(my_balance, index, collection_address, owner_address, content, sender_address, query_id, in_msg_body, fwd_fee);
    1 I. f( `# F: Z
  6.     return ();! r6 A# C. T: H4 O# r* h9 c) r
  7.   }9 `, D: _5 d' T% M) p
  8.   if (op == op::get_static_data()) {% n, G: E) H: A6 N7 F. h0 W/ y9 ?
  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
    ( S2 U) m5 ~4 O+ B
  10.     return ();" z1 ]6 U& s; z8 g
  11.   }
复制代码
接下来是操作代码,可以是 op::transfer 或 op::get_static_data. 这是我们要处理的两个可能值。当我们说 get_static_data, 我们会立即向发送静态数据请求的用户发送一条信息。我们只是报告数据,所以我们会向他发送 index 和 collection_address. 这是 get_static_data 函数。正如你所看到的,这是我们的第一个 send_ msg 用例

2 j$ x0 d0 E% I0 M5 S
  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 {( \4 ~# @1 G2 y; E
  2.     throw_unless(401, equal_slices(sender_address, owner_address));
    . `7 m/ n/ _/ Z0 K

  3. ' F' i) Z) m1 P  o- y
  4.     slice new_owner_address = in_msg_body~load_msg_addr();' q% d. E' R) G9 A2 s
  5.     force_chain(new_owner_address);
    # h2 T/ ?+ w( V+ o" Z# M# }
  6.     slice response_destination = in_msg_body~load_msg_addr();- J% d, ?( t: |; s$ u  W
  7.     in_msg_body~load_int(1); ;; this nft don't use custom_payload/ c9 S/ V, }3 q7 n) v
  8.     int forward_amount = in_msg_body~load_coins();
    8 S% [1 i" h9 J. [
  9.     throw_unless(708, slice_bits(in_msg_body) >= 1);
    8 n0 a8 l) R% a
  10. 4 S( v6 W/ Q5 b, E( ]
  11.     int rest_amount = my_balance - min_tons_for_storage();6 s# E# r# P1 n4 W: y$ m& i0 V; ^
  12.     if (forward_amount) {
    ' g0 ?. S0 R3 r2 F8 \- T* `
  13.       rest_amount -= (forward_amount + fwd_fees);# J2 D( t7 b: ~& m
  14.     }3 @$ `& u9 o, _7 ~  J
  15.     int need_response = response_destination.preload_uint(2) != 0; ;; if NOT addr_none: 003 q9 T4 G1 R- S( P2 {
  16.     if (need_response) {
    1 Z6 ?- J( E( p. M
  17.       rest_amount -= fwd_fees;
    * v; J1 e; X- C- X% A
  18.     }
    0 }) [; X) s1 {  w0 C% X
  19. % F, b5 W0 P9 L7 k# j% e0 W
  20.     throw_unless(402, rest_amount >= 0); ;; base nft spends fixed amount of gas, will not check for response4 v6 w7 t2 N2 \
  21. $ a# [% \2 o  i+ w! G" t/ S
  22.     if (forward_amount) {
    ; k6 h" x) r1 h0 R
  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
    : j$ s' Z9 y$ N  }
  24.     }, R: s4 j$ K$ ?: i! E0 i3 k' p
  25.     if (need_response) {2 w$ \) S4 ]$ G! r- C- p! P& H2 D
  26.       force_chain(response_destination);/ Z1 s; v$ }6 J2 X& ^8 B2 [# t
  27.       send_msg(response_destination, rest_amount, op::excesses(), query_id, null(), 1); ;; paying fees, revert on errors
    . K4 w  E6 H& a  y& s5 g
  28.     }! q7 M& A4 M8 t

  29. * G% k# m5 y* ]! ]
  30.     store_data(index, collection_address, new_owner_address, content);
    3 J2 _% |% H# f7 Q, z3 [; Z
  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 是这里的核心函数之一。您拥有一件物品,有时您会将其所有权转让给其他人或出售,这取决于交易的类型。

  Y( N* u9 l# Q6 _6 Q' d9 b* G
SBT item合约
NFT 可以在另一个层面运作。查看 Getgems (https://getgems.io/) 市场。它们有自己的合约,可以出售这类资产。我们现在不研究这些市场合约。不过,我还是要告诉你一个地方,在那里你可以学到很多关于 NFT 的知识 — GetGems github — 在这里,我还想为大家介绍一种 NFT。
GetGems repository 正在主办一些不同的 NFT 合约、藏品、销售和市场以及一些拍卖活动。这里是了解更多与 NFT 藏品、物品及其相关的合约的好地方。但我想向您展示一份确切的合约,我们可以对其进行深入研究。
sbt-item 是一种灵魂绑定代币(SBT)。灵魂绑定与 NFT 非常相似,但不同之处在于灵魂绑定代币不能擅自转让给其他人。我们仔细看看它的代码。
  1. global int storage::index;
    3 F9 q( P5 Y  b, d2 K8 Q
  2. global int init?;
    ( B- |5 T: |  g/ c0 ]5 }% H- ]
  3. global slice storage::collection_address;
    ( d7 Z5 v: C3 h' P
  4. global slice storage::owner_address;4 N! R# m8 ]1 D9 W1 ?+ H& x2 }6 W
  5. global slice storage::authority_address;
    1 `- }/ Z4 D; ?7 F: W1 U
  6. global cell storage::content;
    & k  B- ~  A* E2 L$ ~" Y  Y
  7. global int storage::revoked_at;- u* J) {6 b* x
  8. () load_data() impure {
    : \7 v$ J0 J! ]7 a3 \6 x. p4 z
  9.     slice ds = get_data().begin_parse();
    , Q5 _: P$ y3 g
  10. 5 U1 b! f3 V1 h+ U
  11.     storage::index              = ds~load_uint(64);: g% Z3 _  A1 o$ R
  12.     storage::collection_address = ds~load_msg_addr();6 G+ S8 J# o  @1 x0 A/ y
  13.     init?                       = false;
    " Z8 S6 [  C; i- g7 T! |; e
  14. $ O+ Q) ^" V: E* V- x
  15.     if (ds.slice_bits() > 0) {
    % v1 G; R1 x( {0 c  a9 `
  16.         init?                      = true;
    4 d$ [: k: j/ ?, h; D1 w2 M% _" \
  17.         storage::owner_address     = ds~load_msg_addr();
    $ l6 x* G: |, B) x5 `7 @% b+ p
  18.         storage::content           = ds~load_ref();" m  u! t- Z# |3 r& y7 H3 a" ~
  19.         storage::authority_address = ds~load_msg_addr();, l/ e& p! i0 {3 G
  20.         storage::revoked_at        = ds~load_uint(64);( [, h- L: |; `( n% T
  21.     }
    , N, J5 i3 G- b* U9 p9 j; \
  22. }
复制代码
这里有一些变量: storage::index, storage::collection_address. 我们还定义了其他全局变量,这只是 GetGems 实现的一个例子。你不必用同样的方法。我想在这里重点谈谈其他部分:

9 n# \& C6 }. H2 m3 _
  1. if (op == op::request_owner()) {
    & p1 k  ~% X( O. h0 w9 Q# w
  2.     slice dest = in_msg_body~load_msg_addr();6 l0 i4 B- o$ @- m3 ~, W0 H! Q
  3.     cell body = in_msg_body~load_ref();
    1 E; p% p' t$ j: A0 u
  4.     int with_content = in_msg_body~load_uint(1);. T5 v% f3 W' L
  5. 3 O* H  z+ a& u1 u) n
  6.     var msg = begin_cell()& P: ]% d( s, _, W' p
  7.             .store_uint(storage::index, 256)
    : B5 a0 K0 V5 [: x+ j% D
  8.             .store_slice(sender_address)
    ( }! @9 [5 Q* k3 I
  9.             .store_slice(storage::owner_address)
    8 y1 T: v3 a6 h* g5 u, e( F
  10.             .store_ref(body)
    $ x% z  w1 Q% I% ~
  11.             .store_uint(storage::revoked_at, 64)
    ( j' G( ]; G+ f
  12.             .store_uint(with_content, 1);0 s6 n7 U. H' K0 O8 S
  13. " n% p7 \' R# E3 R9 |
  14.     if (with_content != 0) {0 Y" l; T+ @0 j: p5 [/ I. f
  15.         msg = msg.store_ref(storage::content);; I: i) k, Y, a. `0 W! o1 s
  16.     }, y; g- ?6 O' z4 @: j7 h

  17. % {: J$ F9 z. o4 N% i
  18.     ;; mode 64 = carry all the remaining value of the inbound message
    ! J+ i" v+ ^; \1 L1 g( G
  19.     send_msg(flag::regular() | flag::bounce(), dest, 0, op::owner_info(), query_id, msg, 64);
    1 H6 a! _# W  e( v; ^7 q
  20.     return ();, b9 X( j, m, L, W, _
  21. }' m1 }: E' d; s- g
  22. if (op == op::prove_ownership()) {
    - i4 b* i. F4 Y/ ^* L
  23.     throw_unless(401, equal_slices(storage::owner_address, sender_address));9 r6 Q, l6 H# t
  24. , O/ g7 \' ?" k2 D+ G9 Y4 X
  25.     slice dest = in_msg_body~load_msg_addr();1 A2 _' ]+ D6 d: G# B* X
  26.     cell body = in_msg_body~load_ref();! T4 g7 p- |  G9 T9 K
  27.     int with_content = in_msg_body~load_uint(1);
    + V& {% }" R: L* t
  28. 7 B3 `! Z5 B1 ^
  29.     var msg = begin_cell()
    + y( `% \( X" Q5 {' w, @
  30.             .store_uint(storage::index, 256), Y% _/ a$ [* ^6 `
  31.             .store_slice(storage::owner_address)4 J, i5 A0 o; g' n5 Z, O
  32.             .store_ref(body)8 n% y4 L" {* ?) C
  33.             .store_uint(storage::revoked_at, 64)- c3 G+ Q  A; e
  34.             .store_uint(with_content, 1);8 I/ T6 G  B7 q! L, m9 [2 `
  35. # V# J  y% Q( _) R4 ]& d- Y3 V5 R
  36.     if (with_content != 0) {
    % c, c' B7 Q' {7 x* L5 P
  37.         msg = msg.store_ref(storage::content);( h! j8 E2 m8 q9 L( D
  38.     }( z1 [  s, ^$ D# e
  39. 0 [2 y) h& }7 Y- q; z* r
  40.     ;; mode 64 = carry all the remaining value of the inbound message
    0 P8 h# w* T# [) O) W+ W
  41.     send_msg(flag::regular() | flag::bounce(), dest, 0, op::ownership_proof(), query_id, msg, 64);
    $ x, C  o; T6 \4 E+ h
  42.     return ();
    ( M4 x+ A& Y! @
  43. }8 J! e( x* U' a2 d
  44. if (op == op::get_static_data()) {
    2 q! M4 {6 V- X$ ^
  45.     var msg = begin_cell().store_uint(storage::index, 256).store_slice(storage::collection_address);5 N4 q( c% ~; ^) ?: N  E+ {

  46. 5 n( y1 H4 y' L2 Q: Y3 d  V
  47.     ;; mode 64 = carry all the remaining value of the inbound message1 Z4 ^4 W& w; i, n0 ^# q+ i
  48.     send_msg(flag::regular(), sender_address, 0, op::report_static_data(), query_id, msg, 64);4 v) i# {2 i3 Q9 Y6 T. ^( j0 h
  49.     return ();
    % R4 h( w/ ^$ c* {. }
  50. }  V- K% _2 L( z' `6 y4 f' e" Y
  51. if (op == op::destroy()) {/ P* X3 `6 b, @! Y5 [' q
  52.     throw_unless(401, equal_slices(storage::owner_address, sender_address));
    # z, ?+ q" s1 g2 w: `$ g  E4 l7 Y
  53. 3 q: e) C0 w: t7 E7 _
  54.     send_msg(flag::regular(), sender_address, 0, op::excesses(), query_id, null(), 128);/ u6 S/ a' I; ]

  55. , Z, E9 Y% `6 }# m) h. {4 ^
  56.     storage::owner_address = null_addr();* @! R8 K2 M, w! q
  57.     storage::authority_address = null_addr();: k; S; P' @0 p
  58.     store_data();
      L2 B: f3 v" F, K
  59.     return ();
    ; s+ j) i; L0 A: Q; z
  60. }
    3 D% R7 w4 S6 P  [
  61. if (op == op::revoke()) {
    & Y" x* a1 ~2 t5 o5 J  j
  62.     throw_unless(401, equal_slices(storage::authority_address, sender_address));9 }/ s/ ^2 c! a; i, Q. V* D5 Q) ?
  63.     throw_unless(403, storage::revoked_at == 0);
    $ P5 o0 T' ~& T3 M; X  \+ P
  64. - f7 e9 r2 k9 ]8 z* H
  65.     storage::revoked_at = now();$ @  V% L% J9 y8 [, @
  66.     store_data();
    9 u) X" Q- u7 E& C/ r6 o3 M
  67.     return ();; b; w/ O! ?  h: u! L
  68. }4 C' E- Y& ?0 v; f
  69. if (op == op::take_excess()) {
    . @/ S9 F& P9 n0 t  A3 Z8 z* {' w/ d! X
  70.     throw_unless(401, equal_slices(storage::owner_address, sender_address));- A2 }- A* k/ K4 J' t1 ~
  71. # y  `% K1 y, j- r2 S
  72.     ;; reserve amount for storage
    + I0 d( o4 e4 k) N0 a: T, [$ w
  73.     raw_reserve(min_tons_for_storage(), 0);. y/ N3 t* f: m  ?4 O

  74. 9 U( q8 F  n) N! {9 ?6 t5 C
  75.     send_msg(flag::regular(), sender_address, 0, op::excesses(), query_id, null(), 128);
    # `( P( @& `' k$ n
  76.     return ();& q/ f% m; e& j5 h8 {) v  v, ~  Y
  77. }
    7 d& C& T/ O7 E% q* _& U6 f
  78. if (op == op::transfer()) {, h/ w8 d2 j! ?+ s$ _1 O' v1 W$ d
  79.     throw(413);
    2 T, L- \, ?; P: |: ~# Y
  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 {+ }8 w4 N/ {' E% j3 {/ m6 l( b
  2.   var ds = get_data().begin_parse();
    ' I; T7 G2 C6 d! {/ b1 d
  3.   return 0 v. `% U+ w# s, c2 z
  4.     (ds~load_msg_addr(), ;; owner_address
    & p% Y# d, \7 s$ v+ _
  5.      ds~load_uint(64), ;; next_item_index2 H& H& z9 W5 j* w; g$ S
  6.      ds~load_ref(), ;; content
    - ]( u0 b4 Z, n7 B
  7.      ds~load_ref(), ;; nft_item_code
    0 I% E) n( L' j9 X
  8.      ds~load_ref()  ;; royalty_params
    - s9 u" t2 c: ]; `" z# g; h/ y
  9.      );
    ) U6 A3 ?* ?5 E9 \
  10. }
复制代码
这样,您就可以实际部署 SBT item collection。此外,您还可以创建一个独立的没有collection SBT item。我们不会掌握这些item的编程,我只是想向大家展示它在更大范围内的工作原理。

; p5 V9 o+ S- ^+ I; F1 Z2 `2 h
结论
1 p3 q5 e( V5 g5 x6 p
从第 3 章中非常简单的逻辑开始,我们已经了解了 NFT 或 Jettons 等复杂合约中的许多内容。这就是一个很好的例子,你可以一步一步地学习某些语法和概念,然后就可以学习更复杂的逻辑。希望这几节课能帮助你理解 Jettons 和 NFTs 的真正含义,以及如何处理它们的代码库--弄清楚它们是如何工作的,并在使用 TON 构建时学习更多可用的语法和架构。
非常感谢您的关注。对你们来说,这可能是最难的一章,虽然我们没有编写任何代码;我们只是在阅读一些你们从未见过的东西,而且非常复杂。你们能坚持到最后一课,我真的很骄傲,我期待着在接下来的章节中看到你们。希望你们喜欢目前的课程。
0 N$ a2 H( M& P7 f

- ]' e+ d! ^  N9 m  P. x$ X8 h3 d1 P/ n; z
" D* Q" l/ _, E' l5 E

8 T2 I2 U( W8 m4 W' x3 N8 V% E* f  M

: ^# a$ Q2 k6 S
5 f' M+ b; a. l' c8 W3 F) k
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则