├── .dockerignore ├── .github ├── ISSUE_TEMPLATE │ ├── _feature-request.md │ ├── bug_report.md │ └── stamp-partnership----integration-details.md ├── actions │ └── check-provider-bitmaps │ │ └── action.yml └── workflows │ ├── add-issue-to-project.yml │ ├── app-cd-review.yml │ ├── app-promote-production.yml │ ├── app-promote-staging.yml │ ├── ceramic-promote-production.yml │ ├── ceramic-promote-staging.yml │ ├── ci.yml │ ├── deploy_to_aws.yml │ ├── deploy_to_branch.yml │ ├── dockerize.yml │ ├── iam-cd-review.yml │ ├── iam-promote-production.yml │ ├── iam-promote-staging.yml │ ├── release_and_deploy.yml │ ├── release_and_deploy_passport.yml │ ├── signer-cd-review.yml │ ├── signer-promote-production.yml │ └── signer-promote-staging.yml ├── .gitignore ├── .husky ├── commit-msg ├── pre-commit └── pre-push ├── .prettierrc.js ├── .vscode └── settings.json ├── CODEOFCONDUCT.md ├── LICENSE ├── README.md ├── app ├── .env-example.env ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .prettierignore ├── .prettierrc.js ├── README.md ├── __mocks__ │ ├── @adraffy │ │ └── ens-normalize.js │ ├── @didtools │ │ ├── cacao.js │ │ └── pkh-ethereum.js │ ├── @gitcoin │ │ ├── passport-database-client │ │ │ └── index.js │ │ └── passport-identity │ │ │ └── index.js │ ├── @self.id │ │ ├── framework │ │ │ └── index.js │ │ └── web │ │ │ └── index.js │ ├── @web3-onboard │ │ ├── common.js │ │ └── react.js │ ├── broadcast-channel.js │ ├── did-session │ │ └── index.js │ └── fileMock.js ├── __test-fixtures__ │ ├── contextTestHelpers.tsx │ ├── databaseStorageFixtures.ts │ ├── onboardHookValues.ts │ ├── toastTestHelpers.tsx │ └── verifiableCredentialResults.ts ├── __tests__ │ ├── components │ │ ├── AttestationProvider.test.tsx │ │ ├── CardList.test.tsx │ │ ├── DashboardScorePanel.test.tsx │ │ ├── ExpiredStampsPanel.test.tsx │ │ ├── GenericPlatform.test.tsx │ │ ├── InitialWelcome.test.tsx │ │ ├── InitiateReverifyStampsButton.test.tsx │ │ ├── JsonOutputModal.test.tsx │ │ ├── NetworkCard.test.tsx │ │ ├── PlatformCard.test.tsx │ │ ├── ProviderCards │ │ │ ├── BrightidCard.test.tsx │ │ │ ├── DiscordCard.test.tsx │ │ │ ├── EnsCard.test.tsx │ │ │ ├── GithubPlatform.test.tsx │ │ │ ├── GoogleCard.test.tsx │ │ │ └── LinkedinCard.test.tsx │ │ ├── RefreshMyStampsSelector.test.tsx │ │ ├── SideBarContent.test.tsx │ │ ├── StampSelector.test.tsx │ │ ├── SupportBanner.test.tsx │ │ └── SyncToChainButton.test.tsx │ ├── context │ │ ├── ceramicContext.test.tsx │ │ ├── datastoreConnectionContext.test.tsx │ │ └── stampClaimingContext.test.tsx │ ├── hooks │ │ ├── useCustomization.test.tsx │ │ └── useOneClickVerification.test.tsx │ ├── pages │ │ ├── Dashboard.test.tsx │ │ ├── Home.test.tsx │ │ ├── Welcome.test.tsx │ │ └── app.test.tsx │ └── utils │ │ ├── helpers.test.ts │ │ ├── onChainStamps.test.ts │ │ └── utils.test.ts ├── components │ ├── BodyWrapper.tsx │ ├── Button.tsx │ ├── CardList.tsx │ ├── Category.tsx │ ├── Checkbox.tsx │ ├── CustomDashboardPanel.tsx │ ├── DashboardScorePanel.tsx │ ├── DashboardValidStampsPanel.tsx │ ├── DoneToastContent.tsx │ ├── DropDownIcon.tsx │ ├── ExpiredStampsPanel.tsx │ ├── Footer.tsx │ ├── GenericBanner.tsx │ ├── GenericPlatform.tsx │ ├── Header.tsx │ ├── HeaderContentFooterGrid.tsx │ ├── InitialWelcome.tsx │ ├── InitiateOnChainButton.tsx │ ├── InitiateReverifyStampsButton.tsx │ ├── JsonOutputModal.tsx │ ├── LoadButton.tsx │ ├── LoadingCard.tsx │ ├── LoadingScreen.tsx │ ├── ManageAccountCenter.tsx │ ├── MinimalHeader.tsx │ ├── NetworkCard.tsx │ ├── OnchainSidebar.tsx │ ├── OnchainTag.tsx │ ├── PageRoot.tsx │ ├── PageWidthGrid.tsx │ ├── PlatformCard.tsx │ ├── PlatformDetails.tsx │ ├── ProcessingPopup.tsx │ ├── Progress.tsx │ ├── RefreshMyStampsSelector.tsx │ ├── RefreshStampsProgressSteps.tsx │ ├── RemoveStampModal.tsx │ ├── SIWEButton.tsx │ ├── SideBarContent.tsx │ ├── StampSelector.tsx │ ├── SupportBanner.tsx │ ├── SyncToChainButton.tsx │ ├── TestingPanel.tsx │ ├── Toggle.tsx │ ├── Tooltip.tsx │ ├── VeraxPanel.tsx │ ├── Warning.tsx │ ├── WebmVideo.tsx │ ├── WelcomeFooter.tsx │ └── WelcomeWrapper.tsx ├── config │ ├── customization_config.ts │ ├── feature_flags.ts │ ├── filters.ts │ ├── platforms.ts │ ├── providers.ts │ └── stamp_config.ts ├── context │ ├── ceramicContext.tsx │ ├── datastoreConnectionContext.tsx │ ├── onChainContext.tsx │ ├── scorerContext.tsx │ ├── stampClaimingContext.tsx │ ├── testModeState.tsx │ ├── userState.tsx │ └── walletStore.tsx ├── hooks │ ├── useCustomization.tsx │ ├── useOnChainStatus.tsx │ ├── useOneClickVerification.tsx │ ├── useSupportBanners.tsx │ └── useSyncToChainButton.tsx ├── jest.config.ts ├── jest.setup.ts ├── next-env.d.ts ├── next.config.js ├── package.json ├── pages │ ├── Dashboard.tsx │ ├── Home.tsx │ ├── Maintenance.tsx │ ├── Welcome.tsx │ ├── _app.tsx │ ├── index.tsx │ └── privacy.tsx ├── postcss.config.js ├── public │ ├── assets │ │ ├── apple-appstore-logo.svg │ │ ├── arb-logo.svg │ │ ├── arbitrum-arb-logo.svg │ │ ├── arrow-left-icon.svg │ │ ├── arrow-right-icon.svg │ │ ├── avax-logo.svg │ │ ├── backgroundRock.png │ │ ├── backgroundTexture.svg │ │ ├── brightidStampIcon.svg │ │ ├── card-background.svg │ │ ├── check-icon-grey.svg │ │ ├── check-icon.svg │ │ ├── check-icon2.svg │ │ ├── civicStampIcon.svg │ │ ├── clock-icon.svg │ │ ├── coinbaseStampIcon.svg │ │ ├── coolSpacestation.svg │ │ ├── cyberconnectLogoIcon.svg │ │ ├── dashboardIllustration.png │ │ ├── discordStampIcon.svg │ │ ├── docsIconDark.svg │ │ ├── docsIconLight.svg │ │ ├── dpoppLogo.svg │ │ ├── ensStampIcon.svg │ │ ├── eth-network-logo.svg │ │ ├── ethLogo.svg │ │ ├── ethStampIcon.svg │ │ ├── ethereumStampIcon.svg │ │ ├── facebookStampIcon.svg │ │ ├── gitPOAPStampIcon.svg │ │ ├── gitcoin-flower.svg │ │ ├── gitcoinLogo.svg │ │ ├── gitcoinLogoAndName.svg │ │ ├── gitcoinLogoDark.svg │ │ ├── gitcoinLogoType.svg │ │ ├── gitcoinLogoWhite.svg │ │ ├── gitcoinStampIcon.svg │ │ ├── gitcoinWordLogo.svg │ │ ├── gitcoindaoGreyDark.svg │ │ ├── gitcoindaoLogoLight.svg │ │ ├── githubLogoDark.svg │ │ ├── githubLogoLight.svg │ │ ├── githubStampIcon.svg │ │ ├── githubWhiteStampIcon.svg │ │ ├── gnosisSafeStampIcon.svg │ │ ├── goerli-base-logo.svg │ │ ├── google-play-logo.svg │ │ ├── googleStampIcon.svg │ │ ├── grantsStackLogo.svg │ │ ├── gtcGrantsLightIcon.svg │ │ ├── gtcPossessionStampIcon.svg │ │ ├── gtcStakingLogoIcon.svg │ │ ├── guildXYZStampIcon.svg │ │ ├── hexagonIcon.svg │ │ ├── holonymStampIcon.svg │ │ ├── hypercertsStampIcon.svg │ │ ├── idenaStampIcon.svg │ │ ├── information-circle-icon.svg │ │ ├── landingPageBackground.svg │ │ ├── lensStampIcon.svg │ │ ├── lensWhiteStampIcon.svg │ │ ├── lenswhite.svg │ │ ├── linea-logo.png │ │ ├── linkedinStampIcon.svg │ │ ├── lockIcon.svg │ │ ├── logoLine.svg │ │ ├── logoTiles.svg │ │ ├── mobileLandingPageBackground.svg │ │ ├── nftStampIcon.svg │ │ ├── on-chain-icon.svg │ │ ├── onboarding.svg │ │ ├── onboarding.webm │ │ ├── op-logo.svg │ │ ├── optimism_logo.png │ │ ├── outdidStampIcon.svg │ │ ├── passport-flash.svg │ │ ├── passportBackgroundLogo.svg │ │ ├── passportLanding.svg │ │ ├── passportLandingPageLogo.svg │ │ ├── passportLogoBlack.svg │ │ ├── passportLogoWhite.svg │ │ ├── passport_score.svg │ │ ├── personIcon.svg │ │ ├── pgn-logo.png │ │ ├── pgn-logo.svg │ │ ├── phiLogoIcon.svg │ │ ├── plus-icon.svg │ │ ├── poapStampIcon.svg │ │ ├── pohStampIcon.svg │ │ ├── purple-check-icon.svg │ │ ├── shield-alert.svg │ │ ├── shield-exclamation-icon-warning.svg │ │ ├── shield-exclamation-icon.svg │ │ ├── shieldLockIcon.svg │ │ ├── sidebarHeader.svg │ │ ├── snapshotStampIcon.svg │ │ ├── splashPageLogo.webm │ │ ├── splashPageLogoFallback.svg │ │ ├── splashPageTexture.png │ │ ├── stamp-cards.svg │ │ ├── trustaLabsStampIcon.svg │ │ ├── twitterStampIcon.svg │ │ ├── verification-failed-bright.svg │ │ ├── verification-failed.svg │ │ ├── verifiedShield.svg │ │ ├── welcome-back.png │ │ ├── welcome-get-started.png │ │ ├── welcome-passport-scoring.png │ │ ├── welcome.png │ │ ├── white-check-icon.svg │ │ ├── whiteBgShieldExclamation.svg │ │ ├── x-icon-black.svg │ │ ├── x-icon.svg │ │ ├── x-mark-icon.svg │ │ └── zksyncStampIcon.svg │ ├── favicon.ico │ └── ipfs-404.html ├── scripts │ └── preBuild.tsx ├── signer │ └── utils.ts ├── styles │ └── globals.css ├── tailwind.config.js ├── tsconfig.json ├── types.ts └── utils │ ├── AttestationProvider.ts │ ├── __mocks__ │ └── onboard.ts │ ├── chains.ts │ ├── customizationUtils.tsx │ ├── helpers.tsx │ ├── onChainStamps.ts │ ├── onChainStatus.ts │ ├── onboard.ts │ └── theme │ ├── chakra │ ├── Menu.tsx │ └── Modal.tsx │ ├── index.tsx │ ├── palette.tsx │ ├── setCustomizationTheme.tsx │ ├── setTheme.tsx │ ├── themeWrapper.tsx │ ├── themes.tsx │ └── types.tsx ├── commitlint.config.js ├── database-client ├── .gitignore ├── README.md ├── __tests__ │ ├── composeDatabase.test.ts │ ├── integration-test-model-aliases.json │ ├── mockStamps.json │ ├── passportScorerClient.test.ts │ └── utils.test.ts ├── composedb.config.json ├── integration-tests │ ├── ceramicDatabaseStampValidity.ts │ ├── ceramicDatabaseTest.ts │ ├── integration-test-model-aliases.json │ └── run-ceramic-tests.sh ├── jest.config.cjs ├── jest.integration.config.js ├── package.json ├── src │ ├── composeDatabase.ts │ ├── index.ts │ ├── logger.ts │ ├── passportScorerClient.ts │ ├── types.ts │ └── utils.ts └── tsconfig.json ├── deployments ├── abi │ ├── GitcoinAttester.json │ ├── GitcoinPassportDecoder.json │ ├── GitcoinResolver.json │ ├── GitcoinVeraxPortal.json │ └── GitcoinVerifier.json └── onchainInfo.json ├── docker-compose.yml ├── funding.json ├── iam ├── .env-example.env ├── .eslintignore ├── .eslintrc.cjs ├── .gitignore ├── .prettierignore ├── .prettierrc.cjs ├── Dockerfile ├── README.md ├── __mocks__ │ ├── @gitcoin │ │ └── passport-identity │ │ │ └── index.js │ ├── dids │ │ └── index.js │ └── key-did-resolver │ │ └── index.js ├── __tests__ │ ├── additional_signer.test.ts │ ├── challenge.test.ts │ ├── easFees.test.ts │ ├── easPassportSchema.test.ts │ ├── easStampSchema.test.ts │ ├── index.test.ts │ └── index_eas_score.test.ts ├── babel.config.json ├── jest.config.cjs ├── jest.setup.cjs ├── package.json ├── src │ ├── index.ts │ ├── issuers.ts │ ├── main.ts │ ├── scripts │ │ ├── buildProviderBitMapInfo.ts │ │ └── checkOnChainProvidersAreInSync.ts │ ├── static │ │ ├── bright-id-template.html │ │ └── providerBitMapInfo.json │ ├── types.d.ts │ └── utils │ │ ├── challenge.ts │ │ ├── easFees.ts │ │ ├── easPassportSchema.ts │ │ ├── easStampSchema.ts │ │ ├── scorerService.ts │ │ └── verifyDidChallenge.ts └── tsconfig.json ├── identity ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .prettierignore ├── .prettierrc.js ├── README.md ├── __mocks__ │ ├── axios.js │ └── didkit.js ├── __tests__ │ └── credentials.test.ts ├── jest.config.js ├── package.json ├── src │ ├── credentials.ts │ ├── index.ts │ └── signingDocuments.ts └── tsconfig.json ├── infra ├── .gitignore ├── README.md ├── aws │ ├── .gitignore │ ├── Pulumi.review.yaml │ ├── Pulumi.staging.yaml │ ├── Pulumi.yaml │ ├── iam_secrets.ts │ ├── index.ts │ └── tsconfig.json ├── lib │ ├── service.ts │ └── staking │ │ └── app.ts ├── package.json └── yarn.lock ├── js-ceramic ├── Dockerfile ├── README.md └── ceramic │ └── daemon.config.json ├── lerna.json ├── package.json ├── platforms ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .prettierignore ├── .prettierrc.js ├── jest.config.cjs ├── jest.config.js ├── package.json ├── src │ ├── Brightid │ │ ├── App-Bindings.ts │ │ ├── Providers-config.ts │ │ ├── Providers │ │ │ └── brightid.ts │ │ ├── Shared.ts │ │ ├── __tests__ │ │ │ ├── App-Bindings.test.ts │ │ │ └── brightid.test.ts │ │ ├── index.ts │ │ └── procedures │ │ │ └── brightid.ts │ ├── Civic │ │ ├── App-Bindings.tsx │ │ ├── Providers-config.ts │ │ ├── Providers │ │ │ ├── civic.ts │ │ │ ├── types.ts │ │ │ └── util.ts │ │ ├── Shared.ts │ │ ├── __tests__ │ │ │ └── civic.test.ts │ │ └── index.ts │ ├── ClearText │ │ ├── Providers │ │ │ ├── clearTextGithubOrg.ts │ │ │ └── clearTextTwitter.ts │ │ ├── __tests__ │ │ │ ├── clearTextGithubOrg.test.ts │ │ │ └── clearTextTwitter.test.ts │ │ └── index.ts │ ├── Coinbase │ │ ├── App-Bindings.tsx │ │ ├── Providers-config.ts │ │ ├── Providers │ │ │ └── coinbase.ts │ │ ├── Shared.ts │ │ ├── __tests__ │ │ │ └── coinbase.test.ts │ │ └── index.ts │ ├── Discord │ │ ├── App-Bindings.ts │ │ ├── Providers-config.ts │ │ ├── Providers │ │ │ └── discord.ts │ │ ├── __tests__ │ │ │ └── discord.test.ts │ │ └── index.ts │ ├── ETH │ │ ├── App-Bindings.ts │ │ ├── Providers-config.ts │ │ ├── Providers │ │ │ └── accountAnalysis.ts │ │ ├── Shared.ts │ │ ├── __tests__ │ │ │ └── accountAnalysis.test.ts │ │ └── index.ts │ ├── Ens │ │ ├── App-Bindings.ts │ │ ├── Providers-config.ts │ │ ├── Providers │ │ │ ├── EnsProvider.ts │ │ │ └── index.ts │ │ ├── Shared.ts │ │ ├── __tests__ │ │ │ └── EnsProvider.test.ts │ │ └── index.ts │ ├── Gitcoin │ │ ├── App-Bindings.tsx │ │ ├── Providers-config.ts │ │ ├── Providers │ │ │ ├── __tests__ │ │ │ │ ├── gitcoinGrantsContributorStatistics.test.ts │ │ │ │ └── gitcoinGrantsStatistics.test.ts │ │ │ ├── gitcoinGrantsContributorStatistics.ts │ │ │ ├── gitcoinGrantsStatistics.ts │ │ │ └── index.ts │ │ └── index.ts │ ├── Github │ │ ├── App-Bindings.ts │ │ ├── Providers-config.ts │ │ ├── Providers │ │ │ ├── __tests__ │ │ │ │ ├── githubClient.test.ts │ │ │ │ └── githubContributionActivity.test.ts │ │ │ ├── githubClient.ts │ │ │ └── githubContributionActivity.ts │ │ └── index.ts │ ├── GnosisSafe │ │ ├── App-Bindings.ts │ │ ├── Providers-config.ts │ │ ├── Providers │ │ │ ├── __tests__ │ │ │ │ └── gnosisSafe.test.ts │ │ │ ├── gnosisSafe.ts │ │ │ └── index.ts │ │ └── index.ts │ ├── Google │ │ ├── App-Bindings.ts │ │ ├── Providers-config.ts │ │ ├── Providers │ │ │ ├── __tests__ │ │ │ │ └── google.test.ts │ │ │ └── google.ts │ │ └── index.js │ ├── GtcStaking │ │ ├── App-Bindings.tsx │ │ ├── Providers-config.ts │ │ ├── Providers │ │ │ ├── GtcStaking.ts │ │ │ ├── communityStaking.ts │ │ │ ├── index.ts │ │ │ └── selfStaking.ts │ │ ├── __tests__ │ │ │ ├── communityStaking.test.ts │ │ │ ├── gtcStaking.test.ts │ │ │ └── selfStaking.test.ts │ │ └── index.ts │ ├── GuildXYZ │ │ ├── App-Bindings.ts │ │ ├── Providers-config.ts │ │ ├── Providers │ │ │ └── guildXYZ.ts │ │ ├── __tests__ │ │ │ └── guildXYZ.test.ts │ │ └── index.ts │ ├── Holonym │ │ ├── App-Bindings.tsx │ │ ├── Providers-config.ts │ │ ├── Providers │ │ │ ├── holonymGovIdProvider.ts │ │ │ └── index.ts │ │ ├── __tests__ │ │ │ └── holonymGovId.test.ts │ │ └── index.ts │ ├── Idena │ │ ├── App-Bindings.ts │ │ ├── Providers-config.ts │ │ ├── Providers │ │ │ └── IdenaStateProvider.ts │ │ ├── README.md │ │ ├── __tests__ │ │ │ ├── provider.test.ts │ │ │ └── signin.test.ts │ │ ├── index.ts │ │ └── procedures │ │ │ └── idenaSignIn.ts │ ├── Lens │ │ ├── App-Bindings.ts │ │ ├── Providers-config.ts │ │ ├── Providers │ │ │ └── lens.ts │ │ ├── Shared.ts │ │ ├── __tests__ │ │ │ └── lens.test.ts │ │ └── index.ts │ ├── Linkedin │ │ ├── App-Bindings.ts │ │ ├── Providers-config.ts │ │ ├── Providers │ │ │ └── linkedin.ts │ │ ├── __tests__ │ │ │ └── linkedin.test.ts │ │ └── index.ts │ ├── NFT │ │ ├── App-Bindings.ts │ │ ├── Providers-config.ts │ │ ├── Providers │ │ │ ├── __tests__ │ │ │ │ ├── collectors_journey.test.ts │ │ │ │ └── nft.test.ts │ │ │ ├── collectors_journey.ts │ │ │ ├── index.ts │ │ │ └── nft.ts │ │ └── index.ts │ ├── Outdid │ │ ├── App-Bindings.ts │ │ ├── Providers-config.ts │ │ ├── Providers │ │ │ └── outdid.ts │ │ ├── __tests__ │ │ │ └── outdid.test.ts │ │ ├── index.ts │ │ └── procedures │ │ │ └── outdidVerification.ts │ ├── POAP │ │ ├── App-Bindings.ts │ │ ├── Providers-config.ts │ │ ├── Providers │ │ │ └── poap.ts │ │ ├── Shared.ts │ │ ├── __tests__ │ │ │ └── poap.test.ts │ │ └── index.ts │ ├── Snapshot │ │ ├── App-Bindings.ts │ │ ├── Providers-config.ts │ │ ├── Providers │ │ │ ├── __tests__ │ │ │ │ └── snapshotProposalsProvider.test.ts │ │ │ ├── index.ts │ │ │ ├── snapshotProposalsProvider.ts │ │ │ └── snapshotVotesProvider.ts │ │ └── index.ts │ ├── TrustaLabs │ │ ├── App-Bindings.tsx │ │ ├── Providers-config.ts │ │ ├── Providers │ │ │ ├── TrustaLabs.ts │ │ │ ├── __tests__ │ │ │ │ └── TrustaLabs.test.ts │ │ │ └── index.ts │ │ └── index.ts │ ├── Twitter │ │ ├── App-Bindings.ts │ │ ├── Providers-config.ts │ │ ├── Shared.ts │ │ ├── index.ts │ │ └── procedures │ │ │ └── twitterOauth.ts │ ├── ZkSync │ │ ├── App-Bindings.ts │ │ ├── Providers-config.ts │ │ ├── Providers │ │ │ ├── accountAnalysis.ts │ │ │ └── zkSyncEra.ts │ │ ├── __tests__ │ │ │ ├── accountAnalysis.test.ts │ │ │ └── zkSyncEra.test.ts │ │ └── index.ts │ ├── __tests__ │ │ └── mocks │ │ │ └── redis.ts │ ├── index.ts │ ├── platforms.ts │ ├── procedure-router.ts │ ├── types.ts │ └── utils │ │ ├── __tests__ │ │ ├── passport-cache.test.ts │ │ ├── platform-cache.test.ts │ │ └── providers.test.ts │ │ ├── clearTextSimpleProvider.ts │ │ ├── errors.ts │ │ ├── handleAxiosError.ts │ │ ├── handleProviderAxiosError.ts │ │ ├── passport-cache.ts │ │ ├── platform-cache.ts │ │ ├── platform.ts │ │ ├── providers.ts │ │ ├── scaffoldPlatform.ts │ │ ├── signer.ts │ │ ├── simpleEvmProvider.ts │ │ └── simpleProvider.ts ├── testSetup.js └── tsconfig.json ├── schemas ├── .env-example.env ├── .gitignore ├── README.md ├── composites │ └── gitcoin-passport-stamps-composite.json ├── models │ └── passportStamps.graphql ├── package.json ├── src │ ├── definitions │ │ ├── json │ │ │ └── gitcoin-passport-stamps.json │ │ └── ts │ │ │ └── gitcoin-passport-stamps.ts │ └── index.ts └── tsconfig.json ├── tsconfig.json ├── tsconfig.settings.json ├── types ├── .eslintrc.js ├── .prettierrc.js ├── README.md ├── package.json ├── src │ ├── brightid.d.ts │ └── index.d.ts └── tsconfig.json └── yarn.lock /.dockerignore: -------------------------------------------------------------------------------- 1 | **/.env 2 | **/node_modules 3 | **/dist 4 | **/.next 5 | *.md 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/_feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: _Feature request 3 | about: Suggest an idea for this project 4 | title: "[to be defined]" 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### User Story: 11 | As a ... 12 | I want to ... 13 | So that I can ... 14 | 15 | ### Acceptance Criteria 16 | GIVEN ... 17 | WHEN ... 18 | THEN ... 19 | 20 | #### Product & Design Links: 21 | 22 | 23 | #### Tech Details: 24 | 25 | #### Open Questions: 26 | 27 | #### Notes/Assumptions: 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG] " 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Overview** 11 | Details, details, details 12 | 13 | **Steps To Reproduce** 14 | 1. Go to '...' 15 | 2. Click on '....' 16 | 3. Scroll down to '....' 17 | 4. See error 18 | 19 | **Observed behavior** 20 | A clear and concise description of what the observed behavior of the system. 21 | 22 | **Expected behavior** 23 | A clear and concise description of what you expected the system to do. 24 | 25 | **Screenshots** 26 | If applicable, add screenshots to help explain your problem. 27 | 28 | **Additional context** 29 | Add any other context about the problem here that will assist in triaging the bug. I.e. Browser information, unique identifiers, etc. 30 | -------------------------------------------------------------------------------- /.github/actions/check-provider-bitmaps/action.yml: -------------------------------------------------------------------------------- 1 | name: "Check Provider Bitmaps" 2 | description: "Checkout that the onchai provider bitmaps are in sync with the configuration in the code" 3 | 4 | inputs: 5 | ALCHEMY_API_KEY_OP: 6 | description: "Alchemy API key for Optimism" 7 | required: true 8 | 9 | ALCHEMY_API_KEY_OP_SEPOLIA: 10 | description: "Alchemy API key for Optimism Sepolia" 11 | required: true 12 | 13 | runs: 14 | using: "composite" 15 | steps: 16 | - name: Check Optimism Onchain Provider Bitmaps 17 | run: | 18 | echo "📋📋📋 Check Optimism Onchain Provider Bitmaps" 19 | yarn workspace @gitcoin/passport-iam checkProviders:op 20 | shell: bash 21 | env: 22 | ALCHEMY_API_KEY: ${{ inputs.ALCHEMY_API_KEY_OP }} 23 | -------------------------------------------------------------------------------- /.github/workflows/add-issue-to-project.yml: -------------------------------------------------------------------------------- 1 | name: Add issues to passport project 2 | 3 | on: 4 | issues: 5 | types: 6 | - opened 7 | 8 | jobs: 9 | add-to-project: 10 | name: Add issue to project 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/add-to-project@v0.1.0 14 | with: 15 | project-url: https://github.com/orgs/gitcoinco/projects/6 16 | github-token: ${{ secrets.ADD_ISSUE_TO_PROJECT_PAT }} 17 | -------------------------------------------------------------------------------- /.github/workflows/app-cd-review.yml: -------------------------------------------------------------------------------- 1 | name: Deploy App to Review 2 | on: 3 | push: 4 | branches: [main] 5 | 6 | jobs: 7 | deploy-app: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v3 11 | - name: Checkout review-app 12 | run: | 13 | git fetch 14 | git checkout -b review-app origin/review-app 15 | git reset --hard origin/main 16 | git remote set-url origin https://${{ secrets.GITHUB_TOKEN }}@github.com/gitcoinco/passport.git 17 | git push origin review-app -f 18 | -------------------------------------------------------------------------------- /.github/workflows/app-promote-production.yml: -------------------------------------------------------------------------------- 1 | name: Deploy App to Production 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | # commit hash (for frontend deploy to fleek) 6 | commit: 7 | description: "Branch/Commit ref" 8 | default: "origin/main" 9 | type: string 10 | jobs: 11 | deploy-app: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3 15 | - name: Checkout production-app 16 | run: | 17 | git fetch 18 | git checkout -b production-app origin/production-app 19 | git reset --hard ${{ github.event.inputs.commit }} 20 | git remote set-url origin https://${{ secrets.GITHUB_TOKEN }}@github.com/gitcoinco/passport.git 21 | git push origin production-app -f 22 | -------------------------------------------------------------------------------- /.github/workflows/app-promote-staging.yml: -------------------------------------------------------------------------------- 1 | name: Deploy App to Staging 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | # commit hash (for frontend deploy to fleek) 6 | commit: 7 | description: "Branch/Commit ref" 8 | default: "origin/main" 9 | type: string 10 | jobs: 11 | deploy-app: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3 15 | - name: Checkout staging-app 16 | run: | 17 | git fetch 18 | git checkout -b staging-app origin/staging-app 19 | git reset --hard ${{ github.event.inputs.commit }} 20 | git remote set-url origin https://${{ secrets.GITHUB_TOKEN }}@github.com/gitcoinco/passport.git 21 | git push origin staging-app -f 22 | -------------------------------------------------------------------------------- /.github/workflows/ceramic-promote-production.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Ceramic Mainnet Node 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | commit: 7 | description: "Commit ref" 8 | required: true 9 | type: string 10 | 11 | jobs: 12 | deploy-production: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v3 16 | - name: Use Node.js 17 | uses: actions/setup-node@v2 18 | with: 19 | cache: "yarn" 20 | cache-dependency-path: infra/ceramic-mainnet/package-lock.json 21 | # Update the pulumi stack with new image 22 | - run: | 23 | npm install 24 | pulumi stack select -c gitcoin/ceramic/mainnet-node 25 | pulumi config -s gitcoin/ceramic/mainnet-node set aws:region us-east-1 --non-interactive 26 | working-directory: infra/ceramic-mainnet 27 | env: 28 | PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }} 29 | - uses: pulumi/actions@v3 30 | id: pulumi 31 | with: 32 | command: up 33 | stack-name: gitcoin/ceramic/mainnet-node 34 | 35 | upsert: false 36 | work-dir: infra/ceramic-mainnet 37 | env: 38 | ROUTE_53_ZONE: ${{ secrets.CERAMIC_ROUTE53_ZONE_ID_PRODUCTION }} 39 | AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID_PRODUCTION }} 40 | AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY_PRODUCTION }} 41 | DOMAIN: passport-iam.gitcoin.co 42 | RPC_URL: ${{ secrets.MAINNET_RPC_URL }} 43 | -------------------------------------------------------------------------------- /.github/workflows/ceramic-promote-staging.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Ceramic Testnet Node 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | commit: 7 | description: "Commit ref" 8 | required: true 9 | type: string 10 | 11 | jobs: 12 | deploy-ceramic-testnet: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v3 16 | - name: Use Node.js 17 | uses: actions/setup-node@v2 18 | with: 19 | cache: "yarn" 20 | cache-dependency-path: infra/ceramic-testnet/package-lock.json 21 | # Update the pulumi stack with new image 22 | - run: | 23 | npm install 24 | pulumi stack select -c gitcoin/ceramic/testnet-node 25 | pulumi config -s gitcoin/ceramic/testnet-node set aws:region us-east-1 --non-interactive 26 | working-directory: infra/ceramic-testnet 27 | env: 28 | PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }} 29 | - uses: pulumi/actions@v3 30 | id: pulumi 31 | with: 32 | command: up 33 | stack-name: gitcoin/ceramic/testnet-node 34 | upsert: false 35 | work-dir: infra/ceramic-testnet 36 | env: 37 | ROUTE_53_ZONE: ${{ secrets.ROUTE53_ZONE_ID_STAGING }} 38 | DOMAIN: ${{ secrets.DOMAIN }} 39 | AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID_STAGING }} 40 | AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY_STAGING }} 41 | -------------------------------------------------------------------------------- /.github/workflows/deploy_to_branch.yml: -------------------------------------------------------------------------------- 1 | name: Deploy to Branch (Release Frontend) 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | refspec: 7 | required: true 8 | type: string 9 | owner: 10 | required: true 11 | type: string 12 | repo: 13 | required: true 14 | type: string 15 | destination_branch: 16 | required: true 17 | type: string 18 | 19 | 20 | permissions: write-all 21 | jobs: 22 | deploy_to_branch: 23 | name: Deploy to Branch 24 | runs-on: ubuntu-latest 25 | steps: 26 | - uses: actions/checkout@v3 27 | with: 28 | token: ${{ secrets.github_token }} 29 | ref: main 30 | fetch-depth: 0 31 | - name: Push to Branch 32 | run: | 33 | git fetch 34 | git checkout -b ${{ inputs.destination_branch }} 35 | git reset --hard ${{ inputs.refspec }} 36 | git reset HEAD -- .github/workflows 37 | git remote set-url origin https://${{ secrets.github_token }}@github.com/${{ inputs.owner }}/${{ inputs.repo }}.git 38 | git push origin ${{ inputs.destination_branch }} -f 39 | -------------------------------------------------------------------------------- /.github/workflows/signer-cd-review.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Signer to Review 2 | on: 3 | push: 4 | branches: [main] 5 | paths: 6 | - "signer/**" 7 | jobs: 8 | deploy-signer: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v3 12 | - name: Checkout review-signer 13 | run: | 14 | git fetch 15 | git checkout -b review-signer origin/review-signer 16 | git reset --hard origin/main 17 | git remote set-url origin https://${{ secrets.GITHUB_TOKEN }}@github.com/gitcoinco/passport.git 18 | git push origin review-signer -f 19 | -------------------------------------------------------------------------------- /.github/workflows/signer-promote-production.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Signer to Production 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | # commit hash (for frontend deploy to fleek) 6 | commit: 7 | description: "Branch/Commit ref" 8 | default: "origin/main" 9 | type: string 10 | jobs: 11 | deploy-signer: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3 15 | - name: Checkout production-signer 16 | run: | 17 | git fetch 18 | git checkout -b production-signer origin/production-signer 19 | git reset --hard ${{ github.event.inputs.commit }} 20 | git remote set-url origin https://${{ secrets.GITHUB_TOKEN }}@github.com/gitcoinco/passport.git 21 | git push origin production-signer -f 22 | -------------------------------------------------------------------------------- /.github/workflows/signer-promote-staging.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Signer to Staging 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | # commit hash (for frontend deploy to fleek) 6 | commit: 7 | description: "Branch/Commit ref" 8 | default: "origin/main" 9 | type: string 10 | jobs: 11 | deploy-signer: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3 15 | - name: Checkout staging-signer 16 | run: | 17 | git fetch 18 | git checkout -b staging-signer origin/staging-signer 19 | git reset --hard ${{ github.event.inputs.commit }} 20 | git remote set-url origin https://${{ secrets.GITHUB_TOKEN }}@github.com/gitcoinco/passport.git 21 | git push origin staging-signer -f 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | .nvmrc 4 | .yarnrc 5 | 6 | # Logs 7 | logs 8 | *.log 9 | npm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | pnpm-debug.log* 13 | lerna-debug.log* 14 | 15 | # Editor directories and files 16 | .yarn/* 17 | .vscode/* 18 | !.vscode/extensions.json 19 | .idea 20 | .DS_Store 21 | *.suo 22 | *.ntvs* 23 | *.njsproj 24 | *.sln 25 | *.sw? 26 | 27 | schemas/.env.yarn -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | yarn commitlint --edit $1 5 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | yarn run lint 5 | -------------------------------------------------------------------------------- /.husky/pre-push: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | yarn run test 5 | # yarn run test:ceramic-integration 6 | # disabled integration test May 30 2023 7 | # it was causing too many errors and is 8 | # addressed during build anyway <3MSG -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | overrides: [ 3 | { 4 | files: ["**/*.js", "**/*.ts", "**/*.tsx"], 5 | options: { 6 | bracketSpacing: true, 7 | trailingComma: "es5", 8 | tabWidth: 2, 9 | printWidth: 120, 10 | singleQuote: false, 11 | semi: true, 12 | }, 13 | }, 14 | ], 15 | }; 16 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "node_modules/typescript/lib" 3 | } 4 | -------------------------------------------------------------------------------- /app/.eslintignore: -------------------------------------------------------------------------------- 1 | /*.js 2 | /*.ts 3 | /test/* 4 | /dist/* 5 | /.next/* 6 | /coverage/* 7 | /node_modules/* 8 | /__mocks__/**/*.js 9 | /out/* -------------------------------------------------------------------------------- /app/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["plugin:testing-library/react", "next", "prettier"], 3 | "rules": { 4 | "@next/next/no-img-element": "off" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | public/stampMetadata.json 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env.local 30 | .env.development.local 31 | .env.test.local 32 | .env.production.local 33 | 34 | # vercel 35 | .vercel 36 | 37 | # typescript 38 | *.tsbuildinfo 39 | -------------------------------------------------------------------------------- /app/.prettierignore: -------------------------------------------------------------------------------- 1 | /dist/* 2 | /build/* 3 | /coverage/* 4 | /.next/* 5 | /out/* 6 | /public/* 7 | -------------------------------------------------------------------------------- /app/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ...require("../.prettierrc.js"), 3 | singleQuote: false, 4 | }; 5 | -------------------------------------------------------------------------------- /app/README.md: -------------------------------------------------------------------------------- 1 | # @gitcoin/passport-app 2 | 3 | This will be the web app allowing users to interact with their Gitcoin Passport. 4 | 5 | ```bash 6 | yarn start 7 | ``` 8 | 9 | Set the `NEXT_PUBLIC_CERAMIC_CLIENT_URL` environment variable to change the Ceramic node to run against - the Ceramic 10 | host defaults to the community node `https://ceramic-clay.3boxlabs.com` if not provided. 11 | -------------------------------------------------------------------------------- /app/__mocks__/@adraffy/ens-normalize.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ens_beautify: jest.fn(), 3 | ens_emoji: jest.fn(), 4 | ens_normalize: jest.fn(), 5 | ens_normalize_fragment: jest.fn(), 6 | ens_split: jest.fn(), 7 | ens_tokenize: jest.fn(), 8 | is_combining_mark: jest.fn(), 9 | nfc: jest.fn(), 10 | nfd: jest.fn(), 11 | safe_str_from_cps: jest.fn(), 12 | should_escape: jest.fn(), 13 | }; 14 | -------------------------------------------------------------------------------- /app/__mocks__/@didtools/cacao.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // Mocked implementation of the @didtools/cacao module 3 | }; 4 | -------------------------------------------------------------------------------- /app/__mocks__/@didtools/pkh-ethereum.js: -------------------------------------------------------------------------------- 1 | export const EthereumWebAuth = { getAuthMethod: jest.fn() }; 2 | -------------------------------------------------------------------------------- /app/__mocks__/@gitcoin/passport-database-client/index.js: -------------------------------------------------------------------------------- 1 | export const createPassportMock = jest.fn(); 2 | export const getPassportMock = jest.fn().mockImplementation(() => { 3 | return { 4 | passport: { 5 | stamps: [], 6 | }, 7 | errorDetails: {}, 8 | status: "Success", 9 | }; 10 | }); 11 | export const addStampMock = jest.fn(); 12 | export const addStampsMock = jest.fn(); 13 | export const deleteStampMock = jest.fn(); 14 | export const deleteStampsMock = jest.fn(); 15 | 16 | export const CeramicDatabase = jest.fn().mockImplementation(() => { 17 | return { 18 | constructor() { 19 | return { 20 | createPassport: createPassportMock, 21 | getPassport: getPassportMock, 22 | addStamp: addStampMock, 23 | addStamps: addStampMock, 24 | deleteStamp: deleteStampMock, 25 | deleteStamps: deleteStampsMock, 26 | }; 27 | }, 28 | }; 29 | }); 30 | 31 | export const PassportDatabase = jest.fn().mockImplementation(() => { 32 | return { 33 | constructor() { 34 | return { 35 | createPassport: createPassportMock, 36 | getPassport: getPassportMock, 37 | addStamp: addStampMock, 38 | addStamps: addStampMock, 39 | deleteStamp: deleteStampMock, 40 | deleteStamps: deleteStampsMock, 41 | }; 42 | }, 43 | }; 44 | }); 45 | -------------------------------------------------------------------------------- /app/__mocks__/@gitcoin/passport-identity/index.js: -------------------------------------------------------------------------------- 1 | // mock everything that we're using in @gitcoin/passport-identity/src into an object and export it 2 | const identity = {}; 3 | 4 | // always verifies 5 | identity.verifyCredential = jest.fn(() => true); 6 | identity.fetchVerifiableCredential = jest.fn(() => true); 7 | 8 | // return full mock 9 | module.exports = identity; 10 | -------------------------------------------------------------------------------- /app/__mocks__/@self.id/framework/index.js: -------------------------------------------------------------------------------- 1 | const framework = {}; 2 | 3 | const mockConnectFn = jest.fn(() => new Promise((resolve) => resolve())); 4 | const mockDisconnectFn = jest.fn(() => new Promise((resolve) => resolve())); 5 | 6 | const viewerConnection = { 7 | status: "idle", 8 | }; 9 | 10 | framework.useViewerConnection = () => [viewerConnection, mockConnectFn, mockDisconnectFn]; 11 | 12 | module.exports = framework; 13 | -------------------------------------------------------------------------------- /app/__mocks__/@self.id/web/index.js: -------------------------------------------------------------------------------- 1 | export default class EthereumAuthProvider { 2 | constructor() { 3 | console.log("Mock EthereumAuthProvider: constructor was called"); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /app/__mocks__/@web3-onboard/common.js: -------------------------------------------------------------------------------- 1 | const common = jest.createMockFromModule("@web3-onboard/common"); 2 | 3 | module.exports = common; 4 | -------------------------------------------------------------------------------- /app/__mocks__/@web3-onboard/react.js: -------------------------------------------------------------------------------- 1 | const react = {}; 2 | 3 | const mockConnectFn = jest.fn(() => new Promise((resolve) => resolve())); 4 | const mockDisconnectFn = jest.fn(() => new Promise((resolve) => resolve())); 5 | const mockUseConnectWallet = () => [{ wallet: {} }, mockConnectFn, mockDisconnectFn]; 6 | 7 | react.useConnectWallet = mockUseConnectWallet; 8 | 9 | react.useWallets = () => []; 10 | 11 | module.exports = react; 12 | -------------------------------------------------------------------------------- /app/__mocks__/broadcast-channel.js: -------------------------------------------------------------------------------- 1 | const constructor = jest.fn(); 2 | const postMessage = jest.fn(); 3 | const close = jest.fn(); 4 | 5 | export class BroadcastChannel { 6 | constructor() { 7 | return constructor(); 8 | } 9 | postMessage() { 10 | return postMessage(); 11 | } 12 | close() { 13 | return close(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/__mocks__/did-session/index.js: -------------------------------------------------------------------------------- 1 | export class DIDSession { 2 | authorize() { 3 | return "some-session-str"; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /app/__mocks__/fileMock.js: -------------------------------------------------------------------------------- 1 | module.exports = "test-file-stub"; 2 | -------------------------------------------------------------------------------- /app/__test-fixtures__/onboardHookValues.ts: -------------------------------------------------------------------------------- 1 | import { Account, ConnectedChain, WalletState } from "@web3-onboard/core/dist/types"; 2 | 3 | const sepoliaChainId = "0xaa36a7"; 4 | export const mockAddress = "0xmyAddress"; 5 | export const mockAccount: Account = { 6 | address: mockAddress, 7 | ens: null, 8 | uns: null, 9 | balance: null, 10 | }; 11 | export const mockWallet: WalletState = { 12 | label: "myWallet", 13 | icon: "", 14 | provider: { on: jest.fn(), removeListener: jest.fn(), request: jest.fn() }, 15 | accounts: [mockAccount], 16 | chains: [ 17 | [ 18 | { 19 | id: sepoliaChainId, 20 | }, 21 | ] as unknown as ConnectedChain, 22 | ], 23 | }; 24 | -------------------------------------------------------------------------------- /app/__test-fixtures__/toastTestHelpers.tsx: -------------------------------------------------------------------------------- 1 | import { screen, waitForElementToBeRemoved } from "@testing-library/react"; 2 | import { toastStore } from "@chakra-ui/toast/dist/toast.store"; 3 | 4 | export const closeAllToasts = async () => { 5 | // close all toasts before each tests and wait for them to be removed 6 | toastStore.closeAll(); 7 | const toasts = screen.queryAllByRole("listitem"); 8 | await Promise.all(toasts.map((toasts) => waitForElementToBeRemoved(toasts))); 9 | }; 10 | -------------------------------------------------------------------------------- /app/__tests__/components/JsonOutputModal.test.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render, screen } from "@testing-library/react"; 3 | 4 | import { JsonOutputModal, JsonOutputModalProps } from "../../components/JsonOutputModal"; 5 | import { ensStampFixture } from "../../__test-fixtures__/databaseStorageFixtures"; 6 | 7 | let props: JsonOutputModalProps; 8 | const passport = { 9 | issuanceDate: "2022-06-14T08:51:28.157Z", 10 | expiryDate: "2022-06-14T08:51:28.157Z", 11 | stamps: [], 12 | }; 13 | 14 | beforeEach(() => { 15 | props = { 16 | isOpen: true, 17 | onClose: jest.fn(), 18 | subheading: "Custom subheading", 19 | title: "Modal Title", 20 | jsonOutput: passport, 21 | closeButtonText: "Custom Close", 22 | }; 23 | }); 24 | 25 | afterEach(() => { 26 | jest.clearAllMocks(); 27 | }); 28 | 29 | describe("displays the modal", () => { 30 | it("should display your modals content", () => { 31 | render(); 32 | const subheading = screen.queryByText("Custom subheading"); 33 | const title = screen.queryByText("Modal Title"); 34 | const close = screen.queryByText("Custom Close"); 35 | const download = screen.queryByText("Download"); 36 | const passportJsonContent = screen.getByTestId("passport-json"); 37 | expect(passportJsonContent.textContent).toBe(JSON.stringify(passport, null, "\t")); 38 | expect(subheading).toBeInTheDocument(); 39 | expect(title).toBeInTheDocument(); 40 | expect(close).toBeInTheDocument(); 41 | expect(download).toBeInTheDocument(); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /app/__tests__/components/NetworkCard.test.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { screen } from "@testing-library/react"; 3 | 4 | import { NetworkCard } from "../../components/NetworkCard"; 5 | 6 | import { makeTestCeramicContext, renderWithContext } from "../../__test-fixtures__/contextTestHelpers"; 7 | 8 | import { CeramicContextState } from "../../context/ceramicContext"; 9 | import { Drawer, DrawerOverlay } from "@chakra-ui/react"; 10 | 11 | jest.mock("next/router", () => ({ 12 | useRouter: () => ({ 13 | query: { filter: "" }, 14 | }), 15 | })); 16 | 17 | const chains = [ 18 | { 19 | id: "12345", 20 | token: "SEP", 21 | label: "Sepolia Testnet", 22 | rpcUrl: "http://www.sepolia.com", 23 | icon: "sepolia.svg", 24 | }, 25 | { 26 | id: "67899", 27 | token: "ETH", 28 | label: "Ethereum Testnet", 29 | rpcUrl: "http://www.etherum.com", 30 | icon: "ethereum.svg", 31 | }, 32 | ]; 33 | 34 | const mockCeramicContext: CeramicContextState = makeTestCeramicContext(); 35 | 36 | describe("OnChainSidebar", () => { 37 | it("renders", () => { 38 | const drawer = () => ( 39 | {}}> 40 | 41 | 42 | 43 | ); 44 | renderWithContext(mockCeramicContext, drawer()); 45 | expect(screen.getByText("Sepolia Testnet")).toBeInTheDocument(); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /app/__tests__/pages/app.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from "@testing-library/react"; 2 | import App from "../../pages/_app"; 3 | import { AppProps } from "next/app"; 4 | 5 | jest.mock("@datadog/browser-rum"); 6 | jest.mock("@datadog/browser-logs"); 7 | jest.mock("@didtools/cacao", () => ({ 8 | Cacao: { 9 | fromBlockBytes: jest.fn(), 10 | }, 11 | })); 12 | 13 | const mockPostMessage = jest.fn(); 14 | jest.mock("broadcast-channel", () => { 15 | return { 16 | BroadcastChannel: jest.fn().mockImplementation(() => { 17 | return { 18 | postMessage: mockPostMessage, 19 | }; 20 | }), 21 | }; 22 | }); 23 | 24 | describe("when index is provided queryParams matching twitters OAuth response", () => { 25 | it("should postMessage to opener and close window", async () => { 26 | const mockCloseWindow = jest.fn(); 27 | 28 | // Mock query params 29 | Object.defineProperty(window, "location", { 30 | writable: false, 31 | value: { 32 | search: "?code=ABC&state=twitter-123", 33 | }, 34 | }); 35 | 36 | // Mock window.close 37 | Object.defineProperty(window, "close", { 38 | writable: false, 39 | value: mockCloseWindow, 40 | }); 41 | 42 | const appProps = {} as AppProps; 43 | 44 | render(); 45 | 46 | // expect message to be posted and window.close() to have been called 47 | expect(mockPostMessage).toBeCalledTimes(1); 48 | expect(mockCloseWindow).toBeCalledTimes(1); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /app/__tests__/utils/helpers.test.ts: -------------------------------------------------------------------------------- 1 | import { createSignedPayload } from "../../utils/helpers"; 2 | import { Cacao } from "@didtools/cacao"; 3 | 4 | jest.mock("@didtools/cacao", () => ({ 5 | Cacao: { 6 | fromBlockBytes: jest.fn().mockImplementation((_) => { 7 | return { 8 | p: { 9 | iss: "did:ethr:0x123", 10 | }, 11 | }; 12 | }), 13 | }, 14 | })); 15 | 16 | describe("createSignedPayload", () => { 17 | it("should sign", async () => { 18 | const mockDid = { 19 | createDagJWS: () => ({ 20 | jws: { 21 | link: { 22 | bytes: [7, 8, 9], 23 | }, 24 | payload: { 25 | hello: "world", 26 | }, 27 | signatures: ["0x123"], 28 | }, 29 | cacaoBlock: [0, 1, 2], 30 | }), 31 | }; 32 | 33 | const signedPayload = await createSignedPayload(mockDid as any, { hello: "world" }); 34 | 35 | expect(Cacao.fromBlockBytes).toHaveBeenCalledWith([0, 1, 2]); 36 | 37 | expect(signedPayload).toEqual({ 38 | signatures: ["0x123"], 39 | payload: { hello: "world" }, 40 | cid: [7, 8, 9], 41 | cacao: [0, 1, 2], 42 | issuer: "did:ethr:0x123", 43 | }); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /app/components/BodyWrapper.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { PAGE_PADDING, CONTENT_MAX_WIDTH_INCLUDING_PADDING } from "./PageWidthGrid"; 3 | 4 | const BodyWrapper = ({ children, className }: { children: React.ReactNode; className?: string }) => ( 5 |
8 | {children} 9 |
10 | ); 11 | 12 | export default BodyWrapper; 13 | -------------------------------------------------------------------------------- /app/components/Button.tsx: -------------------------------------------------------------------------------- 1 | import React, { ButtonHTMLAttributes, useMemo } from "react"; 2 | 3 | export type ButtonProps = ButtonHTMLAttributes & { 4 | variant?: "primary" | "secondary" | "custom"; 5 | }; 6 | 7 | // Children are centered and spaced out with gap-4. 8 | // If your button just contains text, simply use the text 9 | // e.g. 10 | // If your button has an icon or other elements, just include both elements 11 | // e.g. 12 | export const Button = ({ variant, className, ...props }: ButtonProps) => { 13 | const variantClassName = useMemo(() => { 14 | if (variant === "custom") { 15 | return ""; 16 | } else if (variant === "secondary") { 17 | return "text-color-1 bg-background border border-foreground-3 hover:border-foreground-4"; 18 | } else { 19 | // primary, default 20 | return "text-color-4 bg-gradient-to-r from-foreground-2 to-foreground-2 hover:to-foreground-4"; 21 | } 22 | }, [variant]); 23 | 24 | return ( 25 | 17 | setShowSidebar(false)} /> 18 | 19 | ); 20 | }; 21 | 22 | export default InitiateOnChainButton; 23 | -------------------------------------------------------------------------------- /app/components/LoadButton.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Button, ButtonProps } from "./Button"; 3 | import { Spinner } from "@chakra-ui/react"; 4 | 5 | export type LoadingButtonProps = ButtonProps & { 6 | isLoading?: boolean; 7 | }; 8 | 9 | export const LoadButton = ({ isLoading, disabled, children, ...props }: LoadingButtonProps) => { 10 | return ( 11 | 15 | ); 16 | }; 17 | -------------------------------------------------------------------------------- /app/components/LoadingCard.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | export const LoadingCard = ({ className }: { className?: string }): JSX.Element => { 4 | return ( 5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | 20 |
21 |
22 |
23 |
24 |
25 | ); 26 | }; 27 | -------------------------------------------------------------------------------- /app/components/LoadingScreen.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const LoadingScreen = () => { 4 | return ( 5 |
6 | Loading... 7 | Gitcoin Logo 8 |
9 | ); 10 | }; 11 | 12 | export default LoadingScreen; 13 | -------------------------------------------------------------------------------- /app/components/MinimalHeader.tsx: -------------------------------------------------------------------------------- 1 | // --- React methods 2 | import React, { useMemo } from "react"; 3 | 4 | type MinimalHeaderProps = { 5 | className?: string; 6 | }; 7 | 8 | const getAssets = () => { 9 | return { 10 | passportLogo: "/assets/passportLogoWhite.svg", 11 | gitcoinLogo: "/assets/gitcoinLogoWhite.svg", 12 | logoLine: "/assets/logoLine.svg", 13 | emphasisColor: "white", 14 | }; 15 | }; 16 | 17 | const MinimalHeader = ({ className }: MinimalHeaderProps): JSX.Element => { 18 | const assets = useMemo(() => getAssets(), []); 19 | 20 | return ( 21 |
22 |
23 | Gitcoin Logo 24 | Logo Line 25 | Passport Logo 26 |
Passport
27 |
28 |
29 | ); 30 | }; 31 | 32 | export default MinimalHeader; 33 | -------------------------------------------------------------------------------- /app/components/OnchainTag.tsx: -------------------------------------------------------------------------------- 1 | import { Tag, TagLabel } from "@chakra-ui/react"; 2 | 3 | export function OnchainTag({ marginLeft }: { marginLeft?: string }) { 4 | return ( 5 | 15 | Onchain 16 | 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /app/components/PageRoot.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const PageRoot = ({ children, className }: { children: React.ReactNode; className?: string }) => ( 4 |
{children}
5 | ); 6 | 7 | export default PageRoot; 8 | -------------------------------------------------------------------------------- /app/components/PageWidthGrid.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | export const PAGE_PADDING = "px-4 md:px-10 lg:px-20"; 4 | export const CONTENT_MAX_WIDTH_INCLUDING_PADDING = "max-w-[1440px]"; 5 | export const CONTENT_MAX_WIDTH = "max-w-screen-xl"; 6 | 7 | const PageWidthGrid = ({ children, className }: { children: React.ReactNode; className?: string }) => ( 8 |
12 | {children} 13 |
14 | ); 15 | 16 | export default PageWidthGrid; 17 | -------------------------------------------------------------------------------- /app/components/ProcessingPopup.tsx: -------------------------------------------------------------------------------- 1 | export default function ProcessingPopup({ children, ...props }: { children: React.ReactNode }) { 2 | return ( 3 |
4 |
5 | 6 | 7 | 8 | 9 |
{children}
10 |
11 |
12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /app/components/SIWEButton.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Button, ButtonProps } from "./Button"; 3 | 4 | const SIWEButton = (props: ButtonProps & { enableEthBranding: boolean }) => { 5 | const { enableEthBranding, ...rest } = props; 6 | return ( 7 | 23 | ); 24 | }; 25 | 26 | export default SIWEButton; 27 | -------------------------------------------------------------------------------- /app/components/SupportBanner.tsx: -------------------------------------------------------------------------------- 1 | import Warning from "./Warning"; 2 | import { SupportBannerProps } from "../hooks/useSupportBanners"; 3 | 4 | export function SupportBanner({ banners }: { banners: SupportBannerProps[] }): JSX.Element { 5 | return ( 6 | <> 7 | {banners.map((banner) => ( 8 | 14 | ))} 15 | 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /app/components/Toggle.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Switch } from "@headlessui/react"; 3 | import { CheckIcon, XMarkIcon } from "@heroicons/react/24/outline"; 4 | 5 | const toggleIconClassName = "relative left-[2px] top-[2px] h-4 w-4 stroke-[3]"; 6 | 7 | type ToggleProps = { 8 | className?: string; 9 | checked?: boolean; 10 | onChange: (checked: boolean) => void; 11 | disabled?: boolean; 12 | id?: string; 13 | }; 14 | 15 | const Toggle = ({ className, ...props }: ToggleProps) => { 16 | return ( 17 | 21 | 22 | 23 | 24 | 25 | 26 | ); 27 | }; 28 | 29 | export default Toggle; 30 | -------------------------------------------------------------------------------- /app/components/Warning.tsx: -------------------------------------------------------------------------------- 1 | import { ExclamationCircleIcon } from "@heroicons/react/24/solid"; 2 | 3 | import { CONTENT_MAX_WIDTH } from "./PageWidthGrid"; 4 | 5 | import { UserWarning } from "../context/userState"; 6 | 7 | export default function Warning({ 8 | userWarning, 9 | onDismiss, 10 | className, 11 | }: { 12 | userWarning: UserWarning; 13 | onDismiss: () => void; 14 | className?: string; 15 | }) { 16 | const { content, dismissible, icon, link } = userWarning; 17 | return ( 18 |
21 | {icon || ( 22 |
23 | 24 |
25 | )} 26 | {content}{" "} 27 | {link && ( 28 | 29 | More information. 30 | 31 | )} 32 | {dismissible && ( 33 | 36 | )} 37 |
38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /app/components/WebmVideo.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | // WebmVideo is a component that renders a video element with a fallback & loading image 4 | export const WebmVideo = ({ 5 | src, 6 | fallbackSrc, 7 | className, 8 | alt, 9 | }: { 10 | src: string; 11 | fallbackSrc: string; 12 | alt: string; 13 | className?: string; 14 | }) => ( 15 | 19 | ); 20 | -------------------------------------------------------------------------------- /app/config/customization_config.ts: -------------------------------------------------------------------------------- 1 | export const CUSTOMIZATION_ENDPOINT = `${process.env.NEXT_PUBLIC_SCORER_ENDPOINT}/account/customization`; 2 | -------------------------------------------------------------------------------- /app/config/feature_flags.ts: -------------------------------------------------------------------------------- 1 | export type FEATURE_FLAG_TYPE = "FF_CHAIN_SYNC"; 2 | 3 | export let FeatureFlags: Record = { 4 | FF_CHAIN_SYNC: false, 5 | }; 6 | 7 | function configureFeatureFlag( 8 | queryString: URLSearchParams, 9 | featureFlag: FEATURE_FLAG_TYPE, 10 | envVar: string | undefined 11 | ) { 12 | // We want to allow the user to override feature flags in URLs 13 | const urlValue = queryString.get(featureFlag); 14 | 15 | if (urlValue && ["on", "off"].includes(urlValue)) { 16 | FeatureFlags[featureFlag] = urlValue === "on"; 17 | } else { 18 | FeatureFlags[featureFlag] = envVar === "on"; 19 | } 20 | } 21 | 22 | // FeatureFlags need to reliably be set before the chains are configured, and chains 23 | // must be configured before web3Onboard which must be initialized before any 24 | // React code, so we'll do it here. 25 | 26 | if (typeof window !== "undefined") { 27 | const queryString = new URLSearchParams(window?.location?.search); 28 | 29 | // The env var names can't be dynamic due to the way Next.js works 30 | configureFeatureFlag(queryString, "FF_CHAIN_SYNC", process.env.NEXT_PUBLIC_FF_CHAIN_SYNC); 31 | } 32 | -------------------------------------------------------------------------------- /app/config/filters.ts: -------------------------------------------------------------------------------- 1 | export const STAMP_FILTERS: { 2 | [key: string]: { 3 | name: string; 4 | stamps: { 5 | [key: string]: string[]; 6 | }; 7 | }; 8 | } = { 9 | "bankless-academy": { 10 | name: "Bankless Academy", 11 | stamps: { 12 | Google: ["Account Name"], 13 | Ens: ["Account Name"], 14 | Poh: ["Account Name"], 15 | Twitter: ["Account Name"], 16 | Brightid: ["Account Name"], 17 | Linkedin: ["Account Name"], 18 | Discord: ["Account Name"], 19 | }, 20 | }, 21 | }; 22 | 23 | export const getStampProviderFilters = (filter: string): any => { 24 | let stampFilters: any = false; 25 | if (Object.keys(STAMP_FILTERS).includes(filter)) { 26 | stampFilters = STAMP_FILTERS[filter].stamps; 27 | } 28 | return stampFilters; 29 | }; 30 | 31 | export const getFilterName = (filter: string): any => { 32 | let filterName: any = false; 33 | if (Object.keys(STAMP_FILTERS).includes(filter)) { 34 | filterName = STAMP_FILTERS[filter].name; 35 | } 36 | return filterName; 37 | }; 38 | -------------------------------------------------------------------------------- /app/config/platforms.ts: -------------------------------------------------------------------------------- 1 | import { PlatformSpec, platforms } from "@gitcoin/passport-platforms"; 2 | 3 | export const getPlatformSpec = (platformName: string): PlatformSpec | undefined => { 4 | return platforms[platformName]?.PlatformDetails; 5 | }; 6 | 7 | export const PLATFORMS: PlatformSpec[] = Object.values(platforms).map((platform) => platform.PlatformDetails); 8 | -------------------------------------------------------------------------------- /app/config/providers.ts: -------------------------------------------------------------------------------- 1 | import { PLATFORM_ID } from "@gitcoin/passport-types"; 2 | import { platforms, ProviderSpec, PlatformGroupSpec } from "@gitcoin/passport-platforms"; 3 | export type { ProviderSpec, PlatformGroupSpec }; 4 | 5 | export type UpdatedPlatforms = { 6 | [key: string]: boolean; 7 | }; 8 | 9 | // Platform -> Provider[] 10 | export type Providers = { 11 | [platform in PLATFORM_ID]: PlatformGroupSpec[]; 12 | }; 13 | 14 | const providerConfigs = Object.entries(platforms).reduce( 15 | (configs, [platformName, platform]) => ({ 16 | ...configs, 17 | [platformName]: platform?.ProviderConfig, 18 | }), 19 | {} as Record 20 | ); 21 | 22 | export const STAMP_PROVIDERS: Readonly = { 23 | ...providerConfigs, 24 | Signer: [ 25 | { 26 | platformGroup: "Account Name", 27 | providers: [{ title: "Encrypted", name: "Signer" }], 28 | }, 29 | ], 30 | }; 31 | -------------------------------------------------------------------------------- /app/config/stamp_config.ts: -------------------------------------------------------------------------------- 1 | import { SignatureType } from "@gitcoin/passport-types"; 2 | 3 | export const IAM_SIGNATURE_TYPE: SignatureType = 4 | process.env.NEXT_PUBLIC_PASSPORT_IAM_SIGNATURE_TYPE?.toLowerCase() === "eip712" ? "EIP712" : "Ed25519"; 5 | 6 | // Change of plan. We should not use stamps v2. 7 | // The diferentiation of what exact stamp format is used can be made based on data in the stamp itself. 8 | // There is no need to store additional metadata. 9 | // References to STAMPS_V2 shall be deleted in the future. 10 | // const USE_STAMPS_V2 = IAM_SIGNATURE_TYPE === "EIP712"; 11 | const USE_STAMPS_V2 = false; 12 | 13 | const CERAMIC_CACHE_ENDPOINT_V1 = process.env.NEXT_PUBLIC_CERAMIC_CACHE_ENDPOINT; 14 | const CERAMIC_CACHE_ENDPOINT_V2 = process.env.NEXT_PUBLIC_CERAMIC_CACHE_ENDPOINT_V2; 15 | export const CERAMIC_CACHE_ENDPOINT = USE_STAMPS_V2 ? CERAMIC_CACHE_ENDPOINT_V2 : CERAMIC_CACHE_ENDPOINT_V1; 16 | 17 | const IAM_ISSUER_DID_V1 = process.env.NEXT_PUBLIC_PASSPORT_IAM_ISSUER_DID || ""; 18 | const IAM_ISSUER_DID_V2 = process.env.NEXT_PUBLIC_PASSPORT_IAM_ISSUER_DID_V2 || ""; 19 | 20 | // We are going tu support multiple valid issuers 21 | export const IAM_VALID_ISSUER_DIDS = new Set([IAM_ISSUER_DID_V2, IAM_ISSUER_DID_V1]); 22 | 23 | export const iamUrl = process.env.NEXT_PUBLIC_PASSPORT_IAM_URL || "http://localhost:80/api/"; 24 | -------------------------------------------------------------------------------- /app/context/testModeState.tsx: -------------------------------------------------------------------------------- 1 | // This file provides a minimal import to see whether or not the app is in test mode, 2 | // and a toggle function which reloads the page in the opposite mode. 3 | 4 | // This is only set on page load (required to support wallet modal config) 5 | export const TEST_MODE = typeof window !== "undefined" && window.sessionStorage.getItem("testMode") === "on"; 6 | 7 | export const toggleTestMode = () => { 8 | if (TEST_MODE) { 9 | window.sessionStorage.setItem("testMode", "off"); 10 | } else { 11 | window.sessionStorage.setItem("testMode", "on"); 12 | } 13 | window.location.reload(); 14 | }; 15 | -------------------------------------------------------------------------------- /app/context/userState.tsx: -------------------------------------------------------------------------------- 1 | // --- React Methods 2 | import React from "react"; 3 | 4 | // --- Utils & configs 5 | import { atom } from "jotai"; 6 | 7 | type UserWarningName = "expiredStamp" | "cacaoError"; 8 | 9 | export interface UserWarning { 10 | content: React.ReactNode; 11 | icon?: React.ReactNode; 12 | name?: UserWarningName; 13 | dismissible?: boolean; 14 | link?: string; 15 | } 16 | 17 | export const userWarningAtom = atom(undefined); 18 | 19 | export interface UserVerification { 20 | loading: boolean; 21 | success: boolean; 22 | error?: string; 23 | } 24 | 25 | export const userVerificationAtom = atom({ 26 | loading: false, 27 | success: false, 28 | error: undefined, 29 | }); 30 | 31 | export const mutableUserVerificationAtom = atom( 32 | (get) => get(userVerificationAtom), 33 | (_get, set, newState: UserVerification) => { 34 | set(userVerificationAtom, newState); 35 | } 36 | ); 37 | -------------------------------------------------------------------------------- /app/jest.config.ts: -------------------------------------------------------------------------------- 1 | const nextJest = require("next/jest"); 2 | global.TextDecoder = require("util").TextDecoder; 3 | 4 | const createJestConfig = nextJest({ 5 | // Provide the path to your Next.js app to load next.config.js and .env files in your test environment 6 | dir: "./", 7 | }); 8 | 9 | // Add any custom config to be passed to Jest 10 | const customJestConfig = { 11 | testEnvironment: "jest-environment-jsdom", 12 | testEnvironmentOptions: {}, 13 | moduleNameMapper: { 14 | "\\.(gif|ttf|eot|svg|png)$": "/__mocks__/fileMock.js", 15 | "\\.(css|less|sass|scss)$": "identity-obj-proxy", 16 | // Handle module aliases 17 | "^@/components/(.*)$": "/components/$1", 18 | "^@/pages/(.*)$": "/pages/$1", 19 | }, 20 | setupFilesAfterEnv: ["/jest.setup.ts"], 21 | setupFiles: ["jest-localstorage-mock"], 22 | resetMocks: false, 23 | }; 24 | 25 | export default createJestConfig(customJestConfig); 26 | -------------------------------------------------------------------------------- /app/jest.setup.ts: -------------------------------------------------------------------------------- 1 | import "@testing-library/jest-dom"; 2 | import { TextDecoder, TextEncoder } from "util"; 3 | global.TextDecoder = TextDecoder as any; 4 | global.TextEncoder = TextEncoder as any; 5 | 6 | const mockWallet = { 7 | address: "0xfF7edbD01e9d044486781ff52c42EA7a01612644", 8 | chain: "0xa", 9 | provider: jest.fn(), 10 | }; 11 | 12 | jest.mock("@web3-onboard/react", () => ({ 13 | init: () => ({ 14 | connectWallet: () => Promise.resolve([mockWallet]), 15 | disconnectWallet: () => Promise.resolve(), 16 | state: { 17 | select: () => ({ 18 | subscribe: () => {}, 19 | }), 20 | }, 21 | }), 22 | useConnectWallet: () => [{ wallet: mockWallet }, () => Promise.resolve([mockWallet]), jest.fn()], 23 | })); 24 | 25 | jest.mock("@web3-onboard/injected-wallets", () => ({ 26 | __esModule: true, 27 | default: () => {}, 28 | })); 29 | 30 | jest.mock("@web3-onboard/walletconnect", () => ({ 31 | __esModule: true, 32 | default: () => {}, 33 | })); 34 | -------------------------------------------------------------------------------- /app/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /app/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | module.exports = { 3 | output: "export", 4 | exportPathMap: function () { 5 | return { 6 | "/": { page: "/" }, 7 | }; 8 | }, 9 | reactStrictMode: true, 10 | webpack: function (config, { _isServer }) { 11 | config.experiments = { asyncWebAssembly: true }; 12 | config.resolve.fallback = { fs: false, net: false, tls: false }; 13 | return config; 14 | }, 15 | }; 16 | -------------------------------------------------------------------------------- /app/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /app/public/assets/arb-logo.svg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HowittColet/passport/bd7c79421d508ee94a2a1142dec0619b35844b3b/app/public/assets/arb-logo.svg -------------------------------------------------------------------------------- /app/public/assets/arrow-left-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/public/assets/arrow-right-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/public/assets/backgroundRock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HowittColet/passport/bd7c79421d508ee94a2a1142dec0619b35844b3b/app/public/assets/backgroundRock.png -------------------------------------------------------------------------------- /app/public/assets/brightidStampIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/public/assets/check-icon-grey.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/public/assets/check-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/public/assets/check-icon2.svg: -------------------------------------------------------------------------------- 1 | 2 | 11 | 13 | 19 | 26 | 27 | -------------------------------------------------------------------------------- /app/public/assets/civicStampIcon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/public/assets/clock-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/public/assets/coinbaseStampIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/public/assets/dashboardIllustration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HowittColet/passport/bd7c79421d508ee94a2a1142dec0619b35844b3b/app/public/assets/dashboardIllustration.png -------------------------------------------------------------------------------- /app/public/assets/ethLogo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/public/assets/ethStampIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/public/assets/facebookStampIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/public/assets/githubWhiteStampIcon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/public/assets/goerli-base-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /app/public/assets/googleStampIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/public/assets/gtcStakingLogoIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/public/assets/hexagonIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/public/assets/information-circle-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/public/assets/linea-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HowittColet/passport/bd7c79421d508ee94a2a1142dec0619b35844b3b/app/public/assets/linea-logo.png -------------------------------------------------------------------------------- /app/public/assets/linkedinStampIcon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/public/assets/lockIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/public/assets/logoLine.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/public/assets/onboarding.webm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HowittColet/passport/bd7c79421d508ee94a2a1142dec0619b35844b3b/app/public/assets/onboarding.webm -------------------------------------------------------------------------------- /app/public/assets/optimism_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HowittColet/passport/bd7c79421d508ee94a2a1142dec0619b35844b3b/app/public/assets/optimism_logo.png -------------------------------------------------------------------------------- /app/public/assets/personIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/public/assets/pgn-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HowittColet/passport/bd7c79421d508ee94a2a1142dec0619b35844b3b/app/public/assets/pgn-logo.png -------------------------------------------------------------------------------- /app/public/assets/pgn-logo.svg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HowittColet/passport/bd7c79421d508ee94a2a1142dec0619b35844b3b/app/public/assets/pgn-logo.svg -------------------------------------------------------------------------------- /app/public/assets/phiLogoIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | phi logo bold 8080ff-white@1x 4 | 5 | 12 | 13 | -------------------------------------------------------------------------------- /app/public/assets/plus-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/public/assets/purple-check-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/public/assets/shield-alert.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/public/assets/shield-exclamation-icon-warning.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/public/assets/shield-exclamation-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/public/assets/snapshotStampIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | icon 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/public/assets/splashPageLogo.webm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HowittColet/passport/bd7c79421d508ee94a2a1142dec0619b35844b3b/app/public/assets/splashPageLogo.webm -------------------------------------------------------------------------------- /app/public/assets/splashPageTexture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HowittColet/passport/bd7c79421d508ee94a2a1142dec0619b35844b3b/app/public/assets/splashPageTexture.png -------------------------------------------------------------------------------- /app/public/assets/trustaLabsStampIcon.svg: -------------------------------------------------------------------------------- 1 | 资源 1 -------------------------------------------------------------------------------- /app/public/assets/twitterStampIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/public/assets/verification-failed-bright.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/public/assets/verification-failed.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/public/assets/verifiedShield.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/public/assets/welcome-back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HowittColet/passport/bd7c79421d508ee94a2a1142dec0619b35844b3b/app/public/assets/welcome-back.png -------------------------------------------------------------------------------- /app/public/assets/welcome-get-started.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HowittColet/passport/bd7c79421d508ee94a2a1142dec0619b35844b3b/app/public/assets/welcome-get-started.png -------------------------------------------------------------------------------- /app/public/assets/welcome-passport-scoring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HowittColet/passport/bd7c79421d508ee94a2a1142dec0619b35844b3b/app/public/assets/welcome-passport-scoring.png -------------------------------------------------------------------------------- /app/public/assets/welcome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HowittColet/passport/bd7c79421d508ee94a2a1142dec0619b35844b3b/app/public/assets/welcome.png -------------------------------------------------------------------------------- /app/public/assets/white-check-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/public/assets/whiteBgShieldExclamation.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/public/assets/x-icon-black.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/public/assets/x-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/public/assets/x-mark-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HowittColet/passport/bd7c79421d508ee94a2a1142dec0619b35844b3b/app/public/favicon.ico -------------------------------------------------------------------------------- /app/styles/globals.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=DM+Mono&display=swap"); 2 | 3 | /* This sources Adobe CC fonts */ 4 | @import url("https://use.typekit.net/tdl1ktm.css"); 5 | 6 | @tailwind base; 7 | @tailwind components; 8 | @tailwind utilities; 9 | 10 | @layer components { 11 | .verify-btn { 12 | @apply w-full border-t border-accent-2 p-2 hover:text-accent-3; 13 | } 14 | .verify-btn:disabled { 15 | @apply text-gray-400; 16 | } 17 | } 18 | 19 | .step-icon-inner { 20 | width: 0.625rem; 21 | height: 0.625rem; 22 | 23 | animation-duration: 1s; 24 | animation-name: step-icon-loading; 25 | animation-iteration-count: infinite; 26 | animation-direction: alternate; 27 | animation-timing-function: ease; 28 | } 29 | 30 | :root { 31 | --onboard-shadow-3: none; 32 | --account-center-position-top: -14px; 33 | --account-center-position-right: 4.1rem; 34 | --account-center-border-radius: 16px; 35 | --onboard-action-required-btn-text-color: #fff; 36 | --onboard-font-family-normal: var(--font-body); 37 | } 38 | 39 | .override-text-color * { 40 | color: inherit !important; 41 | } 42 | 43 | @media (max-width: 1020px /* md */) { 44 | :root { 45 | --account-center-position-right: 24px; 46 | } 47 | } 48 | 49 | @media (max-width: 480px /* base */) { 50 | :root { 51 | --account-center-position-right: 0px; 52 | --onboard-modal-top: 0; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "target": "ES2022", 5 | "lib": ["dom", "dom.iterable", "esnext"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "strict": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "noEmit": true, 11 | "esModuleInterop": true, 12 | "module": "esnext", 13 | "moduleResolution": "node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "jsx": "preserve", 17 | "incremental": true, 18 | }, 19 | "include": [ 20 | "next-env.d.ts", 21 | "**/*.ts", 22 | "**/*.tsx", 23 | "./*.tsx", 24 | "jest.config.ts", 25 | "jest.setup.ts", 26 | ], 27 | "exclude": ["node_modules"], 28 | "ts-node": { 29 | "esm": true, 30 | "compilerOptions": { 31 | "module": "nodenext", 32 | }, 33 | }, 34 | } 35 | -------------------------------------------------------------------------------- /app/types.ts: -------------------------------------------------------------------------------- 1 | import { Passport, Stamp, DID } from "@gitcoin/passport-types"; 2 | 3 | // Class used as a base for each DataStorage Type 4 | export abstract class DataStorageBase { 5 | abstract createPassport(): DID; 6 | abstract getPassport(did: DID): Passport | undefined; 7 | abstract addStamp(did: DID, stamp: Stamp): void; 8 | } 9 | -------------------------------------------------------------------------------- /app/utils/__mocks__/onboard.ts: -------------------------------------------------------------------------------- 1 | export const RINKEBY_RPC_URL = "https://rinkeby.infura.io/v3/someApiKey"; 2 | export const MAINNET_RPC_URL = "https://rinkeby.infura.io/v3/someApiKey"; 3 | -------------------------------------------------------------------------------- /app/utils/onChainStatus.ts: -------------------------------------------------------------------------------- 1 | export enum OnChainStatus { 2 | LOADING, 3 | NOT_MOVED, 4 | MOVED_OUT_OF_DATE, 5 | MOVED_UP_TO_DATE, 6 | } 7 | -------------------------------------------------------------------------------- /app/utils/onboard.ts: -------------------------------------------------------------------------------- 1 | import { init } from "@web3-onboard/react"; 2 | import injectedModule from "@web3-onboard/injected-wallets"; 3 | import walletConnectModule, { WalletConnectOptions } from "@web3-onboard/walletconnect"; 4 | import { chains } from "./chains"; 5 | 6 | // Injected wallet - shows all available injected wallets 7 | 8 | const injected = injectedModule(); 9 | 10 | // web3Onboard modules 11 | const walletConnectProjectId = (process.env.NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID as string) || "default-project-id"; 12 | 13 | const walletConnectOptions: WalletConnectOptions = { 14 | projectId: walletConnectProjectId, 15 | }; 16 | 17 | const onBoardExploreUrl = 18 | (process.env.NEXT_PUBLIC_WEB3_ONBOARD_EXPLORE_URL as string) || "https://passport.gitcoin.co/"; 19 | 20 | const walletConnect = walletConnectModule(walletConnectOptions); 21 | 22 | // Exports onboard-core instance (https://github.com/blocknative/web3-onboard) 23 | export const onboard = init({ 24 | wallets: [injected, walletConnect], 25 | chains: chains.map(({ id, token, label, rpcUrl, icon }) => ({ id, token, label, rpcUrl, icon })), 26 | appMetadata: { 27 | name: "Passport", 28 | icon: "/assets/gitcoinLogo.svg", 29 | logo: "/assets/gitcoinLogo.svg", 30 | description: "Decentralized Identity Verification", 31 | explore: onBoardExploreUrl, 32 | recommendedInjectedWallets: [ 33 | { name: "Coinbase", url: "https://wallet.coinbase.com/" }, 34 | { name: "MetaMask", url: "https://metamask.io" }, 35 | ], 36 | }, 37 | }); 38 | -------------------------------------------------------------------------------- /app/utils/theme/chakra/Menu.tsx: -------------------------------------------------------------------------------- 1 | import type { ComponentStyleConfig } from "@chakra-ui/theme"; 2 | 3 | const hoverStyle = { 4 | bg: "rgb(var(--color-background-3))", 5 | color: "rgb(var(--color-text-1))", 6 | }; 7 | 8 | const Menu: ComponentStyleConfig = { 9 | parts: ["item", "list"], 10 | baseStyle: { 11 | item: { 12 | _hover: hoverStyle, 13 | _focus: hoverStyle, 14 | }, 15 | list: { 16 | background: "rgb(var(--color-background))", 17 | borderColor: "rgb(var(--color-background-3))", 18 | }, 19 | }, 20 | }; 21 | 22 | export default Menu; 23 | -------------------------------------------------------------------------------- /app/utils/theme/chakra/Modal.tsx: -------------------------------------------------------------------------------- 1 | import type { ComponentStyleConfig } from "@chakra-ui/theme"; 2 | 3 | const Modal: ComponentStyleConfig = { 4 | parts: ["dialog"], 5 | baseStyle: { 6 | dialog: { 7 | marginTop: "5rem", 8 | bg: "rgb(var(--color-background))", 9 | color: "rgb(var(--color-text-1))", 10 | border: "solid 1px rgb(var(--color-foreground-6))", 11 | }, 12 | }, 13 | }; 14 | 15 | export default Modal; 16 | -------------------------------------------------------------------------------- /app/utils/theme/index.tsx: -------------------------------------------------------------------------------- 1 | export { default as ThemeWrapper } from "./themeWrapper"; 2 | export { default as palette } from "./palette"; 3 | export * as themes from "./themes"; 4 | export { default as setTheme } from "./setTheme"; 5 | export type { Theme } from "./types"; 6 | -------------------------------------------------------------------------------- /app/utils/theme/palette.tsx: -------------------------------------------------------------------------------- 1 | export const palette = Object.entries({ 2 | black: "#000000", 3 | white: "#ffffff", 4 | gray: "#6d6d6d", 5 | nightBlue: "#122b33", 6 | ironGray: "#4b5f65", 7 | iris: "#4a47d3", 8 | seaFoam: "#6cB6ad", 9 | green: "#22645c", 10 | darkPurple: "#08205f", 11 | iceBlue: "#c1f6ff", 12 | turquoise: "#074853", 13 | paleYellow: "#d2dc95", 14 | red: "#ff5c00", 15 | }).reduce( 16 | (rgbPalette, [name, hex]) => { 17 | rgbPalette[name] = hexToRGB(hex); 18 | return rgbPalette; 19 | }, 20 | {} as Record 21 | ); 22 | 23 | export function hexToRGB(hex: string) { 24 | const r = parseInt(hex.slice(1, 3), 16) || 0, 25 | g = parseInt(hex.slice(3, 5), 16) || 0, 26 | b = parseInt(hex.slice(5, 7), 16) || 0; 27 | 28 | return "" + r + " " + g + " " + b; 29 | } 30 | 31 | export default palette; 32 | -------------------------------------------------------------------------------- /app/utils/theme/setCustomizationTheme.tsx: -------------------------------------------------------------------------------- 1 | import { hexToRGB } from "./palette"; 2 | import { CustomizationTheme } from "./types"; 3 | 4 | export const setCustomizationTheme = ({ colors }: CustomizationTheme) => { 5 | const r = document.documentElement; 6 | 7 | // We can do this for every sort of tailwind class and CSS prop, 8 | // for example if we need a dynamic caption size we can do... 9 | // (note: this is untested and just an example, but it should work) 10 | // r.style.setProperty("--font-customization-caption-size", font.customizationCaptionSize); 11 | // we'd set it to something like 1.5rem or 24px 12 | // and then in tailwind config... 13 | // fontSize: { "customization-caption-size": "var(--font-customization-caption-size)" } 14 | // and then we can use it in our components... 15 | //

Hello world

16 | 17 | r.style.setProperty("--color-customization-background-1", convertHexToRGB(colors.customizationBackground1)); 18 | r.style.setProperty("--color-customization-background-2", convertHexToRGB(colors.customizationBackground2)); 19 | r.style.setProperty("--color-customization-foreground-1", convertHexToRGB(colors.customizationForeground1)); 20 | }; 21 | 22 | const convertHexToRGB = (color: string) => { 23 | if (color.startsWith("#")) { 24 | return hexToRGB(color); 25 | } 26 | return color; 27 | }; 28 | -------------------------------------------------------------------------------- /app/utils/theme/setTheme.tsx: -------------------------------------------------------------------------------- 1 | import { Theme } from "./types"; 2 | 3 | const setTheme = ({ colors, fonts }: Theme) => { 4 | const r = document.documentElement; 5 | 6 | r.style.setProperty("--color-background", colors.background); 7 | r.style.setProperty("--color-background-2", colors.background2); 8 | r.style.setProperty("--color-background-3", colors.background3); 9 | r.style.setProperty("--color-background-4", colors.background4); 10 | r.style.setProperty("--color-foreground", colors.foreground); 11 | r.style.setProperty("--color-foreground-2", colors.foreground2); 12 | r.style.setProperty("--color-foreground-3", colors.foreground3); 13 | r.style.setProperty("--color-foreground-4", colors.foreground4); 14 | r.style.setProperty("--color-foreground-5", colors.foreground5); 15 | r.style.setProperty("--color-foreground-6", colors.foreground6); 16 | r.style.setProperty("--color-foreground-7", colors.foreground7); 17 | r.style.setProperty("--color-text-1", colors.text1); 18 | r.style.setProperty("--color-text-2", colors.text2); 19 | r.style.setProperty("--color-text-3", colors.text3); 20 | r.style.setProperty("--color-text-4", colors.text4); 21 | r.style.setProperty("--color-text-5", colors.text5); 22 | r.style.setProperty("--color-text-6", colors.text6); 23 | r.style.setProperty("--color-focus", colors.focus); 24 | 25 | r.style.setProperty("--font-body", fonts.body); 26 | r.style.setProperty("--font-heading", fonts.heading); 27 | r.style.setProperty("--font-alt", fonts.alt); 28 | }; 29 | 30 | export default setTheme; 31 | -------------------------------------------------------------------------------- /app/utils/theme/themes.tsx: -------------------------------------------------------------------------------- 1 | import { Theme } from "./types"; 2 | import palette from "./palette"; 3 | 4 | export const LUNARPUNK_DARK_MODE: Theme = { 5 | colors: { 6 | background: palette.black, 7 | background2: palette.darkPurple, 8 | background3: palette.iris, 9 | background4: palette.nightBlue, 10 | foreground: palette.white, 11 | foreground2: palette.iceBlue, 12 | foreground3: palette.ironGray, 13 | foreground4: palette.seaFoam, 14 | foreground5: palette.green, 15 | foreground6: palette.turquoise, 16 | foreground7: palette.paleYellow, 17 | text1: palette.white, 18 | text2: palette.seaFoam, 19 | text3: palette.nightBlue, 20 | text4: palette.black, 21 | text5: palette.gray, 22 | text6: palette.iceBlue, 23 | focus: palette.red, 24 | }, 25 | fonts: { 26 | body: "futura-pt", 27 | heading: "futura-pt", 28 | alt: "DM Mono", 29 | }, 30 | }; 31 | -------------------------------------------------------------------------------- /app/utils/theme/types.tsx: -------------------------------------------------------------------------------- 1 | export type Theme = { 2 | colors: { 3 | background: string; 4 | background2: string; 5 | background3: string; 6 | background4: string; 7 | foreground: string; 8 | foreground2: string; 9 | foreground3: string; 10 | foreground4: string; 11 | foreground5: string; 12 | foreground6: string; 13 | foreground7: string; 14 | text1: string; 15 | text2: string; 16 | text3: string; 17 | text4: string; 18 | text5: string; 19 | text6: string; 20 | focus: string; 21 | }; 22 | fonts: { 23 | body: string; 24 | heading: string; 25 | alt: string; 26 | }; 27 | }; 28 | 29 | export type CustomizationTheme = { 30 | colors: { 31 | customizationBackground1: string; 32 | customizationBackground2: string; 33 | customizationForeground1: string; 34 | }; 35 | }; 36 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = {extends: ['@commitlint/config-conventional']}; 2 | -------------------------------------------------------------------------------- /database-client/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | pnpm-debug.log* 10 | lerna-debug.log* 11 | 12 | # dependencies 13 | /node_modules 14 | /.pnp 15 | .pnp.js 16 | 17 | # build 18 | /dist 19 | 20 | # testing 21 | /coverage 22 | 23 | # production 24 | /build 25 | 26 | # ceramic 27 | .pinning.store 28 | 29 | # misc 30 | .DS_Store 31 | .env 32 | .env.local 33 | .env.development.local 34 | .env.test.local 35 | .env.production.local 36 | .eslintcache 37 | 38 | npm-debug.log* 39 | yarn-debug.log* 40 | yarn-error.log* 41 | -------------------------------------------------------------------------------- /database-client/README.md: -------------------------------------------------------------------------------- 1 | # database-client 2 | 3 | ## Running the Ceramic integration tests locally 4 | 5 | > Start up the Ceramic daemon in another thread 6 | 7 | ```bash 8 | yarn run ceramic 9 | ``` 10 | 11 | > Run the integration tests 12 | 13 | ```bash 14 | yarn run test:integration 15 | ``` 16 | 17 | **Note:** Use the `CERAMIC_CLIENT_URL` env variable (like `export CERAMIC_CLIENT_URL=http://127.0.0.1:7007`) to change the ceramic client URL for the integration tests if required. 18 | 19 | ## Running the Ceramic integration tests in Docker 20 | 21 | IMPORTANT this will overwrite your `schemas/scripts/create-model.json` and `schemas/scripts/publish-model.json` files! Make a backup of these files! 22 | 23 | ```bash 24 | docker-compose up -d 25 | ``` 26 | 27 | Tests are flaky the first time, possibly due to connection issues with the Ceramic node. If tests fail due to an error like `request to http://localhost:7007/api/v0/streams failed, reason: connect ECONNREFUSED 127.0.0.1:7007`, try running `docker-compose up -d` again to re-run the tests. 28 | -------------------------------------------------------------------------------- /database-client/__tests__/integration-test-model-aliases.json: -------------------------------------------------------------------------------- 1 | {"definitions":{"Passport":"kjzl6cwe1jw145znqlxwwar1crvgsm3wf56vcnxo6bu87fqsi6519eypjnzs7mu","VerifiableCredential":"kjzl6cwe1jw149zuvayqa89nhmlvwm0pkdkj0awlxhmtbbay6i972xuwy14jg4f"},"schemas":{"Passport":"ceramic://k3y52l7qbv1fryatc5h4xpnusk6vw8pmle6duu11djx2dke2senbiecu1fw1wrif4","VerifiableCredential":"ceramic://k3y52l7qbv1fry8pdl0tpicir0jxfwktanqceca89gsvy9geg7o2cd4b6hdr33uv4"},"tiles":{}} -------------------------------------------------------------------------------- /database-client/composedb.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "anchor": {}, 3 | "http-api": { 4 | "cors-allowed-origins": [".*"], 5 | "admin-dids": [ 6 | "did:key:z6MknU3gBqubYTbXbHnHzpJurGyrssbpLdS7Mbz1uHdGdzdo", 7 | "did:key:z6Mki9zj9fFYxBbQcaC6EJvST8XHv7i4iXsP281gJV5nM5Hy#z6Mki9zj9fFYxBbQcaC6EJvST8XHv7i4iXsP281gJV5nM5Hy" 8 | ] 9 | }, 10 | "ipfs": { "mode": "bundled" }, 11 | "logger": { "log-level": 2, "log-to-files": false }, 12 | "metrics": { "metrics-exporter-enabled": false, "metrics-port": 9090 }, 13 | "network": { "name": "inmemory" }, 14 | "node": {}, 15 | "state-store": { 16 | "mode": "fs", 17 | "local-directory": "/Users/timschultz/repos/compose-db/ceramic-app/ceramic-app-app/.ceramic/.ceramic/statestore/" 18 | }, 19 | "indexing": { 20 | "db": "sqlite:///Users/timschultz/repos/compose-db/ceramic-app/ceramic-app-app/.ceramic/indexing.sqlite", 21 | "allow-queries-before-historical-sync": true, 22 | "models": [] 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /database-client/integration-tests/integration-test-model-aliases.json: -------------------------------------------------------------------------------- 1 | {"definitions":{"Passport":"kjzl6cwe1jw145znqlxwwar1crvgsm3wf56vcnxo6bu87fqsi6519eypjnzs7mu","VerifiableCredential":"kjzl6cwe1jw149zuvayqa89nhmlvwm0pkdkj0awlxhmtbbay6i972xuwy14jg4f"},"schemas":{"Passport":"ceramic://k3y52l7qbv1fryatc5h4xpnusk6vw8pmle6duu11djx2dke2senbiecu1fw1wrif4","VerifiableCredential":"ceramic://k3y52l7qbv1fry8pdl0tpicir0jxfwktanqceca89gsvy9geg7o2cd4b6hdr33uv4"},"tiles":{}} -------------------------------------------------------------------------------- /database-client/integration-tests/run-ceramic-tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # === preliminary installs === 4 | yarn global add lerna 5 | cd passport 6 | lerna bootstrap -- --ignore-scripts # skipping pre/postinstall scripts 7 | yarn build:database-client 8 | 9 | export CERAMIC_CLIENT_URL="https://ceramic-clay.3boxlabs.com" 10 | 11 | # === start up ceramic in background === 12 | until $(curl --output /dev/null --silent --head --fail $CERAMIC_CLIENT_URL/api/v0/node/healthcheck); do 13 | printf '... waiting for Ceramic daemon ...' 14 | sleep 5 15 | done 16 | 17 | # === fetch passport and VC definitions === 18 | curl $CERAMIC_CLIENT_URL/api/v0/streams/kjzl6cwe1jw145znqlxwwar1crvgsm3wf56vcnxo6bu87fqsi6519eypjnzs7mu 19 | curl $CERAMIC_CLIENT_URL/api/v0/streams/kjzl6cwe1jw149zuvayqa89nhmlvwm0pkdkj0awlxhmtbbay6i972xuwy14jg4f 20 | 21 | # === run ceramic integration tests === 22 | yarn test:ceramic-integration -------------------------------------------------------------------------------- /database-client/jest.config.cjs: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ 2 | 3 | module.exports = { 4 | transform: { 5 | "^.+\\.tsx?$": [ 6 | "ts-jest", 7 | { 8 | useESM: true, 9 | }, 10 | ], 11 | }, 12 | preset: "ts-jest", 13 | extensionsToTreatAsEsm: [".ts"], 14 | }; 15 | -------------------------------------------------------------------------------- /database-client/jest.integration.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | transform: {}, 3 | testMatch: ["**/integration-tests/**/*.js"], 4 | extensionsToTreatAsEsm: [".ts"], 5 | testTimeout: 10000, 6 | }; 7 | -------------------------------------------------------------------------------- /database-client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@gitcoin/passport-database-client", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "type": "module", 6 | "main": "dist/esm/src/index.js", 7 | "directories": { 8 | "src": "src", 9 | "dist": "dist" 10 | }, 11 | "files": [ 12 | "src", 13 | "dist" 14 | ], 15 | "publishConfig": { 16 | "access": "public" 17 | }, 18 | "scripts": { 19 | "build": "tsc", 20 | "clean": "rimraf dist node_modules", 21 | "debug": "tsc --watch", 22 | "ceramic": "CERAMIC_ENABLE_EXPERIMENTAL_COMPOSE_DB='true' ceramic daemon --config composedb.config.json", 23 | "test:integration": "yarn build && yarn node --experimental-vm-modules $(yarn bin jest) -c jest.integration.config.js", 24 | "test": "yarn node --experimental-vm-modules $(yarn bin jest) -c jest.config.cjs" 25 | }, 26 | "dependencies": { 27 | "@composedb/client": "^0.6.0", 28 | "@composedb/types": "^0.6.0", 29 | "@glazed/datamodel": "^0.3.0", 30 | "@glazed/did-datastore": "^0.3.1", 31 | "@glazed/tile-loader": "^0.2.0", 32 | "dids": "^5.0.2", 33 | "dotenv": "^16.0.0", 34 | "key-did-provider-ed25519": "^2.0.0", 35 | "key-did-resolver": "^4.0.0", 36 | "uint8arrays": "^5.0.1" 37 | }, 38 | "devDependencies": { 39 | "@ceramicnetwork/cli": "^3.2.0", 40 | "@composedb/cli": "^0.6.1", 41 | "@types/jest": "^27.4.1", 42 | "@types/node": "^16.11.6", 43 | "jest": "^29.6.4", 44 | "ts-jest": "^29.1.1", 45 | "ts-node": "^10.8.0" 46 | }, 47 | "resolutions": { 48 | "leveldown": "6.1.1" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /database-client/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./logger"; 2 | export * from "./passportScorerClient"; 3 | export * from "./composeDatabase"; 4 | export * from "./types"; 5 | -------------------------------------------------------------------------------- /database-client/src/logger.ts: -------------------------------------------------------------------------------- 1 | export type Logger = { 2 | error: (msg: string, context?: object) => void; 3 | log: (msg: string, context?: object) => void; 4 | warn: (msg: string, context?: object) => void; 5 | debug: (msg: string, context?: object) => void; 6 | info: (msg: string, context?: object) => void; 7 | }; 8 | 9 | -------------------------------------------------------------------------------- /database-client/src/types.ts: -------------------------------------------------------------------------------- 1 | import { 2 | PROVIDER_ID, 3 | Stamp, 4 | PassportLoadResponse, 5 | StampPatch, 6 | SecondaryStorageAddResponse, 7 | SecondaryStorageDeleteResponse, 8 | SecondaryStorageBulkPatchResponse, 9 | } from "@gitcoin/passport-types"; 10 | 11 | // Class used as a base for each DataStorage Type 12 | // Implementations should enforce 1 Passport <-> 1 user 13 | // and it is assumed which Passport/user to act on when 14 | // calling createPassport, getPassport, addStamp 15 | export interface DataStorageBase { 16 | did: string; 17 | createPassport: () => Promise; 18 | getPassport: () => Promise; 19 | addStamps: (stamps: Stamp[]) => Promise; 20 | patchStamps: (stampPatches: StampPatch[]) => Promise; 21 | deleteStamps: (providers: PROVIDER_ID[]) => Promise; 22 | } 23 | 24 | // To start reading from a secondary storage, CeramicContext will 25 | // need to be updated to handle propagation of this data, etc. 26 | // For now, we'll just define the write-only interface 27 | export interface WriteOnlySecondaryDataStorageBase { 28 | did: string; 29 | addStamps: (stamps: Stamp[]) => Promise; 30 | patchStamps: (stampPatches: StampPatch[]) => Promise; 31 | deleteStamps: (providers: PROVIDER_ID[]) => Promise; 32 | } 33 | -------------------------------------------------------------------------------- /database-client/src/utils.ts: -------------------------------------------------------------------------------- 1 | import { Stamp, VerifiableCredential } from "@gitcoin/passport-types"; 2 | 3 | export function getTilesToCreate(stamps: Stamp[], did: string, existingStamps?: Stamp[]) { 4 | const existingStampIdentifiers = existingStamps.map((s) => { 5 | const credential: VerifiableCredential = s.credential; 6 | return { hash: credential.credentialSubject.hash, issuanceDate: credential.issuanceDate } 7 | }); 8 | 9 | const stampsToSave = stamps.filter((s) => { 10 | const identifier = { hash: s.credential.credentialSubject.hash, issuanceDate: s.credential.issuanceDate }; 11 | // Check that stamp is not already saved and that the DID matches the passport DID 12 | return !existingStampIdentifiers.some(existingIdentifier => ( 13 | existingIdentifier.hash === identifier.hash && 14 | existingIdentifier.issuanceDate === identifier.issuanceDate 15 | )) && s.credential.issuer.toLocaleLowerCase() === did; 16 | }); 17 | 18 | return stampsToSave 19 | } 20 | -------------------------------------------------------------------------------- /database-client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.settings.json", 3 | "compilerOptions": { 4 | "module": "esnext", 5 | "esModuleInterop": true, 6 | "declaration": true, 7 | "allowSyntheticDefaultImports": true, 8 | "target": "es5", 9 | "moduleResolution": "node", 10 | "sourceMap": true, 11 | "outDir": "dist/esm", 12 | "allowJs": true, 13 | "baseUrl": "src", 14 | "paths": { 15 | "*": ["../node_modules/*", "node_modules/*"] 16 | }, 17 | "skipLibCheck": true, 18 | "resolveJsonModule": true 19 | }, 20 | "include": ["src/*", "___test___", "integration-tests"] 21 | } 22 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | ceramic-integration-test: 4 | image: node:16 5 | volumes: 6 | - ./database-client:/passport/database-client 7 | - ./schemas:/passport/schemas 8 | - ./types:/passport/types 9 | - ./lerna.json:/passport/lerna.json 10 | - ./package.json:/passport/package.json 11 | - ./tsconfig.json:/passport/tsconfig.json 12 | - ./tsconfig.settings.json:/passport/tsconfig.settings.json 13 | - ./yarn.lock:/passport/yarn.lock 14 | entrypoint: 15 | ["sh", "/passport/database-client/integration-tests/run-ceramic-tests.sh"] 16 | -------------------------------------------------------------------------------- /funding.json: -------------------------------------------------------------------------------- 1 | { 2 | "opRetro": { 3 | "projectId": "0x120cdd8e43ae1efbafdf02eda876e1952c05a52870c8d5a8f56d9ec0f79f586d" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /iam/.eslintignore: -------------------------------------------------------------------------------- 1 | /*.js 2 | /*.ts 3 | /dist/* 4 | /coverage/* 5 | /node_modules/* 6 | /__mocks__/**/* 7 | /__tests__/**/* 8 | -------------------------------------------------------------------------------- /iam/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | /dist 12 | /coverage 13 | dist-ssr 14 | *.local 15 | 16 | # Editor directories and files 17 | .vscode/* 18 | !.vscode/extensions.json 19 | .idea 20 | .DS_Store 21 | *.suo 22 | *.ntvs* 23 | *.njsproj 24 | *.sln 25 | *.sw? 26 | -------------------------------------------------------------------------------- /iam/.prettierignore: -------------------------------------------------------------------------------- 1 | /dist/* 2 | /coverage/* -------------------------------------------------------------------------------- /iam/.prettierrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ...require("../.prettierrc.js"), 3 | }; 4 | -------------------------------------------------------------------------------- /iam/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:20.11 2 | WORKDIR /usr/src 3 | 4 | COPY . . 5 | 6 | RUN yarn 7 | 8 | EXPOSE 80 443 9 | CMD [ "node", "iam/dist/iam/src/main.js" ] 10 | -------------------------------------------------------------------------------- /iam/__mocks__/@gitcoin/passport-identity/index.js: -------------------------------------------------------------------------------- 1 | const realIdentity = require("@gitcoin/passport-identity"); 2 | 3 | // mock everything that we're using in @gitcoin/passport-identity/dist/commonjs into an object and export it 4 | const identity = {}; 5 | 6 | // always returns dummy challenge 7 | identity.issueChallengeCredential = jest.fn(async (DIDKit, key, record) => ({ 8 | credential: { 9 | issuer: "empty", 10 | credentialSubject: { 11 | id: `did:pkh:eip155:1:${record.address}`, 12 | provider: `challenge-${record.type}`, 13 | challenge: "123456789ABDEFGHIJKLMNOPQRSTUVWXYZ", 14 | }, 15 | }, 16 | })); 17 | 18 | // always verifies 19 | identity.verifyCredential = jest.fn(async () => true); 20 | 21 | // return full mock 22 | module.exports = { 23 | ...realIdentity, 24 | ...identity, 25 | realIdentity, 26 | }; 27 | -------------------------------------------------------------------------------- /iam/__mocks__/dids/index.js: -------------------------------------------------------------------------------- 1 | const dids = { 2 | DID: jest.fn().mockImplementation(() => ({ 3 | verifyJWS: jest.fn(), 4 | })), 5 | }; 6 | 7 | module.exports = dids; 8 | -------------------------------------------------------------------------------- /iam/__mocks__/key-did-resolver/index.js: -------------------------------------------------------------------------------- 1 | const keyDidResolver = { 2 | getResolver: jest.fn(), 3 | }; 4 | 5 | module.exports = keyDidResolver; 6 | -------------------------------------------------------------------------------- /iam/babel.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-typescript", 4 | ["@babel/preset-env", { "targets": { "node": "current" } }] 5 | ], 6 | "plugins": [ 7 | "@babel/plugin-syntax-import-assertions", 8 | "babel-plugin-transform-import-meta", 9 | ["babel-plugin-replace-import-extension", { "extMapping": { ".js": "" } }], 10 | "@babel/plugin-transform-modules-commonjs" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /iam/jest.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | modulePathIgnorePatterns: ["/dist/"], 3 | setupFiles: ["dotenv/config", "/jest.setup.cjs"], 4 | testEnvironment: "node", 5 | }; 6 | -------------------------------------------------------------------------------- /iam/jest.setup.cjs: -------------------------------------------------------------------------------- 1 | const DIDKit = require("@spruceid/didkit-wasm-node"); 2 | 3 | process.env.IAM_JWK = DIDKit.generateEd25519Key(); 4 | process.env.IAM_JWK_EIP712 = 5 | '{"kty":"EC","crv":"secp256k1","x":"PdB2nS-knyAxc6KPuxBr65vRpW-duAXwpeXlwGJ03eU","y":"MwoGZ08hF5uv-_UEC9BKsYdJVSbJNHcFhR1BZWer5RQ","d":"z9VrSNNZXf9ywUx3v_8cLDhSw8-pvAT9qu_WZmqqfWM"}'; 6 | process.env.ATTESTATION_SIGNER_PRIVATE_KEY = 7 | "0x04d16281ff3bf268b29cdd684183f72542757d24ae9fdfb863e7c755e599163a"; 8 | process.env.TESTNET_ATTESTATION_SIGNER_PRIVATE_KEY = 9 | "0x04d16281ff3bf268b29cdd684183f72542757d24ae9fdfb863e7c755e599163a"; 10 | process.env.GITCOIN_VERIFIER_CHAIN_ID = "84531"; 11 | process.env.ALLO_SCORER_ID = "1"; 12 | process.env.SCORER_ENDPOINT = "http://127.0.0.1:8002"; 13 | process.env.SCORER_API_KEY = "abcd"; 14 | process.env.MORALIS_API_KEY = "abcd"; 15 | process.env.EAS_GITCOIN_STAMP_SCHEMA = "0x"; 16 | -------------------------------------------------------------------------------- /iam/src/issuers.ts: -------------------------------------------------------------------------------- 1 | import * as DIDKit from "@spruceid/didkit-wasm-node"; 2 | 3 | const key = process.env.IAM_JWK; 4 | const __issuer = DIDKit.keyToDID("key", key); 5 | const eip712Key = process.env.IAM_JWK_EIP712; 6 | const __eip712Issuer = DIDKit.keyToDID("ethr", eip712Key); 7 | 8 | const validIssuers = new Set([__issuer, __eip712Issuer]); 9 | 10 | export function getEd25519IssuerKey(): string { 11 | return key; 12 | } 13 | 14 | export function getEd25519Issuer(): string { 15 | return __issuer; 16 | } 17 | 18 | export function getEip712IssuerKey(): string { 19 | return eip712Key; 20 | } 21 | 22 | export function getEip712Issuer(): string { 23 | return __eip712Issuer; 24 | } 25 | 26 | export function getIssuerKey(signatureType: string): string { 27 | return signatureType === "EIP712" ? eip712Key : key; 28 | } 29 | 30 | export function hasValidIssuer(issuer: string): boolean { 31 | return validIssuers.has(issuer); 32 | } 33 | -------------------------------------------------------------------------------- /iam/src/main.ts: -------------------------------------------------------------------------------- 1 | import "dotenv/config"; 2 | 3 | // ---- Main App from index 4 | import { app } from "./index.js"; 5 | import Moralis from "moralis"; 6 | 7 | // default port to listen on 8 | const port = process.env.IAM_PORT || 80; 9 | 10 | const startServer = async (): Promise => { 11 | await Moralis.start({ 12 | apiKey: process.env.MORALIS_API_KEY, 13 | }); 14 | 15 | const server = app.listen(port, () => { 16 | // eslint-disable-next-line no-console 17 | console.log(`server started at http://localhost:${port}`); 18 | }); 19 | 20 | // This should be > the ELB idle timeout, which is 60 seconds 21 | server.keepAliveTimeout = 61 * 1000; 22 | }; 23 | 24 | startServer().catch((error) => { 25 | // eslint-disable-next-line no-console 26 | console.error(error); 27 | }); 28 | -------------------------------------------------------------------------------- /iam/src/scripts/buildProviderBitMapInfo.ts: -------------------------------------------------------------------------------- 1 | import dotenv from "dotenv"; 2 | import { writeFileSync } from "fs"; 3 | import { join } from "path"; 4 | import axios from "axios"; 5 | 6 | import { StampMetadata, mapBitMapInfo } from "../utils/easPassportSchema"; 7 | 8 | dotenv.config(); 9 | 10 | const stampMetadataEndpoint = process.env.PASSPORT_STAMP_METADATA_PATH || ""; 11 | 12 | const formatProviderBitMapInfo = async (): Promise => { 13 | const stampMetadata: { 14 | data: StampMetadata; 15 | } = await axios.get(stampMetadataEndpoint); 16 | 17 | const bitMapInfo = mapBitMapInfo(stampMetadata.data); 18 | 19 | const outPath = join(__dirname, "..", "static", "providerBitMapInfo.json"); 20 | console.log(`Saving platform info to JSON file at ${outPath}`); 21 | 22 | writeFileSync(outPath, JSON.stringify(bitMapInfo)); 23 | }; 24 | 25 | formatProviderBitMapInfo() 26 | .catch((err) => { 27 | console.error(err); 28 | }) 29 | .finally(() => { 30 | console.log("Done! BitMap info saved"); 31 | }); 32 | -------------------------------------------------------------------------------- /iam/src/types.d.ts: -------------------------------------------------------------------------------- 1 | import { ProviderContext, RequestPayload, VerifiedPayload } from "@gitcoin/passport-types"; 2 | 3 | // All Identity Providers should implement Provider 4 | export interface Provider { 5 | type: string; 6 | verify: (payload: RequestPayload, context?: ProviderContext) => Promise; 7 | } 8 | 9 | // Use unknown 10 | export type ProviderOptions = Record; 11 | -------------------------------------------------------------------------------- /iam/src/utils/scorerService.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import { Score } from "./easStampSchema"; 3 | import { handleAxiosError } from "@gitcoin/passport-platforms"; 4 | 5 | const scorerApiGetScore = `${process.env.SCORER_ENDPOINT}/registry/score/${process.env.ALLO_SCORER_ID}`; 6 | 7 | export class IAMError extends Error { 8 | constructor(public message: string) { 9 | super(message); 10 | this.name = this.constructor.name; 11 | } 12 | } 13 | 14 | type GetScoreResponse = { 15 | data: { 16 | status: string; 17 | evidence: { 18 | rawScore: string; 19 | }; 20 | }; 21 | }; 22 | 23 | // Use public endpoint and static api key to fetch score 24 | export async function fetchPassportScore(address: string): Promise { 25 | const response = await requestScore(address); 26 | 27 | const { data } = response; 28 | if (data.status !== "DONE") { 29 | throw new IAMError(`Score not ready yet. Status: ${data.status}`); 30 | } 31 | 32 | const score: Score = { 33 | score: Number(data.evidence.rawScore), 34 | scorer_id: Number(process.env.ALLO_SCORER_ID), 35 | }; 36 | 37 | return score; 38 | } 39 | 40 | async function requestScore(address: string): Promise { 41 | const apiKey = process.env.SCORER_API_KEY; 42 | 43 | try { 44 | return await axios.get(`${scorerApiGetScore}/${address}`, { 45 | headers: { 46 | "X-API-Key": apiKey, 47 | }, 48 | }); 49 | } catch (error) { 50 | handleAxiosError(error, "Passport score", IAMError, [apiKey]); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /iam/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.settings.json", 3 | "compilerOptions": { 4 | "module": "esnext", 5 | "esModuleInterop": true, 6 | "allowSyntheticDefaultImports": true, 7 | "allowJs": true, 8 | "target": "es6", 9 | "noImplicitAny": true, 10 | "moduleResolution": "node", 11 | "sourceMap": true, 12 | "outDir": "dist", 13 | "baseUrl": ".", 14 | "resolveJsonModule": true, 15 | "paths": { 16 | "*": ["../node_modules/*", "node_modules/*"] 17 | }, 18 | "skipLibCheck": true 19 | }, 20 | "include": ["src/**/*", "__tests__/**/*"] 21 | } 22 | -------------------------------------------------------------------------------- /identity/.eslintignore: -------------------------------------------------------------------------------- 1 | /*.js 2 | /*.ts 3 | /dist/* 4 | /coverage/* 5 | /node_modules/* 6 | /src/didkit-node/* 7 | /src/didkit-browser/* 8 | /__mocks__/**/* 9 | /__tests__/**/* 10 | -------------------------------------------------------------------------------- /identity/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | /dist 12 | /coverage 13 | dist-ssr 14 | *.local 15 | 16 | # Editor directories and files 17 | .vscode/* 18 | !.vscode/extensions.json 19 | .idea 20 | .DS_Store 21 | *.suo 22 | *.ntvs* 23 | *.njsproj 24 | *.sln 25 | *.sw? 26 | -------------------------------------------------------------------------------- /identity/.prettierignore: -------------------------------------------------------------------------------- 1 | /dist/* 2 | /coverage/* 3 | /node_modules/* 4 | /src/didkit-node/* 5 | /src/didkit-browser/* 6 | -------------------------------------------------------------------------------- /identity/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ...require("../.prettierrc.js"), 3 | }; 4 | -------------------------------------------------------------------------------- /identity/README.md: -------------------------------------------------------------------------------- 1 | # @gitcoin/passport-identity 2 | 3 | Shared identity management tools for the Gitcoin Passport repo. 4 | 5 | Instructions: 6 | 7 | - Ensure @gitcoin/passport-identity is included as a package dependency 8 | - Import like so: `import { issueHashedCredential, verifyCredential } from "@gitcoin/passport-identity"` 9 | -------------------------------------------------------------------------------- /identity/__mocks__/axios.js: -------------------------------------------------------------------------------- 1 | // IAM challenge response 2 | const MOCK_CHALLENGE_VALUE = "this is a challenge"; 3 | const MOCK_CHALLENGE_CREDENTIAL = { 4 | credentialSubject: { 5 | challenge: "this is a challenge", 6 | }, 7 | }; 8 | const MOCK_CHALLENGE_RESPONSE_BODY = { 9 | credential: MOCK_CHALLENGE_CREDENTIAL, 10 | }; 11 | 12 | // IAM verify response 13 | const MOCK_VERIFY_RESPONSE_BODY = { 14 | credential: { type: ["VerifiableCredential"] }, 15 | record: { 16 | type: "test", 17 | address: "0xmyAddress", 18 | }, 19 | }; 20 | 21 | const clearAxiosMocks = () => { 22 | post.mockClear(); 23 | }; 24 | 25 | const post = jest.fn(async (url, data) => { 26 | if (url.endsWith("/challenge")) { 27 | return { 28 | data: MOCK_CHALLENGE_RESPONSE_BODY, 29 | }; 30 | } 31 | 32 | if (url.endsWith("/verify")) { 33 | return { 34 | data: MOCK_VERIFY_RESPONSE_BODY, 35 | }; 36 | } 37 | 38 | throw Error("This endpoint is not set up!"); 39 | }); 40 | 41 | module.exports = { 42 | post, 43 | 44 | /* Mock values and helpers */ 45 | clearAxiosMocks, 46 | MOCK_CHALLENGE_VALUE, 47 | MOCK_CHALLENGE_CREDENTIAL, 48 | MOCK_CHALLENGE_RESPONSE_BODY, 49 | MOCK_VERIFY_RESPONSE_BODY, 50 | }; 51 | -------------------------------------------------------------------------------- /identity/__mocks__/didkit.js: -------------------------------------------------------------------------------- 1 | const keyToDID = jest.fn(() => Promise.resolve("did:key:PUBLIC_KEY")); 2 | 3 | const keyToVerificationMethod = jest.fn(() => Promise.resolve("did:key:PUBLIC_KEY#PUBLIC_KEY")); 4 | 5 | const issueCredential = jest.fn((credential) => 6 | Promise.resolve( 7 | JSON.stringify({ 8 | ...JSON.parse(credential), 9 | proof: {}, 10 | }) 11 | ) 12 | ); 13 | const verifyCredential = jest.fn(() => 14 | Promise.resolve( 15 | JSON.stringify({ 16 | checks: [], 17 | warnings: [], 18 | errors: [], 19 | }) 20 | ) 21 | ); 22 | 23 | const clearDidkitMocks = () => { 24 | keyToDID.mockClear(); 25 | keyToVerificationMethod.mockClear(); 26 | issueCredential.mockClear(); 27 | verifyCredential.mockClear(); 28 | }; 29 | 30 | // ---- Generate & Verify methods 31 | module.exports = { 32 | keyToDID, 33 | keyToVerificationMethod, 34 | issueCredential, 35 | verifyCredential, 36 | 37 | /* Mock helpers */ 38 | clearDidkitMocks, 39 | }; 40 | -------------------------------------------------------------------------------- /identity/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testEnvironment: "node", 3 | transform: { 4 | "^.+\\.tsx?$": "ts-jest", 5 | }, 6 | modulePathIgnorePatterns: ["/dist/"], 7 | }; 8 | -------------------------------------------------------------------------------- /identity/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@gitcoin/passport-identity", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "main": "dist/commonjs/index.js", 6 | "directories": { 7 | "src": "src", 8 | "dist": "dist" 9 | }, 10 | "files": [ 11 | "src", 12 | "dist" 13 | ], 14 | "publishConfig": { 15 | "access": "public" 16 | }, 17 | "dependencies": { 18 | "@ethersproject/base64": "^5.6.1", 19 | "@ethersproject/providers": "^5.6.2", 20 | "@gitcoin/passport-types": "^1.0.0", 21 | "axios": "^0.26.1" 22 | }, 23 | "devDependencies": { 24 | "jest": "^27.5.1", 25 | "ts-jest": "^27.1.4", 26 | "typescript": "^5.3.3" 27 | }, 28 | "scripts": { 29 | "clean": "rimraf dist node_modules", 30 | "build": "tsc", 31 | "test": "jest --verbose", 32 | "lint": "tsc --noEmit && eslint --ext .ts,.js,.tsx .", 33 | "prettier": "prettier --write ." 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /identity/src/index.ts: -------------------------------------------------------------------------------- 1 | // export credential tooling 2 | export * from "./credentials"; 3 | export * from "./signingDocuments"; 4 | -------------------------------------------------------------------------------- /identity/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.settings.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "esModuleInterop": true, 6 | "declaration": true, 7 | "allowSyntheticDefaultImports": true, 8 | "target": "ES2022", 9 | "noImplicitAny": true, 10 | "moduleResolution": "node", 11 | "sourceMap": true, 12 | "outDir": "dist/commonjs", 13 | "allowJs": true, 14 | "baseUrl": "src", 15 | "skipLibCheck": true 16 | }, 17 | "include": ["src/**/*"] 18 | } 19 | -------------------------------------------------------------------------------- /infra/.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | /node_modules/ 3 | -------------------------------------------------------------------------------- /infra/README.md: -------------------------------------------------------------------------------- 1 | ## New Stack 2 | ```sh 3 | pulumi stack init gitcoin/dpopp/stackName 4 | ``` 5 | 6 | ## AWS Configuration 7 | ```sh 8 | # set aws profile credentials 9 | aws configure --profile user1 10 | ``` 11 | *Note* you will also need to select this profile in your env: 12 | ```sh 13 | export AWS_PROFILE=user1 14 | ``` 15 | 16 | ## Configure environment 17 | 18 | Before we can run `pulumi up`, there are a few resources that need to be built/pushed to the aws environment, such as the secret manager, Route53 Hosted Zone, and iam-server docker image. Once these are present on aws, we must reference them in our local environment in order for pulumi to be aware of them: 19 | 20 | ```sh 21 | # set route53 zone 22 | export ROUTE_53_ZONE=... 23 | # set environment-specific domain 24 | export DOMAIN=... 25 | # secrets manager resource ARN 26 | export IAM_SERVER_SSM_ARN=... 27 | # iam-server docker image in ECR 28 | export DOCKER_GTC_PASSPORT_IAM_IMAGE=... 29 | ``` 30 | 31 | ## Pulumi deploy 32 | ```sh 33 | pulumi up 34 | ``` 35 | -------------------------------------------------------------------------------- /infra/aws/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | -------------------------------------------------------------------------------- /infra/aws/Pulumi.review.yaml: -------------------------------------------------------------------------------- 1 | config: 2 | aws:region: us-west-2 3 | -------------------------------------------------------------------------------- /infra/aws/Pulumi.staging.yaml: -------------------------------------------------------------------------------- 1 | config: 2 | aws:region: us-west-2 3 | -------------------------------------------------------------------------------- /infra/aws/Pulumi.yaml: -------------------------------------------------------------------------------- 1 | name: passport 2 | runtime: 3 | name: nodejs 4 | options: 5 | typescript: true 6 | description: A minimal AWS JavaScript Pulumi program 7 | -------------------------------------------------------------------------------- /infra/aws/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "outDir": "bin", 5 | "target": "es2016", 6 | "module": "commonjs", 7 | "moduleResolution": "node", 8 | "sourceMap": true, 9 | "experimentalDecorators": true, 10 | "pretty": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "noImplicitReturns": true, 13 | "forceConsistentCasingInFileNames": true 14 | }, 15 | "files": [ 16 | "index.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /infra/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "infra", 3 | "devDependencies": { 4 | "@types/node": "^14" 5 | }, 6 | "dependencies": { 7 | "@pulumi/aws": "^5.0.0", 8 | "@pulumi/awsx": "^0.40.0", 9 | "@pulumi/cloudflare": "^5.26.0", 10 | "@pulumi/github": "^6.1.0", 11 | "@pulumi/pulumi": "^3.0.0", 12 | "@pulumi/std": "^1.6.2" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /js-ceramic/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ceramicnetwork/js-ceramic:3.2.0 2 | 3 | COPY ceramic/daemon.config.json /ceramic/daemon.config.json 4 | 5 | RUN mkdir /ceramic/statestore 6 | 7 | CMD ["--config", "/ceramic/daemon.config.json"] 8 | -------------------------------------------------------------------------------- /js-ceramic/README.md: -------------------------------------------------------------------------------- 1 | # Instructions for building & running docker image 2 | 3 | - build docker image: `docker build . --tag gitcoinpassport/js-ceramic:` 4 | - push docker image: `docker push gitcoinpassport/js-ceramic:` 5 | - running `ceramicnetwork/js-ceramic` directly on local with: `docker run --rm -v $(pwd)/ceramic:/ceramic ceramicnetwork/js-ceramic:3.2.0 --config /ceramic/daemon.config.json` 6 | -------------------------------------------------------------------------------- /js-ceramic/ceramic/daemon.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "anchor": { 3 | "auth-method": "did" 4 | }, 5 | "http-api": { 6 | "cors-allowed-origins": [".*"], 7 | "admin-dids": ["did:key:z6MkgUzNYV8J1yw43wj9K2CbhTZoN25uZ6TJ3Gi4cYVpZyDb"] 8 | }, 9 | "ipfs": { 10 | "mode": "bundled", 11 | "disable-peer-data-sync": false 12 | }, 13 | "logger": { 14 | "log-level": 2, 15 | "log-to-files": false 16 | }, 17 | "metrics": { 18 | "metrics-exporter-enabled": false 19 | }, 20 | "network": { 21 | "name": "testnet-clay" 22 | }, 23 | "node": { 24 | "private-seed-url": "inplace:ed25519#b7d1fc8db6162b7fd9ab19a5486d9c5f8f0134ac87932266033732d5fb5f1c26" 25 | }, 26 | "state-store": { 27 | "mode": "fs", 28 | "local-directory": "/ceramic/statestore/" 29 | }, 30 | "indexing": { 31 | "db": "sqlite:///ceramic/indexing.sqlite", 32 | "allow-queries-before-historical-sync": true, 33 | "disable-composedb": false, 34 | "enable-historical-sync": false 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": [ 3 | "app", 4 | "database-client", 5 | "iam", 6 | "identity", 7 | "schemas", 8 | "types", 9 | "platforms" 10 | ], 11 | "npmClient": "yarn", 12 | "version": "independent", 13 | "useWorkspaces": true, 14 | "stream": true, 15 | "changelogPreset": "angular" 16 | } 17 | -------------------------------------------------------------------------------- /platforms/.eslintignore: -------------------------------------------------------------------------------- 1 | /*.js 2 | /*.ts 3 | /dist/* 4 | /coverage/* 5 | /node_modules/* 6 | /src/didkit-node/* 7 | /src/didkit-browser/* 8 | /__mocks__/**/* 9 | /__tests__/**/* 10 | -------------------------------------------------------------------------------- /platforms/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | /dist 12 | /coverage 13 | dist-ssr 14 | *.local 15 | 16 | # Editor directories and files 17 | .vscode/* 18 | !.vscode/extensions.json 19 | .idea 20 | .DS_Store 21 | *.suo 22 | *.ntvs* 23 | *.njsproj 24 | *.sln 25 | *.sw? 26 | -------------------------------------------------------------------------------- /platforms/.prettierignore: -------------------------------------------------------------------------------- 1 | /dist/* 2 | /coverage/* 3 | /node_modules/* 4 | /src/didkit-node/* 5 | /src/didkit-browser/* 6 | -------------------------------------------------------------------------------- /platforms/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ...require("../.prettierrc.js"), 3 | }; 4 | -------------------------------------------------------------------------------- /platforms/jest.config.cjs: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ 2 | 3 | module.exports = { 4 | // [...] 5 | preset: "ts-jest", 6 | extensionsToTreatAsEsm: [".ts"], 7 | globals: { 8 | "ts-jest": { 9 | useESM: true, 10 | }, 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /platforms/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testEnvironment: "node", 3 | transform: { 4 | "^.+\\.tsx?$": "ts-jest", 5 | }, 6 | modulePathIgnorePatterns: ["/dist/"], 7 | setupFiles: ["dotenv/config", "../platforms/testSetup.js"], 8 | }; 9 | -------------------------------------------------------------------------------- /platforms/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@gitcoin/passport-platforms", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "main": "dist/commonjs/index.js", 6 | "exports": { 7 | ".": "./dist/commonjs/index.js", 8 | "./procedure-router": "./dist/commonjs/procedure-router.js" 9 | }, 10 | "typesVersions": { 11 | "*": { 12 | "*": [ 13 | "./dist/commonjs/index.d.ts" 14 | ], 15 | "procedure-router": [ 16 | "./dist/commonjs/procedure-router.d.ts" 17 | ] 18 | } 19 | }, 20 | "directories": { 21 | "src": "src", 22 | "dist": "dist" 23 | }, 24 | "files": [ 25 | "src", 26 | "dist" 27 | ], 28 | "publishConfig": { 29 | "access": "public" 30 | }, 31 | "dependencies": { 32 | "@ethersproject/base64": "^5.6.1", 33 | "@ethersproject/providers": "^5.6.2", 34 | "@gitcoin/passport-types": "^1.0.0", 35 | "@spruceid/didkit-wasm": "^0.3.0-alpha0", 36 | "axios": "^0.26.1", 37 | "bignumber.js": "4.0.4", 38 | "multiformats": "^13.0.0", 39 | "redis": "^4.6.10", 40 | "typescript": "^5.3.3" 41 | }, 42 | "devDependencies": { 43 | "jest": "^27.5.1", 44 | "jest-mock-extended": "^3.0.4", 45 | "ts-jest": "^27.1.4", 46 | "ts-node": "^10.8.0", 47 | "eslint-plugin-prettier": "^5.1.3" 48 | }, 49 | "scripts": { 50 | "clean": "rimraf dist node_modules", 51 | "build": "tsc", 52 | "test": "jest --verbose", 53 | "lint": "tsc --noEmit && eslint --ext .ts,.js,.tsx .", 54 | "prettier": "prettier --write ." 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /platforms/src/Brightid/Providers-config.ts: -------------------------------------------------------------------------------- 1 | import { PlatformSpec, PlatformGroupSpec, Provider } from "../types"; 2 | import { BrightIdProvider } from "./Providers/brightid"; 3 | 4 | export const PlatformDetails: PlatformSpec = { 5 | icon: "./assets/brightidStampIcon.svg", 6 | platform: "Brightid", 7 | name: "BrightID", 8 | description: "Connect to BrightID to verify your identity on Web3 without revealing any personal information.", 9 | connectMessage: "Connect Account", 10 | isEVM: true, 11 | website: "https://brightid.org/", 12 | }; 13 | 14 | export const ProviderConfig: PlatformGroupSpec[] = [ 15 | { 16 | platformGroup: "Account Name", 17 | providers: [{ title: "Encrypted", name: "Brightid" }], 18 | }, 19 | ]; 20 | 21 | export const providers: Provider[] = [new BrightIdProvider()]; 22 | -------------------------------------------------------------------------------- /platforms/src/Brightid/Shared.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HowittColet/passport/bd7c79421d508ee94a2a1142dec0619b35844b3b/platforms/src/Brightid/Shared.ts -------------------------------------------------------------------------------- /platforms/src/Brightid/index.ts: -------------------------------------------------------------------------------- 1 | export { BrightidPlatform } from "./App-Bindings"; 2 | export { PlatformDetails, ProviderConfig, providers } from "./Providers-config"; 3 | export { BrightIdProvider } from "./Providers/brightid"; 4 | -------------------------------------------------------------------------------- /platforms/src/Civic/Providers/types.ts: -------------------------------------------------------------------------------- 1 | // Mapping civic passes to [EIP3525](https://eips.ethereum.org/EIPS/eip-3525) slotIDs 2 | import { BigNumber } from "@ethersproject/bignumber"; 3 | 4 | export enum CivicPassType { 5 | CAPTCHA = 4, 6 | IDV = 6, 7 | UNIQUENESS = 10, 8 | LIVENESS = 11, 9 | } 10 | 11 | export const supportedCivicPassTypes = Object.values(CivicPassType).filter(Number) as CivicPassType[]; 12 | 13 | export const supportedChains = [ 14 | // Mainnets 15 | "ETHEREUM_MAINNET", 16 | "POLYGON_POS_MAINNET", 17 | "POLYGON_ZKEVM_MAINNET", 18 | "ARBITRUM_MAINNET", 19 | "XDC_MAINNET", 20 | // Testnets 21 | "GOERLI", 22 | "SEPOLIA", 23 | "MUMBAI", 24 | "POLYGON_ZKEVM_TESTNET", 25 | "ARBITRUM_GOERLI", 26 | "XDC_APOTHEM", 27 | ] as const; 28 | 29 | export type SupportedChain = typeof supportedChains[number]; 30 | 31 | type CivicPassState = "ACTIVE" | "FROZEN" | "REVOKED"; 32 | 33 | export type CivicPassLookupPass = { 34 | type: { 35 | slotId: number; 36 | address: string; 37 | name?: string; 38 | }; 39 | chain: string; 40 | identifier: string; 41 | expiry?: number; 42 | state: CivicPassState; 43 | }; 44 | export type PassesForAddress = { passes: Record }; 45 | export type CivicPassLookupResponse = Record; 46 | 47 | type PassDetails = { 48 | expiry?: BigNumber; 49 | identifier: string; 50 | state: CivicPassState; 51 | }; 52 | export type Pass = PassDetails & { 53 | type: CivicPassType; 54 | chain: SupportedChain; 55 | }; 56 | -------------------------------------------------------------------------------- /platforms/src/Civic/Shared.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HowittColet/passport/bd7c79421d508ee94a2a1142dec0619b35844b3b/platforms/src/Civic/Shared.ts -------------------------------------------------------------------------------- /platforms/src/Civic/index.ts: -------------------------------------------------------------------------------- 1 | export { CivicPlatform } from "./App-Bindings"; 2 | export { PlatformDetails, ProviderConfig, providers } from "./Providers-config"; 3 | export { CivicPassProvider } from "./Providers/civic"; 4 | -------------------------------------------------------------------------------- /platforms/src/ClearText/index.ts: -------------------------------------------------------------------------------- 1 | export { ClearTextGithubOrgProvider } from "./Providers/clearTextGithubOrg"; 2 | export { ClearTextTwitterProvider } from "./Providers/clearTextTwitter"; 3 | -------------------------------------------------------------------------------- /platforms/src/Coinbase/Providers-config.ts: -------------------------------------------------------------------------------- 1 | import { PlatformSpec, PlatformGroupSpec, Provider } from "../types"; 2 | import { CoinbaseProvider } from "./Providers/coinbase"; 3 | 4 | export const PlatformDetails: PlatformSpec = { 5 | icon: "./assets/coinbaseStampIcon.svg", 6 | platform: "Coinbase", 7 | name: "Coinbase", 8 | description: "Confirm Your Coinbase Verified ID", 9 | connectMessage: "Connect Account", 10 | website: "https://www.coinbase.com/onchain-verify", 11 | }; 12 | 13 | export const ProviderConfig: PlatformGroupSpec[] = [ 14 | { 15 | platformGroup: "Account & Onchain Identity", 16 | providers: [ 17 | { 18 | title: "Privacy-First Verification", 19 | description: 20 | "Your privacy is paramount. We only retain a unique hash to acknowledge your account's verification.", 21 | name: "CoinbaseDualVerification", 22 | }, 23 | ], 24 | }, 25 | ]; 26 | 27 | export const providers: Provider[] = [new CoinbaseProvider()]; 28 | -------------------------------------------------------------------------------- /platforms/src/Coinbase/Shared.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HowittColet/passport/bd7c79421d508ee94a2a1142dec0619b35844b3b/platforms/src/Coinbase/Shared.ts -------------------------------------------------------------------------------- /platforms/src/Coinbase/index.ts: -------------------------------------------------------------------------------- 1 | export { CoinbasePlatform } from "./App-Bindings"; 2 | export { ProviderConfig, PlatformDetails, providers } from "./Providers-config"; 3 | export { CoinbaseProvider } from "./Providers/coinbase"; 4 | -------------------------------------------------------------------------------- /platforms/src/Discord/App-Bindings.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import { AccessTokenResult, AppContext, ProviderPayload, PlatformOptions } from "../types"; 3 | import { Platform } from "../utils/platform"; 4 | 5 | export class DiscordPlatform extends Platform { 6 | path = "discord"; 7 | platformId = "Discord"; 8 | 9 | clientId: string = null; 10 | redirectUri: string = null; 11 | 12 | constructor(options: PlatformOptions = {}) { 13 | super(); 14 | this.clientId = options.clientId as string; 15 | this.redirectUri = options.redirectUri as string; 16 | this.banner = { 17 | cta: { 18 | label: "Learn more", 19 | url: "https://support.passport.xyz/passport-knowledge-base/stamps/how-do-i-add-passport-stamps/connecting-a-discord-account-to-passport", 20 | }, 21 | }; 22 | } 23 | 24 | async getOAuthUrl(state: string): Promise { 25 | const authUrl = `https://discord.com/api/oauth2/authorize?response_type=code&scope=identify&client_id=${process.env.NEXT_PUBLIC_PASSPORT_DISCORD_CLIENT_ID}&state=${state}&redirect_uri=${process.env.NEXT_PUBLIC_PASSPORT_DISCORD_CALLBACK}`; 26 | return authUrl; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /platforms/src/Discord/Providers-config.ts: -------------------------------------------------------------------------------- 1 | import { PlatformSpec, PlatformGroupSpec, Provider } from "../types"; 2 | import { DiscordProvider } from "./Providers/discord"; 3 | 4 | export const PlatformDetails: PlatformSpec = { 5 | icon: "./assets/discordStampIcon.svg", 6 | platform: "Discord", 7 | name: "Discord", 8 | description: "Connect your Discord account to Gitcoin Passport to identity and reputation in Web3 communities.", 9 | connectMessage: "Connect Account", 10 | website: "https://discord.com/", 11 | }; 12 | 13 | export const ProviderConfig: PlatformGroupSpec[] = [ 14 | { 15 | platformGroup: "Account Name", 16 | providers: [{ title: "Encrypted", name: "Discord" }], 17 | }, 18 | ]; 19 | 20 | export const providers: Provider[] = [new DiscordProvider()]; 21 | -------------------------------------------------------------------------------- /platforms/src/Discord/index.ts: -------------------------------------------------------------------------------- 1 | export { DiscordPlatform } from "./App-Bindings"; 2 | export { ProviderConfig, PlatformDetails, providers } from "./Providers-config"; 3 | export { DiscordProvider } from "./Providers/discord"; 4 | -------------------------------------------------------------------------------- /platforms/src/ETH/App-Bindings.ts: -------------------------------------------------------------------------------- 1 | import { AppContext, ProviderPayload } from "../types"; 2 | import { Platform } from "../utils/platform"; 3 | export class ETHPlatform extends Platform { 4 | platformId = "ETH"; 5 | path = "ETH"; 6 | clientId: string = null; 7 | redirectUri: string = null; 8 | isEVM = true; 9 | 10 | banner = { 11 | heading: ` 12 | Click verify to process your Ethereum L1 transactions. Gitcoin uses a constantly 13 | evolving model to review your transaction history and compare against known Sybil 14 | behavior. The number of points you'll receive is based on many factors related to 15 | the overall activity of the address. 16 | `, 17 | cta: { 18 | label: "Learn more", 19 | url: "https://support.passport.xyz/passport-knowledge-base/stamps/how-do-i-add-passport-stamps/verifying-ethereum-transactions-to-passport", 20 | }, 21 | }; 22 | 23 | async getProviderPayload(appContext: AppContext): Promise { 24 | const result = await Promise.resolve({}); 25 | return result; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /platforms/src/ETH/Shared.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HowittColet/passport/bd7c79421d508ee94a2a1142dec0619b35844b3b/platforms/src/ETH/Shared.ts -------------------------------------------------------------------------------- /platforms/src/ETH/index.ts: -------------------------------------------------------------------------------- 1 | export { ETHPlatform } from "./App-Bindings"; 2 | export { PlatformDetails, ProviderConfig, providers } from "./Providers-config"; 3 | export { ETHAdvocateProvider, ETHMaxiProvider } from "./Providers/accountAnalysis"; 4 | -------------------------------------------------------------------------------- /platforms/src/Ens/App-Bindings.ts: -------------------------------------------------------------------------------- 1 | import { AppContext, ProviderPayload } from "../types"; 2 | import { Platform } from "../utils/platform"; 3 | 4 | export class EnsPlatform extends Platform { 5 | platformId = "Ens"; 6 | path = "Ens"; 7 | clientId: string = null; 8 | redirectUri: string = null; 9 | isEVM = true; 10 | 11 | banner = { 12 | heading: 13 | "The ENS stamp only recognizes ENS domains if they are set to your account as primary ENS (or reverse record).", 14 | cta: { 15 | label: "Learn more", 16 | url: "https://support.passport.xyz/passport-knowledge-base/stamps/how-do-i-add-passport-stamps/connecting-an-ens-account-to-passport", 17 | }, 18 | }; 19 | 20 | async getProviderPayload(appContext: AppContext): Promise { 21 | const result = await Promise.resolve({}); 22 | return result; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /platforms/src/Ens/Providers-config.ts: -------------------------------------------------------------------------------- 1 | import { PlatformSpec, PlatformGroupSpec, Provider } from "../types"; 2 | import { EnsProvider } from "./Providers"; 3 | 4 | export const PlatformDetails: PlatformSpec = { 5 | icon: "./assets/ensStampIcon.svg", 6 | platform: "Ens", 7 | name: "ENS", 8 | description: "Connect to ENS to verify your ownership of your web3 domain name.", 9 | connectMessage: "Connect Account", 10 | isEVM: true, 11 | website: "https://ens.domains/", 12 | }; 13 | 14 | export const ProviderConfig: PlatformGroupSpec[] = [ 15 | { 16 | platformGroup: "Account Name", 17 | providers: [{ title: "Encrypted", name: "Ens" }], 18 | }, 19 | ]; 20 | 21 | export const providers: Provider[] = [new EnsProvider()]; 22 | -------------------------------------------------------------------------------- /platforms/src/Ens/Providers/index.ts: -------------------------------------------------------------------------------- 1 | export { EnsProvider } from "./EnsProvider"; 2 | -------------------------------------------------------------------------------- /platforms/src/Ens/Shared.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HowittColet/passport/bd7c79421d508ee94a2a1142dec0619b35844b3b/platforms/src/Ens/Shared.ts -------------------------------------------------------------------------------- /platforms/src/Ens/index.ts: -------------------------------------------------------------------------------- 1 | export { EnsPlatform } from "./App-Bindings"; 2 | export { PlatformDetails, ProviderConfig, providers } from "./Providers-config"; 3 | export { EnsProvider } from "./Providers/EnsProvider"; 4 | -------------------------------------------------------------------------------- /platforms/src/Gitcoin/Providers/__tests__/gitcoinGrantsContributorStatistics.test.ts: -------------------------------------------------------------------------------- 1 | // ----- Libs 2 | import { GitcoinContributorStatisticsProvider } from "../gitcoinGrantsContributorStatistics"; 3 | /* eslint-disable no-use-before-define */ 4 | describe("GitcoinContributorStatisticsProvider class", function () { 5 | it("should be properly initialized", function () { 6 | const threshold = 193; 7 | const receivingAttribute = "aaa"; 8 | const recordAttribute = "bbb"; 9 | const gitcoin = new GitcoinContributorStatisticsProvider({ 10 | threshold, 11 | receivingAttribute, 12 | recordAttribute, 13 | }); 14 | 15 | expect(gitcoin.type).toEqual(`GitcoinContributorStatistics#${recordAttribute}#${threshold}`); 16 | expect(gitcoin.urlPath).toEqual("/contributor_statistics"); 17 | expect(gitcoin._options).toEqual({ threshold, receivingAttribute, recordAttribute }); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /platforms/src/Gitcoin/Providers/gitcoinGrantsContributorStatistics.ts: -------------------------------------------------------------------------------- 1 | // ----- Types 2 | import { ProviderOptions } from "../../types"; 3 | import { GitcoinGrantStatisticsProvider } from "./gitcoinGrantsStatistics"; 4 | 5 | // Export a Gitcoin Provider 6 | export class GitcoinContributorStatisticsProvider extends GitcoinGrantStatisticsProvider { 7 | // construct the provider instance with supplied options 8 | constructor(options: ProviderOptions = {}) { 9 | super("GitcoinContributorStatistics", options); 10 | this.urlPath = "/contributor_statistics"; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /platforms/src/Gitcoin/Providers/index.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export { GitcoinContributorStatisticsProvider } from "./gitcoinGrantsContributorStatistics"; 3 | -------------------------------------------------------------------------------- /platforms/src/Gitcoin/index.ts: -------------------------------------------------------------------------------- 1 | export { GitcoinPlatform } from "./App-Bindings"; 2 | export { ProviderConfig, PlatformDetails, providers } from "./Providers-config"; 3 | export { GitcoinContributorStatisticsProvider } from "./Providers"; 4 | -------------------------------------------------------------------------------- /platforms/src/Github/App-Bindings.ts: -------------------------------------------------------------------------------- 1 | import { PlatformOptions } from "../types"; 2 | import { Platform } from "../utils/platform"; 3 | export class GithubPlatform extends Platform { 4 | platformId = "Github"; 5 | path = "github"; 6 | clientId: string = null; 7 | redirectUri: string = null; 8 | 9 | constructor(options: PlatformOptions = {}) { 10 | super(); 11 | this.clientId = options.clientId as string; 12 | this.redirectUri = options.redirectUri as string; 13 | this.banner = { 14 | heading: "Verifying Contribution Activity", 15 | content: 16 | "For the Contribution Activity credentials, make sure your contribution data is public. Go to Settings > Public Profile > Contributions & Activity and uncheck 'Make profile private and hide activity'. Verify your contribution history with your Gitcoin Passport!", 17 | cta: { 18 | label: "Learn more", 19 | url: "https://support.passport.xyz/passport-knowledge-base/stamps/how-do-i-add-passport-stamps/connecting-a-github-account-to-passport", 20 | }, 21 | }; 22 | } 23 | 24 | async getOAuthUrl(state: string): Promise { 25 | const githubUrl = await Promise.resolve( 26 | `https://github.com/login/oauth/authorize?client_id=${this.clientId}&redirect_uri=${this.redirectUri}&state=${state}` 27 | ); 28 | return githubUrl; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /platforms/src/Github/Providers-config.ts: -------------------------------------------------------------------------------- 1 | import { PlatformSpec, PlatformGroupSpec, Provider } from "../types"; 2 | import { GithubContributionActivityProvider } from "./Providers/githubContributionActivity"; 3 | 4 | export const PlatformDetails: PlatformSpec = { 5 | icon: "./assets/githubWhiteStampIcon.svg", 6 | platform: "Github", 7 | name: "Github", 8 | description: "Connect to GitHub to verify your code contributions.", 9 | connectMessage: "Connect Account", 10 | website: "https://github.com", 11 | }; 12 | 13 | let providers: Provider[] = []; 14 | let ProviderConfig: PlatformGroupSpec[] = []; 15 | 16 | ProviderConfig = [ 17 | { 18 | platformGroup: "Contribution Activity", 19 | providers: [ 20 | { 21 | title: "Contributions on at least 30 distinct days", 22 | name: "githubContributionActivityGte#30", 23 | }, 24 | { 25 | title: "Contributions on at least 60 distinct days", 26 | name: "githubContributionActivityGte#60", 27 | }, 28 | { 29 | title: "Contributions on at least 120 distinct days", 30 | name: "githubContributionActivityGte#120", 31 | }, 32 | ], 33 | }, 34 | ]; 35 | 36 | providers = [ 37 | new GithubContributionActivityProvider({ 38 | threshold: "30", 39 | }), 40 | new GithubContributionActivityProvider({ 41 | threshold: "60", 42 | }), 43 | new GithubContributionActivityProvider({ 44 | threshold: "120", 45 | }), 46 | ]; 47 | 48 | export { providers, ProviderConfig }; 49 | -------------------------------------------------------------------------------- /platforms/src/Github/index.ts: -------------------------------------------------------------------------------- 1 | export { GithubPlatform } from "./App-Bindings"; 2 | export { ProviderConfig, PlatformDetails, providers } from "./Providers-config"; 3 | -------------------------------------------------------------------------------- /platforms/src/GnosisSafe/App-Bindings.ts: -------------------------------------------------------------------------------- 1 | import { AppContext, ProviderPayload } from "../types"; 2 | import { Platform } from "../utils/platform"; 3 | 4 | export class GnosisSafePlatform extends Platform { 5 | platformId = "GnosisSafe"; 6 | path = "GnosisSafe"; 7 | isEVM = true; 8 | 9 | banner = { 10 | heading: 11 | "Currently, we only recognize Gnosis Safes on the Ethereum main network. So you can't get that stamp through your Gnosis Safes on other networks.", 12 | cta: { 13 | label: "Learn more", 14 | url: "https://support.passport.xyz/passport-knowledge-base/stamps/how-do-i-add-passport-stamps/gnosis-safe-stamp", 15 | }, 16 | }; 17 | 18 | async getProviderPayload(appContext: AppContext): Promise { 19 | const result = await Promise.resolve({}); 20 | return result; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /platforms/src/GnosisSafe/Providers-config.ts: -------------------------------------------------------------------------------- 1 | import { PlatformSpec, PlatformGroupSpec, Provider } from "../types"; 2 | import { GnosisSafeProvider } from "./Providers"; 3 | 4 | export const PlatformDetails: PlatformSpec = { 5 | icon: "./assets/gnosisSafeStampIcon.svg", 6 | platform: "GnosisSafe", 7 | name: "Gnosis Safe", 8 | description: "Gnosis Safe Signer/Owner Verification", 9 | connectMessage: "Verify Account", 10 | isEVM: true, 11 | }; 12 | 13 | export const ProviderConfig: PlatformGroupSpec[] = [ 14 | { 15 | platformGroup: "Account Name", 16 | providers: [{ title: "Encrypted", name: "GnosisSafe" }], 17 | }, 18 | ]; 19 | 20 | export const providers: Provider[] = [new GnosisSafeProvider()]; 21 | -------------------------------------------------------------------------------- /platforms/src/GnosisSafe/Providers/index.ts: -------------------------------------------------------------------------------- 1 | export { GnosisSafeProvider } from "./gnosisSafe"; 2 | -------------------------------------------------------------------------------- /platforms/src/GnosisSafe/index.ts: -------------------------------------------------------------------------------- 1 | export { GnosisSafePlatform } from "./App-Bindings"; 2 | export { GnosisSafeProvider } from "./Providers"; 3 | export { PlatformDetails, ProviderConfig, providers } from "./Providers-config"; 4 | -------------------------------------------------------------------------------- /platforms/src/Google/App-Bindings.ts: -------------------------------------------------------------------------------- 1 | // For details on the google oauth2 flow, please check the following ressources: 2 | // - https://developers.google.com/identity/protocols/oauth2 3 | // - https://developers.google.com/oauthplayground/ 4 | 5 | import { PlatformOptions } from "../types"; 6 | import { Platform } from "../utils/platform"; 7 | 8 | export class GooglePlatform extends Platform { 9 | platformId = "Google"; 10 | path = "Google"; 11 | clientId: string = null; 12 | redirectUri: string = null; 13 | 14 | constructor(options: PlatformOptions = {}) { 15 | super(); 16 | this.clientId = options.clientId as string; 17 | this.redirectUri = options.redirectUri as string; 18 | this.banner = { 19 | cta: { 20 | label: "Learn more", 21 | url: "https://support.passport.xyz/passport-knowledge-base/stamps/how-do-i-add-passport-stamps/connecting-a-google-account-to-passport", 22 | }, 23 | }; 24 | } 25 | 26 | getOAuthUrl(state: string): Promise { 27 | return new Promise((resolve) => { 28 | resolve( 29 | `https://accounts.google.com/o/oauth2/v2/auth?redirect_uri=${this.redirectUri}&prompt=consent&response_type=code&client_id=${this.clientId}&scope=email+profile&access_type=offline&state=${state}` 30 | ); 31 | }); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /platforms/src/Google/Providers-config.ts: -------------------------------------------------------------------------------- 1 | import { PlatformSpec, PlatformGroupSpec, Provider } from "../types"; 2 | import { GoogleProvider } from "./Providers/google"; 3 | 4 | export const PlatformDetails: PlatformSpec = { 5 | icon: "./assets/googleStampIcon.svg", 6 | platform: "Google", 7 | name: "Google", 8 | description: "Connect to Google to verify your email address.", 9 | connectMessage: "Connect Account", 10 | website: "https://www.google.com/", 11 | }; 12 | 13 | export const ProviderConfig: PlatformGroupSpec[] = [ 14 | { platformGroup: "Account Name", providers: [{ title: "Google", name: "Google" }] }, 15 | ]; 16 | 17 | export const providers: Provider[] = [new GoogleProvider()]; 18 | -------------------------------------------------------------------------------- /platforms/src/Google/index.js: -------------------------------------------------------------------------------- 1 | export { GooglePlatform } from "./App-Bindings"; 2 | export { ProviderConfig, PlatformDetails, providers } from "./Providers-config"; 3 | export { GoogleProvider } from "./Providers/google"; 4 | -------------------------------------------------------------------------------- /platforms/src/GtcStaking/App-Bindings.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import React from "react"; 3 | import { AppContext, PlatformOptions, ProviderPayload } from "../types"; 4 | import { Platform } from "../utils/platform"; 5 | 6 | export class GTCStakingPlatform extends Platform { 7 | platformId = "GtcStaking"; 8 | path = "GtcStaking"; 9 | isEVM = true; 10 | clientId: string = null; 11 | 12 | constructor(options: PlatformOptions = {}) { 13 | super(); 14 | this.state = options.state as string; 15 | this.redirectUri = options.redirectUri as string; 16 | } 17 | 18 | async getProviderPayload(appContext: AppContext): Promise { 19 | const result = await Promise.resolve({}); 20 | return result; 21 | } 22 | 23 | getOAuthUrl(state: string): Promise { 24 | throw new Error("Method not implemented."); 25 | } 26 | 27 | 28 | banner = { 29 | content: ( 30 |
31 | If you haven't staked yet, you can do so now. 32 | 43 | Learn more 44 | 45 |
46 | ), 47 | cta: { 48 | label: "Identity Staking", 49 | url: "https://www.staking.passport.gitcoin.co/", 50 | }, 51 | }; 52 | 53 | } 54 | -------------------------------------------------------------------------------- /platforms/src/GtcStaking/Providers/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | BeginnerCommunityStakerProvider, 3 | ExperiencedCommunityStakerProvider, 4 | TrustedCitizenProvider, 5 | } from "./communityStaking"; 6 | export { SelfStakingBronzeProvider, SelfStakingGoldProvider, SelfStakingSilverProvider } from "./selfStaking"; 7 | -------------------------------------------------------------------------------- /platforms/src/GtcStaking/__tests__/gtcStaking.test.ts: -------------------------------------------------------------------------------- 1 | import BigNumber from "bignumber.js"; 2 | import { GtcStakingProvider } from "../Providers/GtcStaking"; 3 | 4 | describe("GtcStakingProvider", () => { 5 | beforeAll(() => { 6 | process.env.GTC_STAKING_ROUNDS = 7 | // eslint-disable-next-line prettier/prettier, quotes 8 | '[{"id": 4, "start": 1693526400, "duration": 7592340}, {"id": 5, "start": 1701118741, "duration": 8157658}]'; 9 | }); 10 | afterEach(() => { 11 | jest.restoreAllMocks(); 12 | }); 13 | it("should get round 4 based on timestamp", () => { 14 | jest.spyOn(Date, "now").mockImplementation(() => new Date("2023-11-15T00:00:00Z").getTime()); 15 | const provider = new GtcStakingProvider({ type: "SelfStakingBronze", thresholdAmount: new BigNumber(5) }); 16 | 17 | const round = provider.getCurrentRound(); 18 | expect(round).toEqual(4); 19 | }); 20 | it("should get round 5 based on timestamp", () => { 21 | jest.spyOn(Date, "now").mockImplementation(() => new Date("2023-11-28T00:00:00Z").getTime()); 22 | const provider = new GtcStakingProvider({ type: "SelfStakingBronze", thresholdAmount: new BigNumber(5) }); 23 | 24 | const round = provider.getCurrentRound(); 25 | expect(round).toEqual(5); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /platforms/src/GtcStaking/index.ts: -------------------------------------------------------------------------------- 1 | export { GTCStakingPlatform } from "./App-Bindings"; 2 | export { PlatformDetails, ProviderConfig, providers } from "./Providers-config"; 3 | export { 4 | SelfStakingBronzeProvider, 5 | SelfStakingGoldProvider, 6 | SelfStakingSilverProvider, 7 | BeginnerCommunityStakerProvider, 8 | ExperiencedCommunityStakerProvider, 9 | TrustedCitizenProvider, 10 | } from "./Providers"; 11 | -------------------------------------------------------------------------------- /platforms/src/GuildXYZ/App-Bindings.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import { AppContext, Platform, PlatformOptions, ProviderPayload } from "../types"; 3 | 4 | export class GuildXYZPlatform implements Platform { 5 | platformId = "GuildXYZ"; 6 | path = "GuildXYZ"; 7 | isEVM = true; 8 | clientId: string = null; 9 | redirectUri: string = null; 10 | 11 | banner = { 12 | heading: "*Qualifying guilds have more than 250 members", 13 | cta: { 14 | label: "Learn more", 15 | url: "https://support.passport.xyz/passport-knowledge-base/stamps/how-do-i-add-passport-stamps/guide-to-add-guild-stamp-to-passport", 16 | }, 17 | }; 18 | 19 | async getProviderPayload(appContext: AppContext): Promise { 20 | return {}; 21 | } 22 | 23 | getOAuthUrl(state: string): Promise { 24 | throw new Error("Method not implemented."); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /platforms/src/GuildXYZ/Providers-config.ts: -------------------------------------------------------------------------------- 1 | import { PlatformSpec, PlatformGroupSpec, Provider } from "../types"; 2 | import { GuildAdminProvider, GuildPassportMemberProvider } from "./Providers/guildXYZ"; 3 | 4 | export const PlatformDetails: PlatformSpec = { 5 | icon: "./assets/guildXYZStampIcon.svg", 6 | platform: "GuildXYZ", 7 | name: "Guild Membership and Roles", 8 | description: "Connect to Guild to verify your membership in open source communities.", 9 | connectMessage: "Verify Guilds", 10 | isEVM: true, 11 | website: "https://guild.xyz/", 12 | }; 13 | 14 | export const ProviderConfig: PlatformGroupSpec[] = [ 15 | { 16 | platformGroup: "Guild Admin", 17 | providers: [ 18 | { 19 | title: "Owner or Administrator of one or more guilds*", 20 | name: "GuildAdmin", 21 | }, 22 | ], 23 | }, 24 | { 25 | platformGroup: "Guild Passport Member", 26 | providers: [{ title: "Member with 1 or more roles in Gitcoin Passport Guild", name: "GuildPassportMember" }], 27 | }, 28 | ]; 29 | 30 | export const providers: Provider[] = [new GuildAdminProvider(), new GuildPassportMemberProvider()]; 31 | -------------------------------------------------------------------------------- /platforms/src/GuildXYZ/index.ts: -------------------------------------------------------------------------------- 1 | export { GuildXYZPlatform } from "./App-Bindings"; 2 | export { PlatformDetails, ProviderConfig, providers } from "./Providers-config"; 3 | export { GuildAdminProvider, GuildPassportMemberProvider } from "./Providers/guildXYZ"; 4 | -------------------------------------------------------------------------------- /platforms/src/Holonym/App-Bindings.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import React from "react"; 3 | import { AppContext, Platform, ProviderPayload } from "../types"; 4 | 5 | export class HolonymPlatform implements Platform { 6 | platformId = "Holonym"; 7 | path = "Holonym"; 8 | 9 | banner = { 10 | heading: "To add the Holonym Stamp to your Gitcoin Passport...", 11 | content: ( 12 |
    13 |
  • Have a smartphone, valid ID, and an Ethereum wallet with ~$10 in ETH or AVAX.
  • 14 |
  • 15 | Go to Holonym's page, verify your ID by connecting your wallet, pay the verification fee, and follow prompts 16 | to take ID and selfie photos. 17 |
  • 18 |
  • After verification, mint the SBT to your wallet, then link it to your Gitcoin Passport by verifying it.
  • 19 |
20 | ), 21 | cta: { 22 | label: "Learn more", 23 | url: "https://support.passport.xyz/passport-knowledge-base/stamps/how-do-i-add-passport-stamps/guide-to-add-holonym-stamp-to-gitcoin-passport", 24 | }, 25 | }; 26 | 27 | async getProviderPayload(appContext: AppContext): Promise { 28 | const result = await Promise.resolve({}); 29 | return result; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /platforms/src/Holonym/Providers-config.ts: -------------------------------------------------------------------------------- 1 | import { PlatformSpec, PlatformGroupSpec, Provider } from "../types"; 2 | import { HolonymGovIdProvider } from "./Providers/holonymGovIdProvider"; 3 | 4 | export const PlatformDetails: PlatformSpec = { 5 | icon: "./assets/holonymStampIcon.svg", 6 | platform: "Holonym", 7 | name: "Holonym", 8 | description: "Connect to Holonym to verify your identity without revealing any personal information.", 9 | connectMessage: "Connect Account", 10 | isEVM: true, 11 | website: "https://holonym.id/", 12 | }; 13 | 14 | export const ProviderConfig: PlatformGroupSpec[] = [ 15 | { 16 | platformGroup: "Government ID", 17 | providers: [{ title: "Proven uniqueness using Holonym with government ID", name: "HolonymGovIdProvider" }], 18 | }, 19 | ]; 20 | 21 | export const providers: Provider[] = [new HolonymGovIdProvider()]; 22 | -------------------------------------------------------------------------------- /platforms/src/Holonym/Providers/index.ts: -------------------------------------------------------------------------------- 1 | export { HolonymGovIdProvider } from "./holonymGovIdProvider"; 2 | -------------------------------------------------------------------------------- /platforms/src/Holonym/index.ts: -------------------------------------------------------------------------------- 1 | export { HolonymPlatform } from "./App-Bindings"; 2 | export { PlatformDetails, ProviderConfig, providers } from "./Providers-config"; 3 | export { HolonymGovIdProvider } from "./Providers/holonymGovIdProvider"; 4 | -------------------------------------------------------------------------------- /platforms/src/Idena/App-Bindings.ts: -------------------------------------------------------------------------------- 1 | import { Platform } from "../utils/platform"; 2 | import axios from "axios"; 3 | 4 | type IdenaProcResponse = { 5 | data: { 6 | token: string; 7 | }; 8 | }; 9 | 10 | export class IdenaPlatform extends Platform { 11 | platformId = "Idena"; 12 | path = "idena"; 13 | 14 | banner = { 15 | cta: { 16 | label: "Learn more", 17 | url: "https://support.passport.xyz/passport-knowledge-base/stamps/how-do-i-add-passport-stamps/idena-stamp", 18 | }, 19 | }; 20 | 21 | async getOAuthUrl(): Promise { 22 | const procedureUrl = process.env.NEXT_PUBLIC_PASSPORT_PROCEDURE_URL?.replace(/\/*?$/, ""); 23 | const idenaCallback = process.env.NEXT_PUBLIC_PASSPORT_IDENA_CALLBACK?.replace(/\/*?$/, ""); 24 | const idenaWebApp = process.env.NEXT_PUBLIC_PASSPORT_IDENA_WEB_APP?.replace(/\/*?$/, ""); 25 | 26 | // Fetch data from external API 27 | const res: IdenaProcResponse = await axios.post(`${procedureUrl}/idena/create-token`); 28 | const token = res.data.token; 29 | 30 | const callbackUrl = encodeURIComponent(`${idenaCallback}?state=${token}&code=${token}`); 31 | const endpoint = procedureUrl; 32 | const nonceEndpoint = `${endpoint}/idena/start-session`; 33 | const authenticationEndpoint = `${endpoint}/idena/authenticate`; 34 | return `${idenaWebApp}/dna/signin?token=${token}&callback_url=${callbackUrl}&callback_target=_self&nonce_endpoint=${nonceEndpoint}&authentication_endpoint=${authenticationEndpoint}`; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /platforms/src/Idena/Providers-config.ts: -------------------------------------------------------------------------------- 1 | import { PlatformSpec, PlatformGroupSpec, Provider } from "../types"; 2 | import { 3 | IdenaStateNewbieProvider, 4 | IdenaStateVerifiedProvider, 5 | IdenaStateHumanProvider, 6 | } from "./Providers/IdenaStateProvider"; 7 | 8 | export const PlatformDetails: PlatformSpec = { 9 | icon: "./assets/idenaStampIcon.svg", 10 | platform: "Idena", 11 | name: "Idena", 12 | description: "Connect to Idena to verify your human identity.", 13 | connectMessage: "Verify Identity", 14 | enablePlatformCardUpdate: true, 15 | website: "https://idena.io/", 16 | }; 17 | 18 | export const ProviderConfig: PlatformGroupSpec[] = [ 19 | { 20 | platformGroup: "Identity State", 21 | providers: [ 22 | { title: "Newbie", name: "IdenaState#Newbie" }, 23 | { title: "Verified", name: "IdenaState#Verified" }, 24 | { title: "Human", name: "IdenaState#Human" }, 25 | ], 26 | }, 27 | ]; 28 | 29 | export const providers: Provider[] = [ 30 | new IdenaStateNewbieProvider(), 31 | new IdenaStateVerifiedProvider(), 32 | new IdenaStateHumanProvider(), 33 | ]; 34 | -------------------------------------------------------------------------------- /platforms/src/Idena/README.md: -------------------------------------------------------------------------------- 1 | # Idena Platform Stamp 2 | 3 | Guide to working with the Idena stamps. 4 | 5 | ## Local Testing 6 | 7 | You must run the idena server locally 8 | 9 | ``` 10 | git clone https://github.com/idena-network/idena-web 11 | cd idena-web 12 | npm i --force 13 | npx next dev -p 3004 14 | ``` 15 | 16 | Add the following to your app/.env 17 | 18 | ``` 19 | NEXT_PUBLIC_FF_IDENA_STAMP=on 20 | NEXT_PUBLIC_PASSPORT_IDENA_WEB_APP=http://localhost:3004/ 21 | NEXT_PUBLIC_PASSPORT_IDENA_CALLBACK=http://localhost:3000/ 22 | ``` 23 | 24 | You must log in to Idena with a real account. Gitcoin has been provided a test 25 | account, ask for details. 26 | 27 | Note that even though the frontend makes the call to the local server, the IAM 28 | will still call the real Idena API. 29 | -------------------------------------------------------------------------------- /platforms/src/Idena/index.ts: -------------------------------------------------------------------------------- 1 | // Idena Platform 2 | export { IdenaPlatform } from "./App-Bindings"; 3 | export { 4 | IdenaStateNewbieProvider, 5 | IdenaStateVerifiedProvider, 6 | IdenaStateHumanProvider, 7 | } from "./Providers/IdenaStateProvider"; 8 | 9 | export { PlatformDetails, ProviderConfig, providers } from "./Providers-config"; 10 | -------------------------------------------------------------------------------- /platforms/src/Lens/App-Bindings.ts: -------------------------------------------------------------------------------- 1 | import { AppContext, ProviderPayload } from "../types"; 2 | import { Platform } from "../utils/platform"; 3 | 4 | export class LensPlatform extends Platform { 5 | platformId = "Lens"; 6 | path = "Lens"; 7 | clientId: string = null; 8 | redirectUri: string = null; 9 | isEVM = true; 10 | 11 | banner = { 12 | content: `To add the Lens Stamp to your Gitcoin Passport, ensure you're using 13 | your Lens Handle, not your profile. A Lens Handle is your unique identifier on 14 | Lens, required for verification. Obtain a Handle either through the Lens beta or 15 | by purchasing one from NFT marketplaces. Note: Verification may be delayed after 16 | claiming your Handle.`, 17 | cta: { 18 | label: "Learn more", 19 | url: "https://support.passport.xyz/passport-knowledge-base/stamps/how-do-i-add-passport-stamps/guide-to-add-lens-stamp-to-gitcoin-passport", 20 | }, 21 | }; 22 | 23 | async getProviderPayload(appContext: AppContext): Promise { 24 | const result = await Promise.resolve({}); 25 | return result; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /platforms/src/Lens/Providers-config.ts: -------------------------------------------------------------------------------- 1 | import { PlatformSpec, PlatformGroupSpec, Provider } from "../types"; 2 | import { LensProfileProvider } from "./Providers/lens"; 3 | 4 | export const PlatformDetails: PlatformSpec = { 5 | icon: "./assets/lensWhiteStampIcon.svg", 6 | platform: "Lens", 7 | name: "Lens", 8 | description: "Connect to Lens to verify your social media presence on Web3.", 9 | connectMessage: "Verify Account", 10 | isEVM: true, 11 | website: "https://lens.xyz/", 12 | }; 13 | 14 | export const ProviderConfig: PlatformGroupSpec[] = [ 15 | { 16 | platformGroup: "Lens Handle", 17 | providers: [{ title: "At least 1 Lens Handle", name: "Lens" }], 18 | }, 19 | ]; 20 | 21 | export const providers: Provider[] = [new LensProfileProvider()]; 22 | -------------------------------------------------------------------------------- /platforms/src/Lens/Shared.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HowittColet/passport/bd7c79421d508ee94a2a1142dec0619b35844b3b/platforms/src/Lens/Shared.ts -------------------------------------------------------------------------------- /platforms/src/Lens/index.ts: -------------------------------------------------------------------------------- 1 | export { LensPlatform } from "./App-Bindings"; 2 | export { PlatformDetails, ProviderConfig, providers } from "./Providers-config"; 3 | export { LensProfileProvider } from "./Providers/lens"; 4 | -------------------------------------------------------------------------------- /platforms/src/Linkedin/App-Bindings.ts: -------------------------------------------------------------------------------- 1 | import { PlatformOptions } from "../types"; 2 | import { Platform } from "../utils/platform"; 3 | export class LinkedinPlatform extends Platform { 4 | platformId = "Linkedin"; 5 | path = "linkedin"; 6 | 7 | constructor(options: PlatformOptions = {}) { 8 | super(); 9 | this.clientId = options.clientId as string; 10 | this.redirectUri = options.redirectUri as string; 11 | this.state = options.state as string; 12 | this.banner = { 13 | cta: { 14 | label: "Learn more", 15 | url: "https://support.passport.xyz/passport-knowledge-base/stamps/how-do-i-add-passport-stamps/guide-to-add-a-linkedin-stamp-to-passport", 16 | }, 17 | } 18 | } 19 | 20 | async getOAuthUrl(state: string): Promise { 21 | const linkedinUrl = await Promise.resolve( 22 | `https://www.linkedin.com/oauth/v2/authorization?response_type=code&client_id=${this.clientId}&redirect_uri=${this.redirectUri}&state=${state}&scope=r_emailaddress%20r_liteprofile` 23 | ); 24 | return linkedinUrl; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /platforms/src/Linkedin/Providers-config.ts: -------------------------------------------------------------------------------- 1 | import { PlatformSpec, PlatformGroupSpec, Provider } from "../types"; 2 | import { LinkedinProvider } from "./Providers/linkedin"; 3 | 4 | export const PlatformDetails: PlatformSpec = { 5 | icon: "./assets/linkedinStampIcon.svg", 6 | platform: "Linkedin", 7 | name: "Linkedin", 8 | description: "Connect your existing Linkedin account to verify.", 9 | connectMessage: "Connect Account", 10 | }; 11 | 12 | export const ProviderConfig: PlatformGroupSpec[] = [ 13 | { 14 | platformGroup: "Account Name", 15 | providers: [{ title: "Encrypted", name: "Linkedin" }], 16 | }, 17 | ]; 18 | 19 | export const providers: Provider[] = [new LinkedinProvider()]; 20 | -------------------------------------------------------------------------------- /platforms/src/Linkedin/index.ts: -------------------------------------------------------------------------------- 1 | export { LinkedinProvider } from "./Providers/linkedin"; 2 | export { PlatformDetails, ProviderConfig, providers } from "./Providers-config"; 3 | export { LinkedinPlatform } from "./App-Bindings"; 4 | -------------------------------------------------------------------------------- /platforms/src/NFT/App-Bindings.ts: -------------------------------------------------------------------------------- 1 | import { AppContext, ProviderPayload } from "../types"; 2 | import { Platform } from "../utils/platform"; 3 | 4 | export class NFTPlatform extends Platform { 5 | platformId = "NFT"; 6 | path = "NFT"; 7 | isEVM = true; 8 | 9 | banner = { 10 | content: 11 | "Click verify to process your Ethereum Mainnet NFTs. Passport uses a constantly evolving model to review your NFT activity and compare against known Sybil behavior. The number of points you'll receive is based on many factors related to the overall NFT portfolio of the address.", 12 | cta: { 13 | label: "Learn more", 14 | url: "https://support.passport.xyz/passport-knowledge-base/how-do-i-add-passport-stamps/nft-stamp", 15 | }, 16 | }; 17 | 18 | async getProviderPayload(appContext: AppContext): Promise { 19 | const result = await Promise.resolve({}); 20 | return result; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /platforms/src/NFT/Providers/index.ts: -------------------------------------------------------------------------------- 1 | export { NFTProvider } from "./nft"; 2 | export { DigitalCollectorProvider, ArtAficionadoProvider, NftVisionaryProvider, NftCollectorBaseProvider } from "./collectors_journey"; 3 | -------------------------------------------------------------------------------- /platforms/src/NFT/index.ts: -------------------------------------------------------------------------------- 1 | export { NFTPlatform } from "./App-Bindings"; 2 | export { NFTProvider } from "./Providers"; 3 | export { PlatformDetails, ProviderConfig, providers } from "./Providers-config"; 4 | -------------------------------------------------------------------------------- /platforms/src/Outdid/Providers-config.ts: -------------------------------------------------------------------------------- 1 | import { PlatformSpec, PlatformGroupSpec, Provider } from "../types"; 2 | import { OutdidProvider } from "./Providers/outdid"; 3 | 4 | export const PlatformDetails: PlatformSpec = { 5 | icon: "./assets/outdidStampIcon.svg", 6 | platform: "Outdid", 7 | name: "Outdid", 8 | description: "Outdid's free ZK ID verification brings a strong sybil signal with complete privacy and anonymity.", 9 | connectMessage: "Connect Account", 10 | website: "https://outdid.io/", 11 | }; 12 | 13 | export const ProviderConfig: PlatformGroupSpec[] = [ 14 | { 15 | platformGroup: "Name of the Stamp platform group", 16 | providers: [ 17 | { 18 | title: "ZK-prove your identity with Outdid", 19 | description: "Outdid uses zero-knowledge cryptography to ensure you are a unique human without revealing any personal information.", 20 | name: "Outdid", 21 | }, 22 | ] 23 | }, 24 | ]; 25 | 26 | export const providers: Provider[] = [new OutdidProvider()] -------------------------------------------------------------------------------- /platforms/src/Outdid/index.ts: -------------------------------------------------------------------------------- 1 | export { OutdidPlatform } from "./App-Bindings"; 2 | export { ProviderConfig, PlatformDetails, providers } from "./Providers-config"; 3 | export { OutdidProvider } from "./Providers/outdid"; -------------------------------------------------------------------------------- /platforms/src/Outdid/procedures/outdidVerification.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | 3 | type OutdidVerificationResponse = { successRedirect: string, verificationID: string, userDid?: string }; 4 | 5 | export const outdidRequestVerification = async (userDid: string, redirect: string): Promise => { 6 | // request a verification containing a unique user identifier 7 | return await axios.post(`https://api.outdid.io/v1/verification-request?apiKey=${process.env.OUTDID_API_KEY}&apiSecret=${process.env.OUTDID_API_SECRET}`, { 8 | verificationParameters: { uniqueness: true }, 9 | verificationType: "icao", 10 | verificationName: userDid, 11 | redirect, 12 | }).then((response: { data: OutdidVerificationResponse }) => { 13 | return response.data; 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /platforms/src/POAP/App-Bindings.ts: -------------------------------------------------------------------------------- 1 | import { AppContext, ProviderPayload } from "../types"; 2 | import { Platform } from "../utils/platform"; 3 | 4 | export class POAPPlatform extends Platform { 5 | platformId = "POAP"; 6 | path = "POAP"; 7 | isEVM = true; 8 | 9 | async getProviderPayload(appContext: AppContext): Promise { 10 | const result = await Promise.resolve({}); 11 | return result; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /platforms/src/POAP/Providers-config.ts: -------------------------------------------------------------------------------- 1 | import { PlatformSpec, PlatformGroupSpec, Provider } from "../types"; 2 | import { POAPProvider } from "./Providers/poap"; 3 | 4 | export const PlatformDetails: PlatformSpec = { 5 | icon: "./assets/poapStampIcon.svg", 6 | platform: "POAP", 7 | name: "POAP", 8 | description: "Connect an account to a POAP owned for over 15 days.", 9 | connectMessage: "Connect to POAP", 10 | isEVM: true, 11 | }; 12 | 13 | export const ProviderConfig: PlatformGroupSpec[] = [ 14 | { 15 | platformGroup: "Account Name", 16 | providers: [{ title: "Connect an account to a POAP owned for over 15 days.", name: "POAP" }], 17 | }, 18 | ]; 19 | 20 | export const providers: Provider[] = [new POAPProvider()]; 21 | -------------------------------------------------------------------------------- /platforms/src/POAP/Shared.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HowittColet/passport/bd7c79421d508ee94a2a1142dec0619b35844b3b/platforms/src/POAP/Shared.ts -------------------------------------------------------------------------------- /platforms/src/POAP/index.ts: -------------------------------------------------------------------------------- 1 | export { POAPPlatform } from "./App-Bindings"; 2 | export { PlatformDetails, ProviderConfig, providers } from "./Providers-config"; 3 | export { POAPProvider } from "./Providers/poap"; 4 | -------------------------------------------------------------------------------- /platforms/src/Snapshot/App-Bindings.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import { AppContext, ProviderPayload } from "../types"; 3 | import { Platform } from "../utils/platform"; 4 | 5 | export class SnapshotPlatform extends Platform { 6 | platformId = "Snapshot"; 7 | path = "Snapshot"; 8 | isEVM = true; 9 | banner = { 10 | cta: { 11 | label: "Learn more", 12 | url: "https://support.passport.xyz/passport-knowledge-base/stamps/how-do-i-add-passport-stamps/connecting-snapshot-to-passport", 13 | }, 14 | }; 15 | async getProviderPayload(appContext: AppContext): Promise { 16 | const result = await Promise.resolve({}); 17 | return result; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /platforms/src/Snapshot/Providers-config.ts: -------------------------------------------------------------------------------- 1 | import { PlatformSpec, PlatformGroupSpec, Provider } from "../types"; 2 | import { SnapshotProposalsProvider } from "./Providers"; 3 | 4 | export const PlatformDetails: PlatformSpec = { 5 | icon: "./assets/snapshotStampIcon.svg", 6 | platform: "Snapshot", 7 | name: "Snapshot", 8 | description: "Connect to Snapshot to verify your DAO voting power.", 9 | connectMessage: "Verify Account", 10 | isEVM: true, 11 | website: "https://snapshot.org/", 12 | }; 13 | 14 | export const ProviderConfig: PlatformGroupSpec[] = [ 15 | { 16 | platformGroup: "Snapshot Proposal Creator", 17 | providers: [ 18 | { title: "Created a DAO proposal that was voted on by at least 1 account", name: "SnapshotProposalsProvider" }, 19 | ], 20 | }, 21 | ]; 22 | 23 | export const providers: Provider[] = [new SnapshotProposalsProvider()]; 24 | -------------------------------------------------------------------------------- /platforms/src/Snapshot/Providers/index.ts: -------------------------------------------------------------------------------- 1 | export { SnapshotProposalsProvider } from "./snapshotProposalsProvider"; 2 | -------------------------------------------------------------------------------- /platforms/src/Snapshot/index.ts: -------------------------------------------------------------------------------- 1 | export { SnapshotPlatform } from "./App-Bindings"; 2 | export { PlatformDetails, ProviderConfig, providers } from "./Providers-config"; 3 | export { SnapshotProposalsProvider } from "./Providers"; 4 | -------------------------------------------------------------------------------- /platforms/src/TrustaLabs/App-Bindings.tsx: -------------------------------------------------------------------------------- 1 | import { AppContext, ProviderPayload } from "../types"; 2 | import { Platform } from "../utils/platform"; 3 | import React from "react"; 4 | 5 | const Link = ({ href, children }: { href: string; children: React.ReactNode }) => ( 6 | 7 | {children} 8 | 9 | ); 10 | 11 | export class TrustaLabsPlatform extends Platform { 12 | platformId = "TrustaLabs"; 13 | path = "TrustaLabs"; 14 | isEVM = true; 15 | 16 | banner = { 17 | content: ( 18 |
19 | This uses Trusta's TrustScan product based on your 20 | activities on Eth Mainnet. You will not be able to claim the stamp if you lack sufficient data or have Sybil 21 | like patterns they have detected. Note, the MEDIA score for zkSync is different from this score. For more 22 | questions please see their{" "} 23 | Q&A. 24 |
25 | ), 26 | cta: { 27 | label: "Learn more", 28 | url: "https://support.passport.xyz/passport-knowledge-base/stamps/how-do-i-add-passport-stamps/guide-to-add-trusta-labs-stamp-to-passport", 29 | }, 30 | }; 31 | 32 | async getProviderPayload(_appContext: AppContext): Promise { 33 | return await Promise.resolve({}); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /platforms/src/TrustaLabs/Providers-config.ts: -------------------------------------------------------------------------------- 1 | import { PlatformSpec, PlatformGroupSpec, Provider } from "../types"; 2 | import { TrustaLabsProvider } from "./Providers/TrustaLabs"; 3 | 4 | export const PlatformDetails: PlatformSpec = { 5 | icon: "./assets/trustaLabsStampIcon.svg", 6 | platform: "TrustaLabs", 7 | name: "Trusta Labs", 8 | description: "Connect to Trusta Labs to verify your identity and reputation on Web3.", 9 | connectMessage: "Connect Account", 10 | website: "https://www.trustalabs.ai/", 11 | }; 12 | 13 | export const ProviderConfig: PlatformGroupSpec[] = [ 14 | { platformGroup: "Trusta Labs", providers: [{ title: "TrustScan Non-Sybil Account", name: "TrustaLabs" }] }, 15 | ]; 16 | 17 | export const providers: Provider[] = [new TrustaLabsProvider()]; 18 | -------------------------------------------------------------------------------- /platforms/src/TrustaLabs/Providers/index.ts: -------------------------------------------------------------------------------- 1 | export { TrustaLabsProvider } from "./TrustaLabs"; 2 | -------------------------------------------------------------------------------- /platforms/src/TrustaLabs/index.ts: -------------------------------------------------------------------------------- 1 | export { TrustaLabsPlatform } from "./App-Bindings"; 2 | export { ProviderConfig, PlatformDetails, providers } from "./Providers-config"; 3 | export { TrustaLabsProvider } from "./Providers/TrustaLabs"; 4 | -------------------------------------------------------------------------------- /platforms/src/Twitter/App-Bindings.ts: -------------------------------------------------------------------------------- 1 | import { Platform } from "../utils/platform"; 2 | import axios from "axios"; 3 | 4 | type TwitterProcResponse = { 5 | data: { 6 | authUrl: string; 7 | }; 8 | }; 9 | export class TwitterPlatform extends Platform { 10 | platformId = "Twitter"; 11 | path = "twitter"; 12 | 13 | async getOAuthUrl(): Promise { 14 | // Fetch data from external API 15 | const res: TwitterProcResponse = await axios.post( 16 | `${process.env.NEXT_PUBLIC_PASSPORT_PROCEDURE_URL?.replace(/\/*?$/, "")}/twitter/generateAuthUrl` 17 | ); 18 | return res.data.authUrl; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /platforms/src/Twitter/Providers-config.ts: -------------------------------------------------------------------------------- 1 | import { PlatformSpec, PlatformGroupSpec, Provider } from "../types"; 2 | 3 | export const PlatformDetails: PlatformSpec = { 4 | icon: "./assets/twitterStampIcon.svg", 5 | platform: "Twitter", 6 | name: "Twitter", 7 | description: "Connect to Twitter to verify your social media presence.", 8 | connectMessage: "Connect Account", 9 | website: "https://twitter.com/", 10 | }; 11 | 12 | export const ProviderConfig: PlatformGroupSpec[] = []; 13 | 14 | export const providers: Provider[] = []; 15 | -------------------------------------------------------------------------------- /platforms/src/Twitter/Shared.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HowittColet/passport/bd7c79421d508ee94a2a1142dec0619b35844b3b/platforms/src/Twitter/Shared.ts -------------------------------------------------------------------------------- /platforms/src/Twitter/index.ts: -------------------------------------------------------------------------------- 1 | // Twitter Platform 2 | export { TwitterPlatform } from "./App-Bindings"; 3 | export { PlatformDetails, ProviderConfig, providers } from "./Providers-config"; 4 | -------------------------------------------------------------------------------- /platforms/src/ZkSync/App-Bindings.ts: -------------------------------------------------------------------------------- 1 | import { AppContext, ProviderPayload } from "../types"; 2 | import { Platform } from "../utils/platform"; 3 | export class ZkSyncPlatform extends Platform { 4 | platformId = "ZkSync"; 5 | path = "ZkSync"; 6 | isEVM = true; 7 | 8 | banner = { 9 | content: 10 | "Click verify to process your zkSync Era transactions. Passport uses a constantly evolving model to review your transaction history and compare against known Sybil behavior. The number of points you'll receive is based on many factors related to the overall activity of the address.", 11 | cta: { 12 | label: "Learn more", 13 | url: "https://support.passport.xyz/passport-knowledge-base/how-do-i-add-passport-stamps/zksync-stamp", 14 | }, 15 | }; 16 | 17 | async getProviderPayload(appContext: AppContext): Promise { 18 | const result = await Promise.resolve({}); 19 | return result; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /platforms/src/ZkSync/index.ts: -------------------------------------------------------------------------------- 1 | export { ZkSyncEraProvider } from "./Providers/zkSyncEra"; 2 | 3 | export { PlatformDetails, ProviderConfig, providers } from "./Providers-config"; 4 | export { ZkSyncPlatform } from "./App-Bindings"; 5 | -------------------------------------------------------------------------------- /platforms/src/utils/__tests__/passport-cache.test.ts: -------------------------------------------------------------------------------- 1 | import { PassportCache } from "../passport-cache"; 2 | 3 | describe("PassportCache", () => { 4 | let passportCache: PassportCache; 5 | 6 | beforeEach(() => { 7 | passportCache = new PassportCache(); 8 | }); 9 | 10 | afterAll(async () => { 11 | await passportCache.disconnect(); 12 | }); 13 | 14 | it("should set a key-value pair", async () => { 15 | await passportCache.set("some_key", "some_value"); 16 | expect(await passportCache.get("some_key")).toBe("some_value"); 17 | }); 18 | it("should set a key-value hash", async () => { 19 | await passportCache.setHash("some_key", "some_field", "400"); 20 | // eslint-disable-next-line prettier/prettier 21 | expect(JSON.stringify(await passportCache.getHash("some_key"))).toBe(JSON.stringify({ some_field: "400" })); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /platforms/src/utils/clearTextSimpleProvider.ts: -------------------------------------------------------------------------------- 1 | // ----- Types 2 | import type { Provider, ProviderOptions } from "../types"; 3 | import type { RequestPayload, VerifiedPayload } from "@gitcoin/passport-types"; 4 | 5 | // Export a simple Provider as an example 6 | export class ClearTextSimpleProvider implements Provider { 7 | // Give the provider a type so that we can select it with a payload 8 | type = "ClearTextSimple"; 9 | // Options can be set here and/or via the constructor 10 | _options = { 11 | valid: "true", 12 | }; 13 | 14 | // construct the provider instance with supplied options 15 | constructor(options: ProviderOptions = {}) { 16 | this._options = { ...this._options, ...options }; 17 | } 18 | 19 | // verify that the proof object contains valid === "true" 20 | verify(payload: RequestPayload): Promise { 21 | return Promise.resolve({ 22 | valid: payload?.proofs?.valid === this._options.valid, 23 | record: { 24 | username: payload?.proofs?.username || "", 25 | pii: "Username", 26 | }, 27 | }); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /platforms/src/utils/errors.ts: -------------------------------------------------------------------------------- 1 | export type ProviderError = { 2 | name?: string; 3 | message?: string; 4 | response?: { 5 | status?: number; 6 | statusText?: string; 7 | data: unknown; 8 | }; 9 | }; 10 | 11 | export function getErrorString(error: ProviderError): string { 12 | return `${error.name} - ${error.message}|\ 13 | response: Status ${error.response?.status} - ${error.response?.statusText}|\ 14 | response data: ${JSON.stringify(error?.response?.data)}`; 15 | } 16 | -------------------------------------------------------------------------------- /platforms/src/utils/handleAxiosError.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | 3 | // Based on https://axios-http.com/docs/handling_errors 4 | export const handleAxiosError = ( 5 | error: any, 6 | label: string, 7 | // Accept any child class of Error 8 | ErrorClass: new (...args: any[]) => T, 9 | secretsToHide?: string[] 10 | ) => { 11 | if (axios.isAxiosError(error)) { 12 | let message = `Error making ${label} request, `; 13 | if (error.response) { 14 | // Received a non 2xx response 15 | const { data, status, headers } = error.response; 16 | message += `received error response with code ${status}: ${JSON.stringify(data)}, headers: ${JSON.stringify( 17 | headers 18 | )}`; 19 | } else if (error.request) { 20 | // No response received 21 | message += "no response received, " + error.message; 22 | } else { 23 | // Something happened in setting up the request that triggered an Error 24 | message += error.message; 25 | } 26 | secretsToHide?.forEach((secret) => { 27 | message = message.replace(secret, "[SECRET]"); 28 | }); 29 | throw new ErrorClass(message); 30 | } 31 | throw error; 32 | }; 33 | -------------------------------------------------------------------------------- /platforms/src/utils/handleProviderAxiosError.ts: -------------------------------------------------------------------------------- 1 | import { handleAxiosError } from "./handleAxiosError"; 2 | import { ProviderExternalVerificationError } from "../types"; 3 | 4 | export const handleProviderAxiosError = (error: any, label: string, secretsToHide?: string[]) => { 5 | return handleAxiosError(error, label, ProviderExternalVerificationError, secretsToHide); 6 | }; 7 | -------------------------------------------------------------------------------- /platforms/src/utils/simpleEvmProvider.ts: -------------------------------------------------------------------------------- 1 | // ----- Types 2 | import type { Provider, ProviderOptions } from "../types"; 3 | import type { RequestPayload, VerifiedPayload } from "@gitcoin/passport-types"; 4 | 5 | // Export a simple Provider as an example 6 | export class SimpleEvmProvider implements Provider { 7 | // Give the provider a type so that we can select it with a payload 8 | type = "SimpleEvm"; 9 | // Options can be set here and/or via the constructor 10 | _options = { 11 | valid: "true", 12 | }; 13 | 14 | // construct the provider instance with supplied options 15 | constructor(options: ProviderOptions = {}) { 16 | this._options = { ...this._options, ...options }; 17 | } 18 | 19 | // verify that the proof object contains valid === "true" 20 | verify(payload: RequestPayload): Promise { 21 | return Promise.resolve({ 22 | valid: payload?.proofs?.valid === this._options.valid, 23 | record: { 24 | address: payload.address, 25 | }, 26 | }); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /platforms/src/utils/simpleProvider.ts: -------------------------------------------------------------------------------- 1 | // ----- Types 2 | import type { Provider, ProviderOptions } from "../types"; 3 | import type { RequestPayload, VerifiedPayload } from "@gitcoin/passport-types"; 4 | 5 | // Export a simple Provider as an example 6 | export class SimpleProvider implements Provider { 7 | // Give the provider a type so that we can select it with a payload 8 | type = "Simple"; 9 | // Options can be set here and/or via the constructor 10 | _options = { 11 | valid: "true", 12 | }; 13 | 14 | // construct the provider instance with supplied options 15 | constructor(options: ProviderOptions = {}) { 16 | this._options = { ...this._options, ...options }; 17 | } 18 | 19 | // verify that the proof object contains valid === "true" 20 | verify(payload: RequestPayload): Promise { 21 | return Promise.resolve(verifySimpleProvider(payload)); 22 | } 23 | } 24 | 25 | // This is pulled out to allow easier mocking in tests 26 | export const verifySimpleProvider = (payload: RequestPayload): VerifiedPayload => { 27 | const valid = payload?.proofs?.valid === "true"; 28 | const errors = valid ? [] : ["Proof is not valid"]; 29 | return { 30 | valid, 31 | errors, 32 | record: { 33 | username: payload?.proofs?.username || "", 34 | }, 35 | }; 36 | }; 37 | -------------------------------------------------------------------------------- /platforms/testSetup.js: -------------------------------------------------------------------------------- 1 | process.env.ZKSYNC_ERA_MAINNET_ENDPOINT = "https://zksync-era-api-endpoint.io"; 2 | process.env.PASSPORT_SCORER_BACKEND = "https://scorer-gtc.com"; 3 | process.env.SCORER_API_KEY = "abcdefg12345567"; 4 | 5 | jest.mock("redis", () => { 6 | // Import your mock Redis client here, so that it doesn't interfere with other mocks 7 | const { createClient } = require("./src/__tests__/mocks/redis"); 8 | return { 9 | createClient: jest.fn().mockImplementation(createClient), 10 | }; 11 | }); 12 | -------------------------------------------------------------------------------- /platforms/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.settings.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "esModuleInterop": true, 6 | "declaration": true, 7 | "allowSyntheticDefaultImports": true, 8 | "target": "ES2022", 9 | "skipLibCheck": true, 10 | "noImplicitAny": true, 11 | "moduleResolution": "node", 12 | "sourceMap": true, 13 | "outDir": "dist/commonjs", 14 | "allowJs": true, 15 | "baseUrl": "src", 16 | "paths": { 17 | "*": ["../node_modules/*", "node_modules/*"] 18 | }, 19 | "jsx": "react", 20 | "lib": ["es6", "dom"] 21 | }, 22 | "include": ["src/**/*", "__tests__/**/*"] 23 | } 24 | -------------------------------------------------------------------------------- /schemas/.env-example.env: -------------------------------------------------------------------------------- 1 | SEED="YOUR_BASE16_SEED_HERE" 2 | CERAMIC_CLIENT_URL=https://ceramic-clay.3boxlabs.com 3 | -------------------------------------------------------------------------------- /schemas/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | pnpm-debug.log* 10 | lerna-debug.log* 11 | 12 | # dependencies 13 | /node_modules 14 | /.pnp 15 | .pnp.js 16 | 17 | # testing 18 | /coverage 19 | 20 | # production 21 | /build 22 | 23 | # ceramic 24 | .pinning.store 25 | scripts/create-model.json 26 | scripts/publish-model.json 27 | 28 | # misc 29 | .DS_Store 30 | .env 31 | .env.local 32 | .env.development.local 33 | .env.test.local 34 | .env.production.local 35 | .eslintcache 36 | 37 | npm-debug.log* 38 | yarn-debug.log* 39 | yarn-error.log* 40 | 41 | /dist -------------------------------------------------------------------------------- /schemas/README.md: -------------------------------------------------------------------------------- 1 | # Gitcoin Passport Ceramic Ceramic Compose DB Setup 2 | 3 | ## Setup 4 | 5 | - `yarn install` 6 | - `yarn start:ceramic` to start local ceramic node 7 | 8 | ## GraphQL 9 | 10 | - Run the following commands to compile and deploy the schemas. I was unable to run them via yarn and had to run them from the command line. Will need ti fix passing the arguments via yarn. 11 | 12 | ````bash 13 | TODO: Fix 14 | 15 | ```bash 16 | composedb composite:create models/passportStamps.graphql --output=composites/gitcoin-passport-stamps-composite.json --did-private-key=${PRIVAKE_KEY} 17 | 18 | 19 | composedb composite:deploy composites/gitcoin-passport-stamps-composite.json --ceramic-url=${CERAMIC_URL} --did-private-key=${PRIVAKE_KEY} 20 | 21 | 22 | composedb composite:compile composites/gitcoin-passport-stamps-composite.json definitions/gitcoin-passport-stamps.ts --ceramic-url=${CERAMIC_URL} 23 | ```` 24 | 25 | - Open `schemas/definitions/gitcoin-passport-stamps.ts` and copy the `definition` object into `schemas/composites/gitcoin-passport-stamps-composite.json` 26 | - run `yarn composedb graphql:server --ceramic-url=${CERAMIC_URL} --graphiql composites/gitcoin-passport-stamps-composite.json --did-private-key=${PRIVAKE_KEY} --port=5005` 27 | -------------------------------------------------------------------------------- /schemas/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./definitions/ts/gitcoin-passport-stamps"; 2 | -------------------------------------------------------------------------------- /schemas/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.settings.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "esModuleInterop": true, 6 | "declaration": true, 7 | "allowSyntheticDefaultImports": true, 8 | "target": "ES2022", 9 | "noImplicitAny": true, 10 | "moduleResolution": "node", 11 | "sourceMap": true, 12 | "outDir": "dist/commonjs", 13 | "allowJs": true, 14 | "baseUrl": "src", 15 | "skipLibCheck": true 16 | }, 17 | "include": ["src/**/*"] 18 | } 19 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "app" }, 5 | { "path": "iam" }, 6 | { "path": "identity" }, 7 | { "path": "types" } 8 | ], 9 | "exclude": ["node_modules"] 10 | } 11 | -------------------------------------------------------------------------------- /tsconfig.settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "declaration": true, 5 | "noImplicitAny": false, 6 | "removeComments": true, 7 | "noLib": false, 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "target": "es6", 11 | "sourceMap": true, 12 | "lib": [ 13 | "es6" 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /types/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ...require("../.prettierrc.js"), 3 | }; 4 | -------------------------------------------------------------------------------- /types/README.md: -------------------------------------------------------------------------------- 1 | # @gitcoin/passport-types 2 | 3 | Shared types for the Gitcoin Passport repo. 4 | 5 | Instructions: 6 | 7 | - Ensure @gitcoin/passport-types is included as a package dependency 8 | - Import like so: `import { VerifiableCredential } from "@gitcoin/passport-types"` 9 | -------------------------------------------------------------------------------- /types/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@gitcoin/passport-types", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "types": "src/index.d.ts", 6 | "scripts": { 7 | "build": "tsc -b .", 8 | "clean": "rimraf dist *.tsbuildinfo", 9 | "lint": "tsc --noEmit && eslint --ext .ts,.js,.tsx .", 10 | "prettier": "prettier --write .", 11 | "precommit": "lint-staged", 12 | "ethers": "^5.0.32" 13 | }, 14 | "devDependencies": { 15 | "tslint": "^6.1.3", 16 | "typescript": "^5.3.3" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /types/src/brightid.d.ts: -------------------------------------------------------------------------------- 1 | export type FailResponse = { 2 | status?: number; 3 | statusText?: string; 4 | data?: { 5 | error: boolean; 6 | errorNum: number; 7 | errorMessage: string; 8 | contextIds?: string[]; 9 | code: number; 10 | }; 11 | }; 12 | 13 | export type SponsorshipSuccessResponse = { 14 | status: string; 15 | statusReason: string; 16 | }; 17 | 18 | export type VerificationSuccessResponse = { 19 | unique?: boolean; 20 | app?: string; 21 | context?: string; 22 | contextIds?: string[]; 23 | }; 24 | 25 | export type BrightIdVerificationResponse = FailResponse | VerificationSuccessResponse; 26 | 27 | export type BrightIdSponsorshipResponse = FailResponse | SponsorshipSuccessResponse; 28 | 29 | export type BrightIdProcedureResponse = { 30 | valid: boolean; 31 | result?: BrightIdSponsorshipResponse | BrightIdVerificationResponse; 32 | error?: string; 33 | }; 34 | -------------------------------------------------------------------------------- /types/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.settings.json", 3 | "compilerOptions": { 4 | "target": "ES2022", 5 | "composite": true, 6 | "declaration": true, 7 | "rootDir": ".", 8 | "types": ["node"], 9 | "outDir": "/tmp/tsc-output", 10 | "skipLibCheck": true, 11 | "noImplicitAny": true 12 | }, 13 | "include": ["src"] 14 | } 15 | --------------------------------------------------------------------------------