Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
39 changes: 37 additions & 2 deletions contracts/allowlist/sources/allowlist.move
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,55 @@ module allowlist::allowlist {
use nft_protocol::bidding;
use nft_protocol::orderbook;
use nft_protocol::transfer_allowlist;
use nft_protocol::ob_kiosk;

struct ALLOWLIST has drop {}

fun init(_otw: ALLOWLIST, ctx: &mut TxContext) {
let (al, al_cap) = transfer_allowlist::new(ctx);

// orderbooks can perform trades with our allowlist
// OB Kiosk is a trusted type for receiving NFTs
transfer_allowlist::insert_authority<ob_kiosk::Witness>(&al_cap, &mut al);
transfer_allowlist::insert_authority<orderbook::Witness>(&al_cap, &mut al);
// bidding contract can perform trades too
transfer_allowlist::insert_authority<bidding::Witness>(&al_cap, &mut al);

// Delete `AllowlistOwnerCap` to guarantee that each release of
// `OriginByte` always has a fixed set of trading contracts
transfer::public_transfer(al_cap, tx_context::sender(ctx));
transfer::public_share_object(al);
}

#[test_only]
use sui::object::{Self, UID};
#[test_only]
use sui::test_scenario::{Self, ctx};

#[test_only]
use nft_protocol::ob_transfer_request;

#[test_only]
const USER: address = @0xA1C04;

#[test_only]
struct Foo has key, store {
id: UID,
}

#[test_only]
struct FOO {}

#[test]
fun test_peer_to_peer_flow() {
let scenario = test_scenario::begin(USER);

init(ALLOWLIST {}, ctx(&mut scenario));

let (policy, cap) =
ob_transfer_request::init_policy<Foo>(publisher, ctx);
}

#[test]
fun test_bidding_flow() {

}
}
2 changes: 1 addition & 1 deletion example_collections/examples/sources/testract.move
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ module examples::testract {
// and now for confirming transfer
// (see `register_allowlist_and_royalty_strategy` and `create_allowlist`)

transfer_allowlist::confirm_transfer(allowlist, &mut transfer_req);
transfer_allowlist::confirm_transfer(&mut transfer_req, allowlist);
royalty_strategy_bps::confirm_transfer<TestNft, SUI>(royalty_strategy, &mut transfer_req);

// only if both rules are OK can we destroy the hot potato
Expand Down
118 changes: 69 additions & 49 deletions sources/kiosk/ob_kiosk.move
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,16 @@ module nft_protocol::ob_kiosk {
use nft_protocol::ob_transfer_request::{Self, TransferRequest};
use nft_protocol::withdraw_request::{Self, WithdrawRequest};
use nft_protocol::borrow_request::{Self, BorrowRequest, BORROW_REQUEST};
use nft_protocol::request::{Self, Policy, RequestBody, WithNft};
use nft_protocol::request::{Policy, RequestBody, WithNft};
use nft_protocol::utils;
use originmate::typed_id::{Self, TypedID};
use nft_protocol::rule_deposit;
use nft_protocol::rule_withdraw;

use std::option::Option;
use std::string::utf8;
use std::type_name::{Self, TypeName};

use sui::display;
use sui::dynamic_field::{Self as df};
use sui::kiosk::{Self, Kiosk, KioskOwnerCap, uid_mut as ext};
Expand Down Expand Up @@ -140,8 +144,6 @@ module nft_protocol::ob_kiosk {
struct KioskOwnerCapDfKey has store, copy, drop {}
/// For `Kiosk::id` value `DepositSetting`
struct DepositSettingDfKey has store, copy, drop {}
/// For `TransferRequest::metadata` value `TypeName`
struct AuthTransferRequestDfKey has store, copy, drop {}

// === Instantiators ===

Expand Down Expand Up @@ -222,11 +224,16 @@ module nft_protocol::ob_kiosk {

// === Deposit to the Kiosk ===

/// Always works if the sender is the owner.
/// Fails if permissionless deposits are not enabled for `T`.
/// See `DepositSetting`.
/// Deposit NFT into `Kiosk`
///
/// #### Panics
///
/// Panics if permissionless deposits are not enabled for `T` and
/// transaction sender is not owner, see `DepositSetting`.
public fun deposit<T: key + store>(
self: &mut Kiosk, nft: T, ctx: &mut TxContext,
self: &mut Kiosk,
nft: T,
ctx: &mut TxContext,
) {
assert_can_deposit<T>(self, ctx);

Expand All @@ -245,6 +252,27 @@ module nft_protocol::ob_kiosk {
set_cap(self, cap);
}

/// Deposit NFT into `Kiosk` in the context of a protected transfer
///
/// Registers `DepositRule` metadata on transfer request.
///
/// #### Panics
///
/// Panics if permissionless deposits are not enabled for `T` and
/// transaction sender is not owner, see `DepositSetting`.
public fun deposit_transfer<T: key + store, P>(
req: &mut RequestBody<WithNft<T, P>>,
self: &mut Kiosk,
nft: T,
ctx: &mut TxContext,
) {
let deposit_rule = rule_deposit::new(
Witness {}, &nft, object::id_address(self),
);
rule_deposit::register_metadata(req, deposit_rule);
deposit(self, nft, ctx)
}

// === Withdraw from the Kiosk ===

/// Authorizes given entity to take given NFT out.
Expand Down Expand Up @@ -312,9 +340,14 @@ module nft_protocol::ob_kiosk {
entity_id: &UID,
ctx: &mut TxContext,
): TransferRequest<T> {
let (nft, builder) = transfer_nft_(source, nft_id, uid_to_address(entity_id), ctx);
deposit(target, nft, ctx);
builder
let (nft, req) = transfer_nft_(source, nft_id, uid_to_address(entity_id), ctx);
deposit_transfer(
ob_transfer_request::inner_mut(&mut req),
target,
nft,
ctx,
);
req
}

/// Similar to `transfer_delegated` but instead of proving origin with
Expand All @@ -327,9 +360,14 @@ module nft_protocol::ob_kiosk {
nft_id: ID,
ctx: &mut TxContext,
): TransferRequest<T> {
let (nft, builder) = transfer_nft_(source, nft_id, sender(ctx), ctx);
deposit(target, nft, ctx);
builder
let (nft, req) = transfer_nft_(source, nft_id, sender(ctx), ctx);
deposit_transfer(
ob_transfer_request::inner_mut(&mut req),
target,
nft,
ctx,
);
req
}

/// We allow withdrawing NFTs for some use cases.
Expand Down Expand Up @@ -469,8 +507,16 @@ module nft_protocol::ob_kiosk {
ctx: &mut TxContext,
): (T, TransferRequest<T>) {
let nft = get_nft(self, nft_id, originator);
let req = ob_transfer_request::new(nft_id, originator, ctx);

(nft, ob_transfer_request::new(nft_id, originator, ctx))
let withdraw_rule = rule_withdraw::new(
Witness {}, &nft, object::id_address(self),
);
rule_withdraw::register_metadata(
ob_transfer_request::inner_mut(&mut req), withdraw_rule,
);

(nft, req)
}

/// After authorization that the call is permitted, gets the NFT.
Expand All @@ -481,8 +527,16 @@ module nft_protocol::ob_kiosk {
ctx: &mut TxContext,
): (T, WithdrawRequest<T>) {
let nft = get_nft(self, nft_id, originator);
let req = withdraw_request::new(originator, ctx);

(nft, withdraw_request::new(originator, ctx))
let withdraw_rule = rule_withdraw::new(
Witness {}, &nft, object::id_address(self),
);
rule_withdraw::register_metadata(
withdraw_request::inner_mut(&mut req), withdraw_rule,
);

(nft, req)
}

fun get_nft<T: key + store>(
Expand All @@ -501,40 +555,6 @@ module nft_protocol::ob_kiosk {

// === Request Auth ===

/// Proves access to given type `Auth`.
/// Useful in conjunction with witness-like types.
/// Trading contracts proves themselves with `Auth` instead of UID.
/// This makes it easier to implement allowlists since we can globally
/// allow a contract to trade.
/// Allowlist could also be implemented with a UID but that would require
/// that the trading contracts maintain a global object.
/// In some cases this is doable, in other it's inconvenient.
public fun set_transfer_request_auth<T, Auth>(
req: &mut TransferRequest<T>, auth: &Auth,
) {
set_transfer_request_auth_(ob_transfer_request::inner_mut(req), auth)
}

public fun set_transfer_request_auth_<T, P, Auth>(
req: &mut RequestBody<WithNft<T, P>>, _auth: &Auth,
) {
let metadata = request::metadata_mut(req);
df::add(metadata, AuthTransferRequestDfKey {}, type_name::get<Auth>());
}

/// What's the authority that created this request?
public fun get_transfer_request_auth<T>(req: &TransferRequest<T>): &TypeName {
get_transfer_request_auth_(ob_transfer_request::inner(req))
}

/// What's the authority that created this request?
public fun get_transfer_request_auth_<T, P>(
req: &RequestBody<WithNft<T, P>>,
): &TypeName {
let metadata = request::metadata(req);
df::borrow(metadata, AuthTransferRequestDfKey {})
}

// === De-listing of NFTs ===

/// Removes _all_ entities from access to the NFT.
Expand Down
5 changes: 4 additions & 1 deletion sources/kiosk/policies/borrow.move
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,10 @@ module nft_protocol::borrow_request {

/// Adds a `Receipt` to the `Request`, unblocking the request and
/// confirming that the policy requirements are satisfied.
public fun add_receipt<Auth: drop, T: key + store, Rule>(self: &mut BorrowRequest<Auth, T>, rule: &Rule) {
public fun add_receipt<Auth: drop, T: key + store, Rule: drop>(
self: &mut BorrowRequest<Auth, T>,
rule: Rule,
) {
request::add_receipt(&mut self.inner, rule);
}

Expand Down
5 changes: 4 additions & 1 deletion sources/kiosk/policies/ob_transfer_request.move
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,10 @@ module nft_protocol::ob_transfer_request {

/// Adds a `Receipt` to the `TransferRequest`, unblocking the request and
/// confirming that the policy requirements are satisfied.
public fun add_receipt<T, Rule>(self: &mut TransferRequest<T>, rule: &Rule) {
public fun add_receipt<T, Rule: drop>(
self: &mut TransferRequest<T>,
rule: Rule,
) {
request::add_receipt(&mut self.inner, rule);
}

Expand Down
2 changes: 1 addition & 1 deletion sources/kiosk/policies/withdraw/wallets.move
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,6 @@ module nft_protocol::wallets {
) {
assert!(vec_set::contains(&self.wallets, &receiver), EUnauthorisedAddress);
transfer::public_transfer(nft, receiver);
request::add_receipt(req, &WalletsRule {});
request::add_receipt(req, WalletsRule {});
}
}
5 changes: 4 additions & 1 deletion sources/kiosk/policies/withdraw/withdraw.move
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ module nft_protocol::withdraw_request {

/// Adds a `Receipt` to the `Request`, unblocking the request and
/// confirming that the policy requirements are satisfied.
public fun add_receipt<T, Rule>(self: &mut WithdrawRequest<T>, rule: &Rule) {
public fun add_receipt<T, Rule: drop>(
self: &mut WithdrawRequest<T>,
rule: Rule,
) {
request::add_receipt(&mut self.inner, rule);
}

Expand Down
2 changes: 1 addition & 1 deletion sources/permissions/access_policy.move
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ module nft_protocol::access_policy {
assert_parent_auth<T>(self, ctx);
};

borrow_request::add_receipt(req, &AccessPolicyRule {});
borrow_request::add_receipt(req, AccessPolicyRule {});
}

public fun confirm_from_collection<Auth: drop, T: key + store>(
Expand Down
5 changes: 5 additions & 0 deletions sources/permissions/authlist.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module nft_protocol::authlist {
struct Authlist {
// TODO: Exact same API as `Allowlist` but for pub keys
}
}
2 changes: 1 addition & 1 deletion sources/permissions/session_tokens.move
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ module nft_protocol::session_token {
assert_parent_auth<Auth, T>(self, req);
};

borrow_request::add_receipt(req, &SessionTokenRule {});
borrow_request::add_receipt(req, SessionTokenRule {});
}

public fun assert_field_auth<Auth: drop, T: key + store>(
Expand Down
5 changes: 4 additions & 1 deletion sources/request/request.move
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,10 @@ module nft_protocol::request {

/// Adds a `Receipt` to the `RequestBody`, unblocking the request and
/// confirming that the policy RequestBodys are satisfied.
public fun add_receipt<P, Rule>(self: &mut RequestBody<P>, _rule: &Rule) {
public fun add_receipt<P, Rule: drop>(
self: &mut RequestBody<P>,
_rule: Rule,
) {
vec_set::insert(&mut self.receipts, type_name::get<Rule>())
}

Expand Down
Loading