├── .github └── workflows │ ├── publish.yaml │ └── push.yaml ├── .gitignore ├── .mocharc.json ├── .prettierrc ├── Dockerfile ├── LICENSE ├── README.md ├── contracts ├── attesters │ ├── hydra-s1 │ │ ├── HydraS1AccountboundAttester.sol │ │ ├── HydraS1SimpleAttester.sol │ │ ├── base │ │ │ ├── HydraS1Base.sol │ │ │ └── IHydraS1Base.sol │ │ ├── interfaces │ │ │ ├── IHydraS1AccountboundAttester.sol │ │ │ └── IHydraS1SimpleAttester.sol │ │ └── libs │ │ │ ├── HydraS1AccountboundLib.sol │ │ │ └── HydraS1Lib.sol │ └── pythia-1 │ │ ├── Pythia1SimpleAttester.sol │ │ ├── base │ │ ├── IPythia1Base.sol │ │ └── Pythia1Base.sol │ │ ├── interfaces │ │ └── IPythia1SimpleAttester.sol │ │ └── libs │ │ └── Pythia1Lib.sol ├── core │ ├── AttestationsRegistry.sol │ ├── Attester.sol │ ├── Badges.sol │ ├── Front.sol │ ├── interfaces │ │ ├── IAttestationsRegistry.sol │ │ ├── IAttestationsRegistryConfigLogic.sol │ │ ├── IAttester.sol │ │ ├── IBadges.sol │ │ └── IFront.sol │ ├── libs │ │ ├── Structs.sol │ │ ├── attestations-registry │ │ │ ├── AttestationsRegistryConfigLogic.sol │ │ │ ├── AttestationsRegistryState.sol │ │ │ ├── InitializableLogic.sol │ │ │ ├── OwnableLogic.sol │ │ │ └── PausableLogic.sol │ │ └── utils │ │ │ ├── Address.sol │ │ │ ├── Bitmap256Bit.sol │ │ │ ├── Context.sol │ │ │ └── RangeLib.sol │ └── utils │ │ ├── AddressesProvider.sol │ │ └── interfaces │ │ └── IAddressesProvider.sol ├── libs │ ├── SismoLib.sol │ └── using-sismo │ │ └── UsingSismo.sol ├── periphery │ └── utils │ │ ├── AvailableRootsRegistry.sol │ │ ├── CommitmentMapperRegistry.sol │ │ ├── FrontendLib.sol │ │ ├── TransparentUpgradeableProxy.sol │ │ └── interfaces │ │ ├── IAvailableRootsRegistry.sol │ │ └── ICommitmentMapperRegistry.sol ├── tests │ ├── MockHydraS1SimpleAttester.sol │ └── mocks │ │ ├── MockAttestationsRegistry.sol │ │ ├── MockAttester.sol │ │ └── mockContractUsingSismoLib.sol └── zkdrop │ └── ZKBadgeboundERC721.sol ├── deployments ├── gnosis │ ├── .chainId │ ├── AttestationsRegistry.json │ ├── AttestationsRegistryImplem.json │ ├── AttestationsRegistryProxy.json │ ├── AvailableRootsRegistry.json │ ├── AvailableRootsRegistryImplem.json │ ├── AvailableRootsRegistryProxy.json │ ├── Badges.json │ ├── BadgesImplem.json │ ├── BadgesProxy.json │ ├── CommitmentMapperRegistry.json │ ├── CommitmentMapperRegistryImplem.json │ ├── CommitmentMapperRegistryProxy.json │ ├── Front.json │ ├── FrontImplem.json │ ├── FrontProxy.json │ ├── FrontendLib.json │ ├── HydraS1AccountboundAttester.json │ ├── HydraS1AccountboundAttesterImplem.json │ ├── HydraS1AccountboundAttesterProxy.json │ ├── HydraS1Verifier.json │ ├── Pythia1SimpleAttester.json │ ├── Pythia1SimpleAttesterImplem.json │ ├── Pythia1SimpleAttesterProxy.json │ ├── Pythia1Verifier.json │ └── solcInputs │ │ └── 61c38ae61d36c4e0fe74ede913f00b14.json ├── goerliStaging │ ├── .chainId │ ├── AddressesProviderStaging.json │ ├── AddressesProviderStagingImplem.json │ ├── AddressesProviderStagingProxy.json │ ├── AttestationsRegistry.json │ ├── AttestationsRegistryImplem.json │ ├── AttestationsRegistryProxy.json │ ├── AvailableRootsRegistry.json │ ├── AvailableRootsRegistryImplem.json │ ├── AvailableRootsRegistryProxy.json │ ├── Badges.json │ ├── BadgesImplem.json │ ├── BadgesProxy.json │ ├── CommitmentMapperRegistry.json │ ├── CommitmentMapperRegistryImplem.json │ ├── CommitmentMapperRegistryProxy.json │ ├── Front.json │ ├── FrontImplem.json │ ├── FrontProxy.json │ ├── FrontendLib.json │ ├── HydraS1AccountboundAttester.json │ ├── HydraS1AccountboundAttesterImplem.json │ ├── HydraS1AccountboundAttesterProxy.json │ ├── HydraS1SimpleAttester.json │ ├── HydraS1SimpleAttesterImplem.json │ ├── HydraS1SimpleAttesterImplemV2.json │ ├── HydraS1SimpleAttesterImplemV3.json │ ├── HydraS1SimpleAttesterProxy.json │ ├── HydraS1SoulboundAttester.json │ ├── HydraS1SoulboundAttesterImplem.json │ ├── HydraS1SoulboundAttesterProxy.json │ ├── HydraS1Verifier.json │ ├── Pythia1SimpleAttester.json │ ├── Pythia1SimpleAttesterImplem.json │ ├── Pythia1SimpleAttesterImplemV2.json │ ├── Pythia1SimpleAttesterProxy.json │ ├── Pythia1Verifier.json │ ├── ZKBadgeboundERC721.json │ ├── ZikiPass.json │ ├── ZikiPassImplem.json │ ├── ZikiPassProxy.json │ └── solcInputs │ │ ├── 24c70469fd559e01f6ff2a10472da9a6.json │ │ ├── 3c35a0b3eece336a6bec6b7e7cad1298.json │ │ ├── 61c38ae61d36c4e0fe74ede913f00b14.json │ │ ├── 62cbcc15387d7a9f73c9f91e370ed0e0.json │ │ ├── 6a43a49cef4871e7629c3936a225083d.json │ │ ├── 6edb98fea2bf424a369954d0e80655f6.json │ │ ├── 70d5ec851bd4311fac67c09b114b9c0c.json │ │ ├── 7e84cd39af8dda1388150d22fc6a7983.json │ │ ├── 8cd3fe249ae2a6d76ecd75bde0d70b64.json │ │ ├── 9638c30436d05a5fd0170ba05ff60057.json │ │ ├── 99f49ed252adf262e947b5c642bd53f3.json │ │ ├── c7c67c4a1ddf53de4ef76f8a114dfc39.json │ │ └── ca3a3d06406f39be0521e9dff90ae191.json ├── goerliTestnet │ ├── .chainId │ ├── AddressesProvider.json │ ├── AddressesProviderImplem.json │ ├── AddressesProviderProxy.json │ ├── AttestationsRegistry.json │ ├── AttestationsRegistryImplem.json │ ├── AttestationsRegistryProxy.json │ ├── AvailableRootsRegistry.json │ ├── AvailableRootsRegistryImplem.json │ ├── AvailableRootsRegistryProxy.json │ ├── Badges.json │ ├── BadgesImplem.json │ ├── BadgesProxy.json │ ├── CommitmentMapperRegistry.json │ ├── CommitmentMapperRegistryImplem.json │ ├── CommitmentMapperRegistryProxy.json │ ├── Front.json │ ├── FrontImplem.json │ ├── FrontProxy.json │ ├── FrontendLib.json │ ├── HydraS1AccountboundAttester.json │ ├── HydraS1AccountboundAttesterImplem.json │ ├── HydraS1AccountboundAttesterProxy.json │ ├── HydraS1Verifier.json │ ├── Pythia1SimpleAttester.json │ ├── Pythia1SimpleAttesterImplem.json │ ├── Pythia1SimpleAttesterProxy.json │ ├── Pythia1Verifier.json │ ├── ZikiPass.json │ ├── ZikiPassImplem.json │ ├── ZikiPassProxy.json │ └── solcInputs │ │ ├── 61c38ae61d36c4e0fe74ede913f00b14.json │ │ └── 6a43a49cef4871e7629c3936a225083d.json ├── local │ ├── .chainId │ ├── AttestationsRegistry.json │ ├── AttestationsRegistryImplem.json │ ├── AttestationsRegistryProxy.json │ ├── AvailableRootsRegistry.json │ ├── AvailableRootsRegistryImplem.json │ ├── AvailableRootsRegistryProxy.json │ ├── Badges.json │ ├── BadgesImplem.json │ ├── BadgesProxy.json │ ├── CommitmentMapperRegistry.json │ ├── CommitmentMapperRegistryImplem.json │ ├── CommitmentMapperRegistryProxy.json │ ├── Front.json │ ├── FrontImplem.json │ ├── FrontProxy.json │ ├── HydraS1SimpleAttester.json │ ├── HydraS1SimpleAttesterImplem.json │ ├── HydraS1SimpleAttesterProxy.json │ └── HydraS1Verifier.json ├── mainnet │ ├── .chainId │ ├── AddressesProvider.json │ ├── AddressesProviderImplem.json │ ├── AddressesProviderProxy.json │ ├── AttestationsRegistry.json │ ├── AttestationsRegistryImplem.json │ ├── AttestationsRegistryProxy.json │ ├── AvailableRootsRegistry.json │ ├── AvailableRootsRegistryImplem.json │ ├── AvailableRootsRegistryProxy.json │ ├── Badges.json │ ├── BadgesImplem.json │ ├── BadgesProxy.json │ ├── CommitmentMapperRegistry.json │ ├── CommitmentMapperRegistryImplem.json │ ├── CommitmentMapperRegistryProxy.json │ ├── Front.json │ ├── FrontImplem.json │ ├── FrontProxy.json │ ├── HydraS1AccountboundAttester.json │ ├── HydraS1AccountboundAttesterImplem.json │ ├── HydraS1AccountboundAttesterProxy.json │ ├── HydraS1Verifier.json │ ├── MergooorPass.json │ ├── MergooorPassImplem.json │ ├── MergooorPassProxy.json │ ├── Pythia1SimpleAttester.json │ ├── Pythia1SimpleAttesterImplem.json │ ├── Pythia1SimpleAttesterProxy.json │ ├── Pythia1Verifier.json │ └── solcInputs │ │ ├── 17323799ce052e363180ed575741910c.json │ │ └── f1771477a6a95f548250af6302581d47.json ├── mumbaiStaging │ ├── .chainId │ ├── AttestationsRegistry.json │ ├── AttestationsRegistryImplem.json │ ├── AttestationsRegistryProxy.json │ ├── AvailableRootsRegistry.json │ ├── AvailableRootsRegistryImplem.json │ ├── AvailableRootsRegistryProxy.json │ ├── Badges.json │ ├── BadgesImplem.json │ ├── BadgesProxy.json │ ├── CommitmentMapperRegistry.json │ ├── CommitmentMapperRegistryImplem.json │ ├── CommitmentMapperRegistryProxy.json │ ├── Front.json │ ├── FrontImplem.json │ ├── FrontProxy.json │ ├── FrontendLib.json │ ├── HydraS1AccountboundAttester.json │ ├── HydraS1AccountboundAttesterImplem.json │ ├── HydraS1SoulboundAttester.json │ ├── HydraS1SoulboundAttesterImplem.json │ ├── HydraS1SoulboundAttesterProxy.json │ ├── HydraS1Verifier.json │ ├── Pythia1SimpleAttester.json │ ├── Pythia1SimpleAttesterImplem.json │ ├── Pythia1SimpleAttesterProxy.json │ ├── Pythia1Verifier.json │ └── solcInputs │ │ ├── 24c70469fd559e01f6ff2a10472da9a6.json │ │ ├── 61c38ae61d36c4e0fe74ede913f00b14.json │ │ ├── 6edb98fea2bf424a369954d0e80655f6.json │ │ ├── 70d5ec851bd4311fac67c09b114b9c0c.json │ │ ├── 8cd3fe249ae2a6d76ecd75bde0d70b64.json │ │ └── c7c67c4a1ddf53de4ef76f8a114dfc39.json ├── mumbaiTestnet │ ├── .chainId │ ├── AttestationsRegistry.json │ ├── AttestationsRegistryImplem.json │ ├── AttestationsRegistryProxy.json │ ├── AvailableRootsRegistry.json │ ├── AvailableRootsRegistryImplem.json │ ├── AvailableRootsRegistryProxy.json │ ├── Badges.json │ ├── BadgesImplem.json │ ├── BadgesProxy.json │ ├── CommitmentMapperRegistry.json │ ├── CommitmentMapperRegistryImplem.json │ ├── CommitmentMapperRegistryProxy.json │ ├── Front.json │ ├── FrontImplem.json │ ├── FrontProxy.json │ ├── FrontendLib.json │ ├── HydraS1AccountboundAttester.json │ ├── HydraS1AccountboundAttesterImplem.json │ ├── HydraS1AccountboundAttesterProxy.json │ ├── HydraS1Verifier.json │ ├── Pythia1SimpleAttester.json │ ├── Pythia1SimpleAttesterImplem.json │ ├── Pythia1SimpleAttesterProxy.json │ ├── Pythia1Verifier.json │ └── solcInputs │ │ ├── 61c38ae61d36c4e0fe74ede913f00b14.json │ │ └── 6a43a49cef4871e7629c3936a225083d.json ├── polygon │ ├── .chainId │ ├── AttestationsRegistry.json │ ├── AttestationsRegistryImplem.json │ ├── AttestationsRegistryProxy.json │ ├── AvailableRootsRegistry.json │ ├── AvailableRootsRegistryImplem.json │ ├── AvailableRootsRegistryProxy.json │ ├── Badges.json │ ├── BadgesImplem.json │ ├── BadgesProxy.json │ ├── CommitmentMapperRegistry.json │ ├── CommitmentMapperRegistryImplem.json │ ├── CommitmentMapperRegistryProxy.json │ ├── Front.json │ ├── FrontImplem.json │ ├── FrontProxy.json │ ├── FrontendLib.json │ ├── HydraS1AccountboundAttester.json │ ├── HydraS1AccountboundAttesterImplem.json │ ├── HydraS1SimpleAttester.json │ ├── HydraS1SimpleAttesterImplem.json │ ├── HydraS1SimpleAttesterProxy.json │ ├── HydraS1SoulboundAttester.json │ ├── HydraS1SoulboundAttesterImplem.json │ ├── HydraS1SoulboundAttesterProxy.json │ ├── HydraS1Verifier.json │ ├── Pythia1SimpleAttester.json │ ├── Pythia1SimpleAttesterImplem.json │ ├── Pythia1SimpleAttesterProxy.json │ ├── Pythia1Verifier.json │ └── solcInputs │ │ ├── 61c38ae61d36c4e0fe74ede913f00b14.json │ │ ├── 70d5ec851bd4311fac67c09b114b9c0c.json │ │ ├── c7c67c4a1ddf53de4ef76f8a114dfc39.json │ │ └── c872f238f220b3571ef309821a459203.json ├── polygonPlayground │ ├── .chainId │ ├── AttestationsRegistry.json │ ├── AttestationsRegistryImplem.json │ ├── AttestationsRegistryProxy.json │ ├── AvailableRootsRegistry.json │ ├── AvailableRootsRegistryImplem.json │ ├── AvailableRootsRegistryProxy.json │ ├── Badges.json │ ├── BadgesImplem.json │ ├── BadgesProxy.json │ ├── CommitmentMapperRegistry.json │ ├── CommitmentMapperRegistryImplem.json │ ├── CommitmentMapperRegistryProxy.json │ ├── Front.json │ ├── FrontImplem.json │ ├── FrontProxy.json │ ├── HydraS1AccountboundAttester.json │ ├── HydraS1AccountboundAttesterImplem.json │ ├── HydraS1SimpleAttester.json │ ├── HydraS1SimpleAttesterImplem.json │ ├── HydraS1SimpleAttesterProxy.json │ ├── HydraS1SoulboundAttester.json │ ├── HydraS1SoulboundAttesterImplem.json │ ├── HydraS1SoulboundAttesterProxy.json │ ├── HydraS1Verifier.json │ ├── Pythia1SimpleAttester.json │ ├── Pythia1SimpleAttesterImplem.json │ ├── Pythia1SimpleAttesterProxy.json │ ├── Pythia1Verifier.json │ └── solcInputs │ │ ├── 6edb98fea2bf424a369954d0e80655f6.json │ │ ├── 70d5ec851bd4311fac67c09b114b9c0c.json │ │ ├── c7c67c4a1ddf53de4ef76f8a114dfc39.json │ │ └── c872f238f220b3571ef309821a459203.json └── rinkeby │ ├── .chainId │ ├── AttestationsRegistry.json │ ├── AttestationsRegistryImplem.json │ ├── AttestationsRegistryProxy.json │ ├── AvailableRootsRegistry.json │ ├── AvailableRootsRegistryImplem.json │ ├── AvailableRootsRegistryProxy.json │ ├── Badges.json │ ├── BadgesImplem.json │ ├── BadgesProxy.json │ ├── CommitmentMapperRegistry.json │ ├── CommitmentMapperRegistryImplem.json │ ├── CommitmentMapperRegistryProxy.json │ ├── Front.json │ ├── FrontImplem.json │ ├── FrontProxy.json │ ├── HydraS1SimpleAttester.json │ ├── HydraS1SimpleAttesterImplem.json │ ├── HydraS1SimpleAttesterProxy.json │ ├── HydraS1SoulboundAttester.json │ ├── HydraS1SoulboundAttesterImplem.json │ ├── HydraS1SoulboundAttesterProxy.json │ ├── HydraS1Verifier.json │ ├── Pythia1SimpleAttester.json │ ├── Pythia1SimpleAttesterImplem.json │ ├── Pythia1SimpleAttesterProxy.json │ ├── Pythia1Verifier.json │ └── solcInputs │ ├── 70d5ec851bd4311fac67c09b114b9c0c.json │ └── c872f238f220b3571ef309821a459203.json ├── docs ├── schema1.png └── top.png ├── hardhat.config.ts ├── helper-hardhat-config.ts ├── package.json ├── scripts └── wait-for-local-chain.sh ├── tasks ├── addresses-provider │ └── set-batch.task.ts ├── available-roots-registry │ ├── register-for-attester.task.ts │ └── unregister-for-attester.task.ts ├── deploy-tasks │ ├── batch │ │ └── deploy-core.task.ts │ ├── deployments-config.ts │ ├── full │ │ ├── 0-deploy-core-and-hydra-s1-simple-and-accountbound-and-pythia1.task.ts │ │ ├── 1-deploy-pythia-1-simple.task.ts │ │ ├── 2-upgrade-proxies.task.ts │ │ ├── 2-upgrade-proxies.test-fork.ts │ │ ├── 3-new-hydra-s1-verifier-and-upgrade-hydra-s1-simple-proxy.task.ts │ │ ├── 3-new-hydra-s1-verifier-and-upgrade-hydra-s1-simple-proxy.test-fork.ts │ │ ├── 4-upgrade-attestations-registry-proxy-and-badges-proxy.task.ts │ │ ├── 4-upgrade-attestations-registry-proxy-and-badges-proxy.test-fork.ts │ │ ├── 5-upgrade-proxies-with-reinitializer.task.ts │ │ ├── 5-upgrade-proxies-with-reinitializer │ │ │ ├── 5-upgrade-proxies-with-reinitializer-available-roots-registry.test-fork.ts │ │ │ ├── 5-upgrade-proxies-with-reinitializer-commitment-mapper-registry.test-fork.ts │ │ │ └── 5-upgrade-proxies-with-reinitializer-pythia1.test-fork.ts │ │ ├── 6-7-8-fork-test │ │ │ └── 6-7-8.test-fork.ts │ │ ├── 6-deploy-sismo-addresses-provider.task.ts │ │ ├── 7-upgrade-hydra-s1-accountbound-and-pythia-1-proxies.task.ts │ │ ├── 9-fork-test │ │ │ └── 9-upgrade-addresses-provider-on-testnets.test-fork.ts │ │ ├── 9-upgrade-addresses-provider-on-testnets.task.ts │ │ ├── local │ │ │ └── deploy-full-local.task.ts │ │ └── staging │ │ │ └── deploy-sismo-addresses-provider-staging.task.ts │ ├── tests │ │ ├── deploy-mock-attestations-registry.task.ts │ │ ├── deploy-mock-attester-and-core.task.ts │ │ ├── deploy-mock-attester.task.ts │ │ ├── deploy-mock-contract-using-sismo-lib.task.ts │ │ └── deploy-zk-badgebound-erc721.task.ts │ ├── unit │ │ ├── attesters │ │ │ ├── hydra-s1 │ │ │ │ ├── deploy-hydra-s1-accountbound-attester.task.ts │ │ │ │ ├── deploy-hydra-s1-simple-attester.task.ts │ │ │ │ └── deploy-hydra-s1-verifier.task.ts │ │ │ └── pythia-1 │ │ │ │ ├── deploy-pythia-1-simple-attester.task.ts │ │ │ │ └── deploy-pythia-1-verifier.task.ts │ │ ├── core │ │ │ ├── deploy-attestations-registry.task.ts │ │ │ ├── deploy-badges.task.ts │ │ │ ├── deploy-front.task.ts │ │ │ └── deploy-sismo-addresses-provider.task.ts │ │ └── periphery │ │ │ ├── deploy-available-roots-registry.task.ts │ │ │ ├── deploy-commitment-mapper-registry.task.ts │ │ │ └── deploy-frontend-lib.task.ts │ ├── utils │ │ ├── deployment.ts │ │ ├── deployments-config-types.ts │ │ └── index.ts │ └── zkdrop │ │ ├── deploy-mergooor-pass.task.ts │ │ ├── deploy-ziki-pass-staging.task.ts │ │ └── deploy-ziki-pass-testnet.task.ts ├── helpers │ ├── authorizations │ │ ├── access-control-grant-role.task.ts │ │ ├── access-control-revoke-role.task.ts │ │ ├── attestations-registry-authorize-range.task.ts │ │ ├── attestations-registry-transfer-ownership.task.ts │ │ ├── change-proxy-admin.task.ts │ │ └── ownable-transfer-ownership.task.ts │ ├── forge-create2-transaction.task.ts │ ├── print-accounts.task.ts │ ├── print-storage-layout.task.ts │ ├── proxy │ │ └── upgrade-proxy.task.ts │ └── verify-contract.task.ts └── utils │ ├── common-options.ts │ ├── confirm.ts │ ├── index.ts │ ├── relayer.ts │ └── types.ts ├── test ├── e2e │ └── e2e.test.ts ├── unit │ ├── attesters │ │ ├── hydra-s1 │ │ │ ├── hydra-s1-accountbound-attester.test.ts │ │ │ └── hydra-s1-simple-attester.test.ts │ │ └── pythia-1 │ │ │ └── pythia-1-simple-attester.test.ts │ ├── core │ │ ├── attestations-registry │ │ │ ├── attestations-registry-config-logic.test.ts │ │ │ └── attestations-registry.test.ts │ │ ├── badges.test.ts │ │ ├── front.test.ts │ │ └── utils │ │ │ └── sismo-addresses-provider.test.ts │ ├── libs │ │ └── using-sismo │ │ │ └── using-sismo.test.ts │ ├── periphery │ │ └── utils │ │ │ ├── available-roots-registry.test.ts │ │ │ ├── commitment-mapper-registry.test.ts │ │ │ └── frontend-lib.test.ts │ └── zkdrop │ │ └── zk-badgebound-erc721.test.ts └── utils │ ├── attestation-logic.ts │ ├── evm.ts │ ├── expectEvent.ts │ ├── hydra-s1-accountbound.ts │ ├── hydra-s1.ts │ ├── index.ts │ ├── pythia-1.ts │ ├── setup.ts │ └── test-helpers.ts ├── tsconfig.json ├── utils ├── constants.ts ├── index.ts ├── proxy.ts └── singletonFactory.ts └── yarn.lock /.github/workflows/publish.yaml: -------------------------------------------------------------------------------- 1 | name: Publish Docker image 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' 7 | 8 | jobs: 9 | push_to_registry: 10 | name: Push Docker image to Docker Hub 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Check out the repo 14 | uses: actions/checkout@v3 15 | 16 | - name: Set up QEMU 17 | uses: docker/setup-qemu-action@v2 18 | 19 | - name: Set up Docker Buildx 20 | uses: docker/setup-buildx-action@v2 21 | 22 | - name: Log in to Docker Hub 23 | uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9 24 | with: 25 | username: ${{ secrets.DOCKER_USERNAME }} 26 | password: ${{ secrets.DOCKER_PASSWORD }} 27 | 28 | - name: Extract metadata (tags, labels) for Docker 29 | id: meta 30 | uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 31 | with: 32 | images: sismo/sismo-protocol 33 | 34 | - name: Build and push Docker image 35 | uses: docker/build-push-action@v3 36 | with: 37 | context: . 38 | push: true 39 | platforms: linux/amd64,linux/arm64/v8 40 | tags: ${{ steps.meta.outputs.tags }} 41 | labels: ${{ steps.meta.outputs.labels }} 42 | 43 | -------------------------------------------------------------------------------- /.github/workflows/push.yaml: -------------------------------------------------------------------------------- 1 | name: On Push checks 2 | on: 3 | push: 4 | jobs: 5 | test: 6 | runs-on: ubuntu-latest 7 | name: Compile, test and test deploy 8 | steps: 9 | - uses: actions/checkout@v2 10 | - name: Setup node 11 | uses: actions/setup-node@v2 12 | with: 13 | node-version: '16.x' 14 | cache: yarn 15 | - run: yarn install --frozen-lockfile 16 | - run: yarn compile 17 | - name: test 18 | run: yarn test 19 | - name: deploy local script 20 | run: npx concurrently --kill-others -s command-1 "npx hardhat node" "sleep 2 & npx yarn deploy:local" 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | deployments 3 | cache 4 | artifacts 5 | typechain-types 6 | types/** 7 | .vscode 8 | deployments/local 9 | save 10 | .env 11 | 12 | -------------------------------------------------------------------------------- /.mocharc.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": "ts-node/register/files", 3 | "timeout": 20000 4 | } 5 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "trailingComma": "es5", 4 | "semi": true, 5 | "singleQuote": true, 6 | "tabWidth": 2, 7 | "overrides": [ 8 | { 9 | "files": "*.sol", 10 | "options": { 11 | "semi": true, 12 | "printWidth": 100 13 | } 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:16 AS build 2 | 3 | WORKDIR /usr/src/build 4 | # Install dependencies 5 | COPY package.json yarn.lock ./ 6 | 7 | RUN yarn install --frozen-lockfile 8 | COPY . . 9 | RUN yarn compile 10 | 11 | FROM node:16-slim AS run 12 | RUN apt-get -y update && apt-get -y install netcat 13 | WORKDIR /usr/src/app 14 | COPY --from=build /usr/src/build/ . 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Sismo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |
3 | Logo 4 | 5 |

6 | Sismo Protocol Contracts 7 |

8 | 9 |

10 | Made by Sismo 11 |

12 | 13 |

14 | 15 | 16 | 17 | 18 | 19 | 20 |

21 | 22 | 23 | 24 |
25 |
26 | This repository contains the smart contracts of the Sismo Protocol. 27 | 28 | There are three core contracts: 29 | 30 | - `core/AttestationsRegistry.sol`: The registry stores all attestations. It is owned by the governance that authorizes/unauthorize issuers to record in it 31 | - `core/Attester.sol` The standard abstract contract must be inherited by attesters. Attesters are issuers of attestations. They verify user requests and build attestations that will be recorded in the registry 32 | - `core/Badges.sol` Reads the registry. Stateless Non Transferable Token view of attestations (ERC1155) 33 | 34 | It also contains implementations of attester in `attesters/`: 35 | - `HydraS1SimpleAttester.sol`: ZK Attester using the [Hydra S1 Proving Scheme](https://hydra-s1.docs.sismo.io) and the notion of nullifiers. Users must provide a ZK Proof along with their request to generate attestations 36 | - `HydraS1AccountboundAttester.sol`: Accountbound version of the Simple Hydra S1 Simple Attester. (Users can update at will where the attestation is stored) 37 | 38 |

39 | 40 | 41 | ## Sismo protocol 42 | 43 | A complete overview of the protocol is available in our [documentation](https://protocol.docs.sismo.io) 44 | 45 | 46 | ## Deployed contracts 47 | 48 | Deployed contracts can be found [here](https://docs.sismo.io/sismo-docs/deployed-contract-addresses) 49 | 50 | 51 | ## Usage 52 | ### Installation 53 | ``` 54 | yarn 55 | ``` 56 | 57 | ### Compile contracts 58 | Compile contracts using hardhat 59 | ``` 60 | yarn compile 61 | ``` 62 | 63 | ### Test 64 | Launch all tests 65 | 66 | ``` 67 | yarn test 68 | ``` 69 | 70 | ### Print storage layout 71 | ``` 72 | yarn storage-layout 73 | ``` 74 | 75 | ### Deploy on local chain 76 | 77 | Terminal tab 1 78 | ``` 79 | yarn chain 80 | ``` 81 | 82 | Terminal tab 2 83 | ``` 84 | yarn deploy:local 85 | ``` 86 | 87 | 88 | ## Create a new Attester 89 | 90 | To develop a new attester, you must inherit the `core/Attester.sol` abstract contract and implement the following functions: 91 | 92 | - `_verifyRequest(request, proofData)`: You must implement the user request verification against the proof provided by the user 93 | - `buildAttestations(request, proofData)`: You must build the attestations that will be recorded from a verified user request 94 | 95 | Other optional hook functions that can be implemented: 96 | 97 | - `_beforeRecordAttestations(request, proofData)` 98 | - `_afterRecordAttestations(request, proofData)` 99 | 100 | The `/attesters/hydra-s1/HydraS1SimpleAttester.sol` is a good example of an attester implementing those functions. 101 | 102 | A [guide](https://attesters.docs.sismo.io) is offered in our documentation. 103 | 104 | Feel free open a PR with your new attester in `/attester`! 105 | 106 | ## License 107 | 108 | Distributed under the MIT License. 109 | 110 | ## Contribute 111 | 112 | Please, feel free to open issues, PRs or simply provide feedback! 113 | 114 | ## Contact 115 | 116 | Prefer [Discord](https://discord.gg/sismo) or [Twitter](https://twitter.com/sismo_eth) 117 | 118 |
119 | bottom 120 | 121 | -------------------------------------------------------------------------------- /contracts/attesters/hydra-s1/base/IHydraS1Base.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.14; 4 | pragma experimental ABIEncoderV2; 5 | 6 | import {IAttester} from '../../../core/interfaces/IAttester.sol'; 7 | import {HydraS1Verifier, HydraS1Lib, HydraS1ProofData} from '../libs/HydraS1Lib.sol'; 8 | import {ICommitmentMapperRegistry} from '../../../periphery/utils/CommitmentMapperRegistry.sol'; 9 | import {IAvailableRootsRegistry} from '../../../periphery/utils/AvailableRootsRegistry.sol'; 10 | 11 | /** 12 | * @title Hydra-S1 Base Interface 13 | * @author Sismo 14 | * @notice Interface that facilitates the use of the Hydra-S1 ZK Proving Scheme. 15 | * Hydra-S1 is single source, single group: it allows users to verify they are part of one and only one group at a time 16 | * It is inherited by the family of Hydra-S1 attesters. 17 | * It contains the errors and method specific of the Hydra-S1 attesters family and the Hydra-S1 ZK Proving Scheme 18 | * We invite readers to refer to the following: 19 | * - https://hydra-s1.docs.sismo.io for a full guide through the Hydra-S1 ZK Attestations 20 | * - https://hydra-s1-circuits.docs.sismo.io for circuits, prover and verifiers of Hydra-S1 21 | **/ 22 | interface IHydraS1Base is IAttester { 23 | error ClaimsLengthDifferentThanOne(uint256 claimLength); 24 | error RegistryRootMismatch(uint256 inputRoot); 25 | error DestinationMismatch(address expectedDestination, address inputDestination); 26 | error CommitmentMapperPubKeyMismatch( 27 | uint256 expectedX, 28 | uint256 expectedY, 29 | uint256 inputX, 30 | uint256 inputY 31 | ); 32 | error ExternalNullifierMismatch(uint256 expectedExternalNullifier, uint256 externalNullifier); 33 | error IsStrictMismatch(bool expectedStrictness, bool strictNess); 34 | error ChainIdMismatch(uint256 expectedChainId, uint256 chainId); 35 | error ValueMismatch(uint256 expectedValue, uint256 inputValue); 36 | error AccountsTreeValueMismatch( 37 | uint256 expectedAccountsTreeValue, 38 | uint256 inputAccountsTreeValue 39 | ); 40 | error InvalidGroth16Proof(string reason); 41 | 42 | function getNullifierFromExtraData(bytes memory extraData) external view returns (uint256); 43 | 44 | /** 45 | * @dev Getter of Hydra-S1 Verifier contract 46 | */ 47 | function getVerifier() external view returns (HydraS1Verifier); 48 | 49 | /** 50 | * @dev Getter of Commitment Mapper Registry contract 51 | */ 52 | function getCommitmentMapperRegistry() external view returns (ICommitmentMapperRegistry); 53 | 54 | /** 55 | * @dev Getter of Roots Registry Contract 56 | */ 57 | function getAvailableRootsRegistry() external view returns (IAvailableRootsRegistry); 58 | } 59 | -------------------------------------------------------------------------------- /contracts/attesters/hydra-s1/interfaces/IHydraS1AccountboundAttester.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.14; 4 | pragma experimental ABIEncoderV2; 5 | 6 | import {IHydraS1SimpleAttester} from '././IHydraS1SimpleAttester.sol'; 7 | 8 | /** 9 | * @title Hydra-S1 Accountbound Interface 10 | * @author Sismo 11 | * @notice Interface of the HydraS1AccountboundAttester contract which inherits from the errors, events and methods specific to the HydraS1SimpleAttester interface. 12 | **/ 13 | interface IHydraS1AccountboundAttester is IHydraS1SimpleAttester { 14 | /** 15 | * @dev Event emitted when the duration of the cooldown duration for a group index (internal collection id) has been set 16 | * @param groupIndex internal collection id 17 | * @param cooldownDuration the duration of the cooldown period 18 | **/ 19 | event CooldownDurationSetForGroupIndex(uint256 indexed groupIndex, uint32 cooldownDuration); 20 | 21 | /** 22 | * @dev Event emitted when the nullifier has been set on cooldown. This happens when the 23 | * attestation destination of a nullifier has been changed 24 | * @param nullifier user nullifier 25 | * @param burnCount the number of times the attestation destination of a nullifier has been changed 26 | **/ 27 | event NullifierSetOnCooldown(uint256 indexed nullifier, uint16 burnCount); 28 | 29 | /** 30 | * @dev Error when the nullifier is on cooldown. The user have to wait the cooldownDuration 31 | * before being able to change again the destination address. 32 | **/ 33 | error NullifierOnCooldown( 34 | uint256 nullifier, 35 | address destination, 36 | uint16 burnCount, 37 | uint32 cooldownStart 38 | ); 39 | 40 | /** 41 | * @dev Error when the cooldown duration for a given groupIndex is equal to zero. 42 | * The HydraS1AccountboundAttester behaves like the HydraS1SimpleAttester. 43 | **/ 44 | error CooldownDurationNotSetForGroupIndex(uint256 groupIndex); 45 | 46 | /** 47 | * @dev Initializes the contract, to be called by the proxy delegating calls to this implementation 48 | * @param owner Owner of the contract, can update public key and address 49 | */ 50 | function initialize(address owner) external; 51 | 52 | /** 53 | * @dev returns the nullifier for a given extraData 54 | * @param extraData bytes where the nullifier is encoded 55 | */ 56 | function getNullifierFromExtraData(bytes memory extraData) external pure returns (uint256); 57 | 58 | /** 59 | * @dev Returns the burn count for a given extraData 60 | * @param extraData bytes where the burnCount is encoded 61 | */ 62 | function getBurnCountFromExtraData(bytes memory extraData) external pure returns (uint16); 63 | 64 | /** 65 | * @dev Getter, returns the cooldown start of a nullifier 66 | * @param nullifier nullifier used 67 | **/ 68 | function getNullifierCooldownStart(uint256 nullifier) external view returns (uint32); 69 | 70 | /** 71 | * @dev Getter, returns the burnCount of a nullifier 72 | * @param nullifier nullifier used 73 | **/ 74 | function getNullifierBurnCount(uint256 nullifier) external view returns (uint16); 75 | 76 | /** 77 | * @dev Setter, sets the cooldown duration of a groupIndex 78 | * @param groupIndex internal collection id 79 | * @param cooldownDuration cooldown duration we want to set for the groupIndex 80 | **/ 81 | function setCooldownDurationForGroupIndex(uint256 groupIndex, uint32 cooldownDuration) external; 82 | 83 | /*/** 84 | * @dev Getter, get the cooldown duration of a groupIndex 85 | * @notice returns 0 when the accountbound feature is deactivated for this group 86 | * @param groupIndex internal collection id 87 | **/ 88 | function getCooldownDurationForGroupIndex(uint256 groupIndex) external view returns (uint32); 89 | } 90 | -------------------------------------------------------------------------------- /contracts/attesters/hydra-s1/interfaces/IHydraS1SimpleAttester.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.14; 4 | pragma experimental ABIEncoderV2; 5 | 6 | import {Attestation} from '../../../core/libs/Structs.sol'; 7 | import {CommitmentMapperRegistry} from '../../../periphery/utils/CommitmentMapperRegistry.sol'; 8 | import {AvailableRootsRegistry} from '../../../periphery/utils/AvailableRootsRegistry.sol'; 9 | import {HydraS1Lib, HydraS1ProofData, HydraS1ProofInput} from './../libs/HydraS1Lib.sol'; 10 | import {IHydraS1Base} from './../base/IHydraS1Base.sol'; 11 | 12 | /** 13 | * @title Hydra-S1 Accountbound Interface 14 | * @author Sismo 15 | * @notice Interface with errors, events and methods specific to the HydraS1SimpleAttester. 16 | **/ 17 | interface IHydraS1SimpleAttester is IHydraS1Base { 18 | /** 19 | * @dev Error when the nullifier is already used for a destination address 20 | **/ 21 | error NullifierUsed(uint256 nullifier); 22 | 23 | /** 24 | * @dev Error when the collectionId of an attestation overflow the AUTHORIZED_COLLECTION_ID_LAST 25 | **/ 26 | error CollectionIdOutOfBound(uint256 collectionId); 27 | 28 | /** 29 | * @dev Event emitted when the nullifier is associated to a destination address. 30 | **/ 31 | event NullifierDestinationUpdated(uint256 nullifier, address newOwner); 32 | 33 | /** 34 | * @dev Getter, returns the last attestation destination of a nullifier 35 | * @param nullifier nullifier used 36 | **/ 37 | function getDestinationOfNullifier(uint256 nullifier) external view returns (address); 38 | 39 | /** 40 | * @dev Getter 41 | * returns of the first collection in which the attester is supposed to record 42 | **/ 43 | function AUTHORIZED_COLLECTION_ID_FIRST() external view returns (uint256); 44 | 45 | /** 46 | * @dev Getter 47 | * returns of the last collection in which the attester is supposed to record 48 | **/ 49 | function AUTHORIZED_COLLECTION_ID_LAST() external view returns (uint256); 50 | } 51 | -------------------------------------------------------------------------------- /contracts/attesters/hydra-s1/libs/HydraS1AccountboundLib.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.14; 3 | 4 | import {Claim, Request} from '../../../core/libs/Structs.sol'; 5 | import {HydraS1Lib, HydraS1Claim, HydraS1GroupProperties} from './HydraS1Lib.sol'; 6 | 7 | // user Hydra-S1 claim retrieved form his request 8 | struct HydraS1AccountboundClaim { 9 | uint256 groupId; // user claims to have an account in this group 10 | uint256 claimedValue; // user claims this value for its account in the group 11 | address destination; // user claims to own this destination[] 12 | HydraS1AccountboundGroupProperties groupProperties; // user claims the group has the following properties 13 | } 14 | 15 | struct HydraS1AccountboundGroupProperties { 16 | uint128 groupIndex; 17 | uint32 generationTimestamp; 18 | uint32 cooldownDuration; 19 | bool isScore; 20 | } 21 | 22 | library HydraS1AccountboundLib { 23 | error GroupIdAndPropertiesMismatch(uint256 expectedGroupId, uint256 groupId); 24 | 25 | function _hydraS1claim(Request memory self) internal pure returns (HydraS1Claim memory) { 26 | Claim memory claim = self.claims[0]; 27 | _validateClaim(claim); 28 | 29 | HydraS1AccountboundGroupProperties memory groupProperties = abi.decode( 30 | claim.extraData, 31 | (HydraS1AccountboundGroupProperties) 32 | ); 33 | 34 | HydraS1GroupProperties memory hydraS1GroupProperties = HydraS1GroupProperties( 35 | groupProperties.groupIndex, 36 | groupProperties.generationTimestamp, 37 | groupProperties.isScore 38 | ); 39 | 40 | return ( 41 | HydraS1Claim(claim.groupId, claim.claimedValue, self.destination, hydraS1GroupProperties) 42 | ); 43 | } 44 | 45 | function _hydraS1Accountboundclaim( 46 | Request memory self 47 | ) internal pure returns (HydraS1AccountboundClaim memory) { 48 | Claim memory claim = self.claims[0]; 49 | _validateClaim(claim); 50 | 51 | HydraS1AccountboundGroupProperties memory hydraS1AccountboundGroupProperties = abi.decode( 52 | claim.extraData, 53 | (HydraS1AccountboundGroupProperties) 54 | ); 55 | 56 | return ( 57 | HydraS1AccountboundClaim( 58 | claim.groupId, 59 | claim.claimedValue, 60 | self.destination, 61 | hydraS1AccountboundGroupProperties 62 | ) 63 | ); 64 | } 65 | 66 | function _generateGroupIdFromEncodedProperties( 67 | bytes memory encodedProperties 68 | ) internal pure returns (uint256) { 69 | return uint256(keccak256(encodedProperties)) % HydraS1Lib.SNARK_FIELD; 70 | } 71 | 72 | function _validateClaim(Claim memory claim) internal pure { 73 | uint256 expectedGroupId = _generateGroupIdFromEncodedProperties(claim.extraData); 74 | if (claim.groupId != expectedGroupId) 75 | revert GroupIdAndPropertiesMismatch(expectedGroupId, claim.groupId); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /contracts/attesters/pythia-1/base/IPythia1Base.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.14; 4 | pragma experimental ABIEncoderV2; 5 | 6 | import {Pythia1Verifier, Pythia1Lib, Pythia1ProofData} from '../libs/Pythia1Lib.sol'; 7 | 8 | interface IPythia1Base { 9 | error DestinationMismatch(address expectedDestination, address inputDestination); 10 | error UserShouldOwnItsDestination(address sender, address inputdestination); 11 | error CommitmentSignerPubKeyMismatch( 12 | uint256 expectedX, 13 | uint256 expectedY, 14 | uint256 inputX, 15 | uint256 inputY 16 | ); 17 | error TicketIdentifierMismatch(uint256 expectedTicketIdentifier, uint256 ticketIdentifier); 18 | error IsStrictMismatch(bool expectedStrictness, bool strictNess); 19 | error ChainIdMismatch(uint256 expectedChainId, uint256 chainId); 20 | error ValueMismatch(uint256 expectedValue, uint256 inputValue); 21 | error GroupIdMismatch(uint256 expectedAccountsTreeValue, uint256 inputAccountsTreeValue); 22 | error InvalidGroth16Proof(string reason); 23 | 24 | /** 25 | * @dev Getter of Pythia-1 Verifier contract 26 | */ 27 | function getVerifier() external view returns (Pythia1Verifier); 28 | 29 | /** 30 | * @dev Getter of the Commitment Signer EdDSA Public Key 31 | */ 32 | function getCommitmentSignerPubKey() external view returns (uint256[2] memory); 33 | } 34 | -------------------------------------------------------------------------------- /contracts/attesters/pythia-1/interfaces/IPythia1SimpleAttester.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.14; 4 | pragma experimental ABIEncoderV2; 5 | 6 | import {Attestation} from '../../../core/libs/Structs.sol'; 7 | import {IAttester} from '../../../core/interfaces/IAttester.sol'; 8 | import {Pythia1Lib, Pythia1ProofData, Pythia1ProofInput} from './../libs/Pythia1Lib.sol'; 9 | import {IPythia1Base} from './../base/IPythia1Base.sol'; 10 | 11 | interface IPythia1SimpleAttester is IPythia1Base, IAttester { 12 | error TicketUsed(uint256 userTicket); 13 | error CollectionIdOutOfBound(uint256 collectionId); 14 | 15 | event TicketDestinationUpdated(uint256 ticket, address newOwner); 16 | event CommitmentSignerPubKeyUpdated(uint256[2] newCommitmentSignerPubKey); 17 | 18 | /** 19 | * @dev Initializes the contract, to be called by the proxy delegating calls to this implementation 20 | * @param commitmentSignerPubKey EdDSA public key of the commitment signer 21 | * @param owner Owner of the contract, can update public key and address 22 | * @notice The reinitializer modifier is needed to configure modules that are added through upgrades and that require initialization. 23 | */ 24 | function initialize(uint256[2] memory commitmentSignerPubKey, address owner) external; 25 | 26 | /** 27 | * @dev Getter, returns the last attestation destination of a ticket 28 | * @param userTicket ticket used 29 | **/ 30 | function getDestinationOfTicket(uint256 userTicket) external view returns (address); 31 | 32 | /** 33 | * @dev Getter 34 | * returns of the first collection in which the attester is supposed to record 35 | **/ 36 | function AUTHORIZED_COLLECTION_ID_FIRST() external view returns (uint256); 37 | 38 | /** 39 | * @dev Getter 40 | * returns of the last collection in which the attester is supposed to record 41 | **/ 42 | function AUTHORIZED_COLLECTION_ID_LAST() external view returns (uint256); 43 | } 44 | -------------------------------------------------------------------------------- /contracts/core/interfaces/IAttestationsRegistry.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.14; 3 | 4 | import {Attestation, AttestationData} from '../libs/Structs.sol'; 5 | import {IAttestationsRegistryConfigLogic} from './IAttestationsRegistryConfigLogic.sol'; 6 | 7 | /** 8 | * @title IAttestationsRegistry 9 | * @author Sismo 10 | * @notice This is the interface of the AttestationRegistry 11 | */ 12 | interface IAttestationsRegistry is IAttestationsRegistryConfigLogic { 13 | error IssuerNotAuthorized(address issuer, uint256 collectionId); 14 | error OwnersAndCollectionIdsLengthMismatch(address[] owners, uint256[] collectionIds); 15 | event AttestationRecorded(Attestation attestation); 16 | event AttestationDeleted(Attestation attestation); 17 | 18 | /** 19 | * @dev Main function to be called by authorized issuers 20 | * @param attestations Attestations to be recorded (creates a new one or overrides an existing one) 21 | */ 22 | function recordAttestations(Attestation[] calldata attestations) external; 23 | 24 | /** 25 | * @dev Delete function to be called by authorized issuers 26 | * @param owners The owners of the attestations to be deleted 27 | * @param collectionIds The collection ids of the attestations to be deleted 28 | */ 29 | function deleteAttestations(address[] calldata owners, uint256[] calldata collectionIds) external; 30 | 31 | /** 32 | * @dev Returns whether a user has an attestation from a collection 33 | * @param collectionId Collection identifier of the targeted attestation 34 | * @param owner Owner of the targeted attestation 35 | */ 36 | function hasAttestation(uint256 collectionId, address owner) external returns (bool); 37 | 38 | /** 39 | * @dev Getter of the data of a specific attestation 40 | * @param collectionId Collection identifier of the targeted attestation 41 | * @param owner Owner of the targeted attestation 42 | */ 43 | function getAttestationData( 44 | uint256 collectionId, 45 | address owner 46 | ) external view returns (AttestationData memory); 47 | 48 | /** 49 | * @dev Getter of the value of a specific attestation 50 | * @param collectionId Collection identifier of the targeted attestation 51 | * @param owner Owner of the targeted attestation 52 | */ 53 | function getAttestationValue(uint256 collectionId, address owner) external view returns (uint256); 54 | 55 | /** 56 | * @dev Getter of the data of a specific attestation as tuple 57 | * @param collectionId Collection identifier of the targeted attestation 58 | * @param owner Owner of the targeted attestation 59 | */ 60 | function getAttestationDataTuple( 61 | uint256 collectionId, 62 | address owner 63 | ) external view returns (address, uint256, uint32, bytes memory); 64 | 65 | /** 66 | * @dev Getter of the extraData of a specific attestation 67 | * @param collectionId Collection identifier of the targeted attestation 68 | * @param owner Owner of the targeted attestation 69 | */ 70 | function getAttestationExtraData( 71 | uint256 collectionId, 72 | address owner 73 | ) external view returns (bytes memory); 74 | 75 | /** 76 | * @dev Getter of the issuer of a specific attestation 77 | * @param collectionId Collection identifier of the targeted attestation 78 | * @param owner Owner of the targeted attestation 79 | */ 80 | function getAttestationIssuer( 81 | uint256 collectionId, 82 | address owner 83 | ) external view returns (address); 84 | 85 | /** 86 | * @dev Getter of the timestamp of a specific attestation 87 | * @param collectionId Collection identifier of the targeted attestation 88 | * @param owner Owner of the targeted attestation 89 | */ 90 | function getAttestationTimestamp( 91 | uint256 collectionId, 92 | address owner 93 | ) external view returns (uint32); 94 | 95 | /** 96 | * @dev Getter of the data of specific attestations 97 | * @param collectionIds Collection identifiers of the targeted attestations 98 | * @param owners Owners of the targeted attestations 99 | */ 100 | function getAttestationDataBatch( 101 | uint256[] memory collectionIds, 102 | address[] memory owners 103 | ) external view returns (AttestationData[] memory); 104 | 105 | /** 106 | * @dev Getter of the values of specific attestations 107 | * @param collectionIds Collection identifiers of the targeted attestations 108 | * @param owners Owners of the targeted attestations 109 | */ 110 | function getAttestationValueBatch( 111 | uint256[] memory collectionIds, 112 | address[] memory owners 113 | ) external view returns (uint256[] memory); 114 | } 115 | -------------------------------------------------------------------------------- /contracts/core/interfaces/IAttester.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.14; 3 | 4 | import {Request, Attestation} from '../libs/Structs.sol'; 5 | import {IAttestationsRegistry} from '../interfaces/IAttestationsRegistry.sol'; 6 | 7 | /** 8 | * @title IAttester 9 | * @author Sismo 10 | * @notice This is the interface for the attesters in Sismo Protocol 11 | */ 12 | interface IAttester { 13 | event AttestationGenerated(Attestation attestation); 14 | 15 | event AttestationDeleted(Attestation attestation); 16 | 17 | error AttestationDeletionNotImplemented(); 18 | 19 | /** 20 | * @dev Main external function. Allows to generate attestations by making a request and submitting proof 21 | * @param request User request 22 | * @param proofData Data sent along the request to prove its validity 23 | * @return attestations Attestations that has been recorded 24 | */ 25 | function generateAttestations( 26 | Request calldata request, 27 | bytes calldata proofData 28 | ) external returns (Attestation[] memory); 29 | 30 | /** 31 | * @dev High level function to generate attestations by making a request and submitting proof 32 | * @param request User request 33 | * @param proofData Data sent along the request to prove its validity 34 | * @return badges owner, badges tokenIds and badges values 35 | */ 36 | function mintBadges( 37 | Request calldata request, 38 | bytes calldata proofData 39 | ) external returns (address, uint256[] memory, uint256[] memory); 40 | 41 | /** 42 | * @dev External facing function. Allows to delete an attestation by submitting proof 43 | * @param collectionIds Collection identifier of attestations to delete 44 | * @param attestationsOwner Owner of attestations to delete 45 | * @param proofData Data sent along the deletion request to prove its validity 46 | * @return attestations Attestations that was deleted 47 | */ 48 | function deleteAttestations( 49 | uint256[] calldata collectionIds, 50 | address attestationsOwner, 51 | bytes calldata proofData 52 | ) external returns (Attestation[] memory); 53 | 54 | /** 55 | * @dev MANDATORY: must be implemented in attesters 56 | * It should build attestations from the user request and the proof 57 | * @param request User request 58 | * @param proofData Data sent along the request to prove its validity 59 | * @return attestations Attestations that will be recorded 60 | */ 61 | function buildAttestations( 62 | Request calldata request, 63 | bytes calldata proofData 64 | ) external view returns (Attestation[] memory); 65 | 66 | /** 67 | * @dev Attestation registry address getter 68 | * @return attestationRegistry Address of the registry 69 | */ 70 | function getAttestationRegistry() external view returns (IAttestationsRegistry); 71 | } 72 | -------------------------------------------------------------------------------- /contracts/core/interfaces/IBadges.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.14; 3 | 4 | /** 5 | * @title Interface for Badges contract 6 | * @author Sismo 7 | * @notice Stateless ERC1155 contract. Reads balance from the values of attestations 8 | * The associated attestations registry triggers TransferSingle events from this contract 9 | * It allows badge "shadow mints and burns" to be caught by off-chain platforms 10 | */ 11 | interface IBadges { 12 | error BadgesNonTransferrable(); 13 | 14 | /** 15 | * @dev Initializes the contract, to be called by the proxy delegating calls to this implementation 16 | * @param uri Uri for the metadata of badges 17 | * @param owner Owner of the contract, super admin, can setup roles and update the attestation registry 18 | * @notice The reinitializer modifier is needed to configure modules that are added through upgrades and that require initialization. 19 | */ 20 | function initialize(string memory uri, address owner) external; 21 | 22 | /** 23 | * @dev Main function of the ERC1155 badge 24 | * The balance of a user is equal to the value of the underlying attestation. 25 | * attestationCollectionId == badgeId 26 | * @param account Address to check badge balance (= value of attestation) 27 | * @param id Badge Id to check (= attestationCollectionId) 28 | */ 29 | function balanceOf(address account, uint256 id) external view returns (uint256); 30 | 31 | /** 32 | * @dev Emits a TransferSingle event, so subgraphs and other off-chain apps relying on events can see badge minting/burning 33 | * can only be called by address having the EVENT_TRIGGERER_ROLE (attestations registry address) 34 | * @param operator who is calling the TransferEvent 35 | * @param from address(0) if minting, address of the badge holder if burning 36 | * @param to address of the badge holder is minting, address(0) if burning 37 | * @param id badgeId for which to trigger the event 38 | * @param value minted/burned balance 39 | */ 40 | function triggerTransferEvent( 41 | address operator, 42 | address from, 43 | address to, 44 | uint256 id, 45 | uint256 value 46 | ) external; 47 | 48 | /** 49 | * @dev Set the attestations registry address. Can only be called by owner (default admin) 50 | * @param attestationsRegistry new attestations registry address 51 | */ 52 | function setAttestationsRegistry(address attestationsRegistry) external; 53 | 54 | /** 55 | * @dev Set the URI. Can only be called by owner (default admin) 56 | * @param uri new attestations registry address 57 | */ 58 | function setUri(string memory uri) external; 59 | 60 | /** 61 | * @dev Getter of the attestations registry 62 | */ 63 | function getAttestationsRegistry() external view returns (address); 64 | 65 | /** 66 | * @dev Getter of the badge issuer 67 | * @param account Address that holds the badge 68 | * @param id Badge Id to check (= attestationCollectionId) 69 | */ 70 | function getBadgeIssuer(address account, uint256 id) external view returns (address); 71 | 72 | /** 73 | * @dev Getter of the badge timestamp 74 | * @param account Address that holds the badge 75 | * @param id Badge Id to check (= attestationCollectionId) 76 | */ 77 | function getBadgeTimestamp(address account, uint256 id) external view returns (uint32); 78 | 79 | /** 80 | * @dev Getter of the badge extra data (it can store nullifier and burnCount) 81 | * @param account Address that holds the badge 82 | * @param id Badge Id to check (= attestationCollectionId) 83 | */ 84 | function getBadgeExtraData(address account, uint256 id) external view returns (bytes memory); 85 | 86 | /** 87 | * @dev Getter of the value of a specific badge attribute 88 | * @param id Badge Id to check (= attestationCollectionId) 89 | * @param index Index of the attribute 90 | */ 91 | function getAttributeValueForBadge(uint256 id, uint8 index) external view returns (uint8); 92 | 93 | /** 94 | * @dev Getter of all badge attributes and their values for a specific badge 95 | * @param id Badge Id to check (= attestationCollectionId) 96 | */ 97 | function getAttributesNamesAndValuesForBadge( 98 | uint256 id 99 | ) external view returns (bytes32[] memory, uint8[] memory); 100 | } 101 | -------------------------------------------------------------------------------- /contracts/core/interfaces/IFront.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.14; 3 | 4 | import {Request, Attestation} from '../libs/Structs.sol'; 5 | 6 | /** 7 | * @title IFront 8 | * @author Sismo 9 | * @notice This is the interface of the Front Contract 10 | */ 11 | interface IFront { 12 | error DifferentRequestsDestinations(); 13 | event EarlyUserAttestationGenerated(address destination); 14 | 15 | /** 16 | * @dev Forward a request to an attester and generates an early user attestation 17 | * @param attester Attester targeted by the request 18 | * @param request Request sent to the attester 19 | * @param proofData Data provided to the attester to back the request 20 | */ 21 | function generateAttestations( 22 | address attester, 23 | Request calldata request, 24 | bytes calldata proofData 25 | ) external returns (Attestation[] memory); 26 | 27 | /** 28 | * @dev generate multiple attestations at once, to the same destination 29 | * @param attesters Attesters targeted by the attesters 30 | * @param requests Requests sent to attester 31 | * @param proofDataArray Data sent with each request 32 | */ 33 | function batchGenerateAttestations( 34 | address[] calldata attesters, 35 | Request[] calldata requests, 36 | bytes[] calldata proofDataArray 37 | ) external returns (Attestation[][] memory); 38 | 39 | /** 40 | * @dev build the attestations from a user request targeting a specific attester. 41 | * Forwards to the build function of targeted attester 42 | * @param attester Targeted attester 43 | * @param request User request 44 | * @param proofData Data sent along the request to prove its validity 45 | * @return attestations Attestations that will be recorded 46 | */ 47 | function buildAttestations( 48 | address attester, 49 | Request calldata request, 50 | bytes calldata proofData 51 | ) external view returns (Attestation[] memory); 52 | 53 | /** 54 | * @dev build the attestations from multiple user requests. 55 | * Forwards to the build function(s) of targeted attester(s) 56 | * @param attesters Targeted attesters 57 | * @param requests User requests 58 | * @param proofDataArray Data sent along the request to prove its validity 59 | * @return attestations Attestations that will be recorded 60 | */ 61 | function batchBuildAttestations( 62 | address[] calldata attesters, 63 | Request[] calldata requests, 64 | bytes[] calldata proofDataArray 65 | ) external view returns (Attestation[][] memory); 66 | } 67 | -------------------------------------------------------------------------------- /contracts/core/libs/Structs.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.14; 3 | 4 | /** 5 | * @title Attestations Registry State 6 | * @author Sismo 7 | * @notice This contract holds all of the storage variables and data 8 | * structures used by the AttestationsRegistry and parent 9 | * contracts. 10 | */ 11 | 12 | // User Attestation Request, can be made by any user 13 | // The context of an Attestation Request is a specific attester contract 14 | // Each attester has groups of accounts in its available data 15 | // eg: for a specific attester: 16 | // group 1 <=> accounts that sent txs on mainnet 17 | // group 2 <=> accounts that sent txs on polygon 18 | // eg: for another attester: 19 | // group 1 <=> accounts that sent eth txs in 2022 20 | // group 2 <=> accounts sent eth txs in 2021 21 | struct Request { 22 | // implicit address attester; 23 | // implicit uint256 chainId; 24 | Claim[] claims; 25 | address destination; // destination that will receive the end attestation 26 | } 27 | 28 | struct Claim { 29 | uint256 groupId; // user claims to have an account in this group 30 | uint256 claimedValue; // user claims this value for its account in the group 31 | bytes extraData; // arbitrary data, may be required by the attester to verify claims or generate a specific attestation 32 | } 33 | 34 | /** 35 | * @dev Attestation Struct. This is the struct receive as argument by the Attestation Registry. 36 | * @param collectionId Attestation collection 37 | * @param owner Attestation collection 38 | * @param issuer Attestation collection 39 | * @param value Attestation collection 40 | * @param timestamp Attestation collection 41 | * @param extraData Attestation collection 42 | */ 43 | struct Attestation { 44 | // implicit uint256 chainId; 45 | uint256 collectionId; // Id of the attestation collection (in the registry) 46 | address owner; // Owner of the attestation 47 | address issuer; // Contract that created or last updated the record. 48 | uint256 value; // Value of the attestation 49 | uint32 timestamp; // Timestamp chosen by the attester, should correspond to the effective date of the attestation 50 | // it is different from the recording timestamp (date when the attestation was recorded) 51 | // e.g a proof of NFT ownership may have be recorded today which is 2 month old data. 52 | bytes extraData; // arbitrary data that can be added by the attester 53 | } 54 | 55 | // Attestation Data, stored in the registry 56 | // The context is a specific owner of a specific collection 57 | struct AttestationData { 58 | // implicit uint256 chainId 59 | // implicit uint256 collectionId - from context 60 | // implicit owner 61 | address issuer; // Address of the contract that recorded the attestation 62 | uint256 value; // Value of the attestation 63 | uint32 timestamp; // Effective date of issuance of the attestation. (can be different from the recording timestamp) 64 | bytes extraData; // arbitrary data that can be added by the attester 65 | } 66 | -------------------------------------------------------------------------------- /contracts/core/libs/attestations-registry/AttestationsRegistryState.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.14; 3 | 4 | import {Range} from '../utils/RangeLib.sol'; 5 | import {Attestation, AttestationData} from '../Structs.sol'; 6 | 7 | contract AttestationsRegistryState { 8 | /******************************************************* 9 | Storage layout: 10 | 19 slots for config 11 | 4 currently used for _initialized, _initializing, _paused, _owner 12 | 15 place holders 13 | 16 slots for logic 14 | 3 currently used for _authorizedRanges, _attestationsCollectionAttributesValuesBitmap, _attributesNames 15 | 13 place holders 16 | 1 slot for _attestationsData 17 | *******************************************************/ 18 | 19 | // main config 20 | // changed `_initialized` from bool to uint8 21 | // as we were using OpenZeppelin Contracts (last updated v4.5.0) (proxy/utils/Initializable.sol) 22 | // and changed to OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/Initializable.sol) 23 | // PR: https://github.com/sismo-core/sismo-protocol/pull/41 24 | uint8 internal _initialized; 25 | bool internal _initializing; 26 | bool internal _paused; 27 | address internal _owner; 28 | // keeping some space for future 29 | uint256[15] private _placeHoldersAdmin; 30 | 31 | // storing the authorized ranges for each attesters 32 | mapping(address => Range[]) internal _authorizedRanges; 33 | // Storing the attributes values used for each attestations collection 34 | // Each attribute value is an hexadecimal 35 | mapping(uint256 => uint256) internal _attestationsCollectionAttributesValuesBitmap; 36 | // Storing the attribute name for each attributes index 37 | mapping(uint8 => bytes32) internal _attributesNames; 38 | // keeping some space for future 39 | uint256[13] private _placeHoldersConfig; 40 | // storing the data of attestations 41 | // =collectionId=> =owner=> attestationData 42 | mapping(uint256 => mapping(address => AttestationData)) internal _attestationsData; 43 | } 44 | -------------------------------------------------------------------------------- /contracts/core/libs/attestations-registry/OwnableLogic.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // Forked from, removed storage, OpenZeppelin Contracts v4.4.1 (access/Ownable.sol) 3 | // OpenZeppelin Contracts v4.4.1 (access/Ownable.sol) 4 | 5 | pragma solidity ^0.8.14; 6 | 7 | import '../utils/Context.sol'; 8 | import './AttestationsRegistryState.sol'; 9 | 10 | /** 11 | * @dev Contract module which provides a basic access control mechanism, where 12 | * there is an account (an owner) that can be granted exclusive access to 13 | * specific functions. 14 | * 15 | * By default, the owner account will be the one that deploys the contract. This 16 | * can later be changed with {transferOwnership}. 17 | * 18 | * This module is used through inheritance. It will make available the modifier 19 | * `onlyOwner`, which can be applied to your functions to restrict their use to 20 | * the owner. 21 | */ 22 | abstract contract OwnableLogic is Context, AttestationsRegistryState { 23 | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); 24 | 25 | // This is the only diff with OZ contract 26 | // address private _owner; 27 | 28 | /** 29 | * @dev Initializes the contract setting the deployer as the initial owner. 30 | */ 31 | constructor() { 32 | _transferOwnership(_msgSender()); 33 | } 34 | 35 | /** 36 | * @dev Returns the address of the current owner. 37 | */ 38 | function owner() public view virtual returns (address) { 39 | return _owner; 40 | } 41 | 42 | /** 43 | * @dev Throws if called by any account other than the owner. 44 | */ 45 | modifier onlyOwner() { 46 | require(owner() == _msgSender(), 'Ownable: caller is not the owner'); 47 | _; 48 | } 49 | 50 | /** 51 | * @dev Leaves the contract without owner. It will not be possible to call 52 | * `onlyOwner` functions anymore. Can only be called by the current owner. 53 | * 54 | * NOTE: Renouncing ownership will leave the contract without an owner, 55 | * thereby removing any functionality that is only available to the owner. 56 | */ 57 | function renounceOwnership() public virtual onlyOwner { 58 | _transferOwnership(address(0)); 59 | } 60 | 61 | /** 62 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 63 | * Can only be called by the current owner. 64 | */ 65 | function transferOwnership(address newOwner) public virtual onlyOwner { 66 | require(newOwner != address(0), 'Ownable: new owner is the zero address'); 67 | _transferOwnership(newOwner); 68 | } 69 | 70 | /** 71 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 72 | * Internal function without access restriction. 73 | */ 74 | function _transferOwnership(address newOwner) internal virtual { 75 | address oldOwner = _owner; 76 | _owner = newOwner; 77 | emit OwnershipTransferred(oldOwner, newOwner); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /contracts/core/libs/attestations-registry/PausableLogic.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // Forked from, removed storage, OpenZeppelin Contracts v4.4.1 (access/Ownable.sol) 3 | // OpenZeppelin Contracts v4.4.1 (security/Pausable.sol) 4 | 5 | pragma solidity ^0.8.14; 6 | 7 | import '../utils/Context.sol'; 8 | import './AttestationsRegistryState.sol'; 9 | 10 | /** 11 | * @dev Contract module which allows children to implement an emergency stop 12 | * mechanism that can be triggered by an authorized account. 13 | * 14 | * This module is used through inheritance. It will make available the 15 | * modifiers `whenNotPaused` and `whenPaused`, which can be applied to 16 | * the functions of your contract. Note that they will not be pausable by 17 | * simply including this module, only once the modifiers are put in place. 18 | */ 19 | abstract contract PausableLogic is Context, AttestationsRegistryState { 20 | /** 21 | * @dev Emitted when the pause is triggered by `account`. 22 | */ 23 | event Paused(address account); 24 | 25 | /** 26 | * @dev Emitted when the pause is lifted by `account`. 27 | */ 28 | event Unpaused(address account); 29 | 30 | // this is the only diff with OZ contract 31 | // bool private _paused; 32 | 33 | /** 34 | * @dev Initializes the contract in unpaused state. 35 | */ 36 | constructor() { 37 | _paused = false; 38 | } 39 | 40 | /** 41 | * @dev Returns true if the contract is paused, and false otherwise. 42 | */ 43 | function paused() public view virtual returns (bool) { 44 | return _paused; 45 | } 46 | 47 | /** 48 | * @dev Modifier to make a function callable only when the contract is not paused. 49 | * 50 | * Requirements: 51 | * 52 | * - The contract must not be paused. 53 | */ 54 | modifier whenNotPaused() { 55 | require(!paused(), 'Pausable: paused'); 56 | _; 57 | } 58 | 59 | /** 60 | * @dev Modifier to make a function callable only when the contract is paused. 61 | * 62 | * Requirements: 63 | * 64 | * - The contract must be paused. 65 | */ 66 | modifier whenPaused() { 67 | require(paused(), 'Pausable: not paused'); 68 | _; 69 | } 70 | 71 | /** 72 | * @dev Triggers stopped state. 73 | * 74 | * Requirements: 75 | * 76 | * - The contract must not be paused. 77 | */ 78 | function _pause() internal virtual whenNotPaused { 79 | _paused = true; 80 | emit Paused(_msgSender()); 81 | } 82 | 83 | /** 84 | * @dev Returns to normal state. 85 | * 86 | * Requirements: 87 | * 88 | * - The contract must be paused. 89 | */ 90 | function _unpause() internal virtual whenPaused { 91 | _paused = false; 92 | emit Unpaused(_msgSender()); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /contracts/core/libs/utils/Bitmap256Bit.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.14; 3 | 4 | /* 5 | * The 256-bit bitmap is structured in 64 chuncks of 4 bits each. 6 | * The 4 bits can encode any value from 0 to 15. 7 | 8 | chunck63 chunck2 chunck1 chunck0 9 | bits bits bits bits 10 | ┌────────────┐ ┌────────────┬────────────┬────────────┐ 11 | │ 1 1 1 1 │ .... │ 1 0 1 1 │ 0 0 0 0 │ 0 0 0 1 │ 12 | └────────────┘ └────────────┴────────────┴────────────┘ 13 | value 15 value 11 value 0 value 1 14 | 15 | * A chunck index must be between 0 and 63. 16 | * A value must be between 0 and 15. 17 | **/ 18 | 19 | library Bitmap256Bit { 20 | uint256 constant MAX_INT = 2 ** 256 - 1; 21 | 22 | error IndexOutOfBounds(uint8 index); 23 | error ValueOutOfBounds(uint8 value); 24 | 25 | /** 26 | * @dev Return the value at a given index of a 256-bit bitmap 27 | * @param index index where the value can be found. Can be between 0 and 63 28 | */ 29 | function _get(uint256 self, uint8 index) internal pure returns (uint8) { 30 | uint256 currentValues = self; 31 | // Get the encoded 4-bit value by right shifting to the `index` position 32 | uint256 shifted = currentValues >> (4 * index); 33 | // Get the value by only masking the last 4 bits with an AND operator 34 | return uint8(shifted & (2 ** 4 - 1)); 35 | } 36 | 37 | /** 38 | * @dev Set a value at a chosen index in a 256-bit bitmap 39 | * @param index index where the value will be stored. Can be between 0 and 63 40 | * @param value value to store. Can be between 0 and 15 41 | */ 42 | function _set(uint256 self, uint8 index, uint8 value) internal pure returns (uint256) { 43 | _checkIndexIsValid(index); 44 | _checkValueIsValid(value); 45 | 46 | uint256 currentValues = self; 47 | // 1. first we need to remove the current value for the inputed `index` 48 | // Left Shift 4 bits mask (1111 mask) to the `index` position 49 | uint256 mask = (2 ** 4 - 1) << (4 * index); 50 | // Apply a XOR operation to obtain a mask with all bits set to 1 except the 4 bits that we want to remove 51 | uint256 negativeMask = MAX_INT ^ mask; 52 | // Apply a AND operation between the current values and the negative mask to remove the wanted bits 53 | uint256 newValues = currentValues & negativeMask; 54 | 55 | // 2. We set the new value wanted at the `index` position 56 | // Create the 4 bits encoding the new value and left shift them to the `index` position 57 | uint256 newValueMask = uint256(value) << (4 * index); 58 | // Apply an OR operation between the current values and the newValueMask to reference new value 59 | return newValues | newValueMask; 60 | } 61 | 62 | /** 63 | * @dev Get all the non-zero values in a 256-bit bitmap 64 | * @param self a 256-bit bitmap 65 | */ 66 | function _getAllNonZeroValues( 67 | uint256 self 68 | ) internal pure returns (uint8[] memory, uint8[] memory, uint8) { 69 | uint8[] memory indices = new uint8[](64); 70 | uint8[] memory values = new uint8[](64); 71 | uint8 nbOfNonZeroValues = 0; 72 | for (uint8 i = 0; i < 63; i++) { 73 | uint8 value = _get(self, i); 74 | if (value > 0) { 75 | indices[nbOfNonZeroValues] = i; 76 | values[nbOfNonZeroValues] = value; 77 | nbOfNonZeroValues++; 78 | } 79 | } 80 | return (indices, values, nbOfNonZeroValues); 81 | } 82 | 83 | /** 84 | * @dev Check if the index is valid (is between 0 and 63) 85 | * @param index index of a chunck 86 | */ 87 | function _checkIndexIsValid(uint8 index) internal pure { 88 | if (index > 63) { 89 | revert IndexOutOfBounds(index); 90 | } 91 | } 92 | 93 | /** 94 | * @dev Check if the value is valid (is between 0 and 15) 95 | * @param value value to encode in a chunck 96 | */ 97 | function _checkValueIsValid(uint8 value) internal pure { 98 | if (value > 15) { 99 | revert ValueOutOfBounds(value); 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /contracts/core/libs/utils/Context.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) 3 | 4 | pragma solidity ^0.8.14; 5 | 6 | /** 7 | * @dev Provides information about the current execution context, including the 8 | * sender of the transaction and its data. While these are generally available 9 | * via msg.sender and msg.data, they should not be accessed in such a direct 10 | * manner, since when dealing with meta-transactions the account sending and 11 | * paying for execution may not be the actual sender (as far as an application 12 | * is concerned). 13 | * 14 | * This contract is only required for intermediate, library-like contracts. 15 | */ 16 | abstract contract Context { 17 | function _msgSender() internal view virtual returns (address) { 18 | return msg.sender; 19 | } 20 | 21 | function _msgData() internal view virtual returns (bytes calldata) { 22 | return msg.data; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /contracts/core/libs/utils/RangeLib.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.14; 3 | 4 | struct Range { 5 | uint256 min; 6 | uint256 max; 7 | } 8 | 9 | // Range [0;3] includees 0 and 3 10 | library RangeUtils { 11 | function _includes(Range[] storage ranges, uint256 collectionId) internal view returns (bool) { 12 | for (uint256 i = 0; i < ranges.length; i++) { 13 | if (collectionId >= ranges[i].min && collectionId <= ranges[i].max) { 14 | return true; 15 | } 16 | } 17 | return false; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /contracts/core/utils/interfaces/IAddressesProvider.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.14; 3 | 4 | interface IAddressesProvider { 5 | /** 6 | * @dev Sets the address of a contract. 7 | * @param contractAddress Address of the contract. 8 | * @param contractName Name of the contract. 9 | */ 10 | function set(address contractAddress, string memory contractName) external; 11 | 12 | /** 13 | * @dev Sets the address of multiple contracts. 14 | * @param contractAddresses Addresses of the contracts. 15 | * @param contractNames Names of the contracts. 16 | */ 17 | function setBatch(address[] calldata contractAddresses, string[] calldata contractNames) external; 18 | 19 | /** 20 | * @dev Returns the address of a contract. 21 | * @param contractName Name of the contract (string). 22 | * @return Address of the contract. 23 | */ 24 | function get(string memory contractName) external view returns (address); 25 | 26 | /** 27 | * @dev Returns the address of a contract. 28 | * @param contractNameHash Hash of the name of the contract (bytes32). 29 | * @return Address of the contract. 30 | */ 31 | function get(bytes32 contractNameHash) external view returns (address); 32 | 33 | /** 34 | * @dev Returns the addresses of all contracts inputed. 35 | * @param contractNames Names of the contracts as strings. 36 | */ 37 | function getBatch(string[] calldata contractNames) external view returns (address[] memory); 38 | 39 | /** 40 | * @dev Returns the addresses of all contracts inputed. 41 | * @param contractNamesHash Names of the contracts as strings. 42 | */ 43 | function getBatch(bytes32[] calldata contractNamesHash) external view returns (address[] memory); 44 | 45 | /** 46 | * @dev Returns the addresses of all contracts in `_contractNames` 47 | * @return Names, Hashed Names and Addresses of all contracts. 48 | */ 49 | function getAll() external view returns (string[] memory, bytes32[] memory, address[] memory); 50 | } 51 | -------------------------------------------------------------------------------- /contracts/libs/SismoLib.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.14; 3 | 4 | /** 5 | * @title SismoLib 6 | * @author Sismo 7 | * @notice This is the Sismo Library of the Sismo protocol 8 | * It is designed to be the only contract that needs to be imported to integrate Sismo in a smart contract. 9 | * Its aim is to provide a set of sub-libraries with high-level functions to interact with the Sismo protocol easily. 10 | */ 11 | 12 | import './using-sismo/UsingSismo.sol'; 13 | -------------------------------------------------------------------------------- /contracts/periphery/utils/AvailableRootsRegistry.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.14; 3 | 4 | import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; 5 | import {IAvailableRootsRegistry} from './interfaces/IAvailableRootsRegistry.sol'; 6 | import {Initializable} from '@openzeppelin/contracts/proxy/utils/Initializable.sol'; 7 | 8 | /** 9 | * @title Attesters Groups Registry 10 | * @author Sismo 11 | * @notice This contract stores that data required by attesters to be available so they can verify user claims 12 | * This contract is deployed behind a proxy and this implementation is focused on storing merkle roots 13 | * For more information: https://available-roots-registry.docs.sismo.io 14 | * 15 | **/ 16 | contract AvailableRootsRegistry is IAvailableRootsRegistry, Initializable, Ownable { 17 | uint8 public constant IMPLEMENTATION_VERSION = 2; 18 | 19 | mapping(address => mapping(uint256 => bool)) public _roots; 20 | 21 | /** 22 | * @dev Constructor 23 | * @param owner Owner of the contract, can register/ unregister roots 24 | */ 25 | constructor(address owner) { 26 | initialize(owner); 27 | } 28 | 29 | /** 30 | * @dev Initializes the contract, to be called by the proxy delegating calls to this implementation 31 | * @param ownerAddress Owner of the contract, can update public key and address 32 | * @notice The reinitializer modifier is needed to configure modules that are added through upgrades and that require initialization. 33 | */ 34 | function initialize(address ownerAddress) public reinitializer(IMPLEMENTATION_VERSION) { 35 | // if proxy did not setup owner yet or if called by constructor (for implem setup) 36 | if (owner() == address(0) || address(this).code.length == 0) { 37 | _transferOwnership(ownerAddress); 38 | } 39 | } 40 | 41 | /** 42 | * @dev Register a root available for an attester 43 | * @param attester Attester which will have the root available 44 | * @param root Root to register 45 | */ 46 | function registerRootForAttester(address attester, uint256 root) external onlyOwner { 47 | if (attester == address(0)) revert CannotRegisterForZeroAddress(); 48 | _registerRootForAttester(attester, root); 49 | } 50 | 51 | /** 52 | * @dev Unregister a root for an attester 53 | * @param attester Attester which will no longer have the root available 54 | * @param root Root to unregister 55 | */ 56 | function unregisterRootForAttester(address attester, uint256 root) external onlyOwner { 57 | if (attester == address(0)) revert CannotUnregisterForZeroAddress(); 58 | _unregisterRootForAttester(attester, root); 59 | } 60 | 61 | /** 62 | * @dev Registers a root, available for all contracts 63 | * @param root Root to register 64 | */ 65 | function registerRootForAll(uint256 root) external onlyOwner { 66 | _registerRootForAttester(address(0), root); 67 | } 68 | 69 | /** 70 | * @dev Unregister a root, available for all contracts 71 | * @param root Root to unregister 72 | */ 73 | function unregisterRootForAll(uint256 root) external onlyOwner { 74 | _unregisterRootForAttester(address(0), root); 75 | } 76 | 77 | /** 78 | * @dev returns whether a root is available for a caller (msg.sender) 79 | * @param root root to check whether it is registered for me or not 80 | */ 81 | function isRootAvailableForMe(uint256 root) external view returns (bool) { 82 | return _roots[_msgSender()][root] || _roots[address(0)][root]; 83 | } 84 | 85 | /** 86 | * @dev Initializes the contract, to be called by the proxy delegating calls to this implementation 87 | * @param attester Owner of the contract, can update public key and address 88 | * @param root Owner of the contract, can update public key and address 89 | */ 90 | function isRootAvailableForAttester(address attester, uint256 root) external view returns (bool) { 91 | return _roots[attester][root] || _roots[address(0)][root]; 92 | } 93 | 94 | function _registerRootForAttester(address attester, uint256 root) internal { 95 | _roots[attester][root] = true; 96 | if (attester == address(0)) { 97 | emit RegisteredRootForAll(root); 98 | } else { 99 | emit RegisteredRootForAttester(attester, root); 100 | } 101 | } 102 | 103 | function _unregisterRootForAttester(address attester, uint256 root) internal { 104 | _roots[attester][root] = false; 105 | if (attester == address(0)) { 106 | emit UnregisteredRootForAll(root); 107 | } else { 108 | emit UnregisteredRootForAttester(attester, root); 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /contracts/periphery/utils/CommitmentMapperRegistry.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.14; 3 | 4 | import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; 5 | import {Initializable} from '@openzeppelin/contracts/proxy/utils/Initializable.sol'; 6 | import {ICommitmentMapperRegistry} from './interfaces/ICommitmentMapperRegistry.sol'; 7 | 8 | /** 9 | * @title Commitment Mapper Registry Contract 10 | * @author Sismo 11 | * @notice This contract stores information about the commitment mapper. 12 | * Its ethereum address and its EdDSA public key 13 | * For more information: https://commitment-mapper.docs.sismo.io 14 | * 15 | **/ 16 | contract CommitmentMapperRegistry is ICommitmentMapperRegistry, Initializable, Ownable { 17 | uint8 public constant IMPLEMENTATION_VERSION = 2; 18 | 19 | uint256[2] internal _commitmentMapperPubKey; 20 | address _commitmentMapperAddress; 21 | 22 | /** 23 | * @dev Constructor 24 | * @param owner Owner of the contract, can update public key and address 25 | * @param commitmentMapperEdDSAPubKey EdDSA public key of the commitment mapper 26 | * @param commitmentMapperAddress Address of the commitment mapper 27 | */ 28 | constructor( 29 | address owner, 30 | uint256[2] memory commitmentMapperEdDSAPubKey, 31 | address commitmentMapperAddress 32 | ) { 33 | initialize(owner, commitmentMapperEdDSAPubKey, commitmentMapperAddress); 34 | } 35 | 36 | /** 37 | * @dev Initializes the contract, to be called by the proxy delegating calls to this implementation 38 | * @param ownerAddress Owner of the contract, can update public key and address 39 | * @param commitmentMapperEdDSAPubKey EdDSA public key of the commitment mapper 40 | * @param commitmentMapperAddress Address of the commitment mapper 41 | * @notice The reinitializer modifier is needed to configure modules that are added through upgrades and that require initialization. 42 | */ 43 | function initialize( 44 | address ownerAddress, 45 | uint256[2] memory commitmentMapperEdDSAPubKey, 46 | address commitmentMapperAddress 47 | ) public reinitializer(IMPLEMENTATION_VERSION) { 48 | // if proxy did not setup owner yet or if called by constructor (for implem setup) 49 | if (owner() == address(0) || address(this).code.length == 0) { 50 | _transferOwnership(ownerAddress); 51 | _updateCommitmentMapperEdDSAPubKey(commitmentMapperEdDSAPubKey); 52 | _updateCommitmentMapperAddress(commitmentMapperAddress); 53 | } 54 | } 55 | 56 | /** 57 | * @dev Updates the EdDSA public key 58 | * @param newEdDSAPubKey new EdDSA pubic key 59 | */ 60 | function updateCommitmentMapperEdDSAPubKey(uint256[2] memory newEdDSAPubKey) external onlyOwner { 61 | _updateCommitmentMapperEdDSAPubKey(newEdDSAPubKey); 62 | } 63 | 64 | /** 65 | * @dev Updates the address 66 | * @param newAddress new address 67 | */ 68 | function updateCommitmentMapperAddress(address newAddress) external onlyOwner { 69 | _updateCommitmentMapperAddress(newAddress); 70 | } 71 | 72 | /** 73 | * @dev Getter of the EdDSA public key of the commitment mapper 74 | */ 75 | function getEdDSAPubKey() external view override returns (uint256[2] memory) { 76 | return _commitmentMapperPubKey; 77 | } 78 | 79 | /** 80 | * @dev Getter of the address of the commitment mapper 81 | */ 82 | function getAddress() external view override returns (address) { 83 | return _commitmentMapperAddress; 84 | } 85 | 86 | function _updateCommitmentMapperAddress(address newAddress) internal { 87 | _commitmentMapperAddress = newAddress; 88 | emit UpdatedCommitmentMapperAddress(newAddress); 89 | } 90 | 91 | function _updateCommitmentMapperEdDSAPubKey(uint256[2] memory pubKey) internal { 92 | _commitmentMapperPubKey = pubKey; 93 | emit UpdatedCommitmentMapperEdDSAPubKey(pubKey); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /contracts/periphery/utils/FrontendLib.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.14; 3 | 4 | import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; 5 | import {HydraS1AccountboundAttester} from '../../attesters/hydra-s1/HydraS1AccountboundAttester.sol'; 6 | import {Initializable} from '@openzeppelin/contracts/proxy/utils/Initializable.sol'; 7 | 8 | contract FrontendLib { 9 | address private immutable _hydraS1AccountboundAttester; 10 | 11 | constructor(address hydraS1AccountboundAttester) { 12 | _hydraS1AccountboundAttester = hydraS1AccountboundAttester; 13 | } 14 | 15 | function getHydraS1AccountboundAttesterDestinationOfNullifierBatch( 16 | uint256[] calldata nullifiers 17 | ) external view returns (address[] memory) { 18 | address[] memory destinations = new address[](nullifiers.length); 19 | 20 | for (uint256 i = 0; i < nullifiers.length; i++) { 21 | destinations[i] = HydraS1AccountboundAttester(_hydraS1AccountboundAttester) 22 | .getDestinationOfNullifier(nullifiers[i]); 23 | } 24 | 25 | return destinations; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /contracts/periphery/utils/interfaces/IAvailableRootsRegistry.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.14; 4 | 5 | /** 6 | * @title IAvailableRootsRegistry 7 | * @author Sismo 8 | * @notice Interface for (Merkle) Roots Registry 9 | */ 10 | interface IAvailableRootsRegistry { 11 | event RegisteredRootForAttester(address attester, uint256 root); 12 | event RegisteredRootForAll(uint256 root); 13 | event UnregisteredRootForAttester(address attester, uint256 root); 14 | event UnregisteredRootForAll(uint256 root); 15 | 16 | error CannotRegisterForZeroAddress(); 17 | error CannotUnregisterForZeroAddress(); 18 | 19 | /** 20 | * @dev Initializes the contract, to be called by the proxy delegating calls to this implementation 21 | * @param owner Owner of the contract, can update public key and address 22 | * @notice The reinitializer modifier is needed to configure modules that are added through upgrades and that require initialization. 23 | */ 24 | function initialize(address owner) external; 25 | 26 | /** 27 | * @dev Register a root available for an attester 28 | * @param attester Attester which will have the root available 29 | * @param root Root to register 30 | */ 31 | function registerRootForAttester(address attester, uint256 root) external; 32 | 33 | /** 34 | * @dev Unregister a root for an attester 35 | * @param attester Attester which will no longer have the root available 36 | * @param root Root to unregister 37 | */ 38 | function unregisterRootForAttester(address attester, uint256 root) external; 39 | 40 | /** 41 | * @dev Registers a root, available for all contracts 42 | * @param root Root to register 43 | */ 44 | function registerRootForAll(uint256 root) external; 45 | 46 | /** 47 | * @dev Unregister a root, available for all contracts 48 | * @param root Root to unregister 49 | */ 50 | function unregisterRootForAll(uint256 root) external; 51 | 52 | /** 53 | * @dev returns whether a root is available for a caller (msg.sender) 54 | * @param root root to check whether it is registered for me or not 55 | */ 56 | function isRootAvailableForMe(uint256 root) external view returns (bool); 57 | 58 | /** 59 | * @dev Initializes the contract, to be called by the proxy delegating calls to this implementation 60 | * @param attester Owner of the contract, can update public key and address 61 | * @param root Owner of the contract, can update public key and address 62 | */ 63 | function isRootAvailableForAttester(address attester, uint256 root) external view returns (bool); 64 | } 65 | -------------------------------------------------------------------------------- /contracts/periphery/utils/interfaces/ICommitmentMapperRegistry.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.14; 3 | 4 | interface ICommitmentMapperRegistry { 5 | event UpdatedCommitmentMapperEdDSAPubKey(uint256[2] newEdDSAPubKey); 6 | event UpdatedCommitmentMapperAddress(address newAddress); 7 | error PubKeyNotValid(uint256[2] pubKey); 8 | 9 | /** 10 | * @dev Initializes the contract, to be called by the proxy delegating calls to this implementation 11 | * @param owner Owner of the contract, can update public key and address 12 | * @param commitmentMapperEdDSAPubKey EdDSA public key of the commitment mapper 13 | * @param commitmentMapperAddress Address of the commitment mapper 14 | * @notice The reinitializer modifier is needed to configure modules that are added through upgrades and that require initialization. 15 | */ 16 | function initialize( 17 | address owner, 18 | uint256[2] memory commitmentMapperEdDSAPubKey, 19 | address commitmentMapperAddress 20 | ) external; 21 | 22 | /** 23 | * @dev Updates the EdDSA public key 24 | * @param newEdDSAPubKey new EdDSA pubic key 25 | */ 26 | function updateCommitmentMapperEdDSAPubKey(uint256[2] memory newEdDSAPubKey) external; 27 | 28 | /** 29 | * @dev Updates the address 30 | * @param newAddress new address 31 | */ 32 | function updateCommitmentMapperAddress(address newAddress) external; 33 | 34 | /** 35 | * @dev Getter of the address of the commitment mapper 36 | */ 37 | function getEdDSAPubKey() external view returns (uint256[2] memory); 38 | 39 | /** 40 | * @dev Getter of the address of the commitment mapper 41 | */ 42 | function getAddress() external view returns (address); 43 | } 44 | -------------------------------------------------------------------------------- /contracts/tests/MockHydraS1SimpleAttester.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.14; 4 | 5 | import {Attestation, Request} from '../core/libs/Structs.sol'; 6 | import {Attester} from '../core/Attester.sol'; 7 | import {IAttester} from '../core/interfaces/IAttester.sol'; 8 | import {IHydraS1AccountboundAttester} from '../attesters/hydra-s1/interfaces/IHydraS1AccountboundAttester.sol'; 9 | 10 | contract MockHydraS1SimpleAttester { 11 | mapping(uint256 => address) internal _nullifiersDestinations; 12 | 13 | function getDestinationOfNullifier(uint256 nullifier) external view returns (address) { 14 | return _nullifiersDestinations[nullifier]; 15 | } 16 | 17 | function setDestinationOfNullifier(uint256 nullifier, address destination) external { 18 | _nullifiersDestinations[nullifier] = destination; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /contracts/tests/mocks/MockAttestationsRegistry.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.14; 3 | import {IAttestationsRegistry} from '../../core/interfaces/IAttestationsRegistry.sol'; 4 | import {AttestationsRegistryConfigLogic} from '../../core/libs/attestations-registry/AttestationsRegistryConfigLogic.sol'; 5 | import {AttestationsRegistryState} from '../../core/libs/attestations-registry/AttestationsRegistryState.sol'; 6 | import {IBadges} from '../../core/interfaces/IBadges.sol'; 7 | import {Attestation, AttestationData} from '../../core/libs/Structs.sol'; 8 | 9 | contract MockAttestationsRegistry { 10 | uint256 immutable ATTESTATION_VALUE; 11 | 12 | event AttestationRecorded(Attestation attestation); 13 | 14 | constructor(uint256 attestationValue) { 15 | ATTESTATION_VALUE = attestationValue; 16 | } 17 | 18 | function getAttestationValue( 19 | uint256 collectionId, 20 | address owner 21 | ) external view returns (uint256) { 22 | return ATTESTATION_VALUE; 23 | } 24 | 25 | function recordAttestations(Attestation[] calldata attestations) external { 26 | for (uint256 i = 0; i < attestations.length; i++) { 27 | emit AttestationRecorded(attestations[i]); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /contracts/tests/mocks/MockAttester.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.14; 4 | 5 | import {Attestation, Request} from '../../core/libs/Structs.sol'; 6 | import {Attester} from '../../core/Attester.sol'; 7 | import {IAttester} from '../../core/interfaces/IAttester.sol'; 8 | 9 | contract MockAttester is IAttester, Attester { 10 | uint256 public immutable ATTESTATION_ID_MIN; 11 | uint256 public immutable ATTESTATION_ID_MAX; 12 | 13 | constructor( 14 | address ATTESTATION_REGISTRY_ADDRESS, 15 | uint256 collectionIdFirst, 16 | uint256 collectionIdLast 17 | ) Attester(ATTESTATION_REGISTRY_ADDRESS) { 18 | ATTESTATION_ID_MIN = collectionIdFirst; 19 | ATTESTATION_ID_MAX = collectionIdLast; 20 | } 21 | 22 | function _verifyRequest( 23 | Request calldata request, 24 | bytes calldata proofData 25 | ) internal virtual override {} 26 | 27 | function buildAttestations( 28 | Request calldata request, 29 | bytes calldata /*data*/ 30 | ) public view virtual override(Attester, IAttester) returns (Attestation[] memory) { 31 | uint256 collectionId = ATTESTATION_ID_MIN + request.claims[0].groupId; 32 | Attestation[] memory attestations = new Attestation[](1); 33 | attestations[0] = Attestation( 34 | collectionId, 35 | request.destination, 36 | address(this), 37 | request.claims[0].claimedValue, 38 | abi.decode(request.claims[0].extraData, (uint32)), 39 | 'Mock Attester v0' 40 | ); 41 | return (attestations); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /contracts/tests/mocks/mockContractUsingSismoLib.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.14; 3 | 4 | import {UsingSismo, Request} from '../../libs/SismoLib.sol'; 5 | 6 | contract MockContractUsingSismoLib is UsingSismo { 7 | uint256 public constant FIRST_GATED_BADGE_ID = 200002; 8 | uint256 public constant SECOND_GATED_BADGE_ID = 200003; 9 | 10 | mapping(address => uint256) public balances; 11 | 12 | /******************************************************* 13 | 1. MINT BADGES from sismoProof received by "Prove With Sismo" off-chain flow 14 | *******************************************************/ 15 | 16 | function testMintSismoBadgeWithAttester( 17 | Request memory request, 18 | bytes memory proofData, 19 | address attester 20 | ) external { 21 | _mintSismoBadge(request, proofData, attester); 22 | } 23 | 24 | function testMintSismoBadge(Request memory request, bytes memory proofData) external { 25 | _mintSismoBadge(request, proofData); 26 | } 27 | 28 | function testMintSismoBadgesWithAttester( 29 | Request memory request, 30 | bytes memory proofData, 31 | address attester 32 | ) external { 33 | _mintSismoBadges(request, proofData, attester); 34 | } 35 | 36 | function testMintSismoBadges(Request memory request, bytes memory proofData) external { 37 | _mintSismoBadges(request, proofData); 38 | } 39 | 40 | /******************************************************* 41 | 2. MODIFIERS 42 | *******************************************************/ 43 | 44 | function testOnlyBadgeHoldersModifier() external onlyBadgeHolders(FIRST_GATED_BADGE_ID) { 45 | _inc(_msgSender()); 46 | } 47 | 48 | function testOnlyBadgesHoldersWithAllBadgesRequiredModifier( 49 | uint256[] memory gatedBadge 50 | ) external onlyBadgesHolders(gatedBadge, true) { 51 | _inc(_msgSender()); 52 | } 53 | 54 | function testOnlyBadgesHoldersWithOnlyOneBadgeRequiredModifier( 55 | uint256[] memory gatedBadge 56 | ) external onlyBadgesHolders(gatedBadge, false) { 57 | _inc(_msgSender()); 58 | } 59 | 60 | function testOnlyBadgeHoldersWithGreaterBalanceModifier() 61 | external 62 | onlyBadgeHoldersWithGreaterBalance(FIRST_GATED_BADGE_ID, 2) 63 | { 64 | _inc(_msgSender()); 65 | } 66 | 67 | function testOnlyBadgeHoldersWithLowerBalanceModifier() 68 | external 69 | onlyBadgeHoldersWithLowerBalance(FIRST_GATED_BADGE_ID, 2) 70 | { 71 | _inc(_msgSender()); 72 | } 73 | 74 | function testOnlyBadgeHoldersWithExactBalanceModifier() 75 | external 76 | onlyBadgeHoldersWithExactBalance(FIRST_GATED_BADGE_ID, 1) 77 | { 78 | _inc(_msgSender()); 79 | } 80 | 81 | function testOnlyBadgesHoldersWithGreaterBalanceAndAllBadgesRequiredModifier( 82 | uint256[] memory badgeTokenIds, 83 | uint256[] memory minBalances 84 | ) external onlyBadgesHoldersWithGreaterBalance(badgeTokenIds, minBalances, true) { 85 | _inc(_msgSender()); 86 | } 87 | 88 | function testOnlyBadgesHoldersWithGreaterBalanceAndOnlyOneBadgeRequiredModifier( 89 | uint256[] memory badgeTokenIds, 90 | uint256[] memory minBalances 91 | ) external onlyBadgesHoldersWithGreaterBalance(badgeTokenIds, minBalances, false) { 92 | _inc(_msgSender()); 93 | } 94 | 95 | function testOnlyBadgesHoldersWithLowerBalanceAndAllBadgesRequiredModifier( 96 | uint256[] memory badgeTokenIds, 97 | uint256[] memory maxBalances 98 | ) external onlyBadgesHoldersWithLowerBalance(badgeTokenIds, maxBalances, true) { 99 | _inc(_msgSender()); 100 | } 101 | 102 | function testOnlyBadgesHoldersWithLowerBalanceAndOnlyOneBadgeRequiredModifier( 103 | uint256[] memory badgeTokenIds, 104 | uint256[] memory maxBalances 105 | ) external onlyBadgesHoldersWithLowerBalance(badgeTokenIds, maxBalances, false) { 106 | _inc(_msgSender()); 107 | } 108 | 109 | function testOnlyBadgesHoldersWithExactBalanceAndAllBadgesRequiredModifier( 110 | uint256[] memory badgeTokenIds, 111 | uint256[] memory exactBalances 112 | ) external onlyBadgesHoldersWithExactBalance(badgeTokenIds, exactBalances, true) { 113 | _inc(_msgSender()); 114 | } 115 | 116 | function testOnlyBadgesHoldersWithExactBalanceAndOnlyOneBadgeRequiredModifier( 117 | uint256[] memory badgeTokenIds, 118 | uint256[] memory exactBalances 119 | ) external onlyBadgesHoldersWithExactBalance(badgeTokenIds, exactBalances, false) { 120 | _inc(_msgSender()); 121 | } 122 | 123 | function _inc(address account) internal { 124 | balances[account]++; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /deployments/gnosis/.chainId: -------------------------------------------------------------------------------- 1 | 100 -------------------------------------------------------------------------------- /deployments/goerliStaging/.chainId: -------------------------------------------------------------------------------- 1 | 5 -------------------------------------------------------------------------------- /deployments/goerliTestnet/.chainId: -------------------------------------------------------------------------------- 1 | 5 -------------------------------------------------------------------------------- /deployments/local/.chainId: -------------------------------------------------------------------------------- 1 | 31337 -------------------------------------------------------------------------------- /deployments/mainnet/.chainId: -------------------------------------------------------------------------------- 1 | 1 -------------------------------------------------------------------------------- /deployments/mumbaiStaging/.chainId: -------------------------------------------------------------------------------- 1 | 80001 -------------------------------------------------------------------------------- /deployments/mumbaiTestnet/.chainId: -------------------------------------------------------------------------------- 1 | 80001 -------------------------------------------------------------------------------- /deployments/polygon/.chainId: -------------------------------------------------------------------------------- 1 | 137 -------------------------------------------------------------------------------- /deployments/polygonPlayground/.chainId: -------------------------------------------------------------------------------- 1 | 137 -------------------------------------------------------------------------------- /deployments/rinkeby/.chainId: -------------------------------------------------------------------------------- 1 | 4 -------------------------------------------------------------------------------- /docs/schema1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismo-core/sismo-badges/09206e396ca2342a88f7eaa897d55783f019f759/docs/schema1.png -------------------------------------------------------------------------------- /docs/top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismo-core/sismo-badges/09206e396ca2342a88f7eaa897d55783f019f759/docs/top.png -------------------------------------------------------------------------------- /helper-hardhat-config.ts: -------------------------------------------------------------------------------- 1 | import dotenv from 'dotenv'; 2 | dotenv.config({}); 3 | 4 | export type Network = EthereumNetwork | PolygonNetwork | GnosisNetwork; 5 | 6 | export enum EthereumNetwork { 7 | kovan = 'kovan', 8 | goerli = 'goerli', 9 | rinkeby = 'rinkeby', 10 | mainnet = 'mainnet', 11 | hardhat = 'hardhat', 12 | tenderlyMain = 'tenderlyMain', 13 | harhatevm = 'harhatevm', 14 | } 15 | 16 | export enum PolygonNetwork { 17 | main = 'polygon-mainnet', 18 | mumbai = 'mumbai', 19 | } 20 | 21 | export enum GnosisNetwork { 22 | gnosis = 'gnosis', 23 | } 24 | 25 | export type ParamsPerNetwork = 26 | | EthereumParamsPerNetwork 27 | | PolygonParamsPerNetwork 28 | | XDaiParamsPerNetwork; 29 | 30 | export interface EthereumParamsPerNetwork { 31 | [EthereumNetwork.harhatevm]: Network; 32 | [EthereumNetwork.rinkeby]: Network; 33 | [EthereumNetwork.mainnet]: Network; 34 | [EthereumNetwork.hardhat]: Network; 35 | [EthereumNetwork.tenderlyMain]: Network; 36 | [EthereumNetwork.goerli]: Network; 37 | } 38 | 39 | export interface PolygonParamsPerNetwork { 40 | [PolygonNetwork.main]: T; 41 | [PolygonNetwork.mumbai]: T; 42 | } 43 | 44 | export interface XDaiParamsPerNetwork { 45 | [GnosisNetwork.gnosis]: T; 46 | } 47 | 48 | export interface ObjectString { 49 | [key: string]: string; 50 | } 51 | export const alchemyUrlOrEnvVar = (defaultAlchemyUrl: string, rpcUrl?: string): string => { 52 | const defaultUrl = `${defaultAlchemyUrl}/${process.env.ALCHEMY_KEY}`; 53 | return rpcUrl ? rpcUrl : defaultUrl; 54 | }; 55 | 56 | export const NETWORKS_RPC_URL: ParamsPerNetwork = { 57 | [EthereumNetwork.rinkeby]: alchemyUrlOrEnvVar( 58 | 'https://eth-rinkeby.alchemyapi.io/v2', 59 | process.env.RINKEBY_RPC_URL 60 | ), 61 | [EthereumNetwork.mainnet]: alchemyUrlOrEnvVar( 62 | 'https://eth-mainnet.alchemyapi.io/v2', 63 | process.env.MAINNET_RPC_URL 64 | ), 65 | [EthereumNetwork.goerli]: alchemyUrlOrEnvVar( 66 | 'https://eth-goerli.g.alchemy.com/v2', 67 | process.env.MAINNET_RPC_URL 68 | ), 69 | [EthereumNetwork.hardhat]: 'http://localhost:8545', 70 | [PolygonNetwork.mumbai]: alchemyUrlOrEnvVar( 71 | 'https://polygon-mumbai.g.alchemy.com/v2', 72 | process.env.MUMBAI_RPC_URL 73 | ), 74 | [PolygonNetwork.main]: alchemyUrlOrEnvVar( 75 | 'https://polygon-mainnet.g.alchemy.com/v2', 76 | process.env.POLYGON_RPC_URL 77 | ), 78 | [GnosisNetwork.gnosis]: 'https://rpc.gnosischain.com', 79 | }; 80 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sismo-protocol", 3 | "version": "1.0.0", 4 | "description": "Sismo attestations repo", 5 | "main": "index.js", 6 | "repository": "git@github.com:sismo-core/sismo-protocol.git", 7 | "author": "leosayous21.sismo.eth ", 8 | "license": "MIT", 9 | "scripts": { 10 | "compile": "SKIP_LOAD=true hardhat compile", 11 | "test": "hardhat test", 12 | "prettier": "prettier --write 'contracts/**/*.sol'", 13 | "chain": "hardhat node", 14 | "storage-layout": "hardhat print-storage-layout", 15 | "deploy:local": "rm -rf deployments/local && hardhat deploy-full-local --network local" 16 | }, 17 | "devDependencies": { 18 | "@nomiclabs/hardhat-etherscan": "^3.0.1", 19 | "@nomiclabs/hardhat-waffle": "^2.0.2", 20 | "@typechain/hardhat": "^4.0.0", 21 | "@types/chai": "^4.3.0", 22 | "@types/jest": "^27.4.0", 23 | "@types/mocha": "^9.1.0", 24 | "chai": "^4.3.6", 25 | "concurrently": "^7.2.0", 26 | "dotenv": "^16.0.0", 27 | "prettier": "^2.5.1", 28 | "prettier-plugin-solidity": "^1.0.0-beta.19", 29 | "solhint": "^3.3.7", 30 | "solidity-coverage": "^0.7.19", 31 | "tslib": "^2.4.0" 32 | }, 33 | "husky": { 34 | "hooks": { 35 | "pre-commit": "pretty-quick --staged --pattern 'test/**/*.ts' --pattern 'tasks/**/*.ts' --pattern 'contracts/**/*.sol'" 36 | } 37 | }, 38 | "dependencies": { 39 | "@metamask/eth-sig-util": "^4.0.0", 40 | "@nomiclabs/hardhat-ethers": "^2.2.1", 41 | "@openzeppelin/contracts": "^4.5.0", 42 | "@openzeppelin/contracts-upgradeable": "^4.8.0", 43 | "@sismo-core/commitment-mapper-tester-js": "^1.0.11", 44 | "@sismo-core/hydra-s1": "^1.0.6", 45 | "@sismo-core/pythia-1": "^1.0.6", 46 | "@trufflesuite/eth-sig-util": "^1.4.2", 47 | "@typechain/ethers-v5": "^9.0.0", 48 | "@typescript-eslint/eslint-plugin": "^5.22.0", 49 | "@typescript-eslint/parser": "^5.22.0", 50 | "defender-relay-client": "^1.21.3", 51 | "eslint": "^8.14.0", 52 | "ethereum-waffle": "^3.4.0", 53 | "ethers": "^5.6.8", 54 | "fast-glob": "^3.2.11", 55 | "hardhat": "^2.9.7", 56 | "hardhat-deploy": "^0.11.22", 57 | "hardhat-gas-reporter": "^1.0.7", 58 | "hardhat-storage-layout": "^0.1.6", 59 | "husky": "4.2.5", 60 | "hydra-s1-previous": "npm:@sismo-core/hydra-s1@v1.0.5", 61 | "js-sha3": "^0.8.0", 62 | "mocha": "^10.0.0", 63 | "pretty-quick": "^3.1.3", 64 | "ts-node": "^10.5.0", 65 | "typechain": "^7.0.0", 66 | "typescript": "^4.5.5", 67 | "web3": "^1.7.1" 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /scripts/wait-for-local-chain.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | HOSTNAME=${LOCAL_HOSTNAME:-'localhost'} 5 | PORT=${LOCAL_PORT:-8545} 6 | while ! nc -z $HOSTNAME $PORT; do 7 | echo "Waiting for chain to be up ..." 8 | sleep 2 9 | done 10 | 11 | >&2 echo "Chain is up - executing command" 12 | exec "$@" 13 | -------------------------------------------------------------------------------- /tasks/addresses-provider/set-batch.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { AddressesProvider__factory } from '../../types'; 4 | import { CommonTaskOptions, wrapCommonOptions } from '../utils'; 5 | import { confirm } from '../utils/confirm'; 6 | import { deploymentsConfig } from '../../tasks/deploy-tasks/deployments-config'; 7 | 8 | export type SetBatchArgs = { 9 | contractAddressesAsString: string; 10 | contractNamesAsString: string; 11 | options?: CommonTaskOptions; 12 | }; 13 | 14 | async function action( 15 | { contractAddressesAsString, contractNamesAsString, options }: SetBatchArgs, 16 | hre: HardhatRuntimeEnvironment 17 | ): Promise { 18 | const [signer] = await hre.ethers.getSigners(); 19 | 20 | const config = deploymentsConfig[process.env.FORK_NETWORK ?? hre.network.name]; 21 | 22 | const contractAddresses = contractAddressesAsString.split(','); 23 | const contractNames = contractNamesAsString.split(','); 24 | 25 | const sismoAddressesProvider = AddressesProvider__factory.connect( 26 | config.sismoAddressesProvider.address, 27 | signer 28 | ); 29 | 30 | if (process.env.SET_BATCH_MANUAL_OPERATION === 'true') { 31 | console.log(` 32 | ************************************ 33 | * SET BATCH * 34 | ************************************`); 35 | 36 | if (options?.manualConfirm) { 37 | await confirm(); 38 | } 39 | 40 | // we can't connect as signer, we need manual operation 41 | const iface = new hre.ethers.utils.Interface(AddressesProvider__factory.abi); 42 | const data = iface.encodeFunctionData('setBatch', [contractAddresses, contractNames]); 43 | 44 | console.log({ 45 | from: await sismoAddressesProvider.owner(), 46 | to: sismoAddressesProvider.address, 47 | data: data, 48 | }); 49 | 50 | console.log('Send the transaction using etherscan !'); 51 | } else { 52 | console.log(` 53 | Aborting setBatch...`); 54 | } 55 | } 56 | 57 | task('set-batch') 58 | .addParam('contractAddressesAsString', 'Addresses of the contracts we want to set') 59 | .addParam('contractNamesAsString', 'Names of the contracts we want to set') 60 | .setAction(wrapCommonOptions(action)); 61 | -------------------------------------------------------------------------------- /tasks/available-roots-registry/register-for-attester.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { getDeployer } from '../deploy-tasks/utils'; 4 | 5 | import { AvailableRootsRegistry__factory } from '../../types'; 6 | import { manualConfirmValidity } from '../utils/confirm'; 7 | import { BigNumber, Signer } from 'ethers'; 8 | import { CommonTaskOptions, wrapCommonOptions } from '../utils'; 9 | import { getRelayerSigner } from '../utils/relayer'; 10 | 11 | export type RegisterForAttesterArgs = { 12 | root: string; 13 | attester: string; 14 | availableRootsRegistryAddress?: string; 15 | relayed?: boolean; 16 | options?: CommonTaskOptions; 17 | }; 18 | 19 | async function action( 20 | { root, attester, relayed, options, availableRootsRegistryAddress }: RegisterForAttesterArgs, 21 | hre: HardhatRuntimeEnvironment 22 | ): Promise { 23 | if (root === '0') { 24 | if (options?.log) { 25 | console.log(` 26 | root undefined for attester ${attester}. Not running the task. 27 | `); 28 | } 29 | return; 30 | } 31 | 32 | const signer = relayed ? await getRelayerSigner() : ((await getDeployer(hre)) as Signer); 33 | 34 | const availableRootsRegistry = AvailableRootsRegistry__factory.connect( 35 | availableRootsRegistryAddress || (await hre.deployments.get(`AvailableRootsRegistry`)).address, 36 | signer 37 | ); 38 | 39 | const isRootAlreadyRegistered = await availableRootsRegistry.isRootAvailableForAttester( 40 | attester, 41 | BigNumber.from(root) 42 | ); 43 | if (isRootAlreadyRegistered) { 44 | if (options?.log) { 45 | console.log(` 46 | Root: ${root} already registered for attester ${availableRootsRegistry.address}`); 47 | } 48 | return; 49 | } 50 | 51 | const actionRegisterRootForAttesterArgs = { 52 | availableRootsRegistry: availableRootsRegistry.address, 53 | root: root, 54 | attester, 55 | }; 56 | await manualConfirmValidity(actionRegisterRootForAttesterArgs, options); 57 | const tx = await availableRootsRegistry.registerRootForAttester( 58 | actionRegisterRootForAttesterArgs.attester, 59 | BigNumber.from(actionRegisterRootForAttesterArgs.root) 60 | ); 61 | await tx.wait(); 62 | } 63 | 64 | task('register-for-attester') 65 | .addParam('root', 'Root to update') 66 | .addParam('attester', 'Register for this Attester') 67 | .addOptionalParam('availableRootsRegistryAddress', 'Root to update') 68 | .addFlag('relayed', 'to use with relayer') 69 | .setAction(wrapCommonOptions(action)); 70 | -------------------------------------------------------------------------------- /tasks/available-roots-registry/unregister-for-attester.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { getDeployer } from '../deploy-tasks/utils'; 4 | 5 | import { AvailableRootsRegistry__factory } from '../../types'; 6 | import { manualConfirmValidity } from '../utils/confirm'; 7 | import { BigNumber, Signer } from 'ethers'; 8 | import { CommonTaskOptions, wrapCommonOptions } from '../utils'; 9 | import { getRelayerSigner } from '../utils/relayer'; 10 | 11 | export type UnregisterForAttesterArgs = { 12 | root: string; 13 | attester: string; 14 | availableRootsRegistryAddress?: string; 15 | relayed?: boolean; 16 | options?: CommonTaskOptions; 17 | }; 18 | 19 | async function action( 20 | { root, attester, relayed, options, availableRootsRegistryAddress }: UnregisterForAttesterArgs, 21 | hre: HardhatRuntimeEnvironment 22 | ): Promise { 23 | if (root === '0') { 24 | if (options?.log) { 25 | console.log(` 26 | root undefined for attester ${attester}. Not running the task. 27 | `); 28 | } 29 | return; 30 | } 31 | 32 | const signer = relayed ? await getRelayerSigner() : ((await getDeployer(hre)) as Signer); 33 | 34 | const availableRootsRegistry = AvailableRootsRegistry__factory.connect( 35 | availableRootsRegistryAddress || (await hre.deployments.get(`AvailableRootsRegistry`)).address, 36 | signer 37 | ); 38 | 39 | const isRootAlreadyRegistered = await availableRootsRegistry.isRootAvailableForAttester( 40 | attester, 41 | BigNumber.from(root) 42 | ); 43 | if (!isRootAlreadyRegistered) { 44 | if (options?.log) { 45 | console.log(` 46 | Root: ${root} already unregistered for attester ${availableRootsRegistry.address}`); 47 | } 48 | return; 49 | } 50 | 51 | const actionUnregisterRootForAttesterArgs = { 52 | availableRootsRegistry: availableRootsRegistry.address, 53 | root: root, 54 | attester, 55 | }; 56 | await manualConfirmValidity(actionUnregisterRootForAttesterArgs, options); 57 | const tx = await availableRootsRegistry.unregisterRootForAttester( 58 | actionUnregisterRootForAttesterArgs.attester, 59 | BigNumber.from(actionUnregisterRootForAttesterArgs.root) 60 | ); 61 | await tx.wait(); 62 | } 63 | 64 | task('unregister-for-attester') 65 | .addParam('root', 'Root to update') 66 | .addParam('attester', 'Register for this Attester') 67 | .addOptionalParam('availableRootsRegistryAddress', 'Root to update') 68 | .addFlag('relayed', 'to use with relayer') 69 | .setAction(wrapCommonOptions(action)); 70 | -------------------------------------------------------------------------------- /tasks/deploy-tasks/batch/deploy-core.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { AttestationsRegistry, Badges, Front } from '../../../types'; 4 | import { 5 | DeployedAttestationsRegistry, 6 | DeployAttestationsRegistryArgs, 7 | } from '../unit/core/deploy-attestations-registry.task'; 8 | import { DeployBadgesArgs, DeployedBadges } from '../unit/core/deploy-badges.task'; 9 | import { DeployOptions, wrapCommonDeployOptions } from '../utils'; 10 | import { DeployedFront, DeployFrontArgs } from '../unit/core/deploy-front.task'; 11 | import { AuthorizeRangeArgs } from 'tasks/helpers/authorizations/attestations-registry-authorize-range.task'; 12 | import { AccessControlGrantRoleArgs } from 'tasks/helpers/authorizations/access-control-grant-role.task'; 13 | 14 | export interface DeployedCore { 15 | attestationsRegistry: AttestationsRegistry; 16 | badges: Badges; 17 | front: Front; 18 | } 19 | 20 | export interface DeployCoreArgs { 21 | uri?: string; 22 | registryOwner?: string; 23 | badgeOwner?: string; 24 | frontFirstCollectionId: string; 25 | frontLastCollectionId: string; 26 | options?: DeployOptions; 27 | } 28 | 29 | async function deploymentAction( 30 | { 31 | uri, 32 | registryOwner, 33 | badgeOwner, 34 | frontFirstCollectionId, 35 | frontLastCollectionId, 36 | options, 37 | }: DeployCoreArgs, 38 | hre: HardhatRuntimeEnvironment 39 | ): Promise { 40 | if (options?.log) console.log('Deploying Core Contracts'); 41 | 42 | // Deployed ERC1155 Default Badge 43 | const { badges } = (await hre.run('deploy-badges', { 44 | uri, 45 | owner: badgeOwner, 46 | options, 47 | } as DeployBadgesArgs)) as DeployedBadges; 48 | 49 | // Deploy main contract Attestation Registry 50 | const { attestationsRegistry } = (await hre.run('deploy-attestations-registry', { 51 | owner: registryOwner, 52 | badges: badges.address, 53 | options, 54 | } as DeployAttestationsRegistryArgs)) as DeployedAttestationsRegistry; 55 | 56 | const registeredAttestationsRegistryInBadges = await badges.getAttestationsRegistry(); 57 | if (registeredAttestationsRegistryInBadges != attestationsRegistry.address) { 58 | await (await badges.setAttestationsRegistry(attestationsRegistry.address)).wait(); 59 | } 60 | 61 | const { front } = (await hre.run('deploy-front', { 62 | attestationsRegistryAddress: attestationsRegistry.address, 63 | badges: badges.address, 64 | options, 65 | } as DeployFrontArgs)) as DeployedFront; 66 | 67 | await hre.run('attestations-registry-authorize-range', { 68 | attestationsRegistryAddress: attestationsRegistry.address, 69 | attesterAddress: front.address, 70 | collectionIdFirst: frontFirstCollectionId, 71 | collectionIdLast: frontLastCollectionId, 72 | options, 73 | } as AuthorizeRangeArgs); 74 | 75 | await hre.run('access-control-grant-role', { 76 | contractAddress: badges.address, 77 | role: await badges.EVENT_TRIGGERER_ROLE(), 78 | accountAddress: attestationsRegistry.address, 79 | options, 80 | } as AccessControlGrantRoleArgs); 81 | 82 | if (options?.log) { 83 | console.log(` 84 | Deployed core contracts of the sismo protocol: 85 | attestationsRegistry: ${attestationsRegistry.address} 86 | badges: ${badges.address} 87 | front: ${front.address} 88 | `); 89 | } 90 | return { attestationsRegistry, badges, front }; 91 | } 92 | 93 | task('deploy-core') 94 | .addOptionalParam('uri', 'uri for the badges') 95 | .addOptionalParam('registryOwner', 'owner of the contracts') 96 | .addOptionalParam('badgeOwner', 'owner of the contracts') 97 | .addOptionalParam('frontFirstCollectionId', 'owner of the contracts') 98 | .addOptionalParam('frontLastCollectionId', 'owner of the contracts') 99 | .setAction(wrapCommonDeployOptions(deploymentAction)); 100 | -------------------------------------------------------------------------------- /tasks/deploy-tasks/full/1-deploy-pythia-1-simple.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { DeployOptions, getDeployer } from '../utils'; 4 | import { deploymentsConfig } from '../deployments-config'; 5 | import { getCommonOptions } from '../../utils/common-options'; 6 | import { AuthorizeRangeArgs } from '../../helpers/authorizations/attestations-registry-authorize-range.task'; 7 | import { Pythia1SimpleAttester } from 'types'; 8 | import { 9 | DeployedPythia1SimpleAttester, 10 | DeployPythia1SimpleAttesterArgs, 11 | } from 'tasks/deploy-tasks/unit/attesters/pythia-1/deploy-pythia-1-simple-attester.task'; 12 | import { Pythia1Verifier } from '@sismo-core/pythia-1'; 13 | 14 | export interface Deployed1 { 15 | pythia1SimpleAttester: Pythia1SimpleAttester; 16 | pythia1Verifier: Pythia1Verifier; 17 | } 18 | 19 | async function deploymentAction( 20 | { options }: { options: DeployOptions }, 21 | hre: HardhatRuntimeEnvironment 22 | ): Promise { 23 | const deployer = await getDeployer(hre); 24 | const config = deploymentsConfig[hre.network.name]; 25 | options = { ...config.deployOptions, ...options }; 26 | if (options.manualConfirm || options.log) { 27 | console.log('1-deploy-pythia-1-simple: ', hre.network.name); 28 | } 29 | 30 | const attestationsRegistry = await hre.deployments.get('AttestationsRegistry'); 31 | // Only deploy contracts without giving final ownership. 32 | // Owners of the different contract are the deployer 33 | const pythia1SimpleAttesterArgs: DeployPythia1SimpleAttesterArgs = { 34 | collectionIdFirst: config.synapsPythia1SimpleAttester.collectionIdFirst, 35 | collectionIdLast: config.synapsPythia1SimpleAttester.collectionIdLast, 36 | attestationsRegistryAddress: attestationsRegistry.address, 37 | commitmentSignerPubKeyX: config.synapsPythia1SimpleAttester.commitmentSignerPubKeyX, 38 | commitmentSignerPubKeyY: config.synapsPythia1SimpleAttester.commitmentSignerPubKeyY, 39 | owner: config.synapsPythia1SimpleAttester.owner, 40 | options, 41 | }; 42 | 43 | const { pythia1SimpleAttester, pythia1Verifier } = (await hre.run( 44 | 'deploy-pythia-1-simple-attester', 45 | pythia1SimpleAttesterArgs 46 | )) as DeployedPythia1SimpleAttester; 47 | 48 | // Give to the attester the authorization to write on the attestations Registry 49 | if (options.manualConfirm || options.log) { 50 | console.log(` 51 | ---------------------------------------------------------------- 52 | * Authorize Pythia1SimpleAttester to record on the AttestationsRegistry`); 53 | } 54 | await hre.run('attestations-registry-authorize-range', { 55 | attestationsRegistryAddress: attestationsRegistry.address, 56 | attesterAddress: pythia1SimpleAttester.address, 57 | collectionIdFirst: config.synapsPythia1SimpleAttester.collectionIdFirst, 58 | collectionIdLast: config.synapsPythia1SimpleAttester.collectionIdLast, 59 | options: getCommonOptions(options), 60 | } as AuthorizeRangeArgs); 61 | 62 | if (options.manualConfirm || options.log) { 63 | console.log(` 64 | ************************************************************ 65 | * RECAP * 66 | ************************************************************ 67 | 68 | date: ${new Date().toISOString()} 69 | 70 | ** Common ** 71 | proxyAdmin: ${config.deployOptions.proxyAdmin} 72 | 73 | * Pythia1SimpleAttester: 74 | -> proxy: ${(await hre.deployments.all()).Pythia1SimpleAttester.address} 75 | -> implem: ${(await hre.deployments.all()).Pythia1SimpleAttesterImplem.address} 76 | collectionIdFirst: ${config.synapsPythia1SimpleAttester.collectionIdFirst} 77 | collectionIdLast: ${config.synapsPythia1SimpleAttester.collectionIdLast} 78 | commitmentSignerPubKeyX: ${config.synapsPythia1SimpleAttester.commitmentSignerPubKeyX} 79 | commitmentSignerPubKeyY: ${config.synapsPythia1SimpleAttester.commitmentSignerPubKeyY} 80 | 81 | * Pythia1Verifier: 82 | -> address: ${(await hre.deployments.all()).Pythia1Verifier.address} 83 | `); 84 | } 85 | 86 | return { 87 | pythia1SimpleAttester, 88 | pythia1Verifier, 89 | }; 90 | } 91 | 92 | task('1-deploy-pythia-1-simple').setAction(deploymentAction); 93 | -------------------------------------------------------------------------------- /tasks/deploy-tasks/full/3-new-hydra-s1-verifier-and-upgrade-hydra-s1-simple-proxy.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { DeployOptions, getDeployer } from '../utils'; 4 | import { HydraS1AccountboundAttester, HydraS1Verifier } from 'types'; 5 | import { DeployedHydraS1AccountboundAttester } from 'tasks/deploy-tasks/unit/attesters/hydra-s1/deploy-hydra-s1-accountbound-attester.task'; 6 | import { deploymentsConfig } from '../deployments-config'; 7 | 8 | export interface Deployed3 { 9 | hydraS1Verifier: HydraS1Verifier; 10 | hydraS1AccountboundAttester: HydraS1AccountboundAttester; 11 | } 12 | 13 | async function deploymentAction( 14 | { options }: { options: DeployOptions }, 15 | hre: HardhatRuntimeEnvironment 16 | ): Promise { 17 | const config = deploymentsConfig[process.env.FORK_NETWORK ?? hre.network.name]; 18 | options = { ...config.deployOptions, ...options }; 19 | 20 | if (options.manualConfirm || options.log) { 21 | console.log('3-new-hydra-s1-verifier-and-upgrade-accountbound-proxy: ', hre.network.name); 22 | } 23 | 24 | // The following proxies will be updated: 25 | // - HydraS1Verifier => rename ticket in nullifier 26 | // - HydraS1SimpleAttester implementation will be replaced by the HydraS1AccountboundAttester implementation => cooldown duration removed from groupProperties + inherits from HydraS1SimpleAttester 27 | // => + reinitializer modifier added and version as constant 28 | 29 | // Upgrade HydraS1Verifier 30 | const { hydraS1Verifier: newHydraS1Verifier } = await hre.run('deploy-hydra-s1-verifier', { 31 | options, 32 | }); 33 | 34 | // Upgrade proxy implementation from HydraS1SimpleAttester to HydraS1AccountboundAttester 35 | const { hydraS1AccountboundAttester: newHydraS1AccountboundAttester } = (await hre.run( 36 | 'deploy-hydra-s1-accountbound-attester', 37 | { 38 | // the collectionIds referenced are the ones used by the previous HydraS1SimpleAttester 39 | collectionIdFirst: config.hydraS1AccountboundAttester.collectionIdFirst, 40 | collectionIdLast: config.hydraS1AccountboundAttester.collectionIdLast, 41 | commitmentMapperRegistryAddress: config.commitmentMapper.address, 42 | availableRootsRegistryAddress: config.availableRootsRegistry.address, 43 | attestationsRegistryAddress: config.attestationsRegistry.address, 44 | hydraS1VerifierAddress: newHydraS1Verifier.address, // reference the new hydraS1Verifier address 45 | owner: config.hydraS1AccountboundAttester.owner, // set the owner referenced in the config 46 | options: { 47 | ...options, 48 | isImplementationUpgrade: true, 49 | proxyAddress: config.hydraS1AccountboundAttester.address, // the address referenced here is the old address of the hydraS1SimpleAttester 50 | }, 51 | } 52 | )) as DeployedHydraS1AccountboundAttester; 53 | 54 | return { 55 | hydraS1Verifier: newHydraS1Verifier, 56 | hydraS1AccountboundAttester: newHydraS1AccountboundAttester, 57 | }; 58 | } 59 | 60 | task('3-new-hydra-s1-verifier-and-upgrade-hydra-s1-simple-proxy').setAction(deploymentAction); 61 | -------------------------------------------------------------------------------- /tasks/deploy-tasks/full/4-upgrade-attestations-registry-proxy-and-badges-proxy.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { DeployOptions, getDeployer } from '../utils'; 4 | import { AttestationsRegistry, Badges } from 'types'; 5 | import { DeployedAttestationsRegistry } from 'tasks/deploy-tasks/unit/core/deploy-attestations-registry.task'; 6 | import { deploymentsConfig } from '../deployments-config'; 7 | import { DeployedBadges } from 'tasks/deploy-tasks/unit/core/deploy-badges.task'; 8 | 9 | export interface Deployed4 { 10 | attestationsRegistry: AttestationsRegistry; 11 | badges: Badges; 12 | } 13 | 14 | async function deploymentAction( 15 | { options }: { options: DeployOptions }, 16 | hre: HardhatRuntimeEnvironment 17 | ): Promise { 18 | const config = deploymentsConfig[process.env.FORK_NETWORK ?? hre.network.name]; 19 | options = { ...config.deployOptions, ...options }; 20 | 21 | if (options.manualConfirm || options.log) { 22 | console.log('4-upgrade-attestations-registry-proxy: ', hre.network.name); 23 | } 24 | 25 | // The following proxy will be updated: 26 | // - AttestationRegistry => introduce attributes names and values for attestationsCollection 27 | // values go from 0 to 15, if the value is 0 the attribute is disabled, else it is enabled with the value set 28 | // + reinitializer modifier added and version as constant 29 | // - Badges => add getters for attestations issuer, timestamp and extradata 30 | // => add getters for attribute values and names 31 | // => + reinitializer modifier added and version as constant 32 | 33 | // Upgrade attestations registry 34 | const { attestationsRegistry: newAttestationsRegistry } = (await hre.run( 35 | 'deploy-attestations-registry', 36 | { 37 | badges: config.badges.address, 38 | owner: config.attestationsRegistry.owner, 39 | options: { 40 | ...options, 41 | isImplementationUpgrade: true, // implementation version has been bumped from v2 to v3 42 | proxyAddress: config.attestationsRegistry.address, 43 | }, 44 | } 45 | )) as DeployedAttestationsRegistry; 46 | 47 | // Upgrade Badges 48 | const { badges: newBadges } = (await hre.run('deploy-badges', { 49 | uri: config.badges.uri, 50 | owner: config.badges.owner, 51 | options: { 52 | ...options, 53 | isImplementationUpgrade: true, // implementation version has been bumped from v2 to v3 54 | proxyAddress: config.badges.address, 55 | }, 56 | })) as DeployedBadges; 57 | 58 | return { 59 | attestationsRegistry: newAttestationsRegistry, 60 | badges: newBadges, 61 | }; 62 | } 63 | 64 | task('4-upgrade-attestations-registry-proxy-and-badges-proxy').setAction(deploymentAction); 65 | -------------------------------------------------------------------------------- /tasks/deploy-tasks/full/5-upgrade-proxies-with-reinitializer.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { DeployOptions, getDeployer } from '../utils'; 4 | import { 5 | AvailableRootsRegistry, 6 | Badges, 7 | CommitmentMapperRegistry, 8 | Pythia1SimpleAttester, 9 | } from 'types'; 10 | import { deploymentsConfig } from '../deployments-config'; 11 | import { DeployedPythia1SimpleAttester } from 'tasks/deploy-tasks/unit/attesters/pythia-1/deploy-pythia-1-simple-attester.task'; 12 | import { DeployedAvailableRootsRegistry } from 'tasks/deploy-tasks/unit/periphery/deploy-available-roots-registry.task'; 13 | import { DeployedCommitmentMapper } from 'tasks/deploy-tasks/unit/periphery/deploy-commitment-mapper-registry.task'; 14 | 15 | export interface Deployed5 { 16 | pythia1SimpleAttester: Pythia1SimpleAttester; 17 | availableRootsRegistry: AvailableRootsRegistry; 18 | commitmentMapperRegistry: CommitmentMapperRegistry; 19 | } 20 | 21 | async function deploymentAction( 22 | { options }: { options: DeployOptions }, 23 | hre: HardhatRuntimeEnvironment 24 | ): Promise { 25 | const config = deploymentsConfig[process.env.FORK_NETWORK ?? hre.network.name]; 26 | options = { ...config.deployOptions, ...options }; 27 | 28 | if (options.manualConfirm || options.log) { 29 | console.log('4-upgrade-attestations-registry-proxy: ', hre.network.name); 30 | } 31 | 32 | // The following proxies will be updated: 33 | // - Pythia1SimpleAttester => reinitializer modifier added and version as constant 34 | // - AvailableRootsRegistry => reinitializer modifier added and version as constant 35 | // - CommitmentMapperRegistry => reinitializer modifier added and version as constant 36 | 37 | // Upgrade pythia1SimpleAttester 38 | const { pythia1SimpleAttester: newPythia1SimpleAttester } = (await hre.run( 39 | 'deploy-pythia-1-simple-attester', 40 | { 41 | collectionIdFirst: config.synapsPythia1SimpleAttester.collectionIdFirst, 42 | collectionIdLast: config.synapsPythia1SimpleAttester.collectionIdLast, 43 | attestationsRegistryAddress: config.attestationsRegistry.address, 44 | commitmentSignerPubKeyX: config.synapsPythia1SimpleAttester.commitmentSignerPubKeyX, 45 | commitmentSignerPubKeyY: config.synapsPythia1SimpleAttester.commitmentSignerPubKeyY, 46 | owner: config.synapsPythia1SimpleAttester.owner, 47 | options: { 48 | ...options, 49 | isImplementationUpgrade: true, // implementation version has been bumped from v2 to v3 50 | proxyAddress: config.synapsPythia1SimpleAttester.address, 51 | }, 52 | } 53 | )) as DeployedPythia1SimpleAttester; 54 | 55 | // Upgrade AvailableRootsRegistry 56 | const { availableRootsRegistry: newAvailableRootsRegistry } = (await hre.run( 57 | 'deploy-available-roots-registry', 58 | { 59 | owner: config.availableRootsRegistry.owner, 60 | options: { 61 | ...options, 62 | isImplementationUpgrade: true, // implementation version has been bumped from v1 to v2 63 | proxyAddress: config.availableRootsRegistry.address, 64 | }, 65 | } 66 | )) as DeployedAvailableRootsRegistry; 67 | 68 | // Upgrade CommitmentMapperRegistry 69 | const { commitmentMapperRegistry: newCommitmentMapperRegistry } = (await hre.run( 70 | 'deploy-commitment-mapper-registry', 71 | { 72 | commitmentMapperPubKeyX: config.commitmentMapper.EdDSAPubKeyX, 73 | commitmentMapperPubKeyY: config.commitmentMapper.EdDSAPubKeyY, 74 | owner: config.commitmentMapper.owner, 75 | options: { 76 | ...options, 77 | isImplementationUpgrade: true, // implementation version has been bumped from v1 to v2 78 | proxyAddress: config.commitmentMapper.address, 79 | }, 80 | } 81 | )) as DeployedCommitmentMapper; 82 | 83 | return { 84 | pythia1SimpleAttester: newPythia1SimpleAttester, 85 | availableRootsRegistry: newAvailableRootsRegistry, 86 | commitmentMapperRegistry: newCommitmentMapperRegistry, 87 | }; 88 | } 89 | 90 | task('5-upgrade-proxies-with-reinitializer').setAction(deploymentAction); 91 | -------------------------------------------------------------------------------- /tasks/deploy-tasks/full/6-deploy-sismo-addresses-provider.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { DeployOptions } from '../utils'; 4 | import { deploymentsConfig } from '../deployments-config'; 5 | import { DeployedSismoAddressesProvider } from 'tasks/deploy-tasks/unit/core/deploy-sismo-addresses-provider.task'; 6 | import { AddressesProvider } from 'types'; 7 | 8 | export interface Deployed6 { 9 | sismoAddressesProvider: AddressesProvider; 10 | } 11 | 12 | async function deploymentAction( 13 | { options }: { options: DeployOptions }, 14 | hre: HardhatRuntimeEnvironment 15 | ): Promise { 16 | const config = deploymentsConfig[process.env.FORK_NETWORK ?? hre.network.name]; 17 | options = { ...config.deployOptions, ...options }; 18 | 19 | if (options.manualConfirm || options.log) { 20 | console.log('6-deploy-sismo-addresses-provider: ', hre.network.name); 21 | } 22 | 23 | // Deploy SismoAddressesProvider 24 | const { sismoAddressesProvider } = (await hre.run('deploy-sismo-addresses-provider', { 25 | owner: config.sismoAddressesProvider.owner, 26 | badges: config.badges.address, 27 | attestationsRegistry: config.attestationsRegistry.address, 28 | front: config.front.address, 29 | hydraS1AccountboundAttester: config.hydraS1AccountboundAttester.address, 30 | commitmentMapperRegistry: config.commitmentMapper.address, 31 | availableRootsRegistry: config.availableRootsRegistry.address, 32 | hydraS1Verifier: config.hydraS1Verifier.address, 33 | options: { ...options, proxyAdmin: config.deployOptions.proxyAdmin }, 34 | })) as DeployedSismoAddressesProvider; 35 | 36 | return { 37 | sismoAddressesProvider, 38 | }; 39 | } 40 | 41 | task('6-deploy-sismo-addresses-provider').setAction(deploymentAction); 42 | -------------------------------------------------------------------------------- /tasks/deploy-tasks/full/7-upgrade-hydra-s1-accountbound-and-pythia-1-proxies.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { DeployOptions } from '../utils'; 4 | import { deploymentsConfig } from '../deployments-config'; 5 | import { DeployedHydraS1AccountboundAttester } from 'tasks/deploy-tasks/unit/attesters/hydra-s1/deploy-hydra-s1-accountbound-attester.task'; 6 | import { DeployedPythia1SimpleAttester } from 'tasks/deploy-tasks/unit/attesters/pythia-1/deploy-pythia-1-simple-attester.task'; 7 | import { HydraS1AccountboundAttester, Pythia1SimpleAttester } from 'types'; 8 | 9 | export interface Deployed7 { 10 | hydraS1AccountboundAttester: HydraS1AccountboundAttester; 11 | pythia1SimpleAttester: Pythia1SimpleAttester; 12 | } 13 | 14 | async function deploymentAction( 15 | { options }: { options: DeployOptions }, 16 | hre: HardhatRuntimeEnvironment 17 | ): Promise { 18 | const config = deploymentsConfig[process.env.FORK_NETWORK ?? hre.network.name]; 19 | options = { ...config.deployOptions, ...options }; 20 | 21 | if (options.manualConfirm || options.log) { 22 | console.log('7-upgrade-hydra-s1-accountbound-and-pythia-1-proxies: ', hre.network.name); 23 | } 24 | 25 | // Upgrade HydraS1AccountboundAttester 26 | const { hydraS1AccountboundAttester: newHydraS1AccountboundAttester } = (await hre.run( 27 | 'deploy-hydra-s1-accountbound-attester', 28 | { 29 | // the collectionIds referenced are the ones used by the previous HydraS1SimpleAttester 30 | collectionIdFirst: config.hydraS1AccountboundAttester.collectionIdFirst, 31 | collectionIdLast: config.hydraS1AccountboundAttester.collectionIdLast, 32 | commitmentMapperRegistryAddress: config.commitmentMapper.address, 33 | availableRootsRegistryAddress: config.availableRootsRegistry.address, 34 | attestationsRegistryAddress: config.attestationsRegistry.address, 35 | hydraS1VerifierAddress: config.hydraS1Verifier.address, 36 | owner: config.hydraS1AccountboundAttester.owner, 37 | options: { 38 | ...options, 39 | isImplementationUpgrade: true, 40 | proxyAddress: config.hydraS1AccountboundAttester.address, 41 | }, 42 | } 43 | )) as DeployedHydraS1AccountboundAttester; 44 | 45 | // Upgrade Pythia1SimpleAttester 46 | const { pythia1SimpleAttester: newPythia1SimpleAttester } = (await hre.run( 47 | 'deploy-pythia-1-simple-attester', 48 | { 49 | collectionIdFirst: config.synapsPythia1SimpleAttester.collectionIdFirst, 50 | collectionIdLast: config.synapsPythia1SimpleAttester.collectionIdLast, 51 | attestationsRegistryAddress: config.attestationsRegistry.address, 52 | commitmentSignerPubKeyX: config.synapsPythia1SimpleAttester.commitmentSignerPubKeyX, 53 | commitmentSignerPubKeyY: config.synapsPythia1SimpleAttester.commitmentSignerPubKeyY, 54 | pythia1VerifierAddress: config.pythia1Verifier.address, 55 | owner: config.synapsPythia1SimpleAttester.owner, 56 | options: { 57 | ...options, 58 | isImplementationUpgrade: true, 59 | proxyAddress: config.synapsPythia1SimpleAttester.address, 60 | }, 61 | } 62 | )) as DeployedPythia1SimpleAttester; 63 | 64 | return { 65 | hydraS1AccountboundAttester: newHydraS1AccountboundAttester, 66 | pythia1SimpleAttester: newPythia1SimpleAttester, 67 | }; 68 | } 69 | 70 | task('7-upgrade-hydra-s1-accountbound-and-pythia-1-proxies').setAction(deploymentAction); 71 | -------------------------------------------------------------------------------- /tasks/deploy-tasks/full/9-upgrade-addresses-provider-on-testnets.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { 4 | afterDeployment, 5 | beforeDeployment, 6 | buildDeploymentName, 7 | customDeployContract, 8 | DeployOptions, 9 | getDeployer, 10 | } from '../utils'; 11 | import { deploymentsConfig } from '../deployments-config'; 12 | import { 13 | AddressesProvider, 14 | AddressesProvider__factory, 15 | TransparentUpgradeableProxy__factory, 16 | } from '../../../types'; 17 | import { confirm } from '../../../tasks/utils'; 18 | 19 | export interface Deployed9 { 20 | sismoAddressesProvider: AddressesProvider; 21 | } 22 | 23 | async function deploymentAction( 24 | { options }: { options: DeployOptions }, 25 | hre: HardhatRuntimeEnvironment 26 | ): Promise { 27 | const config = deploymentsConfig[process.env.FORK_NETWORK ?? hre.network.name]; 28 | 29 | // we need to use the proxyAdmins of staging since we deployed addressesProvider create2 on staging 30 | let badNetwork: string; 31 | let deploymentNetwork = process.env.FORK_NETWORK ?? hre.network.name; 32 | if (deploymentNetwork === 'goerliTestnet') { 33 | badNetwork = 'goerliStaging'; 34 | } else if (deploymentNetwork === 'mumbaiTestnet') { 35 | badNetwork = 'mumbaiStaging'; 36 | } else { 37 | throw new Error('Invalid network'); 38 | } 39 | 40 | options = { 41 | isImplementationUpgrade: true, 42 | proxyAddress: config.sismoAddressesProvider.address, 43 | ...config.deployOptions, 44 | ...options, 45 | }; 46 | 47 | if (options.manualConfirm || options.log) { 48 | console.log('9-upgrade-addresses-provider-on-testnets: ', hre.network.name); 49 | } 50 | const CONTRACT_NAME = 'AddressesProvider'; 51 | 52 | // Deploy SismoAddressesProvider 53 | const deployer = await getDeployer(hre); 54 | const deploymentName = buildDeploymentName(CONTRACT_NAME, options?.deploymentNamePrefix); 55 | 56 | const proxyAdmin = deploymentsConfig[badNetwork].deployOptions.proxyAdmin; // we need to use the proxyAdmins of staging since we deployed addressesProvider create2 on staging 57 | 58 | const deploymentArgs = [ 59 | config.badges.address, 60 | config.attestationsRegistry.address, 61 | config.front.address, 62 | config.hydraS1AccountboundAttester.address, 63 | config.availableRootsRegistry.address, 64 | config.commitmentMapper.address, 65 | config.hydraS1Verifier.address, 66 | config.sismoAddressesProvider.owner, 67 | ]; 68 | 69 | const initData = new AddressesProvider__factory().interface.encodeFunctionData('initialize', [ 70 | config.sismoAddressesProvider.owner, 71 | ]); 72 | 73 | await beforeDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, options); 74 | const deployed = await customDeployContract( 75 | hre, 76 | deployer, 77 | deploymentName, 78 | CONTRACT_NAME, 79 | deploymentArgs, 80 | { 81 | ...options, 82 | proxyData: initData, 83 | isImplementationUpgrade: true, // implementation version has been bumped from v1 to v2 84 | proxyAddress: config.sismoAddressesProvider.address, 85 | proxyAdmin, 86 | } 87 | ); 88 | await afterDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, deployed, options); 89 | 90 | const sismoAddressesProvider = AddressesProvider__factory.connect( 91 | deployed.address, 92 | await hre.ethers.getSigner(deploymentsConfig[badNetwork].sismoAddressesProvider.owner as string) 93 | ); 94 | 95 | return { 96 | sismoAddressesProvider, 97 | }; 98 | } 99 | 100 | task('9-upgrade-addresses-provider-on-testnets').setAction(deploymentAction); 101 | -------------------------------------------------------------------------------- /tasks/deploy-tasks/full/staging/deploy-sismo-addresses-provider-staging.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { 4 | afterDeployment, 5 | beforeDeployment, 6 | buildDeploymentName, 7 | customDeployContract, 8 | DeployOptions, 9 | getDeployer, 10 | } from '../../utils'; 11 | import { deploymentsConfig } from '../../deployments-config'; 12 | import { AddressesProvider__factory } from '../../../../types'; 13 | 14 | const CONTRACT_NAME = 'AddressesProvider'; 15 | 16 | async function deploymentAction( 17 | { options }: { options: DeployOptions }, 18 | hre: HardhatRuntimeEnvironment 19 | ) { 20 | const config = deploymentsConfig[hre.network.name]; 21 | options = { ...config.deployOptions, ...options }; 22 | 23 | const deployer = await getDeployer(hre); 24 | const deploymentName = 'AddressesProviderStaging'; 25 | 26 | // always start by giving the ownership of the deployer 27 | const deploymentArgs = [ 28 | config.badges.address, // badges, 29 | config.attestationsRegistry.address, // attestationsRegistry, 30 | config.front.address, // front, 31 | config.hydraS1AccountboundAttester.address, // hydraS1AccountboundAttester, 32 | config.availableRootsRegistry.address, // availableRootsRegistry, 33 | config.commitmentMapper.address, // commitmentMapperRegistry, 34 | config.hydraS1Verifier.address, // hydraS1Verifier, 35 | config.sismoAddressesProvider.owner, // deployer.address, 36 | ]; 37 | 38 | await beforeDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, options); 39 | 40 | const initData = new AddressesProvider__factory().interface.encodeFunctionData('initialize', [ 41 | config.sismoAddressesProvider.owner, 42 | ]); 43 | 44 | const deployed = await customDeployContract( 45 | hre, 46 | deployer, 47 | deploymentName, 48 | CONTRACT_NAME, 49 | deploymentArgs, 50 | { 51 | ...options, 52 | proxyData: initData, 53 | } 54 | ); 55 | await afterDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, deployed, options); 56 | 57 | if (options.manualConfirm || options.log) { 58 | console.log(` 59 | ************************************************************ 60 | * RECAP * 61 | ************************************************************ 62 | 63 | date: ${new Date().toISOString()} 64 | 65 | ** Common ** 66 | proxyAdmin: ${config.deployOptions.proxyAdmin} 67 | 68 | * AddressesProviderStaging: 69 | -> address: ${(await hre.deployments.all()).AddressesProviderStaging.address} 70 | `); 71 | } 72 | } 73 | 74 | task('deploy-sismo-addresses-provider-staging').setAction(deploymentAction); 75 | -------------------------------------------------------------------------------- /tasks/deploy-tasks/tests/deploy-mock-attestations-registry.task.ts: -------------------------------------------------------------------------------- 1 | import { BigNumberish } from 'ethers'; 2 | import { task } from 'hardhat/config'; 3 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 4 | import { MockAttestationsRegistry, MockAttestationsRegistry__factory } from '../../../types'; 5 | import { 6 | afterDeployment, 7 | beforeDeployment, 8 | buildDeploymentName, 9 | customDeployContract, 10 | DeployOptions, 11 | getDeployer, 12 | wrapCommonDeployOptions, 13 | } from '../utils'; 14 | 15 | export interface DeployMockAttestationsRegistryArgs { 16 | attestationValue: BigNumberish; 17 | options?: DeployOptions; 18 | } 19 | 20 | export interface DeployedMockAttestationsRegistry { 21 | mockAttestationsRegistry: MockAttestationsRegistry; 22 | } 23 | 24 | const CONTRACT_NAME = 'MockAttestationsRegistry'; 25 | 26 | async function deploymentAction( 27 | { attestationValue, options }: DeployMockAttestationsRegistryArgs, 28 | hre: HardhatRuntimeEnvironment 29 | ) { 30 | const deployer = await getDeployer(hre); 31 | const deploymentName = buildDeploymentName(CONTRACT_NAME, options?.deploymentNamePrefix); 32 | const deploymentArgs = [attestationValue || 0]; 33 | 34 | await beforeDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, options); 35 | 36 | const deployed = await customDeployContract( 37 | hre, 38 | deployer, 39 | deploymentName, 40 | CONTRACT_NAME, 41 | deploymentArgs, 42 | options 43 | ); 44 | 45 | await afterDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, deployed, options); 46 | const mockAttestationsRegistry = MockAttestationsRegistry__factory.connect( 47 | deployed.address, 48 | deployer 49 | ); 50 | return { mockAttestationsRegistry }; 51 | } 52 | 53 | task('deploy-mock-attestations-registry').setAction(wrapCommonDeployOptions(deploymentAction)); 54 | -------------------------------------------------------------------------------- /tasks/deploy-tasks/tests/deploy-mock-attester-and-core.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { 4 | DeployOptions, 5 | getDeployer, 6 | wrapCommonDeployOptions, 7 | } from '../../../tasks/deploy-tasks/utils'; 8 | import { DeployCoreArgs, DeployedCore } from '../batch/deploy-core.task'; 9 | import { DeployedMockAttester, DeployMockAttesterArgs } from './deploy-mock-attester.task'; 10 | 11 | export type DeployMockAttesterAndCoreArgs = Omit< 12 | DeployMockAttesterArgs & DeployCoreArgs & DeployOptions, 13 | 'attestationsRegistryAddress' | '' 14 | >; 15 | 16 | export interface DeployedMockAttesterAndCore extends DeployedMockAttester, DeployedCore {} 17 | 18 | async function deploymentAction( 19 | options: DeployMockAttesterAndCoreArgs, 20 | hre: HardhatRuntimeEnvironment 21 | ): Promise { 22 | if (options?.log) { 23 | console.log('Deploying ALL on network: ', hre.network.name); 24 | } 25 | 26 | const deployer = await getDeployer(hre); 27 | 28 | const deployedCore = (await hre.run('deploy-core', { 29 | uri: options.uri, 30 | badgeOwner: options.badgeOwner, 31 | registryOwner: options.registryOwner, 32 | frontFirstCollectionId: options.frontLastCollectionId, 33 | frontLastCollectionId: options.frontLastCollectionId, 34 | options: options.options, 35 | } as DeployCoreArgs)) as DeployedCore; 36 | 37 | const deployedMockAttester = (await hre.run('deploy-mock-attester', { 38 | attestationsRegistryAddress: deployedCore.attestationsRegistry.address, 39 | collectionIdFirst: options.collectionIdFirst, 40 | collectionIdLast: options.collectionIdLast, 41 | options: options.options, 42 | } as DeployMockAttesterArgs)) as DeployedMockAttester; 43 | 44 | // Authorize Mock attester to record attestation on the attestationsRegistry 45 | // for its corresponding min and max 46 | if (options?.log) { 47 | console.log('Authorize Mock on the attestationsRegistry'); 48 | } 49 | 50 | await deployedCore.attestationsRegistry 51 | .connect(deployer) 52 | .authorizeRange( 53 | deployedCore.front.address, 54 | await deployedCore.front.EARLY_USER_COLLECTION(), 55 | await deployedCore.front.EARLY_USER_COLLECTION() 56 | ); 57 | 58 | await deployedCore.attestationsRegistry 59 | .connect(deployer) 60 | .authorizeRange( 61 | deployedMockAttester.mockAttester.address, 62 | await deployedMockAttester.mockAttester.ATTESTATION_ID_MIN(), 63 | await deployedMockAttester.mockAttester.ATTESTATION_ID_MAX() 64 | ); 65 | 66 | return { ...deployedCore, ...deployedMockAttester }; 67 | } 68 | 69 | task('deploy-mock-attester-and-core').setAction(wrapCommonDeployOptions(deploymentAction)); 70 | -------------------------------------------------------------------------------- /tasks/deploy-tasks/tests/deploy-mock-attester.task.ts: -------------------------------------------------------------------------------- 1 | import { BigNumber, BigNumberish } from 'ethers'; 2 | import { task } from 'hardhat/config'; 3 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 4 | import { 5 | afterDeployment, 6 | beforeDeployment, 7 | buildDeploymentName, 8 | customDeployContract, 9 | DeployOptions, 10 | getDeployer, 11 | wrapCommonDeployOptions, 12 | } from '../../../tasks/deploy-tasks/utils'; 13 | import { MockAttester, MockAttester__factory } from '../../../types'; 14 | 15 | export interface DeployMockAttesterArgs { 16 | // address of the attestations Registry contract 17 | attestationsRegistryAddress: string; 18 | collectionIdFirst: BigNumberish; 19 | collectionIdLast: BigNumberish; 20 | options?: DeployOptions; 21 | } 22 | 23 | export interface DeployedMockAttester { 24 | mockAttester: MockAttester; 25 | } 26 | 27 | const CONTRACT_NAME = 'MockAttester'; 28 | 29 | async function deploymentAction( 30 | { 31 | attestationsRegistryAddress, 32 | collectionIdFirst, 33 | collectionIdLast, 34 | options, 35 | }: DeployMockAttesterArgs, 36 | hre: HardhatRuntimeEnvironment 37 | ): Promise { 38 | const deployer = await getDeployer(hre); 39 | 40 | const deploymentName = buildDeploymentName(CONTRACT_NAME, options?.deploymentNamePrefix); 41 | 42 | const deploymentArgs = [ 43 | attestationsRegistryAddress, 44 | BigNumber.from(collectionIdFirst), 45 | BigNumber.from(collectionIdLast), 46 | ]; 47 | 48 | await beforeDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, options); 49 | 50 | const deployed = await customDeployContract( 51 | hre, 52 | deployer, 53 | deploymentName, 54 | CONTRACT_NAME, 55 | deploymentArgs, 56 | options 57 | ); 58 | 59 | await afterDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, deployed, options); 60 | const mockAttester = MockAttester__factory.connect(deployed.address, deployer); 61 | return { mockAttester }; 62 | } 63 | 64 | task('deploy-mock-attester') 65 | .addParam('attestationsRegistryAddress', 'Address of the attestations contract') 66 | .addOptionalParam('collectionIdFirst', '') 67 | .addOptionalParam('collectionIdLast', '') 68 | .setAction(wrapCommonDeployOptions(deploymentAction)); 69 | -------------------------------------------------------------------------------- /tasks/deploy-tasks/tests/deploy-mock-contract-using-sismo-lib.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { 4 | afterDeployment, 5 | beforeDeployment, 6 | buildDeploymentName, 7 | customDeployContract, 8 | DeployOptions, 9 | getDeployer, 10 | wrapCommonDeployOptions, 11 | } from '../../../tasks/deploy-tasks/utils'; 12 | import { MockContractUsingSismoLib, MockContractUsingSismoLib__factory } from '../../../types'; 13 | 14 | export interface DeployMockContractUsingSismoLibArgs { 15 | options?: DeployOptions; 16 | } 17 | 18 | export interface DeployedMockContractUsingSismoLib { 19 | mockContractUsingSismoLib: MockContractUsingSismoLib; 20 | } 21 | 22 | const CONTRACT_NAME = 'MockContractUsingSismoLib'; 23 | 24 | async function deploymentAction( 25 | { options }: DeployMockContractUsingSismoLibArgs, 26 | hre: HardhatRuntimeEnvironment 27 | ): Promise { 28 | const deployer = await getDeployer(hre); 29 | 30 | const deploymentName = buildDeploymentName(CONTRACT_NAME, options?.deploymentNamePrefix); 31 | 32 | const deploymentArgs = []; 33 | 34 | await beforeDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, options); 35 | 36 | const deployed = await customDeployContract( 37 | hre, 38 | deployer, 39 | deploymentName, 40 | CONTRACT_NAME, 41 | deploymentArgs, 42 | options 43 | ); 44 | 45 | await afterDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, deployed, options); 46 | const mockContractUsingSismoLib = MockContractUsingSismoLib__factory.connect( 47 | deployed.address, 48 | deployer 49 | ); 50 | 51 | return { mockContractUsingSismoLib }; 52 | } 53 | 54 | task('deploy-mock-contract-using-sismo-lib').setAction(wrapCommonDeployOptions(deploymentAction)); 55 | -------------------------------------------------------------------------------- /tasks/deploy-tasks/tests/deploy-zk-badgebound-erc721.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { getImplementation } from './../../../utils'; 4 | import { ZKBadgeboundERC721, ZKBadgeboundERC721__factory } from '../../../types'; 5 | import { 6 | afterDeployment, 7 | beforeDeployment, 8 | customDeployContract, 9 | DeployOptions, 10 | getDeployer, 11 | wrapCommonDeployOptions, 12 | } from '../utils'; 13 | 14 | export interface DeployZKBadgeboundERC721Args { 15 | deploymentName?: string; 16 | name: string; 17 | symbol: string; 18 | tokenURI: string; 19 | gatingBadgeTokenId: number; 20 | admin: string; 21 | options?: DeployOptions; 22 | } 23 | 24 | export interface DeployedZkBadgeboundERC721 { 25 | zkBadgeboundERC721: ZKBadgeboundERC721; 26 | } 27 | 28 | const CONTRACT_NAME = 'ZKBadgeboundERC721'; 29 | 30 | async function deploymentAction( 31 | { 32 | deploymentName, 33 | name, 34 | symbol, 35 | tokenURI, 36 | gatingBadgeTokenId, 37 | admin, 38 | options, 39 | }: DeployZKBadgeboundERC721Args, 40 | hre: HardhatRuntimeEnvironment 41 | ) { 42 | const deployer = await getDeployer(hre); 43 | const deploymentArgs = [name, symbol, tokenURI, gatingBadgeTokenId, admin]; 44 | 45 | await beforeDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, options); 46 | 47 | const initData = new ZKBadgeboundERC721__factory().interface.encodeFunctionData('initialize', [ 48 | name, 49 | symbol, 50 | tokenURI, 51 | admin, 52 | ]); 53 | 54 | const deployed = await customDeployContract( 55 | hre, 56 | deployer, 57 | deploymentName ? deploymentName : `${options?.deploymentNamePrefix}_${CONTRACT_NAME}`, 58 | CONTRACT_NAME, 59 | deploymentArgs, 60 | { ...options, proxyData: initData } 61 | ); 62 | 63 | await afterDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, deployed, options); 64 | const zkBadgeboundERC721 = ZKBadgeboundERC721__factory.connect(deployed.address, deployer); 65 | 66 | if (options?.manualConfirm || options?.log) { 67 | console.log(` 68 | ************************************************************ 69 | * RECAP * 70 | ************************************************************ 71 | 72 | date: ${new Date().toISOString()} 73 | 74 | * ZKBadgeboundERC721: 75 | -> proxy: ${zkBadgeboundERC721.address} 76 | -> implem: ${await getImplementation(zkBadgeboundERC721)} 77 | `); 78 | } 79 | 80 | return { zkBadgeboundERC721 }; 81 | } 82 | 83 | task('deploy-zk-badgebound-erc721') 84 | .addOptionalParam('deploymentName', 'Name of the deployment') 85 | .addParam('name', 'Name of the token') 86 | .addParam('symbol', 'Symbol of the token') 87 | .addParam('tokenURI', 'Token URI') 88 | .addParam('gatingBadgeTokenId', 'gatingBadgeTokenId') 89 | .setAction(wrapCommonDeployOptions(deploymentAction)); 90 | -------------------------------------------------------------------------------- /tasks/deploy-tasks/unit/attesters/hydra-s1/deploy-hydra-s1-accountbound-attester.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { 4 | getDeployer, 5 | beforeDeployment, 6 | afterDeployment, 7 | buildDeploymentName, 8 | customDeployContract, 9 | wrapCommonDeployOptions, 10 | DeployOptions, 11 | } from '../../../utils'; 12 | import { 13 | HydraS1AccountboundAttester, 14 | HydraS1AccountboundAttester__factory, 15 | HydraS1Verifier, 16 | HydraS1Verifier__factory, 17 | } from '../../../../../types'; 18 | import { BigNumber, BigNumberish } from 'ethers'; 19 | 20 | export interface DeployHydraS1AccountboundAttesterArgs { 21 | // address of the proving scheme verifier contract 22 | hydraS1VerifierAddress?: string; 23 | // address of the registry MerkleRoot contract 24 | availableRootsRegistryAddress: string; 25 | // address of the commitment mapper registry 26 | commitmentMapperRegistryAddress: string; 27 | // address of the attestations contract, 28 | // which is part of the SAS 29 | // Sismo Attestation State 30 | attestationsRegistryAddress: string; 31 | collectionIdFirst: BigNumberish; 32 | collectionIdLast: BigNumberish; 33 | owner: string; 34 | options?: DeployOptions; 35 | } 36 | 37 | export interface DeployedHydraS1AccountboundAttester { 38 | hydraS1AccountboundAttester: HydraS1AccountboundAttester; 39 | hydraS1Verifier: HydraS1Verifier; 40 | } 41 | 42 | const CONTRACT_NAME = 'HydraS1AccountboundAttester'; 43 | 44 | async function deploymentAction( 45 | { 46 | hydraS1VerifierAddress, 47 | availableRootsRegistryAddress, 48 | commitmentMapperRegistryAddress, 49 | attestationsRegistryAddress, 50 | collectionIdFirst, 51 | collectionIdLast, 52 | owner, 53 | options, 54 | }: DeployHydraS1AccountboundAttesterArgs, 55 | hre: HardhatRuntimeEnvironment 56 | ): Promise { 57 | const deployer = await getDeployer(hre); 58 | const deploymentName = buildDeploymentName(CONTRACT_NAME, options?.deploymentNamePrefix); 59 | 60 | let hydraS1Verifier: HydraS1Verifier; 61 | 62 | if (!hydraS1VerifierAddress) { 63 | ({ hydraS1Verifier } = await hre.run('deploy-hydra-s1-verifier', { 64 | options, 65 | })); 66 | hydraS1VerifierAddress = hydraS1Verifier.address; 67 | } else { 68 | hydraS1Verifier = HydraS1Verifier__factory.connect(hydraS1VerifierAddress, deployer); 69 | } 70 | const deploymentArgs = [ 71 | attestationsRegistryAddress, 72 | hydraS1VerifierAddress, 73 | availableRootsRegistryAddress, 74 | commitmentMapperRegistryAddress, 75 | BigNumber.from(collectionIdFirst), 76 | BigNumber.from(collectionIdLast), 77 | owner || deployer.address, 78 | ]; 79 | 80 | await beforeDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, options); 81 | 82 | const initData = new HydraS1AccountboundAttester__factory().interface.encodeFunctionData( 83 | 'initialize', 84 | [owner || deployer.address] 85 | ); 86 | 87 | const deployed = await customDeployContract( 88 | hre, 89 | deployer, 90 | deploymentName, 91 | CONTRACT_NAME, 92 | deploymentArgs, 93 | { 94 | ...options, 95 | proxyData: initData, 96 | } 97 | ); 98 | 99 | await afterDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, deployed, options); 100 | 101 | const hydraS1AccountboundAttester = HydraS1AccountboundAttester__factory.connect( 102 | deployed.address, 103 | deployer 104 | ); 105 | 106 | return { hydraS1AccountboundAttester, hydraS1Verifier }; 107 | } 108 | 109 | task('deploy-hydra-s1-accountbound-attester') 110 | .addParam('collectionIdFirst', '') 111 | .addParam('collectionIdLast', '') 112 | .addOptionalParam( 113 | 'hydraS1VerifierAddress', 114 | 'address of the proving scheme verifier. Deploy verifier if not defined.' 115 | ) 116 | .addParam('availableRootsRegistryAddress', 'address of the registryMerkleRoot contract') 117 | .addParam( 118 | 'commitmentMapperRegistryAddress', 119 | 'address of the commitmentMapperRegistryAddress contract' 120 | ) 121 | .addParam('attestationsRegistryAddress', 'Address of the attestations contract') 122 | .setAction(wrapCommonDeployOptions(deploymentAction)); 123 | -------------------------------------------------------------------------------- /tasks/deploy-tasks/unit/attesters/hydra-s1/deploy-hydra-s1-simple-attester.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { 4 | getDeployer, 5 | beforeDeployment, 6 | afterDeployment, 7 | buildDeploymentName, 8 | customDeployContract, 9 | wrapCommonDeployOptions, 10 | DeployOptions, 11 | } from '../../../../../tasks/deploy-tasks/utils'; 12 | 13 | import { 14 | HydraS1SimpleAttester, 15 | HydraS1SimpleAttester__factory, 16 | HydraS1Verifier, 17 | HydraS1Verifier__factory, 18 | } from '../../../../../types'; 19 | import { BigNumber, BigNumberish } from 'ethers'; 20 | 21 | export interface DeployHydraS1SimpleAttesterArgs { 22 | // mandatory parameter that indicates if we want to deploy the hydra S1 simple attester 23 | enableDeployment: boolean; 24 | // address of the proving scheme verifier contract 25 | hydraS1VerifierAddress?: string; 26 | // address of the registryMerkleRoot contract 27 | availableRootsRegistryAddress: string; 28 | // address of the commitment mapper registry 29 | commitmentMapperRegistryAddress: string; 30 | // address of the attestations contract, 31 | // which is part of the SAS 32 | // Sismo Attestation State 33 | attestationsRegistryAddress: string; 34 | collectionIdFirst: BigNumberish; 35 | collectionIdLast: BigNumberish; 36 | options?: DeployOptions; 37 | } 38 | 39 | export interface DeployedHydraS1SimpleAttester { 40 | hydraS1SimpleAttester?: HydraS1SimpleAttester; 41 | hydraS1Verifier: HydraS1Verifier; 42 | } 43 | 44 | const CONTRACT_NAME = 'HydraS1SimpleAttester'; 45 | 46 | async function deploymentAction( 47 | { 48 | enableDeployment, 49 | hydraS1VerifierAddress, 50 | availableRootsRegistryAddress, 51 | commitmentMapperRegistryAddress, 52 | attestationsRegistryAddress, 53 | collectionIdFirst = 100, 54 | collectionIdLast = 0, 55 | options, 56 | }: DeployHydraS1SimpleAttesterArgs, 57 | hre: HardhatRuntimeEnvironment 58 | ): Promise { 59 | const deployer = await getDeployer(hre); 60 | const deploymentName = buildDeploymentName(CONTRACT_NAME, options?.deploymentNamePrefix); 61 | 62 | let hydraS1Verifier: HydraS1Verifier; 63 | 64 | if (!hydraS1VerifierAddress) { 65 | ({ hydraS1Verifier } = await hre.run('deploy-hydra-s1-verifier', { 66 | options, 67 | })); 68 | hydraS1VerifierAddress = hydraS1Verifier.address; 69 | } else { 70 | hydraS1Verifier = HydraS1Verifier__factory.connect(hydraS1VerifierAddress, deployer); 71 | } 72 | 73 | // if enableDeployment is false, we just return the verifier 74 | if (!enableDeployment) { 75 | return { hydraS1Verifier }; 76 | } 77 | 78 | const deploymentArgs = [ 79 | attestationsRegistryAddress, 80 | hydraS1VerifierAddress, 81 | availableRootsRegistryAddress, 82 | commitmentMapperRegistryAddress, 83 | BigNumber.from(collectionIdFirst), 84 | BigNumber.from(collectionIdLast), 85 | ]; 86 | 87 | await beforeDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, options); 88 | 89 | const initData = '0x'; 90 | 91 | const deployed = await customDeployContract( 92 | hre, 93 | deployer, 94 | deploymentName, 95 | CONTRACT_NAME, 96 | deploymentArgs, 97 | { 98 | ...options, 99 | proxyData: initData, 100 | } 101 | ); 102 | 103 | await afterDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, deployed, options); 104 | 105 | const hydraS1SimpleAttester = HydraS1SimpleAttester__factory.connect(deployed.address, deployer); 106 | return { hydraS1SimpleAttester, hydraS1Verifier }; 107 | } 108 | 109 | task('deploy-hydra-s1-simple-attester') 110 | .addParam('collectionIdFirst', '') 111 | .addParam('collectionIdLast', '') 112 | .addOptionalParam( 113 | 'hydraS1VerifierAddress', 114 | 'address of the proving scheme verifier. Deploy verifier if not defined.' 115 | ) 116 | .addParam('availableRootsRegistryAddress', 'address of the registryMerkleRoot contract') 117 | .addParam( 118 | 'commitmentMapperRegistryAddress', 119 | 'address of the commitmentMapperRegistryAddress contract' 120 | ) 121 | .addParam('attestationsRegistryAddress', 'Address of the attestations contract') 122 | .setAction(wrapCommonDeployOptions(deploymentAction)); 123 | -------------------------------------------------------------------------------- /tasks/deploy-tasks/unit/attesters/hydra-s1/deploy-hydra-s1-verifier.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { 4 | getDeployer, 5 | beforeDeployment, 6 | afterDeployment, 7 | buildDeploymentName, 8 | customDeployContract, 9 | wrapCommonDeployOptions, 10 | DeployOptions, 11 | } from '../../../../../tasks/deploy-tasks/utils'; 12 | import { HydraS1Verifier, HydraS1Verifier__factory } from '../../../../../types'; 13 | 14 | export interface DeployHydraS1Verifier { 15 | options?: DeployOptions; 16 | } 17 | 18 | export interface DeployedHydraS1Verifier { 19 | hydraS1Verifier: HydraS1Verifier; 20 | } 21 | 22 | const CONTRACT_NAME = 'HydraS1Verifier'; 23 | 24 | async function deploymentAction( 25 | { options }: DeployHydraS1Verifier, 26 | hre: HardhatRuntimeEnvironment 27 | ): Promise { 28 | const deployer = await getDeployer(hre); 29 | const deploymentName = buildDeploymentName(CONTRACT_NAME, options?.deploymentNamePrefix); 30 | const deploymentArgs = []; 31 | 32 | await beforeDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, options); 33 | 34 | const deployed = await hre.deployments.deploy(deploymentName, { 35 | contract: CONTRACT_NAME, 36 | from: deployer.address, 37 | args: deploymentArgs, 38 | skipIfAlreadyDeployed: false, 39 | }); 40 | 41 | await afterDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, deployed, options); 42 | 43 | const hydraS1Verifier = HydraS1Verifier__factory.connect(deployed.address, deployer); 44 | return { hydraS1Verifier }; 45 | } 46 | 47 | task('deploy-hydra-s1-verifier').setAction(wrapCommonDeployOptions(deploymentAction)); 48 | -------------------------------------------------------------------------------- /tasks/deploy-tasks/unit/attesters/pythia-1/deploy-pythia-1-simple-attester.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { 4 | getDeployer, 5 | beforeDeployment, 6 | afterDeployment, 7 | buildDeploymentName, 8 | customDeployContract, 9 | wrapCommonDeployOptions, 10 | DeployOptions, 11 | } from '../../../utils'; 12 | 13 | import { 14 | Pythia1SimpleAttester, 15 | Pythia1SimpleAttester__factory, 16 | Pythia1Verifier, 17 | Pythia1Verifier__factory, 18 | } from '../../../../../types'; 19 | import { BigNumber, BigNumberish } from 'ethers'; 20 | 21 | export interface DeployPythia1SimpleAttesterArgs { 22 | // address of the proving scheme verifier contract 23 | pythia1VerifierAddress?: string; 24 | // Commitment Signer public key 25 | commitmentSignerPubKeyX?: string; 26 | commitmentSignerPubKeyY?: string; 27 | // address of the owner that can update the commitmentSignerPubKey 28 | owner?: string; 29 | // address of the attestations contract, 30 | // which is part of the Attestation Registry 31 | // Sismo Attestation State 32 | attestationsRegistryAddress: string; 33 | collectionIdFirst: BigNumberish; 34 | collectionIdLast: BigNumberish; 35 | options?: DeployOptions; 36 | } 37 | 38 | export interface DeployedPythia1SimpleAttester { 39 | pythia1SimpleAttester: Pythia1SimpleAttester; 40 | pythia1Verifier: Pythia1Verifier; 41 | } 42 | 43 | const CONTRACT_NAME = 'Pythia1SimpleAttester'; 44 | 45 | async function deploymentAction( 46 | { 47 | pythia1VerifierAddress, 48 | attestationsRegistryAddress, 49 | commitmentSignerPubKeyX, 50 | commitmentSignerPubKeyY, 51 | collectionIdFirst = 100, 52 | collectionIdLast = 0, 53 | owner, 54 | options, 55 | }: DeployPythia1SimpleAttesterArgs, 56 | hre: HardhatRuntimeEnvironment 57 | ): Promise { 58 | const deployer = await getDeployer(hre); 59 | const deploymentName = buildDeploymentName(CONTRACT_NAME, options?.deploymentNamePrefix); 60 | 61 | let pythia1Verifier: Pythia1Verifier; 62 | 63 | if (!pythia1VerifierAddress) { 64 | ({ pythia1Verifier } = await hre.run('deploy-pythia-1-verifier', { 65 | options, 66 | })); 67 | pythia1VerifierAddress = pythia1Verifier.address; 68 | } else { 69 | pythia1Verifier = Pythia1Verifier__factory.connect(pythia1VerifierAddress, deployer); 70 | } 71 | 72 | const deploymentArgs = [ 73 | attestationsRegistryAddress, 74 | BigNumber.from(collectionIdFirst), 75 | BigNumber.from(collectionIdLast), 76 | pythia1VerifierAddress, 77 | [commitmentSignerPubKeyX, commitmentSignerPubKeyY], 78 | owner || deployer.address, 79 | ]; 80 | 81 | await beforeDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, options); 82 | 83 | const initData = new Pythia1SimpleAttester__factory().interface.encodeFunctionData('initialize', [ 84 | [commitmentSignerPubKeyX, commitmentSignerPubKeyY], 85 | owner || deployer.address, 86 | ]); 87 | 88 | const deployed = await customDeployContract( 89 | hre, 90 | deployer, 91 | deploymentName, 92 | CONTRACT_NAME, 93 | deploymentArgs, 94 | { 95 | ...options, 96 | proxyData: initData, 97 | } 98 | ); 99 | 100 | await afterDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, deployed, options); 101 | 102 | const pythia1SimpleAttester = Pythia1SimpleAttester__factory.connect(deployed.address, deployer); 103 | return { pythia1SimpleAttester, pythia1Verifier }; 104 | } 105 | 106 | task('deploy-pythia-1-simple-attester') 107 | .addParam('collectionIdFirst', '') 108 | .addParam('collectionIdLast', '') 109 | .addOptionalParam( 110 | 'pythia1VerifierAddress', 111 | 'address of the proving scheme verifier. Deploy verifier if not defined.' 112 | ) 113 | .addParam('attestationsRegistryAddress', 'Address of the attestations contract') 114 | .addParam('commitmentSignerPubKeyX', 'Eddsa public key coordinate X') 115 | .addParam('commitmentSignerPubKeyY', 'Eddsa public key coordinate Y') 116 | .addOptionalParam( 117 | 'owner', 118 | 'Owner of the contract that can change the commitment signer pubKey. Default to deployer' 119 | ) 120 | .setAction(wrapCommonDeployOptions(deploymentAction)); 121 | -------------------------------------------------------------------------------- /tasks/deploy-tasks/unit/attesters/pythia-1/deploy-pythia-1-verifier.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { 4 | getDeployer, 5 | beforeDeployment, 6 | afterDeployment, 7 | buildDeploymentName, 8 | customDeployContract, 9 | wrapCommonDeployOptions, 10 | DeployOptions, 11 | } from '../../../utils'; 12 | import { Pythia1Verifier, Pythia1Verifier__factory } from '../../../../../types'; 13 | 14 | export interface DeployPythia1Verifier { 15 | options?: DeployOptions; 16 | } 17 | 18 | export interface DeployedPythia1Verifier { 19 | pythia1Verifier: Pythia1Verifier; 20 | } 21 | 22 | const CONTRACT_NAME = 'Pythia1Verifier'; 23 | 24 | async function deploymentAction( 25 | { options }: DeployPythia1Verifier, 26 | hre: HardhatRuntimeEnvironment 27 | ): Promise { 28 | const deployer = await getDeployer(hre); 29 | const deploymentName = buildDeploymentName(CONTRACT_NAME, options?.deploymentNamePrefix); 30 | const deploymentArgs = []; 31 | 32 | await beforeDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, options); 33 | 34 | const deployed = await hre.deployments.deploy(deploymentName, { 35 | contract: CONTRACT_NAME, 36 | from: deployer.address, 37 | args: deploymentArgs, 38 | skipIfAlreadyDeployed: false, 39 | }); 40 | 41 | await afterDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, deployed, options); 42 | 43 | const pythia1Verifier = Pythia1Verifier__factory.connect(deployed.address, deployer); 44 | return { pythia1Verifier }; 45 | } 46 | 47 | task('deploy-pythia-1-verifier').setAction(wrapCommonDeployOptions(deploymentAction)); 48 | -------------------------------------------------------------------------------- /tasks/deploy-tasks/unit/core/deploy-attestations-registry.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { 4 | getDeployer, 5 | beforeDeployment, 6 | afterDeployment, 7 | buildDeploymentName, 8 | customDeployContract, 9 | wrapCommonDeployOptions, 10 | DeployOptions, 11 | } from '../../../../tasks/deploy-tasks/utils'; 12 | import { AttestationsRegistry, AttestationsRegistry__factory } from '../../../../types'; 13 | 14 | export interface DeployAttestationsRegistryArgs { 15 | // owner of the contract 16 | owner?: string; 17 | badges: string; 18 | // attester register role 19 | attesterRegister?: string; 20 | options?: DeployOptions; 21 | } 22 | 23 | export interface DeployedAttestationsRegistry { 24 | attestationsRegistry: AttestationsRegistry; 25 | } 26 | 27 | const CONTRACT_NAME = 'AttestationsRegistry'; 28 | 29 | async function deploymentAction( 30 | { owner, badges, options }: DeployAttestationsRegistryArgs, 31 | hre: HardhatRuntimeEnvironment 32 | ): Promise { 33 | const deployer = await getDeployer(hre); 34 | const deploymentName = buildDeploymentName(CONTRACT_NAME, options?.deploymentNamePrefix); 35 | const deploymentArgs = [owner || deployer.address, badges || deployer.address]; 36 | 37 | await beforeDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, options); 38 | 39 | const initData = new AttestationsRegistry__factory(deployer).interface.encodeFunctionData( 40 | 'initialize', 41 | [owner || deployer.address] 42 | ); 43 | 44 | const deployed = await customDeployContract( 45 | hre, 46 | deployer, 47 | deploymentName, 48 | CONTRACT_NAME, 49 | deploymentArgs, 50 | { ...options, proxyData: initData } 51 | ); 52 | 53 | await afterDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, deployed, options); 54 | 55 | const attestationsRegistry = AttestationsRegistry__factory.connect(deployed.address, deployer); 56 | return { attestationsRegistry }; 57 | } 58 | 59 | task('deploy-attestations-registry') 60 | .addOptionalParam('owner', 'Admin of the attester register role. default to deployer') 61 | .addOptionalParam('badges', 'Address of the badges contract') 62 | .setAction(wrapCommonDeployOptions(deploymentAction)); 63 | -------------------------------------------------------------------------------- /tasks/deploy-tasks/unit/core/deploy-badges.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { 4 | getDeployer, 5 | beforeDeployment, 6 | afterDeployment, 7 | buildDeploymentName, 8 | customDeployContract, 9 | wrapCommonDeployOptions, 10 | DeployOptions, 11 | } from '../../../../tasks/deploy-tasks/utils'; 12 | import { Badges, Badges__factory } from '../../../../types'; 13 | 14 | export interface DeployBadgesArgs { 15 | // owner of the contract 16 | uri?: string; 17 | owner?: string; 18 | // attester register role 19 | options?: DeployOptions; 20 | } 21 | 22 | export interface DeployedBadges { 23 | badges: Badges; 24 | } 25 | 26 | const CONTRACT_NAME = 'Badges'; 27 | 28 | async function deploymentAction( 29 | { uri = '', owner, options }: DeployBadgesArgs, 30 | hre: HardhatRuntimeEnvironment 31 | ): Promise { 32 | const deployer = await getDeployer(hre); 33 | const deploymentName = buildDeploymentName(CONTRACT_NAME, options?.deploymentNamePrefix); 34 | const deploymentArgs = [uri, owner || deployer.address]; 35 | 36 | await beforeDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, options); 37 | 38 | const initData = new Badges__factory(deployer).interface.encodeFunctionData('initialize', [ 39 | uri, 40 | owner || deployer.address, 41 | ]); 42 | 43 | const deployed = await customDeployContract( 44 | hre, 45 | deployer, 46 | deploymentName, 47 | CONTRACT_NAME, 48 | deploymentArgs, 49 | { 50 | ...options, 51 | proxyData: initData, 52 | } 53 | ); 54 | 55 | await afterDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, deployed, options); 56 | 57 | const badges = Badges__factory.connect(deployed.address, deployer); 58 | return { badges }; 59 | } 60 | 61 | task('deploy-badges') 62 | .addOptionalParam('uri', 'uri') 63 | .addOptionalParam('owner', 'owner') 64 | .setAction(wrapCommonDeployOptions(deploymentAction)); 65 | -------------------------------------------------------------------------------- /tasks/deploy-tasks/unit/core/deploy-front.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { 4 | getDeployer, 5 | beforeDeployment, 6 | afterDeployment, 7 | buildDeploymentName, 8 | customDeployContract, 9 | wrapCommonDeployOptions, 10 | DeployOptions, 11 | } from '../../../../tasks/deploy-tasks/utils'; 12 | 13 | import { Front, Front__factory } from '../../../../types'; 14 | 15 | export interface DeployFrontArgs { 16 | attestationsRegistryAddress: string; 17 | // owner of the contract 18 | // attester register role 19 | options: DeployOptions; 20 | } 21 | 22 | export interface DeployedFront { 23 | front: Front; 24 | } 25 | 26 | const CONTRACT_NAME = 'Front'; 27 | 28 | async function deploymentAction( 29 | { attestationsRegistryAddress, options }: DeployFrontArgs, 30 | hre: HardhatRuntimeEnvironment 31 | ): Promise { 32 | const deployer = await getDeployer(hre); 33 | const deploymentName = buildDeploymentName(CONTRACT_NAME, options?.deploymentNamePrefix); 34 | const deploymentArgs = [attestationsRegistryAddress]; 35 | 36 | await beforeDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, options); 37 | 38 | const initData = '0x'; 39 | 40 | const deployed = await customDeployContract( 41 | hre, 42 | deployer, 43 | deploymentName, 44 | CONTRACT_NAME, 45 | deploymentArgs, 46 | { 47 | ...options, 48 | proxyData: initData, 49 | } 50 | ); 51 | 52 | await afterDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, deployed, options); 53 | 54 | const front = Front__factory.connect(deployed.address, deployer); 55 | return { front }; 56 | } 57 | 58 | task('deploy-front') 59 | .addParam('attestationsRegistryAddress', 'Attestation Registry on which to read') 60 | .setAction(wrapCommonDeployOptions(deploymentAction)); 61 | -------------------------------------------------------------------------------- /tasks/deploy-tasks/unit/periphery/deploy-available-roots-registry.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { 4 | getDeployer, 5 | beforeDeployment, 6 | afterDeployment, 7 | buildDeploymentName, 8 | customDeployContract, 9 | wrapCommonDeployOptions, 10 | DeployOptions, 11 | } from '../../../../tasks/deploy-tasks/utils'; 12 | 13 | import { AvailableRootsRegistry, AvailableRootsRegistry__factory } from '../../../../types'; 14 | 15 | export interface DeployAvailableRootsRegistry { 16 | // owner of the contract 17 | owner?: string; 18 | options?: DeployOptions; 19 | } 20 | 21 | export interface DeployedAvailableRootsRegistry { 22 | availableRootsRegistry: AvailableRootsRegistry; 23 | } 24 | 25 | const CONTRACT_NAME = 'AvailableRootsRegistry'; 26 | 27 | async function deploymentAction( 28 | { owner, options }: DeployAvailableRootsRegistry, 29 | hre: HardhatRuntimeEnvironment 30 | ): Promise { 31 | const deployer = await getDeployer(hre); 32 | const deploymentName = buildDeploymentName(CONTRACT_NAME, options?.deploymentNamePrefix); 33 | const deploymentArgs = [owner || deployer.address]; 34 | 35 | await beforeDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, options); 36 | 37 | const initData = new AvailableRootsRegistry__factory().interface.encodeFunctionData( 38 | 'initialize', 39 | [owner || deployer.address] 40 | ); 41 | 42 | const deployed = await customDeployContract( 43 | hre, 44 | deployer, 45 | deploymentName, 46 | CONTRACT_NAME, 47 | deploymentArgs, 48 | { 49 | ...options, 50 | proxyData: initData, 51 | } 52 | ); 53 | 54 | await afterDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, deployed, options); 55 | 56 | const availableRootsRegistry = AvailableRootsRegistry__factory.connect( 57 | deployed.address, 58 | deployer 59 | ); 60 | return { availableRootsRegistry }; 61 | } 62 | 63 | task('deploy-available-roots-registry') 64 | .addOptionalParam('owner', 'Admin of the attester register role. default to deployer') 65 | .setAction(wrapCommonDeployOptions(deploymentAction)); 66 | -------------------------------------------------------------------------------- /tasks/deploy-tasks/unit/periphery/deploy-commitment-mapper-registry.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { 4 | getDeployer, 5 | beforeDeployment, 6 | afterDeployment, 7 | buildDeploymentName, 8 | customDeployContract, 9 | wrapCommonDeployOptions, 10 | DeployOptions, 11 | } from '../../../../tasks/deploy-tasks/utils'; 12 | 13 | import { CommitmentMapperRegistry, CommitmentMapperRegistry__factory } from '../../../../types'; 14 | 15 | export interface DeployCommitmentMapperArgs { 16 | // owner of the contract 17 | owner?: string; 18 | commitmentMapperPubKeyX?: string; 19 | commitmentMapperPubKeyY?: string; 20 | commitmentMapperAddress?: string; 21 | options?: DeployOptions; 22 | } 23 | 24 | export interface DeployedCommitmentMapper { 25 | commitmentMapperRegistry: CommitmentMapperRegistry; 26 | } 27 | 28 | const CONTRACT_NAME = 'CommitmentMapperRegistry'; 29 | 30 | async function deploymentAction( 31 | { 32 | owner, 33 | commitmentMapperPubKeyX, 34 | commitmentMapperPubKeyY, 35 | commitmentMapperAddress, 36 | options, 37 | }: DeployCommitmentMapperArgs, 38 | hre: HardhatRuntimeEnvironment 39 | ): Promise { 40 | const deployer = await getDeployer(hre); 41 | const deploymentName = buildDeploymentName(CONTRACT_NAME, options?.deploymentNamePrefix); 42 | const deploymentArgs = [ 43 | owner || deployer.address, 44 | [commitmentMapperPubKeyX, commitmentMapperPubKeyY], 45 | commitmentMapperAddress || hre.ethers.constants.AddressZero, 46 | ]; 47 | 48 | await beforeDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, options); 49 | 50 | const initData = new CommitmentMapperRegistry__factory().interface.encodeFunctionData( 51 | 'initialize', 52 | [ 53 | owner || deployer.address, 54 | [commitmentMapperPubKeyX, commitmentMapperPubKeyY], 55 | commitmentMapperAddress || hre.ethers.constants.AddressZero, 56 | ] 57 | ); 58 | 59 | const deployed = await customDeployContract( 60 | hre, 61 | deployer, 62 | deploymentName, 63 | CONTRACT_NAME, 64 | deploymentArgs, 65 | { 66 | ...options, 67 | proxyData: initData, 68 | } 69 | ); 70 | 71 | await afterDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, deployed, options); 72 | 73 | const commitmentMapperRegistry = CommitmentMapperRegistry__factory.connect( 74 | deployed.address, 75 | deployer 76 | ); 77 | return { commitmentMapperRegistry }; 78 | } 79 | 80 | task('deploy-commitment-mapper-registry') 81 | .addOptionalParam('commitmentMapperPubKeyX', 'Eddsa public key coordinate x') 82 | .addOptionalParam('commitmentMapperPubKeyY', 'Eddsa public key coordinate y') 83 | .addOptionalParam('commitmentMapperAddress', 'ethereum address of commitment mapper') 84 | .addOptionalParam('owner', 'Admin of the commitment mapper updater role. default to deployer') 85 | .setAction(wrapCommonDeployOptions(deploymentAction)); 86 | -------------------------------------------------------------------------------- /tasks/deploy-tasks/unit/periphery/deploy-frontend-lib.task.ts: -------------------------------------------------------------------------------- 1 | import { FrontendLib } from '../../../../types/FrontendLib'; 2 | import { task } from 'hardhat/config'; 3 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 4 | import { 5 | getDeployer, 6 | beforeDeployment, 7 | afterDeployment, 8 | buildDeploymentName, 9 | customDeployContract, 10 | wrapCommonDeployOptions, 11 | DeployOptions, 12 | } from '../../utils'; 13 | 14 | import { FrontendLib__factory } from '../../../../types'; 15 | import { deploymentsConfig } from '../../../../tasks/deploy-tasks/deployments-config'; 16 | 17 | export interface DeployFrontendLib { 18 | hydraS1AccountboundAttester?: string; 19 | options?: DeployOptions; 20 | } 21 | 22 | export interface DeployedFrontendLib { 23 | frontendLib: FrontendLib; 24 | } 25 | 26 | const CONTRACT_NAME = 'FrontendLib'; 27 | 28 | async function deploymentAction( 29 | { hydraS1AccountboundAttester, options }: DeployFrontendLib, 30 | hre: HardhatRuntimeEnvironment 31 | ): Promise { 32 | const deployer = await getDeployer(hre); 33 | const deploymentName = buildDeploymentName(CONTRACT_NAME, options?.deploymentNamePrefix); 34 | const config = deploymentsConfig[hre.network.name]; 35 | 36 | const deploymentArgs = [ 37 | hydraS1AccountboundAttester || config.hydraS1AccountboundAttester.address, 38 | ]; 39 | 40 | await beforeDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, options); 41 | 42 | const deployed = await customDeployContract( 43 | hre, 44 | deployer, 45 | deploymentName, 46 | CONTRACT_NAME, 47 | deploymentArgs, 48 | { 49 | ...options, 50 | behindProxy: false, 51 | } 52 | ); 53 | 54 | await afterDeployment(hre, deployer, CONTRACT_NAME, deploymentArgs, deployed, options); 55 | 56 | const frontLib = FrontendLib__factory.connect(deployed.address, deployer); 57 | return { frontendLib: frontLib }; 58 | } 59 | 60 | task('deploy-frontend-lib') 61 | .addOptionalParam( 62 | 'hydraS1AccountboundAttester', 63 | 'address of the hydraS1AccountboundAttester contract' 64 | ) 65 | .setAction(wrapCommonDeployOptions(deploymentAction)); 66 | -------------------------------------------------------------------------------- /tasks/deploy-tasks/utils/deployments-config-types.ts: -------------------------------------------------------------------------------- 1 | import { CommonTaskOptions } from '../../utils'; 2 | 3 | export interface DeployOptions extends CommonTaskOptions { 4 | // prefix for the contract name 5 | deploymentNamePrefix?: string; 6 | // deploy with proxy? 7 | behindProxy?: boolean; 8 | // Proxy data is the encoded call of the initialize(params) function 9 | proxyData?: string; 10 | // admin of the proxy 11 | proxyAdmin?: string; 12 | // set to true if the deployment is an upgrade of an existing proxy 13 | isImplementationUpgrade?: boolean; 14 | // proxy address, required in case of implementation upgrade 15 | proxyAddress?: string; 16 | // deterministic deployment 17 | deterministicDeployment?: boolean; 18 | } 19 | 20 | export type DeploymentsConfigTypes = { 21 | [chain: string]: { 22 | // Conf related to the deployment (behind proxy, etc.) 23 | deployOptions: DeployOptions; 24 | // Conf related to the hydraS1AccountboundAttester 25 | hydraS1Verifier: { 26 | address: string; 27 | }; 28 | hydraS1AccountboundAttester: { 29 | address: string; 30 | collectionIdFirst: string; 31 | collectionIdLast: string; 32 | initialRoot: string; 33 | owner: string; 34 | }; 35 | hydraS1SimpleAttester: { 36 | enableDeployment: boolean; 37 | address: string; 38 | collectionIdFirst: string; 39 | collectionIdLast: string; 40 | initialRoot: string; 41 | }; 42 | pythia1Verifier: { 43 | address: string; 44 | }; 45 | synapsPythia1SimpleAttester: { 46 | address: string; 47 | collectionIdFirst: string; 48 | collectionIdLast: string; 49 | commitmentSignerPubKeyX: string; 50 | commitmentSignerPubKeyY: string; 51 | owner: string; 52 | }; 53 | // Conf related to the commitment mapper 54 | // https://github.com/sismo-core/sismo-commitment-mapper 55 | commitmentMapper: { 56 | address: string; 57 | owner: string; 58 | EdDSAPubKeyX: string; 59 | EdDSAPubKeyY: string; 60 | }; 61 | badges: { 62 | address: string; 63 | owner: string; 64 | uri: string; 65 | }; 66 | // conf related to the roots Registry to store 67 | // all the merkleRoots 68 | availableRootsRegistry: { 69 | address: string; 70 | owner: string; 71 | }; 72 | attestationsRegistry: { 73 | address: string; 74 | owner: string; 75 | }; 76 | front: { 77 | address: string; 78 | collectionIdFirst: string; 79 | collectionIdLast: string; 80 | }; 81 | sismoAddressesProvider: { 82 | address: string; 83 | owner: string; 84 | }; 85 | }; 86 | }; 87 | -------------------------------------------------------------------------------- /tasks/deploy-tasks/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './deployment'; 2 | export * from './deployments-config-types'; 3 | -------------------------------------------------------------------------------- /tasks/deploy-tasks/zkdrop/deploy-mergooor-pass.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { DeployOptions } from '../utils'; 4 | import { deploymentsConfig } from '../deployments-config'; 5 | import { ZKBadgeboundERC721 } from 'types'; 6 | import { DeployedZkBadgeboundERC721 } from 'tasks/deploy-tasks/tests/deploy-zk-badgebound-erc721.task'; 7 | 8 | export interface DeployedMergooorPass { 9 | zkBadgeboundERC721: ZKBadgeboundERC721; 10 | } 11 | 12 | async function deploymentAction( 13 | { options }: { options: DeployOptions }, 14 | hre: HardhatRuntimeEnvironment 15 | ): Promise { 16 | const config = deploymentsConfig[process.env.FORK_NETWORK ?? hre.network.name]; 17 | options = { ...config.deployOptions, ...options }; 18 | 19 | if (options.manualConfirm || options.log) { 20 | console.log('deploy-mergooor-pass: ', hre.network.name); 21 | } 22 | 23 | // Deploy SismoAddressesProvider 24 | const { zkBadgeboundERC721 } = (await hre.run('deploy-zk-badgebound-erc721', { 25 | name: 'Mergooor Pass', 26 | symbol: 'MP', 27 | tokenURI: 'ipfs://QmPR9q3Q5fByxzfMfRp32azvH2UPXhPoDFhHWAsiGNHBwS/', 28 | gatingBadgeTokenId: '10000040', 29 | admin: '0xaee4acd5c4Bf516330ca8fe11B07206fC6709294', // Sismo owner 30 | deploymentName: 'MergooorPass', 31 | options, 32 | })) as DeployedZkBadgeboundERC721; 33 | 34 | return { 35 | zkBadgeboundERC721, 36 | }; 37 | } 38 | 39 | task('deploy-mergooor-pass').setAction(deploymentAction); 40 | -------------------------------------------------------------------------------- /tasks/deploy-tasks/zkdrop/deploy-ziki-pass-staging.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { DeployOptions } from '../utils'; 4 | import { deploymentsConfig } from '../deployments-config'; 5 | import { ZKBadgeboundERC721 } from 'types'; 6 | import { DeployedZkBadgeboundERC721 } from 'tasks/deploy-tasks/tests/deploy-zk-badgebound-erc721.task'; 7 | 8 | export interface DeployedZikiPass { 9 | zkBadgeboundERC721: ZKBadgeboundERC721; 10 | } 11 | 12 | async function deploymentAction( 13 | { options }: { options: DeployOptions }, 14 | hre: HardhatRuntimeEnvironment 15 | ): Promise { 16 | const config = deploymentsConfig[process.env.FORK_NETWORK ?? hre.network.name]; 17 | options = { ...config.deployOptions, ...options }; 18 | 19 | if (options.manualConfirm || options.log) { 20 | console.log('deploy-ziki-pass-staging: ', hre.network.name); 21 | } 22 | 23 | // Deploy SismoAddressesProvider 24 | const { zkBadgeboundERC721 } = (await hre.run('deploy-zk-badgebound-erc721', { 25 | name: 'Ziki Pass', 26 | symbol: 'ZKP', 27 | tokenURI: 'ipfs://Qme1WfqhZ4dUVSKHE9NqH1z7MXFtviPY6QEPwu8TcgAyjc/', 28 | gatingBadgeTokenId: '10000515', 29 | admin: '0xf61cabba1e6fc166a66bca0fcaa83762edb6d4bd', // leo21.eth 30 | deploymentName: 'ZikiPass', 31 | options, 32 | })) as DeployedZkBadgeboundERC721; 33 | 34 | return { 35 | zkBadgeboundERC721, 36 | }; 37 | } 38 | 39 | task('deploy-ziki-pass-staging').setAction(deploymentAction); 40 | -------------------------------------------------------------------------------- /tasks/deploy-tasks/zkdrop/deploy-ziki-pass-testnet.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { DeployOptions } from '../utils'; 4 | import { deploymentsConfig } from '../deployments-config'; 5 | import { ZKBadgeboundERC721 } from 'types'; 6 | import { DeployedZkBadgeboundERC721 } from 'tasks/deploy-tasks/tests/deploy-zk-badgebound-erc721.task'; 7 | 8 | export interface DeployedZikiPass { 9 | zkBadgeboundERC721: ZKBadgeboundERC721; 10 | } 11 | 12 | async function deploymentAction( 13 | { options }: { options: DeployOptions }, 14 | hre: HardhatRuntimeEnvironment 15 | ): Promise { 16 | const config = deploymentsConfig[process.env.FORK_NETWORK ?? hre.network.name]; 17 | options = { ...config.deployOptions, ...options }; 18 | 19 | if (options.manualConfirm || options.log) { 20 | console.log('deploy-ziki-pass-testnet: ', hre.network.name); 21 | } 22 | 23 | // Deploy SismoAddressesProvider 24 | const { zkBadgeboundERC721 } = (await hre.run('deploy-zk-badgebound-erc721', { 25 | name: 'Ziki Pass', 26 | symbol: 'ZKP', 27 | tokenURI: 'https://metadata-zikies.zkdrop.io/ziki-pass/', 28 | gatingBadgeTokenId: '10000515', 29 | admin: '0xf61cabba1e6fc166a66bca0fcaa83762edb6d4bd', // leo21.eth 30 | deploymentName: 'ZikiPass', 31 | options, 32 | })) as DeployedZkBadgeboundERC721; 33 | 34 | return { 35 | zkBadgeboundERC721, 36 | }; 37 | } 38 | 39 | task('deploy-ziki-pass-testnet').setAction(deploymentAction); 40 | -------------------------------------------------------------------------------- /tasks/helpers/authorizations/access-control-grant-role.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { AccessControl__factory } from '../../../types'; 4 | import { CommonTaskOptions } from '../../utils'; 5 | import { confirm } from '../../utils/confirm'; 6 | 7 | export type AccessControlGrantRoleArgs = { 8 | contractAddress: string; 9 | role: string; 10 | accountAddress: string; 11 | options?: CommonTaskOptions; 12 | }; 13 | 14 | async function grantRole( 15 | { contractAddress, role, accountAddress, options }: AccessControlGrantRoleArgs, 16 | hre: HardhatRuntimeEnvironment 17 | ): Promise { 18 | const [signer] = await hre.ethers.getSigners(); 19 | 20 | if (options?.log || options?.manualConfirm) { 21 | console.log(` 22 | ************************************ 23 | * GRANT ROLE * 24 | ************************************`); 25 | } 26 | 27 | const accessControlContract = AccessControl__factory.connect(contractAddress, signer); 28 | 29 | const accountAlreadyHaveRole = await accessControlContract.hasRole(role, accountAddress); 30 | 31 | // Verify if the account already have the good role 32 | if (accountAlreadyHaveRole) { 33 | if (options?.log || options?.manualConfirm) { 34 | console.log(` 35 | * ${accountAddress} already has role ${role} on contract ${contractAddress} 36 | `); 37 | } 38 | return; 39 | } 40 | 41 | // Verify signer can give the role 42 | const signerAddressIsAdminRole = await accessControlContract.hasRole( 43 | await accessControlContract.DEFAULT_ADMIN_ROLE(), 44 | signer.address 45 | ); 46 | 47 | if (!signerAddressIsAdminRole) { 48 | throw new Error( 49 | `The current signer (${signer.address}) is not admin of the current contract ${contractAddress}. Can't grant role ${role}` 50 | ); 51 | } 52 | 53 | const actionGrantRole = { 54 | role: role, 55 | toAccount: accountAddress, 56 | contract: contractAddress, 57 | }; 58 | // Grant role section 59 | if (options?.log || options?.manualConfirm) { 60 | console.log(` 61 | ${Object.keys(actionGrantRole as Object).map( 62 | (key) => ` 63 | ${key}: ${actionGrantRole?.[key]}` 64 | )}`); 65 | } 66 | if (options?.manualConfirm) { 67 | console.log(); 68 | await confirm(); 69 | } 70 | const tx = await accessControlContract.grantRole(actionGrantRole.role, actionGrantRole.toAccount); 71 | await tx.wait(); 72 | 73 | if (options?.log || options?.manualConfirm) { 74 | console.log(` 75 | * Role Granted ! 76 | `); 77 | } 78 | } 79 | 80 | task('access-control-grant-role') 81 | .addParam('contractAddress', 'Contract concerned by the grantRole call') 82 | .addParam('role', 'Role to grant') 83 | .addParam('accountAddress', 'Account to receive the role') 84 | .setAction(grantRole); 85 | -------------------------------------------------------------------------------- /tasks/helpers/authorizations/access-control-revoke-role.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { AccessControl__factory } from '../../../types'; 4 | import { CommonTaskOptions } from '../../utils'; 5 | import { confirm } from '../../utils/confirm'; 6 | 7 | export type AccessControlRevokeRoleArgs = { 8 | contractAddress: string; 9 | role: string; 10 | accountAddress: string; 11 | options?: CommonTaskOptions; 12 | }; 13 | 14 | async function revokeRole( 15 | { contractAddress, role, accountAddress, options }: AccessControlRevokeRoleArgs, 16 | hre: HardhatRuntimeEnvironment 17 | ): Promise { 18 | const [signer] = await hre.ethers.getSigners(); 19 | 20 | if (options?.log || options?.manualConfirm) { 21 | console.log(` 22 | ************************************ 23 | * REVOKE ROLE * 24 | ************************************`); 25 | } 26 | 27 | const accessControlContract = AccessControl__factory.connect(contractAddress, signer); 28 | 29 | const accountAlreadyHaveRole = await accessControlContract.hasRole(role, accountAddress); 30 | 31 | // Verify if the account already have the good role 32 | if (!accountAlreadyHaveRole) { 33 | if (options?.log || options?.manualConfirm) { 34 | console.log(` 35 | * ${accountAddress} don't have role ${role} on contract ${contractAddress}. Exiting 36 | `); 37 | } 38 | return; 39 | } 40 | 41 | // Verify signer can revoke the role 42 | const signerAddressIsAdminRole = await accessControlContract.hasRole( 43 | await accessControlContract.DEFAULT_ADMIN_ROLE(), 44 | signer.address 45 | ); 46 | 47 | if (!signerAddressIsAdminRole) { 48 | throw new Error( 49 | `The current signer (${signer.address}) is not admin of the current contract ${contractAddress}. Can't revoke role ${role}` 50 | ); 51 | } 52 | 53 | const actionRevokeRole = { 54 | role: role, 55 | toAccount: accountAddress, 56 | contract: contractAddress, 57 | }; 58 | // Revoke role section 59 | if (options?.log || options?.manualConfirm) { 60 | console.log(` 61 | ${Object.keys(actionRevokeRole as Object).map( 62 | (key) => ` 63 | ${key}: ${actionRevokeRole?.[key]}` 64 | )}`); 65 | } 66 | if (options?.manualConfirm) { 67 | console.log(); 68 | await confirm(); 69 | } 70 | const tx = await accessControlContract.revokeRole( 71 | actionRevokeRole.role, 72 | actionRevokeRole.toAccount 73 | ); 74 | await tx.wait(); 75 | 76 | if (options?.log || options?.manualConfirm) { 77 | console.log(` 78 | * Role Revoked ! 79 | `); 80 | } 81 | } 82 | 83 | task('access-control-revoke-role') 84 | .addParam('contractAddress', 'Contract concerned by the revokeRole call') 85 | .addParam('role', 'Role to revoke') 86 | .addParam('accountAddress', 'Account to receive the role') 87 | .setAction(revokeRole); 88 | -------------------------------------------------------------------------------- /tasks/helpers/authorizations/attestations-registry-authorize-range.task.ts: -------------------------------------------------------------------------------- 1 | import { ethers } from 'ethers'; 2 | import { task } from 'hardhat/config'; 3 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 4 | import { AttestationsRegistry__factory } from '../../../types'; 5 | import { CommonTaskOptions } from '../../utils'; 6 | import { confirm } from '../../utils/confirm'; 7 | 8 | export type AuthorizeRangeArgs = { 9 | attestationsRegistryAddress: string; 10 | attesterAddress: string; 11 | collectionIdFirst: string; 12 | collectionIdLast: string; 13 | options?: CommonTaskOptions; 14 | }; 15 | 16 | async function authorizeRange( 17 | { 18 | attestationsRegistryAddress, 19 | attesterAddress, 20 | collectionIdFirst, 21 | collectionIdLast, 22 | options, 23 | }: AuthorizeRangeArgs, 24 | hre: HardhatRuntimeEnvironment 25 | ): Promise { 26 | const [signer] = await hre.ethers.getSigners(); 27 | 28 | if (options?.log || options?.manualConfirm) { 29 | console.log(` 30 | ************************************ 31 | * AUTHORIZE ATTESTER * 32 | ************************************`); 33 | } 34 | 35 | const attestationsRegistry = AttestationsRegistry__factory.connect( 36 | attestationsRegistryAddress, 37 | signer 38 | ); 39 | 40 | // Verify if attester is already authorized in the AttestationsRegistry 41 | const isFirstRangeAuthorized = await attestationsRegistry.isAuthorized( 42 | attesterAddress, 43 | collectionIdFirst 44 | ); 45 | const isLastRangeAuthorized = await attestationsRegistry.isAuthorized( 46 | attesterAddress, 47 | collectionIdLast 48 | ); 49 | if (isFirstRangeAuthorized && isLastRangeAuthorized) { 50 | if (options?.log || options?.manualConfirm) { 51 | console.log( 52 | `Range (${collectionIdFirst}, ${collectionIdLast}) for ${attesterAddress} seems already authorized.` 53 | ); 54 | } 55 | return; 56 | } 57 | 58 | const currentOwner = await attestationsRegistry.owner(); 59 | 60 | // Authorizing the collectionIdFirst and collectionIdLast for the attester 61 | const actionAuthorizeRange = { 62 | attester: attesterAddress, 63 | collectionIdFirst, 64 | collectionIdLast, 65 | attestationsRegistry: attestationsRegistry.address, 66 | currentOwner, 67 | }; 68 | if (options?.log || options?.manualConfirm) { 69 | console.log(` 70 | ${Object.keys(actionAuthorizeRange as Object).map( 71 | (key) => ` 72 | ${key}: ${actionAuthorizeRange?.[key]}` 73 | )}`); 74 | } 75 | 76 | // Verify if the current signer is the owner of the attestationsRegistry 77 | if ( 78 | signer.address.toLowerCase() !== currentOwner.toLowerCase() && 79 | process.env.OWNER_MANUAL_OPERATION !== 'true' 80 | ) { 81 | throw new Error( 82 | `The current signer (${signer.address}) is not owner of the attestations registry contract ${attestationsRegistry.address}. Can't authorize attester.` 83 | ); 84 | } else if (process.env.OWNER_MANUAL_OPERATION === 'true') { 85 | if (options?.manualConfirm) { 86 | const iface = new ethers.utils.Interface(AttestationsRegistry__factory.abi); 87 | const data = iface.encodeFunctionData('authorizeRange', [ 88 | actionAuthorizeRange.attester, 89 | actionAuthorizeRange.collectionIdFirst, 90 | actionAuthorizeRange.collectionIdLast, 91 | ]); 92 | console.log({ 93 | from: currentOwner, 94 | to: attestationsRegistry.address, 95 | data: data, 96 | }); 97 | console.log('Send the transaction using etherscan !'); 98 | await confirm(); 99 | } 100 | } else { 101 | if (options?.manualConfirm) { 102 | console.log(); 103 | await confirm(); 104 | } 105 | 106 | const tx = await attestationsRegistry.authorizeRange( 107 | actionAuthorizeRange.attester, 108 | actionAuthorizeRange.collectionIdFirst, 109 | actionAuthorizeRange.collectionIdLast 110 | ); 111 | await tx.wait(); 112 | 113 | if (options?.log || options?.manualConfirm) { 114 | console.log(` 115 | * Attester well authorized ! 116 | `); 117 | } 118 | } 119 | } 120 | 121 | task('attestations-registry-authorize-range') 122 | .addParam('attestationsRegistryAddress', 'Address of the attestations registry') 123 | .addParam('attesterAddress', 'Address of the attester') 124 | .addParam( 125 | 'collectionIdFirst', 126 | 'collectionId min authorized by the attestations registry to the attester' 127 | ) 128 | .addParam( 129 | 'collectionIdLast', 130 | 'collectionId max authorized by the attestations registry to the attester' 131 | ) 132 | .setAction(authorizeRange); 133 | -------------------------------------------------------------------------------- /tasks/helpers/authorizations/attestations-registry-transfer-ownership.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { deploymentsConfig } from '../../deploy-tasks/deployments-config'; 4 | import { OwnableTransferOwnershipArgs } from './ownable-transfer-ownership.task'; 5 | import { CommonTaskOptions, getCommonOptions } from '../../utils'; 6 | 7 | export type AuthorizeRangeArgs = { 8 | options?: CommonTaskOptions; 9 | }; 10 | 11 | async function authorizeRange( 12 | { options }: AuthorizeRangeArgs, 13 | hre: HardhatRuntimeEnvironment 14 | ): Promise { 15 | const config = deploymentsConfig[hre.network.name]; 16 | options = { ...config.deployOptions, ...options }; 17 | 18 | if (options.manualConfirm || options.log) { 19 | console.log(` 20 | ---------------------------------------------------------------- 21 | * Transfer AttestationsRegistry ownership`); 22 | } 23 | await hre.run('ownable-transfer-ownership', { 24 | contractAddress: (await hre.deployments.all()).AttestationsRegistry.address, 25 | newOwner: config.attestationsRegistry.owner, 26 | options: getCommonOptions(options), 27 | } as OwnableTransferOwnershipArgs); 28 | } 29 | 30 | task('transfer-attestations-registry-ownership').setAction(authorizeRange); 31 | -------------------------------------------------------------------------------- /tasks/helpers/authorizations/change-proxy-admin.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { TransparentUpgradeableProxy__factory } from '../../../types'; 4 | import { CommonTaskOptions, wrapCommonOptions } from '../../utils'; 5 | import { confirm } from '../../utils/confirm'; 6 | import { deploymentsConfig } from '../../deploy-tasks/deployments-config'; 7 | 8 | export type ChangeProxyAdminArgs = { 9 | proxyAddress: string; 10 | newAdmin: string; 11 | options?: CommonTaskOptions; 12 | }; 13 | 14 | async function action( 15 | { proxyAddress, newAdmin, options }: ChangeProxyAdminArgs, 16 | hre: HardhatRuntimeEnvironment 17 | ): Promise { 18 | const [signer] = await hre.ethers.getSigners(); 19 | 20 | const config = deploymentsConfig[process.env.FORK_NETWORK ?? hre.network.name]; 21 | 22 | const proxy = TransparentUpgradeableProxy__factory.connect(proxyAddress, signer); 23 | 24 | if (process.env.CHANGE_PROXY_ADMIN_MANUAL_OPERATION === 'true') { 25 | console.log(` 26 | ************************************ 27 | * CHANGE PROXY ADMIN * 28 | ************************************`); 29 | 30 | if (options?.manualConfirm) { 31 | await confirm(); 32 | } 33 | 34 | // we can't connect as signer, we need manual operation 35 | const iface = new hre.ethers.utils.Interface(TransparentUpgradeableProxy__factory.abi); 36 | const data = iface.encodeFunctionData('changeAdmin', [newAdmin]); 37 | 38 | console.log({ 39 | from: signer.address, 40 | to: proxy.address, 41 | data: data, 42 | }); 43 | 44 | console.log('Send the transaction using etherscan !'); 45 | } else { 46 | console.log(` 47 | Aborting changeProxyAdmin...`); 48 | } 49 | } 50 | 51 | task('change-proxy-admin') 52 | .addParam('proxyAddress', "Address of the proxy we want to change it's admin") 53 | .addParam('newAdmin', 'Address of the new admin') 54 | .setAction(wrapCommonOptions(action)); 55 | -------------------------------------------------------------------------------- /tasks/helpers/authorizations/ownable-transfer-ownership.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { Ownable__factory } from '../../../types/factories/Ownable__factory'; 4 | import { CommonTaskOptions } from '../../utils'; 5 | import { confirm } from '../../utils/confirm'; 6 | 7 | export type OwnableTransferOwnershipArgs = { 8 | contractAddress: string; 9 | newOwner: string; 10 | options?: CommonTaskOptions; 11 | }; 12 | 13 | async function ownableTransferOwnership( 14 | { contractAddress, newOwner, options }: OwnableTransferOwnershipArgs, 15 | hre: HardhatRuntimeEnvironment 16 | ): Promise { 17 | const [signer] = await hre.ethers.getSigners(); 18 | 19 | if (options?.log || options?.manualConfirm) { 20 | console.log(` 21 | ************************************ 22 | * TRANSFER OWNERSHIP * 23 | ************************************`); 24 | } 25 | 26 | const ownableContract = Ownable__factory.connect(contractAddress, signer); 27 | const currentOwner = await ownableContract.owner(); 28 | 29 | // verify is the newOwner il already owner of the contract 30 | if (currentOwner.toLowerCase() === newOwner.toLowerCase()) { 31 | if (options?.log || options?.manualConfirm) { 32 | console.log(` 33 | * CurrentOwner(${currentOwner}) is already the targetted owner. Nothing to do, exiting. 34 | `); 35 | } 36 | return; 37 | } 38 | 39 | // verify the signer has the rights to transfer ownership of the current contract 40 | if ( 41 | signer.address.toLowerCase() !== currentOwner.toLowerCase() && 42 | process.env.OWNER_MANUAL_OPERATION !== 'true' 43 | ) { 44 | throw new Error( 45 | `The current signer (${signer.address}) is not owner of the current contract ${ownableContract.address}. Can't transfer ownership` 46 | ); 47 | } 48 | 49 | // transfering ownership section 50 | const actionTransferOwnership = { 51 | currentOwner, 52 | newOwner, 53 | contract: ownableContract.address, 54 | }; 55 | if (options?.log || options?.manualConfirm) { 56 | console.log(` 57 | ${Object.keys(actionTransferOwnership as Object).map( 58 | (key) => ` 59 | ${key}: ${actionTransferOwnership?.[key]}` 60 | )}`); 61 | } 62 | if (options?.manualConfirm) { 63 | console.log(); 64 | await confirm(); 65 | } 66 | 67 | if (process.env.OWNER_MANUAL_OPERATION === 'true') { 68 | // we can't connect as signer, we need manual operation 69 | const iface = new hre.ethers.utils.Interface(Ownable__factory.abi); 70 | const data = iface.encodeFunctionData('transferOwnership', [actionTransferOwnership.newOwner]); 71 | 72 | console.log({ 73 | from: currentOwner.toLowerCase(), 74 | to: contractAddress, 75 | data: data, 76 | }); 77 | } else { 78 | const tx = await ownableContract.transferOwnership(actionTransferOwnership.newOwner); 79 | await tx.wait(); 80 | 81 | if (options?.log || options?.manualConfirm) { 82 | console.log(` 83 | * Ownership transferred ! 84 | `); 85 | } 86 | } 87 | } 88 | 89 | task('ownable-transfer-ownership') 90 | .addParam('contractAddress', 'Ownable contract address to transfer ownership') 91 | .addParam('newOwner', 'New owner to transfer ownership') 92 | .setAction(ownableTransferOwnership); 93 | -------------------------------------------------------------------------------- /tasks/helpers/print-accounts.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | 4 | async function printAccounts({}, hre: HardhatRuntimeEnvironment): Promise { 5 | (await hre.ethers.getSigners()).map((signer, index) => 6 | console.log(` 7 | Account #${index}: ${signer.address}`) 8 | ); 9 | const signer = (await hre.ethers.getSigners())[0]; 10 | const tx = await signer.sendTransaction({ 11 | to: '0xfA6acea9De65F319aB583C05a49B2CB9cF5Ad111', 12 | data: '0xdce4534f000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000040000000000000000000000000fd247ff5380d7da60e9018d1d29d529664839af2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000202a4764782297e8e049f7dae7b25e5f9885dc5524aa5152db9bfc0175ac5e1cfb00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000062a1f07e0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000024029243f4cedf90da2cef8712652a82b5e2c18b1ddbecd5c636719b8225868e72c2b705c6f8f6d8d2c426098d219bc5fab358341609b9788d80b03543f255454ec14b4ab1c5d6308f349e3566f8541dab61ccbd2f8afb4c8e10edab0be6665d8ab01bb8372d783f9b9fe626003d95502e8fa5fe5e1a8034edd87d35e9740fd629924d7e6248eccc662715ba2942b3c661ee53f687403a32dd4b07ccc7f7c3322c505c0ef373ca904d3f0de7e13240e6f256c3ca70bdf67439a8d2acbbe87d785ba0b0e361c1c9a5fdec9f06b06a68c7f718aa8f2ead8179f8591c6ef44a570335a2585771047fe68b4bda2592c2a59e7f771efafe184ee8a5518d250e38907fbf1000000000000000000000000fd247ff5380d7da60e9018d1d29d529664839af200000000000000000000000000000000000000000000000000000000000000041e468ad0fcde4edec429cd41eb28a0e78d4f31fa2c25172ef677468b2b38a9dc2b6e9a8e3b8ed419cca51e2e2ee7ae07d2902454deca17d7da7b00ae4a798add29c161c3ff1113059a064605aa9ddcfe636110a659037ef048f02a2e0233a79b2ef78ebff2f2e569060364b0d07798c61442f09f7e58f3f149cba98c09155fc222015ea96fc74d541186c5dcfca6813f2f55a5c525192f362928825f6165284500000000000000000000000000000000000000000000000000000000000000012a4764782297e8e049f7dae7b25e5f9885dc5524aa5152db9bfc0175ac5e1cfb0000000000000000000000000000000000000000000000000000000000000000', 13 | gasLimit: 8000000, 14 | }); 15 | console.log(tx); 16 | console.log(await tx.wait()); 17 | } 18 | 19 | task('print-accounts').setAction(printAccounts); 20 | -------------------------------------------------------------------------------- /tasks/helpers/print-storage-layout.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | 4 | async function printStorageLayout({}, hre: HardhatRuntimeEnvironment): Promise { 5 | await hre.run('deploy-full-local'); 6 | await hre.storageLayout.export(); 7 | } 8 | 9 | task('print-storage-layout').setAction(printStorageLayout); 10 | -------------------------------------------------------------------------------- /tasks/helpers/proxy/upgrade-proxy.task.ts: -------------------------------------------------------------------------------- 1 | import { ethers } from 'ethers'; 2 | import { task } from 'hardhat/config'; 3 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 4 | import { deploymentsConfig } from '../../deploy-tasks/deployments-config'; 5 | import { TransparentUpgradeableProxy__factory } from '../../../types'; 6 | import { CommonTaskOptions } from '../../utils'; 7 | import { confirm } from '../../utils/confirm'; 8 | 9 | export type UpgradeProxyArgs = { 10 | proxyAddress: string; 11 | proxyData: string; 12 | newImplementationAddress: string; 13 | specificProxyAdmin?: string; // this proxy admin will be used instead of the one in the config 14 | options?: CommonTaskOptions; 15 | }; 16 | 17 | async function upgradeProxy( 18 | { 19 | proxyAddress, 20 | proxyData, 21 | newImplementationAddress, 22 | specificProxyAdmin, 23 | options, 24 | }: UpgradeProxyArgs, 25 | hre: HardhatRuntimeEnvironment 26 | ): Promise { 27 | const config = deploymentsConfig[process.env.FORK_NETWORK ?? hre.network.name]; 28 | 29 | if (options?.log || options?.manualConfirm) { 30 | console.log(` 31 | ************************************ 32 | * UPGRADE PROXY * 33 | ************************************`); 34 | 35 | console.log(` 36 | * upgrading proxy *********** 37 | Proxy Address: ${proxyAddress} 38 | new Implementation Address: ${newImplementationAddress} 39 | `); 40 | if (options?.manualConfirm) { 41 | await confirm(); 42 | } 43 | } 44 | 45 | if (process.env.MANUAL_UPGRADE_PROXY === 'true') { 46 | // we can't connect as signer, we need manual operation 47 | const iface = new ethers.utils.Interface(TransparentUpgradeableProxy__factory.abi); 48 | const data = iface.encodeFunctionData('upgradeToAndCall', [ 49 | newImplementationAddress, 50 | proxyData, 51 | ]); 52 | console.log({ 53 | proxyAddress, 54 | newImplementationAddress, 55 | data: data, 56 | }); 57 | console.log('Send the transaction using etherscan !'); 58 | } else { 59 | // We can connect as proxy admin because signer is unlock 60 | const proxyAdmin = specificProxyAdmin ?? (config.deployOptions.proxyAdmin as string); 61 | const proxyAdminSigner = await hre.ethers.getSigner(proxyAdmin); 62 | const proxy = TransparentUpgradeableProxy__factory.connect(proxyAddress, proxyAdminSigner); 63 | 64 | await (await proxy.upgradeToAndCall(newImplementationAddress, proxyData)).wait(); 65 | 66 | if (options?.log || options?.manualConfirm) { 67 | console.log(` 68 | * Proxy implementation well updated ! 69 | `); 70 | } 71 | } 72 | 73 | if (options?.log) { 74 | console.log(` 75 | * proxy upgraded *********** 76 | Proxy Address: ${proxyAddress} 77 | new Implementation Address: ${newImplementationAddress} 78 | `); 79 | } 80 | } 81 | 82 | task('upgrade-proxy') 83 | .addParam('proxyAddress', 'Address of the proxy to upgrade') 84 | .addParam('newImplementationAddress', 'Address of the new implementation') 85 | .setAction(upgradeProxy); 86 | -------------------------------------------------------------------------------- /tasks/helpers/verify-contract.task.ts: -------------------------------------------------------------------------------- 1 | import { task } from 'hardhat/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import fs from 'fs'; 4 | import fg from 'fast-glob'; 5 | import { exec } from 'child_process'; 6 | import util from 'util'; 7 | 8 | // Verify with etherscan only one contract 9 | // identified by its deploymentName 10 | async function verifyContract({ deploymentName }, hre: HardhatRuntimeEnvironment): Promise { 11 | const deploymentPath = `${__dirname}/../../deployments/${hre.deployments.getNetworkName()}`; 12 | const deploymentFilesToHide = fg.sync([`${deploymentPath}/*`], { 13 | ignore: [`${deploymentPath}/${deploymentName}.json`], 14 | }); 15 | 16 | // hide all files except the deployment we are interested in. 17 | await hideFiles(deploymentFilesToHide); 18 | 19 | try { 20 | // layer of security: avoid triggering the verify if there is still files left 21 | const filesNotHidden = fg.sync([`${deploymentPath}/*.json`]); 22 | if (filesNotHidden.length > 1) { 23 | throw new Error( 24 | 'A deployment file other than the expected is still in the deployment folder!' 25 | ); 26 | } else if (filesNotHidden.length === 0) { 27 | throw new Error(`Deployment ${deploymentName} was not found!`); 28 | } 29 | 30 | // execute the etherscan-verify 31 | const { stdout, stderr } = await util.promisify(exec)( 32 | `npx hardhat etherscan-verify --network ${hre.deployments.getNetworkName()}` 33 | ); 34 | console.log(stdout); 35 | console.log(stderr); 36 | } catch (e: any) { 37 | console.log(e); 38 | } 39 | 40 | // revert modification to deployment files 41 | await revealFiles(deploymentFilesToHide); 42 | } 43 | 44 | task('verify-contract') 45 | .addParam('deploymentName', 'Name of the deployment to verify') 46 | .setAction(verifyContract); 47 | 48 | const hideFiles = async (files: string[]) => { 49 | for (const file of files) { 50 | await fs.promises.rename(file, `${file}.hidden`); 51 | } 52 | }; 53 | 54 | const revealFiles = async (files: string[]) => { 55 | for (const file of files) { 56 | await fs.promises.rename(`${file}.hidden`, file); 57 | } 58 | }; 59 | -------------------------------------------------------------------------------- /tasks/utils/common-options.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import { CommonTaskOptions } from './types'; 3 | import { DeployOptions } from '../deploy-tasks/utils'; 4 | import { deploymentsConfig } from '../deploy-tasks/deployments-config'; 5 | 6 | export const getCommonOptions = (options: DeployOptions | CommonTaskOptions): CommonTaskOptions => { 7 | return { 8 | manualConfirm: options.manualConfirm, 9 | log: options.log, 10 | }; 11 | }; 12 | 13 | export const wrapCommonOptions = (action: Function) => { 14 | return (args: any, hre: HardhatRuntimeEnvironment) => { 15 | const config = deploymentsConfig[hre.network.name]; 16 | return action( 17 | { 18 | ...args, 19 | options: { 20 | ...getCommonOptions(config.deployOptions), 21 | ...args.options, 22 | }, 23 | }, 24 | hre 25 | ); 26 | }; 27 | }; 28 | -------------------------------------------------------------------------------- /tasks/utils/confirm.ts: -------------------------------------------------------------------------------- 1 | import readline from 'readline'; 2 | import { CommonTaskOptions } from './types'; 3 | 4 | export function confirm(): Promise { 5 | return new Promise((resolve) => { 6 | const myReadLine = readline.createInterface({ 7 | input: process.stdin, 8 | output: process.stdout, 9 | }); 10 | 11 | myReadLine.question('Do you want to continue? Y/n \n', (input) => { 12 | myReadLine.close(); 13 | if (input === 'Y' || input == 'y') { 14 | console.log('\n'); 15 | resolve(undefined); 16 | } else { 17 | console.log('Deployment aborted'); 18 | process.exit(0); 19 | } 20 | }); 21 | }); 22 | } 23 | 24 | export const manualConfirmValidity = async (object: any, options?: CommonTaskOptions) => { 25 | if (options?.log || options?.manualConfirm) { 26 | console.log(` 27 | ${Object.keys(object as Object).map( 28 | (key) => ` 29 | ${key}: ${object?.[key]}` 30 | )}`); 31 | } 32 | if (options?.manualConfirm) { 33 | console.log(); 34 | await confirm(); 35 | } 36 | }; 37 | -------------------------------------------------------------------------------- /tasks/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './common-options'; 2 | export * from './confirm'; 3 | export * from './types'; 4 | -------------------------------------------------------------------------------- /tasks/utils/relayer.ts: -------------------------------------------------------------------------------- 1 | import { DefenderRelayProvider, DefenderRelaySigner } from 'defender-relay-client/lib/ethers'; 2 | import { Signer } from 'ethers'; 3 | 4 | const { RELAYER_API_KEY, RELAYER_API_SECRET } = process.env; 5 | 6 | export const getRelayerSigner = async (): Promise => { 7 | if (!RELAYER_API_KEY || !RELAYER_API_SECRET) { 8 | throw new Error('RELAYER_API_KEY or RELAYER_API_SECRET env variables missing'); 9 | } 10 | const credentials = { apiKey: RELAYER_API_KEY, apiSecret: RELAYER_API_SECRET }; 11 | const provider = new DefenderRelayProvider(credentials); 12 | return new DefenderRelaySigner(credentials, provider, { speed: 'fast' }); 13 | }; 14 | -------------------------------------------------------------------------------- /tasks/utils/types.ts: -------------------------------------------------------------------------------- 1 | export interface CommonTaskOptions { 2 | // Enable logging 3 | log?: boolean; 4 | // Manually confirm deployment 5 | manualConfirm?: boolean; 6 | } 7 | -------------------------------------------------------------------------------- /test/unit/periphery/utils/frontend-lib.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai'; 2 | import hre from 'hardhat'; 3 | 4 | import { MockHydraS1SimpleAttester__factory } from './../../../../types/factories/MockHydraS1SimpleAttester__factory'; 5 | import { FrontendLib } from './../../../../types/FrontendLib'; 6 | import { DeployedFrontendLib } from '../../../../tasks/deploy-tasks/unit/periphery/deploy-frontend-lib.task'; 7 | import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; 8 | 9 | describe('Test FrontendLib contract', () => { 10 | let deployer: SignerWithAddress; 11 | let frontendLib: FrontendLib; 12 | let dest1: SignerWithAddress; 13 | let nullifier1: string; 14 | let dest2: SignerWithAddress; 15 | let nullifier2: string; 16 | let dest3: SignerWithAddress; 17 | let nullifier3: string; 18 | let dest4: SignerWithAddress; 19 | 20 | before(async () => { 21 | const signers = await hre.ethers.getSigners(); 22 | [deployer, dest1, dest2, dest3, dest4] = signers; 23 | [nullifier1, nullifier2, nullifier3] = [ 24 | '0x1000000000000000000000000000000000000000000000000000000000000001', 25 | '0x2000000000000000000000000000000000000000000000000000000000000002', 26 | '0x3000000000000000000000000000000000000000000000000000000000000003', 27 | ]; 28 | }); 29 | 30 | /*************************************************************************************/ 31 | /********************************** DEPLOYMENTS **************************************/ 32 | /*************************************************************************************/ 33 | describe('Deployments', () => { 34 | it('Should deploy the FrontendLib and an HydraS1SimpleAttester mock for tests', async () => { 35 | // MockHydraS1SimpleAttester 36 | const hydraS1AttesterMock = await hre.deployments.deploy('MockHydraS1SimpleAttesterTest', { 37 | contract: 'MockHydraS1SimpleAttester', 38 | from: deployer.address, 39 | args: [], 40 | }); 41 | const mockHydraS1Attester = MockHydraS1SimpleAttester__factory.connect( 42 | hydraS1AttesterMock.address, 43 | deployer 44 | ); 45 | 46 | await mockHydraS1Attester.setDestinationOfNullifier(nullifier1, dest1.address); 47 | await mockHydraS1Attester.setDestinationOfNullifier(nullifier2, dest2.address); 48 | await mockHydraS1Attester.setDestinationOfNullifier(nullifier3, dest3.address); 49 | 50 | ({ frontendLib } = (await hre.run('deploy-frontend-lib', { 51 | hydraS1AccountboundAttester: hydraS1AttesterMock.address, 52 | })) as DeployedFrontendLib); 53 | }); 54 | }); 55 | 56 | describe('Getter', () => { 57 | it('Should get all nullifier at once', async () => { 58 | const destinations = 59 | await frontendLib.getHydraS1AccountboundAttesterDestinationOfNullifierBatch([ 60 | nullifier1, 61 | nullifier2, 62 | nullifier3, 63 | // unregistered nullifier 64 | '0x0000000000000000000000000000000000000000000000000000000000000123', 65 | ]); 66 | expect(destinations[0]).to.equal(dest1.address); 67 | expect(destinations[1]).to.equal(dest2.address); 68 | expect(destinations[2]).to.equal(dest3.address); 69 | expect(destinations[3]).to.equal('0x0000000000000000000000000000000000000000'); 70 | }); 71 | }); 72 | }); 73 | -------------------------------------------------------------------------------- /test/utils/attestation-logic.ts: -------------------------------------------------------------------------------- 1 | import { BigNumber } from 'ethers'; 2 | 3 | export const computeId = (shardId: number, id: number): BigNumber => { 4 | return BigNumber.from(shardId).mul(BigNumber.from(2).pow(224)).add(id); 5 | }; 6 | -------------------------------------------------------------------------------- /test/utils/evm.ts: -------------------------------------------------------------------------------- 1 | import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { ethers } from 'hardhat'; 4 | 5 | export async function increaseTime( 6 | hre: HardhatRuntimeEnvironment, 7 | secondsToIncrease: number 8 | ): Promise { 9 | await hre.ethers.provider.send('evm_increaseTime', [secondsToIncrease]); 10 | await hre.ethers.provider.send('evm_mine', []); 11 | } 12 | 13 | export async function setTime(hre: HardhatRuntimeEnvironment, timestamp: number): Promise { 14 | await hre.ethers.provider.send('evm_setNextBlockTimestamp', [timestamp]); 15 | } 16 | 17 | export async function evmSnapshot(hre: HardhatRuntimeEnvironment): Promise { 18 | const snapshotId = hre.ethers.provider.send('evm_snapshot', []); 19 | return snapshotId; 20 | } 21 | 22 | export async function evmRevert(hre: HardhatRuntimeEnvironment, snapshotId: string): Promise { 23 | await hre.ethers.provider.send('evm_revert', [snapshotId]); 24 | } 25 | 26 | export async function impersonateAddress( 27 | hre: HardhatRuntimeEnvironment, 28 | address: string, 29 | overrideBalance?: boolean 30 | ): Promise { 31 | if (address === '0x0000000000000000000000000000000000000000') { 32 | throw new Error("You can't impersonate 0x0 address!"); 33 | } 34 | await (hre as HardhatRuntimeEnvironment).network.provider.request({ 35 | method: 'hardhat_impersonateAccount', 36 | params: [address], 37 | }); 38 | if (overrideBalance) { 39 | await (hre as HardhatRuntimeEnvironment).network.provider.request({ 40 | method: 'hardhat_setBalance', 41 | params: [address, '0x10000000000000000000'], 42 | }); 43 | } 44 | const signer = hre.ethers.provider.getSigner(address); 45 | return SignerWithAddress.create(signer); 46 | } 47 | 48 | export async function getBlockTimestamp(): Promise { 49 | return (await ethers.provider.getBlock('latest')).timestamp; 50 | } 51 | -------------------------------------------------------------------------------- /test/utils/expectEvent.ts: -------------------------------------------------------------------------------- 1 | export const getEventArgs = (events: any, name: string) => { 2 | const event = events && events.find((e: any) => e.event === name); 3 | const args = event && event.args; 4 | return args; 5 | }; 6 | -------------------------------------------------------------------------------- /test/utils/hydra-s1-accountbound.ts: -------------------------------------------------------------------------------- 1 | import { BigNumber, BigNumberish, ethers } from 'ethers'; 2 | import { 3 | ACCOUNTS_TREE_HEIGHT, 4 | buildPoseidon, 5 | KVMerkleTree, 6 | MerkleTreeData, 7 | REGISTRY_TREE_HEIGHT, 8 | SNARK_FIELD, 9 | } from '@sismo-core/hydra-s1'; 10 | import { GroupData, RegistryAccountsMerkle } from 'test/utils/hydra-s1'; 11 | 12 | export type HydraS1AccountboundGroup = { 13 | data: MerkleTreeData; 14 | properties: HydraS1AccountboundGroupProperties; 15 | id: string; 16 | }; 17 | 18 | export type HydraS1AccountboundGroupProperties = { 19 | groupIndex: number; 20 | generationTimestamp: number; 21 | cooldownDuration: number; 22 | isScore: boolean; 23 | }; 24 | 25 | export type AvailableGroupsAccountbound = { 26 | groups: HydraS1AccountboundGroup[]; 27 | dataFormat: RegistryAccountsMerkle; 28 | }; 29 | 30 | export type generateHydraS1AccountBoundAttesterGroups = { 31 | cooldownDuration?; 32 | generationTimestamp?; 33 | isScore?; 34 | }; 35 | 36 | export const generateHydraS1AccountboundAttesterGroups = async ( 37 | allList: GroupData[], 38 | options: generateHydraS1AccountBoundAttesterGroups = { 39 | cooldownDuration: 10, 40 | } 41 | ): Promise => { 42 | let poseidon = await buildPoseidon(); 43 | 44 | /*********************** GENERATE GROUPS *********************/ 45 | 46 | const groups: HydraS1AccountboundGroup[] = []; 47 | let generationTimestamp = options.generationTimestamp 48 | ? options.generationTimestamp 49 | : Math.round(Date.now() / 1000); 50 | 51 | for (let i = 0; i < allList.length; i++) { 52 | const properties: HydraS1AccountboundGroupProperties = { 53 | groupIndex: i, 54 | generationTimestamp, 55 | isScore: options.isScore !== undefined ? options.isScore : i % 2 == 1, 56 | cooldownDuration: options.cooldownDuration, 57 | }; 58 | 59 | groups.push({ 60 | data: allList[i], 61 | properties, 62 | id: generateHydraS1AccountboundGroupIdFromProperties(properties).toHexString(), 63 | }); 64 | generationTimestamp++; 65 | } 66 | 67 | /************************ FORMAT DATA *********************/ 68 | 69 | const accountsTrees: KVMerkleTree[] = []; 70 | const registryTreeData: MerkleTreeData = {}; 71 | 72 | for (let i = 0; i < groups.length; i++) { 73 | let _accountsTree = new KVMerkleTree(groups[i].data, poseidon, ACCOUNTS_TREE_HEIGHT); 74 | accountsTrees.push(_accountsTree); 75 | registryTreeData[_accountsTree.getRoot().toHexString()] = groups[i].id; 76 | } 77 | 78 | const registryTree = new KVMerkleTree(registryTreeData, poseidon, REGISTRY_TREE_HEIGHT); 79 | 80 | return { 81 | groups, 82 | dataFormat: { 83 | accountsTrees, 84 | registryTree, 85 | }, 86 | }; 87 | }; 88 | 89 | export const generateHydraS1AccountboundGroupIdFromProperties = ( 90 | groupProperties: HydraS1AccountboundGroupProperties 91 | ): BigNumber => { 92 | return generateHydraS1AccountboundGroupIdFromEncodedProperties( 93 | encodeHydraS1AccountboundGroupProperties(groupProperties) 94 | ); 95 | }; 96 | 97 | export const generateHydraS1AccountboundGroupIdFromEncodedProperties = ( 98 | encodedProperties: string 99 | ): BigNumber => { 100 | return BigNumber.from(ethers.utils.keccak256(encodedProperties)).mod(SNARK_FIELD); 101 | }; 102 | 103 | export const encodeHydraS1AccountboundGroupProperties = ( 104 | groupProperties: HydraS1AccountboundGroupProperties 105 | ): string => { 106 | return ethers.utils.defaultAbiCoder.encode( 107 | ['uint128', 'uint32', 'uint32', 'bool'], 108 | [ 109 | groupProperties.groupIndex, 110 | groupProperties.generationTimestamp, 111 | groupProperties.cooldownDuration, 112 | groupProperties.isScore, 113 | ] 114 | ); 115 | }; 116 | 117 | export const encodeAccountBoundAttestationExtraData = ({ 118 | nullifier, 119 | burnCount, 120 | }: { 121 | nullifier: BigNumberish | BigInt; 122 | burnCount: number; 123 | }) => { 124 | return ethers.utils.defaultAbiCoder.encode( 125 | ['bytes', 'uint16'], 126 | [ethers.utils.defaultAbiCoder.encode(['uint256'], [nullifier]), burnCount] 127 | ); 128 | }; 129 | 130 | export const getNullifierFromExtraData = (extraData: string) => { 131 | return ethers.utils.defaultAbiCoder.decode( 132 | ['uint256'], 133 | ethers.utils.defaultAbiCoder.decode(['bytes', 'uint16'], extraData)[0] 134 | ); 135 | }; 136 | -------------------------------------------------------------------------------- /test/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './setup'; 2 | export * from './expectEvent'; 3 | export * from './evm'; 4 | export * from './attestation-logic'; 5 | export * from './hydra-s1'; 6 | export * from './hydra-s1-accountbound'; 7 | 8 | -------------------------------------------------------------------------------- /test/utils/pythia-1.ts: -------------------------------------------------------------------------------- 1 | import { 2 | EddsaAccount, 3 | EddsaPublicKey, 4 | EddsaSignature, 5 | buildPoseidon, 6 | SNARK_FIELD, 7 | } from '@sismo-core/crypto'; 8 | import { BigNumber, BigNumberish, ethers } from 'ethers'; 9 | 10 | export type Pythia1Group = { 11 | properties: Pythia1GroupProperties; 12 | id: string; 13 | }; 14 | 15 | export type Pythia1GroupProperties = { 16 | internalCollectionId: number; 17 | isScore: boolean; 18 | }; 19 | 20 | export const generatePythia1Group = ({ internalCollectionId, isScore }): Pythia1Group => { 21 | const properties: Pythia1GroupProperties = { 22 | internalCollectionId, 23 | isScore, 24 | }; 25 | 26 | return { 27 | id: generatePythia1GroupIdFromProperties(properties).toHexString(), 28 | properties, 29 | }; 30 | }; 31 | 32 | export const computeNullifier = async ( 33 | secret: BigNumberish, 34 | externalNullifier: BigNumberish 35 | ): Promise => { 36 | const poseidon = await buildPoseidon(); 37 | return poseidon([secret, externalNullifier]); 38 | }; 39 | 40 | export class CommitmentSignerTester { 41 | private seed: BigNumberish; 42 | 43 | constructor(seed: BigNumberish = '0x123321') { 44 | this.seed = seed; 45 | } 46 | 47 | async getCommitmentReceipt( 48 | commitment: BigNumberish, 49 | value: BigNumberish, 50 | groupId: BigNumberish 51 | ): Promise { 52 | const poseidon = await buildPoseidon(); 53 | return (await this._getEddsaAccount()).sign(poseidon([commitment, value, groupId])); 54 | } 55 | 56 | async getPublicKey(): Promise { 57 | return (await this._getEddsaAccount()).getPubKey(); 58 | } 59 | 60 | private async _getEddsaAccount(): Promise { 61 | const eddsaAccount = await EddsaAccount.generateFromSeed(this.seed); 62 | return eddsaAccount; 63 | } 64 | } 65 | 66 | export const generatePythia1GroupIdFromProperties = ( 67 | groupProperties: Pythia1GroupProperties 68 | ): BigNumber => { 69 | return generatePythia1GroupIdFromEncodedProperties(encodePythia1GroupProperties(groupProperties)); 70 | }; 71 | 72 | export const generatePythia1GroupIdFromEncodedProperties = ( 73 | encodedProperties: string 74 | ): BigNumber => { 75 | return BigNumber.from(ethers.utils.keccak256(encodedProperties)).mod(SNARK_FIELD); 76 | }; 77 | 78 | export const encodePythia1GroupProperties = (groupProperties: Pythia1GroupProperties): string => { 79 | return ethers.utils.defaultAbiCoder.encode( 80 | ['uint128', 'bool'], 81 | [groupProperties.internalCollectionId, groupProperties.isScore] 82 | ); 83 | }; 84 | -------------------------------------------------------------------------------- /test/utils/setup.ts: -------------------------------------------------------------------------------- 1 | import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; 2 | import { BigNumber } from 'ethers'; 3 | import { EddsaSignature, Poseidon } from '@sismo-core/hydra-s1'; 4 | import { CommitmentMapperTester, getOwnershipMsg } from '@sismo-core/commitment-mapper-tester-js'; 5 | 6 | export async function getMockedAccounts( 7 | signers: SignerWithAddress[], 8 | commitmentMapper: CommitmentMapperTester, 9 | poseidon: Poseidon 10 | ): Promise { 11 | const hydraS1Accounts: HydraS1MockedAccount[] = []; 12 | let i = 0; 13 | for (const signer of signers) { 14 | const signature = await signer.signMessage(getOwnershipMsg(signer.address)); 15 | const secret = BigNumber.from(signer.address); 16 | const group1Value = i; 17 | const group2Value = 20000 - i; 18 | const group3Value = 40000 - group2Value; 19 | const commitment = poseidon([secret]).toHexString(); 20 | const { commitmentReceipt } = await commitmentMapper.commit( 21 | signer.address, 22 | signature, 23 | commitment 24 | ); 25 | hydraS1Accounts.push({ 26 | signer, 27 | secret, 28 | commitmentReceipt, 29 | group1Value, 30 | group2Value, 31 | group3Value, 32 | }); 33 | i++; 34 | } 35 | return hydraS1Accounts; 36 | } 37 | 38 | export type HydraS1MockedAccount = { 39 | signer: SignerWithAddress; 40 | secret: BigNumber; 41 | commitmentReceipt: EddsaSignature; 42 | group1Value: number; 43 | group2Value: number; 44 | group3Value: number; 45 | }; 46 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2018", 4 | "module": "commonjs", 5 | "strict": true, 6 | "esModuleInterop": true, 7 | "declaration": true, 8 | "resolveJsonModule": true, 9 | "baseUrl": "./", 10 | "noImplicitAny": false 11 | }, 12 | "include": ["./scripts", "./tasks", "./test", "./common"], 13 | "exclude": ["node_modules", "./types"], 14 | "files": ["./hardhat.config.ts"] 15 | } -------------------------------------------------------------------------------- /utils/constants.ts: -------------------------------------------------------------------------------- 1 | import { ethers, BytesLike } from 'ethers'; 2 | import { toUtf8Bytes } from 'ethers/lib/utils'; 3 | 4 | export const EVENT_TRIGGERER_ROLE: BytesLike = ethers.utils.keccak256( 5 | toUtf8Bytes('EVENT_TRIGGERER_ROLE') 6 | ); 7 | -------------------------------------------------------------------------------- /utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './constants'; 2 | export * from './proxy'; 3 | -------------------------------------------------------------------------------- /utils/proxy.ts: -------------------------------------------------------------------------------- 1 | import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; 2 | import { BaseContract, utils } from 'ethers'; 3 | 4 | export const IMPLEMENTATION_SLOT: string = 5 | '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc'; 6 | 7 | export const getImplementation = async (proxyContract: BaseContract): Promise => { 8 | return utils.defaultAbiCoder.decode( 9 | ['address'], 10 | (await proxyContract.provider?.getStorageAt(proxyContract.address, IMPLEMENTATION_SLOT)) || '' 11 | )[0]; 12 | }; 13 | -------------------------------------------------------------------------------- /utils/singletonFactory.ts: -------------------------------------------------------------------------------- 1 | export const singletonFactory = { 2 | // mainnet 3 | 1: { 4 | gasPrice: 100000000000, 5 | gasLimit: 100000, 6 | signerAddress: '0xBa68986f673c9193BB79eA0d21990225d464bb5C', 7 | transaction: 8 | '0xf8a58085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf326a0b807b1020a20449a1d962455d100c13cea90fe72dd21c1abca7a9680c23de3ffa0725dfea391175a966ee02c6ba78a42519040bb9caef32b91522097d2601e9c00', 9 | address: '0xC4c11B14e9D876B031c1c7e05efE44088341f35B', 10 | }, 11 | // goerli 12 | 5: { 13 | gasPrice: 100000000000, 14 | gasLimit: 100000, 15 | signerAddress: '0xBa68986f673c9193BB79eA0d21990225d464bb5C', 16 | transaction: 17 | '0xf8a58085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf32ea0bf23472b7c27cefcbfaf2241930df7a61e0e52f7e2af414c071d3cc6d92874a8a04d4315d5e555f794ef107a68765de376b83ee697658b7dacd578b2ec5f721183', 18 | address: '0xC4c11B14e9D876B031c1c7e05efE44088341f35B', 19 | }, 20 | // polygon 21 | 137: { 22 | gasPrice: 100000000000, 23 | gasLimit: 100000, 24 | signerAddress: '0xBa68986f673c9193BB79eA0d21990225d464bb5C', 25 | transaction: 26 | '0xf8a78085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3820135a084ea92419a30b2851e105567772f3346d4ee23ab63a733f82c13a424604cbfdaa06716488c485f03825d5b5b52d982f130199767319e11453d7cacc5053818c23b', 27 | address: '0xC4c11B14e9D876B031c1c7e05efE44088341f35B', 28 | }, 29 | // local 30 | 31337: { 31 | gasPrice: 100000000000, 32 | gasLimit: 100000, 33 | signerAddress: '0xBa68986f673c9193BB79eA0d21990225d464bb5C', 34 | transaction: 35 | '0xf8a78085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf382f4f5a019264dff42982fbff5b815e16a83fff4524568dd0e23a09c4d37cd86e6890f71a07db39e99070faa25eb46904f812cb12feadddf186e58a69ce7688b04a9ee2a0a', 36 | address: '0xC4c11B14e9D876B031c1c7e05efE44088341f35B', 37 | }, 38 | // mumbai 39 | 80001: { 40 | gasPrice: 100000000000, 41 | gasLimit: 100000, 42 | signerAddress: '0xBa68986f673c9193BB79eA0d21990225d464bb5C', 43 | transaction: 44 | '0xf8a88085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf383027126a0b23aa3a7cf3654c8f2dc3ce3c6d37ff504a726085f835a9f4d32d61e865e261ea017add99e70915725b41244e4feefc854f5c17da90f4e1ac6fb994040ae5af242', 45 | address: '0xC4c11B14e9D876B031c1c7e05efE44088341f35B', 46 | }, 47 | }; 48 | --------------------------------------------------------------------------------