,
129 | ctx: &mut TxContext
130 | ) {
131 |
132 | let sender = tx_context::sender(ctx);
133 |
134 | event::emit(NFTDescriptionUpdated {
135 | object_id: object::id(nft),
136 | creator_updated: sender,
137 | new_description_updated: string::utf8(new_description)
138 | });
139 |
140 | nft.description = string::utf8(new_description)
141 | }
142 |
143 | /// Permanently delete `nft`
144 | public fun burn(
145 | nft_burn: FourFutureNFT,
146 | ctx: &mut TxContext
147 | ) {
148 |
149 | let sender = tx_context::sender(ctx);
150 |
151 | event::emit(NFTBurned {
152 | creator_burned: sender
153 | });
154 |
155 | let FourFutureNFT { id, name: _, description: _, url: _ } = nft_burn;
156 | object::delete(id)
157 | }
158 |
159 | }
--------------------------------------------------------------------------------
/front-end/src/pages/DetailItemOwner/DetailItemOwner.css:
--------------------------------------------------------------------------------
1 | .item{
2 | display: flex;
3 | padding: 0 6rem;
4 | font-family: var(--font-family);
5 | }
6 | .item-image{
7 | flex: 1;
8 | display: flex;
9 | justify-content: center;
10 | align-items: center;
11 | border-right: 1px solid rgba(165, 165, 165, 0.1);
12 |
13 | }
14 | .item-image img {
15 | width: 100%;
16 | height: 100%;
17 | border-radius: 70px;
18 | padding: 50px;
19 | }
20 | .item-content{
21 | flex:1;
22 | display: flex;
23 | justify-content: flex-start;
24 | align-items: flex-start;
25 | flex-direction: column;
26 | margin: 5rem;
27 | position: relative;
28 | }
29 |
30 | .item-content-title h1{
31 | font-family: var(--font-family);
32 | font-weight: 600;
33 | font-size: 28px;
34 | line-height: 42px;
35 | color: #FFFFFF;
36 | }
37 | .item-content-title p{
38 | font-family: var(--font-family);
39 | font-weight: normal;
40 | font-size: 14px;
41 | line-height: 21px;
42 | color: #FFFFFF;
43 | }
44 | .item-content-title span{
45 | font-weight: 600;
46 | }
47 | .item-content-creator{
48 | margin-top: 30px;
49 | }
50 | .item-content-creator p{
51 | font-size: 12px;
52 | line-height: 18px;
53 | color: #FFFFFF;
54 | }
55 | .item-content-creator div{
56 | display: flex;
57 | align-items: center;
58 | margin-top: 10px;
59 | }
60 | .item-content-creator div:last-child p{
61 | font-weight: 600;
62 | font-size: 14px;
63 | line-height: 21px;
64 | color: #FFFFFF;
65 | }
66 | .item-content-creator img {
67 | border-radius: 50%;
68 | margin-right: 10px;
69 | width: 50px;
70 | height: 50px;
71 | }
72 | .item-content-detail{
73 | margin-top: 30px;
74 | margin-bottom: 30px;
75 | border-top: 1px solid rgba(165, 165, 165, 0.1);
76 | padding-top: 20px;
77 | }
78 | .item-content-detail p{
79 | font-size: 16px;
80 | line-height: 26px;
81 | color: #FFFFFF;
82 | width: 500px;
83 | }
84 | .item-content-buy .primary-btn{
85 | background: var(--primary-btn);
86 | border-radius: 10px;
87 | border: none;
88 | padding: 0.70rem 3rem;
89 | font-size: 14px;
90 | line-height: 21px;
91 | font-weight: 600;
92 | color: #fff;
93 | margin: 30px;
94 | }
95 |
96 | .item-content-buy .secondary-btn{
97 | background: transparent;
98 | border-radius: 10px;
99 | border: 1px solid var(--primary-color);
100 | padding: 0.70rem 3rem;
101 | font-size: 14px;
102 | line-height: 21px;
103 | font-weight: 600;
104 | color: var(--primary-color);
105 | margin: 30px;
106 | }
107 |
108 | .modal-content{
109 | display: flex;
110 | justify-content: space-between;
111 | }
112 |
113 | .item-content-action{
114 | display: flex;
115 | position: absolute;
116 | right: 0;
117 | }
118 | .item-content-action p{
119 | cursor: pointer;
120 | font-size: 18px;
121 | color: white;
122 | background: var(--primary-btn);
123 | margin-inline: 10px;
124 | border-radius: 5px;
125 | padding: 5px 5px 0px 5px;
126 | }
127 | @media screen and (max-width: 1050px) {
128 | .item{
129 | flex-direction: column;
130 | }
131 | .item-content{
132 | margin: 0 0 3rem;
133 | }
134 | .item-image{
135 | border-right: unset;
136 | }
137 | .item-content-detail p{
138 | width: 100%;
139 | }
140 | }
141 |
142 | @media screen and (max-width: 650px) {
143 | .item-content h1{
144 | font-size: 28px;
145 | line-height: 42px;
146 | }
147 | .item-content p{
148 | font-size: 16px;
149 | line-height: 24px;
150 | }
151 | .item-content__people{
152 | flex-direction: column;
153 | }
154 | .item-content__people p{
155 | margin: 0;
156 | }
157 | .item-content__input input,
158 | .item-content__input button{
159 | font-size: 16px;
160 | line-height: 24px;
161 | }
162 | .item-content-buy .primary-btn{
163 | padding: 0.75rem 33px;
164 | }
165 | .item-content-buy .secondary-btn{
166 | padding: 0.75rem 33px;
167 | }
168 | }
169 | @media screen and (max-width: 490px){
170 | .item-content h1{
171 | font-size: 28px;
172 | line-height: 42px;
173 | }
174 | .item-content p{
175 | font-size: 14px;
176 | line-height: 26px;
177 | }
178 | .item-content__input input,
179 | .item-content__input button{
180 | font-size: 12px;
181 | line-height: 16px;
182 | }
183 | .item{
184 | padding-inline:1rem !important ;
185 | padding-top: 1rem !important;
186 | }
187 | .item-image img{
188 | padding: 0;
189 | border-radius: 20px;
190 | margin-bottom: 25px;
191 | }
192 | .item-content-buy .primary-btn{
193 | margin-right: 10px;
194 | }
195 | .item-content-action{
196 | top: 15%;
197 | }
198 | .item-content-action p{
199 | margin-inline: 5px;
200 |
201 | }
202 |
203 | }
--------------------------------------------------------------------------------
/front-end/src/components/header/Header.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import './header.css'
3 | import "slick-carousel/slick/slick.css";
4 | import "slick-carousel/slick/slick-theme.css";
5 | import Slider from "react-slick";
6 | import seller1 from '../../assets/seller1.jpg'
7 | import seller2 from '../../assets/seller2.png'
8 | import seller3 from '../../assets/seller3.png'
9 | import seller4 from '../../assets/seller4.png'
10 | import seller5 from '../../assets/seller5.png'
11 | import seller6 from '../../assets/seller6.jpg'
12 | import verify from '../../assets/verify.png'
13 | import coin from '../../assets/coin.png'
14 | import { Link } from 'react-router-dom';
15 | const Header = () => {
16 | var settings = {
17 | dots: false,
18 | infinite: false,
19 | speed: 500,
20 | slidesToShow: 5,
21 | slidesToScroll: 1,
22 | initialSlide: 0,
23 | swipeToSlide:true,
24 | responsive: [
25 | {
26 | breakpoint: 1160,
27 | settings: {
28 | slidesToShow: 4,
29 | slidesToScroll: 1,
30 | swipeToSlide:true,
31 | }
32 | },
33 | {
34 | breakpoint: 950,
35 | settings: {
36 | slidesToShow: 3,
37 | slidesToScroll: 1,
38 | swipeToSlide:true,
39 | }
40 | },
41 | {
42 | breakpoint: 750,
43 | settings: {
44 | slidesToShow: 2,
45 | slidesToScroll: 1,
46 | initialSlide: 2,
47 | }
48 | },
49 | {
50 | breakpoint: 550,
51 | settings: {
52 | slidesToShow: 3,
53 | slidesToScroll: 1
54 | }
55 | },
56 | {
57 | breakpoint: 470,
58 | settings: {
59 | slidesToShow: 2,
60 | slidesToScroll: 1,
61 | }
62 | },
63 | {
64 | breakpoint: 400,
65 | settings: {
66 | slidesToShow: 2,
67 | slidesToScroll: 1,
68 | variableWidth: true,
69 | }
70 | }
71 | ]
72 | };
73 | return (
74 |
75 |
76 |
77 |
Create your AI NFTs and make a vote
78 |

79 |
80 |
81 |
82 |
Top Sellers
83 |
84 |
85 |
1
86 |
87 |

88 |

89 |
90 |
91 |
James Bond
92 |
93 |
5.250 SUI
94 |
95 |
96 |
2
97 |
98 |

99 |

100 |
101 |
102 |
Rian Leon
103 |
104 |
4.932 SUI
105 |
106 |
107 |
3
108 |
109 |

110 |

111 |
112 |
113 |
Lady Young
114 |
115 |
4.620 SUI
116 |
117 |
118 |
4
119 |
120 |

121 |

122 |
123 |
124 |
Black Glass
125 |
126 |
4.125 SUI
127 |
128 |
129 |
5
130 |
131 |

132 |

133 |
134 |
135 |
Budhiman
136 |
137 |
3.921 SUI
138 |
139 |
140 |
6
141 |
142 |

143 |

144 |
145 |
146 |
Alex
147 |
148 |
3.548 SUI
149 |
150 |
151 |
152 |
153 | )
154 | }
155 |
156 | export default Header
157 |
--------------------------------------------------------------------------------
/front-end/src/components/Pagination/Pagination.css:
--------------------------------------------------------------------------------
1 |
2 | .bids-container{
3 | display: flex;
4 | flex-direction: column;
5 | justify-content: center;
6 | align-items: center;
7 | margin: auto;
8 | width: 100%;
9 | }
10 | .bids-container-text h1{
11 | font-family: var(--font-family);
12 | font-weight: 600;
13 | font-size: 28px;
14 | line-height: 42px;
15 | color: #FFFFFF;
16 | margin-bottom: 1rem;
17 | }
18 | .bids-container-card{
19 | margin: 0 -5px;
20 | }
21 | .bids-container-card:after {
22 | content: "";
23 | display: table;
24 | clear: both;
25 | }
26 |
27 | .card-row-container{
28 | display: flex;
29 | }
30 |
31 | .card-column{
32 | float: left;
33 | width: 20%;
34 | }
35 | .bids-card{
36 | background: #2A2D3A;
37 | border-radius: 20px;
38 | padding: 11px 12px 19px 11px;
39 | margin-inline: 10px;
40 | margin-bottom: 20px;
41 | }
42 | .bids-card img{
43 | border-radius: 20px;
44 | width: 100%;
45 | }
46 | .bids-card-top p{
47 | font-family: var(--font-family);
48 | font-weight: 600;
49 | font-size: 14px;
50 | line-height: 21px;
51 | color: #FFFFFF;
52 | margin-top: 15px;
53 | }
54 | .bids-card-bottom{
55 | display: flex;
56 | justify-content: space-between;
57 | }
58 | .bids-card-bottom p{
59 | font-family: var(--font-family);
60 | font-weight: 600;
61 | font-size: 12px;
62 | line-height: 18px;
63 | /* text-align: right; */
64 | color: #FFFFFF;
65 | }
66 | .bids-card-bottom p:last-child{
67 | font-weight: normal;
68 |
69 | }
70 | .bids-card-bottom span{
71 | font-weight: normal;
72 | }
73 | .load-more{
74 | display: flex;
75 | justify-content: center;
76 | align-items: center;
77 | margin-top: 2rem;
78 | }
79 |
80 | .photo {
81 | height: 200px;
82 | width: 200px;
83 | }
84 |
85 | @media screen and (max-width: 1440px) {
86 | .card-column {
87 | width: 25%;
88 | }
89 | }
90 |
91 |
92 | @media screen and (max-width: 1200px) {
93 | .card-column {
94 | width: 33.33%;
95 |
96 | }
97 | }
98 |
99 | @media screen and (max-width: 900px) {
100 | .card-column {
101 | width: 50%;
102 |
103 | }
104 | }
105 | @media screen and (max-width: 550px) {
106 | .section__padding{
107 | padding: 2rem 14px !important;
108 | }
109 | .bids-card{
110 | margin-bottom: 10px;
111 | margin-inline: 5px;
112 | }
113 | .bids-card-top p{
114 | font-size: 12px;
115 | line-height: 18px;
116 | margin-top: 5px;
117 | }
118 | .bids-card-bottom p{
119 | font-size: 10px;
120 | line-height: 15px;
121 | }
122 | .bids-container{
123 | width: 100%;
124 | }
125 | }
126 |
127 | .pageNumbers {
128 | display: flex;
129 | justify-content: center;
130 | align-items: center;
131 | height: 50px;
132 | }
133 |
134 | .pageNumbers li{
135 | display:inline;
136 | }
137 |
138 | .pageNumbers ul{
139 | overflow-x:hidden;
140 | white-space:nowrap;
141 | height: 1em;
142 | width: 100%;
143 | }
144 |
145 |
146 | .page-link {
147 | position: relative;
148 | display: inline-flex;
149 | border: 1px solid #dee2e6;
150 | background-color: #ffffff;
151 | padding: 10px 15px;
152 | color: #0d6efd;
153 | font-size: 16px;
154 | font-weight: 500;
155 | text-decoration: none;
156 | transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out,
157 | border-color 0.15s ease-in-out;
158 | cursor: pointer;
159 | }
160 |
161 | .pageNumbers:first-child {
162 | border-top-left-radius: 5px;
163 | border-bottom-left-radius: 5px;
164 | }
165 |
166 | .pageNumbers:last-child {
167 | border-top-right-radius: 5px;
168 | border-bottom-right-radius: 5px;
169 | }
170 |
171 | button{
172 | background-color: #fc0fc0;
173 | color: white;
174 | border-radius: 50%;
175 | }
176 |
177 | .active{
178 | background:#fc0fc0;
179 | color: white;
180 | }
181 |
182 | .pageNumbers:mid {
183 | border-top-right-radius: 5px;
184 | border-bottom-right-radius: 5px;
185 | background:#FFC0CB;
186 | }
187 |
188 | .pageNumbers:not(:first-child) {
189 | margin-left: -1px;
190 | }
191 |
192 | .pageNumbers:hover,
193 | .pageNumbers:focus {
194 | color: #0a58ca;
195 | }
196 |
197 | .pageNumbers:focus {
198 | z-index: 3;
199 | }
200 |
201 | .pageNumbers.active {
202 | z-index: 2;
203 | color: #ffffff;
204 | border-color: #0d6efd;
205 | background-color: #0d6efd;
206 | }
207 |
208 | .pageNumbers.disabled {
209 | color: #6c757d;
210 | pointer-events: none;
211 | }
212 |
213 | .prev-button {
214 | background-color: #fc0fc0;
215 | color: white;
216 | border: none;
217 | height: 40px;
218 | width: 100px;
219 | font-weight: bold;
220 | font-size: 15px;
221 | border-radius: 20px;
222 | cursor: pointer;
223 | margin-right: 10px;
224 | transition: background-color 0.15s;
225 | }
226 |
227 | .prev-button:hover {
228 | background-image: linear-gradient(to right, rgba(222, 176, 216, 0), rgb(232, 131, 229));
229 | }
230 |
231 | .next-button {
232 | background-color: #fc0fc0;
233 | color: white;
234 | border: none;
235 | height: 40px;
236 | width: 100px;
237 | font-weight: bold;
238 | font-size: 15px;
239 | border-radius: 20px;
240 | cursor: pointer;
241 | margin-right: 10px;
242 | transition: background-color 0.15s;
243 | }
244 |
245 | .next-button:hover {
246 | background-image: linear-gradient(to right, rgba(222, 176, 216, 0), rgb(232, 131, 229));
247 | }
248 |
--------------------------------------------------------------------------------
/front-end/src/components/header/header.css:
--------------------------------------------------------------------------------
1 | .header{
2 | display: flex;
3 | flex-direction: column;
4 | align-items: center;
5 | justify-content: center;
6 | margin: auto;
7 | }
8 | .header-content div{
9 | background: var(--primary-btn);
10 | width: 100%;
11 | height: 300px;
12 | border-radius: 25px;
13 | display: flex;
14 | align-items: center;
15 | justify-content: space-around;
16 | margin: auto;
17 | }
18 | .header-content div h1{
19 | font-family: var(--font-family);
20 | width: 70%;
21 | font-weight: bold;
22 | font-size: 48px;
23 | line-height: 105.7%;
24 | color: #FFFFFF;
25 | padding: 1rem;
26 | margin-left: 2rem;
27 | }
28 | .header-content div img{
29 | width: 17%;
30 | }
31 | .header-slider{
32 | margin-top: 5rem;
33 | /* background: wheat; */
34 | color: #FFFFFF;
35 | width: 100%;
36 | position: relative;
37 | display: flex;
38 | flex-direction: column;
39 | justify-content: center;
40 | align-items: center;
41 | }
42 | .header-slider .slider{
43 | width: 70%;
44 | }
45 | .header-slider h1 {
46 | font-family: var(--font-family);
47 | font-weight: 600;
48 | font-size: 28px;
49 | line-height: 42px;
50 | color: #FFFFFF;
51 | margin-bottom: 1rem;
52 |
53 | }
54 |
55 | .slider .slider-card{
56 | width: 180px !important;
57 | height: 200px !important;
58 | background: #2A2D3A;
59 | border-radius: 20px;
60 | display: flex !important;
61 | flex-direction: column;
62 | align-items: center;
63 | justify-content: center;
64 | position: relative;
65 | }
66 | .slider-card img{
67 | border-radius: 50%;
68 | }
69 | .slider-card-number{
70 | position: absolute;
71 | top: 5.5%;
72 | left: 6.11%;
73 | background: var(--primary-color);
74 | width: 33px;
75 | height: 33px;
76 | border-radius: 50%;
77 | font-weight: 600;
78 | font-size: 16px;
79 | display: flex;
80 | align-items: center;
81 | justify-content: center;
82 | }
83 | .slider-card p{
84 | font-family: var(--font-family);
85 | font-weight: 600;
86 | font-size: 16px;
87 | line-height: 24px;
88 | color: #FFFFFF;
89 | margin-top: 5px;
90 | }
91 | .slider-card span{
92 | font-weight: normal !important;
93 | }
94 |
95 | .shake-vertical {
96 | -webkit-animation: shake-vertical 10s cubic-bezier(0.455, 0.030, 0.515, 0.955) 2s infinite both;
97 | animation: shake-vertical 10s cubic-bezier(0.455, 0.030, 0.515, 0.955) 2s infinite both;
98 | }
99 | @-webkit-keyframes shake-vertical {
100 | 0%,
101 | 100% {
102 | -webkit-transform: translateY(0);
103 | transform: translateY(0);
104 | }
105 | 10%,
106 | 30%,
107 | 50%,
108 | 70% {
109 | -webkit-transform: translateY(-8px);
110 | transform: translateY(-8px);
111 | }
112 | 20%,
113 | 40%,
114 | 60% {
115 | -webkit-transform: translateY(8px);
116 | transform: translateY(8px);
117 | }
118 | 80% {
119 | -webkit-transform: translateY(6.4px);
120 | transform: translateY(6.4px);
121 | }
122 | 90% {
123 | -webkit-transform: translateY(-6.4px);
124 | transform: translateY(-6.4px);
125 | }
126 | }
127 | @keyframes shake-vertical {
128 | 0%,
129 | 100% {
130 | -webkit-transform: translateY(0);
131 | transform: translateY(0);
132 | }
133 | 10%,
134 | 30%,
135 | 50%,
136 | 70% {
137 | -webkit-transform: translateY(-8px);
138 | transform: translateY(-8px);
139 | }
140 | 20%,
141 | 40%,
142 | 60% {
143 | -webkit-transform: translateY(8px);
144 | transform: translateY(8px);
145 | }
146 | 80% {
147 | -webkit-transform: translateY(6.4px);
148 | transform: translateY(6.4px);
149 | }
150 | 90% {
151 | -webkit-transform: translateY(-6.4px);
152 | transform: translateY(-6.4px);
153 | }
154 | }
155 |
156 | .slider-img{
157 | position: relative;
158 | }
159 | .verify{
160 | position: absolute;
161 | right: 5px;
162 | bottom: 2px;
163 | }
164 |
165 |
166 | /* media */
167 | @media screen and (max-width: 1600px) {
168 | .header-slider .slider{
169 | width: 90%;
170 | }
171 |
172 | }
173 | @media screen and (max-width: 1350px) {
174 | .header-slider .slider{
175 | width: 100%;
176 | }
177 |
178 | .header-content div{
179 | height: 200px;
180 | }
181 | .header-content div h1{
182 | font-size: 36px;
183 | line-height: 32px;
184 | /* width: 100%; */
185 | }
186 |
187 | }
188 | @media screen and (max-width: 550px) {
189 | .slick-prev, .slick-next{
190 | display: none !important;
191 | }
192 | .header-slider h1{
193 | font-size: 20px;
194 | line-height: 30px;
195 | }
196 | .slider .slider-card{
197 | width: 138px !important;
198 | height: 165px !important;
199 | }
200 | .slider-card-number{
201 | width: 24px;
202 | height: 24px;
203 | }
204 | .slider-card p{
205 | font-size: 14px;
206 | line-height: 21px;
207 | }
208 | .header-content div{
209 | height: 143px;
210 | }
211 | .header-content div h1{
212 | font-size: 20px;
213 | line-height: 24px;
214 | width: 100%;
215 | }
216 | }
217 | @media screen and (max-width: 800px){
218 | .header-content div img{
219 | width: 20%;
220 | margin-right: 10px;
221 | }
222 | .header-content div{
223 | justify-content: unset;
224 | }
225 | .header-content div h1{
226 | margin-left: 1rem;
227 | }
228 | }
229 | @media screen and (max-width: 650px) {
230 | .header-content h1{
231 | font-size: 48px;
232 | line-height: 60px;
233 | }
234 |
235 | }
236 |
237 | @media screen and (max-width: 400px){
238 | .slider .slider-card{
239 | margin-right: 1rem;
240 | }
241 | .bids{
242 | padding: 2rem 0px !important;
243 | }
244 | }
245 | @media screen and (max-width: 335px){
246 | .slider .slider-card{
247 | margin-right: 0.5rem !important;
248 | }
249 | }
--------------------------------------------------------------------------------
/front-end/src/pages/item/Item.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState,useEffect } from 'react';
2 | import './item.css'
3 | import creator from '../../assets/seller2.png'
4 | import { useParams } from 'react-router-dom';
5 | import { useWallet } from '@suiet/wallet-kit'
6 | import { TransactionBlock } from '@mysten/sui.js/transactions';
7 | import * as constant from '../../constant/constant';
8 | import toast, { Toaster } from 'react-hot-toast';
9 |
10 | const mapping = {
11 | 0: { targetId: "0", name: "Abstract Smoke Red", imgAddress: "https://github.com/kasim393/NFT-Marketplace-UI/blob/main/src/assets/bids1.png?raw=true" },
12 | 1: { targetId: "1", name: "Mountain Landscape", imgAddress: "https://github.com/kasim393/NFT-Marketplace-UI/blob/main/src/assets/bids2.png?raw=true" },
13 | 2: { targetId: "2", name: "Paint Colour on Wall", imgAddress: "https://github.com/kasim393/NFT-Marketplace-UI/blob/main/src/assets/bids3.png?raw=true" },
14 | 3: { targetId: "3", name: "Abstract Pattern", imgAddress: "https://github.com/kasim393/NFT-Marketplace-UI/blob/main/src/assets/bids4.png?raw=true" },
15 | 4: { targetId: "4", name: "White Line Grafiti", imgAddress: "https://github.com/kasim393/NFT-Marketplace-UI/blob/main/src/assets/bids5.png?raw=true" },
16 | 5: { targetId: "5", name: "Abstract Triangle", imgAddress: "https://github.com/kasim393/NFT-Marketplace-UI/blob/main/src/assets/bids6.png?raw=true" },
17 | 6: { targetId: "6", name: "Lake Landscape", imgAddress: "https://github.com/kasim393/NFT-Marketplace-UI/blob/main/src/assets/bids7.png?raw=true" },
18 | 7: { targetId: "7", name: "Blue Red Art", imgAddress: "https://github.com/kasim393/NFT-Marketplace-UI/blob/main/src/assets/bids8.png?raw=true" },
19 | };
20 |
21 |
22 | const Item = () => {
23 | let id = useParams().id;
24 | let price = useParams().price;
25 | let owner = useParams().owner;
26 | let type = useParams().type;
27 |
28 |
29 | const packageObjectId = constant.packageObjectId;
30 | const moduleMarketName = constant.moduleMarketName;
31 |
32 | const [data, setData] = useState(null);
33 | const [addressWallet, setAddressWallet] = useState(null);
34 | const [buttonPage,setButtonPage] = useState(null);
35 |
36 | const wallet = useWallet();
37 |
38 |
39 |
40 | async function getNFT() {
41 | const listNFT = [];
42 | const infoObject = await constant.client.call('sui_getObject', [id,{"showContent": true,"showOwner": true,}]);
43 | console.log(infoObject);
44 | listNFT.push(infoObject.data.content.fields)
45 | setData(listNFT);
46 |
47 | }
48 |
49 | useEffect(()=>{
50 | console.log("addressWallet",addressWallet)
51 | console.log("owner",owner)
52 | if(wallet.account?.address == owner){
53 | setButtonPage(
54 |
55 |
56 |
57 | )
58 | }
59 | else
60 | {
61 | setButtonPage(
62 |
63 |
64 |
65 | )
66 | }
67 | },[data])
68 |
69 | useEffect(() => {
70 | if (!wallet.connected) return;
71 | setAddressWallet(wallet.account?.address);
72 | // console.log('connected wallet name: ', wallet.name)
73 | // console.log('account address: ', wallet.account?.address)
74 | // console.log('account publicKey: ', wallet.account?.publicKey)
75 | getNFT();
76 |
77 | }, [wallet.connected,id])
78 |
79 |
80 | async function unList(){
81 | const tx = new TransactionBlock();
82 | tx.moveCall({
83 | target: `${packageObjectId}::${moduleMarketName}::delist_and_take`,
84 | typeArguments: [constant.typeArgNFT,constant.suiCoin],
85 | arguments: [tx.pure(constant.marketID),tx.pure(id)],
86 | });
87 | try{
88 | const res = await wallet.signAndExecuteTransactionBlock({
89 | transactionBlock: tx,
90 | });
91 | console.log(res);
92 | toast.success('Reback NFT success!');
93 | window.location.href = window.location.origin;
94 | }
95 | catch{
96 | toast.error('Reback NFT fail!');
97 | }
98 | }
99 |
100 | async function buy(){
101 | const tx = new TransactionBlock();
102 | const value = price;
103 | const [coins] = tx.splitCoins(tx.gas, [
104 | tx.pure(value),
105 | ])
106 |
107 | tx.moveCall({
108 | target: `${packageObjectId}::${moduleMarketName}::buy_and_take`,
109 | typeArguments: [constant.typeArgNFT,constant.suiCoin],
110 | arguments: [tx.pure(constant.marketID),tx.pure(id),coins],
111 | });
112 | try{
113 | const res = await wallet.signAndExecuteTransactionBlock({
114 | transactionBlock: tx,
115 | });
116 | console.log(res);
117 | toast.success('Buy NFT success!');
118 | window.location.href = window.location.origin;
119 | }
120 | catch{
121 | toast.error('Buy NFT fail!');
122 | }
123 | }
124 |
125 | return (
126 |
127 |
128 | {data?.map((d) => (
129 |
130 |
131 |

132 |
133 |
134 |
135 |
{d.name}
136 |
{price} SUI (transfer fee: 1%)
137 |
138 |
139 |
140 |
141 |

142 |
{owner.substring(0,6)+"..."+owner.substring(owner.length-6,owner.length)}
143 |
144 |
145 |
146 |
{d.description}
147 |
148 | {buttonPage}
149 |
150 |
151 | ))}
152 |
153 | )
154 | };
155 |
156 | export default Item;
157 |
--------------------------------------------------------------------------------
/front-end/src/pages/bidItem/BidItem.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState,useEffect } from 'react';
2 | import './BidItem.css'
3 | import creator from '../../assets/seller2.png'
4 | import { useParams } from 'react-router-dom';
5 | import { useWallet } from '@suiet/wallet-kit'
6 | import { TransactionBlock } from '@mysten/sui.js/transactions';
7 | import * as constant from '../../constant/constant';
8 | import toast, { Toaster } from 'react-hot-toast';
9 |
10 | const BidItem = () => {
11 | let id = useParams().id;
12 | let price = useParams().price;
13 | let owner = useParams().owner;
14 | let auctionID = useParams().auctionID;
15 |
16 | const packageObjectId = constant.packageObjectId;
17 | const moduleMarketName = constant.moduleMarketName;
18 |
19 | const [data, setData] = useState(null);
20 | const [addressWallet, setAddressWallet] = useState(null);
21 | const [buttonPage,setButtonPage] = useState(null);
22 | const [bidInfo,setbidInfo] = useState(null);
23 | const [priceOfBid,setPriceOfBid] = useState(null);
24 | const wallet = useWallet();
25 |
26 |
27 |
28 | async function getNFT() {
29 | const listNFT = [];
30 | const resData = await constant.client.call('sui_getObject',
31 | [auctionID,
32 | {
33 | "showType": true,
34 | "showOwner": true,
35 | "showPreviousTransaction": true,
36 | "showContent": true,
37 | }]);
38 | console.log(resData);
39 | if(resData!= null)
40 | {
41 | listNFT.push({
42 | d:resData.data.content.fields.to_sell.fields,
43 | p:resData.data.content.fields.set_change,
44 | q:resData.data.content.fields.bid_data,
45 | })
46 | }
47 | setData(listNFT);
48 | console.log('listNFT',listNFT);
49 | }
50 |
51 | useEffect(()=>{
52 | if(data!= null)
53 | {
54 | if(data[0].d !== null && data[0].q === null){
55 | setbidInfo(data[0].p +" of "+data[0].p +" times");
56 | }
57 | else if(data[0].d !== null && data[0].q !== null)
58 | {
59 | setbidInfo(data[0].q?.fields.change+" of "+data[0].p +" times - Highest price:"+data[0].q?.fields.funds);
60 | }
61 | else
62 | {
63 | setbidInfo("Bid is expired");
64 | };
65 | }
66 |
67 |
68 | if(addressWallet == owner){
69 | setButtonPage(
70 |
71 |
72 |
73 | )
74 | }
75 | else
76 | {
77 | setButtonPage(
78 |
79 | setPriceOfBid(e.target.value)}/>
80 |
81 |
82 | )
83 | };
84 |
85 | },[data]);
86 |
87 |
88 | useEffect(() => {
89 | if(addressWallet == owner){
90 | setButtonPage(
91 |
92 |
93 |
94 | )
95 | }
96 | else
97 | {
98 | setButtonPage(
99 |
100 | setPriceOfBid(e.target.value)}/>
101 |
102 |
103 | )
104 | };
105 | }, [priceOfBid])
106 |
107 | useEffect(() => {
108 | if (!wallet.connected) return;
109 | setAddressWallet(wallet.account?.address);
110 | // console.log('connected wallet name: ', wallet.name)
111 | // console.log('account address: ', wallet.account?.address)
112 | // console.log('account publicKey: ', wallet.account?.publicKey)
113 | getNFT();
114 | }, [wallet.connected,id])
115 |
116 | async function BidNFT(){
117 | if(priceOfBid!= null && priceOfBid!="")
118 | {
119 | const tx = new TransactionBlock();
120 | const [coins] = tx.splitCoins(tx.gas, [
121 | tx.pure(priceOfBid),
122 | ])
123 | console.log(priceOfBid);
124 | tx.moveCall({
125 | target: `${packageObjectId}::${moduleMarketName}::bid`,
126 | typeArguments: [constant.typeArgNFT],
127 | arguments: [coins,tx.pure(auctionID)],
128 | });
129 | try{
130 | const res = await wallet.signAndExecuteTransactionBlock({
131 | transactionBlock: tx,
132 | });
133 | console.log(res);
134 | toast.success('Bid NFT success!');
135 | window.location.href = window.location.origin;
136 | }
137 | catch{
138 | toast.error('Bid NFT fail!');
139 | }
140 | }
141 | }
142 |
143 | return (
144 |
145 |
146 | {data?.map((d) => (
147 |
148 |
149 |

150 |
151 |
152 |
153 |
{d.d.name}
154 |
{bidInfo} (bid fee: 1%)
155 |
156 |
157 |
158 |
159 |

160 |
{owner.substring(0,6)+"..."+owner.substring(owner.length-6,owner.length)}
161 |
162 |
163 |
164 |
{d.d.description}
165 |
166 | {buttonPage}
167 |
168 |
169 | ))}
170 |
171 | )
172 | };
173 |
174 | export default BidItem;
175 |
--------------------------------------------------------------------------------
/front-end/src/components/Pagination/Pagination.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { AiFillHeart, AiOutlineHeart } from "react-icons/ai";
3 | import { Link } from 'react-router-dom';
4 | import './Pagination.css'
5 |
6 | const Pagination = (props)=>{
7 | const { currentPage, maxPageLimit, minPageLimit} = props;
8 | const totalPages = props.totalPages-1;
9 | const data = props.data;
10 | const title = props.title;
11 | const pages = [];
12 | for(let i=1 ; i<=totalPages; i++){
13 | pages.push(i);
14 | }
15 |
16 |
17 | const handlePrevClick = ()=>{
18 | props.onPrevClick();
19 | }
20 | const handleNextClick = ()=>{
21 | props.onNextClick();
22 | }
23 | const handlePageClick = (e)=>{
24 | props.onPageChange(Number(e.target.id));
25 | }
26 |
27 | const pageNumbers = pages.map(page => {
28 | if(page <= maxPageLimit && page > minPageLimit) {
29 | return(
30 |
32 | {page}
33 |
34 | );
35 | }else{
36 | return null;
37 | }
38 | });
39 |
40 | let pageIncrementEllipses = null;
41 | if(pages.length > maxPageLimit){
42 | pageIncrementEllipses = …
43 | }
44 | let pageDecremenEllipses = null;
45 | if(minPageLimit >=1){
46 | pageDecremenEllipses = …
47 | }
48 | // console.log(props.data);
49 | const renderData = (data)=>{
50 | if(props.type ==1)
51 | {
52 | return(
53 |
54 |
55 |
56 |
{title}
57 |
58 |
59 | {data.map((d) => (
60 |
61 |
62 |
63 |

64 |
65 |
{d.d.name}
66 |
67 |
68 |
71 |
72 |
73 | ))}
74 |
75 |
76 |
77 | )
78 | }
79 | else if(props.type ==2)
80 | {
81 | return(
82 |
83 |
84 |
85 |
{title}
86 |
87 |
88 | {data.map((d) => (
89 |
90 |
91 |
92 |

93 |
94 |
{d.d.name}
95 |
96 |
97 |
98 |
{d.q==null? d.p.ask:d.q.fields.change} auction times
99 |
{d.q==null? "":"Higest price:"+d.q.fields.funds+" SUI"}
100 |
101 |
102 |
103 | ))}
104 |
105 |
106 |
107 | )
108 | }
109 | else
110 | {
111 | return(
112 |
113 |
114 |
115 |
{title}
116 |
117 |
118 | {data?.map((d) => (
119 |
120 |
121 |
122 |

123 |
124 |
{d.name}
125 |
126 |
127 |
128 |
{d.description}
129 |
130 |
131 |
132 | ))}
133 |
134 |
135 |
136 | )
137 | }
138 |
139 |
140 | }
141 |
142 |
143 |
144 | return(
145 |
146 |
147 | {renderData(data)}
148 |
149 |
150 | -
151 |
152 |
153 | {pageDecremenEllipses}
154 | {pageNumbers}
155 | {pageIncrementEllipses}
156 | -
157 |
158 |
159 |
160 |
161 | )
162 | }
163 | export default Pagination;
164 |
--------------------------------------------------------------------------------
/contract/sources/auction_lib.move:
--------------------------------------------------------------------------------
1 | module contract::auction_lib {
2 | use std::option::{Self, Option};
3 | use sui::coin;
4 | use sui::balance::{Self, Balance};
5 | use sui::sui::SUI;
6 | use sui::object::{Self, UID};
7 | use sui::transfer;
8 | use sui::tx_context::{Self,TxContext};
9 |
10 | friend contract::marketplace;
11 |
12 | /// Stores information about an auction bid.
13 | struct BidData has store {
14 | /// Coin representing the current (highest) bid.
15 | funds: Balance,
16 | /// Address of the highest bidder.
17 | highest_bidder: address,
18 | //count change of bid
19 | change: u64,
20 | }
21 |
22 | /// Maintains the state of the auction owned by a trusted
23 | /// auctioneer.
24 | struct Auction has key {
25 | id: UID,
26 | /// Item to be sold. It only really needs to be wrapped in
27 | /// Option if Auction represents a shared object but we do it
28 | /// for single-owner Auctions for better code re-use.
29 | to_sell: Option,
30 | /// Owner of the time to be sold.
31 | owner: address,
32 | /// Data representing the highest bid (starts with no bid)
33 | bid_data: Option,
34 | set_change: u64,
35 | }
36 |
37 | public(friend) fun auction_owner(auction: &Auction): address {
38 | auction.owner
39 | }
40 |
41 | /// Creates an auction. This is executed by the owner of the asset to be
42 | /// auctioned.
43 | public(friend) fun create_auction(
44 | to_sell: T,set_change:u64, ctx: &mut TxContext
45 | ): Auction {
46 | // A question one might asked is how do we know that to_sell
47 | // is owned by the caller of this entry function and the
48 | // answer is that it's checked by the runtime.
49 | Auction {
50 | id: object::new(ctx),
51 | to_sell: option::some(to_sell),
52 | owner: tx_context::sender(ctx),
53 | bid_data: option::none(),
54 | set_change:set_change,
55 | }
56 | }
57 |
58 | public fun dereference_u64(ref: &u64): u64 {
59 | *ref
60 | }
61 |
62 | #[allow(unused_variable)]
63 | /// Updates the auction based on the information in the bid
64 | /// (update auction if higher bid received and send coin back for
65 | /// bids that are too low).
66 | public fun update_auction(
67 | auction: &mut Auction,
68 | bidder: address,
69 | funds: Balance,
70 | ctx: &mut TxContext,
71 | ) {
72 | if (option::is_none(&auction.bid_data)) {
73 | // first bid
74 | let bid_data = BidData {
75 | funds,
76 | highest_bidder: bidder,
77 | change: auction.set_change,
78 | };
79 | option::fill(&mut auction.bid_data, bid_data);
80 | } else {
81 |
82 | let prev_bid_data = option::borrow(&auction.bid_data);
83 | if (balance::value(&funds) > balance::value(&prev_bid_data.funds)) {
84 | // a bid higher than currently highest bid received
85 | let new_bid_data = BidData {
86 | funds,
87 | highest_bidder: bidder,
88 | change: dereference_u64(&prev_bid_data.change) - 1
89 | };
90 |
91 | let s_change = new_bid_data.change;
92 | // update auction to reflect highest bid
93 | let BidData {
94 | funds,
95 | highest_bidder,
96 | change
97 | } = option::swap(&mut auction.bid_data,new_bid_data);
98 |
99 | if(s_change == 0)
100 | {
101 | // transfer previously highest bid to its bidder
102 | send_balance(funds, highest_bidder, ctx);
103 | // end auction send item for bidder
104 | end_shared_auction(auction, ctx);
105 | }
106 | else
107 | {
108 | // a bid is too low - return funds to the bidder
109 | send_balance(funds, bidder, ctx);
110 | };
111 |
112 | } else {
113 | // a bid is too low - return funds to the bidder
114 | send_balance(funds, bidder, ctx);
115 | }
116 | }
117 | }
118 |
119 | #[allow(unused_variable)]
120 | /// Ends the auction - transfers item to the currently highest
121 | /// bidder or to the original owner if no bids have been placed.
122 | fun end_auction(
123 | to_sell: &mut Option,
124 | owner: address,
125 | bid_data: &mut Option,
126 | ctx: &mut TxContext
127 | ) {
128 | let item = option::extract(to_sell);
129 | if (option::is_some(bid_data)) {
130 | // bids have been placed - send funds to the original item
131 | // owner and the item to the highest bidder
132 | let BidData {
133 | funds,
134 | highest_bidder,
135 | change
136 | } = option::extract(bid_data);
137 |
138 | send_balance(funds, owner, ctx);
139 | transfer::public_transfer(item, highest_bidder);
140 | } else {
141 | // no bids placed - send the item back to the original owner
142 | transfer::public_transfer(item, owner);
143 | };
144 | }
145 |
146 | #[allow(unused_variable)]
147 | /// Ends auction and destroys auction object (can only be used if
148 | /// Auction is single-owner object) - transfers item to the
149 | /// currently highest bidder or to the original owner if no bids
150 | /// have been placed.
151 | public fun end_and_destroy_auction(
152 | auction: Auction, ctx: &mut TxContext
153 | ) {
154 | let Auction { id, to_sell, owner, bid_data, set_change} = auction;
155 | object::delete(id);
156 |
157 | end_auction(&mut to_sell, owner, &mut bid_data, ctx);
158 |
159 | option::destroy_none(bid_data);
160 | option::destroy_none(to_sell);
161 | }
162 |
163 | /// Ends auction (should only be used if Auction is a shared
164 | /// object) - transfers item to the currently highest bidder or to
165 | /// the original owner if no bids have been placed.
166 | public fun end_shared_auction(
167 | auction: &mut Auction, ctx: &mut TxContext
168 | ) {
169 | end_auction(&mut auction.to_sell, auction.owner, &mut auction.bid_data, ctx);
170 | }
171 |
172 | /// Helper for the most common operation - wrapping a balance and sending it
173 | fun send_balance(balance: Balance, to: address, ctx: &mut TxContext) {
174 | transfer::public_transfer(coin::from_balance(balance, ctx), to)
175 | }
176 |
177 | /// exposes transfer::transfer
178 | public fun transfer(obj: Auction, recipient: address) {
179 | transfer::transfer(obj, recipient)
180 | }
181 |
182 | #[allow(lint(share_owned))]
183 | public fun share_object(obj: Auction) {
184 | transfer::share_object(obj)
185 | }
186 | }
187 |
--------------------------------------------------------------------------------
/contract/sources/marketplace.move:
--------------------------------------------------------------------------------
1 | module contract::marketplace {
2 | use sui::dynamic_object_field as ofield;
3 | use sui::tx_context::{Self, TxContext};
4 | use sui::object::{Self, ID, UID};
5 | use sui::coin::{Self, Coin};
6 | use sui::bag::{Bag, Self};
7 | use sui::table::{Table, Self};
8 | use sui::sui::SUI;
9 | use sui::event;
10 | use sui::transfer;
11 | use contract::auction_lib::{Self, Auction};
12 |
13 | /// For when amount paid does not match the expected.
14 | const EAmountIncorrect: u64 = 0;
15 | /// For when someone tries to delist without ownership.
16 | const ENotOwner: u64 = 1;
17 |
18 | struct CreateAuction has copy, drop {
19 | sender: address,
20 | }
21 |
22 | struct Bid has copy, drop {
23 | sender: address,
24 | }
25 |
26 | public entry fun create_auction(
27 | bid_market: &mut BidMarket,
28 | to_sell: T,
29 | set_change: u64,
30 | ctx: &mut TxContext)
31 | {
32 | let nft_address = object::id(&to_sell);
33 | let auction = auction_lib::create_auction(to_sell,set_change, ctx);
34 |
35 | event::emit(CreateAuction {
36 | sender: tx_context::sender(ctx)
37 | });
38 | let item_id = object::id(&auction);
39 |
40 | bag::add(&mut bid_market.items,item_id, nft_address);
41 | auction_lib::share_object(auction);
42 | }
43 |
44 | public entry fun bid(coin: Coin, auction: &mut Auction, ctx: &mut TxContext) {
45 |
46 | event::emit(Bid {
47 | sender: tx_context::sender(ctx),
48 | });
49 |
50 | auction_lib::update_auction(
51 | auction,
52 | tx_context::sender(ctx),
53 | coin::into_balance(coin),
54 | ctx
55 | );
56 | }
57 |
58 | /// A shared `Marketplace`. Can be created by anyone using the
59 | /// `create` function. One instance of `Marketplace` accepts
60 | /// only one type of Coin - `COIN` for all its listings.
61 | struct Marketplace has key {
62 | id: UID,
63 | items: Bag,
64 | payments: Table>
65 | }
66 |
67 | /// A shared `Marketplace`. Can be created by anyone using the
68 | /// `create` function. One instance of `Marketplace` accepts
69 | /// only one type of Coin - `COIN` for all its listings.
70 | struct BidMarket has key {
71 | id: UID,
72 | items: Bag,
73 | }
74 |
75 | /// A single listing which contains the listed item and its
76 | /// price in [`Coin`].
77 | struct Listing has key, store {
78 | id: UID,
79 | ask: u64,
80 | owner: address,
81 | }
82 |
83 | /// Create a new shared Marketplace.
84 | public entry fun create(ctx: &mut TxContext) {
85 | let id = object::new(ctx);
86 | let items = bag::new(ctx);
87 | let payments = table::new>(ctx);
88 | transfer::share_object(Marketplace {
89 | id,
90 | items,
91 | payments
92 | })
93 | }
94 |
95 | /// Create a new shared Bid market.
96 | public entry fun createBidMarket(ctx: &mut TxContext) {
97 | let id = object::new(ctx);
98 | let items = bag::new(ctx);
99 | transfer::share_object(BidMarket {
100 | id,
101 | items,
102 | })
103 | }
104 |
105 |
106 | /// List an item at the Marketplace.
107 | public entry fun list(
108 | marketplace: &mut Marketplace,
109 | item: T,
110 | ask: u64,
111 | ctx: &mut TxContext
112 | ) {
113 | let item_id = object::id(&item);
114 | let listing = Listing {
115 | ask,
116 | id: object::new(ctx),
117 | owner: tx_context::sender(ctx),
118 | };
119 |
120 | ofield::add(&mut listing.id, true, item);
121 | bag::add(&mut marketplace.items, item_id, listing)
122 | }
123 |
124 | /// Internal function to remove listing and get an item back. Only owner can do that.
125 | fun delist(
126 | marketplace: &mut Marketplace,
127 | item_id: ID,
128 | ctx: &TxContext
129 | ): T {
130 | let Listing {
131 | id,
132 | owner,
133 | ask: _,
134 | } = bag::remove(&mut marketplace.items, item_id);
135 |
136 | assert!(tx_context::sender(ctx) == owner, ENotOwner);
137 |
138 | let item = ofield::remove(&mut id, true);
139 | object::delete(id);
140 | item
141 | }
142 |
143 | /// Call [`delist`] and transfer item to the sender.
144 | public entry fun delist_and_take(
145 | marketplace: &mut Marketplace,
146 | item_id: ID,
147 | ctx: &mut TxContext
148 | ) {
149 | let item = delist(marketplace, item_id, ctx);
150 | transfer::public_transfer(item, tx_context::sender(ctx));
151 | }
152 |
153 | /// Internal function to purchase an item using a known Listing. Payment is done in Coin.
154 | /// Amount paid must match the requested amount. If conditions are met,
155 | /// owner of the item gets the payment and buyer receives their item.
156 | fun buy(
157 | marketplace: &mut Marketplace,
158 | item_id: ID,
159 | paid: Coin,
160 | ): T {
161 | let Listing {
162 | id,
163 | ask,
164 | owner
165 | } = bag::remove(&mut marketplace.items, item_id);
166 |
167 | assert!(ask == coin::value(&paid), EAmountIncorrect);
168 |
169 | // Check if there's already a Coin hanging and merge `paid` with it.
170 | // Otherwise attach `paid` to the `Marketplace` under owner's `address`.
171 | if (table::contains>(&marketplace.payments, owner)) {
172 | coin::join(
173 | table::borrow_mut>(&mut marketplace.payments, owner),
174 | paid
175 | )
176 | } else {
177 | table::add(&mut marketplace.payments, owner, paid)
178 | };
179 |
180 | let item = ofield::remove(&mut id, true);
181 | object::delete(id);
182 | item
183 | }
184 |
185 | /// Call [`buy`] and transfer item to the sender.
186 | public entry fun buy_and_take(
187 | marketplace: &mut Marketplace,
188 | item_id: ID,
189 | paid: Coin,
190 | ctx: &mut TxContext
191 | ) {
192 | transfer::public_transfer(
193 | buy(marketplace, item_id, paid),
194 | tx_context::sender(ctx)
195 | )
196 | }
197 |
198 | /// Internal function to take profits from selling items on the `Marketplace`.
199 | fun take_profits(
200 | marketplace: &mut Marketplace,
201 | ctx: &TxContext
202 | ): Coin {
203 | table::remove>(&mut marketplace.payments, tx_context::sender(ctx))
204 | }
205 |
206 | #[lint_allow(self_transfer)]
207 | /// Call [`take_profits`] and transfer Coin object to the sender.
208 | public entry fun take_profits_and_keep(
209 | marketplace: &mut Marketplace,
210 | ctx: &mut TxContext
211 | ) {
212 | transfer::public_transfer(
213 | take_profits(marketplace, ctx),
214 | tx_context::sender(ctx)
215 | )
216 | }
217 | }
218 |
--------------------------------------------------------------------------------
/front-end/src/pages/DetailItemOwner/DetailItemOwner.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState,useEffect } from 'react';
2 | import './DetailItemOwner.css'
3 | import creator from '../../assets/seller2.png'
4 | import { useParams } from 'react-router-dom';
5 | import { useWallet } from '@suiet/wallet-kit'
6 | import { TransactionBlock } from '@mysten/sui.js/transactions';
7 | import * as constant from '../../constant/constant';
8 | import toast, { Toaster } from 'react-hot-toast';
9 |
10 | const DetailItemOwner = () => {
11 | let id = useParams().id;
12 | const wallet = useWallet();
13 | const [data, setData] = useState(null);
14 | const [addressWallet, setAddressWallet] = useState(null);
15 | const [transferAddress, settransferAddress] = useState('');
16 | const packageObjectId = constant.packageObjectId;
17 | const moduleName = constant.moduleName;
18 | const moduleMarketName = constant.moduleMarketName;
19 | const [res, setRes] = useState(null);
20 | const [urlEx, seturlEx] = useState(null);
21 | const [numAuction,setNumAuction] = useState(null);
22 | const [NFTPrice,setNFTPrice] = useState(null);
23 |
24 | async function getNFT() {
25 | const listNFT = [];
26 | const infoObject = await constant.client.call('sui_getObject', [id,{"showContent": true}]);
27 | listNFT.push(infoObject.data.content.fields)
28 | //console.log(infoObject);
29 | setData(listNFT);
30 | }
31 |
32 | useEffect(() => {
33 | if (!wallet.connected) return;
34 | setAddressWallet(wallet.account?.address);
35 | // console.log('connected wallet name: ', wallet.name)
36 | // console.log('account address: ', wallet.account?.address)
37 | // console.log('account publicKey: ', wallet.account?.publicKey)
38 | getNFT();
39 |
40 | }, [wallet.connected])
41 |
42 | useEffect(() => {
43 | getRespond();
44 | }, [res])
45 |
46 | async function getRespond(){
47 | const event = await constant.client.call('sui_getEvents', [res.digest]);
48 | console.log(event);
49 | const idObj = event[0].parsedJson.object_id;
50 | seturlEx(constant.suiExploreLink+idObj);
51 | }
52 |
53 | async function transferTo(){
54 | console.log("transferTo", id, addressWallet,transferAddress);
55 | const tx = new TransactionBlock();
56 | tx.moveCall({
57 | target: `${packageObjectId}::${moduleName}::transfer`,
58 | arguments: [tx.pure(id),tx.pure(transferAddress)],
59 | });
60 | try{
61 | const respond = await wallet.signAndExecuteTransactionBlock({
62 | transactionBlock: tx,
63 | });
64 | console.log(respond);
65 | toast.success('Transfer NFT to'+transferAddress+' success!');
66 | setRes(respond);
67 | window.location.href = window.location.origin + "/ItemOwner";
68 | }
69 | catch{
70 | console.log('error');
71 | }
72 | return;
73 | }
74 |
75 | async function BidNFT(){
76 | const tx = new TransactionBlock();
77 | tx.moveCall({
78 | target: `${packageObjectId}::${moduleMarketName}::create_auction`,
79 | typeArguments: [constant.typeArgNFT,constant.suiCoin],
80 | arguments: [tx.pure(constant.bidMarketID),tx.pure(id),tx.pure(numAuction)],
81 | });
82 | try{
83 | const res = await wallet.signAndExecuteTransactionBlock({
84 | transactionBlock: tx,
85 | });
86 | console.log(res);
87 | toast.success('Public to bid success!');
88 | window.location.href = window.location.origin + "/ItemOwner";
89 | }
90 | catch{
91 | console.log('error');
92 | }
93 | }
94 |
95 | async function SaleNFT(){
96 | const tx = new TransactionBlock();
97 | tx.moveCall({
98 | target: `${packageObjectId}::${moduleMarketName}::list`,
99 | typeArguments: [constant.typeArgNFT,constant.suiCoin],
100 | arguments: [tx.pure(constant.marketID),tx.pure(id),tx.pure(NFTPrice)],
101 | });
102 | try{
103 | const res = await wallet.signAndExecuteTransactionBlock({
104 | transactionBlock: tx,
105 | });
106 | console.log(res);
107 | toast.success('Public to sale success!');
108 | window.location.href = window.location.origin + "/ItemOwner";
109 | }
110 | catch{
111 | console.log('error');
112 | }
113 | }
114 |
115 | async function burn(){
116 | console.log("burn", id, addressWallet);
117 | const tx = new TransactionBlock();
118 | tx.moveCall({
119 | target: `${packageObjectId}::${moduleName}::burn`,
120 | arguments: [tx.pure(id)],
121 | });
122 | try{
123 | const res = await wallet.signAndExecuteTransactionBlock({
124 | transactionBlock: tx,
125 | });
126 | console.log(res);
127 | toast.success('Burn NFT success!');
128 | window.location.href = window.location.origin + "/ItemOwner";
129 | }
130 | catch{
131 | console.log('error');
132 | }
133 | return;
134 | }
135 |
136 |
137 |
138 | return (
139 |
140 |
141 | {data?.map((d) => (
142 |
143 |
144 |

145 |
146 |
147 |
148 |
{d.name}
149 |
100 SUI (transfer fee: 1%) ‧ 20 of 25 available
150 |
151 |
152 |
153 |
154 |

155 |
{wallet.account?.address.substring(0,6)+"..."+wallet.account?.address.substring(wallet.account?.address.length-6,wallet.account?.address.length)}
156 |
157 |
158 |
159 |
{d.description}
160 |
161 |
162 | setNumAuction(e.target.value)}/>
163 |
164 |
165 |
166 | setNFTPrice(e.target.value)}/>
167 |
168 |
169 |
170 | settransferAddress(e.target.value)}/>
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 | ))}
179 |
180 | )
181 | };
182 |
183 | export default DetailItemOwner;
184 |
--------------------------------------------------------------------------------
/front-end/src/components/nftMint/nftMint.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState,useEffect } from 'react'
2 | import './nftMint.css'
3 | import OpenAI from "openai";
4 | import { TransactionBlock } from '@mysten/sui.js/transactions';
5 | import { useWallet } from '@suiet/wallet-kit';
6 | import toast, { Toaster } from 'react-hot-toast';
7 | import { getFullnodeUrl, SuiClient } from '@mysten/sui.js/client';
8 | import * as moment from 'moment';
9 | import * as constant from '../../constant/constant';
10 | import { ref, getDownloadURL, uploadBytesResumable } from "firebase/storage";
11 | import domtoimage from 'dom-to-image';
12 |
13 | const NFTMint = () => {
14 | const key=constant.OpenAIKey;
15 | const openai = new OpenAI({ apiKey: key , dangerouslyAllowBrowser: true });
16 | const [data, setData] = useState(null);
17 | const [num, setNum] = useState(0);
18 | const [state, setState] = useState(false);
19 | const randomNumberInRange = (min, max) => {
20 | return Math.floor(Math.random()
21 | * (max - min + 1)) + min;
22 | };
23 | const wallet = useWallet();
24 | const packageObjectId = constant.packageObjectId;
25 | const moduleName = constant.moduleName;
26 |
27 | const rpcUrl = getFullnodeUrl('devnet');
28 | const client = new SuiClient({ url: rpcUrl });
29 | const [res, setRes] = useState(null);
30 | const [nameNFT, setName] = useState(null);
31 | const [urlEx, seturlEx] = useState(null);
32 | const [imgUrl, setImgUrl] = useState(null);
33 | const [text, setText] = useState(null);
34 | const [progresspercent, setProgresspercent] = useState(0);
35 | const [openAIRes, setopenAIRes] = useState("");
36 |
37 | async function handleclick(){
38 | let time = new Date();
39 | setImgUrl(null);
40 | let formattedDate = (moment(time)).format('YYYYMMDDHHmmss')
41 |
42 | setState(true);
43 | setTimeout(() => {
44 | const image = async () => {
45 | try{
46 | const a = await openai.images.generate({ prompt: "Creat cute meme or fun meme or fantasy meme",size:"256x256", n: 1, });
47 | setName("AI_NFT#"+formattedDate);
48 | let urlImage = a.data[0].url;
49 | if(urlImage == null) urlImage = constant.defaultImgURL;
50 | //setData(urlImage);
51 | CreateImage("AI_NFT#"+formattedDate,"Image generateted by for future NFT",urlImage);
52 | toast.success('Mint NFT success!');
53 | }
54 | catch{
55 | //setData(constant.defaultImgURL);
56 | setName("AI_NFT#"+formattedDate);
57 | CreateImage("AI_NFT#"+formattedDate,"MEME created by for future NFT",constant.defaultImgURL);
58 | //setData(constant.defaultImgURL);
59 | toast.error('Limmit access mint NFT for Today!');
60 | }
61 | }
62 | image();
63 | }, 100);
64 | };
65 |
66 | async function convertUrlToBase64(imageUrl) {
67 | if(imageUrl != null){
68 | var img = document.getElementById("myImage");
69 | console.log(img);
70 | domtoimage.toJpeg(document.getElementById('myImage'), { quality: 0.95 })
71 | .then(function (dataUrl) {
72 | console.log(dataUrl);
73 | });
74 | }
75 | }
76 |
77 | async function uploadFireBase(fileName,rootImgURL){
78 | try {
79 | //const base64Data = await convertUrlToBase64(rootImgURL);
80 | // console.log(base64Data);
81 | // let typeimg = base64Data.split('/')[1].split(';')[0];
82 | // console.log(typeimg);
83 | // console.log(base64Data.replace('data:image/'+typeimg+';base64,',''));
84 | // const storageRef = ref(constant.storage, `files/${fileName+"."+typeimg}`);
85 | // const uploadTask = uploadBytesResumable(storageRef,Buffer.from(base64Data.replace('data:image/'+typeimg+';base64,',''), "base64") );
86 |
87 | // uploadTask.on("state_changed",
88 | // (snapshot) => {
89 | // const progress =
90 | // Math.round((snapshot.bytesTransferred / snapshot.totalBytes) * 100);
91 | // setProgresspercent(progress);
92 | // },
93 | // (error) => {
94 | // alert(error);
95 | // },
96 | // () => {
97 | // getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => {
98 | // setImgUrl(downloadURL)
99 | // });
100 | // }
101 | // );
102 | setImgUrl(rootImgURL);
103 | } catch (error) {
104 | console.log(error.message)
105 | //setError(error.message);
106 | }
107 | }
108 |
109 | useEffect(() => {
110 | if (!wallet.connected) return;
111 | // console.log('connected wallet name: ', wallet.name)
112 | // console.log('account address: ', wallet.account?.address)
113 | // console.log('account publicKey: ', wallet.account?.publicKey)
114 | if(!res){
115 | getRespond();
116 | }
117 |
118 | }, [wallet.connected])
119 |
120 | useEffect(() => {
121 | getRespond();
122 | }, [res])
123 |
124 | async function getRespond(){
125 | const event = await client.call('sui_getEvents', [res.digest]);
126 | console.log(event);
127 | const idObj = event[0].parsedJson.object_id;
128 | seturlEx(constant.suiExploreLink+idObj);
129 | }
130 |
131 | async function CreateImage(name,text,url) {
132 | // let unsubscribe = await client.subscribeEvent({
133 | // filter: { Package: packageObjectId },
134 | // onMessage: (event) => {
135 | // console.log("subscribeEvent", JSON.stringify(event, null, 2))
136 | // }
137 | // });
138 | // const committeeInfo = await client.call('suix_getOwnedObjects', [wallet.account?.address]);
139 | // console.log(committeeInfo);
140 | // setState(false);
141 | // return
142 | setText(text);
143 | setName(name);
144 | await uploadFireBase(name,url);
145 |
146 | }
147 |
148 | useEffect(async()=>{
149 | if(imgUrl!=null && state)
150 | {
151 | console.log(nameNFT,imgUrl,text);
152 | const tx = new TransactionBlock();
153 | tx.moveCall({
154 | target: `${packageObjectId}::${moduleName}::mint_to_sender`,
155 | arguments: [tx.pure(nameNFT),tx.pure(text),tx.pure(imgUrl)],
156 | });
157 | try{
158 | const respond = await wallet.signAndExecuteTransactionBlock({
159 | transactionBlock: tx,
160 | });
161 | setRes(respond);
162 | setState(false);
163 | setData(imgUrl);
164 | }
165 | catch{
166 | setState(false);
167 | }
168 | }
169 | },[imgUrl])
170 |
171 | async function tryclick(){
172 | setData(null);
173 | };
174 |
175 | if(data!= null)
176 | {
177 | return(
178 |
179 |
180 |
181 |
Congratulations! This is your NFT!
182 |
183 |
184 |
185 |
186 |
187 |

188 |
189 |
190 |
191 |
{nameNFT}
192 |
193 |
194 |
195 |
196 |
197 |
198 | );
199 | }
200 |
201 | return (
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
Click Mint button to mint your own NFT
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 | )
220 | }
221 |
222 | export default NFTMint
223 |
--------------------------------------------------------------------------------