Skip to content
Open
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
9c4b783
sbt-how-it-works
skywardboundd Sep 26, 2025
ea56e4b
review
skywardboundd Sep 26, 2025
c463b67
review
skywardboundd Sep 26, 2025
754434a
fix
skywardboundd Sep 26, 2025
7b3a19b
Merge branch 'main' into 104-tokens-sbt
anton-trunov Oct 7, 2025
1a2adc4
Merge branch 'main' into 104-tokens-sbt
skywardboundd Oct 12, 2025
ad34e98
review
skywardboundd Oct 12, 2025
0dfacca
fmt
skywardboundd Oct 12, 2025
afc0c86
small fix
skywardboundd Oct 12, 2025
461ab62
fixik
skywardboundd Oct 12, 2025
5366700
Merge branch 'main' into 104-tokens-sbt
skywardboundd Oct 13, 2025
e7ec18f
fix link
skywardboundd Oct 13, 2025
ee9d8c7
fmt
skywardboundd Oct 13, 2025
33c9e17
fix bot review
skywardboundd Oct 13, 2025
85d706c
fmt
skywardboundd Oct 13, 2025
82fdffc
Merge branch 'main' into 104-tokens-sbt
skywardboundd Oct 13, 2025
d42c7b1
Update standard/tokens/sbt/overview.mdx
anton-trunov Oct 14, 2025
869816d
Merge branch 'main' into 104-tokens-sbt
skywardboundd Oct 14, 2025
4b6e117
review
skywardboundd Oct 14, 2025
58a507c
refactor
skywardboundd Oct 24, 2025
4a1f221
Merge remote-tracking branch 'origin/main' into 104-tokens-sbt
skywardboundd Oct 24, 2025
c23fe5d
fmt
skywardboundd Oct 24, 2025
6564fb7
fix link rot
skywardboundd Oct 24, 2025
525d150
fixes
skywardboundd Nov 5, 2025
b5e149b
Merge remote-tracking branch 'origin/main' into 104-tokens-sbt
skywardboundd Nov 5, 2025
6719b20
tmp
skywardboundd Nov 11, 2025
a6a9667
fmt
skywardboundd Nov 11, 2025
71585bc
Merge remote-tracking branch 'origin/main' into 104-tokens-sbt
skywardboundd Nov 11, 2025
ec69383
fixes
skywardboundd Nov 12, 2025
0d38bad
Merge remote-tracking branch 'origin/main' into 104-tokens-sbt
skywardboundd Nov 12, 2025
21f84b8
fixes
skywardboundd Nov 12, 2025
05833d5
fmt
skywardboundd Nov 12, 2025
5a12ba1
Merge branch 'main' into 104-tokens-sbt
verytactical Nov 12, 2025
f7f7e0d
Merge branch 'main' into 104-tokens-sbt
anton-trunov Nov 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@
"group": "SBT",
"pages": [
"standard/tokens/sbt/overview",
"standard/tokens/sbt/how-works"
"standard/tokens/sbt/how-it-works"
]
},
"standard/tokens/airdrop"
Expand Down
201 changes: 201 additions & 0 deletions standard/tokens/sbt/how-it-works.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
---
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.

<Aside type="note">
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.
</Aside>

**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, 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`.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does "rejected" mean in this context?


```mermaid
sequenceDiagram
participant U as Owner
participant S as SBT
participant D as dest (target contract)
U->>S: prove_ownership
alt 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 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)
Empty file removed standard/tokens/sbt/how-works.mdx
Empty file.
12 changes: 7 additions & 5 deletions standard/tokens/sbt/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@ 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

## 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:

Expand All @@ -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-works)
- SBT Standard [TEP-85](https://github.com/ton-blockchain/TEPs/blob/0d7989fba6f2d9cb08811bf47263a9b314dc5296/text/0085-sbt-standard.md)

- [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)