Skip to content

Commit

Permalink
Fixing secondary market
Browse files Browse the repository at this point in the history
  • Loading branch information
avkr003 committed Oct 19, 2023
1 parent 2abcdbe commit ce87788
Show file tree
Hide file tree
Showing 76 changed files with 685 additions and 847 deletions.
1 change: 0 additions & 1 deletion app/constants/Form.scala
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ object Form {
val ADD_FROM_NFT_OWNERS: Form = Form("ADD_FROM_NFT_OWNERS", routes.javascript.WhitelistController.addFromNFTOwnersForm, routes.WhitelistController.addFromNFTOwners())

val NFT_BASIC_DETAIL: Form = Form("NFT_BASIC_DETAIL", routes.javascript.NFTController.basicDetailsForm, routes.NFTController.basicDetails())
val NFT_TAGS: Form = Form("NFT_TAGS", routes.javascript.NFTController.tagsForm, routes.NFTController.tags())
val NFT_SET_PROPERTIES: Form = Form("NFT_SET_PROPERTIES", routes.javascript.NFTController.setPropertiesForm, routes.NFTController.setProperties())
val NFT_MINT: Form = Form("NFT_MINT", routes.javascript.NFTController.mintForm, routes.NFTController.mint())
val NFT_TRANSFER: Form = Form("NFT_TRANSFER", routes.javascript.NFTController.transferForm, routes.NFTController.transfer())
Expand Down
6 changes: 3 additions & 3 deletions app/constants/FormConstraint.scala
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,9 @@ object FormConstraint {
if (errors.isEmpty) Valid else Invalid(errors)
})

val nftTagsConstraint: Constraint[NFTTags.Data] = Constraint("constraints.NFTTagsConstraint")({ nftTagsData: NFTTags.Data =>
if (nftTagsData.tags != "") {
val tags = nftTagsData.tags.split(constants.NFT.Tags.Separator)
val NFTBasicDetailConstraint: Constraint[NFTBasicDetail.Data] = Constraint("constraints.NFTBasicDetail")({ nftBasicDetail: NFTBasicDetail.Data =>
if (nftBasicDetail.tags != "") {
val tags = nftBasicDetail.tags.split(constants.NFT.Tags.Separator)
val errors = Seq(
if (tags.length > constants.NFT.Tags.MaximumAllowed) Option(ValidationError(constants.Response.MAXIMUM_NFT_TAGS_EXCEEDED.message)) else None,
if (tags.exists(x => x.length < constants.NFT.Tags.MinimumLength || x.length > constants.NFT.Tags.MaximumLength)) Option(ValidationError(constants.Response.INVALID_NFT_TAGS_LENGTH.message)) else None,
Expand Down
1 change: 1 addition & 0 deletions app/constants/FormField.scala
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ object FormField {
// LongFormField
val SELL_QUANTITY: LongFormField = LongFormField("SELL_QUANTITY", 1, Long.MaxValue)
val BUY_QUANTITY: LongFormField = LongFormField("BUY_QUANTITY", 1, Long.MaxValue)
val NFT_TRANSFER_AMOUNT: LongFormField = LongFormField("NFT_TRANSFER_AMOUNT", 1, Long.MaxValue)

// SelectFormField
// Not adding Height type for user
Expand Down
1 change: 1 addition & 0 deletions app/constants/View.scala
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ object View {
val BLOCKCHAIN_TRANSACTION_SUCCESS_SUBTITLE = "BLOCKCHAIN_TRANSACTION_SUCCESS_SUBTITLE"
val BROADCASTING_BLOCKCHAIN_TRANSACTION_SUCCESS_TITLE = "BROADCASTING_BLOCKCHAIN_TRANSACTION_SUCCESS_TITLE"
val BUYNOW = "BUYNOW"
val OTHER_OFFERS = "OTHER_OFFERS"
val BUY_MINT_NFT = "BUY_MINT_NFT"
val BUY_SELL = "BUY_SELL"
val CANCEL = "CANCEL"
Expand Down
9 changes: 5 additions & 4 deletions app/controllers/CollectionController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -432,19 +432,20 @@ class CollectionController @Inject()(
}
},
setCapabilitiesData => {
val collectionDraft = masterTransactionCollectionDrafts.Service.tryGet(setCapabilitiesData.collectionId)
def getCollectionDraft = masterTransactionCollectionDrafts.Service.tryGet(setCapabilitiesData.collectionId)

def update(collectionDraft: CollectionDraft) = if (collectionDraft.creatorId == loginState.username) {
masterTransactionCollectionDrafts.Service.addProperties(collectionDraft.copy(properties = collectionDraft.getPropertiesWithoutCapabilities), setCapabilitiesData.getProperties)
} else constants.Response.NOT_COLLECTION_OWNER.throwBaseException()

(for {
collectionDraft <- collectionDraft
collectionDraft <- getCollectionDraft
_ <- update(collectionDraft)
} yield PartialContent(views.html.collection.defineProperties(collectionDraft = collectionDraft))
updatedCollectionDraft <- getCollectionDraft
} yield PartialContent(views.html.collection.defineProperties(collectionDraft = updatedCollectionDraft))
).recover {
case baseException: BaseException => try {
BadRequest(views.html.collection.setCapabilities(SetCapabilities.form.withGlobalError(baseException.failure.message), Await.result(collectionDraft, Duration.Inf)))
BadRequest(views.html.collection.setCapabilities(SetCapabilities.form.withGlobalError(baseException.failure.message), Await.result(getCollectionDraft, Duration.Inf)))
} catch {
case _: Exception => InternalServerError
}
Expand Down
14 changes: 4 additions & 10 deletions app/controllers/IndexController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ class IndexController @Inject()(
}

try {
starter.start()
Await.result(masterSecrets.Utility.setAll(), Duration.Inf)
println(constants.Secret.issueIdentityWallet.address)
println(constants.Secret.defineAssetWallet.address)
Expand All @@ -83,21 +84,14 @@ class IndexController @Inject()(
Await.result(nftPublicListings.Utility.migrate, Duration.Inf)
Await.result(nftSales.Utility.migrate, Duration.Inf)
Await.result(sendCoins.Utility.migrate, Duration.Inf)
} catch {
case exception: Exception => logger.error(exception.getLocalizedMessage)
}
starter.changeAwsKey()

// starter.start()

try {
Await.result(starter.updateIdentityIDs(), Duration.Inf)
Await.result(starter.updateAssetIDs(), Duration.Inf)
Await.result(starter.markMintReady(), Duration.Inf)
starter.fixAllMultipleActiveKeys()
} catch {
case exception: Exception => logger.error(exception.getLocalizedMessage)
}
starter.changeAwsKey()

utilities.Scheduler.startSchedulers(
// blockchain
Expand All @@ -115,8 +109,7 @@ class IndexController @Inject()(
cancelOrderTransactions.Utility.scheduler,
defineAssetTransactions.Utility.scheduler,
issueIdentityTransactions.Utility.scheduler,
masterTransactionLatestBlocks.Utility.scheduler,
// mintAssetTransactions.Utility.scheduler,
mintAssetTransactions.Utility.scheduler,
nftMintingFeeTransactions.Utility.scheduler,
nftTransferTransactions.Utility.scheduler,
provisionAddressTransactions.Utility.scheduler,
Expand All @@ -130,6 +123,7 @@ class IndexController @Inject()(
unprovisionAddressTransactions.Utility.scheduler,
unwrapTransactions.Utility.scheduler,
wrapTransactions.Utility.scheduler,
masterTransactionLatestBlocks.Utility.scheduler,
)

coordinatedShutdown.addTask(CoordinatedShutdown.PhaseBeforeServiceUnbind, "ThreadShutdown")(utilities.Scheduler.shutdownListener())
Expand Down
4 changes: 2 additions & 2 deletions app/controllers/JavaScriptRoutesController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ class JavaScriptRoutesController @Inject()(messagesControllerComponents: Message

routes.javascript.NFTController.viewNFT,
routes.javascript.NFTController.details,
routes.javascript.NFTController.marketListings,
routes.javascript.NFTController.detailViewLeftCards,
routes.javascript.NFTController.detailViewRightCards,
routes.javascript.NFTController.info,
Expand All @@ -87,7 +86,6 @@ class JavaScriptRoutesController @Inject()(messagesControllerComponents: Message
routes.javascript.NFTController.uploadNFTFile,
routes.javascript.NFTController.basicDetailsForm,
routes.javascript.NFTController.setPropertiesForm,
routes.javascript.NFTController.tagsForm,
routes.javascript.NFTController.deleteDraftForm,
routes.javascript.NFTController.deleteDraft,
routes.javascript.NFTController.price,
Expand All @@ -96,7 +94,9 @@ class JavaScriptRoutesController @Inject()(messagesControllerComponents: Message
routes.javascript.NFTController.overview,
routes.javascript.NFTController.trade,
routes.javascript.NFTController.sellOrders,
routes.javascript.NFTController.sellOrdersPerPage,
routes.javascript.NFTController.yourOrders,
routes.javascript.NFTController.yourOrdersPerPage,

routes.javascript.SettingController.viewSettings,
routes.javascript.SettingController.settings,
Expand Down
113 changes: 49 additions & 64 deletions app/controllers/NFTController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,13 @@ class NFTController @Inject()(

def overview(nftId: String, activeTab: String): Action[AnyContent] = withoutLoginActionAsync { implicit loginState =>
implicit request =>
Future(Ok(views.html.nft.detail.view(nftId = nftId, activeTab = activeTab)))
val nft = masterNFTs.Service.tryGet(nftId)
(for {
nft <- nft
} yield Ok(views.html.nft.detail.view(nftId = nftId, totalSupply = nft.totalSupply, activeTab = activeTab))
).recover {
case baseException: BaseException => InternalServerError(baseException.failure.message)
}
}

def details(nftId: String): EssentialAction = cached(req => utilities.Session.getSessionCachingKey(req), constants.CommonConfig.WebAppCacheDuration) {
Expand Down Expand Up @@ -103,31 +109,45 @@ class NFTController @Inject()(
Future(Ok(views.html.nft.detail.trade(nftId = nftId)))
}

def sellOrders(): Action[AnyContent] = withoutLoginActionAsync { implicit loginState =>
def sellOrders(nftId: String): Action[AnyContent] = withoutLoginActionAsync { implicit loginState =>
implicit request =>
Future(Ok(views.html.nft.detail.sellOrders()))
Future(Ok(views.html.nft.detail.sellOrders(nftId)))
}

def yourOrders(): Action[AnyContent] = withoutLoginActionAsync { implicit loginState =>
def sellOrdersPerPage(nftId: String, pageNumber: Int): Action[AnyContent] = withoutLoginActionAsync { implicit loginState =>
implicit request =>
Future(Ok(views.html.nft.detail.yourOrders()))
val secondaryMarkets = masterSecondaryMarkets.Service.getByNFTIdAndPageNumber(nftId = nftId, pageNumber = pageNumber)

def orders(secondaryMarkets: Seq[SecondaryMarket]) = blockchainOrders.Service.get(secondaryMarkets.map(_.orderId))

(for {
secondaryMarkets <- secondaryMarkets
orders <- orders(secondaryMarkets)
} yield Ok(views.html.nft.detail.sellOrdersPerPage(secondaryMarkets.sortBy(_.price), orders, blockchainBlocks.Service.getLatestHeight, masterTransactionTokenPrices.Service.getLatestPrice, pageNumber))
).recover {
case baseException: BaseException => InternalServerError(baseException.failure.message)
}
}

def marketListings(nftId: String, pageNumber: Int): EssentialAction = cached(req => utilities.Session.getSessionCachingKey(req), constants.CommonConfig.WebAppCacheDuration) {
withoutLoginActionAsync { implicit loginState =>
implicit request =>
val secondaryMarkets = masterSecondaryMarkets.Service.getByNFTIdAndPageNumber(nftId, pageNumber)
def yourOrders(nftId: String): Action[AnyContent] = withLoginAction { implicit loginState =>
implicit request =>
implicit val optionalLoginState: Option[LoginState] = Option(loginState)
Ok(views.html.nft.detail.yourOrders(nftId))
}

def orders(secondaryMarkets: Seq[SecondaryMarket]) = blockchainOrders.Service.get(secondaryMarkets.map(_.orderId))
def yourOrdersPerPage(nftId: String, pageNumber: Int): Action[AnyContent] = withLoginActionAsync { implicit loginState =>
implicit request =>
val secondaryMarkets = masterSecondaryMarkets.Service.getByNFTIdAndSellerIdAndPageNumber(nftId = nftId, sellerId = loginState.username, pageNumber = pageNumber)

(for {
secondaryMarkets <- secondaryMarkets
orders <- orders(secondaryMarkets)
} yield Ok(views.html.nft.detail.secondaryMarkets(secondaryMarkets.sortBy(_.price), orders, blockchainBlocks.Service.getLatestHeight, masterTransactionTokenPrices.Service.getLatestPrice))
).recover {
case baseException: BaseException => InternalServerError(baseException.failure.message)
}
}
def orders(secondaryMarkets: Seq[SecondaryMarket]) = blockchainOrders.Service.get(secondaryMarkets.map(_.orderId))

(for {
secondaryMarkets <- secondaryMarkets
orders <- orders(secondaryMarkets)
} yield Ok(views.html.nft.detail.yourOrdersPerPage(secondaryMarkets.sortBy(_.price), orders, blockchainBlocks.Service.getLatestHeight, masterTransactionTokenPrices.Service.getLatestPrice, pageNumber))
).recover {
case baseException: BaseException => InternalServerError(baseException.failure.message)
}
}

def detailViewLeftCards(nftId: String): EssentialAction = cached(req => utilities.Session.getSessionCachingKey(req), constants.CommonConfig.WebAppCacheDuration) {
Expand Down Expand Up @@ -158,6 +178,7 @@ class NFTController @Inject()(
implicit request =>
val nft = masterNFTs.Service.tryGet(nftId)
val countOwners = masterNFTOwners.Service.countOwners(nftId)
val secondaryMarket = masterSecondaryMarkets.Service.getByNFTIdAndLowestPrice(nftId)

def nftOwner(countOwners: Int): Future[Option[NFTOwner]] = if (countOwners == 1) {
masterNFTOwners.Service.getByNFTID(nftId = nftId).map(Option(_))
Expand All @@ -170,7 +191,8 @@ class NFTController @Inject()(
countOwners <- countOwners
nftOwner <- nftOwner(countOwners)
collection <- collection(nft.collectionId)
} yield Ok(views.html.nft.detail.collectionInfo(nft, collection, nftOwner, countOwners))
secondaryMarket <- secondaryMarket
} yield Ok(views.html.nft.detail.collectionInfo(nft, collection, nftOwner, countOwners, secondaryMarket))
).recover {
case baseException: BaseException => InternalServerError(baseException.failure.message)
}
Expand Down Expand Up @@ -331,54 +353,17 @@ class NFTController @Inject()(

},
basicDetailsData => {
val isOwner = masterCollections.Service.isOwner(id = basicDetailsData.collectionId, accountId = loginState.username)
val collection = masterCollections.Service.tryGet(id = basicDetailsData.collectionId)

def update(isOwner: Boolean) = if (isOwner) masterTransactionNFTDrafts.Service.updateNameDescription(id = basicDetailsData.nftId, name = basicDetailsData.name, description = basicDetailsData.description)
else constants.Response.NOT_COLLECTION_OWNER.throwBaseException()

(for {
isOwner <- isOwner
nftDraft <- update(isOwner)
} yield PartialContent(views.html.nft.tags(collectionId = basicDetailsData.collectionId, nftId = nftDraft.id, tags = nftDraft.tagNames.getOrElse(Seq.empty[String])))
).recover {
case baseException: BaseException => BadRequest(views.html.nft.nftBasicDetail(NFTBasicDetail.form.withGlobalError(baseException.failure.message), collectionId = basicDetailsData.collectionId, nftId = basicDetailsData.nftId, None))
}
}
)
}

def tagsForm(collectionId: String, nftId: String): Action[AnyContent] = withLoginActionAsync { implicit loginState =>
implicit request =>
val isOwner = masterCollections.Service.isOwner(id = collectionId, accountId = loginState.username)
val nftDraft = masterTransactionNFTDrafts.Service.get(nftId)
(for {
isOwner <- isOwner
nftDraft <- nftDraft
} yield if (isOwner) Ok(views.html.nft.tags(collectionId = collectionId, nftId = nftId, tags = nftDraft.fold[Seq[String]](Seq())(_.tagNames.getOrElse(Seq.empty[String]))))
else constants.Response.NOT_COLLECTION_OWNER.throwBaseException()
).recover {
case baseException: BaseException => BadRequest(baseException.failure.message)
}
}

def tags(): Action[AnyContent] = withLoginActionAsync { implicit loginState =>
implicit request =>
views.nft.companion.NFTTags.form.bindFromRequest().fold(
formWithErrors => {
Future(BadRequest(views.html.nft.tags(formWithErrors, formWithErrors.data.getOrElse(constants.FormField.COLLECTION_ID.name, ""), formWithErrors.data.getOrElse(constants.FormField.NFT_ID.name, ""), formWithErrors.data.getOrElse(constants.FormField.NFT_TAGS.name, "").split(","))))
},
tagsData => {
val collection = masterCollections.Service.tryGet(id = tagsData.collectionId)

def update(collection: Collection) = if (collection.creatorId == loginState.username) masterTransactionNFTDrafts.Service.updateTagNames(id = tagsData.nftId, tagNames = tagsData.getTags)
def update(isOwner: Boolean) = if (isOwner) masterTransactionNFTDrafts.Service.updateBasicAndTags(id = basicDetailsData.nftId, name = basicDetailsData.name, description = basicDetailsData.description, tags = basicDetailsData.getTags)
else constants.Response.NOT_COLLECTION_OWNER.throwBaseException()

(for {
collection <- collection
_ <- update(collection)
} yield PartialContent(views.html.nft.setProperties(collection = collection, nftId = tagsData.nftId))
nftDraft <- update(collection.creatorId == loginState.username)
} yield PartialContent(views.html.nft.setProperties(collection = collection, nftId = nftDraft.id))
).recover {
case baseException: BaseException => BadRequest(views.html.nft.tags(views.nft.companion.NFTTags.form.withGlobalError(baseException.failure.message), collectionId = tagsData.collectionId, nftId = tagsData.nftId, tags = tagsData.getTags))
case baseException: BaseException => BadRequest(views.html.nft.nftBasicDetail(NFTBasicDetail.form.withGlobalError(baseException.failure.message), collectionId = basicDetailsData.collectionId, nftId = basicDetailsData.nftId, None))
}
}
)
Expand Down Expand Up @@ -593,7 +578,6 @@ class NFTController @Inject()(
Future(BadRequest(views.html.nft.transfer(formWithErrors, formWithErrors.data.getOrElse(constants.FormField.NFT_ID.name, ""))))
},
transferData => {
val quantity = 1 // TODO
val nft = masterNFTs.Service.tryGet(transferData.nftId)
val nftOwner = masterNFTOwners.Service.tryGet(nftId = transferData.nftId, ownerId = loginState.username)
val verifyPassword = masterKeys.Service.validateActiveKeyUsernamePasswordAndGet(username = loginState.username, password = transferData.password)
Expand All @@ -602,10 +586,11 @@ class NFTController @Inject()(

def verifyAndTx(verifyPassword: Boolean, balance: MicroNumber, key: Key, nft: NFT, nftOwner: NFTOwner, toAccountExists: Boolean) = {
val errors = Seq(
if (nftOwner.ownerId != loginState.username) Option(constants.Response.NOT_NFT_OWNER) else None,
if (balance == MicroNumber.zero) Option(constants.Response.INSUFFICIENT_BALANCE) else None,
if (!verifyPassword) Option(constants.Response.INVALID_PASSWORD) else None,
if (!nft.isMinted.getOrElse(false)) Option(constants.Response.NFT_NOT_MINTED) else None,
if (quantity > nftOwner.quantity) Option(constants.Response.INSUFFICIENT_NFT_BALANCE) else None,
if (transferData.amount > nftOwner.quantity) Option(constants.Response.INSUFFICIENT_NFT_BALANCE) else None,
if (!toAccountExists) Option(constants.Response.TO_ACCOUNT_ID_DOES_NOT_EXISTS) else None,
if (transferData.toAccountId == loginState.username) Option(constants.Response.CANNOT_SEND_TO_YOURSELF) else None,
).flatten
Expand All @@ -614,7 +599,7 @@ class NFTController @Inject()(
masterTransactionNFTTransferTransactions.Utility.transaction(
nft = nft,
fromId = loginState.username,
quantity = quantity,
quantity = transferData.amount,
fromAddress = key.address,
toAccountId = transferData.toAccountId,
gasPrice = constants.Transaction.DefaultGasPrice,
Expand Down
Loading

0 comments on commit ce87788

Please sign in to comment.