Module of UnprotectedSafe
type.
UnprotectedSafe
is an abstraction meant to hold NFTs in it.
A user that transfers its NFTs to its Safe is able to delegate the power
of transferability.
One typical issue with on-chain trading is that by sending one's assets
to a shared object (the trading primitive), one looses the ability to
see them in their wallet, even though one has still technical ownership
of such assets, until a trade is effectively executed.
To solve for this, we use UnprotectedSafe
to hold the user's assets
and then instead of transferring the assets to the shared object
(trading primitive), the user transfers a TransferCap
TransferCap
is an object that delegates the ability to transfer a
given NFT out of the seller's Safe
.
The ownership model of the Safe
relies on the object OwnerCap
whose
holder is the effective owner of the Safe
and subsequently the owner of
the assets within it.
Two NFT kinds
We support two kinds of NFTs in this safe implementation.
- Our protocol
nft_protocol::nft::Nft
which is guarded with allowlist. This enables creators to have certain guarantees around royalty enforcement. - Arbitrary type of NFTs. Those are not guarded with allowlist. They can be freely transferred between users and safes.
Structs
unprotected_safe::UnprotectedSafe has store, key
unprotected_safe::UnprotectedSafe has store, key
Fields:
Name | Type | Description |
---|---|---|
id
|
object::UID
|
|
refs
|
vec_map::VecMap<object::ID, unprotected_safe::NftRef>
|
Accounting for deposited NFTs. Each NFT in the object bag is represented in this map. |
unprotected_safe::NftRef has copy, drop, store
unprotected_safe::NftRef has copy, drop, store
Fields:
Name | Type | Description |
---|---|---|
version
|
object::ID
|
Is generated anew every time a counter is incremented from zero to one. We don't use monotonically increasing integer so that we can remove withdrawn NFTs from the map. |
transfer_cap_counter
|
u64
|
How many transfer caps are there for this version. |
is_exclusively_listed
|
bool
|
Only one |
is_generic
|
bool
|
Signalizes whether given NFT is wrapped in our NFT type (nft::Nft) or whether it's a 3rd party type. This has implications on how the NFT is transferred. |
object_type
|
type_name::TypeName
|
What's the NFT type. If it's not generic, it will contain the |
Keeps info about an NFT which enables us to issue transfer caps etc.
unprotected_safe::OwnerCap has store, key
unprotected_safe::OwnerCap has store, key
Fields:
Name | Type | Description |
---|---|---|
id
|
object::UID
|
|
safe
|
object::ID
|
Whoever owns this object can perform some admin actions against the
Safe
shared object with the corresponding id.
unprotected_safe::TransferCap has store, key
unprotected_safe::TransferCap has store, key
Fields:
Name | Type | Description |
---|---|---|
id
|
object::UID
|
|
safe
|
object::ID
|
|
nft
|
object::ID
|
|
version
|
object::ID
|
|
is_exclusive
|
bool
|
If set to true, only one This is useful for trading flows that cannot guarantee that the NFT is claimed atomically. If an NFT is listed exclusively, it cannot be revoked without
burning the |
is_generic
|
bool
|
Signalizes whether given NFT is wrapped in our NFT type (nft::Nft) or whether it's a 3rd party type. This has implications on how the NFT is transferred. |
object_type
|
type_name::TypeName
|
What's the NFT type. If it's not generic, it will contain the |
Enables the owner to transfer given NFT out of the Safe
.
unprotected_safe::DepositEvent has copy, drop
unprotected_safe::DepositEvent has copy, drop
Fields:
Name | Type | Description |
---|---|---|
safe
|
object::ID
|
|
nft
|
object::ID
|
unprotected_safe::TransferEvent has copy, drop
unprotected_safe::TransferEvent has copy, drop
Fields:
Name | Type | Description |
---|---|---|
safe
|
object::ID
|
|
nft
|
object::ID
|
Methods
public fun new(
ctx: &mut tx_context::TxContext,
):
(unprotected_safe::UnprotectedSafe, unprotected_safe::OwnerCap)
public fun new(
ctx: &mut tx_context::TxContext,
):
(unprotected_safe::UnprotectedSafe, unprotected_safe::OwnerCap)
public entry fun create_for_sender(
ctx: &mut tx_context::TxContext,
)
public entry fun create_for_sender(
ctx: &mut tx_context::TxContext,
)
Instantiates a new shared object Safe
and transfer OwnerCap
to the
tx sender.
public fun create_safe(ctx: &mut tx_context::TxContext):
unprotected_safe::OwnerCap
public fun create_safe(ctx: &mut tx_context::TxContext):
unprotected_safe::OwnerCap
Creates a new Safe
shared object and returns the authority capability
that grants authority over this safe.
public fun create_transfer_cap(
nft: object::ID,
owner_cap: &unprotected_safe::OwnerCap,
safe: &mut unprotected_safe::UnprotectedSafe,
ctx: &mut tx_context::TxContext,
): unprotected_safe::TransferCap
public fun create_transfer_cap(
nft: object::ID,
owner_cap: &unprotected_safe::OwnerCap,
safe: &mut unprotected_safe::UnprotectedSafe,
ctx: &mut tx_context::TxContext,
): unprotected_safe::TransferCap
Creates a TransferCap
which must be claimed atomically.
Otherwise, there's a risk of a race condition as multiple non-exclusive transfer caps can be created.
public fun create_exclusive_transfer_cap(
nft: object::ID,
owner_cap: &unprotected_safe::OwnerCap,
safe: &mut unprotected_safe::UnprotectedSafe,
ctx: &mut tx_context::TxContext,
): unprotected_safe::TransferCap
public fun create_exclusive_transfer_cap(
nft: object::ID,
owner_cap: &unprotected_safe::OwnerCap,
safe: &mut unprotected_safe::UnprotectedSafe,
ctx: &mut tx_context::TxContext,
): unprotected_safe::TransferCap
Creates an irrevocable and exclusive transfer cap.
Useful for trading contracts which cannot claim an NFT atomically.
public entry fun deposit_nft<T>(
nft: nft::Nft<T>,
safe: &mut unprotected_safe::UnprotectedSafe,
ctx: &mut tx_context::TxContext,
)
public entry fun deposit_nft<T>(
nft: nft::Nft<T>,
safe: &mut unprotected_safe::UnprotectedSafe,
ctx: &mut tx_context::TxContext,
)
Transfer an NFT into the Safe
.
public entry fun deposit_generic_nft<T: store + key>(
nft: T,
safe: &mut unprotected_safe::UnprotectedSafe,
ctx: &mut tx_context::TxContext,
)
public entry fun deposit_generic_nft<T: store + key>(
nft: T,
safe: &mut unprotected_safe::UnprotectedSafe,
ctx: &mut tx_context::TxContext,
)
Transfer an NFT into the Safe
.
The type T here can refer to any object, not just the NFT protocol's exported NFT type.
public fun transfer_nft_to_recipient<T, Auth: drop>(
transfer_cap: unprotected_safe::TransferCap,
recipient: address,
authority: Auth,
allowlist: &transfer_allowlist::Allowlist,
safe: &mut unprotected_safe::UnprotectedSafe,
)
public fun transfer_nft_to_recipient<T, Auth: drop>(
transfer_cap: unprotected_safe::TransferCap,
recipient: address,
authority: Auth,
allowlist: &transfer_allowlist::Allowlist,
safe: &mut unprotected_safe::UnprotectedSafe,
)
Use a transfer cap to get an NFT out of the Safe
.
If the NFT is not exclusively listed, it can happen that the transfer cap is no longer valid. The NFT could've been traded or the trading cap revoked.
public fun transfer_generic_nft_to_recipient<T: store + key>(
transfer_cap: unprotected_safe::TransferCap,
recipient: address,
safe: &mut unprotected_safe::UnprotectedSafe,
)
public fun transfer_generic_nft_to_recipient<T: store + key>(
transfer_cap: unprotected_safe::TransferCap,
recipient: address,
safe: &mut unprotected_safe::UnprotectedSafe,
)
public fun transfer_nft_to_safe<T, Auth: drop>(
transfer_cap: unprotected_safe::TransferCap,
recipient: address,
authority: Auth,
allowlist: &transfer_allowlist::Allowlist,
source: &mut unprotected_safe::UnprotectedSafe,
target: &mut unprotected_safe::UnprotectedSafe,
ctx: &mut tx_context::TxContext,
)
public fun transfer_nft_to_safe<T, Auth: drop>(
transfer_cap: unprotected_safe::TransferCap,
recipient: address,
authority: Auth,
allowlist: &transfer_allowlist::Allowlist,
source: &mut unprotected_safe::UnprotectedSafe,
target: &mut unprotected_safe::UnprotectedSafe,
ctx: &mut tx_context::TxContext,
)
Use a transfer cap to get an NFT out of source Safe
and deposit it
to the target Safe
. The recipient address should match the owner of
the target Safe
.
If the NFT is not exclusively listed, it can happen that the transfer cap is no longer valid. The NFT could've been traded or the trading cap revoked.
public fun transfer_generic_nft_to_safe<T: store + key>(
transfer_cap: unprotected_safe::TransferCap,
source: &mut unprotected_safe::UnprotectedSafe,
target: &mut unprotected_safe::UnprotectedSafe,
ctx: &mut tx_context::TxContext,
)
public fun transfer_generic_nft_to_safe<T: store + key>(
transfer_cap: unprotected_safe::TransferCap,
source: &mut unprotected_safe::UnprotectedSafe,
target: &mut unprotected_safe::UnprotectedSafe,
ctx: &mut tx_context::TxContext,
)
public entry fun burn_transfer_cap(
transfer_cap: unprotected_safe::TransferCap,
safe: &mut unprotected_safe::UnprotectedSafe,
)
public entry fun burn_transfer_cap(
transfer_cap: unprotected_safe::TransferCap,
safe: &mut unprotected_safe::UnprotectedSafe,
)
Destroys given transfer cap. This is mainly useful for exclusively listed NFTs.
public entry fun delist_nft(
nft: object::ID,
owner_cap: &unprotected_safe::OwnerCap,
safe: &mut unprotected_safe::UnprotectedSafe,
ctx: &mut tx_context::TxContext,
)
public entry fun delist_nft(
nft: object::ID,
owner_cap: &unprotected_safe::OwnerCap,
safe: &mut unprotected_safe::UnprotectedSafe,
ctx: &mut tx_context::TxContext,
)
Changes the transfer ref version, thereby invalidating all existing
TransferCap
objects.
Can happen only if the NFT is not listed exclusively.
public fun borrow_nft<C>(
nft: object::ID,
safe: &unprotected_safe::UnprotectedSafe,
): &nft::Nft<C>
public fun borrow_nft<C>(
nft: object::ID,
safe: &unprotected_safe::UnprotectedSafe,
): &nft::Nft<C>
public fun has_nft<C>(
nft: object::ID,
safe: &unprotected_safe::UnprotectedSafe,
): bool
public fun has_nft<C>(
nft: object::ID,
safe: &unprotected_safe::UnprotectedSafe,
): bool
public fun borrow_generic_nft<C: store + key>(
nft: object::ID,
safe: &unprotected_safe::UnprotectedSafe,
): &C
public fun borrow_generic_nft<C: store + key>(
nft: object::ID,
safe: &unprotected_safe::UnprotectedSafe,
): &C
public fun has_generic_nft<T: store + key>(
nft: object::ID,
safe: &unprotected_safe::UnprotectedSafe,
): bool
public fun has_generic_nft<T: store + key>(
nft: object::ID,
safe: &unprotected_safe::UnprotectedSafe,
): bool
public fun owner_cap_safe(cap: &unprotected_safe::OwnerCap):
object::ID
public fun owner_cap_safe(cap: &unprotected_safe::OwnerCap):
object::ID
public fun transfer_cap_safe(
cap: &unprotected_safe::TransferCap,
): object::ID
public fun transfer_cap_safe(
cap: &unprotected_safe::TransferCap,
): object::ID
public fun transfer_cap_nft(
cap: &unprotected_safe::TransferCap,
): object::ID
public fun transfer_cap_nft(
cap: &unprotected_safe::TransferCap,
): object::ID
public fun transfer_cap_object_type(
cap: &unprotected_safe::TransferCap,
): type_name::TypeName
public fun transfer_cap_object_type(
cap: &unprotected_safe::TransferCap,
): type_name::TypeName
public fun transfer_cap_version(
cap: &unprotected_safe::TransferCap,
): object::ID
public fun transfer_cap_version(
cap: &unprotected_safe::TransferCap,
): object::ID
public fun transfer_cap_is_exclusive(
cap: &unprotected_safe::TransferCap,
): bool
public fun transfer_cap_is_exclusive(
cap: &unprotected_safe::TransferCap,
): bool
public fun transfer_cap_is_nft_generic(
cap: &unprotected_safe::TransferCap,
): bool
public fun transfer_cap_is_nft_generic(
cap: &unprotected_safe::TransferCap,
): bool
public fun assert_owner_cap(
cap: &unprotected_safe::OwnerCap,
safe: &unprotected_safe::UnprotectedSafe,
)
public fun assert_owner_cap(
cap: &unprotected_safe::OwnerCap,
safe: &unprotected_safe::UnprotectedSafe,
)
public fun assert_transfer_cap_of_safe(
cap: &unprotected_safe::TransferCap,
safe: &unprotected_safe::UnprotectedSafe,
)
public fun assert_transfer_cap_of_safe(
cap: &unprotected_safe::TransferCap,
safe: &unprotected_safe::UnprotectedSafe,
)
public fun assert_nft_of_transfer_cap(
nft: &object::ID,
cap: &unprotected_safe::TransferCap,
)
public fun assert_nft_of_transfer_cap(
nft: &object::ID,
cap: &unprotected_safe::TransferCap,
)
public fun assert_has_nft(
nft: &object::ID,
safe: &unprotected_safe::UnprotectedSafe,
)
public fun assert_has_nft(
nft: &object::ID,
safe: &unprotected_safe::UnprotectedSafe,
)
public fun assert_not_exclusively_listed(
cap: &unprotected_safe::TransferCap,
)
public fun assert_not_exclusively_listed(
cap: &unprotected_safe::TransferCap,
)
public fun assert_id(
safe: &unprotected_safe::UnprotectedSafe,
id: object::ID,
)
public fun assert_id(
safe: &unprotected_safe::UnprotectedSafe,
id: object::ID,
)
public fun assert_transfer_cap_exclusive(
cap: &unprotected_safe::TransferCap,
)
public fun assert_transfer_cap_exclusive(
cap: &unprotected_safe::TransferCap,
)
public fun assert_transfer_cap_of_native_nft(
cap: &unprotected_safe::TransferCap,
)
public fun assert_transfer_cap_of_native_nft(
cap: &unprotected_safe::TransferCap,
)
public fun assert_nft_type<C>(
cap: &unprotected_safe::TransferCap,
)
public fun assert_nft_type<C>(
cap: &unprotected_safe::TransferCap,
)
Checks that the transfer cap is issued for an NFT of type Nft<C>
public fun assert_generic_nft_type<C>(
cap: &unprotected_safe::TransferCap,
)
public fun assert_generic_nft_type<C>(
cap: &unprotected_safe::TransferCap,
)
Checks that the transfer cap is issued for an NFT of type C