Đặc tả: NFT Management Feature
Module: web (port 8080) + webmarketplace (port 8084)
Status: Production
1. Tổng quan
Feature quản lý lifecycle của 3 loại NFT (Hunter, Gauntlet, Bounty Ball) và rental marketplace cho Bounty Ball.
2. Phạm vi
In-scope - NFT APIs (web module)
HunterController (/api/nft-hunter)
| Endpoint |
Method |
Mô tả |
/ |
GET |
Danh sách Hunter của user |
/{id} |
GET |
Chi tiết Hunter |
| (CRUD endpoints) |
POST/PUT/DELETE |
Quản lý Hunter |
NftGauntletController (/api/nft-gauntlet)
| Endpoint |
Method |
Mô tả |
/ |
GET |
Danh sách Gauntlet của user |
/{id} |
GET |
Chi tiết Gauntlet |
NftBountyBallController (/api/nft-bounty-ball)
| Endpoint |
Method |
Mô tả |
/ |
GET |
Danh sách Bounty Ball của user |
/{id} |
GET |
Chi tiết Bounty Ball |
| (lifecycle endpoints) |
POST/PUT |
Manage Bounty Ball state |
In-scope - Rental Market (webmarketplace module)
NftRentalController (/api/nft-rental)
| Endpoint |
Method |
Mô tả |
/ |
POST |
Tạo rental order (owner listing NFT) |
/verify-order-creation/{id} |
PUT |
Verify creation (on-chain confirm) |
/my-bounty-balls |
GET |
Bounty balls của owner (paginated + filtered) |
/my-bounty-balls/{id} |
GET |
Bounty ball detail của owner |
/my-rental-order |
GET |
Rental orders của owner (paginated) |
/get-rental-order-by-ball-id/{id} |
GET |
Rental order by Bounty Ball ID |
/get-sale-order-by-ball-id/{id} |
GET |
Sale order by Bounty Ball token ID |
/market-rental |
GET |
Thị trường rental (tất cả NEW orders, exclude owner) |
/{rentalOrderId} |
GET |
Rental order detail |
/confirm-rent/{rentalOrderId} |
PUT |
Renter confirm thuê NFT |
/cancel-rental-order/{id} |
PUT |
Owner cancel rental listing |
/finish-rental-order/{id} |
PUT |
Kết thúc rental (test endpoint) |
/return-rental-early/{id} |
PUT |
Renter trả về sớm |
/rental-duration |
GET |
Danh sách rental duration + fee suggestions |
/rental-data |
GET |
Tổng hợp rental data của user |
Out-of-scope
| Mục |
Lý do |
| NFT minting process |
Xử lý qua webhook + node server |
| NFT trading (buy/sell) |
Thuộc payment-marketplace feature |
| Gacha NFT rewards |
Thuộc prize-allocation feature |
3. User stories
| ID |
Role |
Story |
Acceptance |
| NFT-US-01 |
Owner |
List Bounty Ball lên rental market với giá và thời hạn |
status=NEW, product RENTING |
| NFT-US-02 |
Renter |
Browse market → confirm rent → NFT available trong inventory của renter |
B-Coin trừ, owner nhận deposit |
| NFT-US-03 |
Renter |
Trả về sớm → nhận lại phần coin còn lại (pro-rated) |
status=RETURN_EARLY |
| NFT-US-04 |
Owner |
Cancel listing trước khi có renter → NFT trở lại AVAILABLE |
status=CANCELLED |
| NFT-US-05 |
System |
Rental hết hạn → batch job tự động xử lý return |
processExpiredRental() called |
| NFT-US-06 |
Player |
Xem Hunter/Gauntlet inventory + attribute points |
Correct stats displayed |
4. Functional requirements
| ID |
Requirement |
Chi tiết |
| NFT-F-01 |
Rental order create |
Validate status=AVAILABLE, set product RENTING, tạo NftRentalOrderModel{status=NEW} |
| NFT-F-02 |
Verify creation |
On-chain confirm via transactionHash; nếu fail → rollback product AVAILABLE |
| NFT-F-03 |
Confirm rent |
Charge renter B-Coin, deposit owner (B-Coin), deduct admin fee; set status=RENTING |
| NFT-F-04 |
Cancel rental |
Chỉ cho phép khi status=NEW; set product AVAILABLE, order CANCELLED |
| NFT-F-05 |
Return early |
Pro-rated refund, owner nhận phần đã dùng; status=RETURN_EARLY |
| NFT-F-06 |
Expiry batch |
NftRentalExpirationCheckBatch chạy định kỳ, call processExpiredRental() |
| NFT-F-07 |
Minted/unminted branch |
Nếu NFT minted → call NodeServerService.confirmSolanaNftRental(); unminted → DB only |
| NFT-F-08 |
Rental duration suggestions |
Fee = coefficientA(rarity) × duration: COMMON=50, UNCOMMON=100, RARE=300, EPIC=500, LEGENDARY=1000 |
| NFT-F-09 |
Market filtering |
/market-rental filter: status=NEW, exclude ownerId=loginUser, sort by NEWEST |
| NFT-F-10 |
Equipment/gimmick sync |
NFT state change → update user equipment records |
5. Business rules
Rental status lifecycle
NEW → RENTING → FINISHED
NEW → CANCELLED
RENTING → RETURN_EARLY
RENTING → EXPIRED_HANDLED (by batch)
rentalFeeSuggest = coefficientA(rarity) × duration(days)
Rarity: COMMON=50, UNCOMMON=100, RARE=300, EPIC=500, LEGENDARY=1000
Concurrency guard
- Confirm rent: transaction + status lock (phải
status=NEW để confirm).
- Cancel: phải
status=NEW để cancel.
6. Data contracts
Request - Create rental order
{
"bounty_ball_id": "<nftId>",
"rental_duration": 7,
"rental_fee": 350,
"rental_currency": "BCOIN"
}
Response - NftRentalOrderModel
{
"id": "<orderId>",
"owner_id": "<ownerId>",
"renter_id": null,
"bounty_ball_id": "<nftId>",
"rental_status": "NEW",
"rental_duration": 7,
"rental_fee": 350,
"rental_start_time": null,
"rental_end_time": null,
"ball_of_user": { ... }
}
Response - Rental duration suggestions
[
{ "rental_duration": 7, "rarity": "COMMON", "rental_fee_suggest": 350 },
{ "rental_duration": 7, "rarity": "RARE", "rental_fee_suggest": 2100 },
...
]
7. Acceptance criteria
- [ ] Create rental order: product
status=RENTING, order status=NEW
- [ ] Verify order fail: product rollback
AVAILABLE, order CANCELLED
- [ ] Confirm rent: renter B-Coin charged, owner received, admin fee deducted,
status=RENTING
- [ ] Cancel (status=NEW): product
AVAILABLE, order CANCELLED
- [ ] Return early: pro-rated refund calculated correctly
- [ ] Market listing: không hiển thị item của chính owner
- [ ] Batch expiry: expired rentals processed, NFT returned
- [ ] Minted NFT:
confirmSolanaNftRental() called
- [ ] Rental fee suggestions: match formula per rarity × duration
8. Constraints
- Sort
market-rental: hỗ trợ RentalOrderSortType enum: NEWEST, và các giá trị khác.
my-bounty-balls: filter lang_key là bắt buộc (throw LANG_KEY_IS_INVALID nếu thiếu).
- Exclude chain IDs:
80002, 137 trong Bounty Ball filter.
9. Code references
webmarketplace/
controllers/nft_rental/NftRentalController.java
controllers/nft_rental/dto/NftRentalOrderDto.java
controllers/nft_rental/dto/NftRentalOrderResponse.java
web/
controllers/hunter/NftHunterController.java
controllers/nft_gauntlet/NftGauntletController.java
controllers/nft_bounty_ball/NftBountyBallController.java
application-core/
service/nft_rental/nft_rental_order/NftRentalOrderService.java
service/nft_rental/nft_rental_order/NftRentalOrderModel.java
service/nft_bounty_ball/NftBountyBallService.java
service/nft_hunter/NftHunterService.java
service/nft_gauntlet/NftGauntletService.java
batch/
job/nft_rental/NftRentalExpirationCheckBatch.java