diff --git a/neps/nep-0393.md b/neps/nep-0393.md
new file mode 100644
index 000000000..67b3361c2
--- /dev/null
+++ b/neps/nep-0393.md
@@ -0,0 +1,665 @@
+---
+NEP: 393
+Title: Soulbound Token
+Authors: Robert Zaremba <@robert-zaremba>
+DiscussionsTo:
+Status: Approved
+Type: Standards Track
+Category: Contract
+Created: 12-Sep-2022
+Requires:
+---
+
+# NEP: Soulbound Token
+
+## Summary
+
+Soulbound Token (SBT) is a form of a non-fungible token which represents an aspect of an account: _soul_. [Transferability](#transferability) is limited only to a case of recoverability or a _soul transfer_. The latter must coordinate with a registry to transfer all SBTs from one account to another, and _banning_ the source account.
+
+SBTs are well suited for carrying proof-of-attendance, proof-of-unique-human "stamps" and other similar credibility-carriers.
+
+## Motivation
+
+Recent [Decentralized Society](https://www.bankless.com/decentralized-society-desoc-explained) trends open a new area of Web3 research to model various aspects of what characterizes humans. Economic and governance value is generated by humans and their relationship. SBTs can represent the commitments, credentials, and affiliations of “Souls” that encode the trust networks of the real economy to establish provenance and reputation.
+
+> More importantly, SBTs enable other applications of increasing ambition, such as community wallet recovery, Sybil-resistant governance, mechanisms for decentralization, and novel markets with decomposable, shared rights. We call this richer, pluralistic ecosystem “Decentralized Society” (DeSoc)—a co-determined sociality, where Souls and communities come together bottom-up, as emergent properties of each other to co-create plural network goods and intelligences, at a range of scales.
+
+Creating strong primitives is necessary to model new innovative systems and decentralized societies. Examples include reputation protocols, non-transferrable certificates, non-transferrable rights, undercollateralized lending, proof-of-personhood, proof-of-attendance, proof-of-skill, one-person-one-vote, fair airdrops & ICOs, universal basic income, non KYC identity systems, Human DAOs and methods for Sybil attack resistance.
+
+We propose an SBT standard to model protocols described above.
+
+_Verifiable Credentials_ (VC) could be seen as subset of SBT. However there is an important distinction: VC require set of claims and privacy protocols. It would make more sense to model VC with relation to W3 DID standard. SBT is different, it doesn't require a [resolver](https://www.w3.org/TR/did-core/#dfn-did-resolvers) nor [method](https://www.w3.org/TR/did-core/#dfn-did-methods) registry. For SBT, we need something more elastic than VC.
+
+## Specification
+
+Main requirement for Soulbound tokens is to bound an account to a human. A **Soul** is an account with SBTs, which are used to define account identity.
+Often non transferrable NFT (an NFT token with a no-op transfer function) is used to implement SBTs. However, such model is rather shortsighted. Transferability is required to allow users to either recover their SBTs or merge between the accounts they own. At the same time, we need to limit transferability to assure that an SBTs is kept bound to the same _soul_.
+We also need an efficient on way to make composed ownership queries (for example: check if an account owns SBT of class C1, C2 and C3 issued by issuer I1, I2 and I3 respectively) - this is needed to model emergent properties discussed above.
+
+We introduce a **soul transfer**: an ability for user to move ALL SBT tokens from one account to another in a [semi atomic](#soul-transfer) way, while keeping the SBT bounded to the same _soul_. This happens when a user needs to merge his accounts (e.g. they started with a few different accounts but later decides to merge them to increase an account reputation). Soul transfer is different than a token transfer. The standard forbids a traditional token transfer functionality, where a user can transfer individual tokens. That being said, a registry can have extension functions for more advanced scenarios, which could require a governance approval.
+
+SBT standard separates the token issuer concept from the token registry in order to meet the requirements listed above.
+In the following sections we discuss the functionality of an issuer and registry.
+
+### SBT Registry
+
+Traditional Token model in NEAR blockchain assumes that each token has it's own balance book and implements the authorization and issuance mechanism in the same smart contract. Such model prevents atomic _soul transfer_ in the current NEAR runtime. When token balance is kept separately in each SBT smart contract, synchronizing transfer calls to all such contracts to assure atomicity is not possible at scale. We need an additional contract, the `SBT Registry`, to provide atomic transfer of all user SBTs and efficient way to ban accounts in relation to the Ban event discussed below.
+This, and efficient cross-issuer queries are the main reasons SBT standards separates that token registry and token issuance concerns.
+
+Issuer is an entity which issues new tokens and potentially can update the tokens (for example execute renewal). All standard modification options are discussed in the sections below.
+
+Registry is a smart contract, where issuers register the tokens. Registry provides a balance book of all associated SBTs. Registry must ensure that each issuer has it's own "sandbox" and issuers won't overwrite each other. A registry provides an efficient way to query multiple tokens for a single user. This will allow implementation of use cases such us:
+
+- SBT based identities (main use case of the `i-am-human` protocol);
+- SBT classes;
+- decentralized societies.
+
+```mermaid
+graph TB
+ Issuer1--uses--> Registry
+ Issuer2--uses--> Registry
+ Issuer3--uses--> Registry
+```
+
+We can have multiple competing registries (with different purpose or different management scheme). An SBT issuer SHOULD opt-in to a registry before being able to use registry. Registries may develop different opt-in mechanisms (they could differ by the approval mechanism, be fully permissioned etc..). One SBT smart contract can opt-in to:
+
+- many registries: it MUST relay all state change functions to all registries.
+- or to no registry. We should think about it as a single token registry, and it MUST strictly implement all SBT Registry query functions by itself. The contract address must be part of the arguments, and it must check that it equals to the deployed account address (`require!(ctr == env::current_account_id())`). It also MUST emit related events by itself.
+
+We recommend that each issuer will use only one registry to avoid complex reconciliation and assure single source of truth.
+
+The registry fills a central and important role. But it is **not centralized**, as anyone can create their own registry and SBT issuers can choose which registry to use. It's also not too powerful, as almost all of the power (mint, revoke, burn, recover, etc) still remains with the SBT issuer and not with the registry.
+
+#### Issuer authorization
+
+A registry can limit which issuers can use registry to mint SBTs by implementing a custom issuer whitelist methods (for example simple access control list managed by a DAO) or keep it fully open (allowing any issuer minting withing the registry).
+
+Example: an `SBT_1 Issuer` wants to mint tokens using the `SBT_Registry`. The `SBT_Registry` has a DAO which votes on adding a new issuer:
+
+```mermaid
+sequenceDiagram
+ actor Issuer1 as SBT_1 Issuer
+ actor DAO
+
+ participant SBT_Registry
+
+ Note over Issuer1,DAO: Issuer1 connects with the DAO to be whitelisted.
+
+ Issuer1-->>DAO: request whitelist
+ DAO->>SBT_Registry: whitelist(SBT_1 Issuer)
+```
+
+#### Personal Identifiable Information
+
+Issuers must not include any PII into any SBT.
+
+### Account Ban
+
+`Ban` is an event emitted by a registry signaling that the account is banned, and can't own any SBT. Registry must return zero for every SBT supply query of a banned account. Operations which trigger soul transfer must emit Ban.
+
+A registry can emit a `Ban` for use cases not discussed in this standard. Handling it depends on the registry governance. One example is to use social governance to identify fake accounts (like bots) - in that case the registry should allow to emit `Ban` and block a scam soul and block future transfers.
+NOTE: an SBT Issuer can have it's own list of blocked accounts or allowed only accounts.
+
+### Minting
+
+Minting is done by issuer calling `registry.sbt_mint(tokens_to_mint)` method. Standard doesn't specify how a registry authorizes an issuer. A classical approach is a whitelist of issuers: any whitelisted issuer can mint any amount of new tokens. Registry must keep the balances and assign token IDs to newly minted tokens.
+
+Example: Alice has two accounts: `alice1` and `alice2` which she used to mint tokens. She is getting tokens from 2 issuers that use the same registry. Alice uses her `alice1` account to interact with `SBT_1 Issuer` and receives an SBT with token ID = 238:
+
+```mermaid
+sequenceDiagram
+ actor Alice
+ actor Issuer1 as SBT_1 Issuer
+
+ participant SBT1 as SBT_1 Contract
+ participant SBT_Registry
+
+ Issuer1->>SBT1: sbt_mint(alice1, metadata)
+ activate SBT1
+ SBT1-)SBT_Registry: sbt_mint([[alice1, [metadata]]])
+ SBT_Registry->>SBT_Registry: emit Mint(SBT_1_Contract, alice1, [238])
+ SBT_Registry-)SBT1: [238]
+ deactivate SBT1
+
+ Note over Alice,SBT_Registry: now Alice can query registry to check her SBT
+
+ Alice-->>SBT_Registry: sbt(SBT_1_Contract, 238)
+ SBT_Registry-->>Alice: {token: 238, owner: alice1, metadata}
+```
+
+With `SBT_2 Issuer`, Alice uses her `alice2` account. Note that `SBT_2 Contract` has different mint function (can mint many tokens at once), and validates a proof prior to requesting the registry to mint the tokens.
+
+```mermaid
+sequenceDiagram
+ actor Alice
+ actor Issuer2 as SBT_2 Issuer
+
+ participant SBT2 as SBT_2 Contract
+ participant SBT_Registry
+
+ Issuer2->>SBT2: sbt_mint_multi([[alice2, metadata2], [alice2, metadata3]], proof)
+ activate SBT2
+ SBT2-)SBT_Registry: sbt_mint([[alice2, [metadata2, metadata3]]])
+ SBT_Registry->>SBT_Registry: emit Mint(SBT_2_Contract, alice2, [7991, 7992])
+ SBT_Registry-)SBT2: [7991, 1992]
+ deactivate SBT2
+
+ Note over Alice,SBT_Registry: Alice queries one of her new tokens
+ Alice-->>SBT_Registry: sbt(SBT_2_Contract, 7991)
+ SBT_Registry-->>Alice: {token: 7991, owner: alice2, metadata: metadata2}
+```
+
+### Transferability
+
+Safeguards are set against misuse of SBT transfer and keep the _soul bound_ property. SBT transfer from one account to another should be strictly limited to:
+
+- **revocation** allows issuer to invalidate or burn an SBT in case a token issuance should be reverted (for example the recipient is a Sybil account, that is an account controlled by an entity trying to create the false appearance);
+- **recoverability** in case a user's private key is compromised due to extortion, loss, etc. Users cannot recover an SBT only by themselves. Users must connect with issuer to request recoverability or use more advanced mechanism (like social recoverability). The recovery function provides additional economical cost preventing account trading: user should always be able to recover his SBT, and move to another, not banned account.
+- **soul transfer** - moving all SBT tokens from a source account (issued by all issuers) to a destination account. During such transfer, SBT registry emits `SoulTransfer` and `Ban` events. The latter signals that the account can't host nor receive any SBT in the future, effectively burning the identity of the source account. This creates an inherit cost for the source account: it's identity can't be used any more. Registry can have extension functions for more advanced scenarios, which could require a governance mechanism. `SoulTransfer` event can also trigger similar actions in other registries (specification for this is out of the scope of this NEP).
+
+This becomes especially important for proof-of-human stamps that can only be issued once per user.
+
+#### Revocation
+
+An issuer can revoke SBTs by calling `registry.sbt_revoke(tokens_to_revoke, burn)`. Example: when a related certificate or membership should be revoked, when an issuer finds out that there was an abuse or a scam, etc...). Registry, when receiving `sbt_revoke` request from an issuer must always emit the `Revoke` event. Registry must only accept revoke requests from a valid issuer, and only revoke tokens from that issuer. If `burn=true` is set in the request, then the token should be burned and `Burn` event must be emitted. Otherwise (when `burn=false`) the registry must update token metadata and set expire date to a time in the past. Registry must not ban nor emit `Ban` event when revoking a contract. That would create an attack vector, when a malicious registry would thread the registry by banning accounts.
+
+#### Recoverability
+
+Standard defines issuer recoverability. At minimum, the standard registry exposes `sbt_recover` method, which allows issuer to reassign a token issued by him from one account to another.
+
+SBT recovery MUST not trigger `SoulTransfer` nor `Ban` event: malicious issuer could compromise the system by faking the token recovery and take over all other SBTs from a user. Only the owner of the account can make a Soul Transfer transaction and merge 2 accounts they owns.
+
+#### Recoverability within an SBT Registry
+
+SBT registry can define it's own mechanism to atomically recover all tokens related to one account and execute soul transfer to another account, without going one by one through each SBT issuer (sometimes that might be even not possible). Below we list few ideas a Registry can use to implement recovery:
+
+- KYC based recovery
+- Social recovery
+
+![Social Recovery, Image via “Decentralized Society”](https://bankless.ghost.io/content/images/public/images/cdb1fc23-6179-44f0-9bfe-e5e5831492f7_1399x680.png)
+
+SBT Registry based recovery is not part of this specification.
+
+#### Soul Transfer
+
+The basic use case is described above. Registry MUST provide a permissionless method to allow any user to execute soul transfer. It is essential part of the standard, but the exact interface of the method is not part of the standard, because registries may adopt different mechanism and require different arguments.
+
+Soul transfers must be _semi atomic_. That is, the holder account must be non operational (in terms of SBT supply) until the soul transfer is completed. Given the nature of NEAR blockchain, where transactions are limited by gas, big registries may require to implement the Soul Transfer operation in stages. Source and destination accounts should act as a non-soul accounts while the soul transfer operation is ongoing. For example, in the first call, contract can lock the account, and do maximum X amount of transfers. If the list of to be transferred SBTs has not been exhausted, the contract should keep locking the account and remember the last transferred SBT. Subsequent calls by the same user will resume the operation until the list is exhausted.
+Soul Transfer must emit the `SoulTransfer` event.
+
+Example: Alice has two accounts: `alice1` and `alice2` which she used to mint tokens (see [mint diagram](#minting)). She decides to merge the accounts by doing Soul Transfer.
+
+```mermaid
+sequenceDiagram
+ actor Alice
+ participant SBT_Registry
+
+ Alice->>SBT_Registry: sbt_soul_transfer(alice1) --accountId alice2
+
+ Alice-->>+SBT_Registry: sbt_tokens_by_owner(alice2)
+ SBT_Registry-->>-Alice: []
+
+ Alice-->>+SBT_Registry: sbt_tokens_by_owner(alice1)
+ SBT_Registry-->>-Alice: [[SBT_1_Contract, [238]], [SBT_2_Contract, [7991, 7992]]]}
+```
+
+Implementation Notes:
+
+- There is a risk of conflict. The standard requires that one account can't have more than one SBT of the same (issuer, class) pair.
+- When both `alice1` and `alice2` have SBT of the same (issuer, class) pair, then the transfer should fail. One of the accounts should burn conflicting tokens to be able to continue the soul transfer.
+- Soul transfer may require extra confirmation before executing a transfer. For example, if `alice1` wants to do a soul transfer to `alice2`, the contract my require `alice2` approval before continuing the transfer.
+- Other techniques may be used to enforce that the source account will be deleted.
+
+### Renewal
+
+Soulbound tokens can have an _expire date_. It is useful for tokens which are related to real world certificates with expire time, or social mechanisms (e.g. community membership). Such tokens SHOULD have an option to be renewable. Examples include mandatory renewal with a frequency to check that the owner is still alive, or renew membership to a DAO that uses SBTs as membership gating.
+Registry defines `sbt_renew` method allowing issuers to update the token expire date. The issuer can set a the _expire date_ in the past. This is useful if an issuer wants to invalidate the token without removing it.
+
+### Burning tokens
+
+Registry MAY expose a mechanism to allow an account to burn an unwanted token. The exact mechanism is not part of the standard and it will depend on the registry implementation. We only define a standard `Burn` event, which must be emitted each time a token is removed from existence. Some registries may forbid accounts to burn their tokens in order to preserve specific claims. Ultimately, NEAR is a public blockchain, and even if a token is burned, it's trace will be preserved.
+
+### Token Class (multitoken approach)
+
+SBT tokens can't be fractionized. Also, by definition, there should be only one SBT per token class per user. Examples: user should not be able to receive few badges of the same class, or few proof of attendance to the same event.
+However, we identify a need for having to support token classes (aka multitoken interface) in a single contract:
+
+- badges: one contract. Each badge will have a class (community lead, OG...), and each token will belong to a specific class;
+- certificates: one issuer can create certificates of a different class (eg school department can create diplomas for each major and each graduation year).
+
+We also see a trend in the NFT community and demand for market places to support multi token contracts.
+
+- In Ethereum community many projects are using [ERC-1155 Multi Token Standard](https://eips.ethereum.org/EIPS/eip-1155). NFT projects are using it for fraction ownership: each token id can have many fungible fractions.
+- NEAR [NEP-245](https://github.com/near/NEPs/blob/master/neps/nep-0245.md) has elaborated similar interface for both bridge compatibility with EVM chains as well as flexibility to define different token types with different behavior in a single contract. [DevGovGigs Board](https://near.social/#/mob.near/widget/MainPage.Post.Page?accountId=devgovgigs.near&blockHeight=87938945) recently also shows growing interest to move NEP-245 adoption forward.
+- [NEP-454](https://github.com/near/NEPs/pull/454) proposes royalties support for multi token contracts.
+
+We propose that the SBT Standard will support the multi-token idea from the get go. This won't increase the complexity of the contract (in a traditional case, where one contract will only issue tokens of the single class, the `class` argument is simply ignored in the state, and in the functions it's required to be of a constant value, eg `1`) but will unify the interface.
+It's up to the smart contract design how the token classes is managed. A smart contract can expose an admin function (example: `sbt_new_class() -> ClassId`) or hard code the pre-registered classes.
+
+Finally, we require that each token ID is unique within the smart contract. This will allow us to query token only by token ID, without knowing it's class.
+
+## Smart contract interface
+
+For the Token ID type we propose `u64` rather than `U128`. `u64` capacity is more than 1e19. If we will mint 10'000 SBTs per second, then it will take us 58'494'241 years to fill the capacity.
+Today, the JS integer limit is `2^53-1 ~ 9e15`. Similarly, when minting 10'000 SBTs per second, it will take us 28'561 years to reach the limit. So, we don't need u128 nor the String type. However, if for some reason, we will need to get u64 support for JS, then we can always add another set of methods which will return String, so making it compatible with NFT standard (which is using `U128`, which is a string). Also, it's worth to note, that in 28'000 years JS (if it will still exists) will be completely different.
+The number of combinations for a single issuer is much higher in fact: the token standard uses classes. So technically that makes the number of all possible combinations for a single issuer equal `(2^64)^2 ~ 1e38`. For "today" JS it is `(2^53-1)^2 ~ 1e31`.
+
+Token IDs MUST be created in a sequence to make sure the ID space is not exhausted locally (eg if a registry would decide to introduce segments, it would potentially get into a trap where one of the segments is filled up very quickly).
+
+```rust
+// TokenId and ClassId must be positive (0 is not a valid ID)
+pub type TokenId = u64;
+pub type ClassId = u64;
+
+pub struct Token {
+ pub token: TokenId,
+ pub owner: AccountId,
+ pub metadata: TokenMetadata,
+}
+```
+
+The Soulbound Token follows the NFT [NEP-171](https://github.com/near/NEPs/blob/master/neps/nep-0171.md) interface, with few differences:
+
+- token ID is `u64` (as discussed above).
+- token class is `u64`, it's required when minting and it's part of the token metadata.
+- `TokenMetadata` doesn't have `title`, `description`, `media`, `media_hash`, `copies`, `extra`, `starts_at` nor `updated_at`. All that attributes except the `updated_at` can be part of the document stored at `reference`. `updated_at` can be tracked easily by indexers.
+- We don't have traditional transferability.
+- We propose to use more targeted events, to better reflect the event nature. Moreover events are emitted by the registry, so we need to include issuer contract address in the event.
+
+All time related attributes are defined in milliseconds (as per NEP-171).
+
+```rust
+/// ContractMetadata defines contract wide attributes, which describes the whole contract.
+pub struct ContractMetadata {
+ /// Version with namespace, example: "sbt-1.0.0". Required.
+ pub spec: String,
+ /// Issuer Name, required, ex. "Mosaics"
+ pub name: String,
+ /// Issuer symbol which can be used as a token symbol, eg Ⓝ, ₿, BTC, MOSAIC ...
+ pub symbol: String,
+ /// Icon content (SVG) or a link to an Icon. If it doesn't start with a scheme (eg: https://)
+ /// then `base_uri` should be prepended.
+ pub icon: Option,
+ /// URI prefix which will be prepended to other links which don't start with a scheme
+ /// (eg: ipfs:// or https:// ...).
+ pub base_uri: Option,
+ /// JSON or an URL to a JSON file with more info. If it doesn't start with a scheme
+ /// (eg: https://) then base_uri should be prepended.
+ pub reference: Option,
+ /// Base64-encoded sha256 hash of JSON from reference field. Required if `reference` is included.
+ pub reference_hash: Option,
+}
+
+/// TokenMetadata defines attributes for each SBT token.
+pub struct TokenMetadata {
+ pub class: ClassId, // token class. Required. Must be non zero.
+ pub issued_at: Option, // When token was issued or minted, Unix time in milliseconds
+ pub expires_at: Option, // When token expires, Unix time in milliseconds
+ /// JSON or an URL to a JSON file with more info. If it doesn't start with a scheme
+ /// (eg: https://) then base_uri should be prepended.
+ pub reference: Option,
+ /// Base64-encoded sha256 hash of JSON from reference field. Required if `reference` is included.
+ pub reference_hash: Option,
+}
+
+
+trait SBTRegistry {
+ /**********
+ * QUERIES
+ **********/
+
+ /// Get the information about specific token ID issued by `issuer` SBT contract.
+ fn sbt(&self, issuer: AccountId, token: TokenId) -> Option;
+
+ /// Get the information about list of token IDs issued by the `issuer` SBT contract.
+ /// If token ID is not found `None` is set in the specific return index.
+ fn sbts(&self, issuer: AccountId, token: Vec) -> Vec