diff --git a/.github/workflows/functions_emulated-tests.yml b/.github/workflows/functions_emulated-tests.yml index 24d0fc5ab4..6240ccd4a2 100644 --- a/.github/workflows/functions_emulated-tests.yml +++ b/.github/workflows/functions_emulated-tests.yml @@ -54,11 +54,11 @@ jobs: firebase emulators:exec " npm run test:ci -- --forceExit --findRelatedTests ./test/auth.spec.ts && npm run test:ci -- --forceExit --findRelatedTests ./test/controls/address.spec.ts && + npm run test:ci -- --forceExit --findRelatedTests ./test/controls/auction/auction.bid.spec.ts && npm run test:ci -- --forceExit --findRelatedTests ./test/controls/collection.spec.ts && npm run test:ci -- --forceExit --findRelatedTests ./test/controls/member.spec.ts && - npm run test:ci -- --forceExit --findRelatedTests ./test/controls/nft-bidding.spec.ts && npm run test:ci -- --forceExit --findRelatedTests ./test/controls/nft.spec.ts && - npm run test:ci -- --forceExit --findRelatedTests ./test/controls/order.spec.ts + npm run test:ci -- --forceExit --findRelatedTests ./test/controls/nft/nft.bidding.extends.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -93,13 +93,13 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test:ci -- --forceExit --findRelatedTests ./test/controls/nft/nft.bidding.finalize.spec.ts && + npm run test:ci -- --forceExit --findRelatedTests ./test/controls/nft/nft.bidding.spec.ts && + npm run test:ci -- --forceExit --findRelatedTests ./test/controls/nft/nft.set.for.sale.spec.ts && + npm run test:ci -- --forceExit --findRelatedTests ./test/controls/order.spec.ts && npm run test:ci -- --forceExit --findRelatedTests ./test/controls/project/project.create.spec.ts && npm run test:ci -- --forceExit --findRelatedTests ./test/controls/project/project.deactivate.spec.ts && - npm run test:ci -- --forceExit --findRelatedTests ./test/controls/proposal.spec.ts && - npm run test:ci -- --forceExit --findRelatedTests ./test/controls/space.spec.ts && - npm run test:ci -- --forceExit --findRelatedTests ./test/controls/stake.reward.spec.ts && - npm run test:ci -- --forceExit --findRelatedTests ./test/controls/stamp.control.spec.ts && - npm run test:ci -- --forceExit --findRelatedTests ./test/controls/token-distribution-auto-trigger.spec.ts + npm run test:ci -- --forceExit --findRelatedTests ./test/controls/proposal.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -134,13 +134,13 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test:ci -- --forceExit --findRelatedTests ./test/controls/space.spec.ts && + npm run test:ci -- --forceExit --findRelatedTests ./test/controls/stake.reward.spec.ts && + npm run test:ci -- --forceExit --findRelatedTests ./test/controls/stamp.control.spec.ts && + npm run test:ci -- --forceExit --findRelatedTests ./test/controls/token-distribution-auto-trigger.spec.ts && npm run test:ci -- --forceExit --findRelatedTests ./test/controls/token-distribution.spec.ts && npm run test:ci -- --forceExit --findRelatedTests ./test/controls/token-trade.buy.spec.ts && - npm run test:ci -- --forceExit --findRelatedTests ./test/controls/token-trade.sell.spec.ts && - npm run test:ci -- --forceExit --findRelatedTests ./test/controls/token-trade.trigger.spec.ts && - npm run test:ci -- --forceExit --findRelatedTests ./test/controls/token.expired.sale.cron.spec.ts && - npm run test:ci -- --forceExit --findRelatedTests ./test/controls/token.order.spec.ts && - npm run test:ci -- --forceExit --findRelatedTests ./test/controls/token/token.airdrop.claim.spec.ts + npm run test:ci -- --forceExit --findRelatedTests ./test/controls/token-trade.sell.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -175,13 +175,13 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test:ci -- --forceExit --findRelatedTests ./test/controls/token-trade.trigger.spec.ts && + npm run test:ci -- --forceExit --findRelatedTests ./test/controls/token.expired.sale.cron.spec.ts && + npm run test:ci -- --forceExit --findRelatedTests ./test/controls/token.order.spec.ts && + npm run test:ci -- --forceExit --findRelatedTests ./test/controls/token/token.airdrop.claim.spec.ts && npm run test:ci -- --forceExit --findRelatedTests ./test/controls/token/token.airdrop.spec.ts && npm run test:ci -- --forceExit --findRelatedTests ./test/controls/token/token.cancel.pub.sale.spec.ts && - npm run test:ci -- --forceExit --findRelatedTests ./test/controls/token/token.create.spec.ts && - npm run test:ci -- --forceExit --findRelatedTests ./test/controls/token/token.order.and.claim.air.spec.ts && - npm run test:ci -- --forceExit --findRelatedTests ./test/controls/token/token.rank.spec.ts && - npm run test:ci -- --forceExit --findRelatedTests ./test/controls/token/token.set.to.sale.spec.ts && - npm run test:ci -- --forceExit --findRelatedTests ./test/controls/token/token.update.spec.ts + npm run test:ci -- --forceExit --findRelatedTests ./test/controls/token/token.create.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -216,13 +216,13 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test:ci -- --forceExit --findRelatedTests ./test/controls/token/token.order.and.claim.air.spec.ts && + npm run test:ci -- --forceExit --findRelatedTests ./test/controls/token/token.rank.spec.ts && + npm run test:ci -- --forceExit --findRelatedTests ./test/controls/token/token.set.to.sale.spec.ts && + npm run test:ci -- --forceExit --findRelatedTests ./test/controls/token/token.update.spec.ts && npm run test:ci -- --forceExit --findRelatedTests ./test/controls/token/token.vote.spec.ts && npm run test:ci -- --forceExit --findRelatedTests ./test/controls/workflow-online.spec.ts && - npm run test:ci -- --forceExit --findRelatedTests ./test/controls/workflow.spec.ts && - npm run test:ci -- --forceExit --findRelatedTests ./test/cron/floor-price.cron.only.spec.ts && - npm run test:ci -- --forceExit --findRelatedTests ./test/cron/nft-stake.cron.spec.ts && - npm run test:ci -- --forceExit --findRelatedTests ./test/cron/proposal.cron.spec.ts && - npm run test:ci -- --forceExit --findRelatedTests ./test/db.roll.spec.ts + npm run test:ci -- --forceExit --findRelatedTests ./test/controls/workflow.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -257,6 +257,10 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test:ci -- --forceExit --findRelatedTests ./test/cron/floor-price.cron.only.spec.ts && + npm run test:ci -- --forceExit --findRelatedTests ./test/cron/nft-stake.cron.spec.ts && + npm run test:ci -- --forceExit --findRelatedTests ./test/cron/proposal.cron.spec.ts && + npm run test:ci -- --forceExit --findRelatedTests ./test/db.roll.spec.ts && npm run test:ci -- --forceExit --findRelatedTests ./test/stake/delete.stake.reward.spec.ts && npm run test:ci -- --forceExit --findRelatedTests ./test/stake/stake.reward.cron.spec.ts && npm run test:ci -- --forceExit --findRelatedTests ./test/storage/resize.img.spec.ts diff --git a/.github/workflows/functions_online-emulated-tests.yml b/.github/workflows/functions_online-emulated-tests.yml index 0a6bd7ecf7..0c0a4e424b 100644 --- a/.github/workflows/functions_online-emulated-tests.yml +++ b/.github/workflows/functions_online-emulated-tests.yml @@ -56,11 +56,11 @@ jobs: firebase emulators:exec " npm run test-online:ci -- --forceExit --findRelatedTests ./test/auth.spec.ts && npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/address.spec.ts && + npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/auction/auction.bid.spec.ts && npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/collection.spec.ts && npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/member.spec.ts && - npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/nft-bidding.spec.ts && npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/nft.spec.ts && - npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/order.spec.ts + npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/nft/nft.bidding.extends.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -95,13 +95,13 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/nft/nft.bidding.finalize.spec.ts && + npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/nft/nft.bidding.spec.ts && + npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/nft/nft.set.for.sale.spec.ts && + npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/order.spec.ts && npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/project/project.create.spec.ts && npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/project/project.deactivate.spec.ts && - npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/proposal.spec.ts && - npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/space.spec.ts && - npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/stake.reward.spec.ts && - npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/stamp.control.spec.ts && - npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/token-distribution-auto-trigger.spec.ts + npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/proposal.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -136,13 +136,13 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/space.spec.ts && + npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/stake.reward.spec.ts && + npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/stamp.control.spec.ts && + npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/token-distribution-auto-trigger.spec.ts && npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/token-distribution.spec.ts && npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/token-trade.buy.spec.ts && - npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/token-trade.sell.spec.ts && - npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/token-trade.trigger.spec.ts && - npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/token.expired.sale.cron.spec.ts && - npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/token.order.spec.ts && - npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/token/token.airdrop.claim.spec.ts + npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/token-trade.sell.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -177,13 +177,13 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/token-trade.trigger.spec.ts && + npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/token.expired.sale.cron.spec.ts && + npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/token.order.spec.ts && + npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/token/token.airdrop.claim.spec.ts && npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/token/token.airdrop.spec.ts && npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/token/token.cancel.pub.sale.spec.ts && - npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/token/token.create.spec.ts && - npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/token/token.order.and.claim.air.spec.ts && - npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/token/token.rank.spec.ts && - npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/token/token.set.to.sale.spec.ts && - npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/token/token.update.spec.ts + npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/token/token.create.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -218,13 +218,13 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/token/token.order.and.claim.air.spec.ts && + npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/token/token.rank.spec.ts && + npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/token/token.set.to.sale.spec.ts && + npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/token/token.update.spec.ts && npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/token/token.vote.spec.ts && npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/workflow-online.spec.ts && - npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/workflow.spec.ts && - npm run test-online:ci -- --forceExit --findRelatedTests ./test/cron/nft-stake.cron.spec.ts && - npm run test-online:ci -- --forceExit --findRelatedTests ./test/cron/proposal.cron.spec.ts && - npm run test-online:ci -- --forceExit --findRelatedTests ./test/db.roll.spec.ts && - npm run test-online:ci -- --forceExit --findRelatedTests ./test/stake/delete.stake.reward.spec.ts + npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/workflow.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -259,6 +259,10 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-online:ci -- --forceExit --findRelatedTests ./test/cron/nft-stake.cron.spec.ts && + npm run test-online:ci -- --forceExit --findRelatedTests ./test/cron/proposal.cron.spec.ts && + npm run test-online:ci -- --forceExit --findRelatedTests ./test/db.roll.spec.ts && + npm run test-online:ci -- --forceExit --findRelatedTests ./test/stake/delete.stake.reward.spec.ts && npm run test-online:ci -- --forceExit --findRelatedTests ./test/stake/stake.reward.cron.spec.ts && npm run test-online:ci -- --forceExit --findRelatedTests ./test/storage/resize.img.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data diff --git a/.github/workflows/functions_tangle-online-unit-tests_emulator.yml b/.github/workflows/functions_tangle-online-unit-tests_emulator.yml index 553c342b96..dc4e3dd70d 100644 --- a/.github/workflows/functions_tangle-online-unit-tests_emulator.yml +++ b/.github/workflows/functions_tangle-online-unit-tests_emulator.yml @@ -55,8 +55,8 @@ jobs: npm run milestone-sync & firebase emulators:exec " npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/address.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/award-tangle/award-tangle_1.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/award-tangle/award-tangle_2.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/auction-tangle/auction.bit.tangle.spec.ts && + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/award-tangle/award-tangle_1.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -91,9 +91,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/award-tangle/award-tangle_2.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/award-tangle/award-tangle_3.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/award-tangle/award-tangle_4.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/award-tangle/award-tangle_5.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/award-tangle/award-tangle_4.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -128,9 +128,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/award-tangle/award-tangle_5.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/award-tangle/award-tangle_6.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/award-tangle/award-tangle_7.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_1.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/award-tangle/award-tangle_7.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -165,9 +165,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_1.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_10.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_2.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_3.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_2.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -202,9 +202,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_3.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_4.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_5.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_6.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_5.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -239,9 +239,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_6.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_7.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_8.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_9.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_8.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -276,9 +276,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_9.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_1.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_10.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_11_a.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_10.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -313,9 +313,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_11_a.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_11_b.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_11_c.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_11_d.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_11_c.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -350,9 +350,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_11_d.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_12.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_13.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_2.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_13.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -387,9 +387,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_2.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_3.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_4.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_5.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_4.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -424,9 +424,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_5.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_6.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_7.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_8.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_7.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -461,9 +461,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_8.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_9.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_1.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_10.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_1.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -498,9 +498,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_10.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_11.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_12.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_2.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_12.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -535,9 +535,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_2.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_4.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_5.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_6.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_5.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -572,9 +572,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_6.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_7.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_8.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_9.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_8.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -609,9 +609,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_9.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_1_b.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_1.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_2.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_1.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -646,9 +646,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_2.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_3_b.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_3.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_4.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_3.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -683,9 +683,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_4.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_5_b.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_5.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_6.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_5.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -720,9 +720,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_6.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_7.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_1_b.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_1.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_1_b.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -757,9 +757,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_1.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_10.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_2.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_3.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_2.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -794,9 +794,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_3.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_4.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_5.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_6.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_5.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -831,9 +831,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_6.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_7.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_8.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-airdrop/minted-token-airdrop_1_a.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_8.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -868,9 +868,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-airdrop/minted-token-airdrop_1_a.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-airdrop/minted-token-airdrop_1_b.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-airdrop/minted-token-airdrop_1_c.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-airdrop/minted-token-airdrop_2.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-airdrop/minted-token-airdrop_1_c.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -905,9 +905,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-airdrop/minted-token-airdrop_2.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-airdrop/minted-token-airdrop_4.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-airdrop/minted-token-airdrop_5.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-claim/token.claim.minted_1.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-airdrop/minted-token-airdrop_5.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -942,9 +942,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-claim/token.claim.minted_1.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-claim/token.claim.minted_2.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-claim/token.claim.minted_3.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-claim/token.claim.minted_4.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-claim/token.claim.minted_3.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -979,9 +979,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-claim/token.claim.minted_4.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-claim/token.claim.minted_5.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-claim/token.claim.minted_6.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-claim/token.claim.minted_7.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-claim/token.claim.minted_6.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1016,9 +1016,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-claim/token.claim.minted_7.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_1.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_10.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_11.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_10.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1053,9 +1053,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_11.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_12_b.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_12.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_13.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_12.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1090,9 +1090,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_13.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_14_b.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_14.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_16.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_14.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1127,9 +1127,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_16.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_17.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_18.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_19.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_18.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1164,9 +1164,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_19.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_2.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_3.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_4.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_3.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1201,9 +1201,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_4.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_5.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_6.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_7.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_6.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1238,9 +1238,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_7.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_8.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_9.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-bid/nft-bid.otr_1.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_9.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1275,9 +1275,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-bid/nft-bid.otr_1.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-bid/nft-bid.otr_2.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-bid/nft-bid.otr_3.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-bid/nft-bid.otr_4.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-bid/nft-bid.otr_3.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1312,9 +1312,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-bid/nft-bid.otr_4.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-set-for-sale/nft-set-for-sale_1.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-set-for-sale/nft-set-for-sale_2.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-set-for-sale/nft-set-for-sale_3.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-set-for-sale/nft-set-for-sale_2.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1349,9 +1349,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-set-for-sale/nft-set-for-sale_3.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-staking/nft-staking_1.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-staking/nft-staking_2_b.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-staking/nft-staking_2.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-staking/nft-staking_2_b.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1386,9 +1386,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-staking/nft-staking_2.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-staking/nft-staking_3.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-staking/nft-staking_4.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-staking/nft-staking_5.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-staking/nft-staking_4.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1423,9 +1423,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-staking/nft-staking_5.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-staking/nft-staking_6.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-staking/nft-staking_7.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-staking/nft-staking_8.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-staking/nft-staking_7.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1460,9 +1460,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-staking/nft-staking_8.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/proposal-tangle/proposal.approval.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/proposal-tangle/proposal.create.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/proposal-tangle/proposal.simple.vote.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/proposal-tangle/proposal.create.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1497,9 +1497,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/proposal-tangle/proposal.simple.vote.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/proposal-tangle/proposal.stake.voting.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/proposal-tangle/proposal.token.voting.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/space-tangle/space.accept.member.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/proposal-tangle/proposal.token.voting.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1534,9 +1534,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/space-tangle/space.accept.member.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/space-tangle/space.block.member.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/space-tangle/space.create.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/space-tangle/space.decline.member.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/space-tangle/space.create.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1571,9 +1571,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/space-tangle/space.decline.member.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/space-tangle/space.edit.guardian.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/space-tangle/space.join.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/space-tangle/space.leave.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/space-tangle/space.join.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1608,9 +1608,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/space-tangle/space.leave.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/staking/staking_1.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/staking/staking_2.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/staking/staking_3.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/staking/staking_2.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1645,9 +1645,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/staking/staking_3.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/staking/staking_4.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/staking/staking_5.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/stamp-tangle/stamp-tangle_1.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/staking/staking_5.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1682,9 +1682,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/stamp-tangle/stamp-tangle_1.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/stamp-tangle/stamp-tangle_2.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/stamp-tangle/stamp-tangle_3.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/stamp-tangle/stamp-tangle_4.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/stamp-tangle/stamp-tangle_3.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1719,9 +1719,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/stamp-tangle/stamp-tangle_4.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/stamp-tangle/stamp-tangle_5.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/stamp-tangle/stamp-tangle_6.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/tangleRequest/simple.token.trade.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/stamp-tangle/stamp-tangle_6.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1756,9 +1756,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/tangleRequest/simple.token.trade.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/tangleRequest/tangle-request.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/token-import/token.import_1.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/token-import/token.import_2.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/token-import/token.import_1.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1793,9 +1793,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/token-import/token.import_2.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/token.based.voting/stake.voting.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/token.based.voting/token.based.voting_1.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/token.based.voting/token.based.voting_2.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/token.based.voting/token.based.voting_1.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1830,9 +1830,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/token.based.voting/token.based.voting_2.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/token.based.voting/token.based.voting_3.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/token.based.voting/token.based.voting_4.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/token.based.voting/token.based.voting_5.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/token.based.voting/token.based.voting_4.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1867,9 +1867,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/token.based.voting/token.based.voting_5.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/token.mint/token.mint_1.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/token.mint/token.mint_2.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/token.mint/token.mint_3.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/token.mint/token.mint_2.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1904,9 +1904,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/token.mint/token.mint_3.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/token.mint/token.mint_4.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/trade-base-token-order.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/tran.match.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/trade-base-token-order.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1941,9 +1941,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/tran.match.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_1.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_10.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_11.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_10.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1978,9 +1978,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_11.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_12.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_13.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_2.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_13.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -2015,9 +2015,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_2.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_3.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_4.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_5.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_4.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -2052,9 +2052,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_5.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_6.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_7.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_8.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_7.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -2089,9 +2089,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_8.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_9.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/web3/web3_1.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/web3/web3_2.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/web3/web3_1.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -2126,9 +2126,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/web3/web3_2.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/web3/web3_3.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_1_a.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_1_b.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_1_a.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -2163,9 +2163,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_1_b.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_1_c.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_10_1.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_10_2.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_10_1.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -2200,9 +2200,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_10_2.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_10_3.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_11.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_12_a.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_11.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -2237,9 +2237,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_12_a.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_12_b.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_13.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_14.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_13.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -2274,9 +2274,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_14.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_2.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_4_b.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_4.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_4_b.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -2311,9 +2311,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_4.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_5.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_6.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_7.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_6.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -2348,9 +2348,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_7.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_8.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_9.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/workflow-online.spec.ts + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_9.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -2385,6 +2385,7 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/workflow-online.spec.ts && npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/workflow.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data diff --git a/.github/workflows/functions_tangle-unit-tests.yml b/.github/workflows/functions_tangle-unit-tests.yml index 2a81abf409..4cb79c1115 100644 --- a/.github/workflows/functions_tangle-unit-tests.yml +++ b/.github/workflows/functions_tangle-unit-tests.yml @@ -53,8 +53,8 @@ jobs: npm run milestone-sync & firebase emulators:exec " npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/address.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/award-tangle/award-tangle_1.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/award-tangle/award-tangle_2.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/auction-tangle/auction.bit.tangle.spec.ts && + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/award-tangle/award-tangle_1.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -89,9 +89,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/award-tangle/award-tangle_2.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/award-tangle/award-tangle_3.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/award-tangle/award-tangle_4.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/award-tangle/award-tangle_5.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/award-tangle/award-tangle_4.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -126,9 +126,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/award-tangle/award-tangle_5.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/award-tangle/award-tangle_6.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/award-tangle/award-tangle_7.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_1.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/award-tangle/award-tangle_7.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -163,9 +163,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_1.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_10.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_2.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_3.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_2.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -200,9 +200,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_3.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_4.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_5.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_6.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_5.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -237,9 +237,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_6.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_7.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_8.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_9.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_8.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -274,9 +274,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_9.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_1.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_10.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_11_a.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_10.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -311,9 +311,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_11_a.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_11_b.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_11_c.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_11_d.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_11_c.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -348,9 +348,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_11_d.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_12.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_13.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_2.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_13.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -385,9 +385,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_2.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_3.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_4.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_5.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_4.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -422,9 +422,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_5.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_6.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_7.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_8.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_7.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -459,9 +459,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_8.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_9.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_1.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_10.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_1.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -496,9 +496,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_10.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_11.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_12.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_2.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_12.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -533,9 +533,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_2.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_4.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_5.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_6.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_5.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -570,9 +570,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_6.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_7.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_8.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_9.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_8.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -607,9 +607,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_9.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_1_b.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_1.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_2.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_1.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -644,9 +644,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_2.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_3_b.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_3.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_4.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_3.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -681,9 +681,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_4.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_5_b.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_5.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_6.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_5.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -718,9 +718,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_6.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_7.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_1_b.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_1.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_1_b.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -755,9 +755,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_1.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_10.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_2.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_3.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_2.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -792,9 +792,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_3.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_4.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_5.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_6.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_5.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -829,9 +829,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_6.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_7.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_8.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-airdrop/minted-token-airdrop_1_a.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-nft-trading/minted-nft-trading_8.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -866,9 +866,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-airdrop/minted-token-airdrop_1_a.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-airdrop/minted-token-airdrop_1_b.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-airdrop/minted-token-airdrop_1_c.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-airdrop/minted-token-airdrop_2.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-airdrop/minted-token-airdrop_1_c.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -903,9 +903,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-airdrop/minted-token-airdrop_2.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-airdrop/minted-token-airdrop_4.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-airdrop/minted-token-airdrop_5.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-claim/token.claim.minted_1.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-airdrop/minted-token-airdrop_5.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -940,9 +940,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-claim/token.claim.minted_1.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-claim/token.claim.minted_2.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-claim/token.claim.minted_3.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-claim/token.claim.minted_4.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-claim/token.claim.minted_3.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -977,9 +977,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-claim/token.claim.minted_4.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-claim/token.claim.minted_5.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-claim/token.claim.minted_6.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-claim/token.claim.minted_7.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-claim/token.claim.minted_6.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1014,9 +1014,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-claim/token.claim.minted_7.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_1.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_10.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_11.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_10.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1051,9 +1051,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_11.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_12_b.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_12.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_13.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_12.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1088,9 +1088,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_13.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_14_b.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_14.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_16.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_14.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1125,9 +1125,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_16.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_17.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_18.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_19.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_18.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1162,9 +1162,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_19.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_2.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_3.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_4.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_3.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1199,9 +1199,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_4.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_5.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_6.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_7.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_6.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1236,9 +1236,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_7.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_8.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_9.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-bid/nft-bid.otr_1.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_9.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1273,9 +1273,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-bid/nft-bid.otr_1.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-bid/nft-bid.otr_2.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-bid/nft-bid.otr_3.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-bid/nft-bid.otr_4.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-bid/nft-bid.otr_3.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1310,9 +1310,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-bid/nft-bid.otr_4.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-set-for-sale/nft-set-for-sale_1.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-set-for-sale/nft-set-for-sale_2.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-set-for-sale/nft-set-for-sale_3.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-set-for-sale/nft-set-for-sale_2.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1347,9 +1347,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-set-for-sale/nft-set-for-sale_3.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-staking/nft-staking_1.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-staking/nft-staking_2_b.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-staking/nft-staking_2.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-staking/nft-staking_2_b.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1384,9 +1384,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-staking/nft-staking_2.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-staking/nft-staking_3.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-staking/nft-staking_4.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-staking/nft-staking_5.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-staking/nft-staking_4.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1421,9 +1421,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-staking/nft-staking_5.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-staking/nft-staking_6.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-staking/nft-staking_7.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-staking/nft-staking_8.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-staking/nft-staking_7.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1458,9 +1458,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-staking/nft-staking_8.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/proposal-tangle/proposal.approval.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/proposal-tangle/proposal.create.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/proposal-tangle/proposal.simple.vote.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/proposal-tangle/proposal.create.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1495,9 +1495,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/proposal-tangle/proposal.simple.vote.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/proposal-tangle/proposal.stake.voting.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/proposal-tangle/proposal.token.voting.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/space-tangle/space.accept.member.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/proposal-tangle/proposal.token.voting.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1532,9 +1532,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/space-tangle/space.accept.member.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/space-tangle/space.block.member.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/space-tangle/space.create.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/space-tangle/space.decline.member.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/space-tangle/space.create.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1569,9 +1569,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/space-tangle/space.decline.member.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/space-tangle/space.edit.guardian.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/space-tangle/space.join.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/space-tangle/space.leave.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/space-tangle/space.join.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1606,9 +1606,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/space-tangle/space.leave.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/staking/staking_1.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/staking/staking_2.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/staking/staking_3.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/staking/staking_2.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1643,9 +1643,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/staking/staking_3.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/staking/staking_4.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/staking/staking_5.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/stamp-tangle/stamp-tangle_1.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/staking/staking_5.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1680,9 +1680,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/stamp-tangle/stamp-tangle_1.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/stamp-tangle/stamp-tangle_2.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/stamp-tangle/stamp-tangle_3.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/stamp-tangle/stamp-tangle_4.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/stamp-tangle/stamp-tangle_3.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1717,9 +1717,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/stamp-tangle/stamp-tangle_4.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/stamp-tangle/stamp-tangle_5.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/stamp-tangle/stamp-tangle_6.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/tangleRequest/simple.token.trade.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/stamp-tangle/stamp-tangle_6.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1754,9 +1754,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/tangleRequest/simple.token.trade.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/tangleRequest/tangle-request.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/token-import/token.import_1.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/token-import/token.import_2.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/token-import/token.import_1.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1791,9 +1791,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/token-import/token.import_2.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/token.based.voting/stake.voting.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/token.based.voting/token.based.voting_1.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/token.based.voting/token.based.voting_2.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/token.based.voting/token.based.voting_1.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1828,9 +1828,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/token.based.voting/token.based.voting_2.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/token.based.voting/token.based.voting_3.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/token.based.voting/token.based.voting_4.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/token.based.voting/token.based.voting_5.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/token.based.voting/token.based.voting_4.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1865,9 +1865,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/token.based.voting/token.based.voting_5.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/token.mint/token.mint_1.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/token.mint/token.mint_2.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/token.mint/token.mint_3.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/token.mint/token.mint_2.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1902,9 +1902,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/token.mint/token.mint_3.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/token.mint/token.mint_4.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/trade-base-token-order.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/tran.match.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/trade-base-token-order.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1939,9 +1939,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/tran.match.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_1.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_10.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_11.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_10.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -1976,9 +1976,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_11.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_12.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_13.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_2.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_13.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -2013,9 +2013,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_2.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_3.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_4.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_5.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_4.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -2050,9 +2050,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_5.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_6.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_7.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_8.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_7.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -2087,9 +2087,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_8.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/transaction-trigger/transaction-trigger_9.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/web3/web3_1.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/web3/web3_2.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/web3/web3_1.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -2124,9 +2124,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/web3/web3_2.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/web3/web3_3.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_1_a.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_1_b.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_1_a.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -2161,9 +2161,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_1_b.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_1_c.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_10_1.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_10_2.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_10_1.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -2198,9 +2198,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_10_2.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_10_3.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_11.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_12_a.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_11.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -2235,9 +2235,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_12_a.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_12_b.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_13.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_14.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_13.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -2272,9 +2272,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_14.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_2.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_4_b.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_4.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_4_b.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -2309,9 +2309,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_4.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_5.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_6.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_7.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_6.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -2346,9 +2346,9 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_7.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_8.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_9.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/workflow-online.spec.ts + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_9.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data uses: actions/upload-artifact@v3 @@ -2383,6 +2383,7 @@ jobs: export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" npm run milestone-sync & firebase emulators:exec " + npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/workflow-online.spec.ts && npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/workflow.spec.ts " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - name: Archive firestore data diff --git a/packages/functions/src/controls/auction/AuctionBidRequestSchema.ts b/packages/functions/src/controls/auction/AuctionBidRequestSchema.ts new file mode 100644 index 0000000000..2d311025bd --- /dev/null +++ b/packages/functions/src/controls/auction/AuctionBidRequestSchema.ts @@ -0,0 +1,10 @@ +import { AuctionBidRequest } from '@build-5/interfaces'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; + +export const auctionBidSchema = toJoiObject({ + auction: CommonJoi.uid().description('Build5 id of the auction.'), +}) + .description('Request object to create a bid order.') + .meta({ + className: 'AuctionBidRequest', + }); diff --git a/packages/functions/src/controls/auction/AuctionCreateRequestSchema.ts b/packages/functions/src/controls/auction/AuctionCreateRequestSchema.ts new file mode 100644 index 0000000000..ab068a2e09 --- /dev/null +++ b/packages/functions/src/controls/auction/AuctionCreateRequestSchema.ts @@ -0,0 +1,74 @@ +import { + AuctionCreateRequest, + EXTEND_AUCTION_WITHIN, + MAX_IOTA_AMOUNT, + MIN_IOTA_AMOUNT, + TRANSACTION_AUTO_EXPIRY_MS, + TRANSACTION_MAX_EXPIRY_MS, +} from '@build-5/interfaces'; +import dayjs from 'dayjs'; +import Joi from 'joi'; +import { toJoiObject } from '../../services/joi/common'; +import { AVAILABLE_NETWORKS } from '../common'; + +const minAvailableFrom = 10; +const minBids = 1; +const maxBids = 10; + +export const auctionCreateSchema = { + auctionFrom: Joi.date() + .greater(dayjs().subtract(minAvailableFrom, 'minutes').toDate()) + .required() + .description( + `Starting date of the auction. Can not be sooner then ${minAvailableFrom} minutes.`, + ), + auctionFloorPrice: Joi.number() + .min(MIN_IOTA_AMOUNT) + .max(MAX_IOTA_AMOUNT) + .required() + .description( + `Floor price of the auction. Minimum ${MIN_IOTA_AMOUNT}, maximum ${MAX_IOTA_AMOUNT}`, + ), + auctionLength: Joi.number() + .min(TRANSACTION_AUTO_EXPIRY_MS) + .max(TRANSACTION_MAX_EXPIRY_MS) + .required() + .description( + `Millisecond value of the auction length. Minimum ${TRANSACTION_AUTO_EXPIRY_MS}, maximum ${TRANSACTION_MAX_EXPIRY_MS}`, + ), + extendedAuctionLength: Joi.number() + .min(TRANSACTION_AUTO_EXPIRY_MS) + .max(TRANSACTION_MAX_EXPIRY_MS) + .greater(Joi.ref('auctionLength')) + .description( + 'If set, auction will automatically extended by this length if a bid comes in within {@link extendAuctionWithin} before the end of the auction.', + ), + extendAuctionWithin: Joi.number() + .min(TRANSACTION_AUTO_EXPIRY_MS) + .max(TRANSACTION_MAX_EXPIRY_MS) + .description( + 'Auction will be extended if a bid happens this many milliseconds before auction ends. ' + + `Default value is ${EXTEND_AUCTION_WITHIN} minutes`, + ), + maxBids: Joi.number() + .integer() + .min(minBids) + .max(maxBids) + .required() + .description( + `Sepcifies the maximum number of active bids. Minimum ${minBids}, maximum ${maxBids}`, + ), + network: Joi.string() + .valid(...AVAILABLE_NETWORKS) + .description('Network on wich this auction accepts bids.') + .required(), + topUpBased: Joi.boolean().description( + 'If set to true, consequent bids from the same user will be threated as topups', + ), +}; + +export const acutionCreateSchemaObject = toJoiObject(auctionCreateSchema) + .description('Request object to create an auction.') + .meta({ + className: 'AuctionCreateRequest', + }); diff --git a/packages/functions/src/controls/auction/auction.control.ts b/packages/functions/src/controls/auction/auction.control.ts new file mode 100644 index 0000000000..ef523e6992 --- /dev/null +++ b/packages/functions/src/controls/auction/auction.control.ts @@ -0,0 +1,25 @@ +import { build5Db } from '@build-5/database'; +import { AuctionBidRequest, COL, Transaction, WenError } from '@build-5/interfaces'; +import { createBidOrder } from '../../services/payment/tangle-service/auction/auction.bid.order'; +import { invalidArgument } from '../../utils/error.utils'; +import { Context } from '../common'; + +export const auctionBidControl = async ({ + ip, + owner, + params, + project, +}: Context): Promise => { + const memberDocRef = build5Db().doc(`${COL.MEMBER}/${owner}`); + const member = await memberDocRef.get(); + if (!member) { + throw invalidArgument(WenError.member_does_not_exists); + } + + const bidTransaction = await createBidOrder(project, owner, params.auction, ip); + + const transactionDocRef = build5Db().doc(`${COL.TRANSACTION}/${bidTransaction.uid}`); + await transactionDocRef.create(bidTransaction); + + return (await transactionDocRef.get())!; +}; diff --git a/packages/functions/src/controls/auction/auction.create.control.ts b/packages/functions/src/controls/auction/auction.create.control.ts new file mode 100644 index 0000000000..20c4a21597 --- /dev/null +++ b/packages/functions/src/controls/auction/auction.create.control.ts @@ -0,0 +1,23 @@ +import { build5Db } from '@build-5/database'; +import { Auction, AuctionCreateRequest, COL, Member, WenError } from '@build-5/interfaces'; +import { getAuctionData } from '../../services/payment/tangle-service/auction/auction.create.service'; +import { invalidArgument } from '../../utils/error.utils'; +import { Context } from '../common'; + +export const auctionCreateControl = async ({ + owner, + project, + params, +}: Context) => { + const memberDocRef = build5Db().doc(`${COL.MEMBER}/${owner}`); + const member = await memberDocRef.get(); + if (!member) { + throw invalidArgument(WenError.member_does_not_exists); + } + + const auction = getAuctionData(project, owner, params); + const auctionDocRef = build5Db().doc(`${COL.AUCTION}/${auction.uid}`); + await auctionDocRef.create(auction); + + return await auctionDocRef.get(); +}; diff --git a/packages/functions/src/controls/nft/nft.bid.control.ts b/packages/functions/src/controls/nft/nft.bid.control.ts index 2eb67afd87..63484ab7ac 100644 --- a/packages/functions/src/controls/nft/nft.bid.control.ts +++ b/packages/functions/src/controls/nft/nft.bid.control.ts @@ -1,6 +1,6 @@ import { build5Db } from '@build-5/database'; -import { COL, NftBidRequest, Transaction, WenError } from '@build-5/interfaces'; -import { createNftBidOrder } from '../../services/payment/tangle-service/nft/nft-bid.service'; +import { COL, Nft, NftBidRequest, Transaction, WenError } from '@build-5/interfaces'; +import { createBidOrder } from '../../services/payment/tangle-service/auction/auction.bid.order'; import { invalidArgument } from '../../utils/error.utils'; import { Context } from '../common'; @@ -16,7 +16,10 @@ export const nftBidControl = async ({ throw invalidArgument(WenError.member_does_not_exists); } - const bidTransaction = await createNftBidOrder(project, params.nft, owner, ip || ''); + const nftDocRef = build5Db().doc(`${COL.NFT}/${params.nft}`); + const nft = await nftDocRef.get(); + + const bidTransaction = await createBidOrder(project, owner, nft.auction || '', ip); const transactionDocRef = build5Db().doc(`${COL.TRANSACTION}/${bidTransaction.uid}`); await transactionDocRef.create(bidTransaction); diff --git a/packages/functions/src/controls/nft/nft.set.for.sale.ts b/packages/functions/src/controls/nft/nft.set.for.sale.ts index 2732bd662c..8a6f43114c 100644 --- a/packages/functions/src/controls/nft/nft.set.for.sale.ts +++ b/packages/functions/src/controls/nft/nft.set.for.sale.ts @@ -7,6 +7,7 @@ import { Context } from '../common'; export const setForSaleNftControl = async ({ owner, params, + project, }: Context): Promise => { const memberDocRef = build5Db().doc(`${COL.MEMBER}/${owner}`); const member = await memberDocRef.get(); @@ -14,9 +15,19 @@ export const setForSaleNftControl = async ({ throw invalidArgument(WenError.member_does_not_exists); } - const updateData = await getNftSetForSaleParams(params, member); + const { nft, auction } = await getNftSetForSaleParams(member, project, params); + + const batch = build5Db().batch(); + const nftDocRef = build5Db().doc(`${COL.NFT}/${params.nft}`); - await nftDocRef.update(updateData); + batch.update(nftDocRef, nft); + + if (auction) { + const auctionDocRef = build5Db().doc(`${COL.AUCTION}/${auction.uid}`); + batch.create(auctionDocRef, auction); + } + + await batch.commit(); return (await nftDocRef.get())!; }; diff --git a/packages/functions/src/cron/auction.cron.ts b/packages/functions/src/cron/auction.cron.ts new file mode 100644 index 0000000000..7a7f80528a --- /dev/null +++ b/packages/functions/src/cron/auction.cron.ts @@ -0,0 +1,27 @@ +import { build5Db } from '@build-5/database'; +import { Auction, AuctionType, COL } from '@build-5/interfaces'; +import dayjs from 'dayjs'; +import { AuctionFinalizeService } from '../services/payment/auction/auction.finalize.service'; +import { TransactionService } from '../services/payment/transaction-service'; + +export const finalizeAuctions = async () => { + const snap = await build5Db() + .collection(COL.AUCTION) + .where('auctionTo', '<=', dayjs().toDate()) + .where('active', '==', true) + .get(); + const promises = snap.map(async (a) => { + if (a.type === AuctionType.NFT) { + await finalizeNftAuction(a.uid); + } + }); + await Promise.all(promises); +}; + +const finalizeNftAuction = (auction: string) => + build5Db().runTransaction(async (transaction) => { + const tranService = new TransactionService(transaction); + const service = new AuctionFinalizeService(tranService); + await service.markAsFinalized(auction); + tranService.submit(); + }); diff --git a/packages/functions/src/cron/nft.cron.ts b/packages/functions/src/cron/nft.cron.ts index ae4b99edd6..5b105c05ff 100644 --- a/packages/functions/src/cron/nft.cron.ts +++ b/packages/functions/src/cron/nft.cron.ts @@ -1,28 +1,6 @@ import { build5Db } from '@build-5/database'; import { COL, Nft } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { NftBidService } from '../services/payment/nft/nft-bid.service'; -import { TransactionService } from '../services/payment/transaction-service'; - -const finalizeNftAuction = (nftId: string) => - build5Db().runTransaction(async (transaction) => { - const nftDocRef = build5Db().collection(COL.NFT).doc(nftId); - const nft = (await transaction.get(nftDocRef))!; - - const tranService = new TransactionService(transaction); - const service = new NftBidService(tranService); - await service.markNftAsFinalized(nft); - tranService.submit(); - }); - -export const finalizeAllNftAuctions = async () => { - const snap = await build5Db() - .collection(COL.NFT) - .where('auctionTo', '<=', dayjs().toDate()) - .get(); - const promises = snap.map((d) => finalizeNftAuction(d.uid)); - await Promise.all(promises); -}; export const hidePlaceholderAfterSoldOutCron = async () => { const snap = await build5Db() diff --git a/packages/functions/src/runtime/common.ts b/packages/functions/src/runtime/common.ts index cc5e0cfece..e3743065fe 100644 --- a/packages/functions/src/runtime/common.ts +++ b/packages/functions/src/runtime/common.ts @@ -23,7 +23,7 @@ export enum WEN_SCHEDULED { retryWallet = 'retrywallet', processExpiredAwards = 'processexpiredawards', voidExpiredOrders = 'voidexpiredorders', - finalizeAuctionNft = 'finalizeauctionnft', + finalizeAuctions = 'finalizeauctions', hidePlaceholderAfterSoldOut = 'hideplaceholderaftersoldout', tokenCoolDownOver = 'tokencooldownover', cancelExpiredSale = 'cancelexpiredsale', diff --git a/packages/functions/src/runtime/cron/index.ts b/packages/functions/src/runtime/cron/index.ts index 499d554392..a6f2bd6247 100644 --- a/packages/functions/src/runtime/cron/index.ts +++ b/packages/functions/src/runtime/cron/index.ts @@ -1,8 +1,9 @@ +import { finalizeAuctions } from '../../cron/auction.cron'; import { processExpiredAwards } from '../../cron/award.cron'; import { getLatestBitfinexPricesCron } from '../../cron/bitfinex.cron'; import { updateFloorPriceOnCollections } from '../../cron/collection.floor.price.cron'; import { uploadMediaToWeb3 } from '../../cron/media.cron'; -import { finalizeAllNftAuctions, hidePlaceholderAfterSoldOutCron } from '../../cron/nft.cron'; +import { hidePlaceholderAfterSoldOutCron } from '../../cron/nft.cron'; import { voidExpiredOrdersCron } from '../../cron/orders.cron'; import { markExpiredProposalCompleted } from '../../cron/proposal.cron'; import { removeExpiredStakesFromSpace } from '../../cron/stake.cron'; @@ -29,9 +30,9 @@ exports[WEN_SCHEDULED.voidExpiredOrders] = onSchedule({ handler: voidExpiredOrdersCron, }); -exports[WEN_SCHEDULED.finalizeAuctionNft] = onSchedule({ +exports[WEN_SCHEDULED.finalizeAuctions] = onSchedule({ schedule: 'every 1 minutes', - handler: finalizeAllNftAuctions, + handler: finalizeAuctions, }); exports[WEN_SCHEDULED.hidePlaceholderAfterSoldOut] = onSchedule({ diff --git a/packages/functions/src/runtime/firebase/auction/index.ts b/packages/functions/src/runtime/firebase/auction/index.ts new file mode 100644 index 0000000000..22975354e3 --- /dev/null +++ b/packages/functions/src/runtime/firebase/auction/index.ts @@ -0,0 +1,6 @@ +import { WEN_FUNC } from '@build-5/interfaces'; +import { https } from '../../..'; + +export const auctionCreate = https[WEN_FUNC.createauction]; + +export const bidAuction = https[WEN_FUNC.bidAuction]; diff --git a/packages/functions/src/runtime/https/index.ts b/packages/functions/src/runtime/https/index.ts index 275f880db1..083322286a 100644 --- a/packages/functions/src/runtime/https/index.ts +++ b/packages/functions/src/runtime/https/index.ts @@ -2,6 +2,10 @@ import { NftCreateRequest, ProposalType, WEN_FUNC } from '@build-5/interfaces'; import Joi from 'joi'; import { validateAddressSchemaObject } from '../../controls/address/AddressValidationRequestSchema'; import { validateAddressControl } from '../../controls/address/address.control'; +import { auctionBidSchema } from '../../controls/auction/AuctionBidRequestSchema'; +import { acutionCreateSchemaObject } from '../../controls/auction/AuctionCreateRequestSchema'; +import { auctionBidControl } from '../../controls/auction/auction.control'; +import { auctionCreateControl } from '../../controls/auction/auction.create.control'; import { customTokenSchema } from '../../controls/auth/CutomTokenRequestSchema'; import { generateCustomTokenControl } from '../../controls/auth/auth.control'; import { approveAwardParticipantSchemaObject } from '../../controls/award/AwardApproveParticipantRequestSchema'; @@ -522,3 +526,15 @@ exports[WEN_FUNC.deactivateProject] = onRequest({ schema: toJoiObject({}), handler: deactivateProjectControl, }); + +exports[WEN_FUNC.bidAuction] = onRequest({ + name: WEN_FUNC.bidAuction, + schema: auctionBidSchema, + handler: auctionBidControl, +}); + +exports[WEN_FUNC.createauction] = onRequest({ + name: WEN_FUNC.createauction, + schema: acutionCreateSchemaObject, + handler: auctionCreateControl, +}); diff --git a/packages/functions/src/services/notification/notification.ts b/packages/functions/src/services/notification/notification.ts index 345f550c6c..a02b92236e 100644 --- a/packages/functions/src/services/notification/notification.ts +++ b/packages/functions/src/services/notification/notification.ts @@ -1,62 +1,49 @@ -import { Member, Nft, Notification, NotificationType, Transaction } from '@build-5/interfaces'; +import { Member, Notification, NotificationType } from '@build-5/interfaces'; import { serverTime } from '../../utils/dateTime.utils'; import { getRandomEthAddress } from '../../utils/wallet.utils'; export class NotificationService { - public static prepareBid(member: Member, nft: Nft, tran: Transaction): Notification { + public static prepareBid(member: Member, amount: number, auction: string): Notification { return { uid: getRandomEthAddress(), type: NotificationType.NEW_BID, - member: nft.owner, + member: member.uid, params: { - amount: tran.payload.amount, + amount: amount, member: { name: member.name || member.uid, }, - nft: { - uid: nft.uid, - name: nft.name || nft.uid, - }, + auction, }, createdOn: serverTime(), }; } - public static prepareWinBid(member: Member, nft: Nft, tran: Transaction): Notification { + public static prepareWinBid(member: Member, amount: number, auction: string): Notification { return { uid: getRandomEthAddress(), type: NotificationType.WIN_BID, member: member.uid, params: { - amount: tran.payload.amount, + amount: amount, member: { name: member.name || member.uid, }, - nft: { - uid: nft.uid, - name: nft.name || nft.uid, - }, + auction, }, createdOn: serverTime(), }; } - public static prepareLostBid(member: Member, nft: Nft, tran: Transaction): Notification { - return { + public static prepareLostBid(member: Member, amount: number, auction: string): Notification { + const notification = { uid: getRandomEthAddress(), type: NotificationType.LOST_BID, member: member.uid, - params: { - amount: tran.payload.amount, - member: { - name: member.name || member.uid, - }, - nft: { - uid: nft.uid, - name: nft.name || nft.uid, - }, - }, + params: { amount, member: { name: member.name || member.uid }, auction }, createdOn: serverTime(), }; + + return notification; } } diff --git a/packages/functions/src/services/payment/auction/auction-bid.service.ts b/packages/functions/src/services/payment/auction/auction-bid.service.ts new file mode 100644 index 0000000000..97b5814bdd --- /dev/null +++ b/packages/functions/src/services/payment/auction/auction-bid.service.ts @@ -0,0 +1,189 @@ +import { build5Db } from '@build-5/database'; +import { + Auction, + AuctionBid, + AuctionType, + COL, + Member, + Transaction, + TransactionPayloadType, + TransactionType, +} from '@build-5/interfaces'; +import dayjs from 'dayjs'; +import { head, last, set } from 'lodash'; +import { NotificationService } from '../../notification/notification'; +import { HandlerParams } from '../base'; +import { TransactionService } from '../transaction-service'; + +export class AuctionBidService { + constructor(readonly transactionService: TransactionService) {} + + public handleRequest = async ({ + order, + match, + tran, + tranEntry, + build5Tran, + owner, + }: HandlerParams) => { + const auctionDocRef = build5Db().doc(`${COL.AUCTION}/${order.payload.auction!}`); + const auction = await this.transactionService.get(auctionDocRef); + + if (!auction.active) { + await this.transactionService.processAsInvalid(tran, order, tranEntry, build5Tran); + return; + } + + this.transactionService.markAsReconciled(order, match.msgId); + const payment = await this.transactionService.createPayment(order, match); + await this.addNewBid(owner, auction, order, payment); + }; + + private addNewBid = async ( + owner: string, + auction: Auction, + order: Transaction, + payment: Transaction, + ): Promise => { + if (paidAmountIsBelowFloor(payment, auction) || newPaymentTooLow(payment, auction)) { + await this.creditAsInvalidPayment(payment); + return; + } + + const { bids, invalidBid } = placeBid(auction, order.uid, owner, payment.payload.amount!); + + const auctionUpdateData = this.getAuctionUpdateData(auction, bids); + + if (invalidBid) { + await this.creditInvalidPayments(auction, invalidBid); + } + + if (auctionUpdateData.auctionHighestBid !== auction.auctionHighestBid) { + await this.onAuctionHighestBidChange(order, auctionUpdateData); + } + + if (auction.type === AuctionType.NFT) { + this.updateNft(auctionUpdateData); + } + }; + + private creditInvalidPayments = async (auction: Auction, invalidBid: AuctionBid) => { + const payments = await build5Db() + .collection(COL.TRANSACTION) + .where('type', '==', TransactionType.PAYMENT) + .where('member', '==', invalidBid.bidder) + .where('payload.invalidPayment', '==', false) + .where('payload.auction', '==', auction.uid) + .get(); + for (const payment of payments) { + await this.creditAsInvalidPayment(payment); + } + + const invalidBidderDocRef = build5Db().doc(`${COL.MEMBER}/${invalidBid.bidder}`); + const invalidBidder = await this.transactionService.get(invalidBidderDocRef); + + const notification = NotificationService.prepareLostBid( + invalidBidder, + invalidBid.amount, + auction.uid, + ); + const notificationDocRef = build5Db().doc(`${COL.NOTIFICATION}/${notification.uid}`); + this.transactionService.push({ ref: notificationDocRef, data: notification, action: 'set' }); + }; + + private creditAsInvalidPayment = async (payment: Transaction) => { + const paymentDocRef = build5Db().doc(`${COL.TRANSACTION}/${payment.uid}`); + this.transactionService.push({ + ref: paymentDocRef, + data: { 'payload.invalidPayment': true }, + action: 'update', + }); + const paymentPayload = payment.payload; + await this.transactionService.createCredit(TransactionPayloadType.INVALID_PAYMENT, payment, { + msgId: paymentPayload.chainReference!, + to: { + address: paymentPayload.targetAddress!, + amount: paymentPayload.amount!, + }, + from: paymentPayload.sourceAddress!, + }); + return; + }; + + private onAuctionHighestBidChange = async (order: Transaction, auction: Auction) => { + const memberDocRef = build5Db().doc(`${COL.MEMBER}/${order.member!}`); + const member = await this.transactionService.get(memberDocRef); + const bidNotification = NotificationService.prepareBid( + member, + auction.auctionHighestBid!, + auction.uid, + ); + const notificationDocRef = build5Db().doc(`${COL.NOTIFICATION}/${bidNotification.uid}`); + this.transactionService.push({ ref: notificationDocRef, data: bidNotification, action: 'set' }); + }; + + private getAuctionUpdateData = (auction: Auction, bids: AuctionBid[]) => { + const auctionUpdateData = { + ...auction, + bids, + auctionHighestBidder: head(bids)?.bidder || '', + auctionHighestBid: head(bids)?.amount || 0, + }; + const auctionTTL = dayjs(auction.auctionTo!.toDate()).diff(dayjs()); + if ( + auction.auctionLength < (auction.extendedAuctionLength || 0) && + auctionTTL < (auction.extendAuctionWithin || 0) + ) { + set(auctionUpdateData, 'auctionTo', auction.extendedAuctionTo || null); + set(auctionUpdateData, 'auctionLength', auction.extendedAuctionLength || null); + } + + const auctionDocRef = build5Db().doc(`${COL.AUCTION}/${auction.uid}`); + this.transactionService.push({ ref: auctionDocRef, data: auctionUpdateData, action: 'update' }); + return auctionUpdateData as Auction; + }; + + private updateNft = (auction: Auction) => { + const nftUpdateData = { + auctionTo: auction.auctionTo, + auctionLength: auction.auctionLength, + auctionHighestBid: auction.auctionHighestBid, + auctionHighestBidder: auction.auctionHighestBidder, + }; + this.transactionService.push({ + ref: build5Db().doc(`${COL.NFT}/${auction.nftId}`), + data: nftUpdateData, + action: 'update', + }); + }; +} + +const placeBid = (auction: Auction, order: string, bidder: string, amount: number) => { + const bids = [...auction.bids]; + const currentBid = bids.find((b) => b.bidder === bidder); + + if (currentBid) { + if (auction.topUpBased) { + currentBid.amount += amount; + bids.sort((a, b) => b.amount - a.amount); + } else { + currentBid.amount = Math.max(currentBid.amount, amount); + bids.sort((a, b) => b.amount - a.amount); + bids.push({ bidder, amount: Math.min(currentBid.amount, amount), order }); + } + } else { + bids.push({ bidder, amount, order }); + bids.sort((a, b) => b.amount - a.amount); + } + + return { + bids: bids.slice(0, auction.maxBids), + invalidBid: head(bids.slice(auction.maxBids)), + }; +}; + +const paidAmountIsBelowFloor = (payment: Transaction, auction: Auction) => + payment.payload.amount! < auction.auctionFloorPrice; + +const newPaymentTooLow = (payment: Transaction, auction: Auction) => + !auction.topUpBased && (last(auction.bids)?.amount || 0) > payment.payload.amount!; diff --git a/packages/functions/src/services/payment/auction/auction.finalize.service.ts b/packages/functions/src/services/payment/auction/auction.finalize.service.ts new file mode 100644 index 0000000000..4f3b5567f7 --- /dev/null +++ b/packages/functions/src/services/payment/auction/auction.finalize.service.ts @@ -0,0 +1,103 @@ +import { build5Db } from '@build-5/database'; +import { + Auction, + AuctionType, + COL, + Member, + Nft, + NftStatus, + Transaction, + TransactionType, + WenError, +} from '@build-5/interfaces'; +import { invalidArgument } from '../../../utils/error.utils'; +import { NotificationService } from '../../notification/notification'; +import { BaseNftService } from '../nft/common'; +import { TransactionService } from '../transaction-service'; + +export class AuctionFinalizeService { + constructor(readonly transactionService: TransactionService) {} + + public markAsFinalized = async (auctionId: string) => { + const auctionDocRef = build5Db().doc(`${COL.AUCTION}/${auctionId}`); + const auction = await this.transactionService.get(auctionDocRef); + if (!auction.active) { + throw invalidArgument(WenError.auction_not_active); + } + + this.transactionService.push({ ref: auctionDocRef, data: { active: false }, action: 'update' }); + + switch (auction.type) { + case AuctionType.NFT: + await this.finalizeNftAuction(auction); + } + }; + + private finalizeNftAuction = async (auction: Auction) => { + const nftDocRef = build5Db().doc(`${COL.NFT}/${auction.nftId}`); + const nft = await this.transactionService.get(nftDocRef); + + if (!auction.auctionHighestBidder) { + this.transactionService.push({ + ref: nftDocRef, + data: { + auctionFrom: null, + auctionTo: null, + extendedAuctionTo: null, + auctionFloorPrice: null, + auctionLength: null, + extendedAuctionLength: null, + auctionHighestBid: null, + auctionHighestBidder: null, + auctionHighestTransaction: null, + auction: null, + }, + action: 'update', + }); + } + + const payments = await build5Db() + .collection(COL.TRANSACTION) + .where('type', '==', TransactionType.PAYMENT) + .where('member', '==', auction.auctionHighestBidder) + .where('payload.invalidPayment', '==', false) + .where('payload.auction', '==', auction.uid) + .get(); + for (const payment of payments) { + const orderDocRef = build5Db().doc( + `${COL.TRANSACTION}/${payment.payload.sourceTransaction![0]}`, + ); + const order = await orderDocRef.get(); + this.transactionService.createBillPayment(order, payment); + } + + const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${auction.bids[0].order}`); + const order = await orderDocRef.get(); + + const nftService = new BaseNftService(this.transactionService); + await nftService.setNftOwner(order, auction.auctionHighestBid!); + + const memberDocRef = build5Db().collection(COL.MEMBER).doc(order!.member!); + const member = await memberDocRef.get(); + + const notification = NotificationService.prepareWinBid( + member, + auction.auctionHighestBid!, + auction.uid, + ); + const notificationDocRef = build5Db().doc(`${COL.NOTIFICATION}/${notification.uid}`); + this.transactionService.push({ + ref: notificationDocRef, + data: notification, + action: 'set', + }); + + nftService.setTradingStats(nft); + + const tanglePuchase = order.payload.tanglePuchase; + const disableWithdraw = order.payload.disableWithdraw; + if (!disableWithdraw && tanglePuchase && nft.status === NftStatus.MINTED) { + await nftService.withdrawNft(order, nft); + } + }; +} diff --git a/packages/functions/src/services/payment/nft/common.ts b/packages/functions/src/services/payment/nft/common.ts index 87014edbc8..2881c65a08 100644 --- a/packages/functions/src/services/payment/nft/common.ts +++ b/packages/functions/src/services/payment/nft/common.ts @@ -1,24 +1,15 @@ import { build5Db } from '@build-5/database'; -import { - COL, - Collection, - Member, - Nft, - NftAccess, - Transaction, - TransactionPayloadType, -} from '@build-5/interfaces'; -import dayjs from 'dayjs'; -import { last, set } from 'lodash'; +import { COL, Collection, Member, Nft, NftAccess, Transaction } from '@build-5/interfaces'; import { getAddress } from '../../../utils/address.utils'; import { getProject } from '../../../utils/common.utils'; -import { dateToTimestamp, serverTime } from '../../../utils/dateTime.utils'; -import { NotificationService } from '../../notification/notification'; -import { BaseService } from '../base'; +import { serverTime } from '../../../utils/dateTime.utils'; import { createNftWithdrawOrder } from '../tangle-service/nft/nft-purchase.service'; +import { TransactionService } from '../transaction-service'; -export abstract class BaseNftService extends BaseService { - protected setTradingStats = (nft: Nft) => { +export class BaseNftService { + constructor(private readonly transactionService: TransactionService) {} + + public setTradingStats = (nft: Nft) => { const data = { lastTradedOn: serverTime(), totalTrades: build5Db().inc(1) }; const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${nft.collection}`); this.transactionService.push({ ref: collectionDocRef, data, action: 'update' }); @@ -27,7 +18,7 @@ export abstract class BaseNftService extends BaseService { this.transactionService.push({ ref: nftDocRef, data, action: 'update' }); }; - protected withdrawNft = async (order: Transaction, nft: Nft) => { + public withdrawNft = async (order: Transaction, nft: Nft) => { const membderDocRef = build5Db().doc(`${COL.MEMBER}/${order.member}`); const member = await membderDocRef.get(); const { order: withdrawOrder, nftUpdateData } = createNftWithdrawOrder( @@ -48,14 +39,14 @@ export abstract class BaseNftService extends BaseService { }); }; - protected async setNftOwner(order: Transaction, payment: Transaction): Promise { - const nftDocRef = build5Db().collection(COL.NFT).doc(payment.payload.nft!); + public setNftOwner = async (order: Transaction, amount: number) => { + const nftDocRef = build5Db().collection(COL.NFT).doc(order.payload.nft!); const nft = await this.transactionService.get(nftDocRef); const nftUpdateData = { - owner: payment.member, + owner: order.member, isOwned: true, - price: nft.saleAccess === NftAccess.MEMBERS ? nft.price : payment.payload.amount, + price: nft.saleAccess === NftAccess.MEMBERS ? nft.price : amount, sold: true, locked: false, lockedBy: null, @@ -74,6 +65,7 @@ export abstract class BaseNftService extends BaseService { auctionHighestTransaction: null, saleAccess: null, saleAccessMembers: [], + auction: null, }; this.transactionService.push({ ref: nftDocRef, @@ -81,51 +73,8 @@ export abstract class BaseNftService extends BaseService { action: 'update', }); - if ( - nft.auctionHighestTransaction && - order.payload.type === TransactionPayloadType.NFT_PURCHASE - ) { - const highestTranDocRef = build5Db().doc( - `${COL.TRANSACTION}/${nft.auctionHighestTransaction}`, - ); - const highestPay = (await highestTranDocRef.get())!; - this.transactionService.push({ - ref: highestTranDocRef, - data: { invalidPayment: true }, - action: 'update', - }); - - const sameOwner = highestPay.member === order.member; - const credit = await this.transactionService.createCredit( - TransactionPayloadType.NONE, - highestPay, - { - msgId: highestPay.payload.chainReference || '', - to: { - address: highestPay.payload.targetAddress!, - amount: highestPay.payload.amount!, - }, - from: highestPay.payload.sourceAddress!, - }, - serverTime(), - sameOwner, - ); - - if (!sameOwner) { - const orderId = Array.isArray(highestPay.payload.sourceTransaction) - ? last(highestPay.payload.sourceTransaction)! - : highestPay.payload.sourceTransaction!; - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${orderId}`); - this.transactionService.push({ - ref: orderDocRef, - data: { linkedTransactions: build5Db().arrayUnion(credit?.uid) }, - action: 'update', - }); - } - } - if (order.payload.beneficiary === 'space') { - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${payment.payload.collection}`); + const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${order.payload.collection}`); this.transactionService.push({ ref: collectionDocRef, data: { sold: build5Db().inc(1) }, @@ -149,143 +98,5 @@ export abstract class BaseNftService extends BaseService { }); } } - } - - protected async addNewBid(transaction: Transaction, payment: Transaction): Promise { - const nftDocRef = build5Db().collection(COL.NFT).doc(transaction.payload.nft!); - const paymentDocRef = build5Db().doc(`${COL.TRANSACTION}/${payment.uid}`); - const nft = await this.transactionService.get(nftDocRef); - let newValidPayment = false; - let previousHighestPay: Transaction | undefined; - const paymentPayload = payment.payload; - if (nft?.auctionHighestTransaction) { - const previousHighestPayRef = build5Db().doc( - `${COL.TRANSACTION}/${nft?.auctionHighestTransaction}`, - ); - previousHighestPay = (await this.transactionService.get(previousHighestPayRef))!; - - if ( - previousHighestPay!.payload.amount! < paymentPayload.amount! && - paymentPayload.amount! >= (nft?.auctionFloorPrice || 0) - ) { - newValidPayment = true; - } - } else { - if (paymentPayload.amount! >= (nft?.auctionFloorPrice || 0)) { - newValidPayment = true; - } - } - - // We need to credit the old payment. - if (newValidPayment && previousHighestPay) { - const refPrevPayment = build5Db().doc(`${COL.TRANSACTION}/${previousHighestPay.uid}`); - previousHighestPay.payload.invalidPayment = true; - this.transactionService.push({ - ref: refPrevPayment, - data: previousHighestPay, - action: 'update', - }); - - // Mark as invalid and create credit. - const sameOwner = previousHighestPay.member === transaction.member; - const credit = await this.transactionService.createCredit( - TransactionPayloadType.DATA_NO_LONGER_VALID, - previousHighestPay, - { - msgId: previousHighestPay.payload.chainReference!, - to: { - address: previousHighestPay.payload.targetAddress!, - amount: previousHighestPay.payload.amount!, - }, - from: previousHighestPay.payload.sourceAddress!, - }, - dateToTimestamp(dayjs(payment.createdOn?.toDate()).subtract(1, 's')), - sameOwner, - ); - - // We have to set link on the past order. - if (!sameOwner) { - const sourcTran: string = Array.isArray(previousHighestPay.payload.sourceTransaction) - ? last(previousHighestPay.payload.sourceTransaction)! - : previousHighestPay.payload.sourceTransaction!; - const refHighTranOrderDocRef = build5Db().doc(`${COL.TRANSACTION}/${sourcTran}`); - const refHighTranOrder = await this.transactionService.get( - refHighTranOrderDocRef, - ); - if (refHighTranOrder) { - this.transactionService.push({ - ref: refHighTranOrderDocRef, - data: { - linkedTransactions: [ - ...(refHighTranOrder?.linkedTransactions || []), - ...[credit?.uid], - ], - }, - action: 'update', - }); - - // Notify them. - const refMember = build5Db().collection(COL.MEMBER).doc(refHighTranOrder?.member!); - const sfDocMember = await this.transactionService.get(refMember); - const bidNotification = NotificationService.prepareLostBid( - sfDocMember!, - nft!, - previousHighestPay, - ); - const refNotification = build5Db().collection(COL.NOTIFICATION).doc(bidNotification.uid); - this.transactionService.push({ - ref: refNotification, - data: bidNotification, - action: 'set', - }); - } - } - } - - // Update NFT with highest bid. - if (newValidPayment) { - const nftUpdateData = { - auctionHighestBid: payment.payload.amount, - auctionHighestBidder: payment.member, - auctionHighestTransaction: payment.uid, - }; - const auctionTTL = dayjs(nft?.auctionTo!.toDate()).diff(dayjs()); - if ( - (nft?.auctionLength || 0) < (nft?.extendedAuctionLength || 0) && - auctionTTL < (nft?.extendAuctionWithin || 0) - ) { - set(nftUpdateData, 'auctionTo', nft?.extendedAuctionTo || null); - set(nftUpdateData, 'auctionLength', nft?.extendedAuctionLength || null); - } - this.transactionService.push({ - ref: nftDocRef, - data: nftUpdateData, - action: 'update', - }); - - const refMember = build5Db().collection(COL.MEMBER).doc(transaction.member!); - const sfDocMember = await this.transactionService.get(refMember); - const bidNotification = NotificationService.prepareBid(sfDocMember!, nft!, payment); - const refNotification = build5Db().collection(COL.NOTIFICATION).doc(bidNotification.uid); - this.transactionService.push({ - ref: refNotification, - data: bidNotification, - action: 'set', - }); - } else { - // Invalidate payment. - paymentPayload.invalidPayment = true; - this.transactionService.push({ ref: paymentDocRef, data: payment, action: 'update' }); - - // No valid payment so we credit anyways. - await this.transactionService.createCredit(TransactionPayloadType.INVALID_PAYMENT, payment, { - msgId: paymentPayload.chainReference!, - to: { - address: paymentPayload.targetAddress!, - amount: paymentPayload.amount!, - }, - from: paymentPayload.sourceAddress!, - }); - } - } + }; } diff --git a/packages/functions/src/services/payment/nft/nft-bid.service.ts b/packages/functions/src/services/payment/nft/nft-bid.service.ts deleted file mode 100644 index ff41f01638..0000000000 --- a/packages/functions/src/services/payment/nft/nft-bid.service.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { build5Db } from '@build-5/database'; -import { COL, Member, Nft, NftStatus, Transaction } from '@build-5/interfaces'; -import { last } from 'lodash'; -import { NotificationService } from '../../notification/notification'; -import { HandlerParams } from '../base'; -import { BaseNftService } from './common'; - -export class NftBidService extends BaseNftService { - public handleRequest = async ({ order, match, tran, tranEntry, build5Tran }: HandlerParams) => { - const nftDocRef = build5Db().collection(COL.NFT).doc(order.payload.nft!); - const nft = await this.transactionService.get(nftDocRef); - if (nft?.auctionFrom) { - const payment = await this.transactionService.createPayment(order, match); - await this.addNewBid(order, payment); - } else { - await this.transactionService.processAsInvalid(tran, order, tranEntry, build5Tran); - } - }; - - public async markNftAsFinalized({ uid, auctionFrom }: Nft): Promise { - if (!auctionFrom) { - throw new Error('NFT auctionFrom is no longer defined'); - } - - const nftDocRef = build5Db().doc(`${COL.NFT}/${uid}`); - const nft = await this.transactionService.get(nftDocRef); - if (nft.auctionHighestTransaction) { - const highestPayDocRef = build5Db().doc( - `${COL.TRANSACTION}/${nft.auctionHighestTransaction}`, - ); - const highestPay = (await highestPayDocRef.get())!; - - const orderId = Array.isArray(highestPay.payload.sourceTransaction) - ? last(highestPay.payload.sourceTransaction)! - : highestPay.payload.sourceTransaction!; - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${orderId}`); - const order = await orderDocRef.get(); - if (!order) { - throw new Error('Unable to find ORDER linked to PAYMENT'); - } - - this.transactionService.markAsReconciled(order, highestPay.payload.chainReference!); - this.transactionService.createBillPayment(order, highestPay); - await this.setNftOwner(order, highestPay); - - const memberDocRef = build5Db().collection(COL.MEMBER).doc(order.member!); - const member = await memberDocRef.get(); - - const notification = NotificationService.prepareWinBid(member, nft, highestPay); - const notificationDocRef = build5Db().doc(`${COL.NOTIFICATION}/${notification.uid}`); - this.transactionService.push({ - ref: notificationDocRef, - data: notification, - action: 'set', - }); - this.transactionService.push({ - ref: orderDocRef, - data: { - linkedTransactions: build5Db().arrayUnion(...this.transactionService.linkedTransactions), - }, - action: 'update', - }); - - this.setTradingStats(nft); - - const tanglePuchase = order.payload.tanglePuchase; - const disableWithdraw = order.payload.disableWithdraw; - if (!disableWithdraw && tanglePuchase && nft.status === NftStatus.MINTED) { - await this.withdrawNft(order, nft); - } - } else { - this.transactionService.push({ - ref: nftDocRef, - data: { - auctionFrom: null, - auctionTo: null, - extendedAuctionTo: null, - auctionFloorPrice: null, - auctionLength: null, - extendedAuctionLength: null, - auctionHighestBid: null, - auctionHighestBidder: null, - auctionHighestTransaction: null, - }, - action: 'update', - }); - } - } -} diff --git a/packages/functions/src/services/payment/nft/nft-purchase.service.ts b/packages/functions/src/services/payment/nft/nft-purchase.service.ts index cd58d25be7..1e181df776 100644 --- a/packages/functions/src/services/payment/nft/nft-purchase.service.ts +++ b/packages/functions/src/services/payment/nft/nft-purchase.service.ts @@ -1,9 +1,17 @@ import { build5Db } from '@build-5/database'; -import { COL, Nft, NftStatus, Transaction, TransactionPayloadType } from '@build-5/interfaces'; -import { HandlerParams } from '../base'; +import { + Auction, + COL, + Nft, + NftStatus, + Transaction, + TransactionPayloadType, + TransactionType, +} from '@build-5/interfaces'; +import { BaseService, HandlerParams } from '../base'; import { BaseNftService } from './common'; -export class NftPurchaseService extends BaseNftService { +export class NftPurchaseService extends BaseService { public handleRequest = async ({ order, match, tran, tranEntry, build5Tran }: HandlerParams) => { const nftDocRef = build5Db().doc(`${COL.NFT}/${order.payload.nft}`); const nft = await this.transactionService.get(nftDocRef); @@ -13,17 +21,54 @@ export class NftPurchaseService extends BaseNftService { return; } + const nftService = new BaseNftService(this.transactionService); + const payment = await this.transactionService.createPayment(order, match); this.transactionService.createBillPayment(order, payment); - await this.setNftOwner(order, payment); + await nftService.setNftOwner(order, payment.payload.amount!); + + if (nft.auction) { + await this.creditBids(nft.auction); + } + this.transactionService.markAsReconciled(order, match.msgId); - this.setTradingStats(nft); + nftService.setTradingStats(nft); const tanglePuchase = order.payload.tanglePuchase; const disableWithdraw = order.payload.disableWithdraw; if (!disableWithdraw && tanglePuchase && nft.status === NftStatus.MINTED) { - await this.withdrawNft(order, nft); + await nftService.withdrawNft(order, nft); + } + }; + + private creditBids = async (auctionId: string) => { + const auctionDocRef = build5Db().doc(`${COL.AUCTION}/${auctionId}`); + const auction = await this.transaction.get(auctionDocRef); + this.transactionService.push({ + ref: auctionDocRef, + data: { active: false }, + action: 'update', + }); + + for (const bid of auction.bids) { + const payments = await build5Db() + .collection(COL.TRANSACTION) + .where('type', '==', TransactionType.PAYMENT) + .where('member', '==', bid.bidder) + .where('payload.invalidPayment', '==', false) + .where('payload.auction', '==', auctionId) + .get(); + for (const payment of payments) { + await this.transactionService.createCredit(TransactionPayloadType.NONE, payment, { + msgId: payment.payload.chainReference || '', + to: { + address: payment.payload.targetAddress!, + amount: payment.payload.amount!, + }, + from: payment.payload.sourceAddress!, + }); + } } }; @@ -43,7 +88,11 @@ export class NftPurchaseService extends BaseNftService { data: { locked: false, lockedBy: null }, action: 'update', }); - } else if (transaction.payload.type === TransactionPayloadType.NFT_BID) { + } else if ( + [TransactionPayloadType.AUCTION_BID, TransactionPayloadType.NFT_BID].includes( + transaction.payload.type!, + ) + ) { const payments = await build5Db() .collection(COL.TRANSACTION) .where('payload.invalidPayment', '==', false) diff --git a/packages/functions/src/services/payment/payment-processing.ts b/packages/functions/src/services/payment/payment-processing.ts index 210306fccd..baad332034 100644 --- a/packages/functions/src/services/payment/payment-processing.ts +++ b/packages/functions/src/services/payment/payment-processing.ts @@ -16,12 +16,12 @@ import { dateToTimestamp } from '../../utils/dateTime.utils'; import { invalidArgument } from '../../utils/error.utils'; import { MemberAddressService } from './address/address-member.service'; import { SpaceAddressService } from './address/address.space.service'; +import { AuctionBidService } from './auction/auction-bid.service'; import { AwardFundService } from './award/award-service'; import { HandlerParams } from './base'; import { CreditService } from './credit-service'; import { MetadataNftService } from './metadataNft-service'; import { CollectionMintingService } from './nft/collection-minting.service'; -import { NftBidService } from './nft/nft-bid.service'; import { NftDepositService } from './nft/nft-deposit.service'; import { NftPurchaseService } from './nft/nft-purchase.service'; import { NftStakeService } from './nft/nft-stake.service'; @@ -143,7 +143,8 @@ export class ProcessingService { case TransactionPayloadType.NFT_PURCHASE: return new NftPurchaseService(tranService); case TransactionPayloadType.NFT_BID: - return new NftBidService(tranService); + case TransactionPayloadType.AUCTION_BID: + return new AuctionBidService(tranService); case TransactionPayloadType.SPACE_ADDRESS_VALIDATION: return new SpaceAddressService(tranService); case TransactionPayloadType.MEMBER_ADDRESS_VALIDATION: diff --git a/packages/functions/src/services/payment/tangle-service/TangleRequestService.ts b/packages/functions/src/services/payment/tangle-service/TangleRequestService.ts index 7493b588bb..9721e81a53 100644 --- a/packages/functions/src/services/payment/tangle-service/TangleRequestService.ts +++ b/packages/functions/src/services/payment/tangle-service/TangleRequestService.ts @@ -14,11 +14,12 @@ import { invalidArgument } from '../../../utils/error.utils'; import { getRandomNonce } from '../../../utils/wallet.utils'; import { BaseService, HandlerParams } from '../base'; import { TangleAddressValidationService } from './address/address-validation.service'; +import { TangleAuctionBidService, TangleNftAuctionBidService } from './auction/auction.bid.service'; +import { TangleAuctionCreateService } from './auction/auction.create.service'; import { AwardApproveParticipantService } from './award/award.approve.participant.service'; import { AwardCreateService } from './award/award.create.service'; import { AwardFundService } from './award/award.fund.service'; import { MintMetadataNftService } from './metadataNft/mint-metadata-nft.service'; -import { TangleNftBidService } from './nft/nft-bid.service'; import { NftDepositService } from './nft/nft-deposit.service'; import { TangleNftPurchaseService } from './nft/nft-purchase.service'; import { TangleNftSetForSaleService } from './nft/nft-set-for-sale.service'; @@ -95,7 +96,7 @@ export class TangleRequestService extends BaseService { case TangleRequestType.NFT_SET_FOR_SALE: return new TangleNftSetForSaleService(this.transactionService); case TangleRequestType.NFT_BID: - return new TangleNftBidService(this.transactionService); + return new TangleNftAuctionBidService(this.transactionService); case TangleRequestType.CLAIM_MINTED_AIRDROPS: return new TangleTokenClaimService(this.transactionService); case TangleRequestType.AWARD_CREATE: @@ -132,6 +133,10 @@ export class TangleRequestService extends BaseService { return new MintMetadataNftService(this.transactionService); case TangleRequestType.STAMP: return new StampTangleService(this.transactionService); + case TangleRequestType.CREATE_AUCTION: + return new TangleAuctionCreateService(this.transactionService); + case TangleRequestType.BID_AUCTION: + return new TangleAuctionBidService(this.transactionService); default: throw invalidArgument(WenError.invalid_tangle_request_type); } diff --git a/packages/functions/src/services/payment/tangle-service/auction/AuctionBidTangleRequestSchema.ts b/packages/functions/src/services/payment/tangle-service/auction/AuctionBidTangleRequestSchema.ts new file mode 100644 index 0000000000..4f62d433a5 --- /dev/null +++ b/packages/functions/src/services/payment/tangle-service/auction/AuctionBidTangleRequestSchema.ts @@ -0,0 +1,12 @@ +import { AuctionBidTangleRequest, TangleRequestType } from '@build-5/interfaces'; +import { CommonJoi, toJoiObject } from '../../../joi/common'; +import { baseTangleSchema } from '../common'; + +export const auctionBidTangleSchema = toJoiObject({ + ...baseTangleSchema(TangleRequestType.BID_AUCTION), + auction: CommonJoi.uid().description('Build5 id of the auction to bid on.'), +}) + .description('Tangle request object to create an auction bid') + .meta({ + className: 'AuctionBidTangleRequest', + }); diff --git a/packages/functions/src/services/payment/tangle-service/auction/AuctionCreateTangleRequestSchema.ts b/packages/functions/src/services/payment/tangle-service/auction/AuctionCreateTangleRequestSchema.ts new file mode 100644 index 0000000000..31e3257783 --- /dev/null +++ b/packages/functions/src/services/payment/tangle-service/auction/AuctionCreateTangleRequestSchema.ts @@ -0,0 +1,13 @@ +import { AuctionCreateTangleRequest, TangleRequestType } from '@build-5/interfaces'; +import { auctionCreateSchema } from '../../../../controls/auction/AuctionCreateRequestSchema'; +import { toJoiObject } from '../../../joi/common'; +import { baseTangleSchema } from '../common'; + +export const auctionCreateTangleSchema = toJoiObject({ + ...baseTangleSchema(TangleRequestType.CREATE_AUCTION), + ...auctionCreateSchema, +}) + .description('Request object to create an auction.') + .meta({ + className: 'AuctionCreateTangleRequest', + }); diff --git a/packages/functions/src/services/payment/tangle-service/auction/NftBidTangleRequestSchema.ts b/packages/functions/src/services/payment/tangle-service/auction/NftBidTangleRequestSchema.ts new file mode 100644 index 0000000000..a5ea769043 --- /dev/null +++ b/packages/functions/src/services/payment/tangle-service/auction/NftBidTangleRequestSchema.ts @@ -0,0 +1,16 @@ +import { NftBidTangleRequest, TangleRequestType } from '@build-5/interfaces'; +import Joi from 'joi'; +import { CommonJoi, toJoiObject } from '../../../joi/common'; +import { baseTangleSchema } from '../common'; + +export const nftBidSchema = toJoiObject({ + ...baseTangleSchema(TangleRequestType.NFT_BID), + nft: CommonJoi.uid().description('Build5 id of the nft to bid on.'), + disableWithdraw: Joi.boolean().description( + "If set to true, NFT will not be sent to the buyer's validated address upon purchase.", + ), +}) + .description('Tangle request object to create an NFT bid') + .meta({ + className: 'NftBidTangleRequest', + }); diff --git a/packages/functions/src/services/payment/tangle-service/auction/auction.bid.order.ts b/packages/functions/src/services/payment/tangle-service/auction/auction.bid.order.ts new file mode 100644 index 0000000000..6550d9b861 --- /dev/null +++ b/packages/functions/src/services/payment/tangle-service/auction/auction.bid.order.ts @@ -0,0 +1,164 @@ +import { build5Db } from '@build-5/database'; +import { + Auction, + AuctionType, + COL, + Collection, + CollectionStatus, + Entity, + MIN_AMOUNT_TO_TRANSFER, + Member, + Nft, + NftAccess, + Space, + Transaction, + TransactionPayloadType, + TransactionType, + TransactionValidationType, + WenError, +} from '@build-5/interfaces'; +import { assertMemberHasValidAddress, getAddress } from '../../../../utils/address.utils'; +import { generateRandomAmount, getProjects, getRestrictions } from '../../../../utils/common.utils'; +import { isProdEnv } from '../../../../utils/config.utils'; +import { dateToTimestamp } from '../../../../utils/dateTime.utils'; +import { invalidArgument } from '../../../../utils/error.utils'; +import { assertIpNotBlocked } from '../../../../utils/ip.utils'; +import { getSpace } from '../../../../utils/space.utils'; +import { getRandomEthAddress } from '../../../../utils/wallet.utils'; +import { WalletService } from '../../../wallet/wallet.service'; + +export const createBidOrder = async ( + project: string, + owner: string, + auctionId: string, + ip = '', +): Promise => { + const auctionDocRef = build5Db().doc(`${COL.AUCTION}/${auctionId}`); + const auction = await auctionDocRef.get(); + if (!auction) { + throw invalidArgument(WenError.auction_does_not_exist); + } + if (!auction.active) { + throw invalidArgument(WenError.auction_not_active); + } + + const validationResponse = await assertAuctionData(owner, ip, auction); + + const network = auction?.network; + + const wallet = await WalletService.newWallet(network); + const targetAddress = await wallet.getNewIotaAddressDetails(); + + const order = { + project, + projects: getProjects([], project), + type: TransactionType.ORDER, + uid: getRandomEthAddress(), + member: owner, + space: '', + network, + payload: { + type: + auction.type === AuctionType.NFT + ? TransactionPayloadType.NFT_BID + : TransactionPayloadType.AUCTION_BID, + amount: generateRandomAmount(), + targetAddress: targetAddress.bech32, + expiresOn: dateToTimestamp((auction.extendedAuctionTo || auction.auctionTo).toDate()), + reconciled: false, + validationType: TransactionValidationType.ADDRESS, + void: false, + chainReference: null, + auction: auction.uid, + }, + linkedTransactions: [], + }; + + if (auction.type === AuctionType.NFT) { + const nft = validationResponse as Nft; + + const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${nft.collection}`); + const collection = (await collectionDocRef.get())!; + + const spaceDocRef = build5Db().doc(`${COL.SPACE}/${collection.space}`); + const space = await spaceDocRef.get(); + + const prevOwnerDocRef = build5Db().doc(`${COL.MEMBER}/${nft.owner}`); + const prevOwner = await prevOwnerDocRef.get(); + assertMemberHasValidAddress(prevOwner, network); + + const royaltySpace = await getSpace(collection.royaltiesSpace); + + const auctionFloorPrice = auction.auctionFloorPrice || MIN_AMOUNT_TO_TRANSFER; + const finalPrice = Number(Math.max(auctionFloorPrice, MIN_AMOUNT_TO_TRANSFER).toPrecision(2)); + + return { + ...order, + space: collection.space, + payload: { + ...order.payload, + amount: finalPrice, + beneficiary: nft.owner ? Entity.MEMBER : Entity.SPACE, + beneficiaryUid: nft.owner || collection.space, + beneficiaryAddress: getAddress(nft.owner ? prevOwner : space, network), + royaltiesFee: collection.royaltiesFee, + royaltiesSpace: collection.royaltiesSpace, + royaltiesSpaceAddress: getAddress(royaltySpace, network), + expiresOn: nft.auctionTo!, + nft: nft.uid, + collection: collection.uid, + restrictions: getRestrictions(collection, nft), + }, + }; + } + + return order; +}; + +const assertAuctionData = async (owner: string, ip: string, auction: Auction) => { + if (!auction.active) { + throw invalidArgument(WenError.auction_not_active); + } + switch (auction.type) { + case AuctionType.NFT: + return await assertNftAuction(owner, ip, auction); + } + return; +}; + +const assertNftAuction = async (owner: string, ip: string, auction: Auction) => { + const nftDocRef = build5Db().doc(`${COL.NFT}/${auction.nftId}`); + const nft = await nftDocRef.get(); + if (!nft) { + throw invalidArgument(WenError.nft_does_not_exists); + } + + if (isProdEnv()) { + await assertIpNotBlocked(ip, nft.uid, 'nft'); + } + + const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${nft.collection}`); + const collection = (await collectionDocRef.get())!; + + if (!collection.approved) { + throw invalidArgument(WenError.collection_must_be_approved); + } + + if (![CollectionStatus.PRE_MINTED, CollectionStatus.MINTED].includes(collection.status!)) { + throw invalidArgument(WenError.invalid_collection_status); + } + + if (nft.saleAccess === NftAccess.MEMBERS && !(nft.saleAccessMembers || []).includes(owner)) { + throw invalidArgument(WenError.you_are_not_allowed_member_to_purchase_this_nft); + } + + if (nft.placeholderNft) { + throw invalidArgument(WenError.nft_placeholder_cant_be_purchased); + } + + if (nft.owner === owner) { + throw invalidArgument(WenError.you_cant_buy_your_nft); + } + + return nft; +}; diff --git a/packages/functions/src/services/payment/tangle-service/auction/auction.bid.service.ts b/packages/functions/src/services/payment/tangle-service/auction/auction.bid.service.ts new file mode 100644 index 0000000000..fe79ec9168 --- /dev/null +++ b/packages/functions/src/services/payment/tangle-service/auction/auction.bid.service.ts @@ -0,0 +1,88 @@ +import { build5Db } from '@build-5/database'; +import { COL, Nft, TransactionPayloadType, WenError } from '@build-5/interfaces'; +import { invalidArgument } from '../../../../utils/error.utils'; +import { assertValidationAsync } from '../../../../utils/schema.utils'; +import { HandlerParams } from '../../base'; +import { TransactionService } from '../../transaction-service'; +import { auctionBidTangleSchema } from './AuctionBidTangleRequestSchema'; +import { nftBidSchema } from './NftBidTangleRequestSchema'; +import { createBidOrder } from './auction.bid.order'; + +export class TangleNftAuctionBidService { + constructor(readonly transactionService: TransactionService) {} + + public handleRequest = async ({ + request, + project, + owner, + order: tangleOrder, + tran, + tranEntry, + }: HandlerParams) => { + const params = await assertValidationAsync(nftBidSchema, request); + + const nftDocRef = build5Db().doc(`${COL.NFT}/${params.nft}`); + const nft = await nftDocRef.get(); + + const order = await createBidOrder(project, owner, nft?.auction || ''); + order.payload.tanglePuchase = true; + order.payload.disableWithdraw = params.disableWithdraw || false; + + if (tangleOrder.network !== order.network) { + throw invalidArgument(WenError.invalid_network); + } + + this.transactionService.push({ + ref: build5Db().doc(`${COL.TRANSACTION}/${order.uid}`), + data: order, + action: 'set', + merge: true, + }); + + this.transactionService.createUnlockTransaction( + order, + tran, + tranEntry, + TransactionPayloadType.TANGLE_TRANSFER, + tranEntry.outputId, + ); + return; + }; +} + +export class TangleAuctionBidService { + constructor(readonly transactionService: TransactionService) {} + + public handleRequest = async ({ + request, + project, + owner, + order: tangleOrder, + tran, + tranEntry, + }: HandlerParams) => { + const params = await assertValidationAsync(auctionBidTangleSchema, request); + + const order = await createBidOrder(project, owner, params.auction); + + if (tangleOrder.network !== order.network) { + throw invalidArgument(WenError.invalid_network); + } + + this.transactionService.push({ + ref: build5Db().doc(`${COL.TRANSACTION}/${order.uid}`), + data: order, + action: 'set', + merge: true, + }); + + this.transactionService.createUnlockTransaction( + order, + tran, + tranEntry, + TransactionPayloadType.TANGLE_TRANSFER, + tranEntry.outputId, + ); + return; + }; +} diff --git a/packages/functions/src/services/payment/tangle-service/auction/auction.create.service.ts b/packages/functions/src/services/payment/tangle-service/auction/auction.create.service.ts new file mode 100644 index 0000000000..6873a36597 --- /dev/null +++ b/packages/functions/src/services/payment/tangle-service/auction/auction.create.service.ts @@ -0,0 +1,69 @@ +import { build5Db } from '@build-5/database'; +import { + Auction, + AuctionCreateRequest, + AuctionCreateTangleRequest, + AuctionType, + COL, + Network, +} from '@build-5/interfaces'; +import dayjs from 'dayjs'; +import { getProjects } from '../../../../utils/common.utils'; +import { dateToTimestamp } from '../../../../utils/dateTime.utils'; +import { assertValidationAsync } from '../../../../utils/schema.utils'; +import { getRandomEthAddress } from '../../../../utils/wallet.utils'; +import { HandlerParams } from '../../base'; +import { TransactionService } from '../../transaction-service'; +import { auctionCreateTangleSchema } from './AuctionCreateTangleRequestSchema'; + +export class TangleAuctionCreateService { + constructor(readonly transactionService: TransactionService) {} + + public handleRequest = async ({ request, project, owner }: HandlerParams) => { + const params = await assertValidationAsync(auctionCreateTangleSchema, request); + + const auction = getAuctionData(project, owner, params); + const auctionDocRef = build5Db().doc(`${COL.AUCTION}/${auction.uid}`); + + this.transactionService.push({ ref: auctionDocRef, data: auction, action: 'set' }); + + return { auction: auction.uid }; + }; +} + +export const getAuctionData = ( + project: string, + owner: string, + params: AuctionCreateRequest | AuctionCreateTangleRequest, +) => { + const auction: Auction = { + uid: getRandomEthAddress(), + project, + projects: getProjects([], project), + createdBy: owner, + auctionFrom: dateToTimestamp(params.auctionFrom), + auctionTo: dateToTimestamp(dayjs(params.auctionFrom).add(params.auctionLength)), + auctionLength: params.auctionLength, + + auctionFloorPrice: params.auctionFloorPrice || 0, + + maxBids: params.maxBids, + + type: AuctionType.OPEN, + network: params.network as Network, + + active: true, + topUpBased: params.topUpBased || false, + + bids: [], + }; + + if (params.extendedAuctionLength && params.extendAuctionWithin) { + auction.extendedAuctionLength = params.extendedAuctionLength; + auction.extendAuctionWithin = params.extendAuctionWithin; + auction.extendedAuctionTo = dateToTimestamp( + dayjs(params.auctionFrom).add(params.extendedAuctionLength), + ); + } + return auction; +}; diff --git a/packages/functions/src/services/payment/tangle-service/nft/nft-bid.service.ts b/packages/functions/src/services/payment/tangle-service/nft/nft-bid.service.ts deleted file mode 100644 index 09204e3136..0000000000 --- a/packages/functions/src/services/payment/tangle-service/nft/nft-bid.service.ts +++ /dev/null @@ -1,159 +0,0 @@ -import { build5Db } from '@build-5/database'; -import { - COL, - Collection, - CollectionStatus, - Entity, - MIN_AMOUNT_TO_TRANSFER, - Member, - Network, - Nft, - NftAccess, - Space, - Transaction, - TransactionPayloadType, - TransactionType, - TransactionValidationType, - WenError, -} from '@build-5/interfaces'; -import { assertMemberHasValidAddress, getAddress } from '../../../../utils/address.utils'; -import { getProjects, getRestrictions } from '../../../../utils/common.utils'; -import { isProdEnv } from '../../../../utils/config.utils'; -import { invalidArgument } from '../../../../utils/error.utils'; -import { assertIpNotBlocked } from '../../../../utils/ip.utils'; -import { assertValidationAsync } from '../../../../utils/schema.utils'; -import { getSpace } from '../../../../utils/space.utils'; -import { getRandomEthAddress } from '../../../../utils/wallet.utils'; -import { WalletService } from '../../../wallet/wallet.service'; -import { HandlerParams } from '../../base'; -import { TransactionService } from '../../transaction-service'; -import { nftBidSchema } from './NftBidTangleRequestSchema'; - -export class TangleNftBidService { - constructor(readonly transactionService: TransactionService) {} - - public handleRequest = async ({ - request, - project, - owner, - order: tangleOrder, - tran, - tranEntry, - }: HandlerParams) => { - const params = await assertValidationAsync(nftBidSchema, request); - - const order = await createNftBidOrder(project, params.nft, owner, ''); - order.payload.tanglePuchase = true; - order.payload.disableWithdraw = params.disableWithdraw || false; - - if (tangleOrder.network !== order.network) { - throw invalidArgument(WenError.invalid_network); - } - - this.transactionService.push({ - ref: build5Db().doc(`${COL.TRANSACTION}/${order.uid}`), - data: order, - action: 'set', - }); - - this.transactionService.createUnlockTransaction( - order, - tran, - tranEntry, - TransactionPayloadType.TANGLE_TRANSFER, - tranEntry.outputId, - ); - return; - }; -} - -export const createNftBidOrder = async ( - project: string, - nftId: string, - owner: string, - ip = '', -): Promise => { - const nftDocRef = build5Db().doc(`${COL.NFT}/${nftId}`); - const nft = await nftDocRef.get(); - if (!nft) { - throw invalidArgument(WenError.nft_does_not_exists); - } - - if (isProdEnv()) { - await assertIpNotBlocked(ip, nftId, 'nft'); - } - - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${nft.collection}`); - const collection = (await collectionDocRef.get())!; - - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${collection.space}`); - const space = await spaceDocRef.get(); - - if (!collection.approved) { - throw invalidArgument(WenError.collection_must_be_approved); - } - - if (![CollectionStatus.PRE_MINTED, CollectionStatus.MINTED].includes(collection.status!)) { - throw invalidArgument(WenError.invalid_collection_status); - } - - if (nft.saleAccess === NftAccess.MEMBERS && !(nft.saleAccessMembers || []).includes(owner)) { - throw invalidArgument(WenError.you_are_not_allowed_member_to_purchase_this_nft); - } - - if (!nft.auctionFrom) { - throw invalidArgument(WenError.nft_not_available_for_sale); - } - - if (nft.placeholderNft) { - throw invalidArgument(WenError.nft_placeholder_cant_be_purchased); - } - - if (nft.owner === owner) { - throw invalidArgument(WenError.you_cant_buy_your_nft); - } - - const isProd = isProdEnv(); - const network = nft.mintingData?.network || (isProd ? Network.IOTA : Network.ATOI); - - const prevOwnerDocRef = build5Db().doc(`${COL.MEMBER}/${nft.owner}`); - const prevOwner = await prevOwnerDocRef.get(); - assertMemberHasValidAddress(prevOwner, network); - - const newWallet = await WalletService.newWallet(network); - const targetAddress = await newWallet.getNewIotaAddressDetails(); - const royaltySpace = await getSpace(collection.royaltiesSpace); - - const auctionFloorPrice = nft.auctionFloorPrice || MIN_AMOUNT_TO_TRANSFER; - const finalPrice = Number(Math.max(auctionFloorPrice, MIN_AMOUNT_TO_TRANSFER).toPrecision(2)); - - return { - project, - projects: getProjects([], project), - type: TransactionType.ORDER, - uid: getRandomEthAddress(), - member: owner, - space: collection.space, - network, - payload: { - type: TransactionPayloadType.NFT_BID, - amount: finalPrice, - targetAddress: targetAddress.bech32, - beneficiary: nft.owner ? Entity.MEMBER : Entity.SPACE, - beneficiaryUid: nft.owner || collection.space, - beneficiaryAddress: getAddress(nft.owner ? prevOwner : space, network), - royaltiesFee: collection.royaltiesFee, - royaltiesSpace: collection.royaltiesSpace, - royaltiesSpaceAddress: getAddress(royaltySpace, network), - expiresOn: nft.auctionTo!, - reconciled: false, - validationType: TransactionValidationType.ADDRESS, - void: false, - chainReference: null, - nft: nft.uid, - collection: collection.uid, - restrictions: getRestrictions(collection, nft), - }, - linkedTransactions: [], - }; -}; diff --git a/packages/functions/src/services/payment/tangle-service/nft/nft-set-for-sale.service.ts b/packages/functions/src/services/payment/tangle-service/nft/nft-set-for-sale.service.ts index 2a930eb22c..d44758025c 100644 --- a/packages/functions/src/services/payment/tangle-service/nft/nft-set-for-sale.service.ts +++ b/packages/functions/src/services/payment/tangle-service/nft/nft-set-for-sale.service.ts @@ -1,5 +1,7 @@ import { build5Db } from '@build-5/database'; import { + Auction, + AuctionType, COL, Collection, CollectionStatus, @@ -13,35 +15,47 @@ import { } from '@build-5/interfaces'; import dayjs from 'dayjs'; import { assertMemberHasValidAddress } from '../../../../utils/address.utils'; +import { getProjects } from '../../../../utils/common.utils'; +import { getDefaultNetwork } from '../../../../utils/config.utils'; import { dateToTimestamp } from '../../../../utils/dateTime.utils'; import { invalidArgument } from '../../../../utils/error.utils'; import { assertValidationAsync } from '../../../../utils/schema.utils'; +import { getRandomEthAddress } from '../../../../utils/wallet.utils'; import { BaseService, HandlerParams } from '../../base'; import { setNftForSaleTangleSchema } from './NftSetForSaleTangleRequestSchema'; export class TangleNftSetForSaleService extends BaseService { - public handleRequest = async ({ owner, request }: HandlerParams) => { + public handleRequest = async ({ owner, request, project }: HandlerParams) => { const params = await assertValidationAsync(setNftForSaleTangleSchema, request); const memberDocRef = build5Db().doc(`${COL.MEMBER}/${owner}`); const member = await memberDocRef.get(); - const updateData = await getNftSetForSaleParams(params, member!); + const { nft, auction } = await getNftSetForSaleParams(member!, project, params); const nftDocRef = build5Db().doc(`${COL.NFT}/${params.nft}`); - this.transactionService.push({ ref: nftDocRef, data: updateData, action: 'update' }); + this.transactionService.push({ ref: nftDocRef, data: nft, action: 'update' }); + + if (auction) { + const auctionDocRef = build5Db().doc(`${COL.AUCTION}/${auction.uid}`); + this.transactionService.push({ ref: auctionDocRef, data: auction, action: 'set' }); + } return { status: 'success' }; }; } -export const getNftSetForSaleParams = async (params: NftSetForSaleRequest, owner: Member) => { +export const getNftSetForSaleParams = async ( + owner: Member, + project: string, + params: NftSetForSaleRequest, +) => { const nftDocRef = build5Db().doc(`${COL.NFT}/${params.nft}`); const nft = await nftDocRef.get(); if (!nft) { throw invalidArgument(WenError.nft_does_not_exists); } - if (nft.auctionFrom && dayjs(nft.auctionFrom.toDate()).isBefore(dayjs())) { - throw invalidArgument(WenError.nft_auction_already_in_progress); + if (nft.auction) { + throw invalidArgument(WenError.auction_already_in_progress); } if (nft.setAsAvatar) { @@ -76,7 +90,8 @@ export const getNftSetForSaleParams = async (params: NftSetForSaleRequest, owner throw invalidArgument(WenError.invalid_collection_status); } - return getNftUpdateData(params); + const auction = getAuctionData(project, owner.uid, params, nft); + return { nft: { ...getNftUpdateData(params), auction: auction?.uid || '' }, auction }; }; const getNftUpdateData = (params: NftSetForSaleRequest) => { @@ -123,3 +138,38 @@ const getNftUpdateData = (params: NftSetForSaleRequest) => { } return update; }; + +const getAuctionData = (project: string, owner: string, params: NftSetForSaleRequest, nft: Nft) => { + if (!params.auctionFrom) { + return; + } + const auction: Auction = { + uid: getRandomEthAddress(), + createdBy: owner, + project, + projects: getProjects([], project), + auctionFrom: dateToTimestamp(params.auctionFrom), + auctionTo: dateToTimestamp(dayjs(params.auctionFrom).add(params.auctionLength || 0)), + auctionFloorPrice: params.auctionFloorPrice || 0, + auctionLength: params.auctionLength!, + + bids: [], + maxBids: 1, + type: AuctionType.NFT, + network: nft.mintingData?.network || getDefaultNetwork(), + nftId: nft.uid, + + active: true, + }; + + if (params.extendedAuctionLength) { + return { + ...auction, + extendedAuctionTo: dayjs(params.auctionFrom).add(params.extendedAuctionLength).toDate(), + extendedAuctionLength: params.extendedAuctionLength || 0, + extendAuctionWithin: params.extendAuctionWithin || EXTEND_AUCTION_WITHIN, + }; + } + + return auction; +}; diff --git a/packages/functions/src/services/payment/transaction-service.ts b/packages/functions/src/services/payment/transaction-service.ts index f04a306a08..32e379d2ca 100644 --- a/packages/functions/src/services/payment/transaction-service.ts +++ b/packages/functions/src/services/payment/transaction-service.ts @@ -100,6 +100,9 @@ export class TransactionService { if (order.payload.stamp) { data.payload.stamp = order.payload.stamp; } + if (order.payload.auction) { + data.payload.auction = order.payload.auction; + } if (order.payload.token) { const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${order.payload.token}`); diff --git a/packages/functions/src/utils/config.utils.ts b/packages/functions/src/utils/config.utils.ts index 1400dfd21f..01b4618508 100644 --- a/packages/functions/src/utils/config.utils.ts +++ b/packages/functions/src/utils/config.utils.ts @@ -70,3 +70,5 @@ export const xpTokenUid = () => process.env.XPTOKEN_UID!; export const xpTokenGuardianId = () => process.env.XPTOKEN_GUARDIANID!; export const getStampRoyaltyAddress = (network: Network) => STAMP_ROYALTY_ADDRESS[network]; + +export const getDefaultNetwork = () => (isProdEnv() ? Network.IOTA : Network.ATOI); diff --git a/packages/functions/test-tangle/auction-tangle/auction.bit.tangle.spec.ts b/packages/functions/test-tangle/auction-tangle/auction.bit.tangle.spec.ts new file mode 100644 index 0000000000..dd5a9eabb2 --- /dev/null +++ b/packages/functions/test-tangle/auction-tangle/auction.bit.tangle.spec.ts @@ -0,0 +1,127 @@ +import { IDocument, build5Db } from '@build-5/database'; +import { + Auction, + AuctionType, + COL, + MIN_IOTA_AMOUNT, + Member, + Network, + TangleRequestType, + Transaction, + TransactionType, +} from '@build-5/interfaces'; +import dayjs from 'dayjs'; +import { MnemonicService } from '../../src/services/wallet/mnemonic'; +import { Wallet } from '../../src/services/wallet/wallet'; +import { AddressDetails } from '../../src/services/wallet/wallet.service'; +import { getAddress } from '../../src/utils/address.utils'; +import * as wallet from '../../src/utils/wallet.utils'; +import { createMember, wait } from '../../test/controls/common'; +import { getWallet } from '../../test/set-up'; +import { getTangleOrder } from '../common'; +import { requestFundsFromFaucet } from '../faucet'; + +let walletSpy: any; + +describe('Auction tangle test', () => { + let member: string; + let memberAddress: AddressDetails; + let w: Wallet; + let tangleOrder: Transaction; + let auctionDocRef: IDocument; + const now = dayjs(); + let auction: Auction; + + beforeAll(async () => { + walletSpy = jest.spyOn(wallet, 'decodeAuth'); + w = await getWallet(Network.RMS); + tangleOrder = await getTangleOrder(Network.RMS); + }); + + beforeEach(async () => { + member = await createMember(walletSpy); + + const memberDocRef = build5Db().doc(`${COL.MEMBER}/${member}`); + const memberData = await memberDocRef.get(); + const bech32 = getAddress(memberData, Network.RMS); + memberAddress = await w.getAddressDetails(bech32); + + await requestFundsFromFaucet(Network.RMS, memberAddress.bech32, 5 * MIN_IOTA_AMOUNT); + await w.send(memberAddress, tangleOrder.payload.targetAddress!, 5 * MIN_IOTA_AMOUNT, { + customMetadata: { + request: { + requestType: TangleRequestType.CREATE_AUCTION, + ...auctionRequest(now), + }, + }, + }); + await MnemonicService.store(bech32, memberAddress.mnemonic); + + const creaditQuery = build5Db() + .collection(COL.TRANSACTION) + .where('member', '==', member) + .where('type', '==', TransactionType.CREDIT_TANGLE_REQUEST); + await wait(async () => { + const credits = await creaditQuery.get(); + return credits.length === 1 && credits[0].payload.walletReference?.confirmed; + }); + + const credits = await creaditQuery.get(); + expect(credits[0].payload.response?.auction).toBeDefined(); + + auctionDocRef = build5Db().doc(`${COL.AUCTION}/${credits[0].payload.response?.auction}`); + auction = await auctionDocRef.get(); + }); + + it('Should bid on auction', async () => { + expect(dayjs(auction.auctionFrom.toDate()).isSame(now)).toBe(true); + expect(dayjs(auction.auctionTo.toDate()).isSame(now.add(60000 * 4))); + expect(auction.auctionLength).toBe(60000 * 4); + + expect(dayjs(auction.extendedAuctionTo?.toDate()).isSame(now.add(60000 * 4 + 6000))).toBe(true); + expect(auction.extendedAuctionLength).toBe(60000 * 4 + 6000); + expect(auction.extendAuctionWithin).toBe(60000 * 4); + + expect(auction.auctionFloorPrice).toBe(2 * MIN_IOTA_AMOUNT); + expect(auction.maxBids).toBe(2); + expect(auction.type).toBe(AuctionType.OPEN); + expect(auction.network).toBe(Network.RMS); + expect(auction.nftId).toBeUndefined(); + expect(auction.active).toBe(true); + expect(auction.topUpBased).toBe(true); + }); + + it('Should bid on auction', async () => { + const block = await w.send( + memberAddress, + tangleOrder.payload.targetAddress!, + 2 * MIN_IOTA_AMOUNT, + { + customMetadata: { + request: { + requestType: TangleRequestType.BID_AUCTION, + auction: auction.uid, + }, + }, + }, + ); + console.log(block); + await wait(async () => { + auction = await auctionDocRef.get(); + return auction.auctionHighestBidder === member; + }); + + expect(auction.auctionHighestBid).toBe(2 * MIN_IOTA_AMOUNT); + }); +}); + +const auctionRequest = (now: dayjs.Dayjs, auctionLength = 60000 * 4) => ({ + auctionFrom: now.toDate(), + auctionFloorPrice: 2 * MIN_IOTA_AMOUNT, + auctionLength, + extendedAuctionLength: auctionLength + 6000, + extendAuctionWithin: 60000 * 4, + maxBids: 2, + network: Network.RMS, + topUpBased: true, +}); diff --git a/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_1.spec.ts b/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_1.spec.ts index 7c07255739..8f398471d4 100644 --- a/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_1.spec.ts +++ b/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_1.spec.ts @@ -13,9 +13,8 @@ import { import { NftOutput } from '@iota/sdk'; import dayjs from 'dayjs'; import { isEmpty } from 'lodash'; -import { finalizeAllNftAuctions } from '../../src/cron/nft.cron'; -import { openBid } from '../../src/runtime/firebase/nft'; -import { withdrawNft } from '../../src/runtime/firebase/nft/index'; +import { finalizeAuctions } from '../../src/cron/auction.cron'; +import { openBid, withdrawNft } from '../../src/runtime/firebase/nft/index'; import { getAddress } from '../../src/utils/address.utils'; import { Bech32AddressHelper } from '../../src/utils/bech32-address.helper'; import { dateToTimestamp } from '../../src/utils/dateTime.utils'; @@ -27,94 +26,90 @@ import { Helper } from './Helper'; describe('Minted nft trading', () => { const helper = new Helper(); - it.each([false, true])( - 'Should bid twice on minted nft and withdraw it', - async (hasExpiration: boolean) => { - await helper.beforeEach(Network.RMS); - await helper.createAndOrderNft(); - await helper.mintCollection(); - - await helper.setAvailableForAuction(); - - mockWalletReturnValue(helper.walletSpy, helper.member!, { nft: helper.nft!.uid }); - await expectThrow(testEnv.wrap(withdrawNft)({}), WenError.you_must_be_the_owner_of_nft.key); - - const expiresAt = hasExpiration ? dateToTimestamp(dayjs().add(2, 'h').toDate()) : undefined; - - mockWalletReturnValue(helper.walletSpy, helper.member!, { nft: helper.nft!.uid }); - const bidOrder = await testEnv.wrap(openBid)({}); - await requestFundsFromFaucet( - Network.RMS, - bidOrder.payload.targetAddress, - MIN_IOTA_AMOUNT, - expiresAt, - ); - - await wait(async () => { - const nft = await build5Db().doc(`${COL.NFT}/${helper.nft!.uid}`).get(); - return !isEmpty(nft.auctionHighestTransaction); - }); - - const bidOrder2 = await testEnv.wrap(openBid)({}); - await requestFundsFromFaucet( - Network.RMS, - bidOrder2.payload.targetAddress, - 2 * MIN_IOTA_AMOUNT, - expiresAt, - ); - - await wait(async () => { - const nft = await build5Db().doc(`${COL.NFT}/${helper.nft!.uid}`).get(); - - const payment = ( - await build5Db() - .collection(COL.TRANSACTION) - .where('type', '==', TransactionType.PAYMENT) - .where('payload.sourceTransaction', 'array-contains', bidOrder2.uid) - .get() - )[0]; - return nft.auctionHighestTransaction === payment?.uid; - }); - - await build5Db() - .doc(`${COL.NFT}/${helper.nft!.uid}`) - .update({ auctionTo: dateToTimestamp(dayjs().subtract(1, 'm').toDate()) }); - - await finalizeAllNftAuctions(); - - await wait(async () => { - const nft = await build5Db().doc(`${COL.NFT}/${helper.nft!.uid}`).get(); - return nft.owner === helper.member; - }); - - mockWalletReturnValue(helper.walletSpy, helper.member!, { nft: helper.nft!.uid }); - await testEnv.wrap(withdrawNft)({}); - - const nft = await build5Db().doc(`${COL.NFT}/${helper.nft!.uid}`).get(); - expect(nft.status).toBe(NftStatus.WITHDRAWN); - - await wait(async () => { - const transaction = ( - await build5Db() - .collection(COL.TRANSACTION) - .where('type', '==', TransactionType.WITHDRAW_NFT) - .where('payload.nft', '==', helper.nft!.uid) - .get() - )[0]; - return transaction?.payload?.walletReference?.confirmed; - }); - - const output = ( - await helper.walletService!.client.getOutput( - await helper.walletService!.client.nftOutputId(nft.mintingData?.nftId!), - ) - ).output; - const ownerAddress = Bech32AddressHelper.bech32FromUnlockConditions( - output as NftOutput, - 'rms', - ); - const member = await build5Db().doc(`${COL.MEMBER}/${helper.member}`).get(); - expect(ownerAddress).toBe(getAddress(member, Network.RMS)); - }, - ); + it('Should bid twice on minted nft and withdraw it', async () => { + await helper.beforeEach(Network.RMS); + await helper.createAndOrderNft(); + await helper.mintCollection(); + + await helper.setAvailableForAuction(); + + const nftDocRef = build5Db().doc(`${COL.NFT}/${helper.nft!.uid}`); + + mockWalletReturnValue(helper.walletSpy, helper.member!, { nft: helper.nft!.uid }); + await expectThrow(testEnv.wrap(withdrawNft)({}), WenError.you_must_be_the_owner_of_nft.key); + + const expiresAt = dateToTimestamp(dayjs().add(2, 'h').toDate()); + + mockWalletReturnValue(helper.walletSpy, helper.member!, { nft: helper.nft!.uid }); + const bidOrder = await testEnv.wrap(openBid)({}); + await requestFundsFromFaucet( + Network.RMS, + bidOrder.payload.targetAddress, + MIN_IOTA_AMOUNT, + expiresAt, + ); + + await wait(async () => { + helper.nft = await nftDocRef.get(); + return !isEmpty(helper.nft.auctionHighestBidder); + }); + + const bidOrder2 = await testEnv.wrap(openBid)({}); + await requestFundsFromFaucet( + Network.RMS, + bidOrder2.payload.targetAddress, + 2 * MIN_IOTA_AMOUNT, + expiresAt, + ); + + await wait(async () => { + const nft = await nftDocRef.get(); + + const payment = ( + await build5Db() + .collection(COL.TRANSACTION) + .where('type', '==', TransactionType.PAYMENT) + .where('payload.sourceTransaction', 'array-contains', bidOrder2.uid) + .get() + )[0]; + return nft.auctionHighestBidder === payment?.member; + }); + + await build5Db() + .doc(`${COL.AUCTION}/${helper.nft!.auction}`) + .update({ auctionTo: dateToTimestamp(dayjs().subtract(1, 'm').toDate()) }); + + await finalizeAuctions(); + + await wait(async () => { + const nft = await nftDocRef.get(); + return nft.owner === helper.member; + }); + + mockWalletReturnValue(helper.walletSpy, helper.member!, { nft: helper.nft!.uid }); + await testEnv.wrap(withdrawNft)({}); + + helper.nft = await nftDocRef.get(); + expect(helper.nft.status).toBe(NftStatus.WITHDRAWN); + + await wait(async () => { + const transaction = ( + await build5Db() + .collection(COL.TRANSACTION) + .where('type', '==', TransactionType.WITHDRAW_NFT) + .where('payload.nft', '==', helper.nft!.uid) + .get() + )[0]; + return transaction?.payload?.walletReference?.confirmed; + }); + + const output = ( + await helper.walletService!.client.getOutput( + await helper.walletService!.client.nftOutputId(helper.nft.mintingData?.nftId!), + ) + ).output; + const ownerAddress = Bech32AddressHelper.bech32FromUnlockConditions(output as NftOutput, 'rms'); + const member = await build5Db().doc(`${COL.MEMBER}/${helper.member}`).get(); + expect(ownerAddress).toBe(getAddress(member, Network.RMS)); + }); }); diff --git a/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_1_b.spec.ts b/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_1_b.spec.ts index 39640ac8dd..914d625d6e 100644 --- a/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_1_b.spec.ts +++ b/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_1_b.spec.ts @@ -13,9 +13,8 @@ import { import { NftOutput } from '@iota/sdk'; import dayjs from 'dayjs'; import { isEmpty } from 'lodash'; -import { finalizeAllNftAuctions } from '../../src/cron/nft.cron'; -import { openBid } from '../../src/runtime/firebase/nft'; -import { withdrawNft } from '../../src/runtime/firebase/nft/index'; +import { finalizeAuctions } from '../../src/cron/auction.cron'; +import { openBid, withdrawNft } from '../../src/runtime/firebase/nft/index'; import { getAddress } from '../../src/utils/address.utils'; import { Bech32AddressHelper } from '../../src/utils/bech32-address.helper'; import { dateToTimestamp } from '../../src/utils/dateTime.utils'; @@ -27,91 +26,78 @@ import { Helper } from './Helper'; describe('Minted nft trading', () => { const helper = new Helper(); - it.each([false])( - 'Should bid twice on minted nft and withdraw it', - async (hasExpiration: boolean) => { - await helper.beforeEach(Network.ATOI); - await helper.createAndOrderNft(); - await helper.mintCollection(); - - await helper.setAvailableForAuction(); - - mockWalletReturnValue(helper.walletSpy, helper.member!, { nft: helper.nft!.uid }); - await expectThrow(testEnv.wrap(withdrawNft)({}), WenError.you_must_be_the_owner_of_nft.key); - - const expiresAt = hasExpiration ? dateToTimestamp(dayjs().add(2, 'h').toDate()) : undefined; - - mockWalletReturnValue(helper.walletSpy, helper.member!, { nft: helper.nft!.uid }); - const bidOrder = await testEnv.wrap(openBid)({}); - await requestFundsFromFaucet( - Network.RMS, - bidOrder.payload.targetAddress, - MIN_IOTA_AMOUNT, - expiresAt, - ); - - await wait(async () => { - const nft = await build5Db().doc(`${COL.NFT}/${helper.nft!.uid}`).get(); - return !isEmpty(nft.auctionHighestTransaction); - }); - - const bidOrder2 = await testEnv.wrap(openBid)({}); - await requestFundsFromFaucet( - Network.RMS, - bidOrder2.payload.targetAddress, - 2 * MIN_IOTA_AMOUNT, - expiresAt, - ); - - await wait(async () => { - const nft = await build5Db().doc(`${COL.NFT}/${helper.nft!.uid}`).get(); - - const payment = ( - await build5Db() - .collection(COL.TRANSACTION) - .where('type', '==', TransactionType.PAYMENT) - .where('payload.sourceTransaction', 'array-contains', bidOrder2.uid) - .get() - )[0]; - return nft.auctionHighestTransaction === payment?.uid; - }); - - await build5Db() - .doc(`${COL.NFT}/${helper.nft!.uid}`) - .update({ auctionTo: dateToTimestamp(dayjs().subtract(1, 'm').toDate()) }); - - await finalizeAllNftAuctions(); - - await wait(async () => { - const nft = await build5Db().doc(`${COL.NFT}/${helper.nft!.uid}`).get(); - return nft.owner === helper.member; - }); - - mockWalletReturnValue(helper.walletSpy, helper.member!, { nft: helper.nft!.uid }); - await testEnv.wrap(withdrawNft)({}); - - const nft = await build5Db().doc(`${COL.NFT}/${helper.nft!.uid}`).get(); - expect(nft.status).toBe(NftStatus.WITHDRAWN); - - await wait(async () => { - const transaction = ( - await build5Db() - .collection(COL.TRANSACTION) - .where('type', '==', TransactionType.WITHDRAW_NFT) - .where('payload.nft', '==', helper.nft!.uid) - .get() - )[0]; - return transaction?.payload?.walletReference?.confirmed; - }); - - const output = ( - await helper.walletService!.client.getOutput( - await helper.walletService!.client.nftOutputId(nft.mintingData?.nftId!), - ) - ).output as NftOutput; - const ownerAddress = Bech32AddressHelper.bech32FromUnlockConditions(output, 'rms'); - const member = await build5Db().doc(`${COL.MEMBER}/${helper.member}`).get(); - expect(ownerAddress).toBe(getAddress(member, Network.ATOI)); - }, - ); + it('Should bid twice on minted nft and withdraw it', async () => { + await helper.beforeEach(Network.ATOI); + await helper.createAndOrderNft(); + await helper.mintCollection(); + + await helper.setAvailableForAuction(); + + const nftDocRef = build5Db().doc(`${COL.NFT}/${helper.nft!.uid}`); + + mockWalletReturnValue(helper.walletSpy, helper.member!, { nft: helper.nft!.uid }); + await expectThrow(testEnv.wrap(withdrawNft)({}), WenError.you_must_be_the_owner_of_nft.key); + + mockWalletReturnValue(helper.walletSpy, helper.member!, { nft: helper.nft!.uid }); + const bidOrder = await testEnv.wrap(openBid)({}); + await requestFundsFromFaucet(Network.RMS, bidOrder.payload.targetAddress, MIN_IOTA_AMOUNT); + + await wait(async () => { + helper.nft = await nftDocRef.get(); + return !isEmpty(helper.nft.auctionHighestBidder); + }); + + const bidOrder2 = await testEnv.wrap(openBid)({}); + await requestFundsFromFaucet(Network.RMS, bidOrder2.payload.targetAddress, 2 * MIN_IOTA_AMOUNT); + + await wait(async () => { + helper.nft = await nftDocRef.get(); + + const payment = ( + await build5Db() + .collection(COL.TRANSACTION) + .where('type', '==', TransactionType.PAYMENT) + .where('payload.sourceTransaction', 'array-contains', bidOrder2.uid) + .get() + )[0]; + return helper.nft.auctionHighestBidder === payment?.member; + }); + + await build5Db() + .doc(`${COL.AUCTION}/${helper.nft!.auction}`) + .update({ auctionTo: dateToTimestamp(dayjs().subtract(1, 'm').toDate()) }); + + await finalizeAuctions(); + + await wait(async () => { + const nft = await nftDocRef.get(); + return nft.owner === helper.member; + }); + + mockWalletReturnValue(helper.walletSpy, helper.member!, { nft: helper.nft!.uid }); + await testEnv.wrap(withdrawNft)({}); + + helper.nft = await nftDocRef.get(); + expect(helper.nft.status).toBe(NftStatus.WITHDRAWN); + + await wait(async () => { + const transaction = ( + await build5Db() + .collection(COL.TRANSACTION) + .where('type', '==', TransactionType.WITHDRAW_NFT) + .where('payload.nft', '==', helper.nft!.uid) + .get() + )[0]; + return transaction?.payload?.walletReference?.confirmed; + }); + + const output = ( + await helper.walletService!.client.getOutput( + await helper.walletService!.client.nftOutputId(helper.nft.mintingData?.nftId!), + ) + ).output as NftOutput; + const ownerAddress = Bech32AddressHelper.bech32FromUnlockConditions(output, 'rms'); + const member = await build5Db().doc(`${COL.MEMBER}/${helper.member}`).get(); + expect(ownerAddress).toBe(getAddress(member, Network.ATOI)); + }); }); diff --git a/packages/functions/test-tangle/nft-bid/Helper.ts b/packages/functions/test-tangle/nft-bid/Helper.ts index ca84da1980..d22950fc44 100644 --- a/packages/functions/test-tangle/nft-bid/Helper.ts +++ b/packages/functions/test-tangle/nft-bid/Helper.ts @@ -126,7 +126,11 @@ export class Helper { const uid = nft || this.nft?.uid!; mockWalletReturnValue(this.walletSpy, this.guardian!, this.dummyAuctionData(uid)); await testEnv.wrap(setForSaleNft)({}); - await wait(async () => (await build5Db().doc(`${COL.NFT}/${uid}`).get())?.available === 3); + await wait(async () => { + const docRef = build5Db().doc(`${COL.NFT}/${uid}`); + this.nft = await docRef.get(); + return this.nft.available === 3; + }); }; public setAvailableForSale = async () => { diff --git a/packages/functions/test-tangle/nft-bid/nft-bid.otr_1.spec.ts b/packages/functions/test-tangle/nft-bid/nft-bid.otr_1.spec.ts index b38e75a74f..9c7f4e55d1 100644 --- a/packages/functions/test-tangle/nft-bid/nft-bid.otr_1.spec.ts +++ b/packages/functions/test-tangle/nft-bid/nft-bid.otr_1.spec.ts @@ -12,7 +12,7 @@ import { import { NftOutput } from '@iota/sdk'; import dayjs from 'dayjs'; import { isEmpty } from 'lodash'; -import { finalizeAllNftAuctions } from '../../src/cron/nft.cron'; +import { finalizeAuctions } from '../../src/cron/auction.cron'; import { Bech32AddressHelper } from '../../src/utils/bech32-address.helper'; import { dateToTimestamp } from '../../src/utils/dateTime.utils'; import { wait } from '../../test/controls/common'; @@ -53,14 +53,14 @@ describe('Nft otr bid', () => { const nftDocRef = build5Db().doc(`${COL.NFT}/${helper.nft!.uid}`); await wait(async () => { const nft = await nftDocRef.get(); - return !isEmpty(nft?.auctionHighestTransaction); + return !isEmpty(nft?.auctionHighestBidder); }); await build5Db() - .doc(`${COL.NFT}/${helper.nft!.uid}`) + .doc(`${COL.AUCTION}/${helper.nft!.auction}`) .update({ auctionTo: dateToTimestamp(dayjs().subtract(1, 'm').toDate()) }); - await finalizeAllNftAuctions(); + await finalizeAuctions(); await wait(async () => { const transaction = ( diff --git a/packages/functions/test-tangle/nft-bid/nft-bid.otr_2.spec.ts b/packages/functions/test-tangle/nft-bid/nft-bid.otr_2.spec.ts index 8dc5d0e5ce..fc3ff949dc 100644 --- a/packages/functions/test-tangle/nft-bid/nft-bid.otr_2.spec.ts +++ b/packages/functions/test-tangle/nft-bid/nft-bid.otr_2.spec.ts @@ -10,7 +10,7 @@ import { } from '@build-5/interfaces'; import dayjs from 'dayjs'; import { isEmpty } from 'lodash'; -import { finalizeAllNftAuctions } from '../../src/cron/nft.cron'; +import { finalizeAuctions } from '../../src/cron/auction.cron'; import { dateToTimestamp } from '../../src/utils/dateTime.utils'; import { wait } from '../../test/controls/common'; import { getTangleOrder } from '../common'; @@ -51,14 +51,14 @@ describe('Nft otr bid', () => { const nftDocRef = build5Db().doc(`${COL.NFT}/${helper.nft!.uid}`); await wait(async () => { const nft = await nftDocRef.get(); - return !isEmpty(nft?.auctionHighestTransaction); + return !isEmpty(nft?.auctionHighestBidder); }); await build5Db() - .doc(`${COL.NFT}/${helper.nft!.uid}`) + .doc(`${COL.AUCTION}/${helper.nft!.auction}`) .update({ auctionTo: dateToTimestamp(dayjs().subtract(1, 'm').toDate()) }); - await finalizeAllNftAuctions(); + await finalizeAuctions(); await wait(async () => { const nft = await build5Db().doc(`${COL.NFT}/${helper.nft!.uid}`).get(); diff --git a/packages/functions/test-tangle/nft-bid/nft-bid.otr_3.spec.ts b/packages/functions/test-tangle/nft-bid/nft-bid.otr_3.spec.ts index 33eeecf52d..c499b3abb8 100644 --- a/packages/functions/test-tangle/nft-bid/nft-bid.otr_3.spec.ts +++ b/packages/functions/test-tangle/nft-bid/nft-bid.otr_3.spec.ts @@ -10,7 +10,7 @@ import { } from '@build-5/interfaces'; import dayjs from 'dayjs'; import { isEmpty } from 'lodash'; -import { finalizeAllNftAuctions } from '../../src/cron/nft.cron'; +import { finalizeAuctions } from '../../src/cron/auction.cron'; import { IotaWallet } from '../../src/services/wallet/IotaWalletService'; import { MnemonicService } from '../../src/services/wallet/mnemonic'; import { dateToTimestamp } from '../../src/utils/dateTime.utils'; @@ -53,14 +53,14 @@ describe('Nft otr bid', () => { const nftDocRef = build5Db().doc(`${COL.NFT}/${helper.nft!.uid}`); await wait(async () => { const nft = await nftDocRef.get(); - return !isEmpty(nft?.auctionHighestTransaction); + return !isEmpty(nft?.auctionHighestBidder); }); await build5Db() - .doc(`${COL.NFT}/${helper.nft!.uid}`) + .doc(`${COL.AUCTION}/${helper.nft!.auction}`) .update({ auctionTo: dateToTimestamp(dayjs().subtract(1, 'm').toDate()) }); - await finalizeAllNftAuctions(); + await finalizeAuctions(); await wait(async () => { const nft = await build5Db().doc(`${COL.NFT}/${helper.nft!.uid}`).get(); diff --git a/packages/functions/test-tangle/nft-bid/nft-bid.otr_4.spec.ts b/packages/functions/test-tangle/nft-bid/nft-bid.otr_4.spec.ts index 75485ce515..ce1568f1fa 100644 --- a/packages/functions/test-tangle/nft-bid/nft-bid.otr_4.spec.ts +++ b/packages/functions/test-tangle/nft-bid/nft-bid.otr_4.spec.ts @@ -10,7 +10,7 @@ import { TransactionType, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { finalizeAllNftAuctions } from '../../src/cron/nft.cron'; +import { finalizeAuctions } from '../../src/cron/auction.cron'; import { dateToTimestamp } from '../../src/utils/dateTime.utils'; import { wait } from '../../test/controls/common'; import { getTangleOrder } from '../common'; @@ -67,10 +67,10 @@ describe('Nft otr bid', () => { }); await build5Db() - .doc(`${COL.NFT}/${helper.nft!.uid}`) + .doc(`${COL.AUCTION}/${helper.nft!.auction}`) .update({ auctionTo: dateToTimestamp(dayjs().subtract(1, 'm').toDate()) }); - await finalizeAllNftAuctions(); + await finalizeAuctions(); await wait(async () => { const nft = await build5Db().doc(`${COL.NFT}/${helper.nft!.uid}`).get(); diff --git a/packages/functions/test-tangle/nft-set-for-sale/nft-set-for-sale_3.spec.ts b/packages/functions/test-tangle/nft-set-for-sale/nft-set-for-sale_3.spec.ts index ee6c5fa6d2..d8fc349809 100644 --- a/packages/functions/test-tangle/nft-set-for-sale/nft-set-for-sale_3.spec.ts +++ b/packages/functions/test-tangle/nft-set-for-sale/nft-set-for-sale_3.spec.ts @@ -112,7 +112,7 @@ describe('Nft set for acution OTR', () => { }); const snap = await credit.get(); const creditTransction = snap.find( - (t) => t.payload.response?.code === WenError.nft_auction_already_in_progress.code, + (t) => t.payload.response?.code === WenError.auction_already_in_progress.code, ); expect(creditTransction).toBeDefined(); }); diff --git a/packages/functions/test/controls/auction/Helper.ts b/packages/functions/test/controls/auction/Helper.ts new file mode 100644 index 0000000000..b5ff5c1c00 --- /dev/null +++ b/packages/functions/test/controls/auction/Helper.ts @@ -0,0 +1,47 @@ +import { IDocument, build5Db } from '@build-5/database'; +import { Auction, COL, MIN_IOTA_AMOUNT, Network } from '@build-5/interfaces'; +import dayjs from 'dayjs'; +import { auctionCreate, bidAuction } from '../../../src/runtime/firebase/auction/index'; +import * as wallet from '../../../src/utils/wallet.utils'; +import { testEnv } from '../../set-up'; +import { createMember, mockWalletReturnValue, submitMilestoneFunc } from '../common'; + +export class Helper { + public spy: any = {} as any; + public member: string = {} as any; + public members: string[] = []; + public auction: Auction = {} as any; + public auctionDocRef: IDocument = {} as any; + + public beforeAll = async () => { + this.spy = jest.spyOn(wallet, 'decodeAuth'); + }; + + public beforeEach = async (now: dayjs.Dayjs) => { + this.member = await createMember(this.spy); + const memberPromises = Array.from(Array(3)).map(() => createMember(this.spy)); + this.members = await Promise.all(memberPromises); + + mockWalletReturnValue(this.spy, this.member, auctionRequest(now)); + this.auction = await testEnv.wrap(auctionCreate)({}); + this.auctionDocRef = build5Db().doc(`${COL.AUCTION}/${this.auction.uid}`); + }; + + public bidOnAuction = async (memberId: string, amount: number) => { + mockWalletReturnValue(this.spy, memberId, { auction: this.auction.uid }); + const bidOrder = await testEnv.wrap(bidAuction)({}); + await submitMilestoneFunc(bidOrder, amount); + return bidOrder; + }; +} + +const auctionRequest = (now: dayjs.Dayjs, auctionLength = 60000 * 4) => ({ + auctionFrom: now.toDate(), + auctionFloorPrice: 2 * MIN_IOTA_AMOUNT, + auctionLength, + extendedAuctionLength: auctionLength + 6000, + extendAuctionWithin: 60000 * 4, + maxBids: 2, + network: Network.RMS, + topUpBased: true, +}); diff --git a/packages/functions/test/controls/auction/auction.bid.spec.ts b/packages/functions/test/controls/auction/auction.bid.spec.ts new file mode 100644 index 0000000000..5526557426 --- /dev/null +++ b/packages/functions/test/controls/auction/auction.bid.spec.ts @@ -0,0 +1,91 @@ +import { build5Db } from '@build-5/database'; +import { + Auction, + AuctionType, + COL, + MIN_IOTA_AMOUNT, + Network, + Transaction, + TransactionType, +} from '@build-5/interfaces'; +import dayjs from 'dayjs'; +import { finalizeAuctions } from '../../../src/cron/auction.cron'; +import { dateToTimestamp } from '../../../src/utils/dateTime.utils'; +import { Helper } from './Helper'; + +describe('Open auction bid', () => { + const h = new Helper(); + const now = dayjs(); + + beforeAll(async () => { + await h.beforeAll(); + }); + + beforeEach(async () => { + await h.beforeEach(now); + }); + + it('Should create auction', async () => { + expect(dayjs(h.auction.auctionFrom.toDate()).isSame(now)).toBe(true); + expect(dayjs(h.auction.auctionTo.toDate()).isSame(now.add(60000 * 4))); + expect(h.auction.auctionLength).toBe(60000 * 4); + + expect(dayjs(h.auction.extendedAuctionTo?.toDate()).isSame(now.add(60000 * 4 + 6000))).toBe( + true, + ); + expect(h.auction.extendedAuctionLength).toBe(60000 * 4 + 6000); + expect(h.auction.extendAuctionWithin).toBe(60000 * 4); + + expect(h.auction.auctionFloorPrice).toBe(2 * MIN_IOTA_AMOUNT); + expect(h.auction.maxBids).toBe(2); + expect(h.auction.type).toBe(AuctionType.OPEN); + expect(h.auction.network).toBe(Network.RMS); + expect(h.auction.nftId).toBeUndefined(); + expect(h.auction.active).toBe(true); + expect(h.auction.topUpBased).toBe(true); + }); + + it('Should bid on auction', async () => { + await h.bidOnAuction(h.members[0], 2 * MIN_IOTA_AMOUNT); + await h.bidOnAuction(h.members[1], 3 * MIN_IOTA_AMOUNT); + await h.bidOnAuction(h.members[0], 2 * MIN_IOTA_AMOUNT); + + h.auction = await h.auctionDocRef.get(); + expect(h.auction.bids.length).toBe(2); + expect(h.auction.bids[0].amount).toBe(4 * MIN_IOTA_AMOUNT); + expect(h.auction.bids[0].bidder).toBe(h.members[0]); + expect(h.auction.bids[1].amount).toBe(3 * MIN_IOTA_AMOUNT); + expect(h.auction.bids[1].bidder).toBe(h.members[1]); + + expect(h.auction.auctionHighestBidder).toBe(h.members[0]); + expect(h.auction.auctionHighestBid).toBe(4 * MIN_IOTA_AMOUNT); + + await h.bidOnAuction(h.members[2], 5 * MIN_IOTA_AMOUNT); + + h.auction = await h.auctionDocRef.get(); + expect(h.auction.bids.length).toBe(2); + expect(h.auction.bids[0].amount).toBe(5 * MIN_IOTA_AMOUNT); + expect(h.auction.bids[0].bidder).toBe(h.members[2]); + expect(h.auction.bids[1].amount).toBe(4 * MIN_IOTA_AMOUNT); + expect(h.auction.bids[1].bidder).toBe(h.members[0]); + expect(h.auction.auctionHighestBidder).toBe(h.members[2]); + expect(h.auction.auctionHighestBid).toBe(5 * MIN_IOTA_AMOUNT); + + const credits = await build5Db() + .collection(COL.TRANSACTION) + .where('member', 'in', h.members) + .where('type', '==', TransactionType.CREDIT) + .get(); + expect(credits.length).toBe(1); + expect(credits[0].member).toBe(h.members[1]); + }); + + it('Should finalize auction', async () => { + await h.bidOnAuction(h.members[0], 2 * MIN_IOTA_AMOUNT); + + const auctionDocRef = build5Db().doc(`${COL.AUCTION}/${h.auction.uid}`); + await auctionDocRef.update({ auctionTo: dateToTimestamp(dayjs().subtract(1, 'minute')) }); + + await finalizeAuctions(); + }); +}); diff --git a/packages/functions/test/controls/nft-bidding.spec.ts b/packages/functions/test/controls/nft-bidding.spec.ts deleted file mode 100644 index 4157006f32..0000000000 --- a/packages/functions/test/controls/nft-bidding.spec.ts +++ /dev/null @@ -1,513 +0,0 @@ -import { build5Db, IDocument } from '@build-5/database'; -import { - Access, - Categories, - COL, - Collection, - CollectionType, - MIN_IOTA_AMOUNT, - NetworkAddress, - Nft, - NftAccess, - NftAvailable, - NotificationType, - Space, - Transaction, - TransactionPayloadType, - TransactionType, - TransactionValidationType, - WenError, -} from '@build-5/interfaces'; -import dayjs from 'dayjs'; -import { set } from 'lodash'; -import { finalizeAllNftAuctions } from '../../src/cron/nft.cron'; -import { approveCollection, createCollection } from '../../src/runtime/firebase/collection/index'; -import { openBid } from '../../src/runtime/firebase/nft'; -import { createNft, orderNft, setForSaleNft } from '../../src/runtime/firebase/nft/index'; -import { dateToTimestamp } from '../../src/utils/dateTime.utils'; -import * as wallet from '../../src/utils/wallet.utils'; -import { MEDIA, testEnv } from '../set-up'; -import { - createMember, - createSpace, - expectThrow, - mockWalletReturnValue, - submitMilestoneFunc, - wait, -} from './common'; - -let walletSpy: any; - -const dummyNft = (collection: string, description = 'babba') => ({ - name: 'Collection A', - description, - collection, - availableFrom: dayjs().toDate(), - price: 10 * 1000 * 1000, -}); - -const submitOrderFunc = async (address: NetworkAddress, params: T) => { - mockWalletReturnValue(walletSpy, address, params); - return await testEnv.wrap(orderNft)({}); -}; - -const dummyAuctionData = (uid: string, auctionLength = 60000 * 4, from: dayjs.Dayjs = dayjs()) => ({ - nft: uid, - price: MIN_IOTA_AMOUNT, - availableFrom: from.toDate(), - auctionFrom: from.toDate(), - auctionFloorPrice: MIN_IOTA_AMOUNT, - auctionLength, - access: NftAccess.OPEN, -}); - -const dummySaleData = (uid: string) => ({ - nft: uid, - price: MIN_IOTA_AMOUNT, - availableFrom: dayjs().toDate(), - access: NftAccess.OPEN, -}); - -const bidNft = async (memberId: string, amount: number) => { - mockWalletReturnValue(walletSpy, memberId, { nft: nft.uid }); - const bidOrder = await testEnv.wrap(openBid)({}); - await submitMilestoneFunc(bidOrder, amount); - return bidOrder; -}; - -let memberAddress: NetworkAddress; -let members: string[]; -let space: Space; -let collection: Collection; -let nft: any; - -beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - memberAddress = await createMember(walletSpy); - const memberPromises = Array.from(Array(3)).map(() => createMember(walletSpy)); - members = await Promise.all(memberPromises); - space = await createSpace(walletSpy, memberAddress); - - mockWalletReturnValue(walletSpy, memberAddress, { - name: 'Collection A', - description: 'babba', - type: CollectionType.CLASSIC, - royaltiesFee: 0.6, - category: Categories.ART, - access: Access.OPEN, - space: space.uid, - royaltiesSpace: space.uid, - onePerMemberOnly: false, - availableFrom: dayjs().toDate(), - price: 10 * 1000 * 1000, - }); - - collection = await testEnv.wrap(createCollection)({}); - mockWalletReturnValue(walletSpy, memberAddress, { uid: collection.uid }); - await testEnv.wrap(approveCollection)({}); - - mockWalletReturnValue(walletSpy, memberAddress, { media: MEDIA, ...dummyNft(collection.uid) }); - nft = await testEnv.wrap(createNft)({}); - - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${collection.uid}`); - await wait(async () => { - collection = await collectionDocRef.get(); - return collection.availableNfts === 1; - }); - - const nftOrder = await submitOrderFunc(memberAddress, { - collection: collection.uid, - nft: nft.uid, - }); - await submitMilestoneFunc(nftOrder); - await wait(async () => { - collection = await collectionDocRef.get(); - return collection.availableNfts === 0; - }); -}); - -describe('Nft controller: setForSale', () => { - it('Should set nft for sale', async () => { - mockWalletReturnValue(walletSpy, memberAddress, dummySaleData(nft.uid)); - await testEnv.wrap(setForSaleNft)({}); - - const nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); - await wait(async () => { - const nft = await nftDocRef.get(); - return nft.available === 1; - }); - - const saleNft = await nftDocRef.get(); - expect(saleNft.available).toBe(1); - expect(saleNft.availableFrom).toBeDefined(); - - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${saleNft.collection}`); - const collection = await collectionDocRef.get(); - expect(collection.nftsOnAuction).toBe(0); - expect(collection.nftsOnSale).toBe(1); - }); - - it('Should throw, nft set as avatar', async () => { - const nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); - await nftDocRef.update({ setAsAvatar: true }); - - mockWalletReturnValue(walletSpy, memberAddress, dummySaleData(nft.uid)); - await expectThrow(testEnv.wrap(setForSaleNft)({}), WenError.nft_set_as_avatar.key); - }); - - it('Should set nft for auction', async () => { - mockWalletReturnValue(walletSpy, memberAddress, dummyAuctionData(nft.uid)); - await testEnv.wrap(setForSaleNft)({}); - - const nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); - await wait(async () => { - const nft = await nftDocRef.get(); - return nft.available === 3; - }); - - const auctionNft = await build5Db().doc(`${COL.NFT}/${nft.uid}`).get(); - expect(auctionNft.available).toBe(3); - expect(auctionNft.auctionFrom).toBeDefined(); - expect(auctionNft.auctionTo).toBeDefined(); - expect(auctionNft.auctionLength).toBeDefined(); - - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${auctionNft.collection}`); - const collection = await collectionDocRef.get(); - expect(collection.nftsOnAuction).toBe(1); - expect(collection.nftsOnSale).toBe(1); - }); - - it('Should throw, auction already in progress', async () => { - mockWalletReturnValue(walletSpy, memberAddress, dummyAuctionData(nft.uid)); - await testEnv.wrap(setForSaleNft)({}); - mockWalletReturnValue(walletSpy, memberAddress, dummyAuctionData(nft.uid)); - await expectThrow( - testEnv.wrap(setForSaleNft)({}), - WenError.nft_auction_already_in_progress.key, - ); - }); - - it('Should throw, invalid nft', async () => { - mockWalletReturnValue(walletSpy, memberAddress, { - ...dummyAuctionData(nft.uid), - nft: wallet.getRandomEthAddress(), - }); - await expectThrow(testEnv.wrap(setForSaleNft)({}), WenError.nft_does_not_exists.key); - }); - - it('Should throw, not owner', async () => { - mockWalletReturnValue(walletSpy, members[0], dummyAuctionData(nft.uid)); - await expectThrow(testEnv.wrap(setForSaleNft)({}), WenError.you_must_be_the_owner_of_nft.key); - }); -}); - -describe('Nft bidding', () => { - beforeEach(async () => { - mockWalletReturnValue(walletSpy, memberAddress, dummyAuctionData(nft.uid)); - await testEnv.wrap(setForSaleNft)({}); - await wait( - async () => (await build5Db().doc(`${COL.NFT}/${nft.uid}`).get())?.available === 3, - ); - }); - - it('Should create bid request', async () => { - await bidNft(members[0], MIN_IOTA_AMOUNT); - const snap = await build5Db() - .collection(COL.TRANSACTION) - .where('payload.type', '==', TransactionPayloadType.NFT_BID) - .where('member', '==', members[0]) - .get(); - expect(snap.length).toBe(1); - const tran = snap[0]; - expect(tran.payload.beneficiary).toBe('member'); - expect(tran.payload.beneficiaryUid).toBe(memberAddress); - expect(tran.payload.royaltiesFee).toBe(collection.royaltiesFee); - expect(tran.payload.royaltiesSpace).toBe(collection.royaltiesSpace); - expect(tran.payload.expiresOn).toBeDefined(); - expect(tran.payload.reconciled).toBe(false); - expect(tran.payload.validationType).toBe(TransactionValidationType.ADDRESS); - expect(tran.payload.nft).toBe(nft.uid); - expect(tran.payload.collection).toBe(collection.uid); - - const nftDocRef = build5Db().collection(COL.NFT).doc(nft.uid); - nft = await nftDocRef.get(); - expect(nft.lastTradedOn).toBeDefined(); - expect(nft.totalTrades).toBe(1); - - const collectionDocRef = build5Db().collection(COL.COLLECTION).doc(nft.collection); - collection = await collectionDocRef.get(); - expect(collection.lastTradedOn).toBeDefined(); - expect(collection.totalTrades).toBe(1); - }); - - it('Should bid and send amount', async () => { - await bidNft(members[0], MIN_IOTA_AMOUNT); - const nftData = await build5Db().doc(`${COL.NFT}/${nft.uid}`).get(); - expect(nftData.auctionHighestBidder).toBe(members[0]); - }); - - it('Should credit lowest bidder', async () => { - mockWalletReturnValue(walletSpy, members[0], { nft: nft.uid }); - await bidNft(members[0], 2 * MIN_IOTA_AMOUNT); - const nftData = await build5Db().doc(`${COL.NFT}/${nft.uid}`).get(); - expect(nftData.auctionHighestBidder).toBe(members[0]); - - await bidNft(members[1], 3 * MIN_IOTA_AMOUNT); - const updated = await build5Db().doc(`${COL.NFT}/${nft.uid}`).get(); - expect(updated.auctionHighestBidder).toBe(members[1]); - - const snap = await build5Db() - .collection(COL.TRANSACTION) - .where('type', '==', TransactionType.CREDIT) - .where('member', '==', members[0]) - .where('payload.nft', '==', nft.uid) - .get(); - expect(snap.length).toBe(1); - const tran = snap[0]; - - expect(tran.payload.amount).toBe(2 * MIN_IOTA_AMOUNT); - expect(tran.payload.nft).toBe(nft.uid); - expect(tran.payload.reconciled).toBe(true); - expect(tran.payload.sourceAddress).toBeDefined(); - expect(tran.payload.targetAddress).toBeDefined(); - expect(tran.payload.sourceTransaction!.length).toBe(1); - }); - - it('Should reject smaller bid', async () => { - await bidNft(members[0], 2 * MIN_IOTA_AMOUNT); - const nftData = await build5Db().doc(`${COL.NFT}/${nft.uid}`).get(); - expect(nftData.auctionHighestBidder).toBe(members[0]); - - await bidNft(members[1], MIN_IOTA_AMOUNT); - const updated = await build5Db().doc(`${COL.NFT}/${nft.uid}`).get(); - expect(updated.auctionHighestBidder).toBe(members[0]); - - const snap = await build5Db() - .collection(COL.TRANSACTION) - .where('type', '==', TransactionType.CREDIT) - .where('member', '==', members[1]) - .where('payload.nft', '==', nft.uid) - .get(); - expect(snap.length).toBe(1); - }); - - it('Should bid in parallel', async () => { - const bidPromises = [ - bidNft(members[0], 2 * MIN_IOTA_AMOUNT), - bidNft(members[1], 3 * MIN_IOTA_AMOUNT), - bidNft(members[2], MIN_IOTA_AMOUNT), - ]; - await Promise.all(bidPromises); - const nftData = await build5Db().doc(`${COL.NFT}/${nft.uid}`).get(); - expect(nftData.auctionHighestBidder).toBe(members[1]); - - const transactionSnap = await build5Db() - .collection(COL.TRANSACTION) - .where('type', '==', TransactionType.CREDIT) - .where('member', 'in', [members[0], members[2]]) - .where('payload.nft', '==', nft.uid) - .get(); - expect(transactionSnap.length).toBe(2); - }); -}); - -describe('Nft bidding with extended auction', () => { - let now: dayjs.Dayjs; - let nftDocRef: IDocument; - - const setForSale = async (auctionCustomLength?: number, extendAuctionWithin?: number) => { - now = dayjs(); - const auctionData = { - ...dummyAuctionData(nft.uid, auctionCustomLength, now), - extendedAuctionLength: 60000 * 10, - }; - extendAuctionWithin && set(auctionData, 'extendAuctionWithin', extendAuctionWithin); - mockWalletReturnValue(walletSpy, memberAddress, auctionData); - await testEnv.wrap(setForSaleNft)({}); - - nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); - await wait(async () => (await nftDocRef.get())?.available === 3); - }; - - it('Should bid and auction date to extended date', async () => { - await setForSale(); - - let nftData = await nftDocRef.get(); - - expect(nftData?.auctionLength).toBe(60000 * 4); - let auctionToDate = dayjs(nftData?.auctionTo?.toDate()); - const expectedAuctionToDate = dayjs(dateToTimestamp(now, true).toDate()).add( - nftData?.auctionLength!, - ); - expect(auctionToDate.isSame(expectedAuctionToDate)).toBe(true); - - let auctionExtendedDate = dayjs(nftData?.extendedAuctionTo?.toDate()); - const expectedAuctionExtendedToDate = dayjs(dateToTimestamp(now, true).toDate()).add( - nftData?.extendedAuctionLength!, - ); - expect(auctionExtendedDate.isSame(expectedAuctionExtendedToDate)).toBe(true); - expect(nftData?.extendedAuctionLength).toBe(60000 * 10); - - await bidNft(members[0], MIN_IOTA_AMOUNT); - nftData = await build5Db().doc(`${COL.NFT}/${nft.uid}`).get(); - expect(nftData.auctionHighestBidder).toBe(members[0]); - - nftData = await nftDocRef.get(); - auctionToDate = dayjs(nftData?.auctionTo?.toDate()); - auctionExtendedDate = dayjs(nftData?.extendedAuctionTo?.toDate()); - expect(auctionToDate.isSame(expectedAuctionExtendedToDate)).toBe(true); - expect(nftData?.auctionLength).toBe(nftData?.extendedAuctionLength); - }); - - it('Should bid but not set auction date to extended date', async () => { - await setForSale(60000 * 6); - let nftData = await nftDocRef.get(); - - expect(nftData?.auctionLength).toBe(60000 * 6); - let auctionToDate = dayjs(nftData?.auctionTo?.toDate()); - const expectedAuctionToDate = dayjs(dateToTimestamp(now, true).toDate()).add( - nftData?.auctionLength!, - ); - expect(auctionToDate.isSame(expectedAuctionToDate)).toBe(true); - - let auctionExtendedDate = dayjs(nftData?.extendedAuctionTo?.toDate()); - const expectedAuctionExtendedToDate = dayjs(dateToTimestamp(now, true).toDate()).add( - nftData?.extendedAuctionLength!, - ); - expect(auctionExtendedDate.isSame(expectedAuctionExtendedToDate)).toBe(true); - expect(nftData?.extendedAuctionLength).toBe(60000 * 10); - - await bidNft(members[0], MIN_IOTA_AMOUNT); - nftData = await build5Db().doc(`${COL.NFT}/${nft.uid}`).get(); - expect(nftData.auctionHighestBidder).toBe(members[0]); - - nftData = await nftDocRef.get(); - auctionToDate = dayjs(nftData?.auctionTo?.toDate()); - expect(auctionToDate.isSame(expectedAuctionToDate)).toBe(true); - expect(nftData?.auctionLength).toBe(60000 * 6); - }); - - it('Should throw, extended auction lenght must be greater then auction lenght', async () => { - const auctionData = { - ...dummyAuctionData(nft.uid), - extendedAuctionLength: 60000 * 3, - }; - mockWalletReturnValue(walletSpy, memberAddress, auctionData); - await expectThrow(testEnv.wrap(setForSaleNft)({}), WenError.invalid_params.key); - }); - - it('Should bid but custom extend within time', async () => { - await setForSale(60000 * 6, 60000 * 6); - let nftData = await nftDocRef.get(); - - expect(nftData?.auctionLength).toBe(60000 * 6); - let auctionToDate = dayjs(nftData?.auctionTo?.toDate()); - const expectedAuctionToDate = dayjs(dateToTimestamp(now, true).toDate()).add( - nftData?.auctionLength!, - ); - expect(auctionToDate.isSame(expectedAuctionToDate)).toBe(true); - - let auctionExtendedDate = dayjs(nftData?.extendedAuctionTo?.toDate()); - const expectedAuctionExtendedToDate = dayjs(dateToTimestamp(now, true).toDate()).add( - nftData?.extendedAuctionLength!, - ); - expect(auctionExtendedDate.isSame(expectedAuctionExtendedToDate)).toBe(true); - expect(nftData?.extendedAuctionLength).toBe(60000 * 10); - - await bidNft(members[0], MIN_IOTA_AMOUNT); - nftData = await build5Db().doc(`${COL.NFT}/${nft.uid}`).get(); - expect(nftData.auctionHighestBidder).toBe(members[0]); - - nftData = await nftDocRef.get(); - auctionToDate = dayjs(nftData?.auctionTo?.toDate()); - auctionExtendedDate = dayjs(nftData?.extendedAuctionTo?.toDate()); - expect(auctionToDate.isSame(auctionExtendedDate)).toBe(true); - expect(nftData?.auctionLength).toBe(60000 * 10); - }); - - it('Should throw, invalid extendAuctionWithin', async () => { - const auctionData = { - ...dummyAuctionData(nft.uid), - extendedAuctionLength: 60000 * 10, - extendAuctionWithin: 0, - }; - mockWalletReturnValue(walletSpy, memberAddress, auctionData); - await expectThrow(testEnv.wrap(setForSaleNft)({}), WenError.invalid_params.key); - }); -}); - -describe('Should finalize bidding', () => { - beforeEach(async () => { - mockWalletReturnValue(walletSpy, memberAddress, dummyAuctionData(nft.uid)); - await testEnv.wrap(setForSaleNft)({}); - await wait( - async () => (await build5Db().doc(`${COL.NFT}/${nft.uid}`).get())?.available === 3, - ); - }); - - it.each([false, true])('Should bid and finalize it', async (noRoyaltySpace: boolean) => { - if (noRoyaltySpace) { - await build5Db() - .doc(`${COL.COLLECTION}/${collection.uid}`) - .update({ royaltiesSpace: '', royaltiesFee: 0 }); - } - const bidOrder = await bidNft(members[0], MIN_IOTA_AMOUNT); - expect(bidOrder.payload.restrictions.collection).toEqual({ - access: collection.access, - accessAwards: collection.accessAwards || [], - accessCollections: collection.accessCollections || [], - }); - expect(bidOrder.payload.restrictions.nft).toEqual({ - saleAccess: nft.saleAccess || null, - saleAccessMembers: nft.saleAccessMembers || [], - }); - - const nftData = await build5Db().doc(`${COL.NFT}/${nft.uid}`).get(); - expect(nftData.auctionHighestBidder).toBe(members[0]); - - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${nftData.collection}`); - collection = await collectionDocRef.get(); - expect(collection.nftsOnAuction).toBe(1); - - await build5Db() - .doc(`${COL.NFT}/${nft.uid}`) - .update({ auctionTo: dateToTimestamp(dayjs().subtract(1, 'minute')) }); - - await finalizeAllNftAuctions(); - - const nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); - await wait(async () => { - const updatedNft = await nftDocRef.get(); - return updatedNft.available === NftAvailable.UNAVAILABLE; - }); - const updatedNft = await nftDocRef.get(); - expect(updatedNft.owner).toBe(members[0]); - expect(updatedNft.auctionFrom).toBeNull(); - expect(updatedNft.auctionTo).toBeNull(); - - const snap = await build5Db() - .collection(COL.NOTIFICATION) - .where('member', '==', members[0]) - .where('type', '==', NotificationType.WIN_BID) - .get(); - expect(snap.length).toBe(1); - - collection = await collectionDocRef.get(); - expect(collection.nftsOnAuction).toBe(0); - expect(collection.lastTradedOn).toBeDefined(); - expect(collection.totalTrades).toBe(2); - - nft = await nftDocRef.get(); - expect(nft.lastTradedOn).toBeDefined(); - expect(nft.totalTrades).toBe(2); - - const billPayments = await build5Db() - .collection(COL.TRANSACTION) - .where('type', '==', TransactionType.BILL_PAYMENT) - .where('payload.nft', '==', nft.uid) - .get(); - for (const billPayment of billPayments) { - expect(billPayment.payload.restrictions).toEqual(bidOrder.payload.restrictions); - } - }); -}); diff --git a/packages/functions/test/controls/nft/Helper.ts b/packages/functions/test/controls/nft/Helper.ts new file mode 100644 index 0000000000..e5de63b000 --- /dev/null +++ b/packages/functions/test/controls/nft/Helper.ts @@ -0,0 +1,122 @@ +import { build5Db } from '@build-5/database'; +import { + Access, + COL, + Categories, + Collection, + CollectionType, + MIN_IOTA_AMOUNT, + Nft, + NftAccess, + Space, +} from '@build-5/interfaces'; +import dayjs from 'dayjs'; +import { approveCollection, createCollection } from '../../../src/runtime/firebase/collection'; +import { openBid, createNft, orderNft } from '../../../src/runtime/firebase/nft'; +import * as wallet from '../../../src/utils/wallet.utils'; +import { MEDIA, testEnv } from '../../set-up'; +import { + createMember, + createSpace, + mockWalletReturnValue, + submitMilestoneFunc, + wait, +} from '../common'; + +export class Helper { + public spy: any = {} as any; + public member: string = {} as any; + public members: string[] = []; + public space: Space = {} as any; + public collection: Collection = {} as any; + public nft: Nft = {} as any; + + public beforeAll = async () => { + this.spy = jest.spyOn(wallet, 'decodeAuth'); + }; + + public beforeEach = async () => { + this.member = await createMember(this.spy); + const memberPromises = Array.from(Array(3)).map(() => createMember(this.spy)); + this.members = await Promise.all(memberPromises); + this.space = await createSpace(this.spy, this.member); + + mockWalletReturnValue(this.spy, this.member, { + name: 'Collection A', + description: 'babba', + type: CollectionType.CLASSIC, + royaltiesFee: 0.6, + category: Categories.ART, + access: Access.OPEN, + space: this.space.uid, + royaltiesSpace: this.space.uid, + onePerMemberOnly: false, + availableFrom: dayjs().toDate(), + price: 10 * 1000 * 1000, + }); + + this.collection = await testEnv.wrap(createCollection)({}); + mockWalletReturnValue(this.spy, this.member, { uid: this.collection.uid }); + await testEnv.wrap(approveCollection)({}); + + mockWalletReturnValue(this.spy, this.member, { + media: MEDIA, + ...dummyNft(this.collection.uid), + }); + this.nft = await testEnv.wrap(createNft)({}); + + const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${this.collection.uid}`); + await wait(async () => { + this.collection = await collectionDocRef.get(); + return this.collection.availableNfts === 1; + }); + + mockWalletReturnValue(this.spy, this.member, { + collection: this.collection.uid, + nft: this.nft.uid, + }); + const nftOrder = await testEnv.wrap(orderNft)({}); + await submitMilestoneFunc(nftOrder); + + await wait(async () => { + this.collection = await collectionDocRef.get(); + return this.collection.availableNfts === 0; + }); + }; + + public bidNft = async (memberId: string, amount: number) => { + mockWalletReturnValue(this.spy, memberId, { nft: this.nft.uid }); + const bidOrder = await testEnv.wrap(openBid)({}); + await submitMilestoneFunc(bidOrder, amount); + return bidOrder; + }; +} + +const dummyNft = (collection: string, description = 'babba') => ({ + name: 'Collection A', + description, + collection, + availableFrom: dayjs().toDate(), + price: 10 * 1000 * 1000, +}); + +export const dummySaleData = (uid: string) => ({ + nft: uid, + price: MIN_IOTA_AMOUNT, + availableFrom: dayjs().toDate(), + access: NftAccess.OPEN, +}); + +export const dummyAuctionData = ( + uid: string, + auctionLength = 60000 * 4, + from: dayjs.Dayjs = dayjs(), +) => ({ + nft: uid, + price: MIN_IOTA_AMOUNT, + availableFrom: from.toDate(), + auctionFrom: from.toDate(), + auctionFloorPrice: MIN_IOTA_AMOUNT, + auctionLength, + access: NftAccess.OPEN, +}); diff --git a/packages/functions/test/controls/nft/nft.bidding.extends.spec.ts b/packages/functions/test/controls/nft/nft.bidding.extends.spec.ts new file mode 100644 index 0000000000..3d09652fcc --- /dev/null +++ b/packages/functions/test/controls/nft/nft.bidding.extends.spec.ts @@ -0,0 +1,154 @@ +import { IDocument, build5Db } from '@build-5/database'; +import { Auction, COL, MIN_IOTA_AMOUNT, Nft, WenError } from '@build-5/interfaces'; +import dayjs from 'dayjs'; +import { set } from 'lodash'; +import { setForSaleNft } from '../../../src/runtime/firebase/nft'; +import { dateToTimestamp } from '../../../src/utils/dateTime.utils'; +import { testEnv } from '../../set-up'; +import { expectThrow, mockWalletReturnValue, wait } from '../common'; +import { Helper, dummyAuctionData } from './Helper'; + +describe('Nft bidding with extended auction', () => { + const h = new Helper(); + + let now: dayjs.Dayjs; + let nftDocRef: IDocument; + + beforeAll(async () => { + await h.beforeAll(); + }); + + beforeEach(async () => { + await h.beforeEach(); + }); + + const setForSale = async (auctionCustomLength?: number, extendAuctionWithin?: number) => { + now = dayjs(); + const auctionData = { + ...dummyAuctionData(h.nft.uid, auctionCustomLength, now), + extendedAuctionLength: 60000 * 10, + }; + extendAuctionWithin && set(auctionData, 'extendAuctionWithin', extendAuctionWithin); + mockWalletReturnValue(h.spy, h.member, auctionData); + await testEnv.wrap(setForSaleNft)({}); + + nftDocRef = build5Db().doc(`${COL.NFT}/${h.nft.uid}`); + await wait(async () => { + h.nft = await nftDocRef.get(); + return h.nft.available === 3; + }); + }; + + it('Should bid and auction date to extended date', async () => { + await setForSale(); + + expect(h.nft.auctionLength).toBe(60000 * 4); + let auctionToDate = dayjs(h.nft.auctionTo?.toDate()); + const expectedAuctionToDate = dayjs(dateToTimestamp(now, true).toDate()).add( + h.nft.auctionLength!, + ); + expect(auctionToDate.isSame(expectedAuctionToDate)).toBe(true); + + let auctionExtendedDate = dayjs(h.nft.extendedAuctionTo?.toDate()); + const expectedAuctionExtendedToDate = dayjs(dateToTimestamp(now, true).toDate()).add( + h.nft.extendedAuctionLength!, + ); + expect(auctionExtendedDate.isSame(expectedAuctionExtendedToDate)).toBe(true); + expect(h.nft.extendedAuctionLength).toBe(60000 * 10); + + await h.bidNft(h.members[0], MIN_IOTA_AMOUNT); + h.nft = await build5Db().doc(`${COL.NFT}/${h.nft.uid}`).get(); + expect(h.nft.auctionHighestBidder).toBe(h.members[0]); + + h.nft = await nftDocRef.get(); + auctionToDate = dayjs(h.nft.auctionTo?.toDate()); + auctionExtendedDate = dayjs(h.nft.extendedAuctionTo?.toDate()); + expect(auctionToDate.isSame(expectedAuctionExtendedToDate)).toBe(true); + expect(h.nft.auctionLength).toBe(h.nft.extendedAuctionLength); + + const auctionDocRef = build5Db().doc(`${COL.AUCTION}/${h.nft.auction}`); + const auction = await auctionDocRef.get(); + auctionToDate = dayjs(auction.auctionTo?.toDate()); + auctionExtendedDate = dayjs(auction.extendedAuctionTo?.toDate()); + expect(auctionToDate.isSame(expectedAuctionExtendedToDate)).toBe(true); + expect(auction.auctionLength).toBe(auction.extendedAuctionLength); + }); + + it('Should bid but not set auction date to extended date', async () => { + await setForSale(60000 * 6); + h.nft = await nftDocRef.get(); + + expect(h.nft.auctionLength).toBe(60000 * 6); + let auctionToDate = dayjs(h.nft.auctionTo?.toDate()); + const expectedAuctionToDate = dayjs(dateToTimestamp(now, true).toDate()).add( + h.nft.auctionLength!, + ); + expect(auctionToDate.isSame(expectedAuctionToDate)).toBe(true); + + let auctionExtendedDate = dayjs(h.nft.extendedAuctionTo?.toDate()); + const expectedAuctionExtendedToDate = dayjs(dateToTimestamp(now, true).toDate()).add( + h.nft.extendedAuctionLength!, + ); + expect(auctionExtendedDate.isSame(expectedAuctionExtendedToDate)).toBe(true); + expect(h.nft.extendedAuctionLength).toBe(60000 * 10); + + await h.bidNft(h.members[0], MIN_IOTA_AMOUNT); + h.nft = await nftDocRef.get(); + expect(h.nft.auctionHighestBidder).toBe(h.members[0]); + auctionToDate = dayjs(h.nft.auctionTo?.toDate()); + expect(auctionToDate.isSame(expectedAuctionToDate)).toBe(true); + expect(h.nft.auctionLength).toBe(60000 * 6); + + const auctionDocRef = build5Db().doc(`${COL.AUCTION}/${h.nft.auction}`); + const auction = await auctionDocRef.get(); + auctionToDate = dayjs(auction.auctionTo?.toDate()); + expect(auctionToDate.isSame(expectedAuctionToDate)).toBe(true); + expect(auction.auctionLength).toBe(60000 * 6); + }); + + it('Should throw, extended auction lenght must be greater then auction lenght', async () => { + const auctionData = { + ...dummyAuctionData(h.nft.uid), + extendedAuctionLength: 60000 * 3, + }; + mockWalletReturnValue(h.spy, h.member, auctionData); + await expectThrow(testEnv.wrap(setForSaleNft)({}), WenError.invalid_params.key); + }); + + it('Should bid but custom extend within time', async () => { + await setForSale(60000 * 6, 60000 * 6); + h.nft = await nftDocRef.get(); + + expect(h.nft.auctionLength).toBe(60000 * 6); + let auctionToDate = dayjs(h.nft.auctionTo?.toDate()); + const expectedAuctionToDate = dayjs(dateToTimestamp(now, true).toDate()).add( + h.nft.auctionLength!, + ); + expect(auctionToDate.isSame(expectedAuctionToDate)).toBe(true); + + let auctionExtendedDate = dayjs(h.nft.extendedAuctionTo?.toDate()); + const expectedAuctionExtendedToDate = dayjs(dateToTimestamp(now, true).toDate()).add( + h.nft.extendedAuctionLength!, + ); + expect(auctionExtendedDate.isSame(expectedAuctionExtendedToDate)).toBe(true); + expect(h.nft.extendedAuctionLength).toBe(60000 * 10); + + await h.bidNft(h.members[0], MIN_IOTA_AMOUNT); + h.nft = await nftDocRef.get(); + expect(h.nft.auctionHighestBidder).toBe(h.members[0]); + auctionToDate = dayjs(h.nft.auctionTo?.toDate()); + auctionExtendedDate = dayjs(h.nft.extendedAuctionTo?.toDate()); + expect(auctionToDate.isSame(auctionExtendedDate)).toBe(true); + expect(h.nft.auctionLength).toBe(60000 * 10); + }); + + it('Should throw, invalid extendAuctionWithin', async () => { + const auctionData = { + ...dummyAuctionData(h.nft.uid), + extendedAuctionLength: 60000 * 10, + extendAuctionWithin: 0, + }; + mockWalletReturnValue(h.spy, h.member, auctionData); + await expectThrow(testEnv.wrap(setForSaleNft)({}), WenError.invalid_params.key); + }); +}); diff --git a/packages/functions/test/controls/nft/nft.bidding.finalize.spec.ts b/packages/functions/test/controls/nft/nft.bidding.finalize.spec.ts new file mode 100644 index 0000000000..608060aa06 --- /dev/null +++ b/packages/functions/test/controls/nft/nft.bidding.finalize.spec.ts @@ -0,0 +1,110 @@ +import { build5Db } from '@build-5/database'; +import { + Auction, + COL, + Collection, + MIN_IOTA_AMOUNT, + Nft, + NftAvailable, + NotificationType, + Transaction, + TransactionType, +} from '@build-5/interfaces'; +import dayjs from 'dayjs'; +import { finalizeAuctions } from '../../../src/cron/auction.cron'; +import { setForSaleNft } from '../../../src/runtime/firebase/nft'; +import { dateToTimestamp } from '../../../src/utils/dateTime.utils'; +import { testEnv } from '../../set-up'; +import { mockWalletReturnValue, wait } from '../common'; +import { Helper, dummyAuctionData } from './Helper'; + +describe('Should finalize bidding', () => { + const h = new Helper(); + + beforeAll(async () => { + await h.beforeAll(); + }); + + beforeEach(async () => { + await h.beforeEach(); + }); + + beforeEach(async () => { + await h.beforeEach(); + mockWalletReturnValue(h.spy, h.member, dummyAuctionData(h.nft.uid)); + await testEnv.wrap(setForSaleNft)({}); + await wait(async () => { + const docRef = build5Db().doc(`${COL.NFT}/${h.nft.uid}`); + h.nft = await docRef.get(); + return h.nft.available === 3; + }); + }); + + it.each([true, false])('Should bid and finalize it', async (noRoyaltySpace: boolean) => { + if (noRoyaltySpace) { + await build5Db() + .doc(`${COL.COLLECTION}/${h.collection.uid}`) + .update({ royaltiesSpace: '', royaltiesFee: 0 }); + } + const bidOrder = await h.bidNft(h.members[0], MIN_IOTA_AMOUNT); + expect(bidOrder.payload.restrictions.collection).toEqual({ + access: h.collection.access, + accessAwards: h.collection.accessAwards || [], + accessCollections: h.collection.accessCollections || [], + }); + expect(bidOrder.payload.restrictions.nft).toEqual({ + saleAccess: h.nft.saleAccess || null, + saleAccessMembers: h.nft.saleAccessMembers || [], + }); + + const nftDocRef = build5Db().doc(`${COL.NFT}/${h.nft.uid}`); + h.nft = await nftDocRef.get(); + expect(h.nft.auctionHighestBidder).toBe(h.members[0]); + + const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${h.nft.collection}`); + h.collection = await collectionDocRef.get(); + expect(h.collection.nftsOnAuction).toBe(1); + + const auctionDocRef = build5Db().doc(`${COL.AUCTION}/${h.nft.auction}`); + await auctionDocRef.update({ auctionTo: dateToTimestamp(dayjs().subtract(1, 'minute')) }); + + await finalizeAuctions(); + + await wait(async () => { + h.nft = await nftDocRef.get(); + return h.nft.available === NftAvailable.UNAVAILABLE; + }); + expect(h.nft.owner).toBe(h.members[0]); + expect(h.nft.auctionFrom).toBeNull(); + expect(h.nft.auctionTo).toBeNull(); + expect(h.nft.auction).toBeNull(); + + const snap = await build5Db() + .collection(COL.NOTIFICATION) + .where('member', '==', h.members[0]) + .where('type', '==', NotificationType.WIN_BID) + .get(); + expect(snap.length).toBe(1); + + h.collection = await collectionDocRef.get(); + expect(h.collection.nftsOnAuction).toBe(0); + expect(h.collection.lastTradedOn).toBeDefined(); + expect(h.collection.totalTrades).toBe(2); + + h.nft = await nftDocRef.get(); + expect(h.nft.lastTradedOn).toBeDefined(); + expect(h.nft.totalTrades).toBe(2); + + const billPayments = await build5Db() + .collection(COL.TRANSACTION) + .where('type', '==', TransactionType.BILL_PAYMENT) + .where('payload.nft', '==', h.nft.uid) + .get(); + for (const billPayment of billPayments) { + expect(billPayment.payload.restrictions).toEqual(bidOrder.payload.restrictions); + } + + const auction = await auctionDocRef.get(); + expect(auction.active).toBe(false); + }); +}); diff --git a/packages/functions/test/controls/nft/nft.bidding.spec.ts b/packages/functions/test/controls/nft/nft.bidding.spec.ts new file mode 100644 index 0000000000..0b6fa90bb6 --- /dev/null +++ b/packages/functions/test/controls/nft/nft.bidding.spec.ts @@ -0,0 +1,207 @@ +import { build5Db } from '@build-5/database'; +import { + Auction, + COL, + Collection, + MIN_IOTA_AMOUNT, + Nft, + Transaction, + TransactionPayloadType, + TransactionType, + TransactionValidationType, +} from '@build-5/interfaces'; +import { orderNft, setForSaleNft } from '../../../src/runtime/firebase/nft'; +import { testEnv } from '../../set-up'; +import { mockWalletReturnValue, submitMilestoneFunc, wait } from '../common'; +import { Helper, dummyAuctionData } from './Helper'; + +describe('Nft bidding', () => { + const h = new Helper(); + + beforeAll(async () => { + await h.beforeAll(); + }); + + beforeEach(async () => { + await h.beforeEach(); + mockWalletReturnValue(h.spy, h.member, dummyAuctionData(h.nft.uid)); + await testEnv.wrap(setForSaleNft)({}); + await wait(async () => { + const docRef = build5Db().doc(`${COL.NFT}/${h.nft.uid}`); + h.nft = await docRef.get(); + return h.nft.available === 3; + }); + }); + + it('Should create bid request', async () => { + await h.bidNft(h.members[0], MIN_IOTA_AMOUNT); + const snap = await build5Db() + .collection(COL.TRANSACTION) + .where('type', '==', TransactionType.ORDER) + .where('payload.type', '==', TransactionPayloadType.NFT_BID) + .where('member', '==', h.members[0]) + .get(); + expect(snap.length).toBe(1); + const tran = snap[0]; + expect(tran.payload.beneficiary).toBe('member'); + expect(tran.payload.beneficiaryUid).toBe(h.member); + expect(tran.payload.royaltiesFee).toBe(h.collection.royaltiesFee); + expect(tran.payload.royaltiesSpace).toBe(h.collection.royaltiesSpace); + expect(tran.payload.expiresOn).toBeDefined(); + expect(tran.payload.reconciled).toBe(false); + expect(tran.payload.validationType).toBe(TransactionValidationType.ADDRESS); + expect(tran.payload.nft).toBe(h.nft.uid); + expect(tran.payload.collection).toBe(h.collection.uid); + + const nftDocRef = build5Db().doc(`${COL.NFT}/${h.nft.uid}`); + h.nft = await nftDocRef.get(); + expect(h.nft.lastTradedOn).toBeDefined(); + expect(h.nft.totalTrades).toBe(1); + expect(h.nft.auctionHighestBid).toBe(MIN_IOTA_AMOUNT); + expect(h.nft.auctionHighestBidder).toBe(h.members[0]); + + const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${h.nft.collection}`); + h.collection = await collectionDocRef.get(); + expect(h.collection.lastTradedOn).toBeDefined(); + expect(h.collection.totalTrades).toBe(1); + + const auctionDocRef = build5Db().doc(`${COL.AUCTION}/${h.nft.auction}`); + const auction = await auctionDocRef.get(); + expect(auction.bids.length).toBe(1); + expect(auction.bids[0].amount).toBe(MIN_IOTA_AMOUNT); + expect(auction.bids[0].bidder).toBe(h.members[0]); + }); + + it('Should override 2 bids for same user', async () => { + await h.bidNft(h.members[0], MIN_IOTA_AMOUNT); + await h.bidNft(h.members[0], 2 * MIN_IOTA_AMOUNT); + + const auctionDocRef = build5Db().doc(`${COL.AUCTION}/${h.nft.auction}`); + const auction = await auctionDocRef.get(); + expect(auction.bids.length).toBe(1); + expect(auction.bids[0].amount).toBe(2 * MIN_IOTA_AMOUNT); + expect(auction.bids[0].bidder).toBe(h.members[0]); + + const orders = await build5Db() + .collection(COL.TRANSACTION) + .where('member', '==', h.members[0]) + .where('type', '==', TransactionType.ORDER) + .where('payload.type', '==', TransactionPayloadType.NFT_BID) + .get(); + expect(orders.length).toBe(2); + + const credits = await build5Db() + .collection(COL.TRANSACTION) + .where('member', '==', h.members[0]) + .where('type', '==', TransactionType.CREDIT) + .get(); + expect(credits.length).toBe(1); + expect(credits[0].payload.amount).toBe(MIN_IOTA_AMOUNT); + }); + + it('Should overbid 2 bids, topup', async () => { + const auctionDocRef = build5Db().doc(`${COL.AUCTION}/${h.nft.auction}`); + await auctionDocRef.update({ topUpBased: true }); + + await h.bidNft(h.members[0], MIN_IOTA_AMOUNT); + await h.bidNft(h.members[0], MIN_IOTA_AMOUNT); + + let auction = await auctionDocRef.get(); + expect(auction.bids.length).toBe(1); + expect(auction.bids[0].amount).toBe(2 * MIN_IOTA_AMOUNT); + expect(auction.bids[0].bidder).toBe(h.members[0]); + expect(auction.auctionHighestBid).toBe(2 * MIN_IOTA_AMOUNT); + expect(auction.auctionHighestBidder).toBe(h.members[0]); + + const nftDocRef = build5Db().doc(`${COL.NFT}/${h.nft.uid}`); + h.nft = await nftDocRef.get(); + expect(h.nft.auctionHighestBid).toBe(2 * MIN_IOTA_AMOUNT); + expect(h.nft.auctionHighestBidder).toBe(h.members[0]); + + await h.bidNft(h.members[1], 3 * MIN_IOTA_AMOUNT); + auction = await auctionDocRef.get(); + expect(auction.bids.length).toBe(1); + expect(auction.bids[0].amount).toBe(3 * MIN_IOTA_AMOUNT); + expect(auction.bids[0].bidder).toBe(h.members[1]); + expect(auction.auctionHighestBid).toBe(3 * MIN_IOTA_AMOUNT); + expect(auction.auctionHighestBidder).toBe(h.members[1]); + + h.nft = await nftDocRef.get(); + expect(h.nft.auctionHighestBid).toBe(3 * MIN_IOTA_AMOUNT); + expect(h.nft.auctionHighestBidder).toBe(h.members[1]); + + const payments = await build5Db() + .collection(COL.TRANSACTION) + .where('member', '==', h.members[0]) + .where('type', '==', TransactionType.PAYMENT) + .get(); + for (const payment of payments) { + expect(payment.payload.invalidPayment).toBe(true); + const credit = await build5Db() + .collection(COL.TRANSACTION) + .where('payload.sourceTransaction', 'array-contains', payment.uid) + .get(); + expect(credit).toBeDefined(); + } + }); + + it('Should reject smaller bid', async () => { + const nftDocRef = build5Db().doc(`${COL.NFT}/${h.nft.uid}`); + await h.bidNft(h.members[0], 2 * MIN_IOTA_AMOUNT); + h.nft = await nftDocRef.get(); + expect(h.nft.auctionHighestBidder).toBe(h.members[0]); + + await h.bidNft(h.members[1], MIN_IOTA_AMOUNT); + h.nft = await nftDocRef.get(); + expect(h.nft.auctionHighestBidder).toBe(h.members[0]); + + const snap = await build5Db() + .collection(COL.TRANSACTION) + .where('type', '==', TransactionType.CREDIT) + .where('member', '==', h.members[1]) + .where('payload.nft', '==', h.nft.uid) + .get(); + expect(snap.length).toBe(1); + }); + + it('Should bid in parallel', async () => { + const bidPromises = [ + h.bidNft(h.members[0], 2 * MIN_IOTA_AMOUNT), + h.bidNft(h.members[1], 3 * MIN_IOTA_AMOUNT), + h.bidNft(h.members[2], MIN_IOTA_AMOUNT), + ]; + await Promise.all(bidPromises); + + const nftDocRef = build5Db().doc(`${COL.NFT}/${h.nft.uid}`); + h.nft = await nftDocRef.get(); + expect(h.nft.auctionHighestBidder).toBe(h.members[1]); + + const transactionSnap = await build5Db() + .collection(COL.TRANSACTION) + .where('type', '==', TransactionType.CREDIT) + .where('member', 'in', [h.members[0], h.members[2]]) + .where('payload.nft', '==', h.nft.uid) + .get(); + expect(transactionSnap.length).toBe(2); + }); + + it('Should create bid, then credit on sold', async () => { + await h.bidNft(h.members[0], MIN_IOTA_AMOUNT); + await h.bidNft(h.members[0], MIN_IOTA_AMOUNT); + + mockWalletReturnValue(h.spy, h.members[1], { collection: h.nft.collection, nft: h.nft.uid }); + const nftOrder = await testEnv.wrap(orderNft)({}); + await submitMilestoneFunc(nftOrder); + + const nftDocRef = build5Db().doc(`${COL.NFT}/${h.nft.uid}`); + h.nft = await nftDocRef.get(); + expect(h.nft.owner).toBe(h.members[1]); + + const credits = await build5Db() + .collection(COL.TRANSACTION) + .where('member', '==', h.members[0]) + .where('type', '==', TransactionType.CREDIT) + .get(); + expect(credits.length).toBe(2); + }); +}); diff --git a/packages/functions/test/controls/nft/nft.set.for.sale.spec.ts b/packages/functions/test/controls/nft/nft.set.for.sale.spec.ts new file mode 100644 index 0000000000..a8af4e8c80 --- /dev/null +++ b/packages/functions/test/controls/nft/nft.set.for.sale.spec.ts @@ -0,0 +1,89 @@ +import { build5Db } from '@build-5/database'; +import { COL, Collection, Nft, WenError } from '@build-5/interfaces'; +import { setForSaleNft } from '../../../src/runtime/firebase/nft'; +import { getRandomEthAddress } from '../../../src/utils/wallet.utils'; +import { testEnv } from '../../set-up'; +import { expectThrow, mockWalletReturnValue, wait } from '../common'; +import { Helper, dummyAuctionData, dummySaleData } from './Helper'; + +describe('Nft set for sale', () => { + const h = new Helper(); + + beforeAll(async () => { + await h.beforeAll(); + }); + + beforeEach(async () => { + await h.beforeEach(); + }); + + it('Should set nft for sale', async () => { + mockWalletReturnValue(h.spy, h.member, dummySaleData(h.nft.uid)); + await testEnv.wrap(setForSaleNft)({}); + + const nftDocRef = build5Db().doc(`${COL.NFT}/${h.nft.uid}`); + await wait(async () => { + const nft = await nftDocRef.get(); + return nft.available === 1; + }); + + const saleNft = await nftDocRef.get(); + expect(saleNft.available).toBe(1); + expect(saleNft.availableFrom).toBeDefined(); + + const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${saleNft.collection}`); + const collection = await collectionDocRef.get(); + expect(collection.nftsOnAuction).toBe(0); + expect(collection.nftsOnSale).toBe(1); + }); + + it('Should throw, nft set as avatar', async () => { + const nftDocRef = build5Db().doc(`${COL.NFT}/${h.nft.uid}`); + await nftDocRef.update({ setAsAvatar: true }); + + mockWalletReturnValue(h.spy, h.member, dummySaleData(h.nft.uid)); + await expectThrow(testEnv.wrap(setForSaleNft)({}), WenError.nft_set_as_avatar.key); + }); + + it('Should set nft for auction', async () => { + mockWalletReturnValue(h.spy, h.member, dummyAuctionData(h.nft.uid)); + await testEnv.wrap(setForSaleNft)({}); + + const nftDocRef = build5Db().doc(`${COL.NFT}/${h.nft.uid}`); + await wait(async () => { + const nft = await nftDocRef.get(); + return nft.available === 3; + }); + + const auctionNft = await build5Db().doc(`${COL.NFT}/${h.nft.uid}`).get(); + expect(auctionNft.available).toBe(3); + expect(auctionNft.auctionFrom).toBeDefined(); + expect(auctionNft.auctionTo).toBeDefined(); + expect(auctionNft.auctionLength).toBeDefined(); + + const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${auctionNft.collection}`); + const collection = await collectionDocRef.get(); + expect(collection.nftsOnAuction).toBe(1); + expect(collection.nftsOnSale).toBe(1); + }); + + it('Should throw, auction already in progress', async () => { + mockWalletReturnValue(h.spy, h.member, dummyAuctionData(h.nft.uid)); + await testEnv.wrap(setForSaleNft)({}); + mockWalletReturnValue(h.spy, h.member, dummyAuctionData(h.nft.uid)); + await expectThrow(testEnv.wrap(setForSaleNft)({}), WenError.auction_already_in_progress.key); + }); + + it('Should throw, invalid nft', async () => { + mockWalletReturnValue(h.spy, h.member, { + ...dummyAuctionData(h.nft.uid), + nft: getRandomEthAddress(), + }); + await expectThrow(testEnv.wrap(setForSaleNft)({}), WenError.nft_does_not_exists.key); + }); + + it('Should throw, not owner', async () => { + mockWalletReturnValue(h.spy, h.members[0], dummyAuctionData(h.nft.uid)); + await expectThrow(testEnv.wrap(setForSaleNft)({}), WenError.you_must_be_the_owner_of_nft.key); + }); +}); diff --git a/packages/interfaces/src/api/post/AuctionBidRequest.ts b/packages/interfaces/src/api/post/AuctionBidRequest.ts new file mode 100644 index 0000000000..f2af13ed39 --- /dev/null +++ b/packages/interfaces/src/api/post/AuctionBidRequest.ts @@ -0,0 +1,14 @@ +/** + * This file was automatically generated by joi-to-typescript + * Do not modify this file manually + */ + +/** + * Request object to create a bid order. + */ +export interface AuctionBidRequest { + /** + * Build5 id of the auction. + */ + auction: string; +} diff --git a/packages/interfaces/src/api/post/AuctionCreateRequest.ts b/packages/interfaces/src/api/post/AuctionCreateRequest.ts new file mode 100644 index 0000000000..118d1482d8 --- /dev/null +++ b/packages/interfaces/src/api/post/AuctionCreateRequest.ts @@ -0,0 +1,42 @@ +/** + * This file was automatically generated by joi-to-typescript + * Do not modify this file manually + */ + +/** + * Request object to create an auction. + */ +export interface AuctionCreateRequest { + /** + * Floor price of the auction. Minimum 1000000, maximum 1000000000000 + */ + auctionFloorPrice: number; + /** + * Starting date of the auction. Can not be sooner then 10 minutes. + */ + auctionFrom: Date; + /** + * Millisecond value of the auction length. Minimum 240000, maximum 2678400000 + */ + auctionLength: number; + /** + * Auction will be extended if a bid happens this many milliseconds before auction ends. Default value is 300000 minutes + */ + extendAuctionWithin?: number; + /** + * If set, auction will automatically extended by this length if a bid comes in within {@link extendAuctionWithin} before the end of the auction. + */ + extendedAuctionLength?: number; + /** + * Sepcifies the maximum number of active bids. Minimum 1, maximum 10 + */ + maxBids: number; + /** + * Network on wich this auction accepts bids. + */ + network: 'iota' | 'smr' | 'atoi' | 'rms'; + /** + * If set to true, consequent bids from the same user will be threated as topups + */ + topUpBased?: boolean; +} diff --git a/packages/interfaces/src/api/post/index.ts b/packages/interfaces/src/api/post/index.ts index da9930411e..3f554d33e7 100644 --- a/packages/interfaces/src/api/post/index.ts +++ b/packages/interfaces/src/api/post/index.ts @@ -4,6 +4,8 @@ */ export * from './AddressValidationRequest'; +export * from './AuctionBidRequest'; +export * from './AuctionCreateRequest'; export * from './CutomTokenRequest'; export * from './AwardAddOwnerRequest'; export * from './AwardApproveParticipantRequest'; diff --git a/packages/interfaces/src/api/tangle/AuctionBidTangleRequest.ts b/packages/interfaces/src/api/tangle/AuctionBidTangleRequest.ts new file mode 100644 index 0000000000..0bbc7b08e2 --- /dev/null +++ b/packages/interfaces/src/api/tangle/AuctionBidTangleRequest.ts @@ -0,0 +1,18 @@ +/** + * This file was automatically generated by joi-to-typescript + * Do not modify this file manually + */ + +/** + * Tangle request object to create an auction bid + */ +export interface AuctionBidTangleRequest { + /** + * Build5 id of the auction to bid on. + */ + auction: string; + /** + * Type of the tangle request. + */ + requestType: 'BID_AUCTION'; +} diff --git a/packages/interfaces/src/api/tangle/AuctionCreateTangleRequest.ts b/packages/interfaces/src/api/tangle/AuctionCreateTangleRequest.ts new file mode 100644 index 0000000000..8b5c1eb567 --- /dev/null +++ b/packages/interfaces/src/api/tangle/AuctionCreateTangleRequest.ts @@ -0,0 +1,46 @@ +/** + * This file was automatically generated by joi-to-typescript + * Do not modify this file manually + */ + +/** + * Request object to create an auction. + */ +export interface AuctionCreateTangleRequest { + /** + * Floor price of the auction. Minimum 1000000, maximum 1000000000000 + */ + auctionFloorPrice: number; + /** + * Starting date of the auction. Can not be sooner then 10 minutes. + */ + auctionFrom: Date; + /** + * Millisecond value of the auction length. Minimum 240000, maximum 2678400000 + */ + auctionLength: number; + /** + * Auction will be extended if a bid happens this many milliseconds before auction ends. Default value is 300000 minutes + */ + extendAuctionWithin?: number; + /** + * If set, auction will automatically extended by this length if a bid comes in within {@link extendAuctionWithin} before the end of the auction. + */ + extendedAuctionLength?: number; + /** + * Sepcifies the maximum number of active bids. Minimum 1, maximum 10 + */ + maxBids: number; + /** + * Network on wich this auction accepts bids. + */ + network: 'iota' | 'smr' | 'atoi' | 'rms'; + /** + * Type of the tangle request. + */ + requestType: 'CREATE_AUCTION'; + /** + * If set to true, consequent bids from the same user will be threated as topups + */ + topUpBased?: boolean; +} diff --git a/packages/interfaces/src/api/tangle/NftBidTangleRequest.ts b/packages/interfaces/src/api/tangle/NftBidTangleRequest.ts index e2846a083b..748e88eb2f 100644 --- a/packages/interfaces/src/api/tangle/NftBidTangleRequest.ts +++ b/packages/interfaces/src/api/tangle/NftBidTangleRequest.ts @@ -12,7 +12,7 @@ export interface NftBidTangleRequest { */ disableWithdraw?: boolean; /** - * Build5 if of the nft to bid on. + * Build5 id of the nft to bid on. */ nft: string; /** diff --git a/packages/interfaces/src/api/tangle/common.ts b/packages/interfaces/src/api/tangle/common.ts index 402ec23231..bb968847a4 100644 --- a/packages/interfaces/src/api/tangle/common.ts +++ b/packages/interfaces/src/api/tangle/common.ts @@ -31,4 +31,7 @@ export enum TangleRequestType { MINT_METADATA_NFT = 'MINT_METADATA_NFT', STAMP = 'STAMP', + + CREATE_AUCTION = 'CREATE_AUCTION', + BID_AUCTION = 'BID_AUCTION', } diff --git a/packages/interfaces/src/api/tangle/index.ts b/packages/interfaces/src/api/tangle/index.ts index 18ada23f62..4a480c992d 100644 --- a/packages/interfaces/src/api/tangle/index.ts +++ b/packages/interfaces/src/api/tangle/index.ts @@ -4,6 +4,9 @@ */ export * from './AddressValidationTangleRequest'; +export * from './AuctionBidTangleRequest'; +export * from './AuctionCreateTangleRequest'; +export * from './NftBidTangleRequest'; export * from './AwardAppParticipantTangleRequest'; export * from './AwardCreateTangleRequest'; export * from './AwardFundTangleRequest'; diff --git a/packages/interfaces/src/errors.ts b/packages/interfaces/src/errors.ts index d63ee3f554..c543224a9c 100644 --- a/packages/interfaces/src/errors.ts +++ b/packages/interfaces/src/errors.ts @@ -126,7 +126,7 @@ export const WenError = { key: 'Collection available from date is after NFT available from date.', }, you_must_be_the_owner_of_nft: { code: 2066, key: 'You must be the owner of NFT.' }, - nft_auction_already_in_progress: { code: 2067, key: 'NFT already have auction in progress.' }, + auction_already_in_progress: { code: 2067, key: 'Auction already in progress.' }, nft_placeholder_cant_be_updated: { code: 2068, key: "Can't update placeholder NFT." }, you_cant_buy_your_nft: { code: 2069, key: 'You already own this NFT!' }, you_are_not_allowed_member_to_purchase_this_nft: { @@ -308,4 +308,6 @@ export const WenError = { you_are_not_admin_of_project: { code: 2139, key: 'You are not an admin of the project.' }, invalid_project_api_key: { code: 2140, key: 'Invalid project api key.' }, invalid_target_address: { code: 2141, key: 'Invalid target address.' }, + auction_not_active: { code: 2142, key: 'Auction no longer active.' }, + auction_does_not_exist: { code: 2143, key: 'Auction does not exist.' }, }; diff --git a/packages/interfaces/src/functions/index.ts b/packages/interfaces/src/functions/index.ts index c3dc2ccdc6..6e8087e088 100644 --- a/packages/interfaces/src/functions/index.ts +++ b/packages/interfaces/src/functions/index.ts @@ -50,7 +50,7 @@ export enum WEN_FUNC { // ORDER functions orderNft = 'ordernft', - openBid = 'openbid', + openBid = 'openBid', validateAddress = 'validateaddress', // TOKEN functions @@ -89,6 +89,8 @@ export enum WEN_FUNC { createProjetApiKey = 'createprojetapikey', stamp = 'stamp', + createauction = 'createauction', + bidAuction = 'bidauction', } export interface cMemberNotExists { diff --git a/packages/interfaces/src/models/auction.ts b/packages/interfaces/src/models/auction.ts new file mode 100644 index 0000000000..364e0639e0 --- /dev/null +++ b/packages/interfaces/src/models/auction.ts @@ -0,0 +1,37 @@ +import { BaseRecord, Timestamp } from './base'; +import { Network } from './transaction'; + +export interface AuctionBid { + amount: number; + bidder: string; + order: string; +} + +export enum AuctionType { + OPEN = 'OPEN', + NFT = 'NFT', +} + +export interface Auction extends BaseRecord { + auctionFrom: Timestamp; + auctionTo: Timestamp; + auctionLength: number; + + extendedAuctionTo?: Timestamp | null; + extendedAuctionLength?: number | null; + extendAuctionWithin?: number | null; + + auctionFloorPrice: number; + + bids: AuctionBid[]; + auctionHighestBidder?: string; + auctionHighestBid?: number; + maxBids: number; + + type: AuctionType; + network: Network; + nftId?: string; + + active: boolean; + topUpBased?: boolean; +} diff --git a/packages/interfaces/src/models/base.ts b/packages/interfaces/src/models/base.ts index 8ddf46e8d4..745b9bc436 100644 --- a/packages/interfaces/src/models/base.ts +++ b/packages/interfaces/src/models/base.ts @@ -65,6 +65,7 @@ export enum COL { AIRDROP = 'airdrop', PROJECT = 'project', STAMP = 'stamp', + AUCTION = 'auction', MNEMONIC = '_mnemonic', SYSTEM = '_system', diff --git a/packages/interfaces/src/models/index.ts b/packages/interfaces/src/models/index.ts index 37a31a3be3..498ffaaac5 100644 --- a/packages/interfaces/src/models/index.ts +++ b/packages/interfaces/src/models/index.ts @@ -1,3 +1,4 @@ +export * from './auction'; export * from './award'; export * from './badge'; export * from './base'; diff --git a/packages/interfaces/src/models/nft.ts b/packages/interfaces/src/models/nft.ts index bce19703f1..3996ab271a 100644 --- a/packages/interfaces/src/models/nft.ts +++ b/packages/interfaces/src/models/nft.ts @@ -241,4 +241,8 @@ export interface Nft extends BaseRecord { * NFT is set as avatar. */ setAsAvatar?: boolean; + /** + * The build5 id of the auction this nft belongs to + */ + auction?: string; } diff --git a/packages/interfaces/src/models/notification.ts b/packages/interfaces/src/models/notification.ts index fdbb91ffd3..56f2f2f1c7 100644 --- a/packages/interfaces/src/models/notification.ts +++ b/packages/interfaces/src/models/notification.ts @@ -5,38 +5,18 @@ export enum NotificationType { WIN_BID = 'WIN_BID', } -export interface NotificationBidParams { +interface NotificationParams { member: { name: string; }; amount: number; - nft: { - uid: string; - name: string; - }; + auction: string; } +export interface NotificationBidParams extends NotificationParams {} -export interface NotificationWinBidParams { - member: { - name: string; - }; - amount: number; - nft: { - uid: string; - name: string; - }; -} +export interface NotificationWinBidParams extends NotificationParams {} -export interface NotificationLostBidParams { - member: { - name: string; - }; - amount: number; - nft: { - uid: string; - name: string; - }; -} +export interface NotificationLostBidParams extends NotificationParams {} /** * Notification record. diff --git a/packages/interfaces/src/models/transaction/common.ts b/packages/interfaces/src/models/transaction/common.ts index 7767bd471c..0f48f3cd4b 100644 --- a/packages/interfaces/src/models/transaction/common.ts +++ b/packages/interfaces/src/models/transaction/common.ts @@ -55,6 +55,7 @@ export enum Network { export enum TransactionPayloadType { NFT_PURCHASE = 'NFT_PURCHASE', NFT_BID = 'NFT_BID', + AUCTION_BID = 'AUCTION_BID', SPACE_ADDRESS_VALIDATION = 'SPACE_ADDRESS_VALIDATION', MEMBER_ADDRESS_VALIDATION = 'MEMBER_ADDRESS_VALIDATION', TOKEN_PURCHASE = 'TOKEN_PURCHASE', diff --git a/packages/interfaces/src/models/transaction/payload.ts b/packages/interfaces/src/models/transaction/payload.ts index 66aac120ec..711a2e2026 100644 --- a/packages/interfaces/src/models/transaction/payload.ts +++ b/packages/interfaces/src/models/transaction/payload.ts @@ -153,4 +153,6 @@ export interface TransactionPayload { stamp?: string; tokenTradeOderTargetAddress?: string; + + auction?: string; }