From 05c9183e010b5527f8c5a4fba9ed9b4d006a48bd Mon Sep 17 00:00:00 2001 From: Boldizsar Mezei Date: Tue, 26 Mar 2024 16:35:59 +0100 Subject: [PATCH] Postgres Postgres Postgres Postgres Postgres Postgres Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Remove partials Fixes Fixe Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes FIxes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes --- .firebaserc | 7 - .github/workflows/action_deploy-prod.yml | 1 + .github/workflows/action_deploy-wen.yml | 1 + .../workflows/functions_emulated-tests.yml | 321 +- .../functions_online-emulated-tests.yml | 312 -- ...ions_tangle-online-unit-tests_emulator.yml | 3026 --------------- .../workflows/functions_tangle-unit-tests.yml | 3297 +++++++++-------- .prettierignore | 1 + .prettierrc | 3 +- data.proto | 161 - firebase.json | 18 - firestore.rules | 6 - package-lock.json | 2082 +++++++---- package.json | 7 +- packages/database/.gitignore | 2 +- packages/database/.prettierignore | 1 + packages/database/generators/generator.ts | 7 + .../generators/pg.interface.generator.ts | 230 ++ packages/database/knexfile.ts | 15 + .../migrations/20240129091246_common.ts | 118 + .../migrations/20240129135000_auction.ts | 31 + .../migrations/20240129135000_award.ts | 63 + .../migrations/20240129135000_change.ts | 10 + .../migrations/20240129135000_collection.ts | 86 + .../migrations/20240129135000_member.ts | 31 + .../migrations/20240129135000_milestone.ts | 35 + .../migrations/20240129135000_mnemonic.ts | 17 + .../database/migrations/20240129135000_nft.ts | 59 + .../migrations/20240129135000_nft_stake.ts | 19 + .../migrations/20240129135000_notification.ts | 16 + .../migrations/20240129135000_project.ts | 30 + .../migrations/20240129135000_proposal.ts | 52 + .../migrations/20240129135000_soon_snap.ts | 16 + .../migrations/20240129135000_space.ts | 60 + .../migrations/20240129135000_stake.ts | 25 + .../migrations/20240129135000_stake_reward.ts | 20 + .../migrations/20240129135000_stamp.ts | 34 + .../migrations/20240129135000_swap.ts | 23 + .../migrations/20240129135000_system.ts | 13 + .../migrations/20240129135000_ticker.ts | 12 + .../migrations/20240129135000_token.ts | 167 + .../migrations/20240129135000_token_market.ts | 30 + .../20240129135000_token_purchase.ts | 30 + .../migrations/20240129135000_transaction.ts | 151 + packages/database/package.json | 12 +- packages/database/src/app/app.ts | 11 - packages/database/src/app/build5App.ts | 6 - packages/database/src/app/index.ts | 3 - packages/database/src/app/interface.ts | 5 - packages/database/src/firestore/build5Db.ts | 22 - packages/database/src/firestore/common.ts | 11 - packages/database/src/firestore/firestore.ts | 294 -- packages/database/src/firestore/index.ts | 4 - packages/database/src/firestore/interfaces.ts | 103 - packages/database/src/index.ts | 3 +- packages/database/src/pg/impl/common.ts | 28 + packages/database/src/pg/impl/instance.ts | 4 + packages/database/src/pg/impl/knex.ts | 38 + packages/database/src/pg/impl/postgres.ts | 647 ++++ packages/database/src/pg/impl/pubsub.ts | 32 + .../database/src/pg/impl/tables/airdrop.ts | 62 + .../database/src/pg/impl/tables/auction.ts | 63 + packages/database/src/pg/impl/tables/award.ts | 107 + .../src/pg/impl/tables/award_owner.ts | 23 + .../src/pg/impl/tables/award_participant.ts | 31 + .../database/src/pg/impl/tables/collection.ts | 190 + .../src/pg/impl/tables/collection_rank.ts | 22 + .../src/pg/impl/tables/collection_stats.ts | 36 + .../src/pg/impl/tables/collection_vote.ts | 22 + .../database/src/pg/impl/tables/member.ts | 67 + .../database/src/pg/impl/tables/milestone.ts | 36 + .../pg/impl/tables/milestone_transactions.ts | 53 + .../database/src/pg/impl/tables/mnemonic.ts | 38 + packages/database/src/pg/impl/tables/nft.ts | 198 + .../database/src/pg/impl/tables/nft_stake.ts | 40 + .../src/pg/impl/tables/notification.ts | 42 + .../database/src/pg/impl/tables/project.ts | 42 + .../src/pg/impl/tables/project_admin.ts | 23 + .../src/pg/impl/tables/project_api_key.ts | 25 + .../database/src/pg/impl/tables/proposal.ts | 79 + .../src/pg/impl/tables/proposal_member.ts | 49 + .../src/pg/impl/tables/proposal_owner.ts | 23 + .../src/pg/impl/tables/soon_snapshot.ts | 36 + packages/database/src/pg/impl/tables/space.ts | 92 + .../src/pg/impl/tables/space_guardians.ts | 23 + .../src/pg/impl/tables/space_member.ts | 23 + packages/database/src/pg/impl/tables/stake.ts | 68 + .../src/pg/impl/tables/stake_reward.ts | 41 + packages/database/src/pg/impl/tables/stamp.ts | 62 + packages/database/src/pg/impl/tables/swap.ts | 46 + .../database/src/pg/impl/tables/system.ts | 19 + .../database/src/pg/impl/tables/ticker.ts | 18 + packages/database/src/pg/impl/tables/token.ts | 151 + .../src/pg/impl/tables/token_distribution.ts | 109 + .../src/pg/impl/tables/token_market.ts | 68 + .../src/pg/impl/tables/token_purchase.ts | 67 + .../database/src/pg/impl/tables/token_rank.ts | 22 + .../src/pg/impl/tables/token_stats.ts | 74 + .../database/src/pg/impl/tables/token_vote.ts | 22 + .../src/pg/impl/tables/transaction.ts | 290 ++ packages/database/src/pg/index.ts | 13 + packages/database/src/pg/interfaces.ts | 0 packages/database/src/pg/interfaces/batch.ts | 11 + .../database/src/pg/interfaces/collection.ts | 80 + packages/database/src/pg/interfaces/common.ts | 29 + .../database/src/pg/interfaces/database.ts | 32 + .../src/pg/interfaces/document/common.ts | 77 + .../src/pg/interfaces/document/document.ts | 83 + .../src/pg/interfaces/document/snapshot.ts | 37 + .../pg/interfaces/document/sub.document.ts | 22 + .../database/src/pg/interfaces/query/query.ts | 194 + .../src/pg/interfaces/query/snapshot.ts | 134 + .../src/pg/interfaces/query/sub.query.ts | 22 + .../database/src/pg/interfaces/transaction.ts | 26 + packages/database/src/pg/models/airdrop.ts | 20 + .../database/src/pg/models/airdrop_update.ts | 21 + packages/database/src/pg/models/auction.ts | 27 + .../database/src/pg/models/auction_update.ts | 28 + packages/database/src/pg/models/award.ts | 56 + .../database/src/pg/models/award_update.ts | 57 + packages/database/src/pg/models/changes.ts | 9 + .../database/src/pg/models/changes_update.ts | 9 + packages/database/src/pg/models/collection.ts | 87 + .../src/pg/models/collection_update.ts | 88 + packages/database/src/pg/models/common.ts | 14 + .../database/src/pg/models/common_update.ts | 14 + packages/database/src/pg/models/enums.ts | 4 + packages/database/src/pg/models/index.ts | 42 + packages/database/src/pg/models/member.ts | 25 + .../database/src/pg/models/member_update.ts | 26 + packages/database/src/pg/models/milestone.ts | 65 + .../src/pg/models/milestone_update.ts | 66 + packages/database/src/pg/models/mnemonic.ts | 14 + .../database/src/pg/models/mnemonic_update.ts | 15 + packages/database/src/pg/models/nft.ts | 98 + packages/database/src/pg/models/nft_update.ts | 99 + .../database/src/pg/models/notification.ts | 12 + .../src/pg/models/notification_update.ts | 12 + packages/database/src/pg/models/project.ts | 23 + .../database/src/pg/models/project_update.ts | 23 + packages/database/src/pg/models/proposal.ts | 42 + .../database/src/pg/models/proposal_update.ts | 43 + packages/database/src/pg/models/soon.ts | 13 + .../database/src/pg/models/soon_update.ts | 14 + packages/database/src/pg/models/space.ts | 47 + .../database/src/pg/models/space_update.ts | 48 + packages/database/src/pg/models/stake.ts | 31 + .../database/src/pg/models/stake_update.ts | 32 + packages/database/src/pg/models/stamp.ts | 26 + .../database/src/pg/models/stamp_update.ts | 27 + packages/database/src/pg/models/swap.ts | 18 + .../database/src/pg/models/swap_update.ts | 19 + packages/database/src/pg/models/system.ts | 10 + .../database/src/pg/models/system_update.ts | 11 + packages/database/src/pg/models/ticker.ts | 9 + .../database/src/pg/models/ticker_update.ts | 10 + packages/database/src/pg/models/token.ts | 171 + .../database/src/pg/models/token_update.ts | 172 + .../database/src/pg/models/transaction.ts | 129 + .../src/pg/models/transaction_update.ts | 134 + .../database/src/storage/build5Storage.ts | 3 +- packages/database/src/storage/storage.ts | 14 +- packages/functions/.env | 26 +- packages/functions/.env.dev | 11 - packages/functions/.env.local | 12 - packages/functions/.eslintrc.js | 10 +- packages/functions/.prettierignore | 4 +- packages/functions/.runtimeconfig.json | 33 - packages/functions/Dockerfile | 3 +- packages/functions/deploy.script.ts | 170 +- packages/functions/jest-setup.ts | 125 + packages/functions/jest.config.js | 3 +- .../functions/migration/create.triggers.ts | 57 + packages/functions/migration/index.ts | 35 + .../migration/indexes/composit.indexes.ts | 50 + .../migration/indexes/single.field.indexes.ts | 61 + packages/functions/package.json | 27 +- packages/functions/sa.json | 13 + packages/functions/scripts/db.upgrade.ts | 2 +- .../scripts/dbUpgrades/2.1/soon.snapshot.ts | 235 -- packages/functions/scripts/dummyTransfer.ts | 4 +- .../functions/scripts/duplicatePurchases.ts | 2 +- packages/functions/scripts/manualRefund.ts | 2 +- packages/functions/scripts/nullPayments.ts | 4 +- packages/functions/scripts/retryPayment.ts | 4 +- .../src/controls/address/address.control.ts | 8 +- .../src/controls/auction/auction.control.ts | 6 +- .../auction/auction.create.control.ts | 8 +- .../award/award.approve.participant.ts | 4 +- .../src/controls/award/award.cancel.ts | 6 +- .../src/controls/award/award.create.ts | 8 +- .../src/controls/award/award.fund.ts | 2 +- .../src/controls/award/award.owner.ts | 21 +- .../src/controls/award/award.participate.ts | 11 +- .../src/controls/award/award.reject.ts | 4 +- .../collection/collection-mint.control.ts | 40 +- .../collection/collection.create.control.ts | 37 +- .../collection/collection.reject.control.ts | 4 +- .../collection/collection.update.control.ts | 51 +- .../src/controls/credit/credit.controller.ts | 8 +- .../src/controls/member/member.create.ts | 13 +- .../src/controls/member/member.update.ts | 26 +- .../controls/nft/NftMetadataRequestSchema.ts | 2 +- .../src/controls/nft/nft.bid.control.ts | 8 +- .../functions/src/controls/nft/nft.create.ts | 42 +- .../functions/src/controls/nft/nft.deposit.ts | 2 +- .../src/controls/nft/nft.metadata.control.ts | 16 +- .../controls/nft/nft.puchase.bulk.control.ts | 4 +- .../src/controls/nft/nft.puchase.control.ts | 5 +- .../src/controls/nft/nft.set.for.sale.ts | 12 +- .../functions/src/controls/nft/nft.stake.ts | 4 +- .../src/controls/nft/nft.transfer.ts | 22 +- .../src/controls/nft/nft.update.unsold.ts | 8 +- .../src/controls/nft/nft.withdraw.ts | 32 +- .../project/ProjectCreateRequestSchema.ts | 12 +- .../project/project.create.control.ts | 19 +- .../project/project.deactivate.control.ts | 4 +- .../proposal/approve.reject.proposal.ts | 6 +- .../src/controls/proposal/create.proposal.ts | 13 +- .../src/controls/proposal/vote.on.proposal.ts | 30 +- .../src/controls/rank/rank.control.ts | 69 +- .../controls/space/member.accept.control.ts | 20 +- .../controls/space/member.block.control.ts | 23 +- .../controls/space/member.decline.control.ts | 12 +- .../controls/space/member.leave.control.ts | 14 +- .../controls/space/member.unblock.control.ts | 8 +- .../src/controls/space/space.claim.control.ts | 12 +- .../controls/space/space.create.control.ts | 14 +- .../space/space.guardian.edit.control.ts | 21 +- .../src/controls/space/space.join.control.ts | 24 +- .../controls/space/space.update.control.ts | 24 +- .../src/controls/stake/stake.deposit.ts | 2 +- .../src/controls/stake/stake.reward.revoke.ts | 37 +- .../src/controls/stake/stake.reward.ts | 11 +- .../src/controls/stamp/stamp.create.ts | 19 +- .../src/controls/swaps/swap.create.control.ts | 6 +- .../src/controls/swaps/swap.funded.control.ts | 14 +- .../src/controls/swaps/swap.reject.control.ts | 12 +- .../token-minting/airdrop-minted-token.ts | 16 +- .../claim-minted-token.control.ts | 2 +- .../token-minting/import-minted-token.ts | 8 +- .../token-minting/token-mint.control.ts | 28 +- .../token-trading/TokenTradeRequestSchema.ts | 2 +- .../token-trade-cancel.controller.ts | 5 +- .../token-trading/token-trade.controller.ts | 22 +- .../controls/token/TokenOrderRequestSchema.ts | 2 +- .../src/controls/token/token.airdrop.claim.ts | 9 +- .../src/controls/token/token.airdrop.ts | 31 +- .../controls/token/token.cancel.pub.sale.ts | 16 +- .../src/controls/token/token.create.ts | 25 +- .../src/controls/token/token.credit.ts | 37 +- .../controls/token/token.enable.trading.ts | 10 +- .../src/controls/token/token.order.ts | 20 +- .../src/controls/token/token.set.for.sale.ts | 15 +- .../src/controls/token/token.update.ts | 12 +- .../src/controls/vote/vote.control.ts | 56 +- packages/functions/src/cron/auction.cron.ts | 14 +- packages/functions/src/cron/award.cron.ts | 6 +- packages/functions/src/cron/bitfinex.cron.ts | 14 +- .../src/cron/collection.floor.price.cron.ts | 40 +- packages/functions/src/cron/media.cron.ts | 86 +- packages/functions/src/cron/nft.cron.ts | 4 +- packages/functions/src/cron/nftStake.cron.ts | 37 +- packages/functions/src/cron/orders.cron.ts | 16 +- packages/functions/src/cron/proposal.cron.ts | 12 +- packages/functions/src/cron/stake.cron.ts | 68 +- .../functions/src/cron/stakeReward.cron.ts | 79 +- packages/functions/src/cron/stamp.cron.ts | 8 +- packages/functions/src/cron/token.cron.ts | 33 +- .../functions/src/cron/token.purchase.cron.ts | 14 +- packages/functions/src/cron/wallet.cron.ts | 37 +- packages/functions/src/index.express.ts | 101 - packages/functions/src/index.ts | 204 +- packages/functions/src/runtime/common.ts | 2 +- .../src/runtime/firebase/address/index.ts | 4 - .../src/runtime/firebase/auction/index.ts | 6 - .../src/runtime/firebase/auth/index.ts | 4 - .../src/runtime/firebase/award/index.ts | 10 - .../src/runtime/firebase/collection/index.ts | 7 - .../src/runtime/firebase/credit/index.ts | 4 - .../src/runtime/firebase/member/index.ts | 5 - .../src/runtime/firebase/nft/index.ts | 25 - .../src/runtime/firebase/project/index.ts | 5 - .../src/runtime/firebase/proposal/index.ts | 7 - .../src/runtime/firebase/rank/index.ts | 4 - .../src/runtime/firebase/space/index.ts | 22 - .../src/runtime/firebase/stake/index.ts | 6 - .../src/runtime/firebase/stamp/index.ts | 4 - .../runtime/firebase/storage/file.upload.ts | 4 - .../src/runtime/firebase/swap/index.ts | 8 - .../src/runtime/firebase/token/base/index.ts | 20 - .../runtime/firebase/token/minting/index.ts | 10 - .../runtime/firebase/token/trading/index.ts | 5 - .../src/runtime/firebase/vote/index.ts | 4 - packages/functions/src/runtime/https/https.ts | 13 +- .../src/runtime/proto/protoToJson.ts | 48 - .../functions/src/runtime/trigger/index.ts | 26 +- .../functions/src/runtime/trigger/trigger.ts | 38 +- packages/functions/src/services/joi/common.ts | 9 +- .../payment/address/address-member.service.ts | 33 +- .../payment/address/address.space.service.ts | 62 +- .../src/services/payment/address/common.ts | 26 +- .../payment/auction/auction-bid.service.ts | 71 +- .../auction/auction.finalize.service.ts | 38 +- .../services/payment/award/award-service.ts | 20 +- .../src/services/payment/credit-service.ts | 17 +- .../services/payment/metadataNft-service.ts | 61 +- .../payment/nft/collection-minting.service.ts | 46 +- .../src/services/payment/nft/common.ts | 44 +- .../payment/nft/nft-deposit.service.ts | 114 +- .../payment/nft/nft-purchase.bulk.service.ts | 209 +- .../payment/nft/nft-purchase.service.ts | 61 +- .../services/payment/nft/nft-stake.service.ts | 26 +- .../payment/nft/nft-transfer.service.ts | 20 +- .../services/payment/payment-processing.ts | 18 +- .../services/payment/space/space-service.ts | 41 +- .../src/services/payment/stake-service.ts | 24 +- .../src/services/payment/stamp.service.ts | 37 +- .../src/services/payment/swap/swap-service.ts | 35 +- .../tangle-service/TangleRequestService.ts | 19 +- .../address/address-validation.service.ts | 10 +- .../auction/auction.bid.order.ts | 27 +- .../auction/auction.bid.service.ts | 17 +- .../auction/auction.create.service.ts | 7 +- .../award.approve.participant.service.ts | 74 +- .../award/award.create.service.ts | 17 +- .../award/award.fund.service.ts | 9 +- .../build5/verify.eth.for.b5.service.ts | 18 +- .../metadataNft/mint-metadata-nft.service.ts | 30 +- .../tangle-service/nft/nft-deposit.service.ts | 5 +- .../nft/nft-purchase.bulk.service.ts | 16 +- .../nft/nft-purchase.service.ts | 64 +- .../nft/nft-set-for-sale.service.ts | 35 +- .../nft/nft-transfer.service.ts | 19 +- .../proposal/ProposalApporvalService.ts | 11 +- .../proposal/ProposalCreateService.ts | 33 +- .../proposal/voting/ProposalVoteService.ts | 51 +- .../proposal/voting/simple.voting.ts | 7 +- .../proposal/voting/staked.token.voting.ts | 120 +- .../space/SpaceAcceptMemberService.ts | 44 +- .../space/SpaceBlockMemberService.ts | 41 +- .../space/SpaceCreateService.ts | 47 +- .../space/SpaceDeclineMemberService.ts | 16 +- .../space/SpaceGuardianService.ts | 51 +- .../tangle-service/space/SpaceJoinService.ts | 48 +- .../tangle-service/space/SpaceLeaveService.ts | 41 +- .../stamp/StampTangleService.ts | 36 +- .../swap/SwapCreateTangleService.ts | 9 +- .../swap/SwapRejectTangleService.ts | 13 +- .../swap/SwapSetFundedTangleService.ts | 16 +- .../tangle-service/token/stake.service.ts | 5 +- .../token/token-claim.service.ts | 13 +- .../token/token-trade.service.ts | 23 +- .../token/import-minted-token.service.ts | 10 +- .../payment/token/token-mint.service.ts | 24 +- .../token/token-minted-airdrop.service.ts | 73 +- .../payment/token/token-purchase.service.ts | 29 +- .../services/payment/token/token-service.ts | 130 +- .../payment/token/token-trade.service.ts | 32 +- .../services/payment/transaction-service.ts | 146 +- .../src/services/payment/voting-service.ts | 52 +- .../functions/src/services/stake.service.ts | 69 +- .../src/services/validators/access.ts | 12 +- .../src/services/wallet/NativeTokenWallet.ts | 18 +- .../src/services/wallet/NftWallet.ts | 57 +- .../functions/src/services/wallet/mnemonic.ts | 14 +- .../src/services/wallet/wallet.service.ts | 14 +- .../src/triggers/algolia/algolia.trigger.ts | 39 +- .../triggers/algolia/firestore.to.algolia.ts | 27 - .../functions/src/triggers/award.trigger.ts | 55 +- .../src/triggers/collection.stats.trigger.ts | 29 +- .../src/triggers/collection.trigger.ts | 217 +- packages/functions/src/triggers/common.ts | 10 +- .../MilestoneTransactionAdapter.ts | 18 +- .../milestone-transactions-triggers/common.ts | 26 +- .../consumed.vote.outputs.ts | 69 +- .../milestone-transaction.trigger.ts | 36 +- .../token.foundry.ts | 12 +- .../src/triggers/mnemonic.trigger.ts | 34 +- .../functions/src/triggers/nft.trigger.ts | 26 +- .../src/triggers/proposal.trigger.ts | 152 +- .../triggers/storage/resize.img.trigger.ts | 5 +- .../token-trading/match-base-token.ts | 31 +- .../token-trading/match-minted-token.ts | 28 +- .../token-trading/match-simple-token.ts | 31 +- .../src/triggers/token-trading/match-token.ts | 96 +- .../token-trading/token-purchase.trigger.ts | 26 +- .../token-trade-order.trigger.ts | 31 +- .../functions/src/triggers/token.trigger.ts | 146 +- .../transaction-trigger/airdrop.claim.ts | 180 +- .../award.transaction.update.ts | 55 +- .../transaction-trigger/collection-minting.ts | 132 +- .../transaction-trigger/matadatNft-minting.ts | 162 +- .../transaction-trigger/nft-staked.ts | 23 +- .../transaction-trigger/proposal.vote.ts | 27 +- .../triggers/transaction-trigger/staking.ts | 54 +- .../transaction-trigger/stamp-minting.ts | 64 +- .../transaction-trigger/token-minting.ts | 73 +- .../transaction.trigger.ts | 188 +- .../transaction-trigger/wallet-params.ts | 3 +- packages/functions/src/utils/car.utils.ts | 12 +- .../nft.prop.utils.ts | 3 +- .../collection-minting-utils/nft.utils.ts | 9 +- packages/functions/src/utils/common.utils.ts | 9 +- .../functions/src/utils/dateTime.utils.ts | 3 +- packages/functions/src/utils/error.utils.ts | 20 +- packages/functions/src/utils/logger.ts | 47 + packages/functions/src/utils/media.utils.ts | 33 +- packages/functions/src/utils/milestone.ts | 6 + packages/functions/src/utils/royalty.utils.ts | 6 +- packages/functions/src/utils/schema.utils.ts | 10 +- packages/functions/src/utils/space.utils.ts | 15 +- .../utils/token-minting-utils/member.utils.ts | 24 +- .../functions/src/utils/token-trade.utils.ts | 70 +- packages/functions/src/utils/token.utils.ts | 57 +- packages/functions/src/utils/trace.ts | 21 + packages/functions/src/utils/wallet.utils.ts | 27 +- .../functions/test-service-account-key.json | 12 - .../functions/test-tangle/address.spec.ts | 77 +- .../auction-tangle/auction.bit.tangle.spec.ts | 27 +- .../award-tangle/award-tangle_1.spec.ts | 17 +- .../award-tangle/award-tangle_2.spec.ts | 24 +- .../award-tangle/award-tangle_3.spec.ts | 23 +- .../award-tangle/award-tangle_4.spec.ts | 23 +- .../award-tangle/award-tangle_5.spec.ts | 21 +- .../award-tangle/award-tangle_6.spec.ts | 23 +- .../award-tangle/award-tangle_7.spec.ts | 19 +- .../test-tangle/award-tangle/common.ts | 18 +- .../test-tangle/award/award_1.spec.ts | 76 +- .../test-tangle/award/award_10.spec.ts | 53 +- .../test-tangle/award/award_11.spec.ts | 68 +- .../test-tangle/award/award_12.spec.ts | 70 +- .../test-tangle/award/award_1_b.spec.ts | 29 +- .../test-tangle/award/award_2.spec.ts | 90 +- .../test-tangle/award/award_3.spec.ts | 36 +- .../test-tangle/award/award_4.spec.ts | 64 +- .../test-tangle/award/award_5.spec.ts | 88 +- .../test-tangle/award/award_6.spec.ts | 52 +- .../test-tangle/award/award_7.spec.ts | 52 +- .../test-tangle/award/award_8.spec.ts | 87 +- .../test-tangle/award/award_9.spec.ts | 59 +- .../functions/test-tangle/award/common.ts | 18 +- .../test-tangle/base-token-trading/Helper.ts | 58 +- .../base-token-trading_1.spec.ts | 36 +- .../base-token-trading_10.spec.ts | 24 +- .../base-token-trading_11_a.spec.ts | 20 +- .../base-token-trading_11_b.spec.ts | 65 +- .../base-token-trading_11_c.spec.ts | 20 +- .../base-token-trading_11_d.spec.ts | 20 +- .../base-token-trading_12.spec.ts | 2 +- .../base-token-trading_13.spec.ts | 27 +- .../base-token-trading_14.spec.ts | 21 +- .../base-token-trading_15.spec.ts | 21 +- .../base-token-trading_16.spec.ts | 21 +- .../base-token-trading_17.spec.ts | 21 +- .../base-token-trading_18.spec.ts | 10 +- .../base-token-trading_19.spec.ts | 10 +- .../base-token-trading_2.spec.ts | 16 +- .../base-token-trading_3.spec.ts | 18 +- .../base-token-trading_4.spec.ts | 18 +- .../base-token-trading_5.spec.ts | 26 +- .../base-token-trading_6.spec.ts | 26 +- .../base-token-trading_7.spec.ts | 17 +- .../base-token-trading_8.spec.ts | 16 +- .../base-token-trading_9.spec.ts | 16 +- .../test-tangle/collection-minting/Helper.ts | 92 +- .../collection-minting_1.spec.ts | 21 +- .../collection-minting_10.spec.ts | 6 +- .../collection-minting_11.spec.ts | 8 +- .../collection-minting_12.spec.ts | 8 +- .../collection-minting_13.spec.ts | 19 +- .../collection-minting_2.spec.ts | 39 +- .../collection-minting_3.only.spec.ts | 23 +- .../collection-minting_4_a.spec.ts | 30 +- .../collection-minting_4_b.spec.ts | 26 +- .../collection-minting_4_c.spec.ts | 8 +- .../collection-minting_5.spec.ts | 24 +- .../collection-minting_6.spec.ts | 8 +- .../collection-minting_7.spec.ts | 31 +- .../collection-minting_8.spec.ts | 24 +- .../collection-minting_9.spec.ts | 31 +- packages/functions/test-tangle/common.ts | 8 +- packages/functions/test-tangle/faucet.ts | 6 +- .../test-tangle/metadata-nft/Helper.ts | 20 +- .../metadata-nft/mint-metadata-nft_1.spec.ts | 18 +- .../metadata-nft/mint-metadata-nft_10.spec.ts | 46 +- .../mint-metadata-nft_1_b.spec.ts | 18 +- .../metadata-nft/mint-metadata-nft_2.spec.ts | 16 +- .../metadata-nft/mint-metadata-nft_3.spec.ts | 20 +- .../mint-metadata-nft_3_b.spec.ts | 20 +- .../metadata-nft/mint-metadata-nft_4.spec.ts | 20 +- .../metadata-nft/mint-metadata-nft_5.spec.ts | 14 +- .../mint-metadata-nft_5_b.spec.ts | 14 +- .../metadata-nft/mint-metadata-nft_6.spec.ts | 11 +- .../metadata-nft/mint-metadata-nft_7.spec.ts | 9 +- .../metadata-nft/mint-metadata-nft_8.spec.ts | 25 +- .../metadata-nft/mint-metadata-nft_9.spec.ts | 39 +- .../test-tangle/minted-nft-trading/Helper.ts | 80 +- .../minted-nft-trading_1.spec.ts | 41 +- .../minted-nft-trading_10.spec.ts | 9 +- .../minted-nft-trading_11.only.spec.ts | 18 +- .../minted-nft-trading_1_b.spec.ts | 42 +- .../minted-nft-trading_2.spec.ts | 31 +- .../minted-nft-trading_3.spec.ts | 15 +- .../minted-nft-trading_4.spec.ts | 21 +- .../minted-nft-trading_5.spec.ts | 8 +- .../minted-nft-trading_6.spec.ts | 3 +- .../minted-nft-trading_7.spec.ts | 21 +- .../minted-nft-trading_8.spec.ts | 5 +- .../minted-token-airdrop/Helper.ts | 26 +- .../minted-token-airdrop_1_a.spec.ts | 70 +- .../minted-token-airdrop_1_b.spec.ts | 47 +- .../minted-token-airdrop_1_c.spec.ts | 30 +- .../minted-token-airdrop_2.spec.ts | 66 +- .../minted-token-airdrop_4.spec.ts | 27 +- .../minted-token-airdrop_5.spec.ts | 37 +- .../test-tangle/minted-token-claim/Helper.ts | 26 +- .../token.claim.minted_1.spec.ts | 17 +- .../token.claim.minted_2.spec.ts | 23 +- .../token.claim.minted_3.spec.ts | 15 +- .../token.claim.minted_4.spec.ts | 18 +- .../token.claim.minted_5.spec.ts | 32 +- .../token.claim.minted_6.spec.ts | 35 +- .../token.claim.minted_7.spec.ts | 37 +- .../test-tangle/minted-token-trade/Helper.ts | 55 +- .../minted-token-trade_1.spec.ts | 8 +- .../minted-token-trade_12.spec.ts | 13 +- .../minted-token-trade_12_b.spec.ts | 13 +- .../minted-token-trade_13.spec.ts | 15 +- .../minted-token-trade_14.spec.ts | 2 +- .../minted-token-trade_15.only.spec.ts | 35 +- .../minted-token-trade_16.spec.ts | 18 +- .../minted-token-trade_17.spec.ts | 41 +- .../minted-token-trade_18.spec.ts | 6 +- .../minted-token-trade_19.spec.ts | 27 +- .../minted-token-trade_2.spec.ts | 6 +- .../minted-token-trade_20.spec.ts | 20 +- .../minted-token-trade_21.spec.ts | 7 +- .../minted-token-trade_22.spec.ts | 7 +- .../minted-token-trade_23.spec.ts | 7 +- .../minted-token-trade_24.spec.ts | 7 +- .../minted-token-trade_2_b.spec.ts | 4 +- .../minted-token-trade_3.spec.ts | 24 +- .../minted-token-trade_4.spec.ts | 9 +- .../minted-token-trade_5.spec.ts | 12 +- .../minted-token-trade_6.spec.ts | 16 +- .../minted-token-trade_7.spec.ts | 16 +- .../minted-token-trade_8.spec.ts | 52 +- .../minted-token-trade_9.spec.ts | 14 +- .../functions/test-tangle/nft-bid/Helper.ts | 66 +- .../test-tangle/nft-bid/nft-bid.otr_1.spec.ts | 14 +- .../test-tangle/nft-bid/nft-bid.otr_2.spec.ts | 13 +- .../test-tangle/nft-bid/nft-bid.otr_3.spec.ts | 11 +- .../test-tangle/nft-bid/nft-bid.otr_4.spec.ts | 9 +- .../functions/test-tangle/nft-bulk/Helper.ts | 33 +- .../test-tangle/nft-bulk/order.bulk_1.spec.ts | 19 +- .../test-tangle/nft-bulk/order.bulk_2.spec.ts | 22 +- .../test-tangle/nft-bulk/order.bulk_3.spec.ts | 8 +- .../test-tangle/nft-bulk/order.bulk_4.spec.ts | 19 +- .../test-tangle/nft-bulk/order.bulk_5.spec.ts | 17 +- .../test-tangle/nft-bulk/order.bulk_6.spec.ts | 12 +- .../test-tangle/nft-set-for-sale/Helper.ts | 44 +- .../nft-set-for-sale_1.spec.ts | 9 +- .../nft-set-for-sale_2.spec.ts | 4 +- .../nft-set-for-sale_3.spec.ts | 15 +- .../test-tangle/nft-staking/Helper.ts | 86 +- .../nft-staking/nft-staking_1.spec.ts | 18 +- .../nft-staking/nft-staking_10.spec.ts | 12 +- .../nft-staking/nft-staking_2.spec.ts | 18 +- .../nft-staking/nft-staking_2_b.spec.ts | 20 +- .../nft-staking/nft-staking_3.spec.ts | 24 +- .../nft-staking/nft-staking_4.spec.ts | 20 +- .../nft-staking/nft-staking_5.spec.ts | 38 +- .../nft-staking/nft-staking_6.spec.ts | 25 +- .../nft-staking/nft-staking_7.spec.ts | 29 +- .../nft-staking/nft-staking_8.spec.ts | 25 +- .../nft-staking/nft-staking_9.spec.ts | 25 +- .../test-tangle/nft-transfer/Helper.ts | 64 +- .../nft-transfer/nft-transfer_1.spec.ts | 16 +- .../nft-transfer/nft-transfer_2.spec.ts | 10 +- .../nft-transfer/nft-transfer_3.spec.ts | 12 +- .../nft-transfer/nft-transfer_4.spec.ts | 9 +- .../nft-transfer/nft-transfer_5.spec.ts | 11 +- .../nft-transfer/nft-transfer_6.spec.ts | 12 +- .../nft-transfer/nft-transfer_7.spec.ts | 16 +- .../nft-transfer/nft-transfer_8.spec.ts | 20 +- .../test-tangle/proposal-tangle/Helper.ts | 68 +- .../proposal-tangle/proposal.approval.spec.ts | 2 +- .../proposal.simple.vote.spec.ts | 14 +- .../proposal.stake.voting.spec.ts | 22 +- .../proposal.token.voting.spec.ts | 19 +- .../test-tangle/soon.snapshot.only.spec.ts | 585 --- .../test-tangle/space-tangle/Helper.ts | 20 +- .../space-tangle/space.accept.member.spec.ts | 6 +- .../space-tangle/space.block.member.spec.ts | 25 +- .../space-tangle/space.create.spec.ts | 4 +- .../space-tangle/space.decline.member.spec.ts | 15 +- .../space-tangle/space.edit.guardian.spec.ts | 16 +- .../space-tangle/space.join.spec.ts | 13 +- .../space-tangle/space.leave.spec.ts | 14 +- .../functions/test-tangle/staking/Helper.ts | 97 +- .../test-tangle/staking/staking_1.spec.ts | 76 +- .../test-tangle/staking/staking_2.spec.ts | 15 +- .../test-tangle/staking/staking_3.spec.ts | 9 +- .../test-tangle/staking/staking_4.spec.ts | 75 +- .../test-tangle/staking/staking_5.spec.ts | 9 +- .../test-tangle/stamp-tangle/Helper.ts | 4 +- .../stamp-tangle/stamp-tangle_1_a.spec.ts | 25 +- .../stamp-tangle/stamp-tangle_1_b.spec.ts | 15 +- .../stamp-tangle/stamp-tangle_2.spec.ts | 12 +- .../stamp-tangle/stamp-tangle_3.spec.ts | 14 +- .../stamp-tangle/stamp-tangle_4.spec.ts | 4 +- .../stamp-tangle/stamp-tangle_5.spec.ts | 12 +- .../stamp-tangle/stamp-tangle_6.spec.ts | 16 +- packages/functions/test-tangle/swap/Helper.ts | 55 +- .../functions/test-tangle/swap/swap_1.spec.ts | 32 +- .../functions/test-tangle/swap/swap_2.spec.ts | 24 +- .../test-tangle/swap/swap_3_a.spec.ts | 53 +- .../test-tangle/swap/swap_3_b.spec.ts | 53 +- .../functions/test-tangle/swap/swap_4.spec.ts | 12 +- .../functions/test-tangle/swap/swap_5.spec.ts | 20 +- .../functions/test-tangle/swap/swap_6.spec.ts | 51 +- .../functions/test-tangle/swap/swap_7.spec.ts | 43 +- .../functions/test-tangle/swap/swap_8.spec.ts | 45 +- .../tangleRequest/simple.token.trade.spec.ts | 27 +- .../tangleRequest/tangle-request.spec.ts | 47 +- .../test-tangle/token-import/Helper.ts | 51 +- .../token-import/token.import_1.spec.ts | 26 +- .../token-import/token.import_2.spec.ts | 18 +- .../test-tangle/token.based.voting/Helper.ts | 82 +- .../token.based.voting/stake.voting.spec.ts | 62 +- .../token.based.voting_1.spec.ts | 8 +- .../token.based.voting_2.spec.ts | 16 +- .../token.based.voting_3.spec.ts | 19 +- .../token.based.voting_4.spec.ts | 25 +- .../token.based.voting_5.spec.ts | 10 +- .../test-tangle/token.mint/Helper.ts | 30 +- .../token.mint/token.mint_1.spec.ts | 22 +- .../token.mint/token.mint_2.spec.ts | 75 +- .../token.mint/token.mint_3.spec.ts | 68 +- .../token.mint/token.mint_4.spec.ts | 45 +- .../trade-base-token-order.spec.ts | 64 +- .../functions/test-tangle/tran.match.spec.ts | 2 +- .../transaction-trigger_1.spec.ts | 6 +- .../transaction-trigger_10.spec.ts | 10 +- .../transaction-trigger_11.spec.ts | 6 +- .../transaction-trigger_12.spec.ts | 10 +- .../transaction-trigger_13.spec.ts | 30 +- .../transaction-trigger_14.spec.ts | 14 +- .../transaction-trigger_15.spec.ts | 4 +- .../transaction-trigger_2.spec.ts | 4 +- .../transaction-trigger_3.spec.ts | 6 +- .../transaction-trigger_4.spec.ts | 10 +- .../transaction-trigger_5.spec.ts | 16 +- .../transaction-trigger_6.spec.ts | 8 +- .../transaction-trigger_7.spec.ts | 8 +- .../transaction-trigger_8.spec.ts | 8 +- .../transaction-trigger_9.spec.ts | 26 +- .../functions/test-tangle/web3/web3_1.spec.ts | 81 +- .../functions/test-tangle/web3/web3_2.spec.ts | 25 +- .../functions/test-tangle/web3/web3_3.spec.ts | 47 +- .../withdraw-deposit-nft/Helper.ts | 175 +- .../deposit-withraw-nft_10_1.spec.ts | 13 +- .../deposit-withraw-nft_10_2.spec.ts | 13 +- .../deposit-withraw-nft_10_3.spec.ts | 13 +- .../deposit-withraw-nft_11.spec.ts | 60 +- .../deposit-withraw-nft_12_a.spec.ts | 18 +- .../deposit-withraw-nft_12_b.spec.ts | 17 +- .../deposit-withraw-nft_13.spec.ts | 17 +- .../deposit-withraw-nft_14.spec.ts | 33 +- .../deposit-withraw-nft_15.spec.ts | 17 +- .../deposit-withraw-nft_16.spec.ts | 20 +- .../deposit-withraw-nft_1_a.spec.ts | 41 +- .../deposit-withraw-nft_1_b.spec.ts | 34 +- .../deposit-withraw-nft_1_c.spec.ts | 41 +- .../deposit-withraw-nft_2.spec.ts | 17 +- .../deposit-withraw-nft_4.spec.ts | 29 +- .../deposit-withraw-nft_4_b.spec.ts | 26 +- .../deposit-withraw-nft_5.spec.ts | 29 +- .../deposit-withraw-nft_6.spec.ts | 45 +- .../deposit-withraw-nft_7.spec.ts | 27 +- .../deposit-withraw-nft_8.spec.ts | 27 +- .../deposit-withraw-nft_9.spec.ts | 37 +- .../test-tangle/workflow-online.spec.ts | 25 - packages/functions/test/auth.spec.ts | 94 +- .../functions/test/auth/legacy.auth.spec.ts | 53 +- .../functions/test/controls/address.spec.ts | 124 +- .../functions/test/controls/auction/Helper.ts | 44 +- .../test/controls/auction/auction.bid.spec.ts | 41 +- .../test/controls/collection.spec.ts | 537 ++- packages/functions/test/controls/common.ts | 318 +- .../functions/test/controls/member.spec.ts | 156 +- packages/functions/test/controls/nft.spec.ts | 124 +- .../functions/test/controls/nft/Helper.ts | 56 +- .../controls/nft/nft.bidding.extends.spec.ts | 54 +- .../controls/nft/nft.bidding.finalize.spec.ts | 67 +- .../test/controls/nft/nft.bidding.spec.ts | 87 +- .../controls/nft/nft.set.for.sale.spec.ts | 61 +- .../functions/test/controls/order.spec.ts | 108 +- .../controls/project/project.create.spec.ts | 132 +- .../project/project.deactivate.spec.ts | 50 +- .../functions/test/controls/proposal.spec.ts | 249 +- .../functions/test/controls/space.spec.ts | 671 ++-- .../test/controls/stake.reward.spec.ts | 62 +- .../test/controls/stamp.control.spec.ts | 29 +- .../token-distribution-auto-trigger.spec.ts | 63 +- .../test/controls/token-distribution.spec.ts | 94 +- .../test/controls/token-trade.buy.spec.ts | 61 +- .../test/controls/token-trade.sell.spec.ts | 167 +- .../test/controls/token-trade.trigger.spec.ts | 429 +-- .../controls/token.expired.sale.cron.spec.ts | 32 +- .../test/controls/token.order.spec.ts | 298 +- .../token/token.airdrop.claim.spec.ts | 139 +- .../test/controls/token/token.airdrop.spec.ts | 118 +- .../token/token.cancel.pub.sale.spec.ts | 136 +- .../test/controls/token/token.create.spec.ts | 263 +- .../token/token.order.and.claim.air.spec.ts | 86 +- .../test/controls/token/token.rank.spec.ts | 64 +- .../controls/token/token.set.to.sale.spec.ts | 114 +- .../test/controls/token/token.update.spec.ts | 117 +- .../test/controls/token/token.vote.spec.ts | 62 +- .../test/controls/workflow-online.spec.ts | 22 - .../functions/test/controls/workflow.spec.ts | 1 - .../test/cron/floor-price.cron.only.spec.ts | 19 +- .../test/cron/nft-stake.cron.spec.ts | 16 +- .../functions/test/cron/proposal.cron.spec.ts | 13 +- packages/functions/test/notifier.ts | 156 + packages/functions/test/set-up.ts | 264 +- .../test/stake/delete.stake.reward.spec.ts | 81 +- .../test/stake/stake.reward.cron.spec.ts | 9 +- .../functions/test/storage/resize.img.spec.ts | 32 +- packages/functions/test/teardown.ts | 46 +- packages/functions/workflow.build.js | 146 +- packages/interfaces/src/config.ts | 6 +- packages/interfaces/src/models/award.ts | 4 + packages/interfaces/src/models/base.ts | 1 + packages/interfaces/src/models/collection.ts | 4 + packages/interfaces/src/models/index.ts | 2 +- packages/interfaces/src/models/member.ts | 4 +- packages/interfaces/src/models/milestone.ts | 9 + packages/interfaces/src/models/mnemonic.ts | 4 +- packages/interfaces/src/models/nft.ts | 4 + packages/interfaces/src/models/project.ts | 3 +- packages/interfaces/src/models/proposal.ts | 9 +- packages/interfaces/src/models/space.ts | 12 + packages/interfaces/src/models/stamp.ts | 4 + .../interfaces/src/models/system.config.ts | 4 +- packages/interfaces/src/models/token.ts | 9 + .../src/models/transaction/payload.ts | 7 +- packages/interfaces/src/search/post/index.ts | 16 +- .../interfaces/src/search/tangle/index.ts | 3 +- packages/notifier/.gitignore | 4 + packages/notifier/.prettierignore | 2 + packages/notifier/README.md | 14 + packages/notifier/package.json | 22 + packages/notifier/src/index.ts | 91 + packages/notifier/src/logger.ts | 44 + packages/notifier/tsconfig.json | 16 + packages/sdk/examples/nft/otr/purchase.ts | 2 +- packages/sdk/src/https/datasets/Subset.ts | 6 +- .../datasets/award/AwardParticipantSubset.ts | 6 +- packages/sdk/src/https/datasets/common.ts | 4 +- packages/sdk/src/https/fetch.utils.ts | 2 +- packages/sdk/src/https/index.ts | 4 +- packages/sdk/src/https/utils.ts | 6 +- packages/sdk/test/otr/otr.spec.ts | 2 +- packages/search/.env | 27 +- packages/search/.gitignore | 1 + packages/search/package.json | 2 +- packages/search/src/common.ts | 87 +- packages/search/src/getAddresses.ts | 8 +- packages/search/src/getAvgPrice.ts | 45 +- packages/search/src/getById.ts | 19 +- packages/search/src/getMany.ts | 37 +- packages/search/src/getManyAdvanced.ts | 53 +- packages/search/src/getManyById.ts | 32 +- packages/search/src/getPriceChange.ts | 78 +- packages/search/src/getTokenPrice.ts | 27 +- packages/search/src/getTopMilestones.ts | 4 +- packages/search/src/getUpdatedAfter.ts | 36 +- packages/search/src/index.ts | 33 +- post.functions.deploy.js | 18 - pre.functions.deploy.js | 18 - storage.rules | 8 - 784 files changed, 21363 insertions(+), 18847 deletions(-) delete mode 100644 .firebaserc delete mode 100644 .github/workflows/functions_online-emulated-tests.yml delete mode 100644 .github/workflows/functions_tangle-online-unit-tests_emulator.yml delete mode 100644 data.proto delete mode 100644 firebase.json delete mode 100644 firestore.rules create mode 100644 packages/database/generators/generator.ts create mode 100644 packages/database/generators/pg.interface.generator.ts create mode 100644 packages/database/knexfile.ts create mode 100644 packages/database/migrations/20240129091246_common.ts create mode 100644 packages/database/migrations/20240129135000_auction.ts create mode 100644 packages/database/migrations/20240129135000_award.ts create mode 100644 packages/database/migrations/20240129135000_change.ts create mode 100644 packages/database/migrations/20240129135000_collection.ts create mode 100644 packages/database/migrations/20240129135000_member.ts create mode 100644 packages/database/migrations/20240129135000_milestone.ts create mode 100644 packages/database/migrations/20240129135000_mnemonic.ts create mode 100644 packages/database/migrations/20240129135000_nft.ts create mode 100644 packages/database/migrations/20240129135000_nft_stake.ts create mode 100644 packages/database/migrations/20240129135000_notification.ts create mode 100644 packages/database/migrations/20240129135000_project.ts create mode 100644 packages/database/migrations/20240129135000_proposal.ts create mode 100644 packages/database/migrations/20240129135000_soon_snap.ts create mode 100644 packages/database/migrations/20240129135000_space.ts create mode 100644 packages/database/migrations/20240129135000_stake.ts create mode 100644 packages/database/migrations/20240129135000_stake_reward.ts create mode 100644 packages/database/migrations/20240129135000_stamp.ts create mode 100644 packages/database/migrations/20240129135000_swap.ts create mode 100644 packages/database/migrations/20240129135000_system.ts create mode 100644 packages/database/migrations/20240129135000_ticker.ts create mode 100644 packages/database/migrations/20240129135000_token.ts create mode 100644 packages/database/migrations/20240129135000_token_market.ts create mode 100644 packages/database/migrations/20240129135000_token_purchase.ts create mode 100644 packages/database/migrations/20240129135000_transaction.ts delete mode 100644 packages/database/src/app/app.ts delete mode 100644 packages/database/src/app/build5App.ts delete mode 100644 packages/database/src/app/index.ts delete mode 100644 packages/database/src/app/interface.ts delete mode 100644 packages/database/src/firestore/build5Db.ts delete mode 100644 packages/database/src/firestore/common.ts delete mode 100644 packages/database/src/firestore/firestore.ts delete mode 100644 packages/database/src/firestore/index.ts delete mode 100644 packages/database/src/firestore/interfaces.ts create mode 100644 packages/database/src/pg/impl/common.ts create mode 100644 packages/database/src/pg/impl/instance.ts create mode 100644 packages/database/src/pg/impl/knex.ts create mode 100644 packages/database/src/pg/impl/postgres.ts create mode 100644 packages/database/src/pg/impl/pubsub.ts create mode 100644 packages/database/src/pg/impl/tables/airdrop.ts create mode 100644 packages/database/src/pg/impl/tables/auction.ts create mode 100644 packages/database/src/pg/impl/tables/award.ts create mode 100644 packages/database/src/pg/impl/tables/award_owner.ts create mode 100644 packages/database/src/pg/impl/tables/award_participant.ts create mode 100644 packages/database/src/pg/impl/tables/collection.ts create mode 100644 packages/database/src/pg/impl/tables/collection_rank.ts create mode 100644 packages/database/src/pg/impl/tables/collection_stats.ts create mode 100644 packages/database/src/pg/impl/tables/collection_vote.ts create mode 100644 packages/database/src/pg/impl/tables/member.ts create mode 100644 packages/database/src/pg/impl/tables/milestone.ts create mode 100644 packages/database/src/pg/impl/tables/milestone_transactions.ts create mode 100644 packages/database/src/pg/impl/tables/mnemonic.ts create mode 100644 packages/database/src/pg/impl/tables/nft.ts create mode 100644 packages/database/src/pg/impl/tables/nft_stake.ts create mode 100644 packages/database/src/pg/impl/tables/notification.ts create mode 100644 packages/database/src/pg/impl/tables/project.ts create mode 100644 packages/database/src/pg/impl/tables/project_admin.ts create mode 100644 packages/database/src/pg/impl/tables/project_api_key.ts create mode 100644 packages/database/src/pg/impl/tables/proposal.ts create mode 100644 packages/database/src/pg/impl/tables/proposal_member.ts create mode 100644 packages/database/src/pg/impl/tables/proposal_owner.ts create mode 100644 packages/database/src/pg/impl/tables/soon_snapshot.ts create mode 100644 packages/database/src/pg/impl/tables/space.ts create mode 100644 packages/database/src/pg/impl/tables/space_guardians.ts create mode 100644 packages/database/src/pg/impl/tables/space_member.ts create mode 100644 packages/database/src/pg/impl/tables/stake.ts create mode 100644 packages/database/src/pg/impl/tables/stake_reward.ts create mode 100644 packages/database/src/pg/impl/tables/stamp.ts create mode 100644 packages/database/src/pg/impl/tables/swap.ts create mode 100644 packages/database/src/pg/impl/tables/system.ts create mode 100644 packages/database/src/pg/impl/tables/ticker.ts create mode 100644 packages/database/src/pg/impl/tables/token.ts create mode 100644 packages/database/src/pg/impl/tables/token_distribution.ts create mode 100644 packages/database/src/pg/impl/tables/token_market.ts create mode 100644 packages/database/src/pg/impl/tables/token_purchase.ts create mode 100644 packages/database/src/pg/impl/tables/token_rank.ts create mode 100644 packages/database/src/pg/impl/tables/token_stats.ts create mode 100644 packages/database/src/pg/impl/tables/token_vote.ts create mode 100644 packages/database/src/pg/impl/tables/transaction.ts create mode 100644 packages/database/src/pg/index.ts create mode 100644 packages/database/src/pg/interfaces.ts create mode 100644 packages/database/src/pg/interfaces/batch.ts create mode 100644 packages/database/src/pg/interfaces/collection.ts create mode 100644 packages/database/src/pg/interfaces/common.ts create mode 100644 packages/database/src/pg/interfaces/database.ts create mode 100644 packages/database/src/pg/interfaces/document/common.ts create mode 100644 packages/database/src/pg/interfaces/document/document.ts create mode 100644 packages/database/src/pg/interfaces/document/snapshot.ts create mode 100644 packages/database/src/pg/interfaces/document/sub.document.ts create mode 100644 packages/database/src/pg/interfaces/query/query.ts create mode 100644 packages/database/src/pg/interfaces/query/snapshot.ts create mode 100644 packages/database/src/pg/interfaces/query/sub.query.ts create mode 100644 packages/database/src/pg/interfaces/transaction.ts create mode 100644 packages/database/src/pg/models/airdrop.ts create mode 100644 packages/database/src/pg/models/airdrop_update.ts create mode 100644 packages/database/src/pg/models/auction.ts create mode 100644 packages/database/src/pg/models/auction_update.ts create mode 100644 packages/database/src/pg/models/award.ts create mode 100644 packages/database/src/pg/models/award_update.ts create mode 100644 packages/database/src/pg/models/changes.ts create mode 100644 packages/database/src/pg/models/changes_update.ts create mode 100644 packages/database/src/pg/models/collection.ts create mode 100644 packages/database/src/pg/models/collection_update.ts create mode 100644 packages/database/src/pg/models/common.ts create mode 100644 packages/database/src/pg/models/common_update.ts create mode 100644 packages/database/src/pg/models/enums.ts create mode 100644 packages/database/src/pg/models/index.ts create mode 100644 packages/database/src/pg/models/member.ts create mode 100644 packages/database/src/pg/models/member_update.ts create mode 100644 packages/database/src/pg/models/milestone.ts create mode 100644 packages/database/src/pg/models/milestone_update.ts create mode 100644 packages/database/src/pg/models/mnemonic.ts create mode 100644 packages/database/src/pg/models/mnemonic_update.ts create mode 100644 packages/database/src/pg/models/nft.ts create mode 100644 packages/database/src/pg/models/nft_update.ts create mode 100644 packages/database/src/pg/models/notification.ts create mode 100644 packages/database/src/pg/models/notification_update.ts create mode 100644 packages/database/src/pg/models/project.ts create mode 100644 packages/database/src/pg/models/project_update.ts create mode 100644 packages/database/src/pg/models/proposal.ts create mode 100644 packages/database/src/pg/models/proposal_update.ts create mode 100644 packages/database/src/pg/models/soon.ts create mode 100644 packages/database/src/pg/models/soon_update.ts create mode 100644 packages/database/src/pg/models/space.ts create mode 100644 packages/database/src/pg/models/space_update.ts create mode 100644 packages/database/src/pg/models/stake.ts create mode 100644 packages/database/src/pg/models/stake_update.ts create mode 100644 packages/database/src/pg/models/stamp.ts create mode 100644 packages/database/src/pg/models/stamp_update.ts create mode 100644 packages/database/src/pg/models/swap.ts create mode 100644 packages/database/src/pg/models/swap_update.ts create mode 100644 packages/database/src/pg/models/system.ts create mode 100644 packages/database/src/pg/models/system_update.ts create mode 100644 packages/database/src/pg/models/ticker.ts create mode 100644 packages/database/src/pg/models/ticker_update.ts create mode 100644 packages/database/src/pg/models/token.ts create mode 100644 packages/database/src/pg/models/token_update.ts create mode 100644 packages/database/src/pg/models/transaction.ts create mode 100644 packages/database/src/pg/models/transaction_update.ts delete mode 100644 packages/functions/.env.dev delete mode 100644 packages/functions/.env.local delete mode 100644 packages/functions/.runtimeconfig.json create mode 100644 packages/functions/jest-setup.ts create mode 100644 packages/functions/migration/create.triggers.ts create mode 100644 packages/functions/migration/index.ts create mode 100644 packages/functions/migration/indexes/composit.indexes.ts create mode 100644 packages/functions/migration/indexes/single.field.indexes.ts create mode 100644 packages/functions/sa.json delete mode 100644 packages/functions/scripts/dbUpgrades/2.1/soon.snapshot.ts delete mode 100644 packages/functions/src/index.express.ts delete mode 100644 packages/functions/src/runtime/firebase/address/index.ts delete mode 100644 packages/functions/src/runtime/firebase/auction/index.ts delete mode 100644 packages/functions/src/runtime/firebase/auth/index.ts delete mode 100644 packages/functions/src/runtime/firebase/award/index.ts delete mode 100644 packages/functions/src/runtime/firebase/collection/index.ts delete mode 100644 packages/functions/src/runtime/firebase/credit/index.ts delete mode 100644 packages/functions/src/runtime/firebase/member/index.ts delete mode 100644 packages/functions/src/runtime/firebase/nft/index.ts delete mode 100644 packages/functions/src/runtime/firebase/project/index.ts delete mode 100644 packages/functions/src/runtime/firebase/proposal/index.ts delete mode 100644 packages/functions/src/runtime/firebase/rank/index.ts delete mode 100644 packages/functions/src/runtime/firebase/space/index.ts delete mode 100644 packages/functions/src/runtime/firebase/stake/index.ts delete mode 100644 packages/functions/src/runtime/firebase/stamp/index.ts delete mode 100644 packages/functions/src/runtime/firebase/storage/file.upload.ts delete mode 100644 packages/functions/src/runtime/firebase/swap/index.ts delete mode 100644 packages/functions/src/runtime/firebase/token/base/index.ts delete mode 100644 packages/functions/src/runtime/firebase/token/minting/index.ts delete mode 100644 packages/functions/src/runtime/firebase/token/trading/index.ts delete mode 100644 packages/functions/src/runtime/firebase/vote/index.ts delete mode 100644 packages/functions/src/runtime/proto/protoToJson.ts delete mode 100644 packages/functions/src/triggers/algolia/firestore.to.algolia.ts create mode 100644 packages/functions/src/utils/logger.ts create mode 100644 packages/functions/src/utils/milestone.ts create mode 100644 packages/functions/src/utils/trace.ts delete mode 100644 packages/functions/test-service-account-key.json delete mode 100644 packages/functions/test-tangle/soon.snapshot.only.spec.ts delete mode 100644 packages/functions/test-tangle/workflow-online.spec.ts delete mode 100644 packages/functions/test/controls/workflow-online.spec.ts create mode 100644 packages/functions/test/notifier.ts create mode 100644 packages/notifier/.gitignore create mode 100644 packages/notifier/.prettierignore create mode 100644 packages/notifier/README.md create mode 100644 packages/notifier/package.json create mode 100644 packages/notifier/src/index.ts create mode 100644 packages/notifier/src/logger.ts create mode 100644 packages/notifier/tsconfig.json delete mode 100644 post.functions.deploy.js delete mode 100644 pre.functions.deploy.js delete mode 100644 storage.rules diff --git a/.firebaserc b/.firebaserc deleted file mode 100644 index 1fe4513dc6..0000000000 --- a/.firebaserc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "projects": { - "default": "soonaverse", - "preview": "soonaverse-test", - "dev": "soonaverse-dev" - } -} diff --git a/.github/workflows/action_deploy-prod.yml b/.github/workflows/action_deploy-prod.yml index b850c03605..68c3f39bf4 100644 --- a/.github/workflows/action_deploy-prod.yml +++ b/.github/workflows/action_deploy-prod.yml @@ -39,6 +39,7 @@ jobs: --allow-unauthenticated \ --timeout=600 \ --ingress=internal-and-cloud-load-balancing \ + --add-cloudsql-instances $GOOGLE_CLOUD_PROJECT:us-central1:$GOOGLE_CLOUD_PROJECT \ --region=us-central1 \ deploy_functions: diff --git a/.github/workflows/action_deploy-wen.yml b/.github/workflows/action_deploy-wen.yml index fa4936fb50..40c162c0c3 100644 --- a/.github/workflows/action_deploy-wen.yml +++ b/.github/workflows/action_deploy-wen.yml @@ -40,6 +40,7 @@ jobs: --allow-unauthenticated \ --timeout=600 \ --ingress=internal-and-cloud-load-balancing \ + --add-cloudsql-instances $GOOGLE_CLOUD_PROJECT:us-central1:$GOOGLE_CLOUD_PROJECT \ --region=us-central1 \ deploy_to_npm_as_next: runs-on: ubuntu-latest diff --git a/.github/workflows/functions_emulated-tests.yml b/.github/workflows/functions_emulated-tests.yml index 979f17873b..e702868386 100644 --- a/.github/workflows/functions_emulated-tests.yml +++ b/.github/workflows/functions_emulated-tests.yml @@ -4,6 +4,7 @@ on: pull_request: paths: - packages/functions/** + - packages/database/** jobs: npm-install: @@ -30,6 +31,22 @@ jobs: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -43,34 +60,39 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" - npm run milestone-sync & - firebase emulators:exec " - npm run test:ci -- --forceExit --findRelatedTests ./test/auth.spec.ts && - npm run test:ci -- --forceExit --findRelatedTests ./test/auth/legacy.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.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-chunk_0 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test/auth.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/auth/legacy.auth.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/controls/address.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/controls/auction/auction.bid.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/controls/collection.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/controls/member.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/controls/nft.spec.ts chunk_1: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -84,34 +106,39 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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.extends.spec.ts && - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-chunk_1 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test/controls/nft/nft.bidding.extends.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/controls/nft/nft.bidding.finalize.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/controls/nft/nft.bidding.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/controls/nft/nft.set.for.sale.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/controls/order.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/controls/project/project.create.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/controls/project/project.deactivate.spec.ts chunk_2: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -125,34 +152,39 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" - npm run milestone-sync & - firebase emulators:exec " - 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/token-distribution.spec.ts && - npm run test:ci -- --forceExit --findRelatedTests ./test/controls/token-trade.buy.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-chunk_2 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test/controls/proposal.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/controls/space.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/controls/stake.reward.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/controls/stamp.control.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/controls/token-distribution-auto-trigger.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/controls/token-distribution.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/controls/token-trade.buy.spec.ts chunk_3: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -166,34 +198,39 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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.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/token.airdrop.spec.ts && - npm run test:ci -- --forceExit --findRelatedTests ./test/controls/token/token.cancel.pub.sale.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-chunk_3 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test/controls/token-trade.sell.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/controls/token-trade.trigger.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/controls/token.expired.sale.cron.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/controls/token.order.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/controls/token/token.airdrop.claim.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/controls/token/token.airdrop.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/controls/token/token.cancel.pub.sale.spec.ts chunk_4: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -207,34 +244,39 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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.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.vote.spec.ts && - npm run test:ci -- --forceExit --findRelatedTests ./test/controls/workflow-online.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-chunk_4 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test/controls/token/token.create.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/controls/token/token.order.and.claim.air.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/controls/token/token.rank.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/controls/token/token.set.to.sale.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/controls/token/token.update.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/controls/token/token.vote.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/controls/workflow.spec.ts chunk_5: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -248,34 +290,39 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" - npm run milestone-sync & - firebase emulators:exec " - 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/func.name.spec.ts && - npm run test:ci -- --forceExit --findRelatedTests ./test/naming.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-chunk_5 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test/cron/floor-price.cron.only.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/cron/nft-stake.cron.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/cron/proposal.cron.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/db.roll.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/func.name.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/naming.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/stake/delete.stake.reward.spec.ts chunk_6: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -289,23 +336,11 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" - npm run milestone-sync & - firebase emulators:exec " - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-chunk_6 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test/stake/stake.reward.cron.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test/storage/resize.img.spec.ts diff --git a/.github/workflows/functions_online-emulated-tests.yml b/.github/workflows/functions_online-emulated-tests.yml deleted file mode 100644 index 17f6aaa17a..0000000000 --- a/.github/workflows/functions_online-emulated-tests.yml +++ /dev/null @@ -1,312 +0,0 @@ -name: Functions | Online Emulated Unit Tests - -on: - workflow_run: - workflows: ["Firebase Deploy DEV"] - types: [completed] - branches: - - "develop" - -jobs: - npm-install: - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - id: cache - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Install Dependencies - if: steps.cache.outputs.cache-hit != 'true' - run: npm run build:functions - - chunk_0: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" - npm run milestone-sync & - firebase emulators:exec " - npm run test-online:ci -- --forceExit --findRelatedTests ./test/auth.spec.ts && - npm run test-online:ci -- --forceExit --findRelatedTests ./test/auth/legacy.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.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-online-chunk_0 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_1: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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.extends.spec.ts && - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-online-chunk_1 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_2: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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/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/token-distribution.spec.ts && - npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/token-trade.buy.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-online-chunk_2 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_3: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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.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/token.airdrop.spec.ts && - npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/token/token.cancel.pub.sale.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-online-chunk_3 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_4: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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.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.vote.spec.ts && - npm run test-online:ci -- --forceExit --findRelatedTests ./test/controls/workflow-online.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-online-chunk_4 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_5: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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/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/func.name.spec.ts && - npm run test-online:ci -- --forceExit --findRelatedTests ./test/naming.spec.ts && - npm run test-online:ci -- --forceExit --findRelatedTests ./test/stake/delete.stake.reward.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-online-chunk_5 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_6: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json" - npm run milestone-sync & - firebase emulators:exec " - 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 - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-online-chunk_6 - path: ./packages/functions/firestore-data/ - retention-days: 1 diff --git a/.github/workflows/functions_tangle-online-unit-tests_emulator.yml b/.github/workflows/functions_tangle-online-unit-tests_emulator.yml deleted file mode 100644 index 9d776381a2..0000000000 --- a/.github/workflows/functions_tangle-online-unit-tests_emulator.yml +++ /dev/null @@ -1,3026 +0,0 @@ -name: Functions | Tangle - Online - Emulated Unit Tests - -on: - workflow_run: - workflows: ["Firebase Deploy DEV"] - types: [completed] - branches: - - "develop" - -jobs: - npm-install: - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - id: cache - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Install Dependencies - if: steps.cache.outputs.cache-hit != 'true' - run: npm run build:functions - - chunk_0: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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/address.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@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_0 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_1: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_1 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_2: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_2 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_3: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_b.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/award_10.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_3 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_4: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_11.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_12.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@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_4 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_5: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_5 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_6: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_6 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_7: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_7 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_8: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_8 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_9: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_9 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_10: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_14.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_15.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_16.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_10 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_11: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_17.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_18.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_19.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_11 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_12: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_12 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_13: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_13 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_14: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_14 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_15: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_15 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_16: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_13.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_4_a.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_16 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_17: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_4_b.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_4_c.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@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_17 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_18: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_18 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_19: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_19 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_20: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_10.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_3_b.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_20 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_21: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_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_5_b.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_21 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_22: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_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_7.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_22 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_23: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_8.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_9.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@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_23 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_24: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_24 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_25: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_25 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_26: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_26 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_27: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_27 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_28: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_28 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_29: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_29 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_30: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_30 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_31: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_31 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_32: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_32 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_33: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_33 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_34: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_34 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_35: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_b.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_2.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_35 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_36: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_20.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_21.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_22.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_36 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_37: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_23.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_24.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@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_37 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_38: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_38 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_39: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_39 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_40: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_40 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_41: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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-bulk/order.bulk_1.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-bulk/order.bulk_2.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_41 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_42: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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-bulk/order.bulk_3.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-bulk/order.bulk_4.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-bulk/order.bulk_5.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_42 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_43: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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-bulk/order.bulk_6.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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_43 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_44: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_10.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_44 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_45: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_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_3.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_45 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_46: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_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_6.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_46 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_47: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_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_9.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_47 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_48: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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-transfer/nft-transfer_1.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-transfer/nft-transfer_2.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-transfer/nft-transfer_3.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_48 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_49: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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-transfer/nft-transfer_4.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-transfer/nft-transfer_5.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-transfer/nft-transfer_6.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_49 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_50: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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-transfer/nft-transfer_7.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/nft-transfer/nft-transfer_8.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/proposal-tangle/proposal.approval.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_50 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_51: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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.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.stake.voting.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_51 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_52: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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.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/space-tangle/space.block.member.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_52 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_53: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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.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.edit.guardian.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_53 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_54: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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.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/staking/staking_1.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_54 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_55: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_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_4.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_55 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_56: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_5.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/stamp-tangle/stamp-tangle_1_a.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/stamp-tangle/stamp-tangle_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@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_56 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_57: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_57 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_58: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_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/swap/swap_1.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_58 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_59: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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/swap/swap_2.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/swap/swap_3_a.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/swap/swap_3_b.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_59 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_60: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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/swap/swap_4.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/swap/swap_5.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/swap/swap_6.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_60 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_61: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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/swap/swap_7.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/swap/swap_8.spec.ts && - npm run test-tangle-online:ci -- --forceExit --findRelatedTests ./test-tangle/tangleRequest/simple.token.trade.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_61 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_62: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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/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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_62 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_63: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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/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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_63 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_64: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_64 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_65: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_65 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_66: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_66 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_67: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_67 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_68: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_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_14.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_68 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_69: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_15.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_3.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_69 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_70: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_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_6.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_70 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_71: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_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_9.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_71 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_72: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_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_3.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_72 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_73: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_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_c.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_73 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_74: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_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_3.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_74 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_75: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_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_12_b.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_75 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_76: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_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_15.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_76 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_77: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_16.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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_77 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_78: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_78 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_79: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_79 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_80: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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 - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-online-chunk_80 - path: ./packages/functions/firestore-data/ - retention-days: 1 diff --git a/.github/workflows/functions_tangle-unit-tests.yml b/.github/workflows/functions_tangle-unit-tests.yml index 68d1f3f0a0..bd9d8829ae 100644 --- a/.github/workflows/functions_tangle-unit-tests.yml +++ b/.github/workflows/functions_tangle-unit-tests.yml @@ -4,6 +4,7 @@ on: pull_request: paths: - packages/functions/** + - packages/database/** jobs: npm-install: @@ -30,6 +31,22 @@ jobs: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -43,30 +60,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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/address.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@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_0 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/address.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/auction-tangle/auction.bit.tangle.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/award-tangle/award-tangle_1.spec.ts chunk_1: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -80,30 +102,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_1 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/award-tangle/award-tangle_2.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/award-tangle/award-tangle_3.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/award-tangle/award-tangle_4.spec.ts chunk_2: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -117,30 +144,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_2 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/award-tangle/award-tangle_5.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/award-tangle/award-tangle_6.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/award-tangle/award-tangle_7.spec.ts chunk_3: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -154,30 +186,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_b.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/award_10.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_3 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/award/award_1_b.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/award/award_1.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/award/award_10.spec.ts chunk_4: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -191,30 +228,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_11.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/award/award_12.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@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_4 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/award/award_11.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/award/award_12.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/award/award_2.spec.ts chunk_5: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -228,30 +270,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_5 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/award/award_3.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/award/award_4.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/award/award_5.spec.ts chunk_6: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -265,30 +312,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_6 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/award/award_6.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/award/award_7.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/award/award_8.spec.ts chunk_7: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -302,30 +354,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_7 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/award/award_9.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/base-token-trading/base-token-trading_1.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/base-token-trading/base-token-trading_10.spec.ts chunk_8: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -339,30 +396,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_8 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/base-token-trading/base-token-trading_11_a.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/base-token-trading/base-token-trading_11_b.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/base-token-trading/base-token-trading_11_c.spec.ts chunk_9: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -376,30 +438,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_9 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/base-token-trading/base-token-trading_11_d.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/base-token-trading/base-token-trading_12.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/base-token-trading/base-token-trading_13.spec.ts chunk_10: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -413,30 +480,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_14.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_15.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_16.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_10 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/base-token-trading/base-token-trading_14.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/base-token-trading/base-token-trading_15.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/base-token-trading/base-token-trading_16.spec.ts chunk_11: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -450,30 +522,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_17.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_18.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/base-token-trading/base-token-trading_19.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_11 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/base-token-trading/base-token-trading_17.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/base-token-trading/base-token-trading_18.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/base-token-trading/base-token-trading_19.spec.ts chunk_12: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -487,30 +564,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_12 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/base-token-trading/base-token-trading_2.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/base-token-trading/base-token-trading_3.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/base-token-trading/base-token-trading_4.spec.ts chunk_13: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -524,30 +606,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_13 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/base-token-trading/base-token-trading_5.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/base-token-trading/base-token-trading_6.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/base-token-trading/base-token-trading_7.spec.ts chunk_14: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -561,30 +648,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_14 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/base-token-trading/base-token-trading_8.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/base-token-trading/base-token-trading_9.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/collection-minting/collection-minting_1.spec.ts chunk_15: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -598,30 +690,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_15 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/collection-minting/collection-minting_10.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/collection-minting/collection-minting_11.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/collection-minting/collection-minting_12.spec.ts chunk_16: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -635,30 +732,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_13.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_4_a.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_16 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/collection-minting/collection-minting_13.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/collection-minting/collection-minting_2.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/collection-minting/collection-minting_4_a.spec.ts chunk_17: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -672,30 +774,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_4_b.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/collection-minting/collection-minting_4_c.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@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_17 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/collection-minting/collection-minting_4_b.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/collection-minting/collection-minting_4_c.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/collection-minting/collection-minting_5.spec.ts chunk_18: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -709,30 +816,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_18 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/collection-minting/collection-minting_6.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/collection-minting/collection-minting_7.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/collection-minting/collection-minting_8.spec.ts chunk_19: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -746,30 +858,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_19 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/collection-minting/collection-minting_9.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/metadata-nft/mint-metadata-nft_1_b.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/metadata-nft/mint-metadata-nft_1.spec.ts chunk_20: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -783,30 +900,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_10.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_3_b.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_20 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/metadata-nft/mint-metadata-nft_10.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/metadata-nft/mint-metadata-nft_2.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/metadata-nft/mint-metadata-nft_3_b.spec.ts chunk_21: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -820,30 +942,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_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_5_b.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_21 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/metadata-nft/mint-metadata-nft_3.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/metadata-nft/mint-metadata-nft_4.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/metadata-nft/mint-metadata-nft_5_b.spec.ts chunk_22: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -857,30 +984,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_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_7.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_22 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/metadata-nft/mint-metadata-nft_5.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/metadata-nft/mint-metadata-nft_6.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/metadata-nft/mint-metadata-nft_7.spec.ts chunk_23: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -894,30 +1026,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_8.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/metadata-nft/mint-metadata-nft_9.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@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_23 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/metadata-nft/mint-metadata-nft_8.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/metadata-nft/mint-metadata-nft_9.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-nft-trading/minted-nft-trading_1_b.spec.ts chunk_24: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -931,30 +1068,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_24 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-nft-trading/minted-nft-trading_1.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-nft-trading/minted-nft-trading_10.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-nft-trading/minted-nft-trading_2.spec.ts chunk_25: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -968,30 +1110,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_25 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-nft-trading/minted-nft-trading_3.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-nft-trading/minted-nft-trading_4.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-nft-trading/minted-nft-trading_5.spec.ts chunk_26: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -1005,30 +1152,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_26 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-nft-trading/minted-nft-trading_6.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-nft-trading/minted-nft-trading_7.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-nft-trading/minted-nft-trading_8.spec.ts chunk_27: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -1042,30 +1194,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_27 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-airdrop/minted-token-airdrop_1_a.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-airdrop/minted-token-airdrop_1_b.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-airdrop/minted-token-airdrop_1_c.spec.ts chunk_28: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -1079,30 +1236,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_28 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-airdrop/minted-token-airdrop_2.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-airdrop/minted-token-airdrop_4.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-airdrop/minted-token-airdrop_5.spec.ts chunk_29: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -1116,30 +1278,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_29 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-claim/token.claim.minted_1.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-claim/token.claim.minted_2.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-claim/token.claim.minted_3.spec.ts chunk_30: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -1153,30 +1320,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_30 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-claim/token.claim.minted_4.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-claim/token.claim.minted_5.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-claim/token.claim.minted_6.spec.ts chunk_31: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -1190,30 +1362,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_31 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-claim/token.claim.minted_7.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-trade/minted-token-trade_1.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-trade/minted-token-trade_10.spec.ts chunk_32: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -1227,30 +1404,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_32 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-trade/minted-token-trade_11.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-trade/minted-token-trade_12_b.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-trade/minted-token-trade_12.spec.ts chunk_33: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -1264,30 +1446,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_33 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-trade/minted-token-trade_13.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-trade/minted-token-trade_14_b.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-trade/minted-token-trade_14.spec.ts chunk_34: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -1301,30 +1488,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_34 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-trade/minted-token-trade_16.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-trade/minted-token-trade_17.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-trade/minted-token-trade_18.spec.ts chunk_35: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -1338,30 +1530,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_b.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_2.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_35 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-trade/minted-token-trade_19.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-trade/minted-token-trade_2_b.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-trade/minted-token-trade_2.spec.ts chunk_36: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -1375,30 +1572,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_20.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_21.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_22.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_36 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-trade/minted-token-trade_20.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-trade/minted-token-trade_21.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-trade/minted-token-trade_22.spec.ts chunk_37: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -1412,30 +1614,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_23.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/minted-token-trade/minted-token-trade_24.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@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_37 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-trade/minted-token-trade_23.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-trade/minted-token-trade_24.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-trade/minted-token-trade_3.spec.ts chunk_38: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -1449,30 +1656,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_38 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-trade/minted-token-trade_4.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-trade/minted-token-trade_5.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-trade/minted-token-trade_6.spec.ts chunk_39: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -1486,30 +1698,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_39 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-trade/minted-token-trade_7.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-trade/minted-token-trade_8.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-trade/minted-token-trade_9.spec.ts chunk_40: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -1523,30 +1740,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_40 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/nft-bid/nft-bid.otr_1.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/nft-bid/nft-bid.otr_2.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/nft-bid/nft-bid.otr_3.spec.ts chunk_41: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -1560,30 +1782,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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-bulk/order.bulk_1.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-bulk/order.bulk_2.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_41 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/nft-bid/nft-bid.otr_4.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/nft-bulk/order.bulk_1.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/nft-bulk/order.bulk_2.spec.ts chunk_42: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -1597,30 +1824,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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-bulk/order.bulk_3.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-bulk/order.bulk_4.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-bulk/order.bulk_5.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_42 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/nft-bulk/order.bulk_3.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/nft-bulk/order.bulk_4.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/nft-bulk/order.bulk_5.spec.ts chunk_43: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -1634,30 +1866,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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-bulk/order.bulk_6.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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_43 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/nft-bulk/order.bulk_6.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/nft-set-for-sale/nft-set-for-sale_1.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/nft-set-for-sale/nft-set-for-sale_2.spec.ts chunk_44: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -1671,30 +1908,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_10.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_44 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/nft-set-for-sale/nft-set-for-sale_3.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/nft-staking/nft-staking_1.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/nft-staking/nft-staking_10.spec.ts chunk_45: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -1708,30 +1950,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_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_3.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_45 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/nft-staking/nft-staking_2_b.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/nft-staking/nft-staking_2.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/nft-staking/nft-staking_3.spec.ts chunk_46: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -1745,30 +1992,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_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_6.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_46 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/nft-staking/nft-staking_4.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/nft-staking/nft-staking_5.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/nft-staking/nft-staking_6.spec.ts chunk_47: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -1782,30 +2034,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_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_9.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_47 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/nft-staking/nft-staking_7.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/nft-staking/nft-staking_8.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/nft-staking/nft-staking_9.spec.ts chunk_48: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -1819,30 +2076,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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-transfer/nft-transfer_1.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-transfer/nft-transfer_2.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-transfer/nft-transfer_3.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_48 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/nft-transfer/nft-transfer_1.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/nft-transfer/nft-transfer_2.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/nft-transfer/nft-transfer_3.spec.ts chunk_49: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -1856,30 +2118,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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-transfer/nft-transfer_4.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-transfer/nft-transfer_5.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-transfer/nft-transfer_6.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_49 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/nft-transfer/nft-transfer_4.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/nft-transfer/nft-transfer_5.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/nft-transfer/nft-transfer_6.spec.ts chunk_50: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -1893,30 +2160,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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-transfer/nft-transfer_7.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/nft-transfer/nft-transfer_8.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/proposal-tangle/proposal.approval.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_50 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/nft-transfer/nft-transfer_7.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/nft-transfer/nft-transfer_8.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/proposal-tangle/proposal.approval.spec.ts chunk_51: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -1930,30 +2202,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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.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.stake.voting.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_51 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/proposal-tangle/proposal.create.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/proposal-tangle/proposal.simple.vote.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/proposal-tangle/proposal.stake.voting.spec.ts chunk_52: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -1967,30 +2244,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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.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/space-tangle/space.block.member.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_52 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/proposal-tangle/proposal.token.voting.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/space-tangle/space.accept.member.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/space-tangle/space.block.member.spec.ts chunk_53: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -2004,30 +2286,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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.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.edit.guardian.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_53 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/space-tangle/space.create.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/space-tangle/space.decline.member.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/space-tangle/space.edit.guardian.spec.ts chunk_54: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -2041,30 +2328,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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.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/staking/staking_1.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_54 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/space-tangle/space.join.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/space-tangle/space.leave.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/staking/staking_1.spec.ts chunk_55: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -2078,30 +2370,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_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_4.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_55 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/staking/staking_2.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/staking/staking_3.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/staking/staking_4.spec.ts chunk_56: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -2115,30 +2412,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_5.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/stamp-tangle/stamp-tangle_1_a.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/stamp-tangle/stamp-tangle_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@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_56 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/staking/staking_5.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/stamp-tangle/stamp-tangle_1_a.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/stamp-tangle/stamp-tangle_1_b.spec.ts chunk_57: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -2152,30 +2454,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_57 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/stamp-tangle/stamp-tangle_2.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/stamp-tangle/stamp-tangle_3.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/stamp-tangle/stamp-tangle_4.spec.ts chunk_58: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -2189,30 +2496,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_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/swap/swap_1.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_58 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/stamp-tangle/stamp-tangle_5.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/stamp-tangle/stamp-tangle_6.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/swap/swap_1.spec.ts chunk_59: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -2226,30 +2538,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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/swap/swap_2.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/swap/swap_3_a.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/swap/swap_3_b.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_59 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/swap/swap_2.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/swap/swap_3_a.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/swap/swap_3_b.spec.ts chunk_60: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -2263,30 +2580,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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/swap/swap_4.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/swap/swap_5.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/swap/swap_6.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_60 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/swap/swap_4.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/swap/swap_5.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/swap/swap_6.spec.ts chunk_61: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -2300,30 +2622,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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/swap/swap_7.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/swap/swap_8.spec.ts && - npm run test-tangle:ci -- --forceExit --findRelatedTests ./test-tangle/tangleRequest/simple.token.trade.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_61 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/swap/swap_7.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/swap/swap_8.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/tangleRequest/simple.token.trade.spec.ts chunk_62: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -2337,30 +2664,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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/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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_62 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/tangleRequest/tangle-request.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/token-import/token.import_1.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/token-import/token.import_2.spec.ts chunk_63: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -2374,30 +2706,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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/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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_63 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/token.based.voting/stake.voting.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/token.based.voting/token.based.voting_1.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/token.based.voting/token.based.voting_2.spec.ts chunk_64: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -2411,30 +2748,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_64 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/token.based.voting/token.based.voting_3.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/token.based.voting/token.based.voting_4.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/token.based.voting/token.based.voting_5.spec.ts chunk_65: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -2448,30 +2790,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_65 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/token.mint/token.mint_1.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/token.mint/token.mint_2.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/token.mint/token.mint_3.spec.ts chunk_66: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -2485,30 +2832,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_66 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/token.mint/token.mint_4.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/trade-base-token-order.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/tran.match.spec.ts chunk_67: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -2522,30 +2874,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_67 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/transaction-trigger/transaction-trigger_1.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/transaction-trigger/transaction-trigger_10.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/transaction-trigger/transaction-trigger_11.spec.ts chunk_68: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -2559,30 +2916,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_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_14.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_68 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/transaction-trigger/transaction-trigger_12.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/transaction-trigger/transaction-trigger_13.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/transaction-trigger/transaction-trigger_14.spec.ts chunk_69: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -2596,30 +2958,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_15.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_3.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_69 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/transaction-trigger/transaction-trigger_15.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/transaction-trigger/transaction-trigger_2.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/transaction-trigger/transaction-trigger_3.spec.ts chunk_70: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -2633,30 +3000,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_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_6.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_70 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/transaction-trigger/transaction-trigger_4.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/transaction-trigger/transaction-trigger_5.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/transaction-trigger/transaction-trigger_6.spec.ts chunk_71: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -2670,30 +3042,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_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_9.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_71 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/transaction-trigger/transaction-trigger_7.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/transaction-trigger/transaction-trigger_8.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/transaction-trigger/transaction-trigger_9.spec.ts chunk_72: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -2707,30 +3084,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_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_3.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_72 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/web3/web3_1.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/web3/web3_2.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/web3/web3_3.spec.ts chunk_73: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -2744,30 +3126,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_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_c.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_73 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_1_a.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_1_b.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_1_c.spec.ts chunk_74: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -2781,30 +3168,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_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_3.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_74 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_10_1.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_10_2.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_10_3.spec.ts chunk_75: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -2818,30 +3210,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_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_12_b.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_75 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_11.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_12_a.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_12_b.spec.ts chunk_76: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -2855,30 +3252,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_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_15.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_76 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_13.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_14.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_15.spec.ts chunk_77: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -2892,30 +3294,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_16.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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_77 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_16.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_2.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_4_b.spec.ts chunk_78: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -2929,30 +3336,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_78 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_4.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_5.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_6.spec.ts chunk_79: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -2966,30 +3378,35 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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 - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_79 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_7.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_8.spec.ts && + npm run test -- --findRelatedTests --forceExit ./test-tangle/withdraw-deposit-nft/deposit-withraw-nft_9.spec.ts chunk_80: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -3003,29 +3420,33 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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 - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_80 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/workflow.spec.ts chunk_81: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -3039,28 +3460,33 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_3.only.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_81 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/collection-minting/collection-minting_3.only.spec.ts chunk_82: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -3074,28 +3500,33 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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_11.only.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_82 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-nft-trading/minted-nft-trading_11.only.spec.ts chunk_83: needs: npm-install runs-on: ubuntu-latest timeout-minutes: 20 + + services: + postgres: + image: postgres + env: + POSTGRES_DB: buildcore + POSTGRES_PASSWORD: postgres + POSTGRES_MAX_CONNECTIONS: 400 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -3109,56 +3540,10 @@ jobs: packages/interfaces/node_modules key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - name: Init - run: | - npm run build:functions - npm install -g firebase-tools - - name: Test - working-directory: packages/functions - run: | - 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_15.only.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_83 - path: ./packages/functions/firestore-data/ - retention-days: 1 - chunk_84: - needs: npm-install - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20.x - - uses: actions/cache@v4 - with: - path: | - node_modules - packages/functions/node_modules - packages/interfaces/node_modules - key: ${{ runner.os }}-modules-${{ hashFiles('**/package.json') }} - - name: Init - run: | - npm run build:functions - npm install -g firebase-tools + run: npm run build:functions - name: Test working-directory: packages/functions run: | - 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/soon.snapshot.only.spec.ts - " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data - - name: Archive firestore data - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: firestore-data-test-tangle-chunk_84 - path: ./packages/functions/firestore-data/ - retention-days: 1 + npm run start & + npm run notifier & + npm run test -- --findRelatedTests --forceExit ./test-tangle/minted-token-trade/minted-token-trade_15.only.spec.ts diff --git a/.prettierignore b/.prettierignore index 362a9b7593..f8c80276c6 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,4 +1,5 @@ /dist +**/lib /coverage **/src/**/files **/node_modules diff --git a/.prettierrc b/.prettierrc index 6366838f16..426bb97b58 100644 --- a/.prettierrc +++ b/.prettierrc @@ -5,5 +5,6 @@ "printWidth": 100, "tabWidth": 2, "useTabs": false, - "endOfLine": "auto" + "endOfLine": "auto", + "plugins": ["prettier-plugin-organize-imports"] } diff --git a/data.proto b/data.proto deleted file mode 100644 index 0f241e1dfd..0000000000 --- a/data.proto +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2023 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; - -package google.events.cloud.firestore.v1; - -import "google/protobuf/struct.proto"; -import "google/protobuf/timestamp.proto"; - -option csharp_namespace = "Google.Events.Protobuf.Cloud.Firestore.V1"; -option php_namespace = "Google\\Events\\Cloud\\Firestore\\V1"; -option ruby_package = "Google::Events::Cloud::Firestore::V1"; - -// The data within all Firestore document events. -message DocumentEventData { - // A Document object containing a post-operation document snapshot. - // This is not populated for delete events. - Document value = 1; - - // A Document object containing a pre-operation document snapshot. - // This is only populated for update and delete events. - Document old_value = 2; - - // A DocumentMask object that lists changed fields. - // This is only populated for update events. - DocumentMask update_mask = 3; -} - -// A set of field paths on a document. -message DocumentMask { - // The list of field paths in the mask. - // See [Document.fields][google.cloud.firestore.v1.events.Document.fields] - // for a field path syntax reference. - repeated string field_paths = 1; -} - -// A Firestore document. -message Document { - // The resource name of the document. For example: - // `projects/{project_id}/databases/{database_id}/documents/{document_path}` - string name = 1; - - // The document's fields. - // - // The map keys represent field names. - // - // A simple field name contains only characters `a` to `z`, `A` to `Z`, - // `0` to `9`, or `_`, and must not start with `0` to `9`. For example, - // `foo_bar_17`. - // - // Field names matching the regular expression `__.*__` are reserved. Reserved - // field names are forbidden except in certain documented contexts. The map - // keys, represented as UTF-8, must not exceed 1,500 bytes and cannot be - // empty. - // - // Field paths may be used in other contexts to refer to structured fields - // defined here. For `map_value`, the field path is represented by the simple - // or quoted field names of the containing fields, delimited by `.`. For - // example, the structured field - // `"foo" : { map_value: { "x&y" : { string_value: "hello" }}}` would be - // represented by the field path `foo.x&y`. - // - // Within a field path, a quoted field name starts and ends with `` ` `` and - // may contain any character. Some characters, including `` ` ``, must be - // escaped using a `\`. For example, `` `x&y` `` represents `x&y` and - // `` `bak\`tik` `` represents `` bak`tik ``. - map fields = 2; - - // The time at which the document was created. - // - // This value increases monotonically when a document is deleted then - // recreated. It can also be compared to values from other documents and - // the `read_time` of a query. - google.protobuf.Timestamp create_time = 3; - - // The time at which the document was last changed. - // - // This value is initially set to the `create_time` then increases - // monotonically with each change to the document. It can also be - // compared to values from other documents and the `read_time` of a query. - google.protobuf.Timestamp update_time = 4; -} - -// A message that can hold any of the supported value types. -message Value { - // Must have a value set. - oneof value_type { - // A null value. - google.protobuf.NullValue null_value = 11; - - // A boolean value. - bool boolean_value = 1; - - // An integer value. - int64 integer_value = 2; - - // A double value. - double double_value = 3; - - // A timestamp value. - // - // Precise only to microseconds. When stored, any additional precision is - // rounded down. - google.protobuf.Timestamp timestamp_value = 10; - - // A string value. - // - // The string, represented as UTF-8, must not exceed 1 MiB - 89 bytes. - // Only the first 1,500 bytes of the UTF-8 representation are considered by - // queries. - string string_value = 17; - - // A bytes value. - // - // Must not exceed 1 MiB - 89 bytes. - // Only the first 1,500 bytes are considered by queries. - bytes bytes_value = 18; - - // A reference to a document. For example: - // `projects/{project_id}/databases/{database_id}/documents/{document_path}`. - string reference_value = 5; - - // An array value. - // - // Cannot directly contain another array value, though can contain an - // map which contains another array. - ArrayValue array_value = 9; - - // A map value. - MapValue map_value = 6; - } -} - -// An array value. -message ArrayValue { - // Values in the array. - repeated Value values = 1; -} - -// A map value. -message MapValue { - // The map's fields. - // - // The map keys represent field names. Field names matching the regular - // expression `__.*__` are reserved. Reserved field names are forbidden except - // in certain documented contexts. The map keys, represented as UTF-8, must - // not exceed 1,500 bytes and cannot be empty. - map fields = 1; -} diff --git a/firebase.json b/firebase.json deleted file mode 100644 index 32119dd4fa..0000000000 --- a/firebase.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "firestore": { - "predeploy": ["npm run build:indexes"], - "rules": "firestore.rules", - "indexes": "firestore.indexes.json" - }, - "functions": { - "source": "packages/functions" - }, - "emulators": { - "auth": { "port": 9099 }, - "functions": { "port": 5001 }, - "firestore": { "port": 8080 }, - "ui": { "enabled": true }, - "storage": { "port": 9199 } - }, - "storage": { "rules": "storage.rules" } -} diff --git a/firestore.rules b/firestore.rules deleted file mode 100644 index ca9f680ece..0000000000 --- a/firestore.rules +++ /dev/null @@ -1,6 +0,0 @@ -rules_version = '2'; -service cloud.firestore { - match /{document=**} { - allow read, write: if false; - } -} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index ab67393e06..322fc7528e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,6 +6,7 @@ "": { "name": "root", "workspaces": [ + "packages/notifier", "packages/indexes", "packages/interfaces", "packages/sdk", @@ -17,15 +18,6 @@ "joi-to-typescript": "4.12.0" } }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@adraffy/ens-normalize": { "version": "1.10.1", "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz", @@ -147,13 +139,13 @@ } }, "node_modules/@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" @@ -165,42 +157,42 @@ "integrity": "sha512-HazVq9zwTVwGmqdwYzu7WyQ6FQVZ7SwET0KKQuKm55jD0IfUpZgN0OPIiZG3zV1iSrVYcN0bdwLRXI/VNCYsUA==" }, "node_modules/@babel/code-frame": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", - "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", "dependencies": { - "@babel/highlight": "^7.23.4", - "chalk": "^2.4.2" + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", - "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz", + "integrity": "sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.9.tgz", - "integrity": "sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.5.tgz", + "integrity": "sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.6", + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.5", "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.23.9", - "@babel/parser": "^7.23.9", - "@babel/template": "^7.23.9", - "@babel/traverse": "^7.23.9", - "@babel/types": "^7.23.9", + "@babel/helper-module-transforms": "^7.24.5", + "@babel/helpers": "^7.24.5", + "@babel/parser": "^7.24.5", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.5", + "@babel/types": "^7.24.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -216,13 +208,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", - "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.5.tgz", + "integrity": "sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA==", "dependencies": { - "@babel/types": "^7.23.6", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", + "@babel/types": "^7.24.5", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" }, "engines": { @@ -258,19 +250,19 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.23.10", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.10.tgz", - "integrity": "sha512-2XpP2XhkXzgxecPNEEK8Vz8Asj9aRxt08oKOqtiZoqV2UGZ5T+EkyP9sXQ9nwMxBIG34a7jmasVqoMop7VdPUw==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.5.tgz", + "integrity": "sha512-uRc4Cv8UQWnE4NXlYTIIdM7wfFkOqlFztcC/gVXDKohKoVB3OyonfelUBaJzSwpBntZ2KYGF/9S7asCHsXwW6g==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", - "@babel/helper-member-expression-to-functions": "^7.23.0", + "@babel/helper-member-expression-to-functions": "^7.24.5", "@babel/helper-optimise-call-expression": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-replace-supers": "^7.24.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-split-export-declaration": "^7.24.5", "semver": "^6.3.1" }, "engines": { @@ -312,40 +304,40 @@ } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", - "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.5.tgz", + "integrity": "sha512-4owRteeihKWKamtqg4JmWSsEZU445xpFRXPEwp44HbgbxdWlUV1b4Agg4lkA806Lil5XM/e+FJyS0vj5T6vmcA==", "dev": true, "dependencies": { - "@babel/types": "^7.23.0" + "@babel/types": "^7.24.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz", + "integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==", "dev": true, "dependencies": { - "@babel/types": "^7.22.15" + "@babel/types": "^7.24.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", - "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.5.tgz", + "integrity": "sha512-9GxeY8c2d2mdQUP1Dye0ks3VDyIMS98kt/llQ2nUId8IsWqTF0l1LkSX0/uP7l7MCDrzXS009Hyhe2gzTiGW8A==", "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.20" + "@babel/helper-module-imports": "^7.24.3", + "@babel/helper-simple-access": "^7.24.5", + "@babel/helper-split-export-declaration": "^7.24.5", + "@babel/helper-validator-identifier": "^7.24.5" }, "engines": { "node": ">=6.9.0" @@ -367,22 +359,22 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.5.tgz", + "integrity": "sha512-xjNLDopRzW2o6ba0gKbkZq5YWEBaK3PCyTOY1K2P/O07LGMhMqlMXPxwN4S5/RhWuCobT8z0jrlKGlYmeR1OhQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz", - "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.1.tgz", + "integrity": "sha512-QCR1UqC9BzG5vZl8BMicmZ28RuUBnHhAMddD8yHFHDRH9lLTZ9uUPehX8ctVPT8l0TKblJidqcgUUKGVrePleQ==", "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-member-expression-to-functions": "^7.23.0", "@babel/helper-optimise-call-expression": "^7.22.5" }, "engines": { @@ -393,12 +385,12 @@ } }, "node_modules/@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.5.tgz", + "integrity": "sha512-uH3Hmf5q5n7n8mz7arjUlDOCbttY/DW4DYhE6FUsjKJ/oYC1kQQUvwEQWxRwUpX9qQKRXeqLwWxrqilMrf32sQ==", "dev": true, "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.5" }, "engines": { "node": ">=6.9.0" @@ -417,28 +409,28 @@ } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.5.tgz", + "integrity": "sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q==", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", - "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", + "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz", + "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==", "engines": { "node": ">=6.9.0" } @@ -453,36 +445,37 @@ } }, "node_modules/@babel/helpers": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.9.tgz", - "integrity": "sha512-87ICKgU5t5SzOT7sBMfCOZQ2rHjRU+Pcb9BoILMYz600W6DkVRLFBPwQ18gwUVvggqXivaUakpnxWQGbpywbBQ==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.5.tgz", + "integrity": "sha512-CiQmBMMpMQHwM5m01YnrM6imUG1ebgYJ+fAIW4FZe6m4qHTPaRHti+R8cggAwkdz4oXhtO4/K9JWlh+8hIfR2Q==", "dev": true, "dependencies": { - "@babel/template": "^7.23.9", - "@babel/traverse": "^7.23.9", - "@babel/types": "^7.23.9" + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.5", + "@babel/types": "^7.24.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz", + "integrity": "sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==", "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-validator-identifier": "^7.24.5", "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz", - "integrity": "sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.5.tgz", + "integrity": "sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==", "bin": { "parser": "bin/babel-parser.js" }, @@ -551,12 +544,12 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz", - "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz", + "integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -653,12 +646,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz", - "integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz", + "integrity": "sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -668,13 +661,13 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.3.tgz", - "integrity": "sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.1.tgz", + "integrity": "sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw==", "dev": true, "dependencies": { "@babel/helper-module-transforms": "^7.23.3", - "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-plugin-utils": "^7.24.0", "@babel/helper-simple-access": "^7.22.5" }, "engines": { @@ -685,15 +678,15 @@ } }, "node_modules/@babel/plugin-transform-typescript": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.23.6.tgz", - "integrity": "sha512-6cBG5mBvUu4VUD04OHKnYzbuHNP8huDsD3EDqqpIpsswTDoqHCjLoHb6+QgsV1WsT2nipRqCPgxD3LXnEO7XfA==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.5.tgz", + "integrity": "sha512-E0VWu/hk83BIFUWnsKZ4D81KXjN5L3MobvevOHErASk9IPwKHOkTgvqzvNo1yP/ePJWqqK2SpUR5z+KQbl6NVw==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-create-class-features-plugin": "^7.23.6", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-typescript": "^7.23.3" + "@babel/helper-create-class-features-plugin": "^7.24.5", + "@babel/helper-plugin-utils": "^7.24.5", + "@babel/plugin-syntax-typescript": "^7.24.1" }, "engines": { "node": ">=6.9.0" @@ -722,31 +715,31 @@ } }, "node_modules/@babel/template": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz", - "integrity": "sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", "dependencies": { "@babel/code-frame": "^7.23.5", - "@babel/parser": "^7.23.9", - "@babel/types": "^7.23.9" + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.9.tgz", - "integrity": "sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.5.tgz", + "integrity": "sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA==", "dependencies": { - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.6", + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.5", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.9", - "@babel/types": "^7.23.9", + "@babel/helper-split-export-declaration": "^7.24.5", + "@babel/parser": "^7.24.5", + "@babel/types": "^7.24.5", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -755,12 +748,12 @@ } }, "node_modules/@babel/types": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz", - "integrity": "sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.5.tgz", + "integrity": "sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==", "dependencies": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-string-parser": "^7.24.1", + "@babel/helper-validator-identifier": "^7.24.5", "to-fast-properties": "^2.0.0" }, "engines": { @@ -789,6 +782,10 @@ "resolved": "packages/interfaces", "link": true }, + "node_modules/@build-5/notifier": { + "resolved": "packages/notifier", + "link": true + }, "node_modules/@build-5/sdk": { "resolved": "packages/sdk", "link": true @@ -902,22 +899,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/@eslint/eslintrc/node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -961,12 +942,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -1296,91 +1271,91 @@ ] }, "node_modules/@firebase/app-check-interop-types": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.0.tgz", - "integrity": "sha512-xAxHPZPIgFXnI+vb4sbBjZcde7ZluzPPaSK7Lx3/nmuVk4TjZvnL8ONnkd4ERQKL8WePQySU+pRcWkh8rDf5Sg==" + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.1.tgz", + "integrity": "sha512-NILZbe6RH3X1pZmJnfOfY2gLIrlKmrkUMMrrK6VSXHcSE0eQv28xFEcw16D198i9JYZpy5Kwq394My62qCMaIw==" }, "node_modules/@firebase/app-types": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.0.tgz", - "integrity": "sha512-AeweANOIo0Mb8GiYm3xhTEBVCmPwTYAu9Hcd2qSkLuga/6+j9b1Jskl5bpiSQWy9eJ/j5pavxj6eYogmnuzm+Q==" + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.1.tgz", + "integrity": "sha512-nFGqTYsnDFn1oXf1tCwPAc+hQPxyvBT/QB7qDjwK+IDYThOn63nGhzdUTXxVD9Ca8gUY/e5PQMngeo0ZW/E3uQ==" }, "node_modules/@firebase/auth-interop-types": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.1.tgz", - "integrity": "sha512-VOaGzKp65MY6P5FI84TfYKBXEPi6LmOCSMMzys6o2BN2LOsqy7pCuZCup7NYnfbk5OkkQKzvIfHOzTm0UDpkyg==" + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.2.tgz", + "integrity": "sha512-k3NA28Jfoo0+o391bFjoV9X5QLnUL1WbLhZZRbTQhZdmdGYJfX8ixtNNlHsYQ94bwG0QRbsmvkzDnzuhHrV11w==" }, "node_modules/@firebase/component": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.5.tgz", - "integrity": "sha512-2tVDk1ixi12sbDmmfITK8lxSjmcb73BMF6Qwc3U44hN/J1Fi1QY/Hnnb6klFlbB9/G16a3J3d4nXykye2EADTw==", + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.6.tgz", + "integrity": "sha512-pp7sWqHmAAlA3os6ERgoM3k5Cxff510M9RLXZ9Mc8KFKMBc2ct3RkZTWUF7ixJNvMiK/iNgRLPDrLR2gtRJ9iQ==", "dependencies": { - "@firebase/util": "1.9.4", + "@firebase/util": "1.9.5", "tslib": "^2.1.0" } }, "node_modules/@firebase/database": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.0.3.tgz", - "integrity": "sha512-9fjqLt9JzL46gw9+NRqsgQEMjgRwfd8XtzcKqG+UYyhVeFCdVRQ0Wp6Dw/dvYHnbH5vNEKzNv36dcB4p+PIAAA==", - "dependencies": { - "@firebase/app-check-interop-types": "0.3.0", - "@firebase/auth-interop-types": "0.2.1", - "@firebase/component": "0.6.5", - "@firebase/logger": "0.4.0", - "@firebase/util": "1.9.4", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.0.4.tgz", + "integrity": "sha512-k84cXh+dtpzvY6yOhfyr1B+I1vjvSMtmlqotE0lTNVylc8m5nmOohjzpTLEQDrBWvwACX/VP5fEyajAdmnOKqA==", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.1", + "@firebase/auth-interop-types": "0.2.2", + "@firebase/component": "0.6.6", + "@firebase/logger": "0.4.1", + "@firebase/util": "1.9.5", "faye-websocket": "0.11.4", "tslib": "^2.1.0" } }, "node_modules/@firebase/database-compat": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-1.0.3.tgz", - "integrity": "sha512-7tHEOcMbK5jJzHWyphPux4osogH/adWwncxdMxdBpB9g1DNIyY4dcz1oJdlkXGM/i/AjUBesZsd5CuwTRTBNTw==", - "dependencies": { - "@firebase/component": "0.6.5", - "@firebase/database": "1.0.3", - "@firebase/database-types": "1.0.1", - "@firebase/logger": "0.4.0", - "@firebase/util": "1.9.4", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-1.0.4.tgz", + "integrity": "sha512-GEEDAvsSMAkqy0BIFSVtFzoOIIcKHFfDM4aXHtWL/JCaNn4OOjH7td73jDfN3ALvpIN4hQki0FcxQ89XjqaTjQ==", + "dependencies": { + "@firebase/component": "0.6.6", + "@firebase/database": "1.0.4", + "@firebase/database-types": "1.0.2", + "@firebase/logger": "0.4.1", + "@firebase/util": "1.9.5", "tslib": "^2.1.0" } }, "node_modules/@firebase/database-types": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.1.tgz", - "integrity": "sha512-Tmcmx5XgiI7UVF/4oGg2P3AOTfq3WKEPsm2yf+uXtN7uG/a4WTWhVMrXGYRY2ZUL1xPxv9V33wQRJ+CcrUhVXw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.2.tgz", + "integrity": "sha512-JRigr5JNLEHqOkI99tAGHDZF47469/cJz1tRAgGs8Feh+3ZmQy/vVChSqwMp2DuVUGp9PlmGsNSlpINJ/hDuIA==", "dependencies": { - "@firebase/app-types": "0.9.0", - "@firebase/util": "1.9.4" + "@firebase/app-types": "0.9.1", + "@firebase/util": "1.9.5" } }, "node_modules/@firebase/logger": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.0.tgz", - "integrity": "sha512-eRKSeykumZ5+cJPdxxJRgAC3G5NknY2GwEbKfymdnXtnT0Ucm4pspfR6GT4MUQEDuJwRVbVcSx85kgJulMoFFA==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.1.tgz", + "integrity": "sha512-tTIixB5UJbG9ZHSGZSZdX7THr3KWOLrejZ9B7jYsm6fpwgRNngKznQKA2wgYVyvBc1ta7dGFh9NtJ8n7qfiYIw==", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@firebase/util": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.9.4.tgz", - "integrity": "sha512-WLonYmS1FGHT97TsUmRN3qnTh5TeeoJp1Gg5fithzuAgdZOUtsYECfy7/noQ3llaguios8r5BuXSEiK82+UrxQ==", + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.9.5.tgz", + "integrity": "sha512-PP4pAFISDxsf70l3pEy34Mf3GkkUcVQ3MdKp6aSVb7tcpfUQxnsdV7twDd8EkfB6zZylH6wpUAoangQDmCUMqw==", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@google-cloud/firestore": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-7.3.0.tgz", - "integrity": "sha512-2IftQLAbCuVp0nTd3neeu+d3OYIegJpV/V9R4USQj51LzJcXPe8h8jZ7j3+svSNhJVGy6JsN0T1QqlJdMDhTwg==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-7.6.0.tgz", + "integrity": "sha512-WUDbaLY8UnPxgwsyIaxj6uxCtSDAaUyvzWJykNH5rZ9i92/SZCsPNNMN0ajrVpAR81hPIL4amXTaMJ40y5L+Yg==", "optional": true, "dependencies": { "fast-deep-equal": "^3.1.1", "functional-red-black-tree": "^1.0.1", - "google-gax": "^4.0.4", - "protobufjs": "^7.2.5" + "google-gax": "^4.3.1", + "protobufjs": "^7.2.6" }, "engines": { "node": ">=14.0.0" @@ -1390,7 +1365,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-5.0.0.tgz", "integrity": "sha512-87aeg6QQcEPxGCOthnpUjvw4xAZ57G7pL8FS0C4e/81fr3FjkpUpibf1s2v5XGyGhUVGF4Jfg7yEcxqn2iUw1w==", - "optional": true, "dependencies": { "arrify": "^2.0.0", "extend": "^3.0.2" @@ -1399,11 +1373,18 @@ "node": ">=14.0.0" } }, + "node_modules/@google-cloud/precise-date": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@google-cloud/precise-date/-/precise-date-4.0.0.tgz", + "integrity": "sha512-1TUx3KdaU3cN7nfCdNf+UVqA/PSX29Cjcox3fZZBtINlRrXVTmUkQnCKv2MbBUbCopbK4olAT1IHl76uZyCiVA==", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@google-cloud/projectify": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-4.0.0.tgz", "integrity": "sha512-MmaX6HeSvyPbWGwFq7mXdo0uQZLGBYCwziiLIGq5JVX+/bdI3SAq6bP98trV5eTWfLuvsMcIC1YJOF2vfteLFA==", - "optional": true, "engines": { "node": ">=14.0.0" } @@ -1412,16 +1393,40 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-4.0.0.tgz", "integrity": "sha512-Orxzlfb9c67A15cq2JQEyVc7wEsmFBmHjZWZYQMUyJ1qivXyMwdyNOs9odi79hze+2zqdTtu1E19IM/FtqZ10g==", - "optional": true, "engines": { "node": ">=14" } }, + "node_modules/@google-cloud/pubsub": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@google-cloud/pubsub/-/pubsub-4.3.3.tgz", + "integrity": "sha512-vJKh9L4dHf1XGSDKS1SB0IpqP/sUajQh4/QwhYasuq/NjzfHSxqSt+CuhrFGb5/gioTWE4gce0sn7h1SW7qESg==", + "dependencies": { + "@google-cloud/paginator": "^5.0.0", + "@google-cloud/precise-date": "^4.0.0", + "@google-cloud/projectify": "^4.0.0", + "@google-cloud/promisify": "^4.0.0", + "@opentelemetry/api": "^1.6.0", + "@opentelemetry/semantic-conventions": "~1.21.0", + "@types/duplexify": "^3.6.0", + "@types/long": "^4.0.0", + "arrify": "^2.0.0", + "extend": "^3.0.2", + "google-auth-library": "^9.3.0", + "google-gax": "^4.3.1", + "heap-js": "^2.2.0", + "is-stream-ended": "^0.1.4", + "lodash.snakecase": "^4.1.1", + "p-defer": "^3.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@google-cloud/storage": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-7.7.0.tgz", - "integrity": "sha512-EMCEY+6JiIkx7Dt8NXVGGjy1vRdSGdHkoqZoqjJw7cEBkT7ZkX0c7puedfn1MamnzW5SX4xoa2jVq5u7OWBmkQ==", - "optional": true, + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-7.9.0.tgz", + "integrity": "sha512-PlFl7g3r91NmXtZHXsSEfTZES5ysD3SSBWmX4iBdQ2TFH7tN/Vn/IhnVELCHtgh1vc+uYPZ7XvRYaqtDCdghIA==", "dependencies": { "@google-cloud/paginator": "^5.0.0", "@google-cloud/projectify": "^4.0.0", @@ -1429,11 +1434,11 @@ "abort-controller": "^3.0.0", "async-retry": "^1.3.3", "compressible": "^2.0.12", - "duplexify": "^4.0.0", + "duplexify": "^4.1.3", "ent": "^2.2.0", "fast-xml-parser": "^4.3.0", "gaxios": "^6.0.2", - "google-auth-library": "^9.0.0", + "google-auth-library": "^9.6.3", "mime": "^3.0.0", "mime-types": "^2.0.8", "p-limit": "^3.0.1", @@ -1449,29 +1454,26 @@ "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "optional": true, "bin": { "uuid": "dist/bin/uuid" } }, "node_modules/@grpc/grpc-js": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.10.1.tgz", - "integrity": "sha512-55ONqFytZExfOIjF1RjXPcVmT/jJqFzbbDqxK9jmRV4nxiYWtL9hENSW1Jfx0SdZfrvoqd44YJ/GJTqfRrawSQ==", - "optional": true, + "version": "1.10.6", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.10.6.tgz", + "integrity": "sha512-xP58G7wDQ4TCmN/cMUHh00DS7SRDv/+lC+xFLrTkMIN8h55X5NhZMLYbvy7dSELP15qlI6hPhNCRWVMtZMwqLA==", "dependencies": { - "@grpc/proto-loader": "^0.7.8", - "@types/node": ">=12.12.47" + "@grpc/proto-loader": "^0.7.10", + "@js-sdsl/ordered-map": "^4.4.2" }, "engines": { - "node": "^8.13.0 || >=10.10.0" + "node": ">=12.10.0" } }, "node_modules/@grpc/proto-loader": { - "version": "0.7.10", - "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.10.tgz", - "integrity": "sha512-CAqDfoaQ8ykFd9zqBDn4k6iWT9loLAlc2ETmDFS9JCD70gDcnA4L3AFEo2iV7KyAtAAHFW9ftq1Fz+Vsgq80RQ==", - "optional": true, + "version": "0.7.12", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.12.tgz", + "integrity": "sha512-DCVwMxqYzpUCiDMl7hQ384FqP4T3DbNpXU8pt681l3UWCip1WUiD5JrkImUwCB9a7f2cq4CUTmi5r/xIMRPY1Q==", "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", @@ -1548,9 +1550,9 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", - "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "dev": true }, "node_modules/@img/sharp-darwin-arm64": { @@ -2088,9 +2090,9 @@ } }, "node_modules/@iota/sdk/node_modules/@types/node": { - "version": "18.19.17", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.17.tgz", - "integrity": "sha512-SzyGKgwPzuWp2SHhlpXKzCX0pIOfcI4V2eF37nNBJOhwlegQ83omtVQ1XxZpDE06V/d6AQvfQdPfnw0tRC//Ng==", + "version": "18.19.31", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.31.tgz", + "integrity": "sha512-ArgCD39YpyyrtFKIqMDvjz79jto5fcI/SVUs2HwB+f0dAzq68yqOdyaSivLiLugSziTpNXLQrVb7RZFmdZzbhA==", "dependencies": { "undici-types": "~5.26.4" } @@ -2926,13 +2928,13 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" @@ -2947,9 +2949,9 @@ } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "engines": { "node": ">=6.0.0" } @@ -2960,23 +2962,37 @@ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", - "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@js-sdsl/ordered-map": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", + "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==" + }, "node_modules/@libp2p/interface": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@libp2p/interface/-/interface-1.1.3.tgz", - "integrity": "sha512-id22Ve5acg6CM0jjL8s9cyEaBYWn7z1R+1gy75RpHi0qgW15ifozwi0oFSTGLVA5XzRnNzioDLj+ZP6QwvhIVQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@libp2p/interface/-/interface-1.3.0.tgz", + "integrity": "sha512-K72Km0Co1Z+pXpggWuoAvUUbvwZYvjCcywrHj2Ym3jt2anTE3hzL4rlZrrkzA0YhNTRFRiZ04dnu6WMXT5/4+A==", "dependencies": { - "@multiformats/multiaddr": "^12.1.14", + "@multiformats/multiaddr": "^12.2.1", "it-pushable": "^3.2.3", "it-stream-types": "^2.0.1", - "multiformats": "^13.0.1", + "multiformats": "^13.1.0", "progress-events": "^1.0.0", "uint8arraylist": "^2.4.8" } @@ -3010,9 +3026,9 @@ } }, "node_modules/@metamask/utils": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-8.3.0.tgz", - "integrity": "sha512-WFVcMPEkKKRCJ8DDkZUTVbLlpwgRn98F4VM/WzN89HM8PmHMnCyk/oG0AmK/seOxtik7uC7Bbi2YBC5Z5XB2zw==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-8.4.0.tgz", + "integrity": "sha512-dbIc3C7alOe0agCuBHM1h71UaEaEqOk2W8rAtEn8QGz4haH2Qq7MoK6i7v2guzvkJVVh79c+QCzIqphC3KvrJg==", "dependencies": { "@ethereumjs/tx": "^4.2.0", "@noble/hashes": "^1.3.1", @@ -3021,7 +3037,8 @@ "debug": "^4.3.4", "pony-cause": "^2.1.10", "semver": "^7.5.4", - "superstruct": "^1.0.3" + "superstruct": "^1.0.3", + "uuid": "^9.0.1" }, "engines": { "node": ">=16.0.0" @@ -3057,6 +3074,20 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, + "node_modules/@multiformats/dns": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@multiformats/dns/-/dns-1.0.6.tgz", + "integrity": "sha512-nt/5UqjMPtyvkG9BQYdJ4GfLK3nMqGpFZOzf4hAmIa0sJh2LlS9YKXZ4FgwBDsaHvzZqR/rUFIywIc7pkHNNuw==", + "dependencies": { + "@types/dns-packet": "^5.6.5", + "buffer": "^6.0.3", + "dns-packet": "^5.6.1", + "hashlru": "^2.3.0", + "p-queue": "^8.0.1", + "progress-events": "^1.0.0", + "uint8arrays": "^5.0.2" + } + }, "node_modules/@multiformats/mafmt": { "version": "12.1.6", "resolved": "https://registry.npmjs.org/@multiformats/mafmt/-/mafmt-12.1.6.tgz", @@ -3066,14 +3097,14 @@ } }, "node_modules/@multiformats/multiaddr": { - "version": "12.1.14", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.1.14.tgz", - "integrity": "sha512-1C0Mo73chzu7pTzTquuKs5vUtw70jhqg1i6pUNznGb0WV6RFa6vyB+D697Os5+cLx+DiItrAY6VzMtlGQsMzYg==", + "version": "12.2.1", + "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.2.1.tgz", + "integrity": "sha512-UwjoArBbv64FlaetV4DDwh+PUMfzXUBltxQwdh+uTYnGFzVa8ZfJsn1vt1RJlJ6+Xtrm3RMekF/B+K338i2L5Q==", "dependencies": { "@chainsafe/is-ip": "^2.0.1", "@chainsafe/netmask": "^2.0.0", "@libp2p/interface": "^1.0.0", - "dns-over-http-resolver": "^3.0.2", + "@multiformats/dns": "^1.0.3", "multiformats": "^13.0.0", "uint8-varint": "^2.0.1", "uint8arrays": "^5.0.0" @@ -3104,7 +3135,7 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/@noble/hashes": { + "node_modules/@noble/curves/node_modules/@noble/hashes": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz", "integrity": "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==", @@ -3115,6 +3146,17 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -3150,6 +3192,22 @@ "node": ">= 8" } }, + "node_modules/@opentelemetry/api": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.8.0.tgz", + "integrity": "sha512-I/s6F7yKUDdtMsoBWXJe8Qz40Tui5vsuKCWJEWVL+5q9sSWRzzx6v2KeNsOBEwd94j0eWkpWCH4yB6rZg9Mf0w==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.21.0.tgz", + "integrity": "sha512-lkC8kZYntxVKr7b8xmjCVUgE0a8xgDakPyDo9uSWavXPyYqLgYYGdEd2j8NxihRyb6UwpX3G/hFUF4/9q2V+/g==", + "engines": { + "node": ">=14" + } + }, "node_modules/@pkgr/core": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", @@ -3217,9 +3275,9 @@ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, "node_modules/@scure/base": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.5.tgz", - "integrity": "sha512-Brj9FiG2W1MRQSTB212YVPRrcbjkv48FoZi/u4l/zds/ieRrqsh7aUf6CLwkAq61oKXr/ZlTzlY66gLIj3TFTQ==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.6.tgz", + "integrity": "sha512-ok9AWwhcgYuGG3Zfhyqg+zwl+Wn5uE+dwC0NV/2qQkx4dABbb/bx96vWu8NSj+BNjjSjno+JRYRjle1jV08k3g==", "funding": { "url": "https://paulmillr.com/funding/" } @@ -3237,6 +3295,17 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/@scure/bip32/node_modules/@noble/hashes": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz", + "integrity": "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@scure/bip39": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.2.tgz", @@ -3249,6 +3318,17 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/@scure/bip39/node_modules/@noble/hashes": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz", + "integrity": "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@sideway/address": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", @@ -3321,15 +3401,14 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "optional": true, "engines": { "node": ">= 10" } }, "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", "dev": true }, "node_modules/@tsconfig/node12": { @@ -3412,8 +3491,7 @@ "node_modules/@types/caseless": { "version": "0.12.5", "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.5.tgz", - "integrity": "sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg==", - "optional": true + "integrity": "sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg==" }, "node_modules/@types/chai": { "version": "4.3.11", @@ -3448,6 +3526,7 @@ "version": "2.8.17", "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", + "dev": true, "dependencies": { "@types/node": "*" } @@ -3475,6 +3554,14 @@ "@types/node": "*" } }, + "node_modules/@types/dns-packet": { + "version": "5.6.5", + "resolved": "https://registry.npmjs.org/@types/dns-packet/-/dns-packet-5.6.5.tgz", + "integrity": "sha512-qXOC7XLOEe43ehtWJCMnQXvgcIpv6rPmQ1jXT98Ad8A3TB1Ue50jsCbSSSyuazScEuZ/Q026vHbrOTVkmwA+7Q==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/download": { "version": "8.0.5", "resolved": "https://registry.npmjs.org/@types/download/-/download-8.0.5.tgz", @@ -3486,6 +3573,14 @@ "@types/node": "*" } }, + "node_modules/@types/duplexify": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/@types/duplexify/-/duplexify-3.6.4.tgz", + "integrity": "sha512-2eahVPsd+dy3CL6FugAzJcxoraWhUghZGEQJns1kTKfCXWKJ5iG/VkaB05wRVrDKHfOFKqb0X0kXh91eE99RZg==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/express": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", @@ -3498,9 +3593,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.43", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz", - "integrity": "sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==", + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz", + "integrity": "sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==", "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -3639,9 +3734,9 @@ "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" }, "node_modules/@types/node": { - "version": "20.11.19", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.19.tgz", - "integrity": "sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ==", + "version": "20.12.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", + "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", "dependencies": { "undici-types": "~5.26.4" } @@ -3652,9 +3747,9 @@ "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==" }, "node_modules/@types/qs": { - "version": "6.9.11", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.11.tgz", - "integrity": "sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==" + "version": "6.9.15", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", + "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==" }, "node_modules/@types/range-parser": { "version": "1.2.7", @@ -3665,7 +3760,6 @@ "version": "2.48.12", "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.12.tgz", "integrity": "sha512-G3sY+NpsA9jnwm0ixhAFQSJ3Q9JkpLZpJbI3GMv0mIAT0y3mRabYeINzal5WOChIiaTEGQYlHOKgkaM9EisWHw==", - "optional": true, "dependencies": { "@types/caseless": "*", "@types/node": "*", @@ -3677,7 +3771,6 @@ "version": "2.5.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", - "optional": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", @@ -3693,9 +3786,9 @@ "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" }, "node_modules/@types/semver": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.7.tgz", - "integrity": "sha512-/wdoPq1QqkSj9/QOeKkFquEuPzQbHTWAMPH/PaUMB+JuR31lXhlWXRZ52IpfDYVlDOUBvX09uBrPwxGT1hjNBg==", + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", "dev": true }, "node_modules/@types/send": { @@ -3708,13 +3801,13 @@ } }, "node_modules/@types/serve-static": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", - "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", "dependencies": { "@types/http-errors": "*", - "@types/mime": "*", - "@types/node": "*" + "@types/node": "*", + "@types/send": "*" } }, "node_modules/@types/sharp": { @@ -3761,8 +3854,7 @@ "node_modules/@types/tough-cookie": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", - "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", - "devOptional": true + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==" }, "node_modules/@types/uuid": { "version": "9.0.8", @@ -4218,10 +4310,9 @@ "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==" }, "node_modules/agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", - "optional": true, + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", "dependencies": { "debug": "^4.3.4" }, @@ -4230,13 +4321,14 @@ } }, "node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" }, "funding": { @@ -4244,22 +4336,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, "node_modules/algoliasearch": { "version": "4.22.1", "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.22.1.tgz", @@ -4300,7 +4376,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "devOptional": true, "engines": { "node": ">=8" } @@ -4384,15 +4459,16 @@ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, "node_modules/array-includes": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", - "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", "is-string": "^1.0.7" }, "engines": { @@ -4411,35 +4487,17 @@ "node": ">=8" } }, - "node_modules/array.prototype.filter": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array.prototype.filter/-/array.prototype.filter-1.0.3.tgz", - "integrity": "sha512-VizNcj/RGJiUyQBgzwxzE5oHdeuXY5hSbbmKMlphj1cy1Vl7Pn2asCGbSrru6hSQjmCzqTBPVWAF/whmEOVHbw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-array-method-boxes-properly": "^1.0.0", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/array.prototype.findlastindex": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.4.tgz", - "integrity": "sha512-hzvSHUshSpCflDR1QMUBLHGHP1VIEBegT4pix9H/Z92Xw3ySoy6c2qh7lJWTJnRJ8JCZ9bJNCgTyYaJGcJu6xQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", + "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.5", + "call-bind": "^1.0.7", "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", + "es-abstract": "^1.23.2", "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", "es-shim-unscopables": "^1.0.2" }, "engines": { @@ -4511,7 +4569,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", - "optional": true, "engines": { "node": ">=8" } @@ -4520,7 +4577,6 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", - "optional": true, "dependencies": { "retry": "0.13.1" } @@ -4802,12 +4858,12 @@ "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==" }, "node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", @@ -4815,7 +4871,7 @@ "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.11.0", - "raw-body": "2.5.1", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -4950,6 +5006,14 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, + "node_modules/buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==", + "engines": { + "node": ">=4" + } + }, "node_modules/builtin-modules": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", @@ -5033,9 +5097,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001588", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001588.tgz", - "integrity": "sha512-+hVY9jE44uKLkH0SrUTqxjxqNTOWHsbnQDIKjwkZ3lNTzUUVdBLBGXtj/q5Mp5u98r3droaZAewQuEDzjQdZlQ==", + "version": "1.0.30001614", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001614.tgz", + "integrity": "sha512-jmZQ1VpmlRwHgdP1/uiKzgiAuGOfLEJsYFP4+GBou/QQ4U6IOJCB4NP1c+1p9RGLpwObcT94jA5/uO+F1vBbog==", "dev": true, "funding": [ { @@ -5143,9 +5207,9 @@ } }, "node_modules/cjs-module-lexer": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", - "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz", + "integrity": "sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==", "dev": true }, "node_modules/class-transformer": { @@ -5157,7 +5221,6 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "devOptional": true, "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -5167,38 +5230,14 @@ "node": ">=12" } }, - "node_modules/cloudevents": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/cloudevents/-/cloudevents-8.0.0.tgz", - "integrity": "sha512-G1Z/r8QMFAsP+F1PuZSHzx1ocPy4vrdQMTHD3orjDaM5kccmPU6nMmpVrF07b53aaxcrLbORUmRepY/DgvdhVw==", - "dependencies": { - "ajv": "^8.11.0", - "ajv-formats": "^2.1.1", - "json-bigint": "^1.0.0", - "process": "^0.11.10", - "util": "^0.12.4", - "uuid": "^8.3.2" - }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, "engines": { - "node": ">=16 <=20" - } - }, - "node_modules/cloudevents/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true, - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" } }, "node_modules/collect-v8-coverage": { @@ -5257,6 +5296,11 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "node_modules/colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==" + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -5268,6 +5312,14 @@ "node": ">= 0.8" } }, + "node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "engines": { + "node": ">=14" + } + }, "node_modules/comment-parser": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", @@ -5290,7 +5342,6 @@ "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", - "optional": true, "dependencies": { "mime-db": ">= 1.43.0 < 2" }, @@ -5329,9 +5380,9 @@ "dev": true }, "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "engines": { "node": ">= 0.6" } @@ -5497,6 +5548,57 @@ "node": ">= 6" } }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/dayjs": { "version": "1.11.10", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", @@ -5564,9 +5666,9 @@ } }, "node_modules/dedent": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", - "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", + "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", "dev": true, "peerDependencies": { "babel-plugin-macros": "^3.1.0" @@ -5659,9 +5761,9 @@ } }, "node_modules/detect-libc": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", - "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", "engines": { "node": ">=8" } @@ -5712,14 +5814,26 @@ "dev": true }, "node_modules/dns-over-http-resolver": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/dns-over-http-resolver/-/dns-over-http-resolver-3.0.2.tgz", - "integrity": "sha512-5batkHOjCkuAfrFa+IPmt3jyeZqLtSMfAo1HQp3hfwtzgUwHooecTFplnYC093u5oRNL4CQHCXh3OfER7+vWrA==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/dns-over-http-resolver/-/dns-over-http-resolver-1.2.3.tgz", + "integrity": "sha512-miDiVSI6KSNbi4SVifzO/reD8rMnxgrlnkrlkugOLQpWQTe2qMdHsZp5DmfKjxNE+/T3VAAYLQUZMv9SMr6+AA==", "dependencies": { - "debug": "^4.3.4", + "debug": "^4.3.1", + "native-fetch": "^3.0.0", "receptacle": "^1.3.2" } }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -5744,15 +5858,14 @@ } }, "node_modules/duplexify": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", - "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", - "optional": true, + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.3.tgz", + "integrity": "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==", "dependencies": { "end-of-stream": "^1.4.1", "inherits": "^2.0.3", "readable-stream": "^3.1.1", - "stream-shift": "^1.0.0" + "stream-shift": "^1.0.2" } }, "node_modules/ecdsa-sig-formatter": { @@ -5780,9 +5893,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.677", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.677.tgz", - "integrity": "sha512-erDa3CaDzwJOpyvfKhOiJjBVNnMM0qxHq47RheVVwsSQrgBA9ZSGV9kdaOfZDPXcHzhG7lBxhj6A7KvfLJBd6Q==", + "version": "1.4.752", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.752.tgz", + "integrity": "sha512-P3QJreYI/AUTcfBVrC4zy9KvnZWekViThgQMX/VpJ+IsOBbcX5JFpORM4qWapwWQ+agb2nYAOyn/4PMXOk0m2Q==", "dev": true }, "node_modules/emittery": { @@ -5800,8 +5913,7 @@ "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "devOptional": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/encodeurl": { "version": "1.0.2", @@ -5839,9 +5951,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", - "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz", + "integrity": "sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==", "dev": true, "dependencies": { "graceful-fs": "^4.2.4", @@ -5854,8 +5966,7 @@ "node_modules/ent": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", - "optional": true + "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==" }, "node_modules/err-code": { "version": "3.0.1", @@ -5871,18 +5982,22 @@ } }, "node_modules/es-abstract": { - "version": "1.22.4", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.4.tgz", - "integrity": "sha512-vZYJlk2u6qHYxBOTjAeg7qUxHdNfih64Uu2J8QqWgXZ2cri0ZpJAkzDUK/q593+mvKwlxyaxr6F1Q+3LKoQRgg==", + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", "dev": true, "dependencies": { "array-buffer-byte-length": "^1.0.1", "arraybuffer.prototype.slice": "^1.0.3", - "available-typed-arrays": "^1.0.6", + "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", "es-define-property": "^1.0.0", "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.0.2", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", "es-to-primitive": "^1.2.1", "function.prototype.name": "^1.1.6", "get-intrinsic": "^1.2.4", @@ -5890,15 +6005,16 @@ "globalthis": "^1.0.3", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.1", + "has-proto": "^1.0.3", "has-symbols": "^1.0.3", - "hasown": "^2.0.1", + "hasown": "^2.0.2", "internal-slot": "^1.0.7", "is-array-buffer": "^3.0.4", "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", + "is-shared-array-buffer": "^1.0.3", "is-string": "^1.0.7", "is-typed-array": "^1.1.13", "is-weakref": "^1.0.2", @@ -5906,17 +6022,17 @@ "object-keys": "^1.1.1", "object.assign": "^4.1.5", "regexp.prototype.flags": "^1.5.2", - "safe-array-concat": "^1.1.0", + "safe-array-concat": "^1.1.2", "safe-regex-test": "^1.0.3", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.1", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.14" + "which-typed-array": "^1.1.15" }, "engines": { "node": ">= 0.4" @@ -5925,12 +6041,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/es-array-method-boxes-properly": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", - "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", - "dev": true - }, "node_modules/es-define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", @@ -5950,6 +6060,18 @@ "node": ">= 0.4" } }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-set-tostringtag": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", @@ -5994,7 +6116,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", - "devOptional": true, "engines": { "node": ">=6" } @@ -6137,9 +6258,9 @@ } }, "node_modules/eslint-module-utils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", - "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", + "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", "dev": true, "dependencies": { "debug": "^3.2.7" @@ -6377,22 +6498,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/eslint/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -6536,12 +6641,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/eslint/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, "node_modules/eslint/node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -6623,6 +6722,14 @@ "node": ">= 8" } }, + "node_modules/esm": { + "version": "3.2.25", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", + "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", + "engines": { + "node": ">=6" + } + }, "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", @@ -6714,6 +6821,17 @@ "@scure/bip39": "1.2.2" } }, + "node_modules/ethereum-cryptography/node_modules/@noble/hashes": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz", + "integrity": "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/ethers": { "version": "6.11.1", "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.11.1.tgz", @@ -6796,6 +6914,11 @@ "node": ">=6" } }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==" + }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -6882,16 +7005,16 @@ } }, "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -6938,13 +7061,13 @@ "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "optional": true + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "devOptional": true }, "node_modules/fast-diff": { "version": "1.3.0", @@ -6998,9 +7121,9 @@ "dev": true }, "node_modules/fast-xml-parser": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.3.4.tgz", - "integrity": "sha512-utnwm92SyozgA3hhH2I8qldf2lBqm6qHOICawRNRFu1qMe3+oqr+GcXjGqTmXTMGE5T4eC03kr/rlh5C1IRdZA==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.3.6.tgz", + "integrity": "sha512-M2SovcRxD4+vC493Uc2GZVcZaj66CCJhWurC4viynVSTvrpErCShNcDz1lAho6n9REQKvL/ll4A4/fw6Y9z8nw==", "funding": [ { "type": "github", @@ -7011,7 +7134,6 @@ "url": "https://paypal.me/naturalintelligence" } ], - "optional": true, "dependencies": { "strnum": "^1.0.5" }, @@ -7147,57 +7269,6 @@ "@google-cloud/storage": "^7.7.0" } }, - "node_modules/firebase-functions": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-4.7.0.tgz", - "integrity": "sha512-YgWqA9otWlBUouY4I2yd0vq9SyQdQ6GJxfH7wGJclzS2pzBQHcU5HhE1Vz/xTrWcKJyw8uPN98WtSE9/APUJJg==", - "dependencies": { - "@types/cors": "^2.8.5", - "@types/express": "4.17.3", - "cors": "^2.8.5", - "express": "^4.17.1", - "node-fetch": "^2.6.7", - "protobufjs": "^7.2.2" - }, - "bin": { - "firebase-functions": "lib/bin/firebase-functions.js" - }, - "engines": { - "node": ">=14.10.0" - }, - "peerDependencies": { - "firebase-admin": "^10.0.0 || ^11.0.0 || ^12.0.0" - } - }, - "node_modules/firebase-functions-test": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/firebase-functions-test/-/firebase-functions-test-3.1.1.tgz", - "integrity": "sha512-IlDzcd+8rUd87hD1ZAPXsc3cX5JGdfpKmKlUJWdZJlErdyznwXssPQzbRPX8rh929ZhwmzGpubFBt7itkXAg+A==", - "dev": true, - "dependencies": { - "@types/lodash": "^4.14.104", - "lodash": "^4.17.5", - "ts-deepmerge": "^2.0.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "firebase-admin": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 || ^12.0.0", - "firebase-functions": ">=4.3.0", - "jest": ">=28.0.0" - } - }, - "node_modules/firebase-functions/node_modules/@types/express": { - "version": "4.17.3", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.3.tgz", - "integrity": "sha512-I8cGRJj3pyOLs/HndoP+25vOqhqWkAZsWMEmq1qXy/b/M3ppufecUwaK2/TVDVxcV61/iSdhykUjQQ2DLSrTdg==", - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "*", - "@types/serve-static": "*" - } - }, "node_modules/flat-cache": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", @@ -7341,15 +7412,15 @@ } }, "node_modules/gaxios": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.3.0.tgz", - "integrity": "sha512-p+ggrQw3fBwH2F5N/PAI4k/G/y1art5OxKpb2J2chwNNHM4hHuAOtivjPuirMF4KNKwTTUal/lPfL2+7h2mEcg==", - "optional": true, + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.5.0.tgz", + "integrity": "sha512-R9QGdv8j4/dlNoQbX3hSaK/S0rkMijqjVvW3YM06CoBdbU/VdKd159j4hePpng0KuE6Lh6JJ7UdmVGJZFcAG1w==", "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "is-stream": "^2.0.0", - "node-fetch": "^2.6.9" + "node-fetch": "^2.6.9", + "uuid": "^9.0.1" }, "engines": { "node": ">=14" @@ -7359,7 +7430,6 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "optional": true, "dependencies": { "whatwg-url": "^5.0.0" }, @@ -7379,7 +7449,6 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.0.tgz", "integrity": "sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==", - "optional": true, "dependencies": { "gaxios": "^6.0.0", "json-bigint": "^1.0.0" @@ -7401,7 +7470,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "devOptional": true, "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -7433,7 +7501,6 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, "engines": { "node": ">=8.0.0" } @@ -7468,9 +7535,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.7.2", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.2.tgz", - "integrity": "sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==", + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.3.tgz", + "integrity": "sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg==", "dev": true, "dependencies": { "resolve-pkg-maps": "^1.0.0" @@ -7479,6 +7546,11 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, + "node_modules/getopts": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/getopts/-/getopts-2.3.0.tgz", + "integrity": "sha512-5eDf9fuSXwxBL6q5HX+dhDj+dslFGWzU5thZ9kNKUkcPtaPdatmUFKwHFrLb/uf/WpA4BHET+AX3Scl56cAjpA==" + }, "node_modules/github-from-package": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", @@ -7536,12 +7608,13 @@ } }, "node_modules/globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "dev": true, "dependencies": { - "define-properties": "^1.1.3" + "define-properties": "^1.2.1", + "gopd": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -7571,10 +7644,9 @@ } }, "node_modules/google-auth-library": { - "version": "9.6.3", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.6.3.tgz", - "integrity": "sha512-4CacM29MLC2eT9Cey5GDVK4Q8t+MMp8+OEdOaqD9MG6b0dOyLORaaeJMPQ7EESVgm/+z5EKYyFLxgzBJlJgyHQ==", - "optional": true, + "version": "9.9.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.9.0.tgz", + "integrity": "sha512-9l+zO07h1tDJdIHN74SpnWIlNR+OuOemXlWJlLP9pXy6vFtizgpEzMuwJa4lqY9UAdiAv5DVd5ql0Am916I+aA==", "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", @@ -7588,10 +7660,9 @@ } }, "node_modules/google-gax": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-4.3.1.tgz", - "integrity": "sha512-qpSfslpwqToIgQ+Tf3MjWIDjYK4UFIZ0uz6nLtttlW9N1NQA4PhGf9tlGo6KDYJ4rgL2w4CjXVd0z5yeNpN/Iw==", - "optional": true, + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-4.3.2.tgz", + "integrity": "sha512-2mw7qgei2LPdtGrmd1zvxQviOcduTnsvAWYzCxhOWXK4IQKmQztHnDQwD0ApB690fBQJemFKSU7DnceAy3RLzw==", "dependencies": { "@grpc/grpc-js": "~1.10.0", "@grpc/proto-loader": "^0.7.0", @@ -7636,7 +7707,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz", "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==", - "optional": true, "dependencies": { "gaxios": "^6.0.0", "jws": "^4.0.0" @@ -7764,10 +7834,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hashlru": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/hashlru/-/hashlru-2.3.0.tgz", + "integrity": "sha512-0cMsjjIC8I+D3M44pOQdsy0OHXGLVz6Z0beRuufhKa0KfaD2wGwAev6jILzXsd3/vpnNQJmWyZtIILqM1N+n5A==" + }, "node_modules/hasown": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz", - "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dependencies": { "function-bind": "^1.1.2" }, @@ -7775,6 +7850,14 @@ "node": ">= 0.4" } }, + "node_modules/heap-js": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/heap-js/-/heap-js-2.5.0.tgz", + "integrity": "sha512-kUGoI3p7u6B41z/dp33G6OaL7J4DRqRYwVmeIlwLClx7yaaAy7hoDExnuejTKtuDwfcatGmddHDEOjf6EyIxtQ==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/hosted-git-info": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", @@ -7832,7 +7915,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "optional": true, "dependencies": { "@tootallnate/once": "2", "agent-base": "6", @@ -7846,7 +7928,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "optional": true, "dependencies": { "debug": "4" }, @@ -7858,7 +7939,6 @@ "version": "7.0.4", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", - "optional": true, "dependencies": { "agent-base": "^7.0.2", "debug": "4" @@ -8043,14 +8123,6 @@ "resolved": "https://registry.npmjs.org/interface-store/-/interface-store-2.0.2.tgz", "integrity": "sha512-rScRlhDcz6k199EkHqT8NpM87ebN89ICOzILoBHgaG36/WX50N32BnU/kpZgCGPLhARRAWUUX5/cyaIjt7Kipg==" }, - "node_modules/interfaces": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/interfaces/-/interfaces-0.0.3.tgz", - "integrity": "sha512-nfHWLvWzsZoRme8F21HgoEC69T2vpCHWaFzjptYLzkFiYy6t9GsfWL14Bc0IyvgHRKj51zJg68Rv/emBcbKXgQ==", - "dependencies": { - "underscore": "*" - } - }, "node_modules/internal-slot": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", @@ -8065,6 +8137,14 @@ "node": ">= 0.4" } }, + "node_modules/interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/ip-regex": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.3.0.tgz", @@ -8460,6 +8540,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dev": true, + "dependencies": { + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-date-object": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", @@ -8493,7 +8588,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "devOptional": true, "engines": { "node": ">=8" } @@ -8648,7 +8742,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "devOptional": true, "engines": { "node": ">=8" }, @@ -8656,6 +8749,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-stream-ended": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-stream-ended/-/is-stream-ended-0.1.4.tgz", + "integrity": "sha512-xj0XPvmr7bQFTvirqnFr50o0hQIh6ZItDqloxt5aJrR4NQsYeSsyFQERYGCAzfindAcnKjINnwEEgLx4IqVzQw==" + }, "node_modules/is-string": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", @@ -8908,6 +9006,17 @@ "p-defer": "^4.0.0" } }, + "node_modules/it-pushable/node_modules/p-defer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-4.0.1.tgz", + "integrity": "sha512-Mr5KC5efvAK5VUptYEIopP1bakB85k2IWXaRC0rsh1uwn1L6M0LVml8OIQ4Gudg4oyZakf7FmeRLkMMtZW1i5A==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/it-stream-types": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/it-stream-types/-/it-stream-types-2.0.1.tgz", @@ -8935,14 +9044,6 @@ "readable-stream": "^3.6.0" } }, - "node_modules/it-to-stream/node_modules/p-defer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-3.0.0.tgz", - "integrity": "sha512-ugZxsxmtTln604yeYd29EGrNhazN2lywetzpKhfmQjW/VJmhpDmWbiX+h0zL8V91R0UXkhb3KtPmyq9PZw3aYw==", - "engines": { - "node": ">=8" - } - }, "node_modules/jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", @@ -9578,30 +9679,6 @@ "fsevents": "^2.3.2" } }, - "node_modules/jest-junit": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/jest-junit/-/jest-junit-16.0.0.tgz", - "integrity": "sha512-A94mmw6NfJab4Fg/BlvVOUXzXgF0XIH6EmTgJ5NDPp4xoKq0Kr7sErb+4Xs9nZvu58pJojz5RFGpqnZYJTrRfQ==", - "dev": true, - "dependencies": { - "mkdirp": "^1.0.4", - "strip-ansi": "^6.0.1", - "uuid": "^8.3.2", - "xml": "^1.0.1" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/jest-junit/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/jest-leak-detector": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", @@ -10629,9 +10706,11 @@ } }, "node_modules/joi": { - "version": "17.12.1", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.12.1.tgz", - "integrity": "sha512-vtxmq+Lsc5SlfqotnfVjlViWfOL9nt/avKNbKYizwf6gsCfq9NYY/ceYRMFD8XDdrjJ9abJyScWmhmIiy+XRtQ==", + "version": "17.13.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.0.tgz", + "integrity": "sha512-9qcrTyoBmFZRNHeVP4edKqIUEgFzq7MHvTNSDuHSqkpOPtiBkgNgcmTSqmiw1kw9tdKaiddvIDv/eCJDxmqWCA==", + "dev": true, + "peer": true, "dependencies": { "@hapi/hoek": "^9.3.0", "@hapi/topo": "^5.1.0", @@ -10726,9 +10805,10 @@ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -10828,7 +10908,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", - "optional": true, "dependencies": { "buffer-equal-constant-time": "1.0.1", "ecdsa-sig-formatter": "1.0.11", @@ -10855,7 +10934,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", - "optional": true, "dependencies": { "jwa": "^2.0.0", "safe-buffer": "^5.0.1" @@ -10887,6 +10965,56 @@ "node": ">=6" } }, + "node_modules/knex": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/knex/-/knex-3.1.0.tgz", + "integrity": "sha512-GLoII6hR0c4ti243gMs5/1Rb3B+AjwMOfjYm97pu0FOQa7JH56hgBxYf5WK2525ceSbBY1cjeZ9yk99GPMB6Kw==", + "dependencies": { + "colorette": "2.0.19", + "commander": "^10.0.0", + "debug": "4.3.4", + "escalade": "^3.1.1", + "esm": "^3.2.25", + "get-package-type": "^0.1.0", + "getopts": "2.3.0", + "interpret": "^2.2.0", + "lodash": "^4.17.21", + "pg-connection-string": "2.6.2", + "rechoir": "^0.8.0", + "resolve-from": "^5.0.0", + "tarn": "^3.0.2", + "tildify": "2.0.0" + }, + "bin": { + "knex": "bin/cli.js" + }, + "engines": { + "node": ">=16" + }, + "peerDependenciesMeta": { + "better-sqlite3": { + "optional": true + }, + "mysql": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "pg": { + "optional": true + }, + "pg-native": { + "optional": true + }, + "sqlite3": { + "optional": true + }, + "tedious": { + "optional": true + } + } + }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -10938,8 +11066,7 @@ "node_modules/lodash.camelcase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", - "optional": true + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" }, "node_modules/lodash.clonedeep": { "version": "4.5.0", @@ -10999,6 +11126,11 @@ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" }, + "node_modules/lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==" + }, "node_modules/loglevel": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.1.tgz", @@ -11293,7 +11425,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", - "optional": true, "bin": { "mime": "cli.js" }, @@ -11400,18 +11531,6 @@ "node": ">=0.10.0" } }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/mkdirp-classic": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", @@ -11467,16 +11586,6 @@ "multiaddr": "^10.0.0" } }, - "node_modules/multiaddr/node_modules/dns-over-http-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/dns-over-http-resolver/-/dns-over-http-resolver-1.2.3.tgz", - "integrity": "sha512-miDiVSI6KSNbi4SVifzO/reD8rMnxgrlnkrlkugOLQpWQTe2qMdHsZp5DmfKjxNE+/T3VAAYLQUZMv9SMr6+AA==", - "dependencies": { - "debug": "^4.3.1", - "native-fetch": "^3.0.0", - "receptacle": "^1.3.2" - } - }, "node_modules/multiaddr/node_modules/multiformats": { "version": "9.9.0", "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", @@ -11627,9 +11736,9 @@ } }, "node_modules/node-abi": { - "version": "3.55.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.55.0.tgz", - "integrity": "sha512-uPEjtyh2tFEvWYt4Jw7McOD5FPcHkcxm/tHZc5PWaDB3JYq0rGFUbgaAK+CT5pYpQddBfsZVWI08OwoRfdfbcQ==", + "version": "3.62.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.62.0.tgz", + "integrity": "sha512-CPMcGa+y33xuL1E0TcNIu4YyaZCxnnvkVaEXrsosR3FxN+fV8xvb7Mzpb7IgKler10qeMkE6+Dp8qJhpzdq35g==", "dependencies": { "semver": "^7.3.5" }, @@ -11811,7 +11920,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "optional": true, "engines": { "node": ">= 6" } @@ -11852,14 +11960,15 @@ } }, "node_modules/object.fromentries": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", - "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -11869,27 +11978,28 @@ } }, "node_modules/object.groupby": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.2.tgz", - "integrity": "sha512-bzBq58S+x+uo0VjurFT0UktpKHOZmv4/xePiOA1nbB9pMqpGK7rUPNgf+1YC+7mE+0HzhTMqNUuCqvKhj6FnBw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", "dev": true, "dependencies": { - "array.prototype.filter": "^1.0.3", - "call-bind": "^1.0.5", + "call-bind": "^1.0.7", "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.0.0" + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" } }, "node_modules/object.values": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", - "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -11933,31 +12043,28 @@ } }, "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" }, "engines": { "node": ">= 0.8.0" } }, "node_modules/p-defer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-4.0.0.tgz", - "integrity": "sha512-Vb3QRvQ0Y5XnF40ZUWW7JfLogicVh/EnA5gBIvKDJoYpeI82+1E3AlB9yOcKFS0AhHrWVnAQO39fbR0G99IVEQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-3.0.0.tgz", + "integrity": "sha512-ugZxsxmtTln604yeYd29EGrNhazN2lywetzpKhfmQjW/VJmhpDmWbiX+h0zL8V91R0UXkhb3KtPmyq9PZw3aYw==", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, "node_modules/p-fifo": { @@ -11969,19 +12076,10 @@ "p-defer": "^3.0.0" } }, - "node_modules/p-fifo/node_modules/p-defer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-3.0.0.tgz", - "integrity": "sha512-ugZxsxmtTln604yeYd29EGrNhazN2lywetzpKhfmQjW/VJmhpDmWbiX+h0zL8V91R0UXkhb3KtPmyq9PZw3aYw==", - "engines": { - "node": ">=8" - } - }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "devOptional": true, "dependencies": { "yocto-queue": "^0.1.0" }, @@ -12017,6 +12115,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-queue": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-8.0.1.tgz", + "integrity": "sha512-NXzu9aQJTAzbBqOt2hwsR63ea7yvxJc0PwN/zobNAudYfb1B7R08SzB4TsLeSbUCuG467NhnoT0oO6w1qRO+BA==", + "dependencies": { + "eventemitter3": "^5.0.1", + "p-timeout": "^6.1.2" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/p-retry": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", @@ -12029,6 +12142,17 @@ "node": ">=8" } }, + "node_modules/p-timeout": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-6.1.2.tgz", + "integrity": "sha512-UbD77BuZ9Bc9aABo74gfXhNvzC9Tx7SxtHSh1fxvx3jTLLYvmVhiQZZrJzqqU0jKbN32kb5VOKiLEQI/3bIjgQ==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -12037,6 +12161,11 @@ "node": ">=6" } }, + "node_modules/packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -12124,11 +12253,96 @@ "node": ">=8" } }, + "node_modules/pg": { + "version": "8.11.5", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.5.tgz", + "integrity": "sha512-jqgNHSKL5cbDjFlHyYsCXmQDrfIX/3RsNwYqpd4N0Kt8niLuNoRNH+aazv6cOd43gPh9Y4DjQCtb+X0MH0Hvnw==", + "dependencies": { + "pg-connection-string": "^2.6.4", + "pg-pool": "^3.6.2", + "pg-protocol": "^1.6.1", + "pg-types": "^2.1.0", + "pgpass": "1.x" + }, + "engines": { + "node": ">= 8.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.1.1" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", + "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.2.tgz", + "integrity": "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.2.tgz", + "integrity": "sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg==", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.1.tgz", + "integrity": "sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg==" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pg/node_modules/pg-connection-string": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.4.tgz", + "integrity": "sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA==" + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "dependencies": { + "split2": "^4.1.0" + } + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" }, "node_modules/picomatch": { "version": "2.3.1", @@ -12164,9 +12378,9 @@ } }, "node_modules/pony-cause": { - "version": "2.1.10", - "resolved": "https://registry.npmjs.org/pony-cause/-/pony-cause-2.1.10.tgz", - "integrity": "sha512-3IKLNXclQgkU++2fSi93sQ6BznFuxSLB11HdvZQ6JW/spahf/P1pAHBQEahr20rs0htZW0UDkM1HmA+nZkXKsw==", + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/pony-cause/-/pony-cause-2.1.11.tgz", + "integrity": "sha512-M7LhCsdNbNgiLYiP4WjsfLUuFmCfnjdF6jKe2R9NKl4WFN+HZPGHJZ9lnLP7f9ZnKe3U9nuWD0szirmj+migUg==", "engines": { "node": ">=12.0.0" } @@ -12179,10 +12393,45 @@ "node": ">= 0.4" } }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/prebuild-install": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", - "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.2.tgz", + "integrity": "sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==", "dependencies": { "detect-libc": "^2.0.0", "expand-template": "^2.0.3", @@ -12411,6 +12660,26 @@ "node": ">=6.0.0" } }, + "node_modules/prettier-plugin-organize-imports": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-3.2.4.tgz", + "integrity": "sha512-6m8WBhIp0dfwu0SkgfOxJqh+HpdyfqSSLfKKRZSFbDuEQXDDndb8fTpRWkUrX/uBenkex3MgnVk0J3b3Y5byog==", + "dev": true, + "peerDependencies": { + "@volar/vue-language-plugin-pug": "^1.0.4", + "@volar/vue-typescript": "^1.0.4", + "prettier": ">=2.0", + "typescript": ">=2.9" + }, + "peerDependenciesMeta": { + "@volar/vue-language-plugin-pug": { + "optional": true + }, + "@volar/vue-typescript": { + "optional": true + } + } + }, "node_modules/pretty-format": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", @@ -12437,14 +12706,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", - "engines": { - "node": ">= 0.6.0" - } - }, "node_modules/progress-events": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/progress-events/-/progress-events-1.0.0.tgz", @@ -12476,7 +12737,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/proto3-json-serializer/-/proto3-json-serializer-2.0.1.tgz", "integrity": "sha512-8awBvjO+FwkMd6gNoGFZyqkHZXCFd54CIYTb6De7dPaufGJ2XNW+QUNqbMr8MaAocMdb+KpsD4rxEOaTBDCffA==", - "optional": true, "dependencies": { "protobufjs": "^7.2.5" }, @@ -12542,14 +12802,15 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, "engines": { "node": ">=6" } }, "node_modules/pure-rand": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz", - "integrity": "sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", "dev": true, "funding": [ { @@ -12629,9 +12890,9 @@ } }, "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -12665,9 +12926,9 @@ } }, "node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true }, "node_modules/react-native-fetch-api": { @@ -12678,14 +12939,6 @@ "p-defer": "^3.0.0" } }, - "node_modules/react-native-fetch-api/node_modules/p-defer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-3.0.0.tgz", - "integrity": "sha512-ugZxsxmtTln604yeYd29EGrNhazN2lywetzpKhfmQjW/VJmhpDmWbiX+h0zL8V91R0UXkhb3KtPmyq9PZw3aYw==", - "engines": { - "node": ">=8" - } - }, "node_modules/read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -12777,6 +13030,17 @@ "ms": "^2.1.1" } }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, "node_modules/redent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", @@ -12816,15 +13080,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "devOptional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "engines": { "node": ">=0.10.0" } @@ -12867,7 +13122,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, "engines": { "node": ">=8" } @@ -12907,7 +13161,6 @@ "version": "7.0.2", "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-7.0.2.tgz", "integrity": "sha512-dUOvLMJ0/JJYEn8NrpOaGNE7X3vpI5XlZS/u0ANjqtcZVKnIxP7IgCFwrKTxENw29emmwug53awKtaMm4i9g5w==", - "optional": true, "dependencies": { "@types/request": "^2.48.8", "extend": "^3.0.2", @@ -13016,13 +13269,13 @@ } }, "node_modules/safe-array-concat": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz", - "integrity": "sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", "dev": true, "dependencies": { - "call-bind": "^1.0.5", - "get-intrinsic": "^1.2.2", + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", "has-symbols": "^1.0.3", "isarray": "^2.0.5" }, @@ -13150,16 +13403,16 @@ } }, "node_modules/set-function-length": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz", - "integrity": "sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dependencies": { - "define-data-property": "^1.1.2", + "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.3", + "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.1" + "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -13276,11 +13529,11 @@ } }, "node_modules/side-channel": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz", - "integrity": "sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dependencies": { - "call-bind": "^1.0.6", + "call-bind": "^1.0.7", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.4", "object-inspect": "^1.13.1" @@ -13489,6 +13742,14 @@ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz", "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==" }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "engines": { + "node": ">= 10.x" + } + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -13528,7 +13789,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", "integrity": "sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==", - "optional": true, "dependencies": { "stubs": "^3.0.0" } @@ -13536,8 +13796,7 @@ "node_modules/stream-shift": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", - "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==", - "optional": true + "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==" }, "node_modules/stream-to-it": { "version": "0.2.4", @@ -13588,7 +13847,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "devOptional": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -13599,14 +13857,15 @@ } }, "node_modules/string.prototype.trim": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", - "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -13616,28 +13875,31 @@ } }, "node_modules/string.prototype.trimend": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", - "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -13647,7 +13909,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "devOptional": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -13699,14 +13960,12 @@ "node_modules/strnum": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", - "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", - "optional": true + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==" }, "node_modules/stubs": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", - "integrity": "sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw==", - "optional": true + "integrity": "sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw==" }, "node_modules/subnet-check": { "version": "1.10.1", @@ -13717,9 +13976,9 @@ } }, "node_modules/superstruct": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-1.0.3.tgz", - "integrity": "sha512-8iTn3oSS8nRGn+C2pgXSKPI3jmpm6FExNazNpjvqS6ZUJQCej3PUXEKM8NjHBOs54ExM+LPW/FBRhymrdcCiSg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-1.0.4.tgz", + "integrity": "sha512-7JpaAoX2NGyoFlI9NBh66BQXGONc+uE+MRS5i2iOBKuS4e+ccgMDjATgZldkah+33DakBxDHiss9kvUcGAO8UQ==", "engines": { "node": ">=14.0.0" } @@ -13836,11 +14095,18 @@ "ieee754": "^1.1.13" } }, + "node_modules/tarn": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tarn/-/tarn-3.0.2.tgz", + "integrity": "sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ==", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/teeny-request": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-9.0.0.tgz", "integrity": "sha512-resvxdc6Mgb7YEThw6G6bExlXKkv6+YbuzGg9xuXxSgxJF7Ozs+o8Y9+2R3sArdWdW8nOokoQb1yrpFB0pQK2g==", - "optional": true, "dependencies": { "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0", @@ -13856,7 +14122,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "optional": true, "dependencies": { "debug": "4" }, @@ -13868,7 +14133,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "optional": true, "dependencies": { "agent-base": "6", "debug": "4" @@ -13881,7 +14145,6 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "optional": true, "dependencies": { "whatwg-url": "^5.0.0" }, @@ -13969,6 +14232,14 @@ "resolved": "https://registry.npmjs.org/throttled-queue/-/throttled-queue-2.1.4.tgz", "integrity": "sha512-YGdk8sdmr4ge3g+doFj/7RLF5kLM+Mi7DEciu9PHxnMJZMeVuZeTj31g4VE7ekUffx/IdbvrtOCiz62afg0mkg==" }, + "node_modules/tildify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tildify/-/tildify-2.0.0.tgz", + "integrity": "sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==", + "engines": { + "node": ">=8" + } + }, "node_modules/timeout-abort-controller": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/timeout-abort-controller/-/timeout-abort-controller-1.1.1.tgz", @@ -14026,9 +14297,9 @@ } }, "node_modules/ts-api-utils": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.1.tgz", - "integrity": "sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", "dev": true, "engines": { "node": ">=16" @@ -14037,12 +14308,6 @@ "typescript": ">=4.2.0" } }, - "node_modules/ts-deepmerge": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/ts-deepmerge/-/ts-deepmerge-2.0.7.tgz", - "integrity": "sha512-3phiGcxPSSR47RBubQxPoZ+pqXsEsozLo4G4AlSrsMKTFg9TA3l+3he5BqpUi9wiuDbaHWXH/amlzQ49uEdXtg==", - "dev": true - }, "node_modules/ts-jest": { "version": "29.1.2", "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.2.tgz", @@ -14347,9 +14612,9 @@ } }, "node_modules/typed-array-length": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.5.tgz", - "integrity": "sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", "dev": true, "dependencies": { "call-bind": "^1.0.7", @@ -14397,9 +14662,9 @@ } }, "node_modules/uint8arrays": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-5.0.2.tgz", - "integrity": "sha512-S0GaeR+orZt7LaqzTRs4ZP8QqzAauJ+0d4xvP2lJTA99jIkKsE2FgDs4tGF/K/z5O9I/2W5Yvrh7IuqNeYH+0Q==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-5.0.3.tgz", + "integrity": "sha512-6LBuKji28kHjgPJMkQ6GDaBb1lRwIhyOYq6pDGwYMoDPfImE9SkuYENVmR0yu9yGgs2clHUSY9fKDukR+AXfqQ==", "dependencies": { "multiformats": "^13.0.0" } @@ -14419,11 +14684,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/underscore": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", - "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==" - }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", @@ -14471,6 +14731,7 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, "dependencies": { "punycode": "^2.1.0" } @@ -14711,15 +14972,15 @@ } }, "node_modules/which-typed-array": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.14.tgz", - "integrity": "sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", "dependencies": { - "available-typed-arrays": "^1.0.6", - "call-bind": "^1.0.5", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", - "has-tostringtag": "^1.0.1" + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -14728,11 +14989,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "devOptional": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -14749,7 +15018,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "devOptional": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -14764,7 +15032,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "devOptional": true, "dependencies": { "color-name": "~1.1.4" }, @@ -14775,8 +15042,7 @@ "node_modules/wrap-ansi/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "devOptional": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/wrappy": { "version": "1.0.2", @@ -14816,17 +15082,18 @@ } } }, - "node_modules/xml": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", - "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==", - "dev": true + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "devOptional": true, "engines": { "node": ">=10" } @@ -14841,7 +15108,6 @@ "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "devOptional": true, "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -14867,7 +15133,6 @@ "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "devOptional": true, "engines": { "node": ">=12" } @@ -14885,7 +15150,6 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "devOptional": true, "engines": { "node": ">=10" }, @@ -14899,15 +15163,19 @@ "license": "Apache-2.0", "dependencies": { "@build-5/interfaces": "*", + "@google-cloud/pubsub": "4.3.3", + "@google-cloud/storage": "7.9.0", "dayjs": "1.11.10", - "firebase-admin": "12.0.0", "jsonwebtoken": "9.0.2", - "lodash": "4.17.21" + "knex": "^3.1.0", + "lodash": "4.17.21", + "pg": "^8.11.3" }, "devDependencies": { "@types/lodash": "4.14.202", "dotenv": "16.4.5", "glob": "8.0.3", + "prettier-plugin-organize-imports": "3.2.4", "typescript": "5.3.3" } }, @@ -14928,20 +15196,18 @@ "@iota/util.js": "1.8.6", "@iota/util.js-next": "npm:@iota/util.js@2.0.0-rc.2", "@metamask/eth-sig-util": "7.0.1", + "@types/express": "4.17.21", "algoliasearch": "4.22.1", "axios": "1.6.7", "bip39": "3.1.0", "busboy": "1.6.0", "child-process-promise": "2.2.1", - "cloudevents": "8.0.0", "cors": "2.8.5", "crypto-js": "4.2.0", "dayjs": "1.11.10", "ethers": "6.11.1", + "express": "4.19.2", "files-from-path": "^1.0.4", - "firebase-admin": "12.0.0", - "firebase-functions": "4.7.0", - "interfaces": "0.0.3", "is-ipfs": "8.0.4", "joi": "17.12.1", "js-big-decimal": "2.0.7", @@ -14950,11 +15216,10 @@ "mime-types": "2.1.35", "nft.storage": "7.1.1", "node-ipinfo": "3.5.1", - "protobufjs": "7.2.6", - "rxjs": "7.8.1", "sharp": "0.33.2" }, "devDependencies": { + "@google-cloud/pubsub": "4.3.3", "@types/busboy": "1.5.3", "@types/chai": "4.3.11", "@types/chance": "1.1.6", @@ -14981,10 +15246,8 @@ "eslint-plugin-jsdoc": "48.1.0", "eslint-plugin-prefer-arrow": "1.2.3", "eslint-plugin-prettier": "5.1.3", - "firebase-functions-test": "3.1.1", "glob": "8.0.3", "jest": "29.7.0", - "jest-junit": "16.0.0", "prettier": "3.2.5", "prettier-eslint": "16.3.0", "ts-jest": "29.1.2", @@ -14996,6 +15259,18 @@ "node": "20" } }, + "packages/functions/node_modules/joi": { + "version": "17.12.1", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.12.1.tgz", + "integrity": "sha512-vtxmq+Lsc5SlfqotnfVjlViWfOL9nt/avKNbKYizwf6gsCfq9NYY/ceYRMFD8XDdrjJ9abJyScWmhmIiy+XRtQ==", + "dependencies": { + "@hapi/hoek": "^9.3.0", + "@hapi/topo": "^5.1.0", + "@sideway/address": "^4.1.5", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" + } + }, "packages/indexes": { "name": "@build-5/indexes", "version": "0.0.0", @@ -15011,6 +15286,62 @@ "typescript": "5.3.3" } }, + "packages/notifier": { + "name": "@build-5/notifier", + "version": "0.0.0", + "license": "Apache-2.0", + "dependencies": { + "@google-cloud/pubsub": "4.3.3", + "dotenv": "16.4.5", + "knex": "3.1.0", + "pg": "8.11.3" + }, + "devDependencies": { + "@types/node": "20.12.7", + "typescript": "5.4.5" + } + }, + "packages/notifier/node_modules/pg": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.3.tgz", + "integrity": "sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==", + "dependencies": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.6.2", + "pg-pool": "^3.6.1", + "pg-protocol": "^1.6.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + }, + "engines": { + "node": ">= 8.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.1.1" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "packages/notifier/node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "packages/sdk": { "name": "@build-5/sdk", "version": "0.0.0", @@ -15077,6 +15408,117 @@ "@types/ws": "8.5.10", "typescript": "5.3.3" } + }, + "packages/search/node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "packages/search/node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "packages/search/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "packages/search/node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "packages/search/node_modules/joi": { + "version": "17.12.1", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.12.1.tgz", + "integrity": "sha512-vtxmq+Lsc5SlfqotnfVjlViWfOL9nt/avKNbKYizwf6gsCfq9NYY/ceYRMFD8XDdrjJ9abJyScWmhmIiy+XRtQ==", + "dependencies": { + "@hapi/hoek": "^9.3.0", + "@hapi/topo": "^5.1.0", + "@sideway/address": "^4.1.5", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" + } + }, + "packages/search/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "packages/search/node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } } } } diff --git a/package.json b/package.json index 0ce07ab400..4835b8fce0 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "root", "private": true, "workspaces": [ + "packages/notifier", "packages/indexes", "packages/interfaces", "packages/sdk", @@ -10,12 +11,13 @@ "packages/functions" ], "scripts": { - "build:functions": "npm run build:database && npm i --workspace=packages/functions && npm run build --workspace=packages/functions", + "build:functions": "npm run build:database && npm i --workspace=packages/functions && npm run build --workspace=packages/functions", "build:interfaces": "npm i --workspace=packages/interfaces && npm run build --workspace=packages/interfaces", "build:sdk": "npm run build:interfaces && npm i --workspace=packages/sdk && npm run build --workspace=packages/sdk", "build:indexes": "npm i --workspace=packages/indexes && npm run build --workspace=packages/indexes", "build:database": "npm run build:interfaces && npm i --workspace=packages/database && npm run build --workspace=packages/database", "build:search": "npm run build:database && npm i --workspace=packages/search && npm run build --workspace=packages/search", + "build:notifier": "npm i --workspace=packages/notifier && npm run build --workspace=packages/notifier", "build": "npm i --workspaces && npm run build --workspaces", "clean:search": "rm -rf packages/search/lib; rm -rf packages/search/node_modules", "clean:database": "rm -rf packages/database/lib; rm -rf packages/database/node_modules", @@ -23,7 +25,8 @@ "clean:interfaces": "rm -rf packages/interfaces/lib; rm -rf packages/interfaces/node_modules", "clean:sdk": "rm -rf packages/sdk/lib; rm -rf packages/sdk/node_modules", "clean:indexes": "rm -rf packages/indexes/lib; rm -rf packages/indexes/node_modules", - "clean": "npm run clean:functions; npm run clean:interfaces; npm run clean:indexes; npm run clean:sdk; npm run clean:search; npm run clean:database; rm -rf node_modules", + "clean:notifier": "rm -rf packages/notifier/lib; rm -rf packages/notifier/node_modules", + "clean": "npm run clean:functions; npm run clean:interfaces; npm run clean:indexes; npm run clean:sdk; npm run clean:search; npm run clean:database; npm run clean:notifier; rm -rf node_modules", "prettier": "npx prettier --write ./packages/**", "joi-to-types": "ts-node ./scripts/joi-generator-post.ts && ts-node ./scripts/joi-generator-tangle.ts && npm run prettier", "rebuild": "npm run clean; npm run build", diff --git a/packages/database/.gitignore b/packages/database/.gitignore index 97dba69de2..626c4f31ee 100644 --- a/packages/database/.gitignore +++ b/packages/database/.gitignore @@ -1,2 +1,2 @@ /lib -node_modules/ +/node_modules diff --git a/packages/database/.prettierignore b/packages/database/.prettierignore index 31dae4e582..4a53192272 100644 --- a/packages/database/.prettierignore +++ b/packages/database/.prettierignore @@ -1,2 +1,3 @@ /coverage /lib +.env \ No newline at end of file diff --git a/packages/database/generators/generator.ts b/packages/database/generators/generator.ts new file mode 100644 index 0000000000..3972f4852e --- /dev/null +++ b/packages/database/generators/generator.ts @@ -0,0 +1,7 @@ +import { generatePgInterfaces } from './pg.interface.generator'; + +const main = async () => { + await generatePgInterfaces(); +}; + +main(); diff --git a/packages/database/generators/pg.interface.generator.ts b/packages/database/generators/pg.interface.generator.ts new file mode 100644 index 0000000000..a115eee04d --- /dev/null +++ b/packages/database/generators/pg.interface.generator.ts @@ -0,0 +1,230 @@ +import fs from 'fs'; +import Knex from 'knex'; +import * as knexfile from '../knexfile'; + +const baseFolder = './src/pg/models/'; + +const createCommons = async (isUpdate: boolean) => { + const filePath = baseFolder + `common${isUpdate ? '_update' : ''}.ts`; + let content = setWarningText(filePath); + + if (isUpdate) { + content += 'export interface Update {}\n'; + } + + content += + `export interface BaseRecord${isUpdate ? 'Update extends Update' : ''} {\n` + + (isUpdate ? '' : ' uid: string;') + + ' project?: string;' + + ' createdOn?: Date;' + + ' updatedOn?: Date ;' + + ' createdBy?: string;\n}\n'; + + content += + `export interface BaseSubRecord${isUpdate ? 'Update extends Update' : ''} extends BaseRecord${isUpdate ? 'Update' : ''} {\n` + + `parentId${isUpdate ? '?' : ''}: string;}`; + + fs.writeFileSync(filePath, content); +}; + +const excludeProps = ['uid', 'project', 'createdOn', 'updatedOn', 'createdBy', 'parentId']; + +const createInterfaces = async (tables: { [key: string]: any }) => { + for (const [tableName, props] of Object.entries(tables)) { + const filePath = baseFolder + `${getFileName(tableName)}.ts`; + let content = setWarningText(filePath); + + const interfaceName = getInterfaceName(tableName); + + content += `\nexport interface ${interfaceName} `; + const columns = props.map((p: any) => p.column); + + if (columns.includes('parentId')) { + content += 'extends commons.BaseSubRecord {\n'; + } else { + content += 'extends commons.BaseRecord {\n'; + } + + for (const prop of props) { + if (excludeProps.includes(prop.column)) { + continue; + } + content += + ` ${prop.column}` + + `${prop.nullable ? '?' : ''}` + + `: ${getType(prop.udt, prop.default)}` + + `;\n`; + } + content += `}\n`; + fs.appendFileSync(filePath, content); + + fs.appendFileSync(baseFolder + 'index.ts', `export * from "./${getFileName(tableName)}";\n`); + fs.appendFileSync( + baseFolder + 'index.ts', + `export * from "./${getFileName(tableName)}_update";\n`, + ); + } +}; + +const createUpdateInterfaces = async (tables: { [key: string]: any }) => { + for (const [tableName, props] of Object.entries(tables)) { + const filePath = baseFolder + `${getFileName(tableName)}_update.ts`; + let content = setWarningText(filePath, true); + + const interfaceName = getInterfaceName(tableName); + + content += `\nexport interface ${interfaceName}Update `; + const columns = props.map((p: any) => p.column); + + if (columns.includes('parentId')) { + content += 'extends commons.BaseSubRecordUpdate {\n'; + } else { + content += 'extends commons.BaseRecordUpdate {\n'; + } + + for (const prop of props) { + if (excludeProps.includes(prop.column)) { + continue; + } + const type = getType(prop.udt, prop.default, true); + content += ` ${prop.column}`; + content += '?'; + content += `: ${type}`; + content += `${prop.nullable ? '| null ' : ''}`; + content += type === 'number' ? ' | Increment' : ''; + content += type === 'string[]' ? ' | ArrayUnion | ArrayRemove' : ''; + content += `;\n`; + } + content += `}\n`; + fs.appendFileSync(filePath, content); + + fs.appendFileSync(baseFolder + 'index.ts', `export * from "./${getFileName(tableName)}";\n`); + } +}; + +const getFileName = (tableName: string) => { + const index = tableName.indexOf('_'); + if (index === 0) { + return tableName.substring(1, tableName.length); + } + if (index > -1) { + return tableName.substring(0, index); + } + return tableName; +}; + +const setWarningText = (filePath: string, isUpdate = false) => { + const exists = fs.existsSync(filePath); + if (exists) { + return ''; + } + return ( + '/**\n' + + ' * This file was automatically generated by knex\n' + + ' * Do not modify this file manually\n' + + ' */\n' + + 'import { Increment, ArrayUnion, ArrayRemove } from "../interfaces/common";\n' + + (isUpdate + ? 'import * as commons from "./common_update";\n' + : 'import * as commons from "./common";\n') + ); +}; + +const getInterfaceName = (key: string, prefix = 'Pg') => + prefix + + (key.charAt(0).toUpperCase() + key.slice(1)) + .replace(/_([a-z])/g, (_match, p1) => p1.toUpperCase()) + .replace('_', ''); + +const getType = (udt: string, defaultValue: string, isUpdate = false) => { + switch (udt) { + case 'bool': + return 'boolean'; + case '_varchar': + return 'string[]'; + case 'text': + case 'citext': + case 'money': + case 'numeric': + case 'int8': + case 'char': + case 'character': + case 'bpchar': + case 'varchar': + case 'time': + case 'tsquery': + case 'tsvector': + case 'uuid': + case 'xml': + case 'cidr': + case 'inet': + case 'macaddr': + return 'string'; + case 'smallint': + case 'integer': + case 'int': + case 'int2': + case 'int4': + case 'real': + case 'float': + case 'float4': + case 'float8': + return 'number'; + case '_int4': + case '_float8': + return 'number[]'; + case 'date': + case 'timestamp': + case 'timestamptz': + return 'Date'; + case 'json': + case 'jsonb': + const isArray = defaultValue?.startsWith("'["); + if (isUpdate) { + return 'string' + (isArray ? '' : ' | any'); + } + return 'Record' + (isArray ? '[]' : ''); + case 'bytea': + return 'Buffer'; + case 'interval': + return 'PostgresInterval'; + case '_text': + return 'string[]'; + } +}; + +export const generatePgInterfaces = async () => { + const knex = Knex(knexfile.default); + createCommons(false); + createCommons(true); + + const columns = await knex + .withSchema('information_schema') + .table('columns') + .whereIn('table_schema', ['public']) + .whereNotIn('table_name', ['knex_migrations', 'knex_migrations_lock', 'pg_stat_statements']) + .orderBy('table_schema') + .orderBy('table_name', 'desc') + .orderBy('ordinal_position') + .select( + 'table_schema as schema', + 'table_name as table', + 'column_name as column', + knex.raw("(is_nullable = 'YES') as nullable"), + 'column_default as default', + 'data_type as type', + 'udt_name as udt', + ); + const tables: { [key: string]: any } = columns.reduce( + (acc, act) => ({ + ...acc, + [act.table]: [...(acc[act.table] || []), act], + }), + {} as { [key: string]: any }, + ); + + await createInterfaces(tables); + await createUpdateInterfaces(tables); + await knex.destroy(); + process.exit(); +}; diff --git a/packages/database/knexfile.ts b/packages/database/knexfile.ts new file mode 100644 index 0000000000..0dc38e63b7 --- /dev/null +++ b/packages/database/knexfile.ts @@ -0,0 +1,15 @@ +require('dotenv').config(); +export default { + client: 'pg', + connection: { + user: process.env.DB_USER, + password: process.env.DB_USER_PWD, + database: process.env.DB_NAME, + host: process.env.DB_HOST, + port: Number(process.env.DB_PORT), + }, + migrations: { + directory: './migrations', + extension: 'ts', + }, +}; diff --git a/packages/database/migrations/20240129091246_common.ts b/packages/database/migrations/20240129091246_common.ts new file mode 100644 index 0000000000..440b136433 --- /dev/null +++ b/packages/database/migrations/20240129091246_common.ts @@ -0,0 +1,118 @@ +import type { Knex } from 'knex'; + +export const createTable = async ( + knex: Knex, + col: string, + subCol: string | undefined, + callback: (tableBuilder: Knex.CreateTableBuilder) => any, +) => { + const table = col + (subCol ? `_${subCol}` : '').toLowerCase(); + await knex.schema.createTable(table, callback); + + await knex.raw(` + CREATE OR REPLACE TRIGGER set_updated_on + BEFORE UPDATE ON ${table} + FOR EACH ROW EXECUTE FUNCTION set_updated_on_func(); + `); + + await knex.raw(` + CREATE OR REPLACE FUNCTION ${table}_upsert_func() RETURNS TRIGGER AS $$ + DECLARE + payload JSONB; + BEGIN + payload := jsonb_build_object( + 'table', TG_TABLE_NAME, + 'uid', NEW.uid + ${subCol ? ',\'parentId\', NEW."parentId"' : ''} + ); + + PERFORM pg_notify('onupsert', payload::text); + + RETURN NEW; + END; + $$ LANGUAGE plpgsql; + + CREATE OR REPLACE TRIGGER on_upsert_trigger + AFTER INSERT OR UPDATE ON ${table} + FOR EACH ROW EXECUTE FUNCTION ${table}_upsert_func(); + `); +}; + +export const baseRecord = (knex: Knex, t: Knex.CreateTableBuilder) => { + t.string('uid'); + t.string('project'); + t.timestamp('createdOn').defaultTo(knex.raw('CURRENT_TIMESTAMP')); + t.timestamp('updatedOn').defaultTo(knex.raw('CURRENT_TIMESTAMP')); + t.string('createdBy'); + t.primary(['uid']); +}; + +export const baseSubCollection = (knex: Knex, t: Knex.CreateTableBuilder) => { + t.string('uid'); + t.string('parentId'); + t.string('project'); + t.timestamp('createdOn').defaultTo(knex.raw('CURRENT_TIMESTAMP')); + t.timestamp('updatedOn').defaultTo(knex.raw('CURRENT_TIMESTAMP')); + t.string('createdBy'); + t.primary(['uid', 'parentId']); +}; + +export const mintingData = (t: Knex.CreateTableBuilder, base = 'mintingData_') => { + t.string(base + 'address'); + t.string(base + 'network'); + + t.timestamp(base + 'mintedOn'); + t.string(base + 'mintedBy'); + + t.string(base + 'blockId'); + t.string(base + 'nftId'); + t.double(base + 'storageDeposit'); + + t.string(base + 'aliasBlockId'); + t.string(base + 'aliasId'); + t.double(base + 'aliasStorageDeposit'); + + t.string(base + 'mintingOrderId'); + + t.double(base + 'nftsToMint'); + t.double(base + 'nftMediaToUpload'); + t.double(base + 'nftMediaToPrepare'); + + t.string(base + 'unsoldMintingOptions'); + + t.double(base + 'newPrice'); + t.double(base + 'nftsStorageDeposit'); +}; + +export const networkEnum = ['smr', 'rms', 'iota', 'atoi']; + +export const mediaStatusEnum = ['uploaded', 'pending_upload', 'error', 'prepare_ipfs']; + +export const accessEnum = [ + 'open', + 'members_only', + 'guardians_only', + 'members_with_badge', + 'members_with_nft_from_collection', +]; + +export const unsoldMintingOptionsEnum = [ + 'burn_unsold', + 'set_new_price', + 'keep_price', + 'take_ownership', +]; + +export async function up(knex: Knex): Promise { + await knex.raw(` + CREATE OR REPLACE FUNCTION set_updated_on_func() + RETURNS TRIGGER AS $$ + BEGIN + NEW."updatedOn" = NOW(); + RETURN NEW; + END; + $$ LANGUAGE plpgsql; + `); +} + +export async function down(): Promise {} diff --git a/packages/database/migrations/20240129135000_auction.ts b/packages/database/migrations/20240129135000_auction.ts new file mode 100644 index 0000000000..afc0ed188e --- /dev/null +++ b/packages/database/migrations/20240129135000_auction.ts @@ -0,0 +1,31 @@ +import { COL } from '@build-5/interfaces'; +import { Knex } from 'knex'; +import { baseRecord, createTable } from './20240129091246_common'; + +export async function up(knex: Knex): Promise { + await createTable(knex, COL.AUCTION, undefined, (table) => { + baseRecord(knex, table); + table.string('space'); + table.timestamp('auctionFrom'); + table.timestamp('auctionTo'); + table.double('auctionLength'); + table.timestamp('extendedAuctionTo'); + table.double('extendedAuctionLength'); + table.double('extendAuctionWithin'); + table.double('auctionFloorPrice'); + table.double('minimalBidIncrement'); + table.string('auctionHighestBidder'); + table.double('auctionHighestBid'); + table.double('maxBids'); + table.string('type'); + table.string('network'); + table.string('nftId'); + table.string('targetAddress'); + table.boolean('active'); + table.boolean('topUpBased'); + + table.jsonb('bids').defaultTo([]); + }); +} + +export async function down(_knex: Knex): Promise {} diff --git a/packages/database/migrations/20240129135000_award.ts b/packages/database/migrations/20240129135000_award.ts new file mode 100644 index 0000000000..c27a5bcf5d --- /dev/null +++ b/packages/database/migrations/20240129135000_award.ts @@ -0,0 +1,63 @@ +import { COL, SUB_COL } from '@build-5/interfaces'; +import type { Knex } from 'knex'; +import { baseRecord, baseSubCollection, createTable } from './20240129091246_common'; + +export async function up(knex: Knex): Promise { + await createTable(knex, COL.AWARD, undefined, (table) => { + baseRecord(knex, table); + + table.string('name'); + table.text('description'); + table.string('space'); + table.timestamp('endDate'); + table.double('issued'); + table.double('badgesMinted'); + table.boolean('approved'); + table.boolean('rejected'); + table.boolean('completed'); + table.string('network'); + table.double('aliasStorageDeposit'); + table.double('collectionStorageDeposit'); + table.double('nttStorageDeposit'); + table.double('nativeTokenStorageDeposit'); + table.boolean('funded'); + table.string('fundingAddress'); + table.string('fundedBy'); + table.string('address'); + table.double('airdropClaimed'); + table.string('aliasBlockId'); + table.string('aliasId'); + table.string('collectionBlockId'); + table.string('collectionId'); + table.string('mediaStatus'); + table.double('mediaUploadErrorCount'); + table.boolean('isLegacy'); + table.string('badge_name'); + table.text('badge_description'); + table.double('badge_total'); + table.string('badge_type'); + table.double('badge_tokenReward'); + table.string('badge_tokenUid'); + table.string('badge_tokenId'); + table.string('badge_tokenSymbol'); + table.string('badge_image'); + table.string('badge_ipfsMedia'); + table.string('badge_ipfsMetadata'); + table.string('badge_ipfsRoot'); + table.double('badge_lockTime'); + }); + + await createTable(knex, COL.AWARD, SUB_COL.OWNERS, (table) => { + baseSubCollection(knex, table); + }); + + await createTable(knex, COL.AWARD, SUB_COL.PARTICIPANTS, (table) => { + baseSubCollection(knex, table); + table.text('comment'); + table.boolean('completed'); + table.double('count'); + table.double('tokenReward'); + }); +} + +export async function down(): Promise {} diff --git a/packages/database/migrations/20240129135000_change.ts b/packages/database/migrations/20240129135000_change.ts new file mode 100644 index 0000000000..4487e2f018 --- /dev/null +++ b/packages/database/migrations/20240129135000_change.ts @@ -0,0 +1,10 @@ +import type { Knex } from 'knex'; + +export async function up(knex: Knex): Promise { + await knex.schema.createTable('changes', (t) => { + t.increments('uid').primary(); + t.jsonb('change').defaultTo({}); + }); +} + +export async function down(): Promise {} diff --git a/packages/database/migrations/20240129135000_collection.ts b/packages/database/migrations/20240129135000_collection.ts new file mode 100644 index 0000000000..58e8e1c856 --- /dev/null +++ b/packages/database/migrations/20240129135000_collection.ts @@ -0,0 +1,86 @@ +import { COL, SUB_COL } from '@build-5/interfaces'; +import type { Knex } from 'knex'; +import { baseRecord, baseSubCollection, createTable, mintingData } from './20240129091246_common'; + +export async function up(knex: Knex): Promise { + await createTable(knex, COL.COLLECTION, SUB_COL.STATS, (table) => { + baseSubCollection(knex, table); + + table.double('votes_upvotes'); + table.double('votes_downvotes'); + table.double('votes_voteDiff'); + + table.double('ranks_count'); + table.double('ranks_sum'); + table.double('ranks_avg'); + }); + + await createTable(knex, COL.COLLECTION, undefined, (table) => { + baseRecord(knex, table); + table.string('name'); + table.text('description'); + table.text('bannerUrl'); + table.double('royaltiesFee'); + table.string('royaltiesSpace'); + + table.double('total'); + table.double('totalTrades'); + table.timestamp('lastTradedOn'); + table.double('sold'); + table.text('discord'); + table.text('url'); + table.text('twitter'); + table.boolean('approved'); + table.boolean('rejected'); + table.boolean('limitedEdition'); + table.string('ipfsMedia'); + table.string('ipfsMetadata'); + table.string('ipfsRoot'); + + table.string('category'); + table.integer('type'); + table.integer('access'); + table.specificType('accessAwards', 'TEXT[]').defaultTo('{}'); + table.specificType('accessCollections', 'TEXT[]').defaultTo('{}'); + + table.string('space'); + table.timestamp('availableFrom'); + table.double('price'); + table.double('availablePrice'); + table.boolean('onePerMemberOnly'); + table.string('placeholderNft'); + table.text('placeholderUrl'); + table.string('status'); + + mintingData(table); + + table.double('rankCount'); + table.double('rankSum'); + table.double('rankAvg'); + table.string('mediaStatus'); + table.double('mediaUploadErrorCount'); + table.double('stakedNft'); + table.double('nftsOnSale'); + table.double('nftsOnAuction'); + table.double('availableNfts'); + table.double('floorPrice'); + + table.double('votes_upvotes'); + table.double('votes_downvotes'); + table.double('votes_voteDiff'); + + table.jsonb('discounts').defaultTo([]); + }); + + await createTable(knex, COL.COLLECTION, SUB_COL.RANKS, (t) => { + baseSubCollection(knex, t); + t.double('rank'); + }); + + await createTable(knex, COL.COLLECTION, SUB_COL.VOTES, (t) => { + baseSubCollection(knex, t); + t.double('direction'); + }); +} + +export async function down(): Promise {} diff --git a/packages/database/migrations/20240129135000_member.ts b/packages/database/migrations/20240129135000_member.ts new file mode 100644 index 0000000000..e4b99e3ff3 --- /dev/null +++ b/packages/database/migrations/20240129135000_member.ts @@ -0,0 +1,31 @@ +import { COL } from '@build-5/interfaces'; +import type { Knex } from 'knex'; +import { baseRecord, createTable } from './20240129091246_common'; + +export async function up(knex: Knex): Promise { + await createTable(knex, COL.MEMBER, undefined, (table) => { + baseRecord(knex, table); + table.string('nonce'); + table.string('name'); + table.text('about'); + table.string('avatarNft'); + table.text('avatar'); + table.text('discord'); + table.text('twitter'); + table.text('github'); + + table.string('smrAddress').defaultTo(''); + table.string('rmsAddress').defaultTo(''); + table.string('iotaAddress').defaultTo(''); + table.string('atoiAddress').defaultTo(''); + + table.specificType('prevValidatedAddresses', 'TEXT[]').defaultTo('{}'); + table.double('tokenTradingFeePercentage'); + table.double('tokenPurchaseFeePercentage'); + table.double('awardsCompleted'); + + table.jsonb('spaces').defaultTo({}); + }); +} + +export async function down(): Promise {} diff --git a/packages/database/migrations/20240129135000_milestone.ts b/packages/database/migrations/20240129135000_milestone.ts new file mode 100644 index 0000000000..651451f934 --- /dev/null +++ b/packages/database/migrations/20240129135000_milestone.ts @@ -0,0 +1,35 @@ +import { COL, SUB_COL } from '@build-5/interfaces'; +import type { Knex } from 'knex'; +import { baseRecord, baseSubCollection, createTable } from './20240129091246_common'; + +export async function up(knex: Knex): Promise { + for (const col of [COL.MILESTONE, COL.MILESTONE_SMR, COL.MILESTONE_RMS]) { + await createTable(knex, col, undefined, (t) => { + baseRecord(knex, t); + + t.boolean('completed'); + t.timestamp('completedOn'); + + t.string('listenerNodeId'); + + t.integer('milestone'); + t.timestamp('milestoneTimestamp'); + + t.integer('trxConflictCount'); + t.integer('trxFailedCount'); + t.integer('trxValidCount'); + }); + + await createTable(knex, col, SUB_COL.TRANSACTIONS, (t) => { + baseSubCollection(knex, t); + t.integer('PayloadSize'); + t.text('blockId'); + t.integer('milestone'); + t.jsonb('payload').defaultTo({}); + t.boolean('processed').defaultTo(false); + t.timestamp('processedOn'); + }); + } +} + +export async function down(): Promise {} diff --git a/packages/database/migrations/20240129135000_mnemonic.ts b/packages/database/migrations/20240129135000_mnemonic.ts new file mode 100644 index 0000000000..039c8cb9e4 --- /dev/null +++ b/packages/database/migrations/20240129135000_mnemonic.ts @@ -0,0 +1,17 @@ +import { COL } from '@build-5/interfaces'; +import type { Knex } from 'knex'; +import { baseRecord, createTable } from './20240129091246_common'; + +export async function up(knex: Knex): Promise { + await createTable(knex, COL.MNEMONIC, undefined, (table) => { + baseRecord(knex, table); + table.text('mnemonic'); + table.string('network'); + table.string('lockedBy').defaultTo(''); + table.specificType('consumedOutputIds', 'TEXT[]').defaultTo('{}'); + table.specificType('consumedNftOutputIds', 'TEXT[]').defaultTo('{}'); + table.specificType('consumedAliasOutputIds', 'TEXT[]').defaultTo('{}'); + }); +} + +export async function down(): Promise {} diff --git a/packages/database/migrations/20240129135000_nft.ts b/packages/database/migrations/20240129135000_nft.ts new file mode 100644 index 0000000000..3b0391f200 --- /dev/null +++ b/packages/database/migrations/20240129135000_nft.ts @@ -0,0 +1,59 @@ +import { COL } from '@build-5/interfaces'; +import type { Knex } from 'knex'; +import { baseRecord, createTable, mintingData } from './20240129091246_common'; + +export async function up(knex: Knex): Promise { + await createTable(knex, COL.NFT, undefined, (table) => { + baseRecord(knex, table); + table.string('name'); + table.text('description'); + table.string('collection'); + table.string('owner'); + table.boolean('isOwned'); + table.text('media'); + table.string('ipfsMedia'); + table.string('ipfsMetadata'); + table.string('ipfsRoot'); + table.integer('saleAccess'); + table.specificType('saleAccessMembers', 'TEXT[]').defaultTo('{}'); + table.integer('available'); + table.timestamp('availableFrom'); + table.timestamp('auctionFrom'); + table.timestamp('auctionTo'); + table.timestamp('extendedAuctionTo'); + table.double('auctionHighestBid'); + table.string('auctionHighestBidder'); + table.double('price'); + table.double('totalTrades'); + table.timestamp('lastTradedOn'); + table.double('availablePrice'); + table.double('auctionFloorPrice'); + table.double('auctionLength'); + table.double('extendedAuctionLength'); + table.double('extendAuctionWithin'); + + table.integer('type'); + table.string('space'); + table.text('url'); + table.boolean('approved'); + table.boolean('rejected'); + table.jsonb('properties').defaultTo({}); + table.jsonb('stats').defaultTo({}); + table.boolean('placeholderNft'); + table.double('position'); + table.boolean('locked'); + table.string('lockedBy'); + table.boolean('sold'); + mintingData(table); + mintingData(table, 'depositData_'); + table.string('status'); + table.boolean('hidden'); + table.string('mediaStatus'); + table.double('mediaUploadErrorCount'); + table.timestamp('soldOn'); + table.boolean('setAsAvatar'); + table.string('auction'); + }); +} + +export async function down(): Promise {} diff --git a/packages/database/migrations/20240129135000_nft_stake.ts b/packages/database/migrations/20240129135000_nft_stake.ts new file mode 100644 index 0000000000..7b589c3256 --- /dev/null +++ b/packages/database/migrations/20240129135000_nft_stake.ts @@ -0,0 +1,19 @@ +import { COL } from '@build-5/interfaces'; +import type { Knex } from 'knex'; +import { baseRecord, createTable } from './20240129091246_common'; + +export async function up(knex: Knex): Promise { + await createTable(knex, COL.NFT_STAKE, undefined, (table) => { + baseRecord(knex, table); + table.string('member'); + table.string('space'); + table.string('collection'); + table.string('nft'); + table.double('weeks'); + table.timestamp('expiresAt'); + table.boolean('expirationProcessed'); + table.string('type'); + }); +} + +export async function down(): Promise {} diff --git a/packages/database/migrations/20240129135000_notification.ts b/packages/database/migrations/20240129135000_notification.ts new file mode 100644 index 0000000000..3bacbd1e30 --- /dev/null +++ b/packages/database/migrations/20240129135000_notification.ts @@ -0,0 +1,16 @@ +import { COL } from '@build-5/interfaces'; +import { Knex } from 'knex'; +import { baseRecord, createTable } from './20240129091246_common'; + +export async function up(knex: Knex): Promise { + await createTable(knex, COL.NOTIFICATION, undefined, (table) => { + baseRecord(knex, table); + + table.string('space'); + table.string('member'); + table.string('type'); + table.jsonb('params').defaultTo({}); + }); +} + +export async function down(_knex: Knex): Promise {} diff --git a/packages/database/migrations/20240129135000_project.ts b/packages/database/migrations/20240129135000_project.ts new file mode 100644 index 0000000000..abe44e430d --- /dev/null +++ b/packages/database/migrations/20240129135000_project.ts @@ -0,0 +1,30 @@ +import { COL, SUB_COL } from '@build-5/interfaces'; +import type { Knex } from 'knex'; +import { baseRecord, baseSubCollection, createTable } from './20240129091246_common'; + +export async function up(knex: Knex): Promise { + await createTable(knex, COL.PROJECT, undefined, (table) => { + baseRecord(knex, table); + + table.string('name'); + table.string('contactEmail'); + table.boolean('deactivated'); + table.string('config_billing'); + table.specificType('config_tiers', 'FLOAT[]'); + table.specificType('config_tokenTradingFeeDiscountPercentage', 'FLOAT[]'); + table.string('config_nativeTokenSymbol'); + table.string('config_nativeTokenUid'); + table.jsonb('otr').defaultTo({}); + }); + + await createTable(knex, COL.PROJECT, SUB_COL.ADMINS, (table) => { + baseSubCollection(knex, table); + }); + + await createTable(knex, COL.PROJECT, SUB_COL._API_KEY, (table) => { + baseSubCollection(knex, table); + table.text('token'); + }); +} + +export async function down(): Promise {} diff --git a/packages/database/migrations/20240129135000_proposal.ts b/packages/database/migrations/20240129135000_proposal.ts new file mode 100644 index 0000000000..867f41f1fb --- /dev/null +++ b/packages/database/migrations/20240129135000_proposal.ts @@ -0,0 +1,52 @@ +import { COL, SUB_COL } from '@build-5/interfaces'; +import type { Knex } from 'knex'; +import { baseRecord, baseSubCollection, createTable } from './20240129091246_common'; + +export async function up(knex: Knex): Promise { + await createTable(knex, COL.PROPOSAL, SUB_COL.MEMBERS, (t) => { + baseSubCollection(knex, t); + t.boolean('voted'); + t.double('weight'); + t.string('tranId'); + t.jsonb('values').defaultTo({}); + }); + + await createTable(knex, COL.PROPOSAL, SUB_COL.OWNERS, (t) => { + baseSubCollection(knex, t); + }); + + await createTable(knex, COL.PROPOSAL, undefined, (t) => { + baseRecord(knex, t); + t.string('space'); + t.string('name'); + t.text('description'); + t.text('additionalInfo'); + t.integer('type'); + t.boolean('approved'); + t.boolean('rejected'); + t.string('approvedBy'); + t.string('rejectedBy'); + t.string('eventId'); + t.double('totalWeight'); + t.string('token'); + t.boolean('completed'); + t.double('rank'); + + t.timestamp('settings_startDate'); + t.timestamp('settings_endDate'); + t.boolean('settings_guardiansOnly'); + t.string('settings_addRemoveGuardian'); + t.jsonb('settings_spaceUpdateData').defaultTo({}); + t.boolean('settings_onlyGuardians'); + t.specificType('settings_stakeRewardIds', 'TEXT[]').defaultTo('{}'); + + t.specificType('settings_awards', 'TEXT[]').defaultTo('{}'); + + t.jsonb('questions').defaultTo([]); + t.jsonb('members').defaultTo([]); + + t.jsonb('results').defaultTo({}); + }); +} + +export async function down(): Promise {} diff --git a/packages/database/migrations/20240129135000_soon_snap.ts b/packages/database/migrations/20240129135000_soon_snap.ts new file mode 100644 index 0000000000..82735e47a4 --- /dev/null +++ b/packages/database/migrations/20240129135000_soon_snap.ts @@ -0,0 +1,16 @@ +import { COL } from '@build-5/interfaces'; +import type { Knex } from 'knex'; +import { baseRecord, createTable } from './20240129091246_common'; + +export async function up(knex: Knex): Promise { + await createTable(knex, COL.SOON_SNAP, undefined, (t) => { + baseRecord(knex, t); + t.double('count'); + t.double('paidOut'); + t.timestamp('lastPaidOutOn'); + t.string('ethAddress'); + t.boolean('ethAddressVerified'); + }); +} + +export async function down(): Promise {} diff --git a/packages/database/migrations/20240129135000_space.ts b/packages/database/migrations/20240129135000_space.ts new file mode 100644 index 0000000000..ce010f234b --- /dev/null +++ b/packages/database/migrations/20240129135000_space.ts @@ -0,0 +1,60 @@ +import { COL, SUB_COL } from '@build-5/interfaces'; +import type { Knex } from 'knex'; +import { baseRecord, baseSubCollection, createTable } from './20240129091246_common'; + +export async function up(knex: Knex): Promise { + await createTable(knex, COL.SPACE, undefined, (table) => { + baseRecord(knex, table); + table.string('name'); + table.text('about'); + table.boolean('open'); + table.boolean('tokenBased'); + table.double('minStakedValue'); + table.text('github'); + table.text('twitter'); + table.text('discord'); + table.text('avatarUrl'); + table.text('bannerUrl'); + table.double('totalGuardians'); + table.double('totalMembers'); + table.double('totalPendingMembers'); + + table.string('smrAddress').defaultTo(''); + table.string('rmsAddress').defaultTo(''); + table.string('iotaAddress').defaultTo(''); + table.string('atoiAddress').defaultTo(''); + + table.specificType('prevValidatedAddresses', 'TEXT[]').defaultTo('{}'); + table.string('vaultAddress'); + table.string('collectionId'); + table.boolean('claimed'); + table.string('ipfsMedia'); + table.string('ipfsMetadata'); + table.string('ipfsRoot'); + table.string('mediaStatus'); + table.double('mediaUploadErrorCount'); + table.string('alias_address'); + table.string('alias_aliasId'); + table.string('alias_blockId'); + table.timestamp('alias_mintedOn'); + table.string('alias_mintedBy'); + }); + + await createTable(knex, COL.SPACE, SUB_COL.GUARDIANS, (table) => { + baseSubCollection(knex, table); + }); + + await createTable(knex, COL.SPACE, SUB_COL.MEMBERS, (table) => { + baseSubCollection(knex, table); + }); + + await createTable(knex, COL.SPACE, SUB_COL.BLOCKED_MEMBERS, (table) => { + baseSubCollection(knex, table); + }); + + await createTable(knex, COL.SPACE, SUB_COL.KNOCKING_MEMBERS, (table) => { + baseSubCollection(knex, table); + }); +} + +export async function down(): Promise {} diff --git a/packages/database/migrations/20240129135000_stake.ts b/packages/database/migrations/20240129135000_stake.ts new file mode 100644 index 0000000000..d25d94683d --- /dev/null +++ b/packages/database/migrations/20240129135000_stake.ts @@ -0,0 +1,25 @@ +import { COL } from '@build-5/interfaces'; +import type { Knex } from 'knex'; +import { baseRecord, createTable } from './20240129091246_common'; + +export async function up(knex: Knex): Promise { + await createTable(knex, COL.STAKE, undefined, (table) => { + baseRecord(knex, table); + table.string('member'); + table.string('space'); + table.string('token'); + table.double('amount'); + table.double('value'); + table.double('weeks'); + + table.timestamp('expiresAt'); + table.boolean('expirationProcessed'); + + table.string('orderId'); + table.string('billPaymentId'); + table.string('type'); + table.jsonb('customMetadata').defaultTo({}); + }); +} + +export async function down(): Promise {} diff --git a/packages/database/migrations/20240129135000_stake_reward.ts b/packages/database/migrations/20240129135000_stake_reward.ts new file mode 100644 index 0000000000..809d197089 --- /dev/null +++ b/packages/database/migrations/20240129135000_stake_reward.ts @@ -0,0 +1,20 @@ +import { COL } from '@build-5/interfaces'; +import type { Knex } from 'knex'; +import { baseRecord, createTable } from './20240129091246_common'; + +export async function up(knex: Knex): Promise { + await createTable(knex, COL.STAKE_REWARD, undefined, (t) => { + baseRecord(knex, t); + + t.timestamp('startDate'); + t.timestamp('endDate'); + t.timestamp('tokenVestingDate'); + t.double('tokensToDistribute'); + t.string('token'); + t.double('totalStaked'); + t.double('totalAirdropped'); + t.string('status'); + }); +} + +export async function down(): Promise {} diff --git a/packages/database/migrations/20240129135000_stamp.ts b/packages/database/migrations/20240129135000_stamp.ts new file mode 100644 index 0000000000..9a54836a4e --- /dev/null +++ b/packages/database/migrations/20240129135000_stamp.ts @@ -0,0 +1,34 @@ +import { COL } from '@build-5/interfaces'; +import type { Knex } from 'knex'; +import { baseRecord, createTable } from './20240129091246_common'; + +export async function up(knex: Knex): Promise { + await createTable(knex, COL.STAMP, undefined, (table) => { + baseRecord(knex, table); + + table.string('space'); + table.string('build5Url'); + table.text('originUri'); + table.string('checksum'); + table.string('extension'); + table.double('bytes'); + table.double('costPerMb'); + table.string('network'); + + table.string('ipfsMedia'); + table.string('ipfsRoot'); + + table.timestamp('expiresAt'); + table.string('order'); + table.boolean('funded'); + table.boolean('expired'); + + table.string('mediaStatus'); + table.double('mediaUploadErrorCount'); + + table.string('aliasId'); + table.string('nftId'); + }); +} + +export async function down(): Promise {} diff --git a/packages/database/migrations/20240129135000_swap.ts b/packages/database/migrations/20240129135000_swap.ts new file mode 100644 index 0000000000..3560cde0bc --- /dev/null +++ b/packages/database/migrations/20240129135000_swap.ts @@ -0,0 +1,23 @@ +import { COL } from '@build-5/interfaces'; +import type { Knex } from 'knex'; +import { baseRecord, createTable } from './20240129091246_common'; + +export async function up(knex: Knex): Promise { + await createTable(knex, COL.SWAP, undefined, (t) => { + baseRecord(knex, t); + + t.string('recipient'); + t.string('network'); + t.string('address'); + t.string('orderId'); + t.specificType('nftIdsAsk', 'TEXT[]'); + t.double('baseTokenAmountAsk'); + t.jsonb('nativeTokensAsk').defaultTo('[]'); + t.string('status'); + + t.jsonb('bidOutputs').defaultTo('[]'); + t.jsonb('askOutputs').defaultTo('[]'); + }); +} + +export async function down(): Promise {} diff --git a/packages/database/migrations/20240129135000_system.ts b/packages/database/migrations/20240129135000_system.ts new file mode 100644 index 0000000000..e378082d6b --- /dev/null +++ b/packages/database/migrations/20240129135000_system.ts @@ -0,0 +1,13 @@ +import { COL } from '@build-5/interfaces'; +import type { Knex } from 'knex'; +import { baseRecord, createTable } from './20240129091246_common'; + +export async function up(knex: Knex): Promise { + await createTable(knex, COL.SYSTEM, undefined, (table) => { + baseRecord(knex, table); + table.double('tokenTradingFeePercentage'); + table.double('tokenPurchaseFeePercentage'); + }); +} + +export async function down(): Promise {} diff --git a/packages/database/migrations/20240129135000_ticker.ts b/packages/database/migrations/20240129135000_ticker.ts new file mode 100644 index 0000000000..51a0e252a1 --- /dev/null +++ b/packages/database/migrations/20240129135000_ticker.ts @@ -0,0 +1,12 @@ +import { COL } from '@build-5/interfaces'; +import type { Knex } from 'knex'; +import { baseRecord, createTable } from './20240129091246_common'; + +export async function up(knex: Knex): Promise { + await createTable(knex, COL.TICKER, undefined, (t) => { + baseRecord(knex, t); + t.double('price'); + }); +} + +export async function down(): Promise {} diff --git a/packages/database/migrations/20240129135000_token.ts b/packages/database/migrations/20240129135000_token.ts new file mode 100644 index 0000000000..d40c4ccd85 --- /dev/null +++ b/packages/database/migrations/20240129135000_token.ts @@ -0,0 +1,167 @@ +import { COL, SUB_COL, StakeType, TokenStatus } from '@build-5/interfaces'; +import type { Knex } from 'knex'; +import { baseRecord, baseSubCollection, createTable } from './20240129091246_common'; + +export async function up(knex: Knex): Promise { + await createTable(knex, COL.TOKEN, undefined, (t) => { + baseRecord(knex, t); + + t.string('name').defaultTo(''); + t.string('symbol').defaultTo(''); + t.text('title'); + t.text('description'); + t.text('shortDescriptionTitle'); + t.text('shortDescription'); + t.string('space'); + t.double('pricePerToken'); + + t.double('totalSupply'); + t.jsonb('allocations').defaultTo([]); + + t.timestamp('saleStartDate'); + t.double('saleLength'); + t.timestamp('coolDownEnd'); + t.boolean('autoProcessAt100Percent'); + t.boolean('approved').defaultTo(false); + t.boolean('rejected').defaultTo(false); + t.boolean('public'); + t.specificType('links', 'TEXT[]').defaultTo('{}'); + t.text('icon'); + t.text('overviewGraphics'); + t.string('status').defaultTo(TokenStatus.PRE_MINTED); + + t.double('totalDeposit'); + + t.double('tokensOrdered'); + t.double('totalAirdropped'); + t.text('termsAndConditions').defaultTo(''); + t.integer('access'); + t.specificType('accessAwards', 'TEXT[]').defaultTo('{}'); + + t.specificType('accessCollections', 'TEXT[]').defaultTo('{}'); + + t.string('ipfsMedia'); + t.string('ipfsMetadata'); + t.string('ipfsRoot'); + + t.string('mintingData_mintedBy'); + t.timestamp('mintingData_mintedOn'); + t.string('mintingData_aliasBlockId'); + t.string('mintingData_aliasId'); + t.double('mintingData_aliasStorageDeposit'); + t.string('mintingData_tokenId'); + t.string('mintingData_blockId'); + t.double('mintingData_foundryStorageDeposit'); + + t.string('mintingData_network'); + t.string('mintingData_networkFormat'); + + t.string('mintingData_vaultAddress'); + t.double('mintingData_tokensInVault'); + t.double('mintingData_vaultStorageDeposit'); + t.double('mintingData_guardianStorageDeposit'); + t.double('mintingData_meltedTokens'); + t.double('mintingData_circulatingSupply'); + + t.double('rankCount'); + t.double('rankSum'); + t.double('rankAvg'); + t.string('mediaStatus'); + t.double('mediaUploadErrorCount'); + t.boolean('tradingDisabled'); + t.double('decimals').defaultTo(6); + + t.double('votes_upvotes'); + t.double('votes_downvotes'); + t.double('votes_voteDiff'); + }); + + await createTable(knex, COL.AIRDROP, undefined, (t) => { + baseRecord(knex, t); + t.string('member'); + t.string('token'); + t.string('award'); + t.timestamp('vestingAt'); + t.double('count'); + t.string('status'); + t.string('orderId'); + t.string('billPaymentId'); + t.string('sourceAddress'); + t.string('stakeRewardId'); + t.string('stakeType'); + t.boolean('isBaseToken'); + }); + + await createTable(knex, COL.TOKEN, SUB_COL.DISTRIBUTION, (t) => { + baseSubCollection(knex, t); + t.double('totalDeposit'); + t.double('totalPaid'); + t.double('refundedAmount'); + t.double('totalBought'); + t.boolean('reconciled'); + t.string('billPaymentId'); + t.string('creditPaymentId'); + t.string('royaltyBillPaymentId'); + t.double('tokenClaimed'); + t.double('lockedForSale'); + t.double('sold'); + t.double('totalPurchased'); + t.double('tokenOwned'); + t.timestamp('mintedClaimedOn'); + + t.specificType('mintingTransactions', 'TEXT[]').defaultTo('{}'); + + t.double('stakeRewards'); + t.double('extraStakeRewards'); + t.double('totalUnclaimedAirdrop'); + t.string('stakeVoteTransactionId'); + + for (const type of Object.values(StakeType)) { + t.double('stakes_' + type + '_amount'); + t.double('stakes_' + type + '_totalAmount'); + t.double('stakes_' + type + '_value'); + t.double('stakes_' + type + '_totalValue'); + t.double('stakes_' + type + '_stakingMembersCount'); + } + + t.jsonb('stakeExpiry').defaultTo({}); + }); + + await createTable(knex, COL.TOKEN, SUB_COL.STATS, (t) => { + baseSubCollection(knex, t); + t.double('votes_upvotes'); + t.double('votes_downvotes'); + t.double('votes_voteDiff'); + + t.double('ranks_count'); + t.double('ranks_sum'); + t.double('ranks_avg'); + + t.double('volumeTotal'); + for (const age of ['in24h', 'in48h', 'in7d']) { + t.double('volume_' + age); + } + + for (const type of Object.values(StakeType)) { + t.double('stakes_' + type + '_amount'); + t.double('stakes_' + type + '_totalAmount'); + t.double('stakes_' + type + '_value'); + t.double('stakes_' + type + '_totalValue'); + t.double('stakes_' + type + '_stakingMembersCount'); + } + + t.jsonb('stakeExpiry').defaultTo({}); + }); + + await createTable(knex, COL.TOKEN, SUB_COL.RANKS, (t) => { + baseSubCollection(knex, t); + t.double('rank'); + }); + + await createTable(knex, COL.TOKEN, SUB_COL.VOTES, (t) => { + baseSubCollection(knex, t); + t.double('direction'); + }); +} + +export async function down(): Promise {} diff --git a/packages/database/migrations/20240129135000_token_market.ts b/packages/database/migrations/20240129135000_token_market.ts new file mode 100644 index 0000000000..a19dd2cc3d --- /dev/null +++ b/packages/database/migrations/20240129135000_token_market.ts @@ -0,0 +1,30 @@ +import { COL } from '@build-5/interfaces'; +import type { Knex } from 'knex'; +import { baseRecord, createTable } from './20240129091246_common'; + +export async function up(knex: Knex): Promise { + await createTable(knex, COL.TOKEN_MARKET, undefined, (t) => { + baseRecord(knex, t); + + t.string('owner'); + t.string('token'); + t.string('tokenStatus'); + t.string('type'); + t.double('count'); + t.double('price'); + t.double('totalDeposit'); + t.double('balance'); + t.double('fulfilled'); + t.string('status'); + t.string('orderTransactionId'); + t.string('paymentTransactionId'); + t.string('creditTransactionId'); + t.timestamp('expiresAt'); + t.boolean('shouldRetry'); + t.string('sourceNetwork'); + t.string('targetNetwork'); + t.string('targetAddress'); + }); +} + +export async function down(): Promise {} diff --git a/packages/database/migrations/20240129135000_token_purchase.ts b/packages/database/migrations/20240129135000_token_purchase.ts new file mode 100644 index 0000000000..a0aee50f95 --- /dev/null +++ b/packages/database/migrations/20240129135000_token_purchase.ts @@ -0,0 +1,30 @@ +import { COL } from '@build-5/interfaces'; +import type { Knex } from 'knex'; +import { baseRecord, createTable } from './20240129091246_common'; + +export async function up(knex: Knex): Promise { + await createTable(knex, COL.TOKEN_PURCHASE, undefined, (t) => { + baseRecord(knex, t); + + t.string('token'); + t.string('tokenStatus'); + t.string('sell'); + t.string('buy'); + t.double('count'); + t.double('price'); + t.string('triggeredBy'); + t.string('billPaymentId'); + t.string('buyerBillPaymentId'); + t.specificType('royaltyBillPayments', 'TEXT[]'); + t.string('sourceNetwork'); + t.string('targetNetwork'); + t.double('sellerTokenTradingFeePercentage'); + t.double('sellerTier'); + + t.boolean('in24h').defaultTo(false); + t.boolean('in48h').defaultTo(false); + t.boolean('in7d').defaultTo(false); + }); +} + +export async function down(): Promise {} diff --git a/packages/database/migrations/20240129135000_transaction.ts b/packages/database/migrations/20240129135000_transaction.ts new file mode 100644 index 0000000000..e91a2b61ca --- /dev/null +++ b/packages/database/migrations/20240129135000_transaction.ts @@ -0,0 +1,151 @@ +import { COL } from '@build-5/interfaces'; +import type { Knex } from 'knex'; +import { baseRecord, createTable } from './20240129091246_common'; + +export async function up(knex: Knex): Promise { + await createTable(knex, COL.TRANSACTION, undefined, (table) => { + baseRecord(knex, table); + table.string('network'); + table.string('type'); + table.boolean('isOrderType'); + table.string('member'); + table.string('space'); + table.boolean('shouldRetry'); + table.boolean('ignoreWallet'); + table.specificType('linkedTransactions', 'TEXT[]').defaultTo('{}'); + table.string('ignoreWalletReason'); + + table.string('payload_type'); + table.double('payload_amount'); + table.string('payload_sourceAddress'); + table.string('payload_targetAddress'); + table.jsonb('payload_targetAddresses').defaultTo([]); + table.specificType('payload_sourceTransaction', 'TEXT[]').defaultTo('{}'); + table.integer('payload_validationType'); + table.timestamp('payload_expiresOn'); + table.boolean('payload_reconciled'); + table.boolean('payload_void'); + + table.string('payload_collection'); + table.string('payload_unsoldMintingOptions'); + table.double('payload_newPrice'); + table.double('payload_collectionStorageDeposit'); + table.double('payload_nftsStorageDeposit'); + table.double('payload_aliasStorageDeposit'); + table.double('payload_nftsToMint'); + + table.string('payload_transaction'); + table.string('payload_unlockedBy'); + + table.string('payload_beneficiary'); + table.string('payload_beneficiaryUid'); + table.string('payload_beneficiaryAddress'); + + table.double('payload_royaltiesFee'); + table.string('payload_royaltiesSpace'); + table.string('payload_royaltiesSpaceAddress'); + table.string('payload_chainReference'); + table.string('payload_nft'); + table.jsonb('payload_restrictions').defaultTo({}); + table.string('payload_token'); + table.double('payload_quantity'); + table.string('payload_tokenSymbol'); + + table.double('payload_unclaimedAirdrops'); + table.double('payload_totalAirdropCount'); + table.string('payload_tokenId'); + + table.double('payload_foundryStorageDeposit'); + table.double('payload_vaultStorageDeposit'); + table.double('payload_guardianStorageDeposit'); + table.double('payload_tokensInVault'); + table.string('payload_orderId'); + table.double('payload_collectionOutputAmount'); + table.double('payload_aliasOutputAmount'); + table.double('payload_nftOutputAmount'); + + table.string('payload_aliasId'); + table.string('payload_aliasBlockId'); + table.string('payload_aliasGovAddress'); + table.string('payload_collectionId'); + table.string('payload_nftId'); + table.jsonb('payload_nativeTokens').defaultTo([]); + + table.string('payload_previousOwnerEntity'); + table.string('payload_previousOwner'); + table.string('payload_ownerEntity'); + table.string('payload_owner'); + + table.boolean('payload_royalty'); + table.timestamp('payload_vestingAt'); + + table.jsonb('payload_customMetadata').defaultTo({}); + table.string('payload_stake'); + table.string('payload_award'); + table.string('payload_legacyAwardFundRequestId'); + table.double('payload_legacyAwardsBeeingFunded'); + table.double('payload_weeks'); + table.string('payload_stakeType'); + + table.double('payload_count'); + table.double('payload_price'); + table.double('payload_tokenReward'); + table.double('payload_edition'); + table.timestamp('payload_participatedOn'); + table.string('payload_proposalId'); + table.specificType('payload_voteValues', 'FLOAT[]'); + table.string('payload_storageDepositSourceAddress'); + table.jsonb('payload_storageReturn').defaultTo({}); + table.string('payload_airdropId'); + + table.specificType('payload_nfts', 'TEXT[]').defaultTo('{}'); + table.string('payload_tag'); + table.jsonb('payload_metadata').defaultTo({}); + table.jsonb('payload_response').defaultTo({}); + + table.string('payload_reason'); + table.boolean('payload_invalidPayment'); + table.string('payload_outputToConsume'); + table.boolean('payload_dependsOnBillPayment'); + table.text('payload_milestoneTransactionPath'); + table.double('payload_tokenAmount'); + table.double('payload_weight'); + table.double('payload_weightMultiplier'); + table.specificType('payload_votes', 'FLOAT[]'); + table.specificType('payload_values', 'FLOAT[]'); + table.string('payload_creditId'); + table.boolean('payload_outputConsumed'); + table.timestamp('payload_outputConsumedOn'); + table.specificType('payload_stakes', 'TEXT[]').defaultTo('{}'); + table.string('payload_stakeReward'); + table.boolean('payload_tanglePuchase'); + table.boolean('payload_disableWithdraw'); + table.boolean('payload_lockCollectionNft'); + + table.string('payload_stamp'); + table.string('payload_tokenTradeOderTargetAddress'); + table.string('payload_auction'); + + table.double('payload_days'); + table.double('payload_dailyCost'); + + table.jsonb('payload_nftOrders').defaultTo([]); + table.string('payload_swap'); + + table.timestamp('payload_walletReference_createdOn'); + table.timestamp('payload_walletReference_processedOn'); + table.string('payload_walletReference_chainReference'); + table.specificType('payload_walletReference_chainReferences', 'TEXT[]').defaultTo('{}'); + table.text('payload_walletReference_error'); + table.boolean('payload_walletReference_confirmed'); + table.timestamp('payload_walletReference_confirmedOn'); + table.text('payload_walletReference_milestoneTransactionPath'); + table.double('payload_walletReference_count'); + table.boolean('payload_walletReference_inProgress'); + table.double('payload_walletReference_nodeIndex'); + + table.string('payload_outputId'); + }); +} + +export async function down(): Promise {} diff --git a/packages/database/package.json b/packages/database/package.json index 22fc88e195..be93a3ddab 100644 --- a/packages/database/package.json +++ b/packages/database/package.json @@ -12,19 +12,25 @@ ], "private": true, "scripts": { - "build": "tsc" + "build": "tsc", + "migrate": "knex migrate:latest --knexfile knexfile.ts", + "generate": "rm -rf ./src/pg/models/* && ts-node ./generators/generator.ts && npx prettier . --write" }, "dependencies": { "@build-5/interfaces": "*", + "@google-cloud/pubsub": "4.3.3", + "@google-cloud/storage": "7.9.0", "dayjs": "1.11.10", - "firebase-admin": "12.0.0", "jsonwebtoken": "9.0.2", - "lodash": "4.17.21" + "knex": "^3.1.0", + "lodash": "4.17.21", + "pg": "^8.11.3" }, "devDependencies": { "@types/lodash": "4.14.202", "dotenv": "16.4.5", "glob": "8.0.3", + "prettier-plugin-organize-imports": "3.2.4", "typescript": "5.3.3" } } diff --git a/packages/database/src/app/app.ts b/packages/database/src/app/app.ts deleted file mode 100644 index 37daffe138..0000000000 --- a/packages/database/src/app/app.ts +++ /dev/null @@ -1,11 +0,0 @@ -import admin from 'firebase-admin'; -import { IApp } from './interface'; - -export class FirebaseApp implements IApp { - constructor(private readonly app: admin.app.App) {} - - /* eslint-disable @typescript-eslint/no-explicit-any */ - public getInstance = (): any => this.app; - - public getName = () => this.app.options.projectId!; -} diff --git a/packages/database/src/app/build5App.ts b/packages/database/src/app/build5App.ts deleted file mode 100644 index 8986dfde57..0000000000 --- a/packages/database/src/app/build5App.ts +++ /dev/null @@ -1,6 +0,0 @@ -import admin from 'firebase-admin'; -import { FirebaseApp } from './app'; - -const defaultApp = admin.initializeApp(undefined, 'defaultApp'); - -export const build5App = new FirebaseApp(defaultApp); diff --git a/packages/database/src/app/index.ts b/packages/database/src/app/index.ts deleted file mode 100644 index 473861e4f4..0000000000 --- a/packages/database/src/app/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './app'; -export * from './build5App'; -export * from './interface'; diff --git a/packages/database/src/app/interface.ts b/packages/database/src/app/interface.ts deleted file mode 100644 index de8e3866b7..0000000000 --- a/packages/database/src/app/interface.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface IApp { - /* eslint-disable @typescript-eslint/no-explicit-any */ - getInstance: () => any; - getName: () => string; -} diff --git a/packages/database/src/firestore/build5Db.ts b/packages/database/src/firestore/build5Db.ts deleted file mode 100644 index abf37e1d1b..0000000000 --- a/packages/database/src/firestore/build5Db.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { COL, Dataset, SUB_COL, Subset } from '@build-5/interfaces'; -import { build5App } from '../app/build5App'; -import { Firestore } from './firestore'; -import { IDatabase } from './interfaces'; - -export const build5Db = (): IDatabase => new Firestore(build5App); - -export const getSnapshot = ( - col: COL | Dataset, - id?: string, - subCol?: SUB_COL | Subset, - childId?: string, -) => { - if (!id) { - return; - } - let doc = build5Db().doc(`${col}/${id}`); - if (subCol && childId) { - doc = doc.collection(subCol).doc(childId); - } - return doc.getSnapshot(); -}; diff --git a/packages/database/src/firestore/common.ts b/packages/database/src/firestore/common.ts deleted file mode 100644 index 4f9fe73400..0000000000 --- a/packages/database/src/firestore/common.ts +++ /dev/null @@ -1,11 +0,0 @@ -import dayjs from 'dayjs'; -import { get } from 'lodash'; -import { IDocument } from './interfaces'; - -export const cOn = (doc: IDocument, data: T) => ({ - ...data, - createdOn: get(data, 'createdOn') || dayjs().toDate(), - updatedOn: get(data, 'updatedOn') || dayjs().toDate(), -}); - -export const uOn = (data: T) => ({ ...data, updatedOn: dayjs().toDate() }); diff --git a/packages/database/src/firestore/firestore.ts b/packages/database/src/firestore/firestore.ts deleted file mode 100644 index 44692016ef..0000000000 --- a/packages/database/src/firestore/firestore.ts +++ /dev/null @@ -1,294 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import { COL, Dataset, SUB_COL, Subset } from '@build-5/interfaces'; -import admin from 'firebase-admin'; -import { Filter } from 'firebase-admin/firestore'; -import { isEmpty } from 'lodash'; -import { FirebaseApp } from '../app/app'; -import { cOn, uOn } from './common'; -import { - IBatch, - ICollection, - ICollectionGroup, - IDatabase, - IDocument, - IDocumentSnapshot, - IQuery, - ITransaction, -} from './interfaces'; - -export class Firestore implements IDatabase { - private db: admin.firestore.Firestore; - - constructor(private readonly app: FirebaseApp) { - this.db = this.app.getInstance().firestore(); - } - - public collection = (col: COL | Dataset) => - new FirestoreCollection(this.db, this.db.collection(col)); - - public collectionGroup = (col: SUB_COL | Subset) => - new FirestoreCollectionGroup(this.db.collectionGroup(col)); - - public doc = (documentPath: string) => new FirestoreDocument(this.db, this.db.doc(documentPath)); - - public batch = (): IBatch => new FirestoreBatch(this.db); - - public runTransaction = ( - func: (transaction: FirestoreTransaction) => Promise, - ): Promise => - this.db.runTransaction((transaction) => func(new FirestoreTransaction(this.db, transaction))); - - public inc = (value: number) => admin.firestore.FieldValue.increment(value); - - public arrayUnion = (...value: T[]) => admin.firestore.FieldValue.arrayUnion(...value); - - public arrayRemove = (...value: T[]) => admin.firestore.FieldValue.arrayRemove(...value); - - public deleteField = () => admin.firestore.FieldValue.delete(); - - public get = async (col: COL, uid: string) => { - const docRef = this.db.doc(`${col}/${uid}`); - return (await docRef.get()).data() as T; - }; -} - -export class FirestoreBatch implements IBatch { - private batch: admin.firestore.WriteBatch; - - constructor(private readonly db: admin.firestore.Firestore) { - this.batch = db.batch(); - } - - public create = (docRef: IDocument, data: any) => { - const ref = this.db.doc(docRef.getPath()); - this.batch.create(ref, cOn(docRef, data)); - }; - - public update = (docRef: IDocument, data: any) => { - const ref = this.db.doc(docRef.getPath()); - this.batch.update(ref, uOn(data)); - }; - - public set = (docRef: IDocument, data: any, merge = false) => { - const ref = this.db.doc(docRef.getPath()); - this.batch.set(ref, merge ? uOn(data) : cOn(docRef, data), { merge }); - }; - - public delete = (docRef: IDocument) => { - const ref = this.db.doc(docRef.getPath()); - this.batch.delete(ref); - }; - - public commit = async () => { - await this.batch.commit(); - }; -} - -export class FirestoreTransaction implements ITransaction { - constructor( - private readonly db: admin.firestore.Firestore, - private readonly transaction: admin.firestore.Transaction, - ) {} - - public get = async (docRef: IDocument) => { - const refs = this.db.doc(docRef.getPath()); - const doc = await this.transaction.get(refs); - return doc.data(); - }; - - public getAll = async (...docRefs: IDocument[]) => { - if (isEmpty(docRefs)) { - return []; - } - const refs = docRefs.map((docRef) => this.db.doc(docRef.getPath())); - const snap = await this.transaction.getAll(...refs); - return snap.map((doc) => doc.data() as T | undefined); - }; - - public getByQuery = async (query: IQuery) => { - const snap = await this.transaction.get(query.getInstance()); - return snap.docs.map((d) => d.data() as T); - }; - - public create = (docRef: IDocument, data: any) => { - const ref = this.db.doc(docRef.getPath()); - this.transaction.create(ref, cOn(docRef, data)); - }; - - public update = (docRef: IDocument, data: any) => { - const ref = this.db.doc(docRef.getPath()); - this.transaction.update(ref, uOn(data)); - }; - - public set = (docRef: IDocument, data: any, merge = false) => { - const ref = this.db.doc(docRef.getPath()); - const uData = merge ? uOn(data) : cOn(docRef, data); - this.transaction.set(ref, uData, { merge }); - }; - - public delete = (docRef: IDocument) => { - const ref = this.db.doc(docRef.getPath()); - this.transaction.delete(ref); - }; -} - -class FirestoreCollectionGroup implements ICollectionGroup { - constructor( - protected readonly collection: - | admin.firestore.CollectionGroup - | admin.firestore.CollectionReference, - ) {} - - public get = async () => { - const snap = await this.collection.get(); - return snap.docs.map((d) => d.data() as T); - }; - - public where = (fieldPath: string, operator: admin.firestore.WhereFilterOp, value: any) => - new FirestoreQuery(this.collection.where(fieldPath, operator, value)); - - public or = (filters: { fieldPath: string; value: any }[]) => { - const compositFilter = Filter.or( - ...filters.map((f) => Filter.where(f.fieldPath, '==', f.value)), - ); - return new FirestoreQuery(this.collection.where(compositFilter)); - }; - - public limit = (value: number) => new FirestoreQuery(this.collection.limit(value)); - - public limitToLast = (value: number) => new FirestoreQuery(this.collection.limitToLast(value)); - - public startAfter = (value?: IDocumentSnapshot | string | number | Date) => { - if (!value) { - return new FirestoreQuery(this.collection); - } - return new FirestoreQuery(this.collection.startAfter(value)); - }; - - public orderBy = (field: string, dir: 'asc' | 'desc' = 'asc') => - new FirestoreQuery(this.collection.orderBy(field, dir)); - - public count = async () => (await this.collection.count().get()).data().count; -} - -export class FirestoreCollection extends FirestoreCollectionGroup implements ICollection { - constructor( - private readonly db: admin.firestore.Firestore, - collection: admin.firestore.CollectionReference, - ) { - super(collection); - } - - public doc = (documentPath = '') => { - const colRef = this.collection as admin.firestore.CollectionReference; - const docRef = documentPath ? colRef.doc(documentPath) : colRef.doc(); - return new FirestoreDocument(this.db, docRef); - }; -} - -export class FirestoreDocument implements IDocument { - constructor( - private readonly db: admin.firestore.Firestore, - private readonly document: admin.firestore.DocumentReference, - ) {} - - public create = async (data: any) => { - await this.document.create(cOn(this, data)); - }; - - public update = async (data: any) => { - await this.document.update(uOn(data)); - }; - - public set = async (data: any, merge = false) => { - await this.document.set(merge ? uOn(data) : cOn(this, data), { merge }); - }; - - public delete = async () => { - await this.document.delete(); - }; - - public onSnapshot = ( - callback: (data: T | undefined) => void, - onError?: (error: Error) => void, - ) => - this.document.onSnapshot( - (snap) => { - callback(snap.exists ? ({ ...snap.data(), uid: snap.id } as T) : undefined); - }, - (error) => { - onError && onError(error); - }, - ); - - public collection = (subCol: SUB_COL | Subset): ICollection => - new FirestoreCollection(this.db, this.document.collection(subCol)); - - public get = async (): Promise => { - const doc = await this.document.get(); - return doc.data(); - }; - - public getPath = () => this.document.path; - - public getSnapshot = () => this.document.get(); - - public getId = () => this.document.id; -} - -export class FirestoreQuery implements IQuery { - constructor(private query: admin.firestore.Query) {} - - public get = async (): Promise => { - const snap = await this.query.get(); - return snap.docs.map((d) => ({ ...d.data(), uid: d.id }) as T); - }; - - public where = ( - fieldPath: string, - operator: admin.firestore.WhereFilterOp, - value: any, - ): IQuery => { - this.query = this.query.where(fieldPath, operator, value); - return this; - }; - - public limit = (value: number) => { - this.query = this.query.limit(value); - return this; - }; - - public limitToLast = (value: number) => { - this.query = this.query.limitToLast(value); - return this; - }; - - public startAfter = (value?: IDocumentSnapshot | string | number | Date) => { - if (value) { - this.query = this.query.startAfter(value); - } - return this; - }; - - public orderBy = (field: string, dir: 'asc' | 'desc' = 'asc') => { - this.query = this.query.orderBy(field, dir); - return this; - }; - - public select = (...fields: string[]) => { - this.query = this.query.select(...fields); - return this; - }; - - public onSnapshot = (callback: (data: T[]) => void, onError?: (error: Error) => void) => - this.query.onSnapshot( - (snap) => { - callback(snap.docs.map((d) => ({ ...d.data(), uid: d.id }) as T)); - }, - (error) => { - onError && onError(error); - }, - ); - - public getInstance = () => this.query; -} diff --git a/packages/database/src/firestore/index.ts b/packages/database/src/firestore/index.ts deleted file mode 100644 index b62641cb9d..0000000000 --- a/packages/database/src/firestore/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './build5Db'; -export * from './common'; -export * from './firestore'; -export * from './interfaces'; diff --git a/packages/database/src/firestore/interfaces.ts b/packages/database/src/firestore/interfaces.ts deleted file mode 100644 index ba89abbb6e..0000000000 --- a/packages/database/src/firestore/interfaces.ts +++ /dev/null @@ -1,103 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import { COL, Dataset, SUB_COL, Subset } from '@build-5/interfaces'; - -export interface IDatabase { - collection: (col: COL | Dataset) => ICollection; - collectionGroup: (col: SUB_COL | Subset) => ICollectionGroup; - doc: (documentPath: string) => IDocument; - - batch: () => IBatch; - runTransaction: (func: (transaction: ITransaction) => Promise) => Promise; - - inc: (value: number) => any; - arrayUnion: (...value: T[]) => any; - arrayRemove: (...value: T[]) => any; - deleteField: () => any; - - get: (col: COL, uid: string) => Promise; -} - -export interface ICollectionGroup { - get: () => Promise; - where: (fieldPath: string, operator: WhereFilterOp, value: any) => IQuery; - or: (filters: { fieldPath: string; value: any }[]) => IQuery; - limit: (value: number) => IQuery; - limitToLast: (value: number) => IQuery; - startAfter: (value?: IDocumentSnapshot | string | number | Date) => IQuery; - orderBy: (field: string, dir?: 'asc' | 'desc') => IQuery; - count: () => Promise; -} - -export interface ICollection extends ICollectionGroup { - doc: (documentPath?: string) => IDocument; -} - -export interface IDocument { - create: (data: any) => Promise; - update: (data: any) => Promise; - set: (data: any, merge?: boolean) => Promise; - delete: () => Promise; - - onSnapshot: ( - callback: (data: T | undefined) => void, - error?: (error: Error) => void, - ) => () => void; - - collection: (subCol: SUB_COL | Subset) => ICollection; - get: () => Promise; - - getPath: () => string; - getSnapshot: () => Promise; - - getId: () => string; -} - -export interface IDocumentSnapshot { - readonly id: string; -} - -export interface IQuery { - get: () => Promise; - where: (fieldPath: string, operator: WhereFilterOp, value: any) => IQuery; - - limit: (value: number) => IQuery; - limitToLast: (value: number) => IQuery; - startAfter: (value?: IDocumentSnapshot | string | number | Date) => IQuery; - onSnapshot: (callback: (data: T[]) => void, error?: (error: Error) => void) => () => void; - - getInstance: () => any; - - orderBy: (field: string, dir?: 'asc' | 'desc') => IQuery; - - select: (...fields: string[]) => IQuery; -} - -export interface IBatch { - create: (docRef: IDocument, data: any) => void; - update: (docRef: IDocument, data: any) => void; - set: (docRef: IDocument, data: any, merge?: boolean) => void; - delete: (docRef: IDocument) => void; - commit: () => Promise; -} - -export interface ITransaction { - get: (docRef: IDocument) => Promise; - getAll: (...docRefs: IDocument[]) => Promise<(T | undefined)[]>; - getByQuery: (query: IQuery) => Promise; - create: (docRef: IDocument, data: any) => void; - update: (docRef: IDocument, data: any) => void; - set: (docRef: IDocument, data: any, merge?: boolean) => void; - delete: (docRef: IDocument) => void; -} - -export type WhereFilterOp = - | '<' - | '<=' - | '==' - | '!=' - | '>=' - | '>' - | 'array-contains' - | 'in' - | 'not-in' - | 'array-contains-any'; diff --git a/packages/database/src/index.ts b/packages/database/src/index.ts index de2baa4b9f..8e9f78f42d 100644 --- a/packages/database/src/index.ts +++ b/packages/database/src/index.ts @@ -1,3 +1,2 @@ -export * from './app/index'; -export * from './firestore/index'; +export * from './pg/index'; export * from './storage/index'; diff --git a/packages/database/src/pg/impl/common.ts b/packages/database/src/pg/impl/common.ts new file mode 100644 index 0000000000..5c083ea5b3 --- /dev/null +++ b/packages/database/src/pg/impl/common.ts @@ -0,0 +1,28 @@ +import { Timestamp } from '@build-5/interfaces'; +import { isNull, isUndefined } from 'lodash'; + +export const removeNulls = (data: T) => { + const result: T = Object.entries(data as any).reduce((acc, [key, value]) => { + if (isNull(value) || isUndefined(value)) { + return acc; + } + if (value instanceof Timestamp || Array.isArray(value)) { + return { ...acc, [key]: value }; + } + if (value instanceof Object) { + return { ...acc, [key]: removeNulls(value) }; + } + return { ...acc, [key]: value }; + }, {} as T); + return result; +}; + +export const undefinedToNull = (data: T) => { + const result: T = Object.entries(data as any).reduce((acc, [key, value]) => { + if (isNull(value) || isUndefined(value)) { + return { ...acc, [key]: null }; + } + return { ...acc, [key]: value }; + }, {} as T); + return result; +}; diff --git a/packages/database/src/pg/impl/instance.ts b/packages/database/src/pg/impl/instance.ts new file mode 100644 index 0000000000..b51a568cba --- /dev/null +++ b/packages/database/src/pg/impl/instance.ts @@ -0,0 +1,4 @@ +import { IDatabase } from '../interfaces/database'; +import { PgDatabase } from './postgres'; + +export const build5Db = (): IDatabase => new PgDatabase(); diff --git a/packages/database/src/pg/impl/knex.ts b/packages/database/src/pg/impl/knex.ts new file mode 100644 index 0000000000..43c887c519 --- /dev/null +++ b/packages/database/src/pg/impl/knex.ts @@ -0,0 +1,38 @@ +import Knex from 'knex'; + +export let knex: Knex.Knex | undefined = undefined; + +export const getKnex = () => { + if (!knex) { + knex = Knex({ + client: 'pg', + connection: { + user: process.env.DB_USER, + password: process.env.DB_USER_PWD, + database: process.env.DB_NAME, + host: process.env.DB_HOST, + port: Number(process.env.DB_PORT), + }, + pool: { + min: Number(process.env.DB_POOL_MIN || 0), + max: Number(process.env.DB_POOL_MAX || 20), + }, + }); + } + return knex; +}; + +export let knextran: Knex.Knex | undefined = undefined; + +export const getKnexTran = () => + Knex({ + client: 'pg', + connection: { + user: process.env.DB_USER, + password: process.env.DB_USER_PWD, + database: process.env.DB_NAME, + host: process.env.DB_HOST, + port: Number(process.env.DB_PORT), + }, + pool: { min: 0, max: 1 }, + }); diff --git a/packages/database/src/pg/impl/postgres.ts b/packages/database/src/pg/impl/postgres.ts new file mode 100644 index 0000000000..6a411b8986 --- /dev/null +++ b/packages/database/src/pg/impl/postgres.ts @@ -0,0 +1,647 @@ +import { + Auction, + Award, + AwardOwner, + AwardParticipant, + COL, + Collection, + CollectionStats, + Member, + Mnemonic, + Nft, + NftStake, + Notification, + Project, + ProjectAdmin, + ProjectApiKey, + Proposal, + ProposalMember, + Rank, + SUB_COL, + SoonSnap, + Space, + SpaceGuardian, + SpaceMember, + Stake, + StakeReward, + Stamp, + Swap, + SystemConfig, + Ticker, + Timestamp, + Token, + TokenDistribution, + TokenDrop, + TokenPurchase, + TokenStats, + TokenTradeOrder, + Transaction, + Vote, +} from '@build-5/interfaces'; +import dayjs from 'dayjs'; +import { Knex } from 'knex'; +import { IBatch } from '../interfaces/batch'; +import { ICollection, ISubCollection } from '../interfaces/collection'; +import { ArrayRemove, ArrayUnion, Converter, Increment } from '../interfaces/common'; +import { IDatabase } from '../interfaces/database'; +import { IDocument } from '../interfaces/document/document'; +import { ISubDocument } from '../interfaces/document/sub.document'; +import { ITransaction } from '../interfaces/transaction'; +import { + PgAirdrop, + PgAuction, + PgAward, + PgAwardOwners, + PgAwardParticipants, + PgCollection, + PgCollectionRanks, + PgCollectionStats, + PgCollectionVotes, + PgMember, + PgMilestone, + PgMilestoneTransactions, + PgMilestoneTransactionsUpdate, + PgMilestoneUpdate, + PgMnemonic, + PgNft, + PgNftStake, + PgNotification, + PgProject, + PgProjectAdmins, + PgProjectApiKey, + PgProposal, + PgProposalMembers, + PgProposalOwners, + PgSoonSnapshot, + PgSoonSnapshotUpdate, + PgSpace, + PgSpaceGuardians, + PgSpaceMembers, + PgStake, + PgStakeReward, + PgStamp, + PgSwap, + PgSystem, + PgTicker, + PgToken, + PgTokenDistribution, + PgTokenMarket, + PgTokenPurchase, + PgTokenRanks, + PgTokenStats, + PgTokenVotes, + PgTransaction, +} from '../models'; +import { PgAirdropUpdate } from '../models/airdrop_update'; +import { PgAuctionUpdate } from '../models/auction_update'; +import { + PgAwardOwnersUpdate, + PgAwardParticipantsUpdate, + PgAwardUpdate, +} from '../models/award_update'; +import { + PgCollectionRanksUpdate, + PgCollectionStatsUpdate, + PgCollectionUpdate, + PgCollectionVotesUpdate, +} from '../models/collection_update'; +import { BaseRecord } from '../models/common'; +import { Update } from '../models/common_update'; +import { PgMemberUpdate } from '../models/member_update'; +import { PgMnemonicUpdate } from '../models/mnemonic_update'; +import { PgNftStakeUpdate, PgNftUpdate } from '../models/nft_update'; +import { PgNotificationUpdate } from '../models/notification_update'; +import { + PgProjectAdminsUpdate, + PgProjectApiKeyUpdate, + PgProjectUpdate, +} from '../models/project_update'; +import { + PgProposalMembersUpdate, + PgProposalOwnersUpdate, + PgProposalUpdate, +} from '../models/proposal_update'; +import { + PgSpaceGuardiansUpdate, + PgSpaceMembersUpdate, + PgSpaceUpdate, +} from '../models/space_update'; +import { PgStakeRewardUpdate, PgStakeUpdate } from '../models/stake_update'; +import { PgStampUpdate } from '../models/stamp_update'; +import { PgSwapUpdate } from '../models/swap_update'; +import { PgSystemUpdate } from '../models/system_update'; +import { PgTickerUpdate } from '../models/ticker_update'; +import { + PgTokenDistributionUpdate, + PgTokenMarketUpdate, + PgTokenPurchaseUpdate, + PgTokenRanksUpdate, + PgTokenStatsUpdate, + PgTokenUpdate, + PgTokenVotesUpdate, +} from '../models/token_update'; +import { PgTransactionUpdate } from '../models/transaction_update'; +import { getKnex, getKnexTran, knex, knextran } from './knex'; +import { subscriptions } from './pubsub'; +import { AirdropConverter, PgAirdropCollection } from './tables/airdrop'; +import { AuctionConverter } from './tables/auction'; +import { AwardConverter } from './tables/award'; +import { AwardOwnerConverter } from './tables/award_owner'; +import { AwardParticipantConverter } from './tables/award_participant'; +import { CollectionConverter, PgCollectionCollection } from './tables/collection'; +import { CollectionRankConverter } from './tables/collection_rank'; +import { CollectionStatsConverter } from './tables/collection_stats'; +import { CollectionVotesConverter } from './tables/collection_vote'; +import { MemberConverter } from './tables/member'; +import { MilestoneConverter } from './tables/milestone'; +import { + MilestoneTransactionConverter, + MilestoneTransactions, +} from './tables/milestone_transactions'; +import { MnemonicConverter } from './tables/mnemonic'; +import { NftConverter } from './tables/nft'; +import { NftStakeConverter } from './tables/nft_stake'; +import { NotificationConverter } from './tables/notification'; +import { ProjectConverter } from './tables/project'; +import { ProjectAdminConverter } from './tables/project_admin'; +import { ProjectApiKeyConverter } from './tables/project_api_key'; +import { ProposalConverter } from './tables/proposal'; +import { ProposalMemberConverter } from './tables/proposal_member'; +import { ProposalOwnerConverter } from './tables/proposal_owner'; +import { SoonSnapshotConverter } from './tables/soon_snapshot'; +import { SpaceConverter } from './tables/space'; +import { SpaceMemberConverter } from './tables/space_member'; +import { PgStakeCollection, StakeConverter } from './tables/stake'; +import { StakeRewardConverter } from './tables/stake_reward'; +import { StampConverter } from './tables/stamp'; +import { SwapConverter } from './tables/swap'; +import { SystemConverter } from './tables/system'; +import { TickerConverter } from './tables/ticker'; +import { TokenConverter } from './tables/token'; +import { + PgTokenDistributionCollection, + TokenDistributionConverter, +} from './tables/token_distribution'; +import { TokenTradeOrderConverter } from './tables/token_market'; +import { TokenPurchaseConverter } from './tables/token_purchase'; +import { TokenRankConverter } from './tables/token_rank'; +import { TokenStatsConverter } from './tables/token_stats'; +import { TokenVotesConverter } from './tables/token_vote'; +import { TransactionConverter } from './tables/transaction'; + +// prettier-ignore +export type IColType = + S extends undefined ? + T extends COL.MEMBER ? ICollection : + T extends COL.SPACE ? ICollection : + T extends COL.PROJECT ? ICollection : + T extends COL.COLLECTION ? PgCollectionCollection : + T extends COL.NFT ? ICollection : + T extends COL.NFT_STAKE ? ICollection : + T extends COL.TRANSACTION ? ICollection : + T extends COL.AUCTION ? ICollection : + T extends COL.AWARD ? ICollection : + T extends COL.TOKEN ? ICollection : + T extends COL.PROPOSAL ? ICollection : + T extends COL.STAKE_REWARD ? ICollection : + T extends COL.STAMP ? ICollection : + T extends COL.SWAP ? ICollection : + T extends COL.AIRDROP ? PgAirdropCollection : + T extends COL.TOKEN_MARKET ? ICollection : + T extends COL.STAKE ? PgStakeCollection : + T extends COL.TOKEN_PURCHASE ? ICollection : + T extends COL.MNEMONIC ? ICollection : + T extends COL.NOTIFICATION ? ICollection : + T extends COL.SYSTEM ? ICollection : + T extends COL.TICKER ? ICollection : + T extends COL.SOON_SNAP ? ICollection : + T extends COL.MILESTONE ? ICollection : + T extends COL.MILESTONE_RMS ? ICollection : + T extends COL.MILESTONE_SMR ? ICollection : + undefined : + S extends SUB_COL.OWNERS ? + T extends COL.AWARD ? ICollection : + T extends COL.PROPOSAL ? ICollection : + undefined: + S extends SUB_COL.PARTICIPANTS ? + T extends COL.AWARD ? ICollection : + undefined : + S extends SUB_COL.MEMBERS ? + T extends COL.SPACE ? ICollection : + T extends COL.PROPOSAL ? ICollection : + undefined : + S extends SUB_COL.BLOCKED_MEMBERS ? + T extends COL.SPACE ? ICollection : + undefined : + S extends SUB_COL.KNOCKING_MEMBERS ? + T extends COL.SPACE ? ICollection : + undefined : + S extends SUB_COL.GUARDIANS ? + T extends COL.SPACE ? ICollection : + undefined : + S extends SUB_COL.DISTRIBUTION ? + T extends COL.TOKEN ? PgTokenDistributionCollection : + undefined : + S extends SUB_COL.STATS ? + T extends COL.COLLECTION ? ICollection : + T extends COL.TOKEN ? ICollection : + undefined : + S extends SUB_COL.RANKS ? + T extends COL.TOKEN ? ICollection : + T extends COL.COLLECTION ? ICollection : + undefined : + S extends SUB_COL.VOTES ? + T extends COL.TOKEN ? ICollection : + T extends COL.COLLECTION ? ICollection : + undefined : + S extends SUB_COL.ADMINS ? + T extends COL.PROJECT ? ICollection : + undefined : + S extends SUB_COL._API_KEY ? + T extends COL.PROJECT ? ICollection : + undefined : + S extends SUB_COL.TRANSACTIONS ? ISubCollection : + undefined; + +// prettier-ignore +export type IDocType = + S extends undefined ? + T extends COL.MEMBER ? IDocument : + T extends COL.SPACE ? IDocument : + T extends COL.PROJECT ? IDocument : + T extends COL.COLLECTION ? IDocument : + T extends COL.NFT ? IDocument : + T extends COL.NFT_STAKE ? IDocument : + T extends COL.TRANSACTION ? IDocument : + T extends COL.AUCTION ? IDocument : + T extends COL.AWARD ? IDocument : + T extends COL.TOKEN ? IDocument : + T extends COL.PROPOSAL ? IDocument : + T extends COL.STAKE_REWARD ? IDocument : + T extends COL.STAMP ? IDocument : + T extends COL.SWAP ? IDocument : + T extends COL.AIRDROP ? IDocument : + T extends COL.TOKEN_MARKET ? IDocument : + T extends COL.STAKE ? IDocument : + T extends COL.TOKEN_PURCHASE ? IDocument : + T extends COL.MNEMONIC ? IDocument : + T extends COL.NOTIFICATION ? IDocument : + T extends COL.SYSTEM ? IDocument : + T extends COL.TICKER ? IDocument : + T extends COL.SOON_SNAP ? IDocument : + T extends COL.MILESTONE ? IDocument : + T extends COL.MILESTONE_SMR ? IDocument : + T extends COL.MILESTONE_RMS ? IDocument : + unknown : + S extends SUB_COL.OWNERS ? + T extends COL.AWARD ? IDocument : + T extends COL.PROPOSAL ? IDocument : + undefined: + S extends SUB_COL.PARTICIPANTS ? + T extends COL.AWARD ? IDocument : + undefined : + S extends SUB_COL.MEMBERS ? + T extends COL.SPACE ? IDocument : + T extends COL.PROPOSAL ? IDocument : + undefined : + S extends SUB_COL.BLOCKED_MEMBERS ? + T extends COL.SPACE ? IDocument : + undefined : + S extends SUB_COL.KNOCKING_MEMBERS ? + T extends COL.SPACE ? IDocument : + undefined : + S extends SUB_COL.GUARDIANS ? + T extends COL.SPACE ? IDocument : + undefined : + S extends SUB_COL.DISTRIBUTION ? + T extends COL.TOKEN ? ISubDocument : + undefined : + S extends SUB_COL.STATS ? + T extends COL.TOKEN ? IDocument : + T extends COL.COLLECTION ? IDocument : + undefined : + S extends SUB_COL.RANKS ? + T extends COL.TOKEN ? IDocument : + T extends COL.COLLECTION ? IDocument : + undefined : + S extends SUB_COL.VOTES ? + T extends COL.TOKEN ? IDocument : + T extends COL.COLLECTION ? IDocument : + undefined : + S extends SUB_COL.ADMINS ? + T extends COL.PROJECT ? IDocument : + undefined : + S extends SUB_COL._API_KEY ? + T extends COL.PROJECT ? IDocument : + undefined : + S extends SUB_COL.TRANSACTIONS ? ISubDocument : +undefined; + +export class PgDatabase implements IDatabase { + private readonly con: Knex; + + constructor() { + this.con = getKnex(); + } + + private getConverter = (col: COL, subCol?: SUB_COL) => { + if (!subCol) { + switch (col) { + case COL.MEMBER: + return new MemberConverter(); + case COL.SPACE: + return new SpaceConverter(); + case COL.PROJECT: + return new ProjectConverter(); + case COL.COLLECTION: + return new CollectionConverter(); + case COL.NFT: + return new NftConverter(); + case COL.NFT_STAKE: + return new NftStakeConverter(); + case COL.TRANSACTION: + return new TransactionConverter(); + case COL.AUCTION: + return new AuctionConverter(); + case COL.AWARD: + return new AwardConverter(); + case COL.TOKEN: + return new TokenConverter(); + case COL.PROPOSAL: + return new ProposalConverter(); + case COL.STAKE_REWARD: + return new StakeRewardConverter(); + case COL.STAMP: + return new StampConverter(); + case COL.SWAP: + return new SwapConverter(); + case COL.AIRDROP: + return new AirdropConverter(); + case COL.TOKEN_MARKET: + return new TokenTradeOrderConverter(); + case COL.STAKE: + return new StakeConverter(); + case COL.TOKEN_PURCHASE: + return new TokenPurchaseConverter(); + case COL.MNEMONIC: + return new MnemonicConverter(); + case COL.NOTIFICATION: + return new NotificationConverter(); + case COL.SYSTEM: + return new SystemConverter(); + case COL.TICKER: + return new TickerConverter(); + case COL.SOON_SNAP: + return new SoonSnapshotConverter(); + case COL.MILESTONE: + return new MilestoneConverter(); + case COL.MILESTONE_RMS: + return new MilestoneConverter(); + case COL.MILESTONE_SMR: + return new MilestoneConverter(); + default: + throw Error(`Invalid paramas ${col}, ${subCol}`); + } + } + if (col === COL.SPACE) { + if (subCol === SUB_COL.MEMBERS) return new SpaceMemberConverter(); + if (subCol === SUB_COL.BLOCKED_MEMBERS) return new SpaceMemberConverter(); + if (subCol === SUB_COL.KNOCKING_MEMBERS) return new SpaceMemberConverter(); + if (subCol === SUB_COL.GUARDIANS) return new SpaceMemberConverter(); + } + if (col === COL.AWARD) { + if (subCol === SUB_COL.OWNERS) return new AwardOwnerConverter(); + if (subCol === SUB_COL.PARTICIPANTS) return new AwardParticipantConverter(); + } + if (col === COL.PROPOSAL) { + if (subCol === SUB_COL.OWNERS) return new ProposalOwnerConverter(); + if (subCol === SUB_COL.MEMBERS) return new ProposalMemberConverter(); + } + if (col === COL.TOKEN) { + if (subCol === SUB_COL.DISTRIBUTION) return new TokenDistributionConverter(); + if (subCol === SUB_COL.STATS) return new TokenStatsConverter(); + if (subCol === SUB_COL.RANKS) return new TokenRankConverter(); + if (subCol === SUB_COL.VOTES) return new TokenVotesConverter(); + } + if (col === COL.COLLECTION) { + if (subCol === SUB_COL.STATS) return new CollectionStatsConverter(); + if (subCol === SUB_COL.RANKS) return new CollectionRankConverter(); + if (subCol === SUB_COL.VOTES) return new CollectionVotesConverter(); + } + if (col === COL.PROJECT) { + if (subCol === SUB_COL.ADMINS) return new ProjectAdminConverter(); + if (subCol === SUB_COL._API_KEY) return new ProjectApiKeyConverter(); + } + if (subCol === SUB_COL.TRANSACTIONS) { + return new MilestoneTransactionConverter(); + } + throw Error(`No converter ${col}, ${subCol}`); + }; + + collection = ( + col: C, + colId?: string, + subCol?: S, + ): IColType => { + const converter: Converter = this.getConverter(col, subCol); + if (subCol) { + if (col === COL.TOKEN && subCol === SUB_COL.DISTRIBUTION) { + return new PgTokenDistributionCollection( + this.con, + col, + colId, + subCol, + converter, + ) as unknown as IColType; + } + return new ISubCollection(this.con, col, colId, subCol, converter) as IColType; + } + + if (col === COL.AIRDROP) { + return new PgAirdropCollection(this.con, col, converter) as IColType; + } + if (col === COL.COLLECTION) { + return new PgCollectionCollection(this.con, col, converter) as IColType; + } + if (col === COL.STAKE) { + return new PgStakeCollection(this.con, col, converter) as unknown as IColType; + } + + return new ICollection(this.con, col, converter) as IColType; + }; + + doc = ( + col: C, + colId: string, + subCol?: S, + subColId?: string, + ): IDocType => { + return subCol && subColId + ? (this.collection(col, colId, subCol)!.doc(subColId) as IDocType) + : (this.collection(col)!.doc(colId) as IDocType); + }; + + batch = (): IBatch => new PgBatch(this.con); + + runTransaction = async (func: (transaction: ITransaction) => Promise) => { + for (let i = 0; i < 240; ++i) { + const con = getKnexTran(); + let trx: Knex.Transaction | undefined = undefined; + try { + trx = await con.transaction(); + const transaction = new PgRunTransaction(trx); + const result = await func(transaction); + if (transaction.allLocksAquired) { + await trx.commit(); + return result; + } else { + await trx.rollback(); + await new Promise((resolve) => setTimeout(resolve, Math.floor(Math.random() * 300))); + } + } catch (err) { + await trx?.rollback(); + throw err; + } finally { + await con.destroy(); + } + } + throw { code: 500, key: 'Failed to execute transaction' }; + }; + + inc = (value: number) => new Increment(value); + + arrayUnion = (value: T) => new ArrayUnion(value); + + arrayRemove = (value: T) => new ArrayRemove(value); + + destroy = async () => { + const promises: any[] = [knex?.destroy(), knextran?.destroy()]; + + for (const subs of Object.values(subscriptions)) { + promises.push((await subs).delete()); + } + + await Promise.allSettled(promises); + }; + + getCon = () => this.con; +} + +export const pgDateToTimestamp = (date: Date | string | undefined) => + date ? Timestamp.fromDate(dayjs(date).toDate()) : undefined; + +enum BatchAction { + C = 'create', + U = 'update', + UPS = 'upsert', + D = 'delete', +} + +export class PgBatch implements IBatch { + private changes: { docRef: IDocument; data: any; action: BatchAction }[] = []; + constructor(private readonly con: Knex) {} + + create = (docRef: IDocument, data: C) => { + this.changes.push({ docRef, data, action: BatchAction.C }); + }; + + update = (docRef: IDocument, data: U) => { + this.changes.push({ docRef, data, action: BatchAction.U }); + }; + + upsert = (docRef: IDocument, data: U) => { + this.changes.push({ docRef, data, action: BatchAction.UPS }); + }; + + delete = (docRef: IDocument) => { + this.changes.push({ docRef, data: undefined, action: BatchAction.D }); + }; + + commit = async () => { + const trx = await this.con.transaction(); + try { + for (const { docRef, data, action } of this.changes) { + switch (action) { + case BatchAction.C: + await docRef.useTransaction(trx, (doc) => doc.create(data)); + break; + case BatchAction.U: + await docRef.useTransaction(trx, (doc) => doc.update(data)); + break; + case BatchAction.UPS: + await docRef.useTransaction(trx, (doc) => doc.upsert(data)); + break; + case BatchAction.D: + await docRef.useTransaction(trx, (doc) => doc.delete()); + break; + } + } + await trx.commit(); + } catch (err) { + await trx.rollback(); + throw err; + } + }; +} + +export class PgRunTransaction implements ITransaction { + public allLocksAquired = true; + constructor(private readonly trx: Knex.Transaction) {} + + create = async ( + docRef: IDocument, + data: C, + ) => { + if (!this.allLocksAquired) { + return; + } + await docRef.useTransaction(this.trx, (doc) => doc.create(data)); + }; + + update = async ( + docRef: IDocument, + data: U, + ) => { + if (!this.allLocksAquired) { + return; + } + await docRef.useTransaction(this.trx, (doc) => doc.update(data)); + }; + + upsert = async ( + docRef: IDocument, + data: U, + ) => { + if (!this.allLocksAquired) { + return; + } + await docRef.useTransaction(this.trx, (doc) => doc.upsert(data)); + }; + + delete = async (docRef: IDocument) => { + if (!this.allLocksAquired) { + return; + } + await docRef.useTransaction(this.trx, (doc) => doc.delete()); + }; + + get = async (docRef: IDocument) => { + if (!this.allLocksAquired) { + return await docRef.get(); + } + try { + return await docRef.useTransaction(this.trx, (doc) => doc.get()); + } catch { + this.allLocksAquired = false; + return await docRef.get(); + } + }; + + getAll = async (...docRefs: IDocument[]) => { + if (!this.allLocksAquired) { + return []; + } + const promises = docRefs.map((docRef) => this.get(docRef)); + return await Promise.all(promises); + }; +} diff --git a/packages/database/src/pg/impl/pubsub.ts b/packages/database/src/pg/impl/pubsub.ts new file mode 100644 index 0000000000..4f60263cb0 --- /dev/null +++ b/packages/database/src/pg/impl/pubsub.ts @@ -0,0 +1,32 @@ +import { Message, PubSub, Subscription } from '@google-cloud/pubsub'; +import { Converter } from '../interfaces/common'; +import { BaseRecord } from '../models/common'; + +const pubSub = new PubSub(); +const topic = pubSub.topic('onupsert'); + +export const subscriptions: { [key: string]: Promise } = {}; + +export const getSubscription = (table: string) => { + if (!subscriptions[table]) { + const subsName = Math.random().toString().replace('0.', 'subs-onupsert-'); + subscriptions[table] = new Promise(async (res) => { + const [subscription] = await topic.createSubscription(subsName, { + filter: `attributes.table="${table}"`, + ackDeadlineSeconds: 600, + expirationPolicy: { ttl: { seconds: 86400 } }, + }); + subscription.setMaxListeners(0); + res(subscription); + }); + } + return subscriptions[table]; +}; + +export const getPgData = ( + message: Message, + converter: Converter, +) => { + const raw = JSON.parse(message.data.toString()); + return converter.toPg(converter.fromPg(raw)); +}; diff --git a/packages/database/src/pg/impl/tables/airdrop.ts b/packages/database/src/pg/impl/tables/airdrop.ts new file mode 100644 index 0000000000..0d0735cc65 --- /dev/null +++ b/packages/database/src/pg/impl/tables/airdrop.ts @@ -0,0 +1,62 @@ +import { StakeType, TokenDrop, TokenDropStatus } from '@build-5/interfaces'; +import { head } from 'lodash'; +import { ICollection } from '../../interfaces/collection'; +import { Converter } from '../../interfaces/common'; +import { PgAirdrop } from '../../models'; +import { PgAirdropUpdate } from '../../models/airdrop_update'; +import { removeNulls } from '../common'; +import { pgDateToTimestamp } from '../postgres'; + +export class PgAirdropCollection extends ICollection { + getUnclaimedAirdropTotalValue = async (token: string) => { + const snap = await this.con(this.table) + .select(this.con.raw('SUM(count) as count')) + .where({ token, status: TokenDropStatus.UNCLAIMED }); + return head(snap).count || 0; + }; +} + +export class AirdropConverter implements Converter { + toPg = (airdrop: TokenDrop): PgAirdrop => ({ + uid: airdrop.uid, + project: airdrop.project, + createdOn: airdrop.createdOn?.toDate(), + updatedOn: airdrop.updatedOn?.toDate(), + createdBy: airdrop.createdBy, + + member: airdrop.member, + token: airdrop.token, + award: airdrop.award, + vestingAt: airdrop.vestingAt?.toDate(), + count: airdrop.count, + status: airdrop.status, + orderId: airdrop.orderId, + billPaymentId: airdrop.billPaymentId, + sourceAddress: airdrop.sourceAddress, + stakeRewardId: airdrop.stakeRewardId, + stakeType: airdrop.stakeType, + isBaseToken: airdrop.isBaseToken, + }); + + fromPg = (pg: PgAirdrop): TokenDrop => + removeNulls({ + uid: pg.uid, + project: pg.project, + createdOn: pgDateToTimestamp(pg.createdOn), + updatedOn: pgDateToTimestamp(pg.updatedOn), + createdBy: pg.createdBy || '', + + member: pg.member!, + token: pg.token!, + award: pg.award, + vestingAt: pgDateToTimestamp(pg.vestingAt)!, + count: pg.count!, + status: pg.status as TokenDropStatus, + orderId: pg.orderId, + billPaymentId: pg.billPaymentId, + sourceAddress: pg.sourceAddress, + stakeRewardId: pg.stakeRewardId, + stakeType: pg.stakeType as StakeType, + isBaseToken: pg.isBaseToken, + }); +} diff --git a/packages/database/src/pg/impl/tables/auction.ts b/packages/database/src/pg/impl/tables/auction.ts new file mode 100644 index 0000000000..0818abd7ed --- /dev/null +++ b/packages/database/src/pg/impl/tables/auction.ts @@ -0,0 +1,63 @@ +import { Auction, AuctionBid, AuctionType, Network } from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgAuction } from '../../models'; +import { removeNulls } from '../common'; +import { pgDateToTimestamp } from '../postgres'; + +export class AuctionConverter implements Converter { + toPg = (auction: Auction): PgAuction => ({ + uid: auction.uid, + project: auction.project, + createdOn: auction.createdOn?.toDate(), + updatedOn: auction.updatedOn?.toDate(), + createdBy: auction.createdBy, + space: auction.space, + auctionFrom: auction.auctionFrom?.toDate(), + auctionTo: auction.auctionTo?.toDate(), + auctionLength: auction.auctionLength, + extendedAuctionTo: auction.extendedAuctionTo?.toDate(), + extendedAuctionLength: auction.extendedAuctionLength || undefined, + extendAuctionWithin: auction.extendAuctionWithin || undefined, + auctionFloorPrice: auction.auctionFloorPrice, + minimalBidIncrement: auction.minimalBidIncrement, + auctionHighestBidder: auction.auctionHighestBidder, + auctionHighestBid: auction.auctionHighestBid, + maxBids: auction.maxBids, + type: auction.type, + network: auction.network, + nftId: auction.nftId, + targetAddress: auction.targetAddress, + active: auction.active, + topUpBased: auction.topUpBased, + bids: JSON.stringify(auction.bids) as any, + }); + + fromPg = (pg: PgAuction): Auction => + removeNulls({ + uid: pg.uid, + project: pg.project, + createdOn: pgDateToTimestamp(pg.createdOn), + updatedOn: pgDateToTimestamp(pg.updatedOn), + createdBy: pg.createdBy || '', + + space: pg.space!, + auctionFrom: pgDateToTimestamp(pg.auctionFrom)!, + auctionTo: pgDateToTimestamp(pg.auctionTo)!, + auctionLength: pg.auctionLength || 0, + extendedAuctionTo: pgDateToTimestamp(pg.extendedAuctionTo), + extendedAuctionLength: pg.extendedAuctionLength, + extendAuctionWithin: pg.extendAuctionWithin, + auctionFloorPrice: pg.auctionFloorPrice || 0, + minimalBidIncrement: pg.minimalBidIncrement || 0, + bids: pg.bids as unknown as AuctionBid[], + auctionHighestBidder: pg.auctionHighestBidder, + auctionHighestBid: pg.auctionHighestBid, + maxBids: pg.maxBids || 0, + type: pg.type as AuctionType, + network: pg.network as Network, + nftId: pg.nftId, + targetAddress: pg.targetAddress, + active: pg.active || false, + topUpBased: pg.topUpBased, + }); +} diff --git a/packages/database/src/pg/impl/tables/award.ts b/packages/database/src/pg/impl/tables/award.ts new file mode 100644 index 0000000000..48c168c2c3 --- /dev/null +++ b/packages/database/src/pg/impl/tables/award.ts @@ -0,0 +1,107 @@ +import { Award, AwardBadgeType, MediaStatus, Network } from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgAward } from '../../models'; +import { removeNulls } from '../common'; +import { pgDateToTimestamp } from '../postgres'; + +export class AwardConverter implements Converter { + toPg = (award: Award): PgAward => ({ + uid: award.uid, + project: award.project, + createdOn: award.createdOn?.toDate(), + updatedOn: award.updatedOn?.toDate(), + createdBy: award.createdBy, + + name: award.name, + description: award.description, + space: award.space, + endDate: award.endDate?.toDate(), + issued: award.issued, + badgesMinted: award.badgesMinted, + approved: award.approved, + rejected: award.rejected, + completed: award.completed, + network: award.network, + aliasStorageDeposit: award.aliasStorageDeposit, + collectionStorageDeposit: award.collectionStorageDeposit, + nttStorageDeposit: award.nttStorageDeposit, + nativeTokenStorageDeposit: award.nativeTokenStorageDeposit, + funded: award.funded, + fundingAddress: award.fundingAddress, + fundedBy: award.fundedBy, + address: award.address, + airdropClaimed: award.airdropClaimed, + aliasBlockId: award.aliasBlockId, + aliasId: award.aliasId, + collectionBlockId: award.collectionBlockId, + collectionId: award.collectionId, + mediaStatus: award.mediaStatus, + mediaUploadErrorCount: award.mediaUploadErrorCount, + isLegacy: award.isLegacy, + badge_name: award.badge.name, + badge_description: award.badge?.description, + badge_total: award.badge?.total, + badge_type: award.badge?.type, + badge_tokenReward: award.badge?.tokenReward, + badge_tokenUid: award.badge?.tokenUid, + badge_tokenId: award.badge?.tokenId, + badge_tokenSymbol: award.badge?.tokenSymbol, + badge_image: award.badge?.image, + badge_ipfsMedia: award.badge?.ipfsMedia, + badge_ipfsMetadata: award.badge?.ipfsMetadata, + badge_ipfsRoot: award.badge?.ipfsRoot, + badge_lockTime: award.badge?.lockTime, + }); + + fromPg = (pg: PgAward): Award => + removeNulls({ + uid: pg.uid, + project: pg.project, + createdOn: pgDateToTimestamp(pg.createdOn), + updatedOn: pgDateToTimestamp(pg.updatedOn), + createdBy: pg.createdBy || '', + + name: pg.name || '', + description: pg.description || '', + space: pg.space || '', + endDate: pgDateToTimestamp(pg.endDate)!, + badge: { + name: pg.badge_name!, + description: pg.badge_description!, + total: pg.badge_total!, + type: pg.badge_type as AwardBadgeType, + tokenReward: pg.badge_tokenReward!, + tokenUid: pg.badge_tokenUid!, + tokenId: pg.badge_tokenId, + tokenSymbol: pg.badge_tokenSymbol!, + image: pg.badge_image, + ipfsMedia: pg.badge_ipfsMedia, + ipfsMetadata: pg.badge_ipfsMetadata, + ipfsRoot: pg.badge_ipfsRoot, + lockTime: pg.badge_lockTime || 0, + }, + + issued: pg.issued!, + badgesMinted: pg.badgesMinted!, + approved: pg.approved!, + rejected: pg.rejected!, + completed: pg.completed!, + network: (pg.network as Network)!, + aliasStorageDeposit: pg.aliasStorageDeposit!, + collectionStorageDeposit: pg.collectionStorageDeposit!, + nttStorageDeposit: pg.nttStorageDeposit!, + nativeTokenStorageDeposit: pg.nativeTokenStorageDeposit!, + funded: pg.funded!, + fundedBy: pg.fundedBy, + fundingAddress: pg.fundingAddress, + address: pg.address, + airdropClaimed: pg.airdropClaimed, + aliasBlockId: pg.aliasBlockId, + aliasId: pg.aliasId, + collectionBlockId: pg.collectionBlockId, + collectionId: pg.collectionId, + mediaStatus: pg.mediaStatus as MediaStatus, + mediaUploadErrorCount: pg.mediaUploadErrorCount, + isLegacy: pg.isLegacy, + }); +} diff --git a/packages/database/src/pg/impl/tables/award_owner.ts b/packages/database/src/pg/impl/tables/award_owner.ts new file mode 100644 index 0000000000..3f621e9b20 --- /dev/null +++ b/packages/database/src/pg/impl/tables/award_owner.ts @@ -0,0 +1,23 @@ +import { AwardOwner, COL } from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgAwardOwners } from '../../models'; +import { removeNulls } from '../common'; +import { pgDateToTimestamp } from '../postgres'; + +export class AwardOwnerConverter implements Converter { + toPg = (awardOwner: AwardOwner): PgAwardOwners => ({ + uid: awardOwner.uid, + project: awardOwner.project, + createdOn: awardOwner.createdOn?.toDate(), + parentId: awardOwner.parentId, + }); + + fromPg = (pg: PgAwardOwners): AwardOwner => + removeNulls({ + project: pg.project, + parentId: pg.parentId, + parentCol: COL.AWARD, + uid: pg.uid, + createdOn: pgDateToTimestamp(pg.createdOn), + }); +} diff --git a/packages/database/src/pg/impl/tables/award_participant.ts b/packages/database/src/pg/impl/tables/award_participant.ts new file mode 100644 index 0000000000..af8146a777 --- /dev/null +++ b/packages/database/src/pg/impl/tables/award_participant.ts @@ -0,0 +1,31 @@ +import { AwardParticipant, COL } from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgAwardParticipants } from '../../models'; +import { removeNulls } from '../common'; +import { pgDateToTimestamp } from '../postgres'; + +export class AwardParticipantConverter implements Converter { + toPg = (awardParticipant: AwardParticipant): PgAwardParticipants => ({ + uid: awardParticipant.uid, + project: awardParticipant.project, + createdOn: awardParticipant.createdOn?.toDate(), + parentId: awardParticipant.parentId, + comment: awardParticipant.comment || undefined, + completed: awardParticipant.completed, + count: awardParticipant.count, + tokenReward: awardParticipant.tokenReward, + }); + + fromPg = (pg: PgAwardParticipants): AwardParticipant => + removeNulls({ + uid: pg.uid, + project: pg.project, + parentId: pg.parentId, + parentCol: COL.AWARD, + comment: pg.comment, + completed: pg.completed || false, + createdOn: pgDateToTimestamp(pg.createdOn)!, + count: pg.count || 0, + tokenReward: pg.tokenReward || 0, + }); +} diff --git a/packages/database/src/pg/impl/tables/collection.ts b/packages/database/src/pg/impl/tables/collection.ts new file mode 100644 index 0000000000..128533e294 --- /dev/null +++ b/packages/database/src/pg/impl/tables/collection.ts @@ -0,0 +1,190 @@ +import { + Access, + Categories, + Collection, + CollectionStatus, + CollectionType, + DiscountLine, + MediaStatus, + Network, + UnsoldMintingOptions, +} from '@build-5/interfaces'; +import { get } from 'lodash'; +import { ICollection } from '../../interfaces/collection'; +import { Converter } from '../../interfaces/common'; +import { PgCollection } from '../../models'; +import { PgCollectionUpdate } from '../../models/collection_update'; +import { removeNulls } from '../common'; +import { pgDateToTimestamp } from '../postgres'; + +export class PgCollectionCollection extends ICollection< + Collection, + PgCollection, + PgCollectionUpdate +> { + updateFloorPrice = async () => { + await this.con(this.table).update({ + floorPrice: this.con.raw(`( + SELECT MIN("availablePrice") + FROM nft + WHERE collection = collection.uid AND + nft."saleAccess" = 0 AND + available IN (1, 3) + )`), + }); + }; +} + +export class CollectionConverter implements Converter { + toPg = (collection: Collection): PgCollection => ({ + uid: collection.uid, + project: collection.project, + createdOn: collection.createdOn?.toDate(), + updatedOn: collection.updatedOn?.toDate(), + createdBy: collection.createdBy, + name: collection.name, + description: collection.description, + bannerUrl: collection.bannerUrl, + royaltiesFee: collection.royaltiesFee, + royaltiesSpace: collection.royaltiesSpace, + total: collection.total, + totalTrades: collection.totalTrades, + lastTradedOn: collection.lastTradedOn?.toDate(), + sold: collection.sold, + discord: collection.discord, + url: collection.url, + twitter: collection.twitter, + approved: collection.approved, + rejected: collection.rejected, + limitedEdition: collection.limitedEdition, + ipfsMedia: collection.ipfsMedia, + ipfsMetadata: collection.ipfsMetadata, + ipfsRoot: collection.ipfsRoot, + category: collection.category, + type: collection.type, + access: collection.access, + accessAwards: collection.accessAwards, + accessCollections: collection.accessCollections, + space: collection.space, + availableFrom: collection.availableFrom?.toDate(), + price: collection.price, + availablePrice: collection.availablePrice, + onePerMemberOnly: collection.onePerMemberOnly, + placeholderNft: collection.placeholderNft, + placeholderUrl: collection.placeholderUrl, + status: collection.status, + mintingData_address: collection.mintingData?.address, + mintingData_network: collection.mintingData?.network, + mintingData_mintedOn: collection.mintingData?.mintedOn?.toDate(), + mintingData_mintedBy: collection.mintingData?.mintedBy, + mintingData_blockId: collection.mintingData?.blockId, + mintingData_nftId: collection.mintingData?.nftId, + mintingData_storageDeposit: collection.mintingData?.storageDeposit, + mintingData_aliasBlockId: collection.mintingData?.aliasBlockId, + mintingData_aliasId: collection.mintingData?.aliasId, + mintingData_aliasStorageDeposit: collection.mintingData?.aliasStorageDeposit, + mintingData_mintingOrderId: collection.mintingData?.mintingOrderId, + mintingData_nftsToMint: collection.mintingData?.nftsToMint, + mintingData_nftMediaToUpload: collection.mintingData?.nftMediaToUpload, + mintingData_nftMediaToPrepare: collection.mintingData?.nftMediaToPrepare, + mintingData_unsoldMintingOptions: collection.mintingData?.unsoldMintingOptions, + mintingData_newPrice: collection.mintingData?.newPrice, + mintingData_nftsStorageDeposit: collection.mintingData?.nftsStorageDeposit, + rankCount: collection.rankCount, + rankSum: collection.rankSum, + rankAvg: collection.rankAvg, + mediaStatus: collection.mediaStatus, + mediaUploadErrorCount: collection.mediaUploadErrorCount, + stakedNft: collection.stakedNft, + nftsOnSale: collection.nftsOnSale, + nftsOnAuction: collection.nftsOnAuction, + availableNfts: collection.availableNfts, + floorPrice: collection.floorPrice, + votes_upvotes: collection.votes?.upvotes, + votes_downvotes: collection.votes?.downvotes, + votes_voteDiff: collection.votes?.voteDiff, + }); + + fromPg = (pg: PgCollection): Collection => + removeNulls({ + uid: pg.uid, + project: pg.project, + createdOn: pgDateToTimestamp(pg.createdOn), + updatedOn: pgDateToTimestamp(pg.updatedOn), + createdBy: pg.createdBy, + name: pg.name || '', + description: pg.description || '', + bannerUrl: pg.bannerUrl || '', + royaltiesFee: pg.royaltiesFee || 0, + royaltiesSpace: pg.royaltiesSpace, + discounts: ((pg.discounts as any) || []).map( + (d: any) => + ({ + tokenUid: get(d, 'tokenUid', ''), + tokenSymbol: get(d, 'tokenSymbol', ''), + tokenReward: get(d, 'tokenReward', 0), + amount: get(d, 'amount', 0), + }) as DiscountLine, + ), + total: pg.total || 0, + totalTrades: pg.totalTrades || 0, + lastTradedOn: pgDateToTimestamp(pg.lastTradedOn) || null, + sold: pg.sold || 0, + discord: pg.discord || '', + url: pg.url || '', + twitter: pg.twitter || '', + approved: pg.approved || false, + rejected: pg.rejected || false, + limitedEdition: pg.limitedEdition, + ipfsMedia: pg.ipfsMedia, + ipfsMetadata: pg.ipfsMetadata, + ipfsRoot: pg.ipfsRoot, + category: (pg.category as Categories)!, + type: pg.type as CollectionType, + access: pg.access as Access, + accessAwards: pg.accessAwards || [], + accessCollections: pg.accessCollections || [], + space: pg.space, + availableFrom: pgDateToTimestamp(pg.availableFrom)!, + price: pg.price || 0, + availablePrice: pg.availablePrice || 0, + onePerMemberOnly: pg.onePerMemberOnly || false, + placeholderNft: pg.placeholderNft || '', + placeholderUrl: pg.placeholderUrl || '', + status: pg.status as CollectionStatus, + mintingData: { + address: pg.mintingData_address, + network: pg.mintingData_network as Network, + mintedOn: pgDateToTimestamp(pg.mintingData_mintedOn), + mintedBy: pg.mintingData_mintedBy, + blockId: pg.mintingData_blockId, + nftId: pg.mintingData_nftId, + storageDeposit: pg.mintingData_storageDeposit, + aliasBlockId: pg.mintingData_aliasBlockId, + aliasId: pg.mintingData_aliasId, + aliasStorageDeposit: pg.mintingData_aliasStorageDeposit, + mintingOrderId: pg.mintingData_mintingOrderId, + nftsToMint: pg.mintingData_nftsToMint, + nftMediaToUpload: pg.mintingData_nftMediaToUpload, + nftMediaToPrepare: pg.mintingData_nftMediaToPrepare, + unsoldMintingOptions: pg.mintingData_unsoldMintingOptions as UnsoldMintingOptions, + newPrice: pg.mintingData_newPrice, + nftsStorageDeposit: pg.mintingData_nftsStorageDeposit, + }, + rankCount: pg.rankCount, + rankSum: pg.rankSum, + rankAvg: pg.rankAvg, + mediaStatus: pg.mediaStatus as MediaStatus, + mediaUploadErrorCount: pg.mediaUploadErrorCount, + stakedNft: pg.stakedNft, + nftsOnSale: pg.nftsOnSale, + nftsOnAuction: pg.nftsOnAuction, + availableNfts: pg.availableNfts, + floorPrice: pg.floorPrice, + votes: { + upvotes: pg.votes_upvotes || 0, + downvotes: pg.votes_downvotes || 0, + voteDiff: pg.votes_voteDiff || 0, + }, + }); +} diff --git a/packages/database/src/pg/impl/tables/collection_rank.ts b/packages/database/src/pg/impl/tables/collection_rank.ts new file mode 100644 index 0000000000..d903ea4948 --- /dev/null +++ b/packages/database/src/pg/impl/tables/collection_rank.ts @@ -0,0 +1,22 @@ +import { COL, Rank } from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgCollectionRanks } from '../../models'; +import { removeNulls } from '../common'; + +export class CollectionRankConverter implements Converter { + toPg = (r: Rank): PgCollectionRanks => ({ + uid: r.uid!, + project: r.project, + parentId: r.parentId, + rank: r.rank, + }); + + fromPg = (pg: PgCollectionRanks): Rank => + removeNulls({ + uid: pg.uid, + project: pg.project, + parentId: pg.parentId, + parentCol: COL.COLLECTION, + rank: pg.rank!, + }); +} diff --git a/packages/database/src/pg/impl/tables/collection_stats.ts b/packages/database/src/pg/impl/tables/collection_stats.ts new file mode 100644 index 0000000000..b25219e422 --- /dev/null +++ b/packages/database/src/pg/impl/tables/collection_stats.ts @@ -0,0 +1,36 @@ +import { COL, CollectionStats } from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgCollectionStats } from '../../models'; +import { removeNulls } from '../common'; + +export class CollectionStatsConverter implements Converter { + toPg = (s: CollectionStats): PgCollectionStats => ({ + uid: s.uid!, + project: s.project, + parentId: s.parentId, + votes_upvotes: s.votes?.upvotes, + votes_downvotes: s.votes?.downvotes, + votes_voteDiff: s.votes?.voteDiff, + ranks_count: s.ranks?.count, + ranks_sum: s.ranks?.sum, + ranks_avg: s.ranks?.avg, + }); + + fromPg = (pg: PgCollectionStats): CollectionStats => + removeNulls({ + uid: pg.uid, + project: pg.project, + parentId: pg.parentId, + parentCol: COL.COLLECTION, + votes: { + upvotes: pg.votes_upvotes || 0, + downvotes: pg.votes_downvotes || 0, + voteDiff: pg.votes_voteDiff || 0, + }, + ranks: { + count: pg.ranks_count || 0, + sum: pg.ranks_sum || 0, + avg: pg.ranks_avg || 0, + }, + }); +} diff --git a/packages/database/src/pg/impl/tables/collection_vote.ts b/packages/database/src/pg/impl/tables/collection_vote.ts new file mode 100644 index 0000000000..83edd436a7 --- /dev/null +++ b/packages/database/src/pg/impl/tables/collection_vote.ts @@ -0,0 +1,22 @@ +import { COL, Vote } from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgCollectionVotes } from '../../models'; +import { removeNulls } from '../common'; + +export class CollectionVotesConverter implements Converter { + toPg = (r: Vote): PgCollectionVotes => ({ + uid: r.uid!, + project: r.project, + parentId: r.parentId, + direction: r.direction, + }); + + fromPg = (pg: PgCollectionVotes): Vote => + removeNulls({ + uid: pg.uid, + project: pg.project, + parentId: pg.parentId, + parentCol: COL.COLLECTION, + direction: pg.direction! as 1 | -1, + }); +} diff --git a/packages/database/src/pg/impl/tables/member.ts b/packages/database/src/pg/impl/tables/member.ts new file mode 100644 index 0000000000..df843b1099 --- /dev/null +++ b/packages/database/src/pg/impl/tables/member.ts @@ -0,0 +1,67 @@ +import { Member, Network } from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgMember } from '../../models'; +import { removeNulls } from '../common'; +import { pgDateToTimestamp } from '../postgres'; + +export class MemberConverter implements Converter { + toPg = (member: Member): PgMember => ({ + uid: member.uid, + project: member.project, + createdOn: member.createdOn?.toDate(), + updatedOn: member.updatedOn?.toDate(), + createdBy: member.createdBy, + nonce: member.nonce, + name: member.name, + about: member.about, + avatarNft: member.avatarNft, + avatar: member.avatar, + discord: member.discord, + twitter: member.twitter, + github: member.github, + + smrAddress: (member.validatedAddress || {})[Network.SMR], + rmsAddress: (member.validatedAddress || {})[Network.RMS], + iotaAddress: (member.validatedAddress || {})[Network.IOTA], + atoiAddress: (member.validatedAddress || {})[Network.ATOI], + + prevValidatedAddresses: member.prevValidatedAddresses, + tokenTradingFeePercentage: member.tokenTradingFeePercentage, + tokenPurchaseFeePercentage: member.tokenPurchaseFeePercentage, + awardsCompleted: member.awardsCompleted, + + spaces: member.spaces, + }); + + fromPg = (member: PgMember): Member => + removeNulls({ + uid: member.uid, + project: member.project || '', + createdOn: pgDateToTimestamp(member.createdOn), + updatedOn: pgDateToTimestamp(member.updatedOn), + createdBy: member.createdBy || '', + nonce: member.nonce || '', + name: member.name || '', + about: member.about || '', + avatarNft: member.avatarNft || '', + avatar: member.avatar || '', + discord: member.discord || '', + twitter: member.twitter || '', + github: member.github || '', + + validatedAddress: { + [Network.SMR]: member.smrAddress || '', + [Network.RMS]: member.rmsAddress || '', + [Network.IOTA]: member.iotaAddress || '', + [Network.ATOI]: member.atoiAddress || '', + }, + + prevValidatedAddresses: member.prevValidatedAddresses, + + spaces: member.spaces as any, + + tokenTradingFeePercentage: member.tokenTradingFeePercentage, + tokenPurchaseFeePercentage: member.tokenPurchaseFeePercentage, + awardsCompleted: member.awardsCompleted, + }); +} diff --git a/packages/database/src/pg/impl/tables/milestone.ts b/packages/database/src/pg/impl/tables/milestone.ts new file mode 100644 index 0000000000..e37b378350 --- /dev/null +++ b/packages/database/src/pg/impl/tables/milestone.ts @@ -0,0 +1,36 @@ +import { Milestone } from '@build-5/interfaces'; +import { get } from 'lodash'; +import { Converter } from '../../interfaces/common'; +import { PgMilestone } from '../../models'; +import { pgDateToTimestamp } from '../postgres'; + +export class MilestoneConverter implements Converter { + toPg = (milestone: Milestone): PgMilestone => ({ + uid: get(milestone, 'uid', ''), + createdOn: milestone.createdOn?.toDate(), + completed: milestone.completed, + completedOn: milestone.completedOn?.toDate(), + listenerNodeId: milestone.listenerNodeId, + milestone: milestone.milestone, + milestoneTimestamp: milestone.milestoneTimestamp?.toDate(), + trxConflictCount: milestone.trxConflictCount, + trxFailedCount: milestone.trxFailedCount, + trxValidCount: milestone.trxValidCount, + }); + + fromPg = (pg: PgMilestone): Milestone => ({ + createdOn: pgDateToTimestamp(pg.createdOn)!, + completedOn: pgDateToTimestamp(pg.completedOn)!, + milestone: pg.milestone!, + completed: pg.completed!, + listenerNodeId: pg.listenerNodeId!, + milestoneTimestamp: pgDateToTimestamp(pg.milestoneTimestamp)!, + trxConflictCount: pg.trxConflictCount!, + trxFailedCount: pg.trxFailedCount!, + trxValidCount: pg.trxValidCount!, + + transactions: {}, + cmi: 0, + processed: true, + }); +} diff --git a/packages/database/src/pg/impl/tables/milestone_transactions.ts b/packages/database/src/pg/impl/tables/milestone_transactions.ts new file mode 100644 index 0000000000..f358b031a2 --- /dev/null +++ b/packages/database/src/pg/impl/tables/milestone_transactions.ts @@ -0,0 +1,53 @@ +import { Timestamp } from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgMilestoneTransactions } from '../../models'; +import { pgDateToTimestamp } from '../postgres'; + +export interface MilestoneTransactions { + uid: string; + parentId: string; + + createdOn: Timestamp; + updatedOn: Timestamp; + + PayloadSize: number; + + blockId: string; + milestone: number; + payload: any; + processed: boolean; + processedOn: Timestamp; +} + +export class MilestoneTransactionConverter + implements Converter +{ + toPg = (mt: MilestoneTransactions): PgMilestoneTransactions => ({ + uid: mt.uid, + parentId: mt.milestone.toString(), + createdOn: mt.createdOn?.toDate(), + updatedOn: mt.updatedOn?.toDate(), + PayloadSize: mt.PayloadSize, + blockId: mt.blockId, + milestone: mt.milestone, + payload: JSON.stringify(mt.payload) as any, + processed: mt.processed, + processedOn: mt.processedOn?.toDate(), + }); + + fromPg = (pg: PgMilestoneTransactions): MilestoneTransactions => ({ + uid: pg.uid, + parentId: pg.parentId, + + createdOn: pgDateToTimestamp(pg.createdOn)!, + updatedOn: pgDateToTimestamp(pg.updatedOn)!, + + PayloadSize: pg.PayloadSize!, + + blockId: pg.blockId!, + milestone: pg.milestone!, + payload: pg.payload, + processed: pg.processed!, + processedOn: pgDateToTimestamp(pg.processedOn)!, + }); +} diff --git a/packages/database/src/pg/impl/tables/mnemonic.ts b/packages/database/src/pg/impl/tables/mnemonic.ts new file mode 100644 index 0000000000..9e240dd962 --- /dev/null +++ b/packages/database/src/pg/impl/tables/mnemonic.ts @@ -0,0 +1,38 @@ +import { Mnemonic, Network } from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgMnemonic } from '../../models'; +import { removeNulls } from '../common'; +import { pgDateToTimestamp } from '../postgres'; + +export class MnemonicConverter implements Converter { + toPg = (mnemonic: Mnemonic): PgMnemonic => ({ + uid: mnemonic.uid, + project: mnemonic.project, + createdOn: mnemonic.createdOn?.toDate(), + updatedOn: mnemonic.updatedOn?.toDate(), + createdBy: mnemonic.createdBy, + + mnemonic: mnemonic.mnemonic, + network: mnemonic.network, + lockedBy: mnemonic.lockedBy, + consumedOutputIds: mnemonic.consumedOutputIds, + consumedNftOutputIds: mnemonic.consumedNftOutputIds, + consumedAliasOutputIds: mnemonic.consumedAliasOutputIds, + }); + + fromPg = (pg: PgMnemonic): Mnemonic => + removeNulls({ + uid: pg.uid, + project: pg.project, + createdOn: pgDateToTimestamp(pg.createdOn), + updatedOn: pgDateToTimestamp(pg.updatedOn), + createdBy: pg.createdBy || '', + + mnemonic: pg.mnemonic, + network: pg.network as Network, + lockedBy: pg.lockedBy, + consumedOutputIds: pg.consumedOutputIds, + consumedNftOutputIds: pg.consumedNftOutputIds, + consumedAliasOutputIds: pg.consumedAliasOutputIds, + }); +} diff --git a/packages/database/src/pg/impl/tables/nft.ts b/packages/database/src/pg/impl/tables/nft.ts new file mode 100644 index 0000000000..d90404ad20 --- /dev/null +++ b/packages/database/src/pg/impl/tables/nft.ts @@ -0,0 +1,198 @@ +import { + CollectionType, + MediaStatus, + Network, + Nft, + NftAccess, + NftAvailable, + NftStatus, + PropStats, + UnsoldMintingOptions, +} from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgNft } from '../../models'; +import { removeNulls } from '../common'; +import { pgDateToTimestamp } from '../postgres'; + +export class NftConverter implements Converter { + toPg = (nft: Nft): PgNft => ({ + uid: nft.uid, + project: nft.project, + createdOn: nft.createdOn?.toDate(), + updatedOn: nft.updatedOn?.toDate(), + createdBy: nft.createdBy, + name: nft.name, + description: nft.description, + collection: nft.collection, + owner: nft.owner, + isOwned: nft.isOwned, + media: nft.media, + ipfsMedia: nft.ipfsMedia, + ipfsMetadata: nft.ipfsMetadata, + ipfsRoot: nft.ipfsRoot, + saleAccess: nft.saleAccess, + saleAccessMembers: nft.saleAccessMembers, + available: nft.available, + availableFrom: nft.availableFrom?.toDate(), + auctionFrom: nft.auctionFrom?.toDate(), + auctionTo: nft.auctionTo?.toDate(), + extendedAuctionTo: nft.extendedAuctionTo?.toDate(), + auctionHighestBid: nft.auctionHighestBid || 0, + auctionHighestBidder: nft.auctionHighestBidder || '', + price: nft.price, + totalTrades: nft.totalTrades, + lastTradedOn: nft.lastTradedOn?.toDate(), + availablePrice: nft.availablePrice || 0, + auctionFloorPrice: nft.auctionFloorPrice || 0, + auctionLength: nft.auctionLength || 0, + extendedAuctionLength: nft.extendedAuctionLength || 0, + extendAuctionWithin: nft.extendAuctionWithin || 0, + type: nft.type, + space: nft.space, + url: nft.url, + approved: nft.approved, + rejected: nft.rejected, + properties: nft.properties ? (JSON.stringify(nft.properties) as any) : undefined, + stats: nft.stats ? (JSON.stringify(nft.stats) as any) : undefined, + placeholderNft: nft.placeholderNft, + position: nft.position, + locked: nft.locked, + lockedBy: nft.lockedBy || '', + sold: nft.sold, + mintingData_address: nft.mintingData?.address, + mintingData_network: nft.mintingData?.network, + mintingData_mintedOn: nft.mintingData?.mintedOn?.toDate(), + mintingData_mintedBy: nft.mintingData?.mintedBy, + mintingData_blockId: nft.mintingData?.blockId, + mintingData_nftId: nft.mintingData?.nftId, + mintingData_storageDeposit: nft.mintingData?.storageDeposit, + mintingData_aliasBlockId: nft.mintingData?.aliasBlockId, + mintingData_aliasId: nft.mintingData?.aliasId, + mintingData_aliasStorageDeposit: nft.mintingData?.aliasStorageDeposit, + mintingData_mintingOrderId: nft.mintingData?.mintingOrderId, + mintingData_nftsToMint: nft.mintingData?.nftsToMint, + mintingData_nftMediaToUpload: nft.mintingData?.nftMediaToUpload, + mintingData_nftMediaToPrepare: nft.mintingData?.nftMediaToPrepare, + mintingData_unsoldMintingOptions: nft.mintingData?.unsoldMintingOptions, + mintingData_newPrice: nft.mintingData?.newPrice, + mintingData_nftsStorageDeposit: nft.mintingData?.nftsStorageDeposit, + depositData_address: nft.depositData?.address, + depositData_network: nft.depositData?.network, + depositData_mintedOn: nft.depositData?.mintedOn?.toDate(), + depositData_mintedBy: nft.depositData?.mintedBy, + depositData_blockId: nft.depositData?.blockId, + depositData_nftId: nft.depositData?.nftId, + depositData_storageDeposit: nft.depositData?.storageDeposit, + depositData_aliasBlockId: nft.depositData?.aliasBlockId, + depositData_aliasId: nft.depositData?.aliasId, + depositData_aliasStorageDeposit: nft.depositData?.aliasStorageDeposit, + depositData_mintingOrderId: nft.depositData?.mintingOrderId, + depositData_nftsToMint: nft.depositData?.nftsToMint, + depositData_nftMediaToUpload: nft.depositData?.nftMediaToUpload, + depositData_nftMediaToPrepare: nft.depositData?.nftMediaToPrepare, + depositData_unsoldMintingOptions: nft.depositData?.unsoldMintingOptions, + depositData_newPrice: nft.depositData?.newPrice, + depositData_nftsStorageDeposit: nft.depositData?.nftsStorageDeposit, + status: nft.status, + hidden: nft.hidden, + mediaStatus: nft.mediaStatus, + mediaUploadErrorCount: nft.mediaUploadErrorCount, + soldOn: nft.soldOn?.toDate(), + setAsAvatar: nft.setAsAvatar, + auction: nft.auction || undefined, + }); + + fromPg = (nft: PgNft): Nft => + removeNulls({ + uid: nft.uid, + project: nft.project, + createdOn: pgDateToTimestamp(nft.createdOn), + updatedOn: pgDateToTimestamp(nft.updatedOn), + createdBy: nft.createdBy || '', + name: nft.name || '', + description: nft.description || '', + collection: nft.collection || '', + owner: nft.owner, + isOwned: nft.isOwned, + media: nft.media || '', + ipfsMedia: nft.ipfsMedia || '', + ipfsMetadata: nft.ipfsMetadata || '', + ipfsRoot: nft.ipfsRoot || '', + saleAccess: nft.saleAccess as NftAccess, + saleAccessMembers: nft.saleAccessMembers, + available: nft.available as NftAvailable, + availableFrom: pgDateToTimestamp(nft.availableFrom) || null, + auctionFrom: pgDateToTimestamp(nft.auctionFrom) || null, + auctionTo: pgDateToTimestamp(nft.auctionTo), + extendedAuctionTo: pgDateToTimestamp(nft.extendedAuctionTo), + auctionHighestBid: nft.auctionHighestBid, + auctionHighestBidder: nft.auctionHighestBidder, + price: nft.price || 0, + totalTrades: nft.totalTrades || 0, + lastTradedOn: pgDateToTimestamp(nft.lastTradedOn) || null, + availablePrice: nft.availablePrice, + auctionFloorPrice: nft.auctionFloorPrice, + auctionLength: nft.auctionLength, + extendedAuctionLength: nft.extendedAuctionLength, + extendAuctionWithin: nft.extendAuctionWithin, + type: nft.type as CollectionType, + space: nft.space || '', + url: nft.url || '', + approved: nft.approved || false, + rejected: nft.rejected || false, + properties: nft.properties as unknown as PropStats, + stats: nft.stats as unknown as PropStats, + placeholderNft: nft.placeholderNft || false, + locked: nft.locked, + lockedBy: nft.lockedBy, + sold: nft.sold, + mintingData: { + address: nft.mintingData_address, + network: nft.mintingData_network as Network, + mintedOn: pgDateToTimestamp(nft.mintingData_mintedOn), + mintedBy: nft.mintingData_mintedBy, + blockId: nft.mintingData_blockId, + nftId: nft.mintingData_nftId, + storageDeposit: nft.mintingData_storageDeposit, + aliasBlockId: nft.mintingData_aliasBlockId, + aliasId: nft.mintingData_aliasId, + aliasStorageDeposit: nft.mintingData_aliasStorageDeposit, + mintingOrderId: nft.mintingData_mintingOrderId, + nftsToMint: nft.mintingData_nftsToMint, + nftMediaToUpload: nft.mintingData_nftMediaToUpload, + nftMediaToPrepare: nft.mintingData_nftMediaToPrepare, + unsoldMintingOptions: nft.mintingData_unsoldMintingOptions as UnsoldMintingOptions, + newPrice: nft.mintingData_newPrice, + nftsStorageDeposit: nft.mintingData_nftsStorageDeposit, + }, + depositData: nft.depositData_address + ? { + address: nft.depositData_address, + network: nft.depositData_network as Network, + mintedOn: pgDateToTimestamp(nft.depositData_mintedOn), + mintedBy: nft.depositData_mintedBy, + blockId: nft.depositData_blockId, + nftId: nft.depositData_nftId, + storageDeposit: nft.depositData_storageDeposit, + aliasBlockId: nft.depositData_aliasBlockId, + aliasId: nft.depositData_aliasId, + aliasStorageDeposit: nft.depositData_aliasStorageDeposit, + mintingOrderId: nft.depositData_mintingOrderId, + nftsToMint: nft.depositData_nftsToMint, + nftMediaToUpload: nft.depositData_nftMediaToUpload, + nftMediaToPrepare: nft.depositData_nftMediaToPrepare, + unsoldMintingOptions: nft.depositData_unsoldMintingOptions as UnsoldMintingOptions, + newPrice: nft.depositData_newPrice, + nftsStorageDeposit: nft.depositData_nftsStorageDeposit, + } + : undefined, + status: nft.status as NftStatus, + mediaStatus: nft.mediaStatus as MediaStatus, + mediaUploadErrorCount: nft.mediaUploadErrorCount, + soldOn: pgDateToTimestamp(nft.soldOn), + setAsAvatar: nft.setAsAvatar, + auction: nft.auction, + position: nft.position!, + hidden: nft.hidden, + }); +} diff --git a/packages/database/src/pg/impl/tables/nft_stake.ts b/packages/database/src/pg/impl/tables/nft_stake.ts new file mode 100644 index 0000000000..b43a9e1f83 --- /dev/null +++ b/packages/database/src/pg/impl/tables/nft_stake.ts @@ -0,0 +1,40 @@ +import { NftStake, StakeType } from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgNftStake } from '../../models'; +import { removeNulls } from '../common'; +import { pgDateToTimestamp } from '../postgres'; + +export class NftStakeConverter implements Converter { + toPg = (nftStake: NftStake): PgNftStake => ({ + uid: nftStake.uid, + project: nftStake.project, + createdOn: nftStake.createdOn?.toDate(), + updatedOn: nftStake.updatedOn?.toDate(), + createdBy: nftStake.createdBy, + member: nftStake.member, + space: nftStake.space, + collection: nftStake.collection, + nft: nftStake.nft, + weeks: nftStake.weeks, + expiresAt: nftStake.expiresAt?.toDate(), + expirationProcessed: nftStake.expirationProcessed, + type: nftStake.type, + }); + + fromPg = (nftStake: PgNftStake): NftStake => + removeNulls({ + uid: nftStake.uid, + project: nftStake.project, + createdOn: pgDateToTimestamp(nftStake.createdOn), + updatedOn: pgDateToTimestamp(nftStake.updatedOn), + createdBy: nftStake.createdBy || '', + member: nftStake.member || '', + space: nftStake.space || '', + nft: nftStake.nft || '', + collection: nftStake.collection || '', + weeks: nftStake.weeks || 0, + expiresAt: pgDateToTimestamp(nftStake.expiresAt)!, + expirationProcessed: nftStake.expirationProcessed!, + type: nftStake.type as StakeType, + }); +} diff --git a/packages/database/src/pg/impl/tables/notification.ts b/packages/database/src/pg/impl/tables/notification.ts new file mode 100644 index 0000000000..d0d548b66b --- /dev/null +++ b/packages/database/src/pg/impl/tables/notification.ts @@ -0,0 +1,42 @@ +import { + Notification, + NotificationBidParams, + NotificationLostBidParams, + NotificationType, + NotificationWinBidParams, +} from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgNotification } from '../../models'; +import { removeNulls } from '../common'; +import { pgDateToTimestamp } from '../postgres'; + +export class NotificationConverter implements Converter { + toPg = (notification: Notification): PgNotification => ({ + uid: notification.uid, + project: notification.project, + createdOn: notification.createdOn?.toDate(), + updatedOn: notification.updatedOn?.toDate(), + createdBy: notification.createdBy, + space: notification.space, + member: notification.member, + type: notification.type, + params: JSON.stringify(notification.params || {}) as any, + }); + + fromPg = (pg: PgNotification): Notification => + removeNulls({ + uid: pg.uid, + project: pg.project, + createdOn: pgDateToTimestamp(pg.createdOn), + updatedOn: pgDateToTimestamp(pg.updatedOn), + createdBy: pg.createdBy || '', + + space: pg.space, + member: pg.member, + type: pg.type as NotificationType, + params: pg.params as unknown as + | NotificationBidParams + | NotificationWinBidParams + | NotificationLostBidParams, + }); +} diff --git a/packages/database/src/pg/impl/tables/project.ts b/packages/database/src/pg/impl/tables/project.ts new file mode 100644 index 0000000000..5cd39438f7 --- /dev/null +++ b/packages/database/src/pg/impl/tables/project.ts @@ -0,0 +1,42 @@ +import { Project, ProjectBilling, ProjectOtr } from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgProject } from '../../models'; +import { removeNulls } from '../common'; +import { pgDateToTimestamp } from '../postgres'; + +export class ProjectConverter implements Converter { + toPg = (project: Project): PgProject => ({ + uid: project.uid, + createdOn: project.createdOn?.toDate(), + updatedOn: project.updatedOn?.toDate(), + createdBy: project.createdBy, + name: project.name, + contactEmail: project.contactEmail, + deactivated: project.deactivated, + config_billing: project.config?.billing, + config_tiers: project.config?.tiers, + config_tokenTradingFeeDiscountPercentage: project.config?.tokenTradingFeeDiscountPercentage, + config_nativeTokenSymbol: project.config?.nativeTokenSymbol, + config_nativeTokenUid: project.config?.nativeTokenUid, + otr: JSON.stringify(project.otr || {}) as any, + }); + + fromPg = (project: PgProject): Project => + removeNulls({ + uid: project.uid, + createdOn: pgDateToTimestamp(project.createdOn), + updatedOn: pgDateToTimestamp(project.updatedOn), + createdBy: project.createdBy, + name: project.name || '', + contactEmail: project.contactEmail, + deactivated: project.deactivated, + config: { + billing: project.config_billing as ProjectBilling, + tiers: project.config_tiers, + tokenTradingFeeDiscountPercentage: project.config_tokenTradingFeeDiscountPercentage, + nativeTokenSymbol: project.config_nativeTokenSymbol, + nativeTokenUid: project.config_nativeTokenUid, + }, + otr: project.otr as unknown as { [key: string]: ProjectOtr }, + }); +} diff --git a/packages/database/src/pg/impl/tables/project_admin.ts b/packages/database/src/pg/impl/tables/project_admin.ts new file mode 100644 index 0000000000..4bf511425c --- /dev/null +++ b/packages/database/src/pg/impl/tables/project_admin.ts @@ -0,0 +1,23 @@ +import { COL, ProjectAdmin } from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgProjectAdmins } from '../../models'; +import { removeNulls } from '../common'; +import { pgDateToTimestamp } from '../postgres'; + +export class ProjectAdminConverter implements Converter { + toPg = (projectAdmin: ProjectAdmin): PgProjectAdmins => ({ + uid: projectAdmin.uid, + project: projectAdmin.project, + createdOn: projectAdmin.createdOn?.toDate(), + parentId: projectAdmin.parentId, + }); + + fromPg = (pg: PgProjectAdmins): ProjectAdmin => + removeNulls({ + uid: pg.uid, + project: pg.project, + parentId: pg.parentId, + parentCol: COL.PROJECT, + createdOn: pgDateToTimestamp(pg.createdOn)!, + }); +} diff --git a/packages/database/src/pg/impl/tables/project_api_key.ts b/packages/database/src/pg/impl/tables/project_api_key.ts new file mode 100644 index 0000000000..04d8f6919d --- /dev/null +++ b/packages/database/src/pg/impl/tables/project_api_key.ts @@ -0,0 +1,25 @@ +import { COL, ProjectApiKey } from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgProjectApiKey } from '../../models'; +import { removeNulls } from '../common'; +import { pgDateToTimestamp } from '../postgres'; + +export class ProjectApiKeyConverter implements Converter { + toPg = (pk: ProjectApiKey): PgProjectApiKey => ({ + uid: pk.uid, + project: pk.project, + createdOn: pk.createdOn?.toDate(), + parentId: pk.parentId, + token: pk.token, + }); + + fromPg = (pg: PgProjectApiKey): ProjectApiKey => + removeNulls({ + uid: pg.uid, + project: pg.project, + parentId: pg.parentId, + parentCol: COL.PROJECT, + createdOn: pgDateToTimestamp(pg.createdOn)!, + token: pg.token!, + }); +} diff --git a/packages/database/src/pg/impl/tables/proposal.ts b/packages/database/src/pg/impl/tables/proposal.ts new file mode 100644 index 0000000000..c446cd7995 --- /dev/null +++ b/packages/database/src/pg/impl/tables/proposal.ts @@ -0,0 +1,79 @@ +import { Proposal, ProposalMember, ProposalQuestion, ProposalType } from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgProposal } from '../../models'; +import { removeNulls } from '../common'; +import { pgDateToTimestamp } from '../postgres'; + +export class ProposalConverter implements Converter { + toPg = (proposal: Proposal) => ({ + uid: proposal.uid, + project: proposal.project, + createdOn: proposal.createdOn?.toDate(), + updatedOn: proposal.updatedOn?.toDate(), + createdBy: proposal.createdBy, + + space: proposal.space, + name: proposal.name, + description: proposal.description, + additionalInfo: proposal.additionalInfo, + type: proposal.type, + approved: proposal.approved, + rejected: proposal.rejected, + approvedBy: proposal.approvedBy, + rejectedBy: proposal.rejectedBy, + eventId: proposal.eventId, + totalWeight: proposal.totalWeight, + token: proposal.token, + completed: proposal.completed, + rank: proposal.rank, + settings_startDate: proposal.settings.startDate?.toDate(), + settings_endDate: proposal.settings?.endDate?.toDate(), + settings_guardiansOnly: proposal.settings?.guardiansOnly, + settings_addRemoveGuardian: proposal.settings?.addRemoveGuardian, + settings_spaceUpdateData: JSON.stringify(proposal.settings?.spaceUpdateData) as any, + settings_onlyGuardians: proposal.settings?.onlyGuardians, + settings_stakeRewardIds: proposal.settings?.stakeRewardIds, + settings_awards: proposal.settings?.awards, + questions: JSON.stringify(proposal.questions) as any, + members: JSON.stringify(proposal.members) as any, + + results: proposal.results, + }); + + fromPg = (pg: PgProposal): Proposal => + removeNulls({ + uid: pg.uid, + project: pg.project, + createdOn: pgDateToTimestamp(pg.createdOn), + updatedOn: pgDateToTimestamp(pg.updatedOn), + createdBy: pg.createdBy || '', + + name: pg.name!, + additionalInfo: pg.additionalInfo, + space: pg.space!, + members: pg.members as unknown as { [propName: string]: ProposalMember } | undefined, + description: pg.description!, + type: pg.type as ProposalType, + approved: pg.approved!, + approvedBy: pg.approvedBy, + rejected: pg.rejected, + rejectedBy: pg.rejectedBy, + eventId: pg.eventId, + settings: { + startDate: pgDateToTimestamp(pg.settings_startDate)!, + endDate: pgDateToTimestamp(pg.settings_endDate)!, + guardiansOnly: pg.settings_guardiansOnly, + addRemoveGuardian: pg.settings_addRemoveGuardian, + spaceUpdateData: pg.settings_spaceUpdateData as unknown as any, + onlyGuardians: pg.settings_onlyGuardians, + stakeRewardIds: pg.settings_stakeRewardIds, + awards: pg.settings_awards, + }, + totalWeight: pg.totalWeight, + questions: pg.questions as unknown as ProposalQuestion[], + results: pg.results, + token: pg.token, + completed: pg.completed || false, + rank: pg.rank, + }); +} diff --git a/packages/database/src/pg/impl/tables/proposal_member.ts b/packages/database/src/pg/impl/tables/proposal_member.ts new file mode 100644 index 0000000000..bbf031c5fb --- /dev/null +++ b/packages/database/src/pg/impl/tables/proposal_member.ts @@ -0,0 +1,49 @@ +import { COL, ProposalMember } from '@build-5/interfaces'; +import { get } from 'lodash'; +import { Converter } from '../../interfaces/common'; +import { PgProposalMembers } from '../../models'; +import { removeNulls } from '../common'; +import { pgDateToTimestamp } from '../postgres'; + +export class ProposalMemberConverter implements Converter { + toPg = (pm: ProposalMember): PgProposalMembers => ({ + uid: pm.uid, + project: pm.project, + createdOn: pm.createdOn?.toDate(), + parentId: pm.parentId, + voted: pm.voted, + weight: pm.weight, + tranId: pm.tranId, + values: (pm.values || []).reduce((acc, act) => { + const value = Object.keys(act).filter((k) => k !== 'voteTransaction')[0]; + const voteTranId = get(act, 'voteTransaction', ''); + return { ...acc, [voteTranId]: { value, weight: get(act, value, 0) } }; + }, {}), + }); + + fromPg = (pg: PgProposalMembers): ProposalMember => + removeNulls({ + uid: pg.uid, + project: pg.project, + parentId: pg.parentId, + parentCol: COL.PROPOSAL, + createdOn: pgDateToTimestamp(pg.createdOn)!, + voted: pg.voted, + weight: pg.weight, + weightPerAnswer: Object.values(pg.values || {}).reduce( + (acc: { [key: number]: number }, act: any) => { + const value = Number(act.value); + const weight = act.weight; + return { ...acc, [value]: (acc[value] || 0) + weight }; + }, + {} as { [key: number]: number }, + ), + tranId: pg.tranId, + values: Object.entries(pg.values || {}).map(([key, value]) => { + return { + [Number(get(value, 'value'))]: get(value, 'weight', 0), + voteTransaction: key, + }; + }), + }); +} diff --git a/packages/database/src/pg/impl/tables/proposal_owner.ts b/packages/database/src/pg/impl/tables/proposal_owner.ts new file mode 100644 index 0000000000..b7162c06b4 --- /dev/null +++ b/packages/database/src/pg/impl/tables/proposal_owner.ts @@ -0,0 +1,23 @@ +import { COL, ProposalMember } from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgProposalMembers, PgProposalOwners } from '../../models'; +import { removeNulls } from '../common'; +import { pgDateToTimestamp } from '../postgres'; + +export class ProposalOwnerConverter implements Converter { + toPg = (proposalOwner: ProposalMember): PgProposalOwners => ({ + uid: proposalOwner.uid, + project: proposalOwner.project, + createdOn: proposalOwner.createdOn?.toDate(), + parentId: proposalOwner.parentId, + }); + + fromPg = (pg: PgProposalOwners): ProposalMember => + removeNulls({ + uid: pg.uid, + project: pg.project, + parentId: pg.parentId, + parentCol: COL.PROPOSAL, + createdOn: pgDateToTimestamp(pg.createdOn)!, + }); +} diff --git a/packages/database/src/pg/impl/tables/soon_snapshot.ts b/packages/database/src/pg/impl/tables/soon_snapshot.ts new file mode 100644 index 0000000000..80d81ede7b --- /dev/null +++ b/packages/database/src/pg/impl/tables/soon_snapshot.ts @@ -0,0 +1,36 @@ +import { SoonSnap } from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgSoonSnapshot } from '../../models'; +import { removeNulls } from '../common'; +import { pgDateToTimestamp } from '../postgres'; + +export class SoonSnapshotConverter implements Converter { + toPg = (snapshot: SoonSnap): PgSoonSnapshot => ({ + uid: snapshot.uid, + project: snapshot.project, + createdOn: snapshot.createdOn?.toDate(), + updatedOn: snapshot.updatedOn?.toDate(), + createdBy: snapshot.createdBy, + + count: snapshot.count, + paidOut: snapshot.paidOut, + lastPaidOutOn: snapshot.lastPaidOutOn?.toDate(), + ethAddress: snapshot.ethAddress, + ethAddressVerified: snapshot.ethAddressVerified, + }); + + fromPg = (pg: PgSoonSnapshot): SoonSnap => + removeNulls({ + uid: pg.uid, + project: pg.project, + createdOn: pgDateToTimestamp(pg.createdOn), + updatedOn: pgDateToTimestamp(pg.updatedOn), + createdBy: pg.createdBy || '', + + count: pg.count, + paidOut: pg.paidOut, + lastPaidOutOn: pgDateToTimestamp(pg.lastPaidOutOn), + ethAddress: pg.ethAddress, + ethAddressVerified: pg.ethAddressVerified, + }); +} diff --git a/packages/database/src/pg/impl/tables/space.ts b/packages/database/src/pg/impl/tables/space.ts new file mode 100644 index 0000000000..65cfe845a3 --- /dev/null +++ b/packages/database/src/pg/impl/tables/space.ts @@ -0,0 +1,92 @@ +import { MediaStatus, Network, Space } from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgSpace } from '../../models'; +import { removeNulls } from '../common'; +import { pgDateToTimestamp } from '../postgres'; + +export class SpaceConverter implements Converter { + toPg = (space: Space): PgSpace => ({ + uid: space.uid, + project: space.project, + createdOn: space.createdOn?.toDate(), + updatedOn: space.updatedOn?.toDate(), + createdBy: space.createdBy, + name: space.name, + about: space.about, + open: space.open, + tokenBased: space.tokenBased, + minStakedValue: space.minStakedValue, + github: space.github, + twitter: space.twitter, + discord: space.discord, + avatarUrl: space.avatarUrl, + bannerUrl: space.bannerUrl, + totalGuardians: space.totalGuardians, + totalMembers: space.totalMembers, + totalPendingMembers: space.totalPendingMembers, + smrAddress: (space.validatedAddress || {})[Network.SMR], + rmsAddress: (space.validatedAddress || {})[Network.RMS], + iotaAddress: (space.validatedAddress || {})[Network.IOTA], + atoiAddress: (space.validatedAddress || {})[Network.ATOI], + prevValidatedAddresses: space.prevValidatedAddresses || [], + vaultAddress: space.vaultAddress, + collectionId: space.collectionId, + claimed: space.claimed, + ipfsMedia: space.ipfsMedia, + ipfsMetadata: space.ipfsMetadata, + ipfsRoot: space.ipfsRoot, + mediaStatus: space.mediaStatus, + mediaUploadErrorCount: space.mediaUploadErrorCount, + alias_address: space.alias?.address, + alias_aliasId: space.alias?.aliasId, + alias_blockId: space.alias?.blockId, + alias_mintedOn: space.alias?.mintedOn?.toDate(), + alias_mintedBy: space.alias?.mintedBy, + }); + + fromPg = (pg: PgSpace): Space => + removeNulls({ + uid: pg.uid, + project: pg.project, + createdOn: pgDateToTimestamp(pg.createdOn), + updatedOn: pgDateToTimestamp(pg.updatedOn), + createdBy: pg.createdBy || '', + name: pg.name, + about: pg.about, + open: pg.open, + tokenBased: pg.tokenBased, + minStakedValue: pg.minStakedValue, + github: pg.github, + twitter: pg.twitter, + discord: pg.discord, + avatarUrl: pg.avatarUrl, + bannerUrl: pg.bannerUrl, + totalGuardians: pg.totalGuardians || 0, + totalMembers: pg.totalMembers || 0, + totalPendingMembers: pg.totalPendingMembers || 0, + validatedAddress: { + [Network.SMR]: pg.smrAddress || '', + [Network.RMS]: pg.rmsAddress || '', + [Network.IOTA]: pg.iotaAddress || '', + [Network.ATOI]: pg.atoiAddress || '', + }, + prevValidatedAddresses: pg.prevValidatedAddresses, + vaultAddress: pg.vaultAddress, + collectionId: pg.collectionId, + claimed: pg.claimed, + ipfsMedia: pg.ipfsMedia, + ipfsMetadata: pg.ipfsMetadata, + ipfsRoot: pg.ipfsRoot, + mediaStatus: pg.mediaStatus as MediaStatus, + mediaUploadErrorCount: pg.mediaUploadErrorCount, + members: {}, + guardians: {}, + alias: { + address: pg.alias_address || '', + aliasId: pg.alias_aliasId || '', + blockId: pg.alias_blockId || '', + mintedOn: pgDateToTimestamp(pg.alias_mintedOn)!, + mintedBy: pg.alias_mintedBy || '', + }, + }); +} diff --git a/packages/database/src/pg/impl/tables/space_guardians.ts b/packages/database/src/pg/impl/tables/space_guardians.ts new file mode 100644 index 0000000000..ef3d2282ae --- /dev/null +++ b/packages/database/src/pg/impl/tables/space_guardians.ts @@ -0,0 +1,23 @@ +import { COL, SpaceGuardian } from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgSpaceGuardians } from '../../models'; +import { removeNulls } from '../common'; +import { pgDateToTimestamp } from '../postgres'; + +export class SpaceGuardianConverter implements Converter { + toPg = (spaceGuardian: SpaceGuardian): PgSpaceGuardians => ({ + uid: spaceGuardian.uid, + project: spaceGuardian.project, + createdOn: spaceGuardian.createdOn?.toDate(), + parentId: spaceGuardian.parentId, + }); + + fromPg = (pg: PgSpaceGuardians): SpaceGuardian => + removeNulls({ + project: pg.project, + parentId: pg.parentId, + parentCol: COL.PROPOSAL, + uid: pg.uid, + createdOn: pgDateToTimestamp(pg.createdOn)!, + }); +} diff --git a/packages/database/src/pg/impl/tables/space_member.ts b/packages/database/src/pg/impl/tables/space_member.ts new file mode 100644 index 0000000000..1f797b9fd2 --- /dev/null +++ b/packages/database/src/pg/impl/tables/space_member.ts @@ -0,0 +1,23 @@ +import { COL, SpaceMember } from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgSpaceMembers } from '../../models'; +import { removeNulls } from '../common'; +import { pgDateToTimestamp } from '../postgres'; + +export class SpaceMemberConverter implements Converter { + toPg = (spaceMember: SpaceMember): PgSpaceMembers => ({ + uid: spaceMember.uid, + project: spaceMember.project, + createdOn: spaceMember.createdOn?.toDate(), + parentId: spaceMember.parentId, + }); + + fromPg = (pg: PgSpaceMembers): SpaceMember => + removeNulls({ + project: pg.project, + parentId: pg.parentId, + parentCol: COL.SPACE, + uid: pg.uid, + createdOn: pgDateToTimestamp(pg.createdOn)!, + }); +} diff --git a/packages/database/src/pg/impl/tables/stake.ts b/packages/database/src/pg/impl/tables/stake.ts new file mode 100644 index 0000000000..09106c8d85 --- /dev/null +++ b/packages/database/src/pg/impl/tables/stake.ts @@ -0,0 +1,68 @@ +import { Stake, StakeReward, StakeType } from '@build-5/interfaces'; +import { ICollection } from '../../interfaces/collection'; +import { Converter } from '../../interfaces/common'; +import { PgStake } from '../../models'; +import { PgStakeUpdate } from '../../models/stake_update'; +import { removeNulls } from '../common'; +import { pgDateToTimestamp } from '../postgres'; + +export class PgStakeCollection extends ICollection { + getStakeSumPerMember = async (stakeReward: StakeReward): Promise<{ [key: string]: number }> => { + const result = await this.con(this.col) + .select('member') + .select(this.con.raw('SUM(value) as value')) + .where({ token: stakeReward.token }) + .where({ type: StakeType.DYNAMIC }) + .where('expiresAt', '>=', stakeReward.startDate.toDate()) + .where('createdOn', '<=', stakeReward.endDate.toDate()) + .groupBy('member'); + return (result as { member: string; value: number }[]).reduce( + (acc, act) => ({ ...acc, [act.member]: act.value }), + {} as { [key: string]: number }, + ); + }; +} + +export class StakeConverter implements Converter { + toPg = (stake: Stake): PgStake => ({ + uid: stake.uid, + project: stake.project, + createdOn: stake.createdOn?.toDate(), + updatedOn: stake.updatedOn?.toDate(), + createdBy: stake.createdBy, + + member: stake.member, + space: stake.space, + token: stake.token, + amount: stake.amount, + value: stake.value, + weeks: stake.weeks, + expiresAt: stake.expiresAt?.toDate(), + expirationProcessed: stake.expirationProcessed, + orderId: stake.orderId, + billPaymentId: stake.billPaymentId, + type: stake.type, + customMetadata: JSON.stringify(stake.customMetadata) as any, + }); + + fromPg = (pg: PgStake): Stake => + removeNulls({ + uid: pg.uid, + project: pg.project, + createdOn: pgDateToTimestamp(pg.createdOn), + updatedOn: pgDateToTimestamp(pg.updatedOn), + createdBy: pg.createdBy || '', + member: pg.member!, + space: pg.space!, + token: pg.token!, + amount: pg.amount!, + value: pg.value!, + weeks: pg.weeks!, + expiresAt: pgDateToTimestamp(pg.expiresAt)!, + expirationProcessed: pg.expirationProcessed!, + orderId: pg.orderId!, + billPaymentId: pg.billPaymentId!, + type: pg.type as StakeType, + customMetadata: pg.customMetadata as { [key: string]: string } | undefined, + }); +} diff --git a/packages/database/src/pg/impl/tables/stake_reward.ts b/packages/database/src/pg/impl/tables/stake_reward.ts new file mode 100644 index 0000000000..fbee44499a --- /dev/null +++ b/packages/database/src/pg/impl/tables/stake_reward.ts @@ -0,0 +1,41 @@ +import { StakeReward, StakeRewardStatus } from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgStakeReward } from '../../models'; +import { removeNulls } from '../common'; +import { pgDateToTimestamp } from '../postgres'; + +export class StakeRewardConverter implements Converter { + toPg = (sr: StakeReward): PgStakeReward => ({ + uid: sr.uid, + project: sr.project, + createdOn: sr.createdOn?.toDate(), + updatedOn: sr.updatedOn?.toDate(), + createdBy: sr.createdBy, + + startDate: sr.startDate?.toDate(), + endDate: sr.endDate?.toDate(), + tokenVestingDate: sr.tokenVestingDate?.toDate(), + tokensToDistribute: sr.tokensToDistribute, + token: sr.token, + totalStaked: sr.totalStaked, + totalAirdropped: sr.totalAirdropped, + status: sr.status, + }); + + fromPg = (pg: PgStakeReward): StakeReward => + removeNulls({ + uid: pg.uid, + project: pg.project, + createdOn: pgDateToTimestamp(pg.createdOn), + updatedOn: pgDateToTimestamp(pg.updatedOn), + createdBy: pg.createdBy || '', + startDate: pgDateToTimestamp(pg.startDate)!, + endDate: pgDateToTimestamp(pg.endDate)!, + tokenVestingDate: pgDateToTimestamp(pg.tokenVestingDate)!, + tokensToDistribute: pg.tokensToDistribute!, + token: pg.token!, + status: pg.status as StakeRewardStatus, + totalStaked: pg.totalStaked, + totalAirdropped: pg.totalAirdropped, + }); +} diff --git a/packages/database/src/pg/impl/tables/stamp.ts b/packages/database/src/pg/impl/tables/stamp.ts new file mode 100644 index 0000000000..605c6cea2d --- /dev/null +++ b/packages/database/src/pg/impl/tables/stamp.ts @@ -0,0 +1,62 @@ +import { MediaStatus, Network, Stamp } from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgStamp } from '../../models'; +import { removeNulls } from '../common'; +import { pgDateToTimestamp } from '../postgres'; + +export class StampConverter implements Converter { + toPg = (stamp: Stamp): PgStamp => ({ + uid: stamp.uid, + project: stamp.project, + createdOn: stamp.createdOn?.toDate(), + updatedOn: stamp.updatedOn?.toDate(), + createdBy: stamp.createdBy, + + space: stamp.space, + build5Url: stamp.build5Url, + originUri: stamp.originUri, + checksum: stamp.checksum, + extension: stamp.extension, + bytes: stamp.bytes, + costPerMb: stamp.costPerMb, + network: stamp.network, + ipfsMedia: stamp.ipfsMedia, + ipfsRoot: stamp.ipfsRoot, + expiresAt: stamp.expiresAt.toDate(), + order: stamp.order, + funded: stamp.funded, + expired: stamp.expired, + mediaStatus: stamp.mediaStatus, + mediaUploadErrorCount: stamp.mediaUploadErrorCount, + nftId: stamp.nftId, + aliasId: stamp.aliasId, + }); + + fromPg = (pg: PgStamp): Stamp => + removeNulls({ + uid: pg.uid, + project: pg.project, + createdOn: pgDateToTimestamp(pg.createdOn), + updatedOn: pgDateToTimestamp(pg.updatedOn), + createdBy: pg.createdBy || '', + + space: pg.space!, + build5Url: pg.build5Url!, + originUri: pg.originUri!, + checksum: pg.checksum!, + extension: pg.extension!, + bytes: pg.bytes!, + costPerMb: pg.costPerMb!, + network: pg.network as Network, + ipfsMedia: pg.ipfsMedia, + ipfsRoot: pg.ipfsRoot, + expiresAt: pgDateToTimestamp(pg.expiresAt)!, + order: pg.order!, + funded: pg.funded!, + expired: pg.expired!, + mediaStatus: pg.mediaStatus as MediaStatus, + mediaUploadErrorCount: pg.mediaUploadErrorCount, + aliasId: pg.aliasId, + nftId: pg.nftId, + }); +} diff --git a/packages/database/src/pg/impl/tables/swap.ts b/packages/database/src/pg/impl/tables/swap.ts new file mode 100644 index 0000000000..46db8ec944 --- /dev/null +++ b/packages/database/src/pg/impl/tables/swap.ts @@ -0,0 +1,46 @@ +import { NativeToken, Network, Swap, SwapOutput, SwapStatus } from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgSwap } from '../../models'; +import { removeNulls } from '../common'; +import { pgDateToTimestamp } from '../postgres'; + +export class SwapConverter implements Converter { + toPg = (swap: Swap): PgSwap => ({ + uid: swap.uid, + project: swap.project, + createdOn: swap.createdOn?.toDate(), + updatedOn: swap.updatedOn?.toDate(), + createdBy: swap.createdBy, + + recipient: swap.recipient, + network: swap.network, + address: swap.address, + orderId: swap.orderId, + nftIdsAsk: swap.nftIdsAsk, + baseTokenAmountAsk: swap.baseTokenAmountAsk, + nativeTokensAsk: JSON.stringify(swap.nativeTokensAsk) as any, + status: swap.status, + bidOutputs: JSON.stringify(swap.bidOutputs) as any, + askOutputs: JSON.stringify(swap.askOutputs) as any, + }); + + fromPg = (pg: PgSwap): Swap => + removeNulls({ + uid: pg.uid, + project: pg.project, + createdOn: pgDateToTimestamp(pg.createdOn), + updatedOn: pgDateToTimestamp(pg.updatedOn), + createdBy: pg.createdBy || '', + + recipient: pg.recipient!, + network: pg.network as Network, + address: pg.address!, + orderId: pg.orderId!, + bidOutputs: pg.bidOutputs as unknown as SwapOutput[], + nftIdsAsk: pg.nftIdsAsk!, + baseTokenAmountAsk: pg.baseTokenAmountAsk!, + nativeTokensAsk: pg.nativeTokensAsk as unknown as NativeToken[], + askOutputs: pg.askOutputs as unknown as SwapOutput[], + status: pg.status as SwapStatus, + }); +} diff --git a/packages/database/src/pg/impl/tables/system.ts b/packages/database/src/pg/impl/tables/system.ts new file mode 100644 index 0000000000..d08752181b --- /dev/null +++ b/packages/database/src/pg/impl/tables/system.ts @@ -0,0 +1,19 @@ +import { SystemConfig } from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgSystem } from '../../models'; +import { removeNulls } from '../common'; + +export class SystemConverter implements Converter { + toPg = (system: SystemConfig): PgSystem => ({ + uid: system.uid, + tokenTradingFeePercentage: system.tokenTradingFeePercentage, + tokenPurchaseFeePercentage: system.tokenPurchaseFeePercentage, + }); + + fromPg = (pg: PgSystem): SystemConfig => + removeNulls({ + uid: pg.uid, + tokenTradingFeePercentage: pg.tokenTradingFeePercentage, + tokenPurchaseFeePercentage: pg.tokenPurchaseFeePercentage, + }); +} diff --git a/packages/database/src/pg/impl/tables/ticker.ts b/packages/database/src/pg/impl/tables/ticker.ts new file mode 100644 index 0000000000..e656403704 --- /dev/null +++ b/packages/database/src/pg/impl/tables/ticker.ts @@ -0,0 +1,18 @@ +import { Ticker } from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgTicker } from '../../models'; + +export class TickerConverter implements Converter { + toPg = (ticker: Ticker): PgTicker => ({ + uid: ticker.uid, + createdOn: ticker.createdOn?.toDate(), + updatedOn: ticker.updatedOn?.toDate(), + createdBy: ticker.createdBy, + price: ticker.price, + }); + + fromPg = (ticker: PgTicker): Ticker => ({ + uid: ticker.uid, + price: ticker.price || 0, + }); +} diff --git a/packages/database/src/pg/impl/tables/token.ts b/packages/database/src/pg/impl/tables/token.ts new file mode 100644 index 0000000000..de59e18b26 --- /dev/null +++ b/packages/database/src/pg/impl/tables/token.ts @@ -0,0 +1,151 @@ +import { + Access, + MediaStatus, + Network, + Token, + TokenAllocation, + TokenStatus, +} from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgToken } from '../../models'; +import { removeNulls } from '../common'; +import { pgDateToTimestamp } from '../postgres'; + +export class TokenConverter implements Converter { + toPg = (token: Token): PgToken => ({ + uid: token.uid, + project: token.project, + createdOn: token.createdOn?.toDate(), + updatedOn: token.updatedOn?.toDate(), + createdBy: token.createdBy, + + name: token.name, + symbol: token.symbol, + title: token.title, + description: token.description, + shortDescriptionTitle: token.shortDescriptionTitle, + shortDescription: token.shortDescription, + space: token.space, + pricePerToken: token.pricePerToken, + totalSupply: token.totalSupply, + allocations: JSON.stringify(token.allocations) as any, + saleStartDate: token.saleStartDate?.toDate(), + saleLength: token.saleLength, + coolDownEnd: token.coolDownEnd?.toDate(), + autoProcessAt100Percent: token.autoProcessAt100Percent, + approved: token.approved, + rejected: token.rejected, + public: token.public, + links: token.links?.map((u) => u.toString()), + icon: token.icon, + overviewGraphics: token.overviewGraphics, + status: token.status, + totalDeposit: token.totalDeposit, + tokensOrdered: token.tokensOrdered, + totalAirdropped: token.totalAirdropped, + termsAndConditions: token.termsAndConditions, + access: token.access, + accessAwards: token.accessAwards, + accessCollections: token.accessCollections, + ipfsMedia: token.ipfsMedia, + ipfsMetadata: token.ipfsMetadata, + ipfsRoot: token.ipfsRoot, + mintingData_mintedBy: token.mintingData?.mintedBy, + mintingData_mintedOn: token.mintingData?.mintedOn?.toDate(), + mintingData_aliasBlockId: token.mintingData?.aliasBlockId, + mintingData_aliasId: token.mintingData?.aliasId, + mintingData_aliasStorageDeposit: token.mintingData?.aliasStorageDeposit, + mintingData_tokenId: token.mintingData?.tokenId, + mintingData_blockId: token.mintingData?.blockId, + mintingData_foundryStorageDeposit: token.mintingData?.foundryStorageDeposit, + mintingData_network: token.mintingData?.network, + mintingData_networkFormat: token.mintingData?.networkFormat, + mintingData_vaultAddress: token.mintingData?.vaultAddress, + mintingData_tokensInVault: token.mintingData?.tokensInVault, + mintingData_vaultStorageDeposit: token.mintingData?.vaultStorageDeposit, + mintingData_guardianStorageDeposit: token.mintingData?.guardianStorageDeposit, + mintingData_meltedTokens: token.mintingData?.meltedTokens, + mintingData_circulatingSupply: token.mintingData?.circulatingSupply, + rankCount: token.rankCount, + rankSum: token.rankSum, + rankAvg: token.rankAvg, + mediaStatus: token.mediaStatus, + mediaUploadErrorCount: token.mediaUploadErrorCount, + tradingDisabled: token.tradingDisabled, + decimals: token.decimals, + votes_upvotes: token.votes?.upvotes, + votes_downvotes: token.votes?.downvotes, + votes_voteDiff: token.votes?.voteDiff, + }); + + fromPg = (pg: PgToken): Token => + removeNulls({ + uid: pg.uid, + project: pg.project, + createdOn: pgDateToTimestamp(pg.createdOn), + updatedOn: pgDateToTimestamp(pg.updatedOn), + createdBy: pg.createdBy || '', + + name: pg.name || '', + symbol: pg.symbol || '', + title: pg.title, + description: pg.description, + shortDescriptionTitle: pg.shortDescriptionTitle, + shortDescription: pg.shortDescription, + space: pg.space, + pricePerToken: pg.pricePerToken || 0, + totalSupply: pg.totalSupply || 0, + allocations: pg.allocations as unknown as TokenAllocation[], + saleStartDate: pgDateToTimestamp(pg.saleStartDate), + saleLength: pg.saleLength, + coolDownEnd: pgDateToTimestamp(pg.coolDownEnd), + autoProcessAt100Percent: pg.autoProcessAt100Percent, + approved: pg.approved || false, + rejected: pg.rejected || false, + public: pg.public, + links: (pg.links || []).map((l) => new URL(l)), + icon: pg.icon, + overviewGraphics: pg.overviewGraphics, + status: (pg.status as TokenStatus)!, + totalDeposit: pg.totalDeposit || 0, + tokensOrdered: pg.tokensOrdered, + totalAirdropped: pg.totalAirdropped || 0, + termsAndConditions: pg.termsAndConditions || '', + access: pg.access as Access, + accessAwards: pg.accessAwards, + accessCollections: pg.accessCollections, + ipfsMedia: pg.ipfsMedia, + ipfsMetadata: pg.ipfsMetadata, + ipfsRoot: pg.ipfsRoot, + mintingData: { + mintedBy: pg.mintingData_mintedBy, + mintedOn: pgDateToTimestamp(pg.mintingData_mintedOn), + aliasBlockId: pg.mintingData_aliasBlockId, + aliasId: pg.mintingData_aliasId, + aliasStorageDeposit: pg.mintingData_aliasStorageDeposit, + tokenId: pg.mintingData_tokenId, + blockId: pg.mintingData_blockId, + foundryStorageDeposit: pg.mintingData_foundryStorageDeposit, + network: pg.mintingData_network as Network, + networkFormat: pg.mintingData_networkFormat as Network, + vaultAddress: pg.mintingData_vaultAddress, + tokensInVault: pg.mintingData_tokensInVault, + vaultStorageDeposit: pg.mintingData_vaultStorageDeposit, + guardianStorageDeposit: pg.mintingData_guardianStorageDeposit, + meltedTokens: pg.mintingData_meltedTokens, + circulatingSupply: pg.mintingData_circulatingSupply, + }, + rankCount: pg.rankCount, + rankSum: pg.rankSum, + rankAvg: pg.rankAvg, + mediaStatus: pg.mediaStatus as MediaStatus, + mediaUploadErrorCount: pg.mediaUploadErrorCount, + tradingDisabled: pg.tradingDisabled, + votes: { + upvotes: pg.votes_upvotes || 0, + downvotes: pg.votes_downvotes || 0, + voteDiff: pg.votes_voteDiff || 0, + }, + decimals: pg.decimals || 0, + }); +} diff --git a/packages/database/src/pg/impl/tables/token_distribution.ts b/packages/database/src/pg/impl/tables/token_distribution.ts new file mode 100644 index 0000000000..75726e3a9e --- /dev/null +++ b/packages/database/src/pg/impl/tables/token_distribution.ts @@ -0,0 +1,109 @@ +import { COL, StakeType, TokenDistribution } from '@build-5/interfaces'; +import { head } from 'lodash'; +import { ISubCollection } from '../../interfaces/collection'; +import { Converter } from '../../interfaces/common'; +import { PgTokenDistribution } from '../../models'; +import { PgTokenDistributionUpdate } from '../../models/token_update'; +import { removeNulls } from '../common'; +import { pgDateToTimestamp } from '../postgres'; + +export class PgTokenDistributionCollection extends ISubCollection< + TokenDistribution, + PgTokenDistribution, + PgTokenDistributionUpdate +> { + getTotalOwned = async () => { + const snap = await this.con(this.table) + .select(this.con.raw('SUM("tokenOwned") as "tokenOwned"')) + .where({ parentId: this.colId }); + return Number(head(snap).tokenOwned || 0); + }; +} + +export class TokenDistributionConverter + implements Converter +{ + toPg = (td: TokenDistribution) => ({ + uid: td.uid!, + project: td.project, + createdOn: td.createdOn?.toDate(), + parentId: td.parentId, + + totalDeposit: td.totalDeposit, + totalPaid: td.totalPaid, + refundedAmount: td.refundedAmount, + totalBought: td.totalBought, + reconciled: td.reconciled, + billPaymentId: td.billPaymentId, + creditPaymentId: td.creditPaymentId, + royaltyBillPaymentId: td.royaltyBillPaymentId, + tokenClaimed: td.tokenClaimed, + lockedForSale: td.lockedForSale, + sold: td.sold, + totalPurchased: td.totalPurchased, + tokenOwned: td.tokenOwned, + mintedClaimedOn: td.mintedClaimedOn?.toDate(), + mintingTransactions: td.mintingTransactions, + stakeRewards: td.stakeRewards, + extraStakeRewards: td.extraStakeRewards, + totalUnclaimedAirdrop: td.totalUnclaimedAirdrop, + stakeVoteTransactionId: td.stakeVoteTransactionId, + + stakes_static_amount: td.stakes?.[StakeType.STATIC]?.amount || 0, + stakes_static_totalAmount: td.stakes?.[StakeType.STATIC]?.totalAmount || 0, + stakes_static_value: td.stakes?.[StakeType.STATIC]?.value || 0, + stakes_static_totalValue: td.stakes?.[StakeType.STATIC]?.totalValue || 0, + stakes_static_stakingMembersCount: td.stakes?.[StakeType.STATIC]?.stakingMembersCount || 0, + stakes_dynamic_amount: td.stakes?.[StakeType.DYNAMIC]?.amount || 0, + stakes_dynamic_totalAmount: td.stakes?.[StakeType.DYNAMIC]?.totalAmount || 0, + stakes_dynamic_value: td.stakes?.[StakeType.DYNAMIC]?.value || 0, + stakes_dynamic_totalValue: td.stakes?.[StakeType.DYNAMIC]?.totalValue || 0, + stakes_dynamic_stakingMembersCount: td.stakes?.[StakeType.DYNAMIC]?.stakingMembersCount || 0, + stakeExpiry: td.stakeExpiry, + }); + + fromPg = (pg: PgTokenDistribution): TokenDistribution => + removeNulls({ + uid: pg.uid, + project: pg.project, + parentId: pg.parentId, + parentCol: COL.TOKEN, + totalDeposit: pg.totalDeposit, + totalPaid: pg.totalPaid, + refundedAmount: pg.refundedAmount, + totalBought: pg.totalBought, + reconciled: pg.reconciled, + billPaymentId: pg.billPaymentId, + creditPaymentId: pg.creditPaymentId, + royaltyBillPaymentId: pg.royaltyBillPaymentId, + tokenClaimed: pg.tokenClaimed, + lockedForSale: pg.lockedForSale, + sold: pg.sold, + totalPurchased: pg.totalPurchased, + tokenOwned: pg.tokenOwned, + createdOn: pgDateToTimestamp(pg.createdOn), + mintedClaimedOn: pgDateToTimestamp(pg.mintedClaimedOn), + mintingTransactions: pg.mintingTransactions, + stakes: { + [StakeType.STATIC]: { + amount: pg.stakes_static_amount, + totalAmount: pg.stakes_static_totalAmount, + value: pg.stakes_static_value, + totalValue: pg.stakes_static_totalValue, + stakingMembersCount: pg.stakes_static_stakingMembersCount, + }, + [StakeType.DYNAMIC]: { + amount: pg.stakes_dynamic_amount, + totalAmount: pg.stakes_dynamic_totalAmount, + value: pg.stakes_dynamic_value, + totalValue: pg.stakes_dynamic_totalValue, + stakingMembersCount: pg.stakes_dynamic_stakingMembersCount, + }, + }, + stakeExpiry: pg.stakeExpiry as { [key: string]: { [key: number]: number } }, + stakeRewards: pg.stakeRewards, + extraStakeRewards: pg.extraStakeRewards, + totalUnclaimedAirdrop: pg.totalUnclaimedAirdrop, + stakeVoteTransactionId: pg.stakeVoteTransactionId, + }); +} diff --git a/packages/database/src/pg/impl/tables/token_market.ts b/packages/database/src/pg/impl/tables/token_market.ts new file mode 100644 index 0000000000..29374ad812 --- /dev/null +++ b/packages/database/src/pg/impl/tables/token_market.ts @@ -0,0 +1,68 @@ +import { + Network, + TokenStatus, + TokenTradeOrder, + TokenTradeOrderStatus, + TokenTradeOrderType, +} from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgTokenMarket } from '../../models'; +import { removeNulls } from '../common'; +import { pgDateToTimestamp } from '../postgres'; + +export class TokenTradeOrderConverter implements Converter { + toPg = (to: TokenTradeOrder): PgTokenMarket => ({ + uid: to.uid, + project: to.project, + createdOn: to.createdOn?.toDate(), + updatedOn: to.updatedOn?.toDate(), + createdBy: to.createdBy, + + owner: to.owner, + token: to.token, + tokenStatus: to.tokenStatus, + type: to.type, + count: to.count, + price: to.price, + totalDeposit: to.totalDeposit, + balance: to.balance, + fulfilled: to.fulfilled, + status: to.status, + orderTransactionId: to.orderTransactionId, + paymentTransactionId: to.paymentTransactionId, + creditTransactionId: to.creditTransactionId, + expiresAt: to.expiresAt?.toDate(), + shouldRetry: to.shouldRetry, + sourceNetwork: to.sourceNetwork, + targetNetwork: to.targetNetwork, + targetAddress: to.targetAddress, + }); + + fromPg = (pg: PgTokenMarket): TokenTradeOrder => + removeNulls({ + uid: pg.uid, + project: pg.project, + createdOn: pgDateToTimestamp(pg.createdOn), + updatedOn: pgDateToTimestamp(pg.updatedOn), + createdBy: pg.createdBy || '', + + owner: pg.owner!, + token: pg.token!, + tokenStatus: (pg.tokenStatus as TokenStatus)!, + type: (pg.type as TokenTradeOrderType)!, + count: pg.count!, + price: pg.price!, + totalDeposit: pg.totalDeposit!, + balance: pg.balance!, + fulfilled: pg.fulfilled!, + status: (pg.status as TokenTradeOrderStatus)!, + orderTransactionId: pg.orderTransactionId, + paymentTransactionId: pg.paymentTransactionId, + creditTransactionId: pg.creditTransactionId, + expiresAt: pgDateToTimestamp(pg.expiresAt)!, + shouldRetry: pg.shouldRetry, + sourceNetwork: pg.sourceNetwork as Network, + targetNetwork: pg.targetNetwork as Network, + targetAddress: pg.targetAddress, + }); +} diff --git a/packages/database/src/pg/impl/tables/token_purchase.ts b/packages/database/src/pg/impl/tables/token_purchase.ts new file mode 100644 index 0000000000..d85a13b7bd --- /dev/null +++ b/packages/database/src/pg/impl/tables/token_purchase.ts @@ -0,0 +1,67 @@ +import { + Network, + TokenPurchase, + TokenPurchaseAge, + TokenStatus, + TokenTradeOrderType, +} from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgTokenPurchase } from '../../models'; +import { removeNulls } from '../common'; +import { pgDateToTimestamp } from '../postgres'; + +export class TokenPurchaseConverter implements Converter { + toPg = (tp: TokenPurchase): PgTokenPurchase => ({ + uid: tp.uid, + project: tp.project, + createdOn: tp.createdOn?.toDate(), + updatedOn: tp.updatedOn?.toDate(), + createdBy: tp.createdBy, + + token: tp.token, + tokenStatus: tp.tokenStatus, + sell: tp.sell, + buy: tp.buy, + count: tp.count, + price: tp.price, + triggeredBy: tp.triggeredBy, + billPaymentId: tp.billPaymentId, + buyerBillPaymentId: tp.buyerBillPaymentId, + royaltyBillPayments: tp.royaltyBillPayments, + sourceNetwork: tp.sourceNetwork, + targetNetwork: tp.targetNetwork, + sellerTokenTradingFeePercentage: tp.sellerTokenTradingFeePercentage, + sellerTier: tp.sellerTier, + in24h: tp.age?.includes(TokenPurchaseAge.IN_24_H) || false, + in48h: tp.age?.includes(TokenPurchaseAge.IN_48_H) || false, + in7d: tp.age?.includes(TokenPurchaseAge.IN_7_D) || false, + }); + + fromPg = (pg: PgTokenPurchase): TokenPurchase => + removeNulls({ + uid: pg.uid, + project: pg.project, + createdOn: pgDateToTimestamp(pg.createdOn), + updatedOn: pgDateToTimestamp(pg.updatedOn), + createdBy: pg.createdBy || '', + + token: pg.token!, + tokenStatus: (pg.tokenStatus as TokenStatus)!, + sell: pg.sell!, + buy: pg.buy!, + count: pg.count!, + price: pg.price!, + triggeredBy: (pg.triggeredBy as TokenTradeOrderType)!, + billPaymentId: pg.billPaymentId, + buyerBillPaymentId: pg.buyerBillPaymentId, + royaltyBillPayments: pg.royaltyBillPayments, + sourceNetwork: pg.sourceNetwork as Network, + targetNetwork: pg.targetNetwork as Network, + sellerTokenTradingFeePercentage: pg.sellerTokenTradingFeePercentage, + sellerTier: pg.sellerTier, + age: Object.values(TokenPurchaseAge).reduce( + (acc, act) => (pg[act] ? [...acc, act] : acc), + [] as TokenPurchaseAge[], + ), + }); +} diff --git a/packages/database/src/pg/impl/tables/token_rank.ts b/packages/database/src/pg/impl/tables/token_rank.ts new file mode 100644 index 0000000000..fe5852d6f3 --- /dev/null +++ b/packages/database/src/pg/impl/tables/token_rank.ts @@ -0,0 +1,22 @@ +import { COL, Rank } from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgTokenRanks } from '../../models'; +import { removeNulls } from '../common'; + +export class TokenRankConverter implements Converter { + toPg = (r: Rank): PgTokenRanks => ({ + uid: r.uid!, + project: r.project, + parentId: r.parentId, + rank: r.rank, + }); + + fromPg = (pg: PgTokenRanks): Rank => + removeNulls({ + uid: pg.uid, + project: pg.project, + parentId: pg.parentId, + parentCol: COL.TOKEN, + rank: pg.rank!, + }); +} diff --git a/packages/database/src/pg/impl/tables/token_stats.ts b/packages/database/src/pg/impl/tables/token_stats.ts new file mode 100644 index 0000000000..0d47325401 --- /dev/null +++ b/packages/database/src/pg/impl/tables/token_stats.ts @@ -0,0 +1,74 @@ +import { COL, StakeType, TokenPurchaseAge, TokenStats } from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgTokenStats } from '../../models'; +import { removeNulls } from '../common'; + +export class TokenStatsConverter implements Converter { + toPg = (ts: TokenStats): PgTokenStats => ({ + uid: ts.parentId, + project: ts.project, + parentId: ts.parentId, + + votes_upvotes: ts.votes?.upvotes, + votes_downvotes: ts.votes?.downvotes, + votes_voteDiff: ts.votes?.voteDiff, + ranks_count: ts.ranks?.count, + ranks_sum: ts.ranks?.sum, + ranks_avg: ts.ranks?.avg, + volumeTotal: ts.volumeTotal, + volume_in24h: ts.volume?.[TokenPurchaseAge.IN_24_H], + volume_in48h: ts.volume?.[TokenPurchaseAge.IN_48_H], + volume_in7d: ts.volume?.[TokenPurchaseAge.IN_7_D], + stakes_static_amount: ts.stakes?.[StakeType.STATIC]?.amount, + stakes_static_totalAmount: ts.stakes?.[StakeType.STATIC]?.totalAmount, + stakes_static_value: ts.stakes?.[StakeType.STATIC]?.value, + stakes_static_totalValue: ts.stakes?.[StakeType.STATIC]?.totalValue, + stakes_static_stakingMembersCount: ts.stakes?.[StakeType.STATIC]?.stakingMembersCount, + stakes_dynamic_amount: ts.stakes?.[StakeType.DYNAMIC]?.amount, + stakes_dynamic_totalAmount: ts.stakes?.[StakeType.DYNAMIC]?.totalAmount, + stakes_dynamic_value: ts.stakes?.[StakeType.DYNAMIC]?.value, + stakes_dynamic_totalValue: ts.stakes?.[StakeType.DYNAMIC]?.totalValue, + stakes_dynamic_stakingMembersCount: ts.stakes?.[StakeType.DYNAMIC]?.stakingMembersCount, + stakeExpiry: ts.stakeExpiry, + }); + + fromPg = (pg: PgTokenStats): TokenStats => + removeNulls({ + project: pg.project, + parentId: pg.parentId, + parentCol: COL.TOKEN, + volumeTotal: pg.volumeTotal || 0, + volume: { + [TokenPurchaseAge.IN_24_H]: pg.volume_in24h || 0, + [TokenPurchaseAge.IN_48_H]: pg.volume_in48h || 0, + [TokenPurchaseAge.IN_7_D]: pg.volume_in7d || 0, + }, + stakes: { + [StakeType.STATIC]: { + amount: pg.stakes_static_amount || 0, + totalAmount: pg.stakes_static_totalAmount || 0, + value: pg.stakes_static_value || 0, + totalValue: pg.stakes_static_totalValue || 0, + stakingMembersCount: pg.stakes_static_stakingMembersCount || 0, + }, + [StakeType.DYNAMIC]: { + amount: pg.stakes_dynamic_amount || 0, + totalAmount: pg.stakes_dynamic_totalAmount || 0, + value: pg.stakes_dynamic_value || 0, + totalValue: pg.stakes_dynamic_totalValue || 0, + stakingMembersCount: pg.stakes_dynamic_stakingMembersCount || 0, + }, + }, + votes: { + upvotes: pg.votes_upvotes || 0, + downvotes: pg.votes_downvotes || 0, + voteDiff: pg.votes_voteDiff || 0, + }, + ranks: { + sum: pg.ranks_sum || 0, + avg: pg.ranks_avg || 0, + count: pg.ranks_count || 0, + }, + stakeExpiry: pg.stakeExpiry as { [key: string]: { [key: number]: number } }, + }); +} diff --git a/packages/database/src/pg/impl/tables/token_vote.ts b/packages/database/src/pg/impl/tables/token_vote.ts new file mode 100644 index 0000000000..eb4d38aeb3 --- /dev/null +++ b/packages/database/src/pg/impl/tables/token_vote.ts @@ -0,0 +1,22 @@ +import { COL, Vote } from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgTokenVotes } from '../../models'; +import { removeNulls } from '../common'; + +export class TokenVotesConverter implements Converter { + toPg = (r: Vote): PgTokenVotes => ({ + uid: r.uid!, + project: r.project, + parentId: r.parentId, + direction: r.direction, + }); + + fromPg = (pg: PgTokenVotes): Vote => + removeNulls({ + uid: pg.uid, + project: pg.project, + parentId: pg.parentId, + parentCol: COL.TOKEN, + direction: pg.direction! as 1 | -1, + }); +} diff --git a/packages/database/src/pg/impl/tables/transaction.ts b/packages/database/src/pg/impl/tables/transaction.ts new file mode 100644 index 0000000000..e15377a873 --- /dev/null +++ b/packages/database/src/pg/impl/tables/transaction.ts @@ -0,0 +1,290 @@ +import { + CreditPaymentReason, + Entity, + IgnoreWalletReason, + NativeToken, + Network, + NftBulkOrder, + SendToManyTargets, + StakeType, + StorageReturn, + Transaction, + TransactionPayloadType, + TransactionType, + TransactionValidationType, + UnsoldMintingOptions, +} from '@build-5/interfaces'; +import { Converter } from '../../interfaces/common'; +import { PgTransaction } from '../../models'; +import { removeNulls } from '../common'; +import { pgDateToTimestamp } from '../postgres'; + +export class TransactionConverter implements Converter { + toPg = (trx: Transaction): PgTransaction => ({ + uid: trx.uid, + project: trx.project, + createdOn: trx.createdOn?.toDate(), + updatedOn: trx.updatedOn?.toDate(), + createdBy: trx.createdBy, + + network: trx.network, + type: trx.type, + isOrderType: trx.isOrderType, + member: trx.member, + space: trx.space, + shouldRetry: trx.shouldRetry, + ignoreWallet: trx.ignoreWallet, + linkedTransactions: trx.linkedTransactions, + ignoreWalletReason: trx.ignoreWalletReason || undefined, + payload_type: trx.payload.type, + payload_amount: trx.payload.amount || 0, + payload_sourceAddress: trx.payload.sourceAddress || '', + payload_targetAddress: trx.payload.targetAddress || '', + payload_targetAddresses: JSON.stringify(trx.payload.targetAddresses) as any, + payload_sourceTransaction: trx.payload.sourceTransaction || [], + payload_validationType: trx.payload.validationType, + payload_expiresOn: trx.payload.expiresOn?.toDate(), + payload_reconciled: trx.payload.reconciled, + payload_void: trx.payload.void, + payload_collection: trx.payload.collection || undefined, + payload_unsoldMintingOptions: trx.payload.unsoldMintingOptions, + payload_newPrice: trx.payload.newPrice, + payload_collectionStorageDeposit: trx.payload.collectionStorageDeposit, + payload_nftsStorageDeposit: trx.payload.nftsStorageDeposit, + payload_aliasStorageDeposit: trx.payload.aliasStorageDeposit, + payload_nftsToMint: trx.payload.nftsToMint, + payload_transaction: trx.payload.transaction, + payload_unlockedBy: trx.payload.unlockedBy, + payload_beneficiary: trx.payload.beneficiary, + payload_beneficiaryUid: trx.payload.beneficiaryUid, + payload_beneficiaryAddress: trx.payload.beneficiaryAddress, + payload_royaltiesFee: trx.payload.royaltiesFee, + payload_royaltiesSpace: trx.payload.royaltiesSpace, + payload_royaltiesSpaceAddress: trx.payload.royaltiesSpaceAddress, + payload_chainReference: trx.payload.chainReference || undefined, + payload_nft: trx.payload.nft || undefined, + payload_restrictions: JSON.stringify(trx.payload.restrictions) as any, + payload_token: trx.payload.token, + payload_quantity: trx.payload.quantity, + payload_tokenSymbol: trx.payload.tokenSymbol, + payload_unclaimedAirdrops: trx.payload.unclaimedAirdrops, + payload_totalAirdropCount: trx.payload.totalAirdropCount, + payload_tokenId: trx.payload.tokenId, + payload_foundryStorageDeposit: trx.payload.foundryStorageDeposit, + payload_vaultStorageDeposit: trx.payload.vaultStorageDeposit, + payload_guardianStorageDeposit: trx.payload.guardianStorageDeposit, + payload_tokensInVault: trx.payload.tokensInVault, + payload_orderId: trx.payload.orderId, + payload_collectionOutputAmount: trx.payload.collectionOutputAmount, + payload_aliasOutputAmount: trx.payload.aliasOutputAmount, + payload_nftOutputAmount: trx.payload.nftOutputAmount, + payload_aliasId: trx.payload.aliasId, + payload_aliasBlockId: trx.payload.aliasBlockId, + payload_aliasGovAddress: trx.payload.aliasGovAddress, + payload_collectionId: trx.payload.collectionId || undefined, + payload_nftId: trx.payload.nftId || undefined, + payload_nativeTokens: JSON.stringify( + trx.payload.nativeTokens?.map((nt) => ({ ...nt, amount: Number(nt.amount) })), + ) as any, + payload_previousOwnerEntity: trx.payload.previousOwnerEntity, + payload_previousOwner: trx.payload.previousOwner, + payload_ownerEntity: trx.payload.ownerEntity, + payload_owner: trx.payload.owner, + payload_royalty: trx.payload.royalty, + payload_vestingAt: trx.payload.vestingAt?.toDate(), + payload_customMetadata: JSON.stringify(trx.payload.customMetadata) as any, + payload_stake: trx.payload.stake, + payload_award: trx.payload.award || undefined, + payload_legacyAwardFundRequestId: trx.payload.legacyAwardFundRequestId, + payload_legacyAwardsBeeingFunded: trx.payload.legacyAwardsBeeingFunded, + payload_weeks: trx.payload.weeks, + payload_stakeType: trx.payload.stakeType, + payload_count: trx.payload.count, + payload_price: trx.payload.price, + payload_tokenReward: trx.payload.tokenReward, + payload_edition: trx.payload.edition, + payload_participatedOn: trx.payload.participatedOn?.toDate(), + payload_proposalId: trx.payload.proposalId, + payload_voteValues: trx.payload.voteValues, + payload_storageDepositSourceAddress: trx.payload.storageDepositSourceAddress, + payload_storageReturn: JSON.stringify(trx.payload.storageReturn) as any, + payload_airdropId: trx.payload.airdropId, + payload_nfts: trx.payload.nfts, + payload_tag: trx.payload.tag, + payload_metadata: JSON.stringify(trx.payload.metadata) as any, + payload_response: JSON.stringify(trx.payload.response) as any, + payload_reason: trx.payload.reason, + payload_invalidPayment: trx.payload.invalidPayment, + payload_outputToConsume: trx.payload.outputToConsume, + payload_dependsOnBillPayment: trx.payload.dependsOnBillPayment, + payload_milestoneTransactionPath: trx.payload.milestoneTransactionPath, + payload_tokenAmount: trx.payload.tokenAmount, + payload_weight: trx.payload.weight, + payload_weightMultiplier: trx.payload.weightMultiplier, + payload_votes: trx.payload.votes, + payload_creditId: trx.payload.creditId, + payload_outputConsumed: trx.payload.outputConsumed, + payload_outputConsumedOn: trx.payload.outputConsumedOn?.toDate(), + payload_stakes: trx.payload.stakes, + payload_stakeReward: trx.payload.stakeReward, + payload_tanglePuchase: trx.payload.tanglePuchase, + payload_disableWithdraw: trx.payload.disableWithdraw, + payload_lockCollectionNft: trx.payload.lockCollectionNft, + payload_stamp: trx.payload.stamp, + payload_tokenTradeOderTargetAddress: trx.payload.tokenTradeOderTargetAddress, + payload_auction: trx.payload.auction, + payload_days: trx.payload.days, + payload_dailyCost: trx.payload.dailyCost, + payload_nftOrders: JSON.stringify(trx.payload.nftOrders) as any, + payload_swap: trx.payload.swap, + payload_outputId: trx.payload.outputId, + payload_walletReference_createdOn: trx.payload.walletReference?.createdOn?.toDate(), + payload_walletReference_processedOn: trx.payload.walletReference?.processedOn?.toDate(), + payload_walletReference_chainReference: + trx.payload.walletReference?.chainReference || undefined, + payload_walletReference_chainReferences: trx.payload.walletReference?.chainReferences, + payload_walletReference_error: trx.payload.walletReference?.error as string, + payload_walletReference_confirmed: trx.payload.walletReference?.confirmed, + payload_walletReference_confirmedOn: trx.payload.walletReference?.confirmedOn?.toDate(), + payload_walletReference_milestoneTransactionPath: + trx.payload.walletReference?.milestoneTransactionPath, + payload_walletReference_count: trx.payload.walletReference?.count, + payload_walletReference_inProgress: trx.payload.walletReference?.inProgress, + payload_walletReference_nodeIndex: trx.payload.walletReference?.nodeIndex, + payload_values: trx.payload.values, + }); + + fromPg = (pg: PgTransaction): Transaction => + removeNulls({ + uid: pg.uid, + project: pg.project, + createdOn: pgDateToTimestamp(pg.createdOn), + updatedOn: pgDateToTimestamp(pg.updatedOn), + createdBy: pg.createdBy || '', + network: pg.network as Network, + type: pg.type as TransactionType, + isOrderType: pg.isOrderType, + member: pg.member, + space: pg.space, + shouldRetry: pg.shouldRetry, + ignoreWallet: pg.ignoreWallet, + linkedTransactions: pg.linkedTransactions, + ignoreWalletReason: pg.ignoreWalletReason as IgnoreWalletReason, + payload: { + type: pg.payload_type as TransactionPayloadType, + amount: pg.payload_amount, + sourceAddress: pg.payload_sourceAddress, + targetAddress: pg.payload_targetAddress, + targetAddresses: pg.payload_targetAddresses as SendToManyTargets[] | undefined, + sourceTransaction: pg.payload_sourceTransaction, + validationType: pg.payload_validationType as TransactionValidationType, + expiresOn: pgDateToTimestamp(pg.payload_expiresOn), + reconciled: pg.payload_reconciled, + void: pg.payload_void, + collection: pg.payload_collection, + unsoldMintingOptions: pg.payload_unsoldMintingOptions as UnsoldMintingOptions, + newPrice: pg.payload_newPrice, + collectionStorageDeposit: pg.payload_collectionStorageDeposit, + nftsStorageDeposit: pg.payload_nftsStorageDeposit, + aliasStorageDeposit: pg.payload_aliasStorageDeposit, + nftsToMint: pg.payload_nftsToMint, + transaction: pg.payload_transaction, + unlockedBy: pg.payload_unlockedBy, + beneficiary: pg.payload_beneficiary as Entity, + beneficiaryUid: pg.payload_beneficiaryUid, + beneficiaryAddress: pg.payload_beneficiaryAddress, + royaltiesFee: pg.payload_royaltiesFee, + royaltiesSpace: pg.payload_royaltiesSpace, + royaltiesSpaceAddress: pg.payload_royaltiesSpaceAddress, + chainReference: pg.payload_chainReference, + nft: pg.payload_nft, + restrictions: pg.payload_restrictions as any, + token: pg.payload_token, + quantity: pg.payload_quantity, + tokenSymbol: pg.payload_tokenSymbol, + unclaimedAirdrops: pg.payload_unclaimedAirdrops, + totalAirdropCount: pg.payload_totalAirdropCount, + tokenId: pg.payload_tokenId, + foundryStorageDeposit: pg.payload_foundryStorageDeposit, + vaultStorageDeposit: pg.payload_vaultStorageDeposit, + guardianStorageDeposit: pg.payload_guardianStorageDeposit, + tokensInVault: pg.payload_tokensInVault, + orderId: pg.payload_orderId, + collectionOutputAmount: pg.payload_collectionOutputAmount, + aliasOutputAmount: pg.payload_aliasOutputAmount, + nftOutputAmount: pg.payload_nftOutputAmount, + aliasId: pg.payload_aliasId, + aliasBlockId: pg.payload_aliasBlockId, + aliasGovAddress: pg.payload_aliasGovAddress, + collectionId: pg.payload_collectionId, + nftId: pg.payload_nftId, + nativeTokens: pg.payload_nativeTokens as NativeToken[] | undefined, + previousOwnerEntity: pg.payload_previousOwnerEntity as Entity, + previousOwner: pg.payload_previousOwner, + ownerEntity: pg.payload_ownerEntity as Entity, + owner: pg.payload_owner, + royalty: pg.payload_royalty, + vestingAt: pgDateToTimestamp(pg.payload_vestingAt), + customMetadata: pg.payload_customMetadata as { [key: string]: string } | undefined, + stake: pg.payload_stake, + award: pg.payload_award, + legacyAwardFundRequestId: pg.payload_legacyAwardFundRequestId, + legacyAwardsBeeingFunded: pg.payload_legacyAwardsBeeingFunded, + weeks: pg.payload_weeks, + stakeType: pg.payload_stakeType as StakeType, + count: pg.payload_count, + price: pg.payload_price, + tokenReward: pg.payload_tokenReward, + edition: pg.payload_edition, + participatedOn: pgDateToTimestamp(pg.payload_participatedOn), + proposalId: pg.payload_proposalId, + voteValues: pg.payload_voteValues, + storageDepositSourceAddress: pg.payload_storageDepositSourceAddress, + storageReturn: pg.payload_storageReturn as StorageReturn | undefined, + airdropId: pg.payload_airdropId, + outputId: pg.payload_outputId, + walletReference: { + createdOn: pgDateToTimestamp(pg.payload_walletReference_createdOn)!, + processedOn: pgDateToTimestamp(pg.payload_walletReference_processedOn)!, + chainReference: pg.payload_walletReference_chainReference, + chainReferences: pg.payload_walletReference_chainReferences, + error: pg.payload_walletReference_error, + confirmed: pg.payload_walletReference_confirmed || false, + confirmedOn: pgDateToTimestamp(pg.payload_walletReference_confirmedOn), + milestoneTransactionPath: pg.payload_walletReference_milestoneTransactionPath, + count: pg.payload_walletReference_count || 0, + inProgress: pg.payload_walletReference_inProgress, + nodeIndex: pg.payload_walletReference_nodeIndex, + }, + nfts: pg.payload_nfts, + tag: pg.payload_tag, + metadata: pg.payload_metadata as any, + response: pg.payload_response as any, + reason: pg.payload_reason as CreditPaymentReason, + invalidPayment: pg.payload_invalidPayment, + outputToConsume: pg.payload_outputToConsume, + dependsOnBillPayment: pg.payload_dependsOnBillPayment, + milestoneTransactionPath: pg.payload_milestoneTransactionPath, + values: pg.payload_values, + tokenAmount: pg.payload_tokenAmount, + weight: pg.payload_weight, + weightMultiplier: pg.payload_weightMultiplier, + votes: pg.payload_votes, + creditId: pg.payload_creditId, + outputConsumed: pg.payload_outputConsumed, + outputConsumedOn: pgDateToTimestamp(pg.payload_outputConsumedOn), + stakes: pg.payload_stakes, + stakeReward: pg.payload_stakeReward, + tanglePuchase: pg.payload_tanglePuchase, + disableWithdraw: pg.payload_disableWithdraw, + lockCollectionNft: pg.payload_lockCollectionNft, + stamp: pg.payload_stamp, + tokenTradeOderTargetAddress: pg.payload_tokenTradeOderTargetAddress, + auction: pg.payload_auction, + days: pg.payload_days, + dailyCost: pg.payload_dailyCost, + nftOrders: pg.payload_nftOrders as NftBulkOrder[] | undefined, + swap: pg.payload_swap, + }, + }); +} diff --git a/packages/database/src/pg/index.ts b/packages/database/src/pg/index.ts new file mode 100644 index 0000000000..3d6a41d268 --- /dev/null +++ b/packages/database/src/pg/index.ts @@ -0,0 +1,13 @@ +export * from './impl/common'; +export * from './impl/instance'; +export { MilestoneTransactions } from './impl/tables/milestone_transactions'; +export * from './interfaces/batch'; +export * from './interfaces/collection'; +export * from './interfaces/common'; +export * from './interfaces/database'; +export * from './interfaces/document/document'; +export * from './interfaces/query/query'; +export * from './interfaces/transaction'; +export * from './models'; +export * from './models/common'; +export * from './models/common_update'; diff --git a/packages/database/src/pg/interfaces.ts b/packages/database/src/pg/interfaces.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/database/src/pg/interfaces/batch.ts b/packages/database/src/pg/interfaces/batch.ts new file mode 100644 index 0000000000..c044dc35e3 --- /dev/null +++ b/packages/database/src/pg/interfaces/batch.ts @@ -0,0 +1,11 @@ +import { BaseRecord } from '../models/common'; +import { Update } from '../models/common_update'; +import { IDocument } from './document/document'; + +export interface IBatch { + create: (docRef: IDocument, data: C) => void; + update: (docRef: IDocument, data: U) => void; + upsert: (docRef: IDocument, data: U) => void; + delete: (docRef: IDocument) => void; + commit: () => Promise; +} diff --git a/packages/database/src/pg/interfaces/collection.ts b/packages/database/src/pg/interfaces/collection.ts new file mode 100644 index 0000000000..302d7ea475 --- /dev/null +++ b/packages/database/src/pg/interfaces/collection.ts @@ -0,0 +1,80 @@ +import { COL, SUB_COL } from '@build-5/interfaces'; +import { Knex } from 'knex'; +import { head } from 'lodash'; +import { undefinedToNull } from '../impl/common'; +import { BaseRecord } from '../models/common'; +import { Update } from '../models/common_update'; +import { Converter, WhereFilterOp, getTableName } from './common'; +import { IDocument } from './document/document'; +import { ISubDocument } from './document/sub.document'; +import { IQuery } from './query/query'; +import { ISubColQuery } from './query/sub.query'; + +export class ICollection { + protected table: string = ''; + + constructor( + protected con: Knex, + protected col: COL, + protected converter: Converter, + ) { + this.table = getTableName(col); + } + + protected createQuery = () => new IQuery(this.con, this.col, this.converter); + + doc = (colId: string) => new IDocument(this.con, this.col, colId, this.converter); + + get = () => this.createQuery().get(); + + where = ( + fieldPath: F, + operator: WhereFilterOp, + value: Q[F] | undefined | null, + ) => this.createQuery().where(fieldPath, operator, value); + + update = async (data: U, where: Record) => { + await this.con(this.table).update(undefinedToNull(data)).where(where); + }; + + delete = async (where: Record) => + await this.con(this.table).delete().where(where); + + count = async () => { + const result = await this.con(this.table).count(); + return Number(head(result)?.count || 0); + }; + + limit = (limit: number) => this.createQuery().limit(limit); + + orderBy = (fieldPath: F, dir?: 'asc' | 'desc') => + this.createQuery().orderBy(fieldPath, dir); +} + +export class ISubCollection extends ICollection< + T, + Q, + U +> { + constructor( + con: Knex, + col: COL, + protected colId: string | undefined, + protected subCol: SUB_COL, + protected converter: Converter, + ) { + super(con, col, converter); + this.table = getTableName(col, subCol); + } + + protected createQuery = () => + new ISubColQuery(this.con, this.col, this.colId, this.subCol, this.converter); + + doc = (subColId: string) => + new ISubDocument(this.con, this.col, this.colId!, this.subCol, subColId, this.converter); + + count = async () => { + const result = await this.con(this.table).where({ parentId: this.colId }).count(); + return Number(head(result)?.count || 0); + }; +} diff --git a/packages/database/src/pg/interfaces/common.ts b/packages/database/src/pg/interfaces/common.ts new file mode 100644 index 0000000000..63dbd31d96 --- /dev/null +++ b/packages/database/src/pg/interfaces/common.ts @@ -0,0 +1,29 @@ +import { COL, SUB_COL } from '@build-5/interfaces'; +import { BaseRecord } from '../models/common'; + +export interface PKey { + uid: string; + parentId?: string; +} + +export interface Converter { + toPg: (data: C) => B; + fromPg: (data: B) => C; +} + +export type WhereFilterOp = '<' | '<=' | '==' | '!=' | '>=' | '>' | 'array-contains'; + +export const getTableName = (col: COL, subCol?: SUB_COL) => + (col + (subCol ? '_' + subCol : '')).toLowerCase(); + +export class Increment { + constructor(public value: number) {} +} + +export class ArrayUnion { + constructor(public value: T) {} +} + +export class ArrayRemove { + constructor(public value: T) {} +} diff --git a/packages/database/src/pg/interfaces/database.ts b/packages/database/src/pg/interfaces/database.ts new file mode 100644 index 0000000000..ca8763113c --- /dev/null +++ b/packages/database/src/pg/interfaces/database.ts @@ -0,0 +1,32 @@ +import { COL, SUB_COL } from '@build-5/interfaces'; +import { Knex } from 'knex'; +import { IColType, IDocType } from '../impl/postgres'; +import { IBatch } from './batch'; +import { ArrayRemove, ArrayUnion, Increment } from './common'; +import { ITransaction } from './transaction'; + +export interface IDatabase { + collection: ( + col: C, + colId?: string, + subCol?: S, + ) => IColType; + + doc: ( + col: C, + colId: string, + subCol?: S, + subColId?: string, + ) => IDocType; + + batch: () => IBatch; + runTransaction: (func: (transaction: ITransaction) => Promise) => Promise; + + inc: (value: number) => Increment; + arrayUnion: (value: T) => ArrayUnion; + arrayRemove: (value: T) => ArrayRemove; + + destroy: () => Promise; + + getCon: () => Knex; +} diff --git a/packages/database/src/pg/interfaces/document/common.ts b/packages/database/src/pg/interfaces/document/common.ts new file mode 100644 index 0000000000..7f20d9d73e --- /dev/null +++ b/packages/database/src/pg/interfaces/document/common.ts @@ -0,0 +1,77 @@ +import { Knex } from 'knex'; +import { isArray, isDate, isObject, isUndefined } from 'lodash'; +import { ArrayRemove, ArrayUnion, Increment } from '../common'; + +export const toRaw = (knex: Knex, data: any) => + Object.entries(data).reduce((acc, [key, value]) => { + if (value instanceof Increment) { + return { + ...acc, + [key]: knex.raw(`COALESCE("${key}", 0) + ?`, [value.value]), + }; + } + if (value instanceof ArrayUnion) { + return { + ...acc, + [key]: knex.raw(`array_cat("${key}", ?)`, [[value.value]]), + }; + } + if (value instanceof ArrayRemove) { + return { + ...acc, + [key]: knex.raw(`array_remove("${key}", ?)`, [value.value]), + }; + } + + if (isObject(value) && !isArray(value) && !isDate(value)) { + const { acc: sql, bidings } = objectToJsonRaw(`"${key}"`, value); + return { ...acc, [key]: knex.raw(sql, bidings) }; + } + + return { ...acc, [key]: isUndefined(value) ? null : value }; + }, {}); + +export const objectToJsonRaw = (column: string, data: any, keys: string[] = [], acc = column) => { + let actAcc = acc; + const bidings: any[] = []; + Object.entries(data).forEach(([key, value]) => { + const setPath = [...keys, key].join(', '); + const fullPath = `${column}->${[...keys, key].map((k) => `'${k}'`).join('->')}`; + + if (!value) { + actAcc = `jsonb_strip_nulls(jsonb_set(${actAcc}, '{${setPath}}', ?::jsonb))`; + bidings.push(JSON.stringify(value)); + return; + } + if (value instanceof Increment) { + actAcc = + `jsonb_set(${actAcc}, '{${setPath}}', ` + + `to_jsonb(COALESCE((${fullPath})::numeric, 0) + ?)::jsonb` + + ')'; + bidings.push(JSON.stringify(value.value)); + return; + } + if (value instanceof ArrayUnion) { + actAcc = + `jsonb_set(${actAcc}, '{${setPath}}', ` + + `COALESCE((${fullPath}), '[]'::jsonb) || ?::jsonb)`; + bidings.push(JSON.stringify(value.value)); + return; + } + if (typeof value === 'object') { + actAcc = `jsonb_set(${actAcc}, '{${setPath}}', COALESCE(${fullPath} ,'{}'::jsonb))`; + const { acc, bidings: b } = objectToJsonRaw(column, value, [...keys, key], actAcc); + actAcc = acc; + bidings.push(...b); + return; + } + if (typeof value === 'string') { + actAcc = `jsonb_set(${actAcc}, '{${setPath}}', ?::jsonb)`; + bidings.push(JSON.stringify(value)); + return; + } + actAcc = `jsonb_set(${actAcc}, '{${setPath}}', ?::jsonb)`; + bidings.push(JSON.stringify(value)); + }); + return { acc: actAcc, bidings }; +}; diff --git a/packages/database/src/pg/interfaces/document/document.ts b/packages/database/src/pg/interfaces/document/document.ts new file mode 100644 index 0000000000..98bf8dcad6 --- /dev/null +++ b/packages/database/src/pg/interfaces/document/document.ts @@ -0,0 +1,83 @@ +import { COL } from '@build-5/interfaces'; +import { Knex } from 'knex'; +import { head, unset } from 'lodash'; +import { BaseRecord } from '../../models/common'; +import { Update } from '../../models/common_update'; +import { Converter, PKey, getTableName } from '../common'; +import { toRaw } from './common'; +import { onSnapshot } from './snapshot'; + +export class IDocument { + public pKey: PKey = { uid: '' }; + public table: string; + + constructor( + protected con: Knex | Knex.Transaction, + protected col: COL, + protected colId: string, + public converter: Converter, + ) { + this.table = getTableName(col); + this.pKey.uid = colId; + } + + create = async (data: C): Promise => { + const pgData = this.converter.toPg({ ...data, ...this.pKey }); + await this.con(this.table).insert(pgData); + }; + + createQuery = () => { + let query = this.con(this.table).where(this.pKey); + if (this.con.isTransaction) { + query.forUpdate().noWait(); + } + return query; + }; + + get = async (): Promise => { + const snap = head(await this.createQuery()); + return snap ? this.converter.fromPg(snap) : undefined; + }; + + onSnapshot = ( + callback: (data: C | undefined) => Promise | void, + onError?: (err: any) => void, + ) => onSnapshot(this, callback, onError); + + update = async (data: U) => { + unset(data, 'parentCol'); + const update = toRaw(this.con, data); + await this.con(this.table).update(update).where(this.pKey); + }; + + upsert = async (data: U) => { + unset(data, 'parentCol'); + const update = toRaw(this.con, data); + const trx = await this.con.transaction(); + await trx(this.table).insert(this.pKey).onConflict(Object.keys(this.pKey)).ignore(); + await trx(this.table).update(update).where(this.pKey); + try { + await trx.commit(); + } catch (err) { + await trx.rollback(); + throw err; + } + }; + + delete = async () => { + await this.con(this.table).delete().where(this.pKey); + }; + + useTransaction = async ( + trx: Knex.Transaction, + func: (doc: IDocument) => Promise, + ): Promise => { + const con = this.con; + try { + this.con = trx; + return await func(this); + } finally { + this.con = con; + } + }; +} diff --git a/packages/database/src/pg/interfaces/document/snapshot.ts b/packages/database/src/pg/interfaces/document/snapshot.ts new file mode 100644 index 0000000000..e7eaf9e3c9 --- /dev/null +++ b/packages/database/src/pg/interfaces/document/snapshot.ts @@ -0,0 +1,37 @@ +import { Message } from '@google-cloud/pubsub'; +import { get, head } from 'lodash'; +import { getPgData, getSubscription } from '../../impl/pubsub'; +import { BaseRecord } from '../../models/common'; +import { Update } from '../../models/common_update'; +import { IDocument } from './document'; + +export const onSnapshot = ( + doc: IDocument, + callback: (data: C | undefined) => Promise | void, + onError?: (err: any) => void, +) => { + const onMemssage = (message: Message) => { + message.ack(); + const update = getPgData(message, doc.converter); + if (update.uid === doc.pKey.uid && get(update, 'parentId') === doc.pKey.parentId) { + callback(doc.converter.fromPg(update)); + } + }; + + const subsPromise = getSubscription(doc.table); + + doc + .createQuery() + .then(async (raw) => { + const pgData = head(raw); + callback(pgData ? doc.converter.fromPg(pgData) : undefined); + (await subsPromise).on('message', onMemssage); + }) + .catch(onError); + + return () => { + subsPromise.then((subs) => { + subs.removeListener('message', onMemssage); + }); + }; +}; diff --git a/packages/database/src/pg/interfaces/document/sub.document.ts b/packages/database/src/pg/interfaces/document/sub.document.ts new file mode 100644 index 0000000000..735a4e2522 --- /dev/null +++ b/packages/database/src/pg/interfaces/document/sub.document.ts @@ -0,0 +1,22 @@ +import { COL, SUB_COL } from '@build-5/interfaces'; +import { Knex } from 'knex'; +import { BaseRecord } from '../../models/common'; +import { Update } from '../../models/common_update'; +import { Converter, getTableName } from '../common'; +import { IDocument } from './document'; + +export class ISubDocument extends IDocument { + constructor( + con: Knex | Knex.Transaction, + col: COL, + colId: string, + protected subCol: SUB_COL, + protected subColId: string, + converter: Converter, + ) { + super(con, col, colId, converter); + this.pKey.uid = subColId; + this.pKey.parentId = this.colId; + this.table = getTableName(col, subCol); + } +} diff --git a/packages/database/src/pg/interfaces/query/query.ts b/packages/database/src/pg/interfaces/query/query.ts new file mode 100644 index 0000000000..dacd5224d0 --- /dev/null +++ b/packages/database/src/pg/interfaces/query/query.ts @@ -0,0 +1,194 @@ +import { COL } from '@build-5/interfaces'; +import { Knex } from 'knex'; +import { get, some, uniq } from 'lodash'; +import { BaseRecord } from '../../models/common'; +import { Converter, WhereFilterOp, getTableName } from '../common'; +import { OnSnapshot } from './snapshot'; + +export abstract class BaseIQuery { + public table: string; + public startAfterData: Q | undefined = undefined; + public limits: number = 0; + public whereIns: { key: string; value: any }[] = []; + public wheres: { key: string; opr: WhereFilterOp; value: any }[] = []; + public whereOrs: Record[] = []; + public orderBys: { key: string; dir: 'asc' | 'desc' }[] = []; + + constructor( + public con: Knex, + public col: COL, + public converter: Converter, + ) { + this.table = getTableName(col); + } + + createQuery = () => { + const query = this.con(this.table).select('*'); + + for (const ins of this.whereIns) { + query.whereIn(ins.key, ins.value); + } + + for (const wheres of this.wheres) { + if (wheres.opr === 'array-contains') { + query.where(wheres.key, '@>', `{${wheres.value}}`); + } else { + const opr = wheres.opr === '==' ? '=' : wheres.opr; + query.where(wheres.key, opr, wheres.value); + } + } + + for (const whereOr of this.whereOrs) { + query.where((builder) => { + Object.entries(whereOr).forEach(([key, value]) => { + builder.orWhere(key, value as any); + }); + }); + } + + const orderBys = [...this.orderBys]; + if (!this.orderBys.map((o) => o.key).includes('uid')) { + orderBys.push({ key: 'uid', dir: 'asc' }); + } + + if (this.startAfterData) { + query.where((builder) => { + for (let i = 0; i < orderBys.length; ++i) { + builder.orWhere((b) => { + for (let j = 0; j <= i; ++j) { + b.where( + orderBys[j].key as any, + i === j ? (orderBys[j].dir === 'asc' ? '>' : '<') : '=', + get(this.startAfterData, orderBys[j].key), + ); + } + }); + } + }); + } + + if (this.limits) { + query.limit(this.limits); + } + + for (const orderBy of orderBys) { + query.orderBy(orderBy.key, orderBy.dir); + } + + return query; + }; + + checkIndex = async (query: Knex.QueryBuilder) => { + if (process.env.ENVIRONMENT !== 'emulator') { + return; + } + + const hasOnlyEqual = this.wheres.reduce((acc, act) => acc && act.opr === '==', true); + if (hasOnlyEqual && !this.orderBys.length && !this.whereOrs.length) { + return; + } + + const { name, columns } = this.createIndex(); + + const result = await this.con + .from('pg_catalog.pg_indexes') + .where({ + tablename: this.table, + }) + .whereLike('indexdef', `%(${columns})`); + if (!result.length) { + console.log('Index is missing'); + console.log(query.toSQL()); + console.log(`CREATE INDEX IF NOT EXISTS ${name} ON ${this.table} (${columns})`); + process.exit(1); + } + }; + + createIndex = () => { + const columns = []; + + for (const { key } of this.whereIns) { + columns.push(key); + } + for (const { key } of this.wheres) { + columns.push(key); + } + for (const ors of this.whereOrs) { + for (const key of Object.keys(ors)) { + columns.push(key); + } + } + + const inKeys = this.whereIns.map((i) => i.key); + const whereKeys = this.wheres.map((w) => w.key); + const orKeys = this.whereOrs.map(Object.keys).reduce((acc, act) => [...acc, ...act], []); + const allKeys = uniq([...inKeys, ...whereKeys, ...orKeys]); + + const orderBys = [...this.orderBys]; + if (!this.orderBys.map((o) => o.key).includes('uid')) { + orderBys.push({ key: 'uid', dir: 'asc' }); + } + for (const { key } of orderBys) { + if (!allKeys.includes(key)) { + columns.push(key); + } + } + + const name = `${this.table}_${Math.random().toString().replace('0.', '')}`; + return { + name, + columns: columns + .map((c) => (some(c, (char) => /[A-Z]/.test(char)) || c === 'position' ? `"${c}"` : c)) + .join(', '), + }; + }; +} + +export class IQuery extends BaseIQuery { + get = async (): Promise => { + const query = this.createQuery(); + await this.checkIndex(query); + + const snap = await query; + return snap.map(this.converter.fromPg); + }; + + onSnapshot = (callback: (data: C[]) => Promise | void, onError?: (err: any) => void) => { + const snap = new OnSnapshot(this, callback, onError); + return snap.unsubscrib; + }; + + whereOr = (filters: Record) => { + this.whereOrs.push(filters); + return this; + }; + + where = ( + fieldPath: F, + operator: WhereFilterOp, + value: Q[F] | undefined | null, + ): IQuery => { + this.wheres.push({ key: fieldPath as string, opr: operator, value }); + return this; + }; + + whereIn = (fieldPath: F, value: Q[F][]): IQuery => { + this.whereIns.push({ key: fieldPath as any, value }); + return this; + }; + + startAfter = (data: C | undefined): IQuery => { + this.startAfterData = data ? this.converter.toPg(data) : undefined; + return this; + }; + + limit = (value: number): IQuery => { + this.limits = value; + return this; + }; + + orderBy = (fieldPath: F, dir: 'asc' | 'desc' = 'asc') => { + this.orderBys.push({ key: fieldPath as string, dir }); + return this; + }; +} diff --git a/packages/database/src/pg/interfaces/query/snapshot.ts b/packages/database/src/pg/interfaces/query/snapshot.ts new file mode 100644 index 0000000000..6d099035e6 --- /dev/null +++ b/packages/database/src/pg/interfaces/query/snapshot.ts @@ -0,0 +1,134 @@ +import { Message, Subscription } from '@google-cloud/pubsub'; +import { get, gt, gte, isEqual, lt, lte, orderBy, take } from 'lodash'; +import { getPgData, getSubscription } from '../../impl/pubsub'; +import { WhereFilterOp } from '../common'; +import { IQuery } from './query'; + +export class OnSnapshot { + private subscription: Promise; + private interval: NodeJS.Timeout | undefined; + + private allData: any[] = []; + private rightData: any[] = []; + + constructor( + private query: IQuery, + private callback: (data: any[]) => Promise | void, + private onError?: (err: any) => void, + ) { + this.subscription = getSubscription(query.table); + + query + .createQuery() + .then(async (raw: any[]) => { + this.allData = raw; + this.rightData = raw; + + this.callback(this.rightData.map(query.converter.fromPg)); + + this.interval = setInterval(this.filter, 500); + + (await this.subscription).on('message', this.onMessage); + }) + .catch(this.onError); + } + + unsubscrib = () => { + clearInterval(this.interval); + this.subscription.then((subs) => { + subs.removeListener('message', this.onMessage); + }); + }; + + private onMessage = (message: Message) => { + message.ack(); + + const update = getPgData(message, this.query.converter); + const index = this.allData.findIndex( + (d) => d.uid === update.uid && d.parentId === update.parentId, + ); + + if (index === -1) { + this.allData.push(update); + return; + } + this.allData[index] = update; + }; + + private filter = () => { + let allData = this.allData.splice(0); + if (!allData.length) { + return; + } + + allData = allData.filter(this.shouldSelectData); + + const orderBys = [...this.query.orderBys]; + const orderKeys = orderBys.map((o) => o.key); + if (!orderKeys.includes('uid')) { + orderBys.push({ key: 'uid', dir: 'asc' }); + } + allData = orderBy( + allData, + orderBys.map((o) => o.key), + orderBys.map((o) => o.dir), + ); + + if (this.query.limits) { + allData = take(allData, this.query.limits); + } + + if (isEqual(this.rightData, allData)) { + return; + } + + this.rightData = allData; + this.callback(this.rightData.map(this.query.converter.fromPg)); + }; + + private shouldSelectData = (data: any) => { + for (const ins of this.query.whereIns) { + const value = get(data, ins.key); + if (!ins.value.includes(value)) { + return false; + } + } + + for (const wheres of this.query.wheres) { + const value = get(data, wheres.key); + if (!cmpWithLodash(value, wheres.opr, wheres.value)) { + return false; + } + } + + const whereOrsOk = this.query.whereOrs.reduce((acc, act) => { + for (const [key, value] of Object.entries(act)) { + if (isEqual(get(data, key), value)) { + return acc && true; + } + } + return false; + }, true); + + return whereOrsOk; + }; +} + +const cmpWithLodash = (a: any, opr: WhereFilterOp, b: any) => { + switch (opr) { + case '!=': + return !isEqual(a, b); + case '<': + return lt(a, b); + case '<=': + return lte(a, b); + case '==': + return isEqual(a, b); + case '>': + return gt(a, b); + case '>=': + return gte(a, b); + case 'array-contains': + return a.includes(b); + } +}; diff --git a/packages/database/src/pg/interfaces/query/sub.query.ts b/packages/database/src/pg/interfaces/query/sub.query.ts new file mode 100644 index 0000000000..088d8945ea --- /dev/null +++ b/packages/database/src/pg/interfaces/query/sub.query.ts @@ -0,0 +1,22 @@ +import { COL, SUB_COL } from '@build-5/interfaces'; +import { Knex } from 'knex'; +import { BaseRecord } from '../../models/common'; +import { Converter, getTableName } from '../common'; +import { IQuery } from './query'; + +export class ISubColQuery extends IQuery { + constructor( + public con: Knex, + public col: COL, + public colId: string | undefined, + public subCol: SUB_COL, + converter: Converter, + ) { + super(con, col, converter); + this.table = getTableName(col, subCol); + + if (colId) { + this.where('parentId' as any, '==', colId); + } + } +} diff --git a/packages/database/src/pg/interfaces/transaction.ts b/packages/database/src/pg/interfaces/transaction.ts new file mode 100644 index 0000000000..bc7967b152 --- /dev/null +++ b/packages/database/src/pg/interfaces/transaction.ts @@ -0,0 +1,26 @@ +import { BaseRecord } from '../models/common'; +import { Update } from '../models/common_update'; +import { IDocument } from './document/document'; + +export interface ITransaction { + get: ( + docRef: IDocument, + ) => Promise; + getAll: ( + ...docRefs: IDocument[] + ) => Promise<(C | undefined)[]>; + + create: ( + docRef: IDocument, + data: C, + ) => Promise; + update: ( + docRef: IDocument, + data: U, + ) => Promise; + upsert: ( + docRef: IDocument, + data: U, + ) => Promise; + delete: (docRef: IDocument) => Promise; +} diff --git a/packages/database/src/pg/models/airdrop.ts b/packages/database/src/pg/models/airdrop.ts new file mode 100644 index 0000000000..b53b57f59f --- /dev/null +++ b/packages/database/src/pg/models/airdrop.ts @@ -0,0 +1,20 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import * as commons from './common'; + +export interface PgAirdrop extends commons.BaseRecord { + member?: string; + token?: string; + award?: string; + vestingAt?: Date; + count?: number; + status?: string; + orderId?: string; + billPaymentId?: string; + sourceAddress?: string; + stakeRewardId?: string; + stakeType?: string; + isBaseToken?: boolean; +} diff --git a/packages/database/src/pg/models/airdrop_update.ts b/packages/database/src/pg/models/airdrop_update.ts new file mode 100644 index 0000000000..830c22a807 --- /dev/null +++ b/packages/database/src/pg/models/airdrop_update.ts @@ -0,0 +1,21 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import { Increment } from '../interfaces/common'; +import * as commons from './common_update'; + +export interface PgAirdropUpdate extends commons.BaseRecordUpdate { + member?: string | null; + token?: string | null; + award?: string | null; + vestingAt?: Date | null; + count?: number | null | Increment; + status?: string | null; + orderId?: string | null; + billPaymentId?: string | null; + sourceAddress?: string | null; + stakeRewardId?: string | null; + stakeType?: string | null; + isBaseToken?: boolean | null; +} diff --git a/packages/database/src/pg/models/auction.ts b/packages/database/src/pg/models/auction.ts new file mode 100644 index 0000000000..fdd38ec191 --- /dev/null +++ b/packages/database/src/pg/models/auction.ts @@ -0,0 +1,27 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import * as commons from './common'; + +export interface PgAuction extends commons.BaseRecord { + space?: string; + auctionFrom?: Date; + auctionTo?: Date; + auctionLength?: number; + extendedAuctionTo?: Date; + extendedAuctionLength?: number; + extendAuctionWithin?: number; + auctionFloorPrice?: number; + minimalBidIncrement?: number; + auctionHighestBidder?: string; + auctionHighestBid?: number; + maxBids?: number; + type?: string; + network?: string; + nftId?: string; + targetAddress?: string; + active?: boolean; + topUpBased?: boolean; + bids?: Record[]; +} diff --git a/packages/database/src/pg/models/auction_update.ts b/packages/database/src/pg/models/auction_update.ts new file mode 100644 index 0000000000..b083488dd3 --- /dev/null +++ b/packages/database/src/pg/models/auction_update.ts @@ -0,0 +1,28 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import { Increment } from '../interfaces/common'; +import * as commons from './common_update'; + +export interface PgAuctionUpdate extends commons.BaseRecordUpdate { + space?: string | null; + auctionFrom?: Date | null; + auctionTo?: Date | null; + auctionLength?: number | null | Increment; + extendedAuctionTo?: Date | null; + extendedAuctionLength?: number | null | Increment; + extendAuctionWithin?: number | null | Increment; + auctionFloorPrice?: number | null | Increment; + minimalBidIncrement?: number | null | Increment; + auctionHighestBidder?: string | null; + auctionHighestBid?: number | null | Increment; + maxBids?: number | null | Increment; + type?: string | null; + network?: string | null; + nftId?: string | null; + targetAddress?: string | null; + active?: boolean | null; + topUpBased?: boolean | null; + bids?: string | null; +} diff --git a/packages/database/src/pg/models/award.ts b/packages/database/src/pg/models/award.ts new file mode 100644 index 0000000000..44d0ac90c8 --- /dev/null +++ b/packages/database/src/pg/models/award.ts @@ -0,0 +1,56 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import * as commons from './common'; + +export interface PgAwardParticipants extends commons.BaseSubRecord { + comment?: string; + completed?: boolean; + count?: number; + tokenReward?: number; +} + +export interface PgAwardOwners extends commons.BaseSubRecord {} + +export interface PgAward extends commons.BaseRecord { + name?: string; + description?: string; + space?: string; + endDate?: Date; + issued?: number; + badgesMinted?: number; + approved?: boolean; + rejected?: boolean; + completed?: boolean; + network?: string; + aliasStorageDeposit?: number; + collectionStorageDeposit?: number; + nttStorageDeposit?: number; + nativeTokenStorageDeposit?: number; + funded?: boolean; + fundingAddress?: string; + fundedBy?: string; + address?: string; + airdropClaimed?: number; + aliasBlockId?: string; + aliasId?: string; + collectionBlockId?: string; + collectionId?: string; + mediaStatus?: string; + mediaUploadErrorCount?: number; + isLegacy?: boolean; + badge_name?: string; + badge_description?: string; + badge_total?: number; + badge_type?: string; + badge_tokenReward?: number; + badge_tokenUid?: string; + badge_tokenId?: string; + badge_tokenSymbol?: string; + badge_image?: string; + badge_ipfsMedia?: string; + badge_ipfsMetadata?: string; + badge_ipfsRoot?: string; + badge_lockTime?: number; +} diff --git a/packages/database/src/pg/models/award_update.ts b/packages/database/src/pg/models/award_update.ts new file mode 100644 index 0000000000..9e6aa35a32 --- /dev/null +++ b/packages/database/src/pg/models/award_update.ts @@ -0,0 +1,57 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import { Increment } from '../interfaces/common'; +import * as commons from './common_update'; + +export interface PgAwardParticipantsUpdate extends commons.BaseSubRecordUpdate { + comment?: string | null; + completed?: boolean | null; + count?: number | null | Increment; + tokenReward?: number | null | Increment; +} + +export interface PgAwardOwnersUpdate extends commons.BaseSubRecordUpdate {} + +export interface PgAwardUpdate extends commons.BaseRecordUpdate { + name?: string | null; + description?: string | null; + space?: string | null; + endDate?: Date | null; + issued?: number | null | Increment; + badgesMinted?: number | null | Increment; + approved?: boolean | null; + rejected?: boolean | null; + completed?: boolean | null; + network?: string | null; + aliasStorageDeposit?: number | null | Increment; + collectionStorageDeposit?: number | null | Increment; + nttStorageDeposit?: number | null | Increment; + nativeTokenStorageDeposit?: number | null | Increment; + funded?: boolean | null; + fundingAddress?: string | null; + fundedBy?: string | null; + address?: string | null; + airdropClaimed?: number | null | Increment; + aliasBlockId?: string | null; + aliasId?: string | null; + collectionBlockId?: string | null; + collectionId?: string | null; + mediaStatus?: string | null; + mediaUploadErrorCount?: number | null | Increment; + isLegacy?: boolean | null; + badge_name?: string | null; + badge_description?: string | null; + badge_total?: number | null | Increment; + badge_type?: string | null; + badge_tokenReward?: number | null | Increment; + badge_tokenUid?: string | null; + badge_tokenId?: string | null; + badge_tokenSymbol?: string | null; + badge_image?: string | null; + badge_ipfsMedia?: string | null; + badge_ipfsMetadata?: string | null; + badge_ipfsRoot?: string | null; + badge_lockTime?: number | null | Increment; +} diff --git a/packages/database/src/pg/models/changes.ts b/packages/database/src/pg/models/changes.ts new file mode 100644 index 0000000000..94f0f69842 --- /dev/null +++ b/packages/database/src/pg/models/changes.ts @@ -0,0 +1,9 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import * as commons from './common'; + +export interface PgChanges extends commons.BaseRecord { + change?: Record; +} diff --git a/packages/database/src/pg/models/changes_update.ts b/packages/database/src/pg/models/changes_update.ts new file mode 100644 index 0000000000..6488048de9 --- /dev/null +++ b/packages/database/src/pg/models/changes_update.ts @@ -0,0 +1,9 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import * as commons from './common_update'; + +export interface PgChangesUpdate extends commons.BaseRecordUpdate { + change?: string | any | null; +} diff --git a/packages/database/src/pg/models/collection.ts b/packages/database/src/pg/models/collection.ts new file mode 100644 index 0000000000..dd663e093c --- /dev/null +++ b/packages/database/src/pg/models/collection.ts @@ -0,0 +1,87 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import * as commons from './common'; + +export interface PgCollectionVotes extends commons.BaseSubRecord { + direction?: number; +} + +export interface PgCollectionStats extends commons.BaseSubRecord { + votes_upvotes?: number; + votes_downvotes?: number; + votes_voteDiff?: number; + ranks_count?: number; + ranks_sum?: number; + ranks_avg?: number; +} + +export interface PgCollectionRanks extends commons.BaseSubRecord { + rank?: number; +} + +export interface PgCollection extends commons.BaseRecord { + name?: string; + description?: string; + bannerUrl?: string; + royaltiesFee?: number; + royaltiesSpace?: string; + total?: number; + totalTrades?: number; + lastTradedOn?: Date; + sold?: number; + discord?: string; + url?: string; + twitter?: string; + approved?: boolean; + rejected?: boolean; + limitedEdition?: boolean; + ipfsMedia?: string; + ipfsMetadata?: string; + ipfsRoot?: string; + category?: string; + type?: number; + access?: number; + accessAwards?: string[]; + accessCollections?: string[]; + space?: string; + availableFrom?: Date; + price?: number; + availablePrice?: number; + onePerMemberOnly?: boolean; + placeholderNft?: string; + placeholderUrl?: string; + status?: string; + mintingData_address?: string; + mintingData_network?: string; + mintingData_mintedOn?: Date; + mintingData_mintedBy?: string; + mintingData_blockId?: string; + mintingData_nftId?: string; + mintingData_storageDeposit?: number; + mintingData_aliasBlockId?: string; + mintingData_aliasId?: string; + mintingData_aliasStorageDeposit?: number; + mintingData_mintingOrderId?: string; + mintingData_nftsToMint?: number; + mintingData_nftMediaToUpload?: number; + mintingData_nftMediaToPrepare?: number; + mintingData_unsoldMintingOptions?: string; + mintingData_newPrice?: number; + mintingData_nftsStorageDeposit?: number; + rankCount?: number; + rankSum?: number; + rankAvg?: number; + mediaStatus?: string; + mediaUploadErrorCount?: number; + stakedNft?: number; + nftsOnSale?: number; + nftsOnAuction?: number; + availableNfts?: number; + floorPrice?: number; + votes_upvotes?: number; + votes_downvotes?: number; + votes_voteDiff?: number; + discounts?: Record[]; +} diff --git a/packages/database/src/pg/models/collection_update.ts b/packages/database/src/pg/models/collection_update.ts new file mode 100644 index 0000000000..8b0bb5ad13 --- /dev/null +++ b/packages/database/src/pg/models/collection_update.ts @@ -0,0 +1,88 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import { ArrayRemove, ArrayUnion, Increment } from '../interfaces/common'; +import * as commons from './common_update'; + +export interface PgCollectionVotesUpdate extends commons.BaseSubRecordUpdate { + direction?: number | null | Increment; +} + +export interface PgCollectionStatsUpdate extends commons.BaseSubRecordUpdate { + votes_upvotes?: number | null | Increment; + votes_downvotes?: number | null | Increment; + votes_voteDiff?: number | null | Increment; + ranks_count?: number | null | Increment; + ranks_sum?: number | null | Increment; + ranks_avg?: number | null | Increment; +} + +export interface PgCollectionRanksUpdate extends commons.BaseSubRecordUpdate { + rank?: number | null | Increment; +} + +export interface PgCollectionUpdate extends commons.BaseRecordUpdate { + name?: string | null; + description?: string | null; + bannerUrl?: string | null; + royaltiesFee?: number | null | Increment; + royaltiesSpace?: string | null; + total?: number | null | Increment; + totalTrades?: number | null | Increment; + lastTradedOn?: Date | null; + sold?: number | null | Increment; + discord?: string | null; + url?: string | null; + twitter?: string | null; + approved?: boolean | null; + rejected?: boolean | null; + limitedEdition?: boolean | null; + ipfsMedia?: string | null; + ipfsMetadata?: string | null; + ipfsRoot?: string | null; + category?: string | null; + type?: number | null | Increment; + access?: number | null | Increment; + accessAwards?: string[] | null | ArrayUnion | ArrayRemove; + accessCollections?: string[] | null | ArrayUnion | ArrayRemove; + space?: string | null; + availableFrom?: Date | null; + price?: number | null | Increment; + availablePrice?: number | null | Increment; + onePerMemberOnly?: boolean | null; + placeholderNft?: string | null; + placeholderUrl?: string | null; + status?: string | null; + mintingData_address?: string | null; + mintingData_network?: string | null; + mintingData_mintedOn?: Date | null; + mintingData_mintedBy?: string | null; + mintingData_blockId?: string | null; + mintingData_nftId?: string | null; + mintingData_storageDeposit?: number | null | Increment; + mintingData_aliasBlockId?: string | null; + mintingData_aliasId?: string | null; + mintingData_aliasStorageDeposit?: number | null | Increment; + mintingData_mintingOrderId?: string | null; + mintingData_nftsToMint?: number | null | Increment; + mintingData_nftMediaToUpload?: number | null | Increment; + mintingData_nftMediaToPrepare?: number | null | Increment; + mintingData_unsoldMintingOptions?: string | null; + mintingData_newPrice?: number | null | Increment; + mintingData_nftsStorageDeposit?: number | null | Increment; + rankCount?: number | null | Increment; + rankSum?: number | null | Increment; + rankAvg?: number | null | Increment; + mediaStatus?: string | null; + mediaUploadErrorCount?: number | null | Increment; + stakedNft?: number | null | Increment; + nftsOnSale?: number | null | Increment; + nftsOnAuction?: number | null | Increment; + availableNfts?: number | null | Increment; + floorPrice?: number | null | Increment; + votes_upvotes?: number | null | Increment; + votes_downvotes?: number | null | Increment; + votes_voteDiff?: number | null | Increment; + discounts?: string | null; +} diff --git a/packages/database/src/pg/models/common.ts b/packages/database/src/pg/models/common.ts new file mode 100644 index 0000000000..25242cb6a6 --- /dev/null +++ b/packages/database/src/pg/models/common.ts @@ -0,0 +1,14 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +export interface BaseRecord { + uid: string; + project?: string; + createdOn?: Date; + updatedOn?: Date; + createdBy?: string; +} +export interface BaseSubRecord extends BaseRecord { + parentId: string; +} diff --git a/packages/database/src/pg/models/common_update.ts b/packages/database/src/pg/models/common_update.ts new file mode 100644 index 0000000000..4b9268a994 --- /dev/null +++ b/packages/database/src/pg/models/common_update.ts @@ -0,0 +1,14 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +export interface Update {} +export interface BaseRecordUpdate extends Update { + project?: string; + createdOn?: Date; + updatedOn?: Date; + createdBy?: string; +} +export interface BaseSubRecordUpdate extends Update, BaseRecordUpdate { + parentId?: string; +} diff --git a/packages/database/src/pg/models/enums.ts b/packages/database/src/pg/models/enums.ts new file mode 100644 index 0000000000..aca727b38e --- /dev/null +++ b/packages/database/src/pg/models/enums.ts @@ -0,0 +1,4 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ diff --git a/packages/database/src/pg/models/index.ts b/packages/database/src/pg/models/index.ts new file mode 100644 index 0000000000..e563ada6ee --- /dev/null +++ b/packages/database/src/pg/models/index.ts @@ -0,0 +1,42 @@ +export * from './airdrop'; +export * from './airdrop_update'; +export * from './auction'; +export * from './auction_update'; +export * from './award'; +export * from './award_update'; +export * from './changes'; +export * from './changes_update'; +export * from './collection'; +export * from './collection_update'; +export * from './member'; +export * from './member_update'; +export * from './milestone'; +export * from './milestone_update'; +export * from './mnemonic'; +export * from './mnemonic_update'; +export * from './nft'; +export * from './nft_update'; +export * from './notification'; +export * from './notification_update'; +export * from './project'; +export * from './project_update'; +export * from './proposal'; +export * from './proposal_update'; +export * from './soon'; +export * from './soon_update'; +export * from './space'; +export * from './space_update'; +export * from './stake'; +export * from './stake_update'; +export * from './stamp'; +export * from './stamp_update'; +export * from './swap'; +export * from './swap_update'; +export * from './system'; +export * from './system_update'; +export * from './ticker'; +export * from './ticker_update'; +export * from './token'; +export * from './token_update'; +export * from './transaction'; +export * from './transaction_update'; diff --git a/packages/database/src/pg/models/member.ts b/packages/database/src/pg/models/member.ts new file mode 100644 index 0000000000..490b1b3383 --- /dev/null +++ b/packages/database/src/pg/models/member.ts @@ -0,0 +1,25 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import * as commons from './common'; + +export interface PgMember extends commons.BaseRecord { + nonce?: string; + name?: string; + about?: string; + avatarNft?: string; + avatar?: string; + discord?: string; + twitter?: string; + github?: string; + smrAddress?: string; + rmsAddress?: string; + iotaAddress?: string; + atoiAddress?: string; + prevValidatedAddresses?: string[]; + tokenTradingFeePercentage?: number; + tokenPurchaseFeePercentage?: number; + awardsCompleted?: number; + spaces?: Record; +} diff --git a/packages/database/src/pg/models/member_update.ts b/packages/database/src/pg/models/member_update.ts new file mode 100644 index 0000000000..569cb1a005 --- /dev/null +++ b/packages/database/src/pg/models/member_update.ts @@ -0,0 +1,26 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import { ArrayRemove, ArrayUnion, Increment } from '../interfaces/common'; +import * as commons from './common_update'; + +export interface PgMemberUpdate extends commons.BaseRecordUpdate { + nonce?: string | null; + name?: string | null; + about?: string | null; + avatarNft?: string | null; + avatar?: string | null; + discord?: string | null; + twitter?: string | null; + github?: string | null; + smrAddress?: string | null; + rmsAddress?: string | null; + iotaAddress?: string | null; + atoiAddress?: string | null; + prevValidatedAddresses?: string[] | null | ArrayUnion | ArrayRemove; + tokenTradingFeePercentage?: number | null | Increment; + tokenPurchaseFeePercentage?: number | null | Increment; + awardsCompleted?: number | null | Increment; + spaces?: string | any | null; +} diff --git a/packages/database/src/pg/models/milestone.ts b/packages/database/src/pg/models/milestone.ts new file mode 100644 index 0000000000..23bf82f0eb --- /dev/null +++ b/packages/database/src/pg/models/milestone.ts @@ -0,0 +1,65 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import * as commons from './common'; + +export interface PgMilestoneTransactions extends commons.BaseSubRecord { + PayloadSize?: number; + blockId?: string; + milestone?: number; + payload?: Record; + processed?: boolean; + processedOn?: Date; +} + +export interface PgMilestoneSmrTransactions extends commons.BaseSubRecord { + PayloadSize?: number; + blockId?: string; + milestone?: number; + payload?: Record; + processed?: boolean; + processedOn?: Date; +} + +export interface PgMilestoneSmr extends commons.BaseRecord { + completed?: boolean; + completedOn?: Date; + listenerNodeId?: string; + milestone?: number; + milestoneTimestamp?: Date; + trxConflictCount?: number; + trxFailedCount?: number; + trxValidCount?: number; +} + +export interface PgMilestoneRmsT2Transactions extends commons.BaseSubRecord { + PayloadSize?: number; + blockId?: string; + milestone?: number; + payload?: Record; + processed?: boolean; + processedOn?: Date; +} + +export interface PgMilestoneRmsT2 extends commons.BaseRecord { + completed?: boolean; + completedOn?: Date; + listenerNodeId?: string; + milestone?: number; + milestoneTimestamp?: Date; + trxConflictCount?: number; + trxFailedCount?: number; + trxValidCount?: number; +} + +export interface PgMilestone extends commons.BaseRecord { + completed?: boolean; + completedOn?: Date; + listenerNodeId?: string; + milestone?: number; + milestoneTimestamp?: Date; + trxConflictCount?: number; + trxFailedCount?: number; + trxValidCount?: number; +} diff --git a/packages/database/src/pg/models/milestone_update.ts b/packages/database/src/pg/models/milestone_update.ts new file mode 100644 index 0000000000..2bd96a39f6 --- /dev/null +++ b/packages/database/src/pg/models/milestone_update.ts @@ -0,0 +1,66 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import { Increment } from '../interfaces/common'; +import * as commons from './common_update'; + +export interface PgMilestoneTransactionsUpdate extends commons.BaseSubRecordUpdate { + PayloadSize?: number | null | Increment; + blockId?: string | null; + milestone?: number | null | Increment; + payload?: string | any | null; + processed?: boolean | null; + processedOn?: Date | null; +} + +export interface PgMilestoneSmrTransactionsUpdate extends commons.BaseSubRecordUpdate { + PayloadSize?: number | null | Increment; + blockId?: string | null; + milestone?: number | null | Increment; + payload?: string | any | null; + processed?: boolean | null; + processedOn?: Date | null; +} + +export interface PgMilestoneSmrUpdate extends commons.BaseRecordUpdate { + completed?: boolean | null; + completedOn?: Date | null; + listenerNodeId?: string | null; + milestone?: number | null | Increment; + milestoneTimestamp?: Date | null; + trxConflictCount?: number | null | Increment; + trxFailedCount?: number | null | Increment; + trxValidCount?: number | null | Increment; +} + +export interface PgMilestoneRmsT2TransactionsUpdate extends commons.BaseSubRecordUpdate { + PayloadSize?: number | null | Increment; + blockId?: string | null; + milestone?: number | null | Increment; + payload?: string | any | null; + processed?: boolean | null; + processedOn?: Date | null; +} + +export interface PgMilestoneRmsT2Update extends commons.BaseRecordUpdate { + completed?: boolean | null; + completedOn?: Date | null; + listenerNodeId?: string | null; + milestone?: number | null | Increment; + milestoneTimestamp?: Date | null; + trxConflictCount?: number | null | Increment; + trxFailedCount?: number | null | Increment; + trxValidCount?: number | null | Increment; +} + +export interface PgMilestoneUpdate extends commons.BaseRecordUpdate { + completed?: boolean | null; + completedOn?: Date | null; + listenerNodeId?: string | null; + milestone?: number | null | Increment; + milestoneTimestamp?: Date | null; + trxConflictCount?: number | null | Increment; + trxFailedCount?: number | null | Increment; + trxValidCount?: number | null | Increment; +} diff --git a/packages/database/src/pg/models/mnemonic.ts b/packages/database/src/pg/models/mnemonic.ts new file mode 100644 index 0000000000..c042977a47 --- /dev/null +++ b/packages/database/src/pg/models/mnemonic.ts @@ -0,0 +1,14 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import * as commons from './common'; + +export interface PgMnemonic extends commons.BaseRecord { + mnemonic?: string; + network?: string; + lockedBy?: string; + consumedOutputIds?: string[]; + consumedNftOutputIds?: string[]; + consumedAliasOutputIds?: string[]; +} diff --git a/packages/database/src/pg/models/mnemonic_update.ts b/packages/database/src/pg/models/mnemonic_update.ts new file mode 100644 index 0000000000..c209b2127a --- /dev/null +++ b/packages/database/src/pg/models/mnemonic_update.ts @@ -0,0 +1,15 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import { ArrayRemove, ArrayUnion } from '../interfaces/common'; +import * as commons from './common_update'; + +export interface PgMnemonicUpdate extends commons.BaseRecordUpdate { + mnemonic?: string | null; + network?: string | null; + lockedBy?: string | null; + consumedOutputIds?: string[] | null | ArrayUnion | ArrayRemove; + consumedNftOutputIds?: string[] | null | ArrayUnion | ArrayRemove; + consumedAliasOutputIds?: string[] | null | ArrayUnion | ArrayRemove; +} diff --git a/packages/database/src/pg/models/nft.ts b/packages/database/src/pg/models/nft.ts new file mode 100644 index 0000000000..7ccda34523 --- /dev/null +++ b/packages/database/src/pg/models/nft.ts @@ -0,0 +1,98 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import * as commons from './common'; + +export interface PgNftStake extends commons.BaseRecord { + member?: string; + space?: string; + collection?: string; + nft?: string; + weeks?: number; + expiresAt?: Date; + expirationProcessed?: boolean; + type?: string; +} + +export interface PgNft extends commons.BaseRecord { + name?: string; + description?: string; + collection?: string; + owner?: string; + isOwned?: boolean; + media?: string; + ipfsMedia?: string; + ipfsMetadata?: string; + ipfsRoot?: string; + saleAccess?: number; + saleAccessMembers?: string[]; + available?: number; + availableFrom?: Date; + auctionFrom?: Date; + auctionTo?: Date; + extendedAuctionTo?: Date; + auctionHighestBid?: number; + auctionHighestBidder?: string; + price?: number; + totalTrades?: number; + lastTradedOn?: Date; + availablePrice?: number; + auctionFloorPrice?: number; + auctionLength?: number; + extendedAuctionLength?: number; + extendAuctionWithin?: number; + type?: number; + space?: string; + url?: string; + approved?: boolean; + rejected?: boolean; + properties?: Record; + stats?: Record; + placeholderNft?: boolean; + position?: number; + locked?: boolean; + lockedBy?: string; + sold?: boolean; + mintingData_address?: string; + mintingData_network?: string; + mintingData_mintedOn?: Date; + mintingData_mintedBy?: string; + mintingData_blockId?: string; + mintingData_nftId?: string; + mintingData_storageDeposit?: number; + mintingData_aliasBlockId?: string; + mintingData_aliasId?: string; + mintingData_aliasStorageDeposit?: number; + mintingData_mintingOrderId?: string; + mintingData_nftsToMint?: number; + mintingData_nftMediaToUpload?: number; + mintingData_nftMediaToPrepare?: number; + mintingData_unsoldMintingOptions?: string; + mintingData_newPrice?: number; + mintingData_nftsStorageDeposit?: number; + depositData_address?: string; + depositData_network?: string; + depositData_mintedOn?: Date; + depositData_mintedBy?: string; + depositData_blockId?: string; + depositData_nftId?: string; + depositData_storageDeposit?: number; + depositData_aliasBlockId?: string; + depositData_aliasId?: string; + depositData_aliasStorageDeposit?: number; + depositData_mintingOrderId?: string; + depositData_nftsToMint?: number; + depositData_nftMediaToUpload?: number; + depositData_nftMediaToPrepare?: number; + depositData_unsoldMintingOptions?: string; + depositData_newPrice?: number; + depositData_nftsStorageDeposit?: number; + status?: string; + hidden?: boolean; + mediaStatus?: string; + mediaUploadErrorCount?: number; + soldOn?: Date; + setAsAvatar?: boolean; + auction?: string; +} diff --git a/packages/database/src/pg/models/nft_update.ts b/packages/database/src/pg/models/nft_update.ts new file mode 100644 index 0000000000..f75846c8d3 --- /dev/null +++ b/packages/database/src/pg/models/nft_update.ts @@ -0,0 +1,99 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import { ArrayRemove, ArrayUnion, Increment } from '../interfaces/common'; +import * as commons from './common_update'; + +export interface PgNftStakeUpdate extends commons.BaseRecordUpdate { + member?: string | null; + space?: string | null; + collection?: string | null; + nft?: string | null; + weeks?: number | null | Increment; + expiresAt?: Date | null; + expirationProcessed?: boolean | null; + type?: string | null; +} + +export interface PgNftUpdate extends commons.BaseRecordUpdate { + name?: string | null; + description?: string | null; + collection?: string | null; + owner?: string | null; + isOwned?: boolean | null; + media?: string | null; + ipfsMedia?: string | null; + ipfsMetadata?: string | null; + ipfsRoot?: string | null; + saleAccess?: number | null | Increment; + saleAccessMembers?: string[] | null | ArrayUnion | ArrayRemove; + available?: number | null | Increment; + availableFrom?: Date | null; + auctionFrom?: Date | null; + auctionTo?: Date | null; + extendedAuctionTo?: Date | null; + auctionHighestBid?: number | null | Increment; + auctionHighestBidder?: string | null; + price?: number | null | Increment; + totalTrades?: number | null | Increment; + lastTradedOn?: Date | null; + availablePrice?: number | null | Increment; + auctionFloorPrice?: number | null | Increment; + auctionLength?: number | null | Increment; + extendedAuctionLength?: number | null | Increment; + extendAuctionWithin?: number | null | Increment; + type?: number | null | Increment; + space?: string | null; + url?: string | null; + approved?: boolean | null; + rejected?: boolean | null; + properties?: string | any | null; + stats?: string | any | null; + placeholderNft?: boolean | null; + position?: number | null | Increment; + locked?: boolean | null; + lockedBy?: string | null; + sold?: boolean | null; + mintingData_address?: string | null; + mintingData_network?: string | null; + mintingData_mintedOn?: Date | null; + mintingData_mintedBy?: string | null; + mintingData_blockId?: string | null; + mintingData_nftId?: string | null; + mintingData_storageDeposit?: number | null | Increment; + mintingData_aliasBlockId?: string | null; + mintingData_aliasId?: string | null; + mintingData_aliasStorageDeposit?: number | null | Increment; + mintingData_mintingOrderId?: string | null; + mintingData_nftsToMint?: number | null | Increment; + mintingData_nftMediaToUpload?: number | null | Increment; + mintingData_nftMediaToPrepare?: number | null | Increment; + mintingData_unsoldMintingOptions?: string | null; + mintingData_newPrice?: number | null | Increment; + mintingData_nftsStorageDeposit?: number | null | Increment; + depositData_address?: string | null; + depositData_network?: string | null; + depositData_mintedOn?: Date | null; + depositData_mintedBy?: string | null; + depositData_blockId?: string | null; + depositData_nftId?: string | null; + depositData_storageDeposit?: number | null | Increment; + depositData_aliasBlockId?: string | null; + depositData_aliasId?: string | null; + depositData_aliasStorageDeposit?: number | null | Increment; + depositData_mintingOrderId?: string | null; + depositData_nftsToMint?: number | null | Increment; + depositData_nftMediaToUpload?: number | null | Increment; + depositData_nftMediaToPrepare?: number | null | Increment; + depositData_unsoldMintingOptions?: string | null; + depositData_newPrice?: number | null | Increment; + depositData_nftsStorageDeposit?: number | null | Increment; + status?: string | null; + hidden?: boolean | null; + mediaStatus?: string | null; + mediaUploadErrorCount?: number | null | Increment; + soldOn?: Date | null; + setAsAvatar?: boolean | null; + auction?: string | null; +} diff --git a/packages/database/src/pg/models/notification.ts b/packages/database/src/pg/models/notification.ts new file mode 100644 index 0000000000..6083293033 --- /dev/null +++ b/packages/database/src/pg/models/notification.ts @@ -0,0 +1,12 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import * as commons from './common'; + +export interface PgNotification extends commons.BaseRecord { + space?: string; + member?: string; + type?: string; + params?: Record; +} diff --git a/packages/database/src/pg/models/notification_update.ts b/packages/database/src/pg/models/notification_update.ts new file mode 100644 index 0000000000..c89379bbc5 --- /dev/null +++ b/packages/database/src/pg/models/notification_update.ts @@ -0,0 +1,12 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import * as commons from './common_update'; + +export interface PgNotificationUpdate extends commons.BaseRecordUpdate { + space?: string | null; + member?: string | null; + type?: string | null; + params?: string | any | null; +} diff --git a/packages/database/src/pg/models/project.ts b/packages/database/src/pg/models/project.ts new file mode 100644 index 0000000000..6c13ad7597 --- /dev/null +++ b/packages/database/src/pg/models/project.ts @@ -0,0 +1,23 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import * as commons from './common'; + +export interface PgProjectAdmins extends commons.BaseSubRecord {} + +export interface PgProjectApiKey extends commons.BaseSubRecord { + token?: string; +} + +export interface PgProject extends commons.BaseRecord { + name?: string; + contactEmail?: string; + deactivated?: boolean; + config_billing?: string; + config_tiers?: number[]; + config_tokenTradingFeeDiscountPercentage?: number[]; + config_nativeTokenSymbol?: string; + config_nativeTokenUid?: string; + otr?: Record; +} diff --git a/packages/database/src/pg/models/project_update.ts b/packages/database/src/pg/models/project_update.ts new file mode 100644 index 0000000000..ffa6ad84a7 --- /dev/null +++ b/packages/database/src/pg/models/project_update.ts @@ -0,0 +1,23 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import * as commons from './common_update'; + +export interface PgProjectAdminsUpdate extends commons.BaseSubRecordUpdate {} + +export interface PgProjectApiKeyUpdate extends commons.BaseSubRecordUpdate { + token?: string | null; +} + +export interface PgProjectUpdate extends commons.BaseRecordUpdate { + name?: string | null; + contactEmail?: string | null; + deactivated?: boolean | null; + config_billing?: string | null; + config_tiers?: number[] | null; + config_tokenTradingFeeDiscountPercentage?: number[] | null; + config_nativeTokenSymbol?: string | null; + config_nativeTokenUid?: string | null; + otr?: string | any | null; +} diff --git a/packages/database/src/pg/models/proposal.ts b/packages/database/src/pg/models/proposal.ts new file mode 100644 index 0000000000..89aaaceb5c --- /dev/null +++ b/packages/database/src/pg/models/proposal.ts @@ -0,0 +1,42 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import * as commons from './common'; + +export interface PgProposalOwners extends commons.BaseSubRecord {} + +export interface PgProposalMembers extends commons.BaseSubRecord { + voted?: boolean; + weight?: number; + tranId?: string; + values?: Record; +} + +export interface PgProposal extends commons.BaseRecord { + space?: string; + name?: string; + description?: string; + additionalInfo?: string; + type?: number; + approved?: boolean; + rejected?: boolean; + approvedBy?: string; + rejectedBy?: string; + eventId?: string; + totalWeight?: number; + token?: string; + completed?: boolean; + rank?: number; + settings_startDate?: Date; + settings_endDate?: Date; + settings_guardiansOnly?: boolean; + settings_addRemoveGuardian?: string; + settings_spaceUpdateData?: Record; + settings_onlyGuardians?: boolean; + settings_stakeRewardIds?: string[]; + settings_awards?: string[]; + questions?: Record[]; + members?: Record[]; + results?: Record; +} diff --git a/packages/database/src/pg/models/proposal_update.ts b/packages/database/src/pg/models/proposal_update.ts new file mode 100644 index 0000000000..e0c9980789 --- /dev/null +++ b/packages/database/src/pg/models/proposal_update.ts @@ -0,0 +1,43 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import { ArrayRemove, ArrayUnion, Increment } from '../interfaces/common'; +import * as commons from './common_update'; + +export interface PgProposalOwnersUpdate extends commons.BaseSubRecordUpdate {} + +export interface PgProposalMembersUpdate extends commons.BaseSubRecordUpdate { + voted?: boolean | null; + weight?: number | null | Increment; + tranId?: string | null; + values?: string | any | null; +} + +export interface PgProposalUpdate extends commons.BaseRecordUpdate { + space?: string | null; + name?: string | null; + description?: string | null; + additionalInfo?: string | null; + type?: number | null | Increment; + approved?: boolean | null; + rejected?: boolean | null; + approvedBy?: string | null; + rejectedBy?: string | null; + eventId?: string | null; + totalWeight?: number | null | Increment; + token?: string | null; + completed?: boolean | null; + rank?: number | null | Increment; + settings_startDate?: Date | null; + settings_endDate?: Date | null; + settings_guardiansOnly?: boolean | null; + settings_addRemoveGuardian?: string | null; + settings_spaceUpdateData?: string | any | null; + settings_onlyGuardians?: boolean | null; + settings_stakeRewardIds?: string[] | null | ArrayUnion | ArrayRemove; + settings_awards?: string[] | null | ArrayUnion | ArrayRemove; + questions?: string | null; + members?: string | null; + results?: string | any | null; +} diff --git a/packages/database/src/pg/models/soon.ts b/packages/database/src/pg/models/soon.ts new file mode 100644 index 0000000000..9a0f114dfd --- /dev/null +++ b/packages/database/src/pg/models/soon.ts @@ -0,0 +1,13 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import * as commons from './common'; + +export interface PgSoonSnapshot extends commons.BaseRecord { + count: number; + paidOut: number; + lastPaidOutOn?: Date; + ethAddress: string; + ethAddressVerified: boolean; +} diff --git a/packages/database/src/pg/models/soon_update.ts b/packages/database/src/pg/models/soon_update.ts new file mode 100644 index 0000000000..4befbe9bcc --- /dev/null +++ b/packages/database/src/pg/models/soon_update.ts @@ -0,0 +1,14 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import { Increment } from '../interfaces/common'; +import * as commons from './common_update'; + +export interface PgSoonSnapshotUpdate extends commons.BaseRecordUpdate { + count?: number | Increment; + paidOut?: number | Increment; + lastPaidOutOn?: Date | null; + ethAddress?: string; + ethAddressVerified?: boolean; +} diff --git a/packages/database/src/pg/models/space.ts b/packages/database/src/pg/models/space.ts new file mode 100644 index 0000000000..8fc52d4c2d --- /dev/null +++ b/packages/database/src/pg/models/space.ts @@ -0,0 +1,47 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import * as commons from './common'; + +export interface PgSpaceMembers extends commons.BaseSubRecord {} + +export interface PgSpaceKnockingmembers extends commons.BaseSubRecord {} + +export interface PgSpaceGuardians extends commons.BaseSubRecord {} + +export interface PgSpaceBlockedmembers extends commons.BaseSubRecord {} + +export interface PgSpace extends commons.BaseRecord { + name?: string; + about?: string; + open?: boolean; + tokenBased?: boolean; + minStakedValue?: number; + github?: string; + twitter?: string; + discord?: string; + avatarUrl?: string; + bannerUrl?: string; + totalGuardians?: number; + totalMembers?: number; + totalPendingMembers?: number; + smrAddress?: string; + rmsAddress?: string; + iotaAddress?: string; + atoiAddress?: string; + prevValidatedAddresses?: string[]; + vaultAddress?: string; + collectionId?: string; + claimed?: boolean; + ipfsMedia?: string; + ipfsMetadata?: string; + ipfsRoot?: string; + mediaStatus?: string; + mediaUploadErrorCount?: number; + alias_address?: string; + alias_aliasId?: string; + alias_blockId?: string; + alias_mintedOn?: Date; + alias_mintedBy?: string; +} diff --git a/packages/database/src/pg/models/space_update.ts b/packages/database/src/pg/models/space_update.ts new file mode 100644 index 0000000000..b6cde1f31d --- /dev/null +++ b/packages/database/src/pg/models/space_update.ts @@ -0,0 +1,48 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import { ArrayRemove, ArrayUnion, Increment } from '../interfaces/common'; +import * as commons from './common_update'; + +export interface PgSpaceMembersUpdate extends commons.BaseSubRecordUpdate {} + +export interface PgSpaceKnockingmembersUpdate extends commons.BaseSubRecordUpdate {} + +export interface PgSpaceGuardiansUpdate extends commons.BaseSubRecordUpdate {} + +export interface PgSpaceBlockedmembersUpdate extends commons.BaseSubRecordUpdate {} + +export interface PgSpaceUpdate extends commons.BaseRecordUpdate { + name?: string | null; + about?: string | null; + open?: boolean | null; + tokenBased?: boolean | null; + minStakedValue?: number | null | Increment; + github?: string | null; + twitter?: string | null; + discord?: string | null; + avatarUrl?: string | null; + bannerUrl?: string | null; + totalGuardians?: number | null | Increment; + totalMembers?: number | null | Increment; + totalPendingMembers?: number | null | Increment; + smrAddress?: string | null; + rmsAddress?: string | null; + iotaAddress?: string | null; + atoiAddress?: string | null; + prevValidatedAddresses?: string[] | null | ArrayUnion | ArrayRemove; + vaultAddress?: string | null; + collectionId?: string | null; + claimed?: boolean | null; + ipfsMedia?: string | null; + ipfsMetadata?: string | null; + ipfsRoot?: string | null; + mediaStatus?: string | null; + mediaUploadErrorCount?: number | null | Increment; + alias_address?: string | null; + alias_aliasId?: string | null; + alias_blockId?: string | null; + alias_mintedOn?: Date | null; + alias_mintedBy?: string | null; +} diff --git a/packages/database/src/pg/models/stake.ts b/packages/database/src/pg/models/stake.ts new file mode 100644 index 0000000000..f65939ebd9 --- /dev/null +++ b/packages/database/src/pg/models/stake.ts @@ -0,0 +1,31 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import * as commons from './common'; + +export interface PgStakeReward extends commons.BaseRecord { + startDate?: Date; + endDate?: Date; + tokenVestingDate?: Date; + tokensToDistribute?: number; + token?: string; + totalStaked?: number; + totalAirdropped?: number; + status?: string; +} + +export interface PgStake extends commons.BaseRecord { + member?: string; + space?: string; + token?: string; + amount?: number; + value?: number; + weeks?: number; + expiresAt?: Date; + expirationProcessed?: boolean; + orderId?: string; + billPaymentId?: string; + type?: string; + customMetadata?: Record; +} diff --git a/packages/database/src/pg/models/stake_update.ts b/packages/database/src/pg/models/stake_update.ts new file mode 100644 index 0000000000..61dbd7cfde --- /dev/null +++ b/packages/database/src/pg/models/stake_update.ts @@ -0,0 +1,32 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import { Increment } from '../interfaces/common'; +import * as commons from './common_update'; + +export interface PgStakeRewardUpdate extends commons.BaseRecordUpdate { + startDate?: Date | null; + endDate?: Date | null; + tokenVestingDate?: Date | null; + tokensToDistribute?: number | null | Increment; + token?: string | null; + totalStaked?: number | null | Increment; + totalAirdropped?: number | null | Increment; + status?: string | null; +} + +export interface PgStakeUpdate extends commons.BaseRecordUpdate { + member?: string | null; + space?: string | null; + token?: string | null; + amount?: number | null | Increment; + value?: number | null | Increment; + weeks?: number | null | Increment; + expiresAt?: Date | null; + expirationProcessed?: boolean | null; + orderId?: string | null; + billPaymentId?: string | null; + type?: string | null; + customMetadata?: string | any | null; +} diff --git a/packages/database/src/pg/models/stamp.ts b/packages/database/src/pg/models/stamp.ts new file mode 100644 index 0000000000..f46efb9342 --- /dev/null +++ b/packages/database/src/pg/models/stamp.ts @@ -0,0 +1,26 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import * as commons from './common'; + +export interface PgStamp extends commons.BaseRecord { + space?: string; + build5Url?: string; + originUri?: string; + checksum?: string; + extension?: string; + bytes?: number; + costPerMb?: number; + network?: string; + ipfsMedia?: string; + ipfsRoot?: string; + expiresAt?: Date; + order?: string; + funded?: boolean; + expired?: boolean; + mediaStatus?: string; + mediaUploadErrorCount?: number; + aliasId?: string; + nftId?: string; +} diff --git a/packages/database/src/pg/models/stamp_update.ts b/packages/database/src/pg/models/stamp_update.ts new file mode 100644 index 0000000000..b892be26ac --- /dev/null +++ b/packages/database/src/pg/models/stamp_update.ts @@ -0,0 +1,27 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import { Increment } from '../interfaces/common'; +import * as commons from './common_update'; + +export interface PgStampUpdate extends commons.BaseRecordUpdate { + space?: string | null; + build5Url?: string | null; + originUri?: string | null; + checksum?: string | null; + extension?: string | null; + bytes?: number | null | Increment; + costPerMb?: number | null | Increment; + network?: string | null; + ipfsMedia?: string | null; + ipfsRoot?: string | null; + expiresAt?: Date | null; + order?: string | null; + funded?: boolean | null; + expired?: boolean | null; + mediaStatus?: string | null; + mediaUploadErrorCount?: number | null | Increment; + aliasId?: string | null; + nftId?: string | null; +} diff --git a/packages/database/src/pg/models/swap.ts b/packages/database/src/pg/models/swap.ts new file mode 100644 index 0000000000..70aca74aa1 --- /dev/null +++ b/packages/database/src/pg/models/swap.ts @@ -0,0 +1,18 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import * as commons from './common'; + +export interface PgSwap extends commons.BaseRecord { + recipient?: string; + network?: string; + address?: string; + orderId?: string; + nftIdsAsk?: string[]; + baseTokenAmountAsk?: number; + nativeTokensAsk?: Record[]; + status?: string; + bidOutputs?: Record[]; + askOutputs?: Record[]; +} diff --git a/packages/database/src/pg/models/swap_update.ts b/packages/database/src/pg/models/swap_update.ts new file mode 100644 index 0000000000..7d065746c0 --- /dev/null +++ b/packages/database/src/pg/models/swap_update.ts @@ -0,0 +1,19 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import { ArrayRemove, ArrayUnion, Increment } from '../interfaces/common'; +import * as commons from './common_update'; + +export interface PgSwapUpdate extends commons.BaseRecordUpdate { + recipient?: string | null; + network?: string | null; + address?: string | null; + orderId?: string | null; + nftIdsAsk?: string[] | null | ArrayUnion | ArrayRemove; + baseTokenAmountAsk?: number | null | Increment; + nativeTokensAsk?: string | null; + status?: string | null; + bidOutputs?: string | null; + askOutputs?: string | null; +} diff --git a/packages/database/src/pg/models/system.ts b/packages/database/src/pg/models/system.ts new file mode 100644 index 0000000000..1d88900af2 --- /dev/null +++ b/packages/database/src/pg/models/system.ts @@ -0,0 +1,10 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import * as commons from './common'; + +export interface PgSystem extends commons.BaseRecord { + tokenTradingFeePercentage?: number; + tokenPurchaseFeePercentage?: number; +} diff --git a/packages/database/src/pg/models/system_update.ts b/packages/database/src/pg/models/system_update.ts new file mode 100644 index 0000000000..32620a734c --- /dev/null +++ b/packages/database/src/pg/models/system_update.ts @@ -0,0 +1,11 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import { Increment } from '../interfaces/common'; +import * as commons from './common_update'; + +export interface PgSystemUpdate extends commons.BaseRecordUpdate { + tokenTradingFeePercentage?: number | null | Increment; + tokenPurchaseFeePercentage?: number | null | Increment; +} diff --git a/packages/database/src/pg/models/ticker.ts b/packages/database/src/pg/models/ticker.ts new file mode 100644 index 0000000000..2f899f5093 --- /dev/null +++ b/packages/database/src/pg/models/ticker.ts @@ -0,0 +1,9 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import * as commons from './common'; + +export interface PgTicker extends commons.BaseRecord { + price?: number; +} diff --git a/packages/database/src/pg/models/ticker_update.ts b/packages/database/src/pg/models/ticker_update.ts new file mode 100644 index 0000000000..b198662d33 --- /dev/null +++ b/packages/database/src/pg/models/ticker_update.ts @@ -0,0 +1,10 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import { Increment } from '../interfaces/common'; +import * as commons from './common_update'; + +export interface PgTickerUpdate extends commons.BaseRecordUpdate { + price?: number | null | Increment; +} diff --git a/packages/database/src/pg/models/token.ts b/packages/database/src/pg/models/token.ts new file mode 100644 index 0000000000..6919a80e26 --- /dev/null +++ b/packages/database/src/pg/models/token.ts @@ -0,0 +1,171 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import * as commons from './common'; + +export interface PgTokenVotes extends commons.BaseSubRecord { + direction?: number; +} + +export interface PgTokenStats extends commons.BaseSubRecord { + votes_upvotes?: number; + votes_downvotes?: number; + votes_voteDiff?: number; + ranks_count?: number; + ranks_sum?: number; + ranks_avg?: number; + volumeTotal?: number; + volume_in24h?: number; + volume_in48h?: number; + volume_in7d?: number; + stakes_static_amount?: number; + stakes_static_totalAmount?: number; + stakes_static_value?: number; + stakes_static_totalValue?: number; + stakes_static_stakingMembersCount?: number; + stakes_dynamic_amount?: number; + stakes_dynamic_totalAmount?: number; + stakes_dynamic_value?: number; + stakes_dynamic_totalValue?: number; + stakes_dynamic_stakingMembersCount?: number; + stakeExpiry?: Record; +} + +export interface PgTokenRanks extends commons.BaseSubRecord { + rank?: number; +} + +export interface PgTokenPurchase extends commons.BaseRecord { + token?: string; + tokenStatus?: string; + sell?: string; + buy?: string; + count?: number; + price?: number; + triggeredBy?: string; + billPaymentId?: string; + buyerBillPaymentId?: string; + royaltyBillPayments?: string[]; + sourceNetwork?: string; + targetNetwork?: string; + sellerTokenTradingFeePercentage?: number; + sellerTier?: number; + in24h?: boolean; + in48h?: boolean; + in7d?: boolean; +} + +export interface PgTokenMarket extends commons.BaseRecord { + owner?: string; + token?: string; + tokenStatus?: string; + type?: string; + count?: number; + price?: number; + totalDeposit?: number; + balance?: number; + fulfilled?: number; + status?: string; + orderTransactionId?: string; + paymentTransactionId?: string; + creditTransactionId?: string; + expiresAt?: Date; + shouldRetry?: boolean; + sourceNetwork?: string; + targetNetwork?: string; + targetAddress?: string; +} + +export interface PgTokenDistribution extends commons.BaseSubRecord { + totalDeposit?: number; + totalPaid?: number; + refundedAmount?: number; + totalBought?: number; + reconciled?: boolean; + billPaymentId?: string; + creditPaymentId?: string; + royaltyBillPaymentId?: string; + tokenClaimed?: number; + lockedForSale?: number; + sold?: number; + totalPurchased?: number; + tokenOwned?: number; + mintedClaimedOn?: Date; + mintingTransactions?: string[]; + stakeRewards?: number; + extraStakeRewards?: number; + totalUnclaimedAirdrop?: number; + stakeVoteTransactionId?: string; + stakes_static_amount?: number; + stakes_static_totalAmount?: number; + stakes_static_value?: number; + stakes_static_totalValue?: number; + stakes_static_stakingMembersCount?: number; + stakes_dynamic_amount?: number; + stakes_dynamic_totalAmount?: number; + stakes_dynamic_value?: number; + stakes_dynamic_totalValue?: number; + stakes_dynamic_stakingMembersCount?: number; + stakeExpiry?: Record; +} + +export interface PgToken extends commons.BaseRecord { + name?: string; + symbol?: string; + title?: string; + description?: string; + shortDescriptionTitle?: string; + shortDescription?: string; + space?: string; + pricePerToken?: number; + totalSupply?: number; + allocations?: Record[]; + saleStartDate?: Date; + saleLength?: number; + coolDownEnd?: Date; + autoProcessAt100Percent?: boolean; + approved?: boolean; + rejected?: boolean; + public?: boolean; + links?: string[]; + icon?: string; + overviewGraphics?: string; + status?: string; + totalDeposit?: number; + tokensOrdered?: number; + totalAirdropped?: number; + termsAndConditions?: string; + access?: number; + accessAwards?: string[]; + accessCollections?: string[]; + ipfsMedia?: string; + ipfsMetadata?: string; + ipfsRoot?: string; + mintingData_mintedBy?: string; + mintingData_mintedOn?: Date; + mintingData_aliasBlockId?: string; + mintingData_aliasId?: string; + mintingData_aliasStorageDeposit?: number; + mintingData_tokenId?: string; + mintingData_blockId?: string; + mintingData_foundryStorageDeposit?: number; + mintingData_network?: string; + mintingData_networkFormat?: string; + mintingData_vaultAddress?: string; + mintingData_tokensInVault?: number; + mintingData_vaultStorageDeposit?: number; + mintingData_guardianStorageDeposit?: number; + mintingData_meltedTokens?: number; + mintingData_circulatingSupply?: number; + rankCount?: number; + rankSum?: number; + rankAvg?: number; + mediaStatus?: string; + mediaUploadErrorCount?: number; + tradingDisabled?: boolean; + decimals?: number; + votes_upvotes?: number; + votes_downvotes?: number; + votes_voteDiff?: number; +} diff --git a/packages/database/src/pg/models/token_update.ts b/packages/database/src/pg/models/token_update.ts new file mode 100644 index 0000000000..2ee2e3895e --- /dev/null +++ b/packages/database/src/pg/models/token_update.ts @@ -0,0 +1,172 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import { ArrayRemove, ArrayUnion, Increment } from '../interfaces/common'; +import * as commons from './common_update'; + +export interface PgTokenVotesUpdate extends commons.BaseSubRecordUpdate { + direction?: number | null | Increment; +} + +export interface PgTokenStatsUpdate extends commons.BaseSubRecordUpdate { + votes_upvotes?: number | null | Increment; + votes_downvotes?: number | null | Increment; + votes_voteDiff?: number | null | Increment; + ranks_count?: number | null | Increment; + ranks_sum?: number | null | Increment; + ranks_avg?: number | null | Increment; + volumeTotal?: number | null | Increment; + volume_in24h?: number | null | Increment; + volume_in48h?: number | null | Increment; + volume_in7d?: number | null | Increment; + stakes_static_amount?: number | null | Increment; + stakes_static_totalAmount?: number | null | Increment; + stakes_static_value?: number | null | Increment; + stakes_static_totalValue?: number | null | Increment; + stakes_static_stakingMembersCount?: number | null | Increment; + stakes_dynamic_amount?: number | null | Increment; + stakes_dynamic_totalAmount?: number | null | Increment; + stakes_dynamic_value?: number | null | Increment; + stakes_dynamic_totalValue?: number | null | Increment; + stakes_dynamic_stakingMembersCount?: number | null | Increment; + stakeExpiry?: string | any | null; +} + +export interface PgTokenRanksUpdate extends commons.BaseSubRecordUpdate { + rank?: number | null | Increment; +} + +export interface PgTokenPurchaseUpdate extends commons.BaseRecordUpdate { + token?: string | null; + tokenStatus?: string | null; + sell?: string | null; + buy?: string | null; + count?: number | null | Increment; + price?: number | null | Increment; + triggeredBy?: string | null; + billPaymentId?: string | null; + buyerBillPaymentId?: string | null; + royaltyBillPayments?: string[] | null | ArrayUnion | ArrayRemove; + sourceNetwork?: string | null; + targetNetwork?: string | null; + sellerTokenTradingFeePercentage?: number | null | Increment; + sellerTier?: number | null | Increment; + in24h?: boolean | null; + in48h?: boolean | null; + in7d?: boolean | null; +} + +export interface PgTokenMarketUpdate extends commons.BaseRecordUpdate { + owner?: string | null; + token?: string | null; + tokenStatus?: string | null; + type?: string | null; + count?: number | null | Increment; + price?: number | null | Increment; + totalDeposit?: number | null | Increment; + balance?: number | null | Increment; + fulfilled?: number | null | Increment; + status?: string | null; + orderTransactionId?: string | null; + paymentTransactionId?: string | null; + creditTransactionId?: string | null; + expiresAt?: Date | null; + shouldRetry?: boolean | null; + sourceNetwork?: string | null; + targetNetwork?: string | null; + targetAddress?: string | null; +} + +export interface PgTokenDistributionUpdate extends commons.BaseSubRecordUpdate { + totalDeposit?: number | null | Increment; + totalPaid?: number | null | Increment; + refundedAmount?: number | null | Increment; + totalBought?: number | null | Increment; + reconciled?: boolean | null; + billPaymentId?: string | null; + creditPaymentId?: string | null; + royaltyBillPaymentId?: string | null; + tokenClaimed?: number | null | Increment; + lockedForSale?: number | null | Increment; + sold?: number | null | Increment; + totalPurchased?: number | null | Increment; + tokenOwned?: number | null | Increment; + mintedClaimedOn?: Date | null; + mintingTransactions?: string[] | null | ArrayUnion | ArrayRemove; + stakeRewards?: number | null | Increment; + extraStakeRewards?: number | null | Increment; + totalUnclaimedAirdrop?: number | null | Increment; + stakeVoteTransactionId?: string | null; + stakes_static_amount?: number | null | Increment; + stakes_static_totalAmount?: number | null | Increment; + stakes_static_value?: number | null | Increment; + stakes_static_totalValue?: number | null | Increment; + stakes_static_stakingMembersCount?: number | null | Increment; + stakes_dynamic_amount?: number | null | Increment; + stakes_dynamic_totalAmount?: number | null | Increment; + stakes_dynamic_value?: number | null | Increment; + stakes_dynamic_totalValue?: number | null | Increment; + stakes_dynamic_stakingMembersCount?: number | null | Increment; + stakeExpiry?: string | any | null; +} + +export interface PgTokenUpdate extends commons.BaseRecordUpdate { + name?: string | null; + symbol?: string | null; + title?: string | null; + description?: string | null; + shortDescriptionTitle?: string | null; + shortDescription?: string | null; + space?: string | null; + pricePerToken?: number | null | Increment; + totalSupply?: number | null | Increment; + allocations?: string | null; + saleStartDate?: Date | null; + saleLength?: number | null | Increment; + coolDownEnd?: Date | null; + autoProcessAt100Percent?: boolean | null; + approved?: boolean | null; + rejected?: boolean | null; + public?: boolean | null; + links?: string[] | null | ArrayUnion | ArrayRemove; + icon?: string | null; + overviewGraphics?: string | null; + status?: string | null; + totalDeposit?: number | null | Increment; + tokensOrdered?: number | null | Increment; + totalAirdropped?: number | null | Increment; + termsAndConditions?: string | null; + access?: number | null | Increment; + accessAwards?: string[] | null | ArrayUnion | ArrayRemove; + accessCollections?: string[] | null | ArrayUnion | ArrayRemove; + ipfsMedia?: string | null; + ipfsMetadata?: string | null; + ipfsRoot?: string | null; + mintingData_mintedBy?: string | null; + mintingData_mintedOn?: Date | null; + mintingData_aliasBlockId?: string | null; + mintingData_aliasId?: string | null; + mintingData_aliasStorageDeposit?: number | null | Increment; + mintingData_tokenId?: string | null; + mintingData_blockId?: string | null; + mintingData_foundryStorageDeposit?: number | null | Increment; + mintingData_network?: string | null; + mintingData_networkFormat?: string | null; + mintingData_vaultAddress?: string | null; + mintingData_tokensInVault?: number | null | Increment; + mintingData_vaultStorageDeposit?: number | null | Increment; + mintingData_guardianStorageDeposit?: number | null | Increment; + mintingData_meltedTokens?: number | null | Increment; + mintingData_circulatingSupply?: number | null | Increment; + rankCount?: number | null | Increment; + rankSum?: number | null | Increment; + rankAvg?: number | null | Increment; + mediaStatus?: string | null; + mediaUploadErrorCount?: number | null | Increment; + tradingDisabled?: boolean | null; + decimals?: number | null | Increment; + votes_upvotes?: number | null | Increment; + votes_downvotes?: number | null | Increment; + votes_voteDiff?: number | null | Increment; +} diff --git a/packages/database/src/pg/models/transaction.ts b/packages/database/src/pg/models/transaction.ts new file mode 100644 index 0000000000..a15451ae60 --- /dev/null +++ b/packages/database/src/pg/models/transaction.ts @@ -0,0 +1,129 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import * as commons from './common'; + +export interface PgTransaction extends commons.BaseRecord { + network?: string; + type?: string; + isOrderType?: boolean; + member?: string; + space?: string; + shouldRetry?: boolean; + ignoreWallet?: boolean; + linkedTransactions?: string[]; + ignoreWalletReason?: string; + payload_type?: string; + payload_amount?: number; + payload_sourceAddress?: string; + payload_targetAddress?: string; + payload_targetAddresses?: Record[]; + payload_sourceTransaction?: string[]; + payload_validationType?: number; + payload_expiresOn?: Date; + payload_reconciled?: boolean; + payload_void?: boolean; + payload_collection?: string; + payload_unsoldMintingOptions?: string; + payload_newPrice?: number; + payload_collectionStorageDeposit?: number; + payload_nftsStorageDeposit?: number; + payload_aliasStorageDeposit?: number; + payload_nftsToMint?: number; + payload_transaction?: string; + payload_unlockedBy?: string; + payload_beneficiary?: string; + payload_beneficiaryUid?: string; + payload_beneficiaryAddress?: string; + payload_royaltiesFee?: number; + payload_royaltiesSpace?: string; + payload_royaltiesSpaceAddress?: string; + payload_chainReference?: string; + payload_nft?: string; + payload_restrictions?: Record; + payload_token?: string; + payload_quantity?: number; + payload_tokenSymbol?: string; + payload_unclaimedAirdrops?: number; + payload_totalAirdropCount?: number; + payload_tokenId?: string; + payload_foundryStorageDeposit?: number; + payload_vaultStorageDeposit?: number; + payload_guardianStorageDeposit?: number; + payload_tokensInVault?: number; + payload_orderId?: string; + payload_collectionOutputAmount?: number; + payload_aliasOutputAmount?: number; + payload_nftOutputAmount?: number; + payload_aliasId?: string; + payload_aliasBlockId?: string; + payload_aliasGovAddress?: string; + payload_collectionId?: string; + payload_nftId?: string; + payload_nativeTokens?: Record[]; + payload_previousOwnerEntity?: string; + payload_previousOwner?: string; + payload_ownerEntity?: string; + payload_owner?: string; + payload_royalty?: boolean; + payload_vestingAt?: Date; + payload_customMetadata?: Record; + payload_stake?: string; + payload_award?: string; + payload_legacyAwardFundRequestId?: string; + payload_legacyAwardsBeeingFunded?: number; + payload_weeks?: number; + payload_stakeType?: string; + payload_count?: number; + payload_price?: number; + payload_tokenReward?: number; + payload_edition?: number; + payload_participatedOn?: Date; + payload_proposalId?: string; + payload_voteValues?: number[]; + payload_storageDepositSourceAddress?: string; + payload_storageReturn?: Record; + payload_airdropId?: string; + payload_nfts?: string[]; + payload_tag?: string; + payload_metadata?: Record; + payload_response?: Record; + payload_reason?: string; + payload_invalidPayment?: boolean; + payload_outputToConsume?: string; + payload_dependsOnBillPayment?: boolean; + payload_milestoneTransactionPath?: string; + payload_tokenAmount?: number; + payload_weight?: number; + payload_weightMultiplier?: number; + payload_votes?: number[]; + payload_values?: number[]; + payload_creditId?: string; + payload_outputConsumed?: boolean; + payload_outputConsumedOn?: Date; + payload_stakes?: string[]; + payload_stakeReward?: string; + payload_tanglePuchase?: boolean; + payload_disableWithdraw?: boolean; + payload_lockCollectionNft?: boolean; + payload_stamp?: string; + payload_tokenTradeOderTargetAddress?: string; + payload_auction?: string; + payload_days?: number; + payload_dailyCost?: number; + payload_nftOrders?: Record[]; + payload_swap?: string; + payload_walletReference_createdOn?: Date; + payload_walletReference_processedOn?: Date; + payload_walletReference_chainReference?: string; + payload_walletReference_chainReferences?: string[]; + payload_walletReference_error?: string; + payload_walletReference_confirmed?: boolean; + payload_walletReference_confirmedOn?: Date; + payload_walletReference_milestoneTransactionPath?: string; + payload_walletReference_count?: number; + payload_walletReference_inProgress?: boolean; + payload_walletReference_nodeIndex?: number; + payload_outputId?: string; +} diff --git a/packages/database/src/pg/models/transaction_update.ts b/packages/database/src/pg/models/transaction_update.ts new file mode 100644 index 0000000000..98c6006e35 --- /dev/null +++ b/packages/database/src/pg/models/transaction_update.ts @@ -0,0 +1,134 @@ +/** + * This file was automatically generated by knex + * Do not modify this file manually + */ +import { ArrayRemove, ArrayUnion, Increment } from '../interfaces/common'; +import * as commons from './common_update'; + +export interface PgTransactionUpdate extends commons.BaseRecordUpdate { + network?: string | null; + type?: string | null; + isOrderType?: boolean | null; + member?: string | null; + space?: string | null; + shouldRetry?: boolean | null; + ignoreWallet?: boolean | null; + linkedTransactions?: string[] | null | ArrayUnion | ArrayRemove; + ignoreWalletReason?: string | null; + payload_type?: string | null; + payload_amount?: number | null | Increment; + payload_sourceAddress?: string | null; + payload_targetAddress?: string | null; + payload_targetAddresses?: string | null; + payload_sourceTransaction?: string[] | null | ArrayUnion | ArrayRemove; + payload_validationType?: number | null | Increment; + payload_expiresOn?: Date | null; + payload_reconciled?: boolean | null; + payload_void?: boolean | null; + payload_collection?: string | null; + payload_unsoldMintingOptions?: string | null; + payload_newPrice?: number | null | Increment; + payload_collectionStorageDeposit?: number | null | Increment; + payload_nftsStorageDeposit?: number | null | Increment; + payload_aliasStorageDeposit?: number | null | Increment; + payload_nftsToMint?: number | null | Increment; + payload_transaction?: string | null; + payload_unlockedBy?: string | null; + payload_beneficiary?: string | null; + payload_beneficiaryUid?: string | null; + payload_beneficiaryAddress?: string | null; + payload_royaltiesFee?: number | null | Increment; + payload_royaltiesSpace?: string | null; + payload_royaltiesSpaceAddress?: string | null; + payload_chainReference?: string | null; + payload_nft?: string | null; + payload_restrictions?: string | any | null; + payload_token?: string | null; + payload_quantity?: number | null | Increment; + payload_tokenSymbol?: string | null; + payload_unclaimedAirdrops?: number | null | Increment; + payload_totalAirdropCount?: number | null | Increment; + payload_tokenId?: string | null; + payload_foundryStorageDeposit?: number | null | Increment; + payload_vaultStorageDeposit?: number | null | Increment; + payload_guardianStorageDeposit?: number | null | Increment; + payload_tokensInVault?: number | null | Increment; + payload_orderId?: string | null; + payload_collectionOutputAmount?: number | null | Increment; + payload_aliasOutputAmount?: number | null | Increment; + payload_nftOutputAmount?: number | null | Increment; + payload_aliasId?: string | null; + payload_aliasBlockId?: string | null; + payload_aliasGovAddress?: string | null; + payload_collectionId?: string | null; + payload_nftId?: string | null; + payload_nativeTokens?: string | null; + payload_previousOwnerEntity?: string | null; + payload_previousOwner?: string | null; + payload_ownerEntity?: string | null; + payload_owner?: string | null; + payload_royalty?: boolean | null; + payload_vestingAt?: Date | null; + payload_customMetadata?: string | any | null; + payload_stake?: string | null; + payload_award?: string | null; + payload_legacyAwardFundRequestId?: string | null; + payload_legacyAwardsBeeingFunded?: number | null | Increment; + payload_weeks?: number | null | Increment; + payload_stakeType?: string | null; + payload_count?: number | null | Increment; + payload_price?: number | null | Increment; + payload_tokenReward?: number | null | Increment; + payload_edition?: number | null | Increment; + payload_participatedOn?: Date | null; + payload_proposalId?: string | null; + payload_voteValues?: number[] | null; + payload_storageDepositSourceAddress?: string | null; + payload_storageReturn?: string | any | null; + payload_airdropId?: string | null; + payload_nfts?: string[] | null | ArrayUnion | ArrayRemove; + payload_tag?: string | null; + payload_metadata?: string | any | null; + payload_response?: string | any | null; + payload_reason?: string | null; + payload_invalidPayment?: boolean | null; + payload_outputToConsume?: string | null; + payload_dependsOnBillPayment?: boolean | null; + payload_milestoneTransactionPath?: string | null; + payload_tokenAmount?: number | null | Increment; + payload_weight?: number | null | Increment; + payload_weightMultiplier?: number | null | Increment; + payload_votes?: number[] | null; + payload_values?: number[] | null; + payload_creditId?: string | null; + payload_outputConsumed?: boolean | null; + payload_outputConsumedOn?: Date | null; + payload_stakes?: string[] | null | ArrayUnion | ArrayRemove; + payload_stakeReward?: string | null; + payload_tanglePuchase?: boolean | null; + payload_disableWithdraw?: boolean | null; + payload_lockCollectionNft?: boolean | null; + payload_stamp?: string | null; + payload_tokenTradeOderTargetAddress?: string | null; + payload_auction?: string | null; + payload_days?: number | null | Increment; + payload_dailyCost?: number | null | Increment; + payload_nftOrders?: string | null; + payload_swap?: string | null; + payload_walletReference_createdOn?: Date | null; + payload_walletReference_processedOn?: Date | null; + payload_walletReference_chainReference?: string | null; + payload_walletReference_chainReferences?: + | string[] + | null + | ArrayUnion + | ArrayRemove; + payload_walletReference_error?: string | null; + payload_walletReference_confirmed?: boolean | null; + payload_walletReference_confirmedOn?: Date | null; + payload_walletReference_milestoneTransactionPath?: string | null; + payload_walletReference_count?: number | null | Increment; + payload_walletReference_inProgress?: boolean | null; + payload_walletReference_nodeIndex?: number | null | Increment; + payload_outputId?: string | null; +} diff --git a/packages/database/src/storage/build5Storage.ts b/packages/database/src/storage/build5Storage.ts index 01b7c2d600..0d05201814 100644 --- a/packages/database/src/storage/build5Storage.ts +++ b/packages/database/src/storage/build5Storage.ts @@ -1,5 +1,4 @@ -import { build5App } from '../app/build5App'; import { IStorage } from './interfaces'; import { FirebaseStorage } from './storage'; -export const build5Storage = (): IStorage => new FirebaseStorage(build5App); +export const build5Storage = (): IStorage => new FirebaseStorage(); diff --git a/packages/database/src/storage/storage.ts b/packages/database/src/storage/storage.ts index b649dfdaca..2fca44e5db 100644 --- a/packages/database/src/storage/storage.ts +++ b/packages/database/src/storage/storage.ts @@ -1,16 +1,11 @@ import { Bucket } from '@build-5/interfaces'; -import { Bucket as FBucket } from '@google-cloud/storage'; -import { Storage } from 'firebase-admin/storage'; -import { get } from 'lodash'; -import { FirebaseApp } from '../app/app'; +import { Bucket as FBucket, Storage } from '@google-cloud/storage'; import { IBucket, IStorage } from './interfaces'; export class FirebaseStorage implements IStorage { - private readonly storage: Storage; + private readonly storage = new Storage(); - constructor(private readonly app: FirebaseApp) { - this.storage = this.app.getInstance().storage(); - } + constructor() {} public bucket = (name: string) => new FirebaseBucket(this.storage, name as Bucket); } @@ -29,7 +24,8 @@ export class FirebaseBucket implements IBucket { public upload = async (path: string, destination: string, metadata: Record) => { const response = await this.bucket.upload(path, { destination, metadata }); - return get(response[1], 'mediaLink', ''); + const responseMetadata = response[0].metadata; + return responseMetadata.mediaLink!.replace(`generation=${responseMetadata.generation}&`, ''); }; public download = async (fileName: string, destination: string) => { diff --git a/packages/functions/.env b/packages/functions/.env index 18e81e3968..430e7f117b 100644 --- a/packages/functions/.env +++ b/packages/functions/.env @@ -1,11 +1,17 @@ -ENVIRONMENT=test -WEB3_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweEZCOTFiNTdEN2YzNmVhNjQ4NjQ3ODIyQjJGNGVEOEEyMDZCNERhNjQiLCJpc3MiOiJ3ZWIzLXN0b3JhZ2UiLCJpYXQiOjE2Njc0MDYzNzE3NDksIm5hbWUiOiJ0ZXN0IGRldiJ9.88vd8ZmeEle2Xqyc8uEMBOXJqDrFcxxF8gyHuXIjXgk +ENVIRONMENT="emulator" +WEB3_TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweEVFMjA3Qzk5YzA2NzkxMDg0QjU5NmU4NkEyMzVGNzFiNTc0NWNkMTIiLCJpc3MiOiJ3ZWIzLXN0b3JhZ2UiLCJpYXQiOjE2Njg0Njc4MDQ3NDAsIm5hbWUiOiJERVZfVE9LRU4ifQ.TB2AbWZDMk4WhWIeWKsdEKUReXUh0WUgcHAU5ccb4FA" NFT_STORAGE_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweDhiYjBGMDk4NzIzYTY5ODg1NTg3NTJCYWM0ODRlMTJCNGJlMGYxMDIiLCJpc3MiOiJuZnQtc3RvcmFnZSIsImlhdCI6MTcwNTUwMjkyMTEwMiwibmFtZSI6InNhbmRib3gifQ.a4TfMHsghXJjKQUO9zC9O0Wu_NGXVffDkw1E6-jr3hI -JWT_SECRET="asdas#@#@xdas31sad" -ALGOLIA_APPID=6MPUETJRDB -ALGOLIA_KEY=a75153c20ebe86d31e1fe5874f55dbac -ENCRYPTION_SALT=c4kWxCtNVQ5c2m -IP_INFO_TOKEN='' -XPTOKEN_ID=0x08fe43472f5968c4ccfa7154599e3d9c8df3f2e0b6396cafc2b038f15ee1974e050100000000 -XPTOKEN_UID=0xe71439be7001d2311658ded364e4043a284d16f4 -XPTOKEN_GUARDIANID=0x551fd2c7c7bf356bac194587dab2fcd46420054b \ No newline at end of file +JWT_SECRET="mysecret" +ALGOLIA_APPID="UZXKW1YS76" +ALGOLIA_KEY="8bf460848691fae9111b6159867d6bc1" +ENCRYPTION_SALT="sa#asda!2sasd##asad" +IP_INFO_TOKEN="" +XPTOKEN_ID="0x08f800d9e15c1da60c36cb0b2d4a02366ea3e200a65fc071a9e25f09b7fb9e951f0100000000" +XPTOKEN_UID="0xcef8ddcea97a5b82921d1cadbc8ccddcd69341da" +XPTOKEN_GUARDIANID="0x45f8379c44a73fc0ee6ad56acf51bd0f69240af5" + +DB_USER="postgres" +DB_USER_PWD="postgres" +DB_NAME="buildcore" +DB_HOST="localhost" +DB_PORT=5432 \ No newline at end of file diff --git a/packages/functions/.env.dev b/packages/functions/.env.dev deleted file mode 100644 index 2461f634e2..0000000000 --- a/packages/functions/.env.dev +++ /dev/null @@ -1,11 +0,0 @@ -ENVIRONMENT=dev -WEB3_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweEVFMjA3Qzk5YzA2NzkxMDg0QjU5NmU4NkEyMzVGNzFiNTc0NWNkMTIiLCJpc3MiOiJ3ZWIzLXN0b3JhZ2UiLCJpYXQiOjE2Njg0Njc4MDQ3NDAsIm5hbWUiOiJERVZfVE9LRU4ifQ.TB2AbWZDMk4WhWIeWKsdEKUReXUh0WUgcHAU5ccb4FA -NFT_STORAGE_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweDhiYjBGMDk4NzIzYTY5ODg1NTg3NTJCYWM0ODRlMTJCNGJlMGYxMDIiLCJpc3MiOiJuZnQtc3RvcmFnZSIsImlhdCI6MTcwNTUwMjkyMTEwMiwibmFtZSI6InNhbmRib3gifQ.a4TfMHsghXJjKQUO9zC9O0Wu_NGXVffDkw1E6-jr3hI -JWT_SECRET=mysecret -ALGOLIA_APPID=UZXKW1YS76 -ALGOLIA_KEY=8bf460848691fae9111b6159867d6bc1 -ENCRYPTION_SALT=sa#asda!2sasd##asad -IP_INFO_TOKEN='' -XPTOKEN_ID=0x08f800d9e15c1da60c36cb0b2d4a02366ea3e200a65fc071a9e25f09b7fb9e951f0100000000 -XPTOKEN_UID=0xcef8ddcea97a5b82921d1cadbc8ccddcd69341da -XPTOKEN_GUARDIANID=0x45f8379c44a73fc0ee6ad56acf51bd0f69240af5 \ No newline at end of file diff --git a/packages/functions/.env.local b/packages/functions/.env.local deleted file mode 100644 index b6a0ed52c3..0000000000 --- a/packages/functions/.env.local +++ /dev/null @@ -1,12 +0,0 @@ -FUNCTIONS_EMULATOR_TIMEOUT_SECONDS="540s" -ENVIRONMENT="emulator" -WEB3_TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweEVFMjA3Qzk5YzA2NzkxMDg0QjU5NmU4NkEyMzVGNzFiNTc0NWNkMTIiLCJpc3MiOiJ3ZWIzLXN0b3JhZ2UiLCJpYXQiOjE2Njg0Njc4MDQ3NDAsIm5hbWUiOiJERVZfVE9LRU4ifQ.TB2AbWZDMk4WhWIeWKsdEKUReXUh0WUgcHAU5ccb4FA" -NFT_STORAGE_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweDhiYjBGMDk4NzIzYTY5ODg1NTg3NTJCYWM0ODRlMTJCNGJlMGYxMDIiLCJpc3MiOiJuZnQtc3RvcmFnZSIsImlhdCI6MTcwNTUwMjkyMTEwMiwibmFtZSI6InNhbmRib3gifQ.a4TfMHsghXJjKQUO9zC9O0Wu_NGXVffDkw1E6-jr3hI -JWT_SECRET="mysecret" -ALGOLIA_APPID="UZXKW1YS76" -ALGOLIA_KEY="8bf460848691fae9111b6159867d6bc1" -ENCRYPTION_SALT="sa#asda!2sasd##asad" -IP_INFO_TOKEN="" -XPTOKEN_ID="0x08f800d9e15c1da60c36cb0b2d4a02366ea3e200a65fc071a9e25f09b7fb9e951f0100000000" -XPTOKEN_UID="0xcef8ddcea97a5b82921d1cadbc8ccddcd69341da" -XPTOKEN_GUARDIANID="0x45f8379c44a73fc0ee6ad56acf51bd0f69240af5" \ No newline at end of file diff --git a/packages/functions/.eslintrc.js b/packages/functions/.eslintrc.js index 44802784fa..20c4d0d988 100644 --- a/packages/functions/.eslintrc.js +++ b/packages/functions/.eslintrc.js @@ -41,14 +41,6 @@ module.exports = { '@typescript-eslint/prefer-enum-initializers': 2, '@typescript-eslint/member-delimiter-style': 2, // Disabled for now. - 'require-jsdoc': 0, // ["error", { - // "require": { - // "FunctionDeclaration": true, - // "MethodDefinition": true, - // "ClassDeclaration": true, - // "ArrowFunctionExpression": true, - // "FunctionExpression": true - // } - // }] + 'require-jsdoc': 0, }, }; diff --git a/packages/functions/.prettierignore b/packages/functions/.prettierignore index ee915e9294..13ae64b301 100644 --- a/packages/functions/.prettierignore +++ b/packages/functions/.prettierignore @@ -1,4 +1,6 @@ /coverage /lib /interfaces -/node_modules \ No newline at end of file +/node_modules +.env +sa.json \ No newline at end of file diff --git a/packages/functions/.runtimeconfig.json b/packages/functions/.runtimeconfig.json deleted file mode 100644 index b5eb4a1bb4..0000000000 --- a/packages/functions/.runtimeconfig.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "pinata": { - "key": "", - "secret": "" - }, - "nftstorage": { - "token": "" - }, - "encryption": { - "salt": "sa#asda!2sasd##asad" - }, - "environment": { - "type": "emulator" - }, - "ip_info": { - "token": "" - }, - "web3": { - "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweEVFMjA3Qzk5YzA2NzkxMDg0QjU5NmU4NkEyMzVGNzFiNTc0NWNkMTIiLCJpc3MiOiJ3ZWIzLXN0b3JhZ2UiLCJpYXQiOjE2Njg0Njc4MDQ3NDAsIm5hbWUiOiJERVZfVE9LRU4ifQ.TB2AbWZDMk4WhWIeWKsdEKUReXUh0WUgcHAU5ccb4FA" - }, - "jwt": { - "secret": "mysecret" - }, - "algolia": { - "appid": "UZXKW1YS76", - "key": "8bf460848691fae9111b6159867d6bc1" - }, - "xptoken": { - "id": "0x08f800d9e15c1da60c36cb0b2d4a02366ea3e200a65fc071a9e25f09b7fb9e951f0100000000", - "uid": "0xcef8ddcea97a5b82921d1cadbc8ccddcd69341da", - "guardianid": "0x45f8379c44a73fc0ee6ad56acf51bd0f69240af5" - } -} diff --git a/packages/functions/Dockerfile b/packages/functions/Dockerfile index 5e3514993c..87f8ba552a 100644 --- a/packages/functions/Dockerfile +++ b/packages/functions/Dockerfile @@ -6,10 +6,9 @@ COPY packages/database packages/database COPY packages/interfaces packages/interfaces COPY packages/functions packages/functions COPY package.json ./ -COPY data.proto ./ RUN npm run build:functions EXPOSE 8080 -CMD [ "node", "packages/functions/lib/index.express.js" ] +CMD [ "node", "packages/functions/lib/index.js" ] diff --git a/packages/functions/deploy.script.ts b/packages/functions/deploy.script.ts index 78cbf6e707..60c10d8bd8 100644 --- a/packages/functions/deploy.script.ts +++ b/packages/functions/deploy.script.ts @@ -9,7 +9,6 @@ import { ScheduledFunction } from './src/runtime/cron/scheduled'; import * as onRequests from './src/runtime/https/index'; import * as onStorage from './src/runtime/storage/index'; import * as onTriggers from './src/runtime/trigger/index'; -import { TriggeredFunction, TriggeredFunctionType } from './src/runtime/trigger/trigger'; const file = './deploy.sh'; @@ -27,29 +26,6 @@ const buildImage = () => { fs.appendFileSync(file, 'gcloud builds submit --tag gcr.io/$GOOGLE_CLOUD_PROJECT/functions\n\n'); }; -const indexCheck = () => { - fs.appendFileSync(file, 'check_indexes() {\n'); - fs.appendFileSync( - file, - ' indexes=$(gcloud firestore indexes composite list --format="table[box](state)")\n', - ); - fs.appendFileSync(file, ' if echo "$indexes" | grep -q "CREATING"; then\n'); - fs.appendFileSync(file, ' return 1\n'); - fs.appendFileSync(file, ' else\n'); - fs.appendFileSync(file, ' return 0\n'); - fs.appendFileSync(file, ' fi\n'); - fs.appendFileSync(file, '}\n'); - fs.appendFileSync(file, 'while true; do\n'); - fs.appendFileSync(file, ' if check_indexes; then\n'); - fs.appendFileSync(file, ' echo "No indexes are in CREATING state."\n'); - fs.appendFileSync(file, ' break\n'); - fs.appendFileSync(file, ' else\n'); - fs.appendFileSync(file, ' echo "Waiting for indexes to finish creating..."\n'); - fs.appendFileSync(file, ' sleep 5\n'); - fs.appendFileSync(file, ' fi\n'); - fs.appendFileSync(file, 'done\n\n'); -}; - const deployServices = () => { Object.entries({ ...flattenObject(onRequests), @@ -60,27 +36,28 @@ const deployServices = () => { const options = (value as CloudFunctions).runtimeOptions; let command = `gcloud run deploy ${name} \\ - --image gcr.io/$GOOGLE_CLOUD_PROJECT/functions \\ - --allow-unauthenticated \\ - --ingress=internal-and-cloud-load-balancing \\ -`; + --image gcr.io/$GOOGLE_CLOUD_PROJECT/functions \\ + --allow-unauthenticated \\ + --ingress=internal-and-cloud-load-balancing \\ + --add-cloudsql-instances $GOOGLE_CLOUD_PROJECT:us-central1:$GOOGLE_CLOUD_PROJECT \\ + `; if (options?.region) { - command += ` --region=${options.region} \\\n`; + command += ` --region=${options.region} \\\n`; } if (options?.timeoutSeconds) { - command += ` --timeout=${options.timeoutSeconds} \\\n`; + command += ` --timeout=${options.timeoutSeconds} \\\n`; } if (options?.concurrency) { - command += ` --concurrency=${options.concurrency} \\\n`; + command += ` --concurrency=${options.concurrency} \\\n`; } if (options?.memory) { - command += ` --memory=${options.memory.replace('B', '')} \\\n`; + command += ` --memory=${options.memory.replace('B', '')} \\\n`; } if (options?.minInstances) { - command += ` --min-instances=${options.minInstances} \\\n`; + command += ` --min-instances=${options.minInstances} \\\n`; } if (options?.cpu) { - command += ` --cpu=${options.cpu} \\\n`; + command += ` --cpu=${options.cpu} \\\n`; } fs.appendFileSync(file, command + ' &\n\n'); }); @@ -88,96 +65,79 @@ const deployServices = () => { fs.appendFileSync(file, 'wait\n\n'); }; -const deployStorageTriggers = () => { - Object.entries(flattenObject(onStorage)).forEach(([name, value]) => { - const options = (value as CloudFunctions).runtimeOptions; - const command = `if [ -z "$(gcloud eventarc triggers list --filter="name:${name}" --format="value(name)")" ]; then - gcloud eventarc triggers create ${name} \\ - --destination-run-service=${name} \\ - --destination-run-path="/${name}" \\ - --destination-run-region=${options.region} \\ - --location=us \\ - --event-filters="type=google.cloud.storage.object.v1.finalized" \\ - --event-filters="bucket=${options.bucket}" \\ - --service-account=$PROJECT_NUMBER-compute@developer.gserviceaccount.com\nfi &\n\n`; - fs.appendFileSync(file, command); - - const asyncUpdate = `gcloud eventarc triggers update ${name} \\ - --location=us --async --destination-run-region=${options.region}\n\n`; - fs.appendFileSync(file, asyncUpdate); - }); -}; +// const deployStorageTriggers = () => { +// Object.entries(flattenObject(onStorage)).forEach(([name, value]) => { +// const options = (value as CloudFunctions).runtimeOptions; +// const command = `if [ -z "$(gcloud eventarc triggers list --filter="name:${name}" --format="value(name)")" ]; then +// gcloud eventarc triggers create ${name} \\ +// --destination-run-service=${name} \\ +// --destination-run-path="/${name}" \\ +// --destination-run-region=${options.region} \\ +// --location=us-central1 \\ +// --event-filters="type=google.cloud.storage.object.v1.finalized" \\ +// --event-filters="bucket=${options.bucket}" \\ +// --service-account=$PROJECT_NUMBER-compute@developer.gserviceaccount.com\nfi &\n\n`; +// fs.appendFileSync(file, command); +// fs.appendFileSync(file, 'wait\n\n'); +// }); +// }; const deployFirestoreTriggers = () => { - const getTriggerType = (type: TriggeredFunctionType) => { - switch (type) { - case TriggeredFunctionType.ON_CREATE: - return 'google.cloud.firestore.document.v1.created'; - case TriggeredFunctionType.ON_UPDATE: - return 'google.cloud.firestore.document.v1.updated'; - case TriggeredFunctionType.ON_WRITE: - return 'google.cloud.firestore.document.v1.written'; - } - }; - + Object.entries(flattenObject(onTriggers)).forEach(([name]) => { + const command = `if ! gcloud pubsub topics list --format="value(name)" | grep -q "${name}"; then + gcloud pubsub topics create "${name}"\nfi &\n\n`; + fs.appendFileSync(file, command); + }); + fs.appendFileSync(file, 'wait\n\n'); Object.entries(flattenObject(onTriggers)).forEach(([name, value]) => { const options = (value as CloudFunctions).runtimeOptions; - const type = (value as TriggeredFunction).type; - const document = (value as TriggeredFunction).document; const command = `if [ -z "$(gcloud eventarc triggers list --filter="name:${name}" --format="value(name)")" ]; then - gcloud eventarc triggers create ${name} \\ - --location=nam5 \\ - --service-account=$PROJECT_NUMBER-compute@developer.gserviceaccount.com \\ - --destination-run-service=${name} \\ - --destination-run-region=${options.region} \\ - --destination-run-path="/${name}" \\ - --event-filters="database=(default)" \\ - --event-filters-path-pattern="document=${document}" \\ - --event-filters="namespace=(default)" \\ - --event-filters="type=${getTriggerType(type)}" \\ - --event-data-content-type="application/protobuf"\nfi &\n\n`; + gcloud eventarc triggers create ${name} \\ + --location=us-central1 \\ + --service-account=$PROJECT_NUMBER-compute@developer.gserviceaccount.com \\ + --destination-run-service=${name} \\ + --destination-run-region=${options.region} \\ + --destination-run-path="/${name}" \\ + --transport-topic=projects/$GOOGLE_CLOUD_PROJECT/topics/${name} \\ + --event-filters="type=google.cloud.pubsub.topic.v1.messagePublished"\nfi &\n\n`; fs.appendFileSync(file, command + ''); - - const asyncUpdate = `gcloud eventarc triggers update ${name} \\ - --location=nam5 --async --destination-run-region=${options.region}\n\n`; - fs.appendFileSync(file, asyncUpdate); }); + fs.appendFileSync(file, 'wait\n\n'); }; const deployCronTriggers = () => { Object.entries(flattenObject(onScheduled)).forEach(([name]) => { const command = `if ! gcloud pubsub topics list --format="value(name)" | grep -q "${name}"; then - gcloud pubsub topics create "${name}"\nfi\n\n`; + gcloud pubsub topics create "${name}"\nfi &\n\n`; fs.appendFileSync(file, command); }); + fs.appendFileSync(file, 'wait\n\n'); + Object.entries(flattenObject(onScheduled)).forEach(([name, value]) => { const options = (value as CloudFunctions).runtimeOptions; const command = `if [ -z "$(gcloud eventarc triggers list --filter="name:${name}" --format="value(name)")" ]; then - gcloud eventarc triggers create ${name} \\ - --location=us-central1 \\ - --service-account=$PROJECT_NUMBER-compute@developer.gserviceaccount.com \\ - --transport-topic=projects/$GOOGLE_CLOUD_PROJECT/topics/${name} \\ - --destination-run-service=${name} \\ - --destination-run-region=${options.region} \\ - --destination-run-path="/${name}" \\ - --event-filters="type=google.cloud.pubsub.topic.v1.messagePublished"\nfi &\n\n`; + gcloud eventarc triggers create ${name} \\ + --location=us-central1 \\ + --service-account=$PROJECT_NUMBER-compute@developer.gserviceaccount.com \\ + --transport-topic=projects/$GOOGLE_CLOUD_PROJECT/topics/${name} \\ + --destination-run-service=${name} \\ + --destination-run-region=${options.region} \\ + --destination-run-path="/${name}" \\ + --event-filters="type=google.cloud.pubsub.topic.v1.messagePublished"\nfi &\n\n`; fs.appendFileSync(file, command); - - const asyncUpdate = `gcloud eventarc triggers update ${name} \\ - --location=us-central1 --async --destination-run-region=${options.region}\n\n`; - fs.appendFileSync(file, asyncUpdate); }); fs.appendFileSync(file, 'wait\n\n'); Object.entries(flattenObject(onScheduled)).forEach(([name, value]) => { const schedule = (value as ScheduledFunction).schedule; - const command = `if [ -z "$(gcloud scheduler jobs list --filter="name:${name}" --format="value(name)")" ]; then - gcloud scheduler jobs create pubsub ${name} \\ - --schedule="${schedule}" \\ - --topic=projects/$GOOGLE_CLOUD_PROJECT/topics/${name} \\ - --message-body="{}"\nfi &\n\n`; + const command = `if [ -z "$(gcloud scheduler jobs list --location=us-central1 --filter="name:${name}" --format="value(name)")" ]; then + gcloud scheduler jobs create pubsub ${name} \\ + --schedule="${schedule}" \\ + --location=us-central1 \\ + --topic=projects/$GOOGLE_CLOUD_PROJECT/topics/${name} \\ + --message-body="{}"\nfi &\n\n`; fs.appendFileSync(file, command); }); @@ -192,16 +152,22 @@ const setMaxAckDeadline = () => { fs.appendFileSync(file, `do\n`); fs.appendFileSync( file, - ` gcloud pubsub subscriptions update $SUBSCRIPTION_NAME --ack-deadline=600 &\n`, + ` gcloud pubsub subscriptions update $SUBSCRIPTION_NAME --ack-deadline=600 --min-retry-delay=600 &\n`, ); fs.appendFileSync(file, `done\n`); fs.appendFileSync(file, `wait\n`); }; +const createUpsertTopic = () => { + const command = `if ! gcloud pubsub topics list --format="value(name)" | grep -q onupsert; then + gcloud pubsub topics create onupsert\nfi \n\n`; + fs.appendFileSync(file, command); +}; + buildImage(); -indexCheck(); deployServices(); -deployStorageTriggers(); +// deployStorageTriggers(); deployFirestoreTriggers(); deployCronTriggers(); +createUpsertTopic(); setMaxAckDeadline(); diff --git a/packages/functions/jest-setup.ts b/packages/functions/jest-setup.ts new file mode 100644 index 0000000000..9181757e99 --- /dev/null +++ b/packages/functions/jest-setup.ts @@ -0,0 +1,125 @@ +// eslint-disable-next-line @typescript-eslint/no-var-requires +require('dotenv').config({ path: __dirname + '/.env' }); +import { PgProjectAdmins, PgProjectUpdate, PgTokenUpdate, build5Db } from '@build-5/database'; +import { + Access, + COL, + MIN_IOTA_AMOUNT, + Network, + ProjectBilling, + SOON_PROJECT_ID, + SUB_COL, + TokenStatus, +} from '@build-5/interfaces'; +import initKnex from 'knex'; +import { createChangeTriggers } from './migration/create.triggers'; +import { createCompositeIndexes } from './migration/indexes/composit.indexes'; +import { createSingleFieldIndexes } from './migration/indexes/single.field.indexes'; + +const MEDIA = + 'https://images-wen.soonaverse.com/0x0275dfc7c2624c0111d441a0819dccfd5e947c89%2F6stvhnutvg%2Ftoken_introductionary'; +const SOON_PROJ_GUARDIAN = '0x3d5d0b3f40c9438871b1c43d6b70117eeff77ad8'; +const soonTokenId = '0xa381bfccaf121e38e31362d85b5ad30cd7fc0d06'; +const rmsTokenId = '0x52f27a34170900537acb61e5ff0fe94a2841ff52'; + +const knex = initKnex({ + client: 'pg', + connection: { + user: process.env.DB_USER, + password: process.env.DB_USER_PWD, + database: process.env.DB_NAME, + host: process.env.DB_HOST, + port: Number(process.env.DB_PORT), + }, + migrations: { + directory: '../database/migrations', + extension: 'ts', + }, +}); + +const setup = async () => { + await migrateSchema(); + + await build5Db() + .doc(COL.TOKEN, soonTokenId) + .upsert({ + project: SOON_PROJECT_ID, + uid: soonTokenId, + name: 'Soon token', + symbol: 'SOON', + } as PgTokenUpdate); + + await build5Db().doc(COL.TOKEN, rmsTokenId).upsert({ + project: SOON_PROJECT_ID, + symbol: 'RMS', + approved: true, + name: 'RMS token', + status: TokenStatus.BASE, + access: Access.OPEN, + icon: MEDIA, + mintingData_network: Network.RMS, + }); + + const soonProject: PgProjectUpdate = { + name: 'Soonaverse', + createdBy: SOON_PROJ_GUARDIAN, + deactivated: false, + config_billing: ProjectBilling.TOKEN_BASED, + config_tiers: [0, 0, 0, 0, 0].map((v) => v * MIN_IOTA_AMOUNT), + config_tokenTradingFeeDiscountPercentage: [0, 0, 0, 0, 0], + config_nativeTokenSymbol: 'SOON', + config_nativeTokenUid: soonTokenId, + otr: JSON.stringify({}), + }; + + const soonProjDocRef = build5Db().doc(COL.PROJECT, SOON_PROJECT_ID); + await soonProjDocRef.upsert(soonProject); + const adminDocRef = build5Db().doc( + COL.PROJECT, + SOON_PROJECT_ID, + SUB_COL.ADMINS, + SOON_PROJ_GUARDIAN, + ); + const admin: PgProjectAdmins = { + uid: SOON_PROJ_GUARDIAN, + project: SOON_PROJECT_ID, + parentId: SOON_PROJECT_ID, + }; + await adminDocRef.upsert(admin); + + await build5Db().destroy(); + await knex.destroy(); + console.log('Setup env'); +}; + +const migrateSchema = async () => { + await knex.migrate.latest(); + + await createChangeTriggers(knex); + await createSingleFieldIndexes(knex); + await createCompositeIndexes(knex); + + if (!(await knex.schema.hasTable('blocks'))) { + await knex.schema.createTable('blocks', (t) => { + t.timestamp('createdOn').defaultTo(knex.raw('CURRENT_TIMESTAMP')); + t.string('blockId').primary(); + }); + } + + await knex.raw(` + CREATE OR REPLACE FUNCTION block_func() RETURNS TRIGGER AS $$ + BEGIN + PERFORM pg_notify('blocks', NEW."blockId"); + RETURN NEW; + END; + $$ LANGUAGE plpgsql; + CREATE OR REPLACE TRIGGER block AFTER INSERT ON blocks + FOR EACH ROW EXECUTE FUNCTION block_func(); + `); + + await knex.raw(` + CREATE INDEX IF NOT EXISTS transaction_3997722307389455 ON transaction ("payload_sourceTransaction", uid); + `); +}; + +export default setup; diff --git a/packages/functions/jest.config.js b/packages/functions/jest.config.js index de54050089..73f2f312b9 100644 --- a/packages/functions/jest.config.js +++ b/packages/functions/jest.config.js @@ -2,8 +2,7 @@ module.exports = { preset: 'ts-jest', testEnvironment: 'node', testTimeout: 900000, - globalSetup: './test/set-up.ts', - globalTeardown: './test/teardown.ts', + globalSetup: './jest-setup.ts', reporters: ['default', 'github-actions'], setupFilesAfterEnv: ['./test/teardown.ts'], }; diff --git a/packages/functions/migration/create.triggers.ts b/packages/functions/migration/create.triggers.ts new file mode 100644 index 0000000000..305a040c57 --- /dev/null +++ b/packages/functions/migration/create.triggers.ts @@ -0,0 +1,57 @@ +import { Knex } from 'knex'; +import { flattenObject } from '../src/common'; +import * as triggers from '../src/runtime/trigger/index'; +import { TriggeredFunction, TriggeredFunctionType } from '../src/runtime/trigger/trigger'; + +export const createChangeTriggers = async (knex: Knex) => { + const promises = Object.entries(flattenObject(triggers)).map(async ([key, v]) => { + const trigger = v as TriggeredFunction; + const table = trigger.col + (trigger.subCol ? '_' + trigger.subCol : ''); + const opr = (type: TriggeredFunctionType) => { + switch (type) { + case TriggeredFunctionType.ON_CREATE: + return 'INSERT'; + case TriggeredFunctionType.ON_UPDATE: + return 'UPDATE'; + case TriggeredFunctionType.ON_WRITE: + return 'INSERT OR UPDATE '; + default: + throw Error('Invalid type: ' + type); + } + }; + + await knex.raw(` + CREATE OR REPLACE FUNCTION ${key}_func() RETURNS TRIGGER AS $$ + DECLARE + payload JSON; + subCol TEXT; + subColId TEXT; + generated_id INT; + BEGIN + subCol := '${trigger.subCol || null}'; + subColId := ${trigger.subCol ? 'NEW."parentId"' : null}; + + payload := json_build_object( + 'col', '${trigger.col}', + 'uid', NEW.uid, + 'subCol', subCol, + 'subColId', subColId, + 'prev', row_to_json(OLD), + 'curr', row_to_json(NEW) + ); + + INSERT INTO changes(change) + VALUES (payload) + RETURNING uid INTO generated_id; + + PERFORM pg_notify('trigger', '${key}' || ':' || generated_id::text); + RETURN NEW; + END; + $$ LANGUAGE plpgsql; + CREATE OR REPLACE TRIGGER ${key} AFTER ${opr(trigger.type)} ON ${table} + FOR EACH ROW EXECUTE FUNCTION ${key}_func(); + `); + }); + + await Promise.all(promises); +}; diff --git a/packages/functions/migration/index.ts b/packages/functions/migration/index.ts new file mode 100644 index 0000000000..39ebfabf61 --- /dev/null +++ b/packages/functions/migration/index.ts @@ -0,0 +1,35 @@ +/* eslint-disable import/namespace */ +/* eslint-disable @typescript-eslint/no-var-requires */ +import path from 'path'; +require('dotenv').config({ path: path.join(__dirname, '/../.env') }); + +import initKnex from 'knex'; +import { createChangeTriggers } from './create.triggers'; +import { createCompositeIndexes } from './indexes/composit.indexes'; +import { createSingleFieldIndexes } from './indexes/single.field.indexes'; + +const knex = initKnex({ + client: 'pg', + connection: { + user: 'postgres', + password: process.env.DB_USER_PWD, + database: 'buildcore', + host: '127.0.0.1', + }, + migrations: { + directory: '../database/migrations', + extension: 'ts', + }, +}); + +const migrate = async () => { + await knex.migrate.latest(); + + await createChangeTriggers(knex); + await createSingleFieldIndexes(knex); + await createCompositeIndexes(knex); + + await knex.destroy(); +}; + +migrate(); diff --git a/packages/functions/migration/indexes/composit.indexes.ts b/packages/functions/migration/indexes/composit.indexes.ts new file mode 100644 index 0000000000..fe3e1ad544 --- /dev/null +++ b/packages/functions/migration/indexes/composit.indexes.ts @@ -0,0 +1,50 @@ +import { Knex } from 'knex'; + +export const createCompositeIndexes = async (knex: Knex) => { + await knex.raw(` + CREATE INDEX IF NOT EXISTS + transaction_45109450510125404 + ON transaction + (type, "payload_walletReference_confirmed", "payload_walletReference_count", "payload_sourceAddress", "payload_storageDepositSourceAddress", "payload_aliasGovAddress", uid); + + CREATE INDEX IF NOT EXISTS stake_8122990901144977 ON stake ("expiresAt", "expirationProcessed", uid); + + CREATE INDEX IF NOT EXISTS auction_016830811329459072 ON auction ("auctionTo", active, uid); + + CREATE INDEX IF NOT EXISTS token_distribution_24062260178740802 ON token_distribution ("parentId", "totalDeposit", uid); + + CREATE INDEX IF NOT EXISTS token_market_05202804154440055 ON token_market (type, token, price, status, "createdOn", uid); + + CREATE INDEX IF NOT EXISTS airdrop_10766328113159873 ON airdrop (token, member, status, "vestingAt", uid); + + CREATE INDEX IF NOT EXISTS nft_stake_9374899382500212 ON nft_stake ("expiresAt", "expirationProcessed", uid); + + CREATE INDEX IF NOT EXISTS token_market_5085783731118316 ON token_market (status, "expiresAt", uid); + + CREATE INDEX IF NOT EXISTS proposal_47206329091177945 ON proposal (completed, "settings_endDate", uid); + + CREATE INDEX IF NOT EXISTS transaction_05013994603077765 ON transaction (type, "payload_sourceTransaction", uid); + + CREATE INDEX IF NOT EXISTS award_3008696163765725 ON award (completed, "endDate", uid); + + CREATE INDEX IF NOT EXISTS token_market_28978449906188053 ON token_market ("sourceNetwork", token, price, status, "createdOn", uid); + + CREATE INDEX IF NOT EXISTS nft_8290768562587871 ON nft (sold, locked, "placeholderNft", collection, position, uid); + + CREATE INDEX IF NOT EXISTS airdrop_30090768626374964 ON airdrop (token, member, status, "createdOn", uid); + + CREATE INDEX IF NOT EXISTS token_market_9362306629620307 ON token_market (token, status, price, uid); + + CREATE INDEX IF NOT EXISTS transaction_5731235900684764 ON transaction ("payload_walletReference_confirmed", "payload_walletReference_inProgress", "payload_walletReference_count", uid); + + CREATE INDEX IF NOT EXISTS stake_reward_7659187763841746 ON stake_reward (status, "endDate", uid); + + CREATE INDEX IF NOT EXISTS stamp_5834694438249675 ON stamp ("expiresAt", expired, uid); + + CREATE INDEX IF NOT EXISTS transaction_41816187111373495 ON transaction (member, type, "createdOn", uid); + + CREATE INDEX IF NOT EXISTS nft_41816187111373496 ON nft (collection, "availablePrice", "saleAccess", available); + + CREATE INDEX IF NOT EXISTS transaction_41816187111373494 ON "transaction" ("type", "payload_void", "payload_reconciled", "payload_expiresOn", "uid"); + `); +}; diff --git a/packages/functions/migration/indexes/single.field.indexes.ts b/packages/functions/migration/indexes/single.field.indexes.ts new file mode 100644 index 0000000000..dec44b17b9 --- /dev/null +++ b/packages/functions/migration/indexes/single.field.indexes.ts @@ -0,0 +1,61 @@ +import { Knex } from 'knex'; + +export const createSingleFieldIndexes = async (knex: Knex) => { + const columns = await knex + .withSchema('information_schema') + .table('columns') + .whereIn('table_schema', ['public']) + .whereNotIn('table_name', [ + 'knex_migrations', + 'knex_migrations_lock', + 'pg_stat_statements', + 'changes', + 'ticker', + ]) + .whereRaw(`"table_name" not like 'milestone%'`) + .orderBy('table_schema') + .orderBy('table_name', 'desc') + .orderBy('ordinal_position') + .select( + 'table_schema as schema', + 'table_name as table', + 'column_name as column', + knex.raw("(is_nullable = 'YES') as nullable"), + 'column_default as default', + 'data_type as type', + 'udt_name as udt', + ); + + const promises = columns.map(async ({ table, udt, column }) => { + if (column === 'uid' || !shouldCreateIndex(udt)) { + return; + } + await knex.raw(`CREATE INDEX IF NOT EXISTS ${table}_${column} on ${table} ("${column}");`); + }); + await Promise.all(promises); +}; + +const shouldCreateIndex = (fieldType: string) => { + switch (fieldType) { + case 'bool': + case 'numeric': + case 'int8': + case 'varchar': + case 'time': + case 'smallint': + case 'integer': + case 'int': + case 'int2': + case 'int4': + case 'real': + case 'float': + case 'float4': + case 'float8': + case 'date': + case 'timestamp': + case 'timestamptz': + return true; + default: + return false; + } +}; diff --git a/packages/functions/package.json b/packages/functions/package.json index b173ba7883..0c08cd1971 100644 --- a/packages/functions/package.json +++ b/packages/functions/package.json @@ -17,18 +17,15 @@ "scripts": { "lint": "eslint --ext .js,.ts src", "build": "tsc && cp .env lib/.env", - "emulators": "tsc --watch & firebase -c ../../firebase.json emulators:start --only functions,firestore,storage,ui,auth", - "milestone-sync": "npx ts-node ./test/milestone.sync.ts", - "serve": "run-p \"milestone-sync\" \"emulators\" ", - "test": "export LOCAL_TEST=true && jest --runInBand", - "test-tangle": "export LOCAL_TEST=true && jest test-tangle/ --runInBand ", - "test:ci": "export LOCAL_TEST=true && jest test/ --runInBand --ci --config=jest.config.ci.js", - "test-tangle:ci": "export LOCAL_TEST=true && jest test-tangle/ --runInBand --ci --config=jest.config.ci.js", - "export-online-test-credentials": "export GOOGLE_APPLICATION_CREDENTIALS=\"./test-service-account-key.json\"", - "test-online:ci": "npm run export-online-test-credentials && jest test/ --runInBand --ci --config=jest.config.ci.js", - "test-tangle-online:ci": "npm run export-online-test-credentials && jest test-tangle/ --runInBand --ci --config=jest.config.ci.js" + "start": "export GOOGLE_APPLICATION_CREDENTIALS=\"./sa.json\" && node lib/index.js", + "build-start": "npm run build && npm run start", + "notifier": "export GOOGLE_APPLICATION_CREDENTIALS=\"./sa.json\" && npx ts-node ./test/notifier.ts", + "serve": "run-p \"build-start\" \"notifier\"", + "test": "export GOOGLE_APPLICATION_CREDENTIALS=\"./sa.json\" && jest", + "migrate": "export GOOGLE_APPLICATION_CREDENTIALS=\"./sa.json\" && ts-node ./migration/index.ts" }, "devDependencies": { + "@google-cloud/pubsub": "4.3.3", "@types/busboy": "1.5.3", "@types/chai": "4.3.11", "@types/chance": "1.1.6", @@ -55,10 +52,8 @@ "eslint-plugin-jsdoc": "48.1.0", "eslint-plugin-prefer-arrow": "1.2.3", "eslint-plugin-prettier": "5.1.3", - "firebase-functions-test": "3.1.1", "glob": "8.0.3", "jest": "29.7.0", - "jest-junit": "16.0.0", "prettier": "3.2.5", "prettier-eslint": "16.3.0", "ts-jest": "29.1.2", @@ -79,20 +74,18 @@ "@iota/util.js": "1.8.6", "@iota/util.js-next": "npm:@iota/util.js@2.0.0-rc.2", "@metamask/eth-sig-util": "7.0.1", + "@types/express": "4.17.21", "algoliasearch": "4.22.1", "axios": "1.6.7", "bip39": "3.1.0", "busboy": "1.6.0", "child-process-promise": "2.2.1", - "cloudevents": "8.0.0", "cors": "2.8.5", "crypto-js": "4.2.0", "dayjs": "1.11.10", "ethers": "6.11.1", + "express": "4.19.2", "files-from-path": "^1.0.4", - "firebase-admin": "12.0.0", - "firebase-functions": "4.7.0", - "interfaces": "0.0.3", "is-ipfs": "8.0.4", "joi": "17.12.1", "js-big-decimal": "2.0.7", @@ -101,8 +94,6 @@ "mime-types": "2.1.35", "nft.storage": "7.1.1", "node-ipinfo": "3.5.1", - "protobufjs": "7.2.6", - "rxjs": "7.8.1", "sharp": "0.33.2" } } diff --git a/packages/functions/sa.json b/packages/functions/sa.json new file mode 100644 index 0000000000..7e6ad82a2b --- /dev/null +++ b/packages/functions/sa.json @@ -0,0 +1,13 @@ +{ + "type": "service_account", + "project_id": "buildcore-test", + "private_key_id": "12da966f1c3fcb1e3dfb03db1cf94897847b4b79", + "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCrPoyWQ/HXORFh\nJ122n/ce3mvcTNA1R8qv/oNSaMTP1gtYIpxIRFvpWZpJ+jrmk86qw4V2YShEfbnG\n7ibu5P1690WAbuhFWNBEKxZty/BapZdYB7DYzEsNuw9jZ1AmniYp2gJ5eDDR58rI\n5OfyZjZhHCw6yyg9xGENuQBQKG1NbJX0KfK8AaSgVypjzCaLOoo+no19wplcdVjc\n6WmkuEkIy+aT9sjv5m1Wax/8UvFWejNk5K7HobbptHbCSHuRurhS+sIKqBPNHCtx\nI+ohkc9A6MDeZVBeVBxZeijdSeSO5FtiBZ2tOjBWnZGTn2Oj174eGxJeNGEOag4A\nJYEJt7RvAgMBAAECggEAAOhee3sBy8eB3HI9SlKOyKp5ZhwNu9qrd6LlaSkIWFHq\nR7MM0wGuYK0K/weVXJBDoRQUCtz9lhK6//DEMpjYEdjmsQpFCqrGJFsJDEAjHgjS\nhjBaA3YLQ56OZyz/RQ6Wd8h9+hl2nK4DuxKnpgl66I65Q0tgCDzFSaeteDv6J/qQ\n3TZ6pS8QQb95XcLVby44GA0tJJflted9nE7W8qnjLLxtk1j0m16AQcQ4+T8pPweP\nlfovVsCugYLqZvP1wmNEYbrJ8slKvs5iM60+zl/dgXtKxUSi8SZe5n1GlJmcywds\nbRLArjNlyryrzpjS/5uLTlg28SRobG1StfxYv9nouQKBgQDgaBAdRkmToiZPxFEU\ned9pNHCXZ8ejxTSmLbODsobmOfObDyNieF3nmrZ2g7kjUx3E9gUn+sbSrU6Pfghs\nW0vRgj99NQXvOLAImaiJAM10DRqsJf9BPX9K1+r812lDrilqMV2kfSkP25M6AU8c\nwnHgmT1VL2AcZQAWHZ0EeXLiyQKBgQDDWnHEol2Dt1xXEtnS/dpSSXoIoZYNZoOs\nAREI9mzENBV3OdJgVkNIHdf/MuALRKo0E6byTOs6vwN9duO3+ny6kCqu8jTXlWAY\nWJwJlVIvfv9NsC3SA7ZBfqKI1u4bJzsGh7e4tNq/RKsMYh/cSjtdE7Y09uE9l1Dj\nJvkvPEGBdwKBgQCrZO/B3DhACR2n2PJwaDEJwmKoUTx6yhlPPyKX2NgNqX91E9fb\n0sEuLs1jsXHLGCVplNoVUgVfTbzt/b3jPMuoxglF0SSqNKrGts2xbip9k7CmgRL3\nOkgp2sYAvWoJplC9adzy0CF3miZVrEBHX//oIkJk+J04sq+hNJcDntrveQKBgCq/\nbufNc9Mv25f+OwYtoImjJH4hBdnW1fdcoGKqsfBZSV02nO+R0NVGGo7wjhBJLUmK\nB108MblANT5ONtR6jrKwe3ae76tBN678LOD3+O0FyE4ywEQVpds9H8n75kywz/zE\n1BIqGTgDib6C9l/ZKpZaiuOaJn24z+11CNAqSldPAoGAPJ9Mm0pkn054f0sHmdui\nCT4kDkTlV3EAAW2bt7tI+KnnYbEQuP0x67ZIAbE61s/j5gxuZ/oZ8JM/70N0HKFo\nR02bM+l8M84RwJVK25qQEK19FpwcfLUkBiX8e3JRkLEyMVFx1ECmNzudmw40lHYc\nApHpvyNHDQXmKaUcSNxjBFY=\n-----END PRIVATE KEY-----\n", + "client_email": "643550321681-compute@developer.gserviceaccount.com", + "client_id": "103930549623534475229", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://oauth2.googleapis.com/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/643550321681-compute%40developer.gserviceaccount.com", + "universe_domain": "googleapis.com" +} diff --git a/packages/functions/scripts/db.upgrade.ts b/packages/functions/scripts/db.upgrade.ts index bd2fff49c6..3b0746b365 100644 --- a/packages/functions/scripts/db.upgrade.ts +++ b/packages/functions/scripts/db.upgrade.ts @@ -1,3 +1,4 @@ +import { FirebaseApp } from '@build-5/database'; import { COL } from '@build-5/interfaces'; import crypto from 'crypto'; import dotenv from 'dotenv'; @@ -5,7 +6,6 @@ import admin from 'firebase-admin'; import { getFirestore } from 'firebase-admin/firestore'; import fs from 'fs'; import { glob } from 'glob'; -import { FirebaseApp } from '@build-5/database'; import serviceAccount from './serviceAccountKey.json'; dotenv.config({ path: '../.env' }); diff --git a/packages/functions/scripts/dbUpgrades/2.1/soon.snapshot.ts b/packages/functions/scripts/dbUpgrades/2.1/soon.snapshot.ts deleted file mode 100644 index 34e15d6bd7..0000000000 --- a/packages/functions/scripts/dbUpgrades/2.1/soon.snapshot.ts +++ /dev/null @@ -1,235 +0,0 @@ -import { FirebaseApp } from '@build-5/database'; -import { COL, Network, SUB_COL, TokenDrop, TokenDropStatus } from '@build-5/interfaces'; -import { - Address, - AddressType, - AddressUnlockCondition, - AliasAddress, - AliasOutput, - BasicOutput, - Ed25519Address, - GovernorAddressUnlockCondition, - InputType, - NftAddress, - NftOutput, - OutputType, - RegularTransactionEssence, - StateControllerAddressUnlockCondition, - TransactionPayload, - UTXOInput, - UnlockConditionType, - Utils, -} from '@iota/sdk'; -import dayjs from 'dayjs'; -import admin from 'firebase-admin'; -import { chunk, flatMap, head, last } from 'lodash'; - -const consumedOutputs: Set = new Set(); - -const limit = 1000; - -let tokensPerAddress: { [key: string]: number } = {}; - -let SOON_TOKEN_ID = - '0x0884298fe9b82504d26ddb873dbd234a344c120da3a4317d8063dbcf96d356aa9d0100000000'; -let NETWORK: Network.SMR | Network.RMS = Network.SMR; -let MILESTONE_COL = COL.MILESTONE_SMR; -let MIN_MILESTONE = 125439; - -export const soonSnapshot = async ( - app: FirebaseApp, - tokenId?: string, - network?: Network.SMR | Network.RMS, -) => { - SOON_TOKEN_ID = tokenId === undefined ? SOON_TOKEN_ID : tokenId; - NETWORK = network === undefined ? NETWORK : network; - MILESTONE_COL = NETWORK === Network.SMR ? COL.MILESTONE_SMR : COL.MILESTONE_RMS; - tokensPerAddress = {}; - - const instance = app.getInstance() as admin.app.App; - const firestore = instance.firestore(); - - const tokensPerMember = await createSoonSnapshot(firestore); - - const chunks = chunk(Object.entries(tokensPerMember), 500); - for (const chunk of chunks) { - const batch = firestore.batch(); - - for (const [address, count] of chunk) { - const docRef = firestore.doc(`${COL.SOON_SNAP}/${address}`); - batch.set(docRef, { - uid: address, - createdOn: dayjs().toDate(), - - count, - paidOut: 0, - - ethAddress: address.startsWith('0x') ? address : '', - ethAddressVerified: false, - }); - } - - await batch.commit(); - } - - return tokensPerMember; -}; - -const createSoonSnapshot = async (db: admin.firestore.Firestore) => { - let lastDoc: any = undefined; - - do { - let query = db.collection(MILESTONE_COL).orderBy('createdOn', 'desc').limit(limit); - if (lastDoc) { - query = query.startAfter(lastDoc); - } - - const milestoneSnapshot = await query.get(); - lastDoc = last(milestoneSnapshot.docs); - - const milestones = milestoneSnapshot.docs.map((d) => d.id); - const transactions = await getTransactions(db, milestones); - - for (const transaction of transactions) { - const payload = transaction.payload as TransactionPayload; - const essence = payload.essence as RegularTransactionEssence; - - updateConsumedOutputs(essence); - await processTransactions(payload); - } - } while (lastDoc && Number(lastDoc.data().milestone) > MIN_MILESTONE); - - const promises = Object.entries(tokensPerAddress).map((act) => - addressToMember(db, act[0], act[1]), - ); - - return (await Promise.all(promises)).reduce( - (acc, act) => { - Object.entries(act).forEach(([key, value]) => { - acc[key] = (acc[key] || 0) + value; - }); - return acc; - }, - {} as { [key: string]: number }, - ); -}; - -const addressToMember = async (db: admin.firestore.Firestore, address: string, count: number) => { - const tokensPerMember: { [key: string]: number } = {}; - const airdropsSnap = await db - .collection(COL.AIRDROP) - .where('sourceAddress', '==', address) - .where('status', '==', TokenDropStatus.UNCLAIMED) - .get(); - - for (const doc of airdropsSnap.docs) { - const airdrop = doc.data() as TokenDrop; - - const memberSnap = await db - .collection(COL.MEMBER) - .where(`validatedAddress.${NETWORK}`, '==', airdrop.member) - .limit(1) - .get(); - const memberAddress = - head(memberSnap.docs)?.data().validatedAddress?.[NETWORK] || airdrop.member; - - tokensPerMember[memberAddress] = (tokensPerMember[memberAddress] || 0) + airdrop.count; - } - - if (airdropsSnap.size) { - return tokensPerMember; - } - - const memberSnap = await db - .collection(COL.MEMBER) - .where(`validatedAddress.${NETWORK}`, '==', address) - .get(); - const memberAddress = head(memberSnap.docs)?.data().validatedAddress?.[NETWORK] || address; - tokensPerMember[memberAddress] = (tokensPerMember[memberAddress] || 0) + count; - - return tokensPerMember; -}; - -const getTransactions = async (db: admin.firestore.Firestore, milestones: string[]) => { - const promises = milestones.map(async (milestone) => { - const snap = await db - .collection(MILESTONE_COL) - .doc(milestone) - .collection(SUB_COL.TRANSACTIONS) - .get(); - return snap.docs.map((d) => d.data()); - }); - return flatMap(await Promise.all(promises)); -}; - -const processTransactions = async (payload: TransactionPayload) => { - const essence = payload.essence as RegularTransactionEssence; - - const outputs = essence.outputs.filter( - (o, i) => - [OutputType.Alias, OutputType.Basic, OutputType.Nft].includes(o.type) && - !consumedOutputs.has(Utils.computeOutputId(Utils.transactionId(payload), i)), - ); - - for (const output of outputs) { - const result = getAddressAndSoons(output as AliasOutput | BasicOutput | NftOutput); - if (result.tokens) { - tokensPerAddress[result.address] = (tokensPerAddress[result.address] || 0) + result.tokens; - } - } -}; - -const updateConsumedOutputs = (essence: RegularTransactionEssence) => { - for (const input of essence.inputs) { - if (input.type === InputType.UTXO) { - const i = input as UTXOInput; - consumedOutputs.add(Utils.computeOutputId(i.transactionId, i.transactionOutputIndex)); - } - } -}; - -const getAddressAndSoons = (output: AliasOutput | BasicOutput | NftOutput) => { - const soonTokens = getSoonTokenCount(output); - if (!soonTokens) { - return { tokens: 0, address: '' }; - } - const address = bech32FromUnlockConditions(output, NETWORK); - return { tokens: soonTokens, address }; -}; - -const getSoonTokenCount = (output: BasicOutput | AliasOutput | NftOutput) => - (output.nativeTokens || []) - .filter((nt) => nt.id === SOON_TOKEN_ID) - .reduce((acc, act) => acc + Number(act.amount), 0); - -const bech32FromUnlockConditions = (output: BasicOutput, hrp: string) => - addressToBech32(getUnlockCondition(output)?.address, hrp); - -const getUnlockCondition = (output: AliasOutput | BasicOutput | NftOutput) => { - if (output.type === OutputType.Basic || output.type === OutputType.Nft) { - return output.unlockConditions.find( - (c) => c.type === UnlockConditionType.Address, - ) as AddressUnlockCondition; - } - - const condition = output.unlockConditions.find( - (c) => c.type === UnlockConditionType.GovernorAddress, - ) as GovernorAddressUnlockCondition; - return (condition || - output.unlockConditions.find( - (c) => c.type === UnlockConditionType.StateControllerAddress, - )) as StateControllerAddressUnlockCondition; -}; - -const addressToBech32 = (address: Address, hrp: string) => { - switch (address.type) { - case AddressType.Ed25519: - return Utils.hexToBech32((address as Ed25519Address).pubKeyHash, hrp); - case AddressType.Alias: - return Utils.aliasIdToBech32((address as AliasAddress).aliasId, hrp); - case AddressType.Nft: - return Utils.aliasIdToBech32((address as NftAddress).nftId, hrp); - } -}; - -export const roll = soonSnapshot; diff --git a/packages/functions/scripts/dummyTransfer.ts b/packages/functions/scripts/dummyTransfer.ts index 5479cb88e4..a532879c08 100644 --- a/packages/functions/scripts/dummyTransfer.ts +++ b/packages/functions/scripts/dummyTransfer.ts @@ -1,16 +1,16 @@ import { Bip32Path } from '@iota/crypto.js'; import { Bech32Helper, + ED25519_ADDRESS_TYPE, Ed25519Address, Ed25519Seed, - ED25519_ADDRESS_TYPE, IKeyPair, ISigLockedSingleOutput, IUTXOInput, - sendAdvanced, SIG_LOCKED_SINGLE_OUTPUT_TYPE, SingleNodeClient, UTXO_INPUT_TYPE, + sendAdvanced, } from '@iota/iota.js'; import { Converter } from '@iota/util.js'; import { generateMnemonic } from 'bip39'; diff --git a/packages/functions/scripts/duplicatePurchases.ts b/packages/functions/scripts/duplicatePurchases.ts index 7b953a1a7e..0d14cba798 100644 --- a/packages/functions/scripts/duplicatePurchases.ts +++ b/packages/functions/scripts/duplicatePurchases.ts @@ -10,7 +10,7 @@ const db = getFirestore(); const nfts: any = {}; db.collection('transaction') .where('type', '==', 'BILL_PAYMENT') - .where('payload.royalty', '==', false) + .where('payload_royalty', '==', false) .get() .then(async (ss) => { for (const t of ss.docs) { diff --git a/packages/functions/scripts/manualRefund.ts b/packages/functions/scripts/manualRefund.ts index 158ac5b67c..edcdcc851b 100644 --- a/packages/functions/scripts/manualRefund.ts +++ b/packages/functions/scripts/manualRefund.ts @@ -31,7 +31,7 @@ db.collection(COL.MEMBER) await db .collection(COL.TRANSACTION) .doc(tranId) - .set({ + .upsert({ project: SOON_PROJECT_ID, type: TransactionType.CREDIT, uid: tranId, diff --git a/packages/functions/scripts/nullPayments.ts b/packages/functions/scripts/nullPayments.ts index 8dff8e116e..144ba08843 100644 --- a/packages/functions/scripts/nullPayments.ts +++ b/packages/functions/scripts/nullPayments.ts @@ -9,8 +9,8 @@ initializeApp({ const db = getFirestore(); db.collection('transaction') - .where('payload.walletReference.chainReference', '==', null) - .where('payload.walletReference.error', '==', 'Error: You must specify some inputs') + .where('payload_walletReference.chainReference', '==', null) + .where('payload_walletReference.error', '==', 'Error: You must specify some inputs') .get() .then(async (ss) => { for (const t of ss.docs) { diff --git a/packages/functions/scripts/retryPayment.ts b/packages/functions/scripts/retryPayment.ts index 754d926f2f..fa6c0e3355 100644 --- a/packages/functions/scripts/retryPayment.ts +++ b/packages/functions/scripts/retryPayment.ts @@ -9,8 +9,8 @@ initializeApp({ const db = getFirestore(); db.collection('transaction') - .where('payload.walletReference.confirmed', '==', false) - .where('payload.walletReference.count', '<=', 4) + .where('payload_walletReference.confirmed', '==', false) + .where('payload_walletReference.count', '<=', 4) .orderBy('payload.walletReference.count', 'asc') .limit(10000) .get() diff --git a/packages/functions/src/controls/address/address.control.ts b/packages/functions/src/controls/address/address.control.ts index ca55e5a18c..e505f46127 100644 --- a/packages/functions/src/controls/address/address.control.ts +++ b/packages/functions/src/controls/address/address.control.ts @@ -3,7 +3,6 @@ import { AddressValidationRequest, COL, DEFAULT_NETWORK, - Member, Network, Transaction, WenError, @@ -18,14 +17,15 @@ export const validateAddressControl = async ({ project, }: Context): Promise => { const network = (params.network as Network) || DEFAULT_NETWORK; - const member = await build5Db().doc(`${COL.MEMBER}/${owner}`).get(); + const memberDocRef = build5Db().doc(COL.MEMBER, owner); + const member = await memberDocRef.get(); if (!member) { throw invalidArgument(WenError.member_does_not_exists); } - const order = await createAddressValidationOrder(project, member.uid, network, params.space); - await build5Db().doc(`${COL.TRANSACTION}/${order.uid}`).create(order); + const order = await createAddressValidationOrder(project, owner, network, params.space); + await build5Db().doc(COL.TRANSACTION, order.uid).create(order); return order; }; diff --git a/packages/functions/src/controls/auction/auction.control.ts b/packages/functions/src/controls/auction/auction.control.ts index ef523e6992..a95dbdcc4f 100644 --- a/packages/functions/src/controls/auction/auction.control.ts +++ b/packages/functions/src/controls/auction/auction.control.ts @@ -10,7 +10,7 @@ export const auctionBidControl = async ({ params, project, }: Context): Promise => { - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${owner}`); + const memberDocRef = build5Db().doc(COL.MEMBER, owner); const member = await memberDocRef.get(); if (!member) { throw invalidArgument(WenError.member_does_not_exists); @@ -18,8 +18,8 @@ export const auctionBidControl = async ({ const bidTransaction = await createBidOrder(project, owner, params.auction, ip); - const transactionDocRef = build5Db().doc(`${COL.TRANSACTION}/${bidTransaction.uid}`); + const transactionDocRef = build5Db().doc(COL.TRANSACTION, bidTransaction.uid); await transactionDocRef.create(bidTransaction); - return (await transactionDocRef.get())!; + 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 index 8341d08f29..254222d18d 100644 --- a/packages/functions/src/controls/auction/auction.create.control.ts +++ b/packages/functions/src/controls/auction/auction.create.control.ts @@ -1,5 +1,5 @@ import { build5Db } from '@build-5/database'; -import { Auction, AuctionCreateRequest, COL, Member, WenError } from '@build-5/interfaces'; +import { Auction, AuctionCreateRequest, COL, WenError } from '@build-5/interfaces'; import { getAuctionData } from '../../services/payment/tangle-service/auction/auction.create.service'; import { invalidArgument } from '../../utils/error.utils'; import { assertIsSpaceMember } from '../../utils/space.utils'; @@ -10,8 +10,8 @@ export const auctionCreateControl = async ({ project, params, }: Context) => { - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${owner}`); - const member = await memberDocRef.get(); + const memberDocRef = build5Db().doc(COL.MEMBER, owner); + const member = await memberDocRef.get(); if (!member) { throw invalidArgument(WenError.member_does_not_exists); } @@ -19,7 +19,7 @@ export const auctionCreateControl = async ({ await assertIsSpaceMember(params.space, owner); const auction = getAuctionData(project, member, params); - const auctionDocRef = build5Db().doc(`${COL.AUCTION}/${auction.uid}`); + const auctionDocRef = build5Db().doc(COL.AUCTION, auction.uid); await auctionDocRef.create(auction); return await auctionDocRef.get(); diff --git a/packages/functions/src/controls/award/award.approve.participant.ts b/packages/functions/src/controls/award/award.approve.participant.ts index 748be5c0b7..e986ef5eb0 100644 --- a/packages/functions/src/controls/award/award.approve.participant.ts +++ b/packages/functions/src/controls/award/award.approve.participant.ts @@ -28,8 +28,8 @@ export const approveAwardParticipantControl = async ({ // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (error: any) { errors[member] = { - code: get(error, 'details.code', 0), - message: get(error, 'details.key', ''), + code: get(error, 'eCode', 0), + message: get(error, 'eKey', ''), }; } } diff --git a/packages/functions/src/controls/award/award.cancel.ts b/packages/functions/src/controls/award/award.cancel.ts index dd3832cdb4..6aa7c95b0e 100644 --- a/packages/functions/src/controls/award/award.cancel.ts +++ b/packages/functions/src/controls/award/award.cancel.ts @@ -10,8 +10,8 @@ export const cancelAwardControl = ({ params, }: Context): Promise => build5Db().runTransaction(async (transaction) => { - const awardDocRef = build5Db().doc(`${COL.AWARD}/${params.uid}`); - const award = await transaction.get(awardDocRef); + const awardDocRef = build5Db().doc(COL.AWARD, params.uid); + const award = await transaction.get(awardDocRef); if (!award) { throw invalidArgument(WenError.award_does_not_exists); @@ -26,7 +26,7 @@ export const cancelAwardControl = ({ await assertIsGuardian(award.space, owner); const data = { uid: award.uid, completed: true }; - transaction.update(awardDocRef, data); + await transaction.update(awardDocRef, data); return { ...award, ...data }; }); diff --git a/packages/functions/src/controls/award/award.create.ts b/packages/functions/src/controls/award/award.create.ts index 7a3291aff3..35df70cf96 100644 --- a/packages/functions/src/controls/award/award.create.ts +++ b/packages/functions/src/controls/award/award.create.ts @@ -1,5 +1,5 @@ import { build5Db } from '@build-5/database'; -import { Award, AwardCreateRequest, COL, SUB_COL } from '@build-5/interfaces'; +import { AwardCreateRequest, COL, SUB_COL } from '@build-5/interfaces'; import { createAward } from '../../services/payment/tangle-service/award/award.create.service'; import { Context } from '../common'; @@ -12,13 +12,13 @@ export const createAwardControl = async ({ const batch = build5Db().batch(); - const awardDocRef = build5Db().doc(`${COL.AWARD}/${award.uid}`); + const awardDocRef = build5Db().doc(COL.AWARD, award.uid); batch.create(awardDocRef, award); - const ownerDocRef = awardDocRef.collection(SUB_COL.OWNERS).doc(owner); + const ownerDocRef = build5Db().doc(COL.AWARD, award.uid, SUB_COL.OWNERS, owner); batch.create(ownerDocRef, awardOwner); await batch.commit(); - return await awardDocRef.get(); + return await awardDocRef.get(); }; diff --git a/packages/functions/src/controls/award/award.fund.ts b/packages/functions/src/controls/award/award.fund.ts index d770f23788..4d6c761ed4 100644 --- a/packages/functions/src/controls/award/award.fund.ts +++ b/packages/functions/src/controls/award/award.fund.ts @@ -14,7 +14,7 @@ export const fundAwardControl = async ({ const award = await getAwardForFunding(owner, params.uid); const order = await createAwardFundOrder(project, owner, award); - await build5Db().doc(`${COL.TRANSACTION}/${order.uid}`).create(order); + await build5Db().doc(COL.TRANSACTION, order.uid).create(order); return order; }; diff --git a/packages/functions/src/controls/award/award.owner.ts b/packages/functions/src/controls/award/award.owner.ts index d9bc2c5d73..5f70366daf 100644 --- a/packages/functions/src/controls/award/award.owner.ts +++ b/packages/functions/src/controls/award/award.owner.ts @@ -1,12 +1,5 @@ import { build5Db } from '@build-5/database'; -import { - Award, - AwardAddOwnerRequest, - AwardOwner, - COL, - SUB_COL, - WenError, -} from '@build-5/interfaces'; +import { AwardAddOwnerRequest, AwardOwner, COL, SUB_COL, WenError } from '@build-5/interfaces'; import dayjs from 'dayjs'; import { dateToTimestamp } from '../../utils/dateTime.utils'; import { invalidArgument } from '../../utils/error.utils'; @@ -17,18 +10,20 @@ export const addOwnerControl = async ({ params, project, }: Context): Promise => { - const awardDocRef = build5Db().doc(`${COL.AWARD}/${params.uid}`); - const award = await awardDocRef.get(); + const awardDocRef = build5Db().doc(COL.AWARD, params.uid); + const award = await awardDocRef.get(); if (!award) { throw invalidArgument(WenError.award_does_not_exists); } - const awardOwner = await awardDocRef.collection(SUB_COL.OWNERS).doc(owner).get(); + const awardOwner = await build5Db().doc(COL.AWARD, params.uid, SUB_COL.OWNERS, owner).get(); if (!awardOwner) { throw invalidArgument(WenError.you_are_not_owner_of_the_award); } - const awardMember = await awardDocRef.collection(SUB_COL.OWNERS).doc(params.member).get(); + const awardMember = await build5Db() + .doc(COL.AWARD, params.uid, SUB_COL.OWNERS, params.member) + .get(); if (awardMember) { throw invalidArgument(WenError.member_is_already_owner_of_space); } @@ -40,6 +35,6 @@ export const addOwnerControl = async ({ parentCol: COL.AWARD, createdOn: dateToTimestamp(dayjs()), }; - await awardDocRef.collection(SUB_COL.OWNERS).doc(params.member).create(newOwner); + await build5Db().doc(COL.AWARD, params.uid, SUB_COL.OWNERS, params.member).create(newOwner); return newOwner; }; diff --git a/packages/functions/src/controls/award/award.participate.ts b/packages/functions/src/controls/award/award.participate.ts index 659bc94910..965c6d1108 100644 --- a/packages/functions/src/controls/award/award.participate.ts +++ b/packages/functions/src/controls/award/award.participate.ts @@ -1,6 +1,5 @@ import { build5Db } from '@build-5/database'; import { - Award, AwardParticipant, AwardParticpateRequest, COL, @@ -17,8 +16,8 @@ export const awardParticipateControl = async ({ params, project, }: Context): Promise => { - const awardDocRef = build5Db().doc(`${COL.AWARD}/${params.uid}`); - const award = await awardDocRef.get(); + const awardDocRef = build5Db().doc(COL.AWARD, params.uid); + const award = await awardDocRef.get(); if (!award) { throw invalidArgument(WenError.award_does_not_exists); } @@ -35,7 +34,9 @@ export const awardParticipateControl = async ({ throw invalidArgument(WenError.award_is_no_longer_available); } - const awardParticipant = await awardDocRef.collection(SUB_COL.PARTICIPANTS).doc(owner).get(); + const awardParticipant = await build5Db() + .doc(COL.AWARD, params.uid, SUB_COL.PARTICIPANTS, owner) + .get(); if (awardParticipant) { throw invalidArgument(WenError.member_is_already_participant_of_space); } @@ -51,6 +52,6 @@ export const awardParticipateControl = async ({ tokenReward: 0, createdOn: dateToTimestamp(dayjs()), }; - await awardDocRef.collection(SUB_COL.PARTICIPANTS).doc(owner).create(participant); + await build5Db().doc(COL.AWARD, params.uid, SUB_COL.PARTICIPANTS, owner).create(participant); return participant; }; diff --git a/packages/functions/src/controls/award/award.reject.ts b/packages/functions/src/controls/award/award.reject.ts index f7b45bc3f7..8e6b834ea0 100644 --- a/packages/functions/src/controls/award/award.reject.ts +++ b/packages/functions/src/controls/award/award.reject.ts @@ -8,8 +8,8 @@ export const rejectAwardControl = async ({ owner, params, }: Context): Promise => { - const awardDocRef = build5Db().doc(`${COL.AWARD}/${params.uid}`); - const award = await awardDocRef.get(); + const awardDocRef = build5Db().doc(COL.AWARD, params.uid); + const award = await awardDocRef.get(); if (!award) { throw invalidArgument(WenError.award_does_not_exists); } diff --git a/packages/functions/src/controls/collection/collection-mint.control.ts b/packages/functions/src/controls/collection/collection-mint.control.ts index 95eefce147..ffc6a51429 100644 --- a/packages/functions/src/controls/collection/collection-mint.control.ts +++ b/packages/functions/src/controls/collection/collection-mint.control.ts @@ -1,14 +1,12 @@ -import { build5Db, getSnapshot } from '@build-5/database'; +import { build5Db } from '@build-5/database'; import { COL, Collection, CollectionMintRequest, CollectionStatus, CollectionType, - Member, Network, Nft, - Space, TRANSACTION_AUTO_EXPIRY_MS, Transaction, TransactionPayloadType, @@ -43,12 +41,12 @@ export const mintCollectionOrderControl = async ({ }: Context) => { const network = params.network as Network; - const member = await build5Db().doc(`${COL.MEMBER}/${owner}`).get(); + const member = await build5Db().doc(COL.MEMBER, owner).get(); assertMemberHasValidAddress(member, network); return await build5Db().runTransaction(async (transaction) => { - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${params.collection}`); - const collection = await transaction.get(collectionDocRef); + const collectionDocRef = build5Db().doc(COL.COLLECTION, params.collection); + const collection = await transaction.get(collectionDocRef); if (!collection) { throw invalidArgument(WenError.collection_does_not_exists); @@ -74,13 +72,11 @@ export const mintCollectionOrderControl = async ({ await assertIsCollectionGuardian(collection, owner); - const space = await build5Db().doc(`${COL.SPACE}/${collection.space}`).get(); + const space = await build5Db().doc(COL.SPACE, collection.space!).get(); assertSpaceHasValidAddress(space, network); - if (collection.royaltiesFee) { - const royaltySpace = await build5Db() - .doc(`${COL.SPACE}/${collection.royaltiesSpace}`) - .get(); + if (collection.royaltiesSpace) { + const royaltySpace = await build5Db().doc(COL.SPACE, collection.royaltiesSpace).get(); assertSpaceHasValidAddress(royaltySpace, network); } @@ -128,8 +124,8 @@ export const mintCollectionOrderControl = async ({ nftsToMint, }, }; - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${order.uid}`); - transaction.create(orderDocRef, order); + const orderDocRef = build5Db().doc(COL.TRANSACTION, order.uid); + await transaction.create(orderDocRef, order); return order; }); }; @@ -142,33 +138,31 @@ const getNftsTotalStorageDeposit = async ( ) => { let storageDeposit = 0; let nftsToMint = 0; - let lastUid = ''; + let lastDoc: Nft | undefined = undefined; do { - const lastDoc = await getSnapshot(COL.NFT, lastUid); - const nfts = await build5Db() + const nfts: Nft[] = await build5Db() .collection(COL.NFT) .where('collection', '==', collection.uid) .where('placeholderNft', '==', false) - .limit(500) .startAfter(lastDoc) - .get(); - lastUid = last(nfts)?.uid || ''; + .limit(500) + .get(); + lastDoc = last(nfts); const promises = nfts.map(async (nft) => { if (unsoldMintingOptions === UnsoldMintingOptions.BURN_UNSOLD && !nft.sold) { return 0; } const ownerAddress = new Ed25519Address(address.hex); - const metadata = JSON.stringify( - await nftToMetadata(nft, collection, address.bech32, EMPTY_NFT_ID), - ); + const nftMetadata = await nftToMetadata(nft, collection, address.bech32, EMPTY_NFT_ID); + const metadata = JSON.stringify(nftMetadata); const output = await createNftOutput(wallet, ownerAddress, ownerAddress, metadata); return Number(output.amount); }); const amounts = await Promise.all(promises); storageDeposit += amounts.reduce((acc, act) => acc + act, 0); nftsToMint += amounts.filter((a) => a !== 0).length; - } while (lastUid); + } while (lastDoc); return { storageDeposit, nftsToMint }; }; diff --git a/packages/functions/src/controls/collection/collection.create.control.ts b/packages/functions/src/controls/collection/collection.create.control.ts index d37710a9a4..6f96419c44 100644 --- a/packages/functions/src/controls/collection/collection.create.control.ts +++ b/packages/functions/src/controls/collection/collection.create.control.ts @@ -7,12 +7,12 @@ import { CreateCollectionRequest, DEFAULT_NETWORK, DiscountLine, - Member, + Nft, NftStatus, - Space, SUB_COL, WenError, } from '@build-5/interfaces'; +import { set } from 'lodash'; import { hasStakedTokens } from '../../services/stake.service'; import { assertSpaceHasValidAddress } from '../../utils/address.utils'; import { dateToTimestamp, serverTime } from '../../utils/dateTime.utils'; @@ -33,31 +33,27 @@ export const createCollectionControl = async ({ const spaceUid = params.space || ''; if (spaceUid) { - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${spaceUid}`); - const space = await spaceDocRef.get(); + const spaceDocRef = build5Db().doc(COL.SPACE, spaceUid); + const space = await spaceDocRef.get(); if (!space) { throw invalidArgument(WenError.space_does_not_exists); } assertSpaceHasValidAddress(space, DEFAULT_NETWORK); - const spaceMember = await spaceDocRef.collection(SUB_COL.MEMBERS).doc(owner).get(); + const spaceMember = await build5Db().doc(COL.SPACE, spaceUid, SUB_COL.MEMBERS, owner).get(); if (!spaceMember) { throw invalidArgument(WenError.you_are_not_part_of_space); } } - if (params.royaltiesFee) { - const royaltySpace = await build5Db().doc(`${COL.SPACE}/${params.royaltiesSpace}`).get(); + if (params.royaltiesSpace) { + const royaltySpace = await build5Db().doc(COL.SPACE, params.royaltiesSpace).get(); if (!royaltySpace) { throw invalidArgument(WenError.space_does_not_exists); } assertSpaceHasValidAddress(royaltySpace, DEFAULT_NETWORK); } - if (params.availableFrom) { - params.availableFrom = dateToTimestamp(params.availableFrom, true).toDate(); - } - const batch = build5Db().batch(); const discounts = (params.discounts || []); @@ -73,14 +69,17 @@ export const createCollectionControl = async ({ createdBy: owner, approved: false, rejected: false, - ipfsMedia: null, + ipfsMedia: undefined, limitedEdition: !!params.limitedEdition, onePerMemberOnly: !!params.onePerMemberOnly, - placeholderNft: placeholderNftId || null, + placeholderNft: placeholderNftId || '', status: CollectionStatus.PRE_MINTED, }; - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${collection.uid}`); - batch.create(collectionDocRef, collection); + if (collection.availableFrom) { + set(collection, 'availableFrom', dateToTimestamp(params.availableFrom, true)); + } + const collectionDocRef = build5Db().doc(COL.COLLECTION, collection.uid); + batch.create(collectionDocRef, collection as unknown as Collection); if (placeholderNftId) { const placeholderNft = { @@ -90,7 +89,7 @@ export const createCollectionControl = async ({ description: params.description, locked: false, media: params.placeholderUrl || null, - availableFrom: params.availableFrom || null, + availableFrom: collection.availableFrom, price: params.price, availablePrice: params.price, collection: collection.uid, @@ -109,10 +108,10 @@ export const createCollectionControl = async ({ createdBy: owner, status: NftStatus.PRE_MINTED, }; - const placeholderNftDocRef = build5Db().doc(`${COL.NFT}/${placeholderNft.uid}`); - batch.create(placeholderNftDocRef, placeholderNft); + const placeholderNftDocRef = build5Db().doc(COL.NFT, placeholderNft.uid); + batch.create(placeholderNftDocRef, placeholderNft as unknown as Nft); } await batch.commit(); - return await collectionDocRef.get(); + return await collectionDocRef.get(); }; diff --git a/packages/functions/src/controls/collection/collection.reject.control.ts b/packages/functions/src/controls/collection/collection.reject.control.ts index 8c42ad2887..1c36d48b70 100644 --- a/packages/functions/src/controls/collection/collection.reject.control.ts +++ b/packages/functions/src/controls/collection/collection.reject.control.ts @@ -9,8 +9,8 @@ export const rejectCollectionControl = async ({ owner, params, }: Context): Promise => { - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${params.uid}`); - const collection = await collectionDocRef.get(); + const collectionDocRef = build5Db().doc(COL.COLLECTION, params.uid); + const collection = await collectionDocRef.get(); if (!collection) { throw invalidArgument(WenError.collection_does_not_exists); } diff --git a/packages/functions/src/controls/collection/collection.update.control.ts b/packages/functions/src/controls/collection/collection.update.control.ts index 2f2949ac0d..70e934f3ac 100644 --- a/packages/functions/src/controls/collection/collection.update.control.ts +++ b/packages/functions/src/controls/collection/collection.update.control.ts @@ -1,17 +1,13 @@ -import { build5Db, getSnapshot } from '@build-5/database'; +import { build5Db } from '@build-5/database'; import { COL, - Collection, CollectionStatus, - DiscountLine, - Member, - Nft, NftStatus, UpdateCollectionRequest, WenError, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { isEmpty, last, set } from 'lodash'; +import { isEmpty, set } from 'lodash'; import { dateToTimestamp } from '../../utils/dateTime.utils'; import { invalidArgument } from '../../utils/error.utils'; import { assertValidationAsync } from '../../utils/schema.utils'; @@ -25,17 +21,17 @@ export const updateCollectionControl = async ({ owner, params: rawParams, }: Context) => { - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${rawParams.uid}`); - const collection = await collectionDocRef.get(); + const collectionDocRef = build5Db().doc(COL.COLLECTION, rawParams.uid); + const collection = await collectionDocRef.get(); if (!collection) { throw invalidArgument(WenError.collection_does_not_exists); } const isMinted = collection.status === CollectionStatus.MINTED; const schema = isMinted ? updateMintedCollectionSchemaObject : updateCollectionSchemaObject; - const params = await assertValidationAsync(schema, rawParams); + const { discounts, ...params } = await assertValidationAsync(schema, rawParams); - const member = await build5Db().doc(`${COL.MEMBER}/${owner}`).get(); + const member = await build5Db().doc(COL.MEMBER, owner).get(); if (!member) { throw invalidArgument(WenError.member_does_not_exists); } @@ -64,13 +60,16 @@ export const updateCollectionControl = async ({ ...params, price, availablePrice: price, + access: params.access, uid: params.uid, }; - const discounts = params.discounts; + if (!params.access) { + delete collectionUpdateData.access; + } if (discounts) { - set(collectionUpdateData, 'discounts', await populateTokenUidOnDiscounts(discounts)); + const value = JSON.stringify(await populateTokenUidOnDiscounts(discounts)); + set(collectionUpdateData, 'discounts', value); } - batch.update(collectionDocRef, collectionUpdateData); if (!isMinted && collection.placeholderNft) { @@ -81,7 +80,7 @@ export const updateCollectionControl = async ({ space: collection.space, type: collection.type, }; - const nftDocRef = build5Db().doc(`${COL.NFT}/${collection.placeholderNft}`); + const nftDocRef = build5Db().doc(COL.NFT, collection.placeholderNft); batch.update(nftDocRef, data); } await batch.commit(); @@ -96,27 +95,11 @@ export const updateCollectionControl = async ({ } if (!isEmpty(nftUpdateData)) { for (const status of [NftStatus.PRE_MINTED, NftStatus.MINTED]) { - let lastNftId = ''; - do { - const lastDoc = await getSnapshot(COL.NFT, lastNftId); - const nfts = await build5Db() - .collection(COL.NFT) - .where('collection', '==', collection.uid) - .where('isOwned', '==', false) - .where('status', '==', status) - .limit(500) - .startAfter(lastDoc) - .get(); - lastNftId = last(nfts)?.uid || ''; - - const batch = build5Db().batch(); - for (const nft of nfts) { - batch.update(build5Db().doc(`${COL.NFT}/${nft.uid}`), nftUpdateData); - } - await batch.commit(); - } while (lastNftId); + await build5Db() + .collection(COL.NFT) + .update(nftUpdateData, { collection: collection.uid, isOwned: false, status: status }); } } - return await build5Db().doc(`${COL.COLLECTION}/${params.uid}`).get(); + return await build5Db().doc(COL.COLLECTION, params.uid).get(); }; diff --git a/packages/functions/src/controls/credit/credit.controller.ts b/packages/functions/src/controls/credit/credit.controller.ts index 7e3c7cab89..4fbc221729 100644 --- a/packages/functions/src/controls/credit/credit.controller.ts +++ b/packages/functions/src/controls/credit/credit.controller.ts @@ -25,8 +25,8 @@ export const creditUnrefundableControl = ({ project, }: Context): Promise => build5Db().runTransaction(async (transaction) => { - const transactionDocRef = build5Db().doc(`${COL.TRANSACTION}/${params.transaction}`); - const creditTransaction = await transaction.get(transactionDocRef); + const transactionDocRef = build5Db().doc(COL.TRANSACTION, params.transaction); + const creditTransaction = await transaction.get(transactionDocRef); if ( !creditTransaction || @@ -49,8 +49,8 @@ export const creditUnrefundableControl = ({ const targetAddress = await wallet.getNewIotaAddressDetails(); const creditOrder = createCreditOrder(project, creditTransaction, owner, targetAddress.bech32); - const creditDocRef = build5Db().doc(`${COL.TRANSACTION}/${creditOrder.uid}`); - transaction.create(creditDocRef, creditOrder); + const creditDocRef = build5Db().doc(COL.TRANSACTION, creditOrder.uid); + await transaction.create(creditDocRef, creditOrder); return creditOrder; }); diff --git a/packages/functions/src/controls/member/member.create.ts b/packages/functions/src/controls/member/member.create.ts index 1ca3bdf59b..8ff0e63aa5 100644 --- a/packages/functions/src/controls/member/member.create.ts +++ b/packages/functions/src/controls/member/member.create.ts @@ -1,15 +1,10 @@ import { build5Db } from '@build-5/database'; -import { COL, Member } from '@build-5/interfaces'; +import { COL } from '@build-5/interfaces'; import { getRandomNonce } from '../../utils/wallet.utils'; import { Context } from '../common'; export const createMemberControl = async ({ owner }: Context) => { - const memberDocRef = build5Db().collection(COL.MEMBER).doc(owner); - const member = await memberDocRef.get(); - - if (!member) { - await memberDocRef.create({ uid: owner, nonce: getRandomNonce() }); - } - - return (await memberDocRef.get())!; + const memberDocRef = build5Db().doc(COL.MEMBER, owner); + await memberDocRef.upsert({ nonce: getRandomNonce() }); + return (await memberDocRef.get())!; }; diff --git a/packages/functions/src/controls/member/member.update.ts b/packages/functions/src/controls/member/member.update.ts index 7265f682df..bafa46163e 100644 --- a/packages/functions/src/controls/member/member.update.ts +++ b/packages/functions/src/controls/member/member.update.ts @@ -1,20 +1,12 @@ import { build5Db } from '@build-5/database'; -import { - COL, - Member, - MemberUpdateRequest, - Nft, - NftAvailable, - NftStatus, - WenError, -} from '@build-5/interfaces'; +import { COL, MemberUpdateRequest, NftAvailable, NftStatus, WenError } from '@build-5/interfaces'; import { invalidArgument } from '../../utils/error.utils'; import { cleanupParams } from '../../utils/schema.utils'; import { Context } from '../common'; export const updateMemberControl = async ({ owner, params }: Context) => { - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${owner}`); - const member = await memberDocRef.get(); + const memberDocRef = build5Db().doc(COL.MEMBER, owner); + const member = await memberDocRef.get(); if (!member) { throw invalidArgument(WenError.member_does_not_exists); } @@ -24,7 +16,7 @@ export const updateMemberControl = async ({ owner, params }: Context(); + .get(); if (members.length > 0) { throw invalidArgument(WenError.member_username_exists); } @@ -36,26 +28,26 @@ export const updateMemberControl = async ({ owner, params }: Context).avatar = null; } if (member.avatarNft && member.avatarNft !== params.avatarNft) { - const currentAvatarDocRef = build5Db().doc(`${COL.NFT}/${member.avatarNft}`); + const currentAvatarDocRef = build5Db().doc(COL.NFT, member.avatarNft); batch.update(currentAvatarDocRef, { setAsAvatar: false }); } batch.update(memberDocRef, cleanupParams({ ...params })); await batch.commit(); - return (await memberDocRef.get())!; + return (await memberDocRef.get())!; }; const getNft = async (owner: string, nftId: string) => { - const nftDocRef = build5Db().doc(`${COL.NFT}/${nftId}`); - const nft = await nftDocRef.get(); + const nftDocRef = build5Db().doc(COL.NFT, nftId); + const nft = await nftDocRef.get(); if (!nft) { throw invalidArgument(WenError.nft_does_not_exists); } diff --git a/packages/functions/src/controls/nft/NftMetadataRequestSchema.ts b/packages/functions/src/controls/nft/NftMetadataRequestSchema.ts index 8b57d90c82..db646d6090 100644 --- a/packages/functions/src/controls/nft/NftMetadataRequestSchema.ts +++ b/packages/functions/src/controls/nft/NftMetadataRequestSchema.ts @@ -1,7 +1,7 @@ +import { MintMetadataNftRequest } from '@build-5/interfaces'; import Joi from 'joi'; import { CommonJoi, toJoiObject } from '../../services/joi/common'; import { AVAILABLE_NETWORKS } from '../common'; -import { MintMetadataNftRequest } from '@build-5/interfaces'; export const commonMetadataNftParams = { nftId: CommonJoi.uid(false).description('Nft network id. Only specify it in case of edit.'), diff --git a/packages/functions/src/controls/nft/nft.bid.control.ts b/packages/functions/src/controls/nft/nft.bid.control.ts index 63484ab7ac..2ee2a4124a 100644 --- a/packages/functions/src/controls/nft/nft.bid.control.ts +++ b/packages/functions/src/controls/nft/nft.bid.control.ts @@ -10,19 +10,19 @@ export const nftBidControl = async ({ params, project, }: Context): Promise => { - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${owner}`); + const memberDocRef = build5Db().doc(COL.MEMBER, owner); const member = await memberDocRef.get(); if (!member) { throw invalidArgument(WenError.member_does_not_exists); } - const nftDocRef = build5Db().doc(`${COL.NFT}/${params.nft}`); + 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}`); + const transactionDocRef = build5Db().doc(COL.TRANSACTION, bidTransaction.uid); await transactionDocRef.create(bidTransaction); - return (await transactionDocRef.get())!; + return (await transactionDocRef.get())!; }; diff --git a/packages/functions/src/controls/nft/nft.create.ts b/packages/functions/src/controls/nft/nft.create.ts index b98ece3c10..61905abbc0 100644 --- a/packages/functions/src/controls/nft/nft.create.ts +++ b/packages/functions/src/controls/nft/nft.create.ts @@ -7,7 +7,10 @@ import { MIN_IOTA_AMOUNT, Nft, NftAccess, + NftAvailable, NftCreateRequest, + NftStatus, + PropStats, WenError, } from '@build-5/interfaces'; import dayjs from 'dayjs'; @@ -39,8 +42,8 @@ export const createBatchNftControl = async ({ }; const getCollection = async (owner: string, collectionId: string) => { - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${collectionId}`); - const collection = await collectionDocRef.get(); + const collectionDocRef = build5Db().doc(COL.COLLECTION, collectionId); + const collection = await collectionDocRef.get(); if (!collection) { throw invalidArgument(WenError.collection_does_not_exists); } @@ -101,8 +104,15 @@ const processOneCreateNft = async ( } const price = Math.max(Number(params.price) || 0, MIN_IOTA_AMOUNT); - const nft = { + const nft: Nft = { ...params, + name: params.name || '', + description: params.description || '', + media: params.media || '', + availableFrom: dateToTimestamp(params.availableFrom), + url: params.url || '', + properties: (params.properties || {}) as PropStats, + stats: (params.stats || {}) as PropStats, project, uid: getRandomEthAddress(), locked: false, @@ -110,32 +120,34 @@ const processOneCreateNft = async ( availablePrice: price, saleAccess: isEmpty(params.saleAccessMembers) ? NftAccess.OPEN : NftAccess.MEMBERS, position, - lockedBy: null, - ipfsMedia: null, - ipfsMetadata: null, + lockedBy: undefined, + ipfsMedia: '', + ipfsMetadata: '', sold: false, approved: collection.approved, rejected: collection.rejected, - owner: null, + owner: undefined, isOwned: false, - soldOn: null, - ipfsRetries: 0, - space: collection.space, + soldOn: undefined, + space: collection.space || '', type: collection.type, hidden: CollectionType.CLASSIC !== collection.type, createdBy: collection.createdBy, placeholderNft: false, - status: CollectionStatus.PRE_MINTED, + status: NftStatus.PRE_MINTED, + available: NftAvailable.UNAVAILABLE, + totalTrades: 0, + lastTradedOn: null, }; const batch = build5Db().batch(); - const nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); + const nftDocRef = build5Db().doc(COL.NFT, nft.uid); batch.create(nftDocRef, nft); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${collection.uid}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, collection.uid); batch.update(collectionDocRef, { total: build5Db().inc(1) }); if (collection.placeholderNft) { - const placeholderNftDocRef = build5Db().doc(`${COL.NFT}/${collection.placeholderNft}`); + const placeholderNftDocRef = build5Db().doc(COL.NFT, collection.placeholderNft); batch.update(placeholderNftDocRef, { sold: false, availableFrom: params.availableFrom, @@ -144,5 +156,5 @@ const processOneCreateNft = async ( } await batch.commit(); - return (await nftDocRef.get())!; + return (await nftDocRef.get())!; }; diff --git a/packages/functions/src/controls/nft/nft.deposit.ts b/packages/functions/src/controls/nft/nft.deposit.ts index 0d651f8642..221ff32847 100644 --- a/packages/functions/src/controls/nft/nft.deposit.ts +++ b/packages/functions/src/controls/nft/nft.deposit.ts @@ -41,7 +41,7 @@ export const depositNftControl = async ({ void: false, }, }; - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${order.uid}`); + const orderDocRef = build5Db().doc(COL.TRANSACTION, order.uid); await orderDocRef.create(order); return order; }; diff --git a/packages/functions/src/controls/nft/nft.metadata.control.ts b/packages/functions/src/controls/nft/nft.metadata.control.ts index e09cbd963f..33981e9226 100644 --- a/packages/functions/src/controls/nft/nft.metadata.control.ts +++ b/packages/functions/src/controls/nft/nft.metadata.control.ts @@ -4,6 +4,7 @@ import { MintMetadataNftRequest, Network, SUB_COL, + SpaceGuardian, TRANSACTION_AUTO_EXPIRY_MS, Transaction, TransactionPayloadType, @@ -43,14 +44,19 @@ export const mintMetadataNftControl = async ({ const batch = build5Db().batch(); if (aliasId === EMPTY_ALIAS_ID) { - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${space.uid}`); + const spaceDocRef = build5Db().doc(COL.SPACE, space.uid); batch.create(spaceDocRef, space); - const guardian = { uid: owner, parentId: space.uid, parentCol: COL.SPACE }; - const guardianDocRef = spaceDocRef.collection(SUB_COL.GUARDIANS).doc(owner); + const guardian: SpaceGuardian = { + uid: owner, + parentId: space.uid, + parentCol: COL.SPACE, + createdOn: dateToTimestamp(dayjs()), + }; + const guardianDocRef = build5Db().doc(COL.SPACE, space.uid, SUB_COL.GUARDIANS, owner); batch.create(guardianDocRef, guardian); - const memberDocRef = spaceDocRef.collection(SUB_COL.MEMBERS).doc(owner); + const memberDocRef = build5Db().doc(COL.SPACE, space.uid, SUB_COL.MEMBERS, owner); batch.create(memberDocRef, guardian); } @@ -81,7 +87,7 @@ export const mintMetadataNftControl = async ({ metadata: params.metadata as { [key: string]: unknown }, }, }; - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${order.uid}`); + const orderDocRef = build5Db().doc(COL.TRANSACTION, order.uid); batch.create(orderDocRef, order); await batch.commit(); diff --git a/packages/functions/src/controls/nft/nft.puchase.bulk.control.ts b/packages/functions/src/controls/nft/nft.puchase.bulk.control.ts index 88df487fbe..d97f65a81a 100644 --- a/packages/functions/src/controls/nft/nft.puchase.bulk.control.ts +++ b/packages/functions/src/controls/nft/nft.puchase.bulk.control.ts @@ -10,8 +10,8 @@ export const orderNftBulkControl = async ({ project, }: Context): Promise => { const order = await createNftBulkOrder(project, params.orders, owner, ip); - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${order.uid}`); + const orderDocRef = build5Db().doc(COL.TRANSACTION, order.uid); await orderDocRef.create(order); - return (await orderDocRef.get())!; + return (await orderDocRef.get())!; }; diff --git a/packages/functions/src/controls/nft/nft.puchase.control.ts b/packages/functions/src/controls/nft/nft.puchase.control.ts index ed1077f3a9..3ba4aed64b 100644 --- a/packages/functions/src/controls/nft/nft.puchase.control.ts +++ b/packages/functions/src/controls/nft/nft.puchase.control.ts @@ -10,8 +10,7 @@ export const orderNftControl = async ({ project, }: Context): Promise => { const order = await createNftPuchaseOrder(project, params.collection, params.nft, owner, ip); - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${order.uid}`); + const orderDocRef = build5Db().doc(COL.TRANSACTION, order.uid); await orderDocRef.create(order); - - return (await orderDocRef.get())!; + return (await orderDocRef.get())!; }; 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 8a6f43114c..4f7419e773 100644 --- a/packages/functions/src/controls/nft/nft.set.for.sale.ts +++ b/packages/functions/src/controls/nft/nft.set.for.sale.ts @@ -1,5 +1,5 @@ import { build5Db } from '@build-5/database'; -import { COL, Member, Nft, NftSetForSaleRequest, WenError } from '@build-5/interfaces'; +import { COL, Nft, NftSetForSaleRequest, WenError } from '@build-5/interfaces'; import { getNftSetForSaleParams } from '../../services/payment/tangle-service/nft/nft-set-for-sale.service'; import { invalidArgument } from '../../utils/error.utils'; import { Context } from '../common'; @@ -9,8 +9,8 @@ export const setForSaleNftControl = async ({ params, project, }: Context): Promise => { - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${owner}`); - const member = await memberDocRef.get(); + const memberDocRef = build5Db().doc(COL.MEMBER, owner); + const member = await memberDocRef.get(); if (!member) { throw invalidArgument(WenError.member_does_not_exists); } @@ -19,15 +19,15 @@ export const setForSaleNftControl = async ({ const batch = build5Db().batch(); - const nftDocRef = build5Db().doc(`${COL.NFT}/${params.nft}`); + const nftDocRef = build5Db().doc(COL.NFT, params.nft); batch.update(nftDocRef, nft); if (auction) { - const auctionDocRef = build5Db().doc(`${COL.AUCTION}/${auction.uid}`); + const auctionDocRef = build5Db().doc(COL.AUCTION, auction.uid); batch.create(auctionDocRef, auction); } await batch.commit(); - return (await nftDocRef.get())!; + return (await nftDocRef.get())!; }; diff --git a/packages/functions/src/controls/nft/nft.stake.ts b/packages/functions/src/controls/nft/nft.stake.ts index 984b719304..535b9ca01e 100644 --- a/packages/functions/src/controls/nft/nft.stake.ts +++ b/packages/functions/src/controls/nft/nft.stake.ts @@ -1,7 +1,7 @@ import { build5Db } from '@build-5/database'; import { COL, Network, NftStakeRequest, StakeType, Transaction } from '@build-5/interfaces'; -import { Context } from '../common'; import { createNftStakeOrder } from '../../services/payment/nft/nft-stake.service'; +import { Context } from '../common'; export const nftStakeControl = async ({ owner, @@ -15,7 +15,7 @@ export const nftStakeControl = async ({ params.weeks, params.type as StakeType, ); - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${order.uid}`); + const orderDocRef = build5Db().doc(COL.TRANSACTION, order.uid); await orderDocRef.create(order); return order; }; diff --git a/packages/functions/src/controls/nft/nft.transfer.ts b/packages/functions/src/controls/nft/nft.transfer.ts index acdbfd3c15..088d173e3c 100644 --- a/packages/functions/src/controls/nft/nft.transfer.ts +++ b/packages/functions/src/controls/nft/nft.transfer.ts @@ -3,11 +3,7 @@ import { COL, NftTransferRequest, TransactionType } from '@build-5/interfaces'; import { createNftTransferData } from '../../services/payment/nft/nft-transfer.service'; import { Context } from '../common'; -export const transferNftsControl = async ({ - owner, - params, - project, -}: Context) => +export const transferNftsControl = ({ owner, params, project }: Context) => build5Db().runTransaction(async (transaction) => { const transfers = await createNftTransferData(transaction, project, owner, params.transfers); @@ -16,15 +12,19 @@ export const transferNftsControl = async ({ continue; } - const nftDocRef = build5Db().doc(`${COL.NFT}/${nftId}`); - transaction.update(nftDocRef, nftUpdateData); + if (nftUpdateData) { + const nftDocRef = build5Db().doc(COL.NFT, nftId); + await transaction.update(nftDocRef, nftUpdateData); + } - const tranDocRef = build5Db().doc(`${COL.TRANSACTION}/${order?.uid}`); - transaction.create(tranDocRef, order); + if (order) { + const tranDocRef = build5Db().doc(COL.TRANSACTION, order.uid); + await transaction.create(tranDocRef, order); + } if (order?.type === TransactionType.WITHDRAW_NFT) { - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${order.payload.collection}`); - transaction.update(collectionDocRef, { total: build5Db().inc(-1) }); + const collectionDocRef = build5Db().doc(COL.COLLECTION, order.payload.collection!); + await transaction.update(collectionDocRef, { total: build5Db().inc(-1) }); } } diff --git a/packages/functions/src/controls/nft/nft.update.unsold.ts b/packages/functions/src/controls/nft/nft.update.unsold.ts index c37f96e598..a54281a818 100644 --- a/packages/functions/src/controls/nft/nft.update.unsold.ts +++ b/packages/functions/src/controls/nft/nft.update.unsold.ts @@ -4,13 +4,13 @@ import { invalidArgument } from '../../utils/error.utils'; import { assertIsGuardian } from '../../utils/token.utils'; import { Context } from '../common'; -export const updateUnsoldNftControl = async ({ +export const updateUnsoldNftControl = ({ owner, params, }: Context): Promise => build5Db().runTransaction(async (transaction) => { - const nftDocRef = build5Db().doc(`${COL.NFT}/${params.uid}`); - const nft = await transaction.get(nftDocRef); + const nftDocRef = build5Db().doc(COL.NFT, params.uid); + const nft = await transaction.get(nftDocRef); if (!nft) { throw invalidArgument(WenError.nft_does_not_exists); } @@ -24,6 +24,6 @@ export const updateUnsoldNftControl = async ({ throw invalidArgument(WenError.hidden_nft); } await assertIsGuardian(nft.space, owner); - transaction.update(nftDocRef, params); + await transaction.update(nftDocRef, params); return { ...nft, ...params }; }); diff --git a/packages/functions/src/controls/nft/nft.withdraw.ts b/packages/functions/src/controls/nft/nft.withdraw.ts index 19c3243a0f..f9e2b87e9f 100644 --- a/packages/functions/src/controls/nft/nft.withdraw.ts +++ b/packages/functions/src/controls/nft/nft.withdraw.ts @@ -1,37 +1,29 @@ import { build5Db } from '@build-5/database'; -import { - COL, - Collection, - CollectionStatus, - Member, - Nft, - NftWithdrawRequest, - WenError, -} from '@build-5/interfaces'; +import { COL, CollectionStatus, NftWithdrawRequest, WenError } from '@build-5/interfaces'; import { assertCanBeWithdrawn } from '../../services/payment/nft/nft-withdraw.service'; import { createNftWithdrawOrder } from '../../services/payment/tangle-service/nft/nft-purchase.service'; import { assertMemberHasValidAddress, getAddress } from '../../utils/address.utils'; import { invalidArgument } from '../../utils/error.utils'; import { Context } from '../common'; -export const withdrawNftControl = async ({ owner, params, project }: Context) => +export const withdrawNftControl = ({ owner, params, project }: Context) => build5Db().runTransaction(async (transaction) => { - const nftDocRef = build5Db().doc(`${COL.NFT}/${params.nft}`); - const nft = await transaction.get(nftDocRef); + const nftDocRef = build5Db().doc(COL.NFT, params.nft); + const nft = await transaction.get(nftDocRef); if (!nft) { throw invalidArgument(WenError.nft_does_not_exists); } assertCanBeWithdrawn(nft, owner); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${nft.collection}`); - const collection = await collectionDocRef.get(); + const collectionDocRef = build5Db().doc(COL.COLLECTION, nft.collection); + const collection = await collectionDocRef.get(); if (collection?.status !== CollectionStatus.MINTED) { throw invalidArgument(WenError.nft_not_minted); } - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${owner}`); - const member = await memberDocRef.get(); + const memberDocRef = build5Db().doc(COL.MEMBER, owner); + const member = await memberDocRef.get(); assertMemberHasValidAddress(member, nft.mintingData?.network!); const { order, nftUpdateData } = createNftWithdrawOrder( @@ -40,9 +32,9 @@ export const withdrawNftControl = async ({ owner, params, project }: Context({ .description('Billing type of the project.'), tiers: Joi.array() .when('billing', { - is: Joi.exist().valid(ProjectBilling.TOKEN_BASE), + is: Joi.exist().valid(ProjectBilling.TOKEN_BASED), then: Joi.array().items(Joi.number().integer().min(0)).min(5).max(5).required(), otherwise: Joi.forbidden(), }) .description( - `Tiers for this project. Set only if billing type is ${ProjectBilling.TOKEN_BASE}`, + `Tiers for this project. Set only if billing type is ${ProjectBilling.TOKEN_BASED}`, ), tokenTradingFeeDiscountPercentage: Joi.array() .when('billing', { - is: Joi.exist().valid(ProjectBilling.TOKEN_BASE), + is: Joi.exist().valid(ProjectBilling.TOKEN_BASED), then: Joi.array().items(Joi.number().integer().min(0)).min(5).max(5).required(), otherwise: Joi.forbidden(), }) .description( - `Discounts for this project. Set only if billing type is ${ProjectBilling.TOKEN_BASE}`, + `Discounts for this project. Set only if billing type is ${ProjectBilling.TOKEN_BASED}`, ), nativeTokenSymbol: Joi.string() .when('billing', { - is: Joi.exist().valid(ProjectBilling.TOKEN_BASE), + is: Joi.exist().valid(ProjectBilling.TOKEN_BASED), then: CommonJoi.tokenSymbol(), otherwise: Joi.forbidden(), }) .description( - `Base token symbol for this project. Set only if billing type is ${ProjectBilling.TOKEN_BASE}`, + `Base token symbol for this project. Set only if billing type is ${ProjectBilling.TOKEN_BASED}`, ), }) .required() diff --git a/packages/functions/src/controls/project/project.create.control.ts b/packages/functions/src/controls/project/project.create.control.ts index 23e73f16e4..19810daa1a 100644 --- a/packages/functions/src/controls/project/project.create.control.ts +++ b/packages/functions/src/controls/project/project.create.control.ts @@ -30,7 +30,7 @@ export const createProjectControl = async ({ owner, params, }: Context): Promise => { - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${owner}`); + const memberDocRef = build5Db().doc(COL.MEMBER, owner); const member = await memberDocRef.get(); if (!member) { throw invalidArgument(WenError.member_does_not_exists); @@ -45,21 +45,21 @@ export const createProjectControl = async ({ deactivated: false, } as Project; - if (projectData.config.billing === ProjectBilling.TOKEN_BASE) { + if (projectData.config.billing === ProjectBilling.TOKEN_BASED) { const token = await getTokenBySymbol(projectData.config.nativeTokenSymbol!); if (!token) { throw invalidArgument(WenError.token_does_not_exist); } set(projectData, 'config.nativeTokenUid', token.uid); } - const projectDocRef = build5Db().doc(`${COL.PROJECT}/${projectData.uid}`); + const projectDocRef = build5Db().doc(COL.PROJECT, projectData.uid); const otr = await createOtrs(batch, projectData.uid); set(projectData, 'otr', otr); batch.create(projectDocRef, projectData); - const adminDocRef = projectDocRef.collection(SUB_COL.ADMINS).doc(owner); + const adminDocRef = build5Db().doc(COL.PROJECT, projectData.uid, SUB_COL.ADMINS, owner); const admin: ProjectAdmin = { project: projectData.uid, uid: owner, @@ -76,13 +76,14 @@ export const createProjectControl = async ({ parentCol: COL.PROJECT, parentId: projectData.uid, token, + createdOn: dateToTimestamp(dayjs()), }; - const apiKeyDocRef = projectDocRef.collection(SUB_COL._API_KEY).doc(); + const apiKeyDocRef = build5Db().doc(COL.PROJECT, projectData.uid, SUB_COL._API_KEY, apiKey.uid); batch.create(apiKeyDocRef, apiKey); await batch.commit(); - return { project: (await projectDocRef.get())!, token }; + return { project: (await projectDocRef.get())!, token }; }; const createOtrs = async (batch: IBatch, project: string) => { @@ -110,10 +111,10 @@ const createOtrs = async (batch: IBatch, project: string) => { }); const otrs = await Promise.all(promise); - otrs.forEach((otr) => { - const docRef = build5Db().doc(`${COL.TRANSACTION}/${otr.uid}`); + for (const otr of otrs) { + const docRef = build5Db().doc(COL.TRANSACTION, otr.uid); batch.create(docRef, otr); - }); + } return otrs.reduce( (acc, act) => ({ diff --git a/packages/functions/src/controls/project/project.deactivate.control.ts b/packages/functions/src/controls/project/project.deactivate.control.ts index 967ad139d5..8d8b2d5ba7 100644 --- a/packages/functions/src/controls/project/project.deactivate.control.ts +++ b/packages/functions/src/controls/project/project.deactivate.control.ts @@ -6,7 +6,7 @@ import { Context } from '../common'; export const deactivateProjectControl = async ({ project, owner }: Context): Promise => { await assertIsProjectAdmin(project, owner); - const projectDocRef = build5Db().doc(`${COL.PROJECT}/${project}`); + const projectDocRef = build5Db().doc(COL.PROJECT, project); await projectDocRef.update({ deactivated: true }); - return (await projectDocRef.get())!; + return (await projectDocRef.get())!; }; diff --git a/packages/functions/src/controls/proposal/approve.reject.proposal.ts b/packages/functions/src/controls/proposal/approve.reject.proposal.ts index c59635901e..a7f7c0ba08 100644 --- a/packages/functions/src/controls/proposal/approve.reject.proposal.ts +++ b/packages/functions/src/controls/proposal/approve.reject.proposal.ts @@ -1,5 +1,5 @@ import { build5Db } from '@build-5/database'; -import { ApproveProposalRequest, COL, Proposal, RejectProposalRequest } from '@build-5/interfaces'; +import { ApproveProposalRequest, COL, RejectProposalRequest } from '@build-5/interfaces'; import { getProposalApprovalData } from '../../services/payment/tangle-service/proposal/ProposalApporvalService'; import { Context } from '../common'; @@ -7,7 +7,7 @@ export const proposalApprovalControl = (approve: boolean) => async ({ owner, params }: Context) => { const data = await getProposalApprovalData(owner, params.uid, approve); - const proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${params.uid}`); + const proposalDocRef = build5Db().doc(COL.PROPOSAL, params.uid); await proposalDocRef.update(data); - return (await proposalDocRef.get())!; + return (await proposalDocRef.get())!; }; diff --git a/packages/functions/src/controls/proposal/create.proposal.ts b/packages/functions/src/controls/proposal/create.proposal.ts index bda7fa07b0..5d23e0837e 100644 --- a/packages/functions/src/controls/proposal/create.proposal.ts +++ b/packages/functions/src/controls/proposal/create.proposal.ts @@ -1,5 +1,5 @@ import { build5Db } from '@build-5/database'; -import { COL, Proposal, ProposalCreateRequest, SUB_COL } from '@build-5/interfaces'; +import { COL, ProposalCreateRequest, SUB_COL } from '@build-5/interfaces'; import { createProposal } from '../../services/payment/tangle-service/proposal/ProposalCreateService'; import { Context } from '../common'; @@ -10,11 +10,16 @@ export const createProposalControl = async ({ }: Context) => { const { proposal, proposalOwner } = await createProposal(project, owner, { ...params }); - const proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${proposal.uid}`); + const proposalDocRef = build5Db().doc(COL.PROPOSAL, proposal.uid); await proposalDocRef.create(proposal); - const proposalOwnerDocRef = proposalDocRef.collection(SUB_COL.OWNERS).doc(proposal.uid); + const proposalOwnerDocRef = build5Db().doc( + COL.PROPOSAL, + proposal.uid, + SUB_COL.OWNERS, + proposal.uid, + ); await proposalOwnerDocRef.create(proposalOwner); - return (await proposalDocRef.get())!; + return (await proposalDocRef.get())!; }; diff --git a/packages/functions/src/controls/proposal/vote.on.proposal.ts b/packages/functions/src/controls/proposal/vote.on.proposal.ts index 2c21c617e7..35a89cf0bf 100644 --- a/packages/functions/src/controls/proposal/vote.on.proposal.ts +++ b/packages/functions/src/controls/proposal/vote.on.proposal.ts @@ -34,34 +34,40 @@ export const voteOnProposalControl = async ({ } if (params.voteWithStakedTokes) { - const voteTransaction = await build5Db().runTransaction(async (transaction) => + const voteTransaction = await build5Db().runTransaction((transaction) => voteWithStakedTokens(project, transaction, owner, proposal, [params.value]), ); return voteTransaction; } const order = await createVoteTransactionOrder(project, owner, proposal, [params.value], token); - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${order.uid}`); + const orderDocRef = build5Db().doc(COL.TRANSACTION, order.uid); await orderDocRef.create(order); - return (await orderDocRef.get())!; + return (await orderDocRef.get())!; } - const voteData = await executeSimpleVoting(project, proposalMember, proposal, [params.value]); + const voteData = executeSimpleVoting(project, proposalMember, proposal, [params.value]); const batch = build5Db().batch(); - const proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${proposal.uid}`); - batch.set(proposalDocRef, voteData.proposal, true); - - const proposalMemberDocRef = proposalDocRef.collection(SUB_COL.MEMBERS).doc(proposalMember.uid); - batch.set(proposalMemberDocRef, voteData.proposalMember, true); + if (voteData.proposal) { + const proposalDocRef = build5Db().doc(COL.PROPOSAL, proposal.uid); + batch.update(proposalDocRef, voteData.proposal); + } - const voteTransactionDocRef = build5Db().doc( - `${COL.TRANSACTION}/${voteData.voteTransaction.uid}`, + const proposalMemberDocRef = build5Db().doc( + COL.PROPOSAL, + proposal.uid, + SUB_COL.MEMBERS, + proposalMember.uid, ); + batch.update(proposalMemberDocRef, voteData.proposalMember); + + const voteTransactionDocRef = build5Db().doc(COL.TRANSACTION, voteData.voteTransaction.uid); batch.create(voteTransactionDocRef, voteData.voteTransaction); + await batch.commit(); - const voteTransaction = await voteTransactionDocRef.get(); + const voteTransaction = await voteTransactionDocRef.get(); return voteTransaction!; }; diff --git a/packages/functions/src/controls/rank/rank.control.ts b/packages/functions/src/controls/rank/rank.control.ts index 5ff82b88e2..927b594263 100644 --- a/packages/functions/src/controls/rank/rank.control.ts +++ b/packages/functions/src/controls/rank/rank.control.ts @@ -1,6 +1,5 @@ -import { build5Db } from '@build-5/database'; -import { COL, Collection, Rank, RankRequest, SUB_COL, Token, WenError } from '@build-5/interfaces'; -import { set } from 'lodash'; +import { IDocument, PgCollectionStatsUpdate, Update, build5Db } from '@build-5/database'; +import { COL, RankRequest, SUB_COL, WenError } from '@build-5/interfaces'; import { hasStakedTokens } from '../../services/stake.service'; import { getRankingSpace } from '../../utils/config.utils'; import { invalidArgument } from '../../utils/error.utils'; @@ -13,52 +12,56 @@ export const rankControl = async ({ owner, params, project }: Context = build5Db().doc(col, params.uid); const parent = await parentDocRef.get(); if (!parent) { - const errorMsg = - params.collection === COL.COLLECTION - ? WenError.collection_does_not_exists - : WenError.token_does_not_exist; - throw invalidArgument(errorMsg); + if (col === COL.COLLECTION) { + throw invalidArgument(WenError.collection_does_not_exists); + } + throw invalidArgument(WenError.token_does_not_exist); } const rankingSpaceId = getRankingSpace(params.collection as COL); await assertIsGuardian(rankingSpaceId, owner); + const rankDocRef = build5Db().doc(col, params.uid, SUB_COL.RANKS, owner); + await build5Db().runTransaction(async (transaction) => { - const parent = (await transaction.get(parentDocRef))!; - const rankDocRef = parentDocRef.collection(SUB_COL.RANKS).doc(owner); - const prevRank = await transaction.get(rankDocRef); + const parent = (await transaction.get(parentDocRef))!; + const prevRank = await transaction.get(rankDocRef); - if (prevRank) { - transaction.update(rankDocRef, { rank: params.rank }); - } else { - transaction.create(rankDocRef, { - uid: owner, - parentCol: params.collection, - parentId: params.uid, - rank: params.rank, - }); - } + await transaction.upsert(rankDocRef, { + parentId: params.uid, + rank: params.rank, + }); - const ranks = { - count: (parent.rankCount || 0) + (prevRank ? 0 : 1), - sum: (parent.rankSum || 0) + (-(prevRank?.rank || 0) + params.rank), - avg: 0, - }; - set(ranks, 'avg', Number((ranks.sum / ranks.count).toFixed(3))); + const count = (parent.rankCount || 0) + (prevRank ? 0 : 1); + const sum = (parent.rankSum || 0) + (-(prevRank?.rank || 0) + params.rank); + const ranks = { count, sum, avg: Number((sum / count).toFixed(3)) }; - transaction.update(parentDocRef, { + await transaction.update(parentDocRef, { rankCount: ranks.count, rankSum: ranks.sum, rankAvg: ranks.avg, }); - const statsDocRef = parentDocRef.collection(SUB_COL.STATS).doc(params.uid); - transaction.set(statsDocRef, { ranks }, true); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const statsDocRef: IDocument = build5Db().doc( + col, + params.uid, + SUB_COL.STATS, + params.uid, + ); + await transaction.upsert(statsDocRef, { + project: parent.project, + parentId: params.uid, + ranks_avg: ranks.avg, + ranks_sum: ranks.sum, + ranks_count: ranks.count, + }); }); - const rankDocRef = parentDocRef.collection(SUB_COL.RANKS).doc(owner); - return (await rankDocRef.get())!; + return (await rankDocRef.get())!; }; diff --git a/packages/functions/src/controls/space/member.accept.control.ts b/packages/functions/src/controls/space/member.accept.control.ts index 2eda09c367..1cca9983f3 100644 --- a/packages/functions/src/controls/space/member.accept.control.ts +++ b/packages/functions/src/controls/space/member.accept.control.ts @@ -1,5 +1,5 @@ import { build5Db } from '@build-5/database'; -import { COL, SpaceMember, SpaceMemberUpsertRequest, SUB_COL } from '@build-5/interfaces'; +import { COL, SpaceMemberUpsertRequest, SUB_COL } from '@build-5/interfaces'; import { acceptSpaceMember } from '../../services/payment/tangle-service/space/SpaceAcceptMemberService'; import { Context } from '../common'; @@ -10,17 +10,19 @@ export const acceptSpaceMemberControl = async ({ }: Context) => { const { spaceMember, space } = await acceptSpaceMember(project, owner, params.uid, params.member); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${params.uid}`); - const memberDocRef = spaceDocRef.collection(SUB_COL.MEMBERS).doc(spaceMember.uid); - const knockingMemberDocRef = spaceDocRef - .collection(SUB_COL.KNOCKING_MEMBERS) - .doc(spaceMember.uid); + const memberDocRef = build5Db().doc(COL.SPACE, params.uid, SUB_COL.MEMBERS, spaceMember.uid); + const knockingMemberDocRef = build5Db().doc( + COL.SPACE, + params.uid, + SUB_COL.KNOCKING_MEMBERS, + spaceMember.uid, + ); const batch = build5Db().batch(); - batch.set(memberDocRef, spaceMember); + batch.upsert(memberDocRef, { ...spaceMember, createdOn: spaceMember.createdOn.toDate() }); batch.delete(knockingMemberDocRef); - batch.update(spaceDocRef, space); + batch.update(build5Db().doc(COL.SPACE, params.uid), space); await batch.commit(); - return await memberDocRef.get(); + return await memberDocRef.get(); }; diff --git a/packages/functions/src/controls/space/member.block.control.ts b/packages/functions/src/controls/space/member.block.control.ts index c284da5e81..121483d5c6 100644 --- a/packages/functions/src/controls/space/member.block.control.ts +++ b/packages/functions/src/controls/space/member.block.control.ts @@ -1,5 +1,5 @@ import { build5Db } from '@build-5/database'; -import { COL, SpaceMember, SpaceMemberUpsertRequest, SUB_COL } from '@build-5/interfaces'; +import { COL, SpaceMemberUpsertRequest, SUB_COL } from '@build-5/interfaces'; import { getBlockMemberUpdateData } from '../../services/payment/tangle-service/space/SpaceBlockMemberService'; import { Context } from '../common'; @@ -16,15 +16,22 @@ export const blockMemberControl = async ({ member, ); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${params.uid}`); - const blockedMemberDocRef = spaceDocRef.collection(SUB_COL.BLOCKED_MEMBERS).doc(member); + const blockedMemberDocRef = build5Db().doc( + COL.SPACE, + params.uid, + SUB_COL.BLOCKED_MEMBERS, + member, + ); const batch = build5Db().batch(); - batch.set(blockedMemberDocRef, blockedMember); - batch.delete(spaceDocRef.collection(SUB_COL.MEMBERS).doc(member)); - batch.delete(spaceDocRef.collection(SUB_COL.KNOCKING_MEMBERS).doc(member)); - batch.update(spaceDocRef, space); + batch.upsert(blockedMemberDocRef, { + ...blockedMember, + createdOn: blockedMember.createdOn.toDate(), + }); + batch.delete(build5Db().doc(COL.SPACE, params.uid, SUB_COL.MEMBERS, member)); + batch.delete(build5Db().doc(COL.SPACE, params.uid, SUB_COL.KNOCKING_MEMBERS, member)); + batch.update(build5Db().doc(COL.SPACE, params.uid), space); await batch.commit(); - return await blockedMemberDocRef.get(); + return await blockedMemberDocRef.get(); }; diff --git a/packages/functions/src/controls/space/member.decline.control.ts b/packages/functions/src/controls/space/member.decline.control.ts index 1399d1e26d..afb671086f 100644 --- a/packages/functions/src/controls/space/member.decline.control.ts +++ b/packages/functions/src/controls/space/member.decline.control.ts @@ -9,14 +9,20 @@ export const declineMemberControl = async ({ }: Context) => { await assertIsGuardian(params.uid, owner); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${params.uid}`); - const knockingMemberDocRef = spaceDocRef.collection(SUB_COL.KNOCKING_MEMBERS).doc(params.member); + const knockingMemberDocRef = build5Db().doc( + COL.SPACE, + params.uid, + SUB_COL.KNOCKING_MEMBERS, + params.member, + ); const knockingMemberDoc = await knockingMemberDocRef.get(); const batch = build5Db().batch(); batch.delete(knockingMemberDocRef); - batch.update(spaceDocRef, { totalPendingMembers: build5Db().inc(knockingMemberDoc ? -1 : 0) }); + batch.update(build5Db().doc(COL.SPACE, params.uid), { + totalPendingMembers: build5Db().inc(knockingMemberDoc ? -1 : 0), + }); await batch.commit(); return { status: 'success' }; diff --git a/packages/functions/src/controls/space/member.leave.control.ts b/packages/functions/src/controls/space/member.leave.control.ts index 0a7b52e38d..e6a8ab2c80 100644 --- a/packages/functions/src/controls/space/member.leave.control.ts +++ b/packages/functions/src/controls/space/member.leave.control.ts @@ -4,18 +4,16 @@ import { getLeaveSpaceData } from '../../services/payment/tangle-service/space/S import { Context } from '../common'; export const leaveSpaceControl = async ({ owner, params }: Context) => { - const { space, member } = await getLeaveSpaceData(owner, params.uid); - - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${params.uid}`); + const spaceUpdateData = await getLeaveSpaceData(owner, params.uid); const batch = build5Db().batch(); - batch.delete(spaceDocRef.collection(SUB_COL.MEMBERS).doc(owner)); - batch.delete(spaceDocRef.collection(SUB_COL.GUARDIANS).doc(owner)); - batch.update(spaceDocRef, space); + batch.delete(build5Db().doc(COL.SPACE, params.uid, SUB_COL.MEMBERS, owner)); + batch.delete(build5Db().doc(COL.SPACE, params.uid, SUB_COL.GUARDIANS, owner)); + batch.update(build5Db().doc(COL.SPACE, params.uid), spaceUpdateData); - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${owner}`); - batch.set(memberDocRef, member, true); + const memberDocRef = build5Db().doc(COL.MEMBER, owner); + batch.update(memberDocRef, { spaces: { [params.uid]: { isMember: false } } }); await batch.commit(); diff --git a/packages/functions/src/controls/space/member.unblock.control.ts b/packages/functions/src/controls/space/member.unblock.control.ts index 038a482393..c9e12fa548 100644 --- a/packages/functions/src/controls/space/member.unblock.control.ts +++ b/packages/functions/src/controls/space/member.unblock.control.ts @@ -9,8 +9,12 @@ export const unblockMemberControl = async ({ }: Context) => { await assertIsGuardian(params.uid, owner); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${params.uid}`); - const blockedMemberDocRef = spaceDocRef.collection(SUB_COL.BLOCKED_MEMBERS).doc(params.member); + const blockedMemberDocRef = build5Db().doc( + COL.SPACE, + params.uid, + SUB_COL.BLOCKED_MEMBERS, + params.member, + ); await blockedMemberDocRef.delete(); return { status: 'success' }; diff --git a/packages/functions/src/controls/space/space.claim.control.ts b/packages/functions/src/controls/space/space.claim.control.ts index 7d5c499908..39b119bd0f 100644 --- a/packages/functions/src/controls/space/space.claim.control.ts +++ b/packages/functions/src/controls/space/space.claim.control.ts @@ -1,8 +1,6 @@ import { build5Db } from '@build-5/database'; import { COL, - Collection, - Space, SpaceClaimRequest, TRANSACTION_AUTO_EXPIRY_MS, Transaction, @@ -20,16 +18,16 @@ import { getRandomEthAddress } from '../../utils/wallet.utils'; import { Context } from '../common'; export const claimSpaceControl = async ({ owner, params, project }: Context) => { - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${params.uid}`); - const space = await spaceDocRef.get(); + const spaceDocRef = build5Db().doc(COL.SPACE, params.uid); + const space = await spaceDocRef.get(); if (!space) { throw invalidArgument(WenError.space_does_not_exists); } if (!space.collectionId || space.claimed) { throw invalidArgument(WenError.space_not_claimable); } - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${space.collectionId}`); - const collection = await collectionDocRef.get(); + const collectionDocRef = build5Db().doc(COL.COLLECTION, space.collectionId); + const collection = await collectionDocRef.get(); if (!collection) { throw invalidArgument(WenError.collection_does_not_exists); } @@ -55,7 +53,7 @@ export const claimSpaceControl = async ({ owner, params, project }: Context): Promise => { - const { space, guardian, member } = await getCreateSpaceData(project, owner, { ...params }); + const { space, guardian } = await getCreateSpaceData(project, owner, { ...params }); const batch = build5Db().batch(); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${space.uid}`); + const spaceDocRef = build5Db().doc(COL.SPACE, space.uid); batch.create(spaceDocRef, space); - const spaceGuardianDocRef = spaceDocRef.collection(SUB_COL.GUARDIANS).doc(owner); + const spaceGuardianDocRef = build5Db().doc(COL.SPACE, space.uid, SUB_COL.GUARDIANS, owner); batch.create(spaceGuardianDocRef, guardian); - const spaceMemberDocRef = spaceDocRef.collection(SUB_COL.MEMBERS).doc(owner); + const spaceMemberDocRef = build5Db().doc(COL.SPACE, space.uid, SUB_COL.MEMBERS, owner); batch.create(spaceMemberDocRef, guardian); - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${owner}`); - batch.set(memberDocRef, member, true); + const memberDocRef = build5Db().doc(COL.MEMBER, owner); + batch.update(memberDocRef, { spaces: { [space.uid]: { uid: space.uid, isMember: true } } }); await batch.commit(); - return (await spaceDocRef.get())!; + return (await spaceDocRef.get())!; }; diff --git a/packages/functions/src/controls/space/space.guardian.edit.control.ts b/packages/functions/src/controls/space/space.guardian.edit.control.ts index 4a2060f960..c18aa37cf3 100644 --- a/packages/functions/src/controls/space/space.guardian.edit.control.ts +++ b/packages/functions/src/controls/space/space.guardian.edit.control.ts @@ -1,11 +1,5 @@ import { build5Db } from '@build-5/database'; -import { - COL, - Proposal, - ProposalType, - SUB_COL, - SpaceMemberUpsertRequest, -} from '@build-5/interfaces'; +import { COL, ProposalType, SUB_COL, SpaceMemberUpsertRequest } from '@build-5/interfaces'; import { addRemoveGuardian } from '../../services/payment/tangle-service/space/SpaceGuardianService'; import { Context } from '../common'; @@ -18,16 +12,15 @@ export const editGuardianControl = { ...params }, type, ); - - const proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${proposal.uid}`); - const memberPromisses = members.map((member) => { - proposalDocRef.collection(SUB_COL.MEMBERS).doc(member.uid).set(member); - }); + const memberPromisses = members.map((member) => + build5Db().doc(COL.PROPOSAL, proposal.uid, SUB_COL.MEMBERS, member.uid).create(member), + ); await Promise.all(memberPromisses); - const transactionDocRef = build5Db().doc(`${COL.TRANSACTION}/${voteTransaction.uid}`); + const transactionDocRef = build5Db().doc(COL.TRANSACTION, voteTransaction.uid); await transactionDocRef.create(voteTransaction); + const proposalDocRef = build5Db().doc(COL.PROPOSAL, proposal.uid); await proposalDocRef.create(proposal); - return await proposalDocRef.get(); + return await proposalDocRef.get(); }; diff --git a/packages/functions/src/controls/space/space.join.control.ts b/packages/functions/src/controls/space/space.join.control.ts index 6208ed41d3..3610d9bbd1 100644 --- a/packages/functions/src/controls/space/space.join.control.ts +++ b/packages/functions/src/controls/space/space.join.control.ts @@ -1,31 +1,27 @@ import { build5Db } from '@build-5/database'; -import { COL, Space, SpaceJoinRequest, SUB_COL, WenError } from '@build-5/interfaces'; +import { COL, SpaceJoinRequest, SUB_COL, WenError } from '@build-5/interfaces'; import { getJoinSpaceData } from '../../services/payment/tangle-service/space/SpaceJoinService'; import { invalidArgument } from '../../utils/error.utils'; import { Context } from '../common'; export const joinSpaceControl = async ({ owner, params, project }: Context) => { - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${params.uid}`); - const space = await spaceDocRef.get(); + const spaceDocRef = build5Db().doc(COL.SPACE, params.uid); + const space = await spaceDocRef.get(); if (!space) { throw invalidArgument(WenError.space_does_not_exists); } - const { - space: spaceUpdateData, - spaceMember, - member, - } = await getJoinSpaceData(project, owner, space); + const { space: spaceUpdateData, spaceMember } = await getJoinSpaceData(project, owner, space); const batch = build5Db().batch(); - const joiningMemberDocRef = spaceDocRef - .collection(space.open || space.tokenBased ? SUB_COL.MEMBERS : SUB_COL.KNOCKING_MEMBERS) - .doc(owner); + const subCol = space.open || space.tokenBased ? SUB_COL.MEMBERS : SUB_COL.KNOCKING_MEMBERS; + const joiningMemberDocRef = build5Db().doc(COL.SPACE, params.uid, subCol, owner); - batch.set(joiningMemberDocRef, spaceMember); + batch.create(joiningMemberDocRef, spaceMember); batch.update(spaceDocRef, spaceUpdateData); - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${owner}`); - batch.set(memberDocRef, member, true); + + const memberDocRef = build5Db().doc(COL.MEMBER, owner); + batch.update(memberDocRef, { spaces: { [space.uid]: { uid: space.uid, isMember: true } } }); await batch.commit(); return spaceMember; diff --git a/packages/functions/src/controls/space/space.update.control.ts b/packages/functions/src/controls/space/space.update.control.ts index bd72547550..db94b7ed08 100644 --- a/packages/functions/src/controls/space/space.update.control.ts +++ b/packages/functions/src/controls/space/space.update.control.ts @@ -7,7 +7,6 @@ import { Proposal, ProposalType, Space, - SpaceGuardian, SpaceUpdateRequest, SUB_COL, TokenStatus, @@ -31,8 +30,8 @@ export const updateSpaceControl = async ({ params, project, }: Context) => { - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${params.uid}`); - const space = await spaceDocRef.get(); + const spaceDocRef = build5Db().doc(COL.SPACE, params.uid); + const space = await spaceDocRef.get(); if (!space) { throw invalidArgument(WenError.space_does_not_exists); @@ -55,9 +54,9 @@ export const updateSpaceControl = async ({ throw invalidArgument(WenError.ongoing_proposal); } - const guardianDocRef = build5Db().doc(`${COL.MEMBER}/${owner}`); - const guardian = await guardianDocRef.get(); - const guardians = await spaceDocRef.collection(SUB_COL.GUARDIANS).get(); + const guardianDocRef = build5Db().doc(COL.MEMBER, owner); + const guardian = await guardianDocRef.get(); + const guardians = await build5Db().collection(COL.SPACE, params.uid, SUB_COL.GUARDIANS).get(); const proposal = createUpdateSpaceProposal( project, @@ -84,12 +83,11 @@ export const updateSpaceControl = async ({ linkedTransactions: [], }; - const proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${proposal.uid}`); + const proposalDocRef = build5Db().doc(COL.PROPOSAL, proposal.uid); const memberPromisses = guardians.map((guardian) => { - proposalDocRef - .collection(SUB_COL.MEMBERS) - .doc(guardian.uid) - .set({ + build5Db() + .doc(COL.PROPOSAL, proposal.uid, SUB_COL.MEMBERS, guardian.uid) + .create({ uid: guardian.uid, weight: 1, voted: guardian.uid === owner, @@ -101,11 +99,11 @@ export const updateSpaceControl = async ({ }); await Promise.all(memberPromisses); - await build5Db().doc(`${COL.TRANSACTION}/${voteTransaction.uid}`).create(voteTransaction); + await build5Db().doc(COL.TRANSACTION, voteTransaction.uid).create(voteTransaction); await proposalDocRef.create(proposal); - return (await proposalDocRef.get())!; + return (await proposalDocRef.get())!; }; const createUpdateSpaceProposal = ( diff --git a/packages/functions/src/controls/stake/stake.deposit.ts b/packages/functions/src/controls/stake/stake.deposit.ts index da02089407..c4f7e32b10 100644 --- a/packages/functions/src/controls/stake/stake.deposit.ts +++ b/packages/functions/src/controls/stake/stake.deposit.ts @@ -16,6 +16,6 @@ export const depositStakeControl = async ({ params.type as StakeType, params.customMetadata, ); - await build5Db().doc(`${COL.TRANSACTION}/${order.uid}`).create(order); + await build5Db().doc(COL.TRANSACTION, order.uid).create(order); return order; }; diff --git a/packages/functions/src/controls/stake/stake.reward.revoke.ts b/packages/functions/src/controls/stake/stake.reward.revoke.ts index b262f314a6..9471676fa9 100644 --- a/packages/functions/src/controls/stake/stake.reward.revoke.ts +++ b/packages/functions/src/controls/stake/stake.reward.revoke.ts @@ -8,11 +8,9 @@ import { ProposalType, REMOVE_STAKE_REWARDS_THRESHOLD_PERCENTAGE, Space, - SpaceGuardian, StakeReward, SUB_COL, Timestamp, - Token, TokenStakeRewardsRemoveRequest, Transaction, TransactionType, @@ -33,8 +31,8 @@ export const removeStakeRewardControl = async ({ }: Context) => { const stakeRewardIds = params.stakeRewardIds as string[]; const stakeRewardPromises = stakeRewardIds.map(async (stakeId) => { - const docRef = build5Db().doc(`${COL.STAKE_REWARD}/${stakeId}`); - return await docRef.get(); + const docRef = build5Db().doc(COL.STAKE_REWARD, stakeId); + return await docRef.get(); }); const stakeRewards = await Promise.all(stakeRewardPromises); stakeRewards.sort((a, b) => a!.startDate.seconds - b!.startDate.seconds); @@ -53,8 +51,8 @@ export const removeStakeRewardControl = async ({ throw invalidArgument(WenError.invalid_params); } - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${tokenIds[0]}`); - const token = (await tokenDocRef.get())!; + const tokenDocRef = build5Db().doc(COL.TOKEN, tokenIds[0]); + const token = (await tokenDocRef.get())!; await assertIsTokenGuardian(token, owner); @@ -67,16 +65,12 @@ export const removeStakeRewardControl = async ({ throw invalidArgument(WenError.ongoing_proposal); } - const guardianDocRef = build5Db().doc(`${COL.MEMBER}/${owner}`); - const guardian = (await guardianDocRef.get())!; - const guardians = await build5Db() - .collection(COL.SPACE) - .doc(token.space) - .collection(SUB_COL.GUARDIANS) - .get(); + const guardianDocRef = build5Db().doc(COL.MEMBER, owner); + const guardian = (await guardianDocRef.get())!; + const guardians = await build5Db().collection(COL.SPACE, token.space, SUB_COL.GUARDIANS).get(); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${token.space}`); - const space = await spaceDocRef.get(); + const spaceDocRef = build5Db().doc(COL.SPACE, token.space!); + const space = await spaceDocRef.get(); const proposal = createUpdateSpaceProposal( project, guardian, @@ -102,12 +96,11 @@ export const removeStakeRewardControl = async ({ linkedTransactions: [], }; - const proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${proposal.uid}`); + const proposalDocRef = build5Db().doc(COL.PROPOSAL, proposal.uid); const memberPromisses = guardians.map((guardian) => { - proposalDocRef - .collection(SUB_COL.MEMBERS) - .doc(guardian.uid) - .set({ + build5Db() + .doc(COL.PROPOSAL, proposal.uid, SUB_COL.MEMBERS, guardian.uid) + .create({ project, uid: guardian.uid, weight: 1, @@ -120,11 +113,11 @@ export const removeStakeRewardControl = async ({ }); await Promise.all(memberPromisses); - await build5Db().doc(`${COL.TRANSACTION}/${voteTransaction.uid}`).create(voteTransaction); + await build5Db().doc(COL.TRANSACTION, voteTransaction.uid).create(voteTransaction); await proposalDocRef.create(proposal); - return (await proposalDocRef.get())!; + return (await proposalDocRef.get())!; }; const createUpdateSpaceProposal = ( diff --git a/packages/functions/src/controls/stake/stake.reward.ts b/packages/functions/src/controls/stake/stake.reward.ts index 1b15d50012..8dfd408d0a 100644 --- a/packages/functions/src/controls/stake/stake.reward.ts +++ b/packages/functions/src/controls/stake/stake.reward.ts @@ -3,7 +3,6 @@ import { COL, StakeReward, StakeRewardStatus, - Token, TokenStakeRewardsRequest, WenError, } from '@build-5/interfaces'; @@ -19,8 +18,8 @@ export const stakeRewardControl = async ({ params, project, }: Context) => { - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${params.token}`); - const token = await tokenDocRef.get(); + const tokenDocRef = build5Db().doc(COL.TOKEN, params.token); + const token = await tokenDocRef.get(); if (!token) { throw invalidArgument(WenError.token_does_not_exist); } @@ -38,10 +37,10 @@ export const stakeRewardControl = async ({ })); const batch = build5Db().batch(); - stakeRewards.forEach((stakeReward) => { - const docRef = build5Db().doc(`${COL.STAKE_REWARD}/${stakeReward.uid}`); + for (const stakeReward of stakeRewards) { + const docRef = build5Db().doc(COL.STAKE_REWARD, stakeReward.uid); batch.create(docRef, stakeReward); - }); + } await batch.commit(); return stakeRewards; diff --git a/packages/functions/src/controls/stamp/stamp.create.ts b/packages/functions/src/controls/stamp/stamp.create.ts index de28925c29..5285bbb038 100644 --- a/packages/functions/src/controls/stamp/stamp.create.ts +++ b/packages/functions/src/controls/stamp/stamp.create.ts @@ -1,6 +1,8 @@ import { build5Db } from '@build-5/database'; import { COL, Network, SUB_COL, StampRequest } from '@build-5/interfaces'; +import dayjs from 'dayjs'; import { createStampAndStampOrder } from '../../services/payment/tangle-service/stamp/StampTangleService'; +import { dateToTimestamp } from '../../utils/dateTime.utils'; import { Context } from '../common'; export const stampCreateControl = async ({ project, owner, params }: Context) => { @@ -16,21 +18,26 @@ export const stampCreateControl = async ({ project, owner, params }: Contextawait ownerDocRef.get(); assertMemberHasValidAddress(ownerData, params.network as Network); @@ -29,9 +29,9 @@ export const swapCreateControl = async ({ ); const batch = build5Db().batch(); - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${order.uid}`); + const orderDocRef = build5Db().doc(COL.TRANSACTION, order.uid); batch.create(orderDocRef, order); - const swapDocRef = build5Db().doc(`${COL.SWAP}/${swap.uid}`); + const swapDocRef = build5Db().doc(COL.SWAP, swap.uid); batch.create(swapDocRef, swap); await batch.commit(); diff --git a/packages/functions/src/controls/swaps/swap.funded.control.ts b/packages/functions/src/controls/swaps/swap.funded.control.ts index 20ef72816a..8944a25bd0 100644 --- a/packages/functions/src/controls/swaps/swap.funded.control.ts +++ b/packages/functions/src/controls/swaps/swap.funded.control.ts @@ -7,28 +7,28 @@ import { } from '../../services/payment/swap/swap-service'; import { Context } from '../common'; -export const swapFundedControl = async ({ +export const swapFundedControl = ({ project, owner, params, }: Context): Promise => build5Db().runTransaction(async (transaction) => { - const swapDocRef = build5Db().doc(`${COL.SWAP}/${params.uid}`); - const swap = await transaction.get(swapDocRef); + const swapDocRef = build5Db().doc(COL.SWAP, params.uid); + const swap = await transaction.get(swapDocRef); assertSwapCanBeSetAsFunded(owner, swap); if (asksAreFulfilled(swap!)) { - transaction.update(swapDocRef, { status: SwapStatus.FULFILLED }); + await transaction.update(swapDocRef, { status: SwapStatus.FULFILLED }); const transfers = await createSwapTransfers(project, swap!); for (const transfer of transfers) { - const docRef = build5Db().doc(`${COL.TRANSACTION}/${transfer.uid}`); - transaction.create(docRef, transfer); + const docRef = build5Db().doc(COL.TRANSACTION, transfer.uid); + await transaction.create(docRef, transfer); } return { ...swap!, status: SwapStatus.FULFILLED }; } - transaction.update(swapDocRef, { status: SwapStatus.FUNDED }); + await transaction.update(swapDocRef, { status: SwapStatus.FUNDED }); return swap!; }); diff --git a/packages/functions/src/controls/swaps/swap.reject.control.ts b/packages/functions/src/controls/swaps/swap.reject.control.ts index 0b55727d5f..f0181b3bbb 100644 --- a/packages/functions/src/controls/swaps/swap.reject.control.ts +++ b/packages/functions/src/controls/swaps/swap.reject.control.ts @@ -3,23 +3,23 @@ import { COL, Swap, SwapRejectRequest, SwapStatus } from '@build-5/interfaces'; import { rejectSwap } from '../../services/payment/swap/swap-service'; import { Context } from '../common'; -export const swapRejectControl = async ({ +export const swapRejectControl = ({ project, owner, params, }: Context): Promise => build5Db().runTransaction(async (transaction) => { - const swapDocRef = build5Db().doc(`${COL.SWAP}/${params.uid}`); - const swap = await transaction.get(swapDocRef); + const swapDocRef = build5Db().doc(COL.SWAP, params.uid); + const swap = await transaction.get(swapDocRef); const credits = rejectSwap(project, owner, swap); for (const credit of credits) { - const docRef = build5Db().doc(`${COL.TRANSACTION}/${credit.uid}`); - transaction.create(docRef, credit); + const docRef = build5Db().doc(COL.TRANSACTION, credit.uid); + await transaction.create(docRef, credit); } - transaction.update(swapDocRef, { status: SwapStatus.REJECTED }); + await transaction.update(swapDocRef, { status: SwapStatus.REJECTED }); return { ...swap!, status: SwapStatus.REJECTED }; }); diff --git a/packages/functions/src/controls/token-minting/airdrop-minted-token.ts b/packages/functions/src/controls/token-minting/airdrop-minted-token.ts index d5962061e3..789eda0ea8 100644 --- a/packages/functions/src/controls/token-minting/airdrop-minted-token.ts +++ b/packages/functions/src/controls/token-minting/airdrop-minted-token.ts @@ -5,7 +5,6 @@ import { CreateAirdropsRequest, StakeType, TRANSACTION_AUTO_EXPIRY_MS, - Token, TokenDrop, TokenDropStatus, TokenStatus, @@ -34,9 +33,9 @@ export const airdropMintedTokenControl = async ({ owner, params, }: Context) => { - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${params.token}`); await build5Db().runTransaction(async (transaction) => { - const token = await transaction.get(tokenDocRef); + const tokenDocRef = build5Db().doc(COL.TOKEN, params.token); + const token = await transaction.get(tokenDocRef); if (!token) { throw invalidArgument(WenError.invalid_params); @@ -46,7 +45,8 @@ export const airdropMintedTokenControl = async ({ assertTokenApproved(token); }); - const token = (await tokenDocRef.get())!; + const tokenDocRef = build5Db().doc(COL.TOKEN, params.token); + const token = (await tokenDocRef.get())!; const drops = params.drops; const totalDropped = drops.reduce((acc, act) => acc + act.count, 0); @@ -97,12 +97,12 @@ export const airdropMintedTokenControl = async ({ const chunks = chunk(airdrops, 500); for (const chunk of chunks) { const batch = build5Db().batch(); - chunk.forEach((airdrop) => { - const docRef = build5Db().doc(`${COL.AIRDROP}/${airdrop.uid}`); + for (const airdrop of chunk) { + const docRef = build5Db().doc(COL.AIRDROP, airdrop.uid); batch.create(docRef, airdrop); - }); + } await batch.commit(); } - await build5Db().doc(`${COL.TRANSACTION}/${order.uid}`).create(order); + await build5Db().doc(COL.TRANSACTION, order.uid).create(order); return order; }; diff --git a/packages/functions/src/controls/token-minting/claim-minted-token.control.ts b/packages/functions/src/controls/token-minting/claim-minted-token.control.ts index 0bfe62c7e9..b809731998 100644 --- a/packages/functions/src/controls/token-minting/claim-minted-token.control.ts +++ b/packages/functions/src/controls/token-minting/claim-minted-token.control.ts @@ -9,6 +9,6 @@ export const claimMintedTokenControl = async ({ project, }: Context) => { const order = await createMintedTokenAirdropClaimOrder(project, owner, params.symbol); - await build5Db().doc(`${COL.TRANSACTION}/${order.uid}`).create(order); + await build5Db().doc(COL.TRANSACTION, order.uid).create(order); return order; }; diff --git a/packages/functions/src/controls/token-minting/import-minted-token.ts b/packages/functions/src/controls/token-minting/import-minted-token.ts index 0f8343e48c..c7f17be088 100644 --- a/packages/functions/src/controls/token-minting/import-minted-token.ts +++ b/packages/functions/src/controls/token-minting/import-minted-token.ts @@ -20,7 +20,7 @@ import { assertIsGuardian } from '../../utils/token.utils'; import { getRandomEthAddress } from '../../utils/wallet.utils'; import { Context } from '../common'; -export const importMintedTokenControl = async ({ +export const importMintedTokenControl = ({ owner, params, project, @@ -28,7 +28,7 @@ export const importMintedTokenControl = async ({ build5Db().runTransaction(async (transaction) => { await assertIsGuardian(params.space, owner); - const existingTokenDocRef = build5Db().doc(`${COL.TOKEN}/${params.tokenId}`); + const existingTokenDocRef = build5Db().doc(COL.TOKEN, params.tokenId); const existingToken = await transaction.get(existingTokenDocRef); if (existingToken) { throw invalidArgument(WenError.token_already_exists_for_space); @@ -60,7 +60,7 @@ export const importMintedTokenControl = async ({ tokenId: params.tokenId, }, }; - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${order.uid}`); - transaction.create(orderDocRef, order); + const orderDocRef = build5Db().doc(COL.TRANSACTION, order.uid); + await transaction.create(orderDocRef, order); return order; }); diff --git a/packages/functions/src/controls/token-minting/token-mint.control.ts b/packages/functions/src/controls/token-minting/token-mint.control.ts index 446a1c6ebf..523b98ca62 100644 --- a/packages/functions/src/controls/token-minting/token-mint.control.ts +++ b/packages/functions/src/controls/token-minting/token-mint.control.ts @@ -1,8 +1,8 @@ import { build5Db } from '@build-5/database'; import { COL, - Member, Network, + SUB_COL, TRANSACTION_AUTO_EXPIRY_MS, Token, TokenMintRequest, @@ -26,19 +26,14 @@ import { getVaultAndGuardianOutput, tokenToFoundryMetadata, } from '../../utils/token-minting-utils/foundry.utils'; -import { getOwnedTokenTotal } from '../../utils/token-minting-utils/member.utils'; -import { - assertIsTokenGuardian, - assertTokenStatus, - getUnclaimedAirdropTotalValue, -} from '../../utils/token.utils'; +import { assertIsTokenGuardian, assertTokenStatus } from '../../utils/token.utils'; import { getRandomEthAddress } from '../../utils/wallet.utils'; import { Context } from '../common'; export const mintTokenControl = ({ owner, params, project }: Context) => build5Db().runTransaction(async (transaction) => { - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${params.token}`); - const token = await transaction.get(tokenDocRef); + const tokenDocRef = build5Db().doc(COL.TOKEN, params.token); + const token = await transaction.get(tokenDocRef); if (!token) { throw invalidArgument(WenError.invalid_params); } @@ -50,14 +45,19 @@ export const mintTokenControl = ({ owner, params, project }: Context(); + const member = await build5Db().doc(COL.MEMBER, owner).get(); assertMemberHasValidAddress(member, params.network as Network); const wallet = await WalletService.newWallet(params.network as Network); const targetAddress = await wallet.getNewIotaAddressDetails(); - const totalDistributed = - (await getOwnedTokenTotal(token.uid)) + (await getUnclaimedAirdropTotalValue(token.uid)); + const totalOwned = await build5Db() + .collection(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION) + .getTotalOwned(); + const airdropTotal = await build5Db() + .collection(COL.AIRDROP) + .getUnclaimedAirdropTotalValue(token.uid); + const totalDistributed = totalOwned + airdropTotal; const storageDeposits = await getStorageDepositForMinting( token, totalDistributed, @@ -85,8 +85,8 @@ export const mintTokenControl = ({ owner, params, project }: Context({ symbol: CommonJoi.tokenSymbol().description('Symbol of the token to trade.'), diff --git a/packages/functions/src/controls/token-trading/token-trade-cancel.controller.ts b/packages/functions/src/controls/token-trading/token-trade-cancel.controller.ts index 2e7ffee4d2..c52abea501 100644 --- a/packages/functions/src/controls/token-trading/token-trade-cancel.controller.ts +++ b/packages/functions/src/controls/token-trading/token-trade-cancel.controller.ts @@ -2,7 +2,6 @@ import { build5Db } from '@build-5/database'; import { COL, CancelTokenTradeOrderRequest, - TokenTradeOrder, TokenTradeOrderStatus, WenError, } from '@build-5/interfaces'; @@ -12,8 +11,8 @@ import { Context } from '../common'; export const cancelTradeOrderControl = ({ owner, params }: Context) => build5Db().runTransaction(async (transaction) => { - const tradeOrderDocRef = build5Db().doc(`${COL.TOKEN_MARKET}/${params.uid}`); - const tradeOrder = await transaction.get(tradeOrderDocRef); + const tradeOrderDocRef = build5Db().doc(COL.TOKEN_MARKET, params.uid); + const tradeOrder = await transaction.get(tradeOrderDocRef); if (tradeOrder?.owner !== owner || tradeOrder.status !== TokenTradeOrderStatus.ACTIVE) { throw invalidArgument(WenError.invalid_params); } diff --git a/packages/functions/src/controls/token-trading/token-trade.controller.ts b/packages/functions/src/controls/token-trading/token-trade.controller.ts index 57c35de418..e12466aa6c 100644 --- a/packages/functions/src/controls/token-trading/token-trade.controller.ts +++ b/packages/functions/src/controls/token-trading/token-trade.controller.ts @@ -2,7 +2,6 @@ import { build5Db } from '@build-5/database'; import { COL, SUB_COL, - Token, TokenTradeOrderType, TradeTokenRequest, WenError, @@ -19,10 +18,13 @@ export const tradeTokenControl = async ({ project, }: Context) => { let token = await getTokenBySymbol(params.symbol); + if (!token?.uid) { + throw invalidArgument(WenError.token_does_not_exist); + } return await build5Db().runTransaction(async (transaction) => { - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${token?.uid}`); - token = await transaction.get(tokenDocRef); + const tokenDocRef = build5Db().doc(COL.TOKEN, token?.uid!); + token = await transaction.get(tokenDocRef); if (!token) { throw invalidArgument(WenError.token_does_not_exist); } @@ -42,15 +44,13 @@ export const tradeTokenControl = async ({ ip, ); if (tradeOrder) { - const orderDocRef = build5Db().doc(`${COL.TOKEN_MARKET}/${tradeOrder.uid}`); - transaction.create(orderDocRef, tradeOrder); - const distributionDocRef = build5Db().doc( - `${COL.TOKEN}/${token?.uid}/${SUB_COL.DISTRIBUTION}/${owner}`, - ); - transaction.update(distributionDocRef, distribution); + const orderDocRef = build5Db().doc(COL.TOKEN_MARKET, tradeOrder.uid); + await transaction.create(orderDocRef, tradeOrder); + const distributionDocRef = build5Db().doc(COL.TOKEN, token?.uid, SUB_COL.DISTRIBUTION, owner); + await transaction.update(distributionDocRef, distribution); } else { - const tranDocRef = build5Db().doc(`${COL.TRANSACTION}/${tradeOrderTransaction.uid}`); - transaction.create(tranDocRef, tradeOrderTransaction); + const tranDocRef = build5Db().doc(COL.TRANSACTION, tradeOrderTransaction.uid); + await transaction.create(tranDocRef, tradeOrderTransaction); } return tradeOrder || tradeOrderTransaction; }); diff --git a/packages/functions/src/controls/token/TokenOrderRequestSchema.ts b/packages/functions/src/controls/token/TokenOrderRequestSchema.ts index 0aee5ec89d..f101ddebb5 100644 --- a/packages/functions/src/controls/token/TokenOrderRequestSchema.ts +++ b/packages/functions/src/controls/token/TokenOrderRequestSchema.ts @@ -1,5 +1,5 @@ import { OrderTokenRequest } from '@build-5/interfaces'; -import { toJoiObject, CommonJoi } from '../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; export const orderTokenSchema = toJoiObject({ token: CommonJoi.uid().description('Build5 id of the token'), diff --git a/packages/functions/src/controls/token/token.airdrop.claim.ts b/packages/functions/src/controls/token/token.airdrop.claim.ts index dde441721f..29d20157a0 100644 --- a/packages/functions/src/controls/token/token.airdrop.claim.ts +++ b/packages/functions/src/controls/token/token.airdrop.claim.ts @@ -4,7 +4,6 @@ import { ClaimPreMintedAirdroppedTokensRequest, DEFAULT_NETWORK, TRANSACTION_AUTO_EXPIRY_MS, - Token, TokenStatus, Transaction, TransactionPayloadType, @@ -27,8 +26,8 @@ export const claimAirdroppedTokenControl = async ({ params, project, }: Context): Promise => { - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${params.token}`); - const token = await tokenDocRef.get(); + const tokenDocRef = build5Db().doc(COL.TOKEN, params.token); + const token = await tokenDocRef.get(); if (!token) { throw invalidArgument(WenError.invalid_params); } @@ -36,7 +35,7 @@ export const claimAirdroppedTokenControl = async ({ assertTokenStatus(token, [TokenStatus.AVAILABLE, TokenStatus.PRE_MINTED]); const tranId = getRandomEthAddress(); - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${tranId}`); + const orderDocRef = build5Db().doc(COL.TRANSACTION, tranId); const wallet = await WalletService.newWallet(); const targetAddress = await wallet.getNewIotaAddressDetails(); @@ -67,7 +66,7 @@ export const claimAirdroppedTokenControl = async ({ quantity, }, }; - transaction.create(orderDocRef, order); + await transaction.create(orderDocRef, order); }); return (await orderDocRef.get())!; diff --git a/packages/functions/src/controls/token/token.airdrop.ts b/packages/functions/src/controls/token/token.airdrop.ts index 16aefa2fd2..e7415e30e5 100644 --- a/packages/functions/src/controls/token/token.airdrop.ts +++ b/packages/functions/src/controls/token/token.airdrop.ts @@ -42,8 +42,8 @@ export const airdropTokenControl = async ({ const chunks = chunk(params.drops, 200); for (const chunk of chunks) { await build5Db().runTransaction(async (transaction) => { - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${params.token}`); - const token = await transaction.get(tokenDocRef); + const tokenDocRef = build5Db().doc(COL.TOKEN, params.token); + const token = await transaction.get(tokenDocRef); if (!token) { throw invalidArgument(WenError.token_does_not_exist); @@ -59,7 +59,7 @@ export const airdropTokenControl = async ({ throw invalidArgument(WenError.no_tokens_available_for_airdrop); } - transaction.update(tokenDocRef, { totalAirdropped: build5Db().inc(totalDropped) }); + await transaction.update(tokenDocRef, { totalAirdropped: build5Db().inc(totalDropped) }); for (const drop of chunk) { const airdrop: TokenDrop = { @@ -72,22 +72,19 @@ export const airdropTokenControl = async ({ count: drop.count, status: TokenDropStatus.UNCLAIMED, }; - const docRef = build5Db().doc(`${COL.AIRDROP}/${airdrop.uid}`); - transaction.create(docRef, airdrop); + const docRef = build5Db().doc(COL.AIRDROP, airdrop.uid); + await transaction.create(docRef, airdrop); - const distributionDocRef = tokenDocRef - .collection(SUB_COL.DISTRIBUTION) - .doc(drop.recipient.toLowerCase()); - transaction.set( - distributionDocRef, - { - parentId: token.uid, - parentCol: COL.TOKEN, - uid: drop.recipient.toLowerCase(), - totalUnclaimedAirdrop: build5Db().inc(drop.count), - }, - true, + const distributionDocRef = build5Db().doc( + COL.TOKEN, + params.token, + SUB_COL.DISTRIBUTION, + drop.recipient.toLowerCase(), ); + await transaction.upsert(distributionDocRef, { + parentId: token.uid, + totalUnclaimedAirdrop: build5Db().inc(drop.count), + }); } }); } diff --git a/packages/functions/src/controls/token/token.cancel.pub.sale.ts b/packages/functions/src/controls/token/token.cancel.pub.sale.ts index 049742c8ae..4cb4713aac 100644 --- a/packages/functions/src/controls/token/token.cancel.pub.sale.ts +++ b/packages/functions/src/controls/token/token.cancel.pub.sale.ts @@ -1,5 +1,5 @@ import { build5Db } from '@build-5/database'; -import { COL, CanelPublicSaleRequest, Token, TokenStatus, WenError } from '@build-5/interfaces'; +import { COL, CanelPublicSaleRequest, TokenStatus, WenError } from '@build-5/interfaces'; import dayjs from 'dayjs'; import { invalidArgument } from '../../utils/error.utils'; import { assertIsTokenGuardian } from '../../utils/token.utils'; @@ -9,10 +9,10 @@ export const cancelPublicSaleControl = async ({ owner, params, }: Context) => { - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${params.token}`); + const tokenDocRef = build5Db().doc(COL.TOKEN, params.token); await build5Db().runTransaction(async (transaction) => { - const token = await transaction.get(tokenDocRef); + const token = await transaction.get(tokenDocRef); if (!token) { throw invalidArgument(WenError.invalid_params); @@ -24,14 +24,14 @@ export const cancelPublicSaleControl = async ({ await assertIsTokenGuardian(token, owner); - transaction.update(tokenDocRef, { - saleStartDate: build5Db().deleteField(), - saleLength: build5Db().deleteField(), - coolDownEnd: build5Db().deleteField(), + await transaction.update(tokenDocRef, { + saleStartDate: undefined, + saleLength: undefined, + coolDownEnd: undefined, status: TokenStatus.CANCEL_SALE, totalDeposit: 0, }); }); - return (await tokenDocRef.get())!; + return (await tokenDocRef.get())!; }; diff --git a/packages/functions/src/controls/token/token.create.ts b/packages/functions/src/controls/token/token.create.ts index 7e138e3243..1c219ddc82 100644 --- a/packages/functions/src/controls/token/token.create.ts +++ b/packages/functions/src/controls/token/token.create.ts @@ -1,5 +1,6 @@ import { build5Db } from '@build-5/database'; import { + Access, COL, SOON_PROJECT_ID, Token, @@ -7,7 +8,6 @@ import { TokenStatus, WenError, } from '@build-5/interfaces'; -import { merge } from 'lodash'; import { hasStakedTokens } from '../../services/stake.service'; import { isProdEnv } from '../../utils/config.utils'; import { dateToTimestamp } from '../../utils/dateTime.utils'; @@ -29,7 +29,7 @@ export const createTokenControl = async ({ const space = params.space || ''; if (space) { - const tokens = await build5Db().collection(COL.TOKEN).where('space', '==', space).get(); + const tokens = await build5Db().collection(COL.TOKEN).where('space', '==', space).get(); const nonOrAllRejected = tokens.reduce( (acc, token) => acc && !token.approved && token.rejected, true, @@ -44,7 +44,7 @@ export const createTokenControl = async ({ .collection(COL.TOKEN) .where('symbol', '==', params.symbol) .where('rejected', '==', false) - .get(); + .get(); if (symbolSnapshot.length > 0) { throw invalidArgument(WenError.token_symbol_must_be_globally_unique); } @@ -58,7 +58,7 @@ export const createTokenControl = async ({ params.saleLength || 0, params.coolDownLength || 0, ) - : {}; + : { saleStartDate: undefined, saleLength: undefined, coolDownEnd: undefined }; const tokenUid = getRandomEthAddress(); const extraData = { @@ -76,7 +76,18 @@ export const createTokenControl = async ({ totalAirdropped: 0, tradingDisabled: true, }; - const data = merge(params, publicSaleTimeFrames, extraData); - await build5Db().collection(COL.TOKEN).doc(tokenUid).set(data); - return (await build5Db().doc(`${COL.TOKEN}/${tokenUid}`).get())!; + const data: Token = { + ...params, + ...publicSaleTimeFrames, + ...extraData, + pricePerToken: params.pricePerToken || 0, + allocations: params.allocations || [], + links: (params.links || []).map((l) => new URL(l)), + termsAndConditions: params.termsAndConditions || '', + access: params.access as Access, + ipfsMedia: '', + ipfsMetadata: '', + }; + await build5Db().doc(COL.TOKEN, tokenUid).create(data); + return (await build5Db().doc(COL.TOKEN, tokenUid).get())!; }; diff --git a/packages/functions/src/controls/token/token.credit.ts b/packages/functions/src/controls/token/token.credit.ts index 71ff1d49de..7f209ea364 100644 --- a/packages/functions/src/controls/token/token.credit.ts +++ b/packages/functions/src/controls/token/token.credit.ts @@ -6,8 +6,6 @@ import { MIN_IOTA_AMOUNT, Member, SUB_COL, - Token, - TokenDistribution, TokenStatus, Transaction, TransactionPayloadType, @@ -31,25 +29,28 @@ export const creditTokenControl = async ({ params, }: Context): Promise => { const tranId = getRandomEthAddress(); - const creditTranDoc = build5Db().doc(`${COL.TRANSACTION}/${tranId}`); + const creditTranDoc = build5Db().doc(COL.TRANSACTION, tranId); await build5Db().runTransaction(async (transaction) => { - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${params.token}`); - const distributionDocRef = tokenDocRef.collection(SUB_COL.DISTRIBUTION).doc(owner); - const distribution = await transaction.get(distributionDocRef); + const tokenDocRef = build5Db().doc(COL.TOKEN, params.token); + const distributionDocRef = build5Db().doc(COL.TOKEN, params.token, SUB_COL.DISTRIBUTION, owner); + const distribution = await transaction.get(distributionDocRef); if (!distribution || (distribution.totalDeposit || 0) < params.amount) { throw invalidArgument(WenError.not_enough_funds); } - const token = await tokenDocRef.get(); + const token = await tokenDocRef.get(); if (!token || !tokenIsInCoolDownPeriod(token) || token.status !== TokenStatus.AVAILABLE) { throw invalidArgument(WenError.token_not_in_cool_down_period); } const member = await memberDocRef(owner).get(); - const orderDocRef = build5Db().doc( - `${COL.TRANSACTION}/${tokenOrderTransactionDocId(owner, token)}`, - ); - const order = (await transaction.get(orderDocRef))!; - const payments = await transaction.getByQuery(allPaymentsQuery(owner, token.uid)); + const orderDocRef = build5Db().doc(COL.TRANSACTION, tokenOrderTransactionDocId(owner, token)); + const order = (await transaction.get(orderDocRef))!; + + const payments = await build5Db() + .collection(COL.TRANSACTION) + .where('member', '==', owner) + .where('payload_token', '==', token.uid) + .get(); const totalDepositLeft = (distribution.totalDeposit || 0) - params.amount; const refundAmount = @@ -60,10 +61,10 @@ export const creditTokenControl = async ({ totalDepositLeft || 0, token.pricePerToken, ); - transaction.update(distributionDocRef, { + await transaction.update(distributionDocRef, { totalDeposit: build5Db().inc(-refundAmount), }); - transaction.update(tokenDocRef, { + await transaction.update(tokenDocRef, { totalDeposit: build5Db().inc(-refundAmount), tokensOrdered: build5Db().inc(boughtByMemberDiff), }); @@ -87,14 +88,8 @@ export const creditTokenControl = async ({ tokenSymbol: token.symbol, }, }; - transaction.set(creditTranDoc, creditTransaction); + await transaction.create(creditTranDoc, creditTransaction); }); return (await creditTranDoc.get())!; }; - -const allPaymentsQuery = (member: string, token: string) => - build5Db() - .collection(COL.TRANSACTION) - .where('member', '==', member) - .where('payload.token', '==', token); diff --git a/packages/functions/src/controls/token/token.enable.trading.ts b/packages/functions/src/controls/token/token.enable.trading.ts index d29b3f2cf7..00da0d9433 100644 --- a/packages/functions/src/controls/token/token.enable.trading.ts +++ b/packages/functions/src/controls/token/token.enable.trading.ts @@ -1,5 +1,5 @@ import { build5Db } from '@build-5/database'; -import { COL, EnableTokenTradingRequest, Token, WenError } from '@build-5/interfaces'; +import { COL, EnableTokenTradingRequest, WenError } from '@build-5/interfaces'; import { invalidArgument } from '../../utils/error.utils'; import { assertIsTokenGuardian } from '../../utils/token.utils'; import { Context } from '../common'; @@ -8,8 +8,8 @@ export const enableTokenTradingControl = async ({ owner, params, }: Context) => { - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${params.uid}`); - const token = await tokenDocRef.get(); + const tokenDocRef = build5Db().doc(COL.TOKEN, params.uid); + const token = await tokenDocRef.get(); if (!token) { throw invalidArgument(WenError.token_does_not_exist); } @@ -20,7 +20,7 @@ export const enableTokenTradingControl = async ({ await assertIsTokenGuardian(token, owner); - await tokenDocRef.update({ tradingDisabled: build5Db().deleteField() }); + await tokenDocRef.update({ tradingDisabled: false }); - return (await tokenDocRef.get())!; + return (await tokenDocRef.get())!; }; diff --git a/packages/functions/src/controls/token/token.order.ts b/packages/functions/src/controls/token/token.order.ts index ca938b0560..519333fe28 100644 --- a/packages/functions/src/controls/token/token.order.ts +++ b/packages/functions/src/controls/token/token.order.ts @@ -3,10 +3,7 @@ import { COL, DEFAULT_NETWORK, Entity, - Member, OrderTokenRequest, - Space, - Token, TokenStatus, Transaction, TransactionPayloadType, @@ -31,11 +28,11 @@ export const orderTokenControl = async ({ params, project, }: Context) => { - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${owner}`); - const member = await memberDocRef.get(); + const memberDocRef = build5Db().doc(COL.MEMBER, owner); + const member = await memberDocRef.get(); assertMemberHasValidAddress(member, DEFAULT_NETWORK); - const token = await build5Db().doc(`${COL.TOKEN}/${params.token}`).get(); + const token = await build5Db().doc(COL.TOKEN, params.token).get(); if (!token) { throw invalidArgument(WenError.invalid_params); } @@ -49,8 +46,7 @@ export const orderTokenControl = async ({ } const tranId = tokenOrderTransactionDocId(owner, token); - const orderDoc = build5Db().doc(`${COL.TRANSACTION}/${tranId}`); - const space = await build5Db().doc(`${COL.SPACE}/${token.space}`).get(); + const space = await build5Db().doc(COL.SPACE, token.space!).get(); await assertHasAccess( space!.uid, @@ -63,8 +59,10 @@ export const orderTokenControl = async ({ const network = DEFAULT_NETWORK; const newWallet = await WalletService.newWallet(network); const targetAddress = await newWallet.getNewIotaAddressDetails(); + const orderDoc = build5Db().doc(COL.TRANSACTION, tranId); + await build5Db().runTransaction(async (transaction) => { - const order = await transaction.get(orderDoc); + const order = await transaction.get(orderDoc); if (!order) { const data: Transaction = { project, @@ -91,9 +89,9 @@ export const orderTokenControl = async ({ }, linkedTransactions: [], }; - transaction.create(orderDoc, data); + await transaction.create(orderDoc, data); } }); - return (await orderDoc.get())!; + return (await orderDoc.get())!; }; diff --git a/packages/functions/src/controls/token/token.set.for.sale.ts b/packages/functions/src/controls/token/token.set.for.sale.ts index 36e1a2a362..2dc4f6ac34 100644 --- a/packages/functions/src/controls/token/token.set.for.sale.ts +++ b/packages/functions/src/controls/token/token.set.for.sale.ts @@ -3,8 +3,6 @@ import { COL, DEFAULT_NETWORK, SetTokenForSaleRequest, - Space, - Token, TokenStatus, WenError, } from '@build-5/interfaces'; @@ -23,10 +21,11 @@ export const setTokenAvailableForSaleControl = async ({ owner, params, }: Context) => { - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${params.token}`); + const tokenDocRef = build5Db().doc(COL.TOKEN, params.token); await build5Db().runTransaction(async (transaction) => { - const token = await transaction.get(tokenDocRef); + const token = await transaction.get(tokenDocRef); + if (!token) { throw invalidArgument(WenError.token_does_not_exist); } @@ -35,7 +34,7 @@ export const setTokenAvailableForSaleControl = async ({ throw invalidArgument(WenError.token_must_have_space); } - const spaceData = await build5Db().doc(`${COL.SPACE}/${token.space}`).get(); + const spaceData = await build5Db().doc(COL.SPACE, token.space).get(); assertSpaceHasValidAddress(spaceData, DEFAULT_NETWORK); assertTokenApproved(token); @@ -57,12 +56,14 @@ export const setTokenAvailableForSaleControl = async ({ params.saleLength, params.coolDownLength, ); - transaction.update(tokenDocRef, { + await transaction.update(tokenDocRef, { ...timeFrames, + saleStartDate: timeFrames.saleStartDate?.toDate(), + coolDownEnd: timeFrames.coolDownEnd?.toDate(), autoProcessAt100Percent: params.autoProcessAt100Percent || false, pricePerToken: Number(params.pricePerToken), }); }); - return await tokenDocRef.get(); + return await tokenDocRef.get(); }; diff --git a/packages/functions/src/controls/token/token.update.ts b/packages/functions/src/controls/token/token.update.ts index 757f961997..a42214cc6d 100644 --- a/packages/functions/src/controls/token/token.update.ts +++ b/packages/functions/src/controls/token/token.update.ts @@ -1,5 +1,5 @@ -import { build5Db } from '@build-5/database'; -import { COL, Token, TokenStatus, WenError } from '@build-5/interfaces'; +import { PgTokenUpdate, build5Db } from '@build-5/database'; +import { COL, TokenStatus, WenError } from '@build-5/interfaces'; import { invalidArgument } from '../../utils/error.utils'; import { assertValidationAsync } from '../../utils/schema.utils'; import { assertIsTokenGuardian, assertTokenStatus } from '../../utils/token.utils'; @@ -10,9 +10,9 @@ import { } from './TokenUpdateRequestSchema'; export const updateTokenControl = async ({ owner, params }: Context) => { - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${params.uid}`); + const tokenDocRef = build5Db().doc(COL.TOKEN, params.uid); await build5Db().runTransaction(async (transaction) => { - const token = await transaction.get(tokenDocRef); + const token = await transaction.get(tokenDocRef); if (!token) { throw invalidArgument(WenError.invalid_params); } @@ -26,8 +26,8 @@ export const updateTokenControl = async ({ owner, params }: Context(); + return await tokenDocRef.get(); }; diff --git a/packages/functions/src/controls/vote/vote.control.ts b/packages/functions/src/controls/vote/vote.control.ts index a01fc5caee..b40d00c337 100644 --- a/packages/functions/src/controls/vote/vote.control.ts +++ b/packages/functions/src/controls/vote/vote.control.ts @@ -1,5 +1,5 @@ -import { build5Db } from '@build-5/database'; -import { COL, Collection, SUB_COL, Token, Vote, VoteRequest, WenError } from '@build-5/interfaces'; +import { IDocument, PgTokenStatsUpdate, Update, build5Db } from '@build-5/database'; +import { COL, SUB_COL, VoteRequest, WenError } from '@build-5/interfaces'; import { hasStakedTokens } from '../../services/stake.service'; import { invalidArgument } from '../../utils/error.utils'; import { Context } from '../common'; @@ -10,28 +10,25 @@ export const voteControl = async ({ owner, params, project }: Context(); + const col = params.collection === 'collection' ? COL.COLLECTION : COL.TOKEN; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const parentDocRef: IDocument = build5Db().doc(col, params.uid); + const parent = await parentDocRef.get(); if (!parent) { - const errorMsg = - params.collection === COL.COLLECTION - ? WenError.collection_does_not_exists - : WenError.token_does_not_exist; - throw invalidArgument(errorMsg); + if (col === COL.COLLECTION) { + throw invalidArgument(WenError.collection_does_not_exists); + } + throw invalidArgument(WenError.token_does_not_exist); } await build5Db().runTransaction(async (transaction) => { - const voteDocRef = parentDocRef.collection(SUB_COL.VOTES).doc(owner); - const prevVote = await transaction.get(voteDocRef); + const voteDocRef = build5Db().doc(col, params.uid, SUB_COL.VOTES, owner); + const prevVote = await transaction.get(voteDocRef); if (!params.direction) { - prevVote && transaction.delete(voteDocRef); - } else if (prevVote) { - transaction.update(voteDocRef, { direction: params.direction }); + prevVote && (await transaction.delete(voteDocRef)); } else { - transaction.create(voteDocRef, { - uid: owner, - parentCol: params.collection, + await transaction.upsert(voteDocRef, { parentId: params.uid, direction: params.direction, }); @@ -43,14 +40,29 @@ export const voteControl = async ({ owner, params, project }: Context = build5Db().doc( + col, + params.uid, + SUB_COL.STATS, + params.uid, + ); + await transaction.upsert(statsDocRef, { + parentId: params.uid, + votes_upvotes: votes.upvotes, + votes_downvotes: votes.downvotes, + votes_voteDiff: votes.voteDiff, + }); }); - const voteDocRef = parentDocRef.collection(SUB_COL.VOTES).doc(owner); - return (await voteDocRef.get())!; + const voteDocRef = build5Db().doc(col, params.uid, SUB_COL.VOTES, owner); + return (await voteDocRef.get())!; }; const getVoteChagens = (prevDir: number, currDir: number) => { diff --git a/packages/functions/src/cron/auction.cron.ts b/packages/functions/src/cron/auction.cron.ts index 5e2435eb34..d4d4056b4d 100644 --- a/packages/functions/src/cron/auction.cron.ts +++ b/packages/functions/src/cron/auction.cron.ts @@ -19,7 +19,7 @@ export const finalizeAuctions = async () => { .collection(COL.AUCTION) .where('auctionTo', '<=', dayjs().toDate()) .where('active', '==', true) - .get(); + .get(); const promises = snap.map((a) => { switch (a.type) { case AuctionType.NFT: @@ -36,7 +36,7 @@ const finalizeNftAuction = (auction: string) => const tranService = new TransactionService(transaction); const service = new AuctionFinalizeService(tranService); await service.markAsFinalized(auction); - tranService.submit(); + await tranService.submit(); }); const finalizeOpenAuction = async (auction: Auction) => { @@ -44,7 +44,7 @@ const finalizeOpenAuction = async (auction: Auction) => { let targetAddress = auction.targetAddress; if (!targetAddress) { - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${auction.createdBy}`); + const memberDocRef = build5Db().doc(COL.MEMBER, auction.createdBy!); const member = await memberDocRef.get(); targetAddress = getAddress(member, auction.network); } @@ -52,9 +52,9 @@ const finalizeOpenAuction = async (auction: Auction) => { const payments = await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.PAYMENT) - .where('payload.invalidPayment', '==', false) - .where('payload.auction', '==', auction.uid) - .get(); + .where('payload_invalidPayment', '==', false) + .where('payload_auction', '==', auction.uid) + .get(); for (const payment of payments) { const billPayment: Transaction = { @@ -75,7 +75,7 @@ const finalizeOpenAuction = async (auction: Auction) => { auction: auction.uid, }, }; - const billPaymentDocRef = build5Db().doc(`${COL.TRANSACTION}/${billPayment.uid}`); + const billPaymentDocRef = build5Db().doc(COL.TRANSACTION, billPayment.uid); batch.create(billPaymentDocRef, billPayment); } diff --git a/packages/functions/src/cron/award.cron.ts b/packages/functions/src/cron/award.cron.ts index 9c0646059b..12c3e1a936 100644 --- a/packages/functions/src/cron/award.cron.ts +++ b/packages/functions/src/cron/award.cron.ts @@ -1,5 +1,5 @@ import { build5Db } from '@build-5/database'; -import { Award, COL } from '@build-5/interfaces'; +import { COL } from '@build-5/interfaces'; import dayjs from 'dayjs'; export const processExpiredAwards = async () => { @@ -7,9 +7,9 @@ export const processExpiredAwards = async () => { .collection(COL.AWARD) .where('completed', '==', false) .where('endDate', '<=', dayjs().toDate()) - .get(); + .get(); const promises = snap.map(async (award) => { - const docRef = build5Db().doc(`${COL.AWARD}/${award.uid}`); + const docRef = build5Db().doc(COL.AWARD, award.uid); await docRef.update({ completed: true }); }); await Promise.all(promises); diff --git a/packages/functions/src/cron/bitfinex.cron.ts b/packages/functions/src/cron/bitfinex.cron.ts index 35c9e76a4b..a75831033b 100644 --- a/packages/functions/src/cron/bitfinex.cron.ts +++ b/packages/functions/src/cron/bitfinex.cron.ts @@ -1,6 +1,7 @@ import { build5Db } from '@build-5/database'; import { COL, TICKERS } from '@build-5/interfaces'; import axios from 'axios'; +import { logger } from '../utils/logger'; export const getLatestBitfinexPricesCron = async () => { try { @@ -14,19 +15,12 @@ export const getLatestBitfinexPricesCron = async () => { ).data; if (data[0][1] > 0) { - await build5Db().collection(COL.TICKER).doc(TICKERS.SMRUSD).set({ - uid: TICKERS.SMRUSD, - price: data[0][1], - }); + await build5Db().doc(COL.TICKER, TICKERS.SMRUSD).upsert({ price: data[0][1] }); } - if (data[1][1] > 0) { - await build5Db().collection(COL.TICKER).doc(TICKERS.IOTAUSD).set({ - uid: TICKERS.IOTAUSD, - price: data[1][1], - }); + await build5Db().doc(COL.TICKER, TICKERS.IOTAUSD).upsert({ price: data[1][1] }); } } catch (error) { - console.error('Failed to get latest prices. Try again in 5 minutes', error); + logger.error('Failed to get latest prices. Try again in 5 minutes', error); } }; diff --git a/packages/functions/src/cron/collection.floor.price.cron.ts b/packages/functions/src/cron/collection.floor.price.cron.ts index caa7706642..98448bc518 100644 --- a/packages/functions/src/cron/collection.floor.price.cron.ts +++ b/packages/functions/src/cron/collection.floor.price.cron.ts @@ -1,37 +1,5 @@ -import { build5Db, getSnapshot } from '@build-5/database'; -import { COL, Collection, Nft, NftAccess, NftAvailable } from '@build-5/interfaces'; -import { head, last } from 'lodash'; +import { build5Db } from '@build-5/database'; +import { COL } from '@build-5/interfaces'; -export const updateFloorPriceOnCollections = async () => { - let lastUid = ''; - do { - const lastDoc = await getSnapshot(COL.COLLECTION, lastUid); - const query = build5Db().collection(COL.COLLECTION).limit(400).startAfter(lastDoc); - const snap = await query.get(); - lastUid = last(snap)?.uid || ''; - - const batch = build5Db().batch(); - for (const collection of snap) { - const floorPrice = await updateCollectionFloorPrice(collection); - if (floorPrice !== undefined) { - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${collection.uid}`); - batch.update(collectionDocRef, { floorPrice }); - } - } - await batch.commit(); - - await new Promise((resolve) => setTimeout(resolve, 1000)); - } while (lastUid); -}; - -const updateCollectionFloorPrice = async (collection: Collection) => { - const snap = await build5Db() - .collection(COL.NFT) - .where('collection', '==', collection.uid) - .where('saleAccess', '==', NftAccess.OPEN) - .where('available', 'in', [NftAvailable.SALE, NftAvailable.AUCTION_AND_SALE]) - .orderBy('availablePrice') - .limit(1) - .get(); - return head(snap)?.availablePrice || undefined; -}; +export const updateFloorPriceOnCollections = () => + build5Db().collection(COL.COLLECTION).updateFloorPrice(); diff --git a/packages/functions/src/cron/media.cron.ts b/packages/functions/src/cron/media.cron.ts index 9d3a2f20b9..6a103193be 100644 --- a/packages/functions/src/cron/media.cron.ts +++ b/packages/functions/src/cron/media.cron.ts @@ -1,4 +1,4 @@ -import { build5Db } from '@build-5/database'; +import { ICollection, PgToken, PgTokenUpdate, build5Db } from '@build-5/database'; import { Award, COL, @@ -18,10 +18,13 @@ import { putCar, tokenToIpfsMetadata, } from '../utils/car.utils'; +import { logger } from '../utils/logger'; import { spaceToIpfsMetadata } from '../utils/space.utils'; export const MEDIA_UPLOAD_BACH_SIZE = 30; +type ColWithMedia = COL.NFT | COL.TOKEN | COL.COLLECTION | COL.AWARD | COL.SPACE | COL.STAMP; + export const uploadMediaToWeb3 = async () => { let batchSize = MEDIA_UPLOAD_BACH_SIZE; @@ -37,7 +40,7 @@ export const uploadMediaToWeb3 = async () => { const promises: Promise[] = []; for (const prop of props) { const upload = await uploadMedia( - prop.col, + prop.col as ColWithMedia, batchSize, prop.func as (data: unknown) => Promise, ); @@ -51,21 +54,21 @@ export const uploadMediaToWeb3 = async () => { }; const uploadMedia = async ( - col: COL, + col: ColWithMedia, batchSize: number, uploadFunc: (data: T) => Promise, ) => { if (!batchSize) { return { size: 0, promises: [] as Promise[] }; } - const snap = await pendingUploadQuery(col, batchSize).get>(); + const snap = await pendingUploadQuery(col, batchSize).get(); const promises = snap.map(async (data) => { try { await uploadFunc(data); } catch (error) { await setMediaStatusToError( col, - data.uid as string, + data.uid, (data.mediaUploadErrorCount as number) || 0, error, ); @@ -75,29 +78,40 @@ const uploadMedia = async ( }; const uploadNftMedia = async (nft: Nft) => { - const nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${nft.collection}`); - const collection = (await collectionDocRef.get())!; + const nftDocRef = build5Db().doc(COL.NFT, nft.uid); + const collectionDocRef = build5Db().doc(COL.COLLECTION, nft.collection); + const collection = (await collectionDocRef.get())!; const metadata = nftToIpfsMetadata(collection, nft); const { car, ...ipfs } = await downloadMediaAndPackCar(nft.uid, nft.media, metadata); await putCar(car); const batch = build5Db().batch(); - batch.update(collectionDocRef, { 'mintingData.nftMediaToUpload': build5Db().inc(-1) }); - batch.update(nftDocRef, { mediaStatus: MediaStatus.UPLOADED, ...ipfs }); + batch.update(collectionDocRef, { mintingData_nftMediaToUpload: build5Db().inc(-1) }); + + batch.update(nftDocRef, { + mediaStatus: MediaStatus.UPLOADED, + ipfsMedia: ipfs.ipfsMedia, + ipfsMetadata: ipfs.ipfsMetadata, + ipfsRoot: ipfs.ipfsRoot, + }); await batch.commit(); }; const uploadTokenMedia = async (token: Token) => { - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${token.uid}`); + const tokenDocRef = build5Db().doc(COL.TOKEN, token.uid); const metadata = tokenToIpfsMetadata(token); const { car, ...ipfs } = await downloadMediaAndPackCar(token.uid, token.icon!, metadata); await putCar(car); - await tokenDocRef.update({ mediaStatus: MediaStatus.UPLOADED, ...ipfs }); + await tokenDocRef.update({ + mediaStatus: MediaStatus.UPLOADED, + ipfsMedia: ipfs.ipfsMedia, + ipfsMetadata: ipfs.ipfsMetadata, + ipfsRoot: ipfs.ipfsRoot, + }); }; const uploadCollectionMedia = async (collection: Collection) => { - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${collection.uid}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, collection.uid); const metadata = collectionToIpfsMetadata(collection); const { car, ...ipfs } = await downloadMediaAndPackCar( collection.uid, @@ -106,55 +120,75 @@ const uploadCollectionMedia = async (collection: Collection) => { ); await putCar(car); - await collectionDocRef.update({ mediaStatus: MediaStatus.UPLOADED, ...ipfs }); + await collectionDocRef.update({ + mediaStatus: MediaStatus.UPLOADED, + ipfsMedia: ipfs.ipfsMedia, + ipfsMetadata: ipfs.ipfsMetadata, + ipfsRoot: ipfs.ipfsRoot, + }); }; const uploadAwardMedia = async (award: Award) => { if (!award.badge.image) { return; } - const awardDocRef = build5Db().doc(`${COL.AWARD}/${award.uid}`); + + const awardDocRef = build5Db().doc(COL.AWARD, award.uid); const metadata = awardToIpfsMetadata(award); const { car, ...ipfs } = await downloadMediaAndPackCar(award.uid, award.badge.image, metadata); await putCar(car); - await awardDocRef.update({ mediaStatus: MediaStatus.UPLOADED, ...ipfs }); + await awardDocRef.update({ + mediaStatus: MediaStatus.UPLOADED, + badge_ipfsMedia: ipfs.ipfsMedia, + badge_ipfsMetadata: ipfs.ipfsMetadata, + badge_ipfsRoot: ipfs.ipfsRoot, + }); }; const uploadSpaceMedia = async (space: Space) => { - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${space.uid}`); + const spaceDocRef = build5Db().doc(COL.SPACE, space.uid); const metadata = spaceToIpfsMetadata(space); const { car, ...ipfs } = await downloadMediaAndPackCar(space.uid, space.bannerUrl!, metadata); await putCar(car); - await spaceDocRef.update({ mediaStatus: MediaStatus.UPLOADED, ...ipfs }); + await spaceDocRef.update({ + mediaStatus: MediaStatus.UPLOADED, + ipfsMedia: ipfs.ipfsMedia, + ipfsMetadata: ipfs.ipfsMetadata, + ipfsRoot: ipfs.ipfsRoot, + }); }; const uploadStampMedia = async (stamp: Stamp) => { - const stampDocRef = build5Db().doc(`${COL.STAMP}/${stamp.uid}`); + const stampDocRef = build5Db().doc(COL.STAMP, stamp.uid); const { car, ...ipfs } = await downloadMediaAndPackCar(stamp.uid, stamp.build5Url); await putCar(car); - stampDocRef.update({ + await stampDocRef.update({ mediaStatus: MediaStatus.UPLOADED, ipfsMedia: ipfs.ipfsMedia, ipfsRoot: ipfs.ipfsRoot, }); }; -const pendingUploadQuery = (col: COL, batchSize: number) => - build5Db() - .collection(col) +const pendingUploadQuery = (col: ColWithMedia, batchSize: number) => + (build5Db().collection(col) as ICollection) .where('mediaStatus', '==', MediaStatus.PENDING_UPLOAD) .limit(batchSize); -const setMediaStatusToError = async (col: COL, uid: string, errorCount: number, error: unknown) => { +const setMediaStatusToError = async ( + col: ColWithMedia, + uid: string, + errorCount: number, + error: unknown, +) => { const data = { mediaUploadErrorCount: build5Db().inc(1), mediaStatus: MediaStatus.PENDING_UPLOAD, }; if (errorCount >= MAX_WALLET_RETRY) { data.mediaStatus = MediaStatus.ERROR; - console.error('Image upload error', col, uid, error); + logger.error('Image upload error', col, uid, error); } - const docRef = build5Db().doc(`${col}/${uid}`); + const docRef = build5Db().doc(col, uid); await docRef.update(data); }; diff --git a/packages/functions/src/cron/nft.cron.ts b/packages/functions/src/cron/nft.cron.ts index 5b105c05ff..04c432e2f8 100644 --- a/packages/functions/src/cron/nft.cron.ts +++ b/packages/functions/src/cron/nft.cron.ts @@ -1,5 +1,5 @@ import { build5Db } from '@build-5/database'; -import { COL, Nft } from '@build-5/interfaces'; +import { COL } from '@build-5/interfaces'; import dayjs from 'dayjs'; export const hidePlaceholderAfterSoldOutCron = async () => { @@ -10,7 +10,7 @@ export const hidePlaceholderAfterSoldOutCron = async () => { .where('availableFrom', '==', null) .where('hidden', '==', false) .where('owner', '==', null) - .get(); + .get(); for (const nft of snap) { if ( nft.soldOn && diff --git a/packages/functions/src/cron/nftStake.cron.ts b/packages/functions/src/cron/nftStake.cron.ts index 1ef8e04c61..6cebb5e2a6 100644 --- a/packages/functions/src/cron/nftStake.cron.ts +++ b/packages/functions/src/cron/nftStake.cron.ts @@ -1,38 +1,25 @@ -import { build5Db, getSnapshot } from '@build-5/database'; -import { COL, NftStake } from '@build-5/interfaces'; +import { build5Db } from '@build-5/database'; +import { COL } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { last } from 'lodash'; export const processExpiredNftStakes = async () => { - let lastDocId = ''; - do { - const query = await getExpiredNftStakesQuery(lastDocId); - const snap = await query.get(); - lastDocId = last(snap)?.uid || ''; - - const promises = snap.map((stake) => processExpiredNftStake(stake.uid)); - await Promise.all(promises); - } while (lastDocId); -}; - -const getExpiredNftStakesQuery = async (lastDocId = '') => { - const lastDoc = await getSnapshot(COL.NFT_STAKE, lastDocId); - return build5Db() + const snap = await build5Db() .collection(COL.NFT_STAKE) .where('expiresAt', '<=', dayjs().toDate()) .where('expirationProcessed', '==', false) - .startAfter(lastDoc) - .limit(1000); + .get(); + const promises = snap.map((stake) => processExpiredNftStake(stake.uid)); + await Promise.all(promises); }; -const processExpiredNftStake = async (nftStakeId: string) => +const processExpiredNftStake = (nftStakeId: string) => build5Db().runTransaction(async (transaction) => { - const nftStakeDocRef = build5Db().doc(`${COL.NFT_STAKE}/${nftStakeId}`); - const nftStake = (await transaction.get(nftStakeDocRef))!; + const nftStakeDocRef = build5Db().doc(COL.NFT_STAKE, nftStakeId); + const nftStake = (await transaction.get(nftStakeDocRef))!; if (!nftStake.expirationProcessed) { - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${nftStake.collection}`); - transaction.update(collectionDocRef, { stakedNft: build5Db().inc(-1) }); - transaction.update(nftStakeDocRef, { expirationProcessed: true }); + const collectionDocRef = build5Db().doc(COL.COLLECTION, nftStake.collection); + await transaction.update(collectionDocRef, { stakedNft: build5Db().inc(-1) }); + await transaction.update(nftStakeDocRef, { expirationProcessed: true }); } }); diff --git a/packages/functions/src/cron/orders.cron.ts b/packages/functions/src/cron/orders.cron.ts index 9b1c7cbe96..281d864ac2 100644 --- a/packages/functions/src/cron/orders.cron.ts +++ b/packages/functions/src/cron/orders.cron.ts @@ -1,5 +1,5 @@ import { build5Db } from '@build-5/database'; -import { COL, Transaction, TransactionType } from '@build-5/interfaces'; +import { COL, TransactionType } from '@build-5/interfaces'; import dayjs from 'dayjs'; import { NftPurchaseService } from '../services/payment/nft/nft-purchase.service'; import { TransactionService } from '../services/payment/transaction-service'; @@ -8,20 +8,20 @@ export const voidExpiredOrdersCron = async () => { const transactions = await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.ORDER) - .where('payload.void', '==', false) - .where('payload.reconciled', '==', false) - .where('payload.expiresOn', '<=', dayjs().toDate()) - .get(); + .where('payload_void', '==', false) + .where('payload_reconciled', '==', false) + .where('payload_expiresOn', '<=', dayjs().toDate()) + .get(); for (const tran of transactions) { await build5Db().runTransaction(async (transaction) => { - const tranDocRef = build5Db().doc(`${COL.TRANSACTION}/${tran.uid}`); - const tranData = (await transaction.get(tranDocRef))!; + const tranDocRef = build5Db().doc(COL.TRANSACTION, tran.uid); + const tranData = (await transaction.get(tranDocRef))!; const tranService = new TransactionService(transaction); const service = new NftPurchaseService(tranService); await service.markAsVoid(tranData); - tranService.submit(); + await tranService.submit(); }); } diff --git a/packages/functions/src/cron/proposal.cron.ts b/packages/functions/src/cron/proposal.cron.ts index ff2643772f..c25bb27289 100644 --- a/packages/functions/src/cron/proposal.cron.ts +++ b/packages/functions/src/cron/proposal.cron.ts @@ -1,5 +1,5 @@ import { build5Db } from '@build-5/database'; -import { COL, Proposal } from '@build-5/interfaces'; +import { COL } from '@build-5/interfaces'; import dayjs from 'dayjs'; export const markExpiredProposalCompleted = async () => { @@ -8,16 +8,16 @@ export const markExpiredProposalCompleted = async () => { const snap = await build5Db() .collection(COL.PROPOSAL) .where('completed', '==', false) - .where('settings.endDate', '<', dayjs().toDate()) + .where('settings_endDate', '<', dayjs().toDate()) .limit(500) - .get(); + .get(); size = snap.length; const batch = build5Db().batch(); - snap.forEach((proposal) => { - const proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${proposal.uid}`); + for (const proposal of snap) { + const proposalDocRef = build5Db().doc(COL.PROPOSAL, proposal.uid); batch.update(proposalDocRef, { completed: true }); - }); + } await batch.commit(); } while (size); }; diff --git a/packages/functions/src/cron/stake.cron.ts b/packages/functions/src/cron/stake.cron.ts index 5bbd682df0..78c0412de6 100644 --- a/packages/functions/src/cron/stake.cron.ts +++ b/packages/functions/src/cron/stake.cron.ts @@ -1,36 +1,23 @@ -import { build5Db, getSnapshot } from '@build-5/database'; -import { COL, Stake, SUB_COL } from '@build-5/interfaces'; +import { build5Db } from '@build-5/database'; +import { COL, SUB_COL } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { last } from 'lodash'; import { onStakeExpired } from '../services/stake.service'; -import { dateToTimestamp } from '../utils/dateTime.utils'; export const removeExpiredStakesFromSpace = async () => { - let lastDocId = ''; - do { - const query = await getExpiredStakeQuery(lastDocId); - const snap = await query.get(); - lastDocId = last(snap)?.uid || ''; - - const promises = snap.map((d) => updateTokenStakeStats(d.uid)); - await Promise.all(promises); - } while (lastDocId); -}; - -const getExpiredStakeQuery = async (lastDocId = '') => { - const lastDoc = await getSnapshot(COL.STAKE, lastDocId); - return build5Db() + const snap = await build5Db() .collection(COL.STAKE) - .where('expiresAt', '<=', dateToTimestamp(dayjs().toDate())) + .where('expiresAt', '<=', dayjs().toDate()) .where('expirationProcessed', '==', false) - .startAfter(lastDoc) - .limit(1000); + .get(); + + const promises = snap.map((d) => updateTokenStakeStats(d.uid)); + await Promise.all(promises); }; -const updateTokenStakeStats = async (stakeId: string) => +const updateTokenStakeStats = (stakeId: string) => build5Db().runTransaction(async (transaction) => { - const stakeDocRef = build5Db().doc(`${COL.STAKE}/${stakeId}`); - const stake = await transaction.get(stakeDocRef); + const stakeDocRef = build5Db().doc(COL.STAKE, stakeId); + const stake = (await transaction.get(stakeDocRef))!; if (stake.expirationProcessed) { return; } @@ -38,27 +25,20 @@ const updateTokenStakeStats = async (stakeId: string) => await onStakeExpired(transaction, stake); const updateData = { - stakes: { - [stake.type]: { - amount: build5Db().inc(-stake.amount), - value: build5Db().inc(-stake.value), - }, - }, - stakeExpiry: { - [stake.type]: { - [stake.expiresAt.toMillis()]: build5Db().deleteField(), - }, - }, + [`stakes_${stake.type}_amount`]: build5Db().inc(-stake.amount), + [`stakes_${stake.type}_value`]: build5Db().inc(-stake.value), + stakeExpiry: { [stake.type]: { [stake.expiresAt.toMillis()]: null } }, }; - const spaceDocRef = build5Db().doc( - `${COL.TOKEN}/${stake.token}/${SUB_COL.STATS}/${stake.token}`, - ); - transaction.set(spaceDocRef, updateData, true); - - const spaceMemberDocRef = build5Db().doc( - `${COL.TOKEN}/${stake.token}/${SUB_COL.DISTRIBUTION}/${stake.member}`, + const spaceDocRef = build5Db().doc(COL.TOKEN, stake.token, SUB_COL.STATS, stake.token); + await transaction.upsert(spaceDocRef, updateData); + + const distributionDocRef = build5Db().doc( + COL.TOKEN, + stake.token, + SUB_COL.DISTRIBUTION, + stake.member, ); - transaction.set(spaceMemberDocRef, updateData, true); + await transaction.upsert(distributionDocRef, updateData); - transaction.update(stakeDocRef, { expirationProcessed: true }); + await transaction.update(stakeDocRef, { expirationProcessed: true }); }); diff --git a/packages/functions/src/cron/stakeReward.cron.ts b/packages/functions/src/cron/stakeReward.cron.ts index dea051984f..e27c23410a 100644 --- a/packages/functions/src/cron/stakeReward.cron.ts +++ b/packages/functions/src/cron/stakeReward.cron.ts @@ -1,93 +1,63 @@ -import { build5Db, getSnapshot } from '@build-5/database'; +import { build5Db } from '@build-5/database'; import { COL, Entity, IgnoreWalletReason, SUB_COL, Space, - Stake, StakeReward, StakeRewardStatus, StakeType, Token, - TokenDistribution, TokenDrop, TokenDropStatus, Transaction, TransactionType, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { isEmpty, last } from 'lodash'; +import { isEmpty } from 'lodash'; import { getProject } from '../utils/common.utils'; -import { serverTime } from '../utils/dateTime.utils'; +import { logger } from '../utils/logger'; import { getRandomEthAddress } from '../utils/wallet.utils'; export const onStakeRewardExpired = async () => { const stakeRewards = await getDueStakeRewards(); for (const stakeReward of stakeRewards) { - const stakeRewardDocRef = build5Db().doc(`${COL.STAKE_REWARD}/${stakeReward.uid}`); + const stakeRewardDocRef = build5Db().doc(COL.STAKE_REWARD, stakeReward.uid); await stakeRewardDocRef.update({ status: StakeRewardStatus.PROCESSED }); try { const { totalAirdropped, totalStaked } = await executeStakeRewardDistribution(stakeReward); await stakeRewardDocRef.update({ totalStaked, totalAirdropped }); } catch (error) { - console.error('Stake reward error', stakeReward.uid, error); + logger.error('Stake reward error', stakeReward.uid, error); await stakeRewardDocRef.update({ status: StakeRewardStatus.ERROR }); } } }; const executeStakeRewardDistribution = async (stakeReward: StakeReward) => { - const stakedPerMember = await getStakedPerMember(stakeReward); + const stakedPerMember = await build5Db().collection(COL.STAKE).getStakeSumPerMember(stakeReward); if (isEmpty(stakedPerMember)) { await build5Db() - .doc(`${COL.STAKE_REWARD}/${stakeReward.uid}`) + .doc(COL.STAKE_REWARD, stakeReward.uid) .update({ status: StakeRewardStatus.PROCESSED_NO_STAKES }); return { totalStaked: 0, totalAirdropped: 0 }; } const totalStaked = Object.values(stakedPerMember).reduce((acc, act) => acc + act, 0); - const token = await build5Db().doc(`${COL.TOKEN}/${stakeReward.token}`).get(); + const token = await build5Db().doc(COL.TOKEN, stakeReward.token).get(); const totalAirdropped = await createAirdrops(token, stakeReward, totalStaked, stakedPerMember); return { totalStaked, totalAirdropped }; }; -export const getStakedPerMember = async (stakeReward: StakeReward) => { - const stakedPerMember: { [key: string]: number } = {}; - let lastDocId = ''; - const rewardEndDate = stakeReward.endDate.toDate(); - do { - const lastDoc = await getSnapshot(COL.STAKE, lastDocId); - const snap = await build5Db() - .collection(COL.STAKE) - .where('token', '==', stakeReward.token) - .where('type', '==', StakeType.DYNAMIC) - .where('expiresAt', '>=', stakeReward.startDate) - .orderBy('expiresAt') - .startAfter(lastDoc) - .limit(2000) - .select('createdOn', 'member', 'value') - .get(); - lastDocId = last(snap)?.uid || ''; - snap.forEach((stake) => { - if (dayjs(stake.createdOn?.toDate()).isAfter(rewardEndDate)) { - return; - } - stakedPerMember[stake.member] = (stakedPerMember[stake.member] || 0) + stake.value; - }); - } while (lastDocId); - - return stakedPerMember; -}; - const getDueStakeRewards = () => build5Db() .collection(COL.STAKE_REWARD) .where('status', '==', StakeRewardStatus.UNPROCESSED) - .where('endDate', '<=', serverTime()) - .get(); + .where('endDate', '<=', dayjs().toDate()) + .get(); const createAirdrops = async ( token: Token, @@ -95,7 +65,7 @@ const createAirdrops = async ( totalStaked: number, stakedPerMember: { [key: string]: number }, ) => { - const space = await build5Db().doc(`${COL.SPACE}/${token.space}`).get(); + const space = await build5Db().doc(COL.SPACE, token.space!).get(); const rewards = Object.entries(stakedPerMember) .map(([member, staked]) => ({ @@ -120,15 +90,16 @@ const createAirdrops = async ( } const distributionDocRef = build5Db().doc( - `${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${reward.member}`, + COL.TOKEN, + token.uid, + SUB_COL.DISTRIBUTION, + reward.member, ); - const distribution = await distributionDocRef.get(); + const distribution = await distributionDocRef.get(); if (distribution?.extraStakeRewards && distribution.extraStakeRewards > 0) { await distributionDocRef.update({ parentId: token.uid, - parentCol: COL.TOKEN, - uid: reward.member, extraStakeRewards: build5Db().inc(-reward.value), }); @@ -154,7 +125,7 @@ const createAirdrops = async ( stakeReward: stakeReward.uid, }, }; - await build5Db().doc(`${COL.TRANSACTION}/${billPayment.uid}`).create(billPayment); + await build5Db().doc(COL.TRANSACTION, billPayment.uid).create(billPayment); const remainingExtra = distribution.extraStakeRewards - reward.value; if (remainingExtra >= 0) { @@ -178,19 +149,13 @@ const createAirdrops = async ( stakeType: StakeType.DYNAMIC, }; - const airdropDocRef = build5Db().doc(`${COL.AIRDROP}/${airdrop.uid}`); + const airdropDocRef = build5Db().doc(COL.AIRDROP, airdrop.uid); batch.create(airdropDocRef, airdrop); - batch.set( - distributionDocRef, - { - parentId: token.uid, - parentCol: COL.TOKEN, - uid: reward.member, - stakeRewards: build5Db().inc(reward.value), - }, - true, - ); + batch.upsert(distributionDocRef, { + parentId: token.uid, + stakeRewards: build5Db().inc(reward.value), + }); await batch.commit(); return reward.value; diff --git a/packages/functions/src/cron/stamp.cron.ts b/packages/functions/src/cron/stamp.cron.ts index 939b9d3798..9322606bc2 100644 --- a/packages/functions/src/cron/stamp.cron.ts +++ b/packages/functions/src/cron/stamp.cron.ts @@ -7,12 +7,12 @@ import { getBucket } from '../utils/config.utils'; export const updateExpiredStamp = async () => { let stamps: Stamp[] = []; do { - stamps = await query.get(); + stamps = await query.get(); const batch = build5Db().batch(); - stamps.forEach((s) => { - const docRef = build5Db().doc(`${COL.STAMP}/${s.uid}`); + for (const s of stamps) { + const docRef = build5Db().doc(COL.STAMP, s.uid); batch.update(docRef, { expired: true }); - }); + } await batch.commit(); const promises = stamps.map(async (s) => { diff --git a/packages/functions/src/cron/token.cron.ts b/packages/functions/src/cron/token.cron.ts index d39218887a..e1addff9b8 100644 --- a/packages/functions/src/cron/token.cron.ts +++ b/packages/functions/src/cron/token.cron.ts @@ -1,49 +1,40 @@ import { build5Db } from '@build-5/database'; -import { - COL, - Token, - TokenStatus, - TokenTradeOrder, - TokenTradeOrderStatus, -} from '@build-5/interfaces'; +import { COL, TokenStatus, TokenTradeOrderStatus } from '@build-5/interfaces'; import dayjs from 'dayjs'; import { isEmpty } from 'lodash'; import { guardedRerun } from '../utils/common.utils'; -import { dateToTimestamp, serverTime } from '../utils/dateTime.utils'; import { cancelTradeOrderUtil } from '../utils/token-trade.utils'; export const tokenCoolDownOver = async () => { const tokens = await build5Db() .collection(COL.TOKEN) .where('status', '==', TokenStatus.AVAILABLE) - .where('coolDownEnd', '<=', dateToTimestamp(dayjs().toDate())) - .get(); - const promises = tokens.map((token) => { - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${token.uid}`); - tokenDocRef.update({ status: TokenStatus.PROCESSING }); + .where('coolDownEnd', '<=', dayjs().toDate()) + .get(); + const promises = tokens.map(async (token) => { + const tokenDocRef = build5Db().doc(COL.TOKEN, token.uid); + await tokenDocRef.update({ status: TokenStatus.PROCESSING }); }); return Promise.allSettled(promises); }; export const cancelExpiredSale = async () => { - const runTransaction = () => + const runTransactions = () => build5Db().runTransaction(async (transaction) => { const snap = await build5Db() .collection(COL.TOKEN_MARKET) .where('status', '==', TokenTradeOrderStatus.ACTIVE) - .where('expiresAt', '<=', serverTime()) + .where('expiresAt', '<=', dayjs().toDate()) .orderBy('expiresAt') .limit(150) - .get(); - const docRefs = snap.map((order) => build5Db().doc(`${COL.TOKEN_MARKET}/${order.uid}`)); - const promises = ( - isEmpty(docRefs) ? [] : await transaction.getAll(...docRefs) - ) + .get(); + const docRefs = snap.map((order) => build5Db().doc(COL.TOKEN_MARKET, order.uid)); + const promises = (isEmpty(docRefs) ? [] : await transaction.getAll(...docRefs)) .filter((d) => d!.status === TokenTradeOrderStatus.ACTIVE) .map((d) => cancelTradeOrderUtil(transaction, d!, TokenTradeOrderStatus.EXPIRED)); return (await Promise.all(promises)).length; }); - await guardedRerun(async () => (await runTransaction()) !== 0); + await guardedRerun(async () => (await runTransactions()) !== 0); }; diff --git a/packages/functions/src/cron/token.purchase.cron.ts b/packages/functions/src/cron/token.purchase.cron.ts index b88976908a..5e91b1b707 100644 --- a/packages/functions/src/cron/token.purchase.cron.ts +++ b/packages/functions/src/cron/token.purchase.cron.ts @@ -1,5 +1,5 @@ import { build5Db } from '@build-5/database'; -import { COL, SUB_COL, TokenPurchase, TokenPurchaseAge } from '@build-5/interfaces'; +import { COL, SUB_COL, TokenPurchaseAge } from '@build-5/interfaces'; import dayjs from 'dayjs'; import { chunk } from 'lodash'; @@ -15,12 +15,12 @@ const removeExiredPurchaseFromStats = async (age: TokenPurchaseAge) => { for (const purchases of chunks) { const batch = build5Db().batch(); for (const purchase of purchases) { - const docRef = build5Db().doc(`${COL.TOKEN_PURCHASE}/${purchase.uid}`); - batch.set(docRef, { age: build5Db().arrayRemove(age) }, true); + const docRef = build5Db().doc(COL.TOKEN_PURCHASE, purchase.uid); + batch.update(docRef, { [age]: false }); const token = purchase.token; - const statsDocRef = build5Db().doc(`${COL.TOKEN}/${token}/${SUB_COL.STATS}/${token}`); - batch.set(statsDocRef, { volume: { [age]: build5Db().inc(-purchase.count) } }, true); + const statsDocRef = build5Db().doc(COL.TOKEN, token, SUB_COL.STATS, token); + batch.upsert(statsDocRef, { [`volume_${age}`]: build5Db().inc(-purchase.count) }); } await batch.commit(); } @@ -31,9 +31,9 @@ const getExpiredPurchases = (age: TokenPurchaseAge) => { const createdBefore = dayjs().subtract(days, 'd').toDate(); return build5Db() .collection(COL.TOKEN_PURCHASE) - .where('age', 'array-contains', age) + .where(age, '==', true) .where('createdOn', '<=', createdBefore) - .get(); + .get(); }; const toknePurchaseAgeToDayCount = (age: TokenPurchaseAge) => { diff --git a/packages/functions/src/cron/wallet.cron.ts b/packages/functions/src/cron/wallet.cron.ts index 8bab48bca0..1248dbb7a8 100644 --- a/packages/functions/src/cron/wallet.cron.ts +++ b/packages/functions/src/cron/wallet.cron.ts @@ -11,8 +11,8 @@ export const retryWallet = async () => { const snap = await getFailedTransactionsSnap(); const promises = snap.map((doc) => build5Db().runTransaction(async (transaction) => { - const docRef = build5Db().doc(`${COL.TRANSACTION}/${doc.uid}`); - const tran = (await transaction.get(docRef))!; + const docRef = build5Db().doc(COL.TRANSACTION, doc.uid); + const tran = (await transaction.get(docRef))!; return await rerunTransaction(transaction, tran); }), ); @@ -20,7 +20,7 @@ export const retryWallet = async () => { }; const rerunTransaction = async (transaction: ITransaction, data: Transaction) => { - const docRef = build5Db().doc(`${COL.TRANSACTION}/${data.uid}`); + const docRef = build5Db().doc(COL.TRANSACTION, data.uid); const walletReference = data.payload.walletReference!; const processedOn = dayjs(walletReference.processedOn.toDate()); const delay = RETRY_UNCOFIRMED_PAYMENT_DELAY[(walletReference.count || 1) - 1]; @@ -30,8 +30,8 @@ const rerunTransaction = async (transaction: ITransaction, data: Transaction) => } if (walletReference.count === MAX_WALLET_RETRY) { - const sourceMnemonicDocRef = build5Db().doc(`${COL.MNEMONIC}/${data.payload.sourceAddress}`); - transaction.update(sourceMnemonicDocRef, { + const sourceMnemonicDocRef = build5Db().doc(COL.MNEMONIC, data.payload.sourceAddress!); + await transaction.update(sourceMnemonicDocRef, { lockedBy: '', consumedOutputIds: [], consumedNftOutputIds: [], @@ -39,35 +39,34 @@ const rerunTransaction = async (transaction: ITransaction, data: Transaction) => }); if (data.payload.storageDepositSourceAddress) { const storageSourceDocRef = build5Db().doc( - `${COL.MNEMONIC}/${data.payload.storageDepositSourceAddress}`, + COL.MNEMONIC, + data.payload.storageDepositSourceAddress, ); - transaction.update(storageSourceDocRef, { + await transaction.update(storageSourceDocRef, { lockedBy: '', consumedOutputIds: [], consumedNftOutputIds: [], consumedAliasOutputIds: [], }); } - transaction.update(docRef, { - 'payload.walletReference.chainReference': null, - 'payload.walletReference.inProgress': false, - 'payload.walletReference.count': build5Db().inc(1), + await transaction.update(docRef, { + payload_walletReference_chainReference: undefined, + payload_walletReference_inProgress: false, + payload_walletReference_count: build5Db().inc(1), shouldRetry: false, }); } - transaction.update(docRef, { - 'payload.walletReference.chainReference': null, + await transaction.update(docRef, { + payload_walletReference_chainReference: undefined, shouldRetry: true, }); return data.uid; }; -const COUNT_IN = Array.from(Array(MAX_WALLET_RETRY + 1)).map((_, i) => i); - const getFailedTransactionsSnap = () => build5Db() .collection(COL.TRANSACTION) - .where('payload.walletReference.confirmed', '==', false) - .where('payload.walletReference.inProgress', '==', true) - .where('payload.walletReference.count', 'in', COUNT_IN) - .get(); + .where('payload_walletReference_confirmed', '==', false) + .where('payload_walletReference_inProgress', '==', true) + .where('payload_walletReference_count', '<=', MAX_WALLET_RETRY) + .get(); diff --git a/packages/functions/src/index.express.ts b/packages/functions/src/index.express.ts deleted file mode 100644 index 4eab507c2d..0000000000 --- a/packages/functions/src/index.express.ts +++ /dev/null @@ -1,101 +0,0 @@ -/* eslint-disable import/namespace */ -/* eslint-disable @typescript-eslint/no-var-requires */ -require('dotenv').config({ path: __dirname + '/.env' }); -import { WEN_FUNC } from '@build-5/interfaces'; -import { HTTP } from 'cloudevents'; -import cors from 'cors'; -import express from 'express'; -import { get } from 'lodash'; -import { loadSync } from 'protobufjs'; -import { flattenObject } from './common'; -import { pathToParts } from './runtime/common'; -import * as onScheduled from './runtime/cron/index'; -import { ScheduledFunction } from './runtime/cron/scheduled'; -import { HttpsFunction } from './runtime/https/https'; -import * as onRequests from './runtime/https/index'; -import { protoToJson } from './runtime/proto/protoToJson'; -import * as onStorage from './runtime/storage/index'; -import { StorageFunction } from './runtime/storage/storage'; -import * as onTriggers from './runtime/trigger/index'; -import { TriggeredFunction } from './runtime/trigger/trigger'; - -const app = express(); - -app.use(cors()); - -const httpRawParser = express.raw({ type: '*/*', limit: '100mb' }); -const protoRawParser = express.raw({ type: 'application/protobuf', limit: '2mb' }); -const jsonParser = express.json(); - -// HTTPS -Object.entries(flattenObject(onRequests)).forEach(([name, config]) => { - app.post(`/${name}`, name === WEN_FUNC.uploadFile ? httpRawParser : jsonParser, (req, res) => - (config as HttpsFunction).func(req, res), - ); -}); - -// TRIGGERS -Object.entries(flattenObject(onTriggers)).forEach(([name, config]) => { - app.post(`/${name}`, protoRawParser, async (req, res) => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let json: { [key: string]: any } = {}; - try { - const root = loadSync('./data.proto'); - const type = root.lookupType('DocumentEventData'); - const decoded = type.decode(req.body); - json = protoToJson(decoded); - const cloudEvent = HTTP.toEvent({ - headers: req.headers, - body: {}, - }); - const event = { - prev: json.oldValue?.fields, - curr: json.value?.fields, - path: get(cloudEvent, 'document', ''), - ...pathToParts(get(cloudEvent, 'document', '')), - }; - await (config as TriggeredFunction).handler(event); - } catch (error) { - console.error('onTriggers-error', name, JSON.stringify(json), error); - } finally { - res.sendStatus(200); - } - }); -}); - -// CRON -Object.entries(flattenObject(onScheduled)).forEach(([name, config]) => { - app.post(`/${name}`, async (_, res) => { - try { - await (config as ScheduledFunction).func(); - } catch (error) { - console.error('onScheduled-error', name, error); - } finally { - res.sendStatus(200); - } - }); -}); - -// Storage -Object.entries(flattenObject(onStorage)).forEach(([name, config]) => { - app.post(`/${name}`, express.json(), async (req, res) => { - try { - const event = HTTP.toEvent({ - headers: req.headers, - body: req.body, - }); - await (config as StorageFunction).func({ - metadata: get(event, 'data.metadata'), - name: get(event, 'data.name', ''), - bucket: get(event, 'data.bucket', ''), - contentType: get(event, 'data.contentType'), - }); - } catch (error) { - console.error('onStorage-error', name, error); - } finally { - res.sendStatus(200); - } - }); -}); - -app.listen(8080).setTimeout(0); diff --git a/packages/functions/src/index.ts b/packages/functions/src/index.ts index fedcfa1040..3362649e62 100644 --- a/packages/functions/src/index.ts +++ b/packages/functions/src/index.ts @@ -1,71 +1,155 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable import/namespace */ -import * as functions from 'firebase-functions/v2'; +/* eslint-disable @typescript-eslint/no-var-requires */ +require('dotenv').config({ path: __dirname + '/.env' }); +import { BaseRecord, PgChanges, build5Db } from '@build-5/database'; +import { WEN_FUNC } from '@build-5/interfaces'; +import cors from 'cors'; +import dayjs from 'dayjs'; +import express from 'express'; +import { get, head } from 'lodash'; import { flattenObject } from './common'; -import { CloudFunctions, pathToParts } from './runtime/common'; +import * as onScheduled from './runtime/cron/index'; +import { ScheduledFunction } from './runtime/cron/scheduled'; import { HttpsFunction } from './runtime/https/https'; import * as onRequests from './runtime/https/index'; import * as onStorage from './runtime/storage/index'; import { StorageFunction } from './runtime/storage/storage'; import * as onTriggers from './runtime/trigger/index'; -import { TriggeredFunction, TriggeredFunctionType } from './runtime/trigger/trigger'; - -// On request functions -const toOnRequest = (config: HttpsFunction) => - functions.https.onRequest((req, res) => config.func(req, res)); - -export const https = Object.entries(flattenObject(onRequests)).reduce( - (acc, [name, config]) => ({ ...acc, [name]: toOnRequest(config as HttpsFunction) }), - {} as any, -); - -// Trigger functions -const getFirestoreHandler = (config: TriggeredFunction) => { - const triggerConfig = { - document: config.document, - timeoutSeconds: config.runtimeOptions.timeoutSeconds, - }; - if (config.type === TriggeredFunctionType.ON_CREATE) { - return functions.firestore.onDocumentCreated(triggerConfig, async (event) => { - const data = { - curr: event.data?.data(), - path: event.document, - ...pathToParts(event.document), +import { TriggeredFunction } from './runtime/trigger/trigger'; +import { tangleClients } from './services/wallet/wallet.service'; +import { PgDocEvent } from './triggers/common'; +import { isEmulatorEnv } from './utils/config.utils'; +import { logger } from './utils/logger'; +import { traceMiddleware } from './utils/trace'; + +const app = express(); + +app.use(cors()); +app.use(traceMiddleware); + +const httpRawParser = express.raw({ type: '*/*', limit: '100mb' }); +const jsonParser = express.json(); + +const loggingMiddleware = (name: string) => + isEmulatorEnv() + ? (_req: express.Request, res: express.Response, next: express.NextFunction) => { + const start = dayjs(); + console.log(`Beginning ${name}`); + next(); + res.once('finish', () => { + const end = dayjs(); + console.log(`Finished ${name} in ${end.diff(start)} ms`); + }); + } + : (_req: express.Request, _res: express.Response, next: express.NextFunction) => { + next(); }; - await config.handler(data); - }); - } - const firestoreFunc = - config.type === TriggeredFunctionType.ON_UPDATE - ? functions.firestore.onDocumentUpdated - : functions.firestore.onDocumentWritten; - return firestoreFunc(triggerConfig, async (event) => { - const data = { - prev: event.data?.before?.data(), - curr: event.data?.after?.data(), - path: event.document, - ...pathToParts(event.document), - }; - await config.handler(data); + +// HTTPS +Object.entries(flattenObject(onRequests)).forEach(([name, config]) => { + app.post( + `/${name}`, + name === WEN_FUNC.uploadFile ? httpRawParser : jsonParser, + loggingMiddleware(name), + (req, res) => (config as HttpsFunction).func(req, res), + ); +}); + +// TRIGGERS +Object.entries(flattenObject(onTriggers)).forEach(([name, config]) => { + app.post(`/${name}`, jsonParser, loggingMiddleware(name), async (req, res) => { + const pubSubMessage = req.body.message.data; + const raw = Buffer.from(pubSubMessage, 'base64').toString().trim(); + const processId = JSON.parse(raw).processId; + let snap: PgChanges | undefined = undefined; + + const docRef = build5Db().getCon()('changes').where({ uid: processId }); + try { + snap = head(await docRef); + if (!snap) { + return; + } + + await docRef.delete(); + + await (config as TriggeredFunction).handler({ + ...snap.change, + prev: snap.change!.prev || undefined, + curr: snap.change!.curr || undefined, + } as PgDocEvent); + } catch (error) { + logger.error('onTriggers-error', name, snap, error); + } finally { + res.sendStatus(200); + } }); -}; -export const triggers = Object.entries(flattenObject(onTriggers)).reduce( - (acc, [key, config]) => ({ ...acc, [key]: getFirestoreHandler(config) }), - {} as any, -); +}); + +// CRON +Object.entries(flattenObject(onScheduled)).forEach(([name, config]) => { + app.post(`/${name}`, async (_, res) => { + try { + await (config as ScheduledFunction).func(); + } catch (error) { + logger.error('onScheduled-error', name, error); + } finally { + res.sendStatus(200); + } + }); +}); // Storage -export const stroage = Object.entries(flattenObject(onStorage)).reduce((acc, [name, value]) => { - const config = (value as CloudFunctions).runtimeOptions; - return { - ...acc, - [name]: functions.storage.onObjectFinalized({ bucket: config.bucket! }, (event) => - (value as StorageFunction).func({ - metadata: event.data.metadata, - name: event.data.name, - bucket: event.data.bucket, - contentType: event.data.contentType, - }), - ), - }; -}, {} as any); +Object.entries(flattenObject(onStorage)).forEach(([name, config]) => { + app.post(`/${name}`, jsonParser, loggingMiddleware(name), async (req, res) => { + try { + await (config as StorageFunction).func({ + metadata: get(req, 'body.metadata'), + name: get(req, 'body.name', ''), + bucket: get(req, 'body.bucket', ''), + contentType: get(req, 'body.contentType'), + }); + } catch (error) { + logger.error('onStorage-error', name, error); + } finally { + res.sendStatus(200); + } + }); +}); + +app.head('/', (_, res) => { + res.sendStatus(200); +}); + +app.on('close', async () => { + await build5Db().destroy(); +}); + +const server = app.listen(8080).setTimeout(0); + +process.on('exit', async () => { + await cleanup(); +}); + +process.on('SIGINT', () => { + server.close(async () => { + await cleanup(); + process.exit(0); + }); +}); + +process.on('uncaughtException', async () => { + await cleanup(); + process.exit(1); +}); + +process.on('unhandledRejection', async () => { + await cleanup(); + process.exit(1); +}); + +const cleanup = async () => { + await build5Db().destroy(); + for (const client of Object.values(tangleClients)) { + await client.destroy(); + } +}; diff --git a/packages/functions/src/runtime/common.ts b/packages/functions/src/runtime/common.ts index 24656650ea..79a43fb09c 100644 --- a/packages/functions/src/runtime/common.ts +++ b/packages/functions/src/runtime/common.ts @@ -1,7 +1,7 @@ import { COL, SUB_COL } from '@build-5/interfaces'; export enum WEN_FUNC_TRIGGER { - onProposalWrite = 'onproposaluwrite', + onProposalWrite = 'onproposalwrite', onAwardUpdated = 'onawardupdated', onCollectionUpdated = 'oncollectionupdated', onTokenStatusUpdated = 'ontokenstatusupdated', diff --git a/packages/functions/src/runtime/firebase/address/index.ts b/packages/functions/src/runtime/firebase/address/index.ts deleted file mode 100644 index 71b1832c5d..0000000000 --- a/packages/functions/src/runtime/firebase/address/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { WEN_FUNC } from '@build-5/interfaces'; -import { https } from '../../..'; - -export const validateAddress = https[WEN_FUNC.validateAddress]; diff --git a/packages/functions/src/runtime/firebase/auction/index.ts b/packages/functions/src/runtime/firebase/auction/index.ts deleted file mode 100644 index 22975354e3..0000000000 --- a/packages/functions/src/runtime/firebase/auction/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -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/firebase/auth/index.ts b/packages/functions/src/runtime/firebase/auth/index.ts deleted file mode 100644 index f931291c29..0000000000 --- a/packages/functions/src/runtime/firebase/auth/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { WEN_FUNC } from '@build-5/interfaces'; -import { https } from '../../..'; - -export const generateCustomToken = https[WEN_FUNC.generateCustomToken]; diff --git a/packages/functions/src/runtime/firebase/award/index.ts b/packages/functions/src/runtime/firebase/award/index.ts deleted file mode 100644 index 95f2197719..0000000000 --- a/packages/functions/src/runtime/firebase/award/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { WEN_FUNC } from '@build-5/interfaces'; -import { https } from '../../..'; - -export const createAward = https[WEN_FUNC.createAward]; -export const addOwnerAward = https[WEN_FUNC.addOwnerAward]; -export const fundAward = https[WEN_FUNC.fundAward]; -export const rejectAward = https[WEN_FUNC.rejectAward]; -export const cancelAward = https[WEN_FUNC.cancelAward]; -export const awardParticipate = https[WEN_FUNC.participateAward]; -export const approveAwardParticipant = https[WEN_FUNC.approveParticipantAward]; diff --git a/packages/functions/src/runtime/firebase/collection/index.ts b/packages/functions/src/runtime/firebase/collection/index.ts deleted file mode 100644 index e312fe2986..0000000000 --- a/packages/functions/src/runtime/firebase/collection/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { WEN_FUNC } from '@build-5/interfaces'; -import { https } from '../../..'; - -export const createCollection = https[WEN_FUNC.createCollection]; -export const updateCollection = https[WEN_FUNC.updateCollection]; -export const rejectCollection = https[WEN_FUNC.rejectCollection]; -export const mintCollection = https[WEN_FUNC.mintCollection]; diff --git a/packages/functions/src/runtime/firebase/credit/index.ts b/packages/functions/src/runtime/firebase/credit/index.ts deleted file mode 100644 index 959dfd69e5..0000000000 --- a/packages/functions/src/runtime/firebase/credit/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { WEN_FUNC } from '@build-5/interfaces'; -import { https } from '../../..'; - -export const creditUnrefundable = https[WEN_FUNC.creditUnrefundable]; diff --git a/packages/functions/src/runtime/firebase/member/index.ts b/packages/functions/src/runtime/firebase/member/index.ts deleted file mode 100644 index a4be6082ea..0000000000 --- a/packages/functions/src/runtime/firebase/member/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { WEN_FUNC } from '@build-5/interfaces'; -import { https } from '../../..'; - -export const createMember = https[WEN_FUNC.createMember]; -export const updateMember = https[WEN_FUNC.updateMember]; diff --git a/packages/functions/src/runtime/firebase/nft/index.ts b/packages/functions/src/runtime/firebase/nft/index.ts deleted file mode 100644 index 1140e422a5..0000000000 --- a/packages/functions/src/runtime/firebase/nft/index.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { WEN_FUNC } from '@build-5/interfaces'; -import { https } from '../../..'; - -export const createNft = https[WEN_FUNC.createNft]; - -export const createBatchNft = https[WEN_FUNC.createBatchNft]; - -export const updateUnsoldNft = https[WEN_FUNC.updateUnsoldNft]; -export const setForSaleNft = https[WEN_FUNC.setForSaleNft]; - -export const withdrawNft = https[WEN_FUNC.withdrawNft]; - -export const depositNft = https[WEN_FUNC.depositNft]; - -export const orderNft = https[WEN_FUNC.orderNft]; - -export const orderNftBulk = https[WEN_FUNC.orderNftBulk]; - -export const stakeNft = https[WEN_FUNC.stakeNft]; - -export const openBid = https[WEN_FUNC.openBid]; - -export const nftTransfer = https[WEN_FUNC.nftTransfer]; - -export const mintMetadataNft = https[WEN_FUNC.mintMetadataNft]; diff --git a/packages/functions/src/runtime/firebase/project/index.ts b/packages/functions/src/runtime/firebase/project/index.ts deleted file mode 100644 index f125e76c37..0000000000 --- a/packages/functions/src/runtime/firebase/project/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { WEN_FUNC } from '@build-5/interfaces'; -import { https } from '../../..'; - -export const createProject = https[WEN_FUNC.createProject]; -export const deactivateProject = https[WEN_FUNC.deactivateProject]; diff --git a/packages/functions/src/runtime/firebase/proposal/index.ts b/packages/functions/src/runtime/firebase/proposal/index.ts deleted file mode 100644 index e50d70f617..0000000000 --- a/packages/functions/src/runtime/firebase/proposal/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { WEN_FUNC } from '@build-5/interfaces'; -import { https } from '../../..'; - -export const createProposal = https[WEN_FUNC.createProposal]; -export const approveProposal = https[WEN_FUNC.approveProposal]; -export const rejectProposal = https[WEN_FUNC.rejectProposal]; -export const voteOnProposal = https[WEN_FUNC.voteOnProposal]; diff --git a/packages/functions/src/runtime/firebase/rank/index.ts b/packages/functions/src/runtime/firebase/rank/index.ts deleted file mode 100644 index 3126101bd0..0000000000 --- a/packages/functions/src/runtime/firebase/rank/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { WEN_FUNC } from '@build-5/interfaces'; -import { https } from '../../..'; - -export const rankController = https[WEN_FUNC.rankController]; diff --git a/packages/functions/src/runtime/firebase/space/index.ts b/packages/functions/src/runtime/firebase/space/index.ts deleted file mode 100644 index 3c91c0a176..0000000000 --- a/packages/functions/src/runtime/firebase/space/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { WEN_FUNC } from '@build-5/interfaces'; -import { https } from '../../..'; - -export const createSpace = https[WEN_FUNC.createSpace]; - -export const addGuardian = https[WEN_FUNC.addGuardianSpace]; - -export const removeGuardian = https[WEN_FUNC.removeGuardianSpace]; -export const acceptMemberSpace = https[WEN_FUNC.acceptMemberSpace]; - -export const blockMember = https[WEN_FUNC.blockMemberSpace]; - -export const declineMemberSpace = https[WEN_FUNC.declineMemberSpace]; -export const unblockMember = https[WEN_FUNC.unblockMemberSpace]; - -export const updateSpace = https[WEN_FUNC.updateSpace]; - -export const leaveSpace = https[WEN_FUNC.leaveSpace]; - -export const joinSpace = https[WEN_FUNC.joinSpace]; - -export const claimSpace = https[WEN_FUNC.claimSpace]; diff --git a/packages/functions/src/runtime/firebase/stake/index.ts b/packages/functions/src/runtime/firebase/stake/index.ts deleted file mode 100644 index 392f7096e4..0000000000 --- a/packages/functions/src/runtime/firebase/stake/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { WEN_FUNC } from '@build-5/interfaces'; -import { https } from '../../..'; - -export const depositStake = https[WEN_FUNC.depositStake]; -export const stakeReward = https[WEN_FUNC.stakeReward]; -export const removeStakeReward = https[WEN_FUNC.removeStakeReward]; diff --git a/packages/functions/src/runtime/firebase/stamp/index.ts b/packages/functions/src/runtime/firebase/stamp/index.ts deleted file mode 100644 index 402ef4fec3..0000000000 --- a/packages/functions/src/runtime/firebase/stamp/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { WEN_FUNC } from '@build-5/interfaces'; -import { https } from '../../..'; - -export const stamp = https[WEN_FUNC.stamp]; diff --git a/packages/functions/src/runtime/firebase/storage/file.upload.ts b/packages/functions/src/runtime/firebase/storage/file.upload.ts deleted file mode 100644 index 2660d6f4c6..0000000000 --- a/packages/functions/src/runtime/firebase/storage/file.upload.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { WEN_FUNC } from '@build-5/interfaces'; -import { https } from '../../..'; - -export const uploadFile = https[WEN_FUNC.uploadFile]; diff --git a/packages/functions/src/runtime/firebase/swap/index.ts b/packages/functions/src/runtime/firebase/swap/index.ts deleted file mode 100644 index 05360009a5..0000000000 --- a/packages/functions/src/runtime/firebase/swap/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { WEN_FUNC } from '@build-5/interfaces'; -import { https } from '../../..'; - -export const createSwap = https[WEN_FUNC.createSwap]; - -export const setSwapFunded = https[WEN_FUNC.setSwapFunded]; - -export const rejectSwap = https[WEN_FUNC.rejectSwap]; diff --git a/packages/functions/src/runtime/firebase/token/base/index.ts b/packages/functions/src/runtime/firebase/token/base/index.ts deleted file mode 100644 index 2c34bd0a52..0000000000 --- a/packages/functions/src/runtime/firebase/token/base/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { WEN_FUNC } from '@build-5/interfaces'; -import { https } from '../../../..'; - -export const createToken = https[WEN_FUNC.createToken]; - -export const updateToken = https[WEN_FUNC.updateToken]; - -export const setTokenAvailableForSale = https[WEN_FUNC.setTokenAvailableForSale]; - -export const cancelPublicSale = https[WEN_FUNC.cancelPublicSale]; - -export const creditToken = https[WEN_FUNC.creditToken]; - -export const orderToken = https[WEN_FUNC.orderToken]; - -export const enableTokenTrading = https[WEN_FUNC.enableTokenTrading]; - -export const airdropToken = https[WEN_FUNC.airdropToken]; - -export const claimAirdroppedToken = https[WEN_FUNC.claimAirdroppedToken]; diff --git a/packages/functions/src/runtime/firebase/token/minting/index.ts b/packages/functions/src/runtime/firebase/token/minting/index.ts deleted file mode 100644 index 80c79c1423..0000000000 --- a/packages/functions/src/runtime/firebase/token/minting/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { WEN_FUNC } from '@build-5/interfaces'; -import { https } from '../../../..'; - -export const airdropMintedToken = https[WEN_FUNC.airdropMintedToken]; - -export const claimMintedTokenOrder = https[WEN_FUNC.claimMintedTokenOrder]; - -export const mintTokenOrder = https[WEN_FUNC.mintTokenOrder]; - -export const importMintedToken = https[WEN_FUNC.importMintedToken]; diff --git a/packages/functions/src/runtime/firebase/token/trading/index.ts b/packages/functions/src/runtime/firebase/token/trading/index.ts deleted file mode 100644 index e76d6b8d32..0000000000 --- a/packages/functions/src/runtime/firebase/token/trading/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { WEN_FUNC } from '@build-5/interfaces'; -import { https } from '../../../..'; - -export const cancelTradeOrder = https[WEN_FUNC.cancelTradeOrder]; -export const tradeToken = https[WEN_FUNC.tradeToken]; diff --git a/packages/functions/src/runtime/firebase/vote/index.ts b/packages/functions/src/runtime/firebase/vote/index.ts deleted file mode 100644 index e5796b8fb1..0000000000 --- a/packages/functions/src/runtime/firebase/vote/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { WEN_FUNC } from '@build-5/interfaces'; -import { https } from '../../..'; - -export const voteController = https[WEN_FUNC.voteController]; diff --git a/packages/functions/src/runtime/https/https.ts b/packages/functions/src/runtime/https/https.ts index 8490b3966f..80d14877ee 100644 --- a/packages/functions/src/runtime/https/https.ts +++ b/packages/functions/src/runtime/https/https.ts @@ -5,6 +5,7 @@ import { AnySchema, ValidationOptions } from 'joi'; import { get } from 'lodash'; import { Context } from '../../controls/common'; import { WEN_FUNC_SCALE } from '../../scale.settings'; +import { logger } from '../../utils/logger'; import { CloudFunctions, RuntimeOptions } from '../common'; import { auth } from './middlewares'; @@ -49,11 +50,15 @@ export const onRequest = (params: OnRequest) => { const result = await params.handler(context); res.send(result || {}); } catch (error) { - res.status(get(error, 'httpErrorCode.status', 400)); + const code = get(error, 'eCode', 500); + if (code === 500) { + logger.error(error); + } + res.status(get(error, 'status', 500)); res.send({ - code: get(error, 'details.code', 0), - key: get(error, 'details.key', ''), - message: get(error, 'message', ''), + code, + key: get(error, 'eKey', ''), + message: get(error, 'eMessage', code === 500 ? 'Internal server error' : ''), }); } }; diff --git a/packages/functions/src/runtime/proto/protoToJson.ts b/packages/functions/src/runtime/proto/protoToJson.ts deleted file mode 100644 index 87524fd367..0000000000 --- a/packages/functions/src/runtime/proto/protoToJson.ts +++ /dev/null @@ -1,48 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import { Timestamp } from 'firebase-admin/firestore'; -import { set } from 'lodash'; -import { Message } from 'protobufjs'; - -export const protoToJson = (proto: Message) => { - const json = proto.toJSON(); - - const current = json.value?.fields; - if (current) { - set(json, 'value.fields', protoJsonToJson(current)); - } - const prev = json.oldValue?.fields; - if (prev !== undefined) { - set(json, 'oldValue.fields', protoJsonToJson(prev)); - } - return json; -}; - -const protoJsonToJson = (protoJson: { [key: string]: any }) => - Object.entries(protoJson).reduce( - (acc, [key, value]) => ({ ...acc, [key]: valueToJson(value) }), - {} as { [key: string]: any }, - ); - -const valueToJson = (data: { [key: string]: any }): any => { - const [type, value] = Object.entries(data)[0]; - switch (type) { - case 'nullValue': - return null; - case 'booleanValue': - return Boolean(value); - case 'integerValue': - case 'doubleValue': - return Number(value); - case 'timestampValue': - return new Timestamp(Number(value.seconds), Number(value.nanos || 0)); - case 'stringValue': - return String(value); - case 'bytes': - case 'referenceValue': - return value; - case 'arrayValue': - return ((value.values as any[]) || []).map(valueToJson); - case 'mapValue': - return protoJsonToJson(value.fields || {}); - } -}; diff --git a/packages/functions/src/runtime/trigger/index.ts b/packages/functions/src/runtime/trigger/index.ts index 86af7ad86a..d45ff9d27d 100644 --- a/packages/functions/src/runtime/trigger/index.ts +++ b/packages/functions/src/runtime/trigger/index.ts @@ -17,60 +17,61 @@ import { WEN_FUNC_TRIGGER } from '../common'; import { onCreate, onUpdate, onWrite } from './trigger'; exports[WEN_FUNC_TRIGGER.onProposalWrite] = onWrite({ - document: `${COL.PROPOSAL}/{docId}`, + col: COL.PROPOSAL, handler: onProposalWrite, }); exports[WEN_FUNC_TRIGGER.onAwardUpdated] = onUpdate({ - document: `${COL.AWARD}/{docId}`, + col: COL.AWARD, options: TRIGGER_SCALE[WEN_FUNC_TRIGGER.onAwardUpdated], handler: onAwardUpdated, }); exports[WEN_FUNC_TRIGGER.onCollectionUpdated] = onUpdate({ - document: `${COL.COLLECTION}/{docId}`, + col: COL.COLLECTION, options: TRIGGER_SCALE[WEN_FUNC_TRIGGER.onCollectionUpdated], handler: onCollectionUpdated, }); exports[WEN_FUNC_TRIGGER.onTokenStatusUpdated] = onUpdate({ - document: `${COL.TOKEN}/{docId}`, + col: COL.TOKEN, options: TRIGGER_SCALE[WEN_FUNC_TRIGGER.onTokenStatusUpdated], handler: onTokenStatusUpdated, }); exports[WEN_FUNC_TRIGGER.onTokenTradeOrderWrite] = onWrite({ - document: `${COL.TOKEN_MARKET}/{docId}`, + col: COL.TOKEN_MARKET, options: TRIGGER_SCALE[WEN_FUNC_TRIGGER.onTokenTradeOrderWrite], handler: onTokenTradeOrderWrite, }); exports[WEN_FUNC_TRIGGER.onTokenPurchaseCreated] = onCreate({ - document: `${COL.TOKEN_PURCHASE}/{docId}`, + col: COL.TOKEN_PURCHASE, options: TRIGGER_SCALE[WEN_FUNC_TRIGGER.onTokenPurchaseCreated], handler: onTokenPurchaseCreated, }); exports[WEN_FUNC_TRIGGER.onNftWrite] = onWrite({ - document: `${COL.NFT}/{docId}`, + col: COL.NFT, options: TRIGGER_SCALE[WEN_FUNC_TRIGGER.onNftWrite], handler: onNftWrite, }); exports[WEN_FUNC_TRIGGER.onTransactionWrite] = onWrite({ - document: `${COL.TRANSACTION}/{docId}`, + col: COL.TRANSACTION, options: TRIGGER_SCALE[WEN_FUNC_TRIGGER.onTransactionWrite], handler: onTransactionWrite, }); exports[WEN_FUNC_TRIGGER.onMnemonicUpdated] = onUpdate({ - document: `${COL.MNEMONIC}/{docId}`, + col: COL.MNEMONIC, options: TRIGGER_SCALE[WEN_FUNC_TRIGGER.onMnemonicUpdated], handler: onMnemonicUpdated, }); exports[WEN_FUNC_TRIGGER.onCollectionStatsWrite] = onWrite({ - document: `${COL.COLLECTION}/{docId}/${SUB_COL.STATS}/{subDocId}`, + col: COL.COLLECTION, + subCol: SUB_COL.STATS, options: TRIGGER_SCALE[WEN_FUNC_TRIGGER.onCollectionStatsWrite], handler: onCollectionStatsWrite, }); @@ -79,7 +80,7 @@ export const algolia = (isEmulatorEnv() ? [] : ALGOLIA_COLLECTIONS).reduce( (acc, act) => ({ ...acc, [`${WEN_FUNC_TRIGGER.algolia}${act}`]: onWrite({ - document: `${act}/{docId}`, + col: act, options: ALGOLIA_TRIGGER_SCALE[act], handler: algoliaTrigger, }), @@ -92,7 +93,8 @@ const getMilestoneTrigger = (networks: Network[]) => (acc, act) => ({ ...acc, [`${WEN_FUNC_TRIGGER.onMilestoneTransactionWrite}${act}`]: onWrite({ - document: `${getMilestoneCol(act)}/{docId}/${SUB_COL.TRANSACTIONS}/{subDocId}`, + col: getMilestoneCol(act), + subCol: SUB_COL.TRANSACTIONS, options: TRIGGER_SCALE[WEN_FUNC_TRIGGER.onMilestoneTransactionWrite], handler: handleMilestoneTransactionWrite(act), }), diff --git a/packages/functions/src/runtime/trigger/trigger.ts b/packages/functions/src/runtime/trigger/trigger.ts index 600c6d7349..cc53f88b93 100644 --- a/packages/functions/src/runtime/trigger/trigger.ts +++ b/packages/functions/src/runtime/trigger/trigger.ts @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { FirestoreDocEvent } from '../../triggers/common'; +import { COL, SUB_COL } from '@build-5/interfaces'; +import { PgDocEvent } from '../../triggers/common'; import { CloudFunctions, RuntimeOptions } from '../common'; export enum TriggeredFunctionType { @@ -12,8 +13,9 @@ export enum TriggeredFunctionType { export class TriggeredFunction extends CloudFunctions { constructor( public readonly type: TriggeredFunctionType, - public readonly document: string, - public readonly handler: (event: FirestoreDocEvent) => Promise, + public readonly col: COL, + public readonly subCol: SUB_COL | undefined = undefined, + public readonly handler: (event: PgDocEvent) => Promise, options?: RuntimeOptions, ) { super({ @@ -24,31 +26,37 @@ export class TriggeredFunction extends CloudFunctions { } export const onCreate = ({ - document, + col, + subCol, handler, options, }: { - document: string; - handler: (event: FirestoreDocEvent) => Promise; + col: COL; + subCol?: SUB_COL; + handler: (event: PgDocEvent) => Promise; options?: RuntimeOptions; -}) => new TriggeredFunction(TriggeredFunctionType.ON_CREATE, document, handler, options); +}) => new TriggeredFunction(TriggeredFunctionType.ON_CREATE, col, subCol, handler, options); export const onUpdate = ({ - document, + col, + subCol, handler, options, }: { - document: string; - handler: (event: FirestoreDocEvent) => Promise; + col: COL; + subCol?: SUB_COL; + handler: (event: PgDocEvent) => Promise; options?: RuntimeOptions; -}) => new TriggeredFunction(TriggeredFunctionType.ON_UPDATE, document, handler, options); +}) => new TriggeredFunction(TriggeredFunctionType.ON_UPDATE, col, subCol, handler, options); export const onWrite = ({ - document, + col, + subCol, handler, options, }: { - document: string; - handler: (event: FirestoreDocEvent) => Promise; + col: COL; + subCol?: SUB_COL; + handler: (event: PgDocEvent) => Promise; options?: RuntimeOptions; -}) => new TriggeredFunction(TriggeredFunctionType.ON_WRITE, document, handler, options); +}) => new TriggeredFunction(TriggeredFunctionType.ON_WRITE, col, subCol, handler, options); diff --git a/packages/functions/src/services/joi/common.ts b/packages/functions/src/services/joi/common.ts index f37ec26b92..1949954e98 100644 --- a/packages/functions/src/services/joi/common.ts +++ b/packages/functions/src/services/joi/common.ts @@ -9,7 +9,7 @@ const maxAddressLength = 255; export class CommonJoi { public static uid(required = true): Joi.StringSchema { const base = Joi.string().alphanum().min(minAddressLength).max(maxAddressLength).lowercase(); - return required ? base.required() : base; + return required ? base.required() : base.allow(null, ''); } public static storageUrl(required = true): Joi.StringSchema { const base = Joi.string().custom((url: string, helpers) => { @@ -33,16 +33,13 @@ export const isStorageUrl = (url: string | undefined) => export const BUCKET_BASE_URLS = { [Bucket.PROD]: 'https://' + Bucket.PROD + '/', [Bucket.TEST]: 'https://' + Bucket.TEST + '/', - [Bucket.DEV]: `https://firebasestorage.googleapis.com/v0/b/${Bucket.DEV}/o/`, - local: `http://127.0.0.1:9199/download/storage/v1/b/soonaverse-dev-custom-bucket/o/`, + [Bucket.DEV]: `https://storage.googleapis.com/download/storage/v1/b/${Bucket.DEV}/o/`, }; const startsWithBaseUrl = (url: string) => { if (isEmulatorEnv()) { return ( - url.startsWith(BUCKET_BASE_URLS[Bucket.DEV]) || - url.startsWith(BUCKET_BASE_URLS[Bucket.TEST]) || - url.startsWith(BUCKET_BASE_URLS['local']) + url.startsWith(BUCKET_BASE_URLS[Bucket.DEV]) || url.startsWith(BUCKET_BASE_URLS[Bucket.TEST]) ); } if (isProdEnv()) { diff --git a/packages/functions/src/services/payment/address/address-member.service.ts b/packages/functions/src/services/payment/address/address-member.service.ts index 42f729580b..b37949ec22 100644 --- a/packages/functions/src/services/payment/address/address-member.service.ts +++ b/packages/functions/src/services/payment/address/address-member.service.ts @@ -1,15 +1,13 @@ -import { build5Db, getSnapshot } from '@build-5/database'; +import { build5Db } from '@build-5/database'; import { COL, DEFAULT_NETWORK, Entity, Network, NetworkAddress, - Transaction, TransactionPayloadType, TransactionType, } from '@build-5/interfaces'; -import { last } from 'lodash'; import { HandlerParams } from '../base'; import { BaseAddressService } from './common'; @@ -23,7 +21,7 @@ export class MemberAddressService extends BaseAddressService { ); if (credit) { await this.setValidatedAddress(credit, Entity.MEMBER); - await claimBadges( + await this.claimBadges( order.member!, credit.payload.targetAddress!, order.network || DEFAULT_NETWORK, @@ -31,41 +29,34 @@ export class MemberAddressService extends BaseAddressService { } this.transactionService.markAsReconciled(order, match.msgId); }; -} -const claimBadges = async (member: string, memberAddress: NetworkAddress, network: Network) => { - let lastDocId = ''; - do { - const lastDoc = await getSnapshot(COL.TRANSACTION, lastDocId); + private claimBadges = async (member: string, memberAddress: NetworkAddress, network: Network) => { const snap = await build5Db() .collection(COL.TRANSACTION) .where('network', '==', network) .where('type', '==', TransactionType.AWARD) .where('member', '==', member) .where('ignoreWallet', '==', true) - .where('payload.type', '==', TransactionPayloadType.BADGE) - .limit(500) - .startAfter(lastDoc) - .get(); - lastDocId = last(snap)?.uid || ''; + .where('payload_type', '==', TransactionPayloadType.BADGE) + .get(); const promises = snap.map((badgeTransaction) => updateBadgeTransaction(badgeTransaction.uid, memberAddress), ); await Promise.all(promises); - } while (lastDocId); -}; + }; +} -const updateBadgeTransaction = async (transactionId: string, memberAddress: NetworkAddress) => +const updateBadgeTransaction = (transactionId: string, memberAddress: NetworkAddress) => build5Db().runTransaction(async (transaction) => { - const badgeDocRef = build5Db().doc(`${COL.TRANSACTION}/${transactionId}`); - const badge = await transaction.get(badgeDocRef); + const badgeDocRef = build5Db().doc(COL.TRANSACTION, transactionId); + const badge = await transaction.get(badgeDocRef); if (badge?.ignoreWallet) { const data = { ignoreWallet: false, - 'payload.targetAddress': memberAddress, + payload_targetAddress: memberAddress, shouldRetry: true, }; - transaction.update(badgeDocRef, data); + await transaction.update(badgeDocRef, data); } }); diff --git a/packages/functions/src/services/payment/address/address.space.service.ts b/packages/functions/src/services/payment/address/address.space.service.ts index 6f4446ef2a..18c98188ac 100644 --- a/packages/functions/src/services/payment/address/address.space.service.ts +++ b/packages/functions/src/services/payment/address/address.space.service.ts @@ -8,7 +8,6 @@ import { ProposalType, SUB_COL, Space, - SpaceGuardian, Transaction, TransactionPayloadType, TransactionType, @@ -19,6 +18,7 @@ import { getAddress } from '../../../utils/address.utils'; import { dateToTimestamp } from '../../../utils/dateTime.utils'; import { getRandomEthAddress } from '../../../utils/wallet.utils'; import { BaseService, HandlerParams } from '../base'; +import { Action } from '../transaction-service'; export class SpaceAddressService extends BaseService { public handleRequest = async ({ project, order, match }: HandlerParams) => { @@ -30,13 +30,13 @@ export class SpaceAddressService extends BaseService { ); this.transactionService.markAsReconciled(order, match.msgId); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${order.space}`); - const space = await this.transactionService.get(spaceDocRef); + const spaceDocRef = build5Db().doc(COL.SPACE, order.space!); + const space = await this.transaction.get(spaceDocRef); - const ownerDocRef = build5Db().doc(`${COL.MEMBER}/${order.member}`); - const owner = await ownerDocRef.get(); + const ownerDocRef = build5Db().doc(COL.MEMBER, order.member!); + const owner = await this.transaction.get(ownerDocRef); - const guardians = await spaceDocRef.collection(SUB_COL.GUARDIANS).get(); + const guardians = await build5Db().collection(COL.SPACE, order.space!, SUB_COL.GUARDIANS).get(); const proposal = createUpdateSpaceValidatedAddressProposal( project, order, @@ -62,34 +62,37 @@ export class SpaceAddressService extends BaseService { linkedTransactions: [], }; - const proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${proposal.uid}`); - const memberPromisses = guardians.map((guardian) => { - proposalDocRef - .collection(SUB_COL.MEMBERS) - .doc(guardian.uid) - .set({ - uid: guardian.uid, + for (const guardian of guardians) { + const memberDocRef = build5Db().doc( + COL.PROPOSAL, + proposal.uid, + SUB_COL.MEMBERS, + guardian.uid, + ); + this.transactionService.push({ + ref: memberDocRef, + data: { weight: 1, voted: guardian.uid === owner.uid, tranId: guardian.uid === owner.uid ? voteTransaction.uid : '', - parentId: proposal.uid, - parentCol: COL.PROPOSAL, - values: guardian.uid === owner.uid ? [{ [1]: 1 }] : [], - }); - }); - await Promise.all(memberPromisses); + }, + action: Action.UPS, + }); + } - const voteTransactionDocRef = build5Db().doc(`${COL.TRANSACTION}/${voteTransaction.uid}`); - this.transactionService.push({ - ref: voteTransactionDocRef, - data: voteTransaction, - action: 'set', - }); + const proposalDocRef = build5Db().doc(COL.PROPOSAL, proposal.uid); this.transactionService.push({ ref: proposalDocRef, data: proposal, - action: 'set', + action: Action.C, + }); + + const voteTransactionDocRef = build5Db().doc(COL.TRANSACTION, voteTransaction.uid); + this.transactionService.push({ + ref: voteTransactionDocRef, + data: voteTransaction, + action: Action.C, }); }; } @@ -106,6 +109,7 @@ const createUpdateSpaceValidatedAddressProposal = ( `${owner.name || owner.uid} wants to update the space's validated address. ` + `Request created on ${dayjs().format('MM/DD/YYYY')}. ` + `${UPDATE_SPACE_THRESHOLD_PERCENTAGE} % must agree for this action to proceed`; + const prevAddress = getAddress(space, order.network!); return { project, createdBy: owner.uid, @@ -124,15 +128,13 @@ const createUpdateSpaceValidatedAddressProposal = ( spaceUpdateData: { uid: space.uid, validatedAddress: { [order.network!]: validatedAddress }, - prevValidatedAddresses: getAddress(space, order.network!), + prevValidatedAddresses: prevAddress ? [prevAddress] : [], }, }, questions: [ { text: "Do you want to update the space's validate address?", - additionalInfo: `${order.network!.toUpperCase()}: ${validatedAddress} (previously: ${ - getAddress(space, order.network!) || 'None' - })\n`, + additionalInfo: `${order.network!.toUpperCase()}: ${validatedAddress} (previously: ${getAddress(space, order.network!) || 'None'})\n`, answers: [ { text: 'No', diff --git a/packages/functions/src/services/payment/address/common.ts b/packages/functions/src/services/payment/address/common.ts index 72138fc1f5..8fef82f346 100644 --- a/packages/functions/src/services/payment/address/common.ts +++ b/packages/functions/src/services/payment/address/common.ts @@ -1,20 +1,28 @@ -import { build5Db } from '@build-5/database'; +import { IDocument, PgSpaceUpdate, build5Db } from '@build-5/database'; import { COL, DEFAULT_NETWORK, Entity, Transaction } from '@build-5/interfaces'; import { getAddress } from '../../../utils/address.utils'; import { BaseService } from '../base'; +import { Action } from '../transaction-service'; export abstract class BaseAddressService extends BaseService { protected async setValidatedAddress(credit: Transaction, type: Entity): Promise { const collection = type === Entity.MEMBER ? COL.MEMBER : COL.SPACE; - const id = type === Entity.MEMBER ? credit.member : credit.space; - const ref = build5Db().doc(`${collection}/${id}`); - const docData = await ref.get>(); + const id = type === Entity.MEMBER ? credit.member! : credit.space!; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const ref: IDocument = build5Db().doc(collection, id); + + const docData = await this.transaction.get(ref); const network = credit.network || DEFAULT_NETWORK; const currentAddress = getAddress(docData, network); - const data = { [`validatedAddress.${network}`]: credit.payload.targetAddress }; - if (currentAddress) { - data.prevValidatedAddresses = build5Db().arrayUnion(currentAddress); - } - this.transactionService.push({ ref, data, action: 'update' }); + + const data = currentAddress + ? { + [`${network}Address`]: credit.payload.targetAddress, + prevValidatedAddresses: build5Db().arrayUnion(currentAddress), + } + : { [`${network}Address`]: credit.payload.targetAddress }; + + this.transactionService.push({ ref, data, action: Action.U }); } } diff --git a/packages/functions/src/services/payment/auction/auction-bid.service.ts b/packages/functions/src/services/payment/auction/auction-bid.service.ts index 9b081232c4..a9ec05aea4 100644 --- a/packages/functions/src/services/payment/auction/auction-bid.service.ts +++ b/packages/functions/src/services/payment/auction/auction-bid.service.ts @@ -12,12 +12,11 @@ import { import dayjs from 'dayjs'; import { head, set } from 'lodash'; import { NotificationService } from '../../notification/notification'; +import { BaseAddressService } from '../address/common'; import { HandlerParams } from '../base'; -import { TransactionService } from '../transaction-service'; - -export class AuctionBidService { - constructor(readonly transactionService: TransactionService) {} +import { Action } from '../transaction-service'; +export class AuctionBidService extends BaseAddressService { public handleRequest = async ({ order, match, @@ -26,8 +25,8 @@ export class AuctionBidService { build5Tran, owner, }: HandlerParams) => { - const auctionDocRef = build5Db().doc(`${COL.AUCTION}/${order.payload.auction!}`); - const auction = await this.transactionService.get(auctionDocRef); + const auctionDocRef = build5Db().doc(COL.AUCTION, order.payload.auction!); + const auction = await this.transaction.get(auctionDocRef); if (!auction.active) { await this.transactionService.processAsInvalid(tran, order, tranEntry, build5Tran); @@ -72,34 +71,34 @@ export class AuctionBidService { .collection(COL.TRANSACTION) .where('type', '==', TransactionType.PAYMENT) .where('member', '==', invalidBid.bidder) - .where('payload.invalidPayment', '==', false) - .where('payload.auction', '==', auction.uid) - .get(); + .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 invalidBidderDocRef = build5Db().doc(COL.MEMBER, invalidBid.bidder); + const invalidBidder = await this.transaction.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' }); + const notificationDocRef = build5Db().doc(COL.NOTIFICATION, notification.uid); + this.transactionService.push({ ref: notificationDocRef, data: notification, action: Action.C }); }; private creditAsInvalidPayment = async (payment: Transaction) => { - const paymentDocRef = build5Db().doc(`${COL.TRANSACTION}/${payment.uid}`); + const paymentDocRef = build5Db().doc(COL.TRANSACTION, payment.uid); this.transactionService.push({ ref: paymentDocRef, - data: { 'payload.invalidPayment': true }, - action: 'update', + data: { payload_invalidPayment: true }, + action: Action.U, }); const paymentPayload = payment.payload; - set(payment, 'payload.invalidPayment', true); + set(payment, 'payload_invalidPayment', true); await this.transactionService.createCredit(TransactionPayloadType.INVALID_PAYMENT, payment, { msgId: paymentPayload.chainReference!, to: { @@ -112,49 +111,58 @@ export class AuctionBidService { }; private onAuctionHighestBidChange = async (order: Transaction, auction: Auction) => { - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${order.member!}`); - const member = await this.transactionService.get(memberDocRef); + const memberDocRef = build5Db().doc(COL.MEMBER, order.member!); + const member = await memberDocRef.get(); 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' }); + const notificationDocRef = build5Db().doc(COL.NOTIFICATION, bidNotification.uid); + this.transactionService.push({ + ref: notificationDocRef, + data: bidNotification, + action: Action.C, + }); }; private getAuctionUpdateData = (auction: Auction, bids: AuctionBid[]) => { - const auctionUpdateData = { - ...auction, + const uData = { bids, auctionHighestBidder: head(bids)?.bidder || '', auctionHighestBid: head(bids)?.amount || 0, + auctionTo: auction.auctionTo, + auctionLength: auction.auctionLength, }; 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); + uData.auctionTo = auction.extendedAuctionTo!; + uData.auctionLength = auction.extendedAuctionLength || 0; } - const auctionDocRef = build5Db().doc(`${COL.AUCTION}/${auction.uid}`); - this.transactionService.push({ ref: auctionDocRef, data: auctionUpdateData, action: 'update' }); - return auctionUpdateData as Auction; + const auctionDocRef = build5Db().doc(COL.AUCTION, auction.uid); + this.transactionService.push({ + ref: auctionDocRef, + data: { ...uData, auctionTo: uData.auctionTo?.toDate(), bids: JSON.stringify(uData.bids) }, + action: Action.U, + }); + return { ...auction, ...uData } as Auction; }; private updateNft = (auction: Auction) => { const nftUpdateData = { - auctionTo: auction.auctionTo, + auctionTo: auction.auctionTo?.toDate(), auctionLength: auction.auctionLength, auctionHighestBid: auction.auctionHighestBid, auctionHighestBidder: auction.auctionHighestBidder, }; this.transactionService.push({ - ref: build5Db().doc(`${COL.NFT}/${auction.nftId}`), + ref: build5Db().doc(COL.NFT, auction.nftId!), data: nftUpdateData, - action: 'update', + action: Action.U, }); }; } @@ -197,7 +205,6 @@ const placeBid = (auction: Auction, order: string, bidder: string, amount: numbe 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)), diff --git a/packages/functions/src/services/payment/auction/auction.finalize.service.ts b/packages/functions/src/services/payment/auction/auction.finalize.service.ts index d1bbac8e4d..c7acc711a7 100644 --- a/packages/functions/src/services/payment/auction/auction.finalize.service.ts +++ b/packages/functions/src/services/payment/auction/auction.finalize.service.ts @@ -1,4 +1,4 @@ -import { build5Db } from '@build-5/database'; +import { ITransaction, build5Db } from '@build-5/database'; import { Auction, AuctionType, @@ -13,30 +13,31 @@ import { import { invalidArgument } from '../../../utils/error.utils'; import { NotificationService } from '../../notification/notification'; import { BaseNftService } from '../nft/common'; -import { TransactionService } from '../transaction-service'; +import { Action, TransactionService } from '../transaction-service'; export class AuctionFinalizeService { - constructor(readonly transactionService: TransactionService) {} + private transaction: ITransaction; + constructor(readonly transactionService: TransactionService) { + this.transaction = transactionService.transaction; + } public markAsFinalized = async (auctionId: string) => { - const auctionDocRef = build5Db().doc(`${COL.AUCTION}/${auctionId}`); - const auction = await this.transactionService.get(auctionDocRef); + const auctionDocRef = build5Db().doc(COL.AUCTION, auctionId); + const auction = await this.transaction.get(auctionDocRef); if (!auction.active) { throw invalidArgument(WenError.auction_not_active); } - this.transactionService.push({ ref: auctionDocRef, data: { active: false }, action: 'update' }); + this.transactionService.push({ ref: auctionDocRef, data: { active: false }, action: Action.U }); const payments = await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.PAYMENT) - .where('payload.invalidPayment', '==', false) - .where('payload.auction', '==', auction.uid) - .get(); + .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 orderDocRef = build5Db().doc(COL.TRANSACTION, payment.payload.sourceTransaction![0]); const order = await orderDocRef.get(); this.transactionService.createBillPayment(order, payment); } @@ -48,8 +49,8 @@ export class AuctionFinalizeService { }; private finalizeNftAuction = async (auction: Auction) => { - const nftDocRef = build5Db().doc(`${COL.NFT}/${auction.nftId}`); - const nft = await this.transactionService.get(nftDocRef); + const nftDocRef = build5Db().doc(COL.NFT, auction.nftId!); + const nft = await this.transaction.get(nftDocRef); if (!auction.auctionHighestBidder) { this.transactionService.push({ @@ -65,12 +66,12 @@ export class AuctionFinalizeService { auctionHighestBidder: null, auction: null, }, - action: 'update', + action: Action.U, }); return; } - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${auction.bids[0].order}`); + const orderDocRef = build5Db().doc(COL.TRANSACTION, auction.bids[0].order); const order = await orderDocRef.get(); const nftService = new BaseNftService(this.transactionService); @@ -84,11 +85,10 @@ export class AuctionFinalizeService { auction.auctionHighestBid!, auction.uid, ); - const notificationDocRef = build5Db().doc(`${COL.NOTIFICATION}/${notification.uid}`); this.transactionService.push({ - ref: notificationDocRef, + ref: build5Db().doc(COL.NOTIFICATION, notification.uid), data: notification, - action: 'set', + action: Action.C, }); nftService.setTradingStats(nft); diff --git a/packages/functions/src/services/payment/award/award-service.ts b/packages/functions/src/services/payment/award/award-service.ts index f6964f2fa5..04c4c6ed74 100644 --- a/packages/functions/src/services/payment/award/award-service.ts +++ b/packages/functions/src/services/payment/award/award-service.ts @@ -23,13 +23,14 @@ import { createAliasOutput } from '../../../utils/token-minting-utils/alias.util import { getRandomEthAddress } from '../../../utils/wallet.utils'; import { Wallet } from '../../wallet/wallet'; import { BaseService, HandlerParams } from '../base'; +import { Action } from '../transaction-service'; export class AwardFundService extends BaseService { public handleRequest = async ({ order, match }: HandlerParams) => { const payment = await this.transactionService.createPayment(order, match); - const awardDocRef = build5Db().doc(`${COL.AWARD}/${order.payload.award}`); - const award = await this.transactionService.get(awardDocRef); + const awardDocRef = build5Db().doc(COL.AWARD, order.payload.award!); + const award = await this.transaction.get(awardDocRef); if (award.funded) { await this.transactionService.createCredit( @@ -66,7 +67,7 @@ export class AwardFundService extends BaseService { fundingAddress: match.from, mediaStatus: MediaStatus.PENDING_UPLOAD, }, - action: 'update', + action: Action.U, }); const mintAliasOrder: Transaction = { @@ -84,21 +85,22 @@ export class AwardFundService extends BaseService { award: award.uid, }, }; - const mintAliasTranDocRef = build5Db().doc(`${COL.TRANSACTION}/${mintAliasOrder.uid}`); + const mintAliasTranDocRef = build5Db().doc(COL.TRANSACTION, mintAliasOrder.uid); this.transactionService.push({ ref: mintAliasTranDocRef, data: mintAliasOrder, - action: 'set', + action: Action.C, }); if (order.payload.legacyAwardFundRequestId) { const legacyAwardFundRequesDocRef = build5Db().doc( - `${COL.TRANSACTION}/${order.payload.legacyAwardFundRequestId}`, + COL.TRANSACTION, + order.payload.legacyAwardFundRequestId, ); this.transactionService.push({ ref: legacyAwardFundRequesDocRef, - data: { 'payload.legacyAwardsBeeingFunded': build5Db().inc(-1) }, - action: 'update', + data: { payload_legacyAwardsBeeingFunded: build5Db().inc(-1) }, + action: Action.U, }); } }; @@ -177,7 +179,7 @@ export const getAwardgStorageDeposits = async (award: Award, token: Token, walle const collectioIssuerAddress = new AliasAddress(aliasOutput.aliasId); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${award.space}`); + const spaceDocRef = build5Db().doc(COL.SPACE, award.space); const space = await spaceDocRef.get(); const collectionMetadata = await awardToCollectionMetadata(award, space); diff --git a/packages/functions/src/services/payment/credit-service.ts b/packages/functions/src/services/payment/credit-service.ts index 2bbe205dd3..adfea63f5b 100644 --- a/packages/functions/src/services/payment/credit-service.ts +++ b/packages/functions/src/services/payment/credit-service.ts @@ -1,18 +1,17 @@ import { build5Db } from '@build-5/database'; import { COL, Transaction, TransactionPayloadType, TransactionType } from '@build-5/interfaces'; -import { get, isEmpty } from 'lodash'; +import { isEmpty } from 'lodash'; import { getProject } from '../../utils/common.utils'; import { getRandomEthAddress } from '../../utils/wallet.utils'; import { BaseService, HandlerParams } from './base'; +import { Action } from './transaction-service'; export class CreditService extends BaseService { public handleRequest = async ({ order, match }: HandlerParams) => { const payment = await this.transactionService.createPayment(order, match); - const transactionDocRef = build5Db().doc( - `${COL.TRANSACTION}/${get(order, 'payload.transaction', '')}`, - ); - const transaction = await transactionDocRef.get(); + const transactionDocRef = build5Db().doc(COL.TRANSACTION, order.payload.transaction || ''); + const transaction = await this.transaction.get(transactionDocRef); if (!isEmpty(transaction.payload.unlockedBy)) { await this.transactionService.createCredit( @@ -44,15 +43,15 @@ export class CreditService extends BaseService { }, }; this.transactionService.push({ - ref: build5Db().doc(`${COL.TRANSACTION}/${credit.uid}`), + ref: build5Db().doc(COL.TRANSACTION, credit.uid), data: credit, - action: 'set', + action: Action.C, }); this.transactionService.push({ ref: transactionDocRef, - data: { 'payload.unlockedBy': credit.uid }, - action: 'update', + data: { payload_unlockedBy: credit.uid }, + action: Action.U, }); }; } diff --git a/packages/functions/src/services/payment/metadataNft-service.ts b/packages/functions/src/services/payment/metadataNft-service.ts index 44c45266bb..23e4d18276 100644 --- a/packages/functions/src/services/payment/metadataNft-service.ts +++ b/packages/functions/src/services/payment/metadataNft-service.ts @@ -1,19 +1,21 @@ -import { build5Db } from '@build-5/database'; +import { PgTransaction, build5Db } from '@build-5/database'; import { Access, COL, + Collection, CollectionStatus, CollectionType, + Network, NetworkAddress, Nft, NftAccess, NftAvailable, NftStatus, - Space, Transaction, TransactionPayloadType, TransactionType, } from '@build-5/interfaces'; +import { get } from 'lodash'; import { getCollectionByMintingId, getNftByMintingId, @@ -21,6 +23,7 @@ import { import { getProject } from '../../utils/common.utils'; import { getRandomEthAddress } from '../../utils/wallet.utils'; import { BaseService, HandlerParams } from './base'; +import { Action } from './transaction-service'; export class MetadataNftService extends BaseService { public handleRequest = async ({ project, order, match }: HandlerParams) => { @@ -52,19 +55,23 @@ export class MetadataNftService extends BaseService { }, }; this.transactionService.push({ - ref: build5Db().doc(`${COL.TRANSACTION}/${mintAlias.uid}`), + ref: build5Db().doc(COL.TRANSACTION, mintAlias.uid), data: mintAlias, - action: 'set', + action: Action.C, }); return; } if (!collectionId) { const collection = createMetadataCollection(getProject(order), order.space!); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${collection.uid}`); - this.transactionService.push({ ref: collectionDocRef, data: collection, action: 'set' }); + const collectionDocRef = build5Db().doc(COL.COLLECTION, collection.uid); + this.transactionService.push({ + ref: collectionDocRef, + data: collection as Collection, + action: Action.C, + }); - const space = await build5Db().doc(`${COL.SPACE}/${order.space}`).get(); + const space = await build5Db().doc(COL.SPACE, order.space!).get(); const mintCollectionOrder = createMintMetadataCollectionOrder( order, collection.uid, @@ -72,8 +79,12 @@ export class MetadataNftService extends BaseService { order.uid, space?.alias?.address!, ); - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${mintCollectionOrder.uid}`); - this.transactionService.push({ ref: orderDocRef, data: mintCollectionOrder, action: 'set' }); + const orderDocRef = build5Db().doc(COL.TRANSACTION, mintCollectionOrder.uid); + this.transactionService.push({ + ref: orderDocRef, + data: mintCollectionOrder, + action: Action.C, + }); return; } @@ -88,11 +99,11 @@ export class MetadataNftService extends BaseService { order.payload.metadata || {}, ); if (!nftId) { - const nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); - this.transactionService.push({ ref: nftDocRef, data: nft, action: 'set' }); + const nftDocRef = build5Db().doc(COL.NFT, nft.uid); + this.transactionService.push({ ref: nftDocRef, data: nft, action: Action.C }); } - const space = await build5Db().doc(`${COL.SPACE}/${order.space}`).get(); + const space = await build5Db().doc(COL.SPACE, order.space!).get(); const mintNftOrder = createMintMetadataNftOrder( order, @@ -101,8 +112,8 @@ export class MetadataNftService extends BaseService { order.payload.collectionId || '', order.uid, ); - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${mintNftOrder.uid}`); - this.transactionService.push({ ref: orderDocRef, data: mintNftOrder, action: 'set' }); + const orderDocRef = build5Db().doc(COL.TRANSACTION, mintNftOrder.uid); + this.transactionService.push({ ref: orderDocRef, data: mintNftOrder, action: Action.C }); return; }; } @@ -153,7 +164,7 @@ export const createMetadataCollection = (project: string, space: string) => ({ }); export const createMintMetadataCollectionOrder = ( - transaction: Transaction, + transaction: Transaction | PgTransaction, collection: string, aliasId: string, orderId: string, @@ -165,11 +176,13 @@ export const createMintMetadataCollectionOrder = ( uid: getRandomEthAddress(), member: transaction.member, space: transaction.space, - network: transaction.network, + network: get(transaction, 'network') as Network, payload: { type: TransactionPayloadType.MINT_COLLECTION, - sourceAddress: transaction.payload.targetAddress, - targetAddress: transaction.payload.targetAddress, + sourceAddress: + get(transaction, 'payload.targetAddress') || get(transaction, 'payload_sourceAddress'), + targetAddress: + get(transaction, 'payload.targetAddress') || get(transaction, 'payload_targetAddress'), collection, aliasId, aliasBlockId, @@ -179,7 +192,7 @@ export const createMintMetadataCollectionOrder = ( }); export const createMintMetadataNftOrder = ( - transaction: Transaction, + transaction: Transaction | PgTransaction, nft: Nft, aliasGovAddress: NetworkAddress, collectionId: string, @@ -190,15 +203,17 @@ export const createMintMetadataNftOrder = ( uid: getRandomEthAddress(), member: nft.owner, space: nft.space, - network: transaction.network, + network: transaction.network as Network, payload: { type: nft.mintingData?.nftId ? TransactionPayloadType.UPDATE_MINTED_NFT : TransactionPayloadType.MINT_NFT, - sourceAddress: transaction.payload.targetAddress, + sourceAddress: + get(transaction, 'payload.targetAddress') || get(transaction, 'payload_targetAddress'), aliasGovAddress, - targetAddress: transaction.payload.targetAddress, - aliasId: transaction.payload.aliasId || '', + targetAddress: + get(transaction, 'payload.targetAddress') || get(transaction, 'payload_targetAddress'), + aliasId: get(transaction, 'payload.aliasId') || get(transaction, 'payload_aliasId', ''), collectionId, orderId: baseOrderId, nft: nft.uid, diff --git a/packages/functions/src/services/payment/nft/collection-minting.service.ts b/packages/functions/src/services/payment/nft/collection-minting.service.ts index 1dbb19877f..0274726124 100644 --- a/packages/functions/src/services/payment/nft/collection-minting.service.ts +++ b/packages/functions/src/services/payment/nft/collection-minting.service.ts @@ -1,4 +1,4 @@ -import { build5Db } from '@build-5/database'; +import { PgCollectionUpdate, build5Db } from '@build-5/database'; import { COL, Collection, @@ -6,13 +6,13 @@ import { TransactionPayloadType, UnsoldMintingOptions, } from '@build-5/interfaces'; -import { get } from 'lodash'; import { BaseService, HandlerParams } from '../base'; +import { Action } from '../transaction-service'; export class CollectionMintingService extends BaseService { public handleRequest = async ({ order, match }: HandlerParams) => { - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${order.payload.collection}`); - const collection = await this.transactionService.get(collectionDocRef); + const collectionDocRef = build5Db().doc(COL.COLLECTION, order.payload.collection!); + const collection = await this.transaction.get(collectionDocRef); const payment = await this.transactionService.createPayment(order, match); if (collection.status !== CollectionStatus.PRE_MINTED) { @@ -25,29 +25,29 @@ export class CollectionMintingService extends BaseService { } this.transactionService.markAsReconciled(order, match.msgId); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const data: any = { - 'mintingData.mintingOrderId': order.uid, - 'mintingData.network': order.network, - 'mintingData.mintedBy': order.member, - 'mintingData.unsoldMintingOptions': get( - order, - 'payload.unsoldMintingOptions', - UnsoldMintingOptions.KEEP_PRICE, - ), - 'mintingData.newPrice': get(order, 'payload.newPrice', 0), - 'mintingData.aliasStorageDeposit': get(order, 'payload.aliasStorageDeposit', 0), - 'mintingData.storageDeposit': get(order, 'payload.collectionStorageDeposit', 0), - 'mintingData.nftsStorageDeposit': get(order, 'payload.nftsStorageDeposit', 0), - 'mintingData.address': order.payload.targetAddress, + const collectionUpdateData: PgCollectionUpdate = { + mintingData_mintingOrderId: order.uid, + mintingData_network: order.network, + mintingData_mintedBy: order.member, + mintingData_unsoldMintingOptions: + order.payload.unsoldMintingOptions || UnsoldMintingOptions.KEEP_PRICE, + mintingData_newPrice: order.payload.newPrice || 0, + mintingData_aliasStorageDeposit: order.payload.aliasStorageDeposit || 0, + mintingData_storageDeposit: order.payload.collectionStorageDeposit || 0, + mintingData_nftsStorageDeposit: order.payload.nftsStorageDeposit || 0, + mintingData_address: order.payload.targetAddress, status: CollectionStatus.MINTING, }; - // We have to set new default price on collection as well. - if (get(order, 'payload.newPrice', 0)) { - data.price = get(order, 'payload.newPrice', 0); + const newPrice = order.payload.newPrice || 0; + if (newPrice) { + collectionUpdateData.price = newPrice; } - this.transactionService.push({ ref: collectionDocRef, data, action: 'update' }); + this.transactionService.push({ + ref: collectionDocRef, + data: collectionUpdateData, + action: Action.U, + }); }; } diff --git a/packages/functions/src/services/payment/nft/common.ts b/packages/functions/src/services/payment/nft/common.ts index ae1544172c..4f5f49a221 100644 --- a/packages/functions/src/services/payment/nft/common.ts +++ b/packages/functions/src/services/payment/nft/common.ts @@ -1,25 +1,25 @@ import { build5Db } from '@build-5/database'; -import { COL, Collection, Member, Nft, NftAccess, Transaction } from '@build-5/interfaces'; +import { COL, Member, Nft, NftAccess, Transaction } from '@build-5/interfaces'; +import dayjs from 'dayjs'; import { getAddress } from '../../../utils/address.utils'; import { getProject } from '../../../utils/common.utils'; -import { serverTime } from '../../../utils/dateTime.utils'; import { createNftWithdrawOrder } from '../tangle-service/nft/nft-purchase.service'; -import { TransactionService } from '../transaction-service'; +import { Action, TransactionService } from '../transaction-service'; 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' }); + const data = { lastTradedOn: dayjs().toDate(), totalTrades: build5Db().inc(1) }; + const collectionDocRef = build5Db().doc(COL.COLLECTION, nft.collection); + this.transactionService.push({ ref: collectionDocRef, data, action: Action.U }); - const nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); - this.transactionService.push({ ref: nftDocRef, data, action: 'update' }); + const nftDocRef = build5Db().doc(COL.NFT, nft.uid); + this.transactionService.push({ ref: nftDocRef, data, action: Action.U }); }; public withdrawNft = async (order: Transaction, nft: Nft) => { - const membderDocRef = build5Db().doc(`${COL.MEMBER}/${order.member}`); + const membderDocRef = build5Db().doc(COL.MEMBER, order.member!); const member = await membderDocRef.get(); const { order: withdrawOrder, nftUpdateData } = createNftWithdrawOrder( getProject(order), @@ -28,20 +28,20 @@ export class BaseNftService { getAddress(member, order.network!), ); this.transactionService.push({ - ref: build5Db().doc(`${COL.TRANSACTION}/${withdrawOrder.uid}`), + ref: build5Db().doc(COL.TRANSACTION, withdrawOrder.uid), data: withdrawOrder, - action: 'set', + action: Action.C, }); this.transactionService.push({ - ref: build5Db().doc(`${COL.NFT}/${nft.uid}`), + ref: build5Db().doc(COL.NFT, nft.uid), data: nftUpdateData, - action: 'update', + action: Action.U, }); }; 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 nft = await nftDocRef.get(); const nftUpdateData = { owner: order.member, @@ -51,7 +51,7 @@ export class BaseNftService { locked: false, lockedBy: null, hidden: false, - soldOn: nft.soldOn || serverTime(), + soldOn: nft.soldOn?.toDate() || dayjs().toDate(), availableFrom: null, availablePrice: null, auctionFrom: null, @@ -69,20 +69,20 @@ export class BaseNftService { this.transactionService.push({ ref: nftDocRef, data: nftUpdateData, - action: 'update', + action: Action.U, }); if (order.payload.beneficiary === 'space') { - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${order.payload.collection}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, order.payload.collection!); this.transactionService.push({ ref: collectionDocRef, data: { sold: build5Db().inc(1) }, - action: 'update', + action: Action.U, }); - const collection = (await this.transactionService.get(collectionDocRef))!; + const collection = (await collectionDocRef.get())!; if (collection.placeholderNft && collection.total === collection.sold + 1) { - const placeholderNftDocRef = build5Db().doc(`${COL.NFT}/${collection.placeholderNft}`); + const placeholderNftDocRef = build5Db().doc(COL.NFT, collection.placeholderNft); this.transactionService.push({ ref: placeholderNftDocRef, data: { @@ -90,10 +90,10 @@ export class BaseNftService { owner: null, availablePrice: null, availableFrom: null, - soldOn: serverTime(), + soldOn: dayjs().toDate(), hidden: false, }, - action: 'update', + action: Action.U, }); } } diff --git a/packages/functions/src/services/payment/nft/nft-deposit.service.ts b/packages/functions/src/services/payment/nft/nft-deposit.service.ts index b24fb6316d..13a50a3337 100644 --- a/packages/functions/src/services/payment/nft/nft-deposit.service.ts +++ b/packages/functions/src/services/payment/nft/nft-deposit.service.ts @@ -1,7 +1,6 @@ -import { ITransaction, build5Db, build5Storage } from '@build-5/database'; +import { ITransaction, PgNftUpdate, build5Db, build5Storage } from '@build-5/database'; import { Access, - Award, COL, Categories, Collection, @@ -17,14 +16,17 @@ import { Space, Transaction, TransactionPayloadType, + ValidatedAddress, WenError, } from '@build-5/interfaces'; import { NftOutput } from '@iota/sdk'; +import dayjs from 'dayjs'; import { head, isEmpty, set } from 'lodash'; import { getNftByMintingId } from '../../../utils/collection-minting-utils/nft.utils'; import { getProject } from '../../../utils/common.utils'; import { getBucket } from '../../../utils/config.utils'; -import { serverTime } from '../../../utils/dateTime.utils'; +import { dateToTimestamp, serverTime } from '../../../utils/dateTime.utils'; +import { logger } from '../../../utils/logger'; import { migrateUriToSotrage, uriToUrl } from '../../../utils/media.utils'; import { collectionIrc27Scheam, @@ -38,7 +40,7 @@ import { getRandomEthAddress } from '../../../utils/wallet.utils'; import { NftWallet } from '../../wallet/NftWallet'; import { WalletService } from '../../wallet/wallet.service'; import { BaseService, HandlerParams } from '../base'; -import { TransactionMatch } from '../transaction-service'; +import { Action, TransactionMatch } from '../transaction-service'; export class NftDepositService extends BaseService { public handleRequest = async ({ order, match, tranEntry }: HandlerParams) => { @@ -47,11 +49,11 @@ export class NftDepositService extends BaseService { await this.transactionService.createPayment(order, match); this.transactionService.markAsReconciled(order, match.msgId); - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${order.uid}`); + const orderDocRef = build5Db().doc(COL.TRANSACTION, order.uid); this.transactionService.push({ ref: orderDocRef, - data: { 'payload.nft': nft.uid }, - action: 'update', + data: { payload_nft: nft.uid }, + action: Action.U, }); } catch (error) { const payment = await this.transactionService.createPayment(order, match, true); @@ -88,19 +90,45 @@ export class NftDepositService extends BaseService { nftOutput: NftOutput, match: TransactionMatch, ) => { - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${nft.collection}`); - const collection = await this.transactionService.get(collectionDocRef); + const collectionDocRef = build5Db().doc(COL.COLLECTION, nft.collection); + const collection = await this.transaction.get(collectionDocRef); if (!collection.approved) { throw WenError.collection_must_be_approved; } - const data = { + const data: PgNftUpdate = { + status: NftStatus.MINTED, + depositData_address: order.payload.targetAddress, + depositData_network: order.network, + depositData_mintedOn: dayjs().toDate(), + depositData_mintedBy: order.member, + depositData_blockId: match.msgId, + depositData_nftId: nftOutput.nftId, + depositData_storageDeposit: match.to.amount, + depositData_mintingOrderId: order.uid, + hidden: false, + isOwned: true, + owner: order.member, + }; + const nftDocRef = build5Db().doc(COL.NFT, nft.uid); + this.transactionService.push({ ref: nftDocRef, data, action: Action.U }); + this.transactionService.push({ + ref: build5Db().doc(COL.TRANSACTION, order.uid), + data: { + space: nft.space, + payload_amount: match.to.amount, + payload_nft: nft.uid, + }, + action: Action.U, + }); + return { + ...nft, status: NftStatus.MINTED, depositData: { address: order.payload.targetAddress, network: order.network, - mintedOn: serverTime(), + mintedOn: dateToTimestamp(dayjs().toDate()), mintedBy: order.member, blockId: match.msgId, nftId: nftOutput.nftId, @@ -111,18 +139,6 @@ export class NftDepositService extends BaseService { isOwned: true, owner: order.member, }; - const nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); - this.transactionService.push({ ref: nftDocRef, data, action: 'update' }); - this.transactionService.push({ - ref: build5Db().doc(`${COL.TRANSACTION}/${order.uid}`), - data: { - space: nft.space, - 'payload.amount': match.to.amount, - 'payload.nft': nft.uid, - }, - action: 'update', - }); - return { ...nft, ...data } as Nft; }; private depositNftMintedOutsideBuild5 = async ( @@ -223,25 +239,24 @@ export class NftDepositService extends BaseService { set(migratedCollection, 'mediaStatus', MediaStatus.PENDING_UPLOAD); set(space, 'avatarUrl', bannerUrl); } catch (error) { - console.warn('Could not get banner url warning', order.uid, nftOutput.nftId, error); + logger.warn('Could not get banner url warning', order.uid, nftOutput.nftId, error); } } const collectionDocRef = build5Db().doc( - `${COL.COLLECTION}/${(existingCollection || migratedCollection).uid}`, + COL.COLLECTION, + (existingCollection || migratedCollection).uid, ); + this.transactionService.push({ ref: collectionDocRef, - data: existingCollection - ? { total: build5Db().inc(1) } - : { ...migratedCollection, total: build5Db().inc(1) }, - action: 'set', - merge: true, + data: existingCollection ? { total: build5Db().inc(1) } : migratedCollection, + action: existingCollection ? Action.U : Action.C, }); if (isNewSpace) { - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${space.uid}`); - this.transactionService.push({ ref: spaceDocRef, data: space, action: 'set' }); + const spaceDocRef = build5Db().doc(COL.SPACE, space.uid); + this.transactionService.push({ ref: spaceDocRef, data: space, action: Action.C }); } if (!existingCollection && !isEmpty(metadata.collection.royalties)) { @@ -252,19 +267,24 @@ export class NftDepositService extends BaseService { name: 'Royalty space for ' + migratedCollection.name, collectionId: migratedCollection.uid, claimed: false, - validatedAddress: { [order.network!]: royaltyAddress }, + validatedAddress: { [order.network!]: royaltyAddress } as unknown as ValidatedAddress, + createdBy: order.member!, + totalGuardians: 0, + totalMembers: 0, + totalPendingMembers: 0, + guardians: {}, + members: {}, }; - const royaltySpaceDocRef = build5Db().doc(`${COL.SPACE}/${royaltySpace.uid}`); + const royaltySpaceDocRef = build5Db().doc(COL.SPACE, royaltySpace.uid); this.transactionService.push({ ref: royaltySpaceDocRef, data: royaltySpace, - action: 'set', - merge: true, + action: Action.C, }); } - const nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); - this.transactionService.push({ ref: nftDocRef, data: nft, action: 'set' }); + const nftDocRef = build5Db().doc(COL.NFT, nft.uid); + this.transactionService.push({ ref: nftDocRef, data: nft, action: Action.C }); return nft; }; @@ -300,15 +320,15 @@ export class NftDepositService extends BaseService { const getCollection = async (transaction: ITransaction, collectionId: string) => { const collectionSnap = await build5Db() .collection(COL.COLLECTION) - .where('mintingData.nftId', '==', collectionId) - .get(); + .where('mintingData_nftId', '==', collectionId) + .get(); if (collectionSnap.length) { - const docRef = build5Db().doc(`${COL.COLLECTION}/${collectionSnap[0].uid}`); - return await transaction.get(docRef); + const docRef = build5Db().doc(COL.COLLECTION, collectionSnap[0].uid); + return await transaction.get(docRef); } - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${collectionId}`); - return await transaction.get(collectionDocRef); + const collectionDocRef = build5Db().doc(COL.COLLECTION, collectionId); + return await transaction.get(collectionDocRef); }; const getSpace = async ( @@ -317,7 +337,7 @@ const getSpace = async ( collectionId: string, ) => { if (collection) { - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${collection.space}`); + const spaceDocRef = build5Db().doc(COL.SPACE, collection.space!); const space = await spaceDocRef.get(); return { space, isNewSpace: false }; } @@ -326,11 +346,11 @@ const getSpace = async ( .collection(COL.AWARD) .where('collectionId', '==', collectionId) .limit(1) - .get(); + .get(); if (awardsSnap.length) { const award = awardsSnap[0]; - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${award.space}`); + const spaceDocRef = build5Db().doc(COL.SPACE, award.space); const space = await spaceDocRef.get(); return { space, isNewSpace: false }; } diff --git a/packages/functions/src/services/payment/nft/nft-purchase.bulk.service.ts b/packages/functions/src/services/payment/nft/nft-purchase.bulk.service.ts index af35c4d344..a5dbba51a3 100644 --- a/packages/functions/src/services/payment/nft/nft-purchase.bulk.service.ts +++ b/packages/functions/src/services/payment/nft/nft-purchase.bulk.service.ts @@ -24,10 +24,11 @@ import { getRandomEthAddress } from '../../../utils/wallet.utils'; import { WalletService } from '../../wallet/wallet.service'; import { BaseService, HandlerParams } from '../base'; import { assertNftCanBePurchased, getMember } from '../tangle-service/nft/nft-purchase.service'; +import { Action } from '../transaction-service'; import { NftPurchaseService } from './nft-purchase.service'; export class NftPurchaseBulkService extends BaseService { - public handleRequest = async ({ order, match, tranEntry, tran, project }: HandlerParams) => { + public handleRequest = async ({ order, match, tran, project }: HandlerParams) => { const payment = await this.transactionService.createPayment(order, match); const promises = (order.payload.nftOrders || []).map((nftOrder) => @@ -35,66 +36,44 @@ export class NftPurchaseBulkService extends BaseService { ); const nftOrders = await Promise.all(promises); - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${order.uid}`); + const orderDocRef = build5Db().doc(COL.TRANSACTION, order.uid); this.transactionService.push({ ref: orderDocRef, data: { - 'payload.nftOrders': nftOrders, - 'payload.reconciled': true, - 'payload.chainReference': match.msgId, + payload_nftOrders: JSON.stringify(nftOrders), + payload_reconciled: true, + payload_chainReference: match.msgId, }, - action: 'update', + action: Action.U, }); const total = nftOrders.reduce((acc, act) => acc + act.price, 0); - if (total < tranEntry.amount) { - const credit = { - project, - type: TransactionType.CREDIT, - uid: getRandomEthAddress(), - space: order.space, - member: order.member || match.from, - network: order.network, - payload: { - type: TransactionPayloadType.NFT_PURCHASE_BULK, - amount: tranEntry.amount - total, - sourceAddress: order.payload.targetAddress, - targetAddress: match.from, - sourceTransaction: [payment.uid], - reconciled: false, - void: false, - }, - }; - const docRef = build5Db().doc(`${COL.TRANSACTION}/${credit.uid}`); - this.transactionService.push({ ref: docRef, data: credit, action: 'set' }); - } - if (total) { - const targetAddresses = nftOrders - .filter((o) => o.price > 0) - .map((o) => ({ toAddress: o.targetAddress!, amount: o.price })); - const transfer: Transaction = { - project, - type: TransactionType.UNLOCK, - uid: getRandomEthAddress(), - space: order.space || '', - member: order.member || match.from, - network: order.network, - payload: { - type: TransactionPayloadType.TANGLE_TRANSFER_MANY, - amount: total, - sourceAddress: order.payload.targetAddress, - targetAddresses, - sourceTransaction: [payment.uid], - expiresOn: dateToTimestamp(dayjs().add(TRANSACTION_AUTO_EXPIRY_MS)), - milestoneTransactionPath: `${getMilestoneCol(order.network!)}/${tran.milestone}/${ - SUB_COL.TRANSACTIONS - }/${tran.uid}`, - }, - }; - const docRef = build5Db().doc(`${COL.TRANSACTION}/${transfer.uid}`); - this.transactionService.push({ ref: docRef, data: transfer, action: 'set' }); - } + const targetAddresses = nftOrders + .filter((o) => o.price > 0) + .map((o) => ({ + toAddress: o.targetAddress!, + amount: o.price, + })); + const transfer: Transaction = { + project, + type: TransactionType.UNLOCK, + uid: getRandomEthAddress(), + space: order.space || '', + member: order.member || match.from, + network: order.network, + payload: { + type: TransactionPayloadType.TANGLE_TRANSFER_MANY, + amount: total, + sourceAddress: order.payload.targetAddress, + targetAddresses, + sourceTransaction: [payment.uid], + expiresOn: dateToTimestamp(dayjs().add(TRANSACTION_AUTO_EXPIRY_MS)), + milestoneTransactionPath: `${getMilestoneCol(order.network!)}/${tran.milestone}/${SUB_COL.TRANSACTIONS}/${tran.uid}`, + }, + }; + const docRef = build5Db().doc(COL.TRANSACTION, transfer.uid); + this.transactionService.push({ ref: docRef, data: transfer, action: Action.C }); }; private createNftPurchaseOrder = async ( @@ -106,14 +85,16 @@ export class NftPurchaseBulkService extends BaseService { return { ...nftOrder, targetAddress: '' }; } - const nftDocRef = build5Db().doc(`${COL.NFT}/${nftOrder.nft}`); - const nft = await this.transactionService.get(nftDocRef); + const nftDocRef = build5Db().doc(COL.NFT, nftOrder.nft); + const nft = await this.transaction.get(nftDocRef); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${nft.collection}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, nft.collection); const collection = await collectionDocRef.get(); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${nft.space}`); + const spaceDocRef = build5Db().doc(COL.SPACE, nft.space); const space = await spaceDocRef.get(); + + let errorCode: number | undefined = undefined; try { await assertNftCanBePurchased( space, @@ -123,67 +104,61 @@ export class NftPurchaseBulkService extends BaseService { order.member!, true, ); - - if (nft.auction) { - const service = new NftPurchaseService(this.transactionService); - await service.creditBids(nft.auction); - } - - const wallet = await WalletService.newWallet(order.network); - const targetAddress = await wallet.getNewIotaAddressDetails(); - - const royaltySpace = await getSpace(collection.royaltiesSpace); - - const nftPurchaseOrderId = getRandomEthAddress(); - - const nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); - this.transactionService.push({ - ref: nftDocRef, - data: { locked: true, lockedBy: order.uid }, - action: 'update', - }); - - const currentOwner = nft.owner ? await getMember(nft.owner) : space; - - const nftPurchaseOrder = { - project, - type: TransactionType.ORDER, - uid: nftPurchaseOrderId, - member: order.member!, - space: space.uid, - network: order.network, - payload: { - type: TransactionPayloadType.NFT_PURCHASE, - amount: nftOrder.price, - targetAddress: targetAddress.bech32, - beneficiary: nft.owner ? Entity.MEMBER : Entity.SPACE, - beneficiaryUid: nft.owner || collection.space, - beneficiaryAddress: getAddress(currentOwner, order.network), - royaltiesFee: collection.royaltiesFee, - royaltiesSpace: collection.royaltiesSpace || '', - royaltiesSpaceAddress: getAddress(royaltySpace, order.network), - expiresOn: dateToTimestamp(dayjs().add(TRANSACTION_AUTO_EXPIRY_MS)), - validationType: TransactionValidationType.ADDRESS_AND_AMOUNT, - reconciled: false, - void: false, - chainReference: null, - nft: nft.uid, - collection: collection.uid, - restrictions: getRestrictions(collection, nft), - }, - linkedTransactions: [], - }; - const docRef = build5Db().doc(`${COL.TRANSACTION}/${nftPurchaseOrder.uid}`); - this.transactionService.push({ ref: docRef, data: nftPurchaseOrder, action: 'set' }); - - return { ...nftOrder, targetAddress: targetAddress.bech32 }; } catch (error) { - return { - ...nftOrder, - price: 0, - error: get(error, 'details.code', 0), - targetAddress: '', - } as NftBulkOrder; + errorCode = get(error, 'eCode', 0); + } + + if (nft.auction) { + const service = new NftPurchaseService(this.transactionService); + await service.creditBids(nft.auction); } + + const wallet = await WalletService.newWallet(order.network); + const targetAddress = await wallet.getNewIotaAddressDetails(); + + const royaltySpace = await getSpace(collection.royaltiesSpace); + + const nftPurchaseOrderId = getRandomEthAddress(); + + this.transactionService.push({ + ref: build5Db().doc(COL.NFT, nft.uid), + data: { locked: true, lockedBy: order.uid }, + action: Action.U, + }); + + const currentOwner = nft.owner ? await getMember(nft.owner) : space; + + const nftPurchaseOrder = { + project, + type: TransactionType.ORDER, + uid: nftPurchaseOrderId, + member: order.member!, + space: space.uid, + network: order.network, + payload: { + type: TransactionPayloadType.NFT_PURCHASE, + amount: nftOrder.price, + targetAddress: targetAddress.bech32, + beneficiary: nft.owner ? Entity.MEMBER : Entity.SPACE, + beneficiaryUid: nft.owner || collection.space, + beneficiaryAddress: getAddress(currentOwner, order.network), + royaltiesFee: collection.royaltiesFee, + royaltiesSpace: collection.royaltiesSpace || '', + royaltiesSpaceAddress: getAddress(royaltySpace, order.network), + expiresOn: dateToTimestamp(dayjs().add(TRANSACTION_AUTO_EXPIRY_MS)), + validationType: TransactionValidationType.ADDRESS_AND_AMOUNT, + reconciled: false, + void: errorCode !== undefined, + chainReference: null, + nft: nft.uid, + collection: collection.uid, + restrictions: getRestrictions(collection, nft), + }, + linkedTransactions: [], + }; + const docRef = build5Db().doc(COL.TRANSACTION, nftPurchaseOrder.uid); + this.transactionService.push({ ref: docRef, data: nftPurchaseOrder, action: Action.C }); + + return { ...nftOrder, targetAddress: targetAddress.bech32, error: errorCode }; }; } 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 679fa61f3a..fe4674d682 100644 --- a/packages/functions/src/services/payment/nft/nft-purchase.service.ts +++ b/packages/functions/src/services/payment/nft/nft-purchase.service.ts @@ -9,12 +9,13 @@ import { TransactionType, } from '@build-5/interfaces'; import { BaseService, HandlerParams } from '../base'; +import { Action } from '../transaction-service'; import { BaseNftService } from './common'; 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); + const nftDocRef = build5Db().doc(COL.NFT, order.payload.nft!); + const nft = await this.transaction.get(nftDocRef); if (nft.availableFrom === null) { await this.transactionService.processAsInvalid(tran, order, tranEntry, build5Tran); @@ -43,12 +44,12 @@ export class NftPurchaseService extends BaseService { }; public creditBids = async (auctionId: string) => { - const auctionDocRef = build5Db().doc(`${COL.AUCTION}/${auctionId}`); + const auctionDocRef = build5Db().doc(COL.AUCTION, auctionId); const auction = await this.transaction.get(auctionDocRef); this.transactionService.push({ ref: auctionDocRef, data: { active: false }, - action: 'update', + action: Action.U, }); for (const bid of auction.bids) { @@ -56,9 +57,9 @@ export class NftPurchaseService extends BaseService { .collection(COL.TRANSACTION) .where('type', '==', TransactionType.PAYMENT) .where('member', '==', bid.bidder) - .where('payload.invalidPayment', '==', false) - .where('payload.auction', '==', auctionId) - .get(); + .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 || '', @@ -73,42 +74,44 @@ export class NftPurchaseService extends BaseService { }; public markAsVoid = async (transaction: Transaction): Promise => { - const refSource = build5Db().doc(`${COL.TRANSACTION}/${transaction.uid}`); - const data = (await this.transactionService.get(refSource))!; + const tranDocRef = build5Db().doc(COL.TRANSACTION, transaction.uid); + + const setVoid = () => { + this.transactionService.push({ + ref: tranDocRef, + data: { payload_void: true }, + action: Action.U, + }); + }; + if (transaction.payload.nft) { if (transaction.payload.type === TransactionPayloadType.NFT_PURCHASE) { - const payload = data.payload; - payload.void = true; - this.transactionService.push({ ref: refSource, data: data, action: 'update' }); + setVoid(); - // Unlock NFT. - const refNft = build5Db().collection(COL.NFT).doc(transaction.payload.nft); this.transactionService.push({ - ref: refNft, + ref: build5Db().doc(COL.NFT, transaction.payload.nft), data: { locked: false, lockedBy: null }, - action: 'update', + action: Action.U, }); - } else if ( - [TransactionPayloadType.AUCTION_BID, TransactionPayloadType.NFT_BID].includes( - transaction.payload.type!, - ) + return; + } + if ( + transaction.payload.type === TransactionPayloadType.AUCTION_BID || + transaction.payload.type === TransactionPayloadType.NFT_BID ) { const payments = await build5Db() .collection(COL.TRANSACTION) - .where('payload.invalidPayment', '==', false) - .where('payload.sourceTransaction', 'array-contains', transaction.uid) + .where('payload_invalidPayment', '==', false) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + .where('payload_sourceTransaction', 'array-contains', transaction.uid as any) .limit(1) .get(); if (payments.length === 0) { - const payload = data.payload; - payload.void = true; - this.transactionService.push({ ref: refSource, data: data, action: 'update' }); + setVoid(); } } - } else { - const payload = data.payload; - payload.void = true; - this.transactionService.push({ ref: refSource, data, action: 'update' }); } + + setVoid(); }; } diff --git a/packages/functions/src/services/payment/nft/nft-stake.service.ts b/packages/functions/src/services/payment/nft/nft-stake.service.ts index 5fbfeb28dd..6badc8c317 100644 --- a/packages/functions/src/services/payment/nft/nft-stake.service.ts +++ b/packages/functions/src/services/payment/nft/nft-stake.service.ts @@ -20,12 +20,14 @@ import { Utils, } from '@iota/sdk'; import dayjs from 'dayjs'; -import { cloneDeep, get } from 'lodash'; +import { cloneDeep } from 'lodash'; import { dateToTimestamp } from '../../../utils/dateTime.utils'; +import { logger } from '../../../utils/logger'; import { getRandomEthAddress } from '../../../utils/wallet.utils'; import { WalletService } from '../../wallet/wallet.service'; import { BaseService, HandlerParams } from '../base'; import { createNftWithdrawOrder } from '../tangle-service/nft/nft-purchase.service'; +import { Action } from '../transaction-service'; import { NftDepositService } from './nft-deposit.service'; export class NftStakeService extends BaseService { @@ -49,31 +51,31 @@ export class NftStakeService extends BaseService { nft, order.member!, match.from, - get(order, 'payload.weeks', 0), - get(order, 'payload.stakeType', StakeType.DYNAMIC), + order.payload.weeks || 0, + order.payload.stakeType || StakeType.DYNAMIC, ); - const withdrawOrderDocRef = build5Db().doc(`${COL.TRANSACTION}/${withdrawOrder.uid}`); + const withdrawOrderDocRef = build5Db().doc(COL.TRANSACTION, withdrawOrder.uid); this.transactionService.push({ ref: withdrawOrderDocRef, data: withdrawOrder, - action: 'set', + action: Action.C, }); - const nftDocRef = build5Db().doc(`${COL.NFT}/${nftUpdateData.uid}`); + const nftDocRef = build5Db().doc(COL.NFT, nft.uid); this.transactionService.push({ ref: nftDocRef, data: nftUpdateData, - action: 'update', + action: Action.U, }); await this.transactionService.createPayment(order, match); this.transactionService.markAsReconciled(order, match.msgId); - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${order.uid}`); + const orderDocRef = build5Db().doc(COL.TRANSACTION, order.uid); this.transactionService.push({ ref: orderDocRef, - data: { 'payload.nft': nft.uid, 'payload.collection': nft.collection }, - action: 'update', + data: { payload_nft: nft.uid, payload_collection: nft.collection }, + action: Action.U, }); // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (error: any) { @@ -85,13 +87,13 @@ export class NftStakeService extends BaseService { this.transactionService.createCredit(TransactionPayloadType.DEPOSIT_NFT, payment, match); } - console.error('nft stake error', order.uid, payment.uid, error, customErrorParams); + logger.error('nft stake error', order.uid, payment.uid, error, customErrorParams); } }; private getNftOutputAmount = async (order: Transaction, tranEntry: MilestoneTransactionEntry) => { const wallet = await WalletService.newWallet(order.network); - const weeks = get(order, 'payload.weeks', 0); + const weeks = order.payload.weeks || 0; const params: NftOutputBuilderParams = cloneDeep(tranEntry.nftOutput as NftOutput); params.features = params.features?.filter( (f) => f.type !== FeatureType.Tag && f.type !== FeatureType.Sender, diff --git a/packages/functions/src/services/payment/nft/nft-transfer.service.ts b/packages/functions/src/services/payment/nft/nft-transfer.service.ts index 3c16f3750d..95d183abab 100644 --- a/packages/functions/src/services/payment/nft/nft-transfer.service.ts +++ b/packages/functions/src/services/payment/nft/nft-transfer.service.ts @@ -1,4 +1,4 @@ -import { ITransaction, build5Db } from '@build-5/database'; +import { ITransaction, PgNftUpdate, build5Db } from '@build-5/database'; import { COL, Entity, @@ -22,7 +22,7 @@ interface NftTransfer { interface NftTransferResponse { code: number; - nftUpdateData?: unknown; + nftUpdateData?: PgNftUpdate; order?: Transaction; } @@ -35,8 +35,8 @@ export const createNftTransferData = async ( const members: { [uid: string]: Member } = {}; const getTarget = async (nft: Nft, transfer: NftTransfer) => { - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${transfer.target}`); - const member = members[transfer.target] || (await memberDocRef.get()); + const memberDocRef = build5Db().doc(COL.MEMBER, transfer.target); + const member = members[transfer.target] || (await memberDocRef.get()); if (member) { members[transfer.target] = member; @@ -58,7 +58,7 @@ export const createNftTransferData = async ( try { assertCanBeWithdrawn(nft, owner); } catch (error) { - return { [transfer.nft]: { code: get(error, 'details.code', 0) } }; + return { [transfer.nft]: { code: get(error, 'eCode', 0) } }; } const { targetAddress, withdraw } = await getTarget(nft, transfer); @@ -91,7 +91,7 @@ export const createNftTransferData = async ( } const { order, nftUpdateData } = createNftWithdrawOrder(project, nft, owner, targetAddress); - return { [transfer.nft]: { code: 200, nftUpdateData: nftUpdateData, order } }; + return { [transfer.nft]: { code: 200, nftUpdateData, order } }; }, ); @@ -99,14 +99,14 @@ export const createNftTransferData = async ( }; const getNft = async (transaction: ITransaction, uidOrTangleId: string) => { - const nftDocRef = build5Db().doc(`${COL.NFT}/${uidOrTangleId}`); - const nft = await transaction.get(nftDocRef); + const nftDocRef = build5Db().doc(COL.NFT, uidOrTangleId); + const nft = await transaction.get(nftDocRef); if (nft) { return nft; } const snap = await build5Db() .collection(COL.NFT) - .where('mintingData.nftId', '==', uidOrTangleId) - .get(); + .where('mintingData_nftId', '==', uidOrTangleId) + .get(); return head(snap); }; diff --git a/packages/functions/src/services/payment/payment-processing.ts b/packages/functions/src/services/payment/payment-processing.ts index 5feb8a7866..fc3f760faa 100644 --- a/packages/functions/src/services/payment/payment-processing.ts +++ b/packages/functions/src/services/payment/payment-processing.ts @@ -38,7 +38,7 @@ import { TokenMintedAirdropService } from './token/token-minted-airdrop.service' import { MintedTokenClaimService } from './token/token-minted-claim.service'; import { TokenPurchaseService } from './token/token-purchase.service'; import { TokenTradeService } from './token/token-trade.service'; -import { TransactionService } from './transaction-service'; +import { Action, TransactionService } from './transaction-service'; import { VotingService } from './voting-service'; export class ProcessingService { @@ -77,8 +77,8 @@ export class ProcessingService { orderId: string, build5Tran: Transaction | undefined, ): Promise { - const orderRef = build5Db().doc(`${COL.TRANSACTION}/${orderId}`); - const order = await this.tranService.transaction.get(orderRef); + const orderRef = build5Db().doc(COL.TRANSACTION, orderId); + const order = await this.transaction.get(orderRef); if (!order) { return; @@ -103,7 +103,7 @@ export class ProcessingService { const type = tranEntry.nftOutput ? TransactionPayloadType.UNLOCK_NFT : TransactionPayloadType.UNLOCK_FUNDS; - await this.tranService.createUnlockTransaction( + this.tranService.createUnlockTransaction( undefined, order, tran, @@ -138,7 +138,7 @@ export class ProcessingService { ...this.tranService.linkedTransactions, ], }, - action: 'update', + action: Action.U, }); } @@ -204,9 +204,9 @@ export class ProcessingService { const snap = await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.ORDER) - .where('payload.targetAddress', '==', address) + .where('payload_targetAddress', '==', address) .limit(1) - .get(); + .get(); return head(snap); }; @@ -214,7 +214,7 @@ export class ProcessingService { if (isEmpty(tran.build5TransactionId)) { return; } - const docRef = build5Db().doc(`${COL.TRANSACTION}/${tran.build5TransactionId}`); - return docRef.get(); + const docRef = build5Db().doc(COL.TRANSACTION, tran.build5TransactionId!); + return docRef.get(); }; } diff --git a/packages/functions/src/services/payment/space/space-service.ts b/packages/functions/src/services/payment/space/space-service.ts index 11f2c2a327..2d6f332326 100644 --- a/packages/functions/src/services/payment/space/space-service.ts +++ b/packages/functions/src/services/payment/space/space-service.ts @@ -21,6 +21,7 @@ import { getProject } from '../../../utils/common.utils'; import { serverTime } from '../../../utils/dateTime.utils'; import { WalletService } from '../../wallet/wallet.service'; import { BaseService, HandlerParams } from '../base'; +import { Action } from '../transaction-service'; export class SpaceClaimService extends BaseService { public handleRequest = async ({ order, match }: HandlerParams) => { @@ -31,13 +32,13 @@ export class SpaceClaimService extends BaseService { match, ); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${order.space}`); - const space = await this.transactionService.get(spaceDocRef); + const spaceDocRef = build5Db().doc(COL.SPACE, order.space!); + const space = await this.transaction.get(spaceDocRef); if (!space.collectionId || space.claimed) { return; } - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${space.collectionId}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, space.collectionId); const collection = await collectionDocRef.get(); const senderIsIssuer = await senderIsCollectionIssuer(order.network!, match.from, collection); @@ -52,33 +53,43 @@ export class SpaceClaimService extends BaseService { parentCol: COL.SPACE, createdOn: serverTime(), }; - const spaceGuardianDocRef = spaceDocRef.collection(SUB_COL.GUARDIANS).doc(order.member!); + const spaceGuardianDocRef = build5Db().doc( + COL.SPACE, + order.space!, + SUB_COL.GUARDIANS, + order.member!, + ); this.transactionService.push({ ref: spaceGuardianDocRef, data: spaceMember, - action: 'set', - merge: true, + action: Action.C, }); - const spaceMemberDocRef = spaceDocRef.collection(SUB_COL.MEMBERS).doc(order.member!); + const spaceMemberDocRef = build5Db().doc( + COL.SPACE, + order.space!, + SUB_COL.MEMBERS, + order.member!, + ); this.transactionService.push({ ref: spaceMemberDocRef, data: spaceMember, - action: 'set', - merge: true, + action: Action.C, }); this.transactionService.push({ ref: spaceDocRef, - data: { totalMembers: build5Db().inc(1), totalGuardians: build5Db().inc(1), claimed: true }, - action: 'update', + data: { + totalMembers: build5Db().inc(1), + totalGuardians: build5Db().inc(1), + claimed: true, + }, + action: Action.U, }); - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${order.member}`); this.transactionService.push({ - ref: memberDocRef, + ref: build5Db().doc(COL.MEMBER, order.member!), data: { spaces: { [space.uid]: { uid: space.uid, isMember: true } } }, - action: 'update', - merge: true, + action: Action.U, }); }; } diff --git a/packages/functions/src/services/payment/stake-service.ts b/packages/functions/src/services/payment/stake-service.ts index d5d4f575a5..2cd26e1ea4 100644 --- a/packages/functions/src/services/payment/stake-service.ts +++ b/packages/functions/src/services/payment/stake-service.ts @@ -11,11 +11,11 @@ import { calcStakedMultiplier, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { get } from 'lodash'; import { getProject } from '../../utils/common.utils'; import { dateToTimestamp } from '../../utils/dateTime.utils'; import { getRandomEthAddress } from '../../utils/wallet.utils'; import { BaseService, HandlerParams } from './base'; +import { Action } from './transaction-service'; export class StakeService extends BaseService { public handleRequest = async ({ project, order, match }: HandlerParams) => { @@ -23,7 +23,7 @@ export class StakeService extends BaseService { const matchAmount = match.to.amount; const nativeTokens = (match.to.nativeTokens || []).map((nt) => ({ ...nt, amount: nt.amount })); - const tokenId = get(order, 'payload.tokenId', ''); + const tokenId = order.payload.tokenId || ''; const stakeAmount = Number(nativeTokens.find((nt) => nt.id === tokenId)?.amount || 0); if (!stakeAmount || nativeTokens.length > 1 || matchAmount < order.payload.amount!) { @@ -36,12 +36,12 @@ export class StakeService extends BaseService { } this.transactionService.markAsReconciled(order, match.msgId); - const weeks = get(order, 'payload.weeks', 1); + const weeks = order.payload.weeks || 1; const stakedValue = Math.floor(stakeAmount * calcStakedMultiplier(weeks)); const expiresAt = dateToTimestamp(dayjs().add(weeks, 'week').toDate()); - const tokenUid = get(order, 'payload.token', ''); - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${tokenUid}`); + const tokenUid = order.payload.token || ''; + const tokenDocRef = build5Db().doc(COL.TOKEN, tokenUid); const token = await tokenDocRef.get(); const billPayment: Transaction = { @@ -65,7 +65,7 @@ export class StakeService extends BaseService { royalty: false, void: false, vestingAt: expiresAt, - customMetadata: get(order, 'payload.customMetadata', {}), + customMetadata: order.payload.customMetadata || {}, token: token!.uid, tokenSymbol: token!.symbol, }, @@ -76,7 +76,7 @@ export class StakeService extends BaseService { uid: getRandomEthAddress(), member: order.member!, token: order.payload.token!, - type: get(order, 'payload.stakeType', StakeType.DYNAMIC), + type: order.payload.stakeType || StakeType.DYNAMIC, space: order.space!, amount: stakeAmount, value: stakedValue, @@ -85,20 +85,20 @@ export class StakeService extends BaseService { expirationProcessed: false, orderId: order.uid, billPaymentId: billPayment.uid, - customMetadata: get(order, 'payload.customMetadata', {}), + customMetadata: order.payload.customMetadata || {}, }; billPayment.payload.stake = stake.uid; this.transactionService.push({ - ref: build5Db().doc(`${COL.STAKE}/${stake.uid}`), + ref: build5Db().doc(COL.STAKE, stake.uid), data: stake, - action: 'set', + action: Action.C, }); this.transactionService.push({ - ref: build5Db().doc(`${COL.TRANSACTION}/${billPayment.uid}`), + ref: build5Db().doc(COL.TRANSACTION, billPayment.uid), data: billPayment, - action: 'set', + action: Action.C, }); }; } diff --git a/packages/functions/src/services/payment/stamp.service.ts b/packages/functions/src/services/payment/stamp.service.ts index e07219b21e..bdc4351b2b 100644 --- a/packages/functions/src/services/payment/stamp.service.ts +++ b/packages/functions/src/services/payment/stamp.service.ts @@ -13,19 +13,19 @@ import { set } from 'lodash'; import { packBasicOutput } from '../../utils/basic-output.utils'; import { getProject } from '../../utils/common.utils'; import { getBucket, getStampRoyaltyAddress } from '../../utils/config.utils'; -import { dateToTimestamp } from '../../utils/dateTime.utils'; import { migrateUriToSotrage, uriToUrl } from '../../utils/media.utils'; import { getRandomEthAddress } from '../../utils/wallet.utils'; import { isStorageUrl } from '../joi/common'; import { WalletService } from '../wallet/wallet.service'; import { BaseService, HandlerParams } from './base'; import { getStampDailyCost } from './tangle-service/stamp/StampTangleService'; +import { Action } from './transaction-service'; export class StampService extends BaseService { public handleRequest = async ({ order, match }: HandlerParams) => { const payment = await this.transactionService.createPayment(order, match); - const stampDocRef = build5Db().doc(`${COL.STAMP}/${order.payload.stamp}`); + const stampDocRef = build5Db().doc(COL.STAMP, order.payload.stamp!); const stamp = await this.transaction.get(stampDocRef); const mintAmount = stamp.funded @@ -84,11 +84,10 @@ export class StampService extends BaseService { void: false, }, }; - const creditDocRef = build5Db().doc(`${COL.TRANSACTION}/${credit.uid}`); this.transactionService.push({ - ref: creditDocRef, + ref: build5Db().doc(COL.TRANSACTION, credit.uid), data: credit, - action: 'set', + action: Action.C, }); } } @@ -99,7 +98,7 @@ export class StampService extends BaseService { const updateData = { funded: true, mediaStatus: stamp.mediaStatus || MediaStatus.PENDING_UPLOAD, - expiresAt: dateToTimestamp(expiresAt), + expiresAt: expiresAt.toDate(), }; if (!stamp.funded && !isStorageUrl(stamp.originUri)) { const bucket = build5Storage().bucket(getBucket()); @@ -113,7 +112,7 @@ export class StampService extends BaseService { ); set(updateData, 'build5Url', build5Url); } - this.transactionService.push({ ref: stampDocRef, data: updateData, action: 'update' }); + this.transactionService.push({ ref: stampDocRef, data: updateData, action: Action.U }); const aliasId = order.payload.aliasId; @@ -136,21 +135,19 @@ export class StampService extends BaseService { void: false, }, }; - const royaltyPaymentDocRef = build5Db().doc(`${COL.TRANSACTION}/${royaltyPayment.uid}`); this.transactionService.push({ - ref: royaltyPaymentDocRef, + ref: build5Db().doc(COL.TRANSACTION, royaltyPayment.uid), data: royaltyPayment, - action: 'set', + action: Action.C, }); - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${order.uid}`); this.transactionService.push({ - ref: orderDocRef, + ref: build5Db().doc(COL.TRANSACTION, order.uid), data: { - 'payload.days': build5Db().deleteField(), - 'payload.amount': Number(royaltyOutput.amount), + payload_days: undefined, + payload_amount: Number(royaltyOutput.amount), }, - action: 'update', + action: Action.U, }); if (stamp.funded) { @@ -177,14 +174,14 @@ export class StampService extends BaseService { }, }; this.transactionService.push({ - ref: build5Db().doc(`${COL.TRANSACTION}/${mintAlias.uid}`), + ref: build5Db().doc(COL.TRANSACTION, mintAlias.uid), data: mintAlias, - action: 'set', + action: Action.C, }); return; } - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${stamp.space}`); + const spaceDocRef = build5Db().doc(COL.SPACE, stamp.space); const space = await spaceDocRef.get(); const mintNftOrder: Transaction = { @@ -205,11 +202,11 @@ export class StampService extends BaseService { stamp: order.payload.stamp, }, }; - const nftMintOrderDocRef = build5Db().doc(`${COL.TRANSACTION}/${mintNftOrder.uid}`); + const nftMintOrderDocRef = build5Db().doc(COL.TRANSACTION, mintNftOrder.uid); this.transactionService.push({ ref: nftMintOrderDocRef, data: mintNftOrder, - action: 'set', + action: Action.C, }); return; diff --git a/packages/functions/src/services/payment/swap/swap-service.ts b/packages/functions/src/services/payment/swap/swap-service.ts index a7bf482a08..74ba05528d 100644 --- a/packages/functions/src/services/payment/swap/swap-service.ts +++ b/packages/functions/src/services/payment/swap/swap-service.ts @@ -4,7 +4,6 @@ import { Entity, Member, Network, - Nft, Swap, SwapCreateRequest, SwapCreateTangleRequest, @@ -25,17 +24,17 @@ import { invalidArgument } from '../../../utils/error.utils'; import { getRandomEthAddress } from '../../../utils/wallet.utils'; import { Wallet } from '../../wallet/wallet'; import { BaseService, HandlerParams } from '../base'; -import { TransactionMatch } from '../transaction-service'; +import { Action, TransactionMatch } from '../transaction-service'; export class SwapService extends BaseService { handleRequest = async ({ project, order, match }: HandlerParams) => { const payment = await this.transactionService.createPayment(order, match); - const swapDocRef = build5Db().doc(`${COL.SWAP}/${order.payload.swap!}`); - const swap = await swapDocRef.get(); + const swapDocRef = build5Db().doc(COL.SWAP, order.payload.swap!); + const swap = await this.transaction.get(swapDocRef); if (swap.status == SwapStatus.FULFILLED || swap.status === SwapStatus.REJECTED) { - await this.createCredit(payment, match); + this.createCredit(payment, match); return; } @@ -51,8 +50,8 @@ export class SwapService extends BaseService { const fieldName = this.getUpdateFieldName(swap, swapOutput); this.transactionService.push({ ref: swapDocRef, - data: { [fieldName]: build5Db().arrayUnion(swapOutput) }, - action: 'update', + data: { [fieldName]: JSON.stringify([...get(swap, fieldName, []), swapOutput]) }, + action: Action.U, }); if (fieldName !== 'askOutputs') { @@ -66,14 +65,14 @@ export class SwapService extends BaseService { const transfers = await createSwapTransfers(project, { ...swap, askOutputs }); for (const transfer of transfers) { - const docRef = build5Db().doc(`${COL.TRANSACTION}/${transfer.uid}`); - this.transactionService.push({ ref: docRef, data: transfer, action: 'set' }); + const docRef = build5Db().doc(COL.TRANSACTION, transfer.uid); + this.transactionService.push({ ref: docRef, data: transfer, action: Action.C }); } this.transactionService.push({ ref: swapDocRef, data: { status: SwapStatus.FULFILLED }, - action: 'update', + action: Action.U, }); }; @@ -90,17 +89,17 @@ export class SwapService extends BaseService { return swap.baseTokenAmountAsk ? 'askOutputs' : 'bidOutputs'; }; - private createCredit = async (payment: Transaction, match: TransactionMatch) => { + private createCredit = (payment: Transaction, match: TransactionMatch) => { if (match.to.nftOutput?.nftId) { this.transactionService.createNftCredit(payment, match); return; } this.transactionService.createCredit(TransactionPayloadType.SWAP, payment, match); - const paymentDocRef = build5Db().doc(`${COL.TRANSACTION}/${payment.uid}`); + const paymentDocRef = build5Db().doc(COL.TRANSACTION, payment.uid); this.transactionService.push({ ref: paymentDocRef, - data: { 'payload.invalidPayment': true }, - action: 'set', + data: { payload_invalidPayment: true }, + action: Action.U, }); }; } @@ -168,8 +167,8 @@ export const createSwapOrder = async ( }; const getNftTangleId = async (wallet: Wallet, uidOrTangleId: string) => { - const docRef = build5Db().doc(`${COL.NFT}/${uidOrTangleId}`); - const nft = await docRef.get(); + const docRef = build5Db().doc(COL.NFT, uidOrTangleId); + const nft = await docRef.get(); if (nft?.mintingData?.nftId) { return nft.mintingData.nftId; } @@ -324,7 +323,7 @@ export const asksAreFulfilled = (swap: Swap) => { }; export const createSwapTransfers = async (project: string, swap: Swap) => { - const targetMemberDocRef = build5Db().doc(`${COL.MEMBER}/${swap.recipient}`); + const targetMemberDocRef = build5Db().doc(COL.MEMBER, swap.recipient); const targetMember = await targetMemberDocRef.get(); const bidTransfers = (swap.bidOutputs || []).map((bid) => { @@ -339,7 +338,7 @@ export const createSwapTransfers = async (project: string, swap: Swap) => { ); }); - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${swap.createdBy}`); + const memberDocRef = build5Db().doc(COL.MEMBER, swap.createdBy!); const mmber = await memberDocRef.get(); const askTransfers = (swap.askOutputs || []).map((ask) => { const func = ask.nftId ? createNftTransfer : createAssetTransfer; diff --git a/packages/functions/src/services/payment/tangle-service/TangleRequestService.ts b/packages/functions/src/services/payment/tangle-service/TangleRequestService.ts index fe029ae402..6c45280f67 100644 --- a/packages/functions/src/services/payment/tangle-service/TangleRequestService.ts +++ b/packages/functions/src/services/payment/tangle-service/TangleRequestService.ts @@ -1,17 +1,18 @@ import { build5Db } from '@build-5/database'; import { COL, - Member, Network, NetworkAddress, TangleRequestType, TangleResponse, Transaction, + ValidatedAddress, WenError, } from '@build-5/interfaces'; import { get, isEmpty } from 'lodash'; import { getOutputMetadata } from '../../../utils/basic-output.utils'; import { invalidArgument } from '../../../utils/error.utils'; +import { logger } from '../../../utils/logger'; import { getRandomNonce } from '../../../utils/wallet.utils'; import { BaseTangleService, HandlerParams } from '../base'; import { TangleAddressValidationService } from './address/address-validation.service'; @@ -69,7 +70,7 @@ export class TangleRequestService extends BaseTangleService { ); } } catch (error) { - console.warn('tangle service error warning', owner, error); + logger.warn('tangle service error warning', owner, error); if (!payment) { payment = await this.transactionService.createPayment({ ...order, member: owner }, match); } @@ -78,8 +79,8 @@ export class TangleRequestService extends BaseTangleService { match, { status: 'error', - code: get(error, 'details.code', 1000), - message: get(error, 'details.key', 'none'), + code: get(error, 'eCode', 1000), + message: get(error, 'eKey', 'none'), }, tranEntry.outputId!, ); @@ -164,17 +165,17 @@ export class TangleRequestService extends BaseTangleService { }; private getOwner = async (senderAddress: NetworkAddress, network: Network) => { - const docRef = build5Db().doc(`${COL.MEMBER}/${senderAddress}`); - const member = await docRef.get(); + const docRef = build5Db().doc(COL.MEMBER, senderAddress); + const member = await docRef.get(); if (member) { return senderAddress; } const snap = await build5Db() .collection(COL.MEMBER) - .where(`validatedAddress.${network}`, '==', senderAddress) + .where(`${network}Address`, '==', senderAddress) .limit(2) - .get(); + .get(); if (snap.length > 1) { throw invalidArgument(WenError.multiple_members_with_same_address); @@ -189,7 +190,7 @@ export class TangleRequestService extends BaseTangleService { nonce: getRandomNonce(), validatedAddress: { [network as string]: senderAddress, - }, + } as unknown as ValidatedAddress, }; await docRef.create(memberData); diff --git a/packages/functions/src/services/payment/tangle-service/address/address-validation.service.ts b/packages/functions/src/services/payment/tangle-service/address/address-validation.service.ts index 0540e0ab13..a690264d76 100644 --- a/packages/functions/src/services/payment/tangle-service/address/address-validation.service.ts +++ b/packages/functions/src/services/payment/tangle-service/address/address-validation.service.ts @@ -2,7 +2,6 @@ import { build5Db } from '@build-5/database'; import { COL, Network, - Space, TRANSACTION_AUTO_EXPIRY_MS, TangleResponse, Transaction, @@ -21,6 +20,7 @@ import { assertIsGuardian } from '../../../../utils/token.utils'; import { getRandomEthAddress } from '../../../../utils/wallet.utils'; import { WalletService } from '../../../wallet/wallet.service'; import { BaseTangleService, HandlerParams } from '../../base'; +import { Action } from '../../transaction-service'; import { validateAddressSchemaObject } from './AddressValidationTangleRequestSchema'; export class TangleAddressValidationService extends BaseTangleService { @@ -43,9 +43,9 @@ export class TangleAddressValidationService extends BaseTangleService { - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${spaceId}`); - const space = spaceId ? await spaceDocRef.get() : undefined; + const spaceDocRef = build5Db().doc(COL.SPACE, spaceId!); + const space = spaceId ? await spaceDocRef.get() : undefined; if (spaceId && !space) { throw invalidArgument(WenError.space_does_not_exists); } 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 index ebccb5054a..5c1b7c771a 100644 --- 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 @@ -3,14 +3,11 @@ import { Auction, AuctionType, COL, - Collection, CollectionStatus, Entity, MIN_AMOUNT_TO_TRANSFER, - Member, Nft, NftAccess, - Space, Transaction, TransactionPayloadType, TransactionType, @@ -33,8 +30,8 @@ export const createBidOrder = async ( auctionId: string, ip = '', ): Promise => { - const auctionDocRef = build5Db().doc(`${COL.AUCTION}/${auctionId}`); - const auction = await auctionDocRef.get(); + const auctionDocRef = build5Db().doc(COL.AUCTION, auctionId); + const auction = await auctionDocRef.get(); if (!auction) { throw invalidArgument(WenError.auction_does_not_exist); } @@ -76,14 +73,14 @@ export const createBidOrder = async ( if (auction.type === AuctionType.NFT) { const nft = validationResponse as Nft; - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${nft.collection}`); - const collection = (await collectionDocRef.get())!; + 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 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(); + const prevOwnerDocRef = build5Db().doc(COL.MEMBER, nft.owner!); + const prevOwner = await prevOwnerDocRef.get(); assertMemberHasValidAddress(prevOwner, network); const royaltySpace = await getSpace(collection.royaltiesSpace); @@ -126,8 +123,8 @@ const assertAuctionData = async (owner: string, ip: string, auction: Auction) => }; const assertNftAuction = async (owner: string, ip: string, auction: Auction) => { - const nftDocRef = build5Db().doc(`${COL.NFT}/${auction.nftId}`); - const nft = await nftDocRef.get(); + const nftDocRef = build5Db().doc(COL.NFT, auction.nftId!); + const nft = await nftDocRef.get(); if (!nft) { throw invalidArgument(WenError.nft_does_not_exists); } @@ -136,8 +133,8 @@ const assertNftAuction = async (owner: string, ip: string, auction: Auction) => await assertIpNotBlocked(ip, nft.uid, 'nft'); } - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${nft.collection}`); - const collection = (await collectionDocRef.get())!; + const collectionDocRef = build5Db().doc(COL.COLLECTION, nft.collection); + const collection = (await collectionDocRef.get())!; if (![CollectionStatus.PRE_MINTED, CollectionStatus.MINTED].includes(collection.status!)) { throw invalidArgument(WenError.invalid_collection_status); 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 index bb41f7e47b..19a714f089 100644 --- 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 @@ -1,8 +1,9 @@ import { build5Db } from '@build-5/database'; -import { COL, Nft, TangleResponse, TransactionPayloadType, WenError } from '@build-5/interfaces'; +import { COL, TangleResponse, TransactionPayloadType, WenError } from '@build-5/interfaces'; import { invalidArgument } from '../../../../utils/error.utils'; import { assertValidationAsync } from '../../../../utils/schema.utils'; import { BaseTangleService, HandlerParams } from '../../base'; +import { Action } from '../../transaction-service'; import { auctionBidTangleSchema } from './AuctionBidTangleRequestSchema'; import { nftBidSchema } from './NftBidTangleRequestSchema'; import { createBidOrder } from './auction.bid.order'; @@ -19,8 +20,8 @@ export class TangleNftAuctionBidService extends BaseTangleService { const params = await assertValidationAsync(nftBidSchema, request); - const nftDocRef = build5Db().doc(`${COL.NFT}/${params.nft}`); - const nft = await nftDocRef.get(); + 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; @@ -31,10 +32,9 @@ export class TangleNftAuctionBidService extends BaseTangleService { } this.transactionService.push({ - ref: build5Db().doc(`${COL.TRANSACTION}/${order.uid}`), + ref: build5Db().doc(COL.TRANSACTION, order.uid), data: order, - action: 'set', - merge: true, + action: Action.C, }); this.transactionService.createUnlockTransaction( 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 index 8ee89f4838..7c8bd85f0a 100644 --- 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 @@ -15,6 +15,7 @@ import { dateToTimestamp } from '../../../../utils/dateTime.utils'; import { assertValidationAsync } from '../../../../utils/schema.utils'; import { getRandomEthAddress } from '../../../../utils/wallet.utils'; import { BaseTangleService, HandlerParams } from '../../base'; +import { Action } from '../../transaction-service'; import { auctionCreateTangleSchema } from './AuctionCreateTangleRequestSchema'; export class TangleAuctionCreateService extends BaseTangleService { @@ -25,13 +26,13 @@ export class TangleAuctionCreateService extends BaseTangleService => { const params = await assertValidationAsync(auctionCreateTangleSchema, request); - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${owner}`); + const memberDocRef = build5Db().doc(COL.MEMBER, owner); const member = await memberDocRef.get(); const auction = getAuctionData(project, member, params); - const auctionDocRef = build5Db().doc(`${COL.AUCTION}/${auction.uid}`); + const auctionDocRef = build5Db().doc(COL.AUCTION, auction.uid); - this.transactionService.push({ ref: auctionDocRef, data: auction, action: 'set' }); + this.transactionService.push({ ref: auctionDocRef, data: auction, action: Action.C }); return { auction: auction.uid }; }; diff --git a/packages/functions/src/services/payment/tangle-service/award/award.approve.participant.service.ts b/packages/functions/src/services/payment/tangle-service/award/award.approve.participant.service.ts index 61e864cb14..939e18dbce 100644 --- a/packages/functions/src/services/payment/tangle-service/award/award.approve.participant.service.ts +++ b/packages/functions/src/services/payment/tangle-service/award/award.approve.participant.service.ts @@ -1,10 +1,8 @@ -import { ITransaction, build5Db } from '@build-5/database'; +import { ITransaction, PgMemberUpdate, build5Db } from '@build-5/database'; import { ApiError, - Award, AwardApproveParticipantTangleResponse, AwardBadgeType, - AwardParticipant, COL, IgnoreWalletReason, Member, @@ -48,8 +46,8 @@ export class AwardApproveParticipantService extends BaseTangleService async (transaction: ITransaction) => { - const awardDocRef = build5Db().doc(`${COL.AWARD}/${awardId}`); - const award = await transaction.get(awardDocRef); + const awardDocRef = build5Db().doc(COL.AWARD, awardId); + const award = await transaction.get(awardDocRef); + if (!award) { throw invalidArgument(WenError.award_does_not_exists); } @@ -81,30 +80,23 @@ export const approveAwardParticipant = const memberId = member?.uid || uidOrAddress; const memberAddress = getTargetAddres(member, award.network, uidOrAddress); - const participantDocRef = awardDocRef.collection(SUB_COL.PARTICIPANTS).doc(memberId); - const participant = await transaction.get(participantDocRef); + const participantDocRef = build5Db().doc(COL.AWARD, awardId, SUB_COL.PARTICIPANTS, memberId); + const participant = await transaction.get(participantDocRef); const count = (award.issued || 0) + 1; - const data = { - uid: award.uid, - issued: count, - completed: count === award.badge.total, - }; - transaction.update(awardDocRef, data); + const data = { issued: count, completed: count === award.badge.total }; + await transaction.update(awardDocRef, data); const participantUpdateData = { - uid: memberId, parentId: award.uid, - parentCol: COL.AWARD, completed: true, count: build5Db().inc(1), - createdOn: participant?.createdOn || serverTime(), tokenReward: build5Db().inc(award.badge.tokenReward), }; if (!participant) { set(participantUpdateData, 'project', project); } - transaction.set(participantDocRef, participantUpdateData, true); + await transaction.upsert(participantDocRef, participantUpdateData); const badgeTransaction: Transaction = { project, @@ -128,37 +120,32 @@ export const approveAwardParticipant = void: false, }, }; - const badgeTransactionDocRef = build5Db().doc(`${COL.TRANSACTION}/${badgeTransaction.uid}`); - transaction.create(badgeTransactionDocRef, badgeTransaction); - - const memberUpdateData = { - uid: memberId, + const badgeTransactionDocRef = build5Db().doc(COL.TRANSACTION, badgeTransaction.uid); + await transaction.create(badgeTransactionDocRef, badgeTransaction); + const memberUpdateData: PgMemberUpdate = { awardsCompleted: build5Db().inc(1), - totalReward: build5Db().inc(award.badge.tokenReward), spaces: { [award.space]: { uid: award.space, - createdOn: (member?.spaces || {})[award.space]?.createdOn || serverTime(), - updatedOn: serverTime(), + createdOn: (member?.spaces || {})[award.space]?.createdOn || dayjs().toDate(), + updatedOn: dayjs().toDate(), awardStat: { [award.badge.tokenUid]: { tokenSymbol: award.badge.tokenSymbol, badges: build5Db().arrayUnion(badgeTransaction.uid), completed: build5Db().inc(1), - totalReward: build5Db().inc(award.badge.tokenReward), }, }, awardsCompleted: build5Db().inc(1), - totalReward: build5Db().inc(award.badge.tokenReward), }, }, }; - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${memberId}`); - transaction.set(memberDocRef, memberUpdateData, true); + const memberDocRef = build5Db().doc(COL.MEMBER, memberId); + await transaction.update(memberDocRef, memberUpdateData); if (award.badge.tokenReward) { const airdrop: TokenDrop = { @@ -174,33 +161,36 @@ export const approveAwardParticipant = sourceAddress: award.address, isBaseToken: award.badge.type === AwardBadgeType.BASE, }; - const airdropDocRef = build5Db().doc(`${COL.AIRDROP}/${airdrop.uid}`); - transaction.create(airdropDocRef, airdrop); + const airdropDocRef = build5Db().doc(COL.AIRDROP, airdrop.uid); + await transaction.create(airdropDocRef, airdrop); const distribution = { parentId: airdrop.token, - parentCol: COL.TOKEN, uid: memberId, totalUnclaimedAirdrop: build5Db().inc(airdrop.count), }; - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${airdrop.token}`); - const distributionDocRef = tokenDocRef.collection(SUB_COL.DISTRIBUTION).doc(memberId); - transaction.set(distributionDocRef, distribution, true); + const distributionDocRef = build5Db().doc( + COL.TOKEN, + airdrop.token, + SUB_COL.DISTRIBUTION, + memberId, + ); + await transaction.upsert(distributionDocRef, distribution); } - return badgeTransaction; }; const getMember = async (network: Network, uidOrAddress: NetworkAddress) => { - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${uidOrAddress}`); - const member = await memberDocRef.get(); + const memberDocRef = build5Db().doc(COL.MEMBER, uidOrAddress); + const member = await memberDocRef.get(); if (member) { return member; } const members = await build5Db() .collection(COL.MEMBER) - .where(`validatedAddress.${network}`, '==', uidOrAddress) - .get(); + .where(`${network}Address`, '==', uidOrAddress) + .limit(1) + .get(); return head(members); }; diff --git a/packages/functions/src/services/payment/tangle-service/award/award.create.service.ts b/packages/functions/src/services/payment/tangle-service/award/award.create.service.ts index 7cf7113293..5ef9bdfd9d 100644 --- a/packages/functions/src/services/payment/tangle-service/award/award.create.service.ts +++ b/packages/functions/src/services/payment/tangle-service/award/award.create.service.ts @@ -26,8 +26,9 @@ import { getTokenBySymbol } from '../../../../utils/token.utils'; import { getRandomEthAddress } from '../../../../utils/wallet.utils'; import { isStorageUrl } from '../../../joi/common'; import { WalletService } from '../../../wallet/wallet.service'; -import { getAwardgStorageDeposits as getAwardStorageDeposits } from '../../award/award-service'; +import { getAwardgStorageDeposits } from '../../award/award-service'; import { BaseTangleService, HandlerParams } from '../../base'; +import { Action } from '../../transaction-service'; import { awardCreateSchema } from './AwardCreateTangleRequestSchema'; import { createAwardFundOrder } from './award.fund.service'; @@ -40,22 +41,22 @@ export class AwardCreateService extends BaseTangleService { @@ -28,8 +29,8 @@ export class AwardFundService extends BaseTangleService { const award = await getAwardForFunding(owner, params.uid); const order = await createAwardFundOrder(project, owner, award); - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${order.uid}`); - this.transactionService.push({ ref: orderDocRef, data: order, action: 'set' }); + const orderDocRef = build5Db().doc(COL.TRANSACTION, order.uid); + this.transactionService.push({ ref: orderDocRef, data: order, action: Action.C }); const response = { amount: order.payload.amount!, @@ -82,8 +83,8 @@ export const createAwardFundOrder = async ( }; export const getAwardForFunding = async (owner: string, awardId: string) => { - const awardDocRef = build5Db().doc(`${COL.AWARD}/${awardId}`); - const award = await awardDocRef.get(); + const awardDocRef = build5Db().doc(COL.AWARD, awardId); + const award = await awardDocRef.get(); if (!award) { throw invalidArgument(WenError.award_does_not_exists); diff --git a/packages/functions/src/services/payment/tangle-service/build5/verify.eth.for.b5.service.ts b/packages/functions/src/services/payment/tangle-service/build5/verify.eth.for.b5.service.ts index 1f5bc2c13d..e2e6f45de6 100644 --- a/packages/functions/src/services/payment/tangle-service/build5/verify.eth.for.b5.service.ts +++ b/packages/functions/src/services/payment/tangle-service/build5/verify.eth.for.b5.service.ts @@ -1,8 +1,9 @@ import { build5Db } from '@build-5/database'; -import { COL, SoonSnap, TangleResponse } from '@build-5/interfaces'; +import { COL, TangleResponse } from '@build-5/interfaces'; import axios from 'axios'; import { assertValidationAsync } from '../../../../utils/schema.utils'; import { BaseTangleService, HandlerParams } from '../../base'; +import { Action } from '../../transaction-service'; import { verifyEthForB5TangleSchema } from './VerifyEthForB5TangleRequest'; export class VerifyEthForBuil5TangleService extends BaseTangleService { @@ -10,11 +11,11 @@ export class VerifyEthForBuil5TangleService extends BaseTangleService(soonSnapDocRef); + let soonSnapDocRef = build5Db().doc(COL.SOON_SNAP, match.from); + let soonSnap = await this.transaction.get(soonSnapDocRef); if (!soonSnap) { - soonSnapDocRef = build5Db().doc(`${COL.SOON_SNAP}/${ethAddress}`); - soonSnap = await this.transaction.get(soonSnapDocRef); + soonSnapDocRef = build5Db().doc(COL.SOON_SNAP, ethAddress); + soonSnap = await this.transaction.get(soonSnapDocRef); } ethAddress = soonSnap?.ethAddress || ethAddress; @@ -30,11 +31,8 @@ export class VerifyEthForBuil5TangleService extends BaseTangleService { @@ -84,15 +84,20 @@ export class MintMetadataNftService extends BaseTangleService { } if (aliasId === EMPTY_ALIAS_ID) { - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${space.uid}`); - this.transactionService.push({ ref: spaceDocRef, data: space, action: 'set' }); + const spaceDocRef = build5Db().doc(COL.SPACE, space.uid); + this.transactionService.push({ ref: spaceDocRef, data: space, action: Action.C }); - const guardian = { uid: owner, parentId: space.uid, parentCol: COL.SPACE }; - const guardianDocRef = spaceDocRef.collection(SUB_COL.GUARDIANS).doc(owner); - this.transactionService.push({ ref: guardianDocRef, data: guardian, action: 'set' }); + const guardian = { + uid: owner, + parentId: space.uid, + parentCol: COL.SPACE, + createdOn: dateToTimestamp(dayjs()), + }; + const guardianDocRef = build5Db().doc(COL.SPACE, space.uid, SUB_COL.GUARDIANS, owner); + this.transactionService.push({ ref: guardianDocRef, data: guardian, action: Action.C }); - const memberDocRef = spaceDocRef.collection(SUB_COL.MEMBERS).doc(owner); - this.transactionService.push({ ref: memberDocRef, data: guardian, action: 'set' }); + const memberDocRef = build5Db().doc(COL.SPACE, space.uid, SUB_COL.MEMBERS, owner); + this.transactionService.push({ ref: memberDocRef, data: guardian, action: Action.C }); } const order: Transaction = { @@ -120,8 +125,8 @@ export class MintMetadataNftService extends BaseTangleService { tag: match.msgId, }, }; - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${order.uid}`); - this.transactionService.push({ ref: orderDocRef, data: order, action: 'set' }); + const orderDocRef = build5Db().doc(COL.TRANSACTION, order.uid); + this.transactionService.push({ ref: orderDocRef, data: order, action: Action.C }); this.transactionService.createUnlockTransaction( payment, @@ -175,9 +180,8 @@ const getAliasOutputAmount = async (owner: string, space: Space, wallet: Wallet) if (!space.alias?.address) { throw invalidArgument(WenError.not_alias_governor); } - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${space.uid}`); - const guardianDocRef = spaceDocRef.collection(SUB_COL.GUARDIANS).doc(owner); - const guardian = await guardianDocRef.get(); + const guardianDocRef = build5Db().doc(COL.SPACE, space.uid, SUB_COL.GUARDIANS, owner); + const guardian = await guardianDocRef.get(); if (!guardian) { throw invalidArgument(WenError.not_alias_governor); diff --git a/packages/functions/src/services/payment/tangle-service/nft/nft-deposit.service.ts b/packages/functions/src/services/payment/tangle-service/nft/nft-deposit.service.ts index 8ada43986a..84b18e121f 100644 --- a/packages/functions/src/services/payment/tangle-service/nft/nft-deposit.service.ts +++ b/packages/functions/src/services/payment/tangle-service/nft/nft-deposit.service.ts @@ -14,6 +14,7 @@ import { dateToTimestamp } from '../../../../utils/dateTime.utils'; import { getRandomEthAddress } from '../../../../utils/wallet.utils'; import { WalletService } from '../../../wallet/wallet.service'; import { BaseTangleService, HandlerParams } from '../../base'; +import { Action } from '../../transaction-service'; export class NftDepositService extends BaseTangleService { public handleRequest = async ({ owner, tran, tranEntry, ...params }: HandlerParams) => { @@ -36,8 +37,8 @@ export class NftDepositService extends BaseTangleService { void: false, }, }; - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${order.uid}`); - this.transactionService.push({ ref: orderDocRef, data: order, action: 'set' }); + const orderDocRef = build5Db().doc(COL.TRANSACTION, order.uid); + this.transactionService.push({ ref: orderDocRef, data: order, action: Action.C }); this.transactionService.createUnlockTransaction( params.payment, diff --git a/packages/functions/src/services/payment/tangle-service/nft/nft-purchase.bulk.service.ts b/packages/functions/src/services/payment/tangle-service/nft/nft-purchase.bulk.service.ts index eba0d2ecb2..479da8f5cd 100644 --- a/packages/functions/src/services/payment/tangle-service/nft/nft-purchase.bulk.service.ts +++ b/packages/functions/src/services/payment/tangle-service/nft/nft-purchase.bulk.service.ts @@ -5,7 +5,6 @@ import { CollectionType, Member, Network, - Nft, TRANSACTION_AUTO_EXPIRY_MS, TangleResponse, Transaction, @@ -27,6 +26,7 @@ import { getSpace } from '../../../../utils/space.utils'; import { getRandomEthAddress } from '../../../../utils/wallet.utils'; import { WalletService } from '../../../wallet/wallet.service'; import { BaseTangleService, HandlerParams } from '../../base'; +import { Action } from '../../transaction-service'; import { nftPurchaseBulkSchema } from './NftPurchaseBulkTangleRequestSchema'; import { assertCurrentOwnerAddress, @@ -60,9 +60,9 @@ export class TangleNftPurchaseBulkService extends BaseTangleService, + CollectionNftGroup: Dictionary, member: Member, ip: string, ) => { const defaultNetwork = isProdEnv() ? Network.IOTA : Network.ATOI; - const pricesPromises = Object.entries(colletionNftGroup).map( + const pricesPromises = Object.entries(CollectionNftGroup).map( async ([collectionId, nftOrders]) => { const nftIds = nftOrders.map((o) => o.nft!); const { collection, nfts } = await getNfts(collectionId, nftIds); @@ -176,7 +176,7 @@ const getNftPrices = async ( nft: nft.uid, requestedNft: nftIdParam, price: 0, - error: get(error, 'details.code', 0), + error: get(error, 'eCode', 0), }; } }); @@ -196,8 +196,8 @@ const getNfts = async (collectionId: string, nftIds: (string | undefined)[]) => }; const getNft = async (nftId: string) => { - const docRef = build5Db().doc(`${COL.NFT}/${nftId}`); - const nft = (await getNftByMintingId(nftId)) || (await docRef.get()); + const docRef = build5Db().doc(COL.NFT, nftId); + const nft = (await getNftByMintingId(nftId)) || (await docRef.get()); if (nft) { return nft; } diff --git a/packages/functions/src/services/payment/tangle-service/nft/nft-purchase.service.ts b/packages/functions/src/services/payment/tangle-service/nft/nft-purchase.service.ts index a947a795f9..33977c6d65 100644 --- a/packages/functions/src/services/payment/tangle-service/nft/nft-purchase.service.ts +++ b/packages/functions/src/services/payment/tangle-service/nft/nft-purchase.service.ts @@ -1,4 +1,4 @@ -import { build5Db } from '@build-5/database'; +import { PgNftUpdate, build5Db } from '@build-5/database'; import { COL, Collection, @@ -38,6 +38,7 @@ import { getRandomEthAddress } from '../../../../utils/wallet.utils'; import { assertHasAccess } from '../../../validators/access'; import { WalletService } from '../../../wallet/wallet.service'; import { BaseTangleService, HandlerParams } from '../../base'; +import { Action } from '../../transaction-service'; import { nftPurchaseSchema } from './NftPurchaseTangleRequestSchema'; export class TangleNftPurchaseService extends BaseTangleService { @@ -63,9 +64,9 @@ export class TangleNftPurchaseService extends BaseTangleService order.payload.disableWithdraw = params.disableWithdraw || false; this.transactionService.push({ - ref: build5Db().doc(`${COL.TRANSACTION}/${order.uid}`), + ref: build5Db().doc(COL.TRANSACTION, order.uid), data: order, - action: 'set', + action: Action.C, }); if (tranEntry.amount !== order.payload.amount || tangleOrder.network !== order.network) { @@ -158,8 +159,8 @@ export const createNftPuchaseOrder = async ( }; export const getCollection = async (id: string) => { - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${id}`); - const collection = await collectionDocRef.get(); + const collectionDocRef = build5Db().doc(COL.COLLECTION, id); + const collection = await collectionDocRef.get(); if (!collection) { throw invalidArgument(WenError.collection_does_not_exists); } @@ -171,14 +172,14 @@ export const getCollection = async (id: string) => { }; export const getMember = async (id: string) => { - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${id}`); + const memberDocRef = build5Db().doc(COL.MEMBER, id); return await memberDocRef.get(); }; const getNft = async (collection: Collection, nftId: string | undefined) => { if (nftId) { - const docRef = build5Db().doc(`${COL.NFT}/${nftId}`); - const nft = (await getNftByMintingId(nftId)) || (await docRef.get()); + const docRef = build5Db().doc(COL.NFT, nftId); + const nft = (await getNftByMintingId(nftId)) || (await docRef.get()); if (nft) { return nft; } @@ -214,7 +215,7 @@ export const getNftAbove = (collection: Collection, position: number, limit = 1) .where('position', '>=', position) .orderBy('position', 'asc') .limit(limit) - .get(); + .get(); export const getNftBelow = (collection: Collection, position: number, limit = 1) => build5Db() @@ -224,9 +225,9 @@ export const getNftBelow = (collection: Collection, position: number, limit = 1) .where('placeholderNft', '==', false) .where('collection', '==', collection.uid) .where('position', '<=', position) - .orderBy('position', 'asc') - .limitToLast(limit) - .get(); + .orderBy('position', 'desc') + .limit(limit) + .get(); export const assertNftCanBePurchased = async ( space: Space, @@ -295,8 +296,8 @@ export const assertUserHasOnlyOneNft = async (collection: Collection, owner: str .collection(COL.TRANSACTION) .where('member', '==', owner) .where('type', '==', TransactionType.BILL_PAYMENT) - .where('payload.collection', '==', collection.uid) - .where('payload.previousOwnerEntity', '==', 'space') + .where('payload_collection', '==', collection.uid) + .where('payload_previousOwnerEntity', '==', Entity.SPACE) .get(); if (snap.length) { throw invalidArgument(WenError.you_can_only_own_one_nft_from_collection); @@ -306,11 +307,11 @@ export const assertUserHasOnlyOneNft = async (collection: Collection, owner: str export const assertNoOrderInProgress = async (owner: string) => { const orderInProgress = await build5Db() .collection(COL.TRANSACTION) - .where('payload.reconciled', '==', false) - .where('payload.type', '==', TransactionPayloadType.NFT_PURCHASE) + .where('payload_reconciled', '==', false) + .where('payload_type', '==', TransactionPayloadType.NFT_PURCHASE) .where('member', '==', owner) .where('type', '==', TransactionType.ORDER) - .where('payload.void', '==', false) + .where('payload_void', '==', false) .get(); if (orderInProgress.length) { @@ -342,14 +343,14 @@ export const getDiscount = (collection: Collection, member: Member) => { return 1; }; -export const lockNft = async (nftId: string, orderId: string) => +export const lockNft = (nftId: string, orderId: string) => build5Db().runTransaction(async (transaction) => { - const docRef = build5Db().doc(`${COL.NFT}/${nftId}`); + const docRef = build5Db().doc(COL.NFT, nftId); const nft = await transaction.get(docRef); if (nft.locked) { throw invalidArgument(WenError.nft_locked_for_sale); } - transaction.update(docRef, { locked: true, lockedBy: orderId }); + await transaction.update(docRef, { locked: true, lockedBy: orderId }); }); export const getNftFinalPrice = (nft: Nft, discount: number) => { @@ -388,12 +389,27 @@ export const createNftWithdrawOrder = ( nftId: nft.mintingData?.nftId || '', }, }; - const nftUpdateData = { - uid: nft.uid, + const nftUpdateData: PgNftUpdate = { status: stakeType ? NftStatus.STAKED : NftStatus.WITHDRAWN, hidden: true, - depositData: build5Db().deleteField(), - owner: null, + depositData_address: undefined, + depositData_network: undefined, + depositData_mintedOn: undefined, + depositData_mintedBy: undefined, + depositData_blockId: undefined, + depositData_nftId: undefined, + depositData_storageDeposit: undefined, + depositData_aliasBlockId: undefined, + depositData_aliasId: undefined, + depositData_aliasStorageDeposit: undefined, + depositData_mintingOrderId: undefined, + depositData_nftsToMint: undefined, + depositData_nftMediaToUpload: undefined, + depositData_nftMediaToPrepare: undefined, + depositData_unsoldMintingOptions: undefined, + depositData_newPrice: undefined, + depositData_nftsStorageDeposit: undefined, + owner: undefined, isOwned: false, }; return { order, nftUpdateData }; 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 b5f288a555..2a839846a0 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 @@ -3,7 +3,6 @@ import { Auction, AuctionType, COL, - Collection, CollectionStatus, DEFAULT_NETWORK, EXTEND_AUCTION_WITHIN, @@ -22,21 +21,22 @@ import { invalidArgument } from '../../../../utils/error.utils'; import { assertValidationAsync } from '../../../../utils/schema.utils'; import { getRandomEthAddress } from '../../../../utils/wallet.utils'; import { BaseTangleService, HandlerParams } from '../../base'; +import { Action } from '../../transaction-service'; import { setNftForSaleTangleSchema } from './NftSetForSaleTangleRequestSchema'; export class TangleNftSetForSaleService extends BaseTangleService { 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 memberDocRef = build5Db().doc(COL.MEMBER, owner); + const member = await memberDocRef.get(); const { nft, auction } = await getNftSetForSaleParams(member!, project, params); - const nftDocRef = build5Db().doc(`${COL.NFT}/${params.nft}`); - this.transactionService.push({ ref: nftDocRef, data: nft, action: 'update' }); + const nftDocRef = build5Db().doc(COL.NFT, params.nft); + this.transactionService.push({ ref: nftDocRef, data: nft, action: Action.U }); if (auction) { - const auctionDocRef = build5Db().doc(`${COL.AUCTION}/${auction.uid}`); - this.transactionService.push({ ref: auctionDocRef, data: auction, action: 'set' }); + const auctionDocRef = build5Db().doc(COL.AUCTION, auction.uid); + this.transactionService.push({ ref: auctionDocRef, data: auction, action: Action.C }); } return { status: 'success' }; @@ -48,8 +48,8 @@ export const getNftSetForSaleParams = async ( project: string, params: NftSetForSaleRequest, ) => { - const nftDocRef = build5Db().doc(`${COL.NFT}/${params.nft}`); - const nft = await nftDocRef.get(); + const nftDocRef = build5Db().doc(COL.NFT, params.nft); + const nft = await nftDocRef.get(); if (!nft) { throw invalidArgument(WenError.nft_does_not_exists); } @@ -84,8 +84,8 @@ export const getNftSetForSaleParams = async ( params.auctionFrom = dateToTimestamp(params.auctionFrom, true).toDate(); } - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${nft.collection}`); - const collection = await collectionDocRef.get(); + const collectionDocRef = build5Db().doc(COL.COLLECTION, nft.collection); + const collection = await collectionDocRef.get(); if (![CollectionStatus.PRE_MINTED, CollectionStatus.MINTED].includes(collection?.status!)) { throw invalidArgument(WenError.invalid_collection_status); } @@ -96,7 +96,7 @@ export const getNftSetForSaleParams = async ( const getNftUpdateData = (params: NftSetForSaleRequest) => { const update: Record = { - saleAccess: params.access || NftAccess.OPEN, + saleAccess: (params.access || NftAccess.OPEN) as NftAccess, saleAccessMembers: params.accessMembers || [], }; @@ -137,7 +137,12 @@ const getNftUpdateData = (params: NftSetForSaleRequest) => { return update; }; -const getAuctionData = (project: string, owner: string, params: NftSetForSaleRequest, nft: Nft) => { +const getAuctionData = ( + project: string, + owner: string, + params: NftSetForSaleRequest, + nft: Nft, +): Auction | undefined => { if (!params.auctionFrom) { return; } @@ -165,7 +170,9 @@ const getAuctionData = (project: string, owner: string, params: NftSetForSaleReq if (params.extendedAuctionLength) { return { ...auction, - extendedAuctionTo: dayjs(params.auctionFrom).add(params.extendedAuctionLength).toDate(), + extendedAuctionTo: dateToTimestamp( + dayjs(params.auctionFrom).add(params.extendedAuctionLength), + ), extendedAuctionLength: params.extendedAuctionLength || 0, extendAuctionWithin: params.extendAuctionWithin || EXTEND_AUCTION_WITHIN, }; diff --git a/packages/functions/src/services/payment/tangle-service/nft/nft-transfer.service.ts b/packages/functions/src/services/payment/tangle-service/nft/nft-transfer.service.ts index 1550547138..22c4fa0066 100644 --- a/packages/functions/src/services/payment/tangle-service/nft/nft-transfer.service.ts +++ b/packages/functions/src/services/payment/tangle-service/nft/nft-transfer.service.ts @@ -3,6 +3,7 @@ import { COL, TangleResponse, TransactionType } from '@build-5/interfaces'; import { assertValidationAsync } from '../../../../utils/schema.utils'; import { BaseTangleService, HandlerParams } from '../../base'; import { createNftTransferData } from '../../nft/nft-transfer.service'; +import { Action } from '../../transaction-service'; import { nftTangleTransferSchema } from './NftTransferTangleRequestSchema'; export class TangleNftTransferService extends BaseTangleService { @@ -20,19 +21,21 @@ export class TangleNftTransferService extends BaseTangleService if (code !== 200) { continue; } - - const nftDocRef = build5Db().doc(`${COL.NFT}/${nftId}`); - this.transactionService.push({ ref: nftDocRef, data: nftUpdateData, action: 'update' }); - - const tranDocRef = build5Db().doc(`${COL.TRANSACTION}/${order?.uid}`); - this.transactionService.push({ ref: tranDocRef, data: order, action: 'set' }); + if (nftUpdateData) { + const nftDocRef = build5Db().doc(COL.NFT, nftId); + this.transactionService.push({ ref: nftDocRef, data: nftUpdateData, action: Action.U }); + } + if (order) { + const tranDocRef = build5Db().doc(COL.TRANSACTION, order?.uid!); + this.transactionService.push({ ref: tranDocRef, data: order, action: Action.C }); + } if (order?.type === TransactionType.WITHDRAW_NFT) { - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${order.payload.collection}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, order.payload.collection!); this.transactionService.push({ ref: collectionDocRef, data: { total: build5Db().inc(-1) }, - action: 'update', + action: Action.U, }); } } diff --git a/packages/functions/src/services/payment/tangle-service/proposal/ProposalApporvalService.ts b/packages/functions/src/services/payment/tangle-service/proposal/ProposalApporvalService.ts index af37eeed6c..7d47610891 100644 --- a/packages/functions/src/services/payment/tangle-service/proposal/ProposalApporvalService.ts +++ b/packages/functions/src/services/payment/tangle-service/proposal/ProposalApporvalService.ts @@ -1,9 +1,10 @@ import { build5Db } from '@build-5/database'; -import { COL, Proposal, TangleRequestType, TangleResponse, WenError } from '@build-5/interfaces'; +import { COL, TangleRequestType, TangleResponse, WenError } from '@build-5/interfaces'; import { invalidArgument } from '../../../../utils/error.utils'; import { assertValidationAsync } from '../../../../utils/schema.utils'; import { assertIsGuardian } from '../../../../utils/token.utils'; import { BaseTangleService, HandlerParams } from '../../base'; +import { Action } from '../../transaction-service'; import { proposalApproveSchema } from './ProposalApproveTangleRequestSchema'; export class ProposalApprovalService extends BaseTangleService { @@ -14,8 +15,8 @@ export class ProposalApprovalService extends BaseTangleService { params.uid, params.requestType === TangleRequestType.PROPOSAL_APPROVE, ); - const docRef = build5Db().doc(`${COL.PROPOSAL}/${params.uid}`); - this.transactionService.push({ ref: docRef, data, action: 'update' }); + const docRef = build5Db().doc(COL.PROPOSAL, params.uid); + this.transactionService.push({ ref: docRef, data, action: Action.U }); return { status: 'success' }; }; @@ -26,8 +27,8 @@ export const getProposalApprovalData = async ( proposalId: string, approve: boolean, ) => { - const proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${proposalId}`); - const proposal = await proposalDocRef.get(); + const proposalDocRef = build5Db().doc(COL.PROPOSAL, proposalId); + const proposal = await proposalDocRef.get(); if (!proposal) { throw invalidArgument(WenError.proposal_does_not_exists); } diff --git a/packages/functions/src/services/payment/tangle-service/proposal/ProposalCreateService.ts b/packages/functions/src/services/payment/tangle-service/proposal/ProposalCreateService.ts index f449fd5d4b..b9130ea604 100644 --- a/packages/functions/src/services/payment/tangle-service/proposal/ProposalCreateService.ts +++ b/packages/functions/src/services/payment/tangle-service/proposal/ProposalCreateService.ts @@ -16,6 +16,7 @@ import { assertValidationAsync } from '../../../../utils/schema.utils'; import { getTokenForSpace } from '../../../../utils/token.utils'; import { getRandomEthAddress } from '../../../../utils/wallet.utils'; import { BaseTangleService, HandlerParams } from '../../base'; +import { Action } from '../../transaction-service'; import { proposalCreateSchemaObject } from './ProposalCreateTangleRequestSchema'; export class ProposalCreateService extends BaseTangleService { @@ -28,14 +29,19 @@ export class ProposalCreateService extends BaseTangleService, ) => { - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${params.space}`); - const spaceMemberDocRef = spaceDocRef.collection(SUB_COL.MEMBERS).doc(owner); - const spaceMember = await spaceMemberDocRef.get(); + const spaceMemberDocRef = build5Db().doc( + COL.SPACE, + params.space! as string, + SUB_COL.MEMBERS, + owner, + ); + const spaceMember = await spaceMemberDocRef.get(); if (!spaceMember) { throw invalidArgument(WenError.you_are_not_part_of_space); } @@ -98,16 +108,13 @@ export const createProposal = async ( const createProposalMembersAndGetTotalWeight = async (project: string, proposal: Proposal) => { const subCol = proposal.settings.onlyGuardians ? SUB_COL.GUARDIANS : SUB_COL.MEMBERS; - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${proposal.space}`); - const spaceMembers = await spaceDocRef.collection(subCol).get(); + const spaceMembers = await build5Db().collection(COL.SPACE, proposal.space, subCol).get(); const promises = spaceMembers.map(async (spaceMember) => { const proposalMember = createProposalMember(project, proposal, spaceMember); if (proposalMember.weight || proposal.type === ProposalType.NATIVE) { - const proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${proposal.uid}`); - await proposalDocRef - .collection(SUB_COL.MEMBERS) - .doc(proposalMember.uid) + await build5Db() + .doc(COL.PROPOSAL, proposal.uid, SUB_COL.MEMBERS, proposalMember.uid) .create(proposalMember); } return proposalMember.weight || 0; diff --git a/packages/functions/src/services/payment/tangle-service/proposal/voting/ProposalVoteService.ts b/packages/functions/src/services/payment/tangle-service/proposal/voting/ProposalVoteService.ts index 295c6cba96..14b9d36e00 100644 --- a/packages/functions/src/services/payment/tangle-service/proposal/voting/ProposalVoteService.ts +++ b/packages/functions/src/services/payment/tangle-service/proposal/voting/ProposalVoteService.ts @@ -24,6 +24,7 @@ import { assertValidationAsync } from '../../../../../utils/schema.utils'; import { getTokenForSpace } from '../../../../../utils/token.utils'; import { getRandomEthAddress } from '../../../../../utils/wallet.utils'; import { BaseTangleService, HandlerParams } from '../../../base'; +import { Action } from '../../../transaction-service'; import { voteOnProposalSchemaObject } from './ProposalVoteTangleRequestSchema'; import { executeSimpleVoting } from './simple.voting'; import { voteWithStakedTokens } from './staked.token.voting'; @@ -73,7 +74,7 @@ export class ProposalVoteService extends BaseTangleService { const order = await createVoteTransactionOrder(project, owner, proposal, values, token); - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${order.uid}`); + const orderDocRef = build5Db().doc(COL.TRANSACTION, order.uid); this.transactionService.push({ ref: orderDocRef, data: order, - action: 'set', + action: Action.C, }); this.transactionService.createUnlockTransaction( @@ -107,38 +108,41 @@ export class ProposalVoteService extends BaseTangleService { - const proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${proposal.uid}`); - const proposalMemberDocRef = proposalDocRef.collection(SUB_COL.MEMBERS).doc(proposalMember.uid); + const proposalDocRef = build5Db().doc(COL.PROPOSAL, proposal.uid); + const proposalMemberDocRef = build5Db().doc( + COL.PROPOSAL, + proposal.uid, + SUB_COL.MEMBERS, + proposalMember.uid, + ); - const voteData = await executeSimpleVoting(project, proposalMember, proposal, values); + const voteData = executeSimpleVoting(project, proposalMember, proposal, values); - this.transactionService.push({ - ref: proposalDocRef, - data: voteData.proposal, - action: 'set', - merge: true, - }); + if (voteData.proposal) { + this.transactionService.push({ + ref: proposalDocRef, + data: voteData.proposal, + action: Action.U, + }); + } this.transactionService.push({ ref: proposalMemberDocRef, data: voteData.proposalMember, - action: 'set', - merge: true, + action: Action.U, }); - const voteTransactionDocRef = build5Db().doc( - `${COL.TRANSACTION}/${voteData.voteTransaction.uid}`, - ); + const voteTransactionDocRef = build5Db().doc(COL.TRANSACTION, voteData.voteTransaction.uid); this.transactionService.push({ ref: voteTransactionDocRef, data: voteData.voteTransaction, - action: 'set', + action: Action.C, }); return { status: 'success' }; @@ -146,8 +150,8 @@ export class ProposalVoteService extends BaseTangleService { - const proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${proposalUid}`); - const proposal = await proposalDocRef.get(); + const proposalDocRef = build5Db().doc(COL.PROPOSAL, proposalUid); + const proposal = await proposalDocRef.get(); if (!proposal) { throw invalidArgument(WenError.proposal_does_not_exists); } @@ -177,9 +181,8 @@ export const getProposal = async (proposalUid: string) => { }; export const getProposalMember = async (owner: string, proposal: Proposal, value: number) => { - const proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${proposal.uid}`); - const proposalMemberDocRef = proposalDocRef.collection(SUB_COL.MEMBERS).doc(owner); - const proposalMember = await proposalMemberDocRef.get(); + const proposalMemberDocRef = build5Db().doc(COL.PROPOSAL, proposal.uid, SUB_COL.MEMBERS, owner); + const proposalMember = await proposalMemberDocRef.get(); if (!proposalMember) { throw invalidArgument(WenError.you_are_not_allowed_to_vote_on_this_proposal); } diff --git a/packages/functions/src/services/payment/tangle-service/proposal/voting/simple.voting.ts b/packages/functions/src/services/payment/tangle-service/proposal/voting/simple.voting.ts index beca61924b..63a16e6389 100644 --- a/packages/functions/src/services/payment/tangle-service/proposal/voting/simple.voting.ts +++ b/packages/functions/src/services/payment/tangle-service/proposal/voting/simple.voting.ts @@ -3,7 +3,7 @@ import { Proposal, ProposalMember } from '@build-5/interfaces'; import { head } from 'lodash'; import { createVoteTransaction } from './ProposalVoteService'; -export const executeSimpleVoting = async ( +export const executeSimpleVoting = ( project: string, member: ProposalMember, proposal: Proposal, @@ -16,7 +16,7 @@ export const executeSimpleVoting = async ( uid: member.uid, voted: true, tranId: voteTransaction.uid, - values: [{ [values[0]]: weight }], + values: JSON.stringify({ [voteTransaction.uid]: { value: values[0], weight } }), }; return { proposal: proposalUpdateData, @@ -32,10 +32,9 @@ const getProposalUpdateDataAfterVote = ( ) => { const prevAnswer = head(Object.keys(head(proposalMember.values) || {})); if (prevAnswer === values[0].toString()) { - return { uid: proposalMember.parentId }; + return undefined; } const data = { - uid: proposalMember.parentId, results: { voted: build5Db().inc(proposalMember.voted ? 0 : weight), answers: { [`${values[0]}`]: build5Db().inc(weight) }, diff --git a/packages/functions/src/services/payment/tangle-service/proposal/voting/staked.token.voting.ts b/packages/functions/src/services/payment/tangle-service/proposal/voting/staked.token.voting.ts index 430892c593..4507e2159b 100644 --- a/packages/functions/src/services/payment/tangle-service/proposal/voting/staked.token.voting.ts +++ b/packages/functions/src/services/payment/tangle-service/proposal/voting/staked.token.voting.ts @@ -1,13 +1,5 @@ import { build5Db, ITransaction } from '@build-5/database'; -import { - COL, - Proposal, - Stake, - SUB_COL, - TokenDistribution, - Transaction, - WenError, -} from '@build-5/interfaces'; +import { COL, Proposal, Stake, SUB_COL, WenError } from '@build-5/interfaces'; import dayjs from 'dayjs'; import { invalidArgument } from '../../../../../utils/error.utils'; import { getTokenVoteMultiplier } from '../../../voting-service'; @@ -20,12 +12,13 @@ export const voteWithStakedTokens = async ( proposal: Proposal, values: number[], ) => { - const distributionDocRef = build5Db() - .collection(COL.TOKEN) - .doc(proposal.token!) - .collection(SUB_COL.DISTRIBUTION) - .doc(member); - const distribution = (await transaction.get(distributionDocRef))!; + const distributionDocRef = build5Db().doc( + COL.TOKEN, + proposal.token!, + SUB_COL.DISTRIBUTION, + member, + ); + const distribution = (await transaction.get(distributionDocRef))!; if (distribution.stakeVoteTransactionId) { await expireStakeVoteTransaction(transaction, proposal, distribution.stakeVoteTransactionId); } @@ -50,36 +43,29 @@ export const voteWithStakedTokens = async ( values, stakes.map((s) => s.uid), ); - const voteTransactionDocRef = build5Db().doc(`${COL.TRANSACTION}/${voteTransaction.uid}`); - transaction.create(voteTransactionDocRef, voteTransaction); - - const proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${proposal.uid}`); - const proposalMemberDocRef = proposalDocRef.collection(SUB_COL.MEMBERS).doc(member); - transaction.set( - proposalMemberDocRef, - { - voted: true, - voteTransactions: build5Db().inc(1), - tranId: voteTransaction.uid, - weightPerAnswer: { [values[0]]: build5Db().inc(weight) }, - values: build5Db().arrayUnion({ - [values[0]]: weight, - voteTransaction: voteTransaction.uid, - }), - }, - true, - ); + const voteTransactionDocRef = build5Db().doc(COL.TRANSACTION, voteTransaction.uid); + await transaction.create(voteTransactionDocRef, voteTransaction); + + const proposalDocRef = build5Db().doc(COL.PROPOSAL, proposal.uid); + const proposalMemberDocRef = build5Db().doc(COL.PROPOSAL, proposal.uid, SUB_COL.MEMBERS, member); - const proposalData = { + const value = values[0].toString(); + await transaction.update(proposalDocRef, { results: { total: build5Db().inc(weight), voted: build5Db().inc(weight), - answers: { [`${values[0]}`]: build5Db().inc(weight) }, + answers: { [value]: build5Db().inc(weight) }, }, - }; - transaction.set(proposalDocRef, proposalData, true); + }); + + await transaction.upsert(proposalMemberDocRef, { + voted: true, + tranId: voteTransaction.uid, + weight: build5Db().inc(weight), + values: { [voteTransaction.uid]: { value, weight: build5Db().inc(weight) } }, + }); - transaction.update(distributionDocRef, { stakeVoteTransactionId: voteTransaction.uid }); + await transaction.update(distributionDocRef, { stakeVoteTransactionId: voteTransaction.uid }); return voteTransaction; }; @@ -89,21 +75,18 @@ const expireStakeVoteTransaction = async ( currentProposal: Proposal, voteTransactionId: string, ) => { - const voteTransactionDocRef = build5Db().doc(`${COL.TRANSACTION}/${voteTransactionId}`); - const voteTransaction = (await transaction.get(voteTransactionDocRef))!; + const voteTransactionDocRef = build5Db().doc(COL.TRANSACTION, voteTransactionId); + const voteTransaction = (await transaction.get(voteTransactionDocRef))!; let proposal = currentProposal; - let proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${currentProposal.uid}`); + let proposalDocRef = build5Db().doc(COL.PROPOSAL, currentProposal.uid); if (voteTransaction.payload.proposalId !== currentProposal.uid) { - proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${voteTransaction.payload.proposalId}`); - proposal = (await proposalDocRef.get())!; + proposalDocRef = build5Db().doc(COL.PROPOSAL, voteTransaction.payload.proposalId!); + proposal = (await proposalDocRef.get())!; } if (dayjs().isAfter(dayjs(proposal.settings.endDate.toDate()))) { return; } - const proposalMemberDocRef = proposalDocRef - .collection(SUB_COL.MEMBERS) - .doc(voteTransaction.member!); const stakes = await getStakesById(voteTransaction.payload.stakes!); const weight = getWeightForStakes( @@ -113,33 +96,22 @@ const expireStakeVoteTransaction = async ( dayjs(), ); - transaction.update(voteTransactionDocRef, { - 'payload.weight': weight, - 'payload.outputConsumed': true, - 'payload.outputConsumedOn': dayjs().toDate(), + await transaction.update(voteTransactionDocRef, { + payload_weight: weight, + payload_outputConsumed: true, + payload_outputConsumedOn: dayjs().toDate(), }); const prevWeight = voteTransaction.payload.weight!; - const prevValue = voteTransaction.payload.values![0]; - - transaction.set( - proposalMemberDocRef, - { - values: build5Db().arrayRemove({ - [prevValue]: prevWeight, - voteTransaction: voteTransaction.uid, - }), - voteTransactions: build5Db().inc(-1), - weightPerAnswer: { [prevValue]: build5Db().inc(-prevWeight + weight) }, - }, - true, + const prevValue = voteTransaction.payload.values![0].toString(); + + const proposalMemberDocRef = build5Db().doc( + COL.PROPOSAL, + proposal.uid, + SUB_COL.MEMBERS, + voteTransaction.member!, ); - transaction.update(proposalMemberDocRef, { - values: build5Db().arrayUnion({ - [prevValue]: weight, - voteTransaction: voteTransaction.uid, - }), - }); + await transaction.update(proposalMemberDocRef, { values: { [voteTransaction.uid]: { weight } } }); const data = { results: { @@ -148,13 +120,13 @@ const expireStakeVoteTransaction = async ( answers: { [prevValue]: build5Db().inc(-prevWeight + weight) }, }, }; - transaction.set(proposalDocRef, data, true); + await transaction.update(proposalDocRef, data); }; const getStakesById = (stakeIds: string[]) => { const promises = stakeIds.map(async (uid) => { - const docRef = build5Db().doc(`${COL.STAKE}/${uid}`); - return (await docRef.get())!; + const docRef = build5Db().doc(COL.STAKE, uid); + return (await docRef.get())!; }); return Promise.all(promises); }; @@ -181,6 +153,6 @@ const getActiveStakes = async (member: string, token: string) => { .where('member', '==', member) .where('token', '==', token) .where('expirationProcessed', '==', false) - .get(); + .get(); return stakes.filter((s) => dayjs(s.expiresAt.toDate()).isAfter(dayjs())); }; diff --git a/packages/functions/src/services/payment/tangle-service/space/SpaceAcceptMemberService.ts b/packages/functions/src/services/payment/tangle-service/space/SpaceAcceptMemberService.ts index 1e3aa4613d..8eb5b1468d 100644 --- a/packages/functions/src/services/payment/tangle-service/space/SpaceAcceptMemberService.ts +++ b/packages/functions/src/services/payment/tangle-service/space/SpaceAcceptMemberService.ts @@ -1,10 +1,13 @@ import { build5Db } from '@build-5/database'; -import { COL, Space, SpaceMember, SUB_COL, TangleResponse, WenError } from '@build-5/interfaces'; +import { COL, SUB_COL, TangleResponse, WenError } from '@build-5/interfaces'; +import dayjs from 'dayjs'; import { getProject } from '../../../../utils/common.utils'; +import { dateToTimestamp } from '../../../../utils/dateTime.utils'; import { invalidArgument } from '../../../../utils/error.utils'; import { assertValidationAsync } from '../../../../utils/schema.utils'; import { assertIsGuardian } from '../../../../utils/token.utils'; import { BaseTangleService, HandlerParams } from '../../base'; +import { Action } from '../../transaction-service'; import { editSpaceMemberSchemaObject } from './SpaceEditMemberTangleRequestSchema'; export class SpaceAcceptMemberService extends BaseTangleService { @@ -18,22 +21,29 @@ export class SpaceAcceptMemberService extends BaseTangleService params.member, ); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${params.uid}`); - const spaceMemberDocRef = spaceDocRef.collection(SUB_COL.MEMBERS).doc(spaceMember.uid); - const knockingMemberDocRef = spaceDocRef - .collection(SUB_COL.KNOCKING_MEMBERS) - .doc(spaceMember.uid); + const spaceMemberDocRef = build5Db().doc( + COL.SPACE, + params.uid, + SUB_COL.MEMBERS, + spaceMember.uid, + ); + const knockingMemberDocRef = build5Db().doc( + COL.SPACE, + params.uid, + SUB_COL.KNOCKING_MEMBERS, + spaceMember.uid, + ); this.transactionService.push({ ref: spaceMemberDocRef, data: spaceMember, - action: 'set', + action: Action.C, }); - this.transactionService.push({ ref: knockingMemberDocRef, data: {}, action: 'delete' }); + this.transactionService.push({ ref: knockingMemberDocRef, data: undefined, action: Action.D }); this.transactionService.push({ - ref: spaceDocRef, + ref: build5Db().doc(COL.SPACE, params.uid), data: space, - action: 'update', + action: Action.U, }); return { status: 'success' }; @@ -48,21 +58,21 @@ export const acceptSpaceMember = async ( ) => { await assertIsGuardian(spaceId, owner); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${spaceId}`); - const knockingMember = await spaceDocRef - .collection(SUB_COL.KNOCKING_MEMBERS) - .doc(member) - .get(); + const spaceDocRef = build5Db().doc(COL.SPACE, spaceId); + const knockingMember = await build5Db() + .doc(COL.SPACE, spaceId, SUB_COL.KNOCKING_MEMBERS, member) + .get(); if (!knockingMember) { throw invalidArgument(WenError.member_did_not_request_to_join); } - const space = await spaceDocRef.get(); + const space = await spaceDocRef.get(); const spaceMember = { project, uid: member, - parentId: space, + parentId: space?.uid!, parentCol: COL.SPACE, + createdOn: dateToTimestamp(dayjs()), }; const spaceUpdateData = { diff --git a/packages/functions/src/services/payment/tangle-service/space/SpaceBlockMemberService.ts b/packages/functions/src/services/payment/tangle-service/space/SpaceBlockMemberService.ts index a33340c7dd..98c2022ab0 100644 --- a/packages/functions/src/services/payment/tangle-service/space/SpaceBlockMemberService.ts +++ b/packages/functions/src/services/payment/tangle-service/space/SpaceBlockMemberService.ts @@ -1,10 +1,13 @@ import { build5Db } from '@build-5/database'; import { COL, Space, SUB_COL, TangleResponse, WenError } from '@build-5/interfaces'; +import dayjs from 'dayjs'; import { getProject } from '../../../../utils/common.utils'; +import { dateToTimestamp } from '../../../../utils/dateTime.utils'; import { invalidArgument } from '../../../../utils/error.utils'; import { assertValidationAsync } from '../../../../utils/schema.utils'; import { assertIsGuardian } from '../../../../utils/token.utils'; import { BaseTangleService, HandlerParams } from '../../base'; +import { Action } from '../../transaction-service'; import { editSpaceMemberSchemaObject } from './SpaceEditMemberTangleRequestSchema'; export class SpaceBlockMemberService extends BaseTangleService { @@ -19,31 +22,36 @@ export class SpaceBlockMemberService extends BaseTangleService { member, ); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${params.uid}`); - const blockedMemberDocRef = spaceDocRef.collection(SUB_COL.BLOCKED_MEMBERS).doc(member); + const spaceDocRef = build5Db().doc(COL.SPACE, params.uid); + const blockedMemberDocRef = build5Db().doc( + COL.SPACE, + params.uid, + SUB_COL.BLOCKED_MEMBERS, + member, + ); this.transactionService.push({ ref: blockedMemberDocRef, data: blockedMember, - action: 'set', + action: Action.C, }); this.transactionService.push({ - ref: spaceDocRef.collection(SUB_COL.MEMBERS).doc(member), - data: {}, - action: 'delete', + ref: build5Db().doc(COL.SPACE, params.uid, SUB_COL.MEMBERS, member), + data: undefined, + action: Action.D, }); this.transactionService.push({ - ref: spaceDocRef.collection(SUB_COL.KNOCKING_MEMBERS).doc(member), - data: {}, - action: 'delete', + ref: build5Db().doc(COL.SPACE, params.uid, SUB_COL.KNOCKING_MEMBERS, member), + data: undefined, + action: Action.D, }); this.transactionService.push({ ref: spaceDocRef, data: space, - action: 'update', + action: Action.U, }); return { status: 'success' }; @@ -56,16 +64,18 @@ export const getBlockMemberUpdateData = async ( spaceId: string, member: string, ) => { - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${spaceId}`); + const spaceDocRef = build5Db().doc(COL.SPACE, spaceId); await assertIsGuardian(spaceId, owner); - const spaceMember = await spaceDocRef.collection(SUB_COL.MEMBERS).doc(member).get(); - const knockingMember = await spaceDocRef.collection(SUB_COL.KNOCKING_MEMBERS).doc(member).get(); + const spaceMember = await build5Db().doc(COL.SPACE, spaceId, SUB_COL.MEMBERS, member).get(); + const knockingMember = await build5Db() + .doc(COL.SPACE, spaceId, SUB_COL.KNOCKING_MEMBERS, member) + .get(); if (!spaceMember && !knockingMember) { throw invalidArgument(WenError.member_is_not_part_of_the_space); } - const blockedMemberDocRef = spaceDocRef.collection(SUB_COL.BLOCKED_MEMBERS).doc(member); + const blockedMemberDocRef = build5Db().doc(COL.SPACE, spaceId, SUB_COL.BLOCKED_MEMBERS, member); const blockedMemberDoc = await blockedMemberDocRef.get(); if (blockedMemberDoc) { throw invalidArgument(WenError.member_is_already_blocked); @@ -76,7 +86,7 @@ export const getBlockMemberUpdateData = async ( throw invalidArgument(WenError.at_least_one_member_must_be_in_the_space); } - const guardian = await spaceDocRef.collection(SUB_COL.GUARDIANS).doc(member).get(); + const guardian = await build5Db().doc(COL.SPACE, spaceId, SUB_COL.GUARDIANS, member).get(); if (guardian) { throw invalidArgument(WenError.can_not_block_guardian); } @@ -86,6 +96,7 @@ export const getBlockMemberUpdateData = async ( uid: member, parentId: spaceId, parentCol: COL.SPACE, + createdOn: dateToTimestamp(dayjs()), }; const spaceUpdateData = { totalMembers: build5Db().inc(spaceMember ? -1 : 0), diff --git a/packages/functions/src/services/payment/tangle-service/space/SpaceCreateService.ts b/packages/functions/src/services/payment/tangle-service/space/SpaceCreateService.ts index 9246dcbafa..fc0d7c1106 100644 --- a/packages/functions/src/services/payment/tangle-service/space/SpaceCreateService.ts +++ b/packages/functions/src/services/payment/tangle-service/space/SpaceCreateService.ts @@ -1,8 +1,17 @@ import { build5Db, build5Storage } from '@build-5/database'; -import { COL, MediaStatus, Network, SUB_COL, SpaceCreateTangleResponse } from '@build-5/interfaces'; -import { get, set } from 'lodash'; +import { + COL, + MediaStatus, + Network, + SUB_COL, + SpaceCreateTangleResponse, + SpaceGuardian, +} from '@build-5/interfaces'; +import dayjs from 'dayjs'; +import { set } from 'lodash'; import { downloadMediaAndPackCar } from '../../../../utils/car.utils'; import { getBucket, isProdEnv } from '../../../../utils/config.utils'; +import { dateToTimestamp } from '../../../../utils/dateTime.utils'; import { migrateUriToSotrage, uriToUrl } from '../../../../utils/media.utils'; import { assertValidationAsync } from '../../../../utils/schema.utils'; import { spaceToIpfsMetadata } from '../../../../utils/space.utils'; @@ -10,6 +19,7 @@ import { getRandomEthAddress } from '../../../../utils/wallet.utils'; import { isStorageUrl } from '../../../joi/common'; import { WalletService } from '../../../wallet/wallet.service'; import { BaseTangleService, HandlerParams } from '../../base'; +import { Action } from '../../transaction-service'; import { createSpaceSchemaObject } from './SpaceCreateTangleRequestSchema'; export class SpaceCreateService extends BaseTangleService { @@ -20,30 +30,30 @@ export class SpaceCreateService extends BaseTangleService => { await assertValidationAsync(createSpaceSchemaObject, request); - const { space, guardian, member } = await getCreateSpaceData(project, owner, request); + const { space, guardian } = await getCreateSpaceData(project, owner, request); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${space.uid}`); - this.transactionService.push({ ref: spaceDocRef, data: space, action: 'set' }); + this.transactionService.push({ + ref: build5Db().doc(COL.SPACE, space.uid), + data: space, + action: Action.C, + }); - const spaceGuardianDocRef = spaceDocRef.collection(SUB_COL.GUARDIANS).doc(owner); this.transactionService.push({ - ref: spaceGuardianDocRef, + ref: build5Db().doc(COL.SPACE, space.uid, SUB_COL.GUARDIANS, owner), data: guardian, - action: 'set', + action: Action.C, }); - const spaceMemberDocRef = spaceDocRef.collection(SUB_COL.MEMBERS).doc(owner); this.transactionService.push({ - ref: spaceMemberDocRef, + ref: build5Db().doc(COL.SPACE, space.uid, SUB_COL.MEMBERS, owner), data: guardian, - action: 'set', + action: Action.C, }); - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${owner}`); + const memberDocRef = build5Db().doc(COL.MEMBER, owner); this.transactionService.push({ ref: memberDocRef, - data: member, - action: 'update', - merge: true, + data: { spaces: { [space.uid]: { uid: space.uid, isMember: true } } }, + action: Action.U, }); return { space: space.uid }; @@ -62,6 +72,7 @@ export const getCreateSpaceData = async ( uid: getRandomEthAddress(), project, ...params, + bannerUrl: (params.bannerUrl as string) || '', createdBy: owner, open: params.open === false ? false : true, totalMembers: 1, @@ -71,7 +82,7 @@ export const getCreateSpaceData = async ( vaultAddress: vaultAddress.bech32, }; - let bannerUrl = get(space, 'bannerUrl', ''); + let bannerUrl = space.bannerUrl || ''; if (bannerUrl) { // eslint-disable-next-line @typescript-eslint/no-explicit-any const metadata = spaceToIpfsMetadata(space as any); @@ -95,16 +106,16 @@ export const getCreateSpaceData = async ( set(space, 'mediaStatus', MediaStatus.PENDING_UPLOAD); } - const guardian = { + const guardian: SpaceGuardian = { project, uid: owner, parentId: space.uid, parentCol: COL.SPACE, + createdOn: dateToTimestamp(dayjs()), }; return { space: { ...space, guardians: { [owner]: guardian }, members: { [owner]: guardian } }, guardian, - member: { spaces: { [space.uid]: { uid: space.uid, isMember: true } } }, }; }; diff --git a/packages/functions/src/services/payment/tangle-service/space/SpaceDeclineMemberService.ts b/packages/functions/src/services/payment/tangle-service/space/SpaceDeclineMemberService.ts index 507cbcd67d..28e0097d00 100644 --- a/packages/functions/src/services/payment/tangle-service/space/SpaceDeclineMemberService.ts +++ b/packages/functions/src/services/payment/tangle-service/space/SpaceDeclineMemberService.ts @@ -3,6 +3,7 @@ import { COL, SUB_COL, TangleResponse } from '@build-5/interfaces'; import { assertValidationAsync } from '../../../../utils/schema.utils'; import { assertIsGuardian } from '../../../../utils/token.utils'; import { BaseTangleService, HandlerParams } from '../../base'; +import { Action } from '../../transaction-service'; import { editSpaceMemberSchemaObject } from './SpaceEditMemberTangleRequestSchema'; export class SpaceDeclineMemberService extends BaseTangleService { @@ -11,19 +12,22 @@ export class SpaceDeclineMemberService extends BaseTangleService await assertIsGuardian(params.uid, owner); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${params.uid}`); - const knockingMemberDocRef = spaceDocRef - .collection(SUB_COL.KNOCKING_MEMBERS) - .doc(params.member); + const spaceDocRef = build5Db().doc(COL.SPACE, params.uid); + const knockingMemberDocRef = build5Db().doc( + COL.SPACE, + params.uid, + SUB_COL.KNOCKING_MEMBERS, + params.member, + ); const knockingMember = await knockingMemberDocRef.get(); - this.transactionService.push({ ref: knockingMemberDocRef, data: {}, action: 'delete' }); + this.transactionService.push({ ref: knockingMemberDocRef, data: undefined, action: Action.D }); this.transactionService.push({ ref: spaceDocRef, data: { totalPendingMembers: build5Db().inc(knockingMember ? -1 : 0) }, - action: 'update', + action: Action.U, }); return { status: 'success' }; diff --git a/packages/functions/src/services/payment/tangle-service/space/SpaceGuardianService.ts b/packages/functions/src/services/payment/tangle-service/space/SpaceGuardianService.ts index 24b838f214..12036096c5 100644 --- a/packages/functions/src/services/payment/tangle-service/space/SpaceGuardianService.ts +++ b/packages/functions/src/services/payment/tangle-service/space/SpaceGuardianService.ts @@ -9,7 +9,6 @@ import { ProposalType, Space, SpaceGuardianUpsertTangleResponse, - SpaceMember, SUB_COL, TangleRequestType, Transaction, @@ -24,6 +23,7 @@ import { assertValidationAsync } from '../../../../utils/schema.utils'; import { assertIsGuardian } from '../../../../utils/token.utils'; import { getRandomEthAddress } from '../../../../utils/wallet.utils'; import { BaseTangleService, HandlerParams } from '../../base'; +import { Action } from '../../transaction-service'; import { editSpaceMemberSchemaObject } from './SpaceEditMemberTangleRequestSchema'; export class SpaceGuardianService extends BaseTangleService { @@ -46,22 +46,20 @@ export class SpaceGuardianService extends BaseTangleService { - proposalDocRef.collection(SUB_COL.MEMBERS).doc(member.uid).set(member); - }); + const memberPromisses = members.map((member) => + build5Db().doc(COL.PROPOSAL, proposal.uid, SUB_COL.MEMBERS, member.uid).create(member), + ); await Promise.all(memberPromisses); - const transactionDocRef = build5Db().doc(`${COL.TRANSACTION}/${voteTransaction.uid}`); this.transactionService.push({ - ref: transactionDocRef, + ref: build5Db().doc(COL.TRANSACTION, voteTransaction.uid), data: voteTransaction, - action: 'set', + action: Action.C, }); this.transactionService.push({ - ref: proposalDocRef, + ref: build5Db().doc(COL.PROPOSAL, proposal.uid), data: proposal, - action: 'set', + action: Action.C, }); return { proposal: proposal.uid }; @@ -77,18 +75,16 @@ export const addRemoveGuardian = async ( const isAddGuardian = type === ProposalType.ADD_GUARDIAN; await assertIsGuardian(params.uid as string, owner); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${params.uid}`); - const spaceMemberDoc = await spaceDocRef - .collection(SUB_COL.MEMBERS) - .doc(params.member as string) + const spaceDocRef = build5Db().doc(COL.SPACE, params.uid as string); + const spaceMemberDoc = await build5Db() + .doc(COL.SPACE, params.uid as string, SUB_COL.MEMBERS, params.member as string) .get(); if (!spaceMemberDoc) { throw invalidArgument(WenError.member_is_not_part_of_the_space); } - const spaceGuardianMember = await spaceDocRef - .collection(SUB_COL.GUARDIANS) - .doc(params.member as string) + const spaceGuardianMember = await build5Db() + .doc(COL.SPACE, params.uid as string, SUB_COL.GUARDIANS, params.member as string) .get(); if (isAddGuardian && spaceGuardianMember) { throw invalidArgument(WenError.member_is_already_guardian_of_space); @@ -98,7 +94,7 @@ export const addRemoveGuardian = async ( const ongoingProposalSnap = await build5Db() .collection(COL.PROPOSAL) - .where('settings.addRemoveGuardian', '==', params.member) + .where('settings_addRemoveGuardian', '==', params.member as string) .where('completed', '==', false) .get(); @@ -115,13 +111,14 @@ export const addRemoveGuardian = async ( }); } - const guardian = await build5Db().doc(`${COL.MEMBER}/${owner}`).get(); - const member = await build5Db().doc(`${COL.MEMBER}/${params.member}`).get(); + const guardian = await build5Db().doc(COL.MEMBER, owner).get(); + const member = await build5Db() + .doc(COL.MEMBER, params.member as string) + .get(); const guardians = await build5Db() - .doc(`${COL.SPACE}/${params.uid}`) - .collection(SUB_COL.GUARDIANS) - .get(); - const space = await spaceDocRef.get(); + .collection(COL.SPACE, params.uid as string, SUB_COL.GUARDIANS) + .get(); + const space = await spaceDocRef.get(); const proposal = getProposalData( project, guardian, @@ -153,7 +150,7 @@ export const addRemoveGuardian = async ( voted: guardian.uid === owner, tranId: guardian.uid === owner ? voteTransaction.uid : '', parentId: proposal.uid, - parentCol: COL.PROPOSAL, + parentCol: COL.SPACE, values: guardian.uid === owner ? [{ [1]: 1 }] : [], })); @@ -169,9 +166,7 @@ const getProposalData = ( guardiansCount: number, ): Proposal => { const additionalInfo = - `${owner.name || owner.uid} wants to ${isAddGuardian ? 'add' : 'remove'} ${ - member.name - } as guardian. ` + + `${owner.name || owner.uid} wants to ${isAddGuardian ? 'add' : 'remove'} ${member.name} as guardian. ` + `Request created on ${dayjs().format('MM/DD/YYYY')}. ` + `${ADD_REMOVE_GUARDIAN_THRESHOLD_PERCENTAGE} % must agree for this action to proceed`; return { diff --git a/packages/functions/src/services/payment/tangle-service/space/SpaceJoinService.ts b/packages/functions/src/services/payment/tangle-service/space/SpaceJoinService.ts index 3242fcfcdd..f00b0ca58c 100644 --- a/packages/functions/src/services/payment/tangle-service/space/SpaceJoinService.ts +++ b/packages/functions/src/services/payment/tangle-service/space/SpaceJoinService.ts @@ -6,7 +6,6 @@ import { StakeType, SUB_COL, TangleResponse, - TokenDistribution, WenError, } from '@build-5/interfaces'; import { getProject } from '../../../../utils/common.utils'; @@ -16,45 +15,44 @@ import { assertValidationAsync } from '../../../../utils/schema.utils'; import { getTokenForSpace } from '../../../../utils/token.utils'; import { getStakeForType } from '../../../stake.service'; import { BaseTangleService, HandlerParams } from '../../base'; +import { Action } from '../../transaction-service'; import { joinSpaceSchema } from './SpaceJoinTangleRequestSchema'; export class SpaceJoinService extends BaseTangleService { public handleRequest = async ({ order, owner, request }: HandlerParams) => { const params = await assertValidationAsync(joinSpaceSchema, request); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${params.uid}`); + const spaceDocRef = build5Db().doc(COL.SPACE, params.uid); const space = await spaceDocRef.get(); if (!space) { throw invalidArgument(WenError.space_does_not_exists); } - const { - space: spaceUpdateData, - spaceMember, - member, - } = await getJoinSpaceData(getProject(order), owner, space); + const { space: spaceUpdateData, spaceMember } = await getJoinSpaceData( + getProject(order), + owner, + space, + ); - const joiningMemberDocRef = spaceDocRef - .collection(space.open || space.tokenBased ? SUB_COL.MEMBERS : SUB_COL.KNOCKING_MEMBERS) - .doc(owner); + const subCol = space.open || space.tokenBased ? SUB_COL.MEMBERS : SUB_COL.KNOCKING_MEMBERS; + const joiningMemberDocRef = build5Db().doc(COL.SPACE, params.uid, subCol, owner); this.transactionService.push({ ref: joiningMemberDocRef, data: spaceMember, - action: 'set', + action: Action.C, }); this.transactionService.push({ ref: spaceDocRef, data: spaceUpdateData, - action: 'update', + action: Action.U, }); - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${owner}`); + const memberDocRef = build5Db().doc(COL.MEMBER, owner); this.transactionService.push({ ref: memberDocRef, - data: member, - action: 'set', - merge: true, + data: { spaces: { [space.uid]: { uid: space.uid, isMember: true } } }, + action: Action.U, }); return { status: 'success' }; @@ -62,21 +60,20 @@ export class SpaceJoinService extends BaseTangleService { } export const getJoinSpaceData = async (project: string, owner: string, space: Space) => { - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${space.uid}`); - - const joinedMemberSnap = await spaceDocRef.collection(SUB_COL.MEMBERS).doc(owner).get(); + const joinedMemberSnap = await build5Db().doc(COL.SPACE, space.uid, SUB_COL.MEMBERS, owner).get(); if (joinedMemberSnap) { throw invalidArgument(WenError.you_are_already_part_of_space); } - const blockedMemberSnap = await spaceDocRef.collection(SUB_COL.BLOCKED_MEMBERS).doc(owner).get(); + const blockedMemberSnap = await build5Db() + .doc(COL.SPACE, space.uid, SUB_COL.BLOCKED_MEMBERS, owner) + .get(); if (blockedMemberSnap) { throw invalidArgument(WenError.you_are_not_allowed_to_join_space); } - const knockingMemberSnap = await spaceDocRef - .collection(SUB_COL.KNOCKING_MEMBERS) - .doc(owner) + const knockingMemberSnap = await build5Db() + .doc(COL.SPACE, space.uid, SUB_COL.KNOCKING_MEMBERS, owner) .get(); if (knockingMemberSnap) { throw invalidArgument(WenError.member_already_knocking); @@ -105,9 +102,8 @@ export const getJoinSpaceData = async (project: string, owner: string, space: Sp const assertMemberHasEnoughStakedTokens = async (space: Space, member: string) => { const token = await getTokenForSpace(space.uid); - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${token?.uid}`); - const distributionDocRef = tokenDocRef.collection(SUB_COL.DISTRIBUTION).doc(member); - const distribution = await distributionDocRef.get(); + const distributionDocRef = build5Db().doc(COL.TOKEN, token?.uid!, SUB_COL.DISTRIBUTION, member); + const distribution = await distributionDocRef.get(); const stakeValue = getStakeForType(distribution, StakeType.DYNAMIC); if (stakeValue < (space.minStakedValue || 0)) { throw invalidArgument(WenError.not_enough_staked_tokens); diff --git a/packages/functions/src/services/payment/tangle-service/space/SpaceLeaveService.ts b/packages/functions/src/services/payment/tangle-service/space/SpaceLeaveService.ts index 4e93506ae1..040ab1ec5e 100644 --- a/packages/functions/src/services/payment/tangle-service/space/SpaceLeaveService.ts +++ b/packages/functions/src/services/payment/tangle-service/space/SpaceLeaveService.ts @@ -3,41 +3,40 @@ import { COL, Space, SUB_COL, TangleResponse, WenError } from '@build-5/interfac import { invalidArgument } from '../../../../utils/error.utils'; import { assertValidationAsync } from '../../../../utils/schema.utils'; import { BaseTangleService, HandlerParams } from '../../base'; +import { Action } from '../../transaction-service'; import { leaveSpaceSchema } from './SpaceLeaveTangleRequestSchema'; export class SpaceLeaveService extends BaseTangleService { public handleRequest = async ({ owner, request }: HandlerParams) => { const params = await assertValidationAsync(leaveSpaceSchema, request); - const { space, member } = await getLeaveSpaceData(owner, params.uid); + const spaceUpdateData = await getLeaveSpaceData(owner, params.uid); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${params.uid}`); + const spaceDocRef = build5Db().doc(COL.SPACE, params.uid); this.transactionService.push({ - ref: spaceDocRef.collection(SUB_COL.MEMBERS).doc(owner), - data: {}, - action: 'delete', + ref: build5Db().doc(COL.SPACE, params.uid, SUB_COL.MEMBERS, owner), + data: undefined, + action: Action.D, }); this.transactionService.push({ - ref: spaceDocRef.collection(SUB_COL.GUARDIANS).doc(owner), - data: {}, - action: 'delete', + ref: build5Db().doc(COL.SPACE, params.uid, SUB_COL.GUARDIANS, owner), + data: undefined, + action: Action.D, }); this.transactionService.push({ ref: spaceDocRef, - data: space, - action: 'update', + data: spaceUpdateData, + action: Action.U, }); - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${owner}`); - + const memberSpaceStats = build5Db().doc(COL.MEMBER, owner); this.transactionService.push({ - ref: memberDocRef, - data: member, - action: 'set', - merge: true, + ref: memberSpaceStats, + data: { spaces: { [params.uid]: { isMember: false } } }, + action: Action.U, }); return { status: 'success' }; @@ -45,9 +44,9 @@ export class SpaceLeaveService extends BaseTangleService { } export const getLeaveSpaceData = async (owner: string, spaceId: string) => { - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${spaceId}`); + const spaceDocRef = build5Db().doc(COL.SPACE, spaceId); - const spaceMember = await spaceDocRef.collection(SUB_COL.MEMBERS).doc(owner).get(); + const spaceMember = await build5Db().doc(COL.SPACE, spaceId, SUB_COL.MEMBERS, owner).get(); if (!spaceMember) { throw invalidArgument(WenError.you_are_not_part_of_the_space); } @@ -57,16 +56,14 @@ export const getLeaveSpaceData = async (owner: string, spaceId: string) => { throw invalidArgument(WenError.at_least_one_member_must_be_in_the_space); } - const guardianDoc = await spaceDocRef.collection(SUB_COL.GUARDIANS).doc(owner).get(); + const guardianDoc = await build5Db().doc(COL.SPACE, spaceId, SUB_COL.GUARDIANS, owner).get(); const isGuardian = guardianDoc !== undefined; if (space.totalGuardians === 1 && isGuardian) { throw invalidArgument(WenError.at_least_one_guardian_must_be_in_the_space); } - const spaceUpdateData = { + return { totalMembers: build5Db().inc(-1), totalGuardians: build5Db().inc(isGuardian ? -1 : 0), }; - const member = { spaces: { [space.uid]: { uid: space.uid, isMember: false } } }; - return { space: spaceUpdateData, member }; }; diff --git a/packages/functions/src/services/payment/tangle-service/stamp/StampTangleService.ts b/packages/functions/src/services/payment/tangle-service/stamp/StampTangleService.ts index 3c4f7c1dfe..bbb2567297 100644 --- a/packages/functions/src/services/payment/tangle-service/stamp/StampTangleService.ts +++ b/packages/functions/src/services/payment/tangle-service/stamp/StampTangleService.ts @@ -6,7 +6,6 @@ import { STAMP_COST_PER_MB, SUB_COL, Space, - SpaceGuardian, Stamp, TRANSACTION_AUTO_EXPIRY_MS, TangleResponse, @@ -23,7 +22,7 @@ import { packBasicOutput } from '../../../../utils/basic-output.utils'; import { downloadMediaAndPackCar } from '../../../../utils/car.utils'; import { createNftOutput } from '../../../../utils/collection-minting-utils/nft.utils'; import { getProject } from '../../../../utils/common.utils'; -import { dateToTimestamp } from '../../../../utils/dateTime.utils'; +import { dateToTimestamp, serverTime } from '../../../../utils/dateTime.utils'; import { invalidArgument } from '../../../../utils/error.utils'; import { getRandomBuild5Url, uriToUrl } from '../../../../utils/media.utils'; import { assertValidationAsync } from '../../../../utils/schema.utils'; @@ -37,6 +36,7 @@ import { isStorageUrl } from '../../../joi/common'; import { Wallet } from '../../../wallet/wallet'; import { WalletService } from '../../../wallet/wallet.service'; import { BaseTangleService, HandlerParams } from '../../base'; +import { Action } from '../../transaction-service'; import { stampTangleSchema } from './StampTangleRequestSchema'; export class StampTangleService extends BaseTangleService { @@ -62,22 +62,27 @@ export class StampTangleService extends BaseTangleService { ); if (!params.aliasId) { - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${space.uid}`); - this.transactionService.push({ ref: spaceDocRef, data: space, action: 'set' }); + const spaceDocRef = build5Db().doc(COL.SPACE, space.uid); + this.transactionService.push({ ref: spaceDocRef, data: space, action: Action.C }); - const guardian = { uid: owner, parentId: space.uid, parentCol: COL.SPACE }; - const guardianDocRef = spaceDocRef.collection(SUB_COL.GUARDIANS).doc(owner); - this.transactionService.push({ ref: guardianDocRef, data: guardian, action: 'set' }); + const guardian = { + uid: owner, + parentId: space.uid, + parentCol: COL.SPACE, + createdOn: serverTime(), + }; + const guardianDocRef = build5Db().doc(COL.SPACE, space.uid, SUB_COL.GUARDIANS, owner); + this.transactionService.push({ ref: guardianDocRef, data: guardian, action: Action.C }); - const memberDocRef = spaceDocRef.collection(SUB_COL.MEMBERS).doc(owner); - this.transactionService.push({ ref: memberDocRef, data: guardian, action: 'set' }); + const memberDocRef = build5Db().doc(COL.SPACE, space.uid, SUB_COL.MEMBERS, owner); + this.transactionService.push({ ref: memberDocRef, data: guardian, action: Action.C }); } - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${order.uid}`); - this.transactionService.push({ ref: orderDocRef, data: order, action: 'set' }); + const orderDocRef = build5Db().doc(COL.TRANSACTION, order.uid); + this.transactionService.push({ ref: orderDocRef, data: order, action: Action.C }); - const stampDocRef = build5Db().doc(`${COL.STAMP}/${stamp.uid}`); - this.transactionService.push({ ref: stampDocRef, data: stamp, action: 'set' }); + const stampDocRef = build5Db().doc(COL.STAMP, stamp.uid); + this.transactionService.push({ ref: stampDocRef, data: stamp, action: Action.C }); if (match.to.amount < order.payload.amount!) { return { @@ -222,9 +227,8 @@ const getAliasOutputAmount = async (stamp: Stamp, space: Space, wallet: Wallet) if (!space.alias?.address) { throw invalidArgument(WenError.not_alias_governor); } - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${space.uid}`); - const guardianDocRef = spaceDocRef.collection(SUB_COL.GUARDIANS).doc(stamp.createdBy); - const guardian = await guardianDocRef.get(); + const guardianDocRef = build5Db().doc(COL.SPACE, space.uid, SUB_COL.GUARDIANS, stamp.createdBy); + const guardian = await guardianDocRef.get(); if (!guardian) { throw invalidArgument(WenError.not_alias_governor); diff --git a/packages/functions/src/services/payment/tangle-service/swap/SwapCreateTangleService.ts b/packages/functions/src/services/payment/tangle-service/swap/SwapCreateTangleService.ts index 02b10db14f..bc541ea7e8 100644 --- a/packages/functions/src/services/payment/tangle-service/swap/SwapCreateTangleService.ts +++ b/packages/functions/src/services/payment/tangle-service/swap/SwapCreateTangleService.ts @@ -4,6 +4,7 @@ import { assertValidationAsync } from '../../../../utils/schema.utils'; import { WalletService } from '../../../wallet/wallet.service'; import { BaseTangleService, HandlerParams } from '../../base'; import { createSwapOrder } from '../../swap/swap-service'; +import { Action } from '../../transaction-service'; import { swapCreateTangleSchema } from './SwapCreateTangleRequestSchema'; export class SwapCreateTangleService extends BaseTangleService { @@ -43,11 +44,11 @@ export class SwapCreateTangleService extends BaseTangleService { bids, ); - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${order.uid}`); - this.transactionService.push({ ref: orderDocRef, data: order, action: 'set' }); + const orderDocRef = build5Db().doc(COL.TRANSACTION, order.uid); + this.transactionService.push({ ref: orderDocRef, data: order, action: Action.C }); - const swapDocRef = build5Db().doc(`${COL.SWAP}/${swap.uid}`); - this.transactionService.push({ ref: swapDocRef, data: swap, action: 'set' }); + const swapDocRef = build5Db().doc(COL.SWAP, swap.uid); + this.transactionService.push({ ref: swapDocRef, data: swap, action: Action.C }); if (params.setFunded) { return {}; diff --git a/packages/functions/src/services/payment/tangle-service/swap/SwapRejectTangleService.ts b/packages/functions/src/services/payment/tangle-service/swap/SwapRejectTangleService.ts index d382ecbb7b..218f7d3817 100644 --- a/packages/functions/src/services/payment/tangle-service/swap/SwapRejectTangleService.ts +++ b/packages/functions/src/services/payment/tangle-service/swap/SwapRejectTangleService.ts @@ -1,8 +1,9 @@ import { build5Db } from '@build-5/database'; -import { COL, Swap, SwapStatus, TangleResponse } from '@build-5/interfaces'; +import { COL, SwapStatus, TangleResponse } from '@build-5/interfaces'; import { assertValidationAsync } from '../../../../utils/schema.utils'; import { BaseTangleService, HandlerParams } from '../../base'; import { rejectSwap } from '../../swap/swap-service'; +import { Action } from '../../transaction-service'; import { swapRejectTangleSchema } from './SwapRejectTangleRequestSchema'; export class SwapRejectTangleService extends BaseTangleService { @@ -13,20 +14,20 @@ export class SwapRejectTangleService extends BaseTangleService { }: HandlerParams): Promise => { const params = await assertValidationAsync(swapRejectTangleSchema, request); - const swapDocRef = build5Db().doc(`${COL.SWAP}/${params.uid}`); - const swap = await this.transactionService.get(swapDocRef); + const swapDocRef = build5Db().doc(COL.SWAP, params.uid); + const swap = await this.transaction.get(swapDocRef); const credits = rejectSwap(project, owner, swap); for (const credit of credits) { - const docRef = build5Db().doc(`${COL.TRANSACTION}/${credit.uid}`); - this.transactionService.push({ ref: docRef, data: credit, action: 'set' }); + const docRef = build5Db().doc(COL.TRANSACTION, credit.uid); + this.transactionService.push({ ref: docRef, data: credit, action: Action.C }); } this.transactionService.push({ ref: swapDocRef, data: { status: SwapStatus.REJECTED }, - action: 'update', + action: Action.U, }); return { status: 'success' }; diff --git a/packages/functions/src/services/payment/tangle-service/swap/SwapSetFundedTangleService.ts b/packages/functions/src/services/payment/tangle-service/swap/SwapSetFundedTangleService.ts index d8b059bf4f..a4124adac8 100644 --- a/packages/functions/src/services/payment/tangle-service/swap/SwapSetFundedTangleService.ts +++ b/packages/functions/src/services/payment/tangle-service/swap/SwapSetFundedTangleService.ts @@ -1,5 +1,5 @@ import { build5Db } from '@build-5/database'; -import { COL, Swap, SwapStatus, TangleResponse } from '@build-5/interfaces'; +import { COL, SwapStatus, TangleResponse } from '@build-5/interfaces'; import { assertValidationAsync } from '../../../../utils/schema.utils'; import { BaseTangleService, HandlerParams } from '../../base'; import { @@ -7,6 +7,7 @@ import { assertSwapCanBeSetAsFunded, createSwapTransfers, } from '../../swap/swap-service'; +import { Action } from '../../transaction-service'; import { swapSetFundedTangleSchema } from './SwapSetFundedTangleRequestSchema'; export class SwapSetFundedTangleService extends BaseTangleService { @@ -17,26 +18,25 @@ export class SwapSetFundedTangleService extends BaseTangleService => { const params = await assertValidationAsync(swapSetFundedTangleSchema, request); - const swapDocRef = build5Db().doc(`${COL.SWAP}/${params.uid}`); - const swap = await this.transactionService.get(swapDocRef); + const swapDocRef = build5Db().doc(COL.SWAP, params.uid); + const swap = await this.transaction.get(swapDocRef); assertSwapCanBeSetAsFunded(owner, swap); if (asksAreFulfilled(swap!)) { const transfers = await createSwapTransfers(project, swap!); for (const transfer of transfers) { - const docRef = build5Db().doc(`${COL.TRANSACTION}/${transfer.uid}`); this.transactionService.push({ - ref: docRef, + ref: build5Db().doc(COL.TRANSACTION, transfer.uid), data: transfer, - action: 'set', + action: Action.C, }); } this.transactionService.push({ ref: swapDocRef, data: { status: SwapStatus.FULFILLED }, - action: 'update', + action: Action.U, }); return { status: 'success' }; @@ -45,7 +45,7 @@ export class SwapSetFundedTangleService extends BaseTangleService { @@ -44,9 +45,9 @@ export class TangleStakeService extends BaseTangleService { set(order, 'payload.amount', tranEntry.amount); this.transactionService.push({ - ref: build5Db().doc(`${COL.TRANSACTION}/${order.uid}`), + ref: build5Db().doc(COL.TRANSACTION, order.uid), data: order, - action: 'set', + action: Action.C, }); this.transactionService.createUnlockTransaction( diff --git a/packages/functions/src/services/payment/tangle-service/token/token-claim.service.ts b/packages/functions/src/services/payment/tangle-service/token/token-claim.service.ts index ab9a021562..18e1264ffa 100644 --- a/packages/functions/src/services/payment/tangle-service/token/token-claim.service.ts +++ b/packages/functions/src/services/payment/tangle-service/token/token-claim.service.ts @@ -5,7 +5,6 @@ import { SUB_COL, TRANSACTION_AUTO_EXPIRY_MS, TangleResponse, - TokenDistribution, TokenDrop, TokenDropStatus, TokenStatus, @@ -26,6 +25,7 @@ import { getTokenBySymbol, getUnclaimedDrops } from '../../../../utils/token.uti import { getRandomEthAddress } from '../../../../utils/wallet.utils'; import { WalletService } from '../../../wallet/wallet.service'; import { BaseTangleService, HandlerParams } from '../../base'; +import { Action } from '../../transaction-service'; import { tokenClaimSchema } from './TokenClaimTangleRequestSchema'; export class TangleTokenClaimService extends BaseTangleService { @@ -33,9 +33,9 @@ export class TangleTokenClaimService extends BaseTangleService { const params = await assertValidationAsync(tokenClaimSchema, request); const order = await createMintedTokenAirdropClaimOrder(project, owner, params.symbol); this.transactionService.push({ - ref: build5Db().doc(`${COL.TRANSACTION}/${order.uid}`), + ref: build5Db().doc(COL.TRANSACTION, order.uid), data: order, - action: 'set', + action: Action.C, }); return { amount: order.payload.amount!, address: order.payload.targetAddress! }; }; @@ -55,7 +55,7 @@ export const createMintedTokenAirdropClaimOrder = async ( throw invalidArgument(WenError.token_in_invalid_status); } - const member = await build5Db().doc(`${COL.MEMBER}/${owner}`).get(); + const member = await build5Db().doc(COL.MEMBER, owner).get(); assertMemberHasValidAddress(member, token.mintingData?.network!); const drops = await getClaimableDrops(token.uid, owner); @@ -95,9 +95,8 @@ export const createMintedTokenAirdropClaimOrder = async ( const getClaimableDrops = async (token: string, member: string) => { const airdops = await getUnclaimedDrops(token, member); - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${token}`); - const distributionDocRef = tokenDocRef.collection(SUB_COL.DISTRIBUTION).doc(member); - const distribution = await distributionDocRef.get(); + const distributionDocRef = build5Db().doc(COL.TOKEN, token, SUB_COL.DISTRIBUTION, member); + const distribution = await distributionDocRef.get(); if (distribution?.mintedClaimedOn || !distribution?.tokenOwned) { return airdops; } diff --git a/packages/functions/src/services/payment/tangle-service/token/token-trade.service.ts b/packages/functions/src/services/payment/tangle-service/token/token-trade.service.ts index 75a181345c..03d6aa8d7d 100644 --- a/packages/functions/src/services/payment/tangle-service/token/token-trade.service.ts +++ b/packages/functions/src/services/payment/tangle-service/token/token-trade.service.ts @@ -4,13 +4,11 @@ import { DEFAULT_NETWORK, MAX_TOTAL_TOKEN_SUPPLY, MIN_PRICE_PER_TOKEN, - Member, Network, SUB_COL, TRANSACTION_MAX_EXPIRY_MS, TangleResponse, Token, - TokenDistribution, TokenStatus, TokenTradeOrder, TokenTradeOrderStatus, @@ -41,6 +39,7 @@ import { import { getRandomEthAddress } from '../../../../utils/wallet.utils'; import { WalletService } from '../../../wallet/wallet.service'; import { BaseTangleService, HandlerParams } from '../../base'; +import { Action } from '../../transaction-service'; import { tradeMintedTokenSchema } from './TokenTradeTangleRequestSchema'; export class TangleTokenTradeService extends BaseTangleService { @@ -63,8 +62,8 @@ export class TangleTokenTradeService extends BaseTangleService { params.symbol || (type === TokenTradeOrderType.SELL ? order.network : getNetworkPair(order.network)); let token = await getTokenBySymbol(symbol); - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${token?.uid}`); - token = await this.transactionService.get(tokenDocRef); + const tokenDocRef = build5Db().doc(COL.TOKEN, token?.uid!); + token = await this.transaction.get(tokenDocRef); if (!token) { throw invalidArgument(WenError.token_does_not_exist); } @@ -79,7 +78,7 @@ export class TangleTokenTradeService extends BaseTangleService { token, type, getCount(params, type), - await getPrice(params, type, token.uid), + await getPrice(this.transactionService.transaction, params, type, token.uid), params.targetAddress, '', [TokenStatus.BASE, TokenStatus.MINTED], @@ -93,9 +92,9 @@ export class TangleTokenTradeService extends BaseTangleService { set(tradeOrderTransaction, 'payload.amount', tranEntry.amount); } this.transactionService.push({ - ref: build5Db().doc(`${COL.TRANSACTION}/${tradeOrderTransaction.uid}`), + ref: build5Db().doc(COL.TRANSACTION, tradeOrderTransaction.uid), data: tradeOrderTransaction, - action: 'set', + action: Action.C, }); this.transactionService.createUnlockTransaction( @@ -139,7 +138,7 @@ export const createTokenTradeOrder = async ( assertTokenStatus(token, acceptedTokenStatuses); const [sourceNetwork, targetNetwork] = getSourceAndTargetNetwork(token, isSell); - const member = await build5Db().doc(`${COL.MEMBER}/${owner}`).get(); + const member = await build5Db().doc(COL.MEMBER, owner).get(); assertMemberHasValidAddress(member, sourceNetwork); if (targetAddress) { if (!targetAddress.startsWith(targetNetwork === Network.ATOI ? 'rms' : targetNetwork)) { @@ -164,9 +163,8 @@ export const createTokenTradeOrder = async ( return { tradeOrderTransaction, tradeOrder: undefined, distribution: undefined }; } - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${token.uid}`); - const distributionDocRef = tokenDocRef.collection(SUB_COL.DISTRIBUTION).doc(owner); - const distribution = await transaction.get(distributionDocRef); + const distributionDocRef = build5Db().doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, owner); + const distribution = await transaction.get(distributionDocRef); if (!distribution) { throw invalidArgument(WenError.invalid_params); } @@ -260,6 +258,7 @@ const createTradeOrderTransaction = async ( }; const getPrice = async ( + transaction: ITransaction, params: TradeTokenTangleRequest, type: TokenTradeOrderType, token: string, @@ -277,7 +276,7 @@ const getPrice = async ( .where('status', '==', TokenTradeOrderStatus.ACTIVE) .orderBy('price', 'desc') .limit(1) - .get(); + .get(); const highestSell = head(snap); if (!highestSell) { throw invalidArgument(WenError.no_active_sells); diff --git a/packages/functions/src/services/payment/token/import-minted-token.service.ts b/packages/functions/src/services/payment/token/import-minted-token.service.ts index d43529e9e4..b3ad047c1e 100644 --- a/packages/functions/src/services/payment/token/import-minted-token.service.ts +++ b/packages/functions/src/services/payment/token/import-minted-token.service.ts @@ -29,15 +29,15 @@ import { isAliasGovernor } from '../../../utils/token-minting-utils/alias.utils' import { Wallet } from '../../wallet/wallet'; import { WalletService } from '../../wallet/wallet.service'; import { BaseService, HandlerParams } from '../base'; -import { TransactionMatch } from '../transaction-service'; +import { Action, TransactionMatch } from '../transaction-service'; export class ImportMintedTokenService extends BaseService { public handleRequest = async ({ order, match }: HandlerParams) => { let error: { [key: string]: unknown } = {}; try { const tokenId = order.payload.tokenId!; - const existingTokenDocRef = build5Db().doc(`${COL.TOKEN}/${tokenId}`); - const existingToken = await this.transactionService.get(existingTokenDocRef); + const existingTokenDocRef = build5Db().doc(COL.TOKEN, tokenId); + const existingToken = await this.transaction.get(existingTokenDocRef); if (existingToken) { throw WenError.token_does_not_exist; @@ -99,8 +99,8 @@ export class ImportMintedTokenService extends BaseService { pricePerToken: 0, decimals: metadata.decimals, }; - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${token.uid}`); - this.transactionService.push({ ref: tokenDocRef, data: token, action: 'set' }); + const tokenDocRef = build5Db().doc(COL.TOKEN, token.uid); + this.transactionService.push({ ref: tokenDocRef, data: token, action: Action.C }); } catch (err) { error = { status: 'error', diff --git a/packages/functions/src/services/payment/token/token-mint.service.ts b/packages/functions/src/services/payment/token/token-mint.service.ts index 2d3316563e..8bf521f560 100644 --- a/packages/functions/src/services/payment/token/token-mint.service.ts +++ b/packages/functions/src/services/payment/token/token-mint.service.ts @@ -1,13 +1,13 @@ import { build5Db } from '@build-5/database'; import { COL, Token, TokenStatus, TransactionPayloadType } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { get } from 'lodash'; import { BaseService, HandlerParams } from '../base'; +import { Action } from '../transaction-service'; export class TokenMintService extends BaseService { public handleRequest = async ({ order, match }: HandlerParams) => { - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${order.payload.token}`); - const token = await this.transactionService.get(tokenDocRef); + const tokenDocRef = build5Db().doc(COL.TOKEN, order.payload.token!); + const token = await this.transaction.get(tokenDocRef); const payment = await this.transactionService.createPayment(order, match); if (![TokenStatus.AVAILABLE, TokenStatus.PRE_MINTED].includes(token.status)) { @@ -34,16 +34,16 @@ export class TokenMintService extends BaseService { ref: tokenDocRef, data: { status: TokenStatus.MINTING, - 'mintingData.mintedBy': order.member, - 'mintingData.network': order.network, - 'mintingData.aliasStorageDeposit': get(order, 'payload.aliasStorageDeposit', 0), - 'mintingData.foundryStorageDeposit': get(order, 'payload.foundryStorageDeposit', 0), - 'mintingData.vaultStorageDeposit': get(order, 'payload.vaultStorageDeposit', 0), - 'mintingData.guardianStorageDeposit': get(order, 'payload.guardianStorageDeposit', 0), - 'mintingData.tokensInVault': get(order, 'payload.tokensInVault', 0), - 'mintingData.vaultAddress': order.payload.targetAddress, + mintingData_mintedBy: order.member, + mintingData_network: order.network, + mintingData_aliasStorageDeposit: order.payload.aliasStorageDeposit || 0, + mintingData_foundryStorageDeposit: order.payload.foundryStorageDeposit || 0, + mintingData_vaultStorageDeposit: order.payload.vaultStorageDeposit || 0, + mintingData_guardianStorageDeposit: order.payload.guardianStorageDeposit || 0, + mintingData_tokensInVault: order.payload.tokensInVault || 0, + mintingData_vaultAddress: order.payload.targetAddress, }, - action: 'update', + action: Action.U, }); }; } diff --git a/packages/functions/src/services/payment/token/token-minted-airdrop.service.ts b/packages/functions/src/services/payment/token/token-minted-airdrop.service.ts index 42df057148..78ac64c17d 100644 --- a/packages/functions/src/services/payment/token/token-minted-airdrop.service.ts +++ b/packages/functions/src/services/payment/token/token-minted-airdrop.service.ts @@ -1,25 +1,18 @@ -import { build5Db, getSnapshot } from '@build-5/database'; -import { - COL, - SUB_COL, - Token, - TokenDrop, - TokenDropStatus, - TransactionPayloadType, -} from '@build-5/interfaces'; -import { get, last } from 'lodash'; +import { build5Db } from '@build-5/database'; +import { COL, SUB_COL, Token, TokenDropStatus, TransactionPayloadType } from '@build-5/interfaces'; import { BaseService, HandlerParams } from '../base'; +import { Action } from '../transaction-service'; export class TokenMintedAirdropService extends BaseService { public handleRequest = async ({ order, match, tranEntry }: HandlerParams) => { const payment = await this.transactionService.createPayment(order, match); - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${order.payload.token}`); + const tokenDocRef = build5Db().doc(COL.TOKEN, order.payload.token!); const token = await tokenDocRef.get(); const tokensSent = (tranEntry.nativeTokens || []).reduce( (acc, act) => (act.id === token.mintingData?.tokenId ? acc + Number(act.amount) : acc), 0, ); - const tokensExpected = get(order, 'payload.totalAirdropCount', 0); + const tokensExpected = order.payload.totalAirdropCount || 0; if (tokensSent !== tokensExpected || (tranEntry.nativeTokens || []).length > 1) { await this.transactionService.createCredit( @@ -29,48 +22,34 @@ export class TokenMintedAirdropService extends BaseService { ); return; } + const snap = await build5Db() + .collection(COL.AIRDROP) + .where('orderId', '==', order.uid) + .where('status', '==', TokenDropStatus.DEPOSIT_NEEDED) + .get(); - let lastDocId = ''; - do { - const lastDoc = await getSnapshot(COL.AIRDROP, lastDocId); - const snap = await build5Db() - .collection(COL.AIRDROP) - .where('orderId', '==', order.uid) - .limit(250) - .startAfter(lastDoc) - .get(); - lastDocId = last(snap)?.uid || ''; - - const batch = build5Db().batch(); - snap.forEach((airdrop) => { - const distributionDocRef = build5Db() - .collection(COL.TOKEN) - .doc(airdrop.token) - .collection(SUB_COL.DISTRIBUTION) - .doc(airdrop.member); + for (const airdrop of snap) { + const distributionDocRef = build5Db().doc( + COL.TOKEN, + airdrop.token, + SUB_COL.DISTRIBUTION, + airdrop.member, + ); - batch.set( - distributionDocRef, - { - parentId: airdrop.token, - parentCol: COL.TOKEN, - uid: airdrop.member, - totalUnclaimedAirdrop: build5Db().inc(airdrop.count), - }, - true, - ); - const docRef = build5Db().doc(`${COL.AIRDROP}/${airdrop.uid}`); - batch.update(docRef, { status: TokenDropStatus.UNCLAIMED }); + await this.transaction.upsert(distributionDocRef, { + parentId: airdrop.token, + totalUnclaimedAirdrop: build5Db().inc(airdrop.count), }); - await batch.commit(); - } while (lastDocId); + const docRef = build5Db().doc(COL.AIRDROP, airdrop.uid); + await this.transaction.update(docRef, { status: TokenDropStatus.UNCLAIMED }); + } this.transactionService.markAsReconciled(order, match.msgId); this.transactionService.push({ - ref: build5Db().doc(`${COL.TRANSACTION}/${order.uid}`), - data: { 'payload.amount': tranEntry.amount }, - action: 'update', + ref: build5Db().doc(COL.TRANSACTION, order.uid), + data: { payload_amount: tranEntry.amount }, + action: Action.U, }); }; } diff --git a/packages/functions/src/services/payment/token/token-purchase.service.ts b/packages/functions/src/services/payment/token/token-purchase.service.ts index a02ad70018..c6c8733135 100644 --- a/packages/functions/src/services/payment/token/token-purchase.service.ts +++ b/packages/functions/src/services/payment/token/token-purchase.service.ts @@ -3,7 +3,6 @@ import { COL, SUB_COL, Token, - TokenDistribution, TokenStatus, Transaction, TransactionPayloadType, @@ -11,7 +10,7 @@ import { import bigDecimal from 'js-big-decimal'; import { getBoughtByMemberDiff, getTotalPublicSupply } from '../../../utils/token.utils'; import { BaseService, HandlerParams } from '../base'; -import { TransactionMatch } from '../transaction-service'; +import { Action, TransactionMatch } from '../transaction-service'; export class TokenPurchaseService extends BaseService { public handleRequest = async ({ order, match }: HandlerParams) => { @@ -24,10 +23,15 @@ export class TokenPurchaseService extends BaseService { tran: TransactionMatch, payment: Transaction, ) { - const tokenRef = build5Db().doc(`${COL.TOKEN}/${order.payload.token}`); - const distributionRef = tokenRef.collection(SUB_COL.DISTRIBUTION).doc(order.member!); + const tokenRef = build5Db().doc(COL.TOKEN, order.payload.token!); + const distributionRef = build5Db().doc( + COL.TOKEN, + order.payload.token!, + SUB_COL.DISTRIBUTION, + order.member!, + ); - const token = await this.transactionService.get(tokenRef); + const token = await this.transaction.get(tokenRef); if (token.status !== TokenStatus.AVAILABLE) { await this.transactionService.createCredit( TransactionPayloadType.DATA_NO_LONGER_VALID, @@ -37,8 +41,7 @@ export class TokenPurchaseService extends BaseService { return; } - const distribution = - await this.transactionService.transaction.get(distributionRef); + const distribution = await this.transaction.get(distributionRef); const currentTotalDeposit = Number( bigDecimal.add(distribution?.totalDeposit || 0, tran.to.amount), ); @@ -61,19 +64,13 @@ export class TokenPurchaseService extends BaseService { tokensOrdered >= totalPublicSupply && token.autoProcessAt100Percent ? { ...tokenUpdateData, status: TokenStatus.PROCESSING } : tokenUpdateData, - action: 'update', + action: Action.U, }); this.transactionService.push({ ref: distributionRef, - data: { - uid: order.member, - totalDeposit: build5Db().inc(tran.to.amount), - parentId: order.payload.token, - parentCol: COL.TOKEN, - }, - action: 'set', - merge: true, + data: { totalDeposit: build5Db().inc(tran.to.amount) }, + action: Action.UPS, }); } } diff --git a/packages/functions/src/services/payment/token/token-service.ts b/packages/functions/src/services/payment/token/token-service.ts index 3a90be4fd3..b3495533e3 100644 --- a/packages/functions/src/services/payment/token/token-service.ts +++ b/packages/functions/src/services/payment/token/token-service.ts @@ -1,4 +1,4 @@ -import { build5Db, getSnapshot } from '@build-5/database'; +import { ITransaction, build5Db } from '@build-5/database'; import { COL, DEFAULT_NETWORK, @@ -7,8 +7,6 @@ import { SUB_COL, TRANSACTION_MAX_EXPIRY_MS, Token, - TokenDistribution, - TokenDrop, TokenDropStatus, TokenStatus, TokenTradeOrder, @@ -20,14 +18,17 @@ import { } from '@build-5/interfaces'; import dayjs from 'dayjs'; import bigDecimal from 'js-big-decimal'; -import { get, head, last, set } from 'lodash'; +import { head, set } from 'lodash'; import { dateToTimestamp } from '../../../utils/dateTime.utils'; import { getBoughtByMemberDiff, getTotalPublicSupply } from '../../../utils/token.utils'; import { getRandomEthAddress } from '../../../utils/wallet.utils'; -import { TransactionMatch, TransactionService } from '../transaction-service'; +import { Action, TransactionMatch, TransactionService } from '../transaction-service'; export class TokenService { - constructor(readonly transactionService: TransactionService) {} + private transaction: ITransaction; + constructor(readonly transactionService: TransactionService) { + this.transaction = transactionService.transaction; + } public async handleTokenPurchaseRequest(order: Transaction, match: TransactionMatch) { const payment = await this.transactionService.createPayment(order, match); @@ -50,13 +51,13 @@ export class TokenService { match: TransactionMatch, ) { const payment = await this.transactionService.createPayment(order, match); - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${order.payload.token}`); + const tokenDocRef = build5Db().doc(COL.TOKEN, order.payload.token!); const token = await tokenDocRef.get(); const tokensSent = (tranOutput.nativeTokens || []).reduce( (acc, act) => (act.id === token.mintingData?.tokenId ? acc + Number(act.amount) : acc), 0, ); - const tokensExpected = get(order, 'payload.totalAirdropCount', 0); + const tokensExpected = order.payload.totalAirdropCount || 0; if (tokensSent !== tokensExpected || (tranOutput.nativeTokens || []).length > 1) { await this.transactionService.createCredit( @@ -67,47 +68,34 @@ export class TokenService { return; } - let lastDocId = ''; - do { - const lastDoc = await getSnapshot(COL.AIRDROP, lastDocId); - const snap = await build5Db() - .collection(COL.AIRDROP) - .where('orderId', '==', order.uid) - .limit(250) - .startAfter(lastDoc) - .get(); - lastDocId = last(snap)?.uid || ''; - - const batch = build5Db().batch(); - snap.forEach((airdrop) => { - const distributionDocRef = build5Db() - .collection(COL.TOKEN) - .doc(airdrop.token) - .collection(SUB_COL.DISTRIBUTION) - .doc(airdrop.member); + const snap = await build5Db() + .collection(COL.AIRDROP) + .where('orderId', '==', order.uid) + .where('status', '==', TokenDropStatus.DEPOSIT_NEEDED) + .get(); + + for (const airdrop of snap) { + const distributionDocRef = build5Db().doc( + COL.TOKEN, + airdrop.token, + SUB_COL.DISTRIBUTION, + airdrop.member, + ); - batch.set( - distributionDocRef, - { - parentId: airdrop.token, - parentCol: COL.TOKEN, - uid: airdrop.member, - totalUnclaimedAirdrop: build5Db().inc(airdrop.count), - }, - true, - ); - const docRef = build5Db().doc(`${COL.AIRDROP}/${airdrop.uid}`); - batch.update(docRef, { status: TokenDropStatus.UNCLAIMED }); + await this.transaction.upsert(distributionDocRef, { + parentId: airdrop.token, + totalUnclaimedAirdrop: build5Db().inc(airdrop.count), }); - await batch.commit(); - } while (lastDocId); + const docRef = build5Db().doc(COL.AIRDROP, airdrop.uid); + await this.transaction.update(docRef, { status: TokenDropStatus.UNCLAIMED }); + } this.transactionService.markAsReconciled(order, match.msgId); this.transactionService.push({ - ref: build5Db().doc(`${COL.TRANSACTION}/${order.uid}`), - data: { 'payload.amount': tranOutput.amount }, - action: 'update', + ref: build5Db().doc(COL.TRANSACTION, order.uid), + data: { payload_amount: tranOutput.amount }, + action: Action.U, }); } @@ -134,7 +122,7 @@ export class TokenService { this.transactionService.markAsReconciled(order, match.msgId); await this.createDistributionDocRef(order.payload.token!, order.member!); - const token = await build5Db().doc(`${COL.TOKEN}/${order.payload.token}`).get(); + const token = await build5Db().doc(COL.TOKEN, order.payload.token!).get(); const network = order.network || DEFAULT_NETWORK; const data = { uid: getRandomEthAddress(), @@ -145,8 +133,8 @@ export class TokenService { order.payload.type === TransactionPayloadType.SELL_TOKEN ? TokenTradeOrderType.SELL : TokenTradeOrderType.BUY, - count: nativeTokens || get(order, 'payload.count', 0), - price: get(order, 'payload.price', 0), + count: nativeTokens || order.payload.count || 0, + price: order.payload.price || 0, totalDeposit: nativeTokens || order.payload.amount, balance: nativeTokens || order.payload.amount, fulfilled: 0, @@ -163,18 +151,18 @@ export class TokenService { set(data, 'targetAddress', order.payload.tokenTradeOderTargetAddress); } - const ref = build5Db().doc(`${COL.TOKEN_MARKET}/${data.uid}`); - this.transactionService.push({ ref, data, action: 'set' }); + const ref = build5Db().doc(COL.TOKEN_MARKET, data.uid); + this.transactionService.push({ ref, data, action: Action.C }); if ( order.payload.type === TransactionPayloadType.SELL_TOKEN && token.status === TokenStatus.MINTED ) { - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${order.uid}`); + const orderDocRef = build5Db().doc(COL.TRANSACTION, order.uid); this.transactionService.push({ ref: orderDocRef, - data: { 'payload.amount': match.to.amount }, - action: 'update', + data: { payload_amount: match.to.amount }, + action: Action.U, }); } } @@ -184,10 +172,15 @@ export class TokenService { tran: TransactionMatch, payment: Transaction, ) { - const tokenRef = build5Db().doc(`${COL.TOKEN}/${order.payload.token}`); - const distributionRef = tokenRef.collection(SUB_COL.DISTRIBUTION).doc(order.member!); + const tokenRef = build5Db().doc(COL.TOKEN, order.payload.token!); + const distributionRef = build5Db().doc( + COL.TOKEN, + order.payload.token!, + SUB_COL.DISTRIBUTION, + order.member!, + ); - const token = await this.transactionService.get(tokenRef); + const token = await tokenRef.get(); if (token.status !== TokenStatus.AVAILABLE) { await this.transactionService.createCredit( TransactionPayloadType.DATA_NO_LONGER_VALID, @@ -197,8 +190,7 @@ export class TokenService { return; } - const distribution = - await this.transactionService.transaction.get(distributionRef); + const distribution = await distributionRef.get(); const currentTotalDeposit = Number( bigDecimal.add(distribution?.totalDeposit || 0, tran.to.amount), ); @@ -221,39 +213,25 @@ export class TokenService { tokensOrdered >= totalPublicSupply && token.autoProcessAt100Percent ? { ...tokenUpdateData, status: TokenStatus.PROCESSING } : tokenUpdateData, - action: 'update', + action: Action.U, }); this.transactionService.push({ ref: distributionRef, data: { - uid: order.member, totalDeposit: build5Db().inc(tran.to.amount), parentId: order.payload.token, - parentCol: COL.TOKEN, }, - action: 'set', - merge: true, + action: Action.UPS, }); } private createDistributionDocRef = async (token: string, member: string) => { - const distributionDocRef = build5Db().doc( - `${COL.TOKEN}/${token}/${SUB_COL.DISTRIBUTION}/${member}`, - ); - const distributionDoc = await this.transactionService.transaction.get(distributionDocRef); + const distributionDocRef = build5Db().doc(COL.TOKEN, token, SUB_COL.DISTRIBUTION, member); + const distributionDoc = await this.transaction.get(distributionDocRef); if (!distributionDoc) { - const data = { - uid: member, - parentId: token, - parentCol: COL.TOKEN, - }; - this.transactionService.push({ - ref: distributionDocRef, - data, - action: 'set', - merge: true, - }); + const data = { uid: member, parentId: token, parentCol: COL.TOKEN }; + this.transactionService.push({ ref: distributionDocRef, data, action: Action.C }); } }; } diff --git a/packages/functions/src/services/payment/token/token-trade.service.ts b/packages/functions/src/services/payment/token/token-trade.service.ts index 3aacb40e5c..2ec1e366f2 100644 --- a/packages/functions/src/services/payment/token/token-trade.service.ts +++ b/packages/functions/src/services/payment/token/token-trade.service.ts @@ -17,10 +17,11 @@ import { getNetworkPair, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { get, head, isEqual, set } from 'lodash'; +import { head, isEqual, set } from 'lodash'; import { dateToTimestamp } from '../../../utils/dateTime.utils'; import { getRandomEthAddress } from '../../../utils/wallet.utils'; import { BaseService, HandlerParams } from '../base'; +import { Action } from '../transaction-service'; export class TokenTradeService extends BaseService { public handleRequest = async ({ @@ -49,14 +50,14 @@ export class TokenTradeService extends BaseService { const nativeTokens = Number(head(tranEntry.nativeTokens)?.amount); await this.createDistributionDocRef(order.payload.token!, order.member!); - const token = await build5Db().doc(`${COL.TOKEN}/${order.payload.token}`).get(); + const token = await build5Db().doc(COL.TOKEN, order.payload.token!).get(); const network = order.network || DEFAULT_NETWORK; const type = order.payload.type === TransactionPayloadType.SELL_TOKEN ? TokenTradeOrderType.SELL : TokenTradeOrderType.BUY; - const price = get(order, 'payload.price', 0); + const price = order.payload.price || 0; const count = getCount(order, tranEntry, type); const data: TokenTradeOrder = { @@ -84,34 +85,27 @@ export class TokenTradeService extends BaseService { set(data, 'targetAddress', order.payload.tokenTradeOderTargetAddress); } - const ref = build5Db().doc(`${COL.TOKEN_MARKET}/${data.uid}`); - this.transactionService.push({ ref, data, action: 'set' }); + const ref = build5Db().doc(COL.TOKEN_MARKET, data.uid); + this.transactionService.push({ ref, data, action: Action.C }); - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${order.uid}`); + const orderDocRef = build5Db().doc(COL.TRANSACTION, order.uid); this.transactionService.push({ ref: orderDocRef, - data: { 'payload.amount': match.to.amount, 'payload.count': count }, - action: 'update', + data: { payload_amount: match.to.amount, payload_count: count }, + action: Action.U, }); }; private createDistributionDocRef = async (token: string, member: string) => { - const distributionDocRef = build5Db().doc( - `${COL.TOKEN}/${token}/${SUB_COL.DISTRIBUTION}/${member}`, - ); - const distributionDoc = await this.transactionService.transaction.get(distributionDocRef); + const distributionDocRef = build5Db().doc(COL.TOKEN, token, SUB_COL.DISTRIBUTION, member); + const distributionDoc = await this.transaction.get(distributionDocRef); if (!distributionDoc) { const data = { uid: member, parentId: token, parentCol: COL.TOKEN, }; - this.transactionService.push({ - ref: distributionDocRef, - data, - action: 'set', - merge: true, - }); + this.transactionService.push({ ref: distributionDocRef, data, action: Action.UPS }); } }; } @@ -124,5 +118,5 @@ const getCount = ( if (type === TokenTradeOrderType.SELL) { return Number(head(tranEntry.nativeTokens)?.amount || 0) || tranEntry.amount; } - return get(order, 'payload.count', MAX_TOTAL_TOKEN_SUPPLY); + return order.payload.count || MAX_TOTAL_TOKEN_SUPPLY; }; diff --git a/packages/functions/src/services/payment/transaction-service.ts b/packages/functions/src/services/payment/transaction-service.ts index 133b3c6df4..558d9c221a 100644 --- a/packages/functions/src/services/payment/transaction-service.ts +++ b/packages/functions/src/services/payment/transaction-service.ts @@ -1,4 +1,4 @@ -import { IDocument, ITransaction, build5Db } from '@build-5/database'; +import { BaseRecord, IDocument, ITransaction, Update, build5Db } from '@build-5/database'; import { COL, DEFAULT_NETWORK, @@ -10,7 +10,6 @@ import { StorageReturn, TRANSACTION_AUTO_EXPIRY_MS, Timestamp, - Token, Transaction, TransactionPayloadType, TransactionType, @@ -24,44 +23,66 @@ import { MilestoneTransactionAdapter } from '../../triggers/milestone-transactio import { getOutputMetadata } from '../../utils/basic-output.utils'; import { getProject } from '../../utils/common.utils'; import { dateToTimestamp, serverTime } from '../../utils/dateTime.utils'; +import { logger } from '../../utils/logger'; +import { getPathParts } from '../../utils/milestone'; import { getRandomEthAddress } from '../../utils/wallet.utils'; + export interface TransactionMatch { msgId: string; from: string; to: MilestoneTransactionEntry; } -interface TransactionUpdates { - ref: IDocument; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - data: any; - action: 'update' | 'set' | 'delete'; - merge?: boolean; +export enum Action { + C = 'create', + U = 'update', + UPS = 'upsert', + D = 'delete', +} + +// prettier-ignore +type DataType = + A extends Action.C ? C : + A extends Action.U ? U : + A extends Action.UPS ? U : + A extends Action.D ? undefined : + never; + +interface TransactionUpdates { + ref: IDocument; + data: DataType; + action: A; } export class TransactionService { public readonly linkedTransactions: string[] = []; - private readonly updates: TransactionUpdates[] = []; + private readonly updates: TransactionUpdates[] = []; constructor(public readonly transaction: ITransaction) {} - public submit(): void { - this.updates.forEach((params) => { - if (params.action === 'set') { - this.transaction.set(params.ref, params.data, params.merge || false); - } else if (params.action === 'update') { - this.transaction.update(params.ref, params.data); - } else if (params.action === 'delete') { - this.transaction.delete(params.ref); - } else { - throw Error('Invalid action ' + params.action); + public submit = async () => { + const promises = this.updates.map((params) => { + switch (params.action) { + case Action.C: + return this.transaction.create(params.ref, params.data); + case Action.U: + return this.transaction.update(params.ref, params.data as Update); + case Action.UPS: + return this.transaction.upsert(params.ref, params.data as Update); + case Action.D: + return this.transaction.delete(params.ref); + default: + throw Error('Invalid action ' + params.action); } }); - } - - public push = (update: TransactionUpdates) => this.updates.push(update); + await Promise.all(promises); + }; - public get = (docRef: IDocument) => this.transaction.get(docRef); + public push = ( + update: TransactionUpdates, + ) => + // eslint-disable-next-line @typescript-eslint/no-explicit-any + this.updates.push(update as any); public async createPayment( order: Transaction, @@ -79,7 +100,6 @@ export class TransactionService { space: order.space || '', network: order.network || DEFAULT_NETWORK, payload: { - // This must be the amount they send. As we're handing both correct amount from order or invalid one. amount: tran.to.amount, nativeTokens: (tran.to.nativeTokens || []).map((nt) => ({ ...nt, @@ -107,18 +127,14 @@ export class TransactionService { } if (order.payload.token) { - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${order.payload.token}`); - const token = await tokenDocRef.get(); + const tokenDocRef = build5Db().doc(COL.TOKEN, order.payload.token); + const token = await tokenDocRef.get(); if (token) { set(data, 'payload.token', token.uid); set(data, 'payload.tokenSymbol', token.symbol); } } - this.updates.push({ - ref: build5Db().doc(`${COL.TRANSACTION}/${data.uid}`), - data, - action: 'set', - }); + this.push({ ref: build5Db().doc(COL.TRANSACTION, data.uid), data, action: Action.C }); if (order.payload.type !== TransactionPayloadType.TANGLE_REQUEST) { this.linkedTransactions.push(data.uid); } @@ -163,14 +179,10 @@ export class TransactionService { void: false, collection: order.payload.collection || null, quantity: (order.payload.quantity || null) as number, - restrictions: get(order, 'payload.restrictions', {}), + restrictions: order.payload.restrictions || {}, }, }; - this.updates.push({ - ref: build5Db().doc(`${COL.TRANSACTION}/${data.uid}`), - data, - action: 'set', - }); + this.push({ ref: build5Db().doc(COL.TRANSACTION, data.uid), data, action: Action.C }); transOut.push(data); this.linkedTransactions.push(data.uid); } @@ -196,13 +208,13 @@ export class TransactionService { nft: order.payload.nft || null, collection: order.payload.collection || null, quantity: (order.payload.quantity || null) as number, - restrictions: get(order, 'payload.restrictions', {}), + restrictions: order.payload.restrictions || {}, }, }; - this.updates.push({ - ref: build5Db().doc(`${COL.TRANSACTION}/${data.uid}`), + this.push({ + ref: build5Db().doc(COL.TRANSACTION, data.uid), data, - action: 'set', + action: Action.C, }); transOut.push(data); this.linkedTransactions.push(data.uid); @@ -261,18 +273,14 @@ export class TransactionService { } if (payment.payload.token) { - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${payment.payload.token}`); - const token = await tokenDocRef.get(); + const tokenDocRef = build5Db().doc(COL.TOKEN, payment.payload.token); + const token = await tokenDocRef.get(); if (token) { set(data, 'payload.token', token.uid); set(data, 'payload.tokenSymbol', token.symbol); } } - this.updates.push({ - ref: build5Db().doc(`${COL.TRANSACTION}/${data.uid}`), - data: data, - action: 'set', - }); + this.push({ ref: build5Db().doc(COL.TRANSACTION, data.uid), data, action: Action.C }); setLink && this.linkedTransactions.push(data.uid); return data; } @@ -309,10 +317,10 @@ export class TransactionService { }, linkedTransactions: [], }; - this.updates.push({ - ref: build5Db().doc(`${COL.TRANSACTION}/${data.uid}`), + this.push({ + ref: build5Db().doc(COL.TRANSACTION, data.uid), data: data, - action: 'set', + action: Action.C, }); return data; } @@ -331,7 +339,7 @@ export class TransactionService { ? { status: 'error', code: error.code || '', message: error.key || '', ...customErrorParams } : {}; if (!isEmpty(error) && !get(error, 'code')) { - console.error('createNftCredit-error', payment.uid, tran.to.nftOutput?.nftId, error); + logger.error('createNftCredit-error', payment.uid, tran.to.nftOutput?.nftId, error); } const transaction: Transaction = { project: getProject(payment), @@ -357,23 +365,20 @@ export class TransactionService { if (expiresOn) { set(transaction, 'payload.expiresOn', expiresOn); } - this.updates.push({ - ref: build5Db().doc(`${COL.TRANSACTION}/${transaction.uid}`), + this.push({ + ref: build5Db().doc(COL.TRANSACTION, transaction.uid), data: transaction, - action: 'set', + action: Action.C, }); this.linkedTransactions.push(transaction.uid); return transaction; } public markAsReconciled = (transaction: Transaction, chainRef: string) => - this.updates.push({ - ref: build5Db().doc(`${COL.TRANSACTION}/${transaction.uid}`), - data: { - 'payload.reconciled': true, - 'payload.chainReference': chainRef, - }, - action: 'update', + this.push({ + ref: build5Db().doc(COL.TRANSACTION, transaction.uid), + data: { payload_reconciled: true, payload_chainReference: chainRef }, + action: Action.U, }); private getFromAddress = async ( @@ -382,9 +387,10 @@ export class TransactionService { build5Transaction?: Transaction, ) => { if (build5Transaction?.type === TransactionType.UNLOCK) { - const doc = (await build5Db() - .doc(build5Transaction.payload?.milestoneTransactionPath!) - .get>())!; + const { col, colId, subCol, subColId } = getPathParts( + build5Transaction.payload?.milestoneTransactionPath!, + ); + const doc = (await build5Db().doc(col, colId, subCol, subColId).get())!; const adapter = new MilestoneTransactionAdapter(order.network!); const milestoneTransaction = await adapter.toMilestoneTransaction(doc); return milestoneTransaction.fromAddresses[0]; @@ -529,19 +535,13 @@ export class TransactionService { : tranOutput.address, sourceTransaction: [payment?.uid || order.uid], expiresOn: expiresOn || dateToTimestamp(dayjs().add(TRANSACTION_AUTO_EXPIRY_MS)), - milestoneTransactionPath: `${getMilestoneCol(network)}/${tran.milestone}/${ - SUB_COL.TRANSACTIONS - }/${tran.uid}`, + milestoneTransactionPath: `${getMilestoneCol(network)}/${tran.milestone}/${SUB_COL.TRANSACTIONS}/${tran.uid}`, outputToConsume, customMetadata: getOutputMetadata(tranOutput.output), nftId: tranOutput.nftOutput?.nftId || '', }, }; - this.updates.push({ - ref: build5Db().doc(`${COL.TRANSACTION}/${data.uid}`), - data, - action: 'set', - }); + this.push({ ref: build5Db().doc(COL.TRANSACTION, data.uid), data, action: Action.C }); }; public getExpirationUnlock = (unlockCondition: UnlockCondition[] = []) => diff --git a/packages/functions/src/services/payment/voting-service.ts b/packages/functions/src/services/payment/voting-service.ts index b62cf424da..bc6d3ae20d 100644 --- a/packages/functions/src/services/payment/voting-service.ts +++ b/packages/functions/src/services/payment/voting-service.ts @@ -8,11 +8,12 @@ import { TransactionType, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { get, head } from 'lodash'; +import { head } from 'lodash'; import { getProject } from '../../utils/common.utils'; import { getTokenForSpace } from '../../utils/token.utils'; import { getRandomEthAddress } from '../../utils/wallet.utils'; import { BaseService, HandlerParams } from './base'; +import { Action } from './transaction-service'; export class VotingService extends BaseService { public handleRequest = async ({ order, match }: HandlerParams) => { @@ -22,8 +23,8 @@ export class VotingService extends BaseService { const nativeTokens = match.to.nativeTokens || []; const hasValidToken = head(nativeTokens)?.id === token?.mintingData?.tokenId; - const proposalId = get(order, 'payload.proposalId', ''); - const values = get(order, 'payload.voteValues', []); + const proposalId = order.payload.proposalId || ''; + const values = order.payload.voteValues || []; const customData = hasValidToken ? { proposalId, values } : undefined; const storageReturn = match.to.amount >= order.payload.amount! ? match.from : undefined; @@ -47,10 +48,15 @@ export class VotingService extends BaseService { return; } - const proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${proposalId}`); + const proposalDocRef = build5Db().doc(COL.PROPOSAL, proposalId); const proposal = await proposalDocRef.get(); - const proposalMemberDocRef = proposalDocRef.collection(SUB_COL.MEMBERS).doc(order.member!); + const proposalMemberDocRef = build5Db().doc( + COL.PROPOSAL, + proposalId, + SUB_COL.MEMBERS, + order.member!, + ); const tokenAmount = Number(nativeTokens[0].amount); const weightMultiplier = getTokenVoteMultiplier(proposal, dayjs()); @@ -65,34 +71,29 @@ export class VotingService extends BaseService { values, ); + const value = values[0].toString(); this.transactionService.push({ ref: proposalMemberDocRef, data: { voted: true, - voteTransactions: build5Db().inc(1), + parentId: proposalId, tranId: voteTransaction.uid, - weightPerAnswer: { [values[0]]: build5Db().inc(weight) }, - values: build5Db().arrayUnion({ - [values[0]]: weight, - voteTransaction: voteTransaction.uid, - }), + weight, + values: { [voteTransaction.uid]: { value, weight: build5Db().inc(weight) } }, }, - action: 'set', - merge: true, + action: Action.UPS, }); - const data = { - results: { - total: build5Db().inc(weight), - voted: build5Db().inc(weight), - answers: { [`${values[0]}`]: build5Db().inc(weight) }, - }, - }; this.transactionService.push({ ref: proposalDocRef, - data, - action: 'set', - merge: true, + data: { + results: { + total: build5Db().inc(weight), + voted: build5Db().inc(weight), + answers: { [value]: build5Db().inc(weight) }, + }, + }, + action: Action.U, }); }; @@ -124,11 +125,10 @@ export class VotingService extends BaseService { linkedTransactions: [], }; - const voteTransactionDocRef = build5Db().doc(`${COL.TRANSACTION}/${voteTransaction.uid}`); this.transactionService.push({ - ref: voteTransactionDocRef, + ref: build5Db().doc(COL.TRANSACTION, voteTransaction.uid), data: voteTransaction, - action: 'set', + action: Action.C, }); return voteTransaction; }; diff --git a/packages/functions/src/services/stake.service.ts b/packages/functions/src/services/stake.service.ts index c9668286e3..ea708958b8 100644 --- a/packages/functions/src/services/stake.service.ts +++ b/packages/functions/src/services/stake.service.ts @@ -1,25 +1,28 @@ import { build5Db, ITransaction } from '@build-5/database'; import { COL, - Project, ProjectBilling, - Space, Stake, StakeType, SUB_COL, TokenDistribution, } from '@build-5/interfaces'; -import { getTokenSaleConfig } from '../utils/config.utils'; import { getProject } from '../utils/common.utils'; +import { getTokenSaleConfig } from '../utils/config.utils'; export const hasStakedTokens = async (projectId: string, member: string, type?: StakeType) => { - const project = (await build5Db().get(COL.PROJECT, projectId))!; - if (project.config?.billing !== ProjectBilling.TOKEN_BASE) { + const projectDocRef = build5Db().doc(COL.PROJECT, projectId); + const project = (await projectDocRef.get())!; + if (project.config?.billing !== ProjectBilling.TOKEN_BASED) { return true; } - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${project.config.nativeTokenUid}`); - const distributionDocRef = tokenDocRef.collection(SUB_COL.DISTRIBUTION).doc(member); - const distribution = await distributionDocRef.get(); + const distributionDocRef = build5Db().doc( + COL.TOKEN, + project.config.nativeTokenUid!, + SUB_COL.DISTRIBUTION, + member, + ); + const distribution = await distributionDocRef.get(); const stakeTypes = type ? [type] : Object.values(StakeType); const hasAny = stakeTypes.reduce( @@ -43,7 +46,7 @@ export const onStakeCreated = async (transaction: ITransaction, stake: Stake) => stake.value, ); } - updateStakingMembersStats(transaction, distribution, stake.token, stake.type, stake.value); + await updateStakingMembersStats(transaction, distribution, stake.token, stake.type, stake.value); }; export const onStakeExpired = async (transaction: ITransaction, stake: Stake) => { @@ -58,13 +61,12 @@ export const onStakeExpired = async (transaction: ITransaction, stake: Stake) => ); await removeMemberFromSpace(transaction, distribution, stake); } - updateStakingMembersStats(transaction, distribution, stake.token, stake.type, -stake.value); + await updateStakingMembersStats(transaction, distribution, stake.token, stake.type, -stake.value); }; const getTokenDistribution = async (transaction: ITransaction, token: string, member: string) => { - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${token}`); - const distirbutionDocRef = tokenDocRef.collection(SUB_COL.DISTRIBUTION).doc(member); - return await transaction.get(distirbutionDocRef); + const distirbutionDocRef = build5Db().doc(COL.TOKEN, token, SUB_COL.DISTRIBUTION, member); + return await transaction.get(distirbutionDocRef); }; const updateMemberTokenDiscountPercentage = async ( @@ -74,7 +76,8 @@ const updateMemberTokenDiscountPercentage = async ( member: string, stakeValueDiff: number, ) => { - const project = await build5Db().get(COL.PROJECT, projectId); + const projectDocRef = build5Db().doc(COL.PROJECT, projectId); + const project = await projectDocRef.get(); const stakeValue = getStakeForType(distribution, StakeType.DYNAMIC) + stakeValueDiff; const tier = getTier(project?.config?.tiers || [], stakeValue); @@ -84,8 +87,8 @@ const updateMemberTokenDiscountPercentage = async ( const discount = (project?.config?.tokenTradingFeeDiscountPercentage || [])[tier] / 100; const tokenTradingFeePercentage = getTokenSaleConfig.percentage * (1 - discount); - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${member}`); - transaction.update(memberDocRef, { tokenTradingFeePercentage }); + const memberDocRef = build5Db().doc(COL.MEMBER, member); + await transaction.update(memberDocRef, { tokenTradingFeePercentage }); }; export const getTier = (tiers: number[], stakeValue: number) => { @@ -96,32 +99,28 @@ export const getTier = (tiers: number[], stakeValue: number) => { return tier - 1; }; -const updateStakingMembersStats = ( +const updateStakingMembersStats = async ( transaction: ITransaction, distribution: TokenDistribution | undefined, token: string, type: StakeType, stakeValueDiff: number, ) => { - const tokenStatsDocRef = build5Db().doc(`${COL.TOKEN}/${token}/${SUB_COL.STATS}/${token}`); + const tokenStatsDocRef = build5Db().doc(COL.TOKEN, token, SUB_COL.STATS, token); const prevStakedAmount = getStakeForType(distribution, type); if (!prevStakedAmount) { - transaction.set( - tokenStatsDocRef, - { stakes: { [type]: { stakingMembersCount: build5Db().inc(1) } } }, - true, - ); + await transaction.upsert(tokenStatsDocRef, { + [`stakes_${type}_stakingMembersCount`]: build5Db().inc(1), + }); return; } const currentStakedAmount = prevStakedAmount + stakeValueDiff; if (!currentStakedAmount) { - transaction.set( - tokenStatsDocRef, - { stakes: { [type]: { stakingMembersCount: build5Db().inc(-1) } } }, - true, - ); + await transaction.upsert(tokenStatsDocRef, { + [`stakes_${type}_stakingMembersCount`]: build5Db().inc(-1), + }); return; } }; @@ -131,23 +130,23 @@ const removeMemberFromSpace = async ( distribution: TokenDistribution | undefined, stake: Stake, ) => { - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${stake.space}`); - const space = (await spaceDocRef.get())!; + const spaceDocRef = build5Db().doc(COL.SPACE, stake.space); + const space = (await spaceDocRef.get())!; const stakedValue = getStakeForType(distribution, stake.type) - stake.value; if (!space.tokenBased || stakedValue >= (space.minStakedValue || 0)) { return; } - const guardianDocRef = spaceDocRef.collection(SUB_COL.GUARDIANS).doc(stake.member); + const guardianDocRef = build5Db().doc(COL.SPACE, stake.space, SUB_COL.GUARDIANS, stake.member); const isGuardian = (await spaceDocRef.get()) !== undefined; if (isGuardian && space.totalGuardians > 1) { - transaction.delete(guardianDocRef); + await transaction.delete(guardianDocRef); } if (space.totalMembers > 1) { - const memberDocRef = spaceDocRef.collection(SUB_COL.MEMBERS).doc(stake.member); - transaction.delete(memberDocRef); + const memberDocRef = build5Db().doc(COL.SPACE, stake.space, SUB_COL.MEMBERS, stake.member); + await transaction.delete(memberDocRef); } - transaction.update(spaceDocRef, { + await transaction.update(spaceDocRef, { totalGuardians: build5Db().inc(isGuardian && space.totalGuardians > 1 ? -1 : 0), totalMembers: build5Db().inc(space.totalMembers > 1 ? -1 : 0), }); diff --git a/packages/functions/src/services/validators/access.ts b/packages/functions/src/services/validators/access.ts index a310b1f533..14c65a0b18 100644 --- a/packages/functions/src/services/validators/access.ts +++ b/packages/functions/src/services/validators/access.ts @@ -1,5 +1,5 @@ import { build5Db } from '@build-5/database'; -import { Access, COL, Nft, SUB_COL, TransactionPayloadType, WenError } from '@build-5/interfaces'; +import { Access, COL, SUB_COL, TransactionPayloadType, WenError } from '@build-5/interfaces'; import { invalidArgument } from '../../utils/error.utils'; export const assertHasAccess = async ( @@ -14,13 +14,13 @@ export const assertHasAccess = async ( } if (access === Access.MEMBERS_ONLY) { - if (!(await build5Db().doc(`${COL.SPACE}/${spaceId}/${SUB_COL.MEMBERS}/${member}`).get())) { + if (!(await build5Db().doc(COL.SPACE, spaceId, SUB_COL.MEMBERS, member).get())) { throw invalidArgument(WenError.you_are_not_part_of_space); } } if (access === Access.GUARDIANS_ONLY) { - if (!(await build5Db().doc(`${COL.SPACE}/${spaceId}/${SUB_COL.GUARDIANS}/${member}`).get())) { + if (!(await build5Db().doc(COL.SPACE, spaceId, SUB_COL.GUARDIANS, member).get())) { throw invalidArgument(WenError.you_are_not_guardian_of_space); } } @@ -29,9 +29,9 @@ export const assertHasAccess = async ( for (const award of accessAwards) { const snapshot = await build5Db() .collection(COL.TRANSACTION) - .where('payload.type', '==', TransactionPayloadType.BADGE) + .where('payload_type', '==', TransactionPayloadType.BADGE) .where('member', '==', member) - .where('payload.award', '==', award) + .where('payload_award', '==', award) .limit(1) .get(); if (!snapshot.length) { @@ -42,7 +42,7 @@ export const assertHasAccess = async ( if (access === Access.MEMBERS_WITH_NFT_FROM_COLLECTION) { const includedCollections: string[] = []; - const snapshot = await build5Db().collection(COL.NFT).where('owner', '==', member).get(); + const snapshot = await build5Db().collection(COL.NFT).where('owner', '==', member).get(); if (snapshot.length > 0 && accessCollections?.length) { for (const data of snapshot) { if ( diff --git a/packages/functions/src/services/wallet/NativeTokenWallet.ts b/packages/functions/src/services/wallet/NativeTokenWallet.ts index f2bafdf382..753caa14ff 100644 --- a/packages/functions/src/services/wallet/NativeTokenWallet.ts +++ b/packages/functions/src/services/wallet/NativeTokenWallet.ts @@ -1,5 +1,5 @@ import { build5Db } from '@build-5/database'; -import { COL, Member, Token, Transaction } from '@build-5/interfaces'; +import { COL, Member, SUB_COL, Token, Transaction } from '@build-5/interfaces'; import { AliasOutputBuilderParams, Client, @@ -18,8 +18,6 @@ import { getVaultAndGuardianOutput, tokenToFoundryMetadata, } from '../../utils/token-minting-utils/foundry.utils'; -import { getOwnedTokenTotal } from '../../utils/token-minting-utils/member.utils'; -import { getUnclaimedAirdropTotalValue } from '../../utils/token.utils'; import { AliasWallet } from './AliasWallet'; import { MnemonicService } from './mnemonic'; import { Wallet, WalletParams } from './wallet'; @@ -53,7 +51,7 @@ export class NativeTokenWallet { nextAliasOutput.stateIndex!++; nextAliasOutput.foundryCounter!++; - const token = await build5Db().doc(`${COL.TOKEN}/${transaction.payload.token}`).get(); + const token = await build5Db().doc(COL.TOKEN, transaction.payload.token!).get(); const metadata = await tokenToFoundryMetadata(token); const foundryOutput = await createFoundryOutput( @@ -63,9 +61,15 @@ export class NativeTokenWallet { JSON.stringify(metadata), ); - const totalDistributed = - (await getOwnedTokenTotal(token.uid)) + (await getUnclaimedAirdropTotalValue(token.uid)); - const member = await build5Db().doc(`${COL.MEMBER}/${transaction.member}`).get(); + const totalOwned = await build5Db() + .collection(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION) + .getTotalOwned(); + const airdropTotal = await build5Db() + .collection(COL.AIRDROP) + .getUnclaimedAirdropTotalValue(token.uid); + const totalDistributed = totalOwned + airdropTotal; + + const member = await build5Db().doc(COL.MEMBER, transaction.member!).get(); const tokenId = Utils.computeFoundryId( nextAliasOutput.aliasId, foundryOutput.serialNumber, diff --git a/packages/functions/src/services/wallet/NftWallet.ts b/packages/functions/src/services/wallet/NftWallet.ts index c69d56f389..a90036d331 100644 --- a/packages/functions/src/services/wallet/NftWallet.ts +++ b/packages/functions/src/services/wallet/NftWallet.ts @@ -48,6 +48,7 @@ import { createNftOutput, nftToMetadata, } from '../../utils/collection-minting-utils/nft.utils'; +import { logger } from '../../utils/logger'; import { EMPTY_ALIAS_ID } from '../../utils/token-minting-utils/alias.utils'; import { awardBadgeToNttMetadata, awardToCollectionMetadata } from '../payment/award/award-service'; import { stampToNftMetadata } from '../payment/tangle-service/stamp/StampTangleService'; @@ -105,7 +106,7 @@ export class NftWallet { } nextAliasOutput.stateIndex!++; - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${transaction.payload.collection}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, transaction.payload.collection!); const collection = await collectionDocRef.get(); const collectionMetadata = await this.getCollectionMetadata(transaction.network!, collection); @@ -154,10 +155,8 @@ export class NftWallet { if (collection.type === CollectionType.METADATA) { return { immutableMetadata: '', mutableMetadata: '' }; } - const royaltySpaceDocRef = build5Db().doc( - `${COL.SPACE}/${collection.royaltiesSpace || undefined}`, - ); - const royaltySpace = await royaltySpaceDocRef.get(); + const royaltySpaceDocRef = build5Db().doc(COL.SPACE, collection.royaltiesSpace || ''); + const royaltySpace = await royaltySpaceDocRef.get(); const royaltySpaceAddress = getAddress(royaltySpace, network); const collectionMetadata = await collectionToMetadata(collection, royaltySpaceAddress); return { immutableMetadata: JSON.stringify(collectionMetadata), mutableMetadata: '' }; @@ -184,11 +183,11 @@ export class NftWallet { nextAliasOutput.aliasId = Utils.computeAliasId(aliasOutputId); nextAliasOutput.stateIndex!++; - const awardDocRef = build5Db().doc(`${COL.AWARD}/${transaction.payload.award}`); + const awardDocRef = build5Db().doc(COL.AWARD, transaction.payload.award!); const award = await awardDocRef.get(); const issuerAddress = new AliasAddress(Utils.computeAliasId(aliasOutputId)); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${award.space}`); + const spaceDocRef = build5Db().doc(COL.SPACE, award.space); const space = await spaceDocRef.get(); const metadata = await awardToCollectionMetadata(award, space); const collectionOutput = await createNftOutput( @@ -250,12 +249,10 @@ export class NftWallet { : collectionOutput.nftId; const collection = ( - await build5Db().doc(`${COL.COLLECTION}/${transaction.payload.collection}`).get() - ); - const royaltySpaceDocRef = build5Db().doc( - `${COL.SPACE}/${collection.royaltiesSpace || undefined}`, + await build5Db().doc(COL.COLLECTION, transaction.payload.collection!).get() ); - const royaltySpace = await royaltySpaceDocRef.get(); + const royaltySpaceDocRef = build5Db().doc(COL.SPACE, collection.royaltiesSpace || ''); + const royaltySpace = await royaltySpaceDocRef.get(); const royaltySpaceAddress = getAddress(royaltySpace, transaction.network!); const nfts = await getPreMintedNfts(transaction.payload.collection as string); @@ -293,17 +290,17 @@ export class NftWallet { ); blockId = await submitBlock(this.wallet, essence, unlocks); const batch = build5Db().batch(); - nftOutputsToMint.forEach((output, i) => { - batch.update(build5Db().doc(`${COL.NFT}/${nfts[i].uid}`), { - 'mintingData.address': nftMintAddresses[i].bech32, - 'mintingData.storageDeposit': Number(output.amount), + for (let i = 0; i < nftOutputsToMint.length; ++i) { + batch.update(build5Db().doc(COL.NFT, nfts[i].uid), { + mintingData_address: nftMintAddresses[i].bech32, + mintingData_storageDeposit: Number(nftOutputsToMint[i].amount), }); - }); + } - const transactionDocRef = build5Db().doc(`${COL.TRANSACTION}/${transaction.uid}`); + const transactionDocRef = build5Db().doc(COL.TRANSACTION, transaction.uid); batch.update(transactionDocRef, { - 'payload.amount': nftOutputsToMint.reduce((acc, act) => acc + Number(act.amount), 0), - 'payload.nfts': nfts.slice(0, nftsToMint).map((nft) => nft.uid), + payload_amount: nftOutputsToMint.reduce((acc, act) => acc + Number(act.amount), 0), + payload_nfts: nfts.slice(0, nftsToMint).map((nft) => nft.uid), }); await batch.commit(); @@ -316,7 +313,7 @@ export class NftWallet { if (!nftsToMint) { await unclockMnemonic(sourceAddress.bech32); - console.error('nft mint error', 'Nft data to big to mint', head(nfts)); + logger.error('nft mint error', 'Nft data to big to mint', head(nfts)); throw Error('Nft data to big to mint'); } return blockId; @@ -354,7 +351,7 @@ export class NftWallet { ? Utils.computeNftId(collectionOutputId) : collectionOutput.nftId; - const awardDocRef = build5Db().doc(`${COL.AWARD}/${transaction.payload.award}`); + const awardDocRef = build5Db().doc(COL.AWARD, transaction.payload.award!); const award = await awardDocRef.get(); const issuerAddress = new NftAddress(collectionNftId); @@ -365,7 +362,7 @@ export class NftWallet { collectionNftId, transaction.uid, dayjs(get(transaction, 'payload.participatedOn')!.toDate()), - get(transaction, 'payload.edition', 0), + transaction.payload.edition || 0, ); const ntt = await createNftOutput( this.wallet, @@ -439,9 +436,7 @@ export class NftWallet { nextCollectionOutput.nftId = Utils.computeNftId(collectionOutputId); } - const order = await build5Db() - .doc(`${COL.TRANSACTION}/${transaction.payload.orderId}`) - .get(); + const order = await build5Db().doc(COL.TRANSACTION, transaction.payload.orderId!).get(); const issuerAddress = new NftAddress(transaction.payload.collectionId!); const ownerAddress = Utils.parseBech32Address(transaction.payload.targetAddress!); const mutableMetadata = JSON.stringify(get(order, 'payload.metadata', {})); @@ -519,7 +514,7 @@ export class NftWallet { } nextAliasOutput.stateIndex!++; - const stampDocRef = build5Db().doc(`${COL.STAMP}/${transaction.payload.stamp}`); + const stampDocRef = build5Db().doc(COL.STAMP, transaction.payload.stamp!); const stamp = await stampDocRef.get(); const issuerAddress = new AliasAddress(nextAliasOutput.aliasId); @@ -592,7 +587,7 @@ export class NftWallet { const collectionOutputId = await this.client.nftOutputId(transaction.payload.collectionId!); const collectionOutput = (await this.client.getOutput(collectionOutputId)).output as NftOutput; - const nft = await build5Db().doc(`${COL.NFT}/${transaction.payload.nft}`).get(); + const nft = await build5Db().doc(COL.NFT, transaction.payload.nft!).get(); const nftOwnerAddressBech = nft.mintingData?.address || nft.depositData?.address!; const nftOwnerAddress = await this.wallet.getAddressDetails(nftOwnerAddressBech); const nftOutputId = await this.client.nftOutputId(nft.mintingData?.nftId!); @@ -614,9 +609,7 @@ export class NftWallet { nextCollectionOutput.nftId = Utils.computeNftId(collectionOutputId); } - const order = await build5Db() - .doc(`${COL.TRANSACTION}/${transaction.payload.orderId}`) - .get(); + const order = await build5Db().doc(COL.TRANSACTION, transaction.payload.orderId!).get(); const mutableMetadata = JSON.stringify(get(order, 'payload.metadata', {})); const nextNftOutput: NftOutputBuilderParams = cloneDeep(nftOutput); if (nextNftOutput.nftId === EMPTY_NFT_ID) { @@ -858,4 +851,4 @@ const getPreMintedNfts = (collection: string, limit = 100) => .where('status', '==', NftStatus.PRE_MINTED) .where('placeholderNft', '==', false) .limit(limit) - .get(); + .get(); diff --git a/packages/functions/src/services/wallet/mnemonic.ts b/packages/functions/src/services/wallet/mnemonic.ts index 1fe0b74a47..a43a136da8 100644 --- a/packages/functions/src/services/wallet/mnemonic.ts +++ b/packages/functions/src/services/wallet/mnemonic.ts @@ -1,5 +1,5 @@ import { build5Db } from '@build-5/database'; -import { COL, DEFAULT_NETWORK, Mnemonic, NetworkAddress } from '@build-5/interfaces'; +import { COL, DEFAULT_NETWORK, Mnemonic, Network, NetworkAddress } from '@build-5/interfaces'; import { AES, enc } from 'crypto-js'; export class MnemonicService { @@ -11,9 +11,12 @@ export class MnemonicService { await build5Db() .collection(COL.MNEMONIC) .doc(address) - .set({ + .upsert({ mnemonic: AES.encrypt(mnemonic, process.env.ENCRYPTION_SALT || '').toString(), - network, + network: network as Network, + consumedOutputIds: [], + consumedNftOutputIds: [], + consumedAliasOutputIds: [], }); } @@ -24,8 +27,9 @@ export class MnemonicService { public static async getData(address: NetworkAddress | undefined): Promise { if (!address) { - return {}; + return {} as Mnemonic; } - return (await build5Db().collection(COL.MNEMONIC).doc(address).get()) || {}; + const docRef = build5Db().doc(COL.MNEMONIC, address); + return (await docRef.get()) || ({} as Mnemonic); } } diff --git a/packages/functions/src/services/wallet/wallet.service.ts b/packages/functions/src/services/wallet/wallet.service.ts index 709be20eb0..4752ae4d16 100644 --- a/packages/functions/src/services/wallet/wallet.service.ts +++ b/packages/functions/src/services/wallet/wallet.service.ts @@ -2,6 +2,7 @@ import { build5Db } from '@build-5/database'; import { COL, DEFAULT_NETWORK, Network } from '@build-5/interfaces'; import { Client } from '@iota/sdk'; import { getRandomIndex } from '../../utils/common.utils'; +import { logger } from '../../utils/logger'; import { IotaWallet } from './IotaWalletService'; import { SmrWallet } from './SmrWalletService'; import { Wallet } from './wallet'; @@ -24,23 +25,28 @@ const NODES = { [Network.ATOI]: ['https://rms1.svrs.io/'], }; +export const tangleClients: { [key: string]: Client } = {}; + const getClient = async (network: Network, nodeIndexToExclude?: number) => { let nodeUrl = ''; for (let i = 0; i < 5; ++i) { const nodeIndex = getRandomIndex(NODES[network], nodeIndexToExclude); nodeUrl = NODES[network][nodeIndex]; try { - const client = new Client({ nodes: [nodeUrl] }); + const client = tangleClients[nodeUrl] || new Client({ nodes: [nodeUrl] }); const info = await client.getInfo(); if (info.nodeInfo.status.isHealthy) { + if (!tangleClients[nodeUrl]) { + tangleClients[nodeUrl] = client; + } return { client, info: info.nodeInfo, nodeIndex, nodeUrl }; } } catch (error) { - console.warn(`Could not connect to client error, ${network}`, nodeUrl, error); + logger.warn(`Could not connect to client error, ${network}`, nodeUrl, error); } await new Promise((resolve) => setTimeout(resolve, Math.floor(Math.random() * 1000 + 500))); } - console.error(`Could not connect to client error ${network}`, nodeUrl); + logger.error(`Could not connect to client error ${network}`, nodeUrl); throw Error(`Could not connect to any client ${network}`); }; @@ -64,5 +70,5 @@ export const setConsumedOutputIds = ( consumedAliasOutputIds: string[] = [], ) => build5Db() - .doc(`${COL.MNEMONIC}/${address}`) + .doc(COL.MNEMONIC, address) .update({ consumedOutputIds, consumedNftOutputIds, consumedAliasOutputIds }); diff --git a/packages/functions/src/triggers/algolia/algolia.trigger.ts b/packages/functions/src/triggers/algolia/algolia.trigger.ts index 8a8bd9ba96..6e97f66651 100644 --- a/packages/functions/src/triggers/algolia/algolia.trigger.ts +++ b/packages/functions/src/triggers/algolia/algolia.trigger.ts @@ -1,28 +1,30 @@ +import { BaseRecord } from '@build-5/database'; import { COL, SOON_PROJECT_ID } from '@build-5/interfaces'; import algoliasearch from 'algoliasearch'; import { algoliaAppId, algoliaKey } from '../../utils/config.utils'; -import { FirestoreDocEvent } from '../common'; -import { docToAlgoliaData } from './firestore.to.algolia'; +import { logger } from '../../utils/logger'; +import { PgDocEvent } from '../common'; + const client = algoliasearch(algoliaAppId(), algoliaKey()); const deleteObject = async (col: COL, objectID: string) => { try { await client.initIndex(col).deleteObject(objectID); } catch (error) { - console.error('deleteObject-error', col, objectID, error); + logger.error('deleteObject-error', col, objectID, error); } }; -const upsertObject = async (rawData: Record, col: COL, objectID: string) => { - const data = docToAlgoliaData({ ...rawData, objectID, id: objectID }); +const upsertObject = async (rawData: BaseRecord, col: COL, objectID: string) => { + const data = docToAlgoliaData({ ...rawData, objectID, id: objectID } as BaseRecord); try { await client.initIndex(col).saveObject(data).wait(); } catch (error) { - console.error('upsertObject-error', col, objectID, error); + logger.error('upsertObject-error', col, objectID, error); } }; -export const algoliaTrigger = async (event: FirestoreDocEvent>) => { +export const algoliaTrigger = async (event: PgDocEvent) => { const { prev, curr, col } = event; if (col !== COL.MEMBER && curr?.project !== SOON_PROJECT_ID) { @@ -41,3 +43,26 @@ export const algoliaTrigger = async (event: FirestoreDocEvent processObject(data); + +const processObject = (data: BaseRecord) => + Object.entries(data).reduce((acc, [key, val]) => { + const value = processValue(val); + return isValid(value) ? { ...acc, [key]: value } : acc; + }, {} as BaseRecord); + +const processValue = (value: unknown): unknown => { + if (value instanceof Date) { + return value.getTime(); + } + if (value instanceof Array) { + return value.map(processValue); + } + if (value instanceof Object) { + return processObject({ ...value } as BaseRecord); + } + return value; +}; + +const isValid = (value: unknown) => typeof value !== 'undefined' && value !== null; diff --git a/packages/functions/src/triggers/algolia/firestore.to.algolia.ts b/packages/functions/src/triggers/algolia/firestore.to.algolia.ts deleted file mode 100644 index 1401c41f0c..0000000000 --- a/packages/functions/src/triggers/algolia/firestore.to.algolia.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { firestore } from 'firebase-admin'; - -export const docToAlgoliaData = (data: Record) => processObject(data); - -const processObject = (data: Record) => - Object.entries(data).reduce( - (acc, [key, val]) => { - const value = processValue(val); - return isValid(value) ? { ...acc, [key]: value } : acc; - }, - {} as Record, - ); - -const processValue = (value: unknown): unknown => { - if (value instanceof firestore.Timestamp) { - return value.toDate().getTime(); - } - if (value instanceof Array) { - return value.map(processValue); - } - if (value instanceof Object) { - return processObject({ ...value }); - } - return value; -}; - -const isValid = (value: unknown) => typeof value !== 'undefined' && value !== null; diff --git a/packages/functions/src/triggers/award.trigger.ts b/packages/functions/src/triggers/award.trigger.ts index 0c7b49b378..766107cce4 100644 --- a/packages/functions/src/triggers/award.trigger.ts +++ b/packages/functions/src/triggers/award.trigger.ts @@ -1,9 +1,8 @@ -import { build5Db } from '@build-5/database'; +import { PgAward, build5Db } from '@build-5/database'; import { - Award, AwardBadgeType, COL, - Token, + Network, Transaction, TransactionPayloadType, TransactionType, @@ -11,9 +10,9 @@ import { import { head } from 'lodash'; import { getProject } from '../utils/common.utils'; import { getRandomEthAddress } from '../utils/wallet.utils'; -import { FirestoreDocEvent } from './common'; +import { PgDocEvent } from './common'; -export const onAwardUpdated = async (event: FirestoreDocEvent) => { +export const onAwardUpdated = async (event: PgDocEvent) => { const { prev, curr } = event; if (!prev || !curr || !curr.funded) { return; @@ -26,13 +25,13 @@ export const onAwardUpdated = async (event: FirestoreDocEvent) => { ) { const targetAddress = await getReturnAddress(curr); - const burnAlias = { + const burnAlias: Transaction = { project: getProject(curr), type: TransactionType.AWARD, uid: getRandomEthAddress(), space: curr.space, member: curr.fundedBy, - network: curr.network, + network: curr.network as Network, payload: { type: TransactionPayloadType.BURN_ALIAS, sourceAddress: curr.address, @@ -42,22 +41,22 @@ export const onAwardUpdated = async (event: FirestoreDocEvent) => { award: curr.uid, }, }; - await build5Db().doc(`${COL.TRANSACTION}/${burnAlias.uid}`).create(burnAlias); + await build5Db().doc(COL.TRANSACTION, burnAlias.uid).create(burnAlias); - const remainingBadges = curr.badge.total - curr.issued; - if (curr.badge.type === AwardBadgeType.BASE && remainingBadges) { - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${curr.badge.tokenUid}`); - const token = (await tokenDocRef.get())!; - const baseTokenCredit = { + const remainingBadges = curr.badge_total! - curr.issued!; + if (curr.badge_type === AwardBadgeType.BASE && remainingBadges) { + const tokenDocRef = build5Db().doc(COL.TOKEN, curr.badge_tokenUid!); + const token = (await tokenDocRef.get())!; + const baseTokenCredit: Transaction = { project: getProject(curr), type: TransactionType.CREDIT, uid: getRandomEthAddress(), space: curr.space, member: curr.fundedBy, - network: curr.network, + network: curr.network as Network, payload: { type: TransactionPayloadType.AWARD_COMPLETED, - amount: remainingBadges * curr.badge.tokenReward, + amount: remainingBadges * curr.badge_tokenReward!, sourceAddress: curr.address, targetAddress, reconciled: false, @@ -67,21 +66,21 @@ export const onAwardUpdated = async (event: FirestoreDocEvent) => { tokenSymbol: token.symbol, }, }; - await build5Db().doc(`${COL.TRANSACTION}/${baseTokenCredit.uid}`).create(baseTokenCredit); + await build5Db().doc(COL.TRANSACTION, baseTokenCredit.uid).create(baseTokenCredit); } } if ( - curr.badge.type === AwardBadgeType.NATIVE && + curr.badge_type === AwardBadgeType.NATIVE && (prev.completed !== curr.completed || prev.airdropClaimed !== curr.airdropClaimed) && curr.completed && curr.airdropClaimed === curr.issued ) { const targetAddress = await getReturnAddress(curr); - const remainingBadges = curr.badge.total - curr.issued; + const remainingBadges = curr.badge_total! - curr.issued!; - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${curr.badge.tokenUid}`); - const token = (await tokenDocRef.get())!; + const tokenDocRef = build5Db().doc(COL.TOKEN, curr.badge_tokenUid!); + const token = (await tokenDocRef.get())!; const nativeTokensCredit: Transaction = { project: getProject(curr), @@ -89,15 +88,15 @@ export const onAwardUpdated = async (event: FirestoreDocEvent) => { uid: getRandomEthAddress(), space: curr.space, member: curr.fundedBy, - network: curr.network, + network: curr.network as Network, payload: { type: TransactionPayloadType.AWARD_COMPLETED, amount: curr.nativeTokenStorageDeposit, nativeTokens: remainingBadges ? [ { - id: curr.badge.tokenId!, - amount: BigInt(remainingBadges * curr.badge.tokenReward), + id: curr.badge_tokenId!, + amount: BigInt(remainingBadges * curr.badge_tokenReward!), }, ] : [], @@ -110,20 +109,20 @@ export const onAwardUpdated = async (event: FirestoreDocEvent) => { tokenSymbol: token.symbol, }, }; - await build5Db().doc(`${COL.TRANSACTION}/${nativeTokensCredit.uid}`).create(nativeTokensCredit); + await build5Db().doc(COL.TRANSACTION, nativeTokensCredit.uid).create(nativeTokensCredit); } }; -const getReturnAddress = async (award: Award) => { +const getReturnAddress = async (award: PgAward) => { if (award.fundingAddress) { return award.fundingAddress; } const snap = await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.PAYMENT) - .where('payload.targetAddress', '==', award.address) - .where('payload.invalidPayment', '==', false) + .where('payload_targetAddress', '==', award.address) + .where('payload_invalidPayment', '==', false) .limit(1) - .get(); + .get(); return head(snap)?.payload.sourceAddress || ''; }; diff --git a/packages/functions/src/triggers/collection.stats.trigger.ts b/packages/functions/src/triggers/collection.stats.trigger.ts index 580d654072..835f0c90a1 100644 --- a/packages/functions/src/triggers/collection.stats.trigger.ts +++ b/packages/functions/src/triggers/collection.stats.trigger.ts @@ -1,35 +1,28 @@ -import { build5Db } from '@build-5/database'; -import { COL, CollectionStats } from '@build-5/interfaces'; +import { PgCollectionStats, build5Db } from '@build-5/database'; +import { COL } from '@build-5/interfaces'; import { getRankingThreshold } from '../utils/config.utils'; -import { FirestoreDocEvent } from './common'; +import { PgDocEvent } from './common'; -export const onCollectionStatsWrite = async (event: FirestoreDocEvent) => { +export const onCollectionStatsWrite = async (event: PgDocEvent) => { const { prev, curr } = event; if (!curr) { return; } if (rankingThresholdReached(prev, curr)) { - await onRankingThresholdReached(event.docId); + await build5Db().doc(COL.COLLECTION, event.uid).update({ approved: false, rejected: true }); } }; const rankingThresholdReached = ( - prev: CollectionStats | undefined, - curr: CollectionStats | undefined, + prev: PgCollectionStats | undefined, + curr: PgCollectionStats | undefined, ) => { const rankingThreshold = getRankingThreshold(); return ( - prev?.ranks && - curr?.ranks && - curr.ranks.sum < rankingThreshold && - prev.ranks.sum >= rankingThreshold + prev?.ranks_sum && + curr?.ranks_sum && + curr.ranks_sum < rankingThreshold && + prev.ranks_sum >= rankingThreshold ); }; - -const onRankingThresholdReached = async (collectionId: string) => { - await build5Db().doc(`${COL.COLLECTION}/${collectionId}`).update({ - approved: false, - rejected: true, - }); -}; diff --git a/packages/functions/src/triggers/collection.trigger.ts b/packages/functions/src/triggers/collection.trigger.ts index e4c781bd8e..5d5600dbf2 100644 --- a/packages/functions/src/triggers/collection.trigger.ts +++ b/packages/functions/src/triggers/collection.trigger.ts @@ -1,11 +1,10 @@ -import { build5Db, getSnapshot } from '@build-5/database'; +import { PgCollection, PgNftUpdate, build5Db } from '@build-5/database'; import { COL, - Collection, CollectionStatus, DEFAULT_NETWORK, MediaStatus, - Member, + Network, Nft, Transaction, TransactionPayloadType, @@ -16,24 +15,25 @@ import { last } from 'lodash'; import { getAddress } from '../utils/address.utils'; import { collectionToIpfsMetadata, downloadMediaAndPackCar } from '../utils/car.utils'; import { getProject } from '../utils/common.utils'; +import { logger } from '../utils/logger'; import { getRandomEthAddress } from '../utils/wallet.utils'; -import { FirestoreDocEvent } from './common'; +import { PgDocEvent } from './common'; -export const onCollectionUpdated = async (event: FirestoreDocEvent) => { +export const onCollectionUpdated = async (event: PgDocEvent) => { const { prev, curr } = event; if (!prev || !curr) { return; } try { if (prev && (curr.approved !== prev.approved || curr.rejected !== prev.rejected)) { - return await updateNftApprovalState(curr.uid); + return await updateNftApprovalState(curr.uid, curr.approved || false, curr.rejected || false); } if (curr.placeholderNft && prev.availableNfts !== curr.availableNfts) { return await hidePlaceholderNft(curr); } - if (prev.mintingData?.nftsToMint !== 0 && curr.mintingData?.nftsToMint === 0) { + if (prev.mintingData_nftsToMint !== 0 && curr.mintingData_nftsToMint === 0) { return await onCollectionMinted(curr); } @@ -42,101 +42,78 @@ export const onCollectionUpdated = async (event: FirestoreDocEvent) } if ( curr.status === CollectionStatus.MINTING && - prev.mintingData?.nftMediaToPrepare && - curr.mintingData?.nftMediaToPrepare === 0 + prev.mintingData_nftMediaToPrepare && + curr.mintingData_nftMediaToPrepare === 0 ) { return await onNftMediaPrepared(curr); } } catch (error) { - console.error('onCollectionUpdated-error', curr.uid, error); + logger.error('onCollectionUpdated-error', curr.uid, error); } }; -const updateNftApprovalState = async (collectionId: string) => { - let lastDocId = ''; - do { - const lastDoc = await getSnapshot(COL.NFT, lastDocId); - const snap = await build5Db() - .collection(COL.NFT) - .where('collection', '==', collectionId) - .startAfter(lastDoc) - .limit(500) - .get(); - lastDocId = last(snap)?.uid || ''; - - await build5Db().runTransaction(async (transaction) => { - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${collectionId}`); - const collection = await transaction.get(collectionDocRef); - - snap.forEach((nft) => { - const nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); - transaction.update(nftDocRef, { - approved: collection?.approved || false, - rejected: collection?.rejected || false, - }); - }); - }); - } while (lastDocId); -}; +const updateNftApprovalState = (collectionId: string, approved: boolean, rejected: boolean) => + build5Db().collection(COL.NFT).update({ approved, rejected }, { collection: collectionId }); -const hidePlaceholderNft = async (collection: Collection) => { - const nftDocRef = build5Db().doc(`${COL.NFT}/${collection.placeholderNft}`); +const hidePlaceholderNft = async (collection: PgCollection) => { + const nftDocRef = build5Db().doc(COL.NFT, collection.placeholderNft!); await nftDocRef.update({ hidden: collection.availableNfts === 0 }); }; -const onCollectionMinted = async (collection: Collection) => { +const onCollectionMinted = async (collection: PgCollection) => { + const network = collection.mintingData_network as Network; if (collection.limitedEdition) { const order: Transaction = { project: getProject(collection), type: TransactionType.MINT_COLLECTION, uid: getRandomEthAddress(), - member: collection.mintingData?.mintedBy, + member: collection.mintingData_mintedBy, space: collection.space, - network: collection.mintingData?.network!, + network, payload: { type: TransactionPayloadType.LOCK_COLLECTION, amount: 0, - sourceAddress: collection.mintingData?.address, + sourceAddress: collection.mintingData_address, collection: collection.uid, - aliasStorageDeposit: collection.mintingData?.aliasStorageDeposit || 0, + aliasStorageDeposit: collection.mintingData_aliasStorageDeposit || 0, }, }; - await build5Db().doc(`${COL.TRANSACTION}/${order.uid}`).create(order); + await build5Db().doc(COL.TRANSACTION, order.uid).create(order); return; } - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${collection.mintingData?.mintedBy}`); - const member = (await memberDocRef.get())!; + const memberDocRef = build5Db().doc(COL.MEMBER, collection.mintingData_mintedBy!); + const member = (await memberDocRef.get())!; const order: Transaction = { project: getProject(collection), type: TransactionType.MINT_COLLECTION, uid: getRandomEthAddress(), - member: collection.mintingData?.mintedBy, + member: collection.mintingData_mintedBy, space: collection.space, - network: collection.mintingData?.network!, + network, payload: { type: TransactionPayloadType.SEND_ALIAS_TO_GUARDIAN, - amount: collection.mintingData?.aliasStorageDeposit, - sourceAddress: collection.mintingData?.address, - targetAddress: getAddress(member, collection.mintingData?.network!), + amount: collection.mintingData_aliasStorageDeposit, + sourceAddress: collection.mintingData_address, + targetAddress: getAddress(member, network), collection: collection.uid, lockCollectionNft: collection.limitedEdition || false, }, }; - await build5Db().doc(`${COL.TRANSACTION}/${order.uid}`).create(order); + await build5Db().doc(COL.TRANSACTION, order.uid).create(order); }; -const onCollectionMinting = async (collection: Collection) => { - await build5Db().doc(`${COL.COLLECTION}/${collection.uid}`).update({ - 'mintingData.nftsToMint': build5Db().deleteField(), - 'mintingData.nftMediaToUpload': build5Db().deleteField(), - 'mintingData.nftMediaToPrepare': build5Db().deleteField(), +const onCollectionMinting = async (collection: PgCollection) => { + await build5Db().doc(COL.COLLECTION, collection.uid).update({ + mintingData_nftsToMint: null, + mintingData_nftMediaToUpload: null, + mintingData_nftMediaToPrepare: null, }); const metadata = collectionToIpfsMetadata(collection); - const ipfs = await downloadMediaAndPackCar(collection.uid, collection.bannerUrl, metadata); + const ipfs = await downloadMediaAndPackCar(collection.uid, collection.bannerUrl!, metadata); await updateNftsForMinting(collection); - await build5Db().doc(`${COL.COLLECTION}/${collection.uid}`).update({ + await build5Db().doc(COL.COLLECTION, collection.uid).update({ mediaStatus: MediaStatus.PENDING_UPLOAD, ipfsMedia: ipfs.ipfsMedia, ipfsMetadata: ipfs.ipfsMetadata, @@ -144,54 +121,58 @@ const onCollectionMinting = async (collection: Collection) => { }); }; -const onNftMediaPrepared = async (collection: Collection) => { +const onNftMediaPrepared = async (collection: PgCollection) => { const order: Transaction = { project: getProject(collection), type: TransactionType.MINT_COLLECTION, uid: getRandomEthAddress(), - member: collection.mintingData?.mintedBy!, + member: collection.mintingData_mintedBy!, space: collection.space, - network: collection.mintingData?.network!, + network: collection.mintingData_network as Network, payload: { type: TransactionPayloadType.MINT_ALIAS, - amount: collection.mintingData?.aliasStorageDeposit || 0, - sourceAddress: collection.mintingData?.address, + amount: collection.mintingData_aliasStorageDeposit || 0, + sourceAddress: collection.mintingData_address, collection: collection.uid, - collectionStorageDeposit: collection.mintingData?.storageDeposit, + collectionStorageDeposit: collection.mintingData_storageDeposit, }, }; - await build5Db().doc(`${COL.TRANSACTION}/${order.uid}`).create(order); + await build5Db().doc(COL.TRANSACTION, order.uid).create(order); }; const BATCH_SIZE = 1000; -const updateNftsForMinting = async (collection: Collection) => { - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${collection.uid}`); - const unsoldMintingOptions = collection.mintingData?.unsoldMintingOptions; - let lastDocId = ''; +const updateNftsForMinting = async (collection: PgCollection) => { + const collectionDocRef = build5Db().doc(COL.COLLECTION, collection.uid); + const unsoldMintingOptions = collection.mintingData_unsoldMintingOptions; let unsoldCount = 0; let nftsToMintCount = 0; let nftMediaToUploadCount = 0; let nftMediaToPrepareCount = 0; + if (unsoldMintingOptions === UnsoldMintingOptions.BURN_UNSOLD) { + const deleted = await build5Db() + .collection(COL.NFT) + .delete({ collection: collection.uid, sold: false, placeholderNft: false }); + if (deleted) { + await build5Db() + .doc(COL.COLLECTION, collection.uid) + .update({ total: build5Db().inc(-deleted) }); + } + } + + let lastDoc: Nft | undefined = undefined; do { - const lastDoc = await getSnapshot(COL.NFT, lastDocId); - const allNfts = await build5Db() + const allNfts: Nft[] = await build5Db() .collection(COL.NFT) .where('collection', '==', collection.uid) .where('placeholderNft', '==', false) .startAfter(lastDoc) .limit(BATCH_SIZE) - .get(); - lastDocId = last(allNfts)?.uid || ''; + .get(); + lastDoc = last(allNfts); const unsold = allNfts.filter((nft) => !nft.sold); - if (unsoldMintingOptions === UnsoldMintingOptions.BURN_UNSOLD) { - const promises = unsold.map((nft) => build5Db().doc(`${COL.NFT}/${nft.uid}`).delete()); - await Promise.all(promises); - await build5Db() - .doc(`${COL.COLLECTION}/${collection.uid}`) - .update({ total: build5Db().inc(-unsold.length) }); - } + const nftsToMint = unsoldMintingOptions === UnsoldMintingOptions.BURN_UNSOLD ? allNfts.filter((nft) => nft.sold) @@ -214,29 +195,28 @@ const updateNftsForMinting = async (collection: Collection) => { nftMediaToPrepareCount -= nftMediaAlreadyPrepared; unsoldCount += unsold.length; - } while (lastDocId); + } while (lastDoc); await collectionDocRef.update({ - 'mintingData.nftsToMint': build5Db().inc(nftsToMintCount), - 'mintingData.nftMediaToUpload': build5Db().inc(nftMediaToUploadCount), - 'mintingData.nftMediaToPrepare': build5Db().inc(nftMediaToPrepareCount), + mintingData_nftsToMint: build5Db().inc(nftsToMintCount), + mintingData_nftMediaToUpload: build5Db().inc(nftMediaToUploadCount), + mintingData_nftMediaToPrepare: build5Db().inc(nftMediaToPrepareCount), }); if ( !unsoldCount || - [UnsoldMintingOptions.BURN_UNSOLD, UnsoldMintingOptions.TAKE_OWNERSHIP].includes( - unsoldMintingOptions!, - ) + UnsoldMintingOptions.BURN_UNSOLD === unsoldMintingOptions || + UnsoldMintingOptions.TAKE_OWNERSHIP === unsoldMintingOptions ) { const promises = ( await build5Db() .collection(COL.NFT) .where('collection', '==', collection.uid) .where('placeholderNft', '==', true) - .get() - ).map((nft) => { - const docRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); - docRef.update({ hidden: true }); + .get() + ).map(async (nft) => { + const docRef = build5Db().doc(COL.NFT, nft.uid); + await docRef.update({ hidden: true }); }); await Promise.all(promises); } @@ -248,28 +228,27 @@ const updateNftsForMinting = async (collection: Collection) => { if ( unsoldCount && collection.placeholderNft && - collection.mintingData?.unsoldMintingOptions === UnsoldMintingOptions.SET_NEW_PRICE + collection.mintingData_unsoldMintingOptions === UnsoldMintingOptions.SET_NEW_PRICE ) { await build5Db() - .doc(`${COL.NFT}/${collection.placeholderNft}`) + .doc(COL.NFT, collection.placeholderNft) .update({ - availablePrice: collection.mintingData?.newPrice || collection.price, - price: collection.mintingData?.newPrice || collection.price, + availablePrice: collection.mintingData_newPrice || collection.price, + price: collection.mintingData_newPrice || collection.price, }); } }; -const setNftForMinting = async (nftId: string, collection: Collection): Promise => { - const nftDocRef = build5Db().doc(`${COL.NFT}/${nftId}`); - +const setNftForMinting = async (nftId: string, collection: PgCollection): Promise => { const nft = await build5Db().runTransaction(async (transaction) => { - const nft = (await transaction.get(nftDocRef))!; + const nftDocRef = build5Db().doc(COL.NFT, nftId); + const nft = (await transaction.get(nftDocRef))!; if (nft.mediaStatus === MediaStatus.PREPARE_IPFS) { - transaction.update(nftDocRef, { mediaStatus: MediaStatus.ERROR }); + await transaction.update(nftDocRef, { mediaStatus: MediaStatus.ERROR }); } - const nftUpdateData = { + const nftUpdateData = { auctionFrom: null, auctionTo: null, extendedAuctionTo: null, @@ -286,15 +265,15 @@ const setNftForMinting = async (nftId: string, collection: Collection): Promise< }; if (nft.auction) { - const auctionDocRef = build5Db().doc(`${COL.AUCTION}/${nft.auction}`); - transaction.update(auctionDocRef, { active: false }); + const auctionDocRef = build5Db().doc(COL.AUCTION, nft.auction); + await transaction.update(auctionDocRef, { active: false }); const payments = await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.PAYMENT) - .where('payload.invalidPayment', '==', false) - .where('payload.auction', '==', nft.auction) - .get(); + .where('payload_invalidPayment', '==', false) + .where('payload_auction', '==', nft.auction) + .get(); for (const payment of payments) { const credit: Transaction = { project: getProject(payment), @@ -312,15 +291,14 @@ const setNftForMinting = async (nftId: string, collection: Collection): Promise< collection: nft.collection, }, }; - const creditDocRef = build5Db().doc(`${COL.TRANSACTION}/${credit.uid}`); - transaction.create(creditDocRef, credit); + const creditDocRef = build5Db().doc(COL.TRANSACTION, credit.uid); + await transaction.create(creditDocRef, credit); } } if (nft.locked) { - transaction.update(build5Db().doc(`${COL.TRANSACTION}/${nft.lockedBy}`), { - 'payload.void': true, - }); + const docRef = build5Db().doc(COL.TRANSACTION, nft.lockedBy!); + await transaction.update(docRef, { payload_void: true }); nftUpdateData.locked = false; nftUpdateData.lockedBy = null; } @@ -330,13 +308,13 @@ const setNftForMinting = async (nftId: string, collection: Collection): Promise< nftUpdateData.availablePrice = null; nftUpdateData.price = 0; } else { - if (collection.mintingData?.unsoldMintingOptions === UnsoldMintingOptions.SET_NEW_PRICE) { + if (collection.mintingData_unsoldMintingOptions === UnsoldMintingOptions.SET_NEW_PRICE) { nftUpdateData.availablePrice = - collection.mintingData?.newPrice || nftUpdateData.availablePrice; - nftUpdateData.price = collection.mintingData?.newPrice || nftUpdateData.price; + collection.mintingData_newPrice || nftUpdateData.availablePrice; + nftUpdateData.price = collection.mintingData_newPrice || nftUpdateData.price; } - if (collection.mintingData?.unsoldMintingOptions === UnsoldMintingOptions.TAKE_OWNERSHIP) { - nftUpdateData.owner = collection.mintingData?.mintedBy!; + if (collection.mintingData_unsoldMintingOptions === UnsoldMintingOptions.TAKE_OWNERSHIP) { + nftUpdateData.owner = collection.mintingData_mintedBy!; nftUpdateData.isOwned = true; nftUpdateData.sold = true; nftUpdateData.availableFrom = null; @@ -344,14 +322,15 @@ const setNftForMinting = async (nftId: string, collection: Collection): Promise< nftUpdateData.price = 0; } } - transaction.update(nftDocRef, nftUpdateData); + await transaction.update(nftDocRef, nftUpdateData); return nftUpdateData; }); if (nft.mediaStatus === MediaStatus.ERROR) { + const nftDocRef = build5Db().doc(COL.NFT, nftId); await nftDocRef.update({ mediaStatus: MediaStatus.PREPARE_IPFS }); } - return nft.mediaStatus!; + return nft.mediaStatus as MediaStatus; }; diff --git a/packages/functions/src/triggers/common.ts b/packages/functions/src/triggers/common.ts index aacc45044c..33fd6907d5 100644 --- a/packages/functions/src/triggers/common.ts +++ b/packages/functions/src/triggers/common.ts @@ -1,11 +1,11 @@ +import { BaseRecord } from '@build-5/database'; import { COL, SUB_COL } from '@build-5/interfaces'; -export interface FirestoreDocEvent { - prev?: T; +export interface PgDocEvent { + prev: T; curr?: T; - path: string; col: COL; - docId: string; + uid: string; subCol?: SUB_COL; - subDocId?: string; + subColId?: string; } diff --git a/packages/functions/src/triggers/milestone-transactions-triggers/MilestoneTransactionAdapter.ts b/packages/functions/src/triggers/milestone-transactions-triggers/MilestoneTransactionAdapter.ts index 9b3bc3a214..831dde3c64 100644 --- a/packages/functions/src/triggers/milestone-transactions-triggers/MilestoneTransactionAdapter.ts +++ b/packages/functions/src/triggers/milestone-transactions-triggers/MilestoneTransactionAdapter.ts @@ -1,9 +1,5 @@ -import { - MilestoneTransaction, - MilestoneTransactionEntry, - Network, - Timestamp, -} from '@build-5/interfaces'; +import { MilestoneTransactions } from '@build-5/database'; +import { MilestoneTransaction, MilestoneTransactionEntry, Network } from '@build-5/interfaces'; import { BasicOutput, FeatureType, @@ -27,10 +23,10 @@ export class MilestoneTransactionAdapter { constructor(private readonly network: Network) {} public toMilestoneTransaction = async ( - data: Record, + data: MilestoneTransactions, ): Promise => { const wallet = await WalletService.newWallet(this.network); - const payload = data.payload as TransactionPayload; + const payload = data.payload as unknown as TransactionPayload; const essence = payload.essence as RegularTransactionEssence; const outputs = essence.outputs .filter((o) => VALID_OUTPUTS_TYPES.includes(o.type)) @@ -72,7 +68,7 @@ export class MilestoneTransactionAdapter { fromAddresses.push(senderBech32); } - const build5TransactionId = await getMilestoneTransactionId(data); + const build5TransactionId = getMilestoneTransactionId(data); const consumedOutputIds = essence.inputs.map((i) => { const { transactionId, transactionOutputIndex } = i as UTXOInput; @@ -81,9 +77,9 @@ export class MilestoneTransactionAdapter { return { uid: data.uid as string, - createdOn: data.createdOn as Timestamp, + createdOn: data.createdOn!, messageId: data.blockId as string, - milestone: data.milestone as number, + milestone: data.milestone!, consumedOutputIds, fromAddresses, outputs: entries, diff --git a/packages/functions/src/triggers/milestone-transactions-triggers/common.ts b/packages/functions/src/triggers/milestone-transactions-triggers/common.ts index 45ff1f6d0f..94399f6762 100644 --- a/packages/functions/src/triggers/milestone-transactions-triggers/common.ts +++ b/packages/functions/src/triggers/milestone-transactions-triggers/common.ts @@ -1,5 +1,5 @@ -import { build5Db } from '@build-5/database'; -import { COL, NetworkAddress, Transaction } from '@build-5/interfaces'; +import { MilestoneTransactions, build5Db } from '@build-5/database'; +import { COL, NetworkAddress } from '@build-5/interfaces'; import { RegularTransactionEssence, TaggedDataPayload, @@ -11,23 +11,23 @@ import { isEmpty } from 'lodash'; export const confirmTransaction = async ( milestoneTransactionPath: string, - milestoneTransaction: Record, + milestoneTransaction: MilestoneTransactions, ) => { - const transactionId = await getMilestoneTransactionId(milestoneTransaction); + const transactionId = getMilestoneTransactionId(milestoneTransaction); if (isEmpty(transactionId)) { return; } - const docRef = build5Db().doc(`${COL.TRANSACTION}/${transactionId}`); - const transaction = await docRef.get(); + const docRef = build5Db().doc(COL.TRANSACTION, transactionId); + const transaction = await docRef.get(); if (!transaction) { return; } await docRef.update({ - 'payload.walletReference.confirmed': true, - 'payload.walletReference.confirmedOn': dayjs().toDate(), - 'payload.walletReference.inProgress': false, - 'payload.walletReference.milestoneTransactionPath': milestoneTransactionPath, + payload_walletReference_confirmed: true, + payload_walletReference_confirmedOn: dayjs().toDate(), + payload_walletReference_inProgress: false, + payload_walletReference_milestoneTransactionPath: milestoneTransactionPath, }); await unclockMnemonic(transaction.payload.sourceAddress); @@ -39,7 +39,7 @@ export const unclockMnemonic = async (address: NetworkAddress | undefined) => { if (isEmpty(address)) { return; } - await build5Db().doc(`${COL.MNEMONIC}/${address}`).update({ + await build5Db().doc(COL.MNEMONIC, address!).update({ lockedBy: '', consumedOutputIds: [], consumedNftOutputIds: [], @@ -47,9 +47,9 @@ export const unclockMnemonic = async (address: NetworkAddress | undefined) => { }); }; -export const getMilestoneTransactionId = async (milestoneTransaction: Record) => { +export const getMilestoneTransactionId = (milestoneTransaction: MilestoneTransactions) => { try { - const payload = milestoneTransaction.payload; + const payload = milestoneTransaction.payload as unknown as TransactionPayload; const essence = payload.essence as RegularTransactionEssence; const hexData = (essence?.payload as TaggedDataPayload)?.data || ''; const metadata = JSON.parse(hexToUtf8(hexData)); diff --git a/packages/functions/src/triggers/milestone-transactions-triggers/consumed.vote.outputs.ts b/packages/functions/src/triggers/milestone-transactions-triggers/consumed.vote.outputs.ts index b91fc716df..290eb892ca 100644 --- a/packages/functions/src/triggers/milestone-transactions-triggers/consumed.vote.outputs.ts +++ b/packages/functions/src/triggers/milestone-transactions-triggers/consumed.vote.outputs.ts @@ -1,8 +1,7 @@ -import { build5Db } from '@build-5/database'; -import { COL, Proposal, SUB_COL, Transaction, TransactionType } from '@build-5/interfaces'; +import { PgProposalUpdate, build5Db } from '@build-5/database'; +import { COL, Proposal, SUB_COL, TransactionType } from '@build-5/interfaces'; import dayjs from 'dayjs'; import { getTokenVoteMultiplier } from '../../services/payment/voting-service'; -import { serverTime } from '../../utils/dateTime.utils'; export const processConsumedVoteOutputs = async (consumedOutputIds: string[]) => { const batch = build5Db().batch(); @@ -10,30 +9,27 @@ export const processConsumedVoteOutputs = async (consumedOutputIds: string[]) => const voteTransactionSnap = await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.VOTE) - .where('payload.outputId', '==', consumedOutput) - .where('payload.outputConsumed', '==', false) + .where('payload_outputId', '==', consumedOutput) + .where('payload_outputConsumed', '==', false) .limit(1) - .get(); + .get(); if (!voteTransactionSnap.length) { continue; } - const voteTransactionDocRef = build5Db().doc( - `${COL.TRANSACTION}/${voteTransactionSnap[0].uid}`, - ); + const voteTransactionDocRef = build5Db().doc(COL.TRANSACTION, voteTransactionSnap[0].uid); const voteTransaction = voteTransactionSnap[0]; - const proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${voteTransaction.payload.proposalId}`); + const proposalDocRef = build5Db().doc(COL.PROPOSAL, voteTransaction.payload.proposalId!); const proposal = await proposalDocRef.get(); + if (dayjs().isAfter(proposal.settings.endDate.toDate())) { batch.update(voteTransactionDocRef, { - 'payload.outputConsumed': true, - 'payload.outputConsumedOn': serverTime(), + payload_outputConsumed: true, + payload_outputConsumedOn: dayjs().toDate(), }); continue; } - const prevWeight = voteTransaction.payload.weight!; - const currWeightMultiplier = getTokenVoteMultiplier( proposal, dayjs(voteTransaction.createdOn?.toDate()), @@ -42,42 +38,31 @@ export const processConsumedVoteOutputs = async (consumedOutputIds: string[]) => const currWeight = voteTransaction.payload.tokenAmount! * currWeightMultiplier; const value = voteTransaction.payload.values![0]; - const data = { + const data: PgProposalUpdate = { results: { total: build5Db().inc(-prevWeight + currWeight), voted: build5Db().inc(-prevWeight + currWeight), - answers: { [value]: build5Db().inc(-prevWeight + currWeight) }, + answers: { [value.toString()]: build5Db().inc(-prevWeight + currWeight) }, }, }; - batch.set(proposalDocRef, data, true); + batch.update(proposalDocRef, data); - batch.update(voteTransactionDocRef, { - 'payload.weight': currWeight, - 'payload.weightMultiplier': currWeightMultiplier, - 'payload.outputConsumed': true, - 'payload.outputConsumedOn': serverTime(), - }); - - const proposalMemberDocRef = proposalDocRef - .collection(SUB_COL.MEMBERS) - .doc(voteTransaction.member!); - batch.set( - proposalMemberDocRef, - { - values: build5Db().arrayRemove({ - [value]: prevWeight, - voteTransaction: voteTransaction.uid, - }), - voteTransactions: build5Db().inc(-1), - weightPerAnswer: { [value]: build5Db().inc(-prevWeight + currWeight) }, - }, - true, + const proposalMemberDocRef = build5Db().doc( + COL.PROPOSAL, + voteTransaction.payload.proposalId!, + SUB_COL.MEMBERS, + voteTransaction.member!, ); batch.update(proposalMemberDocRef, { - values: build5Db().arrayUnion({ - [value]: currWeight, - voteTransaction: voteTransaction.uid, - }), + weight: build5Db().inc(-prevWeight + currWeight), + values: { [voteTransaction.uid]: { weight: build5Db().inc(-prevWeight + currWeight) } }, + }); + + batch.update(voteTransactionDocRef, { + payload_weight: currWeight, + payload_weightMultiplier: currWeightMultiplier, + payload_outputConsumed: true, + payload_outputConsumedOn: dayjs().toDate(), }); } await batch.commit(); diff --git a/packages/functions/src/triggers/milestone-transactions-triggers/milestone-transaction.trigger.ts b/packages/functions/src/triggers/milestone-transactions-triggers/milestone-transaction.trigger.ts index 733216b642..f08671d6f7 100644 --- a/packages/functions/src/triggers/milestone-transactions-triggers/milestone-transaction.trigger.ts +++ b/packages/functions/src/triggers/milestone-transactions-triggers/milestone-transaction.trigger.ts @@ -1,42 +1,48 @@ -import { build5Db } from '@build-5/database'; -import { Network } from '@build-5/interfaces'; +import { PgMilestoneTransactions, build5Db } from '@build-5/database'; +import { COL, Network, SUB_COL } from '@build-5/interfaces'; import dayjs from 'dayjs'; import { ProcessingService } from '../../services/payment/payment-processing'; -import { FirestoreDocEvent } from '../common'; +import { logger } from '../../utils/logger'; +import { PgDocEvent } from '../common'; import { MilestoneTransactionAdapter } from './MilestoneTransactionAdapter'; import { confirmTransaction } from './common'; import { processConsumedVoteOutputs } from './consumed.vote.outputs'; import { updateTokenSupplyData } from './token.foundry'; export const handleMilestoneTransactionWrite = - (network: Network) => async (event: FirestoreDocEvent>) => { + // eslint-disable-next-line require-await + (network: Network) => async (event: PgDocEvent) => { const { curr } = event; if (!curr) { return; } + const path = `${event.col}/${event.subColId}/${event.subCol!}/${event.uid}`; try { return build5Db().runTransaction(async (transaction) => { - const docRef = build5Db().doc(event.path); - const data = await transaction.get>(docRef); - if (!data || data.processed) { + const docRef = build5Db().doc( + event.col as COL.MILESTONE, + event.subColId!, + event.subCol! as SUB_COL.TRANSACTIONS, + event.uid, + ); + const milestoneTran = await transaction.get(docRef); + if (!milestoneTran || milestoneTran.processed) { return; } - await confirmTransaction(event.path, data); - await updateTokenSupplyData(data); + await confirmTransaction(path, milestoneTran); + await updateTokenSupplyData(milestoneTran); const adapter = new MilestoneTransactionAdapter(network); - const milestoneTransaction = await adapter.toMilestoneTransaction({ - ...data, - uid: event.subDocId, - }); + const milestoneTransaction = await adapter.toMilestoneTransaction(milestoneTran); const service = new ProcessingService(transaction); await service.processMilestoneTransactions(milestoneTransaction); - service.submit(); + await service.submit(); await processConsumedVoteOutputs(milestoneTransaction.consumedOutputIds); return transaction.update(docRef, { processed: true, processedOn: dayjs().toDate() }); }); } catch (error) { - console.error(`${network} transaction error`, event.path, error); + logger.error(`${network} transaction error`, path, error); + return; } }; diff --git a/packages/functions/src/triggers/milestone-transactions-triggers/token.foundry.ts b/packages/functions/src/triggers/milestone-transactions-triggers/token.foundry.ts index a5638a4d4b..cffe591b5d 100644 --- a/packages/functions/src/triggers/milestone-transactions-triggers/token.foundry.ts +++ b/packages/functions/src/triggers/milestone-transactions-triggers/token.foundry.ts @@ -1,4 +1,4 @@ -import { build5Db } from '@build-5/database'; +import { MilestoneTransactions, build5Db } from '@build-5/database'; import { COL } from '@build-5/interfaces'; import { AddressUnlockCondition, @@ -13,9 +13,9 @@ import { } from '@iota/sdk'; import { getTokenByMintId } from '../../utils/token.utils'; -export const updateTokenSupplyData = async (data: Record) => { +export const updateTokenSupplyData = async (data: MilestoneTransactions) => { const foundryOutputs = ( - (data.payload as TransactionPayload).essence as RegularTransactionEssence + (data.payload as unknown as TransactionPayload).essence as RegularTransactionEssence ).outputs .filter((o) => o.type === OutputType.Foundry) .map((o) => o); @@ -32,10 +32,10 @@ export const updateTokenSupplyData = async (data: Record) => { const tokenScheme = foundryOutput.tokenScheme as SimpleTokenScheme; const meltedTokens = Number(tokenScheme.meltedTokens); const totalSupply = Number(tokenScheme.maximumSupply); - const tokendDocRef = build5Db().doc(`${COL.TOKEN}/${token.uid}`); + const tokendDocRef = build5Db().doc(COL.TOKEN, token.uid); await tokendDocRef.update({ - 'mintingData.meltedTokens': meltedTokens, - 'mintingData.circulatingSupply': totalSupply - meltedTokens, + mintingData_meltedTokens: meltedTokens, + mintingData_circulatingSupply: totalSupply - meltedTokens, }); } }; diff --git a/packages/functions/src/triggers/mnemonic.trigger.ts b/packages/functions/src/triggers/mnemonic.trigger.ts index 52ba987170..61d60a3f54 100644 --- a/packages/functions/src/triggers/mnemonic.trigger.ts +++ b/packages/functions/src/triggers/mnemonic.trigger.ts @@ -1,31 +1,25 @@ -import { build5Db } from '@build-5/database'; -import { COL, MAX_WALLET_RETRY, Mnemonic, NetworkAddress, Transaction } from '@build-5/interfaces'; +import { PgMnemonic, build5Db } from '@build-5/database'; +import { COL, MAX_WALLET_RETRY, NetworkAddress } from '@build-5/interfaces'; import { chunk, isEmpty } from 'lodash'; -import { FirestoreDocEvent } from './common'; +import { PgDocEvent } from './common'; import { CREDIT_EXECUTABLE_TRANSACTIONS, DEFAULT_EXECUTABLE_TRANSACTIONS, } from './transaction-trigger/transaction.trigger'; -enum FieldNameType { - SOURCE_ADDRESS = 'payload.sourceAddress', - STORAGE_DEP_ADDRESS = 'payload.storageDepositSourceAddress', - ALIAS_GOV_ADDRESS = 'payload.aliasGovAddress', -} - -export const onMnemonicUpdated = async (event: FirestoreDocEvent) => { +export const onMnemonicUpdated = async (event: PgDocEvent) => { const { prev, curr } = event; if (!prev || !curr || isEmpty(prev?.lockedBy) || !isEmpty(curr?.lockedBy)) { return; } - const address = event.docId; + const address = event.uid; const tranId = await getUncofirmedTransactionsId(address); if (!isEmpty(tranId)) { await build5Db() - .doc(`${COL.TRANSACTION}/${tranId}`) - .update({ shouldRetry: true, 'payload.walletReference.inProgress': false }); + .doc(COL.TRANSACTION, tranId!) + .update({ shouldRetry: true, payload_walletReference_inProgress: false }); } }; @@ -37,12 +31,16 @@ const getUncofirmedTransactionsId = async (address: NetworkAddress) => { for (const types of TYPE_CHUNKS) { const transactions = await build5Db() .collection(COL.TRANSACTION) - .or(Object.values(FieldNameType).map((fieldPath) => ({ fieldPath, value: address }))) - .where('type', 'in', types) - .where('payload.walletReference.confirmed', '==', false) - .where('payload.walletReference.count', '<', MAX_WALLET_RETRY) + .where('payload_walletReference_confirmed', '==', false) + .whereIn('type', types) + .whereOr({ + payload_sourceAddress: address, + payload_storageDepositSourceAddress: address, + payload_aliasGovAddress: address, + }) + .where('payload_walletReference_count', '<', MAX_WALLET_RETRY) .limit(1) - .get(); + .get(); if (transactions.length) { return transactions[0].uid; } diff --git a/packages/functions/src/triggers/nft.trigger.ts b/packages/functions/src/triggers/nft.trigger.ts index 8b2c45b475..e4c0496db3 100644 --- a/packages/functions/src/triggers/nft.trigger.ts +++ b/packages/functions/src/triggers/nft.trigger.ts @@ -1,9 +1,9 @@ -import { build5Db } from '@build-5/database'; -import { COL, Collection, MediaStatus, Nft, NftAvailable } from '@build-5/interfaces'; +import { PgNft, build5Db } from '@build-5/database'; +import { COL, MediaStatus, NftAvailable } from '@build-5/interfaces'; import { downloadMediaAndPackCar, nftToIpfsMetadata } from '../utils/car.utils'; -import { FirestoreDocEvent } from './common'; +import { PgDocEvent } from './common'; -const getNftAvailability = (nft: Nft | undefined) => { +const getNftAvailability = (nft: PgNft | undefined) => { if (!nft || nft.placeholderNft) { return NftAvailable.UNAVAILABLE; } @@ -19,7 +19,7 @@ const getNftAvailability = (nft: Nft | undefined) => { return NftAvailable.UNAVAILABLE; }; -export const onNftWrite = async (event: FirestoreDocEvent) => { +export const onNftWrite = async (event: PgDocEvent) => { const { prev, curr } = event; if (!curr) { return; @@ -35,14 +35,14 @@ export const onNftWrite = async (event: FirestoreDocEvent) => { ); const availableNfts = getAvailableNftsChange(prevAvailability, currAvailability, prev?.owner); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${curr.collection}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, curr.collection!); await collectionDocRef.update({ nftsOnSale: build5Db().inc(nftsOnSale), nftsOnAuction: build5Db().inc(nftsOnAuction), availableNfts: build5Db().inc(availableNfts), }); - const docRef = build5Db().doc(event.path); + const docRef = build5Db().doc(COL.NFT, curr.uid); await docRef.update({ available: currAvailability }); } @@ -51,17 +51,17 @@ export const onNftWrite = async (event: FirestoreDocEvent) => { } }; -const prepareNftMedia = async (nft: Nft) => { - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${nft.collection}`); - const nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); +const prepareNftMedia = async (nft: PgNft) => { + const collectionDocRef = build5Db().doc(COL.COLLECTION, nft.collection!); + const nftDocRef = build5Db().doc(COL.NFT, nft.uid); const batch = build5Db().batch(); if (nft.ipfsRoot) { batch.update(nftDocRef, { mediaStatus: MediaStatus.PENDING_UPLOAD }); } else { - const collection = (await collectionDocRef.get())!; + const collection = (await collectionDocRef.get())!; const metadata = nftToIpfsMetadata(collection, nft); - const ipfs = await downloadMediaAndPackCar(nft.uid, nft.media, metadata); + const ipfs = await downloadMediaAndPackCar(nft.uid, nft.media!, metadata); batch.update(nftDocRef, { mediaStatus: MediaStatus.PENDING_UPLOAD, ipfsMedia: ipfs.ipfsMedia, @@ -70,7 +70,7 @@ const prepareNftMedia = async (nft: Nft) => { }); } - batch.update(collectionDocRef, { 'mintingData.nftMediaToPrepare': build5Db().inc(-1) }); + batch.update(collectionDocRef, { mintingData_nftMediaToPrepare: build5Db().inc(-1) }); await batch.commit(); }; diff --git a/packages/functions/src/triggers/proposal.trigger.ts b/packages/functions/src/triggers/proposal.trigger.ts index abd9a9e7a6..877c5ccef7 100644 --- a/packages/functions/src/triggers/proposal.trigger.ts +++ b/packages/functions/src/triggers/proposal.trigger.ts @@ -1,33 +1,27 @@ -import { build5Db } from '@build-5/database'; +import { build5Db, PgProposal, removeNulls } from '@build-5/database'; import { ADD_REMOVE_GUARDIAN_THRESHOLD_PERCENTAGE, BaseProposalAnswerValue, COL, MediaStatus, - Member, - Proposal, ProposalType, REMOVE_STAKE_REWARDS_THRESHOLD_PERCENTAGE, - Space, - SpaceGuardian, - SpaceMember, StakeRewardStatus, StakeType, SUB_COL, - TokenDistribution, UPDATE_SPACE_THRESHOLD_PERCENTAGE, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { get, set } from 'lodash'; +import { get, head, set } from 'lodash'; import { getStakeForType } from '../services/stake.service'; import { downloadMediaAndPackCar } from '../utils/car.utils'; -import { dateToTimestamp } from '../utils/dateTime.utils'; import { spaceToIpfsMetadata } from '../utils/space.utils'; import { getTokenForSpace } from '../utils/token.utils'; -import { FirestoreDocEvent } from './common'; +import { PgDocEvent } from './common'; -export const onProposalWrite = async (event: FirestoreDocEvent) => { +export const onProposalWrite = async (event: PgDocEvent) => { const { prev, curr } = event; + if (!curr) { return; } @@ -54,50 +48,58 @@ export const onProposalWrite = async (event: FirestoreDocEvent) => { } }; -const isAddRemoveGuardianVote = (curr: Proposal) => - [ProposalType.ADD_GUARDIAN, ProposalType.REMOVE_GUARDIAN].includes(curr.type); +const isAddRemoveGuardianVote = (curr: PgProposal) => + [ProposalType.ADD_GUARDIAN, ProposalType.REMOVE_GUARDIAN].includes(curr.type!); -const voteThresholdReached = (prev: Proposal | undefined, curr: Proposal, threshold: number) => { +const voteThresholdReached = ( + prev: PgProposal | undefined, + curr: PgProposal, + threshold: number, +) => { + const prevAnswers = prev?.results?.answers as Record | undefined; const prevAnsweredPercentage = - ((prev?.results?.answers[BaseProposalAnswerValue.YES] || 0) * 100) / - (prev?.results?.total || 1); + ((prevAnswers?.[BaseProposalAnswerValue.YES] || 0) * 100) / Number(prev?.results?.total || 1); + + const currAnswers = curr.results?.answers as Record | undefined; const currAnsweredPercentage = - ((curr.results?.answers[BaseProposalAnswerValue.YES] || 0) * 100) / (curr.results?.total || 1); + ((currAnswers?.[BaseProposalAnswerValue.YES] || 0) * 100) / Number(curr.results?.total || 1); return prevAnsweredPercentage <= threshold && currAnsweredPercentage > threshold; }; -const onAddRemoveGuardianProposalApproved = async (proposal: Proposal) => { - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${proposal.space}`); - const guardianDocRef = spaceDocRef - .collection(SUB_COL.GUARDIANS) - .doc(proposal.settings.addRemoveGuardian!); +const onAddRemoveGuardianProposalApproved = async (proposal: PgProposal) => { + const spaceDocRef = build5Db().doc(COL.SPACE, proposal.space!); + const guardianDocRef = build5Db().doc( + COL.SPACE, + proposal.space!, + SUB_COL.GUARDIANS, + proposal.settings_addRemoveGuardian!, + ); const isAddGuardian = proposal.type === ProposalType.ADD_GUARDIAN; const batch = build5Db().batch(); if (isAddGuardian) { - batch.set(guardianDocRef, { - uid: proposal.settings.addRemoveGuardian, + batch.upsert(guardianDocRef, { parentId: proposal.space, - parentCol: COL.SPACE, }); } else { batch.delete(guardianDocRef); } batch.update(spaceDocRef, { totalGuardians: build5Db().inc(isAddGuardian ? 1 : -1) }); - const proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${proposal.uid}`); + const proposalDocRef = build5Db().doc(COL.PROPOSAL, proposal.uid); batch.update(proposalDocRef, { - 'settings.endDate': dateToTimestamp(dayjs().subtract(1, 's')), + settings_endDate: dayjs().subtract(1, 's').toDate(), completed: true, }); await batch.commit(); }; -const onEditSpaceProposalApproved = async (proposal: Proposal) => { - const spaceUpdateData = proposal.settings.spaceUpdateData!; - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${spaceUpdateData.uid}`); +const onEditSpaceProposalApproved = async (proposal: PgProposal) => { + const spaceUpdateData = proposal.settings_spaceUpdateData!; + const spaceId = spaceUpdateData.uid! as string; + const spaceDocRef = build5Db().doc(COL.SPACE, spaceId); if (spaceUpdateData.bannerUrl) { - const space = (await spaceDocRef.get())!; + const space = (await spaceDocRef.get())!; const metadata = spaceToIpfsMetadata({ ...space, ...spaceUpdateData }); const ipfs = await downloadMediaAndPackCar( space.uid, @@ -111,36 +113,43 @@ const onEditSpaceProposalApproved = async (proposal: Proposal) => { } if (spaceUpdateData.open) { - const knockingMembersSnap = await spaceDocRef - .collection(SUB_COL.KNOCKING_MEMBERS) - .get(); + const knockingMembersSnap = await build5Db() + .collection(COL.SPACE, spaceId, SUB_COL.KNOCKING_MEMBERS) + .get(); const deleteKnockingMemberPromise = knockingMembersSnap.map((kMember) => - spaceDocRef.collection(SUB_COL.KNOCKING_MEMBERS).doc(kMember.uid).delete(), + build5Db().doc(COL.SPACE, spaceId, SUB_COL.KNOCKING_MEMBERS, kMember.uid).delete(), ); await Promise.all(deleteKnockingMemberPromise); } const { removedMembers, removedGuardians } = await removeMembersAndGuardiansThatDontHaveEnoughStakes(spaceUpdateData); - const updateData = spaceUpdateData.open - ? { ...spaceUpdateData, totalPendingMembers: 0 } - : spaceUpdateData; - const prevValidatedAddresses = get(updateData, 'prevValidatedAddresses'); - if (prevValidatedAddresses) { - set(updateData, 'prevValidatedAddresses', build5Db().arrayUnion(prevValidatedAddresses)); - } - await spaceDocRef.set( - { - ...updateData, - totalMembers: build5Db().inc(-removedMembers), - totalGuardians: build5Db().inc(-removedGuardians), - }, - true, + + const updateData = removeNulls( + spaceDocRef.converter.toPg( + spaceUpdateData.open + ? { ...spaceUpdateData, totalPendingMembers: 0 } + : // eslint-disable-next-line @typescript-eslint/no-explicit-any + (spaceUpdateData as any), + ), ); + const prevValidatedAddress = head(get(updateData, 'prevValidatedAddresses', [])); + if (prevValidatedAddress) { + set(updateData, 'prevValidatedAddresses', build5Db().arrayUnion(prevValidatedAddress)); + } else { + delete updateData.prevValidatedAddresses; + } + + await spaceDocRef.upsert({ + ...updateData, + totalMembers: build5Db().inc(-removedMembers), + totalGuardians: build5Db().inc(-removedGuardians), + }); + await build5Db() - .doc(`${COL.PROPOSAL}/${proposal.uid}`) + .doc(COL.PROPOSAL, proposal.uid) .update({ - 'settings.endDate': dateToTimestamp(dayjs().subtract(1, 's')), + settings_endDate: dayjs().subtract(1, 's').toDate(), completed: true, }); }; @@ -151,14 +160,16 @@ const removeMembersAndGuardiansThatDontHaveEnoughStakes = async ( if (!updateData.tokenBased) { return { removedMembers: 0, removedGuardians: 0 }; } - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${updateData.uid}`); - const space = (await spaceDocRef.get())!; + const spaceDocRef = build5Db().doc(COL.SPACE, updateData.uid! as string); + const space = (await spaceDocRef.get())!; const token = await getTokenForSpace(space.uid); let removedMembers = 0; let removedGuardians = 0; - const membersSnap = await spaceDocRef.collection(SUB_COL.MEMBERS).get(); + const membersSnap = await build5Db() + .collection(COL.SPACE, updateData.uid! as string, SUB_COL.MEMBERS) + .get(); for (const member of membersSnap) { if (space.totalMembers - removedMembers === 1) { @@ -171,9 +182,16 @@ const removeMembersAndGuardiansThatDontHaveEnoughStakes = async ( ); if (!hasEnoughStaked) { removedMembers++; - await spaceDocRef.collection(SUB_COL.MEMBERS).doc(member.uid).delete(); - const guardianDocRef = spaceDocRef.collection(SUB_COL.GUARDIANS).doc(member.uid); - const guardian = await guardianDocRef.get(); + await build5Db() + .doc(COL.SPACE, updateData.uid! as string, SUB_COL.MEMBERS, member.uid) + .delete(); + const guardianDocRef = build5Db().doc( + COL.SPACE, + updateData.uid! as string, + SUB_COL.GUARDIANS, + member.uid, + ); + const guardian = await guardianDocRef.get(); if (guardian) { await guardianDocRef.delete(); removedGuardians++; @@ -185,26 +203,24 @@ const removeMembersAndGuardiansThatDontHaveEnoughStakes = async ( }; const memberHasEnoughStakedValues = async (token: string, member: string, minStaked: number) => { - const distributionDocRef = build5Db().doc( - `${COL.TOKEN}/${token}/${SUB_COL.DISTRIBUTION}/${member}`, - ); - const distribution = await distributionDocRef.get(); + const distributionDocRef = build5Db().doc(COL.TOKEN, token, SUB_COL.DISTRIBUTION, member); + const distribution = await distributionDocRef.get(); const stakedValue = getStakeForType(distribution, StakeType.DYNAMIC); return stakedValue > minStaked; }; -const onRemoveStakeRewardApporved = async (proposal: Proposal) => { +const onRemoveStakeRewardApporved = async (proposal: PgProposal) => { const batch = build5Db().batch(); - const stakeRewardIds = proposal.settings.stakeRewardIds || []; - stakeRewardIds.forEach((rewardId) => { - const docRef = build5Db().doc(`${COL.STAKE_REWARD}/${rewardId}`); + const stakeRewardIds = proposal.settings_stakeRewardIds || []; + for (const rewardId of stakeRewardIds) { + const docRef = build5Db().doc(COL.STAKE_REWARD, rewardId); batch.update(docRef, { status: StakeRewardStatus.DELETED }); - }); + } - const proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${proposal.uid}`); + const proposalDocRef = build5Db().doc(COL.PROPOSAL, proposal.uid); batch.update(proposalDocRef, { - 'settings.endDate': dateToTimestamp(dayjs().subtract(1, 's')), + settings_endDate: dayjs().subtract(1, 's').toDate(), completed: true, }); diff --git a/packages/functions/src/triggers/storage/resize.img.trigger.ts b/packages/functions/src/triggers/storage/resize.img.trigger.ts index 1f8cfd99e4..6a863bdc5f 100644 --- a/packages/functions/src/triggers/storage/resize.img.trigger.ts +++ b/packages/functions/src/triggers/storage/resize.img.trigger.ts @@ -6,6 +6,7 @@ import fs from 'fs'; import os from 'os'; import path from 'path'; import sharp from 'sharp'; +import { logger } from '../../utils/logger'; import { getRandomEthAddress } from '../../utils/wallet.utils'; // eslint-disable-next-line @typescript-eslint/no-var-requires @@ -35,9 +36,9 @@ export const onStorageObjectFinalized = async (data: StorageObject) => { await uploadVideoPreview(workdir, data, downloadedMediaPath); return; } - console.warn('Unsupported content type error', data); + logger.warn('Unsupported content type error', data); } catch (error) { - console.error('onStorageObjectFinalized-error', data, error); + logger.error('onStorageObjectFinalized-error', data, error); } finally { fs.rmSync(workdir, { recursive: true, force: true }); } diff --git a/packages/functions/src/triggers/token-trading/match-base-token.ts b/packages/functions/src/triggers/token-trading/match-base-token.ts index 5f2d0a8f16..48ff1fcb98 100644 --- a/packages/functions/src/triggers/token-trading/match-base-token.ts +++ b/packages/functions/src/triggers/token-trading/match-base-token.ts @@ -3,7 +3,6 @@ import { COL, Entity, Member, - Space, Token, TokenPurchaseAge, TokenTradeOrder, @@ -39,9 +38,7 @@ const createIotaPayments = async ( if (balance !== 0 && balance < Number(remainder.amount)) { return []; } - const sellOrder = await build5Db() - .doc(`${COL.TRANSACTION}/${sell.orderTransactionId}`) - .get(); + const sellOrder = await build5Db().doc(COL.TRANSACTION, sell.orderTransactionId!).get(); const billPayment: Transaction = { project: getProject(sell), type: TransactionType.BILL_PAYMENT, @@ -105,7 +102,7 @@ const createRoyaltyPayment = async ( spaceId: string, fee: number, ) => { - const space = (await build5Db().doc(`${COL.SPACE}/${spaceId}`).get())!; + const space = (await build5Db().doc(COL.SPACE, spaceId).get())!; const spaceAddress = getAddress(space, buy.sourceNetwork!); const sellerAddress = getAddress(seller, buy.sourceNetwork!); const output = await packBasicOutput(wallet, spaceAddress, 0, { @@ -151,9 +148,7 @@ const createSmrPayments = async ( ): Promise => { const wallet = await WalletService.newWallet(buy.sourceNetwork!); const tmpAddress = await wallet.getNewIotaAddressDetails(false); - const buyOrder = await build5Db() - .doc(`${COL.TRANSACTION}/${buy.orderTransactionId}`) - .get(); + const buyOrder = await build5Db().doc(COL.TRANSACTION, buy.orderTransactionId!).get(); let salePrice = Number(bigDecimal.floor(bigDecimal.multiply(price, tokensToTrade))); let balanceLeft = buy.balance - salePrice; @@ -256,8 +251,8 @@ export const matchBaseToken = async ( buy.count - buy.fulfilled, Math.floor(buy.balance / price), ); - const seller = await build5Db().doc(`${COL.MEMBER}/${sell.owner}`).get(); - const buyer = await build5Db().doc(`${COL.MEMBER}/${buy.owner}`).get(); + const seller = await build5Db().doc(COL.MEMBER, sell.owner).get(); + const buyer = await build5Db().doc(COL.MEMBER, buy.owner).get(); const iotaPayments = await createIotaPayments(token, sell, buy, seller!, buyer!, tokensToTrade); const smrPayments = await createSmrPayments( @@ -272,14 +267,14 @@ export const matchBaseToken = async ( if (isEmpty(iotaPayments) || isEmpty(smrPayments)) { return { sellerCreditId: undefined, buyerCreditId: undefined, purchase: undefined }; } - iotaPayments.forEach((payment) => { - const docRef = build5Db().doc(`${COL.TRANSACTION}/${payment.uid}`); - transaction.create(docRef, payment); - }); - smrPayments.forEach((payment) => { - const docRef = build5Db().doc(`${COL.TRANSACTION}/${payment.uid}`); - transaction.create(docRef, payment); - }); + for (const payment of iotaPayments) { + const docRef = build5Db().doc(COL.TRANSACTION, payment.uid); + await transaction.create(docRef, payment); + } + for (const payment of smrPayments) { + const docRef = build5Db().doc(COL.TRANSACTION, payment.uid); + await transaction.create(docRef, payment); + } return { sellerCreditId: iotaPayments.find((o) => o.type === TransactionType.CREDIT)?.uid, buyerCreditId: smrPayments.find((o) => o.type === TransactionType.CREDIT)?.uid, diff --git a/packages/functions/src/triggers/token-trading/match-minted-token.ts b/packages/functions/src/triggers/token-trading/match-minted-token.ts index 50f80fdf14..b4856ca6fe 100644 --- a/packages/functions/src/triggers/token-trading/match-minted-token.ts +++ b/packages/functions/src/triggers/token-trading/match-minted-token.ts @@ -3,7 +3,6 @@ import { COL, Entity, Member, - Space, Token, TokenPurchaseAge, TokenTradeOrder, @@ -39,7 +38,7 @@ const createRoyaltyBillPayments = async ( const promises = Object.entries(royaltyFees) .filter((entry) => entry[1] > 0) .map(async ([spaceId, fee]): Promise => { - const space = await build5Db().doc(`${COL.SPACE}/${spaceId}`).get(); + const space = await build5Db().doc(COL.SPACE, spaceId).get(); const spaceAddress = getAddress(space, token.mintingData?.network!); const sellerAddress = getAddress(seller, token.mintingData?.network!); const output = await packBasicOutput(wallet, spaceAddress, 0, { @@ -238,15 +237,11 @@ export const matchMintedToken = async ( ): Promise => { const wallet = await WalletService.newWallet(token.mintingData?.network!); - const seller = (await build5Db().doc(`${COL.MEMBER}/${sell.owner}`).get())!; - const buyer = (await build5Db().doc(`${COL.MEMBER}/${buy.owner}`).get())!; + const seller = (await build5Db().doc(COL.MEMBER, sell.owner).get())!; + const buyer = (await build5Db().doc(COL.MEMBER, buy.owner).get())!; - const buyOrderTran = (await build5Db() - .doc(`${COL.TRANSACTION}/${buy.orderTransactionId}`) - .get())!; - const sellOrderTran = (await build5Db() - .doc(`${COL.TRANSACTION}/${sell.orderTransactionId}`) - .get())!; + const buyOrderTran = (await build5Db().doc(COL.TRANSACTION, buy.orderTransactionId!).get())!; + const sellOrderTran = (await build5Db().doc(COL.TRANSACTION, sell.orderTransactionId!).get())!; const tokensToTrade = Math.min( sell.count - sell.fulfilled, @@ -326,18 +321,17 @@ export const matchMintedToken = async ( ? createCreditToBuyer(token, buyer, buy, buyOrderTran, balanceLeft) : undefined; - [ + const payments = [ ...royaltyBillPayments, billPaymentToSeller, billPaymentWithNativeTokens, creditToSeller, creditToBuyer, - ] - .filter((t) => t !== undefined) - .forEach((data) => { - const docRef = build5Db().doc(`${COL.TRANSACTION}/${data!.uid}`); - transaction.create(docRef, data!); - }); + ].filter((t) => t !== undefined); + for (const data of payments) { + const docRef = build5Db().doc(COL.TRANSACTION, data!.uid); + await transaction.create(docRef, data!); + } return { purchase: { diff --git a/packages/functions/src/triggers/token-trading/match-simple-token.ts b/packages/functions/src/triggers/token-trading/match-simple-token.ts index cf095a8b24..a68cd89d2d 100644 --- a/packages/functions/src/triggers/token-trading/match-simple-token.ts +++ b/packages/functions/src/triggers/token-trading/match-simple-token.ts @@ -6,7 +6,6 @@ import { MIN_IOTA_AMOUNT, Member, SUB_COL, - Space, Token, TokenPurchaseAge, TokenTradeOrder, @@ -35,9 +34,7 @@ const createBuyPayments = async ( ) => { let salePrice = Number(bigDecimal.floor(bigDecimal.multiply(tokensToTrade, price))); const fulfilled = buy.fulfilled + tokensToTrade === buy.count; - const buyOrder = (await build5Db() - .doc(`${COL.TRANSACTION}/${buy.orderTransactionId}`) - .get())!; + const buyOrder = (await build5Db().doc(COL.TRANSACTION, buy.orderTransactionId!).get())!; const royaltyFees = await getRoyaltyFees(salePrice, seller.tokenTradingFeePercentage); let balanceLeft = buy.balance - salePrice; @@ -57,7 +54,7 @@ const createBuyPayments = async ( const royaltyPaymentPromises = Object.entries(royaltyFees) .filter((entry) => entry[1] > 0) .map(async ([space, fee]): Promise => { - const spaceData = await build5Db().doc(`${COL.SPACE}/${space}`).get(); + const spaceData = await build5Db().doc(COL.SPACE, space).get(); return { project: getProject(buy), type: TransactionType.BILL_PAYMENT, @@ -145,33 +142,33 @@ const createBuyPayments = async ( return [billPayment, ...royaltyPayments, credit]; }; -const updateSaleLock = ( +const updateSaleLock = async ( transaction: ITransaction, prev: TokenTradeOrder, sell: TokenTradeOrder, ) => { const diff = sell.fulfilled - prev.fulfilled; - const docRef = build5Db().doc(`${COL.TOKEN}/${sell.token}/${SUB_COL.DISTRIBUTION}/${sell.owner}`); + const docRef = build5Db().doc(COL.TOKEN, sell.token, SUB_COL.DISTRIBUTION, sell.owner); const data = { lockedForSale: build5Db().inc(-diff), sold: build5Db().inc(diff), tokenOwned: build5Db().inc(-diff), }; - transaction.set(docRef, data, true); + await transaction.upsert(docRef, data); }; -const updateBuyerDistribution = ( +const updateBuyerDistribution = async ( transaction: ITransaction, prev: TokenTradeOrder, buy: TokenTradeOrder, ) => { const diff = buy.fulfilled - prev.fulfilled; - const docRef = build5Db().doc(`${COL.TOKEN}/${buy.token}/${SUB_COL.DISTRIBUTION}/${buy.owner}`); + const docRef = build5Db().doc(COL.TOKEN, buy.token, SUB_COL.DISTRIBUTION, buy.owner); const data = { totalPurchased: build5Db().inc(diff), tokenOwned: build5Db().inc(diff), }; - transaction.set(docRef, data, true); + await transaction.upsert(docRef, data); }; export const matchSimpleToken = async ( @@ -184,8 +181,8 @@ export const matchSimpleToken = async ( ): Promise => { const tokensToTrade = Math.min(sell.count - sell.fulfilled, buy.count - buy.fulfilled); - const seller = (await build5Db().doc(`${COL.MEMBER}/${sell.owner}`).get())!; - const buyer = (await build5Db().doc(`${COL.MEMBER}/${buy.owner}`).get())!; + const seller = (await build5Db().doc(COL.MEMBER, sell.owner).get())!; + const buyer = (await build5Db().doc(COL.MEMBER, buy.owner).get())!; const buyerPayments = await createBuyPayments( token, buy, @@ -200,7 +197,7 @@ export const matchSimpleToken = async ( return { purchase: undefined, buyerCreditId: undefined, sellerCreditId: undefined }; } buyerPayments.forEach((p) => { - const docRef = build5Db().doc(`${COL.TRANSACTION}/${p.uid}`); + const docRef = build5Db().doc(COL.TRANSACTION, p.uid); return transaction.create(docRef, p); }); @@ -229,13 +226,13 @@ export const matchSimpleToken = async ( }; }; -export const updateSellLockAndDistribution = ( +export const updateSellLockAndDistribution = async ( transaction: ITransaction, prevBuy: TokenTradeOrder, buy: TokenTradeOrder, prevSell: TokenTradeOrder, sell: TokenTradeOrder, ) => { - updateSaleLock(transaction, prevSell, sell); - updateBuyerDistribution(transaction, prevBuy, buy); + await updateSaleLock(transaction, prevSell, sell); + await updateBuyerDistribution(transaction, prevBuy, buy); }; diff --git a/packages/functions/src/triggers/token-trading/match-token.ts b/packages/functions/src/triggers/token-trading/match-token.ts index ea0df2664a..e030fa4273 100644 --- a/packages/functions/src/triggers/token-trading/match-token.ts +++ b/packages/functions/src/triggers/token-trading/match-token.ts @@ -1,4 +1,4 @@ -import { IQuery, ITransaction, build5Db, getSnapshot } from '@build-5/database'; +import { IQuery, ITransaction, PgTokenMarket, build5Db } from '@build-5/database'; import { COL, Token, @@ -10,7 +10,7 @@ import { } from '@build-5/interfaces'; import dayjs from 'dayjs'; import bigDecimal from 'js-big-decimal'; -import { cloneDeep, last } from 'lodash'; +import { cloneDeep } from 'lodash'; import { matchBaseToken } from './match-base-token'; import { matchMintedToken } from './match-minted-token'; import { matchSimpleToken, updateSellLockAndDistribution } from './match-simple-token'; @@ -21,7 +21,7 @@ export interface Match { readonly buyerCreditId: string | undefined; } -type Query = (trade: TokenTradeOrder, startAfter: string) => Promise; +type Query = (trade: TokenTradeOrder) => IQuery; type Matcher = ( transaction: ITransaction, token: Token, @@ -36,60 +36,39 @@ type PostMatchAction = ( buy: TokenTradeOrder, prevSell: TokenTradeOrder, sell: TokenTradeOrder, -) => void; +) => Promise; export const TOKEN_TRADE_ORDER_FETCH_LIMIT = 20; -export const matchTradeOrder = async (tradeOrder: TokenTradeOrder) => { - const token = (await build5Db().doc(`${COL.TOKEN}/${tradeOrder.token}`).get())!; +export const matchTradeOrder = async (tradeOrder: PgTokenMarket) => { + const token = (await build5Db().doc(COL.TOKEN, tradeOrder.token!).get())!; const query = getQuery(token); const matcher = getMatcher(token); const postMatchActions = getPostMatchActions(token); - let lastDocId = ''; - do { - lastDocId = await runTradeOrderMatching( - query, - matcher, - postMatchActions, - lastDocId, - token, - tradeOrder.uid, - ); - } while (lastDocId); + await runTradeOrderMatching(query, matcher, postMatchActions, token, tradeOrder.uid); if (tradeOrder.type === TokenTradeOrderType.BUY) { - do { - lastDocId = await runTradeOrderMatching( - query, - matcher, - postMatchActions, - lastDocId, - token, - tradeOrder.uid, - false, - ); - } while (lastDocId); + await runTradeOrderMatching(query, matcher, postMatchActions, token, tradeOrder.uid, false); } }; -const runTradeOrderMatching = async ( +const runTradeOrderMatching = ( query: Query, matcher: Matcher, postMatchActions: PostMatchAction | undefined, - lastDocId: string, token: Token, tradeOrderId: string, invertedPrice = true, ) => build5Db().runTransaction(async (transaction) => { - const tradeOrderDocRef = build5Db().doc(`${COL.TOKEN_MARKET}/${tradeOrderId}`); - const tradeOrder = (await transaction.get(tradeOrderDocRef))!; + const tradeOrderDocRef = build5Db().doc(COL.TOKEN_MARKET, tradeOrderId); + const tradeOrder = (await transaction.get(tradeOrderDocRef))!; if (tradeOrder.status !== TokenTradeOrderStatus.ACTIVE) { - return ''; + return 0; } - const docs = await (await query(tradeOrder, lastDocId)).get(); + const docs = await query(tradeOrder).get(); const trades = await getTradesSorted(transaction, docs); let update = cloneDeep(tradeOrder); @@ -122,21 +101,33 @@ const runTradeOrderMatching = async ( } const sell = updateTrade(prevSell, purchase); const buy = updateTrade(prevBuy, purchase, buyerCreditId); - const docRef = build5Db().doc(`${COL.TOKEN_MARKET}/${trade!.uid}`); - transaction.update(docRef, isSell ? buy : sell); + const docRef = build5Db().doc(COL.TOKEN_MARKET, trade!.uid); + await transaction.update(docRef, toPgTrade(isSell ? buy : sell)); if (postMatchActions) { - postMatchActions(transaction, prevBuy, buy, prevSell, sell); + await postMatchActions(transaction, prevBuy, buy, prevSell, sell); } - const purchaseDocRef = build5Db().doc(`${COL.TOKEN_PURCHASE}/${purchase.uid}`); - transaction.create(purchaseDocRef, purchase); + const purchaseDocRef = build5Db().doc(COL.TOKEN_PURCHASE, purchase.uid); + await transaction.create(purchaseDocRef, purchase); update = isSell ? sell : buy; } - transaction.update(build5Db().doc(`${COL.TOKEN_MARKET}/${tradeOrder.uid}`), update); - return update.status === TokenTradeOrderStatus.SETTLED ? '' : last(docs)?.uid || ''; + await transaction.update(build5Db().doc(COL.TOKEN_MARKET, tradeOrder.uid), toPgTrade(update)); + return update.status === TokenTradeOrderStatus.SETTLED ? 0 : docs.length; }); +const toPgTrade = (trade: TokenTradeOrder): PgTokenMarket => ({ + ...trade, + createdOn: trade.createdOn?.toDate(), + updatedOn: trade.updatedOn?.toDate(), + tokenStatus: trade.tokenStatus, + type: trade.type, + status: trade.status, + expiresAt: trade.expiresAt.toDate(), + sourceNetwork: trade.sourceNetwork, + targetNetwork: trade.targetNetwork, +}); + const updateTrade = (trade: TokenTradeOrder, purchase: TokenPurchase, creditTransactionId = '') => { const fulfilled = trade.fulfilled + purchase.count; const salePrice = bigDecimal.floor(bigDecimal.multiply(purchase.count, purchase.price)); @@ -178,8 +169,7 @@ const getPostMatchActions = (token: Token) => { } }; -const getSimpleTokenQuery = async (trade: TokenTradeOrder, startAfter = '') => { - const lastDoc = await getSnapshot(COL.TOKEN_MARKET, startAfter); +const getSimpleTokenQuery = (trade: TokenTradeOrder) => { const type = trade.type === TokenTradeOrderType.BUY ? TokenTradeOrderType.SELL : TokenTradeOrderType.BUY; return build5Db() @@ -189,30 +179,22 @@ const getSimpleTokenQuery = async (trade: TokenTradeOrder, startAfter = '') => { .where('price', trade.type === TokenTradeOrderType.BUY ? '<=' : '>=', trade.price) .where('status', '==', TokenTradeOrderStatus.ACTIVE) .orderBy('price', trade.type === TokenTradeOrderType.BUY ? 'asc' : 'desc') - .orderBy('createdOn') - .startAfter(lastDoc) - .limit(TOKEN_TRADE_ORDER_FETCH_LIMIT); + .orderBy('createdOn'); }; -const getBaseTokenTradeQuery = async (trade: TokenTradeOrder, startAfter = '') => { - const lastDoc = await getSnapshot(COL.TOKEN_MARKET, startAfter); - return build5Db() +const getBaseTokenTradeQuery = (trade: TokenTradeOrder) => + build5Db() .collection(COL.TOKEN_MARKET) .where('sourceNetwork', '==', trade.targetNetwork) .where('token', '==', trade.token) .where('price', trade.type === TokenTradeOrderType.BUY ? '<=' : '>=', trade.price) .where('status', '==', TokenTradeOrderStatus.ACTIVE) .orderBy('price', trade.type === TokenTradeOrderType.BUY ? 'asc' : 'desc') - .orderBy('createdOn') - .startAfter(lastDoc) - .limit(TOKEN_TRADE_ORDER_FETCH_LIMIT); -}; + .orderBy('createdOn'); const getTradesSorted = async (transaction: ITransaction, unsortedTrades: TokenTradeOrder[]) => { - const unsortedTradesDocs = unsortedTrades.map((ut) => - build5Db().doc(`${COL.TOKEN_MARKET}/${ut.uid}`), - ); - const trades = await transaction.getAll(...unsortedTradesDocs); + const unsortedTradesDocs = unsortedTrades.map((ut) => build5Db().doc(COL.TOKEN_MARKET, ut.uid)); + const trades = await transaction.getAll(...unsortedTradesDocs); return trades.sort((a, b) => { const price = a?.type === TokenTradeOrderType.SELL ? a.price - b!.price : b!.price - a!.price; const createdOn = dayjs(a!.createdOn?.toDate()).isBefore(dayjs(b!.createdOn?.toDate())) diff --git a/packages/functions/src/triggers/token-trading/token-purchase.trigger.ts b/packages/functions/src/triggers/token-trading/token-purchase.trigger.ts index 3e0da6d1c5..b0d7aa3ae6 100644 --- a/packages/functions/src/triggers/token-trading/token-purchase.trigger.ts +++ b/packages/functions/src/triggers/token-trading/token-purchase.trigger.ts @@ -1,24 +1,20 @@ -import { build5Db } from '@build-5/database'; -import { COL, SUB_COL, TokenPurchase, TokenPurchaseAge } from '@build-5/interfaces'; -import { FirestoreDocEvent } from '../common'; +import { PgTokenPurchase, PgTokenStatsUpdate, build5Db } from '@build-5/database'; +import { COL, SUB_COL } from '@build-5/interfaces'; +import { PgDocEvent } from '../common'; -export const onTokenPurchaseCreated = async (event: FirestoreDocEvent) => { +export const onTokenPurchaseCreated = async (event: PgDocEvent) => { const { curr } = event; if (!curr || !curr.token) { return; } - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${curr.token}`); - const statsDocRef = tokenDocRef.collection(SUB_COL.STATS).doc(curr.token); - const volume = Object.values(TokenPurchaseAge).reduce( - (acc, act) => ({ ...acc, [act]: build5Db().inc(curr.count) }), - {}, - ); - const statsData = { + const statsDocRef = build5Db().doc(COL.TOKEN, curr.token, SUB_COL.STATS, curr.token); + const statsData: PgTokenStatsUpdate = { parentId: curr.token, - parentCol: COL.TOKEN, - volumeTotal: build5Db().inc(curr.count), - volume, + volumeTotal: build5Db().inc(curr.count!), + volume_in24h: build5Db().inc(curr.count!), + volume_in48h: build5Db().inc(curr.count!), + volume_in7d: build5Db().inc(curr.count!), }; - statsDocRef.set(statsData, true); + await statsDocRef.upsert(statsData); }; diff --git a/packages/functions/src/triggers/token-trading/token-trade-order.trigger.ts b/packages/functions/src/triggers/token-trading/token-trade-order.trigger.ts index eeb4f6a2db..06cb3285b7 100644 --- a/packages/functions/src/triggers/token-trading/token-trade-order.trigger.ts +++ b/packages/functions/src/triggers/token-trading/token-trade-order.trigger.ts @@ -1,19 +1,10 @@ -import { build5Db } from '@build-5/database'; -import { - COL, - Member, - Project, - ProjectBilling, - StakeType, - SUB_COL, - TokenDistribution, - TokenTradeOrder, -} from '@build-5/interfaces'; +import { build5Db, PgTokenMarket } from '@build-5/database'; +import { COL, Member, ProjectBilling, StakeType, SUB_COL } from '@build-5/interfaces'; import { getStakeForType, getTier } from '../../services/stake.service'; -import { FirestoreDocEvent } from '../common'; +import { PgDocEvent } from '../common'; import { matchTradeOrder } from './match-token'; -export const onTokenTradeOrderWrite = async (event: FirestoreDocEvent) => { +export const onTokenTradeOrderWrite = async (event: PgDocEvent) => { const { prev, curr } = event; if (!curr) { return; @@ -25,13 +16,17 @@ export const onTokenTradeOrderWrite = async (event: FirestoreDocEvent { - const project = await build5Db().get(COL.PROJECT, projectId); - if (project?.config?.billing !== ProjectBilling.TOKEN_BASE) { + const project = await build5Db().doc(COL.PROJECT, projectId).get(); + if (project?.config?.billing !== ProjectBilling.TOKEN_BASED) { return 0; } - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${project.config.nativeTokenUid}`); - const distributionDocRef = tokenDocRef.collection(SUB_COL.DISTRIBUTION).doc(member.uid); - const distribution = await distributionDocRef.get(); + const distributionDocRef = build5Db().doc( + COL.TOKEN, + project.config.nativeTokenUid!, + SUB_COL.DISTRIBUTION, + member.uid, + ); + const distribution = await distributionDocRef.get(); const stakeValue = getStakeForType(distribution, StakeType.DYNAMIC); return getTier(project.config.tiers || [], stakeValue); }; diff --git a/packages/functions/src/triggers/token.trigger.ts b/packages/functions/src/triggers/token.trigger.ts index 02dbd9d4c7..d0ea2f596b 100644 --- a/packages/functions/src/triggers/token.trigger.ts +++ b/packages/functions/src/triggers/token.trigger.ts @@ -1,4 +1,4 @@ -import { IBatch, build5Db } from '@build-5/database'; +import { IBatch, PgToken, build5Db } from '@build-5/database'; import { COL, DEFAULT_NETWORK, @@ -6,12 +6,11 @@ import { MIN_IOTA_AMOUNT, MediaStatus, Member, + Network, SUB_COL, Space, - Token, TokenDistribution, TokenStatus, - TokenTradeOrder, TokenTradeOrderStatus, Transaction, TransactionPayloadType, @@ -23,6 +22,7 @@ import { WalletService } from '../services/wallet/wallet.service'; import { getAddress } from '../utils/address.utils'; import { downloadMediaAndPackCar, tokenToIpfsMetadata } from '../utils/car.utils'; import { getProject, guardedRerun } from '../utils/common.utils'; +import { logger } from '../utils/logger'; import { getRoyaltyFees } from '../utils/royalty.utils'; import { cancelTradeOrderUtil } from '../utils/token-trade.utils'; import { @@ -33,9 +33,9 @@ import { orderDocRef, } from '../utils/token.utils'; import { getRandomEthAddress } from '../utils/wallet.utils'; -import { FirestoreDocEvent } from './common'; +import { PgDocEvent } from './common'; -export const onTokenStatusUpdated = async (event: FirestoreDocEvent) => { +export const onTokenStatusUpdated = async (event: PgDocEvent) => { const { prev, curr } = event; if (prev?.status === TokenStatus.AVAILABLE && curr?.status === TokenStatus.PROCESSING) { @@ -50,15 +50,15 @@ export const onTokenStatusUpdated = async (event: FirestoreDocEvent) => { return await mintToken(curr); } - if (prev?.mintingData?.tokensInVault && curr?.mintingData?.tokensInVault === 0) { + if (prev?.mintingData_tokensInVault && curr?.mintingData_tokensInVault === 0) { await onTokenVaultEmptied(curr); } }; -const getTokenCount = (token: Token, amount: number) => Math.floor(amount / token.pricePerToken); +const getTokenCount = (token: PgToken, amount: number) => Math.floor(amount / token.pricePerToken!); const getBoughtByMember = ( - token: Token, + token: PgToken, totalDeposit: number, totalSupply: number, totalBought: number, @@ -88,13 +88,13 @@ const getTotalPaid = (pricePerToken: number, boughtByMember: number) => { const getMemberDistribution = ( distribution: TokenDistribution, - token: Token, + token: PgToken, totalSupply: number, totalBought: number, ): TokenDistribution => { const totalDeposit = distribution.totalDeposit || 0; const boughtByMember = getBoughtByMember(token, totalDeposit, totalSupply, totalBought); - const totalPaid = getTotalPaid(token.pricePerToken, boughtByMember); + const totalPaid = getTotalPaid(token.pricePerToken!, boughtByMember); const refundedAmount = Number(bigDecimal.subtract(totalDeposit, totalPaid)); return { uid: distribution.uid, @@ -113,7 +113,7 @@ const getFlooredDistribution = (distribution: TokenDistribution): TokenDistribut }; const createBillAndRoyaltyPayment = async ( - token: Token, + token: PgToken, distribution: TokenDistribution, payments: Transaction[], order: Transaction, @@ -126,14 +126,14 @@ const createBillAndRoyaltyPayment = async ( let balance = distribution.totalPaid + (distribution.refundedAmount! < MIN_IOTA_AMOUNT ? distribution.refundedAmount! : 0); - const member = await memberDocRef(distribution.uid!).get(); + const member = await build5Db().doc(COL.MEMBER, distribution.uid!).get(); const [royaltySpaceId, fee] = Object.entries( await getRoyaltyFees(balance, member.tokenPurchaseFeePercentage, true), )[0]; let royaltyPayment: Transaction | undefined = undefined; if (fee >= MIN_IOTA_AMOUNT && balance - fee >= MIN_IOTA_AMOUNT) { - const royaltySpace = await build5Db().doc(`${COL.SPACE}/${royaltySpaceId}`).get(); + const royaltySpace = await build5Db().doc(COL.SPACE, royaltySpaceId).get(); const network = order.network || DEFAULT_NETWORK; royaltyPayment = { project: getProject(order), @@ -159,7 +159,7 @@ const createBillAndRoyaltyPayment = async ( tokenSymbol: token.symbol, }, }; - const royaltyPaymentDocRef = build5Db().doc(`${COL.TRANSACTION}/${royaltyPayment.uid}`); + const royaltyPaymentDocRef = build5Db().doc(COL.TRANSACTION, royaltyPayment.uid); batch.create(royaltyPaymentDocRef, royaltyPayment); balance -= fee; } @@ -189,13 +189,13 @@ const createBillAndRoyaltyPayment = async ( tokenSymbol: token.symbol, }, }; - const billPaymentDocRef = build5Db().doc(`${COL.TRANSACTION}/${billPayment.uid}`); + const billPaymentDocRef = build5Db().doc(COL.TRANSACTION, billPayment.uid); batch.create(billPaymentDocRef, billPayment); return { billPaymentId: billPayment.uid, royaltyBillPaymentId: royaltyPayment?.uid || '' }; }; const createCredit = async ( - token: Token, + token: PgToken, distribution: TokenDistribution, payments: Transaction[], order: Transaction, @@ -206,7 +206,7 @@ const createCredit = async ( } const member = await memberDocRef(distribution.uid!).get(); const tranId = getRandomEthAddress(); - const docRef = build5Db().doc(`${COL.TRANSACTION}/${tranId}`); + const docRef = build5Db().doc(COL.TRANSACTION, tranId); const network = order.network || DEFAULT_NETWORK; const data: Transaction = { project: getProject(order), @@ -234,16 +234,20 @@ const createCredit = async ( return tranId; }; -const reconcileBuyer = (token: Token) => async (distribution: TokenDistribution) => { +const reconcileBuyer = (token: PgToken) => async (distribution: TokenDistribution) => { const batch = build5Db().batch(); - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${token.uid}`); - const distributionDoc = tokenDocRef.collection(SUB_COL.DISTRIBUTION).doc(distribution.uid!); + const distributionDoc = build5Db().doc( + COL.TOKEN, + token.uid, + SUB_COL.DISTRIBUTION, + distribution.uid!, + ); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${token.space}`); - const space = (await spaceDocRef.get())!; + const spaceDocRef = build5Db().doc(COL.SPACE, token.space!); + const space = (await spaceDocRef.get())!; const order = await orderDocRef(distribution.uid!, token).get(); - const payments = await allPaymentsQuery(distribution.uid!, token.uid).get(); + const payments = await allPaymentsQuery(distribution.uid!, token.uid).get(); const { billPaymentId, royaltyBillPaymentId } = await createBillAndRoyaltyPayment( token, @@ -261,13 +265,17 @@ const reconcileBuyer = (token: Token) => async (distribution: TokenDistribution) batch, ); + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { stakeExpiry, ...rest } = distribution; batch.update(distributionDoc, { - ...distribution, + ...rest, tokenOwned: build5Db().inc(distribution.totalBought || 0), reconciled: true, billPaymentId, royaltyBillPaymentId, creditPaymentId, + mintedClaimedOn: distribution.mintedClaimedOn?.toDate(), + createdOn: distribution.createdOn?.toDate(), }); await batch.commit(); }; @@ -275,14 +283,14 @@ const reconcileBuyer = (token: Token) => async (distribution: TokenDistribution) const distributeLeftoverTokens = ( distributions: TokenDistribution[], totalPublicSupply: number, - token: Token, + token: PgToken, ) => { let tokensLeft = totalPublicSupply - distributions.reduce((sum, p) => sum + p.totalBought!, 0); let i = 0; let sell = false; while (tokensLeft) { const distribution = { ...distributions[i] }; - if (distribution.refundedAmount! >= token.pricePerToken) { + if (distribution.refundedAmount! >= token.pricePerToken!) { sell = true; tokensLeft--; distribution.refundedAmount = Number( @@ -299,18 +307,17 @@ const distributeLeftoverTokens = ( } }; -const cancelPublicSale = async (token: Token) => { - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${token.uid}`); - const distributions = await tokenDocRef - .collection(SUB_COL.DISTRIBUTION) +const cancelPublicSale = async (token: PgToken) => { + const distributions = await build5Db() + .collection(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION) .where('totalDeposit', '>', 0) - .get(); + .get(); const promises = distributions.map(async (distribution) => { const batch = build5Db().batch(); const order = await orderDocRef(distribution.uid!, token).get(); - const payments = await allPaymentsQuery(distribution.uid!, token.uid).get(); + const payments = await allPaymentsQuery(distribution.uid!, token.uid).get(); const creditPaymentId = await createCredit( token, { ...distribution, refundedAmount: distribution?.totalDeposit }, @@ -319,7 +326,12 @@ const cancelPublicSale = async (token: Token) => { batch, ); - const distributionDocRef = tokenDocRef.collection(SUB_COL.DISTRIBUTION).doc(distribution.uid!); + const distributionDocRef = build5Db().doc( + COL.TOKEN, + token.uid, + SUB_COL.DISTRIBUTION, + distribution.uid!, + ); batch.update(distributionDocRef, { creditPaymentId, totalDeposit: 0 }); await batch.commit(); @@ -330,19 +342,18 @@ const cancelPublicSale = async (token: Token) => { .filter((r) => r.status === 'rejected') .map((r) => String((r).reason)); const status = isEmpty(errors) ? TokenStatus.AVAILABLE : TokenStatus.ERROR; - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).update({ status }); + await build5Db().doc(COL.TOKEN, token.uid).update({ status }); if (status === TokenStatus.ERROR) { - console.error('Token processing error', token.uid, errors); + logger.error('Token processing error', token.uid, errors); } }; -const processTokenDistribution = async (token: Token) => { - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${token.uid}`); - const distributionsSnap = await tokenDocRef - .collection(SUB_COL.DISTRIBUTION) +const processTokenDistribution = async (token: PgToken) => { + const distributionsSnap = await build5Db() + .collection(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION) .where('totalDeposit', '>', 0) - .get(); + .get(); const totalBought = distributionsSnap.reduce( (sum, doc) => sum + getTokenCount(token, doc.totalDeposit || 0), 0, @@ -352,7 +363,7 @@ const processTokenDistribution = async (token: Token) => { const distributions = distributionsSnap .sort((a, b) => (b.totalDeposit || 0) - (a.totalDeposit || 0)) - .map((d) => getMemberDistribution(d, token, totalPublicSupply, totalBought)); + .map((d) => getMemberDistribution(d, token, totalPublicSupply, totalBought)); if (totalBought > totalPublicSupply) { distributeLeftoverTokens(distributions, totalPublicSupply, token); @@ -364,59 +375,60 @@ const processTokenDistribution = async (token: Token) => { .filter((r) => r.status === 'rejected') .map((r) => String((r).reason)); const status = isEmpty(errors) ? TokenStatus.PRE_MINTED : TokenStatus.ERROR; - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).update({ status }); + await build5Db().doc(COL.TOKEN, token.uid).update({ status }); if (status === TokenStatus.ERROR) { - console.error('Token processing error', token.uid, errors); + logger.error('Token processing error', token.uid, errors); } }; -const mintToken = async (token: Token) => { +const mintToken = async (token: PgToken) => { await cancelAllActiveSales(token!.uid); await setIpfsData(token); + const network = token.mintingData_network as Network; const order: Transaction = { project: getProject(token), type: TransactionType.MINT_TOKEN, uid: getRandomEthAddress(), - member: token.mintingData?.mintedBy, + member: token.mintingData_mintedBy!, space: token!.space, - network: token.mintingData?.network!, + network, payload: { type: TransactionPayloadType.MINT_ALIAS, - amount: token.mintingData?.aliasStorageDeposit, - sourceAddress: token.mintingData?.vaultAddress, + amount: token.mintingData_aliasStorageDeposit, + sourceAddress: token.mintingData_vaultAddress, token: token.uid, }, }; - await build5Db().doc(`${COL.TRANSACTION}/${order.uid}`).create(order); + await build5Db().doc(COL.TRANSACTION, order.uid).create(order); }; const cancelAllActiveSales = async (token: string) => { - const runTransaction = () => + const runTransactions = () => build5Db().runTransaction(async (transaction) => { const snap = build5Db() .collection(COL.TOKEN_MARKET) .where('status', '==', TokenTradeOrderStatus.ACTIVE) .where('token', '==', token) .limit(150) - .get(); - const docRefs = (await snap).map((to) => build5Db().doc(`${COL.TOKEN_MARKET}/${to.uid}`)); - const promises = (await transaction.getAll(...docRefs)) + .get(); + const docRefs = (await snap).map((to) => build5Db().doc(COL.TOKEN_MARKET, to.uid)); + const promises = (await transaction.getAll(...docRefs)) .filter((d) => d && d.status === TokenTradeOrderStatus.ACTIVE) .map((d) => cancelTradeOrderUtil(transaction, d!, TokenTradeOrderStatus.CANCELLED_MINTING_TOKEN), ); return (await Promise.all(promises)).length; }); - await guardedRerun(async () => (await runTransaction()) !== 0); + await guardedRerun(async () => (await runTransactions()) !== 0); }; -const setIpfsData = async (token: Token) => { +const setIpfsData = async (token: PgToken) => { const metadata = tokenToIpfsMetadata(token); const ipfs = await downloadMediaAndPackCar(token.uid, token.icon!, metadata); - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).update({ + await build5Db().doc(COL.TOKEN, token.uid).update({ mediaStatus: MediaStatus.PENDING_UPLOAD, ipfsMedia: ipfs.ipfsMedia, ipfsMetadata: ipfs.ipfsMetadata, @@ -424,32 +436,34 @@ const setIpfsData = async (token: Token) => { }); }; -const onTokenVaultEmptied = async (token: Token) => { - const wallet = await WalletService.newWallet(token.mintingData?.network); - const { amount: vaultBalance } = await wallet.getBalance(token.mintingData?.vaultAddress!); - const minter = await build5Db().doc(`${COL.MEMBER}/${token.mintingData?.mintedBy}`).get(); +const onTokenVaultEmptied = async (token: PgToken) => { + const network = token.mintingData_network as Network; + const wallet = await WalletService.newWallet(network); + const { amount: vaultBalance } = await wallet.getBalance(token.mintingData_vaultAddress!); + const minter = await build5Db().doc(COL.MEMBER, token.mintingData_mintedBy!).get(); const paymentsSnap = await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.PAYMENT) - .where('payload.sourceTransaction', 'array-contains', token.mintingData?.vaultAddress!) - .get(); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + .where('payload_sourceTransaction', 'array-contains', token.mintingData_vaultAddress! as any) + .get(); const credit: Transaction = { project: getProject(token), type: TransactionType.CREDIT, uid: getRandomEthAddress(), space: token.space, member: minter!.uid, - network: token.mintingData?.network!, + network, payload: { type: TransactionPayloadType.TOKEN_VAULT_EMPTIED, dependsOnBillPayment: true, amount: Number(vaultBalance), - sourceAddress: token.mintingData?.vaultAddress!, - targetAddress: getAddress(minter, token.mintingData?.network!), + sourceAddress: token.mintingData_vaultAddress!, + targetAddress: getAddress(minter, network), sourceTransaction: paymentsSnap.map((p) => p.uid), token: token.uid, tokenSymbol: token.symbol, }, }; - await build5Db().doc(`${COL.TRANSACTION}/${credit.uid}`).create(credit); + await build5Db().doc(COL.TRANSACTION, credit.uid).create(credit); }; diff --git a/packages/functions/src/triggers/transaction-trigger/airdrop.claim.ts b/packages/functions/src/triggers/transaction-trigger/airdrop.claim.ts index 224679b315..f4d1a0b219 100644 --- a/packages/functions/src/triggers/transaction-trigger/airdrop.claim.ts +++ b/packages/functions/src/triggers/transaction-trigger/airdrop.claim.ts @@ -1,14 +1,14 @@ -import { ITransaction, build5Db } from '@build-5/database'; +import { ITransaction, PgTransaction, build5Db } from '@build-5/database'; import { COL, Entity, IgnoreWalletReason, Member, + Network, SUB_COL, Stake, StakeType, Token, - TokenDistribution, TokenDrop, TokenDropStatus, TokenStatus, @@ -24,22 +24,23 @@ import { WalletService } from '../../services/wallet/wallet.service'; import { getAddress } from '../../utils/address.utils'; import { getProject } from '../../utils/common.utils'; import { dateToTimestamp, serverTime } from '../../utils/dateTime.utils'; +import { logger } from '../../utils/logger'; import { dropToOutput } from '../../utils/token-minting-utils/member.utils'; import { getRandomEthAddress } from '../../utils/wallet.utils'; const LOOP_SIZE = 10000; -export const onAirdropClaim = async (order: Transaction) => { - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${order.payload.token}`); - const token = (await tokenDocRef.get())!; +export const onAirdropClaim = async (order: PgTransaction) => { + const tokenDocRef = build5Db().doc(COL.TOKEN, order.payload_token!); + const token = (await tokenDocRef.get())!; - if (order.payload.type === TransactionPayloadType.TOKEN_AIRDROP) { + if (order.payload_type === TransactionPayloadType.TOKEN_AIRDROP) { return await onPreMintedAirdropClaim(order, token); } return await onMintedAirdropClaim(order, token); }; -const onPreMintedAirdropClaim = async (order: Transaction, token: Token) => { +const onPreMintedAirdropClaim = async (order: PgTransaction, token: Token) => { if (![TokenStatus.AVAILABLE, TokenStatus.PRE_MINTED].includes(token.status)) { return; } @@ -48,7 +49,7 @@ const onPreMintedAirdropClaim = async (order: Transaction, token: Token) => { token, true, )(async (transaction, airdrop) => { - const airdropDocRef = build5Db().doc(`${COL.AIRDROP}/${airdrop.uid}`); + const airdropDocRef = build5Db().doc(COL.AIRDROP, airdrop.uid); const billPayment: Transaction = { project: getProject(order), @@ -56,56 +57,54 @@ const onPreMintedAirdropClaim = async (order: Transaction, token: Token) => { uid: getRandomEthAddress(), space: order.space, member: order.member, - network: order.network, + network: order.network as Network, ignoreWallet: true, ignoreWalletReason: IgnoreWalletReason.PRE_MINTED_AIRDROP_CLAIM, payload: { type: TransactionPayloadType.PRE_MINTED_AIRDROP_CLAIM, amount: 0, sourceTransaction: [order.uid], - quantity: order.payload.quantity || 0, + quantity: order.payload_quantity || 0, airdropId: airdrop.uid, token: token.uid, tokenSymbol: token.symbol, }, }; - const billPaymentDocRef = build5Db().doc(`${COL.TRANSACTION}/${billPayment.uid}`); - transaction.create(billPaymentDocRef, billPayment); + const billPaymentDocRef = build5Db().doc(COL.TRANSACTION, billPayment.uid); + await transaction.create(billPaymentDocRef, billPayment); - transaction.update(airdropDocRef, { + await transaction.update(airdropDocRef, { status: TokenDropStatus.CLAIMED, billPaymentId: billPayment.uid, }); const distributionDocRef = build5Db().doc( - `${COL.TOKEN}/${order.payload.token}/${SUB_COL.DISTRIBUTION}/${order.member}`, - ); - transaction.set( - distributionDocRef, - { - parentId: order.payload.token, - parentCol: COL.TOKEN, - uid: order.member, - tokenClaimed: build5Db().inc(airdrop.count), - tokenOwned: build5Db().inc(airdrop.count), - totalUnclaimedAirdrop: build5Db().inc(-airdrop.count), - }, - true, + COL.TOKEN, + order.payload_token!, + SUB_COL.DISTRIBUTION, + order.member, ); + await transaction.upsert(distributionDocRef, { + parentId: order.payload_token, + tokenClaimed: build5Db().inc(airdrop.count), + tokenOwned: build5Db().inc(airdrop.count), + totalUnclaimedAirdrop: build5Db().inc(-airdrop.count), + }); return billPayment.payload.amount!; }); }; -const onMintedAirdropClaim = async (order: Transaction, token: Token) => { +const onMintedAirdropClaim = async (order: PgTransaction, token: Token) => { const paymentsSnap = await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.PAYMENT) - .where('payload.sourceTransaction', 'array-contains', order.uid) - .get(); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + .where('payload_sourceTransaction', 'array-contains', order.uid as any) + .get(); const paymentsId = paymentsSnap.map((d) => d.uid); - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${order.member}`); - const member = (await memberDocRef.get())!; + const memberDocRef = build5Db().doc(COL.MEMBER, order.member!); + const member = (await memberDocRef.get())!; const wallet = await WalletService.newWallet(token.mintingData?.network!); let storageDepositUsed = await claimOwnedMintedTokens(order, paymentsId, token, member, wallet); @@ -114,7 +113,7 @@ const onMintedAirdropClaim = async (order: Transaction, token: Token) => { order, token, )(async (transaction, airdrop) => { - const airdropDocRef = build5Db().doc(`${COL.AIRDROP}/${airdrop.uid}`); + const airdropDocRef = build5Db().doc(COL.AIRDROP, airdrop.uid); const billPayment = await mintedDropToBillPayment( order, @@ -124,84 +123,89 @@ const onMintedAirdropClaim = async (order: Transaction, token: Token) => { member, wallet, ); - const billPaymentDocRef = build5Db().doc(`${COL.TRANSACTION}/${billPayment.uid}`); - transaction.create(billPaymentDocRef, billPayment); const stake = mintedDropToStake(order, airdrop, billPayment); if (stake) { - const stakeDocRef = build5Db().doc(`${COL.STAKE}/${stake.uid}`); - transaction.create(stakeDocRef, stake); + const stakeDocRef = build5Db().doc(COL.STAKE, stake.uid); + await transaction.create(stakeDocRef, stake); } - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${token.uid}`); + const billPaymentDocRef = build5Db().doc(COL.TRANSACTION, billPayment.uid); + await transaction.create(billPaymentDocRef, billPayment); + + const tokenDocRef = build5Db().doc(COL.TOKEN, token.uid); if (!airdrop.sourceAddress) { - transaction.update(tokenDocRef, { - 'mintingData.tokensInVault': build5Db().inc(-airdrop.count), + await transaction.update(tokenDocRef, { + mintingData_tokensInVault: build5Db().inc(-airdrop.count), }); } if (airdrop.orderId) { - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${airdrop.orderId}`); - transaction.update(orderDocRef, { 'payload.unclaimedAirdrops': build5Db().inc(-1) }); + const orderDocRef = build5Db().doc(COL.TRANSACTION, airdrop.orderId); + await transaction.update(orderDocRef, { payload_unclaimedAirdrops: build5Db().inc(-1) }); } - const distributionDocRef = tokenDocRef.collection(SUB_COL.DISTRIBUTION).doc(member.uid); - transaction.set( - distributionDocRef, - { - parentId: token.uid, - parentCol: COL.TOKEN, - uid: member.uid, - tokenClaimed: build5Db().inc(airdrop.count), - tokenOwned: build5Db().inc(airdrop.count), - totalUnclaimedAirdrop: build5Db().inc(-airdrop.count), - mintedClaimedOn: dayjs().toDate(), - }, - true, + const distributionDocRef = build5Db().doc( + COL.TOKEN, + token.uid, + SUB_COL.DISTRIBUTION, + member.uid, ); + await transaction.upsert(distributionDocRef, { + parentId: token.uid, + tokenClaimed: build5Db().inc(airdrop.count), + tokenOwned: build5Db().inc(airdrop.count), + totalUnclaimedAirdrop: build5Db().inc(-airdrop.count), + mintedClaimedOn: dayjs().toDate(), + }); - transaction.update(airdropDocRef, { + await transaction.update(airdropDocRef, { status: TokenDropStatus.CLAIMED, billPaymentId: billPayment.uid, }); return airdrop.isBaseToken ? 0 : billPayment.payload.amount!; }); - if (storageDepositUsed < order.payload.amount!) { - console.info('onMintedAirdropClaim', order.uid, storageDepositUsed, order.payload.amount); + if (storageDepositUsed < order.payload_amount!) { + logger.info('onMintedAirdropClaim', order.uid, storageDepositUsed, order.payload_amount); + const network = (order.network as Network)!; const credit: Transaction = { project: getProject(order), type: TransactionType.CREDIT, uid: getRandomEthAddress(), space: token.space, member: member.uid, - network: order.network, + network, payload: { type: TransactionPayloadType.CLAIM_MINTED_TOKEN, - amount: order.payload.amount! - storageDepositUsed, - sourceAddress: order.payload.targetAddress, - targetAddress: getAddress(member, order.network!), + amount: order.payload_amount! - storageDepositUsed, + sourceAddress: order.payload_targetAddress, + targetAddress: getAddress(member, network), sourceTransaction: paymentsId, token: token.uid, reconciled: true, void: false, }, }; - await build5Db().doc(`${COL.TRANSACTION}/${credit.uid}`).create(credit); + await build5Db().doc(COL.TRANSACTION, credit.uid).create(credit); } }; const claimOwnedMintedTokens = ( - order: Transaction, + order: PgTransaction, sourceTransaction: string[], token: Token, member: Member, wallet: Wallet, ) => build5Db().runTransaction(async (transaction) => { - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${token.uid}`); - const distributionDocRef = tokenDocRef.collection(SUB_COL.DISTRIBUTION).doc(order.member!); - const distribution = (await transaction.get(distributionDocRef))!; + const distributionDocRef = build5Db().doc( + COL.TOKEN, + token.uid, + SUB_COL.DISTRIBUTION, + order.member!, + ); + const distribution = (await transaction.get(distributionDocRef))!; if (distribution?.mintedClaimedOn || !distribution?.tokenOwned) { return 0; } @@ -225,23 +229,26 @@ const claimOwnedMintedTokens = ( member, wallet, ); - const billPaymentDocRef = build5Db().doc(`${COL.TRANSACTION}/${billPayment.uid}`); - transaction.create(billPaymentDocRef, billPayment); const stake = mintedDropToStake(order, airdrop, billPayment); if (stake) { - const stakeDocRef = build5Db().doc(`${COL.STAKE}/${stake.uid}`); - transaction.create(stakeDocRef, stake); + const stakeDocRef = build5Db().doc(COL.STAKE, stake.uid); + await transaction.create(stakeDocRef, stake); } - transaction.update(distributionDocRef, { mintedClaimedOn: dayjs().toDate() }); - transaction.update(tokenDocRef, { - 'mintingData.tokensInVault': build5Db().inc(-airdrop.count), + + const billPaymentDocRef = build5Db().doc(COL.TRANSACTION, billPayment.uid); + await transaction.create(billPaymentDocRef, billPayment); + + await transaction.update(distributionDocRef, { mintedClaimedOn: dayjs().toDate() }); + const tokenDocRef = build5Db().doc(COL.TOKEN, token.uid); + await transaction.update(tokenDocRef, { + mintingData_tokensInVault: build5Db().inc(-airdrop.count), }); return billPayment.payload.amount!; }); const mintedDropToBillPayment = async ( - order: Transaction, + order: PgTransaction, sourceTransaction: string[], token: Token, drop: TokenDrop, @@ -257,7 +264,7 @@ const mintedDropToBillPayment = async ( uid: getRandomEthAddress(), space: token.space, member: order.member, - network: order.network, + network: order.network as Network, payload: { type: drop.isBaseToken ? TransactionPayloadType.BASE_AIRDROP_CLAIM @@ -268,7 +275,7 @@ const mintedDropToBillPayment = async ( previousOwner: token.space, ownerEntity: Entity.MEMBER, owner: order.member!, - storageDepositSourceAddress: drop.isBaseToken ? '' : order.payload.targetAddress, + storageDepositSourceAddress: drop.isBaseToken ? '' : order.payload_targetAddress, vestingAt: dayjs(drop.vestingAt.toDate()).isAfter(dayjs()) ? drop.vestingAt : null, sourceAddress: drop.sourceAddress || token.mintingData?.vaultAddress!, targetAddress: memberAddress, @@ -281,7 +288,7 @@ const mintedDropToBillPayment = async ( }; }; -const mintedDropToStake = (order: Transaction, drop: TokenDrop, billPayment: Transaction) => { +const mintedDropToStake = (order: PgTransaction, drop: TokenDrop, billPayment: Transaction) => { const vestingAt = dayjs(drop.vestingAt.toDate()); const weeks = vestingAt.diff(dayjs(), 'w'); if (weeks < 1 || drop.isBaseToken) { @@ -291,7 +298,7 @@ const mintedDropToStake = (order: Transaction, drop: TokenDrop, billPayment: Tra project: getProject(order), uid: getRandomEthAddress(), member: order.member!, - token: order.payload.token!, + token: order.payload_token!, type: drop.stakeType || StakeType.DYNAMIC, space: order.space!, amount: drop.count, @@ -307,7 +314,7 @@ const mintedDropToStake = (order: Transaction, drop: TokenDrop, billPayment: Tra }; const airdropsQuery = ( - order: Transaction, + order: PgTransaction, token: Token, member: string, isPreMintedClaim?: boolean, @@ -318,7 +325,7 @@ const airdropsQuery = ( .where('member', '==', member) .where('status', '==', TokenDropStatus.UNCLAIMED); if (isPreMintedClaim) { - query = query.where('vestingAt', '<=', serverTime()); + query = query.where('vestingAt', '<=', dayjs().toDate()); } else { query = query.where('createdOn', '<=', order.createdOn).orderBy('createdOn'); } @@ -327,23 +334,18 @@ const airdropsQuery = ( }; const runInAirdropLoop = - (order: Transaction, token: Token, isPreMintedClaim?: boolean) => + (order: PgTransaction, token: Token, isPreMintedClaim?: boolean) => async (func: (transaction: ITransaction, airdrop: TokenDrop) => Promise) => { let storageDeposit = 0; for (let i = 0; i < LOOP_SIZE; ++i) { - const snap = await airdropsQuery( - order, - token, - order.member!, - isPreMintedClaim, - ).get(); + const snap = await airdropsQuery(order, token, order.member!, isPreMintedClaim).get(); if (!snap.length) { return storageDeposit; } - const refs = snap.map((airdrop) => build5Db().doc(`${COL.AIRDROP}/${airdrop.uid}`)); storageDeposit += await build5Db().runTransaction(async (transaction) => { + const refs = snap.map((airdrop) => build5Db().doc(COL.AIRDROP, airdrop.uid)); let actStorageDeposit = 0; - const airdrops = (await transaction.getAll(...refs)).filter( + const airdrops = (await transaction.getAll(...refs)).filter( (drop) => drop!.status === TokenDropStatus.UNCLAIMED, ); for (const airdrop of airdrops) { diff --git a/packages/functions/src/triggers/transaction-trigger/award.transaction.update.ts b/packages/functions/src/triggers/transaction-trigger/award.transaction.update.ts index 88df0144af..1269f08583 100644 --- a/packages/functions/src/triggers/transaction-trigger/award.transaction.update.ts +++ b/packages/functions/src/triggers/transaction-trigger/award.transaction.update.ts @@ -1,11 +1,18 @@ -import { build5Db } from '@build-5/database'; -import { COL, Transaction, TransactionPayloadType, TransactionType } from '@build-5/interfaces'; +import { PgTransaction, build5Db } from '@build-5/database'; +import { + COL, + Network, + Transaction, + TransactionPayloadType, + TransactionType, +} from '@build-5/interfaces'; import { TransactionPayload, Utils } from '@iota/sdk'; import { getProject } from '../../utils/common.utils'; +import { getPathParts } from '../../utils/milestone'; import { getRandomEthAddress } from '../../utils/wallet.utils'; -export const onAwardUpdate = async (transaction: Transaction) => { - switch (transaction.payload.type) { +export const onAwardUpdate = async (transaction: PgTransaction) => { + switch (transaction.payload_type) { case TransactionPayloadType.MINT_ALIAS: { await onAliasMinted(transaction); break; @@ -21,17 +28,19 @@ export const onAwardUpdate = async (transaction: Transaction) => { } }; -const onAliasMinted = async (transaction: Transaction) => { - const path = transaction.payload.walletReference?.milestoneTransactionPath!; - const milestoneTransaction = (await build5Db().doc(path).get>())!; +const onAliasMinted = async (transaction: PgTransaction) => { + const { col, colId, subCol, subColId } = getPathParts( + transaction.payload_walletReference_milestoneTransactionPath!, + ); + const milestoneTransaction = (await build5Db().doc(col, colId, subCol, subColId).get())!; const aliasOutputId = Utils.computeOutputId( - Utils.transactionId(milestoneTransaction.payload as TransactionPayload), + Utils.transactionId(milestoneTransaction.payload as unknown as TransactionPayload), 0, ); - const awardDocRef = build5Db().doc(`${COL.AWARD}/${transaction.payload.award}`); + const awardDocRef = build5Db().doc(COL.AWARD, transaction.payload_award!); await awardDocRef.update({ - aliasBlockId: milestoneTransaction.blockId, + aliasBlockId: milestoneTransaction.blockId as string, aliasId: Utils.computeAliasId(aliasOutputId), }); @@ -41,35 +50,37 @@ const onAliasMinted = async (transaction: Transaction) => { uid: getRandomEthAddress(), member: transaction.member, space: transaction.space, - network: transaction.network, + network: transaction.network as Network, payload: { type: TransactionPayloadType.MINT_COLLECTION, - sourceAddress: transaction.payload.sourceAddress, - award: transaction.payload.award, + sourceAddress: transaction.payload_sourceAddress, + award: transaction.payload_award, }, }; - await build5Db().doc(`${COL.TRANSACTION}/${order.uid}`).create(order); + await build5Db().doc(COL.TRANSACTION, order.uid).create(order); }; -const onCollectionMinted = async (transaction: Transaction) => { - const path = transaction.payload.walletReference?.milestoneTransactionPath!; - const milestoneTransaction = (await build5Db().doc(path).get>())!; +const onCollectionMinted = async (transaction: PgTransaction) => { + const { col, colId, subCol, subColId } = getPathParts( + transaction.payload_walletReference_milestoneTransactionPath!, + ); + const milestoneTransaction = (await build5Db().doc(col, colId, subCol, subColId).get())!; const collectionOutputId = Utils.computeOutputId( - Utils.transactionId(milestoneTransaction.payload as TransactionPayload), + Utils.transactionId(milestoneTransaction.payload as unknown as TransactionPayload), 1, ); await build5Db() - .doc(`${COL.AWARD}/${transaction.payload.award}`) + .doc(COL.AWARD, transaction.payload_award!) .update({ - collectionBlockId: milestoneTransaction.blockId, + collectionBlockId: milestoneTransaction.blockId as string, collectionId: Utils.computeNftId(collectionOutputId), approved: true, rejected: false, }); }; -const onBadgeMinted = async (transaction: Transaction) => +const onBadgeMinted = (transaction: PgTransaction) => build5Db() - .doc(`${COL.AWARD}/${transaction.payload.award}`) + .doc(COL.AWARD, transaction.payload_award!) .update({ badgesMinted: build5Db().inc(1) }); diff --git a/packages/functions/src/triggers/transaction-trigger/collection-minting.ts b/packages/functions/src/triggers/transaction-trigger/collection-minting.ts index cf7015348f..898da48e53 100644 --- a/packages/functions/src/triggers/transaction-trigger/collection-minting.ts +++ b/packages/functions/src/triggers/transaction-trigger/collection-minting.ts @@ -1,9 +1,9 @@ -import { build5Db } from '@build-5/database'; +import { PgTransaction, build5Db } from '@build-5/database'; import { COL, Collection, CollectionStatus, - Member, + Network, NftStatus, Transaction, TransactionPayloadType, @@ -11,13 +11,14 @@ import { } from '@build-5/interfaces'; import { TransactionPayload, Utils } from '@iota/sdk'; import dayjs from 'dayjs'; -import { get } from 'lodash'; import { getAddress } from '../../utils/address.utils'; import { getProject } from '../../utils/common.utils'; +import { logger } from '../../utils/logger'; +import { getPathParts } from '../../utils/milestone'; import { getRandomEthAddress } from '../../utils/wallet.utils'; -export const onCollectionMintingUpdate = async (transaction: Transaction) => { - switch (transaction.payload.type) { +export const onCollectionMintingUpdate = async (transaction: PgTransaction) => { + switch (transaction.payload_type) { case TransactionPayloadType.MINT_ALIAS: { await onCollectionAliasMinted(transaction); break; @@ -39,26 +40,28 @@ export const onCollectionMintingUpdate = async (transaction: Transaction) => { break; } default: { - console.error('Unsupported executable transaction type error', transaction); + logger.error('Unsupported executable transaction type error', transaction); throw Error('Unsupported executable transaction type ' + transaction.type); } } }; -const onCollectionAliasMinted = async (transaction: Transaction) => { - const path = transaction.payload.walletReference?.milestoneTransactionPath!; - const milestoneTransaction = (await build5Db().doc(path).get>())!; +const onCollectionAliasMinted = async (transaction: PgTransaction) => { + const { col, colId, subCol, subColId } = getPathParts( + transaction.payload_walletReference_milestoneTransactionPath!, + ); + const milestoneTransaction = (await build5Db().doc(col, colId, subCol, subColId).get())!; const aliasOutputId = Utils.computeOutputId( - Utils.transactionId(milestoneTransaction.payload as TransactionPayload), + Utils.transactionId(milestoneTransaction.payload as unknown as TransactionPayload), 0, ); await build5Db() - .doc(`${COL.COLLECTION}/${transaction.payload.collection}`) + .doc(COL.COLLECTION, transaction.payload_collection!) .update({ - 'mintingData.aliasBlockId': milestoneTransaction.blockId, - 'mintingData.aliasId': Utils.computeAliasId(aliasOutputId), - 'mintingData.aliasStorageDeposit': transaction.payload.amount, + mintingData_aliasBlockId: milestoneTransaction.blockId as string, + mintingData_aliasId: Utils.computeAliasId(aliasOutputId), + mintingData_aliasStorageDeposit: transaction.payload_amount, }); const order: Transaction = { @@ -67,26 +70,28 @@ const onCollectionAliasMinted = async (transaction: Transaction) => { uid: getRandomEthAddress(), member: transaction.member, space: transaction.space, - network: transaction.network, + network: transaction.network as Network, payload: { type: TransactionPayloadType.MINT_COLLECTION, - amount: get(transaction, 'payload.collectionStorageDeposit', 0), - sourceAddress: transaction.payload.sourceAddress, - collection: transaction.payload.collection, + amount: transaction.payload_collectionStorageDeposit || 0, + sourceAddress: transaction.payload_sourceAddress, + collection: transaction.payload_collection, }, }; - await build5Db().doc(`${COL.TRANSACTION}/${order.uid}`).create(order); + await build5Db().doc(COL.TRANSACTION, order.uid).create(order); }; -const onCollectionMinted = async (transaction: Transaction) => { - const path = transaction.payload.walletReference?.milestoneTransactionPath!; - const milestoneTransaction = (await build5Db().doc(path).get>())!; +const onCollectionMinted = async (transaction: PgTransaction) => { + const { col, colId, subCol, subColId } = getPathParts( + transaction.payload_walletReference_milestoneTransactionPath!, + ); + const milestoneTransaction = (await build5Db().doc(col, colId, subCol, subColId).get())!; const collectionOutputId = Utils.computeOutputId( - Utils.transactionId(milestoneTransaction.payload as TransactionPayload), + Utils.transactionId(milestoneTransaction.payload as unknown as TransactionPayload), 1, ); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${transaction.payload.collection}`); - const collection = (await collectionDocRef.get())!; + const collectionDocRef = build5Db().doc(COL.COLLECTION, transaction.payload_collection!); + const collection = (await collectionDocRef.get())!; await saveCollectionMintingData( transaction, milestoneTransaction.blockId as string, @@ -94,97 +99,100 @@ const onCollectionMinted = async (transaction: Transaction) => { ); if (collection.mintingData?.nftsToMint) { const order = createMintNftsTransaction(transaction); - await build5Db().doc(`${COL.TRANSACTION}/${order.uid}`).create(order); + await build5Db().doc(COL.TRANSACTION, order.uid).create(order); } }; const saveCollectionMintingData = ( - transaction: Transaction, + transaction: PgTransaction, blockId: string, collectionOutputId: string, ) => build5Db() - .doc(`${COL.COLLECTION}/${transaction.payload.collection}`) + .doc(COL.COLLECTION, transaction.payload_collection!) .update({ - 'mintingData.blockId': blockId, - 'mintingData.nftId': Utils.computeNftId(collectionOutputId), - 'mintingData.mintedOn': dayjs().toDate(), + mintingData_blockId: blockId, + mintingData_nftId: Utils.computeNftId(collectionOutputId), + mintingData_mintedOn: dayjs().toDate(), }); -const onNftMintSuccess = async (transaction: Transaction) => { +const onNftMintSuccess = async (transaction: PgTransaction) => { const batch = build5Db().batch(); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${transaction.payload.collection}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, transaction.payload_collection!); const collection = await collectionDocRef.get(); batch.update(collectionDocRef, { - 'mintingData.nftsToMint': build5Db().inc(-transaction.payload.nfts!.length), + mintingData_nftsToMint: build5Db().inc(-transaction.payload_nfts!.length), }); - const milestoneTransaction = (await build5Db() - .doc(transaction.payload.walletReference?.milestoneTransactionPath!) - .get>())!; - transaction.payload.nfts!.forEach((nftId, i) => { + const { col, colId, subCol, subColId } = getPathParts( + transaction.payload_walletReference_milestoneTransactionPath!, + ); + const milestoneTransaction = (await build5Db().doc(col, colId, subCol, subColId).get())!; + for (let i = 0; i < transaction.payload_nfts!.length; ++i) { + const nftId = transaction.payload_nfts![i]; const outputId = Utils.computeOutputId( - Utils.transactionId(milestoneTransaction.payload as TransactionPayload), + Utils.transactionId(milestoneTransaction.payload as unknown as TransactionPayload), i + 2, ); - const docRef = build5Db().doc(`${COL.NFT}/${nftId}`); + const docRef = build5Db().doc(COL.NFT, nftId); batch.update(docRef, { - 'mintingData.network': transaction.network, - 'mintingData.mintedOn': dayjs().toDate(), - 'mintingData.mintedBy': transaction.member, - 'mintingData.blockId': milestoneTransaction.blockId, - 'mintingData.nftId': Utils.computeNftId(outputId), + mintingData_network: transaction.network, + mintingData_mintedOn: dayjs().toDate(), + mintingData_mintedBy: transaction.member, + mintingData_blockId: milestoneTransaction.blockId as string, + mintingData_nftId: Utils.computeNftId(outputId), status: NftStatus.MINTED, }); - }); + } - if (collection.mintingData?.nftsToMint! - transaction.payload.nfts!.length > 0) { + if (collection.mintingData?.nftsToMint! - transaction.payload_nfts!.length > 0) { const order = createMintNftsTransaction(transaction); - const docRef = build5Db().doc(`${COL.TRANSACTION}/${order.uid}`); + const docRef = build5Db().doc(COL.TRANSACTION, order.uid); batch.create(docRef, order); } await batch.commit(); }; -const createMintNftsTransaction = (transaction: Transaction): Transaction => ({ +const createMintNftsTransaction = (transaction: PgTransaction): Transaction => ({ project: getProject(transaction), type: TransactionType.MINT_COLLECTION, uid: getRandomEthAddress(), member: transaction.member, space: transaction.space, - network: transaction.network, + network: (transaction.network as Network)!, payload: { type: TransactionPayloadType.MINT_NFTS, - sourceAddress: transaction.payload.sourceAddress, - collection: transaction.payload.collection, + sourceAddress: transaction.payload_sourceAddress, + collection: transaction.payload_collection, }, }); -const onCollectionLocked = async (transaction: Transaction) => { - const member = (await build5Db().doc(`${COL.MEMBER}/${transaction.member}`).get())!; +const onCollectionLocked = async (transaction: PgTransaction) => { + const member = (await build5Db().doc(COL.MEMBER, transaction.member!).get())!; + const network = transaction.network as Network; const order: Transaction = { project: getProject(transaction), type: TransactionType.MINT_COLLECTION, uid: getRandomEthAddress(), member: transaction.member, space: transaction.space, - network: transaction.network, + network, payload: { type: TransactionPayloadType.SEND_ALIAS_TO_GUARDIAN, - amount: transaction.payload.aliasStorageDeposit, - sourceAddress: transaction.payload.sourceAddress, - targetAddress: getAddress(member, transaction.network!), - collection: transaction.payload.collection, + amount: transaction.payload_aliasStorageDeposit, + sourceAddress: transaction.payload_sourceAddress, + targetAddress: getAddress(member, network), + collection: transaction.payload_collection, }, }; - await build5Db().doc(`${COL.TRANSACTION}/${order.uid}`).create(order); + await build5Db().doc(COL.TRANSACTION, order.uid).create(order); }; -const onCollectionAliasTransfered = async (transaction: Transaction) => +const onCollectionAliasTransfered = (transaction: PgTransaction) => build5Db() - .doc(`${COL.COLLECTION}/${transaction.payload.collection}`) + .doc(COL.COLLECTION, transaction.payload_collection!) .update({ status: CollectionStatus.MINTED, approved: true }); diff --git a/packages/functions/src/triggers/transaction-trigger/matadatNft-minting.ts b/packages/functions/src/triggers/transaction-trigger/matadatNft-minting.ts index 663e81cc18..ca9ea526d9 100644 --- a/packages/functions/src/triggers/transaction-trigger/matadatNft-minting.ts +++ b/packages/functions/src/triggers/transaction-trigger/matadatNft-minting.ts @@ -1,19 +1,16 @@ -import { build5Db } from '@build-5/database'; +import { PgTransaction, build5Db } from '@build-5/database'; import { COL, Collection, DEFAULT_NETWORK, - Member, - Nft, + Network, NftStatus, - Space, Transaction, TransactionPayloadType, TransactionType, } from '@build-5/interfaces'; import { TransactionPayload, Utils } from '@iota/sdk'; import dayjs from 'dayjs'; -import { get } from 'lodash'; import { createMetadataCollection, createMetadataNft, @@ -23,11 +20,11 @@ import { import { WalletService } from '../../services/wallet/wallet.service'; import { getAddress } from '../../utils/address.utils'; import { getProject } from '../../utils/common.utils'; -import { dateToTimestamp } from '../../utils/dateTime.utils'; +import { getPathParts } from '../../utils/milestone'; import { getRandomEthAddress } from '../../utils/wallet.utils'; -export const onMetadataNftMintUpdate = async (transaction: Transaction) => { - switch (transaction.payload.type) { +export const onMetadataNftMintUpdate = async (transaction: PgTransaction) => { + switch (transaction.payload_type) { case TransactionPayloadType.MINT_ALIAS: { await onAliasMinted(transaction); break; @@ -47,138 +44,136 @@ export const onMetadataNftMintUpdate = async (transaction: Transaction) => { } }; -const onAliasMinted = async (transaction: Transaction) => { - const path = transaction.payload.walletReference?.milestoneTransactionPath!; - const milestoneTransaction = (await build5Db().doc(path).get>())!; +const onAliasMinted = async (transaction: PgTransaction) => { + const { col, colId, subCol, subColId } = getPathParts( + transaction.payload_walletReference_milestoneTransactionPath!, + ); + const milestoneTransaction = (await build5Db().doc(col, colId, subCol, subColId).get())!; const aliasOutputId = Utils.computeOutputId( - Utils.transactionId(milestoneTransaction.payload as TransactionPayload), + Utils.transactionId(milestoneTransaction.payload as unknown as TransactionPayload), 0, ); const aliasId = Utils.computeAliasId(aliasOutputId); const batch = build5Db().batch(); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${transaction.space}`); + const spaceDocRef = build5Db().doc(COL.SPACE, transaction.space!); batch.update(spaceDocRef, { name: `Space of alias: ${aliasId}`, - alias: { - address: transaction.payload.targetAddress, - aliasId, - blockId: milestoneTransaction.blockId, - mintedOn: dateToTimestamp(dayjs()), - mintedBy: transaction.member, - }, + alias_address: transaction.payload_targetAddress, + alias_aliasId: aliasId, + alias_blockId: milestoneTransaction.blockId as string, + alias_mintedOn: dayjs().toDate(), + alias_mintedBy: transaction.member, }); const collection = createMetadataCollection(getProject(transaction), transaction.space!); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${collection.uid}`); - batch.create(collectionDocRef, collection); + const collectionDocRef = build5Db().doc(COL.COLLECTION, collection.uid); + batch.create(collectionDocRef, collection as Collection); const order = createMintMetadataCollectionOrder( transaction, collection.uid, aliasId, - get(transaction, 'payload.orderId', ''), - transaction.payload.targetAddress!, + transaction.payload_orderId!, + transaction.payload_targetAddress!, milestoneTransaction.blockId as string, ); - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${order.uid}`); + const orderDocRef = build5Db().doc(COL.TRANSACTION, order.uid); batch.create(orderDocRef, order); await batch.commit(); }; -const onCollectionMinted = async (transaction: Transaction) => { - const path = transaction.payload.walletReference?.milestoneTransactionPath!; - const milestoneTransaction = (await build5Db().doc(path).get>())!; +const onCollectionMinted = async (transaction: PgTransaction) => { + const { col, colId, subCol, subColId } = getPathParts( + transaction.payload_walletReference_milestoneTransactionPath!, + ); + const milestoneTransaction = (await build5Db().doc(col, colId, subCol, subColId).get())!; const collectionOutputId = Utils.computeOutputId( - Utils.transactionId(milestoneTransaction.payload as TransactionPayload), + Utils.transactionId(milestoneTransaction.payload as unknown as TransactionPayload), 1, ); const collectionId = Utils.computeNftId(collectionOutputId); const batch = build5Db().batch(); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${transaction.payload.collection}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, transaction.payload_collection!); batch.update(collectionDocRef, { - mintingData: { - address: transaction.payload.targetAddress, - network: transaction.network, - mintedOn: dateToTimestamp(dayjs()), - mintedBy: transaction.member, - blockId: milestoneTransaction.blockId, - nftId: collectionId, - storageDeposit: get(transaction, 'payload.collectionOutputAmount', 0), - aliasBlockId: get(transaction, 'payload.aliasBlockId', ''), - aliasId: get(transaction, 'payload.aliasId', ''), - }, + mintingData_address: transaction.payload_targetAddress, + mintingData_network: transaction.network, + mintingData_mintedOn: dayjs().toDate(), + mintingData_mintedBy: transaction.member, + mintingData_blockId: milestoneTransaction.blockId as string, + mintingData_nftId: collectionId, + mintingData_storageDeposit: transaction.payload_collectionOutputAmount, + mintingData_aliasBlockId: transaction.payload_aliasBlockId, + mintingData_aliasId: transaction.payload_aliasId, }); - const order = await build5Db() - .doc(`${COL.TRANSACTION}/${transaction.payload.orderId}`) - .get(); + const order = (await build5Db().doc(COL.TRANSACTION, transaction.payload_orderId!).get())!; const nft = createMetadataNft( getProject(transaction), transaction.member!, transaction.space!, - transaction.payload.collection!, - get(order, 'payload.metadata', {}), + transaction.payload_collection!, + order.payload.metadata || {}, ); - const nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); + const nftDocRef = build5Db().doc(COL.NFT, nft.uid); batch.create(nftDocRef, nft); - const space = await build5Db().doc(`${COL.SPACE}/${transaction.space}`).get(); + const space = await build5Db().doc(COL.SPACE, transaction.space!).get(); const nftMintOrder = createMintMetadataNftOrder( transaction, nft, space?.alias?.address!, collectionId, - get(transaction, 'payload.orderId', ''), + transaction.payload_orderId!, ); - const nftMintOrderDocRef = build5Db().doc(`${COL.TRANSACTION}/${nftMintOrder.uid}`); + const nftMintOrderDocRef = build5Db().doc(COL.TRANSACTION, nftMintOrder.uid); batch.create(nftMintOrderDocRef, nftMintOrder); await batch.commit(); }; -const onNftMinted = async (transaction: Transaction) => { - const path = transaction.payload.walletReference?.milestoneTransactionPath!; - const milestoneTransaction = (await build5Db().doc(path).get>())!; +const onNftMinted = async (transaction: PgTransaction) => { + const { col, colId, subCol, subColId } = getPathParts( + transaction.payload_walletReference_milestoneTransactionPath!, + ); + const milestoneTransaction = (await build5Db().doc(col, colId, subCol, subColId).get())!; const nftOutputId = Utils.computeOutputId( - Utils.transactionId(milestoneTransaction.payload as TransactionPayload), + Utils.transactionId(milestoneTransaction.payload as unknown as TransactionPayload), 2, ); const nftId = Utils.computeNftId(nftOutputId); const batch = build5Db().batch(); - const nftDocRef = build5Db().doc(`${COL.NFT}/${transaction.payload.nft}`); - const nft = await nftDocRef.get(); + const nftDocRef = build5Db().doc(COL.NFT, transaction.payload_nft!); + const nft = await nftDocRef.get(); batch.update(nftDocRef, { status: NftStatus.MINTED, - mintingData: { - address: transaction.payload.targetAddress, - network: transaction.network, - mintedOn: dateToTimestamp(dayjs()), - mintedBy: transaction.member, - blockId: milestoneTransaction.blockId, - nftId, - }, + mintingData_address: transaction.payload_targetAddress, + mintingData_network: transaction.network, + mintingData_mintedOn: dayjs().toDate(), + mintingData_mintedBy: transaction.member, + mintingData_blockId: milestoneTransaction.blockId as string, + mintingData_nftId: nftId, }); - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${transaction.payload.orderId}`); + const orderDocRef = build5Db().doc(COL.TRANSACTION, transaction.payload_orderId!); const order = await orderDocRef.get(); const storageDepositTotal = - get(order, 'payload.aliasOutputAmount', 0) + - get(order, 'payload.collectionOutputAmount', 0) + - get(order, 'payload.nftOutputAmount', 0); + (order.payload.aliasOutputAmount || 0) + + (order.payload.collectionOutputAmount || 0) + + (order.payload.nftOutputAmount || 0); - const member = await build5Db().doc(`${COL.MEMBER}/${transaction.member}`).get(); - const collection = await build5Db().doc(`${COL.COLLECTION}/${nft?.collection}`).get(); - const space = await build5Db().doc(`${COL.SPACE}/${collection?.space}`).get(); + const member = await build5Db().doc(COL.MEMBER, transaction.member!).get(); + const collection = await build5Db().doc(COL.COLLECTION, nft?.collection!).get(); + const space = await build5Db().doc(COL.SPACE, collection?.space!).get(); const remainder = order.payload.amount! - storageDepositTotal; @@ -205,31 +200,30 @@ const onNftMinted = async (transaction: Transaction) => { tag: order.payload.tag || '', }, }; - const creditDocRef = build5Db().doc(`${COL.TRANSACTION}/${creditTransaction.uid}`); + const creditDocRef = build5Db().doc(COL.TRANSACTION, creditTransaction.uid); batch.create(creditDocRef, creditTransaction); } await batch.commit(); }; -const onNftUpdated = async (transaction: Transaction) => { +const onNftUpdated = async (transaction: PgTransaction) => { const batch = build5Db().batch(); - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${transaction.payload.orderId}`); + const orderDocRef = build5Db().doc(COL.TRANSACTION, transaction.payload_orderId!); const order = await orderDocRef.get(); - const nftDocRef = build5Db().doc(`${COL.NFT}/${transaction.payload.nft}`); - const nft = await nftDocRef.get(); - batch.update(nftDocRef, { - properties: order.payload.metadata, - }); + const nftDocRef = build5Db().doc(COL.NFT, transaction.payload_nft!); + const nft = await nftDocRef.get(); + batch.update(nftDocRef, { properties: JSON.stringify(order.payload.metadata) }); - const wallet = await WalletService.newWallet(transaction.network!); + const network = transaction.network as Network; + const wallet = await WalletService.newWallet(network!); const { amount: balance } = await wallet.getBalance(order.payload.targetAddress!); - const member = await build5Db().doc(`${COL.MEMBER}/${transaction.member}`).get(); - const collection = await build5Db().doc(`${COL.COLLECTION}/${nft?.collection}`).get(); - const space = await build5Db().doc(`${COL.SPACE}/${collection?.space}`).get(); + const member = await build5Db().doc(COL.MEMBER, transaction.member!).get(); + const collection = await build5Db().doc(COL.COLLECTION, nft?.collection!).get(); + const space = await build5Db().doc(COL.SPACE, collection?.space!).get(); if (Number(balance)) { const creditTransaction: Transaction = { @@ -254,7 +248,7 @@ const onNftUpdated = async (transaction: Transaction) => { tag: order.payload.tag || '', }, }; - const creditDocRef = build5Db().doc(`${COL.TRANSACTION}/${creditTransaction.uid}`); + const creditDocRef = build5Db().doc(COL.TRANSACTION, creditTransaction.uid); batch.create(creditDocRef, creditTransaction); } diff --git a/packages/functions/src/triggers/transaction-trigger/nft-staked.ts b/packages/functions/src/triggers/transaction-trigger/nft-staked.ts index 48b6916bb7..1c3d6a0952 100644 --- a/packages/functions/src/triggers/transaction-trigger/nft-staked.ts +++ b/packages/functions/src/triggers/transaction-trigger/nft-staked.ts @@ -1,31 +1,32 @@ -import { build5Db } from '@build-5/database'; -import { COL, Nft, Transaction } from '@build-5/interfaces'; +import { PgTransaction, build5Db } from '@build-5/database'; +import { COL, StakeType } from '@build-5/interfaces'; import { getProject } from '../../utils/common.utils'; +import { dateToTimestamp } from '../../utils/dateTime.utils'; import { getRandomEthAddress } from '../../utils/wallet.utils'; -export const onNftStaked = async (transaction: Transaction) => { - const nftDocRef = build5Db().doc(`${COL.NFT}/${transaction.payload.nft}`); - const nft = (await nftDocRef.get())!; +export const onNftStaked = async (transaction: PgTransaction) => { + const nftDocRef = build5Db().doc(COL.NFT, transaction.payload_nft!); + const nft = (await nftDocRef.get())!; const nftStake = { project: getProject(transaction), uid: getRandomEthAddress(), - member: transaction.member, + member: transaction.member!, space: nft.space, nft: nft.uid, collection: nft.collection, - weeks: transaction.payload.weeks, - expiresAt: transaction.payload.vestingAt, + weeks: transaction.payload_weeks!, + expiresAt: dateToTimestamp(transaction.payload_vestingAt!), expirationProcessed: false, - type: transaction.payload.stakeType, + type: transaction.payload_stakeType as StakeType, }; const batch = build5Db().batch(); - const nftStakeDocRef = build5Db().doc(`${COL.NFT_STAKE}/${nftStake.uid}`); + const nftStakeDocRef = build5Db().doc(COL.NFT_STAKE, nftStake.uid); batch.create(nftStakeDocRef, nftStake); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${nft.collection}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, nft.collection); batch.update(collectionDocRef, { stakedNft: build5Db().inc(1) }); await batch.commit(); diff --git a/packages/functions/src/triggers/transaction-trigger/proposal.vote.ts b/packages/functions/src/triggers/transaction-trigger/proposal.vote.ts index 4b37aedd2d..3dacfde7ae 100644 --- a/packages/functions/src/triggers/transaction-trigger/proposal.vote.ts +++ b/packages/functions/src/triggers/transaction-trigger/proposal.vote.ts @@ -1,19 +1,22 @@ -import { build5Db } from '@build-5/database'; -import { COL, Transaction, TransactionType } from '@build-5/interfaces'; +import { PgTransaction, build5Db } from '@build-5/database'; +import { COL, Network, TransactionType } from '@build-5/interfaces'; +import { getPathParts } from '../../utils/milestone'; import { MilestoneTransactionAdapter } from '../milestone-transactions-triggers/MilestoneTransactionAdapter'; -export const onProposalVoteCreditConfirmed = async (transaction: Transaction) => { - const milestoneDoc = (await build5Db() - .doc(transaction.payload.walletReference?.milestoneTransactionPath!) - .get>())!; - const adapter = new MilestoneTransactionAdapter(transaction.network!); - const milestoneTransaction = await adapter.toMilestoneTransaction(milestoneDoc); +export const onProposalVoteCreditConfirmed = async (transaction: PgTransaction) => { + const { col, colId, subCol, subColId } = getPathParts( + transaction.payload_walletReference_milestoneTransactionPath!, + ); + const milestone = (await build5Db().doc(col, colId, subCol, subColId).get())!; + const network = (transaction.network as Network)!; + const adapter = new MilestoneTransactionAdapter(network); + const milestoneTransaction = await adapter.toMilestoneTransaction(milestone); const outputId = milestoneTransaction.outputs[0].outputId!; const voteTransactionSnap = await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.VOTE) - .where('payload.creditId', '==', transaction.uid) - .get(); - const voteTransactionDoc = build5Db().doc(`${COL.TRANSACTION}/${voteTransactionSnap[0].uid}`); - await voteTransactionDoc.update({ 'payload.outputId': outputId }); + .where('payload_creditId', '==', transaction.uid) + .get(); + const voteTransactionDoc = build5Db().doc(COL.TRANSACTION, voteTransactionSnap[0].uid); + await voteTransactionDoc.update({ payload_outputId: outputId }); }; diff --git a/packages/functions/src/triggers/transaction-trigger/staking.ts b/packages/functions/src/triggers/transaction-trigger/staking.ts index f5f9504fa6..19aeeba173 100644 --- a/packages/functions/src/triggers/transaction-trigger/staking.ts +++ b/packages/functions/src/triggers/transaction-trigger/staking.ts @@ -1,48 +1,36 @@ -import { build5Db } from '@build-5/database'; -import { COL, Stake, SUB_COL, Transaction } from '@build-5/interfaces'; +import { PgTokenStatsUpdate, PgTransaction, build5Db } from '@build-5/database'; +import { COL, SUB_COL } from '@build-5/interfaces'; import { onStakeCreated } from '../../services/stake.service'; -export const onStakingConfirmed = async (billPayment: Transaction) => { - const stakeDocRef = build5Db().doc(`${COL.STAKE}/${billPayment.payload.stake}`); - const stake = (await stakeDocRef.get())!; +export const onStakingConfirmed = async (billPayment: PgTransaction) => { + const stakeDocRef = build5Db().doc(COL.STAKE, billPayment.payload_stake!); + const stake = (await stakeDocRef.get())!; await build5Db().runTransaction((transaction) => onStakeCreated(transaction, stake)); + const tokenUid = billPayment.payload_token; + const batch = build5Db().batch(); - const updateData = { - stakes: { - [stake.type]: { - amount: build5Db().inc(stake.amount), - totalAmount: build5Db().inc(stake.amount), - value: build5Db().inc(stake.value), - totalValue: build5Db().inc(stake.value), - }, - }, - stakeExpiry: { - [stake.type]: { - [stake.expiresAt.toMillis()]: stake.value, - }, - }, + const updateData: PgTokenStatsUpdate = { + [`stakes_${stake.type}_amount`]: build5Db().inc(stake.amount), + [`stakes_${stake.type}_totalAmount`]: build5Db().inc(stake.amount), + [`stakes_${stake.type}_value`]: build5Db().inc(stake.value), + [`stakes_${stake.type}_totalValue`]: build5Db().inc(stake.value), + stakeExpiry: { [stake.type]: { [stake.expiresAt.toMillis()]: stake.value } }, + parentId: tokenUid!, }; - const tokenUid = billPayment.payload.token; - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${tokenUid}/${SUB_COL.STATS}/${tokenUid}`); - batch.set(tokenDocRef, { stakes: updateData.stakes }, true); + const tokenDocRef = build5Db().doc(COL.TOKEN, tokenUid!, SUB_COL.STATS, tokenUid); + batch.upsert(tokenDocRef, updateData); const distirbutionDocRef = build5Db().doc( - `${COL.TOKEN}/${tokenUid}/${SUB_COL.DISTRIBUTION}/${billPayment.member}`, - ); - batch.set( - distirbutionDocRef, - { - parentId: tokenUid, - parentCol: COL.TOKEN, - uid: billPayment.member, - ...updateData, - }, - true, + COL.TOKEN, + tokenUid!, + SUB_COL.DISTRIBUTION, + billPayment.member, ); + batch.upsert(distirbutionDocRef, updateData); await batch.commit(); }; diff --git a/packages/functions/src/triggers/transaction-trigger/stamp-minting.ts b/packages/functions/src/triggers/transaction-trigger/stamp-minting.ts index b405efdd3f..5b16bb0a1f 100644 --- a/packages/functions/src/triggers/transaction-trigger/stamp-minting.ts +++ b/packages/functions/src/triggers/transaction-trigger/stamp-minting.ts @@ -1,13 +1,19 @@ -import { build5Db } from '@build-5/database'; -import { COL, Transaction, TransactionPayloadType, TransactionType } from '@build-5/interfaces'; +import { PgTransaction, build5Db } from '@build-5/database'; +import { + COL, + Network, + Transaction, + TransactionPayloadType, + TransactionType, +} from '@build-5/interfaces'; import { TransactionPayload, Utils } from '@iota/sdk'; import dayjs from 'dayjs'; import { getProject } from '../../utils/common.utils'; -import { dateToTimestamp } from '../../utils/dateTime.utils'; +import { getPathParts } from '../../utils/milestone'; import { getRandomEthAddress } from '../../utils/wallet.utils'; -export const onStampMintUpdate = async (transaction: Transaction) => { - switch (transaction.payload.type) { +export const onStampMintUpdate = async (transaction: PgTransaction) => { + switch (transaction.payload_type) { case TransactionPayloadType.MINT_ALIAS: { await onAliasMinted(transaction); break; @@ -19,30 +25,29 @@ export const onStampMintUpdate = async (transaction: Transaction) => { } }; -const onAliasMinted = async (transaction: Transaction) => { - const path = transaction.payload.walletReference?.milestoneTransactionPath!; - const milestoneTransaction = (await build5Db().doc(path).get>())!; +const onAliasMinted = async (transaction: PgTransaction) => { + const path = transaction.payload_walletReference_milestoneTransactionPath!; + const { col, colId, subCol, subColId } = getPathParts(path); + const milestoneTransaction = (await build5Db().doc(col, colId, subCol, subColId).get())!; const aliasOutputId = Utils.computeOutputId( - Utils.transactionId(milestoneTransaction.payload as TransactionPayload), + Utils.transactionId(milestoneTransaction.payload as unknown as TransactionPayload), 0, ); const aliasId = Utils.computeAliasId(aliasOutputId); const batch = build5Db().batch(); - const stampDocRef = build5Db().doc(`${COL.STAMP}/${transaction.payload.stamp}`); + const stampDocRef = build5Db().doc(COL.STAMP, transaction.payload_stamp!); batch.update(stampDocRef, { aliasId }); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${transaction.space}`); + const spaceDocRef = build5Db().doc(COL.SPACE, transaction.space!); batch.update(spaceDocRef, { name: `Space of alias: ${aliasId}`, - alias: { - address: transaction.payload.targetAddress, - aliasId, - blockId: milestoneTransaction.blockId, - mintedOn: dateToTimestamp(dayjs()), - mintedBy: transaction.member, - }, + alias_address: transaction.payload_targetAddress, + alias_aliasId: aliasId, + alias_blockId: milestoneTransaction.blockId as string, + alias_mintedOn: dayjs().toDate(), + alias_mintedBy: transaction.member, }); const mintNftOrder: Transaction = { @@ -51,30 +56,31 @@ const onAliasMinted = async (transaction: Transaction) => { uid: getRandomEthAddress(), member: transaction.member, space: transaction.space, - network: transaction.network, + network: transaction.network as Network, payload: { type: TransactionPayloadType.MINT_NFT, - sourceAddress: transaction.payload.targetAddress, - aliasGovAddress: transaction.payload.targetAddress, - targetAddress: transaction.payload.targetAddress, + sourceAddress: transaction.payload_targetAddress, + aliasGovAddress: transaction.payload_targetAddress, + targetAddress: transaction.payload_targetAddress, aliasId, - stamp: transaction.payload.stamp, + stamp: transaction.payload_stamp, }, }; - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${mintNftOrder.uid}`); + const orderDocRef = build5Db().doc(COL.TRANSACTION, mintNftOrder.uid); batch.create(orderDocRef, mintNftOrder); await batch.commit(); }; -const onNftMinted = async (transaction: Transaction) => { - const path = transaction.payload.walletReference?.milestoneTransactionPath!; - const milestoneTransaction = (await build5Db().doc(path).get>())!; +const onNftMinted = async (transaction: PgTransaction) => { + const path = transaction.payload_walletReference_milestoneTransactionPath!; + const { col, colId, subCol, subColId } = getPathParts(path); + const milestoneTransaction = (await build5Db().doc(col, colId, subCol, subColId).get())!; const nftOutputId = Utils.computeOutputId( - Utils.transactionId(milestoneTransaction.payload as TransactionPayload), + Utils.transactionId(milestoneTransaction.payload as unknown as TransactionPayload), 1, ); const nftId = Utils.computeNftId(nftOutputId); - const stampDocRef = build5Db().doc(`${COL.STAMP}/${transaction.payload.stamp}`); + const stampDocRef = build5Db().doc(COL.STAMP, transaction.payload_stamp!); await stampDocRef.update({ nftId }); }; diff --git a/packages/functions/src/triggers/transaction-trigger/token-minting.ts b/packages/functions/src/triggers/transaction-trigger/token-minting.ts index 247f06ce53..9991159645 100644 --- a/packages/functions/src/triggers/transaction-trigger/token-minting.ts +++ b/packages/functions/src/triggers/transaction-trigger/token-minting.ts @@ -1,7 +1,8 @@ -import { build5Db } from '@build-5/database'; +import { PgTransaction, build5Db } from '@build-5/database'; import { COL, Member, + Network, Token, TokenStatus, Transaction, @@ -20,10 +21,12 @@ import { import dayjs from 'dayjs'; import { getAddress } from '../../utils/address.utils'; import { getProject } from '../../utils/common.utils'; +import { logger } from '../../utils/logger'; +import { getPathParts } from '../../utils/milestone'; import { getRandomEthAddress } from '../../utils/wallet.utils'; -export const onTokenMintingUpdate = async (transaction: Transaction) => { - switch (transaction.payload.type) { +export const onTokenMintingUpdate = async (transaction: PgTransaction) => { + switch (transaction.payload_type) { case TransactionPayloadType.MINT_ALIAS: { await onAliasMinted(transaction); break; @@ -37,53 +40,55 @@ export const onTokenMintingUpdate = async (transaction: Transaction) => { break; } default: { - console.error('Unsupported executable transaction type error', transaction); + logger.error('Unsupported executable transaction type error', transaction); throw Error('Unsupported executable transaction type ' + transaction.type); } } }; -const onAliasMinted = async (transaction: Transaction) => { - const path = transaction.payload.walletReference?.milestoneTransactionPath!; - const milestoneTransaction = (await build5Db().doc(path).get>())!; +const onAliasMinted = async (transaction: PgTransaction) => { + const path = transaction.payload_walletReference_milestoneTransactionPath!; + const { col, colId, subCol, subColId } = getPathParts(path); + const milestoneTransaction = (await build5Db().doc(col, colId, subCol, subColId).get())!; const aliasOutputId = Utils.computeOutputId( - Utils.transactionId(milestoneTransaction.payload as TransactionPayload), + Utils.transactionId(milestoneTransaction.payload as unknown as TransactionPayload), 0, ); await build5Db() - .doc(`${COL.TOKEN}/${transaction.payload.token}`) + .doc(COL.TOKEN, transaction.payload_token!) .update({ - 'mintingData.aliasBlockId': milestoneTransaction.blockId, - 'mintingData.aliasId': Utils.computeAliasId(aliasOutputId), + mintingData_aliasBlockId: milestoneTransaction.blockId as string, + mintingData_aliasId: Utils.computeAliasId(aliasOutputId), }); - const token = await build5Db().doc(`${COL.TOKEN}/${transaction.payload.token}`).get(); + const token = await build5Db().doc(COL.TOKEN, transaction.payload_token!).get(); const order: Transaction = { project: getProject(transaction), type: TransactionType.MINT_TOKEN, uid: getRandomEthAddress(), member: transaction.member, space: transaction.space, - network: transaction.network, + network: transaction.network as Network, payload: { type: TransactionPayloadType.MINT_FOUNDRY, amount: token.mintingData?.foundryStorageDeposit! + token.mintingData?.vaultStorageDeposit! + token.mintingData?.guardianStorageDeposit!, - sourceAddress: transaction.payload.sourceAddress, - token: transaction.payload.token, + sourceAddress: transaction.payload_sourceAddress, + token: transaction.payload_token, }, }; - await build5Db().doc(`${COL.TRANSACTION}/${order.uid}`).create(order); + await build5Db().doc(COL.TRANSACTION, order.uid).create(order); }; -const onFoundryMinted = async (transaction: Transaction) => { - const path = transaction.payload.walletReference?.milestoneTransactionPath!; - const milestoneTransaction = (await build5Db().doc(path).get>())!; +const onFoundryMinted = async (transaction: PgTransaction) => { + const path = transaction.payload_walletReference_milestoneTransactionPath!; + const { col, colId, subCol, subColId } = getPathParts(path); + const milestoneTransaction = (await build5Db().doc(col, colId, subCol, subColId).get())!; - const payload = milestoneTransaction.payload as TransactionPayload; + const payload = milestoneTransaction.payload as unknown as TransactionPayload; const essence = payload.essence as RegularTransactionEssence; const aliasOutput = essence.outputs.find((o) => o.type === OutputType.Alias); const foundryOutput = essence.outputs.find((o) => o.type === OutputType.Foundry); @@ -98,39 +103,39 @@ const onFoundryMinted = async (transaction: Transaction) => { const totalSupply = Number(tokenScheme.maximumSupply); await build5Db() - .doc(`${COL.TOKEN}/${transaction.payload.token}`) + .doc(COL.TOKEN, transaction.payload_token!) .update({ - 'mintingData.blockId': milestoneTransaction.blockId, - 'mintingData.tokenId': foundryId, - 'mintingData.meltedTokens': meltedTokens, - 'mintingData.circulatingSupply': totalSupply - meltedTokens, + mintingData_blockId: milestoneTransaction.blockId as string, + mintingData_tokenId: foundryId, + mintingData_meltedTokens: meltedTokens, + mintingData_circulatingSupply: totalSupply - meltedTokens, }); - const token = await build5Db().doc(`${COL.TOKEN}/${transaction.payload.token}`).get(); - const member = await build5Db().doc(`${COL.MEMBER}/${token.mintingData?.mintedBy}`).get(); + const token = await build5Db().doc(COL.TOKEN, transaction.payload_token!).get(); + const member = await build5Db().doc(COL.MEMBER, token.mintingData?.mintedBy!).get(); const order: Transaction = { project: getProject(transaction), type: TransactionType.MINT_TOKEN, uid: getRandomEthAddress(), member: transaction.member, space: transaction.space, - network: transaction.network, + network: (transaction.network as Network)!, payload: { type: TransactionPayloadType.SEND_ALIAS_TO_GUARDIAN, amount: token.mintingData?.aliasStorageDeposit!, - sourceAddress: transaction.payload.sourceAddress, + sourceAddress: transaction.payload_sourceAddress, targetAddress: getAddress(member, token.mintingData?.network!), - token: transaction.payload.token, + token: transaction.payload_token, }, }; - await build5Db().doc(`${COL.TRANSACTION}/${order.uid}`).create(order); + await build5Db().doc(COL.TRANSACTION, order.uid).create(order); }; -const onAliasSendToGuardian = async (transaction: Transaction) => { - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${transaction.payload.token}`); +const onAliasSendToGuardian = async (transaction: PgTransaction) => { + const tokenDocRef = build5Db().doc(COL.TOKEN, transaction.payload_token!); const token = await tokenDocRef.get(); await tokenDocRef.update({ - 'mintingData.mintedOn': dayjs().toDate(), + mintingData_mintedOn: dayjs().toDate(), status: TokenStatus.MINTED, approved: true, tradingDisabled: !token.public || token.tradingDisabled || false, diff --git a/packages/functions/src/triggers/transaction-trigger/transaction.trigger.ts b/packages/functions/src/triggers/transaction-trigger/transaction.trigger.ts index 02f2bf3566..99781b851d 100644 --- a/packages/functions/src/triggers/transaction-trigger/transaction.trigger.ts +++ b/packages/functions/src/triggers/transaction-trigger/transaction.trigger.ts @@ -1,4 +1,4 @@ -import { ITransaction, build5Db } from '@build-5/database'; +import { ITransaction, PgTransaction, build5Db } from '@build-5/database'; import { COL, DEFAULT_NETWORK, @@ -24,8 +24,9 @@ import { getAddress } from '../../utils/address.utils'; import { getProject } from '../../utils/common.utils'; import { isEmulatorEnv } from '../../utils/config.utils'; import { serverTime } from '../../utils/dateTime.utils'; +import { logger } from '../../utils/logger'; import { getRandomEthAddress } from '../../utils/wallet.utils'; -import { FirestoreDocEvent } from '../common'; +import { PgDocEvent } from '../common'; import { unclockMnemonic } from '../milestone-transactions-triggers/common'; import { onAirdropClaim } from './airdrop.claim'; import { onAwardUpdate } from './award.transaction.update'; @@ -61,19 +62,20 @@ export const EXECUTABLE_TRANSACTIONS = [ ...CREDIT_EXECUTABLE_TRANSACTIONS, ]; -export const onTransactionWrite = async (event: FirestoreDocEvent) => { +export const onTransactionWrite = async (event: PgDocEvent) => { const { prev, curr } = event; if (!curr) { return; } - const isExecutableType = EXECUTABLE_TRANSACTIONS.includes(curr.type); + const type = curr.type as TransactionType; + const isExecutableType = EXECUTABLE_TRANSACTIONS.includes(type); const isCreate = prev === undefined; const shouldRetry = !prev?.shouldRetry && curr?.shouldRetry; if (isCreate) { - const docRef = build5Db().doc(`${COL.TRANSACTION}/${curr.uid}`); - await docRef.update({ isOrderType: curr.type === TransactionType.ORDER }); + const docRef = build5Db().doc(COL.TRANSACTION, curr.uid); + await docRef.update({ isOrderType: type === TransactionType.ORDER }); } if (isExecutableType && !curr?.ignoreWallet && (isCreate || shouldRetry)) { @@ -81,45 +83,44 @@ export const onTransactionWrite = async (event: FirestoreDocEvent) } if ( - curr.payload.type === TransactionPayloadType.AIRDROP_MINTED_TOKEN && - prev?.payload?.unclaimedAirdrops && - curr.payload.unclaimedAirdrops === 0 + curr.payload_type === TransactionPayloadType.AIRDROP_MINTED_TOKEN && + prev?.payload_unclaimedAirdrops && + curr.payload_unclaimedAirdrops === 0 ) { await onMintedAirdropCleared(curr); return; } - if (curr.type === TransactionType.MINT_COLLECTION && isConfirmed(prev, curr)) { + if (type === TransactionType.MINT_COLLECTION && isConfirmed(prev, curr)) { await onCollectionMintingUpdate(curr); return; } - if (curr.type === TransactionType.MINT_TOKEN && isConfirmed(prev, curr)) { + if (type === TransactionType.MINT_TOKEN && isConfirmed(prev, curr)) { await onTokenMintingUpdate(curr); return; } - if (curr.type === TransactionType.CREDIT_STORAGE_DEPOSIT_LOCKED && isConfirmed(prev, curr)) { + if (type === TransactionType.CREDIT_STORAGE_DEPOSIT_LOCKED && isConfirmed(prev, curr)) { await build5Db() - .doc(`${COL.TRANSACTION}/${curr.payload.transaction}`) + .doc(COL.TRANSACTION, curr.payload_transaction!) .update({ - 'payload.walletReference.confirmed': true, - 'payload.walletReference.inProgress': false, - 'payload.walletReference.count': build5Db().inc(1), - 'payload.walletReference.processedOn': dayjs().toDate(), - 'payload.walletReference.chainReference': - curr.payload?.walletReference?.chainReference || '', - 'payload.walletReference.chainReferences': build5Db().arrayUnion( - curr.payload?.walletReference?.chainReference || '', + payload_walletReference_confirmed: true, + payload_walletReference_inProgress: false, + payload_walletReference_count: build5Db().inc(1), + payload_walletReference_processedOn: dayjs().toDate(), + payload_walletReference_chainReference: curr.payload_walletReference_chainReference || '', + payload_walletReference_chainReferences: build5Db().arrayUnion( + curr.payload_walletReference_chainReference || '', ), }); return; } if ( - curr.type === TransactionType.BILL_PAYMENT && + type === TransactionType.BILL_PAYMENT && isConfirmed(prev, curr) && - !isEmpty(curr.payload.stake) + !isEmpty(curr.payload_stake) ) { await onStakingConfirmed(curr); return; @@ -131,51 +132,50 @@ export const onTransactionWrite = async (event: FirestoreDocEvent) TransactionPayloadType.CLAIM_BASE_TOKEN, ]; if ( - airdropOrderTypes.includes(curr.payload.type!) && - !prev?.payload.reconciled && - curr.payload.reconciled + airdropOrderTypes.includes(curr.payload_type! as TransactionPayloadType) && + !prev?.payload_reconciled && + curr.payload_reconciled ) { - console.info('onAirdropClaim', JSON.stringify(prev), JSON.stringify(curr)); await onAirdropClaim(curr); return; } - if (isConfirmed(prev, curr) && curr.payload.proposalId && curr.type === TransactionType.CREDIT) { + if (isConfirmed(prev, curr) && curr.payload_proposalId && type === TransactionType.CREDIT) { await onProposalVoteCreditConfirmed(curr); return; } - if (isConfirmed(prev, curr) && curr.payload.weeks && curr.type === TransactionType.WITHDRAW_NFT) { + if (isConfirmed(prev, curr) && curr.payload_weeks && type === TransactionType.WITHDRAW_NFT) { await onNftStaked(curr); return; } - if (isConfirmed(prev, curr) && curr.type === TransactionType.AWARD) { + if (isConfirmed(prev, curr) && type === TransactionType.AWARD) { await onAwardUpdate(curr); return; } - if (isConfirmed(prev, curr) && curr.type === TransactionType.METADATA_NFT) { + if (isConfirmed(prev, curr) && type === TransactionType.METADATA_NFT) { await onMetadataNftMintUpdate(curr); return; } - if (isConfirmed(prev, curr) && curr.type === TransactionType.METADATA_NFT) { + if (isConfirmed(prev, curr) && type === TransactionType.METADATA_NFT) { await onMetadataNftMintUpdate(curr); return; } - if (isConfirmed(prev, curr) && curr.type === TransactionType.STAMP) { + if (isConfirmed(prev, curr) && type === TransactionType.STAMP) { await onStampMintUpdate(curr); return; } if ( isConfirmed(prev, curr) && - curr.payload.award && - curr.payload.type === TransactionPayloadType.MINTED_AIRDROP_CLAIM + curr.payload_award && + curr.payload_type === TransactionPayloadType.MINTED_AIRDROP_CLAIM ) { - const awardDocRef = build5Db().doc(`${COL.AWARD}/${curr.payload.award}`); + const awardDocRef = build5Db().doc(COL.AWARD, curr.payload_award); await awardDocRef.update({ airdropClaimed: build5Db().inc(1) }); } }; @@ -186,8 +186,8 @@ const executeTransaction = async (transactionId: string) => { return; } - const docRef = build5Db().doc(`${COL.TRANSACTION}/${transactionId}`); - const transaction = (await docRef.get())!; + const docRef = build5Db().doc(COL.TRANSACTION, transactionId); + const transaction = (await docRef.get())!; const payload = transaction.payload; const params = await getWalletParams(transaction); @@ -240,7 +240,7 @@ const executeTransaction = async (transactionId: string) => { } default: { - console.error('Unsupported executable transaction type error', transaction); + logger.error('Unsupported executable transaction type error', transaction); throw Error('Unsupported executable transaction type ' + transaction.type); } } @@ -248,18 +248,18 @@ const executeTransaction = async (transactionId: string) => { const chainReference = await submit(); await docRef.update({ - 'payload.walletReference.processedOn': dayjs().toDate(), - 'payload.walletReference.chainReference': chainReference, - 'payload.walletReference.chainReferences': build5Db().arrayUnion(chainReference), - 'payload.walletReference.nodeIndex': wallet.nodeIndex, + payload_walletReference_processedOn: dayjs().toDate(), + payload_walletReference_chainReference: chainReference, + payload_walletReference_chainReferences: build5Db().arrayUnion(chainReference), + payload_walletReference_nodeIndex: wallet.nodeIndex, }); } catch (error) { - console.error('onTransactionWrite-error', transaction.uid, wallet.nodeUrl, error); + logger.error('onTransactionWrite-error', transaction.uid, wallet.nodeUrl, error); await docRef.update({ - 'payload.walletReference.chainReference': null, - 'payload.walletReference.processedOn': dayjs().toDate(), - 'payload.walletReference.error': JSON.stringify(error), - 'payload.walletReference.nodeIndex': wallet.nodeIndex, + payload_walletReference_chainReference: null, + payload_walletReference_processedOn: dayjs().toDate(), + payload_walletReference_error: JSON.stringify(error), + payload_walletReference_nodeIndex: wallet.nodeIndex, }); await unclockMnemonic(payload.sourceAddress!); } @@ -292,7 +292,7 @@ const submitCollectionMintTransactions = ( return aliasWallet.changeAliasOwner(transaction, params); } default: { - console.error('Unsupported executable transaction type error', transaction); + logger.error('Unsupported executable transaction type error', transaction); throw Error('Unsupported executable transaction type ' + transaction.payload.type); } } @@ -317,7 +317,7 @@ const submitTokenMintTransactions = ( return aliasWallet.changeAliasOwner(transaction, params); } default: { - console.error('Unsupported executable transaction type error', transaction); + logger.error('Unsupported executable transaction type error', transaction); throw Error('Unsupported executable transaction type ' + transaction.payload.type); } } @@ -346,7 +346,7 @@ const submitCreateAwardTransaction = ( return aliasWallet.burnAlias(transaction, params); } default: { - console.error( + logger.error( 'Unsupported executable transaction type in submitCreateAwardTransaction - error', transaction, ); @@ -355,7 +355,7 @@ const submitCreateAwardTransaction = ( } }; -const submitMintMetadataTransaction = async ( +const submitMintMetadataTransaction = ( transaction: Transaction, wallet: Wallet, params: WalletParams, @@ -378,7 +378,7 @@ const submitMintMetadataTransaction = async ( return nftWallet.updateMetadataNft(transaction, params); } default: { - console.error( + logger.error( 'Unsupported executable transaction type in submitMintMetadataTransaction - error', transaction, ); @@ -387,7 +387,7 @@ const submitMintMetadataTransaction = async ( } }; -const submitMintStampTransaction = async ( +const submitMintStampTransaction = ( transaction: Transaction, wallet: Wallet, params: WalletParams, @@ -402,7 +402,7 @@ const submitMintStampTransaction = async ( return nftWallet.mintStampNft(transaction, params); } default: { - console.error( + logger.error( 'Unsupported executable transaction type in submitCreateAwardTransaction - error', transaction, ); @@ -437,7 +437,7 @@ const submitUnlockTransaction = async ( return nftWallet.changeNftOwner(transaction, params); } default: { - console.error('Unsupported executable transaction type - error', transaction); + logger.error('Unsupported executable transaction type - error', transaction); throw Error('Unsupported executable transaction type ' + transaction.payload.type); } } @@ -445,8 +445,8 @@ const submitUnlockTransaction = async ( const prepareTransaction = (transactionId: string) => build5Db().runTransaction(async (transaction) => { - const docRef = build5Db().doc(`${COL.TRANSACTION}/${transactionId}`); - const tranData = await transaction.get(docRef); + const docRef = build5Db().doc(COL.TRANSACTION, transactionId); + const tranData = await transaction.get(docRef); if ( isEmulatorEnv() && [Network.SMR, Network.IOTA].includes(tranData?.network || DEFAULT_NETWORK) @@ -459,7 +459,7 @@ const prepareTransaction = (transactionId: string) => !isEmpty(walletResponse.chainReference) || walletResponse.count > MAX_WALLET_RETRY ) { - transaction.update(docRef, { shouldRetry: false }); + await transaction.update(docRef, { shouldRetry: false }); return false; } @@ -468,10 +468,20 @@ const prepareTransaction = (transactionId: string) => tranData.payload.dependsOnBillPayment ) { walletResponse.chainReference = null; - transaction.update(docRef, { + await transaction.update(docRef, { shouldRetry: false, - 'payload.walletReference': walletResponse, - 'payload.dependsOnBillPayment': false, + payload_walletReference_createdOn: walletResponse.createdOn?.toDate(), + payload_walletReference_processedOn: walletResponse.processedOn?.toDate(), + payload_walletReference_chainReference: walletResponse.chainReference || undefined, + payload_walletReference_chainReferences: walletResponse.chainReferences, + payload_walletReference_error: walletResponse.error as string, + payload_walletReference_confirmed: walletResponse.confirmed, + payload_walletReference_confirmedOn: walletResponse.confirmedOn?.toDate(), + payload_walletReference_milestoneTransactionPath: walletResponse.milestoneTransactionPath, + payload_walletReference_count: walletResponse.count, + payload_walletReference_inProgress: walletResponse.inProgress, + payload_walletReference_nodeIndex: walletResponse.nodeIndex, + payload_dependsOnBillPayment: false, }); return false; } @@ -482,12 +492,25 @@ const prepareTransaction = (transactionId: string) => walletResponse.processedOn = serverTime(); walletResponse.inProgress = true; - transaction.update(docRef, { shouldRetry: false, 'payload.walletReference': walletResponse }); + await transaction.update(docRef, { + shouldRetry: false, + payload_walletReference_createdOn: walletResponse.createdOn?.toDate(), + payload_walletReference_processedOn: walletResponse.processedOn?.toDate(), + payload_walletReference_chainReference: walletResponse.chainReference || undefined, + payload_walletReference_chainReferences: walletResponse.chainReferences, + payload_walletReference_error: walletResponse.error as string, + payload_walletReference_confirmed: walletResponse.confirmed, + payload_walletReference_confirmedOn: walletResponse.confirmedOn?.toDate(), + payload_walletReference_milestoneTransactionPath: walletResponse.milestoneTransactionPath, + payload_walletReference_count: walletResponse.count, + payload_walletReference_inProgress: walletResponse.inProgress, + payload_walletReference_nodeIndex: walletResponse.nodeIndex, + }); if (!tranData.payload.outputToConsume) { - lockMnemonic(transaction, transactionId, tranData.payload.sourceAddress); - lockMnemonic(transaction, transactionId, tranData.payload.storageDepositSourceAddress); - lockMnemonic(transaction, transactionId, tranData.payload.aliasGovAddress); + await lockMnemonic(transaction, transactionId, tranData.payload.sourceAddress); + await lockMnemonic(transaction, transactionId, tranData.payload.storageDepositSourceAddress); + await lockMnemonic(transaction, transactionId, tranData.payload.aliasGovAddress); } return true; @@ -506,13 +529,13 @@ const getMnemonic = async ( address: NetworkAddress | undefined, ): Promise => { if (isEmpty(address)) { - return {}; + return {} as Mnemonic; } - const docRef = build5Db().doc(`${COL.MNEMONIC}/${address}`); - return (await transaction.get(docRef)) || {}; + const docRef = build5Db().doc(COL.MNEMONIC, address!); + return (await transaction.get(docRef)) || ({} as Mnemonic); }; -const lockMnemonic = ( +const lockMnemonic = async ( transaction: ITransaction, lockedBy: string, address: NetworkAddress | undefined, @@ -520,8 +543,8 @@ const lockMnemonic = ( if (isEmpty(address)) { return; } - const docRef = build5Db().doc(`${COL.MNEMONIC}/${address}`); - transaction.update(docRef, { + const docRef = build5Db().doc(COL.MNEMONIC, address!); + await transaction.update(docRef, { lockedBy, consumedOutputIds: [], consumedNftOutputIds: [], @@ -543,28 +566,29 @@ const mnemonicsAreLocked = async (transaction: ITransaction, tran: Transaction) ); }; -const isConfirmed = (prev: Transaction | undefined, curr: Transaction | undefined) => - !prev?.payload?.walletReference?.confirmed && curr?.payload?.walletReference?.confirmed; +const isConfirmed = (prev: PgTransaction | undefined, curr: PgTransaction | undefined) => + !prev?.payload_walletReference_confirmed && curr?.payload_walletReference_confirmed; -const onMintedAirdropCleared = async (curr: Transaction) => { - const member = await build5Db().doc(`${COL.MEMBER}/${curr.member}`).get(); +const onMintedAirdropCleared = async (curr: PgTransaction) => { + const network = (curr.network as Network) || DEFAULT_NETWORK; + const member = await build5Db().doc(COL.MEMBER, curr.member!).get(); const credit: Transaction = { project: getProject(curr), type: TransactionType.CREDIT, uid: getRandomEthAddress(), space: curr.space, member: curr.member, - network: curr.network || DEFAULT_NETWORK, + network, payload: { type: TransactionPayloadType.AIRDROP_MINTED_TOKEN, - amount: curr.payload.amount, - sourceAddress: curr.payload.targetAddress, - targetAddress: getAddress(member, curr.network || DEFAULT_NETWORK), + amount: curr.payload_amount, + sourceAddress: curr.payload_targetAddress, + targetAddress: getAddress(member, network), sourceTransaction: [curr.uid], reconciled: true, void: false, - token: curr.payload.token, + token: curr.payload_token, }, }; - await build5Db().doc(`${COL.TRANSACTION}/${credit.uid}`).create(credit); + await build5Db().doc(COL.TRANSACTION, credit.uid).create(credit); }; diff --git a/packages/functions/src/triggers/transaction-trigger/wallet-params.ts b/packages/functions/src/triggers/transaction-trigger/wallet-params.ts index 34143f1857..58cf00693b 100644 --- a/packages/functions/src/triggers/transaction-trigger/wallet-params.ts +++ b/packages/functions/src/triggers/transaction-trigger/wallet-params.ts @@ -3,7 +3,6 @@ import { COL, IOTATangleTransaction, NativeToken, - Nft, Transaction, TransactionType, } from '@build-5/interfaces'; @@ -44,7 +43,7 @@ const getParams = async (transaction: Transaction) => { } if (payload.nft) { details.nft = payload.nft; - const nft = await build5Db().doc(`${COL.NFT}/${payload.nft}`).get(); + const nft = await build5Db().doc(COL.NFT, payload.nft).get(); if (nft && nft.ipfsMedia) { details.ipfsMedia = 'ipfs://' + nft.ipfsMedia; } diff --git a/packages/functions/src/utils/car.utils.ts b/packages/functions/src/utils/car.utils.ts index a410adbd27..6cc9fc76c9 100644 --- a/packages/functions/src/utils/car.utils.ts +++ b/packages/functions/src/utils/car.utils.ts @@ -1,3 +1,4 @@ +import { PgCollection, PgNft, PgToken } from '@build-5/database'; import { Collection, KEY_NAME_TANGLE, Nft, Token } from '@build-5/interfaces'; import { CarReader } from '@ipld/car'; import * as dagPb from '@ipld/dag-pb'; @@ -11,6 +12,7 @@ import { NFTStorage } from 'nft.storage'; import os from 'os'; import { propsToAttributes } from './collection-minting-utils/nft.prop.utils'; import { getNftStorageToken } from './config.utils'; +import { logger } from './logger'; import { downloadFile } from './media.utils'; const MAX_BLOCK_SIZE = 1048576; @@ -28,7 +30,7 @@ export const packCar = async (directory: string) => { const car = await CarReader.fromIterable(out); return { car, cid: root.toString() }; } catch (error) { - console.error('Pack car error', error); + logger.error('Pack car error', error); throw error; } finally { await blockstore.close(); @@ -87,7 +89,7 @@ const toImportCandidate = (file: FileLike) => ({ }, }); -export const collectionToIpfsMetadata = (collection: Collection) => ({ +export const collectionToIpfsMetadata = (collection: Collection | PgCollection) => ({ name: collection.name, description: collection.description, author: collection.createdBy, @@ -97,7 +99,7 @@ export const collectionToIpfsMetadata = (collection: Collection) => ({ uid: collection.uid, }); -export const nftToIpfsMetadata = (collection: Collection, nft: Nft) => { +export const nftToIpfsMetadata = (collection: Collection, nft: Nft | PgNft) => { const props = propsToAttributes(nft.properties); const stats = propsToAttributes(nft.stats); return { @@ -113,11 +115,11 @@ export const nftToIpfsMetadata = (collection: Collection, nft: Nft) => { }; }; -export const tokenToIpfsMetadata = (token: Token) => ({ +export const tokenToIpfsMetadata = (token: Token | PgToken) => ({ name: token.name, description: token.description || '', space: token.space, platform: KEY_NAME_TANGLE, uid: token.uid, - symbol: token.symbol.toUpperCase(), + symbol: token.symbol!.toUpperCase(), }); diff --git a/packages/functions/src/utils/collection-minting-utils/nft.prop.utils.ts b/packages/functions/src/utils/collection-minting-utils/nft.prop.utils.ts index 3a325eaa5c..81ea52427e 100644 --- a/packages/functions/src/utils/collection-minting-utils/nft.prop.utils.ts +++ b/packages/functions/src/utils/collection-minting-utils/nft.prop.utils.ts @@ -1,6 +1,7 @@ import { PropStats } from '@build-5/interfaces'; -export const propsToAttributes = (props: PropStats | undefined) => +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export const propsToAttributes = (props: PropStats | Record | undefined) => Object.entries(props || {}).map(([key, value]) => ({ trait_type: key, value: value.value, diff --git a/packages/functions/src/utils/collection-minting-utils/nft.utils.ts b/packages/functions/src/utils/collection-minting-utils/nft.utils.ts index e6a3abf083..eb8b8cc12e 100644 --- a/packages/functions/src/utils/collection-minting-utils/nft.utils.ts +++ b/packages/functions/src/utils/collection-minting-utils/nft.utils.ts @@ -96,17 +96,14 @@ export const collectionToMetadata = async ( }; export const getNftByMintingId = async (nftId: string) => { - const snap = await build5Db() - .collection(COL.NFT) - .where('mintingData.nftId', '==', nftId) - .get(); + const snap = await build5Db().collection(COL.NFT).where('mintingData_nftId', '==', nftId).get(); return head(snap); }; export const getCollectionByMintingId = async (collectionId: string) => { const snap = await build5Db() .collection(COL.COLLECTION) - .where('mintingData.nftId', '==', collectionId) - .get(); + .where('mintingData_nftId', '==', collectionId) + .get(); return head(snap); }; diff --git a/packages/functions/src/utils/common.utils.ts b/packages/functions/src/utils/common.utils.ts index 8a76b044ee..f2bf469c75 100644 --- a/packages/functions/src/utils/common.utils.ts +++ b/packages/functions/src/utils/common.utils.ts @@ -1,4 +1,4 @@ -import { build5Db } from '@build-5/database'; +import { BaseRecord as PgBaseRecord, build5Db } from '@build-5/database'; import { Access, BaseRecord, @@ -6,7 +6,6 @@ import { Collection, MIN_AMOUNT_TO_TRANSFER, Nft, - ProjectAdmin, Restrictions, SOON_PROJECT_ID, SUB_COL, @@ -69,11 +68,11 @@ export const getRestrictions = (collection?: Collection, nft?: Nft): Restriction }; export const assertIsProjectAdmin = async (project: string, member: string) => { - const projectDocRef = build5Db().doc(`${COL.PROJECT}/${project}`); - const admin = await projectDocRef.collection(SUB_COL.ADMINS).doc(member).get(); + const admin = await build5Db().doc(COL.PROJECT, project, SUB_COL.ADMINS, member).get(); if (!admin) { throw invalidArgument(WenError.you_are_not_admin_of_project); } }; -export const getProject = (data: BaseRecord | undefined) => data?.project || SOON_PROJECT_ID; +export const getProject = (data: BaseRecord | PgBaseRecord | undefined) => + data?.project || SOON_PROJECT_ID; diff --git a/packages/functions/src/utils/dateTime.utils.ts b/packages/functions/src/utils/dateTime.utils.ts index 9722ec8093..bb604dba13 100644 --- a/packages/functions/src/utils/dateTime.utils.ts +++ b/packages/functions/src/utils/dateTime.utils.ts @@ -1,10 +1,9 @@ import { Timestamp as ITimestamp } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { Timestamp } from 'firebase-admin/firestore'; export const dateToTimestamp = (d: dayjs.ConfigType, onlyDownToMinutes = false) => { const date = onlyDownToMinutes ? dayjs(d).second(0).millisecond(0) : dayjs(d); - return Timestamp.fromDate(date.toDate()) as ITimestamp; + return ITimestamp.fromDate(date.toDate()) as ITimestamp; }; export const serverTime = () => dateToTimestamp(dayjs()); diff --git a/packages/functions/src/utils/error.utils.ts b/packages/functions/src/utils/error.utils.ts index 282cfc6d7f..ec285d3c15 100644 --- a/packages/functions/src/utils/error.utils.ts +++ b/packages/functions/src/utils/error.utils.ts @@ -1,14 +1,14 @@ -import { FunctionsErrorCode } from 'firebase-functions/v1/https'; -import * as functions from 'firebase-functions/v2'; - interface Error { - readonly key?: string; + key: string; + code: number; } -const throwArgument = (type: FunctionsErrorCode, err: Error, append = '') => - new functions.https.HttpsError(type, err.key + '. ' + append, err); - -export const invalidArgument = (err: Error, append = '') => - throwArgument('invalid-argument', err, append); +export const invalidArgument = (err: Error, eMessage = '') => { + // eslint-disable-next-line no-throw-literal + throw { eCode: err.code, eKey: err.key, eMessage, status: 400 }; +}; -export const unAuthenticated = (err: Error) => throwArgument('unauthenticated', err); +export const unAuthenticated = (err: Error) => { + // eslint-disable-next-line no-throw-literal + throw { eCode: err.code, eKey: err.key, status: 401 }; +}; diff --git a/packages/functions/src/utils/logger.ts b/packages/functions/src/utils/logger.ts new file mode 100644 index 0000000000..0de2e5574c --- /dev/null +++ b/packages/functions/src/utils/logger.ts @@ -0,0 +1,47 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { format } from 'util'; +import { traceCtx } from './trace'; + +const log = async (severity = 'INFO', ...data: any[]): Promise => { + const trace = traceCtx.getStore()?.trace; + const entry = { + severity, + message: format(...data), + 'logging.googleapis.com/trace': `projects/${process.env.PROJECT_ID}/traces/${trace}`, + }; + console.log(JSON.stringify(removeCircular(entry))); +}; + +export const logger = { + info: (...message: any[]) => log('INFO', message), + error: (...message: any[]) => log('ERROR', message), + warn: (...message: any[]) => log('WARNING', message), +}; + +const removeCircular = (obj: any, refs: any[] = []) => { + if (typeof obj !== 'object' || !obj) { + return obj; + } + if (obj.toJSON) { + return obj.toJSON(); + } + if (refs.includes(obj)) { + return '[Circular]'; + } else { + refs.push(obj); + } + let returnObj: any; + if (Array.isArray(obj)) { + returnObj = new Array(obj.length); + } else { + returnObj = {}; + } + for (const k in obj) { + if (refs.includes(obj[k])) { + returnObj[k] = '[Circular]'; + } else { + returnObj[k] = removeCircular(obj[k], refs); + } + } + return returnObj; +}; diff --git a/packages/functions/src/utils/media.utils.ts b/packages/functions/src/utils/media.utils.ts index 41f135e6da..2f43a4384e 100644 --- a/packages/functions/src/utils/media.utils.ts +++ b/packages/functions/src/utils/media.utils.ts @@ -16,7 +16,8 @@ import mime from 'mime-types'; import os from 'os'; import path from 'path'; import { BUCKET_BASE_URLS } from '../services/joi/common'; -import { getBucket, isEmulatorEnv } from './config.utils'; +import { getBucket } from './config.utils'; +import { logger } from './logger'; export const migrateUriToSotrage = async ( col: COL, @@ -40,7 +41,7 @@ export const migrateUriToSotrage = async ( bucket.getName() === Bucket.DEV ? response : `https://${bucket.getName()}/${destination}`; return build5Url; } catch (error: any) { - console.error('migrateUriToSotrage - error', col, uid, error); + logger.error('migrateUriToSotrage - error', col, uid, error); throw error.code && error.key ? error : WenError.ipfs_retrieve; } finally { fs.rmSync(workdir, { recursive: true, force: true }); @@ -88,13 +89,13 @@ export const uriToUrl = (uri: string) => { export const getRandomBuild5Url = (owner: string, uid: string, extension: string) => { const bucket = build5Storage().bucket(getBucket()); - const baseUrl = isEmulatorEnv() ? BUCKET_BASE_URLS['local'] : BUCKET_BASE_URLS[bucket.getName()]; + const baseUrl = BUCKET_BASE_URLS[bucket.getName()]; - const isEmulatorOrDev = isEmulatorEnv() || bucket.getName() === Bucket.DEV; + const isDev = bucket.getName() === Bucket.DEV; const destination = `${owner}/${uid}/${generateRandomFileName()}.${extension}`; - const url = `${baseUrl}${isEmulatorOrDev ? encodeURIComponent(destination) : destination}`; + const url = `${baseUrl}${isDev ? encodeURIComponent(destination) : destination}`; - return isEmulatorOrDev ? url + '?generation=1695968595134&alt=media' : url; + return isDev ? url + '?alt=media' : url; }; export const downloadFile = async (url: string, workDir: string, fileName: string) => { @@ -117,26 +118,22 @@ export const downloadFile = async (url: string, workDir: string, fileName: strin const extension = mime.extension(contentType); return new Promise<{ extension: string; size: number; hash: string }>((resolve, reject) => { - let size = 0; - const chunks: any = []; - response.data.on('data', (chunk: any) => { - chunks.push(chunk); - size += chunk.length; - }); - - response.data.on('end', () => { - if (size > MAX_FILE_SIZE_BYTES) { + stream.on('finish', () => { + const stats = fs.statSync(destination); + if (stats.size > MAX_FILE_SIZE_BYTES) { reject(WenError.max_size); return; } + const content = fs.readFileSync(destination); resolve({ extension, - size, + size: stats.size, hash: createHash('sha1') - .update('' + chunks.join()) + .update('' + content) .digest('hex'), }); }); - response.data.on('error', reject); + + stream.on('error', reject); }); }; diff --git a/packages/functions/src/utils/milestone.ts b/packages/functions/src/utils/milestone.ts new file mode 100644 index 0000000000..036f2dd8c5 --- /dev/null +++ b/packages/functions/src/utils/milestone.ts @@ -0,0 +1,6 @@ +import { COL, SUB_COL } from '@build-5/interfaces'; + +export const getPathParts = (path: string) => { + const [col, colId, subCol, subColId] = path.split('/'); + return { col: col as COL.MILESTONE, colId, subCol: subCol as SUB_COL.TRANSACTIONS, subColId }; +}; diff --git a/packages/functions/src/utils/royalty.utils.ts b/packages/functions/src/utils/royalty.utils.ts index 225ba496e3..769e493a45 100644 --- a/packages/functions/src/utils/royalty.utils.ts +++ b/packages/functions/src/utils/royalty.utils.ts @@ -1,5 +1,5 @@ import { build5Db } from '@build-5/database'; -import { COL, SYSTEM_CONFIG_DOC_ID, SystemConfig } from '@build-5/interfaces'; +import { COL, SYSTEM_CONFIG_DOC_ID } from '@build-5/interfaces'; import bigDecimal from 'js-big-decimal'; import { getRoyaltyPercentage, @@ -38,9 +38,7 @@ const getTokenPurchaseFeePercentage = async ( if (memberFeePercentage !== undefined) { return memberFeePercentage; } - const systemConfig = await build5Db() - .doc(`${COL.SYSTEM}/${SYSTEM_CONFIG_DOC_ID}`) - .get(); + const systemConfig = await build5Db().doc(COL.SYSTEM, SYSTEM_CONFIG_DOC_ID).get(); const systemPercentage = isTokenPurchase ? systemConfig?.tokenPurchaseFeePercentage : systemConfig?.tokenTradingFeePercentage; diff --git a/packages/functions/src/utils/schema.utils.ts b/packages/functions/src/utils/schema.utils.ts index 6af062fff4..7464c2e27e 100644 --- a/packages/functions/src/utils/schema.utils.ts +++ b/packages/functions/src/utils/schema.utils.ts @@ -4,12 +4,13 @@ import { head } from 'lodash'; import { isStorageUrl } from '../services/joi/common'; import { isProdEnv } from './config.utils'; import { invalidArgument } from './error.utils'; +import { logger } from './logger'; import { fileExists } from './storage.utils'; const assertValidation = (r: ValidationResult) => { if (r.error) { const detail = head(r.error.details); - isProdEnv() && console.warn('Invalid argument warning', { func: r.error }); + isProdEnv() && logger.warn('Invalid argument warning', { func: r.error }); throw invalidArgument( WenError.invalid_params, detail ? `${detail.message || ''}. ${detail.context?.message || ''}` : '', @@ -34,5 +35,8 @@ export const assertValidationAsync = async ( return validationResult.value! as T; }; -export const cleanupParams = (obj: Record) => - Object.entries(obj).reduce((acc, act) => ({ ...acc, [act[0]]: act[1] || null }), {}); +export const cleanupParams = (obj: T): T => + Object.entries(obj as Record).reduce( + (acc, act) => ({ ...acc, [act[0]]: act[1] || null }), + {}, + ) as T; diff --git a/packages/functions/src/utils/space.utils.ts b/packages/functions/src/utils/space.utils.ts index 9f715df08d..4ef85c3104 100644 --- a/packages/functions/src/utils/space.utils.ts +++ b/packages/functions/src/utils/space.utils.ts @@ -4,16 +4,15 @@ import { head } from 'lodash'; import { invalidArgument } from './error.utils'; export const assertSpaceExists = async (spaceId: string) => { - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${spaceId}`); - const space = await spaceDocRef.get(); + const spaceDocRef = build5Db().doc(COL.SPACE, spaceId); + const space = await spaceDocRef.get(); if (!space) { throw invalidArgument(WenError.space_does_not_exists); } }; export const assertIsSpaceMember = async (space: string, member: string) => { - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${space}`); - const spaceMemberDocRef = spaceDocRef.collection(SUB_COL.MEMBERS).doc(member); + const spaceMemberDocRef = build5Db().doc(COL.SPACE, space, SUB_COL.MEMBERS, member); const spaceMember = await spaceMemberDocRef.get(); if (!spaceMember) { throw invalidArgument(WenError.you_are_not_part_of_space); @@ -30,13 +29,13 @@ export const getSpace = async (space: string | undefined) => { return undefined; } const docRef = build5Db().collection(COL.SPACE).doc(space); - return await docRef.get(); + return await docRef.get(); }; export const hasActiveEditProposal = async (space: string) => { const ongoingProposalSnap = await build5Db() .collection(COL.PROPOSAL) - .where('settings.spaceUpdateData.uid', '==', space) + .where('space', '==', space) .where('completed', '==', false) .get(); return ongoingProposalSnap.length > 0; @@ -45,8 +44,8 @@ export const hasActiveEditProposal = async (space: string) => { export const getSpaceByAliasId = async (aliasId: string) => { const spaces = await build5Db() .collection(COL.SPACE) - .where('alias.aliasId', '==', aliasId) + .where('alias_aliasId', '==', aliasId) .limit(1) - .get(); + .get(); return head(spaces); }; diff --git a/packages/functions/src/utils/token-minting-utils/member.utils.ts b/packages/functions/src/utils/token-minting-utils/member.utils.ts index 8d36a11877..b672977626 100644 --- a/packages/functions/src/utils/token-minting-utils/member.utils.ts +++ b/packages/functions/src/utils/token-minting-utils/member.utils.ts @@ -1,30 +1,8 @@ -import { build5Db, getSnapshot } from '@build-5/database'; -import { COL, SUB_COL, Token, TokenDistribution, TokenDrop } from '@build-5/interfaces'; +import { Token, TokenDrop } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { last } from 'lodash'; import { Wallet } from '../../services/wallet/wallet'; import { packBasicOutput } from '../basic-output.utils'; -export const getOwnedTokenTotal = async (token: string) => { - let count = 0; - let lastDocId = ''; - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${token}`); - do { - const lastDoc = lastDocId - ? await getSnapshot(COL.TOKEN, token, SUB_COL.DISTRIBUTION, lastDocId) - : undefined; - const snap = await tokenDocRef - .collection(SUB_COL.DISTRIBUTION) - .startAfter(lastDoc) - .limit(1000) - .get(); - lastDocId = last(snap)?.uid || ''; - - count += snap.reduce((acc, act) => acc + (act.tokenOwned || 0), 0); - } while (lastDocId); - return count; -}; - export const dropToOutput = ( wallet: Wallet, token: Token, diff --git a/packages/functions/src/utils/token-trade.utils.ts b/packages/functions/src/utils/token-trade.utils.ts index a43291e1f2..aa3aaa974a 100644 --- a/packages/functions/src/utils/token-trade.utils.ts +++ b/packages/functions/src/utils/token-trade.utils.ts @@ -3,7 +3,6 @@ import { COL, CreditPaymentReason, DEFAULT_NETWORK, - Member, SUB_COL, Token, TokenStatus, @@ -20,14 +19,14 @@ import { getProject } from './common.utils'; import { getRandomEthAddress } from './wallet.utils'; export const creditBuyer = async (transaction: ITransaction, buy: TokenTradeOrder) => { - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${buy.owner}`); - const member = (await memberDocRef.get())!; + const memberDocRef = build5Db().doc(COL.MEMBER, buy.owner); + const member = (await memberDocRef.get())!; - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${buy.token}`); - const token = (await tokenDocRef.get())!; + const tokenDocRef = build5Db().doc(COL.TOKEN, buy.token); + const token = (await tokenDocRef.get())!; - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${buy.orderTransactionId}`); - const order = (await orderDocRef.get())!; + const orderDocRef = build5Db().doc(COL.TRANSACTION, buy.orderTransactionId!); + const order = (await orderDocRef.get())!; const network = order.network || DEFAULT_NETWORK; const credit: Transaction = { @@ -50,11 +49,11 @@ export const creditBuyer = async (transaction: ITransaction, buy: TokenTradeOrde tokenSymbol: token.symbol, }, }; - const creditDocRef = build5Db().doc(`${COL.TRANSACTION}/${credit.uid}`); - transaction.create(creditDocRef, credit); + const creditDocRef = build5Db().doc(COL.TRANSACTION, credit.uid); + await transaction.create(creditDocRef, credit); - const tradeOrderDocRef = build5Db().doc(`${COL.TOKEN_MARKET}/${buy.uid}`); - transaction.update(tradeOrderDocRef, { creditTransactionId: credit.uid }); + const tradeOrderDocRef = build5Db().doc(COL.TOKEN_MARKET, buy.uid); + await transaction.update(tradeOrderDocRef, { creditTransactionId: credit.uid }); }; const creditBaseTokenSale = async ( @@ -62,11 +61,11 @@ const creditBaseTokenSale = async ( token: Token, sale: TokenTradeOrder, ) => { - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${sale.orderTransactionId}`); - const order = (await orderDocRef.get())!; + const orderDocRef = build5Db().doc(COL.TRANSACTION, sale.orderTransactionId!); + const order = (await orderDocRef.get())!; - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${sale.owner}`); - const member = await memberDocRef.get(); + const memberDocRef = build5Db().doc(COL.MEMBER, sale.owner); + const member = await memberDocRef.get(); const network = order.network || DEFAULT_NETWORK; const data: Transaction = { project: getProject(sale), @@ -88,11 +87,11 @@ const creditBaseTokenSale = async ( tokenSymbol: token.symbol, }, }; - const creditDocRef = build5Db().doc(`${COL.TRANSACTION}/${data.uid}`); - transaction.create(creditDocRef, data); + const creditDocRef = build5Db().doc(COL.TRANSACTION, data.uid); + await transaction.create(creditDocRef, data); - const tradeDocRef = build5Db().doc(`${COL.TOKEN_MARKET}/${sale.uid}`); - transaction.update(tradeDocRef, { + const tradeDocRef = build5Db().doc(COL.TOKEN_MARKET, sale.uid); + await transaction.update(tradeDocRef, { creditTransactionId: data.uid, balance: 0, }); @@ -103,14 +102,14 @@ export const cancelTradeOrderUtil = async ( tradeOrder: TokenTradeOrder, forcedStatus?: TokenTradeOrderStatus, ) => { - const saleDocRef = build5Db().doc(`${COL.TOKEN_MARKET}/${tradeOrder.uid}`); + const saleDocRef = build5Db().doc(COL.TOKEN_MARKET, tradeOrder.uid); const status = forcedStatus || (tradeOrder.fulfilled === 0 ? TokenTradeOrderStatus.CANCELLED : TokenTradeOrderStatus.PARTIALLY_SETTLED_AND_CANCELLED); - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${tradeOrder.token}`); - const token = (await tokenDocRef.get())!; + const tokenDocRef = build5Db().doc(COL.TOKEN, tradeOrder.token); + const token = (await tokenDocRef.get())!; if (token.status === TokenStatus.BASE) { await creditBaseTokenSale(transaction, token, tradeOrder); @@ -118,25 +117,30 @@ export const cancelTradeOrderUtil = async ( if (token.status === TokenStatus.MINTED) { await cancelMintedSell(transaction, tradeOrder, token); } else { - const distributionDocRef = tokenDocRef.collection(SUB_COL.DISTRIBUTION).doc(tradeOrder.owner); + const distributionDocRef = build5Db().doc( + COL.TOKEN, + tradeOrder.token, + SUB_COL.DISTRIBUTION, + tradeOrder.owner, + ); const leftForSale = bigDecimal.subtract(tradeOrder.count, tradeOrder.fulfilled); - transaction.update(distributionDocRef, { + await transaction.update(distributionDocRef, { lockedForSale: build5Db().inc(-Number(leftForSale)), }); } } else { await creditBuyer(transaction, tradeOrder); } - transaction.update(saleDocRef, { status }); + await transaction.update(saleDocRef, { status }); return { ...tradeOrder, status }; }; const cancelMintedSell = async (transaction: ITransaction, sell: TokenTradeOrder, token: Token) => { - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${sell.orderTransactionId}`); - const order = (await orderDocRef.get())!; + const orderDocRef = build5Db().doc(COL.TRANSACTION, sell.orderTransactionId!); + const order = (await orderDocRef.get())!; - const sellerDocRef = build5Db().doc(`${COL.MEMBER}/${sell.owner}`); - const seller = await sellerDocRef.get(); + const sellerDocRef = build5Db().doc(COL.MEMBER, sell.owner); + const seller = await sellerDocRef.get(); const tokensLeft = sell.count - sell.fulfilled; const network = order.network || DEFAULT_NETWORK; @@ -161,9 +165,9 @@ const cancelMintedSell = async (transaction: ITransaction, sell: TokenTradeOrder tokenSymbol: token.symbol, }, }; - const creditDocRef = build5Db().doc(`${COL.TRANSACTION}/${data.uid}`); - transaction.create(creditDocRef, data); + const creditDocRef = build5Db().doc(COL.TRANSACTION, data.uid); + await transaction.create(creditDocRef, data); - const tradeOrderDocRef = build5Db().doc(`${COL.TOKEN_MARKET}/${sell.uid}`); - transaction.update(tradeOrderDocRef, { creditTransactionId: data.uid }); + const tradeOrderDocRef = build5Db().doc(COL.TOKEN_MARKET, sell.uid); + await transaction.update(tradeOrderDocRef, { creditTransactionId: data.uid }); }; diff --git a/packages/functions/src/utils/token.utils.ts b/packages/functions/src/utils/token.utils.ts index de5ebfb47b..58572812b5 100644 --- a/packages/functions/src/utils/token.utils.ts +++ b/packages/functions/src/utils/token.utils.ts @@ -1,39 +1,37 @@ -import { build5Db, getSnapshot } from '@build-5/database'; +import { build5Db, PgToken } from '@build-5/database'; import { COL, Collection, SUB_COL, Token, - TokenDrop, + TokenAllocation, TokenDropStatus, TokenStatus, WenError, } from '@build-5/interfaces'; import dayjs from 'dayjs'; import bigDecimal from 'js-big-decimal'; -import { last } from 'lodash'; +import { head } from 'lodash'; import { invalidArgument } from './error.utils'; export const BIG_DECIMAL_PRECISION = 1000; -export const tokenOrderTransactionDocId = (member: string, token: Token) => - member + '_' + token.uid; +export const tokenOrderTransactionDocId = (member: string, token: Token | PgToken) => + member + token.uid; export const allPaymentsQuery = (member: string, token: string) => build5Db() .collection(COL.TRANSACTION) .where('member', '==', member) - .where('payload.token', '==', token); + .where('payload_token', '==', token); -export const orderDocRef = (member: string, token: Token) => - build5Db().doc(`${COL.TRANSACTION}/${tokenOrderTransactionDocId(member, token)}`); +export const orderDocRef = (member: string, token: Token | PgToken) => + build5Db().doc(COL.TRANSACTION, tokenOrderTransactionDocId(member, token)); -export const memberDocRef = (member: string) => build5Db().doc(`${COL.MEMBER}/${member}`); +export const memberDocRef = (member: string) => build5Db().doc(COL.MEMBER, member); export const assertIsGuardian = async (space: string, member: string) => { - const guardianDoc = await build5Db() - .doc(`${COL.SPACE}/${space}/${SUB_COL.GUARDIANS}/${member}`) - .get(); + const guardianDoc = await build5Db().doc(COL.SPACE, space, SUB_COL.GUARDIANS, member).get(); if (!guardianDoc) { throw invalidArgument(WenError.you_are_not_guardian_of_space); } @@ -78,8 +76,9 @@ export const getBoughtByMemberDiff = ( return Number(bigDecimal.subtract(currentOrderCount, prevOrderCount)); }; -export const getTotalPublicSupply = (token: Token) => { - const publicPercentage = token.allocations.find((a) => a.isPublicSale)?.percentage || 0; +export const getTotalPublicSupply = (token: Token | PgToken) => { + const publicPercentage = + (token.allocations! as TokenAllocation[]).find((a) => a.isPublicSale)?.percentage || 0; return Number(bigDecimal.floor(bigDecimal.multiply(token.totalSupply, publicPercentage / 100))); }; @@ -121,55 +120,35 @@ export const getTokenForSpace = async (space: string) => { return snap[0]; }; -export const getUnclaimedDrops = async (token: string, member: string) => +export const getUnclaimedDrops = (token: string, member: string) => build5Db() .collection(COL.AIRDROP) .where('token', '==', token) .where('member', '==', member) .where('status', '==', TokenDropStatus.UNCLAIMED) - .get(); - -export const getUnclaimedAirdropTotalValue = async (token: string) => { - let count = 0; - let lastDocId = ''; - do { - const lastDoc = await getSnapshot(COL.AIRDROP, lastDocId); - const snap = await build5Db() - .collection(COL.AIRDROP) - .where('token', '==', token) - .where('status', '==', TokenDropStatus.UNCLAIMED) - .startAfter(lastDoc) - .get(); - lastDocId = last(snap)?.uid || ''; - - count += snap.reduce((acc, act) => acc + act.count, 0); - } while (lastDocId); - return count; -}; + .get(); export const getTokenBySymbol = async (symbol: string) => { let snap = await build5Db() .collection(COL.TOKEN) .where('symbol', '==', symbol.toUpperCase()) .where('approved', '==', true) - .limit(1) .get(); if (snap.length) { - return snap[0]; + return head(snap); } snap = await build5Db() .collection(COL.TOKEN) .where('symbol', '==', symbol.toUpperCase()) .where('public', '==', true) - .limit(1) .get(); - return snap[0]; + return head(snap); }; export const getTokenByMintId = async (tokenId: string) => { const snap = await build5Db() .collection(COL.TOKEN) - .where('mintingData.tokenId', '==', tokenId) + .where('mintingData_tokenId', '==', tokenId) .get(); return snap[0]; }; diff --git a/packages/functions/src/utils/trace.ts b/packages/functions/src/utils/trace.ts new file mode 100644 index 0000000000..de8e69b590 --- /dev/null +++ b/packages/functions/src/utils/trace.ts @@ -0,0 +1,21 @@ +import { AsyncLocalStorage } from 'async_hooks'; +import express from 'express'; + +interface Trace { + trace: string; +} + +export const traceCtx = new AsyncLocalStorage(); + +export const traceMiddleware = ( + req: express.Request, + _res: express.Response, + next: express.NextFunction, +) => { + const traceHeader = req.header('X-Cloud-Trace-Context'); + const [trace] = (traceHeader || '').split('/'); + + traceCtx.run({ trace }, () => { + next(); + }); +}; diff --git a/packages/functions/src/utils/wallet.utils.ts b/packages/functions/src/utils/wallet.utils.ts index 720b7bd528..e60bbba47a 100644 --- a/packages/functions/src/utils/wallet.utils.ts +++ b/packages/functions/src/utils/wallet.utils.ts @@ -1,9 +1,8 @@ -import { build5Db } from '@build-5/database'; +import { PgMemberUpdate, build5Db } from '@build-5/database'; import { Build5Request, COL, DecodedToken, - Member, Network, NetworkAddress, WEN_FUNC, @@ -63,7 +62,7 @@ export const decodeAuth = async ( } if (req.customToken) { - await validateWithIdToken(req, func); + validateWithIdToken(req, func); return { address: req.address, project, body: req.body }; } @@ -82,7 +81,7 @@ const validateWithSignature = async (req: Build5Request) => { throw unAuthenticated(WenError.invalid_signature); } - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${req.address}`); + const memberDocRef = build5Db().doc(COL.MEMBER, req.address); await memberDocRef.update({ nonce: getRandomNonce() }); }; @@ -98,10 +97,10 @@ const validateLegacyPubKey = async (req: Build5Request) => { const validatedAddress = (member.validatedAddress || {})[network] || address; const updateData = { nonce: getRandomNonce(), - validatedAddress: { [network]: validatedAddress }, + [`${network}Address`]: validatedAddress, }; - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${address}`); - await memberDocRef.set(updateData, true); + const memberDocRef = build5Db().doc(COL.MEMBER, address); + await memberDocRef.upsert(updateData); return address; }; @@ -171,12 +170,12 @@ const validateWithPublicKey = async (req: Build5Request) => { } const validatedAddress = (member.validatedAddress || {})[network] || address; - const updateData = { + const updateData: PgMemberUpdate = { nonce: getRandomNonce(), - validatedAddress: { [network]: validatedAddress }, + [`${network}Address`]: validatedAddress, }; - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${address}`); - await memberDocRef.set(updateData, true); + const memberDocRef = build5Db().doc(COL.MEMBER, address); + await memberDocRef.upsert(updateData); return address; }; @@ -201,8 +200,8 @@ const validatePubKey = async (info: INodeInfo, req: Build5Request) => { }; const getMember = async (address: NetworkAddress) => { - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${address}`); - const member = await memberDocRef.get(); + const memberDocRef = build5Db().doc(COL.MEMBER, address); + const member = await memberDocRef.get(); if (!member) { throw unAuthenticated(WenError.failed_to_decode_token); } @@ -212,7 +211,7 @@ const getMember = async (address: NetworkAddress) => { return member; }; -const validateWithIdToken = async (req: Build5Request, func: WEN_FUNC) => { +const validateWithIdToken = (req: Build5Request, func: WEN_FUNC) => { const decoded = jwt.verify(req.customToken!, getJwtSecretKey()); if (get(decoded, 'uid', '') !== req.address) { diff --git a/packages/functions/test-service-account-key.json b/packages/functions/test-service-account-key.json deleted file mode 100644 index 0d81536796..0000000000 --- a/packages/functions/test-service-account-key.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "service_account", - "project_id": "soonaverse-dev", - "private_key_id": "65e9f883d2975e13210e66bdea3dcae6f0cce4f0", - "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCzziu+Fr1nldr5\nr0CWLUQfd1VGV5ewwE1rYlRM+Pr6hPkrUbCklwxekUpYR/UQtnmCMpVKKq3rIQ/L\nbqHryOQ7/U99gbojonbaJgIznkvuWR3w6sBAGe4EGZMNLhwtsKihRFZX3/3vlyNd\nFDnJirYMYC0T9GuytVCaaGFqemPeVIlh5eM45puhSBMgFFE0533bdpEe/v6J+7Pf\n5o/t9XzZ3vdXIeo7aMlQcbu2L6nYbxYUSMz043oJg1ZFv7tPf0XyuwOAAdvsBLhB\n9NHlBHC+f+ar1NEcsHSgkVAkIeNdQroleSrR1LPrW4WjFSxY5hmdmTk3R6mhoYnT\nheW9xlv3AgMBAAECggEABrRvnXkum0ATeCUTWlDveIw+zKPeibOaD3Y4C4jAnyU5\n6hDJQ/ydSaIkV2do2YncZ8D9dSm4mOB/kh1FgiEtyu42unONyTS5Nt2c+RIe5bvt\nVGWvQT9WSKaFfRkqPtVBbIYRAYTeQhgXianZP8023ajxIAyIvui+S+EMOj1nH6Fk\n/79BiL8q6zaEVk9mwAFJ6+OS6JGpuY+GAxN2VA3HsyNI/B3F0ApJXS911ap/6Wbf\nwgwWGB8AH5qmh5UCOj8jOwyIqU/nyxZJyaALLIf+0YunHqjC4VSzyTV2Cwg9FDAt\n7XtD4XJEvLYcMF6GaX84ZIvLtRz9pDZ12m2BuyeM8QKBgQDmshOujnaxM4/COAhC\nNkkGCa85bGf9d8zb1d4cHYMqPI9LwstBkNuBPn/y/Y/uZJH+nZp3fZlHAd/DVak6\nKW1ZRHgrQ+TvxUZdrhukE/KJ/43VcLXdkjcAQJ4HzOLT2mkcgg7a2dZYBaiknVmD\nFI+JijguhFPj75lxUXtVqdJLBwKBgQDHhxkBzsP2ikWkAvGaHfQliNGB5fbFO758\n+wVjwBf7MFoLoZkHEZV/S6ohbyOpPF3jAgB/hS1d1ABw/aZDffRwVhVXmKNhRDke\n3BN6VMwQYY+U7Py+xTuD/gy/BvVNcg/89u+bru4M8z7SlganFRAgrWqv/fhI7iHJ\n0J77WJb7kQKBgQDe3fB3tTfjTu218s2/sZPwWlDGh/0aeK8XPdC6lqRNnH3O8hvM\ndrYocQnI5L80zkHgmb9NarA2UhArNEktYDI8iBITsh6sqIenHvmjFIY+XP1X0vBP\nYt7xxnslDAGiKyFaoibZtJMHLEhU55I/ORDGDhrijYJB9Qnm2JHvGwWG5wKBgQCi\nGsuhYVhqrApKZy3dNarO9+qnK6uisJhhuBu34DBbnvv5aTAHwyx/gHzXrxD9BROO\nRGkdMZkbGwvEwP9c5C89OWMbiOJsOt5hiRG2GMC2Kl1Z9HSflWR2J2g5pzCS3DHL\nJuCizquPD+0hcEw1YPJ6ago8tA0NS5NeAMW5lU8NUQKBgQCvRb0tYsYmYXiZ4jMC\nbiM9cqGKnvVmqikDzjxEaX4I5WWHdp8TGXWnYwo2PKh80gPBpVcLNZRvY07gp0MZ\n6cpIaPKGyvt3Bzgh75bY6IJ6qQA6hsqnMVpqp8dflTVyxcimUY5I8f7N865OPE6+\nUjgf4LQdGbUOCa/Kba1yCURELw==\n-----END PRIVATE KEY-----\n", - "client_email": "firebase-adminsdk-muies@soonaverse-dev.iam.gserviceaccount.com", - "client_id": "113350559865730053440", - "auth_uri": "https://accounts.google.com/o/oauth2/auth", - "token_uri": "https://oauth2.googleapis.com/token", - "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", - "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-muies%40soonaverse-dev.iam.gserviceaccount.com" -} diff --git a/packages/functions/test-tangle/address.spec.ts b/packages/functions/test-tangle/address.spec.ts index 39d69c5c33..26a68ca290 100644 --- a/packages/functions/test-tangle/address.spec.ts +++ b/packages/functions/test-tangle/address.spec.ts @@ -12,27 +12,19 @@ import { Transaction, TransactionPayloadType, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; import { isEmpty, set } from 'lodash'; import { getAddress } from '../src/utils/address.utils'; import { dateToTimestamp } from '../src/utils/dateTime.utils'; -import * as wallet from '../src/utils/wallet.utils'; -import { - createMember, - createSpace, - validateMemberAddressFunc, - validateSpaceAddressFunc, - wait, -} from '../test/controls/common'; -import { getWallet } from '../test/set-up'; +import { validateMemberAddressFunc, wait } from '../test/controls/common'; +import { getWallet, mockWalletReturnValue, testEnv } from '../test/set-up'; import { getTangleOrder } from './common'; import { requestFundsFromFaucet } from './faucet'; -let walletSpy: any; - const awaitMemberAddressValidation = async (memberId: string, network: Network) => { - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${memberId}`); + const memberDocRef = build5Db().doc(COL.MEMBER, memberId); await wait(async () => { const member = await memberDocRef.get(); return !isEmpty(getAddress(member, network)); @@ -40,7 +32,7 @@ const awaitMemberAddressValidation = async (memberId: string, network: Network) }; const awaitSpaceAddressValidation = async (space: string, network: Network) => { - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${space}`); + const spaceDocRef = build5Db().doc(COL.SPACE, space); await wait(async () => { const space = await spaceDocRef.get(); return !isEmpty(getAddress(space, network)); @@ -53,13 +45,14 @@ describe('Address validation', () => { let tangleOrder: Transaction; beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - member = await createMember(walletSpy); - await build5Db().doc(`${COL.MEMBER}/${member}`).update({ validatedAddress: {} }); + member = await testEnv.createMember(); + await build5Db() + .doc(COL.MEMBER, member) + .update({ smrAddress: '', rmsAddress: '', iotaAddress: '', atoiAddress: '' }); }); const validateMemberAddress = async (network: Network, expiresAt?: Timestamp) => { - const order = await validateMemberAddressFunc(walletSpy, member, network); + const order = await validateMemberAddressFunc(member, network); const { faucetAddress } = await requestFundsFromFaucet( network, order.payload.targetAddress!, @@ -69,11 +62,19 @@ describe('Address validation', () => { await awaitMemberAddressValidation(member, network); - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${member}`); + const memberDocRef = build5Db().doc(COL.MEMBER, member); const data = await memberDocRef.get(); expect(data.validatedAddress![network]).toBe(faucetAddress.bech32); }; + const validateSpaceAddressFunc = async (adr: string, space: string, network?: Network) => { + mockWalletReturnValue(adr, network ? { space, network } : { space }); + const order = await testEnv.wrap(WEN_FUNC.validateAddress); + expect(order?.type).toBe(TransactionType.ORDER); + expect(order?.payload.type).toBe(TransactionPayloadType.SPACE_ADDRESS_VALIDATION); + return order; + }; + it.each([Network.ATOI, Network.RMS])( 'Should validate member address with network', async (network: Network) => { @@ -87,7 +88,7 @@ describe('Address validation', () => { }); const validateSpace = async (network: Network) => { - const order = await validateSpaceAddressFunc(walletSpy, member, space, network); + const order = await validateSpaceAddressFunc(member, space, network); const { faucetAddress } = await requestFundsFromFaucet( network, order.payload.targetAddress!, @@ -96,7 +97,7 @@ describe('Address validation', () => { await awaitSpaceAddressValidation(space, network); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${space}`); + const spaceDocRef = build5Db().doc(COL.SPACE, space); const spaceData = await spaceDocRef.get(); expect(spaceData.validatedAddress![network]).toBe(faucetAddress.bech32); }; @@ -104,15 +105,19 @@ describe('Address validation', () => { it.each([Network.ATOI, Network.RMS])( 'Should validate space address with network', async (network: Network) => { - space = (await createSpace(walletSpy, member)).uid; - await build5Db().doc(`${COL.SPACE}/${space}`).update({ validatedAddress: {} }); + space = (await testEnv.createSpace(member)).uid; + await build5Db() + .doc(COL.SPACE, space) + .update({ smrAddress: '', rmsAddress: '', iotaAddress: '', atoiAddress: '' }); await validateSpace(network); }, ); it('Should validate space address with both network', async () => { - space = (await createSpace(walletSpy, member)).uid; - await build5Db().doc(`${COL.SPACE}/${space}`).update({ validatedAddress: {} }); + space = (await testEnv.createSpace(member)).uid; + await build5Db() + .doc(COL.SPACE, space) + .update({ smrAddress: '', rmsAddress: '', iotaAddress: '', atoiAddress: '' }); await validateSpace(Network.ATOI); await validateSpace(Network.RMS); }); @@ -125,8 +130,8 @@ describe('Address validation', () => { const walletService = await getWallet(network); const tmpAddress = await walletService.getNewIotaAddressDetails(); - const order = await validateMemberAddressFunc(walletSpy, member, network); - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${member}`); + const order = await validateMemberAddressFunc(member, network); + const memberDocRef = build5Db().doc(COL.MEMBER, member); let memberData = await memberDocRef.get(); await requestFundsFromFaucet(network, tmpAddress.bech32, order.payload.amount!); @@ -153,7 +158,7 @@ describe('Address validation', () => { .collection(COL.TRANSACTION) .where('type', '==', TransactionType.CREDIT) .where('member', '==', member) - .get(); + .get(); return snap.length === 1 && snap[0].payload?.walletReference?.confirmed; }); @@ -172,12 +177,14 @@ describe('Address validation', () => { const tmp = await wallet.getNewIotaAddressDetails(); await build5Db() - .doc(`${COL.MEMBER}/${member}`) - .set({ validatedAddress: { [network]: tmp.bech32 } }, true); + .doc(COL.MEMBER, member) + .upsert({ [`${network}Address`]: tmp.bech32 }); if (validateSpace) { - space = (await createSpace(walletSpy, member)).uid; - await build5Db().doc(`${COL.SPACE}/${space}`).update({ validatedAddress: {} }); + space = (await testEnv.createSpace(member)).uid; + await build5Db() + .doc(COL.SPACE, space) + .update({ smrAddress: '', rmsAddress: '', iotaAddress: '', atoiAddress: '' }); } await requestFundsFromFaucet(network, tmp.bech32, 5 * MIN_IOTA_AMOUNT); @@ -195,15 +202,15 @@ describe('Address validation', () => { .where('member', '==', member); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length > 0 && snap[0]?.payload?.walletReference?.confirmed; }); if (validateSpace) { - const spaceData = await build5Db().doc(`${COL.SPACE}/${space}`).get(); + const spaceData = await build5Db().doc(COL.SPACE, space).get(); expect(spaceData.validatedAddress![network]).toBe(tmp.bech32); } else { - const memberData = await build5Db().doc(`${COL.MEMBER}/${member}`).get(); + const memberData = await build5Db().doc(COL.MEMBER, member).get(); expect(memberData.validatedAddress![network]).toBe(tmp.bech32); expect(memberData.prevValidatedAddresses).toEqual([tmp.bech32]); } @@ -211,7 +218,7 @@ describe('Address validation', () => { const snap = await build5Db() .collection(COL.TRANSACTION) .where('member', '==', member) - .where('payload.type', '==', TransactionPayloadType.TANGLE_TRANSFER) + .where('payload_type', '==', TransactionPayloadType.TANGLE_TRANSFER) .get(); expect(snap.length).toBe(1); }); 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 index 1143897aeb..18ae8b7fda 100644 --- a/packages/functions/test-tangle/auction-tangle/auction.bit.tangle.spec.ts +++ b/packages/functions/test-tangle/auction-tangle/auction.bit.tangle.spec.ts @@ -1,10 +1,9 @@ -import { IDocument, build5Db } from '@build-5/database'; +import { IDocument, Update, build5Db } from '@build-5/database'; import { Auction, AuctionType, COL, MIN_IOTA_AMOUNT, - Member, Network, Space, TangleRequestType, @@ -16,36 +15,32 @@ 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, createSpace, wait } from '../../test/controls/common'; -import { getWallet } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { getWallet, testEnv } from '../../test/set-up'; import { getTangleOrder } from '../common'; import { requestFundsFromFaucet } from '../faucet'; -let walletSpy: any; - describe('Auction tangle test', () => { let member: string; let space: Space; let memberAddress: AddressDetails; let w: Wallet; let tangleOrder: Transaction; - let auctionDocRef: IDocument; + 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); - space = await createSpace(walletSpy, member); + member = await testEnv.createMember(); + space = await testEnv.createSpace(member); - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${member}`); - const memberData = await memberDocRef.get(); + const memberDocRef = build5Db().doc(COL.MEMBER, member); + const memberData = await memberDocRef.get(); const bech32 = getAddress(memberData, Network.RMS); memberAddress = await w.getAddressDetails(bech32); @@ -65,14 +60,14 @@ describe('Auction tangle test', () => { .where('member', '==', member) .where('type', '==', TransactionType.CREDIT_TANGLE_REQUEST); await wait(async () => { - const credits = await creaditQuery.get(); + const credits = await creaditQuery.get(); return credits.length === 1 && credits[0].payload.walletReference?.confirmed; }); - const credits = await creaditQuery.get(); + const credits = await creaditQuery.get(); expect(credits[0].payload.response?.auction).toBeDefined(); - auctionDocRef = build5Db().doc(`${COL.AUCTION}/${credits[0].payload.response?.auction}`); + auctionDocRef = build5Db().doc(COL.AUCTION, credits[0].payload.response?.auction! as string); auction = await auctionDocRef.get(); }); diff --git a/packages/functions/test-tangle/award-tangle/award-tangle_1.spec.ts b/packages/functions/test-tangle/award-tangle/award-tangle_1.spec.ts index 2b9ba0e2ad..9510045248 100644 --- a/packages/functions/test-tangle/award-tangle/award-tangle_1.spec.ts +++ b/packages/functions/test-tangle/award-tangle/award-tangle_1.spec.ts @@ -2,8 +2,8 @@ import { build5Db } from '@build-5/database'; import { Award, COL, - Member, MIN_IOTA_AMOUNT, + Member, Network, Space, TangleRequestType, @@ -15,15 +15,13 @@ import dayjs from 'dayjs'; 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, createSpace, wait } from '../../test/controls/common'; -import { getWallet, MEDIA } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { MEDIA, getWallet, testEnv } from '../../test/set-up'; import { getTangleOrder } from '../common'; import { requestFundsFromFaucet } from '../faucet'; import { saveBaseToken } from './common'; const network = Network.RMS; -let walletSpy: any; const CUSTOM_MEDIA = 'https://ipfs.io/ipfs/bafkreiapx7kczhfukx34ldh3pxhdip5kgvh237dlhp55koefjo6tyupnj4'; @@ -37,18 +35,17 @@ describe('Award tangle request', () => { let tangleOrder: Transaction; beforeAll(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); walletService = await getWallet(network); tangleOrder = await getTangleOrder(Network.RMS); }); beforeEach(async () => { - guardian = await createMember(walletSpy); - space = await createSpace(walletSpy, guardian); + guardian = await testEnv.createMember(); + space = await testEnv.createSpace(guardian); token = await saveBaseToken(space.uid, guardian, Network.RMS); - const guardianDocRef = build5Db().doc(`${COL.MEMBER}/${guardian}`); + const guardianDocRef = build5Db().doc(COL.MEMBER, guardian); const guardianData = await guardianDocRef.get(); const guardianBech32 = getAddress(guardianData, network); guardianAddress = await walletService.getAddressDetails(guardianBech32); @@ -83,7 +80,7 @@ describe('Award tangle request', () => { const credit = snap[0] as Transaction; expect(credit.payload.amount).toBe(5 * MIN_IOTA_AMOUNT); - const awardDocRef = build5Db().doc(`${COL.AWARD}/${credit.payload.response!.award}`); + const awardDocRef = build5Db().doc(COL.AWARD, credit.payload.response!.award! as string); const award = (await awardDocRef.get()) as Award; expect(award.uid).toBe(credit.payload.response!.award); expect(award.name).toBe(newAward.name); diff --git a/packages/functions/test-tangle/award-tangle/award-tangle_2.spec.ts b/packages/functions/test-tangle/award-tangle/award-tangle_2.spec.ts index 2a99bfb02a..8d785e606a 100644 --- a/packages/functions/test-tangle/award-tangle/award-tangle_2.spec.ts +++ b/packages/functions/test-tangle/award-tangle/award-tangle_2.spec.ts @@ -2,8 +2,8 @@ import { build5Db } from '@build-5/database'; import { Award, COL, - Member, MIN_IOTA_AMOUNT, + Member, Network, Space, TangleRequestType, @@ -16,15 +16,12 @@ 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, createSpace, wait } from '../../test/controls/common'; -import { getWallet, MEDIA } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { MEDIA, getWallet, testEnv } from '../../test/set-up'; import { getTangleOrder } from '../common'; import { requestFundsFromFaucet } from '../faucet'; import { saveBaseToken } from './common'; -let walletSpy: any; - describe('Award tangle request', () => { let guardian: string; let space: Space; @@ -36,14 +33,13 @@ describe('Award tangle request', () => { const beforeEach = async (network: Network) => { tangleOrder = await getTangleOrder(network); - walletSpy = jest.spyOn(wallet, 'decodeAuth'); walletService = await getWallet(network); - guardian = await createMember(walletSpy); - space = await createSpace(walletSpy, guardian); + guardian = await testEnv.createMember(); + space = await testEnv.createSpace(guardian); token = await saveBaseToken(space.uid, guardian, network); - const guardianDocRef = build5Db().doc(`${COL.MEMBER}/${guardian}`); + const guardianDocRef = build5Db().doc(COL.MEMBER, guardian); const guardianData = await guardianDocRef.get(); const guardianBech32 = getAddress(guardianData, network); guardianAddress = await walletService.getAddressDetails(guardianBech32); @@ -87,7 +83,7 @@ describe('Award tangle request', () => { credit.payload.response!.amount as number, ); - const awardDocRef = build5Db().doc(`${COL.AWARD}/${credit.payload.response!.award}`); + const awardDocRef = build5Db().doc(COL.AWARD, credit.payload.response!.award! as string); await wait(async () => { const award = (await awardDocRef.get()) as Award; return award.funded; @@ -117,10 +113,10 @@ describe('Award tangle request', () => { const snap = await creditQuery.get(); return snap.length === 1; }); - let snap = await creditQuery.get(); + let snap = await creditQuery.get(); let credit = snap[0] as Transaction; expect(credit.payload.amount).toBe(MIN_IOTA_AMOUNT); - const awardDocRef = build5Db().doc(`${COL.AWARD}/${credit.payload.response!.award}`); + const awardDocRef = build5Db().doc(COL.AWARD, credit.payload.response!.award as string); await walletService.send(guardianAddress, tangleOrder.payload.targetAddress!, MIN_IOTA_AMOUNT, { customMetadata: { @@ -134,7 +130,7 @@ describe('Award tangle request', () => { const snap = await creditQuery.get(); return snap.length === 2; }); - snap = await creditQuery.get(); + snap = await creditQuery.get(); credit = snap.find((doc) => doc?.payload?.response?.award === undefined)!; await requestFundsFromFaucet( Network.RMS, diff --git a/packages/functions/test-tangle/award-tangle/award-tangle_3.spec.ts b/packages/functions/test-tangle/award-tangle/award-tangle_3.spec.ts index 33f1ce3844..d1d4a83195 100644 --- a/packages/functions/test-tangle/award-tangle/award-tangle_3.spec.ts +++ b/packages/functions/test-tangle/award-tangle/award-tangle_3.spec.ts @@ -2,8 +2,8 @@ import { build5Db } from '@build-5/database'; import { Award, COL, - Member, MIN_IOTA_AMOUNT, + Member, NativeToken, Network, SOON_PROJECT_ID, @@ -21,13 +21,11 @@ import { AddressDetails } from '../../src/services/wallet/wallet.service'; import { getAddress } from '../../src/utils/address.utils'; import { serverTime } from '../../src/utils/dateTime.utils'; import * as wallet from '../../src/utils/wallet.utils'; -import { createMember, createSpace, getRandomSymbol, wait } from '../../test/controls/common'; -import { getWallet, MEDIA } from '../../test/set-up'; +import { getRandomSymbol, wait } from '../../test/controls/common'; +import { MEDIA, getWallet, testEnv } from '../../test/set-up'; import { getTangleOrder } from '../common'; import { requestFundsFromFaucet, requestMintedTokenFromFaucet } from '../faucet'; -let walletSpy: any; - describe('Award tangle request', () => { let guardian: string; let space: Space; @@ -39,14 +37,13 @@ describe('Award tangle request', () => { const beforeEach = async (network: Network) => { tangleOrder = await getTangleOrder(network); - walletSpy = jest.spyOn(wallet, 'decodeAuth'); walletService = await getWallet(network); - guardian = await createMember(walletSpy); - space = await createSpace(walletSpy, guardian); + guardian = await testEnv.createMember(); + space = await testEnv.createSpace(guardian); token = await saveToken(space.uid, guardian, network); - const guardianDocRef = build5Db().doc(`${COL.MEMBER}/${guardian}`); + const guardianDocRef = build5Db().doc(COL.MEMBER, guardian); const guardianData = await guardianDocRef.get(); const guardianBech32 = getAddress(guardianData, network); guardianAddress = await walletService.getAddressDetails(guardianBech32); @@ -80,7 +77,7 @@ describe('Award tangle request', () => { let snap = await creditQuery.get(); let credit = snap[0] as Transaction; expect(credit.payload.amount).toBe(MIN_IOTA_AMOUNT); - const awardDocRef = build5Db().doc(`${COL.AWARD}/${credit.payload.response!.award}`); + const awardDocRef = build5Db().doc(COL.AWARD, credit.payload.response!.award as string); await requestMintedTokenFromFaucet( walletService, @@ -144,9 +141,9 @@ const saveToken = async (space: string, guardian: string, network: Network) => { network, tokenId: MINTED_TOKEN_ID, }, - }; - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).set(token); - return token as Token; + } as Token; + await build5Db().doc(COL.TOKEN, token.uid).create(token); + return token; }; export const VAULT_MNEMONIC = diff --git a/packages/functions/test-tangle/award-tangle/award-tangle_4.spec.ts b/packages/functions/test-tangle/award-tangle/award-tangle_4.spec.ts index f6262cc434..3b9e483feb 100644 --- a/packages/functions/test-tangle/award-tangle/award-tangle_4.spec.ts +++ b/packages/functions/test-tangle/award-tangle/award-tangle_4.spec.ts @@ -2,8 +2,8 @@ import { build5Db } from '@build-5/database'; import { Award, COL, - Member, MIN_IOTA_AMOUNT, + Member, Network, Space, TangleRequestType, @@ -17,15 +17,13 @@ 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, createSpace, wait } from '../../test/controls/common'; -import { getWallet, MEDIA } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { MEDIA, getWallet, testEnv } from '../../test/set-up'; import { getTangleOrder } from '../common'; import { requestFundsFromFaucet } from '../faucet'; import { saveBaseToken } from './common'; const network = Network.RMS; -let walletSpy: any; describe('Award tangle request', () => { let guardian: string; @@ -38,15 +36,14 @@ describe('Award tangle request', () => { const beforeEach = async (network: Network) => { tangleOrder = await getTangleOrder(network); - walletSpy = jest.spyOn(wallet, 'decodeAuth'); walletService = await getWallet(network); - guardian = await createMember(walletSpy); - space = await createSpace(walletSpy, guardian); + guardian = await testEnv.createMember(); + space = await testEnv.createSpace(guardian); token = await saveBaseToken(space.uid, guardian, network); - const guardianDocRef = build5Db().doc(`${COL.MEMBER}/${guardian}`); + const guardianDocRef = build5Db().doc(COL.MEMBER, guardian); const guardianData = await guardianDocRef.get(); const guardianBech32 = getAddress(guardianData, network); guardianAddress = await walletService.getAddressDetails(guardianBech32); @@ -69,7 +66,7 @@ describe('Award tangle request', () => { const snap = await creditQuery.get(); return snap.length === 1; }); - let snap = await creditQuery.get(); + let snap = await creditQuery.get(); let credit = snap[0] as Transaction; await requestFundsFromFaucet( network, @@ -77,7 +74,7 @@ describe('Award tangle request', () => { credit.payload.response!.amount as number, ); - const awardDocRef = build5Db().doc(`${COL.AWARD}/${credit.payload.response!.award}`); + const awardDocRef = build5Db().doc(COL.AWARD, credit.payload.response!.award as string); await wait(async () => { const award = (await awardDocRef.get()) as Award; return award.approved; @@ -94,13 +91,13 @@ describe('Award tangle request', () => { }); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return ( snap.length === 2 && snap.reduce((acc, act) => acc && (act?.payload?.walletReference?.confirmed || false), true) ); }); - snap = await creditQuery.get(); + snap = await creditQuery.get(); credit = snap.find((d) => !isEmpty(d?.payload?.response?.badges))!; expect(Object.keys(credit.payload.response!.badges as any).length).toBe(150); diff --git a/packages/functions/test-tangle/award-tangle/award-tangle_5.spec.ts b/packages/functions/test-tangle/award-tangle/award-tangle_5.spec.ts index 1a65b11fa9..e380298880 100644 --- a/packages/functions/test-tangle/award-tangle/award-tangle_5.spec.ts +++ b/packages/functions/test-tangle/award-tangle/award-tangle_5.spec.ts @@ -2,8 +2,8 @@ import { build5Db } from '@build-5/database'; import { Award, COL, - Member, MIN_IOTA_AMOUNT, + Member, Network, NetworkAddress, Space, @@ -18,15 +18,13 @@ 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, createSpace, wait } from '../../test/controls/common'; -import { getWallet, MEDIA } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { MEDIA, getWallet, testEnv } from '../../test/set-up'; import { getTangleOrder } from '../common'; import { requestFundsFromFaucet } from '../faucet'; import { saveBaseToken } from './common'; const network = Network.RMS; -let walletSpy: any; describe('Award tangle request', () => { let guardian: string; @@ -37,18 +35,17 @@ describe('Award tangle request', () => { let tangleOrder: Transaction; beforeAll(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); walletService = await getWallet(network); tangleOrder = await getTangleOrder(Network.RMS); }); beforeEach(async () => { - guardian = await createMember(walletSpy); - space = await createSpace(walletSpy, guardian); + guardian = await testEnv.createMember(); + space = await testEnv.createSpace(guardian); token = await saveBaseToken(space.uid, guardian, Network.RMS); - const guardianDocRef = build5Db().doc(`${COL.MEMBER}/${guardian}`); + const guardianDocRef = build5Db().doc(COL.MEMBER, guardian); const guardianData = await guardianDocRef.get(); const guardianBech32 = getAddress(guardianData, network); guardianAddress = await walletService.getAddressDetails(guardianBech32); @@ -78,7 +75,7 @@ describe('Award tangle request', () => { credit.payload.response!.amount as number, ); - const awardDocRef = build5Db().doc(`${COL.AWARD}/${credit.payload.response!.award}`); + const awardDocRef = build5Db().doc(COL.AWARD, credit.payload.response!.award as string); await wait(async () => { const award = (await awardDocRef.get()) as Award; return award.approved; @@ -96,7 +93,7 @@ describe('Award tangle request', () => { }); await wait(async () => { - const snap = await badgeQuery(tmp.bech32).get(); + const snap = await badgeQuery(tmp.bech32).get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); @@ -113,7 +110,7 @@ describe('Award tangle request', () => { const badgeQuery = (targetAddress: NetworkAddress) => build5Db() .collection(COL.TRANSACTION) - .where('payload.type', '==', TransactionPayloadType.BADGE) + .where('payload_type', '==', TransactionPayloadType.BADGE) .where('member', '==', targetAddress); const awardRequest = (space: string, tokenSymbol: string) => ({ diff --git a/packages/functions/test-tangle/award-tangle/award-tangle_6.spec.ts b/packages/functions/test-tangle/award-tangle/award-tangle_6.spec.ts index fc62400256..d2b745c700 100644 --- a/packages/functions/test-tangle/award-tangle/award-tangle_6.spec.ts +++ b/packages/functions/test-tangle/award-tangle/award-tangle_6.spec.ts @@ -2,8 +2,8 @@ import { build5Db } from '@build-5/database'; import { Award, COL, - Member, MIN_IOTA_AMOUNT, + Member, Network, Space, TangleRequestType, @@ -17,15 +17,13 @@ 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, createSpace, wait } from '../../test/controls/common'; -import { getWallet, MEDIA } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { MEDIA, getWallet, testEnv } from '../../test/set-up'; import { getTangleOrder } from '../common'; import { requestFundsFromFaucet } from '../faucet'; import { saveBaseToken } from './common'; const network = Network.RMS; -let walletSpy: any; describe('Award tangle request', () => { let guardian: string; @@ -36,18 +34,17 @@ describe('Award tangle request', () => { let tangleOrder: Transaction; beforeAll(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); walletService = await getWallet(network); tangleOrder = await getTangleOrder(Network.RMS); }); beforeEach(async () => { - guardian = await createMember(walletSpy); - space = await createSpace(walletSpy, guardian); + guardian = await testEnv.createMember(); + space = await testEnv.createSpace(guardian); token = await saveBaseToken(space.uid, guardian, Network.RMS); - const guardianDocRef = build5Db().doc(`${COL.MEMBER}/${guardian}`); + const guardianDocRef = build5Db().doc(COL.MEMBER, guardian); const guardianData = await guardianDocRef.get(); const guardianBech32 = getAddress(guardianData, network); guardianAddress = await walletService.getAddressDetails(guardianBech32); @@ -69,7 +66,7 @@ describe('Award tangle request', () => { const snap = await creditQuery.get(); return snap.length === 1; }); - let snap = await creditQuery.get(); + let snap = await creditQuery.get(); let credit = snap[0]; await requestFundsFromFaucet( Network.RMS, @@ -77,7 +74,7 @@ describe('Award tangle request', () => { credit.payload.response!.amount as number, ); - const awardDocRef = build5Db().doc(`${COL.AWARD}/${credit.payload.response!.award}`); + const awardDocRef = build5Db().doc(COL.AWARD, credit.payload.response!.award as string); await wait(async () => { const award = await awardDocRef.get(); return award.approved; @@ -94,10 +91,10 @@ describe('Award tangle request', () => { }); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return snap.length === 2; }); - snap = await creditQuery.get(); + snap = await creditQuery.get(); credit = snap.find((d) => !isEmpty(d.payload?.response?.badges))!; expect(Object.keys(credit.payload.response!.badges as any).length).toBe(150); diff --git a/packages/functions/test-tangle/award-tangle/award-tangle_7.spec.ts b/packages/functions/test-tangle/award-tangle/award-tangle_7.spec.ts index fc43984c69..39bc768301 100644 --- a/packages/functions/test-tangle/award-tangle/award-tangle_7.spec.ts +++ b/packages/functions/test-tangle/award-tangle/award-tangle_7.spec.ts @@ -2,8 +2,8 @@ import { build5Db } from '@build-5/database'; import { Award, COL, - Member, MIN_IOTA_AMOUNT, + Member, Network, Space, TangleRequestType, @@ -15,15 +15,12 @@ import dayjs from 'dayjs'; 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, createSpace, wait } from '../../test/controls/common'; -import { getWallet, MEDIA } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { MEDIA, getWallet, testEnv } from '../../test/set-up'; import { getTangleOrder } from '../common'; import { requestFundsFromFaucet } from '../faucet'; import { saveBaseToken } from './common'; -let walletSpy: any; - describe('Award tangle request', () => { let guardian: string; let space: Space; @@ -36,14 +33,14 @@ describe('Award tangle request', () => { const beforeEach = async (network: Network) => { tangleOrder = await getTangleOrder(network); - walletSpy = jest.spyOn(wallet, 'decodeAuth'); + walletService = await getWallet(network); - guardian = await createMember(walletSpy); - space = await createSpace(walletSpy, guardian); + guardian = await testEnv.createMember(); + space = await testEnv.createSpace(guardian); token = await saveBaseToken(space.uid, guardian, network); - const guardianDocRef = build5Db().doc(`${COL.MEMBER}/${guardian}`); + const guardianDocRef = build5Db().doc(COL.MEMBER, guardian); const guardianData = await guardianDocRef.get(); const guardianBech32 = getAddress(guardianData, network); guardianAddress = await walletService.getAddressDetails(guardianBech32); @@ -81,7 +78,7 @@ describe('Award tangle request', () => { const credit = snap[0] as Transaction; expect(credit.payload.amount).toBe(5 * MIN_IOTA_AMOUNT); - const awardDocRef = build5Db().doc(`${COL.AWARD}/${credit.payload.response!.award}`); + const awardDocRef = build5Db().doc(COL.AWARD, credit.payload.response!.award as string); const award = (await awardDocRef.get()) as Award; expect(award.uid).toBe(credit.payload.response!.award); expect(award.name).toBe(newAward.name); diff --git a/packages/functions/test-tangle/award-tangle/common.ts b/packages/functions/test-tangle/award-tangle/common.ts index f98ed354d0..0d03f4c050 100644 --- a/packages/functions/test-tangle/award-tangle/common.ts +++ b/packages/functions/test-tangle/award-tangle/common.ts @@ -16,20 +16,20 @@ import { MEDIA } from '../../test/set-up'; export const awaitAllTransactionsForAward = async (awardId: string) => { const baseTransQuery = build5Db() .collection(COL.TRANSACTION) - .where('payload.award', '==', awardId) - .where('type', 'in', [TransactionType.BILL_PAYMENT, TransactionType.CREDIT]); + .where('payload_award', '==', awardId) + .whereIn('type', [TransactionType.BILL_PAYMENT, TransactionType.CREDIT]); await allConfirmed(baseTransQuery); const nttQuery = build5Db() .collection(COL.TRANSACTION) - .where('payload.award', '==', awardId) - .where('payload.type', '==', TransactionPayloadType.BADGE); + .where('payload_award', '==', awardId) + .where('payload_type', '==', TransactionPayloadType.BADGE); await allConfirmed(nttQuery); }; -const allConfirmed = (query: IQuery) => +const allConfirmed = (query: IQuery) => wait(async () => { - const snap = await query.get(); + const snap = await query.get(); const allConfirmed = snap.reduce( (acc, doc) => acc && doc?.payload?.walletReference?.confirmed, true, @@ -54,7 +54,7 @@ export const saveBaseToken = async (space: string, guardian: string, network: Ne mintingData: { network, }, - }; - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).set(token); - return token as Token; + } as Token; + await build5Db().doc(COL.TOKEN, token.uid).create(token); + return token; }; diff --git a/packages/functions/test-tangle/award/award_1.spec.ts b/packages/functions/test-tangle/award/award_1.spec.ts index 936d74da5f..c23cf7e005 100644 --- a/packages/functions/test-tangle/award/award_1.spec.ts +++ b/packages/functions/test-tangle/award/award_1.spec.ts @@ -2,36 +2,27 @@ import { build5Db } from '@build-5/database'; import { Award, COL, - Member, MIN_IOTA_AMOUNT, + Member, Network, - Space, SUB_COL, + Space, Token, TokenDistribution, Transaction, TransactionPayloadType, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; import { NftOutput, TimelockUnlockCondition, UnlockConditionType } from '@iota/sdk'; import dayjs from 'dayjs'; -import { - approveAwardParticipant, - awardParticipate, - createAward, - fundAward, -} from '../../src/runtime/firebase/award'; -import { claimMintedTokenOrder } from '../../src/runtime/firebase/token/minting'; import { Wallet } from '../../src/services/wallet/wallet'; import { getAddress } from '../../src/utils/address.utils'; -import * as wallet from '../../src/utils/wallet.utils'; -import { createMember, createSpace, mockWalletReturnValue, wait } from '../../test/controls/common'; -import { getWallet, MEDIA, testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { MEDIA, getWallet, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { awaitAllTransactionsForAward, saveBaseToken } from './common'; -let walletSpy: any; - describe('Create award, base', () => { let guardian: string; let member: string; @@ -41,35 +32,31 @@ describe('Create award, base', () => { let now: dayjs.Dayjs; let token: Token; - beforeAll(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - }); - const setup = async (network: Network) => { now = dayjs(); walletService = await getWallet(network); - guardian = await createMember(walletSpy); - member = await createMember(walletSpy); - space = await createSpace(walletSpy, guardian); + guardian = await testEnv.createMember(); + member = await testEnv.createMember(); + space = await testEnv.createSpace(guardian); token = await saveBaseToken(space.uid, guardian, network); - mockWalletReturnValue(walletSpy, guardian, awardRequest(network, space.uid, token.symbol)); - award = await testEnv.wrap(createAward)({}); + mockWalletReturnValue(guardian, awardRequest(network, space.uid, token.symbol)); + award = await testEnv.wrap(WEN_FUNC.createAward); }; it.each([Network.ATOI, Network.RMS])( 'Should create, fund and participate in award', async (network: Network) => { await setup(network); - mockWalletReturnValue(walletSpy, guardian, { uid: award.uid }); - const order = await testEnv.wrap(fundAward)({}); + mockWalletReturnValue(guardian, { uid: award.uid }); + const order = await testEnv.wrap(WEN_FUNC.fundAward); const address = await walletService.getNewIotaAddressDetails(); - await requestFundsFromFaucet(network, address.bech32, order.payload.amount); - await walletService.send(address, order.payload.targetAddress, order.payload.amount, {}); + await requestFundsFromFaucet(network, address.bech32, order.payload.amount!); + await walletService.send(address, order.payload.targetAddress!, order.payload.amount!, {}); - const awardDocRef = build5Db().doc(`${COL.AWARD}/${award.uid}`); + const awardDocRef = build5Db().doc(COL.AWARD, award.uid); await wait(async () => { const award = await awardDocRef.get(); return award.approved && award.funded; @@ -80,36 +67,35 @@ describe('Create award, base', () => { expect(awardData.collectionBlockId).toBeDefined(); expect(awardData.collectionId).toBeDefined(); - mockWalletReturnValue(walletSpy, member, { uid: award.uid }); - await testEnv.wrap(awardParticipate)({}); + mockWalletReturnValue(member, { uid: award.uid }); + await testEnv.wrap(WEN_FUNC.participateAward); - mockWalletReturnValue(walletSpy, guardian, { award: award.uid, members: [member, member] }); - await testEnv.wrap(approveAwardParticipant)({}); + mockWalletReturnValue(guardian, { award: award.uid, members: [member, member] }); + await testEnv.wrap(WEN_FUNC.approveParticipantAward); - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${member}`); + const memberDocRef = build5Db().doc(COL.MEMBER, member); const memberData = await memberDocRef.get(); const memberBech32 = getAddress(memberData, network); - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${token.uid}`); - const distributionDocRef = tokenDocRef.collection(SUB_COL.DISTRIBUTION).doc(member); - let distribution = await distributionDocRef.get(); - expect(distribution.totalUnclaimedAirdrop).toBe(2 * MIN_IOTA_AMOUNT); + const distributionDocRef = build5Db().doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, member); + let distribution = await distributionDocRef.get(); + expect(distribution?.totalUnclaimedAirdrop).toBe(2 * MIN_IOTA_AMOUNT); const nttQuery = build5Db() .collection(COL.TRANSACTION) .where('member', '==', member) - .where('payload.type', '==', TransactionPayloadType.BADGE); + .where('payload_type', '==', TransactionPayloadType.BADGE); await wait(async () => { const snap = await nttQuery.get(); return snap.length === 2; }); - mockWalletReturnValue(walletSpy, member, { symbol: token.symbol }); - const claimOrder = await testEnv.wrap(claimMintedTokenOrder)({}); + mockWalletReturnValue(member, { symbol: token.symbol }); + const claimOrder = await testEnv.wrap(WEN_FUNC.claimMintedTokenOrder); await requestFundsFromFaucet( network, - claimOrder.payload.targetAddress, - claimOrder.payload.amount, + claimOrder.payload.targetAddress!, + claimOrder.payload.amount!, ); const billPaymentQuery = build5Db() @@ -128,7 +114,7 @@ describe('Create award, base', () => { await wait(async () => { let { amount } = await walletService.getBalance(memberBech32); - return amount === 2 * MIN_IOTA_AMOUNT + claimOrder.payload.amount; + return amount === 2 * MIN_IOTA_AMOUNT + claimOrder.payload.amount!; }); await wait(async () => { @@ -150,10 +136,10 @@ describe('Create award, base', () => { const burnAliasQuery = build5Db() .collection(COL.TRANSACTION) - .where('payload.type', '==', TransactionPayloadType.BURN_ALIAS) + .where('payload_type', '==', TransactionPayloadType.BURN_ALIAS) .where('member', '==', guardian); await wait(async () => { - const snap = await burnAliasQuery.get(); + const snap = await burnAliasQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); diff --git a/packages/functions/test-tangle/award/award_10.spec.ts b/packages/functions/test-tangle/award/award_10.spec.ts index 239db273ae..7e19e886b4 100644 --- a/packages/functions/test-tangle/award/award_10.spec.ts +++ b/packages/functions/test-tangle/award/award_10.spec.ts @@ -2,34 +2,26 @@ import { build5Db } from '@build-5/database'; import { Award, COL, - Member, Network, SOON_PROJECT_ID, Space, Token, TokenStatus, + Transaction, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { approveAwardParticipant, createAward, fundAward } from '../../src/runtime/firebase/award'; -import { joinSpace } from '../../src/runtime/firebase/space'; 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 { serverTime } from '../../src/utils/dateTime.utils'; import * as wallet from '../../src/utils/wallet.utils'; -import { - createMember, - createSpace, - getRandomSymbol, - mockWalletReturnValue, - wait, -} from '../../test/controls/common'; -import { MEDIA, getWallet, testEnv } from '../../test/set-up'; +import { getRandomSymbol, wait } from '../../test/controls/common'; +import { MEDIA, getWallet, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet, requestMintedTokenFromFaucet } from '../faucet'; const network = Network.RMS; -let walletSpy: any; describe('Create award, native', () => { let guardian: string; @@ -41,32 +33,31 @@ describe('Create award, native', () => { let token: Token; beforeAll(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); walletService = await getWallet(network); }); beforeEach(async () => { - guardian = await createMember(walletSpy); - member = await createMember(walletSpy); - space = await createSpace(walletSpy, guardian); + guardian = await testEnv.createMember(); + member = await testEnv.createMember(); + space = await testEnv.createSpace(guardian); - mockWalletReturnValue(walletSpy, member, { uid: space?.uid }); - await testEnv.wrap(joinSpace)({}); + mockWalletReturnValue(member, { uid: space?.uid }); + await testEnv.wrap(WEN_FUNC.joinSpace); token = await saveToken(space.uid, guardian); - mockWalletReturnValue(walletSpy, member, awardRequest(space.uid, token.symbol)); - award = await testEnv.wrap(createAward)({}); + mockWalletReturnValue(member, awardRequest(space.uid, token.symbol)); + award = await testEnv.wrap(WEN_FUNC.createAward); - const guardianDocRef = build5Db().doc(`${COL.MEMBER}/${guardian}`); - const guardianData = await guardianDocRef.get(); + const guardianDocRef = build5Db().doc(COL.MEMBER, guardian); + const guardianData = await guardianDocRef.get(); const guardianBech32 = getAddress(guardianData, network); guardianAddress = await walletService.getAddressDetails(guardianBech32); }); it('Should create and issue to upper case address', async () => { - mockWalletReturnValue(walletSpy, guardian, { uid: award.uid }); - const order = await testEnv.wrap(fundAward)({}); + mockWalletReturnValue(guardian, { uid: award.uid }); + const order = await testEnv.wrap(WEN_FUNC.fundAward); await requestFundsFromFaucet(network, guardianAddress.bech32, order.payload.amount); await requestMintedTokenFromFaucet( @@ -76,22 +67,22 @@ describe('Create award, native', () => { VAULT_MNEMONIC, 15, ); - await walletService.send(guardianAddress, order.payload.targetAddress, order.payload.amount, { + await walletService.send(guardianAddress, order.payload.targetAddress!, order.payload.amount!, { nativeTokens: [{ id: MINTED_TOKEN_ID, amount: BigInt(15) }], }); await MnemonicService.store(guardianAddress.bech32, guardianAddress.mnemonic); - const awardDocRef = build5Db().doc(`${COL.AWARD}/${award.uid}`); + const awardDocRef = build5Db().doc(COL.AWARD, award.uid); await wait(async () => { const award = await awardDocRef.get(); return award.approved && award.funded; }); - mockWalletReturnValue(walletSpy, guardian, { + mockWalletReturnValue(guardian, { award: award.uid, members: [member.toUpperCase()], }); - await testEnv.wrap(approveAwardParticipant)({}); + await testEnv.wrap(WEN_FUNC.approveParticipantAward); const snap = await build5Db().collection(COL.AIRDROP).where('member', '==', member).get(); expect(snap.length).toBe(1); @@ -133,9 +124,9 @@ const saveToken = async (space: string, guardian: string) => { network: Network.RMS, tokenId: MINTED_TOKEN_ID, }, - }; - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).set(token); - return token as Token; + } as Token; + await build5Db().doc(COL.TOKEN, token.uid).create(token); + return token; }; export const VAULT_MNEMONIC = diff --git a/packages/functions/test-tangle/award/award_11.spec.ts b/packages/functions/test-tangle/award/award_11.spec.ts index d854fc1d95..57d965f552 100644 --- a/packages/functions/test-tangle/award/award_11.spec.ts +++ b/packages/functions/test-tangle/award/award_11.spec.ts @@ -2,36 +2,27 @@ import { build5Db } from '@build-5/database'; import { Award, COL, - Member, MIN_IOTA_AMOUNT, + Member, Network, - Space, SUB_COL, + Space, Token, TokenDistribution, Transaction, TransactionPayloadType, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; import { NftOutput, TimelockUnlockCondition, UnlockConditionType } from '@iota/sdk'; import dayjs from 'dayjs'; -import { - approveAwardParticipant, - awardParticipate, - createAward, - fundAward, -} from '../../src/runtime/firebase/award'; -import { claimMintedTokenOrder } from '../../src/runtime/firebase/token/minting'; import { Wallet } from '../../src/services/wallet/wallet'; import { getAddress } from '../../src/utils/address.utils'; -import * as wallet from '../../src/utils/wallet.utils'; -import { createMember, createSpace, mockWalletReturnValue, wait } from '../../test/controls/common'; -import { getWallet, MEDIA, testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { MEDIA, getWallet, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { awaitAllTransactionsForAward, saveBaseToken } from './common'; -let walletSpy: any; - describe('Create award, base', () => { let guardian: string; let member: string; @@ -41,34 +32,32 @@ describe('Create award, base', () => { let now: dayjs.Dayjs; let token: Token; - beforeAll(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - }); + beforeAll(async () => {}); const setup = async (network: Network) => { now = dayjs(); walletService = await getWallet(network); - guardian = await createMember(walletSpy); - member = await createMember(walletSpy); - space = await createSpace(walletSpy, guardian); + guardian = await testEnv.createMember(); + member = await testEnv.createMember(); + space = await testEnv.createSpace(guardian); token = await saveBaseToken(space.uid, guardian, network); - mockWalletReturnValue(walletSpy, guardian, awardRequest(network, space.uid, token.symbol)); - award = await testEnv.wrap(createAward)({}); + mockWalletReturnValue(guardian, awardRequest(network, space.uid, token.symbol)); + award = await testEnv.wrap(WEN_FUNC.createAward); }; it('Should create, fund and participate in award, return to sender address', async () => { const network = Network.RMS; await setup(network); - mockWalletReturnValue(walletSpy, guardian, { uid: award.uid }); - const order = await testEnv.wrap(fundAward)({}); + mockWalletReturnValue(guardian, { uid: award.uid }); + const order = await testEnv.wrap(WEN_FUNC.fundAward); const address = await walletService.getNewIotaAddressDetails(); await requestFundsFromFaucet(network, address.bech32, order.payload.amount); - await walletService.send(address, order.payload.targetAddress, order.payload.amount, {}); + await walletService.send(address, order.payload.targetAddress!, order.payload.amount!, {}); - const awardDocRef = build5Db().doc(`${COL.AWARD}/${award.uid}`); + const awardDocRef = build5Db().doc(COL.AWARD, award.uid); await wait(async () => { const award = await awardDocRef.get(); return award.approved && award.funded; @@ -80,32 +69,31 @@ describe('Create award, base', () => { expect(awardData.collectionId).toBeDefined(); expect(awardData.fundingAddress).toBe(address.bech32); - mockWalletReturnValue(walletSpy, member, { uid: award.uid }); - await testEnv.wrap(awardParticipate)({}); + mockWalletReturnValue(member, { uid: award.uid }); + await testEnv.wrap(WEN_FUNC.participateAward); - mockWalletReturnValue(walletSpy, guardian, { award: award.uid, members: [member, member] }); - await testEnv.wrap(approveAwardParticipant)({}); + mockWalletReturnValue(guardian, { award: award.uid, members: [member, member] }); + await testEnv.wrap(WEN_FUNC.approveParticipantAward); - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${member}`); + const memberDocRef = build5Db().doc(COL.MEMBER, member); const memberData = await memberDocRef.get(); const memberBech32 = getAddress(memberData, network); - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${token.uid}`); - const distributionDocRef = tokenDocRef.collection(SUB_COL.DISTRIBUTION).doc(member); + const distributionDocRef = build5Db().doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, member); let distribution = await distributionDocRef.get(); expect(distribution.totalUnclaimedAirdrop).toBe(2 * MIN_IOTA_AMOUNT); const nttQuery = build5Db() .collection(COL.TRANSACTION) .where('member', '==', member) - .where('payload.type', '==', TransactionPayloadType.BADGE); + .where('payload_type', '==', TransactionPayloadType.BADGE); await wait(async () => { const snap = await nttQuery.get(); return snap.length === 2; }); - mockWalletReturnValue(walletSpy, member, { symbol: token.symbol }); - const claimOrder = await testEnv.wrap(claimMintedTokenOrder)({}); + mockWalletReturnValue(member, { symbol: token.symbol }); + const claimOrder = await testEnv.wrap(WEN_FUNC.claimMintedTokenOrder); await requestFundsFromFaucet( network, claimOrder.payload.targetAddress, @@ -128,7 +116,7 @@ describe('Create award, base', () => { await wait(async () => { let { amount } = await walletService.getBalance(memberBech32); - return amount === 2 * MIN_IOTA_AMOUNT + claimOrder.payload.amount; + return amount === 2 * MIN_IOTA_AMOUNT + claimOrder.payload.amount!; }); await wait(async () => { @@ -150,13 +138,13 @@ describe('Create award, base', () => { const burnAliasQuery = build5Db() .collection(COL.TRANSACTION) - .where('payload.type', '==', TransactionPayloadType.BURN_ALIAS) + .where('payload_type', '==', TransactionPayloadType.BURN_ALIAS) .where('member', '==', guardian); await wait(async () => { - const snap = await burnAliasQuery.get(); + const snap = await burnAliasQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); - const snap = await burnAliasQuery.get(); + const snap = await burnAliasQuery.get(); expect(snap[0].payload.targetAddress).toBe(address.bech32); await wait(async () => { diff --git a/packages/functions/test-tangle/award/award_12.spec.ts b/packages/functions/test-tangle/award/award_12.spec.ts index e1a89a0947..a1622c875a 100644 --- a/packages/functions/test-tangle/award/award_12.spec.ts +++ b/packages/functions/test-tangle/award/award_12.spec.ts @@ -2,36 +2,27 @@ import { build5Db } from '@build-5/database'; import { Award, COL, - Member, MIN_IOTA_AMOUNT, + Member, Network, - Space, SUB_COL, + Space, Token, TokenDistribution, Transaction, TransactionPayloadType, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; import { NftOutput, TimelockUnlockCondition, UnlockConditionType } from '@iota/sdk'; import dayjs from 'dayjs'; -import { - approveAwardParticipant, - awardParticipate, - createAward, - fundAward, -} from '../../src/runtime/firebase/award'; -import { claimMintedTokenOrder } from '../../src/runtime/firebase/token/minting'; import { Wallet } from '../../src/services/wallet/wallet'; import { getAddress } from '../../src/utils/address.utils'; -import * as wallet from '../../src/utils/wallet.utils'; -import { createMember, createSpace, mockWalletReturnValue, wait } from '../../test/controls/common'; -import { getWallet, MEDIA, testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { MEDIA, getWallet, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { awaitAllTransactionsForAward, saveBaseToken } from './common'; -let walletSpy: any; - describe('Create award, base', () => { let guardian: string; let member: string; @@ -41,34 +32,32 @@ describe('Create award, base', () => { let now: dayjs.Dayjs; let token: Token; - beforeAll(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - }); + beforeAll(async () => {}); const setup = async (network: Network) => { now = dayjs(); walletService = await getWallet(network); - guardian = await createMember(walletSpy); - member = await createMember(walletSpy); - space = await createSpace(walletSpy, guardian); + guardian = await testEnv.createMember(); + member = await testEnv.createMember(); + space = await testEnv.createSpace(guardian); token = await saveBaseToken(space.uid, guardian, network); - mockWalletReturnValue(walletSpy, guardian, awardRequest(network, space.uid, token.symbol)); - award = await testEnv.wrap(createAward)({}); + mockWalletReturnValue(guardian, awardRequest(network, space.uid, token.symbol)); + award = await testEnv.wrap(WEN_FUNC.createAward); }; it('Should create, fund and participate in award, return to sender address when funding address is missing', async () => { const network = Network.RMS; await setup(network); - mockWalletReturnValue(walletSpy, guardian, { uid: award.uid }); - const order = await testEnv.wrap(fundAward)({}); + mockWalletReturnValue(guardian, { uid: award.uid }); + const order = await testEnv.wrap(WEN_FUNC.fundAward); const address = await walletService.getNewIotaAddressDetails(); await requestFundsFromFaucet(network, address.bech32, order.payload.amount); - await walletService.send(address, order.payload.targetAddress, order.payload.amount, {}); + await walletService.send(address, order.payload.targetAddress!, order.payload.amount!, {}); - const awardDocRef = build5Db().doc(`${COL.AWARD}/${award.uid}`); + const awardDocRef = build5Db().doc(COL.AWARD, award.uid); await wait(async () => { const award = await awardDocRef.get(); return award.approved && award.funded; @@ -79,34 +68,33 @@ describe('Create award, base', () => { expect(awardData.collectionBlockId).toBeDefined(); expect(awardData.collectionId).toBeDefined(); expect(awardData.fundingAddress).toBe(address.bech32); - await awardDocRef.update({ fundingAddress: build5Db().deleteField() }); + await awardDocRef.update({ fundingAddress: undefined }); - mockWalletReturnValue(walletSpy, member, { uid: award.uid }); - await testEnv.wrap(awardParticipate)({}); + mockWalletReturnValue(member, { uid: award.uid }); + await testEnv.wrap(WEN_FUNC.participateAward); - mockWalletReturnValue(walletSpy, guardian, { award: award.uid, members: [member, member] }); - await testEnv.wrap(approveAwardParticipant)({}); + mockWalletReturnValue(guardian, { award: award.uid, members: [member, member] }); + await testEnv.wrap(WEN_FUNC.approveParticipantAward); - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${member}`); + const memberDocRef = build5Db().doc(COL.MEMBER, member); const memberData = await memberDocRef.get(); const memberBech32 = getAddress(memberData, network); - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${token.uid}`); - const distributionDocRef = tokenDocRef.collection(SUB_COL.DISTRIBUTION).doc(member); + const distributionDocRef = build5Db().doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, member); let distribution = await distributionDocRef.get(); expect(distribution.totalUnclaimedAirdrop).toBe(2 * MIN_IOTA_AMOUNT); const nttQuery = build5Db() .collection(COL.TRANSACTION) .where('member', '==', member) - .where('payload.type', '==', TransactionPayloadType.BADGE); + .where('payload_type', '==', TransactionPayloadType.BADGE); await wait(async () => { const snap = await nttQuery.get(); return snap.length === 2; }); - mockWalletReturnValue(walletSpy, member, { symbol: token.symbol }); - const claimOrder = await testEnv.wrap(claimMintedTokenOrder)({}); + mockWalletReturnValue(member, { symbol: token.symbol }); + const claimOrder = await testEnv.wrap(WEN_FUNC.claimMintedTokenOrder); await requestFundsFromFaucet( network, claimOrder.payload.targetAddress, @@ -129,7 +117,7 @@ describe('Create award, base', () => { await wait(async () => { let { amount } = await walletService.getBalance(memberBech32); - return amount === 2 * MIN_IOTA_AMOUNT + claimOrder.payload.amount; + return amount === 2 * MIN_IOTA_AMOUNT + claimOrder.payload.amount!; }); await wait(async () => { @@ -151,13 +139,13 @@ describe('Create award, base', () => { const burnAliasQuery = build5Db() .collection(COL.TRANSACTION) - .where('payload.type', '==', TransactionPayloadType.BURN_ALIAS) + .where('payload_type', '==', TransactionPayloadType.BURN_ALIAS) .where('member', '==', guardian); await wait(async () => { - const snap = await burnAliasQuery.get(); + const snap = await burnAliasQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); - const snap = await burnAliasQuery.get(); + const snap = await burnAliasQuery.get(); expect(snap[0].payload.targetAddress).toBe(address.bech32); await wait(async () => { diff --git a/packages/functions/test-tangle/award/award_1_b.spec.ts b/packages/functions/test-tangle/award/award_1_b.spec.ts index 04080d9da4..3464b38e04 100644 --- a/packages/functions/test-tangle/award/award_1_b.spec.ts +++ b/packages/functions/test-tangle/award/award_1_b.spec.ts @@ -1,32 +1,19 @@ -import { MIN_IOTA_AMOUNT, Network, Token, WenError } from '@build-5/interfaces'; +import { MIN_IOTA_AMOUNT, Network, Token, WEN_FUNC, WenError } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { createAward } from '../../src/runtime/firebase/award'; -import * as wallet from '../../src/utils/wallet.utils'; -import { - createMember, - createSpace, - expectThrow, - mockWalletReturnValue, -} from '../../test/controls/common'; -import { MEDIA, testEnv } from '../../test/set-up'; +import { expectThrow } from '../../test/controls/common'; +import { MEDIA, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { saveBaseToken } from './common'; -let walletSpy: any; - describe('Create award, base', () => { let token: Token; - beforeAll(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - }); - it('Should throw, max lockTime', async () => { const network = Network.RMS; - const guardian = await createMember(walletSpy); - const space = await createSpace(walletSpy, guardian); + const guardian = await testEnv.createMember(); + const space = await testEnv.createSpace(guardian); token = await saveBaseToken(space.uid, guardian, network); - mockWalletReturnValue(walletSpy, guardian, awardRequest(network, space.uid, token.symbol)); - await expectThrow(testEnv.wrap(createAward)({}), WenError.invalid_params.key); + mockWalletReturnValue(guardian, awardRequest(network, space.uid, token.symbol)); + await expectThrow(testEnv.wrap(WEN_FUNC.createAward), WenError.invalid_params.key); }); }); @@ -41,7 +28,7 @@ const awardRequest = (network: Network, space: string, tokenSymbol: string) => ( total: 2, image: MEDIA, tokenReward: MIN_IOTA_AMOUNT, - lockTime: (Math.pow(2, 32) - dayjs().unix() + 100) * 1000, + lockTime: (Math.pow(2, 32) - dayjs().unix() + 1000) * 1000, tokenSymbol, }, network, diff --git a/packages/functions/test-tangle/award/award_2.spec.ts b/packages/functions/test-tangle/award/award_2.spec.ts index 48097e5ca4..657b8c5c84 100644 --- a/packages/functions/test-tangle/award/award_2.spec.ts +++ b/packages/functions/test-tangle/award/award_2.spec.ts @@ -5,27 +5,19 @@ import { Member, Network, SOON_PROJECT_ID, - Space, SUB_COL, + Space, Token, TokenDistribution, - TokenDrop, TokenDropStatus, TokenStatus, Transaction, TransactionPayloadType, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; import { NftOutput, TimelockUnlockCondition, UnlockConditionType } from '@iota/sdk'; import dayjs from 'dayjs'; -import { - approveAwardParticipant, - awardParticipate, - createAward, - fundAward, -} from '../../src/runtime/firebase/award'; -import { joinSpace } from '../../src/runtime/firebase/space'; -import { claimMintedTokenOrder } from '../../src/runtime/firebase/token/minting'; import { MnemonicService } from '../../src/services/wallet/mnemonic'; import { Wallet } from '../../src/services/wallet/wallet'; import { AddressDetails } from '../../src/services/wallet/wallet.service'; @@ -33,20 +25,13 @@ import { getAddress } from '../../src/utils/address.utils'; import { mergeOutputs } from '../../src/utils/basic-output.utils'; import { serverTime } from '../../src/utils/dateTime.utils'; import * as wallet from '../../src/utils/wallet.utils'; -import { - createMember, - createSpace, - getRandomSymbol, - mockWalletReturnValue, - wait, -} from '../../test/controls/common'; -import { getWallet, MEDIA, testEnv } from '../../test/set-up'; +import { getRandomSymbol, wait } from '../../test/controls/common'; +import { MEDIA, getWallet, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken } from '../common'; import { requestFundsFromFaucet, requestMintedTokenFromFaucet } from '../faucet'; import { awaitAllTransactionsForAward } from './common'; const network = Network.RMS; -let walletSpy: any; describe('Create award, native', () => { let guardian: string; @@ -59,35 +44,34 @@ describe('Create award, native', () => { let now: dayjs.Dayjs; beforeAll(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); walletService = await getWallet(network); }); beforeEach(async () => { now = dayjs(); - guardian = await createMember(walletSpy); - member = await createMember(walletSpy); - space = await createSpace(walletSpy, guardian); + guardian = await testEnv.createMember(); + member = await testEnv.createMember(); + space = await testEnv.createSpace(guardian); - mockWalletReturnValue(walletSpy, member, { uid: space?.uid }); - await testEnv.wrap(joinSpace)({}); + mockWalletReturnValue(member, { uid: space?.uid }); + await testEnv.wrap(WEN_FUNC.joinSpace); token = await saveToken(space.uid, guardian); - mockWalletReturnValue(walletSpy, member, awardRequest(space.uid, token.symbol)); - award = await testEnv.wrap(createAward)({}); + mockWalletReturnValue(member, awardRequest(space.uid, token.symbol)); + award = await testEnv.wrap(WEN_FUNC.createAward); - const guardianDocRef = build5Db().doc(`${COL.MEMBER}/${guardian}`); + const guardianDocRef = build5Db().doc(COL.MEMBER, guardian); const guardianData = await guardianDocRef.get(); const guardianBech32 = getAddress(guardianData, network); guardianAddress = await walletService.getAddressDetails(guardianBech32); }); it('Should create and fund award', async () => { - mockWalletReturnValue(walletSpy, guardian, { uid: award.uid }); - const order = await testEnv.wrap(fundAward)({}); + mockWalletReturnValue(guardian, { uid: award.uid }); + const order = await testEnv.wrap(WEN_FUNC.fundAward); - await requestFundsFromFaucet(network, guardianAddress.bech32, order.payload.amount); + await requestFundsFromFaucet(network, guardianAddress.bech32, order.payload.amount!); await requestMintedTokenFromFaucet( walletService, guardianAddress, @@ -95,12 +79,12 @@ describe('Create award, native', () => { VAULT_MNEMONIC, 10, ); - await walletService.send(guardianAddress, order.payload.targetAddress, order.payload.amount, { + await walletService.send(guardianAddress, order.payload.targetAddress!, order.payload.amount!, { nativeTokens: [{ id: MINTED_TOKEN_ID, amount: BigInt('0xA') }], }); await MnemonicService.store(guardianAddress.bech32, guardianAddress.mnemonic); - const awardDocRef = build5Db().doc(`${COL.AWARD}/${award.uid}`); + const awardDocRef = build5Db().doc(COL.AWARD, award.uid); await wait(async () => { const award = await awardDocRef.get(); return award.approved && award.funded; @@ -111,21 +95,20 @@ describe('Create award, native', () => { expect(awardData.collectionBlockId).toBeDefined(); expect(awardData.collectionId).toBeDefined(); - mockWalletReturnValue(walletSpy, member, { uid: award.uid }); - await testEnv.wrap(awardParticipate)({}); + mockWalletReturnValue(member, { uid: award.uid }); + await testEnv.wrap(WEN_FUNC.participateAward); - mockWalletReturnValue(walletSpy, guardian, { award: award.uid, members: [member, member] }); - await testEnv.wrap(approveAwardParticipant)({}); + mockWalletReturnValue(guardian, { award: award.uid, members: [member, member] }); + await testEnv.wrap(WEN_FUNC.approveParticipantAward); - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${token.uid}`); - const distributionDocRef = tokenDocRef.collection(SUB_COL.DISTRIBUTION).doc(member); + const distributionDocRef = build5Db().doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, member); let distribution = await distributionDocRef.get(); expect(distribution.totalUnclaimedAirdrop).toBe(10); const nttQuery = build5Db() .collection(COL.TRANSACTION) .where('member', '==', member) - .where('payload.type', '==', TransactionPayloadType.BADGE); + .where('payload_type', '==', TransactionPayloadType.BADGE); await wait(async () => { const snap = await nttQuery.get(); return snap.length === 2; @@ -133,7 +116,7 @@ describe('Create award, native', () => { await awaitAllTransactionsForAward(award.uid); - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${member}`); + const memberDocRef = build5Db().doc(COL.MEMBER, member); const memberData = await memberDocRef.get(); const memberBech32 = getAddress(memberData, network); await wait(async () => { @@ -154,19 +137,19 @@ describe('Create award, native', () => { } const airdropQuery = build5Db().collection(COL.AIRDROP).where('member', '==', member); - let airdropSnap = await airdropQuery.get(); + let airdropSnap = await airdropQuery.get(); expect(airdropSnap.length).toBe(2); - mockWalletReturnValue(walletSpy, member, { symbol: token.symbol }); - const claimOrder = await testEnv.wrap(claimMintedTokenOrder)({}); + mockWalletReturnValue(member, { symbol: token.symbol }); + const claimOrder = await testEnv.wrap(WEN_FUNC.claimMintedTokenOrder); await requestFundsFromFaucet( network, - claimOrder.payload.targetAddress, - claimOrder.payload.amount, + claimOrder.payload.targetAddress!, + claimOrder.payload.amount!, ); await wait(async () => { - airdropSnap = await airdropQuery.get(); + airdropSnap = await airdropQuery.get(); const allClaimed = airdropSnap.reduce( (acc, doc) => acc && doc.status === TokenDropStatus.CLAIMED, true, @@ -189,16 +172,16 @@ describe('Create award, native', () => { .where('type', '==', TransactionType.CREDIT) .where('member', '==', guardian); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); const burnAliasQuery = build5Db() .collection(COL.TRANSACTION) - .where('payload.type', '==', TransactionPayloadType.BURN_ALIAS) + .where('payload_type', '==', TransactionPayloadType.BURN_ALIAS) .where('member', '==', guardian); await wait(async () => { - const snap = await burnAliasQuery.get(); + const snap = await burnAliasQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); const { amount } = await walletService.getBalance(guardianAddress.bech32); @@ -241,9 +224,10 @@ const saveToken = async (space: string, guardian: string) => { network: Network.RMS, tokenId: MINTED_TOKEN_ID, }, - }; - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).set(token); - return token as Token; + links: [] as URL[], + } as Token; + await build5Db().doc(COL.TOKEN, token.uid).create(token); + return token; }; export const VAULT_MNEMONIC = diff --git a/packages/functions/test-tangle/award/award_3.spec.ts b/packages/functions/test-tangle/award/award_3.spec.ts index f21fb6ea6e..4f2459f395 100644 --- a/packages/functions/test-tangle/award/award_3.spec.ts +++ b/packages/functions/test-tangle/award/award_3.spec.ts @@ -2,24 +2,22 @@ import { build5Db } from '@build-5/database'; import { Award, COL, - MediaStatus, MIN_IOTA_AMOUNT, + MediaStatus, Network, Space, Token, + Transaction, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; import { uploadMediaToWeb3 } from '../../src/cron/media.cron'; -import { createAward, fundAward } from '../../src/runtime/firebase/award'; -import { joinSpace } from '../../src/runtime/firebase/space'; -import * as wallet from '../../src/utils/wallet.utils'; -import { createMember, createSpace, mockWalletReturnValue, wait } from '../../test/controls/common'; -import { MEDIA, testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { MEDIA, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { saveBaseToken } from './common'; const network = Network.RMS; -let walletSpy: any; describe('Create award, base', () => { let guardian: string; @@ -28,30 +26,26 @@ describe('Create award, base', () => { let award: Award; let token: Token; - beforeAll(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - }); - beforeEach(async () => { - guardian = await createMember(walletSpy); - member = await createMember(walletSpy); - space = await createSpace(walletSpy, guardian); + guardian = await testEnv.createMember(); + member = await testEnv.createMember(); + space = await testEnv.createSpace(guardian); - mockWalletReturnValue(walletSpy, member, { uid: space?.uid }); - await testEnv.wrap(joinSpace)({}); + mockWalletReturnValue(member, { uid: space?.uid }); + await testEnv.wrap(WEN_FUNC.joinSpace); token = await saveBaseToken(space.uid, guardian, network); - mockWalletReturnValue(walletSpy, guardian, awardRequest(space.uid, token.symbol)); - award = await testEnv.wrap(createAward)({}); + mockWalletReturnValue(guardian, awardRequest(space.uid, token.symbol)); + award = await testEnv.wrap(WEN_FUNC.createAward); }); it('Should upload award media', async () => { - mockWalletReturnValue(walletSpy, guardian, { uid: award.uid }); - const order = await testEnv.wrap(fundAward)({}); + mockWalletReturnValue(guardian, { uid: award.uid }); + const order = await testEnv.wrap(WEN_FUNC.fundAward); await requestFundsFromFaucet(network, order.payload.targetAddress, order.payload.amount); - const awardDocRef = build5Db().doc(`${COL.AWARD}/${award.uid}`); + const awardDocRef = build5Db().doc(COL.AWARD, award.uid); await wait(async () => { const award = await awardDocRef.get(); return award.approved && award.funded; diff --git a/packages/functions/test-tangle/award/award_4.spec.ts b/packages/functions/test-tangle/award/award_4.spec.ts index 065c204faf..8efa1b4263 100644 --- a/packages/functions/test-tangle/award/award_4.spec.ts +++ b/packages/functions/test-tangle/award/award_4.spec.ts @@ -9,28 +9,17 @@ import { Transaction, TransactionPayloadType, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; import { processExpiredAwards } from '../../src/cron/award.cron'; -import { - approveAwardParticipant, - awardParticipate, - cancelAward, - createAward, - fundAward, -} from '../../src/runtime/firebase/award'; -import { joinSpace } from '../../src/runtime/firebase/space'; -import { claimMintedTokenOrder } from '../../src/runtime/firebase/token/minting'; import { Wallet } from '../../src/services/wallet/wallet'; -import { dateToTimestamp } from '../../src/utils/dateTime.utils'; -import * as wallet from '../../src/utils/wallet.utils'; -import { createMember, createSpace, mockWalletReturnValue, wait } from '../../test/controls/common'; -import { MEDIA, getWallet, testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { MEDIA, getWallet, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { awaitAllTransactionsForAward, saveBaseToken } from './common'; const network = Network.RMS; -let walletSpy: any; describe('Create award, base', () => { let guardian: string; @@ -41,35 +30,34 @@ describe('Create award, base', () => { let token: Token; beforeAll(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); walletService = await getWallet(network); }); beforeEach(async () => { - guardian = await createMember(walletSpy); - member = await createMember(walletSpy); - space = await createSpace(walletSpy, guardian); + guardian = await testEnv.createMember(); + member = await testEnv.createMember(); + space = await testEnv.createSpace(guardian); - mockWalletReturnValue(walletSpy, member, { uid: space?.uid }); - await testEnv.wrap(joinSpace)({}); + mockWalletReturnValue(member, { uid: space?.uid }); + await testEnv.wrap(WEN_FUNC.joinSpace); token = await saveBaseToken(space.uid, guardian, network); - mockWalletReturnValue(walletSpy, guardian, awardRequest(space.uid, token.symbol)); - award = await testEnv.wrap(createAward)({}); + mockWalletReturnValue(guardian, awardRequest(space.uid, token.symbol)); + award = await testEnv.wrap(WEN_FUNC.createAward); }); it.each([false, true])( 'Should create, fund and participate in award, cancel', async (shouldCancel: boolean) => { - mockWalletReturnValue(walletSpy, guardian, { uid: award.uid }); - const order = await testEnv.wrap(fundAward)({}); + mockWalletReturnValue(guardian, { uid: award.uid }); + const order = await testEnv.wrap(WEN_FUNC.fundAward); const address = await walletService.getNewIotaAddressDetails(); await requestFundsFromFaucet(network, address.bech32, order.payload.amount); - await walletService.send(address, order.payload.targetAddress, order.payload.amount, {}); + await walletService.send(address, order.payload.targetAddress!, order.payload.amount!, {}); - const awardDocRef = build5Db().doc(`${COL.AWARD}/${award.uid}`); + const awardDocRef = build5Db().doc(COL.AWARD, award.uid); await wait(async () => { const award = await awardDocRef.get(); return award.approved && award.funded; @@ -80,23 +68,23 @@ describe('Create award, base', () => { expect(awardData.collectionBlockId).toBeDefined(); expect(awardData.collectionId).toBeDefined(); - mockWalletReturnValue(walletSpy, member, { uid: award.uid }); - await testEnv.wrap(awardParticipate)({}); + mockWalletReturnValue(member, { uid: award.uid }); + await testEnv.wrap(WEN_FUNC.participateAward); - mockWalletReturnValue(walletSpy, guardian, { award: award.uid, members: [member] }); - await testEnv.wrap(approveAwardParticipant)({}); + mockWalletReturnValue(guardian, { award: award.uid, members: [member] }); + await testEnv.wrap(WEN_FUNC.approveParticipantAward); if (shouldCancel) { - mockWalletReturnValue(walletSpy, guardian, { uid: award.uid }); - await testEnv.wrap(cancelAward)({}); + mockWalletReturnValue(guardian, { uid: award.uid }); + await testEnv.wrap(WEN_FUNC.cancelAward); } else { - await awardDocRef.update({ endDate: dateToTimestamp(dayjs().subtract(1, 'minute')) }); + await awardDocRef.update({ endDate: dayjs().subtract(1, 'minute').toDate() }); await processExpiredAwards(); await processExpiredAwards(); } - mockWalletReturnValue(walletSpy, member, { symbol: token.symbol }); - const claimOrder = await testEnv.wrap(claimMintedTokenOrder)({}); + mockWalletReturnValue(member, { symbol: token.symbol }); + const claimOrder = await testEnv.wrap(WEN_FUNC.claimMintedTokenOrder); await requestFundsFromFaucet( network, claimOrder.payload.targetAddress, @@ -115,7 +103,7 @@ describe('Create award, base', () => { const nttQuery = build5Db() .collection(COL.TRANSACTION) .where('member', '==', member) - .where('payload.type', '==', TransactionPayloadType.BADGE); + .where('payload_type', '==', TransactionPayloadType.BADGE); await wait(async () => { const snap = await nttQuery.get(); return snap.length === 1; @@ -139,10 +127,10 @@ describe('Create award, base', () => { const burnAliasQuery = build5Db() .collection(COL.TRANSACTION) - .where('payload.type', '==', TransactionPayloadType.BURN_ALIAS) + .where('payload_type', '==', TransactionPayloadType.BURN_ALIAS) .where('member', '==', guardian); await wait(async () => { - const snap = await burnAliasQuery.get(); + const snap = await burnAliasQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); diff --git a/packages/functions/test-tangle/award/award_5.spec.ts b/packages/functions/test-tangle/award/award_5.spec.ts index fb0c0a35f5..440c650891 100644 --- a/packages/functions/test-tangle/award/award_5.spec.ts +++ b/packages/functions/test-tangle/award/award_5.spec.ts @@ -7,45 +7,29 @@ import { SOON_PROJECT_ID, Space, Token, - TokenDrop, TokenDropStatus, TokenStatus, Transaction, TransactionPayloadType, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; import { processExpiredAwards } from '../../src/cron/award.cron'; -import { - approveAwardParticipant, - awardParticipate, - cancelAward, - createAward, - fundAward, -} from '../../src/runtime/firebase/award'; -import { joinSpace } from '../../src/runtime/firebase/space'; -import { claimMintedTokenOrder } from '../../src/runtime/firebase/token/minting'; 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 { mergeOutputs } from '../../src/utils/basic-output.utils'; -import { dateToTimestamp, serverTime } from '../../src/utils/dateTime.utils'; +import { serverTime } from '../../src/utils/dateTime.utils'; import * as wallet from '../../src/utils/wallet.utils'; -import { - createMember, - createSpace, - getRandomSymbol, - mockWalletReturnValue, - wait, -} from '../../test/controls/common'; -import { MEDIA, getWallet, testEnv } from '../../test/set-up'; +import { getRandomSymbol, wait } from '../../test/controls/common'; +import { MEDIA, getWallet, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken } from '../common'; import { requestFundsFromFaucet, requestMintedTokenFromFaucet } from '../faucet'; import { awaitAllTransactionsForAward } from './common'; const network = Network.RMS; -let walletSpy: any; describe('Create award, native', () => { let guardian: string; @@ -57,32 +41,31 @@ describe('Create award, native', () => { let token: Token; beforeAll(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); walletService = await getWallet(network); }); beforeEach(async () => { - guardian = await createMember(walletSpy); - member = await createMember(walletSpy); - space = await createSpace(walletSpy, guardian); + guardian = await testEnv.createMember(); + member = await testEnv.createMember(); + space = await testEnv.createSpace(guardian); - mockWalletReturnValue(walletSpy, member, { uid: space?.uid }); - await testEnv.wrap(joinSpace)({}); + mockWalletReturnValue(member, { uid: space?.uid }); + await testEnv.wrap(WEN_FUNC.joinSpace); token = await saveToken(space.uid, guardian); - mockWalletReturnValue(walletSpy, member, awardRequest(space.uid, token.symbol)); - award = await testEnv.wrap(createAward)({}); + mockWalletReturnValue(member, awardRequest(space.uid, token.symbol)); + award = await testEnv.wrap(WEN_FUNC.createAward); - const guardianDocRef = build5Db().doc(`${COL.MEMBER}/${guardian}`); + const guardianDocRef = build5Db().doc(COL.MEMBER, guardian); const guardianData = await guardianDocRef.get(); const guardianBech32 = getAddress(guardianData, network); guardianAddress = await walletService.getAddressDetails(guardianBech32); }); it.each([false, true])('Should create and fund award, cancel', async (shouldCancel: boolean) => { - mockWalletReturnValue(walletSpy, guardian, { uid: award.uid }); - const order = await testEnv.wrap(fundAward)({}); + mockWalletReturnValue(guardian, { uid: award.uid }); + const order = await testEnv.wrap(WEN_FUNC.fundAward); await requestFundsFromFaucet(network, guardianAddress.bech32, order.payload.amount); await requestMintedTokenFromFaucet( @@ -92,12 +75,12 @@ describe('Create award, native', () => { VAULT_MNEMONIC, 15, ); - await walletService.send(guardianAddress, order.payload.targetAddress, order.payload.amount, { + await walletService.send(guardianAddress, order.payload.targetAddress!, order.payload.amount!, { nativeTokens: [{ id: MINTED_TOKEN_ID, amount: BigInt(15) }], }); await MnemonicService.store(guardianAddress.bech32, guardianAddress.mnemonic); - const awardDocRef = build5Db().doc(`${COL.AWARD}/${award.uid}`); + const awardDocRef = build5Db().doc(COL.AWARD, award.uid); await wait(async () => { const award = await awardDocRef.get(); return award.approved && award.funded; @@ -108,17 +91,17 @@ describe('Create award, native', () => { expect(awardData.collectionBlockId).toBeDefined(); expect(awardData.collectionId).toBeDefined(); - mockWalletReturnValue(walletSpy, member, { uid: award.uid }); - await testEnv.wrap(awardParticipate)({}); + mockWalletReturnValue(member, { uid: award.uid }); + await testEnv.wrap(WEN_FUNC.participateAward); - mockWalletReturnValue(walletSpy, guardian, { award: award.uid, members: [member] }); - await testEnv.wrap(approveAwardParticipant)({}); + mockWalletReturnValue(guardian, { award: award.uid, members: [member] }); + await testEnv.wrap(WEN_FUNC.approveParticipantAward); if (shouldCancel) { - mockWalletReturnValue(walletSpy, guardian, { uid: award.uid }); - await testEnv.wrap(cancelAward)({}); + mockWalletReturnValue(guardian, { uid: award.uid }); + await testEnv.wrap(WEN_FUNC.cancelAward); } else { - await awardDocRef.update({ endDate: dateToTimestamp(dayjs().subtract(1, 'minute')) }); + await awardDocRef.update({ endDate: dayjs().subtract(1, 'minute').toDate() }); await processExpiredAwards(); await processExpiredAwards(); } @@ -126,7 +109,7 @@ describe('Create award, native', () => { const nttQuery = build5Db() .collection(COL.TRANSACTION) .where('member', '==', member) - .where('payload.type', '==', TransactionPayloadType.BADGE); + .where('payload_type', '==', TransactionPayloadType.BADGE); await wait(async () => { const snap = await nttQuery.get(); return snap.length === 1; @@ -134,7 +117,7 @@ describe('Create award, native', () => { await awaitAllTransactionsForAward(award.uid); - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${member}`); + const memberDocRef = build5Db().doc(COL.MEMBER, member); const memberData = await memberDocRef.get(); const memberBech32 = getAddress(memberData, network); await wait(async () => { @@ -143,18 +126,18 @@ describe('Create award, native', () => { }); const airdropQuery = build5Db().collection(COL.AIRDROP).where('member', '==', member); - let airdropSnap = await airdropQuery.get(); + let airdropSnap = await airdropQuery.get(); expect(airdropSnap.length).toBe(1); - mockWalletReturnValue(walletSpy, member, { symbol: token.symbol }); - const claimOrder = await testEnv.wrap(claimMintedTokenOrder)({}); + mockWalletReturnValue(member, { symbol: token.symbol }); + const claimOrder = await testEnv.wrap(WEN_FUNC.claimMintedTokenOrder); await requestFundsFromFaucet( network, claimOrder.payload.targetAddress, claimOrder.payload.amount, ); await wait(async () => { - airdropSnap = await airdropQuery.get(); + airdropSnap = await airdropQuery.get(); const allClaimed = airdropSnap.reduce( (acc, doc) => acc && doc.status === TokenDropStatus.CLAIMED, true, @@ -173,7 +156,7 @@ describe('Create award, native', () => { .where('type', '==', TransactionType.CREDIT) .where('member', '==', guardian); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); const credit = (await creditQuery.get())[0]; @@ -183,10 +166,10 @@ describe('Create award, native', () => { const burnAliasQuery = build5Db() .collection(COL.TRANSACTION) - .where('payload.type', '==', TransactionPayloadType.BURN_ALIAS) + .where('payload_type', '==', TransactionPayloadType.BURN_ALIAS) .where('member', '==', guardian); await wait(async () => { - const snap = await burnAliasQuery.get(); + const snap = await burnAliasQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); const { amount } = await walletService.getBalance(guardianAddress.bech32); @@ -229,9 +212,10 @@ const saveToken = async (space: string, guardian: string) => { network: Network.RMS, tokenId: MINTED_TOKEN_ID, }, - }; - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).set(token); - return token as Token; + links: [] as URL[], + } as Token; + await build5Db().doc(COL.TOKEN, token.uid).create(token); + return token; }; export const VAULT_MNEMONIC = diff --git a/packages/functions/test-tangle/award/award_6.spec.ts b/packages/functions/test-tangle/award/award_6.spec.ts index 914b494a90..e20e797953 100644 --- a/packages/functions/test-tangle/award/award_6.spec.ts +++ b/packages/functions/test-tangle/award/award_6.spec.ts @@ -6,25 +6,20 @@ import { Network, Space, Token, - TokenDrop, TokenDropStatus, Transaction, TransactionPayloadType, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { validateAddress } from '../../src/runtime/firebase/address'; -import { approveAwardParticipant, createAward, fundAward } from '../../src/runtime/firebase/award'; -import { claimMintedTokenOrder } from '../../src/runtime/firebase/token/minting'; import { Wallet } from '../../src/services/wallet/wallet'; -import * as wallet from '../../src/utils/wallet.utils'; -import { createMember, createSpace, mockWalletReturnValue, wait } from '../../test/controls/common'; -import { MEDIA, getWallet, testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { MEDIA, getWallet, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { saveBaseToken } from './common'; const network = Network.RMS; -let walletSpy: any; describe('Award', () => { let guardian: string; @@ -34,41 +29,41 @@ describe('Award', () => { let walletService: Wallet; beforeAll(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); walletService = await getWallet(network); }); beforeEach(async () => { - guardian = await createMember(walletSpy); - space = await createSpace(walletSpy, guardian); + guardian = await testEnv.createMember(); + space = await testEnv.createSpace(guardian); token = await saveBaseToken(space.uid, guardian, network); - mockWalletReturnValue(walletSpy, guardian, awardRequest(space.uid, token.symbol)); - award = await testEnv.wrap(createAward)({}); + mockWalletReturnValue(guardian, awardRequest(space.uid, token.symbol)); + award = await testEnv.wrap(WEN_FUNC.createAward); }); it('Should issue many awards', async () => { - mockWalletReturnValue(walletSpy, guardian, { uid: award.uid }); - const order = await testEnv.wrap(fundAward)({}); + mockWalletReturnValue(guardian, { uid: award.uid }); + const order = await testEnv.wrap(WEN_FUNC.fundAward); await requestFundsFromFaucet(network, order.payload.targetAddress, order.payload.amount); - const awardDocRef = build5Db().doc(`${COL.AWARD}/${award.uid}`); + const awardDocRef = build5Db().doc(COL.AWARD, award.uid); await wait(async () => { const award = await awardDocRef.get(); return award.approved && award.funded; }); - const tmp = wallet.getRandomEthAddress(); - mockWalletReturnValue(walletSpy, guardian, { + const tmp = await testEnv.createMember(); + await build5Db().doc(COL.MEMBER, tmp).update({ rmsAddress: '' }); + mockWalletReturnValue(guardian, { award: award.uid, members: [tmp, tmp], }); - await testEnv.wrap(approveAwardParticipant)({}); + await testEnv.wrap(WEN_FUNC.approveParticipantAward); const tmpAddress = await walletService.getNewIotaAddressDetails(); - mockWalletReturnValue(walletSpy, tmp, { network: Network.RMS }); - const addressValidationOrder = await testEnv.wrap(validateAddress)({}); + mockWalletReturnValue(tmp, { network: Network.RMS }); + const addressValidationOrder = await testEnv.wrap(WEN_FUNC.validateAddress); await requestFundsFromFaucet( Network.RMS, tmpAddress.bech32, @@ -76,8 +71,8 @@ describe('Award', () => { ); await walletService.send( tmpAddress, - addressValidationOrder.payload.targetAddress, - addressValidationOrder.payload.amount, + addressValidationOrder.payload.targetAddress!, + addressValidationOrder.payload.amount!, {}, ); @@ -87,19 +82,18 @@ describe('Award', () => { }); const airdropQuery = build5Db().collection(COL.AIRDROP).where('member', '==', tmp); - let airdropSnap = await airdropQuery.get(); + let airdropSnap = await airdropQuery.get(); expect(airdropSnap.length).toBe(2); - mockWalletReturnValue(walletSpy, tmp, { symbol: token.symbol }); - const claimOrder = await testEnv.wrap(claimMintedTokenOrder)({}); + mockWalletReturnValue(tmp, { symbol: token.symbol }); + const claimOrder = await testEnv.wrap(WEN_FUNC.claimMintedTokenOrder); await requestFundsFromFaucet( network, claimOrder.payload.targetAddress, claimOrder.payload.amount, ); - await wait(async () => { - airdropSnap = await airdropQuery.get(); + airdropSnap = await airdropQuery.get(); const allClaimed = airdropSnap.reduce( (acc, doc) => acc && doc.status === TokenDropStatus.CLAIMED, true, @@ -111,7 +105,7 @@ describe('Award', () => { const { amount } = await walletService.getBalance(tmpAddress.bech32); return ( amount === - 2 * MIN_IOTA_AMOUNT + claimOrder.payload.amount + addressValidationOrder.payload.amount + 2 * MIN_IOTA_AMOUNT + claimOrder.payload.amount! + addressValidationOrder.payload.amount! ); }); diff --git a/packages/functions/test-tangle/award/award_7.spec.ts b/packages/functions/test-tangle/award/award_7.spec.ts index 90ff42f819..497b2ec139 100644 --- a/packages/functions/test-tangle/award/award_7.spec.ts +++ b/packages/functions/test-tangle/award/award_7.spec.ts @@ -10,29 +10,22 @@ import { TokenStatus, Transaction, TransactionPayloadType, + WEN_FUNC, } from '@build-5/interfaces'; import { NftOutput } from '@iota/sdk'; import dayjs from 'dayjs'; -import { approveAwardParticipant, createAward, fundAward } from '../../src/runtime/firebase/award'; 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 { serverTime } from '../../src/utils/dateTime.utils'; import * as wallet from '../../src/utils/wallet.utils'; -import { - createMember, - createSpace, - getRandomSymbol, - mockWalletReturnValue, - wait, -} from '../../test/controls/common'; -import { MEDIA, getWallet, testEnv } from '../../test/set-up'; +import { getRandomSymbol, wait } from '../../test/controls/common'; +import { MEDIA, getWallet, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { getNftMetadata } from '../collection-minting/Helper'; import { requestFundsFromFaucet, requestMintedTokenFromFaucet } from '../faucet'; const network = Network.RMS; -let walletSpy: any; describe('Create award, base', () => { let guardian: string; @@ -44,29 +37,28 @@ describe('Create award, base', () => { let guardianAddress: AddressDetails; beforeAll(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); walletService = await getWallet(network); }); beforeEach(async () => { - guardian = await createMember(walletSpy); - member = await createMember(walletSpy); - space = await createSpace(walletSpy, guardian); + guardian = await testEnv.createMember(); + member = await testEnv.createMember(); + space = await testEnv.createSpace(guardian); token = await saveToken(space.uid, guardian); - mockWalletReturnValue(walletSpy, guardian, awardRequest(space.uid, token.symbol)); - award = await testEnv.wrap(createAward)({}); + mockWalletReturnValue(guardian, awardRequest(space.uid, token.symbol)); + award = await testEnv.wrap(WEN_FUNC.createAward); - const guardianDocRef = build5Db().doc(`${COL.MEMBER}/${guardian}`); + const guardianDocRef = build5Db().doc(COL.MEMBER, guardian); const guardianData = await guardianDocRef.get(); const guardianBech32 = getAddress(guardianData, network); guardianAddress = await walletService.getAddressDetails(guardianBech32); }); it('Should set correct metadata on award collection and ntt', async () => { - mockWalletReturnValue(walletSpy, guardian, { uid: award.uid }); - const order = await testEnv.wrap(fundAward)({}); + mockWalletReturnValue(guardian, { uid: award.uid }); + const order = await testEnv.wrap(WEN_FUNC.fundAward); await requestFundsFromFaucet(network, guardianAddress.bech32, order.payload.amount); await requestMintedTokenFromFaucet( @@ -76,28 +68,28 @@ describe('Create award, base', () => { VAULT_MNEMONIC, 10, ); - await walletService.send(guardianAddress, order.payload.targetAddress, order.payload.amount, { + await walletService.send(guardianAddress, order.payload.targetAddress!, order.payload.amount!, { nativeTokens: [{ id: MINTED_TOKEN_ID, amount: BigInt('0xA') }], }); await MnemonicService.store(guardianAddress.bech32, guardianAddress.mnemonic); - const awardDocRef = build5Db().doc(`${COL.AWARD}/${award.uid}`); + const awardDocRef = build5Db().doc(COL.AWARD, award.uid); await wait(async () => { award = await awardDocRef.get(); return award.approved && award.funded; }); - mockWalletReturnValue(walletSpy, guardian, { award: award.uid, members: [member, member] }); - await testEnv.wrap(approveAwardParticipant)({}); + mockWalletReturnValue(guardian, { award: award.uid, members: [member, member] }); + await testEnv.wrap(WEN_FUNC.approveParticipantAward); - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${member}`); + const memberDocRef = build5Db().doc(COL.MEMBER, member); const memberData = await memberDocRef.get(); const memberBech32 = getAddress(memberData, network); const nttQuery = build5Db() .collection(COL.TRANSACTION) .where('member', '==', member) - .where('payload.type', '==', TransactionPayloadType.BADGE); + .where('payload_type', '==', TransactionPayloadType.BADGE); await wait(async () => { const snap = await nttQuery.get(); return snap.length === 2; @@ -108,7 +100,7 @@ describe('Create award, base', () => { return response.items.length === 2; }); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${space.uid}`); + const spaceDocRef = build5Db().doc(COL.SPACE, space.uid); space = await spaceDocRef.get(); expect(space.ipfsMedia).toBeDefined(); @@ -145,7 +137,7 @@ describe('Create award, base', () => { expect(nttMetadata.collectionId).toBe(award.collectionId); expect(nttMetadata.collectionName).toBe('award'); - const transactionDocRef = build5Db().doc(`${COL.TRANSACTION}/${nttMetadata.build5Id}`); + const transactionDocRef = build5Db().doc(COL.TRANSACTION, nttMetadata.build5Id); const transaction = await transactionDocRef.get(); expect(getAttributeValue(nttMetadata, 'award')).toBe(award.uid); expect(getAttributeValue(nttMetadata, 'tokenReward')).toBe(5); @@ -198,9 +190,9 @@ const saveToken = async (space: string, guardian: string) => { network: Network.RMS, tokenId: MINTED_TOKEN_ID, }, - }; - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).set(token); - return token as Token; + } as Token; + await build5Db().doc(COL.TOKEN, token.uid).create(token); + return token; }; export const VAULT_MNEMONIC = diff --git a/packages/functions/test-tangle/award/award_8.spec.ts b/packages/functions/test-tangle/award/award_8.spec.ts index de44841ac5..ad23dc8f0d 100644 --- a/packages/functions/test-tangle/award/award_8.spec.ts +++ b/packages/functions/test-tangle/award/award_8.spec.ts @@ -1,24 +1,24 @@ import { build5Db } from '@build-5/database'; import { Award, + AwardApproveParticipantResponse, COL, Member, MIN_IOTA_AMOUNT, Network, Space, Token, + Transaction, TransactionPayloadType, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { approveAwardParticipant, createAward, fundAward } from '../../src/runtime/firebase/award'; -import * as wallet from '../../src/utils/wallet.utils'; -import { createMember, createSpace, mockWalletReturnValue, wait } from '../../test/controls/common'; -import { MEDIA, testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { MEDIA, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { saveBaseToken } from './common'; const network = Network.RMS; -let walletSpy: any; describe('Create award, base', () => { let guardian: string; @@ -27,34 +27,32 @@ describe('Create award, base', () => { let awards: Award[] = []; let tokens: Token[] = []; - beforeAll(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - }); + beforeAll(async () => {}); beforeEach(async () => { - guardian = await createMember(walletSpy); - member = await createMember(walletSpy); - spaces = [await createSpace(walletSpy, guardian), await createSpace(walletSpy, guardian)]; + guardian = await testEnv.createMember(); + member = await testEnv.createMember(); + spaces = [await testEnv.createSpace(guardian), await testEnv.createSpace(guardian)]; tokens = [ await saveBaseToken(spaces[1].uid, guardian), await saveBaseToken(spaces[1].uid, guardian), ]; - mockWalletReturnValue(walletSpy, guardian, awardRequest(spaces[0].uid, tokens[0].symbol)); - awards[0] = await testEnv.wrap(createAward)({}); - mockWalletReturnValue(walletSpy, guardian, awardRequest(spaces[0].uid, tokens[1].symbol)); - awards[1] = await testEnv.wrap(createAward)({}); - mockWalletReturnValue(walletSpy, guardian, awardRequest(spaces[1].uid, tokens[0].symbol)); - awards[2] = await testEnv.wrap(createAward)({}); + mockWalletReturnValue(guardian, awardRequest(spaces[0].uid, tokens[0].symbol)); + awards[0] = await testEnv.wrap(WEN_FUNC.createAward); + mockWalletReturnValue(guardian, awardRequest(spaces[0].uid, tokens[1].symbol)); + awards[1] = await testEnv.wrap(WEN_FUNC.createAward); + mockWalletReturnValue(guardian, awardRequest(spaces[1].uid, tokens[0].symbol)); + awards[2] = await testEnv.wrap(WEN_FUNC.createAward); }); const fundAwardWrapper = async (awardId: string) => { - mockWalletReturnValue(walletSpy, guardian, { uid: awardId }); - const order = await testEnv.wrap(fundAward)({}); + mockWalletReturnValue(guardian, { uid: awardId }); + const order = await testEnv.wrap(WEN_FUNC.fundAward); await requestFundsFromFaucet(network, order.payload.targetAddress, order.payload.amount); - const awardDocRef = build5Db().doc(`${COL.AWARD}/${awardId}`); + const awardDocRef = build5Db().doc(COL.AWARD, awardId); await wait(async () => { const award = await awardDocRef.get(); return award.approved && award.funded; @@ -62,55 +60,30 @@ describe('Create award, base', () => { }; it('Should update member space properly', async () => { - let promises = awards.map((award) => fundAwardWrapper(award.uid)); + const promises = awards.map((award) => fundAwardWrapper(award.uid)); await Promise.all(promises); - promises = awards.map((award) => { - mockWalletReturnValue(walletSpy, guardian, { award: award.uid, members: [member, member] }); - return testEnv.wrap(approveAwardParticipant)({}); + const approvePromises = awards.map((award) => { + mockWalletReturnValue(guardian, { award: award.uid, members: [member, member] }); + return testEnv.wrap(WEN_FUNC.approveParticipantAward); }); - await Promise.all(promises); + await Promise.all(approvePromises); const nttQuery = build5Db() .collection(COL.TRANSACTION) .where('member', '==', member) - .where('payload.type', '==', TransactionPayloadType.BADGE); + .where('payload_type', '==', TransactionPayloadType.BADGE); await wait(async () => { const snap = await nttQuery.get(); return snap.length === 6; }); - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${member}`); + const memberDocRef = build5Db().doc(COL.MEMBER, member); const memberData = await memberDocRef.get(); - assertMemberSpaceAwardStats( - memberData, - spaces[0].uid, - tokens[0], - 4, - 4 * MIN_IOTA_AMOUNT, - 2, - 2 * MIN_IOTA_AMOUNT, - ); - assertMemberSpaceAwardStats( - memberData, - spaces[0].uid, - tokens[1], - 4, - 4 * MIN_IOTA_AMOUNT, - 2, - 2 * MIN_IOTA_AMOUNT, - ); - - assertMemberSpaceAwardStats( - memberData, - spaces[1].uid, - tokens[0], - 2, - 2 * MIN_IOTA_AMOUNT, - 2, - 2 * MIN_IOTA_AMOUNT, - ); + assertMemberSpaceAwardStats(memberData, spaces[0].uid, tokens[0], 4, 2); + assertMemberSpaceAwardStats(memberData, spaces[0].uid, tokens[1], 4, 2); + assertMemberSpaceAwardStats(memberData, spaces[1].uid, tokens[0], 2, 2); }); }); @@ -119,16 +92,12 @@ const assertMemberSpaceAwardStats = ( spaceId: string, token: Token, totalCompleted: number, - totalReward: number, completed: number, - reward: number, ) => { const space = member.spaces![spaceId]; expect(space.awardsCompleted).toBe(totalCompleted); - expect(space.totalReward).toBe(totalReward); const stat = space.awardStat![token.uid]; expect(stat.completed).toBe(completed); - expect(stat.totalReward).toBe(reward); expect(stat.tokenSymbol).toBe(token.symbol); }; diff --git a/packages/functions/test-tangle/award/award_9.spec.ts b/packages/functions/test-tangle/award/award_9.spec.ts index 75a1bfcb75..74daa036bc 100644 --- a/packages/functions/test-tangle/award/award_9.spec.ts +++ b/packages/functions/test-tangle/award/award_9.spec.ts @@ -5,34 +5,27 @@ import { Member, Network, SOON_PROJECT_ID, - Space, SUB_COL, + Space, Token, TokenDistribution, TokenStatus, + Transaction, TransactionPayloadType, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { approveAwardParticipant, createAward, fundAward } from '../../src/runtime/firebase/award'; -import { joinSpace } from '../../src/runtime/firebase/space'; 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 { serverTime } from '../../src/utils/dateTime.utils'; import * as wallet from '../../src/utils/wallet.utils'; -import { - createMember, - createSpace, - getRandomSymbol, - mockWalletReturnValue, - wait, -} from '../../test/controls/common'; -import { getWallet, MEDIA, testEnv } from '../../test/set-up'; +import { getRandomSymbol, wait } from '../../test/controls/common'; +import { MEDIA, getWallet, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; const network = Network.RMS; -let walletSpy: any; describe('Create award, native', () => { let guardian: string; @@ -44,43 +37,42 @@ describe('Create award, native', () => { let token: Token; beforeAll(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); walletService = await getWallet(network); }); beforeEach(async () => { - guardian = await createMember(walletSpy); - member = await createMember(walletSpy); - space = await createSpace(walletSpy, guardian); + guardian = await testEnv.createMember(); + member = await testEnv.createMember(); + space = await testEnv.createSpace(guardian); - mockWalletReturnValue(walletSpy, member, { uid: space?.uid }); - await testEnv.wrap(joinSpace)({}); + mockWalletReturnValue(member, { uid: space?.uid }); + await testEnv.wrap(WEN_FUNC.joinSpace); token = await saveToken(space.uid, guardian); - mockWalletReturnValue(walletSpy, member, awardRequest(space.uid, token.symbol)); - award = await testEnv.wrap(createAward)({}); + mockWalletReturnValue(member, awardRequest(space.uid, token.symbol)); + award = await testEnv.wrap(WEN_FUNC.createAward); - const guardianDocRef = build5Db().doc(`${COL.MEMBER}/${guardian}`); + const guardianDocRef = build5Db().doc(COL.MEMBER, guardian); const guardianData = await guardianDocRef.get(); const guardianBech32 = getAddress(guardianData, network); guardianAddress = await walletService.getAddressDetails(guardianBech32); }); it('Should create and fund native award, no reward', async () => { - mockWalletReturnValue(walletSpy, guardian, { uid: award.uid }); - const order = await testEnv.wrap(fundAward)({}); + mockWalletReturnValue(guardian, { uid: award.uid }); + const order = await testEnv.wrap(WEN_FUNC.fundAward); await requestFundsFromFaucet(network, guardianAddress.bech32, order.payload.amount); await walletService.send( guardianAddress, - order.payload.targetAddress, - order.payload.amount, + order.payload.targetAddress!, + order.payload.amount!, {}, ); await MnemonicService.store(guardianAddress.bech32, guardianAddress.mnemonic); - const awardDocRef = build5Db().doc(`${COL.AWARD}/${award.uid}`); + const awardDocRef = build5Db().doc(COL.AWARD, award.uid); await wait(async () => { const award = await awardDocRef.get(); return award.approved && award.funded; @@ -92,18 +84,17 @@ describe('Create award, native', () => { expect(awardData.collectionId).toBeDefined(); expect(awardData.nativeTokenStorageDeposit).toBe(0); - mockWalletReturnValue(walletSpy, guardian, { award: award.uid, members: [member, member] }); - await testEnv.wrap(approveAwardParticipant)({}); + mockWalletReturnValue(guardian, { award: award.uid, members: [member, member] }); + await testEnv.wrap(WEN_FUNC.approveParticipantAward); - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${token.uid}`); - const distributionDocRef = tokenDocRef.collection(SUB_COL.DISTRIBUTION).doc(member); + const distributionDocRef = build5Db().doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, member); let distribution = await distributionDocRef.get(); expect(distribution?.totalUnclaimedAirdrop || 0).toBe(0); const nttQuery = build5Db() .collection(COL.TRANSACTION) .where('member', '==', member) - .where('payload.type', '==', TransactionPayloadType.BADGE); + .where('payload_type', '==', TransactionPayloadType.BADGE); await wait(async () => { const snap = await nttQuery.get(); return snap.length === 2; @@ -146,9 +137,9 @@ const saveToken = async (space: string, guardian: string) => { network: Network.RMS, tokenId: MINTED_TOKEN_ID, }, - }; - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).set(token); - return token as Token; + } as Token; + await build5Db().doc(COL.TOKEN, token.uid).create(token); + return token; }; const MINTED_TOKEN_ID = diff --git a/packages/functions/test-tangle/award/common.ts b/packages/functions/test-tangle/award/common.ts index e096e85683..a509ffa43f 100644 --- a/packages/functions/test-tangle/award/common.ts +++ b/packages/functions/test-tangle/award/common.ts @@ -16,20 +16,20 @@ import { MEDIA } from '../../test/set-up'; export const awaitAllTransactionsForAward = async (awardId: string) => { const baseTransQuery = build5Db() .collection(COL.TRANSACTION) - .where('payload.award', '==', awardId) - .where('type', 'in', [TransactionType.BILL_PAYMENT, TransactionType.CREDIT]); + .where('payload_award', '==', awardId) + .whereIn('type', [TransactionType.BILL_PAYMENT, TransactionType.CREDIT]); await allConfirmed(baseTransQuery); const nttQuery = build5Db() .collection(COL.TRANSACTION) - .where('payload.award', '==', awardId) - .where('payload.type', '==', TransactionPayloadType.BADGE); + .where('payload_award', '==', awardId) + .where('payload_type', '==', TransactionPayloadType.BADGE); await allConfirmed(nttQuery); }; -const allConfirmed = (query: IQuery) => +const allConfirmed = (query: IQuery) => wait(async () => { - const snap = await query.get>(); + const snap = await query.get(); const allConfirmed = snap.reduce( (acc, doc) => acc && doc?.payload?.walletReference?.confirmed, true, @@ -54,7 +54,7 @@ export const saveBaseToken = async (space: string, guardian: string, network = N mintingData: { network, }, - }; - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).set(token); - return token as Token; + } as Token; + await build5Db().doc(COL.TOKEN, token.uid).create(token); + return token; }; diff --git a/packages/functions/test-tangle/base-token-trading/Helper.ts b/packages/functions/test-tangle/base-token-trading/Helper.ts index 4ec2133514..9d209536c2 100644 --- a/packages/functions/test-tangle/base-token-trading/Helper.ts +++ b/packages/functions/test-tangle/base-token-trading/Helper.ts @@ -1,21 +1,13 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { build5Db } from '@build-5/database'; import { COL, Member, Network, SOON_PROJECT_ID, Token, TokenStatus } from '@build-5/interfaces'; -import { createMember } from '../../src/runtime/firebase/member'; import { IotaWallet } from '../../src/services/wallet/IotaWalletService'; import { Wallet } from '../../src/services/wallet/wallet'; import { AddressDetails } from '../../src/services/wallet/wallet.service'; import { serverTime } from '../../src/utils/dateTime.utils'; import * as wallet from '../../src/utils/wallet.utils'; -import { - createMember as createMemberTest, - createRoyaltySpaces, - createSpace, - getRandomSymbol, - mockWalletReturnValue, -} from '../../test/controls/common'; +import { createRoyaltySpaces, getRandomSymbol } from '../../test/controls/common'; import { MEDIA, getWallet, testEnv } from '../../test/set-up'; -import { addValidatedAddress } from '../common'; export class Helper { public sourceNetwork = Network.ATOI; @@ -25,33 +17,38 @@ export class Helper { public buyer: Member | undefined; public buyerValidateAddress = {} as { [key: string]: AddressDetails }; public token: Token | undefined; - public walletSpy: any | undefined; public rmsWallet: Wallet | undefined; public atoiWallet: IotaWallet | undefined; public beforeEach = async () => { await createRoyaltySpaces(); - this.walletSpy = jest.spyOn(wallet, 'decodeAuth'); - const guardian = await createMemberTest(this.walletSpy); - const space = await createSpace(this.walletSpy, guardian); + const guardian = await testEnv.createMember(); + const space = await testEnv.createSpace(guardian); - const sellerId = wallet.getRandomEthAddress(); - mockWalletReturnValue(this.walletSpy, sellerId, {}); - await testEnv.wrap(createMember)({ address: sellerId }); - this.sellerValidateAddress[Network.ATOI] = await addValidatedAddress(Network.ATOI, sellerId); - this.sellerValidateAddress[Network.RMS] = await addValidatedAddress(Network.RMS, sellerId); - this.seller = await build5Db().doc(`${COL.MEMBER}/${sellerId}`).get(); - - const buyerId = wallet.getRandomEthAddress(); - mockWalletReturnValue(this.walletSpy, buyerId, {}); - await testEnv.wrap(createMember)({ address: buyerId }); - this.buyerValidateAddress[Network.ATOI] = await addValidatedAddress(Network.ATOI, buyerId); - this.buyerValidateAddress[Network.RMS] = await addValidatedAddress(Network.RMS, buyerId); - this.buyer = await build5Db().doc(`${COL.MEMBER}/${buyerId}`).get(); - this.token = await this.saveToken(space.uid, guardian); + const sellerId = await testEnv.createMember(); + this.seller = await build5Db().doc(COL.MEMBER, sellerId).get(); this.atoiWallet = (await getWallet(Network.ATOI)) as IotaWallet; this.rmsWallet = await getWallet(Network.RMS); + + this.sellerValidateAddress[Network.ATOI] = await this.atoiWallet.getAddressDetails( + this.seller.validatedAddress![Network.ATOI], + ); + this.sellerValidateAddress[Network.RMS] = await this.rmsWallet.getAddressDetails( + this.seller.validatedAddress![Network.RMS], + ); + + const buyerId = await testEnv.createMember(); + this.buyer = await build5Db().doc(COL.MEMBER, buyerId).get(); + + this.buyerValidateAddress[Network.ATOI] = await this.atoiWallet.getAddressDetails( + this.buyer.validatedAddress![Network.ATOI], + ); + this.buyerValidateAddress[Network.RMS] = await this.rmsWallet.getAddressDetails( + this.buyer.validatedAddress![Network.RMS], + ); + + this.token = await this.saveToken(space.uid, guardian); }; public saveToken = async (space: string, guardian: string) => { @@ -71,8 +68,9 @@ export class Helper { mintingData: { network: Network.ATOI, }, - }; - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).set(token); - return token as Token; + links: [] as URL[], + } as Token; + await build5Db().doc(COL.TOKEN, token.uid).create(token); + return token; }; } diff --git a/packages/functions/test-tangle/base-token-trading/base-token-trading_1.spec.ts b/packages/functions/test-tangle/base-token-trading/base-token-trading_1.spec.ts index 3ce663be91..d4fd9dc51f 100644 --- a/packages/functions/test-tangle/base-token-trading/base-token-trading_1.spec.ts +++ b/packages/functions/test-tangle/base-token-trading/base-token-trading_1.spec.ts @@ -11,14 +11,14 @@ import { Transaction, TransactionPayloadType, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; import { isEmpty } from 'lodash'; -import { tradeToken } from '../../src/runtime/firebase/token/trading'; import { getAddress } from '../../src/utils/address.utils'; import { dateToTimestamp } from '../../src/utils/dateTime.utils'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { getWallet, testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { getWallet, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken } from '../common'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -31,26 +31,26 @@ describe('Base token trading', () => { }); it('Should fulfill sell order', async () => { - mockWalletReturnValue(helper.walletSpy, helper.seller!.uid, { + mockWalletReturnValue(helper.seller!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 2, type: TokenTradeOrderType.SELL, }); - const sellOrder = await testEnv.wrap(tradeToken)({}); + const sellOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.sourceNetwork, sellOrder.payload.targetAddress, MIN_IOTA_AMOUNT, ); - mockWalletReturnValue(helper.walletSpy, helper.buyer!.uid, { + mockWalletReturnValue(helper.buyer!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 2, type: TokenTradeOrderType.BUY, }); - const buyOrder = await testEnv.wrap(tradeToken)({}); + const buyOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.targetNetwork, buyOrder.payload.targetAddress, @@ -94,7 +94,7 @@ describe('Base token trading', () => { expect(purchase.targetNetwork).toBe(helper.targetNetwork); expect(purchase.tokenStatus).toBe(TokenStatus.BASE); expect(purchase.sellerTier).toBe(0); - expect(purchase.sellerTokenTradingFeePercentage).toBeNull(); + expect(purchase.sellerTokenTradingFeePercentage).toBeUndefined(); const sellerBillPaymentsSnap = await build5Db() .collection(COL.TRANSACTION) @@ -194,13 +194,13 @@ describe('Base token trading', () => { const date = dayjs().add(2, 'h').millisecond(0).toDate(); const expiresAt = dateToTimestamp(date); - mockWalletReturnValue(helper.walletSpy, helper.buyer!.uid, { + mockWalletReturnValue(helper.buyer!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 2, type: TokenTradeOrderType.BUY, }); - const buyOrder = await testEnv.wrap(tradeToken)({}); + const buyOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.targetNetwork, buyOrder.payload.targetAddress, @@ -221,13 +221,13 @@ describe('Base token trading', () => { }); it('Should not credit buy order with expiration unlock, custom amount', async () => { - mockWalletReturnValue(helper.walletSpy, helper.seller!.uid, { + mockWalletReturnValue(helper.seller!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 2, type: TokenTradeOrderType.SELL, }); - const sellOrder = await testEnv.wrap(tradeToken)({}); + const sellOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.sourceNetwork, sellOrder.payload.targetAddress, @@ -237,13 +237,13 @@ describe('Base token trading', () => { const date = dayjs().add(2, 'h').millisecond(0).toDate(); const expiresAt = dateToTimestamp(date) as Timestamp; - mockWalletReturnValue(helper.walletSpy, helper.buyer!.uid, { + mockWalletReturnValue(helper.buyer!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 2, type: TokenTradeOrderType.BUY, }); - const buyOrder = await testEnv.wrap(tradeToken)({}); + const buyOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.targetNetwork, buyOrder.payload.targetAddress, @@ -256,10 +256,10 @@ describe('Base token trading', () => { .where('type', '==', TokenTradeOrderType.BUY) .where('owner', '==', helper.buyer?.uid); await wait(async () => { - const snap = await buyQuery.get(); + const snap = await buyQuery.get(); return snap.length === 1 && snap[0].status === TokenTradeOrderStatus.SETTLED; }); - const buy = (await buyQuery.get())[0]; + const buy = (await buyQuery.get())[0]; expect(buy.balance).toBe(2 * MIN_IOTA_AMOUNT); expect(buy.count).toBe(MIN_IOTA_AMOUNT); expect(buy.fulfilled).toBe(MIN_IOTA_AMOUNT); @@ -267,8 +267,8 @@ describe('Base token trading', () => { const credit = await build5Db() .collection(COL.TRANSACTION) .where('member', '==', helper.buyer?.uid) - .where('payload.type', '==', TransactionPayloadType.TOKEN_TRADE_FULLFILLMENT) - .get(); + .where('payload_type', '==', TransactionPayloadType.TOKEN_TRADE_FULLFILLMENT) + .get(); expect(credit.length).toBe(1); expect(credit[0].payload.amount).toBe(2 * MIN_IOTA_AMOUNT); }); diff --git a/packages/functions/test-tangle/base-token-trading/base-token-trading_10.spec.ts b/packages/functions/test-tangle/base-token-trading/base-token-trading_10.spec.ts index 2de1c202cd..9299f55c52 100644 --- a/packages/functions/test-tangle/base-token-trading/base-token-trading_10.spec.ts +++ b/packages/functions/test-tangle/base-token-trading/base-token-trading_10.spec.ts @@ -6,10 +6,10 @@ import { TokenTradeOrderType, Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; -import { tradeToken } from '../../src/runtime/firebase/token/trading'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken } from '../common'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -22,26 +22,26 @@ describe('Base token trading', () => { }); it('Should not fill buy, dust and order not fulfilled', async () => { - mockWalletReturnValue(helper.walletSpy, helper.seller!.uid, { + mockWalletReturnValue(helper.seller!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 2, type: TokenTradeOrderType.SELL, }); - const sellOrder = await testEnv.wrap(tradeToken)({}); + const sellOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.sourceNetwork, sellOrder.payload.targetAddress, MIN_IOTA_AMOUNT, ); - mockWalletReturnValue(helper.walletSpy, helper.buyer!.uid, { + mockWalletReturnValue(helper.buyer!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT + 1, price: 2, type: TokenTradeOrderType.BUY, }); - const buyOrder = await testEnv.wrap(tradeToken)({}); + const buyOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.targetNetwork, buyOrder.payload.targetAddress, @@ -71,13 +71,13 @@ describe('Base token trading', () => { const tradesQuery = build5Db() .collection(COL.TOKEN_MARKET) .where('token', '==', helper.token!.uid); - mockWalletReturnValue(helper.walletSpy, helper.seller!.uid, { + mockWalletReturnValue(helper.seller!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 2, type: TokenTradeOrderType.SELL, }); - const sellOrder = await testEnv.wrap(tradeToken)({}); + const sellOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.sourceNetwork, sellOrder.payload.targetAddress, @@ -89,13 +89,13 @@ describe('Base token trading', () => { return snap.length === 1; }); - mockWalletReturnValue(helper.walletSpy, helper.buyer!.uid, { + mockWalletReturnValue(helper.buyer!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 2.001, type: TokenTradeOrderType.BUY, }); - const buyOrder = await testEnv.wrap(tradeToken)({}); + const buyOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.targetNetwork, buyOrder.payload.targetAddress, @@ -117,7 +117,7 @@ describe('Base token trading', () => { await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.BILL_PAYMENT) - .where('payload.token', '==', helper.token!.uid) + .where('payload_token', '==', helper.token!.uid) .get() ).map((d) => d); diff --git a/packages/functions/test-tangle/base-token-trading/base-token-trading_11_a.spec.ts b/packages/functions/test-tangle/base-token-trading/base-token-trading_11_a.spec.ts index faf80a3058..1c06856f41 100644 --- a/packages/functions/test-tangle/base-token-trading/base-token-trading_11_a.spec.ts +++ b/packages/functions/test-tangle/base-token-trading/base-token-trading_11_a.spec.ts @@ -7,10 +7,10 @@ import { TokenTradeOrderType, Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; -import { tradeToken } from '../../src/runtime/firebase/token/trading'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken } from '../common'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -23,17 +23,15 @@ describe('Base token trading', () => { }); it('Should not create royalty payments, zero percentage fee', async () => { - await build5Db() - .doc(`${COL.SYSTEM}/${SYSTEM_CONFIG_DOC_ID}`) - .set({ tokenTradingFeePercentage: 0 }); + await build5Db().doc(COL.SYSTEM, SYSTEM_CONFIG_DOC_ID).upsert({ tokenTradingFeePercentage: 0 }); - mockWalletReturnValue(helper.walletSpy, helper.seller!.uid, { + mockWalletReturnValue(helper.seller!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 2, type: TokenTradeOrderType.SELL, }); - const sellOrder = await testEnv.wrap(tradeToken)({}); + const sellOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.sourceNetwork, sellOrder.payload.targetAddress, @@ -48,13 +46,13 @@ describe('Base token trading', () => { return snap.length === 1; }); - mockWalletReturnValue(helper.walletSpy, helper.buyer!.uid, { + mockWalletReturnValue(helper.buyer!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 2, type: TokenTradeOrderType.BUY, }); - const buyOrder = await testEnv.wrap(tradeToken)({}); + const buyOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.targetNetwork, buyOrder.payload.targetAddress, @@ -76,7 +74,7 @@ describe('Base token trading', () => { await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.BILL_PAYMENT) - .where('payload.token', '==', helper.token!.uid) + .where('payload_token', '==', helper.token!.uid) .get() ).map((d) => d); expect(billPayments.length).toBe(2); diff --git a/packages/functions/test-tangle/base-token-trading/base-token-trading_11_b.spec.ts b/packages/functions/test-tangle/base-token-trading/base-token-trading_11_b.spec.ts index 325a70dc24..7926eac9b2 100644 --- a/packages/functions/test-tangle/base-token-trading/base-token-trading_11_b.spec.ts +++ b/packages/functions/test-tangle/base-token-trading/base-token-trading_11_b.spec.ts @@ -2,16 +2,15 @@ import { build5Db } from '@build-5/database'; import { COL, MIN_IOTA_AMOUNT, - StakeType, SUB_COL, TokenPurchase, TokenTradeOrderType, Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; -import { tradeToken } from '../../src/runtime/firebase/token/trading'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { soonTokenId, testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, soonTokenId, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken } from '../common'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -24,32 +23,18 @@ describe('Base token trading', () => { }); it('Should not create royalty payments, zero percentage fee', async () => { + await build5Db().doc(COL.MEMBER, helper.seller!.uid).update({ tokenTradingFeePercentage: 0 }); await build5Db() - .doc(`${COL.MEMBER}/${helper.seller!.uid}`) - .update({ tokenTradingFeePercentage: 0 }); - await build5Db() - .collection(COL.TOKEN) - .doc(soonTokenId) - .collection(SUB_COL.DISTRIBUTION) - .doc(helper.seller?.uid!) - .set( - { - stakes: { - [StakeType.DYNAMIC]: { - value: 15000 * MIN_IOTA_AMOUNT, - }, - }, - }, - true, - ); + .doc(COL.TOKEN, soonTokenId, SUB_COL.DISTRIBUTION, helper.seller?.uid!) + .upsert({ stakes_dynamic_value: 15000 * MIN_IOTA_AMOUNT }); - mockWalletReturnValue(helper.walletSpy, helper.seller!.uid, { + mockWalletReturnValue(helper.seller!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 2, type: TokenTradeOrderType.SELL, }); - const sellOrder = await testEnv.wrap(tradeToken)({}); + const sellOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.sourceNetwork, sellOrder.payload.targetAddress, @@ -64,13 +49,13 @@ describe('Base token trading', () => { return snap.length === 1; }); - mockWalletReturnValue(helper.walletSpy, helper.buyer!.uid, { + mockWalletReturnValue(helper.buyer!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 2, type: TokenTradeOrderType.BUY, }); - const buyOrder = await testEnv.wrap(tradeToken)({}); + const buyOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.targetNetwork, buyOrder.payload.targetAddress, @@ -94,7 +79,7 @@ describe('Base token trading', () => { await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.BILL_PAYMENT) - .where('payload.token', '==', helper.token!.uid) + .where('payload_token', '==', helper.token!.uid) .get() ).map((d) => d); expect(billPayments.length).toBe(2); @@ -113,16 +98,14 @@ describe('Base token trading', () => { }); it('Should create royalty payments only with dust', async () => { - await build5Db() - .doc(`${COL.MEMBER}/${helper.seller!.uid}`) - .update({ tokenTradingFeePercentage: 0 }); - mockWalletReturnValue(helper.walletSpy, helper.seller!.uid, { + await build5Db().doc(COL.MEMBER, helper.seller!.uid).update({ tokenTradingFeePercentage: 0 }); + mockWalletReturnValue(helper.seller!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 2, type: TokenTradeOrderType.SELL, }); - const sellOrder = await testEnv.wrap(tradeToken)({}); + const sellOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.sourceNetwork, sellOrder.payload.targetAddress, @@ -137,13 +120,13 @@ describe('Base token trading', () => { return snap.length === 1; }); - mockWalletReturnValue(helper.walletSpy, helper.buyer!.uid, { + mockWalletReturnValue(helper.buyer!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 2.001, type: TokenTradeOrderType.BUY, }); - const buyOrder = await testEnv.wrap(tradeToken)({}); + const buyOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.targetNetwork, buyOrder.payload.targetAddress, @@ -165,7 +148,7 @@ describe('Base token trading', () => { await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.BILL_PAYMENT) - .where('payload.token', '==', helper.token!.uid) + .where('payload_token', '==', helper.token!.uid) .get() ).map((d) => d); expect(billPayments.length).toBe(3); @@ -184,16 +167,14 @@ describe('Base token trading', () => { }); it('Should create royalty payments for different percentage', async () => { - await build5Db() - .doc(`${COL.MEMBER}/${helper.seller!.uid}`) - .update({ tokenTradingFeePercentage: 1 }); - mockWalletReturnValue(helper.walletSpy, helper.seller!.uid, { + await build5Db().doc(COL.MEMBER, helper.seller!.uid).update({ tokenTradingFeePercentage: 1 }); + mockWalletReturnValue(helper.seller!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 2, type: TokenTradeOrderType.SELL, }); - const sellOrder = await testEnv.wrap(tradeToken)({}); + const sellOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.sourceNetwork, sellOrder.payload.targetAddress, @@ -208,13 +189,13 @@ describe('Base token trading', () => { return snap.length === 1; }); - mockWalletReturnValue(helper.walletSpy, helper.buyer!.uid, { + mockWalletReturnValue(helper.buyer!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 2, type: TokenTradeOrderType.BUY, }); - const buyOrder = await testEnv.wrap(tradeToken)({}); + const buyOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.targetNetwork, buyOrder.payload.targetAddress, @@ -236,7 +217,7 @@ describe('Base token trading', () => { await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.BILL_PAYMENT) - .where('payload.token', '==', helper.token!.uid) + .where('payload_token', '==', helper.token!.uid) .get() ).map((d) => d); expect(billPayments.length).toBe(4); diff --git a/packages/functions/test-tangle/base-token-trading/base-token-trading_11_c.spec.ts b/packages/functions/test-tangle/base-token-trading/base-token-trading_11_c.spec.ts index 90e89bb18d..beb4ec3af7 100644 --- a/packages/functions/test-tangle/base-token-trading/base-token-trading_11_c.spec.ts +++ b/packages/functions/test-tangle/base-token-trading/base-token-trading_11_c.spec.ts @@ -6,10 +6,10 @@ import { TokenTradeOrderType, Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; -import { tradeToken } from '../../src/runtime/firebase/token/trading'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken } from '../common'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -22,16 +22,14 @@ describe('Base token trading', () => { }); it('Should create royalty payments only with dust', async () => { - await build5Db() - .doc(`${COL.MEMBER}/${helper.seller!.uid}`) - .update({ tokenTradingFeePercentage: 0 }); - mockWalletReturnValue(helper.walletSpy, helper.seller!.uid, { + await build5Db().doc(COL.MEMBER, helper.seller!.uid).update({ tokenTradingFeePercentage: 0 }); + mockWalletReturnValue(helper.seller!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 2, type: TokenTradeOrderType.SELL, }); - const sellOrder = await testEnv.wrap(tradeToken)({}); + const sellOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.sourceNetwork, sellOrder.payload.targetAddress, @@ -46,13 +44,13 @@ describe('Base token trading', () => { return snap.length === 1; }); - mockWalletReturnValue(helper.walletSpy, helper.buyer!.uid, { + mockWalletReturnValue(helper.buyer!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 2.001, type: TokenTradeOrderType.BUY, }); - const buyOrder = await testEnv.wrap(tradeToken)({}); + const buyOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.targetNetwork, buyOrder.payload.targetAddress, @@ -74,7 +72,7 @@ describe('Base token trading', () => { await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.BILL_PAYMENT) - .where('payload.token', '==', helper.token!.uid) + .where('payload_token', '==', helper.token!.uid) .get() ).map((d) => d); expect(billPayments.length).toBe(3); diff --git a/packages/functions/test-tangle/base-token-trading/base-token-trading_11_d.spec.ts b/packages/functions/test-tangle/base-token-trading/base-token-trading_11_d.spec.ts index 49f74db50d..76be1403cf 100644 --- a/packages/functions/test-tangle/base-token-trading/base-token-trading_11_d.spec.ts +++ b/packages/functions/test-tangle/base-token-trading/base-token-trading_11_d.spec.ts @@ -6,10 +6,10 @@ import { TokenTradeOrderType, Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; -import { tradeToken } from '../../src/runtime/firebase/token/trading'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken } from '../common'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -22,16 +22,14 @@ describe('Base token trading', () => { }); it('Should create royalty payments for different percentage', async () => { - await build5Db() - .doc(`${COL.MEMBER}/${helper.seller!.uid}`) - .update({ tokenTradingFeePercentage: 1 }); - mockWalletReturnValue(helper.walletSpy, helper.seller!.uid, { + await build5Db().doc(COL.MEMBER, helper.seller!.uid).update({ tokenTradingFeePercentage: 1 }); + mockWalletReturnValue(helper.seller!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 2, type: TokenTradeOrderType.SELL, }); - const sellOrder = await testEnv.wrap(tradeToken)({}); + const sellOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.sourceNetwork, sellOrder.payload.targetAddress, @@ -46,13 +44,13 @@ describe('Base token trading', () => { return snap.length === 1; }); - mockWalletReturnValue(helper.walletSpy, helper.buyer!.uid, { + mockWalletReturnValue(helper.buyer!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 2, type: TokenTradeOrderType.BUY, }); - const buyOrder = await testEnv.wrap(tradeToken)({}); + const buyOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.targetNetwork, buyOrder.payload.targetAddress, @@ -74,7 +72,7 @@ describe('Base token trading', () => { await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.BILL_PAYMENT) - .where('payload.token', '==', helper.token!.uid) + .where('payload_token', '==', helper.token!.uid) .get() ).map((d) => d); expect(billPayments.length).toBe(4); diff --git a/packages/functions/test-tangle/base-token-trading/base-token-trading_12.spec.ts b/packages/functions/test-tangle/base-token-trading/base-token-trading_12.spec.ts index 1c1238bef0..1be0ca764d 100644 --- a/packages/functions/test-tangle/base-token-trading/base-token-trading_12.spec.ts +++ b/packages/functions/test-tangle/base-token-trading/base-token-trading_12.spec.ts @@ -48,7 +48,7 @@ describe('Base token trading', () => { const snap = await query.get(); return snap.length > 0; }); - const orderSnap = await query.get(); + const orderSnap = await query.get(); const sellOrder = orderSnap[0]; expect(sellOrder.owner).toBe(helper.seller!.uid); expect(sellOrder.price).toBe(1.5); diff --git a/packages/functions/test-tangle/base-token-trading/base-token-trading_13.spec.ts b/packages/functions/test-tangle/base-token-trading/base-token-trading_13.spec.ts index 150cb480f0..7c4dd3264b 100644 --- a/packages/functions/test-tangle/base-token-trading/base-token-trading_13.spec.ts +++ b/packages/functions/test-tangle/base-token-trading/base-token-trading_13.spec.ts @@ -1,12 +1,5 @@ import { build5Db } from '@build-5/database'; -import { - COL, - MIN_IOTA_AMOUNT, - Network, - TangleRequestType, - TokenTradeOrder, - Transaction, -} from '@build-5/interfaces'; +import { COL, MIN_IOTA_AMOUNT, Network, TangleRequestType, Transaction } from '@build-5/interfaces'; import { wait } from '../../test/controls/common'; import { awaitTransactionConfirmationsForToken, getTangleOrder } from '../common'; import { requestFundsFromFaucet } from '../faucet'; @@ -64,21 +57,25 @@ describe('Base token trading', () => { }, }); - let query = build5Db().collection(COL.TOKEN_MARKET).where('owner', '==', helper.seller!.uid); + const queryBySeller = build5Db() + .collection(COL.TOKEN_MARKET) + .where('owner', '==', helper.seller!.uid); await wait(async () => { - const snap = await query.get(); + const snap = await queryBySeller.get(); return snap.length > 0; }); - const sell = (await query.get())[0]!; + const sell = (await queryBySeller.get())[0]!; - query = build5Db().collection(COL.TOKEN_MARKET).where('owner', '==', helper.buyer!.uid); + const queryByBuyer = build5Db() + .collection(COL.TOKEN_MARKET) + .where('owner', '==', helper.buyer!.uid); await wait(async () => { - const snap = await query.get(); + const snap = await queryByBuyer.get(); return snap.length > 0; }); - const buy = (await query.get())[0]!; + const buy = (await queryByBuyer.get())[0]!; - query = build5Db() + const query = build5Db() .collection(COL.TOKEN_PURCHASE) .where('sell', '==', sell.uid) .where('buy', '==', buy.uid); diff --git a/packages/functions/test-tangle/base-token-trading/base-token-trading_14.spec.ts b/packages/functions/test-tangle/base-token-trading/base-token-trading_14.spec.ts index 88bf95b2e6..2c6baa6600 100644 --- a/packages/functions/test-tangle/base-token-trading/base-token-trading_14.spec.ts +++ b/packages/functions/test-tangle/base-token-trading/base-token-trading_14.spec.ts @@ -5,14 +5,13 @@ import { MIN_IOTA_AMOUNT, Network, TangleRequestType, - TokenTradeOrder, TokenTradeOrderStatus, TokenTradeOrderType, Transaction, + WEN_FUNC, } from '@build-5/interfaces'; -import { tradeToken } from '../../src/runtime/firebase/token/trading'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { getTangleOrder } from '../common'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -26,26 +25,26 @@ describe('Base token trading', () => { }); it('Should create market buy with tangle request, settle it, no balance', async () => { - mockWalletReturnValue(helper.walletSpy, helper.seller!.uid, { + mockWalletReturnValue(helper.seller!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 2, type: TokenTradeOrderType.SELL, }); - let sellOrder = await testEnv.wrap(tradeToken)({}); + let sellOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.sourceNetwork, sellOrder.payload.targetAddress, MIN_IOTA_AMOUNT, ); - mockWalletReturnValue(helper.walletSpy, helper.seller!.uid, { + mockWalletReturnValue(helper.seller!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 4, type: TokenTradeOrderType.SELL, }); - sellOrder = await testEnv.wrap(tradeToken)({}); + sellOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.sourceNetwork, sellOrder.payload.targetAddress, @@ -72,10 +71,10 @@ describe('Base token trading', () => { const query = build5Db().collection(COL.TOKEN_MARKET).where('owner', '==', helper.buyer!.uid); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1 && snap[0].status === TokenTradeOrderStatus.SETTLED; }); - const buyOrder = (await query.get())[0]; + const buyOrder = (await query.get())[0]; expect(buyOrder.count).toBe(MAX_TOTAL_TOKEN_SUPPLY); expect(buyOrder.fulfilled).toBe(1.5 * MIN_IOTA_AMOUNT); @@ -85,7 +84,7 @@ describe('Base token trading', () => { .collection(COL.TOKEN_MARKET) .where('owner', '==', helper.seller?.uid) .where('type', '==', TokenTradeOrderType.SELL) - .get(); + .get(); sellOrders.sort((a, b) => a.price - b.price); expect(sellOrders[0].price).toBe(2); diff --git a/packages/functions/test-tangle/base-token-trading/base-token-trading_15.spec.ts b/packages/functions/test-tangle/base-token-trading/base-token-trading_15.spec.ts index 6620f12d3c..69a3b6fdb5 100644 --- a/packages/functions/test-tangle/base-token-trading/base-token-trading_15.spec.ts +++ b/packages/functions/test-tangle/base-token-trading/base-token-trading_15.spec.ts @@ -5,13 +5,12 @@ import { MIN_IOTA_AMOUNT, Network, TangleRequestType, - TokenTradeOrder, TokenTradeOrderType, Transaction, + WEN_FUNC, } from '@build-5/interfaces'; -import { tradeToken } from '../../src/runtime/firebase/token/trading'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { getTangleOrder } from '../common'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -25,26 +24,26 @@ describe('Base token trading', () => { }); it('Should create market buy with tangle request,do not settle it', async () => { - mockWalletReturnValue(helper.walletSpy, helper.seller!.uid, { + mockWalletReturnValue(helper.seller!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 2, type: TokenTradeOrderType.SELL, }); - let sellOrder = await testEnv.wrap(tradeToken)({}); + let sellOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.sourceNetwork, sellOrder.payload.targetAddress, MIN_IOTA_AMOUNT, ); - mockWalletReturnValue(helper.walletSpy, helper.seller!.uid, { + mockWalletReturnValue(helper.seller!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 4, type: TokenTradeOrderType.SELL, }); - sellOrder = await testEnv.wrap(tradeToken)({}); + sellOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.sourceNetwork, sellOrder.payload.targetAddress, @@ -71,10 +70,10 @@ describe('Base token trading', () => { const query = build5Db().collection(COL.TOKEN_MARKET).where('owner', '==', helper.buyer!.uid); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1 && snap[0].fulfilled === 2 * MIN_IOTA_AMOUNT; }); - const buyOrder = (await query.get())[0]; + const buyOrder = (await query.get())[0]; expect(buyOrder.count).toBe(MAX_TOTAL_TOKEN_SUPPLY); expect(buyOrder.fulfilled).toBe(2 * MIN_IOTA_AMOUNT); @@ -84,7 +83,7 @@ describe('Base token trading', () => { .collection(COL.TOKEN_MARKET) .where('owner', '==', helper.seller?.uid) .where('type', '==', TokenTradeOrderType.SELL) - .get(); + .get(); sellOrders.sort((a, b) => a.price - b.price); expect(sellOrders[0].price).toBe(2); diff --git a/packages/functions/test-tangle/base-token-trading/base-token-trading_16.spec.ts b/packages/functions/test-tangle/base-token-trading/base-token-trading_16.spec.ts index 8a98260181..4320440a3f 100644 --- a/packages/functions/test-tangle/base-token-trading/base-token-trading_16.spec.ts +++ b/packages/functions/test-tangle/base-token-trading/base-token-trading_16.spec.ts @@ -5,14 +5,13 @@ import { MIN_PRICE_PER_TOKEN, Network, TangleRequestType, - TokenTradeOrder, TokenTradeOrderStatus, TokenTradeOrderType, Transaction, + WEN_FUNC, } from '@build-5/interfaces'; -import { tradeToken } from '../../src/runtime/firebase/token/trading'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { getTangleOrder } from '../common'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -26,26 +25,26 @@ describe('Base token trading', () => { }); it('Should create market sell with tangle request, settle it', async () => { - mockWalletReturnValue(helper.walletSpy, helper.buyer!.uid, { + mockWalletReturnValue(helper.buyer!.uid, { symbol: helper.token!.symbol, count: 2 * MIN_IOTA_AMOUNT, price: 1, type: TokenTradeOrderType.BUY, }); - let buyOrder = await testEnv.wrap(tradeToken)({}); + let buyOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.sourceNetwork, buyOrder.payload.targetAddress, buyOrder.payload.amount, ); - mockWalletReturnValue(helper.walletSpy, helper.buyer!.uid, { + mockWalletReturnValue(helper.buyer!.uid, { symbol: helper.token!.symbol, count: 4 * MIN_IOTA_AMOUNT, price: 2, type: TokenTradeOrderType.BUY, }); - buyOrder = await testEnv.wrap(tradeToken)({}); + buyOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.sourceNetwork, buyOrder.payload.targetAddress, @@ -72,10 +71,10 @@ describe('Base token trading', () => { const query = build5Db().collection(COL.TOKEN_MARKET).where('owner', '==', helper.seller!.uid); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1 && snap[0].status === TokenTradeOrderStatus.SETTLED; }); - const sellOrder = (await query.get())[0]; + const sellOrder = (await query.get())[0]; expect(sellOrder.count).toBe(5 * MIN_IOTA_AMOUNT); expect(sellOrder.fulfilled).toBe(5 * MIN_IOTA_AMOUNT); @@ -85,7 +84,7 @@ describe('Base token trading', () => { const buyOrders = await build5Db() .collection(COL.TOKEN_MARKET) .where('owner', '==', helper.buyer?.uid) - .get(); + .get(); buyOrders.sort((a, b) => b.price - a.price); expect(buyOrders[0].price).toBe(2); diff --git a/packages/functions/test-tangle/base-token-trading/base-token-trading_17.spec.ts b/packages/functions/test-tangle/base-token-trading/base-token-trading_17.spec.ts index 70404f2cf5..ff31694aed 100644 --- a/packages/functions/test-tangle/base-token-trading/base-token-trading_17.spec.ts +++ b/packages/functions/test-tangle/base-token-trading/base-token-trading_17.spec.ts @@ -4,13 +4,12 @@ import { MIN_IOTA_AMOUNT, Network, TangleRequestType, - TokenTradeOrder, TokenTradeOrderType, Transaction, + WEN_FUNC, } from '@build-5/interfaces'; -import { tradeToken } from '../../src/runtime/firebase/token/trading'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { getTangleOrder } from '../common'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -24,26 +23,26 @@ describe('Base token trading', () => { }); it('Should create market sell with tangle request, do not settle it', async () => { - mockWalletReturnValue(helper.walletSpy, helper.buyer!.uid, { + mockWalletReturnValue(helper.buyer!.uid, { symbol: helper.token!.symbol, count: 2 * MIN_IOTA_AMOUNT, price: 1, type: TokenTradeOrderType.BUY, }); - let buyOrder = await testEnv.wrap(tradeToken)({}); + let buyOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.sourceNetwork, buyOrder.payload.targetAddress, buyOrder.payload.amount, ); - mockWalletReturnValue(helper.walletSpy, helper.buyer!.uid, { + mockWalletReturnValue(helper.buyer!.uid, { symbol: helper.token!.symbol, count: 4 * MIN_IOTA_AMOUNT, price: 2, type: TokenTradeOrderType.BUY, }); - buyOrder = await testEnv.wrap(tradeToken)({}); + buyOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.sourceNetwork, buyOrder.payload.targetAddress, @@ -70,10 +69,10 @@ describe('Base token trading', () => { const query = build5Db().collection(COL.TOKEN_MARKET).where('owner', '==', helper.seller!.uid); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1 && snap[0].fulfilled === 6 * MIN_IOTA_AMOUNT; }); - const sellOrder = (await query.get())[0]; + const sellOrder = (await query.get())[0]; expect(sellOrder.count).toBe(7 * MIN_IOTA_AMOUNT); expect(sellOrder.fulfilled).toBe(6 * MIN_IOTA_AMOUNT); @@ -82,7 +81,7 @@ describe('Base token trading', () => { const buyOrders = await build5Db() .collection(COL.TOKEN_MARKET) .where('owner', '==', helper.buyer?.uid) - .get(); + .get(); buyOrders.sort((a, b) => b.price - a.price); expect(buyOrders[0].price).toBe(2); diff --git a/packages/functions/test-tangle/base-token-trading/base-token-trading_18.spec.ts b/packages/functions/test-tangle/base-token-trading/base-token-trading_18.spec.ts index 2bbe3a1ff6..0b56336eda 100644 --- a/packages/functions/test-tangle/base-token-trading/base-token-trading_18.spec.ts +++ b/packages/functions/test-tangle/base-token-trading/base-token-trading_18.spec.ts @@ -1,11 +1,5 @@ import { build5Db } from '@build-5/database'; -import { - COL, - MIN_IOTA_AMOUNT, - Network, - TangleRequestType, - TokenTradeOrder, -} from '@build-5/interfaces'; +import { COL, MIN_IOTA_AMOUNT, Network, TangleRequestType } from '@build-5/interfaces'; import { wait } from '../../test/controls/common'; import { getTangleOrder } from '../common'; import { requestFundsFromFaucet } from '../faucet'; @@ -34,7 +28,7 @@ describe('Base token trading', () => { const snap = await query.get(); return snap.length === 1; }); - const order = (await query.get())[0]; + const order = (await query.get())[0]; expect(order.sourceNetwork).toBe(Network.RMS); expect(order.targetNetwork).toBe(Network.ATOI); }); diff --git a/packages/functions/test-tangle/base-token-trading/base-token-trading_19.spec.ts b/packages/functions/test-tangle/base-token-trading/base-token-trading_19.spec.ts index d672b37e96..c4d4a60f88 100644 --- a/packages/functions/test-tangle/base-token-trading/base-token-trading_19.spec.ts +++ b/packages/functions/test-tangle/base-token-trading/base-token-trading_19.spec.ts @@ -1,11 +1,5 @@ import { build5Db } from '@build-5/database'; -import { - COL, - MIN_IOTA_AMOUNT, - Network, - TangleRequestType, - TokenTradeOrder, -} from '@build-5/interfaces'; +import { COL, MIN_IOTA_AMOUNT, Network, TangleRequestType } from '@build-5/interfaces'; import { wait } from '../../test/controls/common'; import { getTangleOrder } from '../common'; import { requestFundsFromFaucet } from '../faucet'; @@ -36,7 +30,7 @@ describe('Base token trading', () => { const snap = await query.get(); return snap.length === 1; }); - const order = (await query.get())[0]; + const order = (await query.get())[0]; expect(order.sourceNetwork).toBe(Network.ATOI); expect(order.targetNetwork).toBe(Network.RMS); }); diff --git a/packages/functions/test-tangle/base-token-trading/base-token-trading_2.spec.ts b/packages/functions/test-tangle/base-token-trading/base-token-trading_2.spec.ts index 386db4cd0f..f7eb0e504c 100644 --- a/packages/functions/test-tangle/base-token-trading/base-token-trading_2.spec.ts +++ b/packages/functions/test-tangle/base-token-trading/base-token-trading_2.spec.ts @@ -7,12 +7,12 @@ import { TokenTradeOrderType, Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; import { isEmpty } from 'lodash'; -import { tradeToken } from '../../src/runtime/firebase/token/trading'; import { getAddress } from '../../src/utils/address.utils'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { getWallet, testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { getWallet, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken } from '../common'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -25,13 +25,13 @@ describe('Base token trading', () => { }); it('Should fulfil trade with half price', async () => { - mockWalletReturnValue(helper.walletSpy, helper.seller!.uid, { + mockWalletReturnValue(helper.seller!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 1, type: TokenTradeOrderType.SELL, }); - const sellOrder = await testEnv.wrap(tradeToken)({}); + const sellOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.sourceNetwork, sellOrder.payload.targetAddress, @@ -46,13 +46,13 @@ describe('Base token trading', () => { return snap.length !== 0; }); - mockWalletReturnValue(helper.walletSpy, helper.buyer!.uid, { + mockWalletReturnValue(helper.buyer!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 2, type: TokenTradeOrderType.BUY, }); - const buyOrder = await testEnv.wrap(tradeToken)({}); + const buyOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.targetNetwork, buyOrder.payload.targetAddress, @@ -156,7 +156,7 @@ describe('Base token trading', () => { .collection(COL.TRANSACTION) .where('member', '==', helper.buyer!.uid) .where('type', '==', TransactionType.CREDIT) - .get(); + .get(); expect(buyerCreditnap.length).toBe(1); expect(buyerCreditnap[0]?.payload.amount).toBe(MIN_IOTA_AMOUNT); buy = (await buyQuery.get())[0]; diff --git a/packages/functions/test-tangle/base-token-trading/base-token-trading_3.spec.ts b/packages/functions/test-tangle/base-token-trading/base-token-trading_3.spec.ts index 3f7d2f7ef1..d771645267 100644 --- a/packages/functions/test-tangle/base-token-trading/base-token-trading_3.spec.ts +++ b/packages/functions/test-tangle/base-token-trading/base-token-trading_3.spec.ts @@ -6,10 +6,10 @@ import { TokenTradeOrderType, Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; -import { tradeToken } from '../../src/runtime/firebase/token/trading'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken } from '../common'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -22,39 +22,39 @@ describe('Base token trading', () => { }); it('Should fulfill sell with two buys', async () => { - mockWalletReturnValue(helper.walletSpy, helper.seller!.uid, { + mockWalletReturnValue(helper.seller!.uid, { symbol: helper.token!.symbol, count: 2 * MIN_IOTA_AMOUNT, price: 1, type: TokenTradeOrderType.SELL, }); - const sellOrder = await testEnv.wrap(tradeToken)({}); + const sellOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.sourceNetwork, sellOrder.payload.targetAddress, 2 * MIN_IOTA_AMOUNT, ); - mockWalletReturnValue(helper.walletSpy, helper.buyer!.uid, { + mockWalletReturnValue(helper.buyer!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 1, type: TokenTradeOrderType.BUY, }); - const buyOrder = await testEnv.wrap(tradeToken)({}); + const buyOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.targetNetwork, buyOrder.payload.targetAddress, MIN_IOTA_AMOUNT, ); - mockWalletReturnValue(helper.walletSpy, helper.buyer!.uid, { + mockWalletReturnValue(helper.buyer!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 1, type: TokenTradeOrderType.BUY, }); - const buyOrder2 = await testEnv.wrap(tradeToken)({}); + const buyOrder2 = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.targetNetwork, buyOrder2.payload.targetAddress, diff --git a/packages/functions/test-tangle/base-token-trading/base-token-trading_4.spec.ts b/packages/functions/test-tangle/base-token-trading/base-token-trading_4.spec.ts index cda71e4e7f..1e6b475c85 100644 --- a/packages/functions/test-tangle/base-token-trading/base-token-trading_4.spec.ts +++ b/packages/functions/test-tangle/base-token-trading/base-token-trading_4.spec.ts @@ -6,10 +6,10 @@ import { TokenTradeOrderType, Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; -import { tradeToken } from '../../src/runtime/firebase/token/trading'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken } from '../common'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -22,39 +22,39 @@ describe('Base token trading', () => { }); it('Should fulfill buy with two sells', async () => { - mockWalletReturnValue(helper.walletSpy, helper.seller!.uid, { + mockWalletReturnValue(helper.seller!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 1, type: TokenTradeOrderType.SELL, }); - const sellOrder = await testEnv.wrap(tradeToken)({}); + const sellOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.sourceNetwork, sellOrder.payload.targetAddress, MIN_IOTA_AMOUNT, ); - mockWalletReturnValue(helper.walletSpy, helper.seller!.uid, { + mockWalletReturnValue(helper.seller!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 1, type: TokenTradeOrderType.SELL, }); - const sellOrder2 = await testEnv.wrap(tradeToken)({}); + const sellOrder2 = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.sourceNetwork, sellOrder2.payload.targetAddress, MIN_IOTA_AMOUNT, ); - mockWalletReturnValue(helper.walletSpy, helper.buyer!.uid, { + mockWalletReturnValue(helper.buyer!.uid, { symbol: helper.token!.symbol, count: 2 * MIN_IOTA_AMOUNT, price: 1, type: TokenTradeOrderType.BUY, }); - const buyOrder = await testEnv.wrap(tradeToken)({}); + const buyOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.targetNetwork, buyOrder.payload.targetAddress, diff --git a/packages/functions/test-tangle/base-token-trading/base-token-trading_5.spec.ts b/packages/functions/test-tangle/base-token-trading/base-token-trading_5.spec.ts index 9a7e87626b..5940d0573b 100644 --- a/packages/functions/test-tangle/base-token-trading/base-token-trading_5.spec.ts +++ b/packages/functions/test-tangle/base-token-trading/base-token-trading_5.spec.ts @@ -1,8 +1,14 @@ import { build5Db } from '@build-5/database'; -import { COL, MIN_IOTA_AMOUNT, TokenPurchase, TokenTradeOrderType } from '@build-5/interfaces'; -import { tradeToken } from '../../src/runtime/firebase/token/trading'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { + COL, + MIN_IOTA_AMOUNT, + TokenPurchase, + TokenTradeOrderType, + Transaction, + WEN_FUNC, +} from '@build-5/interfaces'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken } from '../common'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -15,26 +21,26 @@ describe('Base token trading', () => { }); it('Should fulfill buy with lowest sell', async () => { - mockWalletReturnValue(helper.walletSpy, helper.seller!.uid, { + mockWalletReturnValue(helper.seller!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 2, type: TokenTradeOrderType.SELL, }); - const sellOrder = await testEnv.wrap(tradeToken)({}); + const sellOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.sourceNetwork, sellOrder.payload.targetAddress, sellOrder.payload.amount, ); - mockWalletReturnValue(helper.walletSpy, helper.seller!.uid, { + mockWalletReturnValue(helper.seller!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 1, type: TokenTradeOrderType.SELL, }); - const sellOrder2 = await testEnv.wrap(tradeToken)({}); + const sellOrder2 = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.sourceNetwork, sellOrder2.payload.targetAddress, @@ -49,13 +55,13 @@ describe('Base token trading', () => { return snap.length === 2; }); - mockWalletReturnValue(helper.walletSpy, helper.buyer!.uid, { + mockWalletReturnValue(helper.buyer!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 2, type: TokenTradeOrderType.BUY, }); - const buyOrder = await testEnv.wrap(tradeToken)({}); + const buyOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.targetNetwork, buyOrder.payload.targetAddress, diff --git a/packages/functions/test-tangle/base-token-trading/base-token-trading_6.spec.ts b/packages/functions/test-tangle/base-token-trading/base-token-trading_6.spec.ts index 89f5d5904e..8430de9411 100644 --- a/packages/functions/test-tangle/base-token-trading/base-token-trading_6.spec.ts +++ b/packages/functions/test-tangle/base-token-trading/base-token-trading_6.spec.ts @@ -1,8 +1,14 @@ import { build5Db } from '@build-5/database'; -import { COL, MIN_IOTA_AMOUNT, TokenPurchase, TokenTradeOrderType } from '@build-5/interfaces'; -import { tradeToken } from '../../src/runtime/firebase/token/trading'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { + COL, + MIN_IOTA_AMOUNT, + TokenPurchase, + TokenTradeOrderType, + Transaction, + WEN_FUNC, +} from '@build-5/interfaces'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken } from '../common'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -15,26 +21,26 @@ describe('Base token trading', () => { }); it('Should fulfill sell with highest buy', async () => { - mockWalletReturnValue(helper.walletSpy, helper.buyer!.uid, { + mockWalletReturnValue(helper.buyer!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 1, type: TokenTradeOrderType.BUY, }); - const buyOrder = await testEnv.wrap(tradeToken)({}); + const buyOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.targetNetwork, buyOrder.payload.targetAddress, buyOrder.payload.amount, ); - mockWalletReturnValue(helper.walletSpy, helper.buyer!.uid, { + mockWalletReturnValue(helper.buyer!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 2, type: TokenTradeOrderType.BUY, }); - const buyOrder2 = await testEnv.wrap(tradeToken)({}); + const buyOrder2 = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.targetNetwork, buyOrder2.payload.targetAddress, @@ -49,13 +55,13 @@ describe('Base token trading', () => { return snap.length === 2; }); - mockWalletReturnValue(helper.walletSpy, helper.seller!.uid, { + mockWalletReturnValue(helper.seller!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 1, type: TokenTradeOrderType.SELL, }); - const sellOrder = await testEnv.wrap(tradeToken)({}); + const sellOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( helper.sourceNetwork, sellOrder.payload.targetAddress, diff --git a/packages/functions/test-tangle/base-token-trading/base-token-trading_7.spec.ts b/packages/functions/test-tangle/base-token-trading/base-token-trading_7.spec.ts index 0dc2d0c2fb..d4206c89a1 100644 --- a/packages/functions/test-tangle/base-token-trading/base-token-trading_7.spec.ts +++ b/packages/functions/test-tangle/base-token-trading/base-token-trading_7.spec.ts @@ -8,14 +8,13 @@ import { TokenTradeOrderStatus, TokenTradeOrderType, Transaction, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; import { cancelExpiredSale } from '../../src/cron/token.cron'; -import { tradeToken } from '../../src/runtime/firebase/token/trading'; import { getAddress } from '../../src/utils/address.utils'; -import { dateToTimestamp } from '../../src/utils/dateTime.utils'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -32,13 +31,13 @@ describe('Base token trading', () => { const network = type === TokenTradeOrderType.SELL ? Network.ATOI : Network.RMS; const member = type === TokenTradeOrderType.SELL ? helper.seller! : helper.buyer!; - mockWalletReturnValue(helper.walletSpy, member.uid, { + mockWalletReturnValue(member.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 1, type, }); - const tradeOrder = await testEnv.wrap(tradeToken)({}); + const tradeOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( network, tradeOrder.payload.targetAddress, @@ -54,15 +53,15 @@ describe('Base token trading', () => { }); let trade = (await tradeQuery.get())[0]; await build5Db() - .doc(`${COL.TOKEN_MARKET}/${trade.uid}`) - .update({ expiresAt: dateToTimestamp(dayjs().subtract(1, 'd')) }); + .doc(COL.TOKEN_MARKET, trade.uid) + .update({ expiresAt: dayjs().subtract(1, 'd').toDate() }); await cancelExpiredSale(); trade = (await tradeQuery.get())[0]; expect(trade.status).toBe(TokenTradeOrderStatus.EXPIRED); - const creditDocRef = build5Db().doc(`${COL.TRANSACTION}/${trade.creditTransactionId}`); + const creditDocRef = build5Db().doc(COL.TRANSACTION, trade.creditTransactionId!); await wait(async () => { const credit = await creditDocRef.get(); return credit.payload?.walletReference?.confirmed; diff --git a/packages/functions/test-tangle/base-token-trading/base-token-trading_8.spec.ts b/packages/functions/test-tangle/base-token-trading/base-token-trading_8.spec.ts index 143713df79..f126100e09 100644 --- a/packages/functions/test-tangle/base-token-trading/base-token-trading_8.spec.ts +++ b/packages/functions/test-tangle/base-token-trading/base-token-trading_8.spec.ts @@ -7,10 +7,10 @@ import { TokenTradeOrderStatus, TokenTradeOrderType, Transaction, + WEN_FUNC, } from '@build-5/interfaces'; -import { tradeToken } from '../../src/runtime/firebase/token/trading'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsForManyFromFaucet, requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -24,13 +24,15 @@ describe('Base token trading', () => { it('Should fulfill many sells with buy', async () => { const count = 15; - mockWalletReturnValue(helper.walletSpy, helper.seller!.uid, { + mockWalletReturnValue(helper.seller!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 1, type: TokenTradeOrderType.SELL, }); - const promises = Array.from(Array(count)).map(() => testEnv.wrap(tradeToken)({})); + const promises = Array.from(Array(count)).map(() => + testEnv.wrap(WEN_FUNC.tradeToken), + ); const orders: Transaction[] = await Promise.all(promises); await requestFundsForManyFromFaucet( @@ -46,13 +48,13 @@ describe('Base token trading', () => { return snap.length === count; }); - mockWalletReturnValue(helper.walletSpy, helper.buyer!.uid, { + mockWalletReturnValue(helper.buyer!.uid, { symbol: helper.token!.symbol, count: count * MIN_IOTA_AMOUNT, price: 1, type: TokenTradeOrderType.BUY, }); - const trade = await testEnv.wrap(tradeToken)({}); + const trade = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet(Network.RMS, trade.payload.targetAddress, trade.payload.amount); await wait(async () => { diff --git a/packages/functions/test-tangle/base-token-trading/base-token-trading_9.spec.ts b/packages/functions/test-tangle/base-token-trading/base-token-trading_9.spec.ts index f7c0d9b5dd..dc8068eaed 100644 --- a/packages/functions/test-tangle/base-token-trading/base-token-trading_9.spec.ts +++ b/packages/functions/test-tangle/base-token-trading/base-token-trading_9.spec.ts @@ -7,10 +7,10 @@ import { TokenTradeOrderStatus, TokenTradeOrderType, Transaction, + WEN_FUNC, } from '@build-5/interfaces'; -import { tradeToken } from '../../src/runtime/firebase/token/trading'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsForManyFromFaucet, requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -24,13 +24,15 @@ describe('Base token trading', () => { it('Should fulfill many buys with sell', async () => { const count = 15; - mockWalletReturnValue(helper.walletSpy, helper.buyer!.uid, { + mockWalletReturnValue(helper.buyer!.uid, { symbol: helper.token!.symbol, count: MIN_IOTA_AMOUNT, price: 1, type: TokenTradeOrderType.BUY, }); - const promises = Array.from(Array(count)).map(() => testEnv.wrap(tradeToken)({})); + const promises = Array.from(Array(count)).map(() => + testEnv.wrap(WEN_FUNC.tradeToken), + ); const orders: Transaction[] = await Promise.all(promises); await requestFundsForManyFromFaucet( Network.RMS, @@ -45,13 +47,13 @@ describe('Base token trading', () => { return snap.length === count; }); - mockWalletReturnValue(helper.walletSpy, helper.seller!.uid, { + mockWalletReturnValue(helper.seller!.uid, { symbol: helper.token!.symbol, count: count * MIN_IOTA_AMOUNT, price: 1, type: TokenTradeOrderType.SELL, }); - const trade = await testEnv.wrap(tradeToken)({}); + const trade = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet(Network.ATOI, trade.payload.targetAddress, trade.payload.amount); await wait(async () => { diff --git a/packages/functions/test-tangle/collection-minting/Helper.ts b/packages/functions/test-tangle/collection-minting/Helper.ts index d5ce76c913..80de1205c4 100644 --- a/packages/functions/test-tangle/collection-minting/Helper.ts +++ b/packages/functions/test-tangle/collection-minting/Helper.ts @@ -17,56 +17,44 @@ import { TransactionPayloadType, TransactionType, UnsoldMintingOptions, + WEN_FUNC, } from '@build-5/interfaces'; import { FeatureType, MetadataFeature, NftOutput, hexToUtf8 } from '@iota/sdk'; import dayjs from 'dayjs'; import { set } from 'lodash'; -import { createCollection, mintCollection } from '../../src/runtime/firebase/collection/index'; -import { openBid } from '../../src/runtime/firebase/nft'; -import { createNft, orderNft, setForSaleNft } from '../../src/runtime/firebase/nft/index'; import { NftWallet } from '../../src/services/wallet/NftWallet'; import { Wallet } from '../../src/services/wallet/wallet'; -import * as wallet from '../../src/utils/wallet.utils'; import { getRandomEthAddress } from '../../src/utils/wallet.utils'; -import { - createMember as createMemberTest, - createSpace, - mockWalletReturnValue, - submitMilestoneFunc, - wait, -} from '../../test/controls/common'; -import { MEDIA, getWallet, testEnv } from '../../test/set-up'; +import { submitMilestoneFunc, wait } from '../../test/controls/common'; +import { MEDIA, getWallet, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; export class CollectionMintHelper { - public walletSpy: any | undefined; - public network: Network = Network.RMS; - public collection: string | undefined; - public guardian: string | undefined; - public space: Space | undefined; - public royaltySpace: Space | undefined; - public member: string | undefined; - public walletService: Wallet | undefined; - public nftWallet: NftWallet | undefined; + public network = Network.RMS; + public collection = ''; + public guardian = ''; + public space: Space = {} as any; + public royaltySpace: Space = {} as any; + public member = ''; + public walletService: Wallet = {} as any; + public nftWallet: NftWallet = {} as any; public beforeAll = async () => { - this.walletSpy = jest.spyOn(wallet, 'decodeAuth'); this.walletService = await getWallet(this.network); this.nftWallet = new NftWallet(this.walletService); }; public beforeEach = async () => { - this.guardian = await createMemberTest(this.walletSpy); - this.member = await createMemberTest(this.walletSpy); - this.space = await createSpace(this.walletSpy, this.guardian); - this.royaltySpace = await createSpace(this.walletSpy, this.guardian); + this.guardian = await testEnv.createMember(); + this.member = await testEnv.createMember(); + this.space = await testEnv.createSpace(this.guardian); + this.royaltySpace = await testEnv.createSpace(this.guardian); mockWalletReturnValue( - this.walletSpy, this.guardian, this.createDummyCollection(this.space.uid, this.royaltySpace.uid), ); - this.collection = (await testEnv.wrap(createCollection)({})).uid; + this.collection = (await testEnv.wrap(WEN_FUNC.createCollection)).uid; }; public createLockedNft = async () => { @@ -74,19 +62,19 @@ export class CollectionMintHelper { delete nft.uid; delete nft.status; delete nft.placeholderNft; - mockWalletReturnValue(this.walletSpy, this.guardian!, nft); - nft = await testEnv.wrap(createNft)({}); + mockWalletReturnValue(this.guardian!, nft); + nft = await testEnv.wrap(WEN_FUNC.createNft); await build5Db() - .doc(`${COL.NFT}/${nft.uid}`) + .doc(COL.NFT, nft.uid) .update({ availableFrom: dayjs().subtract(1, 'h').toDate() }); - mockWalletReturnValue(this.walletSpy, this.guardian!, { + mockWalletReturnValue(this.guardian!, { collection: this.collection, nft: nft.uid, }); - await testEnv.wrap(orderNft)({}); - return await build5Db().doc(`${COL.NFT}/${nft.uid}`).get(); + await testEnv.wrap(WEN_FUNC.orderNft); + return await build5Db().doc(COL.NFT, nft.uid).get(); }; public createAndOrderNft = async (buyAndAuctionId = false, shouldBid = false) => { @@ -94,34 +82,32 @@ export class CollectionMintHelper { delete nft.uid; delete nft.status; delete nft.placeholderNft; - mockWalletReturnValue(this.walletSpy, this.guardian!, nft); - nft = await testEnv.wrap(createNft)({}); + mockWalletReturnValue(this.guardian!, nft); + nft = await testEnv.wrap(WEN_FUNC.createNft); if (buyAndAuctionId) { await build5Db() - .doc(`${COL.NFT}/${nft.uid}`) + .doc(COL.NFT, nft.uid) .update({ availableFrom: dayjs().subtract(1, 'h').toDate() }); - mockWalletReturnValue(this.walletSpy, this.guardian!, { + mockWalletReturnValue(this.guardian!, { collection: this.collection, nft: nft.uid, }); - const order = await testEnv.wrap(orderNft)({}); + const order = await testEnv.wrap(WEN_FUNC.orderNft); await submitMilestoneFunc(order); - mockWalletReturnValue(this.walletSpy, this.guardian!, this.dummyAuctionData(nft.uid)); - await testEnv.wrap(setForSaleNft)({}); - await wait( - async () => (await build5Db().doc(`${COL.NFT}/${nft.uid}`).get())?.available === 3, - ); + mockWalletReturnValue(this.guardian!, this.dummyAuctionData(nft.uid)); + await testEnv.wrap(WEN_FUNC.setForSaleNft); + await wait(async () => (await build5Db().doc(COL.NFT, nft.uid).get())?.available === 3); if (shouldBid) { - mockWalletReturnValue(this.walletSpy, this.member!, { nft: nft.uid }); - const bidOrder = await testEnv.wrap(openBid)({}); + mockWalletReturnValue(this.member!, { nft: nft.uid }); + const bidOrder = await testEnv.wrap(WEN_FUNC.openBid); await submitMilestoneFunc(bidOrder, 2 * MIN_IOTA_AMOUNT); } } - return await build5Db().doc(`${COL.NFT}/${nft.uid}`).get(); + return await build5Db().doc(COL.NFT, nft.uid).get(); }; public mintCollection = async ( @@ -136,14 +122,14 @@ export class CollectionMintHelper { if (unsoldMintingOptions === UnsoldMintingOptions.SET_NEW_PRICE) { set(request, 'price', price); } - mockWalletReturnValue(this.walletSpy, this.guardian!, request); - const collectionMintOrder = await testEnv.wrap(mintCollection)({}); + mockWalletReturnValue(this.guardian!, request); + const collectionMintOrder = await testEnv.wrap(WEN_FUNC.mintCollection); await requestFundsFromFaucet( this.network!, collectionMintOrder.payload.targetAddress, collectionMintOrder.payload.amount, ); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${this.collection}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, this.collection); await wait(async () => { const data = await collectionDocRef.get(); return data.status === CollectionStatus.MINTED; @@ -160,7 +146,7 @@ export class CollectionMintHelper { await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.MINT_COLLECTION) - .where('payload.type', '==', TransactionPayloadType.SEND_ALIAS_TO_GUARDIAN) + .where('payload_type', '==', TransactionPayloadType.SEND_ALIAS_TO_GUARDIAN) .where('member', '==', this.guardian) .get() ).map((d) => d); @@ -174,7 +160,7 @@ export class CollectionMintHelper { await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.MINT_COLLECTION) - .where('payload.type', '==', TransactionPayloadType.LOCK_COLLECTION) + .where('payload_type', '==', TransactionPayloadType.LOCK_COLLECTION) .where('member', '==', this.guardian) .get() ).map((d) => d); @@ -199,7 +185,7 @@ export class CollectionMintHelper { }); public createDummyNft = (collection: string, description = 'babba') => ({ - name: 'NFT ' + description, + name: 'NFT ' + Math.random(), description, collection, availableFrom: dayjs().add(1, 'hour').toDate(), diff --git a/packages/functions/test-tangle/collection-minting/collection-minting_1.spec.ts b/packages/functions/test-tangle/collection-minting/collection-minting_1.spec.ts index ef5f4dbfc5..277d9c9591 100644 --- a/packages/functions/test-tangle/collection-minting/collection-minting_1.spec.ts +++ b/packages/functions/test-tangle/collection-minting/collection-minting_1.spec.ts @@ -1,7 +1,6 @@ -import { UnsoldMintingOptions, WenError } from '@build-5/interfaces'; -import { mintCollection } from '../../src/runtime/firebase/collection/index'; -import { expectThrow, mockWalletReturnValue } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { Transaction, UnsoldMintingOptions, WEN_FUNC, WenError } from '@build-5/interfaces'; +import { expectThrow } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { CollectionMintHelper } from './Helper'; describe('Collection minting', () => { @@ -16,21 +15,27 @@ describe('Collection minting', () => { }); it('Should throw, no nfts', async () => { - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { + mockWalletReturnValue(helper.guardian!, { collection: helper.collection, network: helper.network, unsoldMintingOptions: UnsoldMintingOptions.KEEP_PRICE, }); - await expectThrow(testEnv.wrap(mintCollection)({}), WenError.no_nfts_to_mint.key); + await expectThrow( + testEnv.wrap(WEN_FUNC.mintCollection), + WenError.no_nfts_to_mint.key, + ); }); it('Should throw, all nfts will be burned', async () => { await helper.createAndOrderNft(); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { + mockWalletReturnValue(helper.guardian!, { collection: helper.collection, network: helper.network, unsoldMintingOptions: UnsoldMintingOptions.BURN_UNSOLD, }); - await expectThrow(testEnv.wrap(mintCollection)({}), WenError.no_nfts_to_mint.key); + await expectThrow( + testEnv.wrap(WEN_FUNC.mintCollection), + WenError.no_nfts_to_mint.key, + ); }); }); diff --git a/packages/functions/test-tangle/collection-minting/collection-minting_10.spec.ts b/packages/functions/test-tangle/collection-minting/collection-minting_10.spec.ts index 58a3973f5e..2b06783fe9 100644 --- a/packages/functions/test-tangle/collection-minting/collection-minting_10.spec.ts +++ b/packages/functions/test-tangle/collection-minting/collection-minting_10.spec.ts @@ -16,14 +16,14 @@ describe('Collection minting', () => { it('Should hide placeholder nft, all are sold before mint', async () => { await helper.createAndOrderNft(true, true); let placeholderNft = await helper.createAndOrderNft(true, false); - await build5Db().doc(`${COL.NFT}/${placeholderNft.uid}`).update({ placeholderNft: true }); + await build5Db().doc(COL.NFT, placeholderNft.uid).update({ placeholderNft: true }); await build5Db() - .doc(`${COL.COLLECTION}/${helper.collection}`) + .doc(COL.COLLECTION, helper.collection) .update({ total: build5Db().inc(-1) }); await helper.mintCollection(); - placeholderNft = await build5Db().doc(`${COL.NFT}/${placeholderNft.uid}`).get(); + placeholderNft = await build5Db().doc(COL.NFT, placeholderNft.uid).get(); expect(placeholderNft.hidden).toBe(true); }); }); diff --git a/packages/functions/test-tangle/collection-minting/collection-minting_11.spec.ts b/packages/functions/test-tangle/collection-minting/collection-minting_11.spec.ts index 113d5fabae..e4bdc0ab40 100644 --- a/packages/functions/test-tangle/collection-minting/collection-minting_11.spec.ts +++ b/packages/functions/test-tangle/collection-minting/collection-minting_11.spec.ts @@ -19,16 +19,16 @@ describe('Collection minting', () => { await helper.createAndOrderNft(true, true); let nft: Nft | undefined = await helper.createAndOrderNft(); let placeholderNft = await helper.createAndOrderNft(true, false); - await build5Db().doc(`${COL.NFT}/${placeholderNft.uid}`).update({ placeholderNft: true }); + await build5Db().doc(COL.NFT, placeholderNft.uid).update({ placeholderNft: true }); await build5Db() - .doc(`${COL.COLLECTION}/${helper.collection}`) + .doc(COL.COLLECTION, helper.collection) .update({ total: build5Db().inc(-1) }); await helper.mintCollection(unsoldMintingOptions); - placeholderNft = await build5Db().doc(`${COL.NFT}/${placeholderNft.uid}`).get(); + placeholderNft = await build5Db().doc(COL.NFT, placeholderNft.uid).get(); expect(placeholderNft.hidden).toBe(true); - nft = await build5Db().doc(`${COL.NFT}/${nft.uid}`).get(); + nft = await build5Db().doc(COL.NFT, nft.uid).get(); if (unsoldMintingOptions === UnsoldMintingOptions.BURN_UNSOLD) { expect(nft).toBe(undefined); } else { diff --git a/packages/functions/test-tangle/collection-minting/collection-minting_12.spec.ts b/packages/functions/test-tangle/collection-minting/collection-minting_12.spec.ts index 7f9fc72268..e3cb46c1f8 100644 --- a/packages/functions/test-tangle/collection-minting/collection-minting_12.spec.ts +++ b/packages/functions/test-tangle/collection-minting/collection-minting_12.spec.ts @@ -17,16 +17,16 @@ describe('Collection minting', () => { await helper.createAndOrderNft(true, true); let nft: Nft | undefined = await helper.createAndOrderNft(); let placeholderNft = await helper.createAndOrderNft(true, false); - await build5Db().doc(`${COL.NFT}/${placeholderNft.uid}`).update({ placeholderNft: true }); + await build5Db().doc(COL.NFT, placeholderNft.uid).update({ placeholderNft: true }); await build5Db() - .doc(`${COL.COLLECTION}/${helper.collection}`) + .doc(COL.COLLECTION, helper.collection) .update({ total: build5Db().inc(-1) }); await helper.mintCollection(); - placeholderNft = await build5Db().doc(`${COL.NFT}/${placeholderNft.uid}`).get(); + placeholderNft = await build5Db().doc(COL.NFT, placeholderNft.uid).get(); expect(placeholderNft.hidden).toBe(false); - nft = await build5Db().doc(`${COL.NFT}/${nft.uid}`).get(); + nft = await build5Db().doc(COL.NFT, nft.uid).get(); expect(nft).toBeDefined(); }); }); diff --git a/packages/functions/test-tangle/collection-minting/collection-minting_13.spec.ts b/packages/functions/test-tangle/collection-minting/collection-minting_13.spec.ts index 146c1f29d7..c95ec08d58 100644 --- a/packages/functions/test-tangle/collection-minting/collection-minting_13.spec.ts +++ b/packages/functions/test-tangle/collection-minting/collection-minting_13.spec.ts @@ -1,10 +1,9 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { build5Db } from '@build-5/database'; -import { COL, Collection, CollectionStatus, Nft } from '@build-5/interfaces'; +import { COL, Collection, CollectionStatus, Nft, WEN_FUNC } from '@build-5/interfaces'; import { NftOutput } from '@iota/sdk'; -import { createCollection } from '../../src/runtime/firebase/collection'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { CollectionMintHelper, getNftMetadata } from './Helper'; describe('Collection minting', () => { @@ -20,19 +19,19 @@ describe('Collection minting', () => { it('Should mint without royalty space', async () => { const dummyCollection = helper.createDummyCollection(helper.space!.uid); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, dummyCollection); - helper.collection = (await testEnv.wrap(createCollection)({})).uid; + mockWalletReturnValue(helper.guardian!, dummyCollection); + helper.collection = (await testEnv.wrap(WEN_FUNC.createCollection)).uid; let nft = await helper.createAndOrderNft(); await helper.mintCollection(); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${helper.collection}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, helper.collection); await wait(async () => { - const collection = await collectionDocRef.get(); + const collection = await collectionDocRef.get(); return collection?.status === CollectionStatus.MINTED; }); - const collection = await collectionDocRef.get(); + const collection = await collectionDocRef.get(); const client = helper.walletService?.client!; const collectionOutputId = await client.nftOutputId(collection?.mintingData?.nftId!); @@ -40,7 +39,7 @@ describe('Collection minting', () => { const collectionMetadata = getNftMetadata(collectionOutput as NftOutput); expect(collectionMetadata.royalties).toEqual({}); - const nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); + const nftDocRef = build5Db().doc(COL.NFT, nft.uid); nft = await nftDocRef.get(); const nftOutputId = await client.nftOutputId(nft.mintingData?.nftId!); const nftOutput = (await client.getOutput(nftOutputId)).output; diff --git a/packages/functions/test-tangle/collection-minting/collection-minting_2.spec.ts b/packages/functions/test-tangle/collection-minting/collection-minting_2.spec.ts index 11c6330e53..ee394a070a 100644 --- a/packages/functions/test-tangle/collection-minting/collection-minting_2.spec.ts +++ b/packages/functions/test-tangle/collection-minting/collection-minting_2.spec.ts @@ -4,13 +4,14 @@ import { Collection, CollectionStatus, MediaStatus, - Nft, SOON_PROJECT_ID, + Transaction, UnsoldMintingOptions, + WEN_FUNC, } from '@build-5/interfaces'; -import { mintCollection } from '../../src/runtime/firebase/collection'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { MEDIA, testEnv } from '../../test/set-up'; +import { dateToTimestamp } from '../../src/utils/dateTime.utils'; +import { wait } from '../../test/controls/common'; +import { MEDIA, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { CollectionMintHelper } from './Helper'; @@ -27,15 +28,19 @@ describe('Collection minting', () => { it('Should retry minting when prepare ipfs failed', async () => { const count = 5; - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${helper.collection}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, helper.collection!); await collectionDocRef.update({ total: count }); const promises = Array.from(Array(count)).map(async () => { const nft = helper.createDummyNft(helper.collection!); await build5Db() - .doc(`${COL.NFT}/${nft.uid}`) - .create({ ...nft, project: SOON_PROJECT_ID }); - return nft; + .doc(COL.NFT, nft.uid) + .create({ + ...nft, + availableFrom: dateToTimestamp(nft.availableFrom), + project: SOON_PROJECT_ID, + } as any); + return (await build5Db().doc(COL.NFT, nft.uid).get())!; }); const nfts = await Promise.all(promises); @@ -45,11 +50,11 @@ describe('Collection minting', () => { unsoldMintingOptions: UnsoldMintingOptions.KEEP_PRICE, }; - mockWalletReturnValue(helper.walletSpy, helper.guardian!, request); - const collectionMintOrder = await testEnv.wrap(mintCollection)({}); + mockWalletReturnValue(helper.guardian!, request); + const collectionMintOrder = await testEnv.wrap(WEN_FUNC.mintCollection); for (let i = 0; i < nfts.length; ++i) { - const docRef = build5Db().doc(`${COL.NFT}/${nfts[i].uid}`); - await docRef.update({ media: i > 2 ? 'asd' : MEDIA }); + const docRef = build5Db().doc(COL.NFT, nfts[i].uid); + await docRef.update({ media: i > 2 ? 'name' : MEDIA }); } await requestFundsFromFaucet( helper.network!, @@ -65,18 +70,18 @@ describe('Collection minting', () => { const nfts = await nftQuery.get(); return nfts.length === 3; }); - const pendingUploadNfts = await nftQuery.limit(2).get(); + const pendingUploadNfts = await nftQuery.limit(2).get(); for (const nft of pendingUploadNfts) { - const docRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); + const docRef = build5Db().doc(COL.NFT, nft.uid); await docRef.update({ mediaStatus: MediaStatus.UPLOADED }); } - await collectionDocRef.update({ 'mintingData.nftMediaToUpload': 3 }); + await collectionDocRef.update({ mintingData_nftMediaToUpload: 3 }); for (const nft of nfts) { - const docRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); + const docRef = build5Db().doc(COL.NFT, nft.uid); await docRef.update({ media: MEDIA }); } - await collectionDocRef.update({ status: 'asd' }); + await collectionDocRef.update({ status: CollectionStatus.PRE_MINTED }); await collectionDocRef.update({ status: CollectionStatus.MINTING }); await wait(async () => { const data = await collectionDocRef.get(); diff --git a/packages/functions/test-tangle/collection-minting/collection-minting_3.only.spec.ts b/packages/functions/test-tangle/collection-minting/collection-minting_3.only.spec.ts index a7c22609c3..917e6beff5 100644 --- a/packages/functions/test-tangle/collection-minting/collection-minting_3.only.spec.ts +++ b/packages/functions/test-tangle/collection-minting/collection-minting_3.only.spec.ts @@ -4,11 +4,11 @@ import { Nft, NftStatus, SOON_PROJECT_ID, - Transaction, TransactionPayloadType, TransactionType, } from '@build-5/interfaces'; import { isEmpty } from 'lodash'; +import { dateToTimestamp } from '../../src/utils/dateTime.utils'; import { CollectionMintHelper } from './Helper'; describe('Collection minting', () => { @@ -24,12 +24,17 @@ describe('Collection minting', () => { it('Should mint huge nfts', async () => { const count = 30; - await build5Db().doc(`${COL.COLLECTION}/${helper.collection}`).update({ total: count }); - const promises = Array.from(Array(count)).map(() => { + await build5Db().doc(COL.COLLECTION, helper.collection).update({ total: count }); + const promises = Array.from(Array(count)).map(async () => { const nft = helper.createDummyNft(helper.collection!, helper.getRandomDescrptiron()); - return build5Db() - .doc(`${COL.NFT}/${nft.uid}`) - .create({ ...nft, project: SOON_PROJECT_ID }); + await build5Db() + .doc(COL.NFT, nft.uid) + .create({ + ...nft, + availableFrom: dateToTimestamp(nft.availableFrom), + project: SOON_PROJECT_ID, + } as any); + return (await build5Db().doc(COL.NFT, nft.uid).get())!; }); await Promise.all(promises); await helper.mintCollection(); @@ -37,9 +42,9 @@ describe('Collection minting', () => { const nftMintSnap = await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.MINT_COLLECTION) - .where('payload.type', '==', TransactionPayloadType.MINT_NFTS) - .where('payload.collection', '==', helper.collection) - .get(); + .where('payload_type', '==', TransactionPayloadType.MINT_NFTS) + .where('payload_collection', '==', helper.collection) + .get(); expect(nftMintSnap.length).toBeGreaterThan(1); expect(nftMintSnap.reduce((acc, act) => acc && act?.payload.amount! > 0, true)).toBe(true); expect(nftMintSnap.reduce((acc, act) => acc && !isEmpty(act?.payload.nfts), true)).toBe(true); diff --git a/packages/functions/test-tangle/collection-minting/collection-minting_4_a.spec.ts b/packages/functions/test-tangle/collection-minting/collection-minting_4_a.spec.ts index 21d3472552..6d64681b8b 100644 --- a/packages/functions/test-tangle/collection-minting/collection-minting_4_a.spec.ts +++ b/packages/functions/test-tangle/collection-minting/collection-minting_4_a.spec.ts @@ -31,9 +31,9 @@ describe('Collection minting', () => { await helper.createAndOrderNft(true); await helper.createAndOrderNft(true, true); let placeholderNft = await helper.createAndOrderNft(true, false); - await build5Db().doc(`${COL.NFT}/${placeholderNft.uid}`).update({ placeholderNft: true }); + await build5Db().doc(COL.NFT, placeholderNft.uid).update({ placeholderNft: true }); await build5Db() - .doc(`${COL.COLLECTION}/${helper.collection}`) + .doc(COL.COLLECTION, helper.collection) .update({ total: build5Db().inc(-1) }); await helper.mintCollection(); @@ -41,7 +41,7 @@ describe('Collection minting', () => { const bidCredit = ( await build5Db() .collection(COL.TRANSACTION) - .where('payload.collection', '==', helper.collection) + .where('payload_collection', '==', helper.collection) .where('type', '==', TransactionType.CREDIT) .get() ).map((d) => d); @@ -56,23 +56,19 @@ describe('Collection minting', () => { const allCancelled = nfts.reduce( (acc, act) => acc && - act.auctionFrom === null && - act.auctionTo === null && - act.auctionFloorPrice === null && - act.auctionLength === null && - act.auctionHighestBid === null && - act.auctionHighestBidder === null && - (!act.sold || (act.availableFrom === null && act.availablePrice === null)), + act.auctionFrom === undefined && + act.auctionTo === undefined && + act.auctionFloorPrice === undefined && + act.auctionLength === undefined && + act.auctionHighestBid === undefined && + act.auctionHighestBidder === undefined && + (!act.sold || (act.availableFrom === undefined && act.availablePrice === undefined)), true, ); expect(allCancelled).toBe(true); - const collection = ( - await build5Db().doc(`${COL.COLLECTION}/${helper.collection}`).get() - ); - const royaltySpace = ( - await build5Db().doc(`${COL.SPACE}/${collection.royaltiesSpace}`).get() - ); + const collection = await build5Db().doc(COL.COLLECTION, helper.collection).get(); + const royaltySpace = await build5Db().doc(COL.SPACE, collection.royaltiesSpace!).get(); const collectionOutput = await helper.nftWallet!.getNftOutputs( collection.mintingData?.nftId, @@ -110,7 +106,7 @@ describe('Collection minting', () => { expect(metadata.build5Id).toBe(nft.uid); } - placeholderNft = await build5Db().doc(`${COL.NFT}/${placeholderNft.uid}`).get(); + placeholderNft = await build5Db().doc(COL.NFT, placeholderNft.uid).get(); expect(placeholderNft.status).toBe(NftStatus.PRE_MINTED); }); }); diff --git a/packages/functions/test-tangle/collection-minting/collection-minting_4_b.spec.ts b/packages/functions/test-tangle/collection-minting/collection-minting_4_b.spec.ts index 2dfd4436b9..9ce050b980 100644 --- a/packages/functions/test-tangle/collection-minting/collection-minting_4_b.spec.ts +++ b/packages/functions/test-tangle/collection-minting/collection-minting_4_b.spec.ts @@ -33,9 +33,9 @@ describe('Collection minting', () => { await helper.createAndOrderNft(true); await helper.createAndOrderNft(true, true); let placeholderNft = await helper.createAndOrderNft(true, false); - await build5Db().doc(`${COL.NFT}/${placeholderNft.uid}`).update({ placeholderNft: true }); + await build5Db().doc(COL.NFT, placeholderNft.uid).update({ placeholderNft: true }); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${helper.collection}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, helper.collection); await collectionDocRef.update({ total: build5Db().inc(-1), limitedEdition: true }); await helper.mintCollection(); @@ -49,7 +49,7 @@ describe('Collection minting', () => { const bidCredit = ( await build5Db() .collection(COL.TRANSACTION) - .where('payload.collection', '==', helper.collection) + .where('payload_collection', '==', helper.collection) .where('type', '==', TransactionType.CREDIT) .get() ).map((d) => d); @@ -64,21 +64,19 @@ describe('Collection minting', () => { const allCancelled = nfts.reduce( (acc, act) => acc && - act.auctionFrom === null && - act.auctionTo === null && - act.auctionFloorPrice === null && - act.auctionLength === null && - act.auctionHighestBid === null && - act.auctionHighestBidder === null && - (!act.sold || (act.availableFrom === null && act.availablePrice === null)), + act.auctionFrom === undefined && + act.auctionTo === undefined && + act.auctionFloorPrice === undefined && + act.auctionLength === undefined && + act.auctionHighestBid === undefined && + act.auctionHighestBidder === undefined && + (!act.sold || (act.availableFrom === undefined && act.availablePrice === undefined)), true, ); expect(allCancelled).toBe(true); collection = await collectionDocRef.get(); - const royaltySpace = ( - await build5Db().doc(`${COL.SPACE}/${collection.royaltiesSpace}`).get() - ); + const royaltySpace = await build5Db().doc(COL.SPACE, collection.royaltiesSpace!).get(); const collectionOutput = await helper.nftWallet!.getNftOutputs( collection.mintingData?.nftId, @@ -116,7 +114,7 @@ describe('Collection minting', () => { expect(metadata.build5Id).toBe(nft.uid); } - placeholderNft = await build5Db().doc(`${COL.NFT}/${placeholderNft.uid}`).get(); + placeholderNft = await build5Db().doc(COL.NFT, placeholderNft.uid).get(); expect(placeholderNft.status).toBe(NftStatus.PRE_MINTED); }); }); diff --git a/packages/functions/test-tangle/collection-minting/collection-minting_4_c.spec.ts b/packages/functions/test-tangle/collection-minting/collection-minting_4_c.spec.ts index 7acc45bb8f..386d1bbb2a 100644 --- a/packages/functions/test-tangle/collection-minting/collection-minting_4_c.spec.ts +++ b/packages/functions/test-tangle/collection-minting/collection-minting_4_c.spec.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { build5Db } from '@build-5/database'; -import { COL, Nft, NftStatus, Transaction } from '@build-5/interfaces'; +import { COL, NftStatus, Transaction } from '@build-5/interfaces'; import { CollectionMintHelper } from './Helper'; describe('Collection minting', () => { @@ -18,13 +18,13 @@ describe('Collection minting', () => { let lockedNft = await helper.createLockedNft(); await helper.mintCollection(); const lockedNftOrder = ( - await build5Db().doc(`${COL.TRANSACTION}/${lockedNft.lockedBy}`).get() + await build5Db().doc(COL.TRANSACTION, lockedNft.lockedBy!).get() ); expect(lockedNftOrder.payload.void).toBe(true); - lockedNft = await build5Db().doc(`${COL.NFT}/${lockedNft.uid}`).get(); + lockedNft = (await build5Db().doc(COL.NFT, lockedNft.uid).get())!; expect(lockedNft.locked).toBe(false); - expect(lockedNft.lockedBy).toBe(null); + expect(lockedNft.lockedBy).toBe(undefined); expect(lockedNft.mintingData).toBeDefined(); expect(lockedNft.status).toBe(NftStatus.MINTED); }); diff --git a/packages/functions/test-tangle/collection-minting/collection-minting_5.spec.ts b/packages/functions/test-tangle/collection-minting/collection-minting_5.spec.ts index 4603d18643..5cef2e6696 100644 --- a/packages/functions/test-tangle/collection-minting/collection-minting_5.spec.ts +++ b/packages/functions/test-tangle/collection-minting/collection-minting_5.spec.ts @@ -6,11 +6,11 @@ import { Transaction, TransactionType, UnsoldMintingOptions, + WEN_FUNC, } from '@build-5/interfaces'; import { isEqual } from 'lodash'; -import { mintCollection } from '../../src/runtime/firebase/collection/index'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { CollectionMintHelper } from './Helper'; @@ -30,18 +30,18 @@ describe('Collection minting', () => { const tmpAddress1 = await helper.walletService!.getNewIotaAddressDetails(); const tmpAddress2 = await helper.walletService!.getNewIotaAddressDetails(); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { + mockWalletReturnValue(helper.guardian!, { collection: helper.collection, network: helper.network, unsoldMintingOptions: UnsoldMintingOptions.KEEP_PRICE, }); - const collectionMintOrder1 = await testEnv.wrap(mintCollection)({}); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { + const collectionMintOrder1 = await testEnv.wrap(WEN_FUNC.mintCollection); + mockWalletReturnValue(helper.guardian!, { collection: helper.collection, network: helper.network, unsoldMintingOptions: UnsoldMintingOptions.KEEP_PRICE, }); - const collectionMintOrder2 = await testEnv.wrap(mintCollection)({}); + const collectionMintOrder2 = await testEnv.wrap(WEN_FUNC.mintCollection); expect(isEqual(collectionMintOrder1, collectionMintOrder2)).toBe(false); expect(collectionMintOrder1.payload.amount).toBe(collectionMintOrder2.payload.amount); @@ -61,14 +61,14 @@ describe('Collection minting', () => { const promises = [tmpAddress1, tmpAddress2].map((address, i) => helper.walletService!.send( address, - orders[i].payload.targetAddress, - orders[i].payload.amount, + orders[i].payload.targetAddress!, + orders[i].payload.amount!, {}, ), ); await Promise.all(promises); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${helper.collection}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, helper.collection); let collection = await collectionDocRef.get(); await wait(async () => { collection = await collectionDocRef.get(); @@ -79,9 +79,9 @@ describe('Collection minting', () => { const creditQuery = build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.CREDIT) - .where('payload.collection', '==', helper.collection); + .where('payload_collection', '==', helper.collection); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); const allConfirmed = snap.reduce( (acc, act) => acc && (act.payload?.walletReference?.confirmed || false), true, diff --git a/packages/functions/test-tangle/collection-minting/collection-minting_6.spec.ts b/packages/functions/test-tangle/collection-minting/collection-minting_6.spec.ts index 84417c6ff1..e3f5b4c720 100644 --- a/packages/functions/test-tangle/collection-minting/collection-minting_6.spec.ts +++ b/packages/functions/test-tangle/collection-minting/collection-minting_6.spec.ts @@ -19,19 +19,17 @@ describe('Collection minting', () => { await helper.createAndOrderNft(true); let nft = await helper.createAndOrderNft(); let collectionData = ( - await build5Db().doc(`${COL.COLLECTION}/${helper.collection}`).get() + await build5Db().doc(COL.COLLECTION, helper.collection).get() ); expect(collectionData.total).toBe(2); await helper.mintCollection(unsoldMintingOptions); - collectionData = ( - await build5Db().doc(`${COL.COLLECTION}/${helper.collection}`).get() - ); + collectionData = await build5Db().doc(COL.COLLECTION, helper.collection).get(); expect(collectionData.total).toBe( unsoldMintingOptions === UnsoldMintingOptions.BURN_UNSOLD ? 1 : 2, ); - nft = await build5Db().doc(`${COL.NFT}/${nft?.uid}`).get(); + nft = await build5Db().doc(COL.NFT, nft?.uid!).get(); expect(nft === undefined).toBe(unsoldMintingOptions === UnsoldMintingOptions.BURN_UNSOLD); }, ); diff --git a/packages/functions/test-tangle/collection-minting/collection-minting_7.spec.ts b/packages/functions/test-tangle/collection-minting/collection-minting_7.spec.ts index c298bd3811..8bebb77ed4 100644 --- a/packages/functions/test-tangle/collection-minting/collection-minting_7.spec.ts +++ b/packages/functions/test-tangle/collection-minting/collection-minting_7.spec.ts @@ -5,12 +5,13 @@ import { CollectionType, MIN_IOTA_AMOUNT, Nft, + Transaction, UnsoldMintingOptions, + WEN_FUNC, WenError, } from '@build-5/interfaces'; -import { mintCollection } from '../../src/runtime/firebase/collection/index'; -import { expectThrow, mockWalletReturnValue } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { expectThrow } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { CollectionMintHelper } from './Helper'; describe('Collection minting', () => { @@ -27,42 +28,46 @@ describe('Collection minting', () => { it.each([CollectionType.GENERATED, CollectionType.SFT, CollectionType.CLASSIC])( 'Should set new price', async (type: CollectionType) => { - await build5Db().doc(`${COL.COLLECTION}/${helper.collection}`).update({ type }); + await build5Db().doc(COL.COLLECTION, helper.collection).update({ type }); let nft = await helper.createAndOrderNft(); let collectionData = ( - await build5Db().doc(`${COL.COLLECTION}/${helper.collection}`).get() + await build5Db().doc(COL.COLLECTION, helper.collection).get() ); expect(collectionData.total).toBe(1); if (type === CollectionType.CLASSIC) { - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { + mockWalletReturnValue(helper.guardian!, { collection: helper.collection, network: helper.network, unsoldMintingOptions: UnsoldMintingOptions.SET_NEW_PRICE, price: 2 * MIN_IOTA_AMOUNT, }); - await expectThrow(testEnv.wrap(mintCollection)({}), WenError.invalid_collection_status.key); + await expectThrow( + testEnv.wrap(WEN_FUNC.mintCollection), + WenError.invalid_collection_status.key, + ); return; } await helper.mintCollection(UnsoldMintingOptions.SET_NEW_PRICE, 2 * MIN_IOTA_AMOUNT); - collectionData = ( - await build5Db().doc(`${COL.COLLECTION}/${helper.collection}`).get() - ); + collectionData = await build5Db().doc(COL.COLLECTION, helper.collection).get(); expect(collectionData.total).toBe(1); - nft = await build5Db().doc(`${COL.NFT}/${nft?.uid}`).get(); + nft = await build5Db().doc(COL.NFT, nft?.uid!).get(); expect(nft.availablePrice).toBe(2 * MIN_IOTA_AMOUNT); expect(nft.price).toBe(2 * MIN_IOTA_AMOUNT); }, ); it('Should throw, min price below mint iota', async () => { - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { + mockWalletReturnValue(helper.guardian!, { collection: helper.collection, network: helper.network, unsoldMintingOptions: UnsoldMintingOptions.SET_NEW_PRICE, price: MIN_IOTA_AMOUNT / 2, }); - await expectThrow(testEnv.wrap(mintCollection)({}), WenError.invalid_params.key); + await expectThrow( + testEnv.wrap(WEN_FUNC.mintCollection), + WenError.invalid_params.key, + ); }); }); diff --git a/packages/functions/test-tangle/collection-minting/collection-minting_8.spec.ts b/packages/functions/test-tangle/collection-minting/collection-minting_8.spec.ts index b24e8b422f..c342b35629 100644 --- a/packages/functions/test-tangle/collection-minting/collection-minting_8.spec.ts +++ b/packages/functions/test-tangle/collection-minting/collection-minting_8.spec.ts @@ -4,12 +4,13 @@ import { Collection, CollectionType, Nft, + Transaction, UnsoldMintingOptions, + WEN_FUNC, WenError, } from '@build-5/interfaces'; -import { mintCollection } from '../../src/runtime/firebase/collection/index'; -import { expectThrow, mockWalletReturnValue } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { expectThrow } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { CollectionMintHelper } from './Helper'; describe('Collection minting', () => { @@ -26,30 +27,31 @@ describe('Collection minting', () => { it.each([CollectionType.GENERATED, CollectionType.SFT, CollectionType.CLASSIC])( 'Should set owner to guardian', async (type: CollectionType) => { - await build5Db().doc(`${COL.COLLECTION}/${helper.collection}`).update({ type }); + await build5Db().doc(COL.COLLECTION, helper.collection).update({ type }); let nft = await helper.createAndOrderNft(); let collectionData = ( - await build5Db().doc(`${COL.COLLECTION}/${helper.collection}`).get() + await build5Db().doc(COL.COLLECTION, helper.collection).get() ); expect(collectionData.total).toBe(1); expect(collectionData.sold).toBe(0); if (type !== CollectionType.CLASSIC) { - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { + mockWalletReturnValue(helper.guardian!, { collection: helper.collection, network: helper.network, unsoldMintingOptions: UnsoldMintingOptions.TAKE_OWNERSHIP, }); - await expectThrow(testEnv.wrap(mintCollection)({}), WenError.invalid_collection_status.key); + await expectThrow( + testEnv.wrap(WEN_FUNC.mintCollection), + WenError.invalid_collection_status.key, + ); return; } await helper.mintCollection(UnsoldMintingOptions.TAKE_OWNERSHIP); - collectionData = ( - await build5Db().doc(`${COL.COLLECTION}/${helper.collection}`).get() - ); + collectionData = await build5Db().doc(COL.COLLECTION, helper.collection).get(); expect(collectionData.total).toBe(1); - nft = await build5Db().doc(`${COL.NFT}/${nft?.uid}`).get(); + nft = await build5Db().doc(COL.NFT, nft?.uid!).get(); expect(nft.isOwned).toBe(true); expect(nft.owner).toBe(helper.guardian); expect(nft.sold).toBe(true); diff --git a/packages/functions/test-tangle/collection-minting/collection-minting_9.spec.ts b/packages/functions/test-tangle/collection-minting/collection-minting_9.spec.ts index 3c6e8b3402..57ec4953ae 100644 --- a/packages/functions/test-tangle/collection-minting/collection-minting_9.spec.ts +++ b/packages/functions/test-tangle/collection-minting/collection-minting_9.spec.ts @@ -1,8 +1,7 @@ import { build5Db } from '@build-5/database'; -import { COL, UnsoldMintingOptions, WenError } from '@build-5/interfaces'; -import { mintCollection } from '../../src/runtime/firebase/collection/index'; -import { expectThrow, mockWalletReturnValue } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { COL, Transaction, UnsoldMintingOptions, WEN_FUNC, WenError } from '@build-5/interfaces'; +import { expectThrow } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { CollectionMintHelper } from './Helper'; describe('Collection minting', () => { @@ -17,42 +16,46 @@ describe('Collection minting', () => { }); it('Should throw, member has no valid address', async () => { - await build5Db().doc(`${COL.MEMBER}/${helper.guardian}`).update({ validatedAddress: {} }); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { + await build5Db() + .doc(COL.MEMBER, helper.guardian) + .update({ rmsAddress: '', smrAddress: '', iotaAddress: '', atoiAddress: '' }); + mockWalletReturnValue(helper.guardian!, { collection: helper.collection, network: helper.network, unsoldMintingOptions: UnsoldMintingOptions.KEEP_PRICE, }); await expectThrow( - testEnv.wrap(mintCollection)({}), + testEnv.wrap(WEN_FUNC.mintCollection), WenError.member_must_have_validated_address.key, ); }); it('Should throw, space has no valid address', async () => { - await build5Db().doc(`${COL.SPACE}/${helper.space!.uid}`).update({ validatedAddress: {} }); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { + await build5Db() + .doc(COL.SPACE, helper.space!.uid) + .update({ rmsAddress: '', smrAddress: '', iotaAddress: '', atoiAddress: '' }); + mockWalletReturnValue(helper.guardian!, { collection: helper.collection, network: helper.network, unsoldMintingOptions: UnsoldMintingOptions.KEEP_PRICE, }); await expectThrow( - testEnv.wrap(mintCollection)({}), + testEnv.wrap(WEN_FUNC.mintCollection), WenError.space_must_have_validated_address.key, ); }); it('Should throw, royalty space has no valid address', async () => { await build5Db() - .doc(`${COL.SPACE}/${helper.royaltySpace!.uid}`) - .update({ validatedAddress: {} }); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { + .doc(COL.SPACE, helper.royaltySpace!.uid) + .update({ rmsAddress: '', smrAddress: '', iotaAddress: '', atoiAddress: '' }); + mockWalletReturnValue(helper.guardian!, { collection: helper.collection, network: helper.network, unsoldMintingOptions: UnsoldMintingOptions.KEEP_PRICE, }); await expectThrow( - testEnv.wrap(mintCollection)({}), + testEnv.wrap(WEN_FUNC.mintCollection), WenError.space_must_have_validated_address.key, ); }); diff --git a/packages/functions/test-tangle/common.ts b/packages/functions/test-tangle/common.ts index 826880b3fd..ee0a9e15f8 100644 --- a/packages/functions/test-tangle/common.ts +++ b/packages/functions/test-tangle/common.ts @@ -28,7 +28,7 @@ export const addValidatedAddress = async (network: Network, member: string) => { const walletService = await getWallet(network); const address = await walletService.getNewIotaAddressDetails(); await build5Db() - .doc(`${COL.MEMBER}/${member}`) + .doc(COL.MEMBER, member) .update({ [`validatedAddress.${network}`]: address.bech32 }); return address; }; @@ -36,8 +36,8 @@ export const addValidatedAddress = async (network: Network, member: string) => { export const awaitTransactionConfirmationsForToken = async (token: string) => { const query = build5Db() .collection(COL.TRANSACTION) - .where('payload.token', '==', token) - .where('type', 'in', [TransactionType.CREDIT, TransactionType.BILL_PAYMENT]); + .where('payload_token', '==', token) + .whereIn('type', [TransactionType.CREDIT, TransactionType.BILL_PAYMENT]); await wait(async () => { const transactions = (await query.get()).map((d) => d); const hasErrors = transactions.filter((t) => { @@ -88,7 +88,7 @@ export const getTangleOrder = async (network: Network) => { }, linkedTransactions: [], }; - await build5Db().doc(`${COL.TRANSACTION}/${order.uid}`).create(order); + await build5Db().doc(COL.TRANSACTION, order.uid).create(order); tangleOrders[network] = order; return tangleOrders[network]; }; diff --git a/packages/functions/test-tangle/faucet.ts b/packages/functions/test-tangle/faucet.ts index ef8b594159..986a247bb0 100644 --- a/packages/functions/test-tangle/faucet.ts +++ b/packages/functions/test-tangle/faucet.ts @@ -17,8 +17,8 @@ export const getSenderAddress = async (network: Network, amountNeeded: number) = export const requestFundsFromFaucet = async ( network: Network, - targetBech32: string, - amount: number, + targetBech32: string | undefined, + amount: number | undefined, expiresAt?: Timestamp, ) => { const wallet = await getWallet(network); @@ -26,7 +26,7 @@ export const requestFundsFromFaucet = async ( const faucetAddress = await wallet.getIotaAddressDetails(getFaucetMnemonic(network)); try { await MnemonicService.store(faucetAddress.bech32, faucetAddress.mnemonic, network); - const blockId = await wallet.send(faucetAddress, targetBech32, amount, { + const blockId = await wallet.send(faucetAddress, targetBech32!, amount!, { expiration: expiresAt ? { expiresAt, returnAddressBech32: faucetAddress.bech32 } : undefined, diff --git a/packages/functions/test-tangle/metadata-nft/Helper.ts b/packages/functions/test-tangle/metadata-nft/Helper.ts index ed29345196..76710cafdf 100644 --- a/packages/functions/test-tangle/metadata-nft/Helper.ts +++ b/packages/functions/test-tangle/metadata-nft/Helper.ts @@ -1,19 +1,9 @@ import { build5Db } from '@build-5/database'; -import { - COL, - MIN_IOTA_AMOUNT, - Member, - Network, - Space, - Token, - Transaction, -} from '@build-5/interfaces'; +import { COL, MIN_IOTA_AMOUNT, Network, Space, Token, Transaction } from '@build-5/interfaces'; 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 } from '../../test/controls/common'; -import { getWallet } from '../../test/set-up'; +import { getWallet, testEnv } from '../../test/set-up'; import { getTangleOrder } from '../common'; import { requestFundsFromFaucet } from '../faucet'; @@ -25,19 +15,17 @@ export class Helper { public member: string = ''; public memberAddress: AddressDetails = {} as any; public walletService: Wallet = {} as any; - public walletSpy: any; public tangleOrder: Transaction = {} as any; public beforeEach = async (network: Network) => { this.network = network; this.walletService = await getWallet(this.network); - this.walletSpy = jest.spyOn(wallet, 'decodeAuth'); - this.member = await createMember(this.walletSpy); + this.member = await testEnv.createMember(); this.tangleOrder = await getTangleOrder(this.network); - const memberData = await build5Db().doc(`${COL.MEMBER}/${this.member}`).get(); + const memberData = await build5Db().doc(COL.MEMBER, this.member).get(); const memberAddress = getAddress(memberData, this.network); this.memberAddress = await this.walletService.getAddressDetails(memberAddress); await requestFundsFromFaucet(this.network, memberAddress, 10 * MIN_IOTA_AMOUNT); diff --git a/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_1.spec.ts b/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_1.spec.ts index fe3db995fd..98aa4a0ef4 100644 --- a/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_1.spec.ts +++ b/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_1.spec.ts @@ -1,13 +1,9 @@ import { build5Db } from '@build-5/database'; import { COL, - Collection, MIN_IOTA_AMOUNT, Network, - Nft, - Space, TangleRequestType, - Transaction, TransactionType, } from '@build-5/interfaces'; import { BasicOutput, RegularTransactionEssence, TransactionPayload } from '@iota/sdk'; @@ -21,7 +17,7 @@ describe('Metadata nft', () => { it('Should mint metada nft', async () => { await helper.beforeEach(Network.RMS); - const metadata = { mytest: 'mytest', asd: 'asdasdasd' }; + const metadata = { mytest: 'mytest', name: 'asdasdasd' }; const blockId = await helper.walletService.send( helper.memberAddress, helper.tangleOrder.payload.targetAddress!, @@ -55,10 +51,10 @@ describe('Metadata nft', () => { .where('member', '==', helper.member) .where('type', '==', TransactionType.CREDIT); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); - const credit = (await creditQuery.get())[0]; + const credit = (await creditQuery.get())[0]; const block = await helper.walletService.client.getBlock( credit.payload.walletReference!.chainReference!, ); @@ -67,11 +63,9 @@ describe('Metadata nft', () => { const outputMetadata = getOutputMetadata(output); const nftQuery = build5Db().collection(COL.NFT).where('owner', '==', helper.member); - const nft = (await nftQuery.get())[0]; - const collection = await build5Db() - .doc(`${COL.COLLECTION}/${nft.collection}`) - .get(); - const space = await build5Db().doc(`${COL.SPACE}/${nft.space}`).get(); + const nft = (await nftQuery.get())[0]; + const collection = await build5Db().doc(COL.COLLECTION, nft.collection).get(); + const space = await build5Db().doc(COL.SPACE, nft.space).get(); expect(outputMetadata).toEqual({ nftId: nft!.mintingData!.nftId, collectionId: collection!.mintingData!.nftId, diff --git a/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_10.spec.ts b/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_10.spec.ts index 3c4534f73d..43a75028be 100644 --- a/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_10.spec.ts +++ b/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_10.spec.ts @@ -1,10 +1,16 @@ import { build5Db } from '@build-5/database'; -import { COL, Collection, Network, Nft, Transaction, TransactionType } from '@build-5/interfaces'; +import { + COL, + Collection, + Network, + Transaction, + TransactionType, + WEN_FUNC, +} from '@build-5/interfaces'; import { NftOutput } from '@iota/sdk'; -import { mintMetadataNft } from '../../src/runtime/firebase/nft'; import { getOutputMetadata } from '../../src/utils/basic-output.utils'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -15,63 +21,63 @@ describe('Metadata nft', () => { const network = Network.RMS; await h.beforeEach(network); - const metadata = { mytest: 'mytest', asd: 'asdasdasd' }; + const metadata = { mytest: 'mytest', name: 'asdasdasd' }; - mockWalletReturnValue(h.walletSpy, h.member, { network, metadata }); - const order: Transaction = await testEnv.wrap(mintMetadataNft)({}); + mockWalletReturnValue(h.member, { network, metadata }); + const order = await testEnv.wrap(WEN_FUNC.mintMetadataNft); await requestFundsFromFaucet(network, order.payload.targetAddress!, order.payload.amount!); - let query = build5Db() + const typeQuery = build5Db() .collection(COL.TRANSACTION) .where('member', '==', h.member) .where('type', '==', TransactionType.METADATA_NFT); await wait(async () => { - const snap = await query.get(); + const snap = await typeQuery.get(); return ( snap.length === 3 && snap.reduce((acc, act) => (acc && act.payload?.walletReference?.confirmed) || false, true) ); }); - query = build5Db() + let addressQuery = build5Db() .collection(COL.NFT) - .where('mintingData.address', '==', order.payload.targetAddress); + .where('mintingData_address', '==', order.payload.targetAddress); await wait(async () => { - const nfts = await query.get(); + const nfts = await addressQuery.get(); return nfts.length === 1; }); - const nft = (await query.get())[0]; + const nft = (await addressQuery.get())[0]; const client = h.walletService.client; let nftOutputId = await client.nftOutputId(nft.mintingData!.nftId!); let nftOutput = (await client.getOutput(nftOutputId)).output as NftOutput; let outputMetadata = getOutputMetadata(nftOutput); expect(outputMetadata).toEqual(metadata); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${nft.collection}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, nft.collection); const collection = await collectionDocRef.get(); - mockWalletReturnValue(h.walletSpy, h.member, { + mockWalletReturnValue(h.member, { network, metadata: { name: 'SecondNft' }, collectionId: collection.mintingData?.nftId!, }); - const secondOrder: Transaction = await testEnv.wrap(mintMetadataNft)({}); + const secondOrder = await testEnv.wrap(WEN_FUNC.mintMetadataNft); await requestFundsFromFaucet( network, secondOrder.payload.targetAddress!, secondOrder.payload.amount!, ); - query = build5Db() + addressQuery = build5Db() .collection(COL.NFT) - .where('mintingData.address', '==', secondOrder.payload.targetAddress); + .where('mintingData_address', '==', secondOrder.payload.targetAddress); await wait(async () => { - const nfts = await query.get(); + const nfts = await addressQuery.get(); return nfts.length === 1; }); - const secondNft = (await query.get())[0]; + const secondNft = (await addressQuery.get())[0]; expect(nft.collection).toBe(secondNft.collection); }); diff --git a/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_1_b.spec.ts b/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_1_b.spec.ts index f70a6ab353..4d1ac98c75 100644 --- a/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_1_b.spec.ts +++ b/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_1_b.spec.ts @@ -1,13 +1,9 @@ import { build5Db } from '@build-5/database'; import { COL, - Collection, MIN_IOTA_AMOUNT, Network, - Nft, - Space, TangleRequestType, - Transaction, TransactionType, } from '@build-5/interfaces'; import { BasicOutput, RegularTransactionEssence, TransactionPayload } from '@iota/sdk'; @@ -21,7 +17,7 @@ describe('Metadata nft', () => { it('Should mint metada nft', async () => { await helper.beforeEach(Network.ATOI); - const metadata = { mytest: 'mytest', asd: 'asdasdasd' }; + const metadata = { mytest: 'mytest', name: 'asdasdasd' }; const blockId = await helper.walletService.send( helper.memberAddress, helper.tangleOrder.payload.targetAddress!, @@ -55,10 +51,10 @@ describe('Metadata nft', () => { .where('member', '==', helper.member) .where('type', '==', TransactionType.CREDIT); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); - const credit = (await creditQuery.get())[0]; + const credit = (await creditQuery.get())[0]; const block = await helper.walletService.client.getBlock( credit.payload.walletReference!.chainReference!, ); @@ -67,11 +63,9 @@ describe('Metadata nft', () => { const outputMetadata = getOutputMetadata(output); const nftQuery = build5Db().collection(COL.NFT).where('owner', '==', helper.member); - const nft = (await nftQuery.get())[0]; - const collection = await build5Db() - .doc(`${COL.COLLECTION}/${nft.collection}`) - .get(); - const space = await build5Db().doc(`${COL.SPACE}/${nft.space}`).get(); + const nft = (await nftQuery.get())[0]; + const collection = await build5Db().doc(COL.COLLECTION, nft.collection).get(); + const space = await build5Db().doc(COL.SPACE, nft.space).get(); expect(outputMetadata).toEqual({ nftId: nft!.mintingData!.nftId, collectionId: collection!.mintingData!.nftId, diff --git a/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_2.spec.ts b/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_2.spec.ts index 16a538559e..91c75266bd 100644 --- a/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_2.spec.ts +++ b/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_2.spec.ts @@ -1,12 +1,10 @@ import { build5Db } from '@build-5/database'; import { COL, - Collection, MIN_IOTA_AMOUNT, Network, Space, TangleRequestType, - Transaction, TransactionType, } from '@build-5/interfaces'; import { BasicOutput, RegularTransactionEssence, TransactionPayload } from '@iota/sdk'; @@ -23,7 +21,7 @@ describe('Metadata nft', () => { 'Should mint metada nft, mint new one for same collection', async (network: Network) => { await helper.beforeEach(network); - const metadata = { mytest: 'mytest', asd: 'asdasdasd' }; + const metadata = { mytest: 'mytest', name: 'asdasdasd' }; await helper.walletService.send( helper.memberAddress, helper.tangleOrder.payload.targetAddress!, @@ -57,14 +55,14 @@ describe('Metadata nft', () => { .where('member', '==', helper.member) .where('type', '==', TransactionType.CREDIT); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); - const credit = (await creditQuery.get())[0]; + const credit = (await creditQuery.get())[0]; - const space = await build5Db().doc(`${COL.SPACE}/${credit.space}`).get(); + const space = await build5Db().doc(COL.SPACE, credit.space!).get(); const collectionQuery = build5Db().collection(COL.COLLECTION).where('space', '==', space.uid); - const collection = (await collectionQuery.get())[0]; + const collection = (await collectionQuery.get())[0]; await helper.walletService.send( helper.memberAddress, @@ -87,13 +85,13 @@ describe('Metadata nft', () => { ); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return ( snap.length === 2 && snap.reduce((acc, act) => acc && (act.payload?.walletReference?.confirmed || false), true) ); }); - const credits = await creditQuery.get(); + const credits = await creditQuery.get(); const credit1Meta = await getMetadata( helper.walletService, credits[0].payload.walletReference!.chainReference!, diff --git a/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_3.spec.ts b/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_3.spec.ts index a99119f206..cff3b8bb1b 100644 --- a/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_3.spec.ts +++ b/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_3.spec.ts @@ -3,9 +3,7 @@ import { COL, MIN_IOTA_AMOUNT, Network, - Nft, TangleRequestType, - Transaction, TransactionType, } from '@build-5/interfaces'; import { NftOutput } from '@iota/sdk'; @@ -19,7 +17,7 @@ describe('Metadata nft', () => { it('Should mint metada nft then update metadata', async () => { await helper.beforeEach(Network.RMS); - const metadata = { mytest: 'mytest', asd: 'asdasdasd' }; + const metadata = { mytest: 'mytest', name: 'asdasdasd' }; await helper.walletService.send( helper.memberAddress, helper.tangleOrder.payload.targetAddress!, @@ -53,12 +51,12 @@ describe('Metadata nft', () => { .where('member', '==', helper.member) .where('type', '==', TransactionType.CREDIT); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); const nftQuery = build5Db().collection(COL.NFT).where('owner', '==', helper.member); - const nft = (await nftQuery.get())[0]; + const nft = (await nftQuery.get())[0]; await helper.walletService.send( helper.memberAddress, @@ -68,7 +66,7 @@ describe('Metadata nft', () => { customMetadata: { request: { requestType: TangleRequestType.MINT_METADATA_NFT, - metadata: { asd: 'hello' }, + metadata: { name: 'hello' }, nftId: nft.mintingData?.nftId, }, }, @@ -81,7 +79,7 @@ describe('Metadata nft', () => { ); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return ( snap.length === 2 && snap.reduce((acc, act) => acc && (act.payload?.walletReference?.confirmed || false), true) @@ -91,7 +89,7 @@ describe('Metadata nft', () => { let nftOutputId = await helper.walletService.client.nftOutputId(nft.mintingData?.nftId!); let nftOutput = (await helper.walletService.client.getOutput(nftOutputId)).output as NftOutput; let meta = getOutputMetadata(nftOutput); - expect(meta).toEqual({ asd: 'hello' }); + expect(meta).toEqual({ name: 'hello' }); await helper.walletService.send( helper.memberAddress, @@ -101,7 +99,7 @@ describe('Metadata nft', () => { customMetadata: { request: { requestType: TangleRequestType.MINT_METADATA_NFT, - metadata: { asd: 'helloasdasd2' }, + metadata: { name: 'helloasdasd2' }, nftId: nft.mintingData?.nftId, }, }, @@ -114,7 +112,7 @@ describe('Metadata nft', () => { ); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return ( snap.length === 3 && snap.reduce((acc, act) => acc && (act.payload?.walletReference?.confirmed || false), true) @@ -124,6 +122,6 @@ describe('Metadata nft', () => { nftOutputId = await helper.walletService.client.nftOutputId(nft.mintingData?.nftId!); nftOutput = (await helper.walletService.client.getOutput(nftOutputId)).output as NftOutput; meta = getOutputMetadata(nftOutput); - expect(meta).toEqual({ asd: 'helloasdasd2' }); + expect(meta).toEqual({ name: 'helloasdasd2' }); }); }); diff --git a/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_3_b.spec.ts b/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_3_b.spec.ts index 8bcd35639b..82c895b11e 100644 --- a/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_3_b.spec.ts +++ b/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_3_b.spec.ts @@ -3,9 +3,7 @@ import { COL, MIN_IOTA_AMOUNT, Network, - Nft, TangleRequestType, - Transaction, TransactionType, } from '@build-5/interfaces'; import { NftOutput } from '@iota/sdk'; @@ -19,7 +17,7 @@ describe('Metadata nft', () => { it('Should mint metada nft then update metadata', async () => { await helper.beforeEach(Network.ATOI); - const metadata = { mytest: 'mytest', asd: 'asdasdasd' }; + const metadata = { mytest: 'mytest', name: 'asdasdasd' }; await helper.walletService.send( helper.memberAddress, helper.tangleOrder.payload.targetAddress!, @@ -53,12 +51,12 @@ describe('Metadata nft', () => { .where('member', '==', helper.member) .where('type', '==', TransactionType.CREDIT); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); const nftQuery = build5Db().collection(COL.NFT).where('owner', '==', helper.member); - const nft = (await nftQuery.get())[0]; + const nft = (await nftQuery.get())[0]; await helper.walletService.send( helper.memberAddress, @@ -68,7 +66,7 @@ describe('Metadata nft', () => { customMetadata: { request: { requestType: TangleRequestType.MINT_METADATA_NFT, - metadata: { asd: 'hello' }, + metadata: { name: 'hello' }, nftId: nft.mintingData?.nftId, }, }, @@ -81,7 +79,7 @@ describe('Metadata nft', () => { ); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return ( snap.length === 2 && snap.reduce((acc, act) => acc && (act.payload?.walletReference?.confirmed || false), true) @@ -91,7 +89,7 @@ describe('Metadata nft', () => { let nftOutputId = await helper.walletService.client.nftOutputId(nft.mintingData?.nftId!); let nftOutput = (await helper.walletService.client.getOutput(nftOutputId)).output as NftOutput; let meta = getOutputMetadata(nftOutput); - expect(meta).toEqual({ asd: 'hello' }); + expect(meta).toEqual({ name: 'hello' }); await helper.walletService.send( helper.memberAddress, @@ -101,7 +99,7 @@ describe('Metadata nft', () => { customMetadata: { request: { requestType: TangleRequestType.MINT_METADATA_NFT, - metadata: { asd: 'helloasdasd2' }, + metadata: { name: 'helloasdasd2' }, nftId: nft.mintingData?.nftId, }, }, @@ -114,7 +112,7 @@ describe('Metadata nft', () => { ); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return ( snap.length === 3 && snap.reduce((acc, act) => acc && (act.payload?.walletReference?.confirmed || false), true) @@ -124,6 +122,6 @@ describe('Metadata nft', () => { nftOutputId = await helper.walletService.client.nftOutputId(nft.mintingData?.nftId!); nftOutput = (await helper.walletService.client.getOutput(nftOutputId)).output as NftOutput; meta = getOutputMetadata(nftOutput); - expect(meta).toEqual({ asd: 'helloasdasd2' }); + expect(meta).toEqual({ name: 'helloasdasd2' }); }); }); diff --git a/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_4.spec.ts b/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_4.spec.ts index a21debf61a..fb31facc3e 100644 --- a/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_4.spec.ts +++ b/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_4.spec.ts @@ -1,13 +1,10 @@ import { build5Db } from '@build-5/database'; import { COL, - Collection, MIN_IOTA_AMOUNT, Network, - Nft, Space, TangleRequestType, - Transaction, TransactionType, } from '@build-5/interfaces'; import { MnemonicService } from '../../src/services/wallet/mnemonic'; @@ -22,7 +19,7 @@ describe('Metadata nft', () => { async (network: Network) => { await helper.beforeEach(network); - const metadata = { mytest: 'mytest', asd: 'asdasdasd' }; + const metadata = { mytest: 'mytest', name: 'asdasdasd' }; await helper.walletService.send( helper.memberAddress, helper.tangleOrder.payload.targetAddress!, @@ -56,12 +53,12 @@ describe('Metadata nft', () => { .where('member', '==', helper.member) .where('type', '==', TransactionType.CREDIT); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); - const credit = (await creditQuery.get())[0]; + const credit = (await creditQuery.get())[0]; - const space = await build5Db().doc(`${COL.SPACE}/${credit.space}`).get(); + const space = await build5Db().doc(COL.SPACE, credit.space!).get(); await helper.walletService.send( helper.memberAddress, @@ -84,24 +81,21 @@ describe('Metadata nft', () => { ); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return ( snap.length === 2 && snap.reduce((acc, act) => acc && (act.payload?.walletReference?.confirmed || false), true) ); }); - const nfts = await build5Db() - .collection(COL.NFT) - .where('owner', '==', helper.member) - .get(); + const nfts = await build5Db().collection(COL.NFT).where('owner', '==', helper.member).get(); expect(nfts[0].collection).not.toBe(nfts[1].collection); expect(nfts[0].space).toBe(nfts[1].space); const collections = await build5Db() .collection(COL.COLLECTION) .where('space', '==', space.uid) - .get(); + .get(); expect(collections.length).toBe(2); }, ); diff --git a/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_5.spec.ts b/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_5.spec.ts index c533d56d27..6f36091130 100644 --- a/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_5.spec.ts +++ b/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_5.spec.ts @@ -1,12 +1,10 @@ import { build5Db } from '@build-5/database'; import { COL, - Collection, MIN_IOTA_AMOUNT, Network, Space, TangleRequestType, - Transaction, TransactionType, } from '@build-5/interfaces'; import { MnemonicService } from '../../src/services/wallet/mnemonic'; @@ -19,7 +17,7 @@ describe('Metadata nft', () => { it('Should mint metada nft, mint two new one for same collection&alias, in parallel', async () => { await helper.beforeEach(Network.RMS); - const metadata = { mytest: 'mytest', asd: 'asdasdasd' }; + const metadata = { mytest: 'mytest', name: 'asdasdasd' }; await helper.walletService.send( helper.memberAddress, helper.tangleOrder.payload.targetAddress!, @@ -53,14 +51,14 @@ describe('Metadata nft', () => { .where('member', '==', helper.member) .where('type', '==', TransactionType.CREDIT); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); - const credit = (await creditQuery.get())[0]; + const credit = (await creditQuery.get())[0]; - const space = await build5Db().doc(`${COL.SPACE}/${credit.space}`).get(); + const space = await build5Db().doc(COL.SPACE, credit.space!).get(); const collection = ( - await build5Db().collection(COL.COLLECTION).where('space', '==', space.uid).get() + await build5Db().collection(COL.COLLECTION).where('space', '==', space.uid).get() )[0]; await helper.walletService.sendToMany( @@ -100,7 +98,7 @@ describe('Metadata nft', () => { ); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return ( snap.length === 3 && snap.reduce((acc, act) => acc && (act.payload?.walletReference?.confirmed || false), true) diff --git a/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_5_b.spec.ts b/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_5_b.spec.ts index 757b9ae910..5400991cde 100644 --- a/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_5_b.spec.ts +++ b/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_5_b.spec.ts @@ -1,12 +1,10 @@ import { build5Db } from '@build-5/database'; import { COL, - Collection, MIN_IOTA_AMOUNT, Network, Space, TangleRequestType, - Transaction, TransactionType, } from '@build-5/interfaces'; import { MnemonicService } from '../../src/services/wallet/mnemonic'; @@ -19,7 +17,7 @@ describe('Metadata nft', () => { it('Should mint metada nft, mint two new one for same collection&alias, in parallel', async () => { await helper.beforeEach(Network.ATOI); - const metadata = { mytest: 'mytest', asd: 'asdasdasd' }; + const metadata = { mytest: 'mytest', name: 'asdasdasd' }; await helper.walletService.send( helper.memberAddress, helper.tangleOrder.payload.targetAddress!, @@ -53,14 +51,14 @@ describe('Metadata nft', () => { .where('member', '==', helper.member) .where('type', '==', TransactionType.CREDIT); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); - const credit = (await creditQuery.get())[0]; + const credit = (await creditQuery.get())[0]; - const space = await build5Db().doc(`${COL.SPACE}/${credit.space}`).get(); + const space = await build5Db().doc(COL.SPACE, credit.space!).get(); const collection = ( - await build5Db().collection(COL.COLLECTION).where('space', '==', space.uid).get() + await build5Db().collection(COL.COLLECTION).where('space', '==', space.uid).get() )[0]; await helper.walletService.sendToMany( @@ -100,7 +98,7 @@ describe('Metadata nft', () => { ); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return ( snap.length === 3 && snap.reduce((acc, act) => acc && (act.payload?.walletReference?.confirmed || false), true) diff --git a/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_6.spec.ts b/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_6.spec.ts index cd834e32bd..cb6f9f569c 100644 --- a/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_6.spec.ts +++ b/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_6.spec.ts @@ -4,7 +4,6 @@ import { MIN_IOTA_AMOUNT, Network, TangleRequestType, - Transaction, TransactionType, WenError, } from '@build-5/interfaces'; @@ -20,7 +19,7 @@ describe('Metadata nft', () => { 'Should throw invalid nft id on update', async (network: Network) => { await helper.beforeEach(network); - const metadata = { mytest: 'mytest', asd: 'asdasdasd' }; + const metadata = { mytest: 'mytest', name: 'asdasdasd' }; await helper.walletService.send( helper.memberAddress, helper.tangleOrder.payload.targetAddress!, @@ -54,7 +53,7 @@ describe('Metadata nft', () => { .where('member', '==', helper.member) .where('type', '==', TransactionType.CREDIT); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); @@ -66,7 +65,7 @@ describe('Metadata nft', () => { customMetadata: { request: { requestType: TangleRequestType.MINT_METADATA_NFT, - metadata: { asd: 'hello' }, + metadata: { name: 'hello' }, nftId: getRandomEthAddress(), }, }, @@ -83,10 +82,10 @@ describe('Metadata nft', () => { .where('member', '==', helper.member) .where('type', '==', TransactionType.CREDIT_TANGLE_REQUEST); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); expect((snap[0].payload.response as any).message).toBe(WenError.invalid_nft_id.key); }, ); diff --git a/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_7.spec.ts b/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_7.spec.ts index 6a57aa8e16..271d499807 100644 --- a/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_7.spec.ts +++ b/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_7.spec.ts @@ -4,7 +4,6 @@ import { MIN_IOTA_AMOUNT, Network, TangleRequestType, - Transaction, TransactionType, WenError, } from '@build-5/interfaces'; @@ -21,7 +20,7 @@ describe('Metadata nft', () => { async (network: Network) => { await helper.beforeEach(network); - const metadata = { mytest: 'mytest', asd: 'asdasdasd' }; + const metadata = { mytest: 'mytest', name: 'asdasdasd' }; await helper.walletService.send( helper.memberAddress, helper.tangleOrder.payload.targetAddress!, @@ -55,7 +54,7 @@ describe('Metadata nft', () => { .where('member', '==', helper.member) .where('type', '==', TransactionType.CREDIT); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); @@ -78,10 +77,10 @@ describe('Metadata nft', () => { .where('member', '==', helper.member) .where('type', '==', TransactionType.CREDIT_TANGLE_REQUEST); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); expect((snap[0].payload.response as any).message).toBe(WenError.invalid_collection_id.key); }, ); diff --git a/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_8.spec.ts b/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_8.spec.ts index c31ad6270b..824dc50e1e 100644 --- a/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_8.spec.ts +++ b/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_8.spec.ts @@ -1,10 +1,9 @@ import { build5Db } from '@build-5/database'; -import { COL, Network, Nft, Transaction, TransactionType } from '@build-5/interfaces'; +import { COL, Network, Transaction, TransactionType, WEN_FUNC } from '@build-5/interfaces'; import { NftOutput } from '@iota/sdk'; -import { mintMetadataNft } from '../../src/runtime/firebase/nft'; import { getOutputMetadata } from '../../src/utils/basic-output.utils'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -15,34 +14,34 @@ describe('Metadata nft', () => { const network = Network.RMS; await h.beforeEach(network); - const metadata = { mytest: 'mytest', asd: 'asdasdasd' }; + const metadata = { mytest: 'mytest', name: 'asdasdasd' }; - mockWalletReturnValue(h.walletSpy, h.member, { network, metadata }); - const order: Transaction = await testEnv.wrap(mintMetadataNft)({}); + mockWalletReturnValue(h.member, { network, metadata }); + const order = await testEnv.wrap(WEN_FUNC.mintMetadataNft); await requestFundsFromFaucet(network, order.payload.targetAddress!, order.payload.amount!); - let query = build5Db() + const typeQuery = build5Db() .collection(COL.TRANSACTION) .where('member', '==', h.member) .where('type', '==', TransactionType.METADATA_NFT); await wait(async () => { - const snap = await query.get(); + const snap = await typeQuery.get(); return ( snap.length === 3 && snap.reduce((acc, act) => (acc && act.payload?.walletReference?.confirmed) || false, true) ); }); - query = build5Db() + const addressQuery = build5Db() .collection(COL.NFT) - .where('mintingData.address', '==', order.payload.targetAddress); + .where('mintingData_address', '==', order.payload.targetAddress); await wait(async () => { - const nfts = await query.get(); + const nfts = await addressQuery.get(); return nfts.length === 1; }); - const nft = (await query.get())[0]; + const nft = (await addressQuery.get())[0]; const client = h.walletService.client; const nftOutputId = await client.nftOutputId(nft.mintingData!.nftId!); const nftOutput = (await client.getOutput(nftOutputId)).output as NftOutput; diff --git a/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_9.spec.ts b/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_9.spec.ts index 89efa85fbf..3a9055d273 100644 --- a/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_9.spec.ts +++ b/packages/functions/test-tangle/metadata-nft/mint-metadata-nft_9.spec.ts @@ -2,16 +2,15 @@ import { build5Db } from '@build-5/database'; import { COL, Network, - Nft, Transaction, TransactionPayloadType, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; import { NftOutput } from '@iota/sdk'; -import { mintMetadataNft } from '../../src/runtime/firebase/nft'; import { getOutputMetadata } from '../../src/utils/basic-output.utils'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -22,65 +21,65 @@ describe('Metadata nft', () => { const network = Network.RMS; await h.beforeEach(network); - const metadata = { mytest: 'mytest', asd: 'asdasdasd' }; + const metadata = { mytest: 'mytest', sayhi: 'asdasdasd' }; - mockWalletReturnValue(h.walletSpy, h.member, { network, metadata }); - const order: Transaction = await testEnv.wrap(mintMetadataNft)({}); + mockWalletReturnValue(h.member, { network, metadata }); + const order = await testEnv.wrap(WEN_FUNC.mintMetadataNft); await requestFundsFromFaucet(network, order.payload.targetAddress!, order.payload.amount!); - let query = build5Db() + const typeQuery = build5Db() .collection(COL.TRANSACTION) .where('member', '==', h.member) .where('type', '==', TransactionType.METADATA_NFT); await wait(async () => { - const snap = await query.get(); + const snap = await typeQuery.get(); return ( snap.length === 3 && snap.reduce((acc, act) => (acc && act.payload?.walletReference?.confirmed) || false, true) ); }); - query = build5Db() + const addressQuery = build5Db() .collection(COL.NFT) - .where('mintingData.address', '==', order.payload.targetAddress); + .where('mintingData_address', '==', order.payload.targetAddress); await wait(async () => { - const nfts = await query.get(); + const nfts = await addressQuery.get(); return nfts.length === 1; }); - const nft = (await query.get())[0]; + const nft = (await addressQuery.get())[0]; const client = h.walletService.client; let nftOutputId = await client.nftOutputId(nft.mintingData!.nftId!); let nftOutput = (await client.getOutput(nftOutputId)).output as NftOutput; let outputMetadata = getOutputMetadata(nftOutput); expect(outputMetadata).toEqual(metadata); - mockWalletReturnValue(h.walletSpy, h.member, { + mockWalletReturnValue(h.member, { network, - metadata: { asd: 'hello' }, + metadata: { sayhi: 'hello' }, nftId: nft.mintingData?.nftId, }); - const updateOrder: Transaction = await testEnv.wrap(mintMetadataNft)({}); + const updateOrder = await testEnv.wrap(WEN_FUNC.mintMetadataNft); await requestFundsFromFaucet( network, updateOrder.payload.targetAddress!, updateOrder.payload.amount!, ); - query = build5Db() + const typesQuery = build5Db() .collection(COL.TRANSACTION) .where('member', '==', h.member) .where('type', '==', TransactionType.METADATA_NFT) - .where('payload.type', '==', TransactionPayloadType.UPDATE_MINTED_NFT); + .where('payload_type', '==', TransactionPayloadType.UPDATE_MINTED_NFT); await wait(async () => { - const snap = await query.get(); + const snap = await typesQuery.get(); return snap.length === 1 && snap[0].payload?.walletReference?.confirmed; }); nftOutputId = await client.nftOutputId(nft.mintingData!.nftId!); nftOutput = (await client.getOutput(nftOutputId)).output as NftOutput; outputMetadata = getOutputMetadata(nftOutput); - expect(outputMetadata).toEqual({ asd: 'hello' }); + expect(outputMetadata).toEqual({ sayhi: 'hello' }); }); }); diff --git a/packages/functions/test-tangle/minted-nft-trading/Helper.ts b/packages/functions/test-tangle/minted-nft-trading/Helper.ts index 9f6b8f95cc..4126b1449a 100644 --- a/packages/functions/test-tangle/minted-nft-trading/Helper.ts +++ b/packages/functions/test-tangle/minted-nft-trading/Helper.ts @@ -2,8 +2,8 @@ import { build5Db } from '@build-5/database'; import { Access, - Categories, COL, + Categories, Collection, CollectionStatus, CollectionType, @@ -18,82 +18,72 @@ import { Transaction, TransactionType, UnsoldMintingOptions, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { createCollection, mintCollection } from '../../src/runtime/firebase/collection/index'; -import { createNft, orderNft, setForSaleNft } from '../../src/runtime/firebase/nft/index'; import { NftWallet } from '../../src/services/wallet/NftWallet'; import { Wallet } from '../../src/services/wallet/wallet'; import { AddressDetails } from '../../src/services/wallet/wallet.service'; import { serverTime } from '../../src/utils/dateTime.utils'; import * as wallet from '../../src/utils/wallet.utils'; -import { - createMember as createMemberTest, - createSpace, - mockWalletReturnValue, - submitMilestoneFunc, - wait, -} from '../../test/controls/common'; -import { getWallet, MEDIA, testEnv } from '../../test/set-up'; +import { submitMilestoneFunc, wait } from '../../test/controls/common'; +import { MEDIA, getWallet, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { getTangleOrder } from '../common'; import { requestFundsFromFaucet } from '../faucet'; export class Helper { - public walletSpy: any | undefined; public network = Network.RMS; - public collection: string | undefined; - public guardian: string | undefined; - public space: Space | undefined; - public royaltySpace: Space | undefined; - public member: string | undefined; - public walletService: Wallet | undefined; - public nftWallet: NftWallet | undefined; - public nft: Nft | undefined; + public collection = ''; + public guardian = ''; + public space: Space = {} as any; + public royaltySpace: Space = {} as any; + public member = ''; + public walletService: Wallet = {} as any; + public nftWallet: NftWallet = {} as any; + public nft: Nft = {} as any; public tangleOrder: Transaction = {} as any; public beforeEach = async (network: Network, collectionType = CollectionType.CLASSIC) => { this.network = network; - this.walletSpy = jest.spyOn(wallet, 'decodeAuth'); this.walletService = await getWallet(this.network); this.nftWallet = new NftWallet(this.walletService); this.tangleOrder = await getTangleOrder(network); - this.guardian = await createMemberTest(this.walletSpy); - this.member = await createMemberTest(this.walletSpy); - this.space = await createSpace(this.walletSpy, this.guardian); - this.royaltySpace = await createSpace(this.walletSpy, this.guardian); + this.guardian = await testEnv.createMember(); + this.member = await testEnv.createMember(); + this.space = await testEnv.createSpace(this.guardian); + this.royaltySpace = await testEnv.createSpace(this.guardian); mockWalletReturnValue( - this.walletSpy, this.guardian, this.createDummyCollection(this.space.uid, this.royaltySpace.uid, collectionType), ); - this.collection = (await testEnv.wrap(createCollection)({})).uid; + this.collection = (await testEnv.wrap(WEN_FUNC.createCollection)).uid; - await build5Db().doc(`${COL.COLLECTION}/${this.collection}`).update({ approved: true }); + await build5Db().doc(COL.COLLECTION, this.collection).update({ approved: true }); }; public mintCollection = async (expiresAt?: Timestamp) => { - mockWalletReturnValue(this.walletSpy, this.guardian!, { + mockWalletReturnValue(this.guardian!, { collection: this.collection, network: this.network, unsoldMintingOptions: UnsoldMintingOptions.KEEP_PRICE, }); - const collectionMintOrder = await testEnv.wrap(mintCollection)({}); + const collectionMintOrder = await testEnv.wrap(WEN_FUNC.mintCollection); await requestFundsFromFaucet( this.network!, collectionMintOrder.payload.targetAddress, collectionMintOrder.payload.amount, expiresAt, ); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${this.collection}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, this.collection); await wait(async () => { const data = await collectionDocRef.get(); return data.status === CollectionStatus.MINTED; }); - const nftDocRef = build5Db().doc(`${COL.NFT}/${this.nft?.uid}`); + const nftDocRef = build5Db().doc(COL.NFT, this.nft?.uid); this.nft = await nftDocRef.get(); }; @@ -102,37 +92,37 @@ export class Helper { delete nft.uid; delete nft.status; delete nft.placeholderNft; - mockWalletReturnValue(this.walletSpy, this.guardian!, nft); - nft = await testEnv.wrap(createNft)({}); + mockWalletReturnValue(this.guardian!, nft); + nft = await testEnv.wrap(WEN_FUNC.createNft); await build5Db() - .doc(`${COL.NFT}/${nft.uid}`) + .doc(COL.NFT, nft.uid) .update({ availableFrom: dayjs().subtract(1, 'h').toDate() }); if (shouldOrder) { - mockWalletReturnValue(this.walletSpy, this.guardian!, { + mockWalletReturnValue(this.guardian!, { collection: this.collection, nft: nft.uid, }); - const order = await testEnv.wrap(orderNft)({}); + const order = await testEnv.wrap(WEN_FUNC.orderNft); await submitMilestoneFunc(order); } - this.nft = await build5Db().doc(`${COL.NFT}/${nft.uid}`).get(); + this.nft = await build5Db().doc(COL.NFT, nft.uid).get(); return this.nft; }; public setAvailableForAuction = async (nft?: string) => { 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); + mockWalletReturnValue(this.guardian!, this.dummyAuctionData(uid)); + await testEnv.wrap(WEN_FUNC.setForSaleNft); + await wait(async () => (await build5Db().doc(COL.NFT, uid).get())?.available === 3); }; public setAvailableForSale = async (nftId?: string) => { const uid = nftId || this.nft!.uid; - mockWalletReturnValue(this.walletSpy, this.guardian!, this.dummySaleData(uid)); - await testEnv.wrap(setForSaleNft)({}); - await wait(async () => (await build5Db().doc(`${COL.NFT}/${uid}`).get())?.available === 1); + mockWalletReturnValue(this.guardian!, this.dummySaleData(uid)); + await testEnv.wrap(WEN_FUNC.setForSaleNft); + await wait(async () => (await build5Db().doc(COL.NFT, uid).get())?.available === 1); }; public createDummyCollection = (space: string, royaltiesSpace: string, type: CollectionType) => ({ @@ -197,7 +187,7 @@ export class Helper { nftId, }, }; - await build5Db().doc(`${COL.TRANSACTION}/${order.uid}`).create(order); + await build5Db().doc(COL.TRANSACTION, order.uid).create(order); return order.uid; }; } 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 8f398471d4..36e9567d61 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 @@ -1,25 +1,25 @@ import { build5Db } from '@build-5/database'; import { COL, - Member, MIN_IOTA_AMOUNT, + Member, Network, Nft, NftStatus, Transaction, TransactionType, + WEN_FUNC, WenError, } from '@build-5/interfaces'; import { NftOutput } from '@iota/sdk'; import dayjs from 'dayjs'; import { isEmpty } from 'lodash'; 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'; -import { expectThrow, mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { expectThrow, wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -33,15 +33,18 @@ describe('Minted nft trading', () => { await helper.setAvailableForAuction(); - const nftDocRef = build5Db().doc(`${COL.NFT}/${helper.nft!.uid}`); + 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.member!, { nft: helper.nft!.uid }); + await expectThrow( + testEnv.wrap(WEN_FUNC.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)({}); + mockWalletReturnValue(helper.member!, { nft: helper.nft!.uid }); + const bidOrder = await testEnv.wrap(WEN_FUNC.openBid); await requestFundsFromFaucet( Network.RMS, bidOrder.payload.targetAddress, @@ -54,7 +57,7 @@ describe('Minted nft trading', () => { return !isEmpty(helper.nft.auctionHighestBidder); }); - const bidOrder2 = await testEnv.wrap(openBid)({}); + const bidOrder2 = await testEnv.wrap(WEN_FUNC.openBid); await requestFundsFromFaucet( Network.RMS, bidOrder2.payload.targetAddress, @@ -69,15 +72,15 @@ describe('Minted nft trading', () => { await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.PAYMENT) - .where('payload.sourceTransaction', 'array-contains', bidOrder2.uid) - .get() + .where('payload_sourceTransaction', 'array-contains', bidOrder2.uid as any) + .get() )[0]; return nft.auctionHighestBidder === payment?.member; }); await build5Db() - .doc(`${COL.AUCTION}/${helper.nft!.auction}`) - .update({ auctionTo: dateToTimestamp(dayjs().subtract(1, 'm').toDate()) }); + .doc(COL.AUCTION, helper.nft!.auction!) + .update({ auctionTo: dayjs().subtract(1, 'm').toDate() }); await finalizeAuctions(); @@ -86,8 +89,8 @@ describe('Minted nft trading', () => { return nft.owner === helper.member; }); - mockWalletReturnValue(helper.walletSpy, helper.member!, { nft: helper.nft!.uid }); - await testEnv.wrap(withdrawNft)({}); + mockWalletReturnValue(helper.member!, { nft: helper.nft!.uid }); + await testEnv.wrap(WEN_FUNC.withdrawNft); helper.nft = await nftDocRef.get(); expect(helper.nft.status).toBe(NftStatus.WITHDRAWN); @@ -97,8 +100,8 @@ describe('Minted nft trading', () => { await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.WITHDRAW_NFT) - .where('payload.nft', '==', helper.nft!.uid) - .get() + .where('payload_nft', '==', helper.nft!.uid) + .get() )[0]; return transaction?.payload?.walletReference?.confirmed; }); @@ -109,7 +112,7 @@ describe('Minted nft trading', () => { ) ).output; const ownerAddress = Bech32AddressHelper.bech32FromUnlockConditions(output as NftOutput, 'rms'); - const member = await build5Db().doc(`${COL.MEMBER}/${helper.member}`).get(); + 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_10.spec.ts b/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_10.spec.ts index d46ed97972..6c375d66ca 100644 --- a/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_10.spec.ts +++ b/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_10.spec.ts @@ -3,7 +3,6 @@ import { COL, MIN_IOTA_AMOUNT, Network, - Nft, NftPurchaseTangleRequest, TangleRequestType, } from '@build-5/interfaces'; @@ -64,12 +63,12 @@ describe('Minted nft trading', () => { ); await MnemonicService.store(address.bech32, address.mnemonic, Network.RMS); - const nftDocRef1 = build5Db().doc(`${COL.NFT}/${nft1.uid}`); - const nftDocRef2 = build5Db().doc(`${COL.NFT}/${nft2.uid}`); + const nftDocRef1 = build5Db().doc(COL.NFT, nft1.uid); + const nftDocRef2 = build5Db().doc(COL.NFT, nft2.uid); await wait(async () => { - nft1 = (await nftDocRef1.get())!; - nft2 = (await nftDocRef2.get())!; + nft1 = (await nftDocRef1.get())!; + nft2 = (await nftDocRef2.get())!; return nft1?.owner === address.bech32 && nft2?.owner === address.bech32; }); }); diff --git a/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_11.only.spec.ts b/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_11.only.spec.ts index 0770fc11e1..e08a23d514 100644 --- a/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_11.only.spec.ts +++ b/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_11.only.spec.ts @@ -3,11 +3,9 @@ import { COL, MIN_IOTA_AMOUNT, Network, - Nft, NftPurchaseTangleRequest, NftStatus, TangleRequestType, - Transaction, TransactionType, } from '@build-5/interfaces'; import { MnemonicService } from '../../src/services/wallet/mnemonic'; @@ -21,7 +19,7 @@ describe('Minted nft trading', () => { it('Should buy 2 nft in parallel, and deposit in parallel', async () => { await helper.beforeEach(Network.RMS); const address = await helper.walletService!.getNewIotaAddressDetails(); - requestFundsFromFaucet(Network.RMS, address.bech32, 5 * MIN_IOTA_AMOUNT); + await requestFundsFromFaucet(Network.RMS, address.bech32, 5 * MIN_IOTA_AMOUNT); let nft1 = await helper.createAndOrderNft(); let nft2 = await helper.createAndOrderNft(); @@ -65,17 +63,17 @@ describe('Minted nft trading', () => { ); await MnemonicService.store(address.bech32, address.mnemonic, Network.RMS); - const nftDocRef1 = build5Db().doc(`${COL.NFT}/${nft1.uid}`); - const nftDocRef2 = build5Db().doc(`${COL.NFT}/${nft2.uid}`); - nft1 = (await nftDocRef1.get())!; - nft2 = (await nftDocRef2.get())!; + const nftDocRef1 = build5Db().doc(COL.NFT, nft1.uid); + const nftDocRef2 = build5Db().doc(COL.NFT, nft2.uid); + nft1 = (await nftDocRef1.get())!; + nft2 = (await nftDocRef2.get())!; const query = build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.WITHDRAW_NFT) .where('member', '==', address.bech32); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return ( snap.length === 2 && snap[0]?.payload?.walletReference?.confirmed && @@ -95,8 +93,8 @@ describe('Minted nft trading', () => { ); await wait(async () => { - nft1 = (await nftDocRef1.get())!; - nft2 = (await nftDocRef2.get())!; + nft1 = (await nftDocRef1.get())!; + nft2 = (await nftDocRef2.get())!; return nft1?.status === NftStatus.MINTED && nft2?.status === NftStatus.MINTED; }); }); 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 914d625d6e..9a9614bf2a 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 @@ -1,25 +1,24 @@ import { build5Db } from '@build-5/database'; import { COL, - Member, MIN_IOTA_AMOUNT, + Member, Network, Nft, NftStatus, Transaction, TransactionType, + WEN_FUNC, WenError, } from '@build-5/interfaces'; import { NftOutput } from '@iota/sdk'; import dayjs from 'dayjs'; import { isEmpty } from 'lodash'; 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'; -import { expectThrow, mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { expectThrow, wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -33,13 +32,16 @@ describe('Minted nft trading', () => { await helper.setAvailableForAuction(); - const nftDocRef = build5Db().doc(`${COL.NFT}/${helper.nft!.uid}`); + 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.member!, { nft: helper.nft!.uid }); + await expectThrow( + testEnv.wrap(WEN_FUNC.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)({}); + mockWalletReturnValue(helper.member!, { nft: helper.nft!.uid }); + const bidOrder = await testEnv.wrap(WEN_FUNC.openBid); await requestFundsFromFaucet(Network.RMS, bidOrder.payload.targetAddress, MIN_IOTA_AMOUNT); await wait(async () => { @@ -47,7 +49,7 @@ describe('Minted nft trading', () => { return !isEmpty(helper.nft.auctionHighestBidder); }); - const bidOrder2 = await testEnv.wrap(openBid)({}); + const bidOrder2 = await testEnv.wrap(WEN_FUNC.openBid); await requestFundsFromFaucet(Network.RMS, bidOrder2.payload.targetAddress, 2 * MIN_IOTA_AMOUNT); await wait(async () => { @@ -57,15 +59,15 @@ describe('Minted nft trading', () => { await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.PAYMENT) - .where('payload.sourceTransaction', 'array-contains', bidOrder2.uid) - .get() + .where('payload_sourceTransaction', 'array-contains', bidOrder2.uid as any) + .get() )[0]; return helper.nft.auctionHighestBidder === payment?.member; }); await build5Db() - .doc(`${COL.AUCTION}/${helper.nft!.auction}`) - .update({ auctionTo: dateToTimestamp(dayjs().subtract(1, 'm').toDate()) }); + .doc(COL.AUCTION, helper.nft!.auction!) + .update({ auctionTo: dayjs().subtract(1, 'm').toDate() }); await finalizeAuctions(); @@ -74,8 +76,8 @@ describe('Minted nft trading', () => { return nft.owner === helper.member; }); - mockWalletReturnValue(helper.walletSpy, helper.member!, { nft: helper.nft!.uid }); - await testEnv.wrap(withdrawNft)({}); + mockWalletReturnValue(helper.member!, { nft: helper.nft!.uid }); + await testEnv.wrap(WEN_FUNC.withdrawNft); helper.nft = await nftDocRef.get(); expect(helper.nft.status).toBe(NftStatus.WITHDRAWN); @@ -85,8 +87,8 @@ describe('Minted nft trading', () => { await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.WITHDRAW_NFT) - .where('payload.nft', '==', helper.nft!.uid) - .get() + .where('payload_nft', '==', helper.nft!.uid) + .get() )[0]; return transaction?.payload?.walletReference?.confirmed; }); @@ -97,7 +99,7 @@ describe('Minted nft trading', () => { ) ).output as NftOutput; const ownerAddress = Bech32AddressHelper.bech32FromUnlockConditions(output, 'rms'); - const member = await build5Db().doc(`${COL.MEMBER}/${helper.member}`).get(); + const member = await build5Db().doc(COL.MEMBER, helper.member).get(); expect(ownerAddress).toBe(getAddress(member, Network.ATOI)); }); }); diff --git a/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_2.spec.ts b/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_2.spec.ts index ec6f27f362..593b23f442 100644 --- a/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_2.spec.ts +++ b/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_2.spec.ts @@ -7,16 +7,16 @@ import { NftStatus, Transaction, TransactionType, + WEN_FUNC, WenError, } from '@build-5/interfaces'; import { NftOutput } from '@iota/sdk'; import dayjs from 'dayjs'; -import { orderNft, 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'; -import { expectThrow, mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { expectThrow, wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -32,14 +32,17 @@ describe('Minted nft trading', () => { await helper.setAvailableForSale(); - 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.member!, { nft: helper.nft!.uid }); + await expectThrow( + testEnv.wrap(WEN_FUNC.withdrawNft), + WenError.you_must_be_the_owner_of_nft.key, + ); - mockWalletReturnValue(helper.walletSpy, helper.member!, { + mockWalletReturnValue(helper.member!, { collection: helper.collection!, nft: helper.nft!.uid, }); - const order = await testEnv.wrap(orderNft)({}); + const order = await testEnv.wrap(WEN_FUNC.orderNft); await requestFundsFromFaucet( Network.RMS, order.payload.targetAddress, @@ -48,14 +51,14 @@ describe('Minted nft trading', () => { ); await wait(async () => { - const nft = await build5Db().doc(`${COL.NFT}/${helper.nft!.uid}`).get(); + 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)({}); + mockWalletReturnValue(helper.member!, { nft: helper.nft!.uid }); + await testEnv.wrap(WEN_FUNC.withdrawNft); - const nft = await build5Db().doc(`${COL.NFT}/${helper.nft!.uid}`).get(); + const nft = await build5Db().doc(COL.NFT, helper.nft!.uid).get(); expect(nft.status).toBe(NftStatus.WITHDRAWN); await wait(async () => { @@ -63,8 +66,8 @@ describe('Minted nft trading', () => { await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.WITHDRAW_NFT) - .where('payload.nft', '==', helper.nft!.uid) - .get() + .where('payload_nft', '==', helper.nft!.uid) + .get() )[0]; return transaction?.payload?.walletReference?.confirmed; }); @@ -75,7 +78,7 @@ describe('Minted nft trading', () => { ) ).output; const ownerAddress = Bech32AddressHelper.bech32FromUnlockConditions(output as NftOutput, 'rms'); - const member = await build5Db().doc(`${COL.MEMBER}/${helper.member}`).get(); + 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_3.spec.ts b/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_3.spec.ts index 6950bfcc18..47b715e51c 100644 --- a/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_3.spec.ts +++ b/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_3.spec.ts @@ -4,12 +4,13 @@ import { Collection, CollectionStatus, Network, + Transaction, UnsoldMintingOptions, + WEN_FUNC, WenError, } from '@build-5/interfaces'; -import { mintCollection } from '../../src/runtime/firebase/collection/index'; -import { expectThrow, mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { expectThrow, wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -20,12 +21,12 @@ describe('Minted nft trading', () => { await helper.beforeEach(Network.RMS); await helper.createAndOrderNft(); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { + mockWalletReturnValue(helper.guardian!, { collection: helper.collection, network: helper.network, unsoldMintingOptions: UnsoldMintingOptions.KEEP_PRICE, }); - const collectionMintOrder = await testEnv.wrap(mintCollection)({}); + const collectionMintOrder = await testEnv.wrap(WEN_FUNC.mintCollection); await requestFundsFromFaucet( helper.network!, collectionMintOrder.payload.targetAddress, @@ -33,9 +34,7 @@ describe('Minted nft trading', () => { ); await wait(async () => { - const collection = ( - await build5Db().doc(`${COL.COLLECTION}/${helper.collection}`).get() - ); + const collection = await build5Db().doc(COL.COLLECTION, helper.collection).get(); return collection.status === CollectionStatus.MINTING; }); diff --git a/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_4.spec.ts b/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_4.spec.ts index a0d8180463..3d2c04f5d2 100644 --- a/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_4.spec.ts +++ b/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_4.spec.ts @@ -7,7 +7,6 @@ import { Nft, NftStatus, TangleRequestType, - Transaction, TransactionPayloadType, TransactionType, } from '@build-5/interfaces'; @@ -48,13 +47,13 @@ describe('Minted nft trading', () => { .collection(COL.TRANSACTION) .where('member', '==', address.bech32) .where('type', '==', TransactionType.CREDIT_TANGLE_REQUEST) - .get(); + .get(); return snap.length > 0 && snap[0]?.payload?.walletReference?.confirmed; }); await helper.setAvailableForSale(); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${helper.nft?.collection}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, helper.nft?.collection); let collection = await collectionDocRef.get(); expect(collection.nftsOnSale).toBe(1); expect(collection.nftsOnAuction).toBe(0); @@ -74,7 +73,7 @@ describe('Minted nft trading', () => { }, ); - const nftDocRef = build5Db().doc(`${COL.NFT}/${helper.nft?.uid}`); + const nftDocRef = build5Db().doc(COL.NFT, helper.nft?.uid); await wait(async () => { const nft = await nftDocRef.get(); return nft.status === NftStatus.WITHDRAWN; @@ -85,7 +84,7 @@ describe('Minted nft trading', () => { .collection(COL.TRANSACTION) .where('member', '==', address.bech32) .where('type', '==', TransactionType.WITHDRAW_NFT) - .get(); + .get(); return snap.length > 0 && snap[0]?.payload?.walletReference?.confirmed; }); @@ -100,9 +99,9 @@ describe('Minted nft trading', () => { const orders = await build5Db() .collection(COL.TRANSACTION) - .where('payload.type', '==', TransactionPayloadType.NFT_PURCHASE) - .where('payload.nft', '==', helper.nft!.uid) - .get(); + .where('payload_type', '==', TransactionPayloadType.NFT_PURCHASE) + .where('payload_nft', '==', helper.nft!.uid) + .get(); for (const order of orders) { expect(order.payload.restrictions!.collection).toEqual({ access: collection.access, @@ -110,7 +109,7 @@ describe('Minted nft trading', () => { accessCollections: collection.accessCollections || [], }); expect(order.payload.restrictions!.nft).toEqual({ - saleAccess: helper.nft!.saleAccess || null, + saleAccess: helper.nft!.saleAccess || undefined, saleAccessMembers: helper.nft!.saleAccessMembers || [], }); } @@ -118,8 +117,8 @@ describe('Minted nft trading', () => { const billPayments = await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.BILL_PAYMENT) - .where('payload.nft', '==', helper.nft!.uid) - .get(); + .where('payload_nft', '==', helper.nft!.uid) + .get(); for (const billPayment of billPayments) { expect(billPayment.payload.restrictions).toEqual(orders[0].payload.restrictions); } diff --git a/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_5.spec.ts b/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_5.spec.ts index 6ac9f123f6..82fefe1295 100644 --- a/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_5.spec.ts +++ b/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_5.spec.ts @@ -46,13 +46,13 @@ describe('Minted nft trading', () => { .where('member', '==', address.bech32) .where('type', '==', TransactionType.CREDIT_TANGLE_REQUEST); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return snap.length > 0 && snap[0]?.payload?.walletReference?.confirmed; }); const snap = await creditQuery.get(); const credit = snap[0] as Transaction; - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${helper.nft?.collection}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, helper.nft?.collection); const collection = await collectionDocRef.get(); expect(collection.availableNfts).toBe(1); expect(collection.nftsOnSale).toBe(0); @@ -69,7 +69,7 @@ describe('Minted nft trading', () => { {}, ); - const nftDocRef = build5Db().doc(`${COL.NFT}/${helper.nft?.uid}`); + const nftDocRef = build5Db().doc(COL.NFT, helper.nft?.uid); await wait(async () => { const nft = await nftDocRef.get(); return nft.sold || false; @@ -78,7 +78,7 @@ describe('Minted nft trading', () => { expect(nft.owner).toBe(address.bech32); await wait(async () => { - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${helper.nft?.collection}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, helper.nft?.collection); const collection = await collectionDocRef.get(); return !collection.availableNfts && !collection.nftsOnSale && !collection.nftsOnAuction; }); diff --git a/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_6.spec.ts b/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_6.spec.ts index 59d73936da..bf8192104d 100644 --- a/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_6.spec.ts +++ b/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_6.spec.ts @@ -5,7 +5,6 @@ import { MIN_IOTA_AMOUNT, Network, TangleRequestType, - Transaction, TransactionType, } from '@build-5/interfaces'; import { MnemonicService } from '../../src/services/wallet/mnemonic'; @@ -46,7 +45,7 @@ describe('Minted nft trading', () => { .collection(COL.TRANSACTION) .where('member', '==', address.bech32) .where('type', '==', TransactionType.WITHDRAW_NFT) - .get(); + .get(); return snap.length > 0 && snap[0]?.payload?.walletReference?.confirmed; }); const nftOutputIds = await helper.walletService!.client.nftOutputIds([ diff --git a/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_7.spec.ts b/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_7.spec.ts index afe142ac32..222c4f06a3 100644 --- a/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_7.spec.ts +++ b/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_7.spec.ts @@ -8,7 +8,6 @@ import { NftStatus, TangleRequestType, TangleResponse, - Transaction, TransactionPayloadType, TransactionType, } from '@build-5/interfaces'; @@ -53,18 +52,18 @@ describe('Minted nft trading', () => { .where('member', '==', address.bech32) .where('type', '==', TransactionType.CREDIT_TANGLE_REQUEST); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return snap.length > 0 && snap[0].payload?.walletReference?.confirmed; }); - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); const credit = snap[0]; const response = credit.payload.response as TangleResponse; await helper.walletService!.send(address, response.address!, response.amount!, {}); await MnemonicService.store(address.bech32, address.mnemonic, Network.RMS); - const nftDocRef = build5Db().doc(`${COL.NFT}/${helper.nft?.uid}`); + const nftDocRef = build5Db().doc(COL.NFT, helper.nft?.uid); await wait(async () => { const nft = await nftDocRef.get(); return nft.status === NftStatus.WITHDRAWN; @@ -75,7 +74,7 @@ describe('Minted nft trading', () => { .collection(COL.TRANSACTION) .where('member', '==', address.bech32) .where('type', '==', TransactionType.WITHDRAW_NFT) - .get(); + .get(); return snap.length > 0 && snap[0].payload?.walletReference?.confirmed; }); @@ -84,22 +83,22 @@ describe('Minted nft trading', () => { ]); expect(nftOutputIds.items.length).toBe(1); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${helper.nft?.collection}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, helper.nft?.collection); const collection = await collectionDocRef.get(); expect(collection.nftsOnSale).toBe(0); expect(collection.nftsOnAuction).toBe(0); const orders = await build5Db() .collection(COL.TRANSACTION) - .where('payload.type', '==', TransactionPayloadType.NFT_PURCHASE) - .where('payload.nft', '==', helper.nft!.uid) - .get(); + .where('payload_type', '==', TransactionPayloadType.NFT_PURCHASE) + .where('payload_nft', '==', helper.nft!.uid) + .get(); const billPayments = await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.BILL_PAYMENT) - .where('payload.nft', '==', helper.nft!.uid) - .get(); + .where('payload_nft', '==', helper.nft!.uid) + .get(); for (const billPayment of billPayments) { expect(billPayment.payload.restrictions).toEqual(orders[0].payload.restrictions); } diff --git a/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_8.spec.ts b/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_8.spec.ts index ff3519abd0..4fc1d596c7 100644 --- a/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_8.spec.ts +++ b/packages/functions/test-tangle/minted-nft-trading/minted-nft-trading_8.spec.ts @@ -3,7 +3,6 @@ import { COL, MIN_IOTA_AMOUNT, Network, - Nft, NftPurchaseTangleRequest, NftStatus, TangleRequestType, @@ -44,9 +43,9 @@ describe('Minted nft trading', () => { ); await MnemonicService.store(address.bech32, address.mnemonic, Network.RMS); - const nftDocRef = build5Db().doc(`${COL.NFT}/${helper.nft!.uid}`); + const nftDocRef = build5Db().doc(COL.NFT, helper.nft!.uid); await wait(async () => { - const nft = await nftDocRef.get(); + const nft = await nftDocRef.get(); return nft?.owner === address.bech32 && nft.status === NftStatus.MINTED; }); }, diff --git a/packages/functions/test-tangle/minted-token-airdrop/Helper.ts b/packages/functions/test-tangle/minted-token-airdrop/Helper.ts index e87370af8d..ec39143e09 100644 --- a/packages/functions/test-tangle/minted-token-airdrop/Helper.ts +++ b/packages/functions/test-tangle/minted-token-airdrop/Helper.ts @@ -14,28 +14,26 @@ import { MnemonicService } from '../../src/services/wallet/mnemonic'; import { Wallet } from '../../src/services/wallet/wallet'; import { serverTime } from '../../src/utils/dateTime.utils'; import * as wallet from '../../src/utils/wallet.utils'; -import { createMember, createSpace, getRandomSymbol } from '../../test/controls/common'; -import { MEDIA, getWallet } from '../../test/set-up'; +import { getRandomSymbol } from '../../test/controls/common'; +import { MEDIA, getWallet, testEnv } from '../../test/set-up'; export class Helper { public network = Network.RMS; - public space: Space | undefined; - public token: Token | undefined; + public space: Space = {} as any; + public token: Token = {} as any; - public guardian: string | undefined; - public member: string | undefined; - public walletService: Wallet | undefined; - public walletSpy: any; + public guardian = ''; + public member = ''; + public walletService: Wallet = {} as any; public berforeAll = async () => { this.walletService = await getWallet(this.network); - this.walletSpy = jest.spyOn(wallet, 'decodeAuth'); }; public beforeEach = async () => { - this.guardian = await createMember(this.walletSpy); - this.member = await createMember(this.walletSpy); - this.space = await createSpace(this.walletSpy, this.guardian); + this.guardian = await testEnv.createMember(); + this.member = await testEnv.createMember(); + this.space = await testEnv.createSpace(this.guardian); this.token = (await saveToken(this.space.uid, this.guardian, this.walletService!)) as Token; }; @@ -76,8 +74,8 @@ export const saveToken = async ( }, access: 0, icon: MEDIA, - }; - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).set(token); + } as Token; + await build5Db().doc(COL.TOKEN, token.uid).create(token); return token; }; diff --git a/packages/functions/test-tangle/minted-token-airdrop/minted-token-airdrop_1_a.spec.ts b/packages/functions/test-tangle/minted-token-airdrop/minted-token-airdrop_1_a.spec.ts index fa48f13c1c..08757e1e9b 100644 --- a/packages/functions/test-tangle/minted-token-airdrop/minted-token-airdrop_1_a.spec.ts +++ b/packages/functions/test-tangle/minted-token-airdrop/minted-token-airdrop_1_a.spec.ts @@ -14,17 +14,14 @@ import { Transaction, TransactionPayloadType, TransactionType, + WEN_FUNC, WenError, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { head } from 'lodash'; -import { - airdropMintedToken, - claimMintedTokenOrder, -} from '../../src/runtime/firebase/token/minting'; +import { head, isEmpty } from 'lodash'; import { getAddress } from '../../src/utils/address.utils'; -import { expectThrow, mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { expectThrow, wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken } from '../common'; import { requestFundsFromFaucet, requestMintedTokenFromFaucet } from '../faucet'; import { Helper, VAULT_MNEMONIC } from './Helper'; @@ -51,17 +48,20 @@ describe('Minted token airdrop', () => { { count: 1, recipient: helper.member!, vestingAt: dayjs().add(2, 'M').toDate(), stakeType }, ]; const total = drops.reduce((acc, act) => acc + act.count, 0); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { + mockWalletReturnValue(helper.guardian!, { token: helper.token!.uid, drops, }); - let order = await testEnv.wrap(airdropMintedToken)({}); + let order = await testEnv.wrap(WEN_FUNC.airdropMintedToken); expect(order.payload.unclaimedAirdrops).toBe(2); - mockWalletReturnValue(helper.walletSpy, helper.member!, { symbol: helper.token!.symbol }); - await expectThrow(testEnv.wrap(claimMintedTokenOrder)({}), WenError.no_tokens_to_claim.key); + mockWalletReturnValue(helper.member!, { symbol: helper.token!.symbol }); + await expectThrow( + testEnv.wrap(WEN_FUNC.claimMintedTokenOrder), + WenError.no_tokens_to_claim.key, + ); - const guardian = await build5Db().doc(`${COL.MEMBER}/${helper.guardian}`).get(); + const guardian = await build5Db().doc(COL.MEMBER, helper.guardian!).get(); const guardianAddress = await helper.walletService!.getAddressDetails( getAddress(guardian, helper.network), ); @@ -74,7 +74,7 @@ describe('Minted token airdrop', () => { total, ); - await helper.walletService!.send(guardianAddress, order.payload.targetAddress, 0, { + await helper.walletService!.send(guardianAddress, order.payload.targetAddress!, 0, { nativeTokens: [{ id: helper.token?.mintingData?.tokenId!, amount: BigInt(total) }], }); @@ -84,16 +84,19 @@ describe('Minted token airdrop', () => { }); const distributionDocRef = build5Db().doc( - `${COL.TOKEN}/${helper.token!.uid}/${SUB_COL.DISTRIBUTION}/${helper.member}`, + COL.TOKEN, + helper.token!.uid, + SUB_COL.DISTRIBUTION, + helper.member, ); let distribution = await distributionDocRef.get(); expect(distribution.totalUnclaimedAirdrop).toBe(2); - mockWalletReturnValue(helper.walletSpy, helper.member!, { + mockWalletReturnValue(helper.member!, { symbol: helper.token!.symbol, }); - const claimOrder = await testEnv.wrap(claimMintedTokenOrder)({}); - const claimOrder2 = await testEnv.wrap(claimMintedTokenOrder)({}); + const claimOrder = await testEnv.wrap(WEN_FUNC.claimMintedTokenOrder); + const claimOrder2 = await testEnv.wrap(WEN_FUNC.claimMintedTokenOrder); await requestFundsFromFaucet( helper.network, claimOrder.payload.targetAddress, @@ -106,7 +109,7 @@ describe('Minted token airdrop', () => { ); await wait(async () => { - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${order.uid}`); + const orderDocRef = build5Db().doc(COL.TRANSACTION, order.uid); order = await orderDocRef.get(); return order.payload.unclaimedAirdrops === 0; }); @@ -129,25 +132,26 @@ describe('Minted token airdrop', () => { expect(billPayment.payload.tokenSymbol).toBe(helper.token!.symbol); expect(billPayment.payload.type).toBe(TransactionPayloadType.MINTED_AIRDROP_CLAIM); }); + for (let i = 0; i < drops.length; ++i) { - expect( - billPayments.find((bp) => { - if (dayjs(drops[i].vestingAt).isBefore(dayjs())) { - return bp.payload.vestingAt === null; - } - return ( - bp.payload.vestingAt && - dayjs(bp.payload.vestingAt.toDate()).isSame(dayjs(drops[i].vestingAt)) - ); - }), - ).toBeDefined(); + const billPayment = billPayments.find((bp) => { + if (dayjs(drops[i].vestingAt).isBefore(dayjs())) { + return isEmpty(bp.payload.vestingAt); + } + + return ( + bp.payload.vestingAt && + dayjs(bp.payload.vestingAt.toDate()).isSame(dayjs(drops[i].vestingAt)) + ); + }); + expect(billPayment).toBeDefined(); } await wait(async () => { const snap = await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.CREDIT) - .where('member', 'in', [helper.guardian, helper.member]) + .whereIn('member', [helper.guardian, helper.member]) .get(); return snap.length === 2; }); @@ -155,7 +159,7 @@ describe('Minted token airdrop', () => { const { amount } = await helper.walletService!.getBalance(guardianAddress.bech32); expect(amount).toBe(5 * MIN_IOTA_AMOUNT); - const member = await build5Db().doc(`${COL.MEMBER}/${helper.member}`).get(); + const member = await build5Db().doc(COL.MEMBER, helper.member!).get(); const memberAddress = await helper.walletService!.getAddressDetails( getAddress(member, helper.network), ); @@ -178,10 +182,10 @@ describe('Minted token airdrop', () => { const tokenUid = helper.token?.uid; - helper.token = await build5Db().doc(`${COL.TOKEN}/${tokenUid}`).get(); + helper.token = await build5Db().doc(COL.TOKEN, tokenUid!).get(); expect(helper.token.mintingData?.tokensInVault).toBe(0); - const statsDocRef = build5Db().doc(`${COL.TOKEN}/${tokenUid}/${SUB_COL.STATS}/${tokenUid}`); + const statsDocRef = build5Db().doc(COL.TOKEN, tokenUid!, SUB_COL.STATS, tokenUid); const tokenStats = await statsDocRef.get(); expect(tokenStats.stakes![stakeType]?.amount).toBe(1); expect(tokenStats.stakes![stakeType]?.totalAmount).toBe(1); diff --git a/packages/functions/test-tangle/minted-token-airdrop/minted-token-airdrop_1_b.spec.ts b/packages/functions/test-tangle/minted-token-airdrop/minted-token-airdrop_1_b.spec.ts index e6b59c77d8..f692a686da 100644 --- a/packages/functions/test-tangle/minted-token-airdrop/minted-token-airdrop_1_b.spec.ts +++ b/packages/functions/test-tangle/minted-token-airdrop/minted-token-airdrop_1_b.spec.ts @@ -14,18 +14,15 @@ import { Transaction, TransactionPayloadType, TransactionType, + WEN_FUNC, WenError, } from '@build-5/interfaces'; import dayjs from 'dayjs'; import { head } from 'lodash'; -import { - airdropMintedToken, - claimMintedTokenOrder, -} from '../../src/runtime/firebase/token/minting'; import { getAddress } from '../../src/utils/address.utils'; import { dateToTimestamp } from '../../src/utils/dateTime.utils'; -import { expectThrow, mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { expectThrow, wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken } from '../common'; import { requestFundsFromFaucet, requestMintedTokenFromFaucet } from '../faucet'; import { Helper, VAULT_MNEMONIC } from './Helper'; @@ -53,17 +50,20 @@ describe('Minted token airdrop', () => { { count: 1, recipient: helper.member!, vestingAt: dayjs().add(2, 'M').toDate(), stakeType }, ]; const total = drops.reduce((acc, act) => acc + act.count, 0); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { + mockWalletReturnValue(helper.guardian!, { token: helper.token!.uid, drops, }); - let order = await testEnv.wrap(airdropMintedToken)({}); + let order = await testEnv.wrap(WEN_FUNC.airdropMintedToken); expect(order.payload.unclaimedAirdrops).toBe(2); - mockWalletReturnValue(helper.walletSpy, helper.member!, { symbol: helper.token!.symbol }); - await expectThrow(testEnv.wrap(claimMintedTokenOrder)({}), WenError.no_tokens_to_claim.key); + mockWalletReturnValue(helper.member!, { symbol: helper.token!.symbol }); + await expectThrow( + testEnv.wrap(WEN_FUNC.claimMintedTokenOrder), + WenError.no_tokens_to_claim.key, + ); - const guardian = await build5Db().doc(`${COL.MEMBER}/${helper.guardian}`).get(); + const guardian = await build5Db().doc(COL.MEMBER, helper.guardian).get(); const guardianAddress = await helper.walletService!.getAddressDetails( getAddress(guardian, helper.network), ); @@ -82,7 +82,7 @@ describe('Minted token airdrop', () => { expiresAt, ); - await helper.walletService!.send(guardianAddress, order.payload.targetAddress, 0, { + await helper.walletService!.send(guardianAddress, order.payload.targetAddress!, 0, { expiration: expiresAt ? { expiresAt, returnAddressBech32: guardianAddress.bech32 } : undefined, @@ -95,16 +95,19 @@ describe('Minted token airdrop', () => { }); const distributionDocRef = build5Db().doc( - `${COL.TOKEN}/${helper.token!.uid}/${SUB_COL.DISTRIBUTION}/${helper.member}`, + COL.TOKEN, + helper.token!.uid, + SUB_COL.DISTRIBUTION, + helper.member, ); let distribution = await distributionDocRef.get(); expect(distribution.totalUnclaimedAirdrop).toBe(2); - mockWalletReturnValue(helper.walletSpy, helper.member!, { + mockWalletReturnValue(helper.member!, { symbol: helper.token!.symbol, }); - const claimOrder = await testEnv.wrap(claimMintedTokenOrder)({}); - const claimOrder2 = await testEnv.wrap(claimMintedTokenOrder)({}); + const claimOrder = await testEnv.wrap(WEN_FUNC.claimMintedTokenOrder); + const claimOrder2 = await testEnv.wrap(WEN_FUNC.claimMintedTokenOrder); await requestFundsFromFaucet( helper.network, claimOrder.payload.targetAddress, @@ -119,7 +122,7 @@ describe('Minted token airdrop', () => { ); await wait(async () => { - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${order.uid}`); + const orderDocRef = build5Db().doc(COL.TRANSACTION, order.uid); order = await orderDocRef.get(); return order.payload.unclaimedAirdrops === 0; }); @@ -146,7 +149,7 @@ describe('Minted token airdrop', () => { expect( billPayments.find((bp) => { if (dayjs(drops[i].vestingAt).isBefore(dayjs())) { - return bp.payload.vestingAt === null; + return bp.payload.vestingAt === undefined; } return ( bp.payload.vestingAt && @@ -160,7 +163,7 @@ describe('Minted token airdrop', () => { const snap = await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.CREDIT) - .where('member', 'in', [helper.guardian, helper.member]) + .whereIn('member', [helper.guardian, helper.member]) .get(); return snap.length === 2; }); @@ -168,7 +171,7 @@ describe('Minted token airdrop', () => { const { amount } = await helper.walletService!.getBalance(guardianAddress.bech32); expect(amount).toBe(5 * MIN_IOTA_AMOUNT); - const member = await build5Db().doc(`${COL.MEMBER}/${helper.member}`).get(); + const member = await build5Db().doc(COL.MEMBER, helper.member).get(); const memberAddress = await helper.walletService!.getAddressDetails( getAddress(member, helper.network), ); @@ -191,10 +194,10 @@ describe('Minted token airdrop', () => { const tokenUid = helper.token?.uid; - helper.token = await build5Db().doc(`${COL.TOKEN}/${tokenUid}`).get(); + helper.token = await build5Db().doc(COL.TOKEN, tokenUid).get(); expect(helper.token.mintingData?.tokensInVault).toBe(0); - const statsDocRef = build5Db().doc(`${COL.TOKEN}/${tokenUid}/${SUB_COL.STATS}/${tokenUid}`); + const statsDocRef = build5Db().doc(COL.TOKEN, tokenUid, SUB_COL.STATS, tokenUid); const tokenStats = await statsDocRef.get(); expect(tokenStats.stakes![stakeType]?.amount).toBe(1); expect(tokenStats.stakes![stakeType]?.totalAmount).toBe(1); diff --git a/packages/functions/test-tangle/minted-token-airdrop/minted-token-airdrop_1_c.spec.ts b/packages/functions/test-tangle/minted-token-airdrop/minted-token-airdrop_1_c.spec.ts index dca93dcbb7..e854c83352 100644 --- a/packages/functions/test-tangle/minted-token-airdrop/minted-token-airdrop_1_c.spec.ts +++ b/packages/functions/test-tangle/minted-token-airdrop/minted-token-airdrop_1_c.spec.ts @@ -11,15 +11,12 @@ import { TokenDrop, TokenDropStatus, Transaction, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { - airdropMintedToken, - claimMintedTokenOrder, -} from '../../src/runtime/firebase/token/minting'; import { getAddress } from '../../src/utils/address.utils'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken } from '../common'; import { requestFundsFromFaucet, requestMintedTokenFromFaucet } from '../faucet'; import { Helper, VAULT_MNEMONIC } from './Helper'; @@ -45,11 +42,11 @@ describe('Minted token airdrop', () => { stakeType, }, ]; - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { + mockWalletReturnValue(helper.guardian!, { token: helper.token!.uid, drops, }); - let order = await testEnv.wrap(airdropMintedToken)({}); + let order = await testEnv.wrap(WEN_FUNC.airdropMintedToken); const airdropQuery = build5Db().collection(COL.AIRDROP).where('member', '==', helper.member); let airdropsSnap = await airdropQuery.get(); @@ -62,7 +59,7 @@ describe('Minted token airdrop', () => { expect(airdrop.token).toEqual(helper.token?.uid!); expect(airdrop.status).toEqual(TokenDropStatus.DEPOSIT_NEEDED); - const guardianDocRef = build5Db().doc(`${COL.MEMBER}/${helper.guardian}`); + const guardianDocRef = build5Db().doc(COL.MEMBER, helper.guardian); const guardian = await guardianDocRef.get(); const guardianAddress = await helper.walletService!.getAddressDetails( getAddress(guardian, helper.network), @@ -76,19 +73,19 @@ describe('Minted token airdrop', () => { 1, ); - await helper.walletService!.send(guardianAddress, order.payload.targetAddress, 0, { + await helper.walletService!.send(guardianAddress, order.payload.targetAddress!, 0, { nativeTokens: [{ id: helper.token?.mintingData?.tokenId!, amount: BigInt(1) }], }); await wait(async () => { - const airdropsSnap = await airdropQuery.get(); + const airdropsSnap = await airdropQuery.get(); return airdropsSnap.length === 1 && airdropsSnap[0]?.status === TokenDropStatus.UNCLAIMED; }); - mockWalletReturnValue(helper.walletSpy, helper.member!, { + mockWalletReturnValue(helper.member!, { symbol: helper.token!.symbol, }); - const claimOrder = await testEnv.wrap(claimMintedTokenOrder)({}); + const claimOrder = await testEnv.wrap(WEN_FUNC.claimMintedTokenOrder); await requestFundsFromFaucet( helper.network, claimOrder.payload.targetAddress, @@ -96,7 +93,7 @@ describe('Minted token airdrop', () => { ); await wait(async () => { - const docRef = build5Db().doc(`${COL.TRANSACTION}/${order.uid}`); + const docRef = build5Db().doc(COL.TRANSACTION, order.uid); order = await docRef.get(); return order.payload.unclaimedAirdrops === 0; }); @@ -104,7 +101,10 @@ describe('Minted token airdrop', () => { await awaitTransactionConfirmationsForToken(helper.token!.uid); const distributionDocRef = build5Db().doc( - `${COL.TOKEN}/${helper.token!.uid}/${SUB_COL.DISTRIBUTION}/${helper.member}`, + COL.TOKEN, + helper.token!.uid, + SUB_COL.DISTRIBUTION, + helper.member, ); const distribution = await distributionDocRef.get(); expect(distribution?.stakes![stakeType].value).toBe(2); diff --git a/packages/functions/test-tangle/minted-token-airdrop/minted-token-airdrop_2.spec.ts b/packages/functions/test-tangle/minted-token-airdrop/minted-token-airdrop_2.spec.ts index 04e51db5b3..7e342a94f9 100644 --- a/packages/functions/test-tangle/minted-token-airdrop/minted-token-airdrop_2.spec.ts +++ b/packages/functions/test-tangle/minted-token-airdrop/minted-token-airdrop_2.spec.ts @@ -3,8 +3,8 @@ import { build5Db } from '@build-5/database'; import { COL, - Member, MIN_IOTA_AMOUNT, + Member, SOON_PROJECT_ID, SUB_COL, Token, @@ -14,18 +14,14 @@ import { TokenStatus, Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { - airdropMintedToken, - claimMintedTokenOrder, - mintTokenOrder, -} from '../../src/runtime/firebase/token/minting'; import { getAddress } from '../../src/utils/address.utils'; import { dateToTimestamp, serverTime } from '../../src/utils/dateTime.utils'; import { getRandomEthAddress } from '../../src/utils/wallet.utils'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken } from '../common'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -42,14 +38,29 @@ describe('Minted token airdrop', () => { }); it('Mint token, airdrop then claim all', async () => { - await build5Db().doc(`${COL.TOKEN}/${helper.token!.uid}`).update({ - mintingData: {}, + await build5Db().doc(COL.TOKEN, helper.token!.uid).update({ + mintingData_mintedBy: undefined, + mintingData_mintedOn: undefined, + mintingData_aliasBlockId: undefined, + mintingData_aliasId: undefined, + mintingData_aliasStorageDeposit: undefined, + mintingData_tokenId: undefined, + mintingData_blockId: undefined, + mintingData_foundryStorageDeposit: undefined, + mintingData_network: undefined, + mintingData_networkFormat: undefined, + mintingData_vaultAddress: undefined, + mintingData_tokensInVault: undefined, + mintingData_vaultStorageDeposit: undefined, + mintingData_guardianStorageDeposit: undefined, + mintingData_meltedTokens: undefined, + mintingData_circulatingSupply: undefined, status: TokenStatus.AVAILABLE, totalSupply: Number.MAX_SAFE_INTEGER, }); await build5Db() - .doc(`${COL.TOKEN}/${helper.token!.uid}/${SUB_COL.DISTRIBUTION}/${helper.member}`) - .set({ tokenOwned: 1 }); + .doc(COL.TOKEN, helper.token!.uid, SUB_COL.DISTRIBUTION, helper.member) + .upsert({ tokenOwned: 1 }); const airdrop: TokenDrop = { project: SOON_PROJECT_ID, @@ -62,27 +73,27 @@ describe('Minted token airdrop', () => { count: 1, status: TokenDropStatus.UNCLAIMED, }; - await build5Db().doc(`${COL.AIRDROP}/${airdrop.uid}`).create(airdrop); + await build5Db().doc(COL.AIRDROP, airdrop.uid).create(airdrop); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { + mockWalletReturnValue(helper.guardian!, { token: helper.token!.uid, network: helper.network, }); - const mintingOrder = await testEnv.wrap(mintTokenOrder)({}); + const mintingOrder = await testEnv.wrap(WEN_FUNC.mintTokenOrder); await requestFundsFromFaucet( helper.network, mintingOrder.payload.targetAddress, mintingOrder.payload.amount, ); - const guardian = await build5Db().doc(`${COL.MEMBER}/${helper.guardian}`).get(); + const guardian = await build5Db().doc(COL.MEMBER, helper.guardian).get(); await requestFundsFromFaucet( helper.network, getAddress(guardian, helper.network), MIN_IOTA_AMOUNT, ); await wait(async () => { - const tokenDocRef = await build5Db().doc(`${COL.TOKEN}/${helper.token!.uid}`).get(); + const tokenDocRef = await build5Db().doc(COL.TOKEN, helper.token!.uid).get(); return tokenDocRef?.status === TokenStatus.MINTED; }); @@ -90,16 +101,16 @@ describe('Minted token airdrop', () => { { count: 1, recipient: helper.member!, vestingAt: dayjs().subtract(1, 'm').toDate() }, { count: 1, recipient: helper.member!, vestingAt: dayjs().add(2, 'h').toDate() }, ]; - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { + mockWalletReturnValue(helper.guardian!, { token: helper.token!.uid, drops, }); - let order = await testEnv.wrap(airdropMintedToken)({}); + let order = await testEnv.wrap(WEN_FUNC.airdropMintedToken); const guardianAddress = await helper.walletService!.getAddressDetails( getAddress(guardian, helper.network), ); - const token = await build5Db().doc(`${COL.TOKEN}/${helper.token!.uid}`).get(); - await helper.walletService!.send(guardianAddress, order.payload.targetAddress, 0, { + const token = await build5Db().doc(COL.TOKEN, helper.token!.uid).get(); + await helper.walletService!.send(guardianAddress, order.payload.targetAddress!, 0, { nativeTokens: [{ id: token.mintingData?.tokenId!, amount: BigInt(2) }], }); @@ -108,22 +119,25 @@ describe('Minted token airdrop', () => { return airdrops.length === 3; }); - mockWalletReturnValue(helper.walletSpy, helper.member!, { symbol: helper.token!.symbol }); - const claimOrder = await testEnv.wrap(claimMintedTokenOrder)({}); + mockWalletReturnValue(helper.member!, { symbol: helper.token!.symbol }); + const claimOrder = await testEnv.wrap(WEN_FUNC.claimMintedTokenOrder); await requestFundsFromFaucet( helper.network, claimOrder.payload.targetAddress, claimOrder.payload.amount, ); - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${order.uid}`); + const orderDocRef = build5Db().doc(COL.TRANSACTION, order.uid); await wait(async () => { order = await orderDocRef.get(); return order.payload.unclaimedAirdrops === 0; }); const distributionDocRef = build5Db().doc( - `${COL.TOKEN}/${helper.token!.uid}/${SUB_COL.DISTRIBUTION}/${helper.member}`, + COL.TOKEN, + helper.token!.uid, + SUB_COL.DISTRIBUTION, + helper.member, ); const distribution = await distributionDocRef.get(); expect(distribution?.tokenOwned).toBe(4); @@ -149,7 +163,7 @@ describe('Minted token airdrop', () => { ).map((d) => d); expect(credit.length).toBe(2); - const member = await build5Db().doc(`${COL.MEMBER}/${helper.member}`).get(); + const member = await build5Db().doc(COL.MEMBER, helper.member).get(); const memberAddress = await helper.walletService!.getAddressDetails( getAddress(member, helper.network), ); diff --git a/packages/functions/test-tangle/minted-token-airdrop/minted-token-airdrop_4.spec.ts b/packages/functions/test-tangle/minted-token-airdrop/minted-token-airdrop_4.spec.ts index 41b524c924..f82c0e9602 100644 --- a/packages/functions/test-tangle/minted-token-airdrop/minted-token-airdrop_4.spec.ts +++ b/packages/functions/test-tangle/minted-token-airdrop/minted-token-airdrop_4.spec.ts @@ -3,24 +3,24 @@ import { build5Db } from '@build-5/database'; import { COL, - Member, MIN_IOTA_AMOUNT, + Member, Network, - StakeType, SUB_COL, + StakeType, TangleRequestType, TokenDistribution, TokenDropStatus, Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { airdropMintedToken } from '../../src/runtime/firebase/token/minting'; import { MnemonicService } from '../../src/services/wallet/mnemonic'; import { getAddress } from '../../src/utils/address.utils'; import { dateToTimestamp } from '../../src/utils/dateTime.utils'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken, getTangleOrder } from '../common'; import { requestFundsFromFaucet, requestMintedTokenFromFaucet } from '../faucet'; import { Helper, VAULT_MNEMONIC } from './Helper'; @@ -50,14 +50,14 @@ describe('Minted token airdrop tangle claim', () => { { count: 1, recipient: helper.member!, vestingAt: dayjs().add(2, 'M').toDate(), stakeType }, ]; const total = drops.reduce((acc, act) => acc + act.count, 0); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { + mockWalletReturnValue(helper.guardian!, { token: helper.token!.uid, drops, }); - const airdropOrder = await testEnv.wrap(airdropMintedToken)({}); + const airdropOrder = await testEnv.wrap(WEN_FUNC.airdropMintedToken); expect(airdropOrder.payload.unclaimedAirdrops).toBe(2); - const guardian = await build5Db().doc(`${COL.MEMBER}/${helper.guardian}`).get(); + const guardian = await build5Db().doc(COL.MEMBER, helper.guardian).get(); const guardianAddress = await helper.walletService!.getAddressDetails( getAddress(guardian, helper.network), ); @@ -76,7 +76,7 @@ describe('Minted token airdrop tangle claim', () => { expiresAt, ); - await helper.walletService!.send(guardianAddress, airdropOrder.payload.targetAddress, 0, { + await helper.walletService!.send(guardianAddress, airdropOrder.payload.targetAddress!, 0, { expiration: expiresAt ? { expiresAt, returnAddressBech32: guardianAddress.bech32 } : undefined, @@ -89,12 +89,15 @@ describe('Minted token airdrop tangle claim', () => { }); const distributionDocRef = build5Db().doc( - `${COL.TOKEN}/${helper.token!.uid}/${SUB_COL.DISTRIBUTION}/${helper.member}`, + COL.TOKEN, + helper.token!.uid, + SUB_COL.DISTRIBUTION, + helper.member, ); let distribution = await distributionDocRef.get(); expect(distribution.totalUnclaimedAirdrop).toBe(2); - const member = await build5Db().doc(`${COL.MEMBER}/${helper.member}`).get(); + const member = await build5Db().doc(COL.MEMBER, helper.member).get(); const memberAddress = await helper.walletService!.getAddressDetails( getAddress(member, helper.network), ); @@ -134,7 +137,7 @@ describe('Minted token airdrop tangle claim', () => { ); await wait(async () => { - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${airdropOrder.uid}`); + const orderDocRef = build5Db().doc(COL.TRANSACTION, airdropOrder.uid); const order = await orderDocRef.get(); return order.payload.unclaimedAirdrops === 0; }); diff --git a/packages/functions/test-tangle/minted-token-airdrop/minted-token-airdrop_5.spec.ts b/packages/functions/test-tangle/minted-token-airdrop/minted-token-airdrop_5.spec.ts index f19541b52e..18ddafbd08 100644 --- a/packages/functions/test-tangle/minted-token-airdrop/minted-token-airdrop_5.spec.ts +++ b/packages/functions/test-tangle/minted-token-airdrop/minted-token-airdrop_5.spec.ts @@ -2,23 +2,20 @@ import { COL, - Member, MIN_IOTA_AMOUNT, + Member, SUB_COL, TokenDistribution, Transaction, + WEN_FUNC, WenError, } from '@build-5/interfaces'; import { build5Db } from '@build-5/database'; import dayjs from 'dayjs'; -import { - airdropMintedToken, - claimMintedTokenOrder, -} from '../../src/runtime/firebase/token/minting'; import { getAddress } from '../../src/utils/address.utils'; -import { expectThrow, mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { expectThrow, wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet, requestMintedTokenFromFaucet } from '../faucet'; import { Helper, VAULT_MNEMONIC } from './Helper'; @@ -34,7 +31,7 @@ describe('Minted token airdrop', () => { }); it('Should airdrop and claim 600', async () => { - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { + mockWalletReturnValue(helper.guardian!, { token: helper.token!.uid, drops: Array.from(Array(600)).map(() => ({ count: 1, @@ -42,13 +39,16 @@ describe('Minted token airdrop', () => { vestingAt: dayjs().add(1, 'y').toDate(), })), }); - let order = await testEnv.wrap(airdropMintedToken)({}); + let order = await testEnv.wrap(WEN_FUNC.airdropMintedToken); expect(order.payload.unclaimedAirdrops).toBe(600); - mockWalletReturnValue(helper.walletSpy, helper.member!, { symbol: helper.token!.symbol }); - await expectThrow(testEnv.wrap(claimMintedTokenOrder)({}), WenError.no_tokens_to_claim.key); + mockWalletReturnValue(helper.member!, { symbol: helper.token!.symbol }); + await expectThrow( + testEnv.wrap(WEN_FUNC.claimMintedTokenOrder), + WenError.no_tokens_to_claim.key, + ); - const guardian = await build5Db().doc(`${COL.MEMBER}/${helper.guardian}`).get(); + const guardian = await build5Db().doc(COL.MEMBER, helper.guardian).get(); const guardianAddress = await helper.walletService!.getAddressDetails( getAddress(guardian, helper.network), ); @@ -60,7 +60,7 @@ describe('Minted token airdrop', () => { VAULT_MNEMONIC, 600, ); - await helper.walletService!.send(guardianAddress, order.payload.targetAddress, 0, { + await helper.walletService!.send(guardianAddress, order.payload.targetAddress!, 0, { nativeTokens: [{ id: helper.token?.mintingData?.tokenId!, amount: BigInt(600) }], }); @@ -69,10 +69,10 @@ describe('Minted token airdrop', () => { return airdrops.length === 600; }); - mockWalletReturnValue(helper.walletSpy, helper.member!, { + mockWalletReturnValue(helper.member!, { symbol: helper.token!.symbol, }); - const claimOrder = await testEnv.wrap(claimMintedTokenOrder)({}); + const claimOrder = await testEnv.wrap(WEN_FUNC.claimMintedTokenOrder); await requestFundsFromFaucet( helper.network, claimOrder.payload.targetAddress, @@ -80,13 +80,16 @@ describe('Minted token airdrop', () => { ); await wait(async () => { - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${order.uid}`); + const orderDocRef = build5Db().doc(COL.TRANSACTION, order.uid); order = await orderDocRef.get(); return order.payload.unclaimedAirdrops === 0; }); const distributionDocRef = build5Db().doc( - `${COL.TOKEN}/${helper.token?.uid}/${SUB_COL.DISTRIBUTION}/${helper.member!}`, + COL.TOKEN, + helper.token?.uid, + SUB_COL.DISTRIBUTION, + helper.member!, ); const distribution = await distributionDocRef.get(); expect(distribution.tokenOwned).toBe(600); diff --git a/packages/functions/test-tangle/minted-token-claim/Helper.ts b/packages/functions/test-tangle/minted-token-claim/Helper.ts index 9fd421173c..edc213b337 100644 --- a/packages/functions/test-tangle/minted-token-claim/Helper.ts +++ b/packages/functions/test-tangle/minted-token-claim/Helper.ts @@ -1,14 +1,21 @@ import { build5Db } from '@build-5/database'; -import { COL, Member, Network, SOON_PROJECT_ID, Space, TokenStatus } from '@build-5/interfaces'; +import { + COL, + Member, + Network, + SOON_PROJECT_ID, + Space, + Token, + TokenStatus, +} from '@build-5/interfaces'; import { MnemonicService } from '../../src/services/wallet/mnemonic'; import { Wallet } from '../../src/services/wallet/wallet'; import { serverTime } from '../../src/utils/dateTime.utils'; import * as walletUtil from '../../src/utils/wallet.utils'; -import { createMember, createSpace, getRandomSymbol } from '../../test/controls/common'; -import { MEDIA, getWallet } from '../../test/set-up'; +import { getRandomSymbol } from '../../test/controls/common'; +import { MEDIA, getWallet, testEnv } from '../../test/set-up'; export class Helper { - public walletSpy: any; public network = Network.RMS; public guardian: Member = {} as any; public space: Space = {} as any; @@ -17,12 +24,11 @@ export class Helper { public beforeEach = async (vaultMnemonic: string, mintedTokenId: string, notMinted = false) => { this.wallet = await getWallet(this.network); - this.walletSpy = jest.spyOn(walletUtil, 'decodeAuth'); - const guardianId = await createMember(this.walletSpy); - this.guardian = await build5Db().doc(`${COL.MEMBER}/${guardianId}`).get(); + const guardianId = await testEnv.createMember(); + this.guardian = await build5Db().doc(COL.MEMBER, guardianId).get(); - this.space = await createSpace(this.walletSpy, this.guardian.uid); + this.space = await testEnv.createSpace(this.guardian.uid); this.token = await this.saveToken( this.space.uid, this.guardian.uid, @@ -64,8 +70,8 @@ export class Helper { access: 0, totalSupply: 10, icon: MEDIA, - }; - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).set(token); + } as Token; + await build5Db().doc(COL.TOKEN, token.uid).create(token); return token; }; } diff --git a/packages/functions/test-tangle/minted-token-claim/token.claim.minted_1.spec.ts b/packages/functions/test-tangle/minted-token-claim/token.claim.minted_1.spec.ts index 5af97d7f21..07c92f1557 100644 --- a/packages/functions/test-tangle/minted-token-claim/token.claim.minted_1.spec.ts +++ b/packages/functions/test-tangle/minted-token-claim/token.claim.minted_1.spec.ts @@ -1,10 +1,9 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { build5Db } from '@build-5/database'; -import { COL, SUB_COL, Token, Transaction, TransactionType } from '@build-5/interfaces'; -import { claimMintedTokenOrder } from '../../src/runtime/firebase/token/minting'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { COL, SUB_COL, Token, Transaction, TransactionType, WEN_FUNC } from '@build-5/interfaces'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken } from '../common'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -18,11 +17,11 @@ describe('Token minting', () => { it('Claim minted tokens by guardian', async () => { await build5Db() - .doc(`${COL.TOKEN}/${helper.token.uid}/${SUB_COL.DISTRIBUTION}/${helper.guardian.uid}`) - .set({ tokenOwned: 1 }); + .doc(COL.TOKEN, helper.token.uid, SUB_COL.DISTRIBUTION, helper.guardian.uid) + .upsert({ tokenOwned: 1 }); - mockWalletReturnValue(helper.walletSpy, helper.guardian.uid, { symbol: helper.token.symbol }); - const order = await testEnv.wrap(claimMintedTokenOrder)({}); + mockWalletReturnValue(helper.guardian.uid, { symbol: helper.token.symbol }); + const order = await testEnv.wrap(WEN_FUNC.claimMintedTokenOrder); await requestFundsFromFaucet(helper.network, order.payload.targetAddress, order.payload.amount); const query = build5Db() @@ -37,7 +36,7 @@ describe('Token minting', () => { expect(billPayment.payload.amount).toBe(order.payload.amount); expect(billPayment.payload.nativeTokens![0].amount).toBe(1); - const tokenData = await build5Db().doc(`${COL.TOKEN}/${helper.token.uid}`).get(); + const tokenData = await build5Db().doc(COL.TOKEN, helper.token.uid).get(); expect(tokenData.mintingData?.tokensInVault).toBe(9); await awaitTransactionConfirmationsForToken(helper.token.uid); diff --git a/packages/functions/test-tangle/minted-token-claim/token.claim.minted_2.spec.ts b/packages/functions/test-tangle/minted-token-claim/token.claim.minted_2.spec.ts index 8c6e5b6035..d2b55fc429 100644 --- a/packages/functions/test-tangle/minted-token-claim/token.claim.minted_2.spec.ts +++ b/packages/functions/test-tangle/minted-token-claim/token.claim.minted_2.spec.ts @@ -10,14 +10,14 @@ import { TokenDropStatus, Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; import { isEmpty } from 'lodash'; -import { claimMintedTokenOrder } from '../../src/runtime/firebase/token/minting'; import { dateToTimestamp, serverTime } from '../../src/utils/dateTime.utils'; import { getRandomEthAddress } from '../../src/utils/wallet.utils'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken } from '../common'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -31,9 +31,12 @@ describe('Token minting', () => { it('Claim owned and airdroped-vesting', async () => { const distributionDocRef = build5Db().doc( - `${COL.TOKEN}/${helper.token.uid}/${SUB_COL.DISTRIBUTION}/${helper.guardian.uid}`, + COL.TOKEN, + helper.token.uid, + SUB_COL.DISTRIBUTION, + helper.guardian.uid, ); - await distributionDocRef.set({ tokenOwned: 1 }); + await distributionDocRef.upsert({ tokenOwned: 1 }); const airdrop: TokenDrop = { project: SOON_PROJECT_ID, @@ -46,10 +49,10 @@ describe('Token minting', () => { count: 1, status: TokenDropStatus.UNCLAIMED, }; - await build5Db().doc(`${COL.AIRDROP}/${airdrop.uid}`).create(airdrop); + await build5Db().doc(COL.AIRDROP, airdrop.uid).create(airdrop); - mockWalletReturnValue(helper.walletSpy, helper.guardian.uid, { symbol: helper.token.symbol }); - const order = await testEnv.wrap(claimMintedTokenOrder)({}); + mockWalletReturnValue(helper.guardian.uid, { symbol: helper.token.symbol }); + const order = await testEnv.wrap(WEN_FUNC.claimMintedTokenOrder); await requestFundsFromFaucet(helper.network, order.payload.targetAddress, order.payload.amount); const query = build5Db() @@ -66,10 +69,10 @@ describe('Token minting', () => { expect(vesting.payload.nativeTokens![0].amount).toBe(1); const unlocked = billPayments.filter((bp) => isEmpty(bp.payload.vestingAt))[0]; - expect(unlocked.payload.amount).toBe(order.payload.amount - 50100); + expect(unlocked.payload.amount).toBe(order.payload.amount! - 50100); expect(unlocked.payload.nativeTokens![0].amount).toBe(1); - const tokenData = await build5Db().doc(`${COL.TOKEN}/${helper.token.uid}`).get(); + const tokenData = await build5Db().doc(COL.TOKEN, helper.token.uid).get(); expect(tokenData.mintingData?.tokensInVault).toBe(8); await awaitTransactionConfirmationsForToken(helper.token.uid); }); diff --git a/packages/functions/test-tangle/minted-token-claim/token.claim.minted_3.spec.ts b/packages/functions/test-tangle/minted-token-claim/token.claim.minted_3.spec.ts index 339e49aaf8..de9b476a1b 100644 --- a/packages/functions/test-tangle/minted-token-claim/token.claim.minted_3.spec.ts +++ b/packages/functions/test-tangle/minted-token-claim/token.claim.minted_3.spec.ts @@ -7,14 +7,15 @@ import { Token, TokenDrop, TokenDropStatus, + Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { claimMintedTokenOrder } from '../../src/runtime/firebase/token/minting'; import { dateToTimestamp, serverTime } from '../../src/utils/dateTime.utils'; import { getRandomEthAddress } from '../../src/utils/wallet.utils'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken } from '../common'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -38,10 +39,10 @@ describe('Token minting', () => { count: 1, status: TokenDropStatus.UNCLAIMED, }; - await build5Db().doc(`${COL.AIRDROP}/${airdrop.uid}`).create(airdrop); + await build5Db().doc(COL.AIRDROP, airdrop.uid).create(airdrop); - mockWalletReturnValue(helper.walletSpy, helper.guardian.uid, { symbol: helper.token.symbol }); - const order = await testEnv.wrap(claimMintedTokenOrder)({}); + mockWalletReturnValue(helper.guardian.uid, { symbol: helper.token.symbol }); + const order = await testEnv.wrap(WEN_FUNC.claimMintedTokenOrder); await requestFundsFromFaucet(helper.network, order.payload.targetAddress, order.payload.amount); const query = build5Db() @@ -53,7 +54,7 @@ describe('Token minting', () => { return snap.length === 1; }); - const tokenData = await build5Db().doc(`${COL.TOKEN}/${helper.token.uid}`).get(); + const tokenData = await build5Db().doc(COL.TOKEN, helper.token.uid).get(); expect(tokenData.mintingData?.tokensInVault).toBe(9); await awaitTransactionConfirmationsForToken(helper.token.uid); diff --git a/packages/functions/test-tangle/minted-token-claim/token.claim.minted_4.spec.ts b/packages/functions/test-tangle/minted-token-claim/token.claim.minted_4.spec.ts index d9c81b6067..9422777c84 100644 --- a/packages/functions/test-tangle/minted-token-claim/token.claim.minted_4.spec.ts +++ b/packages/functions/test-tangle/minted-token-claim/token.claim.minted_4.spec.ts @@ -9,15 +9,15 @@ import { TokenDropStatus, Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; import { isEmpty } from 'lodash'; import { retryWallet } from '../../src/cron/wallet.cron'; -import { claimMintedTokenOrder } from '../../src/runtime/firebase/token/minting'; import { dateToTimestamp, serverTime } from '../../src/utils/dateTime.utils'; import { getRandomEthAddress } from '../../src/utils/wallet.utils'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken } from '../common'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -42,10 +42,10 @@ describe('Token minting', () => { count: i + 1, status: TokenDropStatus.UNCLAIMED, }; - await build5Db().doc(`${COL.AIRDROP}/${airdrop.uid}`).create(airdrop); + await build5Db().doc(COL.AIRDROP, airdrop.uid).create(airdrop); } - mockWalletReturnValue(helper.walletSpy, helper.guardian.uid, { symbol: helper.token.symbol }); - const order = await testEnv.wrap(claimMintedTokenOrder)({}); + mockWalletReturnValue(helper.guardian.uid, { symbol: helper.token.symbol }); + const order = await testEnv.wrap(WEN_FUNC.claimMintedTokenOrder); await requestFundsFromFaucet(helper.network, order.payload.targetAddress, order.payload.amount); const query = build5Db() @@ -57,17 +57,17 @@ describe('Token minting', () => { return snap.length === 3; }); - const tokenData = await build5Db().doc(`${COL.TOKEN}/${helper.token.uid}`).get(); + const tokenData = await build5Db().doc(COL.TOKEN, helper.token.uid).get(); expect(tokenData.mintingData?.tokensInVault).toBe(4); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); const processed = snap.filter((d) => !isEmpty(d?.payload?.walletReference?.processedOn)); return processed.length == 3; }); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); const confirmed = snap.filter((d) => d!.payload.walletReference?.confirmed).length; if (confirmed !== 3) { await retryWallet(); diff --git a/packages/functions/test-tangle/minted-token-claim/token.claim.minted_5.spec.ts b/packages/functions/test-tangle/minted-token-claim/token.claim.minted_5.spec.ts index 5a99b98b8d..fdcf72182d 100644 --- a/packages/functions/test-tangle/minted-token-claim/token.claim.minted_5.spec.ts +++ b/packages/functions/test-tangle/minted-token-claim/token.claim.minted_5.spec.ts @@ -1,10 +1,17 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { build5Db } from '@build-5/database'; -import { COL, SUB_COL, Token, TokenDistribution, TransactionType } from '@build-5/interfaces'; -import { claimMintedTokenOrder } from '../../src/runtime/firebase/token/minting'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { + COL, + SUB_COL, + Token, + TokenDistribution, + Transaction, + TransactionType, + WEN_FUNC, +} from '@build-5/interfaces'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -17,11 +24,11 @@ describe('Token minting', () => { it('Should credit second claim', async () => { await build5Db() - .doc(`${COL.TOKEN}/${helper.token.uid}/${SUB_COL.DISTRIBUTION}/${helper.guardian.uid}`) - .set({ tokenOwned: 1 }); - mockWalletReturnValue(helper.walletSpy, helper.guardian.uid, { symbol: helper.token.symbol }); - const order = await testEnv.wrap(claimMintedTokenOrder)({}); - const order2 = await testEnv.wrap(claimMintedTokenOrder)({}); + .doc(COL.TOKEN, helper.token.uid, SUB_COL.DISTRIBUTION, helper.guardian.uid) + .upsert({ tokenOwned: 1 }); + mockWalletReturnValue(helper.guardian.uid, { symbol: helper.token.symbol }); + const order = await testEnv.wrap(WEN_FUNC.claimMintedTokenOrder); + const order2 = await testEnv.wrap(WEN_FUNC.claimMintedTokenOrder); await requestFundsFromFaucet(helper.network, order.payload.targetAddress, order.payload.amount); await requestFundsFromFaucet( @@ -32,7 +39,10 @@ describe('Token minting', () => { await wait(async () => { const distributionDocRef = build5Db().doc( - `${COL.TOKEN}/${helper.token.uid}/${SUB_COL.DISTRIBUTION}/${helper.guardian.uid}`, + COL.TOKEN, + helper.token.uid, + SUB_COL.DISTRIBUTION, + helper.guardian.uid, ); const distribution = await distributionDocRef.get(); return distribution?.mintedClaimedOn !== undefined; @@ -47,7 +57,7 @@ describe('Token minting', () => { return snap.length === 1; }); - const tokenData = await build5Db().doc(`${COL.TOKEN}/${helper.token.uid}`).get(); + const tokenData = await build5Db().doc(COL.TOKEN, helper.token.uid).get(); expect(tokenData.mintingData?.tokensInVault).toBe(9); }); }); diff --git a/packages/functions/test-tangle/minted-token-claim/token.claim.minted_6.spec.ts b/packages/functions/test-tangle/minted-token-claim/token.claim.minted_6.spec.ts index 7fc65efded..a791a031b5 100644 --- a/packages/functions/test-tangle/minted-token-claim/token.claim.minted_6.spec.ts +++ b/packages/functions/test-tangle/minted-token-claim/token.claim.minted_6.spec.ts @@ -1,10 +1,17 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { build5Db } from '@build-5/database'; -import { COL, SUB_COL, Token, TokenDistribution, WenError } from '@build-5/interfaces'; -import { claimMintedTokenOrder } from '../../src/runtime/firebase/token/minting'; -import { expectThrow, mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { + COL, + SUB_COL, + Token, + TokenDistribution, + Transaction, + WEN_FUNC, + WenError, +} from '@build-5/interfaces'; +import { expectThrow, wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken } from '../common'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -18,23 +25,29 @@ describe('Token minting', () => { it('Should throw, nothing to claim, can not create order', async () => { await build5Db() - .doc(`${COL.TOKEN}/${helper.token.uid}/${SUB_COL.DISTRIBUTION}/${helper.guardian.uid}`) - .set({ tokenOwned: 1 }); - mockWalletReturnValue(helper.walletSpy, helper.guardian.uid, { symbol: helper.token.symbol }); - const order = await testEnv.wrap(claimMintedTokenOrder)({}); + .doc(COL.TOKEN, helper.token.uid, SUB_COL.DISTRIBUTION, helper.guardian.uid) + .upsert({ tokenOwned: 1 }); + mockWalletReturnValue(helper.guardian.uid, { symbol: helper.token.symbol }); + const order = await testEnv.wrap(WEN_FUNC.claimMintedTokenOrder); await requestFundsFromFaucet(helper.network, order.payload.targetAddress, order.payload.amount); await wait(async () => { const distributionDocRef = build5Db().doc( - `${COL.TOKEN}/${helper.token.uid}/${SUB_COL.DISTRIBUTION}/${helper.guardian.uid}`, + COL.TOKEN, + helper.token.uid, + SUB_COL.DISTRIBUTION, + helper.guardian.uid, ); const distribution = await distributionDocRef.get(); return distribution.mintedClaimedOn !== undefined; }); - await expectThrow(testEnv.wrap(claimMintedTokenOrder)({}), WenError.no_tokens_to_claim.key); + await expectThrow( + testEnv.wrap(WEN_FUNC.claimMintedTokenOrder), + WenError.no_tokens_to_claim.key, + ); - const tokenData = await build5Db().doc(`${COL.TOKEN}/${helper.token.uid}`).get(); + const tokenData = await build5Db().doc(COL.TOKEN, helper.token.uid).get(); expect(tokenData.mintingData?.tokensInVault).toBe(9); await awaitTransactionConfirmationsForToken(helper.token.uid); diff --git a/packages/functions/test-tangle/minted-token-claim/token.claim.minted_7.spec.ts b/packages/functions/test-tangle/minted-token-claim/token.claim.minted_7.spec.ts index 6cb682a671..85a3e24257 100644 --- a/packages/functions/test-tangle/minted-token-claim/token.claim.minted_7.spec.ts +++ b/packages/functions/test-tangle/minted-token-claim/token.claim.minted_7.spec.ts @@ -1,10 +1,17 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { build5Db } from '@build-5/database'; -import { COL, Member, SUB_COL, Token, TokenStatus, TransactionType } from '@build-5/interfaces'; -import { claimMintedTokenOrder, mintTokenOrder } from '../../src/runtime/firebase/token/minting'; -import { createMember, createSpace, mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { + COL, + Member, + SUB_COL, + TokenStatus, + Transaction, + TransactionType, + WEN_FUNC, +} from '@build-5/interfaces'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken } from '../common'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -17,9 +24,9 @@ describe('Token minting', () => { }); it('Should return deposit after claiming all', async () => { - const minterId = await createMember(helper.walletSpy); - const minter = await build5Db().doc(`${COL.MEMBER}/${minterId}`).get(); - helper.space = await createSpace(helper.walletSpy, minter.uid); + const minterId = await testEnv.createMember(); + const minter = await build5Db().doc(COL.MEMBER, minterId).get(); + helper.space = await testEnv.createSpace(minter.uid); helper.token = await helper.saveToken( helper.space.uid, minter.uid, @@ -28,19 +35,19 @@ describe('Token minting', () => { true, ); await build5Db() - .doc(`${COL.TOKEN}/${helper.token.uid}/${SUB_COL.DISTRIBUTION}/${helper.guardian.uid}`) - .set({ tokenOwned: 1 }); + .doc(COL.TOKEN, helper.token.uid, SUB_COL.DISTRIBUTION, helper.guardian.uid) + .upsert({ tokenOwned: 1 }); - mockWalletReturnValue(helper.walletSpy, minter.uid, { + mockWalletReturnValue(minter.uid, { token: helper.token.uid, network: helper.network, }); - const order = await testEnv.wrap(mintTokenOrder)({}); + const order = await testEnv.wrap(WEN_FUNC.mintTokenOrder); await requestFundsFromFaucet(helper.network, order.payload.targetAddress, order.payload.amount); - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${helper.token.uid}`); + const tokenDocRef = build5Db().doc(COL.TOKEN, helper.token.uid); await wait(async () => { - const snap = await tokenDocRef.get(); + const snap = await tokenDocRef.get(); return snap?.status === TokenStatus.MINTED; }); @@ -52,8 +59,8 @@ describe('Token minting', () => { return Number(Object.values(nativeTokens)[0]) === 1; }); - mockWalletReturnValue(helper.walletSpy, helper.guardian.uid, { symbol: helper.token.symbol }); - const claimOrder = await testEnv.wrap(claimMintedTokenOrder)({}); + mockWalletReturnValue(helper.guardian.uid, { symbol: helper.token.symbol }); + const claimOrder = await testEnv.wrap(WEN_FUNC.claimMintedTokenOrder); await requestFundsFromFaucet( helper.network, claimOrder.payload.targetAddress, diff --git a/packages/functions/test-tangle/minted-token-trade/Helper.ts b/packages/functions/test-tangle/minted-token-trade/Helper.ts index 8200a9ba3d..a3851414de 100644 --- a/packages/functions/test-tangle/minted-token-trade/Helper.ts +++ b/packages/functions/test-tangle/minted-token-trade/Helper.ts @@ -12,52 +12,43 @@ import { TokenStatus, TokenTradeOrderType, Transaction, + WEN_FUNC, } from '@build-5/interfaces'; -import { tradeToken } from '../../src/runtime/firebase/token/trading'; 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 { serverTime } from '../../src/utils/dateTime.utils'; import * as wallet from '../../src/utils/wallet.utils'; -import { - createMember, - createRoyaltySpaces, - createSpace, - getRandomSymbol, - mockWalletReturnValue, - wait, -} from '../../test/controls/common'; -import { getWallet, MEDIA, testEnv } from '../../test/set-up'; +import { createRoyaltySpaces, getRandomSymbol, wait } from '../../test/controls/common'; +import { getWallet, MEDIA, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet, requestMintedTokenFromFaucet } from '../faucet'; export class Helper { public network = Network.RMS; - public seller: string | undefined; - public space: Space | undefined; - public token: Token | undefined; - public sellerAddress: AddressDetails | undefined; - public buyer: string | undefined; - public buyerAddress: AddressDetails | undefined; + public seller = ''; + public space: Space = {} as any; + public token: Token = {} as any; + public sellerAddress: AddressDetails = {} as any; + public buyer = ''; + public buyerAddress: AddressDetails = {} as any; - public guardian: string | undefined; - public walletService: Wallet | undefined; - public walletSpy: any; + public guardian = ''; + public walletService: Wallet = {} as any; public berforeAll = async () => { this.walletService = await getWallet(this.network); await createRoyaltySpaces(); - this.walletSpy = jest.spyOn(wallet, 'decodeAuth'); }; public beforeEach = async () => { - this.guardian = await createMember(this.walletSpy); - this.space = await createSpace(this.walletSpy, this.guardian); + this.guardian = await testEnv.createMember(); + this.space = await testEnv.createSpace(this.guardian); this.token = (await saveToken(this.space.uid, this.guardian, this.walletService!)) as Token; - this.seller = await createMember(this.walletSpy); - const sellerDoc = await build5Db().doc(`${COL.MEMBER}/${this.seller}`).get(); + this.seller = await testEnv.createMember(); + const sellerDoc = await build5Db().doc(COL.MEMBER, this.seller).get(); this.sellerAddress = await this.walletService!.getAddressDetails( getAddress(sellerDoc, this.network!), ); @@ -69,8 +60,8 @@ export class Helper { VAULT_MNEMONIC, ); - this.buyer = await createMember(this.walletSpy); - const buyerDoc = await build5Db().doc(`${COL.MEMBER}/${this.buyer}`).get(); + this.buyer = await testEnv.createMember(); + const buyerDoc = await build5Db().doc(COL.MEMBER, this.buyer).get(); this.buyerAddress = await this.walletService!.getAddressDetails( getAddress(buyerDoc, this.network), ); @@ -81,13 +72,13 @@ export class Helper { price = MIN_IOTA_AMOUNT, expiresAt?: Timestamp, ) => { - mockWalletReturnValue(this.walletSpy, this.seller!, { + mockWalletReturnValue(this.seller!, { symbol: this.token!.symbol, count, price, type: TokenTradeOrderType.SELL, }); - const sellOrder: Transaction = await testEnv.wrap(tradeToken)({}); + const sellOrder: Transaction = await testEnv.wrap(WEN_FUNC.tradeToken); await this.walletService!.send(this.sellerAddress!, sellOrder.payload.targetAddress!, 0, { nativeTokens: [{ amount: BigInt(count), id: this.token!.mintingData?.tokenId! }], expiration: expiresAt @@ -113,13 +104,13 @@ export class Helper { }; public createBuyOrder = async (count = 10, price = MIN_IOTA_AMOUNT, expiresAt?: Timestamp) => { - mockWalletReturnValue(this.walletSpy, this.buyer!, { + mockWalletReturnValue(this.buyer!, { symbol: this.token!.symbol, count, price, type: TokenTradeOrderType.BUY, }); - const buyOrder: Transaction = await testEnv.wrap(tradeToken)({}); + const buyOrder: Transaction = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet( this.network, buyOrder.payload.targetAddress!, @@ -163,8 +154,8 @@ export const saveToken = async ( }, access: 0, icon: MEDIA, - }; - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).set(token); + } as Token; + await build5Db().doc(COL.TOKEN, token.uid).create(token); return token; }; diff --git a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_1.spec.ts b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_1.spec.ts index b969fd8461..bac22d66d6 100644 --- a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_1.spec.ts +++ b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_1.spec.ts @@ -40,8 +40,8 @@ describe('Token minting', () => { const billPaymentsQuery = build5Db() .collection(COL.TRANSACTION) - .where('member', 'in', [helper.seller, helper.buyer]) - .where('type', '==', TransactionType.BILL_PAYMENT); + .where('type', '==', TransactionType.BILL_PAYMENT) + .whereIn('member', [helper.seller, helper.buyer]); await wait(async () => { const snap = await billPaymentsQuery.get(); return snap.length === 4; @@ -69,7 +69,7 @@ describe('Token minting', () => { )!; expect(paymentToSeller.payload.amount).toBe(9602600); expect(paymentToSeller.payload.sourceAddress).toBe(buyOrder.payload.targetAddress); - expect(paymentToSeller.payload.storageReturn).toBeUndefined(); + expect(paymentToSeller.payload.storageReturn).toEqual({}); const royaltyOnePayment = billPayments.find((bp) => bp.payload.amount === 271800)!; expect(royaltyOnePayment.payload.storageReturn!.address).toBe(helper.sellerAddress!.bech32); @@ -113,7 +113,7 @@ describe('Token minting', () => { expect(purchase.count).toBe(10); expect(purchase.tokenStatus).toBe(TokenStatus.MINTED); expect(purchase.sellerTier).toBe(0); - expect(purchase.sellerTokenTradingFeePercentage).toBeNull(); + expect(purchase.sellerTokenTradingFeePercentage).toBeUndefined(); await awaitTransactionConfirmationsForToken(helper.token!.uid); }); }); diff --git a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_12.spec.ts b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_12.spec.ts index ee31cf8b22..eef29c4b9c 100644 --- a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_12.spec.ts +++ b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_12.spec.ts @@ -3,8 +3,8 @@ import { build5Db } from '@build-5/database'; import { COL, - Member, MIN_IOTA_AMOUNT, + Member, Network, TokenTradeOrder, TokenTradeOrderStatus, @@ -13,7 +13,6 @@ import { import dayjs from 'dayjs'; import { cancelExpiredSale } from '../../src/cron/token.cron'; import { getAddress } from '../../src/utils/address.utils'; -import { dateToTimestamp } from '../../src/utils/dateTime.utils'; import { wait } from '../../test/controls/common'; import { awaitTransactionConfirmationsForToken } from '../common'; import { Helper } from './Helper'; @@ -40,22 +39,22 @@ describe('Token minting', () => { }); let buy = (await query.get())[0]; await build5Db() - .doc(`${COL.TOKEN_MARKET}/${buy.uid}`) - .update({ expiresAt: dateToTimestamp(dayjs().subtract(1, 'd').toDate()) }); + .doc(COL.TOKEN_MARKET, buy.uid) + .update({ expiresAt: dayjs().subtract(1, 'd').toDate() }); await cancelExpiredSale(); - const buyQuery = build5Db().doc(`${COL.TOKEN_MARKET}/${buy.uid}`); + const buyQuery = build5Db().doc(COL.TOKEN_MARKET, buy.uid); await wait(async () => { buy = await buyQuery.get(); return buy.status === TokenTradeOrderStatus.EXPIRED; }); const credit = ( - await build5Db().doc(`${COL.TRANSACTION}/${buy.creditTransactionId}`).get() + await build5Db().doc(COL.TRANSACTION, buy.creditTransactionId!).get() ); expect(credit.member).toBe(helper.buyer); - const buyer = await build5Db().doc(`${COL.MEMBER}/${helper.buyer!}`).get(); + const buyer = await build5Db().doc(COL.MEMBER, helper.buyer!).get(); expect(credit.payload.targetAddress).toBe(getAddress(buyer, Network.RMS)); expect(credit.payload.amount).toBe(5 * MIN_IOTA_AMOUNT); diff --git a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_12_b.spec.ts b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_12_b.spec.ts index 492407ad6a..3371cac151 100644 --- a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_12_b.spec.ts +++ b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_12_b.spec.ts @@ -3,8 +3,8 @@ import { build5Db } from '@build-5/database'; import { COL, - Member, MIN_IOTA_AMOUNT, + Member, Network, TokenTradeOrder, TokenTradeOrderStatus, @@ -13,7 +13,6 @@ import { import dayjs from 'dayjs'; import { cancelExpiredSale } from '../../src/cron/token.cron'; import { getAddress } from '../../src/utils/address.utils'; -import { dateToTimestamp } from '../../src/utils/dateTime.utils'; import { wait } from '../../test/controls/common'; import { awaitTransactionConfirmationsForToken } from '../common'; import { Helper } from './Helper'; @@ -40,22 +39,22 @@ describe('Token minting', () => { }); let sell = (await query.get())[0]; await build5Db() - .doc(`${COL.TOKEN_MARKET}/${sell.uid}`) - .update({ expiresAt: dateToTimestamp(dayjs().subtract(1, 'd').toDate()) }); + .doc(COL.TOKEN_MARKET, sell.uid) + .update({ expiresAt: dayjs().subtract(1, 'd').toDate() }); await cancelExpiredSale(); - const sellQuery = build5Db().doc(`${COL.TOKEN_MARKET}/${sell.uid}`); + const sellQuery = build5Db().doc(COL.TOKEN_MARKET, sell.uid); await wait(async () => { sell = await sellQuery.get(); return sell.status === TokenTradeOrderStatus.EXPIRED; }); const credit = ( - await build5Db().doc(`${COL.TRANSACTION}/${sell.creditTransactionId}`).get() + await build5Db().doc(COL.TRANSACTION, sell.creditTransactionId!).get() ); expect(credit.member).toBe(helper.seller); - const seller = await build5Db().doc(`${COL.MEMBER}/${helper.seller!}`).get(); + const seller = await build5Db().doc(COL.MEMBER, helper.seller!).get(); expect(credit.payload.targetAddress).toBe(getAddress(seller, Network.RMS)); expect(credit.payload.amount).toBe(49600); expect(credit.payload.nativeTokens![0].amount).toBe(5); diff --git a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_13.spec.ts b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_13.spec.ts index a7031c36e9..ade26bd979 100644 --- a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_13.spec.ts +++ b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_13.spec.ts @@ -8,10 +8,11 @@ import { TokenTradeOrder, TokenTradeOrderStatus, TokenTradeOrderType, + Transaction, + WEN_FUNC, } from '@build-5/interfaces'; -import { tradeToken } from '../../src/runtime/firebase/token/trading'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsForManyFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -28,17 +29,19 @@ describe('Token minting', () => { it('Fulfill many buys with sell', async () => { const count = 15; - mockWalletReturnValue(helper.walletSpy, helper.buyer!, { + mockWalletReturnValue(helper.buyer!, { symbol: helper.token!.symbol, count: 1, price: MIN_IOTA_AMOUNT, type: TokenTradeOrderType.BUY, }); - const promises = Array.from(Array(count)).map(() => testEnv.wrap(tradeToken)({})); + const promises = Array.from(Array(count)).map(() => + testEnv.wrap(WEN_FUNC.tradeToken), + ); const orders = await Promise.all(promises); await requestFundsForManyFromFaucet( Network.RMS, - orders.map((o) => ({ toAddress: o.payload.targetAddress, amount: o.payload.amount })), + orders.map((o) => ({ toAddress: o.payload.targetAddress!, amount: o.payload.amount! })), ); const tradeQuery = build5Db() diff --git a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_14.spec.ts b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_14.spec.ts index 411ca4faa9..55ad306e85 100644 --- a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_14.spec.ts +++ b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_14.spec.ts @@ -44,7 +44,7 @@ describe('Token minting', () => { await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.BILL_PAYMENT) - .where('payload.token', '==', helper.token!.uid) + .where('payload_token', '==', helper.token!.uid) .get() ).map((d) => d); diff --git a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_15.only.spec.ts b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_15.only.spec.ts index 2b57cf2b3c..49b8282cae 100644 --- a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_15.only.spec.ts +++ b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_15.only.spec.ts @@ -4,7 +4,6 @@ import { build5Db } from '@build-5/database'; import { COL, MIN_IOTA_AMOUNT, - StakeType, SUB_COL, SYSTEM_CONFIG_DOC_ID, TokenPurchase, @@ -32,28 +31,14 @@ describe('Token minting', () => { 'Should not create royalty payments, zero percentage', async (isMember: boolean) => { if (isMember) { + await build5Db().doc(COL.MEMBER, helper.seller!).update({ tokenTradingFeePercentage: 0 }); await build5Db() - .doc(`${COL.MEMBER}/${helper.seller}`) - .update({ tokenTradingFeePercentage: 0 }); - await build5Db() - .collection(COL.TOKEN) - .doc(soonTokenId) - .collection(SUB_COL.DISTRIBUTION) - .doc(helper.seller!) - .set( - { - stakes: { - [StakeType.DYNAMIC]: { - value: 15000 * MIN_IOTA_AMOUNT, - }, - }, - }, - true, - ); + .doc(COL.TOKEN, soonTokenId, SUB_COL.DISTRIBUTION, helper.seller!) + .upsert({ stakes_dynamic_value: 15000 * MIN_IOTA_AMOUNT }); } else { await build5Db() - .doc(`${COL.SYSTEM}/${SYSTEM_CONFIG_DOC_ID}`) - .set({ tokenTradingFeePercentage: 0 }); + .doc(COL.SYSTEM, SYSTEM_CONFIG_DOC_ID) + .upsert({ tokenTradingFeePercentage: 0 }); } await helper.createSellTradeOrder(20, MIN_IOTA_AMOUNT); @@ -79,7 +64,7 @@ describe('Token minting', () => { await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.BILL_PAYMENT) - .where('payload.token', '==', helper.token!.uid) + .where('payload_token', '==', helper.token!.uid) .get() ).map((d) => d); expect(billPayments.length).toBe(2); @@ -99,7 +84,7 @@ describe('Token minting', () => { ); it('Should create royalty payments for different percentage', async () => { - await build5Db().doc(`${COL.MEMBER}/${helper.seller}`).update({ tokenTradingFeePercentage: 1 }); + await build5Db().doc(COL.MEMBER, helper.seller).update({ tokenTradingFeePercentage: 1 }); await helper.createSellTradeOrder(20, MIN_IOTA_AMOUNT); await helper.createBuyOrder(20, MIN_IOTA_AMOUNT); @@ -120,7 +105,7 @@ describe('Token minting', () => { await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.BILL_PAYMENT) - .where('payload.token', '==', helper.token!.uid) + .where('payload_token', '==', helper.token!.uid) .get() ).map((d) => d); expect(billPayments.length).toBe(4); @@ -154,7 +139,7 @@ describe('Token minting', () => { }); it('Should not create royalty payments as percentage is zero, but send dust', async () => { - await build5Db().doc(`${COL.MEMBER}/${helper.seller}`).update({ tokenTradingFeePercentage: 0 }); + await build5Db().doc(COL.MEMBER, helper.seller).update({ tokenTradingFeePercentage: 0 }); await helper.createSellTradeOrder(20, MIN_IOTA_AMOUNT); await helper.createBuyOrder(20, MIN_IOTA_AMOUNT + 0.1); @@ -174,7 +159,7 @@ describe('Token minting', () => { await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.BILL_PAYMENT) - .where('payload.token', '==', helper.token!.uid) + .where('payload_token', '==', helper.token!.uid) .get() ).map((d) => d); expect(billPayments.length).toBe(3); diff --git a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_16.spec.ts b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_16.spec.ts index 4a8b29023e..dd3b129f89 100644 --- a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_16.spec.ts +++ b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_16.spec.ts @@ -8,11 +8,11 @@ import { TokenTradeOrderType, Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; -import { cancelTradeOrder, tradeToken } from '../../src/runtime/firebase/token/trading'; import { MnemonicService } from '../../src/services/wallet/mnemonic'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken } from '../common'; import { Helper } from './Helper'; @@ -28,13 +28,13 @@ describe('Token minting', () => { }); it('Should create sell with higher storage deposit', async () => { - mockWalletReturnValue(helper.walletSpy, helper.seller!, { + mockWalletReturnValue(helper.seller!, { symbol: helper.token!.symbol, count: 1, price: 5 * MIN_IOTA_AMOUNT, type: TokenTradeOrderType.SELL, }); - const sellOrder: Transaction = await testEnv.wrap(tradeToken)({}); + const sellOrder: Transaction = await testEnv.wrap(WEN_FUNC.tradeToken); await helper.walletService!.send( helper.sellerAddress!, sellOrder.payload.targetAddress!, @@ -65,8 +65,8 @@ describe('Token minting', () => { )[0] ); - mockWalletReturnValue(helper.walletSpy, helper.seller!, { uid: sell.uid }); - await testEnv.wrap(cancelTradeOrder)({}); + mockWalletReturnValue(helper.seller!, { uid: sell.uid }); + await testEnv.wrap(WEN_FUNC.cancelTradeOrder); const sellerCreditSnap = await build5Db() .collection(COL.TRANSACTION) @@ -83,13 +83,13 @@ describe('Token minting', () => { it('Should fulfill sell and credit higher storage deposit', async () => { await helper.createBuyOrder(1, 5 * MIN_IOTA_AMOUNT); - mockWalletReturnValue(helper.walletSpy, helper.seller!, { + mockWalletReturnValue(helper.seller!, { symbol: helper.token!.symbol, count: 1, price: 5 * MIN_IOTA_AMOUNT, type: TokenTradeOrderType.SELL, }); - const sellOrder: Transaction = await testEnv.wrap(tradeToken)({}); + const sellOrder: Transaction = await testEnv.wrap(WEN_FUNC.tradeToken); await helper.walletService!.send( helper.sellerAddress!, sellOrder.payload.targetAddress!, diff --git a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_17.spec.ts b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_17.spec.ts index 20cd3a3006..fe6f279e06 100644 --- a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_17.spec.ts +++ b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_17.spec.ts @@ -8,11 +8,10 @@ import { TokenTradeOrderType, Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; -import { creditUnrefundable } from '../../src/runtime/firebase/credit/index'; -import { tradeToken } from '../../src/runtime/firebase/token/trading'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -28,13 +27,13 @@ describe('Token minting', () => { }); it('Should credit sell order, storage deposit unlock condition', async () => { - mockWalletReturnValue(helper.walletSpy, helper.seller!, { + mockWalletReturnValue(helper.seller!, { symbol: helper.token!.symbol, count: 10, price: MIN_IOTA_AMOUNT, type: TokenTradeOrderType.SELL, }); - const sellOrder: Transaction = await testEnv.wrap(tradeToken)({}); + const sellOrder: Transaction = await testEnv.wrap(WEN_FUNC.tradeToken); await helper.walletService!.send(helper.sellerAddress!, sellOrder.payload.targetAddress!, 0, { nativeTokens: [{ amount: BigInt(10), id: helper.token!.mintingData?.tokenId! }], storageDepositReturnAddress: helper.sellerAddress?.bech32, @@ -44,7 +43,7 @@ describe('Token minting', () => { .where('type', '==', TransactionType.CREDIT) .where('member', '==', helper.seller); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return ( snap.length === 1 && snap[0]!.ignoreWalletReason === @@ -52,15 +51,15 @@ describe('Token minting', () => { snap[0]!.payload.targetAddress === helper.sellerAddress!.bech32 ); }); - const snap = await query.get(); - mockWalletReturnValue(helper.walletSpy, helper.seller!, { + const snap = await query.get(); + mockWalletReturnValue(helper.seller!, { transaction: snap[0].uid, }); - const order = await testEnv.wrap(creditUnrefundable)({}); + const order = await testEnv.wrap(WEN_FUNC.creditUnrefundable); await requestFundsFromFaucet(helper.network, order.payload.targetAddress, order.payload.amount); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1 && snap[0]!.payload?.walletReference?.confirmed; }); const creditStorageTran = ( @@ -72,7 +71,7 @@ describe('Token minting', () => { .get() )[0] ); - const creditSnap = await query.get(); + const creditSnap = await query.get(); expect(creditSnap[0]!.payload?.walletReference?.chainReference).toBe( creditStorageTran.payload.walletReference?.chainReference, ); @@ -97,13 +96,13 @@ describe('Token minting', () => { }); it('Shoult credit second unlock credit', async () => { - mockWalletReturnValue(helper.walletSpy, helper.seller!, { + mockWalletReturnValue(helper.seller!, { symbol: helper.token!.symbol, count: 10, price: MIN_IOTA_AMOUNT, type: TokenTradeOrderType.SELL, }); - const sellOrder: Transaction = await testEnv.wrap(tradeToken)({}); + const sellOrder: Transaction = await testEnv.wrap(WEN_FUNC.tradeToken); await helper.walletService!.send(helper.sellerAddress!, sellOrder.payload.targetAddress!, 0, { nativeTokens: [{ amount: BigInt(10), id: helper.token!.mintingData?.tokenId! }], storageDepositReturnAddress: helper.sellerAddress?.bech32, @@ -113,7 +112,7 @@ describe('Token minting', () => { .where('type', '==', TransactionType.CREDIT) .where('member', '==', helper.seller); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return ( snap.length === 1 && snap[0]!.ignoreWalletReason === @@ -121,12 +120,12 @@ describe('Token minting', () => { snap[0]!.payload.targetAddress === helper.sellerAddress!.bech32 ); }); - const snap = await query.get(); - mockWalletReturnValue(helper.walletSpy, helper.seller!, { + const snap = await query.get(); + mockWalletReturnValue(helper.seller!, { transaction: snap[0].uid, }); - const order = await testEnv.wrap(creditUnrefundable)({}); - const order2 = await testEnv.wrap(creditUnrefundable)({}); + const order = await testEnv.wrap(WEN_FUNC.creditUnrefundable); + const order2 = await testEnv.wrap(WEN_FUNC.creditUnrefundable); await requestFundsFromFaucet(helper.network, order.payload.targetAddress, order.payload.amount); await requestFundsFromFaucet( @@ -144,9 +143,7 @@ describe('Token minting', () => { return snap.length == 2; }); - const transaction = ( - await build5Db().doc(`${COL.TRANSACTION}/${snap[0].uid}`).get() - ); + const transaction = await build5Db().doc(COL.TRANSACTION, snap[0].uid).get(); expect(transaction.payload.unlockedBy).toBeDefined(); }); }); diff --git a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_18.spec.ts b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_18.spec.ts index 70b5539338..cdf3818f87 100644 --- a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_18.spec.ts +++ b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_18.spec.ts @@ -43,7 +43,7 @@ describe('Minted toke trading tangle request', () => { }, }, }); - await build5Db().doc(`${COL.MNEMONIC}/${tmp.bech32}`).update({ consumedOutputIds: [] }); + await build5Db().doc(COL.MNEMONIC, tmp.bech32).update({ consumedOutputIds: [] }); const query = build5Db().collection(COL.TOKEN_MARKET).where('owner', '==', tmp.bech32); await wait(async () => { @@ -113,7 +113,7 @@ describe('Minted toke trading tangle request', () => { ); it('Should throw, trading disabled', async () => { - await build5Db().doc(`${COL.TOKEN}/${helper.token!.uid}`).update({ tradingDisabled: true }); + await build5Db().doc(COL.TOKEN, helper.token!.uid).update({ tradingDisabled: true }); const tmp = await helper.walletService!.getNewIotaAddressDetails(); await requestFundsFromFaucet(Network.RMS, tmp.bech32, 10 * MIN_IOTA_AMOUNT); @@ -127,7 +127,7 @@ describe('Minted toke trading tangle request', () => { }, }, }); - await build5Db().doc(`${COL.MNEMONIC}/${tmp.bech32}`).update({ consumedOutputIds: [] }); + await build5Db().doc(COL.MNEMONIC, tmp.bech32).update({ consumedOutputIds: [] }); const creditQuery = build5Db() .collection(COL.TRANSACTION) diff --git a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_19.spec.ts b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_19.spec.ts index 7f46b009d2..0592ee2dc2 100644 --- a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_19.spec.ts +++ b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_19.spec.ts @@ -1,11 +1,4 @@ -import { - COL, - MIN_IOTA_AMOUNT, - Network, - TangleRequestType, - TokenTradeOrder, - Transaction, -} from '@build-5/interfaces'; +import { COL, MIN_IOTA_AMOUNT, Network, TangleRequestType, Transaction } from '@build-5/interfaces'; import { build5Db } from '@build-5/database'; import { wait } from '../../test/controls/common'; @@ -75,26 +68,28 @@ describe('Minted toke trading tangle request', () => { }, ); - let query = build5Db().collection(COL.TOKEN_MARKET).where('owner', '==', helper.seller); + const queryBySeller = build5Db() + .collection(COL.TOKEN_MARKET) + .where('owner', '==', helper.seller); await wait(async () => { - const snap = await query.get(); + const snap = await queryBySeller.get(); return snap.length > 0; }); - const sell = (await query.get())[0]!; + const sell = (await queryBySeller.get())[0]!; - query = build5Db().collection(COL.TOKEN_MARKET).where('owner', '==', helper.buyer); + const queryByOwner = build5Db().collection(COL.TOKEN_MARKET).where('owner', '==', helper.buyer); await wait(async () => { - const snap = await query.get(); + const snap = await queryByOwner.get(); return snap.length > 0; }); - const buy = (await query.get())[0]!; + const buy = (await queryByOwner.get())[0]!; - query = build5Db() + const queryByTrade = build5Db() .collection(COL.TOKEN_PURCHASE) .where('sell', '==', sell.uid) .where('buy', '==', buy.uid); await wait(async () => { - const snap = await query.get(); + const snap = await queryByTrade.get(); return snap.length > 0; }); diff --git a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_2.spec.ts b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_2.spec.ts index 26c5d9c45e..150b893d12 100644 --- a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_2.spec.ts +++ b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_2.spec.ts @@ -29,8 +29,8 @@ describe('Token minting', () => { const billPaymentsQuery = build5Db() .collection(COL.TRANSACTION) - .where('member', 'in', [helper.seller, helper.buyer]) - .where('type', '==', TransactionType.BILL_PAYMENT); + .where('type', '==', TransactionType.BILL_PAYMENT) + .whereIn('member', [helper.seller, helper.buyer]); await wait(async () => { const snap = await billPaymentsQuery.get(); return snap.length === 4; @@ -43,7 +43,7 @@ describe('Token minting', () => { expect(paymentToSeller.payload.amount).toBe(9602600); expect(paymentToSeller.payload.sourceAddress).toBe(buyOrder.payload.targetAddress); - expect(paymentToSeller.payload.storageReturn).toBeUndefined(); + expect(paymentToSeller.payload.storageReturn).toEqual({}); const royaltyOnePayment = billPayments.find((bp) => bp.payload.amount === 271800)!; expect(royaltyOnePayment.payload.storageReturn!.address).toBe(helper.sellerAddress!.bech32); diff --git a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_20.spec.ts b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_20.spec.ts index 2e0c137397..67e68ae62b 100644 --- a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_20.spec.ts +++ b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_20.spec.ts @@ -9,13 +9,12 @@ import { TokenTradeOrderType, Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { creditUnrefundable } from '../../src/runtime/firebase/credit/index'; -import { tradeToken } from '../../src/runtime/firebase/token/trading'; import { dateToTimestamp } from '../../src/utils/dateTime.utils'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; describe('Token minting', () => { @@ -30,13 +29,13 @@ describe('Token minting', () => { }); it('Should not create sell order, storage deposit unlock condition, also not claimable', async () => { - mockWalletReturnValue(helper.walletSpy, helper.seller!, { + mockWalletReturnValue(helper.seller!, { symbol: helper.token!.symbol, count: 10, price: MIN_IOTA_AMOUNT, type: TokenTradeOrderType.SELL, }); - const sellOrder: Transaction = await testEnv.wrap(tradeToken)({}); + const sellOrder: Transaction = await testEnv.wrap(WEN_FUNC.tradeToken); await helper.walletService!.send(helper.sellerAddress!, sellOrder.payload.targetAddress!, 0, { nativeTokens: [{ amount: BigInt(10), id: helper.token!.mintingData?.tokenId! }], storageDepositReturnAddress: helper.sellerAddress?.bech32, @@ -50,7 +49,7 @@ describe('Token minting', () => { .where('type', '==', TransactionType.CREDIT) .where('member', '==', helper.seller); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return ( snap.length === 1 && snap[0].ignoreWalletReason === @@ -59,9 +58,10 @@ describe('Token minting', () => { ); }); - const snap = await query.get(); - mockWalletReturnValue(helper.walletSpy, helper.seller!, { transaction: snap[0].uid }); - const order = await testEnv.wrap(creditUnrefundable)({}); + const snap = await query.get(); + mockWalletReturnValue(helper.seller!, { transaction: snap[0].uid }); + let order = await testEnv.wrap(WEN_FUNC.creditUnrefundable); + order = (await build5Db().doc(COL.TRANSACTION, order.uid).get())!; const expiresOn = order.payload.expiresOn!; const isEarlier = dayjs(expiresOn.toDate()).isBefore(dayjs().add(TRANSACTION_AUTO_EXPIRY_MS)); diff --git a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_21.spec.ts b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_21.spec.ts index 1b089bf51e..ea52e9be29 100644 --- a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_21.spec.ts +++ b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_21.spec.ts @@ -5,7 +5,6 @@ import { MIN_IOTA_AMOUNT, Network, TangleRequestType, - TokenTradeOrder, TokenTradeOrderStatus, TokenTradeOrderType, Transaction, @@ -54,10 +53,10 @@ describe('Minted toke trading tangle request', () => { .where('owner', '==', tmp.bech32) .where('type', '==', TokenTradeOrderType.BUY); await wait(async () => { - const snap = await buyQuery.get(); + const snap = await buyQuery.get(); return snap.length === 1 && snap[0].status === TokenTradeOrderStatus.SETTLED; }); - const buyOrder = (await buyQuery.get())[0]; + const buyOrder = (await buyQuery.get())[0]; expect(buyOrder.count).toBe(MAX_TOTAL_TOKEN_SUPPLY); expect(buyOrder.fulfilled).toBe(15); @@ -67,7 +66,7 @@ describe('Minted toke trading tangle request', () => { .collection(COL.TOKEN_MARKET) .where('owner', '==', helper.seller) .where('type', '==', TokenTradeOrderType.SELL) - .get(); + .get(); sellOrders.sort((a, b) => a.price - b.price); expect(sellOrders[0].price).toBe(MIN_IOTA_AMOUNT); diff --git a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_22.spec.ts b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_22.spec.ts index 51f6e72a80..88aeb963e9 100644 --- a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_22.spec.ts +++ b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_22.spec.ts @@ -5,7 +5,6 @@ import { MIN_IOTA_AMOUNT, Network, TangleRequestType, - TokenTradeOrder, TokenTradeOrderStatus, TokenTradeOrderType, Transaction, @@ -49,10 +48,10 @@ describe('Minted toke trading tangle request', () => { .where('owner', '==', tmp.bech32) .where('type', '==', TokenTradeOrderType.BUY); await wait(async () => { - const snap = await buyQuery.get(); + const snap = await buyQuery.get(); return snap.length === 1 && snap[0].fulfilled === 3; }); - const buyOrder = (await buyQuery.get())[0]; + const buyOrder = (await buyQuery.get())[0]; expect(buyOrder.count).toBe(MAX_TOTAL_TOKEN_SUPPLY); expect(buyOrder.fulfilled).toBe(3); @@ -63,7 +62,7 @@ describe('Minted toke trading tangle request', () => { .collection(COL.TOKEN_MARKET) .where('owner', '==', helper.seller) .where('type', '==', TokenTradeOrderType.SELL) - .get(); + .get(); sellOrders.sort((a, b) => a.price - b.price); expect(sellOrders[0].price).toBe(MIN_IOTA_AMOUNT); diff --git a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_23.spec.ts b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_23.spec.ts index 53d59d6be0..8dbc740406 100644 --- a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_23.spec.ts +++ b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_23.spec.ts @@ -5,7 +5,6 @@ import { MIN_PRICE_PER_TOKEN, Network, TangleRequestType, - TokenTradeOrder, TokenTradeOrderStatus, TokenTradeOrderType, Transaction, @@ -51,10 +50,10 @@ describe('Minted toke trading tangle request', () => { .where('owner', '==', helper.seller!) .where('type', '==', TokenTradeOrderType.SELL); await wait(async () => { - const snap = await sellQuery.get(); + const snap = await sellQuery.get(); return snap.length === 1 && snap[0].status === TokenTradeOrderStatus.SETTLED; }); - const sellOrder = (await sellQuery.get())[0]; + const sellOrder = (await sellQuery.get())[0]; expect(sellOrder.count).toBe(3); expect(sellOrder.fulfilled).toBe(3); @@ -65,7 +64,7 @@ describe('Minted toke trading tangle request', () => { .collection(COL.TOKEN_MARKET) .where('owner', '==', helper.buyer!) .where('type', '==', TokenTradeOrderType.BUY) - .get(); + .get(); buyOrders.sort((a, b) => b.price - a.price); expect(buyOrders[0].price).toBe(2 * MIN_IOTA_AMOUNT); diff --git a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_24.spec.ts b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_24.spec.ts index dd2e44f480..ed5e6909d4 100644 --- a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_24.spec.ts +++ b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_24.spec.ts @@ -4,7 +4,6 @@ import { MIN_IOTA_AMOUNT, Network, TangleRequestType, - TokenTradeOrder, TokenTradeOrderType, Transaction, } from '@build-5/interfaces'; @@ -49,10 +48,10 @@ describe('Minted toke trading tangle request', () => { .where('owner', '==', helper.seller!) .where('type', '==', TokenTradeOrderType.SELL); await wait(async () => { - const snap = await sellQuery.get(); + const snap = await sellQuery.get(); return snap.length === 1 && snap[0].fulfilled === 3; }); - const sellOrder = (await sellQuery.get())[0]; + const sellOrder = (await sellQuery.get())[0]; expect(sellOrder.count).toBe(4); expect(sellOrder.fulfilled).toBe(3); @@ -62,7 +61,7 @@ describe('Minted toke trading tangle request', () => { .collection(COL.TOKEN_MARKET) .where('owner', '==', helper.buyer!) .where('type', '==', TokenTradeOrderType.BUY) - .get(); + .get(); buyOrders.sort((a, b) => b.price - a.price); expect(buyOrders[0].price).toBe(2 * MIN_IOTA_AMOUNT); diff --git a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_2_b.spec.ts b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_2_b.spec.ts index c7a4c73687..aa696c942c 100644 --- a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_2_b.spec.ts +++ b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_2_b.spec.ts @@ -34,7 +34,7 @@ describe('Token minting', () => { .collection(COL.TOKEN_MARKET) .where('orderTransactionId', '==', buyOrder.uid); await wait(async () => { - const buySnap = await buyQuery.get(); + const buySnap = await buyQuery.get(); return buySnap[0].fulfilled === 99; }); let buy = (await buyQuery.get())[0] as TokenTradeOrder; @@ -48,7 +48,7 @@ describe('Token minting', () => { .collection(COL.TOKEN_MARKET) .where('orderTransactionId', '==', buyOrder2.uid); await wait(async () => { - const buySnap = await buyQuery2.get(); + const buySnap = await buyQuery2.get(); return buySnap[0].fulfilled === 1; }); diff --git a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_3.spec.ts b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_3.spec.ts index 2840f64806..116a467d8c 100644 --- a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_3.spec.ts +++ b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_3.spec.ts @@ -10,14 +10,14 @@ import { TokenTradeOrderType, Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; import { cancelExpiredSale } from '../../src/cron/token.cron'; -import { tradeToken } from '../../src/runtime/firebase/token/trading'; import { getAddress } from '../../src/utils/address.utils'; import { dateToTimestamp } from '../../src/utils/dateTime.utils'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken } from '../common'; import { Helper } from './Helper'; @@ -61,7 +61,7 @@ describe('Token minting', () => { } const member = await build5Db() - .doc(`${COL.MEMBER}/${type === TokenTradeOrderType.SELL ? helper.seller! : helper.buyer!}`) + .doc(COL.MEMBER, type === TokenTradeOrderType.SELL ? helper.seller! : helper.buyer!) .get(); const tradeQuery = build5Db().collection(COL.TOKEN_MARKET).where('owner', '==', member.uid); @@ -73,8 +73,8 @@ describe('Token minting', () => { expect(dayjs(trade.expiresAt.toDate()).isSame(dayjs(expiresAt.toDate()))).toBe(true); await build5Db() - .doc(`${COL.TOKEN_MARKET}/${trade.uid}`) - .update({ expiresAt: dateToTimestamp(dayjs().subtract(1, 'm').toDate()) }); + .doc(COL.TOKEN_MARKET, trade.uid) + .update({ expiresAt: dayjs().subtract(1, 'm').toDate() }); await cancelExpiredSale(); await wait(async () => { @@ -82,7 +82,7 @@ describe('Token minting', () => { .collection(COL.TRANSACTION) .where('type', '==', TransactionType.CREDIT) .where('member', '==', member.uid) - .get(); + .get(); return ( snap.length === 1 && snap[0]!.payload.targetAddress === getAddress(member, helper.network) ); @@ -94,16 +94,16 @@ describe('Token minting', () => { const date = dayjs().add(2, 'h').millisecond(0).toDate(); const expiresAt = dateToTimestamp(date) as Timestamp; - mockWalletReturnValue(helper.walletSpy, helper.seller!, { + mockWalletReturnValue(helper.seller!, { symbol: helper.token!.symbol, count: 10, price: MIN_IOTA_AMOUNT, type: TokenTradeOrderType.SELL, }); - const sellOrder: Transaction = await testEnv.wrap(tradeToken)({}); + const sellOrder: Transaction = await testEnv.wrap(WEN_FUNC.tradeToken); await build5Db() - .doc(`${COL.TRANSACTION}/${sellOrder.uid}`) - .update({ 'payload.expiresOn': dateToTimestamp(dayjs().subtract(2, 'h').toDate()) }); + .doc(COL.TRANSACTION, sellOrder.uid) + .update({ payload_expiresOn: dayjs().subtract(2, 'h').toDate() }); await helper.walletService!.send(helper.sellerAddress!, sellOrder.payload.targetAddress!, 0, { nativeTokens: [{ amount: BigInt(10), id: helper.token!.mintingData?.tokenId! }], @@ -120,7 +120,7 @@ describe('Token minting', () => { .collection(COL.TRANSACTION) .where('type', '==', TransactionType.CREDIT) .where('member', '==', helper.seller) - .get(); + .get(); return ( snap.length === 1 && snap[0]!.payload.walletReference?.confirmed && diff --git a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_4.spec.ts b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_4.spec.ts index ed1b731aaa..8bbdca3c1f 100644 --- a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_4.spec.ts +++ b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_4.spec.ts @@ -7,10 +7,9 @@ import { TokenTradeOrder, Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; -import { cancelTradeOrder } from '../../src/runtime/firebase/token/trading'; -import { mockWalletReturnValue } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken } from '../common'; import { Helper } from './Helper'; @@ -30,8 +29,8 @@ describe('Token minting', () => { const query = build5Db().collection(COL.TOKEN_MARKET).where('owner', '==', helper.seller); const sell = (await query.get())[0]; - mockWalletReturnValue(helper.walletSpy, helper.seller!, { uid: sell.uid }); - await testEnv.wrap(cancelTradeOrder)({}); + mockWalletReturnValue(helper.seller!, { uid: sell.uid }); + await testEnv.wrap(WEN_FUNC.cancelTradeOrder); const sellerCreditSnap = await build5Db() .collection(COL.TRANSACTION) diff --git a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_5.spec.ts b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_5.spec.ts index 465fe5b1d8..fd0a93f3f1 100644 --- a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_5.spec.ts +++ b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_5.spec.ts @@ -6,12 +6,10 @@ import { CreditPaymentReason, MIN_IOTA_AMOUNT, TokenTradeOrder, - Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; -import { cancelTradeOrder } from '../../src/runtime/firebase/token/trading'; -import { mockWalletReturnValue } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken } from '../common'; import { Helper } from './Helper'; @@ -31,14 +29,14 @@ describe('Token minting', () => { const query = build5Db().collection(COL.TOKEN_MARKET).where('owner', '==', helper.buyer); const buy = (await query.get())[0]; - mockWalletReturnValue(helper.walletSpy, helper.buyer!, { uid: buy.uid }); - await testEnv.wrap(cancelTradeOrder)({}); + mockWalletReturnValue(helper.buyer!, { uid: buy.uid }); + await testEnv.wrap(WEN_FUNC.cancelTradeOrder); const buyerCreditnap = await build5Db() .collection(COL.TRANSACTION) .where('member', '==', helper.buyer) .where('type', '==', TransactionType.CREDIT) - .get(); + .get(); expect(buyerCreditnap.length).toBe(1); expect(buyerCreditnap[0]?.payload?.amount).toBe(10 * MIN_IOTA_AMOUNT); expect(buyerCreditnap[0]?.payload?.reason).toBe(CreditPaymentReason.TRADE_CANCELLED); diff --git a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_6.spec.ts b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_6.spec.ts index 3122747175..ab8424740b 100644 --- a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_6.spec.ts +++ b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_6.spec.ts @@ -8,10 +8,10 @@ import { TokenTradeOrder, Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; -import { cancelTradeOrder } from '../../src/runtime/firebase/token/trading'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken } from '../common'; import { Helper } from './Helper'; @@ -37,13 +37,13 @@ describe('Token minting', () => { }); const buy = (await query.get())[0]; - mockWalletReturnValue(helper.walletSpy, helper.buyer!, { uid: buy.uid }); - await testEnv.wrap(cancelTradeOrder)({}); + mockWalletReturnValue(helper.buyer!, { uid: buy.uid }); + await testEnv.wrap(WEN_FUNC.cancelTradeOrder); const billPaymentsQuery = build5Db() .collection(COL.TRANSACTION) - .where('member', 'in', [helper.seller, helper.buyer]) - .where('type', '==', TransactionType.BILL_PAYMENT); + .where('type', '==', TransactionType.BILL_PAYMENT) + .whereIn('member', [helper.seller, helper.buyer]); await wait(async () => { const snap = await billPaymentsQuery.get(); return snap.length === 4; @@ -55,7 +55,7 @@ describe('Token minting', () => { )!; expect(paymentToSeller.payload.amount).toBe(4727600); expect(paymentToSeller.payload.sourceAddress).toBe(buyOrder.payload.targetAddress); - expect(paymentToSeller.payload.storageReturn).toBeUndefined(); + expect(paymentToSeller.payload.storageReturn).toEqual({}); const royaltyOnePayment = billPayments.find((bp) => bp.payload.amount === 159300)!; expect(royaltyOnePayment.payload.storageReturn!.address).toBe(helper.sellerAddress!.bech32); diff --git a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_7.spec.ts b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_7.spec.ts index 28ec8fc8e3..d728f2cd26 100644 --- a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_7.spec.ts +++ b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_7.spec.ts @@ -8,10 +8,10 @@ import { TokenTradeOrder, Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; -import { cancelTradeOrder } from '../../src/runtime/firebase/token/trading'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken } from '../common'; import { Helper } from './Helper'; @@ -38,13 +38,13 @@ describe('Token minting', () => { await awaitTransactionConfirmationsForToken(helper.token!.uid); const sell = (await query.get())[0]; - mockWalletReturnValue(helper.walletSpy, helper.seller!, { uid: sell.uid }); - await testEnv.wrap(cancelTradeOrder)({}); + mockWalletReturnValue(helper.seller!, { uid: sell.uid }); + await testEnv.wrap(WEN_FUNC.cancelTradeOrder); const billPaymentsQuery = build5Db() .collection(COL.TRANSACTION) - .where('member', 'in', [helper.seller, helper.buyer]) - .where('type', '==', TransactionType.BILL_PAYMENT); + .where('type', '==', TransactionType.BILL_PAYMENT) + .whereIn('member', [helper.seller, helper.buyer]); await wait(async () => { const snap = await billPaymentsQuery.get(); return snap.length === 4; @@ -56,7 +56,7 @@ describe('Token minting', () => { )!; expect(paymentToSeller.payload.amount).toBe(4727600); expect(paymentToSeller.payload.sourceAddress).toBe(buyOrder.payload.targetAddress); - expect(paymentToSeller.payload.storageReturn).toBeUndefined(); + expect(paymentToSeller.payload.storageReturn).toEqual({}); const royaltyOnePayment = billPayments.find((bp) => bp.payload.amount === 159300)!; expect(royaltyOnePayment.payload.storageReturn!.address).toBe(helper.sellerAddress!.bech32); diff --git a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_8.spec.ts b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_8.spec.ts index 2c82c047ef..4ef8e8a287 100644 --- a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_8.spec.ts +++ b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_8.spec.ts @@ -1,10 +1,16 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { build5Db } from '@build-5/database'; -import { COL, MIN_IOTA_AMOUNT, TokenTradeOrderType, WenError } from '@build-5/interfaces'; -import { tradeToken } from '../../src/runtime/firebase/token/trading'; -import { expectThrow, mockWalletReturnValue } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { + COL, + MIN_IOTA_AMOUNT, + TokenTradeOrderType, + Transaction, + WEN_FUNC, + WenError, +} from '@build-5/interfaces'; +import { expectThrow } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken } from '../common'; import { Helper } from './Helper'; @@ -21,52 +27,50 @@ describe('Token minting', () => { it('Should create sell order, not approved, but public', async () => { // Should throw at sell, not approved, not public - await build5Db() - .doc(`${COL.TOKEN}/${helper.token!.uid}`) - .update({ approved: false, public: false }); - mockWalletReturnValue(helper.walletSpy, helper.seller!, { + await build5Db().doc(COL.TOKEN, helper.token!.uid).update({ approved: false, public: false }); + mockWalletReturnValue(helper.seller!, { symbol: helper.token!.symbol, count: 10, price: MIN_IOTA_AMOUNT, type: TokenTradeOrderType.SELL, }); - await expectThrow(testEnv.wrap(tradeToken)({}), WenError.token_does_not_exist.key); + await expectThrow( + testEnv.wrap(WEN_FUNC.tradeToken), + WenError.token_does_not_exist.key, + ); // Should throw at buy, not approved, not public - await build5Db() - .doc(`${COL.TOKEN}/${helper.token!.uid}`) - .update({ approved: false, public: false }); - mockWalletReturnValue(helper.walletSpy, helper.buyer!, { + await build5Db().doc(COL.TOKEN, helper.token!.uid).update({ approved: false, public: false }); + mockWalletReturnValue(helper.buyer!, { symbol: helper.token!.symbol, count: 5, price: MIN_IOTA_AMOUNT, type: TokenTradeOrderType.BUY, }); - await expectThrow(testEnv.wrap(tradeToken)({}), WenError.token_does_not_exist.key); + await expectThrow( + testEnv.wrap(WEN_FUNC.tradeToken), + WenError.token_does_not_exist.key, + ); // Should create sell order, not approved, but public - await build5Db() - .doc(`${COL.TOKEN}/${helper.token!.uid}`) - .update({ approved: false, public: true }); - mockWalletReturnValue(helper.walletSpy, helper.seller!, { + await build5Db().doc(COL.TOKEN, helper.token!.uid).update({ approved: false, public: true }); + mockWalletReturnValue(helper.seller!, { symbol: helper.token!.symbol, count: 10, price: MIN_IOTA_AMOUNT, type: TokenTradeOrderType.SELL, }); - expect(await testEnv.wrap(tradeToken)({})).toBeDefined(); + expect(await testEnv.wrap(WEN_FUNC.tradeToken)).toBeDefined(); // Should create buy order, not approved, but public' - await build5Db() - .doc(`${COL.TOKEN}/${helper.token!.uid}`) - .update({ approved: false, public: true }); - mockWalletReturnValue(helper.walletSpy, helper.seller!, { + await build5Db().doc(COL.TOKEN, helper.token!.uid).update({ approved: false, public: true }); + mockWalletReturnValue(helper.seller!, { symbol: helper.token!.symbol, count: 10, price: MIN_IOTA_AMOUNT, type: TokenTradeOrderType.BUY, }); - expect(await testEnv.wrap(tradeToken)({})).toBeDefined(); + expect(await testEnv.wrap(WEN_FUNC.tradeToken)).toBeDefined(); await awaitTransactionConfirmationsForToken(helper.token!.uid); }); diff --git a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_9.spec.ts b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_9.spec.ts index 8dc60fc7e6..20cd1946cd 100644 --- a/packages/functions/test-tangle/minted-token-trade/minted-token-trade_9.spec.ts +++ b/packages/functions/test-tangle/minted-token-trade/minted-token-trade_9.spec.ts @@ -7,11 +7,11 @@ import { TokenTradeOrderType, Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; -import { tradeToken } from '../../src/runtime/firebase/token/trading'; import { packBasicOutput } from '../../src/utils/basic-output.utils'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken } from '../common'; import { Helper, MINTED_TOKEN_ID, dummyTokenId, saveToken } from './Helper'; @@ -33,14 +33,14 @@ describe('Token minting', () => { helper.walletService!, dummyTokenId, ); - mockWalletReturnValue(helper.walletSpy, helper.seller!, { + mockWalletReturnValue(helper.seller!, { symbol: dummyToken.symbol, count: 10, price: MIN_IOTA_AMOUNT, type: TokenTradeOrderType.SELL, }); - const sellOrder = await testEnv.wrap(tradeToken)({}); - await helper.walletService!.send(helper.sellerAddress!, sellOrder.payload.targetAddress, 0, { + const sellOrder = await testEnv.wrap(WEN_FUNC.tradeToken); + await helper.walletService!.send(helper.sellerAddress!, sellOrder.payload.targetAddress!, 0, { nativeTokens: [{ amount: BigInt(10), id: helper.token!.mintingData?.tokenId! }], }); @@ -56,7 +56,7 @@ describe('Token minting', () => { const credit = snap[0]; const output = await packBasicOutput( helper.walletService!, - sellOrder.payload.targetAddress, + sellOrder.payload.targetAddress!, 0, { nativeTokens: [{ amount: BigInt(10), id: helper.token!.mintingData?.tokenId! }], diff --git a/packages/functions/test-tangle/nft-bid/Helper.ts b/packages/functions/test-tangle/nft-bid/Helper.ts index cc4120384f..840d867e0f 100644 --- a/packages/functions/test-tangle/nft-bid/Helper.ts +++ b/packages/functions/test-tangle/nft-bid/Helper.ts @@ -2,8 +2,8 @@ import { build5Db } from '@build-5/database'; import { Access, - Categories, COL, + Categories, Collection, CollectionStatus, CollectionType, @@ -17,27 +17,19 @@ import { Transaction, TransactionType, UnsoldMintingOptions, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { createCollection, mintCollection } from '../../src/runtime/firebase/collection/index'; -import { createNft, orderNft, setForSaleNft } from '../../src/runtime/firebase/nft/index'; import { NftWallet } from '../../src/services/wallet/NftWallet'; import { Wallet } from '../../src/services/wallet/wallet'; import { AddressDetails } from '../../src/services/wallet/wallet.service'; import { serverTime } from '../../src/utils/dateTime.utils'; import * as wallet from '../../src/utils/wallet.utils'; -import { - createMember as createMemberTest, - createSpace, - mockWalletReturnValue, - submitMilestoneFunc, - wait, -} from '../../test/controls/common'; -import { getWallet, MEDIA, testEnv } from '../../test/set-up'; +import { submitMilestoneFunc, wait } from '../../test/controls/common'; +import { MEDIA, getWallet, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; export class Helper { - public walletSpy: any = {} as any; public network = Network.RMS; public collection: string = {} as any; public guardian: string = {} as any; @@ -49,47 +41,45 @@ export class Helper { public nft: Nft = {} as any; public beforeAll = async () => { - this.walletSpy = jest.spyOn(wallet, 'decodeAuth'); this.walletService = await getWallet(this.network); this.nftWallet = new NftWallet(this.walletService); }; public beforeEach = async (collectionType = CollectionType.CLASSIC) => { - this.guardian = await createMemberTest(this.walletSpy); - this.member = await createMemberTest(this.walletSpy); - this.space = await createSpace(this.walletSpy, this.guardian); - this.royaltySpace = await createSpace(this.walletSpy, this.guardian); + this.guardian = await testEnv.createMember(); + this.member = await testEnv.createMember(); + this.space = await testEnv.createSpace(this.guardian); + this.royaltySpace = await testEnv.createSpace(this.guardian); mockWalletReturnValue( - this.walletSpy, this.guardian, this.createDummyCollection(this.space.uid, this.royaltySpace.uid, collectionType), ); - this.collection = (await testEnv.wrap(createCollection)({})).uid; + this.collection = (await testEnv.wrap(WEN_FUNC.createCollection)).uid; - await build5Db().doc(`${COL.COLLECTION}/${this.collection}`).update({ approved: true }); + await build5Db().doc(COL.COLLECTION, this.collection).update({ approved: true }); }; public mintCollection = async (expiresAt?: Timestamp) => { - mockWalletReturnValue(this.walletSpy, this.guardian!, { + mockWalletReturnValue(this.guardian!, { collection: this.collection, network: this.network, unsoldMintingOptions: UnsoldMintingOptions.KEEP_PRICE, }); - const collectionMintOrder = await testEnv.wrap(mintCollection)({}); + const collectionMintOrder = await testEnv.wrap(WEN_FUNC.mintCollection); await requestFundsFromFaucet( this.network!, collectionMintOrder.payload.targetAddress, collectionMintOrder.payload.amount, expiresAt, ); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${this.collection}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, this.collection); await wait(async () => { const data = await collectionDocRef.get(); return data.status === CollectionStatus.MINTED; }); - const nftDocRef = build5Db().doc(`${COL.NFT}/${this.nft?.uid}`); + const nftDocRef = build5Db().doc(COL.NFT, this.nft?.uid); this.nft = await nftDocRef.get(); }; @@ -98,42 +88,40 @@ export class Helper { delete nft.uid; delete nft.status; delete nft.placeholderNft; - mockWalletReturnValue(this.walletSpy, this.guardian!, nft); - nft = await testEnv.wrap(createNft)({}); + mockWalletReturnValue(this.guardian!, nft); + nft = await testEnv.wrap(WEN_FUNC.createNft); await build5Db() - .doc(`${COL.NFT}/${nft.uid}`) + .doc(COL.NFT, nft.uid) .update({ availableFrom: dayjs().subtract(1, 'h').toDate() }); if (shouldOrder) { - mockWalletReturnValue(this.walletSpy, this.guardian!, { + mockWalletReturnValue(this.guardian!, { collection: this.collection, nft: nft.uid, }); - const order = await testEnv.wrap(orderNft)({}); + const order = await testEnv.wrap(WEN_FUNC.orderNft); await submitMilestoneFunc(order); } - this.nft = await build5Db().doc(`${COL.NFT}/${nft.uid}`).get(); + this.nft = await build5Db().doc(COL.NFT, nft.uid).get(); return this.nft; }; public setAvailableForAuction = async (nft?: string) => { const uid = nft || this.nft?.uid!; - mockWalletReturnValue(this.walletSpy, this.guardian!, this.dummyAuctionData(uid)); - await testEnv.wrap(setForSaleNft)({}); + mockWalletReturnValue(this.guardian!, this.dummyAuctionData(uid)); + await testEnv.wrap(WEN_FUNC.setForSaleNft); await wait(async () => { - const docRef = build5Db().doc(`${COL.NFT}/${uid}`); + const docRef = build5Db().doc(COL.NFT, uid); this.nft = await docRef.get(); return this.nft.available === 3; }); }; public setAvailableForSale = async () => { - mockWalletReturnValue(this.walletSpy, this.guardian!, this.dummySaleData(this.nft!.uid)); - await testEnv.wrap(setForSaleNft)({}); - await wait( - async () => (await build5Db().doc(`${COL.NFT}/${this.nft!.uid}`).get())?.available === 1, - ); + mockWalletReturnValue(this.guardian!, this.dummySaleData(this.nft!.uid)); + await testEnv.wrap(WEN_FUNC.setForSaleNft); + await wait(async () => (await build5Db().doc(COL.NFT, this.nft!.uid).get())?.available === 1); }; public createDummyCollection = (space: string, royaltiesSpace: string, type: CollectionType) => ({ @@ -197,7 +185,7 @@ export class Helper { nftId, }, }; - await build5Db().doc(`${COL.TRANSACTION}/${order.uid}`).create(order); + await build5Db().doc(COL.TRANSACTION, order.uid).create(order); return order.uid; }; } 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 09ac011791..082323513d 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 @@ -3,7 +3,6 @@ import { COL, MIN_IOTA_AMOUNT, Network, - Nft, NftBidTangleRequest, TangleRequestType, Transaction, @@ -14,7 +13,6 @@ import dayjs from 'dayjs'; import { isEmpty } from 'lodash'; 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'; import { getTangleOrder } from '../common'; import { requestFundsFromFaucet } from '../faucet'; @@ -50,15 +48,15 @@ describe('Nft otr bid', () => { }, }); - const nftDocRef = build5Db().doc(`${COL.NFT}/${helper.nft!.uid}`); + const nftDocRef = build5Db().doc(COL.NFT, helper.nft!.uid); await wait(async () => { - const nft = await nftDocRef.get(); + const nft = await nftDocRef.get(); return !isEmpty(nft?.auctionHighestBidder); }); await build5Db() - .doc(`${COL.AUCTION}/${helper.nft!.auction}`) - .update({ auctionTo: dateToTimestamp(dayjs().subtract(1, 'm').toDate()) }); + .doc(COL.AUCTION, helper.nft!.auction!) + .update({ auctionTo: dayjs().subtract(1, 'm').toDate() }); await finalizeAuctions(); @@ -67,8 +65,8 @@ describe('Nft otr bid', () => { await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.WITHDRAW_NFT) - .where('payload.nft', '==', helper.nft!.uid) - .get() + .where('payload_nft', '==', helper.nft!.uid) + .get() )[0]; return transaction?.payload?.walletReference?.confirmed; }); 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 fc3ff949dc..1e400abb67 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 @@ -11,7 +11,6 @@ import { import dayjs from 'dayjs'; import { isEmpty } from 'lodash'; import { finalizeAuctions } from '../../src/cron/auction.cron'; -import { dateToTimestamp } from '../../src/utils/dateTime.utils'; import { wait } from '../../test/controls/common'; import { getTangleOrder } from '../common'; import { requestFundsFromFaucet } from '../faucet'; @@ -32,7 +31,7 @@ describe('Nft otr bid', () => { it('Should bid on minted nft with OTR, no withdraw', async () => { const address = await helper.walletService!.getNewIotaAddressDetails(); - requestFundsFromFaucet(Network.RMS, address.bech32, 5 * MIN_IOTA_AMOUNT); + await requestFundsFromFaucet(Network.RMS, address.bech32, 5 * MIN_IOTA_AMOUNT); await helper.createAndOrderNft(); await helper.mintCollection(); @@ -48,20 +47,20 @@ describe('Nft otr bid', () => { }, }); - const nftDocRef = build5Db().doc(`${COL.NFT}/${helper.nft!.uid}`); + const nftDocRef = build5Db().doc(COL.NFT, helper.nft!.uid); await wait(async () => { - const nft = await nftDocRef.get(); + const nft = await nftDocRef.get(); return !isEmpty(nft?.auctionHighestBidder); }); await build5Db() - .doc(`${COL.AUCTION}/${helper.nft!.auction}`) - .update({ auctionTo: dateToTimestamp(dayjs().subtract(1, 'm').toDate()) }); + .doc(COL.AUCTION, helper.nft!.auction!) + .update({ auctionTo: dayjs().subtract(1, 'm').toDate() }); await finalizeAuctions(); await wait(async () => { - const nft = await build5Db().doc(`${COL.NFT}/${helper.nft!.uid}`).get(); + const nft = await build5Db().doc(COL.NFT, helper.nft!.uid).get(); return nft.owner === address.bech32; }); }); 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 c499b3abb8..4de6e75e3f 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 @@ -13,7 +13,6 @@ import { isEmpty } from 'lodash'; 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'; import { wait } from '../../test/controls/common'; import { getWallet } from '../../test/set-up'; import { getTangleOrder } from '../common'; @@ -50,20 +49,20 @@ describe('Nft otr bid', () => { }, }); await MnemonicService.store(atoiAddress.bech32, atoiAddress.mnemonic, Network.RMS); - const nftDocRef = build5Db().doc(`${COL.NFT}/${helper.nft!.uid}`); + const nftDocRef = build5Db().doc(COL.NFT, helper.nft!.uid); await wait(async () => { - const nft = await nftDocRef.get(); + const nft = await nftDocRef.get(); return !isEmpty(nft?.auctionHighestBidder); }); await build5Db() - .doc(`${COL.AUCTION}/${helper.nft!.auction}`) - .update({ auctionTo: dateToTimestamp(dayjs().subtract(1, 'm').toDate()) }); + .doc(COL.AUCTION, helper.nft!.auction!) + .update({ auctionTo: dayjs().subtract(1, 'm').toDate() }); await finalizeAuctions(); await wait(async () => { - const nft = await build5Db().doc(`${COL.NFT}/${helper.nft!.uid}`).get(); + const nft = await build5Db().doc(COL.NFT, helper.nft!.uid).get(); return nft.owner === atoiAddress.bech32; }); }); 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 7fdffd94b0..2ad5c3b40b 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 @@ -11,7 +11,6 @@ import { } from '@build-5/interfaces'; import dayjs from 'dayjs'; import { finalizeAuctions } from '../../src/cron/auction.cron'; -import { dateToTimestamp } from '../../src/utils/dateTime.utils'; import { wait } from '../../test/controls/common'; import { getTangleOrder } from '../common'; import { requestFundsFromFaucet } from '../faucet'; @@ -60,15 +59,15 @@ describe('Nft otr bid', () => { }, }); - const nftDocRef = build5Db().doc(`${COL.NFT}/${helper.nft!.uid}`); + const nftDocRef = build5Db().doc(COL.NFT, helper.nft!.uid); await wait(async () => { helper.nft = await nftDocRef.get(); return helper.nft.auctionHighestBidder === address2.bech32; }); await build5Db() - .doc(`${COL.AUCTION}/${helper.nft!.auction}`) - .update({ auctionTo: dateToTimestamp(dayjs().subtract(1, 'm').toDate()) }); + .doc(COL.AUCTION, helper.nft!.auction!) + .update({ auctionTo: dayjs().subtract(1, 'm').toDate() }); await finalizeAuctions(); @@ -82,7 +81,7 @@ describe('Nft otr bid', () => { .where('type', '==', TransactionType.CREDIT) .where('member', '==', address1.bech32); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); }); diff --git a/packages/functions/test-tangle/nft-bulk/Helper.ts b/packages/functions/test-tangle/nft-bulk/Helper.ts index 4f19929b9f..b9371e4546 100644 --- a/packages/functions/test-tangle/nft-bulk/Helper.ts +++ b/packages/functions/test-tangle/nft-bulk/Helper.ts @@ -12,23 +12,15 @@ import { NetworkAddress, Nft, Space, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { createCollection } from '../../src/runtime/firebase/collection'; -import { createNft } from '../../src/runtime/firebase/nft'; 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 as createMemberTest, - createSpace, - mockWalletReturnValue, -} from '../../test/controls/common'; -import { getWallet, testEnv } from '../../test/set-up'; +import { getWallet, mockWalletReturnValue, testEnv } from '../../test/set-up'; export class Helper { - public walletSpy: any = {} as any; public member: string = {} as any; public memberAddress: AddressDetails = {} as any; public space: Space = {} as any; @@ -36,28 +28,27 @@ export class Helper { public member2: string = {} as any; public beforeEach = async () => { - this.walletSpy = jest.spyOn(wallet, 'decodeAuth'); - this.member = await createMemberTest(this.walletSpy); - this.member2 = await createMemberTest(this.walletSpy); - this.space = await createSpace(this.walletSpy, this.member); + this.member = await testEnv.createMember(); + this.member2 = await testEnv.createMember(); + this.space = await testEnv.createSpace(this.member); this.walletService = await getWallet(Network.ATOI); - const memberData = await build5Db().doc(`${COL.MEMBER}/${this.member}`).get(); + const memberData = await build5Db().doc(COL.MEMBER, this.member).get(); this.memberAddress = await this.walletService!.getAddressDetails( getAddress(memberData, Network.ATOI), ); }; - public createColletionAndNft = async ( + public createCollectionAndNft = async ( address: NetworkAddress, space: Space, type = CollectionType.CLASSIC, ) => { - mockWalletReturnValue(this.walletSpy, address, this.dummyCollection(space, type)); - const cCollection = await testEnv.wrap(createCollection)({}); + mockWalletReturnValue(address, this.dummyCollection(space, type)); + const cCollection = await testEnv.wrap(WEN_FUNC.createCollection); expect(cCollection?.uid).toBeDefined(); - await build5Db().doc(`${COL.COLLECTION}/${cCollection?.uid}`).update({ approved: true }); + await build5Db().doc(COL.COLLECTION, cCollection?.uid).update({ approved: true }); const collection = cCollection; const nft = await this.createNft(address, collection); @@ -65,8 +56,8 @@ export class Helper { }; public createNft = async (address: NetworkAddress, collection: Collection) => { - mockWalletReturnValue(this.walletSpy, address, this.dummyNft(collection)); - const nft = await testEnv.wrap(createNft)({}); + mockWalletReturnValue(address, this.dummyNft(collection)); + const nft = await testEnv.wrap(WEN_FUNC.createNft); expect(nft?.createdOn).toBeDefined(); return nft; }; diff --git a/packages/functions/test-tangle/nft-bulk/order.bulk_1.spec.ts b/packages/functions/test-tangle/nft-bulk/order.bulk_1.spec.ts index 88831d2ff4..98486bd8a5 100644 --- a/packages/functions/test-tangle/nft-bulk/order.bulk_1.spec.ts +++ b/packages/functions/test-tangle/nft-bulk/order.bulk_1.spec.ts @@ -1,8 +1,7 @@ import { build5Db } from '@build-5/database'; -import { COL, Nft, NftPurchaseBulkRequest, Transaction } from '@build-5/interfaces'; -import { orderNftBulk } from '../../src/runtime/firebase/nft'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { COL, Nft, NftPurchaseBulkRequest, Transaction, WEN_FUNC } from '@build-5/interfaces'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -14,8 +13,8 @@ describe('Nft bulk order', () => { }); it('Should order 2 nfts', async () => { - const { collection: col1, nft: nft1 } = await h.createColletionAndNft(h.member, h.space); - const { collection: col2, nft: nft2 } = await h.createColletionAndNft(h.member, h.space); + const { collection: col1, nft: nft1 } = await h.createCollectionAndNft(h.member, h.space); + const { collection: col2, nft: nft2 } = await h.createCollectionAndNft(h.member, h.space); const request: NftPurchaseBulkRequest = { orders: [ @@ -23,8 +22,8 @@ describe('Nft bulk order', () => { { collection: col2.uid, nft: nft2.uid }, ], }; - mockWalletReturnValue(h.walletSpy, h.member, request); - const order: Transaction = await testEnv.wrap(orderNftBulk)({}); + mockWalletReturnValue(h.member, request); + const order = await testEnv.wrap(WEN_FUNC.orderNftBulk); await requestFundsFromFaucet( order.network, @@ -32,8 +31,8 @@ describe('Nft bulk order', () => { order.payload.amount!, ); - const nft1DocRef = build5Db().doc(`${COL.NFT}/${nft1.uid}`); - const nft2DocRef = build5Db().doc(`${COL.NFT}/${nft2.uid}`); + const nft1DocRef = build5Db().doc(COL.NFT, nft1.uid); + const nft2DocRef = build5Db().doc(COL.NFT, nft2.uid); await wait(async () => { const nft1 = await nft1DocRef.get(); const nft2 = await nft2DocRef.get(); diff --git a/packages/functions/test-tangle/nft-bulk/order.bulk_2.spec.ts b/packages/functions/test-tangle/nft-bulk/order.bulk_2.spec.ts index bcbd8d94dc..3159f9c986 100644 --- a/packages/functions/test-tangle/nft-bulk/order.bulk_2.spec.ts +++ b/packages/functions/test-tangle/nft-bulk/order.bulk_2.spec.ts @@ -6,10 +6,10 @@ import { NftPurchaseBulkRequest, Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; -import { orderNftBulk } from '../../src/runtime/firebase/nft'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -21,8 +21,8 @@ describe('Nft bulk order', () => { }); it('Should order 2 nfts, buy only one', async () => { - const { collection: col1, nft: nft1 } = await h.createColletionAndNft(h.member, h.space); - const { collection: col2, nft: nft2 } = await h.createColletionAndNft(h.member, h.space); + const { collection: col1, nft: nft1 } = await h.createCollectionAndNft(h.member, h.space); + const { collection: col2, nft: nft2 } = await h.createCollectionAndNft(h.member, h.space); const request: NftPurchaseBulkRequest = { orders: [ @@ -30,11 +30,11 @@ describe('Nft bulk order', () => { { collection: col2.uid, nft: nft2.uid }, ], }; - mockWalletReturnValue(h.walletSpy, h.member, request); - const order: Transaction = await testEnv.wrap(orderNftBulk)({}); + mockWalletReturnValue(h.member, request); + const order = await testEnv.wrap(WEN_FUNC.orderNftBulk); - const nft1DocRef = build5Db().doc(`${COL.NFT}/${nft1.uid}`); - const nft2DocRef = build5Db().doc(`${COL.NFT}/${nft2.uid}`); + const nft1DocRef = build5Db().doc(COL.NFT, nft1.uid); + const nft2DocRef = build5Db().doc(COL.NFT, nft2.uid); await nft2DocRef.update({ locked: true }); await requestFundsFromFaucet( @@ -53,10 +53,10 @@ describe('Nft bulk order', () => { .where('type', '==', TransactionType.CREDIT) .where('member', '==', h.member); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1; }); - const snap = await query.get(); + const snap = await query.get(); expect(snap[0].payload.amount).toBe(1 * MIN_IOTA_AMOUNT); }); }); diff --git a/packages/functions/test-tangle/nft-bulk/order.bulk_3.spec.ts b/packages/functions/test-tangle/nft-bulk/order.bulk_3.spec.ts index 51103f1083..dd317ff662 100644 --- a/packages/functions/test-tangle/nft-bulk/order.bulk_3.spec.ts +++ b/packages/functions/test-tangle/nft-bulk/order.bulk_3.spec.ts @@ -22,8 +22,8 @@ describe('Nft bulk order', () => { }); it('Should order 2 nfts with tangle order', async () => { - const { collection: col1, nft: nft1 } = await h.createColletionAndNft(h.member, h.space); - const { collection: col2, nft: nft2 } = await h.createColletionAndNft(h.member, h.space); + const { collection: col1, nft: nft1 } = await h.createCollectionAndNft(h.member, h.space); + const { collection: col2, nft: nft2 } = await h.createCollectionAndNft(h.member, h.space); await requestFundsFromFaucet(Network.ATOI, h.memberAddress.bech32, 2 * MIN_IOTA_AMOUNT); await h.walletService.send( @@ -43,8 +43,8 @@ describe('Nft bulk order', () => { }, ); - const nft1DocRef = build5Db().doc(`${COL.NFT}/${nft1.uid}`); - const nft2DocRef = build5Db().doc(`${COL.NFT}/${nft2.uid}`); + const nft1DocRef = build5Db().doc(COL.NFT, nft1.uid); + const nft2DocRef = build5Db().doc(COL.NFT, nft2.uid); await wait(async () => { const nft1 = await nft1DocRef.get(); diff --git a/packages/functions/test-tangle/nft-bulk/order.bulk_4.spec.ts b/packages/functions/test-tangle/nft-bulk/order.bulk_4.spec.ts index 88b7ece7ad..55b70c7ea9 100644 --- a/packages/functions/test-tangle/nft-bulk/order.bulk_4.spec.ts +++ b/packages/functions/test-tangle/nft-bulk/order.bulk_4.spec.ts @@ -1,8 +1,7 @@ import { build5Db } from '@build-5/database'; -import { COL, CollectionType, Nft, Transaction } from '@build-5/interfaces'; -import { orderNftBulk } from '../../src/runtime/firebase/nft'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { COL, CollectionType, Nft, Transaction, WEN_FUNC } from '@build-5/interfaces'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -14,9 +13,9 @@ describe('Nft bulk order', () => { }); it('Should order 2 nfts, 2 random', async () => { - const { collection: col1, nft: nft1 } = await h.createColletionAndNft(h.member, h.space); - const { collection: col2, nft: nft2 } = await h.createColletionAndNft(h.member, h.space); - const { collection: col3 } = await h.createColletionAndNft( + const { collection: col1, nft: nft1 } = await h.createCollectionAndNft(h.member, h.space); + const { collection: col2, nft: nft2 } = await h.createCollectionAndNft(h.member, h.space); + const { collection: col3 } = await h.createCollectionAndNft( h.member, h.space, CollectionType.GENERATED, @@ -33,8 +32,8 @@ describe('Nft bulk order', () => { { collection: col3.uid }, ], }; - mockWalletReturnValue(h.walletSpy, h.member, request); - const order: Transaction = await testEnv.wrap(orderNftBulk)({}); + mockWalletReturnValue(h.member, request); + const order = await testEnv.wrap(WEN_FUNC.orderNftBulk); await requestFundsFromFaucet( order.network, order.payload.targetAddress!, @@ -43,7 +42,7 @@ describe('Nft bulk order', () => { await wait(async () => { const promises = order.payload.nftOrders!.map(async (nftOrder) => { - const docRef = build5Db().doc(`${COL.NFT}/${nftOrder.nft}`); + const docRef = build5Db().doc(COL.NFT, nftOrder.nft); return await docRef.get(); }); const nfts = await Promise.all(promises); diff --git a/packages/functions/test-tangle/nft-bulk/order.bulk_5.spec.ts b/packages/functions/test-tangle/nft-bulk/order.bulk_5.spec.ts index fcaf44ea3f..533eca7b6d 100644 --- a/packages/functions/test-tangle/nft-bulk/order.bulk_5.spec.ts +++ b/packages/functions/test-tangle/nft-bulk/order.bulk_5.spec.ts @@ -24,8 +24,8 @@ describe('Nft bulk order', () => { }); it('Should order 2 nfts, buy only one with tangle', async () => { - const { collection: col1, nft: nft1 } = await h.createColletionAndNft(h.member, h.space); - const { collection: col2, nft: nft2 } = await h.createColletionAndNft(h.member, h.space); + const { collection: col1, nft: nft1 } = await h.createCollectionAndNft(h.member, h.space); + const { collection: col2, nft: nft2 } = await h.createCollectionAndNft(h.member, h.space); await requestFundsFromFaucet(Network.ATOI, h.memberAddress.bech32, 3 * MIN_IOTA_AMOUNT); await h.walletService.send( @@ -51,15 +51,15 @@ describe('Nft bulk order', () => { .where('member', '==', h.member) .where('type', '==', TransactionType.CREDIT_TANGLE_REQUEST); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1 && snap[0].payload.walletReference?.confirmed; }); - const nft1DocRef = build5Db().doc(`${COL.NFT}/${nft1.uid}`); - const nft2DocRef = build5Db().doc(`${COL.NFT}/${nft2.uid}`); + const nft1DocRef = build5Db().doc(COL.NFT, nft1.uid); + const nft2DocRef = build5Db().doc(COL.NFT, nft2.uid); await nft2DocRef.update({ locked: true }); - const credit = (await query.get())[0]; + const credit = (await query.get())[0]; await h.walletService.send( h.memberAddress, credit.payload.response!.address as string, @@ -76,11 +76,12 @@ describe('Nft bulk order', () => { .collection(COL.TRANSACTION) .where('type', '==', TransactionType.CREDIT) .where('member', '==', h.member); + await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1; }); - const snap = await query.get(); + const snap = await query.get(); expect(snap[0].payload.amount).toBe(1 * MIN_IOTA_AMOUNT); }); }); diff --git a/packages/functions/test-tangle/nft-bulk/order.bulk_6.spec.ts b/packages/functions/test-tangle/nft-bulk/order.bulk_6.spec.ts index 50eec9ae71..53bd004af1 100644 --- a/packages/functions/test-tangle/nft-bulk/order.bulk_6.spec.ts +++ b/packages/functions/test-tangle/nft-bulk/order.bulk_6.spec.ts @@ -24,10 +24,10 @@ describe('Nft bulk order', () => { }); it('Should order 2 nfts, only one available', async () => { - const { collection: col1, nft: nft1 } = await h.createColletionAndNft(h.member, h.space); - const { collection: col2, nft: nft2 } = await h.createColletionAndNft(h.member, h.space); - const nft1DocRef = build5Db().doc(`${COL.NFT}/${nft1.uid}`); - const nft2DocRef = build5Db().doc(`${COL.NFT}/${nft2.uid}`); + const { collection: col1, nft: nft1 } = await h.createCollectionAndNft(h.member, h.space); + const { collection: col2, nft: nft2 } = await h.createCollectionAndNft(h.member, h.space); + const nft1DocRef = build5Db().doc(COL.NFT, nft1.uid); + const nft2DocRef = build5Db().doc(COL.NFT, nft2.uid); await nft2DocRef.update({ locked: true }); await requestFundsFromFaucet(Network.ATOI, h.memberAddress.bech32, 2 * MIN_IOTA_AMOUNT); @@ -54,11 +54,11 @@ describe('Nft bulk order', () => { .where('member', '==', h.member) .where('type', '==', TransactionType.CREDIT_TANGLE_REQUEST); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1 && snap[0].payload.walletReference?.confirmed; }); - const credit = (await query.get())[0]; + const credit = (await query.get())[0]; expect(credit.payload.amount).toBe(2 * MIN_IOTA_AMOUNT); expect(credit.payload.response!.amount).toBe(MIN_IOTA_AMOUNT); await h.walletService.send( diff --git a/packages/functions/test-tangle/nft-set-for-sale/Helper.ts b/packages/functions/test-tangle/nft-set-for-sale/Helper.ts index c506f01905..6895beb40b 100644 --- a/packages/functions/test-tangle/nft-set-for-sale/Helper.ts +++ b/packages/functions/test-tangle/nft-set-for-sale/Helper.ts @@ -4,32 +4,26 @@ import { Access, Categories, COL, + Collection, CollectionType, - Member, MIN_IOTA_AMOUNT, Network, Nft, NftAccess, NftStatus, Space, + Transaction, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { createCollection } from '../../src/runtime/firebase/collection/index'; -import { createNft, orderNft } from '../../src/runtime/firebase/nft/index'; 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 as createMemberTest, - createSpace, - mockWalletReturnValue, - submitMilestoneFunc, -} from '../../test/controls/common'; -import { getWallet, MEDIA, testEnv } from '../../test/set-up'; +import { submitMilestoneFunc } from '../../test/controls/common'; +import { getWallet, MEDIA, mockWalletReturnValue, testEnv } from '../../test/set-up'; export class Helper { - public walletSpy: any = {} as any; public network = Network.RMS; public collection: string = {} as any; public guardian: string = {} as any; @@ -40,28 +34,26 @@ export class Helper { public nft: Nft = {} as any; public beforeAll = async () => { - this.walletSpy = jest.spyOn(wallet, 'decodeAuth'); this.walletService = await getWallet(this.network); }; public beforeEach = async (collectionType = CollectionType.CLASSIC) => { - this.guardian = await createMemberTest(this.walletSpy); - const guardianDocRef = build5Db().doc(`${COL.MEMBER}/${this.guardian}`); - const guardianData = await guardianDocRef.get(); + this.guardian = await testEnv.createMember(); + const guardianDocRef = build5Db().doc(COL.MEMBER, this.guardian); + const guardianData = await guardianDocRef.get(); const guardianBech32 = getAddress(guardianData, this.network); this.guardianAddress = await this.walletService.getAddressDetails(guardianBech32); - this.space = await createSpace(this.walletSpy, this.guardian); - this.royaltySpace = await createSpace(this.walletSpy, this.guardian); + this.space = await testEnv.createSpace(this.guardian); + this.royaltySpace = await testEnv.createSpace(this.guardian); mockWalletReturnValue( - this.walletSpy, this.guardian, this.createDummyCollection(this.space.uid, this.royaltySpace.uid, collectionType), ); - this.collection = (await testEnv.wrap(createCollection)({})).uid; + this.collection = (await testEnv.wrap(WEN_FUNC.createCollection)).uid; - await build5Db().doc(`${COL.COLLECTION}/${this.collection}`).update({ approved: true }); + await build5Db().doc(COL.COLLECTION, this.collection).update({ approved: true }); }; public createAndOrderNft = async (shouldOrder = true) => { @@ -69,22 +61,22 @@ export class Helper { delete nft.uid; delete nft.status; delete nft.placeholderNft; - mockWalletReturnValue(this.walletSpy, this.guardian!, nft); - nft = await testEnv.wrap(createNft)({}); + mockWalletReturnValue(this.guardian!, nft); + nft = await testEnv.wrap(WEN_FUNC.createNft); await build5Db() - .doc(`${COL.NFT}/${nft.uid}`) + .doc(COL.NFT, nft.uid) .update({ availableFrom: dayjs().subtract(1, 'h').toDate() }); if (shouldOrder) { - mockWalletReturnValue(this.walletSpy, this.guardian!, { + mockWalletReturnValue(this.guardian!, { collection: this.collection, nft: nft.uid, }); - const order = await testEnv.wrap(orderNft)({}); + const order = await testEnv.wrap(WEN_FUNC.orderNft); await submitMilestoneFunc(order); } - this.nft = await build5Db().doc(`${COL.NFT}/${nft.uid}`).get(); + this.nft = await build5Db().doc(COL.NFT, nft.uid).get(); return this.nft; }; diff --git a/packages/functions/test-tangle/nft-set-for-sale/nft-set-for-sale_1.spec.ts b/packages/functions/test-tangle/nft-set-for-sale/nft-set-for-sale_1.spec.ts index 7425d48919..44bcaa8237 100644 --- a/packages/functions/test-tangle/nft-set-for-sale/nft-set-for-sale_1.spec.ts +++ b/packages/functions/test-tangle/nft-set-for-sale/nft-set-for-sale_1.spec.ts @@ -3,7 +3,6 @@ import { COL, MIN_IOTA_AMOUNT, Network, - Nft, NftAvailable, NftSetForSaleTangleRequest, TangleRequestType, @@ -47,9 +46,9 @@ describe('Nft set for sale OTR', () => { }, ); - const nftDocRef = build5Db().doc(`${COL.NFT}/${helper.nft.uid}`); + const nftDocRef = build5Db().doc(COL.NFT, helper.nft.uid); await wait(async () => { - helper.nft = (await nftDocRef.get())!; + helper.nft = (await nftDocRef.get())!; return helper.nft.available === NftAvailable.SALE; }); }); @@ -74,9 +73,9 @@ describe('Nft set for sale OTR', () => { }, ); - const nftDocRef = build5Db().doc(`${COL.NFT}/${helper.nft.uid}`); + const nftDocRef = build5Db().doc(COL.NFT, helper.nft.uid); await wait(async () => { - helper.nft = (await nftDocRef.get())!; + helper.nft = (await nftDocRef.get())!; return helper.nft.available === NftAvailable.AUCTION_AND_SALE; }); }); diff --git a/packages/functions/test-tangle/nft-set-for-sale/nft-set-for-sale_2.spec.ts b/packages/functions/test-tangle/nft-set-for-sale/nft-set-for-sale_2.spec.ts index ca1ecb46cc..9e99c9b0ec 100644 --- a/packages/functions/test-tangle/nft-set-for-sale/nft-set-for-sale_2.spec.ts +++ b/packages/functions/test-tangle/nft-set-for-sale/nft-set-for-sale_2.spec.ts @@ -48,11 +48,11 @@ describe('Nft set for sale OTR', () => { .where('member', '==', address.bech32) .where('type', '==', TransactionType.CREDIT_TANGLE_REQUEST); await wait(async () => { - const snap = await credit.get(); + const snap = await credit.get(); return snap.length === 1 && snap[0].payload?.walletReference?.confirmed; }); - const snap = await credit.get(); + const snap = await credit.get(); expect(snap[0].payload.response!['code']).toBe(WenError.you_must_be_the_owner_of_nft.code); }); }); 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 f599bffd40..3bf8d4a578 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 @@ -3,7 +3,6 @@ import { COL, MIN_IOTA_AMOUNT, Network, - Nft, NftAvailable, NftSetForSaleTangleRequest, TangleRequestType, @@ -56,9 +55,9 @@ describe('Nft set for auction OTR', () => { ); await MnemonicService.store(helper.guardianAddress.bech32, helper.guardianAddress.mnemonic); - const nftDocRef = build5Db().doc(`${COL.NFT}/${helper.nft.uid}`); + const nftDocRef = build5Db().doc(COL.NFT, helper.nft.uid); await wait(async () => { - helper.nft = (await nftDocRef.get())!; + helper.nft = (await nftDocRef.get())!; return helper.nft.available === NftAvailable.AUCTION_AND_SALE; }); @@ -83,12 +82,10 @@ describe('Nft set for auction OTR', () => { .where('member', '==', helper.guardian) .where('type', '==', TransactionType.CREDIT_TANGLE_REQUEST); await wait(async () => { - const snap = await credit.get(); + const snap = await credit.get(); return snap.length === 2; }); - const succeses = (await credit.get()).filter( - (t) => t.payload.response?.status === 'success', - ); + const succeses = (await credit.get()).filter((t) => t.payload.response?.status === 'success'); expect(succeses.length).toBe(2); auctionData = helper.dummyAuctionData(helper.nft.uid); @@ -107,10 +104,10 @@ describe('Nft set for auction OTR', () => { ); await wait(async () => { - const snap = await credit.get(); + const snap = await credit.get(); return snap.length === 3; }); - const snap = await credit.get(); + const snap = await credit.get(); const creditTransction = snap.find( (t) => t.payload.response?.code === WenError.auction_already_in_progress.code, ); diff --git a/packages/functions/test-tangle/nft-staking/Helper.ts b/packages/functions/test-tangle/nft-staking/Helper.ts index 8b0d38bfbe..b9f8ec334c 100644 --- a/packages/functions/test-tangle/nft-staking/Helper.ts +++ b/packages/functions/test-tangle/nft-staking/Helper.ts @@ -18,6 +18,7 @@ import { TransactionPayloadType, TransactionType, UnsoldMintingOptions, + WEN_FUNC, } from '@build-5/interfaces'; import { AddressUnlockCondition, @@ -32,13 +33,6 @@ import { } from '@iota/sdk'; import dayjs from 'dayjs'; import { cloneDeep } from 'lodash'; -import { createCollection, mintCollection } from '../../src/runtime/firebase/collection/index'; -import { - createNft, - orderNft, - setForSaleNft, - withdrawNft, -} from '../../src/runtime/firebase/nft/index'; import { NftWallet } from '../../src/services/wallet/NftWallet'; import { MnemonicService } from '../../src/services/wallet/mnemonic'; import { Wallet } from '../../src/services/wallet/wallet'; @@ -48,15 +42,8 @@ import { mergeOutputs, packBasicOutput } from '../../src/utils/basic-output.util import { createUnlock, packEssence, submitBlock } from '../../src/utils/block.utils'; import { EMPTY_NFT_ID } from '../../src/utils/collection-minting-utils/nft.utils'; import * as wallet from '../../src/utils/wallet.utils'; -import { getRandomEthAddress } from '../../src/utils/wallet.utils'; -import { - createMember as createMemberTest, - createSpace, - mockWalletReturnValue, - submitMilestoneFunc, - wait, -} from '../../test/controls/common'; -import { MEDIA, getWallet, testEnv } from '../../test/set-up'; +import { submitMilestoneFunc, wait } from '../../test/controls/common'; +import { MEDIA, getWallet, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; export class Helper { @@ -65,31 +52,28 @@ export class Helper { public guardian: string | undefined; public space: Space | undefined; public walletService: Wallet | undefined; - public walletSpy: any; public nft: Nft | undefined; public guardianAddress: AddressDetails | undefined; public royaltySpace: Space | undefined; public beforeAll = async () => { - this.walletSpy = jest.spyOn(wallet, 'decodeAuth'); this.walletService = await getWallet(this.network); }; public beforeEach = async () => { - this.guardian = await createMemberTest(this.walletSpy); - this.space = await createSpace(this.walletSpy, this.guardian!); - this.royaltySpace = await createSpace(this.walletSpy, this.guardian!); + this.guardian = await testEnv.createMember(); + this.space = await testEnv.createSpace(this.guardian!); + this.royaltySpace = await testEnv.createSpace(this.guardian!); mockWalletReturnValue( - this.walletSpy, this.guardian!, this.createDummyCollection(this.space!.uid, this.royaltySpace!.uid), ); - this.collection = (await testEnv.wrap(createCollection)({})).uid; + this.collection = (await testEnv.wrap(WEN_FUNC.createCollection)).uid; - await build5Db().doc(`${COL.COLLECTION}/${this.collection}`).update({ approved: true }); + await build5Db().doc(COL.COLLECTION, this.collection).update({ approved: true }); - const guardianDocRef = build5Db().doc(`${COL.MEMBER}/${this.guardian}`); + const guardianDocRef = build5Db().doc(COL.MEMBER, this.guardian); const guardianData = await guardianDocRef.get(); const guardianBech32 = getAddress(guardianData, this.network!); this.guardianAddress = await this.walletService?.getAddressDetails(guardianBech32)!; @@ -98,31 +82,31 @@ export class Helper { public createAndOrderNft = async () => { let nft: any = this.createDummyNft(this.collection!); delete nft.uid; - mockWalletReturnValue(this.walletSpy, this.guardian!, nft); - nft = await testEnv.wrap(createNft)({}); + mockWalletReturnValue(this.guardian!, nft); + nft = await testEnv.wrap(WEN_FUNC.createNft); await build5Db() - .doc(`${COL.NFT}/${nft.uid}`) + .doc(COL.NFT, nft.uid) .update({ availableFrom: dayjs().subtract(1, 'h').toDate() }); - mockWalletReturnValue(this.walletSpy, this.guardian!, { + mockWalletReturnValue(this.guardian!, { collection: this.collection, nft: nft.uid, }); - const order = await testEnv.wrap(orderNft)({}); + const order = await testEnv.wrap(WEN_FUNC.orderNft); await submitMilestoneFunc(order); - this.nft = await build5Db().doc(`${COL.NFT}/${nft.uid}`).get(); + this.nft = await build5Db().doc(COL.NFT, nft.uid).get(); return this.nft; }; public mintCollection = async (expiresAt?: Timestamp) => { - mockWalletReturnValue(this.walletSpy, this.guardian!, { + mockWalletReturnValue(this.guardian!, { collection: this.collection!, network: this.network, unsoldMintingOptions: UnsoldMintingOptions.KEEP_PRICE, }); - const collectionMintOrder = await testEnv.wrap(mintCollection)({}); + const collectionMintOrder = await testEnv.wrap(WEN_FUNC.mintCollection); await requestFundsFromFaucet( this.network, this.guardianAddress!.bech32, @@ -131,13 +115,13 @@ export class Helper { ); await this.walletService!.send( this.guardianAddress!, - collectionMintOrder.payload.targetAddress, - collectionMintOrder.payload.amount, + collectionMintOrder.payload.targetAddress!, + collectionMintOrder.payload.amount!, {}, ); await MnemonicService.store(this.guardianAddress!.bech32, this.guardianAddress!.mnemonic); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${this.collection}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, this.collection!); await wait(async () => { const data = await collectionDocRef.get(); return data.status === CollectionStatus.MINTED; @@ -154,7 +138,7 @@ export class Helper { await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.MINT_COLLECTION) - .where('payload.type', '==', TransactionPayloadType.SEND_ALIAS_TO_GUARDIAN) + .where('payload_type', '==', TransactionPayloadType.SEND_ALIAS_TO_GUARDIAN) .where('member', '==', this.guardian) .get() ).map((d) => d); @@ -241,37 +225,33 @@ export class Helper { await createUnlock(essence, sourceAddress), ...refUnlocks, ]); - await build5Db().doc(`blocks/${blockId}`).create({ blockId }); + await testEnv.createBlock(blockId); return blockId; }; public withdrawNftAndAwait = async (nft: string) => { - mockWalletReturnValue(this.walletSpy, this.guardian!, { nft }); - await testEnv.wrap(withdrawNft)({}); + mockWalletReturnValue(this.guardian!, { nft }); + await testEnv.wrap(WEN_FUNC.withdrawNft); await wait(async () => { const snap = await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.WITHDRAW_NFT) - .where('payload.nft', '==', nft) - .get(); + .where('payload_nft', '==', nft) + .get(); return snap[0]?.payload?.walletReference?.confirmed; }); }; public setAvailableForAuction = async () => { - mockWalletReturnValue(this.walletSpy, this.guardian!, this.dummyAuctionData(this.nft!.uid)); - await testEnv.wrap(setForSaleNft)({}); - await wait( - async () => (await build5Db().doc(`${COL.NFT}/${this.nft!.uid}`).get())?.available === 3, - ); + mockWalletReturnValue(this.guardian!, this.dummyAuctionData(this.nft!.uid)); + await testEnv.wrap(WEN_FUNC.setForSaleNft); + await wait(async () => (await build5Db().doc(COL.NFT, this.nft!.uid).get())?.available === 3); }; public setAvailableForSale = async () => { - mockWalletReturnValue(this.walletSpy, this.guardian!, this.dummySaleData(this.nft!.uid)); - await testEnv.wrap(setForSaleNft)({}); - await wait( - async () => (await build5Db().doc(`${COL.NFT}/${this.nft!.uid}`).get())?.available === 1, - ); + mockWalletReturnValue(this.guardian!, this.dummySaleData(this.nft!.uid)); + await testEnv.wrap(WEN_FUNC.setForSaleNft); + await wait(async () => (await build5Db().doc(COL.NFT, this.nft!.uid).get())?.available === 1); }; public createDummyCollection = (space: string, royaltiesSpace: string) => ({ @@ -295,7 +275,7 @@ export class Helper { collection, availableFrom: dayjs().add(1, 'hour').toDate(), price: 10 * 1000 * 1000, - uid: getRandomEthAddress(), + uid: wallet.getRandomEthAddress(), media: MEDIA, properties: { custom: { diff --git a/packages/functions/test-tangle/nft-staking/nft-staking_1.spec.ts b/packages/functions/test-tangle/nft-staking/nft-staking_1.spec.ts index d7b01a8738..0704b8702a 100644 --- a/packages/functions/test-tangle/nft-staking/nft-staking_1.spec.ts +++ b/packages/functions/test-tangle/nft-staking/nft-staking_1.spec.ts @@ -7,12 +7,12 @@ import { NftStake, StakeType, Transaction, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { stakeNft } from '../../src/runtime/firebase/nft'; import { dateToTimestamp } from '../../src/utils/dateTime.utils'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; describe('Stake nft', () => { @@ -30,20 +30,20 @@ describe('Stake nft', () => { 'Should stake nft', async (stakeType: StakeType) => { let nft = await helper.createAndOrderNft(); - const nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); + const nftDocRef = build5Db().doc(COL.NFT, nft.uid); await helper.mintCollection(); await helper.withdrawNftAndAwait(nft.uid); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { + mockWalletReturnValue(helper.guardian!, { network: Network.RMS, weeks: 25, type: stakeType, }); - let stakeNftOrder = await testEnv.wrap(stakeNft)({}); + let stakeNftOrder = await testEnv.wrap(WEN_FUNC.stakeNft); nft = await nftDocRef.get(); await helper.sendNftToAddress( helper.guardianAddress!, - stakeNftOrder.payload.targetAddress, + stakeNftOrder.payload.targetAddress!, dateToTimestamp(dayjs().add(2, 'd')), nft.mintingData?.nftId, ); @@ -65,11 +65,11 @@ describe('Stake nft', () => { expect(nftStake.expirationProcessed).toBe(false); expect(nftStake.type).toBe(stakeType); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${nftStake.collection}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, nftStake.collection); const collection = await collectionDocRef.get(); expect(collection.stakedNft).toBe(1); - const stakeNftOrderDocRef = build5Db().doc(`${COL.TRANSACTION}/${stakeNftOrder.uid}`); + const stakeNftOrderDocRef = build5Db().doc(COL.TRANSACTION, stakeNftOrder.uid); stakeNftOrder = await stakeNftOrderDocRef.get(); expect(stakeNftOrder.payload.nft).toBe(nft.uid); expect(stakeNftOrder.payload.collection).toBe(nft.collection); diff --git a/packages/functions/test-tangle/nft-staking/nft-staking_10.spec.ts b/packages/functions/test-tangle/nft-staking/nft-staking_10.spec.ts index c364d173bf..7126a99be9 100644 --- a/packages/functions/test-tangle/nft-staking/nft-staking_10.spec.ts +++ b/packages/functions/test-tangle/nft-staking/nft-staking_10.spec.ts @@ -7,10 +7,10 @@ import { StakeType, Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; -import { stakeNft } from '../../src/runtime/firebase/nft/index'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -26,12 +26,12 @@ describe('Collection minting', () => { }); it('Should return credits when nft deposit order does not receive nft', async () => { - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { + mockWalletReturnValue(helper.guardian!, { network: Network.RMS, weeks: 25, type: StakeType.DYNAMIC, }); - const order = await testEnv.wrap(stakeNft)({}); + const order = await testEnv.wrap(WEN_FUNC.stakeNft); await requestFundsFromFaucet(Network.RMS, order.payload.targetAddress, MIN_IOTA_AMOUNT); const query = build5Db() @@ -39,7 +39,7 @@ describe('Collection minting', () => { .where('type', '==', TransactionType.CREDIT) .where('member', '==', helper.guardian!); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return ( snap.length === 1 && snap[0].payload.walletReference?.confirmed && diff --git a/packages/functions/test-tangle/nft-staking/nft-staking_2.spec.ts b/packages/functions/test-tangle/nft-staking/nft-staking_2.spec.ts index abfeb3854a..db3eedfdf6 100644 --- a/packages/functions/test-tangle/nft-staking/nft-staking_2.spec.ts +++ b/packages/functions/test-tangle/nft-staking/nft-staking_2.spec.ts @@ -6,11 +6,11 @@ import { StakeType, Transaction, TransactionType, + WEN_FUNC, WenError, } from '@build-5/interfaces'; -import { stakeNft } from '../../src/runtime/firebase/nft'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; describe('Stake nft', () => { @@ -26,20 +26,20 @@ describe('Stake nft', () => { it('Should credit nft, not enough base tokens', async () => { let nft = await helper.createAndOrderNft(); - let nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); + let nftDocRef = build5Db().doc(COL.NFT, nft.uid); await helper.mintCollection(); nft = await nftDocRef.get(); await helper.withdrawNftAndAwait(nft.uid); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { + mockWalletReturnValue(helper.guardian!, { network: Network.RMS, weeks: 25, type: StakeType.DYNAMIC, }); - const stakeNftOrder = await testEnv.wrap(stakeNft)({}); + const stakeNftOrder = await testEnv.wrap(WEN_FUNC.stakeNft); await helper.sendNftToAddress( helper.guardianAddress!, - stakeNftOrder.payload.targetAddress, + stakeNftOrder.payload.targetAddress!, undefined, nft.mintingData?.nftId, ); @@ -49,7 +49,7 @@ describe('Stake nft', () => { .where('type', '==', TransactionType.CREDIT_NFT) .where('member', '==', helper.guardian); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); @@ -61,7 +61,7 @@ describe('Stake nft', () => { nft = await nftDocRef.get(); expect(nft.isOwned).toBe(false); - expect(nft.owner).toBeNull(); + expect(nft.owner).toBeUndefined(); expect(nft.hidden).toBe(true); }); }); diff --git a/packages/functions/test-tangle/nft-staking/nft-staking_2_b.spec.ts b/packages/functions/test-tangle/nft-staking/nft-staking_2_b.spec.ts index e3292c6fd8..5997b6bc10 100644 --- a/packages/functions/test-tangle/nft-staking/nft-staking_2_b.spec.ts +++ b/packages/functions/test-tangle/nft-staking/nft-staking_2_b.spec.ts @@ -6,11 +6,11 @@ import { StakeType, Transaction, TransactionType, + WEN_FUNC, WenError, } from '@build-5/interfaces'; -import { stakeNft } from '../../src/runtime/firebase/nft'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; describe('Stake nft', () => { @@ -26,23 +26,23 @@ describe('Stake nft', () => { it('Should credit nft, not enough base tokens', async () => { let nft = await helper.createAndOrderNft(); - let nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); + let nftDocRef = build5Db().doc(COL.NFT, nft.uid); await helper.mintCollection(); nft = await nftDocRef.get(); await helper.withdrawNftAndAwait(nft.uid); await nftDocRef.delete(); - await build5Db().doc(`${COL.COLLECTION}/${nft.collection}`).delete(); + await build5Db().doc(COL.COLLECTION, nft.collection).delete(); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { + mockWalletReturnValue(helper.guardian!, { network: Network.RMS, weeks: 25, type: StakeType.DYNAMIC, }); - const stakeNftOrder = await testEnv.wrap(stakeNft)({}); + const stakeNftOrder = await testEnv.wrap(WEN_FUNC.stakeNft); await helper.sendNftToAddress( helper.guardianAddress!, - stakeNftOrder.payload.targetAddress, + stakeNftOrder.payload.targetAddress!, undefined, nft.mintingData?.nftId, ); @@ -52,7 +52,7 @@ describe('Stake nft', () => { .where('type', '==', TransactionType.CREDIT_NFT) .where('member', '==', helper.guardian); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); @@ -62,7 +62,7 @@ describe('Stake nft', () => { expect(credit.payload.response!.message).toBe(WenError.not_enough_base_token.key); expect(credit.payload.response!.requiredAmount).toBeDefined(); - nftDocRef = build5Db().doc(`${COL.NFT}/${nft.mintingData?.nftId}`); + nftDocRef = build5Db().doc(COL.NFT, nft.mintingData?.nftId!); nft = await nftDocRef.get(); expect(nft).toBeUndefined(); }); diff --git a/packages/functions/test-tangle/nft-staking/nft-staking_3.spec.ts b/packages/functions/test-tangle/nft-staking/nft-staking_3.spec.ts index a7678d167f..eaf1aa4ca0 100644 --- a/packages/functions/test-tangle/nft-staking/nft-staking_3.spec.ts +++ b/packages/functions/test-tangle/nft-staking/nft-staking_3.spec.ts @@ -7,14 +7,14 @@ import { NftStake, StakeType, Transaction, + WEN_FUNC, } from '@build-5/interfaces'; import { UnlockConditionType } from '@iota/sdk'; import dayjs from 'dayjs'; -import { stakeNft } from '../../src/runtime/firebase/nft'; import { NftWallet } from '../../src/services/wallet/NftWallet'; import { dateToTimestamp } from '../../src/utils/dateTime.utils'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; describe('Stake nft', () => { @@ -30,23 +30,23 @@ describe('Stake nft', () => { it('Should stake nft minted outside build-5', async () => { let nft = await helper.createAndOrderNft(); - let nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); + let nftDocRef = build5Db().doc(COL.NFT, nft.uid); await helper.mintCollection(); await helper.withdrawNftAndAwait(nft.uid); nft = await nftDocRef.get(); - await build5Db().doc(`${COL.NFT}/${nft.uid}`).delete(); - await build5Db().doc(`${COL.COLLECTION}/${nft.collection}`).delete(); + await build5Db().doc(COL.NFT, nft.uid).delete(); + await build5Db().doc(COL.COLLECTION, nft.collection).delete(); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { + mockWalletReturnValue(helper.guardian!, { network: Network.RMS, weeks: 25, type: StakeType.DYNAMIC, }); - let stakeNftOrder = await testEnv.wrap(stakeNft)({}); + let stakeNftOrder = await testEnv.wrap(WEN_FUNC.stakeNft); await helper.sendNftToAddress( helper.guardianAddress!, - stakeNftOrder.payload.targetAddress, + stakeNftOrder.payload.targetAddress!, dateToTimestamp(dayjs().add(2, 'd')), nft.mintingData?.nftId, ); @@ -59,7 +59,7 @@ describe('Stake nft', () => { return snap.length === 1; }); - nftDocRef = build5Db().doc(`${COL.NFT}/${nft.mintingData?.nftId}`); + nftDocRef = build5Db().doc(COL.NFT, nft.mintingData?.nftId!); nft = await nftDocRef.get(); const snap = await stakeQuery.get(); const nftStake = snap[0] as NftStake; @@ -80,11 +80,11 @@ describe('Stake nft', () => { output.unlockConditions.find((uc) => uc.type === UnlockConditionType.Timelock), ).toBeDefined(); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${nftStake.collection}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, nftStake.collection); const collection = await collectionDocRef.get(); expect(collection.stakedNft).toBe(1); - const stakeNftOrderDocRef = build5Db().doc(`${COL.TRANSACTION}/${stakeNftOrder.uid}`); + const stakeNftOrderDocRef = build5Db().doc(COL.TRANSACTION, stakeNftOrder.uid); stakeNftOrder = await stakeNftOrderDocRef.get(); expect(stakeNftOrder.payload.nft).toBe(nft.uid); }); diff --git a/packages/functions/test-tangle/nft-staking/nft-staking_4.spec.ts b/packages/functions/test-tangle/nft-staking/nft-staking_4.spec.ts index 1a139ce495..bf54cfe664 100644 --- a/packages/functions/test-tangle/nft-staking/nft-staking_4.spec.ts +++ b/packages/functions/test-tangle/nft-staking/nft-staking_4.spec.ts @@ -6,11 +6,11 @@ import { StakeType, Transaction, TransactionType, + WEN_FUNC, WenError, } from '@build-5/interfaces'; -import { stakeNft } from '../../src/runtime/firebase/nft'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; describe('Stake nft', () => { @@ -26,25 +26,25 @@ describe('Stake nft', () => { it.each([true, false])('Should credit first then stake', async (migration: boolean) => { let nft = await helper.createAndOrderNft(); - let nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); + let nftDocRef = build5Db().doc(COL.NFT, nft.uid); await helper.mintCollection(); nft = await nftDocRef.get(); await helper.withdrawNftAndAwait(nft.uid); if (migration) { await nftDocRef.delete(); - await build5Db().doc(`${COL.COLLECTION}/${nft.collection}`).delete(); + await build5Db().doc(COL.COLLECTION, nft.collection).delete(); } - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { + mockWalletReturnValue(helper.guardian!, { network: Network.RMS, weeks: 25, type: StakeType.DYNAMIC, }); - const stakeNftOrder = await testEnv.wrap(stakeNft)({}); + const stakeNftOrder = await testEnv.wrap(WEN_FUNC.stakeNft); await helper.sendNftToAddress( helper.guardianAddress!, - stakeNftOrder.payload.targetAddress, + stakeNftOrder.payload.targetAddress!, undefined, nft.mintingData?.nftId, ); @@ -54,7 +54,7 @@ describe('Stake nft', () => { .where('type', '==', TransactionType.CREDIT_NFT) .where('member', '==', helper.guardian); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); @@ -67,7 +67,7 @@ describe('Stake nft', () => { (credit.payload.response!.requiredAmount as number) - nft.mintingData?.storageDeposit!; await helper.sendNftToAddress( helper.guardianAddress!, - stakeNftOrder.payload.targetAddress, + stakeNftOrder.payload.targetAddress!, undefined, nft.mintingData?.nftId, extraRequired, diff --git a/packages/functions/test-tangle/nft-staking/nft-staking_5.spec.ts b/packages/functions/test-tangle/nft-staking/nft-staking_5.spec.ts index ed10c8bffa..4e8e6505de 100644 --- a/packages/functions/test-tangle/nft-staking/nft-staking_5.spec.ts +++ b/packages/functions/test-tangle/nft-staking/nft-staking_5.spec.ts @@ -4,16 +4,14 @@ import { COL, MIN_IOTA_AMOUNT, Network, - Nft, StakeType, Transaction, TransactionPayloadType, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { approveAwardParticipant, createAward, fundAward } from '../../src/runtime/firebase/award'; -import { stakeNft } from '../../src/runtime/firebase/nft'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { MEDIA, testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { MEDIA, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { saveBaseToken } from '../award/common'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -31,47 +29,43 @@ describe('Stake nft', () => { it('Should deposit badge ntt ', async () => { const token = await saveBaseToken(helper.space!.uid, helper.guardian!); - mockWalletReturnValue( - helper.walletSpy, - helper.guardian!, - awardRequest(helper.space!.uid, token.symbol), - ); - let award = await testEnv.wrap(createAward)({}); + mockWalletReturnValue(helper.guardian!, awardRequest(helper.space!.uid, token.symbol)); + let award = await testEnv.wrap(WEN_FUNC.createAward); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { uid: award.uid }); - const order = await testEnv.wrap(fundAward)({}); + mockWalletReturnValue(helper.guardian!, { uid: award.uid }); + const order = await testEnv.wrap(WEN_FUNC.fundAward); await requestFundsFromFaucet(Network.RMS, order.payload.targetAddress, order.payload.amount); - const awardDocRef = build5Db().doc(`${COL.AWARD}/${award.uid}`); + const awardDocRef = build5Db().doc(COL.AWARD, award.uid); await wait(async () => { award = await awardDocRef.get(); return award.approved && award.funded; }); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { + mockWalletReturnValue(helper.guardian!, { award: award.uid, members: [helper.guardian!], }); - await testEnv.wrap(approveAwardParticipant)({}); + await testEnv.wrap(WEN_FUNC.approveParticipantAward); const nttQuery = build5Db() .collection(COL.TRANSACTION) .where('member', '==', helper.guardian!) - .where('payload.type', '==', TransactionPayloadType.BADGE); + .where('payload_type', '==', TransactionPayloadType.BADGE); await wait(async () => { - const snap = await nttQuery.get(); + const snap = await nttQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { + mockWalletReturnValue(helper.guardian!, { network: Network.RMS, weeks: 25, type: StakeType.DYNAMIC, }); - const stakeNftOrder = await testEnv.wrap(stakeNft)({}); + const stakeNftOrder = await testEnv.wrap(WEN_FUNC.stakeNft); await helper.sendNftToAddress( helper.guardianAddress!, - stakeNftOrder.payload.targetAddress, + stakeNftOrder.payload.targetAddress!, undefined, undefined, MIN_IOTA_AMOUNT, @@ -84,7 +78,7 @@ describe('Stake nft', () => { }); const nftQuery = build5Db().collection(COL.NFT).where('space', '==', helper.space?.uid); - const nftSnap = await nftQuery.get(); + const nftSnap = await nftQuery.get(); expect(nftSnap.length).toBe(1); expect(nftSnap[0]?.space).toBe(award.space); }); diff --git a/packages/functions/test-tangle/nft-staking/nft-staking_6.spec.ts b/packages/functions/test-tangle/nft-staking/nft-staking_6.spec.ts index fa0c8e8d2a..2b0b64600b 100644 --- a/packages/functions/test-tangle/nft-staking/nft-staking_6.spec.ts +++ b/packages/functions/test-tangle/nft-staking/nft-staking_6.spec.ts @@ -1,9 +1,16 @@ import { build5Db } from '@build-5/database'; -import { COL, KEY_NAME_TANGLE, Network, Nft, StakeType } from '@build-5/interfaces'; +import { + COL, + KEY_NAME_TANGLE, + Network, + Nft, + StakeType, + Transaction, + WEN_FUNC, +} from '@build-5/interfaces'; import { NftOutput, NftOutputBuilderParams, TagFeature, Utils, utf8ToHex } from '@iota/sdk'; -import { stakeNft } from '../../src/runtime/firebase/nft'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; describe('Stake nft', () => { @@ -19,17 +26,17 @@ describe('Stake nft', () => { it.each([false, true])('Should stake with tag', async (migration: boolean) => { let nft = await helper.createAndOrderNft(); - let nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); + let nftDocRef = build5Db().doc(COL.NFT, nft.uid); await helper.mintCollection(); nft = await nftDocRef.get(); await helper.withdrawNftAndAwait(nft.uid); if (migration) { await nftDocRef.delete(); - await build5Db().doc(`${COL.COLLECTION}/${nft.collection}`).delete(); + await build5Db().doc(COL.COLLECTION, nft.collection).delete(); } - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { + mockWalletReturnValue(helper.guardian!, { network: Network.RMS, weeks: 25, type: StakeType.DYNAMIC, @@ -47,10 +54,10 @@ describe('Stake nft', () => { helper.walletService!.info.protocol.rentStructure, ); const extraAmount = Number(storageDeposit) - Number(nftOutput.amount); - const stakeNftOrder = await testEnv.wrap(stakeNft)({}); + const stakeNftOrder = await testEnv.wrap(WEN_FUNC.stakeNft); await helper.sendNftToAddress( helper.guardianAddress!, - stakeNftOrder.payload.targetAddress, + stakeNftOrder.payload.targetAddress!, undefined, nft.mintingData?.nftId, extraAmount, diff --git a/packages/functions/test-tangle/nft-staking/nft-staking_7.spec.ts b/packages/functions/test-tangle/nft-staking/nft-staking_7.spec.ts index 3a2ec70576..c5d49d3db8 100644 --- a/packages/functions/test-tangle/nft-staking/nft-staking_7.spec.ts +++ b/packages/functions/test-tangle/nft-staking/nft-staking_7.spec.ts @@ -1,8 +1,15 @@ import { build5Db } from '@build-5/database'; -import { COL, Network, Nft, StakeType, Transaction, TransactionType } from '@build-5/interfaces'; -import { stakeNft } from '../../src/runtime/firebase/nft'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { + COL, + Network, + Nft, + StakeType, + Transaction, + TransactionType, + WEN_FUNC, +} from '@build-5/interfaces'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; describe('Stake nft', () => { @@ -18,20 +25,20 @@ describe('Stake nft', () => { it('Should credit twice', async () => { let nft = await helper.createAndOrderNft(); - let nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); + let nftDocRef = build5Db().doc(COL.NFT, nft.uid); await helper.mintCollection(); nft = await nftDocRef.get(); await helper.withdrawNftAndAwait(nft.uid); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { + mockWalletReturnValue(helper.guardian!, { network: Network.RMS, weeks: 25, type: StakeType.DYNAMIC, }); - const stakeNftOrder = await testEnv.wrap(stakeNft)({}); + const stakeNftOrder = await testEnv.wrap(WEN_FUNC.stakeNft); await helper.sendNftToAddress( helper.guardianAddress!, - stakeNftOrder.payload.targetAddress, + stakeNftOrder.payload.targetAddress!, undefined, nft.mintingData?.nftId, ); @@ -41,19 +48,19 @@ describe('Stake nft', () => { .where('type', '==', TransactionType.CREDIT_NFT) .where('member', '==', helper.guardian); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); await helper.sendNftToAddress( helper.guardianAddress!, - stakeNftOrder.payload.targetAddress, + stakeNftOrder.payload.targetAddress!, undefined, nft.mintingData?.nftId, ); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return ( snap.length === 2 && snap[0]?.payload?.walletReference?.confirmed && diff --git a/packages/functions/test-tangle/nft-staking/nft-staking_8.spec.ts b/packages/functions/test-tangle/nft-staking/nft-staking_8.spec.ts index 3ac4e81d7c..999e78f344 100644 --- a/packages/functions/test-tangle/nft-staking/nft-staking_8.spec.ts +++ b/packages/functions/test-tangle/nft-staking/nft-staking_8.spec.ts @@ -8,11 +8,10 @@ import { StakeType, Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; -import { creditUnrefundable } from '../../src/runtime/firebase/credit'; -import { stakeNft } from '../../src/runtime/firebase/nft'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -29,20 +28,20 @@ describe('Stake nft', () => { it('Should not stake with storage dep', async () => { let nft = await helper.createAndOrderNft(); - let nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); + let nftDocRef = build5Db().doc(COL.NFT, nft.uid); await helper.mintCollection(); nft = await nftDocRef.get(); await helper.withdrawNftAndAwait(nft.uid); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { + mockWalletReturnValue(helper.guardian!, { network: Network.RMS, weeks: 25, type: StakeType.DYNAMIC, }); - const stakeNftOrder = await testEnv.wrap(stakeNft)({}); + const stakeNftOrder = await testEnv.wrap(WEN_FUNC.stakeNft); await helper.sendNftToAddress( helper.guardianAddress!, - stakeNftOrder.payload.targetAddress, + stakeNftOrder.payload.targetAddress!, undefined, nft.mintingData?.nftId, MIN_IOTA_AMOUNT, @@ -60,13 +59,13 @@ describe('Stake nft', () => { IgnoreWalletReason.UNREFUNDABLE_DUE_STORAGE_DEPOSIT_CONDITION, ); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return snap.length === 1; }); - const snap = await creditQuery.get(); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { transaction: snap[0].uid }); - const order = await testEnv.wrap(creditUnrefundable)({}); + const snap = await creditQuery.get(); + mockWalletReturnValue(helper.guardian!, { transaction: snap[0].uid }); + const order = await testEnv.wrap(WEN_FUNC.creditUnrefundable); await requestFundsFromFaucet(Network.RMS, order.payload.targetAddress, order.payload.amount); creditQuery = build5Db() @@ -74,7 +73,7 @@ describe('Stake nft', () => { .where('type', '==', TransactionType.CREDIT_STORAGE_DEPOSIT_LOCKED) .where('member', '==', helper.guardian); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return snap.length === 1 && snap[0].payload.walletReference?.confirmed; }); diff --git a/packages/functions/test-tangle/nft-staking/nft-staking_9.spec.ts b/packages/functions/test-tangle/nft-staking/nft-staking_9.spec.ts index 4e4303ff56..09bf3a4cfd 100644 --- a/packages/functions/test-tangle/nft-staking/nft-staking_9.spec.ts +++ b/packages/functions/test-tangle/nft-staking/nft-staking_9.spec.ts @@ -9,13 +9,12 @@ import { TRANSACTION_AUTO_EXPIRY_MS, Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { creditUnrefundable } from '../../src/runtime/firebase/credit'; -import { stakeNft } from '../../src/runtime/firebase/nft'; import { dateToTimestamp } from '../../src/utils/dateTime.utils'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; describe('Stake nft', () => { @@ -31,20 +30,20 @@ describe('Stake nft', () => { it('Should not stake with storage dep and timelock, also should not credit', async () => { let nft = await helper.createAndOrderNft(); - let nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); + let nftDocRef = build5Db().doc(COL.NFT, nft.uid); await helper.mintCollection(); nft = await nftDocRef.get(); await helper.withdrawNftAndAwait(nft.uid); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { + mockWalletReturnValue(helper.guardian!, { network: Network.RMS, weeks: 25, type: StakeType.DYNAMIC, }); - const stakeNftOrder = await testEnv.wrap(stakeNft)({}); + const stakeNftOrder = await testEnv.wrap(WEN_FUNC.stakeNft); await helper.sendNftToAddress( helper.guardianAddress!, - stakeNftOrder.payload.targetAddress, + stakeNftOrder.payload.targetAddress!, dateToTimestamp(dayjs().add(1, 'm')), nft.mintingData?.nftId, MIN_IOTA_AMOUNT, @@ -62,14 +61,14 @@ describe('Stake nft', () => { IgnoreWalletReason.UNREFUNDABLE_DUE_STORAGE_DEPOSIT_CONDITION, ); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return snap.length === 1; }); - const snap = await creditQuery.get(); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { transaction: snap[0].uid }); - const order = await testEnv.wrap(creditUnrefundable)({}); - + const snap = await creditQuery.get(); + mockWalletReturnValue(helper.guardian!, { transaction: snap[0].uid }); + let order = await testEnv.wrap(WEN_FUNC.creditUnrefundable); + order = (await build5Db().doc(COL.TRANSACTION, order.uid).get())!; const expiresOn = order.payload.expiresOn!; const isEarlier = dayjs(expiresOn.toDate()).isBefore(dayjs().add(TRANSACTION_AUTO_EXPIRY_MS)); expect(isEarlier).toBe(true); diff --git a/packages/functions/test-tangle/nft-transfer/Helper.ts b/packages/functions/test-tangle/nft-transfer/Helper.ts index e8a0e86bfb..727b3eed83 100644 --- a/packages/functions/test-tangle/nft-transfer/Helper.ts +++ b/packages/functions/test-tangle/nft-transfer/Helper.ts @@ -2,8 +2,8 @@ import { build5Db } from '@build-5/database'; import { Access, - Categories, COL, + Categories, Collection, CollectionStatus, CollectionType, @@ -17,27 +17,19 @@ import { Transaction, TransactionType, UnsoldMintingOptions, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { createCollection, mintCollection } from '../../src/runtime/firebase/collection/index'; -import { createNft, orderNft, setForSaleNft } from '../../src/runtime/firebase/nft/index'; import { NftWallet } from '../../src/services/wallet/NftWallet'; import { Wallet } from '../../src/services/wallet/wallet'; import { AddressDetails } from '../../src/services/wallet/wallet.service'; import { serverTime } from '../../src/utils/dateTime.utils'; import * as wallet from '../../src/utils/wallet.utils'; -import { - createMember as createMemberTest, - createSpace, - mockWalletReturnValue, - submitMilestoneFunc, - wait, -} from '../../test/controls/common'; -import { getWallet, MEDIA, testEnv } from '../../test/set-up'; +import { submitMilestoneFunc, wait } from '../../test/controls/common'; +import { MEDIA, getWallet, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; export class Helper { - public spy: any = {} as any; public network = Network.RMS; public collection: string = {} as any; public guardian: string = {} as any; @@ -49,47 +41,45 @@ export class Helper { public nft: Nft = {} as any; public beforeAll = async () => { - this.spy = jest.spyOn(wallet, 'decodeAuth'); this.walletService = await getWallet(this.network); this.nftWallet = new NftWallet(this.walletService); }; public beforeEach = async (collectionType = CollectionType.CLASSIC) => { - this.guardian = await createMemberTest(this.spy); - this.member = await createMemberTest(this.spy); - this.space = await createSpace(this.spy, this.guardian); - this.royaltySpace = await createSpace(this.spy, this.guardian); + this.guardian = await testEnv.createMember(); + this.member = await testEnv.createMember(); + this.space = await testEnv.createSpace(this.guardian); + this.royaltySpace = await testEnv.createSpace(this.guardian); mockWalletReturnValue( - this.spy, this.guardian, this.createDummyCollection(this.space.uid, this.royaltySpace.uid, collectionType), ); - this.collection = (await testEnv.wrap(createCollection)({})).uid; + this.collection = (await testEnv.wrap(WEN_FUNC.createCollection)).uid; - await build5Db().doc(`${COL.COLLECTION}/${this.collection}`).update({ approved: true }); + await build5Db().doc(COL.COLLECTION, this.collection).update({ approved: true }); }; public mintCollection = async (expiresAt?: Timestamp) => { - mockWalletReturnValue(this.spy, this.guardian!, { + mockWalletReturnValue(this.guardian!, { collection: this.collection, network: this.network, unsoldMintingOptions: UnsoldMintingOptions.KEEP_PRICE, }); - const collectionMintOrder = await testEnv.wrap(mintCollection)({}); + const collectionMintOrder = await testEnv.wrap(WEN_FUNC.mintCollection); await requestFundsFromFaucet( this.network!, collectionMintOrder.payload.targetAddress, collectionMintOrder.payload.amount, expiresAt, ); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${this.collection}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, this.collection); await wait(async () => { const data = await collectionDocRef.get(); return data.status === CollectionStatus.MINTED; }); - const nftDocRef = build5Db().doc(`${COL.NFT}/${this.nft?.uid}`); + const nftDocRef = build5Db().doc(COL.NFT, this.nft?.uid); this.nft = await nftDocRef.get(); }; @@ -98,41 +88,41 @@ export class Helper { delete nft.uid; delete nft.status; delete nft.placeholderNft; - mockWalletReturnValue(this.spy, this.guardian!, nft); - nft = await testEnv.wrap(createNft)({}); + mockWalletReturnValue(this.guardian!, nft); + nft = await testEnv.wrap(WEN_FUNC.createNft); await build5Db() - .doc(`${COL.NFT}/${nft.uid}`) + .doc(COL.NFT, nft.uid) .update({ availableFrom: dayjs().subtract(1, 'h').toDate() }); if (shouldOrder) { - mockWalletReturnValue(this.spy, this.guardian!, { + mockWalletReturnValue(this.guardian!, { collection: this.collection, nft: nft.uid, }); - const order = await testEnv.wrap(orderNft)({}); + const order = await testEnv.wrap(WEN_FUNC.orderNft); await submitMilestoneFunc(order); } - this.nft = await build5Db().doc(`${COL.NFT}/${nft.uid}`).get(); + this.nft = await build5Db().doc(COL.NFT, nft.uid).get(); return this.nft; }; public setAvailableForAuction = async (nft?: string) => { const uid = nft || this.nft?.uid!; - mockWalletReturnValue(this.spy, this.guardian!, this.dummyAuctionData(uid)); - await testEnv.wrap(setForSaleNft)({}); + mockWalletReturnValue(this.guardian!, this.dummyAuctionData(uid)); + await testEnv.wrap(WEN_FUNC.setForSaleNft); await wait(async () => { - const docRef = build5Db().doc(`${COL.NFT}/${uid}`); + const docRef = build5Db().doc(COL.NFT, uid); this.nft = await docRef.get(); return this.nft.available === 3; }); }; public setAvailableForSale = async (nftId: string) => { - mockWalletReturnValue(this.spy, this.guardian!, this.dummySaleData(nftId)); - await testEnv.wrap(setForSaleNft)({}); + mockWalletReturnValue(this.guardian!, this.dummySaleData(nftId)); + await testEnv.wrap(WEN_FUNC.setForSaleNft); await wait(async () => { - const nft = await build5Db().doc(`${COL.NFT}/${nftId}`).get(); + const nft = await build5Db().doc(COL.NFT, nftId).get(); return nft?.available === 1; }); }; @@ -198,7 +188,7 @@ export class Helper { nftId, }, }; - await build5Db().doc(`${COL.TRANSACTION}/${order.uid}`).create(order); + await build5Db().doc(COL.TRANSACTION, order.uid).create(order); return order.uid; }; } diff --git a/packages/functions/test-tangle/nft-transfer/nft-transfer_1.spec.ts b/packages/functions/test-tangle/nft-transfer/nft-transfer_1.spec.ts index 2986de5cce..2e11a421c9 100644 --- a/packages/functions/test-tangle/nft-transfer/nft-transfer_1.spec.ts +++ b/packages/functions/test-tangle/nft-transfer/nft-transfer_1.spec.ts @@ -1,8 +1,6 @@ import { build5Db } from '@build-5/database'; -import { COL, Nft, NftTransferRequest, Transaction, TransactionType } from '@build-5/interfaces'; -import { nftTransfer } from '../../src/runtime/firebase/nft'; -import { mockWalletReturnValue } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { COL, Nft, NftTransferRequest, TransactionType, WEN_FUNC } from '@build-5/interfaces'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; describe('Nft transfer', () => { @@ -28,8 +26,8 @@ describe('Nft transfer', () => { ], }; - mockWalletReturnValue(h.spy, h.guardian, request); - const response: { [key: string]: number } = await testEnv.wrap(nftTransfer)({}); + mockWalletReturnValue(h.guardian, request); + const response: { [key: string]: number } = await testEnv.wrap(WEN_FUNC.nftTransfer); expect(response[nft1.uid]).toBe(200); expect(response[nft2.uid]).toBe(200); @@ -37,14 +35,14 @@ describe('Nft transfer', () => { .collection(COL.TRANSACTION) .where('member', '==', h.guardian) .where('type', '==', TransactionType.NFT_TRANSFER) - .get(); + .get(); expect(transfers.length).toBe(2); - const nft1DocRef = build5Db().doc(`${COL.NFT}/${nft1.uid}`); + const nft1DocRef = build5Db().doc(COL.NFT, nft1.uid); nft1 = await nft1DocRef.get(); expect(nft1.owner).toBe(h.member); - const nft2DocRef = build5Db().doc(`${COL.NFT}/${nft2.uid}`); + const nft2DocRef = build5Db().doc(COL.NFT, nft2.uid); nft2 = await nft2DocRef.get(); expect(nft2.owner).toBe(h.member); }); diff --git a/packages/functions/test-tangle/nft-transfer/nft-transfer_2.spec.ts b/packages/functions/test-tangle/nft-transfer/nft-transfer_2.spec.ts index 1a981d9cc9..b57c9e6733 100644 --- a/packages/functions/test-tangle/nft-transfer/nft-transfer_2.spec.ts +++ b/packages/functions/test-tangle/nft-transfer/nft-transfer_2.spec.ts @@ -1,7 +1,5 @@ -import { NftTransferRequest } from '@build-5/interfaces'; -import { nftTransfer } from '../../src/runtime/firebase/nft'; -import { mockWalletReturnValue } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { NftTransferRequest, WEN_FUNC } from '@build-5/interfaces'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; describe('Nft transfer', () => { @@ -29,8 +27,8 @@ describe('Nft transfer', () => { ], }; - mockWalletReturnValue(h.spy, h.guardian, request); - const response: { [key: string]: number } = await testEnv.wrap(nftTransfer)({}); + mockWalletReturnValue(h.guardian, request); + const response: { [key: string]: number } = await testEnv.wrap(WEN_FUNC.nftTransfer); expect(response[nft1.uid]).toBe(200); expect(response[nft2.uid]).toBe(2092); }); diff --git a/packages/functions/test-tangle/nft-transfer/nft-transfer_3.spec.ts b/packages/functions/test-tangle/nft-transfer/nft-transfer_3.spec.ts index a0c38dc8c3..f2e32bd343 100644 --- a/packages/functions/test-tangle/nft-transfer/nft-transfer_3.spec.ts +++ b/packages/functions/test-tangle/nft-transfer/nft-transfer_3.spec.ts @@ -1,8 +1,6 @@ import { build5Db } from '@build-5/database'; -import { COL, NftTransferRequest, Transaction, TransactionType } from '@build-5/interfaces'; -import { nftTransfer } from '../../src/runtime/firebase/nft'; -import { mockWalletReturnValue } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { COL, NftTransferRequest, TransactionType, WEN_FUNC } from '@build-5/interfaces'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; describe('Nft transfer', () => { @@ -28,8 +26,8 @@ describe('Nft transfer', () => { ], }; - mockWalletReturnValue(h.spy, h.member, request); - const response: { [key: string]: number } = await testEnv.wrap(nftTransfer)({}); + mockWalletReturnValue(h.member, request); + const response: { [key: string]: number } = await testEnv.wrap(WEN_FUNC.nftTransfer); expect(response[nft1.uid]).toBe(2066); expect(response[nft2.uid]).toBe(2066); @@ -37,7 +35,7 @@ describe('Nft transfer', () => { .collection(COL.TRANSACTION) .where('member', '==', h.member) .where('type', '==', TransactionType.NFT_TRANSFER) - .get(); + .get(); expect(transfers.length).toBe(0); }); }); diff --git a/packages/functions/test-tangle/nft-transfer/nft-transfer_4.spec.ts b/packages/functions/test-tangle/nft-transfer/nft-transfer_4.spec.ts index 32e8788b88..0e14897565 100644 --- a/packages/functions/test-tangle/nft-transfer/nft-transfer_4.spec.ts +++ b/packages/functions/test-tangle/nft-transfer/nft-transfer_4.spec.ts @@ -2,7 +2,6 @@ import { build5Db } from '@build-5/database'; import { COL, MIN_IOTA_AMOUNT, - Member, Network, TangleRequestType, Transaction, @@ -32,8 +31,8 @@ describe('Nft transfer', () => { const nft2 = await h.createAndOrderNft(); await h.mintCollection(); - const guardianDocRef = build5Db().doc(`${COL.MEMBER}/${h.guardian}`); - const guardian = await guardianDocRef.get(); + const guardianDocRef = build5Db().doc(COL.MEMBER, h.guardian); + const guardian = await guardianDocRef.get(); const bech32 = getAddress(guardian, Network.RMS); const address = await h.walletService.getAddressDetails(bech32); @@ -56,10 +55,10 @@ describe('Nft transfer', () => { .where('member', '==', h.guardian) .where('type', '==', TransactionType.CREDIT_TANGLE_REQUEST); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1; }); - const credit = (await query.get())[0]; + const credit = (await query.get())[0]; expect(credit.payload.response![nft1.uid]).toBe(200); expect(credit.payload.response![nft2.uid]).toBe(200); }); diff --git a/packages/functions/test-tangle/nft-transfer/nft-transfer_5.spec.ts b/packages/functions/test-tangle/nft-transfer/nft-transfer_5.spec.ts index 0dd3c0de91..33bfadc132 100644 --- a/packages/functions/test-tangle/nft-transfer/nft-transfer_5.spec.ts +++ b/packages/functions/test-tangle/nft-transfer/nft-transfer_5.spec.ts @@ -2,7 +2,6 @@ import { build5Db } from '@build-5/database'; import { COL, MIN_IOTA_AMOUNT, - Member, Network, TangleRequestType, Transaction, @@ -34,8 +33,8 @@ describe('Nft transfer', () => { const targetAddress = await h.walletService.getNewIotaAddressDetails(); - const guardianDocRef = build5Db().doc(`${COL.MEMBER}/${h.guardian}`); - const guardian = await guardianDocRef.get(); + const guardianDocRef = build5Db().doc(COL.MEMBER, h.guardian); + const guardian = await guardianDocRef.get(); const bech32 = getAddress(guardian, Network.RMS); const address = await h.walletService.getAddressDetails(bech32); @@ -58,10 +57,10 @@ describe('Nft transfer', () => { .where('member', '==', h.guardian) .where('type', '==', TransactionType.CREDIT_TANGLE_REQUEST); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1; }); - const credit = (await query.get())[0]; + const credit = (await query.get())[0]; expect(credit.payload.response![nft1.uid]).toBe(200); expect(credit.payload.response![nft2.uid]).toBe(200); @@ -70,7 +69,7 @@ describe('Nft transfer', () => { .where('member', '==', h.guardian) .where('type', '==', TransactionType.WITHDRAW_NFT); await wait(async () => { - const withdraws = await query.get(); + const withdraws = await query.get(); return ( withdraws.length === 2 && withdraws[0].payload.walletReference?.confirmed && diff --git a/packages/functions/test-tangle/nft-transfer/nft-transfer_6.spec.ts b/packages/functions/test-tangle/nft-transfer/nft-transfer_6.spec.ts index 711910d51c..5728a08737 100644 --- a/packages/functions/test-tangle/nft-transfer/nft-transfer_6.spec.ts +++ b/packages/functions/test-tangle/nft-transfer/nft-transfer_6.spec.ts @@ -1,9 +1,7 @@ import { build5Db } from '@build-5/database'; -import { COL, NftTransferRequest, Transaction, TransactionType } from '@build-5/interfaces'; -import { nftTransfer } from '../../src/runtime/firebase/nft'; +import { COL, NftTransferRequest, TransactionType, WEN_FUNC } from '@build-5/interfaces'; import { getRandomEthAddress } from '../../src/utils/wallet.utils'; -import { mockWalletReturnValue } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; describe('Nft transfer', () => { @@ -29,8 +27,8 @@ describe('Nft transfer', () => { ], }; - mockWalletReturnValue(h.spy, h.guardian, request); - const response: { [key: string]: number } = await testEnv.wrap(nftTransfer)({}); + mockWalletReturnValue(h.guardian, request); + const response: { [key: string]: number } = await testEnv.wrap(WEN_FUNC.nftTransfer); expect(response[nft1.uid]).toBe(200); expect(response[nft2.uid]).toBe(2141); @@ -38,7 +36,7 @@ describe('Nft transfer', () => { .collection(COL.TRANSACTION) .where('member', '==', h.guardian) .where('type', '==', TransactionType.NFT_TRANSFER) - .get(); + .get(); expect(transfers.length).toBe(1); }); }); diff --git a/packages/functions/test-tangle/nft-transfer/nft-transfer_7.spec.ts b/packages/functions/test-tangle/nft-transfer/nft-transfer_7.spec.ts index 858339b32f..c98c5517ca 100644 --- a/packages/functions/test-tangle/nft-transfer/nft-transfer_7.spec.ts +++ b/packages/functions/test-tangle/nft-transfer/nft-transfer_7.spec.ts @@ -1,8 +1,6 @@ import { build5Db } from '@build-5/database'; -import { COL, Nft, NftTransferRequest, Transaction, TransactionType } from '@build-5/interfaces'; -import { nftTransfer } from '../../src/runtime/firebase/nft'; -import { mockWalletReturnValue } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { COL, Nft, NftTransferRequest, TransactionType, WEN_FUNC } from '@build-5/interfaces'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; describe('Nft transfer', () => { @@ -28,8 +26,8 @@ describe('Nft transfer', () => { ], }; - mockWalletReturnValue(h.spy, h.guardian, request); - const response: { [key: string]: number } = await testEnv.wrap(nftTransfer)({}); + mockWalletReturnValue(h.guardian, request); + const response: { [key: string]: number } = await testEnv.wrap(WEN_FUNC.nftTransfer); expect(response[nft1.uid]).toBe(200); expect(response[nft2.uid]).toBe(200); @@ -37,10 +35,10 @@ describe('Nft transfer', () => { .collection(COL.TRANSACTION) .where('member', '==', h.guardian) .where('type', '==', TransactionType.NFT_TRANSFER) - .get(); + .get(); expect(transfers.length).toBe(1); - const nft2DocRef = build5Db().doc(`${COL.NFT}/${nft2.uid}`); + const nft2DocRef = build5Db().doc(COL.NFT, nft2.uid); nft2 = await nft2DocRef.get(); expect(nft2.owner).toBe(h.member); @@ -48,7 +46,7 @@ describe('Nft transfer', () => { .collection(COL.TRANSACTION) .where('member', '==', h.guardian) .where('type', '==', TransactionType.WITHDRAW_NFT) - .get(); + .get(); expect(withdraws.length).toBe(1); }); }); diff --git a/packages/functions/test-tangle/nft-transfer/nft-transfer_8.spec.ts b/packages/functions/test-tangle/nft-transfer/nft-transfer_8.spec.ts index 7891260af2..37382989f3 100644 --- a/packages/functions/test-tangle/nft-transfer/nft-transfer_8.spec.ts +++ b/packages/functions/test-tangle/nft-transfer/nft-transfer_8.spec.ts @@ -1,8 +1,6 @@ import { build5Db } from '@build-5/database'; -import { COL, Nft, NftTransferRequest, Transaction, TransactionType } from '@build-5/interfaces'; -import { nftTransfer } from '../../src/runtime/firebase/nft'; -import { mockWalletReturnValue } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { COL, Nft, NftTransferRequest, TransactionType, WEN_FUNC } from '@build-5/interfaces'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; describe('Nft transfer', () => { @@ -21,8 +19,8 @@ describe('Nft transfer', () => { let nft2 = await h.createAndOrderNft(); await h.mintCollection(); - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${h.member}`); - await memberDocRef.update({ validatedAddress: {} }); + const memberDocRef = build5Db().doc(COL.MEMBER, h.member); + await memberDocRef.update({ rmsAddress: '', smrAddress: '', iotaAddress: '', atoiAddress: '' }); const request: NftTransferRequest = { transfers: [ @@ -31,8 +29,8 @@ describe('Nft transfer', () => { ], }; - mockWalletReturnValue(h.spy, h.guardian, request); - const response: { [key: string]: number } = await testEnv.wrap(nftTransfer)({}); + mockWalletReturnValue(h.guardian, request); + const response: { [key: string]: number } = await testEnv.wrap(WEN_FUNC.nftTransfer); expect(response[nft1.uid]).toBe(200); expect(response[nft2.uid]).toBe(200); @@ -40,14 +38,14 @@ describe('Nft transfer', () => { .collection(COL.TRANSACTION) .where('member', '==', h.guardian) .where('type', '==', TransactionType.NFT_TRANSFER) - .get(); + .get(); expect(transfers.length).toBe(2); - const nft1DocRef = build5Db().doc(`${COL.NFT}/${nft1.uid}`); + const nft1DocRef = build5Db().doc(COL.NFT, nft1.uid); nft1 = await nft1DocRef.get(); expect(nft1.owner).toBe(h.member); - const nft2DocRef = build5Db().doc(`${COL.NFT}/${nft2.uid}`); + const nft2DocRef = build5Db().doc(COL.NFT, nft2.uid); nft2 = await nft2DocRef.get(); expect(nft2.owner).toBe(h.member); }); diff --git a/packages/functions/test-tangle/proposal-tangle/Helper.ts b/packages/functions/test-tangle/proposal-tangle/Helper.ts index e9f518d18b..48e6d16bf1 100644 --- a/packages/functions/test-tangle/proposal-tangle/Helper.ts +++ b/packages/functions/test-tangle/proposal-tangle/Helper.ts @@ -9,8 +9,10 @@ import { ProposalType, SOON_PROJECT_ID, Space, + Stake, SUB_COL, TangleRequestType, + Token, TokenStatus, Transaction, TransactionType, @@ -22,22 +24,21 @@ import { AddressDetails } from '../../src/services/wallet/wallet.service'; import { getAddress } from '../../src/utils/address.utils'; import { dateToTimestamp } from '../../src/utils/dateTime.utils'; import * as wallet from '../../src/utils/wallet.utils'; -import { createMember, createSpace, wait } from '../../test/controls/common'; -import { getWallet } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { getWallet, testEnv } from '../../test/set-up'; import { getTangleOrder } from '../common'; import { requestFundsFromFaucet, requestMintedTokenFromFaucet } from '../faucet'; export class Helper { constructor(public readonly type = ProposalType.NATIVE) {} - public walletSpy: any = {} as any; public guardian: string = ''; public space: Space = {} as any; public guardianAddress: AddressDetails = {} as any; public walletService: Wallet = {} as any; public tangleOrder: Transaction = {} as any; public network = Network.RMS; - public guardianCreditQuery: IQuery = {} as any; + public guardianCreditQuery: IQuery = {} as any; public tokenId = ''; public proposalUid = ''; @@ -47,18 +48,17 @@ export class Helper { }; public beforeEach = async () => { - this.walletSpy = jest.spyOn(wallet, 'decodeAuth'); - this.guardian = await createMember(this.walletSpy); - const guardianDocRef = build5Db().doc(`${COL.MEMBER}/${this.guardian}`); + this.guardian = await testEnv.createMember(); + const guardianDocRef = build5Db().doc(COL.MEMBER, this.guardian); const guardianData = await guardianDocRef.get(); const guardianBech32 = getAddress(guardianData, this.network); this.guardianAddress = await this.walletService.getAddressDetails(guardianBech32); - this.space = await createSpace(this.walletSpy, this.guardian); + this.space = await testEnv.createSpace(this.guardian); this.tokenId = wallet.getRandomEthAddress(); await build5Db() - .doc(`${COL.TOKEN}/${this.tokenId}`) + .doc(COL.TOKEN, this.tokenId) .create({ project: SOON_PROJECT_ID, uid: this.tokenId, @@ -66,14 +66,15 @@ export class Helper { status: TokenStatus.MINTED, mintingData: { tokenId: MINTED_TOKEN_ID }, approved: true, - }); + } as Token); - const distributionDocRef = build5Db() - .collection(COL.TOKEN) - .doc(this.tokenId) - .collection(SUB_COL.DISTRIBUTION) - .doc(this.guardian); - await distributionDocRef.create({}); + const distributionDocRef = build5Db().doc( + COL.TOKEN, + this.tokenId, + SUB_COL.DISTRIBUTION, + this.guardian, + ); + await distributionDocRef.create({ parentId: this.tokenId, parentCol: COL.TOKEN }); this.guardianCreditQuery = build5Db() .collection(COL.TRANSACTION) @@ -135,13 +136,13 @@ export class Helper { uid: wallet.getRandomEthAddress(), token: this.tokenId, expirationProcessed: false, - }; - const docRef = build5Db().doc(`${COL.STAKE}/${stake.uid}`); + } as Stake; + const docRef = build5Db().doc(COL.STAKE, stake.uid); await docRef.create(stake); }; public assertProposalWeights = async (total: number, voted: number) => { - const proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${this.proposalUid}`); + const proposalDocRef = build5Db().doc(COL.PROPOSAL, this.proposalUid); const proposal = await proposalDocRef.get(); expect(+proposal.results?.total.toFixed(0)).toBe(total); expect(+proposal.results?.voted.toFixed(0)).toBe(voted); @@ -152,34 +153,29 @@ export class Helper { weight: number, answer: number, ) => { - const proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${this.proposalUid}`); - const proposalMemberDocRef = proposalDocRef.collection(SUB_COL.MEMBERS).doc(member); + const proposalMemberDocRef = build5Db().doc( + COL.PROPOSAL, + this.proposalUid, + SUB_COL.MEMBERS, + member, + ); const proposalMember = await proposalMemberDocRef.get(); expect(+proposalMember.weightPerAnswer![answer].toFixed(0)).toBe(weight); }; public updatePropoasalDates = (startDate: dayjs.Dayjs, endDate: dayjs.Dayjs) => - build5Db() - .doc(`${COL.PROPOSAL}/${this.proposalUid}`) - .set( - { - settings: { - startDate: dateToTimestamp(startDate), - endDate: dateToTimestamp(endDate), - }, - }, - true, - ); + build5Db().doc(COL.PROPOSAL, this.proposalUid).upsert({ + settings_startDate: startDate.toDate(), + settings_endDate: endDate.toDate(), + }); public updateVoteTranCreatedOn = (voteTransactionId: string, createdOn: dayjs.Dayjs) => - build5Db() - .doc(`${COL.TRANSACTION}/${voteTransactionId}`) - .update({ createdOn: dateToTimestamp(createdOn) }); + build5Db().doc(COL.TRANSACTION, voteTransactionId).update({ createdOn: createdOn.toDate() }); public getVoteTransactionForCredit = async (creditId: string) => { const query = build5Db() .collection(COL.TRANSACTION) - .where('payload.creditId', '==', creditId) + .where('payload_creditId', '==', creditId) .where('type', '==', TransactionType.VOTE); const voteTranSnap = await query.get(); return voteTranSnap[0] as Transaction; diff --git a/packages/functions/test-tangle/proposal-tangle/proposal.approval.spec.ts b/packages/functions/test-tangle/proposal-tangle/proposal.approval.spec.ts index 3ec213b28e..99eb6ae0c8 100644 --- a/packages/functions/test-tangle/proposal-tangle/proposal.approval.spec.ts +++ b/packages/functions/test-tangle/proposal-tangle/proposal.approval.spec.ts @@ -41,7 +41,7 @@ describe('Proposal approval via tangle request', () => { return snap.length === 2; }); - const proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${proposalUid}`); + const proposalDocRef = build5Db().doc(COL.PROPOSAL, proposalUid); const proposal = await proposalDocRef.get(); expect(approve ? proposal.approved : proposal.rejected).toBe(true); diff --git a/packages/functions/test-tangle/proposal-tangle/proposal.simple.vote.spec.ts b/packages/functions/test-tangle/proposal-tangle/proposal.simple.vote.spec.ts index 04208da99c..522a2c1232 100644 --- a/packages/functions/test-tangle/proposal-tangle/proposal.simple.vote.spec.ts +++ b/packages/functions/test-tangle/proposal-tangle/proposal.simple.vote.spec.ts @@ -5,11 +5,11 @@ import { Proposal, ProposalType, TangleRequestType, + WEN_FUNC, } from '@build-5/interfaces'; -import { approveProposal } from '../../src/runtime/firebase/proposal'; import { MnemonicService } from '../../src/services/wallet/mnemonic'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; describe('Create proposal via tangle request', () => { @@ -26,8 +26,8 @@ describe('Create proposal via tangle request', () => { it('Should create proposal and vote', async () => { const proposalUid = await helper.sendCreateProposalRequest(); - mockWalletReturnValue(helper.walletSpy, helper.guardian, { uid: proposalUid }); - await testEnv.wrap(approveProposal)({}); + mockWalletReturnValue(helper.guardian, { uid: proposalUid }); + await testEnv.wrap(WEN_FUNC.approveProposal); await helper.walletService.send( helper.guardianAddress, @@ -49,7 +49,7 @@ describe('Create proposal via tangle request', () => { return snap.length === 2; }); - let proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${proposalUid}`); + let proposalDocRef = build5Db().doc(COL.PROPOSAL, proposalUid); let proposal = await proposalDocRef.get(); expect(proposal.results.answers[1]).toBe(1); @@ -73,7 +73,7 @@ describe('Create proposal via tangle request', () => { return snap.length === 3; }); - proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${proposalUid}`); + proposalDocRef = build5Db().doc(COL.PROPOSAL, proposalUid); proposal = await proposalDocRef.get(); expect(proposal.results.answers[2]).toBe(1); expect(proposal.results.answers[1]).toBe(0); diff --git a/packages/functions/test-tangle/proposal-tangle/proposal.stake.voting.spec.ts b/packages/functions/test-tangle/proposal-tangle/proposal.stake.voting.spec.ts index e193fff0ea..161c1029b7 100644 --- a/packages/functions/test-tangle/proposal-tangle/proposal.stake.voting.spec.ts +++ b/packages/functions/test-tangle/proposal-tangle/proposal.stake.voting.spec.ts @@ -1,10 +1,15 @@ import { build5Db } from '@build-5/database'; -import { COL, MIN_IOTA_AMOUNT, TangleRequestType, Transaction } from '@build-5/interfaces'; +import { + COL, + MIN_IOTA_AMOUNT, + TangleRequestType, + Transaction, + WEN_FUNC, +} from '@build-5/interfaces'; import dayjs from 'dayjs'; import { isEmpty } from 'lodash'; -import { approveProposal } from '../../src/runtime/firebase/proposal'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; describe('Create proposal via tangle request', () => { @@ -20,8 +25,8 @@ describe('Create proposal via tangle request', () => { proposalUid = await helper.sendCreateProposalRequest(); - mockWalletReturnValue(helper.walletSpy, helper.guardian, { uid: proposalUid }); - await testEnv.wrap(approveProposal)({}); + mockWalletReturnValue(helper.guardian, { uid: proposalUid }); + await testEnv.wrap(WEN_FUNC.approveProposal); }); it('Should create proposal and vote with staked tokens', async () => { @@ -49,12 +54,13 @@ describe('Create proposal via tangle request', () => { return snap.length === 2; }); - const snap = await helper.guardianCreditQuery.get(); + const snap = await helper.guardianCreditQuery.get(); const credit = snap.find((c) => !isEmpty(c?.payload?.response?.voteTransaction))!; expect(credit.payload.amount).toBe(MIN_IOTA_AMOUNT); const voteTransactionDocRef = build5Db().doc( - `${COL.TRANSACTION}/${credit.payload.response!.voteTransaction}`, + COL.TRANSACTION, + credit.payload.response!.voteTransaction, ); const voteTransaction = await voteTransactionDocRef.get(); expect(+voteTransaction.payload.weight!.toFixed(0)).toBe(150); diff --git a/packages/functions/test-tangle/proposal-tangle/proposal.token.voting.spec.ts b/packages/functions/test-tangle/proposal-tangle/proposal.token.voting.spec.ts index 67ea1458e7..eddb686677 100644 --- a/packages/functions/test-tangle/proposal-tangle/proposal.token.voting.spec.ts +++ b/packages/functions/test-tangle/proposal-tangle/proposal.token.voting.spec.ts @@ -3,14 +3,13 @@ import { COL, MIN_IOTA_AMOUNT, TangleRequestType, - Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { approveProposal } from '../../src/runtime/firebase/proposal'; import { MnemonicService } from '../../src/services/wallet/mnemonic'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper, MINTED_TOKEN_ID } from './Helper'; describe('Create proposal via tangle request', () => { @@ -27,8 +26,8 @@ describe('Create proposal via tangle request', () => { proposalUid = await helper.sendCreateProposalRequest(); - mockWalletReturnValue(helper.walletSpy, helper.guardian, { uid: proposalUid }); - await testEnv.wrap(approveProposal)({}); + mockWalletReturnValue(helper.guardian, { uid: proposalUid }); + await testEnv.wrap(WEN_FUNC.approveProposal); }); it('Should vote full, then 50%', async () => { @@ -53,28 +52,22 @@ describe('Create proposal via tangle request', () => { .collection(COL.TRANSACTION) .where('type', '==', TransactionType.VOTE) .where('member', '==', helper.guardian); - console.log('asd', 1); await wait(async () => { const snap = await orderQuery.get(); return snap.length === 1; }); - console.log('asd', 2); - const snap = await orderQuery.get(); + const snap = await orderQuery.get(); const voteTransaction = snap[0]; - console.log('asd', helper.guardianAddress.bech32); await wait(async () => { const { amount } = await helper.walletService.getBalance(helper.guardianAddress.bech32); - console.log(amount); return amount === 6 * MIN_IOTA_AMOUNT; }); - console.log('asd', 4); await helper.assertProposalWeights(10, 10); await helper.assertProposalMemberWeightsPerAnser(helper.guardian, 10, 1); - console.log('asd', 5); await helper.updatePropoasalDates(dayjs().subtract(2, 'd'), dayjs().add(2, 'd')); await helper.updateVoteTranCreatedOn(voteTransaction.uid, dayjs().subtract(3, 'd')); }); diff --git a/packages/functions/test-tangle/soon.snapshot.only.spec.ts b/packages/functions/test-tangle/soon.snapshot.only.spec.ts deleted file mode 100644 index 67e1df265a..0000000000 --- a/packages/functions/test-tangle/soon.snapshot.only.spec.ts +++ /dev/null @@ -1,585 +0,0 @@ -import { build5App, build5Db } from '@build-5/database'; -import { - COL, - MIN_IOTA_AMOUNT, - Network, - SOON_PROJECT_ID, - SUB_COL, - SoonSnap, - TangleRequestType, - Token, - TokenDrop, - TokenDropStatus, - TokenStatus, - Transaction, - TransactionType, - getMilestoneCol, -} from '@build-5/interfaces'; -import { - AddressUnlockCondition, - AliasOutputBuilderParams, - Ed25519Address, - GovernorAddressUnlockCondition, - IssuerFeature, - NftOutputBuilderParams, - ReferenceUnlock, - StateControllerAddressUnlockCondition, - UTXOInput, - Unlock, - Utils, -} from '@iota/sdk'; -import dayjs from 'dayjs'; -import admin from 'firebase-admin'; -import { cloneDeep } from 'lodash'; -import { soonSnapshot } from '../scripts/dbUpgrades/2.1/soon.snapshot'; -import { airdropMintedToken } from '../src/runtime/firebase/token/minting'; -import { MnemonicService } from '../src/services/wallet/mnemonic'; -import { Wallet } from '../src/services/wallet/wallet'; -import { AddressDetails } from '../src/services/wallet/wallet.service'; -import { mergeOutputs } from '../src/utils/basic-output.utils'; -import { createUnlock, packEssence, submitBlock } from '../src/utils/block.utils'; -import { EMPTY_NFT_ID } from '../src/utils/collection-minting-utils/nft.utils'; -import { dateToTimestamp } from '../src/utils/dateTime.utils'; -import { EMPTY_ALIAS_ID } from '../src/utils/token-minting-utils/alias.utils'; -import * as walletUtils from '../src/utils/wallet.utils'; -import { - createMember, - createSpace, - getRandomSymbol, - mockWalletReturnValue, - wait, -} from '../test/controls/common'; -import { getWallet, testEnv } from '../test/set-up'; -import { awaitTransactionConfirmationsForToken, getTangleOrder } from './common'; -import { requestFundsFromFaucet, requestMintedTokenFromFaucet } from './faucet'; - -const tokenId = '0x08e232e6541a81d2b2c0df252e90d8ba4e6fc6680f668fc266b1e43fc3cc01f4830100000000'; -const vaultAddress = 'rms1qpukey66jkfnpvyf968ewld9df5ymfudaw7hfrry4ad3jgaxg7kp2qsz5uv'; -const vaultMnemonic = - 'slender bag negative song swallow can inform used grocery old camp scatter develop surface lock clutch year hat oyster crack obvious first member dog'; - -describe('Soon snapshot test', () => { - const network = Network.RMS; - let guardian: string; - let wallet: Wallet; - let address: AddressDetails; - let targetAddress: AddressDetails; - let currentSoonTotal: number; - let walletSpy: any; - let token: Token; - let tangleOrder: Transaction; - - beforeAll(async () => { - wallet = await getWallet(network); - tangleOrder = await getTangleOrder(Network.RMS); - }); - - beforeEach(async () => { - walletSpy = jest.spyOn(walletUtils, 'decodeAuth'); - - address = await wallet.getNewIotaAddressDetails(); - targetAddress = await wallet.getNewIotaAddressDetails(); - - guardian = await createMember(walletSpy); - await build5Db() - .doc(`${COL.MEMBER}/${guardian}`) - .update({ [`validatedAddress.${network}`]: address.bech32 }); - const space = await createSpace(walletSpy, guardian); - - const db = (build5App.getInstance() as admin.app.App).firestore(); - let snap = await db.collectionGroup(SUB_COL.TRANSACTIONS).get(); - await Promise.all(snap.docs.map((d) => d.ref.delete())); - snap = await db.collection(getMilestoneCol(network)).get(); - await Promise.all(snap.docs.map((d) => d.ref.delete())); - - currentSoonTotal = (await wallet.getBalance(vaultAddress)).nativeTokens[tokenId]; - currentSoonTotal -= 100; - - await requestFundsFromFaucet(network, address.bech32, 5 * MIN_IOTA_AMOUNT); - - const blockId = await requestMintedTokenFromFaucet( - wallet, - address, - tokenId, - vaultMnemonic, - 100, - ); - await blockInDd(blockId); - - token = { - project: SOON_PROJECT_ID, - createdBy: guardian, - symbol: getRandomSymbol(), - uid: tokenId, - space: space.uid, - status: TokenStatus.MINTED, - mintingData: { - tokenId, - network, - }, - approved: true, - } as Token; - await build5Db().doc(`${COL.TOKEN}/${tokenId}`).set(token); - }); - - it('Should get 100 token from vault and claim it', async () => { - const tokensPerMember = await soonSnapshot(build5App, tokenId, network); - expect(tokensPerMember[vaultAddress]).toBe(currentSoonTotal); - expect(tokensPerMember[address.bech32]).toBe(100); - - let snapshot = await build5Db().doc(`${COL.SOON_SNAP}/${vaultAddress}`).get(); - expect(snapshot?.uid).toBe(vaultAddress); - expect(snapshot?.count).toBe(currentSoonTotal); - expect(snapshot?.paidOut).toBe(0); - expect(snapshot?.ethAddress).toBe(''); - expect(snapshot?.ethAddressVerified).toBe(false); - - snapshot = await build5Db().doc(`${COL.SOON_SNAP}/${address.bech32}`).get(); - expect(snapshot?.uid).toBe(address.bech32); - expect(snapshot?.count).toBe(100); - expect(snapshot?.paidOut).toBe(0); - expect(snapshot?.ethAddress).toBe(''); - expect(snapshot?.ethAddressVerified).toBe(false); - - const ethAddress = '0x69252ebdc3b77624c6e640a81a086aaa720734d3'; - await wallet.send(address, tangleOrder.payload.targetAddress!, MIN_IOTA_AMOUNT, { - customMetadata: { - request: { requestType: TangleRequestType.VERIFY_ETH_ADDRESS, ethAddress }, - }, - }); - await MnemonicService.store(address.bech32, address.mnemonic); - - const creditQuery = build5Db() - .collection(COL.TRANSACTION) - .where('type', '==', TransactionType.CREDIT_TANGLE_REQUEST) - .where('member', '==', guardian); - await wait(async () => { - const snap = await creditQuery.get(); - return snap.length === 1 && snap[0].payload.walletReference?.confirmed; - }); - - const docRef = build5Db().doc(`${COL.SOON_SNAP}/${address.bech32}`); - snapshot = await docRef.get(); - expect(snapshot?.uid).toBe(address.bech32); - expect(snapshot?.count).toBe(100); - expect(snapshot?.paidOut).toBe(0); - expect(snapshot?.ethAddress).toBe(ethAddress); - expect(snapshot?.ethAddressVerified).toBe(true); - await docRef.update({ paidOut: snapshot!.count }); - - await wallet.send(address, tangleOrder.payload.targetAddress!, MIN_IOTA_AMOUNT, { - customMetadata: { - request: { requestType: TangleRequestType.VERIFY_ETH_ADDRESS, ethAddress }, - }, - }); - - await wait(async () => { - const snap = await creditQuery.get(); - return snap.length === 2; - }); - - snapshot = await docRef.get(); - expect(snapshot?.uid).toBe(address.bech32); - expect(snapshot?.count).toBe(100); - expect(snapshot?.paidOut).toBe(100); - expect(snapshot?.ethAddress).toBe(ethAddress); - expect(snapshot?.ethAddressVerified).toBe(true); - }); - - it('Should get 100 token from vault, can not claim, not following', async () => { - const tokensPerMember = await soonSnapshot(build5App, tokenId, network); - expect(tokensPerMember[vaultAddress]).toBe(currentSoonTotal); - expect(tokensPerMember[address.bech32]).toBe(100); - - let snapshot = await build5Db().doc(`${COL.SOON_SNAP}/${vaultAddress}`).get(); - expect(snapshot?.uid).toBe(vaultAddress); - expect(snapshot?.count).toBe(currentSoonTotal); - expect(snapshot?.paidOut).toBe(0); - expect(snapshot?.ethAddress).toBe(''); - expect(snapshot?.ethAddressVerified).toBe(false); - - snapshot = await build5Db().doc(`${COL.SOON_SNAP}/${address.bech32}`).get(); - expect(snapshot?.uid).toBe(address.bech32); - expect(snapshot?.count).toBe(100); - expect(snapshot?.paidOut).toBe(0); - expect(snapshot?.ethAddress).toBe(''); - expect(snapshot?.ethAddressVerified).toBe(false); - - const ethAddress = walletUtils.getRandomEthAddress(); - await wallet.send(address, tangleOrder.payload.targetAddress!, MIN_IOTA_AMOUNT, { - customMetadata: { - request: { requestType: TangleRequestType.VERIFY_ETH_ADDRESS, ethAddress }, - }, - }); - - const creditQuery = build5Db() - .collection(COL.TRANSACTION) - .where('type', '==', TransactionType.CREDIT_TANGLE_REQUEST) - .where('member', '==', guardian); - await wait(async () => { - const snap = await creditQuery.get(); - return snap.length === 1 && snap[0].payload.walletReference?.confirmed; - }); - const credit = (await creditQuery.get())[0]; - expect(credit.payload.response?.message).toBe('Must follow JustBuild'); - - const docRef = build5Db().doc(`${COL.SOON_SNAP}/${address.bech32}`); - snapshot = await docRef.get(); - expect(snapshot?.uid).toBe(address.bech32); - expect(snapshot?.count).toBe(100); - expect(snapshot?.paidOut).toBe(0); - expect(snapshot?.ethAddress).toBe(''); - expect(snapshot?.ethAddressVerified).toBe(false); - }); - - it('Should send 50 to random user, keep 50', async () => { - const blockId = await wallet.send(address, targetAddress.bech32, MIN_IOTA_AMOUNT / 2, { - nativeTokens: [{ id: tokenId, amount: BigInt(50) }], - }); - await blockInDd(blockId); - - const tokensPerMember = await soonSnapshot(build5App, tokenId, network); - expect(tokensPerMember[vaultAddress]).toBe(currentSoonTotal); - expect(tokensPerMember[address.bech32]).toBe(50); - expect(tokensPerMember[targetAddress.bech32]).toBe(50); - - await requestFundsFromFaucet(network, targetAddress.bech32, MIN_IOTA_AMOUNT); - const ethAddress = '0x69252ebdc3b77624c6e640a81a086aaa720734d3'; - await wallet.send(targetAddress, tangleOrder.payload.targetAddress!, MIN_IOTA_AMOUNT, { - customMetadata: { - request: { requestType: TangleRequestType.VERIFY_ETH_ADDRESS, ethAddress }, - }, - }); - const creditQuery = build5Db() - .collection(COL.TRANSACTION) - .where('type', '==', TransactionType.CREDIT_TANGLE_REQUEST) - .where('member', '==', targetAddress.bech32); - await wait(async () => { - const snap = await creditQuery.get(); - return snap.length === 1 && snap[0].payload.walletReference?.confirmed; - }); - - const snapshot = await build5Db() - .doc(`${COL.SOON_SNAP}/${targetAddress.bech32}`) - .get(); - expect(snapshot?.uid).toBe(targetAddress.bech32); - expect(snapshot?.count).toBe(50); - expect(snapshot?.paidOut).toBe(0); - expect(snapshot?.ethAddress).toBe(ethAddress); - expect(snapshot?.ethAddressVerified).toBe(true); - }); - - it('Receive 25 back locked', async () => { - let blockId = await wallet.send(address, targetAddress.bech32, MIN_IOTA_AMOUNT / 2, { - nativeTokens: [{ id: tokenId, amount: BigInt(50) }], - }); - await blockInDd(blockId); - - blockId = await wallet.send(targetAddress, address.bech32, 0, { - nativeTokens: [{ id: tokenId, amount: BigInt(25) }], - vestingAt: dateToTimestamp(dayjs().add(100, 'd')), - }); - await blockInDd(blockId); - - const tokensPerMember = await soonSnapshot(build5App, tokenId, network); - expect(tokensPerMember[vaultAddress]).toBe(currentSoonTotal); - expect(tokensPerMember[address.bech32]).toBe(75); - expect(tokensPerMember[targetAddress.bech32]).toBe(25); - }); - - it('Receive 10 back with expiration', async () => { - let blockId = await wallet.send(address, targetAddress.bech32, MIN_IOTA_AMOUNT / 2, { - nativeTokens: [{ id: tokenId, amount: BigInt(50) }], - }); - await blockInDd(blockId); - - blockId = await wallet.send(targetAddress, address.bech32, 0, { - nativeTokens: [{ id: tokenId, amount: BigInt(10) }], - expiration: { - expiresAt: dateToTimestamp(dayjs().add(100, 'd')), - returnAddressBech32: targetAddress.bech32, - }, - }); - await blockInDd(blockId); - - const tokensPerMember = await soonSnapshot(build5App, tokenId, network); - expect(tokensPerMember[vaultAddress]).toBe(currentSoonTotal); - expect(tokensPerMember[address.bech32]).toBe(60); - expect(tokensPerMember[targetAddress.bech32]).toBe(40); - }); - - it('Mint nft and store native tokens', async () => { - const outputs = await wallet.getOutputs(address.bech32, undefined, undefined, false); - const output = mergeOutputs(cloneDeep(Object.values(outputs))); - - const issuerAddress = new Ed25519Address(address.hex); - const ownerAddress = new Ed25519Address(targetAddress.hex); - - const nftOutputParams: NftOutputBuilderParams = { - nftId: EMPTY_NFT_ID, - immutableFeatures: [new IssuerFeature(issuerAddress)], - unlockConditions: [new AddressUnlockCondition(ownerAddress)], - nativeTokens: [{ id: tokenId, amount: BigInt(10) }], - }; - const nftOutput = await wallet.client.buildNftOutput(nftOutputParams); - - output.amount = (Number(output.amount!) - Number(nftOutput.amount)).toString(); - output.nativeTokens = [ - { id: tokenId, amount: BigInt(Number(output.nativeTokens![0].amount) - 10) }, - ]; - - const inputs = Object.keys(outputs).map(UTXOInput.fromOutputId); - const inputsCommitment = Utils.computeInputsCommitment(Object.values(outputs)); - - const essence = await packEssence( - wallet, - inputs, - inputsCommitment, - [await wallet.client.buildBasicOutput(output), nftOutput], - {}, - ); - const fromUnlock = await createUnlock(essence, address); - const unlocks: Unlock[] = Object.values(outputs).map((_, index) => - index ? new ReferenceUnlock(0) : fromUnlock, - ); - const blockId = await submitBlock(wallet, essence, unlocks); - await build5Db().doc(`blocks/${blockId}`).create({ blockId }); - await blockInDd(blockId); - - const tokensPerMember = await soonSnapshot(build5App, tokenId, network); - expect(tokensPerMember[vaultAddress]).toBe(currentSoonTotal); - expect(tokensPerMember[address.bech32]).toBe(90); - expect(tokensPerMember[targetAddress.bech32]).toBe(10); - }); - - it('Mint alias and store 10 tokens', async () => { - const outputs = await wallet.getOutputs(address.bech32, undefined, undefined, false); - const output = mergeOutputs(cloneDeep(Object.values(outputs))); - - const issuerAddress = new Ed25519Address(address.hex); - const governorAddress = new Ed25519Address(targetAddress.hex); - - const aliasOutputParams: AliasOutputBuilderParams = { - aliasId: EMPTY_ALIAS_ID, - stateIndex: 0, - foundryCounter: 0, - immutableFeatures: [new IssuerFeature(issuerAddress)], - unlockConditions: [ - new StateControllerAddressUnlockCondition(governorAddress), - new GovernorAddressUnlockCondition(governorAddress), - ], - nativeTokens: [{ id: tokenId, amount: BigInt(10) }], - }; - const aliasOutput = await wallet.client.buildAliasOutput(aliasOutputParams); - - output.amount = (Number(output.amount!) - Number(aliasOutput.amount)).toString(); - output.nativeTokens = [ - { id: tokenId, amount: BigInt(Number(output.nativeTokens![0].amount) - 10) }, - ]; - - const inputs = Object.keys(outputs).map(UTXOInput.fromOutputId); - const inputsCommitment = Utils.computeInputsCommitment(Object.values(outputs)); - - const essence = await packEssence( - wallet, - inputs, - inputsCommitment, - [await wallet.client.buildBasicOutput(output), aliasOutput], - {}, - ); - const fromUnlock = await createUnlock(essence, address); - const unlocks: Unlock[] = Object.values(outputs).map((_, index) => - index ? new ReferenceUnlock(0) : fromUnlock, - ); - const blockId = await submitBlock(wallet, essence, unlocks); - await build5Db().doc(`blocks/${blockId}`).create({ blockId }); - await blockInDd(blockId); - - const tokensPerMember = await soonSnapshot(build5App, tokenId, network); - expect(tokensPerMember[vaultAddress]).toBe(currentSoonTotal); - expect(tokensPerMember[address.bech32]).toBe(90); - expect(tokensPerMember[targetAddress.bech32]).toBe(10); - }); - - it('Airdrop 2 * 10 token, unclaimed', async () => { - const drops = [ - { - count: 10, - recipient: targetAddress.bech32, - vestingAt: dayjs().subtract(1, 'm').toDate(), - }, - { count: 10, recipient: targetAddress.bech32, vestingAt: dayjs().add(2, 'M').toDate() }, - ]; - mockWalletReturnValue(walletSpy, guardian, { token: tokenId, drops }); - let order = await testEnv.wrap(airdropMintedToken)({}); - const blockId = await wallet.send(address, order.payload.targetAddress, 0, { - nativeTokens: [{ id: tokenId, amount: BigInt(20) }], - }); - await MnemonicService.store(address.bech32, address.mnemonic); - await blockInDd(blockId); - - mockWalletReturnValue(walletSpy, guardian, { token: tokenId, drops }); - order = await testEnv.wrap(airdropMintedToken)({}); - await wallet.send(address, order.payload.targetAddress, 0, { - nativeTokens: [{ id: tokenId, amount: BigInt(20) }], - }); - - await wait(async () => { - const snap = await build5Db() - .collection(COL.AIRDROP) - .where('member', '==', targetAddress.bech32) - .get(); - const status = snap.reduce( - (acc, act) => acc && act.status === TokenDropStatus.UNCLAIMED, - true, - ); - return snap.length === 4 && status; - }); - - const tokensPerMember = await soonSnapshot(build5App, tokenId, network); - expect(tokensPerMember[vaultAddress]).toBe(currentSoonTotal); - expect(tokensPerMember[address.bech32]).toBe(60); - expect(tokensPerMember[targetAddress.bech32]).toBe(40); - }); - - it('Airdrop 2 * 10 token, claim half, do not count twice', async () => { - const tmp = await wallet.getNewIotaAddressDetails(); - const drops = [ - { - count: 10, - recipient: targetAddress.bech32, - vestingAt: dayjs().subtract(1, 'm').toDate(), - }, - { count: 10, recipient: tmp.bech32, vestingAt: dayjs().add(2, 'M').toDate() }, - ]; - mockWalletReturnValue(walletSpy, guardian, { token: tokenId, drops }); - let order = await testEnv.wrap(airdropMintedToken)({}); - const blockId = await wallet.send(address, order.payload.targetAddress, 0, { - nativeTokens: [{ id: tokenId, amount: BigInt(20) }], - }); - await MnemonicService.store(address.bech32, address.mnemonic); - await blockInDd(blockId); - - await requestFundsFromFaucet(network, tmp.bech32, MIN_IOTA_AMOUNT); - await wallet.send(tmp, tangleOrder.payload.targetAddress!, MIN_IOTA_AMOUNT, { - customMetadata: { - request: { - requestType: TangleRequestType.CLAIM_MINTED_AIRDROPS, - symbol: token.symbol, - }, - }, - }); - await MnemonicService.store(tmp.bech32, tmp.mnemonic); - - const orderQuery = build5Db() - .collection(COL.TRANSACTION) - .where('member', '==', tmp.bech32) - .where('type', '==', TransactionType.CREDIT_TANGLE_REQUEST); - - await wait(async () => { - const snap = await orderQuery.get(); - return snap.length === 1 && snap[0].payload.walletReference?.confirmed; - }); - - const claimOrder = (await orderQuery.get())[0]; - await wallet.send( - tmp, - claimOrder.payload.response!.address as string, - claimOrder.payload.response!.amount as number, - {}, - ); - - mockWalletReturnValue(walletSpy, guardian, { token: tokenId, drops }); - order = await testEnv.wrap(airdropMintedToken)({}); - await wallet.send(address, order.payload.targetAddress, 0, { - nativeTokens: [{ id: tokenId, amount: BigInt(20) }], - }); - - await wait(async () => { - const snap = await build5Db() - .collection(COL.AIRDROP) - .where('member', 'in', [targetAddress.bech32, tmp.bech32]) - .get(); - const claimed = snap.filter((s) => s.status === TokenDropStatus.CLAIMED); - const unclaimed = snap.filter((s) => s.status === TokenDropStatus.UNCLAIMED); - return snap.length === 4 && claimed.length === 1 && unclaimed.length === 3; - }); - - await awaitTransactionConfirmationsForToken(tokenId); - - const tokensPerMember = await soonSnapshot(build5App, tokenId, network); - expect(tokensPerMember[vaultAddress]).toBe(currentSoonTotal); - expect(tokensPerMember[address.bech32]).toBe(60); - expect(tokensPerMember[targetAddress.bech32]).toBe(20); - expect(tokensPerMember[tmp.bech32]).toBe(20); - - let snapshot = await build5Db().doc(`${COL.SOON_SNAP}/${vaultAddress}`).get(); - expect(snapshot?.count).toBe(currentSoonTotal); - snapshot = await build5Db().doc(`${COL.SOON_SNAP}/${address.bech32}`).get(); - expect(snapshot?.count).toBe(60); - snapshot = await build5Db().doc(`${COL.SOON_SNAP}/${targetAddress.bech32}`).get(); - expect(snapshot?.count).toBe(20); - snapshot = await build5Db().doc(`${COL.SOON_SNAP}/${tmp.bech32}`).get(); - expect(snapshot?.count).toBe(20); - }); - - it('Airdrop to member with no validated address', async () => { - const member = '0x69252ebdc3b77624c6e640a81a086aaa720734d3'; - await build5Db().doc(`${COL.MEMBER}/${member}`).set({ uid: member, validatedAddress: {} }); - const drops = [{ count: 10, recipient: member, vestingAt: dayjs().add(2, 'M').toDate() }]; - - mockWalletReturnValue(walletSpy, guardian, { token: tokenId, drops }); - let order = await testEnv.wrap(airdropMintedToken)({}); - const blockId = await wallet.send(address, order.payload.targetAddress, 0, { - nativeTokens: [{ id: tokenId, amount: BigInt(10) }], - }); - await MnemonicService.store(address.bech32, address.mnemonic); - await blockInDd(blockId); - - await wait(async () => { - const snap = await build5Db() - .collection(COL.AIRDROP) - .where('member', '==', member) - .where('status', '==', TokenDropStatus.UNCLAIMED) - .get(); - return snap.length === 1; - }); - - const tokensPerMember = await soonSnapshot(build5App, tokenId, network); - expect(tokensPerMember[vaultAddress]).toBe(currentSoonTotal); - expect(tokensPerMember[address.bech32]).toBe(90); - expect(tokensPerMember[member]).toBe(10); - - const tmp = await wallet.getNewIotaAddressDetails(); - await requestFundsFromFaucet(network, tmp.bech32, MIN_IOTA_AMOUNT); - await wallet.send(tmp, tangleOrder.payload.targetAddress!, MIN_IOTA_AMOUNT, { - customMetadata: { - request: { requestType: TangleRequestType.VERIFY_ETH_ADDRESS, ethAddress: member }, - }, - }); - - const creditQuery = build5Db() - .collection(COL.TRANSACTION) - .where('type', '==', TransactionType.CREDIT_TANGLE_REQUEST) - .where('member', '==', tmp.bech32); - await wait(async () => { - const snap = await creditQuery.get(); - return snap.length === 1 && snap[0].payload.walletReference?.confirmed; - }); - - const snapshot = await build5Db().doc(`${COL.SOON_SNAP}/${member}`).get(); - expect(snapshot?.uid).toBe(member); - expect(snapshot?.count).toBe(10); - expect(snapshot?.paidOut).toBe(0); - expect(snapshot?.ethAddress).toBe(member); - expect(snapshot?.ethAddressVerified).toBe(true); - }); -}); - -const blockInDd = async (blockId: string) => { - await wait(async () => { - const snap = await build5Db().collectionGroup(SUB_COL.TRANSACTIONS).get(); - const blockIds = snap.map((s) => s.blockId); - return blockIds.includes(blockId); - }); -}; diff --git a/packages/functions/test-tangle/space-tangle/Helper.ts b/packages/functions/test-tangle/space-tangle/Helper.ts index 4a32119719..22646f2d1b 100644 --- a/packages/functions/test-tangle/space-tangle/Helper.ts +++ b/packages/functions/test-tangle/space-tangle/Helper.ts @@ -3,13 +3,10 @@ import { COL, Member, Network, Space, Transaction, TransactionType } from '@buil 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, createSpace } from '../../test/controls/common'; -import { getWallet } from '../../test/set-up'; +import { getWallet, testEnv } from '../../test/set-up'; import { getTangleOrder } from '../common'; export class Helper { - public walletSpy: any = {} as any; public guardian: string = ''; public member: string = ''; public space: Space = {} as any; @@ -17,8 +14,8 @@ export class Helper { public walletService: Wallet = {} as any; public network = Network.RMS; public tangleOrder: Transaction = {} as any; - public memberCreditQuery: IQuery = {} as any; - public guardianCreditQuery: IQuery = {} as any; + public memberCreditQuery: IQuery = {} as any; + public guardianCreditQuery: IQuery = {} as any; public guardianAddress: AddressDetails = {} as any; public beforeAll = async () => { @@ -27,17 +24,16 @@ export class Helper { }; public beforeEach = async () => { - this.walletSpy = jest.spyOn(wallet, 'decodeAuth'); - this.guardian = await createMember(this.walletSpy); - this.member = await createMember(this.walletSpy); - this.space = await createSpace(this.walletSpy, this.guardian); + this.guardian = await testEnv.createMember(); + this.member = await testEnv.createMember(); + this.space = await testEnv.createSpace(this.guardian); - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${this.member}`); + const memberDocRef = build5Db().doc(COL.MEMBER, this.member); const memberData = await memberDocRef.get(); const memberBech32 = getAddress(memberData, this.network); this.memberAddress = await this.walletService.getAddressDetails(memberBech32); - const guardianDocRef = build5Db().doc(`${COL.MEMBER}/${this.guardian}`); + const guardianDocRef = build5Db().doc(COL.MEMBER, this.guardian); const guardianData = await guardianDocRef.get(); const guardianBech32 = getAddress(guardianData, this.network); this.guardianAddress = await this.walletService.getAddressDetails(guardianBech32); diff --git a/packages/functions/test-tangle/space-tangle/space.accept.member.spec.ts b/packages/functions/test-tangle/space-tangle/space.accept.member.spec.ts index 58fcd78ddf..330096004b 100644 --- a/packages/functions/test-tangle/space-tangle/space.accept.member.spec.ts +++ b/packages/functions/test-tangle/space-tangle/space.accept.member.spec.ts @@ -23,7 +23,7 @@ describe('Join space', () => { }); it('Should join space via tangle request', async () => { - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${helper.space.uid}`); + const spaceDocRef = build5Db().doc(COL.SPACE, helper.space.uid); await spaceDocRef.update({ open: false }); await requestFundsFromFaucet(Network.RMS, helper.memberAddress.bech32, MIN_IOTA_AMOUNT); @@ -42,7 +42,7 @@ describe('Join space', () => { ); await wait(async () => { - const snap = await helper.memberCreditQuery.get(); + const snap = await helper.memberCreditQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); let snap = await helper.memberCreditQuery.get(); @@ -70,7 +70,7 @@ describe('Join space', () => { ); await wait(async () => { - const snap = await helper.guardianCreditQuery.get(); + const snap = await helper.guardianCreditQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); snap = await helper.guardianCreditQuery.get(); diff --git a/packages/functions/test-tangle/space-tangle/space.block.member.spec.ts b/packages/functions/test-tangle/space-tangle/space.block.member.spec.ts index ae421f1a90..c5d822e830 100644 --- a/packages/functions/test-tangle/space-tangle/space.block.member.spec.ts +++ b/packages/functions/test-tangle/space-tangle/space.block.member.spec.ts @@ -6,11 +6,10 @@ import { SUB_COL, Space, TangleRequestType, - Transaction, + WEN_FUNC, } from '@build-5/interfaces'; -import { joinSpace } from '../../src/runtime/firebase/space'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -26,8 +25,8 @@ describe('Block space member', () => { }); it('Should block member', async () => { - mockWalletReturnValue(helper.walletSpy, helper.member, { uid: helper.space.uid }); - await testEnv.wrap(joinSpace)({}); + mockWalletReturnValue(helper.member, { uid: helper.space.uid }); + await testEnv.wrap(WEN_FUNC.joinSpace); await requestFundsFromFaucet(Network.RMS, helper.guardianAddress.bech32, MIN_IOTA_AMOUNT); await helper.walletService.send( @@ -46,19 +45,21 @@ describe('Block space member', () => { ); await wait(async () => { - const snap = await helper.guardianCreditQuery.get(); + const snap = await helper.guardianCreditQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${helper.space.uid}`); + const spaceDocRef = build5Db().doc(COL.SPACE, helper.space.uid); helper.space = await spaceDocRef.get(); expect(helper.space.totalMembers).toBe(1); expect(helper.space.totalGuardians).toBe(1); - const guardianCount = await spaceDocRef.collection(SUB_COL.GUARDIANS).count(); - expect(guardianCount).toBe(1); + const guardians = await build5Db() + .collection(COL.SPACE, helper.space.uid, SUB_COL.GUARDIANS) + .get(); + expect(guardians.length).toBe(1); - const memberCount = await spaceDocRef.collection(SUB_COL.MEMBERS).count(); - expect(memberCount).toBe(1); + const members = await build5Db().collection(COL.SPACE, helper.space.uid, SUB_COL.MEMBERS).get(); + expect(members.length).toBe(1); }); }); diff --git a/packages/functions/test-tangle/space-tangle/space.create.spec.ts b/packages/functions/test-tangle/space-tangle/space.create.spec.ts index 0e2193ed0c..31d91577ea 100644 --- a/packages/functions/test-tangle/space-tangle/space.create.spec.ts +++ b/packages/functions/test-tangle/space-tangle/space.create.spec.ts @@ -41,12 +41,12 @@ describe('Create space', () => { ); await wait(async () => { - const snap = await helper.memberCreditQuery.get(); + const snap = await helper.memberCreditQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); const snap = await helper.memberCreditQuery.get(); const credit = snap[0] as Transaction; - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${credit.payload.response!.space}`); + const spaceDocRef = build5Db().doc(COL.SPACE, credit.payload.response!.space as string); const space = await spaceDocRef.get(); expect(space.name).toBe('Space A'); }); diff --git a/packages/functions/test-tangle/space-tangle/space.decline.member.spec.ts b/packages/functions/test-tangle/space-tangle/space.decline.member.spec.ts index 3644240489..d34db62cda 100644 --- a/packages/functions/test-tangle/space-tangle/space.decline.member.spec.ts +++ b/packages/functions/test-tangle/space-tangle/space.decline.member.spec.ts @@ -5,11 +5,10 @@ import { Network, Space, TangleRequestType, - Transaction, + WEN_FUNC, } from '@build-5/interfaces'; -import { joinSpace } from '../../src/runtime/firebase/space'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -25,11 +24,11 @@ describe('Block space member', () => { }); it('Should block member', async () => { - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${helper.space.uid}`); + const spaceDocRef = build5Db().doc(COL.SPACE, helper.space.uid); await spaceDocRef.update({ open: false }); - mockWalletReturnValue(helper.walletSpy, helper.member, { uid: helper.space.uid }); - await testEnv.wrap(joinSpace)({}); + mockWalletReturnValue(helper.member, { uid: helper.space.uid }); + await testEnv.wrap(WEN_FUNC.joinSpace); helper.space = await spaceDocRef.get(); expect(helper.space.totalMembers).toBe(1); @@ -52,7 +51,7 @@ describe('Block space member', () => { ); await wait(async () => { - const snap = await helper.guardianCreditQuery.get(); + const snap = await helper.guardianCreditQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); diff --git a/packages/functions/test-tangle/space-tangle/space.edit.guardian.spec.ts b/packages/functions/test-tangle/space-tangle/space.edit.guardian.spec.ts index 84a261d5f5..95004a62c6 100644 --- a/packages/functions/test-tangle/space-tangle/space.edit.guardian.spec.ts +++ b/packages/functions/test-tangle/space-tangle/space.edit.guardian.spec.ts @@ -7,10 +7,10 @@ import { ProposalType, TangleRequestType, Transaction, + WEN_FUNC, } from '@build-5/interfaces'; -import { joinSpace } from '../../src/runtime/firebase/space'; -import { addGuardianToSpace, mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { addGuardianToSpace, wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -28,8 +28,8 @@ describe('Edit guardian space', () => { it.each([TangleRequestType.SPACE_ADD_GUARDIAN, TangleRequestType.SPACE_REMOVE_GUARDIAN])( 'Should add/remove guardian', async (requestType: TangleRequestType) => { - mockWalletReturnValue(helper.walletSpy, helper.member, { uid: helper.space.uid }); - await testEnv.wrap(joinSpace)({}); + mockWalletReturnValue(helper.member, { uid: helper.space.uid }); + await testEnv.wrap(WEN_FUNC.joinSpace); if (requestType === TangleRequestType.SPACE_REMOVE_GUARDIAN) { await addGuardianToSpace(helper.space.uid, helper.member); @@ -52,14 +52,14 @@ describe('Edit guardian space', () => { ); await wait(async () => { - const snap = await helper.guardianCreditQuery.get(); + const snap = await helper.guardianCreditQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); const snap = await helper.guardianCreditQuery.get(); const credit = snap[0] as Transaction; - const proposalId = credit.payload.response!.proposal; + const proposalId = credit.payload.response!.proposal as string; - const proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${proposalId}`); + const proposalDocRef = build5Db().doc(COL.PROPOSAL, proposalId); const proposal = await proposalDocRef.get(); expect(proposal.type).toBe( requestType === TangleRequestType.SPACE_ADD_GUARDIAN diff --git a/packages/functions/test-tangle/space-tangle/space.join.spec.ts b/packages/functions/test-tangle/space-tangle/space.join.spec.ts index 24c9b26070..71dde979b8 100644 --- a/packages/functions/test-tangle/space-tangle/space.join.spec.ts +++ b/packages/functions/test-tangle/space-tangle/space.join.spec.ts @@ -3,9 +3,9 @@ import { COL, MIN_IOTA_AMOUNT, Network, + SUB_COL, Space, SpaceMember, - SUB_COL, TangleRequestType, Transaction, } from '@build-5/interfaces'; @@ -41,18 +41,23 @@ describe('Join space', () => { ); await wait(async () => { - const snap = await helper.memberCreditQuery.get(); + const snap = await helper.memberCreditQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); const snap = await helper.memberCreditQuery.get(); const credit = snap[0] as Transaction; expect(credit.payload.response!.status).toBe('success'); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${helper.space.uid}`); + const spaceDocRef = build5Db().doc(COL.SPACE, helper.space.uid); helper.space = await spaceDocRef.get(); expect(helper.space.totalMembers).toBe(2); - const spaceMemberDocRef = spaceDocRef.collection(SUB_COL.MEMBERS).doc(helper.member); + const spaceMemberDocRef = build5Db().doc( + COL.SPACE, + helper.space.uid, + SUB_COL.MEMBERS, + helper.member, + ); const spaceMember = await spaceMemberDocRef.get(); expect(spaceMember).toBeDefined(); }); diff --git a/packages/functions/test-tangle/space-tangle/space.leave.spec.ts b/packages/functions/test-tangle/space-tangle/space.leave.spec.ts index 6bfe4d0d26..b8bb2e2550 100644 --- a/packages/functions/test-tangle/space-tangle/space.leave.spec.ts +++ b/packages/functions/test-tangle/space-tangle/space.leave.spec.ts @@ -6,10 +6,10 @@ import { Space, TangleRequestType, Transaction, + WEN_FUNC, } from '@build-5/interfaces'; -import { joinSpace } from '../../src/runtime/firebase/space'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -25,10 +25,10 @@ describe('Join space', () => { }); it('Should leave space via tangle request', async () => { - mockWalletReturnValue(helper.walletSpy, helper.member, { uid: helper.space.uid }); - await testEnv.wrap(joinSpace)({}); + mockWalletReturnValue(helper.member, { uid: helper.space.uid }); + await testEnv.wrap(WEN_FUNC.joinSpace); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${helper.space.uid}`); + const spaceDocRef = build5Db().doc(COL.SPACE, helper.space.uid); helper.space = await spaceDocRef.get(); expect(helper.space.totalMembers).toBe(2); @@ -48,7 +48,7 @@ describe('Join space', () => { ); await wait(async () => { - const snap = await helper.memberCreditQuery.get(); + const snap = await helper.memberCreditQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); let snap = await helper.memberCreditQuery.get(); diff --git a/packages/functions/test-tangle/staking/Helper.ts b/packages/functions/test-tangle/staking/Helper.ts index 647e505a17..55c0b0ab42 100644 --- a/packages/functions/test-tangle/staking/Helper.ts +++ b/packages/functions/test-tangle/staking/Helper.ts @@ -17,25 +17,19 @@ import { TokenStatus, Transaction, TransactionPayloadType, + WEN_FUNC, calcStakedMultiplier, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { isEmpty } from 'lodash'; -import { depositStake } from '../../src/runtime/firebase/stake'; +import { isEmpty, set } from 'lodash'; 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 { dateToTimestamp, serverTime } from '../../src/utils/dateTime.utils'; import * as wallet from '../../src/utils/wallet.utils'; -import { - createMember, - createSpace, - getRandomSymbol, - mockWalletReturnValue, - wait, -} from '../../test/controls/common'; -import { MEDIA, getWallet, testEnv } from '../../test/set-up'; +import { getRandomSymbol, wait } from '../../test/controls/common'; +import { MEDIA, getWallet, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet, requestMintedTokenFromFaucet } from '../faucet'; export class Helper { @@ -48,27 +42,23 @@ export class Helper { public memberAddress: AddressDetails | undefined; public space: Space | undefined; public walletService: Wallet | undefined; - public walletSpy: any; public network = Network.RMS; public token: Token | undefined; public tokenStats: TokenStats | undefined; public beforeAll = async () => { - this.walletSpy = jest.spyOn(wallet, 'decodeAuth'); this.walletService = await getWallet(this.network); }; public beforeEach = async () => { - const memberId = await createMember(this.walletSpy); - this.member = await build5Db().doc(`${COL.MEMBER}/${memberId}`).get(); + const memberId = await testEnv.createMember(); + this.member = await build5Db().doc(COL.MEMBER, memberId).get(); this.memberAddress = await this.walletService?.getNewIotaAddressDetails(); - this.space = await createSpace(this.walletSpy, memberId); + this.space = await testEnv.createSpace(memberId); this.token = await this.saveToken(this.space!.uid, this.member!.uid); this.tokenStats = ( - await build5Db() - .doc(`${COL.TOKEN}/${this.token.uid}/${SUB_COL.STATS}/${this.token.uid}`) - .get() + await build5Db().doc(COL.TOKEN, this.token.uid, SUB_COL.STATS, this.token.uid).get() ); await requestFundsFromFaucet(this.network, this.memberAddress!.bech32, 10 * MIN_IOTA_AMOUNT); await requestMintedTokenFromFaucet( @@ -100,9 +90,9 @@ export class Helper { }, access: 0, icon: MEDIA, - }; - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).set(token); - return token; + } as Token; + await build5Db().doc(COL.TOKEN, token.uid).create(token); + return token; }; public stakeAmount = async ( @@ -114,19 +104,23 @@ export class Helper { memberUid?: string, ) => { const member = await build5Db() - .doc(`${COL.MEMBER}/${memberUid || this.member?.uid}`) + .doc(COL.MEMBER, memberUid || this.member?.uid!) .get(); - mockWalletReturnValue(this.walletSpy, member.uid, { + + const body = { symbol: this.token?.symbol, weeks, type: type || StakeType.DYNAMIC, - customMetadata, - }); - const order = await testEnv.wrap(depositStake)({}); + }; + if (!isEmpty(customMetadata)) { + set(body, 'customMetadata', customMetadata); + } + mockWalletReturnValue(member.uid, body); + const order = await testEnv.wrap(WEN_FUNC.depositStake); const address = memberUid ? await this.walletService!.getAddressDetails(getAddress(member, Network.RMS)) : this.memberAddress!; - await this.walletService!.send(address, order.payload.targetAddress, order.payload.amount, { + await this.walletService!.send(address, order.payload.targetAddress!, order.payload.amount!, { expiration: expiresAt ? { expiresAt, returnAddressBech32: this.memberAddress!.bech32 } : undefined, @@ -149,9 +143,7 @@ export class Helper { await wait(async () => { const currTokenStats = ( - await build5Db() - .doc(`${COL.TOKEN}/${this.token?.uid}/${SUB_COL.STATS}/${this.token?.uid}`) - .get() + await build5Db().doc(COL.TOKEN, this.token?.uid!, SUB_COL.STATS, this.token?.uid).get() ); return ( (currTokenStats?.stakes || {})[type || StakeType.DYNAMIC]?.totalAmount !== @@ -159,7 +151,7 @@ export class Helper { ); }); - const billPaymentDocRef = build5Db().doc(`${COL.TRANSACTION}/${stake.billPaymentId}`); + const billPaymentDocRef = build5Db().doc(COL.TRANSACTION, stake.billPaymentId); await wait(async () => { const billPayment = await billPaymentDocRef.get(); return billPayment.payload.walletReference?.confirmed; @@ -183,9 +175,7 @@ export class Helper { membersCount: number, ) => { this.tokenStats = ( - await build5Db() - .doc(`${COL.TOKEN}/${this.token!.uid}/${SUB_COL.STATS}/${this.token?.uid}`) - .get() + await build5Db().doc(COL.TOKEN, this.token!.uid, SUB_COL.STATS, this.token?.uid).get() ); expect(this.tokenStats.stakes![type].amount).toBe(stakeAmount); expect(this.tokenStats.stakes![type].totalAmount).toBe(stakeTotalAmount); @@ -203,7 +193,7 @@ export class Helper { member?: string, ) => { const distribution = await build5Db() - .doc(`${COL.TOKEN}/${this.token!.uid}/${SUB_COL.DISTRIBUTION}/${member || this.member!.uid}`) + .doc(COL.TOKEN, this.token!.uid, SUB_COL.DISTRIBUTION, member || this.member!.uid) .get(); expect(distribution.stakes![type].amount).toBe(stakeAmount); expect(distribution.stakes![type].totalAmount).toBe(stakeTotalAmount); @@ -213,35 +203,40 @@ export class Helper { public assertDistributionStakeExpiry = async (stake: Stake) => { const distributionDocRef = build5Db().doc( - `${COL.TOKEN}/${this.token?.uid}/${SUB_COL.DISTRIBUTION}/${this.member!.uid}`, + COL.TOKEN, + this.token?.uid!, + SUB_COL.DISTRIBUTION, + this.member!.uid, ); const distirbution = await distributionDocRef.get(); expect(distirbution.stakeExpiry![stake.type][stake.expiresAt.toMillis()]).toBe(stake.value); }; public updateStakeExpiresAt = async (stake: Stake, expiresAt: dayjs.Dayjs) => { - await build5Db() - .doc(`${COL.STAKE}/${stake.uid}`) - .update({ expiresAt: dateToTimestamp(expiresAt.toDate()) }); + await build5Db().doc(COL.STAKE, stake.uid).update({ expiresAt: expiresAt.toDate() }); const distributionDocRef = build5Db().doc( - `${COL.TOKEN}/${this.token?.uid}/${SUB_COL.DISTRIBUTION}/${this.member!.uid}`, + COL.TOKEN, + this.token?.uid!, + SUB_COL.DISTRIBUTION, + this.member!.uid, ); - await distributionDocRef.set( - { - stakeExpiry: { - [stake.type]: { - [stake.expiresAt.toMillis()]: build5Db().deleteField(), - [dateToTimestamp(expiresAt.toDate()).toMillis()]: stake.value, - }, - }, + + await distributionDocRef.update({ + stakeExpiry: { [stake.type]: { [stake.expiresAt.toMillis()]: null } }, + }); + await distributionDocRef.update({ + stakeExpiry: { + [stake.type]: { [dateToTimestamp(expiresAt.toDate()).toMillis()]: stake.value }, }, - true, - ); + }); }; public assertStakeExpiryCleared = async (type: StakeType) => { const distributionDocRef = build5Db().doc( - `${COL.TOKEN}/${this.token?.uid}/${SUB_COL.DISTRIBUTION}/${this.member!.uid}`, + COL.TOKEN, + this.token?.uid!, + SUB_COL.DISTRIBUTION, + this.member!.uid, ); const distribution = await distributionDocRef.get(); expect(isEmpty(distribution.stakeExpiry![type])).toBe(true); diff --git a/packages/functions/test-tangle/staking/staking_1.spec.ts b/packages/functions/test-tangle/staking/staking_1.spec.ts index 3ac23d42b4..08642c0dbf 100644 --- a/packages/functions/test-tangle/staking/staking_1.spec.ts +++ b/packages/functions/test-tangle/staking/staking_1.spec.ts @@ -8,22 +8,16 @@ import { SUB_COL, Transaction, TransactionType, + WEN_FUNC, WenError, } from '@build-5/interfaces'; import { UnlockConditionType } from '@iota/sdk'; import dayjs from 'dayjs'; import { removeExpiredStakesFromSpace } from '../../src/cron/stake.cron'; -import { depositStake } from '../../src/runtime/firebase/stake'; import { MnemonicService } from '../../src/services/wallet/mnemonic'; import { dateToTimestamp } from '../../src/utils/dateTime.utils'; -import { - addGuardianToSpace, - createMember, - expectThrow, - mockWalletReturnValue, - wait, -} from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { addGuardianToSpace, expectThrow, wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; describe('Staking test', () => { @@ -52,13 +46,19 @@ describe('Staking test', () => { type: StakeType.STATIC, customMetadata, }; - mockWalletReturnValue(helper.walletSpy, helper.member!.uid, data); - await expectThrow(testEnv.wrap(depositStake)({}), WenError.invalid_params.key); + mockWalletReturnValue(helper.member!.uid, data); + await expectThrow( + testEnv.wrap(WEN_FUNC.depositStake), + WenError.invalid_params.key, + ); delete customMetadata.key6; customMetadata.key5 = 12; - mockWalletReturnValue(helper.walletSpy, helper.member!.uid, { ...data, customMetadata }); - await expectThrow(testEnv.wrap(depositStake)({}), WenError.invalid_params.key); + mockWalletReturnValue(helper.member!.uid, { ...data, customMetadata }); + await expectThrow( + testEnv.wrap(WEN_FUNC.depositStake), + WenError.invalid_params.key, + ); }); it('Should throw, invalid weeks', async () => { @@ -67,11 +67,17 @@ describe('Staking test', () => { weeks: 0, type: StakeType.STATIC, }; - mockWalletReturnValue(helper.walletSpy, helper.member!.uid, data); - await expectThrow(testEnv.wrap(depositStake)({}), WenError.invalid_params.key); + mockWalletReturnValue(helper.member!.uid, data); + await expectThrow( + testEnv.wrap(WEN_FUNC.depositStake), + WenError.invalid_params.key, + ); - mockWalletReturnValue(helper.walletSpy, helper.member!.uid, { ...data, weeks: 53 }); - await expectThrow(testEnv.wrap(depositStake)({}), WenError.invalid_params.key); + mockWalletReturnValue(helper.member!.uid, { ...data, weeks: 53 }); + await expectThrow( + testEnv.wrap(WEN_FUNC.depositStake), + WenError.invalid_params.key, + ); }); it.each([ @@ -79,22 +85,16 @@ describe('Staking test', () => { { expiration: false, type: StakeType.STATIC }, { expiration: true, type: StakeType.DYNAMIC }, ])('Should set stake amount and remove it once expired', async ({ expiration, type }) => { - const secondGuardian = await createMember(helper.walletSpy!); + const secondGuardian = await testEnv.createMember(); await addGuardianToSpace(helper.space?.uid!, secondGuardian); await build5Db() - .doc(`${COL.TOKEN}/${helper.token?.uid!}/${SUB_COL.DISTRIBUTION}/${secondGuardian}`) - .set({ + .doc(COL.TOKEN, helper.token?.uid!, SUB_COL.DISTRIBUTION, secondGuardian) + .upsert({ parentId: helper.token?.uid!, - parentCol: COL.TOKEN, - uid: secondGuardian, - stakes: { - [StakeType.DYNAMIC]: { - amount: 10, - totalAmount: 10, - value: 10, - totalValue: 10, - }, - }, + stakes_dynamic_amount: 10, + stakes_dynamic_totalAmount: 10, + stakes_dynamic_value: 10, + stakes_dynamic_totalValue: 10, }); const expiresAt = expiration ? dateToTimestamp(dayjs().add(1, 'h').toDate()) : undefined; @@ -104,7 +104,7 @@ describe('Staking test', () => { await helper.validateMemberStakeAmount(10, 10, 14, 14, type); await helper.assertDistributionStakeExpiry(stake1); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${helper.space?.uid}`); + const spaceDocRef = build5Db().doc(COL.SPACE, helper.space?.uid!); await spaceDocRef.update({ tokenBased: true, minStakedValue: 10 }); const stake2 = await helper.stakeAmount(20, 26, expiresAt, type); @@ -163,17 +163,17 @@ describe('Staking test', () => { it('Should credit invalid stake payment', async () => { const expiresAt = dateToTimestamp(dayjs().add(1, 'h').toDate()); - mockWalletReturnValue(helper.walletSpy, helper.member!.uid, { + mockWalletReturnValue(helper.member!.uid, { symbol: helper.token?.symbol, weeks: 26, type: StakeType.DYNAMIC, }); - const order = await testEnv.wrap(depositStake)({}); + const order = await testEnv.wrap(WEN_FUNC.depositStake); await helper.walletService!.send( helper.memberAddress!, - order.payload.targetAddress, - order.payload.amount, + order.payload.targetAddress!, + order.payload.amount!, { expiration: { expiresAt, returnAddressBech32: helper.memberAddress!.bech32 }, nativeTokens: [{ id: helper.MINTED_TOKEN_ID, amount: BigInt(10) }], @@ -193,8 +193,8 @@ describe('Staking test', () => { .get(); if (snap.length) { await build5Db() - .doc(`${COL.TRANSACTION}/${order.uid}`) - .update({ 'payload.expiresOn': dateToTimestamp(dayjs().subtract(1, 'd')) }); + .doc(COL.TRANSACTION, order.uid) + .update({ payload_expiresOn: dayjs().subtract(1, 'd').toDate() }); } return snap.length > 0; }, @@ -210,7 +210,7 @@ describe('Staking test', () => { const snap = await creditQuery.get(); return snap.length > 0; }); - const credits = await creditQuery.get(); + const credits = await creditQuery.get(); expect(credits.length).toBe(1); expect(credits[0]?.payload.targetAddress).toBe(helper.memberAddress?.bech32); }); diff --git a/packages/functions/test-tangle/staking/staking_2.spec.ts b/packages/functions/test-tangle/staking/staking_2.spec.ts index fea3cdfa81..3dab3194d6 100644 --- a/packages/functions/test-tangle/staking/staking_2.spec.ts +++ b/packages/functions/test-tangle/staking/staking_2.spec.ts @@ -3,7 +3,6 @@ import { COL, Space, StakeType } from '@build-5/interfaces'; import { FeatureType, MetadataFeature, UnlockConditionType, hexToUtf8 } from '@iota/sdk'; import dayjs from 'dayjs'; import { removeExpiredStakesFromSpace } from '../../src/cron/stake.cron'; -import { dateToTimestamp } from '../../src/utils/dateTime.utils'; import { Helper } from './Helper'; describe('Staking test', () => { @@ -21,7 +20,7 @@ describe('Staking test', () => { const type = StakeType.DYNAMIC; const customMetadata = { name: 'random name', - asd: 'true', + isOld: 'true', }; await helper.stakeAmount(10, 26, undefined, type, customMetadata); await helper.validateStatsStakeAmount(10, 10, 14, 14, type, 1); @@ -40,13 +39,13 @@ describe('Staking test', () => { ); const decoded = JSON.parse(hexToUtf8(hexMetadata.data)); expect(decoded.name).toBe(customMetadata.name); - expect(decoded.asd).toBe(customMetadata.asd); + expect(decoded.isOld).toBe(customMetadata.isOld); }); it.each([StakeType.DYNAMIC, StakeType.STATIC])( 'Should set stake amount and remove it once expired, 52 weeks', async (type: StakeType) => { - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${helper.space?.uid}`); + const spaceDocRef = build5Db().doc(COL.SPACE, helper.space?.uid!); await spaceDocRef.update({ tokenBased: true, minStakedValue: 10 }); let space = await spaceDocRef.get(); expect(space.totalMembers).toBe(1); @@ -65,15 +64,15 @@ describe('Staking test', () => { await helper.validateMemberStakeAmount(30, 30, 60, 60, type); await build5Db() - .doc(`${COL.STAKE}/${stake2.uid}`) - .update({ expiresAt: dateToTimestamp(dayjs().subtract(1, 'm').toDate()) }); + .doc(COL.STAKE, stake2.uid) + .update({ expiresAt: dayjs().subtract(1, 'm').toDate() }); await removeExpiredStakesFromSpace(); await helper.validateStatsStakeAmount(10, 30, 20, 60, type, 1); await helper.validateMemberStakeAmount(10, 30, 20, 60, type); await build5Db() - .doc(`${COL.STAKE}/${stake1.uid}`) - .update({ expiresAt: dateToTimestamp(dayjs().subtract(1, 'm').toDate()) }); + .doc(COL.STAKE, stake1.uid) + .update({ expiresAt: dayjs().subtract(1, 'm').toDate() }); await removeExpiredStakesFromSpace(); await helper.validateStatsStakeAmount(0, 30, 0, 60, type, 0); await helper.validateMemberStakeAmount(0, 30, 0, 60, type); diff --git a/packages/functions/test-tangle/staking/staking_3.spec.ts b/packages/functions/test-tangle/staking/staking_3.spec.ts index a765b49bfc..d0ca2b8841 100644 --- a/packages/functions/test-tangle/staking/staking_3.spec.ts +++ b/packages/functions/test-tangle/staking/staking_3.spec.ts @@ -2,7 +2,6 @@ import { build5Db } from '@build-5/database'; import { COL, Member, MIN_IOTA_AMOUNT, Stake, StakeType } from '@build-5/interfaces'; import dayjs from 'dayjs'; import { removeExpiredStakesFromSpace } from '../../src/cron/stake.cron'; -import { dateToTimestamp } from '../../src/utils/dateTime.utils'; import { setProdTiers, setTestTiers, wait } from '../../test/controls/common'; import { requestMintedTokenFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -21,15 +20,15 @@ describe('Staking test', () => { const validateMemberTradingFee = async (expected: number) => { await wait(async () => { - helper.member = await build5Db().doc(`${COL.MEMBER}/${helper.member?.uid}`).get(); - return helper.member.tokenTradingFeePercentage === expected; + helper.member = await build5Db().doc(COL.MEMBER, helper.member?.uid!).get(); + return (helper.member.tokenTradingFeePercentage || 0) === expected; }); }; const expireStakeAndValidateFee = async (stake: Stake, expectedFee: number) => { await build5Db() - .doc(`${COL.STAKE}/${stake.uid}`) - .update({ expiresAt: dateToTimestamp(dayjs().subtract(1, 'm').toDate()) }); + .doc(COL.STAKE, stake.uid) + .update({ expiresAt: dayjs().subtract(1, 'm').toDate() }); await removeExpiredStakesFromSpace(); await validateMemberTradingFee(expectedFee); }; diff --git a/packages/functions/test-tangle/staking/staking_4.spec.ts b/packages/functions/test-tangle/staking/staking_4.spec.ts index 8493be328b..1f0575bcf5 100644 --- a/packages/functions/test-tangle/staking/staking_4.spec.ts +++ b/packages/functions/test-tangle/staking/staking_4.spec.ts @@ -14,17 +14,17 @@ import { TokenDrop, Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; import { isEmpty } from 'lodash'; import { onStakeRewardExpired } from '../../src/cron/stakeReward.cron'; import { retryWallet } from '../../src/cron/wallet.cron'; -import { claimMintedTokenOrder } from '../../src/runtime/firebase/token/minting'; import { getAddress } from '../../src/utils/address.utils'; import { dateToTimestamp, serverTime } from '../../src/utils/dateTime.utils'; import { getRandomEthAddress } from '../../src/utils/wallet.utils'; -import { createMember, mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken } from '../common'; import { requestFundsFromFaucet, requestMintedTokenFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -56,7 +56,10 @@ describe('Stake reward test test', () => { true, ); const distributionDocRef = build5Db().doc( - `${COL.TOKEN}/${helper.token!.uid}/${SUB_COL.DISTRIBUTION}/${member}`, + COL.TOKEN, + helper.token!.uid, + SUB_COL.DISTRIBUTION, + member, ); const distribution = await distributionDocRef.get(); expect(distribution.stakeRewards).toBe(count); @@ -74,7 +77,7 @@ describe('Stake reward test test', () => { token: helper.token?.uid!, status: StakeRewardStatus.UNPROCESSED, }; - const stakeRewardDocRef = build5Db().doc(`${COL.STAKE_REWARD}/${stakeReward.uid}`); + const stakeRewardDocRef = build5Db().doc(COL.STAKE_REWARD, stakeReward.uid); await stakeRewardDocRef.create(stakeReward); await onStakeRewardExpired(); @@ -95,8 +98,8 @@ describe('Stake reward test test', () => { await helper.stakeAmount(1000, 26); await helper.validateStatsStakeAmount(1000, 1000, 1490, 1490, StakeType.DYNAMIC, 1); - const member2Uid = await createMember(helper.walletSpy); - const member2 = await build5Db().doc(`${COL.MEMBER}/${member2Uid}`).get(); + const member2Uid = await testEnv.createMember(); + const member2 = await build5Db().doc(COL.MEMBER, member2Uid).get(); const member2Address = await helper.walletService?.getAddressDetails( getAddress(member2, helper.network)!, )!; @@ -122,7 +125,7 @@ describe('Stake reward test test', () => { token: helper.token?.uid!, status: StakeRewardStatus.UNPROCESSED, }; - const stakeRewardDocRef = build5Db().doc(`${COL.STAKE_REWARD}/${stakeReward.uid}`); + const stakeRewardDocRef = build5Db().doc(COL.STAKE_REWARD, stakeReward.uid); await stakeRewardDocRef.create(stakeReward); await onStakeRewardExpired(); @@ -162,16 +165,16 @@ describe('Stake reward test test', () => { token: helper.token?.uid!, status: StakeRewardStatus.UNPROCESSED, }; - const stakeRewardDocRef = build5Db().doc(`${COL.STAKE_REWARD}/${stakeReward.uid}`); + const stakeRewardDocRef = build5Db().doc(COL.STAKE_REWARD, stakeReward.uid); await stakeRewardDocRef.create(stakeReward); await onStakeRewardExpired(); await verifyMemberAirdrop(helper.member!.uid, 149); - mockWalletReturnValue(helper.walletSpy, helper.member!.uid, { + mockWalletReturnValue(helper.member!.uid, { symbol: helper.token!.symbol, }); - const claimOrder = await testEnv.wrap(claimMintedTokenOrder)({}); + const claimOrder = await testEnv.wrap(WEN_FUNC.claimMintedTokenOrder); await requestFundsFromFaucet( helper.network, claimOrder.payload.targetAddress, @@ -189,7 +192,7 @@ describe('Stake reward test test', () => { await awaitTransactionConfirmationsForToken(helper.token?.uid!); - const member = await build5Db().doc(`${COL.MEMBER}/${helper.member?.uid}`).get(); + const member = await build5Db().doc(COL.MEMBER, helper.member?.uid!).get(); for (const address of [helper.memberAddress?.bech32!, getAddress(member, Network.RMS)]) { const outputs = await helper.walletService!.getOutputs(address, [], false, true); const nativeTokens = Object.values(outputs).reduce( @@ -200,7 +203,10 @@ describe('Stake reward test test', () => { } const distributionDocRef = build5Db().doc( - `${COL.TOKEN}/${helper.token?.uid}/${SUB_COL.DISTRIBUTION}/${helper.member?.uid}`, + COL.TOKEN, + helper.token?.uid!, + SUB_COL.DISTRIBUTION, + helper.member?.uid, ); await wait(async () => { const distribution = await distributionDocRef.get(); @@ -225,16 +231,16 @@ describe('Stake reward test test', () => { token: helper.token?.uid!, status: StakeRewardStatus.UNPROCESSED, }; - const stakeRewardDocRef = build5Db().doc(`${COL.STAKE_REWARD}/${stakeReward.uid}`); + const stakeRewardDocRef = build5Db().doc(COL.STAKE_REWARD, stakeReward.uid); await stakeRewardDocRef.create(stakeReward); await onStakeRewardExpired(); await verifyMemberAirdrop(helper.member!.uid, 149); - mockWalletReturnValue(helper.walletSpy, helper.member!.uid, { + mockWalletReturnValue(helper.member!.uid, { symbol: helper.token!.symbol, }); - const claimOrder = await testEnv.wrap(claimMintedTokenOrder)({}); + const claimOrder = await testEnv.wrap(WEN_FUNC.claimMintedTokenOrder); await requestFundsFromFaucet( helper.network, claimOrder.payload.targetAddress, @@ -247,7 +253,7 @@ describe('Stake reward test test', () => { .where('type', '==', TransactionType.BILL_PAYMENT); let failed: any; await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); failed = snap.find((d) => d?.payload?.walletReference?.count === 5); return snap.length === 2 && failed !== undefined; }); @@ -267,17 +273,17 @@ describe('Stake reward test test', () => { }); if (failed) { - const docRef = build5Db().doc(`${COL.TRANSACTION}/${failed.uid}`); + const docRef = build5Db().doc(COL.TRANSACTION, failed.uid); await docRef.update({ - 'payload.walletReference.count': 4, - 'payload.walletReference.processedOn': dateToTimestamp(dayjs().subtract(1, 'h')), + payload_walletReference_count: 4, + payload_walletReference_processedOn: dayjs().subtract(1, 'h').toDate(), }); } await retryWallet(); await awaitTransactionConfirmationsForToken(helper.token?.uid!); - const member = await build5Db().doc(`${COL.MEMBER}/${helper.member?.uid}`).get(); + const member = await build5Db().doc(COL.MEMBER, helper.member?.uid!).get(); for (const address of [helper.memberAddress?.bech32!, getAddress(member, Network.RMS)]) { const outputs = await helper.walletService!.getOutputs(address, [], false, true); const nativeTokens = Object.values(outputs).reduce( @@ -303,17 +309,17 @@ describe('Stake reward test test', () => { await helper.stakeAmount(25, 26); const stake = await helper.stakeAmount(12, 26); await build5Db() - .doc(`${COL.STAKE}/${stake.uid}`) + .doc(COL.STAKE, stake.uid) .update({ - createdOn: dateToTimestamp(dayjs().subtract(3, 'h')), - expiresAt: dateToTimestamp(dayjs().subtract(2, 'h')), + createdOn: dayjs().subtract(3, 'h').toDate(), + expiresAt: dayjs().subtract(2, 'h').toDate(), }); const stake2 = await helper.stakeAmount(13, 26); await build5Db() - .doc(`${COL.STAKE}/${stake2.uid}`) + .doc(COL.STAKE, stake2.uid) .update({ - createdOn: dateToTimestamp(dayjs().add(2, 'h')), - expiresAt: dateToTimestamp(dayjs().add(3, 'h')), + createdOn: dayjs().add(2, 'h').toDate(), + expiresAt: dayjs().add(3, 'h').toDate(), }); let stakeReward: StakeReward = { @@ -327,7 +333,7 @@ describe('Stake reward test test', () => { token: helper.token?.uid!, status: StakeRewardStatus.UNPROCESSED, }; - const stakeRewardDocRef = build5Db().doc(`${COL.STAKE_REWARD}/${stakeReward.uid}`); + const stakeRewardDocRef = build5Db().doc(COL.STAKE_REWARD, stakeReward.uid); await stakeRewardDocRef.create(stakeReward); await onStakeRewardExpired(); @@ -343,9 +349,12 @@ describe('Stake reward test test', () => { it('Should claim extras properly', async () => { const distributionDocRef = build5Db().doc( - `${COL.TOKEN}/${helper.token?.uid!}/${SUB_COL.DISTRIBUTION}/${helper.member?.uid}`, + COL.TOKEN, + helper.token?.uid!, + SUB_COL.DISTRIBUTION, + helper.member?.uid, ); - await distributionDocRef.set({ extraStakeRewards: 400 }, true); + await distributionDocRef.upsert({ extraStakeRewards: 400 }); const vaultAddress = await helper.walletService!.getAddressDetails(helper.space?.vaultAddress!); await requestFundsFromFaucet(helper.network, vaultAddress.bech32, MIN_IOTA_AMOUNT); @@ -370,7 +379,7 @@ describe('Stake reward test test', () => { token: helper.token?.uid!, status: StakeRewardStatus.UNPROCESSED, }; - const stakeRewardDocRef = build5Db().doc(`${COL.STAKE_REWARD}/${stakeReward.uid}`); + const stakeRewardDocRef = build5Db().doc(COL.STAKE_REWARD, stakeReward.uid); await stakeRewardDocRef.create(stakeReward); const billPaymentQuery = build5Db() @@ -380,12 +389,12 @@ describe('Stake reward test test', () => { // No reward, 149 reduction await onStakeRewardExpired(); - let snap = await billPaymentQuery.get(); + let snap = await billPaymentQuery.get(); expect(snap.length).toBe(1); await stakeRewardDocRef.update({ status: StakeRewardStatus.UNPROCESSED }); let distribution = await distributionDocRef.get(); expect(distribution.extraStakeRewards).toBe(251); - snap = await billPaymentQuery.get(); + snap = await billPaymentQuery.get(); expect(snap[0]?.payload.nativeTokens![0]?.amount).toBe(149); // No reward, 149 reduction diff --git a/packages/functions/test-tangle/staking/staking_5.spec.ts b/packages/functions/test-tangle/staking/staking_5.spec.ts index f693cea0f8..cb9c9ea316 100644 --- a/packages/functions/test-tangle/staking/staking_5.spec.ts +++ b/packages/functions/test-tangle/staking/staking_5.spec.ts @@ -3,8 +3,8 @@ import { COL, MIN_IOTA_AMOUNT, Network, - StakeType, SUB_COL, + StakeType, TangleRequestType, TokenDistribution, Transaction, @@ -54,11 +54,14 @@ describe('Stake reward test test', () => { }, }, }); - await build5Db().doc(`${COL.MNEMONIC}/${tmp.bech32}`).update({ consumedOutputIds: [] }); + await build5Db().doc(COL.MNEMONIC, tmp.bech32).update({ consumedOutputIds: [] }); await wait(async () => { const distributionDocRef = build5Db().doc( - `${COL.TOKEN}/${helper.token!.uid}/${SUB_COL.DISTRIBUTION}/${tmp.bech32}`, + COL.TOKEN, + helper.token!.uid, + SUB_COL.DISTRIBUTION, + tmp.bech32, ); const distribution = await distributionDocRef.get(); return (distribution?.stakes || {})[type]?.value === 200; diff --git a/packages/functions/test-tangle/stamp-tangle/Helper.ts b/packages/functions/test-tangle/stamp-tangle/Helper.ts index 2ceab6bcfe..37435fe8a6 100644 --- a/packages/functions/test-tangle/stamp-tangle/Helper.ts +++ b/packages/functions/test-tangle/stamp-tangle/Helper.ts @@ -55,11 +55,11 @@ export class Helper { .where('member', '==', this.address.bech32) .where('type', '==', TransactionType.CREDIT_TANGLE_REQUEST); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1 && snap[0].payload.walletReference?.confirmed === true; }); - const credit = (await query.get())[0]; + const credit = (await query.get())[0]; return credit.payload.response!; }; } diff --git a/packages/functions/test-tangle/stamp-tangle/stamp-tangle_1_a.spec.ts b/packages/functions/test-tangle/stamp-tangle/stamp-tangle_1_a.spec.ts index 732aeabce8..4c7f5a3a72 100644 --- a/packages/functions/test-tangle/stamp-tangle/stamp-tangle_1_a.spec.ts +++ b/packages/functions/test-tangle/stamp-tangle/stamp-tangle_1_a.spec.ts @@ -1,12 +1,5 @@ import { build5Db } from '@build-5/database'; -import { - COL, - KEY_NAME_TANGLE, - MediaStatus, - Stamp, - Transaction, - TransactionType, -} from '@build-5/interfaces'; +import { COL, KEY_NAME_TANGLE, MediaStatus, Stamp, TransactionType } from '@build-5/interfaces'; import { NftOutput } from '@iota/sdk'; import dayjs from 'dayjs'; import { uploadMediaToWeb3 } from '../../src/cron/media.cron'; @@ -23,7 +16,7 @@ describe('Stamp tangle test', () => { beforeEach(helper.beforeEach); it('Should create and mint stamp', async () => { - const fiftyDayCost = 2124 * 50 + 53700 + 108000; + const fiftyDayCost = 2124 * 50 + 53700 + 104500; await helper.wallet!.send( helper.address, @@ -35,10 +28,10 @@ describe('Stamp tangle test', () => { const query = build5Db().collection(COL.STAMP).where('createdBy', '==', helper.address.bech32); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1 && snap[0].funded; }); - let stamp = (await query.get())[0]; + let stamp = (await query.get())[0]; expect(stamp?.mediaStatus).toBe(MediaStatus.PENDING_UPLOAD); expect(stamp?.ipfsMedia).toBeDefined(); @@ -48,12 +41,12 @@ describe('Stamp tangle test', () => { expect(expiresBefore51Days).toBe(true); await uploadMediaToWeb3(); - const stampDocRef = build5Db().doc(`${COL.STAMP}/${stamp.uid}`); + const stampDocRef = build5Db().doc(COL.STAMP, stamp.uid); await wait(async () => { - const stamp = await stampDocRef.get(); + const stamp = await stampDocRef.get(); return stamp?.mediaStatus === MediaStatus.UPLOADED; }); - const uploadedMediaStamp = await stampDocRef.get(); + const uploadedMediaStamp = await stampDocRef.get(); expect(uploadedMediaStamp?.ipfsMedia).toBe(stamp?.ipfsMedia); await wait(async () => { @@ -74,8 +67,8 @@ describe('Stamp tangle test', () => { const billPayment = await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.BILL_PAYMENT) - .where('payload.stamp', '==', stamp?.uid) - .get(); + .where('payload_stamp', '==', stamp?.uid) + .get(); expect(billPayment.length).toBe(1); }); }); diff --git a/packages/functions/test-tangle/stamp-tangle/stamp-tangle_1_b.spec.ts b/packages/functions/test-tangle/stamp-tangle/stamp-tangle_1_b.spec.ts index ab60c89f62..b331c7cf5d 100644 --- a/packages/functions/test-tangle/stamp-tangle/stamp-tangle_1_b.spec.ts +++ b/packages/functions/test-tangle/stamp-tangle/stamp-tangle_1_b.spec.ts @@ -5,7 +5,6 @@ import { MIN_IOTA_AMOUNT, MediaStatus, Stamp, - Transaction, TransactionType, } from '@build-5/interfaces'; import { NftOutput } from '@iota/sdk'; @@ -34,10 +33,10 @@ describe('Stamp tangle test', () => { const query = build5Db().collection(COL.STAMP).where('createdBy', '==', helper.address.bech32); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1 && snap[0].funded; }); - let stamp = (await query.get())[0]; + let stamp = (await query.get())[0]; expect(stamp?.mediaStatus).toBe(MediaStatus.PENDING_UPLOAD); expect(stamp?.ipfsMedia).toBeDefined(); @@ -47,12 +46,12 @@ describe('Stamp tangle test', () => { expect(expiresAfter30Days).toBe(true); await uploadMediaToWeb3(); - const stampDocRef = build5Db().doc(`${COL.STAMP}/${stamp.uid}`); + const stampDocRef = build5Db().doc(COL.STAMP, stamp.uid); await wait(async () => { - const stamp = await stampDocRef.get(); + const stamp = await stampDocRef.get(); return stamp?.mediaStatus === MediaStatus.UPLOADED; }); - const uploadedMediaStamp = await stampDocRef.get(); + const uploadedMediaStamp = await stampDocRef.get(); expect(uploadedMediaStamp?.ipfsMedia).toBe(stamp?.ipfsMedia); await wait(async () => { @@ -73,8 +72,8 @@ describe('Stamp tangle test', () => { const billPayment = await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.BILL_PAYMENT) - .where('payload.stamp', '==', stamp?.uid) - .get(); + .where('payload_stamp', '==', stamp?.uid) + .get(); expect(billPayment.length).toBe(1); }); }); diff --git a/packages/functions/test-tangle/stamp-tangle/stamp-tangle_2.spec.ts b/packages/functions/test-tangle/stamp-tangle/stamp-tangle_2.spec.ts index b66e1f72fe..272b41b492 100644 --- a/packages/functions/test-tangle/stamp-tangle/stamp-tangle_2.spec.ts +++ b/packages/functions/test-tangle/stamp-tangle/stamp-tangle_2.spec.ts @@ -1,5 +1,5 @@ import { build5Db } from '@build-5/database'; -import { COL, MIN_IOTA_AMOUNT, Stamp } from '@build-5/interfaces'; +import { COL, MIN_IOTA_AMOUNT } from '@build-5/interfaces'; import { isEmpty } from 'lodash'; import { MnemonicService } from '../../src/services/wallet/mnemonic'; import { EMPTY_ALIAS_ID } from '../../src/utils/token-minting-utils/alias.utils'; @@ -23,10 +23,10 @@ describe('Stamp tangle test', () => { let query = build5Db().collection(COL.STAMP).where('createdBy', '==', helper.address.bech32); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1 && snap[0].aliasId !== EMPTY_ALIAS_ID; }); - const stamp = (await query.get())[0]; + const stamp = (await query.get())[0]; await helper.wallet!.send( helper.address, @@ -37,15 +37,15 @@ describe('Stamp tangle test', () => { await MnemonicService.store(helper.address.bech32, helper.address.mnemonic); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 2 && snap[0].aliasId === snap[1].aliasId; }); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.reduce((acc, act) => acc && !isEmpty(act.nftId), true); }); - const stamps = await query.get(); + const stamps = await query.get(); expect(stamps.length).toBe(2); expect(stamps[0].aliasId).toBe(stamps[1].aliasId); expect(stamps[0].nftId).not.toBe(stamps[1].nftId); diff --git a/packages/functions/test-tangle/stamp-tangle/stamp-tangle_3.spec.ts b/packages/functions/test-tangle/stamp-tangle/stamp-tangle_3.spec.ts index 9f66919cc9..1b3ea38dce 100644 --- a/packages/functions/test-tangle/stamp-tangle/stamp-tangle_3.spec.ts +++ b/packages/functions/test-tangle/stamp-tangle/stamp-tangle_3.spec.ts @@ -20,7 +20,7 @@ describe('Stamp tangle test', () => { it('Should extend stamp', async () => { const now = dayjs(); - const fiftyDayCost = 2124 * 50 + 53700 + 108000; + const fiftyDayCost = 2124 * 50 + 53700 + 104500; await helper.wallet!.send( helper.address, helper.tangleOrder.payload.targetAddress!, @@ -31,21 +31,21 @@ describe('Stamp tangle test', () => { const query = build5Db().collection(COL.STAMP).where('createdBy', '==', helper.address.bech32); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1 && snap[0].nftId !== undefined; }); - let stamp = (await query.get())[0]; + let stamp = (await query.get())[0]; const expiresAfter50Days = dayjs(stamp?.expiresAt.toDate()).isAfter(dayjs().add(4.32e9)); expect(expiresAfter50Days).toBe(true); - const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${stamp.order}`); + const orderDocRef = build5Db().doc(COL.TRANSACTION, stamp.order); const order = await orderDocRef.get(); await helper.wallet!.send(helper.address, order.payload.targetAddress!, fiftyDayCost, {}); await MnemonicService.store(helper.address.bech32, helper.address.mnemonic); await wait(async () => { - const stamp = (await query.get())[0]; + const stamp = (await query.get())[0]; const expiresAfter100Days = dayjs(stamp?.expiresAt.toDate()).isAfter(now.add(2 * 4.32e9)); return expiresAfter100Days; }); @@ -59,7 +59,7 @@ describe('Stamp tangle test', () => { .get(); expect(snap.length).toBe(2); - const stampDocRef = build5Db().doc(`${COL.STAMP}/${stamp.uid}`); + const stampDocRef = build5Db().doc(COL.STAMP, stamp.uid); await stampDocRef.update({ expiresAt: dayjs().subtract(1, 'h').toDate() }); await updateExpiredStamp(); stamp = await stampDocRef.get(); @@ -73,7 +73,7 @@ describe('Stamp tangle test', () => { .collection(COL.TRANSACTION) .where('member', '==', helper.address.bech32) .where('type', '==', TransactionType.CREDIT) - .where('payload.type', '==', TransactionPayloadType.INVALID_PAYMENT) + .where('payload_type', '==', TransactionPayloadType.INVALID_PAYMENT) .get(); return creditSnap.length === 1; }); diff --git a/packages/functions/test-tangle/stamp-tangle/stamp-tangle_4.spec.ts b/packages/functions/test-tangle/stamp-tangle/stamp-tangle_4.spec.ts index 99e630552f..106021106b 100644 --- a/packages/functions/test-tangle/stamp-tangle/stamp-tangle_4.spec.ts +++ b/packages/functions/test-tangle/stamp-tangle/stamp-tangle_4.spec.ts @@ -1,5 +1,5 @@ import { build5Db } from '@build-5/database'; -import { COL, Transaction, TransactionType } from '@build-5/interfaces'; +import { COL, TransactionType } from '@build-5/interfaces'; import { MnemonicService } from '../../src/services/wallet/mnemonic'; import { wait } from '../../test/controls/common'; import { Helper } from './Helper'; @@ -28,7 +28,7 @@ describe('Stamp tangle test', () => { const snap = await query.get(); return snap.length === 1; }); - const credit = (await query.get())[0]; + const credit = (await query.get())[0]; expect(credit.payload.response!.address).toBeDefined(); }); }); diff --git a/packages/functions/test-tangle/stamp-tangle/stamp-tangle_5.spec.ts b/packages/functions/test-tangle/stamp-tangle/stamp-tangle_5.spec.ts index 9c730ea01d..0a826a7a69 100644 --- a/packages/functions/test-tangle/stamp-tangle/stamp-tangle_5.spec.ts +++ b/packages/functions/test-tangle/stamp-tangle/stamp-tangle_5.spec.ts @@ -1,5 +1,5 @@ import { build5Db, build5Storage } from '@build-5/database'; -import { Bucket, COL, MIN_IOTA_AMOUNT, MediaStatus, Stamp } from '@build-5/interfaces'; +import { Bucket, COL, MIN_IOTA_AMOUNT, MediaStatus } from '@build-5/interfaces'; import { uploadMediaToWeb3 } from '../../src/cron/media.cron'; import { MnemonicService } from '../../src/services/wallet/mnemonic'; import { EMPTY_ALIAS_ID } from '../../src/utils/token-minting-utils/alias.utils'; @@ -29,23 +29,23 @@ describe('Stamp tangle test', () => { const query = build5Db().collection(COL.STAMP).where('createdBy', '==', helper.address.bech32); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1 && snap[0].funded; }); - const stamp = (await query.get())[0]; + const stamp = (await query.get())[0]; expect(stamp?.mediaStatus).toBe(MediaStatus.PENDING_UPLOAD); expect(stamp?.ipfsMedia).toBeDefined(); await uploadMediaToWeb3(); await wait(async () => { - const stamp = (await query.get())[0]; + const stamp = (await query.get())[0]; return stamp?.mediaStatus === MediaStatus.UPLOADED; }); - const uploadedMediaStamp = (await query.get())[0]; + const uploadedMediaStamp = (await query.get())[0]; expect(uploadedMediaStamp?.ipfsMedia).toBe(stamp?.ipfsMedia); await wait(async () => { - const stamp = (await query.get())[0]; + const stamp = (await query.get())[0]; return stamp?.aliasId !== EMPTY_ALIAS_ID && stamp?.nftId !== undefined; }); }); diff --git a/packages/functions/test-tangle/stamp-tangle/stamp-tangle_6.spec.ts b/packages/functions/test-tangle/stamp-tangle/stamp-tangle_6.spec.ts index 1f43f59a3e..0397629950 100644 --- a/packages/functions/test-tangle/stamp-tangle/stamp-tangle_6.spec.ts +++ b/packages/functions/test-tangle/stamp-tangle/stamp-tangle_6.spec.ts @@ -4,8 +4,6 @@ import { KEY_NAME_TANGLE, MIN_IOTA_AMOUNT, MediaStatus, - Stamp, - Transaction, TransactionType, } from '@build-5/interfaces'; import { NftOutput } from '@iota/sdk'; @@ -36,10 +34,10 @@ describe('Stamp tangle test', () => { const query = build5Db().collection(COL.STAMP).where('createdBy', '==', helper.address.bech32); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1 && snap[0].funded; }); - let stamp = (await query.get())[0]; + let stamp = (await query.get())[0]; expect(stamp?.mediaStatus).toBe(MediaStatus.PENDING_UPLOAD); expect(stamp?.ipfsMedia).toBeDefined(); const ipfsMedia = stamp.ipfsMedia; @@ -47,17 +45,17 @@ describe('Stamp tangle test', () => { await uploadMediaToWeb3(); await wait(async () => { - stamp = (await query.get())[0]; + stamp = (await query.get())[0]; return stamp?.mediaStatus === MediaStatus.UPLOADED; }); expect(stamp?.ipfsMedia).toBe(ipfsMedia); await wait(async () => { - stamp = (await query.get())[0]; + stamp = (await query.get())[0]; return stamp?.aliasId !== EMPTY_ALIAS_ID && stamp?.nftId !== undefined; }); - stamp = (await query.get())[0]; + stamp = (await query.get())[0]; const nftOutputId = await helper.wallet.client.nftOutputId(stamp?.nftId!); const nftOutput = (await helper.wallet.client.getOutput(nftOutputId)).output as NftOutput; const metadata = getNftMetadata(nftOutput); @@ -68,8 +66,8 @@ describe('Stamp tangle test', () => { const billPayment = await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.BILL_PAYMENT) - .where('payload.stamp', '==', stamp?.uid) - .get(); + .where('payload_stamp', '==', stamp?.uid) + .get(); expect(billPayment.length).toBe(1); }); }); diff --git a/packages/functions/test-tangle/swap/Helper.ts b/packages/functions/test-tangle/swap/Helper.ts index a195c91dbf..a887c5c166 100644 --- a/packages/functions/test-tangle/swap/Helper.ts +++ b/packages/functions/test-tangle/swap/Helper.ts @@ -17,26 +17,18 @@ import { TransactionPayloadType, TransactionType, UnsoldMintingOptions, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; import { set } from 'lodash'; -import { mintCollection } from '../../src/runtime/firebase/collection'; -import { createNft, openBid, orderNft, setForSaleNft } from '../../src/runtime/firebase/nft'; import { Wallet } from '../../src/services/wallet/wallet'; import { AddressDetails } from '../../src/services/wallet/wallet.service'; import * as wallet from '../../src/utils/wallet.utils'; -import { - createMember as createMemberTest, - createSpace, - mockWalletReturnValue, - submitMilestoneFunc, - wait, -} from '../../test/controls/common'; -import { MEDIA, getWallet, testEnv } from '../../test/set-up'; +import { submitMilestoneFunc, wait } from '../../test/controls/common'; +import { MEDIA, getWallet, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; export class Helper { - public spy: any = {} as any; public network = Network.RMS; public guardian: string = {} as any; public member: string = {} as any; @@ -45,14 +37,13 @@ export class Helper { public space: Space = {} as any; public beforeAll = async () => { - this.spy = jest.spyOn(wallet, 'decodeAuth'); this.wallet = await getWallet(this.network); }; public beforeEach = async () => { - this.guardian = await createMemberTest(this.spy); - this.space = await createSpace(this.spy, this.guardian); - this.member = await createMemberTest(this.spy); + this.guardian = await testEnv.createMember(); + this.space = await testEnv.createSpace(this.guardian); + this.member = await testEnv.createMember(); }; public createDummyNft = (collection: string, description = 'babba') => ({ @@ -106,14 +97,14 @@ export class Helper { if (unsoldMintingOptions === UnsoldMintingOptions.SET_NEW_PRICE) { set(request, 'price', price); } - mockWalletReturnValue(this.spy, this.guardian!, request); - const collectionMintOrder = await testEnv.wrap(mintCollection)({}); + mockWalletReturnValue(this.guardian!, request); + const collectionMintOrder = await testEnv.wrap(WEN_FUNC.mintCollection); await requestFundsFromFaucet( this.network!, collectionMintOrder.payload.targetAddress, collectionMintOrder.payload.amount, ); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${this.collection}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, this.collection); await wait(async () => { const data = await collectionDocRef.get(); return data.status === CollectionStatus.MINTED; @@ -130,7 +121,7 @@ export class Helper { await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.MINT_COLLECTION) - .where('payload.type', '==', TransactionPayloadType.SEND_ALIAS_TO_GUARDIAN) + .where('payload_type', '==', TransactionPayloadType.SEND_ALIAS_TO_GUARDIAN) .where('member', '==', this.guardian) .get() ).map((d) => d); @@ -144,34 +135,32 @@ export class Helper { delete nft.uid; delete nft.status; delete nft.placeholderNft; - mockWalletReturnValue(this.spy, this.guardian!, nft); - nft = await testEnv.wrap(createNft)({}); + mockWalletReturnValue(this.guardian!, nft); + nft = await testEnv.wrap(WEN_FUNC.createNft); if (buyAndAuctionId) { await build5Db() - .doc(`${COL.NFT}/${nft.uid}`) + .doc(COL.NFT, nft.uid) .update({ availableFrom: dayjs().subtract(1, 'h').toDate() }); - mockWalletReturnValue(this.spy, this.guardian!, { + mockWalletReturnValue(this.guardian!, { collection: this.collection, nft: nft.uid, }); - const order = await testEnv.wrap(orderNft)({}); + const order = await testEnv.wrap(WEN_FUNC.orderNft); await submitMilestoneFunc(order); - mockWalletReturnValue(this.spy, this.guardian!, this.dummyAuctionData(nft.uid)); - await testEnv.wrap(setForSaleNft)({}); - await wait( - async () => (await build5Db().doc(`${COL.NFT}/${nft.uid}`).get())?.available === 3, - ); + mockWalletReturnValue(this.guardian!, this.dummyAuctionData(nft.uid)); + await testEnv.wrap(WEN_FUNC.setForSaleNft); + await wait(async () => (await build5Db().doc(COL.NFT, nft.uid).get())?.available === 3); if (shouldBid) { - mockWalletReturnValue(this.spy, this.member!, { nft: nft.uid }); - const bidOrder = await testEnv.wrap(openBid)({}); + mockWalletReturnValue(this.member!, { nft: nft.uid }); + const bidOrder = await testEnv.wrap(WEN_FUNC.openBid); await submitMilestoneFunc(bidOrder, 2 * MIN_IOTA_AMOUNT); } } - return await build5Db().doc(`${COL.NFT}/${nft.uid}`).get(); + return await build5Db().doc(COL.NFT, nft.uid).get(); }; public dummyAuctionData = (uid: string) => ({ @@ -201,7 +190,7 @@ export class Helper { nftId, }, }; - await build5Db().doc(`${COL.TRANSACTION}/${order.uid}`).create(order); + await build5Db().doc(COL.TRANSACTION, order.uid).create(order); return order.uid; }; } diff --git a/packages/functions/test-tangle/swap/swap_1.spec.ts b/packages/functions/test-tangle/swap/swap_1.spec.ts index 04d921b1b3..f8889732de 100644 --- a/packages/functions/test-tangle/swap/swap_1.spec.ts +++ b/packages/functions/test-tangle/swap/swap_1.spec.ts @@ -6,12 +6,12 @@ import { SwapStatus, Transaction, TransactionType, + WEN_FUNC, WenError, } from '@build-5/interfaces'; -import { createSwap, setSwapFunded } from '../../src/runtime/firebase/swap'; import { MnemonicService } from '../../src/services/wallet/mnemonic'; -import { expectThrow, mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { expectThrow, wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitLedgerInclusionState, requestFundsFromFaucet, @@ -37,18 +37,18 @@ describe('Swap control test', () => { }); it('Should create, offer minted tokens, request base token', async () => { - mockWalletReturnValue(h.spy, h.guardian, { + mockWalletReturnValue(h.guardian, { network: h.network, baseTokenAmount: MIN_IOTA_AMOUNT, recipient: h.member, }); - const swapOrder: Transaction = await testEnv.wrap(createSwap)({}); + const swapOrder = await testEnv.wrap(WEN_FUNC.createSwap); - const swapDocRef = build5Db().doc(`${COL.SWAP}/${swapOrder.payload.swap}`); + const swapDocRef = build5Db().doc(COL.SWAP, swapOrder.payload.swap!); let swap = await swapDocRef.get(); - mockWalletReturnValue(h.spy, h.guardian, { uid: swap.uid }); - await expectThrow(testEnv.wrap(setSwapFunded)({}), WenError.swap_must_be_funded.key); + mockWalletReturnValue(h.guardian, { uid: swap.uid }); + await expectThrow(testEnv.wrap(WEN_FUNC.setSwapFunded), WenError.swap_must_be_funded.key); const source = await h.wallet.getNewIotaAddressDetails(); await requestFundsFromFaucet(h.network, source.bech32, 10 * MIN_IOTA_AMOUNT); @@ -77,10 +77,10 @@ describe('Swap control test', () => { ]); expect(swap.bidOutputs!.map((nt) => nt.nativeTokens![0].amount!)).toEqual(['0x5', '0x5']); - mockWalletReturnValue(h.spy, h.member, { uid: swap.uid }); - await expectThrow(testEnv.wrap(setSwapFunded)({}), WenError.not_swap_owner.key); - mockWalletReturnValue(h.spy, h.guardian, { uid: swap.uid }); - await testEnv.wrap(setSwapFunded)({}); + mockWalletReturnValue(h.member, { uid: swap.uid }); + await expectThrow(testEnv.wrap(WEN_FUNC.setSwapFunded), WenError.not_swap_owner.key); + mockWalletReturnValue(h.guardian, { uid: swap.uid }); + await testEnv.wrap(WEN_FUNC.setSwapFunded); swap = await swapDocRef.get(); expect(swap.status).toBe(SwapStatus.FUNDED); @@ -93,10 +93,10 @@ describe('Swap control test', () => { let query = build5Db() .collection(COL.TRANSACTION) - .where('payload.swap', '==', swap.uid) + .where('payload_swap', '==', swap.uid) .where('type', '==', TransactionType.BILL_PAYMENT); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return ( snap.length === 3 && snap.reduce((acc, act) => (acc && act.payload.walletReference?.confirmed) || false, true) @@ -107,7 +107,7 @@ describe('Swap control test', () => { .collection(COL.TRANSACTION) .where('member', '==', h.guardian) .where('type', '==', TransactionType.BILL_PAYMENT); - let billPayments = await query.get(); + let billPayments = await query.get(); expect(billPayments.length).toBe(1); expect(billPayments[0].payload.amount).toBe(MIN_IOTA_AMOUNT); expect(billPayments[0].payload.nativeTokens).toEqual([]); @@ -117,7 +117,7 @@ describe('Swap control test', () => { .collection(COL.TRANSACTION) .where('member', '==', h.member) .where('type', '==', TransactionType.BILL_PAYMENT); - billPayments = await query.get(); + billPayments = await query.get(); expect(billPayments.length).toBe(2); expect(billPayments.map((b) => b.payload.nativeTokens![0].id).sort()).toEqual( [MINTED_TOKEN_ID_1, MINTED_TOKEN_ID_2].sort(), diff --git a/packages/functions/test-tangle/swap/swap_2.spec.ts b/packages/functions/test-tangle/swap/swap_2.spec.ts index 466118c893..b299517984 100644 --- a/packages/functions/test-tangle/swap/swap_2.spec.ts +++ b/packages/functions/test-tangle/swap/swap_2.spec.ts @@ -6,11 +6,11 @@ import { SwapStatus, Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; -import { createSwap, setSwapFunded } from '../../src/runtime/firebase/swap'; import { MnemonicService } from '../../src/services/wallet/mnemonic'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitLedgerInclusionState, requestFundsFromFaucet, @@ -36,7 +36,7 @@ describe('Swap control test', () => { }); it('Should create, offer base token, request minted tokens, ', async () => { - mockWalletReturnValue(h.spy, h.guardian, { + mockWalletReturnValue(h.guardian, { network: h.network, nativeTokens: [ { id: MINTED_TOKEN_ID_1, amount: 5 }, @@ -44,9 +44,9 @@ describe('Swap control test', () => { ], recipient: h.member, }); - const swapOrder: Transaction = await testEnv.wrap(createSwap)({}); + const swapOrder = await testEnv.wrap(WEN_FUNC.createSwap); - const swapDocRef = build5Db().doc(`${COL.SWAP}/${swapOrder.payload.swap}`); + const swapDocRef = build5Db().doc(COL.SWAP, swapOrder.payload.swap!); let swap = await swapDocRef.get(); await requestFundsFromFaucet(h.network, swapOrder.payload.targetAddress!, MIN_IOTA_AMOUNT); @@ -55,8 +55,8 @@ describe('Swap control test', () => { return swap.bidOutputs?.length === 1; }); - mockWalletReturnValue(h.spy, h.guardian, { uid: swap.uid }); - await testEnv.wrap(setSwapFunded)({}); + mockWalletReturnValue(h.guardian, { uid: swap.uid }); + await testEnv.wrap(WEN_FUNC.setSwapFunded); swap = await swapDocRef.get(); expect(swap.status).toBe(SwapStatus.FUNDED); @@ -94,10 +94,10 @@ describe('Swap control test', () => { let query = build5Db() .collection(COL.TRANSACTION) - .where('payload.swap', '==', swap.uid) + .where('payload_swap', '==', swap.uid) .where('type', '==', TransactionType.BILL_PAYMENT); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return ( snap.length === 3 && snap.reduce((acc, act) => (acc && act.payload.walletReference?.confirmed) || false, true) @@ -108,7 +108,7 @@ describe('Swap control test', () => { .collection(COL.TRANSACTION) .where('member', '==', h.member) .where('type', '==', TransactionType.BILL_PAYMENT); - let billPayments = await query.get(); + let billPayments = await query.get(); expect(billPayments.length).toBe(1); expect(billPayments[0].payload.amount).toBe(MIN_IOTA_AMOUNT); expect(billPayments[0].payload.nativeTokens).toEqual([]); @@ -118,7 +118,7 @@ describe('Swap control test', () => { .collection(COL.TRANSACTION) .where('member', '==', h.guardian) .where('type', '==', TransactionType.BILL_PAYMENT); - billPayments = await query.get(); + billPayments = await query.get(); expect(billPayments.length).toBe(2); const nativeTokens = billPayments.map((b) => b.payload.nativeTokens![0].id).sort(); expect(nativeTokens).toEqual([MINTED_TOKEN_ID_1, MINTED_TOKEN_ID_2].sort()); diff --git a/packages/functions/test-tangle/swap/swap_3_a.spec.ts b/packages/functions/test-tangle/swap/swap_3_a.spec.ts index 3f0624b816..5eff1df993 100644 --- a/packages/functions/test-tangle/swap/swap_3_a.spec.ts +++ b/packages/functions/test-tangle/swap/swap_3_a.spec.ts @@ -1,6 +1,7 @@ import { build5Db } from '@build-5/database'; import { COL, + Collection, MIN_IOTA_AMOUNT, Member, Nft, @@ -8,14 +9,12 @@ import { SwapStatus, Transaction, TransactionType, + WEN_FUNC, WenError, } from '@build-5/interfaces'; -import { createCollection } from '../../src/runtime/firebase/collection'; -import { withdrawNft } from '../../src/runtime/firebase/nft'; -import { createSwap, rejectSwap, setSwapFunded } from '../../src/runtime/firebase/swap'; import { getAddress } from '../../src/utils/address.utils'; -import { expectThrow, mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { expectThrow, wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet, requestMintedTokenFromFaucet } from '../faucet'; import { Helper, MINTED_TOKEN_ID_1, VAULT_MNEMONIC_1 } from './Helper'; @@ -30,30 +29,30 @@ describe('Swap control test', () => { beforeEach(async () => { await h.beforeEach(); - mockWalletReturnValue(h.spy, h.guardian, h.createDummyCollection(h.space.uid, h.space.uid)); - h.collection = (await testEnv.wrap(createCollection)({})).uid; + mockWalletReturnValue(h.guardian, h.createDummyCollection(h.space.uid, h.space.uid)); + h.collection = (await testEnv.wrap(WEN_FUNC.createCollection)).uid; nfts = [(await h.createAndOrderNft(true)).uid, (await h.createAndOrderNft(true)).uid]; await h.mintCollection(); - mockWalletReturnValue(h.spy, h.guardian!, { nft: nfts[0] }); - await testEnv.wrap(withdrawNft)({}); + mockWalletReturnValue(h.guardian!, { nft: nfts[0] }); + await testEnv.wrap(WEN_FUNC.withdrawNft); - mockWalletReturnValue(h.spy, h.guardian!, { nft: nfts[1] }); - await testEnv.wrap(withdrawNft)({}); + mockWalletReturnValue(h.guardian!, { nft: nfts[1] }); + await testEnv.wrap(WEN_FUNC.withdrawNft); }); it('Should create, offer base token, request nft', async () => { - mockWalletReturnValue(h.spy, h.member, { + mockWalletReturnValue(h.member, { network: h.network, nativeTokens: [{ id: MINTED_TOKEN_ID_1, amount: 5 }], nfts, recipient: h.guardian, }); - const swapOrder: Transaction = await testEnv.wrap(createSwap)({}); + const swapOrder = await testEnv.wrap(WEN_FUNC.createSwap); - const swapDocRef = build5Db().doc(`${COL.SWAP}/${swapOrder.payload.swap}`); + const swapDocRef = build5Db().doc(COL.SWAP, swapOrder.payload.swap!); let swap = await swapDocRef.get(); await requestFundsFromFaucet(h.network, swapOrder.payload.targetAddress!, MIN_IOTA_AMOUNT); @@ -61,12 +60,12 @@ describe('Swap control test', () => { swap = await swapDocRef.get(); return swap.bidOutputs?.length === 1; }); - mockWalletReturnValue(h.spy, h.member, { uid: swap.uid }); - await testEnv.wrap(setSwapFunded)({}); + mockWalletReturnValue(h.member, { uid: swap.uid }); + await testEnv.wrap(WEN_FUNC.setSwapFunded); swap = await swapDocRef.get(); expect(swap.status).toBe(SwapStatus.FUNDED); - const guardianDocRef = build5Db().doc(`${COL.MEMBER}/${h.guardian}`); + const guardianDocRef = build5Db().doc(COL.MEMBER, h.guardian); const guardianData = await guardianDocRef.get(); const sourceAddress = await h.wallet.getAddressDetails(getAddress(guardianData, h.network)); @@ -75,7 +74,7 @@ describe('Swap control test', () => { return result.items.length === 2; }); for (const nftUid of nfts) { - const docRef = build5Db().doc(`${COL.NFT}/${nftUid}`); + const docRef = build5Db().doc(COL.NFT, nftUid); const nft = await docRef.get(); await h.sendNftToAddress(sourceAddress, swap.address, nft.mintingData?.nftId!); } @@ -96,9 +95,9 @@ describe('Swap control test', () => { .collection(COL.TRANSACTION) .where('member', '==', h.member) .where('type', '==', TransactionType.BILL_PAYMENT) - .where('payload.swap', '==', swap.uid); + .where('payload_swap', '==', swap.uid); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1 && (snap[0].payload.walletReference?.confirmed || false); }); @@ -106,9 +105,9 @@ describe('Swap control test', () => { .collection(COL.TRANSACTION) .where('member', '==', h.member) .where('type', '==', TransactionType.WITHDRAW_NFT) - .where('payload.swap', '==', swap.uid); + .where('payload_swap', '==', swap.uid); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return ( snap.length === 2 && (snap[0].payload.walletReference?.confirmed || false) && @@ -116,7 +115,7 @@ describe('Swap control test', () => { ); }); - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${h.member}`); + const memberDocRef = build5Db().doc(COL.MEMBER, h.member); const member = await memberDocRef.get(); const response = await h.wallet.client.nftOutputIds([ { address: getAddress(member, h.network) }, @@ -127,13 +126,13 @@ describe('Swap control test', () => { .collection(COL.TRANSACTION) .where('member', '==', h.guardian) .where('type', '==', TransactionType.BILL_PAYMENT) - .where('payload.swap', '==', swap.uid); + .where('payload_swap', '==', swap.uid); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1 && (snap[0].payload.walletReference?.confirmed || false); }); - mockWalletReturnValue(h.spy, h.member, { uid: swap.uid }); - await expectThrow(testEnv.wrap(rejectSwap)({}), WenError.swap_already_fulfilled.key); + mockWalletReturnValue(h.member, { uid: swap.uid }); + await expectThrow(testEnv.wrap(WEN_FUNC.rejectSwap), WenError.swap_already_fulfilled.key); }); }); diff --git a/packages/functions/test-tangle/swap/swap_3_b.spec.ts b/packages/functions/test-tangle/swap/swap_3_b.spec.ts index 2af09e2879..7c4bfa4945 100644 --- a/packages/functions/test-tangle/swap/swap_3_b.spec.ts +++ b/packages/functions/test-tangle/swap/swap_3_b.spec.ts @@ -1,6 +1,7 @@ import { build5Db } from '@build-5/database'; import { COL, + Collection, MIN_IOTA_AMOUNT, Member, Nft, @@ -8,14 +9,12 @@ import { SwapStatus, Transaction, TransactionType, + WEN_FUNC, WenError, } from '@build-5/interfaces'; -import { createCollection } from '../../src/runtime/firebase/collection'; -import { withdrawNft } from '../../src/runtime/firebase/nft'; -import { createSwap, rejectSwap, setSwapFunded } from '../../src/runtime/firebase/swap'; import { getAddress } from '../../src/utils/address.utils'; -import { expectThrow, mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { expectThrow, wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet, requestMintedTokenFromFaucet } from '../faucet'; import { Helper, MINTED_TOKEN_ID_1, VAULT_MNEMONIC_1 } from './Helper'; @@ -30,30 +29,30 @@ describe('Swap control test', () => { beforeEach(async () => { await h.beforeEach(); - mockWalletReturnValue(h.spy, h.guardian, h.createDummyCollection(h.space.uid, h.space.uid)); - h.collection = (await testEnv.wrap(createCollection)({})).uid; + mockWalletReturnValue(h.guardian, h.createDummyCollection(h.space.uid, h.space.uid)); + h.collection = (await testEnv.wrap(WEN_FUNC.createCollection)).uid; nfts = [(await h.createAndOrderNft(true)).uid, (await h.createAndOrderNft(true)).uid]; await h.mintCollection(); - mockWalletReturnValue(h.spy, h.guardian!, { nft: nfts[0] }); - await testEnv.wrap(withdrawNft)({}); + mockWalletReturnValue(h.guardian!, { nft: nfts[0] }); + await testEnv.wrap(WEN_FUNC.withdrawNft); - mockWalletReturnValue(h.spy, h.guardian!, { nft: nfts[1] }); - await testEnv.wrap(withdrawNft)({}); + mockWalletReturnValue(h.guardian!, { nft: nfts[1] }); + await testEnv.wrap(WEN_FUNC.withdrawNft); }); it('Should create, offer base token, request nft', async () => { - mockWalletReturnValue(h.spy, h.member, { + mockWalletReturnValue(h.member, { network: h.network, nativeTokens: [{ id: MINTED_TOKEN_ID_1, amount: 5 }], nfts, recipient: h.guardian, }); - const swapOrder: Transaction = await testEnv.wrap(createSwap)({}); + const swapOrder = await testEnv.wrap(WEN_FUNC.createSwap); - const swapDocRef = build5Db().doc(`${COL.SWAP}/${swapOrder.payload.swap}`); + const swapDocRef = build5Db().doc(COL.SWAP, swapOrder.payload.swap!); let swap = await swapDocRef.get(); await requestFundsFromFaucet(h.network, swapOrder.payload.targetAddress!, MIN_IOTA_AMOUNT); @@ -62,7 +61,7 @@ describe('Swap control test', () => { return swap.bidOutputs?.length === 1; }); - const guardianDocRef = build5Db().doc(`${COL.MEMBER}/${h.guardian}`); + const guardianDocRef = build5Db().doc(COL.MEMBER, h.guardian); const guardianData = await guardianDocRef.get(); const sourceAddress = await h.wallet.getAddressDetails(getAddress(guardianData, h.network)); await wait(async () => { @@ -70,7 +69,7 @@ describe('Swap control test', () => { return result.items.length === 2; }); for (const nftUid of nfts) { - const docRef = build5Db().doc(`${COL.NFT}/${nftUid}`); + const docRef = build5Db().doc(COL.NFT, nftUid); const nft = await docRef.get(); await h.sendNftToAddress(sourceAddress, swap.address, nft.mintingData?.nftId!); } @@ -87,8 +86,8 @@ describe('Swap control test', () => { return swap.askOutputs?.length === 3 && swap.bidOutputs?.length === 1; }); - mockWalletReturnValue(h.spy, h.member, { uid: swap.uid }); - await testEnv.wrap(setSwapFunded)({}); + mockWalletReturnValue(h.member, { uid: swap.uid }); + await testEnv.wrap(WEN_FUNC.setSwapFunded); swap = await swapDocRef.get(); expect(swap.status).toBe(SwapStatus.FULFILLED); @@ -96,9 +95,9 @@ describe('Swap control test', () => { .collection(COL.TRANSACTION) .where('member', '==', h.member) .where('type', '==', TransactionType.BILL_PAYMENT) - .where('payload.swap', '==', swap.uid); + .where('payload_swap', '==', swap.uid); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1 && (snap[0].payload.walletReference?.confirmed || false); }); @@ -106,9 +105,9 @@ describe('Swap control test', () => { .collection(COL.TRANSACTION) .where('member', '==', h.member) .where('type', '==', TransactionType.WITHDRAW_NFT) - .where('payload.swap', '==', swap.uid); + .where('payload_swap', '==', swap.uid); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return ( snap.length === 2 && (snap[0].payload.walletReference?.confirmed || false) && @@ -116,7 +115,7 @@ describe('Swap control test', () => { ); }); - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${h.member}`); + const memberDocRef = build5Db().doc(COL.MEMBER, h.member); const member = await memberDocRef.get(); const response = await h.wallet.client.nftOutputIds([ { address: getAddress(member, h.network) }, @@ -127,13 +126,13 @@ describe('Swap control test', () => { .collection(COL.TRANSACTION) .where('member', '==', h.guardian) .where('type', '==', TransactionType.BILL_PAYMENT) - .where('payload.swap', '==', swap.uid); + .where('payload_swap', '==', swap.uid); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1 && (snap[0].payload.walletReference?.confirmed || false); }); - mockWalletReturnValue(h.spy, h.member, { uid: swap.uid }); - await expectThrow(testEnv.wrap(rejectSwap)({}), WenError.swap_already_fulfilled.key); + mockWalletReturnValue(h.member, { uid: swap.uid }); + await expectThrow(testEnv.wrap(WEN_FUNC.rejectSwap), WenError.swap_already_fulfilled.key); }); }); diff --git a/packages/functions/test-tangle/swap/swap_4.spec.ts b/packages/functions/test-tangle/swap/swap_4.spec.ts index 4fc0888a61..8f71d39317 100644 --- a/packages/functions/test-tangle/swap/swap_4.spec.ts +++ b/packages/functions/test-tangle/swap/swap_4.spec.ts @@ -2,10 +2,8 @@ import { build5Db } from '@build-5/database'; import { COL, MIN_IOTA_AMOUNT, - Swap, SwapStatus, TangleRequestType, - Transaction, TransactionType, } from '@build-5/interfaces'; import { wait } from '../../test/controls/common'; @@ -44,12 +42,12 @@ describe('Swap control test', () => { customMetadata: { request }, }); - let query = build5Db().collection(COL.SWAP).where('createdBy', '==', address.bech32); + const createdByQuery = build5Db().collection(COL.SWAP).where('createdBy', '==', address.bech32); await wait(async () => { - const snap = await query.get(); + const snap = await createdByQuery.get(); return snap.length === 1; }); - const swap = (await query.get())[0]; + const swap = (await createdByQuery.get())[0]; expect(swap.bidOutputs?.length).toBe(1); expect(swap.bidOutputs![0].amount).toBe(MIN_IOTA_AMOUNT); expect(swap.status).toBe(SwapStatus.FUNDED); @@ -57,11 +55,11 @@ describe('Swap control test', () => { [MINTED_TOKEN_ID_1, MINTED_TOKEN_ID_2].sort(), ); - query = build5Db() + const query = build5Db() .collection(COL.TRANSACTION) .where('member', '==', address.bech32) .where('type', '==', TransactionType.CREDIT_TANGLE_REQUEST); - const snap = await query.get(); + const snap = await query.get(); expect(snap.length).toBe(0); }); }); diff --git a/packages/functions/test-tangle/swap/swap_5.spec.ts b/packages/functions/test-tangle/swap/swap_5.spec.ts index 0900787269..b3f2d433b8 100644 --- a/packages/functions/test-tangle/swap/swap_5.spec.ts +++ b/packages/functions/test-tangle/swap/swap_5.spec.ts @@ -2,10 +2,8 @@ import { build5Db } from '@build-5/database'; import { COL, MIN_IOTA_AMOUNT, - Swap, SwapStatus, TangleRequestType, - Transaction, TransactionType, } from '@build-5/interfaces'; import { MnemonicService } from '../../src/services/wallet/mnemonic'; @@ -51,35 +49,35 @@ describe('Swap control test', () => { .where('type', '==', TransactionType.CREDIT_TANGLE_REQUEST) .orderBy('createdOn'); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return snap.length === 1 && snap[0].payload.walletReference?.confirmed; }); - let credit = (await creditQuery.get())[0]; + let credit = (await creditQuery.get())[0]; expect(credit.payload.response?.address).toBeDefined(); expect(credit.payload.response?.swap).toBeDefined(); const swapAddress = credit.payload.response?.address as string; - const swapUid = credit.payload.response?.swap!; + const swapUid = credit.payload.response?.swap! as string; await h.wallet.send(address, tangleOrder.payload.targetAddress!, MIN_IOTA_AMOUNT, { customMetadata: { request: { requestType: TangleRequestType.SET_SWAP_FUNDED, uid: swapUid } }, }); await MnemonicService.store(address.bech32, address.mnemonic, h.network); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return ( snap.length === 2 && snap.reduce((acc, act) => (acc && act.payload.walletReference?.confirmed) || false, true) ); }); - credit = (await creditQuery.get())[1]; + credit = (await creditQuery.get())[1]; expect(credit.payload.response?.code).toBe(2152); await h.wallet.send(address, swapAddress, MIN_IOTA_AMOUNT, {}); await MnemonicService.store(address.bech32, address.mnemonic, h.network); - const swapDocRef = build5Db().doc(`${COL.SWAP}/${swapUid}`); + const swapDocRef = build5Db().doc(COL.SWAP, swapUid); await wait(async () => { - const swap = await swapDocRef.get(); + const swap = await swapDocRef.get(); return swap?.bidOutputs?.length === 1; }); @@ -89,14 +87,14 @@ describe('Swap control test', () => { await MnemonicService.store(address.bech32, address.mnemonic, h.network); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return ( snap.length === 3 && snap.reduce((acc, act) => (acc && act.payload.walletReference?.confirmed) || false, true) ); }); - const swap = await swapDocRef.get(); + const swap = await swapDocRef.get(); expect(swap?.bidOutputs?.length).toBe(1); expect(swap?.status).toBe(SwapStatus.FUNDED); }); diff --git a/packages/functions/test-tangle/swap/swap_6.spec.ts b/packages/functions/test-tangle/swap/swap_6.spec.ts index f026495925..016b6b272b 100644 --- a/packages/functions/test-tangle/swap/swap_6.spec.ts +++ b/packages/functions/test-tangle/swap/swap_6.spec.ts @@ -1,6 +1,7 @@ import { build5Db } from '@build-5/database'; import { COL, + Collection, MIN_IOTA_AMOUNT, Member, Nft, @@ -8,14 +9,12 @@ import { SwapStatus, Transaction, TransactionType, + WEN_FUNC, WenError, } from '@build-5/interfaces'; -import { createCollection } from '../../src/runtime/firebase/collection'; -import { withdrawNft } from '../../src/runtime/firebase/nft'; -import { createSwap, rejectSwap } from '../../src/runtime/firebase/swap'; import { getAddress } from '../../src/utils/address.utils'; -import { createMember, expectThrow, mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { expectThrow, wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet, requestMintedTokenFromFaucet } from '../faucet'; import { Helper, MINTED_TOKEN_ID_1, VAULT_MNEMONIC_1 } from './Helper'; @@ -30,30 +29,30 @@ describe('Swap control test', () => { beforeEach(async () => { await h.beforeEach(); - mockWalletReturnValue(h.spy, h.guardian, h.createDummyCollection(h.space.uid, h.space.uid)); - h.collection = (await testEnv.wrap(createCollection)({})).uid; + mockWalletReturnValue(h.guardian, h.createDummyCollection(h.space.uid, h.space.uid)); + h.collection = (await testEnv.wrap(WEN_FUNC.createCollection)).uid; nfts = [(await h.createAndOrderNft(true)).uid, (await h.createAndOrderNft(true)).uid]; await h.mintCollection(); - mockWalletReturnValue(h.spy, h.guardian!, { nft: nfts[0] }); - await testEnv.wrap(withdrawNft)({}); + mockWalletReturnValue(h.guardian!, { nft: nfts[0] }); + await testEnv.wrap(WEN_FUNC.withdrawNft); - mockWalletReturnValue(h.spy, h.guardian!, { nft: nfts[1] }); - await testEnv.wrap(withdrawNft)({}); + mockWalletReturnValue(h.guardian!, { nft: nfts[1] }); + await testEnv.wrap(WEN_FUNC.withdrawNft); }); it('Should create, offer base token, request nft, reject', async () => { - mockWalletReturnValue(h.spy, h.member, { + mockWalletReturnValue(h.member, { network: h.network, nativeTokens: [{ id: MINTED_TOKEN_ID_1, amount: 5 }], nfts, recipient: h.guardian, }); - const swapOrder: Transaction = await testEnv.wrap(createSwap)({}); + const swapOrder = await testEnv.wrap(WEN_FUNC.createSwap); - const swapDocRef = build5Db().doc(`${COL.SWAP}/${swapOrder.payload.swap}`); + const swapDocRef = build5Db().doc(COL.SWAP, swapOrder.payload.swap!); let swap = await swapDocRef.get(); await requestFundsFromFaucet(h.network, swapOrder.payload.targetAddress!, MIN_IOTA_AMOUNT); @@ -62,7 +61,7 @@ describe('Swap control test', () => { return swap.bidOutputs?.length === 1; }); - const guardianDocRef = build5Db().doc(`${COL.MEMBER}/${h.guardian}`); + const guardianDocRef = build5Db().doc(COL.MEMBER, h.guardian); const guardianData = await guardianDocRef.get(); const guardianAddress = await h.wallet.getAddressDetails(getAddress(guardianData, h.network)); await wait(async () => { @@ -70,7 +69,7 @@ describe('Swap control test', () => { return result.items.length === 2; }); for (const nftUid of nfts) { - const docRef = build5Db().doc(`${COL.NFT}/${nftUid}`); + const docRef = build5Db().doc(COL.NFT, nftUid); const nft = await docRef.get(); await h.sendNftToAddress(guardianAddress, swap.address, nft.mintingData?.nftId!); } @@ -87,21 +86,21 @@ describe('Swap control test', () => { return swap.askOutputs?.length === 3 && swap.bidOutputs?.length === 1; }); - const member2 = await createMember(h.spy); - mockWalletReturnValue(h.spy, member2, { uid: swap.uid }); - await expectThrow(testEnv.wrap(rejectSwap)({}), WenError.not_swap_owner.key); + const member2 = await testEnv.createMember(); + mockWalletReturnValue(member2, { uid: swap.uid }); + await expectThrow(testEnv.wrap(WEN_FUNC.rejectSwap), WenError.not_swap_owner.key); - mockWalletReturnValue(h.spy, h.member, { uid: swap.uid }); - await testEnv.wrap(rejectSwap)({}); + mockWalletReturnValue(h.member, { uid: swap.uid }); + await testEnv.wrap(WEN_FUNC.rejectSwap); swap = await swapDocRef.get(); expect(swap.status).toBe(SwapStatus.REJECTED); let query = build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.CREDIT) - .where('payload.swap', '==', swap.uid); + .where('payload_swap', '==', swap.uid); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return ( snap.length === 2 && snap[0].payload.walletReference?.confirmed && @@ -112,16 +111,16 @@ describe('Swap control test', () => { query = build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.CREDIT_NFT) - .where('payload.swap', '==', swap.uid); + .where('payload_swap', '==', swap.uid); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return ( snap.length === 2 && snap[0].payload.walletReference?.confirmed && snap[1].payload.walletReference?.confirmed ); }); - const snap = await query.get(); + const snap = await query.get(); expect(snap[0].payload.targetAddress).toBe(guardianAddress.bech32); expect(snap[1].payload.targetAddress).toBe(guardianAddress.bech32); diff --git a/packages/functions/test-tangle/swap/swap_7.spec.ts b/packages/functions/test-tangle/swap/swap_7.spec.ts index 6288554065..8a11ccd0e3 100644 --- a/packages/functions/test-tangle/swap/swap_7.spec.ts +++ b/packages/functions/test-tangle/swap/swap_7.spec.ts @@ -1,6 +1,7 @@ import { build5Db } from '@build-5/database'; import { COL, + Collection, MIN_IOTA_AMOUNT, Member, Nft, @@ -9,13 +10,11 @@ import { TangleRequestType, Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; -import { createCollection } from '../../src/runtime/firebase/collection'; -import { withdrawNft } from '../../src/runtime/firebase/nft'; -import { createSwap } from '../../src/runtime/firebase/swap'; import { getAddress } from '../../src/utils/address.utils'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { getTangleOrder } from '../common'; import { requestFundsFromFaucet, requestMintedTokenFromFaucet } from '../faucet'; import { Helper, MINTED_TOKEN_ID_1, VAULT_MNEMONIC_1 } from './Helper'; @@ -31,30 +30,30 @@ describe('Swap control test', () => { beforeEach(async () => { await h.beforeEach(); - mockWalletReturnValue(h.spy, h.guardian, h.createDummyCollection(h.space.uid, h.space.uid)); - h.collection = (await testEnv.wrap(createCollection)({})).uid; + mockWalletReturnValue(h.guardian, h.createDummyCollection(h.space.uid, h.space.uid)); + h.collection = (await testEnv.wrap(WEN_FUNC.createCollection)).uid; nfts = [(await h.createAndOrderNft(true)).uid, (await h.createAndOrderNft(true)).uid]; await h.mintCollection(); - mockWalletReturnValue(h.spy, h.guardian!, { nft: nfts[0] }); - await testEnv.wrap(withdrawNft)({}); + mockWalletReturnValue(h.guardian!, { nft: nfts[0] }); + await testEnv.wrap(WEN_FUNC.withdrawNft); - mockWalletReturnValue(h.spy, h.guardian!, { nft: nfts[1] }); - await testEnv.wrap(withdrawNft)({}); + mockWalletReturnValue(h.guardian!, { nft: nfts[1] }); + await testEnv.wrap(WEN_FUNC.withdrawNft); }); it('Should create, offer base token, request nft, reject with OTR', async () => { - mockWalletReturnValue(h.spy, h.member, { + mockWalletReturnValue(h.member, { network: h.network, nativeTokens: [{ id: MINTED_TOKEN_ID_1, amount: 5 }], nfts, recipient: h.guardian, }); - const swapOrder: Transaction = await testEnv.wrap(createSwap)({}); + const swapOrder = await testEnv.wrap(WEN_FUNC.createSwap); - const swapDocRef = build5Db().doc(`${COL.SWAP}/${swapOrder.payload.swap}`); + const swapDocRef = build5Db().doc(COL.SWAP, swapOrder.payload.swap!); let swap = await swapDocRef.get(); await requestFundsFromFaucet(h.network, swapOrder.payload.targetAddress!, MIN_IOTA_AMOUNT); @@ -63,7 +62,7 @@ describe('Swap control test', () => { return swap.bidOutputs?.length === 1; }); - const guardianDocRef = build5Db().doc(`${COL.MEMBER}/${h.guardian}`); + const guardianDocRef = build5Db().doc(COL.MEMBER, h.guardian); const guardianData = await guardianDocRef.get(); const guardianAddress = await h.wallet.getAddressDetails(getAddress(guardianData, h.network)); await wait(async () => { @@ -72,7 +71,7 @@ describe('Swap control test', () => { }); for (const nftUid of nfts) { - const docRef = build5Db().doc(`${COL.NFT}/${nftUid}`); + const docRef = build5Db().doc(COL.NFT, nftUid); const nft = await docRef.get(); await h.sendNftToAddress(guardianAddress, swap.address, nft.mintingData?.nftId!); } @@ -89,7 +88,7 @@ describe('Swap control test', () => { return swap.askOutputs?.length === 3 && swap.bidOutputs?.length === 1; }); - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${h.member}`); + const memberDocRef = build5Db().doc(COL.MEMBER, h.member); const memberData = await memberDocRef.get(); const memberAddress = await h.wallet.getAddressDetails(getAddress(memberData, h.network)); await requestFundsFromFaucet(h.network, memberAddress.bech32, MIN_IOTA_AMOUNT); @@ -107,9 +106,9 @@ describe('Swap control test', () => { let query = build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.CREDIT) - .where('payload.swap', '==', swap.uid); + .where('payload_swap', '==', swap.uid); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return ( snap.length === 2 && snap[0].payload.walletReference?.confirmed && @@ -120,16 +119,16 @@ describe('Swap control test', () => { query = build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.CREDIT_NFT) - .where('payload.swap', '==', swap.uid); + .where('payload_swap', '==', swap.uid); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return ( snap.length === 2 && snap[0].payload.walletReference?.confirmed && snap[1].payload.walletReference?.confirmed ); }); - const snap = await query.get(); + const snap = await query.get(); expect(snap[0].payload.targetAddress).toBe(guardianAddress.bech32); expect(snap[1].payload.targetAddress).toBe(guardianAddress.bech32); diff --git a/packages/functions/test-tangle/swap/swap_8.spec.ts b/packages/functions/test-tangle/swap/swap_8.spec.ts index da2ec59762..91c56c1aa1 100644 --- a/packages/functions/test-tangle/swap/swap_8.spec.ts +++ b/packages/functions/test-tangle/swap/swap_8.spec.ts @@ -1,6 +1,7 @@ import { build5Db } from '@build-5/database'; import { COL, + Collection, MIN_IOTA_AMOUNT, Member, NftTransferRequest, @@ -8,14 +9,12 @@ import { SwapStatus, Transaction, TransactionType, + WEN_FUNC, WenError, } from '@build-5/interfaces'; -import { createCollection } from '../../src/runtime/firebase/collection'; -import { nftTransfer } from '../../src/runtime/firebase/nft'; -import { createSwap, rejectSwap, setSwapFunded } from '../../src/runtime/firebase/swap'; import { getAddress } from '../../src/utils/address.utils'; -import { expectThrow, mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { expectThrow, wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet, requestMintedTokenFromFaucet } from '../faucet'; import { Helper, MINTED_TOKEN_ID_1, VAULT_MNEMONIC_1 } from './Helper'; @@ -30,8 +29,8 @@ describe('Swap control test', () => { beforeEach(async () => { await h.beforeEach(); - mockWalletReturnValue(h.spy, h.guardian, h.createDummyCollection(h.space.uid, h.space.uid)); - h.collection = (await testEnv.wrap(createCollection)({})).uid; + mockWalletReturnValue(h.guardian, h.createDummyCollection(h.space.uid, h.space.uid)); + h.collection = (await testEnv.wrap(WEN_FUNC.createCollection)).uid; nfts = [(await h.createAndOrderNft(true)).uid, (await h.createAndOrderNft(true)).uid]; @@ -39,15 +38,15 @@ describe('Swap control test', () => { }); it('Should create, offer base token, request nft, do nft transfer', async () => { - mockWalletReturnValue(h.spy, h.member, { + mockWalletReturnValue(h.member, { network: h.network, nativeTokens: [{ id: MINTED_TOKEN_ID_1, amount: 5 }], nfts, recipient: h.guardian, }); - const swapOrder: Transaction = await testEnv.wrap(createSwap)({}); + const swapOrder = await testEnv.wrap(WEN_FUNC.createSwap); - const swapDocRef = build5Db().doc(`${COL.SWAP}/${swapOrder.payload.swap}`); + const swapDocRef = build5Db().doc(COL.SWAP, swapOrder.payload.swap!); let swap = await swapDocRef.get(); await requestFundsFromFaucet(h.network, swapOrder.payload.targetAddress!, MIN_IOTA_AMOUNT); @@ -62,8 +61,8 @@ describe('Swap control test', () => { { nft: nfts[1], target: swapOrder.payload.targetAddress! }, ], }; - mockWalletReturnValue(h.spy, h.guardian, request); - await testEnv.wrap(nftTransfer)({}); + mockWalletReturnValue(h.guardian, request); + await testEnv.wrap(WEN_FUNC.nftTransfer); const source = await h.wallet.getNewIotaAddressDetails(); await requestFundsFromFaucet(h.network, source.bech32, 10 * MIN_IOTA_AMOUNT); @@ -77,8 +76,8 @@ describe('Swap control test', () => { return swap.askOutputs?.length === 3 && swap.bidOutputs?.length === 1; }); - mockWalletReturnValue(h.spy, h.member, { uid: swap.uid }); - await testEnv.wrap(setSwapFunded)({}); + mockWalletReturnValue(h.member, { uid: swap.uid }); + await testEnv.wrap(WEN_FUNC.setSwapFunded); swap = await swapDocRef.get(); expect(swap.status).toBe(SwapStatus.FULFILLED); @@ -86,9 +85,9 @@ describe('Swap control test', () => { .collection(COL.TRANSACTION) .where('member', '==', h.member) .where('type', '==', TransactionType.BILL_PAYMENT) - .where('payload.swap', '==', swap.uid); + .where('payload_swap', '==', swap.uid); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1 && (snap[0].payload.walletReference?.confirmed || false); }); @@ -96,9 +95,9 @@ describe('Swap control test', () => { .collection(COL.TRANSACTION) .where('member', '==', h.member) .where('type', '==', TransactionType.WITHDRAW_NFT) - .where('payload.swap', '==', swap.uid); + .where('payload_swap', '==', swap.uid); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return ( snap.length === 2 && (snap[0].payload.walletReference?.confirmed || false) && @@ -106,7 +105,7 @@ describe('Swap control test', () => { ); }); - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${h.member}`); + const memberDocRef = build5Db().doc(COL.MEMBER, h.member); const member = await memberDocRef.get(); const response = await h.wallet.client.nftOutputIds([ { address: getAddress(member, h.network) }, @@ -117,13 +116,13 @@ describe('Swap control test', () => { .collection(COL.TRANSACTION) .where('member', '==', h.guardian) .where('type', '==', TransactionType.BILL_PAYMENT) - .where('payload.swap', '==', swap.uid); + .where('payload_swap', '==', swap.uid); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1 && (snap[0].payload.walletReference?.confirmed || false); }); - mockWalletReturnValue(h.spy, h.member, { uid: swap.uid }); - await expectThrow(testEnv.wrap(rejectSwap)({}), WenError.swap_already_fulfilled.key); + mockWalletReturnValue(h.member, { uid: swap.uid }); + await expectThrow(testEnv.wrap(WEN_FUNC.rejectSwap), WenError.swap_already_fulfilled.key); }); }); diff --git a/packages/functions/test-tangle/tangleRequest/simple.token.trade.spec.ts b/packages/functions/test-tangle/tangleRequest/simple.token.trade.spec.ts index f9f48d44a8..fe4bc417ba 100644 --- a/packages/functions/test-tangle/tangleRequest/simple.token.trade.spec.ts +++ b/packages/functions/test-tangle/tangleRequest/simple.token.trade.spec.ts @@ -17,13 +17,11 @@ import { import { Wallet } from '../../src/services/wallet/wallet'; import { getAddress } from '../../src/utils/address.utils'; import * as wallet from '../../src/utils/wallet.utils'; -import { createMember, getRandomSymbol, wait } from '../../test/controls/common'; -import { getWallet } from '../../test/set-up'; +import { getRandomSymbol, wait } from '../../test/controls/common'; +import { getWallet, testEnv } from '../../test/set-up'; import { getTangleOrder } from '../common'; import { requestFundsFromFaucet } from '../faucet'; -let walletSpy: any; - describe('Simple token trading', () => { let member: string; let token: Token; @@ -35,8 +33,7 @@ describe('Simple token trading', () => { }); beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - member = await createMember(walletSpy); + member = await testEnv.createMember(); token = { project: SOON_PROJECT_ID, @@ -47,8 +44,8 @@ describe('Simple token trading', () => { status: TokenStatus.AVAILABLE, approved: true, }; - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).set(token); - await build5Db().doc(`${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${member}`).create({ + await build5Db().doc(COL.TOKEN, token.uid).create(token); + await build5Db().doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, member).create({ parentId: token.uid, parentCol: COL.TOKEN, tokenOwned: 100, @@ -58,7 +55,7 @@ describe('Simple token trading', () => { }); it('Should credit on simple token buy', async () => { - const memberData = await build5Db().doc(`${COL.MEMBER}/${member}`).get(); + const memberData = await build5Db().doc(COL.MEMBER, member).get(); const rmsAddress = await rmsWallet.getAddressDetails(getAddress(memberData, Network.RMS)!); await requestFundsFromFaucet(Network.RMS, rmsAddress.bech32, 5 * MIN_IOTA_AMOUNT); @@ -78,10 +75,10 @@ describe('Simple token trading', () => { .where('member', '==', member) .where('type', '==', TransactionType.CREDIT_TANGLE_REQUEST); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length > 0 && snap[0]?.payload?.walletReference?.confirmed; }); - const snap = await query.get(); + const snap = await query.get(); expect(snap.length).toBe(1); expect(snap[0]?.payload?.response).toEqual({ code: WenError.token_in_invalid_status.code, @@ -91,7 +88,7 @@ describe('Simple token trading', () => { }); it('Should credit on simple token sell', async () => { - const memberData = await build5Db().doc(`${COL.MEMBER}/${member}`).get(); + const memberData = await build5Db().doc(COL.MEMBER, member).get(); const rmsAddress = await rmsWallet.getAddressDetails(getAddress(memberData, Network.RMS)!); await requestFundsFromFaucet(Network.RMS, rmsAddress.bech32, 5 * MIN_IOTA_AMOUNT); @@ -111,10 +108,10 @@ describe('Simple token trading', () => { .where('member', '==', member) .where('type', '==', TransactionType.CREDIT_TANGLE_REQUEST); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length > 0 && snap[0]?.payload?.walletReference?.confirmed; }); - const snap = await query.get(); + const snap = await query.get(); expect(snap.length).toBe(1); expect(snap[0]?.payload?.response).toEqual({ code: WenError.token_in_invalid_status.code, @@ -124,7 +121,7 @@ describe('Simple token trading', () => { }); it('Should set member in case of invalid OTR payment', async () => { - const memberData = await build5Db().doc(`${COL.MEMBER}/${member}`).get(); + const memberData = await build5Db().doc(COL.MEMBER, member).get(); const rmsAddress = await rmsWallet.getAddressDetails(getAddress(memberData, Network.RMS)!); await requestFundsFromFaucet(Network.RMS, rmsAddress.bech32, 5 * MIN_IOTA_AMOUNT); diff --git a/packages/functions/test-tangle/tangleRequest/tangle-request.spec.ts b/packages/functions/test-tangle/tangleRequest/tangle-request.spec.ts index b8469f38cb..03e5ec23bc 100644 --- a/packages/functions/test-tangle/tangleRequest/tangle-request.spec.ts +++ b/packages/functions/test-tangle/tangleRequest/tangle-request.spec.ts @@ -19,13 +19,11 @@ import { AddressDetails } from '../../src/services/wallet/wallet.service'; import { getAddress } from '../../src/utils/address.utils'; import { serverTime } from '../../src/utils/dateTime.utils'; import * as wallet from '../../src/utils/wallet.utils'; -import { createMember, createSpace, getRandomSymbol, wait } from '../../test/controls/common'; -import { getWallet, MEDIA } from '../../test/set-up'; +import { getRandomSymbol, wait } from '../../test/controls/common'; +import { getWallet, MEDIA, testEnv } from '../../test/set-up'; import { getTangleOrder } from '../common'; import { requestFundsFromFaucet } from '../faucet'; -let walletSpy: any; - describe('Tangle request spec', () => { let member: string; let rmsWallet: Wallet; @@ -38,22 +36,19 @@ describe('Tangle request spec', () => { }); beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - member = await createMember(walletSpy); + member = await testEnv.createMember(); rmsWallet = await getWallet(Network.RMS); - const space = await createSpace(walletSpy, member); + const space = await testEnv.createSpace(member); token = await saveToken(space.uid, member); - const memberData = await build5Db().doc(`${COL.MEMBER}/${member}`).get(); + const memberData = await build5Db().doc(COL.MEMBER, member).get(); rmsAddress = await rmsWallet.getAddressDetails(getAddress(memberData, Network.RMS)!); await requestFundsFromFaucet(Network.RMS, rmsAddress.bech32, 10 * MIN_IOTA_AMOUNT); }); it('Should return amount, multiple users with same address', async () => { - const member2 = await createMember(walletSpy); - await build5Db() - .doc(`${COL.MEMBER}/${member2}`) - .set({ validatedAddress: { [Network.RMS]: rmsAddress.bech32 } }, true); + const member2 = await testEnv.createMember(); + await build5Db().doc(COL.MEMBER, member2).upsert({ rmsAddress: rmsAddress.bech32 }); await rmsWallet.send(rmsAddress, tangleOrder.payload.targetAddress!, 5 * MIN_IOTA_AMOUNT, { customMetadata: { @@ -71,10 +66,10 @@ describe('Tangle request spec', () => { .where('member', '==', rmsAddress.bech32) .where('type', '==', TransactionType.CREDIT_TANGLE_REQUEST); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length > 0 && snap[0]?.payload?.walletReference?.confirmed; }); - const snap = await query.get(); + const snap = await query.get(); expect(snap.length).toBe(1); expect(snap[0]?.payload?.response).toEqual({ code: WenError.multiple_members_with_same_address.code, @@ -105,18 +100,14 @@ describe('Tangle request spec', () => { .where('owner', '==', address.bech32) .where('type', '==', TokenTradeOrderType.BUY); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1; }); - const member2 = await createMember(walletSpy); - await build5Db() - .doc(`${COL.MEMBER}/${member2}`) - .set({ validatedAddress: { [Network.RMS]: rmsAddress.bech32 } }, true); - const member3 = await createMember(walletSpy); - await build5Db() - .doc(`${COL.MEMBER}/${member3}`) - .set({ validatedAddress: { [Network.RMS]: rmsAddress.bech32 } }, true); + const member2 = await testEnv.createMember(); + await build5Db().doc(COL.MEMBER, member2).upsert({ rmsAddress: rmsAddress.bech32 }); + const member3 = await testEnv.createMember(); + await build5Db().doc(COL.MEMBER, member3).upsert({ rmsAddress: rmsAddress.bech32 }); await rmsWallet.send(address, tangleOrder.payload.targetAddress!, 0.2 * MIN_IOTA_AMOUNT, { customMetadata: { @@ -130,7 +121,7 @@ describe('Tangle request spec', () => { }); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 2; }); }); @@ -166,10 +157,10 @@ describe('Tangle request spec', () => { .where('member', '==', member) .where('type', '==', TransactionType.CREDIT_TANGLE_REQUEST); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length > 0 && snap[0]?.payload?.walletReference?.confirmed; }); - const snap = await query.get(); + const snap = await query.get(); expect(snap.length).toBe(1); expect(snap[0]?.payload?.response).toEqual({ code: WenError.invalid_tangle_request_type.code, @@ -196,7 +187,7 @@ const saveToken = async (space: string, guardian: string) => { mintingData: { network: Network.RMS, }, - }; - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).set(token); + } as Token; + await build5Db().doc(COL.TOKEN, token.uid).create(token); return token as Token; }; diff --git a/packages/functions/test-tangle/token-import/Helper.ts b/packages/functions/test-tangle/token-import/Helper.ts index 1aed1961d4..80cc77afc9 100644 --- a/packages/functions/test-tangle/token-import/Helper.ts +++ b/packages/functions/test-tangle/token-import/Helper.ts @@ -1,20 +1,22 @@ import { build5Db } from '@build-5/database'; -import { COL, Member, Network, Space, SUB_COL, Token, TokenStatus } from '@build-5/interfaces'; -import { mintTokenOrder } from '../../src/runtime/firebase/token/minting'; +import { + COL, + Member, + Network, + SUB_COL, + Space, + Token, + TokenStatus, + Transaction, + WEN_FUNC, +} from '@build-5/interfaces'; import { Wallet } from '../../src/services/wallet/wallet'; import { AddressDetails } from '../../src/services/wallet/wallet.service'; import { getAddress } from '../../src/utils/address.utils'; import { serverTime } from '../../src/utils/dateTime.utils'; -import * as wallet from '../../src/utils/wallet.utils'; import { getRandomEthAddress } from '../../src/utils/wallet.utils'; -import { - createMember, - createSpace, - getRandomSymbol, - mockWalletReturnValue, - wait, -} from '../../test/controls/common'; -import { getWallet, MEDIA, testEnv } from '../../test/set-up'; +import { getRandomSymbol, wait } from '../../test/controls/common'; +import { MEDIA, getWallet, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; export class Helper { @@ -25,32 +27,29 @@ export class Helper { public token: Token = {} as any; public walletService: Wallet = {} as any; public member: string = ''; - public walletSpy: any = {} as any; public network = Network.RMS; public totalSupply = 1500; public beforeEach = async () => { - this.walletSpy = jest.spyOn(wallet, 'decodeAuth'); - - const guardianId = await createMember(this.walletSpy); - this.member = await createMember(this.walletSpy); - this.guardian = await build5Db().doc(`${COL.MEMBER}/${guardianId}`).get(); - this.space = await createSpace(this.walletSpy, this.guardian.uid); - this.importSpace = await createSpace(this.walletSpy, this.guardian.uid); + const guardianId = await testEnv.createMember(); + this.member = await testEnv.createMember(); + this.guardian = await build5Db().doc(COL.MEMBER, guardianId).get(); + this.space = await testEnv.createSpace(this.guardian.uid); + this.importSpace = await testEnv.createSpace(this.guardian.uid); this.token = await this.saveToken(this.space.uid, this.guardian.uid, this.member); this.walletService = await getWallet(this.network); this.address = await this.walletService.getAddressDetails( getAddress(this.guardian, this.network), ); - mockWalletReturnValue(this.walletSpy, this.guardian.uid, { + mockWalletReturnValue(this.guardian.uid, { token: this.token.uid, network: this.network, }); - const order = await testEnv.wrap(mintTokenOrder)({}); + const order = await testEnv.wrap(WEN_FUNC.mintTokenOrder); await requestFundsFromFaucet(this.network, order.payload.targetAddress, order.payload.amount); - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${this.token.uid}`); + const tokenDocRef = build5Db().doc(COL.TOKEN, this.token.uid); await wait(async () => { this.token = await tokenDocRef.get(); return this.token.status === TokenStatus.MINTED; @@ -76,11 +75,11 @@ export class Helper { description: 'myrandomtoken', icon: MEDIA, decimals: 4, - }; - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).set(token); + } as Token; + await build5Db().doc(COL.TOKEN, token.uid).create(token); await build5Db() - .doc(`${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${member}`) - .set({ tokenOwned: 1000 }); + .doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, member) + .upsert({ tokenOwned: 1000 }); return token; }; } diff --git a/packages/functions/test-tangle/token-import/token.import_1.spec.ts b/packages/functions/test-tangle/token-import/token.import_1.spec.ts index e8c814fb63..e94729184f 100644 --- a/packages/functions/test-tangle/token-import/token.import_1.spec.ts +++ b/packages/functions/test-tangle/token-import/token.import_1.spec.ts @@ -2,18 +2,18 @@ import { build5Db } from '@build-5/database'; import { Access, COL, - MediaStatus, MIN_IOTA_AMOUNT, + MediaStatus, Token, TokenStatus, Transaction, TransactionPayloadType, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; -import { importMintedToken } from '../../src/runtime/firebase/token/minting'; import { getAddress } from '../../src/utils/address.utils'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -25,24 +25,24 @@ describe('Token import', () => { }); it('Should migrate token', async () => { - mockWalletReturnValue(helper.walletSpy, helper.guardian.uid, { + mockWalletReturnValue(helper.guardian.uid, { space: helper.importSpace.uid, tokenId: helper.token.mintingData?.tokenId, network: helper.network, }); - const order = await testEnv.wrap(importMintedToken)({}); + const order = await testEnv.wrap(WEN_FUNC.importMintedToken); const guardianBech32 = getAddress(helper.guardian, helper.network); const guardianAddress = await helper.walletService.getAddressDetails(guardianBech32); await requestFundsFromFaucet(helper.network, guardianBech32, 2 * MIN_IOTA_AMOUNT); await helper.walletService.send( guardianAddress, - order.payload.targetAddress, + order.payload.targetAddress!, 2 * MIN_IOTA_AMOUNT, {}, ); - const migratedTokenDocRef = build5Db().doc(`${COL.TOKEN}/${helper.token.mintingData?.tokenId}`); + const migratedTokenDocRef = build5Db().doc(COL.TOKEN, helper.token.mintingData?.tokenId!); await wait(async () => (await migratedTokenDocRef.get()) !== undefined); const migratedToken = await migratedTokenDocRef.get(); @@ -83,17 +83,17 @@ describe('Token import', () => { .collection(COL.TRANSACTION) .where('member', '==', helper.guardian.uid) .where('type', '==', TransactionType.CREDIT) - .where('payload.type', '==', TransactionPayloadType.IMPORT_TOKEN); + .where('payload_type', '==', TransactionPayloadType.IMPORT_TOKEN); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); expect(snap[0]?.payload.amount).toBe(2 * MIN_IOTA_AMOUNT); const payment = await build5Db() - .doc(`${COL.TRANSACTION}/${snap[0].payload.sourceTransaction![0]}`) - .get(); + .doc(COL.TRANSACTION, snap[0].payload.sourceTransaction![0]) + .get(); expect(payment?.payload.invalidPayment).toBe(false); }); }); diff --git a/packages/functions/test-tangle/token-import/token.import_2.spec.ts b/packages/functions/test-tangle/token-import/token.import_2.spec.ts index 86f57531f7..21a058c5e9 100644 --- a/packages/functions/test-tangle/token-import/token.import_2.spec.ts +++ b/packages/functions/test-tangle/token-import/token.import_2.spec.ts @@ -1,8 +1,7 @@ import { build5Db } from '@build-5/database'; -import { COL, MIN_IOTA_AMOUNT, Transaction } from '@build-5/interfaces'; -import { importMintedToken } from '../../src/runtime/firebase/token/minting'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { COL, MIN_IOTA_AMOUNT, Transaction, WEN_FUNC } from '@build-5/interfaces'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -14,23 +13,22 @@ describe('Token import', () => { }); it('Should throw, not guardian ', async () => { - mockWalletReturnValue(helper.walletSpy, helper.guardian.uid, { + mockWalletReturnValue(helper.guardian.uid, { space: helper.importSpace.uid, tokenId: helper.token.mintingData?.tokenId, network: helper.network, }); - const order = await testEnv.wrap(importMintedToken)({}); + const order = await testEnv.wrap(WEN_FUNC.importMintedToken); await requestFundsFromFaucet(helper.network, order.payload.targetAddress, 2 * MIN_IOTA_AMOUNT); const creditQuery = build5Db() .collection(COL.TRANSACTION) - .where('member', '==', helper.guardian.uid) - .where('payload.response.code', '==', 2122); + .where('member', '==', helper.guardian.uid); await wait(async () => { - const snap = await creditQuery.get(); + const snap = (await creditQuery.get()).filter((s) => s.payload.response?.code === 2122); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); - const migratedTokenDocRef = build5Db().doc(`${COL.TOKEN}/${helper.token.mintingData?.tokenId}`); + const migratedTokenDocRef = build5Db().doc(COL.TOKEN, helper.token.mintingData?.tokenId!); expect((await migratedTokenDocRef.get()) !== undefined).toBe(false); }); }); diff --git a/packages/functions/test-tangle/token.based.voting/Helper.ts b/packages/functions/test-tangle/token.based.voting/Helper.ts index f5d916fd19..188aec9d56 100644 --- a/packages/functions/test-tangle/token.based.voting/Helper.ts +++ b/packages/functions/test-tangle/token.based.voting/Helper.ts @@ -1,7 +1,6 @@ import { build5Db } from '@build-5/database'; import { COL, - Member, MIN_IOTA_AMOUNT, Network, NetworkAddress, @@ -10,31 +9,27 @@ import { ProposalType, SOON_PROJECT_ID, Space, + Stake, SUB_COL, + Token, TokenStatus, Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; import { set } from 'lodash'; -import { - approveProposal, - createProposal, - voteOnProposal, -} from '../../src/runtime/firebase/proposal'; -import { joinSpace } from '../../src/runtime/firebase/space'; 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 { dateToTimestamp } from '../../src/utils/dateTime.utils'; import * as wallet from '../../src/utils/wallet.utils'; -import { createMember, createSpace, mockWalletReturnValue, wait } from '../../test/controls/common'; -import { getWallet, testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { getWallet, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet, requestMintedTokenFromFaucet } from '../faucet'; export class Helper { - public walletSpy: any; public guardian: string = ''; public member: string = ''; public space: Space | undefined; @@ -49,25 +44,24 @@ export class Helper { }; public beforeEach = async () => { - this.walletSpy = jest.spyOn(wallet, 'decodeAuth'); - this.guardian = await createMember(this.walletSpy); - this.member = await createMember(this.walletSpy); - this.space = await createSpace(this.walletSpy, this.guardian); + this.guardian = await testEnv.createMember(); + this.member = await testEnv.createMember(); + this.space = await testEnv.createSpace(this.guardian); - mockWalletReturnValue(this.walletSpy, this.member, { uid: this.space.uid }); - await testEnv.wrap(joinSpace)({}); + mockWalletReturnValue(this.member, { uid: this.space.uid }); + await testEnv.wrap(WEN_FUNC.joinSpace); this.proposal = dummyProposal(this.space.uid); delete (this.proposal as any).completed; - const guardianDocRef = build5Db().doc(`${COL.MEMBER}/${this.guardian}`); - const guardianData = await guardianDocRef.get(); + const guardianDocRef = build5Db().doc(COL.MEMBER, this.guardian); + const guardianData = await guardianDocRef.get(); const guardianAddressBech = getAddress(guardianData, this.network); this.guardianAddress = await this.walletService!.getAddressDetails(guardianAddressBech); this.tokenId = wallet.getRandomEthAddress(); await build5Db() - .doc(`${COL.TOKEN}/${this.tokenId}`) + .doc(COL.TOKEN, this.tokenId) .create({ project: SOON_PROJECT_ID, uid: this.tokenId, @@ -75,15 +69,15 @@ export class Helper { mintingData: { tokenId: MINTED_TOKEN_ID }, status: TokenStatus.MINTED, approved: true, - }); + } as Token); const { uid, ...requestData } = this.proposal; set(requestData, 'settings.startDate', this.proposal.settings.startDate.toDate()); set(requestData, 'settings.endDate', this.proposal.settings.endDate.toDate()); - mockWalletReturnValue(this.walletSpy, this.guardian, requestData); - this.proposal = await testEnv.wrap(createProposal)({}); - mockWalletReturnValue(this.walletSpy, this.guardian, { uid: this.proposal?.uid }); - await testEnv.wrap(approveProposal)({}); + mockWalletReturnValue(this.guardian, requestData); + this.proposal = await testEnv.wrap(WEN_FUNC.createProposal); + mockWalletReturnValue(this.guardian, { uid: this.proposal?.uid }); + await testEnv.wrap(WEN_FUNC.approveProposal); }; public requestFunds = async () => { @@ -114,10 +108,10 @@ export class Helper { ) => { const query = build5Db() .collection(COL.TRANSACTION) - .where('payload.sourceAddress', '==', voteTransactionOrderTargetAddress) + .where('payload_sourceAddress', '==', voteTransactionOrderTargetAddress) .where('type', '==', TransactionType.CREDIT); await wait(async () => { - const creditSnap = await query.get(); + const creditSnap = await query.get(); return creditSnap.length === 1 && creditSnap[0]?.payload?.walletReference?.confirmed; }); const creditSnap = await query.get(); @@ -127,36 +121,27 @@ export class Helper { public getVoteTransactionForCredit = async (creditId: string) => { const query = build5Db() .collection(COL.TRANSACTION) - .where('payload.creditId', '==', creditId) + .where('payload_creditId', '==', creditId) .where('type', '==', TransactionType.VOTE); const voteTranSnap = await query.get(); return voteTranSnap[0] as Transaction; }; public updatePropoasalDates = (startDate: dayjs.Dayjs, endDate: dayjs.Dayjs) => - build5Db() - .doc(`${COL.PROPOSAL}/${this.proposal!.uid}`) - .set( - { - settings: { - startDate: dateToTimestamp(startDate), - endDate: dateToTimestamp(endDate), - }, - }, - true, - ); + build5Db().doc(COL.PROPOSAL, this.proposal!.uid).upsert({ + settings_startDate: startDate.toDate(), + settings_endDate: endDate.toDate(), + }); public updateVoteTranCreatedOn = (voteTransactionId: string, createdOn: dayjs.Dayjs) => - build5Db() - .doc(`${COL.TRANSACTION}/${voteTransactionId}`) - .update({ createdOn: dateToTimestamp(createdOn) }); + build5Db().doc(COL.TRANSACTION, voteTransactionId).update({ createdOn: createdOn.toDate() }); public assertProposalWeights = async ( total: number, voted: number, proposalId = this.proposal!.uid, ) => { - const proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${proposalId}`); + const proposalDocRef = build5Db().doc(COL.PROPOSAL, proposalId); const proposal = await proposalDocRef.get(); expect(+proposal.results?.total.toFixed(0)).toBe(total); expect(+proposal.results?.voted.toFixed(0)).toBe(voted); @@ -168,8 +153,7 @@ export class Helper { answer: number, proposalId = this.proposal!.uid, ) => { - const proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${proposalId}`); - const proposalMemberDocRef = proposalDocRef.collection(SUB_COL.MEMBERS).doc(member); + const proposalMemberDocRef = build5Db().doc(COL.PROPOSAL, proposalId, SUB_COL.MEMBERS, member); const proposalMember = await proposalMemberDocRef.get(); expect(+proposalMember.weightPerAnswer![answer].toFixed(0)).toBe(weight); }; @@ -180,12 +164,12 @@ export class Helper { member = this.guardian, proposalId = this.proposal!.uid, ) => { - mockWalletReturnValue(this.walletSpy, member, { + mockWalletReturnValue(member, { uid: proposalId, value, voteWithStakedTokes, }); - return await testEnv.wrap(voteOnProposal)({}); + return await testEnv.wrap(WEN_FUNC.voteOnProposal); }; public createStake = async (createdOn: dayjs.Dayjs, expiresAt: dayjs.Dayjs, amount = 100) => { @@ -198,13 +182,13 @@ export class Helper { member: this.guardian, uid: wallet.getRandomEthAddress(), token: this.tokenId, - }; - const docRef = build5Db().doc(`${COL.STAKE}/${stake.uid}`); + } as Stake; + const docRef = build5Db().doc(COL.STAKE, stake.uid); await docRef.create(stake); }; public getTransaction = async (uid: string) => { - const docRef = build5Db().doc(`${COL.TRANSACTION}/${uid}`); + const docRef = build5Db().doc(COL.TRANSACTION, uid); return await docRef.get(); }; } diff --git a/packages/functions/test-tangle/token.based.voting/stake.voting.spec.ts b/packages/functions/test-tangle/token.based.voting/stake.voting.spec.ts index af414c812e..4bf3ae15be 100644 --- a/packages/functions/test-tangle/token.based.voting/stake.voting.spec.ts +++ b/packages/functions/test-tangle/token.based.voting/stake.voting.spec.ts @@ -1,10 +1,8 @@ import { build5Db } from '@build-5/database'; -import { COL, SUB_COL } from '@build-5/interfaces'; +import { COL, Proposal, ProposalMember, SUB_COL, WEN_FUNC } from '@build-5/interfaces'; import dayjs from 'dayjs'; import { set } from 'lodash'; -import { approveProposal, createProposal } from '../../src/runtime/firebase/proposal'; -import { mockWalletReturnValue } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper, dummyProposal } from './Helper'; describe('Staked oken based voting', () => { @@ -17,28 +15,44 @@ describe('Staked oken based voting', () => { beforeEach(async () => { await helper.beforeEach(); - const distributionDocRef = build5Db() - .collection(COL.TOKEN) - .doc(helper.tokenId) - .collection(SUB_COL.DISTRIBUTION) - .doc(helper.guardian); - await distributionDocRef.create({}); + const distributionDocRef = build5Db().doc( + COL.TOKEN, + helper.tokenId, + SUB_COL.DISTRIBUTION, + helper.guardian, + ); + await distributionDocRef.create({ parentId: helper.tokenId, parentCol: COL.TOKEN }); }); it('Should vote with staked tokens', async () => { await helper.createStake(dayjs().subtract(2, 'd'), dayjs().add(1, 'y')); await helper.createStake(dayjs().subtract(2, 'd'), dayjs().add(3, 'd')); const voteTransaction = await helper.voteOnProposal(1, true); - expect(+voteTransaction.payload.weight.toFixed(0)).toBe(150); - - await helper.assertProposalWeights(150, 150); - await helper.assertProposalMemberWeightsPerAnser(helper.guardian, 150, 1); + expect(Math.floor(voteTransaction.payload.weight!)).toBeGreaterThanOrEqual(149); + expect(Math.floor(voteTransaction.payload.weight!)).toBeLessThanOrEqual(150); + + const proposalDocRef = build5Db().doc(COL.PROPOSAL, helper.proposal!.uid); + const proposal = await proposalDocRef.get(); + expect(Math.floor(proposal.results?.total)).toBeGreaterThanOrEqual(149); + expect(Math.floor(proposal.results?.total)).toBeLessThanOrEqual(150); + expect(Math.floor(proposal.results?.voted)).toBeGreaterThanOrEqual(149); + expect(Math.floor(proposal.results?.voted)).toBeLessThanOrEqual(150); + + const proposalMemberDocRef = build5Db().doc( + COL.PROPOSAL, + helper.proposal!.uid, + SUB_COL.MEMBERS, + helper.guardian, + ); + const proposalMember = await proposalMemberDocRef.get(); + expect(Math.floor(proposalMember.weightPerAnswer![1])).toBeGreaterThanOrEqual(149); + expect(Math.floor(proposalMember.weightPerAnswer![1])).toBeLessThanOrEqual(150); }); it('Should vote in the beginning and mid way ', async () => { await helper.createStake(dayjs().subtract(2, 'd'), dayjs().add(1, 'y')); let voteTransaction1 = await helper.voteOnProposal(1, true); - expect(+voteTransaction1.payload.weight.toFixed(2)).toBe(100); + expect(+voteTransaction1.payload.weight!.toFixed(2)).toBe(100); await helper.assertProposalWeights(100, 100); await helper.assertProposalMemberWeightsPerAnser(helper.guardian, 100, 1); @@ -47,10 +61,10 @@ describe('Staked oken based voting', () => { await helper.updateVoteTranCreatedOn(voteTransaction1.uid, dayjs().subtract(3, 'd')); const voteTransaction2 = await helper.voteOnProposal(1, true); - expect(+voteTransaction2.payload.weight.toFixed(2)).toBe(50); + expect(+voteTransaction2.payload.weight!.toFixed(2)).toBe(50); voteTransaction1 = await helper.getTransaction(voteTransaction1.uid); - expect(+voteTransaction1.payload.weight.toFixed(2)).toBe(50); + expect(+voteTransaction1.payload.weight!.toFixed(2)).toBe(50); await helper.assertProposalWeights(100, 100); await helper.assertProposalMemberWeightsPerAnser(helper.guardian, 100, 1); @@ -62,25 +76,25 @@ describe('Staked oken based voting', () => { const { uid, completed, ...requestData } = dummyProposal(helper.space!.uid); set(requestData, 'settings.startDate', requestData.settings.startDate.toDate()); set(requestData, 'settings.endDate', requestData.settings.endDate.toDate()); - mockWalletReturnValue(helper.walletSpy, helper.guardian, requestData); + mockWalletReturnValue(helper.guardian, requestData); - const proposal = await testEnv.wrap(createProposal)({}); - mockWalletReturnValue(helper.walletSpy, helper.guardian, { uid: proposal!.uid }); - await testEnv.wrap(approveProposal)({}); + const proposal = await testEnv.wrap(WEN_FUNC.createProposal); + mockWalletReturnValue(helper.guardian, { uid: proposal!.uid }); + await testEnv.wrap(WEN_FUNC.approveProposal); let voteTransaction1 = await helper.voteOnProposal(1, true); - expect(+voteTransaction1.payload.weight.toFixed(2)).toBe(100); + expect(+voteTransaction1.payload.weight!.toFixed(2)).toBe(100); await helper.updatePropoasalDates(dayjs().subtract(2, 'd'), dayjs().add(2, 'd')); await helper.updateVoteTranCreatedOn(voteTransaction1.uid, dayjs().subtract(3, 'd')); const voteTransaction2 = await helper.voteOnProposal(1, true, undefined, proposal.uid); - expect(+voteTransaction2.payload.weight.toFixed(2)).toBe(100); + expect(+voteTransaction2.payload.weight!.toFixed(2)).toBe(100); await helper.assertProposalWeights(100, 100, proposal.uid); await helper.assertProposalMemberWeightsPerAnser(helper.guardian, 100, 1, proposal.uid); voteTransaction1 = await helper.getTransaction(voteTransaction1.uid); - expect(+voteTransaction1.payload.weight.toFixed(2)).toBe(50); + expect(+voteTransaction1.payload.weight!.toFixed(2)).toBe(50); await helper.assertProposalWeights(50, 50); await helper.assertProposalMemberWeightsPerAnser(helper.guardian, 50, 1); }); diff --git a/packages/functions/test-tangle/token.based.voting/token.based.voting_1.spec.ts b/packages/functions/test-tangle/token.based.voting/token.based.voting_1.spec.ts index f2f07bea69..98ca027dd3 100644 --- a/packages/functions/test-tangle/token.based.voting/token.based.voting_1.spec.ts +++ b/packages/functions/test-tangle/token.based.voting/token.based.voting_1.spec.ts @@ -17,9 +17,9 @@ describe('Token based voting', () => { it('Should vote full, then 50%', async () => { const voteTransactionOrder = await helper.voteOnProposal(1); - await helper.sendTokensToVote(voteTransactionOrder.payload.targetAddress); + await helper.sendTokensToVote(voteTransactionOrder.payload.targetAddress!); const credit = await helper.awaitVoteTransactionCreditIsConfirmed( - voteTransactionOrder.payload.targetAddress, + voteTransactionOrder.payload.targetAddress!, ); const voteTransaction = await helper.getVoteTransactionForCredit(credit.uid); @@ -44,13 +44,13 @@ describe('Token based voting', () => { const voteTransactionOrder = await helper.voteOnProposal(1); await helper.sendTokensToVote( - voteTransactionOrder.payload.targetAddress, + voteTransactionOrder.payload.targetAddress!, 10, undefined, voteTransactionOrder.payload.amount, ); const credit = await helper.awaitVoteTransactionCreditIsConfirmed( - voteTransactionOrder.payload.targetAddress, + voteTransactionOrder.payload.targetAddress!, ); const voteTransaction = await helper.getVoteTransactionForCredit(credit.uid); diff --git a/packages/functions/test-tangle/token.based.voting/token.based.voting_2.spec.ts b/packages/functions/test-tangle/token.based.voting/token.based.voting_2.spec.ts index f4302fdb73..701dbb63c2 100644 --- a/packages/functions/test-tangle/token.based.voting/token.based.voting_2.spec.ts +++ b/packages/functions/test-tangle/token.based.voting/token.based.voting_2.spec.ts @@ -18,9 +18,9 @@ describe('Token based voting', () => { it('Should vote, spend and vote again', async () => { let voteTransactionOrder = await helper.voteOnProposal(1); - await helper.sendTokensToVote(voteTransactionOrder.payload.targetAddress); + await helper.sendTokensToVote(voteTransactionOrder.payload.targetAddress!); let credit = await helper.awaitVoteTransactionCreditIsConfirmed( - voteTransactionOrder.payload.targetAddress, + voteTransactionOrder.payload.targetAddress!, ); let voteTransaction = await helper.getVoteTransactionForCredit(credit.uid); @@ -40,9 +40,9 @@ describe('Token based voting', () => { await helper.assertProposalMemberWeightsPerAnser(helper.guardian, 5, 1); voteTransactionOrder = await helper.voteOnProposal(1); - await helper.sendTokensToVote(voteTransactionOrder.payload.targetAddress); + await helper.sendTokensToVote(voteTransactionOrder.payload.targetAddress!); credit = await helper.awaitVoteTransactionCreditIsConfirmed( - voteTransactionOrder.payload.targetAddress, + voteTransactionOrder.payload.targetAddress!, ); voteTransaction = await helper.getVoteTransactionForCredit(credit.uid); expect(+voteTransaction.payload.weight!.toFixed(2)).toBe(5); @@ -52,9 +52,9 @@ describe('Token based voting', () => { it('Should vote twice without spending', async () => { let voteTransactionOrder = await helper.voteOnProposal(1); - await helper.sendTokensToVote(voteTransactionOrder.payload.targetAddress); + await helper.sendTokensToVote(voteTransactionOrder.payload.targetAddress!); let credit = await helper.awaitVoteTransactionCreditIsConfirmed( - voteTransactionOrder.payload.targetAddress, + voteTransactionOrder.payload.targetAddress!, ); let voteTransaction = await helper.getVoteTransactionForCredit(credit.uid); @@ -76,9 +76,9 @@ describe('Token based voting', () => { ); voteTransactionOrder = await helper.voteOnProposal(1); - await helper.sendTokensToVote(voteTransactionOrder.payload.targetAddress, 10, tmp); + await helper.sendTokensToVote(voteTransactionOrder.payload.targetAddress!, 10, tmp); credit = await helper.awaitVoteTransactionCreditIsConfirmed( - voteTransactionOrder.payload.targetAddress, + voteTransactionOrder.payload.targetAddress!, ); voteTransaction = await helper.getVoteTransactionForCredit(credit.uid); expect(+voteTransaction.payload.weight!.toFixed(2)).toBe(5); diff --git a/packages/functions/test-tangle/token.based.voting/token.based.voting_3.spec.ts b/packages/functions/test-tangle/token.based.voting/token.based.voting_3.spec.ts index af84b57286..25d38ca123 100644 --- a/packages/functions/test-tangle/token.based.voting/token.based.voting_3.spec.ts +++ b/packages/functions/test-tangle/token.based.voting/token.based.voting_3.spec.ts @@ -1,8 +1,7 @@ -import { MIN_IOTA_AMOUNT, WenError } from '@build-5/interfaces'; +import { MIN_IOTA_AMOUNT, WEN_FUNC, WenError } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { voteOnProposal } from '../../src/runtime/firebase/proposal'; -import { expectThrow, mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { expectThrow, wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet, requestMintedTokenFromFaucet } from '../faucet'; import { Helper, MINTED_TOKEN_ID, VAULT_MNEMONIC } from './Helper'; @@ -20,9 +19,9 @@ describe('Token based voting', () => { it('Should vote on both answers and spend both', async () => { let voteTransactionOrder = await helper.voteOnProposal(1); - await helper.sendTokensToVote(voteTransactionOrder.payload.targetAddress); + await helper.sendTokensToVote(voteTransactionOrder.payload.targetAddress!); const credit = await helper.awaitVoteTransactionCreditIsConfirmed( - voteTransactionOrder.payload.targetAddress, + voteTransactionOrder.payload.targetAddress!, ); const voteTransaction = await helper.getVoteTransactionForCredit(credit.uid); @@ -44,9 +43,9 @@ describe('Token based voting', () => { ); voteTransactionOrder = await helper.voteOnProposal(2); - await helper.sendTokensToVote(voteTransactionOrder.payload.targetAddress, 10, tmp); + await helper.sendTokensToVote(voteTransactionOrder.payload.targetAddress!, 10, tmp); const credit2 = await helper.awaitVoteTransactionCreditIsConfirmed( - voteTransactionOrder.payload.targetAddress, + voteTransactionOrder.payload.targetAddress!, ); const voteTransaction2 = await helper.getVoteTransactionForCredit(credit2.uid); expect(+voteTransaction2.payload.weight!.toFixed(2)).toBe(5); @@ -72,10 +71,10 @@ describe('Token based voting', () => { it('Should throw, can not vote after end date', async () => { await helper.updatePropoasalDates(dayjs().subtract(2, 'd'), dayjs().subtract(1, 'd')); - mockWalletReturnValue(helper.walletSpy, helper.guardian, { + mockWalletReturnValue(helper.guardian, { uid: helper.proposal!.uid, value: 1, }); - await expectThrow(testEnv.wrap(voteOnProposal)({}), WenError.vote_is_no_longer_active.key); + await expectThrow(testEnv.wrap(WEN_FUNC.voteOnProposal), WenError.vote_is_no_longer_active.key); }); }); diff --git a/packages/functions/test-tangle/token.based.voting/token.based.voting_4.spec.ts b/packages/functions/test-tangle/token.based.voting/token.based.voting_4.spec.ts index 590933542c..5530a52e80 100644 --- a/packages/functions/test-tangle/token.based.voting/token.based.voting_4.spec.ts +++ b/packages/functions/test-tangle/token.based.voting/token.based.voting_4.spec.ts @@ -1,10 +1,9 @@ import { build5Db } from '@build-5/database'; -import { COL, Member, WenError } from '@build-5/interfaces'; +import { COL, Member, WEN_FUNC, WenError } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { voteOnProposal } from '../../src/runtime/firebase/proposal'; import { getAddress } from '../../src/utils/address.utils'; -import { expectThrow, mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { expectThrow, wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; describe('Token based voting', () => { @@ -21,18 +20,18 @@ describe('Token based voting', () => { it('Should throw, can only vote 24 hours before', async () => { await helper.updatePropoasalDates(dayjs().add(3, 'd'), dayjs().add(5, 'd')); - mockWalletReturnValue(helper.walletSpy, helper.guardian, { + mockWalletReturnValue(helper.guardian, { uid: helper.proposal!.uid, value: 1, }); - await expectThrow(testEnv.wrap(voteOnProposal)({}), WenError.vote_is_no_longer_active.key); + await expectThrow(testEnv.wrap(WEN_FUNC.voteOnProposal), WenError.vote_is_no_longer_active.key); }); it('Should vote, spend, other person votes with it', async () => { let voteTransactionOrder = await helper.voteOnProposal(1); - await helper.sendTokensToVote(voteTransactionOrder.payload.targetAddress); + await helper.sendTokensToVote(voteTransactionOrder.payload.targetAddress!); let credit = await helper.awaitVoteTransactionCreditIsConfirmed( - voteTransactionOrder.payload.targetAddress, + voteTransactionOrder.payload.targetAddress!, ); let voteTransaction = await helper.getVoteTransactionForCredit(credit.uid); @@ -43,7 +42,7 @@ describe('Token based voting', () => { await helper.updatePropoasalDates(dayjs().subtract(2, 'd'), dayjs().add(2, 'd')); await helper.updateVoteTranCreatedOn(voteTransaction.uid, dayjs().subtract(3, 'd')); - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${helper.member}`); + const memberDocRef = build5Db().doc(COL.MEMBER, helper.member); const member = await memberDocRef.get(); const memberAddress = await helper.walletService!.getAddressDetails( getAddress(member, helper.network), @@ -57,9 +56,9 @@ describe('Token based voting', () => { await helper.assertProposalMemberWeightsPerAnser(helper.guardian, 5, 1); voteTransactionOrder = await helper.voteOnProposal(1, false, helper.member); - await helper.sendTokensToVote(voteTransactionOrder.payload.targetAddress, 10, memberAddress); + await helper.sendTokensToVote(voteTransactionOrder.payload.targetAddress!, 10, memberAddress); credit = await helper.awaitVoteTransactionCreditIsConfirmed( - voteTransactionOrder.payload.targetAddress, + voteTransactionOrder.payload.targetAddress!, ); voteTransaction = await helper.getVoteTransactionForCredit(credit.uid); @@ -70,9 +69,9 @@ describe('Token based voting', () => { it('Should not reduce weight when voting after end date', async () => { const voteTransactionOrder = await helper.voteOnProposal(1); - await helper.sendTokensToVote(voteTransactionOrder.payload.targetAddress); + await helper.sendTokensToVote(voteTransactionOrder.payload.targetAddress!); const credit = await helper.awaitVoteTransactionCreditIsConfirmed( - voteTransactionOrder.payload.targetAddress, + voteTransactionOrder.payload.targetAddress!, ); let voteTransaction = await helper.getVoteTransactionForCredit(credit.uid); diff --git a/packages/functions/test-tangle/token.based.voting/token.based.voting_5.spec.ts b/packages/functions/test-tangle/token.based.voting/token.based.voting_5.spec.ts index 339ed38a06..463795aac5 100644 --- a/packages/functions/test-tangle/token.based.voting/token.based.voting_5.spec.ts +++ b/packages/functions/test-tangle/token.based.voting/token.based.voting_5.spec.ts @@ -1,5 +1,5 @@ import { build5Db } from '@build-5/database'; -import { COL, SOON_PROJECT_ID, TokenStatus } from '@build-5/interfaces'; +import { COL, SOON_PROJECT_ID, Token, TokenStatus } from '@build-5/interfaces'; import { getRandomEthAddress } from '../../src/utils/wallet.utils'; import { Helper } from './Helper'; @@ -22,14 +22,14 @@ describe('Token based voting', () => { space: helper.space!.uid, status: TokenStatus.PRE_MINTED, approved: false, - }; - await build5Db().doc(`${COL.TOKEN}/${falseToken.uid}`).create(falseToken); + } as Token; + await build5Db().doc(COL.TOKEN, falseToken.uid).create(falseToken); const voteTransactionOrder = await helper.voteOnProposal(1); - await helper.sendTokensToVote(voteTransactionOrder.payload.targetAddress); + await helper.sendTokensToVote(voteTransactionOrder.payload.targetAddress!); const credit = await helper.awaitVoteTransactionCreditIsConfirmed( - voteTransactionOrder.payload.targetAddress, + voteTransactionOrder.payload.targetAddress!, ); const voteTransaction = await helper.getVoteTransactionForCredit(credit.uid); diff --git a/packages/functions/test-tangle/token.mint/Helper.ts b/packages/functions/test-tangle/token.mint/Helper.ts index 00ec543c97..926dab266f 100644 --- a/packages/functions/test-tangle/token.mint/Helper.ts +++ b/packages/functions/test-tangle/token.mint/Helper.ts @@ -33,9 +33,8 @@ import { packBasicOutput } from '../../src/utils/basic-output.utils'; import { createUnlock, packEssence, submitBlock } from '../../src/utils/block.utils'; import { serverTime } from '../../src/utils/dateTime.utils'; import * as wallet from '../../src/utils/wallet.utils'; -import { getRandomEthAddress } from '../../src/utils/wallet.utils'; -import { createMember, createSpace, getRandomSymbol } from '../../test/controls/common'; -import { MEDIA, getWallet } from '../../test/set-up'; +import { getRandomSymbol } from '../../test/controls/common'; +import { MEDIA, getWallet, testEnv } from '../../test/set-up'; export class Helper { public guardian: Member = {} as any; @@ -44,19 +43,14 @@ export class Helper { public token: Token = {} as any; public walletService: Wallet = {} as any; public member: string = ''; - public walletSpy: any = {} as any; public network = Network.RMS; public totalSupply = 1500; - public beforeEach = async () => { - this.walletSpy = jest.spyOn(wallet, 'decodeAuth'); - }; - public setup = async (approved = true, isPublicToken?: boolean) => { - const guardianId = await createMember(this.walletSpy); - this.member = await createMember(this.walletSpy); - this.guardian = await build5Db().doc(`${COL.MEMBER}/${guardianId}`).get(); - this.space = await createSpace(this.walletSpy, this.guardian.uid); + const guardianId = await testEnv.createMember(); + this.member = await testEnv.createMember(); + this.guardian = await build5Db().doc(COL.MEMBER, guardianId).get(); + this.space = await testEnv.createSpace(this.guardian.uid); this.token = await this.saveToken( this.space.uid, this.guardian.uid, @@ -77,7 +71,7 @@ export class Helper { approved = true, isPublicToken = true, ) => { - const tokenId = getRandomEthAddress(); + const tokenId = wallet.getRandomEthAddress(); const token = { project: SOON_PROJECT_ID, symbol: getRandomSymbol(), @@ -94,11 +88,11 @@ export class Helper { public: isPublicToken, approved, decimals: 5, - }; - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).set(token); + } as Token; + await build5Db().doc(COL.TOKEN, token.uid).create(token); await build5Db() - .doc(`${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${member}`) - .set({ tokenOwned: 1000 }); + .doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, member) + .upsert({ tokenOwned: 1000 }); return token; }; @@ -161,7 +155,7 @@ export class Helper { ]; const blockId = await submitBlock(wallet, essence, unlocks); - await build5Db().doc(`blocks/${blockId}`).create({ blockId }); + await testEnv.createBlock(blockId); return blockId; }; } diff --git a/packages/functions/test-tangle/token.mint/token.mint_1.spec.ts b/packages/functions/test-tangle/token.mint/token.mint_1.spec.ts index 214567ea98..f2a757ff98 100644 --- a/packages/functions/test-tangle/token.mint/token.mint_1.spec.ts +++ b/packages/functions/test-tangle/token.mint/token.mint_1.spec.ts @@ -10,34 +10,30 @@ import { Transaction, TransactionPayloadType, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; import { FoundryOutput } from '@iota/sdk'; import dayjs from 'dayjs'; import { isEqual } from 'lodash'; -import { mintTokenOrder } from '../../src/runtime/firebase/token/minting'; import { getAddress } from '../../src/utils/address.utils'; import { dateToTimestamp } from '../../src/utils/dateTime.utils'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { Helper, getAliasOutput, getFoundryMetadata, getStateAndGovernorAddress } from './Helper'; describe('Token minting', () => { const helper = new Helper(); - beforeEach(async () => { - await helper.beforeEach(); - }); - it.each([false, true])('Should mint token', async (hasExpiration: boolean) => { const expiresAt = hasExpiration ? dateToTimestamp(dayjs().add(2, 'h').toDate()) : undefined; await helper.setup(false, hasExpiration); - mockWalletReturnValue(helper.walletSpy, helper.guardian.uid, { + mockWalletReturnValue(helper.guardian.uid, { token: helper.token.uid, network: helper.network, }); - const order = await testEnv.wrap(mintTokenOrder)({}); + const order = await testEnv.wrap(WEN_FUNC.mintTokenOrder); await requestFundsFromFaucet( helper.network, order.payload.targetAddress, @@ -45,9 +41,9 @@ describe('Token minting', () => { expiresAt, ); - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${helper.token.uid}`); + const tokenDocRef = build5Db().doc(COL.TOKEN, helper.token.uid); await wait(async () => { - const snap = await tokenDocRef.get(); + const snap = await tokenDocRef.get(); return snap?.status === TokenStatus.MINTED; }); @@ -75,7 +71,7 @@ describe('Token minting', () => { ); return Number(Object.values(nativeTokens)[0]) === 1000; }); - const guardianData = await build5Db().doc(`${COL.MEMBER}/${helper.guardian.uid}`).get(); + const guardianData = await build5Db().doc(COL.MEMBER, helper.guardian.uid).get(); await wait(async () => { const { nativeTokens } = await helper.walletService.getBalance( getAddress(guardianData, helper.network), @@ -95,7 +91,7 @@ describe('Token minting', () => { const mintTransactions = ( await build5Db() .collection(COL.TRANSACTION) - .where('payload.token', '==', helper.token.uid) + .where('payload_token', '==', helper.token.uid) .where('type', '==', TransactionType.MINT_TOKEN) .get() ).map((d) => d); diff --git a/packages/functions/test-tangle/token.mint/token.mint_2.spec.ts b/packages/functions/test-tangle/token.mint/token.mint_2.spec.ts index accc67abe3..0927033f1a 100644 --- a/packages/functions/test-tangle/token.mint/token.mint_2.spec.ts +++ b/packages/functions/test-tangle/token.mint/token.mint_2.spec.ts @@ -1,12 +1,19 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { build5Db } from '@build-5/database'; -import { COL, Member, Token, TokenStatus, TransactionType, WenError } from '@build-5/interfaces'; -import { mintTokenOrder } from '../../src/runtime/firebase/token/minting'; +import { + COL, + Member, + Token, + TokenStatus, + Transaction, + TransactionType, + WEN_FUNC, + WenError, +} from '@build-5/interfaces'; import { getAddress } from '../../src/utils/address.utils'; -import * as wallet from '../../src/utils/wallet.utils'; -import { expectThrow, mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { expectThrow, wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitTransactionConfirmationsForToken } from '../common'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -14,26 +21,22 @@ import { Helper } from './Helper'; describe('Token minting', () => { const helper = new Helper(); - beforeEach(async () => { - await helper.beforeEach(); - }); - it('Should mint token and melt some', async () => { await helper.setup(); - mockWalletReturnValue(helper.walletSpy, helper.guardian.uid, { + mockWalletReturnValue(helper.guardian.uid, { token: helper.token.uid, network: helper.network, }); - const order = await testEnv.wrap(mintTokenOrder)({}); + const order = await testEnv.wrap(WEN_FUNC.mintTokenOrder); await requestFundsFromFaucet(helper.network, order.payload.targetAddress, order.payload.amount); - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${helper.token.uid}`); + const tokenDocRef = build5Db().doc(COL.TOKEN, helper.token.uid); await wait(async () => { helper.token = await tokenDocRef.get(); return helper.token.status === TokenStatus.MINTED; }); - const guardianData = await build5Db().doc(`${COL.MEMBER}/${helper.guardian.uid}`).get(); + const guardianData = await build5Db().doc(COL.MEMBER, helper.guardian.uid).get(); const guardianAddress = getAddress(guardianData, helper.network); await wait(async () => { const { nativeTokens } = await helper.walletService.getBalance(guardianAddress); @@ -53,57 +56,61 @@ describe('Token minting', () => { it('Should create order, not approved but public', async () => { await helper.setup(); - await build5Db() - .doc(`${COL.TOKEN}/${helper.token.uid}`) - .update({ approved: false, public: true }); - mockWalletReturnValue(helper.walletSpy, helper.guardian.uid, { + await build5Db().doc(COL.TOKEN, helper.token.uid).update({ approved: false, public: true }); + mockWalletReturnValue(helper.guardian.uid, { token: helper.token.uid, network: helper.network, }); - const order = await testEnv.wrap(mintTokenOrder)({}); + const order = await testEnv.wrap(WEN_FUNC.mintTokenOrder); expect(order).toBeDefined(); }); it('Should throw, member has no valid address', async () => { await helper.setup(); - await build5Db().doc(`${COL.MEMBER}/${helper.guardian.uid}`).update({ validatedAddress: {} }); - mockWalletReturnValue(helper.walletSpy, helper.guardian.uid, { + await build5Db() + .doc(COL.MEMBER, helper.guardian.uid) + .update({ smrAddress: '', rmsAddress: '', iotaAddress: '', atoiAddress: '' }); + mockWalletReturnValue(helper.guardian.uid, { token: helper.token.uid, network: helper.network, }); await expectThrow( - testEnv.wrap(mintTokenOrder)({}), + testEnv.wrap(WEN_FUNC.mintTokenOrder), WenError.member_must_have_validated_address.key, ); }); it('Should throw, not guardian', async () => { await helper.setup(); - mockWalletReturnValue(helper.walletSpy, wallet.getRandomEthAddress(), { - token: helper.token.uid, - network: helper.network, - }); - await expectThrow(testEnv.wrap(mintTokenOrder)({}), WenError.you_are_not_guardian_of_space.key); + + mockWalletReturnValue(helper.member, { token: helper.token.uid, network: helper.network }); + await expectThrow( + testEnv.wrap(WEN_FUNC.mintTokenOrder), + WenError.you_are_not_guardian_of_space.key, + ); }); it('Should throw, already minted', async () => { await helper.setup(); - await build5Db().doc(`${COL.TOKEN}/${helper.token.uid}`).update({ status: TokenStatus.MINTED }); - mockWalletReturnValue(helper.walletSpy, helper.guardian.uid, { + await build5Db().doc(COL.TOKEN, helper.token.uid).update({ status: TokenStatus.MINTED }); + mockWalletReturnValue(helper.guardian.uid, { token: helper.token.uid, network: helper.network, }); - await expectThrow(testEnv.wrap(mintTokenOrder)({}), WenError.token_in_invalid_status.key); + await expectThrow( + testEnv.wrap(WEN_FUNC.mintTokenOrder), + WenError.token_in_invalid_status.key, + ); }); it('Should credit, already minted', async () => { await helper.setup(); - mockWalletReturnValue(helper.walletSpy, helper.guardian.uid, { + mockWalletReturnValue(helper.guardian.uid, { token: helper.token.uid, network: helper.network, }); - const order = await testEnv.wrap(mintTokenOrder)({}); - const order2 = await testEnv.wrap(mintTokenOrder)({}); + const order = await testEnv.wrap(WEN_FUNC.mintTokenOrder); + const order2 = await testEnv.wrap(WEN_FUNC.mintTokenOrder); await requestFundsFromFaucet(helper.network, order.payload.targetAddress, order.payload.amount); await requestFundsFromFaucet( @@ -112,9 +119,9 @@ describe('Token minting', () => { order2.payload.amount, ); - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${helper.token.uid}`); + const tokenDocRef = build5Db().doc(COL.TOKEN, helper.token.uid); await wait(async () => { - const snap = await tokenDocRef.get(); + const snap = await tokenDocRef.get(); return snap?.status === TokenStatus.MINTED; }); await wait(async () => { diff --git a/packages/functions/test-tangle/token.mint/token.mint_3.spec.ts b/packages/functions/test-tangle/token.mint/token.mint_3.spec.ts index acb79dec10..7f9a28934b 100644 --- a/packages/functions/test-tangle/token.mint/token.mint_3.spec.ts +++ b/packages/functions/test-tangle/token.mint/token.mint_3.spec.ts @@ -10,31 +10,21 @@ import { TokenStatus, TokenTradeOrderStatus, TokenTradeOrderType, + Transaction, TransactionType, + WEN_FUNC, WenError, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { setTokenAvailableForSale } from '../../src/runtime/firebase/token/base'; -import { mintTokenOrder } from '../../src/runtime/firebase/token/minting'; -import { tradeToken } from '../../src/runtime/firebase/token/trading'; import { dateToTimestamp } from '../../src/utils/dateTime.utils'; -import { - expectThrow, - mockWalletReturnValue, - submitMilestoneFunc, - wait, -} from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { expectThrow, submitMilestoneFunc, wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; describe('Token minting', () => { const helper = new Helper(); - beforeEach(async () => { - await helper.beforeEach(); - }); - it('Should cancel all active buys', async () => { await helper.setup(); const request = { @@ -43,12 +33,12 @@ describe('Token minting', () => { count: 5, type: TokenTradeOrderType.BUY, }; - mockWalletReturnValue(helper.walletSpy, helper.guardian.uid, request); + mockWalletReturnValue(helper.guardian.uid, request); - const order = await testEnv.wrap(tradeToken)({}); + const order = await testEnv.wrap(WEN_FUNC.tradeToken); await submitMilestoneFunc(order); - const order2 = await testEnv.wrap(tradeToken)({}); + const order2 = await testEnv.wrap(WEN_FUNC.tradeToken); await submitMilestoneFunc(order2); await wait(async () => { @@ -60,20 +50,20 @@ describe('Token minting', () => { return buySnap.length === 2; }); - mockWalletReturnValue(helper.walletSpy, helper.guardian.uid, { + mockWalletReturnValue(helper.guardian.uid, { token: helper.token.uid, network: helper.network, }); - const mintOrder = await testEnv.wrap(mintTokenOrder)({}); + const mintOrder = await testEnv.wrap(WEN_FUNC.mintTokenOrder); await requestFundsFromFaucet( helper.network, mintOrder.payload.targetAddress, mintOrder.payload.amount, ); - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${helper.token.uid}`); + const tokenDocRef = build5Db().doc(COL.TOKEN, helper.token.uid); await wait(async () => { - const snap = await tokenDocRef.get(); + const snap = await tokenDocRef.get(); return snap?.status === TokenStatus.MINTING; }); @@ -106,15 +96,15 @@ describe('Token minting', () => { count: 500, type: TokenTradeOrderType.SELL, }; - mockWalletReturnValue(helper.walletSpy, helper.member, request); - await testEnv.wrap(tradeToken)({}); - await testEnv.wrap(tradeToken)({}); + mockWalletReturnValue(helper.member, request); + await testEnv.wrap(WEN_FUNC.tradeToken); + await testEnv.wrap(WEN_FUNC.tradeToken); - mockWalletReturnValue(helper.walletSpy, helper.guardian.uid, { + mockWalletReturnValue(helper.guardian.uid, { token: helper.token.uid, network: helper.network, }); - const mintOrder = await testEnv.wrap(mintTokenOrder)({}); + const mintOrder = await testEnv.wrap(WEN_FUNC.mintTokenOrder); await requestFundsFromFaucet( helper.network, mintOrder.payload.targetAddress, @@ -122,7 +112,7 @@ describe('Token minting', () => { ); await wait(async () => { - const snap = await build5Db().doc(`${COL.TOKEN}/${helper.token.uid}`).get(); + const snap = await build5Db().doc(COL.TOKEN, helper.token.uid).get(); return snap?.status === TokenStatus.MINTING; }); @@ -137,9 +127,7 @@ describe('Token minting', () => { }); const distribution = ( - await build5Db() - .doc(`${COL.TOKEN}/${helper.token.uid}/${SUB_COL.DISTRIBUTION}/${helper.member}`) - .get() + await build5Db().doc(COL.TOKEN, helper.token.uid, SUB_COL.DISTRIBUTION, helper.member).get() ); expect(distribution.lockedForSale).toBe(0); expect(distribution.tokenOwned).toBe(1000); @@ -153,19 +141,25 @@ describe('Token minting', () => { coolDownLength: 86400000, }; await build5Db() - .doc(`${COL.TOKEN}/${helper.token.uid}`) - .update({ allocations: [{ title: 'public', percentage: 100, isPublicSale: true }] }); + .doc(COL.TOKEN, helper.token.uid) + .update({ + allocations: JSON.stringify([{ title: 'public', percentage: 100, isPublicSale: true }]), + }); const updateData = { token: helper.token.uid, ...publicTime, pricePerToken: MIN_IOTA_AMOUNT }; - mockWalletReturnValue(helper.walletSpy, helper.guardian.uid, updateData); - const result = await testEnv.wrap(setTokenAvailableForSale)({}); - expect(result?.saleStartDate.toDate()).toEqual( + mockWalletReturnValue(helper.guardian.uid, updateData); + let token = await testEnv.wrap(WEN_FUNC.setTokenAvailableForSale); + token = (await build5Db().doc(COL.TOKEN, token.uid).get())!; + expect(token.saleStartDate?.toDate()).toEqual( dateToTimestamp(dayjs(publicTime.saleStartDate), true).toDate(), ); - mockWalletReturnValue(helper.walletSpy, helper.guardian.uid, { + mockWalletReturnValue(helper.guardian.uid, { token: helper.token.uid, network: helper.network, }); - await expectThrow(testEnv.wrap(mintTokenOrder)({}), WenError.can_not_mint_in_pub_sale.key); + await expectThrow( + testEnv.wrap(WEN_FUNC.mintTokenOrder), + WenError.can_not_mint_in_pub_sale.key, + ); }); }); diff --git a/packages/functions/test-tangle/token.mint/token.mint_4.spec.ts b/packages/functions/test-tangle/token.mint/token.mint_4.spec.ts index 27de8d92fd..78e15eb11f 100644 --- a/packages/functions/test-tangle/token.mint/token.mint_4.spec.ts +++ b/packages/functions/test-tangle/token.mint/token.mint_4.spec.ts @@ -8,30 +8,25 @@ import { TokenStatus, Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { cancelPublicSale, setTokenAvailableForSale } from '../../src/runtime/firebase/token/base'; -import { mintTokenOrder } from '../../src/runtime/firebase/token/minting'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; describe('Token minting', () => { const helper = new Helper(); - beforeEach(async () => { - await helper.beforeEach(); - }); - it('Should credit, token in public sale', async () => { await helper.setup(); - mockWalletReturnValue(helper.walletSpy, helper.guardian.uid, { + mockWalletReturnValue(helper.guardian.uid, { token: helper.token.uid, network: helper.network, }); - const order = await testEnv.wrap(mintTokenOrder)({}); + const order = await testEnv.wrap(WEN_FUNC.mintTokenOrder); const publicTime = { saleStartDate: dayjs().add(2, 'd').toDate(), @@ -39,11 +34,13 @@ describe('Token minting', () => { coolDownLength: 86400000, }; await build5Db() - .doc(`${COL.TOKEN}/${helper.token.uid}`) - .update({ allocations: [{ title: 'public', percentage: 100, isPublicSale: true }] }); + .doc(COL.TOKEN, helper.token.uid) + .update({ + allocations: JSON.stringify([{ title: 'public', percentage: 100, isPublicSale: true }]), + }); const updateData = { token: helper.token.uid, ...publicTime, pricePerToken: MIN_IOTA_AMOUNT }; - mockWalletReturnValue(helper.walletSpy, helper.guardian.uid, updateData); - await testEnv.wrap(setTokenAvailableForSale)({}); + mockWalletReturnValue(helper.guardian.uid, updateData); + await testEnv.wrap(WEN_FUNC.setTokenAvailableForSale); await requestFundsFromFaucet(helper.network, order.payload.targetAddress, order.payload.amount); @@ -62,11 +59,11 @@ describe('Token minting', () => { it('Should credit, token in public sale, cancel public sale then mint', async () => { await helper.setup(); - mockWalletReturnValue(helper.walletSpy, helper.guardian.uid, { + mockWalletReturnValue(helper.guardian.uid, { token: helper.token.uid, network: helper.network, }); - const order = await testEnv.wrap(mintTokenOrder)({}); + const order = await testEnv.wrap(WEN_FUNC.mintTokenOrder); const publicTime = { saleStartDate: dayjs().add(2, 'd').toDate(), @@ -74,11 +71,13 @@ describe('Token minting', () => { coolDownLength: 86400000, }; await build5Db() - .doc(`${COL.TOKEN}/${helper.token.uid}`) - .update({ allocations: [{ title: 'public', percentage: 100, isPublicSale: true }] }); + .doc(COL.TOKEN, helper.token.uid) + .update({ + allocations: JSON.stringify([{ title: 'public', percentage: 100, isPublicSale: true }]), + }); const updateData = { token: helper.token.uid, ...publicTime, pricePerToken: MIN_IOTA_AMOUNT }; - mockWalletReturnValue(helper.walletSpy, helper.guardian.uid, updateData); - await testEnv.wrap(setTokenAvailableForSale)({}); + mockWalletReturnValue(helper.guardian.uid, updateData); + await testEnv.wrap(WEN_FUNC.setTokenAvailableForSale); await requestFundsFromFaucet(helper.network, order.payload.targetAddress, order.payload.amount); @@ -93,12 +92,12 @@ describe('Token minting', () => { const credit = (await creditQuery.get()).map((d) => d)[0]; expect(credit?.payload?.amount).toBe(order.payload.amount); - mockWalletReturnValue(helper.walletSpy, helper.guardian.uid, { token: helper.token.uid }); - await testEnv.wrap(cancelPublicSale)({}); + mockWalletReturnValue(helper.guardian.uid, { token: helper.token.uid }); + await testEnv.wrap(WEN_FUNC.cancelPublicSale); await requestFundsFromFaucet(helper.network, order.payload.targetAddress, order.payload.amount); await wait(async () => { - const tokenData = await build5Db().doc(`${COL.TOKEN}/${helper.token.uid}`).get(); + const tokenData = await build5Db().doc(COL.TOKEN, helper.token.uid).get(); return tokenData.status === TokenStatus.MINTED; }); }); diff --git a/packages/functions/test-tangle/trade-base-token-order.spec.ts b/packages/functions/test-tangle/trade-base-token-order.spec.ts index 23aa588b66..5e78efb9b4 100644 --- a/packages/functions/test-tangle/trade-base-token-order.spec.ts +++ b/packages/functions/test-tangle/trade-base-token-order.spec.ts @@ -13,47 +13,29 @@ import { TokenTradeOrderType, Transaction, TransactionType, + WEN_FUNC, WenError, } from '@build-5/interfaces'; -import { createMember } from '../src/runtime/firebase/member'; -import { cancelTradeOrder, tradeToken } from '../src/runtime/firebase/token/trading'; -import { AddressDetails } from '../src/services/wallet/wallet.service'; import { getAddress } from '../src/utils/address.utils'; import { serverTime } from '../src/utils/dateTime.utils'; import * as wallet from '../src/utils/wallet.utils'; -import { - createMember as createMemberTest, - createRoyaltySpaces, - createSpace, - expectThrow, - getRandomSymbol, - mockWalletReturnValue, - wait, -} from '../test/controls/common'; -import { MEDIA, testEnv } from '../test/set-up'; -import { addValidatedAddress, awaitTransactionConfirmationsForToken } from './common'; +import { createRoyaltySpaces, expectThrow, getRandomSymbol, wait } from '../test/controls/common'; +import { MEDIA, mockWalletReturnValue, testEnv } from '../test/set-up'; +import { awaitTransactionConfirmationsForToken } from './common'; import { requestFundsFromFaucet } from './faucet'; -let walletSpy: any; - describe('Trade base token controller', () => { let seller: Member; - const validateAddress = {} as { [key: string]: AddressDetails }; let token: Token; beforeEach(async () => { await createRoyaltySpaces(); - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - const sellerId = wallet.getRandomEthAddress(); - mockWalletReturnValue(walletSpy, sellerId, {}); - await testEnv.wrap(createMember)({ address: sellerId }); - validateAddress[Network.ATOI] = await addValidatedAddress(Network.ATOI, sellerId); - validateAddress[Network.RMS] = await addValidatedAddress(Network.RMS, sellerId); - seller = await build5Db().doc(`${COL.MEMBER}/${sellerId}`).get(); + const sellerId = await testEnv.createMember(); + seller = await build5Db().doc(COL.MEMBER, sellerId).get(); - const guardian = await createMemberTest(walletSpy); - const space = await createSpace(walletSpy, guardian); + const guardian = await testEnv.createMember(); + const space = await testEnv.createSpace(guardian); token = await saveToken(space.uid, guardian); }); @@ -62,13 +44,13 @@ describe('Trade base token controller', () => { { sourceNetwork: Network.ATOI, targetNetwork: Network.RMS }, { sourceNetwork: Network.RMS, targetNetwork: Network.ATOI }, ])('Should create trade order', async ({ sourceNetwork, targetNetwork }) => { - mockWalletReturnValue(walletSpy, seller.uid, { + mockWalletReturnValue(seller.uid, { symbol: token.symbol, count: MIN_IOTA_AMOUNT, price: 1, type: sourceNetwork === Network.ATOI ? TokenTradeOrderType.SELL : TokenTradeOrderType.BUY, }); - const tradeOrder = await testEnv.wrap(tradeToken)({}); + const tradeOrder = await testEnv.wrap(WEN_FUNC.tradeToken); await requestFundsFromFaucet(sourceNetwork, tradeOrder.payload.targetAddress, MIN_IOTA_AMOUNT); const query = build5Db().collection(COL.TOKEN_MARKET).where('owner', '==', seller.uid); @@ -85,8 +67,8 @@ describe('Trade base token controller', () => { sourceNetwork === Network.ATOI ? TokenTradeOrderType.SELL : TokenTradeOrderType.BUY, ); - mockWalletReturnValue(walletSpy, seller.uid, { uid: trade.uid }); - const cancelled = await testEnv.wrap(cancelTradeOrder)({}); + mockWalletReturnValue(seller.uid, { uid: trade.uid }); + const cancelled = await testEnv.wrap(WEN_FUNC.cancelTradeOrder); expect(cancelled.status).toBe(TokenTradeOrderStatus.CANCELLED); const creditSnap = await build5Db() @@ -106,16 +88,16 @@ describe('Trade base token controller', () => { 'Should throw, source address not verified', async (network: Network) => { await build5Db() - .doc(`${COL.MEMBER}/${seller.uid}`) - .update({ [`validatedAddress.${network}`]: build5Db().deleteField() }); - mockWalletReturnValue(walletSpy, seller.uid, { + .doc(COL.MEMBER, seller.uid) + .update({ [`${network}Address`]: undefined }); + mockWalletReturnValue(seller.uid, { symbol: token.symbol, count: 10, price: MIN_IOTA_AMOUNT, type: network === Network.ATOI ? TokenTradeOrderType.SELL : TokenTradeOrderType.BUY, }); await expectThrow( - testEnv.wrap(tradeToken)({}), + testEnv.wrap(WEN_FUNC.tradeToken), WenError.member_must_have_validated_address.key, ); }, @@ -126,16 +108,16 @@ describe('Trade base token controller', () => { { sourceNetwork: Network.RMS, targetNetwork: Network.ATOI }, ])('Should throw, target address not verified', async ({ sourceNetwork, targetNetwork }) => { await build5Db() - .doc(`${COL.MEMBER}/${seller.uid}`) - .update({ [`validatedAddress.${targetNetwork}`]: build5Db().deleteField() }); - mockWalletReturnValue(walletSpy, seller.uid, { + .doc(COL.MEMBER, seller.uid) + .update({ [`${targetNetwork}Address`]: undefined }); + mockWalletReturnValue(seller.uid, { symbol: token.symbol, count: 10, price: MIN_IOTA_AMOUNT, type: sourceNetwork === Network.ATOI ? TokenTradeOrderType.SELL : TokenTradeOrderType.BUY, }); await expectThrow( - testEnv.wrap(tradeToken)({}), + testEnv.wrap(WEN_FUNC.tradeToken), WenError.member_must_have_validated_address.key, ); }); @@ -156,7 +138,7 @@ const saveToken = async (space: string, guardian: string) => { access: 0, icon: MEDIA, mintingData: { network: Network.ATOI }, - }; - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).set(token); - return token as Token; + } as Token; + await build5Db().doc(COL.TOKEN, token.uid).create(token); + return token; }; diff --git a/packages/functions/test-tangle/tran.match.spec.ts b/packages/functions/test-tangle/tran.match.spec.ts index 19d2dbc426..8a45efe851 100644 --- a/packages/functions/test-tangle/tran.match.spec.ts +++ b/packages/functions/test-tangle/tran.match.spec.ts @@ -87,6 +87,6 @@ const saveOrder = async (wallet: Wallet) => { validationType: TransactionValidationType.ADDRESS, }, }; - await build5Db().doc(`${COL.TRANSACTION}/${data.uid}`).create(data); + await build5Db().doc(COL.TRANSACTION, data.uid).create(data); return data; }; diff --git a/packages/functions/test-tangle/transaction-trigger/transaction-trigger_1.spec.ts b/packages/functions/test-tangle/transaction-trigger/transaction-trigger_1.spec.ts index d92c02aead..9d53c59c2a 100644 --- a/packages/functions/test-tangle/transaction-trigger/transaction-trigger_1.spec.ts +++ b/packages/functions/test-tangle/transaction-trigger/transaction-trigger_1.spec.ts @@ -49,16 +49,14 @@ describe('Transaction trigger spec', () => { void: false, }, }; - await build5Db().doc(`${COL.TRANSACTION}/${billPayment.uid}`).create(billPayment); + await build5Db().doc(COL.TRANSACTION, billPayment.uid).create(billPayment); await wait(async () => { const { amount } = await wallet.getBalance(targetAddress.bech32); return amount === MIN_IOTA_AMOUNT; }); await wait(async () => { - billPayment = ( - await build5Db().doc(`${COL.TRANSACTION}/${billPayment.uid}`).get() - ); + billPayment = await build5Db().doc(COL.TRANSACTION, billPayment.uid).get(); return billPayment.payload?.walletReference?.confirmed; }); }, diff --git a/packages/functions/test-tangle/transaction-trigger/transaction-trigger_10.spec.ts b/packages/functions/test-tangle/transaction-trigger/transaction-trigger_10.spec.ts index 3d9ff01ef9..a95b5b2503 100644 --- a/packages/functions/test-tangle/transaction-trigger/transaction-trigger_10.spec.ts +++ b/packages/functions/test-tangle/transaction-trigger/transaction-trigger_10.spec.ts @@ -49,15 +49,13 @@ describe('Transaction trigger spec', () => { targetAddress.bech32, ); const batch = build5Db().batch(); - batch.create(build5Db().doc(`${COL.TRANSACTION}/${credit.uid}`), credit); - batch.create(build5Db().doc(`${COL.TRANSACTION}/${billPayment.uid}`), billPayment); + batch.create(build5Db().doc(COL.TRANSACTION, credit.uid), credit); + batch.create(build5Db().doc(COL.TRANSACTION, billPayment.uid), billPayment); await batch.commit(); await wait(async () => { - billPayment = ( - await build5Db().doc(`${COL.TRANSACTION}/${billPayment.uid}`).get() - ); - credit = await build5Db().doc(`${COL.TRANSACTION}/${credit.uid}`).get(); + billPayment = await build5Db().doc(COL.TRANSACTION, billPayment.uid).get(); + credit = await build5Db().doc(COL.TRANSACTION, credit.uid).get(); return ( billPayment?.payload?.walletReference?.confirmed && credit?.payload?.walletReference?.confirmed diff --git a/packages/functions/test-tangle/transaction-trigger/transaction-trigger_11.spec.ts b/packages/functions/test-tangle/transaction-trigger/transaction-trigger_11.spec.ts index 7970ba70f1..d14f437b0e 100644 --- a/packages/functions/test-tangle/transaction-trigger/transaction-trigger_11.spec.ts +++ b/packages/functions/test-tangle/transaction-trigger/transaction-trigger_11.spec.ts @@ -45,7 +45,7 @@ describe('Transaction trigger spec', () => { sourceAddress.bech32, targetAddress.bech32, ); - await build5Db().doc(`${COL.TRANSACTION}/${billPayment.uid}`).create(billPayment); + await build5Db().doc(COL.TRANSACTION, billPayment.uid).create(billPayment); await wait(async () => { const mnemonic = await MnemonicService.getData(sourceAddress.bech32); @@ -54,9 +54,7 @@ describe('Transaction trigger spec', () => { await wait(async () => { const mnemonic = await MnemonicService.getData(sourceAddress.bech32); - const payment = ( - await build5Db().doc(`${COL.TRANSACTION}/${billPayment.uid}`).get() - ); + const payment = await build5Db().doc(COL.TRANSACTION, billPayment.uid).get(); return ( isEmpty(mnemonic.consumedOutputIds) && payment?.payload?.walletReference?.confirmed && diff --git a/packages/functions/test-tangle/transaction-trigger/transaction-trigger_12.spec.ts b/packages/functions/test-tangle/transaction-trigger/transaction-trigger_12.spec.ts index d796c6b603..c6dbbf8a4b 100644 --- a/packages/functions/test-tangle/transaction-trigger/transaction-trigger_12.spec.ts +++ b/packages/functions/test-tangle/transaction-trigger/transaction-trigger_12.spec.ts @@ -15,7 +15,7 @@ import { isEmpty } from 'lodash'; import { retryWallet } from '../../src/cron/wallet.cron'; import { MnemonicService } from '../../src/services/wallet/mnemonic'; import { AddressDetails } from '../../src/services/wallet/wallet.service'; -import { dateToTimestamp, serverTime } from '../../src/utils/dateTime.utils'; +import { serverTime } from '../../src/utils/dateTime.utils'; import { getRandomEthAddress } from '../../src/utils/wallet.utils'; import { wait } from '../../test/controls/common'; import { getWallet } from '../../test/set-up'; @@ -52,7 +52,7 @@ describe('Transaction trigger spec', () => { 2 * MIN_IOTA_AMOUNT, ), }; - const billPaymentDocRef = build5Db().doc(`${COL.TRANSACTION}/${billPayment.uid}`); + const billPaymentDocRef = build5Db().doc(COL.TRANSACTION, billPayment.uid); await billPaymentDocRef.create(billPayment); await wait(async () => { @@ -65,10 +65,8 @@ describe('Transaction trigger spec', () => { expect(consumedOutputIds.sort()).toEqual(outputIds.sort()); await billPaymentDocRef.update({ - 'payload.amount': MIN_IOTA_AMOUNT, - 'payload.walletReference.processedOn': dateToTimestamp( - dayjs().subtract(4, 'minute').toDate(), - ), + payload_amount: MIN_IOTA_AMOUNT, + payload_walletReference_processedOn: dayjs().subtract(4, 'minute').toDate(), }); const result = await retryWallet(); expect(result.find((r) => r === billPayment.uid)).toBeDefined(); diff --git a/packages/functions/test-tangle/transaction-trigger/transaction-trigger_13.spec.ts b/packages/functions/test-tangle/transaction-trigger/transaction-trigger_13.spec.ts index aba50ef86c..f3968fe645 100644 --- a/packages/functions/test-tangle/transaction-trigger/transaction-trigger_13.spec.ts +++ b/packages/functions/test-tangle/transaction-trigger/transaction-trigger_13.spec.ts @@ -15,7 +15,7 @@ import dayjs from 'dayjs'; import { isEmpty } from 'lodash'; import { retryWallet } from '../../src/cron/wallet.cron'; import { AddressDetails } from '../../src/services/wallet/wallet.service'; -import { dateToTimestamp, serverTime } from '../../src/utils/dateTime.utils'; +import { serverTime } from '../../src/utils/dateTime.utils'; import { getRandomEthAddress } from '../../src/utils/wallet.utils'; import { wait } from '../../test/controls/common'; import { getWallet } from '../../test/set-up'; @@ -51,20 +51,20 @@ describe('Transaction trigger spec', () => { ), ignoreWallet: true, }; - await build5Db().doc(`${COL.TRANSACTION}/${billPayment.uid}`).create(billPayment); + await build5Db().doc(COL.TRANSACTION, billPayment.uid).create(billPayment); await new Promise((r) => setTimeout(r, 1000)); await build5Db() - .doc(`${COL.MNEMONIC}/${sourceAddress.bech32}`) + .doc(COL.MNEMONIC, sourceAddress.bech32) .update({ lockedBy: billPayment.uid, consumedOutputIds: outputIds }); await build5Db() - .doc(`${COL.TRANSACTION}/${billPayment.uid}`) + .doc(COL.TRANSACTION, billPayment.uid) .update({ ignoreWallet: false, - 'payload.walletReference.confirmed': false, - 'payload.walletReference.inProgress': true, - 'payload.walletReference.count': MAX_WALLET_RETRY, - 'payload.walletReference.processedOn': dateToTimestamp(dayjs().subtract(4, 'd').toDate()), + payload_walletReference_confirmed: false, + payload_walletReference_inProgress: true, + payload_walletReference_count: MAX_WALLET_RETRY, + payload_walletReference_processedOn: dayjs().subtract(4, 'd').toDate(), }); let billPayment2 = dummyPayment( @@ -73,17 +73,13 @@ describe('Transaction trigger spec', () => { sourceAddress.bech32, targetAddress.bech32, ); - await build5Db().doc(`${COL.TRANSACTION}/${billPayment2.uid}`).create(billPayment2); + await build5Db().doc(COL.TRANSACTION, billPayment2.uid).create(billPayment2); await retryWallet(); await wait(async () => { - const mnemonic = ( - await build5Db().doc(`${COL.MNEMONIC}/${sourceAddress.bech32}`).get() - ); - billPayment = ( - await build5Db().doc(`${COL.TRANSACTION}/${billPayment.uid}`).get() - ); + const mnemonic = await build5Db().doc(COL.MNEMONIC, sourceAddress.bech32).get(); + billPayment = await build5Db().doc(COL.TRANSACTION, billPayment.uid).get(); return ( !billPayment.payload?.walletReference?.inProgress && !billPayment.payload?.walletReference?.confirmed && @@ -93,9 +89,7 @@ describe('Transaction trigger spec', () => { }); await wait(async () => { - billPayment2 = ( - await build5Db().doc(`${COL.TRANSACTION}/${billPayment2.uid}`).get() - ); + billPayment2 = await build5Db().doc(COL.TRANSACTION, billPayment2.uid).get(); return billPayment2.payload?.walletReference?.confirmed; }); }, diff --git a/packages/functions/test-tangle/transaction-trigger/transaction-trigger_14.spec.ts b/packages/functions/test-tangle/transaction-trigger/transaction-trigger_14.spec.ts index ebddd11ad9..cfae38face 100644 --- a/packages/functions/test-tangle/transaction-trigger/transaction-trigger_14.spec.ts +++ b/packages/functions/test-tangle/transaction-trigger/transaction-trigger_14.spec.ts @@ -12,7 +12,7 @@ import dayjs from 'dayjs'; import { isEmpty } from 'lodash'; import { retryWallet } from '../../src/cron/wallet.cron'; import { AddressDetails } from '../../src/services/wallet/wallet.service'; -import { dateToTimestamp, serverTime } from '../../src/utils/dateTime.utils'; +import { serverTime } from '../../src/utils/dateTime.utils'; import { getRandomEthAddress } from '../../src/utils/wallet.utils'; import { wait } from '../../test/controls/common'; import { getWallet } from '../../test/set-up'; @@ -50,7 +50,7 @@ describe('Transaction trigger spec', () => { void: false, }, }; - const docRef = build5Db().doc(`${COL.TRANSACTION}/${billPayment.uid}`); + const docRef = build5Db().doc(COL.TRANSACTION, billPayment.uid); await docRef.create(billPayment); await wait(async () => { @@ -65,21 +65,19 @@ describe('Transaction trigger spec', () => { let retryWalletResult = await retryWallet(); expect(retryWalletResult.find((r) => r == billPayment.uid)).toBeUndefined(); docRef.update({ - 'payload.walletReference.processedOn': dateToTimestamp( - dayjs().subtract(4, 'minute').toDate(), - ), - 'payload.amount': MIN_IOTA_AMOUNT, + payload_walletReference_processedOn: dayjs().subtract(4, 'minute').toDate(), + payload_amount: MIN_IOTA_AMOUNT, }); retryWalletResult = await retryWallet(); expect(retryWalletResult.find((r) => r == billPayment.uid)).toBeDefined(); await wait(async () => { - const data = await docRef.get(); + const data = await docRef.get(); return data?.payload?.walletReference?.confirmed; }); - const billPaymentDocRef = build5Db().doc(`${COL.TRANSACTION}/${billPayment.uid}`); + const billPaymentDocRef = build5Db().doc(COL.TRANSACTION, billPayment.uid); await wait(async () => { billPayment = await billPaymentDocRef.get(); return billPayment.payload?.walletReference?.confirmed; diff --git a/packages/functions/test-tangle/transaction-trigger/transaction-trigger_15.spec.ts b/packages/functions/test-tangle/transaction-trigger/transaction-trigger_15.spec.ts index 6b9ad048e1..3da66e74cb 100644 --- a/packages/functions/test-tangle/transaction-trigger/transaction-trigger_15.spec.ts +++ b/packages/functions/test-tangle/transaction-trigger/transaction-trigger_15.spec.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { build5Db } from '@build-5/database'; -import { COL, MIN_IOTA_AMOUNT, Network, TangleRequestType, Transaction } from '@build-5/interfaces'; +import { COL, MIN_IOTA_AMOUNT, Network, TangleRequestType } from '@build-5/interfaces'; import dayjs from 'dayjs'; import { dateToTimestamp } from '../../src/utils/dateTime.utils'; import { wait } from '../../test/controls/common'; @@ -37,7 +37,7 @@ describe('Transaction trigger spec', () => { const snap = await build5Db() .collection(COL.TRANSACTION) .where('member', '==', address.bech32) - .get(); + .get(); return snap.length === 1 && snap[0].payload.invalidPayment; }); diff --git a/packages/functions/test-tangle/transaction-trigger/transaction-trigger_2.spec.ts b/packages/functions/test-tangle/transaction-trigger/transaction-trigger_2.spec.ts index 3f90b0bb17..5d36ca98e4 100644 --- a/packages/functions/test-tangle/transaction-trigger/transaction-trigger_2.spec.ts +++ b/packages/functions/test-tangle/transaction-trigger/transaction-trigger_2.spec.ts @@ -53,10 +53,10 @@ describe('Transaction trigger spec', () => { void: false, }, }; - const docRef = build5Db().doc(`${COL.TRANSACTION}/${billPayment.uid}`); + const docRef = build5Db().doc(COL.TRANSACTION, billPayment.uid); await docRef.create(billPayment); await wait(async () => { - const doc = await docRef.get(); + const doc = await docRef.get(); return doc?.payload?.walletReference?.confirmed; }); const outputs = await wallet.getOutputs(targetAddress.bech32, [], undefined); diff --git a/packages/functions/test-tangle/transaction-trigger/transaction-trigger_3.spec.ts b/packages/functions/test-tangle/transaction-trigger/transaction-trigger_3.spec.ts index 373567c76f..9d625733ec 100644 --- a/packages/functions/test-tangle/transaction-trigger/transaction-trigger_3.spec.ts +++ b/packages/functions/test-tangle/transaction-trigger/transaction-trigger_3.spec.ts @@ -60,7 +60,7 @@ describe('Transaction trigger spec', () => { void: false, }, }; - await build5Db().doc(`${COL.TRANSACTION}/${billPayment.uid}`).create(billPayment); + await build5Db().doc(COL.TRANSACTION, billPayment.uid).create(billPayment); await wait(async () => { const { nativeTokens } = await wallet.getBalance(targetAddress.bech32); @@ -72,9 +72,7 @@ describe('Transaction trigger spec', () => { }); await wait(async () => { - billPayment = ( - await build5Db().doc(`${COL.TRANSACTION}/${billPayment.uid}`).get() - ); + billPayment = await build5Db().doc(COL.TRANSACTION, billPayment.uid).get(); return billPayment.payload?.walletReference?.confirmed; }); }); diff --git a/packages/functions/test-tangle/transaction-trigger/transaction-trigger_4.spec.ts b/packages/functions/test-tangle/transaction-trigger/transaction-trigger_4.spec.ts index 6d767901f3..2371f6e09e 100644 --- a/packages/functions/test-tangle/transaction-trigger/transaction-trigger_4.spec.ts +++ b/packages/functions/test-tangle/transaction-trigger/transaction-trigger_4.spec.ts @@ -60,7 +60,7 @@ describe('Transaction trigger spec', () => { void: false, }, }; - await build5Db().doc(`${COL.TRANSACTION}/${billPayment.uid}`).create(billPayment); + await build5Db().doc(COL.TRANSACTION, billPayment.uid).create(billPayment); await wait(async () => { const { nativeTokens } = await wallet.getBalance(targetAddress.bech32); return Number(Object.values(nativeTokens)[0]) === 1; @@ -80,17 +80,15 @@ describe('Transaction trigger spec', () => { void: false, }, }; - await build5Db().doc(`${COL.TRANSACTION}/${credit.uid}`).create(credit); + await build5Db().doc(COL.TRANSACTION, credit.uid).create(credit); await wait(async () => { const { nativeTokens } = await wallet.getBalance(sourceAddress.bech32); return Number(Object.values(nativeTokens)[0]) === 1; }); await wait(async () => { - billPayment = ( - await build5Db().doc(`${COL.TRANSACTION}/${billPayment.uid}`).get() - ); - credit = await build5Db().doc(`${COL.TRANSACTION}/${credit.uid}`).get(); + billPayment = await build5Db().doc(COL.TRANSACTION, billPayment.uid).get(); + credit = await build5Db().doc(COL.TRANSACTION, credit.uid).get(); return ( billPayment.payload?.walletReference?.confirmed && credit.payload?.walletReference?.confirmed diff --git a/packages/functions/test-tangle/transaction-trigger/transaction-trigger_5.spec.ts b/packages/functions/test-tangle/transaction-trigger/transaction-trigger_5.spec.ts index 2fbff204c0..53430c4cce 100644 --- a/packages/functions/test-tangle/transaction-trigger/transaction-trigger_5.spec.ts +++ b/packages/functions/test-tangle/transaction-trigger/transaction-trigger_5.spec.ts @@ -12,7 +12,7 @@ import dayjs from 'dayjs'; import { isEmpty } from 'lodash'; import { retryWallet } from '../../src/cron/wallet.cron'; import { AddressDetails } from '../../src/services/wallet/wallet.service'; -import { dateToTimestamp, serverTime } from '../../src/utils/dateTime.utils'; +import { serverTime } from '../../src/utils/dateTime.utils'; import { getRandomEthAddress } from '../../src/utils/wallet.utils'; import { wait } from '../../test/controls/common'; import { getWallet } from '../../test/set-up'; @@ -50,7 +50,7 @@ describe('Transaction trigger spec', () => { void: false, }, }; - const docRef = build5Db().doc(`${COL.TRANSACTION}/${billPayment.uid}`); + const docRef = build5Db().doc(COL.TRANSACTION, billPayment.uid); await docRef.create(billPayment); await wait(async () => { @@ -61,24 +61,20 @@ describe('Transaction trigger spec', () => { let retryWalletResult = await retryWallet(); expect(retryWalletResult.find((r) => r == billPayment.uid)).toBeUndefined(); docRef.update({ - 'payload.walletReference.processedOn': dateToTimestamp( - dayjs().subtract(4, 'minute').toDate(), - ), - 'payload.amount': MIN_IOTA_AMOUNT, + payload_walletReference_processedOn: dayjs().subtract(4, 'minute').toDate(), + payload_amount: MIN_IOTA_AMOUNT, }); retryWalletResult = await retryWallet(); expect(retryWalletResult.find((r) => r == billPayment.uid)).toBeDefined(); await wait(async () => { - const data = await docRef.get(); + const data = await docRef.get(); return data?.payload?.walletReference?.confirmed; }); await wait(async () => { - billPayment = ( - await build5Db().doc(`${COL.TRANSACTION}/${billPayment.uid}`).get() - ); + billPayment = await build5Db().doc(COL.TRANSACTION, billPayment.uid).get(); return billPayment.payload?.walletReference?.confirmed; }); }); diff --git a/packages/functions/test-tangle/transaction-trigger/transaction-trigger_6.spec.ts b/packages/functions/test-tangle/transaction-trigger/transaction-trigger_6.spec.ts index f9cc74ca6d..5fa02fd3ea 100644 --- a/packages/functions/test-tangle/transaction-trigger/transaction-trigger_6.spec.ts +++ b/packages/functions/test-tangle/transaction-trigger/transaction-trigger_6.spec.ts @@ -48,10 +48,10 @@ describe('Transaction trigger spec', () => { void: false, }, }; - const docRef = build5Db().doc(`${COL.TRANSACTION}/${billPayment.uid}`); + const docRef = build5Db().doc(COL.TRANSACTION, billPayment.uid); await docRef.create(billPayment); await wait(async () => { - const doc = await docRef.get(); + const doc = await docRef.get(); return ( doc?.payload?.walletReference?.confirmed === true && !doc?.payload?.walletReference?.inProgress @@ -59,9 +59,7 @@ describe('Transaction trigger spec', () => { }); await wait(async () => { - billPayment = ( - await build5Db().doc(`${COL.TRANSACTION}/${billPayment.uid}`).get() - ); + billPayment = await build5Db().doc(COL.TRANSACTION, billPayment.uid).get(); return billPayment.payload?.walletReference?.confirmed; }); }, diff --git a/packages/functions/test-tangle/transaction-trigger/transaction-trigger_7.spec.ts b/packages/functions/test-tangle/transaction-trigger/transaction-trigger_7.spec.ts index ab674ed548..cac299f52c 100644 --- a/packages/functions/test-tangle/transaction-trigger/transaction-trigger_7.spec.ts +++ b/packages/functions/test-tangle/transaction-trigger/transaction-trigger_7.spec.ts @@ -53,23 +53,23 @@ describe('Transaction trigger spec', () => { void: false, }, }; - const docRef = build5Db().doc(`${COL.TRANSACTION}/${billPayment.uid}`); + const docRef = build5Db().doc(COL.TRANSACTION, billPayment.uid); return docRef.create(billPayment); }); await Promise.all(promises); const query = build5Db() .collection(COL.TRANSACTION) - .where('payload.sourceAddress', '==', sourceAddress.bech32); + .where('payload_sourceAddress', '==', sourceAddress.bech32); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); const allConfirmed = snap.reduce( (acc, act) => acc && (act?.payload?.walletReference?.confirmed || false), true, ); return snap.length === count && allConfirmed; }); - const snap = await query.get(); + const snap = await query.get(); for (const doc of snap) { expect(doc?.payload?.walletReference?.count).toBe(1); } diff --git a/packages/functions/test-tangle/transaction-trigger/transaction-trigger_8.spec.ts b/packages/functions/test-tangle/transaction-trigger/transaction-trigger_8.spec.ts index b788252c21..6b1f453507 100644 --- a/packages/functions/test-tangle/transaction-trigger/transaction-trigger_8.spec.ts +++ b/packages/functions/test-tangle/transaction-trigger/transaction-trigger_8.spec.ts @@ -51,7 +51,7 @@ describe('Transaction trigger spec', () => { void: false, }, }; - const docRef = build5Db().doc(`${COL.TRANSACTION}/${billPayment.uid}`); + const docRef = build5Db().doc(COL.TRANSACTION, billPayment.uid); return docRef.create(billPayment); }); await Promise.all(promises); @@ -59,9 +59,9 @@ describe('Transaction trigger spec', () => { await wait(async () => { const snap = await build5Db() .collection(COL.TRANSACTION) - .where('payload.sourceAddress', '==', sourceAddress.bech32) - .where('payload.walletReference.confirmed', '==', true) - .get(); + .where('payload_sourceAddress', '==', sourceAddress.bech32) + .where('payload_walletReference_confirmed', '==', true) + .get(); const countSum = snap.reduce( (acc, act) => acc + (act?.payload?.walletReference?.count || 0), 0, diff --git a/packages/functions/test-tangle/transaction-trigger/transaction-trigger_9.spec.ts b/packages/functions/test-tangle/transaction-trigger/transaction-trigger_9.spec.ts index e779ebdaf8..5015fbadc1 100644 --- a/packages/functions/test-tangle/transaction-trigger/transaction-trigger_9.spec.ts +++ b/packages/functions/test-tangle/transaction-trigger/transaction-trigger_9.spec.ts @@ -53,31 +53,23 @@ describe('Transaction trigger spec', () => { targetAddress.bech32, ); const batch = build5Db().batch(); - batch.create(build5Db().doc(`${COL.TRANSACTION}/${billPayment1.uid}`), billPayment1); - batch.create(build5Db().doc(`${COL.TRANSACTION}/${credit.uid}`), credit); - batch.create(build5Db().doc(`${COL.TRANSACTION}/${billPayment2.uid}`), billPayment2); + batch.create(build5Db().doc(COL.TRANSACTION, billPayment1.uid), billPayment1); + batch.create(build5Db().doc(COL.TRANSACTION, credit.uid), credit); + batch.create(build5Db().doc(COL.TRANSACTION, billPayment2.uid), billPayment2); await batch.commit(); await wait(async () => { - billPayment1 = ( - await build5Db().doc(`${COL.TRANSACTION}/${billPayment1.uid}`).get() - ); - billPayment2 = ( - await build5Db().doc(`${COL.TRANSACTION}/${billPayment2.uid}`).get() - ); - credit = await build5Db().doc(`${COL.TRANSACTION}/${credit.uid}`).get(); + billPayment1 = await build5Db().doc(COL.TRANSACTION, billPayment1.uid).get(); + billPayment2 = await build5Db().doc(COL.TRANSACTION, billPayment2.uid).get(); + credit = await build5Db().doc(COL.TRANSACTION, credit.uid).get(); return ( billPayment1?.payload?.walletReference?.confirmed && billPayment2?.payload?.walletReference?.confirmed && credit?.payload?.walletReference?.confirmed ); }); - billPayment1 = ( - await build5Db().doc(`${COL.TRANSACTION}/${billPayment1.uid}`).get() - ); - billPayment2 = ( - await build5Db().doc(`${COL.TRANSACTION}/${billPayment2.uid}`).get() - ); - credit = await build5Db().doc(`${COL.TRANSACTION}/${credit.uid}`).get(); + billPayment1 = await build5Db().doc(COL.TRANSACTION, billPayment1.uid).get(); + billPayment2 = await build5Db().doc(COL.TRANSACTION, billPayment2.uid).get(); + credit = await build5Db().doc(COL.TRANSACTION, credit.uid).get(); expect( dayjs(billPayment1?.payload?.walletReference?.processedOn?.toDate()).isBefore( diff --git a/packages/functions/test-tangle/web3/web3_1.spec.ts b/packages/functions/test-tangle/web3/web3_1.spec.ts index fbb71abd65..87d0f12fac 100644 --- a/packages/functions/test-tangle/web3/web3_1.spec.ts +++ b/packages/functions/test-tangle/web3/web3_1.spec.ts @@ -9,23 +9,17 @@ import { SUB_COL, Token, TokenStatus, + Transaction, + WEN_FUNC, } from '@build-5/interfaces'; import { uploadMediaToWeb3 } from '../../src/cron/media.cron'; -import { mintTokenOrder } from '../../src/runtime/firebase/token/minting'; -import { serverTime } from '../../src/utils/dateTime.utils'; +import { dateToTimestamp, serverTime } from '../../src/utils/dateTime.utils'; import * as wallet from '../../src/utils/wallet.utils'; -import { - createMember, - createSpace, - getRandomSymbol, - mockWalletReturnValue, - wait, -} from '../../test/controls/common'; -import { MEDIA, testEnv } from '../../test/set-up'; +import { getRandomSymbol, wait } from '../../test/controls/common'; +import { MEDIA, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { CollectionMintHelper } from '../collection-minting/Helper'; import { requestFundsFromFaucet } from '../faucet'; -let walletSpy: any; const network = Network.RMS; const totalSupply = 1500; @@ -45,62 +39,61 @@ const saveToken = async (space: string, guardian: string, member: string) => { status: TokenStatus.AVAILABLE, access: 0, icon: MEDIA, - }; - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).set(token); + } as Token; + await build5Db().doc(COL.TOKEN, token.uid).create(token); await build5Db() - .doc(`${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${member}`) - .set({ tokenOwned: 1000 }); + .doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, member) + .upsert({ tokenOwned: 1000 }); return token; }; describe('Web3 cron test', () => { - const collectionHelper = new CollectionMintHelper(); + const h = new CollectionMintHelper(); beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); await cleanupPendingUploads(); }); it('Should upload collection&nft media on mint', async () => { - await collectionHelper.beforeAll(); - await collectionHelper.beforeEach(); + await h.beforeAll(); + await h.beforeEach(); const count = 5; - await build5Db() - .doc(`${COL.COLLECTION}/${collectionHelper.collection}`) - .update({ total: count }); + await build5Db().doc(COL.COLLECTION, h.collection).update({ total: count }); const promises = Array.from(Array(count)).map(() => { - const nft = collectionHelper.createDummyNft( - collectionHelper.collection!, - collectionHelper.getRandomDescrptiron(), - ); + const nft = h.createDummyNft(h.collection!, h.getRandomDescrptiron()); return build5Db() - .doc(`${COL.NFT}/${nft.uid}`) - .create({ ...nft, project: SOON_PROJECT_ID }); + .doc(COL.NFT, nft.uid) + .create({ + ...nft, + availableFrom: dateToTimestamp(nft.availableFrom), + project: SOON_PROJECT_ID, + } as any); }); await Promise.all(promises); - await collectionHelper.mintCollection(); + await h.mintCollection(); await uploadMediaToWeb3(); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${collectionHelper.collection}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, h.collection); const collection = await collectionDocRef.get(); expect(collection.mintingData?.nftMediaToUpload).toBe(0); + expect(collection.mediaStatus).toBe(MediaStatus.UPLOADED); }); it('Should upload token media on mint', async () => { - const guardianId = await createMember(walletSpy); - const member = await createMember(walletSpy); - const guardian = await build5Db().doc(`${COL.MEMBER}/${guardianId}`).get(); - const space = await createSpace(walletSpy, guardian.uid); + const guardianId = await testEnv.createMember(); + const member = await testEnv.createMember(); + const guardian = await build5Db().doc(COL.MEMBER, guardianId).get(); + const space = await testEnv.createSpace(guardian.uid); let token = await saveToken(space.uid, guardian.uid, member); - mockWalletReturnValue(walletSpy, guardian.uid, { token: token.uid, network }); - const order = await testEnv.wrap(mintTokenOrder)({}); + mockWalletReturnValue(guardian.uid, { token: token.uid, network }); + const order = await testEnv.wrap(WEN_FUNC.mintTokenOrder); await requestFundsFromFaucet(network, order.payload.targetAddress, order.payload.amount); - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${token.uid}`); + const tokenDocRef = build5Db().doc(COL.TOKEN, token.uid); await wait(async () => { - const snap = await tokenDocRef.get(); + const snap = await tokenDocRef.get(); return snap?.status === TokenStatus.MINTED; }); @@ -121,14 +114,16 @@ describe('Web3 cron test', () => { const cleanupPendingUploads = async () => { for (const col of [COL.TOKEN, COL.NFT, COL.COLLECTION]) { - const snap = await pendingUploadsQuery(col).get>(); + const snap = await pendingUploadsQuery(col as COL.TOKEN).get(); const promises = snap.map((d) => { - const docRef = build5Db().doc(`${col}/${d.uid}`); - return docRef.update({ mediaStatus: build5Db().deleteField() }); + const docRef = build5Db().doc(col as COL.TOKEN, d.uid); + return docRef.update({ mediaStatus: undefined }); }); await Promise.all(promises); } }; -const pendingUploadsQuery = (col: COL) => - build5Db().collection(col).where('mediaStatus', '==', MediaStatus.PENDING_UPLOAD); +const pendingUploadsQuery = (col: COL.TOKEN | COL.NFT | COL.COLLECTION) => + build5Db() + .collection(col as COL.TOKEN) + .where('mediaStatus', '==', MediaStatus.PENDING_UPLOAD); diff --git a/packages/functions/test-tangle/web3/web3_2.spec.ts b/packages/functions/test-tangle/web3/web3_2.spec.ts index 2c276d91b5..42f370749c 100644 --- a/packages/functions/test-tangle/web3/web3_2.spec.ts +++ b/packages/functions/test-tangle/web3/web3_2.spec.ts @@ -2,17 +2,14 @@ import { build5Db } from '@build-5/database'; import { COL, Collection, MediaStatus, Space } from '@build-5/interfaces'; import { uploadMediaToWeb3 } from '../../src/cron/media.cron'; import { collectionToIpfsMetadata, nftToIpfsMetadata } from '../../src/utils/car.utils'; -import * as wallet from '../../src/utils/wallet.utils'; -import { createMember, createSpace, wait } from '../../test/controls/common'; +import { wait } from '../../test/controls/common'; +import { testEnv } from '../../test/set-up'; import { CollectionMintHelper } from '../collection-minting/Helper'; -let walletSpy: any; - describe('Web3 cron test', () => { const collectionHelper = new CollectionMintHelper(); beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); await cleanupPendingUploads(); }); @@ -20,7 +17,7 @@ describe('Web3 cron test', () => { await collectionHelper.beforeAll(); await collectionHelper.beforeEach(); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${collectionHelper.collection}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, collectionHelper.collection); const collection = await collectionDocRef.get(); const nft = collectionHelper.createDummyNft(collection.uid, collectionHelper.space!.uid) as any; @@ -47,12 +44,12 @@ describe('Web3 cron test', () => { }); it('Should upload space media', async () => { - const guardian = await createMember(walletSpy); - let space = await createSpace(walletSpy, guardian); + const guardian = await testEnv.createMember(); + let space = await testEnv.createSpace(guardian); await uploadMediaToWeb3(); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${space.uid}`); + const spaceDocRef = build5Db().doc(COL.SPACE, space.uid); await wait(async () => { space = await spaceDocRef.get(); return space.mediaStatus === MediaStatus.UPLOADED; @@ -66,14 +63,16 @@ describe('Web3 cron test', () => { const cleanupPendingUploads = async () => { for (const col of [COL.TOKEN, COL.NFT, COL.COLLECTION]) { - const snap = await pendingUploadsQuery(col).get>(); + const snap = await pendingUploadsQuery(col).get(); const promises = snap.map((d) => { - const docRef = build5Db().doc(`${col}/${d.uid}`); - return docRef.update({ mediaStatus: build5Db().deleteField() }); + const docRef = build5Db().doc(col as COL.TOKEN, d.uid); + return docRef.update({ mediaStatus: undefined }); }); await Promise.all(promises); } }; const pendingUploadsQuery = (col: COL) => - build5Db().collection(col).where('mediaStatus', '==', MediaStatus.PENDING_UPLOAD); + build5Db() + .collection(col as COL.TOKEN) + .where('mediaStatus', '==', MediaStatus.PENDING_UPLOAD); diff --git a/packages/functions/test-tangle/web3/web3_3.spec.ts b/packages/functions/test-tangle/web3/web3_3.spec.ts index 9648a2c315..cfdc06f447 100644 --- a/packages/functions/test-tangle/web3/web3_3.spec.ts +++ b/packages/functions/test-tangle/web3/web3_3.spec.ts @@ -1,28 +1,23 @@ import { build5Db } from '@build-5/database'; -import { COL, MediaStatus, Space } from '@build-5/interfaces'; +import { COL, MediaStatus, Space, WEN_FUNC } from '@build-5/interfaces'; import { uploadMediaToWeb3 } from '../../src/cron/media.cron'; -import { updateSpace } from '../../src/runtime/firebase/space'; -import * as wallet from '../../src/utils/wallet.utils'; -import { createMember, createSpace, mockWalletReturnValue, wait } from '../../test/controls/common'; -import { MEDIA, testEnv } from '../../test/set-up'; - -let walletSpy: any; +import { wait } from '../../test/controls/common'; +import { MEDIA, mockWalletReturnValue, testEnv } from '../../test/set-up'; describe('Web3 cron test', () => { beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); await cleanupPendingUploads(); }); it('Should upload space media after edit vote', async () => { - const guardian = await createMember(walletSpy); - let space = await createSpace(walletSpy, guardian); + const guardian = await testEnv.createMember(); + let space = await testEnv.createSpace(guardian); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${space.uid}`); + const spaceDocRef = build5Db().doc(COL.SPACE, space.uid); await spaceDocRef.update({ bannerUrl: '' }); - mockWalletReturnValue(walletSpy, guardian, { uid: space?.uid, bannerUrl: MEDIA }); - await testEnv.wrap(updateSpace)({}); + mockWalletReturnValue(guardian, { uid: space?.uid, bannerUrl: MEDIA }); + await testEnv.wrap(WEN_FUNC.updateSpace); await wait(async () => { space = await spaceDocRef.get(); @@ -38,11 +33,11 @@ describe('Web3 cron test', () => { }); it('Should fail first then retry', async () => { - const guardian = await createMember(walletSpy); - let space = await createSpace(walletSpy, guardian); + const guardian = await testEnv.createMember(); + let space = await testEnv.createSpace(guardian); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${space.uid}`); - await spaceDocRef.update({ bannerUrl: 'asd' }); + const spaceDocRef = build5Db().doc(COL.SPACE, space.uid); + await spaceDocRef.update({ bannerUrl: 'wrong-banner-url' }); await uploadMediaToWeb3(); @@ -58,11 +53,11 @@ describe('Web3 cron test', () => { }); it('Should fail 5 times, then set to error', async () => { - const guardian = await createMember(walletSpy); - let space = await createSpace(walletSpy, guardian); + const guardian = await testEnv.createMember(); + let space = await testEnv.createSpace(guardian); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${space.uid}`); - await spaceDocRef.update({ bannerUrl: 'asd' }); + const spaceDocRef = build5Db().doc(COL.SPACE, space.uid); + await spaceDocRef.update({ bannerUrl: 'wrong-banner-url' }); for (let i = 0; i < 6; ++i) { await uploadMediaToWeb3(); @@ -79,14 +74,16 @@ describe('Web3 cron test', () => { const cleanupPendingUploads = async () => { for (const col of [COL.TOKEN, COL.NFT, COL.COLLECTION]) { - const snap = await pendingUploadsQuery(col).get>(); + const snap = await pendingUploadsQuery(col).get(); const promises = snap.map((d) => { - const docRef = build5Db().doc(`${col}/${d.uid}`); - return docRef.update({ mediaStatus: build5Db().deleteField() }); + const docRef = build5Db().doc(col as COL.TOKEN, d.uid); + return docRef.update({ mediaStatus: undefined }); }); await Promise.all(promises); } }; const pendingUploadsQuery = (col: COL) => - build5Db().collection(col).where('mediaStatus', '==', MediaStatus.PENDING_UPLOAD); + build5Db() + .collection(col as COL.TOKEN) + .where('mediaStatus', '==', MediaStatus.PENDING_UPLOAD); diff --git a/packages/functions/test-tangle/withdraw-deposit-nft/Helper.ts b/packages/functions/test-tangle/withdraw-deposit-nft/Helper.ts index 84c5cd0b93..5670b45250 100644 --- a/packages/functions/test-tangle/withdraw-deposit-nft/Helper.ts +++ b/packages/functions/test-tangle/withdraw-deposit-nft/Helper.ts @@ -22,6 +22,7 @@ import { TransactionPayloadType, TransactionType, UnsoldMintingOptions, + WEN_FUNC, } from '@build-5/interfaces'; import { AddressUnlockCondition, @@ -34,14 +35,6 @@ import { } from '@iota/sdk'; import dayjs from 'dayjs'; import { cloneDeep } from 'lodash'; -import { createCollection, mintCollection } from '../../src/runtime/firebase/collection/index'; -import { - createNft, - orderNft, - setForSaleNft, - withdrawNft, -} from '../../src/runtime/firebase/nft/index'; -import { claimSpace } from '../../src/runtime/firebase/space'; import { NftWallet } from '../../src/services/wallet/NftWallet'; import { MnemonicService } from '../../src/services/wallet/mnemonic'; import { Wallet } from '../../src/services/wallet/wallet'; @@ -49,49 +42,39 @@ import { AddressDetails } from '../../src/services/wallet/wallet.service'; import { getAddress } from '../../src/utils/address.utils'; import { createUnlock, packEssence, submitBlock } from '../../src/utils/block.utils'; import { serverTime } from '../../src/utils/dateTime.utils'; -import * as wallet from '../../src/utils/wallet.utils'; import { getRandomEthAddress } from '../../src/utils/wallet.utils'; -import { - createMember as createMemberTest, - createSpace, - mockWalletReturnValue, - submitMilestoneFunc, - wait, -} from '../../test/controls/common'; -import { MEDIA, getWallet, testEnv } from '../../test/set-up'; +import { submitMilestoneFunc, wait } from '../../test/controls/common'; +import { MEDIA, getWallet, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; export class Helper { public network = Network.RMS; - public collection: string | undefined; - public guardian: string | undefined; - public space: Space | undefined; - public walletService: Wallet | undefined; - public walletSpy: any; - public nft: Nft | undefined; - public guardianAddress: AddressDetails | undefined; - public royaltySpace: Space | undefined; + public collection = ''; + public guardian = ''; + public space: Space = {} as any; + public walletService: Wallet = {} as any; + public nft: Nft = {} as any; + public guardianAddress: AddressDetails = {} as any; + public royaltySpace: Space = {} as any; public beforeAll = async () => { - this.walletSpy = jest.spyOn(wallet, 'decodeAuth'); this.walletService = await getWallet(this.network); }; public beforeEach = async () => { - this.guardian = await createMemberTest(this.walletSpy); - this.space = await createSpace(this.walletSpy, this.guardian!); - this.royaltySpace = await createSpace(this.walletSpy, this.guardian!); + this.guardian = await testEnv.createMember(); + this.space = await testEnv.createSpace(this.guardian); + this.royaltySpace = await testEnv.createSpace(this.guardian); mockWalletReturnValue( - this.walletSpy, this.guardian!, this.createDummyCollection(this.space!.uid, this.royaltySpace!.uid), ); - this.collection = (await testEnv.wrap(createCollection)({})).uid; + this.collection = (await testEnv.wrap(WEN_FUNC.createCollection)).uid; - await build5Db().doc(`${COL.COLLECTION}/${this.collection}`).update({ approved: true }); + await build5Db().doc(COL.COLLECTION, this.collection).update({ approved: true }); - const guardianDocRef = build5Db().doc(`${COL.MEMBER}/${this.guardian}`); + const guardianDocRef = build5Db().doc(COL.MEMBER, this.guardian); const guardianData = await guardianDocRef.get(); const guardianBech32 = getAddress(guardianData, this.network!); this.guardianAddress = await this.walletService?.getAddressDetails(guardianBech32)!; @@ -100,31 +83,31 @@ export class Helper { public createAndOrderNft = async () => { let nft: any = this.createDummyNft(this.collection!); delete nft.uid; - mockWalletReturnValue(this.walletSpy, this.guardian!, nft); - nft = await testEnv.wrap(createNft)({}); + mockWalletReturnValue(this.guardian!, nft); + nft = await testEnv.wrap(WEN_FUNC.createNft); await build5Db() - .doc(`${COL.NFT}/${nft.uid}`) + .doc(COL.NFT, nft.uid) .update({ availableFrom: dayjs().subtract(1, 'h').toDate() }); - mockWalletReturnValue(this.walletSpy, this.guardian!, { + mockWalletReturnValue(this.guardian!, { collection: this.collection, nft: nft.uid, }); - const order = await testEnv.wrap(orderNft)({}); + const order = await testEnv.wrap(WEN_FUNC.orderNft); await submitMilestoneFunc(order); - this.nft = await build5Db().doc(`${COL.NFT}/${nft.uid}`).get(); + this.nft = await build5Db().doc(COL.NFT, nft.uid).get(); return this.nft; }; public mintCollection = async (expiresAt?: Timestamp) => { - mockWalletReturnValue(this.walletSpy, this.guardian!, { + mockWalletReturnValue(this.guardian!, { collection: this.collection!, network: this.network, unsoldMintingOptions: UnsoldMintingOptions.KEEP_PRICE, }); - const collectionMintOrder = await testEnv.wrap(mintCollection)({}); + const collectionMintOrder = await testEnv.wrap(WEN_FUNC.mintCollection); await requestFundsFromFaucet( this.network, this.guardianAddress!.bech32, @@ -133,13 +116,13 @@ export class Helper { ); await this.walletService!.send( this.guardianAddress!, - collectionMintOrder.payload.targetAddress, - collectionMintOrder.payload.amount, + collectionMintOrder.payload.targetAddress!, + collectionMintOrder.payload.amount!, {}, ); await MnemonicService.store(this.guardianAddress!.bech32, this.guardianAddress!.mnemonic); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${this.collection}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, this.collection!); await wait(async () => { const data = await collectionDocRef.get(); return data.status === CollectionStatus.MINTED; @@ -156,7 +139,7 @@ export class Helper { await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.MINT_COLLECTION) - .where('payload.type', '==', TransactionPayloadType.SEND_ALIAS_TO_GUARDIAN) + .where('payload_type', '==', TransactionPayloadType.SEND_ALIAS_TO_GUARDIAN) .where('member', '==', this.guardian) .get() ).map((d) => d); @@ -167,8 +150,8 @@ export class Helper { public updateGuardianAddress = (address: NetworkAddress) => build5Db() - .doc(`${COL.MEMBER}/${this.guardian}`) - .update({ [`validatedAddress.${this.network}`]: address }); + .doc(COL.MEMBER, this.guardian) + .update({ [`${this.network}Address`]: address }); public sendNftToAddress = async ( sourceAddress: AddressDetails, @@ -188,11 +171,11 @@ export class Helper { payload: { sourceAddress: sourceAddress.bech32, targetAddress: targetAddressBech32, - expiresOn: expiresOn || null, + expiresOn: expiresOn || undefined, nftId: nftId || '', }, }; - await build5Db().doc(`${COL.TRANSACTION}/${order.uid}`).create(order); + await build5Db().doc(COL.TRANSACTION, order.uid).create(order); return order.uid; } @@ -245,37 +228,33 @@ export class Helper { const unlocks = [await createUnlock(essence, sourceAddress), new ReferenceUnlock(0)]; const blockId = await submitBlock(this.walletService!, essence, unlocks); - await build5Db().doc(`blocks/${blockId}`).create({ blockId }); + await testEnv.createBlock(blockId); return blockId; }; public withdrawNftAndAwait = async (nft: string) => { - mockWalletReturnValue(this.walletSpy, this.guardian!, { nft }); - await testEnv.wrap(withdrawNft)({}); + mockWalletReturnValue(this.guardian!, { nft }); + await testEnv.wrap(WEN_FUNC.withdrawNft); await wait(async () => { const snap = await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.WITHDRAW_NFT) - .where('payload.nft', '==', nft) - .get(); + .where('payload_nft', '==', nft) + .get(); return snap[0]?.payload?.walletReference?.confirmed; }); }; public setAvailableForAuction = async () => { - mockWalletReturnValue(this.walletSpy, this.guardian!, this.dummyAuctionData(this.nft!.uid)); - await testEnv.wrap(setForSaleNft)({}); - await wait( - async () => (await build5Db().doc(`${COL.NFT}/${this.nft!.uid}`).get())?.available === 3, - ); + mockWalletReturnValue(this.guardian!, this.dummyAuctionData(this.nft!.uid)); + await testEnv.wrap(WEN_FUNC.setForSaleNft); + await wait(async () => (await build5Db().doc(COL.NFT, this.nft!.uid).get())?.available === 3); }; public setAvailableForSale = async () => { - mockWalletReturnValue(this.walletSpy, this.guardian!, this.dummySaleData(this.nft!.uid)); - await testEnv.wrap(setForSaleNft)({}); - await wait( - async () => (await build5Db().doc(`${COL.NFT}/${this.nft!.uid}`).get())?.available === 1, - ); + mockWalletReturnValue(this.guardian!, this.dummySaleData(this.nft!.uid)); + await testEnv.wrap(WEN_FUNC.setForSaleNft); + await wait(async () => (await build5Db().doc(COL.NFT, this.nft!.uid).get())?.available === 1); }; public createDummyCollection = (space: string, royaltiesSpace: string) => ({ @@ -333,17 +312,17 @@ export class Helper { }); public claimSpaceFunc = async (spaceId: string) => { - mockWalletReturnValue(this.walletSpy, this.guardian!, { uid: spaceId }); - const order = await testEnv.wrap(claimSpace)({}); + mockWalletReturnValue(this.guardian!, { uid: spaceId }); + const order = await testEnv.wrap(WEN_FUNC.claimSpace); await this.walletService!.send( this.guardianAddress!, - order.payload.targetAddress, - order.payload.amount, + order.payload.targetAddress!, + order.payload.amount!, {}, ); await MnemonicService.store(this.guardianAddress!.bech32, this.guardianAddress!.mnemonic); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${spaceId}`); + const spaceDocRef = build5Db().doc(COL.SPACE, spaceId); await wait(async () => { const space = await spaceDocRef.get(); return space.claimed || false; @@ -354,77 +333,87 @@ export class Helper { expect(space.totalMembers).toBe(1); expect(space.totalGuardians).toBe(1); - const spaceMemberDocRef = spaceDocRef.collection(SUB_COL.MEMBERS).doc(this.guardian!); + const spaceMemberDocRef = build5Db().doc(COL.SPACE, spaceId, SUB_COL.MEMBERS, this.guardian!); const spaceMember = await spaceMemberDocRef.get(); expect(spaceMember !== undefined).toBe(true); - const spaceGuardianDocRef = spaceDocRef.collection(SUB_COL.GUARDIANS).doc(this.guardian!); + const spaceGuardianDocRef = build5Db().doc( + COL.SPACE, + spaceId, + SUB_COL.GUARDIANS, + this.guardian!, + ); const spaceGuardian = await spaceGuardianDocRef.get(); expect(spaceGuardian !== undefined).toBe(true); - const guardianDocRef = build5Db().doc(`${COL.MEMBER}/${this.guardian}`); + const guardianDocRef = build5Db().doc(COL.MEMBER, this.guardian); const guardianData = await guardianDocRef.get(); expect(guardianData.spaces![space.uid].isMember).toBe(true); }; public isInvalidPayment = async (paymentId: string) => { - const paymentDocRef = build5Db().doc(`${COL.TRANSACTION}/${paymentId}`); - const payment = (await paymentDocRef.get())!; + const paymentDocRef = build5Db().doc(COL.TRANSACTION, paymentId); + const payment = (await paymentDocRef.get())!; expect(payment.payload.invalidPayment).toBe(true); }; public mintWithCustomNftCID = async (func: (ipfsMedia: string) => string) => { let nft = await this.createAndOrderNft(); - const nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); + const nftDocRef = build5Db().doc(COL.NFT, nft.uid); - mockWalletReturnValue(this.walletSpy, this.guardian!, { + mockWalletReturnValue(this.guardian!, { collection: this.collection!, network: this.network, unsoldMintingOptions: UnsoldMintingOptions.KEEP_PRICE, }); - const collectionMintOrder = await testEnv.wrap(mintCollection)({}); + const collectionMintOrder = await testEnv.wrap(WEN_FUNC.mintCollection); await requestFundsFromFaucet(this.network, this.guardianAddress!.bech32, 10 * MIN_IOTA_AMOUNT); await this.walletService!.send( this.guardianAddress!, - collectionMintOrder.payload.targetAddress, - collectionMintOrder.payload.amount, + collectionMintOrder.payload.targetAddress!, + collectionMintOrder.payload.amount!, {}, ); await MnemonicService.store(this.guardianAddress!.bech32, this.guardianAddress!.mnemonic); - const unsubscribe = nftDocRef.onSnapshot(async (doc) => { - const nft = doc as Nft; - const ipfsMedia = func(nft.ipfsMedia || ''); - if (nft.mediaStatus === MediaStatus.PENDING_UPLOAD && nft.ipfsMedia !== ipfsMedia) { - await nftDocRef.update({ ipfsMedia }); - } - }); + await wait( + async () => { + const nft = await nftDocRef.get(); + const ipfsMedia = func(nft.ipfsMedia || ''); + if (nft.mediaStatus === MediaStatus.PENDING_UPLOAD && nft.ipfsMedia !== ipfsMedia) { + await nftDocRef.update({ ipfsMedia }); + } + return nft.mediaStatus === MediaStatus.PENDING_UPLOAD && nft.ipfsMedia !== ipfsMedia; + }, + undefined, + 100, + ); + await wait(async () => { const nft = await nftDocRef.get(); return nft.mediaStatus === MediaStatus.PENDING_UPLOAD; }); - unsubscribe(); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${this.collection}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, this.collection); await wait(async () => { const collection = await collectionDocRef.get(); return collection.status === CollectionStatus.MINTED; }); - mockWalletReturnValue(this.walletSpy, this.guardian!, { nft: nft.uid }); - await testEnv.wrap(withdrawNft)({}); + mockWalletReturnValue(this.guardian!, { nft: nft.uid }); + await testEnv.wrap(WEN_FUNC.withdrawNft); let query = build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.WITHDRAW_NFT) - .where('payload.nft', '==', nft.uid); + .where('payload_nft', '==', nft.uid); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); nft = await nftDocRef.get(); await nftDocRef.delete(); - await build5Db().doc(`${COL.COLLECTION}/${nft.collection}`).delete(); + await build5Db().doc(COL.COLLECTION, nft.collection).delete(); }; } diff --git a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_10_1.spec.ts b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_10_1.spec.ts index bae5e75b56..d63ba582e8 100644 --- a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_10_1.spec.ts +++ b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_10_1.spec.ts @@ -1,9 +1,8 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { build5Db } from '@build-5/database'; -import { COL, Transaction, TransactionType } from '@build-5/interfaces'; -import { depositNft } from '../../src/runtime/firebase/nft'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { COL, Transaction, TransactionType, WEN_FUNC } from '@build-5/interfaces'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; describe('Collection minting', () => { @@ -24,9 +23,9 @@ describe('Collection minting', () => { .join(''), ); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { network: helper.network }); - const depositOrder = await testEnv.wrap(depositNft)({}); - await helper.sendNftToAddress(helper.guardianAddress!, depositOrder.payload.targetAddress); + mockWalletReturnValue(helper.guardian!, { network: helper.network }); + const depositOrder = await testEnv.wrap(WEN_FUNC.depositNft); + await helper.sendNftToAddress(helper.guardianAddress!, depositOrder.payload.targetAddress!); const query = build5Db() .collection(COL.TRANSACTION) diff --git a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_10_2.spec.ts b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_10_2.spec.ts index 8602fc71bd..9282bd5532 100644 --- a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_10_2.spec.ts +++ b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_10_2.spec.ts @@ -1,9 +1,8 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { build5Db } from '@build-5/database'; -import { COL, Transaction, TransactionType } from '@build-5/interfaces'; -import { depositNft } from '../../src/runtime/firebase/nft'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { COL, Transaction, TransactionType, WEN_FUNC } from '@build-5/interfaces'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; const HUGE_CID = 'bafybeidxlcm7vs3uh3afk6tzye3rdzjjgaqrmj6fzaz3jf23e66f35dkce'; @@ -23,9 +22,9 @@ describe('Collection minting', () => { it.skip('Should credit, ipfs max size', async () => { await helper.mintWithCustomNftCID(() => HUGE_CID); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { network: helper.network }); - const depositOrder = await testEnv.wrap(depositNft)({}); - await helper.sendNftToAddress(helper.guardianAddress!, depositOrder.payload.targetAddress); + mockWalletReturnValue(helper.guardian!, { network: helper.network }); + const depositOrder = await testEnv.wrap(WEN_FUNC.depositNft); + await helper.sendNftToAddress(helper.guardianAddress!, depositOrder.payload.targetAddress!); const query = build5Db() .collection(COL.TRANSACTION) diff --git a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_10_3.spec.ts b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_10_3.spec.ts index 3ccbfa210a..584cb4c291 100644 --- a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_10_3.spec.ts +++ b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_10_3.spec.ts @@ -1,9 +1,8 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { build5Db } from '@build-5/database'; -import { COL, Transaction, TransactionType } from '@build-5/interfaces'; -import { depositNft } from '../../src/runtime/firebase/nft'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { COL, Transaction, TransactionType, WEN_FUNC } from '@build-5/interfaces'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; describe('Collection minting', () => { @@ -22,9 +21,9 @@ describe('Collection minting', () => { () => 'bafybeidzgwp4grz4a3bze26xaouzts4jkkovz6idpu456n3dy36gpe6qem', ); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { network: helper.network }); - const depositOrder = await testEnv.wrap(depositNft)({}); - await helper.sendNftToAddress(helper.guardianAddress!, depositOrder.payload.targetAddress); + mockWalletReturnValue(helper.guardian!, { network: helper.network }); + const depositOrder = await testEnv.wrap(WEN_FUNC.depositNft); + await helper.sendNftToAddress(helper.guardianAddress!, depositOrder.payload.targetAddress!); const query = build5Db() .collection(COL.TRANSACTION) diff --git a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_11.spec.ts b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_11.spec.ts index 268cec4af3..0eb368ea2f 100644 --- a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_11.spec.ts +++ b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_11.spec.ts @@ -1,10 +1,16 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { build5Db } from '@build-5/database'; -import { COL, Collection, Nft, Space, Transaction, TransactionType } from '@build-5/interfaces'; -import { depositNft, withdrawNft } from '../../src/runtime/firebase/nft/index'; -import { claimSpace } from '../../src/runtime/firebase/space'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { + COL, + Collection, + Nft, + Space, + Transaction, + TransactionType, + WEN_FUNC, +} from '@build-5/interfaces'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; describe('Nft depositing', () => { @@ -18,16 +24,16 @@ describe('Nft depositing', () => { }); const withdrawNftFunc = async (nftId: string) => { - const nftDocRef = build5Db().doc(`${COL.NFT}/${nftId}`); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { nft: nftId }); - await testEnv.wrap(withdrawNft)({}); + const nftDocRef = build5Db().doc(COL.NFT, nftId); + mockWalletReturnValue(helper.guardian!, { nft: nftId }); + await testEnv.wrap(WEN_FUNC.withdrawNft); const query = build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.WITHDRAW_NFT) - .where('payload.nft', '==', nftId); + .where('payload_nft', '==', nftId); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); return await nftDocRef.get(); @@ -42,20 +48,20 @@ describe('Nft depositing', () => { nft1 = await withdrawNftFunc(nft1.uid); nft2 = await withdrawNftFunc(nft2.uid); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${nft1.collection}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, nft1.collection); collection = await collectionDocRef.get(); }); it('Should deposit 2 nfts minted outside build-5', async () => { - await build5Db().doc(`${COL.NFT}/${nft1.uid}`).delete(); - await build5Db().doc(`${COL.NFT}/${nft2.uid}`).delete(); - await build5Db().doc(`${COL.COLLECTION}/${collection.uid}`).delete(); + await build5Db().doc(COL.NFT, nft1.uid).delete(); + await build5Db().doc(COL.NFT, nft2.uid).delete(); + await build5Db().doc(COL.COLLECTION, collection.uid).delete(); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { network: helper.network }); - let depositOrder = await testEnv.wrap(depositNft)({}); + mockWalletReturnValue(helper.guardian!, { network: helper.network }); + let depositOrder = await testEnv.wrap(WEN_FUNC.depositNft); await helper.sendNftToAddress( helper.guardianAddress!, - depositOrder.payload.targetAddress, + depositOrder.payload.targetAddress!, undefined, nft1.mintingData!.nftId, ); @@ -66,29 +72,29 @@ describe('Nft depositing', () => { return snap.length === 1; }); - const nft1DocRef = build5Db().doc(`${COL.NFT}/${nft1.mintingData!.nftId}`); + const nft1DocRef = build5Db().doc(COL.NFT, nft1.mintingData!.nftId!); nft1 = await nft1DocRef.get(); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { uid: nft1.space }); - const order = await testEnv.wrap(claimSpace)({}); + mockWalletReturnValue(helper.guardian!, { uid: nft1.space }); + const order = await testEnv.wrap(WEN_FUNC.claimSpace); await helper.walletService!.send( helper.guardianAddress!, - order.payload.targetAddress, - order.payload.amount, + order.payload.targetAddress!, + order.payload.amount!, {}, ); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${nft1.space}`); + const spaceDocRef = build5Db().doc(COL.SPACE, nft1.space); await wait(async () => { const space = await spaceDocRef.get(); return space.claimed || false; }); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { network: helper.network }); - depositOrder = await testEnv.wrap(depositNft)({}); + mockWalletReturnValue(helper.guardian!, { network: helper.network }); + depositOrder = await testEnv.wrap(WEN_FUNC.depositNft); await helper.sendNftToAddress( helper.guardianAddress!, - depositOrder.payload.targetAddress, + depositOrder.payload.targetAddress!, undefined, nft2.mintingData!.nftId, ); @@ -98,7 +104,7 @@ describe('Nft depositing', () => { return snap.length === 2; }); - const nft2DocRef = build5Db().doc(`${COL.NFT}/${nft2.mintingData!.nftId}`); + const nft2DocRef = build5Db().doc(COL.NFT, nft2.mintingData!.nftId!); nft2 = await nft2DocRef.get(); expect(nft1.collection).toBe(nft2.collection); diff --git a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_12_a.spec.ts b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_12_a.spec.ts index df6d756bd4..a0862309f4 100644 --- a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_12_a.spec.ts +++ b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_12_a.spec.ts @@ -6,6 +6,7 @@ import { Network, Transaction, TransactionType, + WEN_FUNC, WenError, } from '@build-5/interfaces'; import { @@ -20,14 +21,13 @@ import { Utils, } from '@iota/sdk'; import { cloneDeep } from 'lodash'; -import { depositNft } from '../../src/runtime/firebase/nft'; import { NftWallet } from '../../src/services/wallet/NftWallet'; import { AddressDetails } from '../../src/services/wallet/wallet.service'; import { packBasicOutput } from '../../src/utils/basic-output.utils'; import { createUnlock, indexToString, packEssence, submitBlock } from '../../src/utils/block.utils'; import { EMPTY_NFT_ID, createNftOutput } from '../../src/utils/collection-minting-utils/nft.utils'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { getWallet, testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { getWallet, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitLedgerInclusionState, requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -49,7 +49,7 @@ describe('Collection minting', () => { .where('member', '==', helper.guardian) .where('type', '==', TransactionType.CREDIT_NFT); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); const snap = await query.get(); @@ -83,11 +83,11 @@ describe('Collection minting', () => { fail(); } - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { network: helper.network }); - const depositOrder = await testEnv.wrap(depositNft)({}); + mockWalletReturnValue(helper.guardian!, { network: helper.network }); + const depositOrder = await testEnv.wrap(WEN_FUNC.depositNft); await helper.sendNftToAddress( helper.guardianAddress!, - depositOrder.payload.targetAddress, + depositOrder.payload.targetAddress!, undefined, nftId, ); @@ -121,7 +121,7 @@ const mintCustomCollection = async (address: AddressDetails, metadata: any) => { const unlocks = [await createUnlock(essence, address)]; const blockId = await submitBlock(wallet, essence, unlocks); - await build5Db().doc(`blocks/${blockId}`).create({ blockId }); + await testEnv.createBlock(blockId); const payload = new TransactionPayload(essence, unlocks); const collectionOutputId = Utils.computeOutputId(Utils.transactionId(payload), 0); @@ -179,7 +179,7 @@ const mintNft = async (address: AddressDetails, metadata: any) => { const payload = new TransactionPayload(essence, unlocks); const blockId = await submitBlock(wallet, essence, unlocks); - await build5Db().doc(`blocks/${blockId}`).create({ blockId }); + await testEnv.createBlock(blockId); const nftId = Utils.computeNftId(Utils.transactionId(payload) + indexToString(1)); return [blockId, nftId]; diff --git a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_12_b.spec.ts b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_12_b.spec.ts index c2bb123b89..decd3b987b 100644 --- a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_12_b.spec.ts +++ b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_12_b.spec.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { build5Db } from '@build-5/database'; -import { COL, MIN_IOTA_AMOUNT, Network } from '@build-5/interfaces'; +import { COL, MIN_IOTA_AMOUNT, Network, Transaction, WEN_FUNC } from '@build-5/interfaces'; import { Ed25519Address, NftAddress, @@ -13,14 +13,13 @@ import { Utils, } from '@iota/sdk'; import { cloneDeep } from 'lodash'; -import { depositNft } from '../../src/runtime/firebase/nft'; import { NftWallet } from '../../src/services/wallet/NftWallet'; import { AddressDetails } from '../../src/services/wallet/wallet.service'; import { packBasicOutput } from '../../src/utils/basic-output.utils'; import { createUnlock, packEssence, submitBlock } from '../../src/utils/block.utils'; import { EMPTY_NFT_ID, createNftOutput } from '../../src/utils/collection-minting-utils/nft.utils'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { getWallet, testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { getWallet, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitLedgerInclusionState, requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -80,11 +79,11 @@ describe('Collection minting', () => { fail(); } - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { network: helper.network }); - const depositOrder = await testEnv.wrap(depositNft)({}); + mockWalletReturnValue(helper.guardian!, { network: helper.network }); + const depositOrder = await testEnv.wrap(WEN_FUNC.depositNft); await helper.sendNftToAddress( helper.guardianAddress!, - depositOrder.payload.targetAddress, + depositOrder.payload.targetAddress!, undefined, nftId, ); @@ -119,7 +118,7 @@ const mintCustomCollection = async (address: AddressDetails, metadata: any) => { const payload = new TransactionPayload(essence, unlocks); const blockId = await submitBlock(wallet, essence, unlocks); - await build5Db().doc(`blocks/${blockId}`).create({ blockId }); + await testEnv.createBlock(blockId); const collectionOutputId = Utils.computeOutputId(Utils.transactionId(payload), 0); const collectionId = Utils.computeNftId(collectionOutputId); @@ -176,7 +175,7 @@ const mintNft = async (address: AddressDetails, metadata: any) => { const payload = new TransactionPayload(essence, unlocks); const blockId = await submitBlock(wallet, essence, unlocks); - await build5Db().doc(`blocks/${blockId}`).create({ blockId }); + await testEnv.createBlock(blockId); const nftOutputId = Utils.computeOutputId(Utils.transactionId(payload), 1); const nftId = Utils.computeNftId(nftOutputId); diff --git a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_13.spec.ts b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_13.spec.ts index 9e6c7798a7..0ed8702ab0 100644 --- a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_13.spec.ts +++ b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_13.spec.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { build5Db } from '@build-5/database'; -import { COL, MIN_IOTA_AMOUNT, Network, Nft } from '@build-5/interfaces'; +import { COL, MIN_IOTA_AMOUNT, Network, Nft, Transaction, WEN_FUNC } from '@build-5/interfaces'; import { Ed25519Address, NftAddress, @@ -13,14 +13,13 @@ import { Utils, } from '@iota/sdk'; import { cloneDeep } from 'lodash'; -import { depositNft } from '../../src/runtime/firebase/nft'; import { NftWallet } from '../../src/services/wallet/NftWallet'; import { AddressDetails } from '../../src/services/wallet/wallet.service'; import { packBasicOutput } from '../../src/utils/basic-output.utils'; import { createUnlock, packEssence, submitBlock } from '../../src/utils/block.utils'; import { EMPTY_NFT_ID, createNftOutput } from '../../src/utils/collection-minting-utils/nft.utils'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { getWallet, testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { getWallet, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitLedgerInclusionState, requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -105,11 +104,11 @@ describe('Collection minting', () => { fail(); } - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { network: helper.network }); - const depositOrder = await testEnv.wrap(depositNft)({}); + mockWalletReturnValue(helper.guardian!, { network: helper.network }); + const depositOrder = await testEnv.wrap(WEN_FUNC.depositNft); await helper.sendNftToAddress( helper.guardianAddress!, - depositOrder.payload.targetAddress, + depositOrder.payload.targetAddress!, undefined, nftId, ); @@ -144,7 +143,7 @@ const mintCustomCollection = async (address: AddressDetails, metadata: any) => { const payload = new TransactionPayload(essence, unlocks); const blockId = await submitBlock(wallet, essence, unlocks); - await build5Db().doc(`blocks/${blockId}`).create({ blockId }); + await testEnv.createBlock(blockId); const collectionOutputId = Utils.computeOutputId(Utils.transactionId(payload), 0); const collectionId = Utils.computeNftId(collectionOutputId); @@ -200,7 +199,7 @@ const mintNft = async (address: AddressDetails, metadata: any) => { const payload = new TransactionPayload(essence, unlocks); const blockId = await submitBlock(wallet, essence, unlocks); - await build5Db().doc(`blocks/${blockId}`).create({ blockId }); + await testEnv.createBlock(blockId); const nftOutputId = Utils.computeOutputId(Utils.transactionId(payload), 1); const nftId = Utils.computeNftId(nftOutputId); diff --git a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_14.spec.ts b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_14.spec.ts index 1fe09fb440..18fb7f0ada 100644 --- a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_14.spec.ts +++ b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_14.spec.ts @@ -8,15 +8,14 @@ import { Nft, Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { creditUnrefundable } from '../../src/runtime/firebase/credit/index'; -import { depositNft, withdrawNft } from '../../src/runtime/firebase/nft/index'; import { NftWallet } from '../../src/services/wallet/NftWallet'; import { getAddress } from '../../src/utils/address.utils'; import { dateToTimestamp } from '../../src/utils/dateTime.utils'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { getWallet, testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { getWallet, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; describe('Collection minting', () => { @@ -36,36 +35,36 @@ describe('Collection minting', () => { const tmpAddress = await helper.walletService!.getNewIotaAddressDetails(); await helper.updateGuardianAddress(tmpAddress.bech32); - const nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { nft: nft.uid }); - await testEnv.wrap(withdrawNft)({}); + const nftDocRef = build5Db().doc(COL.NFT, nft.uid); + mockWalletReturnValue(helper.guardian!, { nft: nft.uid }); + await testEnv.wrap(WEN_FUNC.withdrawNft); const query = build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.WITHDRAW_NFT) - .where('payload.nft', '==', nft.uid); + .where('payload_nft', '==', nft.uid); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); nft = await nftDocRef.get(); - let snap = await query.get(); + let snap = await query.get(); expect(snap[0].payload.nftId).toBe(nft.mintingData?.nftId); const wallet = await getWallet(helper.network); - const guardianDocRef = build5Db().doc(`${COL.MEMBER}/${helper.guardian}`); + const guardianDocRef = build5Db().doc(COL.MEMBER, helper.guardian!); const guardianData = await guardianDocRef.get(); const guardianAddress = getAddress(guardianData, helper.network!); const nftWallet = new NftWallet(wallet); const outputs = await nftWallet.getNftOutputs(undefined, guardianAddress); expect(Object.keys(outputs).length).toBe(1); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { network: helper.network }); - let depositOrder = await testEnv.wrap(depositNft)({}); + mockWalletReturnValue(helper.guardian!, { network: helper.network }); + let depositOrder = await testEnv.wrap(WEN_FUNC.depositNft); const sourceAddress = await helper.walletService!.getAddressDetails(guardianAddress); await helper.sendNftToAddress( sourceAddress!, - depositOrder.payload.targetAddress, + depositOrder.payload.targetAddress!, dateToTimestamp(dayjs().add(1, 'd')), undefined, guardianAddress, @@ -87,12 +86,12 @@ describe('Collection minting', () => { IgnoreWalletReason.UNREFUNDABLE_DUE_STORAGE_DEPOSIT_CONDITION, ); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { transaction: credit.uid }); - const order = await testEnv.wrap(creditUnrefundable)({}); + mockWalletReturnValue(helper.guardian!, { transaction: credit.uid }); + const order = await testEnv.wrap(WEN_FUNC.creditUnrefundable); await requestFundsFromFaucet(Network.RMS, order.payload.targetAddress, order.payload.amount); await wait(async () => { - const snap = await creditQuery.get(); + const snap = await creditQuery.get(); return snap[0]?.payload?.walletReference?.confirmed; }); }); diff --git a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_15.spec.ts b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_15.spec.ts index 57f09a31c2..bb86ae3ee2 100644 --- a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_15.spec.ts +++ b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_15.spec.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { build5Db } from '@build-5/database'; -import { COL, MIN_IOTA_AMOUNT, Network } from '@build-5/interfaces'; +import { COL, MIN_IOTA_AMOUNT, Network, Transaction, WEN_FUNC } from '@build-5/interfaces'; import { Ed25519Address, NftAddress, @@ -13,14 +13,13 @@ import { Utils, } from '@iota/sdk'; import { cloneDeep } from 'lodash'; -import { depositNft } from '../../src/runtime/firebase/nft'; import { NftWallet } from '../../src/services/wallet/NftWallet'; import { AddressDetails } from '../../src/services/wallet/wallet.service'; import { packBasicOutput } from '../../src/utils/basic-output.utils'; import { createUnlock, packEssence, submitBlock } from '../../src/utils/block.utils'; import { EMPTY_NFT_ID, createNftOutput } from '../../src/utils/collection-minting-utils/nft.utils'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { MEDIA, getWallet, testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { MEDIA, getWallet, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { awaitLedgerInclusionState, requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -78,11 +77,11 @@ describe('Collection minting', () => { fail(); } - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { network: helper.network }); - const depositOrder = await testEnv.wrap(depositNft)({}); + mockWalletReturnValue(helper.guardian!, { network: helper.network }); + const depositOrder = await testEnv.wrap(WEN_FUNC.depositNft); await helper.sendNftToAddress( helper.guardianAddress!, - depositOrder.payload.targetAddress, + depositOrder.payload.targetAddress!, undefined, nftId, ); @@ -117,7 +116,7 @@ const mintCustomCollection = async (address: AddressDetails, metadata: any) => { const payload = new TransactionPayload(essence, unlocks); const blockId = await submitBlock(wallet, essence, unlocks); - await build5Db().doc(`blocks/${blockId}`).create({ blockId }); + await testEnv.createBlock(blockId); const collectionOutputId = Utils.computeOutputId(Utils.transactionId(payload), 0); const collectionId = Utils.computeNftId(collectionOutputId); @@ -173,7 +172,7 @@ const mintNft = async (address: AddressDetails, metadata: any) => { const payload = new TransactionPayload(essence, unlocks); const blockId = await submitBlock(wallet, essence, unlocks); - await build5Db().doc(`blocks/${blockId}`).create({ blockId }); + await testEnv.createBlock(blockId); const nftOutputId = Utils.computeOutputId(Utils.transactionId(payload), 1); const nftId = Utils.computeNftId(nftOutputId); diff --git a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_16.spec.ts b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_16.spec.ts index ea6fef011a..7a94096713 100644 --- a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_16.spec.ts +++ b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_16.spec.ts @@ -1,9 +1,15 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { build5Db } from '@build-5/database'; -import { COL, MIN_IOTA_AMOUNT, Network, Transaction, TransactionType } from '@build-5/interfaces'; -import { depositNft } from '../../src/runtime/firebase/nft/index'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { + COL, + MIN_IOTA_AMOUNT, + Network, + Transaction, + TransactionType, + WEN_FUNC, +} from '@build-5/interfaces'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet } from '../faucet'; import { Helper } from './Helper'; @@ -19,8 +25,8 @@ describe('Collection minting', () => { }); it('Should return credits when nft deposit order does not receive nft', async () => { - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { network: helper.network }); - const order = await testEnv.wrap(depositNft)({}); + mockWalletReturnValue(helper.guardian!, { network: helper.network }); + const order = await testEnv.wrap(WEN_FUNC.depositNft); await requestFundsFromFaucet(Network.RMS, order.payload.targetAddress, MIN_IOTA_AMOUNT); const query = build5Db() @@ -28,7 +34,7 @@ describe('Collection minting', () => { .where('type', '==', TransactionType.CREDIT) .where('member', '==', helper.guardian!); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return ( snap.length === 1 && snap[0].payload.walletReference?.confirmed && diff --git a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_1_a.spec.ts b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_1_a.spec.ts index 775216cc9b..4c128e8216 100644 --- a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_1_a.spec.ts +++ b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_1_a.spec.ts @@ -1,12 +1,19 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { build5Db } from '@build-5/database'; -import { COL, Member, Nft, NftStatus, Transaction, TransactionType } from '@build-5/interfaces'; +import { + COL, + Member, + Nft, + NftStatus, + Transaction, + TransactionType, + WEN_FUNC, +} from '@build-5/interfaces'; import { isEqual } from 'lodash'; -import { depositNft, withdrawNft } from '../../src/runtime/firebase/nft/index'; import { NftWallet } from '../../src/services/wallet/NftWallet'; import { getAddress } from '../../src/utils/address.utils'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { getWallet, testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { getWallet, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; describe('Collection minting', () => { @@ -26,27 +33,29 @@ describe('Collection minting', () => { const tmpAddress = await helper.walletService!.getNewIotaAddressDetails(); await helper.updateGuardianAddress(tmpAddress.bech32); - const nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); + const nftDocRef = build5Db().doc(COL.NFT, nft.uid); const mintingData = (await nftDocRef.get()).mintingData; - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { nft: nft.uid }); - await testEnv.wrap(withdrawNft)({}); + mockWalletReturnValue(helper.guardian!, { nft: nft.uid }); + await testEnv.wrap(WEN_FUNC.withdrawNft); const query = build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.WITHDRAW_NFT) - .where('payload.nft', '==', nft.uid); + .where('payload_nft', '==', nft.uid); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); nft = await nftDocRef.get(); expect(nft.status).toBe(NftStatus.WITHDRAWN); expect(nft.hidden).toBe(true); expect(nft.isOwned).toBe(false); - expect(nft.owner).toBeNull(); + expect(nft.owner).toBeUndefined(); + delete (nft.mintingData as any).mintedOn; + delete (mintingData as any).mintedOn; expect(isEqual(nft.mintingData, mintingData)).toBe(true); const wallet = await getWallet(helper.network); - const guardianData = await build5Db().doc(`${COL.MEMBER}/${helper.guardian}`).get(); + const guardianData = await build5Db().doc(COL.MEMBER, helper.guardian!).get(); const nftWallet = new NftWallet(wallet); let outputs = await nftWallet.getNftOutputs( undefined, @@ -54,21 +63,19 @@ describe('Collection minting', () => { ); expect(Object.keys(outputs).length).toBe(1); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { network: helper.network }); - let depositOrder = await testEnv.wrap(depositNft)({}); + mockWalletReturnValue(helper.guardian!, { network: helper.network }); + let depositOrder = await testEnv.wrap(WEN_FUNC.depositNft); const sourceAddress = await helper.walletService?.getAddressDetails( getAddress(guardianData, helper.network!), ); - await helper.sendNftToAddress(sourceAddress!, depositOrder.payload.targetAddress); + await helper.sendNftToAddress(sourceAddress!, depositOrder.payload.targetAddress!); await wait(async () => { nft = await nftDocRef.get(); return nft.status === NftStatus.MINTED; }); - depositOrder = ( - await build5Db().doc(`${COL.TRANSACTION}/${depositOrder.uid}`).get() - ); + depositOrder = await build5Db().doc(COL.TRANSACTION, depositOrder.uid).get(); expect(depositOrder.payload.nft).toBe(nft.uid); expect(nft.depositData?.storageDeposit).toBe(Number(Object.values(outputs)[0].amount)); expect(nft.depositData?.address).toBe(depositOrder.payload.targetAddress); diff --git a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_1_b.spec.ts b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_1_b.spec.ts index efa94de6dc..ab7b720a7f 100644 --- a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_1_b.spec.ts +++ b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_1_b.spec.ts @@ -2,21 +2,21 @@ import { build5Db } from '@build-5/database'; import { COL, - Member, MIN_IOTA_AMOUNT, + Member, Nft, NftStatus, Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; import { isEqual } from 'lodash'; -import { depositNft, withdrawNft } from '../../src/runtime/firebase/nft/index'; import { NftWallet } from '../../src/services/wallet/NftWallet'; import { getAddress } from '../../src/utils/address.utils'; import { dateToTimestamp } from '../../src/utils/dateTime.utils'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { getWallet, testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { getWallet, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; describe('Collection minting', () => { @@ -38,27 +38,29 @@ describe('Collection minting', () => { const tmpAddress = await helper.walletService!.getNewIotaAddressDetails(); await helper.updateGuardianAddress(tmpAddress.bech32); - const nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); + const nftDocRef = build5Db().doc(COL.NFT, nft.uid); const mintingData = (await nftDocRef.get()).mintingData; - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { nft: nft.uid }); - await testEnv.wrap(withdrawNft)({}); + mockWalletReturnValue(helper.guardian!, { nft: nft.uid }); + await testEnv.wrap(WEN_FUNC.withdrawNft); const query = build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.WITHDRAW_NFT) - .where('payload.nft', '==', nft.uid); + .where('payload_nft', '==', nft.uid); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); nft = await nftDocRef.get(); expect(nft.status).toBe(NftStatus.WITHDRAWN); expect(nft.hidden).toBe(true); expect(nft.isOwned).toBe(false); - expect(nft.owner).toBeNull(); + expect(nft.owner).toBeUndefined(); + delete (nft.mintingData as any).mintedOn; + delete (mintingData as any).mintedOn; expect(isEqual(nft.mintingData, mintingData)).toBe(true); const wallet = await getWallet(helper.network); - const guardianData = await build5Db().doc(`${COL.MEMBER}/${helper.guardian}`).get(); + const guardianData = await build5Db().doc(COL.MEMBER, helper.guardian!).get(); const nftWallet = new NftWallet(wallet); let outputs = await nftWallet.getNftOutputs( undefined, @@ -66,21 +68,19 @@ describe('Collection minting', () => { ); expect(Object.keys(outputs).length).toBe(1); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { network: helper.network }); - let depositOrder = await testEnv.wrap(depositNft)({}); + mockWalletReturnValue(helper.guardian!, { network: helper.network }); + let depositOrder = await testEnv.wrap(WEN_FUNC.depositNft); const sourceAddress = await helper.walletService?.getAddressDetails( getAddress(guardianData, helper.network!), ); - await helper.sendNftToAddress(sourceAddress!, depositOrder.payload.targetAddress, expiresAt); + await helper.sendNftToAddress(sourceAddress!, depositOrder.payload.targetAddress!, expiresAt); await wait(async () => { nft = await nftDocRef.get(); return nft.status === NftStatus.MINTED; }); - depositOrder = ( - await build5Db().doc(`${COL.TRANSACTION}/${depositOrder.uid}`).get() - ); + depositOrder = await build5Db().doc(COL.TRANSACTION, depositOrder.uid).get(); expect(depositOrder.payload.nft).toBe(nft.uid); expect(nft.depositData?.storageDeposit).toBe( Number(Object.values(outputs)[0].amount) + MIN_IOTA_AMOUNT, diff --git a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_1_c.spec.ts b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_1_c.spec.ts index 1a21aa5272..920c60e294 100644 --- a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_1_c.spec.ts +++ b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_1_c.spec.ts @@ -1,14 +1,21 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { build5Db } from '@build-5/database'; -import { COL, Member, Nft, NftStatus, Transaction, TransactionType } from '@build-5/interfaces'; +import { + COL, + Member, + Nft, + NftStatus, + Transaction, + TransactionType, + WEN_FUNC, +} from '@build-5/interfaces'; import dayjs from 'dayjs'; import { isEqual } from 'lodash'; -import { depositNft, withdrawNft } from '../../src/runtime/firebase/nft/index'; import { NftWallet } from '../../src/services/wallet/NftWallet'; import { getAddress } from '../../src/utils/address.utils'; import { dateToTimestamp } from '../../src/utils/dateTime.utils'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { getWallet, testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { getWallet, mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; describe('Collection minting', () => { @@ -29,25 +36,27 @@ describe('Collection minting', () => { const tmpAddress = await helper.walletService!.getNewIotaAddressDetails(); await helper.updateGuardianAddress(tmpAddress.bech32); - const nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); + const nftDocRef = build5Db().doc(COL.NFT, nft.uid); const mintingData = (await nftDocRef.get()).mintingData; - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { nft: nft.uid }); - await testEnv.wrap(withdrawNft)({}); + mockWalletReturnValue(helper.guardian!, { nft: nft.uid }); + await testEnv.wrap(WEN_FUNC.withdrawNft); const query = build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.WITHDRAW_NFT) - .where('payload.nft', '==', nft.uid); + .where('payload_nft', '==', nft.uid); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); nft = await nftDocRef.get(); expect(nft.status).toBe(NftStatus.WITHDRAWN); expect(nft.hidden).toBe(true); + delete (nft.mintingData as any).mintedOn; + delete (mintingData as any).mintedOn; expect(isEqual(nft.mintingData, mintingData)).toBe(true); const wallet = await getWallet(helper.network); - const guardianData = await build5Db().doc(`${COL.MEMBER}/${helper.guardian}`).get(); + const guardianData = await build5Db().doc(COL.MEMBER, helper.guardian!).get(); const nftWallet = new NftWallet(wallet); let outputs = await nftWallet.getNftOutputs( undefined, @@ -55,23 +64,23 @@ describe('Collection minting', () => { ); expect(Object.keys(outputs).length).toBe(1); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { network: helper.network }); - const depositOrder = await testEnv.wrap(depositNft)({}); + mockWalletReturnValue(helper.guardian!, { network: helper.network }); + const depositOrder = await testEnv.wrap(WEN_FUNC.depositNft); await build5Db() - .doc(`${COL.TRANSACTION}/${depositOrder.uid}`) - .update({ 'payload.expiresOn': dateToTimestamp(dayjs().subtract(2, 'h').toDate()) }); + .doc(COL.TRANSACTION, depositOrder.uid) + .update({ payload_expiresOn: dayjs().subtract(2, 'h').toDate() }); const sourceAddress = await helper.walletService?.getAddressDetails( getAddress(guardianData, helper.network!), ); - await helper.sendNftToAddress(sourceAddress!, depositOrder.payload.targetAddress, expiresAt); + await helper.sendNftToAddress(sourceAddress!, depositOrder.payload.targetAddress!, expiresAt); await wait(async () => { const snap = await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.CREDIT_NFT) .where('member', '==', helper.guardian!) - .get(); + .get(); return ( snap.length === 1 && snap[0]!.payload.walletReference?.confirmed && diff --git a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_2.spec.ts b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_2.spec.ts index 48f3ec9440..19a27f5220 100644 --- a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_2.spec.ts +++ b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_2.spec.ts @@ -1,9 +1,8 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { build5Db } from '@build-5/database'; -import { COL, Transaction, TransactionType } from '@build-5/interfaces'; -import { depositNft } from '../../src/runtime/firebase/nft/index'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { COL, Transaction, TransactionType, WEN_FUNC } from '@build-5/interfaces'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; describe('Collection minting', () => { @@ -30,12 +29,12 @@ describe('Collection minting', () => { await helper.updateGuardianAddress(tmpAddress2.bech32); await helper.withdrawNftAndAwait(nft2.uid); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { network: helper.network }); - const depositOrder = await testEnv.wrap(depositNft)({}); + mockWalletReturnValue(helper.guardian!, { network: helper.network }); + const depositOrder = await testEnv.wrap(WEN_FUNC.depositNft); const promises = [ - helper.sendNftToAddress(tmpAddress1, depositOrder.payload.targetAddress), - helper.sendNftToAddress(tmpAddress2, depositOrder.payload.targetAddress), + helper.sendNftToAddress(tmpAddress1, depositOrder.payload.targetAddress!), + helper.sendNftToAddress(tmpAddress2, depositOrder.payload.targetAddress!), ]; await Promise.all(promises); @@ -44,7 +43,7 @@ describe('Collection minting', () => { .collection(COL.TRANSACTION) .where('type', '==', TransactionType.CREDIT_NFT) .where('member', '==', helper.guardian) - .get(); + .get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); }); diff --git a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_4.spec.ts b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_4.spec.ts index fd4b512e50..b264f5d41a 100644 --- a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_4.spec.ts +++ b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_4.spec.ts @@ -1,9 +1,8 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { build5Db } from '@build-5/database'; -import { COL, WenError } from '@build-5/interfaces'; -import { withdrawNft } from '../../src/runtime/firebase/nft/index'; -import { expectThrow, mockWalletReturnValue } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { COL, WEN_FUNC, WenError } from '@build-5/interfaces'; +import { expectThrow } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; describe('Collection minting', () => { @@ -22,20 +21,20 @@ describe('Collection minting', () => { await helper.mintCollection(); await helper.setAvailableForSale(); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { nft: helper.nft!.uid }); - await expectThrow(testEnv.wrap(withdrawNft)({}), WenError.nft_on_sale.key); + mockWalletReturnValue(helper.guardian!, { nft: helper.nft!.uid }); + await expectThrow(testEnv.wrap(WEN_FUNC.withdrawNft), WenError.nft_on_sale.key); - await build5Db().doc(`${COL.NFT}/${helper.nft!.uid}`).update({ - auctionFrom: null, - auctionTo: null, - auctionFloorPrice: null, - auctionLength: null, - auctionHighestBid: null, - auctionHighestBidder: null, + await build5Db().doc(COL.NFT, helper.nft!.uid).update({ + auctionFrom: undefined, + auctionTo: undefined, + auctionFloorPrice: undefined, + auctionLength: undefined, + auctionHighestBid: undefined, + auctionHighestBidder: undefined, }); await helper.setAvailableForAuction(); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { nft: helper.nft!.uid }); - await expectThrow(testEnv.wrap(withdrawNft)({}), WenError.nft_on_sale.key); + mockWalletReturnValue(helper.guardian!, { nft: helper.nft!.uid }); + await expectThrow(testEnv.wrap(WEN_FUNC.withdrawNft), WenError.nft_on_sale.key); }); }); diff --git a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_4_b.spec.ts b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_4_b.spec.ts index 7cc185c190..b1351ab41f 100644 --- a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_4_b.spec.ts +++ b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_4_b.spec.ts @@ -1,10 +1,8 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { build5Db } from '@build-5/database'; -import { COL, Nft, NftStatus, WenError } from '@build-5/interfaces'; -import { updateMember } from '../../src/runtime/firebase/member'; -import { withdrawNft } from '../../src/runtime/firebase/nft/index'; -import { expectThrow, mockWalletReturnValue } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { COL, Nft, NftStatus, WEN_FUNC, WenError } from '@build-5/interfaces'; +import { expectThrow } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; describe('Collection minting', () => { @@ -22,19 +20,19 @@ describe('Collection minting', () => { await helper.createAndOrderNft(); await helper.mintCollection(); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { avatarNft: helper.nft?.uid }); - await testEnv.wrap(updateMember)({}); + mockWalletReturnValue(helper.guardian!, { avatarNft: helper.nft?.uid }); + await testEnv.wrap(WEN_FUNC.updateMember); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { nft: helper.nft!.uid }); - await expectThrow(testEnv.wrap(withdrawNft)({}), WenError.nft_set_as_avatar.key); + mockWalletReturnValue(helper.guardian!, { nft: helper.nft!.uid }); + await expectThrow(testEnv.wrap(WEN_FUNC.withdrawNft), WenError.nft_set_as_avatar.key); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { avatarNft: undefined }); - await testEnv.wrap(updateMember)({}); + mockWalletReturnValue(helper.guardian!, { avatarNft: undefined }); + await testEnv.wrap(WEN_FUNC.updateMember); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { nft: helper.nft!.uid }); - await testEnv.wrap(withdrawNft)({}); + mockWalletReturnValue(helper.guardian!, { nft: helper.nft!.uid }); + await testEnv.wrap(WEN_FUNC.withdrawNft); - const nftDocRef = build5Db().doc(`${COL.NFT}/${helper.nft?.uid}`); + const nftDocRef = build5Db().doc(COL.NFT, helper.nft?.uid!); const nft = await nftDocRef.get(); expect(nft.status).toBe(NftStatus.WITHDRAWN); }); diff --git a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_5.spec.ts b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_5.spec.ts index f19db509f7..822a174cc6 100644 --- a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_5.spec.ts +++ b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_5.spec.ts @@ -1,10 +1,9 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { build5Db } from '@build-5/database'; -import { COL, Member, Nft, Transaction, TransactionType } from '@build-5/interfaces'; -import { depositNft, withdrawNft } from '../../src/runtime/firebase/nft/index'; +import { COL, Member, Nft, Transaction, TransactionType, WEN_FUNC } from '@build-5/interfaces'; import { getAddress } from '../../src/utils/address.utils'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; describe('Collection minting', () => { @@ -22,37 +21,37 @@ describe('Collection minting', () => { await helper.createAndOrderNft(); await helper.mintCollection(); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { nft: helper.nft!.uid }); - await testEnv.wrap(withdrawNft)({}); + mockWalletReturnValue(helper.guardian!, { nft: helper.nft!.uid }); + await testEnv.wrap(WEN_FUNC.withdrawNft); const query = build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.WITHDRAW_NFT) - .where('payload.nft', '==', helper.nft!.uid); + .where('payload_nft', '==', helper.nft!.uid); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); - await build5Db().doc(`${COL.COLLECTION}/${helper.collection}`).update({ approved: false }); + await build5Db().doc(COL.COLLECTION, helper.collection!).update({ approved: false }); - const guardianData = await build5Db().doc(`${COL.MEMBER}/${helper.guardian}`).get(); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { network: helper.network }); - const depositOrder = await testEnv.wrap(depositNft)({}); + const guardianData = await build5Db().doc(COL.MEMBER, helper.guardian!).get(); + mockWalletReturnValue(helper.guardian!, { network: helper.network }); + const depositOrder = await testEnv.wrap(WEN_FUNC.depositNft); const sourceAddress = await helper.walletService?.getAddressDetails( getAddress(guardianData, helper.network!), ); - await helper.sendNftToAddress(sourceAddress!, depositOrder.payload.targetAddress); + await helper.sendNftToAddress(sourceAddress!, depositOrder.payload.targetAddress!); const creditNftQuery = build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.CREDIT_NFT) .where('member', '==', helper.guardian); await wait(async () => { - const snap = await creditNftQuery.get(); + const snap = await creditNftQuery.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); - const nft = await build5Db().doc(`${COL.NFT}/${helper.nft!.uid}`).get(); + const nft = await build5Db().doc(COL.NFT, helper.nft!.uid).get(); const creditNftTransaction = (await creditNftQuery.get())[0] as Transaction; expect(creditNftTransaction.payload.nftId).toBe(nft.mintingData?.nftId); }); diff --git a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_6.spec.ts b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_6.spec.ts index bfd91dc7a1..d0b69efa6f 100644 --- a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_6.spec.ts +++ b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_6.spec.ts @@ -11,11 +11,11 @@ import { Space, Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; -import { depositNft, withdrawNft } from '../../src/runtime/firebase/nft/index'; import { getAddress } from '../../src/utils/address.utils'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; describe('Nft depositing', () => { @@ -32,33 +32,33 @@ describe('Nft depositing', () => { nft = await helper.createAndOrderNft(); await helper.mintCollection(); - const nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { nft: nft.uid }); - await testEnv.wrap(withdrawNft)({}); + const nftDocRef = build5Db().doc(COL.NFT, nft.uid); + mockWalletReturnValue(helper.guardian!, { nft: nft.uid }); + await testEnv.wrap(WEN_FUNC.withdrawNft); const query = build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.WITHDRAW_NFT) - .where('payload.nft', '==', nft.uid); + .where('payload_nft', '==', nft.uid); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); nft = await nftDocRef.get(); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${nft.collection}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, nft.collection); collection = await collectionDocRef.get(); }); it('Should deposit nft minted outside build-5 and withdraw it', async () => { - const nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); + const nftDocRef = build5Db().doc(COL.NFT, nft.uid); await nftDocRef.delete(); - await build5Db().doc(`${COL.COLLECTION}/${nft.collection}`).delete(); + await build5Db().doc(COL.COLLECTION, nft.collection).delete(); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { network: helper.network }); - let depositOrder = await testEnv.wrap(depositNft)({}); - await helper.sendNftToAddress(helper.guardianAddress!, depositOrder.payload.targetAddress); + mockWalletReturnValue(helper.guardian!, { network: helper.network }); + let depositOrder = await testEnv.wrap(WEN_FUNC.depositNft); + await helper.sendNftToAddress(helper.guardianAddress!, depositOrder.payload.targetAddress!); const nftQuery = build5Db().collection(COL.NFT).where('owner', '==', helper.guardian); await wait(async () => { @@ -76,7 +76,8 @@ describe('Nft depositing', () => { expect(migratedNft.space).toBeDefined(); expect(migratedNft.owner).toBe(helper.guardian); expect(migratedNft.isOwned).toBe(true); - expect(migratedNft.depositData?.network).toBe(nft.mintingData?.network); + expect(migratedNft.depositData?.network).toBe(helper.network); + expect(migratedNft.mintingData?.network).toBe(helper.network); expect(migratedNft.depositData?.nftId).toBe(nft.mintingData?.nftId); expect(migratedNft.depositData?.address).toBe(depositOrder.payload.targetAddress); expect(migratedNft.status).toBe(NftStatus.MINTED); @@ -85,7 +86,7 @@ describe('Nft depositing', () => { expect(migratedNft.properties.custom.value).toBe(1); expect(migratedNft.properties.customStat.value).toBe('customStat'); - const migratedCollectionDocRef = build5Db().doc(`${COL.COLLECTION}/${migratedNft.collection}`); + const migratedCollectionDocRef = build5Db().doc(COL.COLLECTION, migratedNft.collection); const migratedCollection = await migratedCollectionDocRef.get(); expect(migratedCollection.space).toBe(migratedNft.space); expect(migratedCollection.uid).toBe(collection.mintingData?.nftId!); @@ -100,7 +101,7 @@ describe('Nft depositing', () => { expect(migratedCollection.royaltiesFee).toBe(0.45); expect(migratedCollection.royaltiesSpace).toBe(getAddress(helper.royaltySpace!, Network.RMS)); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${migratedNft.space}`); + const spaceDocRef = build5Db().doc(COL.SPACE, migratedNft.space); const space = await spaceDocRef.get(); expect(space.uid).toBeDefined(); expect(space.name).toBe(migratedCollection.name); @@ -109,18 +110,18 @@ describe('Nft depositing', () => { expect(space.avatarUrl).toBe(migratedCollection.bannerUrl); const nftId = nft.mintingData?.nftId; - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { nft: nftId }); - await testEnv.wrap(withdrawNft)({}); + mockWalletReturnValue(helper.guardian!, { nft: nftId }); + await testEnv.wrap(WEN_FUNC.withdrawNft); const query = build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.WITHDRAW_NFT) - .where('payload.nft', '==', nftId); + .where('payload_nft', '==', nftId); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); - const depositOrderDocRef = build5Db().doc(`${COL.TRANSACTION}/${depositOrder.uid}`); + const depositOrderDocRef = build5Db().doc(COL.TRANSACTION, depositOrder.uid); depositOrder = await depositOrderDocRef.get(); expect(depositOrder.payload.nft).toBe(nftId); }); diff --git a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_7.spec.ts b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_7.spec.ts index 2780132e62..aecb42725b 100644 --- a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_7.spec.ts +++ b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_7.spec.ts @@ -1,9 +1,8 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { build5Db } from '@build-5/database'; -import { COL, Network, Nft, Transaction, TransactionType } from '@build-5/interfaces'; -import { depositNft, withdrawNft } from '../../src/runtime/firebase/nft/index'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { COL, Network, Nft, Transaction, TransactionType, WEN_FUNC } from '@build-5/interfaces'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; describe('Collection minting', () => { @@ -19,30 +18,30 @@ describe('Collection minting', () => { nft = await helper.createAndOrderNft(); await helper.mintCollection(); - const nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { nft: nft.uid }); - await testEnv.wrap(withdrawNft)({}); + const nftDocRef = build5Db().doc(COL.NFT, nft.uid); + mockWalletReturnValue(helper.guardian!, { nft: nft.uid }); + await testEnv.wrap(WEN_FUNC.withdrawNft); const query = build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.WITHDRAW_NFT) - .where('payload.nft', '==', nft.uid); + .where('payload_nft', '==', nft.uid); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); nft = await nftDocRef.get(); }); it('Should deposit and claim space', async () => { - const nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); + const nftDocRef = build5Db().doc(COL.NFT, nft.uid); await nftDocRef.delete(); - await build5Db().doc(`${COL.COLLECTION}/${nft.collection}`).delete(); + await build5Db().doc(COL.COLLECTION, nft.collection).delete(); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { network: helper.network }); - const depositOrder = await testEnv.wrap(depositNft)({}); - await helper.sendNftToAddress(helper.guardianAddress!, depositOrder.payload.targetAddress); + mockWalletReturnValue(helper.guardian!, { network: helper.network }); + const depositOrder = await testEnv.wrap(WEN_FUNC.depositNft); + await helper.sendNftToAddress(helper.guardianAddress!, depositOrder.payload.targetAddress!); const nftQuery = build5Db().collection(COL.NFT).where('owner', '==', helper.guardian); await wait(async () => { diff --git a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_8.spec.ts b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_8.spec.ts index c1f097ba50..28e161f807 100644 --- a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_8.spec.ts +++ b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_8.spec.ts @@ -1,9 +1,8 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { build5Db } from '@build-5/database'; -import { COL, Collection, Nft, Transaction, TransactionType } from '@build-5/interfaces'; -import { depositNft, withdrawNft } from '../../src/runtime/firebase/nft/index'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { COL, Collection, Nft, Transaction, TransactionType, WEN_FUNC } from '@build-5/interfaces'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; describe('Collection minting', () => { @@ -20,32 +19,32 @@ describe('Collection minting', () => { nft = await helper.createAndOrderNft(); await helper.mintCollection(); - const nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { nft: nft.uid }); - await testEnv.wrap(withdrawNft)({}); + const nftDocRef = build5Db().doc(COL.NFT, nft.uid); + mockWalletReturnValue(helper.guardian!, { nft: nft.uid }); + await testEnv.wrap(WEN_FUNC.withdrawNft); const query = build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.WITHDRAW_NFT) - .where('payload.nft', '==', nft.uid); + .where('payload_nft', '==', nft.uid); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); nft = await nftDocRef.get(); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${nft.collection}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, nft.collection); collection = await collectionDocRef.get(); }); it('Should migrate nft to existing collection', async () => { - const nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); + const nftDocRef = build5Db().doc(COL.NFT, nft.uid); await nftDocRef.delete(); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { network: helper.network }); - const depositOrder = await testEnv.wrap(depositNft)({}); - await helper.sendNftToAddress(helper.guardianAddress!, depositOrder.payload.targetAddress); + mockWalletReturnValue(helper.guardian!, { network: helper.network }); + const depositOrder = await testEnv.wrap(WEN_FUNC.depositNft); + await helper.sendNftToAddress(helper.guardianAddress!, depositOrder.payload.targetAddress!); const nftQuery = build5Db().collection(COL.NFT).where('owner', '==', helper.guardian); await wait(async () => { diff --git a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_9.spec.ts b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_9.spec.ts index 5622f31f1a..463a2e2bc2 100644 --- a/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_9.spec.ts +++ b/packages/functions/test-tangle/withdraw-deposit-nft/deposit-withraw-nft_9.spec.ts @@ -1,9 +1,16 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { build5Db, build5Storage } from '@build-5/database'; -import { Bucket, COL, Collection, Nft, Transaction, TransactionType } from '@build-5/interfaces'; -import { depositNft, withdrawNft } from '../../src/runtime/firebase/nft/index'; -import { mockWalletReturnValue, wait } from '../../test/controls/common'; -import { testEnv } from '../../test/set-up'; +import { + Bucket, + COL, + Collection, + Nft, + Transaction, + TransactionType, + WEN_FUNC, +} from '@build-5/interfaces'; +import { wait } from '../../test/controls/common'; +import { mockWalletReturnValue, testEnv } from '../../test/set-up'; import { Helper } from './Helper'; describe('Collection minting', () => { @@ -19,16 +26,16 @@ describe('Collection minting', () => { nft = await helper.createAndOrderNft(); await helper.mintCollection(); - const nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { nft: nft.uid }); - await testEnv.wrap(withdrawNft)({}); + const nftDocRef = build5Db().doc(COL.NFT, nft.uid); + mockWalletReturnValue(helper.guardian!, { nft: nft.uid }); + await testEnv.wrap(WEN_FUNC.withdrawNft); const query = build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.WITHDRAW_NFT) - .where('payload.nft', '==', nft.uid); + .where('payload_nft', '==', nft.uid); await wait(async () => { - const snap = await query.get(); + const snap = await query.get(); return snap.length === 1 && snap[0]?.payload?.walletReference?.confirmed; }); nft = await nftDocRef.get(); @@ -41,14 +48,14 @@ describe('Collection minting', () => { }); it('Should migrate media', async () => { - const nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); + const nftDocRef = build5Db().doc(COL.NFT, nft.uid); await nftDocRef.delete(); - await build5Db().doc(`${COL.COLLECTION}/${nft.collection}`).delete(); + await build5Db().doc(COL.COLLECTION, nft.collection).delete(); - mockWalletReturnValue(helper.walletSpy, helper.guardian!, { network: helper.network }); - const depositOrder = await testEnv.wrap(depositNft)({}); - await helper.sendNftToAddress(helper.guardianAddress!, depositOrder.payload.targetAddress); + mockWalletReturnValue(helper.guardian!, { network: helper.network }); + const depositOrder = await testEnv.wrap(WEN_FUNC.depositNft); + await helper.sendNftToAddress(helper.guardianAddress!, depositOrder.payload.targetAddress!); const nftQuery = build5Db().collection(COL.NFT).where('owner', '==', helper.guardian); await wait(async () => { @@ -60,7 +67,7 @@ describe('Collection minting', () => { const migratedNft = snap[0]; await validateStorageFileCount(helper.guardian!, migratedNft.uid); - const migratedCollectionDocRef = build5Db().doc(`${COL.COLLECTION}/${migratedNft.collection}`); + const migratedCollectionDocRef = build5Db().doc(COL.COLLECTION, migratedNft.collection); const migratedCollection = await migratedCollectionDocRef.get(); await validateStorageFileCount(migratedCollection.space!, migratedCollection.uid); }); diff --git a/packages/functions/test-tangle/workflow-online.spec.ts b/packages/functions/test-tangle/workflow-online.spec.ts deleted file mode 100644 index efc6c19726..0000000000 --- a/packages/functions/test-tangle/workflow-online.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import fs from 'fs'; - -describe('Workflow test', () => { - it('Test if workflow contains all files', async () => { - const buffer = fs.readFileSync( - '../../.github/workflows/functions_tangle-online-unit-tests_emulator.yml', - ); - const workflowTxt = buffer.toString(); - - const glob = require('glob'); - const testFileNames = glob - .sync(`./test-tangle/**/*.spec.ts`) - .filter((f: any) => !f.includes('exclude')) - .filter((f: any) => !f.includes('only.spec.ts')) - .filter((f: any) => !f.includes('web3.spec')) - .filter((f: any) => !f.includes('dbRoll')); - for (const testFileName of testFileNames) { - if (!workflowTxt.includes(testFileName)) { - throw Error( - `Action misses the following file: ${testFileName}. Pls run node workflow-online.build.js`, - ); - } - } - }); -}); diff --git a/packages/functions/test/auth.spec.ts b/packages/functions/test/auth.spec.ts index 84fcca88fd..cf31c2aa3c 100644 --- a/packages/functions/test/auth.spec.ts +++ b/packages/functions/test/auth.spec.ts @@ -3,30 +3,24 @@ import { COL, Member, Network, WEN_FUNC, WenError } from '@build-5/interfaces'; import { CoinType, utf8ToHex } from '@iota/sdk'; import jwt from 'jsonwebtoken'; import { get } from 'lodash'; -import { generateCustomToken } from '../src/runtime/firebase/auth'; import * as config from '../src/utils/config.utils'; import { getJwtSecretKey } from '../src/utils/config.utils'; import { getSecretManager } from '../src/utils/secret.manager.utils'; -import * as wallet from '../src/utils/wallet.utils'; import { decodeAuth, getRandomNonce } from '../src/utils/wallet.utils'; -import { createMember, expectThrow, mockWalletReturnValue } from './controls/common'; -import { PROJECT_API_KEY, getWallet, testEnv } from './set-up'; +import { expectThrow } from './controls/common'; +import { PROJECT_API_KEY, getWallet, mockWalletReturnValue, testEnv } from './set-up'; describe('Auth control test', () => { - let walletSpy: jest.SpyInstance; let configSpy: jest.SpyInstance; let member: string; beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - member = await createMember(walletSpy); + member = await testEnv.createMember(); }); it('Should create and reuse custom token', async () => { - mockWalletReturnValue(walletSpy, member, {}); - const token = await testEnv.wrap(generateCustomToken)({}); - walletSpy.mockRestore(); - const tokenGeneratedWithToken = await testEnv.wrap(generateCustomToken)({}, member, token); + mockWalletReturnValue(member, {}); + const tokenGeneratedWithToken = await testEnv.wrap(WEN_FUNC.generateCustomToken); expect(tokenGeneratedWithToken).toBeDefined(); const decoded = jwt.verify(tokenGeneratedWithToken, getJwtSecretKey()); expect(get(decoded, 'uid')).toBe(member); @@ -35,19 +29,23 @@ describe('Auth control test', () => { }); it('Should throw, custom token for func expired', async () => { - mockWalletReturnValue(walletSpy, member, {}); - const token = await testEnv.wrap(generateCustomToken)({}); - walletSpy.mockRestore(); - + mockWalletReturnValue(member, undefined); + const token = await testEnv.wrap(WEN_FUNC.generateCustomToken); configSpy = jest.spyOn(config, 'getCustomTokenLifetime'); configSpy.mockReturnValue(1); - await new Promise((resolve) => setTimeout(resolve, 2000)); - await expectThrow( - testEnv.wrap(generateCustomToken)({}, member, token), - WenError.invalid_custom_token.key, + const call = decodeAuth( + { + address: member, + projectApiKey: PROJECT_API_KEY, + signature: '', + publicKey: {} as any, + customToken: token, + body: {}, + }, + WEN_FUNC.generateCustomToken, ); - + await expectThrow(call, WenError.invalid_custom_token.key); configSpy.mockRestore(); }); }); @@ -56,11 +54,9 @@ describe('Pub key test', () => { it.each([Network.RMS, Network.SMR])('Should validate SMR pub key', async (network: Network) => { const wallet = await getWallet(network); const address = await wallet.getNewIotaAddressDetails(); - const nonce = getRandomNonce(); - const userDocRef = build5Db().doc(`${COL.MEMBER}/${address.bech32}`); + const userDocRef = build5Db().doc(COL.MEMBER, address.bech32); await userDocRef.create({ uid: address.bech32, nonce }); - const secretManager = getSecretManager(address.mnemonic); const signature = await secretManager.signEd25519(utf8ToHex(nonce), { coinType: CoinType.IOTA, @@ -69,17 +65,11 @@ describe('Pub key test', () => { address: 'address', projectApiKey: PROJECT_API_KEY, signature: signature.signature, - publicKey: { - hex: signature.publicKey, - network, - }, + publicKey: { hex: signature.publicKey, network }, body: {}, }; - const result = await decodeAuth(request, WEN_FUNC.approveProposal); - expect(result.address).toBe(address.bech32); - const user = await userDocRef.get(); expect(user.validatedAddress![network]).toBe(address.bech32); }); @@ -89,11 +79,9 @@ describe('Pub key test', () => { async (network: Network) => { const wallet = await getWallet(network); const address = await wallet.getNewIotaAddressDetails(); - const nonce = getRandomNonce(); - const userDocRef = build5Db().doc(`${COL.MEMBER}/${address.bech32}`); + const userDocRef = build5Db().doc(COL.MEMBER, address.bech32); await userDocRef.create({ uid: address.bech32, nonce }); - const secretManager = getSecretManager(address.mnemonic); const signature = await secretManager.signEd25519(utf8ToHex(nonce), { coinType: CoinType.IOTA, @@ -102,17 +90,11 @@ describe('Pub key test', () => { address: address.bech32, signature: signature.signature, projectApiKey: PROJECT_API_KEY, - publicKey: { - hex: signature.publicKey, - network, - }, + publicKey: { hex: signature.publicKey, network }, body: {}, }; - const result = await decodeAuth(request, WEN_FUNC.approveProposal); - expect(result.address).toBe(address.bech32); - const user = await userDocRef.get(); expect(user.validatedAddress![network]).toBe(address.bech32); }, @@ -121,16 +103,13 @@ describe('Pub key test', () => { it.each([Network.RMS, Network.SMR])('Should throw wrong pub key', async (network: Network) => { const wallet = await getWallet(network); const address = await wallet.getNewIotaAddressDetails(); - const nonce = getRandomNonce(); - const userDocRef = build5Db().doc(`${COL.MEMBER}/${address.bech32}`); + const userDocRef = build5Db().doc(COL.MEMBER, address.bech32); await userDocRef.create({ uid: address.bech32, nonce }); - const secretManager = getSecretManager(address.mnemonic); const signature = await secretManager.signEd25519(utf8ToHex(nonce), { coinType: CoinType.IOTA, }); - const wallet2 = await getWallet(network === Network.SMR ? Network.RMS : Network.SMR); const secondAddress = await wallet2.getNewIotaAddressDetails(); const secretManagerSecond = getSecretManager(secondAddress.mnemonic); @@ -141,28 +120,21 @@ describe('Pub key test', () => { address: 'address', projectApiKey: PROJECT_API_KEY, signature: signature.signature, - publicKey: { - hex: signatureSecond.publicKey, - network, - }, + publicKey: { hex: signatureSecond.publicKey, network }, body: {}, }; - try { - await decodeAuth(request, WEN_FUNC.approveProposal); - fail(); - } catch (error: any) { - expect(error.details.key).toBe(WenError.failed_to_decode_token.key); - } + await expectThrow( + decodeAuth(request, WEN_FUNC.approveProposal), + WenError.failed_to_decode_token.key, + ); }); it('Should update nonce when public key sign in', async () => { const wallet = await getWallet(Network.RMS); const address = await wallet.getNewIotaAddressDetails(); - const nonce = getRandomNonce(); - const userDocRef = build5Db().doc(`${COL.MEMBER}/${address.bech32}`); + const userDocRef = build5Db().doc(COL.MEMBER, address.bech32); await userDocRef.create({ uid: address.bech32, nonce }); - const secretManager = getSecretManager(address.mnemonic); const signature = await secretManager.signEd25519(utf8ToHex(nonce), { coinType: CoinType.IOTA, @@ -171,17 +143,11 @@ describe('Pub key test', () => { address: 'address', signature: signature.signature, projectApiKey: PROJECT_API_KEY, - publicKey: { - hex: signature.publicKey, - network: Network.RMS, - }, + publicKey: { hex: signature.publicKey, network: Network.RMS }, body: {}, }; - const result = await decodeAuth(request, WEN_FUNC.approveProposal); - expect(result.address).toBe(address.bech32); - const user = await userDocRef.get(); expect(user.validatedAddress![Network.RMS]).toBe(address.bech32); expect(user.nonce).not.toBe(nonce); diff --git a/packages/functions/test/auth/legacy.auth.spec.ts b/packages/functions/test/auth/legacy.auth.spec.ts index 6358f0e6aa..61094db9d3 100644 --- a/packages/functions/test/auth/legacy.auth.spec.ts +++ b/packages/functions/test/auth/legacy.auth.spec.ts @@ -13,16 +13,15 @@ import { Converter } from '@iota/util.js'; import { Converter as ConverterNext } from '@iota/util.js-next'; import { generateMnemonic } from 'bip39'; import { decodeAuth, getRandomNonce } from '../../src/utils/wallet.utils'; +import { expectThrow } from '../controls/common'; import { PROJECT_API_KEY } from '../set-up'; describe('Legacy Pub key test', () => { - it.each([Network.RMS])('Should validate SMR pub key', async (network: Network) => { + it.each([Network.RMS, Network.SMR])('Should validate SMR pub key', async (network: Network) => { const address = getSmrAddress(network); - const nonce = getRandomNonce(); - const userDocRef = build5Db().doc(`${COL.MEMBER}/${address.bech32}`); + const userDocRef = build5Db().doc(COL.MEMBER, address.bech32); await userDocRef.create({ uid: address.bech32, nonce }); - const signature = Ed25519Next.sign( address.keyPair.privateKey, Converter.utf8ToBytes(`0x${toHex(nonce)}`), @@ -31,33 +30,24 @@ describe('Legacy Pub key test', () => { address: 'address', signature: ConverterNext.bytesToHex(signature), projectApiKey: PROJECT_API_KEY, - legacyPublicKey: { - hex: ConverterNext.bytesToHex(address.keyPair.publicKey), - network, - }, + legacyPublicKey: { hex: ConverterNext.bytesToHex(address.keyPair.publicKey), network }, body: {}, }; - const result = await decodeAuth(request, WEN_FUNC.approveProposal); - expect(result.address).toBe(address.bech32); - const user = await userDocRef.get(); expect(user.validatedAddress![network]).toBe(address.bech32); }); it('Should validate IOTA pub key', async () => { const address = await getIotaAddress(Network.IOTA); - const nonce = getRandomNonce(); - const userDocRef = build5Db().doc(`${COL.MEMBER}/${address.bech32}`); + const userDocRef = build5Db().doc(COL.MEMBER, address.bech32); await userDocRef.create({ uid: address.bech32, nonce }); - const signature = Ed25519.sign( address.keyPair.privateKey, Converter.utf8ToBytes(`0x${toHex(nonce)}`), ); - const request = { address: 'address', signature: Converter.bytesToHex(signature), @@ -68,53 +58,40 @@ describe('Legacy Pub key test', () => { }, body: {}, }; - const result = await decodeAuth(request, WEN_FUNC.approveProposal); - expect(result.address).toBe(address.bech32); - const user = await userDocRef.get(); expect(user.validatedAddress![Network.IOTA]).toBe(address.bech32); }); it.each([Network.RMS, Network.SMR])('Should throw wrong pub key', async (network: Network) => { const address = getSmrAddress(network); - const nonce = getRandomNonce(); - const userDocRef = build5Db().doc(`${COL.MEMBER}/${address.bech32}`); + const userDocRef = build5Db().doc(COL.MEMBER, address.bech32); await userDocRef.create({ uid: address.bech32, nonce }); - const signature = Ed25519Next.sign( address.keyPair.privateKey, Converter.utf8ToBytes(`0x${toHex(nonce)}`), ); - const secondAddress = getSmrAddress(network); const request = { address: 'address', signature: ConverterNext.bytesToHex(signature), projectApiKey: PROJECT_API_KEY, - legacyPublicKey: { - hex: ConverterNext.bytesToHex(secondAddress.keyPair.publicKey), - network, - }, + legacyPublicKey: { hex: ConverterNext.bytesToHex(secondAddress.keyPair.publicKey), network }, body: {}, }; - try { - await decodeAuth(request, WEN_FUNC.approveProposal); - fail(); - } catch (error: any) { - expect(error.details.key).toBe(WenError.failed_to_decode_token.key); - } + await expectThrow( + decodeAuth(request, WEN_FUNC.approveProposal), + WenError.failed_to_decode_token.key, + ); }); it('Should update nonce when public key sign in', async () => { const address = getSmrAddress(Network.RMS); - const nonce = getRandomNonce(); - const userDocRef = build5Db().doc(`${COL.MEMBER}/${address.bech32}`); + const userDocRef = build5Db().doc(COL.MEMBER, address.bech32); await userDocRef.create({ uid: address.bech32, nonce }); - const signature = Ed25519Next.sign( address.keyPair.privateKey, Converter.utf8ToBytes(`0x${toHex(nonce)}`), @@ -129,11 +106,8 @@ describe('Legacy Pub key test', () => { }, body: {}, }; - const result = await decodeAuth(request, WEN_FUNC.approveProposal); - expect(result.address).toBe(address.bech32); - const user = await userDocRef.get(); expect(user.validatedAddress![Network.RMS]).toBe(address.bech32); expect(user.nonce).not.toBe(nonce); @@ -148,7 +122,6 @@ const toHex = (stringToConvert: string) => const getSmrAddress = (network: Network) => { const mnemonic = generateMnemonic() + ' ' + generateMnemonic(); - const walletSeed = Ed25519SeedNext.fromMnemonic(mnemonic); const walletPath = new Bip32PathNext("m/44'/4218'/0'/0'/0'"); const walletAddressSeed = walletSeed.generateSeedFromPath(walletPath); @@ -157,7 +130,6 @@ const getSmrAddress = (network: Network) => { const walletAddress = walletEd25519Address.toAddress(); const hex = ConverterNext.bytesToHex(walletAddress, true); const bech32 = Bech32HelperNext.toBech32(ED25519_ADDRESS_TYPE_NEXT, walletAddress, network); - return { mnemonic, keyPair, hex, bech32 }; }; @@ -171,6 +143,5 @@ const getIotaAddress = async (network: Network) => { const genesisWalletAddress = genesisEd25519Address.toAddress(); const hex = Converter.bytesToHex(genesisWalletAddress); const bech32 = Bech32Helper.toBech32(ED25519_ADDRESS_TYPE, genesisWalletAddress, network); - return { mnemonic, bech32, keyPair, hex }; }; diff --git a/packages/functions/test/controls/address.spec.ts b/packages/functions/test/controls/address.spec.ts index 7857623922..5220dfcef3 100644 --- a/packages/functions/test/controls/address.spec.ts +++ b/packages/functions/test/controls/address.spec.ts @@ -1,72 +1,58 @@ import { build5Db } from '@build-5/database'; -import { COL, Member, Network, Proposal, Space, WenError } from '@build-5/interfaces'; +import { COL, Member, Network, Space, Transaction, WEN_FUNC, WenError } from '@build-5/interfaces'; import { isEmpty } from 'lodash'; -import { validateAddress } from '../../src/runtime/firebase/address'; import { getAddress } from '../../src/utils/address.utils'; -import * as wallet from '../../src/utils/wallet.utils'; -import { getWallet, testEnv } from '../set-up'; -import { - createMember, - createSpace, - expectThrow, - mockWalletReturnValue, - submitMilestoneFunc, - validateMemberAddressFunc, - validateSpaceAddressFunc, - wait, -} from './common'; - -const waitForAddressValidation = async (id: string, col: COL) => { +import { getRandomEthAddress } from '../../src/utils/wallet.utils'; +import { getWallet, mockWalletReturnValue, testEnv } from '../set-up'; +import { expectThrow, submitMilestoneFunc, validateMemberAddressFunc, wait } from './common'; + +const waitForAddressValidation = async ( + id: string, + col: COL.SPACE | COL.MEMBER, + network = Network.RMS, +) => { await wait(async () => { - const doc = await build5Db().doc(`${col}/${id}`).get>(); - return !isEmpty(getAddress(doc, Network.IOTA)); + const data = await build5Db().doc(col, id).get(); + return !isEmpty(getAddress(data, network)); }); }; describe('Address validation test', () => { let member: string; - let space: string; - let walletSpy: any; + let space: Space; beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - member = await createMember(walletSpy); - await build5Db().doc(`${COL.MEMBER}/${member}`).update({ validatedAddress: {} }); - space = (await createSpace(walletSpy, member)).uid; - await build5Db().doc(`${COL.SPACE}/${space}`).update({ validatedAddress: {} }); + member = await testEnv.createMember(); + await build5Db().doc(COL.MEMBER, member).update({ rmsAddress: '' }); + space = await testEnv.createSpace(member); + await build5Db().doc(COL.SPACE, space.uid).update({ rmsAddress: '', iotaAddress: '' }); }); it('Should validate member address', async () => { - const order = await validateMemberAddressFunc(walletSpy, member); + const order = await validateMemberAddressFunc(member, Network.RMS); await submitMilestoneFunc(order); - await waitForAddressValidation(member, COL.MEMBER); + await waitForAddressValidation(member, COL.MEMBER, Network.RMS); }); - it.each([Network.RMS, Network.SMR])( - 'Should throw, member id is address', - async (network: Network) => { - const wallet = await getWallet(network); - const address = await wallet.getNewIotaAddressDetails(); - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${address.bech32}`); - await memberDocRef.create({ uid: address.bech32 }); - await expectThrow( - validateMemberAddressFunc(walletSpy, address.bech32, network), - WenError.can_not_change_validated_addess.key, - ); - }, - ); + it('Should throw, member id is address', async () => { + const wallet = await getWallet(Network.RMS); + const address = await wallet.getNewIotaAddressDetails(); + mockWalletReturnValue(member, { address: address.bech32 }); + const member2 = await testEnv.wrap(WEN_FUNC.createMember); + const call = validateMemberAddressFunc(member2.uid, Network.RMS); + await expectThrow(call, WenError.can_not_change_validated_addess.key); + }); it('Should validate space address', async () => { - let order = await validateSpaceAddressFunc(walletSpy, member, space); + mockWalletReturnValue(member, { space: space.uid }); + let order = await testEnv.wrap(WEN_FUNC.validateAddress); const milestone = await submitMilestoneFunc(order); - - const proposalQuery = build5Db().collection(COL.PROPOSAL).where('space', '==', space); + const proposalQuery = build5Db().collection(COL.PROPOSAL).where('space', '==', space.uid); await wait(async () => { const snap = await proposalQuery.get(); return snap.length > 0; }); - - const snap = await proposalQuery.get(); + const snap = await proposalQuery.get(); const proposal = snap[0]!; expect(proposal.questions[0].text).toBe("Do you want to update the space's validate address?"); expect(proposal.questions[0].additionalInfo).toBe( @@ -75,11 +61,11 @@ describe('Address validation test', () => { expect((proposal.settings.spaceUpdateData!.validatedAddress as any)![Network.IOTA]).toBe( milestone.fromAdd, ); - expect(proposal.settings.spaceUpdateData!.uid).toBe(space); - - await waitForAddressValidation(space, COL.SPACE); + expect(proposal.settings.spaceUpdateData!.uid).toBe(space.uid); - order = await validateSpaceAddressFunc(walletSpy, member, space); + await waitForAddressValidation(space.uid, COL.SPACE, Network.IOTA); + mockWalletReturnValue(member, { space: space.uid }); + order = await testEnv.wrap(WEN_FUNC.validateAddress); const milestone2 = await submitMilestoneFunc(order); await wait(async () => { @@ -88,50 +74,56 @@ describe('Address validation test', () => { }); await wait(async () => { - const spaceData = await build5Db().doc(`${COL.SPACE}/${space}`).get(); + const spaceData = await build5Db().doc(COL.SPACE, space.uid).get(); return getAddress(spaceData, order.network!) === milestone2.fromAdd; }); - const spaceData = await build5Db().doc(`${COL.SPACE}/${space}`).get(); + const spaceData = await build5Db().doc(COL.SPACE, space.uid).get(); expect(spaceData?.prevValidatedAddresses).toEqual([milestone.fromAdd]); }); it('Should throw, not guardian', async () => { - const randomMember = await createMember(walletSpy); - mockWalletReturnValue(walletSpy, randomMember, { space }); - await expectThrow( - testEnv.wrap(validateAddress)({}), - WenError.you_are_not_guardian_of_space.key, - ); + const randomMember = await testEnv.createMember(); + mockWalletReturnValue(randomMember, { space: space.uid }); + const call = testEnv.wrap(WEN_FUNC.validateAddress); + await expectThrow(call, WenError.you_are_not_guardian_of_space.key); }); it('Should throw, member does not exist', async () => { - mockWalletReturnValue(walletSpy, wallet.getRandomEthAddress(), { space }); - await expectThrow(testEnv.wrap(validateAddress)({}), WenError.member_does_not_exists.key); + await build5Db().doc(COL.MEMBER, member).delete(); + mockWalletReturnValue(member, { space: space.uid }); + const call = testEnv.wrap(WEN_FUNC.validateAddress); + await expectThrow(call, WenError.member_does_not_exists.key); }); it('Should throw, space does not exist', async () => { - mockWalletReturnValue(walletSpy, member, { space: wallet.getRandomEthAddress() }); - await expectThrow(testEnv.wrap(validateAddress)({}), WenError.space_does_not_exists.key); + mockWalletReturnValue(member, { + network: Network.RMS, + space: getRandomEthAddress(), + }); + const call = testEnv.wrap(WEN_FUNC.validateAddress); + await expectThrow(call, WenError.space_does_not_exists.key); }); it('Should replace member address', async () => { + const network = Network.RMS; const validate = async () => { - const order = await validateMemberAddressFunc(walletSpy, member); + const order = await validateMemberAddressFunc(member, network); await submitMilestoneFunc(order); }; await validate(); - await waitForAddressValidation(member, COL.MEMBER); - const docRef = build5Db().doc(`${COL.MEMBER}/${member}`); + await waitForAddressValidation(member, COL.MEMBER, network); + + const docRef = build5Db().doc(COL.MEMBER, member); const memberData = await docRef.get(); await validate(); await wait(async () => { const data = await docRef.get(); - return getAddress(data, Network.IOTA) !== getAddress(memberData, Network.IOTA); + return getAddress(data, network) !== getAddress(memberData, network); }); const updatedMemberData = await docRef.get(); expect(updatedMemberData.prevValidatedAddresses?.length).toBe(1); - expect(updatedMemberData.prevValidatedAddresses![0]).toBe(getAddress(memberData, Network.IOTA)); + expect(updatedMemberData.prevValidatedAddresses![0]).toBe(getAddress(memberData, network)); }); }); diff --git a/packages/functions/test/controls/auction/Helper.ts b/packages/functions/test/controls/auction/Helper.ts index 04762b2c69..9be2e307e5 100644 --- a/packages/functions/test/controls/auction/Helper.ts +++ b/packages/functions/test/controls/auction/Helper.ts @@ -1,44 +1,44 @@ -import { IDocument, build5Db } from '@build-5/database'; -import { Auction, COL, MIN_IOTA_AMOUNT, Network, Space } from '@build-5/interfaces'; +import { IDocument, PgAuction, PgAuctionUpdate, build5Db } from '@build-5/database'; +import { + Auction, + COL, + MIN_IOTA_AMOUNT, + Network, + Space, + Transaction, + WEN_FUNC, +} 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, createSpace, mockWalletReturnValue, submitMilestoneFunc } from '../common'; - +import { mockWalletReturnValue, testEnv } from '../../set-up'; +import { submitMilestoneFunc } from '../common'; export class Helper { - public spy: any = {} as any; public space: Space = {} 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 auctionDocRef: IDocument = {} as any; public beforeEach = async (now: dayjs.Dayjs) => { - this.member = await createMember(this.spy); - this.space = await createSpace(this.spy, this.member); - const memberPromises = Array.from(Array(3)).map(() => createMember(this.spy)); + this.member = await testEnv.createMember(); + this.space = await testEnv.createSpace(this.member); + const memberPromises = Array.from(Array(3)).map(() => testEnv.createMember()); this.members = await Promise.all(memberPromises); - await this.createAuction(now); }; public createAuction = async (now: dayjs.Dayjs, customAuctionParams?: { [key: string]: any }) => { - mockWalletReturnValue(this.spy, this.member, { + mockWalletReturnValue(this.member, { ...auctionRequest(this.space.uid, now), ...customAuctionParams, }); - this.auction = await testEnv.wrap(auctionCreate)({}); - this.auctionDocRef = build5Db().doc(`${COL.AUCTION}/${this.auction.uid}`); + const auc = await testEnv.wrap(WEN_FUNC.createauction); + this.auction = (await build5Db().doc(COL.AUCTION, auc.uid).get())!; + 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)({}); + mockWalletReturnValue(memberId, { auction: this.auction.uid }); + const bidOrder = await testEnv.wrap(WEN_FUNC.bidAuction); await submitMilestoneFunc(bidOrder, amount); return bidOrder; }; diff --git a/packages/functions/test/controls/auction/auction.bid.spec.ts b/packages/functions/test/controls/auction/auction.bid.spec.ts index 5f25802050..b82af8644e 100644 --- a/packages/functions/test/controls/auction/auction.bid.spec.ts +++ b/packages/functions/test/controls/auction/auction.bid.spec.ts @@ -4,15 +4,12 @@ import { AuctionType, COL, MIN_IOTA_AMOUNT, - Member, Network, - Transaction, TransactionType, } from '@build-5/interfaces'; import dayjs from 'dayjs'; import { finalizeAuctions } from '../../../src/cron/auction.cron'; import { getAddress } from '../../../src/utils/address.utils'; -import { dateToTimestamp } from '../../../src/utils/dateTime.utils'; import { getWallet } from '../../set-up'; import { wait } from '../common'; import { Helper } from './Helper'; @@ -21,10 +18,6 @@ describe('Open auction bid', () => { const h = new Helper(); const now = dayjs(); - beforeAll(async () => { - await h.beforeAll(); - }); - beforeEach(async () => { await h.beforeEach(now); }); @@ -77,9 +70,9 @@ describe('Open auction bid', () => { const credits = await build5Db() .collection(COL.TRANSACTION) - .where('member', 'in', h.members) .where('type', '==', TransactionType.CREDIT) - .get(); + .whereIn('member', h.members) + .get(); expect(credits.length).toBe(1); expect(credits[0].member).toBe(h.members[1]); }); @@ -88,20 +81,20 @@ describe('Open auction bid', () => { await h.bidOnAuction(h.members[0], 2 * MIN_IOTA_AMOUNT); await h.bidOnAuction(h.members[0], 3 * MIN_IOTA_AMOUNT); - const auctionDocRef = build5Db().doc(`${COL.AUCTION}/${h.auction.uid}`); - await auctionDocRef.update({ auctionTo: dateToTimestamp(dayjs().subtract(1, 'minute')) }); + const auctionDocRef = build5Db().doc(COL.AUCTION, h.auction.uid); + await auctionDocRef.update({ auctionTo: dayjs().subtract(1, 'minute').toDate() }); await finalizeAuctions(); - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${h.member}`); - const member = await memberDocRef.get(); + const memberDocRef = build5Db().doc(COL.MEMBER, h.member); + const member = await memberDocRef.get(); const address = getAddress(member, h.auction.network); const billPayments = await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.BILL_PAYMENT) .where('member', '==', h.members[0]) - .get(); + .get(); billPayments.sort((a, b) => a.payload.amount! - b.payload.amount!); expect(billPayments.length).toBe(2); expect(billPayments[0].payload.amount!).toBe(2 * MIN_IOTA_AMOUNT); @@ -119,8 +112,8 @@ describe('Open auction bid', () => { await h.bidOnAuction(h.members[0], 2 * MIN_IOTA_AMOUNT); await h.bidOnAuction(h.members[0], 3 * MIN_IOTA_AMOUNT); - const auctionDocRef = build5Db().doc(`${COL.AUCTION}/${h.auction.uid}`); - await auctionDocRef.update({ auctionTo: dateToTimestamp(dayjs().subtract(1, 'minute')) }); + const auctionDocRef = build5Db().doc(COL.AUCTION, h.auction.uid); + await auctionDocRef.update({ auctionTo: dayjs().subtract(1, 'minute').toDate() }); await finalizeAuctions(); @@ -128,7 +121,7 @@ describe('Open auction bid', () => { .collection(COL.TRANSACTION) .where('type', '==', TransactionType.BILL_PAYMENT) .where('member', '==', h.members[0]) - .get(); + .get(); billPayments.sort((a, b) => a.payload.amount! - b.payload.amount!); expect(billPayments.length).toBe(2); expect(billPayments[0].payload.amount!).toBe(2 * MIN_IOTA_AMOUNT); @@ -138,12 +131,12 @@ describe('Open auction bid', () => { }); it('Should finalize open auction, no bids', async () => { - const auctionDocRef = build5Db().doc(`${COL.AUCTION}/${h.auction.uid}`); - await auctionDocRef.update({ auctionTo: dateToTimestamp(dayjs().subtract(1, 'minute')) }); + const auctionDocRef = build5Db().doc(COL.AUCTION, h.auction.uid); + await auctionDocRef.update({ auctionTo: dayjs().subtract(1, 'minute').toDate() }); await finalizeAuctions(); }); - const awaitPayments = (query: IQuery, count: number) => + const awaitPayments = (query: IQuery, count: number) => wait(async () => { const snap = await query.get(); return snap.length === count; @@ -156,12 +149,12 @@ describe('Open auction bid', () => { .collection(COL.TRANSACTION) .where('type', '==', TransactionType.PAYMENT) .where('member', '==', h.members[0]) - .where('payload.invalidPayment', '==', false); + .where('payload_invalidPayment', '==', false); const invalidPaymentsQuery = build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.PAYMENT) .where('member', '==', h.members[0]) - .where('payload.invalidPayment', '==', true); + .where('payload_invalidPayment', '==', true); // Below floor, credit await h.bidOnAuction(h.members[0], 1.5 * MIN_IOTA_AMOUNT); @@ -194,12 +187,12 @@ describe('Open auction bid', () => { .collection(COL.TRANSACTION) .where('type', '==', TransactionType.PAYMENT) .where('member', '==', h.members[0]) - .where('payload.invalidPayment', '==', false); + .where('payload_invalidPayment', '==', false); const invalidPaymentsQuery = build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.PAYMENT) .where('member', '==', h.members[0]) - .where('payload.invalidPayment', '==', true); + .where('payload_invalidPayment', '==', true); // Below floor, credit await h.bidOnAuction(h.members[0], 1.5 * MIN_IOTA_AMOUNT); diff --git a/packages/functions/test/controls/collection.spec.ts b/packages/functions/test/controls/collection.spec.ts index 1ff165575c..201f92e2e7 100644 --- a/packages/functions/test/controls/collection.spec.ts +++ b/packages/functions/test/controls/collection.spec.ts @@ -5,51 +5,38 @@ import { COL, Categories, Collection, - CollectionStats, CollectionStatus, CollectionType, MIN_IOTA_AMOUNT, - Member, NetworkAddress, Nft, RANKING_TEST, + Rank, SOON_PROJECT_ID, SUB_COL, Space, StakeType, Token, + Vote, WEN_FUNC, WenError, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { chunk, set } from 'lodash'; -import { createNft } from '../../src/runtime/firebase/nft'; -import { rankController } from '../../src/runtime/firebase/rank'; -import { voteController } from '../../src/runtime/firebase/vote'; -import * as wallet from '../../src/utils/wallet.utils'; -import { soonTokenId, testEnv } from '../set-up'; -import { - createCollection, - rejectCollection, - updateCollection, -} from './../../src/runtime/firebase/collection/index'; -import { createMember } from './../../src/runtime/firebase/member'; +import { chunk, isEmpty, set } from 'lodash'; +import { dateToTimestamp } from '../../src/utils/dateTime.utils'; +import { getRandomEthAddress } from '../../src/utils/wallet.utils'; +import { mockWalletReturnValue, soonTokenId, testEnv } from '../set-up'; import { addGuardianToSpace, - createMember as createMemberFunc, createRoyaltySpaces, - createSpace as createSpaceFunc, expectThrow, getRandomSymbol, - mockWalletReturnValue, setProdTiers, setTestTiers, wait, } from './common'; -let walletSpy: any; - -const dummyCollection: any = (spaceId: string, royaltiesFee: number, noSpace = false) => { +const dummyCollection = (space: Space, royaltiesFee: number, noSpace = false) => { const data = { name: 'Collection A', description: 'babba', @@ -57,33 +44,28 @@ const dummyCollection: any = (spaceId: string, royaltiesFee: number, noSpace = f category: Categories.ART, access: Access.OPEN, royaltiesFee, - royaltiesSpace: spaceId, + royaltiesSpace: space.uid, onePerMemberOnly: false, availableFrom: dayjs().add(1, 'hour').toDate(), price: 10 * 1000 * 1000, }; if (!noSpace) { - set(data, 'space', spaceId); + set(data, 'space', space.uid); } return data; }; describe('CollectionController: ' + WEN_FUNC.createCollection, () => { - let dummyAddress: NetworkAddress; - let space: any; - let member: Member; - + let space: Space; + let member: string; beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - dummyAddress = await createMemberFunc(walletSpy); - member = await testEnv.wrap(createMember)({ address: dummyAddress }); - expect(member?.uid).toEqual(dummyAddress.toLowerCase()); - space = await createSpaceFunc(walletSpy, dummyAddress); + member = await testEnv.createMember(); + space = await testEnv.createSpace(member); }); it('successfully create collection', async () => { - mockWalletReturnValue(walletSpy, dummyAddress, dummyCollection(space.uid, 0.6)); - const collection = await testEnv.wrap(createCollection)({}); + mockWalletReturnValue(member, dummyCollection(space, 0.6)); + const collection = await testEnv.wrap(WEN_FUNC.createCollection); expect(collection?.uid).toBeDefined(); expect(collection?.createdOn).toBeDefined(); expect(collection?.approved).toBe(false); @@ -91,12 +73,11 @@ describe('CollectionController: ' + WEN_FUNC.createCollection, () => { expect(collection?.updatedOn).toBeDefined(); expect(collection?.total).toBe(0); expect(collection?.sold).toBe(0); - walletSpy.mockRestore(); }); it('successfully create collection, no space', async () => { - mockWalletReturnValue(walletSpy, dummyAddress, dummyCollection(space.uid, 0.6, true)); - const collection = await testEnv.wrap(createCollection)({}); + mockWalletReturnValue(member, dummyCollection(space, 0.6, true)); + const collection = await testEnv.wrap(WEN_FUNC.createCollection); expect(collection?.uid).toBeDefined(); expect(collection?.createdOn).toBeDefined(); expect(collection?.approved).toBe(false); @@ -105,100 +86,95 @@ describe('CollectionController: ' + WEN_FUNC.createCollection, () => { expect(collection?.total).toBe(0); expect(collection?.sold).toBe(0); expect(collection.space).toBe(''); - walletSpy.mockRestore(); }); it('Should throw, invalid icon url', async () => { - mockWalletReturnValue(walletSpy, dummyAddress, { - media: 'asd', - ...dummyCollection(space.uid, 0.6), + mockWalletReturnValue(member, { + media: 'name', + ...dummyCollection(space, 0.6), }); - await expectThrow(testEnv.wrap(createCollection)({}), WenError.invalid_params.key); - - mockWalletReturnValue(walletSpy, dummyAddress, { - media: `https://firebasestorage.googleapis.com/v0/b/${Bucket.DEV}/o/`, - ...dummyCollection(space.uid, 0.6), + let call = testEnv.wrap(WEN_FUNC.createCollection); + await expectThrow(call, WenError.invalid_params.key); + mockWalletReturnValue(member, { + media: `https://storage.googleapis.com/download/storage/v1/b/${Bucket.DEV}/o`, + ...dummyCollection(space, 0.6), }); - await expectThrow(testEnv.wrap(createCollection)({}), WenError.invalid_params.key); + call = testEnv.wrap(WEN_FUNC.createCollection); + await expectThrow(call, WenError.invalid_params.key); }); it('Should throw, no soon staked', async () => { - mockWalletReturnValue(walletSpy, dummyAddress, dummyCollection(space.uid, 0.6)); await setProdTiers(); - await expectThrow(testEnv.wrap(createCollection)({}), WenError.no_staked_soon.key); + mockWalletReturnValue(member, dummyCollection(space, 0.6)); + const call = testEnv.wrap(WEN_FUNC.createCollection); + await expectThrow(call, WenError.no_staked_soon.key); await setTestTiers(); }); it('Should create collection, soon check', async () => { await build5Db() - .doc(`${COL.TOKEN}/${soonTokenId}/${SUB_COL.DISTRIBUTION}/${dummyAddress}`) + .doc(COL.TOKEN, soonTokenId, SUB_COL.DISTRIBUTION, member) .create({ - stakes: { - [StakeType.DYNAMIC]: { - value: 10 * MIN_IOTA_AMOUNT, - }, - }, + parentId: soonTokenId, + parentCol: COL.TOKEN, + stakes: { [StakeType.DYNAMIC]: { value: 10 * MIN_IOTA_AMOUNT } }, }); - - mockWalletReturnValue(walletSpy, dummyAddress, dummyCollection(space.uid, 0.6)); await setProdTiers(); - const collection = await testEnv.wrap(createCollection)({}); + mockWalletReturnValue(member, dummyCollection(space, 0.6)); + const collection = await testEnv.wrap(WEN_FUNC.createCollection); expect(collection?.uid).toBeDefined(); await setTestTiers(); }); it('fail to create collection - wrong royalties', async () => { - mockWalletReturnValue(walletSpy, dummyAddress, dummyCollection(space.uid, 4)); - await expectThrow(testEnv.wrap(createCollection)({}), WenError.invalid_params.key); - walletSpy.mockRestore(); + mockWalletReturnValue(member, dummyCollection(space, 4)); + const call = testEnv.wrap(WEN_FUNC.createCollection); + await expectThrow(call, WenError.invalid_params.key); }); it('fail to create collection - missing royalties space', async () => { - const collection = dummyCollection(space.uid, 0.1); - delete collection.royaltiesSpace; - mockWalletReturnValue(walletSpy, dummyAddress, collection); - await expectThrow(testEnv.wrap(createCollection)({}), WenError.invalid_params.key); - walletSpy.mockRestore(); + const collection = dummyCollection(space, 0.1); + delete (collection as any).royaltiesSpace; + mockWalletReturnValue(member, dummyCollection(space, 4)); + const call = testEnv.wrap(WEN_FUNC.createCollection); + await expectThrow(call, WenError.invalid_params.key); }); it('collection does not exists for update', async () => { - mockWalletReturnValue(walletSpy, dummyAddress, { - uid: wallet.getRandomEthAddress(), + const collection = { + uid: getRandomEthAddress(), name: 'Collection A', description: 'babba', royaltiesFee: 0.6, royaltiesSpace: space.uid, - }); - await expectThrow(testEnv.wrap(updateCollection)({}), WenError.collection_does_not_exists.key); - walletSpy.mockRestore(); + }; + mockWalletReturnValue(member, collection); + const call = testEnv.wrap(WEN_FUNC.updateCollection); + await expectThrow(call, WenError.collection_does_not_exists.key); }); it('successfully create collection & update', async () => { - const collection = dummyCollection(space.uid, 0.6); - mockWalletReturnValue(walletSpy, dummyAddress, collection); - - const cCollection = await testEnv.wrap(createCollection)({}); + const collection = dummyCollection(space, 0.6); + mockWalletReturnValue(member, collection); + const cCollection = await testEnv.wrap(WEN_FUNC.createCollection); expect(cCollection?.uid).toBeDefined(); expect(cCollection?.description).toBe('babba'); - - mockWalletReturnValue(walletSpy, dummyAddress, { + const uData = { uid: cCollection?.uid, name: 'Collection A', description: '123', royaltiesFee: 0.6, royaltiesSpace: space.uid, - }); - const uCollection = await testEnv.wrap(updateCollection)({}); + }; + mockWalletReturnValue(member, uData); + const uCollection = await testEnv.wrap(WEN_FUNC.updateCollection); expect(uCollection?.uid).toBeDefined(); expect(uCollection?.description).toBe('123'); - walletSpy.mockRestore(); }); it('successfully create collection & update, no space', async () => { - mockWalletReturnValue(walletSpy, dummyAddress, dummyCollection(space.uid, 0.6, true)); - - const cCollection = await testEnv.wrap(createCollection)({}); - + mockWalletReturnValue(member, dummyCollection(space, 0.6, true)); + const cCollection = await testEnv.wrap(WEN_FUNC.createCollection); const updateData = { uid: cCollection?.uid, name: 'Collection A', @@ -206,28 +182,21 @@ describe('CollectionController: ' + WEN_FUNC.createCollection, () => { royaltiesFee: 0.6, royaltiesSpace: space.uid, }; - - const randomMember = await createMemberFunc(walletSpy); - mockWalletReturnValue(walletSpy, randomMember, updateData); - await expectThrow( - testEnv.wrap(updateCollection)({}), - WenError.you_must_be_the_creator_of_this_collection.key, - ); - - mockWalletReturnValue(walletSpy, dummyAddress, updateData); - const uCollection = await testEnv.wrap(updateCollection)({}); + const randomMember = await testEnv.createMember(); + mockWalletReturnValue(randomMember, updateData); + const call = testEnv.wrap(WEN_FUNC.updateCollection); + await expectThrow(call, WenError.you_must_be_the_creator_of_this_collection.key); + mockWalletReturnValue(member, updateData); + const uCollection = await testEnv.wrap(WEN_FUNC.updateCollection); expect(uCollection?.name).toBe(updateData.name); expect(uCollection?.description).toBe(updateData.description); - walletSpy.mockRestore(); }); it('successfully create collection & update price', async () => { - let collection = dummyCollection(space.uid, 0.6); - mockWalletReturnValue(walletSpy, dummyAddress, collection); - collection = await testEnv.wrap(createCollection)({}); - - await build5Db().doc(`${COL.COLLECTION}/${collection.uid}`).update({ approved: true }); - + let collection = dummyCollection(space, 0.6) as unknown as Collection; + mockWalletReturnValue(member, collection); + collection = await testEnv.wrap(WEN_FUNC.createCollection); + await build5Db().doc(COL.COLLECTION, collection.uid).update({ approved: true }); const dummyNft = () => ({ name: 'Collection A', description: 'babba', @@ -237,94 +206,90 @@ describe('CollectionController: ' + WEN_FUNC.createCollection, () => { }); const nfts: Nft[] = []; for (let i = 0; i < 4; ++i) { - mockWalletReturnValue(walletSpy, dummyAddress, dummyNft()); - const nft = await testEnv.wrap(createNft)({}); + mockWalletReturnValue(member, dummyNft()); + const nft = await testEnv.wrap(WEN_FUNC.createNft); nfts.push(nft); } - const availableFrom = dayjs().add(1, 'd'); - mockWalletReturnValue(walletSpy, dummyAddress, { + const updateCollection = { uid: collection?.uid, price: 15 * MIN_IOTA_AMOUNT, - name: 'asd', + name: 'name', description: '123', royaltiesFee: 0.6, royaltiesSpace: space.uid, availableFrom: availableFrom.toDate(), - }); - const uCollection = await testEnv.wrap(updateCollection)({}); + }; + mockWalletReturnValue(member, updateCollection); + const uCollection = await testEnv.wrap(WEN_FUNC.updateCollection); expect(uCollection?.uid).toBe(collection.uid); expect(uCollection?.price).toBe(15 * MIN_IOTA_AMOUNT); expect(uCollection?.availablePrice).toBe(15 * MIN_IOTA_AMOUNT); - for (let i = 0; i < 4; ++i) { - const nftDocRef = build5Db().doc(`${COL.NFT}/${nfts[i].uid}`); + const nftDocRef = build5Db().doc(COL.NFT, nfts[i].uid); const nft = await nftDocRef.get(); expect(nft.price).toBe(15 * MIN_IOTA_AMOUNT); expect(nft.availablePrice).toBe(15 * MIN_IOTA_AMOUNT); } - - walletSpy.mockRestore(); }); it('Only allow discounts, access, accessAwards, accessCollections update on minted collection', async () => { const token = await saveToken(space.uid); - const collection = dummyCollection(space.uid, 0.6); - mockWalletReturnValue(walletSpy, dummyAddress, collection); - const cCollection = await testEnv.wrap(createCollection)({}); + const collection = dummyCollection(space, 0.6); + mockWalletReturnValue(member, collection); + const cCollection = await testEnv.wrap(WEN_FUNC.createCollection); await build5Db() - .doc(`${COL.COLLECTION}/${cCollection.uid}`) + .doc(COL.COLLECTION, cCollection.uid) .update({ status: CollectionStatus.MINTED }); - - mockWalletReturnValue(walletSpy, dummyAddress, { uid: cCollection?.uid, name: 'Collection A' }); - await expectThrow(testEnv.wrap(updateCollection)({}), WenError.invalid_params.key); - - mockWalletReturnValue(walletSpy, dummyAddress, { + expect(cCollection?.access).toBe(Access.OPEN); + mockWalletReturnValue(member, { + uid: cCollection?.uid, + name: 'Collection A', + }); + await expectThrow(testEnv.wrap(WEN_FUNC.updateCollection), WenError.invalid_params.key); + mockWalletReturnValue(member, { uid: cCollection?.uid, discounts: [{ tokenSymbol: token.symbol, tokenReward: 10, amount: 0.5 }], }); - let uCollection = await testEnv.wrap(updateCollection)({}); + let uCollection = await testEnv.wrap(WEN_FUNC.updateCollection); expect(uCollection?.discounts).toEqual([ { tokenSymbol: token.symbol, tokenUid: token.uid, tokenReward: 10, amount: 0.5 }, ]); expect(uCollection?.access).toBe(Access.OPEN); - const updateAwards = { uid: cCollection?.uid, access: Access.MEMBERS_WITH_BADGE, - accessAwards: [wallet.getRandomEthAddress()], + accessAwards: [getRandomEthAddress()], }; - mockWalletReturnValue(walletSpy, dummyAddress, updateAwards); - uCollection = await testEnv.wrap(updateCollection)({}); + mockWalletReturnValue(member, updateAwards); + uCollection = await testEnv.wrap(WEN_FUNC.updateCollection); expect(uCollection?.access).toBe(Access.MEMBERS_WITH_BADGE); expect(uCollection?.accessAwards).toEqual(updateAwards.accessAwards); - const updateCollections = { uid: cCollection?.uid, access: Access.MEMBERS_WITH_NFT_FROM_COLLECTION, - accessCollections: [wallet.getRandomEthAddress()], + accessCollections: [getRandomEthAddress()], }; - mockWalletReturnValue(walletSpy, dummyAddress, updateCollections); - uCollection = await testEnv.wrap(updateCollection)({}); + mockWalletReturnValue(member, updateCollections); + uCollection = await testEnv.wrap(WEN_FUNC.updateCollection); expect(uCollection?.access).toBe(Access.MEMBERS_WITH_NFT_FROM_COLLECTION); expect(uCollection?.accessCollections).toEqual(updateCollections.accessCollections); }); it('Should not update placeholder nft when collection is minted', async () => { const token = await saveToken(space.uid); - const collection = { ...dummyCollection(space.uid, 0.6), type: CollectionType.SFT }; - mockWalletReturnValue(walletSpy, dummyAddress, collection); - const cCollection = await testEnv.wrap(createCollection)({}); + const collection = { ...dummyCollection(space, 0.6), type: CollectionType.SFT }; + mockWalletReturnValue(member, collection); + const cCollection = await testEnv.wrap(WEN_FUNC.createCollection); await build5Db() - .doc(`${COL.COLLECTION}/${cCollection.uid}`) + .doc(COL.COLLECTION, cCollection.uid) .update({ status: CollectionStatus.MINTED }); - - mockWalletReturnValue(walletSpy, dummyAddress, { + mockWalletReturnValue(member, { uid: cCollection?.uid, discounts: [{ tokenSymbol: token.symbol, tokenReward: 10, amount: 0.5 }], access: Access.GUARDIANS_ONLY, }); - let uCollection = await testEnv.wrap(updateCollection)({}); + let uCollection = await testEnv.wrap(WEN_FUNC.updateCollection); expect(uCollection?.discounts).toEqual([ { tokenSymbol: token.symbol, tokenUid: token.uid, tokenReward: 10, amount: 0.5 }, ]); @@ -333,173 +298,162 @@ describe('CollectionController: ' + WEN_FUNC.createCollection, () => { it('Should throw, discount has same tokenReward', async () => { const token = await saveToken(space.uid); - const collection = dummyCollection(space.uid, 0.6); - mockWalletReturnValue(walletSpy, dummyAddress, collection); - const cCollection = await testEnv.wrap(createCollection)({}); - - mockWalletReturnValue(walletSpy, dummyAddress, { + const collection = dummyCollection(space, 0.6); + mockWalletReturnValue(member, collection); + const cCollection = await testEnv.wrap(WEN_FUNC.createCollection); + mockWalletReturnValue(member, { uid: cCollection?.uid, discounts: [ { tokenSymbol: token.symbol, tokenReward: 10, amount: 0.5 }, { tokenSymbol: token.symbol, tokenReward: 10, amount: 0.6 }, ], }); - await expectThrow(testEnv.wrap(updateCollection)({}), WenError.invalid_params.key); + await expectThrow( + testEnv.wrap(WEN_FUNC.updateCollection), + WenError.invalid_params.key, + ); }); it('Should throw, token does not exist', async () => { - const collection = dummyCollection(space.uid, 0.6); - mockWalletReturnValue(walletSpy, dummyAddress, collection); - const cCollection = await testEnv.wrap(createCollection)({}); + const collection = dummyCollection(space, 0.6); + mockWalletReturnValue(member, collection); + const cCollection = await testEnv.wrap(WEN_FUNC.createCollection); await build5Db() - .doc(`${COL.COLLECTION}/${cCollection.uid}`) + .doc(COL.COLLECTION, cCollection.uid) .update({ status: CollectionStatus.MINTED }); - - mockWalletReturnValue(walletSpy, dummyAddress, { + mockWalletReturnValue(member, { uid: cCollection?.uid, discounts: [{ tokenSymbol: 'ASD', tokenReward: 10, amount: 0.5 }], }); - await expectThrow(testEnv.wrap(updateCollection)({}), WenError.token_does_not_exist.key); + await expectThrow( + testEnv.wrap(WEN_FUNC.updateCollection), + WenError.token_does_not_exist.key, + ); }); it('successfully create collection & approve', async () => { - mockWalletReturnValue(walletSpy, dummyAddress, dummyCollection(space.uid, 0.6)); - const cCollection = await testEnv.wrap(createCollection)({}); + mockWalletReturnValue(member, dummyCollection(space, 0.6)); + const cCollection = await testEnv.wrap(WEN_FUNC.createCollection); expect(cCollection?.uid).toBeDefined(); expect(cCollection?.description).toBe('babba'); }); it('successfully create collection & reject', async () => { - mockWalletReturnValue(walletSpy, dummyAddress, dummyCollection(space.uid, 0.6)); - const returns = await testEnv.wrap(createCollection)({}); + mockWalletReturnValue(member, dummyCollection(space, 0.6)); + const returns = await testEnv.wrap(WEN_FUNC.createCollection); expect(returns?.uid).toBeDefined(); expect(returns?.description).toBe('babba'); - - mockWalletReturnValue(walletSpy, dummyAddress, { uid: returns?.uid }); - const returns2 = await testEnv.wrap(rejectCollection)({}); + mockWalletReturnValue(member, { uid: returns?.uid }); + const returns2 = await testEnv.wrap(WEN_FUNC.rejectCollection); expect(returns2?.uid).toBeDefined(); expect(returns2?.approved).toBe(false); expect(returns2?.rejected).toBe(true); - walletSpy.mockRestore(); }); it('successfully create collection & reject, no space', async () => { - mockWalletReturnValue(walletSpy, dummyAddress, dummyCollection(space.uid, 0.6, true)); - const returns = await testEnv.wrap(createCollection)({}); - - mockWalletReturnValue(walletSpy, wallet.getRandomEthAddress(), { uid: returns?.uid }); + mockWalletReturnValue(member, dummyCollection(space, 0.6, true)); + let collection = await testEnv.wrap(WEN_FUNC.createCollection); + const randomMember = await testEnv.createMember(); + mockWalletReturnValue(randomMember, { uid: collection.uid }); await expectThrow( - testEnv.wrap(rejectCollection)({}), + testEnv.wrap(WEN_FUNC.rejectCollection), WenError.you_must_be_the_creator_of_this_collection.key, ); - - mockWalletReturnValue(walletSpy, dummyAddress, { uid: returns?.uid }); - const returns2 = await testEnv.wrap(rejectCollection)({}); - expect(returns2?.uid).toBeDefined(); - expect(returns2?.approved).toBe(false); - expect(returns2?.rejected).toBe(true); - walletSpy.mockRestore(); + mockWalletReturnValue(member, { uid: collection.uid }); + collection = await testEnv.wrap(WEN_FUNC.rejectCollection); + expect(collection.uid).toBeDefined(); + expect(collection.approved).toBe(false); + expect(collection.rejected).toBe(true); }); it('Any guardian can update collection after approved', async () => { - const secondGuardian = await createMemberFunc(walletSpy); + const secondGuardian = await testEnv.createMember(); await addGuardianToSpace(space.uid, secondGuardian); - - mockWalletReturnValue(walletSpy, dummyAddress, dummyCollection(space.uid, 0.6)); - const cCollection = await testEnv.wrap(createCollection)({}); - + mockWalletReturnValue(member, dummyCollection(space, 0.6)); + const cCollection = await testEnv.wrap(WEN_FUNC.createCollection); const updateData = { uid: cCollection?.uid, - name: 'asd', + name: 'name', description: '123', royaltiesFee: 0.6, royaltiesSpace: space.uid, }; - mockWalletReturnValue(walletSpy, secondGuardian, updateData); + mockWalletReturnValue(secondGuardian, updateData); await expectThrow( - testEnv.wrap(updateCollection)({}), + testEnv.wrap(WEN_FUNC.updateCollection), WenError.you_must_be_the_creator_of_this_collection.key, ); - - await build5Db().doc(`${COL.COLLECTION}/${cCollection?.uid}`).update({ approved: true }); - - mockWalletReturnValue(walletSpy, secondGuardian, updateData); - const uCollection = await testEnv.wrap(updateCollection)({}); + await build5Db().doc(COL.COLLECTION, cCollection?.uid).update({ approved: true }); + mockWalletReturnValue(secondGuardian, updateData); + const uCollection = await testEnv.wrap(WEN_FUNC.updateCollection); expect(uCollection?.uid).toBeDefined(); - expect(uCollection?.name).toBe('asd'); - - walletSpy.mockRestore(); + expect(uCollection?.name).toBe('name'); }); }); describe('Collection trigger test', () => { it('Should set approved&reject properly on nfts', async () => { + const member = await testEnv.createMember(); + const space = await testEnv.createSpace(member); const collection = { - ...dummyCollection('', 0.1), + ...dummyCollection(space, 0.1), project: SOON_PROJECT_ID, - uid: wallet.getRandomEthAddress(), + uid: getRandomEthAddress(), }; - await build5Db().doc(`${COL.COLLECTION}/${collection.uid}`).create(collection); - + await build5Db() + .doc(COL.COLLECTION, collection.uid) + .create({ + ...collection, + availableFrom: dateToTimestamp(collection.availableFrom), + } as Collection); const nftIds = Array.from(Array(1000)); const chunks = chunk(nftIds, 500); for (let chunkIndex = 0; chunkIndex < chunks.length; ++chunkIndex) { const batch = build5Db().batch(); - chunks[chunkIndex].forEach((_, index) => { - const id = wallet.getRandomEthAddress(); - batch.create(build5Db().doc(`${COL.NFT}/${id}`), { - ...dummyNft(chunkIndex * 500 + index, id, collection.uid), + const promises = chunks[chunkIndex].map(async (_, index) => { + const id = getRandomEthAddress(); + const nft = dummyNft(chunkIndex * 500 + index, id, collection.uid); + batch.create(build5Db().doc(COL.NFT, id), { + ...nft, + availableFrom: dateToTimestamp(nft.availableFrom), project: SOON_PROJECT_ID, - }); + } as unknown as Nft); }); + await Promise.all(promises); await batch.commit(); } - - await build5Db().doc(`${COL.COLLECTION}/${collection.uid}`).update({ - approved: true, - }); - + await build5Db().doc(COL.COLLECTION, collection.uid).update({ approved: true }); await wait(async () => { const snap = await build5Db() .collection(COL.NFT) .where('collection', '==', collection.uid) - .get(); + .get(); const allHaveUpdated = snap.reduce((acc, act) => acc && act.approved, true); return allHaveUpdated; }); - - await build5Db().doc(`${COL.COLLECTION}/${collection.uid}`).update({ - approved: false, - }); - await build5Db().doc(`${COL.COLLECTION}/${collection.uid}`).update({ - approved: true, - }); - + await build5Db().doc(COL.COLLECTION, collection.uid).update({ approved: false }); + await build5Db().doc(COL.COLLECTION, collection.uid).update({ approved: true }); await wait(async () => { const snap = await build5Db() .collection(COL.NFT) .where('collection', '==', collection.uid) - .get(); + .get(); const allHaveUpdated = snap.reduce((acc, act) => acc && act.approved, true); return allHaveUpdated; }); - - await build5Db().doc(`${COL.COLLECTION}/${collection.uid}`).update({ - approved: false, - rejected: true, - }); - + await build5Db() + .doc(COL.COLLECTION, collection.uid) + .update({ approved: false, rejected: true }); await wait(async () => { const snap = await build5Db() .collection(COL.NFT) .where('collection', '==', collection.uid) - .get(); + .get(); const allHaveUpdated = snap.reduce((acc, act) => acc && !act.approved && act.rejected, true); return allHaveUpdated; }); }); }); - const dummyNft = (index: number, uid: string, collection: string, description = 'babba') => ({ uid, name: 'Nft ' + index, @@ -510,54 +464,56 @@ const dummyNft = (index: number, uid: string, collection: string, description = }); describe('Collection vote test', () => { - let memberAddress: NetworkAddress; + let member: NetworkAddress; let space: Space; let collection: any; - beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - memberAddress = await createMemberFunc(walletSpy); - space = await createSpaceFunc(walletSpy, memberAddress); - - mockWalletReturnValue(walletSpy, memberAddress, dummyCollection(space.uid, 0.6)); - collection = await testEnv.wrap(createCollection)({}); + member = await testEnv.createMember(); + space = await testEnv.createSpace(member); + mockWalletReturnValue(member, dummyCollection(space, 0.6)); + collection = await testEnv.wrap(WEN_FUNC.createCollection); }); it('Should throw, no collection', async () => { - mockWalletReturnValue(walletSpy, memberAddress, { + mockWalletReturnValue(member, { collection: COL.COLLECTION, - uid: wallet.getRandomEthAddress(), + uid: getRandomEthAddress(), direction: 1, }); - await expectThrow(testEnv.wrap(voteController)({}), WenError.collection_does_not_exists.key); + await expectThrow( + testEnv.wrap(WEN_FUNC.voteController), + WenError.collection_does_not_exists.key, + ); }); it('Should throw, invalid direction', async () => { - mockWalletReturnValue(walletSpy, memberAddress, { + mockWalletReturnValue(member, { collection: COL.COLLECTION, uid: collection.uid, direction: 2, }); - await expectThrow(testEnv.wrap(voteController)({}), WenError.invalid_params.key); + await expectThrow(testEnv.wrap(WEN_FUNC.voteController), WenError.invalid_params.key); }); it('Should throw, no soons staked', async () => { await setProdTiers(); - mockWalletReturnValue(walletSpy, memberAddress, { + mockWalletReturnValue(member, { collection: COL.COLLECTION, uid: collection.uid, direction: 1, }); - await expectThrow(testEnv.wrap(voteController)({}), WenError.no_staked_soon.key); + await expectThrow(testEnv.wrap(WEN_FUNC.voteController), WenError.no_staked_soon.key); await setTestTiers(); }); - const validateStats = async (upvotes: number, downvotes: number, diff: number) => { await wait(async () => { const statsDocRef = build5Db().doc( - `${COL.COLLECTION}/${collection.uid}/${SUB_COL.STATS}/${collection.uid}`, + COL.COLLECTION, + collection.uid, + SUB_COL.STATS, + collection.uid, ); - const stats = await statsDocRef.get(); + const stats = await statsDocRef.get(); return ( stats?.votes?.upvotes === upvotes && stats?.votes?.downvotes === downvotes && @@ -565,34 +521,30 @@ describe('Collection vote test', () => { ); }); }; - const sendVote = async (direction: number) => { - mockWalletReturnValue(walletSpy, memberAddress, { + mockWalletReturnValue(member, { collection: COL.COLLECTION, uid: collection.uid, direction, }); - const vote = await testEnv.wrap(voteController)({}); - expect(vote.uid).toBe(memberAddress); + const vote = await testEnv.wrap(WEN_FUNC.voteController); + expect(vote.uid).toBe(member); expect(vote.parentId).toBe(collection.uid); expect(vote.parentCol).toBe(COL.COLLECTION); expect(vote.direction).toBe(direction); }; - it('Should vote', async () => { await sendVote(1); await validateStats(1, 0, 1); - await sendVote(-1); await validateStats(0, 1, -1); - - mockWalletReturnValue(walletSpy, memberAddress, { + mockWalletReturnValue(member, { collection: COL.COLLECTION, uid: collection.uid, direction: 0, }); - const vote = await testEnv.wrap(voteController)({}); - expect(vote).toBe(undefined); + const vote = await testEnv.wrap(WEN_FUNC.voteController); + expect(isEmpty(vote)).toBe(true); }); }); @@ -600,80 +552,79 @@ describe('Collection rank test', () => { let member: string; let space: Space; let collection: any; - beforeAll(async () => { await createRoyaltySpaces(); }); - beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - member = await createMemberFunc(walletSpy); - space = await createSpaceFunc(walletSpy, member); - - mockWalletReturnValue(walletSpy, member, dummyCollection(space.uid, 0.6)); - collection = await testEnv.wrap(createCollection)({}); - + member = await testEnv.createMember(); + space = await testEnv.createSpace(member); + mockWalletReturnValue(member, dummyCollection(space, 0.6)); + collection = await testEnv.wrap(WEN_FUNC.createCollection); await build5Db() - .doc(`${COL.SPACE}/${RANKING_TEST.collectionSpace}/${SUB_COL.GUARDIANS}/${member}`) - .set({ - uid: member, - parentId: RANKING_TEST.collectionSpace, - parentCol: COL.SPACE, - }); + .doc(COL.SPACE, RANKING_TEST.collectionSpace, SUB_COL.GUARDIANS, member) + .upsert({ parentId: RANKING_TEST.collectionSpace }); }); it('Should throw, no collection', async () => { - mockWalletReturnValue(walletSpy, member, { + mockWalletReturnValue(member, { collection: COL.COLLECTION, - uid: wallet.getRandomEthAddress(), + uid: getRandomEthAddress(), rank: 1, }); - await expectThrow(testEnv.wrap(rankController)({}), WenError.collection_does_not_exists.key); + await expectThrow( + testEnv.wrap(WEN_FUNC.rankController), + WenError.collection_does_not_exists.key, + ); }); it('Should throw, invalid rank', async () => { - mockWalletReturnValue(walletSpy, member, { + mockWalletReturnValue(member, { collection: COL.COLLECTION, uid: collection.uid, rank: 200, }); - await expectThrow(testEnv.wrap(rankController)({}), WenError.invalid_params.key); + await expectThrow(testEnv.wrap(WEN_FUNC.rankController), WenError.invalid_params.key); }); it('Should throw, no soons staked', async () => { - mockWalletReturnValue(walletSpy, member, { + await setProdTiers(); + mockWalletReturnValue(member, { collection: COL.COLLECTION, uid: collection.uid, rank: 1, }); - await setProdTiers(); - await expectThrow(testEnv.wrap(rankController)({}), WenError.no_staked_soon.key); + await expectThrow(testEnv.wrap(WEN_FUNC.rankController), WenError.no_staked_soon.key); await setTestTiers(); }); it('Should throw, not space member', async () => { await build5Db() - .doc(`${COL.SPACE}/${RANKING_TEST.collectionSpace}/${SUB_COL.GUARDIANS}/${member}`) + .doc(COL.SPACE, RANKING_TEST.collectionSpace, SUB_COL.GUARDIANS, member) .delete(); - - mockWalletReturnValue(walletSpy, member, { + mockWalletReturnValue(member, { collection: COL.COLLECTION, uid: collection.uid, rank: 1, }); - await expectThrow(testEnv.wrap(rankController)({}), WenError.you_are_not_guardian_of_space.key); + await expectThrow( + testEnv.wrap(WEN_FUNC.rankController), + WenError.you_are_not_guardian_of_space.key, + ); }); - const validateStats = async (count: number, sum: number) => { await wait(async () => { - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${collection.uid}`); - const statsDocRef = collectionDocRef.collection(SUB_COL.STATS).doc(collection.uid); - const stats = await statsDocRef.get(); + const collectionDocRef = build5Db().doc(COL.COLLECTION, collection.uid); + const statsDocRef = build5Db().doc( + COL.COLLECTION, + collection.uid, + SUB_COL.STATS, + collection.uid, + ); + const stats = await statsDocRef.get(); const statsAreCorrect = stats?.ranks?.count === count && stats?.ranks?.sum === sum && stats?.ranks?.avg === Number((stats?.ranks?.sum! / stats?.ranks?.count!).toFixed(3)); - collection = await collectionDocRef.get(); return ( statsAreCorrect && @@ -683,55 +634,45 @@ describe('Collection rank test', () => { ); }); }; - const sendRank = async (rankValue: number, memberAddress?: string) => { - mockWalletReturnValue(walletSpy, memberAddress || member, { + mockWalletReturnValue(memberAddress || member, { collection: COL.COLLECTION, uid: collection.uid, rank: rankValue, }); - const rank = await testEnv.wrap(rankController)({}); + const rank = await testEnv.wrap(WEN_FUNC.rankController); expect(rank.uid).toBe(memberAddress || member); expect(rank.parentId).toBe(collection.uid); expect(rank.parentCol).toBe(COL.COLLECTION); expect(rank.rank).toBe(rankValue); }; - it('Should rank', async () => { await sendRank(100); await validateStats(1, 100); - await sendRank(-100); await validateStats(1, -100); - - const secondMember = await createMemberFunc(walletSpy); + const secondMember = await testEnv.createMember(); await build5Db() - .doc(`${COL.SPACE}/${RANKING_TEST.collectionSpace}/${SUB_COL.GUARDIANS}/${secondMember}`) - .set({ - uid: secondMember, - parentId: RANKING_TEST.collectionSpace, - parentCol: COL.SPACE, - }); - + .doc(COL.SPACE, RANKING_TEST.collectionSpace, SUB_COL.GUARDIANS, secondMember) + .upsert({ parentId: RANKING_TEST.collectionSpace }); await sendRank(-50, secondMember); await validateStats(2, -150); - await wait(async () => { - const doc = await build5Db().doc(`${COL.COLLECTION}/${collection.uid}`).get(); - return !doc.approved && doc.rejected; + const doc = await build5Db().doc(COL.COLLECTION, collection.uid).get(); + return !doc!.approved && doc!.rejected; }); }); }); - const saveToken = async (space: string) => { const token = { project: SOON_PROJECT_ID, - uid: wallet.getRandomEthAddress(), + uid: getRandomEthAddress(), symbol: getRandomSymbol(), approved: true, space, name: 'MyToken', }; - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).set(token); - return token; + const docRef = build5Db().doc(COL.TOKEN, token.uid); + await docRef.upsert(token); + return await docRef.get(); }; diff --git a/packages/functions/test/controls/common.ts b/packages/functions/test/controls/common.ts index 9e1dcfa14e..f44b0c90da 100644 --- a/packages/functions/test/controls/common.ts +++ b/packages/functions/test/controls/common.ts @@ -1,74 +1,35 @@ import { build5Db } from '@build-5/database'; import { COL, - DecodedToken, MIN_IOTA_AMOUNT, Network, - NetworkAddress, SOON_PROJECT_ID, SUB_COL, - Space, TOKEN_SALE_TEST, - Token, - TokenDistribution, TokenStatus, Transaction, TransactionPayloadType, TransactionType, + WEN_FUNC, getMilestoneCol, } from '@build-5/interfaces'; import { TransactionPayload, UTXOInput, Utils } from '@iota/sdk'; import dayjs from 'dayjs'; -import { validateAddress } from '../../src/runtime/firebase/address'; -import { createMember as createMemberFunc } from '../../src/runtime/firebase/member'; -import { createSpace as createSpaceFunc } from '../../src/runtime/firebase/space/index'; +import { createSpaceControl } from '../../src/controls/space/space.create.control'; import { packBasicOutput } from '../../src/utils/basic-output.utils'; import { createUnlock, packEssence } from '../../src/utils/block.utils'; import * as config from '../../src/utils/config.utils'; import * as ipUtils from '../../src/utils/ip.utils'; import * as wallet from '../../src/utils/wallet.utils'; -import { MEDIA, getWallet, testEnv } from '../set-up'; +import { getRandomEthAddress } from '../../src/utils/wallet.utils'; +import { MEDIA, getWallet, mockWalletReturnValue, testEnv } from '../set-up'; -export const mockWalletReturnValue = ( - walletSpy: any, - address: NetworkAddress, - body: T, - noProject = false, -) => { - const decodedToken: DecodedToken = { address, body, project: noProject ? '' : SOON_PROJECT_ID }; - return walletSpy.mockReturnValue(Promise.resolve(decodedToken)); -}; - -export const expectThrow = async (call: C | Promise, error: E, message?: string) => { - try { - await call; - fail(); - } catch (e: any) { - expect(e.key).toBe(error); - if (message) { - expect(e.message).toBe(message); - } - } -}; - -export const milestoneProcessed = async ( - nextMilestone: string, - defTranId: string, - network: Network, -) => { - for (let attempt = 0; attempt < 400; ++attempt) { - await new Promise((r) => setTimeout(r, 500)); - const milestoneTranDocRef = build5Db() - .collection(getMilestoneCol(network)) - .doc(nextMilestone) - .collection(SUB_COL.TRANSACTIONS) - .doc(defTranId); - const doc = await milestoneTranDocRef.get>(); - if (doc?.processed) { - return; - } - } - throw new Error('Milestone was not processed. Id: ' + nextMilestone); +export const validateMemberAddressFunc = async (member: string, network = Network.RMS) => { + mockWalletReturnValue(member, { network }); + const order = await testEnv.wrap(WEN_FUNC.validateAddress); + expect(order?.type).toBe(TransactionType.ORDER); + expect(order?.payload.type).toBe(TransactionPayloadType.MEMBER_ADDRESS_VALIDATION); + return order; }; export const submitMilestoneFunc = async (order: Transaction, customAmount?: number) => { @@ -76,9 +37,7 @@ export const submitMilestoneFunc = async (order: Transaction, customAmount?: num const network = order.network || Network.IOTA; const to = order.payload.targetAddress!; const walletService = await getWallet(network); - const from = await walletService.getNewIotaAddressDetails(); - const consumedOutputId = '0xbdb062b39e38c3ea0b37c32d564ee839da4e1d66ceb035a56ed1e87caa3fc5950000'; const consumedOutputs = await packBasicOutput(walletService, from.bech32, amount, {}); const inputs = [UTXOInput.fromOutputId(consumedOutputId)]; @@ -87,91 +46,40 @@ export const submitMilestoneFunc = async (order: Transaction, customAmount?: num const essence = await packEssence(walletService, inputs, inputsCommitment, outputs, {}); const unlocks = [await createUnlock(essence, from)]; const payload = new TransactionPayload(essence, unlocks); - - const milestoneColl = getMilestoneCol(network); - const nextMilestone = wallet.getRandomEthAddress(); - const defTranId = wallet.getRandomEthAddress(); - const tranDocRef = build5Db() - .doc(`${milestoneColl}/${nextMilestone}`) - .collection(SUB_COL.TRANSACTIONS) - .doc(defTranId); - await tranDocRef.set({ - uid: defTranId, + const milestoneCol = getMilestoneCol(network); + const nextMilestone = Math.floor(Math.random() * MIN_IOTA_AMOUNT).toString(); + const defTranId = getRandomEthAddress(); + const tranDocRef = build5Db().doc(milestoneCol, nextMilestone, SUB_COL.TRANSACTIONS, defTranId); + await tranDocRef.upsert({ createdOn: dayjs().toDate(), - blockId: wallet.getRandomEthAddress(), - milestone: wallet.getRandomEthAddress(), - payload: JSON.parse(JSON.stringify(payload)), + blockId: getRandomEthAddress(), + milestone: Number(nextMilestone), + payload: JSON.stringify(payload), }); - await tranDocRef.update({ complete: true }); - await milestoneProcessed(nextMilestone, defTranId, network); - return { milestone: nextMilestone, tranId: defTranId, fromAdd: from.bech32 }; }; -export const validateSpaceAddressFunc = async ( - spy: any, - adr: string, - space: string, - network?: Network, +export const milestoneProcessed = async ( + nextMilestone: string, + defTranId: string, + network: Network, ) => { - mockWalletReturnValue(spy, adr, network ? { space, network } : { space }); - const order = await testEnv.wrap(validateAddress)({}); - expect(order?.type).toBe(TransactionType.ORDER); - expect(order?.payload.type).toBe(TransactionPayloadType.SPACE_ADDRESS_VALIDATION); - return order; -}; - -export const validateMemberAddressFunc = async (spy: any, adr: string, network?: Network) => { - mockWalletReturnValue(spy, adr, network ? { network } : {}); - const order = await testEnv.wrap(validateAddress)({}); - expect(order?.type).toBe(TransactionType.ORDER); - expect(order?.payload.type).toBe(TransactionPayloadType.MEMBER_ADDRESS_VALIDATION); - return order; -}; - -export const createMember = async (spy: any): Promise => { - const memberAddress = wallet.getRandomEthAddress(); - mockWalletReturnValue(spy, memberAddress, {}); - await testEnv.wrap(createMemberFunc)({ address: memberAddress }); - for (const network of Object.values(Network)) { - const wallet = await getWallet(network); - const address = await wallet.getNewIotaAddressDetails(); - await build5Db() - .doc(`${COL.MEMBER}/${memberAddress}`) - .update({ [`validatedAddress.${network}`]: address.bech32, name: getRandomSymbol() }); - } - return memberAddress; -}; - -export const createSpace = async (spy: any, guardian: string): Promise => { - mockWalletReturnValue(spy, guardian, { name: 'Space A', bannerUrl: MEDIA }); - const space = await testEnv.wrap(createSpaceFunc)({}); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${space.uid}`); - for (const network of Object.values(Network)) { - const wallet = await getWallet(network); - const address = await wallet.getNewIotaAddressDetails(); - await spaceDocRef.update({ [`validatedAddress.${network}`]: address.bech32 }); - } - return await spaceDocRef.get(); -}; - -export const tokenProcessed = (tokenId: string, distributionLength: number, reconciled: boolean) => - wait(async () => { - const doc = await build5Db().doc(`${COL.TOKEN}/${tokenId}`).get(); - const distributionsSnap = await build5Db() - .doc(`${COL.TOKEN}/${tokenId}`) - .collection(SUB_COL.DISTRIBUTION) - .get(); - const distributionsOk = distributionsSnap.reduce( - (acc, doc) => acc && (doc?.reconciled || false) === reconciled, - distributionLength === distributionsSnap.length, + for (let attempt = 0; attempt < 400; ++attempt) { + await new Promise((r) => setTimeout(r, 500)); + const milestoneTranDocRef = build5Db().doc( + getMilestoneCol(network), + nextMilestone, + SUB_COL.TRANSACTIONS, + defTranId, ); - if (doc?.status === TokenStatus.ERROR) { - throw new Error('Token not processed: ' + tokenId); + const doc = await milestoneTranDocRef.get(); + if (doc?.processed) { + return; } - return distributionsOk && doc?.status === TokenStatus.PRE_MINTED; - }); + } + throw new Error('Milestone was not processed. Id: ' + nextMilestone); +}; export const wait = async ( func: () => Promise, @@ -187,93 +95,125 @@ export const wait = async ( throw new Error('Timeout'); }; -const isProdSpy = jest.spyOn(config, 'isProdEnv'); -const blockedCountriesSpy = jest.spyOn(ipUtils, 'getBlockedCountries'); -const ipInfoMock = jest.spyOn(ipUtils, 'getIpInfo'); - -export const mockIpCheck = ( - isProdEnv: boolean, - blockedCountries: { [key: string]: string[] }, - ipInfo: any, -) => { - isProdSpy.mockReturnValueOnce(isProdEnv); - blockedCountriesSpy.mockReturnValueOnce(blockedCountries); - ipInfoMock.mockReturnValueOnce(ipInfo); +export const setProdTiers = async () => { + const soonProjDocRef = build5Db().doc(COL.PROJECT, SOON_PROJECT_ID); + const soonProject = { + config_tiers: [0, 10, 4000, 6000, 15000].map((v) => v * MIN_IOTA_AMOUNT), + config_tokenTradingFeeDiscountPercentage: [0, 25, 50, 75, 100], + }; + await soonProjDocRef.upsert(soonProject); }; +export const setTestTiers = async () => { + const soonProjDocRef = build5Db().doc(COL.PROJECT, SOON_PROJECT_ID); + const soonProject = { + config_tiers: [0, 0, 0, 0, 0].map((v) => v * MIN_IOTA_AMOUNT), + config_tokenTradingFeeDiscountPercentage: [0, 0, 0, 0, 0], + }; + await soonProjDocRef.upsert(soonProject); +}; const alphabet = 'abcdefghijklmnopqrstuvwxyz'; + export const getRandomSymbol = () => Array.from(Array(4)) .map(() => alphabet[Math.floor(Math.random() * alphabet.length)]) .join('') .toUpperCase(); +export const expectThrow = async (call: Promise, error: string, message = '') => { + try { + await call; + fail(); + } catch (e: any) { + expect(e.key || e.eKey).toBe(error); + if (message) { + expect(e.message || e.eMessage).toBe(message); + } + } +}; + +export const addGuardianToSpace = async (space: string, member: string) => { + const guardianDocRef = build5Db().doc(COL.SPACE, space, SUB_COL.GUARDIANS, member); + const guardian = await guardianDocRef.get(); + if (guardian) { + return; + } + await guardianDocRef.upsert({ parentId: space }); + await build5Db() + .doc(COL.SPACE, space) + .update({ totalGuardians: build5Db().inc(1), totalMembers: build5Db().inc(1) }); +}; + export const createRoyaltySpaces = async () => { + const guardian = await testEnv.createMember(); const spaceOneId = TOKEN_SALE_TEST.spaceone; const spaceTwoId = TOKEN_SALE_TEST.spacetwo; - const walletSpy = jest.spyOn(wallet, 'decodeAuth'); - const guardian = await createMember(walletSpy); - const spaceIdSpy = jest.spyOn(wallet, 'getRandomEthAddress'); - const spaceOneDoc = await build5Db().doc(`${COL.SPACE}/${spaceOneId}`).get(); - if (!spaceOneDoc) { + const spaceOneDoc = build5Db().doc(COL.SPACE, spaceOneId); + if (!(await spaceOneDoc.get())) { spaceIdSpy.mockReturnValue(spaceOneId); - await createSpace(walletSpy, guardian); + mockWalletReturnValue(guardian, { name: 'Space A', bannerUrl: MEDIA }); + await testEnv.mockWrap(createSpaceControl); + const addresses = {} as any; + const promises = Object.values(Network).map(async (network) => { + const wallet = await getWallet(network); + const address = await wallet.getNewIotaAddressDetails(); + addresses[`${network}Address`] = address.bech32; + }); + await Promise.all(promises); + await spaceOneDoc.update(addresses); } - - const spaceTwoDoc = await build5Db().doc(`${COL.SPACE}/${spaceTwoId}`).get(); - if (!spaceTwoDoc) { + const spaceTwoDoc = build5Db().doc(COL.SPACE, spaceTwoId); + if (!(await spaceTwoDoc.get())) { spaceIdSpy.mockReturnValue(spaceTwoId); - await createSpace(walletSpy, guardian); + mockWalletReturnValue(guardian, { name: 'Space A', bannerUrl: MEDIA }); + await testEnv.mockWrap(createSpaceControl); + const addresses = {} as any; + const promises = Object.values(Network).map(async (network) => { + const wallet = await getWallet(network); + const address = await wallet.getNewIotaAddressDetails(); + addresses[`${network}Address`] = address.bech32; + }); + await Promise.all(promises); + await spaceTwoDoc.update(addresses); } - spaceIdSpy.mockRestore(); - walletSpy.mockRestore(); -}; - -export const addGuardianToSpace = async (space: string, member: string) => { - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${space}`); - const guardianDocRef = spaceDocRef.collection(SUB_COL.GUARDIANS).doc(member); - const guardian = await guardianDocRef.get(); - if (guardian) { - return; - } - await guardianDocRef.set({ - uid: member, - parentId: space, - parentCol: COL.SPACE, - }); - await spaceDocRef.update({ totalGuardians: build5Db().inc(1), totalMembers: build5Db().inc(1) }); }; export const removeGuardianFromSpace = async (space: string, member: string) => { - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${space}`); - const guardianDocRef = spaceDocRef.collection(SUB_COL.GUARDIANS).doc(member); + const spaceDocRef = build5Db().doc(COL.SPACE, space); + const guardianDocRef = build5Db().doc(COL.SPACE, space, SUB_COL.GUARDIANS, member); await guardianDocRef.delete(); await spaceDocRef.update({ totalGuardians: build5Db().inc(-1), - totalMembers: build5Db().inc(-11), + totalMembers: build5Db().inc(-1), }); }; -export const setProdTiers = async () => { - const soonProjDocRef = build5Db().doc(`${COL.PROJECT}/${SOON_PROJECT_ID}`); - const soonProject = { - config: { - tiers: [0, 10, 4000, 6000, 15000].map((v) => v * MIN_IOTA_AMOUNT), - tokenTradingFeeDiscountPercentage: [0, 25, 50, 75, 100], - }, - }; - await soonProjDocRef.set(soonProject, true); -}; - -export const setTestTiers = async () => { - const soonProjDocRef = build5Db().doc(`${COL.PROJECT}/${SOON_PROJECT_ID}`); - const soonProject = { - config: { - tiers: [0, 0, 0, 0, 0].map((v) => v * MIN_IOTA_AMOUNT), - tokenTradingFeeDiscountPercentage: [0, 0, 0, 0, 0], - }, - }; - await soonProjDocRef.set(soonProject, true); +export const tokenProcessed = (tokenId: string, distributionLength: number, reconciled: boolean) => + wait(async () => { + const doc = await build5Db().doc(COL.TOKEN, tokenId).get(); + const distributionsSnap = await build5Db() + .collection(COL.TOKEN, tokenId, SUB_COL.DISTRIBUTION) + .get(); + const distributionsOk = distributionsSnap.reduce( + (acc, doc) => acc && (doc?.reconciled || false) === reconciled, + distributionLength === distributionsSnap.length, + ); + if (doc?.status === TokenStatus.ERROR) { + throw new Error('Token not processed: ' + tokenId); + } + return distributionsOk && doc?.status === TokenStatus.PRE_MINTED; + }); +const isProdSpy = jest.spyOn(config, 'isProdEnv'); +const blockedCountriesSpy = jest.spyOn(ipUtils, 'getBlockedCountries'); +const ipInfoMock = jest.spyOn(ipUtils, 'getIpInfo'); +export const mockIpCheck = ( + isProdEnv: boolean, + blockedCountries: { [key: string]: string[] }, + ipInfo: any, +) => { + isProdSpy.mockReturnValueOnce(isProdEnv); + blockedCountriesSpy.mockReturnValueOnce(blockedCountries); + ipInfoMock.mockReturnValueOnce(ipInfo); }; diff --git a/packages/functions/test/controls/member.spec.ts b/packages/functions/test/controls/member.spec.ts index 0230cf533e..e0ff4479e5 100644 --- a/packages/functions/test/controls/member.spec.ts +++ b/packages/functions/test/controls/member.spec.ts @@ -1,6 +1,7 @@ import { build5Db } from '@build-5/database'; import { COL, + Member, Nft, NftAvailable, NftStatus, @@ -8,101 +9,86 @@ import { WEN_FUNC, WenError, } from '@build-5/interfaces'; -import { createMember, updateMember } from '../../src/runtime/firebase/member'; -import * as wallet from '../../src/utils/wallet.utils'; -import { MEDIA, testEnv } from '../../test/set-up'; -import { expectThrow, mockWalletReturnValue } from './common'; +import { getRandomEthAddress } from '../../src/utils/wallet.utils'; +import { MEDIA, mockWalletReturnValue, testEnv } from '../set-up'; +import { expectThrow } from './common'; -let walletSpy: any; - -describe('MemberController: ' + WEN_FUNC.createMember, () => { +describe('Member control - create', () => { it('successfully create member', async () => { - const dummyAddress = wallet.getRandomEthAddress(); - const member = await testEnv.wrap(createMember)({ address: dummyAddress }); - expect(member?.uid).toEqual(dummyAddress.toLowerCase()); + const uid = await testEnv.createMember(); + const memberDocRef = build5Db().doc(COL.MEMBER, uid); + const member = await memberDocRef.get(); + expect(member?.uid).toEqual(uid.toLowerCase()); expect(member?.createdOn).toBeDefined(); expect(member?.updatedOn).toBeDefined(); }); }); -describe('MemberController: ' + WEN_FUNC.updateMember, () => { - let dummyAddress: any; - let doc: any; - +describe('Member control - update', () => { + let member: string; beforeEach(async () => { - dummyAddress = wallet.getRandomEthAddress(); - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - mockWalletReturnValue(walletSpy, dummyAddress, {}); - doc = await testEnv.wrap(createMember)({ address: dummyAddress }); - expect(doc?.uid).toEqual(dummyAddress.toLowerCase()); + member = await testEnv.createMember(); }); it('successfully update member', async () => { const updateParams = { - name: wallet.getRandomEthAddress(), + name: getRandomEthAddress(), about: 'He rocks', discord: 'adamkun#1233', twitter: 'asdasd', github: 'asdasda', }; - mockWalletReturnValue(walletSpy, dummyAddress, updateParams); - const uMember: any = await testEnv.wrap(updateMember)({}); - expect(uMember?.name).toEqual(updateParams.name); - expect(uMember?.about).toEqual('He rocks'); - expect(uMember?.discord).toEqual(updateParams.discord); - expect(uMember?.twitter).toEqual(updateParams.twitter); - expect(uMember?.github).toEqual(updateParams.github); - walletSpy.mockRestore(); + mockWalletReturnValue(member, updateParams); + const updated = await testEnv.wrap(WEN_FUNC.updateMember); + expect(updated.name).toEqual(updateParams.name); + expect(updated.about).toEqual(updateParams.about); + expect(updated.discord).toEqual(updateParams.discord); + expect(updated.twitter).toEqual(updateParams.twitter); + expect(updated.github).toEqual(updateParams.github); }); it('fail to update member username exists already', async () => { const updateParams = { name: 'abcd' + Math.floor(Math.random() * 1000) }; - mockWalletReturnValue(walletSpy, dummyAddress, updateParams); - const uMember = await testEnv.wrap(updateMember)({}); - expect(uMember?.name).toEqual(updateParams.name); - - const dummyAddress2 = wallet.getRandomEthAddress(); - mockWalletReturnValue(walletSpy, dummyAddress2, {}); - const cMember = await testEnv.wrap(createMember)({ address: dummyAddress2 }); - expect(cMember?.uid).toEqual(dummyAddress2.toLowerCase()); - - mockWalletReturnValue(walletSpy, dummyAddress2, { name: updateParams.name }); - await expectThrow(testEnv.wrap(updateMember)({}), WenError.member_username_exists.key); + mockWalletReturnValue(member, updateParams); + const updated = await testEnv.wrap(WEN_FUNC.updateMember); + expect(updated.name).toEqual(updateParams.name); + const member2 = await testEnv.createMember(); + mockWalletReturnValue(member2, updateParams); + const call = testEnv.wrap(WEN_FUNC.updateMember); + await expectThrow(call, WenError.member_username_exists.key); }); it('unset discord', async () => { const updateParams = { discord: undefined }; - mockWalletReturnValue(walletSpy, dummyAddress, updateParams); - const uMember = await testEnv.wrap(updateMember)({}); - expect(uMember?.discord).toEqual(null); - walletSpy.mockRestore(); + mockWalletReturnValue(member, updateParams); + const updated = await testEnv.wrap(WEN_FUNC.updateMember); + expect(updated?.discord).toBe(''); }); it('Should set nft as avatar, then unset', async () => { const nft = { + name: 'mynft', + description: 'description', project: SOON_PROJECT_ID, - uid: wallet.getRandomEthAddress(), + uid: getRandomEthAddress(), media: MEDIA, - owner: dummyAddress, + owner: member, status: NftStatus.MINTED, available: NftAvailable.UNAVAILABLE, - }; - const nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); + } as Nft; + const nftDocRef = build5Db().doc(COL.NFT, nft.uid); await nftDocRef.create(nft); const updateParams = { avatarNft: nft.uid }; - mockWalletReturnValue(walletSpy, dummyAddress, updateParams); - let uMember = await testEnv.wrap(updateMember)({}); - expect(uMember.avatarNft).toBe(nft.uid); - expect(uMember.avatar).toBe(MEDIA); - - let nftData = await nftDocRef.get(); + mockWalletReturnValue(member, updateParams); + let updated = await testEnv.wrap(WEN_FUNC.updateMember); + expect(updated.avatarNft).toBe(nft.uid); + expect(updated.avatar).toBe(MEDIA); + let nftData = await nftDocRef.get(); expect(nftData?.setAsAvatar).toBe(true); - - mockWalletReturnValue(walletSpy, dummyAddress, { avatarNft: undefined }); - uMember = await testEnv.wrap(updateMember)({}); - expect(uMember.avatarNft).toBeNull(); - expect(uMember.avatar).toBeNull(); - + mockWalletReturnValue(member, { avatarNft: undefined }); + updated = await testEnv.wrap(WEN_FUNC.updateMember); + expect(updated.avatarNft).toBe(''); + expect(updated.avatar).toBe(''); nftData = await nftDocRef.get(); expect(nftData?.setAsAvatar).toBe(false); }); @@ -110,41 +96,39 @@ describe('MemberController: ' + WEN_FUNC.updateMember, () => { it('Should set nft as avatar, when available field is missing', async () => { const nft = { project: SOON_PROJECT_ID, - uid: wallet.getRandomEthAddress(), + uid: getRandomEthAddress(), media: MEDIA, - owner: dummyAddress, + owner: member, status: NftStatus.MINTED, - }; - const nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); + } as Nft; + const nftDocRef = build5Db().doc(COL.NFT, nft.uid); await nftDocRef.create(nft); const updateParams = { avatarNft: nft.uid }; - mockWalletReturnValue(walletSpy, dummyAddress, updateParams); - let uMember = await testEnv.wrap(updateMember)({}); - expect(uMember.avatarNft).toBe(nft.uid); - expect(uMember.avatar).toBe(MEDIA); + mockWalletReturnValue(member, updateParams); + const updated = await testEnv.wrap(WEN_FUNC.updateMember); + expect(updated.avatarNft).toBe(nft.uid); + expect(updated.avatar).toBe(MEDIA); }); it('Should throw, invalid nft not nft owner', async () => { - mockWalletReturnValue(walletSpy, dummyAddress, { avatarNft: wallet.getRandomEthAddress() }); - await expectThrow(testEnv.wrap(updateMember)({}), WenError.nft_does_not_exists.key); - - const nft = { - project: SOON_PROJECT_ID, - uid: wallet.getRandomEthAddress(), - media: MEDIA, - }; - const nftDocRef = build5Db().doc(`${COL.NFT}/${nft.uid}`); - + mockWalletReturnValue(member, { + avatarNft: getRandomEthAddress(), + }); + let call = testEnv.wrap(WEN_FUNC.updateMember); + await expectThrow(call, WenError.nft_does_not_exists.key); + const nft = { project: SOON_PROJECT_ID, uid: getRandomEthAddress(), media: MEDIA } as Nft; + const nftDocRef = build5Db().doc(COL.NFT, nft.uid); await nftDocRef.create(nft); - mockWalletReturnValue(walletSpy, dummyAddress, { avatarNft: nft.uid }); - await expectThrow(testEnv.wrap(updateMember)({}), WenError.you_must_be_the_owner_of_nft.key); - - await nftDocRef.update({ status: NftStatus.WITHDRAWN, owner: dummyAddress }); - mockWalletReturnValue(walletSpy, dummyAddress, { avatarNft: nft.uid }); - await expectThrow(testEnv.wrap(updateMember)({}), WenError.nft_not_minted.key); - + mockWalletReturnValue(member, { avatarNft: nft.uid }); + call = testEnv.wrap(WEN_FUNC.updateMember); + await expectThrow(call, WenError.you_must_be_the_owner_of_nft.key); + await nftDocRef.update({ status: NftStatus.WITHDRAWN, owner: member }); + mockWalletReturnValue(member, { avatarNft: nft.uid }); + call = testEnv.wrap(WEN_FUNC.updateMember); + await expectThrow(call, WenError.nft_not_minted.key); await nftDocRef.update({ status: NftStatus.MINTED, available: NftAvailable.AUCTION }); - mockWalletReturnValue(walletSpy, dummyAddress, { avatarNft: nft.uid }); - await expectThrow(testEnv.wrap(updateMember)({}), WenError.nft_on_sale.key); + mockWalletReturnValue(member, { avatarNft: nft.uid }); + call = testEnv.wrap(WEN_FUNC.updateMember); + await expectThrow(call, WenError.nft_on_sale.key); }); }); diff --git a/packages/functions/test/controls/nft.spec.ts b/packages/functions/test/controls/nft.spec.ts index d76d4c4651..63434a7b97 100644 --- a/packages/functions/test/controls/nft.spec.ts +++ b/packages/functions/test/controls/nft.spec.ts @@ -15,31 +15,25 @@ import { WenError, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { createCollection } from '../../src/runtime/firebase/collection/index'; import * as wallet from '../../src/utils/wallet.utils'; -import { MEDIA, testEnv } from '../set-up'; -import { createBatchNft, createNft, updateUnsoldNft } from './../../src/runtime/firebase/nft/index'; -import { createMember, createSpace, expectThrow, mockWalletReturnValue } from './common'; - -let walletSpy: any; +import { MEDIA, mockWalletReturnValue, testEnv } from '../set-up'; +import { expectThrow } from './common'; describe('Nft controll: ' + WEN_FUNC.createCollection, () => { let space: Space; let collection: Collection; let member: string; - beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - member = await createMember(walletSpy); - space = await createSpace(walletSpy, member); - mockWalletReturnValue(walletSpy, member, dummyCollection(space)); - collection = await testEnv.wrap(createCollection)({}); + member = await testEnv.createMember(); + space = await testEnv.createSpace(member); + mockWalletReturnValue(member, dummyCollection(space)); + collection = await testEnv.wrap(WEN_FUNC.createCollection); }); it('successfully create NFT', async () => { const nft = { media: MEDIA, ...dummyNft(collection.uid) }; - mockWalletReturnValue(walletSpy, member, nft); - const cNft = await testEnv.wrap(createNft)({}); + mockWalletReturnValue(member, nft); + const cNft = await testEnv.wrap(WEN_FUNC.createNft); expect(cNft?.createdOn).toBeDefined(); expect(cNft?.updatedOn).toBeDefined(); expect(cNft?.status).toBe(NftStatus.PRE_MINTED); @@ -47,66 +41,62 @@ describe('Nft controll: ' + WEN_FUNC.createCollection, () => { it('successfully create NFT with sale access', async () => { const nft = dummyNft(collection.uid, '', [member]); - mockWalletReturnValue(walletSpy, member, nft); - const cNft = await testEnv.wrap(createNft)({}); - + mockWalletReturnValue(member, nft); + const cNft = await testEnv.wrap(WEN_FUNC.createNft); expect(cNft?.saleAccessMembers).toEqual([member]); expect(cNft?.saleAccess).toBe(NftAccess.MEMBERS); expect(cNft?.status).toBe(NftStatus.PRE_MINTED); - const nfts = [ dummyNft(collection.uid, '', [member]), dummyNft(collection.uid, '', [member]), dummyNft(collection.uid), ]; - mockWalletReturnValue(walletSpy, member, nfts); - const cBatchNft = await testEnv.wrap(createBatchNft)({}); + mockWalletReturnValue(member, nfts); + const cBatchNft = await testEnv.wrap(WEN_FUNC.createBatchNft); expect(cBatchNft?.length).toBe(3); - for (let i = 0; i < nfts.length; ++i) { - const docRef = build5Db().doc(`${COL.NFT}/${cBatchNft[i]}`); + const docRef = build5Db().doc(COL.NFT, cBatchNft[i]); const nft = await docRef.get(); expect(nft.saleAccessMembers).toEqual(i === nfts.length - 1 ? [] : [member]); } }); it('successfully create NFT', async () => { - let nft = { media: 'asd', ...dummyNft(collection.uid) }; - mockWalletReturnValue(walletSpy, member, nft); - await expectThrow(testEnv.wrap(createNft)({}), WenError.invalid_params.key); - + let nft = { media: 'some-media-url', ...dummyNft(collection.uid) }; + mockWalletReturnValue(member, nft); + await expectThrow(testEnv.wrap(WEN_FUNC.createNft), WenError.invalid_params.key); nft = { - media: `https://firebasestorage.googleapis.com/v0/b/${Bucket.DEV}/o/`, + media: `https://storage.googleapis.com/download/storage/v1/b/${Bucket.DEV}/o`, ...dummyNft(collection.uid), }; - mockWalletReturnValue(walletSpy, member, nft); - await expectThrow(testEnv.wrap(createNft)({}), WenError.invalid_params.key); + mockWalletReturnValue(member, nft); + await expectThrow(testEnv.wrap(WEN_FUNC.createNft), WenError.invalid_params.key); }); it('successfully batch create 2 NFT', async () => { - mockWalletReturnValue(walletSpy, member, [ - dummyNft(collection.uid), - dummyNft(collection.uid, 'babbssa'), - ]); - const cBatchNft = await testEnv.wrap(createBatchNft)({}); + mockWalletReturnValue(member, [dummyNft(collection.uid), dummyNft(collection.uid, 'babbssa')]); + const cBatchNft = await testEnv.wrap(WEN_FUNC.createBatchNft); expect(cBatchNft?.length).toBe(2); }); it('successfully create NFT to high buy price', async () => { const nft = { ...dummyNft(collection.uid), price: 1000 * 1000 * 1000 * 1000 * 1000 }; - mockWalletReturnValue(walletSpy, member, nft); - await expectThrow(testEnv.wrap(createNft)({}), WenError.invalid_params.key); + mockWalletReturnValue(member, nft); + await expectThrow(testEnv.wrap(WEN_FUNC.createNft), WenError.invalid_params.key); }); it('successfully create NFT to high buy price - wrong collection', async () => { const nft = { ...dummyNft(collection.uid), collection: wallet.getRandomEthAddress() }; - mockWalletReturnValue(walletSpy, member, nft); - await expectThrow(testEnv.wrap(createNft)({}), WenError.collection_does_not_exists.key); + mockWalletReturnValue(member, nft); + await expectThrow( + testEnv.wrap(WEN_FUNC.createNft), + WenError.collection_does_not_exists.key, + ); }); it('successfully create NFT - validate space/type', async () => { - mockWalletReturnValue(walletSpy, member, dummyNft(collection.uid)); - const cNft = await testEnv.wrap(createNft)({}); + mockWalletReturnValue(member, dummyNft(collection.uid)); + const cNft = await testEnv.wrap(WEN_FUNC.createNft); expect(cNft?.createdOn).toBeDefined(); expect(cNft?.updatedOn).toBeDefined(); expect(cNft?.space).toBe(space.uid); @@ -119,49 +109,51 @@ describe('Nft controll: ' + WEN_FUNC.updateUnsoldNft, () => { let space: Space; let collection: Collection; let member: string; - beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - member = await createMember(walletSpy); - space = await createSpace(walletSpy, member); - mockWalletReturnValue(walletSpy, member, dummyCollection(space)); - collection = await testEnv.wrap(createCollection)({}); + member = await testEnv.createMember(); + space = await testEnv.createSpace(member); + mockWalletReturnValue(member, dummyCollection(space)); + collection = await testEnv.wrap(WEN_FUNC.createCollection); }); it('Should update unsold nft price', async () => { - mockWalletReturnValue(walletSpy, member, { media: MEDIA, ...dummyNft(collection.uid) }); - let nft = await testEnv.wrap(createNft)({}); + mockWalletReturnValue(member, { media: MEDIA, ...dummyNft(collection.uid) }); + let nft = await testEnv.wrap(WEN_FUNC.createNft); expect(nft.price).toBe(10 * MIN_IOTA_AMOUNT); - mockWalletReturnValue(walletSpy, member, { uid: nft.uid, price: 50 * MIN_IOTA_AMOUNT }); - nft = await testEnv.wrap(updateUnsoldNft)({}); + mockWalletReturnValue(member, { uid: nft.uid, price: 50 * MIN_IOTA_AMOUNT }); + nft = await testEnv.wrap(WEN_FUNC.updateUnsoldNft); expect(nft.price).toBe(50 * MIN_IOTA_AMOUNT); }); it('Should throw, nft can not be updated', async () => { - mockWalletReturnValue(walletSpy, member, { media: MEDIA, ...dummyNft(collection.uid) }); - let nft = await testEnv.wrap(createNft)({}); + mockWalletReturnValue(member, { media: MEDIA, ...dummyNft(collection.uid) }); + let nft = await testEnv.wrap(WEN_FUNC.createNft); expect(nft.price).toBe(10 * MIN_IOTA_AMOUNT); - mockWalletReturnValue(walletSpy, member, { uid: nft.uid, price: 50 * MIN_IOTA_AMOUNT }); - - await build5Db().doc(`${COL.NFT}/${nft.uid}`).update({ sold: true }); - await expectThrow(testEnv.wrap(updateUnsoldNft)({}), WenError.nft_already_sold.key); + await build5Db().doc(COL.NFT, nft.uid).update({ sold: true }); + mockWalletReturnValue(member, { + uid: nft.uid, + price: 50 * MIN_IOTA_AMOUNT, + }); + await expectThrow(testEnv.wrap(WEN_FUNC.updateUnsoldNft), WenError.nft_already_sold.key); - await build5Db().doc(`${COL.NFT}/${nft.uid}`).update({ hidden: true, sold: false }); - await expectThrow(testEnv.wrap(updateUnsoldNft)({}), WenError.hidden_nft.key); + await build5Db().doc(COL.NFT, nft.uid).update({ hidden: true, sold: false }); + mockWalletReturnValue(member, { uid: nft.uid, price: 50 * MIN_IOTA_AMOUNT }); + await expectThrow(testEnv.wrap(WEN_FUNC.updateUnsoldNft), WenError.hidden_nft.key); - await build5Db().doc(`${COL.NFT}/${nft.uid}`).update({ placeholderNft: true, hidden: false }); + await build5Db().doc(COL.NFT, nft.uid).update({ placeholderNft: true, hidden: false }); + mockWalletReturnValue(member, { uid: nft.uid, price: 50 * MIN_IOTA_AMOUNT }); await expectThrow( - testEnv.wrap(updateUnsoldNft)({}), + testEnv.wrap(WEN_FUNC.updateUnsoldNft), WenError.nft_placeholder_cant_be_updated.key, ); - await build5Db().doc(`${COL.NFT}/${nft.uid}`).update({ placeholderNft: false }); + await build5Db().doc(COL.NFT, nft.uid).update({ placeholderNft: false }); - const tmpMember = await createMember(walletSpy); - mockWalletReturnValue(walletSpy, tmpMember, { uid: nft.uid, price: 50 * MIN_IOTA_AMOUNT }); + const tmpMember = await testEnv.createMember(); + mockWalletReturnValue(tmpMember, { uid: nft.uid, price: 50 * MIN_IOTA_AMOUNT }); await expectThrow( - testEnv.wrap(updateUnsoldNft)({}), + testEnv.wrap(WEN_FUNC.updateUnsoldNft), WenError.you_are_not_guardian_of_space.key, ); }); @@ -189,6 +181,4 @@ const dummyNft = (collection: string, description = 'babba', saleAccessMembers: price: 10 * 1000 * 1000, saleAccessMembers, }); - -// TODO test invalid royalty amount -// TODO add set new price once owned. +// TODO test invalid royalty amount// TODO add set new price once owned. diff --git a/packages/functions/test/controls/nft/Helper.ts b/packages/functions/test/controls/nft/Helper.ts index b6de746c2f..6799469f6e 100644 --- a/packages/functions/test/controls/nft/Helper.ts +++ b/packages/functions/test/controls/nft/Helper.ts @@ -9,39 +9,26 @@ import { Nft, NftAccess, Space, + Transaction, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { createCollection } from '../../../src/runtime/firebase/collection'; -import { createNft, openBid, 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'; +import { MEDIA, mockWalletReturnValue, testEnv } from '../../set-up'; +import { 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.member = await testEnv.createMember(); + const memberPromises = Array.from(Array(3)).map(() => testEnv.createMember()); this.members = await Promise.all(memberPromises); - this.space = await createSpace(this.spy, this.member); - - mockWalletReturnValue(this.spy, this.member, { + this.space = await testEnv.createSpace(this.member); + const dummyCol = { name: 'Collection A', description: 'babba', type: CollectionType.CLASSIC, @@ -53,44 +40,41 @@ export class Helper { onePerMemberOnly: false, availableFrom: dayjs().toDate(), price: 10 * 1000 * 1000, - }); - - this.collection = await testEnv.wrap(createCollection)({}); - await build5Db().doc(`${COL.COLLECTION}/${this.collection.uid}`).update({ approved: true }); + }; + mockWalletReturnValue(this.member, dummyCol); + this.collection = await testEnv.wrap(WEN_FUNC.createCollection); + await build5Db().doc(COL.COLLECTION, this.collection.uid).update({ approved: true }); this.nft = await this.createNft(); - - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${this.collection.uid}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, this.collection.uid); await wait(async () => { this.collection = await collectionDocRef.get(); return this.collection.availableNfts === 1; }); - await this.orderNft(this.nft.uid); - await wait(async () => { this.collection = await collectionDocRef.get(); return this.collection.availableNfts === 0; }); }; - public createNft = async () => { - mockWalletReturnValue(this.spy, this.member, { + public createNft = () => { + mockWalletReturnValue(this.member, { media: MEDIA, ...dummyNft(this.collection.uid), }); - return (await testEnv.wrap(createNft)({})) as Nft; + return testEnv.wrap(WEN_FUNC.createNft); }; public orderNft = async (nft: string) => { - mockWalletReturnValue(this.spy, this.member, { collection: this.collection.uid, nft }); - const nftOrder = await testEnv.wrap(orderNft)({}); + mockWalletReturnValue(this.member, { collection: this.collection.uid, nft }); + const nftOrder = await testEnv.wrap(WEN_FUNC.orderNft); await submitMilestoneFunc(nftOrder); }; public bidNft = async (memberId: string, amount: number) => { - mockWalletReturnValue(this.spy, memberId, { nft: this.nft.uid }); - const bidOrder = await testEnv.wrap(openBid)({}); + mockWalletReturnValue(memberId, { nft: this.nft.uid }); + const bidOrder = await testEnv.wrap(WEN_FUNC.openBid); await submitMilestoneFunc(bidOrder, amount); return bidOrder; }; diff --git a/packages/functions/test/controls/nft/nft.bidding.extends.spec.ts b/packages/functions/test/controls/nft/nft.bidding.extends.spec.ts index 3d09652fcc..5f73dcc9ed 100644 --- a/packages/functions/test/controls/nft/nft.bidding.extends.spec.ts +++ b/packages/functions/test/controls/nft/nft.bidding.extends.spec.ts @@ -1,22 +1,16 @@ -import { IDocument, build5Db } from '@build-5/database'; -import { Auction, COL, MIN_IOTA_AMOUNT, Nft, WenError } from '@build-5/interfaces'; +import { IDocument, PgNft, PgNftUpdate, build5Db } from '@build-5/database'; +import { Auction, COL, MIN_IOTA_AMOUNT, Nft, WEN_FUNC, 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 { mockWalletReturnValue, testEnv } from '../../set-up'; +import { expectThrow, 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(); - }); + let nftDocRef: IDocument; beforeEach(async () => { await h.beforeEach(); @@ -29,10 +23,9 @@ describe('Nft bidding with extended auction', () => { 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}`); + mockWalletReturnValue(h.member, auctionData); + await testEnv.wrap(WEN_FUNC.setForSaleNft); + nftDocRef = build5Db().doc(COL.NFT, h.nft.uid); await wait(async () => { h.nft = await nftDocRef.get(); return h.nft.available === 3; @@ -41,32 +34,27 @@ describe('Nft bidding with extended auction', () => { 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(); + 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 auctionDocRef = build5Db().doc(COL.AUCTION, h.nft.auction!); const auction = await auctionDocRef.get(); auctionToDate = dayjs(auction.auctionTo?.toDate()); auctionExtendedDate = dayjs(auction.extendedAuctionTo?.toDate()); @@ -77,29 +65,25 @@ describe('Nft bidding with extended auction', () => { 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 auctionDocRef = build5Db().doc(COL.AUCTION, h.nft.auction!); const auction = await auctionDocRef.get(); auctionToDate = dayjs(auction.auctionTo?.toDate()); expect(auctionToDate.isSame(expectedAuctionToDate)).toBe(true); @@ -107,32 +91,26 @@ describe('Nft bidding with extended auction', () => { }); 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); + const auctionData = { ...dummyAuctionData(h.nft.uid), extendedAuctionLength: 60000 * 3 }; + mockWalletReturnValue(h.member, auctionData); + await expectThrow(testEnv.wrap(WEN_FUNC.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]); @@ -148,7 +126,7 @@ describe('Nft bidding with extended auction', () => { extendedAuctionLength: 60000 * 10, extendAuctionWithin: 0, }; - mockWalletReturnValue(h.spy, h.member, auctionData); - await expectThrow(testEnv.wrap(setForSaleNft)({}), WenError.invalid_params.key); + mockWalletReturnValue(h.member, auctionData); + await expectThrow(testEnv.wrap(WEN_FUNC.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 index 92110e94f5..8629cff974 100644 --- a/packages/functions/test/controls/nft/nft.bidding.finalize.spec.ts +++ b/packages/functions/test/controls/nft/nft.bidding.finalize.spec.ts @@ -7,30 +7,24 @@ import { Nft, NftAvailable, NotificationType, - Transaction, TransactionType, + WEN_FUNC, } 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 { mockWalletReturnValue, testEnv } from '../../set-up'; +import { 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(); - mockWalletReturnValue(h.spy, h.member, dummyAuctionData(h.nft.uid)); - await testEnv.wrap(setForSaleNft)({}); + mockWalletReturnValue(h.member, dummyAuctionData(h.nft.uid)); + await testEnv.wrap(WEN_FUNC.setForSaleNft); await wait(async () => { - const docRef = build5Db().doc(`${COL.NFT}/${h.nft.uid}`); + const docRef = build5Db().doc(COL.NFT, h.nft.uid); h.nft = await docRef.get(); return h.nft.available === 3; }); @@ -39,84 +33,73 @@ describe('Should finalize bidding', () => { it.each([true, false])('Should bid and finalize it', async (noRoyaltySpace: boolean) => { if (noRoyaltySpace) { await build5Db() - .doc(`${COL.COLLECTION}/${h.collection.uid}`) + .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({ + 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, + expect(bidOrder.payload.restrictions!.nft).toEqual({ + saleAccess: h.nft.saleAccess || undefined, saleAccessMembers: h.nft.saleAccessMembers || [], }); - - const nftDocRef = build5Db().doc(`${COL.NFT}/${h.nft.uid}`); + 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}`); + 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')) }); - + const auctionDocRef = build5Db().doc(COL.AUCTION, h.nft.auction!); + await auctionDocRef.update({ auctionTo: dayjs().subtract(1, 'minute').toDate() }); 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(); - + expect(h.nft.auctionFrom).toBeUndefined(); + expect(h.nft.auctionTo).toBeUndefined(); + expect(h.nft.auction).toBeUndefined(); 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(); + .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); }); it('Should finalize it, no bids', async () => { - const auctionDocRef = build5Db().doc(`${COL.AUCTION}/${h.nft.auction}`); - await auctionDocRef.update({ auctionTo: dateToTimestamp(dayjs().subtract(1, 'minute')) }); + const auctionDocRef = build5Db().doc(COL.AUCTION, h.nft.auction!); + await auctionDocRef.update({ auctionTo: dayjs().subtract(1, 'minute').toDate() }); await finalizeAuctions(); - - const nftDocRef = build5Db().doc(`${COL.NFT}/${h.nft.uid}`); + const nftDocRef = build5Db().doc(COL.NFT, h.nft.uid); await wait(async () => { h.nft = await nftDocRef.get(); return h.nft.available === NftAvailable.SALE; }); expect(h.nft.owner).toBe(h.member); - expect(h.nft.auctionFrom).toBeNull(); - expect(h.nft.auctionTo).toBeNull(); - expect(h.nft.auction).toBeNull(); + expect(h.nft.auctionFrom).toBeUndefined(); + expect(h.nft.auctionTo).toBeUndefined(); + expect(h.nft.auction).toBeUndefined(); }); }); diff --git a/packages/functions/test/controls/nft/nft.bidding.spec.ts b/packages/functions/test/controls/nft/nft.bidding.spec.ts index 6e0411cbd6..acf9cd6e06 100644 --- a/packages/functions/test/controls/nft/nft.bidding.spec.ts +++ b/packages/functions/test/controls/nft/nft.bidding.spec.ts @@ -9,25 +9,20 @@ import { TransactionPayloadType, TransactionType, TransactionValidationType, + WEN_FUNC, } from '@build-5/interfaces'; -import { orderNft, setForSaleNft } from '../../../src/runtime/firebase/nft'; -import { testEnv } from '../../set-up'; -import { mockWalletReturnValue, submitMilestoneFunc, wait } from '../common'; +import { mockWalletReturnValue, testEnv } from '../../set-up'; +import { 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)({}); + mockWalletReturnValue(h.member, dummyAuctionData(h.nft.uid)); + await testEnv.wrap(WEN_FUNC.setForSaleNft); await wait(async () => { - const docRef = build5Db().doc(`${COL.NFT}/${h.nft.uid}`); + const docRef = build5Db().doc(COL.NFT, h.nft.uid); h.nft = await docRef.get(); return h.nft.available === 3; }); @@ -38,7 +33,7 @@ describe('Nft bidding', () => { const snap = await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.ORDER) - .where('payload.type', '==', TransactionPayloadType.NFT_BID) + .where('payload_type', '==', TransactionPayloadType.NFT_BID) .where('member', '==', h.members[0]) .get(); expect(snap.length).toBe(1); @@ -52,20 +47,17 @@ describe('Nft bidding', () => { 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}`); + 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}`); + 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 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); @@ -75,32 +67,29 @@ describe('Nft bidding', () => { 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 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(); + .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(); + .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}`); + const auctionDocRef = build5Db().doc(COL.AUCTION, h.nft.auction!); await auctionDocRef.update({ topUpBased: true }); await h.bidNft(h.members[0], MIN_IOTA_AMOUNT); @@ -112,12 +101,10 @@ describe('Nft bidding', () => { 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}`); + 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); @@ -125,60 +112,53 @@ describe('Nft bidding', () => { 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(); + .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(); + .where('payload_sourceTransaction', 'array-contains', payment.uid as any) + .get(); expect(credit).toBeDefined(); } }); it('Should reject smaller bid', async () => { - const nftDocRef = build5Db().doc(`${COL.NFT}/${h.nft.uid}`); + 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) + .where('payload_nft', '==', h.nft.uid) .get(); expect(snap.length).toBe(1); }); it('Should reject bid where min inc is too small', async () => { - const nftDocRef = build5Db().doc(`${COL.NFT}/${h.nft.uid}`); + const nftDocRef = build5Db().doc(COL.NFT, h.nft.uid); await h.bidNft(h.members[0], MIN_IOTA_AMOUNT); - h.nft = await nftDocRef.get(); expect(h.nft.auctionHighestBidder).toBe(h.members[0]); - await h.bidNft(h.members[0], 1.5 * MIN_IOTA_AMOUNT); - const snap = await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.CREDIT) .where('member', '==', h.members[0]) - .where('payload.nft', '==', h.nft.uid) - .get(); + .where('payload_nft', '==', h.nft.uid) + .get(); expect(snap.length).toBe(1); expect(snap[0].payload.amount).toBe(1.5 * MIN_IOTA_AMOUNT); }); @@ -190,16 +170,14 @@ describe('Nft bidding', () => { h.bidNft(h.members[2], MIN_IOTA_AMOUNT), ]; await Promise.all(bidPromises); - - const nftDocRef = build5Db().doc(`${COL.NFT}/${h.nft.uid}`); + 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) + .where('payload_nft', '==', h.nft.uid) + .whereIn('member', [h.members[0], h.members[2]]) .get(); expect(transactionSnap.length).toBe(2); }); @@ -207,20 +185,17 @@ describe('Nft bidding', () => { 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)({}); + mockWalletReturnValue(h.members[1], { collection: h.nft.collection, nft: h.nft.uid }); + const nftOrder = await testEnv.wrap(WEN_FUNC.orderNft); await submitMilestoneFunc(nftOrder); - - const nftDocRef = build5Db().doc(`${COL.NFT}/${h.nft.uid}`); + 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(); + .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 index a8af4e8c80..202440bd30 100644 --- a/packages/functions/test/controls/nft/nft.set.for.sale.spec.ts +++ b/packages/functions/test/controls/nft/nft.set.for.sale.spec.ts @@ -1,27 +1,22 @@ import { build5Db } from '@build-5/database'; -import { COL, Collection, Nft, WenError } from '@build-5/interfaces'; -import { setForSaleNft } from '../../../src/runtime/firebase/nft'; +import { COL, Collection, Nft, WEN_FUNC, WenError } from '@build-5/interfaces'; import { getRandomEthAddress } from '../../../src/utils/wallet.utils'; -import { testEnv } from '../../set-up'; -import { expectThrow, mockWalletReturnValue, wait } from '../common'; +import { mockWalletReturnValue, testEnv } from '../../set-up'; +import { expectThrow, 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)({}); + mockWalletReturnValue(h.member, dummySaleData(h.nft.uid)); + await testEnv.wrap(WEN_FUNC.setForSaleNft); - const nftDocRef = build5Db().doc(`${COL.NFT}/${h.nft.uid}`); + const nftDocRef = build5Db().doc(COL.NFT, h.nft.uid); await wait(async () => { const nft = await nftDocRef.get(); return nft.available === 1; @@ -31,59 +26,61 @@ describe('Nft set for sale', () => { expect(saleNft.available).toBe(1); expect(saleNft.availableFrom).toBeDefined(); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${saleNft.collection}`); + 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}`); + 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); + mockWalletReturnValue(h.member, dummySaleData(h.nft.uid)); + await expectThrow(testEnv.wrap(WEN_FUNC.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)({}); + mockWalletReturnValue(h.member, dummyAuctionData(h.nft.uid)); + await testEnv.wrap(WEN_FUNC.setForSaleNft); - const nftDocRef = build5Db().doc(`${COL.NFT}/${h.nft.uid}`); + 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(); + 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 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); + mockWalletReturnValue(h.member, dummyAuctionData(h.nft.uid)); + await testEnv.wrap(WEN_FUNC.setForSaleNft); + mockWalletReturnValue(h.member, dummyAuctionData(h.nft.uid)); + await expectThrow( + testEnv.wrap(WEN_FUNC.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); + mockWalletReturnValue(h.member, { ...dummyAuctionData(h.nft.uid), nft: getRandomEthAddress() }); + await expectThrow(testEnv.wrap(WEN_FUNC.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); + mockWalletReturnValue(h.members[0], dummyAuctionData(h.nft.uid)); + await expectThrow( + testEnv.wrap(WEN_FUNC.setForSaleNft), + WenError.you_must_be_the_owner_of_nft.key, + ); }); }); diff --git a/packages/functions/test/controls/order.spec.ts b/packages/functions/test/controls/order.spec.ts index 1f62c25964..fc6737333f 100644 --- a/packages/functions/test/controls/order.spec.ts +++ b/packages/functions/test/controls/order.spec.ts @@ -6,6 +6,7 @@ import { Collection, CollectionType, MIN_IOTA_AMOUNT, + Network, NetworkAddress, Nft, NftAccess, @@ -14,31 +15,17 @@ import { Transaction, TransactionPayloadType, TransactionType, + WEN_FUNC, WenError, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { - createNft, - orderNft, - setForSaleNft, -} from '../../../functions/src/runtime/firebase//nft/index'; -import { createCollection } from '../../../functions/src/runtime/firebase/collection/index'; +import { orderNftControl } from '../../src/controls/nft/nft.puchase.control'; import * as wallet from '../../src/utils/wallet.utils'; -import { testEnv } from '../set-up'; -import { - createMember, - createSpace, - expectThrow, - mockIpCheck, - mockWalletReturnValue, - submitMilestoneFunc, - wait, -} from './common'; +import { mockWalletReturnValue, testEnv } from '../set-up'; +import { expectThrow, mockIpCheck, submitMilestoneFunc, wait } from './common'; const db = build5Db(); -let walletSpy: any; - const dummyCollection = ( space: Space, type: CollectionType, @@ -72,24 +59,24 @@ const dummyNft = ( }); const createCollectionFunc = async (address: NetworkAddress, params: T) => { - mockWalletReturnValue(walletSpy, address, params); - const cCollection = await testEnv.wrap(createCollection)({}); + mockWalletReturnValue(address, params); + const cCollection = await testEnv.wrap(WEN_FUNC.createCollection); expect(cCollection?.uid).toBeDefined(); - await build5Db().doc(`${COL.COLLECTION}/${cCollection?.uid}`).update({ approved: true }); + await build5Db().doc(COL.COLLECTION, cCollection?.uid).update({ approved: true }); return cCollection; }; const createNftFunc = async (address: NetworkAddress, params: T) => { - mockWalletReturnValue(walletSpy, address, params); - const nft = await testEnv.wrap(createNft)({}); + mockWalletReturnValue(address, params); + const nft = await testEnv.wrap(WEN_FUNC.createNft); expect(nft?.createdOn).toBeDefined(); return nft; }; const submitOrderFunc = async (address: NetworkAddress, params: T) => { - mockWalletReturnValue(walletSpy, address, params); - const order = await testEnv.wrap(orderNft)({}); + mockWalletReturnValue(address, params); + const order = await testEnv.wrap(WEN_FUNC.orderNft); expect(order?.createdOn).toBeDefined(); return order; }; @@ -106,9 +93,8 @@ describe('Ordering flows', () => { let space: Space; beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - member = await createMember(walletSpy); - space = await createSpace(walletSpy, member); + member = await testEnv.createMember(); + space = await testEnv.createSpace(member); }); it('One collection, one classic NFT, one purchase - not paid for', async () => { @@ -145,19 +131,18 @@ describe('Ordering flows', () => { ); if (noRoyaltySpace) { await build5Db() - .doc(`${COL.COLLECTION}/${collection.uid}`) + .doc(COL.COLLECTION, collection.uid) .update({ royaltiesSpace: '', royaltiesFee: 0 }); } let nft: Nft = await createNftFunc(member, dummyNft(collection, price)); - const order = await submitOrderFunc(member, { collection: collection.uid, nft: nft.uid }); - expect(order.payload.restrictions.collection).toEqual({ + expect(order.payload.restrictions!.collection).toEqual({ access: collection.access, accessAwards: collection.accessAwards || [], accessCollections: collection.accessCollections || [], }); - expect(order.payload.restrictions.nft).toEqual({ - saleAccess: nft.saleAccess || null, + expect(order.payload.restrictions!.nft).toEqual({ + saleAccess: nft.saleAccess || undefined, saleAccessMembers: nft.saleAccessMembers || [], }); await submitMilestoneFunc(order); @@ -176,8 +161,8 @@ describe('Ordering flows', () => { const billPayments = await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.BILL_PAYMENT) - .where('payload.nft', '==', nft.uid) - .get(); + .where('payload_nft', '==', nft.uid) + .get(); for (const billPayment of billPayments) { expect(billPayment.payload.restrictions).toEqual(order.payload.restrictions); } @@ -199,17 +184,17 @@ describe('Ordering flows', () => { nft = await nftDocRef.get(); expect(nft.soldOn).toBeDefined(); - mockWalletReturnValue(walletSpy, member, dummySaleData(nft.uid)); - await testEnv.wrap(setForSaleNft)({}); + mockWalletReturnValue(member, dummySaleData(nft.uid)); + await testEnv.wrap(WEN_FUNC.setForSaleNft); await new Promise((resolve) => setTimeout(resolve, 1000)); - const buyer = await createMember(walletSpy); + const buyer = await testEnv.createMember(); order = await submitOrderFunc(buyer, { collection: collection.uid, nft: nft.uid }); await submitMilestoneFunc(order); const secondSoldNft = await nftDocRef.get(); - expect(secondSoldNft.soldOn).toEqual(nft.soldOn); + expect(secondSoldNft.soldOn?.seconds).toBe(nft.soldOn?.seconds); }); it('One collection, one classic NFT, one purchase & paid for and try again', async () => { @@ -245,7 +230,7 @@ describe('Ordering flows', () => { const order = await submitOrderFunc(member, { collection: collection.uid }); await submitMilestoneFunc(order); - const nftDbRec: any = await db.collection(COL.NFT).doc(order.payload.nft).get(); + const nftDbRec: any = await db.doc(COL.NFT, order.payload.nft!).get(); expect(member).toBe(nftDbRec.owner); }); @@ -262,7 +247,7 @@ describe('Ordering flows', () => { const order = await submitOrderFunc(member, { collection: collection.uid }); await submitMilestoneFunc(order); - const nftDbRec: any = await db.collection(COL.NFT).doc(order.payload.nft).get(); + const nftDbRec: any = await db.collection(COL.NFT).doc(order.payload.nft!).get(); expect(member).toBe(nftDbRec.owner); await expectThrow( @@ -270,7 +255,7 @@ describe('Ordering flows', () => { WenError.no_more_nft_available_for_sale.key, ); - const placeholderNftDocRef = build5Db().doc(`${COL.NFT}/${collection.placeholderNft}`); + const placeholderNftDocRef = build5Db().doc(COL.NFT, collection.placeholderNft); await wait(async () => { const placeholderNft = await placeholderNftDocRef.get(); return placeholderNft.hidden || false; @@ -279,7 +264,7 @@ describe('Ordering flows', () => { it('One collection, generated NFT, 15 Nfts should equal to 15 purchases', async () => { const batchSize = 15; - const memberPromises = Array.from(Array(batchSize)).map(() => createMember(walletSpy)); + const memberPromises = Array.from(Array(batchSize)).map(() => testEnv.createMember()); const members = await Promise.all(memberPromises); const price = 100; @@ -311,7 +296,7 @@ describe('Ordering flows', () => { batchSize + ' purchases + payment in multiple milestone', async () => { - const memberPromises = Array.from(Array(batchSize)).map(() => createMember(walletSpy)); + const memberPromises = Array.from(Array(batchSize)).map(() => testEnv.createMember()); const members = await Promise.all(memberPromises); const price = 100; @@ -368,13 +353,13 @@ describe('Ordering flows', () => { const order = await submitOrderFunc(member, { collection: collection.uid }); // Confirm payment. - const wrongAmount = order.payload.amount * 1.5; + const wrongAmount = order.payload.amount! * 1.5; const milestone = await submitMilestoneFunc(order, wrongAmount); - const nftDbRec = await db.collection(COL.NFT).doc(order.payload.nft).get(); + const nftDbRec = await db.collection(COL.NFT).doc(order.payload.nft!).get(); expect(nftDbRec?.sold).toBe(false); - const tran = await db.collection(COL.TRANSACTION).doc(order.uid).get(); + const tran = await db.collection(COL.TRANSACTION).doc(order.uid).get(); expect(tran?.linkedTransactions?.length).toBe(2); let c = 0; @@ -413,7 +398,7 @@ describe('Ordering flows', () => { await submitMilestoneFunc(order); - const nftDbRec: any = await db.collection(COL.NFT).doc(order.payload.nft).get(); + const nftDbRec: any = await db.collection(COL.NFT).doc(order.payload.nft!).get(); expect(nftDbRec.sold).toBe(true); const tran: any = await db.collection(COL.TRANSACTION).doc(order.uid).get(); @@ -438,10 +423,9 @@ describe('Ordering flows', () => { ); const nft = await createNftFunc(member, dummyNft(collection, price)); mockIpCheck(true, { common: ['HU'] }, { countryCode: 'HU' }); - await expectThrow( - submitOrderFunc(member, { collection: collection.uid, nft: nft.uid }), - WenError.blocked_country.key, - ); + mockWalletReturnValue(member, { collection: collection.uid, nft: nft.uid }); + const call = testEnv.mockWrap(orderNftControl); + await expectThrow(call, WenError.blocked_country.key); }); it('Order should fail, country blocked for nft', async () => { @@ -452,10 +436,10 @@ describe('Ordering flows', () => { ); const nft = await createNftFunc(member, dummyNft(collection, price)); mockIpCheck(true, { common: ['USA'], [nft.uid]: ['USA', 'HU'] }, { countryCode: 'HU' }); - await expectThrow( - submitOrderFunc(member, { collection: collection.uid, nft: nft.uid }), - WenError.blocked_country.key, - ); + + mockWalletReturnValue(member, { collection: collection.uid, nft: nft.uid }); + const call = testEnv.mockWrap(orderNftControl); + await expectThrow(call, WenError.blocked_country.key); }); it('Should validate access awards', async () => { @@ -478,8 +462,9 @@ describe('Ordering flows', () => { type: TransactionType.AWARD, uid: wallet.getRandomEthAddress(), payload: { type: TransactionPayloadType.BADGE, award: awards[0] }, + network: Network.RMS, }; - await build5Db().doc(`${COL.TRANSACTION}/${badge.uid}`).create(badge); + await build5Db().doc(COL.TRANSACTION, badge.uid).create(badge); await expectThrow( submitOrderFunc(member, { collection: collection.uid, nft: nft.uid }), WenError.you_dont_have_required_badge.key, @@ -491,17 +476,18 @@ describe('Ordering flows', () => { type: TransactionType.AWARD, uid: wallet.getRandomEthAddress(), payload: { type: TransactionPayloadType.BADGE, award: awards[1] }, + network: Network.RMS, }; - await build5Db().doc(`${COL.TRANSACTION}/${badge.uid}`).create(badge); + await build5Db().doc(COL.TRANSACTION, badge.uid).create(badge); const order = await submitOrderFunc(member, { collection: collection.uid, nft: nft.uid }); expect(order).toBeDefined(); - expect(order.payload.restrictions.collection).toEqual({ + expect(order.payload.restrictions!.collection).toEqual({ access: collection.access, accessAwards: collection.accessAwards || [], accessCollections: collection.accessCollections || [], }); - expect(order.payload.restrictions.nft).toEqual({ - saleAccess: nft.saleAccess || null, + expect(order.payload.restrictions!.nft).toEqual({ + saleAccess: nft.saleAccess || undefined, saleAccessMembers: nft.saleAccessMembers || [], }); }); diff --git a/packages/functions/test/controls/project/project.create.spec.ts b/packages/functions/test/controls/project/project.create.spec.ts index 947b419b71..d7abb7bf56 100644 --- a/packages/functions/test/controls/project/project.create.spec.ts +++ b/packages/functions/test/controls/project/project.create.spec.ts @@ -1,40 +1,28 @@ import { build5Db } from '@build-5/database'; import { COL, - Network, - Project, - ProjectAdmin, ProjectBilling, + ProjectCreateResponse, SOON_PROJECT_ID, SUB_COL, Token, TokenStatus, Transaction, + WEN_FUNC, WenError, } from '@build-5/interfaces'; -import { CoinType, utf8ToHex } from '@iota/sdk'; -import axios from 'axios'; import { AVAILABLE_NETWORKS } from '../../../src/controls/common'; -import { createProject } from '../../../src/runtime/firebase/project/index'; -import { getSecretManager } from '../../../src/utils/secret.manager.utils'; import * as wallet from '../../../src/utils/wallet.utils'; -import { getRandomNonce } from '../../../src/utils/wallet.utils'; -import { getWallet, testEnv } from '../../set-up'; -import { createMember, expectThrow, getRandomSymbol, mockWalletReturnValue } from '../common'; +import { mockWalletReturnValue, testEnv } from '../../set-up'; +import { expectThrow, getRandomSymbol } from '../common'; describe('Project create', () => { - let walletSpy: any; let guardian: string; let token: Token; - - beforeAll(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - }); - beforeEach(async () => { - guardian = await createMember(walletSpy); + guardian = await testEnv.createMember(); const tokenId = wallet.getRandomEthAddress(); - token = { + const tokenUpsert = { project: SOON_PROJECT_ID, uid: tokenId, symbol: getRandomSymbol(), @@ -43,7 +31,8 @@ describe('Project create', () => { status: TokenStatus.AVAILABLE, approved: true, }; - await build5Db().doc(`${COL.TOKEN}/${tokenId}`).set(token); + await build5Db().doc(COL.TOKEN, tokenId).upsert(tokenUpsert); + token = (await build5Db().doc(COL.TOKEN, tokenId).get())!; }); it('Should create volume based project', async () => { @@ -52,27 +41,33 @@ describe('Project create', () => { contactEmail: 'myemail@gmail.com', config: { billing: ProjectBilling.VOLUME_BASED }, }; - mockWalletReturnValue(walletSpy, guardian, dummyProject); - const { project: newProject } = await testEnv.wrap(createProject)({}); - const projectDocRef = build5Db().doc(`${COL.PROJECT}/${newProject.uid}`); - const project = await projectDocRef.get(); + mockWalletReturnValue(guardian, dummyProject); + const { project: newProject } = await testEnv.wrap( + WEN_FUNC.createProject, + ); + + const projectDocRef = build5Db().doc(COL.PROJECT, newProject.uid); + const project = await projectDocRef.get(); expect(project?.name).toBe(dummyProject.name); expect(project?.contactEmail).toBe(dummyProject.contactEmail); expect(project?.deactivated).toBe(false); expect(project?.config?.billing).toBe(ProjectBilling.VOLUME_BASED); - const projectAdminDocRef = projectDocRef.collection(SUB_COL.ADMINS).doc(guardian); - const projectAdmin = await projectAdminDocRef.get(); + const projectAdminDocRef = build5Db().doc( + COL.PROJECT, + newProject.uid, + SUB_COL.ADMINS, + guardian, + ); + const projectAdmin = await projectAdminDocRef.get(); expect(projectAdmin?.uid).toBe(guardian); expect(projectAdmin?.parentCol).toBe(COL.PROJECT); expect(projectAdmin?.parentId).toBe(project?.uid); - const networks = Object.values(project!.otr!).map((o) => o.network); expect(networks.sort()).toEqual(AVAILABLE_NETWORKS.sort()); - for (const [uid, otr] of Object.entries(project?.otr!)) { - const docRef = build5Db().doc(`${COL.TRANSACTION}/${uid}`); + const docRef = build5Db().doc(COL.TRANSACTION, uid); const otrOrder = await docRef.get(); expect(otrOrder.uid).toBe(uid); expect(otrOrder.network).toBe(otr.network); @@ -87,8 +82,12 @@ describe('Project create', () => { contactEmail: 'myemail@gmail.com', config: { billing: ProjectBilling.VOLUME_BASED, tiers: [1, 2, 3, 4] }, }; - mockWalletReturnValue(walletSpy, guardian, dummyProject); - await expectThrow(testEnv.wrap(createProject)({}), WenError.invalid_params.key); + + mockWalletReturnValue(guardian, dummyProject); + await expectThrow( + testEnv.wrap(WEN_FUNC.createProject), + WenError.invalid_params.key, + ); }); it('Should create token based project', async () => { @@ -96,39 +95,42 @@ describe('Project create', () => { name: 'My project', contactEmail: 'myemail@gmail.com', config: { - billing: ProjectBilling.TOKEN_BASE, + billing: ProjectBilling.TOKEN_BASED, tiers: [1, 2, 3, 4, 5], tokenTradingFeeDiscountPercentage: [0, 0, 0, 0, 0], nativeTokenSymbol: token.symbol, }, }; - mockWalletReturnValue(walletSpy, guardian, dummyProject); - const { project: newProject } = await testEnv.wrap(createProject)({}); - - const projectDocRef = build5Db().doc(`${COL.PROJECT}/${newProject.uid}`); - const project = await projectDocRef.get(); + mockWalletReturnValue(guardian, dummyProject); + const { project: newProject } = await testEnv.wrap( + WEN_FUNC.createProject, + ); + const projectDocRef = build5Db().doc(COL.PROJECT, newProject.uid); + const project = await projectDocRef.get(); expect(project?.name).toBe(dummyProject.name); expect(project?.contactEmail).toBe(dummyProject.contactEmail); expect(project?.deactivated).toBe(false); - expect(project?.config?.billing).toBe(ProjectBilling.TOKEN_BASE); + expect(project?.config?.billing).toBe(ProjectBilling.TOKEN_BASED); expect(project?.config?.tiers).toEqual(dummyProject.config.tiers); expect(project?.config?.tokenTradingFeeDiscountPercentage).toEqual( dummyProject.config.tokenTradingFeeDiscountPercentage, ); expect(project?.config?.nativeTokenSymbol).toBe(dummyProject.config.nativeTokenSymbol); expect(project?.config?.nativeTokenUid).toBe(token.uid); - - const projectAdminDocRef = projectDocRef.collection(SUB_COL.ADMINS).doc(guardian); - const adminGuardian = await projectAdminDocRef.get(); + const projectAdminDocRef = build5Db().doc( + COL.PROJECT, + newProject.uid, + SUB_COL.ADMINS, + guardian, + ); + const adminGuardian = await projectAdminDocRef.get(); expect(adminGuardian?.uid).toBe(guardian); expect(adminGuardian?.parentCol).toBe(COL.PROJECT); expect(adminGuardian?.parentId).toBe(project?.uid); - const networks = Object.values(project!.otr!).map((o) => o.network); expect(networks.sort()).toEqual(AVAILABLE_NETWORKS.sort()); - for (const [uid, otr] of Object.entries(project?.otr!)) { - const docRef = build5Db().doc(`${COL.TRANSACTION}/${uid}`); + const docRef = build5Db().doc(COL.TRANSACTION, uid); const otrOrder = await docRef.get(); expect(otrOrder.uid).toBe(uid); expect(otrOrder.network).toBe(otr.network); @@ -139,33 +141,25 @@ describe('Project create', () => { }); it('Should create project without project id', async () => { - const wallet = await getWallet(Network.RMS); - const address = await wallet.getNewIotaAddressDetails(); - - const nonce = getRandomNonce(); - const userDocRef = build5Db().doc(`${COL.MEMBER}/${address.bech32}`); - await userDocRef.create({ uid: address.bech32, nonce }); - - const secretManager = getSecretManager(address.mnemonic); - const signature = await secretManager.signEd25519(utf8ToHex(nonce), { - coinType: CoinType.IOTA, - }); - const request = { - address: address.bech32, - projectApiKey: '', - signature: signature.signature, - publicKey: { - hex: signature.publicKey, - network: Network.RMS, - }, - body: { - name: 'My project', - contactEmail: 'myemail@gmail.com', - config: { billing: ProjectBilling.VOLUME_BASED }, + const dummyProject = { + name: 'My project', + contactEmail: 'myemail@gmail.com', + config: { + billing: ProjectBilling.TOKEN_BASED, + tiers: [1, 2, 3, 4, 5], + tokenTradingFeeDiscountPercentage: [0, 0, 0, 0, 0], + nativeTokenSymbol: token.symbol, }, }; - const url = 'http://127.0.0.1:5001/soonaverse-dev/us-central1/https-createproject'; - const response = await axios.post(url, request); - expect(response.data.token).toBeDefined(); + mockWalletReturnValue(guardian, dummyProject, ''); + const { project: newProject } = await testEnv.wrap( + WEN_FUNC.createProject, + ); + const projectDocRef = build5Db().doc(COL.PROJECT, newProject.uid); + const project = await projectDocRef.get(); + expect(project?.name).toBe(dummyProject.name); + expect(project?.contactEmail).toBe(dummyProject.contactEmail); + expect(project?.deactivated).toBe(false); + expect(project?.config?.billing).toBe(ProjectBilling.TOKEN_BASED); }); }); diff --git a/packages/functions/test/controls/project/project.deactivate.spec.ts b/packages/functions/test/controls/project/project.deactivate.spec.ts index b24baf313f..e44ca81cbd 100644 --- a/packages/functions/test/controls/project/project.deactivate.spec.ts +++ b/packages/functions/test/controls/project/project.deactivate.spec.ts @@ -1,34 +1,50 @@ import { build5Db } from '@build-5/database'; -import { COL, Project, SOON_PROJECT_ID, WenError } from '@build-5/interfaces'; -import { deactivateProject } from '../../../src/runtime/firebase/project/index'; -import * as wallet from '../../../src/utils/wallet.utils'; -import { SOON_PROJ_GUARDIAN, testEnv } from '../../set-up'; -import { createMember, expectThrow, mockWalletReturnValue } from '../common'; +import { + COL, + Project, + ProjectBilling, + ProjectCreateResponse, + SUB_COL, + WEN_FUNC, + WenError, +} from '@build-5/interfaces'; +import { mockWalletReturnValue, testEnv } from '../../set-up'; +import { expectThrow } from '../common'; describe('Project create', () => { - let walletSpy: any; let guardian: string; + let project: Project; + let token: string; beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - guardian = await createMember(walletSpy); + guardian = await testEnv.createMember(); + const dummyProject = { + name: 'My project', + contactEmail: 'myemail@gmail.com', + config: { billing: ProjectBilling.VOLUME_BASED }, + }; + mockWalletReturnValue(guardian, dummyProject); + const { project: newProject } = await testEnv.wrap( + WEN_FUNC.createProject, + ); + project = newProject; + const apiKey = await build5Db().collection(COL.PROJECT, newProject.uid, SUB_COL._API_KEY).get(); + token = apiKey[0].token; }); it('Should deactivate project', async () => { - mockWalletReturnValue(walletSpy, SOON_PROJ_GUARDIAN, {}); - await testEnv.wrap(deactivateProject)({}); - - const projectDocRef = build5Db().doc(`${COL.PROJECT}/${SOON_PROJECT_ID}`); - const projectData = await projectDocRef.get(); + mockWalletReturnValue(guardian, {}, undefined, token); + await testEnv.wrap(WEN_FUNC.deactivateProject); + const projectDocRef = build5Db().doc(COL.PROJECT, project.uid); + const projectData = await projectDocRef.get(); expect(projectData?.deactivated).toBe(true); - - await projectDocRef.update({ deactivated: false }); }); it('Should throw, not guardian of the project', async () => { - mockWalletReturnValue(walletSpy, guardian, {}); + const random = await testEnv.createMember(); + mockWalletReturnValue(random, {}, undefined, token); await expectThrow( - testEnv.wrap(deactivateProject)({}), + testEnv.wrap(WEN_FUNC.deactivateProject), WenError.you_are_not_admin_of_project.key, ); }); diff --git a/packages/functions/test/controls/proposal.spec.ts b/packages/functions/test/controls/proposal.spec.ts index ddc0577f4f..5f4c4009c5 100644 --- a/packages/functions/test/controls/proposal.spec.ts +++ b/packages/functions/test/controls/proposal.spec.ts @@ -1,5 +1,9 @@ import { build5Db } from '@build-5/database'; import { + Access, + Award, + AwardApproveParticipantResponse, + AwardParticipant, COL, Network, NetworkAddress, @@ -11,6 +15,7 @@ import { Space, Token, TokenStatus, + Transaction, WEN_FUNC, WenError, } from '@build-5/interfaces'; @@ -18,28 +23,8 @@ import dayjs from 'dayjs'; import { serverTime } from '../../src/utils/dateTime.utils'; import * as wallet from '../../src/utils/wallet.utils'; import { getRandomEthAddress } from '../../src/utils/wallet.utils'; -import { MEDIA, testEnv } from '../set-up'; -import { - approveAwardParticipant, - awardParticipate, - createAward, -} from './../../src/runtime/firebase/award/index'; -import { - approveProposal, - createProposal, - rejectProposal, - voteOnProposal, -} from './../../src/runtime/firebase/proposal/index'; -import { createSpace, joinSpace } from './../../src/runtime/firebase/space/index'; -import { - addGuardianToSpace, - createMember, - expectThrow, - getRandomSymbol, - mockWalletReturnValue, -} from './common'; - -let walletSpy: any; +import { MEDIA, mockWalletReturnValue, testEnv } from '../set-up'; +import { addGuardianToSpace, expectThrow, getRandomSymbol } from './common'; const dummyBody = (space: string) => ({ name: 'All 4 HORNET', @@ -69,26 +54,26 @@ describe('ProposalController: ' + WEN_FUNC.rejectProposal + ' NATIVE', () => { let body: any; beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - member = await createMember(walletSpy); - mockWalletReturnValue(walletSpy, member, { name: 'Space A' }); - space = await testEnv.wrap(createSpace)({}); - expect(space?.uid).toBeDefined(); + member = await testEnv.createMember(); + space = await testEnv.createSpace(member); body = dummyBody(space.uid); const tokenId = wallet.getRandomEthAddress(); - await build5Db().doc(`${COL.TOKEN}/${tokenId}`).create({ - project: SOON_PROJECT_ID, - uid: tokenId, - space: space.uid, - status: TokenStatus.MINTED, - approved: true, - }); + await build5Db() + .doc(COL.TOKEN, tokenId) + .create({ + links: [] as URL[], + project: SOON_PROJECT_ID, + uid: tokenId, + space: space.uid, + status: TokenStatus.MINTED, + approved: true, + } as Token); }); it('successfully create proposal with name', async () => { - mockWalletReturnValue(walletSpy, member, body); - const cProposal = await testEnv.wrap(createProposal)({}); + mockWalletReturnValue(member, body); + const cProposal = await testEnv.wrap(WEN_FUNC.createProposal); expect(cProposal?.uid).toBeDefined(); expect(cProposal?.name).toEqual(body.name); expect(cProposal?.additionalInfo).toEqual(body.additionalInfo); @@ -96,82 +81,94 @@ describe('ProposalController: ' + WEN_FUNC.rejectProposal + ' NATIVE', () => { expect(cProposal?.questions).toBeDefined(); expect(cProposal?.createdOn).toBeDefined(); expect(cProposal?.updatedOn).toBeDefined(); - walletSpy.mockRestore(); }); describe('Proposal validations', () => { it('empty body', async () => { - mockWalletReturnValue(walletSpy, member, {}); - await expectThrow(testEnv.wrap(createProposal)({}), WenError.invalid_params.key); + mockWalletReturnValue(member, {}); + await expectThrow( + testEnv.wrap(WEN_FUNC.createProposal), + WenError.invalid_params.key, + ); }); it('missing name', async () => { delete body.name; - mockWalletReturnValue(walletSpy, member, body); - await expectThrow(testEnv.wrap(createProposal)({}), WenError.invalid_params.key); + mockWalletReturnValue(member, body); + await expectThrow( + testEnv.wrap(WEN_FUNC.createProposal), + WenError.invalid_params.key, + ); }); it('no questions', async () => { body.questions = []; - mockWalletReturnValue(walletSpy, member, body); - await expectThrow(testEnv.wrap(createProposal)({}), WenError.invalid_params.key); + mockWalletReturnValue(member, body); + await expectThrow( + testEnv.wrap(WEN_FUNC.createProposal), + WenError.invalid_params.key, + ); }); it('only one answer', async () => { delete body.questions[0].answers[1]; - mockWalletReturnValue(walletSpy, member, body); - await expectThrow(testEnv.wrap(createProposal)({}), WenError.invalid_params.key); + mockWalletReturnValue(member, body); + await expectThrow( + testEnv.wrap(WEN_FUNC.createProposal), + WenError.invalid_params.key, + ); }); it('invalid type', async () => { body.type = 2; - mockWalletReturnValue(walletSpy, member, body); - await expectThrow(testEnv.wrap(createProposal)({}), WenError.invalid_params.key); + mockWalletReturnValue(member, body); + await expectThrow( + testEnv.wrap(WEN_FUNC.createProposal), + WenError.invalid_params.key, + ); }); }); ['approve', 'reject'].forEach((s) => { - const command = s === 'approve' ? approveProposal : rejectProposal; + const command = s === 'approve' ? WEN_FUNC.approveProposal : WEN_FUNC.rejectProposal; const field = s === 'approve' ? 'approved' : 'rejected'; it(s + ' proposal', async () => { - mockWalletReturnValue(walletSpy, member, body); - const cProposal = await testEnv.wrap(createProposal)({}); + mockWalletReturnValue(member, body); + const cProposal = await testEnv.wrap(WEN_FUNC.createProposal); expect(cProposal?.uid).toBeDefined(); - mockWalletReturnValue(walletSpy, member, { uid: cProposal.uid }); - const uProposal = await testEnv.wrap(command)({}); + mockWalletReturnValue(member, { uid: cProposal.uid }); + const uProposal = await testEnv.wrap(command); expect(uProposal?.uid).toBeDefined(); expect(uProposal?.[field]).toEqual(true); - walletSpy.mockRestore(); }); it('fail to ' + s + ' proposal (not guardian)', async () => { - mockWalletReturnValue(walletSpy, member, body); - const cProposal = await testEnv.wrap(createProposal)({}); + mockWalletReturnValue(member, body); + const cProposal = await testEnv.wrap(WEN_FUNC.createProposal); expect(cProposal?.uid).toBeDefined(); - mockWalletReturnValue(walletSpy, wallet.getRandomEthAddress(), { uid: cProposal.uid }); - await expectThrow(testEnv.wrap(command)({}), WenError.you_are_not_guardian_of_space.key); - walletSpy.mockRestore(); + const randomUser = await testEnv.createMember(); + mockWalletReturnValue(randomUser, { uid: cProposal.uid }); + await expectThrow(testEnv.wrap(command), WenError.you_are_not_guardian_of_space.key); }); it(s + ' proposal by other guardian (not creator)', async () => { - const guardian2 = wallet.getRandomEthAddress(); - mockWalletReturnValue(walletSpy, guardian2, { uid: space.uid }); - const jSpace = await testEnv.wrap(joinSpace)({}); + const guardian2 = await testEnv.createMember(); + mockWalletReturnValue(guardian2, { uid: space.uid }); + const jSpace = await testEnv.wrap(WEN_FUNC.joinSpace); expect(jSpace).toBeDefined(); expect(jSpace.createdOn).toBeDefined(); expect(jSpace.uid).toEqual(guardian2); await addGuardianToSpace(space.uid, guardian2); - mockWalletReturnValue(walletSpy, member, body); - const cProposal = await testEnv.wrap(createProposal)({}); + mockWalletReturnValue(member, body); + const cProposal = await testEnv.wrap(WEN_FUNC.createProposal); expect(cProposal?.uid).toBeDefined(); - mockWalletReturnValue(walletSpy, guardian2, { uid: cProposal.uid }); - const result = await testEnv.wrap(command)({}); + mockWalletReturnValue(guardian2, { uid: cProposal.uid }); + const result = await testEnv.wrap(command); expect(result?.uid).toBeDefined(); expect(result?.[field]).toEqual(true); - walletSpy.mockRestore(); }); }); }); @@ -182,17 +179,17 @@ describe('ProposalController: ' + WEN_FUNC.createProposal + ' MEMBERS', () => { let token: Token; const cSpace = async (address: NetworkAddress) => { - mockWalletReturnValue(walletSpy, address, { name: 'Space A' }); - const space = await testEnv.wrap(createSpace)({}); + mockWalletReturnValue(address, { name: 'Space A' }); + space = await testEnv.wrap(WEN_FUNC.createSpace); expect(space?.uid).toBeDefined(); return space as Space; }; const jSpace = async (address: NetworkAddress, space: Space) => { - mockWalletReturnValue(walletSpy, address, { uid: space.uid }); - const jSpace = await testEnv.wrap(joinSpace)({}); + mockWalletReturnValue(address, { uid: space.uid }); + const jSpace = await testEnv.wrap(WEN_FUNC.joinSpace); expect(jSpace?.uid).toBeDefined(); - return jSpace as Space; + return jSpace; }; const cProposal = ( @@ -221,20 +218,20 @@ describe('ProposalController: ' + WEN_FUNC.createProposal + ' MEMBERS', () => { }, ], }; - mockWalletReturnValue(walletSpy, address, proposal); - return testEnv.wrap(createProposal)({}); + mockWalletReturnValue(address, proposal); + return testEnv.wrap(WEN_FUNC.createProposal); }; const apprProposal = async (address: NetworkAddress, proposal: any) => { - mockWalletReturnValue(walletSpy, address, { uid: proposal.uid }); - const pr = await testEnv.wrap(approveProposal)({}); + mockWalletReturnValue(address, { uid: proposal.uid }); + const pr = await testEnv.wrap(WEN_FUNC.approveProposal); expect(proposal?.uid).toBeDefined(); return pr; }; const vote = async (address: NetworkAddress, proposal: any, value: number) => { - mockWalletReturnValue(walletSpy, address, { uid: proposal.uid, value }); - const pr = await testEnv.wrap(voteOnProposal)({}); + mockWalletReturnValue(address, { uid: proposal.uid, value }); + const pr = await testEnv.wrap(WEN_FUNC.voteOnProposal); expect(proposal?.uid).toBeDefined(); return pr; }; @@ -246,7 +243,7 @@ describe('ProposalController: ' + WEN_FUNC.createProposal + ' MEMBERS', () => { tokenSymbol: string, tokenReward = 0, ) => { - mockWalletReturnValue(walletSpy, address, { + mockWalletReturnValue(address, { name: 'Award A', description: 'Finish this and that', space: space?.uid, @@ -262,19 +259,21 @@ describe('ProposalController: ' + WEN_FUNC.createProposal + ' MEMBERS', () => { }, network: Network.RMS, }); - const award = await testEnv.wrap(createAward)({}); + const award = await testEnv.wrap(WEN_FUNC.createAward); expect(award?.uid).toBeDefined(); - await build5Db().doc(`${COL.AWARD}/${award.uid}`).update({ approved: true, address: '' }); + await build5Db().doc(COL.AWARD, award.uid).update({ approved: true, address: '' }); // Participate - mockWalletReturnValue(walletSpy, address, { uid: award?.uid }); - const returnsParti = await testEnv.wrap(awardParticipate)({}); + mockWalletReturnValue(address, { uid: award?.uid }); + const returnsParti = await testEnv.wrap(WEN_FUNC.participateAward); expect(returnsParti?.uid).toBeDefined(); // Approve - mockWalletReturnValue(walletSpy, guardian, { award: award.uid, members: [address] }); - const returns2 = await testEnv.wrap(approveAwardParticipant)({}); + mockWalletReturnValue(guardian, { award: award.uid, members: [address] }); + const returns2 = await testEnv.wrap( + WEN_FUNC.approveParticipantAward, + ); expect(Object.keys(returns2?.badges).length).toBe(1); return award; @@ -284,8 +283,7 @@ describe('ProposalController: ' + WEN_FUNC.createProposal + ' MEMBERS', () => { // Disable start date validation. ProposalStartDateMin.value = -60 * 60; RelatedRecordsResponse.status = true; - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - memberId = await createMember(walletSpy); + memberId = await testEnv.createMember(); space = await cSpace(memberId); token = await saveBaseToken(space.uid, memberId); @@ -311,13 +309,12 @@ describe('ProposalController: ' + WEN_FUNC.createProposal + ' MEMBERS', () => { expect(vResult?.payload?.weight).toEqual(1); await vote(memberId, proposal, 2); - const proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${proposal.uid}`); + const proposalDocRef = build5Db().doc(COL.PROPOSAL, proposal.uid); proposal = await proposalDocRef.get(); - expect(proposal.results.answers[2]).toBe(1); }); - it('create proposal, approve & vote twice on different ', async () => { + it('create proposal, approve & vote twice on different', async () => { await giveBadge(memberId, memberId, space, token.symbol, 10); let proposal: Proposal = await cProposal(memberId, space, ProposalType.MEMBERS); @@ -326,9 +323,10 @@ describe('ProposalController: ' + WEN_FUNC.createProposal + ' MEMBERS', () => { const vResult = await vote(memberId, proposal, 2); expect(vResult?.payload).toBeDefined(); expect(vResult?.payload?.weight).toEqual(1); + await vote(memberId, proposal, 1); - const proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${proposal.uid}`); + const proposalDocRef = build5Db().doc(COL.PROPOSAL, proposal.uid); proposal = await proposalDocRef.get(); expect(proposal.results.answers[2]).toBe(0); @@ -336,14 +334,14 @@ describe('ProposalController: ' + WEN_FUNC.createProposal + ' MEMBERS', () => { }); it('create proposal, approve & vote - 7 ppl all same', async () => { - const memberId = await createMember(walletSpy); - const memberId1 = await createMember(walletSpy); - const memberId2 = await createMember(walletSpy); - const memberId3 = await createMember(walletSpy); - const memberId4 = await createMember(walletSpy); - const memberId5 = await createMember(walletSpy); - const memberId6 = await createMember(walletSpy); - const memberId7 = await createMember(walletSpy); + const memberId = await testEnv.createMember(); + const memberId1 = await testEnv.createMember(); + const memberId2 = await testEnv.createMember(); + const memberId3 = await testEnv.createMember(); + const memberId4 = await testEnv.createMember(); + const memberId5 = await testEnv.createMember(); + const memberId6 = await testEnv.createMember(); + const memberId7 = await testEnv.createMember(); const space = await cSpace(memberId); await jSpace(memberId1, space); await jSpace(memberId2, space); @@ -367,8 +365,8 @@ describe('ProposalController: ' + WEN_FUNC.createProposal + ' MEMBERS', () => { expect(v?.payload).toBeDefined(); expect(v?.payload?.weight).toEqual(1); - const proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${proposal.uid}`); - proposal = await proposalDocRef.get(); + const proposalDocRef = build5Db().doc(COL.PROPOSAL, proposal.uid); + proposal = (await proposalDocRef.get())!; expect(proposal.results.answers['1']).toEqual(7); expect(proposal.results.voted).toEqual(7); expect(proposal.results.total).toEqual(8); @@ -376,14 +374,14 @@ describe('ProposalController: ' + WEN_FUNC.createProposal + ' MEMBERS', () => { }); it('create proposal, approve & vote - 7 ppl 4/3', async () => { - const memberId = await createMember(walletSpy); - const memberId1 = await createMember(walletSpy); - const memberId2 = await createMember(walletSpy); - const memberId3 = await createMember(walletSpy); - const memberId4 = await createMember(walletSpy); - const memberId5 = await createMember(walletSpy); - const memberId6 = await createMember(walletSpy); - const memberId7 = await createMember(walletSpy); + const memberId = await testEnv.createMember(); + const memberId1 = await testEnv.createMember(); + const memberId2 = await testEnv.createMember(); + const memberId3 = await testEnv.createMember(); + const memberId4 = await testEnv.createMember(); + const memberId5 = await testEnv.createMember(); + const memberId6 = await testEnv.createMember(); + const memberId7 = await testEnv.createMember(); const space = await cSpace(memberId); await jSpace(memberId1, space); await jSpace(memberId2, space); @@ -406,8 +404,8 @@ describe('ProposalController: ' + WEN_FUNC.createProposal + ' MEMBERS', () => { expect(v?.payload).toBeDefined(); expect(v?.payload?.weight).toEqual(1); - const proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${proposal.uid}`); - proposal = await proposalDocRef.get(); + const proposalDocRef = build5Db().doc(COL.PROPOSAL, proposal.uid); + proposal = (await proposalDocRef.get())!; expect(proposal.results.answers['1']).toEqual(4); expect(proposal.results.answers['2']).toEqual(3); expect(proposal.results.voted).toEqual(7); @@ -416,12 +414,12 @@ describe('ProposalController: ' + WEN_FUNC.createProposal + ' MEMBERS', () => { }); it('create proposal, approve & vote - 4 ppl badges', async () => { - const memberId = await createMember(walletSpy); - const memberId1 = await createMember(walletSpy); - const memberId2 = await createMember(walletSpy); - const memberId3 = await createMember(walletSpy); - const memberId4 = await createMember(walletSpy); - const memberId5 = await createMember(walletSpy); + const memberId = await testEnv.createMember(); + const memberId1 = await testEnv.createMember(); + const memberId2 = await testEnv.createMember(); + const memberId3 = await testEnv.createMember(); + const memberId4 = await testEnv.createMember(); + const memberId5 = await testEnv.createMember(); const space = await cSpace(memberId); await jSpace(memberId1, space); await jSpace(memberId2, space); @@ -455,8 +453,8 @@ describe('ProposalController: ' + WEN_FUNC.createProposal + ' MEMBERS', () => { expect(v?.payload).toBeDefined(); expect(v?.payload?.weight).toEqual(1); - const proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${proposal.uid}`); - proposal = await proposalDocRef.get(); + const proposalDocRef = build5Db().doc(COL.PROPOSAL, proposal.uid); + proposal = (await proposalDocRef.get())!; expect(proposal.results.answers['1']).toEqual(2); expect(proposal.results.answers['2']).toEqual(3); expect(proposal.results.voted).toEqual(5); @@ -470,19 +468,18 @@ export const saveBaseToken = async (space: string, guardian: string) => { project: SOON_PROJECT_ID, symbol: getRandomSymbol(), approved: true, - updatedOn: serverTime(), - createdOn: serverTime(), + updatedOn: serverTime().toDate(), + createdOn: serverTime().toDate(), space, uid: getRandomEthAddress(), createdBy: guardian, name: 'MyToken', status: TokenStatus.BASE, - access: 0, + access: Access.OPEN, icon: MEDIA, - mintingData: { - network: Network.RMS, - }, + mintingData_network: Network.RMS, }; - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).set(token); - return token as Token; + const docRef = build5Db().doc(COL.TOKEN, token.uid); + await docRef.upsert(token); + return (await docRef.get())!; }; diff --git a/packages/functions/test/controls/space.spec.ts b/packages/functions/test/controls/space.spec.ts index 8613f80782..8bfd9b647a 100644 --- a/packages/functions/test/controls/space.spec.ts +++ b/packages/functions/test/controls/space.spec.ts @@ -9,9 +9,8 @@ import { SOON_PROJECT_ID, SUB_COL, Space, - StakeType, + SpaceMember, TokenStatus, - Transaction, TransactionType, UPDATE_SPACE_THRESHOLD_PERCENTAGE, WEN_FUNC, @@ -19,32 +18,9 @@ import { } from '@build-5/interfaces'; import dayjs from 'dayjs'; import { tail } from 'lodash'; -import { voteOnProposal } from '../../src/runtime/firebase/proposal'; -import { - acceptMemberSpace, - addGuardian, - blockMember, - createSpace, - declineMemberSpace, - joinSpace, - leaveSpace, - removeGuardian, - unblockMember, - updateSpace, -} from '../../src/runtime/firebase/space'; import * as wallet from '../../src/utils/wallet.utils'; -import { testEnv } from '../set-up'; -import { - addGuardianToSpace, - createMember, - createSpace as createSpaceFunc, - expectThrow, - mockWalletReturnValue, - removeGuardianFromSpace, - wait, -} from './common'; - -let walletSpy: any; +import { mockWalletReturnValue, testEnv } from '../set-up'; +import { addGuardianToSpace, expectThrow, removeGuardianFromSpace, wait } from './common'; const assertCreatedOnAndId = (data: any, uid: string) => { expect(data).toBeDefined(); @@ -53,65 +29,53 @@ const assertCreatedOnAndId = (data: any, uid: string) => { }; const joinSpaceFunc = async (member: string, uid: string) => { - mockWalletReturnValue(walletSpy, member, { uid }); - const jSpace = await testEnv.wrap(joinSpace)({}); + mockWalletReturnValue(member, { uid }); + const jSpace = await testEnv.wrap(WEN_FUNC.joinSpace); assertCreatedOnAndId(jSpace, member); }; -/** - * TODO - * at_least_one_guardian_must_be_in_the_space - */ -describe('SpaceController: ' + WEN_FUNC.createSpace, () => { - it('successfully create space', async () => { - const dummyAddress = wallet.getRandomEthAddress(); - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - mockWalletReturnValue(walletSpy, dummyAddress, {}); - - const returns = await testEnv.wrap(createSpace)({}); - expect(returns?.uid).toBeDefined(); - expect(returns?.createdOn).toBeDefined(); - expect(returns?.updatedOn).toBeDefined(); - - // am I member and guardian. - expect(returns.members).toBeDefined(); - expect(returns.members[dummyAddress]).toBeDefined(); - expect(returns.guardians).toBeDefined(); - expect(returns.guardians[dummyAddress]).toBeDefined(); - expect(returns?.totalGuardians).toEqual(1); - expect(returns?.totalMembers).toEqual(1); - expect(returns?.totalPendingMembers).toEqual(0); - walletSpy.mockRestore(); - }); - - it('successfully create space with name', async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - mockWalletReturnValue(walletSpy, wallet.getRandomEthAddress(), { - name: 'Space ABC', - about: 'very cool', +/** * TODO * at_least_one_guardian_must_be_in_the_space */ describe( + 'SpaceController: ' + WEN_FUNC.createSpace, + () => { + let member: string; + beforeEach(async () => { + member = await testEnv.createMember(); }); - const returns = await testEnv.wrap(createSpace)({}); - expect(returns?.uid).toBeDefined(); - expect(returns?.name).toEqual('Space ABC'); - expect(returns?.about).toEqual('very cool'); - expect(returns?.totalGuardians).toEqual(1); - expect(returns?.totalMembers).toEqual(1); - walletSpy.mockRestore(); - }); -}); + it('successfully create space', async () => { + mockWalletReturnValue(member, {}); + const space = await testEnv.wrap(WEN_FUNC.createSpace); + expect(space.uid).toBeDefined(); + expect(space.createdOn).toBeDefined(); + expect(space.updatedOn).toBeDefined(); + expect(space.totalGuardians).toEqual(1); + expect(space.totalMembers).toEqual(1); + expect(space.totalPendingMembers).toEqual(0); + }); + + it('successfully create space with name', async () => { + mockWalletReturnValue(member, { + name: 'Space ABC', + about: 'very cool', + }); + const space = await testEnv.wrap(WEN_FUNC.createSpace); + expect(space.uid).toBeDefined(); + expect(space.name).toEqual('Space ABC'); + expect(space.about).toEqual('very cool'); + expect(space.totalGuardians).toEqual(1); + expect(space.totalMembers).toEqual(1); + }); + }, +); describe('SpaceController: ' + WEN_FUNC.updateSpace, () => { let guardian: string; let member: string; let space: Space; - beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - guardian = await createMember(walletSpy); - member = await createMember(walletSpy); - space = await createSpaceFunc(walletSpy, guardian); - + guardian = await testEnv.createMember(); + member = await testEnv.createMember(); + space = await testEnv.createSpace(guardian); await addGuardianToSpace(space.uid, member); }); @@ -123,41 +87,29 @@ describe('SpaceController: ' + WEN_FUNC.updateSpace, () => { twitter: 'asdasd', discord: 'adamkun1233', }; - const owner = await build5Db().doc(`${COL.MEMBER}/${guardian}`).get(); - mockWalletReturnValue(walletSpy, guardian, updateParams); - const proposal = await testEnv.wrap(updateSpace)({}); - + const owner = await build5Db().doc(COL.MEMBER, guardian).get(); + mockWalletReturnValue(guardian, updateParams); + const proposal = await testEnv.wrap(WEN_FUNC.updateSpace); expect(proposal.type).toBe(ProposalType.EDIT_SPACE); expect(proposal.approved).toBe(true); expect(proposal.results?.total).toBe(2); expect(proposal.results?.voted).toBe(1); expect(proposal.results?.answers).toEqual({ [1]: 1 }); expect(proposal.additionalInfo).toBe( - `${owner.name} wants to edit the space. ` + + `${owner.uid} wants to edit the space. ` + `Request created on ${dayjs().format('MM/DD/YYYY')}. ` + `${UPDATE_SPACE_THRESHOLD_PERCENTAGE} % must agree for this action to proceed`, ); expect(proposal.name).toBe('Edit space'); - - // TODO - I'm running out of time and need to release this. - // expect(proposal.questions[0].additionalInfo).toBe( - // 'Changes requested.
' + - // 'Name: abc (previously: Space A)
' + - // 'Discord: adamkun1233 (previously: None)
' + - // 'Github: sadas (previously: None)
' + - // 'Twitter: asdasd (previously: None)
', - // ); - - space = await build5Db().doc(`${COL.SPACE}/${space.uid}`).get(); + // TODO - I'm running out of time and need to release this. // expect(proposal.questions[0].additionalInfo).toBe( // 'Changes requested.
' + // 'Name: abc (previously: Space A)
' + // 'Discord: adamkun1233 (previously: None)
' + // 'Github: sadas (previously: None)
' + // 'Twitter: asdasd (previously: None)
', // ); + space = await build5Db().doc(COL.SPACE, space.uid).get(); const updatedOn = space.updatedOn; - mockWalletReturnValue(walletSpy, member, { uid: proposal.uid, value: 1 }); - await testEnv.wrap(voteOnProposal)({}); - + mockWalletReturnValue(member, { uid: proposal.uid, value: 1 }); + await testEnv.wrap(WEN_FUNC.voteOnProposal); await wait(async () => { - space = await build5Db().doc(`${COL.SPACE}/${space.uid}`).get(); + space = await build5Db().doc(COL.SPACE, space.uid).get(); return dayjs(updatedOn?.toDate()).isBefore(dayjs(space.updatedOn?.toDate())); }); - expect(space.name).toBe(updateParams.name); expect(space.github).toBe(updateParams.github); expect(space.twitter).toBe(updateParams.twitter); @@ -166,34 +118,32 @@ describe('SpaceController: ' + WEN_FUNC.updateSpace, () => { it('failed to update space - invalid URL', async () => { const updateParams = { uid: space?.uid, name: 'abc', twitter: 'WRONG URL' }; - mockWalletReturnValue(walletSpy, guardian, updateParams); - await expectThrow(testEnv.wrap(updateSpace)({}), WenError.invalid_params.key); - walletSpy.mockRestore(); + mockWalletReturnValue(guardian, updateParams); + await expectThrow(testEnv.wrap(WEN_FUNC.updateSpace), WenError.invalid_params.key); }); it('failed to update space - missing UID', async () => { - mockWalletReturnValue(walletSpy, guardian, { name: 'abc' }); - await expectThrow(testEnv.wrap(updateSpace)({}), WenError.invalid_params.key); - walletSpy.mockRestore(); + mockWalletReturnValue(guardian, { name: 'abc' }); + await expectThrow(testEnv.wrap(WEN_FUNC.updateSpace), WenError.invalid_params.key); }); it('failed to update space - does not exists', async () => { - mockWalletReturnValue(walletSpy, guardian, { uid: guardian, name: 'abc' }); - await expectThrow(testEnv.wrap(updateSpace)({}), WenError.space_does_not_exists.key); - walletSpy.mockRestore(); + mockWalletReturnValue(guardian, { uid: guardian, name: 'abc' }); + await expectThrow(testEnv.wrap(WEN_FUNC.updateSpace), WenError.space_does_not_exists.key); }); it('Should only allow one ongoing edit proposal', async () => { const updateParams = { uid: space?.uid, name: 'new name' }; - mockWalletReturnValue(walletSpy, guardian, updateParams); - const proposal = await testEnv.wrap(updateSpace)({}); - await expectThrow(testEnv.wrap(updateSpace)({}), WenError.ongoing_proposal.key); + mockWalletReturnValue(guardian, updateParams); + const proposal = await testEnv.wrap(WEN_FUNC.updateSpace); - mockWalletReturnValue(walletSpy, member, { uid: proposal.uid, value: 1 }); - await testEnv.wrap(voteOnProposal)({}); + mockWalletReturnValue(guardian, updateParams); + await expectThrow(testEnv.wrap(WEN_FUNC.updateSpace), WenError.ongoing_proposal.key); + mockWalletReturnValue(member, { uid: proposal.uid, value: 1 }); + await testEnv.wrap(WEN_FUNC.voteOnProposal); await wait(async () => { - space = await build5Db().doc(`${COL.SPACE}/${space.uid}`).get(); + space = await build5Db().doc(COL.SPACE, space.uid).get(); return space.name === 'new name'; }); }); @@ -205,102 +155,113 @@ describe('SpaceController: member management', () => { let space: Space; beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - guardian = wallet.getRandomEthAddress(); - member = wallet.getRandomEthAddress(); - mockWalletReturnValue(walletSpy, guardian, { name: 'This space rocks' }); - space = await testEnv.wrap(createSpace)({}); - expect(space?.uid).toBeDefined(); + guardian = await testEnv.createMember(); + member = await testEnv.createMember(); + mockWalletReturnValue(guardian, { name: 'This space rocks' }); + space = await testEnv.wrap(WEN_FUNC.createSpace); }); it('successfully join space', async () => { await joinSpaceFunc(member, space.uid); - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${member}`); + const memberDocRef = build5Db().doc(COL.MEMBER, member); const memberData = await memberDocRef.get(); expect((memberData.spaces || {})[space.uid].isMember).toBe(true); }); it('fail to join space - already in', async () => { - mockWalletReturnValue(walletSpy, guardian, { uid: space.uid }); - await expectThrow(testEnv.wrap(joinSpace)({}), WenError.you_are_already_part_of_space.key); + mockWalletReturnValue(guardian, { uid: space.uid }); + await expectThrow( + testEnv.wrap(WEN_FUNC.joinSpace), + WenError.you_are_already_part_of_space.key, + ); }); it('successfully leave space', async () => { await joinSpaceFunc(member, space.uid); - const lSpace = await testEnv.wrap(leaveSpace)({}); + mockWalletReturnValue(member, { uid: space.uid }); + const lSpace = await testEnv.wrap<{ status: string }>(WEN_FUNC.leaveSpace); expect(lSpace).toBeDefined(); expect(lSpace.status).toEqual('success'); - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${member}`); + const memberDocRef = build5Db().doc(COL.MEMBER, member); const memberData = await memberDocRef.get(); expect((memberData.spaces || {})[space.uid].isMember).toBe(false); }); it('fail to leave space - as only guardian', async () => { await joinSpaceFunc(member, space.uid); - mockWalletReturnValue(walletSpy, guardian, { uid: space.uid }); + mockWalletReturnValue(guardian, { uid: space.uid }); await expectThrow( - testEnv.wrap(leaveSpace)({}), + testEnv.wrap(WEN_FUNC.leaveSpace), WenError.at_least_one_guardian_must_be_in_the_space.key, ); }); it('fail to leave space - as only member', async () => { - mockWalletReturnValue(walletSpy, guardian, { uid: space.uid }); + mockWalletReturnValue(guardian, { uid: space.uid }); await expectThrow( - testEnv.wrap(leaveSpace)({}), + testEnv.wrap(WEN_FUNC.leaveSpace), WenError.at_least_one_member_must_be_in_the_space.key, ); }); it('fail to leave space where Im not in', async () => { - mockWalletReturnValue(walletSpy, member, { uid: space.uid }); - await expectThrow(testEnv.wrap(leaveSpace)({}), WenError.you_are_not_part_of_the_space.key); + mockWalletReturnValue(member, { uid: space.uid }); + await expectThrow( + testEnv.wrap(WEN_FUNC.leaveSpace), + WenError.you_are_not_part_of_the_space.key, + ); }); it('fail to make guardian - must be member', async () => { - mockWalletReturnValue(walletSpy, guardian, { uid: space.uid, member }); - await expectThrow(testEnv.wrap(addGuardian)({}), WenError.member_is_not_part_of_the_space.key); + mockWalletReturnValue(guardian, { uid: space.uid, member }); + await expectThrow( + testEnv.wrap(WEN_FUNC.addGuardianSpace), + WenError.member_is_not_part_of_the_space.key, + ); }); it('fail to make guardian - already is', async () => { - mockWalletReturnValue(walletSpy, guardian, { uid: space.uid, member: guardian }); + mockWalletReturnValue(guardian, { uid: space.uid, member: guardian }); await expectThrow( - testEnv.wrap(addGuardian)({}), + testEnv.wrap(WEN_FUNC.addGuardianSpace), WenError.member_is_already_guardian_of_space.key, ); }); it('successfully block member', async () => { await joinSpaceFunc(member, space.uid); - mockWalletReturnValue(walletSpy, guardian, { uid: space.uid, member }); - const blockMemberResult = await testEnv.wrap(blockMember)({}); + mockWalletReturnValue(guardian, { uid: space.uid, member }); + const blockMemberResult = await testEnv.wrap(WEN_FUNC.blockMemberSpace); assertCreatedOnAndId(blockMemberResult, member); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${space.uid}`); + const spaceDocRef = build5Db().doc(COL.SPACE, space.uid); space = await spaceDocRef.get(); expect(space.totalGuardians).toBe(1); expect(space.totalMembers).toBe(1); - const guardianCount = await spaceDocRef.collection(SUB_COL.GUARDIANS).count(); + const guardianCount = await build5Db() + .collection(COL.SPACE, space.uid, SUB_COL.GUARDIANS) + .count(); expect(guardianCount).toBe(1); - const memberCount = await spaceDocRef.collection(SUB_COL.MEMBERS).count(); + const memberCount = await build5Db().collection(COL.SPACE, space.uid, SUB_COL.MEMBERS).count(); expect(memberCount).toBe(1); }); it('block member and unblock', async () => { await joinSpaceFunc(member, space.uid); - mockWalletReturnValue(walletSpy, guardian, { uid: space.uid, member }); - const bMember = await testEnv.wrap(blockMember)({}); + mockWalletReturnValue(guardian, { uid: space.uid, member }); + const bMember = await testEnv.wrap(WEN_FUNC.blockMemberSpace); assertCreatedOnAndId(bMember, member); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${space.uid}`); - const blockedDocRef = spaceDocRef.collection(SUB_COL.BLOCKED_MEMBERS).doc(member); + const spaceDocRef = build5Db().doc(COL.SPACE, space.uid); + const blockedDocRef = build5Db().doc(COL.SPACE, space.uid, SUB_COL.BLOCKED_MEMBERS, member); let blocked = await blockedDocRef.get(); expect(blocked).toBeDefined(); - const ubMember = await testEnv.wrap(unblockMember)({}); + mockWalletReturnValue(guardian, { uid: space.uid, member }); + const ubMember = await testEnv.wrap<{ status: string }>(WEN_FUNC.unblockMemberSpace); expect(ubMember).toBeDefined(); expect(ubMember.status).toEqual('success'); @@ -308,10 +269,12 @@ describe('SpaceController: member management', () => { expect(space.totalGuardians).toBe(1); expect(space.totalMembers).toBe(1); - const guardianCount = await spaceDocRef.collection(SUB_COL.GUARDIANS).count(); + const guardianCount = await build5Db() + .collection(COL.SPACE, space.uid, SUB_COL.GUARDIANS) + .count(); expect(guardianCount).toBe(1); - const memberCount = await spaceDocRef.collection(SUB_COL.MEMBERS).count(); + const memberCount = await build5Db().collection(COL.SPACE, space.uid, SUB_COL.MEMBERS).count(); expect(memberCount).toBe(1); blocked = await blockedDocRef.get(); @@ -319,36 +282,37 @@ describe('SpaceController: member management', () => { }); it('fail to block member - if its the only one', async () => { - mockWalletReturnValue(walletSpy, guardian, { uid: space.uid, member: guardian }); + mockWalletReturnValue(guardian, { uid: space.uid, member: guardian }); await expectThrow( - testEnv.wrap(blockMember)({}), + testEnv.wrap(WEN_FUNC.blockMemberSpace), WenError.at_least_one_member_must_be_in_the_space.key, ); }); it('fail to block myself if Im only guardian', async () => { await joinSpaceFunc(member, space.uid); - mockWalletReturnValue(walletSpy, guardian, { uid: space.uid, member: guardian }); - await expectThrow(testEnv.wrap(blockMember)({}), WenError.can_not_block_guardian.key); + mockWalletReturnValue(guardian, { uid: space.uid, member: guardian }); + await expectThrow(testEnv.wrap(WEN_FUNC.blockMemberSpace), WenError.can_not_block_guardian.key); }); it('successfully block member and unable to join space', async () => { await joinSpaceFunc(member, space.uid); - - mockWalletReturnValue(walletSpy, guardian, { uid: space.uid, member }); - const bMember = await testEnv.wrap(blockMember)({}); + mockWalletReturnValue(guardian, { uid: space.uid, member }); + const bMember = await testEnv.wrap(WEN_FUNC.blockMemberSpace); assertCreatedOnAndId(bMember, member); - mockWalletReturnValue(walletSpy, member, { uid: space.uid }); - await expectThrow(testEnv.wrap(joinSpace)({}), WenError.you_are_not_allowed_to_join_space.key); + mockWalletReturnValue(member, { uid: space.uid }); + await expectThrow( + testEnv.wrap(WEN_FUNC.joinSpace), + WenError.you_are_not_allowed_to_join_space.key, + ); }); describe('SpaceController: member management - NOT OPEN', () => { beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - guardian = await createMember(walletSpy); - member = await createMember(walletSpy); - space = await createSpaceFunc(walletSpy, guardian); - await build5Db().doc(`${COL.SPACE}/${space.uid}`).update({ open: false }); + guardian = await testEnv.createMember(); + member = await testEnv.createMember(); + space = await testEnv.createSpace(guardian); + await build5Db().doc(COL.SPACE, space.uid).update({ open: false }); }); it('successfully join space', async () => { @@ -357,91 +321,76 @@ describe('SpaceController: member management', () => { it('successfully join space and fail to accept - NOT GUARDIAN', async () => { await joinSpaceFunc(member, space.uid); - - mockWalletReturnValue(walletSpy, member, { uid: space.uid, member }); + mockWalletReturnValue(member, { uid: space.uid, member }); await expectThrow( - testEnv.wrap(acceptMemberSpace)({}), + testEnv.wrap(WEN_FUNC.acceptMemberSpace), WenError.you_are_not_guardian_of_space.key, ); }); it('successfully join space and be accepted', async () => { await joinSpaceFunc(member, space.uid); - - mockWalletReturnValue(walletSpy, guardian, { uid: space.uid, member }); - const aSpace = await testEnv.wrap(acceptMemberSpace)({}); + mockWalletReturnValue(guardian, { uid: space.uid, member }); + const aSpace = await testEnv.wrap(WEN_FUNC.acceptMemberSpace); assertCreatedOnAndId(aSpace, member); }); it('join space, edit space and still able to accept', async () => { await joinSpaceFunc(member, space.uid); - - const guardian2 = await createMember(walletSpy); + const guardian2 = await testEnv.createMember(); await addGuardianToSpace(space.uid, guardian2); const name = 'This space rocks rocks'; - mockWalletReturnValue(walletSpy, guardian, { - uid: space.uid, - name, - open: false, - }); - const proposal = await testEnv.wrap(updateSpace)({}); - - mockWalletReturnValue(walletSpy, guardian2, { uid: proposal.uid, value: 1 }); - await testEnv.wrap(voteOnProposal)({}); - + mockWalletReturnValue(guardian, { uid: space.uid, name, open: false }); + const proposal = await testEnv.wrap(WEN_FUNC.updateSpace); + mockWalletReturnValue(guardian2, { uid: proposal.uid, value: 1 }); + await testEnv.wrap(WEN_FUNC.voteOnProposal); await wait(async () => { - space = await build5Db().doc(`${COL.SPACE}/${space.uid}`).get(); + space = await build5Db().doc(COL.SPACE, space.uid).get(); return space.name === name; }); - - mockWalletReturnValue(walletSpy, guardian, { uid: space.uid, member }); - const aSpace = await testEnv.wrap(acceptMemberSpace)({}); + mockWalletReturnValue(guardian, { uid: space.uid, member }); + const aSpace = await testEnv.wrap(WEN_FUNC.acceptMemberSpace); assertCreatedOnAndId(aSpace, member); }); it('join space, edit space to open and it should no longer be able to accept', async () => { await joinSpaceFunc(member, space.uid); - - const guardian2 = await createMember(walletSpy); + const guardian2 = await testEnv.createMember(); await addGuardianToSpace(space.uid, guardian2); - const name = 'This space rocks rocks'; - mockWalletReturnValue(walletSpy, guardian, { - uid: space.uid, - name, - open: true, - }); - const proposal = await testEnv.wrap(updateSpace)({}); - - mockWalletReturnValue(walletSpy, guardian2, { uid: proposal.uid, value: 1 }); - await testEnv.wrap(voteOnProposal)({}); - + mockWalletReturnValue(guardian, { uid: space.uid, name, open: true }); + const proposal = await testEnv.wrap(WEN_FUNC.updateSpace); + mockWalletReturnValue(guardian2, { uid: proposal.uid, value: 1 }); + await testEnv.wrap(WEN_FUNC.voteOnProposal); await wait(async () => { - space = await build5Db().doc(`${COL.SPACE}/${space.uid}`).get(); + space = await build5Db().doc(COL.SPACE, space.uid).get(); return space.name === name; }); - mockWalletReturnValue(walletSpy, guardian, { uid: space.uid, member }); + mockWalletReturnValue(guardian, { uid: space.uid, member }); await expectThrow( - testEnv.wrap(acceptMemberSpace)({}), + testEnv.wrap(WEN_FUNC.acceptMemberSpace), WenError.member_did_not_request_to_join.key, ); }); it('successfully join space and be rejected', async () => { await joinSpaceFunc(member, space.uid); - - mockWalletReturnValue(walletSpy, guardian, { uid: space.uid, member }); - const declineMemberResult = await testEnv.wrap(declineMemberSpace)({}); + mockWalletReturnValue(guardian, { uid: space.uid, member }); + const declineMemberResult = await testEnv.wrap<{ status: string }>( + WEN_FUNC.declineMemberSpace, + ); expect(declineMemberResult).toBeDefined(); expect(declineMemberResult.status).toEqual('success'); }); it('Should throw on second time when member ask to join', async () => { await joinSpaceFunc(member, space.uid); - - mockWalletReturnValue(walletSpy, member, { uid: space.uid }); - await expectThrow(testEnv.wrap(joinSpace)({}), WenError.member_already_knocking.key); + mockWalletReturnValue(member, { uid: space.uid }); + await expectThrow( + testEnv.wrap(WEN_FUNC.joinSpace), + WenError.member_already_knocking.key, + ); }); }); }); @@ -453,139 +402,137 @@ describe('Add guardian', () => { let space: Space; beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - let promises: any[] = Array.from(Array(guardianCount)).map(() => createMember(walletSpy)); + let promises: any[] = Array.from(Array(guardianCount)).map(() => testEnv.createMember()); guardians = await Promise.all(promises); - member = await createMember(walletSpy); - space = await createSpaceFunc(walletSpy, guardians[0]); - + member = await testEnv.createMember(); + space = await testEnv.createSpace(guardians[0]); promises = tail(guardians).map(async (guardian) => addGuardianToSpace(space.uid, guardian)); await Promise.all(promises); }); it('Should throw, not guardian of the space', async () => { - mockWalletReturnValue(walletSpy, member, { uid: space.uid, member }); - await expectThrow(testEnv.wrap(addGuardian)({}), WenError.you_are_not_guardian_of_space.key); - mockWalletReturnValue(walletSpy, guardians[0], { uid: wallet.getRandomEthAddress(), member }); - await expectThrow(testEnv.wrap(addGuardian)({}), WenError.you_are_not_guardian_of_space.key); + mockWalletReturnValue(member, { uid: space.uid, member }); + await expectThrow( + testEnv.wrap(WEN_FUNC.addGuardianSpace), + WenError.you_are_not_guardian_of_space.key, + ); + mockWalletReturnValue(guardians[0], { uid: wallet.getRandomEthAddress(), member }); + await expectThrow( + testEnv.wrap(WEN_FUNC.addGuardianSpace), + WenError.you_are_not_guardian_of_space.key, + ); }); it('Should throw, member not part of space', async () => { - mockWalletReturnValue(walletSpy, guardians[0], { uid: space.uid, member }); - await expectThrow(testEnv.wrap(addGuardian)({}), WenError.member_is_not_part_of_the_space.key); + mockWalletReturnValue(guardians[0], { uid: space.uid, member }); + await expectThrow( + testEnv.wrap(WEN_FUNC.addGuardianSpace), + WenError.member_is_not_part_of_the_space.key, + ); }); it('Should throw, member already guardian', async () => { - mockWalletReturnValue(walletSpy, guardians[0], { uid: space.uid, member: guardians[0] }); + mockWalletReturnValue(guardians[0], { + uid: space.uid, + member: guardians[0], + }); await expectThrow( - testEnv.wrap(addGuardian)({}), + testEnv.wrap(WEN_FUNC.addGuardianSpace), WenError.member_is_already_guardian_of_space.key, ); }); const createProposal = async (type: ProposalType, resultTotal: number) => { - mockWalletReturnValue(walletSpy, guardians[0], { uid: space.uid, member }); - const proposal: Proposal = await testEnv.wrap( - type === ProposalType.ADD_GUARDIAN ? addGuardian : removeGuardian, - )({}); - - const guardianData = await build5Db().doc(`${COL.MEMBER}/${guardians[0]}`).get(); - const memberData = await build5Db().doc(`${COL.MEMBER}/${member}`).get(); - + const wenFunc = + type === ProposalType.ADD_GUARDIAN ? WEN_FUNC.addGuardianSpace : WEN_FUNC.removeGuardianSpace; + mockWalletReturnValue(guardians[0], { uid: space.uid, member }); + const proposal = await testEnv.wrap(wenFunc); + const guardianData = await build5Db().doc(COL.MEMBER, guardians[0]).get(); + const memberData = await build5Db().doc(COL.MEMBER, member).get(); expect(proposal.type).toBe(type); expect(proposal.approved).toBe(true); expect(proposal.results?.total).toBe(resultTotal); expect(proposal.results?.voted).toBe(1); expect(proposal.results?.answers).toEqual({ [1]: 1 }); expect(proposal.additionalInfo).toBe( - `${guardianData.name} wants to ${type === ProposalType.ADD_GUARDIAN ? 'add' : 'remove'} ${ - memberData.name - } as guardian. ` + + `${guardianData.uid} wants to ${type === ProposalType.ADD_GUARDIAN ? 'add' : 'remove'} ${memberData.name} as guardian. ` + `Request created on ${dayjs().format('MM/DD/YYYY')}. ` + `${ADD_REMOVE_GUARDIAN_THRESHOLD_PERCENTAGE} % must agree for this action to proceed`, ); expect(proposal.name).toBe(`${type === ProposalType.ADD_GUARDIAN ? 'Add' : 'Remove'} guardian`); - const voteTransaction = await build5Db() .collection(COL.TRANSACTION) .where('member', '==', guardians[0]) .where('type', '==', TransactionType.VOTE) - .where('payload.proposalId', '==', proposal.uid) - .get(); + .where('payload_proposalId', '==', proposal.uid) + .get(); expect(voteTransaction.length).toBe(1); - const proposalMember = ( - await build5Db() - .doc(`${COL.PROPOSAL}/${proposal.uid}/${SUB_COL.MEMBERS}/${guardians[0]}`) - .get() + await build5Db().doc(COL.PROPOSAL, proposal.uid, SUB_COL.MEMBERS, guardians[0]).get() ); expect(proposalMember.voted).toBe(true); expect((proposalMember as any).tranId).toBe(voteTransaction[0]?.uid); - return proposal; }; - it('Should add guardian to space after vote, than remove it', async () => { - mockWalletReturnValue(walletSpy, member, { uid: space?.uid }); - await testEnv.wrap(joinSpace)({}); - + it('Should add guardian to space after vote, then remove it', async () => { + mockWalletReturnValue(member, { uid: space?.uid }); + await testEnv.wrap(WEN_FUNC.joinSpace); const proposal = await createProposal(ProposalType.ADD_GUARDIAN, 3); - mockWalletReturnValue(walletSpy, guardians[1], { uid: proposal.uid, value: 0 }); await new Promise((resolve) => setTimeout(resolve, 2000)); - await testEnv.wrap(voteOnProposal)({}); - mockWalletReturnValue(walletSpy, guardians[2], { uid: proposal.uid, value: 1 }); - await testEnv.wrap(voteOnProposal)({}); + mockWalletReturnValue(guardians[1], { uid: proposal.uid, value: 0 }); + await testEnv.wrap(WEN_FUNC.voteOnProposal); + mockWalletReturnValue(guardians[2], { uid: proposal.uid, value: 1 }); + await testEnv.wrap(WEN_FUNC.voteOnProposal); await wait(async () => { - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${space.uid}`); + const spaceDocRef = build5Db().doc(COL.SPACE, space.uid); space = await spaceDocRef.get(); - const guardian = await spaceDocRef.collection(SUB_COL.GUARDIANS).doc(member).get(); + const guardian = await build5Db().doc(COL.SPACE, space.uid, SUB_COL.GUARDIANS, member).get(); return space.totalGuardians === guardianCount + 1 && guardian !== undefined; }); - mockWalletReturnValue(walletSpy, guardians[0], { uid: proposal.uid, value: 0 }); - await expectThrow(testEnv.wrap(voteOnProposal)({}), WenError.vote_is_no_longer_active.key); - + mockWalletReturnValue(guardians[0], { uid: proposal.uid, value: 0 }); + await expectThrow(testEnv.wrap(WEN_FUNC.voteOnProposal), WenError.vote_is_no_longer_active.key); const removeProposal = await createProposal(ProposalType.REMOVE_GUARDIAN, 4); - - mockWalletReturnValue(walletSpy, guardians[1], { uid: removeProposal.uid, value: 1 }); - await testEnv.wrap(voteOnProposal)({}); - mockWalletReturnValue(walletSpy, guardians[2], { uid: removeProposal.uid, value: 1 }); - await testEnv.wrap(voteOnProposal)({}); - + mockWalletReturnValue(guardians[1], { uid: removeProposal.uid, value: 1 }); + await testEnv.wrap(WEN_FUNC.voteOnProposal); + mockWalletReturnValue(guardians[2], { uid: removeProposal.uid, value: 1 }); + await testEnv.wrap(WEN_FUNC.voteOnProposal); await wait(async () => { - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${space.uid}`); + const spaceDocRef = build5Db().doc(COL.SPACE, space.uid); space = await spaceDocRef.get(); - const guardian = await spaceDocRef.collection(SUB_COL.GUARDIANS).doc(member).get(); + const guardian = await build5Db().doc(COL.SPACE, space.uid, SUB_COL.GUARDIANS, member).get(); return space.totalGuardians === guardianCount && guardian === undefined; }); - mockWalletReturnValue(walletSpy, guardians[0], { uid: removeProposal.uid, value: 0 }); - await expectThrow(testEnv.wrap(voteOnProposal)({}), WenError.vote_is_no_longer_active.key); + mockWalletReturnValue(guardians[0], { uid: removeProposal.uid, value: 0 }); + await expectThrow(testEnv.wrap(WEN_FUNC.voteOnProposal), WenError.vote_is_no_longer_active.key); }); it('Should add guardian to space only after threshold reached', async () => { - mockWalletReturnValue(walletSpy, member, { uid: space?.uid }); - await testEnv.wrap(joinSpace)({}); - + mockWalletReturnValue(member, { uid: space?.uid }); + await testEnv.wrap(WEN_FUNC.joinSpace); const proposal = await createProposal(ProposalType.ADD_GUARDIAN, 3); - mockWalletReturnValue(walletSpy, guardians[1], { uid: proposal.uid, value: 0 }); - await testEnv.wrap(voteOnProposal)({}); - mockWalletReturnValue(walletSpy, guardians[2], { uid: proposal.uid, value: 0 }); - await testEnv.wrap(voteOnProposal)({}); + mockWalletReturnValue(guardians[1], { uid: proposal.uid, value: 0 }); + await testEnv.wrap(WEN_FUNC.voteOnProposal); + mockWalletReturnValue(guardians[2], { uid: proposal.uid, value: 0 }); + await testEnv.wrap(WEN_FUNC.voteOnProposal); await new Promise((resolve) => setTimeout(resolve, 2000)); - mockWalletReturnValue(walletSpy, guardians[1], { uid: proposal.uid, value: 1 }); - await testEnv.wrap(voteOnProposal)({}); + + mockWalletReturnValue(guardians[1], { uid: proposal.uid, value: 1 }); + await testEnv.wrap(WEN_FUNC.voteOnProposal); await wait(async () => { - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${space.uid}`); + const spaceDocRef = build5Db().doc(COL.SPACE, space.uid); space = await spaceDocRef.get(); - const guardian = await spaceDocRef.collection(SUB_COL.GUARDIANS).doc(member).get(); + const guardian = await build5Db().doc(COL.SPACE, space.uid, SUB_COL.GUARDIANS, member).get(); return space.totalGuardians === guardianCount + 1 && guardian !== undefined; }); - mockWalletReturnValue(walletSpy, guardians[0], { uid: proposal.uid, value: 0 }); - await expectThrow(testEnv.wrap(voteOnProposal)({}), WenError.vote_is_no_longer_active.key); + + mockWalletReturnValue(guardians[0], { uid: proposal.uid, value: 0 }); + await expectThrow(testEnv.wrap(WEN_FUNC.voteOnProposal), WenError.vote_is_no_longer_active.key); }); it('Should add guardian to space when only one guardiand exists', async () => { @@ -593,67 +540,62 @@ describe('Add guardian', () => { removeGuardianFromSpace(space.uid, guardian), ); await Promise.all(promises); - - mockWalletReturnValue(walletSpy, member, { uid: space?.uid }); - await testEnv.wrap(joinSpace)({}); - + mockWalletReturnValue(member, { uid: space?.uid }); + await testEnv.wrap(WEN_FUNC.joinSpace); await createProposal(ProposalType.ADD_GUARDIAN, 1); - await wait(async () => { - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${space.uid}`); + const spaceDocRef = build5Db().doc(COL.SPACE, space.uid); space = await spaceDocRef.get(); - const guardian = await spaceDocRef.collection(SUB_COL.GUARDIANS).doc(member).get(); + const guardian = await build5Db().doc(COL.SPACE, space.uid, SUB_COL.GUARDIANS, member).get(); return space.totalGuardians === 2 && guardian !== undefined; }); }); it('Should only allow one ongoing add/remove proposal', async () => { - mockWalletReturnValue(walletSpy, member, { uid: space?.uid }); - await testEnv.wrap(joinSpace)({}); - + mockWalletReturnValue(member, { uid: space?.uid }); + await testEnv.wrap(WEN_FUNC.joinSpace); let proposal = await createProposal(ProposalType.ADD_GUARDIAN, 3); await expectThrow(createProposal(ProposalType.ADD_GUARDIAN, 3), WenError.ongoing_proposal.key); - mockWalletReturnValue(walletSpy, guardians[1], { uid: proposal.uid, value: 1 }); - await testEnv.wrap(voteOnProposal)({}); - + mockWalletReturnValue(guardians[1], { uid: proposal.uid, value: 1 }); + await testEnv.wrap(WEN_FUNC.voteOnProposal); await wait(async () => { - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${space.uid}`); + const spaceDocRef = build5Db().doc(COL.SPACE, space.uid); space = await spaceDocRef.get(); - const guardian = await spaceDocRef.collection(SUB_COL.GUARDIANS).doc(member).get(); + const guardian = await build5Db().doc(COL.SPACE, space.uid, SUB_COL.GUARDIANS, member).get(); return space.totalGuardians === guardianCount + 1 && guardian !== undefined; }); - await expectThrow( createProposal(ProposalType.ADD_GUARDIAN, 3), WenError.member_is_already_guardian_of_space.key, ); - const removeProposal = await createProposal(ProposalType.REMOVE_GUARDIAN, 4); await expectThrow( createProposal(ProposalType.REMOVE_GUARDIAN, 4), WenError.ongoing_proposal.key, ); - mockWalletReturnValue(walletSpy, guardians[1], { uid: removeProposal.uid, value: 1 }); - await testEnv.wrap(voteOnProposal)({}); - mockWalletReturnValue(walletSpy, guardians[2], { uid: removeProposal.uid, value: 1 }); - await testEnv.wrap(voteOnProposal)({}); + + mockWalletReturnValue(guardians[1], { uid: removeProposal.uid, value: 1 }); + await testEnv.wrap(WEN_FUNC.voteOnProposal); + + mockWalletReturnValue(guardians[2], { uid: removeProposal.uid, value: 1 }); + await testEnv.wrap(WEN_FUNC.voteOnProposal); await wait(async () => { - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${space.uid}`); + const spaceDocRef = build5Db().doc(COL.SPACE, space.uid); space = await spaceDocRef.get(); - const guardian = await spaceDocRef.collection(SUB_COL.GUARDIANS).doc(member).get(); + const guardian = await build5Db().doc(COL.SPACE, space.uid, SUB_COL.GUARDIANS, member).get(); return space.totalGuardians === guardianCount && guardian === undefined; }); proposal = await createProposal(ProposalType.ADD_GUARDIAN, 3); await expectThrow(createProposal(ProposalType.ADD_GUARDIAN, 3), WenError.ongoing_proposal.key); - mockWalletReturnValue(walletSpy, guardians[1], { uid: proposal.uid, value: 1 }); - await testEnv.wrap(voteOnProposal)({}); + mockWalletReturnValue(guardians[1], { uid: proposal.uid, value: 1 }); + await testEnv.wrap(WEN_FUNC.voteOnProposal); await wait(async () => { - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${space.uid}`); + const spaceDocRef = build5Db().doc(COL.SPACE, space.uid); space = await spaceDocRef.get(); - const guardian = await spaceDocRef.collection(SUB_COL.GUARDIANS).doc(member).get(); + const guardian = await build5Db().doc(COL.SPACE, space.uid, SUB_COL.GUARDIANS, member).get(); return space.totalGuardians === guardianCount + 1 && guardian !== undefined; }); }); @@ -667,153 +609,130 @@ describe('Token based space', () => { let token: string; beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - guardian = await createMember(walletSpy); - guardian2 = await createMember(walletSpy); - member = await createMember(walletSpy); - space = await createSpaceFunc(walletSpy, guardian); + guardian = await testEnv.createMember(); + guardian2 = await testEnv.createMember(); + member = await testEnv.createMember(); + space = await testEnv.createSpace(guardian); await addGuardianToSpace(space.uid, guardian2); - token = wallet.getRandomEthAddress(); - await build5Db().doc(`${COL.TOKEN}/${token}`).set({ + await build5Db().doc(COL.TOKEN, token).upsert({ project: SOON_PROJECT_ID, status: TokenStatus.MINTED, space: space.uid, - uid: token, approved: true, }); - - mockWalletReturnValue(walletSpy, member, { uid: space?.uid }); - await testEnv.wrap(joinSpace)({}); + mockWalletReturnValue(member, { uid: space?.uid }); + await testEnv.wrap(WEN_FUNC.joinSpace); }); it('Should make space token based, can not update access further but can update others', async () => { await wait(async () => { - space = await build5Db().doc(`${COL.SPACE}/${space.uid}`).get(); + space = await build5Db().doc(COL.SPACE, space.uid).get(); return space.totalGuardians === 2 && space.totalMembers === 3; }); - - const updateParams = { - uid: space?.uid, - tokenBased: true, - minStakedValue: 100, - }; - mockWalletReturnValue(walletSpy, guardian, updateParams); - const proposal = await testEnv.wrap(updateSpace)({}); - - mockWalletReturnValue(walletSpy, guardian2, { uid: proposal.uid, value: 1 }); - await testEnv.wrap(voteOnProposal)({}); - + const updateParams = { uid: space?.uid, tokenBased: true, minStakedValue: 100 }; + mockWalletReturnValue(guardian, updateParams); + const proposal = await testEnv.wrap(WEN_FUNC.updateSpace); + mockWalletReturnValue(guardian2, { uid: proposal.uid, value: 1 }); + await testEnv.wrap(WEN_FUNC.voteOnProposal); await wait(async () => { - space = await build5Db().doc(`${COL.SPACE}/${space.uid}`).get(); + space = await build5Db().doc(COL.SPACE, space.uid).get(); return space.tokenBased === true && space.minStakedValue === updateParams.minStakedValue; }); expect(space.totalGuardians).toBe(1); expect(space.totalMembers).toBe(1); - await addGuardianToSpace(space.uid, guardian); await addGuardianToSpace(space.uid, guardian2); - mockWalletReturnValue(walletSpy, guardian, updateParams); + mockWalletReturnValue(guardian, updateParams); await expectThrow( - testEnv.wrap(updateSpace)({}), + testEnv.wrap(WEN_FUNC.updateSpace), WenError.token_based_space_access_can_not_be_edited.key, ); - mockWalletReturnValue(walletSpy, guardian, { uid: space.uid, open: false }); + + mockWalletReturnValue(guardian, { uid: space.uid, open: false }); await expectThrow( - testEnv.wrap(updateSpace)({}), + testEnv.wrap(WEN_FUNC.updateSpace), WenError.token_based_space_access_can_not_be_edited.key, ); const name = 'second update'; - mockWalletReturnValue(walletSpy, guardian, { uid: space.uid, name }); - const proposal2 = await testEnv.wrap(updateSpace)({}); - mockWalletReturnValue(walletSpy, guardian2, { uid: proposal2.uid, value: 1 }); - await testEnv.wrap(voteOnProposal)({}); - + mockWalletReturnValue(guardian, { uid: space.uid, name }); + const proposal2 = await testEnv.wrap(WEN_FUNC.updateSpace); + mockWalletReturnValue(guardian2, { uid: proposal2.uid, value: 1 }); + await testEnv.wrap(WEN_FUNC.voteOnProposal); await wait(async () => { - space = await build5Db().doc(`${COL.SPACE}/${space.uid}`).get(); + space = await build5Db().doc(COL.SPACE, space.uid).get(); return space.name === name; }); }); it('Should join token based space', async () => { - const updateParams = { - uid: space?.uid, - tokenBased: true, - minStakedValue: 100, - }; - mockWalletReturnValue(walletSpy, guardian, updateParams); - const proposal = await testEnv.wrap(updateSpace)({}); + const updateParams = { uid: space?.uid, tokenBased: true, minStakedValue: 100 }; + mockWalletReturnValue(guardian, updateParams); + const proposal = await testEnv.wrap(WEN_FUNC.updateSpace); - mockWalletReturnValue(walletSpy, guardian2, { uid: proposal.uid, value: 1 }); - await testEnv.wrap(voteOnProposal)({}); + mockWalletReturnValue(guardian2, { uid: proposal.uid, value: 1 }); + await testEnv.wrap(WEN_FUNC.voteOnProposal); await wait(async () => { - space = await build5Db().doc(`${COL.SPACE}/${space.uid}`).get(); + space = await build5Db().doc(COL.SPACE, space.uid).get(); return space.tokenBased === true && space.minStakedValue === updateParams.minStakedValue; }); - const newMember = await createMember(walletSpy); + const newMember = await testEnv.createMember(); await build5Db() - .doc(`${COL.TOKEN}/${token}/${SUB_COL.DISTRIBUTION}/${newMember}`) - .set({ stakes: { [StakeType.DYNAMIC]: { value: 200 } } }); - mockWalletReturnValue(walletSpy, newMember, { uid: space?.uid }); - await testEnv.wrap(joinSpace)({}); + .doc(COL.TOKEN, token, SUB_COL.DISTRIBUTION, newMember) + .upsert({ stakes_dynamic_value: 200 }); + mockWalletReturnValue(newMember, { uid: space?.uid }); + await testEnv.wrap(WEN_FUNC.joinSpace); await wait(async () => { - space = await build5Db().doc(`${COL.SPACE}/${space.uid}`).get(); + space = await build5Db().doc(COL.SPACE, space.uid).get(); return space.totalMembers === 2 && space.totalGuardians === 1; }); }); it('Should not remove member as it has enough stakes', async () => { await build5Db() - .doc(`${COL.TOKEN}/${token}/${SUB_COL.DISTRIBUTION}/${member}`) - .set({ stakes: { [StakeType.DYNAMIC]: { value: 200 } } }); + .doc(COL.TOKEN, token, SUB_COL.DISTRIBUTION, member) + .upsert({ stakes_dynamic_value: 200 }); + const updateParams = { uid: space?.uid, tokenBased: true, minStakedValue: 100 }; - const updateParams = { - uid: space?.uid, - tokenBased: true, - minStakedValue: 100, - }; - mockWalletReturnValue(walletSpy, guardian, updateParams); - const proposal = await testEnv.wrap(updateSpace)({}); + mockWalletReturnValue(guardian, updateParams); + const proposal = await testEnv.wrap(WEN_FUNC.updateSpace); - mockWalletReturnValue(walletSpy, guardian2, { uid: proposal.uid, value: 1 }); - await testEnv.wrap(voteOnProposal)({}); + mockWalletReturnValue(guardian2, { uid: proposal.uid, value: 1 }); + await testEnv.wrap(WEN_FUNC.voteOnProposal); await wait(async () => { - space = await build5Db().doc(`${COL.SPACE}/${space.uid}`).get(); + space = await build5Db().doc(COL.SPACE, space.uid).get(); return space.tokenBased === true && space.minStakedValue === updateParams.minStakedValue; }); + expect(space.totalMembers).toBe(2); expect(space.totalGuardians).toBe(1); }); it('Should not remove guardians as they have enough stakes', async () => { await build5Db() - .doc(`${COL.TOKEN}/${token}/${SUB_COL.DISTRIBUTION}/${guardian}`) - .set({ stakes: { [StakeType.DYNAMIC]: { value: 200 } } }); + .doc(COL.TOKEN, token, SUB_COL.DISTRIBUTION, guardian) + .upsert({ stakes_dynamic_value: 200 }); await build5Db() - .doc(`${COL.TOKEN}/${token}/${SUB_COL.DISTRIBUTION}/${guardian2}`) - .set({ stakes: { [StakeType.DYNAMIC]: { value: 200 } } }); + .doc(COL.TOKEN, token, SUB_COL.DISTRIBUTION, guardian2) + .upsert({ stakes_dynamic_value: 200 }); + const updateParams = { uid: space?.uid, tokenBased: true, minStakedValue: 100 }; - const updateParams = { - uid: space?.uid, - tokenBased: true, - minStakedValue: 100, - }; - mockWalletReturnValue(walletSpy, guardian, updateParams); - const proposal = await testEnv.wrap(updateSpace)({}); - - mockWalletReturnValue(walletSpy, guardian2, { uid: proposal.uid, value: 1 }); - await testEnv.wrap(voteOnProposal)({}); + mockWalletReturnValue(guardian, updateParams); + const proposal = await testEnv.wrap(WEN_FUNC.updateSpace); + mockWalletReturnValue(guardian2, { uid: proposal.uid, value: 1 }); + await testEnv.wrap(WEN_FUNC.voteOnProposal); await wait(async () => { - space = await build5Db().doc(`${COL.SPACE}/${space.uid}`).get(); + space = await build5Db().doc(COL.SPACE, space.uid).get(); return space.tokenBased === true && space.minStakedValue === updateParams.minStakedValue; }); + expect(space.totalMembers).toBe(2); expect(space.totalGuardians).toBe(2); }); diff --git a/packages/functions/test/controls/stake.reward.spec.ts b/packages/functions/test/controls/stake.reward.spec.ts index b7b3da89a7..94329227e6 100644 --- a/packages/functions/test/controls/stake.reward.spec.ts +++ b/packages/functions/test/controls/stake.reward.spec.ts @@ -1,29 +1,37 @@ import { build5Db } from '@build-5/database'; -import { COL, SOON_PROJECT_ID, Space, StakeReward, WenError } from '@build-5/interfaces'; +import { + COL, + SOON_PROJECT_ID, + Space, + StakeReward, + Token, + WEN_FUNC, + WenError, +} from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { stakeReward } from '../../src/runtime/firebase/stake'; import { dateToTimestamp } from '../../src/utils/dateTime.utils'; import * as wallet from '../../src/utils/wallet.utils'; -import { testEnv } from '../set-up'; -import { createMember, createSpace, expectThrow, mockWalletReturnValue } from './common'; +import { mockWalletReturnValue, testEnv } from '../set-up'; +import { expectThrow } from './common'; describe('Stake reward controller', () => { - let walletSpy: any; let guardian: string; let space: Space; let token: string; beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - guardian = await createMember(walletSpy); - space = await createSpace(walletSpy, guardian); + guardian = await testEnv.createMember(); + space = await testEnv.createSpace(guardian); token = wallet.getRandomEthAddress(); - await build5Db().doc(`${COL.TOKEN}/${token}`).create({ - project: SOON_PROJECT_ID, - uid: token, - space: space.uid, - }); + await build5Db() + .doc(COL.TOKEN, token) + .create({ + project: SOON_PROJECT_ID, + uid: token, + space: space.uid, + links: [] as URL[], + } as Token); }); it('Should throw, token does not exist', async () => { @@ -35,12 +43,12 @@ describe('Stake reward controller', () => { tokensToDistribute: 100, }, ]; - mockWalletReturnValue(walletSpy, guardian, { token: wallet.getRandomEthAddress(), items }); - await expectThrow(testEnv.wrap(stakeReward)({}), WenError.token_does_not_exist.key); + mockWalletReturnValue(guardian, { token: wallet.getRandomEthAddress(), items }); + await expectThrow(testEnv.wrap(WEN_FUNC.stakeReward), WenError.token_does_not_exist.key); }); it('Should throw, not guardian', async () => { - await build5Db().doc(`${COL.TOKEN}/${token}`).update({ space: wallet.getRandomEthAddress() }); + await build5Db().doc(COL.TOKEN, token).update({ space: wallet.getRandomEthAddress() }); const items = [ { startDate: dayjs().valueOf(), @@ -49,8 +57,11 @@ describe('Stake reward controller', () => { tokensToDistribute: 100, }, ]; - mockWalletReturnValue(walletSpy, guardian, { token, items }); - await expectThrow(testEnv.wrap(stakeReward)({}), WenError.you_are_not_guardian_of_space.key); + mockWalletReturnValue(guardian, { token, items }); + await expectThrow( + testEnv.wrap(WEN_FUNC.stakeReward), + WenError.you_are_not_guardian_of_space.key, + ); }); it('Should create rewards', async () => { @@ -63,11 +74,12 @@ describe('Stake reward controller', () => { tokensToDistribute: 100, }, ]; - mockWalletReturnValue(walletSpy, guardian, { token, items: [items[0], items[0]] }); - const stakeRewards: StakeReward[] = await testEnv.wrap(stakeReward)({}); + mockWalletReturnValue(guardian, { token, items: [items[0], items[0]] }); + const stakeRewards: StakeReward[] = await testEnv.wrap(WEN_FUNC.stakeReward); expect(stakeRewards.length).toBe(2); - for (const stakeReward of stakeRewards) { + for (let stakeReward of stakeRewards) { + stakeReward = (await build5Db().doc(COL.STAKE_REWARD, stakeReward.uid).get())!; expect(stakeReward.uid).toBeDefined(); expect(stakeReward.token).toBe(token); expect( @@ -99,8 +111,8 @@ describe('Stake reward controller', () => { tokensToDistribute: 100, }, ]; - mockWalletReturnValue(walletSpy, guardian, { token, items }); - await expectThrow(testEnv.wrap(stakeReward)({}), WenError.invalid_params.key); + mockWalletReturnValue(guardian, { token, items }); + await expectThrow(testEnv.wrap(WEN_FUNC.stakeReward), WenError.invalid_params.key); }); it('Should throw, vesting date before end date', async () => { @@ -113,7 +125,7 @@ describe('Stake reward controller', () => { tokensToDistribute: 100, }, ]; - mockWalletReturnValue(walletSpy, guardian, { token, items }); - await expectThrow(testEnv.wrap(stakeReward)({}), WenError.invalid_params.key); + mockWalletReturnValue(guardian, { token, items }); + await expectThrow(testEnv.wrap(WEN_FUNC.stakeReward), WenError.invalid_params.key); }); }); diff --git a/packages/functions/test/controls/stamp.control.spec.ts b/packages/functions/test/controls/stamp.control.spec.ts index 1657ffff45..fd64d668b3 100644 --- a/packages/functions/test/controls/stamp.control.spec.ts +++ b/packages/functions/test/controls/stamp.control.spec.ts @@ -6,40 +6,32 @@ import { SOON_PROJECT_ID, STAMP_COST_PER_MB, SUB_COL, - SpaceGuardian, - Stamp, Transaction, TransactionPayloadType, TransactionType, TransactionValidationType, + WEN_FUNC, } from '@build-5/interfaces'; -import { stamp as stampFunc } from '../../src/runtime/firebase/stamp'; import { EMPTY_ALIAS_ID } from '../../src/utils/token-minting-utils/alias.utils'; import * as wallet from '../../src/utils/wallet.utils'; -import { testEnv } from '../set-up'; -import { createMember, mockWalletReturnValue } from './common'; +import { mockWalletReturnValue, testEnv } from '../set-up'; describe('Stamp control', () => { - let walletSpy: any; let member: string; let dowloadUrl: string; - beforeAll(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - }); - beforeEach(async () => { const bucket = build5Storage().bucket(Bucket.DEV); const destination = `nft/${wallet.getRandomEthAddress()}/image.jpeg`; dowloadUrl = await bucket.upload('./test/puppy.jpeg', destination, { contentType: 'image/jpeg', }); - member = await createMember(walletSpy); + member = await testEnv.createMember(); }); it('Should create stamp order', async () => { - mockWalletReturnValue(walletSpy, member, { network: Network.RMS, file: dowloadUrl }); - const order = (await testEnv.wrap(stampFunc)({})) as Transaction; + mockWalletReturnValue(member, { network: Network.RMS, file: dowloadUrl }); + const order = await testEnv.wrap(WEN_FUNC.stamp); expect(order.project).toBe(SOON_PROJECT_ID); expect(order.type).toBe(TransactionType.ORDER); expect(order.member).toBe(member); @@ -51,10 +43,10 @@ describe('Stamp control', () => { expect(order.payload.stamp).toBeDefined(); expect(order.payload.aliasId).toBe(''); expect(order.payload.aliasOutputAmount).toBe(53700); - expect(order.payload.nftOutputAmount).toBe(107700); + expect(order.payload.nftOutputAmount).toBe(104500); - const stampDocRef = build5Db().doc(`${COL.STAMP}/${order.payload.stamp}`); - const stamp = await stampDocRef.get(); + const stampDocRef = build5Db().doc(COL.STAMP, order.payload.stamp!); + const stamp = await stampDocRef.get(); expect(stamp?.space).toBe(order.space); expect(stamp?.build5Url).toBe(dowloadUrl); expect(stamp?.originUri).toBe(dowloadUrl); @@ -68,9 +60,8 @@ describe('Stamp control', () => { expect(stamp?.aliasId).toBe(EMPTY_ALIAS_ID); expect(stamp?.nftId).toBeUndefined(); - const spaceDocRef = build5Db().doc(`${COL.SPACE}/${order.space}`); - const guardianDocRef = spaceDocRef.collection(SUB_COL.GUARDIANS).doc(member); - const guardian = await guardianDocRef.get(); + const guardianDocRef = build5Db().doc(COL.SPACE, order.space!, SUB_COL.GUARDIANS, member); + const guardian = await guardianDocRef.get(); expect(guardian).toBeDefined(); }); }); diff --git a/packages/functions/test/controls/token-distribution-auto-trigger.spec.ts b/packages/functions/test/controls/token-distribution-auto-trigger.spec.ts index d316f65166..648eb24cfd 100644 --- a/packages/functions/test/controls/token-distribution-auto-trigger.spec.ts +++ b/packages/functions/test/controls/token-distribution-auto-trigger.spec.ts @@ -13,25 +13,16 @@ import { TokenStatus, Transaction, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; import bigDecimal from 'js-big-decimal'; import { isEmpty } from 'lodash'; -import { orderToken } from '../../src/runtime/firebase/token/base'; import { getAddress } from '../../src/utils/address.utils'; import { dateToTimestamp, serverTime } from '../../src/utils/dateTime.utils'; import * as wallet from '../../src/utils/wallet.utils'; -import { testEnv } from '../set-up'; -import { - createMember, - createSpace, - getRandomSymbol, - mockWalletReturnValue, - submitMilestoneFunc, - tokenProcessed, -} from './common'; - -let walletSpy: any; +import { mockWalletReturnValue, testEnv } from '../set-up'; +import { getRandomSymbol, submitMilestoneFunc, tokenProcessed } from './common'; interface Inputs { readonly totalDeposit: number[]; @@ -79,9 +70,9 @@ const scenarios = [ }, ]; -const submitTokenOrderFunc = async (spy: string, address: NetworkAddress, params: T) => { - mockWalletReturnValue(spy, address, params); - const order = await testEnv.wrap(orderToken)({}); +const submitTokenOrderFunc = async (address: NetworkAddress, params: T) => { + mockWalletReturnValue(address, params); + const order = await testEnv.wrap(WEN_FUNC.orderToken); expect(order?.createdOn).toBeDefined(); return order; }; @@ -120,14 +111,13 @@ describe('Token trigger test', () => { let members: string[]; beforeAll(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - guardian = await createMember(walletSpy); - space = await createSpace(walletSpy, guardian); + guardian = await testEnv.createMember(); + space = await testEnv.createSpace(guardian); const maxMembers = scenarios.reduce( (max, scenario) => Math.max(max, scenario.totalDeposit.length), 0, ); - const memberPromises = Array.from(Array(maxMembers)).map(() => createMember(walletSpy)); + const memberPromises = Array.from(Array(maxMembers)).map(() => testEnv.createMember()); members = await Promise.all(memberPromises); }); @@ -139,10 +129,10 @@ describe('Token trigger test', () => { input.publicPercentage, guardian, ); - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).create(token); + await build5Db().doc(COL.TOKEN, token.uid).create(token); const orderPromises = input.totalDeposit.map(async (_, i) => { - const order = await submitTokenOrderFunc(walletSpy, members[i], { token: token.uid }); + const order = await submitTokenOrderFunc(members[i], { token: token.uid }); await submitMilestoneFunc( order, Number(bigDecimal.multiply(input.totalDeposit[i], MIN_IOTA_AMOUNT)), @@ -154,7 +144,7 @@ describe('Token trigger test', () => { await tokenProcessed(token.uid, input.totalDeposit.length, true); - const tokenData = await build5Db().doc(`${COL.TOKEN}/${token.uid}`).get(); + const tokenData = await build5Db().doc(COL.TOKEN, token.uid).get(); expect(tokenData.tokensOrdered).toBe( input.totalDeposit.reduce( (sum, act) => sum + (act * MIN_IOTA_AMOUNT) / tokenData.pricePerToken, @@ -165,7 +155,7 @@ describe('Token trigger test', () => { for (let i = 0; i < input.totalDeposit.length; ++i) { const member = members[i]; const distribution = ( - await build5Db().doc(`${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${member}`).get() + await build5Db().doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, member).get() ); const refundedAmount = Number(bigDecimal.multiply(input.refundedAmount[i], MIN_IOTA_AMOUNT)); expect(distribution.totalDeposit).toBe( @@ -181,9 +171,7 @@ describe('Token trigger test', () => { expect(distribution.billPaymentId).toBeDefined(); } if (distribution.billPaymentId) { - const paymentDoc = await build5Db() - .doc(`${COL.TRANSACTION}/${distribution.billPaymentId}`) - .get(); + const paymentDoc = await build5Db().doc(COL.TRANSACTION, distribution.billPaymentId).get(); expect(paymentDoc !== undefined).toBe(true); const paidAmount = isEmpty(input.paymentAmount) ? input.totalPaid[i] @@ -196,8 +184,8 @@ describe('Token trigger test', () => { } if (distribution.creditPaymentId) { const creditPaymentDoc = await build5Db() - .doc(`${COL.TRANSACTION}/${distribution.creditPaymentId}`) - .get(); + .doc(COL.TRANSACTION, distribution.creditPaymentId) + .get(); expect(creditPaymentDoc !== undefined).toBe(true); const creditAmount = isEmpty(input.creditAmount) ? input.refundedAmount[i] @@ -205,7 +193,7 @@ describe('Token trigger test', () => { expect(creditPaymentDoc?.payload?.amount).toBe( Number(bigDecimal.multiply(creditAmount, MIN_IOTA_AMOUNT)), ); - const memberData = await build5Db().doc(`${COL.MEMBER}/${member}`).get(); + const memberData = await build5Db().doc(COL.MEMBER, member).get(); expect(creditPaymentDoc?.payload?.sourceAddress).toBe(orders[i].payload?.targetAddress); expect(creditPaymentDoc?.payload?.targetAddress).toBe(getAddress(memberData, Network.IOTA)); } @@ -213,14 +201,14 @@ describe('Token trigger test', () => { }); it('Should should create two and credit third', async () => { - members.push(await createMember(walletSpy)); + members.push(await testEnv.createMember()); token = dummyToken(10, space, MIN_IOTA_AMOUNT, 100, guardian); - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).create(token); + await build5Db().doc(COL.TOKEN, token.uid).create(token); const orderPromises = members .map(() => 7) .map(async (totalDeposit, i) => { - const order = await submitTokenOrderFunc(walletSpy, members[i], { token: token.uid }); + const order = await submitTokenOrderFunc(members[i], { token: token.uid }); await submitMilestoneFunc( order, Number(bigDecimal.multiply(totalDeposit, MIN_IOTA_AMOUNT)), @@ -231,13 +219,12 @@ describe('Token trigger test', () => { await Promise.all(orderPromises); await tokenProcessed(token.uid, 2, true); - const tokenData = await build5Db().doc(`${COL.TOKEN}/${token.uid}`).get(); + const tokenData = await build5Db().doc(COL.TOKEN, token.uid).get(); expect(tokenData.tokensOrdered).toBe(14); const distributions = await build5Db() - .doc(`${COL.TOKEN}/${token.uid}`) - .collection(SUB_COL.DISTRIBUTION) - .get(); + .collection(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION) + .get(); expect(distributions.length).toBe(2); distributions.forEach((d) => { expect(d.totalDeposit).toBe(7 * MIN_IOTA_AMOUNT); @@ -248,9 +235,9 @@ describe('Token trigger test', () => { const credit = await build5Db() .collection(COL.TRANSACTION) - .where('member', 'in', members) .where('type', '==', TransactionType.CREDIT) - .where('payload.amount', '==', 7 * MIN_IOTA_AMOUNT) + .where('payload_amount', '==', 7 * MIN_IOTA_AMOUNT) + .whereIn('member', members) .get(); expect(credit.length).toBe(1); }); diff --git a/packages/functions/test/controls/token-distribution.spec.ts b/packages/functions/test/controls/token-distribution.spec.ts index 6209d0d956..83b8d8faaa 100644 --- a/packages/functions/test/controls/token-distribution.spec.ts +++ b/packages/functions/test/controls/token-distribution.spec.ts @@ -15,27 +15,22 @@ import { Transaction, TransactionPayloadType, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; import bigDecimal from 'js-big-decimal'; import { isEmpty } from 'lodash'; -import { orderToken } from '../../src/runtime/firebase/token/base'; import { getAddress } from '../../src/utils/address.utils'; import { dateToTimestamp, serverTime } from '../../src/utils/dateTime.utils'; import * as wallet from '../../src/utils/wallet.utils'; -import { testEnv } from '../set-up'; +import { mockWalletReturnValue, testEnv } from '../set-up'; import { - createMember, createRoyaltySpaces, - createSpace, getRandomSymbol, - mockWalletReturnValue, submitMilestoneFunc, tokenProcessed, } from './common'; -let walletSpy: any; - interface Inputs { readonly totalDeposit: number[]; readonly totalPaid: number[]; @@ -296,9 +291,9 @@ const scenarios = [ custom, ]; -const submitTokenOrderFunc = async (spy: string, address: NetworkAddress, params: T) => { - mockWalletReturnValue(spy, address, params); - const order = await testEnv.wrap(orderToken)({}); +const submitTokenOrderFunc = async (address: NetworkAddress, params: T) => { + mockWalletReturnValue(address, params); + const order = await testEnv.wrap(WEN_FUNC.orderToken); expect(order?.createdOn).toBeDefined(); return order; }; @@ -337,21 +332,20 @@ describe('Token trigger test', () => { beforeAll(async () => { await createRoyaltySpaces(); - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - guardian = await createMember(walletSpy); - space = await createSpace(walletSpy, guardian); + guardian = await testEnv.createMember(); + space = await testEnv.createSpace(guardian); const maxMembers = scenarios.reduce( (max, scenario) => Math.max(max, scenario.totalDeposit.length), 0, ); - const memberPromises = Array.from(Array(maxMembers)).map(() => createMember(walletSpy)); + const memberPromises = Array.from(Array(maxMembers)).map(() => testEnv.createMember()); members = await Promise.all(memberPromises); }); beforeEach(async () => { await build5Db() - .doc(`${COL.SYSTEM}/${SYSTEM_CONFIG_DOC_ID}`) - .set({ tokenPurchaseFeePercentage: build5Db().deleteField() }, true); + .doc(COL.SYSTEM, SYSTEM_CONFIG_DOC_ID) + .upsert({ tokenPurchaseFeePercentage: undefined }); }); it.each(scenarios)('Should buy tokens', async (input: Inputs) => { @@ -362,10 +356,9 @@ describe('Token trigger test', () => { input.publicPercentage, guardian, ); - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).create(token); - + await build5Db().doc(COL.TOKEN, token.uid).create(token); const orderPromises = Array.from(Array(input.totalDeposit.length)).map(async (_, i) => { - const order = await submitTokenOrderFunc(walletSpy, members[i], { token: token.uid }); + const order = await submitTokenOrderFunc(members[i], { token: token.uid }); await submitMilestoneFunc( order, Number(bigDecimal.multiply(input.totalDeposit[i], MIN_IOTA_AMOUNT)), @@ -374,13 +367,13 @@ describe('Token trigger test', () => { }); const orders = await Promise.all(orderPromises); - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).update({ status: TokenStatus.PROCESSING }); + await build5Db().doc(COL.TOKEN, token.uid).update({ status: TokenStatus.PROCESSING }); await tokenProcessed(token.uid, input.totalDeposit.length, true); for (let i = 0; i < input.totalDeposit.length; ++i) { const member = members[i]; const distribution = ( - await build5Db().doc(`${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${member}`).get() + await build5Db().doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, member).get() ); const refundedAmount = Number(bigDecimal.multiply(input.refundedAmount[i], MIN_IOTA_AMOUNT)); expect(distribution.totalDeposit).toBe( @@ -397,9 +390,7 @@ describe('Token trigger test', () => { } if (distribution.billPaymentId) { - const paymentDoc = await build5Db() - .doc(`${COL.TRANSACTION}/${distribution.billPaymentId}`) - .get(); + const paymentDoc = await build5Db().doc(COL.TRANSACTION, distribution.billPaymentId).get(); expect(paymentDoc !== undefined).toBe(true); const paidAmount = isEmpty(input.paymentAmount) ? input.totalPaid[i] @@ -421,22 +412,20 @@ describe('Token trigger test', () => { if (supposedRoyaltyAmount < MIN_IOTA_AMOUNT) { expect(distribution.royaltyBillPaymentId).toBe(''); } else { - const royaltySpace = ( - await build5Db().doc(`${COL.SPACE}/${TOKEN_SALE_TEST.spaceone}`).get() - ); - const royaltyPayment = ( - await build5Db().doc(`${COL.TRANSACTION}/${distribution.royaltyBillPaymentId}`).get() - ); - expect(royaltyPayment.payload.amount).toBe(Math.floor(supposedRoyaltyAmount)); - expect(royaltyPayment.payload.targetAddress).toBe( - getAddress(royaltySpace, royaltyPayment.network!), + const royaltySpace = await build5Db().doc(COL.SPACE, TOKEN_SALE_TEST.spaceone).get(); + const royaltyPayment = await build5Db() + .doc(COL.TRANSACTION, distribution.royaltyBillPaymentId!) + .get(); + expect(royaltyPayment!.payload.amount).toBe(Math.floor(supposedRoyaltyAmount)); + expect(royaltyPayment!.payload.targetAddress).toBe( + getAddress(royaltySpace, royaltyPayment!.network!), ); } if (distribution.creditPaymentId) { const creditPaymentDoc = await build5Db() - .doc(`${COL.TRANSACTION}/${distribution.creditPaymentId}`) - .get(); + .doc(COL.TRANSACTION, distribution.creditPaymentId) + .get(); expect(creditPaymentDoc !== undefined).toBe(true); const creditAmount = isEmpty(input.creditAmount) ? input.refundedAmount[i] @@ -444,7 +433,7 @@ describe('Token trigger test', () => { expect(creditPaymentDoc?.payload?.amount).toBe( Number(bigDecimal.multiply(creditAmount, MIN_IOTA_AMOUNT)), ); - const memberData = await build5Db().doc(`${COL.MEMBER}/${member}`).get(); + const memberData = await build5Db().doc(COL.MEMBER, member).get(); expect(creditPaymentDoc?.payload?.sourceAddress).toBe(orders[i].payload?.targetAddress); expect(creditPaymentDoc?.payload?.targetAddress).toBe(getAddress(memberData, Network.IOTA)); } @@ -453,29 +442,29 @@ describe('Token trigger test', () => { it('Should refund everyone if public sale is set to zero', async () => { token = dummyToken(100, space, MIN_IOTA_AMOUNT, 10, guardian); - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).create(token); + await build5Db().doc(COL.TOKEN, token.uid).create(token); const totalDeposits = [2, 3]; const orderPromises = totalDeposits.map(async (totalDeposit, i) => { - const order = await submitTokenOrderFunc(walletSpy, members[i], { token: token.uid }); + const order = await submitTokenOrderFunc(members[i], { token: token.uid }); await submitMilestoneFunc(order, Number(bigDecimal.multiply(totalDeposit, MIN_IOTA_AMOUNT))); return order; }); await Promise.all(orderPromises); await build5Db() - .doc(`${COL.TOKEN}/${token.uid}`) + .doc(COL.TOKEN, token.uid) .update({ status: TokenStatus.PROCESSING, - allocations: [{ title: 'Public sale', isPublicSale: true, percentage: 0 }], + allocations: JSON.stringify([{ title: 'Public sale', isPublicSale: true, percentage: 0 }]), }); await tokenProcessed(token.uid, totalDeposits.length, true); for (let i = 0; i < totalDeposits.length; ++i) { const member = members[i]; const distribution = ( - await build5Db().doc(`${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${member}`).get() + await build5Db().doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, member).get() ); const refundedAmount = Number(bigDecimal.multiply(totalDeposits[i], MIN_IOTA_AMOUNT)); expect(distribution.totalDeposit).toBe( @@ -495,32 +484,29 @@ describe('Token trigger test', () => { { isMember: false, fee: 5 }, ])('Custom fees', async ({ isMember, fee }: { isMember: boolean; fee: number }) => { if (isMember) { - await build5Db() - .doc(`${COL.MEMBER}/${members[0]}`) - .update({ tokenPurchaseFeePercentage: fee }); + await build5Db().doc(COL.MEMBER, members[0]).update({ tokenPurchaseFeePercentage: fee }); } else { await build5Db() - .doc(`${COL.SYSTEM}/${SYSTEM_CONFIG_DOC_ID}`) - .set({ tokenPurchaseFeePercentage: fee }); + .doc(COL.SYSTEM, SYSTEM_CONFIG_DOC_ID) + .upsert({ tokenPurchaseFeePercentage: fee }); } const totalPaid = 100 * MIN_IOTA_AMOUNT; token = dummyToken(100, space, MIN_IOTA_AMOUNT, 100, guardian); - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).create(token); + await build5Db().doc(COL.TOKEN, token.uid).create(token); - const order = await submitTokenOrderFunc(walletSpy, members[0], { token: token.uid }); + const order = await submitTokenOrderFunc(members[0], { token: token.uid }); await submitMilestoneFunc(order, totalPaid); - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).update({ status: TokenStatus.PROCESSING }); + await build5Db().doc(COL.TOKEN, token.uid).update({ status: TokenStatus.PROCESSING }); await tokenProcessed(token.uid, 1, true); const billPayments = await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.BILL_PAYMENT) .where('member', '==', members[0]) - .where('payload.token', '==', token.uid) - .get(); - + .where('payload_token', '==', token.uid) + .get(); const billPaymentToSpace = billPayments.find( (bp) => bp.payload.amount === totalPaid * (1 - fee / 100), ); @@ -535,8 +521,6 @@ describe('Token trigger test', () => { expect(billPayments.filter((bp) => bp.payload.royalty).length).toBe(0); } - await build5Db() - .doc(`${COL.MEMBER}/${members[0]}`) - .set({ tokenPurchaseFeePercentage: build5Db().deleteField() }, true); + await build5Db().doc(COL.MEMBER, members[0]).upsert({ tokenPurchaseFeePercentage: undefined }); }); }); diff --git a/packages/functions/test/controls/token-trade.buy.spec.ts b/packages/functions/test/controls/token-trade.buy.spec.ts index 1f67fa3477..e5fa2e265e 100644 --- a/packages/functions/test/controls/token-trade.buy.spec.ts +++ b/packages/functions/test/controls/token-trade.buy.spec.ts @@ -12,32 +12,23 @@ import { Transaction, TransactionPayloadType, TransactionType, + WEN_FUNC, WenError, } from '@build-5/interfaces'; -import { cancelTradeOrder, tradeToken } from '../../src/runtime/firebase/token/trading'; +import { tradeTokenControl } from '../../src/controls/token-trading/token-trade.controller'; import * as wallet from '../../src/utils/wallet.utils'; -import { testEnv } from '../set-up'; -import { - createMember, - expectThrow, - getRandomSymbol, - mockIpCheck, - mockWalletReturnValue, - submitMilestoneFunc, -} from './common'; - -let walletSpy: any; +import { mockWalletReturnValue, testEnv } from '../set-up'; +import { expectThrow, getRandomSymbol, mockIpCheck, submitMilestoneFunc } from './common'; describe('Trade controller, buy token', () => { let memberAddress: NetworkAddress; let token: Token; beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - memberAddress = await createMember(walletSpy); + memberAddress = await testEnv.createMember(); const tokenId = wallet.getRandomEthAddress(); - token = { + const tokenUpsert = { project: SOON_PROJECT_ID, uid: tokenId, symbol: getRandomSymbol(), @@ -46,7 +37,8 @@ describe('Trade controller, buy token', () => { status: TokenStatus.AVAILABLE, approved: true, }; - await build5Db().doc(`${COL.TOKEN}/${tokenId}`).set(token); + await build5Db().doc(COL.TOKEN, tokenId).upsert(tokenUpsert); + token = (await build5Db().doc(COL.TOKEN, tokenId).get())!; }); it('Should create buy order and cancel it', async () => { @@ -56,8 +48,8 @@ describe('Trade controller, buy token', () => { count: 5, type: TokenTradeOrderType.BUY, }; - mockWalletReturnValue(walletSpy, memberAddress, request); - const order = await testEnv.wrap(tradeToken)({}); + mockWalletReturnValue(memberAddress, request); + const order = await testEnv.wrap(WEN_FUNC.tradeToken); await submitMilestoneFunc(order, MIN_IOTA_AMOUNT * 5); const buySnap = await build5Db() @@ -73,16 +65,16 @@ describe('Trade controller, buy token', () => { expect(buy.tokenStatus).toBe(TokenStatus.AVAILABLE); const cancelRequest = { uid: buy.uid }; - mockWalletReturnValue(walletSpy, memberAddress, cancelRequest); - const cancelled = await testEnv.wrap(cancelTradeOrder)({}); + mockWalletReturnValue(memberAddress, cancelRequest); + const cancelled = await testEnv.wrap(WEN_FUNC.cancelTradeOrder); expect(cancelled.status).toBe(TokenTradeOrderStatus.CANCELLED); const creditSnap = await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.CREDIT) .where('member', '==', memberAddress) - .where('payload.type', '==', TransactionPayloadType.TOKEN_BUY) - .get(); + .where('payload_type', '==', TransactionPayloadType.TOKEN_BUY) + .get(); expect(creditSnap.length).toBe(1); expect(creditSnap[0]?.payload?.amount).toBe(5 * MIN_IOTA_AMOUNT); }); @@ -94,8 +86,8 @@ describe('Trade controller, buy token', () => { count: 5, type: TokenTradeOrderType.BUY, }; - mockWalletReturnValue(walletSpy, memberAddress, request); - const order = await testEnv.wrap(tradeToken)({}); + mockWalletReturnValue(memberAddress, request); + const order = await testEnv.wrap(WEN_FUNC.tradeToken); await submitMilestoneFunc(order, MIN_IOTA_AMOUNT * 5); await submitMilestoneFunc(order, MIN_IOTA_AMOUNT * 5); @@ -110,21 +102,24 @@ describe('Trade controller, buy token', () => { .collection(COL.TRANSACTION) .where('type', '==', TransactionType.CREDIT) .where('member', '==', memberAddress) - .where('payload.amount', '==', 5 * MIN_IOTA_AMOUNT) + .where('payload_amount', '==', 5 * MIN_IOTA_AMOUNT) .get(); expect(creditSnap.length).toBe(1); }); it('Should throw, token not approved', async () => { - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).update({ approved: false }); + await build5Db().doc(COL.TOKEN, token.uid).update({ approved: false }); const request = { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: 5, type: TokenTradeOrderType.BUY, }; - mockWalletReturnValue(walletSpy, memberAddress, request); - await expectThrow(testEnv.wrap(tradeToken)({}), WenError.token_does_not_exist.key); + mockWalletReturnValue(memberAddress, request); + await expectThrow( + testEnv.wrap(WEN_FUNC.tradeToken), + WenError.token_does_not_exist.key, + ); }); it('Should fail, country blocked by default', async () => { @@ -135,8 +130,9 @@ describe('Trade controller, buy token', () => { count: 5, type: TokenTradeOrderType.BUY, }; - mockWalletReturnValue(walletSpy, memberAddress, request); - await expectThrow(testEnv.wrap(tradeToken)({}), WenError.blocked_country.key); + mockWalletReturnValue(memberAddress, request); + const call = testEnv.mockWrap(tradeTokenControl); + await expectThrow(call, WenError.blocked_country.key); }); it('Should fail, country blocked for token', async () => { @@ -147,7 +143,8 @@ describe('Trade controller, buy token', () => { count: 5, type: TokenTradeOrderType.BUY, }; - mockWalletReturnValue(walletSpy, memberAddress, request); - await expectThrow(testEnv.wrap(tradeToken)({}), WenError.blocked_country.key); + mockWalletReturnValue(memberAddress, request); + const call = testEnv.mockWrap(tradeTokenControl); + await expectThrow(call, WenError.blocked_country.key); }); }); diff --git a/packages/functions/test/controls/token-trade.sell.spec.ts b/packages/functions/test/controls/token-trade.sell.spec.ts index b64485bef1..2db9ca0c5e 100644 --- a/packages/functions/test/controls/token-trade.sell.spec.ts +++ b/packages/functions/test/controls/token-trade.sell.spec.ts @@ -7,42 +7,29 @@ import { Space, SUB_COL, Token, - TokenDistribution, TokenStatus, TokenTradeOrder, TokenTradeOrderStatus, TokenTradeOrderType, + Transaction, + WEN_FUNC, WenError, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { enableTokenTrading } from '../../src/runtime/firebase/token/base'; -import { cancelTradeOrder, tradeToken } from '../../src/runtime/firebase/token/trading'; +import { tradeTokenControl } from '../../src/controls/token-trading/token-trade.controller'; import * as wallet from '../../src/utils/wallet.utils'; -import { testEnv } from '../set-up'; -import { - createMember, - createSpace, - expectThrow, - getRandomSymbol, - mockIpCheck, - mockWalletReturnValue, - wait, -} from './common'; - -let walletSpy: any; +import { mockWalletReturnValue, testEnv } from '../set-up'; +import { expectThrow, getRandomSymbol, mockIpCheck, wait } from './common'; describe('Trade controller, sell token', () => { let memberAddress: NetworkAddress; let token: Token; let space: Space; - beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - memberAddress = await createMember(walletSpy); - space = await createSpace(walletSpy, memberAddress); - + memberAddress = await testEnv.createMember(); + space = await testEnv.createSpace(memberAddress); const tokenId = wallet.getRandomEthAddress(); - token = { + const upserToken = { project: SOON_PROJECT_ID, uid: tokenId, symbol: getRandomSymbol(), @@ -51,11 +38,11 @@ describe('Trade controller, sell token', () => { approved: true, space: space.uid, }; - await build5Db().doc(`${COL.TOKEN}/${tokenId}`).set(token); - const distribution = { tokenOwned: 10 }; + await build5Db().doc(COL.TOKEN, tokenId).upsert(upserToken); + token = (await build5Db().doc(COL.TOKEN, tokenId).get())!; await build5Db() - .doc(`${COL.TOKEN}/${tokenId}/${SUB_COL.DISTRIBUTION}/${memberAddress}`) - .set(distribution); + .doc(COL.TOKEN, tokenId, SUB_COL.DISTRIBUTION, memberAddress) + .upsert({ tokenOwned: 10 }); }); it('Should create sell order and cancel it', async () => { @@ -65,33 +52,29 @@ describe('Trade controller, sell token', () => { count: 5, type: TokenTradeOrderType.SELL, }; - mockWalletReturnValue(walletSpy, memberAddress, request); - const sell = await testEnv.wrap(tradeToken)({}); + mockWalletReturnValue(memberAddress, request); + const sell = await testEnv.wrap(WEN_FUNC.tradeToken); expect(sell.count).toBe(5); expect(sell.price).toBe(MIN_IOTA_AMOUNT); expect(sell.tokenStatus).toBe(TokenStatus.AVAILABLE); - const distribution = await build5Db() - .doc(`${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${memberAddress}`) - .get(); + .doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, memberAddress) + .get(); expect(distribution?.lockedForSale).toBe(5); - await wait(async () => { - const doc = await build5Db().doc(`${COL.TOKEN_MARKET}/${sell.uid}`).get(); + const doc = await build5Db().doc(COL.TOKEN_MARKET, sell.uid).get(); return ( doc.updatedOn !== undefined && dayjs(doc.updatedOn.toDate()).isAfter(doc.createdOn!.toDate()) ); }); - const cancelRequest = { uid: sell.uid }; - mockWalletReturnValue(walletSpy, memberAddress, cancelRequest); - const cancelled = await testEnv.wrap(cancelTradeOrder)({}); + mockWalletReturnValue(memberAddress, cancelRequest); + const cancelled = await testEnv.wrap(WEN_FUNC.cancelTradeOrder); expect(cancelled.status).toBe(TokenTradeOrderStatus.CANCELLED); - const cancelledDistribution = await build5Db() - .doc(`${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${memberAddress}`) - .get(); + .doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, memberAddress) + .get(); expect(cancelledDistribution?.lockedForSale).toBe(0); }); @@ -102,8 +85,8 @@ describe('Trade controller, sell token', () => { count: 11, type: TokenTradeOrderType.SELL, }; - mockWalletReturnValue(walletSpy, memberAddress, request); - await expectThrow(testEnv.wrap(tradeToken)({}), WenError.no_available_tokens_for_sale.key); + mockWalletReturnValue(memberAddress, request); + await expectThrow(testEnv.wrap(WEN_FUNC.tradeToken), WenError.no_available_tokens_for_sale.key); }); it('Should create, total price too low', async () => { @@ -113,108 +96,107 @@ describe('Trade controller, sell token', () => { count: 1, type: TokenTradeOrderType.SELL, }; - mockWalletReturnValue(walletSpy, memberAddress, request); - const sellOrder = await testEnv.wrap(tradeToken)({}); + mockWalletReturnValue(memberAddress, request); + const sellOrder = await testEnv.wrap(WEN_FUNC.tradeToken); expect(sellOrder.price).toBe(MIN_IOTA_AMOUNT / 2); }); it('Should throw on one, not enough tokens', async () => { - mockWalletReturnValue(walletSpy, memberAddress, { + mockWalletReturnValue(memberAddress, { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: 8, type: TokenTradeOrderType.SELL, }); - await testEnv.wrap(tradeToken)({}); - mockWalletReturnValue(walletSpy, memberAddress, { + await testEnv.wrap(WEN_FUNC.tradeToken); + mockWalletReturnValue(memberAddress, { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: 8, type: TokenTradeOrderType.SELL, }); - await expectThrow(testEnv.wrap(tradeToken)({}), WenError.no_available_tokens_for_sale.key); + await expectThrow(testEnv.wrap(WEN_FUNC.tradeToken), WenError.no_available_tokens_for_sale.key); }); it('Should throw, not enough tokens even after cancels', async () => { - mockWalletReturnValue(walletSpy, memberAddress, { + mockWalletReturnValue(memberAddress, { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: 5, type: TokenTradeOrderType.SELL, }); - const sell = await testEnv.wrap(tradeToken)({}); - mockWalletReturnValue(walletSpy, memberAddress, { + const sell = await testEnv.wrap(WEN_FUNC.tradeToken); + + mockWalletReturnValue(memberAddress, { symbol: token.symbol, price: MIN_IOTA_AMOUNT as any, count: 5, type: TokenTradeOrderType.SELL, }); - await testEnv.wrap(tradeToken)({}); + await testEnv.wrap(WEN_FUNC.tradeToken); - mockWalletReturnValue(walletSpy, memberAddress, { + mockWalletReturnValue(memberAddress, { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: 8, type: TokenTradeOrderType.SELL, }); - await expectThrow(testEnv.wrap(tradeToken)({}), WenError.no_available_tokens_for_sale.key); - + await expectThrow(testEnv.wrap(WEN_FUNC.tradeToken), WenError.no_available_tokens_for_sale.key); const cancelRequest = { uid: sell.uid }; - mockWalletReturnValue(walletSpy, memberAddress, cancelRequest); - await testEnv.wrap(cancelTradeOrder)({}); - + mockWalletReturnValue(memberAddress, cancelRequest); + await testEnv.wrap(WEN_FUNC.cancelTradeOrder); const distribution = await build5Db() - .doc(`${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${memberAddress}`) - .get(); + .doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, memberAddress) + .get(); expect(distribution?.lockedForSale).toBe(5); - mockWalletReturnValue(walletSpy, memberAddress, { + mockWalletReturnValue(memberAddress, { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: 8, type: TokenTradeOrderType.SELL, }); - await expectThrow(testEnv.wrap(tradeToken)({}), WenError.no_available_tokens_for_sale.key); + await expectThrow(testEnv.wrap(WEN_FUNC.tradeToken), WenError.no_available_tokens_for_sale.key); }); it('Should update sale lock properly', async () => { - const distDocRef = build5Db().doc( - `${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${memberAddress}`, - ); + const distDocRef = build5Db().doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, memberAddress); const count = 3; const sells = [] as any[]; for (let i = 0; i < count; ++i) { - mockWalletReturnValue(walletSpy, memberAddress, { + mockWalletReturnValue(memberAddress, { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: 1, type: TokenTradeOrderType.SELL, }); - sells.push(await testEnv.wrap(tradeToken)({})); + sells.push(await testEnv.wrap(WEN_FUNC.tradeToken)); } + await wait(async () => { - const distribution = await distDocRef.get(); + const distribution = await distDocRef.get(); return distribution?.lockedForSale === count; }); for (let i = 0; i < count; ++i) { const cancelRequest = { uid: sells[i].uid }; - mockWalletReturnValue(walletSpy, memberAddress, cancelRequest); - await testEnv.wrap(cancelTradeOrder)({}); - const distribution = await distDocRef.get(); + mockWalletReturnValue(memberAddress, cancelRequest); + await testEnv.wrap(WEN_FUNC.cancelTradeOrder); + const distribution = await distDocRef.get(); expect(distribution?.lockedForSale).toBe(count - i - 1); } }); it('Should throw, token not approved', async () => { - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).update({ approved: false }); - mockWalletReturnValue(walletSpy, memberAddress, { + await build5Db().doc(COL.TOKEN, token.uid).update({ approved: false }); + + mockWalletReturnValue(memberAddress, { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: 8, type: TokenTradeOrderType.SELL, }); - await expectThrow(testEnv.wrap(tradeToken)({}), WenError.token_does_not_exist.key); + await expectThrow(testEnv.wrap(WEN_FUNC.tradeToken), WenError.token_does_not_exist.key); }); it('Should throw, precision too much', async () => { @@ -224,18 +206,18 @@ describe('Trade controller, sell token', () => { count: 5, type: TokenTradeOrderType.SELL, }; - mockWalletReturnValue(walletSpy, memberAddress, request); - const sell = await testEnv.wrap(tradeToken)({}); + mockWalletReturnValue(memberAddress, request); + const sell = await testEnv.wrap(WEN_FUNC.tradeToken); expect(sell.count).toBe(5); - const request2 = { symbol: token.symbol, - price: MIN_IOTA_AMOUNT + 0.1234567, + price: MIN_IOTA_AMOUNT + 0.1543267, count: 5, type: TokenTradeOrderType.SELL, }; - mockWalletReturnValue(walletSpy, memberAddress, request2); - await expectThrow(testEnv.wrap(tradeToken)({}), WenError.invalid_params.key); + + mockWalletReturnValue(memberAddress, request2); + await expectThrow(testEnv.wrap(WEN_FUNC.tradeToken), WenError.invalid_params.key); }); it('Should fail, country blocked by default', async () => { @@ -246,8 +228,10 @@ describe('Trade controller, sell token', () => { count: 5, type: TokenTradeOrderType.SELL, }; - mockWalletReturnValue(walletSpy, memberAddress, request); - await expectThrow(testEnv.wrap(tradeToken)({}), WenError.blocked_country.key); + + mockWalletReturnValue(memberAddress, request); + const call = testEnv.mockWrap(tradeTokenControl); + await expectThrow(call, WenError.blocked_country.key); }); it('Should fail, country blocked for token', async () => { @@ -258,28 +242,25 @@ describe('Trade controller, sell token', () => { count: 5, type: TokenTradeOrderType.SELL, }; - mockWalletReturnValue(walletSpy, memberAddress, request); - await expectThrow(testEnv.wrap(tradeToken)({}), WenError.blocked_country.key); + mockWalletReturnValue(memberAddress, request); + const call = testEnv.mockWrap(tradeTokenControl); + await expectThrow(call, WenError.blocked_country.key); }); it('Should fail first, tading disabled, then succeeed', async () => { - await build5Db() - .doc(`${COL.TOKEN}/${token.uid}`) - .update({ tradingDisabled: true, public: true }); + await build5Db().doc(COL.TOKEN, token.uid).update({ tradingDisabled: true, public: true }); const request = { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: 5, type: TokenTradeOrderType.SELL, }; - mockWalletReturnValue(walletSpy, memberAddress, request); - await expectThrow(testEnv.wrap(tradeToken)({}), WenError.token_trading_disabled.key); - - mockWalletReturnValue(walletSpy, memberAddress, { uid: token.uid }); - await testEnv.wrap(enableTokenTrading)({}); - - mockWalletReturnValue(walletSpy, memberAddress, request); - const sell = await testEnv.wrap(tradeToken)({}); + mockWalletReturnValue(memberAddress, request); + await expectThrow(testEnv.wrap(WEN_FUNC.tradeToken), WenError.token_trading_disabled.key); + mockWalletReturnValue(memberAddress, { uid: token.uid }); + await testEnv.wrap(WEN_FUNC.enableTokenTrading); + mockWalletReturnValue(memberAddress, request); + const sell = await testEnv.wrap(WEN_FUNC.tradeToken); expect(sell.count).toBe(5); expect(sell.price).toBe(MIN_IOTA_AMOUNT); expect(sell.tokenStatus).toBe(TokenStatus.AVAILABLE); diff --git a/packages/functions/test/controls/token-trade.trigger.spec.ts b/packages/functions/test/controls/token-trade.trigger.spec.ts index 0a7d4c82e5..40bbd8406f 100644 --- a/packages/functions/test/controls/token-trade.trigger.spec.ts +++ b/packages/functions/test/controls/token-trade.trigger.spec.ts @@ -10,12 +10,10 @@ import { SOON_PROJECT_ID, SUB_COL, SYSTEM_CONFIG_DOC_ID, - StakeType, TOKEN_SALE_TEST, Token, TokenDistribution, TokenPurchase, - TokenStats, TokenStatus, TokenTradeOrder, TokenTradeOrderStatus, @@ -23,50 +21,37 @@ import { Transaction, TransactionPayloadType, TransactionType, + WEN_FUNC, } from '@build-5/interfaces'; import bigDecimal from 'js-big-decimal'; import { isEmpty } from 'lodash'; -import { cancelTradeOrder, tradeToken } from '../../src/runtime/firebase/token/trading'; import { TOKEN_TRADE_ORDER_FETCH_LIMIT } from '../../src/triggers/token-trading/match-token'; import { getAddress } from '../../src/utils/address.utils'; import { serverTime } from '../../src/utils/dateTime.utils'; import * as wallet from '../../src/utils/wallet.utils'; -import { soonTokenId, testEnv } from '../set-up'; -import { - createMember, - createRoyaltySpaces, - getRandomSymbol, - mockWalletReturnValue, - submitMilestoneFunc, - wait, -} from './common'; - -let walletSpy: any; +import { mockWalletReturnValue, soonTokenId, testEnv } from '../set-up'; +import { createRoyaltySpaces, getRandomSymbol, submitMilestoneFunc, wait } from './common'; const buyTokenFunc = async (memberAddress: NetworkAddress, request: any) => { - mockWalletReturnValue(walletSpy, memberAddress, { ...request, type: TokenTradeOrderType.BUY }); - const order = await testEnv.wrap(tradeToken)({}); + mockWalletReturnValue(memberAddress, { ...request, type: TokenTradeOrderType.BUY }); + const order = await testEnv.wrap(WEN_FUNC.tradeToken); await submitMilestoneFunc( order, Number(bigDecimal.floor(bigDecimal.multiply(request.price, request.count))), ); return order; }; - const assertVolumeTotal = async (tokenId: string, volumeTotal: number) => { - const statDoc = build5Db().doc(`${COL.TOKEN}/${tokenId}/${SUB_COL.STATS}/${tokenId}`); - await wait(async () => (await statDoc.get())?.volumeTotal === volumeTotal); + const statDoc = build5Db().doc(COL.TOKEN, tokenId, SUB_COL.STATS, tokenId); + await wait(async () => (await statDoc.get())?.volumeTotal === volumeTotal); }; - const getBillPayments = (member: string) => build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.BILL_PAYMENT) .where('member', '==', member) - .get(); - + .get(); const { percentage, spaceonepercentage } = TOKEN_SALE_TEST; - const getRoyaltyDistribution = (amount: number) => { const spaceOne = amount * (percentage / 100) * (spaceonepercentage / 100); const spaceTwo = amount * (percentage / 100) * (1 - spaceonepercentage / 100); @@ -82,10 +67,8 @@ const getRoyaltyDistribution = (amount: number) => { describe('Trade trigger', () => { let seller: string; let buyer: string; - let token: Token; const tokenCount = 400; - const saveSellToDb = async (count: number, price: number) => { const data = { project: SOON_PROJECT_ID, @@ -102,7 +85,7 @@ describe('Trade trigger', () => { fulfilled: 0, status: TokenTradeOrderStatus.ACTIVE, }; - await build5Db().doc(`${COL.TOKEN_MARKET}/${data.uid}`).create(data); + await build5Db().doc(COL.TOKEN_MARKET, data.uid).create(data); }; beforeAll(async () => { @@ -110,12 +93,10 @@ describe('Trade trigger', () => { }); beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - seller = await createMember(walletSpy); - buyer = await createMember(walletSpy); - + seller = await testEnv.createMember(); + buyer = await testEnv.createMember(); const tokenId = wallet.getRandomEthAddress(); - token = { + const tokenUpsert = { project: SOON_PROJECT_ID, uid: tokenId, symbol: getRandomSymbol(), @@ -124,38 +105,33 @@ describe('Trade trigger', () => { status: TokenStatus.PRE_MINTED, approved: true, }; - await build5Db().doc(`${COL.TOKEN}/${tokenId}`).set(token); - const distribution = { tokenOwned: tokenCount * 3 }; + await build5Db().doc(COL.TOKEN, tokenId).upsert(tokenUpsert); + token = (await build5Db().doc(COL.TOKEN, tokenId).get())!; + const distribution = { tokenOwned: tokenCount * 3 }; + await build5Db().doc(COL.TOKEN, tokenId, SUB_COL.DISTRIBUTION, seller).upsert(distribution); await build5Db() - .doc(`${COL.TOKEN}/${tokenId}/${SUB_COL.DISTRIBUTION}/${seller}`) - .set(distribution); - - await build5Db() - .doc(`${COL.SYSTEM}/${SYSTEM_CONFIG_DOC_ID}`) - .set({ tokenTradingFeePercentage: build5Db().deleteField() }, true); + .doc(COL.SYSTEM, SYSTEM_CONFIG_DOC_ID) + .upsert({ tokenTradingFeePercentage: undefined }); }); it('Should fulfill buy with one sell', async () => { - mockWalletReturnValue(walletSpy, seller, { + mockWalletReturnValue(seller, { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: tokenCount, type: TokenTradeOrderType.SELL, }); - await testEnv.wrap(tradeToken)({}); - + await testEnv.wrap(WEN_FUNC.tradeToken); const request = { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: tokenCount }; const order = await buyTokenFunc(buyer, request); - await wait(async () => { const buySnap = await build5Db() .collection(COL.TOKEN_MARKET) .where('type', '==', TokenTradeOrderType.BUY) .where('owner', '==', buyer) - .get(); + .get(); return buySnap[0].fulfilled === tokenCount; }); - const buySnap = await build5Db() .collection(COL.TOKEN_MARKET) .where('type', '==', TokenTradeOrderType.BUY) @@ -165,7 +141,6 @@ describe('Trade trigger', () => { const buy = buySnap[0]; expect(buy.status).toBe(TokenTradeOrderStatus.SETTLED); expect(buy.tokenStatus).toBe(TokenStatus.PRE_MINTED); - const sellSnap = await build5Db() .collection(COL.TOKEN_MARKET) .where('type', '==', TokenTradeOrderType.SELL) @@ -175,19 +150,17 @@ describe('Trade trigger', () => { const sell = sellSnap[0]; expect(sell.status).toBe(TokenTradeOrderStatus.SETTLED); expect(sell.tokenStatus).toBe(TokenStatus.PRE_MINTED); - const sellDistribution = ( - await build5Db().doc(`${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${seller}`).get() + await build5Db().doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, seller).get() ); expect(sellDistribution.lockedForSale).toBe(0); expect(sellDistribution.sold).toBe(tokenCount); expect(sellDistribution.tokenOwned).toBe(2 * tokenCount); const buyDistribution = ( - await build5Db().doc(`${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${buyer}`).get() + await build5Db().doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, buyer).get() ); expect(buyDistribution.totalPurchased).toBe(tokenCount); expect(buyDistribution.tokenOwned).toBe(tokenCount); - const purchases = await build5Db() .collection(COL.TOKEN_PURCHASE) .where('buy', '==', buy.uid) @@ -200,17 +173,15 @@ describe('Trade trigger', () => { expect(purchase.count).toBe(tokenCount); expect(purchase.tokenStatus).toBe(TokenStatus.PRE_MINTED); expect(purchase.sellerTier).toBe(0); - expect(purchase.sellerTokenTradingFeePercentage).toBeNull(); - - const sellerData = await build5Db().doc(`${COL.MEMBER}/${seller}`).get(); - const billPaymentDocRef = build5Db().doc(`${COL.TRANSACTION}/${purchase.billPaymentId}`); + expect(purchase.sellerTokenTradingFeePercentage).toBeUndefined(); + const sellerData = await build5Db().doc(COL.MEMBER, seller).get(); + const billPaymentDocRef = build5Db().doc(COL.TRANSACTION, purchase.billPaymentId!); const billPayment = await billPaymentDocRef.get(); expect(billPayment.payload.sourceAddress).toBe(order.payload.targetAddress); expect(billPayment.payload.targetAddress).toBe(getAddress(sellerData, Network.IOTA)); expect(billPayment.payload.token).toBe(token.uid); expect(billPayment.payload.tokenSymbol).toBe(token.symbol); expect(billPayment.payload.type).toBe(TransactionPayloadType.PRE_MINTED_TOKEN_TRADE); - const paymentSnap = await getBillPayments(buyer); expect(paymentSnap.length).toBe(3); const payments = paymentSnap.sort((a, b) => a.payload.amount! - b.payload.amount!); @@ -218,38 +189,32 @@ describe('Trade trigger', () => { getRoyaltyDistribution(MIN_IOTA_AMOUNT * tokenCount), ); expect(payments.map((d) => d.ignoreWallet)).toEqual([false, false, undefined]); - payments.forEach((p) => { expect(p?.payload?.previousOwner).toBe(buyer); expect(p?.member).toBe(buyer); }); - await assertVolumeTotal(token.uid, tokenCount); }); it('Should fulfill buy with one sell, same owner', async () => { buyer = seller; - - mockWalletReturnValue(walletSpy, seller, { + mockWalletReturnValue(seller, { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: tokenCount, type: TokenTradeOrderType.SELL, }); - await testEnv.wrap(tradeToken)({}); - + await testEnv.wrap(WEN_FUNC.tradeToken); const request = { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: tokenCount }; const order = await buyTokenFunc(buyer, request); - await wait(async () => { const buySnap = await build5Db() .collection(COL.TOKEN_MARKET) .where('type', '==', TokenTradeOrderType.BUY) .where('owner', '==', buyer) - .get(); + .get(); return buySnap[0].fulfilled === tokenCount; }); - const buySnap = await build5Db() .collection(COL.TOKEN_MARKET) .where('type', '==', TokenTradeOrderType.BUY) @@ -259,30 +224,27 @@ describe('Trade trigger', () => { const buy = buySnap[0]; expect(buy.status).toBe(TokenTradeOrderStatus.SETTLED); const buyDistribution = ( - await build5Db().doc(`${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${buyer}`).get() + await build5Db().doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, buyer).get() ); expect(buyDistribution.totalPurchased).toBe(tokenCount); expect(buyDistribution.tokenOwned).toBe(3 * tokenCount); - const purchase = await build5Db() .collection(COL.TOKEN_PURCHASE) .where('buy', '==', buy.uid) - .get(); + .get(); expect(purchase.length).toBe(1); expect(purchase[0].buy).toBe(buy.uid); expect(purchase[0].sell).toBeDefined(); expect(purchase[0].price).toBe(MIN_IOTA_AMOUNT); expect(purchase[0].count).toBe(tokenCount); - - const sellerData = await build5Db().doc(`${COL.MEMBER}/${seller}`).get(); - const billPaymentDocRef = build5Db().doc(`${COL.TRANSACTION}/${purchase[0].billPaymentId}`); + const sellerData = await build5Db().doc(COL.MEMBER, seller).get(); + const billPaymentDocRef = build5Db().doc(COL.TRANSACTION, purchase[0].billPaymentId!); const billPayment = await billPaymentDocRef.get(); expect(billPayment.payload.sourceAddress).toBe(order.payload.targetAddress); expect(billPayment.payload.targetAddress).toBe(getAddress(sellerData, Network.IOTA)); expect(billPayment.payload.token).toBe(token.uid); expect(billPayment.payload.tokenSymbol).toBe(token.symbol); expect(billPayment.payload.type).toBe(TransactionPayloadType.PRE_MINTED_TOKEN_TRADE); - const paymentSnap = await getBillPayments(buyer); expect(paymentSnap.length).toBe(3); const payments = paymentSnap.sort((a, b) => a.payload.amount! - b.payload.amount!); @@ -290,62 +252,55 @@ describe('Trade trigger', () => { getRoyaltyDistribution(MIN_IOTA_AMOUNT * tokenCount), ); expect(payments.map((d) => d.ignoreWallet)).toEqual([false, false, undefined]); - payments.forEach((p) => { expect(p?.payload?.previousOwner).toBe(seller); expect(p?.member).toBe(buyer); }); - await assertVolumeTotal(token.uid, tokenCount); }); it('Should fulfill buy with two sell and credit owner', async () => { - mockWalletReturnValue(walletSpy, seller, { + mockWalletReturnValue(seller, { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: tokenCount, type: TokenTradeOrderType.SELL, }); - await testEnv.wrap(tradeToken)({}); - mockWalletReturnValue(walletSpy, seller, { + await testEnv.wrap(WEN_FUNC.tradeToken); + mockWalletReturnValue(seller, { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: tokenCount, type: TokenTradeOrderType.SELL, }); - await testEnv.wrap(tradeToken)({}); - + await testEnv.wrap(WEN_FUNC.tradeToken); const request = { symbol: token.symbol, price: MIN_IOTA_AMOUNT * 2, count: 2 * tokenCount }; const order = await buyTokenFunc(buyer, request); - await wait(async () => { const buySnap = await build5Db() .collection(COL.TOKEN_MARKET) .where('type', '==', TokenTradeOrderType.BUY) .where('owner', '==', buyer) - .get(); + .get(); return buySnap[0].fulfilled === 2 * tokenCount; }); - const buySnap = await build5Db() .collection(COL.TOKEN_MARKET) .where('type', '==', TokenTradeOrderType.BUY) .where('owner', '==', buyer) - .get(); + .get(); expect(buySnap.length).toBe(1); const buy = buySnap[0]; expect(buy.status).toBe(TokenTradeOrderStatus.SETTLED); - const credit = ( - await build5Db().doc(`${COL.TRANSACTION}/${buy.creditTransactionId}`).get() + await build5Db().doc(COL.TRANSACTION, buy.creditTransactionId!).get() ); expect(credit.payload.amount).toBe(MIN_IOTA_AMOUNT * 2 * tokenCount); expect(credit.payload.sourceTransaction).toContain(buySnap[0].paymentTransactionId); expect(credit?.payload?.sourceAddress).toBe(order.payload.targetAddress); - const buyerData = await build5Db().doc(`${COL.MEMBER}/${buyer}`).get(); + const buyerData = await build5Db().doc(COL.MEMBER, buyer).get(); expect(credit?.payload?.targetAddress).toBe(getAddress(buyerData, Network.IOTA)); expect(credit.network).toBe(DEFAULT_NETWORK); - const paymentSnap = await getBillPayments(buyer); expect(paymentSnap.length).toBe(6); const amounts = paymentSnap.map((d) => d.payload.amount!).sort((a, b) => a - b); @@ -356,7 +311,6 @@ describe('Trade trigger', () => { ].sort((a, b) => a - b), ); paymentSnap.forEach((doc) => expect(doc?.network).toBe(DEFAULT_NETWORK)); - await assertVolumeTotal(token.uid, 2 * tokenCount); }); @@ -364,24 +318,21 @@ describe('Trade trigger', () => { const request = { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: tokenCount }; await buyTokenFunc(buyer, request); await buyTokenFunc(buyer, request); - - mockWalletReturnValue(walletSpy, seller, { + mockWalletReturnValue(seller, { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: 2 * tokenCount, type: TokenTradeOrderType.SELL, }); - await testEnv.wrap(tradeToken)({}); - + await testEnv.wrap(WEN_FUNC.tradeToken); await wait(async () => { const sellSnap = await build5Db() .collection(COL.TOKEN_MARKET) .where('type', '==', TokenTradeOrderType.SELL) .where('owner', '==', seller) - .get(); + .get(); return sellSnap[0].fulfilled === 2 * tokenCount; }); - const sellSnap = await build5Db() .collection(COL.TOKEN_MARKET) .where('type', '==', TokenTradeOrderType.SELL) @@ -391,53 +342,49 @@ describe('Trade trigger', () => { const sell = sellSnap[0]; expect(sell.status).toBe(TokenTradeOrderStatus.SETTLED); expect(sell.fulfilled).toBe(2 * tokenCount); - await assertVolumeTotal(token.uid, 2 * tokenCount); }); it('Should sell tokens in two transactions', async () => { - mockWalletReturnValue(walletSpy, seller, { + mockWalletReturnValue(seller, { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: 2 * tokenCount, type: TokenTradeOrderType.SELL, }); - await testEnv.wrap(tradeToken)({}); + await testEnv.wrap(WEN_FUNC.tradeToken); await buyTokenFunc(buyer, { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: 2 * tokenCount, }); - - mockWalletReturnValue(walletSpy, seller, { + mockWalletReturnValue(seller, { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: tokenCount, type: TokenTradeOrderType.SELL, }); - await testEnv.wrap(tradeToken)({}); + await testEnv.wrap(WEN_FUNC.tradeToken); await buyTokenFunc(buyer, { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: tokenCount }); - await wait(async () => { const distribution = ( - await build5Db().doc(`${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${seller}`).get() + await build5Db().doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, seller).get() ); return distribution.tokenOwned === 0 && distribution.sold === 3 * tokenCount; }); }); it('Should buy in parallel', async () => { - mockWalletReturnValue(walletSpy, seller, { + mockWalletReturnValue(seller, { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: 2 * tokenCount, type: TokenTradeOrderType.SELL, }); - await testEnv.wrap(tradeToken)({}); + await testEnv.wrap(WEN_FUNC.tradeToken); const request = { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: tokenCount }; const promises = [buyTokenFunc(buyer, request), buyTokenFunc(buyer, request)]; await Promise.all(promises); - await wait(async () => { const allSettled = ( await build5Db().collection(COL.TOKEN_MARKET).where('owner', '==', buyer).get() @@ -446,10 +393,10 @@ describe('Trade trigger', () => { .reduce((sum, act) => sum && act.status === TokenTradeOrderStatus.SETTLED, true); return allSettled; }); - - const sales = ( - await build5Db().collection(COL.TOKEN_MARKET).where('owner', 'in', [seller, buyer]).get() - ).map((d) => d); + const sales = [ + ...(await build5Db().collection(COL.TOKEN_MARKET).where('owner', '==', seller).get()), + ...(await build5Db().collection(COL.TOKEN_MARKET).where('owner', '==', buyer).get()), + ].map((d) => d); expect(sales.length).toBe(3); const buyFulfillmentCount = sales.reduce( (sum, sale) => sum + (sale.type === TokenTradeOrderType.BUY ? sale.fulfilled : 0), @@ -461,16 +408,13 @@ describe('Trade trigger', () => { 0, ); expect(sellFulfillmentCount).toBe(2 * tokenCount); - await assertVolumeTotal(token.uid, 2 * tokenCount); }); it('Should buy and sell in parallel', async () => { - const distributionDocRef = build5Db().doc( - `${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${seller}`, - ); - const distribution = { tokenOwned: 3 * tokenCount }; - await distributionDocRef.set(distribution); + const distributionDocRef = build5Db().doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, seller); + const distribution = { tokenOwned: 3 * tokenCount }; + await distributionDocRef.upsert(distribution); const sellTokenFunc = async (count: number, price: number) => { const sellDocId = wallet.getRandomEthAddress(); const data = { @@ -488,12 +432,9 @@ describe('Trade trigger', () => { status: TokenTradeOrderStatus.ACTIVE, createdOn: serverTime(), }; - await build5Db().doc(`${COL.TOKEN_MARKET}/${sellDocId}`).create(data); - await distributionDocRef.update({ - lockedForSale: build5Db().inc(count), - }); + await build5Db().doc(COL.TOKEN_MARKET, sellDocId).create(data); + await distributionDocRef.update({ lockedForSale: build5Db().inc(count) }); }; - const buyRequest = { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: tokenCount }; const promises = [ buyTokenFunc(buyer, buyRequest), @@ -503,36 +444,33 @@ describe('Trade trigger', () => { sellTokenFunc(tokenCount, MIN_IOTA_AMOUNT), ]; await Promise.all(promises); - await wait(async () => { - const allSettled = ( - await build5Db().collection(COL.TOKEN_MARKET).where('owner', 'in', [seller, buyer]).get() - ) + const allSettled = [ + ...(await build5Db().collection(COL.TOKEN_MARKET).where('owner', '==', seller).get()), + ...(await build5Db().collection(COL.TOKEN_MARKET).where('owner', '==', buyer).get()), + ] .map((d) => d) .reduce((sum, act) => sum && act.status === TokenTradeOrderStatus.SETTLED, true); return allSettled; }); - - const sales = ( - await build5Db().collection(COL.TOKEN_MARKET).where('owner', 'in', [seller, buyer]).get() - ).map((d) => d); - + const sales = [ + ...(await build5Db().collection(COL.TOKEN_MARKET).where('owner', '==', seller).get()), + ...(await build5Db().collection(COL.TOKEN_MARKET).where('owner', '==', buyer).get()), + ].map((d) => d); const allSettled = sales.reduce( (sum, act) => sum && act.status === TokenTradeOrderStatus.SETTLED, true, ); expect(allSettled).toBe(true); - const sellDistribution = await distributionDocRef.get(); expect(sellDistribution.sold).toBe(3 * tokenCount); expect(sellDistribution.lockedForSale).toBe(0); expect(sellDistribution.tokenOwned).toBe(0); const buyDistribution = ( - await build5Db().doc(`${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${buyer}`).get() + await build5Db().doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, buyer).get() ); expect(buyDistribution.totalPurchased).toBe(3 * tokenCount); expect(buyDistribution.tokenOwned).toBe(3 * tokenCount); - const paymentSnap = await getBillPayments(buyer); expect(paymentSnap.length).toBe(9); const amounts = paymentSnap.map((d) => d.payload.amount!).sort((a, b) => a - b); @@ -540,81 +478,70 @@ describe('Trade trigger', () => { expect(amounts).toEqual( [...sortedAmount, ...sortedAmount, ...sortedAmount].sort((a, b) => a - b), ); - await assertVolumeTotal(token.uid, 3 * tokenCount); }); it('Should cancel buy after half fulfilled', async () => { - mockWalletReturnValue(walletSpy, seller, { + mockWalletReturnValue(seller, { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: tokenCount, type: TokenTradeOrderType.SELL, }); - await testEnv.wrap(tradeToken)({}); + await testEnv.wrap(WEN_FUNC.tradeToken); await buyTokenFunc(buyer, { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: 2 * tokenCount, }); - await wait(async () => { const snap = await build5Db() .collection(COL.TOKEN_MARKET) .where('owner', '==', buyer) .where('type', '==', TokenTradeOrderType.BUY) - .get(); + .get(); return snap[0].fulfilled === tokenCount; }); - const snap = await build5Db() .collection(COL.TOKEN_MARKET) .where('owner', '==', buyer) .where('type', '==', TokenTradeOrderType.BUY) - .get(); - mockWalletReturnValue(walletSpy, buyer, { uid: snap[0].uid }); - const cancelled = await testEnv.wrap(cancelTradeOrder)({}); + .get(); + mockWalletReturnValue(buyer, { uid: snap[0].uid }); + const cancelled = await testEnv.wrap(WEN_FUNC.cancelTradeOrder); expect(cancelled.status).toBe(TokenTradeOrderStatus.PARTIALLY_SETTLED_AND_CANCELLED); - const creditSnap = await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.CREDIT) .where('member', '==', buyer) - .where('payload.type', '==', TransactionPayloadType.TOKEN_BUY) - .get(); + .where('payload_type', '==', TransactionPayloadType.TOKEN_BUY) + .get(); expect(creditSnap.length).toBe(1); expect(creditSnap[0]?.payload?.amount).toBe(tokenCount * MIN_IOTA_AMOUNT); expect(creditSnap[0]?.payload?.reason).toBe(CreditPaymentReason.TRADE_CANCELLED); - await assertVolumeTotal(token.uid, tokenCount); }); it('Should cancel buy after half fulfilled, decimal values', async () => { const tokenCount = 7; - mockWalletReturnValue(walletSpy, seller, { + mockWalletReturnValue(seller, { symbol: token.symbol, price: MIN_IOTA_AMOUNT + 0.1, count: tokenCount, type: TokenTradeOrderType.SELL, }); - await testEnv.wrap(tradeToken)({}); + await testEnv.wrap(WEN_FUNC.tradeToken); await buyTokenFunc(buyer, { symbol: token.symbol, price: MIN_IOTA_AMOUNT + 0.1, count: 2 * tokenCount, }); - await wait(async () => { return ( - ( - await build5Db() - .collection(COL.TOKEN_MARKET) - .where('owner', '==', buyer) - .get() - )[0]?.fulfilled === tokenCount + (await build5Db().collection(COL.TOKEN_MARKET).where('owner', '==', buyer).get())[0] + ?.fulfilled === tokenCount ); }); - const buyQuery = build5Db() .collection(COL.TOKEN_MARKET) .where('type', '==', TokenTradeOrderType.BUY) @@ -622,38 +549,30 @@ describe('Trade trigger', () => { const buySnap = await buyQuery.get(); expect(buySnap.length).toBe(1); const buy = buySnap[0]; - - mockWalletReturnValue(walletSpy, buyer, { uid: buy.uid }); - const cancelled = await testEnv.wrap(cancelTradeOrder)({}); + mockWalletReturnValue(buyer, { uid: buy.uid }); + const cancelled = await testEnv.wrap(WEN_FUNC.cancelTradeOrder); expect(cancelled.status).toBe(TokenTradeOrderStatus.PARTIALLY_SETTLED_AND_CANCELLED); - const creditSnap = await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.CREDIT) .where('member', '==', buyer) - .where('payload.type', '==', TransactionPayloadType.TOKEN_BUY) - .get(); + .where('payload_type', '==', TransactionPayloadType.TOKEN_BUY) + .get(); expect(creditSnap.length).toBe(1); expect(creditSnap[0]?.payload?.amount).toBe(tokenCount * MIN_IOTA_AMOUNT + 1); expect(creditSnap[0]?.payload?.reason).toBe(CreditPaymentReason.TRADE_CANCELLED); }); it('Should settle after second run on more than batch limit', async () => { - const distribution = { tokenOwned: 70 * tokenCount }; - await build5Db() - .doc(`${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${seller}`) - .set(distribution); - + const distribution = { tokenOwned: 70 * tokenCount }; + await build5Db().doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, seller).upsert(distribution); const promises = Array.from(Array(TOKEN_TRADE_ORDER_FETCH_LIMIT + 50)).map(() => saveSellToDb(1, MIN_IOTA_AMOUNT), ); await Promise.all(promises); - const count = TOKEN_TRADE_ORDER_FETCH_LIMIT + 20; - const request = { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count }; await buyTokenFunc(buyer, request); - await wait(async () => { return ( ( @@ -661,7 +580,7 @@ describe('Trade trigger', () => { .collection(COL.TOKEN_MARKET) .where('type', '==', TokenTradeOrderType.BUY) .where('owner', '==', buyer) - .get() + .get() )[0].status === TokenTradeOrderStatus.SETTLED ); }); @@ -669,11 +588,10 @@ describe('Trade trigger', () => { .collection(COL.TOKEN_MARKET) .where('type', '==', TokenTradeOrderType.BUY) .where('owner', '==', buyer) - .get(); + .get(); expect(bu.length).toBe(1); expect(bu[0]?.fulfilled).toBe(count); expect(bu[0]?.status).toBe(TokenTradeOrderStatus.SETTLED); - const purchases = await build5Db() .collection(COL.TOKEN_PURCHASE) .where('buy', '==', bu[0]?.uid) @@ -685,10 +603,8 @@ describe('Trade trigger', () => { const promises = Array.from(Array(100)).map(() => saveSellToDb(1, 1)); await Promise.all(promises); await saveSellToDb(1, MIN_IOTA_AMOUNT); - const request = { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: 1 }; await buyTokenFunc(buyer, request); - await wait(async () => { return ( ( @@ -696,7 +612,7 @@ describe('Trade trigger', () => { .collection(COL.TOKEN_MARKET) .where('type', '==', TokenTradeOrderType.BUY) .where('owner', '==', buyer) - .get() + .get() )[0].status === TokenTradeOrderStatus.SETTLED ); }); @@ -704,11 +620,10 @@ describe('Trade trigger', () => { .collection(COL.TOKEN_MARKET) .where('type', '==', TokenTradeOrderType.BUY) .where('owner', '==', buyer) - .get(); + .get(); expect(bu.length).toBe(1); expect(bu[0]?.fulfilled).toBe(1); expect(bu[0]?.status).toBe(TokenTradeOrderStatus.SETTLED); - const purchases = await build5Db() .collection(COL.TOKEN_PURCHASE) .where('buy', '==', bu[0]?.uid) @@ -717,28 +632,24 @@ describe('Trade trigger', () => { }); it('Should not fill buy, balance would be less then MIN_IOTA_AMOUNT and order not fulfilled', async () => { - mockWalletReturnValue(walletSpy, seller, { + mockWalletReturnValue(seller, { symbol: token.symbol, price: MIN_IOTA_AMOUNT / 2, count: 2 * tokenCount - 1, type: TokenTradeOrderType.SELL, }); - await testEnv.wrap(tradeToken)({}); - + await testEnv.wrap(WEN_FUNC.tradeToken); await buyTokenFunc(buyer, { symbol: token.symbol, price: MIN_IOTA_AMOUNT / 2, count: 2 * tokenCount, }); - const orderQuery = build5Db().collection(COL.TOKEN_MARKET).where('token', '==', token.uid); await wait(async () => { const snap = await orderQuery.get(); return snap.length === 2; }); - await new Promise((resolve) => setTimeout(resolve, 2000)); - const purchase = await build5Db() .collection(COL.TOKEN_PURCHASE) .where('token', '==', token.uid) @@ -747,48 +658,41 @@ describe('Trade trigger', () => { }); it('Should fill buy and send dust to space one', async () => { - mockWalletReturnValue(walletSpy, seller, { + mockWalletReturnValue(seller, { symbol: token.symbol, price: MIN_IOTA_AMOUNT / 2, count: 2 * tokenCount, type: TokenTradeOrderType.SELL, }); - await testEnv.wrap(tradeToken)({}); - + await testEnv.wrap(WEN_FUNC.tradeToken); await buyTokenFunc(buyer, { symbol: token.symbol, price: MIN_IOTA_AMOUNT / 2 + 1, count: 2 * tokenCount, }); - const purchaseQuery = build5Db().collection(COL.TOKEN_PURCHASE).where('token', '==', token.uid); await wait(async () => { const snap = await purchaseQuery.get(); return snap.length === 1; }); - const purchase = (await purchaseQuery.get())[0]; expect(purchase.count).toBe(2 * tokenCount); expect(purchase.price).toBe(MIN_IOTA_AMOUNT / 2); - const billPayments = ( await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.BILL_PAYMENT) - .where('payload.token', '==', token.uid) + .where('payload_token', '==', token.uid) .get() ).map((d) => d); - const billPaymentToSeller = billPayments.find( (bp) => bp.payload.amount === (MIN_IOTA_AMOUNT / 2) * (2 * tokenCount) * 0.975, ); expect(billPaymentToSeller).toBeDefined(); - const billPaymentToSpaceOne = billPayments.find( (bp) => bp.payload.amount === (MIN_IOTA_AMOUNT / 2) * (2 * tokenCount) * 0.025 * 0.1 + 800, ); expect(billPaymentToSpaceOne).toBeDefined(); - const billPaymentToSpaceTwo = billPayments.find( (bp) => bp.payload.amount === (MIN_IOTA_AMOUNT / 2) * (2 * tokenCount) * 0.025 * 0.9, ); @@ -799,41 +703,27 @@ describe('Trade trigger', () => { 'Should not create royalty payments as percentage is zero', async (isMember: boolean) => { if (isMember) { - await build5Db().doc(`${COL.MEMBER}/${seller}`).update({ tokenTradingFeePercentage: 0 }); + await build5Db().doc(COL.MEMBER, seller).update({ tokenTradingFeePercentage: 0 }); await build5Db() - .collection(COL.TOKEN) - .doc(soonTokenId) - .collection(SUB_COL.DISTRIBUTION) - .doc(seller) - .set( - { - stakes: { - [StakeType.DYNAMIC]: { - value: 15000 * MIN_IOTA_AMOUNT, - }, - }, - }, - true, - ); + .doc(COL.TOKEN, soonTokenId, SUB_COL.DISTRIBUTION, seller) + .upsert({ stakes_dynamic_value: 15000 * MIN_IOTA_AMOUNT }); } else { await build5Db() - .doc(`${COL.SYSTEM}/${SYSTEM_CONFIG_DOC_ID}`) - .set({ tokenTradingFeePercentage: 0 }); + .doc(COL.SYSTEM, SYSTEM_CONFIG_DOC_ID) + .upsert({ tokenTradingFeePercentage: 0 }); } - mockWalletReturnValue(walletSpy, seller, { + mockWalletReturnValue(seller, { symbol: token.symbol, price: MIN_IOTA_AMOUNT / 2, count: 2 * tokenCount, type: TokenTradeOrderType.SELL, }); - await testEnv.wrap(tradeToken)({}); - + await testEnv.wrap(WEN_FUNC.tradeToken); await buyTokenFunc(buyer, { symbol: token.symbol, price: MIN_IOTA_AMOUNT / 2, count: 2 * tokenCount, }); - const purchaseQuery = build5Db() .collection(COL.TOKEN_PURCHASE) .where('token', '==', token.uid); @@ -841,7 +731,6 @@ describe('Trade trigger', () => { const snap = await purchaseQuery.get(); return snap.length === 1; }); - const purchase = (await purchaseQuery.get())[0]; expect(purchase.count).toBe(2 * tokenCount); expect(purchase.price).toBe(MIN_IOTA_AMOUNT / 2); @@ -849,16 +738,14 @@ describe('Trade trigger', () => { expect(purchase.sellerTier).toBe(4); expect(purchase.sellerTokenTradingFeePercentage).toBe(0); } - const billPayments = ( await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.BILL_PAYMENT) - .where('payload.token', '==', token.uid) + .where('payload_token', '==', token.uid) .get() ).map((d) => d); expect(billPayments.length).toBe(1); - const billPaymentToSeller = billPayments.find( (bp) => bp.payload.amount === (MIN_IOTA_AMOUNT / 2) * (2 * tokenCount), ); @@ -867,93 +754,80 @@ describe('Trade trigger', () => { ); it('Should create royalty payments only with dust', async () => { - await build5Db().doc(`${COL.MEMBER}/${seller}`).update({ tokenTradingFeePercentage: 0 }); - mockWalletReturnValue(walletSpy, seller, { + await build5Db().doc(COL.MEMBER, seller).update({ tokenTradingFeePercentage: 0 }); + mockWalletReturnValue(seller, { symbol: token.symbol, price: MIN_IOTA_AMOUNT / 2, count: 2 * tokenCount, type: TokenTradeOrderType.SELL, }); - await testEnv.wrap(tradeToken)({}); - + await testEnv.wrap(WEN_FUNC.tradeToken); await buyTokenFunc(buyer, { symbol: token.symbol, price: MIN_IOTA_AMOUNT / 2 + 1, count: 2 * tokenCount, }); - const purchaseQuery = build5Db().collection(COL.TOKEN_PURCHASE).where('token', '==', token.uid); await wait(async () => { const snap = await purchaseQuery.get(); return snap.length === 1; }); - const purchase = (await purchaseQuery.get())[0]; expect(purchase.count).toBe(2 * tokenCount); expect(purchase.price).toBe(MIN_IOTA_AMOUNT / 2); - const billPayments = ( await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.BILL_PAYMENT) - .where('payload.token', '==', token.uid) + .where('payload_token', '==', token.uid) .get() ).map((d) => d); expect(billPayments.length).toBe(2); - const billPaymentToSeller = billPayments.find( (bp) => bp.payload.amount === (MIN_IOTA_AMOUNT / 2) * (2 * tokenCount) + 800, ); expect(billPaymentToSeller).toBeDefined(); - const billPaymentToSpaceOne = billPayments.find((bp) => bp.payload.amount === 800); expect(billPaymentToSpaceOne).toBeDefined(); }); it('Should fill buy and send dust to space one', async () => { - await build5Db().doc(`${COL.MEMBER}/${seller}`).update({ tokenTradingFeePercentage: 1 }); - mockWalletReturnValue(walletSpy, seller, { + await build5Db().doc(COL.MEMBER, seller).update({ tokenTradingFeePercentage: 1 }); + mockWalletReturnValue(seller, { symbol: token.symbol, price: MIN_IOTA_AMOUNT / 2, count: 2 * tokenCount, type: TokenTradeOrderType.SELL, }); - await testEnv.wrap(tradeToken)({}); - + await testEnv.wrap(WEN_FUNC.tradeToken); await buyTokenFunc(buyer, { symbol: token.symbol, price: MIN_IOTA_AMOUNT / 2, count: 2 * tokenCount, }); - const purchaseQuery = build5Db().collection(COL.TOKEN_PURCHASE).where('token', '==', token.uid); await wait(async () => { const snap = await purchaseQuery.get(); return snap.length === 1; }); - const purchase = (await purchaseQuery.get())[0]; expect(purchase.count).toBe(2 * tokenCount); expect(purchase.price).toBe(MIN_IOTA_AMOUNT / 2); - const billPayments = ( await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.BILL_PAYMENT) - .where('payload.token', '==', token.uid) + .where('payload_token', '==', token.uid) .get() ).map((d) => d); - const billPaymentToSpaceOne = billPayments.find( (bp) => bp.payload.amount === (MIN_IOTA_AMOUNT / 2) * (2 * tokenCount) * 0.01 * 0.1, ); expect(billPaymentToSpaceOne).toBeDefined(); - const billPaymentToSpaceTwo = billPayments.find( (bp) => bp.payload.amount === (MIN_IOTA_AMOUNT / 2) * (2 * tokenCount) * 0.01 * 0.9, ); expect(billPaymentToSpaceTwo).toBeDefined(); - const billPaymentToSeller = billPayments.find( (bp) => bp.payload.amount === @@ -970,16 +844,15 @@ describe('Trade trigger', () => { it('Should fulfill buy but only create one space bill payment', async () => { const tokenCount = 100; - mockWalletReturnValue(walletSpy, seller, { + mockWalletReturnValue(seller, { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: tokenCount, type: TokenTradeOrderType.SELL, }); - await testEnv.wrap(tradeToken)({}); + await testEnv.wrap(WEN_FUNC.tradeToken); const request = { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: tokenCount }; await buyTokenFunc(buyer, request); - await wait(async () => { return ( ( @@ -987,7 +860,7 @@ describe('Trade trigger', () => { .collection(COL.TOKEN_MARKET) .where('type', '==', TokenTradeOrderType.BUY) .where('owner', '==', buyer) - .get() + .get() )[0].status === TokenTradeOrderStatus.SETTLED ); }); @@ -1001,31 +874,25 @@ describe('Trade trigger', () => { }); it('Should cancel sell after half fulfilled', async () => { - mockWalletReturnValue(walletSpy, seller, { + mockWalletReturnValue(seller, { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: 10, type: TokenTradeOrderType.SELL, }); - const sell = await testEnv.wrap(tradeToken)({}); + const sell = await testEnv.wrap(WEN_FUNC.tradeToken); await buyTokenFunc(buyer, { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: 5 }); - await wait(async () => { return ( - ( - await build5Db() - .collection(COL.TOKEN_MARKET) - .where('owner', '==', buyer) - .get() - )[0]?.fulfilled === 5 + (await build5Db().collection(COL.TOKEN_MARKET).where('owner', '==', buyer).get())[0] + ?.fulfilled === 5 ); }); - mockWalletReturnValue(walletSpy, seller, { uid: sell.uid }); - const cancelled = await testEnv.wrap(cancelTradeOrder)({}); + mockWalletReturnValue(seller, { uid: sell.uid }); + const cancelled = await testEnv.wrap(WEN_FUNC.cancelTradeOrder); expect(cancelled.status).toBe(TokenTradeOrderStatus.PARTIALLY_SETTLED_AND_CANCELLED); - const sellDistribution = ( - await build5Db().doc(`${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${seller}`).get() + await build5Db().doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, seller).get() ); expect(sellDistribution.lockedForSale).toBe(0); expect(sellDistribution.sold).toBe(5); @@ -1033,37 +900,29 @@ describe('Trade trigger', () => { }); it('Should fulfill buy with lowest sell', async () => { - mockWalletReturnValue(walletSpy, seller, { + mockWalletReturnValue(seller, { symbol: token.symbol, price: 2 * MIN_IOTA_AMOUNT, count: 10, type: TokenTradeOrderType.SELL, }); - await testEnv.wrap(tradeToken)({}); - mockWalletReturnValue(walletSpy, seller, { + await testEnv.wrap(WEN_FUNC.tradeToken); + + mockWalletReturnValue(seller, { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: 10, type: TokenTradeOrderType.SELL, }); - await testEnv.wrap(tradeToken)({}); + await testEnv.wrap(WEN_FUNC.tradeToken); await buyTokenFunc(buyer, { symbol: token.symbol, price: 2 * MIN_IOTA_AMOUNT, count: 10 }); - await wait(async () => { return ( - ( - await build5Db() - .collection(COL.TOKEN_MARKET) - .where('owner', '==', buyer) - .get() - )[0]?.fulfilled === 10 + (await build5Db().collection(COL.TOKEN_MARKET).where('owner', '==', buyer).get())[0] + ?.fulfilled === 10 ); }); - - const buys = await build5Db() - .collection(COL.TOKEN_MARKET) - .where('owner', '==', buyer) - .get(); + const buys = await build5Db().collection(COL.TOKEN_MARKET).where('owner', '==', buyer).get(); const purchase = ( (await build5Db().collection(COL.TOKEN_PURCHASE).where('buy', '==', buys[0].uid).get())[0] ); @@ -1074,30 +933,23 @@ describe('Trade trigger', () => { await buyTokenFunc(buyer, { symbol: token.symbol, price: 2 * MIN_IOTA_AMOUNT, count: 10 }); await buyTokenFunc(buyer, { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: 10 }); await wait(async () => { - const snap = await build5Db() - .collection(COL.TOKEN_MARKET) - .where('owner', '==', buyer) - .get(); + const snap = await build5Db().collection(COL.TOKEN_MARKET).where('owner', '==', buyer).get(); const wasUpdated = snap.reduce((acc, act) => acc && !isEmpty(act.updatedOn), true); return snap.length === 2 && wasUpdated; }); - mockWalletReturnValue(walletSpy, seller, { + mockWalletReturnValue(seller, { symbol: token.symbol, price: MIN_IOTA_AMOUNT, count: 10, type: TokenTradeOrderType.SELL, }); - const sell = await testEnv.wrap(tradeToken)({}); + const sell = await testEnv.wrap(WEN_FUNC.tradeToken); await wait(async () => { return ( - ( - await build5Db() - .collection(COL.TOKEN_MARKET) - .where('owner', '==', seller) - .get() - )[0]?.fulfilled === 10 + (await build5Db().collection(COL.TOKEN_MARKET).where('owner', '==', seller).get())[0] + ?.fulfilled === 10 ); }); @@ -1108,14 +960,13 @@ describe('Trade trigger', () => { }); it('Should fulfill low price sell with high price buy', async () => { - mockWalletReturnValue(walletSpy, seller, { + mockWalletReturnValue(seller, { symbol: token.symbol, price: MIN_IOTA_AMOUNT / 2, count: 100, type: TokenTradeOrderType.SELL, }); - await testEnv.wrap(tradeToken)({}); - + await testEnv.wrap(WEN_FUNC.tradeToken); const order = await buyTokenFunc(buyer, { symbol: token.symbol, price: MIN_IOTA_AMOUNT, @@ -1126,7 +977,7 @@ describe('Trade trigger', () => { .collection(COL.TOKEN_MARKET) .where('orderTransactionId', '==', order.uid); await wait(async () => { - const buySnap = await buyQuery.get(); + const buySnap = await buyQuery.get(); return buySnap[0].fulfilled === 99; }); @@ -1135,11 +986,12 @@ describe('Trade trigger', () => { price: 2 * MIN_IOTA_AMOUNT, count: 1, }); + const buyQuery2 = build5Db() .collection(COL.TOKEN_MARKET) .where('orderTransactionId', '==', order2.uid); await wait(async () => { - const buySnap = await buyQuery2.get(); + const buySnap = await buyQuery2.get(); return buySnap[0].fulfilled === 1; }); @@ -1147,6 +999,7 @@ describe('Trade trigger', () => { const purchase = ( await build5Db().collection(COL.TOKEN_PURCHASE).where('buy', '==', buy.uid).get() )[0] as TokenPurchase; + expect(purchase.price).toBe(2 * MIN_IOTA_AMOUNT); }); }); diff --git a/packages/functions/test/controls/token.expired.sale.cron.spec.ts b/packages/functions/test/controls/token.expired.sale.cron.spec.ts index 5bfe700b00..b44ec68237 100644 --- a/packages/functions/test/controls/token.expired.sale.cron.spec.ts +++ b/packages/functions/test/controls/token.expired.sale.cron.spec.ts @@ -5,7 +5,6 @@ import { SOON_PROJECT_ID, SUB_COL, Token, - TokenDistribution, TokenStatus, TokenTradeOrder, TokenTradeOrderStatus, @@ -15,21 +14,16 @@ import dayjs from 'dayjs'; import { cancelExpiredSale } from '../../src/cron/token.cron'; import { dateToTimestamp } from '../../src/utils/dateTime.utils'; import * as wallet from '../../src/utils/wallet.utils'; -import { createMember, getRandomSymbol, wait } from './common'; - -let walletSpy: any; +import { testEnv } from '../set-up'; +import { getRandomSymbol, wait } from './common'; describe('Expired sales cron', () => { let seller: string; - let token: Token; - beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - seller = await createMember(walletSpy); - + seller = await testEnv.createMember(); const tokenId = wallet.getRandomEthAddress(); - token = { + const tokenUpsert = { project: SOON_PROJECT_ID, uid: tokenId, symbol: getRandomSymbol(), @@ -38,11 +32,10 @@ describe('Expired sales cron', () => { status: TokenStatus.PRE_MINTED, approved: true, }; - await build5Db().doc(`${COL.TOKEN}/${tokenId}`).set(token); - const distribution = { tokenOwned: 1000 }; - await build5Db() - .doc(`${COL.TOKEN}/${tokenId}/${SUB_COL.DISTRIBUTION}/${seller}`) - .set(distribution); + await build5Db().doc(COL.TOKEN, tokenId).upsert(tokenUpsert); + token = (await build5Db().doc(COL.TOKEN, tokenId).get())!; + const distribution = { tokenOwned: 1000 }; + await build5Db().doc(COL.TOKEN, tokenId, SUB_COL.DISTRIBUTION, seller).upsert(distribution); }); it('Should cancel all expired sales', async () => { @@ -71,29 +64,26 @@ describe('Expired sales cron', () => { ) => { const sells = Array.from(Array(count)).map(() => getDummySell(status, type)); const batch = build5Db().batch(); - sells.forEach((s) => batch.create(build5Db().doc(`${COL.TOKEN_MARKET}/${s.uid}`), s)); + const promises = sells.map((s) => batch.create(build5Db().doc(COL.TOKEN_MARKET, s.uid), s)); + await Promise.all(promises); await batch.commit(); return sells; }; - await createSales(TokenTradeOrderStatus.ACTIVE, TokenTradeOrderType.SELL, salesCount); await createSales(TokenTradeOrderStatus.SETTLED, TokenTradeOrderType.SELL, 3); - await wait(async () => { const snap = await build5Db() .collection(COL.TOKEN_MARKET) .where('owner', '==', seller) .where('status', '==', TokenTradeOrderStatus.ACTIVE) - .get(); + .get(); const processed = snap.reduce( (sum, act) => sum && (act).updatedOn !== undefined, true, ); return processed; }); - await cancelExpiredSale(); - const snap = await build5Db() .collection(COL.TOKEN_MARKET) .where('owner', '==', seller) diff --git a/packages/functions/test/controls/token.order.spec.ts b/packages/functions/test/controls/token.order.spec.ts index 26e2a6bbce..0756c78929 100644 --- a/packages/functions/test/controls/token.order.spec.ts +++ b/packages/functions/test/controls/token.order.spec.ts @@ -10,58 +10,43 @@ import { Token, TokenDistribution, TokenStatus, + Transaction, WEN_FUNC, WenError, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { joinSpace } from '../../src/runtime/firebase/space'; -import { creditToken, orderToken } from '../../src/runtime/firebase/token/base'; -import { dateToTimestamp, serverTime } from '../../src/utils/dateTime.utils'; +import { orderTokenControl } from '../../src/controls/token/token.order'; +import { serverTime } from '../../src/utils/dateTime.utils'; import * as wallet from '../../src/utils/wallet.utils'; -import { MEDIA, testEnv } from '../set-up'; -import { - createMember, - createSpace, - expectThrow, - getRandomSymbol, - mockIpCheck, - mockWalletReturnValue, - submitMilestoneFunc, -} from './common'; - -let walletSpy: any; +import { MEDIA, mockWalletReturnValue, testEnv } from '../set-up'; +import { expectThrow, getRandomSymbol, mockIpCheck, submitMilestoneFunc } from './common'; -const submitTokenOrderFunc = async (spy: string, address: NetworkAddress, params: T) => { - mockWalletReturnValue(spy, address, params); - const order = await testEnv.wrap(orderToken)({}); +const submitTokenOrderFunc = async (address: NetworkAddress, params: T) => { + mockWalletReturnValue(address, params); + const order = await testEnv.wrap(WEN_FUNC.orderToken); expect(order?.createdOn).toBeDefined(); return order; }; - -const submitCreditTokenFunc = async (spy: string, address: NetworkAddress, params: T) => { - mockWalletReturnValue(spy, address, params); - const order = await testEnv.wrap(creditToken)({}); +const submitCreditTokenFunc = async (address: NetworkAddress, params: T) => { + mockWalletReturnValue(address, params); + const order = await testEnv.wrap(WEN_FUNC.creditToken); expect(order?.createdOn).toBeDefined(); return order; }; - const assertOrderedTokensCount = async (tokenId: string, expected: number) => { - const token = await build5Db().doc(`${COL.TOKEN}/${tokenId}`).get(); + const token = await build5Db().doc(COL.TOKEN, tokenId).get(); expect(token.tokensOrdered).toBe(expected); }; describe('Token controller: ' + WEN_FUNC.orderToken, () => { - let memberAddress: NetworkAddress; + let member: NetworkAddress; let space: Space; let token: Token; - beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - memberAddress = await createMember(walletSpy); - space = await createSpace(walletSpy, memberAddress); - + member = await testEnv.createMember(); + space = await testEnv.createSpace(member); const tokenId = wallet.getRandomEthAddress(); - token = { + const tokenUpsert = { project: SOON_PROJECT_ID, symbol: getRandomSymbol(), totalSupply: 1000, @@ -69,233 +54,223 @@ describe('Token controller: ' + WEN_FUNC.orderToken, () => { rejected: false, icon: MEDIA, overviewGraphics: MEDIA, - updatedOn: serverTime(), - createdOn: serverTime(), + updatedOn: serverTime().toDate(), + createdOn: serverTime().toDate(), space: space.uid, uid: tokenId, pricePerToken: MIN_IOTA_AMOUNT, - allocations: [ + allocations: JSON.stringify([ { title: 'Public sale', isPublicSale: true, percentage: 50 }, { title: 'Private', percentage: 50 }, - ], - createdBy: memberAddress, + ]), + createdBy: member, name: 'MyToken', saleLength: 86400000 * 2, - saleStartDate: dateToTimestamp(dayjs().subtract(1, 'd').toDate()), + saleStartDate: dayjs().subtract(1, 'd').toDate(), links: [], status: TokenStatus.AVAILABLE, totalDeposit: 0, totalAirdropped: 0, termsAndConditions: 'https://wen.soonaverse.com/token/terms-and-conditions', - access: 0, + access: Access.OPEN, decimals: 6, }; - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).set(token); + await build5Db().doc(COL.TOKEN, tokenId).upsert(tokenUpsert); + token = (await build5Db().doc(COL.TOKEN, tokenId).get())!; }); it('Should create token order', async () => { - const order = await submitTokenOrderFunc(walletSpy, memberAddress, { token: token.uid }); + const order = await submitTokenOrderFunc(member, { token: token.uid }); await submitMilestoneFunc(order); - const distribution = await build5Db() - .doc(`${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${memberAddress}`) - .get(); + .doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, member) + .get(); expect(distribution?.totalDeposit).toBe(MIN_IOTA_AMOUNT); await assertOrderedTokensCount(token.uid, 1); }); it('Should order more token', async () => { - const order = await submitTokenOrderFunc(walletSpy, memberAddress, { token: token.uid }); + const order = await submitTokenOrderFunc(member, { token: token.uid }); await submitMilestoneFunc(order); - - const order2 = await submitTokenOrderFunc(walletSpy, memberAddress, { token: token.uid }); + const order2 = await submitTokenOrderFunc(member, { token: token.uid }); await submitMilestoneFunc(order2); - const distribution = await build5Db() - .doc(`${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${memberAddress}`) - .get(); + .doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, member) + .get(); expect(distribution?.totalDeposit).toBe(MIN_IOTA_AMOUNT * 2); await assertOrderedTokensCount(token.uid, 2); }); it('Should create token order and should credit some amount', async () => { for (const _ of [0, 1]) { - const order = await submitTokenOrderFunc(walletSpy, memberAddress, { token: token.uid }); + const order = await submitTokenOrderFunc(member, { token: token.uid }); await submitMilestoneFunc(order); } - const distribution = await build5Db() - .doc(`${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${memberAddress}`) - .get(); + .doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, member) + .get(); expect(distribution?.totalDeposit).toBe(MIN_IOTA_AMOUNT * 2); - await build5Db() - .doc(`${COL.TOKEN}/${token.uid}`) + .doc(COL.TOKEN, token.uid) .update({ - saleStartDate: dateToTimestamp(dayjs().subtract(3, 'd').toDate()), - coolDownEnd: dateToTimestamp(dayjs().add(1, 'd').toDate()), + saleStartDate: dayjs().subtract(3, 'd').toDate(), + coolDownEnd: dayjs().add(1, 'd').toDate(), }); - - await submitCreditTokenFunc(walletSpy, memberAddress, { - token: token.uid, - amount: MIN_IOTA_AMOUNT, - }); - + await submitCreditTokenFunc(member, { token: token.uid, amount: MIN_IOTA_AMOUNT }); const updatedDistribution = await build5Db() - .doc(`${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${memberAddress}`) - .get(); + .doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, member) + .get(); expect(updatedDistribution?.totalDeposit).toBe(MIN_IOTA_AMOUNT); - - const updatedToken = await build5Db().doc(`${COL.TOKEN}/${token.uid}`).get(); + const updatedToken = await build5Db().doc(COL.TOKEN, token.uid).get(); expect(updatedToken?.totalDeposit).toBe(MIN_IOTA_AMOUNT); - await assertOrderedTokensCount(token.uid, 1); }); it('Should create token order and should credit all amount', async () => { - const order = await submitTokenOrderFunc(walletSpy, memberAddress, { token: token.uid }); + const order = await submitTokenOrderFunc(member, { token: token.uid }); await submitMilestoneFunc(order); - const distribution = await build5Db() - .doc(`${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${memberAddress}`) - .get(); + .doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, member) + .get(); expect(distribution?.totalDeposit).toBe(MIN_IOTA_AMOUNT); - await build5Db() - .doc(`${COL.TOKEN}/${token.uid}`) + .doc(COL.TOKEN, token.uid) .update({ - saleStartDate: dateToTimestamp(dayjs().subtract(3, 'd').toDate()), - coolDownEnd: dateToTimestamp(dayjs().add(1, 'd').toDate()), + saleStartDate: dayjs().subtract(3, 'd').toDate(), + coolDownEnd: dayjs().add(1, 'd').toDate(), }); - - await submitCreditTokenFunc(walletSpy, memberAddress, { - token: token.uid, - amount: MIN_IOTA_AMOUNT, - }); - + await submitCreditTokenFunc(member, { token: token.uid, amount: MIN_IOTA_AMOUNT }); const updatedDistribution = await build5Db() - .doc(`${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${memberAddress}`) - .get(); + .doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, member) + .get(); expect(updatedDistribution?.totalDeposit).toBe(0); - - const updatedToken = await build5Db().doc(`${COL.TOKEN}/${token.uid}`).get(); + const updatedToken = await build5Db().doc(COL.TOKEN, token.uid).get(); expect(updatedToken?.totalDeposit).toBe(0); await assertOrderedTokensCount(token.uid, 0); }); it('Should create token order and should fail credit, not in cool down period', async () => { - const order = await submitTokenOrderFunc(walletSpy, memberAddress, { token: token.uid }); + const order = await submitTokenOrderFunc(member, { token: token.uid }); await submitMilestoneFunc(order); - await build5Db() - .doc(`${COL.TOKEN}/${token.uid}`) + .doc(COL.TOKEN, token.uid) .update({ - saleStartDate: dateToTimestamp(dayjs().subtract(3, 'd').toDate()), - coolDownEnd: dateToTimestamp(dayjs().subtract(1, 'm').toDate()), + saleStartDate: dayjs().subtract(3, 'd').toDate(), + coolDownEnd: dayjs().subtract(1, 'm').toDate(), }); - - mockWalletReturnValue(walletSpy, memberAddress, { token: token.uid, amount: MIN_IOTA_AMOUNT }); - await expectThrow(testEnv.wrap(creditToken)({}), WenError.token_not_in_cool_down_period.key); + mockWalletReturnValue(member, { token: token.uid, amount: MIN_IOTA_AMOUNT }); + await expectThrow( + testEnv.wrap(WEN_FUNC.creditToken), + WenError.token_not_in_cool_down_period.key, + ); }); it('Should throw, amount too much to refund', async () => { - const order = await submitTokenOrderFunc(walletSpy, memberAddress, { token: token.uid }); + const order = await submitTokenOrderFunc(member, { token: token.uid }); await submitMilestoneFunc(order); - const distribution = await build5Db() - .doc(`${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${memberAddress}`) - .get(); + .doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, member) + .get(); expect(distribution?.totalDeposit).toBe(token.pricePerToken); - - mockWalletReturnValue(walletSpy, memberAddress, { + mockWalletReturnValue(member, { token: token.uid, amount: MIN_IOTA_AMOUNT * 4, }); - await expectThrow(testEnv.wrap(creditToken)({}), WenError.not_enough_funds.key); + await expectThrow(testEnv.wrap(WEN_FUNC.creditToken), WenError.not_enough_funds.key); }); it('Should throw, amount too much to refund after second credit', async () => { - const order = await submitTokenOrderFunc(walletSpy, memberAddress, { token: token.uid }); + const order = await submitTokenOrderFunc(member, { token: token.uid }); await submitMilestoneFunc(order); - await build5Db() - .doc(`${COL.TOKEN}/${token.uid}`) + .doc(COL.TOKEN, token.uid) .update({ - saleStartDate: dateToTimestamp(dayjs().subtract(3, 'd').toDate()), - coolDownEnd: dateToTimestamp(dayjs().add(1, 'd').toDate()), + saleStartDate: dayjs().subtract(3, 'd').toDate(), + coolDownEnd: dayjs().add(1, 'd').toDate(), }); - - mockWalletReturnValue(walletSpy, memberAddress, { + mockWalletReturnValue(member, { token: token.uid, amount: token.pricePerToken, }); - await testEnv.wrap(creditToken)({}); - - mockWalletReturnValue(walletSpy, memberAddress, { + await testEnv.wrap(WEN_FUNC.creditToken); + mockWalletReturnValue(member, { token: token.uid, amount: token.pricePerToken, }); - await expectThrow(testEnv.wrap(creditToken)({}), WenError.not_enough_funds.key); + await expectThrow(testEnv.wrap(WEN_FUNC.creditToken), WenError.not_enough_funds.key); }); it('Should allow only for members', async () => { - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).update({ access: Access.MEMBERS_ONLY }); - mockWalletReturnValue(walletSpy, memberAddress, { token: token.uid }); - await testEnv.wrap(orderToken)({}); - const newMember = await createMember(walletSpy); - mockWalletReturnValue(walletSpy, newMember, { token: token.uid }); - await expectThrow(testEnv.wrap(orderToken)({}), WenError.you_are_not_part_of_space.key); + await build5Db().doc(COL.TOKEN, token.uid).update({ access: Access.MEMBERS_ONLY }); + mockWalletReturnValue(member, { token: token.uid }); + await testEnv.wrap(WEN_FUNC.orderToken); + const newMember = await testEnv.createMember(); + mockWalletReturnValue(newMember, { token: token.uid }); + await expectThrow( + testEnv.wrap(WEN_FUNC.orderToken), + WenError.you_are_not_part_of_space.key, + ); }); it('Should allow only for guardians', async () => { - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).update({ access: Access.GUARDIANS_ONLY }); - - const newMember = await createMember(walletSpy); - mockWalletReturnValue(walletSpy, newMember, { uid: space.uid }); - await testEnv.wrap(joinSpace)({}); - - mockWalletReturnValue(walletSpy, memberAddress, { token: token.uid }); - await testEnv.wrap(orderToken)({}); - - mockWalletReturnValue(walletSpy, newMember, { token: token.uid }); - await expectThrow(testEnv.wrap(orderToken)({}), WenError.you_are_not_guardian_of_space.key); + await build5Db().doc(COL.TOKEN, token.uid).update({ access: Access.GUARDIANS_ONLY }); + const newMember = await testEnv.createMember(); + mockWalletReturnValue(newMember, { uid: space.uid }); + await testEnv.wrap(WEN_FUNC.joinSpace); + mockWalletReturnValue(member, { token: token.uid }); + await testEnv.wrap(WEN_FUNC.orderToken); + + mockWalletReturnValue(newMember, { token: token.uid }); + await expectThrow( + testEnv.wrap(WEN_FUNC.orderToken), + WenError.you_are_not_guardian_of_space.key, + ); }); it('Should throw, no badge so can not access', async () => { await build5Db() - .doc(`${COL.TOKEN}/${token.uid}`) - .update({ access: Access.MEMBERS_WITH_BADGE, accessAwards: [wallet.getRandomEthAddress()] }); - mockWalletReturnValue(walletSpy, memberAddress, { token: token.uid }); - await expectThrow(testEnv.wrap(orderToken)({}), WenError.you_dont_have_required_badge.key); + .doc(COL.TOKEN, token.uid) + .update({ + access: Access.MEMBERS_WITH_BADGE, + accessAwards: [wallet.getRandomEthAddress()], + }); + + mockWalletReturnValue(member, { token: token.uid }); + await expectThrow( + testEnv.wrap(WEN_FUNC.orderToken), + WenError.you_dont_have_required_badge.key, + ); }); it('Should throw, no nft so can not access', async () => { await build5Db() - .doc(`${COL.TOKEN}/${token.uid}`) + .doc(COL.TOKEN, token.uid) .update({ access: Access.MEMBERS_WITH_NFT_FROM_COLLECTION, accessCollections: [wallet.getRandomEthAddress()], }); - mockWalletReturnValue(walletSpy, memberAddress, { token: token.uid }); - await expectThrow(testEnv.wrap(orderToken)({}), WenError.you_dont_have_required_NFTs.key); + + mockWalletReturnValue(member, { token: token.uid }); + await expectThrow( + testEnv.wrap(WEN_FUNC.orderToken), + WenError.you_dont_have_required_NFTs.key, + ); }); + it('Should create token order and should credit, not leave less then MIN amount', async () => { - const order = await submitTokenOrderFunc(walletSpy, memberAddress, { token: token.uid }); + const order = await submitTokenOrderFunc(member, { token: token.uid }); await submitMilestoneFunc(order, 1.5 * MIN_IOTA_AMOUNT); - const distribution = await build5Db() - .doc(`${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${memberAddress}`) - .get(); + .doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, member) + .get(); expect(distribution?.totalDeposit).toBe(1.5 * MIN_IOTA_AMOUNT); - await build5Db() - .doc(`${COL.TOKEN}/${token.uid}`) + .doc(COL.TOKEN, token.uid) .update({ - saleStartDate: dateToTimestamp(dayjs().subtract(3, 'd').toDate()), - coolDownEnd: dateToTimestamp(dayjs().add(1, 'd').toDate()), + saleStartDate: dayjs().subtract(3, 'd').toDate(), + coolDownEnd: dayjs().add(1, 'd').toDate(), }); - - const credit = await submitCreditTokenFunc(walletSpy, memberAddress, { + const credit = await submitCreditTokenFunc(member, { token: token.uid, amount: MIN_IOTA_AMOUNT, }); @@ -304,17 +279,14 @@ describe('Token controller: ' + WEN_FUNC.orderToken, () => { it('Should create order and deposit in parallel', async () => { const array = Array.from(Array(10)); - const order = await submitTokenOrderFunc(walletSpy, memberAddress, { token: token.uid }); + const order = await submitTokenOrderFunc(member, { token: token.uid }); const amounts = array.map((_, index) => (index + 1) * MIN_IOTA_AMOUNT); const total = array.reduce((sum, _, index) => sum + (index + 1) * MIN_IOTA_AMOUNT, 0); const deposit = async (amount: number) => submitMilestoneFunc(order, amount); - const promises = amounts.map(deposit); await Promise.all(promises); const distribution = ( - await build5Db() - .doc(`${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${memberAddress}`) - .get() + await build5Db().doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, member).get() ); expect(distribution.totalDeposit).toBe(total); await assertOrderedTokensCount(token.uid, total / MIN_IOTA_AMOUNT); @@ -322,25 +294,25 @@ describe('Token controller: ' + WEN_FUNC.orderToken, () => { it('Should fail, country blocked by default', async () => { mockIpCheck(true, { common: ['HU'] }, { countryCode: 'HU' }); - await expectThrow( - submitTokenOrderFunc(walletSpy, memberAddress, { token: token.uid }), - WenError.blocked_country.key, - ); + + mockWalletReturnValue(member, { token: token.uid }); + const call = testEnv.mockWrap(orderTokenControl); + await expectThrow(call, WenError.blocked_country.key); }); it('Should fail, country blocked for entity', async () => { mockIpCheck(true, { common: ['USA'], [token.uid]: ['USA', 'HU'] }, { countryCode: 'HU' }); - await expectThrow( - submitTokenOrderFunc(walletSpy, memberAddress, { token: token.uid }), - WenError.blocked_country.key, - ); + + mockWalletReturnValue(member, { token: token.uid }); + const call = testEnv.mockWrap(orderTokenControl); + await expectThrow(call, WenError.blocked_country.key); }); it('Should fail, country blocked for token', async () => { mockIpCheck(true, { common: ['USA'], token: ['HU'] }, { countryCode: 'HU' }); - await expectThrow( - submitTokenOrderFunc(walletSpy, memberAddress, { token: token.uid }), - WenError.blocked_country.key, - ); + + mockWalletReturnValue(member, { token: token.uid }); + const call = testEnv.mockWrap(orderTokenControl); + await expectThrow(call, WenError.blocked_country.key); }); }); diff --git a/packages/functions/test/controls/token/token.airdrop.claim.spec.ts b/packages/functions/test/controls/token/token.airdrop.claim.spec.ts index a89d268c92..31746fd146 100644 --- a/packages/functions/test/controls/token/token.airdrop.claim.spec.ts +++ b/packages/functions/test/controls/token/token.airdrop.claim.spec.ts @@ -1,38 +1,23 @@ import { build5Db } from '@build-5/database'; import { + Access, COL, SUB_COL, Space, Token, TokenAllocation, - TokenDistribution, TokenDrop, TokenDropStatus, TokenStatus, Transaction, TransactionPayloadType, TransactionType, + WEN_FUNC, WenError, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { - airdropToken, - claimAirdroppedToken, - createToken, -} from '../../../src/runtime/firebase/token/base'; -import * as wallet from '../../../src/utils/wallet.utils'; -import { MEDIA, testEnv } from '../../set-up'; -import { - createMember, - createSpace, - expectThrow, - getRandomSymbol, - mockWalletReturnValue, - submitMilestoneFunc, - wait, -} from '../common'; - -let walletSpy: any; +import { MEDIA, mockWalletReturnValue, testEnv } from '../../set-up'; +import { expectThrow, getRandomSymbol, submitMilestoneFunc, wait } from '../common'; const dummyToken = (space: string) => ({ @@ -44,7 +29,7 @@ const dummyToken = (space: string) => icon: MEDIA, overviewGraphics: MEDIA, termsAndConditions: 'https://wen.soonaverse.com/token/terms-and-conditions', - access: 0, + access: Access.OPEN, decimals: 6, }) as any; @@ -61,9 +46,8 @@ describe('Claim airdropped token test', () => { let token: Token; beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - guardian = await createMember(walletSpy); - space = await createSpace(walletSpy, guardian); + guardian = await testEnv.createMember(); + space = await testEnv.createSpace(guardian); const dummyTokenData = dummyToken(space.uid); dummyTokenData.saleStartDate = dayjs().add(8, 'day').toDate(); dummyTokenData.saleLength = 86400000; @@ -72,9 +56,9 @@ describe('Claim airdropped token test', () => { { title: 'Private', percentage: 90 }, { title: 'Public', percentage: 10, isPublicSale: true }, ]; - mockWalletReturnValue(walletSpy, guardian, dummyTokenData); - token = await testEnv.wrap(createToken)({}); - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).update({ approved: true }); + mockWalletReturnValue(guardian, dummyTokenData); + token = await testEnv.wrap(WEN_FUNC.createToken); + await build5Db().doc(COL.TOKEN, token.uid).update({ approved: true }); }); const airdrop = async () => { @@ -82,17 +66,17 @@ describe('Claim airdropped token test', () => { token: token.uid, drops: [{ count: 450, recipient: guardian, vestingAt: dayjs().toDate() }], }; - mockWalletReturnValue(walletSpy, guardian, airdropRequest); - await testEnv.wrap(airdropToken)({}); + mockWalletReturnValue(guardian, airdropRequest); + await testEnv.wrap(WEN_FUNC.airdropToken); }; it('Should claim token', async () => { await airdrop(); - mockWalletReturnValue(walletSpy, guardian, { token: token.uid }); - const order = await testEnv.wrap(claimAirdroppedToken)({}); + mockWalletReturnValue(guardian, { token: token.uid }); + const order = await testEnv.wrap(WEN_FUNC.claimAirdroppedToken); await submitMilestoneFunc(order); - const orderTran = await build5Db().doc(`${COL.TRANSACTION}/${order.uid}`).get(); + const orderTran = await build5Db().doc(COL.TRANSACTION, order.uid).get(); expect(orderTran.member).toBe(guardian); expect(orderTran.payload.type).toBe(TransactionPayloadType.TOKEN_AIRDROP); @@ -100,15 +84,13 @@ describe('Claim airdropped token test', () => { const paymentsSnap = await build5Db() .collection(COL.TRANSACTION) - .where('payload.sourceTransaction', 'array-contains', orderTran.uid) - .get(); + .where('payload_sourceTransaction', 'array-contains', orderTran.uid! as any) + .get(); const types = paymentsSnap.map((d) => d.type).sort(); expect(types).toEqual([TransactionType.BILL_PAYMENT, TransactionType.PAYMENT]); - const distirbutionDocRef = build5Db().doc( - `${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${guardian}`, - ); - const distribution = await distirbutionDocRef.get(); + const distirbutionDocRef = build5Db().doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, guardian); + const distribution = await distirbutionDocRef.get(); expect(distribution?.tokenClaimed).toBe(450); expect(distribution?.tokenOwned).toBe(450); @@ -120,12 +102,11 @@ describe('Claim airdropped token test', () => { it('Should claim multiple drops token', async () => { await airdrop(); await airdrop(); - - mockWalletReturnValue(walletSpy, guardian, { token: token.uid }); - const order = await testEnv.wrap(claimAirdroppedToken)({}); + mockWalletReturnValue(guardian, { token: token.uid }); + const order = await testEnv.wrap(WEN_FUNC.claimAirdroppedToken); await submitMilestoneFunc(order); - const orderTran = await build5Db().doc(`${COL.TRANSACTION}/${order.uid}`).get(); + const orderTran = await build5Db().doc(COL.TRANSACTION, order.uid).get(); expect(orderTran.member).toBe(guardian); expect(orderTran.payload.type).toBe(TransactionPayloadType.TOKEN_AIRDROP); @@ -133,22 +114,18 @@ describe('Claim airdropped token test', () => { const paymentsSnap = await build5Db() .collection(COL.TRANSACTION) - .where('payload.sourceTransaction', 'array-contains', orderTran.uid) - .get(); + .where('payload_sourceTransaction', 'array-contains', orderTran.uid as any) + .get(); const types = paymentsSnap.map((d) => d.type).sort(); expect(types).toEqual([ TransactionType.BILL_PAYMENT, TransactionType.BILL_PAYMENT, TransactionType.PAYMENT, ]); - - const distirbutionDocRef = build5Db().doc( - `${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${guardian}`, - ); - const distribution = await distirbutionDocRef.get(); + const distirbutionDocRef = build5Db().doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, guardian); + const distribution = await distirbutionDocRef.get(); expect(distribution?.tokenClaimed).toBe(900); expect(distribution?.tokenOwned).toBe(900); - const airdrops = await getAirdropsForToken(token.uid); expect(airdrops.length).toBe(2); expect(airdrops[0].status).toBe(TokenDropStatus.CLAIMED); @@ -161,38 +138,32 @@ describe('Claim airdropped token test', () => { token: token.uid, drops: [{ count: 450, recipient: guardian, vestingAt: dayjs().add(1, 'd').toDate() }], }; - mockWalletReturnValue(walletSpy, guardian, airdropRequest); - await testEnv.wrap(airdropToken)({}); - - mockWalletReturnValue(walletSpy, guardian, { token: token.uid }); - const order = await testEnv.wrap(claimAirdroppedToken)({}); + mockWalletReturnValue(guardian, airdropRequest); + await testEnv.wrap(WEN_FUNC.airdropToken); + mockWalletReturnValue(guardian, { token: token.uid }); + const order = await testEnv.wrap(WEN_FUNC.claimAirdroppedToken); await submitMilestoneFunc(order); - - const orderTran = await build5Db().doc(`${COL.TRANSACTION}/${order.uid}`).get(); + const orderTran = await build5Db().doc(COL.TRANSACTION, order.uid).get(); expect(orderTran.member).toBe(guardian); expect(orderTran.payload.type).toBe(TransactionPayloadType.TOKEN_AIRDROP); await waitAllClaimed(token.uid, 1); - const paymentsSnap = await build5Db() .collection(COL.TRANSACTION) - .where('payload.sourceTransaction', 'array-contains', orderTran.uid) - .get(); + .where('payload_sourceTransaction', 'array-contains', orderTran.uid as any) + .get(); const types = paymentsSnap.map((d) => d.type).sort(); expect(types).toEqual([TransactionType.BILL_PAYMENT, TransactionType.PAYMENT]); - - const distirbutionDocRef = build5Db().doc( - `${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${guardian}`, - ); - const distribution = await distirbutionDocRef.get(); + const distirbutionDocRef = build5Db().doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, guardian); + const distribution = await distirbutionDocRef.get(); expect(distribution?.tokenClaimed).toBe(450); expect(distribution?.tokenOwned).toBe(450); }); it('Should claim same in parallel', async () => { await airdrop(); - mockWalletReturnValue(walletSpy, guardian, { token: token.uid }); const claimToken = async () => { - const order = await testEnv.wrap(claimAirdroppedToken)({}); + mockWalletReturnValue(guardian, { token: token.uid }); + const order = await testEnv.wrap(WEN_FUNC.claimAirdroppedToken); await new Promise((r) => setTimeout(r, 1000)); await submitMilestoneFunc(order); return order; @@ -200,28 +171,23 @@ describe('Claim airdropped token test', () => { const promises = [claimToken(), claimToken()]; await Promise.all(promises); await waitAllClaimed(token.uid); - - const distirbutionDocRef = build5Db().doc( - `${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${guardian}`, - ); - const distribution = await distirbutionDocRef.get(); + const distirbutionDocRef = build5Db().doc(COL.TOKEN, token.uid, SUB_COL.DISTRIBUTION, guardian); + const distribution = await distirbutionDocRef.get(); expect(distribution?.tokenClaimed).toBe(450); expect(distribution?.tokenOwned).toBe(450); - const creditSnap = await build5Db() .collection(COL.TRANSACTION) .where('member', '==', guardian) .where('type', '==', TransactionType.CREDIT) - .where('payload.token', '==', token.uid) + .where('payload_token', '==', token.uid) .get(); expect(creditSnap.length).toBe(2); - const billPaymentSnap = await build5Db() .collection(COL.TRANSACTION) .where('member', '==', guardian) .where('type', '==', TransactionType.BILL_PAYMENT) - .where('payload.token', '==', token.uid) - .get(); + .where('payload_token', '==', token.uid) + .get(); expect(billPaymentSnap.length).toBe(1); const billPayment = billPaymentSnap[0]!; expect(billPayment.payload.token).toBe(token.uid); @@ -230,9 +196,12 @@ describe('Claim airdropped token test', () => { }); it('Should throw, token is minted', async () => { - mockWalletReturnValue(walletSpy, guardian, { token: token.uid }); - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).update({ status: TokenStatus.MINTED }); - await expectThrow(testEnv.wrap(claimAirdroppedToken)({}), WenError.token_in_invalid_status.key); + await build5Db().doc(COL.TOKEN, token.uid).update({ status: TokenStatus.MINTED }); + mockWalletReturnValue(guardian, { token: token.uid }); + await expectThrow( + testEnv.wrap(WEN_FUNC.claimAirdroppedToken), + WenError.token_in_invalid_status.key, + ); }); it('Should claim 700', async () => { @@ -246,14 +215,12 @@ describe('Claim airdropped token test', () => { .toDate(), })), }; - mockWalletReturnValue(walletSpy, guardian, airdropRequest); - await testEnv.wrap(airdropToken)({}); - - mockWalletReturnValue(walletSpy, guardian, { token: token.uid }); - const order = await testEnv.wrap(claimAirdroppedToken)({}); + mockWalletReturnValue(guardian, airdropRequest); + await testEnv.wrap(WEN_FUNC.airdropToken); + mockWalletReturnValue(guardian, { token: token.uid }); + const order = await testEnv.wrap(WEN_FUNC.claimAirdroppedToken); await submitMilestoneFunc(order); - - const orderTran = await build5Db().doc(`${COL.TRANSACTION}/${order.uid}`).get(); + const orderTran = await build5Db().doc(COL.TRANSACTION, order.uid).get(); expect(orderTran.member).toBe(guardian); expect(orderTran.payload.type).toBe(TransactionPayloadType.TOKEN_AIRDROP); await waitAllClaimed(token.uid, 700); diff --git a/packages/functions/test/controls/token/token.airdrop.spec.ts b/packages/functions/test/controls/token/token.airdrop.spec.ts index dfaedf359a..236df3dec6 100644 --- a/packages/functions/test/controls/token/token.airdrop.spec.ts +++ b/packages/functions/test/controls/token/token.airdrop.spec.ts @@ -6,22 +6,12 @@ import { TokenAllocation, TokenDrop, TokenDropStatus, + WEN_FUNC, WenError, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { airdropToken, createToken } from '../../../src/runtime/firebase/token/base'; -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, - getRandomSymbol, - mockWalletReturnValue, -} from '../common'; - -let walletSpy: any; +import { MEDIA, mockWalletReturnValue, testEnv } from '../../set-up'; +import { expectThrow, getRandomSymbol } from '../common'; const dummyToken = (space: string) => ({ @@ -44,9 +34,8 @@ describe('Token airdrop test', () => { let token: Token; beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - guardian = await createMember(walletSpy); - space = await createSpace(walletSpy, guardian); + guardian = await testEnv.createMember(); + space = await testEnv.createSpace(guardian); const dummyTokenData = dummyToken(space.uid); dummyTokenData.saleStartDate = dayjs().add(8, 'day').toDate(); dummyTokenData.saleLength = 86400000; @@ -55,20 +44,20 @@ describe('Token airdrop test', () => { { title: 'Private', percentage: 90 }, { title: 'Public', percentage: 10, isPublicSale: true }, ]; - mockWalletReturnValue(walletSpy, guardian, dummyTokenData); - token = await testEnv.wrap(createToken)({}); - member = await createMember(walletSpy); - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).update({ approved: true }); + mockWalletReturnValue(guardian, dummyTokenData); + token = await testEnv.wrap(WEN_FUNC.createToken); + member = await testEnv.createMember(); + await build5Db().doc(COL.TOKEN, token.uid).update({ approved: true }); }); it('Should fail, token not approved', async () => { - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).update({ approved: false }); + await build5Db().doc(COL.TOKEN, token.uid).update({ approved: false }); const airdropRequest = { token: token.uid, drops: [{ count: 900, recipient: guardian, vestingAt: dayjs().toDate() }], }; - mockWalletReturnValue(walletSpy, guardian, airdropRequest); - await expectThrow(testEnv.wrap(airdropToken)({}), WenError.token_not_approved.key); + mockWalletReturnValue(guardian, airdropRequest); + await expectThrow(testEnv.wrap(WEN_FUNC.airdropToken), WenError.token_not_approved.key); }); it('Should airdrop token', async () => { @@ -77,13 +66,12 @@ describe('Token airdrop test', () => { token: token.uid, drops: [{ count: 900, recipient: guardian, vestingAt }], }; - mockWalletReturnValue(walletSpy, guardian, airdropRequest); - await testEnv.wrap(airdropToken)({}); - + mockWalletReturnValue(guardian, airdropRequest); + await testEnv.wrap(WEN_FUNC.airdropToken); const airdrops = await getAirdropsForMember(guardian); expect(airdrops.length).toBe(1); expect(airdrops[0].count).toBe(900); - expect(airdrops[0].vestingAt).toEqual(dateToTimestamp(vestingAt)); + expect(airdrops[0].vestingAt.toDate()).toEqual(vestingAt); expect(airdrops[0].member).toBe(guardian); expect(airdrops[0].token).toBe(token.uid); expect(airdrops[0].createdBy).toBe(guardian); @@ -91,26 +79,24 @@ describe('Token airdrop test', () => { }); it('Should airdrop token with no space', async () => { - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).update({ space: '' }); + await build5Db().doc(COL.TOKEN, token.uid).update({ space: '' }); const vestingAt = dayjs().toDate(); const airdropRequest = { token: token.uid, drops: [{ count: 900, recipient: guardian, vestingAt }], }; - mockWalletReturnValue(walletSpy, member, airdropRequest); + mockWalletReturnValue(member, airdropRequest); await expectThrow( - testEnv.wrap(airdropToken)({}), + testEnv.wrap(WEN_FUNC.airdropToken), WenError.you_must_be_the_creator_of_this_token.key, ); - - mockWalletReturnValue(walletSpy, guardian, airdropRequest); - await testEnv.wrap(airdropToken)({}); - + mockWalletReturnValue(guardian, airdropRequest); + await testEnv.wrap(WEN_FUNC.airdropToken); const airdrops = await getAirdropsForMember(guardian); expect(airdrops.length).toBe(1); expect(airdrops[0].count).toBe(900); - expect(airdrops[0].vestingAt).toEqual(dateToTimestamp(vestingAt)); + expect(airdrops[0].vestingAt.toDate()).toEqual(vestingAt); expect(airdrops[0].member).toBe(guardian); expect(airdrops[0].token).toBe(token.uid); expect(airdrops[0].createdBy).toBe(guardian); @@ -123,9 +109,8 @@ describe('Token airdrop test', () => { token: token.uid, drops: Array.from(Array(900)).map(() => ({ count: 1, recipient: guardian, vestingAt })), }; - mockWalletReturnValue(walletSpy, guardian, airdropRequest); - await testEnv.wrap(airdropToken)({}); - + mockWalletReturnValue(guardian, airdropRequest); + await testEnv.wrap(WEN_FUNC.airdropToken); const airdrops = await getAirdropsForMember(guardian); expect(airdrops.length).toBe(900); }); @@ -139,16 +124,15 @@ describe('Token airdrop test', () => { { count: 100, recipient: member, vestingAt }, ], }; - mockWalletReturnValue(walletSpy, guardian, airdropRequest); - await testEnv.wrap(airdropToken)({}); - + mockWalletReturnValue(guardian, airdropRequest); + await testEnv.wrap(WEN_FUNC.airdropToken); const airdrops = (await getAirdropsForToken(token.uid)).sort((a, b) => b.count - a.count); expect(airdrops.length).toBe(2); expect(airdrops[0].count).toBe(800); - expect(airdrops[0].vestingAt).toEqual(dateToTimestamp(vestingAt)); + expect(airdrops[0].vestingAt.toDate()).toEqual(vestingAt); expect(airdrops[0].member).toBe(guardian); expect(airdrops[1].count).toBe(100); - expect(airdrops[1].vestingAt).toEqual(dateToTimestamp(vestingAt)); + expect(airdrops[1].vestingAt.toDate()).toEqual(vestingAt); expect(airdrops[1].member).toBe(member); }); @@ -157,17 +141,18 @@ describe('Token airdrop test', () => { token: token.uid, drops: [{ count: 1000, recipient: guardian, vestingAt: dayjs().toDate() }], }; - mockWalletReturnValue(walletSpy, guardian, airdropRequest); - await expectThrow(testEnv.wrap(airdropToken)({}), WenError.no_tokens_available_for_airdrop.key); + + mockWalletReturnValue(guardian, airdropRequest); + await expectThrow( + testEnv.wrap(WEN_FUNC.airdropToken), + WenError.no_tokens_available_for_airdrop.key, + ); }); it('Should throw, no vesting', async () => { - const airdropRequest = { - token: token.uid, - drops: [{ count: 1000, recipient: guardian }], - }; - mockWalletReturnValue(walletSpy, guardian, airdropRequest); - await expectThrow(testEnv.wrap(airdropToken)({}), WenError.invalid_params.key); + const airdropRequest = { token: token.uid, drops: [{ count: 1000, recipient: guardian }] }; + mockWalletReturnValue(guardian, airdropRequest); + await expectThrow(testEnv.wrap(WEN_FUNC.airdropToken), WenError.invalid_params.key); }); it('Should throw, not guardian', async () => { @@ -175,8 +160,12 @@ describe('Token airdrop test', () => { token: token.uid, drops: [{ count: 50, recipient: guardian, vestingAt: dayjs().toDate() }], }; - mockWalletReturnValue(walletSpy, member, airdropRequest); - await expectThrow(testEnv.wrap(airdropToken)({}), WenError.you_are_not_guardian_of_space.key); + + mockWalletReturnValue(member, airdropRequest); + await expectThrow( + testEnv.wrap(WEN_FUNC.airdropToken), + WenError.you_are_not_guardian_of_space.key, + ); }); it('Should throw at second drop', async () => { @@ -185,20 +174,23 @@ describe('Token airdrop test', () => { token: token.uid, drops: [{ count: 900, recipient: guardian, vestingAt: vestingAt.toDate() }], }; - mockWalletReturnValue(walletSpy, guardian, airdropRequest); - await testEnv.wrap(airdropToken)({}); + mockWalletReturnValue(guardian, airdropRequest); + await testEnv.wrap(WEN_FUNC.airdropToken); const airdrops = await getAirdropsForMember(guardian); expect(airdrops.length).toBe(1); expect(airdrops[0].count).toBe(900); - expect(airdrops[0].vestingAt).toEqual(dateToTimestamp(vestingAt)); + expect(airdrops[0].vestingAt.toDate()).toEqual(vestingAt.toDate()); expect(airdrops[0].member).toBe(guardian); - const airdropRequest2 = { token: token.uid, drops: [{ count: 100, recipient: guardian, vestingAt: dayjs().toDate() }], }; - mockWalletReturnValue(walletSpy, guardian, airdropRequest2); - await expectThrow(testEnv.wrap(airdropToken)({}), WenError.no_tokens_available_for_airdrop.key); + + mockWalletReturnValue(guardian, airdropRequest2); + await expectThrow( + testEnv.wrap(WEN_FUNC.airdropToken), + WenError.no_tokens_available_for_airdrop.key, + ); }); it('Should drop multiple for same user', async () => { @@ -210,10 +202,10 @@ describe('Token airdrop test', () => { { count: 50, recipient: member, vestingAt }, ], }; - mockWalletReturnValue(walletSpy, guardian, airdropRequest); - await testEnv.wrap(airdropToken)({}); - await testEnv.wrap(airdropToken)({}); - + mockWalletReturnValue(guardian, airdropRequest); + await testEnv.wrap(WEN_FUNC.airdropToken); + mockWalletReturnValue(guardian, airdropRequest); + await testEnv.wrap(WEN_FUNC.airdropToken); const guardianDrops = await getAirdropsForMember(guardian); expect(guardianDrops.length).toBe(2); const memberDrops = await getAirdropsForMember(member); diff --git a/packages/functions/test/controls/token/token.cancel.pub.sale.spec.ts b/packages/functions/test/controls/token/token.cancel.pub.sale.spec.ts index a7a92e1847..80542dc8b5 100644 --- a/packages/functions/test/controls/token/token.cancel.pub.sale.spec.ts +++ b/packages/functions/test/controls/token/token.cancel.pub.sale.spec.ts @@ -1,11 +1,12 @@ import { build5Db } from '@build-5/database'; import { + Access, COL, MIN_IOTA_AMOUNT, NetworkAddress, SOON_PROJECT_ID, - Space, SUB_COL, + Space, Token, TokenDistribution, TokenStatus, @@ -15,60 +16,44 @@ import { WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { - cancelPublicSale, - orderToken, - setTokenAvailableForSale, -} from '../../../src/runtime/firebase/token/base/index'; import { dateToTimestamp, serverTime } from '../../../src/utils/dateTime.utils'; import * as wallet from '../../../src/utils/wallet.utils'; -import { MEDIA, testEnv } from '../../set-up'; -import { - createMember, - createSpace, - getRandomSymbol, - mockWalletReturnValue, - submitMilestoneFunc, - wait, -} from '../common'; - -let walletSpy: any; +import { MEDIA, mockWalletReturnValue, testEnv } from '../../set-up'; +import { getRandomSymbol, submitMilestoneFunc, wait } from '../common'; -const submitTokenOrderFunc = async (spy: string, address: NetworkAddress, params: T) => { - mockWalletReturnValue(spy, address, params); - const order = await testEnv.wrap(orderToken)({}); +const submitTokenOrderFunc = async (address: NetworkAddress, params: T) => { + mockWalletReturnValue(address, params); + const order = await testEnv.wrap(WEN_FUNC.orderToken); expect(order?.createdOn).toBeDefined(); return order; }; - const setAvailableOrderAndCancelSale = async ( token: Token, memberAddress: NetworkAddress, miotas: number, ) => { - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${token.uid}`); + const tokenDocRef = build5Db().doc(COL.TOKEN, token.uid); const distributionDocRef = build5Db().doc( - `${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${memberAddress}`, + COL.TOKEN, + token.uid, + SUB_COL.DISTRIBUTION, + memberAddress, ); await tokenDocRef.update({ saleLength: 86400000 * 2, - saleStartDate: dateToTimestamp(dayjs().subtract(1, 'd').toDate()), - coolDownEnd: dateToTimestamp( - dayjs() - .subtract(1, 'd') - .add(86400000 * 2, 'ms') - .toDate(), - ), + saleStartDate: dayjs().subtract(1, 'd').toDate(), + coolDownEnd: dayjs() + .subtract(1, 'd') + .add(86400000 * 2, 'ms') + .toDate(), }); - const order = await submitTokenOrderFunc(walletSpy, memberAddress, { token: token.uid }); + const order = await submitTokenOrderFunc(memberAddress, { token: token.uid }); await submitMilestoneFunc(order, miotas * MIN_IOTA_AMOUNT); - const distribution = await distributionDocRef.get(); expect(distribution.totalDeposit).toBe(miotas * MIN_IOTA_AMOUNT); - - mockWalletReturnValue(walletSpy, memberAddress, { token: token.uid }); - await testEnv.wrap(cancelPublicSale)({}); - await wait(async () => (await tokenDocRef.get())?.status === TokenStatus.AVAILABLE); + mockWalletReturnValue(memberAddress, { token: token.uid }); + await testEnv.wrap(WEN_FUNC.cancelPublicSale); + await wait(async () => (await tokenDocRef.get())?.status === TokenStatus.AVAILABLE); const tokenData = await tokenDocRef.get(); expect(tokenData.saleStartDate).toBeUndefined(); }; @@ -77,13 +62,11 @@ describe('Token controller: ' + WEN_FUNC.cancelPublicSale, () => { let memberAddress: NetworkAddress; let space: Space; let token: any; - beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - memberAddress = await createMember(walletSpy); - space = await createSpace(walletSpy, memberAddress); + memberAddress = await testEnv.createMember(); + space = await testEnv.createSpace(memberAddress); const tokenId = wallet.getRandomEthAddress(); - token = { + const tokenUpsert = { project: SOON_PROJECT_ID, symbol: getRandomSymbol(), totalSupply: 10, @@ -91,15 +74,15 @@ describe('Token controller: ' + WEN_FUNC.cancelPublicSale, () => { rejected: false, icon: MEDIA, overviewGraphics: MEDIA, - updatedOn: serverTime(), - createdOn: serverTime(), + updatedOn: serverTime().toDate(), + createdOn: serverTime().toDate(), space: space.uid, uid: tokenId, pricePerToken: MIN_IOTA_AMOUNT, - allocations: [ + allocations: JSON.stringify([ { title: 'Public sale', isPublicSale: true, percentage: 50 }, { title: 'Private', percentage: 50 }, - ], + ]), createdBy: memberAddress, name: 'MyToken', links: [], @@ -107,14 +90,18 @@ describe('Token controller: ' + WEN_FUNC.cancelPublicSale, () => { totalDeposit: 0, totalAirdropped: 0, termsAndConditions: 'https://wen.soonaverse.com/token/terms-and-conditions', - access: 0, + access: Access.OPEN, }; - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).set(token); + await build5Db().doc(COL.TOKEN, tokenId).upsert(tokenUpsert); + token = (await build5Db().doc(COL.TOKEN, tokenId).get())!; }); it('Should cancel public sale and refund buyers twice', async () => { const distributionDocRef = build5Db().doc( - `${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${memberAddress}`, + COL.TOKEN, + token.uid, + SUB_COL.DISTRIBUTION, + memberAddress, ); await setAvailableOrderAndCancelSale(token, memberAddress, 5); await setAvailableOrderAndCancelSale(token, memberAddress, 6); @@ -123,9 +110,9 @@ describe('Token controller: ' + WEN_FUNC.cancelPublicSale, () => { const creditDocs = await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.CREDIT) - .where('payload.type', '==', TransactionPayloadType.TOKEN_PURCHASE) + .where('payload_type', '==', TransactionPayloadType.TOKEN_PURCHASE) .where('member', '==', memberAddress) - .get(); + .get(); expect(creditDocs.map((d) => d?.payload?.amount!).sort((a, b) => a - b)).toEqual([ 5 * MIN_IOTA_AMOUNT, 6 * MIN_IOTA_AMOUNT, @@ -134,7 +121,10 @@ describe('Token controller: ' + WEN_FUNC.cancelPublicSale, () => { it('Should cancel public sale and refund buyers twice, then finish sale', async () => { const distributionDocRef = build5Db().doc( - `${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${memberAddress}`, + COL.TOKEN, + token.uid, + SUB_COL.DISTRIBUTION, + memberAddress, ); await setAvailableOrderAndCancelSale(token, memberAddress, 5); await setAvailableOrderAndCancelSale(token, memberAddress, 6); @@ -143,31 +133,26 @@ describe('Token controller: ' + WEN_FUNC.cancelPublicSale, () => { const creditDocs = await build5Db() .collection(COL.TRANSACTION) .where('type', '==', TransactionType.CREDIT) - .where('payload.type', '==', TransactionPayloadType.TOKEN_PURCHASE) + .where('payload_type', '==', TransactionPayloadType.TOKEN_PURCHASE) .where('member', '==', memberAddress) - .get(); + .get(); expect(creditDocs.map((d) => d?.payload?.amount!).sort((a, b) => a - b)).toEqual([ 5 * MIN_IOTA_AMOUNT, 6 * MIN_IOTA_AMOUNT, ]); - - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${token.uid}`); + const tokenDocRef = build5Db().doc(COL.TOKEN, token.uid); await tokenDocRef.update({ saleLength: 86400000 * 2, - saleStartDate: dateToTimestamp(dayjs().subtract(1, 'd').toDate()), - coolDownEnd: dateToTimestamp( - dayjs() - .subtract(1, 'd') - .add(86400000 * 2, 'ms') - .toDate(), - ), + saleStartDate: dayjs().subtract(1, 'd').toDate(), + coolDownEnd: dayjs() + .subtract(1, 'd') + .add(86400000 * 2, 'ms') + .toDate(), }); - const order = await submitTokenOrderFunc(walletSpy, memberAddress, { token: token.uid }); + const order = await submitTokenOrderFunc(memberAddress, { token: token.uid }); await submitMilestoneFunc(order, 7 * MIN_IOTA_AMOUNT); - await tokenDocRef.update({ status: TokenStatus.PROCESSING }); - await wait(async () => (await tokenDocRef.get())?.status === TokenStatus.PRE_MINTED); - + await wait(async () => (await tokenDocRef.get())?.status === TokenStatus.PRE_MINTED); distribution = await distributionDocRef.get(); expect(distribution.totalPaid).toBe(5 * MIN_IOTA_AMOUNT); expect(distribution.refundedAmount).toBe(2 * MIN_IOTA_AMOUNT); @@ -181,23 +166,22 @@ describe('Token controller: ' + WEN_FUNC.cancelPublicSale, () => { coolDownLength: 86400000, }; await build5Db() - .doc(`${COL.TOKEN}/${token.uid}`) + .doc(COL.TOKEN, token.uid) .update({ - allocations: [{ title: 'public', percentage: 100, isPublicSale: true }], + allocations: JSON.stringify([{ title: 'public', percentage: 100, isPublicSale: true }]), public: true, }); const updateData = { token: token.uid, ...publicTime, pricePerToken: MIN_IOTA_AMOUNT }; - mockWalletReturnValue(walletSpy, memberAddress, updateData); - const result = await testEnv.wrap(setTokenAvailableForSale)({}); - expect(result?.saleStartDate.toDate()).toEqual( + mockWalletReturnValue(memberAddress, updateData); + const result = await testEnv.wrap(WEN_FUNC.setTokenAvailableForSale); + token = await build5Db().doc(COL.TOKEN, result.uid).get(); + expect(token.saleStartDate!.toDate()).toEqual( dateToTimestamp(dayjs(publicTime.saleStartDate), true).toDate(), ); - - mockWalletReturnValue(walletSpy, memberAddress, { token: token.uid }); - await testEnv.wrap(cancelPublicSale)({}); - + mockWalletReturnValue(memberAddress, { token: token.uid }); + await testEnv.wrap(WEN_FUNC.cancelPublicSale); await wait(async () => { - const tokenData = await build5Db().doc(`${COL.TOKEN}/${token.uid}`).get(); + const tokenData = await build5Db().doc(COL.TOKEN, token.uid).get(); return tokenData.status === TokenStatus.AVAILABLE; }); }); diff --git a/packages/functions/test/controls/token/token.create.spec.ts b/packages/functions/test/controls/token/token.create.spec.ts index ad6c09c6d7..e5882fa88b 100644 --- a/packages/functions/test/controls/token/token.create.spec.ts +++ b/packages/functions/test/controls/token/token.create.spec.ts @@ -1,35 +1,22 @@ import { build5Db } from '@build-5/database'; import { Access, - Bucket, COL, MAX_TOTAL_TOKEN_SUPPLY, MIN_IOTA_AMOUNT, NetworkAddress, SUB_COL, Space, - StakeType, + Token, TokenAllocation, WEN_FUNC, WenError, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { createToken } from '../../../src/runtime/firebase/token/base'; import { dateToTimestamp } from '../../../src/utils/dateTime.utils'; import * as wallet from '../../../src/utils/wallet.utils'; -import { MEDIA, soonTokenId, testEnv } from '../../set-up'; -import { - createMember, - createSpace, - expectThrow, - getRandomSymbol, - mockWalletReturnValue, - setProdTiers, - setTestTiers, -} from '../common'; - -let walletSpy: any; - +import { MEDIA, mockWalletReturnValue, soonTokenId, testEnv } from '../../set-up'; +import { expectThrow, getRandomSymbol, setProdTiers, setTestTiers } from '../common'; const dummyToken = (space: string) => ({ name: 'MyToken', @@ -48,17 +35,15 @@ describe('Token controller: ' + WEN_FUNC.createToken, () => { let memberAddress: NetworkAddress; let space: Space; let token: any; - beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - memberAddress = await createMember(walletSpy); - space = await createSpace(walletSpy, memberAddress); + memberAddress = await testEnv.createMember(); + space = await testEnv.createSpace(memberAddress); token = dummyToken(space.uid); }); it('Should create token', async () => { - mockWalletReturnValue(walletSpy, memberAddress, token); - const result = await testEnv.wrap(createToken)({}); + mockWalletReturnValue(memberAddress, token); + const result = await testEnv.wrap(WEN_FUNC.createToken); expect(result?.uid).toBeDefined(); expect(result.tradingDisabled).toBe(true); expect(result.decimals).toBe(5); @@ -66,8 +51,8 @@ describe('Token controller: ' + WEN_FUNC.createToken, () => { it('Should create token without space', async () => { delete token.space; - mockWalletReturnValue(walletSpy, memberAddress, token); - const result = await testEnv.wrap(createToken)({}); + mockWalletReturnValue(memberAddress, token); + const result = await testEnv.wrap(WEN_FUNC.createToken); expect(result?.uid).toBeDefined(); expect(result.tradingDisabled).toBe(true); expect(result.decimals).toBe(5); @@ -75,182 +60,176 @@ describe('Token controller: ' + WEN_FUNC.createToken, () => { }); it('Should create token with $ prefix', async () => { - mockWalletReturnValue(walletSpy, memberAddress, { ...token, symbol: '$' + token.symbol }); - const result = await testEnv.wrap(createToken)({}); + mockWalletReturnValue(memberAddress, { ...token, symbol: '$' + token.symbol }); + const result = await testEnv.wrap(WEN_FUNC.createToken); expect(result?.uid).toBeDefined(); expect(result.tradingDisabled).toBe(true); expect(result.decimals).toBe(5); }); it('Should throw, invalid icon url', async () => { - mockWalletReturnValue(walletSpy, memberAddress, { ...token, icon: 'asd' }); - await expectThrow(testEnv.wrap(createToken)({}), WenError.invalid_params.key); - - mockWalletReturnValue(walletSpy, memberAddress, { - ...token, - icon: `https://firebasestorage.googleapis.com/v0/b/${Bucket.DEV}/o/`, - }); - await expectThrow(testEnv.wrap(createToken)({}), WenError.invalid_params.key); + mockWalletReturnValue(memberAddress, { ...token, icon: 'some-icon-url' }); + await expectThrow(testEnv.wrap(WEN_FUNC.createToken), WenError.invalid_params.key); + mockWalletReturnValue(memberAddress, { ...token, icon: `invalid-icon-url` }); + await expectThrow(testEnv.wrap(WEN_FUNC.createToken), WenError.invalid_params.key); }); it('Should create token, verify soon', async () => { await build5Db() - .doc(`${COL.TOKEN}/${soonTokenId}/${SUB_COL.DISTRIBUTION}/${memberAddress}`) - .create({ - stakes: { - [StakeType.DYNAMIC]: { - value: 10 * MIN_IOTA_AMOUNT, - }, - }, - }); - - mockWalletReturnValue(walletSpy, memberAddress, token); + .doc(COL.TOKEN, soonTokenId, SUB_COL.DISTRIBUTION, memberAddress) + .upsert({ stakes_dynamic_value: 10 * MIN_IOTA_AMOUNT }); await setProdTiers(); - const result = await testEnv.wrap(createToken)({}); + mockWalletReturnValue(memberAddress, token); + const result = await testEnv.wrap(WEN_FUNC.createToken); expect(result?.uid).toBeDefined(); await setTestTiers(); }); it('Should create token with max token supply', async () => { - mockWalletReturnValue(walletSpy, memberAddress, { - ...token, - totalSupply: MAX_TOTAL_TOKEN_SUPPLY, - }); - const result = await testEnv.wrap(createToken)({}); + mockWalletReturnValue(memberAddress, { ...token, totalSupply: MAX_TOTAL_TOKEN_SUPPLY }); + const result = await testEnv.wrap(WEN_FUNC.createToken); expect(result?.uid).toBeDefined(); }); it('Should create, one public sale', async () => { - token.allocations = [{ title: 'asd', percentage: 100, isPublicSale: true }]; + token.allocations = [{ title: 'name', percentage: 100, isPublicSale: true }]; const saleStartDate = dayjs().add(8, 'day'); token.saleStartDate = saleStartDate.toDate(); token.saleLength = 86400000; token.coolDownLength = 86400000; token.autoProcessAt100Percent = true; - mockWalletReturnValue(walletSpy, memberAddress, token); - const result = await testEnv.wrap(createToken)({}); - expect(result?.uid).toBeDefined(); - expect(result?.saleStartDate.toDate()).toEqual(dateToTimestamp(saleStartDate, true).toDate()); - expect(result?.saleLength).toBe(86400000); - expect(result?.coolDownEnd.toDate()).toEqual( - dateToTimestamp( - dayjs(saleStartDate).add(token.saleLength + token.coolDownLength, 'ms'), - true, - ).toDate(), + mockWalletReturnValue(memberAddress, token); + const result = await testEnv.wrap(WEN_FUNC.createToken); + token = await build5Db().doc(COL.TOKEN, result.uid).get(); + expect(token.uid).toBeDefined(); + expect(token.saleStartDate!.toDate()).toEqual(dateToTimestamp(saleStartDate, true).toDate()); + expect(token.saleLength).toBe(86400000); + expect(token.coolDownEnd!.toDate()).toEqual( + dateToTimestamp(dayjs(saleStartDate).add(token.saleLength + 86400000, 'ms'), true).toDate(), ); - expect(result?.autoProcessAt100Percent).toBe(true); + expect(token.autoProcessAt100Percent).toBe(true); }); it('Should create, one public sale, no cooldown period', async () => { - token.allocations = [{ title: 'asd', percentage: 100, isPublicSale: true }]; + token.allocations = [{ title: 'name', percentage: 100, isPublicSale: true }]; const saleStartDate = dayjs().add(8, 'day'); token.saleStartDate = saleStartDate.toDate(); token.saleLength = 86400000; token.coolDownLength = 0; - mockWalletReturnValue(walletSpy, memberAddress, token); - const result = await testEnv.wrap(createToken)({}); - expect(result?.uid).toBeDefined(); - expect(result?.saleStartDate.toDate()).toEqual(dateToTimestamp(saleStartDate, true).toDate()); - expect(result?.saleLength).toBe(86400000); - expect(result?.coolDownEnd.toDate()).toEqual( + mockWalletReturnValue(memberAddress, token); + const result = await testEnv.wrap(WEN_FUNC.createToken); + token = await build5Db().doc(COL.TOKEN, result.uid).get(); + expect(token.uid).toBeDefined(); + expect(token.saleStartDate!.toDate()).toEqual(dateToTimestamp(saleStartDate, true).toDate()); + expect(token.saleLength).toBe(86400000); + expect(token.coolDownEnd!.toDate()).toEqual( dateToTimestamp(dayjs(saleStartDate).add(token.saleLength, 'ms'), true).toDate(), ); }); it('Should not allow two tokens', async () => { - mockWalletReturnValue(walletSpy, memberAddress, token); - await testEnv.wrap(createToken)({}); - mockWalletReturnValue(walletSpy, memberAddress, dummyToken(space.uid)); - await expectThrow(testEnv.wrap(createToken)({}), WenError.token_already_exists_for_space.key); + mockWalletReturnValue(memberAddress, token); + await testEnv.wrap(WEN_FUNC.createToken); + + mockWalletReturnValue(memberAddress, dummyToken(space.uid)); + await expectThrow( + testEnv.wrap(WEN_FUNC.createToken), + WenError.token_already_exists_for_space.key, + ); }); it('Should only allow two tokens if first rejected', async () => { - mockWalletReturnValue(walletSpy, memberAddress, token); - const cToken = await testEnv.wrap(createToken)({}); - await build5Db().doc(`${COL.TOKEN}/${cToken.uid}`).update({ approved: false, rejected: true }); - mockWalletReturnValue(walletSpy, memberAddress, dummyToken(space.uid)); - const secondToken = await testEnv.wrap(createToken)({}); + mockWalletReturnValue(memberAddress, token); + const cToken = await testEnv.wrap(WEN_FUNC.createToken); + await build5Db().doc(COL.TOKEN, cToken.uid).update({ approved: false, rejected: true }); + mockWalletReturnValue(memberAddress, dummyToken(space.uid)); + const secondToken = await testEnv.wrap(WEN_FUNC.createToken); expect(secondToken.uid).toBeDefined(); }); it('Should throw, no name', async () => { delete token.name; - mockWalletReturnValue(walletSpy, memberAddress, token); + mockWalletReturnValue(memberAddress, token); await expectThrow( - testEnv.wrap(createToken)({}), + testEnv.wrap(WEN_FUNC.createToken), WenError.invalid_params.key, - 'Invalid params. "name" is required. ', + '"name" is required. ', ); }); it('Should throw, no terms and conditions', async () => { delete token.termsAndConditions; - mockWalletReturnValue(walletSpy, memberAddress, token); - const result = await testEnv.wrap(createToken)({}); + mockWalletReturnValue(memberAddress, token); + const result = await testEnv.wrap(WEN_FUNC.createToken); expect(result).toBeDefined(); }); it('Should throw, no symbol', async () => { delete token.symbol; - mockWalletReturnValue(walletSpy, memberAddress, token); - await expectThrow(testEnv.wrap(createToken)({}), WenError.invalid_params.key); + mockWalletReturnValue(memberAddress, token); + await expectThrow(testEnv.wrap(WEN_FUNC.createToken), WenError.invalid_params.key); }); it('Should throw, no totalSupply', async () => { delete token.totalSupply; - mockWalletReturnValue(walletSpy, memberAddress, token); - await expectThrow(testEnv.wrap(createToken)({}), WenError.invalid_params.key); + mockWalletReturnValue(memberAddress, token); + await expectThrow(testEnv.wrap(WEN_FUNC.createToken), WenError.invalid_params.key); }); it('Should work with no allocations', async () => { delete token.allocations; - mockWalletReturnValue(walletSpy, memberAddress, token); - const result = await testEnv.wrap(createToken)({}); + mockWalletReturnValue(memberAddress, token); + const result = await testEnv.wrap(WEN_FUNC.createToken); expect(result).toBeDefined(); }); it('Should throw, wrong total percentage', async () => { token.allocations = [ - { title: 'asd', percentage: 50 }, + { title: 'name', percentage: 50 }, { title: 'ccc', percentage: 40 }, ]; - mockWalletReturnValue(walletSpy, memberAddress, token); + + mockWalletReturnValue(memberAddress, token); await expectThrow( - testEnv.wrap(createToken)({}), + testEnv.wrap(WEN_FUNC.createToken), WenError.invalid_params.key, - 'Invalid params. "allocations" contains an invalid value. Allocations percentage sum must be 100', + '"allocations" contains an invalid value. Allocations percentage sum must be 100', ); }); it('Should throw, more then one public sale', async () => { token.allocations = [ - { title: 'asd', percentage: 50, isPublicSale: true }, + { title: 'name', percentage: 50, isPublicSale: true }, { title: 'ccc', percentage: 50, isPublicSale: true }, ]; - mockWalletReturnValue(walletSpy, memberAddress, token); + mockWalletReturnValue(memberAddress, token); await expectThrow( - testEnv.wrap(createToken)({}), + testEnv.wrap(WEN_FUNC.createToken), WenError.invalid_params.key, - 'Invalid params. "allocations" contains a duplicate value. Only one public sale is allowed', + '"allocations" contains a duplicate value. Only one public sale is allowed', ); }); it('Should throw, past start date', async () => { token.startDate = dayjs().subtract(1, 'd').toDate(); - mockWalletReturnValue(walletSpy, memberAddress, token); - await expectThrow(testEnv.wrap(createToken)({}), WenError.invalid_params.key); + mockWalletReturnValue(memberAddress, token); + await expectThrow(testEnv.wrap(WEN_FUNC.createToken), WenError.invalid_params.key); }); it('Should throw, creator is not guardian', async () => { - mockWalletReturnValue(walletSpy, wallet.getRandomEthAddress(), token); - await expectThrow(testEnv.wrap(createToken)({}), WenError.you_are_not_guardian_of_space.key); + const random = await testEnv.createMember(); + mockWalletReturnValue(random, token); + await expectThrow( + testEnv.wrap(WEN_FUNC.createToken), + WenError.you_are_not_guardian_of_space.key, + ); }); it('Should create with public sale but no date', async () => { const token: any = dummyToken(space.uid); - token.allocations = [{ title: 'asd', percentage: 100, isPublicSale: true }]; - mockWalletReturnValue(walletSpy, memberAddress, token); - const result = await testEnv.wrap(createToken)({}); + token.allocations = [{ title: 'name', percentage: 100, isPublicSale: true }]; + mockWalletReturnValue(memberAddress, token); + const result = await testEnv.wrap(WEN_FUNC.createToken); expect(result?.uid).toBeDefined(); }); @@ -259,64 +238,64 @@ describe('Token controller: ' + WEN_FUNC.createToken, () => { token.saleStartDate = dayjs().add(8, 'd').toDate(); token.saleLength = 86400000; token.coolDownLength = 86400000; - mockWalletReturnValue(walletSpy, memberAddress, token); - await expectThrow(testEnv.wrap(createToken)({}), WenError.no_token_public_sale.key); + mockWalletReturnValue(memberAddress, token); + await expectThrow(testEnv.wrap(WEN_FUNC.createToken), WenError.no_token_public_sale.key); }); it('Should throw, when public sale data is incomplete', async () => { const token: any = dummyToken(space.uid); - token.allocations = [{ title: 'asd', percentage: 100, isPublicSale: true }]; - + token.allocations = [{ title: 'name', percentage: 100, isPublicSale: true }]; token.saleStartDate = dayjs().add(8, 'd').toDate(); - mockWalletReturnValue(walletSpy, memberAddress, token); - await expectThrow(testEnv.wrap(createToken)({}), WenError.invalid_params.key); - + mockWalletReturnValue(memberAddress, token); + await expectThrow(testEnv.wrap(WEN_FUNC.createToken), WenError.invalid_params.key); token.saleLength = 86400000; - mockWalletReturnValue(walletSpy, memberAddress, token); - await expectThrow(testEnv.wrap(createToken)({}), WenError.invalid_params.key); - + mockWalletReturnValue(memberAddress, token); + await expectThrow(testEnv.wrap(WEN_FUNC.createToken), WenError.invalid_params.key); token.coolDownLength = 86400000; - mockWalletReturnValue(walletSpy, memberAddress, token); - const result = await testEnv.wrap(createToken)({}); + mockWalletReturnValue(memberAddress, token); + const result = await testEnv.wrap(WEN_FUNC.createToken); expect(result?.uid).toBeDefined(); }); it('Should throw, token symbol not unique', async () => { - mockWalletReturnValue(walletSpy, memberAddress, token); - await testEnv.wrap(createToken)({}); - const space = await createSpace(walletSpy, memberAddress); + mockWalletReturnValue(memberAddress, token); + await testEnv.wrap(WEN_FUNC.createToken); + const space = await testEnv.createSpace(memberAddress); const data = dummyToken(space.uid); - mockWalletReturnValue(walletSpy, memberAddress, { ...data, symbol: token.symbol }); + + mockWalletReturnValue(memberAddress, { ...data, symbol: token.symbol }); await expectThrow( - testEnv.wrap(createToken)({}), + testEnv.wrap(WEN_FUNC.createToken), WenError.token_symbol_must_be_globally_unique.key, ); }); it('Should not throw, token symbol not unique but prev token is rejected', async () => { - mockWalletReturnValue(walletSpy, memberAddress, token); - const newToken = await testEnv.wrap(createToken)({}); - await build5Db().doc(`${COL.TOKEN}/${newToken.uid}`).update({ rejected: true }); - - const space = await createSpace(walletSpy, memberAddress); - mockWalletReturnValue(walletSpy, memberAddress, { + mockWalletReturnValue(memberAddress, token); + const newToken = await testEnv.wrap(WEN_FUNC.createToken); + await build5Db().doc(COL.TOKEN, newToken.uid).update({ rejected: true }); + const space = await testEnv.createSpace(memberAddress); + mockWalletReturnValue(memberAddress, { ...dummyToken(space.uid), symbol: token.symbol, }); - await testEnv.wrap(createToken)({}); + await testEnv.wrap(WEN_FUNC.createToken); }); it('Should throw, space does not exist', async () => { token.space = wallet.getRandomEthAddress(); - mockWalletReturnValue(walletSpy, memberAddress, token); - await expectThrow(testEnv.wrap(createToken)({}), WenError.you_are_not_guardian_of_space.key); + mockWalletReturnValue(memberAddress, token); + await expectThrow( + testEnv.wrap(WEN_FUNC.createToken), + WenError.you_are_not_guardian_of_space.key, + ); }); it('Should create with short description', async () => { token.shortDescriptionTitle = 'shortDescriptionTitle'; token.shortDescription = 'shortDescription'; - mockWalletReturnValue(walletSpy, memberAddress, token); - const result = await testEnv.wrap(createToken)({}); + mockWalletReturnValue(memberAddress, token); + const result = await testEnv.wrap(WEN_FUNC.createToken); expect(result.shortDescriptionTitle).toBe('shortDescriptionTitle'); expect(result.shortDescription).toBe('shortDescription'); }); @@ -324,27 +303,27 @@ describe('Token controller: ' + WEN_FUNC.createToken, () => { it('Should throw, accessAwards required if access is MEMBERS_WITH_BADGE', async () => { token.access = Access.MEMBERS_WITH_BADGE; token.accessAwards = [wallet.getRandomEthAddress()]; - mockWalletReturnValue(walletSpy, memberAddress, token); - await testEnv.wrap(createToken)({}); + mockWalletReturnValue(memberAddress, token); + await testEnv.wrap(WEN_FUNC.createToken); token.accessAwards = []; - mockWalletReturnValue(walletSpy, memberAddress, token); - await expectThrow(testEnv.wrap(createToken)({}), WenError.invalid_params.key); + mockWalletReturnValue(memberAddress, token); + await expectThrow(testEnv.wrap(WEN_FUNC.createToken), WenError.invalid_params.key); }); it('Should throw, accessCollections required if access is MEMBERS_WITH_NFT_FROM_COLLECTION', async () => { token.access = Access.MEMBERS_WITH_NFT_FROM_COLLECTION; token.accessCollections = [wallet.getRandomEthAddress()]; - mockWalletReturnValue(walletSpy, memberAddress, token); - await testEnv.wrap(createToken)({}); + mockWalletReturnValue(memberAddress, token); + await testEnv.wrap(WEN_FUNC.createToken); token.accessCollections = []; - mockWalletReturnValue(walletSpy, memberAddress, token); - await expectThrow(testEnv.wrap(createToken)({}), WenError.invalid_params.key); + mockWalletReturnValue(memberAddress, token); + await expectThrow(testEnv.wrap(WEN_FUNC.createToken), WenError.invalid_params.key); }); it('Should throw, no tokens staked', async () => { - mockWalletReturnValue(walletSpy, memberAddress, token); await setProdTiers(); - await expectThrow(testEnv.wrap(createToken)({}), WenError.no_staked_soon.key); + mockWalletReturnValue(memberAddress, token); + await expectThrow(testEnv.wrap(WEN_FUNC.createToken), WenError.no_staked_soon.key); await setTestTiers(); }); }); diff --git a/packages/functions/test/controls/token/token.order.and.claim.air.spec.ts b/packages/functions/test/controls/token/token.order.and.claim.air.spec.ts index 6d3701e5ae..2736f4c585 100644 --- a/packages/functions/test/controls/token/token.order.and.claim.air.spec.ts +++ b/packages/functions/test/controls/token/token.order.and.claim.air.spec.ts @@ -1,40 +1,27 @@ import { build5Db } from '@build-5/database'; import { + Access, COL, MIN_IOTA_AMOUNT, NetworkAddress, SOON_PROJECT_ID, - Space, SUB_COL, + Space, Token, - TokenDistribution, TokenDropStatus, TokenStatus, + Transaction, + WEN_FUNC, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { - airdropToken, - claimAirdroppedToken, - orderToken, -} from '../../../src/runtime/firebase/token/base'; -import { dateToTimestamp, serverTime } from '../../../src/utils/dateTime.utils'; +import { serverTime } from '../../../src/utils/dateTime.utils'; import * as wallet from '../../../src/utils/wallet.utils'; -import { MEDIA, testEnv } from '../../set-up'; -import { - createMember, - createSpace, - getRandomSymbol, - mockWalletReturnValue, - submitMilestoneFunc, - tokenProcessed, - wait, -} from '../common'; +import { MEDIA, mockWalletReturnValue, testEnv } from '../../set-up'; +import { getRandomSymbol, submitMilestoneFunc, tokenProcessed, wait } from '../common'; -let walletSpy: any; - -const submitTokenOrderFunc = async (spy: string, address: NetworkAddress, params: T) => { - mockWalletReturnValue(spy, address, params); - const order = await testEnv.wrap(orderToken)({}); +const submitTokenOrderFunc = async (address: NetworkAddress, params: T) => { + mockWalletReturnValue(address, params); + const order = await testEnv.wrap(WEN_FUNC.orderToken); expect(order?.createdOn).toBeDefined(); return order; }; @@ -43,14 +30,11 @@ describe('Order and claim airdropped token test', () => { let memberAddress: NetworkAddress; let space: Space; let token: Token; - beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - memberAddress = await createMember(walletSpy); - space = await createSpace(walletSpy, memberAddress); - + memberAddress = await testEnv.createMember(); + space = await testEnv.createSpace(memberAddress); const tokenId = wallet.getRandomEthAddress(); - token = { + const tokenUpsert = { project: SOON_PROJECT_ID, symbol: getRandomSymbol(), totalSupply: 10, @@ -58,51 +42,51 @@ describe('Order and claim airdropped token test', () => { rejected: false, icon: MEDIA, overviewGraphics: MEDIA, - updatedOn: serverTime(), - createdOn: serverTime(), + updatedOn: serverTime().toDate(), + createdOn: serverTime().toDate(), space: space.uid, uid: tokenId, pricePerToken: MIN_IOTA_AMOUNT, - allocations: [ + allocations: JSON.stringify([ { title: 'Public sale', isPublicSale: true, percentage: 50 }, { title: 'Private', percentage: 50 }, - ], + ]), createdBy: memberAddress, name: 'MyToken', saleLength: 86400000 * 2, - saleStartDate: dateToTimestamp(dayjs().subtract(1, 'd').toDate()), + saleStartDate: dayjs().subtract(1, 'd').toDate(), links: [], status: TokenStatus.AVAILABLE, totalDeposit: 0, totalAirdropped: 0, termsAndConditions: 'https://wen.soonaverse.com/token/terms-and-conditions', - access: 0, + access: Access.OPEN, decimals: 6, }; - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).set(token); - + await build5Db().doc(COL.TOKEN, tokenId).upsert(tokenUpsert); + token = (await build5Db().doc(COL.TOKEN, tokenId).get())!; const airdropRequest = { token: token.uid, drops: [{ count: 5, recipient: memberAddress, vestingAt: dayjs().toDate() }], }; - mockWalletReturnValue(walletSpy, memberAddress, airdropRequest); - await testEnv.wrap(airdropToken)({}); + mockWalletReturnValue(memberAddress, airdropRequest); + await testEnv.wrap(WEN_FUNC.airdropToken); }); it('Should order and claim dropped', async () => { const distributionDocRef = build5Db().doc( - `${COL.TOKEN}/${token.uid}/${SUB_COL.DISTRIBUTION}/${memberAddress}`, + COL.TOKEN, + token.uid, + SUB_COL.DISTRIBUTION, + memberAddress, ); - let distribution = await distributionDocRef.get(); - expect(distribution.totalUnclaimedAirdrop).toBe(5); - - const order = await submitTokenOrderFunc(walletSpy, memberAddress, { token: token.uid }); + let distribution = await distributionDocRef.get(); + expect(distribution!.totalUnclaimedAirdrop).toBe(5); + const order = await submitTokenOrderFunc(memberAddress, { token: token.uid }); await submitMilestoneFunc(order, 5 * token.pricePerToken); - - mockWalletReturnValue(walletSpy, memberAddress, { token: token.uid }); - const claimOrder = await testEnv.wrap(claimAirdroppedToken)({}); + mockWalletReturnValue(memberAddress, { token: token.uid }); + const claimOrder = await testEnv.wrap(WEN_FUNC.claimAirdroppedToken); await submitMilestoneFunc(claimOrder); - await wait(async () => { const snap = await build5Db() .collection(COL.AIRDROP) @@ -111,11 +95,9 @@ describe('Order and claim airdropped token test', () => { .get(); return snap.length === 1; }); - - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).update({ status: TokenStatus.PROCESSING }); + await build5Db().doc(COL.TOKEN, token.uid).update({ status: TokenStatus.PROCESSING }); await tokenProcessed(token.uid, 1, true); - - distribution = await distributionDocRef.get(); + distribution = (await distributionDocRef.get())!; expect(distribution.tokenClaimed).toBe(5); expect(distribution.totalPaid).toBe(5 * token.pricePerToken); expect(distribution.tokenOwned).toBe(10); diff --git a/packages/functions/test/controls/token/token.rank.spec.ts b/packages/functions/test/controls/token/token.rank.spec.ts index 3c6cc83a11..95bab30f8f 100644 --- a/packages/functions/test/controls/token/token.rank.spec.ts +++ b/packages/functions/test/controls/token/token.rank.spec.ts @@ -1,32 +1,27 @@ import { build5Db } from '@build-5/database'; import { COL, + Rank, RANKING_TEST, Space, SUB_COL, Token, TokenAllocation, TokenStats, + WEN_FUNC, WenError, } from '@build-5/interfaces'; -import { rankController } from '../../../src/runtime/firebase/rank'; -import { createToken } from '../../../src/runtime/firebase/token/base'; import * as wallet from '../../../src/utils/wallet.utils'; -import { MEDIA, testEnv } from '../../set-up'; +import { MEDIA, mockWalletReturnValue, testEnv } from '../../set-up'; import { - createMember, createRoyaltySpaces, - createSpace, expectThrow, getRandomSymbol, - mockWalletReturnValue, setProdTiers, setTestTiers, wait, } from '../common'; -let walletSpy: any; - const dummyToken = (space: string) => ({ name: 'MyToken', @@ -51,75 +46,72 @@ describe('Token rank test', () => { }); beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - member = await createMember(walletSpy); - space = await createSpace(walletSpy, member); - mockWalletReturnValue(walletSpy, member, dummyToken(space.uid)); - token = await testEnv.wrap(createToken)({}); - - await build5Db() - .doc(`${COL.SPACE}/${RANKING_TEST.tokenSpace}/${SUB_COL.GUARDIANS}/${member}`) - .set({ - uid: member, - parentId: RANKING_TEST.tokenSpace, - parentCol: COL.SPACE, - }); + member = await testEnv.createMember(); + space = await testEnv.createSpace(member); + + mockWalletReturnValue(member, dummyToken(space.uid)); + token = await testEnv.wrap(WEN_FUNC.createToken); + + await build5Db().doc(COL.SPACE, RANKING_TEST.tokenSpace, SUB_COL.GUARDIANS, member).upsert({ + parentId: RANKING_TEST.tokenSpace, + }); }); it('Should throw, no token', async () => { - mockWalletReturnValue(walletSpy, member, { + mockWalletReturnValue(member, { collection: COL.TOKEN, uid: wallet.getRandomEthAddress(), rank: 1, }); - await expectThrow(testEnv.wrap(rankController)({}), WenError.token_does_not_exist.key); + await expectThrow(testEnv.wrap(WEN_FUNC.rankController), WenError.token_does_not_exist.key); }); it('Should throw, invalid rank', async () => { - mockWalletReturnValue(walletSpy, member, { + mockWalletReturnValue(member, { collection: COL.TOKEN, uid: token.uid, rank: 200, }); - await expectThrow(testEnv.wrap(rankController)({}), WenError.invalid_params.key); + await expectThrow(testEnv.wrap(WEN_FUNC.rankController), WenError.invalid_params.key); }); it('Should throw, no soons staked', async () => { await setProdTiers(); - mockWalletReturnValue(walletSpy, member, { + mockWalletReturnValue(member, { collection: COL.TOKEN, uid: token.uid, rank: 1, }); - await expectThrow(testEnv.wrap(rankController)({}), WenError.no_staked_soon.key); + await expectThrow(testEnv.wrap(WEN_FUNC.rankController), WenError.no_staked_soon.key); await setTestTiers(); }); it('Should throw, not space member', async () => { - await build5Db() - .doc(`${COL.SPACE}/${RANKING_TEST.tokenSpace}/${SUB_COL.GUARDIANS}/${member}`) - .delete(); + await build5Db().doc(COL.SPACE, RANKING_TEST.tokenSpace, SUB_COL.GUARDIANS, member).delete(); - mockWalletReturnValue(walletSpy, member, { + mockWalletReturnValue(member, { collection: COL.TOKEN, uid: token.uid, rank: 1, }); - await expectThrow(testEnv.wrap(rankController)({}), WenError.you_are_not_guardian_of_space.key); + await expectThrow( + testEnv.wrap(WEN_FUNC.rankController), + WenError.you_are_not_guardian_of_space.key, + ); }); const validateStats = async (count: number, sum: number) => { await wait(async () => { - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${token.uid}`); - const statsDocRef = tokenDocRef.collection(SUB_COL.STATS).doc(token.uid); + const statsDocRef = build5Db().doc(COL.TOKEN, token.uid, SUB_COL.STATS, token.uid); const stats = await statsDocRef.get(); const statsAreCorrect = stats?.ranks?.count === count && stats?.ranks?.sum === sum && stats?.ranks?.avg === Number((stats?.ranks?.sum! / stats?.ranks?.count!).toFixed(3)); + const tokenDocRef = build5Db().doc(COL.TOKEN, token.uid); token = await tokenDocRef.get(); return ( statsAreCorrect && @@ -131,12 +123,12 @@ describe('Token rank test', () => { }; const sendRank = async (rankValue: number) => { - mockWalletReturnValue(walletSpy, member, { + mockWalletReturnValue(member, { collection: COL.TOKEN, uid: token.uid, rank: rankValue, }); - const rank = await testEnv.wrap(rankController)({}); + const rank = await testEnv.wrap(WEN_FUNC.rankController); expect(rank.uid).toBe(member); expect(rank.parentId).toBe(token.uid); expect(rank.parentCol).toBe(COL.TOKEN); diff --git a/packages/functions/test/controls/token/token.set.to.sale.spec.ts b/packages/functions/test/controls/token/token.set.to.sale.spec.ts index a72d78ea30..deace5daa1 100644 --- a/packages/functions/test/controls/token/token.set.to.sale.spec.ts +++ b/packages/functions/test/controls/token/token.set.to.sale.spec.ts @@ -4,25 +4,15 @@ import { MIN_IOTA_AMOUNT, NetworkAddress, Space, + Token, TokenAllocation, WEN_FUNC, WenError, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { createToken, setTokenAvailableForSale } from '../../../src/runtime/firebase/token/base'; 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, - getRandomSymbol, - mockWalletReturnValue, -} from '../common'; - -let walletSpy: any; - +import { MEDIA, mockWalletReturnValue, testEnv } from '../../set-up'; +import { expectThrow, getRandomSymbol } from '../common'; const dummyToken = (space: string) => ({ name: 'MyToken', @@ -46,131 +36,141 @@ describe('Token controller: ' + WEN_FUNC.setTokenAvailableForSale, () => { saleLength: 86400000 * 2, coolDownLength: 86400000, }; - beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - memberAddress = await createMember(walletSpy); - space = await createSpace(walletSpy, memberAddress); - mockWalletReturnValue(walletSpy, memberAddress, dummyToken(space.uid)); - token = await testEnv.wrap(createToken)({}); - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).update({ approved: true }); + memberAddress = await testEnv.createMember(); + space = await testEnv.createSpace(memberAddress); + mockWalletReturnValue(memberAddress, dummyToken(space.uid)); + token = await testEnv.wrap(WEN_FUNC.createToken); + await build5Db().doc(COL.TOKEN, token.uid).update({ approved: true }); }); it('Should throw, not approved', async () => { - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).update({ approved: false }); + await build5Db().doc(COL.TOKEN, token.uid).update({ approved: false }); const updateData = { token: token.uid, ...publicTime, pricePerToken: MIN_IOTA_AMOUNT }; - mockWalletReturnValue(walletSpy, memberAddress, updateData); - await expectThrow(testEnv.wrap(setTokenAvailableForSale)({}), WenError.token_not_approved.key); + mockWalletReturnValue(memberAddress, updateData); + await expectThrow( + testEnv.wrap(WEN_FUNC.setTokenAvailableForSale), + WenError.token_not_approved.key, + ); }); it('Should throw, rejected', async () => { - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).update({ approved: true, rejected: true }); + await build5Db().doc(COL.TOKEN, token.uid).update({ approved: true, rejected: true }); const updateData = { token: token.uid, ...publicTime, pricePerToken: MIN_IOTA_AMOUNT }; - mockWalletReturnValue(walletSpy, memberAddress, updateData); - await expectThrow(testEnv.wrap(setTokenAvailableForSale)({}), WenError.token_not_approved.key); + mockWalletReturnValue(memberAddress, updateData); + await expectThrow( + testEnv.wrap(WEN_FUNC.setTokenAvailableForSale), + WenError.token_not_approved.key, + ); }); it('Should throw, not on public sale', async () => { const updateData = { token: token.uid, ...publicTime, pricePerToken: MIN_IOTA_AMOUNT }; - mockWalletReturnValue(walletSpy, memberAddress, updateData); + mockWalletReturnValue(memberAddress, updateData); await expectThrow( - testEnv.wrap(setTokenAvailableForSale)({}), + testEnv.wrap(WEN_FUNC.setTokenAvailableForSale), WenError.no_token_public_sale.key, ); }); it('Should throw, not guardian', async () => { + const random = await testEnv.createMember(); const updateData = { token: token.uid, ...publicTime, pricePerToken: MIN_IOTA_AMOUNT }; - mockWalletReturnValue(walletSpy, wallet.getRandomEthAddress(), updateData); + mockWalletReturnValue(random, updateData); await expectThrow( - testEnv.wrap(setTokenAvailableForSale)({}), + testEnv.wrap(WEN_FUNC.setTokenAvailableForSale), WenError.you_are_not_guardian_of_space.key, ); }); it('Should throw, no space', async () => { - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${token.uid}`); + const tokenDocRef = build5Db().doc(COL.TOKEN, token.uid); await tokenDocRef.update({ space: '', - allocations: [{ title: 'public', percentage: 100, isPublicSale: true }], + allocations: JSON.stringify([{ title: 'public', percentage: 100, isPublicSale: true }]), }); const updateData = { token: token.uid, ...publicTime, pricePerToken: MIN_IOTA_AMOUNT }; - mockWalletReturnValue(walletSpy, memberAddress, updateData); + mockWalletReturnValue(memberAddress, updateData); await expectThrow( - testEnv.wrap(setTokenAvailableForSale)({}), + testEnv.wrap(WEN_FUNC.setTokenAvailableForSale), WenError.token_must_have_space.key, ); }); it('Should set public availability', async () => { await build5Db() - .doc(`${COL.TOKEN}/${token.uid}`) - .update({ allocations: [{ title: 'public', percentage: 100, isPublicSale: true }] }); + .doc(COL.TOKEN, token.uid) + .update({ + allocations: JSON.stringify([{ title: 'public', percentage: 100, isPublicSale: true }]), + }); const updateData = { token: token.uid, ...publicTime, autoProcessAt100Percent: true, pricePerToken: MIN_IOTA_AMOUNT, }; - mockWalletReturnValue(walletSpy, memberAddress, updateData); - const result = await testEnv.wrap(setTokenAvailableForSale)({}); - expect(result?.uid).toBeDefined(); - expect(result?.saleStartDate.toDate()).toEqual( + mockWalletReturnValue(memberAddress, updateData); + const result = await testEnv.wrap(WEN_FUNC.setTokenAvailableForSale); + token = await build5Db().doc(COL.TOKEN, result.uid).get(); + expect(token.uid).toBeDefined(); + expect(token.saleStartDate!.toDate()).toEqual( dateToTimestamp(dayjs(publicTime.saleStartDate), true).toDate(), ); - expect(result?.saleLength).toBe(2 * 86400000); - expect(result?.coolDownEnd.toDate()).toEqual( + expect(token.saleLength).toBe(2 * 86400000); + expect(token.coolDownEnd!.toDate()).toEqual( dateToTimestamp( dayjs(publicTime.saleStartDate).add(86400000 * 2 + 86400000, 'ms'), true, ).toDate(), ); - expect(result?.autoProcessAt100Percent).toBe(true); + expect(token.autoProcessAt100Percent).toBe(true); }); it('Should throw, can not set public availability twice', async () => { await build5Db() - .doc(`${COL.TOKEN}/${token.uid}`) - .update({ allocations: [{ title: 'public', percentage: 100, isPublicSale: true }] }); - mockWalletReturnValue(walletSpy, memberAddress, { + .doc(COL.TOKEN, token.uid) + .update({ + allocations: JSON.stringify([{ title: 'public', percentage: 100, isPublicSale: true }]), + }); + mockWalletReturnValue(memberAddress, { token: token.uid, ...publicTime, pricePerToken: MIN_IOTA_AMOUNT, }); - await testEnv.wrap(setTokenAvailableForSale)({}); - - mockWalletReturnValue(walletSpy, memberAddress, { + await testEnv.wrap(WEN_FUNC.setTokenAvailableForSale); + mockWalletReturnValue(memberAddress, { token: token.uid, ...publicTime, pricePerToken: MIN_IOTA_AMOUNT, }); await expectThrow( - testEnv.wrap(setTokenAvailableForSale)({}), + testEnv.wrap(WEN_FUNC.setTokenAvailableForSale), WenError.public_sale_already_set.key, ); }); it('Should set no cool down length', async () => { - const docRef = build5Db().doc(`${COL.TOKEN}/${token.uid}`); + const docRef = build5Db().doc(COL.TOKEN, token.uid); await docRef.update({ - allocations: [{ title: 'public', percentage: 100, isPublicSale: true }], + allocations: JSON.stringify([{ title: 'public', percentage: 100, isPublicSale: true }]), }); const publicTime = { saleStartDate: dayjs().toDate(), saleLength: 86400000 * 2, coolDownLength: 0, }; - mockWalletReturnValue(walletSpy, memberAddress, { + mockWalletReturnValue(memberAddress, { token: token.uid, ...publicTime, pricePerToken: MIN_IOTA_AMOUNT, }); - const result = await testEnv.wrap(setTokenAvailableForSale)({}); - expect(result?.saleStartDate.toDate()).toEqual( + const result = await testEnv.wrap(WEN_FUNC.setTokenAvailableForSale); + token = await build5Db().doc(COL.TOKEN, result.uid).get(); + expect(token.saleStartDate!.toDate()).toEqual( dateToTimestamp(dayjs(publicTime.saleStartDate), true).toDate(), ); - expect(result?.saleLength).toBe(publicTime.saleLength); - expect(result?.coolDownEnd.toDate()).toEqual( + expect(token.saleLength).toBe(publicTime.saleLength); + expect(token.coolDownEnd!.toDate()).toEqual( dateToTimestamp( dayjs(publicTime.saleStartDate).add(publicTime.saleLength, 'ms'), true, diff --git a/packages/functions/test/controls/token/token.update.spec.ts b/packages/functions/test/controls/token/token.update.spec.ts index 33476e13b4..a2305bb646 100644 --- a/packages/functions/test/controls/token/token.update.spec.ts +++ b/packages/functions/test/controls/token/token.update.spec.ts @@ -4,24 +4,14 @@ import { MIN_IOTA_AMOUNT, NetworkAddress, Space, + Token, TokenAllocation, TokenStatus, WEN_FUNC, WenError, } from '@build-5/interfaces'; -import { createToken, updateToken } from '../../../src/runtime/firebase/token/base'; -import * as wallet from '../../../src/utils/wallet.utils'; -import { MEDIA, testEnv } from '../../set-up'; -import { - createMember, - createSpace, - expectThrow, - getRandomSymbol, - mockWalletReturnValue, -} from '../common'; - -let walletSpy: any; - +import { MEDIA, mockWalletReturnValue, testEnv } from '../../set-up'; +import { expectThrow, getRandomSymbol } from '../common'; const dummyToken = (space: string) => ({ name: 'MyToken', @@ -39,23 +29,20 @@ const dummyToken = (space: string) => describe('Token controller: ' + WEN_FUNC.updateToken, () => { let memberAddress: NetworkAddress; let space: Space; - let token: any; - + let token: Token; const data = { - shortDescriptionTitle: null, - shortDescription: null, - name: null, - uid: null, - title: null, - description: null, + shortDescriptionTitle: undefined, + shortDescription: undefined, + name: undefined, + uid: undefined, + title: undefined, + description: undefined, }; - beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - memberAddress = await createMember(walletSpy); - space = await createSpace(walletSpy, memberAddress); - mockWalletReturnValue(walletSpy, memberAddress, dummyToken(space.uid)); - token = await testEnv.wrap(createToken)({}); + memberAddress = await testEnv.createMember(); + space = await testEnv.createSpace(memberAddress); + mockWalletReturnValue(memberAddress, dummyToken(space.uid)); + token = await testEnv.wrap(WEN_FUNC.createToken); }); it('Should update token', async () => { @@ -67,8 +54,8 @@ describe('Token controller: ' + WEN_FUNC.updateToken, () => { description: 'description', pricePerToken: 2 * MIN_IOTA_AMOUNT, }; - mockWalletReturnValue(walletSpy, memberAddress, updateData); - const result = await testEnv.wrap(updateToken)({}); + mockWalletReturnValue(memberAddress, updateData); + const result = await testEnv.wrap(WEN_FUNC.updateToken); expect(result.name).toBe(updateData.name); expect(result.title).toBe(updateData.title); expect(result.description).toBe(updateData.description); @@ -76,7 +63,7 @@ describe('Token controller: ' + WEN_FUNC.updateToken, () => { }); it('Should update token, no space', async () => { - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).update({ space: '' }); + await build5Db().doc(COL.TOKEN, token.uid).update({ space: '' }); const updateData = { ...data, name: 'TokenName2', @@ -85,14 +72,15 @@ describe('Token controller: ' + WEN_FUNC.updateToken, () => { description: 'description', pricePerToken: 2 * MIN_IOTA_AMOUNT, }; - mockWalletReturnValue(walletSpy, wallet.getRandomEthAddress(), updateData); + const random = await testEnv.createMember(); + + mockWalletReturnValue(random, updateData); await expectThrow( - testEnv.wrap(updateToken)({}), + testEnv.wrap(WEN_FUNC.updateToken), WenError.you_must_be_the_creator_of_this_token.key, ); - - mockWalletReturnValue(walletSpy, memberAddress, updateData); - const result = await testEnv.wrap(updateToken)({}); + mockWalletReturnValue(memberAddress, updateData); + const result = await testEnv.wrap(WEN_FUNC.updateToken); expect(result.name).toBe(updateData.name); expect(result.title).toBe(updateData.title); expect(result.description).toBe(updateData.description); @@ -101,11 +89,12 @@ describe('Token controller: ' + WEN_FUNC.updateToken, () => { it('Should update token - remove description', async () => { const updateData = { ...data, name: token.name, uid: token.uid, title: 'title2' }; - mockWalletReturnValue(walletSpy, memberAddress, updateData); - const result = await testEnv.wrap(updateToken)({}); - expect(result.name).toBe(token.name); - expect(result.title).toBe(updateData.title); - expect(result.description).toBe(updateData.description); + mockWalletReturnValue(memberAddress, updateData); + const result = await testEnv.wrap(WEN_FUNC.updateToken); + token = (await build5Db().doc(COL.TOKEN, result.uid).get())!; + expect(token.name).toBe(token.name); + expect(token.title).toBe(updateData.title); + expect(token.description).toBe(updateData.description); }); it('Should throw, not owner', async () => { @@ -116,8 +105,13 @@ describe('Token controller: ' + WEN_FUNC.updateToken, () => { title: 'title', description: 'description', }; - mockWalletReturnValue(walletSpy, wallet.getRandomEthAddress(), updateData); - await expectThrow(testEnv.wrap(updateToken)({}), WenError.you_are_not_guardian_of_space.key); + const random = await testEnv.createMember(); + + mockWalletReturnValue(random, updateData); + await expectThrow( + testEnv.wrap(WEN_FUNC.updateToken), + WenError.you_are_not_guardian_of_space.key, + ); }); it('Should throw, not guardian', async () => { @@ -128,34 +122,33 @@ describe('Token controller: ' + WEN_FUNC.updateToken, () => { title: 'title', description: 'description', }; - mockWalletReturnValue(walletSpy, wallet.getRandomEthAddress(), updateData); - await expectThrow(testEnv.wrap(updateToken)({}), WenError.you_are_not_guardian_of_space.key); + const random = await testEnv.createMember(); + mockWalletReturnValue(random, updateData); + await expectThrow( + testEnv.wrap(WEN_FUNC.updateToken), + WenError.you_are_not_guardian_of_space.key, + ); }); it('Should update short description', async () => { const updateData = { ...data, name: token.name, uid: token.uid, title: 'title2' }; - mockWalletReturnValue(walletSpy, memberAddress, updateData); - - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).update({ status: TokenStatus.CANCEL_SALE }); - await expectThrow(testEnv.wrap(updateToken)({}), WenError.token_in_invalid_status.key); - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).update({ status: TokenStatus.BASE }); - await expectThrow(testEnv.wrap(updateToken)({}), WenError.token_in_invalid_status.key); - - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).update({ status: TokenStatus.AVAILABLE }); - const result = await testEnv.wrap(updateToken)({}); + await build5Db().doc(COL.TOKEN, token.uid).update({ status: TokenStatus.BASE }); + mockWalletReturnValue(memberAddress, updateData); + await expectThrow( + testEnv.wrap(WEN_FUNC.updateToken), + WenError.token_in_invalid_status.key, + ); + await build5Db().doc(COL.TOKEN, token.uid).update({ status: TokenStatus.AVAILABLE }); + mockWalletReturnValue(memberAddress, updateData); + const result = await testEnv.wrap(WEN_FUNC.updateToken); expect(result.name).toBe(token.name); }); it('Should throw, token minted', async () => { - await build5Db().doc(`${COL.TOKEN}/${token.uid}`).update({ status: TokenStatus.MINTED }); - const updateData = { - ...data, - name: 'TokenName2', - uid: token.uid, - title: 'title', - }; - mockWalletReturnValue(walletSpy, memberAddress, updateData); - await expectThrow(testEnv.wrap(updateToken)({}), WenError.invalid_params.key); + await build5Db().doc(COL.TOKEN, token.uid).update({ status: TokenStatus.MINTED }); + const updateData = { ...data, name: 'TokenName2', uid: token.uid, title: 'title' }; + mockWalletReturnValue(memberAddress, updateData); + await expectThrow(testEnv.wrap(WEN_FUNC.updateToken), WenError.invalid_params.key); }); }); diff --git a/packages/functions/test/controls/token/token.vote.spec.ts b/packages/functions/test/controls/token/token.vote.spec.ts index 1244ec4e50..9f4d231b56 100644 --- a/packages/functions/test/controls/token/token.vote.spec.ts +++ b/packages/functions/test/controls/token/token.vote.spec.ts @@ -4,26 +4,16 @@ import { NetworkAddress, Space, SUB_COL, + Token, TokenAllocation, TokenStats, + Vote, + WEN_FUNC, WenError, } from '@build-5/interfaces'; -import { createToken } from '../../../src/runtime/firebase/token/base'; -import { voteController } from '../../../src/runtime/firebase/vote'; -import * as wallet from '../../../src/utils/wallet.utils'; -import { MEDIA, testEnv } from '../../set-up'; -import { - createMember, - createSpace, - expectThrow, - getRandomSymbol, - mockWalletReturnValue, - setProdTiers, - setTestTiers, - wait, -} from '../common'; - -let walletSpy: any; +import { getRandomEthAddress } from '../../../src/utils/wallet.utils'; +import { MEDIA, mockWalletReturnValue, testEnv } from '../../set-up'; +import { expectThrow, getRandomSymbol, setProdTiers, setTestTiers, wait } from '../common'; const dummyToken = (space: string) => ({ @@ -45,45 +35,44 @@ describe('Token vote test', () => { let token: any; beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - memberAddress = await createMember(walletSpy); - space = await createSpace(walletSpy, memberAddress); - mockWalletReturnValue(walletSpy, memberAddress, dummyToken(space.uid)); - token = await testEnv.wrap(createToken)({}); + memberAddress = await testEnv.createMember(); + space = await testEnv.createSpace(memberAddress); + mockWalletReturnValue(memberAddress, dummyToken(space.uid)); + token = await testEnv.wrap(WEN_FUNC.createToken); }); it('Should throw, no token', async () => { - mockWalletReturnValue(walletSpy, memberAddress, { + mockWalletReturnValue(memberAddress, { collection: COL.TOKEN, - uid: wallet.getRandomEthAddress(), + uid: getRandomEthAddress(), direction: 1, }); - await expectThrow(testEnv.wrap(voteController)({}), WenError.token_does_not_exist.key); + await expectThrow(testEnv.wrap(WEN_FUNC.voteController), WenError.token_does_not_exist.key); }); it('Should throw, invalid direction', async () => { - mockWalletReturnValue(walletSpy, memberAddress, { + mockWalletReturnValue(memberAddress, { collection: COL.TOKEN, uid: token.uid, direction: 2, }); - await expectThrow(testEnv.wrap(voteController)({}), WenError.invalid_params.key); + await expectThrow(testEnv.wrap(WEN_FUNC.voteController), WenError.invalid_params.key); }); it('Should throw, no soons staked', async () => { - mockWalletReturnValue(walletSpy, memberAddress, { + await setProdTiers(); + mockWalletReturnValue(memberAddress, { collection: COL.TOKEN, uid: token.uid, direction: 1, }); - await setProdTiers(); - await expectThrow(testEnv.wrap(voteController)({}), WenError.no_staked_soon.key); + await expectThrow(testEnv.wrap(WEN_FUNC.voteController), WenError.no_staked_soon.key); await setTestTiers(); }); const validateStats = async (upvotes: number, downvotes: number, diff: number) => { await wait(async () => { - const statsDocRef = build5Db().doc(`${COL.TOKEN}/${token.uid}/${SUB_COL.STATS}/${token.uid}`); + const statsDocRef = build5Db().doc(COL.TOKEN, token.uid, SUB_COL.STATS, token.uid); const stats = await statsDocRef.get(); return ( stats?.votes?.upvotes === upvotes && @@ -94,12 +83,13 @@ describe('Token vote test', () => { }; const sendVote = async (direction: number) => { - mockWalletReturnValue(walletSpy, memberAddress, { + mockWalletReturnValue(memberAddress, { collection: COL.TOKEN, uid: token.uid, direction, }); - const vote = await testEnv.wrap(voteController)({}); + const vote = await testEnv.wrap(WEN_FUNC.voteController); + expect(vote.uid).toBe(memberAddress); expect(vote.parentId).toBe(token.uid); expect(vote.parentCol).toBe(COL.TOKEN); @@ -112,13 +102,13 @@ describe('Token vote test', () => { await sendVote(-1); await validateStats(0, 1, -1); - - mockWalletReturnValue(walletSpy, memberAddress, { + mockWalletReturnValue(memberAddress, { collection: COL.TOKEN, uid: token.uid, direction: 0, }); - const vote = await testEnv.wrap(voteController)({}); - expect(vote).toBe(undefined); + const vote = await testEnv.wrap(WEN_FUNC.voteController); + + expect(vote).toEqual({}); }); }); diff --git a/packages/functions/test/controls/workflow-online.spec.ts b/packages/functions/test/controls/workflow-online.spec.ts deleted file mode 100644 index 5cbfd1f89a..0000000000 --- a/packages/functions/test/controls/workflow-online.spec.ts +++ /dev/null @@ -1,22 +0,0 @@ -import fs from 'fs'; - -describe('Workflow test', () => { - it('Test if workflow contains all files', async () => { - const buffer = fs.readFileSync('../../.github/workflows/functions_online-emulated-tests.yml'); - const workflowTxt = buffer.toString(); - - const glob = require('glob'); - const testFileNames = glob - .sync(`./test/**/*.spec.ts`) - .filter((f: any) => !f.includes('exclude')) - .filter((f: any) => !f.includes('only.spec.ts')) - .filter((f: any) => !f.includes('dbRoll')); - for (const testFileName of testFileNames) { - if (!workflowTxt.includes(testFileName)) { - throw Error( - `Action misses the following file: ${testFileName}. Pls run node workflow.build.js`, - ); - } - } - }); -}); diff --git a/packages/functions/test/controls/workflow.spec.ts b/packages/functions/test/controls/workflow.spec.ts index 685388bfd3..25f0f0b65a 100644 --- a/packages/functions/test/controls/workflow.spec.ts +++ b/packages/functions/test/controls/workflow.spec.ts @@ -4,7 +4,6 @@ describe('Workflow test', () => { it('Test if workflow contains all files', async () => { const buffer = fs.readFileSync('../../.github/workflows/functions_emulated-tests.yml'); const workflowTxt = buffer.toString(); - const glob = require('glob'); const testFileNames = glob .sync(`./test/**/*.spec.ts`) diff --git a/packages/functions/test/cron/floor-price.cron.only.spec.ts b/packages/functions/test/cron/floor-price.cron.only.spec.ts index c7e3d5a277..f26a9302aa 100644 --- a/packages/functions/test/cron/floor-price.cron.only.spec.ts +++ b/packages/functions/test/cron/floor-price.cron.only.spec.ts @@ -3,6 +3,7 @@ import { COL, Collection, MIN_IOTA_AMOUNT, + Nft, NftAccess, NftAvailable, SOON_PROJECT_ID, @@ -13,13 +14,8 @@ import { getRandomEthAddress } from '../../src/utils/wallet.utils'; describe('Collection floor price', () => { it('Should set collection floor price', async () => { const collection = getRandomEthAddress(); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${collection}`); - await collectionDocRef.create({ - project: SOON_PROJECT_ID, - uid: collection, - name: 'asd', - }); - + const collectionDocRef = build5Db().doc(COL.COLLECTION, collection); + await collectionDocRef.create({ project: SOON_PROJECT_ID, name: 'name' } as Collection); const promises = [ NftAvailable.AUCTION, NftAvailable.SALE, @@ -34,17 +30,16 @@ describe('Collection floor price', () => { saleAccess: NftAccess.OPEN, availablePrice: i * MIN_IOTA_AMOUNT, }; - await build5Db().doc(`${COL.NFT}/${nft.uid}`).create(nft); + await build5Db() + .doc(COL.NFT, nft.uid) + .create(nft as Nft); return nft; }); const nfts = await Promise.all(promises); - await updateFloorPriceOnCollections(); - let collectionData = await collectionDocRef.get(); expect(collectionData.floorPrice).toBe(MIN_IOTA_AMOUNT); - - await build5Db().doc(`${COL.NFT}/${nfts[1].uid}`).delete(); + await build5Db().doc(COL.NFT, nfts[1].uid).delete(); await updateFloorPriceOnCollections(); collectionData = await collectionDocRef.get(); expect(collectionData.floorPrice).toBe(2 * MIN_IOTA_AMOUNT); diff --git a/packages/functions/test/cron/nft-stake.cron.spec.ts b/packages/functions/test/cron/nft-stake.cron.spec.ts index ae5653f62f..13c4d955eb 100644 --- a/packages/functions/test/cron/nft-stake.cron.spec.ts +++ b/packages/functions/test/cron/nft-stake.cron.spec.ts @@ -6,16 +6,16 @@ import { dateToTimestamp } from '../../src/utils/dateTime.utils'; import { getRandomEthAddress } from '../../src/utils/wallet.utils'; describe('Expired nft stake cron', () => { + beforeAll(() => {}); it('Should process expired nft stake', async () => { const collection = getRandomEthAddress(); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${collection}`); + const collectionDocRef = build5Db().doc(COL.COLLECTION, collection); await collectionDocRef.create({ project: SOON_PROJECT_ID, uid: collection, - name: 'asd', + name: 'name', stakedNft: 2, - }); - + } as Collection); let nftStake: NftStake = { project: SOON_PROJECT_ID, uid: getRandomEthAddress(), @@ -33,17 +33,13 @@ describe('Expired nft stake cron', () => { uid: getRandomEthAddress(), expiresAt: dateToTimestamp(dayjs().add(2, 'd')), }; - await build5Db().doc(`${COL.NFT_STAKE}/${nonExpiredStake.uid}`).create(nonExpiredStake); - - const stakeDocRef = build5Db().doc(`${COL.NFT_STAKE}/${nftStake.uid}`); + await build5Db().doc(COL.NFT_STAKE, nonExpiredStake.uid).create(nonExpiredStake); + const stakeDocRef = build5Db().doc(COL.NFT_STAKE, nftStake.uid); await stakeDocRef.create(nftStake); - const promises = [processExpiredNftStakes(), processExpiredNftStakes()]; await Promise.all(promises); - const collectionData = await collectionDocRef.get(); expect(collectionData.stakedNft).toBe(1); - nftStake = await stakeDocRef.get(); expect(nftStake.expirationProcessed).toBe(true); }); diff --git a/packages/functions/test/cron/proposal.cron.spec.ts b/packages/functions/test/cron/proposal.cron.spec.ts index aa3ce39119..7dc707e981 100644 --- a/packages/functions/test/cron/proposal.cron.spec.ts +++ b/packages/functions/test/cron/proposal.cron.spec.ts @@ -1,5 +1,5 @@ import { build5Db } from '@build-5/database'; -import { COL, SOON_PROJECT_ID } from '@build-5/interfaces'; +import { COL, ProposalType, SOON_PROJECT_ID } from '@build-5/interfaces'; import dayjs from 'dayjs'; import { markExpiredProposalCompleted } from '../../src/cron/proposal.cron'; import { dateToTimestamp } from '../../src/utils/dateTime.utils'; @@ -10,10 +10,14 @@ describe('Set proposal completed', () => { const member = getRandomEthAddress(); const count = 600; const ids = Array.from(Array(count)).map(() => getRandomEthAddress()); - let batch = build5Db().batch(); for (let i = 0; i < count; ++i) { const proposal = { + name: 'proposal', + space: getRandomEthAddress(), + description: 'name', + type: ProposalType.ADD_GUARDIAN, + questions: [], project: SOON_PROJECT_ID, uid: ids[i], settings: { @@ -23,7 +27,7 @@ describe('Set proposal completed', () => { createdBy: member, completed: i < 550, }; - const docRef = build5Db().doc(`${COL.PROPOSAL}/${proposal.uid}`); + const docRef = build5Db().doc(COL.PROPOSAL, proposal.uid); batch.create(docRef, proposal); if (i > 0 && i % 499 === 0) { await batch.commit(); @@ -31,16 +35,13 @@ describe('Set proposal completed', () => { } } await batch.commit(); - await markExpiredProposalCompleted(); - const completed = await build5Db() .collection(COL.PROPOSAL) .where('createdBy', '==', member) .where('completed', '==', true) .get(); expect(completed.length).toBe(550); - const inProgress = await build5Db() .collection(COL.PROPOSAL) .where('createdBy', '==', member) diff --git a/packages/functions/test/notifier.ts b/packages/functions/test/notifier.ts new file mode 100644 index 0000000000..33e98fa082 --- /dev/null +++ b/packages/functions/test/notifier.ts @@ -0,0 +1,156 @@ +require('dotenv').config({ path: (__dirname + '/.env').replace('test/', '') }); +import { COL, getMilestoneCol, Network, SUB_COL } from '@build-5/interfaces'; +import { PubSub } from '@google-cloud/pubsub'; +import { Client } from '@iota/sdk'; +import axios from 'axios'; +import dayjs from 'dayjs'; +import Knex from 'knex'; +import { head, uniq } from 'lodash'; + +const knex = Knex({ + client: 'pg', + connection: { + user: process.env.DB_USER, + password: process.env.DB_USER_PWD, + database: process.env.DB_NAME, + host: process.env.DB_HOST, + port: Number(process.env.DB_PORT), + }, +}); + +const upsertQueue: any[] = []; + +const cleanAllTables = async () => { + const tables = await knex('information_schema.tables') + .select('table_name') + .where('table_schema', 'public'); // Filter by schema if needed + + for (const table of tables.map((row) => row.table_name)) { + if (table.includes('knex')) { + continue; + } + await knex(table).delete(); + } +}; + +const notifier = async () => { + await cleanAllTables(); + const connection = await knex.client.acquireConnection(); + + connection.query(`LISTEN trigger`); + connection.query(`LISTEN blocks`); + connection.query(`LISTEN onupsert`); + + connection.on('notification', async (data: any) => { + if (data.channel === 'blocks') { + await onBlockCreated(data); + return; + } + + if (data.channel === 'trigger') { + const [channel, changeId] = data.payload.split(':'); + if (channel === 'ontransactionwrite') { + await transactionToBlock(changeId); + } + await notifyTriggers(channel, changeId); + return; + } + + if (data.channel === 'onupsert') { + upsertQueue.push(JSON.parse(data.payload)); + } + }); + + process.stdin.resume(); +}; + +const notifyTriggers = async (channel: string, changeId: string) => { + const body = { message: { data: btoa(JSON.stringify({ processId: Number(changeId) })) } }; + + let error: any = undefined; + for (let i = 0; i < 5; ++i) { + try { + await axios.post('http://localhost:8080/' + channel, body, { + headers: { 'Content-Type': 'application/json' }, + timeout: 3 * 60000, + }); + return; + } catch (err: any) { + error = err; + await new Promise((resolve) => setTimeout(resolve, 1000)); + } + } + throw error; +}; + +const client = new Client({ nodes: ['https://rms1.svrs.io/'] }); + +const onBlockCreated = async (data: any) => { + const blockId = data.payload; + + const metadata = await getBlockMetadata(blockId); + if (metadata?.ledgerInclusionState !== 'included') { + return; + } + const block = await client.getBlock(blockId); + + await knex(`${getMilestoneCol(Network.RMS)}_${SUB_COL.TRANSACTIONS}`).insert({ + uid: blockId, + blockId, + parentId: metadata.referencedByMilestoneIndex + '', + milestone: metadata.referencedByMilestoneIndex + '', + createdOn: dayjs().toDate(), + payload: JSON.stringify(block.payload), + processed: false, + }); +}; + +const getBlockMetadata = async (blockId: string) => { + for (let attempt = 0; attempt < 1200; ++attempt) { + const metadata = await client.getBlockMetadata(blockId); + if (metadata.ledgerInclusionState) { + return metadata; + } + await new Promise((r) => setTimeout(r, 500)); + } + return; +}; + +const transactionToBlock = async (changeId: string) => { + const doc = await knex('changes').where({ uid: Number(changeId) }); + const transactionId = head(doc).change.uid; + + const query = knex(COL.TRANSACTION).where({ uid: transactionId }); + const transaction = head(await query); + + const blockId = transaction.payload_walletReference_chainReference; + if (blockId && !blockId.startsWith('payment')) { + await knex('blocks').insert({ blockId }).onConflict().ignore(); + } +}; + +const pubSub = new PubSub(); + +const upserTopic = pubSub.topic('onupsert'); + +const postDataToPubSub = async () => { + const data = uniq(upsertQueue.splice(0)); + + const promises = data.map(async (d) => { + const pKey = d.parentId ? { uid: d.uid, parentId: d.parentId } : { uid: d.uid }; + const snap = head(await knex(d.table).where(pKey)); + if (!snap) { + return; + } + await upserTopic.publishMessage({ + data: Buffer.from(JSON.stringify(snap)), + attributes: { table: d.table }, + }); + }); + + await Promise.all(promises); +}; + +setInterval(postDataToPubSub, 500); + +notifier(); diff --git a/packages/functions/test/set-up.ts b/packages/functions/test/set-up.ts index e84f3ed0d4..15ef4c8721 100644 --- a/packages/functions/test/set-up.ts +++ b/packages/functions/test/set-up.ts @@ -1,158 +1,139 @@ +require('dotenv').config({ path: (__dirname + '/.env').replace('test/', '') }); import { build5Db } from '@build-5/database'; import { - Build5Request, COL, - MIN_IOTA_AMOUNT, Network, - ProjectAdmin, - ProjectBilling, SOON_PROJECT_ID, - SUB_COL, SendToManyTargets, - TokenStatus, + Space, + WEN_FUNC, } from '@build-5/interfaces'; -import dayjs from 'dayjs'; -import dotenv from 'dotenv'; -import express from 'express'; -import test from 'firebase-functions-test'; -import * as functions from 'firebase-functions/v2'; -import { isEmpty } from 'lodash'; +import { CoinType, utf8ToHex } from '@iota/sdk'; +import axios from 'axios'; +import { generateCustomTokenControl } from '../src/controls/auth/auth.control'; +import { Context } from '../src/controls/common'; +import { createMemberControl } from '../src/controls/member/member.create'; +import { MnemonicService } from '../src/services/wallet/mnemonic'; import { Wallet, WalletParams } from '../src/services/wallet/wallet'; import { AddressDetails, WalletService } from '../src/services/wallet/wallet.service'; -import { dateToTimestamp } from '../src/utils/dateTime.utils'; +import { getSecretManager } from '../src/utils/secret.manager.utils'; +import { getRandomEthAddress } from '../src/utils/wallet.utils'; -dotenv.config({ path: '.env.local' }); - -export const projectId = 'soonaverse-dev'; -process.env.GCLOUD_PROJECT = projectId; - -export const getConfig = () => { - if (process.env.LOCAL_TEST) { - process.env.FIRESTORE_EMULATOR_HOST = '127.0.0.1:8080'; - process.env.FIREBASE_STORAGE_EMULATOR_HOST = '127.0.0.1:9199'; - return { - projectId, - storageBucket: 'soonaverse-dev.appspot.com', - }; - } - return { - databaseURL: `https://${projectId}.firebaseio.com`, - projectId, - storageBucket: 'soonaverse-dev.appspot.com', - }; -}; +const tokens: { [key: string]: string } = {}; export const PROJECT_API_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwcm9qZWN0IjoiMHg0NjIyM2VkZDQxNTc2MzVkZmM2Mzk5MTU1NjA5ZjMwMWRlY2JmZDg4IiwiaWF0IjoxNjk5MjgyMTQxfQ.Bd0IZNdtc3ne--CC1Bk5qDgWl4NojAsX64K1rCj-5Co'; -export const sendOnRequest = - (func: (req: functions.https.Request, response: express.Response) => void | Promise) => - async (body: any, address = '', customToken = '') => { - const wenReq: Build5Request = { - address, - customToken, - projectApiKey: PROJECT_API_KEY, - body, - }; - const req = { - ip: '127.0.0.1', - body: wenReq, - headers: { origin: true }, - } as any; - let error = false; - let response: any = undefined; - const res = { - status: (code: number) => { - if (code !== 200) { - error = true; - } - }, - send: (res: any) => { - response = res; - }, - setHeader: (key: any, value: any) => {}, - getHeader: (key: any) => {}, - } as any; - await func(req, res); - - for (let attempt = 0; attempt < 5000; ++attempt) { - if (response !== undefined) { - break; - } - await new Promise((r) => setTimeout(r, 100)); - } - - if (error) { - throw response; - } - return isEmpty(response) ? undefined : response; - }; - -export const testEnv = { - config: process.env.LOCAL_TEST - ? test(getConfig()) - : test(getConfig(), './test-service-account-key.json'), - wrap: sendOnRequest, +const mockk = { + address: '', + body: {} as any, + token: undefined as string | undefined, + projectApiKey: PROJECT_API_KEY, }; -export const MEDIA = - 'https://images-wen.soonaverse.com/0x0275dfc7c2624c0111d441a0819dccfd5e947c89%2F6stvhnutvg%2Ftoken_introductionary'; - -export const SOON_PROJ_GUARDIAN = '0x3d5d0b3f40c9438871b1c43d6b70117eeff77ad8'; +export const mockWalletReturnValue = ( + address: string, + body: any, + token?: string, + projectApiKey?: string, +) => { + mockk.address = address; + mockk.body = body; + mockk.token = token; + mockk.projectApiKey = projectApiKey !== undefined ? projectApiKey : PROJECT_API_KEY; +}; -export const soonTokenId = '0xa381bfccaf121e38e31362d85b5ad30cd7fc0d06'; -export const rmsTokenId = '0x52f27a34170900537acb61e5ff0fe94a2841ff52'; -export const atoiTokenId = '0x9c119bd60f7cadf3406c43cead6c8723012bca27'; +export const testEnv = { + wrap: async (func: WEN_FUNC) => { + try { + let request = { + address: mockk.address, + projectApiKey: mockk.projectApiKey, + signature: '', + publicKey: {}, + customToken: mockk.token || tokens[mockk.address], + body: mockk.body || {}, + }; + if (!request.customToken) { + const memberDocRef = build5Db().doc(COL.MEMBER, mockk.address); + const member = await memberDocRef.get(); + const mnemonic = await MnemonicService.get(mockk.address); + const secretManager = getSecretManager(mnemonic); + const signature = await secretManager.signEd25519(utf8ToHex(member?.nonce!), { + coinType: CoinType.IOTA, + }); + request = { + address: mockk.address, + projectApiKey: mockk.projectApiKey, + signature: signature.signature, + publicKey: { hex: signature.publicKey, network: Network.RMS }, + customToken: '', + body: mockk.body || {}, + }; + } + const payload = JSON.stringify(request, (_key, value) => + value === undefined ? null : value, + ); + const response = await axios.post('http://localhost:8080/' + func, payload, { + headers: { 'Content-Type': 'application/json' }, + }); + return response.data as T; + } catch (err: any) { + if (err.response?.data) { + throw err.response?.data; + } + throw err; + } + }, -const setup = async () => { - await build5Db().doc(`${COL.TOKEN}/${soonTokenId}`).set({ - project: SOON_PROJECT_ID, - uid: soonTokenId, - symbol: 'SOON', - }); - await build5Db() - .doc(`${COL.TOKEN}/${rmsTokenId}`) - .set({ + mockWrap: async (func: (context: Context) => Promise) => { + const request = { + ip: '127.0.0.1', + owner: mockk.address, + params: mockk.body || {}, project: SOON_PROJECT_ID, - symbol: 'RMS', - approved: true, - space: '', - uid: rmsTokenId, - name: 'RMS token', - status: TokenStatus.BASE, - access: 0, - icon: MEDIA, - mintingData: { - network: Network.RMS, - }, + headers: {}, + rawBody: {}, + }; + return (await func(request)) as T; + }, + + createMember: async () => { + const owner = getRandomEthAddress(); + mockWalletReturnValue(owner, undefined); + await testEnv.mockWrap(createMemberControl); + mockWalletReturnValue(owner, undefined); + const token = await testEnv.mockWrap(generateCustomTokenControl); + tokens[owner] = token; + const addresses = {} as any; + const promises = Object.values(Network).map(async (network) => { + const wallet = await getWallet(network); + const address = await wallet.getNewIotaAddressDetails(); + addresses[`${network}Address`] = address.bech32; }); - - const soonProject = { - uid: SOON_PROJECT_ID, - name: 'Soonaverse', - createdBy: SOON_PROJ_GUARDIAN, - deactivated: false, - config: { - billing: ProjectBilling.TOKEN_BASE, - tiers: [0, 0, 0, 0, 0].map((v) => v * MIN_IOTA_AMOUNT), - tokenTradingFeeDiscountPercentage: [0, 0, 0, 0, 0], - nativeTokenSymbol: 'SOON', - nativeTokenUid: soonTokenId, - }, - }; - const soonProjDocRef = build5Db().doc(`${COL.PROJECT}/${soonProject.uid}`); - await soonProjDocRef.set(soonProject); - - const adminDocRef = soonProjDocRef.collection(SUB_COL.ADMINS).doc(SOON_PROJ_GUARDIAN); - const admin: ProjectAdmin = { - uid: SOON_PROJ_GUARDIAN, - createdOn: dateToTimestamp(dayjs()), - parentCol: COL.PROJECT, - parentId: SOON_PROJECT_ID, - }; - await adminDocRef.set(admin); - - console.log('Setup env'); + await Promise.all(promises); + await build5Db().doc(COL.MEMBER, owner).update(addresses); + return owner; + }, + + createSpace: async (member: string) => { + mockWalletReturnValue(member, { name: 'Space A', bannerUrl: MEDIA }); + const space = await testEnv.wrap(WEN_FUNC.createSpace); + + const addresses = {} as any; + const promises = Object.values(Network).map(async (network) => { + const wallet = await getWallet(network); + const address = await wallet.getNewIotaAddressDetails(); + addresses[`${network}Address`] = address.bech32; + }); + await Promise.all(promises); + await build5Db().doc(COL.SPACE, space.uid).update(addresses); + return (await build5Db().doc(COL.SPACE, space.uid).get())!; + }, + + createBlock: async (blockId: string) => { + await build5Db().getCon()('blocks').insert({ blockId }); + }, }; export const wallets: { [key: string]: Wallet } = {}; @@ -166,7 +147,6 @@ class TestWallet extends Wallet { public getNewIotaAddressDetails = this.wallet.getNewIotaAddressDetails; public getIotaAddressDetails = this.wallet.getIotaAddressDetails; public getAddressDetails = this.wallet.getAddressDetails; - public bechAddressFromOutput = this.wallet.bechAddressFromOutput; public getOutputs = this.wallet.getOutputs; public creditLocked = this.wallet.creditLocked; @@ -179,16 +159,17 @@ class TestWallet extends Wallet { outputToConsume?: string | undefined, ) => { const blockId = await this.wallet.send(from, toAddress, amount, params, outputToConsume); - await build5Db().doc(`blocks/${blockId}`).create({ blockId }); + await build5Db().getCon()('blocks').insert({ blockId }); return blockId; }; + public sendToMany = async ( from: AddressDetails, targets: SendToManyTargets[], params: WalletParams, ) => { const blockId = await this.wallet.sendToMany(from, targets, params); - await build5Db().doc(`blocks/${blockId}`).create({ blockId }); + await build5Db().getCon()('blocks').insert({ blockId }); return blockId; }; } @@ -202,4 +183,9 @@ export const getWallet = async (network: Network) => { return wallets[network]; }; -export default setup; +export const MEDIA = + 'https://images-wen.soonaverse.com/0x0275dfc7c2624c0111d441a0819dccfd5e947c89%2F6stvhnutvg%2Ftoken_introductionary'; +export const SOON_PROJ_GUARDIAN = '0x3d5d0b3f40c9438871b1c43d6b70117eeff77ad8'; +export const soonTokenId = '0xa381bfccaf121e38e31362d85b5ad30cd7fc0d06'; +export const rmsTokenId = '0x52f27a34170900537acb61e5ff0fe94a2841ff52'; +export const atoiTokenId = '0x9c119bd60f7cadf3406c43cead6c8723012bca27'; diff --git a/packages/functions/test/stake/delete.stake.reward.spec.ts b/packages/functions/test/stake/delete.stake.reward.spec.ts index 8c6d401ac6..18e1d8322e 100644 --- a/packages/functions/test/stake/delete.stake.reward.spec.ts +++ b/packages/functions/test/stake/delete.stake.reward.spec.ts @@ -7,24 +7,15 @@ import { Space, StakeReward, StakeRewardStatus, + Token, + WEN_FUNC, WenError, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { voteOnProposal } from '../../src/runtime/firebase/proposal'; -import { removeStakeReward } from '../../src/runtime/firebase/stake'; import { dateToTimestamp } from '../../src/utils/dateTime.utils'; import * as wallet from '../../src/utils/wallet.utils'; -import { - addGuardianToSpace, - createMember, - createSpace, - expectThrow, - mockWalletReturnValue, - wait, -} from '../controls/common'; -import { testEnv } from '../set-up'; - -let walletSpy: any; +import { addGuardianToSpace, expectThrow, wait } from '../controls/common'; +import { mockWalletReturnValue, testEnv } from '../set-up'; describe('Delete stake reward', () => { let guardian: string; @@ -33,19 +24,20 @@ describe('Delete stake reward', () => { let token: string; beforeEach(async () => { - walletSpy = jest.spyOn(wallet, 'decodeAuth'); - guardian = await createMember(walletSpy); - member = await createMember(walletSpy); - space = await createSpace(walletSpy, guardian); + guardian = await testEnv.createMember(); + member = await testEnv.createMember(); + space = await testEnv.createSpace(guardian); await addGuardianToSpace(space.uid, member); token = wallet.getRandomEthAddress(); - await build5Db().doc(`${COL.TOKEN}/${token}`).create({ - project: SOON_PROJECT_ID, - uid: token, - space: space.uid, - }); + await build5Db() + .doc(COL.TOKEN, token) + .create({ + project: SOON_PROJECT_ID, + space: space.uid, + links: [] as URL[], + } as Token); }); const createStakeRewards = async () => { @@ -73,14 +65,14 @@ describe('Delete stake reward', () => { }, ]; for (const stakeReward of stakeRewards) { - await build5Db().doc(`${COL.STAKE_REWARD}/${stakeReward.uid}`).create(stakeReward); + await build5Db().doc(COL.STAKE_REWARD, stakeReward.uid).create(stakeReward); } return stakeRewards; }; const getStakeRewards = async (stakeRewardIds: string[]) => { const promises = stakeRewardIds.map(async (stakeRewardId) => { - const docRef = build5Db().doc(`${COL.STAKE_REWARD}/${stakeRewardId}`); + const docRef = build5Db().doc(COL.STAKE_REWARD, stakeRewardId); return await docRef.get(); }); return await Promise.all(promises); @@ -89,10 +81,9 @@ describe('Delete stake reward', () => { it('Should create proposal and delete stake reward', async () => { const stakeRewards = await createStakeRewards(); const stakeRewardIds = stakeRewards.map((reward) => reward.uid); - mockWalletReturnValue(walletSpy, guardian, { - stakeRewardIds, - }); - let proposal: Proposal = await testEnv.wrap(removeStakeReward)({}); + mockWalletReturnValue(guardian, { stakeRewardIds }); + let proposal = await testEnv.wrap(WEN_FUNC.removeStakeReward); + proposal = (await build5Db().doc(COL.PROPOSAL, proposal.uid).get())!; expect(proposal.settings.stakeRewardIds!.sort()).toEqual(stakeRewardIds.sort()); expect( dayjs(proposal.settings.endDate.toDate()).isSame(dayjs(stakeRewards[1].startDate.toDate())), @@ -117,8 +108,8 @@ describe('Delete stake reward', () => { `| ${stakeRewards[0].tokensToDistribute} |`, ); - mockWalletReturnValue(walletSpy, member, { uid: proposal.uid, value: 1 }); - await testEnv.wrap(voteOnProposal)({}); + mockWalletReturnValue(member, { uid: proposal.uid, value: 1 }); + await testEnv.wrap(WEN_FUNC.voteOnProposal); await new Promise((resolve) => setTimeout(resolve, 1000)); await wait(async () => { @@ -130,48 +121,48 @@ describe('Delete stake reward', () => { return allDeleted; }); - proposal = await build5Db().doc(`${COL.PROPOSAL}/${proposal.uid}`).get(); + proposal = await build5Db().doc(COL.PROPOSAL, proposal.uid).get(); expect(dayjs(proposal.settings.endDate.toDate()).isBefore(dayjs())).toBe(true); }); it('Should throw, not guardian', async () => { - const tmp = await createMember(walletSpy); + const tmp = await testEnv.createMember(); const stakeRewards = await createStakeRewards(); const stakeRewardIds = stakeRewards.map((reward) => reward.uid); - mockWalletReturnValue(walletSpy, tmp, { stakeRewardIds }); + mockWalletReturnValue(tmp, { stakeRewardIds }); await expectThrow( - testEnv.wrap(removeStakeReward)({}), + testEnv.wrap(WEN_FUNC.removeStakeReward), WenError.you_are_not_guardian_of_space.key, ); }); it('Should throw, multiple tokens', async () => { const stakeRewards = await createStakeRewards(); - await build5Db().doc(`${COL.STAKE_REWARD}/${stakeRewards[0].uid}`).update({ token: 'asd' }); + await build5Db().doc(COL.STAKE_REWARD, stakeRewards[0].uid).update({ token: 'name' }); const stakeRewardIds = stakeRewards.map((reward) => reward.uid); - mockWalletReturnValue(walletSpy, guardian, { stakeRewardIds }); - await expectThrow(testEnv.wrap(removeStakeReward)({}), WenError.invalid_params.key); + mockWalletReturnValue(guardian, { stakeRewardIds }); + await expectThrow(testEnv.wrap(WEN_FUNC.removeStakeReward), WenError.invalid_params.key); }); it('Should throw, 2 ongoing proposals', async () => { const stakeRewards = await createStakeRewards(); const stakeRewardIds = stakeRewards.map((reward) => reward.uid); - mockWalletReturnValue(walletSpy, guardian, { stakeRewardIds }); - await testEnv.wrap(removeStakeReward)({}); + mockWalletReturnValue(guardian, { stakeRewardIds }); + await testEnv.wrap(WEN_FUNC.removeStakeReward); - mockWalletReturnValue(walletSpy, guardian, { stakeRewardIds }); - await expectThrow(testEnv.wrap(removeStakeReward)({}), WenError.ongoing_proposal.key); + mockWalletReturnValue(guardian, { stakeRewardIds }); + await expectThrow(testEnv.wrap(WEN_FUNC.removeStakeReward), WenError.ongoing_proposal.key); }); it('Should throw, stake reward expired', async () => { const stakeRewards = await createStakeRewards(); - const docRef = build5Db().doc(`${COL.STAKE_REWARD}/${stakeRewards[1].uid}`); - await docRef.update({ startDate: dateToTimestamp(dayjs().subtract(1, 'm')) }); + const docRef = build5Db().doc(COL.STAKE_REWARD, stakeRewards[1].uid); + await docRef.update({ startDate: dayjs().subtract(1, 'm').toDate() }); const stakeRewardIds = stakeRewards.map((reward) => reward.uid); - mockWalletReturnValue(walletSpy, guardian, { + mockWalletReturnValue(guardian, { stakeRewardIds, }); - await expectThrow(testEnv.wrap(removeStakeReward)({}), WenError.stake_reward_started.key); + await expectThrow(testEnv.wrap(WEN_FUNC.removeStakeReward), WenError.stake_reward_started.key); }); }); diff --git a/packages/functions/test/stake/stake.reward.cron.spec.ts b/packages/functions/test/stake/stake.reward.cron.spec.ts index 8ad6a2d130..053ff695b3 100644 --- a/packages/functions/test/stake/stake.reward.cron.spec.ts +++ b/packages/functions/test/stake/stake.reward.cron.spec.ts @@ -8,7 +8,6 @@ import { StakeType, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { getStakedPerMember } from '../../src/cron/stakeReward.cron'; import { dateToTimestamp } from '../../src/utils/dateTime.utils'; import { getRandomEthAddress } from '../../src/utils/wallet.utils'; @@ -145,7 +144,7 @@ describe('Stake reward cron: getStakedPerMember', () => { orderId: '', billPaymentId: '', }; - await build5Db().doc(`${COL.STAKE}/${stake.uid}`).create(stake); + await build5Db().doc(COL.STAKE, stake.uid).create(stake); return stake; }; @@ -160,7 +159,7 @@ describe('Stake reward cron: getStakedPerMember', () => { token, status: StakeRewardStatus.UNPROCESSED, } as StakeReward; - await build5Db().doc(`${COL.STAKE_REWARD}/${stakeReward.uid}`).create(stakeReward); + await build5Db().doc(COL.STAKE_REWARD, stakeReward.uid).create(stakeReward); return stakeReward; }; @@ -169,7 +168,9 @@ describe('Stake reward cron: getStakedPerMember', () => { await createStake(stake.createdOn, stake.expiresAt); } const stakeReward = await createReward(reward.startDate, reward.endDate); - const stakedPerMember = await getStakedPerMember(stakeReward); + const stakedPerMember = await build5Db() + .collection(COL.STAKE) + .getStakeSumPerMember(stakeReward); expect(stakedPerMember[member]).toBe(expectedValue || undefined); }); }); diff --git a/packages/functions/test/storage/resize.img.spec.ts b/packages/functions/test/storage/resize.img.spec.ts index 6558690e28..f1cdd930a4 100644 --- a/packages/functions/test/storage/resize.img.spec.ts +++ b/packages/functions/test/storage/resize.img.spec.ts @@ -1,21 +1,32 @@ import { build5Storage } from '@build-5/database'; import { Bucket, ImageWidth } from '@build-5/interfaces'; +import axios from 'axios'; +import { WEN_STORAGE_TRIGGER } from '../../src/runtime/common'; import { getRandomEthAddress } from '../../src/utils/wallet.utils'; import { wait } from '../controls/common'; +const triggerResizer = async (name: string, contentType: string) => { + try { + await axios.post( + 'http://localhost:8080/' + WEN_STORAGE_TRIGGER.onUploadFinalized, + { name, bucket: Bucket.DEV, contentType, metadata: {} }, + { headers: { 'Content-Type': 'application/json' } }, + ); + } catch (err) { + console.log(err); + } +}; + describe('Resize img test', () => { it('Should resize img', async () => { - const name = 'nft/test/image'; + const folder = getRandomEthAddress(); + const name = `nft/${folder}/image`; const extensions = Object.values(ImageWidth) .map((size) => `_jpeg_${size}X${size}.webp`) .concat('.jpeg'); - const bucket = build5Storage().bucket(Bucket.DEV); - const destination = 'nft/test/image.jpeg'; - await bucket.upload('./test/puppy.jpeg', destination, { - contentType: 'image/jpeg', - }); - + await bucket.upload('./test/puppy.jpeg', name + '.jpeg', { contentType: 'image/jpeg' }); + await triggerResizer(name + '.jpeg', 'image/jpeg'); for (const extension of extensions) { await wait( async () => @@ -30,9 +41,8 @@ describe('Resize img test', () => { const id = getRandomEthAddress(); const bucket = build5Storage().bucket(Bucket.DEV); const destination = `nft/test/${id}.mov`; - await bucket.upload('./test/nft_video.mov', destination, { - contentType: 'video/quicktime', - }); + await bucket.upload('./test/nft_video.mov', destination, { contentType: 'video/quicktime' }); + await triggerResizer(destination, 'video/quicktime'); await wait( async () => await build5Storage().bucket(Bucket.DEV).exists(`nft/test/${id}_mov_preview.webp`), @@ -41,11 +51,11 @@ describe('Resize img test', () => { it.each(['png', 'jpeg'])('Should not override', async (extension: string) => { const name = 'nft/test/image'; - const bucket = build5Storage().bucket(Bucket.DEV); await bucket.upload('./test/puppy.jpeg', 'nft/test/image.' + extension, { contentType: 'image/' + extension, }); + await triggerResizer('nft/test/image.' + extension, 'image/' + extension); const extensions = Object.values(ImageWidth) .map((size) => `_${extension}_${size}X${size}.webp`) .concat(`.${extension}`); diff --git a/packages/functions/test/teardown.ts b/packages/functions/test/teardown.ts index 88f744bba7..b463d454ec 100644 --- a/packages/functions/test/teardown.ts +++ b/packages/functions/test/teardown.ts @@ -1,34 +1,20 @@ import { build5Db } from '@build-5/database'; -import { BaseRecord, COL } from '@build-5/interfaces'; -import { isEmpty } from 'lodash'; +import axios from 'axios'; +import { tangleClients } from '../src/services/wallet/wallet.service'; +import { wallets } from './set-up'; -const collections = [ - COL.AWARD, - COL.COLLECTION, - COL.NFT, - COL.SPACE, - COL.PROPOSAL, - COL.TRANSACTION, - COL.BADGES, - COL.TOKEN, - COL.TOKEN_MARKET, - COL.TOKEN_PURCHASE, - COL.STAKE, - COL.STAKE_REWARD, - COL.NFT_STAKE, - COL.AIRDROP, -]; - -const teardown = async () => { - for (const collection of collections) { - const snap = await build5Db().collection(collection).get(); - for (const data of snap) { - if (isEmpty(data.project)) { - console.log(collection, data); - throw Error('Project not defined'); - } - } +afterAll(async () => { + await build5Db().destroy(); + for (const client of Object.values(wallets)) { + await client.client.destroy(); + } + for (const client of Object.values(tangleClients)) { + await client.destroy(); } -}; -export default teardown; + await new Promise((resolve) => setTimeout(resolve, 2000)); + const response = await axios.head('http://localhost:8080/'); + if (response.status !== 200) { + throw new Error('Server is not running'); + } +}); diff --git a/packages/functions/workflow.build.js b/packages/functions/workflow.build.js index 3d49993bf0..a987b51c3e 100644 --- a/packages/functions/workflow.build.js +++ b/packages/functions/workflow.build.js @@ -3,32 +3,19 @@ const fs = require('fs'); const { chunk } = require('lodash'); const tangleTestFile = '../../.github/workflows/functions_tangle-unit-tests.yml'; -const tangleOnlineTestFile = - '../../.github/workflows/functions_tangle-online-unit-tests_emulator.yml'; +('../../.github/workflows/functions_tangle-online-unit-tests_emulator.yml'); const emulatedTestFile = '../../.github/workflows/functions_emulated-tests.yml'; -const emulatedOnlineTestFile = '../../.github/workflows/functions_online-emulated-tests.yml'; const tangleTestFileName = 'Functions | Tangle - Emulated Unit Tests'; -const tangleOnlineTestFileName = 'Functions | Tangle - Online - Emulated Unit Tests'; const emulatedTestFileName = 'Functions | Emulated Unit Tests'; -const emulatedOnlineTestFileName = 'Functions | Online Emulated Unit Tests'; function setup(outputFile, title) { fs.writeFileSync(outputFile, `name: ${title}\n\n`); fs.appendFileSync(outputFile, 'on:\n'); fs.appendFileSync(outputFile, ' pull_request:\n'); fs.appendFileSync(outputFile, ' paths:\n'); - fs.appendFileSync(outputFile, ' - packages/functions/**\n\n'); -} - -function setupOnline(outputFile, title) { - fs.writeFileSync(outputFile, `name: ${title}\n\n`); - fs.appendFileSync(outputFile, 'on:\n'); - fs.appendFileSync(outputFile, ' workflow_run:\n'); - fs.appendFileSync(outputFile, ' workflows: ["Firebase Deploy DEV"]\n'); - fs.appendFileSync(outputFile, ' types: [completed]\n'); - fs.appendFileSync(outputFile, ' branches:\n'); - fs.appendFileSync(outputFile, ' - "develop"\n\n'); + fs.appendFileSync(outputFile, ' - packages/functions/**\n'); + fs.appendFileSync(outputFile, ' - packages/database/**\n\n'); } function init(outputFile) { @@ -36,14 +23,8 @@ function init(outputFile) { fs.appendFileSync(outputFile, ' npm-install:\n'); fs.appendFileSync(outputFile, ' runs-on: ubuntu-latest\n'); fs.appendFileSync(outputFile, ' timeout-minutes: 10\n'); + fs.appendFileSync(outputFile, ' steps:\n'); - // Foresight telemetry - // fs.appendFileSync(outputFile, ' - name: Collect Workflow Telemetry\n'); - // fs.appendFileSync(outputFile, ' uses: runforesight/foresight-workflow-kit-action@v1\n'); - // fs.appendFileSync(outputFile, ' if: ${{ always() }}\n'); - // fs.appendFileSync(outputFile, ' with:\n'); - // fs.appendFileSync(outputFile, ' api_key: ${{ secrets.FORESIGHT_KEY }}\n'); - // end fs.appendFileSync(outputFile, ' - uses: actions/checkout@v4\n'); fs.appendFileSync(outputFile, ' - uses: actions/setup-node@v4\n'); fs.appendFileSync(outputFile, ' with:\n'); @@ -64,19 +45,30 @@ function init(outputFile) { fs.appendFileSync(outputFile, ' run: npm run build:functions\n\n'); } -function job(outputFile, chunk, files, commandName) { +function job(outputFile, chunk, files) { fs.appendFileSync(outputFile, ` chunk_${chunk}:\n`); fs.appendFileSync(outputFile, ` needs: npm-install\n`); fs.appendFileSync(outputFile, ` runs-on: ubuntu-latest\n`); - fs.appendFileSync(outputFile, ` timeout-minutes: 20\n`); + fs.appendFileSync(outputFile, ` timeout-minutes: 20\n\n`); + + fs.appendFileSync(outputFile, ' services:\n'); + fs.appendFileSync(outputFile, ' postgres:\n'); + fs.appendFileSync(outputFile, ' image: postgres\n'); + fs.appendFileSync(outputFile, ' env:\n'); + fs.appendFileSync(outputFile, ' POSTGRES_DB: buildcore\n'); + fs.appendFileSync(outputFile, ' POSTGRES_PASSWORD: postgres\n'); + fs.appendFileSync(outputFile, ' POSTGRES_MAX_CONNECTIONS: 400\n'); + fs.appendFileSync(outputFile, ' ports:\n'); + fs.appendFileSync(outputFile, ' - 5432:5432\n'); + + fs.appendFileSync(outputFile, ' options: >-\n'); + fs.appendFileSync(outputFile, ' --health-cmd pg_isready\n'); + fs.appendFileSync(outputFile, ' --health-interval 10s\n'); + fs.appendFileSync(outputFile, ' --health-timeout 5s\n'); + fs.appendFileSync(outputFile, ' --health-retries 5\n\n'); + fs.appendFileSync(outputFile, ` steps:\n`); - // // Foresight telemetry - // fs.appendFileSync(outputFile, ' - name: Collect Workflow Telemetry\n'); - // fs.appendFileSync(outputFile, ' uses: runforesight/foresight-workflow-kit-action@v1\n'); - // fs.appendFileSync(outputFile, ' if: ${{ always() }}\n'); - // fs.appendFileSync(outputFile, ' with:\n'); - // fs.appendFileSync(outputFile, ' api_key: ${{ secrets.FORESIGHT_KEY }}\n'); - // end + fs.appendFileSync(outputFile, ` - uses: actions/checkout@v4\n`); fs.appendFileSync(outputFile, ` - uses: actions/setup-node@v4\n`); fs.appendFileSync(outputFile, ` with:\n`); @@ -93,64 +85,20 @@ function job(outputFile, chunk, files, commandName) { ); fs.appendFileSync(outputFile, ` - name: Init\n`); - fs.appendFileSync(outputFile, ` run: |\n`); - fs.appendFileSync(outputFile, ` npm run build:functions\n`); - fs.appendFileSync(outputFile, ` npm install -g firebase-tools\n`); + fs.appendFileSync(outputFile, ` run: npm run build:functions\n`); fs.appendFileSync(outputFile, ` - name: Test\n`); fs.appendFileSync(outputFile, ` working-directory: packages/functions\n`); - fs.appendFileSync(outputFile, ` run: |\n`); - fs.appendFileSync( - outputFile, - ` export GOOGLE_APPLICATION_CREDENTIALS="./test-service-account-key.json"\n`, - ); - fs.appendFileSync(outputFile, ` npm run milestone-sync &\n`); - fs.appendFileSync(outputFile, ` firebase emulators:exec "\n`); + fs.appendFileSync(outputFile, ` npm run start &\n`); + fs.appendFileSync(outputFile, ` npm run notifier &\n`); + files.forEach((file, index) => { fs.appendFileSync( outputFile, - ` npm run ${commandName}:ci -- --forceExit --findRelatedTests ${file} ${ - index < files.length - 1 ? '&&' : '' - }\n`, + ` npm run test -- --findRelatedTests --forceExit ${file} ${index < files.length - 1 ? '&&' : ''}\n`, ); }); - fs.appendFileSync( - outputFile, - ` " --project dev --only functions,firestore,storage,ui,auth --export-on-exit=./firestore-data\n`, - ); - // Test reports collection via github action. - // fs.appendFileSync(outputFile, ` - name: Test Report\n`); - // fs.appendFileSync( - // outputFile, - // ` uses: phoenix-actions/test-reporting@f68b7c5fcffefd98dd230c686cca6c26683668c3\n`, - // ); - // fs.appendFileSync(outputFile, ` if: success() || failure()\n`); - // fs.appendFileSync(outputFile, ` with:\n`); - // fs.appendFileSync(outputFile, ` name: Tests results - chunk_${chunk}\n`); - // fs.appendFileSync(outputFile, ` path: packages/functions/reports/junit-*.xml\n`); - // fs.appendFileSync(outputFile, ` output-to: checks\n`); - // fs.appendFileSync(outputFile, ` reporter: jest-junit\n\n`); - - // Coverage & test results via foresight - fs.appendFileSync(outputFile, ` - name: Archive firestore data\n`); - fs.appendFileSync(outputFile, ` uses: actions/upload-artifact@v4\n`); - fs.appendFileSync(outputFile, ' if: ${{ failure() }}\n'); - fs.appendFileSync(outputFile, ` with:\n`); - fs.appendFileSync(outputFile, ` name: firestore-data-${commandName}-chunk_${chunk}\n`); - fs.appendFileSync(outputFile, ` path: ./packages/functions/firestore-data/\n`); - fs.appendFileSync(outputFile, ` retention-days: 1\n`); - - // fs.appendFileSync(outputFile, ` - name: Analyze Test and Coverage Results\n`); - // fs.appendFileSync(outputFile, ` uses: runforesight/foresight-test-kit-action@v1\n`); - // fs.appendFileSync(outputFile, ` if: \${{ always() }}\n`); - // fs.appendFileSync(outputFile, ` with:\n`); - // fs.appendFileSync(outputFile, ` api_key: \${{ secrets.FORESIGHT_KEY }}\n`); - // fs.appendFileSync(outputFile, ` test_format: JUNIT\n`); - // fs.appendFileSync(outputFile, ` test_framework: JEST\n`); - // fs.appendFileSync(outputFile, ` test_path: packages/functions/reports/test\n`); - // fs.appendFileSync(outputFile, ` coverage_format: COBERTURA/XML\n`); - // fs.appendFileSync(outputFile, ` coverage_path: packages/functions/reports/coverage\n\n`); } const tangleChunkSize = 3; @@ -163,46 +111,16 @@ function createTangleTest() { const only = files.filter((f) => f.includes('only.spec.ts')); const rest = files.filter((f) => !f.includes('only.spec.ts')); const restChunks = chunk(rest, tangleChunkSize); - restChunks.forEach((chunk, i) => job(tangleTestFile, i, chunk, 'test-tangle')); - chunk(only, 1).forEach((chunk, i) => - job(tangleTestFile, i + restChunks.length, chunk, 'test-tangle'), - ); -} - -function createTangleOnlineTest() { - setupOnline(tangleOnlineTestFile, tangleOnlineTestFileName); - init(tangleOnlineTestFile); - const files = glob - .sync(`./test-tangle/**/*.spec.ts`) - .filter((f) => !f.includes('only.spec.ts')) - .filter((f) => !f.includes('web3.spec')) - .filter((f) => !f.includes('dbRoll')); - chunk(files, tangleChunkSize).forEach((chunk, i) => - job(tangleOnlineTestFile, i, chunk, 'test-tangle-online'), - ); + restChunks.forEach((chunk, i) => job(tangleTestFile, i, chunk)); + chunk(only, 1).forEach((chunk, i) => job(tangleTestFile, i + restChunks.length, chunk)); } function createEmulatedTest() { setup(emulatedTestFile, emulatedTestFileName); init(emulatedTestFile); const files = glob.sync(`./test/**/*.spec.ts`).filter((f) => !f.includes('exclude')); - chunk(files, emulatorChunkSize).forEach((chunk, i) => job(emulatedTestFile, i, chunk, 'test')); -} - -function createEmulatedOnlineTest() { - setupOnline(emulatedOnlineTestFile, emulatedOnlineTestFileName); - init(emulatedOnlineTestFile); - const files = glob - .sync(`./test/**/*.spec.ts`) - .filter((f) => !f.includes('exclude')) - .filter((f) => !f.includes('only.spec.ts')) - .filter((f) => !f.includes('dbRoll')); - chunk(files, emulatorChunkSize).forEach((chunk, i) => - job(emulatedOnlineTestFile, i, chunk, 'test-online'), - ); + chunk(files, emulatorChunkSize).forEach((chunk, i) => job(emulatedTestFile, i, chunk)); } createTangleTest(); createEmulatedTest(); -createTangleOnlineTest(); -createEmulatedOnlineTest(); diff --git a/packages/interfaces/src/config.ts b/packages/interfaces/src/config.ts index 50d5d50530..16409cf901 100644 --- a/packages/interfaces/src/config.ts +++ b/packages/interfaces/src/config.ts @@ -36,11 +36,11 @@ export const SOON_SPACE_TEST = '0x0702535a8409d58d832fe80660c28dc61dee9704'; /** * Soonaverse SOON token in wen.soonaverse.com (sandbox) */ -export const SOON_TOKEN_TEST = '0x15e7e6663f3a88c0cce72a4cc3cd5c6786f0b1cf'; +export const SOON_TOKEN_TEST = '0x86e2511438ddc372e6ce68c8a0dbf92b3b730fc2'; export const SOON_PROD_ADDRESS = 'https://soonaverse.com/'; export const SOON_TEST_ADDRESS = 'https://wen2.soonaverse.com/'; -export const BUILD5_PROD_ADDRESS_API = 'https://api.build5.com/'; -export const BUILD5_TEST_ADDRESS_API = 'https://api-test.build5.com/'; +export const BUILD5_PROD_ADDRESS_API = 'https://api.buildcore.io/'; +export const BUILD5_TEST_ADDRESS_API = 'https://api-test.buildcore.io/'; export const GITHUB_REGEXP = /^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}$/i; export const DISCORD_REGEXP = /^.{3,32}$/i; export const TWITTER_REGEXP = /^@?(\w){1,15}$/i; diff --git a/packages/interfaces/src/models/award.ts b/packages/interfaces/src/models/award.ts index 78227d6dca..3f2a297345 100644 --- a/packages/interfaces/src/models/award.ts +++ b/packages/interfaces/src/models/award.ts @@ -215,6 +215,10 @@ export interface Award extends BaseRecord { * Media status {@link MediaStatus} */ readonly mediaStatus?: MediaStatus; + /** + * @hidden + */ + readonly mediaUploadErrorCount?: number; /** * Is this legacy award? * @deprecated diff --git a/packages/interfaces/src/models/base.ts b/packages/interfaces/src/models/base.ts index 5624bd8756..abae7b95aa 100644 --- a/packages/interfaces/src/models/base.ts +++ b/packages/interfaces/src/models/base.ts @@ -138,6 +138,7 @@ export interface Base { } export interface BaseSubCollection { + uid?: string; project?: string; parentId: string; parentCol: string; diff --git a/packages/interfaces/src/models/collection.ts b/packages/interfaces/src/models/collection.ts index 3d36bd6432..57e93ac47b 100644 --- a/packages/interfaces/src/models/collection.ts +++ b/packages/interfaces/src/models/collection.ts @@ -227,6 +227,10 @@ export interface Collection extends CollectionBase { * Status of media upload to IFPS. */ mediaStatus?: MediaStatus; + /** + * @hidden + */ + mediaUploadErrorCount?: number; /** * Total number of staked NFTs */ diff --git a/packages/interfaces/src/models/index.ts b/packages/interfaces/src/models/index.ts index 6409411804..53f952b1c7 100644 --- a/packages/interfaces/src/models/index.ts +++ b/packages/interfaces/src/models/index.ts @@ -12,6 +12,7 @@ export * from './nftStake'; export * from './notification'; export * from './project'; export * from './proposal'; +export * from './soon_snap'; export * from './space'; export * from './stake'; export * from './stamp'; @@ -20,4 +21,3 @@ export * from './system.config'; export * from './ticker'; export * from './token'; export * from './transaction'; -export * from './soon_snap'; diff --git a/packages/interfaces/src/models/member.ts b/packages/interfaces/src/models/member.ts index 3829580eb6..d3b1959673 100644 --- a/packages/interfaces/src/models/member.ts +++ b/packages/interfaces/src/models/member.ts @@ -3,7 +3,7 @@ import { BaseRecord, NetworkAddress, Timestamp, ValidatedAddress } from './base' /** * Member Award Stats. */ -interface MemberAwardStat { +export interface MemberAwardStat { /** * Token Symbol. */ @@ -27,7 +27,7 @@ interface MemberAwardStat { /** * Member Space Stats. */ -interface MemberSpaceStat { +export interface MemberSpaceStat { /** * Space UID */ diff --git a/packages/interfaces/src/models/milestone.ts b/packages/interfaces/src/models/milestone.ts index a4dbfc7972..ed14a371f8 100644 --- a/packages/interfaces/src/models/milestone.ts +++ b/packages/interfaces/src/models/milestone.ts @@ -38,6 +38,10 @@ export interface Milestone { * Created on */ createdOn: Timestamp; + /** + * Completed on + */ + completedOn: Timestamp; /** * Milestone number */ @@ -48,4 +52,9 @@ export interface Milestone { cmi: number; completed: boolean; processed: boolean; + listenerNodeId: string; + milestoneTimestamp: Timestamp; + trxConflictCount: number; + trxFailedCount: number; + trxValidCount: number; } diff --git a/packages/interfaces/src/models/mnemonic.ts b/packages/interfaces/src/models/mnemonic.ts index 7901c03d4c..363a0a59c3 100644 --- a/packages/interfaces/src/models/mnemonic.ts +++ b/packages/interfaces/src/models/mnemonic.ts @@ -1,4 +1,4 @@ -import { Timestamp } from './base'; +import { BaseRecord, Timestamp } from './base'; import { Network } from './transaction'; /** @@ -6,7 +6,7 @@ import { Network } from './transaction'; * * @hidden */ -export interface Mnemonic { +export interface Mnemonic extends BaseRecord { readonly mnemonic?: string; readonly network?: Network; readonly createdOn?: Timestamp; diff --git a/packages/interfaces/src/models/nft.ts b/packages/interfaces/src/models/nft.ts index a22f8cd941..77d9cf7f86 100644 --- a/packages/interfaces/src/models/nft.ts +++ b/packages/interfaces/src/models/nft.ts @@ -229,6 +229,10 @@ export interface Nft extends BaseRecord { * NFT Media status */ mediaStatus?: MediaStatus; + /** + * @hidden + */ + mediaUploadErrorCount?: number; /** * NFT Sold on */ diff --git a/packages/interfaces/src/models/project.ts b/packages/interfaces/src/models/project.ts index 52482a2efa..804c171e5d 100644 --- a/packages/interfaces/src/models/project.ts +++ b/packages/interfaces/src/models/project.ts @@ -26,7 +26,7 @@ export interface Project extends BaseRecord { } export enum ProjectBilling { - TOKEN_BASE = 'token_based', + TOKEN_BASED = 'token_based', VOLUME_BASED = 'volume_based', } @@ -59,6 +59,7 @@ export interface ProjectAdmin extends BaseSubCollection { export interface ProjectApiKey extends BaseSubCollection { uid: string; createdOn: Timestamp; + token: string; } export interface ProjectOtr { diff --git a/packages/interfaces/src/models/proposal.ts b/packages/interfaces/src/models/proposal.ts index b38d10153c..a5d5a0f319 100644 --- a/packages/interfaces/src/models/proposal.ts +++ b/packages/interfaces/src/models/proposal.ts @@ -32,7 +32,10 @@ export interface ProposalMember extends BaseSubCollection { /** * Selected values. */ - values?: number[]; + values?: { + [x: number]: number; + voteTransaction?: string; + }[]; /** * Created on. */ @@ -45,6 +48,10 @@ export interface ProposalMember extends BaseSubCollection { * Weight per answer. */ weightPerAnswer?: { [key: number]: number }; + /** + * Vote transaction uid + */ + tranId?: string; } /** diff --git a/packages/interfaces/src/models/space.ts b/packages/interfaces/src/models/space.ts index 9976a4e3fe..0b8faf3468 100644 --- a/packages/interfaces/src/models/space.ts +++ b/packages/interfaces/src/models/space.ts @@ -133,10 +133,18 @@ export interface Space extends BaseRecord { * Vault address */ vaultAddress?: string; + + /** + * @deprecated This is not longer used + */ guardians: { // Owner / from date [propName: string]: SpaceGuardian; }; + + /** + * @deprecated This is not longer used + */ members: { // Owner / from date [propName: string]: SpaceMember; @@ -165,6 +173,10 @@ export interface Space extends BaseRecord { * Media status */ readonly mediaStatus?: MediaStatus; + /** + * @hidden + */ + readonly mediaUploadErrorCount?: number; /** * Space Alias details. */ diff --git a/packages/interfaces/src/models/stamp.ts b/packages/interfaces/src/models/stamp.ts index 2e827d0a56..5bda10a543 100644 --- a/packages/interfaces/src/models/stamp.ts +++ b/packages/interfaces/src/models/stamp.ts @@ -21,6 +21,10 @@ export interface Stamp extends BaseRecord { expired: boolean; mediaStatus?: MediaStatus; + /** + * @hidden + */ + mediaUploadErrorCount?: number; aliasId?: string; nftId?: string; diff --git a/packages/interfaces/src/models/system.config.ts b/packages/interfaces/src/models/system.config.ts index ff60237e13..d38c6d4db8 100644 --- a/packages/interfaces/src/models/system.config.ts +++ b/packages/interfaces/src/models/system.config.ts @@ -1,9 +1,11 @@ +import { BaseRecord } from './base'; + export const SYSTEM_CONFIG_DOC_ID = 'config'; /** * System Config record. */ -export interface SystemConfig { +export interface SystemConfig extends BaseRecord { readonly tokenTradingFeePercentage?: number; readonly tokenPurchaseFeePercentage?: number; } diff --git a/packages/interfaces/src/models/token.ts b/packages/interfaces/src/models/token.ts index 66bb20503a..f4ca43d0c6 100644 --- a/packages/interfaces/src/models/token.ts +++ b/packages/interfaces/src/models/token.ts @@ -271,6 +271,10 @@ export interface Token extends BaseRecord { * Token media status */ readonly mediaStatus?: MediaStatus; + /** + * @hidden + */ + readonly mediaUploadErrorCount?: number; /** * Trading disabled for the token */ @@ -641,4 +645,9 @@ export interface TokenStats extends BaseSubCollection { * TODODOC */ readonly ranks?: RankStats; + + // First key -> dynamic/static + // Second key -> stake expires at in millis + // value -> stake value + readonly stakeExpiry?: { [key: string]: { [key: number]: number } }; } diff --git a/packages/interfaces/src/models/transaction/payload.ts b/packages/interfaces/src/models/transaction/payload.ts index 05084832f2..78d2bdff1b 100644 --- a/packages/interfaces/src/models/transaction/payload.ts +++ b/packages/interfaces/src/models/transaction/payload.ts @@ -79,7 +79,7 @@ export interface TransactionPayload { /** * A reference to the source order or payment */ - sourceTransaction?: string | string[]; + sourceTransaction?: string[]; /** * Specifies the processing type */ @@ -309,6 +309,10 @@ export interface TransactionPayload { * Legacy award fund request id */ legacyAwardFundRequestId?: NetworkAddress; + /** + * Number of legacy awards being funded by this transaction + */ + legacyAwardsBeeingFunded?: number; /** * Length of the stake in weeks */ @@ -494,5 +498,6 @@ export interface TransactionPayload { */ nftOrders?: NftBulkOrder[]; + outputId?: string; swap?: string; } diff --git a/packages/interfaces/src/search/post/index.ts b/packages/interfaces/src/search/post/index.ts index 19afa13de1..262a337235 100644 --- a/packages/interfaces/src/search/post/index.ts +++ b/packages/interfaces/src/search/post/index.ts @@ -6,7 +6,6 @@ export * from './AddressValidationRequest'; export * from './AuctionBidRequest'; export * from './AuctionCreateRequest'; -export * from './CutomTokenRequest'; export * from './AwardAddOwnerRequest'; export * from './AwardApproveParticipantRequest'; export * from './AwardCancelRequest'; @@ -19,11 +18,11 @@ export * from './CollectionMintRequest'; export * from './CollectionRejectRequest'; export * from './CollectionUpdateMintedRequest'; export * from './CollectionUpdateRequest'; +export * from './CreateMemberRequest'; export * from './CreditUnrefundableRequest'; +export * from './CutomTokenRequest'; export * from './FileUploadRequest'; export * from './FileUploadResponse'; -export * from './CreateMemberRequest'; -export * from './UpdateMemberRequest'; export * from './NftBidRequest'; export * from './NftCreateRequest'; export * from './NftDepositRequest'; @@ -58,16 +57,17 @@ export * from './SwapReject'; export * from './SwapSetFunded'; export * from './TokenAirdropRequest'; export * from './TokenCancelPubSaleRequest'; +export * from './TokenCanelTradeOrderRequest'; export * from './TokenClaimAirdroppedRequest'; +export * from './TokenClaimMintedRequest'; export * from './TokenCreateRequest'; export * from './TokenCreditRequest'; export * from './TokenEnableTradingRequest'; -export * from './TokenOrderRequest'; -export * from './TokenSetAvailableForSaleRequest'; -export * from './TokenUpdateRequest'; -export * from './TokenClaimMintedRequest'; export * from './TokenImportRequest'; export * from './TokenMintRequest'; -export * from './TokenCanelTradeOrderRequest'; +export * from './TokenOrderRequest'; +export * from './TokenSetAvailableForSaleRequest'; export * from './TokenTradeRequest'; +export * from './TokenUpdateRequest'; +export * from './UpdateMemberRequest'; export * from './VoteRequest'; diff --git a/packages/interfaces/src/search/tangle/index.ts b/packages/interfaces/src/search/tangle/index.ts index a42434fe30..152d5e976f 100644 --- a/packages/interfaces/src/search/tangle/index.ts +++ b/packages/interfaces/src/search/tangle/index.ts @@ -6,11 +6,9 @@ export * from './AddressValidationTangleRequest'; export * from './AuctionBidTangleRequest'; export * from './AuctionCreateTangleRequest'; -export * from './NftBidTangleRequest'; export * from './AwardAppParticipantTangleRequest'; export * from './AwardCreateTangleRequest'; export * from './AwardFundTangleRequest'; -export * from './VerifyEthForB5TangleRequest'; export * from './MetadataNftTangleRequest'; export * from './NftBidTangleRequest'; export * from './NftPurchaseBulkTangleRequest'; @@ -31,4 +29,5 @@ export * from './SwapSetFundedTangleRequest'; export * from './TokenClaimTangleRequest'; export * from './TokenStakeTangleRequest'; export * from './TokenTradeTangleRequest'; +export * from './VerifyEthForB5TangleRequest'; export * from './responses'; diff --git a/packages/notifier/.gitignore b/packages/notifier/.gitignore new file mode 100644 index 0000000000..f30cc924f4 --- /dev/null +++ b/packages/notifier/.gitignore @@ -0,0 +1,4 @@ +/lib +/node_modules +.env +sa.json \ No newline at end of file diff --git a/packages/notifier/.prettierignore b/packages/notifier/.prettierignore new file mode 100644 index 0000000000..31dae4e582 --- /dev/null +++ b/packages/notifier/.prettierignore @@ -0,0 +1,2 @@ +/coverage +/lib diff --git a/packages/notifier/README.md b/packages/notifier/README.md new file mode 100644 index 0000000000..52e9e26680 --- /dev/null +++ b/packages/notifier/README.md @@ -0,0 +1,14 @@ +- Notifier to post pg_notify messages on pubsub + +1. cd packages/notifier +2. gcloud compute scp --recurse ./ notifier:~/notifier +3. gcloud compute ssh notifier +4. sudo apt install npm +5. curl -o cloud-sql-proxy \ + https://storage.googleapis.com/cloud-sql-connectors/cloud-sql-proxy/v2.0.0/cloud-sql-proxy.linux.amd64 +6. chmod +x cloud-sql-proxy +7. ./cloud-sql-proxy --credentials-file ./notifier/sa.json buildcore-test:us-central1:buildcore-test & +8. sudo npm install pm2 -g +9. cd notifier && npm i && npm run build +10. export GOOGLE_APPLICATION_CREDENTIALS="./sa.json" +11. pm2 start lib/index.js --name notifier diff --git a/packages/notifier/package.json b/packages/notifier/package.json new file mode 100644 index 0000000000..d185cd7bb3 --- /dev/null +++ b/packages/notifier/package.json @@ -0,0 +1,22 @@ +{ + "name": "@build-5/notifier", + "version": "0.0.0", + "description": "pg_notify listener", + "main": "lib/index.js", + "scripts": { + "build": "tsc", + "start": "export GOOGLE_APPLICATION_CREDENTIALS=\"./sa.json\" && node lib/index.js" + }, + "author": "Boldizsar Mezei", + "license": "Apache-2.0", + "dependencies": { + "@google-cloud/pubsub": "4.3.3", + "dotenv": "16.4.5", + "knex": "3.1.0", + "pg": "8.11.3" + }, + "devDependencies": { + "@types/node": "20.12.7", + "typescript": "5.4.5" + } +} diff --git a/packages/notifier/src/index.ts b/packages/notifier/src/index.ts new file mode 100644 index 0000000000..ee57144515 --- /dev/null +++ b/packages/notifier/src/index.ts @@ -0,0 +1,91 @@ +import { PubSub, Topic } from '@google-cloud/pubsub'; +import Knex from 'knex'; +import path from 'path'; +import { logger } from './logger'; +require('dotenv').config({ path: path.join(__dirname, '/../.env') }); + +const knex = Knex({ + client: 'pg', + connection: { + user: process.env.DB_USER, + password: process.env.DB_USER_PWD, + database: process.env.DB_NAME, + host: process.env.DB_HOST, + port: Number(process.env.DB_PORT), + }, + pool: { max: 20 }, +}); + +interface Upsert { + table: string; + uid: string; + parentId?: string; +} +const upsertQueue: Upsert[] = []; + +const notifier = async () => { + const connection = await knex.client.acquireConnection(); + + connection.query(`LISTEN trigger`, () => logger.info('Listenting to {trigger} events')); + connection.query(`LISTEN onupsert`, () => logger.info('Listenting to {onupsert} events')); + + connection.on('notification', async (data: any) => { + if (data.channel === 'trigger') { + const [channel, processId] = data.payload.split(':'); + await notifyTriggers(channel, processId); + return; + } + + if (data.channel === 'onupsert') { + upsertQueue.push(JSON.parse(data.payload)); + return; + } + }); + + process.stdin.resume(); +}; + +const pubSub = new PubSub(); + +const triggerTopics: { [key: string]: Topic } = {}; + +const getTriggerTopic = (topic: string) => { + if (!triggerTopics[topic]) { + triggerTopics[topic] = pubSub.topic(topic); + } + return triggerTopics[topic]; +}; + +const notifyTriggers = async (channel: string, processId: string) => { + await getTriggerTopic(channel).publishMessage({ + data: Buffer.from(JSON.stringify({ processId: Number(processId) })), + }); +}; + +const upserTopic = pubSub.topic('onupsert'); + +const postDataToPubSub = async () => { + const data = new Set(upsertQueue.splice(0)); + + const promises = [...data.values()].map(async (d) => { + try { + const pKey = d.parentId ? { uid: d.uid, parentId: d.parentId } : { uid: d.uid }; + const snap = (await knex(d.table).where(pKey))[0]; + if (!snap) { + return; + } + await upserTopic.publishMessage({ + data: Buffer.from(JSON.stringify(snap)), + attributes: { table: d.table }, + }); + } catch (err) { + logger.error(err, d); + } + }); + + await Promise.allSettled(promises); +}; + +setInterval(postDataToPubSub, 500); + +notifier(); diff --git a/packages/notifier/src/logger.ts b/packages/notifier/src/logger.ts new file mode 100644 index 0000000000..e8f3198a79 --- /dev/null +++ b/packages/notifier/src/logger.ts @@ -0,0 +1,44 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { format } from 'util'; + +const log = async (severity = 'INFO', ...data: any[]): Promise => { + const entry = { + severity, + message: format(...data), + }; + console.log(JSON.stringify(removeCircular(entry))); +}; + +export const logger = { + info: (...message: any[]) => log('INFO', message), + error: (...message: any[]) => log('ERROR', message), + warn: (...message: any[]) => log('WARNING', message), +}; + +const removeCircular = (obj: any, refs: any[] = []) => { + if (typeof obj !== 'object' || !obj) { + return obj; + } + if (obj.toJSON) { + return obj.toJSON(); + } + if (refs.includes(obj)) { + return '[Circular]'; + } else { + refs.push(obj); + } + let returnObj: any; + if (Array.isArray(obj)) { + returnObj = new Array(obj.length); + } else { + returnObj = {}; + } + for (const k in obj) { + if (refs.includes(obj[k])) { + returnObj[k] = '[Circular]'; + } else { + returnObj[k] = removeCircular(obj[k], refs); + } + } + return returnObj; +}; diff --git a/packages/notifier/tsconfig.json b/packages/notifier/tsconfig.json new file mode 100644 index 0000000000..00ea7a37c7 --- /dev/null +++ b/packages/notifier/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "module": "commonjs", + "noImplicitReturns": true, + "noUnusedLocals": true, + "outDir": "lib", + "sourceMap": true, + "strict": true, + "target": "es2017", + "skipLibCheck": true, + "esModuleInterop": true, + "resolveJsonModule": true + }, + "compileOnSave": true, + "include": ["src"] +} diff --git a/packages/sdk/examples/nft/otr/purchase.ts b/packages/sdk/examples/nft/otr/purchase.ts index f63fd47f10..025841413b 100644 --- a/packages/sdk/examples/nft/otr/purchase.ts +++ b/packages/sdk/examples/nft/otr/purchase.ts @@ -1,5 +1,5 @@ import { Dataset } from '@build-5/interfaces'; -import { Build5, SoonaverseOtrAddress, https, otr, SoonaverseApiKey } from '@build-5/sdk'; +import { Build5, SoonaverseApiKey, SoonaverseOtrAddress, https, otr } from '@build-5/sdk'; const collectionId = 'build5collectionid1'; const nftId = 'build5nftid1'; diff --git a/packages/sdk/src/https/datasets/Subset.ts b/packages/sdk/src/https/datasets/Subset.ts index 7e22bb6b85..5e2192b409 100644 --- a/packages/sdk/src/https/datasets/Subset.ts +++ b/packages/sdk/src/https/datasets/Subset.ts @@ -125,9 +125,9 @@ export class SubsetClass extends BaseSubset { const params: GetManyAdvancedRequest = { dataset: this.dataset, subset: this.subset, - fieldName: ['uid', 'parentCol'], - fieldValue: [subsetId, this.dataset], - operator: [Opr.EQUAL, Opr.EQUAL], + fieldName: ['uid'], + fieldValue: [subsetId], + operator: [Opr.EQUAL], startAfter, limit, orderBy, diff --git a/packages/sdk/src/https/datasets/award/AwardParticipantSubset.ts b/packages/sdk/src/https/datasets/award/AwardParticipantSubset.ts index cb2390ebb5..6b02c5a30d 100644 --- a/packages/sdk/src/https/datasets/award/AwardParticipantSubset.ts +++ b/packages/sdk/src/https/datasets/award/AwardParticipantSubset.ts @@ -46,9 +46,9 @@ export class AwardParticpateSubset extends SubsetClass { const params: GetManyAdvancedRequest = { dataset: this.dataset, subset: this.subset, - fieldName: ['uid', 'parentCol', 'completed'], - fieldValue: [member, this.dataset, completed], - operator: [Opr.EQUAL, Opr.EQUAL, Opr.EQUAL], + fieldName: ['uid', 'completed'], + fieldValue: [member, completed], + operator: [Opr.EQUAL, Opr.EQUAL], startAfter, orderBy: ['createdOn'], orderByDir: ['desc'], diff --git a/packages/sdk/src/https/datasets/common.ts b/packages/sdk/src/https/datasets/common.ts index 98b8fafc4e..99ebb7b127 100644 --- a/packages/sdk/src/https/datasets/common.ts +++ b/packages/sdk/src/https/datasets/common.ts @@ -10,6 +10,8 @@ import { ProjectDataset } from './ProjectDataset'; import { StakeDataset } from './StakeDataset'; import { StakeRewardDataset } from './StakeRewardDataset'; import { StampDataset } from './StampDataset'; +import { SubsetClass } from './Subset'; +import { SwapDataset } from './SwapDataset'; import { TickerDataset } from './TickerDataset'; import { TransactionDataset } from './TransactionDataset'; import { AwardDataset } from './award/AwardDataset'; @@ -33,8 +35,6 @@ import { TokenDistributionSubset } from './token/TokenDistributionSubset'; import { TokenMarketDataset } from './token/TokenMarketDataset'; import { TokenPurchaseDataset } from './token/TokenPurchaseDataset'; import { TokenStatsSubset } from './token/TokenStatsSubset'; -import { SubsetClass } from './Subset'; -import { SwapDataset } from './SwapDataset'; // prettier-ignore export type DatasetType = diff --git a/packages/sdk/src/https/fetch.utils.ts b/packages/sdk/src/https/fetch.utils.ts index 0edfd6b543..cd0f464cec 100644 --- a/packages/sdk/src/https/fetch.utils.ts +++ b/packages/sdk/src/https/fetch.utils.ts @@ -10,7 +10,7 @@ export const isOnlineCheckInterval = setInterval(async () => { return; } try { - const response = await fetch('https://build5.com', { method: 'HEAD' }); + const response = await fetch('https://buildcore.io', { method: 'HEAD' }); isAppOnline = response.ok; } catch { isAppOnline = false; diff --git a/packages/sdk/src/https/index.ts b/packages/sdk/src/https/index.ts index 404edd6542..fe57206a95 100644 --- a/packages/sdk/src/https/index.ts +++ b/packages/sdk/src/https/index.ts @@ -40,8 +40,8 @@ class HttpsWrapper { * Build.5 API endpoints. */ export enum Build5 { - PROD = 'https://api.build5.com', - TEST = 'https://api-test.build5.com', + PROD = 'https://api.buildcore.io', + TEST = 'https://api-test.buildcore.io', } /** diff --git a/packages/sdk/src/https/utils.ts b/packages/sdk/src/https/utils.ts index 9986e9500e..1b6665eb59 100644 --- a/packages/sdk/src/https/utils.ts +++ b/packages/sdk/src/https/utils.ts @@ -22,8 +22,8 @@ const processValue = (value: any): any => { } if (value && typeof value === 'object') { const keys = Object.keys(value); - if (isEqual(keys, ['_seconds', '_nanoseconds'])) { - return new Timestamp(value._seconds, value._nanoseconds); + if (isEqual(keys, ['seconds', 'nanoseconds'])) { + return new Timestamp(value.seconds, value.nanoseconds); } return processObject(value); } @@ -32,7 +32,7 @@ const processValue = (value: any): any => { export const randomString = (length = 16) => { let result = ''; - const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0154326789'; for (let i = 0; i < length; i++) { const randomIndex = Math.floor(Math.random() * characters.length); result += characters.charAt(randomIndex); diff --git a/packages/sdk/test/otr/otr.spec.ts b/packages/sdk/test/otr/otr.spec.ts index ee655c200b..2b629878f4 100644 --- a/packages/sdk/test/otr/otr.spec.ts +++ b/packages/sdk/test/otr/otr.spec.ts @@ -1,6 +1,6 @@ import { Dataset } from '@build-5/interfaces'; import * as build5 from '../../src'; -import { SoonaverseApiKey, Build5 } from '../../src/https'; +import { Build5, SoonaverseApiKey } from '../../src/https'; import { SoonaverseOtrAddress } from '../../src/otr'; describe('', () => { diff --git a/packages/search/.env b/packages/search/.env index 9d4d5ca0bf..430e7f117b 100644 --- a/packages/search/.env +++ b/packages/search/.env @@ -1,10 +1,17 @@ -ENVIRONMENT=test -WEB3_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweEZCOTFiNTdEN2YzNmVhNjQ4NjQ3ODIyQjJGNGVEOEEyMDZCNERhNjQiLCJpc3MiOiJ3ZWIzLXN0b3JhZ2UiLCJpYXQiOjE2Njc0MDYzNzE3NDksIm5hbWUiOiJ0ZXN0IGRldiJ9.88vd8ZmeEle2Xqyc8uEMBOXJqDrFcxxF8gyHuXIjXgk -JWT_SECRET="asdas#@#@xdas31sad" -ALGOLIA_APPID=6MPUETJRDB -ALGOLIA_KEY=a75153c20ebe86d31e1fe5874f55dbac -ENCRYPTION_SALT=c4kWxCtNVQ5c2m -IP_INFO_TOKEN='' -XPTOKEN_ID=0x08fe43472f5968c4ccfa7154599e3d9c8df3f2e0b6396cafc2b038f15ee1974e050100000000 -XPTOKEN_UID=0xe71439be7001d2311658ded364e4043a284d16f4 -XPTOKEN_GUARDIANID=0x551fd2c7c7bf356bac194587dab2fcd46420054b \ No newline at end of file +ENVIRONMENT="emulator" +WEB3_TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweEVFMjA3Qzk5YzA2NzkxMDg0QjU5NmU4NkEyMzVGNzFiNTc0NWNkMTIiLCJpc3MiOiJ3ZWIzLXN0b3JhZ2UiLCJpYXQiOjE2Njg0Njc4MDQ3NDAsIm5hbWUiOiJERVZfVE9LRU4ifQ.TB2AbWZDMk4WhWIeWKsdEKUReXUh0WUgcHAU5ccb4FA" +NFT_STORAGE_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweDhiYjBGMDk4NzIzYTY5ODg1NTg3NTJCYWM0ODRlMTJCNGJlMGYxMDIiLCJpc3MiOiJuZnQtc3RvcmFnZSIsImlhdCI6MTcwNTUwMjkyMTEwMiwibmFtZSI6InNhbmRib3gifQ.a4TfMHsghXJjKQUO9zC9O0Wu_NGXVffDkw1E6-jr3hI +JWT_SECRET="mysecret" +ALGOLIA_APPID="UZXKW1YS76" +ALGOLIA_KEY="8bf460848691fae9111b6159867d6bc1" +ENCRYPTION_SALT="sa#asda!2sasd##asad" +IP_INFO_TOKEN="" +XPTOKEN_ID="0x08f800d9e15c1da60c36cb0b2d4a02366ea3e200a65fc071a9e25f09b7fb9e951f0100000000" +XPTOKEN_UID="0xcef8ddcea97a5b82921d1cadbc8ccddcd69341da" +XPTOKEN_GUARDIANID="0x45f8379c44a73fc0ee6ad56acf51bd0f69240af5" + +DB_USER="postgres" +DB_USER_PWD="postgres" +DB_NAME="buildcore" +DB_HOST="localhost" +DB_PORT=5432 \ No newline at end of file diff --git a/packages/search/.gitignore b/packages/search/.gitignore index 97dba69de2..2c977f6eaa 100644 --- a/packages/search/.gitignore +++ b/packages/search/.gitignore @@ -1,2 +1,3 @@ /lib node_modules/ +sa.json \ No newline at end of file diff --git a/packages/search/package.json b/packages/search/package.json index 0a075cdf3b..ee0e32be72 100644 --- a/packages/search/package.json +++ b/packages/search/package.json @@ -13,7 +13,7 @@ "private": "true", "scripts": { "build": "tsc && cp .env lib/.env", - "start": "tsc && node lib/index" + "start": "npm run build && export GOOGLE_APPLICATION_CREDENTIALS=\"./sa.json\" && node lib/index.js" }, "dependencies": { "@build-5/database": "*", diff --git a/packages/search/src/common.ts b/packages/search/src/common.ts index 5a09530660..8ec325dff7 100644 --- a/packages/search/src/common.ts +++ b/packages/search/src/common.ts @@ -1,4 +1,4 @@ -import { IDocument, IQuery } from '@build-5/database'; +import { BaseRecord, IDocument, IQuery, PgTokenPurchase, Update } from '@build-5/database'; import { Dataset, QUERY_MAX_LENGTH, Subset, TokenPurchase } from '@build-5/interfaces'; import Joi from 'joi'; import { head } from 'lodash'; @@ -25,41 +25,64 @@ const queryStrToParams = (url: string) => { ); }; -export const isHiddenNft = (dataset: Dataset, data?: Record) => +export const isHiddenNft = (dataset: Dataset, data?: any) => dataset === Dataset.NFT && data?.hidden === true; -export const queryToObservable = (query: IQuery) => - new Observable((observer) => { - const unsubscribe = query.onSnapshot( - (data) => { - observer.next(data); - }, - (error) => { - observer.error(error); - }, - ); - return () => { - unsubscribe(); - }; +export const queryToObservable = (query: IQuery, isLive: boolean) => { + if (isLive) { + return new Observable((obs) => { + const unsubscribe = query.onSnapshot( + (data) => { + obs.next(data); + }, + (error) => { + obs.error(error); + }, + ); + return () => { + unsubscribe(); + }; + }); + } + + return new Observable((obs) => { + query + .get() + .then((r) => obs.next(r)) + .catch((err) => obs.error(err)); }); +}; + +export const documentToObservable = ( + doc: IDocument, + isLive: boolean, +): Observable => { + if (isLive) { + return new Observable((observer) => { + const unsubscribe = doc.onSnapshot( + (data) => { + observer.next(data); + }, + (error) => { + observer.error(error); + }, + ); + return () => { + unsubscribe(); + }; + }); + } -export const documentToObservable = (doc: IDocument) => - new Observable((observer) => { - const unsubscribe = doc.onSnapshot( - (data) => { - observer.next(data); - }, - (error) => { - observer.error(error); - }, - ); - return () => { - unsubscribe(); - }; + return new Observable((obs) => { + doc + .get() + .then((r) => obs.next(r)) + .catch((err) => obs.error(err)); }); +}; -export const getHeadPriceObs = (query: IQuery) => - queryToObservable(query).pipe(map((r) => head(r)?.price || 0)); +export const getHeadPriceObs = (query: IQuery, isLive: boolean) => + queryToObservable(query, isLive).pipe(map((r) => head(r)?.price || 0)); // Used to be 42, changed to 5 to support milestone get and transactions subset export const minAddressLength = 5; @@ -90,3 +113,7 @@ export const shouldSetProjectFilter = (dataset: Dataset, subset?: Subset): boole Dataset.MILESTONE_SMR, Dataset.TICKER, ].includes(dataset) && !subset; + +export const keyToPg = (key: string) => { + return key.replace(/\./g, '_') as any; +}; diff --git a/packages/search/src/getAddresses.ts b/packages/search/src/getAddresses.ts index 0f2cee0b03..5af69cfe0d 100644 --- a/packages/search/src/getAddresses.ts +++ b/packages/search/src/getAddresses.ts @@ -13,19 +13,17 @@ const getAddressesSchema = Joi.object({ createdAfter: Joi.number().min(0).max(MAX_MILLISECONDS).integer().required(), }); -export const getAddresses = async (url: string) => { +export const getAddresses = async (url: string, isLive: boolean) => { const body = getQueryParams(url, getAddressesSchema); const query = build5Db() .collection(COL.MNEMONIC) .where('network', '==', body.network) + .where('createdOn', '>', dayjs.unix(body.createdAfter).toDate()) .orderBy('createdOn') - .startAfter(dayjs.unix(body.createdAfter).toDate()) .limit(1000); - return queryToObservable(query).pipe( - map((mnemonics) => mnemonics.map(sanitizeMnemonic)), - ); + return queryToObservable(query, isLive).pipe(map((mnemonics) => mnemonics.map(sanitizeMnemonic))); }; const sanitizeMnemonic = (mnemonic: Mnemonic) => ({ diff --git a/packages/search/src/getAvgPrice.ts b/packages/search/src/getAvgPrice.ts index 424398f474..fad0b54a8b 100644 --- a/packages/search/src/getAvgPrice.ts +++ b/packages/search/src/getAvgPrice.ts @@ -1,11 +1,5 @@ import { build5Db } from '@build-5/database'; -import { - Dataset, - GetAvgPriceRequest, - QUERY_MAX_LENGTH, - QUERY_MIN_LENGTH, - TokenPurchaseAge, -} from '@build-5/interfaces'; +import { COL, GetAvgPriceRequest, QUERY_MAX_LENGTH, QUERY_MIN_LENGTH } from '@build-5/interfaces'; import Joi from 'joi'; import { combineLatest, map } from 'rxjs'; import { CommonJoi, getHeadPriceObs, getQueryParams } from './common'; @@ -19,20 +13,20 @@ const getAvgPriceSchema = Joi.object({ .required(), }); -export const getAvgPrice = async (url: string) => { +export const getAvgPrice = async (url: string, isLive: boolean) => { const body = getQueryParams(url, getAvgPriceSchema); const tokens = Array.isArray(body.token) ? body.token : [body.token]; - const changes = tokens.map(getAvgLive); + const changes = tokens.map((t) => getAvgLive(t, isLive)); const observable = combineLatest(changes).pipe(map((r) => (r.length === 1 ? r[0] : r))); return observable; }; -const getAvgLive = (token: string) => { - const lowestPurchaseObs = getHeadPriceObs(purchaseQuery(token, true)); - const highestPurchaseObs = getHeadPriceObs(purchaseQuery(token, false)); - const lastPurchaseObs = getHeadPriceObs(purchaseQuery(token)); +const getAvgLive = (token: string, isLive: boolean) => { + const lowestPurchaseObs = getHeadPriceObs(purchaseQuery(token, true), isLive); + const highestPurchaseObs = getHeadPriceObs(purchaseQuery(token, false), isLive); + const lastPurchaseObs = getHeadPriceObs(purchaseQuery(token), isLive); return combineLatest([lowestPurchaseObs, highestPurchaseObs, lastPurchaseObs]).pipe( map(([lowest, highest, last]) => (highest + lowest + last) / 3), map((avg) => ({ id: token, avg })), @@ -42,18 +36,23 @@ const getAvgLive = (token: string) => { const purchaseQuery = (token: string, lowest?: boolean) => { if (lowest === undefined) { return build5Db() - .collection(Dataset.TOKEN_PURCHASE) + .collection(COL.TOKEN_PURCHASE) .where('token', '==', token) - .orderBy('createdOn') - .limitToLast(1); + .orderBy('createdOn', 'desc') + .limit(1); } - const query = build5Db() - .collection(Dataset.TOKEN_PURCHASE) - .where('token', '==', token) - .where('age', 'array-contains', TokenPurchaseAge.IN_7_D) - .orderBy('price', 'asc'); if (lowest) { - return query.limit(1); + return build5Db() + .collection(COL.TOKEN_PURCHASE) + .where('token', '==', token) + .where('in7d', '==', true) + .orderBy('price', 'asc') + .limit(1); } - return query.limitToLast(1); + return build5Db() + .collection(COL.TOKEN_PURCHASE) + .where('token', '==', token) + .where('in7d', '==', true) + .orderBy('price', 'desc') + .limit(1); }; diff --git a/packages/search/src/getById.ts b/packages/search/src/getById.ts index 489480610d..715390df1d 100644 --- a/packages/search/src/getById.ts +++ b/packages/search/src/getById.ts @@ -1,5 +1,5 @@ -import { build5Db } from '@build-5/database'; -import { Dataset, GetByIdRequest, Subset } from '@build-5/interfaces'; +import { BaseRecord, IDocument, Update, build5Db } from '@build-5/database'; +import { COL, Dataset, GetByIdRequest, SUB_COL, Subset } from '@build-5/interfaces'; import Joi from 'joi'; import { map } from 'rxjs'; import { @@ -21,16 +21,17 @@ const getByIdSchema = Joi.object({ subsetId: CommonJoi.uid(false, 7), }); -export const getById = async (url: string) => { +export const getById = async (url: string, isLive: boolean) => { const body = getQueryParams(url, getByIdSchema); - const docPath = - body.subset && body.subsetId - ? `${body.dataset}/${body.setId}/${body.subset}/${body.subsetId}` - : `${body.dataset}/${body.setId}`; - const docRef = build5Db().doc(docPath); + const docRef = build5Db().doc( + body.dataset as unknown as COL, + body.setId, + body.subset as unknown as SUB_COL, + body.subsetId, + )! as unknown as IDocument; - const observable = documentToObservable>(docRef).pipe( + const observable = documentToObservable(docRef, isLive).pipe( map((data) => { if (!data || isHiddenNft(body.dataset, data)) { return {}; diff --git a/packages/search/src/getMany.ts b/packages/search/src/getMany.ts index e78c51acb3..86331f8e21 100644 --- a/packages/search/src/getMany.ts +++ b/packages/search/src/getMany.ts @@ -1,10 +1,11 @@ -import { build5Db, getSnapshot } from '@build-5/database'; +import { BaseRecord, IDocument, IQuery, Update, build5Db } from '@build-5/database'; import { COL, Dataset, GetManyRequest, MAX_FIELD_NAME_LENGTH, MAX_FIELD_VALUE_LENGTH, + SUB_COL, Subset, WenError, } from '@build-5/interfaces'; @@ -15,6 +16,7 @@ import { CommonJoi, getQueryLimit, getQueryParams, + keyToPg, queryToObservable, shouldSetProjectFilter, } from './common'; @@ -47,21 +49,23 @@ const getManySchema = Joi.object({ startAfter: CommonJoi.uid(false), }); -export const getMany = async (project: string, url: string) => { +export const getMany = async (project: string, url: string, isLive: boolean) => { const body = getQueryParams(url, getManySchema); - const baseCollectionPath = - body.subset && body.setId ? `${body.dataset}/${body.setId}/${body.subset}` : body.dataset; let query = build5Db() - .collection(baseCollectionPath as COL) - .limit(getQueryLimit(body.dataset)); + .collection(body.dataset as unknown as COL, body.setId, body.subset as unknown as SUB_COL)! + .limit(getQueryLimit(body.dataset)) as unknown as IQuery; if (body.fieldName && body.fieldValue != null) { try { const filters = getFilters(body.fieldName, body.fieldValue); Object.entries(filters).forEach(([key, value]) => { const hasMany = value.length > 1; - query = query.where(key, hasMany ? 'in' : '==', hasMany ? value : value[0]); + if (hasMany) { + query = query.whereIn(keyToPg(key), value); + return; + } + query = query.where(keyToPg(key), '==', value[0]); }); } catch (error) { throw { code: 400, message: get(error, 'details.key', 'unknown') }; @@ -69,11 +73,11 @@ export const getMany = async (project: string, url: string) => { } if (body.dataset === Dataset.NFT) { - query = query.where('hidden', '==', false); + query = query.where('hidden' as any, '==', false); } if (body.dataset === Dataset.TRANSACTION) { - query = query.where('isOrderType', '==', false); + query = query.where('isOrderType' as any, '==', false); } if (shouldSetProjectFilter(body.dataset, body.subset)) { @@ -81,16 +85,19 @@ export const getMany = async (project: string, url: string) => { } if (body.startAfter) { - const startAfter = getSnapshot( - body.dataset, + const docRef = build5Db().doc( + body.dataset as unknown as COL, body.setId || body.startAfter, - body.subset, + body.subset as unknown as SUB_COL, body.startAfter, - ); - query = query.startAfter(await startAfter); + )! as unknown as IDocument; + const startAfter = await docRef.get(); + if (startAfter) { + query = query.startAfter(startAfter); + } } - const observable = queryToObservable>(query).pipe( + const observable = queryToObservable(query, isLive).pipe( map((snap) => snap.filter((d) => !isEmpty(d)).map((d) => ({ id: d.uid, ...d }))), ); return observable; diff --git a/packages/search/src/getManyAdvanced.ts b/packages/search/src/getManyAdvanced.ts index 2d70ba2c2a..b61d00e869 100644 --- a/packages/search/src/getManyAdvanced.ts +++ b/packages/search/src/getManyAdvanced.ts @@ -1,4 +1,11 @@ -import { build5Db, getSnapshot } from '@build-5/database'; +import { + BaseRecord, + ICollection, + IDocument, + Update, + WhereFilterOp, + build5Db, +} from '@build-5/database'; import { COL, Dataset, @@ -7,6 +14,7 @@ import { MAX_FIELD_VALUE_LENGTH, Opr, QUERY_MAX_LENGTH, + SUB_COL, Subset, TransactionType, WenError, @@ -18,6 +26,7 @@ import { CommonJoi, getQueryLimit, getQueryParams, + keyToPg, queryToObservable, shouldSetProjectFilter, } from './common'; @@ -52,7 +61,7 @@ const getManyAdvancedSchema = Joi.object({ startAfter: CommonJoi.uid(false), }); -export const getManyAdvanced = async (project: string, url: string) => { +export const getManyAdvanced = async (project: string, url: string, isLive: boolean) => { const body = getQueryParams(url, getManyAdvancedSchema); const { dataset, subset, setId } = body; @@ -62,11 +71,11 @@ export const getManyAdvanced = async (project: string, url: string) => { try { for (const [key, values] of Object.entries(filters)) { if (operators[key][0] === Opr.IN) { - query = query.where(key, operators[key][0], values); + query = query.whereIn(keyToPg(key), values); continue; } for (let i = 0; i < values.length; ++i) { - query = query.where(key, operators[key][i], values[i]); + query = query.where(keyToPg(key), operators[key][i] as WhereFilterOp, values[i]); } } } catch (error) { @@ -74,11 +83,11 @@ export const getManyAdvanced = async (project: string, url: string) => { } if (body.dataset === Dataset.NFT && !isEqual(filters['hidden'], [false])) { - query = query.where('hidden', '==', false); + query = query.where('hidden' as any, '==', false); } if (shouldSetProjectFilter(body.dataset, body.subset)) { - query = query.where('project', '==', project); + query = query.where('project' as any, '==', project); } const typeFilters = filters['type']; @@ -86,12 +95,12 @@ export const getManyAdvanced = async (project: string, url: string) => { body.dataset === Dataset.TRANSACTION && (!typeFilters || typeFilters.includes(TransactionType.ORDER)) ) { - query = query.where('isOrderType', '==', false); + query = query.where('isOrderType' as any, '==', false); } const orderByDir = (body.orderByDir || []) as ('asc' | 'desc')[]; for (let i = 0; i < (body.orderBy?.length || 0); ++i) { - query = query.orderBy(body.orderBy![i], orderByDir[i]); + query = query.orderBy(keyToPg(body.orderBy![i]), orderByDir[i]); } if (body.limit) { @@ -99,16 +108,19 @@ export const getManyAdvanced = async (project: string, url: string) => { } if (body.startAfter) { - const startAfter = await getSnapshot( - body.dataset, + const docRef = build5Db().doc( + body.dataset as unknown as COL, body.setId || body.startAfter, - body.subset, + body.subset as unknown as SUB_COL, body.startAfter, - ); - query = query.startAfter(startAfter); + )! as unknown as IDocument; + const startAfter = await docRef.get(); + if (startAfter) { + query = query.startAfter(startAfter); + } } - return queryToObservable>(query).pipe( + return queryToObservable(query, isLive).pipe( map((snap) => snap.filter((d) => !isEmpty(d)).map((d) => ({ id: d.uid, ...d }))), ); }; @@ -139,10 +151,9 @@ const getFilters = (fieldNames?: string[], fieldValues?: unknown[], fieldOperato return { filters: nameAndValues, operators: nameAndOperators }; }; -const getBaseQuery = (dataset: Dataset, setId?: string, subset?: Subset) => { - if (!setId && subset) { - return build5Db().collectionGroup(subset); - } - const path = subset && setId ? `${dataset}/${setId}/${subset}` : dataset; - return build5Db().collection(path as COL); -}; +const getBaseQuery = (dataset: Dataset, setId?: string, subset?: Subset) => + build5Db().collection( + dataset as unknown as COL, + setId, + subset as unknown as SUB_COL, + )! as unknown as ICollection; diff --git a/packages/search/src/getManyById.ts b/packages/search/src/getManyById.ts index ae4f31306b..15b7bab826 100644 --- a/packages/search/src/getManyById.ts +++ b/packages/search/src/getManyById.ts @@ -1,5 +1,12 @@ -import { build5Db } from '@build-5/database'; -import { Dataset, GetManyByIdRequest, QUERY_MAX_LENGTH, Subset } from '@build-5/interfaces'; +import { BaseRecord, IDocument, Update, build5Db } from '@build-5/database'; +import { + COL, + Dataset, + GetManyByIdRequest, + QUERY_MAX_LENGTH, + SUB_COL, + Subset, +} from '@build-5/interfaces'; import Joi from 'joi'; import { combineLatest, map } from 'rxjs'; import { @@ -23,10 +30,10 @@ const getManyByIdSchema = Joi.object({ subsetIds: Joi.array().items(uidSchema).min(1).max(QUERY_MAX_LENGTH).optional(), }); -export const getManyById = async (url: string) => { +export const getManyById = async (url: string, isLive: boolean) => { const body = getQueryParams(url, getManyByIdSchema); - const observables = getQueries(body).map(documentToObservable>); + const observables = getQueries(body).map((b) => documentToObservable(b, isLive)); return combineLatest(observables).pipe( map((all) => all.flat().filter((record) => record && !isHiddenNft(body.dataset, record))), ); @@ -35,11 +42,16 @@ export const getManyById = async (url: string) => { const getQueries = (body: GetManyByIdRequest) => body.setIds.map((setId, i) => { if (body.subset && body.subsetIds?.[i]) { - return build5Db() - .collection(body.dataset) - .doc(setId) - .collection(body.subset) - .doc(body.subsetIds[i]); + return build5Db().doc( + body.dataset as unknown as COL, + setId, + body.subset as unknown as SUB_COL, + body.subsetIds[i], + )! as unknown as IDocument; } - return build5Db().doc(`${body.dataset}/${setId}`); + return build5Db().doc(body.dataset as unknown as COL, setId)! as IDocument< + any, + BaseRecord, + Update + >; }); diff --git a/packages/search/src/getPriceChange.ts b/packages/search/src/getPriceChange.ts index 17eac34801..68740bed72 100644 --- a/packages/search/src/getPriceChange.ts +++ b/packages/search/src/getPriceChange.ts @@ -1,10 +1,10 @@ -import { IQuery, build5Db } from '@build-5/database'; +import { IQuery, PgTokenPurchase, build5Db } from '@build-5/database'; import { - Dataset, + COL, GetPriceChangeRequest, QUERY_MAX_LENGTH, QUERY_MIN_LENGTH, - TokenPurchaseAge, + TokenPurchase, } from '@build-5/interfaces'; import dayjs from 'dayjs'; import Joi from 'joi'; @@ -20,18 +20,18 @@ const getAvgPriceSchema = Joi.object({ .required(), }); -export const getPriceChange = async (url: string) => { +export const getPriceChange = async (url: string, isLive: boolean) => { const body = getQueryParams(url, getAvgPriceSchema); const tokens = Array.isArray(body.token) ? body.token : [body.token]; - const changes = tokens.map(getPriceChangeLive); + const changes = tokens.map((t) => getPriceChangeLive(t, isLive)); return combineLatest(changes).pipe(map((r) => (r.length === 1 ? r[0] : r))); }; -const getPriceChangeLive = (token: string) => { - const today = getVWAPForDates(token, purchaseQueryToday); - const yesterday = getVWAPForDates(token, purchaseQueryYesterday); +const getPriceChangeLive = (token: string, isLive: boolean) => { + const today = getVWAPForDates(token, purchaseQueryToday, isLive); + const yesterday = getVWAPForDates(token, purchaseQueryYesterday, isLive); return combineLatest([today, yesterday]).pipe( map(([last, secondToLast]) => { if (!secondToLast) { @@ -44,11 +44,12 @@ const getPriceChangeLive = (token: string) => { const getVWAPForDates = ( token: string, - queryBuilder: (token: string, lowest?: boolean) => IQuery, + queryBuilder: (token: string, lowest?: boolean) => IQuery, + isLive: boolean, ) => { - const lowestPurchaseObs = getHeadPriceObs(queryBuilder(token, true)); - const highestPurchaseObs = getHeadPriceObs(queryBuilder(token, false)); - const lastPurchaseObs = getHeadPriceObs(queryBuilder(token)); + const lowestPurchaseObs = getHeadPriceObs(queryBuilder(token, true), isLive); + const highestPurchaseObs = getHeadPriceObs(queryBuilder(token, false), isLive); + const lastPurchaseObs = getHeadPriceObs(queryBuilder(token), isLive); return combineLatest([lowestPurchaseObs, highestPurchaseObs, lastPurchaseObs]).pipe( map(([lowest, highest, last]) => (highest + lowest + last) / 3), ); @@ -57,40 +58,53 @@ const getVWAPForDates = ( const purchaseQueryToday = (token: string, lowest?: boolean) => { if (lowest === undefined) { return build5Db() - .collection(Dataset.TOKEN_PURCHASE) + .collection(COL.TOKEN_PURCHASE) .where('token', '==', token) .where('createdOn', '>=', dayjs().subtract(1, 'd').toDate()) - .orderBy('createdOn') - .limitToLast(1); + .orderBy('createdOn', 'desc') + .limit(1); } - const query = build5Db() - .collection(Dataset.TOKEN_PURCHASE) - .where('token', '==', token) - .where('age', 'array-contains', TokenPurchaseAge.IN_24_H) - .orderBy('price', 'asc'); if (lowest) { - return query.limit(1); + return build5Db() + .collection(COL.TOKEN_PURCHASE) + .where('token', '==', token) + .where('in24h', '==', true) + .orderBy('price') + .limit(1); } - return query.limitToLast(1); + return build5Db() + .collection(COL.TOKEN_PURCHASE) + .where('token', '==', token) + .where('in24h', '==', true) + .orderBy('price', 'desc') + .limit(1); }; const purchaseQueryYesterday = (token: string, lowest?: boolean) => { if (lowest === undefined) { return build5Db() - .collection(Dataset.TOKEN_PURCHASE) + .collection(COL.TOKEN_PURCHASE) .where('token', '==', token) .where('createdOn', '<', dayjs().subtract(1, 'd').toDate()) .where('createdOn', '>=', dayjs().subtract(2, 'd').toDate()) - .orderBy('createdOn') - .limitToLast(1); + .orderBy('createdOn', 'desc') + .limit(1); } - const query = build5Db() - .collection(Dataset.TOKEN_PURCHASE) - .where('token', '==', token) - .where('age', '==', [TokenPurchaseAge.IN_48_H, TokenPurchaseAge.IN_7_D]) - .orderBy('price', 'asc'); if (lowest) { - return query.limit(1); + return build5Db() + .collection(COL.TOKEN_PURCHASE) + .where('token', '==', token) + .where('in48h', '==', true) + .where('in7d', '==', true) + .orderBy('price') + .limit(1); } - return query.limitToLast(1); + + return build5Db() + .collection(COL.TOKEN_PURCHASE) + .where('token', '==', token) + .where('in48h', '==', true) + .where('in7d', '==', true) + .orderBy('price', 'desc') + .limit(1); }; diff --git a/packages/search/src/getTokenPrice.ts b/packages/search/src/getTokenPrice.ts index 1e2bdcc8f6..7ad56eac80 100644 --- a/packages/search/src/getTokenPrice.ts +++ b/packages/search/src/getTokenPrice.ts @@ -1,20 +1,19 @@ import { build5Db } from '@build-5/database'; import { COL, - Dataset, GetTokenPrice, MIN_IOTA_AMOUNT, QUERY_MAX_LENGTH, QUERY_MIN_LENGTH, - Ticker, TICKERS, + Ticker, TokenTradeOrder, TokenTradeOrderStatus, TokenTradeOrderType, } from '@build-5/interfaces'; import Joi from 'joi'; import { head } from 'lodash'; -import { combineLatest, map, Observable } from 'rxjs'; +import { Observable, combineLatest, map } from 'rxjs'; import { CommonJoi, documentToObservable, getQueryParams, queryToObservable } from './common'; const getTokenPriceSchema = Joi.object({ @@ -26,14 +25,14 @@ const getTokenPriceSchema = Joi.object({ .required(), }); -const tickerDocRef = build5Db().doc(`${COL.TICKER}/${TICKERS.SMRUSD}`); +const tickerDocRef = build5Db().doc(COL.TICKER, TICKERS.SMRUSD); -export const getTokenPrice = async (url: string) => { +export const getTokenPrice = async (url: string, isLive: boolean) => { const body = getQueryParams(url, getTokenPriceSchema); - const ticker = documentToObservable(tickerDocRef); + const ticker = documentToObservable(tickerDocRef, isLive); const tokens = Array.isArray(body.token) ? body.token : [body.token]; - const observables = tokens.map((token) => getPriceForTokenLive(token, ticker)); + const observables = tokens.map((token) => getPriceForTokenLive(token, ticker, isLive)); const combined = combineLatest(observables).pipe( map((result) => (result.length === 1 ? result[0] : result)), ); @@ -41,9 +40,9 @@ export const getTokenPrice = async (url: string) => { return combined; }; -const getPriceForTokenLive = (token: string, ticker: Observable) => { - const lowestSell = queryToObservable(lowestSellQuery(token)); - const highestBuy = queryToObservable(highestBuyQuery(token)); +const getPriceForTokenLive = (token: string, ticker: Observable, isLive: boolean) => { + const lowestSell = queryToObservable(lowestSellQuery(token), isLive); + const highestBuy = queryToObservable(highestBuyQuery(token), isLive); const combined = combineLatest([lowestSell, highestBuy, ticker]).pipe( map(([lowestSell, highestBuy, ticker]) => { const price = calculatePrice(lowestSell, highestBuy); @@ -55,7 +54,7 @@ const getPriceForTokenLive = (token: string, ticker: Observable) => { const lowestSellQuery = (token: string) => build5Db() - .collection(Dataset.TOKEN_MARKET) + .collection(COL.TOKEN_MARKET) .where('status', '==', TokenTradeOrderStatus.ACTIVE) .where('token', '==', token) .where('type', '==', TokenTradeOrderType.SELL) @@ -64,12 +63,12 @@ const lowestSellQuery = (token: string) => const highestBuyQuery = (token: string) => build5Db() - .collection(Dataset.TOKEN_MARKET) + .collection(COL.TOKEN_MARKET) .where('status', '==', TokenTradeOrderStatus.ACTIVE) .where('token', '==', token) .where('type', '==', TokenTradeOrderType.BUY) - .orderBy('price') - .limitToLast(1); + .orderBy('price', 'desc') + .limit(1); const calculatePrice = ( lowestSellOrders: TokenTradeOrder[], diff --git a/packages/search/src/getTopMilestones.ts b/packages/search/src/getTopMilestones.ts index 78c9ddd782..66536db64a 100644 --- a/packages/search/src/getTopMilestones.ts +++ b/packages/search/src/getTopMilestones.ts @@ -3,9 +3,9 @@ import { Network, getMilestoneCol } from '@build-5/interfaces'; import { combineLatest, map } from 'rxjs'; import { queryToObservable } from './common'; -export const getTopMilestones = async (_: string) => { +export const getTopMilestones = async (_: string, isLive: boolean) => { const observables = Object.values(Network).map((network) => - queryToObservable(networkToQuery(network)).pipe(map((r) => ({ [network]: r[0] }))), + queryToObservable(networkToQuery(network), isLive).pipe(map((r) => ({ [network]: r[0] }))), ); return combineLatest(observables).pipe(map((r) => r.reduce((acc, act) => ({ ...acc, ...act })))); }; diff --git a/packages/search/src/getUpdatedAfter.ts b/packages/search/src/getUpdatedAfter.ts index 4937d7b326..ddfb635d95 100644 --- a/packages/search/src/getUpdatedAfter.ts +++ b/packages/search/src/getUpdatedAfter.ts @@ -1,9 +1,10 @@ -import { build5Db, getSnapshot } from '@build-5/database'; +import { BaseRecord, ICollection, IDocument, Update, build5Db } from '@build-5/database'; import { COL, Dataset, GetUpdatedAfterRequest, MAX_MILLISECONDS, + SUB_COL, Subset, } from '@build-5/interfaces'; import dayjs from 'dayjs'; @@ -30,28 +31,27 @@ const getUpdatedAfterSchema = Joi.object({ startAfter: CommonJoi.uid(false), }); -export const getUpdatedAfter = async (project: string, url: string) => { +export const getUpdatedAfter = async (project: string, url: string, isLive: boolean) => { const body = getQueryParams(url, getUpdatedAfterSchema); - const isSubCollectionQuery = body.subset && body.setId; - const baseCollectionPath = isSubCollectionQuery - ? `${body.dataset}/${body.setId}/${body.subset}` - : body.dataset; - const updatedAfter = body.updatedAfter ? dayjs.unix(body.updatedAfter) : dayjs().subtract(1, 'h'); - let query = build5Db() - .collection(baseCollectionPath as COL) + const collection = build5Db().collection( + body.dataset as unknown as COL, + body.setId, + body.subset as unknown as SUB_COL, + )! as unknown as ICollection; + let query = collection .where('updatedOn', '>=', updatedAfter.toDate()) .orderBy('updatedOn') .limit(getQueryLimit(body.dataset)); if (body.dataset === Dataset.NFT) { - query = query.where('hidden', '==', false); + query = query.where('hidden' as any, '==', false); } if (body.dataset === Dataset.TRANSACTION) { - query = query.where('isOrderType', '==', false); + query = query.where('isOrderType' as any, '==', false); } if (shouldSetProjectFilter(body.dataset, body.subset)) { @@ -59,11 +59,19 @@ export const getUpdatedAfter = async (project: string, url: string) => { } if (body.startAfter) { - const startAfter = await getSnapshot(baseCollectionPath as COL, body.startAfter); - query = query.startAfter(startAfter); + const docRef = build5Db().doc( + body.dataset as unknown as COL, + body.setId || body.startAfter, + body.subset as unknown as SUB_COL, + body.startAfter, + )! as unknown as IDocument; + const startAfter = await docRef.get(); + if (startAfter) { + query = query.startAfter(startAfter); + } } - return queryToObservable>(query).pipe( + return queryToObservable>(query, isLive).pipe( map((snap) => snap.filter((d) => !isEmpty(d)).map((d) => ({ id: d.uid, ...d }))), ); }; diff --git a/packages/search/src/index.ts b/packages/search/src/index.ts index e74d975beb..9031d0271e 100644 --- a/packages/search/src/index.ts +++ b/packages/search/src/index.ts @@ -62,11 +62,14 @@ const onConnection = async (jwtToken: string, url: URL, res: express.Response | try { const project = getProjectId(jwtToken); - const observable = await getObservable(project, url); - if (res instanceof ws.WebSocket) { + const isLive = res instanceof ws.WebSocket; + const observable = await getObservable(project, url, isLive); + + if (isLive) { sendLiveUpdates(res, observable); return; } + observable.pipe(first()).subscribe({ next: (r) => { res.send(r); @@ -80,28 +83,32 @@ const onConnection = async (jwtToken: string, url: URL, res: express.Response | } }; -const getObservable = (project: string, url: URL): Promise> => { +const getObservable = ( + project: string, + url: URL, + isLive: boolean, +): Promise> => { switch (url.pathname) { case ApiRoutes.GET_BY_ID: - return getById(url.href); + return getById(url.href, isLive); case ApiRoutes.GET_MANY_BY_ID: - return getManyById(url.href); + return getManyById(url.href, isLive); case ApiRoutes.GET_MANY: - return getMany(project, url.href); + return getMany(project, url.href, isLive); case ApiRoutes.GET_MANY_ADVANCED: - return getManyAdvanced(project, url.href); + return getManyAdvanced(project, url.href, isLive); case ApiRoutes.GET_UPDATED_AFTER: - return getUpdatedAfter(project, url.href); + return getUpdatedAfter(project, url.href, isLive); case ApiRoutes.GET_TOKEN_PRICE: - return getTokenPrice(url.href); + return getTokenPrice(url.href, isLive); case ApiRoutes.GET_AVG_PRICE: - return getAvgPrice(url.href); + return getAvgPrice(url.href, isLive); case ApiRoutes.GET_PRICE_CHANGE: - return getPriceChange(url.href); + return getPriceChange(url.href, isLive); case ApiRoutes.GET_ADDRESSES: - return getAddresses(url.href); + return getAddresses(url.href, isLive); case ApiRoutes.GET_TOP_MILESTONES: - return getTopMilestones(url.href); + return getTopMilestones(url.href, isLive); case ApiRoutes.GET_NFT_MUTABLE_METADATA: return getNftMutableMetadata(url.href); case ApiRoutes.GET_NFT_IDS: diff --git a/post.functions.deploy.js b/post.functions.deploy.js deleted file mode 100644 index 7786ae8a5d..0000000000 --- a/post.functions.deploy.js +++ /dev/null @@ -1,18 +0,0 @@ -const fs = require('fs'); -const json = require('./packages/functions/package.json'); - -fs.writeFileSync( - 'packages/functions/package.json', - JSON.stringify( - { - ...json, - dependencies: { - ...json.dependencies, - '@build-5/interfaces': '*', - '@build-5/database': '*', - }, - }, - null, - 2, - ) + '\n', -); diff --git a/pre.functions.deploy.js b/pre.functions.deploy.js deleted file mode 100644 index 678d1e2ad3..0000000000 --- a/pre.functions.deploy.js +++ /dev/null @@ -1,18 +0,0 @@ -const fs = require('fs'); -const json = require('./packages/functions/package.json'); - -fs.writeFileSync( - 'packages/functions/package.json', - JSON.stringify( - { - ...json, - dependencies: { - ...json.dependencies, - '@build-5/interfaces': 'file:./interfaces', - '@build-5/database': 'file:./database', - }, - }, - null, - 2, - ) + '\n', -); diff --git a/storage.rules b/storage.rules deleted file mode 100644 index 70d1daf5fe..0000000000 --- a/storage.rules +++ /dev/null @@ -1,8 +0,0 @@ -rules_version = '2'; -service firebase.storage { - match /b/{bucket}/o { - match /{allPaths=**} { - allow read; - } - } -}