Skip to content

Commit 1b0a058

Browse files
committed
Initial
1 parent 1b80a7f commit 1b0a058

2 files changed

Lines changed: 308 additions & 102 deletions

File tree

contracts/kiosk/sources/kiosk/ob_kiosk.move

Lines changed: 144 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ module ob_kiosk::ob_kiosk {
3939
use sui::dynamic_field::{Self as df};
4040
use sui::kiosk::{Self, Kiosk, KioskOwnerCap, uid, uid_mut as ext};
4141
use sui::object::{Self, ID, UID, uid_to_address};
42-
use sui::coin;
42+
use sui::coin::{Self, Coin};
4343
use sui::table::{Self, Table};
4444
use sui::transfer::{transfer, public_share_object, public_transfer};
4545
use sui::tx_context::{Self, TxContext, sender};
@@ -55,6 +55,7 @@ module ob_kiosk::ob_kiosk {
5555
// Track the current version of the module
5656
const VERSION: u64 = 3;
5757

58+
const EDeprecatedApi: u64 = 998;
5859
const ENotUpgraded: u64 = 999;
5960
const EWrongVersion: u64 = 1000;
6061

@@ -328,8 +329,11 @@ module ob_kiosk::ob_kiosk {
328329
assert_version_and_upgrade(ext(self));
329330
assert_can_deposit<T>(self, ctx);
330331

332+
let nft_id = object::id(&nft);
333+
331334
let cap = pop_cap(self);
332-
deposit_(self, &cap, nft);
335+
kiosk::place(self, &cap, nft);
336+
register_nft_(self, nft_id);
333337
set_cap(self, cap);
334338
}
335339

@@ -353,29 +357,41 @@ module ob_kiosk::ob_kiosk {
353357
let cap = pop_cap(self);
354358
while (!vector::is_empty(&nfts)) {
355359
let nft = vector::pop_back(&mut nfts);
356-
deposit_(self, &cap, nft);
360+
let nft_id = object::id(&nft);
361+
kiosk::place(self, &cap, nft);
362+
register_nft_(self, nft_id);
357363
};
358364

359365
vector::destroy_empty(nfts);
360366
set_cap(self, cap);
361367
}
362368

363-
/// Deposits NFT into `Kiosk` and handles `NftRef` accounting
364-
fun deposit_<T: key + store>(
369+
/// Deposit an NFT and lock it within the `Kiosk`
370+
///
371+
/// NFTs deposited using `deposit_locked` must use `transfer_locked_nft` to
372+
/// transfer the NFT.
373+
///
374+
/// Useful for interacting with non-OB collections.
375+
///
376+
/// #### Panics
377+
///
378+
/// Panics if transaction sender is not owner or `Kiosk` is not
379+
/// permissionless.
380+
public fun deposit_locked<T: key + store>(
365381
self: &mut Kiosk,
366-
cap: &KioskOwnerCap,
382+
policy: &sui::transfer_policy::TransferPolicy<T>,
367383
nft: T,
384+
ctx: &mut TxContext,
368385
) {
369-
let nft_id = object::id(&nft);
386+
assert_version_and_upgrade(ext(self));
387+
assert_can_deposit<T>(self, ctx);
370388

371-
let refs = nft_refs_mut(self);
372-
table::add(refs, nft_id, NftRef {
373-
auths: vec_set::empty(),
374-
is_exclusively_listed: false,
375-
});
389+
let nft_id = object::id(&nft);
376390

377-
// place underlying NFT to kiosk
378-
kiosk::place(self, cap, nft);
391+
let cap = pop_cap(self);
392+
kiosk::lock(self, &cap, policy, nft);
393+
register_nft_(self, nft_id);
394+
set_cap(self, cap);
379395
}
380396

381397
// === Withdraw from the Kiosk ===
@@ -522,6 +538,8 @@ module ob_kiosk::ob_kiosk {
522538

523539
/// Transfer NFT out of Kiosk that has been previously delegated
524540
///
541+
/// NFT will not be locked in the target `Kiosk`.
542+
///
525543
/// Requires that address of sender was previously passed to
526544
/// `auth_transfer`.
527545
///
@@ -546,6 +564,35 @@ module ob_kiosk::ob_kiosk {
546564
req
547565
}
548566

567+
/// Transfer NFT out of Kiosk that has been previously delegated
568+
///
569+
/// NFT will be locked in the target `Kiosk`.
570+
///
571+
/// Requires that address of sender was previously passed to
572+
/// `auth_transfer`.
573+
///
574+
/// #### Panics
575+
///
576+
/// - Entity `UID` was not previously authorized for transfer
577+
/// - NFT does not exist
578+
/// - Target `Kiosk` deposit conditions were not met, see `deposit` method
579+
/// - Source or target `Kiosk` are not OriginByte kiosks
580+
public fun transfer_delegated_locked<T: key + store>(
581+
source: &mut Kiosk,
582+
target: &mut Kiosk,
583+
nft_id: ID,
584+
entity_id: &UID,
585+
price: u64,
586+
transfer_policy: &sui::transfer_policy::TransferPolicy<T>,
587+
ctx: &mut TxContext,
588+
): TransferRequest<T> {
589+
assert_version_and_upgrade(ext(source));
590+
591+
let (nft, req) = transfer_nft_(source, nft_id, uid_to_address(entity_id), price, ctx);
592+
deposit_locked(target, transfer_policy, nft, ctx);
593+
req
594+
}
595+
549596
/// Transfer NFT out of Kiosk that has been previously delegated
550597
///
551598
/// Requires that address of sender was previously passed to
@@ -576,8 +623,10 @@ module ob_kiosk::ob_kiosk {
576623
req
577624
}
578625

579-
/// Transfer NFT out of Kiosk that has been previously delegated to a base
580-
/// Sui `Kiosk`
626+
/// Transfer locked NFT out of Kiosk that has been previously delegated to
627+
/// a base Sui `Kiosk`
628+
///
629+
/// The transferred NFT is immediately locked in the target `Kiosk`.
581630
///
582631
/// Requires that `UID` of sender was previously passed to either
583632
/// `auth_transfer` or `auth_exclusive_transfer`.
@@ -589,29 +638,81 @@ module ob_kiosk::ob_kiosk {
589638
/// - Sender was not previously authorized for transfer or is not owner
590639
/// - NFT does not exist
591640
/// - Source is not an OriginByte `Kiosk`
592-
public fun transfer_locked_nft<T: key + store>(
641+
public fun transfer_locked<T: key + store>(
593642
source: &mut Kiosk,
594643
target: &mut Kiosk,
595644
nft_id: ID,
596645
entity_id: &UID,
646+
paid: Coin<sui::sui::SUI>,
647+
transfer_policy: &sui::transfer_policy::TransferPolicy<T>,
597648
ctx: &mut TxContext,
598649
): TransferRequest<T> {
599650
assert_version_and_upgrade(ext(source));
600651

601652
check_entity_and_pop_ref(source, uid_to_address(entity_id), nft_id, ctx);
602653

603654
let cap = pop_cap(source);
604-
kiosk::list<T>(source, &cap, nft_id, 0);
655+
kiosk::list<T>(source, &cap, nft_id, coin::value(&paid));
605656
set_cap(source, cap);
606657

607-
let (nft, req) = kiosk::purchase<T>(source, nft_id, coin::zero(ctx));
658+
let (nft, req) = kiosk::purchase<T>(source, nft_id, paid);
659+
deposit_locked(target, transfer_policy, nft, ctx);
660+
661+
let req = transfer_request::from_sui<T>(req, nft_id, uid_to_address(entity_id), ctx);
662+
663+
req
664+
}
665+
666+
/// Transfer locked NFT out of Kiosk that has been previously delegated to
667+
/// a base Sui `Kiosk`
668+
///
669+
/// The transferred NFT is not locked in the target `Kiosk`.
670+
///
671+
/// Requires that `UID` of sender was previously passed to either
672+
/// `auth_transfer` or `auth_exclusive_transfer`.
673+
///
674+
/// Will always work if transaction sender is the `Kiosk` owner.
675+
///
676+
/// #### Panics
677+
///
678+
/// - Sender was not previously authorized for transfer or is not owner
679+
/// - NFT does not exist
680+
/// - Source is not an OriginByte `Kiosk`
681+
public fun transfer_unlocked<T: key + store>(
682+
source: &mut Kiosk,
683+
target: &mut Kiosk,
684+
nft_id: ID,
685+
entity_id: &UID,
686+
paid: Coin<sui::sui::SUI>,
687+
ctx: &mut TxContext,
688+
): TransferRequest<T> {
689+
assert_version_and_upgrade(ext(source));
690+
691+
check_entity_and_pop_ref(source, uid_to_address(entity_id), nft_id, ctx);
692+
693+
let cap = pop_cap(source);
694+
kiosk::list<T>(source, &cap, nft_id, coin::value(&paid));
695+
set_cap(source, cap);
696+
697+
let (nft, req) = kiosk::purchase<T>(source, nft_id, paid);
608698
deposit(target, nft, ctx);
609699

610700
let req = transfer_request::from_sui<T>(req, nft_id, uid_to_address(entity_id), ctx);
611701

612702
req
613703
}
614704

705+
/// Deprecated, use `transfer_locked` instead
706+
public fun transfer_locked_nft<T: key + store>(
707+
_source: &mut Kiosk,
708+
_target: &mut Kiosk,
709+
_nft_id: ID,
710+
_entity_id: &UID,
711+
_ctx: &mut TxContext,
712+
): TransferRequest<T> {
713+
abort(EDeprecatedApi)
714+
}
715+
615716
/// Withdraw NFT from `Kiosk` without returning it
616717
///
617718
/// Requires that `UID` of sender was previously passed to either
@@ -819,6 +920,8 @@ module ob_kiosk::ob_kiosk {
819920
assert!(kiosk::has_access(self, &kiosk_cap), ENotOwner);
820921
assert!(!is_ob_kiosk(self), EKioskOriginByteVersion);
821922

923+
// Ensure that `uid_mut` will work
924+
kiosk::set_allow_extensions(self, &kiosk_cap, true);
822925
let kiosk_ext = ext(self);
823926

824927
df::add(kiosk_ext, VersionDfKey {}, VERSION);
@@ -849,12 +952,21 @@ module ob_kiosk::ob_kiosk {
849952
assert_version_and_upgrade(ext(self));
850953
assert_permission(self, ctx);
851954

852-
// Assert that Kiosk has NFT
955+
register_nft_(self, nft_id);
956+
}
957+
958+
/// Create an `NftRef` entry for the NFT
959+
///
960+
/// #### Panics
961+
///
962+
/// Panics if `NftRef` already exists
963+
fun register_nft_(
964+
self: &mut Kiosk,
965+
nft_id: ID,
966+
) {
853967
assert_has_nft(self, nft_id);
854968
assert!(!kiosk::is_listed(self, nft_id), ENftIsListedInBaseKiosk);
855969

856-
// Assert that Kiosk has no NftRef, which means the NFT was
857-
// placed in the Kiosk before installing the OB extension
858970
let refs = nft_refs_mut(self);
859971
assert_missing_ref(refs, nft_id);
860972

@@ -1164,6 +1276,8 @@ module ob_kiosk::ob_kiosk {
11641276
df::exists_(uid(self), NftRefsDfKey {})
11651277
}
11661278

1279+
/// Returns whether the current transaction sender can deposit into `Kiosk`
1280+
///
11671281
/// Either sender is owner or permissionless deposits of `T` enabled.
11681282
public fun can_deposit<T>(self: &mut Kiosk, ctx: &mut TxContext): bool {
11691283
sender(ctx) == kiosk::owner(self) || can_deposit_permissionlessly<T>(self)
@@ -1189,7 +1303,6 @@ module ob_kiosk::ob_kiosk {
11891303
/// Panics if `Kiosk` is not OriginByte `Kiosk`
11901304
//
11911305
// TODO: Replace with immutable API
1192-
// TODO: Consider removing test_only
11931306
public fun nft_refs(self: &Kiosk): &Table<ID, NftRef> {
11941307
is_ob_kiosk_imut(self);
11951308
df::borrow(uid(self), NftRefsDfKey {})
@@ -1221,6 +1334,11 @@ module ob_kiosk::ob_kiosk {
12211334
assert!(is_permissionless(self), EKioskNotPermissionless);
12221335
}
12231336

1337+
/// Asserts that the transaction sender may deposit into `Kiosk`
1338+
///
1339+
/// #### Panics
1340+
///
1341+
/// Panics if sender is not owner or `Kiosk` is not permissionless.
12241342
public fun assert_can_deposit<T>(self: &mut Kiosk, ctx: &mut TxContext) {
12251343
assert!(can_deposit<T>(self, ctx), ECannotDeposit);
12261344
}
@@ -1296,7 +1414,7 @@ module ob_kiosk::ob_kiosk {
12961414
assert!(vec_set::size(&ref.auths) == 0, ENftAlreadyListed);
12971415
}
12981416

1299-
/// Check whether NFT can be transferred by given authority
1417+
/// Check whether NFT can be transferred by given authority and remove the NftRef entry
13001418
///
13011419
/// #### Panics
13021420
///
@@ -1307,7 +1425,7 @@ module ob_kiosk::ob_kiosk {
13071425
entity: address,
13081426
nft_id: ID,
13091427
ctx: &mut TxContext,
1310-
) {
1428+
): NftRef {
13111429
let refs = nft_refs_mut(self);
13121430
// NFT is being transferred - destroy the ref
13131431
let ref: NftRef = table::remove(refs, nft_id);
@@ -1316,6 +1434,7 @@ module ob_kiosk::ob_kiosk {
13161434
is_owner(self, sender(ctx)) || vec_set::contains(&ref.auths, &entity),
13171435
ENotAuthorized,
13181436
);
1437+
ref
13191438
}
13201439

13211440
/// Borrow `DepositSetting` field

0 commit comments

Comments
 (0)