-
Notifications
You must be signed in to change notification settings - Fork 98
/
marketplace.move
161 lines (141 loc) · 5.02 KB
/
marketplace.move
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// Copyright (c) Sui Foundation, Inc.
// SPDX-License-Identifier: Apache-2.0
// Modified from https://github.com/MystenLabs/sui/blob/main/sui_programmability/examples/nfts/sources/marketplace.move
module marketplace::marketplace {
use sui::dynamic_object_field as ofield;
use sui::tx_context::{Self, TxContext};
use sui::object::{Self, ID, UID};
use sui::coin::{Self, Coin};
use sui::bag::{Bag, Self};
use sui::table::{Table, Self};
use sui::transfer;
/// For when amount paid does not match the expected.
const EAmountIncorrect: u64 = 0;
/// For when someone tries to delist without ownership.
const ENotOwner: u64 = 1;
/// A shared `Marketplace`. Can be created by anyone using the
/// `create` function. One instance of `Marketplace` accepts
/// only one type of Coin - `COIN` for all its listings.
public struct Marketplace<phantom COIN> has key {
id: UID,
items: Bag,
payments: Table<address, Coin<COIN>>
}
/// A single listing which contains the listed item and its
/// price in [`Coin<COIN>`].
public struct Listing has key, store {
id: UID,
ask: u64,
owner: address,
}
/// Create a new shared Marketplace.
public fun create<COIN>(ctx: &mut TxContext) {
let id = object::new(ctx);
let items = bag::new(ctx);
let payments = table::new<address, Coin<COIN>>(ctx);
transfer::share_object(Marketplace<COIN> {
id,
items,
payments
})
}
/// List an item at the Marketplace.
public fun list<T: key + store, COIN>(
marketplace: &mut Marketplace<COIN>,
item: T,
ask: u64,
ctx: &mut TxContext
) {
let item_id = object::id(&item);
let mut listing = Listing {
ask,
id: object::new(ctx),
owner: tx_context::sender(ctx),
};
ofield::add(&mut listing.id, true, item);
bag::add(&mut marketplace.items, item_id, listing)
}
/// Internal function to remove listing and get an item back. Only owner can do that.
fun delist<T: key + store, COIN>(
marketplace: &mut Marketplace<COIN>,
item_id: ID,
ctx: &TxContext
): T {
let Listing {
mut id,
owner,
ask: _,
} = bag::remove(&mut marketplace.items, item_id);
assert!(tx_context::sender(ctx) == owner, ENotOwner);
let item = ofield::remove(&mut id, true);
object::delete(id);
item
}
/// Call [`delist`] and transfer item to the sender.
public fun delist_and_take<T: key + store, COIN>(
marketplace: &mut Marketplace<COIN>,
item_id: ID,
ctx: &mut TxContext
) {
let item = delist<T, COIN>(marketplace, item_id, ctx);
transfer::public_transfer(item, tx_context::sender(ctx));
}
/// Internal function to purchase an item using a known Listing. Payment is done in Coin<C>.
/// Amount paid must match the requested amount. If conditions are met,
/// owner of the item gets the payment and buyer receives their item.
fun buy<T: key + store, COIN>(
marketplace: &mut Marketplace<COIN>,
item_id: ID,
paid: Coin<COIN>,
): T {
let Listing {
mut id,
ask,
owner
} = bag::remove(&mut marketplace.items, item_id);
assert!(ask == coin::value(&paid), EAmountIncorrect);
// Check if there's already a Coin hanging and merge `paid` with it.
// Otherwise attach `paid` to the `Marketplace` under owner's `address`.
if (table::contains<address, Coin<COIN>>(&marketplace.payments, owner)) {
coin::join(
table::borrow_mut<address, Coin<COIN>>(&mut marketplace.payments, owner),
paid
)
} else {
table::add(&mut marketplace.payments, owner, paid)
};
let item = ofield::remove(&mut id, true);
object::delete(id);
item
}
/// Call [`buy`] and transfer item to the sender.
public fun buy_and_take<T: key + store, COIN>(
marketplace: &mut Marketplace<COIN>,
item_id: ID,
paid: Coin<COIN>,
ctx: &mut TxContext
) {
transfer::public_transfer(
buy<T, COIN>(marketplace, item_id, paid),
tx_context::sender(ctx)
)
}
/// Internal function to take profits from selling items on the `Marketplace`.
fun take_profits<COIN>(
marketplace: &mut Marketplace<COIN>,
ctx: &TxContext
): Coin<COIN> {
table::remove<address, Coin<COIN>>(&mut marketplace.payments, tx_context::sender(ctx))
}
#[lint_allow(self_transfer)]
/// Call [`take_profits`] and transfer Coin object to the sender.
public fun take_profits_and_keep<COIN>(
marketplace: &mut Marketplace<COIN>,
ctx: &mut TxContext
) {
transfer::public_transfer(
take_profits(marketplace, ctx),
tx_context::sender(ctx)
)
}
}