From 9ac60fcec74ccc5df8fcd8d96c79dda34d8dd88c Mon Sep 17 00:00:00 2001 From: Boldizsar Mezei Date: Fri, 20 Oct 2023 07:45:13 +0200 Subject: [PATCH] Docker build Scale settings Fixses Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes Fixes --- .dockerignore | 3 + .github/workflows/action_deploy-prod.yml | 45 +- .github/workflows/action_deploy-wen.yml | 45 +- .gitignore | 3 + data.proto | 162 ++++++ firebase.json | 10 - package.json | 4 +- packages/api/Dockerfile | 24 + packages/api/build.js | 12 - packages/api/package.json | 12 +- packages/api/src/index.ts | 6 +- packages/database/package.json | 2 +- packages/functions/Dockerfile | 24 + packages/functions/deploy.script.ts | 132 +++++ packages/functions/package.json | 18 +- .../functions/src/algolia/algolia.trigger.ts | 48 -- packages/functions/src/common.ts | 17 + .../address/AddressValidationRequestSchema.ts | 4 +- .../controls/{ => address}/address.control.ts | 12 +- .../auth/CutomTokenRequestSchema.ts | 0 .../src/controls/{ => auth}/auth.control.ts | 5 +- .../award/AwardAddOwnerRequestSchema.ts | 2 +- .../AwardApproveParticipantRequestSchema.ts | 2 +- .../award/AwardCancelRequestSchema.ts | 2 +- .../award/AwardCreateRequestSchema.ts | 4 +- .../award/AwardFundRequestSchema.ts | 2 +- .../award/AwardParticipateRequestSchema.ts | 2 +- .../award/AwardRejectRequestSchema.ts | 2 +- .../award/award.approve.participant.ts | 9 +- .../src/controls/award/award.cancel.ts | 6 +- .../src/controls/award/award.create.ts | 3 +- .../src/controls/award/award.fund.ts | 9 +- .../src/controls/award/award.owner.ts | 9 +- .../src/controls/award/award.participate.ts | 9 +- .../src/controls/award/award.reject.ts | 9 +- .../CollectionApproveRequestSchema.ts | 2 +- .../CollectionCreateRequestSchema.ts | 2 +- .../collection/CollectionMintRequestSchema.ts | 6 +- .../CollectionRejectRequestSchema.ts | 2 +- .../CollectionUpdateMintedRequestSchema.ts | 2 +- .../CollectionUpdateRequestSchema.ts | 2 +- .../collection/collection-mint.control.ts | 6 +- .../collection/collection.approve.control.ts | 9 +- .../collection/collection.create.control.ts | 6 +- .../collection/collection.reject.control.ts | 9 +- .../collection/collection.update.control.ts | 11 +- packages/functions/src/controls/common.ts | 15 + .../credit/CreditUnrefundableRequestSchema.ts | 2 +- .../src/controls/credit/credit.controller.ts | 9 +- .../file}/FileUploadRequestSchema.ts | 2 +- .../src/controls/file/file.upload.control.ts | 72 +++ .../member/CreateMemberRequestSchema.ts | 2 +- .../member/UpdateMemberRequestSchema.ts | 2 +- .../src/controls/member/member.create.ts | 3 +- .../src/controls/member/member.update.ts | 6 +- .../nft/NftBidRequestSchema.ts | 2 +- .../nft/NftCreateRequestSchema.ts | 2 +- .../nft/NftDepositRequestSchema.ts | 6 +- .../nft/NftPurchaseRequestSchema.ts | 2 +- .../nft/NftSetForSaleRequestSchema.ts | 2 +- .../nft/NftStakeRequestSchema.ts | 6 +- .../nft/NftUpdateUnsoldRequestSchema.ts | 2 +- .../nft/NftWithdrawRequestSchema.ts | 2 +- .../src/controls/nft/nft.bid.control.ts | 17 +- .../functions/src/controls/nft/nft.create.ts | 14 +- .../functions/src/controls/nft/nft.deposit.ts | 9 +- .../src/controls/nft/nft.puchase.control.ts | 18 +- .../src/controls/nft/nft.set.for.sale.ts | 9 +- .../functions/src/controls/nft/nft.stake.ts | 9 +- .../src/controls/nft/nft.update.unsold.ts | 9 +- .../src/controls/nft/nft.withdraw.ts | 3 +- .../proposal/ProposalApproveRequestSchema.ts | 2 +- .../proposal/ProposalCreateRequestSchema.ts | 4 +- .../proposal/ProposalRejectRequestSchema.ts | 2 +- .../proposal/ProposalVoteRequestSchema.ts | 2 +- .../proposal/approve.reject.proposal.ts | 3 +- .../src/controls/proposal/create.proposal.ts | 3 +- .../src/controls/proposal/vote.on.proposal.ts | 9 +- .../rank/RankRequestSchema.ts | 4 +- .../src/controls/{ => rank}/rank.control.ts | 13 +- .../space/SpaceClaimRequestSchema.ts | 2 +- .../space/SpaceCreateRequestSchema.ts | 2 +- .../space/SpaceEditMemberRequestSchema.ts | 2 +- .../space/SpaceJoinRequestSchema.ts | 2 +- .../space/SpaceLeaveRequestSchema.ts | 2 +- .../space/SpaceUpdateRequestSchema.ts | 2 +- .../controls/space/member.accept.control.ts | 6 +- .../controls/space/member.block.control.ts | 3 +- .../controls/space/member.decline.control.ts | 6 +- .../controls/space/member.leave.control.ts | 3 +- .../controls/space/member.unblock.control.ts | 6 +- .../src/controls/space/space.claim.control.ts | 3 +- .../controls/space/space.create.control.ts | 9 +- .../space/space.guardian.edit.control.ts | 4 +- .../src/controls/space/space.join.control.ts | 3 +- .../controls/space/space.update.control.ts | 3 +- .../stake/StakeRewardRemoveRequestSchema.ts | 2 +- .../stake/StakeRewardRequestSchema.ts | 2 +- .../stake/StakeTokenRequestSchema.ts | 2 +- .../src/controls/stake/stake.deposit.ts | 3 +- .../src/controls/stake/stake.reward.revoke.ts | 9 +- .../src/controls/stake/stake.reward.ts | 3 +- .../TokenClaimMintedRequestSchema.ts | 2 +- .../TokenImportRequestSchema.ts | 6 +- .../token-minting}/TokenMintRequestSchema.ts | 6 +- .../token-minting/airdrop-minted-token.ts | 10 +- .../claim-minted-token.control.ts | 9 +- .../token-minting/import-minted-token.ts | 6 +- .../token-minting/token-mint.control.ts | 3 +- .../TokenCanelTradeOrderRequestSchema.ts | 2 +- .../token-trading}/TokenTradeRequestSchema.ts | 4 +- .../token-trade-cancel.controller.ts | 3 +- .../token-trading/token-trade.controller.ts | 9 +- .../token}/TokenAirdropRequestSchema.ts | 2 +- .../token}/TokenCancelPubSaleRequestSchema.ts | 2 +- .../TokenClaimAirdroppedRequestSchema.ts | 2 +- .../token}/TokenCreateRequestSchema.ts | 4 +- .../token}/TokenCreditRequestSchema.ts | 2 +- .../token}/TokenEnableTradingRequestSchema.ts | 2 +- .../token}/TokenOrderRequestSchema.ts | 2 +- .../TokenSetAvailableForSaleRequestSchema.ts | 4 +- .../token}/TokenUpdateRequestSchema.ts | 2 +- .../functions/src/controls/token/common.ts | 15 +- .../src/controls/token/token.airdrop.claim.ts | 9 +- .../src/controls/token/token.airdrop.ts | 5 +- .../controls/token/token.cancel.pub.sale.ts | 6 +- .../src/controls/token/token.create.ts | 3 +- .../src/controls/token/token.credit.ts | 9 +- .../controls/token/token.enable.trading.ts | 9 +- .../src/controls/token/token.order.ts | 9 +- .../src/controls/token/token.set.for.sale.ts | 9 +- .../src/controls/token/token.update.ts | 12 +- .../vote/VoteRequestSchema.ts | 2 +- .../src/controls/{ => vote}/vote.control.ts | 9 +- packages/functions/src/cron.ts | 118 ----- packages/functions/src/cron/media.cron.ts | 3 +- .../functions/src/cron/stakeReward.cron.ts | 3 +- .../src/firebase/functions/onRequest.ts | 63 --- packages/functions/src/index.express.ts | 73 +++ packages/functions/src/index.ts | 270 +++------- packages/functions/src/runtime/common.ts | 62 +++ packages/functions/src/runtime/cron/index.ts | 93 ++++ .../functions/src/runtime/cron/scheduled.ts | 20 + .../src/runtime/firebase/address/index.ts | 9 +- .../src/runtime/firebase/auth/index.ts | 8 +- .../src/runtime/firebase/award/index.ts | 47 +- .../src/runtime/firebase/collection/index.ts | 42 +- .../functions/src/runtime/firebase/common.ts | 7 - .../src/runtime/firebase/credit/index.ts | 9 +- .../src/runtime/firebase/member/index.ts | 32 +- .../src/runtime/firebase/nft/index.ts | 68 +-- .../src/runtime/firebase/proposal/index.ts | 32 +- .../src/runtime/firebase/rank/index.ts | 6 +- .../src/runtime/firebase/space/index.ts | 83 +-- .../src/runtime/firebase/stake/index.ts | 22 +- .../runtime/firebase/storage/file.upload.ts | 102 +--- .../src/runtime/firebase/token/base/common.ts | 8 - .../src/runtime/firebase/token/base/index.ts | 76 +-- .../runtime/firebase/token/minting/index.ts | 27 +- .../runtime/firebase/token/trading/index.ts | 17 +- .../src/runtime/firebase/vote/index.ts | 6 +- packages/functions/src/runtime/https/https.ts | 56 ++ packages/functions/src/runtime/https/index.ts | 501 ++++++++++++++++++ .../src/runtime/https/middlewares.ts | 28 + .../src/runtime/proto/protoToJson.ts | 41 ++ .../functions/src/runtime/storage/index.ts | 9 + .../functions/src/runtime/storage/storage.ts | 19 + .../functions/src/runtime/trigger/index.ts | 108 ++++ .../functions/src/runtime/trigger/trigger.ts | 54 ++ packages/functions/src/scale.settings.ts | 182 ++++--- .../payment/nft/nft-deposit-service.ts | 3 +- .../services/payment/nft/nft-stake-service.ts | 3 +- .../tangle-service/TangleRequestService.ts | 3 +- .../AddressValidationTangleRequestSchema.ts | 2 +- .../AwardAppParticipantTangleRequestSchema.ts | 2 +- .../award/AwardCreateTangleRequestSchema.ts | 2 +- .../nft/NftSetForSaleTangleRequestSchema.ts | 2 +- .../ProposalCreateTangleRequestSchema.ts | 2 +- .../voting/ProposalVoteTangleRequestSchema.ts | 2 +- .../space/SpaceCreateTangleRequestSchema.ts | 2 +- .../SpaceEditMemberTangleRequestSchema.ts | 2 +- .../token/TokenStakeTangleRequestSchema.ts | 2 +- .../services/payment/transaction-service.ts | 3 +- .../src/services/wallet/NftWallet.ts | 3 +- .../src/services/wallet/wallet.service.ts | 5 +- .../src/triggers/algolia/algolia.trigger.ts | 41 ++ .../algolia/firestore.to.algolia.ts | 0 .../functions/src/triggers/award.trigger.ts | 168 +++--- .../src/triggers/collection.stats.trigger.ts | 26 +- .../src/triggers/collection.trigger.ts | 67 +-- packages/functions/src/triggers/common.ts | 11 + .../milestone-transactions-triggers/common.ts | 9 +- .../milestone-transaction.trigger.ts | 41 +- .../src/triggers/mnemonic.trigger.ts | 45 +- .../functions/src/triggers/nft.trigger.ts | 76 +-- .../src/triggers/proposal.trigger.ts | 54 +- .../triggers/storage/resize.img.trigger.ts | 67 +-- .../token-trading/token-purchase.trigger.ts | 66 +-- .../token-trade-order.trigger.ts | 53 +- .../functions/src/triggers/token.trigger.ts | 49 +- .../transaction-trigger/collection-minting.ts | 3 +- .../transaction-trigger/token-minting.ts | 3 +- .../transaction.trigger.ts | 222 ++++---- packages/functions/src/utils/car.utils.ts | 3 +- packages/functions/src/utils/error.utils.ts | 1 + packages/functions/src/utils/google.utils.ts | 13 - packages/functions/src/utils/media.utils.ts | 3 +- packages/functions/src/utils/schema.utils.ts | 3 +- .../award-tangle/award-tangle_3.spec.ts | 5 +- .../test-tangle/award/award_10.spec.ts | 5 +- .../test-tangle/award/award_2.spec.ts | 5 +- .../test-tangle/award/award_5.spec.ts | 5 +- .../test-tangle/award/award_7.spec.ts | 5 +- .../test-tangle/award/award_9.spec.ts | 2 +- packages/functions/test-tangle/faucet.ts | 8 +- .../minted-nft-trading_10.spec.ts | 2 +- .../minted-nft-trading_11.only.spec.ts | 2 +- .../minted-token-airdrop/Helper.ts | 4 +- .../token.claim.minted_1.spec.ts | 8 +- .../token.claim.minted_2.spec.ts | 8 +- .../token.claim.minted_3.spec.ts | 8 +- .../token.claim.minted_4.spec.ts | 8 +- .../token.claim.minted_5.spec.ts | 8 +- .../token.claim.minted_6.spec.ts | 8 +- .../token.claim.minted_7.spec.ts | 8 +- .../test-tangle/minted-token-trade/Helper.ts | 5 +- .../test-tangle/nft-staking/Helper.ts | 4 +- .../test-tangle/proposal-tangle/Helper.ts | 5 +- .../functions/test-tangle/staking/Helper.ts | 12 +- .../functions/test-tangle/staking/newFile.ts | 99 ---- .../test-tangle/staking/staking_1.spec.ts | 2 +- .../test-tangle/staking/staking_3.spec.ts | 3 +- .../test-tangle/staking/staking_4.spec.ts | 12 +- .../test-tangle/staking/staking_5.spec.ts | 2 +- .../test-tangle/token.based.voting/Helper.ts | 5 +- .../test-tangle/token.mint/Helper.ts | 4 +- .../transaction-trigger_3.spec.ts | 8 +- .../transaction-trigger_4.spec.ts | 8 +- .../withdraw-deposit-nft/Helper.ts | 4 +- .../deposit-withraw-nft_12_a.spec.ts | 9 +- .../deposit-withraw-nft_12_b.spec.ts | 9 +- .../deposit-withraw-nft_13.spec.ts | 9 +- packages/functions/test/auth.spec.ts | 48 -- packages/functions/test/milestone.sync.ts | 130 ++--- packages/functions/test/set-up.ts | 56 +- .../functions/test/storage/resize.img.spec.ts | 3 +- packages/interfaces/src/api/post/index.ts | 2 +- packages/interfaces/src/config.ts | 4 - packages/interfaces/src/functions/index.ts | 28 +- packages/interfaces/src/models/file.ts | 6 + packages/interfaces/src/models/index.ts | 1 + scripts/joi-generator-post.ts | 2 +- 252 files changed, 2891 insertions(+), 2294 deletions(-) create mode 100644 .dockerignore create mode 100644 data.proto create mode 100644 packages/api/Dockerfile delete mode 100644 packages/api/build.js create mode 100644 packages/functions/Dockerfile create mode 100644 packages/functions/deploy.script.ts delete mode 100644 packages/functions/src/algolia/algolia.trigger.ts create mode 100644 packages/functions/src/common.ts rename packages/functions/src/{runtime/firebase => controls}/address/AddressValidationRequestSchema.ts (81%) rename packages/functions/src/controls/{ => address}/address.control.ts (57%) rename packages/functions/src/{runtime/firebase => controls}/auth/CutomTokenRequestSchema.ts (100%) rename packages/functions/src/controls/{ => auth}/auth.control.ts (62%) rename packages/functions/src/{runtime/firebase => controls}/award/AwardAddOwnerRequestSchema.ts (86%) rename packages/functions/src/{runtime/firebase => controls}/award/AwardApproveParticipantRequestSchema.ts (91%) rename packages/functions/src/{runtime/firebase => controls}/award/AwardCancelRequestSchema.ts (80%) rename packages/functions/src/{runtime/firebase => controls}/award/AwardCreateRequestSchema.ts (93%) rename packages/functions/src/{runtime/firebase => controls}/award/AwardFundRequestSchema.ts (80%) rename packages/functions/src/{runtime/firebase => controls}/award/AwardParticipateRequestSchema.ts (85%) rename packages/functions/src/{runtime/firebase => controls}/award/AwardRejectRequestSchema.ts (80%) rename packages/functions/src/{runtime/firebase => controls}/collection/CollectionApproveRequestSchema.ts (82%) rename packages/functions/src/{runtime/firebase => controls}/collection/CollectionCreateRequestSchema.ts (96%) rename packages/functions/src/{runtime/firebase => controls}/collection/CollectionMintRequestSchema.ts (86%) rename packages/functions/src/{runtime/firebase => controls}/collection/CollectionRejectRequestSchema.ts (82%) rename packages/functions/src/{runtime/firebase => controls}/collection/CollectionUpdateMintedRequestSchema.ts (97%) rename packages/functions/src/{runtime/firebase => controls}/collection/CollectionUpdateRequestSchema.ts (95%) rename packages/functions/src/{runtime/firebase => controls}/credit/CreditUnrefundableRequestSchema.ts (84%) rename packages/functions/src/{runtime/firebase/storage => controls/file}/FileUploadRequestSchema.ts (88%) create mode 100644 packages/functions/src/controls/file/file.upload.control.ts rename packages/functions/src/{runtime/firebase => controls}/member/CreateMemberRequestSchema.ts (81%) rename packages/functions/src/{runtime/firebase => controls}/member/UpdateMemberRequestSchema.ts (93%) rename packages/functions/src/{runtime/firebase => controls}/nft/NftBidRequestSchema.ts (80%) rename packages/functions/src/{runtime/firebase => controls}/nft/NftCreateRequestSchema.ts (95%) rename packages/functions/src/{runtime/firebase => controls}/nft/NftDepositRequestSchema.ts (72%) rename packages/functions/src/{runtime/firebase => controls}/nft/NftPurchaseRequestSchema.ts (86%) rename packages/functions/src/{runtime/firebase => controls}/nft/NftSetForSaleRequestSchema.ts (97%) rename packages/functions/src/{runtime/firebase => controls}/nft/NftStakeRequestSchema.ts (83%) rename packages/functions/src/{runtime/firebase => controls}/nft/NftUpdateUnsoldRequestSchema.ts (88%) rename packages/functions/src/{runtime/firebase => controls}/nft/NftWithdrawRequestSchema.ts (81%) rename packages/functions/src/{runtime/firebase => controls}/proposal/ProposalApproveRequestSchema.ts (82%) rename packages/functions/src/{runtime/firebase => controls}/proposal/ProposalCreateRequestSchema.ts (94%) rename packages/functions/src/{runtime/firebase => controls}/proposal/ProposalRejectRequestSchema.ts (82%) rename packages/functions/src/{runtime/firebase => controls}/proposal/ProposalVoteRequestSchema.ts (89%) rename packages/functions/src/{runtime/firebase => controls}/rank/RankRequestSchema.ts (83%) rename packages/functions/src/controls/{ => rank}/rank.control.ts (81%) rename packages/functions/src/{runtime/firebase => controls}/space/SpaceClaimRequestSchema.ts (80%) rename packages/functions/src/{runtime/firebase => controls}/space/SpaceCreateRequestSchema.ts (94%) rename packages/functions/src/{runtime/firebase => controls}/space/SpaceEditMemberRequestSchema.ts (86%) rename packages/functions/src/{runtime/firebase => controls}/space/SpaceJoinRequestSchema.ts (80%) rename packages/functions/src/{runtime/firebase => controls}/space/SpaceLeaveRequestSchema.ts (80%) rename packages/functions/src/{runtime/firebase => controls}/space/SpaceUpdateRequestSchema.ts (93%) rename packages/functions/src/{runtime/firebase => controls}/stake/StakeRewardRemoveRequestSchema.ts (88%) rename packages/functions/src/{runtime/firebase => controls}/stake/StakeRewardRequestSchema.ts (96%) rename packages/functions/src/{runtime/firebase => controls}/stake/StakeTokenRequestSchema.ts (94%) rename packages/functions/src/{runtime/firebase/token/minting => controls/token-minting}/TokenClaimMintedRequestSchema.ts (82%) rename packages/functions/src/{runtime/firebase/token/minting => controls/token-minting}/TokenImportRequestSchema.ts (77%) rename packages/functions/src/{runtime/firebase/token/minting => controls/token-minting}/TokenMintRequestSchema.ts (72%) rename packages/functions/src/{runtime/firebase/token/trading => controls/token-trading}/TokenCanelTradeOrderRequestSchema.ts (82%) rename packages/functions/src/{runtime/firebase/token/trading => controls/token-trading}/TokenTradeRequestSchema.ts (86%) rename packages/functions/src/{runtime/firebase/token/base => controls/token}/TokenAirdropRequestSchema.ts (95%) rename packages/functions/src/{runtime/firebase/token/base => controls/token}/TokenCancelPubSaleRequestSchema.ts (81%) rename packages/functions/src/{runtime/firebase/token/base => controls/token}/TokenClaimAirdroppedRequestSchema.ts (86%) rename packages/functions/src/{runtime/firebase/token/base => controls/token}/TokenCreateRequestSchema.ts (97%) rename packages/functions/src/{runtime/firebase/token/base => controls/token}/TokenCreditRequestSchema.ts (88%) rename packages/functions/src/{runtime/firebase/token/base => controls/token}/TokenEnableTradingRequestSchema.ts (81%) rename packages/functions/src/{runtime/firebase/token/base => controls/token}/TokenOrderRequestSchema.ts (80%) rename packages/functions/src/{runtime/firebase/token/base => controls/token}/TokenSetAvailableForSaleRequestSchema.ts (92%) rename packages/functions/src/{runtime/firebase/token/base => controls/token}/TokenUpdateRequestSchema.ts (95%) rename packages/functions/src/{runtime/firebase => controls}/vote/VoteRequestSchema.ts (88%) rename packages/functions/src/controls/{ => vote}/vote.control.ts (87%) delete mode 100644 packages/functions/src/cron.ts delete mode 100644 packages/functions/src/firebase/functions/onRequest.ts create mode 100644 packages/functions/src/index.express.ts create mode 100644 packages/functions/src/runtime/common.ts create mode 100644 packages/functions/src/runtime/cron/index.ts create mode 100644 packages/functions/src/runtime/cron/scheduled.ts delete mode 100644 packages/functions/src/runtime/firebase/common.ts delete mode 100644 packages/functions/src/runtime/firebase/token/base/common.ts create mode 100644 packages/functions/src/runtime/https/https.ts create mode 100644 packages/functions/src/runtime/https/index.ts create mode 100644 packages/functions/src/runtime/https/middlewares.ts create mode 100644 packages/functions/src/runtime/proto/protoToJson.ts create mode 100644 packages/functions/src/runtime/storage/index.ts create mode 100644 packages/functions/src/runtime/storage/storage.ts create mode 100644 packages/functions/src/runtime/trigger/index.ts create mode 100644 packages/functions/src/runtime/trigger/trigger.ts create mode 100644 packages/functions/src/triggers/algolia/algolia.trigger.ts rename packages/functions/src/{ => triggers}/algolia/firestore.to.algolia.ts (100%) create mode 100644 packages/functions/src/triggers/common.ts delete mode 100644 packages/functions/src/utils/google.utils.ts delete mode 100644 packages/functions/test-tangle/staking/newFile.ts diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..034fff6ca1 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +**/node_modules +**/lib +**/scripts diff --git a/.github/workflows/action_deploy-prod.yml b/.github/workflows/action_deploy-prod.yml index a10d541b6c..e38c468818 100644 --- a/.github/workflows/action_deploy-prod.yml +++ b/.github/workflows/action_deploy-prod.yml @@ -19,16 +19,23 @@ jobs: credentials_json: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_SOONAVERSE }}' - name: 'Set up Cloud SDK' uses: 'google-github-actions/setup-gcloud@v1' - - name: 'Use gcloud CLI' - run: 'gcloud info' - - name: Install dependencies - run: npm install - - name: Build Instance - run: npm run build:api - - name: Deploy Instance + - name: Build image + run: | + cp packages/api/Dockerfile . + gcloud builds submit --tag gcr.io/$GOOGLE_CLOUD_PROJECT/api + - name: Deploy run: | - cd packages/api - npm run deploy:prod + gcloud run deploy api \ + --image gcr.io/$GOOGLE_CLOUD_PROJECT/api \ + --min-instances=3 \ + --memory=1Gi \ + --cpu=1 \ + --concurrency=1000 \ + --allow-unauthenticated \ + --timeout=600 \ + --ingress=internal-and-cloud-load-balancing \ + --region=us-central1 \ + deploy_functions: runs-on: ubuntu-latest environment: production @@ -37,17 +44,17 @@ jobs: - uses: actions/setup-node@v3 with: node-version: 18 - - name: Set env vars - working-directory: packages/functions - run: echo "$FUNCTIONS_ENV_VARS" >> .env - env: - FUNCTIONS_ENV_VARS: ${{ secrets.FUNCTIONS_ENV_VARS_PROD }} - - name: Deploy to Firebase - uses: w9jds/firebase-action@master + - id: 'auth' + uses: 'google-github-actions/auth@v1' with: - args: deploy --only functions,firestore:indexes -P soonaverse -f - env: - FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }} + credentials_json: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_SOONAVERSE_TEST }}' + - name: 'Set up Cloud SDK' + uses: 'google-github-actions/setup-gcloud@v1' + - name: Build and deploy + run: | + npm run create-deploy-script + chmod 777 ./deploy.sh + ./deploy.sh deploy_to_npm: runs-on: ubuntu-latest diff --git a/.github/workflows/action_deploy-wen.yml b/.github/workflows/action_deploy-wen.yml index 2eae35789f..ac40ffb586 100644 --- a/.github/workflows/action_deploy-wen.yml +++ b/.github/workflows/action_deploy-wen.yml @@ -20,16 +20,23 @@ jobs: credentials_json: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_SOONAVERSE_TEST }}' - name: 'Set up Cloud SDK' uses: 'google-github-actions/setup-gcloud@v1' - - name: 'Use gcloud CLI' - run: 'gcloud info' - - name: Install dependencies - run: npm install - - name: Build Instance - run: npm run build:api - - name: Deploy Instance + - name: Build image + run: | + cp packages/api/Dockerfile . + gcloud builds submit --tag gcr.io/$GOOGLE_CLOUD_PROJECT/api + - name: Deploy run: | - cd packages/api - npm run deploy:prod + gcloud run deploy api \ + --image gcr.io/$GOOGLE_CLOUD_PROJECT/api \ + --min-instances=3 \ + --memory=1Gi \ + --cpu=1 \ + --concurrency=1000 \ + --allow-unauthenticated \ + --timeout=600 \ + --ingress=internal-and-cloud-load-balancing \ + --region=us-central1 \ + deploy_functions: runs-on: ubuntu-latest environment: staging @@ -38,17 +45,17 @@ jobs: - uses: actions/setup-node@v3 with: node-version: 18 - - name: Set env vars - working-directory: packages/functions - run: echo "$FUNCTIONS_ENV_VARS" >> .env - env: - FUNCTIONS_ENV_VARS: ${{ secrets.FUNCTIONS_ENV_VARS_TEST }} - - name: Deploy to Firebase - uses: w9jds/firebase-action@master + - id: 'auth' + uses: 'google-github-actions/auth@v1' with: - args: deploy --only functions,firestore:indexes -P soonaverse-test -f - env: - FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }} + credentials_json: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_SOONAVERSE_TEST }}' + - name: 'Set up Cloud SDK' + uses: 'google-github-actions/setup-gcloud@v1' + - name: Build and deploy + run: | + npm run create-deploy-script + chmod 777 ./deploy.sh + ./deploy.sh roll-firestore: runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index d6626ecd64..a5023baaf1 100644 --- a/.gitignore +++ b/.gitignore @@ -60,3 +60,6 @@ dist package-lock.json packages/functions/scripts/*.json + +/Dockerfile +deploy.sh diff --git a/data.proto b/data.proto new file mode 100644 index 0000000000..94f4fbc0f7 --- /dev/null +++ b/data.proto @@ -0,0 +1,162 @@ +// 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"; +import "google/type/latlng.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 index 222fe6d958..32119dd4fa 100644 --- a/firebase.json +++ b/firebase.json @@ -5,16 +5,6 @@ "indexes": "firestore.indexes.json" }, "functions": { - "predeploy": [ - "npm run build:functions", - "cp -r packages/interfaces packages/functions/interfaces", - "sed -i.bu 's/\"*\"/\"file:.\\/interfaces\"/g' packages/functions/package.json", - "rm packages/functions/package.json.bu" - ], - "postdeploy": [ - "sed -i.bu 's/\"file:.\\/interfaces\"/\"*\"/g' packages/functions/package.json", - "rm packages/functions/package.json.bu" - ], "source": "packages/functions" }, "emulators": { diff --git a/package.json b/package.json index d467b5efb7..0b9100a537 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,9 @@ "prettier:database": "npx prettier --write ./packages/database", "prettier:api": "npx prettier --write ./packages/api", "prettier": "npm run prettier:functions; npm run prettier:interfaces; npm run prettier:indexes; npm run prettier:lib; npm run prettier:database; npm run prettier:api", - "joi-to-types": "ts-node ./scripts/joi-generator-post.ts && ts-node ./scripts/joi-generator-tangle.ts && npm run prettier" + "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", + "create-deploy-script": "ts-node packages/functions/deploy.script.ts" }, "devDependencies": { "joi-to-typescript": "4.7.0" diff --git a/packages/api/Dockerfile b/packages/api/Dockerfile new file mode 100644 index 0000000000..3b10d778be --- /dev/null +++ b/packages/api/Dockerfile @@ -0,0 +1,24 @@ +FROM node:18 + +WORKDIR api + +RUN apt-get -y update +RUN apt-get -y install libudev-dev +RUN apt-get -y install cmake +RUN apt-get -y install clang +RUN apt-get -y install openssl +RUN apt-get -y install build-essential + +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y +ENV PATH="/root/.cargo/bin:${PATH}" + +COPY packages/database packages/database +COPY packages/interfaces packages/interfaces +COPY packages/api packages/api +COPY package.json ./ + +RUN npm run build:api + +EXPOSE 8080 + +CMD [ "node", "packages/api/lib/index.js" ] diff --git a/packages/api/build.js b/packages/api/build.js deleted file mode 100644 index 1128fbce23..0000000000 --- a/packages/api/build.js +++ /dev/null @@ -1,12 +0,0 @@ -const package = require('./package.json'); -const fs = require('fs'); - -delete package.dependencies['@build-5/interfaces']; -const prodPackageJson = { - scripts: { - start: 'node index', - }, - dependencies: { ...package.dependencies, '@build-5/database': 'file:./database' }, -}; - -fs.writeFileSync('./lib/package.json', JSON.stringify(prodPackageJson)); diff --git a/packages/api/package.json b/packages/api/package.json index e4380e4130..699082fa45 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -12,17 +12,13 @@ ], "private": "true", "scripts": { - "build": "rm -rf lib && tsc && node build && cp -r ../database lib/database", - "start": "tsc && node lib/index", - "deploy:prod": "npm run build && npm run gceploy:prod", - "deploy:test": "npm run build && npm run gceploy:test", - "gceploy:prod": "gcloud run deploy api --min-instances=3 --memory=1Gi --cpu=1 --concurrency=1000 --allow-unauthenticated --timeout=600 --ingress=internal-and-cloud-load-balancing --region=us-central1 --source=lib", - "gceploy:test": "gcloud run deploy api --allow-unauthenticated --timeout=600 --ingress=internal-and-cloud-load-balancing --region=us-central1 --source=lib" + "build": "tsc", + "start": "tsc && node lib/index" }, "dependencies": { "@build-5/database": "*", "@build-5/interfaces": "*", - "@iota/sdk": "^1.1.0", + "@iota/sdk": "1.1.1", "cors": "^2.8.5", "dayjs": "^1.11.9", "express": "^4.18.2", @@ -36,6 +32,6 @@ "@types/express": "^4.17.17", "@types/lodash": "^4.14.197", "@types/ws": "^8.5.5", - "typescript": "^5.2.2" + "typescript": "4.9.5" } } diff --git a/packages/api/src/index.ts b/packages/api/src/index.ts index b1a80654cb..ff5f21592f 100644 --- a/packages/api/src/index.ts +++ b/packages/api/src/index.ts @@ -18,14 +18,12 @@ import { getNftMutableMetadata } from './metadataNft/getNftMutableMetadata'; import { getNftMutableMetadataHistory } from './metadataNft/getNftMutableMetadataHistory'; import { sendLiveUpdates } from './sendLiveUpdates'; -const port = process.env.PORT || 3000; +const port = 8080; const app = express(); app.use(cors()); -Object.values(ApiRoutes).forEach((route) => { - app.get('/api' + route, (req, res) => onConnection(req.url, res)); -}); +app.get('/*', (req, res) => onConnection(req.url, res)); const wsServer = new ws.Server({ noServer: true }); diff --git a/packages/database/package.json b/packages/database/package.json index 5b759426e8..95b35e50a8 100644 --- a/packages/database/package.json +++ b/packages/database/package.json @@ -24,6 +24,6 @@ "@types/lodash": "^4.14.197", "dotenv": "^16.3.1", "glob": "8.0.3", - "typescript": "^5.2.2" + "typescript": "4.9.5" } } diff --git a/packages/functions/Dockerfile b/packages/functions/Dockerfile new file mode 100644 index 0000000000..71ad102187 --- /dev/null +++ b/packages/functions/Dockerfile @@ -0,0 +1,24 @@ +FROM node:18 + +WORKDIR api + +RUN apt-get -y update +RUN apt-get -y install libudev-dev +RUN apt-get -y install cmake +RUN apt-get -y install clang +RUN apt-get -y install openssl +RUN apt-get -y install build-essential + +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y +ENV PATH="/root/.cargo/bin:${PATH}" + +COPY packages/database packages/database +COPY packages/interfaces packages/interfaces +COPY packages/functions packages/functions +COPY package.json ./ + +RUN npm run build:functions + +EXPOSE 8080 + +CMD [ "node", "packages/functions/lib/index.express.js" ] diff --git a/packages/functions/deploy.script.ts b/packages/functions/deploy.script.ts new file mode 100644 index 0000000000..81e4449214 --- /dev/null +++ b/packages/functions/deploy.script.ts @@ -0,0 +1,132 @@ +import fs from 'fs'; +import { flattenObject } from './src/common'; +import { CloudFunctions } from './src/runtime/common'; +import * as onScheduled from './src/runtime/cron/index'; +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'; +fs.writeFileSync(file, 'cp packages/functions/Dockerfile ./Dockerfile\n\n'); + +fs.appendFileSync(file, 'gcloud builds submit --tag gcr.io/$GOOGLE_CLOUD_PROJECT/functions\n\n'); + +fs.appendFileSync(file, `export GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project)\n\n`); + +fs.appendFileSync( + file, + "export PROJECT_NUMBER=$(gcloud projects describe $(gcloud config get-value project) --format='value(projectNumber)')\n\n", +); + +Object.entries({ + ...flattenObject(onRequests), + ...flattenObject(onTriggers), + ...flattenObject(onScheduled), + ...flattenObject(onStorage), +}).forEach(([name, value]) => { + 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 \\ +`; + if (options?.timeoutSeconds) { + command += ` --timeout=${options.timeoutSeconds} \\\n`; + } + if (options?.concurrency) { + command += ` --concurrency=${options.concurrency} \\\n`; + } + if (options?.memory) { + command += ` --memory=${options.memory.replace('B', '')} \\\n`; + } + if (options?.minInstances) { + command += ` --min-instances=${options.minInstances} \\\n`; + } + if (options?.cpu) { + command += ` --cpu=${options.cpu} \\\n`; + } + fs.appendFileSync(file, command + ' &\n\n'); +}); + +fs.appendFileSync(file, 'wait\n\n'); + +Object.entries(flattenObject(onStorage)).forEach(([name, value]) => { + const options = (value as CloudFunctions).runtimeOptions; + let 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 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, value]) => { + const options = (value as CloudFunctions).runtimeOptions; + const type = (value as TriggeredFunction).type; + const document = (value as TriggeredFunction).document; + let 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="document=${document}" \\ + --event-filters="namespace=(default)" \\ + --event-filters="type=${getTriggerType(type)}" \\ + --event-data-content-type="application/protobuf"\nfi &\n\n`; + fs.appendFileSync(file, command + ''); +}); + +Object.entries(flattenObject(onScheduled)).forEach(([name, value]) => { + 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); +}); + +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`; + fs.appendFileSync(file, command); +}); + +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`; + fs.appendFileSync(file, command); +}); + +fs.appendFileSync(file, 'wait\n\n'); diff --git a/packages/functions/package.json b/packages/functions/package.json index 30ddaab18b..2a609c5b9a 100644 --- a/packages/functions/package.json +++ b/packages/functions/package.json @@ -20,20 +20,10 @@ "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\" ", - "shell": "npm run build && firebase functions:shell", - "start": "npm run shell", - "export-online-test-credentials": "export GOOGLE_APPLICATION_CREDENTIALS=\"./test-service-account-key.json\"", "test": "export LOCAL_TEST=true && jest --runInBand", - "test-online": "npm run export-online-test-credentials && jest test/ --runInBand", "test-tangle": "export LOCAL_TEST=true && jest test-tangle/ --runInBand ", - "test-tangle-online": "npm run export-online-test-credentials && jest test-tangle/ --runInBand", "test:ci": "export LOCAL_TEST=true && jest test/ --runInBand --ci --config=jest.config.ci.js", - "test-online:ci": "npm run export-online-test-credentials && 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", - "test-tangle-online:ci": "npm run export-online-test-credentials && jest test-tangle/ --runInBand --ci --config=jest.config.ci.js", - "test:watch": "jest test/ --watch-all --detect-open-handles", - "deploy": "firebase deploy --only functions -f", - "logs": "firebase functions:log" + "test-tangle:ci": "export LOCAL_TEST=true && jest test-tangle/ --runInBand --ci --config=jest.config.ci.js" }, "devDependencies": { "@types/busboy": "1.5.0", @@ -70,19 +60,20 @@ "ts-jest": "29.0.5", "ts-node": "10.9.1", "ts-sinon": "2.0.2", - "typescript": "4.8.4" + "typescript": "4.9.5" }, "dependencies": { "@build-5/interfaces": "*", "@ffmpeg-installer/ffmpeg": "1.1.0", "@ffprobe-installer/ffprobe": "2.0.0", - "@iota/sdk": "^1.1.0", + "@iota/sdk": "1.1.1", "@metamask/eth-sig-util": "5.0.2", "algoliasearch": "4.16.0", "axios": "1.3.4", "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.1.1", "dayjs": "1.11.7", @@ -98,6 +89,7 @@ "lodash": "4.17.21", "mime-types": "2.1.35", "node-ipinfo": "3.4.0", + "protobufjs": "^7.2.5", "rxjs": "7.8.1", "sharp": "0.32.0", "web3.storage": "4.5.4" diff --git a/packages/functions/src/algolia/algolia.trigger.ts b/packages/functions/src/algolia/algolia.trigger.ts deleted file mode 100644 index 0a2d86667b..0000000000 --- a/packages/functions/src/algolia/algolia.trigger.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { ALGOLIA_COLLECTIONS, COL } from '@build-5/interfaces'; -import algoliasearch from 'algoliasearch'; -import * as functions from 'firebase-functions/v2'; -import { scaleAlgolia } from '../scale.settings'; -import { algoliaAppId, algoliaKey, isEmulatorEnv } from '../utils/config.utils'; -import { docToAlgoliaData } from './firestore.to.algolia'; -const client = algoliasearch(algoliaAppId(), algoliaKey()); - -const deleteObject = async (col: COL, objectID: string) => { - try { - await client.initIndex(col).deleteObject(objectID); - } catch (error) { - functions.logger.error(col, objectID, error); - } -}; - -const upsertObject = async (rawData: Record, col: COL, objectID: string) => { - const data = docToAlgoliaData({ ...rawData, objectID, id: objectID }); - try { - await client.initIndex(col).saveObject(data).wait(); - } catch (error) { - functions.logger.error(col, objectID, error); - } -}; - -export const algoliaTrigger = ALGOLIA_COLLECTIONS.map((col) => ({ - [col]: functions.firestore.onDocumentWritten( - { document: col + '/{documentId}', ...scaleAlgolia(col) }, - async (event) => { - if (isEmulatorEnv()) { - return; - } - const prev = event.data?.before?.data(); - const curr = event.data?.after?.data(); - const objectID = curr?.uid || prev?.uid || ''; - - if (!objectID) { - return; - } - - if (!curr) { - return await deleteObject(col, objectID); - } - - return await upsertObject(curr, col, objectID); - }, - ), -})).reduce((acc, act) => ({ ...acc, ...act }), {}); diff --git a/packages/functions/src/common.ts b/packages/functions/src/common.ts new file mode 100644 index 0000000000..b4af9e4d3a --- /dev/null +++ b/packages/functions/src/common.ts @@ -0,0 +1,17 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { CloudFunctions } from './runtime/common'; + +export const flattenObject = (obj: any): { [key: string]: any } => { + const flat: { [key: string]: any } = {}; + Object.entries(obj).forEach(([key, value]) => { + if (value instanceof CloudFunctions) { + flat[key] = value; + } else if (typeof value === 'object' && !Array.isArray(value)) { + const nestedObj = flattenObject(value); + for (const nestedKey of Object.keys(nestedObj)) { + flat[nestedKey] = nestedObj[nestedKey]; + } + } + }); + return flat; +}; diff --git a/packages/functions/src/runtime/firebase/address/AddressValidationRequestSchema.ts b/packages/functions/src/controls/address/AddressValidationRequestSchema.ts similarity index 81% rename from packages/functions/src/runtime/firebase/address/AddressValidationRequestSchema.ts rename to packages/functions/src/controls/address/AddressValidationRequestSchema.ts index 340bef3d63..e431796c6c 100644 --- a/packages/functions/src/runtime/firebase/address/AddressValidationRequestSchema.ts +++ b/packages/functions/src/controls/address/AddressValidationRequestSchema.ts @@ -1,7 +1,7 @@ import { AddressValidationRequest } from '@build-5/interfaces'; import Joi from 'joi'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; -import { networks } from '../../../utils/config.utils'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; +import { networks } from '../../utils/config.utils'; export const validateAddressSchema = { space: CommonJoi.uid(false).optional().description('Build5 id of the space'), diff --git a/packages/functions/src/controls/address.control.ts b/packages/functions/src/controls/address/address.control.ts similarity index 57% rename from packages/functions/src/controls/address.control.ts rename to packages/functions/src/controls/address/address.control.ts index 4a04edf71b..d7bbc09cb1 100644 --- a/packages/functions/src/controls/address.control.ts +++ b/packages/functions/src/controls/address/address.control.ts @@ -6,11 +6,15 @@ import { Network, WenError, } from '@build-5/interfaces'; -import { build5Db } from '../firebase/firestore/build5Db'; -import { createAddressValidationOrder } from '../services/payment/tangle-service/address/address-validation.service'; -import { invalidArgument } from '../utils/error.utils'; +import { build5Db } from '../../firebase/firestore/build5Db'; +import { createAddressValidationOrder } from '../../services/payment/tangle-service/address/address-validation.service'; +import { invalidArgument } from '../../utils/error.utils'; +import { Context } from '../common'; -export const validateAddressControl = async (owner: string, params: AddressValidationRequest) => { +export const validateAddressControl = async ({ + owner, + params, +}: Context) => { const network = (params.network as Network) || DEFAULT_NETWORK; const member = await build5Db().doc(`${COL.MEMBER}/${owner}`).get(); diff --git a/packages/functions/src/runtime/firebase/auth/CutomTokenRequestSchema.ts b/packages/functions/src/controls/auth/CutomTokenRequestSchema.ts similarity index 100% rename from packages/functions/src/runtime/firebase/auth/CutomTokenRequestSchema.ts rename to packages/functions/src/controls/auth/CutomTokenRequestSchema.ts diff --git a/packages/functions/src/controls/auth.control.ts b/packages/functions/src/controls/auth/auth.control.ts similarity index 62% rename from packages/functions/src/controls/auth.control.ts rename to packages/functions/src/controls/auth/auth.control.ts index 0e74030746..976c9bfa56 100644 --- a/packages/functions/src/controls/auth.control.ts +++ b/packages/functions/src/controls/auth/auth.control.ts @@ -1,9 +1,10 @@ import { TOKEN_EXPIRY_HOURS } from '@build-5/interfaces'; import dayjs from 'dayjs'; import jwt from 'jsonwebtoken'; -import { getJwtSecretKey } from '../utils/config.utils'; +import { getJwtSecretKey } from '../../utils/config.utils'; +import { Context } from '../common'; -export const generateCustomTokenControl = async (owner: string) => { +export const generateCustomTokenControl = async ({ owner }: Context) => { const rawJwt = { uid: owner, iat: dayjs().unix(), diff --git a/packages/functions/src/runtime/firebase/award/AwardAddOwnerRequestSchema.ts b/packages/functions/src/controls/award/AwardAddOwnerRequestSchema.ts similarity index 86% rename from packages/functions/src/runtime/firebase/award/AwardAddOwnerRequestSchema.ts rename to packages/functions/src/controls/award/AwardAddOwnerRequestSchema.ts index 683f4377cd..910793a21c 100644 --- a/packages/functions/src/runtime/firebase/award/AwardAddOwnerRequestSchema.ts +++ b/packages/functions/src/controls/award/AwardAddOwnerRequestSchema.ts @@ -1,5 +1,5 @@ import { AwardAddOwnerRequest } from '@build-5/interfaces'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; export const addOwnerSchema = toJoiObject({ uid: CommonJoi.uid().description('Build5 id of the award.'), diff --git a/packages/functions/src/runtime/firebase/award/AwardApproveParticipantRequestSchema.ts b/packages/functions/src/controls/award/AwardApproveParticipantRequestSchema.ts similarity index 91% rename from packages/functions/src/runtime/firebase/award/AwardApproveParticipantRequestSchema.ts rename to packages/functions/src/controls/award/AwardApproveParticipantRequestSchema.ts index 6d0fc9c908..8849c6d38d 100644 --- a/packages/functions/src/runtime/firebase/award/AwardApproveParticipantRequestSchema.ts +++ b/packages/functions/src/controls/award/AwardApproveParticipantRequestSchema.ts @@ -1,6 +1,6 @@ import { AwardApproveParticipantRequest } from '@build-5/interfaces'; import Joi from 'joi'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; const MIN_MEMBERS = 1; const MAX_MEMBERS = 1000; diff --git a/packages/functions/src/runtime/firebase/award/AwardCancelRequestSchema.ts b/packages/functions/src/controls/award/AwardCancelRequestSchema.ts similarity index 80% rename from packages/functions/src/runtime/firebase/award/AwardCancelRequestSchema.ts rename to packages/functions/src/controls/award/AwardCancelRequestSchema.ts index 79ddf64ed5..a857ccfe6c 100644 --- a/packages/functions/src/runtime/firebase/award/AwardCancelRequestSchema.ts +++ b/packages/functions/src/controls/award/AwardCancelRequestSchema.ts @@ -1,5 +1,5 @@ import { AwardCancelRequest } from '@build-5/interfaces'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; export const awardCancelSchema = toJoiObject({ uid: CommonJoi.uid().description('Build5 id of the award.'), diff --git a/packages/functions/src/runtime/firebase/award/AwardCreateRequestSchema.ts b/packages/functions/src/controls/award/AwardCreateRequestSchema.ts similarity index 93% rename from packages/functions/src/runtime/firebase/award/AwardCreateRequestSchema.ts rename to packages/functions/src/controls/award/AwardCreateRequestSchema.ts index 4b66248f7e..69858cba9a 100644 --- a/packages/functions/src/runtime/firebase/award/AwardCreateRequestSchema.ts +++ b/packages/functions/src/controls/award/AwardCreateRequestSchema.ts @@ -1,7 +1,7 @@ import { AwardCreateBadgeRequest, AwardCreateRequest, MAX_IOTA_AMOUNT } from '@build-5/interfaces'; import Joi from 'joi'; -import { AVAILABLE_NETWORKS } from '../../../controls/common'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; +import { AVAILABLE_NETWORKS } from '../common'; const MIN_TOTAL_BADGES = 1; const MAX_TOTAL_BADGES = 10000; diff --git a/packages/functions/src/runtime/firebase/award/AwardFundRequestSchema.ts b/packages/functions/src/controls/award/AwardFundRequestSchema.ts similarity index 80% rename from packages/functions/src/runtime/firebase/award/AwardFundRequestSchema.ts rename to packages/functions/src/controls/award/AwardFundRequestSchema.ts index aad3daf305..d118f34bac 100644 --- a/packages/functions/src/runtime/firebase/award/AwardFundRequestSchema.ts +++ b/packages/functions/src/controls/award/AwardFundRequestSchema.ts @@ -1,5 +1,5 @@ import { AwardFundRequest } from '@build-5/interfaces'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; export const awardFundSchema = toJoiObject({ uid: CommonJoi.uid().description('Build5 id of the award.'), diff --git a/packages/functions/src/runtime/firebase/award/AwardParticipateRequestSchema.ts b/packages/functions/src/controls/award/AwardParticipateRequestSchema.ts similarity index 85% rename from packages/functions/src/runtime/firebase/award/AwardParticipateRequestSchema.ts rename to packages/functions/src/controls/award/AwardParticipateRequestSchema.ts index 607b22e72d..73070d1907 100644 --- a/packages/functions/src/runtime/firebase/award/AwardParticipateRequestSchema.ts +++ b/packages/functions/src/controls/award/AwardParticipateRequestSchema.ts @@ -1,6 +1,6 @@ import { AwardParticpateRequest } from '@build-5/interfaces'; import Joi from 'joi'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; export const awardParticipateSchema = toJoiObject({ uid: CommonJoi.uid().description('Build5 id of the award'), diff --git a/packages/functions/src/runtime/firebase/award/AwardRejectRequestSchema.ts b/packages/functions/src/controls/award/AwardRejectRequestSchema.ts similarity index 80% rename from packages/functions/src/runtime/firebase/award/AwardRejectRequestSchema.ts rename to packages/functions/src/controls/award/AwardRejectRequestSchema.ts index 5f17fd809c..bbaeedda62 100644 --- a/packages/functions/src/runtime/firebase/award/AwardRejectRequestSchema.ts +++ b/packages/functions/src/controls/award/AwardRejectRequestSchema.ts @@ -1,5 +1,5 @@ import { AwardRejectRequest } from '@build-5/interfaces'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; export const awardRejectSchema = toJoiObject({ uid: CommonJoi.uid().description('Build5 id of the award.'), diff --git a/packages/functions/src/controls/award/award.approve.participant.ts b/packages/functions/src/controls/award/award.approve.participant.ts index 7a41360917..ed99e20aba 100644 --- a/packages/functions/src/controls/award/award.approve.participant.ts +++ b/packages/functions/src/controls/award/award.approve.participant.ts @@ -7,11 +7,12 @@ import { import { get } from 'lodash'; import { build5Db } from '../../firebase/firestore/build5Db'; import { approveAwardParticipant } from '../../services/payment/tangle-service/award/award.approve.participant.service'; +import { Context } from '../common'; -export const approveAwardParticipantControl = async ( - owner: string, - params: AwardApproveParticipantRequest, -): Promise => { +export const approveAwardParticipantControl = async ({ + owner, + params, +}: Context): Promise => { const members = params.members.map((m) => m.toLowerCase()); const awardId = params.award; const badges: { [key: string]: Transaction } = {}; diff --git a/packages/functions/src/controls/award/award.cancel.ts b/packages/functions/src/controls/award/award.cancel.ts index b949fffa0c..bef412dcee 100644 --- a/packages/functions/src/controls/award/award.cancel.ts +++ b/packages/functions/src/controls/award/award.cancel.ts @@ -3,8 +3,12 @@ import dayjs from 'dayjs'; import { build5Db } from '../../firebase/firestore/build5Db'; import { invalidArgument } from '../../utils/error.utils'; import { assertIsGuardian } from '../../utils/token.utils'; +import { Context } from '../common'; -export const cancelAwardControl = (owner: string, params: AwardCancelRequest): Promise => +export const cancelAwardControl = ({ + owner, + params, +}: Context): Promise => build5Db().runTransaction(async (transaction) => { const awardDocRef = build5Db().doc(`${COL.AWARD}/${params.uid}`); const award = await transaction.get(awardDocRef); diff --git a/packages/functions/src/controls/award/award.create.ts b/packages/functions/src/controls/award/award.create.ts index 74658895ba..e3348ae72d 100644 --- a/packages/functions/src/controls/award/award.create.ts +++ b/packages/functions/src/controls/award/award.create.ts @@ -1,8 +1,9 @@ import { Award, AwardCreateRequest, COL, SUB_COL } from '@build-5/interfaces'; import { build5Db } from '../../firebase/firestore/build5Db'; import { createAward } from '../../services/payment/tangle-service/award/award.create.service'; +import { Context } from '../common'; -export const createAwardControl = async (owner: string, params: AwardCreateRequest) => { +export const createAwardControl = async ({ owner, params }: Context) => { const { owner: awardOwner, award } = await createAward(owner, params); const batch = build5Db().batch(); diff --git a/packages/functions/src/controls/award/award.fund.ts b/packages/functions/src/controls/award/award.fund.ts index 324d536d5e..5138d4a784 100644 --- a/packages/functions/src/controls/award/award.fund.ts +++ b/packages/functions/src/controls/award/award.fund.ts @@ -4,11 +4,12 @@ import { createAwardFundOrder, getAwardForFunding, } from '../../services/payment/tangle-service/award/award.fund.service'; +import { Context } from '../common'; -export const fundAwardControl = async ( - owner: string, - params: AwardFundRequest, -): Promise => { +export const fundAwardControl = async ({ + owner, + params, +}: Context): Promise => { const award = await getAwardForFunding(owner, params.uid); const order = await createAwardFundOrder(owner, award); diff --git a/packages/functions/src/controls/award/award.owner.ts b/packages/functions/src/controls/award/award.owner.ts index a372f08eaf..c35ed72f43 100644 --- a/packages/functions/src/controls/award/award.owner.ts +++ b/packages/functions/src/controls/award/award.owner.ts @@ -10,11 +10,12 @@ import dayjs from 'dayjs'; import { build5Db } from '../../firebase/firestore/build5Db'; import { dateToTimestamp } from '../../utils/dateTime.utils'; import { invalidArgument } from '../../utils/error.utils'; +import { Context } from '../common'; -export const addOwnerControl = async ( - owner: string, - params: AwardAddOwnerRequest, -): Promise => { +export const addOwnerControl = async ({ + owner, + params, +}: Context): Promise => { const awardDocRef = build5Db().doc(`${COL.AWARD}/${params.uid}`); const award = await awardDocRef.get(); if (!award) { diff --git a/packages/functions/src/controls/award/award.participate.ts b/packages/functions/src/controls/award/award.participate.ts index 3aec90583b..4445f5d916 100644 --- a/packages/functions/src/controls/award/award.participate.ts +++ b/packages/functions/src/controls/award/award.participate.ts @@ -10,11 +10,12 @@ import dayjs from 'dayjs'; import { build5Db } from '../../firebase/firestore/build5Db'; import { dateToTimestamp } from '../../utils/dateTime.utils'; import { invalidArgument } from '../../utils/error.utils'; +import { Context } from '../common'; -export const awardParticipateControl = async ( - owner: string, - params: AwardParticpateRequest, -): Promise => { +export const awardParticipateControl = async ({ + owner, + params, +}: Context): Promise => { const awardDocRef = build5Db().doc(`${COL.AWARD}/${params.uid}`); const award = await awardDocRef.get(); if (!award) { diff --git a/packages/functions/src/controls/award/award.reject.ts b/packages/functions/src/controls/award/award.reject.ts index 8e30ab5561..c5efabf870 100644 --- a/packages/functions/src/controls/award/award.reject.ts +++ b/packages/functions/src/controls/award/award.reject.ts @@ -2,11 +2,12 @@ import { Award, AwardRejectRequest, COL, WenError } from '@build-5/interfaces'; import { build5Db } from '../../firebase/firestore/build5Db'; import { invalidArgument } from '../../utils/error.utils'; import { assertIsGuardian } from '../../utils/token.utils'; +import { Context } from '../common'; -export const rejectAwardControl = async ( - owner: string, - params: AwardRejectRequest, -): Promise => { +export const rejectAwardControl = async ({ + owner, + params, +}: Context): Promise => { const awardDocRef = build5Db().doc(`${COL.AWARD}/${params.uid}`); const award = await awardDocRef.get(); if (!award) { diff --git a/packages/functions/src/runtime/firebase/collection/CollectionApproveRequestSchema.ts b/packages/functions/src/controls/collection/CollectionApproveRequestSchema.ts similarity index 82% rename from packages/functions/src/runtime/firebase/collection/CollectionApproveRequestSchema.ts rename to packages/functions/src/controls/collection/CollectionApproveRequestSchema.ts index 93bc80ac8b..fb2cebd8cd 100644 --- a/packages/functions/src/runtime/firebase/collection/CollectionApproveRequestSchema.ts +++ b/packages/functions/src/controls/collection/CollectionApproveRequestSchema.ts @@ -1,5 +1,5 @@ import { ApproveCollectionRequest } from '@build-5/interfaces'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; export const approveCollectionSchema = toJoiObject({ uid: CommonJoi.uid().description('Build5 id of the collection.'), diff --git a/packages/functions/src/runtime/firebase/collection/CollectionCreateRequestSchema.ts b/packages/functions/src/controls/collection/CollectionCreateRequestSchema.ts similarity index 96% rename from packages/functions/src/runtime/firebase/collection/CollectionCreateRequestSchema.ts rename to packages/functions/src/controls/collection/CollectionCreateRequestSchema.ts index 0c7c656344..8982f5ce3f 100644 --- a/packages/functions/src/runtime/firebase/collection/CollectionCreateRequestSchema.ts +++ b/packages/functions/src/controls/collection/CollectionCreateRequestSchema.ts @@ -8,7 +8,7 @@ import { } from '@build-5/interfaces'; import dayjs from 'dayjs'; import Joi from 'joi'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; import { availableFromMinMinutes } from './CollectionUpdateMintedRequestSchema'; import { updateCollectionSchema } from './CollectionUpdateRequestSchema'; diff --git a/packages/functions/src/runtime/firebase/collection/CollectionMintRequestSchema.ts b/packages/functions/src/controls/collection/CollectionMintRequestSchema.ts similarity index 86% rename from packages/functions/src/runtime/firebase/collection/CollectionMintRequestSchema.ts rename to packages/functions/src/controls/collection/CollectionMintRequestSchema.ts index c01c5b36ef..3ff0119337 100644 --- a/packages/functions/src/runtime/firebase/collection/CollectionMintRequestSchema.ts +++ b/packages/functions/src/controls/collection/CollectionMintRequestSchema.ts @@ -5,9 +5,9 @@ import { UnsoldMintingOptions, } from '@build-5/interfaces'; import Joi from 'joi'; -import { AVAILABLE_NETWORKS } from '../../../controls/common'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; -import { networks } from '../../../utils/config.utils'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; +import { networks } from '../../utils/config.utils'; +import { AVAILABLE_NETWORKS } from '../common'; const availaibleNetworks = AVAILABLE_NETWORKS.filter((n) => networks.includes(n)); export const mintCollectionSchema = toJoiObject({ diff --git a/packages/functions/src/runtime/firebase/collection/CollectionRejectRequestSchema.ts b/packages/functions/src/controls/collection/CollectionRejectRequestSchema.ts similarity index 82% rename from packages/functions/src/runtime/firebase/collection/CollectionRejectRequestSchema.ts rename to packages/functions/src/controls/collection/CollectionRejectRequestSchema.ts index 3445e13280..3674de4088 100644 --- a/packages/functions/src/runtime/firebase/collection/CollectionRejectRequestSchema.ts +++ b/packages/functions/src/controls/collection/CollectionRejectRequestSchema.ts @@ -1,5 +1,5 @@ import { RejectCollectionRequest } from '@build-5/interfaces'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; export const rejectCollectionSchema = toJoiObject({ uid: CommonJoi.uid().description('Build5 id of the collection.'), diff --git a/packages/functions/src/runtime/firebase/collection/CollectionUpdateMintedRequestSchema.ts b/packages/functions/src/controls/collection/CollectionUpdateMintedRequestSchema.ts similarity index 97% rename from packages/functions/src/runtime/firebase/collection/CollectionUpdateMintedRequestSchema.ts rename to packages/functions/src/controls/collection/CollectionUpdateMintedRequestSchema.ts index 3a3eb73d45..31b3720c4b 100644 --- a/packages/functions/src/runtime/firebase/collection/CollectionUpdateMintedRequestSchema.ts +++ b/packages/functions/src/controls/collection/CollectionUpdateMintedRequestSchema.ts @@ -7,7 +7,7 @@ import { import dayjs from 'dayjs'; import Joi from 'joi'; import { uniq } from 'lodash'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; const MIN_DISCOUNTS = 0; const MAX_DISCOUNTS = 5; diff --git a/packages/functions/src/runtime/firebase/collection/CollectionUpdateRequestSchema.ts b/packages/functions/src/controls/collection/CollectionUpdateRequestSchema.ts similarity index 95% rename from packages/functions/src/runtime/firebase/collection/CollectionUpdateRequestSchema.ts rename to packages/functions/src/controls/collection/CollectionUpdateRequestSchema.ts index a9fcc3dd8a..82074c319f 100644 --- a/packages/functions/src/runtime/firebase/collection/CollectionUpdateRequestSchema.ts +++ b/packages/functions/src/controls/collection/CollectionUpdateRequestSchema.ts @@ -1,6 +1,6 @@ import { DISCORD_REGEXP, TWITTER_REGEXP, UpdateCollectionRequest } from '@build-5/interfaces'; import Joi from 'joi'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; import { updateMintedCollectionSchema } from './CollectionUpdateMintedRequestSchema'; const MIN_ROYALTY_FEE = 0; diff --git a/packages/functions/src/controls/collection/collection-mint.control.ts b/packages/functions/src/controls/collection/collection-mint.control.ts index 9aaf49c9eb..789471c02f 100644 --- a/packages/functions/src/controls/collection/collection-mint.control.ts +++ b/packages/functions/src/controls/collection/collection-mint.control.ts @@ -35,8 +35,12 @@ import { invalidArgument } from '../../utils/error.utils'; import { createAliasOutput } from '../../utils/token-minting-utils/alias.utils'; import { assertIsGuardian } from '../../utils/token.utils'; import { getRandomEthAddress } from '../../utils/wallet.utils'; +import { Context } from '../common'; -export const mintCollectionOrderControl = async (owner: string, params: CollectionMintRequest) => { +export const mintCollectionOrderControl = async ({ + owner, + params, +}: Context) => { const network = params.network as Network; const member = await build5Db().doc(`${COL.MEMBER}/${owner}`).get(); diff --git a/packages/functions/src/controls/collection/collection.approve.control.ts b/packages/functions/src/controls/collection/collection.approve.control.ts index 551edbb1e1..98bc7bee91 100644 --- a/packages/functions/src/controls/collection/collection.approve.control.ts +++ b/packages/functions/src/controls/collection/collection.approve.control.ts @@ -2,11 +2,12 @@ import { ApproveCollectionRequest, COL, Collection, WenError } from '@build-5/in import { build5Db } from '../../firebase/firestore/build5Db'; import { invalidArgument } from '../../utils/error.utils'; import { assertIsGuardian } from '../../utils/token.utils'; +import { Context } from '../common'; -export const approveCollectionControl = async ( - owner: string, - params: ApproveCollectionRequest, -): Promise => { +export const approveCollectionControl = async ({ + owner, + params, +}: Context): Promise => { const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${params.uid}`); const collection = await collectionDocRef.get(); if (!collection) { diff --git a/packages/functions/src/controls/collection/collection.create.control.ts b/packages/functions/src/controls/collection/collection.create.control.ts index 48516d2aa5..d2f6f25dd9 100644 --- a/packages/functions/src/controls/collection/collection.create.control.ts +++ b/packages/functions/src/controls/collection/collection.create.control.ts @@ -18,9 +18,13 @@ import { assertSpaceHasValidAddress } from '../../utils/address.utils'; import { dateToTimestamp, serverTime } from '../../utils/dateTime.utils'; import { invalidArgument } from '../../utils/error.utils'; import { getRandomEthAddress } from '../../utils/wallet.utils'; +import { Context } from '../common'; import { populateTokenUidOnDiscounts } from './common'; -export const createCollectionControl = async (owner: string, params: CreateCollectionRequest) => { +export const createCollectionControl = async ({ + owner, + params, +}: Context) => { const hasStakedSoons = await hasStakedSoonTokens(owner); if (!hasStakedSoons) { throw invalidArgument(WenError.no_staked_soon); diff --git a/packages/functions/src/controls/collection/collection.reject.control.ts b/packages/functions/src/controls/collection/collection.reject.control.ts index 63f11b59c4..79f834510e 100644 --- a/packages/functions/src/controls/collection/collection.reject.control.ts +++ b/packages/functions/src/controls/collection/collection.reject.control.ts @@ -3,11 +3,12 @@ import dayjs from 'dayjs'; import { build5Db } from '../../firebase/firestore/build5Db'; import { invalidArgument } from '../../utils/error.utils'; import { assertIsGuardian } from '../../utils/token.utils'; +import { Context } from '../common'; -export const rejectCollectionControl = async ( - owner: string, - params: RejectCollectionRequest, -): Promise => { +export const rejectCollectionControl = async ({ + owner, + params, +}: Context): Promise => { const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${params.uid}`); const collection = await collectionDocRef.get(); if (!collection) { diff --git a/packages/functions/src/controls/collection/collection.update.control.ts b/packages/functions/src/controls/collection/collection.update.control.ts index 804b26afa1..bcd3c95b0a 100644 --- a/packages/functions/src/controls/collection/collection.update.control.ts +++ b/packages/functions/src/controls/collection/collection.update.control.ts @@ -12,16 +12,19 @@ import { import dayjs from 'dayjs'; import { isEmpty, last, set } from 'lodash'; import { build5Db, getSnapshot } from '../../firebase/firestore/build5Db'; -import { updateMintedCollectionSchemaObject } from '../../runtime/firebase/collection/CollectionUpdateMintedRequestSchema'; -import { updateCollectionSchemaObject } from '../../runtime/firebase/collection/CollectionUpdateRequestSchema'; -import { UidSchemaObject } from '../../runtime/firebase/common'; 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 { Context, UidSchemaObject } from '../common'; +import { updateMintedCollectionSchemaObject } from './CollectionUpdateMintedRequestSchema'; +import { updateCollectionSchemaObject } from './CollectionUpdateRequestSchema'; import { populateTokenUidOnDiscounts } from './common'; -export const updateCollectionControl = async (owner: string, rawParams: UidSchemaObject) => { +export const updateCollectionControl = async ({ + owner, + params: rawParams, +}: Context) => { const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${rawParams.uid}`); const collection = await collectionDocRef.get(); if (!collection) { diff --git a/packages/functions/src/controls/common.ts b/packages/functions/src/controls/common.ts index fdc26d7953..30d27afe90 100644 --- a/packages/functions/src/controls/common.ts +++ b/packages/functions/src/controls/common.ts @@ -1,9 +1,24 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import { + EthAddress, PROD_AVAILABLE_MINTABLE_NETWORKS, TEST_AVAILABLE_MINTABLE_NETWORKS, } from '@build-5/interfaces'; +import { CommonJoi } from '../services/joi/common'; import { isProdEnv } from '../utils/config.utils'; export const AVAILABLE_NETWORKS = isProdEnv() ? PROD_AVAILABLE_MINTABLE_NETWORKS : TEST_AVAILABLE_MINTABLE_NETWORKS; + +export interface Context { + ip: string; + owner: string; + params: T; + headers: any; +} + +export interface UidSchemaObject { + uid: EthAddress; +} +export const uidSchema = { uid: CommonJoi.uid() }; diff --git a/packages/functions/src/runtime/firebase/credit/CreditUnrefundableRequestSchema.ts b/packages/functions/src/controls/credit/CreditUnrefundableRequestSchema.ts similarity index 84% rename from packages/functions/src/runtime/firebase/credit/CreditUnrefundableRequestSchema.ts rename to packages/functions/src/controls/credit/CreditUnrefundableRequestSchema.ts index 995c320edf..c1a1e88624 100644 --- a/packages/functions/src/runtime/firebase/credit/CreditUnrefundableRequestSchema.ts +++ b/packages/functions/src/controls/credit/CreditUnrefundableRequestSchema.ts @@ -1,5 +1,5 @@ import { CreditUnrefundableRequest } from '@build-5/interfaces'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; export const creditUnrefundableSchema = toJoiObject({ transaction: CommonJoi.uid().description( diff --git a/packages/functions/src/controls/credit/credit.controller.ts b/packages/functions/src/controls/credit/credit.controller.ts index 00cf767e8d..8c0e4a47af 100644 --- a/packages/functions/src/controls/credit/credit.controller.ts +++ b/packages/functions/src/controls/credit/credit.controller.ts @@ -16,11 +16,12 @@ import { WalletService } from '../../services/wallet/wallet.service'; import { dateToTimestamp } from '../../utils/dateTime.utils'; import { invalidArgument } from '../../utils/error.utils'; import { getRandomEthAddress } from '../../utils/wallet.utils'; +import { Context } from '../common'; -export const creditUnrefundableControl = ( - owner: string, - params: CreditUnrefundableRequest, -): Promise => +export const creditUnrefundableControl = ({ + owner, + params, +}: Context): Promise => build5Db().runTransaction(async (transaction) => { const transactionDocRef = build5Db().doc(`${COL.TRANSACTION}/${params.transaction}`); const creditTransaction = await transaction.get(transactionDocRef); diff --git a/packages/functions/src/runtime/firebase/storage/FileUploadRequestSchema.ts b/packages/functions/src/controls/file/FileUploadRequestSchema.ts similarity index 88% rename from packages/functions/src/runtime/firebase/storage/FileUploadRequestSchema.ts rename to packages/functions/src/controls/file/FileUploadRequestSchema.ts index 1aee446001..d0b102c18a 100644 --- a/packages/functions/src/runtime/firebase/storage/FileUploadRequestSchema.ts +++ b/packages/functions/src/controls/file/FileUploadRequestSchema.ts @@ -1,5 +1,5 @@ import Joi from 'joi'; -import { CommonJoi } from '../../../services/joi/common'; +import { CommonJoi } from '../../services/joi/common'; export const fileUploadSchema = Joi.object({ member: CommonJoi.uid().description('Build5 id of the member.'), diff --git a/packages/functions/src/controls/file/file.upload.control.ts b/packages/functions/src/controls/file/file.upload.control.ts new file mode 100644 index 0000000000..09c4561b96 --- /dev/null +++ b/packages/functions/src/controls/file/file.upload.control.ts @@ -0,0 +1,72 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { Bucket, FileUploadRequest, WenError, generateRandomFileName } from '@build-5/interfaces'; +import busboy from 'busboy'; +import fs from 'fs'; +import mime from 'mime-types'; +import os from 'os'; +import path from 'path'; +import { build5Storage } from '../../firebase/storage/build5Storage'; +import { getBucket } from '../../utils/config.utils'; +import { invalidArgument } from '../../utils/error.utils'; +import { assertValidationAsync } from '../../utils/schema.utils'; +import { getRandomEthAddress } from '../../utils/wallet.utils'; +import { Context } from '../common'; +import { fileUploadSchema } from './FileUploadRequestSchema'; + +const MAX_FILE_SIZE_BYTES = 104857600; // 100 MB + +export const uploadFileControl = async ({ headers }: Context) => { + const workdir = `${os.tmpdir()}/${getRandomEthAddress()}`; + const params = await getParams(headers, workdir); + + const { member, uid, ext, mimeType } = params; + await assertValidationAsync(fileUploadSchema, { member, uid, mimeType }); + + const destination = `${member}/${uid}/${generateRandomFileName()}.${ext}`; + const bucketName = getBucket(); + const bucket = build5Storage().bucket(bucketName); + const dowloadUrl = await bucket.upload(params.filePath as string, destination, {}); + + fs.rmSync(workdir, { recursive: true, force: true }); + (params.file as any).resume(); + + const idDevBucket = bucketName === Bucket.DEV; + return { url: idDevBucket ? dowloadUrl : `https://${bucket.getName()}/${destination}` }; +}; + +const getParams = (headers: any, workdir: string) => + new Promise>((res, rej) => { + const bb = busboy({ headers, limits: { fileSize: MAX_FILE_SIZE_BYTES } }); + const params: Record = {}; + + bb.on('file', (_, file, info) => { + if (params.filePath) { + file.resume(); + return; + } + + fs.mkdirSync(workdir); + const { filename, mimeType } = info; + const filepath = path.join(workdir, filename); + const writeStream = fs.createWriteStream(filepath); + file.pipe(writeStream); + + params.filePath = filepath; + params.mimeType = mimeType; + params.ext = mime.extension(mimeType); + params.file = file; + }); + + bb.on('field', (name, val) => { + params[name] = val; + }); + + bb.on('finish', async () => { + if (!params.filePath) { + rej(invalidArgument(WenError.invalid_params)); + return; + } + bb.end(); + res(params); + }); + }); diff --git a/packages/functions/src/runtime/firebase/member/CreateMemberRequestSchema.ts b/packages/functions/src/controls/member/CreateMemberRequestSchema.ts similarity index 81% rename from packages/functions/src/runtime/firebase/member/CreateMemberRequestSchema.ts rename to packages/functions/src/controls/member/CreateMemberRequestSchema.ts index ed450b27da..1a07a7e608 100644 --- a/packages/functions/src/runtime/firebase/member/CreateMemberRequestSchema.ts +++ b/packages/functions/src/controls/member/CreateMemberRequestSchema.ts @@ -1,5 +1,5 @@ import { CreateMemberRequest } from '@build-5/interfaces'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; export const createMemberSchema = toJoiObject({ address: CommonJoi.uid().description('Wallet address of the member'), diff --git a/packages/functions/src/runtime/firebase/member/UpdateMemberRequestSchema.ts b/packages/functions/src/controls/member/UpdateMemberRequestSchema.ts similarity index 93% rename from packages/functions/src/runtime/firebase/member/UpdateMemberRequestSchema.ts rename to packages/functions/src/controls/member/UpdateMemberRequestSchema.ts index 7643d031bf..8df46e2a5b 100644 --- a/packages/functions/src/runtime/firebase/member/UpdateMemberRequestSchema.ts +++ b/packages/functions/src/controls/member/UpdateMemberRequestSchema.ts @@ -5,7 +5,7 @@ import { TWITTER_REGEXP, } from '@build-5/interfaces'; import Joi from 'joi'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; export const updateMemberSchema = toJoiObject({ name: Joi.string().allow(null, '').optional().description('Name of the member'), diff --git a/packages/functions/src/controls/member/member.create.ts b/packages/functions/src/controls/member/member.create.ts index 062528c524..42b2b96b1f 100644 --- a/packages/functions/src/controls/member/member.create.ts +++ b/packages/functions/src/controls/member/member.create.ts @@ -1,8 +1,9 @@ import { COL, Member } from '@build-5/interfaces'; import { build5Db } from '../../firebase/firestore/build5Db'; import { getRandomNonce } from '../../utils/wallet.utils'; +import { Context } from '../common'; -export const createMemberControl = async (owner: string) => { +export const createMemberControl = async ({ owner }: Context) => { const memberDocRef = build5Db().collection(COL.MEMBER).doc(owner); const member = await memberDocRef.get(); diff --git a/packages/functions/src/controls/member/member.update.ts b/packages/functions/src/controls/member/member.update.ts index 9d3045b0e6..1ffb1566ee 100644 --- a/packages/functions/src/controls/member/member.update.ts +++ b/packages/functions/src/controls/member/member.update.ts @@ -10,11 +10,9 @@ import { import { build5Db } from '../../firebase/firestore/build5Db'; import { invalidArgument } from '../../utils/error.utils'; import { cleanupParams } from '../../utils/schema.utils'; +import { Context } from '../common'; -export const updateMemberControl = async ( - owner: string, - params: MemberUpdateRequest, -): Promise => { +export const updateMemberControl = async ({ owner, params }: Context) => { const memberDocRef = build5Db().doc(`${COL.MEMBER}/${owner}`); const member = await memberDocRef.get(); if (!member) { diff --git a/packages/functions/src/runtime/firebase/nft/NftBidRequestSchema.ts b/packages/functions/src/controls/nft/NftBidRequestSchema.ts similarity index 80% rename from packages/functions/src/runtime/firebase/nft/NftBidRequestSchema.ts rename to packages/functions/src/controls/nft/NftBidRequestSchema.ts index 34f06318df..4ba18ea989 100644 --- a/packages/functions/src/runtime/firebase/nft/NftBidRequestSchema.ts +++ b/packages/functions/src/controls/nft/NftBidRequestSchema.ts @@ -1,5 +1,5 @@ import { NftBidRequest } from '@build-5/interfaces'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; export const nftBidSchema = toJoiObject({ nft: CommonJoi.uid().description('Build5 id of the nft.'), diff --git a/packages/functions/src/runtime/firebase/nft/NftCreateRequestSchema.ts b/packages/functions/src/controls/nft/NftCreateRequestSchema.ts similarity index 95% rename from packages/functions/src/runtime/firebase/nft/NftCreateRequestSchema.ts rename to packages/functions/src/controls/nft/NftCreateRequestSchema.ts index dfd4d0bfc1..dda2031b9b 100644 --- a/packages/functions/src/runtime/firebase/nft/NftCreateRequestSchema.ts +++ b/packages/functions/src/controls/nft/NftCreateRequestSchema.ts @@ -1,6 +1,6 @@ import { MAX_IOTA_AMOUNT, MIN_IOTA_AMOUNT, NftCreateRequest } from '@build-5/interfaces'; import Joi from 'joi'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; export const createSchema = { name: Joi.string().allow(null, '').required().description('Name of the nft'), diff --git a/packages/functions/src/runtime/firebase/nft/NftDepositRequestSchema.ts b/packages/functions/src/controls/nft/NftDepositRequestSchema.ts similarity index 72% rename from packages/functions/src/runtime/firebase/nft/NftDepositRequestSchema.ts rename to packages/functions/src/controls/nft/NftDepositRequestSchema.ts index 8f251ff442..54cf007418 100644 --- a/packages/functions/src/runtime/firebase/nft/NftDepositRequestSchema.ts +++ b/packages/functions/src/controls/nft/NftDepositRequestSchema.ts @@ -1,8 +1,8 @@ import { NftDepositRequest } from '@build-5/interfaces'; import Joi from 'joi'; -import { AVAILABLE_NETWORKS } from '../../../controls/common'; -import { toJoiObject } from '../../../services/joi/common'; -import { networks } from '../../../utils/config.utils'; +import { toJoiObject } from '../../services/joi/common'; +import { networks } from '../../utils/config.utils'; +import { AVAILABLE_NETWORKS } from '../common'; const availaibleNetworks = AVAILABLE_NETWORKS.filter((n) => networks.includes(n)); export const depositNftSchema = toJoiObject({ diff --git a/packages/functions/src/runtime/firebase/nft/NftPurchaseRequestSchema.ts b/packages/functions/src/controls/nft/NftPurchaseRequestSchema.ts similarity index 86% rename from packages/functions/src/runtime/firebase/nft/NftPurchaseRequestSchema.ts rename to packages/functions/src/controls/nft/NftPurchaseRequestSchema.ts index 90abb32591..d55e7bf5cc 100644 --- a/packages/functions/src/runtime/firebase/nft/NftPurchaseRequestSchema.ts +++ b/packages/functions/src/controls/nft/NftPurchaseRequestSchema.ts @@ -1,5 +1,5 @@ import { NftPurchaseRequest } from '@build-5/interfaces'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; export const nftPurchaseSchema = toJoiObject({ collection: CommonJoi.uid().description( diff --git a/packages/functions/src/runtime/firebase/nft/NftSetForSaleRequestSchema.ts b/packages/functions/src/controls/nft/NftSetForSaleRequestSchema.ts similarity index 97% rename from packages/functions/src/runtime/firebase/nft/NftSetForSaleRequestSchema.ts rename to packages/functions/src/controls/nft/NftSetForSaleRequestSchema.ts index cfdec27845..22d5ac1f53 100644 --- a/packages/functions/src/runtime/firebase/nft/NftSetForSaleRequestSchema.ts +++ b/packages/functions/src/controls/nft/NftSetForSaleRequestSchema.ts @@ -9,7 +9,7 @@ import { } from '@build-5/interfaces'; import dayjs from 'dayjs'; import Joi from 'joi'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; const minAvailableFrom = 10; diff --git a/packages/functions/src/runtime/firebase/nft/NftStakeRequestSchema.ts b/packages/functions/src/controls/nft/NftStakeRequestSchema.ts similarity index 83% rename from packages/functions/src/runtime/firebase/nft/NftStakeRequestSchema.ts rename to packages/functions/src/controls/nft/NftStakeRequestSchema.ts index a14248a603..f8115a0e89 100644 --- a/packages/functions/src/runtime/firebase/nft/NftStakeRequestSchema.ts +++ b/packages/functions/src/controls/nft/NftStakeRequestSchema.ts @@ -5,9 +5,9 @@ import { StakeType, } from '@build-5/interfaces'; import Joi from 'joi'; -import { AVAILABLE_NETWORKS } from '../../../controls/common'; -import { toJoiObject } from '../../../services/joi/common'; -import { networks } from '../../../utils/config.utils'; +import { toJoiObject } from '../../services/joi/common'; +import { networks } from '../../utils/config.utils'; +import { AVAILABLE_NETWORKS } from '../common'; const availaibleNetworks = AVAILABLE_NETWORKS.filter((n) => networks.includes(n)); diff --git a/packages/functions/src/runtime/firebase/nft/NftUpdateUnsoldRequestSchema.ts b/packages/functions/src/controls/nft/NftUpdateUnsoldRequestSchema.ts similarity index 88% rename from packages/functions/src/runtime/firebase/nft/NftUpdateUnsoldRequestSchema.ts rename to packages/functions/src/controls/nft/NftUpdateUnsoldRequestSchema.ts index d079a4f0fa..c0c423f84f 100644 --- a/packages/functions/src/runtime/firebase/nft/NftUpdateUnsoldRequestSchema.ts +++ b/packages/functions/src/controls/nft/NftUpdateUnsoldRequestSchema.ts @@ -1,6 +1,6 @@ import { MAX_IOTA_AMOUNT, MIN_IOTA_AMOUNT, NftUpdateUnsoldRequest } from '@build-5/interfaces'; import Joi from 'joi'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; export const updateUnsoldNftSchema = toJoiObject({ uid: CommonJoi.uid().description('Build5 id of the nft to update'), diff --git a/packages/functions/src/runtime/firebase/nft/NftWithdrawRequestSchema.ts b/packages/functions/src/controls/nft/NftWithdrawRequestSchema.ts similarity index 81% rename from packages/functions/src/runtime/firebase/nft/NftWithdrawRequestSchema.ts rename to packages/functions/src/controls/nft/NftWithdrawRequestSchema.ts index 5860bbe117..cb57ab3502 100644 --- a/packages/functions/src/runtime/firebase/nft/NftWithdrawRequestSchema.ts +++ b/packages/functions/src/controls/nft/NftWithdrawRequestSchema.ts @@ -1,5 +1,5 @@ import { NftWithdrawRequest } from '@build-5/interfaces'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; export const nftWithdrawSchema = toJoiObject({ nft: CommonJoi.uid().description('Build5 id of the nft to withdraw.'), diff --git a/packages/functions/src/controls/nft/nft.bid.control.ts b/packages/functions/src/controls/nft/nft.bid.control.ts index b1c78775a1..4c4c9226ce 100644 --- a/packages/functions/src/controls/nft/nft.bid.control.ts +++ b/packages/functions/src/controls/nft/nft.bid.control.ts @@ -2,23 +2,20 @@ import { COL, NftBidRequest, Transaction, WenError } from '@build-5/interfaces'; import { build5Db } from '../../firebase/firestore/build5Db'; import { createNftBidOrder } from '../../services/payment/tangle-service/nft/nft-bid.service'; import { invalidArgument } from '../../utils/error.utils'; +import { Context } from '../common'; -export const nftBidControl = async ( - owner: string, - params: NftBidRequest, - customParams?: Record, -): Promise => { +export const nftBidControl = async ({ + ip, + owner, + params, +}: Context): Promise => { const memberDocRef = build5Db().doc(`${COL.MEMBER}/${owner}`); const member = await memberDocRef.get(); if (!member) { throw invalidArgument(WenError.member_does_not_exists); } - const bidTransaction = await createNftBidOrder( - params.nft, - owner, - (customParams?.ip as string) || '', - ); + const bidTransaction = await createNftBidOrder(params.nft, owner, ip); const transactionDocRef = build5Db().doc(`${COL.TRANSACTION}/${bidTransaction.uid}`); await transactionDocRef.create(bidTransaction); diff --git a/packages/functions/src/controls/nft/nft.create.ts b/packages/functions/src/controls/nft/nft.create.ts index 76b7d4addb..fa3869721a 100644 --- a/packages/functions/src/controls/nft/nft.create.ts +++ b/packages/functions/src/controls/nft/nft.create.ts @@ -15,16 +15,20 @@ import { build5Db } from '../../firebase/firestore/build5Db'; import { dateToTimestamp } from '../../utils/dateTime.utils'; import { invalidArgument } from '../../utils/error.utils'; import { getRandomEthAddress } from '../../utils/wallet.utils'; +import { Context } from '../common'; -export const createNftControl = async (owner: string, params: NftCreateRequest): Promise => { +export const createNftControl = async ({ + owner, + params, +}: Context): Promise => { const collection = await getCollection(owner, params.collection as string); return await processOneCreateNft(params, collection, collection.total + 1); }; -export const createBatchNftControl = async ( - owner: string, - params: NftCreateRequest[], -): Promise => { +export const createBatchNftControl = async ({ + owner, + params, +}: Context): Promise => { const collection = await getCollection(owner, params[0].collection); const promises = params.map((param, i) => processOneCreateNft(param, collection, collection.total + i + 1), diff --git a/packages/functions/src/controls/nft/nft.deposit.ts b/packages/functions/src/controls/nft/nft.deposit.ts index 7fd2fa5ade..96df036da0 100644 --- a/packages/functions/src/controls/nft/nft.deposit.ts +++ b/packages/functions/src/controls/nft/nft.deposit.ts @@ -13,11 +13,12 @@ import { build5Db } from '../../firebase/firestore/build5Db'; import { WalletService } from '../../services/wallet/wallet.service'; import { dateToTimestamp } from '../../utils/dateTime.utils'; import { getRandomEthAddress } from '../../utils/wallet.utils'; +import { Context } from '../common'; -export const depositNftControl = async ( - owner: string, - params: NftDepositRequest, -): Promise => { +export const depositNftControl = async ({ + owner, + params, +}: Context): Promise => { const network = params.network as Network; const wallet = await WalletService.newWallet(network); const targetAddress = await wallet.getNewIotaAddressDetails(); diff --git a/packages/functions/src/controls/nft/nft.puchase.control.ts b/packages/functions/src/controls/nft/nft.puchase.control.ts index c38c20fd8f..91d554d7e2 100644 --- a/packages/functions/src/controls/nft/nft.puchase.control.ts +++ b/packages/functions/src/controls/nft/nft.puchase.control.ts @@ -1,18 +1,14 @@ import { COL, NftPurchaseRequest, Transaction } from '@build-5/interfaces'; import { build5Db } from '../../firebase/firestore/build5Db'; import { createNftPuchaseOrder } from '../../services/payment/tangle-service/nft/nft-purchase.service'; +import { Context } from '../common'; -export const orderNftControl = async ( - owner: string, - params: NftPurchaseRequest, - customParams?: Record, -): Promise => { - const order = await createNftPuchaseOrder( - params.collection, - params.nft, - owner, - (customParams?.ip || '') as string, - ); +export const orderNftControl = async ({ + ip, + owner, + params, +}: Context): Promise => { + const order = await createNftPuchaseOrder(params.collection, params.nft, owner, ip); const orderDocRef = build5Db().doc(`${COL.TRANSACTION}/${order.uid}`); await orderDocRef.create(order); 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 b1a417c73c..c1235b1ce4 100644 --- a/packages/functions/src/controls/nft/nft.set.for.sale.ts +++ b/packages/functions/src/controls/nft/nft.set.for.sale.ts @@ -2,11 +2,12 @@ import { COL, Member, Nft, NftSetForSaleRequest, WenError } from '@build-5/inter import { build5Db } from '../../firebase/firestore/build5Db'; import { getNftSetForSaleParams } from '../../services/payment/tangle-service/nft/nft-set-for-sale.service'; import { invalidArgument } from '../../utils/error.utils'; +import { Context } from '../common'; -export const setForSaleNftControl = async ( - owner: string, - params: NftSetForSaleRequest, -): Promise => { +export const setForSaleNftControl = async ({ + owner, + params, +}: Context): Promise => { const memberDocRef = build5Db().doc(`${COL.MEMBER}/${owner}`); const member = await memberDocRef.get(); if (!member) { diff --git a/packages/functions/src/controls/nft/nft.stake.ts b/packages/functions/src/controls/nft/nft.stake.ts index 7e24463922..f8b504cae7 100644 --- a/packages/functions/src/controls/nft/nft.stake.ts +++ b/packages/functions/src/controls/nft/nft.stake.ts @@ -1,11 +1,12 @@ import { COL, Network, NftStakeRequest, StakeType, Transaction } from '@build-5/interfaces'; import { build5Db } from '../../firebase/firestore/build5Db'; import { createNftStakeOrder } from '../../services/payment/nft/nft-stake-service'; +import { Context } from '../common'; -export const nftStakeControl = async ( - owner: string, - params: NftStakeRequest, -): Promise => { +export const nftStakeControl = async ({ + owner, + params, +}: Context): Promise => { const order = await createNftStakeOrder( owner, params.network as Network, diff --git a/packages/functions/src/controls/nft/nft.update.unsold.ts b/packages/functions/src/controls/nft/nft.update.unsold.ts index 4666a45909..411f847c0f 100644 --- a/packages/functions/src/controls/nft/nft.update.unsold.ts +++ b/packages/functions/src/controls/nft/nft.update.unsold.ts @@ -2,11 +2,12 @@ import { COL, Nft, NftUpdateUnsoldRequest, WenError } from '@build-5/interfaces' import { build5Db } from '../../firebase/firestore/build5Db'; import { invalidArgument } from '../../utils/error.utils'; import { assertIsGuardian } from '../../utils/token.utils'; +import { Context } from '../common'; -export const updateUnsoldNftControl = async ( - owner: string, - params: NftUpdateUnsoldRequest, -): Promise => +export const updateUnsoldNftControl = async ({ + owner, + params, +}: Context): Promise => build5Db().runTransaction(async (transaction) => { const nftDocRef = build5Db().doc(`${COL.NFT}/${params.uid}`); const nft = await transaction.get(nftDocRef); diff --git a/packages/functions/src/controls/nft/nft.withdraw.ts b/packages/functions/src/controls/nft/nft.withdraw.ts index 498b1889da..cc76c5e702 100644 --- a/packages/functions/src/controls/nft/nft.withdraw.ts +++ b/packages/functions/src/controls/nft/nft.withdraw.ts @@ -12,8 +12,9 @@ import { build5Db } from '../../firebase/firestore/build5Db'; 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: string, params: NftWithdrawRequest) => +export const withdrawNftControl = async ({ owner, params }: Context) => build5Db().runTransaction(async (transaction) => { const nftDocRef = build5Db().doc(`${COL.NFT}/${params.nft}`); const nft = await transaction.get(nftDocRef); diff --git a/packages/functions/src/runtime/firebase/proposal/ProposalApproveRequestSchema.ts b/packages/functions/src/controls/proposal/ProposalApproveRequestSchema.ts similarity index 82% rename from packages/functions/src/runtime/firebase/proposal/ProposalApproveRequestSchema.ts rename to packages/functions/src/controls/proposal/ProposalApproveRequestSchema.ts index 86cc2f046b..49997a0cc6 100644 --- a/packages/functions/src/runtime/firebase/proposal/ProposalApproveRequestSchema.ts +++ b/packages/functions/src/controls/proposal/ProposalApproveRequestSchema.ts @@ -1,5 +1,5 @@ import { ApproveProposalRequest } from '@build-5/interfaces'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; export const approveProposaSchema = toJoiObject({ uid: CommonJoi.uid().description('Build5 id of the proposal to be approved.'), diff --git a/packages/functions/src/runtime/firebase/proposal/ProposalCreateRequestSchema.ts b/packages/functions/src/controls/proposal/ProposalCreateRequestSchema.ts similarity index 94% rename from packages/functions/src/runtime/firebase/proposal/ProposalCreateRequestSchema.ts rename to packages/functions/src/controls/proposal/ProposalCreateRequestSchema.ts index fb7b01f2bd..23e1eb44a0 100644 --- a/packages/functions/src/runtime/firebase/proposal/ProposalCreateRequestSchema.ts +++ b/packages/functions/src/controls/proposal/ProposalCreateRequestSchema.ts @@ -1,7 +1,7 @@ import { ProposalCreateRequest, ProposalStartDateMin, ProposalType } from '@build-5/interfaces'; import Joi from 'joi'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; -import { isProdEnv } from '../../../utils/config.utils'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; +import { isProdEnv } from '../../utils/config.utils'; export const createProposalSchema = { name: Joi.string().required().description('Name of the proposal'), diff --git a/packages/functions/src/runtime/firebase/proposal/ProposalRejectRequestSchema.ts b/packages/functions/src/controls/proposal/ProposalRejectRequestSchema.ts similarity index 82% rename from packages/functions/src/runtime/firebase/proposal/ProposalRejectRequestSchema.ts rename to packages/functions/src/controls/proposal/ProposalRejectRequestSchema.ts index 603246d2bd..958abf648f 100644 --- a/packages/functions/src/runtime/firebase/proposal/ProposalRejectRequestSchema.ts +++ b/packages/functions/src/controls/proposal/ProposalRejectRequestSchema.ts @@ -1,5 +1,5 @@ import { RejectProposalRequest } from '@build-5/interfaces'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; export const rejectProposaSchema = toJoiObject({ uid: CommonJoi.uid().description('Build5 id of the proposal to be rejected.'), diff --git a/packages/functions/src/runtime/firebase/proposal/ProposalVoteRequestSchema.ts b/packages/functions/src/controls/proposal/ProposalVoteRequestSchema.ts similarity index 89% rename from packages/functions/src/runtime/firebase/proposal/ProposalVoteRequestSchema.ts rename to packages/functions/src/controls/proposal/ProposalVoteRequestSchema.ts index 9e93d4c331..c9ec42560a 100644 --- a/packages/functions/src/runtime/firebase/proposal/ProposalVoteRequestSchema.ts +++ b/packages/functions/src/controls/proposal/ProposalVoteRequestSchema.ts @@ -1,6 +1,6 @@ import { ProposalVoteRequest } from '@build-5/interfaces'; import Joi from 'joi'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; export const voteOnProposalSchema = { uid: CommonJoi.uid().description('Build5 id of the proposal to vote on.'), diff --git a/packages/functions/src/controls/proposal/approve.reject.proposal.ts b/packages/functions/src/controls/proposal/approve.reject.proposal.ts index 17e3c63cf3..28d930b543 100644 --- a/packages/functions/src/controls/proposal/approve.reject.proposal.ts +++ b/packages/functions/src/controls/proposal/approve.reject.proposal.ts @@ -1,10 +1,11 @@ import { ApproveProposalRequest, COL, Proposal, RejectProposalRequest } from '@build-5/interfaces'; import { build5Db } from '../../firebase/firestore/build5Db'; import { getProposalApprovalData } from '../../services/payment/tangle-service/proposal/ProposalApporvalService'; +import { Context } from '../common'; export const proposalApprovalControl = (approve: boolean) => - async (owner: string, params: ApproveProposalRequest | RejectProposalRequest) => { + async ({ owner, params }: Context) => { const data = await getProposalApprovalData(owner, params.uid, approve); const proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${params.uid}`); await proposalDocRef.update(data); diff --git a/packages/functions/src/controls/proposal/create.proposal.ts b/packages/functions/src/controls/proposal/create.proposal.ts index 34e5dff6be..53a6b2f2f5 100644 --- a/packages/functions/src/controls/proposal/create.proposal.ts +++ b/packages/functions/src/controls/proposal/create.proposal.ts @@ -1,8 +1,9 @@ import { COL, Proposal, ProposalCreateRequest, SUB_COL } from '@build-5/interfaces'; import { build5Db } from '../../firebase/firestore/build5Db'; import { createProposal } from '../../services/payment/tangle-service/proposal/ProposalCreateService'; +import { Context } from '../common'; -export const createProposalControl = async (owner: string, params: ProposalCreateRequest) => { +export const createProposalControl = async ({ owner, params }: Context) => { const { proposal, proposalOwner } = await createProposal(owner, { ...params }); const proposalDocRef = build5Db().doc(`${COL.PROPOSAL}/${proposal.uid}`); diff --git a/packages/functions/src/controls/proposal/vote.on.proposal.ts b/packages/functions/src/controls/proposal/vote.on.proposal.ts index 26df9463f6..44d398cf9d 100644 --- a/packages/functions/src/controls/proposal/vote.on.proposal.ts +++ b/packages/functions/src/controls/proposal/vote.on.proposal.ts @@ -17,11 +17,12 @@ import { voteWithStakedTokens } from '../../services/payment/tangle-service/prop import { createVoteTransactionOrder } from '../../services/payment/tangle-service/proposal/voting/token.voting'; import { invalidArgument } from '../../utils/error.utils'; import { getTokenForSpace } from '../../utils/token.utils'; +import { Context } from '../common'; -export const voteOnProposalControl = async ( - owner: string, - params: ProposalVoteRequest, -): Promise => { +export const voteOnProposalControl = async ({ + owner, + params, +}: Context): Promise => { const proposal = await getProposal(params.uid); const proposalMember = await getProposalMember(owner, proposal, params.value); diff --git a/packages/functions/src/runtime/firebase/rank/RankRequestSchema.ts b/packages/functions/src/controls/rank/RankRequestSchema.ts similarity index 83% rename from packages/functions/src/runtime/firebase/rank/RankRequestSchema.ts rename to packages/functions/src/controls/rank/RankRequestSchema.ts index 23d47aabde..37d0d8b96f 100644 --- a/packages/functions/src/runtime/firebase/rank/RankRequestSchema.ts +++ b/packages/functions/src/controls/rank/RankRequestSchema.ts @@ -1,7 +1,7 @@ import { COL, RankRequest } from '@build-5/interfaces'; import Joi from 'joi'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; -import { RANK_CONFIG } from '../../../utils/config.utils'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; +import { RANK_CONFIG } from '../../utils/config.utils'; export const rankSchema = toJoiObject({ collection: Joi.string() diff --git a/packages/functions/src/controls/rank.control.ts b/packages/functions/src/controls/rank/rank.control.ts similarity index 81% rename from packages/functions/src/controls/rank.control.ts rename to packages/functions/src/controls/rank/rank.control.ts index 9dbf86fc53..198494aab7 100644 --- a/packages/functions/src/controls/rank.control.ts +++ b/packages/functions/src/controls/rank/rank.control.ts @@ -1,12 +1,13 @@ import { COL, Collection, Rank, RankRequest, SUB_COL, Token, WenError } from '@build-5/interfaces'; import { set } from 'lodash'; -import { build5Db } from '../firebase/firestore/build5Db'; -import { hasStakedSoonTokens } from '../services/stake.service'; -import { getRankingSpace } from '../utils/config.utils'; -import { invalidArgument } from '../utils/error.utils'; -import { assertIsGuardian } from '../utils/token.utils'; +import { build5Db } from '../../firebase/firestore/build5Db'; +import { hasStakedSoonTokens } from '../../services/stake.service'; +import { getRankingSpace } from '../../utils/config.utils'; +import { invalidArgument } from '../../utils/error.utils'; +import { assertIsGuardian } from '../../utils/token.utils'; +import { Context } from '../common'; -export const rankControl = async (owner: string, params: RankRequest) => { +export const rankControl = async ({ owner, params }: Context) => { const hasStakedSoons = await hasStakedSoonTokens(owner); if (!hasStakedSoons) { throw invalidArgument(WenError.no_staked_soon); diff --git a/packages/functions/src/runtime/firebase/space/SpaceClaimRequestSchema.ts b/packages/functions/src/controls/space/SpaceClaimRequestSchema.ts similarity index 80% rename from packages/functions/src/runtime/firebase/space/SpaceClaimRequestSchema.ts rename to packages/functions/src/controls/space/SpaceClaimRequestSchema.ts index 7f90201eb5..85e94e4889 100644 --- a/packages/functions/src/runtime/firebase/space/SpaceClaimRequestSchema.ts +++ b/packages/functions/src/controls/space/SpaceClaimRequestSchema.ts @@ -1,5 +1,5 @@ import { SpaceClaimRequest } from '@build-5/interfaces'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; export const spaceClaimSchema = toJoiObject({ uid: CommonJoi.uid().description('Build5 id of the space.'), diff --git a/packages/functions/src/runtime/firebase/space/SpaceCreateRequestSchema.ts b/packages/functions/src/controls/space/SpaceCreateRequestSchema.ts similarity index 94% rename from packages/functions/src/runtime/firebase/space/SpaceCreateRequestSchema.ts rename to packages/functions/src/controls/space/SpaceCreateRequestSchema.ts index d5c9ef2c74..af02ac771d 100644 --- a/packages/functions/src/runtime/firebase/space/SpaceCreateRequestSchema.ts +++ b/packages/functions/src/controls/space/SpaceCreateRequestSchema.ts @@ -1,6 +1,6 @@ import { GITHUB_REGEXP, SpaceCreateRequest, TWITTER_REGEXP } from '@build-5/interfaces'; import Joi from 'joi'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; export const createSpaceSchema = { name: Joi.string().allow(null, '').optional().description('Name of the space.'), diff --git a/packages/functions/src/runtime/firebase/space/SpaceEditMemberRequestSchema.ts b/packages/functions/src/controls/space/SpaceEditMemberRequestSchema.ts similarity index 86% rename from packages/functions/src/runtime/firebase/space/SpaceEditMemberRequestSchema.ts rename to packages/functions/src/controls/space/SpaceEditMemberRequestSchema.ts index 173391eae9..b5ec04441b 100644 --- a/packages/functions/src/runtime/firebase/space/SpaceEditMemberRequestSchema.ts +++ b/packages/functions/src/controls/space/SpaceEditMemberRequestSchema.ts @@ -1,5 +1,5 @@ import { SpaceMemberUpsertRequest } from '@build-5/interfaces'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; export const editSpaceMemberSchema = { uid: CommonJoi.uid().description('Build5 id of the space'), diff --git a/packages/functions/src/runtime/firebase/space/SpaceJoinRequestSchema.ts b/packages/functions/src/controls/space/SpaceJoinRequestSchema.ts similarity index 80% rename from packages/functions/src/runtime/firebase/space/SpaceJoinRequestSchema.ts rename to packages/functions/src/controls/space/SpaceJoinRequestSchema.ts index 77b78df284..c3ca2dc74c 100644 --- a/packages/functions/src/runtime/firebase/space/SpaceJoinRequestSchema.ts +++ b/packages/functions/src/controls/space/SpaceJoinRequestSchema.ts @@ -1,5 +1,5 @@ import { SpaceJoinRequest } from '@build-5/interfaces'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; export const spaceJoinSchema = toJoiObject({ uid: CommonJoi.uid().description('Build5 id of the space.'), diff --git a/packages/functions/src/runtime/firebase/space/SpaceLeaveRequestSchema.ts b/packages/functions/src/controls/space/SpaceLeaveRequestSchema.ts similarity index 80% rename from packages/functions/src/runtime/firebase/space/SpaceLeaveRequestSchema.ts rename to packages/functions/src/controls/space/SpaceLeaveRequestSchema.ts index 63df21aab1..9fa6f8bc59 100644 --- a/packages/functions/src/runtime/firebase/space/SpaceLeaveRequestSchema.ts +++ b/packages/functions/src/controls/space/SpaceLeaveRequestSchema.ts @@ -1,5 +1,5 @@ import { SpaceLeaveRequest } from '@build-5/interfaces'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; export const spaceLeaveSchema = toJoiObject({ uid: CommonJoi.uid().description('Build5 id of the space.'), diff --git a/packages/functions/src/runtime/firebase/space/SpaceUpdateRequestSchema.ts b/packages/functions/src/controls/space/SpaceUpdateRequestSchema.ts similarity index 93% rename from packages/functions/src/runtime/firebase/space/SpaceUpdateRequestSchema.ts rename to packages/functions/src/controls/space/SpaceUpdateRequestSchema.ts index e93bd6461b..32a1031bc7 100644 --- a/packages/functions/src/runtime/firebase/space/SpaceUpdateRequestSchema.ts +++ b/packages/functions/src/controls/space/SpaceUpdateRequestSchema.ts @@ -1,6 +1,6 @@ import { MAX_TOTAL_TOKEN_SUPPLY, SpaceUpdateRequest } from '@build-5/interfaces'; import Joi from 'joi'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; import { createSpaceSchema } from './SpaceCreateRequestSchema'; const MIN_STAKE_VALUE = 1; diff --git a/packages/functions/src/controls/space/member.accept.control.ts b/packages/functions/src/controls/space/member.accept.control.ts index cbad88c772..a66cd7e4af 100644 --- a/packages/functions/src/controls/space/member.accept.control.ts +++ b/packages/functions/src/controls/space/member.accept.control.ts @@ -1,8 +1,12 @@ import { COL, SpaceMember, SpaceMemberUpsertRequest, SUB_COL } from '@build-5/interfaces'; import { build5Db } from '../../firebase/firestore/build5Db'; import { acceptSpaceMember } from '../../services/payment/tangle-service/space/SpaceAcceptMemberService'; +import { Context } from '../common'; -export const acceptSpaceMemberControl = async (owner: string, params: SpaceMemberUpsertRequest) => { +export const acceptSpaceMemberControl = async ({ + owner, + params, +}: Context) => { const { spaceMember, space } = await acceptSpaceMember(owner, params.uid, params.member); const spaceDocRef = build5Db().doc(`${COL.SPACE}/${params.uid}`); diff --git a/packages/functions/src/controls/space/member.block.control.ts b/packages/functions/src/controls/space/member.block.control.ts index 6f8b59521a..ccb78ae903 100644 --- a/packages/functions/src/controls/space/member.block.control.ts +++ b/packages/functions/src/controls/space/member.block.control.ts @@ -1,8 +1,9 @@ import { COL, SpaceMember, SpaceMemberUpsertRequest, SUB_COL } from '@build-5/interfaces'; import { build5Db } from '../../firebase/firestore/build5Db'; import { getBlockMemberUpdateData } from '../../services/payment/tangle-service/space/SpaceBlockMemberService'; +import { Context } from '../common'; -export const blockMemberControl = async (owner: string, params: SpaceMemberUpsertRequest) => { +export const blockMemberControl = async ({ owner, params }: Context) => { const member = params.member; const { space, blockedMember } = await getBlockMemberUpdateData(owner, params.uid, member); diff --git a/packages/functions/src/controls/space/member.decline.control.ts b/packages/functions/src/controls/space/member.decline.control.ts index 5e7fe24fa7..d07e7baad1 100644 --- a/packages/functions/src/controls/space/member.decline.control.ts +++ b/packages/functions/src/controls/space/member.decline.control.ts @@ -1,8 +1,12 @@ import { COL, SUB_COL, SpaceMemberUpsertRequest } from '@build-5/interfaces'; import { build5Db } from '../../firebase/firestore/build5Db'; import { assertIsGuardian } from '../../utils/token.utils'; +import { Context } from '../common'; -export const declineMemberControl = async (owner: string, params: SpaceMemberUpsertRequest) => { +export const declineMemberControl = async ({ + owner, + params, +}: Context) => { await assertIsGuardian(params.uid, owner); const spaceDocRef = build5Db().doc(`${COL.SPACE}/${params.uid}`); diff --git a/packages/functions/src/controls/space/member.leave.control.ts b/packages/functions/src/controls/space/member.leave.control.ts index f452bc41f8..d1e79c1fc1 100644 --- a/packages/functions/src/controls/space/member.leave.control.ts +++ b/packages/functions/src/controls/space/member.leave.control.ts @@ -1,8 +1,9 @@ import { COL, SUB_COL, SpaceLeaveRequest } from '@build-5/interfaces'; import { build5Db } from '../../firebase/firestore/build5Db'; import { getLeaveSpaceData } from '../../services/payment/tangle-service/space/SpaceLeaveService'; +import { Context } from '../common'; -export const leaveSpaceControl = async (owner: string, params: SpaceLeaveRequest) => { +export const leaveSpaceControl = async ({ owner, params }: Context) => { const { space, member } = await getLeaveSpaceData(owner, params.uid); const spaceDocRef = build5Db().doc(`${COL.SPACE}/${params.uid}`); diff --git a/packages/functions/src/controls/space/member.unblock.control.ts b/packages/functions/src/controls/space/member.unblock.control.ts index 4e6218b773..a4db6d4be0 100644 --- a/packages/functions/src/controls/space/member.unblock.control.ts +++ b/packages/functions/src/controls/space/member.unblock.control.ts @@ -1,8 +1,12 @@ import { COL, SUB_COL, SpaceMemberUpsertRequest } from '@build-5/interfaces'; import { build5Db } from '../../firebase/firestore/build5Db'; import { assertIsGuardian } from '../../utils/token.utils'; +import { Context } from '../common'; -export const unblockMemberControl = async (owner: string, params: SpaceMemberUpsertRequest) => { +export const unblockMemberControl = async ({ + owner, + params, +}: Context) => { await assertIsGuardian(params.uid, owner); const spaceDocRef = build5Db().doc(`${COL.SPACE}/${params.uid}`); diff --git a/packages/functions/src/controls/space/space.claim.control.ts b/packages/functions/src/controls/space/space.claim.control.ts index 23f40c527c..be247e75ef 100644 --- a/packages/functions/src/controls/space/space.claim.control.ts +++ b/packages/functions/src/controls/space/space.claim.control.ts @@ -17,8 +17,9 @@ import { generateRandomAmount } from '../../utils/common.utils'; import { dateToTimestamp } from '../../utils/dateTime.utils'; import { invalidArgument } from '../../utils/error.utils'; import { getRandomEthAddress } from '../../utils/wallet.utils'; +import { Context } from '../common'; -export const claimSpaceControl = async (owner: string, params: SpaceClaimRequest) => { +export const claimSpaceControl = async ({ owner, params }: Context) => { const spaceDocRef = build5Db().doc(`${COL.SPACE}/${params.uid}`); const space = await spaceDocRef.get(); if (!space) { diff --git a/packages/functions/src/controls/space/space.create.control.ts b/packages/functions/src/controls/space/space.create.control.ts index 3b1a5f0ccf..4ef53cd866 100644 --- a/packages/functions/src/controls/space/space.create.control.ts +++ b/packages/functions/src/controls/space/space.create.control.ts @@ -1,11 +1,12 @@ import { COL, SUB_COL, Space, SpaceCreateRequest } from '@build-5/interfaces'; import { build5Db } from '../../firebase/firestore/build5Db'; import { getCreateSpaceData } from '../../services/payment/tangle-service/space/SpaceCreateService'; +import { Context } from '../common'; -export const createSpaceControl = async ( - owner: string, - params: SpaceCreateRequest, -): Promise => { +export const createSpaceControl = async ({ + owner, + params, +}: Context): Promise => { const { space, guardian, member } = await getCreateSpaceData(owner, { ...params }); const batch = build5Db().batch(); 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 ec9d947757..d93e117896 100644 --- a/packages/functions/src/controls/space/space.guardian.edit.control.ts +++ b/packages/functions/src/controls/space/space.guardian.edit.control.ts @@ -7,9 +7,11 @@ import { } from '@build-5/interfaces'; import { build5Db } from '../../firebase/firestore/build5Db'; import { addRemoveGuardian } from '../../services/payment/tangle-service/space/SpaceGuardianService'; +import { Context } from '../common'; export const editGuardianControl = - (type: ProposalType) => async (owner: string, params: SpaceMemberUpsertRequest) => { + (type: ProposalType) => + async ({ owner, params }: Context) => { const { proposal, voteTransaction, members } = await addRemoveGuardian( owner, { ...params }, diff --git a/packages/functions/src/controls/space/space.join.control.ts b/packages/functions/src/controls/space/space.join.control.ts index d8e29ae7cc..bac7cda9fc 100644 --- a/packages/functions/src/controls/space/space.join.control.ts +++ b/packages/functions/src/controls/space/space.join.control.ts @@ -2,8 +2,9 @@ import { COL, Space, SpaceJoinRequest, SUB_COL, WenError } from '@build-5/interf import { build5Db } from '../../firebase/firestore/build5Db'; import { getJoinSpaceData } from '../../services/payment/tangle-service/space/SpaceJoinService'; import { invalidArgument } from '../../utils/error.utils'; +import { Context } from '../common'; -export const joinSpaceControl = async (owner: string, params: SpaceJoinRequest) => { +export const joinSpaceControl = async ({ owner, params }: Context) => { const spaceDocRef = build5Db().doc(`${COL.SPACE}/${params.uid}`); const space = await spaceDocRef.get(); if (!space) { diff --git a/packages/functions/src/controls/space/space.update.control.ts b/packages/functions/src/controls/space/space.update.control.ts index 77e9ae7d92..04b177a02a 100644 --- a/packages/functions/src/controls/space/space.update.control.ts +++ b/packages/functions/src/controls/space/space.update.control.ts @@ -24,8 +24,9 @@ import { cleanupParams } from '../../utils/schema.utils'; import { hasActiveEditProposal } from '../../utils/space.utils'; import { assertIsGuardian, getTokenForSpace } from '../../utils/token.utils'; import { getRandomEthAddress } from '../../utils/wallet.utils'; +import { Context } from '../common'; -export const updateSpaceControl = async (owner: string, params: SpaceUpdateRequest) => { +export const updateSpaceControl = async ({ owner, params }: Context) => { const spaceDocRef = build5Db().doc(`${COL.SPACE}/${params.uid}`); const space = await spaceDocRef.get(); diff --git a/packages/functions/src/runtime/firebase/stake/StakeRewardRemoveRequestSchema.ts b/packages/functions/src/controls/stake/StakeRewardRemoveRequestSchema.ts similarity index 88% rename from packages/functions/src/runtime/firebase/stake/StakeRewardRemoveRequestSchema.ts rename to packages/functions/src/controls/stake/StakeRewardRemoveRequestSchema.ts index aa3f9b22f2..7eb321cd6d 100644 --- a/packages/functions/src/runtime/firebase/stake/StakeRewardRemoveRequestSchema.ts +++ b/packages/functions/src/controls/stake/StakeRewardRemoveRequestSchema.ts @@ -1,6 +1,6 @@ import { TokenStakeRewardsRemoveRequest } from '@build-5/interfaces'; import Joi from 'joi'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; const MIN_COUNT = 1; const MAX_COUNT = 450; diff --git a/packages/functions/src/runtime/firebase/stake/StakeRewardRequestSchema.ts b/packages/functions/src/controls/stake/StakeRewardRequestSchema.ts similarity index 96% rename from packages/functions/src/runtime/firebase/stake/StakeRewardRequestSchema.ts rename to packages/functions/src/controls/stake/StakeRewardRequestSchema.ts index 19fb0af9f2..ac94023260 100644 --- a/packages/functions/src/runtime/firebase/stake/StakeRewardRequestSchema.ts +++ b/packages/functions/src/controls/stake/StakeRewardRequestSchema.ts @@ -5,7 +5,7 @@ import { TokenStakeRewardsRequest, } from '@build-5/interfaces'; import Joi from 'joi'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; const MIN_START_DATE = 0; const MAX_START_DATE = MAX_MILLISECONDS; diff --git a/packages/functions/src/runtime/firebase/stake/StakeTokenRequestSchema.ts b/packages/functions/src/controls/stake/StakeTokenRequestSchema.ts similarity index 94% rename from packages/functions/src/runtime/firebase/stake/StakeTokenRequestSchema.ts rename to packages/functions/src/controls/stake/StakeTokenRequestSchema.ts index d72a7da8d0..4695d8eb9b 100644 --- a/packages/functions/src/runtime/firebase/stake/StakeTokenRequestSchema.ts +++ b/packages/functions/src/controls/stake/StakeTokenRequestSchema.ts @@ -5,7 +5,7 @@ import { TokenStakeRequest, } from '@build-5/interfaces'; import Joi from 'joi'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; const KEY_COUNT = 5; const FIELD_NAME_LENGTH = 50; diff --git a/packages/functions/src/controls/stake/stake.deposit.ts b/packages/functions/src/controls/stake/stake.deposit.ts index 55c15ed476..1db5584b5d 100644 --- a/packages/functions/src/controls/stake/stake.deposit.ts +++ b/packages/functions/src/controls/stake/stake.deposit.ts @@ -1,8 +1,9 @@ import { COL, StakeType, TokenStakeRequest } from '@build-5/interfaces'; import { build5Db } from '../../firebase/firestore/build5Db'; import { createStakeOrder } from '../../services/payment/tangle-service/token/stake.service'; +import { Context } from '../common'; -export const depositStakeControl = async (owner: string, params: TokenStakeRequest) => { +export const depositStakeControl = async ({ owner, params }: Context) => { const order = await createStakeOrder( owner, params.symbol, diff --git a/packages/functions/src/controls/stake/stake.reward.revoke.ts b/packages/functions/src/controls/stake/stake.reward.revoke.ts index 9be9e09366..4d0e5b00a7 100644 --- a/packages/functions/src/controls/stake/stake.reward.revoke.ts +++ b/packages/functions/src/controls/stake/stake.reward.revoke.ts @@ -23,11 +23,12 @@ import { dateToTimestamp, serverTime } from '../../utils/dateTime.utils'; import { invalidArgument } from '../../utils/error.utils'; import { assertIsGuardian } from '../../utils/token.utils'; import { getRandomEthAddress } from '../../utils/wallet.utils'; +import { Context } from '../common'; -export const removeStakeRewardControl = async ( - owner: string, - params: TokenStakeRewardsRemoveRequest, -) => { +export const removeStakeRewardControl = async ({ + owner, + params, +}: Context) => { const stakeRewardIds = params.stakeRewardIds as string[]; const stakeRewardPromises = stakeRewardIds.map(async (stakeId) => { const docRef = build5Db().doc(`${COL.STAKE_REWARD}/${stakeId}`); diff --git a/packages/functions/src/controls/stake/stake.reward.ts b/packages/functions/src/controls/stake/stake.reward.ts index 769ab956db..a2c4bc79cf 100644 --- a/packages/functions/src/controls/stake/stake.reward.ts +++ b/packages/functions/src/controls/stake/stake.reward.ts @@ -12,8 +12,9 @@ import { dateToTimestamp } from '../../utils/dateTime.utils'; import { invalidArgument } from '../../utils/error.utils'; import { assertIsGuardian } from '../../utils/token.utils'; import { getRandomEthAddress } from '../../utils/wallet.utils'; +import { Context } from '../common'; -export const stakeRewardControl = async (owner: string, params: TokenStakeRewardsRequest) => { +export const stakeRewardControl = async ({ owner, params }: Context) => { const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${params.token}`); const token = await tokenDocRef.get(); if (!token) { diff --git a/packages/functions/src/runtime/firebase/token/minting/TokenClaimMintedRequestSchema.ts b/packages/functions/src/controls/token-minting/TokenClaimMintedRequestSchema.ts similarity index 82% rename from packages/functions/src/runtime/firebase/token/minting/TokenClaimMintedRequestSchema.ts rename to packages/functions/src/controls/token-minting/TokenClaimMintedRequestSchema.ts index 6f6fac3139..5cd87b138a 100644 --- a/packages/functions/src/runtime/firebase/token/minting/TokenClaimMintedRequestSchema.ts +++ b/packages/functions/src/controls/token-minting/TokenClaimMintedRequestSchema.ts @@ -1,5 +1,5 @@ import { ClaimAirdroppedTokensRequest } from '@build-5/interfaces'; -import { CommonJoi, toJoiObject } from '../../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; export const symbolSchema = toJoiObject({ symbol: CommonJoi.tokenSymbol().description('Symbol of the token to claim.'), diff --git a/packages/functions/src/runtime/firebase/token/minting/TokenImportRequestSchema.ts b/packages/functions/src/controls/token-minting/TokenImportRequestSchema.ts similarity index 77% rename from packages/functions/src/runtime/firebase/token/minting/TokenImportRequestSchema.ts rename to packages/functions/src/controls/token-minting/TokenImportRequestSchema.ts index 6b73e424cb..dc1eb10d32 100644 --- a/packages/functions/src/runtime/firebase/token/minting/TokenImportRequestSchema.ts +++ b/packages/functions/src/controls/token-minting/TokenImportRequestSchema.ts @@ -1,8 +1,8 @@ import { ImportMintedTokenRequest } from '@build-5/interfaces'; import Joi from 'joi'; -import { AVAILABLE_NETWORKS } from '../../../../controls/common'; -import { CommonJoi, toJoiObject } from '../../../../services/joi/common'; -import { networks } from '../../../../utils/config.utils'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; +import { networks } from '../../utils/config.utils'; +import { AVAILABLE_NETWORKS } from '../common'; const availaibleNetworks = AVAILABLE_NETWORKS.filter((n) => networks.includes(n)); diff --git a/packages/functions/src/runtime/firebase/token/minting/TokenMintRequestSchema.ts b/packages/functions/src/controls/token-minting/TokenMintRequestSchema.ts similarity index 72% rename from packages/functions/src/runtime/firebase/token/minting/TokenMintRequestSchema.ts rename to packages/functions/src/controls/token-minting/TokenMintRequestSchema.ts index 9416cf12ec..c2db28a3ce 100644 --- a/packages/functions/src/runtime/firebase/token/minting/TokenMintRequestSchema.ts +++ b/packages/functions/src/controls/token-minting/TokenMintRequestSchema.ts @@ -1,8 +1,8 @@ import { TokenMintRequest } from '@build-5/interfaces'; import Joi from 'joi'; -import { AVAILABLE_NETWORKS } from '../../../../controls/common'; -import { CommonJoi, toJoiObject } from '../../../../services/joi/common'; -import { networks } from '../../../../utils/config.utils'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; +import { networks } from '../../utils/config.utils'; +import { AVAILABLE_NETWORKS } from '../common'; const availaibleNetworks = AVAILABLE_NETWORKS.filter((n) => networks.includes(n)); 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 9b0106297c..1a28c2b525 100644 --- a/packages/functions/src/controls/token-minting/airdrop-minted-token.ts +++ b/packages/functions/src/controls/token-minting/airdrop-minted-token.ts @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { COL, + CreateAirdropsRequest, StakeType, TRANSACTION_AUTO_EXPIRY_MS, Token, @@ -16,15 +17,18 @@ import { import dayjs from 'dayjs'; import { chunk } from 'lodash'; import { build5Db } from '../../firebase/firestore/build5Db'; -import { CreateAirdropsRequest } from '../../runtime/firebase/token/base/TokenAirdropRequestSchema'; import { WalletService } from '../../services/wallet/wallet.service'; import { packBasicOutput } from '../../utils/basic-output.utils'; import { dateToTimestamp } from '../../utils/dateTime.utils'; import { invalidArgument } from '../../utils/error.utils'; import { assertIsGuardian, assertTokenApproved, assertTokenStatus } from '../../utils/token.utils'; import { getRandomEthAddress } from '../../utils/wallet.utils'; +import { Context } from '../common'; -export const airdropMintedTokenControl = async (owner: string, params: CreateAirdropsRequest) => { +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); @@ -80,7 +84,7 @@ export const airdropMintedTokenControl = async (owner: string, params: CreateAir status: TokenDropStatus.DEPOSIT_NEEDED, orderId: order.uid, sourceAddress: targetAddress.bech32, - stakeType: drop.stakeType || StakeType.DYNAMIC, + stakeType: (drop.stakeType as StakeType) || StakeType.DYNAMIC, })); const chunks = chunk(airdrops, 500); 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 3c0a21dcff..d155bbbd87 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 @@ -1,11 +1,12 @@ import { COL, ClaimAirdroppedTokensRequest } from '@build-5/interfaces'; import { build5Db } from '../../firebase/firestore/build5Db'; import { createMintedTokenAirdropCalimOrder } from '../../services/payment/tangle-service/token/token-claim.service'; +import { Context } from '../common'; -export const claimMintedTokenControl = async ( - owner: string, - params: ClaimAirdroppedTokensRequest, -) => { +export const claimMintedTokenControl = async ({ + owner, + params, +}: Context) => { const order = await createMintedTokenAirdropCalimOrder(owner, params.symbol); 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 f6175e98fa..0fd8d24253 100644 --- a/packages/functions/src/controls/token-minting/import-minted-token.ts +++ b/packages/functions/src/controls/token-minting/import-minted-token.ts @@ -18,8 +18,12 @@ import { dateToTimestamp } from '../../utils/dateTime.utils'; import { invalidArgument } from '../../utils/error.utils'; import { assertIsGuardian } from '../../utils/token.utils'; import { getRandomEthAddress } from '../../utils/wallet.utils'; +import { Context } from '../common'; -export const importMintedTokenControl = async (owner: string, params: ImportMintedTokenRequest) => +export const importMintedTokenControl = async ({ + owner, + params, +}: Context) => build5Db().runTransaction(async (transaction) => { await assertIsGuardian(params.space, owner); 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 fabf36600e..2139b52210 100644 --- a/packages/functions/src/controls/token-minting/token-mint.control.ts +++ b/packages/functions/src/controls/token-minting/token-mint.control.ts @@ -33,8 +33,9 @@ import { getUnclaimedAirdropTotalValue, } from '../../utils/token.utils'; import { getRandomEthAddress } from '../../utils/wallet.utils'; +import { Context } from '../common'; -export const mintTokenControl = (owner: string, params: TokenMintRequest) => +export const mintTokenControl = ({ owner, params }: Context) => build5Db().runTransaction(async (transaction) => { const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${params.token}`); const token = await transaction.get(tokenDocRef); diff --git a/packages/functions/src/runtime/firebase/token/trading/TokenCanelTradeOrderRequestSchema.ts b/packages/functions/src/controls/token-trading/TokenCanelTradeOrderRequestSchema.ts similarity index 82% rename from packages/functions/src/runtime/firebase/token/trading/TokenCanelTradeOrderRequestSchema.ts rename to packages/functions/src/controls/token-trading/TokenCanelTradeOrderRequestSchema.ts index 659a967c5f..c87b66291e 100644 --- a/packages/functions/src/runtime/firebase/token/trading/TokenCanelTradeOrderRequestSchema.ts +++ b/packages/functions/src/controls/token-trading/TokenCanelTradeOrderRequestSchema.ts @@ -1,5 +1,5 @@ import { CancelTokenTradeOrderRequest } from '@build-5/interfaces'; -import { CommonJoi, toJoiObject } from '../../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; export const cancelTradeOrderSchema = toJoiObject({ uid: CommonJoi.uid().description('Build5 id of the trade order.'), diff --git a/packages/functions/src/runtime/firebase/token/trading/TokenTradeRequestSchema.ts b/packages/functions/src/controls/token-trading/TokenTradeRequestSchema.ts similarity index 86% rename from packages/functions/src/runtime/firebase/token/trading/TokenTradeRequestSchema.ts rename to packages/functions/src/controls/token-trading/TokenTradeRequestSchema.ts index b7ef007521..1c6ebf7fdc 100644 --- a/packages/functions/src/runtime/firebase/token/trading/TokenTradeRequestSchema.ts +++ b/packages/functions/src/controls/token-trading/TokenTradeRequestSchema.ts @@ -1,7 +1,7 @@ import { MIN_PRICE_PER_TOKEN, TokenTradeOrderType, TradeTokenRequest } from '@build-5/interfaces'; import Joi from 'joi'; -import { CommonJoi, toJoiObject } from '../../../../services/joi/common'; -import { MAX_COUNT, MAX_PRICE, MIN_COUNT } from '../base/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; +import { MIN_COUNT, MAX_COUNT, MAX_PRICE } from '../token/common'; export const tradeTokenSchema = toJoiObject({ 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 9f0780efd9..b836db3054 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 @@ -8,8 +8,9 @@ import { import { build5Db } from '../../firebase/firestore/build5Db'; import { invalidArgument } from '../../utils/error.utils'; import { cancelTradeOrderUtil } from '../../utils/token-trade.utils'; +import { Context } from '../common'; -export const cancelTradeOrderControl = (owner: string, params: CancelTokenTradeOrderRequest) => +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); 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 462b04758b..fdb062e1cd 100644 --- a/packages/functions/src/controls/token-trading/token-trade.controller.ts +++ b/packages/functions/src/controls/token-trading/token-trade.controller.ts @@ -10,12 +10,9 @@ import { build5Db } from '../../firebase/firestore/build5Db'; import { createTokenTradeOrder } from '../../services/payment/tangle-service/token/token-trade.service'; import { invalidArgument } from '../../utils/error.utils'; import { getTokenBySymbol } from '../../utils/token.utils'; +import { Context } from '../common'; -export const tradeTokenControl = async ( - owner: string, - params: TradeTokenRequest, - customParams?: Record, -) => { +export const tradeTokenControl = async ({ ip, owner, params }: Context) => { let token = await getTokenBySymbol(params.symbol); return await build5Db().runTransaction(async (transaction) => { @@ -36,7 +33,7 @@ export const tradeTokenControl = async ( params.count, params.price, '', - customParams?.ip as string | undefined, + ip, ); if (tradeOrder) { const orderDocRef = build5Db().doc(`${COL.TOKEN_MARKET}/${tradeOrder.uid}`); diff --git a/packages/functions/src/runtime/firebase/token/base/TokenAirdropRequestSchema.ts b/packages/functions/src/controls/token/TokenAirdropRequestSchema.ts similarity index 95% rename from packages/functions/src/runtime/firebase/token/base/TokenAirdropRequestSchema.ts rename to packages/functions/src/controls/token/TokenAirdropRequestSchema.ts index 85cf885102..036d49c661 100644 --- a/packages/functions/src/runtime/firebase/token/base/TokenAirdropRequestSchema.ts +++ b/packages/functions/src/controls/token/TokenAirdropRequestSchema.ts @@ -1,6 +1,6 @@ import { EthAddress, MAX_AIRDROP, MAX_TOTAL_TOKEN_SUPPLY, StakeType } from '@build-5/interfaces'; import Joi from 'joi'; -import { CommonJoi, toJoiObject } from '../../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; import { MAX_COUNT, MIN_AIRDROP, MIN_COUNT } from './common'; export interface AirdropRequest { diff --git a/packages/functions/src/runtime/firebase/token/base/TokenCancelPubSaleRequestSchema.ts b/packages/functions/src/controls/token/TokenCancelPubSaleRequestSchema.ts similarity index 81% rename from packages/functions/src/runtime/firebase/token/base/TokenCancelPubSaleRequestSchema.ts rename to packages/functions/src/controls/token/TokenCancelPubSaleRequestSchema.ts index 8035f06947..4e6bb06ecb 100644 --- a/packages/functions/src/runtime/firebase/token/base/TokenCancelPubSaleRequestSchema.ts +++ b/packages/functions/src/controls/token/TokenCancelPubSaleRequestSchema.ts @@ -1,5 +1,5 @@ import { CanelPublicSaleRequest } from '@build-5/interfaces'; -import { CommonJoi, toJoiObject } from '../../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; export const cancelPubSaleSchema = toJoiObject({ token: CommonJoi.uid().description('Build5 id of the token.'), diff --git a/packages/functions/src/runtime/firebase/token/base/TokenClaimAirdroppedRequestSchema.ts b/packages/functions/src/controls/token/TokenClaimAirdroppedRequestSchema.ts similarity index 86% rename from packages/functions/src/runtime/firebase/token/base/TokenClaimAirdroppedRequestSchema.ts rename to packages/functions/src/controls/token/TokenClaimAirdroppedRequestSchema.ts index f35959860f..27dde542fa 100644 --- a/packages/functions/src/runtime/firebase/token/base/TokenClaimAirdroppedRequestSchema.ts +++ b/packages/functions/src/controls/token/TokenClaimAirdroppedRequestSchema.ts @@ -1,6 +1,6 @@ import { ClaimPreMintedAirdroppedTokensRequest } from '@build-5/interfaces'; import Joi from 'joi'; -import { toJoiObject } from '../../../../services/joi/common'; +import { toJoiObject } from '../../services/joi/common'; export const claimAirdroppedTokenSchema = toJoiObject({ token: Joi.string().required().description('Build5 id of the token.'), diff --git a/packages/functions/src/runtime/firebase/token/base/TokenCreateRequestSchema.ts b/packages/functions/src/controls/token/TokenCreateRequestSchema.ts similarity index 97% rename from packages/functions/src/runtime/firebase/token/base/TokenCreateRequestSchema.ts rename to packages/functions/src/controls/token/TokenCreateRequestSchema.ts index 8cfb6ed0d6..d4c2a76fff 100644 --- a/packages/functions/src/runtime/firebase/token/base/TokenCreateRequestSchema.ts +++ b/packages/functions/src/controls/token/TokenCreateRequestSchema.ts @@ -11,8 +11,8 @@ import { } from '@build-5/interfaces'; import dayjs from 'dayjs'; import Joi from 'joi'; -import { CommonJoi, toJoiObject } from '../../../../services/joi/common'; -import { isProdEnv } from '../../../../utils/config.utils'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; +import { isProdEnv } from '../../utils/config.utils'; import { MAX_PRICE } from './common'; const MIN_PERCENTAGE = 0.01; diff --git a/packages/functions/src/runtime/firebase/token/base/TokenCreditRequestSchema.ts b/packages/functions/src/controls/token/TokenCreditRequestSchema.ts similarity index 88% rename from packages/functions/src/runtime/firebase/token/base/TokenCreditRequestSchema.ts rename to packages/functions/src/controls/token/TokenCreditRequestSchema.ts index 08af98a71a..e0e75b68ac 100644 --- a/packages/functions/src/runtime/firebase/token/base/TokenCreditRequestSchema.ts +++ b/packages/functions/src/controls/token/TokenCreditRequestSchema.ts @@ -1,6 +1,6 @@ import { CreditTokenRequest, MAX_IOTA_AMOUNT, MIN_IOTA_AMOUNT } from '@build-5/interfaces'; import Joi from 'joi'; -import { CommonJoi, toJoiObject } from '../../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; export const creditTokenSchema = toJoiObject({ token: CommonJoi.uid().description('Build5 id of the token.'), diff --git a/packages/functions/src/runtime/firebase/token/base/TokenEnableTradingRequestSchema.ts b/packages/functions/src/controls/token/TokenEnableTradingRequestSchema.ts similarity index 81% rename from packages/functions/src/runtime/firebase/token/base/TokenEnableTradingRequestSchema.ts rename to packages/functions/src/controls/token/TokenEnableTradingRequestSchema.ts index ecde3cebdc..3a25894853 100644 --- a/packages/functions/src/runtime/firebase/token/base/TokenEnableTradingRequestSchema.ts +++ b/packages/functions/src/controls/token/TokenEnableTradingRequestSchema.ts @@ -1,5 +1,5 @@ import { EnableTokenTradingRequest } from '@build-5/interfaces'; -import { CommonJoi, toJoiObject } from '../../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; export const enableTradingSchema = toJoiObject({ uid: CommonJoi.uid().description('Build5 id of the token.'), diff --git a/packages/functions/src/runtime/firebase/token/base/TokenOrderRequestSchema.ts b/packages/functions/src/controls/token/TokenOrderRequestSchema.ts similarity index 80% rename from packages/functions/src/runtime/firebase/token/base/TokenOrderRequestSchema.ts rename to packages/functions/src/controls/token/TokenOrderRequestSchema.ts index 9b2cbb7803..0aee5ec89d 100644 --- a/packages/functions/src/runtime/firebase/token/base/TokenOrderRequestSchema.ts +++ b/packages/functions/src/controls/token/TokenOrderRequestSchema.ts @@ -1,5 +1,5 @@ import { OrderTokenRequest } from '@build-5/interfaces'; -import { CommonJoi, toJoiObject } from '../../../../services/joi/common'; +import { toJoiObject, CommonJoi } from '../../services/joi/common'; export const orderTokenSchema = toJoiObject({ token: CommonJoi.uid().description('Build5 id of the token'), diff --git a/packages/functions/src/runtime/firebase/token/base/TokenSetAvailableForSaleRequestSchema.ts b/packages/functions/src/controls/token/TokenSetAvailableForSaleRequestSchema.ts similarity index 92% rename from packages/functions/src/runtime/firebase/token/base/TokenSetAvailableForSaleRequestSchema.ts rename to packages/functions/src/controls/token/TokenSetAvailableForSaleRequestSchema.ts index 07ec9d468b..33166f2714 100644 --- a/packages/functions/src/runtime/firebase/token/base/TokenSetAvailableForSaleRequestSchema.ts +++ b/packages/functions/src/controls/token/TokenSetAvailableForSaleRequestSchema.ts @@ -7,8 +7,8 @@ import { } from '@build-5/interfaces'; import dayjs from 'dayjs'; import Joi from 'joi'; -import { CommonJoi, toJoiObject } from '../../../../services/joi/common'; -import { isProdEnv } from '../../../../utils/config.utils'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; +import { isProdEnv } from '../../utils/config.utils'; import { MAX_PRICE } from './common'; const MIN_COOL_DOWN = 0; diff --git a/packages/functions/src/runtime/firebase/token/base/TokenUpdateRequestSchema.ts b/packages/functions/src/controls/token/TokenUpdateRequestSchema.ts similarity index 95% rename from packages/functions/src/runtime/firebase/token/base/TokenUpdateRequestSchema.ts rename to packages/functions/src/controls/token/TokenUpdateRequestSchema.ts index 3656808f06..238cd585d0 100644 --- a/packages/functions/src/runtime/firebase/token/base/TokenUpdateRequestSchema.ts +++ b/packages/functions/src/controls/token/TokenUpdateRequestSchema.ts @@ -5,7 +5,7 @@ import { TokenUpdateRequest, } from '@build-5/interfaces'; import Joi from 'joi'; -import { CommonJoi, toJoiObject } from '../../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; const MAX_PRICE = MAX_IOTA_AMOUNT; diff --git a/packages/functions/src/controls/token/common.ts b/packages/functions/src/controls/token/common.ts index 5f12c0e700..7385278c13 100644 --- a/packages/functions/src/controls/token/common.ts +++ b/packages/functions/src/controls/token/common.ts @@ -1,4 +1,10 @@ -import { Timestamp, TokenAllocation, WenError } from '@build-5/interfaces'; +import { + MAX_IOTA_AMOUNT, + MAX_TOTAL_TOKEN_SUPPLY, + Timestamp, + TokenAllocation, + WenError, +} from '@build-5/interfaces'; import dayjs from 'dayjs'; import { dateToTimestamp } from '../../utils/dateTime.utils'; import { invalidArgument } from '../../utils/error.utils'; @@ -28,3 +34,10 @@ export const getPublicSaleTimeFrames = ( const coolDownEnd = dayjs(saleStartDate.toDate()).add(saleLength + coolDownLength, 'ms'); return { saleStartDate, saleLength, coolDownEnd: dateToTimestamp(coolDownEnd, true) }; }; + +export const MAX_PRICE = MAX_IOTA_AMOUNT; + +export const MIN_AIRDROP = 1; + +export const MIN_COUNT = 1; +export const MAX_COUNT = MAX_TOTAL_TOKEN_SUPPLY; diff --git a/packages/functions/src/controls/token/token.airdrop.claim.ts b/packages/functions/src/controls/token/token.airdrop.claim.ts index eb53a53dcb..2344afe542 100644 --- a/packages/functions/src/controls/token/token.airdrop.claim.ts +++ b/packages/functions/src/controls/token/token.airdrop.claim.ts @@ -20,11 +20,12 @@ import { dateToTimestamp } from '../../utils/dateTime.utils'; import { invalidArgument } from '../../utils/error.utils'; import { assertTokenStatus, getUnclaimedDrops } from '../../utils/token.utils'; import { getRandomEthAddress } from '../../utils/wallet.utils'; +import { Context } from '../common'; -export const claimAirdroppedTokenControl = async ( - owner: string, - params: ClaimPreMintedAirdroppedTokensRequest, -): Promise => { +export const claimAirdroppedTokenControl = async ({ + owner, + params, +}: Context): Promise => { const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${params.token}`); const token = await tokenDocRef.get(); if (!token) { diff --git a/packages/functions/src/controls/token/token.airdrop.ts b/packages/functions/src/controls/token/token.airdrop.ts index 93fce80951..4558a3ee6d 100644 --- a/packages/functions/src/controls/token/token.airdrop.ts +++ b/packages/functions/src/controls/token/token.airdrop.ts @@ -1,5 +1,6 @@ import { COL, + CreateAirdropsRequest, StakeType, SUB_COL, Token, @@ -10,11 +11,11 @@ import { } from '@build-5/interfaces'; import { chunk } from 'lodash'; import { build5Db } from '../../firebase/firestore/build5Db'; -import { CreateAirdropsRequest } from '../../runtime/firebase/token/base/TokenAirdropRequestSchema'; import { dateToTimestamp } from '../../utils/dateTime.utils'; import { invalidArgument } from '../../utils/error.utils'; import { assertIsGuardian, assertTokenApproved, assertTokenStatus } from '../../utils/token.utils'; import { getRandomEthAddress } from '../../utils/wallet.utils'; +import { Context } from '../common'; export interface TokenDropRequest { readonly vestingAt: Date; @@ -29,7 +30,7 @@ const hasAvailableTokenToAirdrop = (token: Token, count: number) => { return token.totalSupply - totalPublicSupply - token.totalAirdropped >= count; }; -export const airdropTokenControl = async (owner: string, params: CreateAirdropsRequest) => { +export const airdropTokenControl = async ({ owner, params }: Context) => { const chunks = chunk(params.drops, 200); for (const chunk of chunks) { await build5Db().runTransaction(async (transaction) => { 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 7908e4906d..ea506aca5e 100644 --- a/packages/functions/src/controls/token/token.cancel.pub.sale.ts +++ b/packages/functions/src/controls/token/token.cancel.pub.sale.ts @@ -3,8 +3,12 @@ import dayjs from 'dayjs'; import { build5Db } from '../../firebase/firestore/build5Db'; import { invalidArgument } from '../../utils/error.utils'; import { assertIsGuardian } from '../../utils/token.utils'; +import { Context } from '../common'; -export const cancelPublicSaleControl = async (owner: string, params: CanelPublicSaleRequest) => { +export const cancelPublicSaleControl = async ({ + owner, + params, +}: Context) => { const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${params.token}`); await build5Db().runTransaction(async (transaction) => { diff --git a/packages/functions/src/controls/token/token.create.ts b/packages/functions/src/controls/token/token.create.ts index 041b6bb554..1379a33119 100644 --- a/packages/functions/src/controls/token/token.create.ts +++ b/packages/functions/src/controls/token/token.create.ts @@ -16,9 +16,10 @@ import { dateToTimestamp } from '../../utils/dateTime.utils'; import { invalidArgument } from '../../utils/error.utils'; import { assertIsGuardian } from '../../utils/token.utils'; import { getRandomEthAddress } from '../../utils/wallet.utils'; +import { Context } from '../common'; import { getPublicSaleTimeFrames, shouldSetPublicSaleTimeFrames } from './common'; -export const createTokenControl = async (owner: string, params: TokenCreateRequest) => { +export const createTokenControl = async ({ owner, params }: Context) => { const hasStakedSoons = await hasStakedSoonTokens(owner); if (!hasStakedSoons) { throw invalidArgument(WenError.no_staked_soon); diff --git a/packages/functions/src/controls/token/token.credit.ts b/packages/functions/src/controls/token/token.credit.ts index da5a1380ba..e5822f0396 100644 --- a/packages/functions/src/controls/token/token.credit.ts +++ b/packages/functions/src/controls/token/token.credit.ts @@ -23,11 +23,12 @@ import { tokenOrderTransactionDocId, } from '../../utils/token.utils'; import { getRandomEthAddress } from '../../utils/wallet.utils'; +import { Context } from '../common'; -export const creditTokenControl = async ( - owner: string, - params: CreditTokenRequest, -): Promise => { +export const creditTokenControl = async ({ + owner, + params, +}: Context): Promise => { const tranId = getRandomEthAddress(); const creditTranDoc = build5Db().doc(`${COL.TRANSACTION}/${tranId}`); diff --git a/packages/functions/src/controls/token/token.enable.trading.ts b/packages/functions/src/controls/token/token.enable.trading.ts index 20026ea216..276c45f70a 100644 --- a/packages/functions/src/controls/token/token.enable.trading.ts +++ b/packages/functions/src/controls/token/token.enable.trading.ts @@ -2,11 +2,12 @@ import { COL, EnableTokenTradingRequest, Token, WenError } from '@build-5/interf import { build5Db } from '../../firebase/firestore/build5Db'; import { invalidArgument } from '../../utils/error.utils'; import { assertIsGuardian } from '../../utils/token.utils'; +import { Context } from '../common'; -export const enableTokenTradingControl = async ( - owner: string, - params: EnableTokenTradingRequest, -) => { +export const enableTokenTradingControl = async ({ + owner, + params, +}: Context) => { const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${params.uid}`); const token = await tokenDocRef.get(); if (!token) { diff --git a/packages/functions/src/controls/token/token.order.ts b/packages/functions/src/controls/token/token.order.ts index 6ff818881b..e8059f9cbf 100644 --- a/packages/functions/src/controls/token/token.order.ts +++ b/packages/functions/src/controls/token/token.order.ts @@ -23,12 +23,9 @@ import { dateToTimestamp } from '../../utils/dateTime.utils'; import { invalidArgument } from '../../utils/error.utils'; import { assertIpNotBlocked } from '../../utils/ip.utils'; import { tokenIsInPublicSalePeriod, tokenOrderTransactionDocId } from '../../utils/token.utils'; +import { Context } from '../common'; -export const orderTokenControl = async ( - owner: string, - params: OrderTokenRequest, - customParams?: Record, -) => { +export const orderTokenControl = async ({ ip, owner, params }: Context) => { const memberDocRef = build5Db().doc(`${COL.MEMBER}/${owner}`); const member = await memberDocRef.get(); assertMemberHasValidAddress(member, DEFAULT_NETWORK); @@ -39,7 +36,7 @@ export const orderTokenControl = async ( } if (isProdEnv()) { - await assertIpNotBlocked((customParams?.ip as string) || '', token.uid, 'token'); + await assertIpNotBlocked(ip, token.uid, 'token'); } if (!tokenIsInPublicSalePeriod(token) || token.status !== TokenStatus.AVAILABLE) { 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 d6863f947a..38dcd50b15 100644 --- a/packages/functions/src/controls/token/token.set.for.sale.ts +++ b/packages/functions/src/controls/token/token.set.for.sale.ts @@ -3,12 +3,13 @@ import { build5Db } from '../../firebase/firestore/build5Db'; import { dateToTimestamp } from '../../utils/dateTime.utils'; import { invalidArgument } from '../../utils/error.utils'; import { assertIsGuardian, assertTokenApproved, assertTokenStatus } from '../../utils/token.utils'; +import { Context } from '../common'; import { getPublicSaleTimeFrames, shouldSetPublicSaleTimeFrames } from './common'; -export const setTokenAvailableForSaleControl = async ( - owner: string, - params: SetTokenForSaleRequest, -) => { +export const setTokenAvailableForSaleControl = async ({ + owner, + params, +}: Context) => { const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${params.token}`); await build5Db().runTransaction(async (transaction) => { diff --git a/packages/functions/src/controls/token/token.update.ts b/packages/functions/src/controls/token/token.update.ts index e2ddca9b2e..1dfd916698 100644 --- a/packages/functions/src/controls/token/token.update.ts +++ b/packages/functions/src/controls/token/token.update.ts @@ -1,15 +1,15 @@ import { COL, Token, TokenStatus, WenError } from '@build-5/interfaces'; import { build5Db } from '../../firebase/firestore/build5Db'; -import { UidSchemaObject } from '../../runtime/firebase/common'; -import { - updateTokenSchemaObject, - uptdateMintedTokenSchemaObject, -} from '../../runtime/firebase/token/base/TokenUpdateRequestSchema'; import { invalidArgument } from '../../utils/error.utils'; import { assertValidationAsync } from '../../utils/schema.utils'; import { assertIsGuardian, assertTokenStatus } from '../../utils/token.utils'; +import { Context, UidSchemaObject } from '../common'; +import { + updateTokenSchemaObject, + uptdateMintedTokenSchemaObject, +} from './TokenUpdateRequestSchema'; -export const updateTokenControl = async (owner: string, params: UidSchemaObject) => { +export const updateTokenControl = async ({ owner, params }: Context) => { const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${params.uid}`); await build5Db().runTransaction(async (transaction) => { const token = await transaction.get(tokenDocRef); diff --git a/packages/functions/src/runtime/firebase/vote/VoteRequestSchema.ts b/packages/functions/src/controls/vote/VoteRequestSchema.ts similarity index 88% rename from packages/functions/src/runtime/firebase/vote/VoteRequestSchema.ts rename to packages/functions/src/controls/vote/VoteRequestSchema.ts index ce875b0c6c..0662007613 100644 --- a/packages/functions/src/runtime/firebase/vote/VoteRequestSchema.ts +++ b/packages/functions/src/controls/vote/VoteRequestSchema.ts @@ -1,6 +1,6 @@ import { COL, VoteRequest } from '@build-5/interfaces'; import Joi from 'joi'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; export const voteSchema = toJoiObject({ collection: Joi.string() diff --git a/packages/functions/src/controls/vote.control.ts b/packages/functions/src/controls/vote/vote.control.ts similarity index 87% rename from packages/functions/src/controls/vote.control.ts rename to packages/functions/src/controls/vote/vote.control.ts index 2f89ca9668..63455c60be 100644 --- a/packages/functions/src/controls/vote.control.ts +++ b/packages/functions/src/controls/vote/vote.control.ts @@ -1,9 +1,10 @@ import { COL, Collection, SUB_COL, Token, Vote, VoteRequest, WenError } from '@build-5/interfaces'; -import { build5Db } from '../firebase/firestore/build5Db'; -import { hasStakedSoonTokens } from '../services/stake.service'; -import { invalidArgument } from '../utils/error.utils'; +import { build5Db } from '../../firebase/firestore/build5Db'; +import { hasStakedSoonTokens } from '../../services/stake.service'; +import { invalidArgument } from '../../utils/error.utils'; +import { Context } from '../common'; -export const voteControl = async (owner: string, params: VoteRequest) => { +export const voteControl = async ({ owner, params }: Context) => { const hasStakedSoons = await hasStakedSoonTokens(owner); if (!hasStakedSoons) { throw invalidArgument(WenError.no_staked_soon); diff --git a/packages/functions/src/cron.ts b/packages/functions/src/cron.ts deleted file mode 100644 index 9c0909fb30..0000000000 --- a/packages/functions/src/cron.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { - STAKE_REWARD_CRON_INTERVAL_CONFIG, - STAKE_REWARD_TEST_CRON_INTERVAL_CONFIG, -} from '@build-5/interfaces'; -import * as functions from 'firebase-functions/v2'; -import { processExpiredAwards } from './cron/award.cron'; -import { getLatestBitfinexPricesCron } from './cron/bitfinex.cron'; -import { updateFloorPriceOnCollections } from './cron/collection.floor.price.cron'; -import { uploadMediaToWeb3 } from './cron/media.cron'; -import { finalizeAllNftAuctions, hidePlaceholderAfterSoldOutCron } from './cron/nft.cron'; -import { processExpiredNftStakes } from './cron/nftStake.cron'; -import { voidExpiredOrdersCron } from './cron/orders.cron'; -import { markExpiredProposalCompleted } from './cron/proposal.cron'; -import { removeExpiredStakesFromSpace } from './cron/stake.cron'; -import { stakeRewardCronTask } from './cron/stakeReward.cron'; -import { cancelExpiredSale, tokenCoolDownOver } from './cron/token.cron'; -import { removePurchasesFromVolumeStats } from './cron/token.purchase.cron'; -import { retryWallet } from './cron/wallet.cron'; -import { isProdEnv, isProdOrTestEnv } from './utils/config.utils'; - -const processExpiredAwardsCron = functions.scheduler.onSchedule( - 'every 1 minutes', - processExpiredAwards, -); - -const getLatestBitfinexPrices = functions.scheduler.onSchedule( - 'every 5 minutes', - getLatestBitfinexPricesCron, -); - -const retryWalletCron = functions.scheduler.onSchedule('every 2 minutes', async () => { - await retryWallet(); -}); - -const voidExpiredOrders = functions.scheduler.onSchedule('every 1 minutes', async () => { - await voidExpiredOrdersCron(); -}); - -const finalizeAuctionNft = functions.scheduler.onSchedule( - 'every 1 minutes', - finalizeAllNftAuctions, -); - -const hidePlaceholderAfterSoldOut = functions.scheduler.onSchedule('every 5 minutes', async () => { - await hidePlaceholderAfterSoldOutCron(); -}); - -const tokenCoolDownOverCron = functions.scheduler.onSchedule('every 1 minutes', async () => { - await tokenCoolDownOver(); -}); - -const cancelExpiredSaleCron = functions.scheduler.onSchedule('every 1 minutes', cancelExpiredSale); - -const stakeRewardCron = functions.scheduler.onSchedule( - { - timeoutSeconds: 540, - memory: '1GiB', - schedule: isProdEnv() - ? STAKE_REWARD_CRON_INTERVAL_CONFIG - : STAKE_REWARD_TEST_CRON_INTERVAL_CONFIG, - }, - stakeRewardCronTask, -); - -const removeExpiredStakesFromSpaceCron = functions.scheduler.onSchedule( - 'every 1 minutes', - removeExpiredStakesFromSpace, -); - -const mediaUploadCron = functions.scheduler.onSchedule( - { memory: '4GiB', schedule: 'every 1 minutes' }, - async () => { - await uploadMediaToWeb3(); - }, -); - -const removeExpiredNftStakes = functions.scheduler.onSchedule( - 'every 1 minutes', - processExpiredNftStakes, -); - -const updateFloorPriceOnCollectionsCron = functions.scheduler.onSchedule( - { - timeoutSeconds: 1800, - schedule: 'every 5 minutes', - }, - updateFloorPriceOnCollections, -); - -const markExpiredProposalCompletedCron = functions.scheduler.onSchedule( - 'every 5 minutes', - markExpiredProposalCompleted, -); - -const removePurchasesFromVolumeStatsCron = functions.scheduler.onSchedule( - 'every 1 minutes', - removePurchasesFromVolumeStats, -); - -export const cron = isProdOrTestEnv() - ? { - retrywalletcron: retryWalletCron, - processexpiredawardscron: processExpiredAwardsCron, - voidexpiredorders: voidExpiredOrders, - finalizeauctionnft: finalizeAuctionNft, - hideplaceholderaftersoldout: hidePlaceholderAfterSoldOut, - tokencooldownovercron: tokenCoolDownOverCron, - cancelexpiredsalecron: cancelExpiredSaleCron, - removeexpiredstakesfromspacecron: removeExpiredStakesFromSpaceCron, - getlatestbitfinexprices: getLatestBitfinexPrices, - stakerewardcron: stakeRewardCron, - mediauploadcron: mediaUploadCron, - removeexpirednftstakes: removeExpiredNftStakes, - updatefloorpriceoncollectionscron: updateFloorPriceOnCollectionsCron, - markexpiredproposalcompletedcron: markExpiredProposalCompletedCron, - removepurchasesfromvolumestatscron: removePurchasesFromVolumeStatsCron, - } - : {}; diff --git a/packages/functions/src/cron/media.cron.ts b/packages/functions/src/cron/media.cron.ts index d189c49826..6ff9b55f91 100644 --- a/packages/functions/src/cron/media.cron.ts +++ b/packages/functions/src/cron/media.cron.ts @@ -8,7 +8,6 @@ import { Space, Token, } from '@build-5/interfaces'; -import * as functions from 'firebase-functions/v2'; import { build5Db } from '../firebase/firestore/build5Db'; import { awardToIpfsMetadata } from '../services/payment/award/award-service'; import { @@ -139,7 +138,7 @@ const setMediaStatusToError = async (col: COL, uid: string, errorCount: number, }; if (errorCount >= MAX_WALLET_RETRY) { data.mediaStatus = MediaStatus.ERROR; - functions.logger.error(col, uid, 'Image upload error', error); + console.error(col, uid, 'Image upload error', error); } const docRef = build5Db().doc(`${col}/${uid}`); await docRef.update(data); diff --git a/packages/functions/src/cron/stakeReward.cron.ts b/packages/functions/src/cron/stakeReward.cron.ts index 83da26db5b..eb7664a9f6 100644 --- a/packages/functions/src/cron/stakeReward.cron.ts +++ b/packages/functions/src/cron/stakeReward.cron.ts @@ -16,7 +16,6 @@ import { TransactionType, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import * as functions from 'firebase-functions/v2'; import { isEmpty, last } from 'lodash'; import { build5Db, getSnapshot } from '../firebase/firestore/build5Db'; import { serverTime } from '../utils/dateTime.utils'; @@ -31,7 +30,7 @@ export const stakeRewardCronTask = async () => { const { totalAirdropped, totalStaked } = await executeStakeRewardDistribution(stakeReward); await stakeRewardDocRef.update({ totalStaked, totalAirdropped }); } catch (error) { - functions.logger.error('Stake reward error', stakeReward.uid, error); + console.error('Stake reward error', stakeReward.uid, error); await stakeRewardDocRef.update({ status: StakeRewardStatus.ERROR }); } } diff --git a/packages/functions/src/firebase/functions/onRequest.ts b/packages/functions/src/firebase/functions/onRequest.ts deleted file mode 100644 index c59e6701d0..0000000000 --- a/packages/functions/src/firebase/functions/onRequest.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { WEN_FUNC } from '@build-5/interfaces'; -import cors from 'cors'; -import * as functions from 'firebase-functions/v2'; -import { HttpsOptions } from 'firebase-functions/v2/https'; -import Joi from 'joi'; -import { get } from 'lodash'; -import { scale } from '../../scale.settings'; -import { isEmulatorEnv } from '../../utils/config.utils'; -import { assertValidationAsync } from '../../utils/schema.utils'; -import { decodeAuth } from '../../utils/wallet.utils'; - -export const onRequest = - ( - funcName: WEN_FUNC, - runtimeOptions?: functions.https.CallableOptions, - joiOptions?: Joi.ValidationOptions, - ) => - ( - schema: Joi.AnySchema

, - func: (owner: string, params: P, customParams?: Record) => Promise, - validateOnlyUid = false, - ) => - functions.https.onRequest(onRequestConfig(funcName, runtimeOptions), (req, res) => - cors({ origin: true })(req, res, async () => { - try { - const params = await decodeAuth(req.body.data, funcName); - const owner = params.address.toLowerCase(); - await assertValidationAsync( - schema, - validateOnlyUid ? { uid: params.body.uid } : params.body, - joiOptions, - ); - const result = await func(owner, params.body, { ip: req.ip }); - res.send({ data: result || {} }); - } catch (error) { - res.status(get(error, 'httpErrorCode.status', 400)); - res.send({ - data: { - code: get(error, 'details.code', 0), - key: get(error, 'details.key', ''), - message: get(error, 'message', ''), - }, - }); - } - }), - ); - -export const onRequestConfig = ( - funcName: WEN_FUNC, - runtimeOptions?: functions.https.CallableOptions, -) => { - const config: HttpsOptions = { - ingressSettings: 'ALLOW_INTERNAL_AND_GCLB', - minInstances: scale(funcName), - }; - if (!isEmulatorEnv()) { - config.cors = true; - } - return { - ...config, - ...runtimeOptions, - } as HttpsOptions; -}; diff --git a/packages/functions/src/index.express.ts b/packages/functions/src/index.express.ts new file mode 100644 index 0000000000..63e6357a20 --- /dev/null +++ b/packages/functions/src/index.express.ts @@ -0,0 +1,73 @@ +/* eslint-disable import/namespace */ + +import { HTTP } from 'cloudevents'; +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(); + +// HTTPS +Object.entries(flattenObject(onRequests)).forEach(([name, config]) => { + app.post(`/${name}`, express.json(), (req, res) => (config as HttpsFunction).func(req, res)); +}); + +// TRIGGERS +Object.entries(flattenObject(onTriggers)).forEach(([name, config]) => { + app.post(`/${name}`, app.use(express.raw({ type: 'application/protobuf' })), async (req, res) => { + const root = loadSync('./data.proto'); + const type = root.lookupType('DocumentEventData'); + const decoded = type.decode(req.body); + const 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); + res.send(200); + }); +}); + +// CRON +Object.entries(flattenObject(onScheduled)).forEach(([name, config]) => { + app.post(`/${name}`, async (_, res) => { + await (config as ScheduledFunction).func(); + res.send(200); + }); +}); + +// Storage +Object.entries(flattenObject(onStorage)).forEach(([name, config]) => { + app.post(`/${name}`, express.json(), async (req, res) => { + 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'), + }); + res.send(200); + }); +}); + +app.listen(8080).setTimeout(0); diff --git a/packages/functions/src/index.ts b/packages/functions/src/index.ts index 3c2e18bd18..ee1332a16a 100644 --- a/packages/functions/src/index.ts +++ b/packages/functions/src/index.ts @@ -1,204 +1,68 @@ -import { WEN_FUNC, WEN_FUNC_TRIGGER } from '@build-5/interfaces'; -import { algoliaTrigger } from './algolia/algolia.trigger'; -import { validateAddress } from './runtime/firebase/address'; -import { generateCustomToken } from './runtime/firebase/auth'; -import { - addOwnerAward, - approveAwardParticipant, - awardParticipate, - cancelAward, - createAward, - fundAward, - rejectAward, -} from './runtime/firebase/award/index'; -import { - approveCollection, - createCollection, - mintCollection, - rejectCollection, - updateCollection, -} from './runtime/firebase/collection'; -import { creditUnrefundable } from './runtime/firebase/credit/index'; -import { createMember, updateMember } from './runtime/firebase/member'; -import { - createBatchNft, - createNft, - depositNft, - openBid, - orderNft, - setForSaleNft, - stakeNft, - updateUnsoldNft, - withdrawNft, -} from './runtime/firebase/nft/index'; -import { - approveProposal, - createProposal, - rejectProposal, - voteOnProposal, -} from './runtime/firebase/proposal'; -import { rankController } from './runtime/firebase/rank'; -import { - acceptMemberSpace, - addGuardian, - blockMember, - claimSpace, - createSpace, - declineMemberSpace, - joinSpace, - leaveSpace, - removeGuardian, - unblockMember, - updateSpace, -} from './runtime/firebase/space'; -import { depositStake, removeStakeReward, stakeReward } from './runtime/firebase/stake'; -import { uploadFile } from './runtime/firebase/storage/file.upload'; -import { - airdropToken, - cancelPublicSale, - claimAirdroppedToken, - createToken, - creditToken, - enableTokenTrading, - orderToken, - setTokenAvailableForSale, - updateToken, -} from './runtime/firebase/token/base'; -import { - airdropMintedToken, - claimMintedTokenOrder, - importMintedToken, - mintTokenOrder, -} from './runtime/firebase/token/minting'; -import { cancelTradeOrder, tradeToken } from './runtime/firebase/token/trading'; -import { voteController } from './runtime/firebase/vote'; -import { awardUpdateTrigger } from './triggers/award.trigger'; -import { collectionStatsUpdate } from './triggers/collection.stats.trigger'; -import { collectionWrite } from './triggers/collection.trigger'; -import { - atoiMilestoneTransactionWrite, - iotaMilestoneTransactionWrite, - rmsMilestoneTransactionWrite, - smrMilestoneTransactionWrite, -} from './triggers/milestone-transactions-triggers/milestone-transaction.trigger'; -import { mnemonicWrite } from './triggers/mnemonic.trigger'; -import { nftWrite } from './triggers/nft.trigger'; -import { onProposalUpdated } from './triggers/proposal.trigger'; -import { resizeImageTrigger } from './triggers/storage/resize.img.trigger'; -import { onTokenPurchaseCreated } from './triggers/token-trading/token-purchase.trigger'; -import { onTokenTradeOrderWrite } from './triggers/token-trading/token-trade-order.trigger'; -import { onTokenStatusUpdate } from './triggers/token.trigger'; -import { transactionWrite } from './triggers/transaction-trigger/transaction.trigger'; -import { isProdEnv } from './utils/config.utils'; - -// Members functions. -exports[WEN_FUNC.createMember] = createMember; -exports[WEN_FUNC.updateMember] = updateMember; - -// Space functions. -exports[WEN_FUNC.createSpace] = createSpace; -exports[WEN_FUNC.updateSpace] = updateSpace; -exports[WEN_FUNC.joinSpace] = joinSpace; -exports[WEN_FUNC.leaveSpace] = leaveSpace; -exports[WEN_FUNC.addGuardianSpace] = addGuardian; -exports[WEN_FUNC.removeGuardianSpace] = removeGuardian; -exports[WEN_FUNC.blockMemberSpace] = blockMember; -exports[WEN_FUNC.unblockMemberSpace] = unblockMember; -exports[WEN_FUNC.acceptMemberSpace] = acceptMemberSpace; -exports[WEN_FUNC.declineMemberSpace] = declineMemberSpace; - -// Award Functions -exports[WEN_FUNC.createAward] = createAward; -exports[WEN_FUNC.fundAward] = fundAward; -exports[WEN_FUNC.rejectAward] = rejectAward; -exports[WEN_FUNC.addOwnerAward] = addOwnerAward; -exports[WEN_FUNC.participateAward] = awardParticipate; -exports[WEN_FUNC.approveParticipantAward] = approveAwardParticipant; -exports[WEN_FUNC_TRIGGER.awardTrigger] = awardUpdateTrigger; -exports[WEN_FUNC.cancelAward] = cancelAward; - -// Award Functions -exports[WEN_FUNC.createProposal] = createProposal; -exports[WEN_FUNC.approveProposal] = approveProposal; -exports[WEN_FUNC.rejectProposal] = rejectProposal; -exports[WEN_FUNC.voteOnProposal] = voteOnProposal; -exports['trigger_' + WEN_FUNC_TRIGGER.onProposalUpdated] = onProposalUpdated; - -// Collection functions -exports[WEN_FUNC.createCollection] = createCollection; -exports[WEN_FUNC.updateCollection] = updateCollection; -exports[WEN_FUNC.approveCollection] = approveCollection; -exports[WEN_FUNC.rejectCollection] = rejectCollection; - -// Order functions -exports[WEN_FUNC.openBid] = openBid; -exports[WEN_FUNC.validateAddress] = validateAddress; - -export * from './cron'; -export { algoliaTrigger, milestoneTriggers as trigger }; - -exports[WEN_FUNC.creditUnrefundable] = creditUnrefundable; -exports[WEN_FUNC.mintCollection] = mintCollection; - -exports[WEN_FUNC.createNft] = createNft; -exports[WEN_FUNC.createBatchNft] = createBatchNft; -exports[WEN_FUNC.updateUnsoldNft] = updateUnsoldNft; -exports[WEN_FUNC.setForSaleNft] = setForSaleNft; -exports[WEN_FUNC.withdrawNft] = withdrawNft; -exports[WEN_FUNC.depositNft] = depositNft; -exports[WEN_FUNC.orderNft] = orderNft; -exports[WEN_FUNC.stakeNft] = stakeNft; - -// TRIGGER Tasks -const prodMilestoneTriggers = { - iotaMilestoneTransactionWrite, - smrMilestoneTransactionWrite, +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable import/namespace */ + +import * as functions from 'firebase-functions/v2'; +import { flattenObject } from './common'; +import { CloudFunctions, pathToParts } from './runtime/common'; +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) => { + if (config.type === TriggeredFunctionType.ON_CREATE) { + return functions.firestore.onDocumentCreated(config.document, async (event) => { + const data = { + curr: event.data?.data(), + path: event.document, + ...pathToParts(event.document), + }; + await config.handler(data); + }); + } + const firestoreFunc = + config.type === TriggeredFunctionType.ON_UPDATE + ? functions.firestore.onDocumentUpdated + : functions.firestore.onDocumentWritten; + return firestoreFunc(config.document, async (event) => { + const data = { + prev: event.data?.before?.data(), + curr: event.data?.after?.data(), + path: event.document, + ...pathToParts(event.document), + }; + await config.handler(data); + }); }; -const testMilestoneTriggers = { - atoiMilestoneTransactionWrite, - rmsMilestoneTransactionWrite, -}; -const milestoneTriggers = isProdEnv() - ? prodMilestoneTriggers - : { ...prodMilestoneTriggers, ...testMilestoneTriggers }; - -exports['trigger_transactionWrite'] = transactionWrite; -exports['trigger_collectionWrite'] = collectionWrite; -exports['trigger_collectionStatsUpdate'] = collectionStatsUpdate; -exports['trigger_nftWrite'] = nftWrite; - -// Token functions -exports[WEN_FUNC.createToken] = createToken; -exports[WEN_FUNC.updateToken] = updateToken; -exports[WEN_FUNC.setTokenAvailableForSale] = setTokenAvailableForSale; -exports[WEN_FUNC.orderToken] = orderToken; -exports[WEN_FUNC.creditToken] = creditToken; -exports[WEN_FUNC.airdropToken] = airdropToken; -exports[WEN_FUNC.claimAirdroppedToken] = claimAirdroppedToken; -exports['trigger_onTokenStatusUpdate'] = onTokenStatusUpdate; -exports['trigger_onTokenTradeOrderWrite'] = onTokenTradeOrderWrite; -exports['trigger_onTokenPurchaseCreated'] = onTokenPurchaseCreated; -exports[WEN_FUNC.cancelTradeOrder] = cancelTradeOrder; -exports[WEN_FUNC.tradeToken] = tradeToken; -exports[WEN_FUNC.cancelPublicSale] = cancelPublicSale; -exports[WEN_FUNC.mintTokenOrder] = mintTokenOrder; -exports[WEN_FUNC.claimMintedTokenOrder] = claimMintedTokenOrder; -exports['trigger_' + WEN_FUNC_TRIGGER.mnemonicWrite] = mnemonicWrite; -exports[WEN_FUNC.depositStake] = depositStake; -exports[WEN_FUNC.airdropMintedToken] = airdropMintedToken; -exports[WEN_FUNC.voteController] = voteController; -exports[WEN_FUNC.rankController] = rankController; -exports[WEN_FUNC.enableTokenTrading] = enableTokenTrading; - -exports['storage_trigger_resizeImage'] = resizeImageTrigger; - -exports[WEN_FUNC.stakeReward] = stakeReward; -exports[WEN_FUNC.removeStakeReward] = removeStakeReward; - -exports[WEN_FUNC.generateCustomToken] = generateCustomToken; - -exports[WEN_FUNC.claimSpace] = claimSpace; - -exports[WEN_FUNC.importMintedToken] = importMintedToken; - -exports[WEN_FUNC.uploadFile] = uploadFile; +export const triggers = Object.entries(flattenObject(onTriggers)).reduce( + (acc, [key, config]) => ({ ...acc, [key]: getFirestoreHandler(config) }), + {} as any, +); + +// 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); diff --git a/packages/functions/src/runtime/common.ts b/packages/functions/src/runtime/common.ts new file mode 100644 index 0000000000..cc5e0cfece --- /dev/null +++ b/packages/functions/src/runtime/common.ts @@ -0,0 +1,62 @@ +import { COL, SUB_COL } from '@build-5/interfaces'; + +export enum WEN_FUNC_TRIGGER { + onProposalWrite = 'onproposaluwrite', + onAwardUpdated = 'onawardupdated', + onCollectionUpdated = 'oncollectionupdated', + onTokenStatusUpdated = 'ontokenstatusupdated', + onTokenTradeOrderWrite = 'ontokentradeorderwrite', + onTokenPurchaseCreated = 'ontokenpurchasecreated', + onMilestoneTransactionWrite = 'onmilestonetransactionwrite', + onNftWrite = 'onnftwrite', + onTransactionWrite = 'ontransactionwrite', + onMnemonicUpdated = 'onmnemonicupdated', + onCollectionStatsWrite = 'oncollectionstatswrite', + algolia = 'algolia', +} + +export enum WEN_STORAGE_TRIGGER { + onUploadFinalized = 'onuploadfinalized', +} + +export enum WEN_SCHEDULED { + retryWallet = 'retrywallet', + processExpiredAwards = 'processexpiredawards', + voidExpiredOrders = 'voidexpiredorders', + finalizeAuctionNft = 'finalizeauctionnft', + hidePlaceholderAfterSoldOut = 'hideplaceholderaftersoldout', + tokenCoolDownOver = 'tokencooldownover', + cancelExpiredSale = 'cancelexpiredsale', + removeExpiredStakesFromSpace = 'removeexpiredstakesfromspace', + getLatestBitfinexPrices = 'getlatestbitfinexprices', + stakeReward = 'stakereward', + mediaUpload = 'mediaupload', + removeExpiredNftStakes = 'removeexpirednftstakes', + updateFloorPriceOnCollections = 'updatefloorpriceoncollections', + markExpiredProposalCompleted = 'markexpiredproposalcompleted', + removePurchasesFromVolumeStats = 'removepurchasesfromvolumestats', +} + +export interface RuntimeOptions { + timeoutSeconds?: number; + concurrency?: number; + memory?: string; + minInstances?: number; + cpu?: number; + region?: string; + bucket?: string; +} + +export const pathToParts = (document: string) => { + const parts = document.split('/'); + return { + col: parts[0] as COL, + docId: parts[1] as string, + subCol: parts[2] as SUB_COL, + subDocId: parts[3] as string, + }; +}; + +export abstract class CloudFunctions { + constructor(public readonly runtimeOptions: RuntimeOptions) {} +} diff --git a/packages/functions/src/runtime/cron/index.ts b/packages/functions/src/runtime/cron/index.ts new file mode 100644 index 0000000000..499d554392 --- /dev/null +++ b/packages/functions/src/runtime/cron/index.ts @@ -0,0 +1,93 @@ +import { processExpiredAwards } from '../../cron/award.cron'; +import { getLatestBitfinexPricesCron } from '../../cron/bitfinex.cron'; +import { updateFloorPriceOnCollections } from '../../cron/collection.floor.price.cron'; +import { uploadMediaToWeb3 } from '../../cron/media.cron'; +import { finalizeAllNftAuctions, hidePlaceholderAfterSoldOutCron } from '../../cron/nft.cron'; +import { voidExpiredOrdersCron } from '../../cron/orders.cron'; +import { markExpiredProposalCompleted } from '../../cron/proposal.cron'; +import { removeExpiredStakesFromSpace } from '../../cron/stake.cron'; +import { stakeRewardCronTask } from '../../cron/stakeReward.cron'; +import { cancelExpiredSale, tokenCoolDownOver } from '../../cron/token.cron'; +import { removePurchasesFromVolumeStats } from '../../cron/token.purchase.cron'; +import { retryWallet } from '../../cron/wallet.cron'; +import { CRON_TRIGGER_SCALE } from '../../scale.settings'; +import { WEN_SCHEDULED } from '../common'; +import { onSchedule } from './scheduled'; + +exports[WEN_SCHEDULED.retryWallet] = onSchedule({ + schedule: 'every 2 minutes', + handler: retryWallet, +}); + +exports[WEN_SCHEDULED.processExpiredAwards] = onSchedule({ + schedule: 'every 1 minutes', + handler: processExpiredAwards, +}); + +exports[WEN_SCHEDULED.voidExpiredOrders] = onSchedule({ + schedule: 'every 1 minutes', + handler: voidExpiredOrdersCron, +}); + +exports[WEN_SCHEDULED.finalizeAuctionNft] = onSchedule({ + schedule: 'every 1 minutes', + handler: finalizeAllNftAuctions, +}); + +exports[WEN_SCHEDULED.hidePlaceholderAfterSoldOut] = onSchedule({ + schedule: 'every 5 minutes', + handler: hidePlaceholderAfterSoldOutCron, +}); + +exports[WEN_SCHEDULED.tokenCoolDownOver] = onSchedule({ + schedule: 'every 1 minutes', + handler: tokenCoolDownOver, +}); + +exports[WEN_SCHEDULED.cancelExpiredSale] = onSchedule({ + schedule: 'every 1 minutes', + handler: cancelExpiredSale, +}); + +exports[WEN_SCHEDULED.removeExpiredStakesFromSpace] = onSchedule({ + schedule: 'every 1 minutes', + handler: removeExpiredStakesFromSpace, +}); + +exports[WEN_SCHEDULED.getLatestBitfinexPrices] = onSchedule({ + schedule: 'every 5 minutes', + handler: getLatestBitfinexPricesCron, +}); + +exports[WEN_SCHEDULED.stakeReward] = onSchedule({ + runtimeOptions: CRON_TRIGGER_SCALE[WEN_SCHEDULED.stakeReward], + schedule: 'every 1 hours', + handler: stakeRewardCronTask, +}); + +exports[WEN_SCHEDULED.mediaUpload] = onSchedule({ + runtimeOptions: CRON_TRIGGER_SCALE[WEN_SCHEDULED.mediaUpload], + schedule: 'every 1 minutes', + handler: uploadMediaToWeb3, +}); + +exports[WEN_SCHEDULED.removeExpiredNftStakes] = onSchedule({ + schedule: 'every 1 minutes', + handler: removeExpiredStakesFromSpace, +}); + +exports[WEN_SCHEDULED.updateFloorPriceOnCollections] = onSchedule({ + runtimeOptions: CRON_TRIGGER_SCALE[WEN_SCHEDULED.updateFloorPriceOnCollections], + schedule: 'every 5 minutes', + handler: updateFloorPriceOnCollections, +}); + +exports[WEN_SCHEDULED.markExpiredProposalCompleted] = onSchedule({ + schedule: 'every 5 minutes', + handler: markExpiredProposalCompleted, +}); + +exports[WEN_SCHEDULED.removePurchasesFromVolumeStats] = onSchedule({ + schedule: 'every 1 minutes', + handler: removePurchasesFromVolumeStats, +}); diff --git a/packages/functions/src/runtime/cron/scheduled.ts b/packages/functions/src/runtime/cron/scheduled.ts new file mode 100644 index 0000000000..e37616d27e --- /dev/null +++ b/packages/functions/src/runtime/cron/scheduled.ts @@ -0,0 +1,20 @@ +import { CloudFunctions, RuntimeOptions } from '../common'; + +export class ScheduledFunction extends CloudFunctions { + constructor( + public readonly schedule: string, + public readonly func: () => Promise, + options?: RuntimeOptions, + ) { + super({ + region: 'us-central1', + ...options, + }); + } +} + +export const onSchedule = (params: { + schedule: string; + runtimeOptions?: RuntimeOptions; + handler: () => Promise; +}) => new ScheduledFunction(params.schedule, params.handler, params.runtimeOptions); diff --git a/packages/functions/src/runtime/firebase/address/index.ts b/packages/functions/src/runtime/firebase/address/index.ts index 5626972786..71b1832c5d 100644 --- a/packages/functions/src/runtime/firebase/address/index.ts +++ b/packages/functions/src/runtime/firebase/address/index.ts @@ -1,9 +1,4 @@ import { WEN_FUNC } from '@build-5/interfaces'; -import { validateAddressControl } from '../../../controls/address.control'; -import { onRequest } from '../../../firebase/functions/onRequest'; -import { validateAddressSchemaObject } from './AddressValidationRequestSchema'; +import { https } from '../../..'; -export const validateAddress = onRequest(WEN_FUNC.validateAddress)( - validateAddressSchemaObject, - validateAddressControl, -); +export const validateAddress = https[WEN_FUNC.validateAddress]; diff --git a/packages/functions/src/runtime/firebase/auth/index.ts b/packages/functions/src/runtime/firebase/auth/index.ts index 11056b724e..f931291c29 100644 --- a/packages/functions/src/runtime/firebase/auth/index.ts +++ b/packages/functions/src/runtime/firebase/auth/index.ts @@ -1,8 +1,4 @@ import { WEN_FUNC } from '@build-5/interfaces'; -import { generateCustomTokenControl } from '../../../controls/auth.control'; -import { onRequest } from '../../../firebase/functions/onRequest'; -import { customTokenSchema } from './CutomTokenRequestSchema'; +import { https } from '../../..'; -export const generateCustomToken = onRequest(WEN_FUNC.generateCustomToken, undefined, { - allowUnknown: true, -})(customTokenSchema, generateCustomTokenControl); +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 index 8e0ee87dda..95f2197719 100644 --- a/packages/functions/src/runtime/firebase/award/index.ts +++ b/packages/functions/src/runtime/firebase/award/index.ts @@ -1,39 +1,10 @@ import { WEN_FUNC } from '@build-5/interfaces'; -import { approveAwardParticipantControl } from '../../../controls/award/award.approve.participant'; -import { cancelAwardControl } from '../../../controls/award/award.cancel'; -import { createAwardControl } from '../../../controls/award/award.create'; -import { fundAwardControl } from '../../../controls/award/award.fund'; -import { addOwnerControl } from '../../../controls/award/award.owner'; -import { awardParticipateControl } from '../../../controls/award/award.participate'; -import { rejectAwardControl } from '../../../controls/award/award.reject'; -import { onRequest } from '../../../firebase/functions/onRequest'; -import { addOwnerSchema } from './AwardAddOwnerRequestSchema'; -import { approveAwardParticipantSchemaObject } from './AwardApproveParticipantRequestSchema'; -import { awardCancelSchema } from './AwardCancelRequestSchema'; -import { awardCreateSchemaObject } from './AwardCreateRequestSchema'; -import { awardFundSchema } from './AwardFundRequestSchema'; -import { awardParticipateSchema } from './AwardParticipateRequestSchema'; -import { awardRejectSchema } from './AwardRejectRequestSchema'; - -export const createAward = onRequest(WEN_FUNC.createAward)( - awardCreateSchemaObject, - createAwardControl, -); - -export const addOwnerAward = onRequest(WEN_FUNC.addOwnerAward)(addOwnerSchema, addOwnerControl); - -export const fundAward = onRequest(WEN_FUNC.fundAward)(awardFundSchema, fundAwardControl); - -export const rejectAward = onRequest(WEN_FUNC.rejectAward)(awardRejectSchema, rejectAwardControl); - -export const cancelAward = onRequest(WEN_FUNC.cancelAward)(awardCancelSchema, cancelAwardControl); - -export const awardParticipate = onRequest(WEN_FUNC.participateAward)( - awardParticipateSchema, - awardParticipateControl, -); - -export const approveAwardParticipant = onRequest(WEN_FUNC.approveParticipantAward, { - timeoutSeconds: 540, - memory: '4GiB', -})(approveAwardParticipantSchemaObject, approveAwardParticipantControl); +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 index d55f7d043d..54cbf9eb0c 100644 --- a/packages/functions/src/runtime/firebase/collection/index.ts +++ b/packages/functions/src/runtime/firebase/collection/index.ts @@ -1,38 +1,8 @@ import { WEN_FUNC } from '@build-5/interfaces'; -import { mintCollectionOrderControl } from '../../../controls/collection/collection-mint.control'; -import { approveCollectionControl } from '../../../controls/collection/collection.approve.control'; -import { createCollectionControl } from '../../../controls/collection/collection.create.control'; -import { rejectCollectionControl } from '../../../controls/collection/collection.reject.control'; -import { updateCollectionControl } from '../../../controls/collection/collection.update.control'; -import { onRequest } from '../../../firebase/functions/onRequest'; -import { CommonJoi, toJoiObject } from '../../../services/joi/common'; -import { UidSchemaObject } from '../common'; -import { approveCollectionSchema } from './CollectionApproveRequestSchema'; -import { createCollectionSchema } from './CollectionCreateRequestSchema'; -import { mintCollectionSchema } from './CollectionMintRequestSchema'; -import { rejectCollectionSchema } from './CollectionRejectRequestSchema'; +import { https } from '../../..'; -export const createCollection = onRequest(WEN_FUNC.createCollection)( - createCollectionSchema, - createCollectionControl, -); - -export const updateCollection = onRequest(WEN_FUNC.updateCollection)( - toJoiObject({ uid: CommonJoi.uid() }), - updateCollectionControl, - true, -); - -export const approveCollection = onRequest(WEN_FUNC.approveCollection)( - approveCollectionSchema, - approveCollectionControl, -); -export const rejectCollection = onRequest(WEN_FUNC.rejectCollection)( - rejectCollectionSchema, - rejectCollectionControl, -); - -export const mintCollection = onRequest(WEN_FUNC.mintCollection, { - memory: '8GiB', - timeoutSeconds: 540, -})(mintCollectionSchema, mintCollectionOrderControl); +export const createCollection = https[WEN_FUNC.createCollection]; +export const updateCollection = https[WEN_FUNC.updateCollection]; +export const approveCollection = https[WEN_FUNC.approveCollection]; +export const rejectCollection = https[WEN_FUNC.rejectCollection]; +export const mintCollection = https[WEN_FUNC.mintCollection]; diff --git a/packages/functions/src/runtime/firebase/common.ts b/packages/functions/src/runtime/firebase/common.ts deleted file mode 100644 index 75caf62581..0000000000 --- a/packages/functions/src/runtime/firebase/common.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { EthAddress } from '@build-5/interfaces'; -import { CommonJoi } from '../../services/joi/common'; - -export interface UidSchemaObject { - uid: EthAddress; -} -export const uidSchema = { uid: CommonJoi.uid() }; diff --git a/packages/functions/src/runtime/firebase/credit/index.ts b/packages/functions/src/runtime/firebase/credit/index.ts index c6bd343719..959dfd69e5 100644 --- a/packages/functions/src/runtime/firebase/credit/index.ts +++ b/packages/functions/src/runtime/firebase/credit/index.ts @@ -1,9 +1,4 @@ import { WEN_FUNC } from '@build-5/interfaces'; -import { creditUnrefundableControl } from '../../../controls/credit/credit.controller'; -import { onRequest } from '../../../firebase/functions/onRequest'; -import { creditUnrefundableSchema } from './CreditUnrefundableRequestSchema'; +import { https } from '../../..'; -export const creditUnrefundable = onRequest(WEN_FUNC.creditUnrefundable)( - creditUnrefundableSchema, - creditUnrefundableControl, -); +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 index 37e1d86e95..a4be6082ea 100644 --- a/packages/functions/src/runtime/firebase/member/index.ts +++ b/packages/functions/src/runtime/firebase/member/index.ts @@ -1,29 +1,5 @@ -import { WEN_FUNC, WenError } from '@build-5/interfaces'; -import cors from 'cors'; -import * as functions from 'firebase-functions/v2'; -import { createMemberControl } from '../../../controls/member/member.create'; -import { updateMemberControl } from '../../../controls/member/member.update'; -import { onRequest, onRequestConfig } from '../../../firebase/functions/onRequest'; -import { assertValidationAsync } from '../../../utils/schema.utils'; -import { createMemberSchema } from './CreateMemberRequestSchema'; -import { updateMemberSchema } from './UpdateMemberRequestSchema'; +import { WEN_FUNC } from '@build-5/interfaces'; +import { https } from '../../..'; -export const createMember = functions.https.onRequest( - onRequestConfig(WEN_FUNC.createMember), - (req, res) => - cors({ origin: true })(req, res, async () => { - try { - const address = req.body.data; - await assertValidationAsync(createMemberSchema, { address }); - res.send({ data: await createMemberControl(address) }); - } catch { - res.status(401); - res.send({ data: WenError.address_must_be_provided }); - } - }), -); - -export const updateMember = onRequest(WEN_FUNC.updateMember)( - updateMemberSchema, - updateMemberControl, -); +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 index 089b354ca5..6802e440cf 100644 --- a/packages/functions/src/runtime/firebase/nft/index.ts +++ b/packages/functions/src/runtime/firebase/nft/index.ts @@ -1,49 +1,19 @@ -import { NftCreateRequest, WEN_FUNC } from '@build-5/interfaces'; -import Joi from 'joi'; -import { nftBidControl } from '../../../controls/nft/nft.bid.control'; -import { createBatchNftControl, createNftControl } from '../../../controls/nft/nft.create'; -import { depositNftControl } from '../../../controls/nft/nft.deposit'; -import { orderNftControl } from '../../../controls/nft/nft.puchase.control'; -import { setForSaleNftControl } from '../../../controls/nft/nft.set.for.sale'; -import { nftStakeControl } from '../../../controls/nft/nft.stake'; -import { updateUnsoldNftControl } from '../../../controls/nft/nft.update.unsold'; -import { withdrawNftControl } from '../../../controls/nft/nft.withdraw'; -import { onRequest } from '../../../firebase/functions/onRequest'; -import { nftBidSchema } from './NftBidRequestSchema'; -import { createSchema, nftCreateSchema } from './NftCreateRequestSchema'; -import { depositNftSchema } from './NftDepositRequestSchema'; -import { nftPurchaseSchema } from './NftPurchaseRequestSchema'; -import { setNftForSaleSchema } from './NftSetForSaleRequestSchema'; -import { stakeNftSchema } from './NftStakeRequestSchema'; -import { updateUnsoldNftSchema } from './NftUpdateUnsoldRequestSchema'; -import { nftWithdrawSchema } from './NftWithdrawRequestSchema'; - -export const createNft = onRequest(WEN_FUNC.createNft)(nftCreateSchema, createNftControl); - -export const createBatchNft = onRequest(WEN_FUNC.createBatchNft, { - timeoutSeconds: 300, - memory: '4GiB', -})( - Joi.array().items(Joi.object().keys(createSchema)).min(1).max(500), - createBatchNftControl, -); - -export const updateUnsoldNft = onRequest(WEN_FUNC.updateUnsoldNft)( - updateUnsoldNftSchema, - updateUnsoldNftControl, -); - -export const setForSaleNft = onRequest(WEN_FUNC.setForSaleNft)( - setNftForSaleSchema, - setForSaleNftControl, -); - -export const withdrawNft = onRequest(WEN_FUNC.withdrawNft)(nftWithdrawSchema, withdrawNftControl); - -export const depositNft = onRequest(WEN_FUNC.depositNft)(depositNftSchema, depositNftControl); - -export const orderNft = onRequest(WEN_FUNC.orderNft)(nftPurchaseSchema, orderNftControl); - -export const stakeNft = onRequest(WEN_FUNC.stakeNft)(stakeNftSchema, nftStakeControl); - -export const openBid = onRequest(WEN_FUNC.openBid)(nftBidSchema, nftBidControl); +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 stakeNft = https[WEN_FUNC.stakeNft]; + +export const openBid = https[WEN_FUNC.openBid]; diff --git a/packages/functions/src/runtime/firebase/proposal/index.ts b/packages/functions/src/runtime/firebase/proposal/index.ts index 75129796ca..e50d70f617 100644 --- a/packages/functions/src/runtime/firebase/proposal/index.ts +++ b/packages/functions/src/runtime/firebase/proposal/index.ts @@ -1,29 +1,7 @@ import { WEN_FUNC } from '@build-5/interfaces'; -import { proposalApprovalControl } from '../../../controls/proposal/approve.reject.proposal'; -import { createProposalControl } from '../../../controls/proposal/create.proposal'; -import { voteOnProposalControl } from '../../../controls/proposal/vote.on.proposal'; -import { onRequest } from '../../../firebase/functions/onRequest'; -import { approveProposaSchema } from './ProposalApproveRequestSchema'; -import { proposalCreateSchemaObject } from './ProposalCreateRequestSchema'; -import { rejectProposaSchema } from './ProposalRejectRequestSchema'; -import { voteOnProposalSchemaObject } from './ProposalVoteRequestSchema'; +import { https } from '../../..'; -export const createProposal = onRequest(WEN_FUNC.createProposal, { - timeoutSeconds: 300, - memory: '2GiB', -})(proposalCreateSchemaObject, createProposalControl); - -export const approveProposal = onRequest(WEN_FUNC.approveProposal)( - approveProposaSchema, - proposalApprovalControl(true), -); - -export const rejectProposal = onRequest(WEN_FUNC.rejectProposal)( - rejectProposaSchema, - proposalApprovalControl(false), -); - -export const voteOnProposal = onRequest(WEN_FUNC.voteOnProposal)( - voteOnProposalSchemaObject, - voteOnProposalControl, -); +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 index 6d7209be83..3126101bd0 100644 --- a/packages/functions/src/runtime/firebase/rank/index.ts +++ b/packages/functions/src/runtime/firebase/rank/index.ts @@ -1,6 +1,4 @@ import { WEN_FUNC } from '@build-5/interfaces'; -import { rankControl } from '../../../controls/rank.control'; -import { onRequest } from '../../../firebase/functions/onRequest'; -import { rankSchema } from './RankRequestSchema'; +import { https } from '../../..'; -export const rankController = onRequest(WEN_FUNC.rankController)(rankSchema, rankControl); +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 index 17f0834584..3c91c0a176 100644 --- a/packages/functions/src/runtime/firebase/space/index.ts +++ b/packages/functions/src/runtime/firebase/space/index.ts @@ -1,61 +1,22 @@ -import { ProposalType, WEN_FUNC } from '@build-5/interfaces'; -import { acceptSpaceMemberControl } from '../../../controls/space/member.accept.control'; -import { blockMemberControl } from '../../../controls/space/member.block.control'; -import { declineMemberControl } from '../../../controls/space/member.decline.control'; -import { leaveSpaceControl } from '../../../controls/space/member.leave.control'; -import { unblockMemberControl } from '../../../controls/space/member.unblock.control'; -import { claimSpaceControl } from '../../../controls/space/space.claim.control'; -import { createSpaceControl } from '../../../controls/space/space.create.control'; -import { editGuardianControl } from '../../../controls/space/space.guardian.edit.control'; -import { joinSpaceControl } from '../../../controls/space/space.join.control'; -import { updateSpaceControl } from '../../../controls/space/space.update.control'; -import { onRequest } from '../../../firebase/functions/onRequest'; -import { spaceClaimSchema } from './SpaceClaimRequestSchema'; -import { createSpaceSchemaObject } from './SpaceCreateRequestSchema'; -import { editSpaceMemberSchemaObject } from './SpaceEditMemberRequestSchema'; -import { spaceJoinSchema } from './SpaceJoinRequestSchema'; -import { spaceLeaveSchema } from './SpaceLeaveRequestSchema'; -import { updateSpaceSchema } from './SpaceUpdateRequestSchema'; - -export const createSpace = onRequest(WEN_FUNC.createSpace)( - createSpaceSchemaObject, - createSpaceControl, -); - -export const addGuardian = onRequest(WEN_FUNC.addGuardianSpace)( - editSpaceMemberSchemaObject, - editGuardianControl(ProposalType.ADD_GUARDIAN), -); - -export const removeGuardian = onRequest(WEN_FUNC.removeGuardianSpace)( - editSpaceMemberSchemaObject, - editGuardianControl(ProposalType.REMOVE_GUARDIAN), -); - -export const acceptMemberSpace = onRequest(WEN_FUNC.acceptMemberSpace)( - editSpaceMemberSchemaObject, - acceptSpaceMemberControl, -); - -export const blockMember = onRequest(WEN_FUNC.blockMemberSpace)( - editSpaceMemberSchemaObject, - blockMemberControl, -); - -export const declineMemberSpace = onRequest(WEN_FUNC.declineMemberSpace)( - editSpaceMemberSchemaObject, - declineMemberControl, -); - -export const unblockMember = onRequest(WEN_FUNC.unblockMemberSpace)( - editSpaceMemberSchemaObject, - unblockMemberControl, -); - -export const updateSpace = onRequest(WEN_FUNC.updateSpace)(updateSpaceSchema, updateSpaceControl); - -export const leaveSpace = onRequest(WEN_FUNC.leaveSpace)(spaceLeaveSchema, leaveSpaceControl); - -export const joinSpace = onRequest(WEN_FUNC.claimSpace)(spaceJoinSchema, joinSpaceControl); - -export const claimSpace = onRequest(WEN_FUNC.claimSpace)(spaceClaimSchema, claimSpaceControl); +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 index 765b122f0c..392f7096e4 100644 --- a/packages/functions/src/runtime/firebase/stake/index.ts +++ b/packages/functions/src/runtime/firebase/stake/index.ts @@ -1,20 +1,6 @@ import { WEN_FUNC } from '@build-5/interfaces'; -import { depositStakeControl } from '../../../controls/stake/stake.deposit'; -import { stakeRewardControl } from '../../../controls/stake/stake.reward'; -import { removeStakeRewardControl } from '../../../controls/stake/stake.reward.revoke'; -import { onRequest } from '../../../firebase/functions/onRequest'; -import { removeStakeRewardSchema } from './StakeRewardRemoveRequestSchema'; -import { stakeRewardsSchema } from './StakeRewardRequestSchema'; -import { depositStakeSchemaObject } from './StakeTokenRequestSchema'; +import { https } from '../../..'; -export const depositStake = onRequest(WEN_FUNC.depositStake)( - depositStakeSchemaObject, - depositStakeControl, -); - -export const stakeReward = onRequest(WEN_FUNC.stakeReward)(stakeRewardsSchema, stakeRewardControl); - -export const removeStakeReward = onRequest(WEN_FUNC.removeStakeReward)( - removeStakeRewardSchema, - removeStakeRewardControl, -); +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/storage/file.upload.ts b/packages/functions/src/runtime/firebase/storage/file.upload.ts index 404d025a3d..2660d6f4c6 100644 --- a/packages/functions/src/runtime/firebase/storage/file.upload.ts +++ b/packages/functions/src/runtime/firebase/storage/file.upload.ts @@ -1,100 +1,4 @@ -import { Bucket, WEN_FUNC, WenError, generateRandomFileName } from '@build-5/interfaces'; -import busboy from 'busboy'; -import cors from 'cors'; -import express from 'express'; -import * as functions from 'firebase-functions/v2'; -import fs from 'fs'; -import mime from 'mime-types'; -import os from 'os'; -import path from 'path'; -import { onRequestConfig } from '../../../firebase/functions/onRequest'; -import { build5Storage } from '../../../firebase/storage/build5Storage'; -import { getBucket } from '../../../utils/config.utils'; -import { getRandomEthAddress } from '../../../utils/wallet.utils'; -import { fileUploadSchema } from './FileUploadRequestSchema'; +import { WEN_FUNC } from '@build-5/interfaces'; +import { https } from '../../..'; -const MAX_FILE_SIZE_BYTES = 104857600; // 100 MB - -export const uploadFile = functions.https.onRequest( - onRequestConfig(WEN_FUNC.uploadFile, { memory: '512MiB' }), - (req, res) => - cors({ origin: true })(req, res, async () => { - if (req.method !== 'POST') { - sendBadRequest(res); - return; - } - uploadFileControl(req, res); - }), -); - -export const uploadFileControl = (req: functions.https.Request, res: express.Response) => { - const workdir = `${os.tmpdir()}/${getRandomEthAddress()}`; - const bb = busboy({ headers: req.headers, limits: { fileSize: MAX_FILE_SIZE_BYTES } }); - const params: Record = {}; - - bb.on('file', (_, file, info) => { - if (params.filePath) { - file.resume(); - return; - } - - fs.mkdirSync(workdir); - const { filename, mimeType } = info; - const filepath = path.join(workdir, filename); - const writeStream = fs.createWriteStream(filepath); - file.pipe(writeStream); - - params.filePath = filepath; - params.mimeType = mimeType; - params.ext = mime.extension(mimeType); - params.file = file; - }); - - bb.on('field', (name, val) => { - params[name] = val; - }); - - bb.on('finish', async () => { - if (!params.filePath) { - sendBadRequest(res); - return; - } - - const { member, uid, ext, mimeType } = params; - const areParamsCorrect = assertParams({ member, uid, mimeType }, res); - if (!areParamsCorrect) { - return; - } - - const destination = `${member}/${uid}/${generateRandomFileName()}.${ext}`; - const bucketName = getBucket(); - const bucket = build5Storage().bucket(bucketName); - const dowloadUrl = await bucket.upload(params.filePath as string, destination, {}); - - fs.rmSync(workdir, { recursive: true, force: true }); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (params.file as any).resume(); - - const idDevBucket = bucketName === Bucket.DEV; - const url = idDevBucket ? dowloadUrl : `https://${bucket.getName()}/${destination}`; - res.status(200); - res.send({ url }); - }); - - bb.end(req.rawBody); -}; - -const sendBadRequest = (res: express.Response) => { - res.status(400); - res.send({ data: WenError.invalid_params }); -}; - -const assertParams = (params: Record, res: express.Response) => { - const joiResult = fileUploadSchema.validate(params); - if (joiResult.error) { - res.status(400); - res.send(joiResult.error.details.map((d) => d.message)); - return false; - } - return true; -}; +export const uploadFile = https[WEN_FUNC.uploadFile]; diff --git a/packages/functions/src/runtime/firebase/token/base/common.ts b/packages/functions/src/runtime/firebase/token/base/common.ts deleted file mode 100644 index 06678fcf76..0000000000 --- a/packages/functions/src/runtime/firebase/token/base/common.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { MAX_IOTA_AMOUNT, MAX_TOTAL_TOKEN_SUPPLY } from '@build-5/interfaces'; - -export const MAX_PRICE = MAX_IOTA_AMOUNT; - -export const MIN_AIRDROP = 1; - -export const MIN_COUNT = 1; -export const MAX_COUNT = MAX_TOTAL_TOKEN_SUPPLY; diff --git a/packages/functions/src/runtime/firebase/token/base/index.ts b/packages/functions/src/runtime/firebase/token/base/index.ts index c4b83c9fa4..2c34bd0a52 100644 --- a/packages/functions/src/runtime/firebase/token/base/index.ts +++ b/packages/functions/src/runtime/firebase/token/base/index.ts @@ -1,58 +1,20 @@ import { WEN_FUNC } from '@build-5/interfaces'; -import { airdropTokenControl } from '../../../../controls/token/token.airdrop'; -import { claimAirdroppedTokenControl } from '../../../../controls/token/token.airdrop.claim'; -import { cancelPublicSaleControl } from '../../../../controls/token/token.cancel.pub.sale'; -import { createTokenControl } from '../../../../controls/token/token.create'; -import { creditTokenControl } from '../../../../controls/token/token.credit'; -import { enableTokenTradingControl } from '../../../../controls/token/token.enable.trading'; -import { orderTokenControl } from '../../../../controls/token/token.order'; -import { setTokenAvailableForSaleControl } from '../../../../controls/token/token.set.for.sale'; -import { updateTokenControl } from '../../../../controls/token/token.update'; -import { onRequest } from '../../../../firebase/functions/onRequest'; -import { toJoiObject } from '../../../../services/joi/common'; -import { UidSchemaObject, uidSchema } from '../../common'; -import { airdropTokenSchema } from './TokenAirdropRequestSchema'; -import { cancelPubSaleSchema } from './TokenCancelPubSaleRequestSchema'; -import { claimAirdroppedTokenSchema } from './TokenClaimAirdroppedRequestSchema'; -import { createTokenSchema } from './TokenCreateRequestSchema'; -import { creditTokenSchema } from './TokenCreditRequestSchema'; -import { enableTradingSchema } from './TokenEnableTradingRequestSchema'; -import { orderTokenSchema } from './TokenOrderRequestSchema'; -import { setAvailableForSaleSchema } from './TokenSetAvailableForSaleRequestSchema'; - -export const createToken = onRequest(WEN_FUNC.createToken)(createTokenSchema, createTokenControl); - -export const updateToken = onRequest(WEN_FUNC.updateToken)( - toJoiObject(uidSchema), - updateTokenControl, - true, -); - -export const setTokenAvailableForSale = onRequest(WEN_FUNC.setTokenAvailableForSale)( - setAvailableForSaleSchema, - setTokenAvailableForSaleControl, -); - -export const cancelPublicSale = onRequest(WEN_FUNC.cancelPublicSale)( - cancelPubSaleSchema, - cancelPublicSaleControl, -); - -export const creditToken = onRequest(WEN_FUNC.creditToken)(creditTokenSchema, creditTokenControl); - -export const orderToken = onRequest(WEN_FUNC.orderToken)(orderTokenSchema, orderTokenControl); - -export const enableTokenTrading = onRequest(WEN_FUNC.enableTokenTrading)( - enableTradingSchema, - enableTokenTradingControl, -); - -export const airdropToken = onRequest(WEN_FUNC.airdropToken)( - airdropTokenSchema, - airdropTokenControl, -); - -export const claimAirdroppedToken = onRequest(WEN_FUNC.claimAirdroppedToken)( - claimAirdroppedTokenSchema, - claimAirdroppedTokenControl, -); +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 index bc3ccc93e8..80c79c1423 100644 --- a/packages/functions/src/runtime/firebase/token/minting/index.ts +++ b/packages/functions/src/runtime/firebase/token/minting/index.ts @@ -1,27 +1,10 @@ import { WEN_FUNC } from '@build-5/interfaces'; -import { airdropMintedTokenControl } from '../../../../controls/token-minting/airdrop-minted-token'; -import { claimMintedTokenControl } from '../../../../controls/token-minting/claim-minted-token.control'; -import { importMintedTokenControl } from '../../../../controls/token-minting/import-minted-token'; -import { mintTokenControl } from '../../../../controls/token-minting/token-mint.control'; -import { onRequest } from '../../../../firebase/functions/onRequest'; -import { airdropTokenSchema } from '../base/TokenAirdropRequestSchema'; -import { symbolSchema } from './TokenClaimMintedRequestSchema'; -import { importMintedTokenSchema } from './TokenImportRequestSchema'; -import { mintTokenSchema } from './TokenMintRequestSchema'; +import { https } from '../../../..'; -export const airdropMintedToken = onRequest(WEN_FUNC.airdropMintedToken)( - airdropTokenSchema, - airdropMintedTokenControl, -); +export const airdropMintedToken = https[WEN_FUNC.airdropMintedToken]; -export const claimMintedTokenOrder = onRequest(WEN_FUNC.claimMintedTokenOrder)( - symbolSchema, - claimMintedTokenControl, -); +export const claimMintedTokenOrder = https[WEN_FUNC.claimMintedTokenOrder]; -export const mintTokenOrder = onRequest(WEN_FUNC.mintTokenOrder)(mintTokenSchema, mintTokenControl); +export const mintTokenOrder = https[WEN_FUNC.mintTokenOrder]; -export const importMintedToken = onRequest(WEN_FUNC.importMintedToken)( - importMintedTokenSchema, - importMintedTokenControl, -); +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 index 98bed47807..e76d6b8d32 100644 --- a/packages/functions/src/runtime/firebase/token/trading/index.ts +++ b/packages/functions/src/runtime/firebase/token/trading/index.ts @@ -1,16 +1,5 @@ import { WEN_FUNC } from '@build-5/interfaces'; -import { cancelTradeOrderControl } from '../../../../controls/token-trading/token-trade-cancel.controller'; -import { tradeTokenControl } from '../../../../controls/token-trading/token-trade.controller'; -import { onRequest } from '../../../../firebase/functions/onRequest'; -import { cancelTradeOrderSchema } from './TokenCanelTradeOrderRequestSchema'; -import { tradeTokenSchema } from './TokenTradeRequestSchema'; +import { https } from '../../../..'; -export const cancelTradeOrder = onRequest(WEN_FUNC.cancelTradeOrder)( - cancelTradeOrderSchema, - cancelTradeOrderControl, -); - -export const tradeToken = onRequest(WEN_FUNC.tradeToken, undefined, { convert: false })( - tradeTokenSchema, - tradeTokenControl, -); +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 index fd1478b35a..e5796b8fb1 100644 --- a/packages/functions/src/runtime/firebase/vote/index.ts +++ b/packages/functions/src/runtime/firebase/vote/index.ts @@ -1,6 +1,4 @@ import { WEN_FUNC } from '@build-5/interfaces'; -import { voteControl } from '../../../controls/vote.control'; -import { onRequest } from '../../../firebase/functions/onRequest'; -import { voteSchema } from './VoteRequestSchema'; +import { https } from '../../..'; -export const voteController = onRequest(WEN_FUNC.voteController)(voteSchema, voteControl); +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 new file mode 100644 index 0000000000..8e50c81774 --- /dev/null +++ b/packages/functions/src/runtime/https/https.ts @@ -0,0 +1,56 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { WEN_FUNC } from '@build-5/interfaces'; +import express from 'express'; +import { AnySchema, ValidationOptions } from 'joi'; +import { get } from 'lodash'; +import { Context } from '../../controls/common'; +import { WEN_FUNC_SCALE } from '../../scale.settings'; +import { CloudFunctions, RuntimeOptions } from '../common'; +import { auth } from './middlewares'; + +type HandlerType = (req: express.Request, res: express.Response) => Promise; + +type MiddlewareType = ( + req: express.Request, + func: WEN_FUNC, + schema: AnySchema, + options?: ValidationOptions, +) => Promise>; + +export class HttpsFunction extends CloudFunctions { + constructor(public readonly func: HandlerType, options: RuntimeOptions) { + super(options); + } +} + +export const onRequest = ({ + name, + schema, + schemaOptions, + middleware, + handler, +}: { + name: WEN_FUNC; + schema: AnySchema; + schemaOptions?: ValidationOptions; + middleware?: MiddlewareType; + handler: (context: Context) => Promise; +}) => { + const func = async (req: express.Request, res: express.Response): Promise => { + try { + const context = await (middleware || auth)(req, name, schema, schemaOptions); + const result = await handler(context); + res.send({ data: result || {} }); + } catch (error) { + res.status(get(error, 'httpErrorCode.status', 400)); + res.send({ + data: { + code: get(error, 'details.code', 0), + key: get(error, 'details.key', ''), + message: get(error, 'message', ''), + }, + }); + } + }; + return new HttpsFunction(func, { region: 'us-central1', ...WEN_FUNC_SCALE[name] }); +}; diff --git a/packages/functions/src/runtime/https/index.ts b/packages/functions/src/runtime/https/index.ts new file mode 100644 index 0000000000..b0eef2cf4f --- /dev/null +++ b/packages/functions/src/runtime/https/index.ts @@ -0,0 +1,501 @@ +import { NftCreateRequest, ProposalType, WEN_FUNC } from '@build-5/interfaces'; +import Joi from 'joi'; +import { validateAddressSchemaObject } from '../../controls/address/AddressValidationRequestSchema'; +import { validateAddressControl } from '../../controls/address/address.control'; +import { customTokenSchema } from '../../controls/auth/CutomTokenRequestSchema'; +import { generateCustomTokenControl } from '../../controls/auth/auth.control'; +import { approveAwardParticipantSchemaObject } from '../../controls/award/AwardApproveParticipantRequestSchema'; +import { awardCancelSchema } from '../../controls/award/AwardCancelRequestSchema'; +import { awardCreateSchemaObject } from '../../controls/award/AwardCreateRequestSchema'; +import { awardFundSchema } from '../../controls/award/AwardFundRequestSchema'; +import { awardParticipateSchema } from '../../controls/award/AwardParticipateRequestSchema'; +import { awardRejectSchema } from '../../controls/award/AwardRejectRequestSchema'; +import { approveAwardParticipantControl } from '../../controls/award/award.approve.participant'; +import { cancelAwardControl } from '../../controls/award/award.cancel'; +import { createAwardControl } from '../../controls/award/award.create'; +import { fundAwardControl } from '../../controls/award/award.fund'; +import { awardParticipateControl } from '../../controls/award/award.participate'; +import { rejectAwardControl } from '../../controls/award/award.reject'; +import { approveCollectionSchema } from '../../controls/collection/CollectionApproveRequestSchema'; +import { createCollectionSchema } from '../../controls/collection/CollectionCreateRequestSchema'; +import { mintCollectionSchema } from '../../controls/collection/CollectionMintRequestSchema'; +import { rejectCollectionSchema } from '../../controls/collection/CollectionRejectRequestSchema'; +import { mintCollectionOrderControl } from '../../controls/collection/collection-mint.control'; +import { approveCollectionControl } from '../../controls/collection/collection.approve.control'; +import { createCollectionControl } from '../../controls/collection/collection.create.control'; +import { rejectCollectionControl } from '../../controls/collection/collection.reject.control'; +import { updateCollectionControl } from '../../controls/collection/collection.update.control'; +import { UidSchemaObject, uidSchema } from '../../controls/common'; +import { creditUnrefundableSchema } from '../../controls/credit/CreditUnrefundableRequestSchema'; +import { creditUnrefundableControl } from '../../controls/credit/credit.controller'; +import { uploadFileControl } from '../../controls/file/file.upload.control'; +import { updateMemberSchema } from '../../controls/member/UpdateMemberRequestSchema'; +import { createMemberControl } from '../../controls/member/member.create'; +import { updateMemberControl } from '../../controls/member/member.update'; +import { nftBidSchema } from '../../controls/nft/NftBidRequestSchema'; +import { createSchema, nftCreateSchema } from '../../controls/nft/NftCreateRequestSchema'; +import { depositNftSchema } from '../../controls/nft/NftDepositRequestSchema'; +import { nftPurchaseSchema } from '../../controls/nft/NftPurchaseRequestSchema'; +import { setNftForSaleSchema } from '../../controls/nft/NftSetForSaleRequestSchema'; +import { stakeNftSchema } from '../../controls/nft/NftStakeRequestSchema'; +import { updateUnsoldNftSchema } from '../../controls/nft/NftUpdateUnsoldRequestSchema'; +import { nftWithdrawSchema } from '../../controls/nft/NftWithdrawRequestSchema'; +import { nftBidControl } from '../../controls/nft/nft.bid.control'; +import { createBatchNftControl, createNftControl } from '../../controls/nft/nft.create'; +import { depositNftControl } from '../../controls/nft/nft.deposit'; +import { orderNftControl } from '../../controls/nft/nft.puchase.control'; +import { setForSaleNftControl } from '../../controls/nft/nft.set.for.sale'; +import { nftStakeControl } from '../../controls/nft/nft.stake'; +import { updateUnsoldNftControl } from '../../controls/nft/nft.update.unsold'; +import { withdrawNftControl } from '../../controls/nft/nft.withdraw'; +import { approveProposaSchema } from '../../controls/proposal/ProposalApproveRequestSchema'; +import { proposalCreateSchemaObject } from '../../controls/proposal/ProposalCreateRequestSchema'; +import { rejectProposaSchema } from '../../controls/proposal/ProposalRejectRequestSchema'; +import { voteOnProposalSchemaObject } from '../../controls/proposal/ProposalVoteRequestSchema'; +import { proposalApprovalControl } from '../../controls/proposal/approve.reject.proposal'; +import { createProposalControl } from '../../controls/proposal/create.proposal'; +import { voteOnProposalControl } from '../../controls/proposal/vote.on.proposal'; +import { rankSchema } from '../../controls/rank/RankRequestSchema'; +import { rankControl } from '../../controls/rank/rank.control'; +import { spaceClaimSchema } from '../../controls/space/SpaceClaimRequestSchema'; +import { createSpaceSchemaObject } from '../../controls/space/SpaceCreateRequestSchema'; +import { editSpaceMemberSchemaObject } from '../../controls/space/SpaceEditMemberRequestSchema'; +import { spaceJoinSchema } from '../../controls/space/SpaceJoinRequestSchema'; +import { spaceLeaveSchema } from '../../controls/space/SpaceLeaveRequestSchema'; +import { updateSpaceSchema } from '../../controls/space/SpaceUpdateRequestSchema'; +import { acceptSpaceMemberControl } from '../../controls/space/member.accept.control'; +import { blockMemberControl } from '../../controls/space/member.block.control'; +import { declineMemberControl } from '../../controls/space/member.decline.control'; +import { leaveSpaceControl } from '../../controls/space/member.leave.control'; +import { unblockMemberControl } from '../../controls/space/member.unblock.control'; +import { claimSpaceControl } from '../../controls/space/space.claim.control'; +import { createSpaceControl } from '../../controls/space/space.create.control'; +import { editGuardianControl } from '../../controls/space/space.guardian.edit.control'; +import { joinSpaceControl } from '../../controls/space/space.join.control'; +import { updateSpaceControl } from '../../controls/space/space.update.control'; +import { removeStakeRewardSchema } from '../../controls/stake/StakeRewardRemoveRequestSchema'; +import { stakeRewardsSchema } from '../../controls/stake/StakeRewardRequestSchema'; +import { depositStakeSchemaObject } from '../../controls/stake/StakeTokenRequestSchema'; +import { depositStakeControl } from '../../controls/stake/stake.deposit'; +import { stakeRewardControl } from '../../controls/stake/stake.reward'; +import { removeStakeRewardControl } from '../../controls/stake/stake.reward.revoke'; +import { symbolSchema } from '../../controls/token-minting/TokenClaimMintedRequestSchema'; +import { importMintedTokenSchema } from '../../controls/token-minting/TokenImportRequestSchema'; +import { mintTokenSchema } from '../../controls/token-minting/TokenMintRequestSchema'; +import { airdropMintedTokenControl } from '../../controls/token-minting/airdrop-minted-token'; +import { claimMintedTokenControl } from '../../controls/token-minting/claim-minted-token.control'; +import { importMintedTokenControl } from '../../controls/token-minting/import-minted-token'; +import { mintTokenControl } from '../../controls/token-minting/token-mint.control'; +import { cancelTradeOrderSchema } from '../../controls/token-trading/TokenCanelTradeOrderRequestSchema'; +import { tradeTokenSchema } from '../../controls/token-trading/TokenTradeRequestSchema'; +import { cancelTradeOrderControl } from '../../controls/token-trading/token-trade-cancel.controller'; +import { tradeTokenControl } from '../../controls/token-trading/token-trade.controller'; +import { airdropTokenSchema } from '../../controls/token/TokenAirdropRequestSchema'; +import { cancelPubSaleSchema } from '../../controls/token/TokenCancelPubSaleRequestSchema'; +import { claimAirdroppedTokenSchema } from '../../controls/token/TokenClaimAirdroppedRequestSchema'; +import { createTokenSchema } from '../../controls/token/TokenCreateRequestSchema'; +import { creditTokenSchema } from '../../controls/token/TokenCreditRequestSchema'; +import { enableTradingSchema } from '../../controls/token/TokenEnableTradingRequestSchema'; +import { orderTokenSchema } from '../../controls/token/TokenOrderRequestSchema'; +import { setAvailableForSaleSchema } from '../../controls/token/TokenSetAvailableForSaleRequestSchema'; +import { airdropTokenControl } from '../../controls/token/token.airdrop'; +import { claimAirdroppedTokenControl } from '../../controls/token/token.airdrop.claim'; +import { cancelPublicSaleControl } from '../../controls/token/token.cancel.pub.sale'; +import { createTokenControl } from '../../controls/token/token.create'; +import { creditTokenControl } from '../../controls/token/token.credit'; +import { enableTokenTradingControl } from '../../controls/token/token.enable.trading'; +import { orderTokenControl } from '../../controls/token/token.order'; +import { setTokenAvailableForSaleControl } from '../../controls/token/token.set.for.sale'; +import { updateTokenControl } from '../../controls/token/token.update'; +import { voteSchema } from '../../controls/vote/VoteRequestSchema'; +import { voteControl } from '../../controls/vote/vote.control'; +import { CommonJoi, toJoiObject } from '../../services/joi/common'; +import { onRequest } from './https'; +import { memberCreate } from './middlewares'; + +exports[WEN_FUNC.createMember] = onRequest({ + name: WEN_FUNC.updateMember, + schema: Joi.object({}), + middleware: memberCreate, + handler: createMemberControl, +}); + +exports[WEN_FUNC.updateMember] = onRequest({ + name: WEN_FUNC.updateMember, + schema: updateMemberSchema, + handler: updateMemberControl, +}); + +// Space functions +exports[WEN_FUNC.createSpace] = onRequest({ + name: WEN_FUNC.createSpace, + schema: createSpaceSchemaObject, + handler: createSpaceControl, +}); + +exports[WEN_FUNC.updateSpace] = onRequest({ + name: WEN_FUNC.updateSpace, + schema: updateSpaceSchema, + handler: updateSpaceControl, +}); + +exports[WEN_FUNC.joinSpace] = onRequest({ + name: WEN_FUNC.joinSpace, + schema: spaceJoinSchema, + handler: joinSpaceControl, +}); + +exports[WEN_FUNC.leaveSpace] = onRequest({ + name: WEN_FUNC.leaveSpace, + schema: spaceLeaveSchema, + handler: leaveSpaceControl, +}); + +exports[WEN_FUNC.blockMemberSpace] = onRequest({ + name: WEN_FUNC.blockMemberSpace, + schema: editSpaceMemberSchemaObject, + handler: blockMemberControl, +}); + +exports[WEN_FUNC.unblockMemberSpace] = onRequest({ + name: WEN_FUNC.unblockMemberSpace, + schema: editSpaceMemberSchemaObject, + handler: unblockMemberControl, +}); + +exports[WEN_FUNC.acceptMemberSpace] = onRequest({ + name: WEN_FUNC.acceptMemberSpace, + schema: editSpaceMemberSchemaObject, + handler: acceptSpaceMemberControl, +}); + +exports[WEN_FUNC.declineMemberSpace] = onRequest({ + name: WEN_FUNC.declineMemberSpace, + schema: editSpaceMemberSchemaObject, + handler: declineMemberControl, +}); + +exports[WEN_FUNC.addGuardianSpace] = onRequest({ + name: WEN_FUNC.addGuardianSpace, + schema: editSpaceMemberSchemaObject, + handler: editGuardianControl(ProposalType.ADD_GUARDIAN), +}); + +exports[WEN_FUNC.removeGuardianSpace] = onRequest({ + name: WEN_FUNC.removeGuardianSpace, + schema: editSpaceMemberSchemaObject, + handler: editGuardianControl(ProposalType.REMOVE_GUARDIAN), +}); + +exports[WEN_FUNC.claimSpace] = onRequest({ + name: WEN_FUNC.claimSpace, + schema: spaceClaimSchema, + handler: claimSpaceControl, +}); + +// Award functions +exports[WEN_FUNC.createAward] = onRequest({ + name: WEN_FUNC.createAward, + schema: awardCreateSchemaObject, + handler: createAwardControl, +}); + +exports[WEN_FUNC.fundAward] = onRequest({ + name: WEN_FUNC.fundAward, + schema: awardFundSchema, + handler: fundAwardControl, +}); + +exports[WEN_FUNC.rejectAward] = onRequest({ + name: WEN_FUNC.rejectAward, + schema: awardRejectSchema, + handler: rejectAwardControl, +}); + +exports[WEN_FUNC.addOwnerAward] = onRequest({ + name: WEN_FUNC.addOwnerAward, + schema: awardCancelSchema, + handler: cancelAwardControl, +}); + +exports[WEN_FUNC.participateAward] = onRequest({ + name: WEN_FUNC.participateAward, + schema: awardParticipateSchema, + handler: awardParticipateControl, +}); + +exports[WEN_FUNC.approveParticipantAward] = onRequest({ + name: WEN_FUNC.approveParticipantAward, + schema: approveAwardParticipantSchemaObject, + handler: approveAwardParticipantControl, +}); + +exports[WEN_FUNC.cancelAward] = onRequest({ + name: WEN_FUNC.cancelAward, + schema: awardCancelSchema, + handler: cancelAwardControl, +}); + +// Proposal functions +exports[WEN_FUNC.createProposal] = onRequest({ + name: WEN_FUNC.createProposal, + schema: proposalCreateSchemaObject, + handler: createProposalControl, +}); + +exports[WEN_FUNC.approveProposal] = onRequest({ + name: WEN_FUNC.approveProposal, + schema: approveProposaSchema, + handler: proposalApprovalControl(true), +}); + +exports[WEN_FUNC.rejectProposal] = onRequest({ + name: WEN_FUNC.rejectProposal, + schema: rejectProposaSchema, + handler: proposalApprovalControl(false), +}); + +exports[WEN_FUNC.voteOnProposal] = onRequest({ + name: WEN_FUNC.voteOnProposal, + schema: voteOnProposalSchemaObject, + handler: voteOnProposalControl, +}); + +// Collection functions +exports[WEN_FUNC.createCollection] = onRequest({ + name: WEN_FUNC.createCollection, + schema: createCollectionSchema, + handler: createCollectionControl, +}); + +exports[WEN_FUNC.updateCollection] = onRequest({ + name: WEN_FUNC.updateCollection, + schema: toJoiObject({ uid: CommonJoi.uid() }), + schemaOptions: { allowUnknown: true }, + handler: updateCollectionControl, +}); + +exports[WEN_FUNC.approveCollection] = onRequest({ + name: WEN_FUNC.approveCollection, + schema: approveCollectionSchema, + handler: approveCollectionControl, +}); + +exports[WEN_FUNC.rejectCollection] = onRequest({ + name: WEN_FUNC.rejectCollection, + schema: rejectCollectionSchema, + handler: rejectCollectionControl, +}); + +exports[WEN_FUNC.mintCollection] = onRequest({ + name: WEN_FUNC.mintCollection, + schema: mintCollectionSchema, + handler: mintCollectionOrderControl, +}); + +// NFT functions +exports[WEN_FUNC.createNft] = onRequest({ + name: WEN_FUNC.createNft, + schema: nftCreateSchema, + handler: createNftControl, +}); + +exports[WEN_FUNC.createBatchNft] = onRequest({ + name: WEN_FUNC.createBatchNft, + schema: Joi.array().items(Joi.object().keys(createSchema)).min(1).max(500), + handler: createBatchNftControl, +}); + +exports[WEN_FUNC.updateUnsoldNft] = onRequest({ + name: WEN_FUNC.updateUnsoldNft, + schema: updateUnsoldNftSchema, + handler: updateUnsoldNftControl, +}); + +exports[WEN_FUNC.setForSaleNft] = onRequest({ + name: WEN_FUNC.setForSaleNft, + schema: setNftForSaleSchema, + handler: setForSaleNftControl, +}); + +exports[WEN_FUNC.withdrawNft] = onRequest({ + name: WEN_FUNC.withdrawNft, + schema: nftWithdrawSchema, + handler: withdrawNftControl, +}); + +exports[WEN_FUNC.depositNft] = onRequest({ + name: WEN_FUNC.depositNft, + schema: depositNftSchema, + handler: depositNftControl, +}); + +exports[WEN_FUNC.stakeNft] = onRequest({ + name: WEN_FUNC.stakeNft, + schema: stakeNftSchema, + handler: nftStakeControl, +}); + +exports[WEN_FUNC.orderNft] = onRequest({ + name: WEN_FUNC.orderNft, + schema: nftPurchaseSchema, + handler: orderNftControl, +}); + +exports[WEN_FUNC.openBid] = onRequest({ + name: WEN_FUNC.openBid, + schema: nftBidSchema, + handler: nftBidControl, +}); + +// Address functions +exports[WEN_FUNC.validateAddress] = onRequest({ + name: WEN_FUNC.validateAddress, + schema: validateAddressSchemaObject, + handler: validateAddressControl, +}); + +// TOKEN functions +exports[WEN_FUNC.createToken] = onRequest({ + name: WEN_FUNC.createToken, + schema: createTokenSchema, + handler: createTokenControl, +}); + +exports[WEN_FUNC.updateToken] = onRequest({ + name: WEN_FUNC.updateToken, + schema: toJoiObject(uidSchema), + schemaOptions: { allowUnknown: true }, + handler: updateTokenControl, +}); + +exports[WEN_FUNC.setTokenAvailableForSale] = onRequest({ + name: WEN_FUNC.setTokenAvailableForSale, + schema: setAvailableForSaleSchema, + handler: setTokenAvailableForSaleControl, +}); + +exports[WEN_FUNC.cancelPublicSale] = onRequest({ + name: WEN_FUNC.cancelPublicSale, + schema: cancelPubSaleSchema, + handler: cancelPublicSaleControl, +}); + +exports[WEN_FUNC.orderToken] = onRequest({ + name: WEN_FUNC.orderToken, + schema: orderTokenSchema, + handler: orderTokenControl, +}); + +exports[WEN_FUNC.creditToken] = onRequest({ + name: WEN_FUNC.creditToken, + schema: creditTokenSchema, + handler: creditTokenControl, +}); + +exports[WEN_FUNC.enableTokenTrading] = onRequest({ + name: WEN_FUNC.enableTokenTrading, + schema: enableTradingSchema, + handler: enableTokenTradingControl, +}); + +exports[WEN_FUNC.airdropToken] = onRequest({ + name: WEN_FUNC.airdropToken, + schema: airdropTokenSchema, + handler: airdropTokenControl, +}); + +exports[WEN_FUNC.claimAirdroppedToken] = onRequest({ + name: WEN_FUNC.claimAirdroppedToken, + schema: claimAirdroppedTokenSchema, + handler: claimAirdroppedTokenControl, +}); + +exports[WEN_FUNC.tradeToken] = onRequest({ + name: WEN_FUNC.tradeToken, + schema: tradeTokenSchema, + schemaOptions: { convert: false }, + handler: tradeTokenControl, +}); + +exports[WEN_FUNC.cancelTradeOrder] = onRequest({ + name: WEN_FUNC.cancelTradeOrder, + schema: cancelTradeOrderSchema, + handler: cancelTradeOrderControl, +}); + +exports[WEN_FUNC.mintTokenOrder] = onRequest({ + name: WEN_FUNC.mintTokenOrder, + schema: mintTokenSchema, + handler: mintTokenControl, +}); + +exports[WEN_FUNC.claimMintedTokenOrder] = onRequest({ + name: WEN_FUNC.claimMintedTokenOrder, + schema: symbolSchema, + handler: claimMintedTokenControl, +}); + +exports[WEN_FUNC.airdropMintedToken] = onRequest({ + name: WEN_FUNC.airdropMintedToken, + schema: airdropTokenSchema, + handler: airdropMintedTokenControl, +}); + +exports[WEN_FUNC.importMintedToken] = onRequest({ + name: WEN_FUNC.importMintedToken, + schema: importMintedTokenSchema, + handler: importMintedTokenControl, +}); + +exports[WEN_FUNC.creditUnrefundable] = onRequest({ + name: WEN_FUNC.creditUnrefundable, + schema: creditUnrefundableSchema, + handler: creditUnrefundableControl, +}); + +exports[WEN_FUNC.depositStake] = onRequest({ + name: WEN_FUNC.depositStake, + schema: depositStakeSchemaObject, + handler: depositStakeControl, +}); + +exports[WEN_FUNC.voteController] = onRequest({ + name: WEN_FUNC.voteController, + schema: voteSchema, + handler: voteControl, +}); + +exports[WEN_FUNC.rankController] = onRequest({ + name: WEN_FUNC.rankController, + schema: rankSchema, + handler: rankControl, +}); + +exports[WEN_FUNC.stakeReward] = onRequest({ + name: WEN_FUNC.stakeReward, + schema: stakeRewardsSchema, + handler: stakeRewardControl, +}); + +exports[WEN_FUNC.removeStakeReward] = onRequest({ + name: WEN_FUNC.removeStakeReward, + schema: removeStakeRewardSchema, + handler: removeStakeRewardControl, +}); + +exports[WEN_FUNC.generateCustomToken] = onRequest({ + name: WEN_FUNC.generateCustomToken, + schemaOptions: { + allowUnknown: true, + }, + schema: customTokenSchema, + handler: generateCustomTokenControl, +}); + +exports[WEN_FUNC.uploadFile] = onRequest({ + name: WEN_FUNC.uploadFile, + schema: Joi.object({}), + schemaOptions: { allowUnknown: true }, + handler: uploadFileControl, +}); diff --git a/packages/functions/src/runtime/https/middlewares.ts b/packages/functions/src/runtime/https/middlewares.ts new file mode 100644 index 0000000000..49b0cc7edb --- /dev/null +++ b/packages/functions/src/runtime/https/middlewares.ts @@ -0,0 +1,28 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { WEN_FUNC } from '@build-5/interfaces'; +import express from 'express'; +import { AnySchema, ValidationOptions } from 'joi'; +import { Context } from '../../controls/common'; +import { assertValidationAsync } from '../../utils/schema.utils'; +import { decodeAuth } from '../../utils/wallet.utils'; + +export const auth = async ( + req: express.Request, + func: WEN_FUNC, + schema: AnySchema, + options?: ValidationOptions, +): Promise> => { + const decoded = await decodeAuth(req.body.data, func); + const owner = decoded.address.toLowerCase(); + const params = await assertValidationAsync(schema, decoded.body, options); + return { ip: req.ip || '', owner, params, headers: req.headers }; +}; + +export const memberCreate = async (req: express.Request): Promise> => { + return { + ip: req.ip || '', + owner: req.body.data, + params: {}, + headers: req.headers, + }; +}; diff --git a/packages/functions/src/runtime/proto/protoToJson.ts b/packages/functions/src/runtime/proto/protoToJson.ts new file mode 100644 index 0000000000..64cedc61b6 --- /dev/null +++ b/packages/functions/src/runtime/proto/protoToJson.ts @@ -0,0 +1,41 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +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 'booleanValue': + case 'integerValue': + case 'doubleValue': + case 'timestampValue': + case 'stringValue': + 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/storage/index.ts b/packages/functions/src/runtime/storage/index.ts new file mode 100644 index 0000000000..c71dc080df --- /dev/null +++ b/packages/functions/src/runtime/storage/index.ts @@ -0,0 +1,9 @@ +import { STORAGE_TRIGGER_SCALE } from '../../scale.settings'; +import { onStorageObjectFinalized } from '../../triggers/storage/resize.img.trigger'; +import { WEN_STORAGE_TRIGGER } from '../common'; +import { onObjectFinalized } from './storage'; + +exports[WEN_STORAGE_TRIGGER.onUploadFinalized] = onObjectFinalized({ + runtimeOptions: STORAGE_TRIGGER_SCALE[WEN_STORAGE_TRIGGER.onUploadFinalized], + handler: onStorageObjectFinalized, +}); diff --git a/packages/functions/src/runtime/storage/storage.ts b/packages/functions/src/runtime/storage/storage.ts new file mode 100644 index 0000000000..c7b72ff6a7 --- /dev/null +++ b/packages/functions/src/runtime/storage/storage.ts @@ -0,0 +1,19 @@ +import { StorageObject } from '../../triggers/storage/resize.img.trigger'; +import { CloudFunctions, RuntimeOptions } from '../common'; + +export class StorageFunction extends CloudFunctions { + constructor( + public readonly func: (obj: StorageObject) => Promise, + options: RuntimeOptions, + ) { + super({ + region: 'us-central1', + ...options, + }); + } +} + +export const onObjectFinalized = (params: { + runtimeOptions: RuntimeOptions; + handler: (obj: StorageObject) => Promise; +}) => new StorageFunction(params.handler, params.runtimeOptions); diff --git a/packages/functions/src/runtime/trigger/index.ts b/packages/functions/src/runtime/trigger/index.ts new file mode 100644 index 0000000000..9fe97987ea --- /dev/null +++ b/packages/functions/src/runtime/trigger/index.ts @@ -0,0 +1,108 @@ +import { ALGOLIA_COLLECTIONS, COL, Network, SUB_COL, getMilestoneCol } from '@build-5/interfaces'; +import { ALGOLIA_TRIGGER_SCALE, TRIGGER_SCALE } from '../../scale.settings'; +import { algoliaTrigger } from '../../triggers/algolia/algolia.trigger'; +import { onAwardUpdated } from '../../triggers/award.trigger'; +import { onCollectionStatsWrite } from '../../triggers/collection.stats.trigger'; +import { onCollectionUpdated } from '../../triggers/collection.trigger'; +import { handleMilestoneTransactionWrite } from '../../triggers/milestone-transactions-triggers/milestone-transaction.trigger'; +import { onMnemonicUpdated } from '../../triggers/mnemonic.trigger'; +import { onNftWrite } from '../../triggers/nft.trigger'; +import { onProposalWrite } from '../../triggers/proposal.trigger'; +import { onTokenPurchaseCreated } from '../../triggers/token-trading/token-purchase.trigger'; +import { onTokenTradeOrderWrite } from '../../triggers/token-trading/token-trade-order.trigger'; +import { onTokenStatusUpdated } from '../../triggers/token.trigger'; +import { onTransactionWrite } from '../../triggers/transaction-trigger/transaction.trigger'; +import { isProdEnv } from '../../utils/config.utils'; +import { WEN_FUNC_TRIGGER } from '../common'; +import { onCreate, onUpdate, onWrite } from './trigger'; + +exports[WEN_FUNC_TRIGGER.onProposalWrite] = onWrite({ + document: `${COL.PROPOSAL}/{docId}`, + handler: onProposalWrite, +}); + +exports[WEN_FUNC_TRIGGER.onAwardUpdated] = onUpdate({ + document: `${COL.AWARD}/{docId}`, + options: TRIGGER_SCALE[WEN_FUNC_TRIGGER.onAwardUpdated], + handler: onAwardUpdated, +}); + +exports[WEN_FUNC_TRIGGER.onCollectionUpdated] = onUpdate({ + document: `${COL.COLLECTION}/{docId}`, + options: TRIGGER_SCALE[WEN_FUNC_TRIGGER.onCollectionUpdated], + handler: onCollectionUpdated, +}); + +exports[WEN_FUNC_TRIGGER.onTokenStatusUpdated] = onUpdate({ + document: `${COL.TOKEN}/{docId}`, + options: TRIGGER_SCALE[WEN_FUNC_TRIGGER.onTokenStatusUpdated], + handler: onTokenStatusUpdated, +}); + +exports[WEN_FUNC_TRIGGER.onTokenTradeOrderWrite] = onWrite({ + document: `${COL.TOKEN_MARKET}/{docId}`, + options: TRIGGER_SCALE[WEN_FUNC_TRIGGER.onTokenTradeOrderWrite], + handler: onTokenTradeOrderWrite, +}); + +exports[WEN_FUNC_TRIGGER.onTokenPurchaseCreated] = onCreate({ + document: `${COL.TOKEN_PURCHASE}/{docId}`, + options: TRIGGER_SCALE[WEN_FUNC_TRIGGER.onTokenPurchaseCreated], + handler: onTokenPurchaseCreated, +}); + +exports[WEN_FUNC_TRIGGER.onNftWrite] = onWrite({ + document: `${COL.NFT}/{docId}`, + options: TRIGGER_SCALE[WEN_FUNC_TRIGGER.onNftWrite], + handler: onNftWrite, +}); + +exports[WEN_FUNC_TRIGGER.onTransactionWrite] = onWrite({ + document: `${COL.TRANSACTION}/{docId}`, + options: TRIGGER_SCALE[WEN_FUNC_TRIGGER.onTransactionWrite], + handler: onTransactionWrite, +}); + +exports[WEN_FUNC_TRIGGER.onMnemonicUpdated] = onUpdate({ + document: `${COL.MNEMONIC}/{docId}`, + options: TRIGGER_SCALE[WEN_FUNC_TRIGGER.onMnemonicUpdated], + handler: onMnemonicUpdated, +}); + +exports[WEN_FUNC_TRIGGER.onCollectionStatsWrite] = onWrite({ + document: `${COL.COLLECTION}/{docId}/${SUB_COL.STATS}/{subDocId}`, + options: TRIGGER_SCALE[WEN_FUNC_TRIGGER.onCollectionStatsWrite], + handler: onCollectionStatsWrite, +}); + +export const algolia = ALGOLIA_COLLECTIONS.reduce( + (acc, act) => ({ + ...acc, + [`${WEN_FUNC_TRIGGER.algolia}${act}`]: onWrite({ + document: `${act}/{docId}`, + options: ALGOLIA_TRIGGER_SCALE[act], + handler: algoliaTrigger, + }), + }), + {}, +); + +const getMilestoneTrigger = (networks: Network[]) => + networks.reduce( + (acc, act) => ({ + ...acc, + [`${WEN_FUNC_TRIGGER.onMilestoneTransactionWrite}${act}`]: onWrite({ + document: `${getMilestoneCol(act)}/{docId}/${SUB_COL.TRANSACTIONS}/{subDocId}`, + options: TRIGGER_SCALE[WEN_FUNC_TRIGGER.onMilestoneTransactionWrite], + handler: handleMilestoneTransactionWrite(act), + }), + }), + {}, + ); + +const prodMilestoneTriggers = getMilestoneTrigger([Network.IOTA, Network.SMR]); +const testMilestoneTriggers = getMilestoneTrigger([Network.RMS]); + +export const milestoneTriggers = isProdEnv() + ? prodMilestoneTriggers + : { ...prodMilestoneTriggers, ...testMilestoneTriggers }; diff --git a/packages/functions/src/runtime/trigger/trigger.ts b/packages/functions/src/runtime/trigger/trigger.ts new file mode 100644 index 0000000000..600c6d7349 --- /dev/null +++ b/packages/functions/src/runtime/trigger/trigger.ts @@ -0,0 +1,54 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import { FirestoreDocEvent } from '../../triggers/common'; +import { CloudFunctions, RuntimeOptions } from '../common'; + +export enum TriggeredFunctionType { + ON_CREATE = 'on_create', + ON_UPDATE = 'on_update', + ON_WRITE = 'on_write', +} + +export class TriggeredFunction extends CloudFunctions { + constructor( + public readonly type: TriggeredFunctionType, + public readonly document: string, + public readonly handler: (event: FirestoreDocEvent) => Promise, + options?: RuntimeOptions, + ) { + super({ + region: 'us-central1', + ...options, + }); + } +} + +export const onCreate = ({ + document, + handler, + options, +}: { + document: string; + handler: (event: FirestoreDocEvent) => Promise; + options?: RuntimeOptions; +}) => new TriggeredFunction(TriggeredFunctionType.ON_CREATE, document, handler, options); + +export const onUpdate = ({ + document, + handler, + options, +}: { + document: string; + handler: (event: FirestoreDocEvent) => Promise; + options?: RuntimeOptions; +}) => new TriggeredFunction(TriggeredFunctionType.ON_UPDATE, document, handler, options); + +export const onWrite = ({ + document, + handler, + options, +}: { + document: string; + handler: (event: FirestoreDocEvent) => Promise; + options?: RuntimeOptions; +}) => new TriggeredFunction(TriggeredFunctionType.ON_WRITE, document, handler, options); diff --git a/packages/functions/src/scale.settings.ts b/packages/functions/src/scale.settings.ts index 268c018b8c..711f35b83b 100644 --- a/packages/functions/src/scale.settings.ts +++ b/packages/functions/src/scale.settings.ts @@ -1,113 +1,121 @@ -import { COL, WEN_FUNC, WEN_FUNC_TRIGGER } from '@build-5/interfaces'; -import { GlobalOptions } from 'firebase-functions/v2'; -import { isProdEnv } from './utils/config.utils'; +import { COL, WEN_FUNC } from '@build-5/interfaces'; +import { + RuntimeOptions, + WEN_FUNC_TRIGGER, + WEN_SCHEDULED, + WEN_STORAGE_TRIGGER, +} from './runtime/common'; +import { getBucket, isProdEnv } from './utils/config.utils'; export const lowCold = 0; export const lowWarm = isProdEnv() ? 1 : lowCold; export const highUse = isProdEnv() ? 3 : lowWarm; -export function scale(func: WEN_FUNC | WEN_FUNC_TRIGGER): number { - const scaleSettings = {} as { [key: string]: number }; +export const WEN_FUNC_SCALE: { [key: string]: RuntimeOptions } = { // Min MEMORY / CPU instance, so high use works well here. - scaleSettings[WEN_FUNC.createMember] = highUse; - scaleSettings[WEN_FUNC.updateMember] = lowWarm; + [WEN_FUNC.createMember]: { minInstances: highUse }, + [WEN_FUNC.updateMember]: { minInstances: lowWarm }, - // Space functions. - scaleSettings[WEN_FUNC.createSpace] = lowCold; - scaleSettings[WEN_FUNC.updateSpace] = lowCold; - scaleSettings[WEN_FUNC.joinSpace] = lowWarm; - scaleSettings[WEN_FUNC.leaveSpace] = lowCold; - scaleSettings[WEN_FUNC.addGuardianSpace] = lowCold; - scaleSettings[WEN_FUNC.removeGuardianSpace] = lowCold; - scaleSettings[WEN_FUNC.blockMemberSpace] = lowCold; - scaleSettings[WEN_FUNC.unblockMemberSpace] = lowCold; - scaleSettings[WEN_FUNC.acceptMemberSpace] = lowCold; - scaleSettings[WEN_FUNC.declineMemberSpace] = lowCold; + // Space functions + [WEN_FUNC.createSpace]: { minInstances: lowCold }, + [WEN_FUNC.updateSpace]: { minInstances: lowCold }, + [WEN_FUNC.joinSpace]: { minInstances: lowWarm }, + [WEN_FUNC.leaveSpace]: { minInstances: lowCold }, + [WEN_FUNC.addGuardianSpace]: { minInstances: lowCold }, + [WEN_FUNC.removeGuardianSpace]: { minInstances: lowCold }, + [WEN_FUNC.blockMemberSpace]: { minInstances: lowCold }, + [WEN_FUNC.unblockMemberSpace]: { minInstances: lowCold }, + [WEN_FUNC.acceptMemberSpace]: { minInstances: lowCold }, + [WEN_FUNC.declineMemberSpace]: { minInstances: lowCold }, // Award Functions - scaleSettings[WEN_FUNC.createAward] = lowCold; - scaleSettings[WEN_FUNC.addOwnerAward] = lowCold; - scaleSettings[WEN_FUNC.participateAward] = lowWarm; - scaleSettings[WEN_FUNC.approveParticipantAward] = lowCold; + [WEN_FUNC.createAward]: { minInstances: lowCold }, + [WEN_FUNC.addOwnerAward]: { minInstances: lowCold }, + [WEN_FUNC.participateAward]: { minInstances: lowWarm }, + [WEN_FUNC.approveParticipantAward]: { + minInstances: lowCold, + timeoutSeconds: 540, + memory: '4GiB', + }, // Proposal Functions - scaleSettings[WEN_FUNC.createProposal] = lowCold; - scaleSettings[WEN_FUNC.approveProposal] = lowCold; - scaleSettings[WEN_FUNC.rejectProposal] = lowCold; - scaleSettings[WEN_FUNC.voteOnProposal] = lowCold; + [WEN_FUNC.createProposal]: { minInstances: lowCold, timeoutSeconds: 300, memory: '2GiB' }, + [WEN_FUNC.approveProposal]: { minInstances: lowCold }, + [WEN_FUNC.rejectProposal]: { minInstances: lowCold }, + [WEN_FUNC.voteOnProposal]: { minInstances: lowCold }, // Collections - scaleSettings[WEN_FUNC.createCollection] = lowCold; - scaleSettings[WEN_FUNC.updateCollection] = lowWarm; - scaleSettings[WEN_FUNC.approveCollection] = lowCold; - scaleSettings[WEN_FUNC.rejectCollection] = lowCold; - scaleSettings[WEN_FUNC_TRIGGER.collectionWrite] = lowWarm; + [WEN_FUNC.createCollection]: { minInstances: lowCold }, + [WEN_FUNC.updateCollection]: { minInstances: lowWarm }, + [WEN_FUNC.approveCollection]: { minInstances: lowCold }, + [WEN_FUNC.rejectCollection]: { minInstances: lowCold }, - scaleSettings[WEN_FUNC.createNft] = lowCold; - scaleSettings[WEN_FUNC.setForSaleNft] = lowWarm; - scaleSettings[WEN_FUNC.createBatchNft] = lowCold; - scaleSettings[WEN_FUNC.updateUnsoldNft] = lowCold; + [WEN_FUNC.createNft]: { minInstances: lowCold }, + [WEN_FUNC.setForSaleNft]: { minInstances: lowWarm }, + [WEN_FUNC.createBatchNft]: { minInstances: lowCold, timeoutSeconds: 300, memory: '4GiB' }, + [WEN_FUNC.updateUnsoldNft]: { minInstances: lowCold }, // Min MEMORY / CPU instance, so high use works well here. - scaleSettings[WEN_FUNC.orderNft] = highUse; - scaleSettings[WEN_FUNC.validateAddress] = lowWarm; + [WEN_FUNC.orderNft]: { minInstances: highUse }, + [WEN_FUNC.validateAddress]: { minInstances: lowWarm }, - scaleSettings[WEN_FUNC.createToken] = lowCold; - scaleSettings[WEN_FUNC_TRIGGER.onTokenStatusUpdate] = lowWarm; - // Min MEMORY / CPU instance, so high use works well here. - scaleSettings[WEN_FUNC_TRIGGER.onTokenTradeOrderWrite] = highUse; - scaleSettings[WEN_FUNC_TRIGGER.onTokenPurchaseCreated] = lowWarm; + [WEN_FUNC.createToken]: { minInstances: lowCold }, // Min MEMORY / CPU instance, so high use works well here. - scaleSettings[WEN_FUNC_TRIGGER.milestoneTransactionWrite] = highUse; - scaleSettings[WEN_FUNC_TRIGGER.nftWrite] = lowWarm; - scaleSettings[WEN_FUNC_TRIGGER.transactionWrite] = lowWarm; - scaleSettings[WEN_FUNC_TRIGGER.mnemonicWrite] = lowWarm; - scaleSettings[WEN_FUNC.mintCollection] = lowCold; - scaleSettings[WEN_FUNC_TRIGGER.resizeImg] = lowWarm; + [WEN_FUNC.mintCollection]: { minInstances: lowCold, memory: '8GiB', timeoutSeconds: 540, cpu: 2 }, - return isProdEnv() ? scaleSettings[func] || lowCold : 0; -} + [WEN_FUNC.uploadFile]: { memory: '512MiB' }, +}; -export function scaleAlgolia(col: COL): GlobalOptions { - const scaleSettings = {} as { [key: string]: GlobalOptions }; - scaleSettings[COL.SPACE] = { - minInstances: lowWarm, - memory: '256MiB', - }; - scaleSettings[COL.TOKEN] = { - minInstances: lowWarm, - memory: '256MiB', - }; - scaleSettings[COL.AWARD] = { +export const ALGOLIA_TRIGGER_SCALE: { [key: string]: RuntimeOptions } = { + [COL.SPACE]: { minInstances: lowWarm, memory: '256MiB' }, + [COL.TOKEN]: { minInstances: lowWarm, memory: '256MiB' }, + [COL.AWARD]: { minInstances: lowWarm, memory: '256MiB' }, + [COL.NFT]: { minInstances: lowWarm, memory: '512MiB', cpu: 1, concurrency: 100 }, + [COL.COLLECTION]: { minInstances: lowWarm, memory: '512MiB', cpu: 1, concurrency: 300 }, + [COL.MEMBER]: { minInstances: lowWarm, memory: '256MiB' }, + [COL.PROPOSAL]: { minInstances: lowWarm, memory: '256MiB' }, +}; + +export const TRIGGER_SCALE: { [key: string]: RuntimeOptions } = { + [WEN_FUNC_TRIGGER.onMilestoneTransactionWrite]: { minInstances: highUse }, + [WEN_FUNC_TRIGGER.onAwardUpdated]: { concurrency: 1000 }, + [WEN_FUNC_TRIGGER.onCollectionUpdated]: { + timeoutSeconds: 540, minInstances: lowWarm, - memory: '256MiB', - }; - // To support concurency. - scaleSettings[COL.NFT] = { + memory: isProdEnv() ? '1GiB' : undefined, + }, + [WEN_FUNC_TRIGGER.onTokenStatusUpdated]: { + timeoutSeconds: 540, + memory: '4GiB', minInstances: lowWarm, - memory: '512MiB', - cpu: 1, - concurrency: 100, - }; - // To support concurency. - scaleSettings[COL.COLLECTION] = { + }, + [WEN_FUNC_TRIGGER.onTokenTradeOrderWrite]: { timeoutSeconds: 540, minInstances: highUse }, + [WEN_FUNC_TRIGGER.onTokenPurchaseCreated]: { minInstances: lowWarm, concurrency: 1000 }, + [WEN_FUNC_TRIGGER.onNftWrite]: { minInstances: lowWarm, - memory: '512MiB', - cpu: 1, - concurrency: 300, - }; - scaleSettings[COL.MEMBER] = { + timeoutSeconds: 540, + memory: '2GiB', + concurrency: 40, + }, + [WEN_FUNC_TRIGGER.onTransactionWrite]: { + timeoutSeconds: 540, minInstances: lowWarm, - memory: '256MiB', - }; - scaleSettings[COL.PROPOSAL] = { + memory: '4GiB', + }, + [WEN_FUNC_TRIGGER.onMnemonicUpdated]: { minInstances: lowWarm, concurrency: 500 }, + [WEN_FUNC_TRIGGER.onCollectionStatsWrite]: { concurrency: 1000 }, +}; + +export const STORAGE_TRIGGER_SCALE: { [key: string]: RuntimeOptions } = { + [WEN_STORAGE_TRIGGER.onUploadFinalized]: { + memory: '4GiB', minInstances: lowWarm, - memory: '256MiB', - }; + bucket: getBucket(), + }, +}; - return isProdEnv() - ? scaleSettings[col] || { - minInstances: lowWarm, - } - : { minInstances: 0 }; -} +export const CRON_TRIGGER_SCALE: { [key: string]: RuntimeOptions } = { + [WEN_SCHEDULED.stakeReward]: { timeoutSeconds: 540, memory: '1GiB' }, + [WEN_SCHEDULED.mediaUpload]: { memory: '4GiB' }, + [WEN_SCHEDULED.updateFloorPriceOnCollections]: { timeoutSeconds: 1800 }, +}; 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 32b07a8911..16f40bf8c1 100644 --- a/packages/functions/src/services/payment/nft/nft-deposit-service.ts +++ b/packages/functions/src/services/payment/nft/nft-deposit-service.ts @@ -19,7 +19,6 @@ import { WenError, } from '@build-5/interfaces'; import { NftOutput } from '@iota/sdk'; -import * as functions from 'firebase-functions/v2'; import { head, isEmpty, set } from 'lodash'; import { build5Db } from '../../../firebase/firestore/build5Db'; import { ITransaction } from '../../../firebase/firestore/interfaces'; @@ -224,7 +223,7 @@ export class NftDepositService { set(migratedCollection, 'mediaStatus', MediaStatus.PENDING_UPLOAD); set(space, 'avatarUrl', bannerUrl); } catch (error) { - functions.logger.warn('Could not get banner url', order.uid, nftOutput.nftId, error); + console.warn('Could not get banner url', order.uid, nftOutput.nftId, error); } } 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 aa5cf8678d..15c419844c 100644 --- a/packages/functions/src/services/payment/nft/nft-stake-service.ts +++ b/packages/functions/src/services/payment/nft/nft-stake-service.ts @@ -19,7 +19,6 @@ import { Utils, } from '@iota/sdk'; import dayjs from 'dayjs'; -import * as functions from 'firebase-functions/v2'; import { cloneDeep, get } from 'lodash'; import { build5Db } from '../../../firebase/firestore/build5Db'; import { intToU32 } from '../../../utils/common.utils'; @@ -85,7 +84,7 @@ export class NftStakeService { } catch (error: any) { const payment = await this.transactionService.createPayment(order, match, true); this.transactionService.createNftCredit(payment, match, error, customErrorParams); - functions.logger.error(order.uid, payment.uid, error, customErrorParams); + console.error(order.uid, payment.uid, error, customErrorParams); } }; diff --git a/packages/functions/src/services/payment/tangle-service/TangleRequestService.ts b/packages/functions/src/services/payment/tangle-service/TangleRequestService.ts index ac452e042e..48c06c97d3 100644 --- a/packages/functions/src/services/payment/tangle-service/TangleRequestService.ts +++ b/packages/functions/src/services/payment/tangle-service/TangleRequestService.ts @@ -8,7 +8,6 @@ import { Transaction, WenError, } from '@build-5/interfaces'; -import * as functions from 'firebase-functions/v2'; import { get } from 'lodash'; import { build5Db } from '../../../firebase/firestore/build5Db'; import { getOutputMetadata } from '../../../utils/basic-output.utils'; @@ -73,7 +72,7 @@ export class TangleRequestService { ); } } catch (error) { - functions.logger.warn(owner, error); + console.warn(owner, error); if (!payment) { payment = await this.transactionService.createPayment({ ...order, member: owner }, match); } diff --git a/packages/functions/src/services/payment/tangle-service/address/AddressValidationTangleRequestSchema.ts b/packages/functions/src/services/payment/tangle-service/address/AddressValidationTangleRequestSchema.ts index c28850b9bf..7beb8a3857 100644 --- a/packages/functions/src/services/payment/tangle-service/address/AddressValidationTangleRequestSchema.ts +++ b/packages/functions/src/services/payment/tangle-service/address/AddressValidationTangleRequestSchema.ts @@ -1,5 +1,5 @@ import { AddressValidationTangleRequest, TangleRequestType } from '@build-5/interfaces'; -import { validateAddressSchema } from '../../../../runtime/firebase/address/AddressValidationRequestSchema'; +import { validateAddressSchema } from '../../../../controls/address/AddressValidationRequestSchema'; import { toJoiObject } from '../../../joi/common'; import { baseTangleSchema } from '../common'; diff --git a/packages/functions/src/services/payment/tangle-service/award/AwardAppParticipantTangleRequestSchema.ts b/packages/functions/src/services/payment/tangle-service/award/AwardAppParticipantTangleRequestSchema.ts index 99b91b0623..79631fda4b 100644 --- a/packages/functions/src/services/payment/tangle-service/award/AwardAppParticipantTangleRequestSchema.ts +++ b/packages/functions/src/services/payment/tangle-service/award/AwardAppParticipantTangleRequestSchema.ts @@ -1,5 +1,5 @@ import { AwardApproveParticipantTangleRequest, TangleRequestType } from '@build-5/interfaces'; -import { approveAwardParticipantSchema } from '../../../../runtime/firebase/award/AwardApproveParticipantRequestSchema'; +import { approveAwardParticipantSchema } from '../../../../controls/award/AwardApproveParticipantRequestSchema'; import { toJoiObject } from '../../../joi/common'; import { baseTangleSchema } from '../common'; diff --git a/packages/functions/src/services/payment/tangle-service/award/AwardCreateTangleRequestSchema.ts b/packages/functions/src/services/payment/tangle-service/award/AwardCreateTangleRequestSchema.ts index 9c67f9d694..a02501890d 100644 --- a/packages/functions/src/services/payment/tangle-service/award/AwardCreateTangleRequestSchema.ts +++ b/packages/functions/src/services/payment/tangle-service/award/AwardCreateTangleRequestSchema.ts @@ -7,7 +7,7 @@ import Joi from 'joi'; import { awardBageSchema as baseAwardBageSchema, awardCreateSchema as baseAwardCreateSchema, -} from '../../../../runtime/firebase/award/AwardCreateRequestSchema'; +} from '../../../../controls/award/AwardCreateRequestSchema'; import { toJoiObject } from '../../../joi/common'; import { baseTangleSchema } from '../common'; diff --git a/packages/functions/src/services/payment/tangle-service/nft/NftSetForSaleTangleRequestSchema.ts b/packages/functions/src/services/payment/tangle-service/nft/NftSetForSaleTangleRequestSchema.ts index 21607e0cc1..4288c43bbb 100644 --- a/packages/functions/src/services/payment/tangle-service/nft/NftSetForSaleTangleRequestSchema.ts +++ b/packages/functions/src/services/payment/tangle-service/nft/NftSetForSaleTangleRequestSchema.ts @@ -1,5 +1,5 @@ import { NftSetForSaleTangleRequest, TangleRequestType } from '@build-5/interfaces'; -import { baseNftSetForSaleSchema } from '../../../../runtime/firebase/nft/NftSetForSaleRequestSchema'; +import { baseNftSetForSaleSchema } from '../../../../controls/nft/NftSetForSaleRequestSchema'; import { toJoiObject } from '../../../joi/common'; import { baseTangleSchema } from '../common'; diff --git a/packages/functions/src/services/payment/tangle-service/proposal/ProposalCreateTangleRequestSchema.ts b/packages/functions/src/services/payment/tangle-service/proposal/ProposalCreateTangleRequestSchema.ts index e1d93405db..33aa5c0ee6 100644 --- a/packages/functions/src/services/payment/tangle-service/proposal/ProposalCreateTangleRequestSchema.ts +++ b/packages/functions/src/services/payment/tangle-service/proposal/ProposalCreateTangleRequestSchema.ts @@ -1,5 +1,5 @@ import { ProposalCreateTangleRequest, TangleRequestType } from '@build-5/interfaces'; -import { createProposalSchema } from '../../../../runtime/firebase/proposal/ProposalCreateRequestSchema'; +import { createProposalSchema } from '../../../../controls/proposal/ProposalCreateRequestSchema'; import { toJoiObject } from '../../../joi/common'; import { baseTangleSchema } from '../common'; diff --git a/packages/functions/src/services/payment/tangle-service/proposal/voting/ProposalVoteTangleRequestSchema.ts b/packages/functions/src/services/payment/tangle-service/proposal/voting/ProposalVoteTangleRequestSchema.ts index f211c5703e..34467f8353 100644 --- a/packages/functions/src/services/payment/tangle-service/proposal/voting/ProposalVoteTangleRequestSchema.ts +++ b/packages/functions/src/services/payment/tangle-service/proposal/voting/ProposalVoteTangleRequestSchema.ts @@ -1,5 +1,5 @@ import { ProposalVoteTangleRequest, TangleRequestType } from '@build-5/interfaces'; -import { voteOnProposalSchema } from '../../../../../runtime/firebase/proposal/ProposalVoteRequestSchema'; +import { voteOnProposalSchema } from '../../../../../controls/proposal/ProposalVoteRequestSchema'; import { toJoiObject } from '../../../../joi/common'; import { baseTangleSchema } from '../../common'; diff --git a/packages/functions/src/services/payment/tangle-service/space/SpaceCreateTangleRequestSchema.ts b/packages/functions/src/services/payment/tangle-service/space/SpaceCreateTangleRequestSchema.ts index 00d8b057d0..fdeff09232 100644 --- a/packages/functions/src/services/payment/tangle-service/space/SpaceCreateTangleRequestSchema.ts +++ b/packages/functions/src/services/payment/tangle-service/space/SpaceCreateTangleRequestSchema.ts @@ -1,6 +1,6 @@ import { SpaceCreateTangleRequest, TangleRequestType } from '@build-5/interfaces'; import Joi from 'joi'; -import { createSpaceSchema } from '../../../../runtime/firebase/space/SpaceCreateRequestSchema'; +import { createSpaceSchema } from '../../../../controls/space/SpaceCreateRequestSchema'; import { toJoiObject } from '../../../joi/common'; import { baseTangleSchema } from '../common'; diff --git a/packages/functions/src/services/payment/tangle-service/space/SpaceEditMemberTangleRequestSchema.ts b/packages/functions/src/services/payment/tangle-service/space/SpaceEditMemberTangleRequestSchema.ts index 02d59df247..90ab6b202e 100644 --- a/packages/functions/src/services/payment/tangle-service/space/SpaceEditMemberTangleRequestSchema.ts +++ b/packages/functions/src/services/payment/tangle-service/space/SpaceEditMemberTangleRequestSchema.ts @@ -1,5 +1,5 @@ import { SpaceMemberUpsertTangleRequest, TangleRequestType } from '@build-5/interfaces'; -import { editSpaceMemberSchema } from '../../../../runtime/firebase/space/SpaceEditMemberRequestSchema'; +import { editSpaceMemberSchema } from '../../../../controls/space/SpaceEditMemberRequestSchema'; import { toJoiObject } from '../../../joi/common'; import { baseTangleSchema } from '../common'; diff --git a/packages/functions/src/services/payment/tangle-service/token/TokenStakeTangleRequestSchema.ts b/packages/functions/src/services/payment/tangle-service/token/TokenStakeTangleRequestSchema.ts index 0298042904..906cd49751 100644 --- a/packages/functions/src/services/payment/tangle-service/token/TokenStakeTangleRequestSchema.ts +++ b/packages/functions/src/services/payment/tangle-service/token/TokenStakeTangleRequestSchema.ts @@ -1,5 +1,5 @@ import { TangleRequestType, TokenStakeTangleRequest } from '@build-5/interfaces'; -import { depositStakeSchema } from '../../../../runtime/firebase/stake/StakeTokenRequestSchema'; +import { depositStakeSchema } from '../../../../controls/stake/StakeTokenRequestSchema'; import { toJoiObject } from '../../../joi/common'; import { baseTangleSchema } from '../common'; diff --git a/packages/functions/src/services/payment/transaction-service.ts b/packages/functions/src/services/payment/transaction-service.ts index 2e1a3d668e..1c92dba19c 100644 --- a/packages/functions/src/services/payment/transaction-service.ts +++ b/packages/functions/src/services/payment/transaction-service.ts @@ -18,7 +18,6 @@ import { } from '@build-5/interfaces'; import { ExpirationUnlockCondition, UnlockCondition, UnlockConditionType } from '@iota/sdk'; import dayjs from 'dayjs'; -import * as functions from 'firebase-functions/v2'; import { get, isEmpty, set } from 'lodash'; import { build5Db } from '../../firebase/firestore/build5Db'; import { IDocument, ITransaction } from '../../firebase/firestore/interfaces'; @@ -313,7 +312,7 @@ export class TransactionService { ? { status: 'error', code: error.code || '', message: error.key || '', ...customErrorParams } : {}; if (!isEmpty(error) && !get(error, 'code')) { - functions.logger.error(payment.uid, tran.to.nftOutput?.nftId, error); + console.error(payment.uid, tran.to.nftOutput?.nftId, error); } const transaction = { type: TransactionType.CREDIT_NFT, diff --git a/packages/functions/src/services/wallet/NftWallet.ts b/packages/functions/src/services/wallet/NftWallet.ts index 415105a433..1f4ed817e6 100644 --- a/packages/functions/src/services/wallet/NftWallet.ts +++ b/packages/functions/src/services/wallet/NftWallet.ts @@ -33,7 +33,6 @@ import { utf8ToHex, } from '@iota/sdk'; import dayjs from 'dayjs'; -import * as functions from 'firebase-functions/v2'; import { cloneDeep, get, head, isEmpty } from 'lodash'; import { build5Db } from '../../firebase/firestore/build5Db'; import { unclockMnemonic } from '../../triggers/milestone-transactions-triggers/common'; @@ -312,7 +311,7 @@ export class NftWallet { if (!nftsToMint) { await unclockMnemonic(sourceAddress.bech32); - functions.logger.error('Nft data to big to mint', head(nfts)); + console.error('Nft data to big to mint', head(nfts)); throw Error('Nft data to big to mint'); } return blockId; diff --git a/packages/functions/src/services/wallet/wallet.service.ts b/packages/functions/src/services/wallet/wallet.service.ts index e09e36ea19..2c483b2a4a 100644 --- a/packages/functions/src/services/wallet/wallet.service.ts +++ b/packages/functions/src/services/wallet/wallet.service.ts @@ -1,6 +1,5 @@ import { COL, DEFAULT_NETWORK, NativeToken, Network } from '@build-5/interfaces'; import { Client } from '@iota/sdk'; -import * as functions from 'firebase-functions/v2'; import { build5Db } from '../../firebase/firestore/build5Db'; import { getRandomElement } from '../../utils/common.utils'; import { IotaWallet } from './IotaWalletService'; @@ -43,11 +42,11 @@ const getClient = async (network: Network) => { return { client, info: info.nodeInfo }; } } catch (error) { - functions.logger.warn(`Could not connect to client ${network}`, nodeUrl, error); + console.warn(`Could not connect to client ${network}`, nodeUrl, error); } await new Promise((resolve) => setTimeout(resolve, Math.floor(Math.random() * 1000 + 500))); } - functions.logger.error(`Could not connect to client ${network}`, nodeUrl); + console.error(`Could not connect to client ${network}`, nodeUrl); throw Error(`Could not connect to any client ${network}`); }; diff --git a/packages/functions/src/triggers/algolia/algolia.trigger.ts b/packages/functions/src/triggers/algolia/algolia.trigger.ts new file mode 100644 index 0000000000..126e8f658d --- /dev/null +++ b/packages/functions/src/triggers/algolia/algolia.trigger.ts @@ -0,0 +1,41 @@ +import { COL } from '@build-5/interfaces'; +import algoliasearch from 'algoliasearch'; +import { algoliaAppId, algoliaKey, isEmulatorEnv } from '../../utils/config.utils'; +import { FirestoreDocEvent } from '../common'; +import { docToAlgoliaData } from './firestore.to.algolia'; +const client = algoliasearch(algoliaAppId(), algoliaKey()); + +const deleteObject = async (col: COL, objectID: string) => { + try { + await client.initIndex(col).deleteObject(objectID); + } catch (error) { + console.error(col, objectID, error); + } +}; + +const upsertObject = async (rawData: Record, col: COL, objectID: string) => { + const data = docToAlgoliaData({ ...rawData, objectID, id: objectID }); + try { + await client.initIndex(col).saveObject(data).wait(); + } catch (error) { + console.error(col, objectID, error); + } +}; + +export const algoliaTrigger = async (event: FirestoreDocEvent>) => { + if (isEmulatorEnv()) { + return; + } + const { prev, curr, col } = event; + const objectID = curr?.uid || prev?.uid || ''; + + if (!objectID) { + return; + } + + if (!curr) { + return await deleteObject(col, objectID); + } + + return await upsertObject(curr, col, objectID); +}; diff --git a/packages/functions/src/algolia/firestore.to.algolia.ts b/packages/functions/src/triggers/algolia/firestore.to.algolia.ts similarity index 100% rename from packages/functions/src/algolia/firestore.to.algolia.ts rename to packages/functions/src/triggers/algolia/firestore.to.algolia.ts diff --git a/packages/functions/src/triggers/award.trigger.ts b/packages/functions/src/triggers/award.trigger.ts index b3aa6826e1..c7019eb078 100644 --- a/packages/functions/src/triggers/award.trigger.ts +++ b/packages/functions/src/triggers/award.trigger.ts @@ -8,88 +8,48 @@ import { TransactionPayloadType, TransactionType, } from '@build-5/interfaces'; -import * as functions from 'firebase-functions/v2'; import { build5Db } from '../firebase/firestore/build5Db'; import { getAddress } from '../utils/address.utils'; import { getRandomEthAddress } from '../utils/wallet.utils'; +import { FirestoreDocEvent } from './common'; -export const awardUpdateTrigger = functions.firestore.onDocumentUpdated( - { document: COL.AWARD + '/{awardId}', concurrency: 1000 }, - async (event) => { - const prev = event.data?.before?.data(); - const curr = event.data?.after?.data(); - if (!curr || !curr.funded) { - return; - } - - if ( - (prev.completed !== curr.completed || prev.badgesMinted !== curr.badgesMinted) && - curr.completed && - curr.badgesMinted === curr.issued - ) { - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${curr.fundedBy}`); - const member = await memberDocRef.get(); - const targetAddress = getAddress(member, curr.network); - - const burnAlias = { - type: TransactionType.AWARD, - uid: getRandomEthAddress(), - space: curr.space, - member: curr.fundedBy, - network: curr.network, - payload: { - type: TransactionPayloadType.BURN_ALIAS, - sourceAddress: curr.address, - targetAddress, - reconciled: false, - void: false, - award: curr.uid, - }, - }; - 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 = { - type: TransactionType.CREDIT, - uid: getRandomEthAddress(), - space: curr.space, - member: curr.fundedBy, - network: curr.network, - payload: { - type: TransactionPayloadType.AWARD_COMPLETED, - amount: remainingBadges * curr.badge.tokenReward, - sourceAddress: curr.address, - targetAddress, - reconciled: false, - void: false, - award: curr.uid, - token: token.uid, - tokenSymbol: token.symbol, - }, - }; - await build5Db().doc(`${COL.TRANSACTION}/${baseTokenCredit.uid}`).create(baseTokenCredit); - } - } +export const onAwardUpdated = async (event: FirestoreDocEvent) => { + const { prev, curr } = event; + if (!prev || !curr || !curr.funded) { + return; + } - if ( - curr.badge.type === AwardBadgeType.NATIVE && - (prev.completed !== curr.completed || prev.airdropClaimed !== curr.airdropClaimed) && - curr.completed && - curr.airdropClaimed === curr.issued - ) { - const memberDocRef = build5Db().doc(`${COL.MEMBER}/${curr.fundedBy}`); - const member = await memberDocRef.get(); - const targetAddress = getAddress(member, curr.network); + if ( + (prev.completed !== curr.completed || prev.badgesMinted !== curr.badgesMinted) && + curr.completed && + curr.badgesMinted === curr.issued + ) { + const memberDocRef = build5Db().doc(`${COL.MEMBER}/${curr.fundedBy}`); + const member = await memberDocRef.get(); + const targetAddress = getAddress(member, curr.network); - const remainingBadges = curr.badge.total - curr.issued; + const burnAlias = { + type: TransactionType.AWARD, + uid: getRandomEthAddress(), + space: curr.space, + member: curr.fundedBy, + network: curr.network, + payload: { + type: TransactionPayloadType.BURN_ALIAS, + sourceAddress: curr.address, + targetAddress, + reconciled: false, + void: false, + award: curr.uid, + }, + }; + 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 nativeTokensCredit: Transaction = { + const baseTokenCredit = { type: TransactionType.CREDIT, uid: getRandomEthAddress(), space: curr.space, @@ -97,15 +57,7 @@ export const awardUpdateTrigger = functions.firestore.onDocumentUpdated( network: curr.network, payload: { type: TransactionPayloadType.AWARD_COMPLETED, - amount: curr.nativeTokenStorageDeposit, - nativeTokens: remainingBadges - ? [ - { - id: curr.badge.tokenId!, - amount: BigInt(remainingBadges * curr.badge.tokenReward), - }, - ] - : [], + amount: remainingBadges * curr.badge.tokenReward, sourceAddress: curr.address, targetAddress, reconciled: false, @@ -115,9 +67,51 @@ export const awardUpdateTrigger = functions.firestore.onDocumentUpdated( tokenSymbol: token.symbol, }, }; - await build5Db() - .doc(`${COL.TRANSACTION}/${nativeTokensCredit.uid}`) - .create(nativeTokensCredit); + await build5Db().doc(`${COL.TRANSACTION}/${baseTokenCredit.uid}`).create(baseTokenCredit); } - }, -); + } + + if ( + curr.badge.type === AwardBadgeType.NATIVE && + (prev.completed !== curr.completed || prev.airdropClaimed !== curr.airdropClaimed) && + curr.completed && + curr.airdropClaimed === curr.issued + ) { + const memberDocRef = build5Db().doc(`${COL.MEMBER}/${curr.fundedBy}`); + const member = await memberDocRef.get(); + const targetAddress = getAddress(member, curr.network); + + const remainingBadges = curr.badge.total - curr.issued; + + const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${curr.badge.tokenUid}`); + const token = (await tokenDocRef.get())!; + + const nativeTokensCredit: Transaction = { + type: TransactionType.CREDIT, + uid: getRandomEthAddress(), + space: curr.space, + member: curr.fundedBy, + network: curr.network, + payload: { + type: TransactionPayloadType.AWARD_COMPLETED, + amount: curr.nativeTokenStorageDeposit, + nativeTokens: remainingBadges + ? [ + { + id: curr.badge.tokenId!, + amount: BigInt(remainingBadges * curr.badge.tokenReward), + }, + ] + : [], + sourceAddress: curr.address, + targetAddress, + reconciled: false, + void: false, + award: curr.uid, + token: token.uid, + tokenSymbol: token.symbol, + }, + }; + await build5Db().doc(`${COL.TRANSACTION}/${nativeTokensCredit.uid}`).create(nativeTokensCredit); + } +}; diff --git a/packages/functions/src/triggers/collection.stats.trigger.ts b/packages/functions/src/triggers/collection.stats.trigger.ts index 201472e908..5ed81a3959 100644 --- a/packages/functions/src/triggers/collection.stats.trigger.ts +++ b/packages/functions/src/triggers/collection.stats.trigger.ts @@ -1,22 +1,18 @@ -import { COL, CollectionStats, SUB_COL } from '@build-5/interfaces'; -import * as functions from 'firebase-functions/v2'; +import { COL, CollectionStats } from '@build-5/interfaces'; import { build5Db } from '../firebase/firestore/build5Db'; import { getRankingThreshold } from '../utils/config.utils'; +import { FirestoreDocEvent } from './common'; -export const collectionStatsUpdate = functions.firestore.onDocumentWritten( - { document: `${COL.COLLECTION}/{collectionId}/${SUB_COL.STATS}/{subDocId}`, concurrency: 1000 }, - async (event) => { - const prev = event.data?.before?.data(); - const curr = event.data?.after?.data(); - if (!curr) { - return; - } +export const onCollectionStatsWrite = async (event: FirestoreDocEvent) => { + const { prev, curr } = event; + if (!curr) { + return; + } - if (rankingThresholdReached(prev, curr)) { - await onRankingThresholdReached(event.params.collectionId); - } - }, -); + if (rankingThresholdReached(prev, curr)) { + await onRankingThresholdReached(event.docId); + } +}; const rankingThresholdReached = ( prev: CollectionStats | undefined, diff --git a/packages/functions/src/triggers/collection.trigger.ts b/packages/functions/src/triggers/collection.trigger.ts index f2f599248c..7e540f462b 100644 --- a/packages/functions/src/triggers/collection.trigger.ts +++ b/packages/functions/src/triggers/collection.trigger.ts @@ -10,57 +10,46 @@ import { TransactionPayloadType, TransactionType, UnsoldMintingOptions, - WEN_FUNC_TRIGGER, } from '@build-5/interfaces'; -import * as functions from 'firebase-functions/v2'; import { last } from 'lodash'; import { build5Db, getSnapshot } from '../firebase/firestore/build5Db'; -import { scale } from '../scale.settings'; import { getAddress } from '../utils/address.utils'; import { collectionToIpfsMetadata, downloadMediaAndPackCar } from '../utils/car.utils'; import { getRandomEthAddress } from '../utils/wallet.utils'; +import { FirestoreDocEvent } from './common'; -export const collectionWrite = functions.firestore.onDocumentUpdated( - { - document: COL.COLLECTION + '/{collectionId}', - timeoutSeconds: 540, - minInstances: scale(WEN_FUNC_TRIGGER.collectionWrite), - memory: '1GiB', - }, - async (event) => { - const prev = event.data?.before?.data(); - const curr = event.data?.after?.data(); - if (!curr) { - return; +export const onCollectionUpdated = async (event: FirestoreDocEvent) => { + const { prev, curr } = event; + if (!prev || !curr) { + return; + } + try { + if (prev && (curr.approved !== prev.approved || curr.rejected !== prev.rejected)) { + return await updateNftApprovalState(curr.uid); } - try { - if (prev && (curr.approved !== prev.approved || curr.rejected !== prev.rejected)) { - return await updateNftApprovalState(curr.uid); - } - if (curr.placeholderNft && prev.availableNfts !== curr.availableNfts) { - return await hidePlaceholderNft(curr); - } + if (curr.placeholderNft && prev.availableNfts !== curr.availableNfts) { + return await hidePlaceholderNft(curr); + } - if (prev.mintingData?.nftsToMint !== 0 && curr.mintingData?.nftsToMint === 0) { - return await onCollectionMinted(curr); - } + if (prev.mintingData?.nftsToMint !== 0 && curr.mintingData?.nftsToMint === 0) { + return await onCollectionMinted(curr); + } - if (prev.status !== curr.status && curr.status === CollectionStatus.MINTING) { - return await onCollectionMinting(curr); - } - if ( - curr.status === CollectionStatus.MINTING && - prev.mintingData?.nftMediaToPrepare && - curr.mintingData?.nftMediaToPrepare === 0 - ) { - return await onNftMediaPrepared(curr); - } - } catch (error) { - functions.logger.error(curr.uid, error); + if (prev.status !== curr.status && curr.status === CollectionStatus.MINTING) { + return await onCollectionMinting(curr); } - }, -); + if ( + curr.status === CollectionStatus.MINTING && + prev.mintingData?.nftMediaToPrepare && + curr.mintingData?.nftMediaToPrepare === 0 + ) { + return await onNftMediaPrepared(curr); + } + } catch (error) { + console.error(curr.uid, error); + } +}; const updateNftApprovalState = async (collectionId: string) => { let lastDocId = ''; diff --git a/packages/functions/src/triggers/common.ts b/packages/functions/src/triggers/common.ts new file mode 100644 index 0000000000..aacc45044c --- /dev/null +++ b/packages/functions/src/triggers/common.ts @@ -0,0 +1,11 @@ +import { COL, SUB_COL } from '@build-5/interfaces'; + +export interface FirestoreDocEvent { + prev?: T; + curr?: T; + path: string; + col: COL; + docId: string; + subCol?: SUB_COL; + subDocId?: string; +} diff --git a/packages/functions/src/triggers/milestone-transactions-triggers/common.ts b/packages/functions/src/triggers/milestone-transactions-triggers/common.ts index 9b6aaec890..9a56671b8b 100644 --- a/packages/functions/src/triggers/milestone-transactions-triggers/common.ts +++ b/packages/functions/src/triggers/milestone-transactions-triggers/common.ts @@ -1,4 +1,4 @@ -import { COL, Transaction, WEN_FUNC_TRIGGER } from '@build-5/interfaces'; +import { COL, Transaction } from '@build-5/interfaces'; import { RegularTransactionEssence, TaggedDataPayload, @@ -6,15 +6,8 @@ import { hexToUtf8, } from '@iota/sdk'; import dayjs from 'dayjs'; -import { DocumentOptions } from 'firebase-functions/v2/firestore'; import { isEmpty } from 'lodash'; import { build5Db } from '../../firebase/firestore/build5Db'; -import { scale } from '../../scale.settings'; - -export const milestoneTriggerConfig = { - timeoutSeconds: 300, - minInstances: scale(WEN_FUNC_TRIGGER.milestoneTransactionWrite), -} as DocumentOptions; export const confirmTransaction = async ( milestoneTransactionPath: string, 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 497a3c36a5..db4eb6809c 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,39 +1,32 @@ -import { Network, SUB_COL, getMilestoneCol } from '@build-5/interfaces'; +import { Network } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { DocumentSnapshot } from 'firebase-admin/firestore'; -import * as functions from 'firebase-functions/v2'; -import { FirestoreEvent } from 'firebase-functions/v2/firestore'; import { build5Db } from '../../firebase/firestore/build5Db'; import { ProcessingService } from '../../services/payment/payment-processing'; +import { FirestoreDocEvent } from '../common'; import { MilestoneTransactionAdapter } from './MilestoneTransactionAdapter'; import { confirmTransaction } from './common'; import { processConsumedVoteOutputs } from './consumed.vote.outputs'; import { updateTokenSupplyData } from './token.foundry'; -const handleMilestoneTransactionWrite = - (network: Network) => - async ( - event: FirestoreEvent< - functions.Change | undefined, - functions.ParamsOf - >, - ) => { - if (!event.data?.after?.data()) { +export const handleMilestoneTransactionWrite = + (network: Network) => async (event: FirestoreDocEvent>) => { + const { curr } = event; + if (!curr) { return; } try { return build5Db().runTransaction(async (transaction) => { - const docRef = build5Db().doc(event.data!.after.ref.path); + const docRef = build5Db().doc(event.path); const data = await transaction.get>(docRef); if (!data || data.processed) { return; } - await confirmTransaction(event.data!.after.ref.path, data); + await confirmTransaction(event.path, data); await updateTokenSupplyData(data); const adapter = new MilestoneTransactionAdapter(network); const milestoneTransaction = await adapter.toMilestoneTransaction({ ...data, - uid: event.params.tranId, + uid: event.subDocId, }); const service = new ProcessingService(transaction); await service.processMilestoneTransactions(milestoneTransaction); @@ -44,20 +37,6 @@ const handleMilestoneTransactionWrite = return transaction.update(docRef, { processed: true, processedOn: dayjs().toDate() }); }); } catch (error) { - functions.logger.error(`${network} transaction error`, event.data!.after.ref.path, error); + console.error(`${network} transaction error`, event.path, error); } }; - -const getDoc = (network: Network) => - `${getMilestoneCol(network)}/{milestoneId}/${SUB_COL.TRANSACTIONS}/{tranId}`; - -const getHandler = (network: Network) => - functions.firestore.onDocumentWritten( - { document: getDoc(network) }, - handleMilestoneTransactionWrite(network || Network.IOTA), - ); - -export const smrMilestoneTransactionWrite = getHandler(Network.SMR); -export const rmsMilestoneTransactionWrite = getHandler(Network.RMS); -export const iotaMilestoneTransactionWrite = getHandler(Network.IOTA); -export const atoiMilestoneTransactionWrite = getHandler(Network.ATOI); diff --git a/packages/functions/src/triggers/mnemonic.trigger.ts b/packages/functions/src/triggers/mnemonic.trigger.ts index 4bcca1b7d5..1f06cb2a3d 100644 --- a/packages/functions/src/triggers/mnemonic.trigger.ts +++ b/packages/functions/src/triggers/mnemonic.trigger.ts @@ -1,14 +1,7 @@ -import { - COL, - MAX_WALLET_RETRY, - Mnemonic, - Transaction, - WEN_FUNC_TRIGGER, -} from '@build-5/interfaces'; -import * as functions from 'firebase-functions/v2'; +import { COL, MAX_WALLET_RETRY, Mnemonic, Transaction } from '@build-5/interfaces'; import { chunk, isEmpty } from 'lodash'; import { build5Db } from '../firebase/firestore/build5Db'; -import { scale } from '../scale.settings'; +import { FirestoreDocEvent } from './common'; import { CREDIT_EXECUTABLE_TRANSACTIONS, DEFAULT_EXECUTABLE_TRANSACTIONS, @@ -20,29 +13,21 @@ enum FieldNameType { ALIAS_GOV_ADDRESS = 'payload.aliasGovAddress', } -export const mnemonicWrite = functions.firestore.onDocumentUpdated( - { - document: COL.MNEMONIC + '/{address}', - minInstances: scale(WEN_FUNC_TRIGGER.mnemonicWrite), - concurrency: 500, - }, - async (event) => { - const prev = event.data?.before?.data(); - const curr = event.data?.after?.data(); - if (!prev || !curr || isEmpty(prev?.lockedBy) || !isEmpty(curr?.lockedBy)) { - return; - } +export const onMnemonicUpdated = async (event: FirestoreDocEvent) => { + const { prev, curr } = event; + if (!prev || !curr || isEmpty(prev?.lockedBy) || !isEmpty(curr?.lockedBy)) { + return; + } - const address = event.params.address as string; - const tranId = await getUncofirmedTransactionsId(address); + const address = event.docId; + const tranId = await getUncofirmedTransactionsId(address); - if (!isEmpty(tranId)) { - await build5Db() - .doc(`${COL.TRANSACTION}/${tranId}`) - .update({ shouldRetry: true, 'payload.walletReference.inProgress': false }); - } - }, -); + if (!isEmpty(tranId)) { + await build5Db() + .doc(`${COL.TRANSACTION}/${tranId}`) + .update({ shouldRetry: true, 'payload.walletReference.inProgress': false }); + } +}; const TYPE_CHUNKS = chunk(DEFAULT_EXECUTABLE_TRANSACTIONS, 10).concat([ CREDIT_EXECUTABLE_TRANSACTIONS, diff --git a/packages/functions/src/triggers/nft.trigger.ts b/packages/functions/src/triggers/nft.trigger.ts index 5678d12872..f2c63ec65c 100644 --- a/packages/functions/src/triggers/nft.trigger.ts +++ b/packages/functions/src/triggers/nft.trigger.ts @@ -1,15 +1,7 @@ -import { - COL, - Collection, - MediaStatus, - Nft, - NftAvailable, - WEN_FUNC_TRIGGER, -} from '@build-5/interfaces'; -import * as functions from 'firebase-functions/v2'; +import { COL, Collection, MediaStatus, Nft, NftAvailable } from '@build-5/interfaces'; import { build5Db } from '../firebase/firestore/build5Db'; -import { scale } from '../scale.settings'; import { downloadMediaAndPackCar, nftToIpfsMetadata } from '../utils/car.utils'; +import { FirestoreDocEvent } from './common'; const getNftAvailability = (nft: Nft | undefined) => { if (!nft || nft.placeholderNft) { @@ -27,47 +19,37 @@ const getNftAvailability = (nft: Nft | undefined) => { return NftAvailable.UNAVAILABLE; }; -export const nftWrite = functions.firestore.onDocumentWritten( - { - minInstances: scale(WEN_FUNC_TRIGGER.nftWrite), - timeoutSeconds: 540, - document: COL.NFT + '/{nftId}', - - memory: '2GiB', - concurrency: 40, - }, - async (event) => { - const prev = event.data?.before?.data(); - const curr = event.data?.after?.data(); - if (!curr) { - return; - } +export const onNftWrite = async (event: FirestoreDocEvent) => { + const { prev, curr } = event; + if (!curr) { + return; + } - const prevAvailability = getNftAvailability(prev); - const currAvailability = getNftAvailability(curr); - if (prevAvailability !== currAvailability) { - const { nftsOnSale, nftsOnAuction } = getSaleChanges( - prevAvailability, - currAvailability, - prev?.owner, - ); - const availableNfts = getAvailableNftsChange(prevAvailability, currAvailability, prev?.owner); + const prevAvailability = getNftAvailability(prev); + const currAvailability = getNftAvailability(curr); + if (prevAvailability !== currAvailability) { + const { nftsOnSale, nftsOnAuction } = getSaleChanges( + prevAvailability, + currAvailability, + prev?.owner, + ); + const availableNfts = getAvailableNftsChange(prevAvailability, currAvailability, prev?.owner); - const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${curr.collection}`); - await collectionDocRef.update({ - nftsOnSale: build5Db().inc(nftsOnSale), - nftsOnAuction: build5Db().inc(nftsOnAuction), - availableNfts: build5Db().inc(availableNfts), - }); + const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${curr.collection}`); + await collectionDocRef.update({ + nftsOnSale: build5Db().inc(nftsOnSale), + nftsOnAuction: build5Db().inc(nftsOnAuction), + availableNfts: build5Db().inc(availableNfts), + }); - await event.data!.after.ref.update({ available: currAvailability }); - } + const docRef = build5Db().doc(event.path); + await docRef.update({ available: currAvailability }); + } - if (prev?.mediaStatus !== curr.mediaStatus && curr.mediaStatus === MediaStatus.PREPARE_IPFS) { - await prepareNftMedia(curr); - } - }, -); + if (prev?.mediaStatus !== curr.mediaStatus && curr.mediaStatus === MediaStatus.PREPARE_IPFS) { + await prepareNftMedia(curr); + } +}; const prepareNftMedia = async (nft: Nft) => { const collectionDocRef = build5Db().doc(`${COL.COLLECTION}/${nft.collection}`); diff --git a/packages/functions/src/triggers/proposal.trigger.ts b/packages/functions/src/triggers/proposal.trigger.ts index e530ef0579..aeb1b38874 100644 --- a/packages/functions/src/triggers/proposal.trigger.ts +++ b/packages/functions/src/triggers/proposal.trigger.ts @@ -17,7 +17,6 @@ import { UPDATE_SPACE_THRESHOLD_PERCENTAGE, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import * as functions from 'firebase-functions/v2'; import { get, set } from 'lodash'; import { build5Db } from '../firebase/firestore/build5Db'; import { getStakeForType } from '../services/stake.service'; @@ -25,38 +24,35 @@ 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'; -export const onProposalUpdated = functions.firestore.onDocumentWritten( - { document: COL.PROPOSAL + '/{proposalId}' }, - async (event) => { - const prev = event.data?.before?.data(); - const curr = event.data?.after?.data(); - if (!curr) { - return; - } +export const onProposalWrite = async (event: FirestoreDocEvent) => { + const { prev, curr } = event; + if (!curr) { + return; + } - if ( - isAddRemoveGuardianVote(curr) && - voteThresholdReached(prev, curr, ADD_REMOVE_GUARDIAN_THRESHOLD_PERCENTAGE) - ) { - return await onAddRemoveGuardianProposalApproved(curr); - } + if ( + isAddRemoveGuardianVote(curr) && + voteThresholdReached(prev, curr, ADD_REMOVE_GUARDIAN_THRESHOLD_PERCENTAGE) + ) { + return await onAddRemoveGuardianProposalApproved(curr); + } - if ( - curr.type === ProposalType.EDIT_SPACE && - voteThresholdReached(prev, curr, UPDATE_SPACE_THRESHOLD_PERCENTAGE) - ) { - return await onEditSpaceProposalApproved(curr); - } + if ( + curr.type === ProposalType.EDIT_SPACE && + voteThresholdReached(prev, curr, UPDATE_SPACE_THRESHOLD_PERCENTAGE) + ) { + return await onEditSpaceProposalApproved(curr); + } - if ( - curr.type === ProposalType.REMOVE_STAKE_REWARD && - voteThresholdReached(prev, curr, REMOVE_STAKE_REWARDS_THRESHOLD_PERCENTAGE) - ) { - return await onRemoveStakeRewardApporved(curr); - } - }, -); + if ( + curr.type === ProposalType.REMOVE_STAKE_REWARD && + voteThresholdReached(prev, curr, REMOVE_STAKE_REWARDS_THRESHOLD_PERCENTAGE) + ) { + return await onRemoveStakeRewardApporved(curr); + } +}; const isAddRemoveGuardianVote = (curr: Proposal) => [ProposalType.ADD_GUARDIAN, ProposalType.REMOVE_GUARDIAN].includes(curr.type); diff --git a/packages/functions/src/triggers/storage/resize.img.trigger.ts b/packages/functions/src/triggers/storage/resize.img.trigger.ts index 14d401b1db..a0cda19863 100644 --- a/packages/functions/src/triggers/storage/resize.img.trigger.ts +++ b/packages/functions/src/triggers/storage/resize.img.trigger.ts @@ -1,56 +1,47 @@ -import { IMAGE_CACHE_AGE, WEN_FUNC_TRIGGER } from '@build-5/interfaces'; +import { IMAGE_CACHE_AGE, ImageWidth } from '@build-5/interfaces'; import { path as ffmpegPath } from '@ffmpeg-installer/ffmpeg'; import { spawn } from 'child-process-promise'; -import * as functions from 'firebase-functions/v2'; import fs from 'fs'; import os from 'os'; import path from 'path'; import sharp from 'sharp'; import { build5Storage } from '../../firebase/storage/build5Storage'; import { IBucket } from '../../firebase/storage/interfaces'; -import { scale } from '../../scale.settings'; -import { getBucket } from '../../utils/config.utils'; import { getRandomEthAddress } from '../../utils/wallet.utils'; // eslint-disable-next-line @typescript-eslint/no-var-requires const ffprobePath = require('@ffprobe-installer/ffprobe').path; -export enum ImageWidth { - tb = '200', - md = '680', - lg = '1600', +export interface StorageObject { + metadata?: Record; + name: string; + bucket: string; + contentType?: string; } -export const resizeImageTrigger = functions.storage.onObjectFinalized( - { - memory: '4GiB', - minInstances: scale(WEN_FUNC_TRIGGER.resizeImg), - bucket: getBucket(), - }, - async (event) => { - if (event.data.metadata?.resized) { - return; +export const onStorageObjectFinalized = async (data: StorageObject) => { + if (!data || data.metadata?.resized) { + return; + } + + const workdir = `${os.tmpdir()}/${getRandomEthAddress()}`; + try { + fs.mkdirSync(workdir); + const downloadedMediaPath = await downloadMedia(workdir, data); + if (data.contentType?.startsWith('image/')) { + await uploadeResizedImages(workdir, data, downloadedMediaPath); + } else { + await uploadVideoPreview(workdir, data, downloadedMediaPath); } + } catch (error) { + console.error(error); + throw error; + } finally { + fs.rmSync(workdir, { recursive: true, force: true }); + } +}; - const workdir = `${os.tmpdir()}/${getRandomEthAddress()}`; - try { - fs.mkdirSync(workdir); - const downloadedMediaPath = await downloadMedia(workdir, event.data); - if (event.data.contentType?.startsWith('image/')) { - await uploadeResizedImages(workdir, event.data, downloadedMediaPath); - } else { - await uploadVideoPreview(workdir, event.data, downloadedMediaPath); - } - } catch (error) { - functions.logger.error(error); - throw error; - } finally { - fs.rmSync(workdir, { recursive: true, force: true }); - } - }, -); - -const downloadMedia = async (workdir: string, object: functions.storage.StorageObjectData) => { +const downloadMedia = async (workdir: string, object: StorageObject) => { const destination = path.join(workdir, path.basename(object.name!)); await build5Storage().bucket(object.bucket).download(object.name!, destination); return destination; @@ -58,7 +49,7 @@ const downloadMedia = async (workdir: string, object: functions.storage.StorageO const uploadeResizedImages = async ( workdir: string, - object: functions.storage.StorageObjectData, + object: StorageObject, downloadedImgPath: string, ) => { const extension = path.extname(downloadedImgPath); @@ -79,7 +70,7 @@ const uploadeResizedImages = async ( const uploadVideoPreview = async ( workdir: string, - object: functions.storage.StorageObjectData, + object: StorageObject, downloadedVideoPath: string, ) => { const extension = path.extname(downloadedVideoPath); 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 ff3fdc31cc..671c66d457 100644 --- a/packages/functions/src/triggers/token-trading/token-purchase.trigger.ts +++ b/packages/functions/src/triggers/token-trading/token-purchase.trigger.ts @@ -1,45 +1,31 @@ -import { - COL, - SUB_COL, - TokenPurchase, - TokenPurchaseAge, - WEN_FUNC_TRIGGER, -} from '@build-5/interfaces'; -import * as functions from 'firebase-functions/v2'; +import { COL, SUB_COL, TokenPurchase, TokenPurchaseAge } from '@build-5/interfaces'; import { build5Db } from '../../firebase/firestore/build5Db'; -import { scale } from '../../scale.settings'; +import { FirestoreDocEvent } from '../common'; -export const onTokenPurchaseCreated = functions.firestore.onDocumentCreated( - { - document: COL.TOKEN_PURCHASE + '/{docId}', - minInstances: scale(WEN_FUNC_TRIGGER.onTokenPurchaseCreated), - concurrency: 1000, - }, - async (event) => { - const data = event.data!.data(); - if (!data.token) { - return; - } - const batch = build5Db().batch(); +export const onTokenPurchaseCreated = async (event: FirestoreDocEvent) => { + const { curr } = event; + if (!curr || !curr.token) { + return; + } + const batch = build5Db().batch(); - const tokenDocRef = build5Db().doc(`${COL.TOKEN}/${data.token}`); - const statsDocRef = tokenDocRef.collection(SUB_COL.STATS).doc(data.token); - const volume = Object.values(TokenPurchaseAge).reduce( - (acc, act) => ({ ...acc, [act]: build5Db().inc(data.count) }), - {}, - ); - const statsData = { - parentId: data.token, - parentCol: COL.TOKEN, - volumeTotal: build5Db().inc(data.count), - volume, - }; - batch.set(statsDocRef, statsData, true); + 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 = { + parentId: curr.token, + parentCol: COL.TOKEN, + volumeTotal: build5Db().inc(curr.count), + volume, + }; + batch.set(statsDocRef, statsData, true); - const purchaseDocRef = build5Db().doc(`${COL.TOKEN_PURCHASE}/${data.uid}`); - const age = Object.values(TokenPurchaseAge).reduce((acc, act) => ({ ...acc, [act]: true }), {}); - batch.update(purchaseDocRef, { age }); + const purchaseDocRef = build5Db().doc(`${COL.TOKEN_PURCHASE}/${curr.uid}`); + const age = Object.values(TokenPurchaseAge).reduce((acc, act) => ({ ...acc, [act]: true }), {}); + batch.update(purchaseDocRef, { age }); - await batch.commit(); - }, -); + await batch.commit(); +}; 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 e7d76310b7..4ee79bd33f 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 @@ -7,50 +7,37 @@ import { TokenTradeOrder, TokenTradeOrderStatus, TokenTradeOrderType, - WEN_FUNC_TRIGGER, } from '@build-5/interfaces'; -import * as functions from 'firebase-functions/v2'; -import { DocumentOptions } from 'firebase-functions/v2/firestore'; import bigDecimal from 'js-big-decimal'; import { build5Db } from '../../firebase/firestore/build5Db'; -import { scale } from '../../scale.settings'; import { getStakeForType, getTier } from '../../services/stake.service'; import { cancelTradeOrderUtil } from '../../utils/token-trade.utils'; import { BIG_DECIMAL_PRECISION, getSoonToken } from '../../utils/token.utils'; +import { FirestoreDocEvent } from '../common'; import { matchTradeOrder } from './match-token'; -const runParams = { - document: `${COL.TOKEN_MARKET}/{tradeId}`, - timeoutSeconds: 540, - minInstances: scale(WEN_FUNC_TRIGGER.onTokenTradeOrderWrite), -} as DocumentOptions; +export const onTokenTradeOrderWrite = async (event: FirestoreDocEvent) => { + const { prev, curr } = event; + if (!curr) { + return; + } -export const onTokenTradeOrderWrite = functions.firestore.onDocumentWritten( - runParams, - async (event) => { - const prev = event.data?.before?.data(); - const next = event.data?.after?.data(); - if (!next) { - return; - } + if (!prev || (!prev.shouldRetry && curr?.shouldRetry)) { + return await matchTradeOrder(curr); + } - if (!prev || (!prev.shouldRetry && next?.shouldRetry)) { - return await matchTradeOrder(next); + return await build5Db().runTransaction(async (transaction) => { + const tradeOrderDocRef = build5Db().doc(`${COL.TOKEN_MARKET}/${curr.uid}`); + const tradeOrder = await transaction.get(tradeOrderDocRef); + if (tradeOrder && isActiveBuy(tradeOrder) && needsHigherBuyAmount(tradeOrder!)) { + await cancelTradeOrderUtil( + transaction, + tradeOrder, + TokenTradeOrderStatus.CANCELLED_UNFULFILLABLE, + ); } - - return await build5Db().runTransaction(async (transaction) => { - const tradeOrderDocRef = build5Db().doc(`${COL.TOKEN_MARKET}/${next.uid}`); - const tradeOrder = await transaction.get(tradeOrderDocRef); - if (tradeOrder && isActiveBuy(tradeOrder) && needsHigherBuyAmount(tradeOrder!)) { - await cancelTradeOrderUtil( - transaction, - tradeOrder, - TokenTradeOrderStatus.CANCELLED_UNFULFILLABLE, - ); - } - }); - }, -); + }); +}; const isActiveBuy = (sale?: TokenTradeOrder) => sale?.type === TokenTradeOrderType.BUY && sale?.status === TokenTradeOrderStatus.ACTIVE; diff --git a/packages/functions/src/triggers/token.trigger.ts b/packages/functions/src/triggers/token.trigger.ts index f857f22587..fcb897348f 100644 --- a/packages/functions/src/triggers/token.trigger.ts +++ b/packages/functions/src/triggers/token.trigger.ts @@ -15,14 +15,11 @@ import { Transaction, TransactionPayloadType, TransactionType, - WEN_FUNC_TRIGGER, } from '@build-5/interfaces'; -import * as functions from 'firebase-functions/v2'; import bigDecimal from 'js-big-decimal'; import { isEmpty } from 'lodash'; import { build5Db } from '../firebase/firestore/build5Db'; import { IBatch } from '../firebase/firestore/interfaces'; -import { scale } from '../scale.settings'; import { WalletService } from '../services/wallet/wallet.service'; import { getAddress } from '../utils/address.utils'; import { downloadMediaAndPackCar, tokenToIpfsMetadata } from '../utils/car.utils'; @@ -37,35 +34,27 @@ import { orderDocRef, } from '../utils/token.utils'; import { getRandomEthAddress } from '../utils/wallet.utils'; +import { FirestoreDocEvent } from './common'; -export const onTokenStatusUpdate = functions.firestore.onDocumentUpdated( - { - timeoutSeconds: 540, - memory: '4GiB', - minInstances: scale(WEN_FUNC_TRIGGER.onTokenStatusUpdate), - document: COL.TOKEN + '/{tokenId}', - }, - async (event) => { - const prev = event.data?.before?.data(); - const curr = event.data?.after?.data(); - - if (prev?.status === TokenStatus.AVAILABLE && curr?.status === TokenStatus.PROCESSING) { - return await processTokenDistribution(curr!); - } +export const onTokenStatusUpdated = async (event: FirestoreDocEvent) => { + const { prev, curr } = event; - if (prev?.status !== curr?.status && curr?.status === TokenStatus.CANCEL_SALE) { - return await cancelPublicSale(curr!); - } + if (prev?.status === TokenStatus.AVAILABLE && curr?.status === TokenStatus.PROCESSING) { + return await processTokenDistribution(curr!); + } - if (prev?.status !== curr?.status && curr?.status === TokenStatus.MINTING) { - return await mintToken(curr); - } + if (prev?.status !== curr?.status && curr?.status === TokenStatus.CANCEL_SALE) { + return await cancelPublicSale(curr!); + } - if (prev?.mintingData?.tokensInVault && curr?.mintingData?.tokensInVault === 0) { - await onTokenVaultEmptied(curr); - } - }, -); + if (prev?.status !== curr?.status && curr?.status === TokenStatus.MINTING) { + return await mintToken(curr); + } + + if (prev?.mintingData?.tokensInVault && curr?.mintingData?.tokensInVault === 0) { + await onTokenVaultEmptied(curr); + } +}; const getTokenCount = (token: Token, amount: number) => Math.floor(amount / token.pricePerToken); @@ -342,7 +331,7 @@ const cancelPublicSale = async (token: Token) => { await build5Db().doc(`${COL.TOKEN}/${token.uid}`).update({ status }); if (status === TokenStatus.ERROR) { - functions.logger.error('Token processing error', token.uid, errors); + console.error('Token processing error', token.uid, errors); } }; @@ -376,7 +365,7 @@ const processTokenDistribution = async (token: Token) => { await build5Db().doc(`${COL.TOKEN}/${token.uid}`).update({ status }); if (status === TokenStatus.ERROR) { - functions.logger.error('Token processing error', token.uid, errors); + console.error('Token processing error', token.uid, errors); } }; diff --git a/packages/functions/src/triggers/transaction-trigger/collection-minting.ts b/packages/functions/src/triggers/transaction-trigger/collection-minting.ts index 28d3d7084d..e7deca8614 100644 --- a/packages/functions/src/triggers/transaction-trigger/collection-minting.ts +++ b/packages/functions/src/triggers/transaction-trigger/collection-minting.ts @@ -10,7 +10,6 @@ import { } from '@build-5/interfaces'; import { TransactionPayload, Utils } from '@iota/sdk'; import dayjs from 'dayjs'; -import * as functions from 'firebase-functions/v2'; import { get } from 'lodash'; import { build5Db } from '../../firebase/firestore/build5Db'; import { getAddress } from '../../utils/address.utils'; @@ -39,7 +38,7 @@ export const onCollectionMintingUpdate = async (transaction: Transaction) => { break; } default: { - functions.logger.error('Unsupported executable transaction type', transaction); + console.error('Unsupported executable transaction type', transaction); throw Error('Unsupported executable transaction type ' + transaction.type); } } diff --git a/packages/functions/src/triggers/transaction-trigger/token-minting.ts b/packages/functions/src/triggers/transaction-trigger/token-minting.ts index 700410e4c3..8fd7365042 100644 --- a/packages/functions/src/triggers/transaction-trigger/token-minting.ts +++ b/packages/functions/src/triggers/transaction-trigger/token-minting.ts @@ -17,7 +17,6 @@ import { Utils, } from '@iota/sdk'; import dayjs from 'dayjs'; -import * as functions from 'firebase-functions/v2'; import { build5Db } from '../../firebase/firestore/build5Db'; import { getAddress } from '../../utils/address.utils'; import { getRandomEthAddress } from '../../utils/wallet.utils'; @@ -37,7 +36,7 @@ export const onTokenMintingUpdate = async (transaction: Transaction) => { break; } default: { - functions.logger.error('Unsupported executable transaction type', transaction); + console.error('Unsupported executable transaction type', transaction); throw Error('Unsupported executable transaction type ' + transaction.type); } } diff --git a/packages/functions/src/triggers/transaction-trigger/transaction.trigger.ts b/packages/functions/src/triggers/transaction-trigger/transaction.trigger.ts index 9fb1b6d971..5fe119c012 100644 --- a/packages/functions/src/triggers/transaction-trigger/transaction.trigger.ts +++ b/packages/functions/src/triggers/transaction-trigger/transaction.trigger.ts @@ -9,15 +9,12 @@ import { Transaction, TransactionPayloadType, TransactionType, - WEN_FUNC_TRIGGER, WalletResult, } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import * as functions from 'firebase-functions/v2'; import { isEmpty } from 'lodash'; import { build5Db } from '../../firebase/firestore/build5Db'; import { ITransaction } from '../../firebase/firestore/interfaces'; -import { scale } from '../../scale.settings'; import { AliasWallet } from '../../services/wallet/AliasWallet'; import { NativeTokenWallet } from '../../services/wallet/NativeTokenWallet'; import { NftWallet } from '../../services/wallet/NftWallet'; @@ -27,6 +24,7 @@ import { getAddress } from '../../utils/address.utils'; import { isEmulatorEnv } from '../../utils/config.utils'; import { serverTime } from '../../utils/dateTime.utils'; import { getRandomEthAddress } from '../../utils/wallet.utils'; +import { FirestoreDocEvent } from '../common'; import { unclockMnemonic } from '../milestone-transactions-triggers/common'; import { onAirdropClaim } from './airdrop.claim'; import { onAwardUpdate } from './award.transaction.update'; @@ -60,131 +58,113 @@ export const EXECUTABLE_TRANSACTIONS = [ ...CREDIT_EXECUTABLE_TRANSACTIONS, ]; -export const transactionWrite = functions.firestore.onDocumentWritten( - { - document: COL.TRANSACTION + '/{tranId}', - timeoutSeconds: 540, - minInstances: scale(WEN_FUNC_TRIGGER.transactionWrite), - memory: '4GiB', - }, - async (event) => { - const prev = event.data?.before?.data(); - const curr = event.data?.after?.data(); - - if (!curr) { - return; - } +export const onTransactionWrite = async (event: FirestoreDocEvent) => { + const { prev, curr } = event; + if (!curr) { + return; + } - const isExecutableType = EXECUTABLE_TRANSACTIONS.includes(curr.type); - const isCreate = prev === undefined; - const shouldRetry = !prev?.shouldRetry && curr?.shouldRetry; + const isExecutableType = EXECUTABLE_TRANSACTIONS.includes(curr.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 }); - } + if (isCreate) { + const docRef = build5Db().doc(`${COL.TRANSACTION}/${curr.uid}`); + await docRef.update({ isOrderType: curr.type === TransactionType.ORDER }); + } - if (isExecutableType && !curr?.ignoreWallet && (isCreate || shouldRetry)) { - return await executeTransaction(curr.uid); - } + if (isExecutableType && !curr?.ignoreWallet && (isCreate || shouldRetry)) { + return await executeTransaction(curr.uid); + } - if ( - curr.payload.type === TransactionPayloadType.AIRDROP_MINTED_TOKEN && - prev?.payload?.unclaimedAirdrops && - curr.payload.unclaimedAirdrops === 0 - ) { - await onMintedAirdropCleared(curr); - return; - } + if ( + 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)) { - await onCollectionMintingUpdate(curr); - return; - } + if (curr.type === TransactionType.MINT_COLLECTION && isConfirmed(prev, curr)) { + await onCollectionMintingUpdate(curr); + return; + } - if (curr.type === TransactionType.MINT_TOKEN && isConfirmed(prev, curr)) { - await onTokenMintingUpdate(curr); - return; - } + if (curr.type === TransactionType.MINT_TOKEN && isConfirmed(prev, curr)) { + await onTokenMintingUpdate(curr); + return; + } - if (curr.type === TransactionType.CREDIT_STORAGE_DEPOSIT_LOCKED && isConfirmed(prev, curr)) { - await build5Db() - .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 || '', - ), - }); - return; - } + if (curr.type === TransactionType.CREDIT_STORAGE_DEPOSIT_LOCKED && isConfirmed(prev, curr)) { + await build5Db() + .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 || '', + ), + }); + return; + } - if ( - curr.type === TransactionType.BILL_PAYMENT && - isConfirmed(prev, curr) && - !isEmpty(curr.payload.stake) - ) { - await onStakingConfirmed(curr); - return; - } + if ( + curr.type === TransactionType.BILL_PAYMENT && + isConfirmed(prev, curr) && + !isEmpty(curr.payload.stake) + ) { + await onStakingConfirmed(curr); + return; + } - const airdropOrderTypes = [ - TransactionPayloadType.TOKEN_AIRDROP, - TransactionPayloadType.CLAIM_MINTED_TOKEN, - TransactionPayloadType.CLAIM_BASE_TOKEN, - ]; - if ( - airdropOrderTypes.includes(curr.payload.type!) && - !prev?.payload.reconciled && - curr.payload.reconciled - ) { - await onAirdropClaim(curr); - return; - } + const airdropOrderTypes = [ + TransactionPayloadType.TOKEN_AIRDROP, + TransactionPayloadType.CLAIM_MINTED_TOKEN, + TransactionPayloadType.CLAIM_BASE_TOKEN, + ]; + if ( + airdropOrderTypes.includes(curr.payload.type!) && + !prev?.payload.reconciled && + curr.payload.reconciled + ) { + await onAirdropClaim(curr); + return; + } - if ( - isConfirmed(prev, curr) && - curr.payload.proposalId && - curr.type === TransactionType.CREDIT - ) { - await onProposalVoteCreditConfirmed(curr); - return; - } + if (isConfirmed(prev, curr) && curr.payload.proposalId && curr.type === TransactionType.CREDIT) { + await onProposalVoteCreditConfirmed(curr); + return; + } - if ( - isConfirmed(prev, curr) && - curr.payload.weeks && - curr.type === TransactionType.WITHDRAW_NFT - ) { - await onNftStaked(curr); - return; - } + if (isConfirmed(prev, curr) && curr.payload.weeks && curr.type === TransactionType.WITHDRAW_NFT) { + await onNftStaked(curr); + return; + } - if (isConfirmed(prev, curr) && curr.type === TransactionType.AWARD) { - await onAwardUpdate(curr); - return; - } + if (isConfirmed(prev, curr) && curr.type === TransactionType.AWARD) { + await onAwardUpdate(curr); + return; + } - if (isConfirmed(prev, curr) && curr.type === TransactionType.METADATA_NFT) { - await onMetadataNftMintUpdate(curr); - return; - } + if (isConfirmed(prev, curr) && curr.type === TransactionType.METADATA_NFT) { + await onMetadataNftMintUpdate(curr); + return; + } - if ( - isConfirmed(prev, curr) && - curr.payload.award && - curr.payload.type === TransactionPayloadType.MINTED_AIRDROP_CLAIM - ) { - const awardDocRef = build5Db().doc(`${COL.AWARD}/${curr.payload.award}`); - await awardDocRef.update({ airdropClaimed: build5Db().inc(1) }); - } - }, -); + if ( + isConfirmed(prev, curr) && + curr.payload.award && + curr.payload.type === TransactionPayloadType.MINTED_AIRDROP_CLAIM + ) { + const awardDocRef = build5Db().doc(`${COL.AWARD}/${curr.payload.award}`); + await awardDocRef.update({ airdropClaimed: build5Db().inc(1) }); + } +}; const executeTransaction = async (transactionId: string) => { const shouldProcess = await prepareTransaction(transactionId); @@ -239,7 +219,7 @@ const executeTransaction = async (transactionId: string) => { } default: { - functions.logger.error('Unsupported executable transaction type', transaction); + console.error('Unsupported executable transaction type', transaction); throw Error('Unsupported executable transaction type ' + transaction.type); } } @@ -252,7 +232,7 @@ const executeTransaction = async (transactionId: string) => { 'payload.walletReference.chainReferences': build5Db().arrayUnion(chainReference), }); } catch (error) { - functions.logger.error(transaction.uid, error); + console.error(transaction.uid, error); await docRef.update({ 'payload.walletReference.chainReference': null, 'payload.walletReference.processedOn': dayjs().toDate(), @@ -289,7 +269,7 @@ const submitCollectionMintTransactions = ( return aliasWallet.changeAliasOwner(transaction, params); } default: { - functions.logger.error('Unsupported executable transaction type', transaction); + console.error('Unsupported executable transaction type', transaction); throw Error('Unsupported executable transaction type ' + transaction.payload.type); } } @@ -314,7 +294,7 @@ const submitTokenMintTransactions = ( return aliasWallet.changeAliasOwner(transaction, params); } default: { - functions.logger.error('Unsupported executable transaction type', transaction); + console.error('Unsupported executable transaction type', transaction); throw Error('Unsupported executable transaction type ' + transaction.payload.type); } } @@ -343,7 +323,7 @@ const submitCreateAwardTransaction = ( return aliasWallet.burnAlias(transaction, params); } default: { - functions.logger.error( + console.error( 'Unsupported executable transaction type in submitCreateAwardTransaction', transaction, ); @@ -375,7 +355,7 @@ const submitMintMetadataTransaction = async ( return nftWallet.updateMetadataNft(transaction, params); } default: { - functions.logger.error( + console.error( 'Unsupported executable transaction type in submitCreateAwardTransaction', transaction, ); @@ -406,7 +386,7 @@ const submitUnlockTransaction = async ( return nftWallet.changeNftOwner(transaction, params); } default: { - functions.logger.error('Unsupported executable transaction type', transaction); + console.error('Unsupported executable transaction type', transaction); throw Error('Unsupported executable transaction type ' + transaction.payload.type); } } diff --git a/packages/functions/src/utils/car.utils.ts b/packages/functions/src/utils/car.utils.ts index 375cf265d8..18a8b2ec95 100644 --- a/packages/functions/src/utils/car.utils.ts +++ b/packages/functions/src/utils/car.utils.ts @@ -2,7 +2,6 @@ import { Collection, KEY_NAME_TANGLE, Nft, Token } from '@build-5/interfaces'; import { CarReader } from '@ipld/car'; import * as dagPb from '@ipld/dag-pb'; import { randomUUID } from 'crypto'; -import * as functions from 'firebase-functions/v2'; import fs from 'fs'; import { FsBlockStore as Blockstore } from 'ipfs-car/blockstore/fs'; import { pack } from 'ipfs-car/pack'; @@ -28,7 +27,7 @@ export const packCar = async (directory: string) => { const car = await CarReader.fromIterable(out); return { car, cid: root.toString() }; } catch (error) { - functions.logger.error('Pack car error', error); + console.error('Pack car error', error); throw error; } finally { await blockstore.close(); diff --git a/packages/functions/src/utils/error.utils.ts b/packages/functions/src/utils/error.utils.ts index ee8d58e6ad..282cfc6d7f 100644 --- a/packages/functions/src/utils/error.utils.ts +++ b/packages/functions/src/utils/error.utils.ts @@ -1,5 +1,6 @@ import { FunctionsErrorCode } from 'firebase-functions/v1/https'; import * as functions from 'firebase-functions/v2'; + interface Error { readonly key?: string; } diff --git a/packages/functions/src/utils/google.utils.ts b/packages/functions/src/utils/google.utils.ts deleted file mode 100644 index e3da2b08fa..0000000000 --- a/packages/functions/src/utils/google.utils.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { AppCheck, WenError } from '@build-5/interfaces'; -import * as functions from 'firebase-functions/v2'; -import { isProdEnv } from './config.utils'; -import { invalidArgument } from './error.utils'; - -const APP_CHECK_ERROR = 'The function must be called from an App Check verified app.'; - -export function appCheck(func: string, request: functions.https.CallableRequest) { - if (!request.app && AppCheck.enabled && isProdEnv()) { - functions.logger.warn('failed-app-check', APP_CHECK_ERROR, { func }); - throw invalidArgument(WenError.unapproved_site); - } -} diff --git a/packages/functions/src/utils/media.utils.ts b/packages/functions/src/utils/media.utils.ts index fb06db7b4a..f942152dac 100644 --- a/packages/functions/src/utils/media.utils.ts +++ b/packages/functions/src/utils/media.utils.ts @@ -8,7 +8,6 @@ import { } from '@build-5/interfaces'; import axios from 'axios'; import { randomUUID } from 'crypto'; -import * as functions from 'firebase-functions/v2'; import fs from 'fs'; import mime from 'mime-types'; import os from 'os'; @@ -42,7 +41,7 @@ export const migrateUriToSotrage = async ( return `https://${bucket.getName()}/${owner}/${uid}/${fileName}`; // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (error: any) { - functions.logger.error(col, uid, error); + console.error(col, uid, error); throw error.code && error.key ? error : WenError.ipfs_retrieve; } finally { fs.rmSync(workdir, { recursive: true, force: true }); diff --git a/packages/functions/src/utils/schema.utils.ts b/packages/functions/src/utils/schema.utils.ts index 7e89710ada..0c900a472f 100644 --- a/packages/functions/src/utils/schema.utils.ts +++ b/packages/functions/src/utils/schema.utils.ts @@ -1,5 +1,4 @@ import { WenError } from '@build-5/interfaces'; -import * as functions from 'firebase-functions/v2'; import Joi, { AnySchema, ValidationResult } from 'joi'; import { head } from 'lodash'; import { isStorageUrl } from '../services/joi/common'; @@ -10,7 +9,7 @@ import { fileExists } from './storage.utils'; const assertValidation = (r: ValidationResult) => { if (r.error) { const detail = head(r.error.details); - isProdEnv() && functions.logger.warn('invalid-argument', 'Invalid argument', { func: r.error }); + isProdEnv() && console.warn('invalid-argument', 'Invalid argument', { func: r.error }); throw invalidArgument( WenError.invalid_params, detail ? `${detail.message || ''}. ${detail.context?.message || ''}` : '', 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 c3a78c4871..a8c8f6fe6a 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 @@ -149,7 +149,6 @@ const saveToken = async (space: string, guardian: string, network: Network) => { }; export const VAULT_MNEMONIC = - 'media income depth opera health hybrid person expect supply kid napkin science maze believe they inspire hockey random escape size below monkey lemon veteran'; - + 'wise push option delay harvest reward equal sketch seed mystery cruise exact photo cabbage ill clump pen lab orphan cradle creek march install health'; export const MINTED_TOKEN_ID = - '0x08f56bb2eefc47c050e67f8ba85d4a08e1de5ac0580fb9e80dc2f62eab97f944350100000000'; + '0x08a7a6e15732dac0262fd0e102dd293acdf1eb5cc9cd45512ab818fb7bae4aebff0100000000'; diff --git a/packages/functions/test-tangle/award/award_10.spec.ts b/packages/functions/test-tangle/award/award_10.spec.ts index a366579101..3bb9350e5c 100644 --- a/packages/functions/test-tangle/award/award_10.spec.ts +++ b/packages/functions/test-tangle/award/award_10.spec.ts @@ -130,7 +130,6 @@ const saveToken = async (space: string, guardian: string) => { }; export const VAULT_MNEMONIC = - 'media income depth opera health hybrid person expect supply kid napkin science maze believe they inspire hockey random escape size below monkey lemon veteran'; - + 'unfair traffic retire voyage timber guide label amateur armed gadget fatigue retreat quiz belt century entire accuse what inner ticket can general giggle latin'; export const MINTED_TOKEN_ID = - '0x08f56bb2eefc47c050e67f8ba85d4a08e1de5ac0580fb9e80dc2f62eab97f944350100000000'; + '0x08d6fdcd4e3bea675746239a3b411294d4c40774be59081e6bbc61e3424b6590ff0100000000'; diff --git a/packages/functions/test-tangle/award/award_2.spec.ts b/packages/functions/test-tangle/award/award_2.spec.ts index 314d115175..cdc6480bbe 100644 --- a/packages/functions/test-tangle/award/award_2.spec.ts +++ b/packages/functions/test-tangle/award/award_2.spec.ts @@ -245,7 +245,6 @@ const saveToken = async (space: string, guardian: string) => { }; export const VAULT_MNEMONIC = - 'media income depth opera health hybrid person expect supply kid napkin science maze believe they inspire hockey random escape size below monkey lemon veteran'; - + 'cruel pass athlete east topple metal glove reward banana lunch sight jelly guess coil labor swim sniff orphan ramp tackle month panel surface real'; export const MINTED_TOKEN_ID = - '0x08f56bb2eefc47c050e67f8ba85d4a08e1de5ac0580fb9e80dc2f62eab97f944350100000000'; + '0x086d27c57107bd6e4b8e0a5e8827ffb30b4bd6acfc780af7d950e232f1b065f7a00100000000'; diff --git a/packages/functions/test-tangle/award/award_5.spec.ts b/packages/functions/test-tangle/award/award_5.spec.ts index fa8ecb08d4..2add1ac634 100644 --- a/packages/functions/test-tangle/award/award_5.spec.ts +++ b/packages/functions/test-tangle/award/award_5.spec.ts @@ -234,7 +234,6 @@ const saveToken = async (space: string, guardian: string) => { }; export const VAULT_MNEMONIC = - 'media income depth opera health hybrid person expect supply kid napkin science maze believe they inspire hockey random escape size below monkey lemon veteran'; - + 'lift primary tornado antenna confirm smoke oxygen rescue drift tenant mirror small barrel people predict elevator retreat hold various adjust keep decade valve scheme'; export const MINTED_TOKEN_ID = - '0x08f56bb2eefc47c050e67f8ba85d4a08e1de5ac0580fb9e80dc2f62eab97f944350100000000'; + '0x08c9c7b7e22a43ed9f14fdcc876bd9fb56e10ccac4b3c2299013d71b363db801a40100000000'; diff --git a/packages/functions/test-tangle/award/award_7.spec.ts b/packages/functions/test-tangle/award/award_7.spec.ts index a220ee07bf..388f8067d3 100644 --- a/packages/functions/test-tangle/award/award_7.spec.ts +++ b/packages/functions/test-tangle/award/award_7.spec.ts @@ -202,7 +202,6 @@ const saveToken = async (space: string, guardian: string) => { }; export const VAULT_MNEMONIC = - 'media income depth opera health hybrid person expect supply kid napkin science maze believe they inspire hockey random escape size below monkey lemon veteran'; - + 'figure random fitness double guard write auction penalty mimic office capital asthma laptop rifle club chuckle organ era prepare unit road echo bundle shrug'; export const MINTED_TOKEN_ID = - '0x08f56bb2eefc47c050e67f8ba85d4a08e1de5ac0580fb9e80dc2f62eab97f944350100000000'; + '0x08f33de73663373e0c0fa11cb4c93bf83c7905357573882a21a001d2ddc176d57e0100000000'; diff --git a/packages/functions/test-tangle/award/award_9.spec.ts b/packages/functions/test-tangle/award/award_9.spec.ts index 96dbf38b9e..c823ff0c88 100644 --- a/packages/functions/test-tangle/award/award_9.spec.ts +++ b/packages/functions/test-tangle/award/award_9.spec.ts @@ -150,4 +150,4 @@ const saveToken = async (space: string, guardian: string) => { }; const MINTED_TOKEN_ID = - '0x08f56bb2eefc47c050e67f8ba85d4a08e1de5ac0580fb9e80dc2f62eab97f944350100000000'; + '0x0833fb03653c5312a4d02b03c1999c4d03f43c532431cc8684f3941a69bd32fbb90100000000'; diff --git a/packages/functions/test-tangle/faucet.ts b/packages/functions/test-tangle/faucet.ts index 88b924eca6..3390dda633 100644 --- a/packages/functions/test-tangle/faucet.ts +++ b/packages/functions/test-tangle/faucet.ts @@ -31,7 +31,7 @@ export const requestFundsFromFaucet = async ( ? { expiresAt, returnAddressBech32: faucetAddress.bech32 } : undefined, }); - const ledgerInclusionState = await awaitLedgerInclusionState(blockId, network); + const ledgerInclusionState = await awaitLedgerInclusionState(blockId); if (ledgerInclusionState === 'included') { return { blockId, faucetAddress }; } @@ -55,7 +55,7 @@ export const requestFundsForManyFromFaucet = async ( try { await MnemonicService.store(faucetAddress.bech32, faucetAddress.mnemonic, network); const blockId = await wallet.sendToMany(faucetAddress, targets, {}); - const ledgerInclusionState = await awaitLedgerInclusionState(blockId, network); + const ledgerInclusionState = await awaitLedgerInclusionState(blockId); if (ledgerInclusionState === 'included') { return blockId; } @@ -86,7 +86,7 @@ export const requestMintedTokenFromFaucet = async ( nativeTokens: [{ id: tokenId, amount: BigInt(amount) }], storageDepositSourceAddress: targetAddress.bech32, }); - const ledgerInclusionState = await awaitLedgerInclusionState(blockId, Network.RMS); + const ledgerInclusionState = await awaitLedgerInclusionState(blockId); if (ledgerInclusionState === 'included') { return blockId; } @@ -100,7 +100,7 @@ export const requestMintedTokenFromFaucet = async ( throw Error('Could not get native tokens from faucet'); }; -export const awaitLedgerInclusionState = async (blockId: string, network: Network) => { +export const awaitLedgerInclusionState = async (blockId: string) => { let ledgerInclusionState: string | undefined = ''; const client = new Client({ nodes: ['https://api.testnet.shimmer.network'] }); await wait(async () => { 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 5b077cec78..3e618b0e0e 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 @@ -45,7 +45,7 @@ describe('Minted nft trading', () => { ); await MnemonicService.store(address.bech32, address.mnemonic, Network.RMS); - await awaitLedgerInclusionState(blockId, helper.tangleOrder.network); + await awaitLedgerInclusionState(blockId); await helper.walletService!.send( address, 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 9e0a367bd5..4d4bee408e 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 @@ -47,7 +47,7 @@ describe('Minted nft trading', () => { ); await MnemonicService.store(address.bech32, address.mnemonic, Network.RMS); - await awaitLedgerInclusionState(blockId, helper.tangleOrder.network); + await awaitLedgerInclusionState(blockId); await helper.walletService!.send( address, diff --git a/packages/functions/test-tangle/minted-token-airdrop/Helper.ts b/packages/functions/test-tangle/minted-token-airdrop/Helper.ts index a38746310d..ca2bcbc428 100644 --- a/packages/functions/test-tangle/minted-token-airdrop/Helper.ts +++ b/packages/functions/test-tangle/minted-token-airdrop/Helper.ts @@ -83,6 +83,6 @@ export const dummyTokenId = '0x080c409a8c0ffa795676e55f24e0223e5b48dbe2b1bc4314140333543b5e7e8d360100000000'; export const VAULT_MNEMONIC = - 'add peanut behind flame hundred luxury dress loan anger depth tag round elbow damage celery clever crew question enlist near gun differ when already'; + 'pipe jump moment hybrid palm faint wait minute sustain crane income unable hobby antique bleak advance deputy mandate explain clip deal viable sponsor silly'; export const MINTED_TOKEN_ID = - '0x08d5d8c4f4139a3d09e780edd4826162c095b787ab94af7425c0d079b0b8e4302e0100000000'; + '0x08774bcb5848829764241e1bd5b1a8ebb6da08f22e88c2f656d1fa4deafb3217bc0100000000'; 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 95288c80b5..6d26d27b0b 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 @@ -44,7 +44,7 @@ describe('Token minting', () => { }); }); -const VAULT_MNEMONIC = - 'suit buyer board limit suspect cycle month promote wolf company smile salt banner arrest burden raccoon chat ridge novel gallery diary roast coach visual'; -const MINTED_TOKEN_ID = - '0x084880278c0a02f22f3fe388edd51a340be1c22e31a572307e44296d639bf359d80100000000'; +export const VAULT_MNEMONIC = + 'egg festival about walnut drama exclude thrive chest edge hollow miss civil turkey april toast survey already mail sign fire exile rack kidney wagon'; +export const MINTED_TOKEN_ID = + '0x0844694a6b67ba375246148afd9cca94d7a3d06e91d77c51f2cc4e68dcb69508ba0100000000'; 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 18b7ebca08..a029cf229b 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 @@ -73,7 +73,7 @@ describe('Token minting', () => { }); }); -const VAULT_MNEMONIC = - 'tuna all present setup soldier cup pluck sponsor act grit top uncover flash mammal tilt liquid truck expose snack best swift shove slab adjust'; -const MINTED_TOKEN_ID = - '0x08aecdbb63390b390b3234716b2435fd2beee03490181685ee4810173eb0ba1a3d0100000000'; +export const VAULT_MNEMONIC = + 'ball rack trash outside mix decade detail unfair select dad concert praise erupt urge cabbage cruise program knock daughter dinosaur exhaust rhythm innocent portion'; +export const MINTED_TOKEN_ID = + '0x08554b7257adc1a7a0d4eea5b3d7d146ce473720f349d17a7bfc31f41c43c22a930100000000'; 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 96674080c7..6835d176d2 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 @@ -52,7 +52,7 @@ describe('Token minting', () => { }); }); -const VAULT_MNEMONIC = - 'jealous switch narrow pen coil addict gospel rotate episode second acid gift off shock duty weapon profit merry utility snap erode author someone cute'; -const MINTED_TOKEN_ID = - '0x08b2bc19206a801a09a57f18f3c8737ac967bb868e04e0f45043ccccce7d2bbea70100000000'; +export const VAULT_MNEMONIC = + 'put crisp lecture fine axis route tomato impact analyst insane arm exercise surprise pistol angry sing foil plug medal error extra spatial tongue indoor'; +export const MINTED_TOKEN_ID = + '0x0810f989d9e3f66d147eb8ae6ec102ccbbb419a1b4202df7363f339d279883866c0100000000'; 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 69316b34f4..18c704a3a6 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 @@ -78,7 +78,7 @@ describe('Token minting', () => { }); }); -const VAULT_MNEMONIC = - 'senior orphan field peasant pioneer fox enjoy excite denial lyrics crowd wash peasant chat taxi jungle copper awesome item demand roast spread couple cube'; -const MINTED_TOKEN_ID = - '0x08f5bee0f3a87cbf93cd9b5395fb185edb85a09a9548b67b13f578098b77970a330100000000'; +export const VAULT_MNEMONIC = + 'question lunch output credit rabbit issue leopard property region egg master engage brief boost resist panda long snow inform whisper second faculty honey super'; +export const MINTED_TOKEN_ID = + '0x08516cf8ebcf220dbbc3dd5dd9cfc6b8ad9a69d598b3ab951268415a55a03ba7520100000000'; 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 623adaf6e5..25a8c335cc 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 @@ -52,7 +52,7 @@ describe('Token minting', () => { }); }); -const VAULT_MNEMONIC = - 'silent boost spin repeat scene planet similar sibling pink rely require castle enact drum fashion menu room cattle argue over carpet sustain slow artist'; -const MINTED_TOKEN_ID = - '0x08be19ed1c31bae0f1f3aa17be7f3de0ead117e012f94c1d9448a0628ab6c4d2ec0100000000'; +export const VAULT_MNEMONIC = + 'wreck detail wheat pony leg rib grit width clog nominee giggle behave beef boy help maple robot avocado orphan spider exist hair fury tomato'; +export const MINTED_TOKEN_ID = + '0x08e855e4178b569d03e6866aebda32ac8de6926a98d286bdd35ff72cdffbcc92a80100000000'; 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 dce99b91d7..03cd2f8c2f 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 @@ -41,7 +41,7 @@ describe('Token minting', () => { }); }); -const VAULT_MNEMONIC = - 'you right side purity bracket orphan control strong affair east pet bean future file spy wet witness flat garden flavor mechanic path load amused'; -const MINTED_TOKEN_ID = - '0x08a0dfb75950fc14feb84f6152aa41d518959831f8f4253ec355ee1dab5747f37e0100000000'; +export const VAULT_MNEMONIC = + 'grief supreme rural sugar coral finish muffin giraffe require slice hurdle annual opera concert skirt enough hood hollow clip inner home return almost regular'; +export const MINTED_TOKEN_ID = + '0x083e0ec0612f9429e95cc23bc9110a2a119a65f0a4cdf5cccabb99bb135e5afb590100000000'; 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 649b345d6d..f8a71b3cb0 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 @@ -82,7 +82,7 @@ describe('Token minting', () => { }); }); -const VAULT_MNEMONIC = - 'able seek despair task prize rack isolate usual select tooth minor seed empower pulp venture tourist castle south enroll sauce milk surge evolve reflect'; -const MINTED_TOKEN_ID = - '0x08251a171a5cf36c755b64ff204f95834fa09b1129992d18bfed817bc8a30a0f410100000000'; +export const VAULT_MNEMONIC = + 'impose liar slush abandon mean diary neglect rocket gown coast promote leaf artist animal fall gadget tree oak explain guard topic hair rose marble'; +export const MINTED_TOKEN_ID = + '0x0896a499f3b8d416197b633a01c45a2bcea60ca82c36f0c571466787612fe983860100000000'; diff --git a/packages/functions/test-tangle/minted-token-trade/Helper.ts b/packages/functions/test-tangle/minted-token-trade/Helper.ts index f722a69c27..beffaa1ce5 100644 --- a/packages/functions/test-tangle/minted-token-trade/Helper.ts +++ b/packages/functions/test-tangle/minted-token-trade/Helper.ts @@ -174,7 +174,6 @@ export const dummyTokenId = '0x080c409a8c0ffa795676e55f24e0223e5b48dbe2b1bc4314140333543b5e7e8d360100000000'; export const VAULT_MNEMONIC = - 'offer kingdom rate never hurt follow wrestle cloud alien admit bird usage avoid cloth soldier evidence crawl harsh electric wheat ten mushroom glare reject'; - + 'dad core rival blush concert cool aunt drum pupil youth original example issue around absent amused alley parrot blade intact visa noise slam slab'; export const MINTED_TOKEN_ID = - '0x085f6308dd034c70ea90b4e2600c4f8fb65d0b53504a0d96e37ce8641a8835d2110100000000'; + '0x0808ee67386034f8c76b331745655a3eff500cb7ee0875f89213b2c826a20ddc570100000000'; diff --git a/packages/functions/test-tangle/nft-staking/Helper.ts b/packages/functions/test-tangle/nft-staking/Helper.ts index 60a83ef3d5..f76cbdd39d 100644 --- a/packages/functions/test-tangle/nft-staking/Helper.ts +++ b/packages/functions/test-tangle/nft-staking/Helper.ts @@ -242,10 +242,12 @@ export class Helper { {}, ); const refUnlocks = Object.keys(outputs).map(() => new ReferenceUnlock(0)); - return await submitBlock(this.walletService!, essence, [ + const blockId = await submitBlock(this.walletService!, essence, [ await createUnlock(essence, sourceAddress), ...refUnlocks, ]); + await build5Db().doc(`blocks/${blockId}`).create({ blockId }); + return blockId; }; public withdrawNftAndAwait = async (nft: string) => { diff --git a/packages/functions/test-tangle/proposal-tangle/Helper.ts b/packages/functions/test-tangle/proposal-tangle/Helper.ts index 2983b21c66..9fc91a6a90 100644 --- a/packages/functions/test-tangle/proposal-tangle/Helper.ts +++ b/packages/functions/test-tangle/proposal-tangle/Helper.ts @@ -206,7 +206,6 @@ const proposalRequest = (space: string, type: ProposalType) => ({ }); export const VAULT_MNEMONIC = - 'offer kingdom rate never hurt follow wrestle cloud alien admit bird usage avoid cloth soldier evidence crawl harsh electric wheat ten mushroom glare reject'; - + 'word promote enrich any planet square hurt conduct tongue across trumpet flavor settle bacon hole axis asset blast tennis lift monkey organ evolve mention'; export const MINTED_TOKEN_ID = - '0x085f6308dd034c70ea90b4e2600c4f8fb65d0b53504a0d96e37ce8641a8835d2110100000000'; + '0x08db01317129a23b7ff618a9f73d4263c8c4c062ea5d987e8b1154b5059a3e5c960100000000'; diff --git a/packages/functions/test-tangle/staking/Helper.ts b/packages/functions/test-tangle/staking/Helper.ts index c677386886..919b4adc7d 100644 --- a/packages/functions/test-tangle/staking/Helper.ts +++ b/packages/functions/test-tangle/staking/Helper.ts @@ -39,10 +39,10 @@ import { MEDIA, getWallet, testEnv } from '../../test/set-up'; import { requestFundsFromFaucet, requestMintedTokenFromFaucet } from '../faucet'; export class Helper { - public TOKEN_ID = - '0x087dbad2655a6b8846f51a91973745e583657614c5160e0ab969309c0322132f8b0100000000'; + public MINTED_TOKEN_ID = + '0x08b97105c2c2a57205798940be8d955a2e5491a99229540bbcd9c98530660952bc0100000000'; public VAULT_MNEMONIC = - 'woman bulk engine voice travel tobacco other fiscal dress life text gossip tag situate skill social item dance friend scissors small setup lava key'; + 'ask vintage language rescue slab gas soda rebel delay crew vault bunker march palm supply novel whisper saddle enhance size embark minute penalty buyer'; public member: Member | undefined; public memberAddress: AddressDetails | undefined; @@ -74,7 +74,7 @@ export class Helper { await requestMintedTokenFromFaucet( this.walletService!, this.memberAddress!, - this.TOKEN_ID, + this.MINTED_TOKEN_ID, this.VAULT_MNEMONIC, 100, ); @@ -93,7 +93,7 @@ export class Helper { name: 'MyToken', status: TokenStatus.MINTED, mintingData: { - tokenId: this.TOKEN_ID, + tokenId: this.MINTED_TOKEN_ID, network: Network.RMS, vaultAddress: vaultAddress.bech32, }, @@ -129,7 +129,7 @@ export class Helper { expiration: expiresAt ? { expiresAt, returnAddressBech32: this.memberAddress!.bech32 } : undefined, - nativeTokens: [{ id: this.TOKEN_ID, amount: BigInt(amount) }], + nativeTokens: [{ id: this.MINTED_TOKEN_ID, amount: BigInt(amount) }], }); await MnemonicService.store(address.bech32, address.mnemonic, Network.RMS); const query = build5Db().collection(COL.STAKE).where('orderId', '==', order.uid); diff --git a/packages/functions/test-tangle/staking/newFile.ts b/packages/functions/test-tangle/staking/newFile.ts deleted file mode 100644 index 619a20c17a..0000000000 --- a/packages/functions/test-tangle/staking/newFile.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { COL, Space, StakeType } from '@build-5/interfaces'; -import { FeatureType, MetadataFeature } from '@iota/sdk'; -import dayjs from 'dayjs'; -import { removeExpiredStakesFromSpace } from '../../src/cron/stake.cron'; -import { build5Db } from '../../src/firebase/firestore/build5Db'; -import { dateToTimestamp } from '../../src/utils/dateTime.utils'; -import { Helper } from './Helper'; - -describe('Staking test', () => { - const helper = new Helper(); - - beforeAll(async () => { - await helper.beforeAll(); - }); - - beforeEach(async () => { - await helper.beforeEach(); - }); - - it('Should stake with metadata', async () => { - const type = StakeType.DYNAMIC; - const customMetadata = { - name: 'random name', - asd: 'true', - }; - await helper.stakeAmount(10, 26, undefined, type, customMetadata); - await helper.validateStatsStakeAmount(10, 10, 14, 14, type, 1); - await helper.validateMemberStakeAmount(10, 10, 14, 14, type); - - const outputs = await helper.walletService!.getOutputs( - helper.memberAddress!.bech32, - [], - false, - true, - ); - expect(Object.keys(outputs).length).toBe(1); - - const hexMetadata = ( - Object.values(outputs)[0].features?.find((t) => t.type === FeatureType.Metadata)! - ); - const decoded = JSON.parse(hexToUtf8(hexMetadata.data)); - expect(decoded.name).toBe(customMetadata.name); - expect(decoded.asd).toBe(customMetadata.asd); - }); - - 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}`); - await spaceDocRef.update({ tokenBased: true, minStakedValue: 10 }); - let space = await spaceDocRef.get(); - expect(space.totalMembers).toBe(1); - expect(space.totalGuardians).toBe(1); - - const stake1 = await helper.stakeAmount(10, 52, undefined, type); - await helper.validateStatsStakeAmount(10, 10, 20, 20, type, 1); - await helper.validateMemberStakeAmount(10, 10, 20, 20, type); - - const stake2 = await helper.stakeAmount(20, 52, undefined, type); - await helper.validateStatsStakeAmount(30, 30, 60, 60, type, 1); - await helper.validateMemberStakeAmount(30, 30, 60, 60, type); - - await removeExpiredStakesFromSpace(); - await helper.validateStatsStakeAmount(30, 30, 60, 60, type, 1); - await helper.validateMemberStakeAmount(30, 30, 60, 60, type); - - await build5Db() - .doc(`${COL.STAKE}/${stake2.uid}`) - .update({ expiresAt: dateToTimestamp(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()) }); - await removeExpiredStakesFromSpace(); - await helper.validateStatsStakeAmount(0, 30, 0, 60, type, 0); - await helper.validateMemberStakeAmount(0, 30, 0, 60, type); - - space = await spaceDocRef.get(); - expect(space.totalMembers).toBe(1); - expect(space.totalGuardians).toBe(1); - - const outputs = await helper.walletService!.getOutputs( - helper.memberAddress!.bech32, - [], - false, - true, - ); - expect(Object.keys(outputs).length).toBe(2); - const hasTimelock = Object.values(outputs).filter( - (o) => - o.unlockConditions.find((u) => u.type === TIMELOCK_UNLOCK_CONDITION_TYPE) !== undefined, - ); - expect(hasTimelock.length).toBe(2); - }, - ); -}); diff --git a/packages/functions/test-tangle/staking/staking_1.spec.ts b/packages/functions/test-tangle/staking/staking_1.spec.ts index a4f23d438d..59a587ff0b 100644 --- a/packages/functions/test-tangle/staking/staking_1.spec.ts +++ b/packages/functions/test-tangle/staking/staking_1.spec.ts @@ -177,7 +177,7 @@ describe('Staking test', () => { order.payload.amount, { expiration: { expiresAt, returnAddressBech32: helper.memberAddress!.bech32 }, - nativeTokens: [{ id: helper.TOKEN_ID, amount: BigInt(10) }], + nativeTokens: [{ id: helper.MINTED_TOKEN_ID, amount: BigInt(10) }], }, ); await MnemonicService.store( diff --git a/packages/functions/test-tangle/staking/staking_3.spec.ts b/packages/functions/test-tangle/staking/staking_3.spec.ts index 05d61d446b..208f987cfb 100644 --- a/packages/functions/test-tangle/staking/staking_3.spec.ts +++ b/packages/functions/test-tangle/staking/staking_3.spec.ts @@ -37,11 +37,10 @@ describe('Staking test', () => { await requestMintedTokenFromFaucet( helper.walletService!, helper.memberAddress!, - helper.TOKEN_ID, + helper.MINTED_TOKEN_ID, helper.VAULT_MNEMONIC, 7500 * MIN_IOTA_AMOUNT, ); - const stake1 = await helper.stakeAmount( 500 * MIN_IOTA_AMOUNT, 52, diff --git a/packages/functions/test-tangle/staking/staking_4.spec.ts b/packages/functions/test-tangle/staking/staking_4.spec.ts index 04eff2b493..9d0245720a 100644 --- a/packages/functions/test-tangle/staking/staking_4.spec.ts +++ b/packages/functions/test-tangle/staking/staking_4.spec.ts @@ -86,7 +86,7 @@ describe('Stake reward test test', () => { await requestMintedTokenFromFaucet( helper.walletService!, helper.memberAddress!, - helper.TOKEN_ID, + helper.MINTED_TOKEN_ID, helper.VAULT_MNEMONIC, 1000, ); @@ -102,7 +102,7 @@ describe('Stake reward test test', () => { await requestMintedTokenFromFaucet( helper.walletService!, member2Address, - helper.TOKEN_ID, + helper.MINTED_TOKEN_ID, helper.VAULT_MNEMONIC, 500, ); @@ -142,7 +142,7 @@ describe('Stake reward test test', () => { await requestMintedTokenFromFaucet( helper.walletService!, vaultAddress, - helper.TOKEN_ID, + helper.MINTED_TOKEN_ID, helper.VAULT_MNEMONIC, 149, ); @@ -251,7 +251,7 @@ describe('Stake reward test test', () => { await requestMintedTokenFromFaucet( helper.walletService!, vaultAddress, - helper.TOKEN_ID, + helper.MINTED_TOKEN_ID, helper.VAULT_MNEMONIC, 149, ); @@ -289,7 +289,7 @@ describe('Stake reward test test', () => { await requestMintedTokenFromFaucet( helper.walletService!, vaultAddress, - helper.TOKEN_ID, + helper.MINTED_TOKEN_ID, helper.VAULT_MNEMONIC, 149, ); @@ -346,7 +346,7 @@ describe('Stake reward test test', () => { await requestMintedTokenFromFaucet( helper.walletService!, vaultAddress, - helper.TOKEN_ID, + helper.MINTED_TOKEN_ID, helper.VAULT_MNEMONIC, 149, ); diff --git a/packages/functions/test-tangle/staking/staking_5.spec.ts b/packages/functions/test-tangle/staking/staking_5.spec.ts index ef014f7f0c..9832cb0c20 100644 --- a/packages/functions/test-tangle/staking/staking_5.spec.ts +++ b/packages/functions/test-tangle/staking/staking_5.spec.ts @@ -36,7 +36,7 @@ describe('Stake reward test test', () => { await requestMintedTokenFromFaucet( helper.walletService!, tmp, - helper.TOKEN_ID, + helper.MINTED_TOKEN_ID, helper.VAULT_MNEMONIC, 100, ); diff --git a/packages/functions/test-tangle/token.based.voting/Helper.ts b/packages/functions/test-tangle/token.based.voting/Helper.ts index 3755ff2e52..9e6fb71e4a 100644 --- a/packages/functions/test-tangle/token.based.voting/Helper.ts +++ b/packages/functions/test-tangle/token.based.voting/Helper.ts @@ -233,7 +233,6 @@ export const dummyProposal = (space: string): Proposal => ({ }); export const VAULT_MNEMONIC = - 'offer kingdom rate never hurt follow wrestle cloud alien admit bird usage avoid cloth soldier evidence crawl harsh electric wheat ten mushroom glare reject'; - + 'spoil combine iron zero junk confirm present erase miracle lazy town rough chapter broken atom scare that mutual step parade always face loan guide'; export const MINTED_TOKEN_ID = - '0x085f6308dd034c70ea90b4e2600c4f8fb65d0b53504a0d96e37ce8641a8835d2110100000000'; + '0x087c042b2aea020609809189e329fed4a0bbf549a4156bae3c52e07c9b4466975c0100000000'; diff --git a/packages/functions/test-tangle/token.mint/Helper.ts b/packages/functions/test-tangle/token.mint/Helper.ts index 3bff6a6d3e..4a31067a29 100644 --- a/packages/functions/test-tangle/token.mint/Helper.ts +++ b/packages/functions/test-tangle/token.mint/Helper.ts @@ -150,7 +150,9 @@ export class Helper { new ReferenceUnlock(0), ]; - return await submitBlock(wallet, essence, unlocks); + const blockId = await submitBlock(wallet, essence, unlocks); + await build5Db().doc(`blocks/${blockId}`).create({ blockId }); + return blockId; }; } 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 e63446b0c9..bcb8c4183d 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 @@ -72,7 +72,7 @@ describe('Transaction trigger spec', () => { }); }); -const VAULT_MNEMONIC = - 'crouch violin broom degree diet primary juice vacuum crouch invite cotton endorse zebra mosquito dawn evil motion turkey apple secret indicate miracle lady husband'; -const MINTED_TOKEN_ID = - '0x08a7d756feb7427a5e31b152fb425ede7ee938a8af0b0e2730ea809c8435022ecd0100000000'; +export const VAULT_MNEMONIC = + 'metal access lucky twelve glare museum craft bullet symbol photo manage almost approve rich piano clown cargo race town few story fit bomb volcano'; +export const MINTED_TOKEN_ID = + '0x08dad66e6994b77a07e02448707b27f220e1a8b10a48687a3601734327c74b10a60100000000'; 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 662f3fbe98..894e82aeb0 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 @@ -90,7 +90,7 @@ describe('Transaction trigger spec', () => { }); }); -const VAULT_MNEMONIC = - 'crouch violin broom degree diet primary juice vacuum crouch invite cotton endorse zebra mosquito dawn evil motion turkey apple secret indicate miracle lady husband'; -const MINTED_TOKEN_ID = - '0x08a7d756feb7427a5e31b152fb425ede7ee938a8af0b0e2730ea809c8435022ecd0100000000'; +export const VAULT_MNEMONIC = + 'find adapt flag dentist chicken soldier push all odor vacuum jacket twelve voyage senior into mother fix expose dice risk soup cradle sound isolate'; +export const MINTED_TOKEN_ID = + '0x08e3afe829d6cb7ca885d1ad95428e200541f8bb21cecc42054f122d56cd606a370100000000'; diff --git a/packages/functions/test-tangle/withdraw-deposit-nft/Helper.ts b/packages/functions/test-tangle/withdraw-deposit-nft/Helper.ts index f483efcfce..62cf116e59 100644 --- a/packages/functions/test-tangle/withdraw-deposit-nft/Helper.ts +++ b/packages/functions/test-tangle/withdraw-deposit-nft/Helper.ts @@ -246,7 +246,9 @@ export class Helper { ); const unlocks = [await createUnlock(essence, sourceAddress), new ReferenceUnlock(0)]; - return await submitBlock(this.walletService!, essence, unlocks); + const blockId = await submitBlock(this.walletService!, essence, unlocks); + await build5Db().doc(`blocks/${blockId}`).create({ blockId }); + return blockId; }; public withdrawNftAndAwait = async (nft: string) => { 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 544354e8b8..a0707eb377 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 @@ -69,10 +69,7 @@ describe('Collection minting', () => { helper.guardianAddress!, collectionMetadata, ); - const collectionBlockState = await awaitLedgerInclusionState( - collectionMintingBlock, - Network.RMS, - ); + const collectionBlockState = await awaitLedgerInclusionState(collectionMintingBlock); if (collectionBlockState !== 'included') { fail(); } @@ -81,7 +78,7 @@ describe('Collection minting', () => { collectionId, ...nftMetadata, }); - const nftBlockState = await awaitLedgerInclusionState(nftMintingBlock, Network.RMS); + const nftBlockState = await awaitLedgerInclusionState(nftMintingBlock); if (nftBlockState !== 'included') { fail(); } @@ -124,6 +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 }); const payload = new TransactionPayload(essence, unlocks); const collectionOutputId = Utils.computeOutputId(Utils.transactionId(payload), 0); @@ -181,6 +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 }); 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 6077ea67fd..75af028499 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 @@ -66,10 +66,7 @@ describe('Collection minting', () => { helper.guardianAddress!, collectionMetadata, ); - const collectionBlockState = await awaitLedgerInclusionState( - collectionMintingBlock, - Network.RMS, - ); + const collectionBlockState = await awaitLedgerInclusionState(collectionMintingBlock); if (collectionBlockState !== 'included') { fail(); } @@ -78,7 +75,7 @@ describe('Collection minting', () => { collectionId, ...nftMetadata, }); - const nftBlockState = await awaitLedgerInclusionState(nftMintingBlock, Network.RMS); + const nftBlockState = await awaitLedgerInclusionState(nftMintingBlock); if (nftBlockState !== 'included') { fail(); } @@ -122,6 +119,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 }); const collectionOutputId = Utils.computeOutputId(Utils.transactionId(payload), 0); const collectionId = Utils.computeNftId(collectionOutputId); @@ -178,6 +176,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 }); 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 e5eb862912..ddca695c0e 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 @@ -91,10 +91,7 @@ describe('Collection minting', () => { helper.guardianAddress!, collectionMetadata, ); - const collectionBlockState = await awaitLedgerInclusionState( - collectionMintingBlock, - Network.RMS, - ); + const collectionBlockState = await awaitLedgerInclusionState(collectionMintingBlock); if (collectionBlockState !== 'included') { fail(); } @@ -103,7 +100,7 @@ describe('Collection minting', () => { collectionId, ...nftMetadata, }); - const nftBlockState = await awaitLedgerInclusionState(nftMintingBlock, Network.RMS); + const nftBlockState = await awaitLedgerInclusionState(nftMintingBlock); if (nftBlockState !== 'included') { fail(); } @@ -147,6 +144,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 }); const collectionOutputId = Utils.computeOutputId(Utils.transactionId(payload), 0); const collectionId = Utils.computeNftId(collectionOutputId); @@ -202,6 +200,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 }); const nftOutputId = Utils.computeOutputId(Utils.transactionId(payload), 1); const nftId = Utils.computeNftId(nftOutputId); diff --git a/packages/functions/test/auth.spec.ts b/packages/functions/test/auth.spec.ts index f68bbb5143..04d76c7304 100644 --- a/packages/functions/test/auth.spec.ts +++ b/packages/functions/test/auth.spec.ts @@ -1,6 +1,5 @@ import { COL, Member, Network, WEN_FUNC, WenError } from '@build-5/interfaces'; import { CoinType, utf8ToHex } from '@iota/sdk'; -import { recoverPersonalSignature } from '@metamask/eth-sig-util'; import jwt from 'jsonwebtoken'; import { get } from 'lodash'; import { build5Db } from '../src/firebase/firestore/build5Db'; @@ -13,8 +12,6 @@ import { decodeAuth, getRandomNonce } from '../src/utils/wallet.utils'; import { createMember, expectThrow, mockWalletReturnValue } from './controls/common'; import { getWallet, testEnv } from './set-up'; -jest.mock('@metamask/eth-sig-util'); - describe('Auth control test', () => { let walletSpy: jest.SpyInstance; let configSpy: jest.SpyInstance; @@ -194,49 +191,4 @@ describe('Pub key test', () => { expect(user.validatedAddress![Network.RMS]).toBe(address.bech32); expect(user.nonce).not.toBe(nonce); }); - - it('Should update nonce when metamask sign in', async () => { - const address = wallet.getRandomEthAddress(); - - const nonce = getRandomNonce(); - const userDocRef = build5Db().doc(`${COL.MEMBER}/${address}`); - await userDocRef.create({ uid: address, nonce }); - - const recoverPersonalSignatureMock = recoverPersonalSignature as jest.Mock; - recoverPersonalSignatureMock.mockReturnValue(address); - - const request = { - address, - signature: 'signature', - body: {}, - }; - - const result = await decodeAuth(request, WEN_FUNC.approveProposal); - expect(result.address).toBe(address); - - const user = await userDocRef.get(); - expect(user?.nonce).not.toBe(nonce); - - recoverPersonalSignatureMock.mockRestore(); - }); - - it('Should throw with metamask sign in, wrong signature', async () => { - const address = wallet.getRandomEthAddress(); - - const nonce = getRandomNonce(); - const userDocRef = build5Db().doc(`${COL.MEMBER}/${address}`); - await userDocRef.create({ uid: address, nonce }); - - const request = { - address, - signature: 'signature', - body: {}, - }; - try { - await decodeAuth(request, WEN_FUNC.approveProposal); - fail(); - } catch (error: any) { - expect(error.details.key).toBe(WenError.invalid_signature.key); - } - }); }); diff --git a/packages/functions/test/milestone.sync.ts b/packages/functions/test/milestone.sync.ts index b8bc2b8ecc..085f3a6e7d 100644 --- a/packages/functions/test/milestone.sync.ts +++ b/packages/functions/test/milestone.sync.ts @@ -1,77 +1,85 @@ -import { COL, Network, SUB_COL } from '@build-5/interfaces'; +import { COL, Network, SUB_COL, Transaction, getMilestoneCol } from '@build-5/interfaces'; +import { Client } from '@iota/sdk'; +import dayjs from 'dayjs'; +import * as admin from 'firebase-admin'; -import { Output, OutputType } from '@iota/sdk'; -import * as adminPackage from 'firebase-admin'; -import { last } from 'lodash'; -import { build5Db } from '../src/firebase/firestore/build5Db'; -import { Wallet } from '../src/services/wallet/wallet'; -import { getWallet, projectId } from './set-up'; - -process.env.FIRESTORE_EMULATOR_HOST = ''; -const config = { - credential: adminPackage.credential.cert('./test-service-account-key.json'), - - databaseURL: `https://${projectId}.firebaseio.com`, -}; -const app = adminPackage.initializeApp(config, 'second'); -const onlineDb = app.firestore(); process.env.FIRESTORE_EMULATOR_HOST = 'localhost:8080'; -const syncMilestones = async (col: COL) => { - const lastDocQuery = onlineDb.collection(col).orderBy('createdOn', 'desc').limit(1); - let lastDoc = (await lastDocQuery.get()).docs[0]; +admin.initializeApp(); - const wallet = await getWallet(Network.RMS); +const client = new Client({ nodes: ['https://rms1.svrs.io/'] }); - while (1) { - const snap = await onlineDb - .collection(col) - .orderBy('createdOn') - .startAfter(lastDoc) - .limit(10) - .get(); - lastDoc = last(snap.docs) || lastDoc; - - const batch = build5Db().batch(); - snap.docs.forEach((doc) => { - batch.create(build5Db().doc(doc.ref.path), doc.data()); +const downloadBlocks = async () => { + admin + .firestore() + .collection('blocks') + .orderBy('createdOn', 'desc') + .limit(1) + .onSnapshot((snap) => { + snap.docChanges().forEach((change) => { + if (change.type === 'added') { + saveBlock(change.doc.data().blockId); + } + }); }); - await batch.commit(); - - await new Promise((resolve) => setTimeout(resolve, 1000)); +}; - const promises = snap.docs.map((doc) => syncTransactions(wallet, doc.ref.path)); - await Promise.all(promises); +const saveBlock = async (blockId: string) => { + const metadata = await getBlockMetadata(blockId); + if (metadata?.ledgerInclusionState !== 'included') { + return; } + + const block = await client.getBlock(blockId); + await admin + .firestore() + .collection(getMilestoneCol(Network.RMS)) + .doc(metadata.referencedByMilestoneIndex + '') + .collection(SUB_COL.TRANSACTIONS) + .doc(blockId) + .create({ + blockId, + createdOn: dayjs().toDate(), + milestone: metadata.referencedByMilestoneIndex, + payload: JSON.parse(JSON.stringify(block.payload)), + processed: false, + }); }; -const syncTransactions = async (wallet: Wallet, parentPath: string) => { - const snap = await onlineDb.collection(`${parentPath}/${SUB_COL.TRANSACTIONS}`).get(); - const promises = snap.docs.map(async (doc) => { - const data = doc.data(); - const addresses = getAddesses(data, wallet); - if (await addressInDb(addresses)) { - await build5Db() - .doc(doc!.ref.path) - .create({ ...doc!.data(), 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 Promise.all(promises); + await new Promise((r) => setTimeout(r, 500)); + } + return; }; -const getAddesses = (doc: any, wallet: Wallet) => - (doc.payload.essence.outputs as Output[]) - .filter((o) => o.type !== OutputType.Treasury) - .map((o) => wallet.bechAddressFromOutput(o as any)); +downloadBlocks(); -const addressInDb = async (addresses: string[]) => { - for (const address of addresses) { - const doc = await build5Db().collection(COL.MNEMONIC).doc(address).get(); - if (doc) { - return true; - } - } - return false; +const transactionToBlock = () => { + admin + .firestore() + .collection(COL.TRANSACTION) + .orderBy('updatedOn', 'desc') + .limit(1) + .onSnapshot(async (snap) => { + for (const doc of snap.docs) { + const transaction = doc.data() as Transaction; + const chainReference = transaction.payload.walletReference?.chainReference; + if (chainReference && !chainReference.startsWith('payment')) { + try { + await admin + .firestore() + .collection('blocks') + .doc(chainReference) + .create({ blockId: chainReference, createdOn: dayjs().toDate() }); + } catch {} + } + } + }); }; -syncMilestones(COL.MILESTONE_RMS); +transactionToBlock(); diff --git a/packages/functions/test/set-up.ts b/packages/functions/test/set-up.ts index abd95a7d39..07c0bd8e7d 100644 --- a/packages/functions/test/set-up.ts +++ b/packages/functions/test/set-up.ts @@ -4,8 +4,13 @@ import express from 'express'; import test from 'firebase-functions-test'; import * as functions from 'firebase-functions/v2'; import { isEmpty } from 'lodash'; -import { Wallet } from '../src/services/wallet/wallet'; -import { WalletService } from '../src/services/wallet/wallet.service'; +import { build5Db } from '../src/firebase/firestore/build5Db'; +import { Wallet, WalletParams } from '../src/services/wallet/wallet'; +import { + AddressDetails, + SendToManyTargets, + WalletService, +} from '../src/services/wallet/wallet.service'; dotenv.config({ path: '.env.local' }); @@ -14,8 +19,8 @@ process.env.GCLOUD_PROJECT = projectId; export const getConfig = () => { if (process.env.LOCAL_TEST) { - process.env.FIRESTORE_EMULATOR_HOST = 'localhost:8080'; - process.env.FIREBASE_STORAGE_EMULATOR_HOST = 'localhost:9199'; + 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', @@ -28,7 +33,7 @@ export const getConfig = () => { }; }; -export const sentOnRequest = +export const sendOnRequest = (func: (req: functions.https.Request, response: express.Response) => void | Promise) => async (data: any) => { const req = { ip: '127.0.0.1', body: { data }, headers: { origin: true } } as any; @@ -65,7 +70,7 @@ export const testEnv = { config: process.env.LOCAL_TEST ? test(getConfig()) : test(getConfig(), './test-service-account-key.json'), - wrap: sentOnRequest, + wrap: sendOnRequest, }; export const MEDIA = @@ -77,10 +82,47 @@ const setup = async () => { export const wallets: { [key: string]: Wallet } = {}; +class TestWallet extends Wallet { + constructor(private readonly wallet: Wallet) { + super(wallet.client, wallet.info, wallet.network); + } + + public getBalance = this.wallet.getBalance; + 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; + + public send = async ( + from: AddressDetails, + toAddress: string, + amount: number, + params: WalletParams, + outputToConsume?: string | undefined, + ) => { + const blockId = await this.wallet.send(from, toAddress, amount, params, outputToConsume); + await build5Db().doc(`blocks/${blockId}`).create({ 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 }); + return blockId; + }; +} + export const getWallet = async (network: Network) => { const wallet = wallets[network]; if (!wallet) { - wallets[network] = await WalletService.newWallet(network); + const baseWallet = await WalletService.newWallet(network); + wallets[network] = new TestWallet(baseWallet); } return wallets[network]; }; diff --git a/packages/functions/test/storage/resize.img.spec.ts b/packages/functions/test/storage/resize.img.spec.ts index ed86b8be84..c2fd06d590 100644 --- a/packages/functions/test/storage/resize.img.spec.ts +++ b/packages/functions/test/storage/resize.img.spec.ts @@ -1,6 +1,5 @@ -import { Bucket } from '@build-5/interfaces'; +import { Bucket, ImageWidth } from '@build-5/interfaces'; import { build5Storage } from '../../src/firebase/storage/build5Storage'; -import { ImageWidth } from '../../src/triggers/storage/resize.img.trigger'; import { getRandomEthAddress } from '../../src/utils/wallet.utils'; import { wait } from '../controls/common'; diff --git a/packages/interfaces/src/api/post/index.ts b/packages/interfaces/src/api/post/index.ts index bd3a58584a..7bfe00f117 100644 --- a/packages/interfaces/src/api/post/index.ts +++ b/packages/interfaces/src/api/post/index.ts @@ -19,6 +19,7 @@ export * from './CollectionRejectRequest'; export * from './CollectionUpdateMintedRequest'; export * from './CollectionUpdateRequest'; export * from './CreditUnrefundableRequest'; +export * from './FileUploadRequest'; export * from './CreateMemberRequest'; export * from './UpdateMemberRequest'; export * from './NftBidRequest'; @@ -43,7 +44,6 @@ export * from './SpaceUpdateRequest'; export * from './StakeRewardRemoveRequest'; export * from './StakeRewardRequest'; export * from './StakeTokenRequest'; -export * from './FileUploadRequest'; export * from './TokenAirdropRequest'; export * from './TokenCancelPubSaleRequest'; export * from './TokenClaimAirdroppedRequest'; diff --git a/packages/interfaces/src/config.ts b/packages/interfaces/src/config.ts index 51da76f10e..a35da7c231 100644 --- a/packages/interfaces/src/config.ts +++ b/packages/interfaces/src/config.ts @@ -8,10 +8,6 @@ export class ProposalStartDateMin { public static value = 5 * 60 * 1000; } -export class AppCheck { - public static enabled = true; -} - export enum URL_PATHS { NFT = 'nft', SPACE = 'space', diff --git a/packages/interfaces/src/functions/index.ts b/packages/interfaces/src/functions/index.ts index b1cced8e7c..8a91b12d73 100644 --- a/packages/interfaces/src/functions/index.ts +++ b/packages/interfaces/src/functions/index.ts @@ -1,27 +1,11 @@ import { EthAddress } from '../models/base'; -export enum WEN_FUNC_TRIGGER { - onProposalUpdated = 'onproposalupdated', - awardTrigger = 'awardtrigger', - collectionWrite = 'collectionwrite', - onTokenStatusUpdate = 'ontokenstatusupdate', - onTokenTradeOrderWrite = 'ontokentradeorderwrite', - onTokenPurchaseCreated = 'ontokenpurchasecreated', - milestoneTransactionWrite = 'milestonetransactionwrite', - nftWrite = 'nftwrite', - transactionWrite = 'transactionwrite', - mnemonicWrite = 'mnemonicwrite', - collectionStatsUpdate = 'collectionstatsupdate', - algolia = 'algolia', - resizeImg = 'resizeimg', -} - export enum WEN_FUNC { - // Member functions. + // Member functions createMember = 'cmembernotexists', updateMember = 'umember', - // Space functions. + // Space functions createSpace = 'cspace', updateSpace = 'uspace', joinSpace = 'joinspace', @@ -48,14 +32,14 @@ export enum WEN_FUNC { rejectProposal = 'rproposal', voteOnProposal = 'voteonproposal', - // Collection functions. + // Collection functions createCollection = 'ccollection', updateCollection = 'ucollection', approveCollection = 'approvecollection', rejectCollection = 'rejectcollection', mintCollection = 'mintcollection', - // NFT functions. + // NFT functions createNft = 'cnft', createBatchNft = 'cbatchnft', setForSaleNft = 'setforsalenft', @@ -64,7 +48,7 @@ export enum WEN_FUNC { updateUnsoldNft = 'updateunsoldnft', stakeNft = 'stakenft', - // ORDER functions. + // ORDER functions orderNft = 'ordernft', openBid = 'openbid', validateAddress = 'validateaddress', @@ -98,8 +82,6 @@ export enum WEN_FUNC { generateCustomToken = 'generatecustomtoken', - api = 'api', - uploadFile = 'uploadfile', } diff --git a/packages/interfaces/src/models/file.ts b/packages/interfaces/src/models/file.ts index 851c8a55b6..38e0d53889 100644 --- a/packages/interfaces/src/models/file.ts +++ b/packages/interfaces/src/models/file.ts @@ -8,3 +8,9 @@ export interface File extends BaseRecord { uid: string; ipfsCid: string; } + +export enum ImageWidth { + tb = '200', + md = '680', + lg = '1600', +} diff --git a/packages/interfaces/src/models/index.ts b/packages/interfaces/src/models/index.ts index 8f657dc851..7d1010d7db 100644 --- a/packages/interfaces/src/models/index.ts +++ b/packages/interfaces/src/models/index.ts @@ -2,6 +2,7 @@ export * from './award'; export * from './badge'; export * from './base'; export * from './collection'; +export * from './file'; export * from './member'; export * from './milestone'; export * from './mnemonic'; diff --git a/scripts/joi-generator-post.ts b/scripts/joi-generator-post.ts index 3e7c7a1367..fdb2237696 100644 --- a/scripts/joi-generator-post.ts +++ b/scripts/joi-generator-post.ts @@ -1,7 +1,7 @@ import { convertFromDirectory } from 'joi-to-typescript'; convertFromDirectory({ - schemaDirectory: './packages/functions/src/runtime/firebase/', + schemaDirectory: './packages/functions/src/controls/', typeOutputDirectory: './packages/interfaces/src/api/post/', flattenTree: true, });