From 9c4b7834d088cc5f1bc3db24a23bc91b3eab6800 Mon Sep 17 00:00:00 2001 From: skywardboundd Date: Fri, 26 Sep 2025 22:03:20 +0300 Subject: [PATCH 01/14] sbt-how-it-works --- standard/tokens/sbt/how-works.mdx | 133 ++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) diff --git a/standard/tokens/sbt/how-works.mdx b/standard/tokens/sbt/how-works.mdx index e69de29b..b746de57 100644 --- a/standard/tokens/sbt/how-works.mdx +++ b/standard/tokens/sbt/how-works.mdx @@ -0,0 +1,133 @@ +--- +title: "SBT: How it works" +sidebarTitle: "How it works" +--- + +SBT is like an NFT but without transfers. The `owner` is set at mint time and never changes. Below is a simple explanation of the key operations and their message flows. + +## 1) Prove ownership — `prove_ownership` + +Allows the `owner` to ask the SBT to send a proof to a target contract confirming that they own this SBT. You may include arbitrary `forward_payload` and optionally attach `content`. + +```tlb title="TL-B" +;; Inbound message to SBT +prove_ownership#04ded148 query_id:uint64 dest:MsgAddress + forward_payload:^Cell with_content:Bool = InternalMsgBody; + +;; SBT response to the target contract (if checks pass) +ownership_proof#0524c7ae query_id:uint64 item_id:uint256 owner:MsgAddress + data:^Cell revoked_at:uint64 content:(Maybe ^Cell) = InternalMsgBody; +``` + +- `query_id`: arbitrary request identifier +- `dest`: address of the target contract to prove ownership to +- `forward_payload`: arbitrary data for the target contract +- `with_content`: if `true`, attach SBT `content` +- `revoked_at`: revoke time if SBT is revoked, `0` otherwise + +Rejected if the sender is not the `owner`. + +```mermaid +sequenceDiagram + participant U as Owner + participant S as SBT + participant D as dest (target contract) + + U->>S: prove_ownership(query_id, dest, forward_payload, with_content) + alt U == owner + S->>D: ownership_proof(query_id, item_id, owner, data, revoked_at, content?) + else not owner + S-->>U: reject + end +``` + +## 2) Request current owner — `request_owner` + +Any initiator may ask the SBT to send the current `owner` (and optionally the `content`) to a target contract. + +```tlb title="TL-B" +;; Inbound message to SBT +request_owner#d0c3bfea query_id:uint64 dest:MsgAddress + forward_payload:^Cell with_content:Bool = InternalMsgBody; + +;; SBT response to the target contract +owner_info#0dd607e3 query_id:uint64 item_id:uint256 initiator:MsgAddress owner:MsgAddress + data:^Cell revoked_at:uint64 content:(Maybe ^Cell) = InternalMsgBody; +``` + +- `initiator`: address of the requester +- Other fields mirror `prove_ownership` + +```mermaid +sequenceDiagram + participant I as Initiator + participant S as SBT + participant D as dest (target contract) + + I->>S: request_owner(query_id, dest, forward_payload, with_content) + S->>D: owner_info(query_id, item_id, initiator, owner, data, revoked_at, content?) +``` + +## 3) Destroy the contract — `destroy` + +The `owner` can destroy the SBT contract. This clears the `owner` and `authority` fields, and sends remaining balance back to the sender via an `excesses` message. + +```tlb title="TL-B" +;; Internal message to SBT +destroy#1f04537a query_id:uint64 = InternalMsgBody; + +;; Excess returned to the sender +excesses#d53276db query_id:uint64 = InternalMsgBody; +``` + +Rejected if the sender is not the `owner`. + +```mermaid +sequenceDiagram + participant U as Owner + participant S as SBT + + U->>S: destroy(query_id) + alt U == owner + S->>S: owner = null, authority = null + S-->>U: excesses(query_id) + else not owner + S-->>U: reject + end +``` + +## 4) Revoke SBT — `revoke` + +The `authority` can mark the SBT as revoked. Double-revoke is disallowed. + +```tlb title="TL-B" +;; Inbound message to SBT +revoke#6f89f5e3 query_id:uint64 = InternalMsgBody; +``` + +Rejected if: +- the sender is not the `authority`; +- the SBT was already revoked. + +```mermaid +sequenceDiagram + participant A as Authority + participant S as SBT + + A->>S: revoke(query_id) + alt A == authority and not revoked + S->>S: revoked_at = now + else not authority or already revoked + S-->>A: reject + end +``` + +--- + +### Quick field reference + +- `item_id`: identifier of the SBT item (analogous to an NFT item) +- `owner`: current owner +- `authority`: the address allowed to revoke the SBT +- `content`: SBT content (may be attached optionally) +- `revoked_at`: Unix timestamp of revoke (`0` means not revoked) From ea56e4b24dc2c583dba4e4cf34bf89a9e9ed3a02 Mon Sep 17 00:00:00 2001 From: skywardboundd Date: Fri, 26 Sep 2025 22:09:29 +0300 Subject: [PATCH 02/14] review --- standard/tokens/sbt/how-works.mdx | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/standard/tokens/sbt/how-works.mdx b/standard/tokens/sbt/how-works.mdx index b746de57..b2dc9d2d 100644 --- a/standard/tokens/sbt/how-works.mdx +++ b/standard/tokens/sbt/how-works.mdx @@ -3,9 +3,12 @@ title: "SBT: How it works" sidebarTitle: "How it works" --- -SBT is like an NFT but without transfers. The `owner` is set at mint time and never changes. Below is a simple explanation of the key operations and their message flows. +SBT is like an NFT but with several differences. -## 1) Prove ownership — `prove_ownership` +## 1) Without transfer +The `owner` is set at mint time and never changes. Below is a simple explanation of the key operations and their message flows. + +## 2) Prove ownership — `prove_ownership` Allows the `owner` to ask the SBT to send a proof to a target contract confirming that they own this SBT. You may include arbitrary `forward_payload` and optionally attach `content`. @@ -41,7 +44,7 @@ sequenceDiagram end ``` -## 2) Request current owner — `request_owner` +## 3) Request current owner — `request_owner` Any initiator may ask the SBT to send the current `owner` (and optionally the `content`) to a target contract. @@ -68,7 +71,7 @@ sequenceDiagram S->>D: owner_info(query_id, item_id, initiator, owner, data, revoked_at, content?) ``` -## 3) Destroy the contract — `destroy` +## 4) Destroy the contract — `destroy` The `owner` can destroy the SBT contract. This clears the `owner` and `authority` fields, and sends remaining balance back to the sender via an `excesses` message. @@ -96,7 +99,7 @@ sequenceDiagram end ``` -## 4) Revoke SBT — `revoke` +## 5) Revoke SBT — `revoke` The `authority` can mark the SBT as revoked. Double-revoke is disallowed. @@ -131,3 +134,6 @@ sequenceDiagram - `authority`: the address allowed to revoke the SBT - `content`: SBT content (may be attached optionally) - `revoked_at`: Unix timestamp of revoke (`0` means not revoked) + +See more: +- SBT Standard [TEP-85](https://github.com/ton-blockchain/TEPs/blob/c5bfe285ef91810fab02c5352593f5a1455458bf/text/0085-sbt-standard.md) From c463b67218ea6c8b1fef736d57b0e96bf4cf8716 Mon Sep 17 00:00:00 2001 From: skywardboundd Date: Fri, 26 Sep 2025 22:10:23 +0300 Subject: [PATCH 03/14] review --- standard/tokens/sbt/how-works.mdx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/standard/tokens/sbt/how-works.mdx b/standard/tokens/sbt/how-works.mdx index b2dc9d2d..d16a451f 100644 --- a/standard/tokens/sbt/how-works.mdx +++ b/standard/tokens/sbt/how-works.mdx @@ -5,10 +5,10 @@ sidebarTitle: "How it works" SBT is like an NFT but with several differences. -## 1) Without transfer +## Without transfer The `owner` is set at mint time and never changes. Below is a simple explanation of the key operations and their message flows. -## 2) Prove ownership — `prove_ownership` +## Prove ownership — `prove_ownership` Allows the `owner` to ask the SBT to send a proof to a target contract confirming that they own this SBT. You may include arbitrary `forward_payload` and optionally attach `content`. @@ -44,7 +44,7 @@ sequenceDiagram end ``` -## 3) Request current owner — `request_owner` +## Request current owner — `request_owner` Any initiator may ask the SBT to send the current `owner` (and optionally the `content`) to a target contract. @@ -71,7 +71,7 @@ sequenceDiagram S->>D: owner_info(query_id, item_id, initiator, owner, data, revoked_at, content?) ``` -## 4) Destroy the contract — `destroy` +## Destroy the contract — `destroy` The `owner` can destroy the SBT contract. This clears the `owner` and `authority` fields, and sends remaining balance back to the sender via an `excesses` message. @@ -99,7 +99,7 @@ sequenceDiagram end ``` -## 5) Revoke SBT — `revoke` +## Revoke SBT — `revoke` The `authority` can mark the SBT as revoked. Double-revoke is disallowed. From 754434a7f671e84763186073a14ecba6ff6f7cb8 Mon Sep 17 00:00:00 2001 From: skywardboundd Date: Fri, 26 Sep 2025 22:10:56 +0300 Subject: [PATCH 04/14] fix --- standard/tokens/sbt/how-works.mdx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/standard/tokens/sbt/how-works.mdx b/standard/tokens/sbt/how-works.mdx index d16a451f..98451e79 100644 --- a/standard/tokens/sbt/how-works.mdx +++ b/standard/tokens/sbt/how-works.mdx @@ -8,7 +8,7 @@ SBT is like an NFT but with several differences. ## Without transfer The `owner` is set at mint time and never changes. Below is a simple explanation of the key operations and their message flows. -## Prove ownership — `prove_ownership` +## Prove ownership Allows the `owner` to ask the SBT to send a proof to a target contract confirming that they own this SBT. You may include arbitrary `forward_payload` and optionally attach `content`. @@ -44,7 +44,7 @@ sequenceDiagram end ``` -## Request current owner — `request_owner` +## Request current owner Any initiator may ask the SBT to send the current `owner` (and optionally the `content`) to a target contract. @@ -71,7 +71,7 @@ sequenceDiagram S->>D: owner_info(query_id, item_id, initiator, owner, data, revoked_at, content?) ``` -## Destroy the contract — `destroy` +## Destroy the contract The `owner` can destroy the SBT contract. This clears the `owner` and `authority` fields, and sends remaining balance back to the sender via an `excesses` message. @@ -99,7 +99,7 @@ sequenceDiagram end ``` -## Revoke SBT — `revoke` +## Revoke SBT The `authority` can mark the SBT as revoked. Double-revoke is disallowed. From ad34e9844f5f30b56f2376cccab59255dac87373 Mon Sep 17 00:00:00 2001 From: skywardboundd Date: Sun, 12 Oct 2025 14:47:57 +0300 Subject: [PATCH 05/14] review --- docs.json | 2 +- standard/tokens/sbt/how-it-works.mdx | 194 +++++++++++++++++++++++++++ standard/tokens/sbt/how-works.mdx | 139 ------------------- 3 files changed, 195 insertions(+), 140 deletions(-) create mode 100644 standard/tokens/sbt/how-it-works.mdx delete mode 100644 standard/tokens/sbt/how-works.mdx diff --git a/docs.json b/docs.json index 4ffb14f7..67a4c436 100644 --- a/docs.json +++ b/docs.json @@ -321,7 +321,7 @@ "group": "SBT", "pages": [ "standard/tokens/sbt/overview", - "standard/tokens/sbt/how-works" + "standard/tokens/sbt/how-it-works" ] }, "standard/tokens/airdrop" diff --git a/standard/tokens/sbt/how-it-works.mdx b/standard/tokens/sbt/how-it-works.mdx new file mode 100644 index 00000000..1ea8f9e3 --- /dev/null +++ b/standard/tokens/sbt/how-it-works.mdx @@ -0,0 +1,194 @@ +--- +title: "SBT: How it works" +sidebarTitle: "How it works" +--- + +SBT is a variation of an NFT Item, but has some differences. + +SBT standards provide only a general scheme of interaction, leaving the specific implementation of related contracts to developers. + +**Nota bene: in all schemes below you will see the `query id` field. Nowadays the field is almost deprecated, and protocols itself doesn't need it. +It is mostly used for easier off-chain parsing and other web2 processing**. + +## Bound to single owner +The `owner` is set at mint time and never changes. Below is a simple explanation of the key operations and their message flows. + +## Prove ownership + +Allows the `owner` to ask the SBT to send a proof to a target contract confirming that they own this SBT. You may include arbitrary `forward_payload` and optionally attach `content`. + +```tlb title="TL-B" +;; Inbound message to SBT +prove_ownership#04ded148 query_id:uint64 dest:MsgAddress + forward_payload:^Cell with_content:Bool = InternalMsgBody; + +;; SBT response to the target contract (if checks pass) +ownership_proof#0524c7ae query_id:uint64 item_id:uint256 owner:MsgAddress + data:^Cell revoked_at:uint64 content:(Maybe ^Cell) = InternalMsgBody; +``` + +`Inbound to SBT`. Prove ownership message contains the following data: + +| Name | Type | Description | +| ----------------- | -------- | ------------------------------------------------------------- | +| `query_id` | uint64 | Links the request `prove_ownership` and the response `ownership_proof` to each other. To ensure this process works correctly, always use a unique query ID. | +| `dest` | MsgAddress | Address of the target contract to receive the proof. | +| `forward_payload` | Cell | Arbitrary data forwarded to the target contract. | +| `with_content` | Bool | If `true`, attach SBT `content`. | + +`SBT -> dest (target contract)`. Ownership proof message contains the following data: + +| Name | Type | Description | +| ------------ | ---------- | --------------------------------------------------------- | +| `query_id` | uint64 | Links the request `prove_ownership` and this `ownership_proof` response to each other. To ensure this process works correctly, always use a unique query ID. | +| `item_id` | uint256 | Identifier of the SBT item. | +| `owner` | MsgAddress | Current owner address. | +| `data` | Cell | Custom data forwarded to the target contract. | +| `revoked_at` | uint64 | Revoke time if SBT is revoked, `0` otherwise. | +| `content` | maybe Cell | SBT content if it was requested with `with_content=true`. | + +Rejected if the sender is not the `owner`. + +```mermaid +sequenceDiagram + participant U as Owner + participant S as SBT + participant D as dest (target contract) + + U->>S: prove_ownership + alt U == owner + S->>D: ownership_proof + else not owner + S-->>U: reject + end +``` + +## Request current owner + +Any initiator may ask the SBT to send the current `owner` (and optionally the `content`) to a target contract. + +```tlb title="TL-B" +;; Inbound message to SBT +request_owner#d0c3bfea query_id:uint64 dest:MsgAddress + forward_payload:^Cell with_content:Bool = InternalMsgBody; + +;; SBT response to the target contract +owner_info#0dd607e3 query_id:uint64 item_id:uint256 initiator:MsgAddress owner:MsgAddress + data:^Cell revoked_at:uint64 content:(Maybe ^Cell) = InternalMsgBody; +``` + +`Inbound to SBT`. Request owner message contains the following data: + +| Name | Type | Description | +| ----------------- | ---------- | ------------------------------------------------------------- | +| `query_id` | uint64 | Links the request `request_owner` and the response `owner_info` to each other. To ensure this process works correctly, always use a unique query ID. | +| `dest` | MsgAddress | Address of the target contract to receive the response. | +| `forward_payload` | Cell | Arbitrary data forwarded to the target contract. | +| `with_content` | Bool | If `true`, attach SBT `content` in the response. | + +`SBT -> dest (target contract)`. Owner info message contains the following data: + +| Name | Type | Description | +| ------------ | ---------- | ----------------------------------------- | +| `query_id` | uint64 | Links the request `request_owner` and this `owner_info` response to each other. To ensure this process works correctly, always use a unique query ID. | +| `item_id` | uint256 | Identifier of the SBT item. | +| `initiator` | MsgAddress | Address of the requester. | +| `owner` | MsgAddress | Current owner address. | +| `data` | Cell | Custom data forwarded to the target, equals to `forward_payload`. | +| `revoked_at` | uint64 | Revoke time if revoked, `0` otherwise. | +| `content` | maybe Cell | SBT content if it was requested. | + +```mermaid +sequenceDiagram + participant I as Initiator + participant S as SBT + participant D as dest (target contract) + + I->>S: request_owner + S->>D: owner_info +``` + +## Destroy + +The `owner` can destroy the SBT contract. This clears the `owner` and `authority` fields, and sends remaining balance back to the sender via an `excesses` message. + +```tlb title="TL-B" +;; Internal message to SBT +destroy#1f04537a query_id:uint64 = InternalMsgBody; + +;; Excess returned to the sender +excesses#d53276db query_id:uint64 = InternalMsgBody; +``` + +`Inbound to SBT`. Destroy message contains the following data: + +| Name | Type | Description | +| ----------- | ------ | ------------------------------------ | +| `query_id` | uint64 | Links the request `destroy` and the response `excesses` to each other. To ensure this process works correctly, always use a unique query ID. | + +`SBT -> sender`. Excesses message contains the following data: + +| Name | Type | Description | +| ---------- | ------ | ------------------------------------ | +| `query_id` | uint64 | Links the request `destroy` and this `excesses` response to each other. To ensure this process works correctly, always use a unique query ID. | + +Rejected if the sender is not the `owner`. + +```mermaid +sequenceDiagram + participant U as Owner + participant S as SBT + + U->>S: destroy(query_id) + alt U == owner + S->>S: owner = null, authority = null + S-->>U: excesses(query_id) + else not owner + S-->>U: reject + end +``` + +## Revoke SBT + +The `authority` can mark the SBT as revoked. Revoking twice is disallowed. + +```tlb title="TL-B" +;; Inbound message to SBT +revoke#6f89f5e3 query_id:uint64 = InternalMsgBody; +``` + +`Inbound to SBT`. Revoke message contains the following data: + +| Name | Type | Description | +| ---------- | ------ | ------------------------------------ | +| `query_id` | uint64 | Identifies the `revoke` request for off-chain parsing. To ensure this process works correctly, always use a unique query ID. | + +Rejected if: +- the sender is not the `authority`; +- the SBT was already revoked. + +```mermaid +sequenceDiagram + participant A as Authority + participant S as SBT + + A->>S: revoke(query_id) + alt A == authority and not revoked + S->>S: revoked_at = now + else not authority or already revoked + S-->>A: reject + end +``` + +--- + +### Quick field reference + +- `item_id`: identifier of the SBT item (analogous to an NFT item) +- `owner`: current owner +- `authority`: the address allowed to revoke the SBT +- `content`: SBT content (may be attached optionally) +- `revoked_at`: Unix timestamp of revoke (`0` means not revoked) + +See more: +- SBT Standard [TEP-85](https://github.com/ton-blockchain/TEPs/blob/c5bfe285ef91810fab02c5352593f5a1455458bf/text/0085-sbt-standard.md) diff --git a/standard/tokens/sbt/how-works.mdx b/standard/tokens/sbt/how-works.mdx deleted file mode 100644 index 98451e79..00000000 --- a/standard/tokens/sbt/how-works.mdx +++ /dev/null @@ -1,139 +0,0 @@ ---- -title: "SBT: How it works" -sidebarTitle: "How it works" ---- - -SBT is like an NFT but with several differences. - -## Without transfer -The `owner` is set at mint time and never changes. Below is a simple explanation of the key operations and their message flows. - -## Prove ownership - -Allows the `owner` to ask the SBT to send a proof to a target contract confirming that they own this SBT. You may include arbitrary `forward_payload` and optionally attach `content`. - -```tlb title="TL-B" -;; Inbound message to SBT -prove_ownership#04ded148 query_id:uint64 dest:MsgAddress - forward_payload:^Cell with_content:Bool = InternalMsgBody; - -;; SBT response to the target contract (if checks pass) -ownership_proof#0524c7ae query_id:uint64 item_id:uint256 owner:MsgAddress - data:^Cell revoked_at:uint64 content:(Maybe ^Cell) = InternalMsgBody; -``` - -- `query_id`: arbitrary request identifier -- `dest`: address of the target contract to prove ownership to -- `forward_payload`: arbitrary data for the target contract -- `with_content`: if `true`, attach SBT `content` -- `revoked_at`: revoke time if SBT is revoked, `0` otherwise - -Rejected if the sender is not the `owner`. - -```mermaid -sequenceDiagram - participant U as Owner - participant S as SBT - participant D as dest (target contract) - - U->>S: prove_ownership(query_id, dest, forward_payload, with_content) - alt U == owner - S->>D: ownership_proof(query_id, item_id, owner, data, revoked_at, content?) - else not owner - S-->>U: reject - end -``` - -## Request current owner - -Any initiator may ask the SBT to send the current `owner` (and optionally the `content`) to a target contract. - -```tlb title="TL-B" -;; Inbound message to SBT -request_owner#d0c3bfea query_id:uint64 dest:MsgAddress - forward_payload:^Cell with_content:Bool = InternalMsgBody; - -;; SBT response to the target contract -owner_info#0dd607e3 query_id:uint64 item_id:uint256 initiator:MsgAddress owner:MsgAddress - data:^Cell revoked_at:uint64 content:(Maybe ^Cell) = InternalMsgBody; -``` - -- `initiator`: address of the requester -- Other fields mirror `prove_ownership` - -```mermaid -sequenceDiagram - participant I as Initiator - participant S as SBT - participant D as dest (target contract) - - I->>S: request_owner(query_id, dest, forward_payload, with_content) - S->>D: owner_info(query_id, item_id, initiator, owner, data, revoked_at, content?) -``` - -## Destroy the contract - -The `owner` can destroy the SBT contract. This clears the `owner` and `authority` fields, and sends remaining balance back to the sender via an `excesses` message. - -```tlb title="TL-B" -;; Internal message to SBT -destroy#1f04537a query_id:uint64 = InternalMsgBody; - -;; Excess returned to the sender -excesses#d53276db query_id:uint64 = InternalMsgBody; -``` - -Rejected if the sender is not the `owner`. - -```mermaid -sequenceDiagram - participant U as Owner - participant S as SBT - - U->>S: destroy(query_id) - alt U == owner - S->>S: owner = null, authority = null - S-->>U: excesses(query_id) - else not owner - S-->>U: reject - end -``` - -## Revoke SBT - -The `authority` can mark the SBT as revoked. Double-revoke is disallowed. - -```tlb title="TL-B" -;; Inbound message to SBT -revoke#6f89f5e3 query_id:uint64 = InternalMsgBody; -``` - -Rejected if: -- the sender is not the `authority`; -- the SBT was already revoked. - -```mermaid -sequenceDiagram - participant A as Authority - participant S as SBT - - A->>S: revoke(query_id) - alt A == authority and not revoked - S->>S: revoked_at = now - else not authority or already revoked - S-->>A: reject - end -``` - ---- - -### Quick field reference - -- `item_id`: identifier of the SBT item (analogous to an NFT item) -- `owner`: current owner -- `authority`: the address allowed to revoke the SBT -- `content`: SBT content (may be attached optionally) -- `revoked_at`: Unix timestamp of revoke (`0` means not revoked) - -See more: -- SBT Standard [TEP-85](https://github.com/ton-blockchain/TEPs/blob/c5bfe285ef91810fab02c5352593f5a1455458bf/text/0085-sbt-standard.md) From 0dfaccadeb411330883f00f7f51f6036ff6d56e7 Mon Sep 17 00:00:00 2001 From: skywardboundd Date: Sun, 12 Oct 2025 14:49:32 +0300 Subject: [PATCH 06/14] fmt --- standard/tokens/sbt/how-it-works.mdx | 71 +++++++++++++++------------- 1 file changed, 37 insertions(+), 34 deletions(-) diff --git a/standard/tokens/sbt/how-it-works.mdx b/standard/tokens/sbt/how-it-works.mdx index 1ea8f9e3..157bd656 100644 --- a/standard/tokens/sbt/how-it-works.mdx +++ b/standard/tokens/sbt/how-it-works.mdx @@ -10,7 +10,8 @@ SBT standards provide only a general scheme of interaction, leaving the specific **Nota bene: in all schemes below you will see the `query id` field. Nowadays the field is almost deprecated, and protocols itself doesn't need it. It is mostly used for easier off-chain parsing and other web2 processing**. -## Bound to single owner +## Bound to single owner + The `owner` is set at mint time and never changes. Below is a simple explanation of the key operations and their message flows. ## Prove ownership @@ -29,23 +30,23 @@ ownership_proof#0524c7ae query_id:uint64 item_id:uint256 owner:MsgAddress `Inbound to SBT`. Prove ownership message contains the following data: -| Name | Type | Description | -| ----------------- | -------- | ------------------------------------------------------------- | -| `query_id` | uint64 | Links the request `prove_ownership` and the response `ownership_proof` to each other. To ensure this process works correctly, always use a unique query ID. | -| `dest` | MsgAddress | Address of the target contract to receive the proof. | -| `forward_payload` | Cell | Arbitrary data forwarded to the target contract. | -| `with_content` | Bool | If `true`, attach SBT `content`. | +| Name | Type | Description | +| ----------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `query_id` | uint64 | Links the request `prove_ownership` and the response `ownership_proof` to each other. To ensure this process works correctly, always use a unique query ID. | +| `dest` | MsgAddress | Address of the target contract to receive the proof. | +| `forward_payload` | Cell | Arbitrary data forwarded to the target contract. | +| `with_content` | Bool | If `true`, attach SBT `content`. | `SBT -> dest (target contract)`. Ownership proof message contains the following data: -| Name | Type | Description | -| ------------ | ---------- | --------------------------------------------------------- | +| Name | Type | Description | +| ------------ | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `query_id` | uint64 | Links the request `prove_ownership` and this `ownership_proof` response to each other. To ensure this process works correctly, always use a unique query ID. | -| `item_id` | uint256 | Identifier of the SBT item. | -| `owner` | MsgAddress | Current owner address. | -| `data` | Cell | Custom data forwarded to the target contract. | -| `revoked_at` | uint64 | Revoke time if SBT is revoked, `0` otherwise. | -| `content` | maybe Cell | SBT content if it was requested with `with_content=true`. | +| `item_id` | uint256 | Identifier of the SBT item. | +| `owner` | MsgAddress | Current owner address. | +| `data` | Cell | Custom data forwarded to the target contract. | +| `revoked_at` | uint64 | Revoke time if SBT is revoked, `0` otherwise. | +| `content` | maybe Cell | SBT content if it was requested with `with_content=true`. | Rejected if the sender is not the `owner`. @@ -79,24 +80,24 @@ owner_info#0dd607e3 query_id:uint64 item_id:uint256 initiator:MsgAddress owner:M `Inbound to SBT`. Request owner message contains the following data: -| Name | Type | Description | -| ----------------- | ---------- | ------------------------------------------------------------- | +| Name | Type | Description | +| ----------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | `query_id` | uint64 | Links the request `request_owner` and the response `owner_info` to each other. To ensure this process works correctly, always use a unique query ID. | -| `dest` | MsgAddress | Address of the target contract to receive the response. | -| `forward_payload` | Cell | Arbitrary data forwarded to the target contract. | -| `with_content` | Bool | If `true`, attach SBT `content` in the response. | +| `dest` | MsgAddress | Address of the target contract to receive the response. | +| `forward_payload` | Cell | Arbitrary data forwarded to the target contract. | +| `with_content` | Bool | If `true`, attach SBT `content` in the response. | `SBT -> dest (target contract)`. Owner info message contains the following data: -| Name | Type | Description | -| ------------ | ---------- | ----------------------------------------- | +| Name | Type | Description | +| ------------ | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | | `query_id` | uint64 | Links the request `request_owner` and this `owner_info` response to each other. To ensure this process works correctly, always use a unique query ID. | -| `item_id` | uint256 | Identifier of the SBT item. | -| `initiator` | MsgAddress | Address of the requester. | -| `owner` | MsgAddress | Current owner address. | -| `data` | Cell | Custom data forwarded to the target, equals to `forward_payload`. | -| `revoked_at` | uint64 | Revoke time if revoked, `0` otherwise. | -| `content` | maybe Cell | SBT content if it was requested. | +| `item_id` | uint256 | Identifier of the SBT item. | +| `initiator` | MsgAddress | Address of the requester. | +| `owner` | MsgAddress | Current owner address. | +| `data` | Cell | Custom data forwarded to the target, equals to `forward_payload`. | +| `revoked_at` | uint64 | Revoke time if revoked, `0` otherwise. | +| `content` | maybe Cell | SBT content if it was requested. | ```mermaid sequenceDiagram @@ -122,14 +123,14 @@ excesses#d53276db query_id:uint64 = InternalMsgBody; `Inbound to SBT`. Destroy message contains the following data: -| Name | Type | Description | -| ----------- | ------ | ------------------------------------ | -| `query_id` | uint64 | Links the request `destroy` and the response `excesses` to each other. To ensure this process works correctly, always use a unique query ID. | +| Name | Type | Description | +| ---------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------- | +| `query_id` | uint64 | Links the request `destroy` and the response `excesses` to each other. To ensure this process works correctly, always use a unique query ID. | `SBT -> sender`. Excesses message contains the following data: -| Name | Type | Description | -| ---------- | ------ | ------------------------------------ | +| Name | Type | Description | +| ---------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------- | | `query_id` | uint64 | Links the request `destroy` and this `excesses` response to each other. To ensure this process works correctly, always use a unique query ID. | Rejected if the sender is not the `owner`. @@ -159,11 +160,12 @@ revoke#6f89f5e3 query_id:uint64 = InternalMsgBody; `Inbound to SBT`. Revoke message contains the following data: -| Name | Type | Description | -| ---------- | ------ | ------------------------------------ | +| Name | Type | Description | +| ---------- | ------ | ---------------------------------------------------------------------------------------------------------------------------- | | `query_id` | uint64 | Identifies the `revoke` request for off-chain parsing. To ensure this process works correctly, always use a unique query ID. | Rejected if: + - the sender is not the `authority`; - the SBT was already revoked. @@ -191,4 +193,5 @@ sequenceDiagram - `revoked_at`: Unix timestamp of revoke (`0` means not revoked) See more: + - SBT Standard [TEP-85](https://github.com/ton-blockchain/TEPs/blob/c5bfe285ef91810fab02c5352593f5a1455458bf/text/0085-sbt-standard.md) From afc0c86d490c93277a8dbc079ae5fb4f1d8a6eb9 Mon Sep 17 00:00:00 2001 From: skywardboundd Date: Sun, 12 Oct 2025 14:58:52 +0300 Subject: [PATCH 07/14] small fix --- standard/tokens/sbt/how-it-works.mdx | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/standard/tokens/sbt/how-it-works.mdx b/standard/tokens/sbt/how-it-works.mdx index 157bd656..92a8f2f6 100644 --- a/standard/tokens/sbt/how-it-works.mdx +++ b/standard/tokens/sbt/how-it-works.mdx @@ -3,9 +3,15 @@ title: "SBT: How it works" sidebarTitle: "How it works" --- +import { Aside } from '/snippets/aside.jsx'; + +This article describes the basic ideas and processes behind the implementation of SBT (Soul-Bound Token) in the TON Blockchain. + SBT is a variation of an NFT Item, but has some differences. -SBT standards provide only a general scheme of interaction, leaving the specific implementation of related contracts to developers. + **Nota bene: in all schemes below you will see the `query id` field. Nowadays the field is almost deprecated, and protocols itself doesn't need it. It is mostly used for easier off-chain parsing and other web2 processing**. @@ -44,7 +50,7 @@ ownership_proof#0524c7ae query_id:uint64 item_id:uint256 owner:MsgAddress | `query_id` | uint64 | Links the request `prove_ownership` and this `ownership_proof` response to each other. To ensure this process works correctly, always use a unique query ID. | | `item_id` | uint256 | Identifier of the SBT item. | | `owner` | MsgAddress | Current owner address. | -| `data` | Cell | Custom data forwarded to the target contract. | +| `data` | Cell | Custom data forwarded to the target contract, equal to `forward_payload`. | | `revoked_at` | uint64 | Revoke time if SBT is revoked, `0` otherwise. | | `content` | maybe Cell | SBT content if it was requested with `with_content=true`. | @@ -182,8 +188,6 @@ sequenceDiagram end ``` ---- - ### Quick field reference - `item_id`: identifier of the SBT item (analogous to an NFT item) @@ -192,6 +196,6 @@ sequenceDiagram - `content`: SBT content (may be attached optionally) - `revoked_at`: Unix timestamp of revoke (`0` means not revoked) -See more: +## See more: - SBT Standard [TEP-85](https://github.com/ton-blockchain/TEPs/blob/c5bfe285ef91810fab02c5352593f5a1455458bf/text/0085-sbt-standard.md) From 461ab6269bf4a3690d2d965938172924935d6b4a Mon Sep 17 00:00:00 2001 From: skywardboundd Date: Sun, 12 Oct 2025 15:28:34 +0300 Subject: [PATCH 08/14] fixik --- standard/tokens/sbt/how-it-works.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/standard/tokens/sbt/how-it-works.mdx b/standard/tokens/sbt/how-it-works.mdx index 92a8f2f6..a0be8c3b 100644 --- a/standard/tokens/sbt/how-it-works.mdx +++ b/standard/tokens/sbt/how-it-works.mdx @@ -63,7 +63,7 @@ sequenceDiagram participant D as dest (target contract) U->>S: prove_ownership - alt U == owner + alt owner S->>D: ownership_proof else not owner S-->>U: reject @@ -147,7 +147,7 @@ sequenceDiagram participant S as SBT U->>S: destroy(query_id) - alt U == owner + alt owner S->>S: owner = null, authority = null S-->>U: excesses(query_id) else not owner From e7ec18f5363c5cafc185ecff1fabf6ede3fdb373 Mon Sep 17 00:00:00 2001 From: skywardboundd Date: Mon, 13 Oct 2025 12:45:12 +0300 Subject: [PATCH 09/14] fix link --- standard/tokens/sbt/overview.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standard/tokens/sbt/overview.mdx b/standard/tokens/sbt/overview.mdx index c3ca505f..a7638e4f 100644 --- a/standard/tokens/sbt/overview.mdx +++ b/standard/tokens/sbt/overview.mdx @@ -21,5 +21,5 @@ The defining characteristic of SBTs lies in their non-transferable nature. Once - Community contribution ## Deep Dive -- [SBTs working principles](/standard/tokens/sbt/how-works) +- [SBTs working principles](/standard/tokens/sbt/how-it-works) - SBT Standard [TEP-85](https://github.com/ton-blockchain/TEPs/blob/0d7989fba6f2d9cb08811bf47263a9b314dc5296/text/0085-sbt-standard.md) \ No newline at end of file From ee9d8c7e890eed1fca3396a4cdb303391a40e452 Mon Sep 17 00:00:00 2001 From: skywardboundd Date: Mon, 13 Oct 2025 12:46:29 +0300 Subject: [PATCH 10/14] fmt --- standard/tokens/sbt/overview.mdx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/standard/tokens/sbt/overview.mdx b/standard/tokens/sbt/overview.mdx index a7638e4f..b8651ecf 100644 --- a/standard/tokens/sbt/overview.mdx +++ b/standard/tokens/sbt/overview.mdx @@ -5,14 +5,15 @@ sidebarTitle: "Overview" Soul-bound Tokens are non-transferable [NFTs](/standard/tokens/nft/overview). -## Why +## Why + Soul-bound Tokens represent a revolutionary concept in digital identity and credential management within the TON blockchain. These tokens embody permanence and non-transferability, creating an immutable link between specific credentials and their holders' blockchain addresses. The term "soul-bound" references the permanent binding of these tokens to their recipient's account. Everyone can be confident that each SBT has exactly one owner, enabling protocols to grant privileges to that owner via the SBT, which expands the protocol's capabilities. The technical foundation of SBTs builds upon existing NFT infrastructure while implementing transfer restrictions. SBTs inherit the uniqueness and metadata capabilities of NFTs but incorporate smart contract logic that prevents transfer operations. This design ensures that tokens remain permanently bound to their original recipients while maintaining all the verification and authenticity benefits of blockchain technology. -The defining characteristic of SBTs lies in their non-transferable nature. Once issued to a specific address, these tokens cannot be moved, sold, or transferred to any other address. +The defining characteristic of SBTs lies in their non-transferable nature. Once issued to a specific address, these tokens cannot be moved, sold, or transferred to any other address. ## Use cases: @@ -21,5 +22,6 @@ The defining characteristic of SBTs lies in their non-transferable nature. Once - Community contribution ## Deep Dive + - [SBTs working principles](/standard/tokens/sbt/how-it-works) -- SBT Standard [TEP-85](https://github.com/ton-blockchain/TEPs/blob/0d7989fba6f2d9cb08811bf47263a9b314dc5296/text/0085-sbt-standard.md) \ No newline at end of file +- SBT Standard [TEP-85](https://github.com/ton-blockchain/TEPs/blob/0d7989fba6f2d9cb08811bf47263a9b314dc5296/text/0085-sbt-standard.md) From 33c9e1794782e998aec49a8d8a894755c6731d09 Mon Sep 17 00:00:00 2001 From: skywardboundd Date: Mon, 13 Oct 2025 13:30:29 +0300 Subject: [PATCH 11/14] fix bot review --- standard/tokens/sbt/how-it-works.mdx | 48 ++++++++++++++-------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/standard/tokens/sbt/how-it-works.mdx b/standard/tokens/sbt/how-it-works.mdx index a0be8c3b..e31b10bc 100644 --- a/standard/tokens/sbt/how-it-works.mdx +++ b/standard/tokens/sbt/how-it-works.mdx @@ -38,21 +38,21 @@ ownership_proof#0524c7ae query_id:uint64 item_id:uint256 owner:MsgAddress | Name | Type | Description | | ----------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `query_id` | uint64 | Links the request `prove_ownership` and the response `ownership_proof` to each other. To ensure this process works correctly, always use a unique query ID. | -| `dest` | MsgAddress | Address of the target contract to receive the proof. | -| `forward_payload` | Cell | Arbitrary data forwarded to the target contract. | -| `with_content` | Bool | If `true`, attach SBT `content`. | +| `query_id` | `uint64` | Links the request `prove_ownership` and the response `ownership_proof` to each other. To ensure this process works correctly, always use a unique query ID. | +| `dest` | `MsgAddress` | Address of the target contract to receive the proof. | +| `forward_payload` | `Cell` | Arbitrary data forwarded to the target contract. | +| `with_content` | `Bool` | If `true`, attach SBT `content`. | `SBT -> dest (target contract)`. Ownership proof message contains the following data: | Name | Type | Description | | ------------ | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `query_id` | uint64 | Links the request `prove_ownership` and this `ownership_proof` response to each other. To ensure this process works correctly, always use a unique query ID. | -| `item_id` | uint256 | Identifier of the SBT item. | -| `owner` | MsgAddress | Current owner address. | -| `data` | Cell | Custom data forwarded to the target contract, equal to `forward_payload`. | -| `revoked_at` | uint64 | Revoke time if SBT is revoked, `0` otherwise. | -| `content` | maybe Cell | SBT content if it was requested with `with_content=true`. | +| `query_id` | `uint64` | Links the request `prove_ownership` and this `ownership_proof` response to each other. To ensure this process works correctly, always use a unique query ID. | +| `item_id` | `uint256` | Identifier of the SBT item. | +| `owner` | `MsgAddress` | Current owner address. | +| `data` | `Cell` | Custom data forwarded to the target contract, equal to `forward_payload`. | +| `revoked_at` | `uint64` | Revoke time if SBT is revoked, `0` otherwise. | +| `content` | `maybe Cell` | SBT content if it was requested with `with_content=true`. | Rejected if the sender is not the `owner`. @@ -88,22 +88,22 @@ owner_info#0dd607e3 query_id:uint64 item_id:uint256 initiator:MsgAddress owner:M | Name | Type | Description | | ----------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | -| `query_id` | uint64 | Links the request `request_owner` and the response `owner_info` to each other. To ensure this process works correctly, always use a unique query ID. | -| `dest` | MsgAddress | Address of the target contract to receive the response. | -| `forward_payload` | Cell | Arbitrary data forwarded to the target contract. | -| `with_content` | Bool | If `true`, attach SBT `content` in the response. | +| `query_id` | `uint64` | Links the request `request_owner` and the response `owner_info` to each other. To ensure this process works correctly, always use a unique query ID. | +| `dest` | `MsgAddress` | Address of the target contract to receive the response. | +| `forward_payload` | `Cell` | Arbitrary data forwarded to the target contract. | +| `with_content` | `Bool` | If `true`, attach SBT `content` in the response. | `SBT -> dest (target contract)`. Owner info message contains the following data: | Name | Type | Description | | ------------ | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | -| `query_id` | uint64 | Links the request `request_owner` and this `owner_info` response to each other. To ensure this process works correctly, always use a unique query ID. | -| `item_id` | uint256 | Identifier of the SBT item. | -| `initiator` | MsgAddress | Address of the requester. | -| `owner` | MsgAddress | Current owner address. | -| `data` | Cell | Custom data forwarded to the target, equals to `forward_payload`. | -| `revoked_at` | uint64 | Revoke time if revoked, `0` otherwise. | -| `content` | maybe Cell | SBT content if it was requested. | +| `query_id` | `uint64` | Links the request `request_owner` and this `owner_info` response to each other. To ensure this process works correctly, always use a unique query ID. | +| `item_id` | `uint256` | Identifier of the SBT item. | +| `initiator` | `MsgAddress` | Address of the requester. | +| `owner` | `MsgAddress` | Current owner address. | +| `data` | `Cell` | Custom data forwarded to the target, equals to `forward_payload`. | +| `revoked_at` | `uint64` | Revoke time if revoked, `0` otherwise. | +| `content` | `maybe Cell` | SBT content if it was requested. | ```mermaid sequenceDiagram @@ -131,13 +131,13 @@ excesses#d53276db query_id:uint64 = InternalMsgBody; | Name | Type | Description | | ---------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------- | -| `query_id` | uint64 | Links the request `destroy` and the response `excesses` to each other. To ensure this process works correctly, always use a unique query ID. | +| `query_id` | `uint64` | Links the request `destroy` and the response `excesses` to each other. To ensure this process works correctly, always use a unique query ID. | `SBT -> sender`. Excesses message contains the following data: | Name | Type | Description | | ---------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------- | -| `query_id` | uint64 | Links the request `destroy` and this `excesses` response to each other. To ensure this process works correctly, always use a unique query ID. | +| `query_id` | `uint64` | Links the request `destroy` and this `excesses` response to each other. To ensure this process works correctly, always use a unique query ID. | Rejected if the sender is not the `owner`. @@ -168,7 +168,7 @@ revoke#6f89f5e3 query_id:uint64 = InternalMsgBody; | Name | Type | Description | | ---------- | ------ | ---------------------------------------------------------------------------------------------------------------------------- | -| `query_id` | uint64 | Identifies the `revoke` request for off-chain parsing. To ensure this process works correctly, always use a unique query ID. | +| `query_id` | `uint64` | Identifies the `revoke` request for off-chain parsing. To ensure this process works correctly, always use a unique query ID. | Rejected if: From 85d706c5f63d66986857a45a5fd0f5983123a619 Mon Sep 17 00:00:00 2001 From: skywardboundd Date: Mon, 13 Oct 2025 13:31:43 +0300 Subject: [PATCH 12/14] fmt --- standard/tokens/sbt/how-it-works.mdx | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/standard/tokens/sbt/how-it-works.mdx b/standard/tokens/sbt/how-it-works.mdx index e31b10bc..13bf6790 100644 --- a/standard/tokens/sbt/how-it-works.mdx +++ b/standard/tokens/sbt/how-it-works.mdx @@ -36,8 +36,8 @@ ownership_proof#0524c7ae query_id:uint64 item_id:uint256 owner:MsgAddress `Inbound to SBT`. Prove ownership message contains the following data: -| Name | Type | Description | -| ----------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Name | Type | Description | +| ----------------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | `query_id` | `uint64` | Links the request `prove_ownership` and the response `ownership_proof` to each other. To ensure this process works correctly, always use a unique query ID. | | `dest` | `MsgAddress` | Address of the target contract to receive the proof. | | `forward_payload` | `Cell` | Arbitrary data forwarded to the target contract. | @@ -45,8 +45,8 @@ ownership_proof#0524c7ae query_id:uint64 item_id:uint256 owner:MsgAddress `SBT -> dest (target contract)`. Ownership proof message contains the following data: -| Name | Type | Description | -| ------------ | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Name | Type | Description | +| ------------ | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `query_id` | `uint64` | Links the request `prove_ownership` and this `ownership_proof` response to each other. To ensure this process works correctly, always use a unique query ID. | | `item_id` | `uint256` | Identifier of the SBT item. | | `owner` | `MsgAddress` | Current owner address. | @@ -86,8 +86,8 @@ owner_info#0dd607e3 query_id:uint64 item_id:uint256 initiator:MsgAddress owner:M `Inbound to SBT`. Request owner message contains the following data: -| Name | Type | Description | -| ----------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | +| Name | Type | Description | +| ----------------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | `query_id` | `uint64` | Links the request `request_owner` and the response `owner_info` to each other. To ensure this process works correctly, always use a unique query ID. | | `dest` | `MsgAddress` | Address of the target contract to receive the response. | | `forward_payload` | `Cell` | Arbitrary data forwarded to the target contract. | @@ -95,8 +95,8 @@ owner_info#0dd607e3 query_id:uint64 item_id:uint256 initiator:MsgAddress owner:M `SBT -> dest (target contract)`. Owner info message contains the following data: -| Name | Type | Description | -| ------------ | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | +| Name | Type | Description | +| ------------ | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- | | `query_id` | `uint64` | Links the request `request_owner` and this `owner_info` response to each other. To ensure this process works correctly, always use a unique query ID. | | `item_id` | `uint256` | Identifier of the SBT item. | | `initiator` | `MsgAddress` | Address of the requester. | @@ -129,14 +129,14 @@ excesses#d53276db query_id:uint64 = InternalMsgBody; `Inbound to SBT`. Destroy message contains the following data: -| Name | Type | Description | -| ---------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------- | +| Name | Type | Description | +| ---------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------- | | `query_id` | `uint64` | Links the request `destroy` and the response `excesses` to each other. To ensure this process works correctly, always use a unique query ID. | `SBT -> sender`. Excesses message contains the following data: -| Name | Type | Description | -| ---------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------- | +| Name | Type | Description | +| ---------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------- | | `query_id` | `uint64` | Links the request `destroy` and this `excesses` response to each other. To ensure this process works correctly, always use a unique query ID. | Rejected if the sender is not the `owner`. @@ -166,8 +166,8 @@ revoke#6f89f5e3 query_id:uint64 = InternalMsgBody; `Inbound to SBT`. Revoke message contains the following data: -| Name | Type | Description | -| ---------- | ------ | ---------------------------------------------------------------------------------------------------------------------------- | +| Name | Type | Description | +| ---------- | -------- | ---------------------------------------------------------------------------------------------------------------------------- | | `query_id` | `uint64` | Identifies the `revoke` request for off-chain parsing. To ensure this process works correctly, always use a unique query ID. | Rejected if: From d42c7b1e98e3d2713ff867701cd8bb0bc3fc6920 Mon Sep 17 00:00:00 2001 From: Anton Trunov Date: Tue, 14 Oct 2025 12:25:56 +0400 Subject: [PATCH 13/14] Update standard/tokens/sbt/overview.mdx --- standard/tokens/sbt/overview.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standard/tokens/sbt/overview.mdx b/standard/tokens/sbt/overview.mdx index b8651ecf..75d11aa8 100644 --- a/standard/tokens/sbt/overview.mdx +++ b/standard/tokens/sbt/overview.mdx @@ -3,7 +3,7 @@ title: "SBT: Soul-bound token" sidebarTitle: "Overview" --- -Soul-bound Tokens are non-transferable [NFTs](/standard/tokens/nft/overview). +Soul-bound Tokens are essentially non-transferable [NFTs](/standard/tokens/nft/overview). ## Why From 4b6e11779fb5317e3585062a11ebb813c50094e2 Mon Sep 17 00:00:00 2001 From: skywardboundd Date: Tue, 14 Oct 2025 20:15:18 +0300 Subject: [PATCH 14/14] review --- docs.json | 1 - guidebook/from-ethereum.mdx | 2 +- standard/tokens/nft/comparison.mdx | 10 +++ standard/tokens/overview.mdx | 2 +- standard/tokens/sbt/how-it-works.mdx | 94 ++++++++++++++++------------ standard/tokens/sbt/overview.mdx | 27 -------- 6 files changed, 65 insertions(+), 71 deletions(-) delete mode 100644 standard/tokens/sbt/overview.mdx diff --git a/docs.json b/docs.json index 38057ba9..060d517e 100644 --- a/docs.json +++ b/docs.json @@ -331,7 +331,6 @@ { "group": "SBT", "pages": [ - "standard/tokens/sbt/overview", "standard/tokens/sbt/how-it-works" ] }, diff --git a/guidebook/from-ethereum.mdx b/guidebook/from-ethereum.mdx index a1b672a0..b6c78c3e 100644 --- a/guidebook/from-ethereum.mdx +++ b/guidebook/from-ethereum.mdx @@ -118,5 +118,5 @@ This section showcases match between some of the Ethereum standards and proposal | Token metadata | ERC-4955 (Not exactly, but close match) | [Token Data Standard (TEP-0064)](/standard/tokens/metadata) | | NFT royalty standard | EIP-2981 | [NFT Royalty Standard (TEP-0066)](/standard/tokens/nft/comparison) | | DNS-like registry | ENS (EIP-137) | [DNS Standard (TEP-0081)](/services/dns) | -| Soulbound / account-bound token concept | EIP-4973 | [SBT Standard (TEP-0085)](/standard/tokens/sbt/overview) | +| Soulbound / account-bound token concept | EIP-4973 | [SBT Standard (TEP-0085)](/standard/tokens/nft/comparison#sbt) | | Wallet connection protocol | WalletConnect / EIP-1193 | [TonConnect (TEP-0115)](/ecosystem/ton-connect) | diff --git a/standard/tokens/nft/comparison.mdx b/standard/tokens/nft/comparison.mdx index b7d49576..85558c74 100644 --- a/standard/tokens/nft/comparison.mdx +++ b/standard/tokens/nft/comparison.mdx @@ -56,6 +56,16 @@ Short overview: An SBT inherits the uniqueness and metadata model of NFTs but disables transfer operations, binding the token permanently to the recipient's address after mint. This makes SBTs well‑suited for identity and credentials: attendance records, participation proofs, and non‑transferable achievements. It also has on-chain API to proof ownership of SBT item. +#### Core functionality + +SBTs provide several key operations that enable secure credential management: + +- **Ownership binding** - the owner is set at mint time and never changes, ensuring permanent association with the recipient. +- **Ownership proof** - allows the owner to request the SBT to send a proof to a target contract confirming ownership, with optional content attachment. +- **Owner information requests** - any party can request current owner information and optional content from the SBT. +- **SBT destruction** - the owner can destroy the SBT contract, clearing ownership and authority fields. +- **Revocation mechanism** - the authority can mark the SBT as revoked, preventing further use while maintaining historical records. + ## Single NFT (no collection) A Single NFT is an item contract deployed without an associated collection. It keeps the same ownership semantics but omits shared collection metadata and indexing. diff --git a/standard/tokens/overview.mdx b/standard/tokens/overview.mdx index 36e11fbc..caf8433e 100644 --- a/standard/tokens/overview.mdx +++ b/standard/tokens/overview.mdx @@ -9,7 +9,7 @@ The TON blockchain supports three distinct categories of digital tokens, each de - [Fungible tokens](/standard/tokens/jettons/overview) (Jettons) - this is a web3 way to create new currency on your own - [Non-Fungible Tokens](/standard/tokens/nft/overview) (NFTs) - like Jettons, but each token is unique and represent distinct entity -- [Soul-bound Tokens](/standard/tokens/sbt/overview) (SBTs) - like NFTs, but not-transferable, bound to a single owner +- [Soul-bound Tokens](/standard/tokens/nft/comparison#sbt) (SBTs) - like NFTs, but not-transferable, bound to a single owner ## Comparison table diff --git a/standard/tokens/sbt/how-it-works.mdx b/standard/tokens/sbt/how-it-works.mdx index 13bf6790..0bd8b7aa 100644 --- a/standard/tokens/sbt/how-it-works.mdx +++ b/standard/tokens/sbt/how-it-works.mdx @@ -13,29 +13,35 @@ SBT is a variation of an NFT Item, but has some differences. It is important to keep in mind that SBT standards provide only a general scheme of interaction, leaving the specific implementation of related contracts to developers. -**Nota bene: in all schemes below you will see the `query id` field. Nowadays the field is almost deprecated, and protocols itself doesn't need it. -It is mostly used for easier off-chain parsing and other web2 processing**. + + +## Message flows + +Interactions with SBT contracts, which are most often encountered by users and developers, are: + +- prove ownership: sending proof of SBT ownership to a target contract; +- request current owner: requesting current owner information from SBT; +- destroy SBT: destroying the SBT contract and returning remaining balance; +- revoke SBT: marking the SBT as revoked by authority. ## Bound to single owner -The `owner` is set at mint time and never changes. Below is a simple explanation of the key operations and their message flows. +The `owner` of SBT is set at the minting time and never changes. Below is a simple explanation of the key operations and their message flows. ## Prove ownership -Allows the `owner` to ask the SBT to send a proof to a target contract confirming that they own this SBT. You may include arbitrary `forward_payload` and optionally attach `content`. +This message flow allows the `owner` to ask the SBT to send a proof to a target contract confirming that they own this SBT. You may include arbitrary `forward_payload` and optionally attach `content`. + +### Prove ownership message (inbound to SBT) ```tlb title="TL-B" ;; Inbound message to SBT prove_ownership#04ded148 query_id:uint64 dest:MsgAddress forward_payload:^Cell with_content:Bool = InternalMsgBody; - -;; SBT response to the target contract (if checks pass) -ownership_proof#0524c7ae query_id:uint64 item_id:uint256 owner:MsgAddress - data:^Cell revoked_at:uint64 content:(Maybe ^Cell) = InternalMsgBody; ``` -`Inbound to SBT`. Prove ownership message contains the following data: - | Name | Type | Description | | ----------------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | `query_id` | `uint64` | Links the request `prove_ownership` and the response `ownership_proof` to each other. To ensure this process works correctly, always use a unique query ID. | @@ -43,7 +49,13 @@ ownership_proof#0524c7ae query_id:uint64 item_id:uint256 owner:MsgAddress | `forward_payload` | `Cell` | Arbitrary data forwarded to the target contract. | | `with_content` | `Bool` | If `true`, attach SBT `content`. | -`SBT -> dest (target contract)`. Ownership proof message contains the following data: +### Ownership proof message (SBT -> target contract) + +```tlb title="TL-B" +;; SBT response to the target contract (if checks pass) +ownership_proof#0524c7ae query_id:uint64 item_id:uint256 owner:MsgAddress + data:^Cell revoked_at:uint64 content:(Maybe ^Cell) = InternalMsgBody; +``` | Name | Type | Description | | ------------ | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | @@ -54,7 +66,7 @@ ownership_proof#0524c7ae query_id:uint64 item_id:uint256 owner:MsgAddress | `revoked_at` | `uint64` | Revoke time if SBT is revoked, `0` otherwise. | | `content` | `maybe Cell` | SBT content if it was requested with `with_content=true`. | -Rejected if the sender is not the `owner`. +Rejected transaction if the sender is not the `owner`. ```mermaid sequenceDiagram @@ -72,20 +84,16 @@ sequenceDiagram ## Request current owner -Any initiator may ask the SBT to send the current `owner` (and optionally the `content`) to a target contract. +This message flow allows any initiator to ask the SBT to send the current `owner` (and optionally the `content`) to a target contract. + +### Request owner message (inbound to SBT) ```tlb title="TL-B" ;; Inbound message to SBT request_owner#d0c3bfea query_id:uint64 dest:MsgAddress forward_payload:^Cell with_content:Bool = InternalMsgBody; - -;; SBT response to the target contract -owner_info#0dd607e3 query_id:uint64 item_id:uint256 initiator:MsgAddress owner:MsgAddress - data:^Cell revoked_at:uint64 content:(Maybe ^Cell) = InternalMsgBody; ``` -`Inbound to SBT`. Request owner message contains the following data: - | Name | Type | Description | | ----------------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | `query_id` | `uint64` | Links the request `request_owner` and the response `owner_info` to each other. To ensure this process works correctly, always use a unique query ID. | @@ -93,7 +101,13 @@ owner_info#0dd607e3 query_id:uint64 item_id:uint256 initiator:MsgAddress owner:M | `forward_payload` | `Cell` | Arbitrary data forwarded to the target contract. | | `with_content` | `Bool` | If `true`, attach SBT `content` in the response. | -`SBT -> dest (target contract)`. Owner info message contains the following data: +### Owner info message (SBT -> target contract) + +```tlb title="TL-B" +;; SBT response to the target contract +owner_info#0dd607e3 query_id:uint64 item_id:uint256 initiator:MsgAddress owner:MsgAddress + data:^Cell revoked_at:uint64 content:(Maybe ^Cell) = InternalMsgBody; +``` | Name | Type | Description | | ------------ | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- | @@ -101,10 +115,12 @@ owner_info#0dd607e3 query_id:uint64 item_id:uint256 initiator:MsgAddress owner:M | `item_id` | `uint256` | Identifier of the SBT item. | | `initiator` | `MsgAddress` | Address of the requester. | | `owner` | `MsgAddress` | Current owner address. | -| `data` | `Cell` | Custom data forwarded to the target, equals to `forward_payload`. | +| `data` | `Cell` | Custom data forwarded to the target, equal to `forward_payload`. | | `revoked_at` | `uint64` | Revoke time if revoked, `0` otherwise. | | `content` | `maybe Cell` | SBT content if it was requested. | +### Full pipeline + ```mermaid sequenceDiagram participant I as Initiator @@ -117,29 +133,33 @@ sequenceDiagram ## Destroy -The `owner` can destroy the SBT contract. This clears the `owner` and `authority` fields, and sends remaining balance back to the sender via an `excesses` message. +This message flow allows the `owner` to destroy the SBT contract. This clears the `owner` and `authority` fields, and sends remaining balance back to the sender via an `excesses` message. + +### Destroy message (inbound to SBT) ```tlb title="TL-B" ;; Internal message to SBT destroy#1f04537a query_id:uint64 = InternalMsgBody; - -;; Excess returned to the sender -excesses#d53276db query_id:uint64 = InternalMsgBody; ``` -`Inbound to SBT`. Destroy message contains the following data: - | Name | Type | Description | | ---------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------- | | `query_id` | `uint64` | Links the request `destroy` and the response `excesses` to each other. To ensure this process works correctly, always use a unique query ID. | -`SBT -> sender`. Excesses message contains the following data: +### Excesses message (SBT -> sender) + +```tlb title="TL-B" +;; Excess returned to the sender +excesses#d53276db query_id:uint64 = InternalMsgBody; +``` | Name | Type | Description | | ---------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------- | | `query_id` | `uint64` | Links the request `destroy` and this `excesses` response to each other. To ensure this process works correctly, always use a unique query ID. | -Rejected if the sender is not the `owner`. +Rejected transaction if the sender is not the `owner`. + +### Full pipeline ```mermaid sequenceDiagram @@ -157,20 +177,20 @@ sequenceDiagram ## Revoke SBT -The `authority` can mark the SBT as revoked. Revoking twice is disallowed. +This message flow allows the `authority` to mark the SBT as revoked. Revoking twice is disallowed. + +### Revoke message (inbound to SBT) ```tlb title="TL-B" ;; Inbound message to SBT revoke#6f89f5e3 query_id:uint64 = InternalMsgBody; ``` -`Inbound to SBT`. Revoke message contains the following data: - | Name | Type | Description | | ---------- | -------- | ---------------------------------------------------------------------------------------------------------------------------- | | `query_id` | `uint64` | Identifies the `revoke` request for off-chain parsing. To ensure this process works correctly, always use a unique query ID. | -Rejected if: +Rejected transaction if: - the sender is not the `authority`; - the SBT was already revoked. @@ -188,14 +208,6 @@ sequenceDiagram end ``` -### Quick field reference - -- `item_id`: identifier of the SBT item (analogous to an NFT item) -- `owner`: current owner -- `authority`: the address allowed to revoke the SBT -- `content`: SBT content (may be attached optionally) -- `revoked_at`: Unix timestamp of revoke (`0` means not revoked) - ## See more: - SBT Standard [TEP-85](https://github.com/ton-blockchain/TEPs/blob/c5bfe285ef91810fab02c5352593f5a1455458bf/text/0085-sbt-standard.md) diff --git a/standard/tokens/sbt/overview.mdx b/standard/tokens/sbt/overview.mdx deleted file mode 100644 index 75d11aa8..00000000 --- a/standard/tokens/sbt/overview.mdx +++ /dev/null @@ -1,27 +0,0 @@ ---- -title: "SBT: Soul-bound token" -sidebarTitle: "Overview" ---- - -Soul-bound Tokens are essentially non-transferable [NFTs](/standard/tokens/nft/overview). - -## Why - -Soul-bound Tokens represent a revolutionary concept in digital identity and credential management within the TON blockchain. These tokens embody permanence and non-transferability, creating an immutable link between specific credentials and their holders' blockchain addresses. The term "soul-bound" references the permanent binding of these tokens to their recipient's account. - -Everyone can be confident that each SBT has exactly one owner, enabling protocols to grant privileges to that owner via the SBT, which expands the protocol's capabilities. - -The technical foundation of SBTs builds upon existing NFT infrastructure while implementing transfer restrictions. SBTs inherit the uniqueness and metadata capabilities of NFTs but incorporate smart contract logic that prevents transfer operations. This design ensures that tokens remain permanently bound to their original recipients while maintaining all the verification and authenticity benefits of blockchain technology. - -The defining characteristic of SBTs lies in their non-transferable nature. Once issued to a specific address, these tokens cannot be moved, sold, or transferred to any other address. - -## Use cases: - -- Event participation record -- Attendance certificate -- Community contribution - -## Deep Dive - -- [SBTs working principles](/standard/tokens/sbt/how-it-works) -- SBT Standard [TEP-85](https://github.com/ton-blockchain/TEPs/blob/0d7989fba6f2d9cb08811bf47263a9b314dc5296/text/0085-sbt-standard.md)